From 0c0c178a3d3bc541ccf076f99c54d5aa6908cbcb Mon Sep 17 00:00:00 2001 From: Lev Stipakov Date: Wed, 7 Jan 2015 21:26:38 +0200 Subject: [PATCH 001/643] Disallow lameduck's float to an address taken by another client Existing check didn't take into account the case when floated client is lame duck (CN for lame duck is NULL), which allowed lame duck to float to an address taken by another client. As a fix we use cert_hash_compare function which, besides fixing mentioned case, also allows lame duck to float to an address already taken by the same client. Acked-by: Steffan Karger Message-Id: <1420658798-29943-1-git-send-email-lstipakov@gmail.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/9386 Signed-off-by: Gert Doering --- src/openvpn/multi.c | 13 ++++++++----- src/openvpn/ssl_verify.c | 2 +- src/openvpn/ssl_verify.h | 8 ++++++++ 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index 6ddfbb5992b..441249141eb 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -2127,17 +2127,20 @@ void multi_process_float (struct multi_context* m, struct multi_instance* mi) const uint32_t hv = hash_value (hash, &real); struct hash_bucket *bucket = hash_bucket (hash, hv); + /* make sure that we don't float to an address taken by another client */ struct hash_element *he = hash_lookup_fast (hash, bucket, &real, hv); if (he) { struct multi_instance *ex_mi = (struct multi_instance *) he->value; - const char *cn = tls_common_name (mi->context.c2.tls_multi, true); - const char *ex_cn = tls_common_name (ex_mi->context.c2.tls_multi, true); - if (cn && ex_cn && strcmp (cn, ex_cn)) + struct tls_multi *m1 = mi->context.c2.tls_multi; + struct tls_multi *m2 = ex_mi->context.c2.tls_multi; + + /* do not float if target address is taken by client with another cert */ + if (!cert_hash_compare(m1->locked_cert_hash_set, m2->locked_cert_hash_set)) { - msg (D_MULTI_MEDIUM, "prevent float to %s", - multi_instance_string (ex_mi, false, &gc)); + msg (D_MULTI_MEDIUM, "Disallow float to an address taken by another client %s", + multi_instance_string (ex_mi, false, &gc)); mi->context.c2.buf.len = 0; diff --git a/src/openvpn/ssl_verify.c b/src/openvpn/ssl_verify.c index cec5f025d0b..ad50458b89e 100644 --- a/src/openvpn/ssl_verify.c +++ b/src/openvpn/ssl_verify.c @@ -238,7 +238,7 @@ cert_hash_free (struct cert_hash_set *chs) } } -static bool +bool cert_hash_compare (const struct cert_hash_set *chs1, const struct cert_hash_set *chs2) { if (chs1 && chs2) diff --git a/src/openvpn/ssl_verify.h b/src/openvpn/ssl_verify.h index 5f23431ed9d..d5bf22e51ca 100644 --- a/src/openvpn/ssl_verify.h +++ b/src/openvpn/ssl_verify.h @@ -137,6 +137,14 @@ const char *tls_common_name (const struct tls_multi* multi, const bool null); */ const char *tls_username (const struct tls_multi *multi, const bool null); +/** + * Compares certificates hashes, returns true if hashes are equal. + * + * @param chs1 cert 1 hash set + * @param chs2 cert 2 hash set + */ +bool cert_hash_compare (const struct cert_hash_set *chs1, const struct cert_hash_set *chs2); + #ifdef ENABLE_PF /** From f95010ad247a8998e0c39e394236251fca316849 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Fri, 23 Jan 2015 20:52:41 +0100 Subject: [PATCH 002/643] Account for peer-id in frame size calculation Data channel packet using P_DATA_V2 will use three bytes extra for the peer-id. This needs to be accounted for, otherwise OpenVPN will throw TCP/UDP packet too large on write to [AF_INET]10.1.1.1:1194 warnings. Signed-off-by: Steffan Karger Acked-by: Lev Stipakov Message-Id: <1422042761-10014-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/9418 Signed-off-by: Gert Doering --- src/openvpn/ssl.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 0bca28d0530..80293efdeaf 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -264,16 +264,14 @@ tls_get_cipher_name_pair (const char * cipher_name, size_t len) { return NULL; } -/* - * Max number of bytes we will add - * for data structures common to both - * data and control channel packets. - * (opcode only). +/** + * Max number of bytes we will add for data structures common to both data and + * control channel packets (1 byte opcode + 3 bytes peer-id). */ void tls_adjust_frame_parameters(struct frame *frame) { - frame_add_to_extra_frame (frame, 1); /* space for opcode */ + frame_add_to_extra_frame (frame, 1 + 3); /* space for opcode + peer-id */ } /* From 2350d709e4d3c28d8850b5106169d799fdad5a29 Mon Sep 17 00:00:00 2001 From: Lev Stipakov Date: Fri, 6 Feb 2015 14:38:00 +0200 Subject: [PATCH 003/643] Fix NULL dereferencing In certain cases buf.len can be -1, which causes BPTR to return NULL and NULL pointer dereferencing on the next line. As a fix, process only packets with non-zero length. Acked-by: Gert Doering Message-Id: <1423226280-9580-1-git-send-email-lstipakov@gmail.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/9444 Signed-off-by: Gert Doering --- src/openvpn/mudp.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/openvpn/mudp.c b/src/openvpn/mudp.c index 3e3f75086af..57118f879c3 100644 --- a/src/openvpn/mudp.c +++ b/src/openvpn/mudp.c @@ -52,20 +52,19 @@ multi_get_create_instance_udp (struct multi_context *m, bool *floated) struct multi_instance *mi = NULL; struct hash *hash = m->hash; - if (mroute_extract_openvpn_sockaddr (&real, &m->top.c2.from.dest, true)) + if (mroute_extract_openvpn_sockaddr (&real, &m->top.c2.from.dest, true) && + m->top.c2.buf.len > 0) { struct hash_element *he; const uint32_t hv = hash_value (hash, &real); struct hash_bucket *bucket = hash_bucket (hash, hv); uint8_t* ptr = BPTR(&m->top.c2.buf); uint8_t op = ptr[0] >> P_OPCODE_SHIFT; - uint32_t peer_id; - int i; /* make sure buffer has enough length to read opcode (1 byte) and peer-id (3 bytes) */ if (op == P_DATA_V2 && m->top.c2.buf.len >= (1 + 3)) { - peer_id = ntohl(*(uint32_t*)ptr) & 0xFFFFFF; + uint32_t peer_id = ntohl(*(uint32_t*)ptr) & 0xFFFFFF; if ((peer_id < m->max_clients) && (m->instances[peer_id])) { mi = m->instances[peer_id]; @@ -99,6 +98,8 @@ multi_get_create_instance_udp (struct multi_context *m, bool *floated) mi = multi_create_instance (m, &real); if (mi) { + int i; + hash_add_fast (hash, bucket, &mi->real, hv, mi); mi->did_real_hash = true; From 251c17a0bc55db59b91338d8f306144182755aa4 Mon Sep 17 00:00:00 2001 From: "Jonathan K. Bullard" Date: Fri, 6 Feb 2015 14:49:10 -0500 Subject: [PATCH 004/643] Fix mismatch of fprintf format specifier and argument type This fixes a warning about a mismatch between a fprintf format string and an argument type on Darwin-64-bit builds: %lu specifies type 'unsigned long' but the argument has type '__darwin_suseconds_t' (aka 'int') Acked-by: Arne Schwabe Message-Id: URL: http://article.gmane.org/gmane.network.openvpn.devel/9446 Signed-off-by: Gert Doering --- src/openvpn/error.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openvpn/error.c b/src/openvpn/error.c index 9d52962ae76..77b6cec06ba 100644 --- a/src/openvpn/error.c +++ b/src/openvpn/error.c @@ -319,7 +319,7 @@ void x_msg_va (const unsigned int flags, const char *format, va_list arglist) fprintf (fp, "%lu.%06lu %x %s%s%s%s", tv.tv_sec, - tv.tv_usec, + (unsigned long)tv.tv_usec, flags, prefix, prefix_sep, From 5d5233778868ddd568140c394adfcfc8e3453245 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sun, 15 Feb 2015 15:24:26 +0100 Subject: [PATCH 005/643] Disable SSL compression As reported in trac #502, SSL compression can cause problems in some corner cases. OpenVPN does not need SSL compression, since the control channel is low bandwidth. This does not influence the data channel compressen (i.e. --comp or --comp-lzo). Even though this has not yet been relevant for OpenVPN (since an attacker can not easily control contents of control channel messages), SSL compression has been used in the CRIME and BREACH attacks on TLS. TLS 1.3 will probably even remove support for compression all together, for exactly this reason. Since we don't need it, and SSL compression causes issues, let's just disable it in OpenSSL builds. PolarSSL has no run-time flag to disable compression, but is by default compiled without compression. Signed-off-by: Steffan Karger Acked-by: Arne Schwabe Acked-by: Gert Doering Message-Id: <1424010266-5910-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/9453 Signed-off-by: Gert Doering --- src/openvpn/ssl_openssl.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c index 48c05715275..d9abc6ea436 100644 --- a/src/openvpn/ssl_openssl.c +++ b/src/openvpn/ssl_openssl.c @@ -202,6 +202,10 @@ tls_ctx_set_options (struct tls_root_ctx *ctx, unsigned int ssl_flags) #ifdef SSL_OP_NO_TLSv1_2 if (tls_ver_min > TLS_VER_1_2 || tls_ver_max < TLS_VER_1_2) sslopt |= SSL_OP_NO_TLSv1_2; +#endif +#ifdef SSL_OP_NO_COMPRESSION + /* Disable compression - flag not available in OpenSSL 0.9.8 */ + sslopt |= SSL_OP_NO_COMPRESSION; #endif SSL_CTX_set_options (ctx->ctx, sslopt); } From 9e0963c11aa439deb382d7d6bc40b6ade999401c Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Sun, 8 Feb 2015 11:18:45 +0100 Subject: [PATCH 006/643] New approach to handle peer-id related changes to link-mtu. Instead of statically increasing link-mtu by +3, keep the old value for OCC compatibility with old servers/clients, and only increase link-mtu if peer-id option is enabled (right now: is pushed by server). If link-mtu has been set in the config, keep configured value, and log warning (because the extra overhead has to decrease tun-mtu). Reserve extra +3 bytes in frame->extra_link. v2: use frame->extra_link, not frame->extra_buffer (receive path on server) introduce frame_add_to_link_mtu() to manipulate frame->link_mtu value rework comments to make more clear what is happening This reverts commit f95010ad247a8998e0c39e394236251fca316849. Signed-off-by: Gert Doering Acked-by: Arne Schwabe Message-Id: <1423390725-13438-1-git-send-email-gert@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/9450 --- src/openvpn/init.c | 24 ++++++++++++++++++++++++ src/openvpn/mtu.h | 6 ++++++ src/openvpn/ssl.c | 10 ++++++---- 3 files changed, 36 insertions(+), 4 deletions(-) diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 706d07ca3dc..b670a48fc91 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -1794,6 +1794,19 @@ do_deferred_options (struct context *c, const unsigned int found) msg (D_PUSH, "OPTIONS IMPORT: peer-id set"); c->c2.tls_multi->use_peer_id = true; c->c2.tls_multi->peer_id = c->options.peer_id; + frame_add_to_extra_frame(&c->c2.frame, +3); /* peer-id overhead */ + if ( !c->options.ce.link_mtu_defined ) + { + frame_add_to_link_mtu(&c->c2.frame, +3); + msg (D_PUSH, "OPTIONS IMPORT: adjusting link_mtu to %d", + EXPANDED_SIZE(&c->c2.frame)); + } + else + { + msg (M_WARN, "OPTIONS IMPORT: WARNING: peer-id set, but link-mtu" + " fixed by config - reducing tun-mtu to %d, expect" + " MTU problems", TUN_MTU_SIZE(&c->c2.frame) ); + } } #endif } @@ -2403,6 +2416,17 @@ do_init_frame (struct context *c) #endif #endif /* USE_COMP */ + /* packets with peer-id (P_DATA_V2) need 3 extra bytes in frame (on client) + * and need link_mtu+3 bytes on socket reception (on server). + * + * accomodate receive path in f->extra_link, which has the side effect of + * also increasing send buffers (BUF_SIZE() macro), which need to be + * allocated big enough before receiving peer-id option from server. + * + * f->extra_frame is adjusted when peer-id option is push-received + */ + frame_add_to_extra_link(&c->c2.frame, 3); + #ifdef ENABLE_FRAGMENT /* * Set frame parameter for fragment code. This is necessary because diff --git a/src/openvpn/mtu.h b/src/openvpn/mtu.h index 29ec21fda7d..bccd6810fde 100644 --- a/src/openvpn/mtu.h +++ b/src/openvpn/mtu.h @@ -257,6 +257,12 @@ frame_headroom (const struct frame *f, const unsigned int flag_mask) * frame member adjustment functions */ +static inline void +frame_add_to_link_mtu (struct frame *frame, const int increment) +{ + frame->link_mtu += increment; +} + static inline void frame_add_to_extra_frame (struct frame *frame, const int increment) { diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 80293efdeaf..222c8285eca 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -264,14 +264,16 @@ tls_get_cipher_name_pair (const char * cipher_name, size_t len) { return NULL; } -/** - * Max number of bytes we will add for data structures common to both data and - * control channel packets (1 byte opcode + 3 bytes peer-id). +/* + * Max number of bytes we will add + * for data structures common to both + * data and control channel packets. + * (opcode only). */ void tls_adjust_frame_parameters(struct frame *frame) { - frame_add_to_extra_frame (frame, 1 + 3); /* space for opcode + peer-id */ + frame_add_to_extra_frame (frame, 1); /* space for opcode */ } /* From 0b1a68fffa33e175c320c2828604cdc7dfb097e7 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Mon, 29 Dec 2014 18:48:45 +0100 Subject: [PATCH 007/643] Print remote IPv4 address on a dual-stack v6 socket in IPv4 format Previously, the code would print IPv4-mapped format ("::ffff:1.2.3.4"), which is technically correct but adds no extra value, and is confusingly different from the output if using a v4 socket. Print "1.2.3.4" instead, whatever socket type is used. Affects client IP address in log file, status output (mroute_addr_print_ex), and environment (setenv_sockaddr). The fact that a dual-stack socket was used is still visible in the initial peer connect message in the log: '... Peer Connection Initiated with [AF_INET6]::ffff:1.1.3.4:53779' Signed-off-by: Gert Doering Acked-by: Arne Schwabe Message-Id: <1419875325-96015-1-git-send-email-gert@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/9363 --- src/openvpn/mroute.c | 12 ++++++++++-- src/openvpn/socket.c | 16 +++++++++++++--- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/openvpn/mroute.c b/src/openvpn/mroute.c index ba4ef46f639..972f1dd5e45 100644 --- a/src/openvpn/mroute.c +++ b/src/openvpn/mroute.c @@ -426,8 +426,16 @@ mroute_addr_print_ex (const struct mroute_addr *ma, break; case MR_ADDR_IPV6: { - buf_printf (&out, "%s", - print_in6_addr( *(struct in6_addr*)&maddr.addr, 0, gc)); + if ( IN6_IS_ADDR_V4MAPPED( (struct in6_addr*)&maddr.addr ) ) + { + buf_printf (&out, "%s", + print_in_addr_t( *(in_addr_t*)(&maddr.addr[12]), IA_NET_ORDER, gc)); + } + else + { + buf_printf (&out, "%s", + print_in6_addr( *(struct in6_addr*)&maddr.addr, 0, gc)); + } if (maddr.type & MR_WITH_NETBITS) { buf_printf (&out, "/%d", maddr.netbits); diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c index 331a9d9f7bd..f5c740d8e5a 100644 --- a/src/openvpn/socket.c +++ b/src/openvpn/socket.c @@ -2573,9 +2573,19 @@ setenv_sockaddr (struct env_set *es, const char *name_prefix, const struct openv } break; case AF_INET6: - openvpn_snprintf (name_buf, sizeof (name_buf), "%s_ip6", name_prefix); - getnameinfo(&addr->addr.sa, sizeof (struct sockaddr_in6), - buf, sizeof(buf), NULL, 0, NI_NUMERICHOST); + if ( IN6_IS_ADDR_V4MAPPED( &addr->addr.in6.sin6_addr )) + { + struct in_addr ia; + ia.s_addr = *(in_addr_t *)&addr->addr.in6.sin6_addr.s6_addr[12] ; + openvpn_snprintf (name_buf, sizeof (name_buf), "%s_ip", name_prefix); + openvpn_snprintf (buf, sizeof(buf), "%s", inet_ntoa(ia) ); + } + else + { + openvpn_snprintf (name_buf, sizeof (name_buf), "%s_ip6", name_prefix); + getnameinfo(&addr->addr.sa, sizeof (struct sockaddr_in6), + buf, sizeof(buf), NULL, 0, NI_NUMERICHOST); + } setenv_str (es, name_buf, buf); if ((flags & SA_IP_PORT) && addr->addr.in6.sin6_port) From 513eef4884c9be1fd31ba676dfe34d91a4ce6141 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sun, 22 Feb 2015 15:11:08 +0100 Subject: [PATCH 008/643] Use tls-auth in sample config files For two reasons: 1) May motivate people to use tls-auth in their setups 2) Verify tls-auth functionality when running 'make check' Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1424614268-5078-1-git-send-email-steffan.karger@fox-it.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/9467 Signed-off-by: Gert Doering --- sample/sample-config-files/client.conf | 2 +- sample/sample-config-files/loopback-client | 1 + sample/sample-config-files/loopback-server | 1 + sample/sample-config-files/server.conf | 2 +- sample/sample-keys/gen-sample-keys.sh | 3 +++ sample/sample-keys/ta.key | 21 +++++++++++++++++++++ 6 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 sample/sample-keys/ta.key diff --git a/sample/sample-config-files/client.conf b/sample/sample-config-files/client.conf index 050ef600eca..fedcbd6e8dc 100644 --- a/sample/sample-config-files/client.conf +++ b/sample/sample-config-files/client.conf @@ -105,7 +105,7 @@ remote-cert-tls server # If a tls-auth key is used on the server # then every client must also have the key. -;tls-auth ta.key 1 +tls-auth ta.key 1 # Select a cryptographic cipher. # If the cipher option is used on the server diff --git a/sample/sample-config-files/loopback-client b/sample/sample-config-files/loopback-client index ebbd1cf4056..7117307de71 100644 --- a/sample/sample-config-files/loopback-client +++ b/sample/sample-config-files/loopback-client @@ -21,5 +21,6 @@ remote-cert-tls server ca sample-keys/ca.crt key sample-keys/client.key cert sample-keys/client.crt +tls-auth sample-keys/ta.key 1 ping 1 inactive 120 10000000 diff --git a/sample/sample-config-files/loopback-server b/sample/sample-config-files/loopback-server index 8cb97be0aa5..8e1f39cd3d0 100644 --- a/sample/sample-config-files/loopback-server +++ b/sample/sample-config-files/loopback-server @@ -21,5 +21,6 @@ dh sample-keys/dh2048.pem ca sample-keys/ca.crt key sample-keys/server.key cert sample-keys/server.crt +tls-auth sample-keys/ta.key 0 ping 1 inactive 120 10000000 diff --git a/sample/sample-config-files/server.conf b/sample/sample-config-files/server.conf index 701be3ccee3..c85ca0ffdb0 100644 --- a/sample/sample-config-files/server.conf +++ b/sample/sample-config-files/server.conf @@ -241,7 +241,7 @@ keepalive 10 120 # a copy of this key. # The second parameter should be '0' # on the server and '1' on the clients. -;tls-auth ta.key 0 # This file is secret +tls-auth ta.key 0 # This file is secret # Select a cryptographic cipher. # This config item must be copied to diff --git a/sample/sample-keys/gen-sample-keys.sh b/sample/sample-keys/gen-sample-keys.sh index 414687eb725..725cfc970c1 100755 --- a/sample/sample-keys/gen-sample-keys.sh +++ b/sample/sample-keys/gen-sample-keys.sh @@ -14,6 +14,9 @@ then exit 1 fi +# Generate static key for tls-auth (or static key mode) +$(dirname ${0})/../../src/openvpn/openvpn --genkey --secret ta.key + # Create required directories and files mkdir -p sample-ca rm -f sample-ca/index.txt diff --git a/sample/sample-keys/ta.key b/sample/sample-keys/ta.key new file mode 100644 index 00000000000..166903681fa --- /dev/null +++ b/sample/sample-keys/ta.key @@ -0,0 +1,21 @@ +# +# 2048 bit OpenVPN static key +# +-----BEGIN OpenVPN Static key V1----- +a863b1cbdb911ff4ef3360ce135157e7 +241a465f5045f51cf9a92ebc24da34fd +5fc48456778c977e374d55a8a7298aef +40d0ab0c60b5e09838510526b73473a0 +8da46a8c352572dd86d4a871700a915b +6aaa58a9dac560db2dfdd7ef15a202e1 +fca6913d7ee79c678c5798fbf7bd920c +caa7a64720908da7254598b052d07f55 +5e31dc5721932cffbdd8965d04107415 +46c86823da18b66aab347e4522cc05ff +634968889209c96b1024909cd4ce574c +f829aa9c17d5df4a66043182ee23635d +8cabf5a7ba02345ad94a3aa25a63d55c +e13f4ad235a0825e3fe17f9419baff1c +e73ad1dd652f1e48c7102fe8ee181e54 +10a160ae255f63fd01db1f29e6efcb8e +-----END OpenVPN Static key V1----- From 669f898b8fcaf7a8d43825fa0255c2791cc0ef89 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Tue, 29 Jul 2014 22:52:24 +0200 Subject: [PATCH 009/643] Fix frame size calculation for non-CBC modes. CBC mode is the only mode that OpenVPN supports that needs padding. So, only include the worst case padding size in the frame size calculation when using CBC mode. While doing so, rewrite crypto_adjust_frame_parameters() to be better readable, and provide debug output (for high debug levels). Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1406667144-17674-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/8952 Signed-off-by: Gert Doering --- src/openvpn/crypto.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c index 5cf9b9cd14a..c1b9df31712 100644 --- a/src/openvpn/crypto.c +++ b/src/openvpn/crypto.c @@ -403,11 +403,27 @@ crypto_adjust_frame_parameters(struct frame *frame, bool packet_id, bool packet_id_long_form) { - frame_add_to_extra_frame (frame, - (packet_id ? packet_id_size (packet_id_long_form) : 0) + - ((cipher_defined && use_iv) ? cipher_kt_iv_size (kt->cipher) : 0) + - (cipher_defined ? cipher_kt_block_size (kt->cipher) : 0) + /* worst case padding expansion */ - kt->hmac_length); + size_t crypto_overhead = 0; + + if (packet_id) + crypto_overhead += packet_id_size (packet_id_long_form); + + if (cipher_defined) + { + if (use_iv) + crypto_overhead += cipher_kt_iv_size (kt->cipher); + + if (cipher_kt_mode_cbc (kt->cipher)) + /* worst case padding expansion */ + crypto_overhead += cipher_kt_block_size (kt->cipher); + } + + crypto_overhead += kt->hmac_length; + + frame_add_to_extra_frame (frame, crypto_overhead); + + msg(D_MTU_DEBUG, "%s: Adjusting frame parameters for crypto by %zu bytes", + __func__, crypto_overhead); } /* From a6ef6c7c3318a4bc8f9a4df8c75c943da43a7662 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Wed, 4 Mar 2015 15:23:44 +0100 Subject: [PATCH 010/643] Remove unused function sock_addr_set Acked-by: Gert Doering Message-Id: <1425479025-7573-1-git-send-email-arne@rfc2549.org> URL: http://article.gmane.org/gmane.network.openvpn.devel/9502 Signed-off-by: Gert Doering --- src/openvpn/ps.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/openvpn/ps.c b/src/openvpn/ps.c index 6807aac0e4a..fe18a9df535 100644 --- a/src/openvpn/ps.c +++ b/src/openvpn/ps.c @@ -372,17 +372,6 @@ proxy_list_close (struct proxy_connection **list) } } -static void -sock_addr_set (struct openvpn_sockaddr *osaddr, - const in_addr_t addr, - const int port) -{ - CLEAR (*osaddr); - osaddr->addr.in4.sin_family = AF_INET; - osaddr->addr.in4.sin_addr.s_addr = htonl (addr); - osaddr->addr.in4.sin_port = htons (port); -} - static inline void proxy_connection_io_requeue (struct proxy_connection *pc, const int rwflags_new, struct event_set *es) { From 77f464bddcfcc958f10fd3e9c45e1cb46d5206d0 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Wed, 4 Mar 2015 15:23:45 +0100 Subject: [PATCH 011/643] Document the default for tls-cipher. Acked-by: Gert Doering Message-Id: <1425479025-7573-2-git-send-email-arne@rfc2549.org> URL: http://article.gmane.org/gmane.network.openvpn.devel/9503 Signed-off-by: Gert Doering --- doc/openvpn.8 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index a8c189c918f..95515668f87 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -4514,6 +4514,9 @@ of security they both support. Use .B \-\-show-tls to see a list of supported TLS ciphers. + +The default for --tls-cipher is to use PolarSSL's default cipher list +when using PolarSSL or "DEFAULT:!EXP:!PSK:!SRP:!kRSA" when using OpenSSL. .\"********************************************************* .TP .B \-\-tls-timeout n From 48e5e425b7568d8fbd2e32517b7c358dbb6d4c5f Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Thu, 5 Mar 2015 22:58:35 +0100 Subject: [PATCH 012/643] Get rid of old OpenSSL workarounds. We now only support OpenSSL 0.9.8+, so we don't have to work around the bug in 0.9.6b anymore. Also, OBJ_txt2nid() now takes a const char * (instead of a char *), so we no langer have to cast away const. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1425592716-14243-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/9512 Signed-off-by: Gert Doering --- src/openvpn/ssl_verify_openssl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/openvpn/ssl_verify_openssl.c b/src/openvpn/ssl_verify_openssl.c index 0348e98adc1..81b2e38da81 100644 --- a/src/openvpn/ssl_verify_openssl.c +++ b/src/openvpn/ssl_verify_openssl.c @@ -169,8 +169,8 @@ extract_x509_field_ssl (X509_NAME *x509, const char *field_name, char *out, int tmp = -1; X509_NAME_ENTRY *x509ne = 0; ASN1_STRING *asn1 = 0; - unsigned char *buf = (unsigned char *)1; /* bug in OpenSSL 0.9.6b ASN1_STRING_to_UTF8 requires this workaround */ - int nid = OBJ_txt2nid((char *)field_name); + unsigned char *buf = NULL; + int nid = OBJ_txt2nid(field_name); ASSERT (size > 0); *out = '\0'; From 63559e142eb71a5e38dfc55d429f35f6e1af0b7c Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Thu, 5 Mar 2015 22:58:36 +0100 Subject: [PATCH 013/643] polarssl: make sure to always null-terminate the cn Just a precaution, this could never fail in the current code since in the one place this function is called, the cn is already zero-initialized. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1425592716-14243-2-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/9511 Signed-off-by: Gert Doering --- src/openvpn/ssl_verify_polarssl.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/openvpn/ssl_verify_polarssl.c b/src/openvpn/ssl_verify_polarssl.c index e21301d3090..2edf21dd3dd 100644 --- a/src/openvpn/ssl_verify_polarssl.c +++ b/src/openvpn/ssl_verify_polarssl.c @@ -115,7 +115,10 @@ backend_x509_get_username (char *cn, int cn_len, /* Found, extract CN */ if (cn_len > name->val.len) - memcpy( cn, name->val.p, name->val.len ); + { + memcpy( cn, name->val.p, name->val.len ); + cn[name->val.len] = '\0'; + } else { memcpy( cn, name->val.p, cn_len); From ecd934b1ef83eec58eb2df5d3a98309ca56d5812 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Thu, 5 Mar 2015 22:37:31 +0100 Subject: [PATCH 014/643] Allow for CN/username of 64 characters (fixes off-by-one) This is an alternative patch to fix the issue reported in trac #515 by Jorge Peixoto. Instead of increasing the TLS_USERNAME_LEN define, do +1 at the relevant places in the code. Also see Jorge's original patch and the discussion on the maillinglist: http://thread.gmane.org/gmane.network.openvpn.devel/9438 Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <54F8CC9B.9040104@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/9508 Signed-off-by: Gert Doering --- src/openvpn/ssl_verify.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/openvpn/ssl_verify.c b/src/openvpn/ssl_verify.c index ad50458b89e..ccfa9d26256 100644 --- a/src/openvpn/ssl_verify.c +++ b/src/openvpn/ssl_verify.c @@ -592,7 +592,7 @@ verify_cert(struct tls_session *session, openvpn_x509_cert_t *cert, int cert_dep { result_t ret = FAILURE; char *subject = NULL; - char common_name[TLS_USERNAME_LEN] = {0}; + char common_name[TLS_USERNAME_LEN+1] = {0}; /* null-terminated */ const struct tls_options *opt; struct gc_arena gc = gc_new(); @@ -615,7 +615,7 @@ verify_cert(struct tls_session *session, openvpn_x509_cert_t *cert, int cert_dep string_replace_leading (subject, '-', '_'); /* extract the username (default is CN) */ - if (SUCCESS != backend_x509_get_username (common_name, TLS_USERNAME_LEN, + if (SUCCESS != backend_x509_get_username (common_name, sizeof(common_name), opt->x509_username_field, cert)) { if (!cert_depth) @@ -1163,7 +1163,7 @@ verify_user_pass(struct user_pass *up, struct tls_multi *multi, s2 = verify_user_pass_script (session, up); /* check sizing of username if it will become our common name */ - if ((session->opt->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) && strlen (up->username) >= TLS_USERNAME_LEN) + if ((session->opt->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) && strlen (up->username) > TLS_USERNAME_LEN) { msg (D_TLS_ERRORS, "TLS Auth Error: --username-as-common name specified and username is longer than the maximum permitted Common Name length of %d characters", TLS_USERNAME_LEN); s1 = OPENVPN_PLUGIN_FUNC_ERROR; From d384a9587951617d12e31e0a18050bd86402d5df Mon Sep 17 00:00:00 2001 From: Lev Stipakov Date: Thu, 5 Mar 2015 22:33:56 +0200 Subject: [PATCH 015/643] Fix mssfix default value in connection_list context Due to this bug, mssfix hasn't been assigned to fragment value and used default value (1450) instead. As a consequence, TCP packets get fragmented, which causes performance penalty. Since dual stack patch (commit 23d61c56b9fd218c39ad151b01b7e2d6690e6093) OpenVPN uses options->connection_list, even for single remote. This fix assigns mssfix value to fragment value for connection_entry inside connection_list instead of connection_entry inside options struct (which does not work for connection_list case). Acked-by: Gert Doering Message-Id: <1425587636-23338-1-git-send-email-lstipakov@gmail.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/9507 Signed-off-by: Gert Doering --- src/openvpn/options.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 4ea03d1bee4..20b37db9dd1 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -2352,7 +2352,7 @@ options_postprocess_mutate_ce (struct options *o, struct connection_entry *ce) { #ifdef ENABLE_FRAGMENT if (ce->fragment) - o->ce.mssfix = ce->fragment; + ce->mssfix = ce->fragment; #else msg (M_USAGE, "--mssfix must specify a parameter"); #endif From bacd640f57c935fb8de4efa71be0e8601c48f26f Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sat, 7 Mar 2015 17:23:11 +0100 Subject: [PATCH 016/643] Change float log message to include common name, if available. Makes it a lot easier to see which client is floating. Signed-off-by: Steffan Karger Acked-by: Lev Stipakov Message-Id: <1425745391-8069-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/9526 Signed-off-by: Gert Doering --- src/openvpn/multi.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index 441249141eb..b0f66ca2796 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -2151,8 +2151,11 @@ void multi_process_float (struct multi_context* m, struct multi_instance* mi) multi_close_instance(m, ex_mi, false); } - msg (D_MULTI_MEDIUM, "peer %" PRIu32 " floated from %s to %s", mi->context.c2.tls_multi->peer_id, - mroute_addr_print (&mi->real, &gc), print_link_socket_actual (&m->top.c2.from, &gc)); + msg (D_MULTI_MEDIUM, "peer %" PRIu32 " (%s) floated from %s to %s", + mi->context.c2.tls_multi->peer_id, + tls_common_name (mi->context.c2.tls_multi, false), + mroute_addr_print (&mi->real, &gc), + print_link_socket_actual (&m->top.c2.from, &gc)); ASSERT (hash_remove(m->hash, &mi->real)); ASSERT (hash_remove(m->iter, &mi->real)); From e8562d5531277ee4dd7c517ef68e87af077ac948 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Sun, 8 Mar 2015 13:56:41 +0100 Subject: [PATCH 017/643] Fix incorrect use of get_ipv6_addr() for iroute options. get_ipv6_addr() returns "bool/false", not "int < 0" to signal error. Signed-off-by: Gert Doering Acked-by: Steffan Karger Message-Id: <1425819401-18465-1-git-send-email-gert@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/9532 --- src/openvpn/options.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 20b37db9dd1..df9a641074c 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -1254,7 +1254,7 @@ option_iroute_ipv6 (struct options *o, ALLOC_OBJ_GC (ir, struct iroute_ipv6, &o->gc); - if ( get_ipv6_addr (prefix_str, &ir->network, &ir->netbits, NULL, msglevel ) < 0 ) + if ( !get_ipv6_addr (prefix_str, &ir->network, &ir->netbits, NULL, msglevel )) { msg (msglevel, "in --iroute-ipv6 %s: Bad IPv6 prefix specification", prefix_str); From ec2fbf374f018366c18644d271cd4d793d04244b Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Sat, 27 Dec 2014 21:59:43 +0100 Subject: [PATCH 018/643] Remove count_netmask_bits(), convert users to use netmask_to_netbits2() The previous Linux/iproute2 code converted binary netmasks to string representation (print_in_addr_t()), just to immediately scanf() it back to binary to count bits. netmask_to_netbits2() directly works on the in_addr_t. Signed-off-by: Gert Doering Acked-by: Steffan Karger Message-Id: <1419713983-16272-1-git-send-email-gert@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/9360 --- src/openvpn/misc.c | 26 -------------------------- src/openvpn/misc.h | 4 ---- src/openvpn/route.c | 4 ++-- src/openvpn/route.h | 1 + src/openvpn/tun.c | 4 ++-- 5 files changed, 5 insertions(+), 34 deletions(-) diff --git a/src/openvpn/misc.c b/src/openvpn/misc.c index 61bc523dda0..5627cb9eaec 100644 --- a/src/openvpn/misc.c +++ b/src/openvpn/misc.c @@ -827,32 +827,6 @@ setenv_str_i (struct env_set *es, const char *name, const char *value, const int gc_free (&gc); } -/* - * taken from busybox networking/ifupdown.c - */ -unsigned int -count_bits(unsigned int a) -{ - unsigned int result; - result = (a & 0x55) + ((a >> 1) & 0x55); - result = (result & 0x33) + ((result >> 2) & 0x33); - return((result & 0x0F) + ((result >> 4) & 0x0F)); -} - -int -count_netmask_bits(const char *dotted_quad) -{ - unsigned int result, a, b, c, d; - /* Found a netmask... Check if it is dotted quad */ - if (sscanf(dotted_quad, "%u.%u.%u.%u", &a, &b, &c, &d) != 4) - return -1; - result = count_bits(a); - result += count_bits(b); - result += count_bits(c); - result += count_bits(d); - return ((int)result); -} - /* return true if filename can be opened for read */ bool test_file (const char *filename) diff --git a/src/openvpn/misc.h b/src/openvpn/misc.h index 41748bd8324..5fe085e916e 100644 --- a/src/openvpn/misc.h +++ b/src/openvpn/misc.h @@ -166,10 +166,6 @@ const char **make_env_array (const struct env_set *es, const char **make_arg_array (const char *first, const char *parms, struct gc_arena *gc); const char **make_extended_arg_array (char **p, struct gc_arena *gc); -/* convert netmasks for iproute2 */ -int count_netmask_bits(const char *); -unsigned int count_bits(unsigned int ); - /* an analogue to the random() function, but use OpenSSL functions if available */ #ifdef ENABLE_CRYPTO long int get_random(void); diff --git a/src/openvpn/route.c b/src/openvpn/route.c index 7ec482b9ce9..a349ac9808c 100644 --- a/src/openvpn/route.c +++ b/src/openvpn/route.c @@ -1288,7 +1288,7 @@ add_route (struct route_ipv4 *r, argv_printf (&argv, "%s route add %s/%d", iproute_path, network, - count_netmask_bits(netmask)); + netmask_to_netbits2(r->netmask)); if (r->flags & RT_METRIC_DEFINED) argv_printf_cat (&argv, "metric %d", r->metric); @@ -1765,7 +1765,7 @@ delete_route (struct route_ipv4 *r, argv_printf (&argv, "%s route del %s/%d", iproute_path, network, - count_netmask_bits(netmask)); + netmask_to_netbits2(r->netmask)); #else argv_printf (&argv, "%s del -net %s netmask %s", ROUTE_PATH, diff --git a/src/openvpn/route.h b/src/openvpn/route.h index f3c01501e25..3cec08dfb35 100644 --- a/src/openvpn/route.h +++ b/src/openvpn/route.h @@ -305,6 +305,7 @@ static inline bool test_routes (const struct route_list *rl, const struct tuntap #endif bool netmask_to_netbits (const in_addr_t network, const in_addr_t netmask, int *netbits); +int netmask_to_netbits2 (in_addr_t netmask); static inline in_addr_t netbits_to_netmask (const int netbits) diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index e92edc2f6f1..11a6d714cd1 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -722,7 +722,7 @@ do_ifconfig (struct tuntap *tt, iproute_path, actual, ifconfig_local, - count_netmask_bits(ifconfig_remote_netmask), + netmask_to_netbits2(tt->remote_netmask), ifconfig_broadcast ); argv_msg (M_INFO, &argv); @@ -1819,7 +1819,7 @@ close_tun (struct tuntap *tt) iproute_path, tt->actual_name, print_in_addr_t (tt->local, 0, &gc), - count_netmask_bits(print_in_addr_t (tt->remote_netmask, 0, &gc)) + netmask_to_netbits2(tt->remote_netmask) ); } #else From 39e3d336d4eeab847a3395ddeb430e0a9ca387b9 Mon Sep 17 00:00:00 2001 From: Vasily Kulikov Date: Wed, 25 Feb 2015 19:07:18 +0300 Subject: [PATCH 019/643] Mac OS X Keychain management client This patch adds support for using certificates stored in the Mac OSX Keychain to authenticate with the OpenVPN server. This works with certificates stored on the computer as well as certificates on hardware tokens that support Apple's tokend interface. The patch is based on the Windows Crypto API certificate functionality that currently exists in OpenVPN. This patch version implements management client which handles RSA-SIGN command for RSA offloading. Also it handles new 'NEED-CERTIFICATE' request to pass a certificate from the keychain to OpenVPN. OpenVPN itself gets new 'NEED-CERTIFICATE" command which is called when --management-external-cert is used. It is implemented as a multiline command very similar to an existing 'RSA-SIGN' command. The patch is against commit 3341a98c2852d1d0c1eafdc70a3bdb218ec29049. v4: - added '--management-external-cert' argument - keychain-mcd now parses NEED-CERTIFICATE argument if 'auto' is passed as cmdline's identity template - fixed typo in help output option name - added '--management-external-cert' info in openvpn(8) manpage - added 'certificate' command documentation into doc/management-notes.txt v3: - used new 'NEED-CERTIFICATE' command for certificate data request instead of 'NEED-OK' - improved option checking - improved invalid certificate selection string handling - added man page for keychain-mcd - handle INFO, FATAL commands from openvpn and show them to user * ACK from Arne Schwabe for OpenVPN part * ACK from James based on Arne's testing v2 (http://sourceforge.net/p/openvpn/mailman/message/33225603/): - used management interface to communicate with OpenVPN process v1 (http://sourceforge.net/p/openvpn/mailman/message/33125844/): - used RSA_METHOD to extend openvpn itself Signed-off-by: Vasily Kulikov -- Acked-by: Arne Schwabe Message-Id: <20150225160718.GA6306@cachalot> URL: http://article.gmane.org/gmane.network.openvpn.devel/9486 Signed-off-by: Gert Doering --- contrib/keychain-mcd/Makefile | 13 + contrib/keychain-mcd/cert_data.c | 733 ++++++++++++++++++++++++++++ contrib/keychain-mcd/cert_data.h | 46 ++ contrib/keychain-mcd/common_osx.c | 94 ++++ contrib/keychain-mcd/common_osx.h | 36 ++ contrib/keychain-mcd/crypto_osx.c | 75 +++ contrib/keychain-mcd/crypto_osx.h | 44 ++ contrib/keychain-mcd/keychain-mcd.8 | 161 ++++++ contrib/keychain-mcd/main.c | 255 ++++++++++ doc/management-notes.txt | 22 + doc/openvpn.8 | 9 + src/openvpn/buffer.c | 13 +- src/openvpn/buffer.h | 1 + src/openvpn/manage.c | 153 ++++-- src/openvpn/manage.h | 5 + src/openvpn/options.c | 22 +- src/openvpn/options.h | 1 + src/openvpn/ssl.c | 17 +- 18 files changed, 1665 insertions(+), 35 deletions(-) create mode 100644 contrib/keychain-mcd/Makefile create mode 100644 contrib/keychain-mcd/cert_data.c create mode 100644 contrib/keychain-mcd/cert_data.h create mode 100644 contrib/keychain-mcd/common_osx.c create mode 100644 contrib/keychain-mcd/common_osx.h create mode 100644 contrib/keychain-mcd/crypto_osx.c create mode 100644 contrib/keychain-mcd/crypto_osx.h create mode 100644 contrib/keychain-mcd/keychain-mcd.8 create mode 100644 contrib/keychain-mcd/main.c diff --git a/contrib/keychain-mcd/Makefile b/contrib/keychain-mcd/Makefile new file mode 100644 index 00000000000..c6431df1587 --- /dev/null +++ b/contrib/keychain-mcd/Makefile @@ -0,0 +1,13 @@ +CFILES = cert_data.c common_osx.c crypto_osx.c main.c +OFILES = $(CFILES:.c=.o) ../../src/openvpn/base64.o +prog = keychain-mcd + +CC = gcc +CFLAGS = -Wall +LDFLAGS = -framework CoreFoundation -framework Security -framework CoreServices + +$(prog): $(OFILES) + $(CC) $(LDFLAGS) $(OFILES) -o $(prog) + +%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ diff --git a/contrib/keychain-mcd/cert_data.c b/contrib/keychain-mcd/cert_data.c new file mode 100644 index 00000000000..f2b33edced8 --- /dev/null +++ b/contrib/keychain-mcd/cert_data.c @@ -0,0 +1,733 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2010 Brian Raderman + * Copyright (C) 2013-2015 Vasily Kulikov + * + * 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 + */ + + +#include "cert_data.h" +#include +#include + +#include "common_osx.h" +#include "crypto_osx.h" +#include + +CFStringRef kCertDataSubjectName = CFSTR("subject"), + kCertDataIssuerName = CFSTR("issuer"), + kCertDataSha1Name = CFSTR("SHA1"), + kCertDataMd5Name = CFSTR("MD5"), + kCertDataSerialName = CFSTR("serial"), + kCertNameFwdSlash = CFSTR("/"), + kCertNameEquals = CFSTR("="); +CFStringRef kCertNameOrganization = CFSTR("o"), + kCertNameOrganizationalUnit = CFSTR("ou"), + kCertNameCountry = CFSTR("c"), + kCertNameLocality = CFSTR("l"), + kCertNameState = CFSTR("st"), + kCertNameCommonName = CFSTR("cn"), + kCertNameEmail = CFSTR("e"); +CFStringRef kStringSpace = CFSTR(" "), + kStringEmpty = CFSTR(""); + +typedef struct _CertName +{ + CFArrayRef countryName, organization, organizationalUnit, commonName, description, emailAddress, + stateName, localityName; +} CertName, *CertNameRef; + +typedef struct _DescData +{ + CFStringRef name, value; +} DescData, *DescDataRef; + +void destroyDescData(DescDataRef pData); + +CertNameRef createCertName() +{ + CertNameRef pCertName = (CertNameRef)malloc(sizeof(CertName)); + pCertName->countryName = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + pCertName->organization = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + pCertName->organizationalUnit = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + pCertName->commonName = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + pCertName->description = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + pCertName->emailAddress = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + pCertName->stateName = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + pCertName->localityName = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + return pCertName; +} + +void destroyCertName(CertNameRef pCertName) +{ + if (!pCertName) + return; + + CFRelease(pCertName->countryName); + CFRelease(pCertName->organization); + CFRelease(pCertName->organizationalUnit); + CFRelease(pCertName->commonName); + CFRelease(pCertName->description); + CFRelease(pCertName->emailAddress); + CFRelease(pCertName->stateName); + CFRelease(pCertName->localityName); + free(pCertName); +} + +bool CFStringRefCmpCString(CFStringRef cfstr, const char *str) +{ + CFStringRef tmp = CFStringCreateWithCStringNoCopy(NULL, str, kCFStringEncodingUTF8, kCFAllocatorNull); + CFComparisonResult cresult = CFStringCompare(cfstr, tmp, 0); + bool result = cresult == kCFCompareEqualTo; + CFRelease(tmp); + return result; +} + +CFDateRef GetDateFieldFromCertificate(SecCertificateRef certificate, CFTypeRef oid) +{ + const void *keys[] = { oid }; + CFDictionaryRef dict = NULL; + CFErrorRef error; + CFDateRef date = NULL; + + CFArrayRef keySelection = CFArrayCreate(NULL, keys , sizeof(keys)/sizeof(keys[0]), &kCFTypeArrayCallBacks); + dict = SecCertificateCopyValues(certificate, keySelection, &error); + if (dict == NULL) + { + printErrorMsg("GetDateFieldFromCertificate: SecCertificateCopyValues", error); + goto release_ks; + } + CFDictionaryRef vals = dict ? CFDictionaryGetValue(dict, oid) : NULL; + CFNumberRef vals2 = vals ? CFDictionaryGetValue(vals, kSecPropertyKeyValue) : NULL; + if (vals2 == NULL) + goto release_dict; + + CFAbsoluteTime validityNotBefore; + if (CFNumberGetValue(vals2, kCFNumberDoubleType, &validityNotBefore)) + date = CFDateCreate(kCFAllocatorDefault,validityNotBefore); + +release_dict: + CFRelease(dict); +release_ks: + CFRelease(keySelection); + return date; +} + +CFArrayRef GetFieldsFromCertificate(SecCertificateRef certificate, CFTypeRef oid) +{ + CFMutableArrayRef fields = CFArrayCreateMutable(NULL, 0, NULL); + CertNameRef pCertName = createCertName(); + const void* keys[] = { oid, }; + CFDictionaryRef dict; + CFErrorRef error; + + CFArrayRef keySelection = CFArrayCreate(NULL, keys , 1, NULL); + + dict = SecCertificateCopyValues(certificate, keySelection, &error); + if (dict == NULL) { + printErrorMsg("GetFieldsFromCertificate: SecCertificateCopyValues", error); + CFRelease(keySelection); + CFRelease(fields); + return NULL; + } + CFDictionaryRef vals = CFDictionaryGetValue(dict, oid); + CFArrayRef vals2 = vals ? CFDictionaryGetValue(vals, kSecPropertyKeyValue) : NULL; + if (vals2) + { + for(int i = 0; i < CFArrayGetCount(vals2); i++) { + CFDictionaryRef subDict = CFArrayGetValueAtIndex(vals2, i); + CFStringRef label = CFDictionaryGetValue(subDict, kSecPropertyKeyLabel); + CFStringRef value = CFDictionaryGetValue(subDict, kSecPropertyKeyValue); + + if (CFStringCompare(label, kSecOIDEmailAddress, 0) == kCFCompareEqualTo) + CFArrayAppendValue((CFMutableArrayRef)pCertName->emailAddress, value); + else if (CFStringCompare(label, kSecOIDCountryName, 0) == kCFCompareEqualTo) + CFArrayAppendValue((CFMutableArrayRef)pCertName->countryName, value); + else if (CFStringCompare(label, kSecOIDOrganizationName, 0) == kCFCompareEqualTo) + CFArrayAppendValue((CFMutableArrayRef)pCertName->organization, value); + else if (CFStringCompare(label, kSecOIDOrganizationalUnitName, 0) == kCFCompareEqualTo) + CFArrayAppendValue((CFMutableArrayRef)pCertName->organizationalUnit, value); + else if (CFStringCompare(label, kSecOIDCommonName, 0) == kCFCompareEqualTo) + CFArrayAppendValue((CFMutableArrayRef)pCertName->commonName, value); + else if (CFStringCompare(label, kSecOIDDescription, 0) == kCFCompareEqualTo) + CFArrayAppendValue((CFMutableArrayRef)pCertName->description, value); + else if (CFStringCompare(label, kSecOIDStateProvinceName, 0) == kCFCompareEqualTo) + CFArrayAppendValue((CFMutableArrayRef)pCertName->stateName, value); + else if (CFStringCompare(label, kSecOIDLocalityName, 0) == kCFCompareEqualTo) + CFArrayAppendValue((CFMutableArrayRef)pCertName->localityName, value); + } + CFArrayAppendValue(fields, pCertName); + } + + CFRelease(dict); + CFRelease(keySelection); + return fields; +} + +CertDataRef createCertDataFromCertificate(SecCertificateRef certificate) +{ + CertDataRef pCertData = (CertDataRef)malloc(sizeof(CertData)); + pCertData->subject = GetFieldsFromCertificate(certificate, kSecOIDX509V1SubjectName); + pCertData->issuer = GetFieldsFromCertificate(certificate, kSecOIDX509V1IssuerName); + + CFDataRef data = SecCertificateCopyData(certificate); + if (data == NULL) + { + warnx("SecCertificateCopyData() returned NULL"); + destroyCertData(pCertData); + return NULL; + } + + unsigned char sha1[CC_SHA1_DIGEST_LENGTH]; + CC_SHA1(CFDataGetBytePtr(data), CFDataGetLength(data), sha1); + pCertData->sha1 = createHexString(sha1, CC_SHA1_DIGEST_LENGTH); + + unsigned char md5[CC_MD5_DIGEST_LENGTH]; + CC_MD5(CFDataGetBytePtr(data), CFDataGetLength(data), md5); + pCertData->md5 = createHexString((unsigned char*)md5, CC_MD5_DIGEST_LENGTH); + + CFDataRef serial = SecCertificateCopySerialNumber(certificate, NULL); + pCertData->serial = createHexString((unsigned char *)CFDataGetBytePtr(serial), CFDataGetLength(serial)); + CFRelease(serial); + + return pCertData; +} + +CFStringRef stringFromRange(const char *cstring, CFRange range) +{ + CFStringRef str = CFStringCreateWithBytes (NULL, (uint8*)&cstring[range.location], range.length, kCFStringEncodingUTF8, false); + CFMutableStringRef mutableStr = CFStringCreateMutableCopy(NULL, 0, str); + CFStringTrimWhitespace(mutableStr); + CFRelease(str); + return mutableStr; +} + +DescDataRef createDescData(const char *description, CFRange nameRange, CFRange valueRange) +{ + DescDataRef pRetVal = (DescDataRef)malloc(sizeof(DescData)); + + memset(pRetVal, 0, sizeof(DescData)); + + if (nameRange.length > 0) + pRetVal->name = stringFromRange(description, nameRange); + + if (valueRange.length > 0) + pRetVal->value = stringFromRange(description, valueRange); + +#if 0 + fprintf(stderr, "name = '%s', value = '%s'\n", + CFStringGetCStringPtr(pRetVal->name, kCFStringEncodingUTF8), + CFStringGetCStringPtr(pRetVal->value, kCFStringEncodingUTF8)); +#endif + return pRetVal; +} + +void destroyDescData(DescDataRef pData) +{ + if (pData->name) + CFRelease(pData->name); + + if (pData->value) + CFRelease(pData->value); + + free(pData); +} + +CFArrayRef createDescDataPairs(const char *description) +{ + int numChars = strlen(description); + CFRange nameRange, valueRange; + DescDataRef pData; + CFMutableArrayRef retVal = CFArrayCreateMutable(NULL, 0, NULL); + + int i = 0; + + nameRange = CFRangeMake(0, 0); + valueRange = CFRangeMake(0, 0); + bool bInValue = false; + + while(i < numChars) + { + if (!bInValue && (description[i] != ':')) + { + nameRange.length++; + } + else if (bInValue && (description[i] != ':')) + { + valueRange.length++; + } + else if(!bInValue) + { + bInValue = true; + valueRange.location = i + 1; + valueRange.length = 0; + } + else //(bInValue) + { + bInValue = false; + while(description[i] != ' ') + { + valueRange.length--; + i--; + } + + pData = createDescData(description, nameRange, valueRange); + CFArrayAppendValue(retVal, pData); + + nameRange.location = i + 1; + nameRange.length = 0; + } + + i++; + } + + pData = createDescData(description, nameRange, valueRange); + CFArrayAppendValue(retVal, pData); + return retVal; +} + +void arrayDestroyDescData(const void *val, void *context) +{ + DescDataRef pData = (DescDataRef) val; + destroyDescData(pData); +} + + +int parseNameComponent(CFStringRef dn, CFStringRef *pName, CFStringRef *pValue) +{ + CFArrayRef nameStrings = CFStringCreateArrayBySeparatingStrings(NULL, dn, kCertNameEquals); + + *pName = *pValue = NULL; + + if (CFArrayGetCount(nameStrings) != 2) + return 0; + + CFMutableStringRef str; + + str = CFStringCreateMutableCopy(NULL, 0, CFArrayGetValueAtIndex(nameStrings, 0)); + CFStringTrimWhitespace(str); + *pName = str; + + str = CFStringCreateMutableCopy(NULL, 0, CFArrayGetValueAtIndex(nameStrings, 1)); + CFStringTrimWhitespace(str); + *pValue = str; + + CFRelease(nameStrings); + return 1; +} + +int tryAppendSingleCertField(CertNameRef pCertName, CFArrayRef where, CFStringRef key, + CFStringRef name, CFStringRef value) +{ + if (CFStringCompareWithOptions(name, key, CFRangeMake(0, CFStringGetLength(name)), kCFCompareCaseInsensitive) + == kCFCompareEqualTo) { + CFArrayAppendValue((CFMutableArrayRef)where, value); + return 1; + } + return 0; +} + +int appendCertField(CertNameRef pCert, CFStringRef name, CFStringRef value) +{ + struct { + CFArrayRef field; + CFStringRef key; + } fields[] = { + { pCert->organization, kCertNameOrganization}, + { pCert->organizationalUnit, kCertNameOrganizationalUnit}, + { pCert->countryName, kCertNameCountry}, + { pCert->localityName, kCertNameLocality}, + { pCert->stateName, kCertNameState}, + { pCert->commonName, kCertNameCommonName}, + { pCert->emailAddress, kCertNameEmail}, + }; + int i; + int ret = 0; + + for (i=0; iname || !pDescData->value) + return 0; + + if (CFStringCompareWithOptions(pDescData->name, kCertDataSubjectName, CFRangeMake(0, CFStringGetLength(pDescData->name)), kCFCompareCaseInsensitive) == kCFCompareEqualTo) + ret = parseCertName(pDescData->value, (CFMutableArrayRef)pCertData->subject); + else if (CFStringCompareWithOptions(pDescData->name, kCertDataIssuerName, CFRangeMake(0, CFStringGetLength(pDescData->name)), kCFCompareCaseInsensitive) == kCFCompareEqualTo) + ret = parseCertName(pDescData->value, (CFMutableArrayRef)pCertData->issuer); + else if (CFStringCompareWithOptions(pDescData->name, kCertDataSha1Name, CFRangeMake(0, CFStringGetLength(pDescData->name)), kCFCompareCaseInsensitive) == kCFCompareEqualTo) + pCertData->sha1 = CFRetain(pDescData->value); + else if (CFStringCompareWithOptions(pDescData->name, kCertDataMd5Name, CFRangeMake(0, CFStringGetLength(pDescData->name)), kCFCompareCaseInsensitive) == kCFCompareEqualTo) + pCertData->md5 = CFRetain(pDescData->value); + else if (CFStringCompareWithOptions(pDescData->name, kCertDataSerialName, CFRangeMake(0, CFStringGetLength(pDescData->name)), kCFCompareCaseInsensitive) == kCFCompareEqualTo) + pCertData->serial = CFRetain(pDescData->value); + else + return 0; + + return ret; +} + +CertDataRef createCertDataFromString(const char *description) +{ + CertDataRef pCertData = (CertDataRef)malloc(sizeof(CertData)); + pCertData->subject = CFArrayCreateMutable(NULL, 0, NULL); + pCertData->issuer = CFArrayCreateMutable(NULL, 0, NULL); + pCertData->sha1 = NULL; + pCertData->md5 = NULL; + pCertData->serial = NULL; + + CFArrayRef pairs = createDescDataPairs(description); + for (int i=0; isubject) + { + CFArrayApplyFunction(pCertData->subject, CFRangeMake(0, CFArrayGetCount(pCertData->subject)), arrayDestroyCertName, NULL); + CFRelease(pCertData->subject); + } + + if (pCertData->issuer) + { + CFArrayApplyFunction(pCertData->issuer, CFRangeMake(0, CFArrayGetCount(pCertData->issuer)), arrayDestroyCertName, NULL); + CFRelease(pCertData->issuer); + } + + if (pCertData->sha1) + CFRelease(pCertData->sha1); + + if (pCertData->md5) + CFRelease(pCertData->md5); + + if (pCertData->serial) + CFRelease(pCertData->serial); + + free(pCertData); +} + +bool stringArrayMatchesTemplate(CFArrayRef strings, CFArrayRef templateArray) +{ + int templateCount, stringCount, i; + + templateCount = CFArrayGetCount(templateArray); + + if (templateCount > 0) + { + stringCount = CFArrayGetCount(strings); + if (stringCount != templateCount) + return false; + + for(i = 0;i < stringCount;i++) + { + CFStringRef str, template; + + template = (CFStringRef)CFArrayGetValueAtIndex(templateArray, i); + str = (CFStringRef)CFArrayGetValueAtIndex(strings, i); + + if (CFStringCompareWithOptions(template, str, CFRangeMake(0, CFStringGetLength(template)), kCFCompareCaseInsensitive) != kCFCompareEqualTo) + return false; + } + } + + return true; + +} + +bool certNameMatchesTemplate(CertNameRef pCertName, CertNameRef pTemplate) +{ + if (!stringArrayMatchesTemplate(pCertName->countryName, pTemplate->countryName)) + return false; + else if (!stringArrayMatchesTemplate(pCertName->organization, pTemplate->organization)) + return false; + else if (!stringArrayMatchesTemplate(pCertName->organizationalUnit, pTemplate->organizationalUnit)) + return false; + else if (!stringArrayMatchesTemplate(pCertName->commonName, pTemplate->commonName)) + return false; + else if (!stringArrayMatchesTemplate(pCertName->emailAddress, pTemplate->emailAddress)) + return false; + else if (!stringArrayMatchesTemplate(pCertName->stateName, pTemplate->stateName)) + return false; + else if (!stringArrayMatchesTemplate(pCertName->localityName, pTemplate->localityName)) + return false; + else + return true; +} + +bool certNameArrayMatchesTemplate(CFArrayRef certNameArray, CFArrayRef templateArray) +{ + int templateCount, certCount, i; + + templateCount = CFArrayGetCount(templateArray); + + if (templateCount > 0) + { + certCount = CFArrayGetCount(certNameArray); + if (certCount != templateCount) + return false; + + for(i = 0;i < certCount;i++) + { + CertNameRef pName, pTemplateName; + + pTemplateName = (CertNameRef)CFArrayGetValueAtIndex(templateArray, i); + pName = (CertNameRef)CFArrayGetValueAtIndex(certNameArray, i); + + if (!certNameMatchesTemplate(pName, pTemplateName)) + return false; + } + } + + return true; +} + +bool hexStringMatchesTemplate(CFStringRef str, CFStringRef template) +{ + if (template) + { + if (!str) + return false; + + CFMutableStringRef strMutable, templateMutable; + + strMutable = CFStringCreateMutableCopy(NULL, 0, str); + templateMutable = CFStringCreateMutableCopy(NULL, 0, template); + + CFStringFindAndReplace(strMutable, kStringSpace, kStringEmpty, CFRangeMake(0, CFStringGetLength(strMutable)), 0); + CFStringFindAndReplace(templateMutable, kStringSpace, kStringEmpty, CFRangeMake(0, CFStringGetLength(templateMutable)), 0); + + CFComparisonResult result = CFStringCompareWithOptions(templateMutable, strMutable, CFRangeMake(0, CFStringGetLength(templateMutable)), kCFCompareCaseInsensitive); + + CFRelease(strMutable); + CFRelease(templateMutable); + + if (result != kCFCompareEqualTo) + return false; + } + + return true; +} + +bool certDataMatchesTemplate(CertDataRef pCertData, CertDataRef pTemplate) +{ + if (!certNameArrayMatchesTemplate(pCertData->subject, pTemplate->subject)) + return false; + + if (!certNameArrayMatchesTemplate(pCertData->issuer, pTemplate->issuer)) + return false; + + if (!hexStringMatchesTemplate(pCertData->sha1, pTemplate->sha1)) + return false; + + if (!hexStringMatchesTemplate(pCertData->md5, pTemplate->md5)) + return false; + + if (!hexStringMatchesTemplate(pCertData->serial, pTemplate->serial)) + return false; + + return true; +} + +bool certExpired(SecCertificateRef certificate) +{ + bool result; + CFDateRef notAfter = GetDateFieldFromCertificate(certificate, kSecOIDX509V1ValidityNotAfter); + CFDateRef notBefore = GetDateFieldFromCertificate(certificate, kSecOIDX509V1ValidityNotBefore); + CFDateRef now = CFDateCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent()); + + if (!notAfter || !notBefore || !now) + { + warnx("GetDateFieldFromCertificate() returned NULL"); + result = true; + } + else + { + if (CFDateCompare(notBefore, now, NULL) != kCFCompareLessThan || + CFDateCompare(now, notAfter, NULL) != kCFCompareLessThan) + result = true; + else + result = false; + } + + CFRelease(notAfter); + CFRelease(notBefore); + CFRelease(now); + return result; +} + +SecIdentityRef findIdentity(CertDataRef pCertDataTemplate) +{ + const void *keys[] = { + kSecClass, + kSecReturnRef, + kSecMatchLimit + }; + const void *values[] = { + kSecClassIdentity, + kCFBooleanTrue, + kSecMatchLimitAll + }; + CFArrayRef result = NULL; + + CFDictionaryRef query = CFDictionaryCreate(NULL, keys, values, + sizeof(keys) / sizeof(*keys), + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + OSStatus status = SecItemCopyMatching(query, (CFTypeRef*)&result); + CFRelease(query); + if (status != noErr) + { + warnx ("No identities in keychain found"); + return NULL; + } + + SecIdentityRef bestIdentity = NULL; + CFDateRef bestNotBeforeDate = NULL; + + for (int i=0; i + * Copyright (C) 2013-2015 Vasily Kulikov + * + * 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 __cert_data_h__ +#define __cert_data_h__ + +#include +#include + +typedef struct _CertData +{ + CFArrayRef subject; + CFArrayRef issuer; + CFStringRef serial; + CFStringRef md5, sha1; +} CertData, *CertDataRef; + +CertDataRef createCertDataFromCertificate(SecCertificateRef certificate); +CertDataRef createCertDataFromString(const char *description); +void destroyCertData(CertDataRef pCertData); +bool certDataMatchesTemplate(CertDataRef pCertData, CertDataRef pTemplate); +void printCertData(CertDataRef pCertData); +SecIdentityRef findIdentity(CertDataRef pCertDataTemplate); + +#endif diff --git a/contrib/keychain-mcd/common_osx.c b/contrib/keychain-mcd/common_osx.c new file mode 100644 index 00000000000..3effa8b0c06 --- /dev/null +++ b/contrib/keychain-mcd/common_osx.c @@ -0,0 +1,94 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2010 Brian Raderman + * Copyright (C) 2013-2015 Vasily Kulikov + * + * 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 + */ + +/* +#include "config.h" +#include "syshead.h" +#include "common.h" +#include "buffer.h" +#include "error.h" +*/ + +#include "common_osx.h" +#include + +void printCFString(CFStringRef str) +{ + CFIndex bufferLength = CFStringGetLength(str) + 1; + char *pBuffer = (char*)malloc(sizeof(char) * bufferLength); + CFStringGetCString(str, pBuffer, bufferLength, kCFStringEncodingUTF8); + warnx("%s\n", pBuffer); + free(pBuffer); +} + +char* cfstringToCstr(CFStringRef str) +{ + CFIndex bufferLength = CFStringGetLength(str) + 1; + char *pBuffer = (char*)malloc(sizeof(char) * bufferLength); + CFStringGetCString(str, pBuffer, bufferLength, kCFStringEncodingUTF8); + return pBuffer; +} + +void appendHexChar(CFMutableStringRef str, unsigned char halfByte) +{ + if (halfByte < 10) + { + CFStringAppendFormat (str, NULL, CFSTR("%d"), halfByte); + } + else + { + char tmp[2] = {'A'+halfByte-10, 0}; + CFStringAppendCString(str, tmp, kCFStringEncodingUTF8); + } +} + +CFStringRef createHexString(unsigned char *pData, int length) +{ + unsigned char byte, low, high; + int i; + CFMutableStringRef str = CFStringCreateMutable(NULL, 0); + + for(i = 0;i < length;i++) + { + byte = pData[i]; + low = byte & 0x0F; + high = (byte >> 4); + + appendHexChar(str, high); + appendHexChar(str, low); + + if (i != (length - 1)) + CFStringAppendCString(str, " ", kCFStringEncodingUTF8); + } + + return str; +} + +void printHex(unsigned char *pData, int length) +{ + CFStringRef hexStr = createHexString(pData, length); + printCFString(hexStr); + CFRelease(hexStr); +} diff --git a/contrib/keychain-mcd/common_osx.h b/contrib/keychain-mcd/common_osx.h new file mode 100644 index 00000000000..42735486981 --- /dev/null +++ b/contrib/keychain-mcd/common_osx.h @@ -0,0 +1,36 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2010 Brian Raderman + * Copyright (C) 2013-2015 Vasily Kulikov + * + * 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 __common_osx_h__ +#define __common_osx_h__ + +#include + +void printCFString(CFStringRef str); +char* cfstringToCstr(CFStringRef str); +CFStringRef createHexString(unsigned char *pData, int length); +void printHex(unsigned char *pData, int length); + +#endif //__Common_osx_h__ diff --git a/contrib/keychain-mcd/crypto_osx.c b/contrib/keychain-mcd/crypto_osx.c new file mode 100644 index 00000000000..87ba09ba6cc --- /dev/null +++ b/contrib/keychain-mcd/crypto_osx.c @@ -0,0 +1,75 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2010 Brian Raderman + * Copyright (C) 2013-2015 Vasily Kulikov + * + * 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 + */ + + +#include +#include +#include + +#include "crypto_osx.h" +#include + +void printErrorMsg(const char *func, CFErrorRef error) +{ + CFStringRef desc = CFErrorCopyDescription(error); + warnx("%s failed: %s", func, CFStringGetCStringPtr(desc, kCFStringEncodingUTF8)); + CFRelease(desc); +} + +void printErrorStatusMsg(const char *func, OSStatus status) +{ + CFStringRef error; + error = SecCopyErrorMessageString(status, NULL); + if (error) + { + warnx("%s failed: %s", func, CFStringGetCStringPtr(error, kCFStringEncodingUTF8)); + CFRelease(error); + } + else + warnx("%s failed: %X", func, (int)status); +} + +void signData(SecIdentityRef identity, const uint8_t *from, int flen, uint8_t *to, size_t *tlen) +{ + SecKeyRef privateKey = NULL; + OSStatus status; + + status = SecIdentityCopyPrivateKey(identity, &privateKey); + if (status != noErr) + { + printErrorStatusMsg("signData: SecIdentityCopyPrivateKey", status); + *tlen = 0; + return; + } + + status = SecKeyRawSign(privateKey, kSecPaddingPKCS1, from, flen, to, tlen); + CFRelease(privateKey); + if (status != noErr) + { + printErrorStatusMsg("signData: SecKeyRawSign", status); + *tlen = 0; + return; + } +} diff --git a/contrib/keychain-mcd/crypto_osx.h b/contrib/keychain-mcd/crypto_osx.h new file mode 100644 index 00000000000..0da58b60acd --- /dev/null +++ b/contrib/keychain-mcd/crypto_osx.h @@ -0,0 +1,44 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2010 Brian Raderman + * Copyright (C) 2013-2015 Vasily Kulikov + * + * 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 __crypto_osx_h__ +#define __crypto_osx_h__ + +#include +#include + +extern OSStatus SecKeyRawSign ( + SecKeyRef key, + SecPadding padding, + const uint8_t *dataToSign, + size_t dataToSignLen, + uint8_t *sig, + size_t *sigLen +); + +void signData(SecIdentityRef identity, const uint8_t *from, int flen, uint8_t *to, size_t *tlen); +void printErrorMsg(const char *func, CFErrorRef error); + +#endif //__crypto_osx_h__ diff --git a/contrib/keychain-mcd/keychain-mcd.8 b/contrib/keychain-mcd/keychain-mcd.8 new file mode 100644 index 00000000000..676b1646da5 --- /dev/null +++ b/contrib/keychain-mcd/keychain-mcd.8 @@ -0,0 +1,161 @@ +.TH keychain-mcd 8 +.SH NAME + +keychain-mcd \- Mac OS X Keychain management daemon for OpenVPN + +.SH SYNOPSIS + +.B keychain-mcd +.I identity-template management-server-ip management-server-port +[ +.I password-file +] + +.SH DESCRIPTION + +.B keychain-mcd +is Mac OS X Keychain management daemon for OpenVPN. +It loads the certificate and private key from the Mac OSX Keychain (Mac OSX Only). +.B keychain-mcd +connects to OpenVPN via management interface and handles +certificate and private key commands (namely +.B NEED-CERTIFICATE +and +.B RSA-SIGN +commands). + +.B keychain-mcd +makes it possible to use any smart card supported by Mac OSX using the tokend interface, but also any +kind of certificate, residing in the Keychain, where you have access to +the private key. This option has been tested on the client side with an Aladdin eToken +on Mac OSX Leopard and with software certificates stored in the Keychain on Mac OS X. + +Note that Mac OS X might need to present the user with an authentication GUI when the Keychain +is accessed by keychain-mcd. + +Use +.B keychain-mcd +along with +.B --management-external-key +and/or +.B --management-external-cert +passed to +.B openvpn. + +.SH OPTIONS + +.TP +.BR identity-template + +A select string which is used to choose a keychain identity from +Mac OS X Keychain or +.I auto +if the identity template is passed from openvpn. + +\fBSubject\fR, \fBIssuer\fR, \fBSerial\fR, \fBSHA1\fR, \fBMD5\fR selectors can be used. + +To select a certificate based on a string search in the +certificate's subject and/or issuer: + +.nf + +"SUBJECT:c=US/o=Apple Inc./ou=me.com/cn=username ISSUER:c=US/o=Apple Computer, Inc./ou=Apple Computer Certificate Authority/cn=Apple .Mac Certificate Authority" + +.fi + +.I "Distinguished Name Component Abbreviations:" +.br +o = organization +.br +ou = organizational unit +.br +c = country +.br +l = locality +.br +st = state +.br +cn = common name +.br +e = email +.br + +All of the distinguished name components are optional, although you do need to specify at least one of them. You can +add spaces around the '/' and '=' characters, e.g. "SUBJECT: c = US / o = Apple Inc.". You do not need to specify +both the subject and the issuer, one or the other will work fine. +The identity searching algorithm will return the +certificate it finds that matches all of the criteria you have specified. +If there are several certificates matching all of the criteria then the youngest certificate is returned +(i.e. with the greater "not before" validity field). +You can also include the MD5 and/or SHA1 thumbprints and/or serial number +along with the subject and issuer. + +To select a certificate based on certificate's MD5 or SHA1 thumbprint: + +.nf +"SHA1: 30 F7 3A 7A B7 73 2A 98 54 33 4A A7 00 6F 6E AC EC D1 EF 02" + +"MD5: D5 F5 11 F1 38 EB 5F 4D CF 23 B6 94 E8 33 D8 B5" +.fi + +Again, you can include both the SHA1 and the MD5 thumbprints, but you can also use just one of them. +The thumbprint hex strings can easily be copy-and-pasted from the OSX Keychain Access GUI in the Applications/Utilities folder. +The hex string comparison is not case sensitive. + +To select a certificate based on certificate's serial number: + +"Serial: 3E 9B 6F 02 00 00 00 01 1F 20" + +If +.BR identity-template +equals to +.I auto +then the actual identity template is +obtained from argument of NEED-CERTIFICATE notification of openvpn. +In this case the argument of NEED-CERTIFICATE must begin with 'macosx-keychain:' prefix +and the rest of it must contain the actual identity template in the format described above. + + +.TP +.BR management-server-ip +OpenVPN management IP to connect to. +Both IPv4 and IPv6 addresses can be used. + +.TP +.BR management-server-port +OpenVPN management port to connect to. +Use +.B unix +for +.I management-server-port +and socket path for +.I management-server-ip +to connect to a local unix socket. + +.TP +.BR password-file + +Password file containing the management password on first line. +The password will be used to connect to +.B openvpn +management interface. + +Pass +.I password-file +to +.B keychain-mcd +if +.I pw-file +was specified in +.B --management +option to +.B openvpn. + + +.SH AUTHOR + +Vasily Kulikov + +.SH "SEE ALSO" + +.BR openvpn (8) diff --git a/contrib/keychain-mcd/main.c b/contrib/keychain-mcd/main.c new file mode 100644 index 00000000000..2263b7d3ea0 --- /dev/null +++ b/contrib/keychain-mcd/main.c @@ -0,0 +1,255 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2015 Vasily Kulikov + * + * 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 + */ + + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "cert_data.h" +#include "crypto_osx.h" +#include "../../src/openvpn/base64.h" + + +SecIdentityRef template_to_identity(const char *template) +{ + SecIdentityRef identity; + CertDataRef pCertDataTemplate = createCertDataFromString(template); + if (pCertDataTemplate == NULL) + errx(1, "Bad certificate template"); + identity = findIdentity(pCertDataTemplate); + if (identity == NULL) + errx(1, "No such identify"); + fprintf(stderr, "Identity found\n"); + destroyCertData(pCertDataTemplate); + return identity; +} + +int connect_to_management_server(const char *ip, const char *port) +{ + int fd; + struct sockaddr_un addr_un; + struct sockaddr *addr; + size_t addr_len; + + if (strcmp(port, "unix") == 0) { + addr = (struct sockaddr*)&addr_un; + addr_len = sizeof(addr_un); + + addr_un.sun_family = AF_UNIX; + strncpy(addr_un.sun_path, ip, sizeof(addr_un.sun_path)); + fd = socket(AF_UNIX, SOCK_STREAM, 0); + } + else { + int rv; + struct addrinfo *result; + struct addrinfo hints; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + rv = getaddrinfo(ip, port, &hints, &result); + if (rv < 0) + errx(1, "getaddrinfo: %s", gai_strerror(rv)); + if (result == NULL) + errx(1, "getaddrinfo returned 0 addressed"); + + /* Use the first found address */ + fd = socket(result->ai_family, result->ai_socktype, result->ai_protocol); + addr = result->ai_addr; + addr_len = result->ai_addrlen; + } + if (fd < 0) + err(1, "socket"); + + if (connect(fd, addr, addr_len) < 0) + err(1, "connect"); + + return fd; +} + +int is_prefix(const char *s, const char *prefix) +{ + return strncmp(s, prefix, strlen(prefix)) == 0; +} + +void handle_rsasign(FILE *man_file, SecIdentityRef identity, const char *input) +{ + const char *input_b64 = strchr(input, ':') + 1; + char *input_binary; + int input_len; + char *output_binary; + size_t output_len; + char *output_b64; + + input_len = strlen(input_b64)*8/6 + 4; + input_binary = malloc(input_len); + input_len = openvpn_base64_decode(input_b64, input_binary, input_len); + if (input_len < 0) + errx(1, "openvpn_base64_decode: overflow"); + + output_len = 1024; + output_binary = malloc(output_len); + signData(identity, (const uint8_t *)input_binary, input_len, (uint8_t *)output_binary, &output_len); + if (output_len == 0) + errx(1, "handle_rsasign: failed to sign data"); + + openvpn_base64_encode(output_binary, output_len, &output_b64); + fprintf(man_file, "rsa-sig\n%s\nEND\n", output_b64); + free(output_b64); + free(input_binary); + free(output_binary); + + fprintf(stderr, "Handled RSA_SIGN command\n"); +} + +void handle_needcertificate(FILE *man_file, SecIdentityRef identity) +{ + OSStatus status; + SecCertificateRef certificate = NULL; + CFDataRef data; + const unsigned char *cert; + size_t cert_len; + char *result_b64, *tmp_b64; + + status = SecIdentityCopyCertificate(identity, &certificate); + if (status != noErr) { + const char *msg = GetMacOSStatusErrorString(status); + err(1, "SecIdentityCopyCertificate() failed: %s", msg); + } + + data = SecCertificateCopyData(certificate); + if (data == NULL) + err(1, "SecCertificateCopyData() returned NULL"); + + cert = CFDataGetBytePtr(data); + cert_len = CFDataGetLength(data); + + openvpn_base64_encode(cert, cert_len, &result_b64); +#if 0 + fprintf(stderr, "certificate %s\n", result_b64); +#endif + + fprintf(man_file, "certificate\n"); + fprintf(man_file, "-----BEGIN CERTIFICATE-----\n"); + tmp_b64 = result_b64; + while (strlen(tmp_b64) > 64) { + fprintf(man_file, "%.64s\n", tmp_b64); + tmp_b64 += 64; + } + if (*tmp_b64) + fprintf(man_file, "%s\n", tmp_b64); + fprintf(man_file, "-----END CERTIFICATE-----\n"); + fprintf(man_file, "END\n"); + + free(result_b64); + CFRelease(data); + CFRelease(certificate); + + fprintf(stderr, "Handled NEED 'cert' command\n"); +} + +void management_loop(SecIdentityRef identity, int man_fd, const char *password) +{ + char *buffer = NULL; + size_t buffer_len = 0; + FILE *man = fdopen(man_fd, "w+"); + if (man == 0) + err(1, "fdopen"); + + if (password) + fprintf(man, "%s\n", password); + + while (1) { + if (getline(&buffer, &buffer_len, man) < 0) + err(1, "getline"); +#if 0 + fprintf(stderr, "M: %s", buffer); +#endif + + if (is_prefix(buffer, ">RSA_SIGN:")) + handle_rsasign(man, identity, buffer); + if (is_prefix(buffer, ">NEED-CERTIFICATE")) { + if (!identity) { + const char prefix[] = ">NEED-CERTIFICATE:macosx-keychain:"; + if (!is_prefix(buffer, prefix)) + errx(1, "No identity template is passed via command line and " \ + "NEED-CERTIFICATE management interface command " \ + "misses 'macosx-keychain' prefix."); + identity = template_to_identity(buffer+strlen(prefix)); + } + handle_needcertificate(man, identity); + } + if (is_prefix(buffer, ">FATAL")) + fprintf(stderr, "Fatal message from OpenVPN: %s\n", buffer+7); + if (is_prefix(buffer, ">INFO")) + fprintf(stderr, "INFO message from OpenVPN: %s\n", buffer+6); + } +} + +char *read_password(const char *fname) +{ + char *password = NULL; + FILE *pwf = fopen(fname, "r"); + size_t n = 0; + + if (pwf == NULL) + errx(1, "fopen(%s) failed", fname); + if (getline(&password, &n, pwf) < 0) + err(1, "getline"); + fclose(pwf); + return password; +} + +int main(int argc, char* argv[]) +{ + if (argc < 4) + err(1, "usage: %s []", argv[0]); + + char *identity_template = argv[1]; + char *s_ip = argv[2]; + char *s_port = argv[3]; + char *password = NULL; + int man_fd; + + if (argc > 4) { + char *s_pw_file = argv[4]; + password = read_password(s_pw_file); + } + + SecIdentityRef identity = NULL; + if (strcmp(identity_template, "auto")) + identity = template_to_identity(identity_template); + man_fd = connect_to_management_server(s_ip, s_port); + fprintf(stderr, "Successfully connected to openvpn\n"); + + management_loop(identity, man_fd, password); +} diff --git a/doc/management-notes.txt b/doc/management-notes.txt index ef39b855391..0265d5579d3 100644 --- a/doc/management-notes.txt +++ b/doc/management-notes.txt @@ -777,6 +777,28 @@ correct signature. This capability is intended to allow the use of arbitrary cryptographic service providers with OpenVPN via the management interface. +COMMAND -- certificate (OpenVPN 2.4 or higher) +---------------------------------------------- +Provides support for external storage of the certificate. Requires the +--management-external-cert option. This option can be used instead of "cert" +in client mode. On SSL protocol initialization a notification will be sent +to the management interface with a hint as follows: + +>NEED-CERTIFICATE:macosx-keychain:subject:o=OpenVPN-TEST + +The management interface client should use the hint to obtain the specific +SSL certificate and then return base64 encoded certificate as follows: + +certificate +[BASE64_CERT_LINE] +. +. +. +END + +This capability is intended to allow the use of certificates +stored outside of the filesystem (e.g. in Mac OS X Keychain) +with OpenVPN via the management interface. OUTPUT FORMAT ------------- diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 95515668f87..8b3e1a21aea 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -2591,6 +2591,15 @@ Allows usage for external private key file instead of option (client-only). .\"********************************************************* .TP +.B \-\-management-external-cert certificate-hint +Allows usage for external certificate instead of +.B \-\-cert +option (client-only). +.B certificate-hint +is an arbitrary string which is passed to a management +interface client as an argument of NEED-CERTIFICATE notification. +.\"********************************************************* +.TP .B \-\-management-forget-disconnect Make OpenVPN forget passwords when management session disconnects. diff --git a/src/openvpn/buffer.c b/src/openvpn/buffer.c index 46f874b2f8d..421d60e94ec 100644 --- a/src/openvpn/buffer.c +++ b/src/openvpn/buffer.c @@ -1066,8 +1066,10 @@ buffer_list_peek (struct buffer_list *ol) } void -buffer_list_aggregate (struct buffer_list *bl, const size_t max) +buffer_list_aggregate_separator (struct buffer_list *bl, const size_t max, const char *sep) { + int sep_len = strlen(sep); + if (bl->head) { struct buffer_entry *more = bl->head; @@ -1075,7 +1077,7 @@ buffer_list_aggregate (struct buffer_list *bl, const size_t max) int count = 0; for (count = 0; more && size <= max; ++count) { - size += BLEN(&more->buf); + size += BLEN(&more->buf) + sep_len; more = more->next; } @@ -1092,6 +1094,7 @@ buffer_list_aggregate (struct buffer_list *bl, const size_t max) { struct buffer_entry *next = e->next; buf_copy (&f->buf, &e->buf); + buf_write(&f->buf, sep, sep_len); free_buf (&e->buf); free (e); e = next; @@ -1104,6 +1107,12 @@ buffer_list_aggregate (struct buffer_list *bl, const size_t max) } } +void +buffer_list_aggregate (struct buffer_list *bl, const size_t max) +{ + buffer_list_aggregate_separator(bl, max, ""); +} + void buffer_list_pop (struct buffer_list *ol) { diff --git a/src/openvpn/buffer.h b/src/openvpn/buffer.h index 7469da634c8..5695f64f380 100644 --- a/src/openvpn/buffer.h +++ b/src/openvpn/buffer.h @@ -931,6 +931,7 @@ void buffer_list_advance (struct buffer_list *ol, int n); void buffer_list_pop (struct buffer_list *ol); void buffer_list_aggregate (struct buffer_list *bl, const size_t max); +void buffer_list_aggregate_separator (struct buffer_list *bl, const size_t max, const char *sep); struct buffer_list *buffer_list_file (const char *fn, int max_line_len); #endif /* BUFFER_H */ diff --git a/src/openvpn/manage.c b/src/openvpn/manage.c index e59776d273e..4f0945ca5c6 100644 --- a/src/openvpn/manage.c +++ b/src/openvpn/manage.c @@ -113,6 +113,8 @@ man_help () #ifdef MANAGMENT_EXTERNAL_KEY msg (M_CLIENT, "rsa-sig : Enter an RSA signature in response to >RSA_SIGN challenge"); msg (M_CLIENT, " Enter signature base64 on subsequent lines followed by END"); + msg (M_CLIENT, "certificate : Enter a client certificate in response to >NEED-CERT challenge"); + msg (M_CLIENT, " Enter certificate base64 on subsequent lines followed by END"); #endif msg (M_CLIENT, "signal s : Send signal s to daemon,"); msg (M_CLIENT, " s = SIGHUP|SIGTERM|SIGUSR1|SIGUSR2."); @@ -868,6 +870,12 @@ in_extra_dispatch (struct management *man) man->connection.ext_key_input = man->connection.in_extra; man->connection.in_extra = NULL; return; + case IEC_CERTIFICATE: + man->connection.ext_cert_state = EKS_READY; + buffer_list_free (man->connection.ext_cert_input); + man->connection.ext_cert_input = man->connection.in_extra; + man->connection.in_extra = NULL; + return; #endif } in_extra_reset (&man->connection, IER_RESET); @@ -1030,6 +1038,20 @@ man_rsa_sig (struct management *man) msg (M_CLIENT, "ERROR: The rsa-sig command is not currently available"); } +static void +man_certificate (struct management *man) +{ + struct man_connection *mc = &man->connection; + if (mc->ext_cert_state == EKS_SOLICIT) + { + mc->ext_cert_state = EKS_INPUT; + mc->in_extra_cmd = IEC_CERTIFICATE; + in_extra_reset (mc, IER_NEW); + } + else + msg (M_CLIENT, "ERROR: The certificate command is not currently available"); +} + #endif static void @@ -1311,6 +1333,10 @@ man_dispatch_command (struct management *man, struct status_output *so, const ch { man_rsa_sig (man); } + else if (streq (p[0], "certificate")) + { + man_certificate (man); + } #endif #ifdef ENABLE_PKCS11 else if (streq (p[0], "pkcs11-id-count")) @@ -3097,15 +3123,14 @@ management_query_user_pass (struct management *man, #ifdef MANAGMENT_EXTERNAL_KEY -char * /* returns allocated base64 signature */ -management_query_rsa_sig (struct management *man, - const char *b64_data) +int +management_query_multiline (struct management *man, + const char *b64_data, const char *prompt, const char *cmd, int *state, struct buffer_list **input) { struct gc_arena gc = gc_new (); - char *ret = NULL; + int ret = 0; volatile int signal_received = 0; struct buffer alert_msg = clear_buf(); - struct buffer *buf; const bool standalone_disabled_save = man->persist.standalone_disabled; struct man_connection *mc = &man->connection; @@ -3114,10 +3139,15 @@ management_query_rsa_sig (struct management *man, man->persist.standalone_disabled = false; /* This is so M_CLIENT messages will be correctly passed through msg() */ man->persist.special_state_msg = NULL; - mc->ext_key_state = EKS_SOLICIT; + *state = EKS_SOLICIT; - alert_msg = alloc_buf_gc (strlen(b64_data)+64, &gc); - buf_printf (&alert_msg, ">RSA_SIGN:%s", b64_data); + if (b64_data) { + alert_msg = alloc_buf_gc (strlen(b64_data)+strlen(prompt)+3, &gc); + buf_printf (&alert_msg, ">%s:%s", prompt, b64_data); + } else { + alert_msg = alloc_buf_gc (strlen(prompt)+3, &gc); + buf_printf (&alert_msg, ">%s", prompt); + } man_wait_for_client_connection (man, &signal_received, 0, MWCC_OTHER_WAIT); @@ -3135,40 +3165,107 @@ management_query_rsa_sig (struct management *man, man_check_for_signals (&signal_received); if (signal_received) goto done; - } while (mc->ext_key_state != EKS_READY); + } while (*state != EKS_READY); - if (buffer_list_defined(mc->ext_key_input)) - { - buffer_list_aggregate (mc->ext_key_input, 2048); - buf = buffer_list_peek (mc->ext_key_input); - if (buf && BLEN(buf) > 0) - { - ret = (char *) malloc(BLEN(buf)+1); - check_malloc_return(ret); - memcpy(ret, buf->data, BLEN(buf)); - ret[BLEN(buf)] = '\0'; - } - } + ret = 1; } done: - if (mc->ext_key_state == EKS_READY && ret) - msg (M_CLIENT, "SUCCESS: rsa-sig command succeeded"); - else if (mc->ext_key_state == EKS_INPUT || mc->ext_key_state == EKS_READY) - msg (M_CLIENT, "ERROR: rsa-sig command failed"); + if (*state == EKS_READY && ret) + msg (M_CLIENT, "SUCCESS: %s command succeeded", cmd); + else if (*state == EKS_INPUT || *state == EKS_READY) + msg (M_CLIENT, "ERROR: %s command failed", cmd); /* revert state */ man->persist.standalone_disabled = standalone_disabled_save; man->persist.special_state_msg = NULL; in_extra_reset (mc, IER_RESET); - mc->ext_key_state = EKS_UNDEF; - buffer_list_free (mc->ext_key_input); - mc->ext_key_input = NULL; + *state = EKS_UNDEF; gc_free (&gc); return ret; } +char * /* returns allocated base64 signature */ +management_query_multiline_flatten_newline (struct management *man, + const char *b64_data, const char *prompt, const char *cmd, int *state, struct buffer_list **input) +{ + int ok; + char *result = NULL; + struct buffer *buf; + + ok = management_query_multiline(man, b64_data, prompt, cmd, state, input); + if (ok && buffer_list_defined(*input)) + { + buffer_list_aggregate_separator (*input, 10000, "\n"); + buf = buffer_list_peek (*input); + if (buf && BLEN(buf) > 0) + { + result = (char *) malloc(BLEN(buf)+1); + check_malloc_return(result); + memcpy(result, buf->data, BLEN(buf)); + result[BLEN(buf)] = '\0'; + } + } + + buffer_list_free (*input); + *input = NULL; + + return result; +} + +char * /* returns allocated base64 signature */ +management_query_multiline_flatten (struct management *man, + const char *b64_data, const char *prompt, const char *cmd, int *state, struct buffer_list **input) +{ + int ok; + char *result = NULL; + struct buffer *buf; + + ok = management_query_multiline(man, b64_data, prompt, cmd, state, input); + if (ok && buffer_list_defined(*input)) + { + buffer_list_aggregate (*input, 2048); + buf = buffer_list_peek (*input); + if (buf && BLEN(buf) > 0) + { + result = (char *) malloc(BLEN(buf)+1); + check_malloc_return(result); + memcpy(result, buf->data, BLEN(buf)); + result[BLEN(buf)] = '\0'; + } + } + + buffer_list_free (*input); + *input = NULL; + + return result; +} + +char * /* returns allocated base64 signature */ +management_query_rsa_sig (struct management *man, + const char *b64_data) +{ + return management_query_multiline_flatten(man, b64_data, "RSA_SIGN", "rsa-sign", + &man->connection.ext_key_state, &man->connection.ext_key_input); +} + + +char* management_query_cert (struct management *man, const char *cert_name) +{ + const char prompt_1[] = "NEED-CERTIFICATE:"; + struct buffer buf_prompt = alloc_buf(strlen(cert_name) + 20); + buf_write(&buf_prompt, prompt_1, strlen(prompt_1)); + buf_write(&buf_prompt, cert_name, strlen(cert_name)+1); // +1 for \0 + + char *result; + result = management_query_multiline_flatten_newline(management, + NULL, (char*)buf_bptr(&buf_prompt), "certificate", + &man->connection.ext_cert_state, &man->connection.ext_cert_input); + free_buf(&buf_prompt); + return result; +} + #endif /* diff --git a/src/openvpn/manage.h b/src/openvpn/manage.h index 1c8dda6911c..8d6e87efa06 100644 --- a/src/openvpn/manage.h +++ b/src/openvpn/manage.h @@ -268,6 +268,7 @@ struct man_connection { # define IEC_CLIENT_AUTH 1 # define IEC_CLIENT_PF 2 # define IEC_RSA_SIGN 3 +# define IEC_CERTIFICATE 4 int in_extra_cmd; struct buffer_list *in_extra; #ifdef MANAGEMENT_DEF_AUTH @@ -281,6 +282,8 @@ struct man_connection { # define EKS_READY 3 int ext_key_state; struct buffer_list *ext_key_input; + int ext_cert_state; + struct buffer_list *ext_cert_input; #endif #endif struct event_set *es; @@ -338,6 +341,7 @@ struct management *management_init (void); #define MF_UP_DOWN (1<<10) #define MF_QUERY_REMOTE (1<<11) #define MF_QUERY_PROXY (1<<12) +#define MF_EXTERNAL_CERT (1<<13) bool management_open (struct management *man, const char *addr, @@ -420,6 +424,7 @@ void management_learn_addr (struct management *management, #ifdef MANAGMENT_EXTERNAL_KEY char *management_query_rsa_sig (struct management *man, const char *b64_data); +char* management_query_cert (struct management *man, const char *cert_name); #endif diff --git a/src/openvpn/options.c b/src/openvpn/options.c index df9a641074c..e8cf06a2913 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -1576,6 +1576,11 @@ show_settings (const struct options *o) SHOW_STR (ca_file); SHOW_STR (ca_path); SHOW_STR (dh_file); +#ifdef MANAGMENT_EXTERNAL_KEY + if((o->management_flags & MF_EXTERNAL_CERT)) + SHOW_PARM ("cert_file","EXTERNAL_CERT","%s"); + else +#endif SHOW_STR (cert_file); #ifdef MANAGMENT_EXTERNAL_KEY @@ -2152,6 +2157,8 @@ options_postprocess_verify_ce (const struct options *options, const struct conne #ifdef MANAGMENT_EXTERNAL_KEY if (options->management_flags & MF_EXTERNAL_KEY) msg(M_USAGE, "Parameter --management-external-key cannot be used when --pkcs11-provider is also specified."); + if (options->management_flags & MF_EXTERNAL_CERT) + msg(M_USAGE, "Parameter --management-external-cert cannot be used when --pkcs11-provider is also specified."); #endif if (options->pkcs12_file) msg(M_USAGE, "Parameter --pkcs12 cannot be used when --pkcs11-provider is also specified."); @@ -2183,6 +2190,8 @@ options_postprocess_verify_ce (const struct options *options, const struct conne #ifdef MANAGMENT_EXTERNAL_KEY if (options->management_flags & MF_EXTERNAL_KEY) msg(M_USAGE, "Parameter --management-external-key cannot be used when --cryptoapicert is also specified."); + if (options->management_flags & MF_EXTERNAL_CERT) + msg(M_USAGE, "Parameter --management-external-cert cannot be used when --cryptoapicert is also specified."); #endif } else @@ -2200,7 +2209,9 @@ options_postprocess_verify_ce (const struct options *options, const struct conne msg(M_USAGE, "Parameter --key cannot be used when --pkcs12 is also specified."); #ifdef MANAGMENT_EXTERNAL_KEY if (options->management_flags & MF_EXTERNAL_KEY) - msg(M_USAGE, "Parameter --external-management-key cannot be used when --pkcs12 is also specified."); + msg(M_USAGE, "Parameter --management-external-key cannot be used when --pkcs12 is also specified."); + if (options->management_flags & MF_EXTERNAL_CERT) + msg(M_USAGE, "Parameter --management-external-cert cannot be used when --pkcs12 is also specified."); #endif #endif } @@ -2242,6 +2253,9 @@ options_postprocess_verify_ce (const struct options *options, const struct conne } else { +#ifdef MANAGMENT_EXTERNAL_KEY + if (!(options->management_flags & MF_EXTERNAL_CERT)) +#endif notnull (options->cert_file, "certificate file (--cert) or PKCS#12 file (--pkcs12)"); #ifdef MANAGMENT_EXTERNAL_KEY if (!(options->management_flags & MF_EXTERNAL_KEY)) @@ -4244,6 +4258,12 @@ add_option (struct options *options, VERIFY_PERMISSION (OPT_P_GENERAL); options->management_flags |= MF_EXTERNAL_KEY; } + else if (streq (p[0], "management-external-cert") && p[1]) + { + VERIFY_PERMISSION (OPT_P_GENERAL); + options->management_flags |= MF_EXTERNAL_CERT; + options->management_certificate = p[1]; + } #endif #ifdef MANAGEMENT_DEF_AUTH else if (streq (p[0], "management-client-auth")) diff --git a/src/openvpn/options.h b/src/openvpn/options.h index 7a8b21e0b46..25b9e3c0613 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -370,6 +370,7 @@ struct options /* Mask of MF_ values of manage.h */ unsigned int management_flags; + const char *management_certificate; #endif #ifdef ENABLE_PLUGIN diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 222c8285eca..dce6c3042e8 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -520,10 +520,19 @@ init_ssl (const struct options *options, struct tls_root_ctx *new_ctx) } #endif #ifdef MANAGMENT_EXTERNAL_KEY - else if ((options->management_flags & MF_EXTERNAL_KEY) && options->cert_file) - { - tls_ctx_use_external_private_key(new_ctx, options->cert_file, - options->cert_file_inline); + else if ((options->management_flags & MF_EXTERNAL_KEY) && + (options->cert_file || options->management_flags & MF_EXTERNAL_CERT)) + { + if (options->cert_file) { + tls_ctx_use_external_private_key(new_ctx, options->cert_file, + options->cert_file_inline); + } else { + char *external_certificate = management_query_cert(management, + options->management_certificate); + tls_ctx_use_external_private_key(new_ctx, INLINE_FILE_TAG, + external_certificate); + free(external_certificate); + } } #endif else From 857c04ef06cd13d59c5b45332f07996e71372576 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Thu, 26 Mar 2015 01:01:29 +0100 Subject: [PATCH 020/643] Remove unneeded parameter 'first_time' from possibly_become_daemon() The static helper function possibly_become_daemon() is called only once, by do_init_first_time(), which checks 'first_time' to be true before calling possibly_become_daemon(). This makes the parameter useless. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1427328089-886-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/9555 Signed-off-by: Gert Doering --- src/openvpn/init.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/openvpn/init.c b/src/openvpn/init.c index b670a48fc91..b97d2da76a1 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -917,10 +917,10 @@ do_persist_tuntap (const struct options *options) * Return true if we did it. */ static bool -possibly_become_daemon (const struct options *options, const bool first_time) +possibly_become_daemon (const struct options *options) { bool ret = false; - if (first_time && options->daemon) + if (options->daemon) { ASSERT (!options->inetd); if (daemon (options->cd_dir != NULL, options->log) < 0) @@ -2771,7 +2771,7 @@ do_init_first_time (struct context *c) get_pid_file (c->options.writepid, &c0->pid_state); /* become a daemon if --daemon */ - c->did_we_daemonize = possibly_become_daemon (&c->options, c->first_time); + c->did_we_daemonize = possibly_become_daemon (&c->options); /* should we disable paging? */ if (c->options.mlock && c->did_we_daemonize) From 0e3f894098f9286ec3e703ce16fe9bda0cd2c74e Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Tue, 21 Apr 2015 22:49:12 +0200 Subject: [PATCH 021/643] Fix leftover 'if (false) ;' statements Commit a4b8f653ee5be9c2292c removed the #ifdefs for ENABLE_HTTP_PROXY and ENABLE_SOCKS, thus making this "if (false) ; else if (...)" construct superfluous. Spotted by David Sommerseth. Signed-off-by: Gert Doering Acked-by: Arne Schwabe Message-Id: <1429649352-21034-1-git-send-email-gert@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/9603 --- src/openvpn/socket.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c index f5c740d8e5a..afc1e606335 100644 --- a/src/openvpn/socket.c +++ b/src/openvpn/socket.c @@ -1575,10 +1575,8 @@ link_socket_init_phase1 (struct link_socket *sock, sock->sd = accept_from->sd; } - if (false) - ; /* are we running in HTTP proxy mode? */ - else if (sock->http_proxy) + if (sock->http_proxy) { ASSERT (sock->info.proto == PROTO_TCP_CLIENT); ASSERT (!sock->inetd); @@ -1793,9 +1791,7 @@ phase2_tcp_client (struct link_socket *sock, struct signal_info *sig_info) if (sig_info->signal_received) return; - if (false) - ; - else if (sock->http_proxy) + if (sock->http_proxy) { proxy_retry = establish_http_proxy_passthru (sock->http_proxy, sock->sd, From 4ad2b65d9deb3197d847d7dcc36715aa5394836f Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Tue, 28 Apr 2015 13:04:23 +0200 Subject: [PATCH 022/643] Print helpful error message on --mktun/--rmtun if not available. OpenVPN only supports --mktun/--rmtun to create/destroy persistant tunnels on Linux. On BSD OSes, "ifconfig tun0 create" can do the same job, so we do not actually need to support it - but the previous error message ("unknown option") wasn't helpful. So always accept the option now, and on non-supported systems, direct user to manpage. Trac #85 Signed-off-by: Gert Doering Acked-by: David Sommerseth Message-Id: <1430219063-12291-1-git-send-email-gert@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/9617 --- src/openvpn/init.c | 10 ++++++++-- src/openvpn/options.c | 2 -- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/openvpn/init.c b/src/openvpn/init.c index b97d2da76a1..42cb3e201b1 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -887,7 +887,6 @@ do_genkey (const struct options * options) bool do_persist_tuntap (const struct options *options) { -#ifdef ENABLE_FEATURE_TUN_PERSIST if (options->persist_config) { /* sanity check on options for --mktun or --rmtun */ @@ -901,14 +900,21 @@ do_persist_tuntap (const struct options *options) ) msg (M_FATAL|M_OPTERR, "options --mktun or --rmtun should only be used together with --dev"); +#ifdef ENABLE_FEATURE_TUN_PERSIST tuncfg (options->dev, options->dev_type, options->dev_node, options->persist_mode, options->username, options->groupname, &options->tuntap_options); if (options->persist_mode && options->lladdr) set_lladdr(options->dev, options->lladdr, NULL); return true; - } +#else + msg( M_FATAL|M_OPTERR, + "options --mktun and --rmtun are not available on your operating " + "system. Please check 'man tun' (or 'tap'), whether your system " + "supports using 'ifconfig %s create' / 'destroy' to create/remove " + "persistant tunnel interfaces.", options->dev ); #endif + } return false; } diff --git a/src/openvpn/options.c b/src/openvpn/options.c index e8cf06a2913..4f27336593e 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -7023,7 +7023,6 @@ add_option (struct options *options, options->pkcs11_id_management = true; } #endif -#ifdef ENABLE_FEATURE_TUN_PERSIST else if (streq (p[0], "rmtun")) { VERIFY_PERMISSION (OPT_P_GENERAL); @@ -7036,7 +7035,6 @@ add_option (struct options *options, options->persist_config = true; options->persist_mode = 1; } -#endif else if (streq (p[0], "peer-id")) { VERIFY_PERMISSION (OPT_P_PEER_ID); From 3a840739e43acc5ea15814be08debb9dbb7ba67c Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Tue, 28 Apr 2015 12:20:19 +0200 Subject: [PATCH 023/643] explain effect of --topology subnet on --ifconfig The fact that the second parameter of --ifconfig is no longer a "remote address" but a "netmask" when using --dev tun and --topology subnet was not documented clearly enough. Trac #370 Signed-off-by: Gert Doering Acked-by: Steffan Karger Message-Id: <1430216419-11943-1-git-send-email-gert@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/9616 --- doc/openvpn.8 | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 8b3e1a21aea..587b7697ab7 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -798,6 +798,12 @@ driver supports an command which sets a subnet instead of a remote endpoint IP address. This option exists in OpenVPN 2.1 or higher. + +Note: Using +.B \-\-topology subnet +changes the interpretation of the arguments of +.B \-\-ifconfig +to mean "address netmask", no longer "local remote". .\"********************************************************* .TP .B \-\-tun-ipv6 @@ -861,16 +867,21 @@ May be used in order to execute OpenVPN in unprivileged environment. Set TUN/TAP adapter parameters. .B l is the IP address of the local VPN endpoint. -For TUN devices, +For TUN devices in point-to-point mode, .B rn is the IP address of the remote VPN endpoint. -For TAP devices, +For TAP devices, or TUN devices used with +.B \-\-topology subnet, .B rn -is the subnet mask of the virtual ethernet segment +is the subnet mask of the virtual network segment which is being created or connected to. For TUN devices, which facilitate virtual -point-to-point IP connections, +point-to-point IP connections (when used in +.B \-\-topology net30 +or +.B p2p +mode), the proper usage of .B \-\-ifconfig is to use two private IP addresses @@ -885,7 +896,9 @@ you will be pinging across the VPN. For TAP devices, which provide the ability to create virtual -ethernet segments, +ethernet segments, or TUN devices in +.B --topology subnet +mode (which create virtual "multipoint networks"), .B \-\-ifconfig is used to set an IP address and subnet mask just as a physical From e473b7c4ce41a450645e0f89579bc25b4a7f7d49 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Mon, 27 Apr 2015 10:12:22 +0200 Subject: [PATCH 024/643] Remove size limit for files inlined in config As described in trac #484, the current inline file size limit of 10000 bytes is becoming an issue for some users. Since RSA keys and signature sizes are increasing, we need to adjust our limits. As #484 reports, 10000 can be too small for PKCS#12 files with 4K RSA keys. Instead of postponing this issue by increasing the static limit, dynamically increase the buffer size while reading. This keeps the memory usage limited but does allow for larger inlined files. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1430122342-11742-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/9607 Signed-off-by: Gert Doering --- src/openvpn/options.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 4f27336593e..6d5e58ea2ca 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -3698,12 +3698,21 @@ static char * read_inline_file (struct in_src *is, const char *close_tag, struct gc_arena *gc) { char line[OPTION_LINE_SIZE]; - struct buffer buf = alloc_buf (10000); + struct buffer buf = alloc_buf (8*OPTION_LINE_SIZE); char *ret; while (in_src_get (is, line, sizeof (line))) { if (!strncmp (line, close_tag, strlen (close_tag))) break; + if (!buf_safe (&buf, strlen(line))) + { + /* Increase buffer size */ + struct buffer buf2 = alloc_buf (buf.capacity * 2); + ASSERT (buf_copy (&buf2, &buf)); + buf_clear (&buf); + free_buf (&buf); + buf = buf2; + } buf_printf (&buf, "%s", line); } ret = string_alloc (BSTR (&buf), gc); From d55be0fb8091ff03af1319a27f68401d31ce8571 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Sat, 2 May 2015 21:07:05 +0200 Subject: [PATCH 025/643] Add note about file permissions and --crl-verify to manpage. Trac #522 Signed-off-by: Gert Doering Acked-by: Steffan Karger Message-Id: <1430593625-855-1-git-send-email-gert@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/9634 --- doc/openvpn.8 | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 587b7697ab7..b09f7d7c659 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -5068,6 +5068,11 @@ is a directory containing files named as revoked serial numbers requests a connection, where the client certificate serial number (decimal string) is the name of a file present in the directory, it will be rejected. + +Note: As the crl file (or directory) is read every time a peer connects, +if you are dropping root privileges with +.B --user, +make sure that this user has sufficient privileges to read the file. .\"********************************************************* .SS SSL Library information: .\"********************************************************* From 23b6ba6378bf3a3f5ceb828c8a4dd7cc38947d07 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sun, 3 May 2015 14:06:01 +0200 Subject: [PATCH 026/643] polarssl: remove code duplication in key_state_write_plaintext{, _const}() Both functions had almost exactly the same code. Instead of the code duplication, have key_state_write_plaintext() call key_state_write_plaintext_const() to do the actual work. This is just a bit of cleanup, it should not change any behaviour. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1430654761-26563-2-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/9640 Signed-off-by: Gert Doering --- src/openvpn/ssl_polarssl.c | 38 +++++--------------------------------- 1 file changed, 5 insertions(+), 33 deletions(-) diff --git a/src/openvpn/ssl_polarssl.c b/src/openvpn/ssl_polarssl.c index 8cb328e79c3..913585d0011 100644 --- a/src/openvpn/ssl_polarssl.c +++ b/src/openvpn/ssl_polarssl.c @@ -838,46 +838,18 @@ int key_state_write_plaintext (struct key_state_ssl *ks, struct buffer *buf) { int retval = 0; - perf_push (PERF_BIO_WRITE_PLAINTEXT); - ASSERT (NULL != ks); ASSERT (buf); - ASSERT (buf->len >= 0); - if (0 == buf->len) - { - perf_pop (); - return 0; - } - - retval = ssl_write(ks->ctx, BPTR(buf), buf->len); - - if (retval < 0) - { - perf_pop (); - if (POLARSSL_ERR_NET_WANT_WRITE == retval || POLARSSL_ERR_NET_WANT_READ == retval) - return 0; - msg (D_TLS_ERRORS, "TLS ERROR: write tls_write_plaintext error"); - return -1; - } + retval = key_state_write_plaintext_const(ks, BPTR(buf), BLEN(buf)); - if (retval != buf->len) + if (1 == retval) { - msg (D_TLS_ERRORS, - "TLS ERROR: write tls_write_plaintext incomplete %d/%d", - retval, buf->len); - perf_pop (); - return -1; + memset (BPTR (buf), 0, BLEN (buf)); /* erase data just written */ + buf->len = 0; } - /* successful write */ - dmsg (D_HANDSHAKE_VERBOSE, "write tls_write_plaintext %d bytes", retval); - - memset (BPTR (buf), 0, BLEN (buf)); /* erase data just written */ - buf->len = 0; - - perf_pop (); - return 1; + return retval; } int From 5f66f907cfc57b89110c08e50c7aab228e090911 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Tue, 5 May 2015 17:47:37 +0200 Subject: [PATCH 027/643] Improve --tls-cipher and --show-tls man page description As reported in trac tickets #304, #358 and #359 (and possibly more), the usage and interpretation of --tls-cipher (and --show-tls) is tricky. This patch extends the man page to explain those a bit better and point out that --tls-cipher is an expert feature (i.e. easy to get wrong). Also add a notice to the --show-tls output, referring to the man page explanation. Signed-off-by: Steffan Karger Acked-by: Arne Schwabe Message-Id: <1430840857-6123-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/9651 Signed-off-by: Gert Doering --- doc/openvpn.8 | 40 ++++++++++++++++++++++++++------------ src/openvpn/ssl_common.h | 5 +++++ src/openvpn/ssl_openssl.c | 2 +- src/openvpn/ssl_polarssl.c | 2 +- 4 files changed, 35 insertions(+), 14 deletions(-) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index b09f7d7c659..d2f47b3e0c2 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -4524,18 +4524,29 @@ separately negotiated over the existing secure TLS channel. Here, determines the derivation of the tunnel session keys. .\"********************************************************* .TP -.B \-\-tls-cipher l +.B \-\-tls\-cipher l A list .B l of allowable TLS ciphers delimited by a colon (":"). -If you require a high level of security, -you may want to set this parameter manually, to prevent a -version rollback attack where a man-in-the-middle attacker tries -to force two peers to negotiate to the lowest level -of security they both support. + +This setting can be used to ensure that certain cipher suites are used (or +not used) for the TLS connection. OpenVPN uses TLS to secure the control +channel, over which the keys that are used to protect the actual VPN traffic +are exchanged. + +The supplied list of ciphers is (after potential OpenSSL/IANA name translation) +simply supplied to the crypto library. Please see the OpenSSL and/or PolarSSL +documentation for details on the cipher list interpretation. + Use -.B \-\-show-tls -to see a list of supported TLS ciphers. +.B \-\-show\-tls +to see a list of TLS ciphers supported by your crypto library. + +Warning! +.B \-\-tls\-cipher +is an expert feature, which - if used correcly - can improve the security of +your VPN connection. But it is also easy to unwittingly use it to carefully +align a gun with your foot, or just break your connection. Use with care! The default for --tls-cipher is to use PolarSSL's default cipher list when using PolarSSL or "DEFAULT:!EXP:!PSK:!SRP:!kRSA" when using OpenSSL. @@ -5091,11 +5102,16 @@ Show all message digest algorithms to use with the option. .\"********************************************************* .TP -.B \-\-show-tls +.B \-\-show\-tls (Standalone) -Show all TLS ciphers (TLS used only as a control channel). The TLS -ciphers will be sorted from highest preference (most secure) to -lowest. +Show all TLS ciphers supported by the crypto library. OpenVPN uses TLS to +secure the control channel, over which the keys that are used to protect the +actual VPN traffic are exchanged. The TLS ciphers will be sorted from highest +preference (most secure) to lowest. + +Be aware that whether a cipher suite in this list can actually work depends on +the specific setup of both peers (e.g. both peers must support the cipher, and +an ECDSA cipher suite will not work if you are using an RSA certificate, etc.). .\"********************************************************* .TP .B \-\-show-engines diff --git a/src/openvpn/ssl_common.h b/src/openvpn/ssl_common.h index 6222bd67edb..bb1c1c281f6 100644 --- a/src/openvpn/ssl_common.h +++ b/src/openvpn/ssl_common.h @@ -511,4 +511,9 @@ struct tls_multi }; +#define SHOW_TLS_CIPHER_LIST_WARNING \ + "Be aware that that whether a cipher suite in this list can actually work\n" \ + "depends on the specific setup of both peers. See the man page entries of\n" \ + "--tls-cipher and --show-tls for more details.\n\n" + #endif /* SSL_COMMON_H_ */ diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c index d9abc6ea436..df9fa8734cb 100644 --- a/src/openvpn/ssl_openssl.c +++ b/src/openvpn/ssl_openssl.c @@ -1395,7 +1395,7 @@ show_available_tls_ciphers (const char *cipher_list) } } - printf ("\n"); + printf ("\n" SHOW_TLS_CIPHER_LIST_WARNING); SSL_free (ssl); SSL_CTX_free (tls_ctx.ctx); diff --git a/src/openvpn/ssl_polarssl.c b/src/openvpn/ssl_polarssl.c index 913585d0011..cb282d9f848 100644 --- a/src/openvpn/ssl_polarssl.c +++ b/src/openvpn/ssl_polarssl.c @@ -1099,7 +1099,7 @@ show_available_tls_ciphers (const char *cipher_list) printf ("%s\n", ssl_get_ciphersuite_name(*ciphers)); ciphers++; } - printf ("\n"); + printf ("\n" SHOW_TLS_CIPHER_LIST_WARNING); tls_ctx_free(&tls_ctx); } From d0f26fb524744a63615a1bf4e7ddcefcd102b328 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Mon, 4 May 2015 21:06:38 +0200 Subject: [PATCH 028/643] polarssl: disable 1/n-1 record splitting Disable record splitting (for now). OpenVPN assumes records are sent unfragmented, which is no longer a valid assumption when record splitting is enabled (which polarssl/mbedtls did in 1.3.10, see trac #524). Changing the code to deal with record splitting will require intrusive changes that need thorough review and testing. Since OpenVPN is not susceptible to BEAST (the data transmitted over the control channel is very hard to influence for a remote attacker), we can just disable record splitting as a quick fix. This gives us the time to develop a proper solution in the mean time, and test that thoroughly. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1430766398-17209-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/9646 Signed-off-by: Gert Doering --- src/openvpn/ssl_polarssl.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/openvpn/ssl_polarssl.c b/src/openvpn/ssl_polarssl.c index cb282d9f848..dd0fab0bd33 100644 --- a/src/openvpn/ssl_polarssl.c +++ b/src/openvpn/ssl_polarssl.c @@ -738,6 +738,14 @@ void key_state_ssl_init(struct key_state_ssl *ks_ssl, if (ssl_ctx->allowed_ciphers) ssl_set_ciphersuites (ks_ssl->ctx, ssl_ctx->allowed_ciphers); + /* Disable record splitting (for now). OpenVPN assumes records are sent + * unfragmented, and changing that will require thorough review and + * testing. Since OpenVPN is not susceptible to BEAST, we can just + * disable record splitting as a quick fix. */ +#if defined(POLARSSL_SSL_CBC_RECORD_SPLITTING) + ssl_set_cbc_record_splitting (ks_ssl->ctx, SSL_CBC_RECORD_SPLITTING_DISABLED); +#endif /* POLARSSL_SSL_CBC_RECORD_SPLITTING */ + /* Initialise authentication information */ if (is_server) ssl_set_dh_param_ctx (ks_ssl->ctx, ssl_ctx->dhm_ctx ); From 2d321609674a916c8cd7bbf0090e0342e90cca36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuli=20Sepp=C3=A4nen?= Date: Mon, 11 May 2015 13:19:14 +0300 Subject: [PATCH 029/643] Properly escape dashes on the man-page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On UTF-8 systems groff interprets unescaped dashes as hyphens and escaped dashes as minus signs. Unescaped dashes can cause problems when searching for or copying and pasting options. This patch ensures that dashes in command-line options are escaped and that everything else is left unescaped. This patch is for the Git "master" branch. Trac: 512 Signed-off-by: Samuli Seppänen Acked-by: Gert Doering Message-Id: <1431339554-20553-1-git-send-email-samuli@openvpn.net> URL: http://article.gmane.org/gmane.network.openvpn.devel/9674 Signed-off-by: Gert Doering --- doc/openvpn.8 | 1200 ++++++++++++++++++++++++------------------------- 1 file changed, 600 insertions(+), 600 deletions(-) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index d2f47b3e0c2..23cc789cf2b 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -234,7 +234,7 @@ Note that since UDP is connectionless, connection failure is defined by the .B \-\-ping and -.B \-\-ping-restart +.B \-\-ping\-restart options. Note the following corner case: If you use multiple @@ -273,7 +273,7 @@ chosen, providing a sort of basic load-balancing and failover capability. .\"********************************************************* .TP -.B \-\-remote-random-hostname +.B \-\-remote\-random\-hostname Prepend a random string (6 bytes, 12 hex characters) to hostname to prevent DNS caching. For example, "foo.bar.gov" would be modified to ".foo.bar.gov". @@ -292,7 +292,7 @@ and An OpenVPN client will try each connection profile sequentially until it achieves a successful connection. -.B \-\-remote-random +.B \-\-remote\-random can be used to initially "scramble" the connection list. @@ -314,20 +314,20 @@ remote 198.19.34.56 443 tcp remote 198.19.34.56 443 tcp -http-proxy 192.168.0.8 8080 -http-proxy-retry +http\-proxy 192.168.0.8 8080 +http\-proxy\-retry remote 198.19.36.99 443 tcp -http-proxy 192.168.0.8 8080 -http-proxy-retry +http\-proxy 192.168.0.8 8080 +http\-proxy\-retry -persist-key -persist-tun +persist\-key +persist\-tun pkcs12 client.p12 -ns-cert-type server +ns\-cert\-type server verb 3 .in -4 .ft @@ -346,30 +346,30 @@ a block: .B bind, -.B connect-retry, -.B connect-retry-max, -.B connect-timeout, -.B explicit-exit-notify, +.B connect\-retry, +.B connect\-retry\-max, +.B connect\-timeout, +.B explicit\-exit\-notify, .B float, .B fragment, -.B http-proxy, -.B http-proxy-option, -.B http-proxy-retry, -.B http-proxy-timeout, -.B link-mtu, +.B http\-proxy, +.B http\-proxy\-option, +.B http\-proxy\-retry, +.B http\-proxy\-timeout, +.B link\-mtu, .B local, .B lport, .B mssfix, -.B mtu-disc, +.B mtu\-disc, .B nobind, .B port, .B proto, .B remote, .B rport, -.B socks-proxy, -.B socks-proxy-retry, -.B tun-mtu and -.B tun-mtu-extra. +.B socks\-proxy, +.B socks\-proxy\-retry, +.B tun\-mtu and +.B tun\-mtu\-extra. A defaulting mechanism exists for specifying options to apply to all @@ -396,14 +396,14 @@ were declared in all blocks below it. .\"********************************************************* .TP -.B \-\-proto-force p +.B \-\-proto\-force p When iterating through connection profiles, only consider profiles using protocol .B p ('tcp'|'udp'). .\"********************************************************* .TP -.B \-\-remote-random +.B \-\-remote\-random When multiple .B \-\-remote address/ports are specified, or if connection profiles are being @@ -418,9 +418,9 @@ for communicating with remote host. .B p can be .B udp, -.B tcp-client, +.B tcp\-client, or -.B tcp-server. +.B tcp\-server. The default protocol is .B udp @@ -433,19 +433,19 @@ For UDP operation, should be specified on both peers. For TCP operation, one peer must use -.B \-\-proto tcp-server +.B \-\-proto tcp\-server and the other must use -.B \-\-proto tcp-client. +.B \-\-proto tcp\-client. A peer started with -.B tcp-server +.B tcp\-server will wait indefinitely for an incoming connection. A peer started with -.B tcp-client +.B tcp\-client will attempt to connect, and if that fails, will sleep for 5 seconds (adjustable via the -.B \-\-connect-retry +.B \-\-connect\-retry option) and try again infinite or up to N retries (adjustable via the -.B \-\-connect-retry-max +.B \-\-connect\-retry\-max option). Both TCP client and server will simulate a SIGUSR1 restart signal if either side resets the connection. @@ -465,21 +465,21 @@ application-level UDP protocols, or tunneling protocols which don't possess a built-in reliability layer. .\"********************************************************* .TP -.B \-\-connect-retry n +.B \-\-connect\-retry n Wait .B n seconds between connection attempts (default=5). .\"********************************************************* .TP -.B \-\-connect-timeout n +.B \-\-connect\-timeout n For -.B \-\-proto tcp-client, +.B \-\-proto tcp\-client, set connection timeout to .B n seconds (default=10). .\"********************************************************* .TP -.B \-\-connect-retry-max n +.B \-\-connect\-retry\-max n .B n specifies the number of times all .B \-\-remote @@ -491,12 +491,12 @@ as one would try each entry exactly once. A sucessful connection resets the counter. (default=umlimited). .\"********************************************************* .TP -.B \-\-show-proxy-settings +.B \-\-show\-proxy\-settings Show sensed HTTP or SOCKS proxy settings. Currently, only Windows clients support this option. .\"********************************************************* .TP -.B \-\-http-proxy server port [authfile|'auto'|'auto-nct'] [auth-method] +.B \-\-http\-proxy server port [authfile|'auto'|'auto\-nct'] [auth-method] Connect to remote host through an HTTP proxy at address .B server and port @@ -506,56 +506,56 @@ If HTTP Proxy-Authenticate is required, is a file containing a username and password on 2 lines, or "stdin" to prompt from console. -.B auth-method +.B auth\-method should be one of "none", "basic", or "ntlm". HTTP Digest authentication is supported as well, but only via the .B auto or -.B auto-nct +.B auto\-nct flags (below). The .B auto flag causes OpenVPN to automatically determine the -.B auth-method +.B auth\-method and query stdin or the management interface for username/password credentials, if required. This flag exists on OpenVPN 2.1 or higher. The -.B auto-nct +.B auto\-nct flag (no clear-text auth) instructs OpenVPN to automatically determine the authentication method, but to reject weak authentication protocols such as HTTP Basic Authentication. .\"********************************************************* .TP -.B \-\-http-proxy-retry +.B \-\-http\-proxy\-retry Retry indefinitely on HTTP proxy errors. If an HTTP proxy error occurs, simulate a SIGUSR1 reset. .\"********************************************************* .TP -.B \-\-http-proxy-timeout n +.B \-\-http\-proxy\-timeout n Set proxy timeout to .B n seconds, default=5. .\"********************************************************* .TP -.B \-\-http-proxy-option type [parm] +.B \-\-http\-proxy\-option type [parm] Set extended HTTP proxy options. Repeat to set multiple options. -.B VERSION version \-\- +.B VERSION version -- Set HTTP version number to .B version (default=1.0). -.B AGENT user-agent \-\- +.B AGENT user-agent -- Set HTTP "User-Agent" string to .B user-agent. -.B CUSTOM\-HEADER name content \-\- +.B CUSTOM\-HEADER name content -- Adds the custom Header with .B name as name and @@ -563,7 +563,7 @@ as name and as the content of the custom HTTP header. .\"********************************************************* .TP -.B \-\-socks-proxy server [port] [authfile] +.B \-\-socks\-proxy server [port] [authfile] Connect to remote host through a Socks5 proxy at address .B server and port @@ -574,12 +574,12 @@ and port "stdin" to prompt from console. .\"********************************************************* .TP -.B \-\-socks-proxy-retry +.B \-\-socks\-proxy\-retry Retry indefinitely on Socks proxy errors. If a Socks proxy error occurs, simulate a SIGUSR1 reset. .\"********************************************************* .TP -.B \-\-resolv-retry n +.B \-\-resolv\-retry n If hostname resolve fails for .B \-\-remote, retry resolve for @@ -591,7 +591,7 @@ Set to "infinite" to retry indefinitely. By default, -.B \-\-resolv-retry infinite +.B \-\-resolv\-retry infinite is enabled. You can disable by setting n=0. .\"********************************************************* .TP @@ -642,7 +642,7 @@ Don't use in .B \-\-mode server mode. Use a -.B \-\-client-connect +.B \-\-client\-connect script instead. See the "Environmental Variables" section below for @@ -686,11 +686,11 @@ TCP/UDP port number or name for remote. .TP .B \-\-bind [ipv6only] Bind to local address and port. This is the default unless any of -.B \-\-proto tcp-client +.B \-\-proto tcp\-client , -.B \-\-http-proxy +.B \-\-http\-proxy or -.B \-\-socks-proxy +.B \-\-socks\-proxy are used. If the @@ -727,7 +727,7 @@ devices encapsulate IPv4 or IPv6 (OSI Layer 3) while devices encapsulate Ethernet 802.3 (OSI Layer 2). .\"********************************************************* .TP -.B \-\-dev-type device-type +.B \-\-dev\-type device-type Which device type are we using? .B device-type should be @@ -756,7 +756,7 @@ topology. If you set this directive on the server, the .B \-\-server and -.B \-\-server-bridge +.B \-\-server\-bridge directives will automatically push your chosen topology setting to clients as well. This directive can also be manually pushed to clients. Like the .B \-\-dev @@ -778,7 +778,7 @@ This mode allocates a single IP address per connecting client. Only use when none of the connecting clients are Windows systems. This mode is functionally equivalent to the -.B \-\-ifconfig-pool-linear +.B \-\-ifconfig\-pool\-linear directive which is available in OpenVPN 2.0 and is now deprecated. .B subnet \-\- @@ -806,7 +806,7 @@ changes the interpretation of the arguments of to mean "address netmask", no longer "local remote". .\"********************************************************* .TP -.B \-\-tun-ipv6 +.B \-\-tun\-ipv6 Build a tun link capable of forwarding IPv6 traffic. Should be used in conjunction with .B \-\-dev tun @@ -818,16 +818,16 @@ if no specific IPv6 TUN support for your OS has been compiled into OpenVPN. See below for further IPv6-related configuration options. .\"********************************************************* .TP -.B \-\-dev-node node +.B \-\-dev\-node node Explicitly set the device node rather than using /dev/net/tun, /dev/tun, /dev/tap, etc. If OpenVPN cannot figure out whether .B node is a TUN or TAP device based on the name, you should also specify -.B \-\-dev-type tun +.B \-\-dev\-type tun or -.B \-\-dev-type tap. +.B \-\-dev\-type tap. Under Mac OS X this option can be used to specify the default tun implementation. Using @@ -846,7 +846,7 @@ is named in the Network Connections Control Panel or the raw GUID of the adapter enclosed by braces. The -.B \-\-show-adapters +.B \-\-show\-adapters option under Windows can also be used to enumerate all available TAP-Win32 adapters and will show both the network @@ -932,14 +932,14 @@ getting an IP address lease from a DHCP server. .\"********************************************************* .TP -.B \-\-ifconfig-noexec +.B \-\-ifconfig\-noexec Don't actually execute ifconfig/netsh commands, instead pass .B \-\-ifconfig parameters to scripts using environmental variables. .\"********************************************************* .TP -.B \-\-ifconfig-nowarn +.B \-\-ifconfig\-nowarn Don't output an options consistency check warning if the .B \-\-ifconfig @@ -947,7 +947,7 @@ option on this side of the connection doesn't match the remote side. This is useful when you want to retain the overall benefits of the options consistency check (also see -.B \-\-disable-occ +.B \-\-disable\-occ option) while only disabling the ifconfig component of the check. @@ -955,7 +955,7 @@ For example, if you have a configuration where the local host uses .B \-\-ifconfig but the remote host does not, use -.B \-\-ifconfig-nowarn +.B \-\-ifconfig\-nowarn on the local host. This option will also silence warnings about potential @@ -977,11 +977,11 @@ while at the same time providing portable semantics across OpenVPN's platform space. .B netmask -default \-\- 255.255.255.255 +default -- 255.255.255.255 .B gateway -default \-\- taken from -.B \-\-route-gateway +default -- taken from +.B \-\-route\-gateway or the second parameter to .B \-\-ifconfig when @@ -989,8 +989,8 @@ when is specified. .B metric -default \-\- taken from -.B \-\-route-metric +default -- taken from +.B \-\-route\-metric otherwise 0. The default can be specified by leaving an option blank or setting @@ -1005,9 +1005,9 @@ also be specified as a DNS or /etc/hosts file resolvable name, or as one of three special keywords: .B vpn_gateway -\-\- The remote VPN endpoint address +-- The remote VPN endpoint address (derived either from -.B \-\-route-gateway +.B \-\-route\-gateway or the second parameter to .B \-\-ifconfig when @@ -1015,16 +1015,16 @@ when is specified). .B net_gateway -\-\- The pre-existing IP default gateway, read from the routing +-- The pre-existing IP default gateway, read from the routing table (not supported on all OSes). .B remote_host -\-\- The +-- The .B \-\-remote address if OpenVPN is being run in client mode, and is undefined in server mode. .\"********************************************************* .TP -.B \-\-route-gateway gw|'dhcp' +.B \-\-route\-gateway gw|'dhcp' Specify a default gateway .B gw for use with @@ -1037,14 +1037,14 @@ the gateway address will be extracted from a DHCP negotiation with the OpenVPN server-side LAN. .\"********************************************************* .TP -.B \-\-route-metric m +.B \-\-route\-metric m Specify a default metric .B m for use with .B \-\-route. .\"********************************************************* .TP -.B \-\-route-delay [n] [w] +.B \-\-route\-delay [n] [w] Delay .B n seconds (default=0) after connection @@ -1052,7 +1052,7 @@ establishment, before adding routes. If .B n is 0, routes will be added immediately upon connection establishment. If -.B \-\-route-delay +.B \-\-route\-delay is omitted, routes will be added immediately after TUN/TAP device open and .B \-\-up @@ -1070,18 +1070,18 @@ tap adapter addresses. The delay will give the DHCP handshake time to complete before routes are added. On Windows, -.B \-\-route-delay +.B \-\-route\-delay tries to be more intelligent by waiting .B w seconds (w=30 by default) for the TAP-Win32 adapter to come up before adding routes. .\"********************************************************* .TP -.B \-\-route-up cmd +.B \-\-route\-up cmd Run command .B cmd after routes are added, subject to -.B \-\-route-delay. +.B \-\-route\-delay. .B cmd consists of a path to script (or executable program), optionally @@ -1092,7 +1092,7 @@ See the "Environmental Variables" section below for additional parameters passed as environmental variables. .\"********************************************************* .TP -.B \-\-route-pre-down cmd +.B \-\-route\-pre\-down cmd Run command .B cmd before routes are removed upon disconnection. @@ -1106,13 +1106,13 @@ See the "Environmental Variables" section below for additional parameters passed as environmental variables. .\"********************************************************* .TP -.B \-\-route-noexec +.B \-\-route\-noexec Don't add or remove routes automatically. Instead pass routes to -.B \-\-route-up +.B \-\-route\-up script using environmental variables. .\"********************************************************* .TP -.B \-\-route-nopull +.B \-\-route\-nopull When used with .B \-\-client or @@ -1126,16 +1126,16 @@ however note that this option still allows the server to set the TCP/IP properties of the client's TUN/TAP interface. .\"********************************************************* .TP -.B \-\-allow-pull-fqdn +.B \-\-allow\-pull\-fqdn Allow client to pull DNS names from server (rather than being limited to IP address) for .B \-\-ifconfig, .B \-\-route, and -.B \-\-route-gateway. +.B \-\-route\-gateway. .\"********************************************************* .TP -.B \-\-client-nat snat|dnat network netmask alias +.B \-\-client\-nat snat|dnat network netmask alias This pushable client option sets up a stateless one-to-one NAT rule on packet addresses (not ports), and is useful in cases where routes or ifconfig settings pushed to the client would @@ -1160,7 +1160,7 @@ for debugging info showing the transformation of src/dest addresses in packets. .\"********************************************************* .TP -.B \-\-redirect-gateway flags... +.B \-\-redirect\-gateway flags... Automatically execute routing commands to cause all outgoing IP traffic to be redirected over the VPN. This is a client-side option. @@ -1179,7 +1179,7 @@ Delete the default gateway route. .B (3) Set the new default gateway to be the VPN endpoint address (derived either from -.B \-\-route-gateway +.B \-\-route\-gateway or the second parameter to .B \-\-ifconfig when @@ -1206,43 +1206,43 @@ Try to automatically determine whether to enable .B local flag above. -.B def1 \-\- +.B def1 -- Use this flag to override the default gateway by using 0.0.0.0/1 and 128.0.0.0/1 rather than 0.0.0.0/0. This has the benefit of overriding but not wiping out the original default gateway. -.B bypass-dhcp \-\- +.B bypass-dhcp -- Add a direct route to the DHCP server (if it is non-local) which bypasses the tunnel (Available on Windows clients, may not be available on non-Windows clients). -.B bypass-dns \-\- +.B bypass-dns -- Add a direct route to the DNS server(s) (if they are non-local) which bypasses the tunnel (Available on Windows clients, may not be available on non-Windows clients). -.B block-local \-\- +.B block-local -- Block access to local LAN when the tunnel is active, except for the LAN gateway itself. This is accomplished by routing the local LAN (except for the LAN gateway address) into the tunnel. .\"********************************************************* .TP -.B \-\-link-mtu n +.B \-\-link\-mtu n Sets an upper bound on the size of UDP packets which are sent between OpenVPN peers. It's best not to set this parameter unless you know what you're doing. .\"********************************************************* .\"********************************************************* .TP -.B \-\-redirect-private [flags] -Like \-\-redirect-gateway, but omit actually changing the default +.B \-\-redirect\-private [flags] +Like \-\-redirect\-gateway, but omit actually changing the default gateway. Useful when pushing private subnets. .\"********************************************************* .TP -.B \-\-tun-mtu n +.B \-\-tun\-mtu n Take the TUN device MTU to be .B n and derive the link MTU @@ -1264,11 +1264,11 @@ and/or options to deal with MTU sizing issues. .\"********************************************************* .TP -.B \-\-tun-mtu-extra n +.B \-\-tun\-mtu\-extra n Assume that the TUN/TAP device might return as many as .B n bytes more than the -.B \-\-tun-mtu +.B \-\-tun\-mtu size on read. This parameter defaults to 0, which is sufficient for most TUN devices. TAP devices may introduce additional overhead in excess of the MTU size, and a setting of 32 is the default when TAP devices are used. @@ -1276,30 +1276,30 @@ This parameter only controls internal OpenVPN buffer sizing, so there is no transmission overhead associated with using a larger value. .\"********************************************************* .TP -.B \-\-mtu-disc type +.B \-\-mtu\-disc type Should we do Path MTU discovery on TCP/UDP channel? Only supported on OSes such as Linux that supports the necessary system call to set. .B 'no' -\-\- Never send DF (Don't Fragment) frames +-- Never send DF (Don't Fragment) frames .br .B 'maybe' -\-\- Use per-route hints +-- Use per-route hints .br .B 'yes' -\-\- Always DF (Don't Fragment) +-- Always DF (Don't Fragment) .br .\"********************************************************* .TP -.B \-\-mtu-test +.B \-\-mtu\-test To empirically measure MTU on connection startup, add the -.B \-\-mtu-test +.B \-\-mtu\-test option to your configuration. OpenVPN will send ping packets of various sizes to the remote peer and measure the largest packets which were successfully received. The -.B \-\-mtu-test +.B \-\-mtu\-test process normally takes about 3 minutes to complete. .\"********************************************************* .TP @@ -1313,7 +1313,7 @@ bytes. The .B max parameter is interpreted in the same way as the -.B \-\-link-mtu +.B \-\-link\-mtu parameter, i.e. the UDP packet size after encapsulation overhead has been added in, but not including the UDP header itself. @@ -1355,7 +1355,7 @@ bytes. The default value is The .B max parameter is interpreted in the same way as the -.B \-\-link-mtu +.B \-\-link\-mtu parameter, i.e. the UDP packet size after encapsulation overhead has been added in, but not including the UDP header itself. @@ -1405,7 +1405,7 @@ Therefore, one could lower the maximum UDP packet size to 1300 (a good first try for solving MTU-related connection problems) with the following options: -.B \-\-tun-mtu 1500 \-\-fragment 1300 \-\-mssfix +.B \-\-tun\-mtu 1500 \-\-fragment 1300 \-\-mssfix .\"********************************************************* .TP .B \-\-sndbuf size @@ -1424,7 +1424,7 @@ matched in policy routing and packetfilter rules. This option is only supported in Linux and does nothing on other operating systems. .\"********************************************************* .TP -.B \-\-socket-flags flags... +.B \-\-socket\-flags flags... Apply the given flags to the OpenVPN transport socket. Currently, only .B TCP_NODELAY @@ -1516,9 +1516,9 @@ seconds (specify on both peers to cause ping packets to be sent in both directions since OpenVPN ping packets are not echoed like IP ping packets). When used in one of OpenVPN's secure modes (where -.B \-\-secret, \-\-tls-server, +.B \-\-secret, \-\-tls\-server, or -.B \-\-tls-client +.B \-\-tls\-client is specified), the ping packet will be cryptographically secure. @@ -1531,11 +1531,11 @@ pass will not time out. (2) To provide a basis for the remote to test the existence of its peer using the -.B \-\-ping-exit +.B \-\-ping\-exit option. .\"********************************************************* .TP -.B \-\-ping-exit n +.B \-\-ping\-exit n Causes OpenVPN to exit after .B n seconds pass without reception of a ping @@ -1543,21 +1543,21 @@ or other packet from remote. This option can be combined with .B \-\-inactive, \-\-ping, and -.B \-\-ping-exit +.B \-\-ping\-exit to create a two-tiered inactivity disconnect. For example, -.B openvpn [options...] \-\-inactive 3600 \-\-ping 10 \-\-ping-exit 60 +.B openvpn [options...] \-\-inactive 3600 \-\-ping 10 \-\-ping\-exit 60 when used on both peers will cause OpenVPN to exit within 60 seconds if its peer disconnects, but will exit after one hour if no actual tunnel data is exchanged. .\"********************************************************* .TP -.B \-\-ping-restart n +.B \-\-ping\-restart n Similar to -.B \-\-ping-exit, +.B \-\-ping\-exit, but trigger a .B SIGUSR1 restart after @@ -1578,11 +1578,11 @@ If the peer cannot be reached, a restart will be triggered, causing the hostname used with .B \-\-remote to be re-resolved (if -.B \-\-resolv-retry +.B \-\-resolv\-retry is also specified). In server mode, -.B \-\-ping-restart, \-\-inactive, +.B \-\-ping\-restart, \-\-inactive, or any other type of internally generated signal will always be applied to individual client instance objects, never to whole server itself. @@ -1591,14 +1591,14 @@ which would normally cause a restart, will cause the deletion of the client instance object instead. In client mode, the -.B \-\-ping-restart +.B \-\-ping\-restart parameter is set to 120 seconds by default. This default will hold until the client pulls a replacement value from the server, based on the .B \-\-keepalive setting in the server configuration. To disable the 120 second default, set -.B \-\-ping-restart 0 +.B \-\-ping\-restart 0 on the client. See the signals section below for more information @@ -1608,15 +1608,15 @@ on Note that the behavior of .B SIGUSR1 can be modified by the -.B \-\-persist-tun, \-\-persist-key, \-\-persist-local-ip, +.B \-\-persist\-tun, \-\-persist\-key, \-\-persist\-local\-ip, and -.B \-\-persist-remote-ip +.B \-\-persist\-remote\-ip options. Also note that -.B \-\-ping-exit +.B \-\-ping\-exit and -.B \-\-ping-restart +.B \-\-ping\-restart are mutually exclusive and cannot be used together. .\"********************************************************* .TP @@ -1624,7 +1624,7 @@ are mutually exclusive and cannot be used together. A helper directive designed to simplify the expression of .B \-\-ping and -.B \-\-ping-restart +.B \-\-ping\-restart in server mode configurations. The server timeout is set twice the value of the second argument. @@ -1640,22 +1640,22 @@ expands as follows: .in +4 if mode server: ping 10 - ping-restart 120 + ping\-restart 120 push "ping 10" - push "ping-restart 60" + push "ping\-restart 60" else ping 10 - ping-restart 60 + ping\-restart 60 .in -4 .ft .fi .\"********************************************************* .TP -.B \-\-ping-timer-rem +.B \-\-ping\-timer\-rem Run the -.B \-\-ping-exit +.B \-\-ping\-exit / -.B \-\-ping-restart +.B \-\-ping\-restart timer only if we have a remote address. Use this option if you are starting the daemon in listen mode (i.e. without an explicit .B \-\-remote @@ -1663,12 +1663,12 @@ peer), and you don't want to start clocking timeouts until a remote peer connects. .\"********************************************************* .TP -.B \-\-persist-tun +.B \-\-persist\-tun Don't close and reopen TUN/TAP device or run up/down scripts across .B SIGUSR1 or -.B \-\-ping-restart +.B \-\-ping\-restart restarts. .B SIGUSR1 @@ -1678,11 +1678,11 @@ but which offers finer-grained control over reset options. .\"********************************************************* .TP -.B \-\-persist-key +.B \-\-persist\-key Don't re-read key files across .B SIGUSR1 or -.B \-\-ping-restart. +.B \-\-ping\-restart. This option can be combined with .B \-\-user nobody @@ -1698,21 +1698,21 @@ This option solves the problem by persisting keys across resets, so they don't need to be re-read. .\"********************************************************* .TP -.B \-\-persist-local-ip +.B \-\-persist\-local\-ip Preserve initially resolved local IP address and port number across .B SIGUSR1 or -.B \-\-ping-restart +.B \-\-ping\-restart restarts. .\"********************************************************* .TP -.B \-\-persist-remote-ip +.B \-\-persist\-remote\-ip Preserve most recently authenticated remote IP address and port number across .B SIGUSR1 or -.B \-\-ping-restart +.B \-\-ping\-restart restarts. .\"********************************************************* .TP @@ -1790,19 +1790,19 @@ In this context, the last command line parameter passed to the script will be .I init. If the -.B \-\-up-restart +.B \-\-up\-restart option is also used, the up script will be called for restarts as well. A restart is considered to be a partial reinitialization of OpenVPN where the TUN/TAP instance is preserved (the -.B \-\-persist-tun +.B \-\-persist\-tun option will enable such preservation). A restart can be generated by a SIGUSR1 signal, a -.B \-\-ping-restart +.B \-\-ping\-restart timeout, or a connection reset when the TCP protocol is enabled with the .B \-\-proto option. If a restart occurs, and -.B \-\-up-restart +.B \-\-up\-restart has been specified, the up script will be called with .I restart as the last parameter. @@ -1814,7 +1814,7 @@ script can be called in both an initialization and restart context. 9999 is blocked by your firewall. Also, the example will run indefinitely, so you should abort with control-c). -.B openvpn \-\-dev tun \-\-port 9999 \-\-verb 4 \-\-ping-restart 10 \-\-up 'echo up' \-\-down 'echo down' \-\-persist-tun \-\-up-restart +.B openvpn \-\-dev tun \-\-port 9999 \-\-verb 4 \-\-ping\-restart 10 \-\-up 'echo up' \-\-down 'echo down' \-\-persist\-tun \-\-up\-restart Note that OpenVPN also provides the .B \-\-ifconfig @@ -1833,10 +1833,10 @@ and remote endpoints on the command line to the .B \-\-up script so that they can be used to configure routes such as: -.B route add -net 10.0.0.0 netmask 255.255.255.0 gw $5 +.B route add \-net 10.0.0.0 netmask 255.255.255.0 gw $5 .\"********************************************************* .TP -.B \-\-up-delay +.B \-\-up\-delay Delay TUN/TAP open and possible .B \-\-up script execution @@ -1882,13 +1882,13 @@ your script will also run at reduced privilege. .\"********************************************************* .TP -.B \-\-down-pre +.B \-\-down\-pre Call .B \-\-down cmd/script before, rather than after, TUN/TAP close. .\"********************************************************* .TP -.B \-\-up-restart +.B \-\-up\-restart Enable the .B \-\-up and @@ -1927,10 +1927,10 @@ Versions prior to OpenVPN 2.3.3 will always ignore options set with the directive. See also -.B \-\-ignore-unknown-option +.B \-\-ignore\-unknown\-option .\"********************************************************* .TP -.B \-\-setenv-safe name value +.B \-\-setenv\-safe name value Set a custom environmental variable .B OPENVPN_name=value to pass to script. @@ -1941,13 +1941,13 @@ is a safety precaution to prevent a LD_PRELOAD style attack from a malicious or compromised server. .\"********************************************************* .TP -.B \-\-ignore-unknown-option opt1 opt2 opt3 ... optN +.B \-\-ignore\-unknown\-option opt1 opt2 opt3 ... optN When one of options .B opt1 ... optN is encountered in the configuration file the configuration file parsing does not fail if this OpenVPN version does not support the option. Multiple -.B \-\-ignore-unknown-option +.B \-\-ignore\-unknown\-option options can be given to support a larger number of options to ignore. This option should be used with caution, as there are good security @@ -1956,11 +1956,11 @@ config file. Having said that, there are valid reasons for wanting new software features to gracefully degrade when encountered by older software versions. -.B \-\-ignore-unknown-option +.B \-\-ignore\-unknown\-option is available since OpenVPN 2.3.3. .\"********************************************************* .TP -.B \-\-script-security level +.B \-\-script\-security level This directive offers policy-level control over OpenVPN's usage of external programs and scripts. Lower .B level @@ -2015,7 +2015,7 @@ flag was removed is due to the security implications with shell expansions when executing scripts via the system() call. .\"********************************************************* .TP -.B \-\-disable-occ +.B \-\-disable\-occ Don't output a warning message if option inconsistencies are detected between peers. An example of an option inconsistency would be where one peer uses .B \-\-dev tun @@ -2143,9 +2143,9 @@ allow many things required only during initialization. Like with chroot, complications can result when scripts or restarts are executed after the setcon operation, which is why you should really consider using the -.B \-\-persist-key +.B \-\-persist\-key and -.B \-\-persist-tun +.B \-\-persist\-tun options. .\"********************************************************* .TP @@ -2195,7 +2195,7 @@ directive above for description of .B progname parameter. .TP -.B \-\-errors-to-stderr +.B \-\-errors\-to\-stderr Output errors to stderr instead of stdout unless log output is redirected by one of the .B \-\-log options. @@ -2216,7 +2216,7 @@ option must match what is specified in the inetd/xinetd config file. The .B nowait mode can only be used with -.B \-\-proto tcp-server. +.B \-\-proto tcp\-server. The default is .B wait. The @@ -2265,14 +2265,14 @@ is also specified. This option is persistent over the entire course of an OpenVPN instantiation and will not be reset by SIGHUP, SIGUSR1, or -.B \-\-ping-restart. +.B \-\-ping\-restart. Note that on Windows, when OpenVPN is started as a service, logging occurs by default without the need to specify this option. .\"********************************************************* .TP -.B \-\-log-append file +.B \-\-log\-append file Append logging messages to .B file. If @@ -2284,13 +2284,13 @@ except that it appends to rather than truncating the log file. .\"********************************************************* .TP -.B \-\-suppress-timestamps +.B \-\-suppress\-timestamps Avoid writing timestamps to log messages, even when they otherwise would be prepended. In particular, this applies to log messages sent to stdout. .\"********************************************************* .TP -.B \-\-machine-readable-output +.B \-\-machine\-readable\-output Always write timestamps and message flags to log messages, even when they otherwise would not be prefixed. In particular, this applies to log messages sent to stdout. @@ -2310,14 +2310,14 @@ greater than 0 is lower priority, less than zero is higher priority). .\"********************************************************* .\".TP -.\".B \-\-nice-work n +.\".B \-\-nice\-work n .\"Change priority of background TLS work thread. The TLS thread .\"feature is enabled when OpenVPN is built .\"with pthread support, and you are running OpenVPN .\"in TLS mode (i.e. with -.\".B \-\-tls-client +.\".B \-\-tls\-client .\"or -.\".B \-\-tls-server +.\".B \-\-tls\-server .\"specified). .\" .\"Using a TLS thread offloads the CPU-intensive process of SSL/TLS-based @@ -2332,7 +2332,7 @@ less than zero is higher priority). .\"than the main thread. .\"********************************************************* .TP -.B \-\-fast-io +.B \-\-fast\-io (Experimental) Optimize TUN/TAP/UDP I/O writes by avoiding a call to poll/epoll/select prior to the write operation. The purpose of such a call would normally be to block until the device @@ -2378,7 +2378,7 @@ Designed to be used to send messages to a controlling application which is receiving the OpenVPN log output. .\"********************************************************* .TP -.B \-\-remap-usr1 signal +.B \-\-remap\-usr1 signal Control whether internally or externally generated SIGUSR1 signals are remapped to SIGHUP (restart without persisting state) or @@ -2427,7 +2427,7 @@ Status can also be written to the syslog by sending a signal. .\"********************************************************* .TP -.B \-\-status-version [n] +.B \-\-status\-version [n] Choose the status file format version number. Currently .B n can be 1, 2, or 3 and defaults to 1. @@ -2449,7 +2449,7 @@ parameter may be "snappy", "lzo", "lz4", or empty. Snappy, LZO and LZ4 are different compression algorithms, with Snappy generally offering the best performance while LZ4 is faster with less CPU usage. For backwards compatibility with OpenVPN versions before 2.4, use "lzo" -(which is identical to the older option "\-\-comp-lzo yes"). +(which is identical to the older option "\-\-comp\-lzo yes"). If the .B algorithm @@ -2458,8 +2458,8 @@ framing for compression will still be enabled, allowing a different setting to be pushed later. .\"********************************************************* .TP -.B \-\-comp-lzo [mode] -Use LZO compression \-\- may add up to 1 byte per +.B \-\-comp\-lzo [mode] +Use LZO compression -- may add up to 1 byte per packet for incompressible data. .B mode may be "yes", "no", or "adaptive" (default). @@ -2473,40 +2473,40 @@ compression on or off for individual clients. First, make sure the client-side config file enables selective compression by having at least one -.B \-\-comp-lzo +.B \-\-comp\-lzo directive, such as -.B \-\-comp-lzo no. +.B \-\-comp\-lzo no. This will turn off compression by default, but allow a future directive push from the server to dynamically change the on/off/adaptive setting. Next in a -.B \-\-client-config-dir +.B \-\-client\-config\-dir file, specify the compression setting for the client, for example: .nf .ft 3 .in +4 -comp-lzo yes -push "comp-lzo yes" +comp\-lzo yes +push "comp\-lzo yes" .in -4 .ft .fi The first line sets the -.B comp-lzo +.B comp\-lzo setting for the server side of the link, the second sets the client side. .\"********************************************************* .TP -.B \-\-comp-noadapt +.B \-\-comp\-noadapt When used in conjunction with -.B \-\-comp-lzo, +.B \-\-comp\-lzo, this option will disable OpenVPN's adaptive compression algorithm. Normally, adaptive compression is enabled with -.B \-\-comp-lzo. +.B \-\-comp\-lzo. Adaptive compression tries to optimize the case where you have compression enabled, but you are sending predominantly incompressible @@ -2537,9 +2537,9 @@ and set .B port to 'unix'. While the default behavior is to create a unix domain socket that may be connected to by any process, the -.B \-\-management-client-user +.B \-\-management\-client\-user and -.B \-\-management-client-group +.B \-\-management\-client\-group directives can be used to restrict access. The management interface provides a special mode where the TCP @@ -2556,7 +2556,7 @@ to the port, using a telnet client in "raw" mode. Once connected, type "help" for a list of commands. For detailed documentation on the management interface, see -the management-notes.txt file in the +the management\-notes.txt file in the .B management folder of the OpenVPN source distribution. @@ -2567,7 +2567,7 @@ be set to 127.0.0.1 (localhost) to restrict accessibility of the management server to local clients. .TP -.B \-\-management-client +.B \-\-management\-client Management interface will connect as a TCP/unix domain client to .B IP:port specified by @@ -2578,33 +2578,33 @@ If the client connection fails to connect or is disconnected, a SIGTERM signal will be generated causing OpenVPN to quit. .\"********************************************************* .TP -.B \-\-management-query-passwords +.B \-\-management\-query\-passwords Query management channel for private key password and -.B \-\-auth-user-pass +.B \-\-auth\-user\-pass username/password. Only query the management channel for inputs which ordinarily would have been queried from the console. .\"********************************************************* .TP -.B \-\-management-query-proxy +.B \-\-management\-query\-proxy Query management channel for proxy server information for a specific .B \-\-remote (client-only). .\"********************************************************* .TP -.B \-\-management-query-remote +.B \-\-management\-query\-remote Allow management interface to override .B \-\-remote directives (client-only). .\"********************************************************* .TP -.B \-\-management-external-key +.B \-\-management\-external\-key Allows usage for external private key file instead of .B \-\-key option (client-only). .\"********************************************************* .TP -.B \-\-management-external-cert certificate-hint +.B \-\-management\-external\-cert certificate-hint Allows usage for external certificate instead of .B \-\-cert option (client-only). @@ -2613,16 +2613,16 @@ is an arbitrary string which is passed to a management interface client as an argument of NEED-CERTIFICATE notification. .\"********************************************************* .TP -.B \-\-management-forget-disconnect +.B \-\-management\-forget\-disconnect Make OpenVPN forget passwords when management session disconnects. This directive does not affect the -.B \-\-http-proxy +.B \-\-http\-proxy username/password. It is always cached. .\"********************************************************* .TP -.B \-\-management-hold +.B \-\-management\-hold Start OpenVPN in a hibernating state, until a client of the management interface explicitly starts it with the @@ -2630,45 +2630,45 @@ with the command. .\"********************************************************* .TP -.B \-\-management-signal +.B \-\-management\-signal Send SIGUSR1 signal to OpenVPN if management session disconnects. This is useful when you wish to disconnect an OpenVPN session on -user logoff. For --management-client this option is not needed since +user logoff. For \-\-management\-client this option is not needed since a disconnect will always generate a SIGTERM. .\"********************************************************* .TP -.B \-\-management-log-cache n +.B \-\-management\-log\-cache n Cache the most recent .B n lines of log file history for usage by the management channel. .\"********************************************************* .TP -.B \-\-management-up-down +.B \-\-management\-up\-down Report tunnel up/down events to management interface. .B .\"********************************************************* .TP -.B \-\-management-client-auth +.B \-\-management\-client\-auth Gives management interface client the responsibility to authenticate clients after their client certificate has been verified. See management-notes.txt in OpenVPN distribution for detailed notes. .\"********************************************************* .TP -.B \-\-management-client-pf +.B \-\-management\-client\-pf Management interface clients must specify a packet -filter file for each connecting client. See management-notes.txt +filter file for each connecting client. See management\-notes.txt in OpenVPN distribution for detailed notes. .\"********************************************************* .TP -.B \-\-management-client-user u +.B \-\-management\-client\-user u When the management interface is listening on a unix domain socket, only allow connections from user .B u. .\"********************************************************* .TP -.B \-\-management-client-group g +.B \-\-management\-client\-group g When the management interface is listening on a unix domain socket, only allow connections from group .B g. @@ -2702,8 +2702,8 @@ OpenVPN in the order that they are declared in the config file. If both a plugin and script are configured for the same callback, the script will be called last. If the return code of the module/script controls an authentication -function (such as tls-verify, auth-user-pass-verify, or -client-connect), then +function (such as tls\-verify, auth\-user\-pass\-verify, or +client\-connect), then every module and script must return success (0) in order for the connection to be authenticated. .\"********************************************************* @@ -2737,15 +2737,15 @@ expands as follows: .ft 3 .in +4 mode server - tls-server + tls\-server push "topology [topology]" if dev tun AND (topology == net30 OR topology == p2p): ifconfig 10.8.0.1 10.8.0.2 if !nopool: - ifconfig-pool 10.8.0.4 10.8.0.251 + ifconfig\-pool 10.8.0.4 10.8.0.251 route 10.8.0.0 255.255.255.0 - if client-to-client: + if client\-to\-client: push "route 10.8.0.0 255.255.255.0" else if topology == net30: push "route 10.8.0.1" @@ -2753,10 +2753,10 @@ expands as follows: if dev tap OR (dev tun AND topology == subnet): ifconfig 10.8.0.1 255.255.255.0 if !nopool: - ifconfig-pool 10.8.0.2 10.8.0.254 255.255.255.0 - push "route-gateway 10.8.0.1" - if route-gateway unset: - route-gateway 10.8.0.2 + ifconfig\-pool 10.8.0.2 10.8.0.254 255.255.255.0 + push "route\-gateway 10.8.0.1" + if route\-gateway unset: + route\-gateway 10.8.0.2 .in -4 .ft @@ -2765,13 +2765,13 @@ expands as follows: Don't use .B \-\-server if you are ethernet bridging. Use -.B \-\-server-bridge +.B \-\-server\-bridge instead. .\"********************************************************* .TP -.B \-\-server-bridge gateway netmask pool-start-IP pool-end-IP +.B \-\-server\-bridge gateway netmask pool-start-IP pool-end-IP .TP -.B \-\-server-bridge ['nogw'] +.B \-\-server\-bridge ['nogw'] A helper directive similar to .B \-\-server @@ -2779,7 +2779,7 @@ which is designed to simplify the configuration of OpenVPN's server mode in ethernet bridging configurations. If -.B \-\-server-bridge +.B \-\-server\-bridge is used without any parameters, it will enable a DHCP-proxy mode, where connecting OpenVPN clients will receive an IP address for their TAP adapter from the DHCP server running @@ -2807,7 +2807,7 @@ IP/netmask on the bridge interface. The and .B netmask parameters to -.B \-\-server-bridge +.B \-\-server\-bridge can be set to either the IP/netmask of the bridge interface, or the IP/netmask of the default gateway/router on the bridged @@ -2823,45 +2823,45 @@ for OpenVPN to allocate to connecting clients. For example, -.B server-bridge 10.8.0.4 255.255.255.0 10.8.0.128 10.8.0.254 +.B server\-bridge 10.8.0.4 255.255.255.0 10.8.0.128 10.8.0.254 expands as follows: .nf .ft 3 .in +4 mode server -tls-server +tls\-server -ifconfig-pool 10.8.0.128 10.8.0.254 255.255.255.0 -push "route-gateway 10.8.0.4" +ifconfig\-pool 10.8.0.128 10.8.0.254 255.255.255.0 +push "route\-gateway 10.8.0.4" .in -4 .ft .fi In another example, -.B \-\-server-bridge +.B \-\-server\-bridge (without parameters) expands as follows: .nf .ft 3 .in +4 mode server -tls-server +tls\-server -push "route-gateway dhcp" +push "route\-gateway dhcp" .in -4 .ft .fi Or -.B \-\-server-bridge nogw +.B \-\-server\-bridge nogw expands as follows: .nf .ft 3 .in +4 mode server -tls-server +tls\-server .in -4 .ft .fi @@ -2884,26 +2884,26 @@ cannot be pushed because the client needs to know them before the connection to the server can be initiated. This is a partial list of options which can currently be pushed: -.B \-\-route, \-\-route-gateway, \-\-route-delay, \-\-redirect-gateway, -.B \-\-ip-win32, \-\-dhcp-option, -.B \-\-inactive, \-\-ping, \-\-ping-exit, \-\-ping-restart, +.B \-\-route, \-\-route\-gateway, \-\-route\-delay, \-\-redirect\-gateway, +.B \-\-ip\-win32, \-\-dhcp\-option, +.B \-\-inactive, \-\-ping, \-\-ping\-exit, \-\-ping\-restart, .B \-\-setenv, -.B \-\-persist-key, \-\-persist-tun, \-\-echo, -.B \-\-comp-lzo, -.B \-\-socket-flags, +.B \-\-persist\-key, \-\-persist\-tun, \-\-echo, +.B \-\-comp\-lzo, +.B \-\-socket\-flags, .B \-\-sndbuf, \-\-rcvbuf .\"********************************************************* .TP -.B \-\-push-reset +.B \-\-push\-reset Don't inherit the global push list for a specific client instance. Specify this option in a client-specific context such as with a -.B \-\-client-config-dir +.B \-\-client\-config\-dir configuration file. This option will ignore .B \-\-push options at the global config file level. .TP -.B \-\-push-peer-info +.B \-\-push\-peer\-info Push additional information about the client to server. The additional information consists of the following data: @@ -2923,19 +2923,19 @@ Disable a particular client (based on the common name) from connecting. Don't use this option to disable a client due to key or password compromise. Use a CRL (certificate revocation list) instead (see the -.B \-\-crl-verify +.B \-\-crl\-verify option). This option must be associated with a specific client instance, which means that it must be specified either in a client instance config file using -.B \-\-client-config-dir +.B \-\-client\-config\-dir or dynamically generated using a -.B \-\-client-connect +.B \-\-client\-connect script. .\"********************************************************* .TP -.B \-\-ifconfig-pool start-IP end-IP [netmask] +.B \-\-ifconfig\-pool start-IP end-IP [netmask] Set aside a pool of subnets to be dynamically allocated to connecting clients, similar to a DHCP server. For tun-style @@ -2948,8 +2948,8 @@ parameter will also be pushed to clients. .\"********************************************************* .TP -.B \-\-ifconfig-pool-persist file [seconds] -Persist/unpersist ifconfig-pool +.B \-\-ifconfig\-pool\-persist file [seconds] +Persist/unpersist ifconfig\-pool data to .B file, at @@ -2963,7 +2963,7 @@ IP address assigned to them from the ifconfig-pool. Maintaining a long-term association is good for clients because it allows them to effectively use the -.B \-\-persist-tun +.B \-\-persist\-tun option. .B file @@ -2984,12 +2984,12 @@ suggestions only, based on past associations between a common name and IP address. They do not guarantee that the given common name will always receive the given IP address. If you want guaranteed assignment, use -.B \-\-ifconfig-push +.B \-\-ifconfig\-push .\"********************************************************* .TP -.B \-\-ifconfig-pool-linear +.B \-\-ifconfig\-pool\-linear Modifies the -.B \-\-ifconfig-pool +.B \-\-ifconfig\-pool directive to allocate individual TUN interface addresses for clients rather than /30 subnets. NOTE: This option @@ -3000,21 +3000,21 @@ This option is deprecated, and should be replaced with which is functionally equivalent. .\"********************************************************* .TP -.B \-\-ifconfig-push local remote-netmask [alias] +.B \-\-ifconfig\-push local remote\-netmask [alias] Push virtual IP endpoints for client tunnel, -overriding the \-\-ifconfig-pool dynamic allocation. +overriding the \-\-ifconfig\-pool dynamic allocation. The parameters .B local and -.B remote-netmask +.B remote\-netmask are set according to the .B \-\-ifconfig directive which you want to execute on the client machine to configure the remote end of the tunnel. Note that the parameters .B local and -.B remote-netmask +.B remote\-netmask are from the perspective of the client, not the server. They may be DNS names rather than IP addresses, in which case they will be resolved on the server at the time of client connection. @@ -3023,17 +3023,17 @@ The optional .B alias parameter may be used in cases where NAT causes the client view of its local endpoint to differ from the server view. In this case -.B local/remote-netmask +.B local/remote\-netmask will refer to the server view while -.B alias/remote-netmask +.B alias/remote\-netmask will refer to the client view. This option must be associated with a specific client instance, which means that it must be specified either in a client instance config file using -.B \-\-client-config-dir +.B \-\-client\-config\-dir or dynamically generated using a -.B \-\-client-connect +.B \-\-client\-connect script. Remember also to include a @@ -3047,18 +3047,18 @@ OpenVPN's internal client IP address selection algorithm works as follows: .B 1 -\-\- Use -.B \-\-client-connect script +-- Use +.B \-\-client\-connect script generated file for static IP (first choice). .br .B 2 -\-\- Use -.B \-\-client-config-dir +-- Use +.B \-\-client\-config\-dir file for static IP (next choice). .br .B 3 -\-\- Use -.B \-\-ifconfig-pool +-- Use +.B \-\-ifconfig\-pool allocation for dynamic IP (last choice). .br .\"********************************************************* @@ -3085,9 +3085,9 @@ directive routes to the specific client. This option must be specified either in a client instance config file using -.B \-\-client-config-dir +.B \-\-client\-config\-dir or dynamically generated using a -.B \-\-client-connect +.B \-\-client\-connect script. The @@ -3103,7 +3103,7 @@ subnet, you can use .B \-\-push "route ..." together with -.B \-\-client-to-client +.B \-\-client\-to\-client to effect this. In order for all clients to see A's subnet, OpenVPN must push this route to all clients EXCEPT for A, since the subnet is already owned by A. @@ -3112,11 +3112,11 @@ not pushing a route to a client if it matches one of the client's iroutes. .\"********************************************************* .TP -.B \-\-client-to-client +.B \-\-client\-to\-client Because the OpenVPN server mode handles multiple clients through a single tun or tap interface, it is effectively a router. The -.B \-\-client-to-client +.B \-\-client\-to\-client flag tells OpenVPN to internally route client-to-client traffic rather than pushing all client-originating traffic to the TUN/TAP interface. @@ -3128,13 +3128,13 @@ if you want to firewall tunnel traffic using custom, per-client rules. .\"********************************************************* .TP -.B \-\-duplicate-cn +.B \-\-duplicate\-cn Allow multiple clients with the same common name to concurrently connect. In the absence of this option, OpenVPN will disconnect a client instance upon connection of a new client having the same common name. .\"********************************************************* .TP -.B \-\-client-connect cmd +.B \-\-client\-connect cmd Run .B command cmd on client connection. @@ -3159,7 +3159,7 @@ to be applied on the server when the client connects, it should write it to the file named by the last argument. See the -.B \-\-client-config-dir +.B \-\-client\-config\-dir option below for options which can be legally used in a dynamically generated config file. @@ -3171,18 +3171,18 @@ returns a non-zero error status, it will cause the client to be disconnected. .\"********************************************************* .TP -.B \-\-client-disconnect cmd +.B \-\-client\-disconnect cmd Like -.B \-\-client-connect +.B \-\-client\-connect but called on client instance shutdown. Will not be called unless the -.B \-\-client-connect +.B \-\-client\-connect script and plugins (if defined) were previously called on this instance with successful (0) status returns. The exception to this rule is if the -.B \-\-client-disconnect +.B \-\-client\-disconnect command or plugins are cascaded, and at least one client-connect function succeeded, then ALL of the client-disconnect functions for scripts and plugins will be called on client instance object deletion, @@ -3190,16 +3190,16 @@ even in cases where some of the related client-connect functions returned an error status. The -.B \-\-client-disconnect +.B \-\-client\-disconnect command is passed the same pathname as the corresponding -.B \-\-client-connect +.B \-\-client\-connect command as its last argument. (after any arguments specified in .B cmd ). .B .\"********************************************************* .TP -.B \-\-client-config-dir dir +.B \-\-client\-config\-dir dir Specify a directory .B dir for custom client config files. After @@ -3215,7 +3215,7 @@ after it has dropped it's root privileges. This file can specify a fixed IP address for a given client using -.B \-\-ifconfig-push, +.B \-\-ifconfig\-push, as well as fixed subnets owned by the client using .B \-\-iroute. @@ -3226,19 +3226,19 @@ without needing to restart the server. The following options are legal in a client-specific context: -.B \-\-push, \-\-push-reset, \-\-iroute, \-\-ifconfig-push, +.B \-\-push, \-\-push\-reset, \-\-iroute, \-\-ifconfig\-push, and .B \-\-config. .\"********************************************************* .TP -.B \-\-ccd-exclusive +.B \-\-ccd\-exclusive Require, as a condition of authentication, that a connecting client has a -.B \-\-client-config-dir +.B \-\-client\-config\-dir file. .\"********************************************************* .TP -.B \-\-tmp-dir dir +.B \-\-tmp\-dir dir Specify a directory .B dir for temporary files. This directory will be used by @@ -3250,7 +3250,7 @@ after it has dropped it's root privileges. This directory will be used by in the following cases: * -.B \-\-client-connect +.B \-\-client\-connect scripts to dynamically generate client-specific configuration files. @@ -3264,7 +3264,7 @@ when using deferred auth method plugin hook to pass filtering rules via pf_file .\"********************************************************* .TP -.B \-\-hash-size r v +.B \-\-hash\-size r v Set the size of the real address hash table to .B r and the virtual address table to @@ -3272,13 +3272,13 @@ and the virtual address table to By default, both tables are sized at 256 buckets. .\"********************************************************* .TP -.B \-\-bcast-buffers n +.B \-\-bcast\-buffers n Allocate .B n buffers for broadcast datagrams (default=256). .\"********************************************************* .TP -.B \-\-tcp-queue-limit n +.B \-\-tcp\-queue\-limit n Maximum number of output packets queued before TCP (default=64). When OpenVPN is tunneling data from a TUN/TAP device to a @@ -3290,7 +3290,7 @@ OpenVPN will start to drop outgoing packets directed at this client. .\"********************************************************* .TP -.B \-\-tcp-nodelay +.B \-\-tcp\-nodelay This macro sets the TCP_NODELAY socket flag on the server as well as pushes it to connecting clients. The TCP_NODELAY flag disables the Nagle algorithm on TCP sockets causing @@ -3306,20 +3306,20 @@ The macro expands as follows: .ft 3 .in +4 if mode server: - socket-flags TCP_NODELAY - push "socket-flags TCP_NODELAY" + socket\-flags TCP_NODELAY + push "socket\-flags TCP_NODELAY" .in -4 .ft .fi .\"********************************************************* .TP -.B \-\-max-clients n +.B \-\-max\-clients n Limit server to a maximum of .B n concurrent clients. .\"********************************************************* .TP -.B \-\-max-routes-per-client n +.B \-\-max\-routes\-per\-client n Allow a maximum of .B n internal routes per client (default=256). @@ -3329,9 +3329,9 @@ server with packets appearing to come from many unique MAC addresses, forcing the server to deplete virtual memory as its internal routing table expands. This directive can be used in a -.B \-\-client-config-dir +.B \-\-client\-config\-dir file or auto-generated by a -.B \-\-client-connect +.B \-\-client\-connect script to override the global value for a particular client. Note that this @@ -3339,7 +3339,7 @@ directive affects OpenVPN's internal routing table, not the kernel routing table. .\"********************************************************* .TP -.B \-\-stale-routes-check n [t] +.B \-\-stale\-routes\-check n [t] Remove routes haven't had activity for .B n seconds (i.e. the ageing time). @@ -3355,10 +3355,10 @@ is not present it defaults to This option helps to keep the dynamic routing table small. See also -.B \-\-max-routes-per-client +.B \-\-max\-routes\-per\-client .\"********************************************************* .TP -.B \-\-connect-freq n sec +.B \-\-connect\-freq n sec Allow a maximum of .B n new connections per @@ -3374,10 +3374,10 @@ For the best protection against DoS attacks in server mode, use .B \-\-proto udp and -.B \-\-tls-auth. +.B \-\-tls\-auth. .\"********************************************************* .TP -.B \-\-learn-address cmd +.B \-\-learn\-address cmd Run command .B cmd to validate client virtual addresses or routes. @@ -3423,7 +3423,7 @@ policies with regard to the client's high-level common name, rather than the low level client virtual addresses. .\"********************************************************* .TP -.B \-\-auth-user-pass-verify cmd method +.B \-\-auth\-user\-pass\-verify cmd method Require the client to provide a username/password (possibly in addition to a client certificate) for authentication. @@ -3439,7 +3439,7 @@ and/or escaped using a backslash, and should be separated by one or more spaces. If .B method -is set to "via-env", OpenVPN will call +is set to "via\-env", OpenVPN will call .B script with the environmental variables .B username @@ -3452,17 +3452,17 @@ unprivileged processes. If .B method -is set to "via-file", OpenVPN will write the username and +is set to "via\-file", OpenVPN will write the username and password to the first two lines of a temporary file. The filename will be passed as an argument to .B script, and the file will be automatically deleted by OpenVPN after the script returns. The location of the temporary file is controlled by the -.B \-\-tmp-dir +.B \-\-tmp\-dir option, and will default to the current directory if unspecified. For security, consider setting -.B \-\-tmp-dir +.B \-\-tmp\-dir to a volatile storage medium such as .B /dev/shm (if available) to prevent the username/password file from touching the hard drive. @@ -3490,30 +3490,30 @@ strings are handled. Never use these strings in such a way that they might be escaped or evaluated by a shell interpreter. For a sample script that performs PAM authentication, see -.B sample-scripts/auth-pam.pl +.B sample\-scripts/auth\-pam.pl in the OpenVPN source distribution. .\"********************************************************* .TP -.B \-\-opt-verify +.B \-\-opt\-verify Clients that connect with options that are incompatible with those of the server will be disconnected. Options that will be compared for compatibility include -dev-type, link-mtu, tun-mtu, proto, tun-ipv6, ifconfig, -comp-lzo, fragment, keydir, cipher, auth, keysize, secret, -no-replay, no-iv, tls-auth, key-method, tls-server, and tls-client. +dev\-type, link\-mtu, tun\-mtu, proto, tun\-ipv6, ifconfig, +comp\-lzo, fragment, keydir, cipher, auth, keysize, secret, +no\-replay, no\-iv, tls\-auth, key\-method, tls\-server, and tls\-client. This option requires that -.B \-\-disable-occ +.B \-\-disable\-occ NOT be used. .\"********************************************************* .TP -.B \-\-auth-user-pass-optional +.B \-\-auth\-user\-pass\-optional Allow connections by clients that do not specify a username/password. Normally, when -.B \-\-auth-user-pass-verify +.B \-\-auth\-user\-pass\-verify or -.B \-\-management-client-auth +.B \-\-management\-client\-auth is specified (or an authentication plugin module), the OpenVPN server daemon will require connecting clients to specify a username and password. This option makes the submission of a username/password @@ -3526,29 +3526,29 @@ to empty strings (""). The authentication module/script MUST have logic to detect this condition and respond accordingly. .\"********************************************************* .TP -.B \-\-client-cert-not-required +.B \-\-client\-cert\-not\-required Don't require client certificate, client will authenticate using username/password only. Be aware that using this directive is less secure than requiring certificates from all clients. If you use this directive, the entire responsibility of authentication will rest on your -.B \-\-auth-user-pass-verify +.B \-\-auth\-user\-pass\-verify script, so keep in mind that bugs in your script could potentially compromise the security of your VPN. If you don't use this directive, but you also specify an -.B \-\-auth-user-pass-verify +.B \-\-auth\-user\-pass\-verify script, then OpenVPN will perform double authentication. The client certificate verification AND the -.B \-\-auth-user-pass-verify +.B \-\-auth\-user\-pass\-verify script will need to succeed in order for a client to be authenticated and accepted onto the VPN. .\"********************************************************* .TP -.B \-\-username-as-common-name +.B \-\-username\-as\-common\-name For -.B \-\-auth-user-pass-verify +.B \-\-auth\-user\-pass\-verify authentication, use the authenticated username as the common name, rather than the common name from the client cert. @@ -3600,9 +3600,9 @@ carriage-return. no-remapping is only available on the server side. This option is immediately deprecated. It is only implemented to make the transition to the new formatting less intrusive. It will be removed either in OpenVPN v2.4 or v2.5. So please make sure you use the -.B \-\-verify-x509-name +.B \-\-verify\-x509\-name option instead of -.B \-\-tls-remote +.B \-\-tls\-remote as soon as possible and update your scripts where necessary. .\"********************************************************* .TP @@ -3623,7 +3623,7 @@ described with the option as soon as possible. .\"********************************************************* .TP -.B \-\-port-share host port [dir] +.B \-\-port\-share host port [dir] When run in TCP server mode, share the OpenVPN port with another application, such as an HTTPS server. If OpenVPN senses a connection to its port which is using a non-OpenVPN @@ -3648,7 +3648,7 @@ Not implemented on Windows. .SS Client Mode Use client mode when connecting to an OpenVPN server which has -.B \-\-server, \-\-server-bridge, +.B \-\-server, \-\-server\-bridge, or .B \-\-mode server in it's configuration. @@ -3662,7 +3662,7 @@ of OpenVPN's client mode. This directive is equivalent to: .ft 3 .in +4 pull - tls-client + tls\-client .in -4 .ft .fi @@ -3689,12 +3689,12 @@ in situations where you don't trust the server to have control over the client's routing table. .\"********************************************************* .TP -.B \-\-auth-user-pass [up] +.B \-\-auth\-user\-pass [up] Authenticate with server using username/password. .B up is a file containing username/password on 2 lines (Note: OpenVPN will only read passwords from a file if it has been built -with the \-\-enable-password-save configure option, or on Windows +with the \-\-enable\-password\-save configure option, or on Windows by defining ENABLE_PASSWORD_SAVE in win/settings.in). If @@ -3703,12 +3703,12 @@ is omitted, username/password will be prompted from the console. The server configuration must specify an -.B \-\-auth-user-pass-verify +.B \-\-auth\-user\-pass\-verify script to verify the username/password provided by the client. .\"********************************************************* .TP -.B \-\-auth-retry type +.B \-\-auth\-retry type Controls how OpenVPN responds to username/password verification errors such as the client-side response to an AUTH_FAILED message from the server or verification failure of the private key password. @@ -3719,9 +3719,9 @@ of error. An AUTH_FAILED message is generated by the server if the client fails -.B \-\-auth-user-pass +.B \-\-auth\-user\-pass authentication, or if the server-side -.B \-\-client-connect +.B \-\-client\-connect script returns an error status when the client tries to connect. @@ -3733,12 +3733,12 @@ Client will exit with a fatal error (this is the default). .br .B nointeract \-\- Client will retry the connection without requerying for an -.B \-\-auth-user-pass +.B \-\-auth\-user\-pass username/password. Use this option for unattended clients. .br .B interact \-\- Client will requery for an -.B \-\-auth-user-pass +.B \-\-auth\-user\-pass username/password and/or private key password before attempting a reconnection. Note that while this option cannot be pushed, it can be controlled @@ -3760,14 +3760,14 @@ See management\-notes.txt in the OpenVPN distribution for a description of the OpenVPN challenge/response protocol. .\"********************************************************* .TP -.B \-\-server-poll-timeout n +.B \-\-server\-poll\-timeout n when polling possible remote servers to connect to in a round-robin fashion, spend no more than .B n seconds waiting for a response before trying the next server. .\"********************************************************* .TP -.B \-\-explicit-exit-notify [n] +.B \-\-explicit\-exit\-notify [n] In UDP client mode or point-to-point mode, send server/peer an exit notification if tunnel is restarted or OpenVPN process is exited. In client mode, on exit/restart, this @@ -3849,9 +3849,9 @@ would see nothing but random-looking data. .\"********************************************************* .TP -.B \-\-key-direction +.B \-\-key\-direction Alternative way of specifying the optional direction parameter for the -.B \-\-tls-auth +.B \-\-tls\-auth and .B \-\-secret options. Useful when using inline files (See section on inline files). @@ -3900,7 +3900,7 @@ For more information on blowfish, see To see other ciphers that are available with OpenVPN, use the -.B \-\-show-ciphers +.B \-\-show\-ciphers option. OpenVPN supports the CBC, CFB, and OFB cipher modes, @@ -3915,7 +3915,7 @@ to disable encryption. .B \-\-keysize n Size of cipher key in bits (optional). If unspecified, defaults to cipher-specific default. The -.B \-\-show-ciphers +.B \-\-show\-ciphers option (see below) shows all available OpenSSL ciphers, their default key sizes, and whether the key size can be changed. Use care in changing a cipher's default @@ -3947,12 +3947,12 @@ If .B engine-name is specified, use a specific crypto engine. Use the -.B \-\-show-engines +.B \-\-show\-engines standalone option to list the crypto engines which are supported by OpenSSL. .\"********************************************************* .TP -.B \-\-no-replay +.B \-\-no\-replay (Advanced) Disable OpenVPN's protection against replay attacks. Don't use this option unless you are prepared to make a tradeoff of greater efficiency in exchange for less @@ -3996,7 +3996,7 @@ algorithm used by IPSec. .\"********************************************************* .TP -.B \-\-replay-window n [t] +.B \-\-replay\-window n [t] Use a replay protection sliding-window of size .B n and a time window of @@ -4025,7 +4025,7 @@ the TCP/IP protocol stack, provided they satisfy several constraints. .B (a) The packet cannot be a replay (unless -.B \-\-no-replay +.B \-\-no\-replay is specified, which disables replay protection altogether). .B (b) @@ -4083,7 +4083,7 @@ parameters of what is to be expected from the physical IP layer. The problem is easily fixed by simply using TCP as the VPN transport layer. .\"********************************************************* .TP -.B \-\-mute-replay-warnings +.B \-\-mute\-replay\-warnings Silence the output of replay warnings, which are a common false alarm on WiFi networks. This option preserves the security of the replay protection code without @@ -4091,7 +4091,7 @@ the verbosity associated with warnings about duplicate packets. .\"********************************************************* .TP -.B \-\-replay-persist file +.B \-\-replay\-persist file Persist replay-protection state across sessions using .B file to save and reload the state. @@ -4112,10 +4112,10 @@ This option only makes sense when replay protection is enabled (the default) and you are using either .B \-\-secret (shared-secret key mode) or TLS mode with -.B \-\-tls-auth. +.B \-\-tls\-auth. .\"********************************************************* .TP -.B \-\-no-iv +.B \-\-no\-iv (Advanced) Disable OpenVPN's use of IV (cipher initialization vector). Don't use this option unless you are prepared to make a tradeoff of greater efficiency in exchange for less @@ -4136,7 +4136,7 @@ space-saving optimization that uses the unique identifier for datagram replay protection as the IV. .\"********************************************************* .TP -.B \-\-use-prediction-resistance +.B \-\-use\-prediction\-resistance Enable prediction resistance on PolarSSL's RNG. Enabling prediction resistance causes the RNG to reseed in each @@ -4150,7 +4150,7 @@ Note that this option only works with PolarSSL versions greater than 1.1. .\"********************************************************* .TP -.B \-\-test-crypto +.B \-\-test\-crypto Do a self-test of OpenVPN's crypto options by encrypting and decrypting test packets using the data channel encryption options specified above. This option does not require a peer to function, @@ -4160,14 +4160,14 @@ or .B \-\-remote. The typical usage of -.B \-\-test-crypto +.B \-\-test\-crypto would be something like this: -.B openvpn \-\-test-crypto \-\-secret key +.B openvpn \-\-test\-crypto \-\-secret key or -.B openvpn \-\-test-crypto \-\-secret key \-\-verb 9 +.B openvpn \-\-test\-crypto \-\-secret key \-\-verb 9 This option is very useful to test OpenVPN after it has been ported to a new platform, or to isolate problems in the compiler, OpenSSL @@ -4218,14 +4218,14 @@ The easy-rsa package is also rendered in web form here: .I http://openvpn.net/easyrsa.html .\"********************************************************* .TP -.B \-\-tls-server +.B \-\-tls\-server Enable TLS and assume server role during TLS handshake. Note that OpenVPN is designed as a peer-to-peer application. The designation of client or server is only for the purpose of negotiating the TLS control channel. .\"********************************************************* .TP -.B \-\-tls-client +.B \-\-tls\-client Enable TLS and assume client role during TLS handshake. .\"********************************************************* .TP @@ -4236,7 +4236,7 @@ certificate. This file can have multiple certificates in .pem format, concatenated together. You can construct your own certificate authority certificate and private key by using a command such as: -.B openssl req -nodes -new -x509 -keyout ca.key -out ca.crt +.B openssl req \-nodes \-new \-x509 \-keyout ca.key \-out ca.crt Then edit your openssl.cnf file and edit the .B certificate @@ -4260,7 +4260,7 @@ Not available with PolarSSL. .B \-\-dh file File containing Diffie Hellman parameters in .pem format (required for -.B \-\-tls-server +.B \-\-tls\-server only). Set @@ -4270,20 +4270,20 @@ requires peers to be using an SSL library that supports ECDH TLS cipher suites (e.g. OpenSSL 1.0.1+, or PolarSSL 1.3+). Use -.B openssl dhparam -out dh2048.pem 2048 +.B openssl dhparam \-out dh2048.pem 2048 to generate 2048-bit DH parameters. Diffie Hellman parameters may be considered public. .\"********************************************************* .TP -.B \-\-ecdh-curve name +.B \-\-ecdh\-curve name Specify the curve to use for elliptic curve Diffie Hellman. Available curves can be listed with -.B \-\-show-curves +.B \-\-show\-curves . The specified curve will only be used for ECDH TLS-ciphers. .\"********************************************************* .TP .B \-\-cert file -Local peer's signed certificate in .pem format \-\- must be signed +Local peer's signed certificate in .pem format -- must be signed by a certificate authority whose certificate is in .B \-\-ca file. Each peer in an OpenVPN link running in TLS mode should have its own @@ -4298,14 +4298,14 @@ helping to finance the world's second space tourist :). To generate a certificate, you can use a command such as: -.B openssl req -nodes -new -keyout mycert.key -out mycert.csr +.B openssl req \-nodes \-new \-keyout mycert.key \-out mycert.csr If your certificate authority private key lives on another machine, copy the certificate signing request (mycert.csr) to this other machine (this can be done over an insecure channel such as email). Now sign the certificate with a command such as: -.B openssl ca -out mycert.crt -in mycert.csr +.B openssl ca \-out mycert.crt \-in mycert.csr Now copy the certificate (mycert.crt) back to the peer which initially generated the .csr file (this @@ -4315,7 +4315,7 @@ Note that the command reads the location of the certificate authority key from its configuration file such as .B /usr/share/ssl/openssl.cnf -\-\- note also +-- note also that for certificate authority functions, you must set up the files .B index.txt (may be empty) and @@ -4326,7 +4326,7 @@ that for certificate authority functions, you must set up the files ). .\"********************************************************* .TP -.B \-\-extra-certs file +.B \-\-extra\-certs file Specify a .B file containing one or more PEM certs (concatenated together) @@ -4345,11 +4345,11 @@ file. .B \-\-key file Local peer's private key in .pem format. Use the private key which was generated when you built your peer's certificate (see -.B -cert file +.B \-\-cert file above). .\"********************************************************* .TP -.B \-\-tls-version-min version ['or-highest'] +.B \-\-tls\-version\-min version ['or\-highest'] Sets the minimum TLS version we will accept from the peer (default is "1.0"). Examples for version @@ -4358,7 +4358,7 @@ and version is not recognized, we will only accept the highest TLS version supported by the local SSL implementation. .\"********************************************************* .TP -.B \-\-tls-version-max version +.B \-\-tls\-version\-max version Set the maximum TLS version we will use (default is the highest version supported). Examples for version include "1.0", "1.1", or "1.2". .\"********************************************************* @@ -4373,7 +4373,7 @@ and Not available with PolarSSL. .\"********************************************************* .TP -.B \-\-verify-hash hash +.B \-\-verify\-hash hash Specify SHA1 fingerprint for level-1 cert. The level-1 cert is the CA (or intermediate cert) that signs the leaf certificate, and is one removed from the leaf certificate in the direction of the root. @@ -4384,36 +4384,36 @@ or certificate verification will fail. Hash is specified as XX:XX:... For example: AD:B0:95:D8:09:C8:36:45:12:A9:89:C8:90:09:CB:13:72:A6:AD:16 .\"********************************************************* .TP -.B \-\-pkcs11-cert-private [0|1]... +.B \-\-pkcs11\-cert\-private [0|1]... Set if access to certificate object should be performed after login. Every provider has its own setting. .\"********************************************************* .TP -.B \-\-pkcs11-id name +.B \-\-pkcs11\-id name Specify the serialized certificate id to be used. The id can be gotten by the standalone -.B \-\-show-pkcs11-ids +.B \-\-show\-pkcs11\-ids option. .\"********************************************************* .TP -.B \-\-pkcs11-id-management +.B \-\-pkcs11\-id\-management Acquire PKCS#11 id from management interface. In this case a NEED-STR 'pkcs11-id-request' real-time message will be triggered, application may use pkcs11-id-count command to retrieve available number of certificates, and pkcs11-id-get command to retrieve certificate id and certificate body. .\"********************************************************* .TP -.B \-\-pkcs11-pin-cache seconds +.B \-\-pkcs11\-pin\-cache seconds Specify how many seconds the PIN can be cached, the default is until the token is removed. .\"********************************************************* .TP -.B \-\-pkcs11-protected-authentication [0|1]... +.B \-\-pkcs11\-protected\-authentication [0|1]... Use PKCS#11 protected authentication path, useful for biometric and external keypad devices. Every provider has its own setting. .\"********************************************************* .TP -.B \-\-pkcs11-providers provider... +.B \-\-pkcs11\-providers provider... Specify a RSA Security Inc. PKCS #11 Cryptographic Token Interface (Cryptoki) providers to load. This option can be used instead of @@ -4422,7 +4422,7 @@ and .B \-\-pkcs12. If p11-kit is present on the system, its -.B p11-kit-proxy.so +.B p11\-kit\-proxy.so module will be loaded by default if either the .B \-\-pkcs11\-id or @@ -4432,25 +4432,25 @@ options are specified without being given. .\"********************************************************* .TP -.B \-\-pkcs11-private-mode mode... +.B \-\-pkcs11\-private\-mode mode... Specify which method to use in order to perform private key operations. A different mode can be specified for each provider. Mode is encoded as hex number, and can be a mask one of the following: .B 0 -(default) \-\- Try to determine automatically. +(default) -- Try to determine automatically. .br .B 1 -\-\- Use sign. +-- Use sign. .br .B 2 -\-\- Use sign recover. +-- Use sign recover. .br .B 4 -\-\- Use decrypt. +-- Use decrypt. .br .B 8 -\-\- Use unwrap. +-- Use unwrap. .br .\"********************************************************* .TP @@ -4487,7 +4487,7 @@ Certificate Store GUI. .\"********************************************************* .TP -.B \-\-key-method m +.B \-\-key\-method m Use data channel key negotiation method .B m. The key method must match on both sides of the connection. @@ -4515,12 +4515,12 @@ of keying occur: of the connection producing certificates and verifying the certificate (or other authentication info provided) of the other side. The -.B \-\-key-method +.B \-\-key\-method parameter has no effect on this process. (2) After the TLS connection is established, the tunnel session keys are separately negotiated over the existing secure TLS channel. Here, -.B \-\-key-method +.B \-\-key\-method determines the derivation of the tunnel session keys. .\"********************************************************* .TP @@ -4548,11 +4548,11 @@ is an expert feature, which - if used correcly - can improve the security of your VPN connection. But it is also easy to unwittingly use it to carefully align a gun with your foot, or just break your connection. Use with care! -The default for --tls-cipher is to use PolarSSL's default cipher list +The default for \-\-tls\-cipher is to use PolarSSL's default cipher list when using PolarSSL or "DEFAULT:!EXP:!PSK:!SRP:!kRSA" when using OpenSSL. .\"********************************************************* .TP -.B \-\-tls-timeout n +.B \-\-tls\-timeout n Packet retransmit timeout on TLS control channel if no acknowledgment from remote within .B n @@ -4569,7 +4569,7 @@ the higher level network protocols running on top of the tunnel such as TCP expect this role to be left to them. .\"********************************************************* .TP -.B \-\-reneg-bytes n +.B \-\-reneg\-bytes n Renegotiate data channel key after .B n bytes sent or received (disabled by default). @@ -4579,13 +4579,13 @@ a number of seconds. A key renegotiation will be forced if any of these three criteria are met by either peer. .\"********************************************************* .TP -.B \-\-reneg-pkts n +.B \-\-reneg\-pkts n Renegotiate data channel key after .B n packets sent and received (disabled by default). .\"********************************************************* .TP -.B \-\-reneg-sec n +.B \-\-reneg\-sec n Renegotiate data channel key after .B n seconds (default=3600). @@ -4596,16 +4596,16 @@ cause the end user to be challenged to reauthorize once per hour. Also, keep in mind that this option can be used on both the client and server, and whichever uses the lower value will be the one to trigger the renegotiation. A common mistake is to set -.B \-\-reneg-sec +.B \-\-reneg\-sec to a higher value on either the client or server, while the other side of the connection is still using the default value of 3600 seconds, meaning that the renegotiation will -still occur once per 3600 seconds. The solution is to increase \-\-reneg-sec on both the +still occur once per 3600 seconds. The solution is to increase \-\-reneg\-sec on both the client and server, or set it to 0 on one side of the connection (to disable), and to your chosen value on the other side. .\"********************************************************* .TP -.B \-\-hand-window n -Handshake Window \-\- the TLS-based key exchange must finalize within +.B \-\-hand\-window n +Handshake Window -- the TLS-based key exchange must finalize within .B n seconds of handshake initiation by any peer (default = 60 seconds). @@ -4613,47 +4613,47 @@ If the handshake fails we will attempt to reset our connection with our peer and try again. Even in the event of handshake failure we will still use our expiring key for up to -.B \-\-tran-window +.B \-\-tran\-window seconds to maintain continuity of transmission of tunnel data. .\"********************************************************* .TP -.B \-\-tran-window n -Transition window \-\- our old key can live this many seconds +.B \-\-tran\-window n +Transition window -- our old key can live this many seconds after a new a key renegotiation begins (default = 3600 seconds). This feature allows for a graceful transition from old to new key, and removes the key renegotiation sequence from the critical path of tunnel data forwarding. .\"********************************************************* .TP -.B \-\-single-session +.B \-\-single\-session After initially connecting to a remote peer, disallow any new connections. Using this option means that a remote peer cannot connect, disconnect, and then reconnect. If the daemon is reset by a signal or -.B \-\-ping-restart, +.B \-\-ping\-restart, it will allow one new connection. -.B \-\-single-session +.B \-\-single\-session can be used with -.B \-\-ping-exit +.B \-\-ping\-exit or .B \-\-inactive to create a single dynamic session that will exit when finished. .\"********************************************************* .TP -.B \-\-tls-exit +.B \-\-tls\-exit Exit on TLS negotiation failure. .\"********************************************************* .TP -.B \-\-tls-auth file [direction] +.B \-\-tls\-auth file [direction] Add an additional layer of HMAC authentication on top of the TLS control channel to protect against DoS attacks. In a nutshell, -.B \-\-tls-auth +.B \-\-tls\-auth enables a kind of "HMAC firewall" on OpenVPN's TCP/UDP port, where TLS control channel packets bearing an incorrect HMAC signature can be dropped immediately without @@ -4672,7 +4672,7 @@ option for more information on the optional .B direction parameter. -.B \-\-tls-auth +.B \-\-tls\-auth is recommended when you are running OpenVPN in a mode where it is listening for packets from any IP address, such as when .B \-\-remote @@ -4706,7 +4706,7 @@ An important rule of thumb in reducing vulnerability to DoS attacks is to minimize the amount of resources a potential, but as yet unauthenticated, client is able to consume. -.B \-\-tls-auth +.B \-\-tls\-auth does this by signing every TLS control channel packet with an HMAC signature, including packets which are sent before the TLS level has had a chance to authenticate the peer. @@ -4714,15 +4714,15 @@ The result is that packets without the correct signature can be dropped immediately upon reception, before they have a chance to consume additional system resources such as by initiating a TLS handshake. -.B \-\-tls-auth +.B \-\-tls\-auth can be strengthened by adding the -.B \-\-replay-persist +.B \-\-replay\-persist option which will keep OpenVPN's replay protection state in a file so that it is not lost across restarts. It should be emphasized that this feature is optional and that the passphrase/key file used with -.B \-\-tls-auth +.B \-\-tls\-auth gives a peer nothing more than the power to initiate a TLS handshake. It is not used to encrypt or authenticate any tunnel data. .\"********************************************************* @@ -4740,7 +4740,7 @@ daemon is started you must be there to type the password. The option allows you to start OpenVPN from the command line. It will query you for a password before it daemonizes. To protect a private key with a password you should omit the -.B -nodes +.B \-nodes option when you use the .B openssl command line tool to manage certificates and private keys. @@ -4753,15 +4753,15 @@ Keep in mind that storing your password in a file to a certain extent invalidates the extra security provided by using an encrypted key (Note: OpenVPN will only read passwords from a file if it has been built -with the \-\-enable-password-save configure option, or on Windows +with the \-\-enable\-password\-save configure option, or on Windows by defining ENABLE_PASSWORD_SAVE in win/settings.in). .\"********************************************************* .TP -.B \-\-auth-nocache +.B \-\-auth\-nocache Don't cache .B \-\-askpass or -.B \-\-auth-user-pass +.B \-\-auth\-user\-pass username/passwords in virtual memory. If specified, this directive will cause OpenVPN to immediately @@ -4771,19 +4771,19 @@ from stdin, which may be multiple times during the duration of an OpenVPN session. This directive does not affect the -.B \-\-http-proxy +.B \-\-http\-proxy username/password. It is always cached. .\"********************************************************* .TP -.B \-\-tls-verify cmd +.B \-\-tls\-verify cmd Run command .B cmd to verify the X509 name of a pending TLS connection that has otherwise passed all other tests of certification (except for revocation via -.B \-\-crl-verify +.B \-\-crl\-verify directive; the revocation test occurs after the -.B \-\-tls-verify +.B \-\-tls\-verify test). .B cmd @@ -4813,31 +4813,31 @@ peer certificate you will accept. This feature allows you to write a script which will test the X509 name on a certificate and decide whether or not it should be accepted. For a simple perl script which will test the common name field on the certificate, see the file -.B verify-cn +.B verify\-cn in the OpenVPN distribution. See the "Environmental Variables" section below for additional parameters passed as environmental variables. .\"********************************************************* .TP -.B \-\-tls-export-cert directory +.B \-\-tls\-export\-cert directory Store the certificates the clients uses upon connection to this -directory. This will be done before \-\-tls-verify is called. The +directory. This will be done before \-\-tls\-verify is called. The certificates will use a temporary name and will be deleted when -the tls-verify script returns. The file name used for the certificate +the tls\-verify script returns. The file name used for the certificate is available via the peer_cert environment variable. .\"********************************************************* .TP -.B \-\-x509-username-field [ext:\]fieldname +.B \-\-x509\-username\-field [ext:\]fieldname Field in the X.509 certificate subject to be used as the username (default=CN). Typically, this option is specified with .B fieldname as either of the following: -.B \-\-x509-username-field +.B \-\-x509\-username\-field emailAddress .br -.B \-\-x509-username-field ext:\fRsubjectAltName +.B \-\-x509\-username\-field ext:\fRsubjectAltName The first example uses the value of the "emailAddress" attribute in the certificate's Subject field as the username. The second example uses @@ -4852,7 +4852,7 @@ in the last occurrence is chosen. When this option is used, the -.B \-\-verify-x509-name +.B \-\-verify\-x509\-name option will match against the chosen .B fieldname instead of the Common Name. @@ -4868,7 +4868,7 @@ prefix will be left as-is. This automatic upcasing feature is deprecated and will be removed in a future release. .\"********************************************************* .TP -.B \-\-tls-remote name (DEPRECATED) +.B \-\-tls\-remote name (DEPRECATED) Accept connections only from a host with X509 name or common name equal to .B name. @@ -4876,7 +4876,7 @@ The remote host must also pass all other tests of verification. .B NOTE: -Because tls-remote may test against a common name prefix, +Because tls\-remote may test against a common name prefix, only use this option when you are using OpenVPN with a custom CA certificate that is under your control. Never use this option when your client certificates are signed by @@ -4885,18 +4885,18 @@ a third party, such as a commercial web CA. Name can also be a common name prefix, for example if you want a client to only accept connections to "Server-1", "Server-2", etc., you can simply use -.B \-\-tls-remote Server +.B \-\-tls\-remote Server Using a common name prefix is a useful alternative to managing a CRL (Certificate Revocation List) on the client, since it allows the client to refuse all certificates except for those associated with designated servers. -.B \-\-tls-remote +.B \-\-tls\-remote is a useful replacement for the -.B \-\-tls-verify +.B \-\-tls\-verify option to verify the remote host, because -.B \-\-tls-remote +.B \-\-tls\-remote works in a .B \-\-chroot environment too. @@ -4905,13 +4905,13 @@ environment too. This option is now deprecated. It will be removed either in OpenVPN v2.4 or v2.5. So please make sure you support the new X.509 name formatting described with the -.B \-\-compat-names +.B \-\-compat\-names option as soon as possible by updating your configurations to use -.B \-\-verify-x509-name +.B \-\-verify\-x509\-name instead. .\"********************************************************* .TP -.B \-\-verify-x509-name name type +.B \-\-verify\-x509\-name name type Accept connections only if a host's X.509 name is equal to .B name. The remote host must also pass all other tests of verification. @@ -4923,22 +4923,22 @@ depends on the setting of type. can be "subject" to match the complete subject DN (default), "name" to match a subject RDN or "name-prefix" to match a subject RDN prefix. Which RDN is verified as name depends on the -.B \-\-x509-username-field +.B \-\-x509\-username\-field option. But it defaults to the common name (CN), e.g. a certificate with a subject DN "C=KG, ST=NA, L=Bishkek, CN=Server-1" would be matched by: -.B \-\-verify-x509-name 'C=KG, ST=NA, L=Bishkek, CN=Server-1' +.B \-\-verify\-x509\-name 'C=KG, ST=NA, L=Bishkek, CN=Server\-1' and -.B \-\-verify-x509-name Server-1 name +.B \-\-verify\-x509\-name Server\-1 name or you could use -.B \-\-verify-x509-name Server- name-prefix +.B \-\-verify\-x509\-name Server -name-prefix if you want a client to only accept connections to "Server-1", "Server-2", etc. -.B \-\-verify-x509-name +.B \-\-verify\-x509\-name is a useful replacement for the -.B \-\-tls-verify +.B \-\-tls\-verify option to verify the remote host, because -.B \-\-verify-x509-name +.B \-\-verify\-x509\-name works in a .B \-\-chroot environment without any dependencies. @@ -4955,7 +4955,7 @@ Never use this option with type "name-prefix" when your client certificates are signed by a third party, such as a commercial web CA. .\"********************************************************* .TP -.B \-\-x509-track attribute +.B \-\-x509\-track attribute Save peer X509 .B attribute value in environment for use by plugins and management interface. @@ -4963,12 +4963,12 @@ Prepend a '+' to .B attribute to save values from full cert chain. Values will be encoded as X509__=. Multiple -.B \-\-x509-track +.B \-\-x509\-track options can be defined to track multiple attributes. Not available with PolarSSL. .\"********************************************************* .TP -.B \-\-ns-cert-type client|server +.B \-\-ns\-cert\-type client|server Require that peer certificate was signed with an explicit .B nsCertType designation of "client" or "server". @@ -4976,26 +4976,26 @@ designation of "client" or "server". This is a useful security option for clients, to ensure that the host they connect with is a designated server. -See the easy-rsa/build-key-server script for an example +See the easy\-rsa/build\-key\-server script for an example of how to generate a certificate with the .B nsCertType field set to "server". If the server certificate's nsCertType field is set to "server", then the clients can verify this with -.B \-\-ns-cert-type server. +.B \-\-ns\-cert\-type server. This is an important security precaution to protect against a man-in-the-middle attack where an authorized client attempts to connect to another client by impersonating the server. The attack is easily prevented by having clients verify the server certificate using any one of -.B \-\-ns-cert-type, \-\-verify-x509-name, +.B \-\-ns\-cert\-type, \-\-verify\-x509\-name, or -.B \-\-tls-verify. +.B \-\-tls\-verify. .\"********************************************************* .TP -.B \-\-remote-cert-ku v... +.B \-\-remote\-cert\-ku v... Require that peer certificate was signed with an explicit .B key usage. @@ -5006,7 +5006,7 @@ The key usage should be encoded in hex, more than one key usage can be specified. .\"********************************************************* .TP -.B \-\-remote-cert-eku oid +.B \-\-remote\-cert\-eku oid Require that peer certificate was signed with an explicit .B extended key usage. @@ -5017,7 +5017,7 @@ The extended key usage should be encoded in oid notation, or OpenSSL symbolic representation. .\"********************************************************* .TP -.B \-\-remote-cert-tls client|server +.B \-\-remote\-cert\-tls client|server Require that peer certificate was signed with an explicit .B key usage and @@ -5028,18 +5028,18 @@ This is a useful security option for clients, to ensure that the host they connect to is a designated server. The -.B \-\-remote-cert-tls client +.B \-\-remote\-cert\-tls client option is equivalent to .B -\-\-remote-cert-ku 80 08 88 \-\-remote-cert-eku "TLS Web Client Authentication" +\-\-remote\-cert\-ku 80 08 88 \-\-remote\-cert\-eku "TLS Web Client Authentication" The key usage is digitalSignature and/or keyAgreement. The -.B \-\-remote-cert-tls server +.B \-\-remote\-cert\-tls server option is equivalent to .B -\-\-remote-cert-ku a0 88 \-\-remote-cert-eku "TLS Web Server Authentication" +\-\-remote\-cert\-ku a0 88 \-\-remote\-cert\-eku "TLS Web Server Authentication" The key usage is digitalSignature and ( keyEncipherment or keyAgreement ). @@ -5048,12 +5048,12 @@ a man-in-the-middle attack where an authorized client attempts to connect to another client by impersonating the server. The attack is easily prevented by having clients verify the server certificate using any one of -.B \-\-remote-cert-tls, \-\-verify-x509-name, +.B \-\-remote\-cert\-tls, \-\-verify\-x509\-name, or -.B \-\-tls-verify. +.B \-\-tls\-verify. .\"********************************************************* .TP -.B \-\-crl-verify crl ['dir'] +.B \-\-crl\-verify crl ['dir'] Check peer certificate against the file .B crl in PEM format. @@ -5082,20 +5082,20 @@ it will be rejected. Note: As the crl file (or directory) is read every time a peer connects, if you are dropping root privileges with -.B --user, +.B \-\-user, make sure that this user has sufficient privileges to read the file. .\"********************************************************* .SS SSL Library information: .\"********************************************************* .TP -.B \-\-show-ciphers +.B \-\-show\-ciphers (Standalone) Show all cipher algorithms to use with the .B \-\-cipher option. .\"********************************************************* .TP -.B \-\-show-digests +.B \-\-show\-digests (Standalone) Show all message digest algorithms to use with the .B \-\-auth @@ -5114,16 +5114,16 @@ the specific setup of both peers (e.g. both peers must support the cipher, and an ECDSA cipher suite will not work if you are using an RSA certificate, etc.). .\"********************************************************* .TP -.B \-\-show-engines +.B \-\-show\-engines (Standalone) Show currently available hardware-based crypto acceleration engines supported by the OpenSSL library. .\"********************************************************* .TP -.B \-\-show-curves +.B \-\-show\-curves (Standalone) Show all available elliptic curves to use with the -.B \-\-ecdh-curve +.B \-\-ecdh\-curve option. .\"********************************************************* .SS Generate a random key: @@ -5180,9 +5180,9 @@ option above). One disadvantage of persistent tunnels is that it is harder to automatically configure their MTU value (see -.B \-\-link-mtu +.B \-\-link\-mtu and -.B \-\-tun-mtu +.B \-\-tun\-mtu above). On some platforms such as Windows, TAP-Win32 tunnels are persistent by @@ -5208,7 +5208,7 @@ Optional group to be owner of this tunnel. .SS Windows-Specific Options: .\"********************************************************* .TP -.B \-\-win-sys path +.B \-\-win\-sys path Set the Windows system directory pathname to use when looking for system executables such as .B route.exe @@ -5219,7 +5219,7 @@ not specified, OpenVPN will use the SystemRoot environment variable. This option have changed behaviour in OpenVPN 2.3. Earlier you had to define -.B --win-sys env +.B \-\-win\-sys env to use the SystemRoot environment variable, otherwise it defaulted to C:\\WINDOWS. It is not needed to use the .B env @@ -5227,7 +5227,7 @@ keyword any more, and it will just be ignored. A warning is logged when this is found in the configuration file. .\"********************************************************* .TP -.B \-\-ip-win32 method +.B \-\-ip\-win32 method When using .B \-\-ifconfig on Windows, set the TAP-Win32 adapter @@ -5243,7 +5243,7 @@ to the console telling the user to configure the adapter manually and indicating the IP/netmask which OpenVPN expects the adapter to be set to. -.B dynamic [offset] [lease-time] \-\- +.B dynamic [offset] [lease-time] -- Automatically set the IP address and netmask by replying to DHCP query messages generated by the kernel. This mode is probably the "cleanest" solution @@ -5326,28 +5326,28 @@ mode to restore the TAP-Win32 adapter TCP/IP properties to a DHCP configuration. .\"********************************************************* .TP -.B \-\-route-method m +.B \-\-route\-method m Which method .B m to use for adding routes on Windows? .B adaptive -(default) \-\- Try IP helper API first. If that fails, fall +(default) -- Try IP helper API first. If that fails, fall back to the route.exe shell command. .br .B ipapi -\-\- Use IP helper API. +-- Use IP helper API. .br .B exe -\-\- Call the route.exe shell command. +-- Call the route.exe shell command. .\"********************************************************* .TP -.B \-\-dhcp-option type [parm] +.B \-\-dhcp\-option type [parm] Set extended TAP-Win32 TCP/IP properties, must be used with -.B \-\-ip-win32 dynamic +.B \-\-ip\-win32 dynamic or -.B \-\-ip-win32 adaptive. +.B \-\-ip\-win32 adaptive. This option can be used to set additional TCP/IP properties on the TAP-Win32 adapter, and is particularly useful for configuring an OpenVPN client to access a Samba server @@ -5387,7 +5387,7 @@ then query name server), and .B 8 = h-node (query name server, then broadcast). -.B NBS scope-id \-\- +.B NBS scope-id -- Set NetBIOS over TCP/IP Scope. A NetBIOS Scope ID provides an extended naming service for the NetBIOS over TCP/IP (Known as NBT) module. The primary purpose of a NetBIOS scope ID is to isolate NetBIOS traffic on @@ -5399,11 +5399,11 @@ computers to use the same computer name, as they have different scope IDs. The Scope ID becomes a part of the NetBIOS name, making the name unique. (This description of NetBIOS scopes courtesy of NeonSurge@abyss.com) -.B DISABLE-NBT \-\- +.B DISABLE-NBT -- Disable Netbios-over-TCP/IP. Note that if -.B \-\-dhcp-option +.B \-\-dhcp\-option is pushed via .B \-\-push to a non-windows client, the option will be saved in the client's @@ -5411,7 +5411,7 @@ environment before the up script is called, under the name "foreign_option_{n}". .\"********************************************************* .TP -.B \-\-tap-sleep n +.B \-\-tap\-sleep n Cause OpenVPN to sleep for .B n seconds immediately after the TAP-Win32 adapter state @@ -5421,19 +5421,19 @@ This option is intended to be used to troubleshoot problems with the .B \-\-ifconfig and -.B \-\-ip-win32 +.B \-\-ip\-win32 options, and is used to give the TAP-Win32 adapter time to come up before Windows IP Helper API operations are applied to it. .\"********************************************************* .TP -.B \-\-show-net-up +.B \-\-show\-net\-up Output OpenVPN's view of the system routing table and network adapter list to the syslog or log file after the TUN/TAP adapter has been brought up and any routes have been added. .\"********************************************************* .TP -.B \-\-dhcp-renew +.B \-\-dhcp\-renew Ask Windows to renew the TAP adapter lease on startup. This option is normally unnecessary, as Windows automatically triggers a DHCP renegotiation on the TAP adapter when it @@ -5442,21 +5442,21 @@ Media Status property to "Always Connected", you may need this flag. .\"********************************************************* .TP -.B \-\-dhcp-release +.B \-\-dhcp\-release Ask Windows to release the TAP adapter lease on shutdown. This option has the same caveats as -.B \-\-dhcp-renew +.B \-\-dhcp\-renew above. .\"********************************************************* .TP -.B \-\-register-dns +.B \-\-register\-dns Run net stop dnscache, net start dnscache, ipconfig /flushdns and ipconfig /registerdns on connection initiation. This is known to kick Windows into recognizing pushed DNS servers. .\"********************************************************* .TP -.B \-\-pause-exit +.B \-\-pause\-exit Put up a "press any key to continue" message on the console prior to OpenVPN program exit. This option is automatically used by the Windows explorer when OpenVPN is run on a configuration @@ -5492,20 +5492,20 @@ window to output status/error messages, therefore it is useful to use .B \-\-log or -.B \-\-log-append +.B \-\-log\-append to write these messages to a file. .\"********************************************************* .TP -.B \-\-show-adapters +.B \-\-show\-adapters (Standalone) Show available TAP-Win32 adapters which can be selected using the -.B \-\-dev-node +.B \-\-dev\-node option. On non-Windows systems, the .BR ifconfig (8) command provides similar functionality. .\"********************************************************* .TP -.B \-\-allow-nonadmin [TAP-adapter] +.B \-\-allow\-nonadmin [TAP\-adapter] (Standalone) Set .B TAP-adapter @@ -5520,7 +5520,7 @@ and reloaded. This directive can only be used by an administrator. .\"********************************************************* .TP -.B \-\-show-valid-subnets +.B \-\-show\-valid\-subnets (Standalone) Show valid subnets for .B \-\-dev tun @@ -5533,7 +5533,7 @@ Namely, the point-to-point endpoints used in TUN device emulation must be the middle two addresses of a /30 subnet (netmask 255.255.255.252). .\"********************************************************* .TP -.B \-\-show-net +.B \-\-show\-net (Standalone) Show OpenVPN's view of the system routing table and network adapter list. @@ -5541,7 +5541,7 @@ adapter list. .SS PKCS#11 Standalone Options: .\"********************************************************* .TP -.B \-\-show-pkcs11-ids [provider] [cert_private] +.B \-\-show\-pkcs11\-ids [provider] [cert_private] (Standalone) Show PKCS#11 token object list. Specify cert_private as 1 if certificates are stored as private objects. @@ -5549,7 +5549,7 @@ if certificates are stored as private objects. If p11-kit is present on the system, the .B provider argument is optional; if omitted the default -.B p11-kit-proxy.so +.B p11\-kit\-proxy.so module will be queried. .B \-\-verb @@ -5564,30 +5564,30 @@ as well (except for .B \-\-topology , which has no effect on IPv6). .TP -.B --ifconfig-ipv6 ipv6addr/bits ipv6remote +.B \-\-ifconfig\-ipv6 ipv6addr/bits ipv6remote configure IPv6 address .B ipv6addr/bits on the ``tun'' device. The second parameter is used as route target for -.B --route-ipv6 +.B \-\-route\-ipv6 if no gateway is specified. .TP -.B --route-ipv6 ipv6addr/bits [gateway] [metric] +.B \-\-route\-ipv6 ipv6addr/bits [gateway] [metric] setup IPv6 routing in the system to send the specified IPv6 network into OpenVPN's ``tun''. The gateway parameter is only used for IPv6 routes across ``tap'' devices, and if missing, the ``ipv6remote'' field from -.B --ifconfig-ipv6 +.B \-\-ifconfig\-ipv6 is used. .TP -.B --server-ipv6 ipv6addr/bits +.B \-\-server\-ipv6 ipv6addr/bits convenience-function to enable a number of IPv6 related options at once, namely -.B --ifconfig-ipv6, --ifconfig-ipv6-pool, --tun-ipv6 +.B \-\-ifconfig\-ipv6, \-\-ifconfig\-ipv6\-pool, \-\-tun\-ipv6 and -.B --push tun-ipv6 -Is only accepted if ``--mode server'' or ``--server'' is set. +.B \-\-push tun\-ipv6 +Is only accepted if ``\-\-mode server'' or ``\-\-server'' is set. .TP -.B --ifconfig-ipv6-pool ipv6addr/bits +.B \-\-ifconfig\-ipv6\-pool ipv6addr/bits Specify an IPv6 address pool for dynamic assignment to clients. The pool starts at .B ipv6addr @@ -5596,20 +5596,20 @@ and increments by +1 for every new client (linear mode). The setting controls the size of the pool. Due to implementation details, the pool size must be between /64 and /112. .TP -.B --ifconfig-ipv6-push ipv6addr/bits ipv6remote +.B \-\-ifconfig\-ipv6\-push ipv6addr/bits ipv6remote for ccd/ per-client static IPv6 interface configuration, see -.B --client-config-dir +.B \-\-client\-config\-dir and -.B --ifconfig-push +.B \-\-ifconfig\-push for more details. .TP -.B --iroute-ipv6 ipv6addr/bits +.B \-\-iroute\-ipv6 ipv6addr/bits for ccd/ per-client static IPv6 route configuration, see -.B --iroute +.B \-\-iroute for more details how to setup and use this, and how -.B --iroute +.B \-\-iroute and -.B --route +.B \-\-route interact. .\"********************************************************* @@ -5624,7 +5624,7 @@ of environmental variables for use by user-defined scripts. Executed after TCP/UDP socket bind and TUN/TAP open. .\"********************************************************* .TP -.B \-\-tls-verify +.B \-\-tls\-verify Executed when we have a still untrusted remote peer. .\"********************************************************* .TP @@ -5632,25 +5632,25 @@ Executed when we have a still untrusted remote peer. Executed after connection authentication, or remote IP address change. .\"********************************************************* .TP -.B \-\-client-connect +.B \-\-client\-connect Executed in .B \-\-mode server mode immediately after client authentication. .\"********************************************************* .TP -.B \-\-route-up +.B \-\-route\-up Executed after connection authentication, either immediately after, or some number of seconds after as defined by the -.B \-\-route-delay +.B \-\-route\-delay option. .\"********************************************************* .TP -.B \-\-route-pre-down +.B \-\-route\-pre\-down Executed right before the routes are removed. .\"********************************************************* .TP -.B \-\-client-disconnect +.B \-\-client\-disconnect Executed in .B \-\-mode server mode on client instance shutdown. @@ -5660,14 +5660,14 @@ mode on client instance shutdown. Executed after TCP/UDP and TUN/TAP close. .\"********************************************************* .TP -.B \-\-learn-address +.B \-\-learn\-address Executed in .B \-\-mode server mode whenever an IPv4 address/route or MAC address is added to OpenVPN's internal routing table. .\"********************************************************* .TP -.B \-\-auth-user-pass-verify +.B \-\-auth\-user\-pass\-verify Executed in .B \-\-mode server mode on new client connections, when the client is @@ -5693,7 +5693,7 @@ Can string remapping be disabled? .B A: Yes, by using the -.B \-\-no-name-remapping +.B \-\-no\-name\-remapping option, however this should be considered an advanced option. Here is a brief rundown of OpenVPN's current string types and the @@ -5709,17 +5709,17 @@ true. Alphanumeric, underbar ('_'), dash ('-'), dot ('.'), and at ('@'). -.B \-\-auth-user-pass username: +.B \-\-auth\-user\-pass username: Same as Common Name, with one exception: starting with OpenVPN 2.0.1, the username is passed to the OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY plugin in its raw form, without string remapping. -.B \-\-auth-user-pass password: +.B \-\-auth\-user\-pass password: Any "printable" character except CR or LF. Printable is defined to be a character which will cause the C library isprint() function to return true. -.B \-\-client-config-dir filename as derived from common name or username: +.B \-\-client\-config\-dir filename as derived from common name or username: Alphanumeric, underbar ('_'), dash ('-'), and dot ('.') except for "." or ".." as standalone strings. As of 2.0.1-rc6, the at ('@') character has been added as well for compatibility with the common name character class. @@ -5749,23 +5749,23 @@ which refer to different client instances. .B bytes_received Total number of bytes received from client during VPN session. Set prior to execution of the -.B \-\-client-disconnect +.B \-\-client\-disconnect script. .\"********************************************************* .TP .B bytes_sent Total number of bytes sent to client during VPN session. Set prior to execution of the -.B \-\-client-disconnect +.B \-\-client\-disconnect script. .\"********************************************************* .TP .B common_name The X509 common name of an authenticated client. Set prior to execution of -.B \-\-client-connect, \-\-client-disconnect, +.B \-\-client\-connect, \-\-client\-disconnect, and -.B \-\-auth-user-pass-verify +.B \-\-auth\-user\-pass\-verify scripts. .\"********************************************************* .TP @@ -5787,7 +5787,7 @@ Set on program initiation and reset on SIGHUP. Set to "1" if the .B \-\-log or -.B \-\-log-append +.B \-\-log\-append directives are specified, or "0" otherwise. Set on program initiation and reset on SIGHUP. .\"********************************************************* @@ -5807,7 +5807,7 @@ An option pushed via .B \-\-push to a client which does not natively support it, such as -.B \-\-dhcp-option +.B \-\-dhcp\-option on a non-Windows system, will be recorded to this environmental variable sequence prior to .B \-\-up @@ -5833,7 +5833,7 @@ script execution. .TP .B ifconfig_ipv6_local The local VPN endpoint IPv6 address specified in the -.B \-\-ifconfig-ipv6 +.B \-\-ifconfig\-ipv6 option (first parameter). Set prior to OpenVPN calling the .I ifconfig @@ -5848,7 +5848,7 @@ script execution. .B ifconfig_ipv6_netbits The prefix length of the IPv6 network on the VPN interface. Derived from the /nnn parameter of the IPv6 address in the -.B \-\-ifconfig-ipv6 +.B \-\-ifconfig\-ipv6 option (first parameter). Set prior to OpenVPN calling the .I ifconfig @@ -5862,7 +5862,7 @@ script execution. .TP .B ifconfig_ipv6_remote The remote VPN endpoint IPv6 address specified in the -.B \-\-ifconfig-ipv6 +.B \-\-ifconfig\-ipv6 option (second parameter). Set prior to OpenVPN calling the .I ifconfig @@ -5924,54 +5924,54 @@ script execution. .B ifconfig_pool_local_ip The local virtual IP address for the TUN/TAP tunnel taken from an -.B \-\-ifconfig-push +.B \-\-ifconfig\-push directive if specified, or otherwise from the ifconfig pool (controlled by the -.B \-\-ifconfig-pool +.B \-\-ifconfig\-pool config file directive). Only set for .B \-\-dev tun tunnels. This option is set on the server prior to execution of the -.B \-\-client-connect +.B \-\-client\-connect and -.B \-\-client-disconnect +.B \-\-client\-disconnect scripts. .\"********************************************************* .TP .B ifconfig_pool_netmask The virtual IP netmask for the TUN/TAP tunnel taken from an -.B \-\-ifconfig-push +.B \-\-ifconfig\-push directive if specified, or otherwise from the ifconfig pool (controlled by the -.B \-\-ifconfig-pool +.B \-\-ifconfig\-pool config file directive). Only set for .B \-\-dev tap tunnels. This option is set on the server prior to execution of the -.B \-\-client-connect +.B \-\-client\-connect and -.B \-\-client-disconnect +.B \-\-client\-disconnect scripts. .\"********************************************************* .TP .B ifconfig_pool_remote_ip The remote virtual IP address for the TUN/TAP tunnel taken from an -.B \-\-ifconfig-push +.B \-\-ifconfig\-push directive if specified, or otherwise from the ifconfig pool (controlled by the -.B \-\-ifconfig-pool +.B \-\-ifconfig\-pool config file directive). This option is set on the server prior to execution of the -.B \-\-client-connect +.B \-\-client\-connect and -.B \-\-client-disconnect +.B \-\-client\-disconnect scripts. .\"********************************************************* .TP @@ -6003,9 +6003,9 @@ Set on program initiation and reset on SIGHUP. .B password The password provided by a connecting client. Set prior to -.B \-\-auth-user-pass-verify +.B \-\-auth\-user\-pass\-verify script execution only when the -.B via-env +.B via\-env modifier is specified, and deleted from the environment after the script returns. .\"********************************************************* @@ -6044,7 +6044,7 @@ script execution. The default gateway used by .B \-\-route options, as specified in either the -.B \-\-route-gateway +.B \-\-route\-gateway option or the second parameter to .B \-\-ifconfig when @@ -6095,7 +6095,7 @@ or configuration file. .TP .B peer_cert Temporary file name containing the client certificate upon -connection. Useful in conjunction with --tls-verify +connection. Useful in conjunction with \-\-tls\-verify .\"********************************************************* .TP .B script_context @@ -6108,10 +6108,10 @@ documentation for .B script_type Prior to execution of any script, this variable is set to the type of script being run. It can be one of the following: -.B up, down, ipchange, route-up, tls-verify, auth-user-pass-verify, -.B client-connect, client-disconnect, +.B up, down, ipchange, route\-up, tls\-verify, auth\-user\-pass\-verify, +.B client\-connect, client\-disconnect, or -.B learn-address. +.B learn\-address. Set prior to execution of any script. .\"********************************************************* .TP @@ -6121,15 +6121,15 @@ The reason for exit or restart. Can be one of (controlled by .B \-\-inactive option), -.B ping-exit +.B ping\-exit (controlled by -.B \-\-ping-exit +.B \-\-ping\-exit option), -.B ping-restart +.B ping\-restart (controlled by -.B \-\-ping-restart +.B \-\-ping\-restart option), -.B connection-reset +.B connection\-reset (triggered on TCP connection reset), .B error, or @@ -6141,7 +6141,7 @@ or Client connection timestamp, formatted as a human-readable time string. Set prior to execution of the -.B \-\-client-connect +.B \-\-client\-connect script. .\"********************************************************* .TP @@ -6149,7 +6149,7 @@ script. The duration (in seconds) of the client session which is now disconnecting. Set prior to execution of the -.B \-\-client-disconnect +.B \-\-client\-disconnect script. .\"********************************************************* .TP @@ -6157,7 +6157,7 @@ script. Client connection timestamp, formatted as a unix integer date/time value. Set prior to execution of the -.B \-\-client-connect +.B \-\-client\-connect script. .\"********************************************************* .TP @@ -6167,7 +6167,7 @@ where .B n is the verification level. Only set for TLS connections. Set prior to execution of -.B \-\-tls-verify +.B \-\-tls\-verify script. .\"********************************************************* .TP @@ -6177,7 +6177,7 @@ where .B n is the verification level. Only set for TLS connections. Set prior to execution of -.B \-\-tls-verify +.B \-\-tls\-verify script. .\"********************************************************* .TP @@ -6187,7 +6187,7 @@ where .B n is the verification level. Only set for TLS connections. Set prior to execution of -.B \-\-tls-verify +.B \-\-tls\-verify script. This is in the form of a decimal string like "933971680", which is suitable for doing serial-based OCSP queries (with OpenSSL, do not prepend "0x" to the string) If something goes wrong while reading @@ -6214,9 +6214,9 @@ script execution. .B trusted_ip (or trusted_ip6) Actual IP address of connecting client or peer which has been authenticated. Set prior to execution of -.B \-\-ipchange, \-\-client-connect, +.B \-\-ipchange, \-\-client\-connect, and -.B \-\-client-disconnect +.B \-\-client\-disconnect scripts. If using ipv6 endpoints (udp6, tcp6), .B trusted_ip6 @@ -6226,9 +6226,9 @@ will be set instead. .B trusted_port Actual port number of connecting client or peer which has been authenticated. Set prior to execution of -.B \-\-ipchange, \-\-client-connect, +.B \-\-ipchange, \-\-client\-connect, and -.B \-\-client-disconnect +.B \-\-client\-disconnect scripts. .\"********************************************************* .TP @@ -6237,12 +6237,12 @@ Actual IP address of connecting client or peer which has not been authenticated yet. Sometimes used to .B nmap the connecting host in a -.B \-\-tls-verify +.B \-\-tls\-verify script to ensure it is firewalled properly. Set prior to execution of -.B \-\-tls-verify +.B \-\-tls\-verify and -.B \-\-auth-user-pass-verify +.B \-\-auth\-user\-pass\-verify scripts. If using ipv6 endpoints (udp6, tcp6), .B untrusted_ip6 @@ -6253,18 +6253,18 @@ will be set instead. Actual port number of connecting client or peer which has not been authenticated yet. Set prior to execution of -.B \-\-tls-verify +.B \-\-tls\-verify and -.B \-\-auth-user-pass-verify +.B \-\-auth\-user\-pass\-verify scripts. .\"********************************************************* .TP .B username The username provided by a connecting client. Set prior to -.B \-\-auth-user-pass-verify +.B \-\-auth\-user\-pass\-verify script execution only when the -.B via-env +.B via\-env modifier is specified. .\"********************************************************* .TP @@ -6274,7 +6274,7 @@ where .B n is the verification level. Only set for TLS connections. Set prior to execution of -.B \-\-tls-verify +.B \-\-tls\-verify script. This variable is similar to .B tls_id_{n} except the component X509 subject fields are broken out, and @@ -6282,7 +6282,7 @@ no string remapping occurs on these field values (except for remapping of control characters to "_"). For example, the following variables would be set on the OpenVPN server using the sample client certificate -in sample-keys (client.crt). +in sample\-keys (client.crt). Note that the verification level is 0 for the client certificate and 1 for the CA certificate. @@ -6305,9 +6305,9 @@ X509_1_C=KG .\"********************************************************* .SH INLINE FILE SUPPORT OpenVPN allows including files in the main configuration for the -.B \-\-ca, \-\-cert, \-\-dh, \-\-extra-certs, \-\-key, \-\-pkcs12, \-\-secret +.B \-\-ca, \-\-cert, \-\-dh, \-\-extra\-certs, \-\-key, \-\-pkcs12, \-\-secret and -.B \-\-tls-auth +.B \-\-tls\-auth options. Each inline file started by the line @@ -6332,7 +6332,7 @@ Here is an example of an inline file usage When using the inline file feature with .B \-\-pkcs12 the inline file has to be base64 encoded. Encoding of a .p12 file into base64 can be done for example with OpenSSL by running -.B openssl base64 -in input.p12 +.B openssl base64 \-in input.p12 .SH SIGNALS .TP @@ -6349,18 +6349,18 @@ Like except don't re-read configuration file, and possibly don't close and reopen TUN/TAP device, re-read key files, preserve local IP address/port, or preserve most recently authenticated remote IP address/port based on -.B \-\-persist-tun, \-\-persist-key, \-\-persist-local-ip, +.B \-\-persist\-tun, \-\-persist\-key, \-\-persist\-local\-ip, and -.B \-\-persist-remote-ip +.B \-\-persist\-remote\-ip options respectively (see above). This signal may also be internally generated by a timeout condition, governed by the -.B \-\-ping-restart +.B \-\-ping\-restart option. This signal, when combined with -.B \-\-persist-remote-ip, +.B \-\-persist\-remote\-ip, may be sent when the underlying parameters of the host's network interface change such as when the host is a DHCP client and is assigned a new IP address. @@ -6430,7 +6430,7 @@ without an explicit firewall rule). If you are using a Linux iptables-based firewall, you may need to enter the following command to allow incoming packets on the TUN device: .IP -.B iptables -A INPUT -i tun+ -j ACCEPT +.B iptables \-A INPUT \-i tun+ \-j ACCEPT .LP See the firewalls section below for more information on configuring firewalls for use with OpenVPN. @@ -6571,11 +6571,11 @@ parameters you can use the included file dh1024.pem. .LP On may: .IP -.B openvpn \-\-remote june.kg \-\-dev tun1 \-\-ifconfig 10.4.0.1 10.4.0.2 \-\-tls-client \-\-ca ca.crt \-\-cert client.crt \-\-key client.key \-\-reneg-sec 60 \-\-verb 5 +.B openvpn \-\-remote june.kg \-\-dev tun1 \-\-ifconfig 10.4.0.1 10.4.0.2 \-\-tls\-client \-\-ca ca.crt \-\-cert client.crt \-\-key client.key \-\-reneg\-sec 60 \-\-verb 5 .LP On june: .IP -.B openvpn \-\-remote may.kg \-\-dev tun1 \-\-ifconfig 10.4.0.2 10.4.0.1 \-\-tls-server \-\-dh dh1024.pem \-\-ca ca.crt \-\-cert server.crt \-\-key server.key \-\-reneg-sec 60 \-\-verb 5 +.B openvpn \-\-remote may.kg \-\-dev tun1 \-\-ifconfig 10.4.0.2 10.4.0.1 \-\-tls\-server \-\-dh dh1024.pem \-\-ca ca.crt \-\-cert server.crt \-\-key server.key \-\-reneg\-sec 60 \-\-verb 5 .LP Now verify the tunnel is working by pinging across the tunnel. .LP @@ -6588,7 +6588,7 @@ On june: .B ping 10.4.0.1 .LP Notice the -.B \-\-reneg-sec 60 +.B \-\-reneg\-sec 60 option we used above. That tells OpenVPN to renegotiate the data channel keys every minute. Since we used @@ -6597,7 +6597,7 @@ above, you will see status information on each new key negotiation. For production operations, a key renegotiation interval of 60 seconds is probably too frequent. Omit the -.B \-\-reneg-sec 60 +.B \-\-reneg\-sec 60 option to use OpenVPN's default key renegotiation interval of one hour. .\"********************************************************* .SS Routing: @@ -6617,15 +6617,15 @@ On Linux, enable routing: .LP and enable TUN packet forwarding through the firewall: .IP -.B iptables -A FORWARD -i tun+ -j ACCEPT +.B iptables \-A FORWARD \-i tun+ \-j ACCEPT .LP On may: .IP -.B route add -net 10.0.1.0 netmask 255.255.255.0 gw 10.4.0.2 +.B route add \-net 10.0.1.0 netmask 255.255.255.0 gw 10.4.0.2 .LP On june: .IP -.B route add -net 10.0.0.0 netmask 255.255.255.0 gw 10.4.0.1 +.B route add \-net 10.0.0.0 netmask 255.255.255.0 gw 10.4.0.1 .LP Now any machine on the 10.0.0.0/24 subnet can access any machine on the 10.0.1.0/24 subnet @@ -6641,7 +6641,7 @@ OpenVPN's usage of a single UDP port makes it fairly firewall-friendly. You should add an entry to your firewall rules to allow incoming OpenVPN packets. On Linux 2.4+: .IP -.B iptables -A INPUT -p udp -s 1.2.3.4 \-\-dport 1194 -j ACCEPT +.B iptables \-A INPUT \-p udp \-s 1.2.3.4 \-\-dport 1194 \-j ACCEPT .LP This will allow incoming packets on UDP port 1194 (OpenVPN's default UDP port) from an OpenVPN peer at 1.2.3.4. @@ -6652,7 +6652,7 @@ address can be considered optional, since HMAC packet authentication is a much more secure method of verifying the authenticity of a packet source. In that case: .IP -.B iptables -A INPUT -p udp \-\-dport 1194 -j ACCEPT +.B iptables \-A INPUT \-p udp \-\-dport 1194 \-j ACCEPT .LP would be adequate and would not render the host inflexible with respect to its peer having a dynamic IP address. @@ -6674,20 +6674,20 @@ firewall rules. You should also add firewall rules to allow incoming IP traffic on TUN or TAP devices such as: .IP -.B iptables -A INPUT -i tun+ -j ACCEPT +.B iptables \-A INPUT \-i tun+ \-j ACCEPT .LP to allow input packets from tun devices, .IP -.B iptables -A FORWARD -i tun+ -j ACCEPT +.B iptables \-A FORWARD \-i tun+ \-j ACCEPT .LP to allow input packets from tun devices to be forwarded to other hosts on the local network, .IP -.B iptables -A INPUT -i tap+ -j ACCEPT +.B iptables \-A INPUT \-i tap+ \-j ACCEPT .LP to allow input packets from tap devices, and .IP -.B iptables -A FORWARD -i tap+ -j ACCEPT +.B iptables \-A FORWARD \-i tap+ \-j ACCEPT .LP to allow input packets from tap devices to be forwarded to other hosts on the local network. From ddb1f20a9ddbb94956c9f7b1115c89543d9b411a Mon Sep 17 00:00:00 2001 From: Felix Janda Date: Sat, 16 May 2015 15:59:50 +0200 Subject: [PATCH 030/643] Use OPENVPN_ETH_P_* so that is unecessary Fixes compilation error on linux with musl libc because of conflicting ethhdr declarations in and which is included from Signed-off-by: Felix Janda Acked-by: Steffan Karger Message-Id: <20150516134604.GA2302@euler> URL: http://article.gmane.org/gmane.network.openvpn.devel/9690 Signed-off-by: Gert Doering --- configure.ac | 2 +- src/openvpn/syshead.h | 4 ---- src/openvpn/tun.c | 4 ++-- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/configure.ac b/configure.ac index 91324688141..5dccfbbc920 100644 --- a/configure.ac +++ b/configure.ac @@ -461,7 +461,7 @@ SOCKET_INCLUDES=" " AC_CHECK_HEADERS( - [net/if.h netinet/ip.h netinet/if_ether.h resolv.h sys/un.h net/if_utun.h sys/kern_control.h], + [net/if.h netinet/ip.h resolv.h sys/un.h net/if_utun.h sys/kern_control.h], , , [[${SOCKET_INCLUDES}]] diff --git a/src/openvpn/syshead.h b/src/openvpn/syshead.h index b898bf2f363..cf29131f2bc 100644 --- a/src/openvpn/syshead.h +++ b/src/openvpn/syshead.h @@ -214,10 +214,6 @@ #if defined(TARGET_LINUX) || defined (TARGET_ANDROID) -#if defined(HAVE_NETINET_IF_ETHER_H) -#include -#endif - #ifdef HAVE_LINUX_IF_TUN_H #include #endif diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index 11a6d714cd1..ce3ed853ba9 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -1856,9 +1856,9 @@ write_tun (struct tuntap* tt, uint8_t *buf, int len) pi.flags = 0; if(iph->version == 6) - pi.proto = htons(ETH_P_IPV6); + pi.proto = htons(OPENVPN_ETH_P_IPV6); else - pi.proto = htons(ETH_P_IP); + pi.proto = htons(OPENVPN_ETH_P_IPV4); vect[0].iov_len = sizeof(pi); vect[0].iov_base = π From d3eacb2d6ebb8a42506343c54e00c72252d683f8 Mon Sep 17 00:00:00 2001 From: Robert Fischer Date: Mon, 18 May 2015 21:21:09 +0200 Subject: [PATCH 031/643] Updated manpage for --rport and --lport [SK: v2, patch taken from trac #127 and updated to current master branch] Signed-off-by: Robert Fischer Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1431976869-4948-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/9701 Signed-off-by: Gert Doering --- doc/openvpn.8 | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 23cc789cf2b..b9eee0d9a8d 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -670,18 +670,28 @@ peer on its new IP address. .\"********************************************************* .TP .B \-\-port port -TCP/UDP port number or port name for both local and remote. The current +TCP/UDP port number or port name for both local and remote (sets both +.B \-\-lport +and +.B \-\-rport +options to given port). The current default of 1194 represents the official IANA port number assignment for OpenVPN and has been used since version 2.0-beta17. Previous versions used port 5000 as the default. .\"********************************************************* .TP .B \-\-lport port -TCP/UDP port number or name for bind. +Set local TCP/UDP port number or name. Cannot be used together with +.B \-\-nobind +option. .\"********************************************************* .TP .B \-\-rport port -TCP/UDP port number or name for remote. +Set TCP/UDP port number or name used by the +.B \-\-remote +option. The port can also be set directly using the +.B \-\-remote +option. .\"********************************************************* .TP .B \-\-bind [ipv6only] From db950be85d37eab40d8fffe0bc2060059f8a7e10 Mon Sep 17 00:00:00 2001 From: Jan Just Keijser Date: Wed, 20 May 2015 04:33:20 +0200 Subject: [PATCH 032/643] include ifconfig_ environment variables in --up-restart env set here's my patch for bug #93: missing ifconfig_* env vars after up-restart. Tested with both IPv4, IPv6, topology subnet and topology net30 Document differences between --up-restart and --up in openvpn.8 See trac #93 and the discussion starting with <555BF270.3090706@nikhef.nl> on the openvpn-devel mailing list. fix trac #93 Acked-by: Gert Doering Message-Id: <555BF270.3090706@nikhef.nl> URL: http://article.gmane.org/gmane.network.openvpn.devel/9705 Signed-off-by: Gert Doering --- doc/openvpn.8 | 6 ++++ src/openvpn/init.c | 3 ++ src/openvpn/tun.c | 87 +++++++++++++++++++++++----------------------- src/openvpn/tun.h | 3 ++ 4 files changed, 56 insertions(+), 43 deletions(-) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index b9eee0d9a8d..ef87bb7223f 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -1817,6 +1817,12 @@ has been specified, the up script will be called with .I restart as the last parameter. +NOTE: on restart, OpenVPN will not pass the full set of environment +variables to the script. Namely, everything related to routing and +gateways will not be passed, as nothing needs to be done anyway - all +the routing setup is already in place. Additionally, the up\-restart +script will run with the downgraded UID/GID settings (if configured). + The following standalone example shows how the .B \-\-up script can be called in both an initialization and restart context. diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 42cb3e201b1..769ab9b514b 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -1486,6 +1486,9 @@ do_open_tun (struct context *c) msg (M_INFO, "Preserving previous TUN/TAP instance: %s", c->c1.tuntap->actual_name); + /* explicitly set the ifconfig_* env vars */ + do_ifconfig_setenv(c->c1.tuntap, c->c2.es); + /* run the up script if user specified --up-restart */ if (c->options.up_restart) run_up_down (c->options.up_script, diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index ce3ed853ba9..9e853c00368 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -396,6 +396,45 @@ is_tun_p2p (const struct tuntap *tt) return tun; } +/* + * Set the ifconfig_* environment variables, both for IPv4 and IPv6 + */ +void +do_ifconfig_setenv (const struct tuntap *tt, struct env_set *es) +{ + struct gc_arena gc = gc_new (); + bool tun = is_tun_p2p (tt); + const char *ifconfig_local = print_in_addr_t (tt->local, 0, &gc); + const char *ifconfig_remote_netmask = print_in_addr_t (tt->remote_netmask, 0, &gc); + + /* + * Set environmental variables with ifconfig parameters. + */ + setenv_str (es, "ifconfig_local", ifconfig_local); + if (tun) + { + setenv_str (es, "ifconfig_remote", ifconfig_remote_netmask); + } + else + { + const char *ifconfig_broadcast = print_in_addr_t (tt->broadcast, 0, &gc); + setenv_str (es, "ifconfig_netmask", ifconfig_remote_netmask); + setenv_str (es, "ifconfig_broadcast", ifconfig_broadcast); + } + + if (tt->did_ifconfig_ipv6_setup) + { + const char *ifconfig_ipv6_local = print_in6_addr (tt->local_ipv6, 0, &gc); + const char *ifconfig_ipv6_remote = print_in6_addr (tt->remote_ipv6, 0, &gc); + + setenv_str (es, "ifconfig_ipv6_local", ifconfig_ipv6_local); + setenv_int (es, "ifconfig_ipv6_netbits", tt->netbits_ipv6); + setenv_str (es, "ifconfig_ipv6_remote", ifconfig_ipv6_remote); + } + + gc_free (&gc); +} + /* * Init tun/tap object. * @@ -428,9 +467,6 @@ init_tun (const char *dev, /* --dev option */ if (ifconfig_local_parm && ifconfig_remote_netmask_parm) { bool tun = false; - const char *ifconfig_local = NULL; - const char *ifconfig_remote_netmask = NULL; - const char *ifconfig_broadcast = NULL; /* * We only handle TUN/TAP devices here, not --dev null devices. @@ -498,45 +534,20 @@ init_tun (const char *dev, /* --dev option */ check_subnet_conflict (tt->local, IPV4_NETMASK_HOST, "TUN/TAP adapter"); } - /* - * Set ifconfig parameters - */ - ifconfig_local = print_in_addr_t (tt->local, 0, &gc); - ifconfig_remote_netmask = print_in_addr_t (tt->remote_netmask, 0, &gc); - /* * If TAP-style interface, generate broadcast address. */ if (!tun) { tt->broadcast = generate_ifconfig_broadcast_addr (tt->local, tt->remote_netmask); - ifconfig_broadcast = print_in_addr_t (tt->broadcast, 0, &gc); } - /* - * Set environmental variables with ifconfig parameters. - */ - if (es) - { - setenv_str (es, "ifconfig_local", ifconfig_local); - if (tun) - { - setenv_str (es, "ifconfig_remote", ifconfig_remote_netmask); - } - else - { - setenv_str (es, "ifconfig_netmask", ifconfig_remote_netmask); - setenv_str (es, "ifconfig_broadcast", ifconfig_broadcast); - } - } tt->did_ifconfig_setup = true; } if (ifconfig_ipv6_local_parm && ifconfig_ipv6_remote_parm) { - const char *ifconfig_ipv6_local = NULL; - const char *ifconfig_ipv6_remote = NULL; /* * Convert arguments to binary IPv6 addresses. @@ -549,24 +560,14 @@ init_tun (const char *dev, /* --dev option */ } tt->netbits_ipv6 = ifconfig_ipv6_netbits_parm; - /* - * Set ifconfig parameters - */ - ifconfig_ipv6_local = print_in6_addr (tt->local_ipv6, 0, &gc); - ifconfig_ipv6_remote = print_in6_addr (tt->remote_ipv6, 0, &gc); - - /* - * Set environmental variables with ifconfig parameters. - */ - if (es) - { - setenv_str (es, "ifconfig_ipv6_local", ifconfig_ipv6_local); - setenv_int (es, "ifconfig_ipv6_netbits", tt->netbits_ipv6); - setenv_str (es, "ifconfig_ipv6_remote", ifconfig_ipv6_remote); - } tt->did_ifconfig_ipv6_setup = true; } + /* + * Set environmental variables with ifconfig parameters. + */ + if (es) do_ifconfig_setenv(tt, es); + gc_free (&gc); return tt; } diff --git a/src/openvpn/tun.h b/src/openvpn/tun.h index 79e2d188396..65bacac0556 100644 --- a/src/openvpn/tun.h +++ b/src/openvpn/tun.h @@ -241,6 +241,9 @@ void init_tun_post (struct tuntap *tt, const struct frame *frame, const struct tuntap_options *options); +void do_ifconfig_setenv (const struct tuntap *tt, + struct env_set *es); + void do_ifconfig (struct tuntap *tt, const char *actual, /* actual device name */ int tun_mtu, From 827de237860813d2859aaae3aca292d42a9c2a82 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sun, 3 May 2015 17:07:11 +0200 Subject: [PATCH 033/643] cleanup: remove md5 helper functions The MD5 wrapper functions were used in just a few places, which imho is not worth the extra code. Instead of using these wrappers, just use the generic md_ctx_*() functions directly. The md5sum() function was only used for logging information that was not useful to a user; first the full options string would be printed, and later just the hash. That hash is less informative than the full string, so why print it at all? Finally, also removed save_pulled_options_digest(). The two times it was called, it executed either one of the possible branches in the function, where one of these needed a comment to explain what passing NULL as newdigest is supposed to do... Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1430665631-4022-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/9642 Signed-off-by: Gert Doering --- src/openvpn/crypto.c | 58 ------------------------------------------ src/openvpn/crypto.h | 20 --------------- src/openvpn/errlevel.h | 1 - src/openvpn/init.c | 56 ++++++++++++++++++---------------------- src/openvpn/openvpn.h | 6 ++--- src/openvpn/push.c | 9 ++++--- 6 files changed, 33 insertions(+), 117 deletions(-) diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c index c1b9df31712..588d9f05436 100644 --- a/src/openvpn/crypto.c +++ b/src/openvpn/crypto.c @@ -1335,62 +1335,4 @@ get_random() return l; } -/* - * md5 functions - */ - -const char * -md5sum (uint8_t *buf, int len, int n_print_chars, struct gc_arena *gc) -{ - uint8_t digest[MD5_DIGEST_LENGTH]; - const md_kt_t *md5_kt = md_kt_get("MD5"); - - md_full(md5_kt, buf, len, digest); - - return format_hex (digest, MD5_DIGEST_LENGTH, n_print_chars, gc); -} - -void -md5_state_init (struct md5_state *s) -{ - const md_kt_t *md5_kt = md_kt_get("MD5"); - - md_ctx_init(&s->ctx, md5_kt); -} - -void -md5_state_update (struct md5_state *s, void *data, size_t len) -{ - md_ctx_update(&s->ctx, data, len); -} - -void -md5_state_final (struct md5_state *s, struct md5_digest *out) -{ - md_ctx_final(&s->ctx, out->digest); - md_ctx_cleanup(&s->ctx); -} - -void -md5_digest_clear (struct md5_digest *digest) -{ - CLEAR (*digest); -} - -bool -md5_digest_defined (const struct md5_digest *digest) -{ - int i; - for (i = 0; i < MD5_DIGEST_LENGTH; ++i) - if (digest->digest[i]) - return true; - return false; -} - -bool -md5_digest_equal (const struct md5_digest *d1, const struct md5_digest *d2) -{ - return memcmp(d1->digest, d2->digest, MD5_DIGEST_LENGTH) == 0; -} - #endif /* ENABLE_CRYPTO */ diff --git a/src/openvpn/crypto.h b/src/openvpn/crypto.h index 82158f9c160..504896dee13 100644 --- a/src/openvpn/crypto.h +++ b/src/openvpn/crypto.h @@ -420,26 +420,6 @@ void get_tls_handshake_key (const struct key_type *key_type, const int key_direction, const unsigned int flags); -/* - * md5 functions - */ - -struct md5_state { - md_ctx_t ctx; -}; - -struct md5_digest { - uint8_t digest [MD5_DIGEST_LENGTH]; -}; - -const char *md5sum(uint8_t *buf, int len, int n_print_chars, struct gc_arena *gc); -void md5_state_init (struct md5_state *s); -void md5_state_update (struct md5_state *s, void *data, size_t len); -void md5_state_final (struct md5_state *s, struct md5_digest *out); -void md5_digest_clear (struct md5_digest *digest); -bool md5_digest_defined (const struct md5_digest *digest); -bool md5_digest_equal (const struct md5_digest *d1, const struct md5_digest *d2); - /* * Inline functions */ diff --git a/src/openvpn/errlevel.h b/src/openvpn/errlevel.h index 3ee4ebc3624..da600ab8a18 100644 --- a/src/openvpn/errlevel.h +++ b/src/openvpn/errlevel.h @@ -105,7 +105,6 @@ #define D_X509_ATTR LOGLEV(4, 59, 0) /* show x509-track attributes on connection */ #define D_INIT_MEDIUM LOGLEV(4, 60, 0) /* show medium frequency init messages */ #define D_MTU_INFO LOGLEV(4, 61, 0) /* show terse MTU info */ -#define D_SHOW_OCC_HASH LOGLEV(4, 62, 0) /* show MD5 hash of option compatibility string */ #define D_PID_DEBUG_LOW LOGLEV(4, 63, 0) /* show low-freq packet-id debugging info */ #define D_PID_DEBUG_MEDIUM LOGLEV(4, 64, 0) /* show medium-freq packet-id debugging info */ diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 769ab9b514b..3434ce07d9a 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -1329,21 +1329,6 @@ do_route (const struct options *options, #endif } -/* - * Save current pulled options string in the c1 context store, so we can - * compare against it after possible future restarts. - */ -#if P2MP -static void -save_pulled_options_digest (struct context *c, const struct md5_digest *newdigest) -{ - if (newdigest) - c->c1.pulled_options_digest_save = *newdigest; - else - md5_digest_clear (&c->c1.pulled_options_digest_save); -} -#endif - /* * initialize tun/tap device object */ @@ -1522,7 +1507,7 @@ do_close_tun_simple (struct context *c) c->c1.tuntap = NULL; c->c1.tuntap_owned = false; #if P2MP - save_pulled_options_digest (c, NULL); /* delete C1-saved pulled_options_digest */ + CLEAR (c->c1.pulled_options_digest_save); #endif } @@ -1634,6 +1619,20 @@ tun_abort() * Handle delayed tun/tap interface bringup due to --up-delay or --pull */ +#if P2MP +/** + * Helper for do_up(). Take two option hashes and return true if they are not + * equal, or either one is all-zeroes. + */ +static bool +options_hash_changed_or_zero(const uint8_t (*a)[MD5_DIGEST_LENGTH], + const uint8_t (*b)[MD5_DIGEST_LENGTH]) +{ + const uint8_t zero[MD5_DIGEST_LENGTH] = {0}; + return memcmp (*a, *b, MD5_DIGEST_LENGTH) || memcmp (*a, zero, MD5_DIGEST_LENGTH); +} +#endif /* P2MP */ + void do_up (struct context *c, bool pulled_options, unsigned int option_types_found) { @@ -1658,8 +1657,8 @@ do_up (struct context *c, bool pulled_options, unsigned int option_types_found) if (!c->c2.did_open_tun && PULL_DEFINED (&c->options) && c->c1.tuntap - && (!md5_digest_defined (&c->c1.pulled_options_digest_save) || !md5_digest_defined (&c->c2.pulled_options_digest) - || !md5_digest_equal (&c->c1.pulled_options_digest_save, &c->c2.pulled_options_digest))) + && options_hash_changed_or_zero (&c->c1.pulled_options_digest_save, + &c->c2.pulled_options_digest)) { /* if so, close tun, delete routes, then reinitialize tun and add routes */ msg (M_INFO, "NOTE: Pulled options changed on restart, will need to close and reopen TUN/TAP device."); @@ -1674,7 +1673,8 @@ do_up (struct context *c, bool pulled_options, unsigned int option_types_found) if (c->c2.did_open_tun) { #if P2MP - save_pulled_options_digest (c, &c->c2.pulled_options_digest); + memcpy(c->c1.pulled_options_digest_save, c->c2.pulled_options_digest, + sizeof(c->c1.pulled_options_digest_save)); #endif /* if --route-delay was specified, start timer */ @@ -2732,20 +2732,14 @@ do_compute_occ_strings (struct context *c) c->c2.options_string_remote = options_string (&c->options, &c->c2.frame, c->c1.tuntap, true, &gc); - msg (D_SHOW_OCC, "Local Options String: '%s'", c->c2.options_string_local); - msg (D_SHOW_OCC, "Expected Remote Options String: '%s'", - c->c2.options_string_remote); + msg (D_SHOW_OCC, "Local Options String (VER=%s): '%s'", + options_string_version (c->c2.options_string_local, &gc), + c->c2.options_string_local); + msg (D_SHOW_OCC, "Expected Remote Options String (VER=%s): '%s'", + options_string_version (c->c2.options_string_remote, &gc), + c->c2.options_string_remote); #ifdef ENABLE_CRYPTO - msg (D_SHOW_OCC_HASH, "Local Options hash (VER=%s): '%s'", - options_string_version (c->c2.options_string_local, &gc), - md5sum ((uint8_t*)c->c2.options_string_local, - strlen (c->c2.options_string_local), 9, &gc)); - msg (D_SHOW_OCC_HASH, "Expected Remote Options hash (VER=%s): '%s'", - options_string_version (c->c2.options_string_remote, &gc), - md5sum ((uint8_t*)c->c2.options_string_remote, - strlen (c->c2.options_string_remote), 9, &gc)); - if (c->c2.tls_multi) tls_multi_init_set_options (c->c2.tls_multi, c->c2.options_string_local, diff --git a/src/openvpn/openvpn.h b/src/openvpn/openvpn.h index fb532a2f64b..9ab50b80b5e 100644 --- a/src/openvpn/openvpn.h +++ b/src/openvpn/openvpn.h @@ -202,7 +202,7 @@ struct context_1 #endif /* if client mode, hash of option strings we pulled from server */ - struct md5_digest pulled_options_digest_save; + uint8_t pulled_options_digest_save[MD5_DIGEST_LENGTH]; /**< Hash of option strings received from the * remote OpenVPN server. Only used in * client-mode. */ @@ -467,8 +467,8 @@ struct context_2 /* hash of pulled options, so we can compare when options change */ bool pulled_options_md5_init_done; - struct md5_state pulled_options_state; - struct md5_digest pulled_options_digest; + md_ctx_t pulled_options_state; + uint8_t pulled_options_digest[MD5_DIGEST_LENGTH]; struct event_timeout server_poll_interval; diff --git a/src/openvpn/push.c b/src/openvpn/push.c index 932df5cf23c..c99a097d188 100644 --- a/src/openvpn/push.c +++ b/src/openvpn/push.c @@ -465,7 +465,7 @@ process_incoming_push_msg (struct context *c, struct buffer buf_orig = buf; if (!c->c2.pulled_options_md5_init_done) { - md5_state_init (&c->c2.pulled_options_state); + md_ctx_init(&c->c2.pulled_options_state, md_kt_get("MD5")); c->c2.pulled_options_md5_init_done = true; } if (!c->c2.did_pre_pull_restore) @@ -482,13 +482,14 @@ process_incoming_push_msg (struct context *c, { case 0: case 1: - md5_state_update (&c->c2.pulled_options_state, BPTR(&buf_orig), BLEN(&buf_orig)); - md5_state_final (&c->c2.pulled_options_state, &c->c2.pulled_options_digest); + md_ctx_update (&c->c2.pulled_options_state, BPTR(&buf_orig), BLEN(&buf_orig)); + md_ctx_final (&c->c2.pulled_options_state, c->c2.pulled_options_digest); + md_ctx_cleanup (&c->c2.pulled_options_state); c->c2.pulled_options_md5_init_done = false; ret = PUSH_MSG_REPLY; break; case 2: - md5_state_update (&c->c2.pulled_options_state, BPTR(&buf_orig), BLEN(&buf_orig)); + md_ctx_update (&c->c2.pulled_options_state, BPTR(&buf_orig), BLEN(&buf_orig)); ret = PUSH_MSG_CONTINUATION; break; } From 970c4bd2e473f625699bd56db44c1970a9e10ed9 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Sat, 23 May 2015 19:35:05 +0200 Subject: [PATCH 034/643] repair --dev null breakage caused by db950be85d37 "make check" self-test was broken after commit db950be85d37 due to do_ifconfig_setenv() not checking whether tt->did_ifconfig_setup was set (which isn't, for "dev null" type setups) Signed-off-by: Gert Doering Acked-by: Steffan Karger Message-Id: <1432404098-29401-1-git-send-email-gert@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/9718 Signed-off-by: Gert Doering --- src/openvpn/tun.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index 9e853c00368..e479d4d177d 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -403,23 +403,27 @@ void do_ifconfig_setenv (const struct tuntap *tt, struct env_set *es) { struct gc_arena gc = gc_new (); - bool tun = is_tun_p2p (tt); const char *ifconfig_local = print_in_addr_t (tt->local, 0, &gc); const char *ifconfig_remote_netmask = print_in_addr_t (tt->remote_netmask, 0, &gc); /* * Set environmental variables with ifconfig parameters. */ - setenv_str (es, "ifconfig_local", ifconfig_local); - if (tun) + if (tt->did_ifconfig_setup) { - setenv_str (es, "ifconfig_remote", ifconfig_remote_netmask); - } - else - { - const char *ifconfig_broadcast = print_in_addr_t (tt->broadcast, 0, &gc); - setenv_str (es, "ifconfig_netmask", ifconfig_remote_netmask); - setenv_str (es, "ifconfig_broadcast", ifconfig_broadcast); + bool tun = is_tun_p2p (tt); + + setenv_str (es, "ifconfig_local", ifconfig_local); + if (tun) + { + setenv_str (es, "ifconfig_remote", ifconfig_remote_netmask); + } + else + { + const char *ifconfig_broadcast = print_in_addr_t (tt->broadcast, 0, &gc); + setenv_str (es, "ifconfig_netmask", ifconfig_remote_netmask); + setenv_str (es, "ifconfig_broadcast", ifconfig_broadcast); + } } if (tt->did_ifconfig_ipv6_setup) From ac1cb5bfbb9e09e79fd737bc57999d968d77c5ad Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sat, 23 May 2015 15:02:25 +0200 Subject: [PATCH 035/643] Re-read auth-user-pass file on (re)connect if required Fixes trac #225 ('--auth-user-pass FILE' and '--auth-nocache' problem). This patch is based on the changes suggested by ye_olde_iron in the trac ticket. Also added a note to the manpage to inform people to use absolute paths when combining --auth-user-pass file and --auth-nocache. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1432386145-15045-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/9717 Signed-off-by: Gert Doering --- doc/openvpn.8 | 3 +++ src/openvpn/init.c | 1 + src/openvpn/ssl.c | 4 ++-- src/openvpn/ssl_common.h | 1 + 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index ef87bb7223f..67e6ddd59b9 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -4786,6 +4786,9 @@ when OpenVPN needs a username/password, it will prompt for input from stdin, which may be multiple times during the duration of an OpenVPN session. +When using \-\-auth\-nocache in combination with a user/password file +and \-\-chroot or \-\-daemon, make sure to use an absolute path. + This directive does not affect the .B \-\-http\-proxy username/password. It is always cached. diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 3434ce07d9a..d093f463d3d 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -2252,6 +2252,7 @@ do_init_crypto_tls (struct context *c, const unsigned int flags) to.tmp_dir = options->tmp_dir; if (options->ccd_exclusive) to.client_config_dir_exclusive = options->client_config_dir; + to.auth_user_pass_file = options->auth_user_pass_file; #endif #ifdef ENABLE_X509_TRACK diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index dce6c3042e8..ebb2f0db93e 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -1920,9 +1920,9 @@ key_method_2_write (struct buffer *buf, struct tls_session *session) if (auth_user_pass_enabled) { #ifdef ENABLE_CLIENT_CR - auth_user_pass_setup (NULL, session->opt->sci); + auth_user_pass_setup (session->opt->auth_user_pass_file, session->opt->sci); #else - auth_user_pass_setup (NULL, NULL); + auth_user_pass_setup (session->opt->auth_user_pass_file, NULL); #endif if (!write_string (buf, auth_user_pass.username, -1)) goto error; diff --git a/src/openvpn/ssl_common.h b/src/openvpn/ssl_common.h index bb1c1c281f6..95cd2f7d93d 100644 --- a/src/openvpn/ssl_common.h +++ b/src/openvpn/ssl_common.h @@ -277,6 +277,7 @@ struct tls_options const char *auth_user_pass_verify_script; bool auth_user_pass_verify_script_via_file; const char *tmp_dir; + const char *auth_user_pass_file; /* use the client-config-dir as a positive authenticator */ const char *client_config_dir_exclusive; From 403dc434d245e5df5ae262935aa2e7364547e260 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Mon, 27 Apr 2015 21:27:21 +0200 Subject: [PATCH 036/643] assume res_init() is always there. Previously, the code tried to find res_init(), and on some systems got it wrong in configure, silently not-using res_init(), leading to unexpected failures to re-init the resolver. We know that all supported OSes (except Windows) have res_init(), so change the call to "#ifndef WIN32", and adjust configure.ac to just find the library to link (if any). With that, failures to find res_init() are no longer "hidden" but clearly visible at link time. AC_SEARCH_LIBS() bits inspired by CUPS' cups_network.m4 (GPLv2) Fix (part of) trac #523 Signed-off-by: Gert Doering Lazy-ACK-by: Gert Doering Message-Id: <1430162841-5840-1-git-send-email-gert@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/9614 --- configure.ac | 11 +++++------ src/openvpn/socket.c | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/configure.ac b/configure.ac index 5dccfbbc920..54fe4f53d99 100644 --- a/configure.ac +++ b/configure.ac @@ -613,12 +613,6 @@ AC_SUBST([SOCKETS_LIBS]) old_LIBS="${LIBS}" LIBS="${LIBS} ${SOCKETS_LIBS}" AC_CHECK_FUNCS([sendmsg recvmsg inet_ntop inet_pton]) -AC_CHECK_FUNCS( - [res_init], - , - , - [[#include ]] -) # Windows use stdcall for winsock so we cannot auto detect these m4_define( [SOCKET_FUNCS], @@ -646,6 +640,11 @@ else fi LIBS="${old_LIBS}" +# we assume res_init() always exist, but need to find out *where*... +AC_SEARCH_LIBS(__res_init, resolv bind, , + AC_SEARCH_LIBS(res_9_init, resolv bind, , + AC_SEARCH_LIBS(res_init, resolv bind, , ))) + AC_ARG_VAR([TAP_CFLAGS], [C compiler flags for tap]) old_CFLAGS="${CFLAGS}" CFLAGS="${CFLAGS} ${TAP_CFLAGS}" diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c index afc1e606335..13ed9817424 100644 --- a/src/openvpn/socket.c +++ b/src/openvpn/socket.c @@ -314,7 +314,7 @@ openvpn_getaddrinfo (unsigned int flags, ASSERT(res); -#if defined(HAVE_RES_INIT) +#ifndef WIN32 res_init (); #endif From 025d611fc68aa0c651c391bd6178d062246f36f0 Mon Sep 17 00:00:00 2001 From: "Jonathan K. Bullard" Date: Sat, 23 May 2015 15:33:21 -0400 Subject: [PATCH 037/643] Fix null pointer dereference in options.c Acked-by: Gert Doering Message-Id: URL: http://article.gmane.org/gmane.network.openvpn.devel/9723 Signed-off-by: Gert Doering --- src/openvpn/options.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 6d5e58ea2ca..bc7f3c67566 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -7044,7 +7044,7 @@ add_option (struct options *options, options->persist_config = true; options->persist_mode = 1; } - else if (streq (p[0], "peer-id")) + else if (streq (p[0], "peer-id") && p[1]) { VERIFY_PERMISSION (OPT_P_PEER_ID); options->use_peer_id = true; From 0322510375b5c54f63f5302b9088972d58b32b76 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Sun, 24 May 2015 09:56:12 +0200 Subject: [PATCH 038/643] Correct note about DNS randomization in openvpn.8 Commit 4880739c17b502d00a removed DNS randomization, and the dual-stack patches for 2.4 completely changed the getaddrinfo() result handling again, but neither fact ever made it into the man page. Trac #411 Signed-off-by: Gert Doering Acked-by: Arne Schwabe Message-Id: <1432454172-1318-1-git-send-email-gert@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/9730 --- doc/openvpn.8 | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 67e6ddd59b9..07219c3ec26 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -268,9 +268,11 @@ not match If .B host is a DNS name which resolves to multiple IP addresses, -one will be randomly -chosen, providing a sort of basic load-balancing and -failover capability. +OpenVPN will try them in the order that the system getaddrinfo() +presents them, so priorization and DNS randomization is done +by the system library. Unless an IP version is forced by the +protocol specification (4/6 suffix), OpenVPN will try both IPv4 +and IPv6 addresses, in the order getaddrinfo() returns them. .\"********************************************************* .TP .B \-\-remote\-random\-hostname From f4684ff2b5622a26c7c2e620e789b7dca8cfd778 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sun, 24 May 2015 11:45:40 +0200 Subject: [PATCH 039/643] Clarify --capath option in manpage Prevent confusion as described in trac #422 by better explaining the behaviour of --capath, and providing pointers to relevant openssl man pages. Attached are patches for the master and release/2.3 branches. The only difference is that in the master patch, a line referencing the requirement for OpenSSL 0.9.7 is removed, since master already requires OpenSSL >= 0.9.8. -Steffan Content-Type: text/x-patch; name="2.3-Clarify-capath-option-in-manpage.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="2.3-Clarify-capath-option-in-manpage.patch" >From 3626088e146dbf959d7ec73f4e7cc5ab24c1ad57 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sun, 24 May 2015 11:18:34 +0200 Subject: [PATCH] Clarify --capath option in manpage Prevent confusion as described in trac #422 by better explaining the behaviour of --capath, and providing pointers to relevant openssl man pages. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <55619DC4.2020108@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/9732 Signed-off-by: Gert Doering --- doc/openvpn.8 | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 07219c3ec26..b1c2fab558e 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -4271,8 +4271,23 @@ they are distributed with OpenVPN, they are totally insecure. .TP .B \-\-capath dir Directory containing trusted certificates (CAs and CRLs). -Available with OpenSSL version >= 0.9.7 dev. Not available with PolarSSL. + +When using the +.B \-\-capath +option, you are required to supply valid CRLs for the CAs too. CAs in the +capath directory are expected to be named .. CRLs are expected to +be named .r. See the +.B -CApath +option of +.B openssl verify +, and the +.B -hash +option of +.B openssl x509 +and +.B openssl crl +for more information. .\"********************************************************* .TP .B \-\-dh file From 6478c1f359e6b0ea2046d9e2801830753e53c06a Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Sun, 24 May 2015 15:02:34 +0200 Subject: [PATCH 040/643] Disallow usage of --server-poll-timeout in --secret key mode. The internal machinery wants TLS for this to work, so just add this to the (long) list of options not allowed unless either --tls-client or --tls-server is active. For added sanity, add an ASSERT() call to the place where this combination caused a NULL ptr reference, and document the restriction. Fix trac #373 Signed-off-by: Gert Doering Acked-by: Steffan Karger Message-Id: <1432472554-24666-1-git-send-email-gert@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/9736 --- doc/openvpn.8 | 4 ++++ src/openvpn/forward.c | 1 + src/openvpn/options.c | 3 +++ 3 files changed, 8 insertions(+) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index b1c2fab558e..3fff3f2c41d 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -3783,6 +3783,10 @@ when polling possible remote servers to connect to in a round-robin fashion, spend no more than .B n seconds waiting for a response before trying the next server. +As this only makes sense in client-to-server setups, it cannot +be used in point-to-point setups using +.B \-\-secret +symmetrical key mode. .\"********************************************************* .TP .B \-\-explicit\-exit\-notify [n] diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c index a3323e92df2..6d459d2db50 100644 --- a/src/openvpn/forward.c +++ b/src/openvpn/forward.c @@ -328,6 +328,7 @@ void check_server_poll_timeout_dowork (struct context *c) { event_timeout_reset (&c->c2.server_poll_interval); + ASSERT(c->c2.tls_multi); if (!tls_initial_packet_received (c->c2.tls_multi)) { msg (M_INFO, "Server poll timeout, restarting"); diff --git a/src/openvpn/options.c b/src/openvpn/options.c index bc7f3c67566..8487ce1405e 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -2310,6 +2310,9 @@ options_postprocess_verify_ce (const struct options *options, const struct conne MUST_BE_UNDEF (pkcs11_id); MUST_BE_UNDEF (pkcs11_id_management); #endif +#if P2MP + MUST_BE_UNDEF (server_poll_timeout); +#endif if (pull) msg (M_USAGE, err, "--pull"); From da9b292733e929a2900dc32d37f0424c3d588366 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Mon, 27 Apr 2015 16:28:57 +0200 Subject: [PATCH 041/643] Call daemon() before initializing crypto library But keep the chdir to / at the place where deamon() was before, to preserve the current behaviour wrt relative paths in the config. This should fix the issue reported in trac #480, without changing the behaviour visible to the end user. Note that by moving the daemon() call to an earlier stage of the init process, we no longer have to call platform_mlockall() again, or do a pkcs11_forkFixup(). Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1430144937-4149-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/9609 Signed-off-by: Gert Doering --- src/openvpn/init.c | 32 +++++++++++--------------------- src/openvpn/init.h | 2 ++ src/openvpn/openvpn.c | 4 ++++ src/openvpn/pkcs11.c | 5 ----- src/openvpn/pkcs11.h | 3 --- 5 files changed, 17 insertions(+), 29 deletions(-) diff --git a/src/openvpn/init.c b/src/openvpn/init.c index d093f463d3d..3daf5a46efa 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -922,23 +922,20 @@ do_persist_tuntap (const struct options *options) * Should we become a daemon? * Return true if we did it. */ -static bool +bool possibly_become_daemon (const struct options *options) { bool ret = false; if (options->daemon) { ASSERT (!options->inetd); - if (daemon (options->cd_dir != NULL, options->log) < 0) + /* Don't chdir immediately, but the end of the init sequence, if needed */ + if (daemon (1, options->log) < 0) msg (M_ERR, "daemon() failed or unsupported"); restore_signal_state (); if (options->log) set_std_files_to_null (true); -#if defined(ENABLE_PKCS11) - pkcs11_forkFixup (); -#endif - ret = true; } return ret; @@ -1824,15 +1821,11 @@ do_deferred_options (struct context *c, const unsigned int found) * Possible hold on initialization */ static bool -do_hold (struct context *c) +do_hold (void) { #ifdef ENABLE_MANAGEMENT if (management) { - /* if c is defined, daemonize before hold */ - if (c && c->options.daemon && management_should_daemonize (management)) - do_init_first_time (c); - /* block until management hold is released */ if (management_hold (management)) return true; @@ -1882,7 +1875,7 @@ socket_restart_pause (struct context *c) c->persist.restart_sleep_seconds = 0; /* do managment hold on context restart, i.e. second, third, fourth, etc. initialization */ - if (do_hold (NULL)) + if (do_hold ()) sec = 0; if (sec) @@ -1901,7 +1894,7 @@ do_startup_pause (struct context *c) if (!c->first_time) socket_restart_pause (c); else - do_hold (NULL); /* do management hold on first context initialization */ + do_hold (); /* do management hold on first context initialization */ } /* @@ -2759,7 +2752,7 @@ do_compute_occ_strings (struct context *c) static void do_init_first_time (struct context *c) { - if (c->first_time && !c->did_we_daemonize && !c->c0) + if (c->first_time && !c->c0) { struct context_0 *c0; @@ -2774,12 +2767,9 @@ do_init_first_time (struct context *c) /* get --writepid file descriptor */ get_pid_file (c->options.writepid, &c0->pid_state); - /* become a daemon if --daemon */ - c->did_we_daemonize = possibly_become_daemon (&c->options); - - /* should we disable paging? */ - if (c->options.mlock && c->did_we_daemonize) - platform_mlockall (true); /* call again in case we daemonized */ + /* perform postponed chdir if --daemon */ + if (c->did_we_daemonize && c->options.cd_dir == NULL) + platform_chdir("/"); /* save process ID in a file */ write_pid (&c0->pid_state); @@ -3237,7 +3227,7 @@ open_management (struct context *c) } /* initial management hold, called early, before first context initialization */ - do_hold (c); + do_hold (); if (IS_SIG (c)) { msg (M_WARN, "Signal received from management interface, exiting"); diff --git a/src/openvpn/init.h b/src/openvpn/init.h index 5a1d1dcff14..d1908ed128c 100644 --- a/src/openvpn/init.h +++ b/src/openvpn/init.h @@ -55,6 +55,8 @@ bool do_genkey (const struct options *options); bool do_persist_tuntap (const struct options *options); +bool possibly_become_daemon (const struct options *options); + void pre_setup (const struct options *options); void init_instance_handle_signals (struct context *c, const struct env_set *env, const unsigned int flags); diff --git a/src/openvpn/openvpn.c b/src/openvpn/openvpn.c index fd87fc16f17..2f327f36706 100644 --- a/src/openvpn/openvpn.c +++ b/src/openvpn/openvpn.c @@ -229,6 +229,10 @@ openvpn_main (int argc, char *argv[]) if (do_test_crypto (&c.options)) break; + /* become a daemon if --daemon */ + if (c.first_time) + c.did_we_daemonize = possibly_become_daemon (&c.options); + #ifdef ENABLE_MANAGEMENT /* open management subsystem */ if (!open_management (&c)) diff --git a/src/openvpn/pkcs11.c b/src/openvpn/pkcs11.c index 3a15ef68cab..a1f13c5a759 100644 --- a/src/openvpn/pkcs11.c +++ b/src/openvpn/pkcs11.c @@ -336,11 +336,6 @@ pkcs11_terminate () { ); } -void -pkcs11_forkFixup () { - pkcs11h_forkFixup (); -} - bool pkcs11_addProvider ( const char * const provider, diff --git a/src/openvpn/pkcs11.h b/src/openvpn/pkcs11.h index 4261871d446..b49401ca096 100644 --- a/src/openvpn/pkcs11.h +++ b/src/openvpn/pkcs11.h @@ -38,9 +38,6 @@ pkcs11_initialize ( void pkcs11_terminate (); -void -pkcs11_forkFixup (); - bool pkcs11_addProvider ( const char * const provider, From 0fe2498ef9326e301869c9e8a9e622a3996ae579 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Tue, 26 May 2015 23:01:03 +0200 Subject: [PATCH 042/643] slightly enhance documentation about --cipher point out that this is for "data channel" packets trac #463 Signed-off-by: Gert Doering Acked-by: Steffan Karger Message-Id: <1432674063-15916-1-git-send-email-gert@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/9746 --- doc/openvpn.8 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 3fff3f2c41d..df16a7f4b2d 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -3908,7 +3908,7 @@ For more information on HMAC see .\"********************************************************* .TP .B \-\-cipher alg -Encrypt packets with cipher algorithm +Encrypt data channel packets with cipher algorithm .B alg. The default is .B BF-CBC, From fc03ca9d13e35c40bdf1c3c676db2adf48c60223 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Wed, 27 May 2015 20:31:38 +0200 Subject: [PATCH 043/643] Enforce "serial-tests" behaviour for tests/Makefile Our "make check" testsuite creates quite a bit of output which is intended to help pinpointing the exact reason for failure - hidden by default by automake 1.12 and up, which default to "parallel-tests" which has no benefit for us. So, just set the automake option to revert to the old behaviour. See also: https://www.gnu.org/software/automake/manual/html_node/Serial-Test-Harness.html Trac #427 Signed-off-by: Gert Doering Message-ID: <20150524193011.GK382@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/9738 Acked-by: David Sommerseth --- tests/Makefile.am | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/Makefile.am b/tests/Makefile.am index b7980e04b8b..02fa392de3c 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -9,6 +9,8 @@ # Copyright (C) 2006-2012 Alon Bar-Lev # +AUTOMAKE_OPTIONS = serial-tests + MAINTAINERCLEANFILES = \ $(srcdir)/Makefile.in From 859f6aaac6ef35c54306b6f10d2ec902dd41c89b Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Thu, 28 May 2015 11:09:50 +0200 Subject: [PATCH 044/643] Revert "Enforce "serial-tests" behaviour for tests/Makefile" This reverts commit fc03ca9d13e35c40bdf1c3c676db2adf48c60223, because it breaks "autoreconf -vif" on autoconf versions older than 1.12 - like, CentOS 6, Debian 7, ... --- tests/Makefile.am | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/Makefile.am b/tests/Makefile.am index 02fa392de3c..b7980e04b8b 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -9,8 +9,6 @@ # Copyright (C) 2006-2012 Alon Bar-Lev # -AUTOMAKE_OPTIONS = serial-tests - MAINTAINERCLEANFILES = \ $(srcdir)/Makefile.in From 7d30696ac51aa9649f2290ada2c0fb5865cfe859 Mon Sep 17 00:00:00 2001 From: Yegor Yefremov Date: Mon, 20 Apr 2015 16:30:56 +0200 Subject: [PATCH 045/643] cert_data: fix memory leak Release pCertName, if SecCertificateCopyValues() fails. Found via cppcheck. Signed-off-by: Yegor Yefremov Cc: Vasily Kulikov Acked-by: Vasily Kulikov Message-Id: <1429540256-4906-1-git-send-email-yegorslists@googlemail.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/9600 Signed-off-by: Gert Doering --- contrib/keychain-mcd/cert_data.c | 1 + 1 file changed, 1 insertion(+) diff --git a/contrib/keychain-mcd/cert_data.c b/contrib/keychain-mcd/cert_data.c index f2b33edced8..a04bf79c307 100644 --- a/contrib/keychain-mcd/cert_data.c +++ b/contrib/keychain-mcd/cert_data.c @@ -146,6 +146,7 @@ CFArrayRef GetFieldsFromCertificate(SecCertificateRef certificate, CFTypeRef oid printErrorMsg("GetFieldsFromCertificate: SecCertificateCopyValues", error); CFRelease(keySelection); CFRelease(fields); + destroyCertName(pCertName); return NULL; } CFDictionaryRef vals = CFDictionaryGetValue(dict, oid); From 5f6c01ea6172ed1d8ed04e31f9f6c3f8e4696109 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Sun, 31 May 2015 22:41:58 +0200 Subject: [PATCH 046/643] On signal reception, return EAI_SYSTEM from openvpn_getaddrinfo(). A signal (except SIGUSR1) received while waiting for getaddrinfo() is considered fatal, so openvpn_getaddrinfo() is destroying the returned information with freeaddrinfo(), but still signalled "success" (0) to the caller - so if the caller accessed *res before checking *signal_received, it would access just-free()ed memory, which on some platforms still worked and on others caused a crash. Also, ensure that *ai is also NULLed in the caller now. Trac #276 Signed-off-by: Gert Doering Acked-by: Arne Schwabe Message-Id: <1433104918-9523-1-git-send-email-gert@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/9764 --- src/openvpn/socket.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c index 13ed9817424..e751154adcf 100644 --- a/src/openvpn/socket.c +++ b/src/openvpn/socket.c @@ -412,10 +412,13 @@ openvpn_getaddrinfo (unsigned int flags, } else { + /* turn success into failure (interrupted syscall) */ if (0 == status) { ASSERT(res); freeaddrinfo(*res); - res = NULL; + *res = NULL; + status = EAI_SYSTEM; + errno = EINTR; } goto done; } From c615835aa93701c764c23fc2579d97757c1a9970 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Mon, 1 Jun 2015 21:04:47 +0200 Subject: [PATCH 047/643] Use configure.ac hack to apply serial_test AM option only if supported. Inspired by libguestfs' configure.ac hack - test automake version, and if 1.12 or newer, use m4 magic to pass "serial_tests" option to AM_INIT_AUTOMAKE(). https://www.redhat.com/archives/libguestfs/2013-February/msg00102.html Trac #427 Signed-off-by: Gert Doering Acked-by: David Sommerseth Message-Id: <1433185487-9724-1-git-send-email-gert@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/9769 --- configure.ac | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 54fe4f53d99..cd450d39aec 100644 --- a/configure.ac +++ b/configure.ac @@ -35,7 +35,21 @@ AC_CONFIG_AUX_DIR([.]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_SRCDIR([src/openvpn/syshead.h]) AC_CONFIG_MACRO_DIR([m4]) -AM_INIT_AUTOMAKE + +dnl Initialize automake. automake < 1.12 didn't have serial-tests and +dnl gives an error if it sees this, but for automake >= 1.13 +dnl serial-tests is required so we have to include it. Solution is to +dnl test for the version of automake (by running an external command) +dnl and provide it if necessary. Note we have to do this entirely using +dnl m4 macros since automake queries this macro by running +dnl 'autoconf --trace ...'. +m4_define([serial_tests], [ + m4_esyscmd([automake --version | + head -1 | + awk '{split ($NF,a,"."); if (a[1] == 1 && a[2] >= 12) { print "serial-tests" }}' + ]) +]) +AM_INIT_AUTOMAKE(foreign serial_tests) dnl NB: Do not [quote] this parameter. AC_CANONICAL_HOST AC_USE_SYSTEM_EXTENSIONS From 8ceb9619a26f8c507bafbc6d59aed3f65a30455d Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Mon, 1 Jun 2015 19:15:14 +0200 Subject: [PATCH 048/643] Use EAI_AGAIN instead of EAI_SYSTEM for openvpn_getaddrinfo(). Windows has no EAI_SYSTEM (introduced by 5f6c01ea6172ed), but everyone has EAI_AGAIN - which also fits ("a temporary failure in name resolution"). Trac #276 Signed-off-by: Gert Doering Acked-by: Steffan Karger Message-Id: <1433178914-7842-1-git-send-email-gert@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/9768 --- src/openvpn/socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c index e751154adcf..4f1139d7569 100644 --- a/src/openvpn/socket.c +++ b/src/openvpn/socket.c @@ -417,7 +417,7 @@ openvpn_getaddrinfo (unsigned int flags, ASSERT(res); freeaddrinfo(*res); *res = NULL; - status = EAI_SYSTEM; + status = EAI_AGAIN; /* = temporary failure */ errno = EINTR; } goto done; From 1e2b229e5140b784820906feb8446e47c1ecc62e Mon Sep 17 00:00:00 2001 From: Guy Yur Date: Mon, 1 Jun 2015 21:51:13 +0200 Subject: [PATCH 049/643] Fix --redirect-private in --dev tap mode. When specifying redirect-private option and not specifying route-gateway or ifconfig options, OpenVPN fails to add the route to the remote host with the following message: NOTE: unable to redirect default gateway -- VPN gateway parameter (--route-gateway or --ifconfig) is missing In redirect_default_route_to_vpn() the check for remote endpoint happens even though it is not used by redirect-private - make check conditional on RG_REROUTE_GW (= --redirect-gateway). Trac #261 Acked-by: Gert Doering Message-Id: <20150531120327.GE382@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/9761 Signed-off-by: Gert Doering --- src/openvpn/route.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openvpn/route.c b/src/openvpn/route.c index a349ac9808c..ee7c0def89b 100644 --- a/src/openvpn/route.c +++ b/src/openvpn/route.c @@ -808,7 +808,7 @@ redirect_default_route_to_vpn (struct route_list *rl, const struct tuntap *tt, u if ( rl && rl->flags & RG_ENABLE ) { - if (!(rl->spec.flags & RTSA_REMOTE_ENDPOINT)) + if (!(rl->spec.flags & RTSA_REMOTE_ENDPOINT) && (rl->flags & RG_REROUTE_GW)) { msg (M_WARN, "%s VPN gateway parameter (--route-gateway or --ifconfig) is missing", err); } From 288a819af7d3a6fab9e0b69ae8dbaac74b36307b Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Sun, 31 May 2015 15:59:09 +0200 Subject: [PATCH 050/643] Move res_init() call to inner openvpn_getaddrinfo() loop A non-working nameserver in /etc/resolv.conf could lead to endless loops inside openvpn_getaddrinfo(), because many systems will only pick up changes to resolv.conf if res_init() is called again. To reproduce, run openvpn with --resolv-retry infinite (2.3) or --resolv-retry "a high number" (master) on a BSD system. Linux glibc seems to stat() resolv.conf on calls to getaddrinfo() and pick up changes automatically. Trac #523 Signed-off-by: Gert Doering Acked-by: Arne Schwabe Message-Id: <1433080749-6892-1-git-send-email-gert@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/9763 --- src/openvpn/socket.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c index 4f1139d7569..7f889b1fecb 100644 --- a/src/openvpn/socket.c +++ b/src/openvpn/socket.c @@ -314,10 +314,6 @@ openvpn_getaddrinfo (unsigned int flags, ASSERT(res); -#ifndef WIN32 - res_init (); -#endif - ASSERT (hostname || servname); ASSERT (!(flags & GETADDR_HOST_ORDER)); @@ -394,6 +390,9 @@ openvpn_getaddrinfo (unsigned int flags, */ while (true) { +#ifndef WIN32 + res_init (); +#endif /* try hostname lookup */ hints.ai_flags &= ~AI_NUMERICHOST; dmsg (D_SOCKET_DEBUG, "GETADDRINFO flags=0x%04x ai_family=%d ai_socktype=%d", From 001384e2952b54089e889edbda3196283b21641d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuli=20Sepp=C3=A4nen?= Date: Tue, 2 Jun 2015 10:59:42 +0300 Subject: [PATCH 051/643] Improve documentation in --script-security section of the man-page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Trac: #395 Signed-off-by: Samuli Seppänen Acked-by: Gert Doering Message-Id: <1433231982-24945-1-git-send-email-samuli@openvpn.net> URL: http://article.gmane.org/gmane.network.openvpn.devel/9777 Signed-off-by: Gert Doering --- doc/openvpn.8 | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index df16a7f4b2d..3eb2493a8f4 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -2007,6 +2007,11 @@ or As of OpenVPN v2.3, this flag is no longer accepted. In most *nix environments the execve() approach has been used without any issues. +Some directives such as \-\-up allow options to be passed to the external +script. In these cases make sure the script name does not contain any spaces or +the configuration parser will choke because it can't determine where the script +name ends and script options start. + To run scripts in Windows in earlier OpenVPN versions you needed to either add a full path to the script interpreter which can parse the script or use the From 60fd44e501f2002459a49c6c9bc64370ea26ca87 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Sun, 26 Apr 2015 20:03:58 +0200 Subject: [PATCH 052/643] Fix FreeBSD ifconfig for topology subnet tunnels. For "topology subnet", we only pretend to have a subnet and keep using the tun if in point-to-point mode - but for that to fully work, the "remote" address needs to be different from the "local" address. So just arbitrarily construct one from the on-link subnet - base+1, if "that is not us", base+2, otherwise. Fix trac #481 See also: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=194745 Signed-off-by: Gert Doering Tested-By: Anton Sayetsky Lazy-ACK-by: Gert Doering Message-Id: <1430071438-31675-1-git-send-email-gert@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/9606 --- src/openvpn/tun.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index e479d4d177d..59e7436bf66 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -631,6 +631,28 @@ void delete_route_connected_v6_net(struct tuntap * tt, } #endif +#if defined(TARGET_FREEBSD)||defined(TARGET_DRAGONFLY) +/* we can't use true subnet mode on tun on all platforms, as that + * conflicts with IPv6 (wants to use ND then, which we don't do), + * but the OSes want "a remote address that is different from ours" + * - so we construct one, normally the first in the subnet, but if + * this is the same as ours, use the second one. + * The actual address does not matter at all, as the tun interface + * is still point to point and no layer 2 resolution is done... + */ + +char * +create_arbitrary_remote( struct tuntap *tt, struct gc_arena * gc ) +{ + in_addr_t remote; + + remote = (tt->local & tt->remote_netmask) +1; + + if ( remote == tt->local ) remote ++; + + return print_in_addr_t (remote, 0, &gc); +} +#endif /* execute the ifconfig command through the shell */ void @@ -1155,7 +1177,7 @@ do_ifconfig (struct tuntap *tt, IFCONFIG_PATH, actual, ifconfig_local, - ifconfig_local, + create_arbitrary_remote( tt, &gc ), tun_mtu, ifconfig_remote_netmask ); From 659eae7b79e5565bb0c93f6d6d04e2163fea1141 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Fri, 19 Jun 2015 00:08:45 +0200 Subject: [PATCH 053/643] write pid file immediately after daemonizing Since we split daemonizing from changing directory in commit da9b292 (f025de005d719201a69ad0313d545a1ddd244752 in release/2.3), we can now simply write the pid file immediately after daemonizing. This not only fixes the bug reported in trac #563, but also further simplifies the code. trac #563 Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1434665325-3225-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/9793 Signed-off-by: Gert Doering --- src/openvpn/init.c | 6 ------ src/openvpn/misc.c | 27 +++++++++------------------ src/openvpn/misc.h | 9 +-------- src/openvpn/openvpn.c | 5 ++++- src/openvpn/openvpn.h | 3 --- 5 files changed, 14 insertions(+), 36 deletions(-) diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 3daf5a46efa..13f5612d193 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -2764,16 +2764,10 @@ do_init_first_time (struct context *c) platform_group_get (c->options.groupname, &c0->platform_state_group) | platform_user_get (c->options.username, &c0->platform_state_user); - /* get --writepid file descriptor */ - get_pid_file (c->options.writepid, &c0->pid_state); - /* perform postponed chdir if --daemon */ if (c->did_we_daemonize && c->options.cd_dir == NULL) platform_chdir("/"); - /* save process ID in a file */ - write_pid (&c0->pid_state); - /* should we change scheduling priority? */ platform_nice (c->options.nice); } diff --git a/src/openvpn/misc.c b/src/openvpn/misc.c index 5627cb9eaec..4fdbf1753ee 100644 --- a/src/openvpn/misc.c +++ b/src/openvpn/misc.c @@ -127,30 +127,21 @@ run_up_down (const char *command, gc_free (&gc); } -/* Get the file we will later write our process ID to */ +/* Write our PID to a file */ void -get_pid_file (const char* filename, struct pid_state *state) +write_pid (const char *filename) { - CLEAR (*state); if (filename) { - state->fp = platform_fopen (filename, "w"); - if (!state->fp) + unsigned int pid = 0; + FILE *fp = platform_fopen (filename, "w"); + if (!fp) msg (M_ERR, "Open error on pid file %s", filename); - state->filename = filename; - } -} -/* Write our PID to a file */ -void -write_pid (const struct pid_state *state) -{ - if (state->filename && state->fp) - { - unsigned int pid = platform_getpid (); - fprintf(state->fp, "%u\n", pid); - if (fclose (state->fp)) - msg (M_ERR, "Close error on pid file %s", state->filename); + pid = platform_getpid (); + fprintf(fp, "%u\n", pid); + if (fclose (fp)) + msg (M_ERR, "Close error on pid file %s", filename); } } diff --git a/src/openvpn/misc.h b/src/openvpn/misc.h index 5fe085e916e..7c2691257b0 100644 --- a/src/openvpn/misc.h +++ b/src/openvpn/misc.h @@ -73,14 +73,7 @@ void run_up_down (const char *command, const char *script_type, struct env_set *es); -/* workspace for get_pid_file/write_pid */ -struct pid_state { - FILE *fp; - const char *filename; -}; - -void get_pid_file (const char* filename, struct pid_state *state); -void write_pid (const struct pid_state *state); +void write_pid (const char *filename); /* check file protections */ void warn_if_group_others_accessible(const char* filename); diff --git a/src/openvpn/openvpn.c b/src/openvpn/openvpn.c index 2f327f36706..00bd5703c36 100644 --- a/src/openvpn/openvpn.c +++ b/src/openvpn/openvpn.c @@ -231,7 +231,10 @@ openvpn_main (int argc, char *argv[]) /* become a daemon if --daemon */ if (c.first_time) - c.did_we_daemonize = possibly_become_daemon (&c.options); + { + c.did_we_daemonize = possibly_become_daemon (&c.options); + write_pid (c.options.writepid); + } #ifdef ENABLE_MANAGEMENT /* open management subsystem */ diff --git a/src/openvpn/openvpn.h b/src/openvpn/openvpn.h index 9ab50b80b5e..ef7ca1d027f 100644 --- a/src/openvpn/openvpn.h +++ b/src/openvpn/openvpn.h @@ -134,9 +134,6 @@ struct context_persist */ struct context_0 { - /* workspace for get_pid_file/write_pid */ - struct pid_state pid_state; - /* workspace for --user/--group */ bool uid_gid_specified; bool uid_gid_set; From 3d6a4cded2b20fb816b17d70eb65cd6c14a95eff Mon Sep 17 00:00:00 2001 From: "Jonathan K. Bullard" Date: Tue, 2 Jun 2015 08:43:26 -0400 Subject: [PATCH 054/643] Fail if options have extra parameters [v2] Throw an error if an option has extra parameters; previously they were silently ignored (see also trac #557) This feature was discussed on the openvpn-devel mailing list (http://thread.gmane.org/gmane.network.openvpn.devel/9599). The (modified) message "Unrecognized option or missing or extra parameter(s)" is used except for a few options: * The --help option: An extra parameter for --help generates a specific error message after showing the syntax message. This is done to help a user who tries "--help tls-cipher" or similar, hoping to get more information about the "tls-cipher" option. * The --dhcp-option option: It has its own similar message, into which " or extra" has been inserted. * Ten options such as --up that accept a command (instead of a path) already detect extra parameters and generate specific error messages that mention double-quoting commands which contain embedded spaces. Acked-by: Arne Schwabe Message-Id: URL: http://article.gmane.org/gmane.network.openvpn.devel/9783 URL: https://community.openvpn.net/openvpn/ticket/557 Signed-off-by: Gert Doering --- src/openvpn/options.c | 543 +++++++++++++++++++++--------------------- 1 file changed, 276 insertions(+), 267 deletions(-) diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 8487ce1405e..74276d453a3 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -4126,13 +4126,18 @@ add_option (struct options *options, { VERIFY_PERMISSION (OPT_P_GENERAL); usage (); + if (p[1]) + { + msg (msglevel, "--help does not accept any parameters"); + goto err; + } } - if (streq (p[0], "version")) + if (streq (p[0], "version") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); usage_version (); } - else if (streq (p[0], "config") && p[1]) + else if (streq (p[0], "config") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_CONFIG); @@ -4143,7 +4148,7 @@ add_option (struct options *options, read_config_file (options, p[1], level, file, line, msglevel, permission_mask, option_types_found, es); } #if defined(ENABLE_DEBUG) && !defined(ENABLE_SMALL) - else if (streq (p[0], "show-gateway")) + else if (streq (p[0], "show-gateway") && !p[1]) { struct route_gateway_info rgi; VERIFY_PERMISSION (OPT_P_GENERAL); @@ -4193,7 +4198,7 @@ add_option (struct options *options, msg (M_WARN, "echo/parameter option overflow"); } #ifdef ENABLE_MANAGEMENT - else if (streq (p[0], "management") && p[1] && p[2]) + else if (streq (p[0], "management") && p[1] && p[2] && !p[4]) { VERIFY_PERMISSION (OPT_P_GENERAL); if (streq (p[2], "unix")) @@ -4213,64 +4218,64 @@ add_option (struct options *options, options->management_user_pass = p[3]; } } - else if (streq (p[0], "management-client-user") && p[1]) + else if (streq (p[0], "management-client-user") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->management_client_user = p[1]; } - else if (streq (p[0], "management-client-group") && p[1]) + else if (streq (p[0], "management-client-group") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->management_client_group = p[1]; } - else if (streq (p[0], "management-query-passwords")) + else if (streq (p[0], "management-query-passwords") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->management_flags |= MF_QUERY_PASSWORDS; } - else if (streq (p[0], "management-query-remote")) + else if (streq (p[0], "management-query-remote") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->management_flags |= MF_QUERY_REMOTE; } - else if (streq (p[0], "management-query-proxy")) + else if (streq (p[0], "management-query-proxy") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->management_flags |= MF_QUERY_PROXY; } - else if (streq (p[0], "management-hold")) + else if (streq (p[0], "management-hold") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->management_flags |= MF_HOLD; } - else if (streq (p[0], "management-signal")) + else if (streq (p[0], "management-signal") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->management_flags |= MF_SIGNAL; } - else if (streq (p[0], "management-forget-disconnect")) + else if (streq (p[0], "management-forget-disconnect") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->management_flags |= MF_FORGET_DISCONNECT; } - else if (streq (p[0], "management-up-down")) + else if (streq (p[0], "management-up-down") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->management_flags |= MF_UP_DOWN; } - else if (streq (p[0], "management-client")) + else if (streq (p[0], "management-client") && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->management_flags |= MF_CONNECT_AS_CLIENT; options->management_write_peer_info_file = p[1]; } #ifdef MANAGMENT_EXTERNAL_KEY - else if (streq (p[0], "management-external-key")) + else if (streq (p[0], "management-external-key") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->management_flags |= MF_EXTERNAL_KEY; } - else if (streq (p[0], "management-external-cert") && p[1]) + else if (streq (p[0], "management-external-cert") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->management_flags |= MF_EXTERNAL_CERT; @@ -4278,27 +4283,27 @@ add_option (struct options *options, } #endif #ifdef MANAGEMENT_DEF_AUTH - else if (streq (p[0], "management-client-auth")) + else if (streq (p[0], "management-client-auth") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->management_flags |= MF_CLIENT_AUTH; } #endif #ifdef ENABLE_X509_TRACK - else if (streq (p[0], "x509-track") && p[1]) + else if (streq (p[0], "x509-track") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); x509_track_add (&options->x509_track, p[1], msglevel, &options->gc); } #endif #ifdef MANAGEMENT_PF - else if (streq (p[0], "management-client-pf")) + else if (streq (p[0], "management-client-pf") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->management_flags |= (MF_CLIENT_PF | MF_CLIENT_AUTH); } #endif - else if (streq (p[0], "management-log-cache") && p[1]) + else if (streq (p[0], "management-log-cache") && p[1] && !p[2]) { int cache; @@ -4313,7 +4318,7 @@ add_option (struct options *options, } #endif #ifdef ENABLE_PLUGIN - else if (streq (p[0], "plugin") && p[1]) + else if (streq (p[0], "plugin") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_PLUGIN); if (!options->plugin_list) @@ -4325,7 +4330,7 @@ add_option (struct options *options, } } #endif - else if (streq (p[0], "mode") && p[1]) + else if (streq (p[0], "mode") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); if (streq (p[1], "p2p")) @@ -4340,22 +4345,22 @@ add_option (struct options *options, goto err; } } - else if (streq (p[0], "dev") && p[1]) + else if (streq (p[0], "dev") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->dev = p[1]; } - else if (streq (p[0], "dev-type") && p[1]) + else if (streq (p[0], "dev-type") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->dev_type = p[1]; } - else if (streq (p[0], "dev-node") && p[1]) + else if (streq (p[0], "dev-node") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->dev_node = p[1]; } - else if (streq (p[0], "lladdr") && p[1]) + else if (streq (p[0], "lladdr") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_UP); if (mac_addr_safe (p[1])) /* MAC address only */ @@ -4366,24 +4371,24 @@ add_option (struct options *options, goto err; } } - else if (streq (p[0], "topology") && p[1]) + else if (streq (p[0], "topology") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_UP); options->topology = parse_topology (p[1], msglevel); } - else if (streq (p[0], "tun-ipv6")) + else if (streq (p[0], "tun-ipv6") && !p[1]) { VERIFY_PERMISSION (OPT_P_UP); options->tun_ipv6 = true; } #ifdef ENABLE_IPROUTE - else if (streq (p[0], "iproute") && p[1]) + else if (streq (p[0], "iproute") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); iproute_path = p[1]; } #endif - else if (streq (p[0], "ifconfig") && p[1] && p[2]) + else if (streq (p[0], "ifconfig") && p[1] && p[2] && !p[3]) { VERIFY_PERMISSION (OPT_P_UP); if (ip_or_dns_addr_safe (p[1], options->allow_pull_fqdn) && ip_or_dns_addr_safe (p[2], options->allow_pull_fqdn)) /* FQDN -- may be DNS name */ @@ -4397,7 +4402,7 @@ add_option (struct options *options, goto err; } } - else if (streq (p[0], "ifconfig-ipv6") && p[1] && p[2] ) + else if (streq (p[0], "ifconfig-ipv6") && p[1] && p[2] && !p[3]) { unsigned int netbits; char * ipv6_local; @@ -4426,27 +4431,27 @@ add_option (struct options *options, goto err; } } - else if (streq (p[0], "ifconfig-noexec")) + else if (streq (p[0], "ifconfig-noexec") && !p[1]) { VERIFY_PERMISSION (OPT_P_UP); options->ifconfig_noexec = true; } - else if (streq (p[0], "ifconfig-nowarn")) + else if (streq (p[0], "ifconfig-nowarn") && !p[1]) { VERIFY_PERMISSION (OPT_P_UP); options->ifconfig_nowarn = true; } - else if (streq (p[0], "local") && p[1]) + else if (streq (p[0], "local") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); options->ce.local = p[1]; } - else if (streq (p[0], "remote-random")) + else if (streq (p[0], "remote-random") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->remote_random = true; } - else if (streq (p[0], "connection") && p[1]) + else if (streq (p[0], "connection") && p[1] && !p[3]) { VERIFY_PERMISSION (OPT_P_GENERAL); if (streq (p[1], INLINE_FILE_TAG) && p[2]) @@ -4509,7 +4514,7 @@ add_option (struct options *options, options->ignore_unknown_option[i] = NULL; } #if ENABLE_MANAGEMENT - else if (streq (p[0], "http-proxy-override") && p[1] && p[2]) + else if (streq (p[0], "http-proxy-override") && p[1] && p[2] && !p[4]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->http_proxy_override = parse_http_proxy_override(p[1], p[2], p[3], msglevel, &options->gc); @@ -4517,7 +4522,7 @@ add_option (struct options *options, goto err; } #endif - else if (streq (p[0], "remote") && p[1]) + else if (streq (p[0], "remote") && p[1] && !p[4]) { struct remote_entry re; re.remote = re.remote_port= NULL; @@ -4554,7 +4559,7 @@ add_option (struct options *options, connection_entry_load_re (&options->ce, &re); } } - else if (streq (p[0], "resolv-retry") && p[1]) + else if (streq (p[0], "resolv-retry") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); if (streq (p[1], "infinite")) @@ -4562,7 +4567,7 @@ add_option (struct options *options, else options->resolve_retry_seconds = positive_atoi (p[1]); } - else if (streq (p[0], "preresolve") || streq (p[0], "ip-remote-hint")) + else if (streq (p[0], "preresolve") || streq (p[0], "ip-remote-hint") && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->resolve_in_advance = true; @@ -4571,18 +4576,18 @@ add_option (struct options *options, if (p[1]) options->ip_remote_hint=p[1]; } - else if (streq (p[0], "connect-retry") && p[1]) + else if (streq (p[0], "connect-retry") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); options->ce.connect_retry_seconds = positive_atoi (p[1]); } - else if (streq (p[0], "connect-timeout") && p[1]) + else if (streq (p[0], "connect-timeout") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); options->ce.connect_timeout = positive_atoi (p[1]); options->ce.connect_timeout_defined = true; } - else if (streq (p[0], "connect-retry-max") && p[1]) + else if (streq (p[0], "connect-retry-max") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); options->connect_retry_max = positive_atoi (p[1]); @@ -4597,24 +4602,24 @@ add_option (struct options *options, string_substitute (p[1], ',', ' ', &options->gc), "ipchange", true); } - else if (streq (p[0], "float")) + else if (streq (p[0], "float") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); options->ce.remote_float = true; } #ifdef ENABLE_DEBUG - else if (streq (p[0], "gremlin") && p[1]) + else if (streq (p[0], "gremlin") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->gremlin = positive_atoi (p[1]); } #endif - else if (streq (p[0], "chroot") && p[1]) + else if (streq (p[0], "chroot") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->chroot_dir = p[1]; } - else if (streq (p[0], "cd") && p[1]) + else if (streq (p[0], "cd") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); if (platform_chdir (p[1])) @@ -4625,13 +4630,13 @@ add_option (struct options *options, options->cd_dir = p[1]; } #ifdef ENABLE_SELINUX - else if (streq (p[0], "setcon") && p[1]) + else if (streq (p[0], "setcon") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->selinux_context = p[1]; } #endif - else if (streq (p[0], "writepid") && p[1]) + else if (streq (p[0], "writepid") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->writepid = p[1]; @@ -4650,27 +4655,27 @@ add_option (struct options *options, goto err; set_user_script (options, &options->down_script, p[1], "down", true); } - else if (streq (p[0], "down-pre")) + else if (streq (p[0], "down-pre") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->down_pre = true; } - else if (streq (p[0], "up-delay")) + else if (streq (p[0], "up-delay") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->up_delay = true; } - else if (streq (p[0], "up-restart")) + else if (streq (p[0], "up-restart") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->up_restart = true; } - else if (streq (p[0], "syslog")) + else if (streq (p[0], "syslog") && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); open_syslog (p[1], false); } - else if (streq (p[0], "daemon")) + else if (streq (p[0], "daemon") && !p[2]) { bool didit = false; VERIFY_PERMISSION (OPT_P_GENERAL); @@ -4688,7 +4693,7 @@ add_option (struct options *options, } } } - else if (streq (p[0], "inetd")) + else if (streq (p[0], "inetd") && !p[3]) { VERIFY_PERMISSION (OPT_P_GENERAL); if (!options->inetd) @@ -4743,50 +4748,50 @@ add_option (struct options *options, open_syslog (name, true); } } - else if (streq (p[0], "log") && p[1]) + else if (streq (p[0], "log") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->log = true; redirect_stdout_stderr (p[1], false); } - else if (streq (p[0], "suppress-timestamps")) + else if (streq (p[0], "suppress-timestamps") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->suppress_timestamps = true; set_suppress_timestamps(true); } - else if (streq (p[0], "machine-readable-output")) + else if (streq (p[0], "machine-readable-output") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->machine_readable_output = true; set_machine_readable_output(true); } - else if (streq (p[0], "log-append") && p[1]) + else if (streq (p[0], "log-append") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->log = true; redirect_stdout_stderr (p[1], true); } #ifdef ENABLE_MEMSTATS - else if (streq (p[0], "memstats") && p[1]) + else if (streq (p[0], "memstats") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->memstats_fn = p[1]; } #endif - else if (streq (p[0], "mlock")) + else if (streq (p[0], "mlock") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->mlock = true; } #if ENABLE_IP_PKTINFO - else if (streq (p[0], "multihome")) + else if (streq (p[0], "multihome") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->sockflags |= SF_USE_IP_PKTINFO; } #endif - else if (streq (p[0], "verb") && p[1]) + else if (streq (p[0], "verb") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_MESSAGES); options->verbosity = positive_atoi (p[1]); @@ -4797,17 +4802,17 @@ add_option (struct options *options, options->verbosity); #endif } - else if (streq (p[0], "mute") && p[1]) + else if (streq (p[0], "mute") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_MESSAGES); options->mute = positive_atoi (p[1]); } - else if (streq (p[0], "errors-to-stderr")) + else if (streq (p[0], "errors-to-stderr") && !p[1]) { VERIFY_PERMISSION (OPT_P_MESSAGES); errors_to_stderr(); } - else if (streq (p[0], "status") && p[1]) + else if (streq (p[0], "status") && p[1] && !p[3]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->status_file = p[1]; @@ -4816,7 +4821,7 @@ add_option (struct options *options, options->status_file_update_freq = positive_atoi (p[2]); } } - else if (streq (p[0], "status-version") && p[1]) + else if (streq (p[0], "status-version") && p[1] && !p[2]) { int version; @@ -4829,7 +4834,7 @@ add_option (struct options *options, } options->status_file_version = version; } - else if (streq (p[0], "remap-usr1") && p[1]) + else if (streq (p[0], "remap-usr1") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); if (streq (p[1], "SIGHUP")) @@ -4842,19 +4847,19 @@ add_option (struct options *options, goto err; } } - else if ((streq (p[0], "link-mtu") || streq (p[0], "udp-mtu")) && p[1]) + else if ((streq (p[0], "link-mtu") || streq (p[0], "udp-mtu")) && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_MTU|OPT_P_CONNECTION); options->ce.link_mtu = positive_atoi (p[1]); options->ce.link_mtu_defined = true; } - else if (streq (p[0], "tun-mtu") && p[1]) + else if (streq (p[0], "tun-mtu") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_MTU|OPT_P_CONNECTION); options->ce.tun_mtu = positive_atoi (p[1]); options->ce.tun_mtu_defined = true; } - else if (streq (p[0], "tun-mtu-extra") && p[1]) + else if (streq (p[0], "tun-mtu-extra") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_MTU|OPT_P_CONNECTION); options->ce.tun_mtu_extra = positive_atoi (p[1]); @@ -4867,41 +4872,41 @@ add_option (struct options *options, msg (msglevel, "--mtu-dynamic has been replaced by --fragment"); goto err; } - else if (streq (p[0], "fragment") && p[1]) + else if (streq (p[0], "fragment") && p[1] && !p[2]) { /* VERIFY_PERMISSION (OPT_P_MTU); */ VERIFY_PERMISSION (OPT_P_MTU|OPT_P_CONNECTION); options->ce.fragment = positive_atoi (p[1]); } #endif - else if (streq (p[0], "mtu-disc") && p[1]) + else if (streq (p[0], "mtu-disc") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_MTU|OPT_P_CONNECTION); options->ce.mtu_discover_type = translate_mtu_discover_type_name (p[1]); } #ifdef ENABLE_OCC - else if (streq (p[0], "mtu-test")) + else if (streq (p[0], "mtu-test") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->mtu_test = true; } #endif - else if (streq (p[0], "nice") && p[1]) + else if (streq (p[0], "nice") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_NICE); options->nice = atoi (p[1]); } - else if (streq (p[0], "rcvbuf") && p[1]) + else if (streq (p[0], "rcvbuf") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_SOCKBUF); options->rcvbuf = positive_atoi (p[1]); } - else if (streq (p[0], "sndbuf") && p[1]) + else if (streq (p[0], "sndbuf") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_SOCKBUF); options->sndbuf = positive_atoi (p[1]); } - else if (streq (p[0], "mark") && p[1]) + else if (streq (p[0], "mark") && p[1] && !p[2]) { #if defined(TARGET_LINUX) && HAVE_DECL_SO_MARK VERIFY_PERMISSION (OPT_P_GENERAL); @@ -4920,7 +4925,7 @@ add_option (struct options *options, msg (msglevel, "unknown socket flag: %s", p[j]); } } - else if (streq (p[0], "txqueuelen") && p[1]) + else if (streq (p[0], "txqueuelen") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); #ifdef TARGET_LINUX @@ -4930,7 +4935,7 @@ add_option (struct options *options, goto err; #endif } - else if (streq (p[0], "shaper") && p[1]) + else if (streq (p[0], "shaper") && p[1] && !p[2]) { #ifdef ENABLE_FEATURE_SHAPER int shaper; @@ -4950,23 +4955,23 @@ add_option (struct options *options, goto err; #endif /* ENABLE_FEATURE_SHAPER */ } - else if (streq (p[0], "port") && p[1]) + else if (streq (p[0], "port") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); options->ce.local_port = options->ce.remote_port = p[1]; } - else if (streq (p[0], "lport") && p[1]) + else if (streq (p[0], "lport") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); options->ce.local_port_defined = true; options->ce.local_port = p[1]; } - else if (streq (p[0], "rport") && p[1]) + else if (streq (p[0], "rport") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); options->ce.remote_port = p[1]; } - else if (streq (p[0], "bind")) + else if (streq (p[0], "bind") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); options->ce.bind_defined = true; @@ -4974,24 +4979,24 @@ add_option (struct options *options, options->ce.bind_ipv6_only=true; } - else if (streq (p[0], "nobind")) + else if (streq (p[0], "nobind") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); options->ce.bind_local = false; } - else if (streq (p[0], "fast-io")) + else if (streq (p[0], "fast-io") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->fast_io = true; } - else if (streq (p[0], "inactive") && p[1]) + else if (streq (p[0], "inactive") && p[1] && !p[3]) { VERIFY_PERMISSION (OPT_P_TIMER); options->inactivity_timeout = positive_atoi (p[1]); if (p[2]) options->inactivity_minimum_bytes = positive_atoi (p[2]); } - else if (streq (p[0], "proto") && p[1]) + else if (streq (p[0], "proto") && p[1] && !p[2]) { int proto; sa_family_t af; @@ -5008,7 +5013,7 @@ add_option (struct options *options, options->ce.proto = proto; options->ce.af = af; } - else if (streq (p[0], "proto-force") && p[1]) + else if (streq (p[0], "proto-force") && p[1] && !p[2]) { int proto_force; VERIFY_PERMISSION (OPT_P_GENERAL); @@ -5020,7 +5025,7 @@ add_option (struct options *options, } options->proto_force = proto_force; } - else if (streq (p[0], "http-proxy") && p[1]) + else if (streq (p[0], "http-proxy") && p[1] && !p[5]) { struct http_proxy_options *ho; @@ -5064,14 +5069,14 @@ add_option (struct options *options, ho->auth_method_string = "none"; } } - else if (streq (p[0], "http-proxy-retry")) + else if (streq (p[0], "http-proxy-retry") && !p[1]) { struct http_proxy_options *ho; VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); ho = init_http_proxy_options_once (&options->ce.http_proxy_options, &options->gc); ho->retry = true; } - else if (streq (p[0], "http-proxy-timeout") && p[1]) + else if (streq (p[0], "http-proxy-timeout") && p[1] && !p[2]) { struct http_proxy_options *ho; @@ -5079,18 +5084,18 @@ add_option (struct options *options, ho = init_http_proxy_options_once (&options->ce.http_proxy_options, &options->gc); ho->timeout = positive_atoi (p[1]); } - else if (streq (p[0], "http-proxy-option") && p[1]) + else if (streq (p[0], "http-proxy-option") && p[1] && !p[4]) { struct http_proxy_options *ho; VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); ho = init_http_proxy_options_once (&options->ce.http_proxy_options, &options->gc); - if (streq (p[1], "VERSION") && p[2]) + if (streq (p[1], "VERSION") && p[2] && !p[3]) { ho->http_version = p[2]; } - else if (streq (p[1], "AGENT") && p[2]) + else if (streq (p[1], "AGENT") && p[2] && !p[3]) { ho->user_agent = p[2]; } @@ -5123,10 +5128,10 @@ add_option (struct options *options, } else { - msg (msglevel, "Bad http-proxy-option or missing parameter: '%s'", p[1]); + msg (msglevel, "Bad http-proxy-option or missing or extra parameter: '%s'", p[1]); } } - else if (streq (p[0], "socks-proxy") && p[1]) + else if (streq (p[0], "socks-proxy") && p[1] && !p[4]) { VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); @@ -5141,41 +5146,41 @@ add_option (struct options *options, options->ce.socks_proxy_server = p[1]; options->ce.socks_proxy_authfile = p[3]; /* might be NULL */ } - else if (streq (p[0], "socks-proxy-retry")) + else if (streq (p[0], "socks-proxy-retry") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); options->ce.socks_proxy_retry = true; } - else if (streq (p[0], "keepalive") && p[1] && p[2]) + else if (streq (p[0], "keepalive") && p[1] && p[2] && !p[3]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->keepalive_ping = atoi (p[1]); options->keepalive_timeout = atoi (p[2]); } - else if (streq (p[0], "ping") && p[1]) + else if (streq (p[0], "ping") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_TIMER); options->ping_send_timeout = positive_atoi (p[1]); } - else if (streq (p[0], "ping-exit") && p[1]) + else if (streq (p[0], "ping-exit") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_TIMER); options->ping_rec_timeout = positive_atoi (p[1]); options->ping_rec_timeout_action = PING_EXIT; } - else if (streq (p[0], "ping-restart") && p[1]) + else if (streq (p[0], "ping-restart") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_TIMER); options->ping_rec_timeout = positive_atoi (p[1]); options->ping_rec_timeout_action = PING_RESTART; } - else if (streq (p[0], "ping-timer-rem")) + else if (streq (p[0], "ping-timer-rem") && !p[1]) { VERIFY_PERMISSION (OPT_P_TIMER); options->ping_timer_remote = true; } #ifdef ENABLE_OCC - else if (streq (p[0], "explicit-exit-notify")) + else if (streq (p[0], "explicit-exit-notify") && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION|OPT_P_EXPLICIT_NOTIFY); if (p[1]) @@ -5188,35 +5193,35 @@ add_option (struct options *options, } } #endif - else if (streq (p[0], "persist-tun")) + else if (streq (p[0], "persist-tun") && !p[1]) { VERIFY_PERMISSION (OPT_P_PERSIST); options->persist_tun = true; } - else if (streq (p[0], "persist-key")) + else if (streq (p[0], "persist-key") && !p[1]) { VERIFY_PERMISSION (OPT_P_PERSIST); options->persist_key = true; } - else if (streq (p[0], "persist-local-ip")) + else if (streq (p[0], "persist-local-ip") && !p[1]) { VERIFY_PERMISSION (OPT_P_PERSIST_IP); options->persist_local_ip = true; } - else if (streq (p[0], "persist-remote-ip")) + else if (streq (p[0], "persist-remote-ip") && !p[1]) { VERIFY_PERMISSION (OPT_P_PERSIST_IP); options->persist_remote_ip = true; } #ifdef ENABLE_CLIENT_NAT - else if (streq (p[0], "client-nat") && p[1] && p[2] && p[3] && p[4]) + else if (streq (p[0], "client-nat") && p[1] && p[2] && p[3] && p[4] && !p[5]) { VERIFY_PERMISSION (OPT_P_ROUTE); cnol_check_alloc (options); add_client_nat_to_option_list(options->client_nat, p[1], p[2], p[3], p[4], msglevel); } #endif - else if (streq (p[0], "route") && p[1]) + else if (streq (p[0], "route") && p[1] && !p[5]) { VERIFY_PERMISSION (OPT_P_ROUTE); rol_check_alloc (options); @@ -5240,7 +5245,7 @@ add_option (struct options *options, } add_route_to_option_list (options->routes, p[1], p[2], p[3], p[4]); } - else if (streq (p[0], "route-ipv6") && p[1]) + else if (streq (p[0], "route-ipv6") && p[1] && !p[4]) { VERIFY_PERMISSION (OPT_P_ROUTE); rol6_check_alloc (options); @@ -5260,14 +5265,14 @@ add_option (struct options *options, } add_route_ipv6_to_option_list (options->routes_ipv6, p[1], p[2], p[3]); } - else if (streq (p[0], "max-routes")) + else if (streq (p[0], "max-routes") && !p[2]) { msg (M_WARN, "DEPRECATED OPTION: --max-routes option ignored." "The number of routes is unlimited as of version 2.4. " "This option will be removed in a future version, " "please remove it from your configuration."); } - else if (streq (p[0], "route-gateway") && p[1]) + else if (streq (p[0], "route-gateway") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_ROUTE_EXTRAS); if (streq (p[1], "dhcp")) @@ -5287,12 +5292,12 @@ add_option (struct options *options, } } } - else if (streq (p[0], "route-metric") && p[1]) + else if (streq (p[0], "route-metric") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_ROUTE); options->route_default_metric = positive_atoi (p[1]); } - else if (streq (p[0], "route-delay")) + else if (streq (p[0], "route-delay") && !p[3]) { VERIFY_PERMISSION (OPT_P_ROUTE_EXTRAS); options->route_delay_defined = true; @@ -5326,17 +5331,17 @@ add_option (struct options *options, p[1], "route-pre-down", true); } - else if (streq (p[0], "route-noexec")) + else if (streq (p[0], "route-noexec") && !p[1]) { VERIFY_PERMISSION (OPT_P_SCRIPT); options->route_noexec = true; } - else if (streq (p[0], "route-nopull")) + else if (streq (p[0], "route-nopull") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->route_nopull = true; } - else if (streq (p[0], "allow-pull-fqdn")) + else if (streq (p[0], "allow-pull-fqdn") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->allow_pull_fqdn = true; @@ -5370,15 +5375,15 @@ add_option (struct options *options, } options->routes->flags |= RG_ENABLE; } - else if (streq (p[0], "remote-random-hostname")) + else if (streq (p[0], "remote-random-hostname") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->sockflags |= SF_HOST_RANDOMIZE; } - else if (streq (p[0], "setenv") && p[1]) + else if (streq (p[0], "setenv") && p[1] && !p[3]) { VERIFY_PERMISSION (OPT_P_GENERAL); - if (streq (p[1], "REMOTE_RANDOM_HOSTNAME")) + if (streq (p[1], "REMOTE_RANDOM_HOSTNAME") && !p[2]) { options->sockflags |= SF_HOST_RANDOMIZE; } @@ -5388,7 +5393,7 @@ add_option (struct options *options, goto err; } #ifdef ENABLE_PUSH_PEER_INFO - else if (streq (p[1], "PUSH_PEER_INFO")) + else if (streq (p[1], "PUSH_PEER_INFO") && !p[2]) { options->push_peer_info = true; } @@ -5409,17 +5414,17 @@ add_option (struct options *options, setenv_str (es, p[1], p[2] ? p[2] : ""); } } - else if (streq (p[0], "setenv-safe") && p[1]) + else if (streq (p[0], "setenv-safe") && p[1] && !p[3]) { VERIFY_PERMISSION (OPT_P_SETENV); setenv_str_safe (es, p[1], p[2] ? p[2] : ""); } - else if (streq (p[0], "script-security") && p[1]) + else if (streq (p[0], "script-security") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); script_security = atoi (p[1]); } - else if (streq (p[0], "mssfix")) + else if (streq (p[0], "mssfix") && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); if (p[1]) @@ -5431,7 +5436,7 @@ add_option (struct options *options, } #ifdef ENABLE_OCC - else if (streq (p[0], "disable-occ")) + else if (streq (p[0], "disable-occ") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->occ = false; @@ -5439,7 +5444,7 @@ add_option (struct options *options, #endif #if P2MP #if P2MP_SERVER - else if (streq (p[0], "server") && p[1] && p[2]) + else if (streq (p[0], "server") && p[1] && p[2] && !p[4]) { const int lev = M_WARN; bool error = false; @@ -5468,7 +5473,7 @@ add_option (struct options *options, } } } - else if (streq (p[0], "server-ipv6") && p[1] ) + else if (streq (p[0], "server-ipv6") && p[1] && !p[3]) { const int lev = M_WARN; struct in6_addr network; @@ -5495,7 +5500,7 @@ add_option (struct options *options, goto err; } } - else if (streq (p[0], "server-bridge") && p[1] && p[2] && p[3] && p[4]) + else if (streq (p[0], "server-bridge") && p[1] && p[2] && p[3] && p[4] && !p[5]) { const int lev = M_WARN; bool error = false; @@ -5517,7 +5522,7 @@ add_option (struct options *options, options->server_bridge_pool_start = pool_start; options->server_bridge_pool_end = pool_end; } - else if (streq (p[0], "server-bridge") && p[1] && streq (p[1], "nogw")) + else if (streq (p[0], "server-bridge") && p[1] && streq (p[1], "nogw") && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->server_bridge_proxy_dhcp = true; @@ -5528,17 +5533,17 @@ add_option (struct options *options, VERIFY_PERMISSION (OPT_P_GENERAL); options->server_bridge_proxy_dhcp = true; } - else if (streq (p[0], "push") && p[1]) + else if (streq (p[0], "push") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_PUSH); push_options (options, &p[1], msglevel, &options->gc); } - else if (streq (p[0], "push-reset")) + else if (streq (p[0], "push-reset") && !p[1]) { VERIFY_PERMISSION (OPT_P_INSTANCE); push_reset (options); } - else if (streq (p[0], "ifconfig-pool") && p[1] && p[2]) + else if (streq (p[0], "ifconfig-pool") && p[1] && p[2] && !p[4]) { const int lev = M_WARN; bool error = false; @@ -5565,7 +5570,7 @@ add_option (struct options *options, if (netmask) options->ifconfig_pool_netmask = netmask; } - else if (streq (p[0], "ifconfig-pool-persist") && p[1]) + else if (streq (p[0], "ifconfig-pool-persist") && p[1] && !p[3]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->ifconfig_pool_persist_filename = p[1]; @@ -5574,12 +5579,12 @@ add_option (struct options *options, options->ifconfig_pool_persist_refresh_freq = positive_atoi (p[2]); } } - else if (streq (p[0], "ifconfig-pool-linear")) + else if (streq (p[0], "ifconfig-pool-linear") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->topology = TOP_P2P; } - else if (streq (p[0], "ifconfig-ipv6-pool") && p[1] ) + else if (streq (p[0], "ifconfig-ipv6-pool") && p[1] && !p[2]) { const int lev = M_WARN; struct in6_addr network; @@ -5601,7 +5606,7 @@ add_option (struct options *options, options->ifconfig_ipv6_pool_base = network; options->ifconfig_ipv6_pool_netbits = netbits; } - else if (streq (p[0], "hash-size") && p[1] && p[2]) + else if (streq (p[0], "hash-size") && p[1] && p[2] && !p[3]) { int real, virtual; @@ -5616,7 +5621,7 @@ add_option (struct options *options, options->real_hash_size = real; options->virtual_hash_size = real; } - else if (streq (p[0], "connect-freq") && p[1] && p[2]) + else if (streq (p[0], "connect-freq") && p[1] && p[2] && !p[3]) { int cf_max, cf_per; @@ -5631,7 +5636,7 @@ add_option (struct options *options, options->cf_max = cf_max; options->cf_per = cf_per; } - else if (streq (p[0], "max-clients") && p[1]) + else if (streq (p[0], "max-clients") && p[1] && !p[2]) { int max_clients; @@ -5644,27 +5649,27 @@ add_option (struct options *options, } options->max_clients = max_clients; } - else if (streq (p[0], "max-routes-per-client") && p[1]) + else if (streq (p[0], "max-routes-per-client") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_INHERIT); options->max_routes_per_client = max_int (atoi (p[1]), 1); } - else if (streq (p[0], "client-cert-not-required")) + else if (streq (p[0], "client-cert-not-required") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->ssl_flags |= SSLF_CLIENT_CERT_NOT_REQUIRED; } - else if (streq (p[0], "username-as-common-name")) + else if (streq (p[0], "username-as-common-name") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->ssl_flags |= SSLF_USERNAME_AS_COMMON_NAME; } - else if (streq (p[0], "auth-user-pass-optional")) + else if (streq (p[0], "auth-user-pass-optional") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->ssl_flags |= SSLF_AUTH_USER_PASS_OPTIONAL; } - else if (streq (p[0], "opt-verify")) + else if (streq (p[0], "opt-verify") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->ssl_flags |= SSLF_OPT_VERIFY; @@ -5719,22 +5724,22 @@ add_option (struct options *options, set_user_script (options, &options->learn_address_script, p[1], "learn-address", true); } - else if (streq (p[0], "tmp-dir") && p[1]) + else if (streq (p[0], "tmp-dir") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->tmp_dir = p[1]; } - else if (streq (p[0], "client-config-dir") && p[1]) + else if (streq (p[0], "client-config-dir") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->client_config_dir = p[1]; } - else if (streq (p[0], "ccd-exclusive")) + else if (streq (p[0], "ccd-exclusive") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->ccd_exclusive = true; } - else if (streq (p[0], "bcast-buffers") && p[1]) + else if (streq (p[0], "bcast-buffers") && p[1] && !p[2]) { int n_bcast_buf; @@ -5744,7 +5749,7 @@ add_option (struct options *options, msg (msglevel, "--bcast-buffers parameter must be > 0"); options->n_bcast_buf = n_bcast_buf; } - else if (streq (p[0], "tcp-queue-limit") && p[1]) + else if (streq (p[0], "tcp-queue-limit") && p[1] && !p[2]) { int tcp_queue_limit; @@ -5755,7 +5760,7 @@ add_option (struct options *options, options->tcp_queue_limit = tcp_queue_limit; } #if PORT_SHARE - else if (streq (p[0], "port-share") && p[1] && p[2]) + else if (streq (p[0], "port-share") && p[1] && p[2] && !p[4]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->port_share_host = p[1]; @@ -5763,17 +5768,17 @@ add_option (struct options *options, options->port_share_journal_dir = p[3]; } #endif - else if (streq (p[0], "client-to-client")) + else if (streq (p[0], "client-to-client") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->enable_c2c = true; } - else if (streq (p[0], "duplicate-cn")) + else if (streq (p[0], "duplicate-cn") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->duplicate_cn = true; } - else if (streq (p[0], "iroute") && p[1]) + else if (streq (p[0], "iroute") && p[1] && !p[3]) { const char *netmask = NULL; @@ -5784,12 +5789,12 @@ add_option (struct options *options, } option_iroute (options, p[1], netmask, msglevel); } - else if (streq (p[0], "iroute-ipv6") && p[1]) + else if (streq (p[0], "iroute-ipv6") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_INSTANCE); option_iroute_ipv6 (options, p[1], msglevel); } - else if (streq (p[0], "ifconfig-push") && p[1] && p[2]) + else if (streq (p[0], "ifconfig-push") && p[1] && p[2] && !p[4]) { in_addr_t local, remote_netmask; @@ -5812,7 +5817,7 @@ add_option (struct options *options, goto err; } } - else if (streq (p[0], "ifconfig-push-constraint") && p[1] && p[2]) + else if (streq (p[0], "ifconfig-push-constraint") && p[1] && p[2] && !p[3]) { in_addr_t network, netmask; @@ -5831,7 +5836,7 @@ add_option (struct options *options, goto err; } } - else if (streq (p[0], "ifconfig-ipv6-push") && p[1] ) + else if (streq (p[0], "ifconfig-ipv6-push") && p[1] && !p[3]) { struct in6_addr local, remote; unsigned int netbits; @@ -5868,17 +5873,17 @@ add_option (struct options *options, options->push_ifconfig_ipv6_netbits = netbits; options->push_ifconfig_ipv6_remote = remote; } - else if (streq (p[0], "disable")) + else if (streq (p[0], "disable") && !p[1]) { VERIFY_PERMISSION (OPT_P_INSTANCE); options->disable = true; } - else if (streq (p[0], "tcp-nodelay")) + else if (streq (p[0], "tcp-nodelay") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->server_flags |= SF_TCP_NODELAY_HELPER; } - else if (streq (p[0], "stale-routes-check") && p[1]) + else if (streq (p[0], "stale-routes-check") && p[1] && !p[3]) { int ageing_time, check_interval; @@ -5899,27 +5904,27 @@ add_option (struct options *options, } #endif /* P2MP_SERVER */ - else if (streq (p[0], "client")) + else if (streq (p[0], "client") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->client = true; } - else if (streq (p[0], "pull")) + else if (streq (p[0], "pull") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->pull = true; } - else if (streq (p[0], "push-continuation") && p[1]) + else if (streq (p[0], "push-continuation") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_PULL_MODE); options->push_continuation = atoi(p[1]); } - else if (streq (p[0], "server-poll-timeout") && p[1]) + else if (streq (p[0], "server-poll-timeout") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->server_poll_timeout = positive_atoi(p[1]); } - else if (streq (p[0], "auth-user-pass")) + else if (streq (p[0], "auth-user-pass") && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); if (p[1]) @@ -5929,13 +5934,13 @@ add_option (struct options *options, else options->auth_user_pass_file = "stdin"; } - else if (streq (p[0], "auth-retry") && p[1]) + else if (streq (p[0], "auth-retry") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); auth_retry_set (msglevel, p[1]); } #ifdef ENABLE_CLIENT_CR - else if (streq (p[0], "static-challenge") && p[1] && p[2]) + else if (streq (p[0], "static-challenge") && p[1] && p[2] && !p[3]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->sc_info.challenge_text = p[1]; @@ -5945,7 +5950,7 @@ add_option (struct options *options, #endif #endif #ifdef WIN32 - else if (streq (p[0], "win-sys") && p[1]) + else if (streq (p[0], "win-sys") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); if (streq (p[1], "env")) @@ -5955,7 +5960,7 @@ add_option (struct options *options, else set_win_sys_path (p[1], es); } - else if (streq (p[0], "route-method") && p[1]) + else if (streq (p[0], "route-method") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_ROUTE_EXTRAS); if (streq (p[1], "adaptive")) @@ -5970,7 +5975,7 @@ add_option (struct options *options, goto err; } } - else if (streq (p[0], "ip-win32") && p[1]) + else if (streq (p[0], "ip-win32") && p[1] && !p[4]) { const int index = ascii2ipset (p[1]); struct tuntap_options *to = &options->tuntap_options; @@ -6026,7 +6031,7 @@ add_option (struct options *options, } #endif #if defined(WIN32) || defined(TARGET_ANDROID) - else if (streq (p[0], "dhcp-option") && p[1]) + else if (streq (p[0], "dhcp-option") && p[1] && !p[3]) { struct tuntap_options *o = &options->tuntap_options; VERIFY_PERMISSION (OPT_P_IPWIN32); @@ -6066,38 +6071,38 @@ add_option (struct options *options, { dhcp_option_address_parse ("NBDD", p[2], o->nbdd, &o->nbdd_len, msglevel); } - else if (streq (p[1], "DISABLE-NBT")) + else if (streq (p[1], "DISABLE-NBT") && !p[2]) { o->disable_nbt = 1; } else { - msg (msglevel, "--dhcp-option: unknown option type '%s' or missing parameter", p[1]); + msg (msglevel, "--dhcp-option: unknown option type '%s' or missing or unknown parameter", p[1]); goto err; } o->dhcp_options = true; } #endif #ifdef WIN32 - else if (streq (p[0], "show-adapters")) + else if (streq (p[0], "show-adapters") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); show_tap_win_adapters (M_INFO|M_NOPREFIX, M_WARN|M_NOPREFIX); openvpn_exit (OPENVPN_EXIT_STATUS_GOOD); /* exit point */ } - else if (streq (p[0], "show-net")) + else if (streq (p[0], "show-net") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); show_routes (M_INFO|M_NOPREFIX); show_adapters (M_INFO|M_NOPREFIX); openvpn_exit (OPENVPN_EXIT_STATUS_GOOD); /* exit point */ } - else if (streq (p[0], "show-net-up")) + else if (streq (p[0], "show-net-up") && !p[1]) { VERIFY_PERMISSION (OPT_P_UP); options->show_net_up = true; } - else if (streq (p[0], "tap-sleep") && p[1]) + else if (streq (p[0], "tap-sleep") && p[1] && !p[2]) { int s; VERIFY_PERMISSION (OPT_P_IPWIN32); @@ -6109,22 +6114,22 @@ add_option (struct options *options, } options->tuntap_options.tap_sleep = s; } - else if (streq (p[0], "dhcp-renew")) + else if (streq (p[0], "dhcp-renew") && !p[1]) { VERIFY_PERMISSION (OPT_P_IPWIN32); options->tuntap_options.dhcp_renew = true; } - else if (streq (p[0], "dhcp-pre-release")) + else if (streq (p[0], "dhcp-pre-release") && !p[1]) { VERIFY_PERMISSION (OPT_P_IPWIN32); options->tuntap_options.dhcp_pre_release = true; } - else if (streq (p[0], "dhcp-release")) + else if (streq (p[0], "dhcp-release") && !p[1]) { VERIFY_PERMISSION (OPT_P_IPWIN32); options->tuntap_options.dhcp_release = true; } - else if (streq (p[0], "dhcp-internal") && p[1]) /* standalone method for internal use */ + else if (streq (p[0], "dhcp-internal") && p[1] && !p[2]) /* standalone method for internal use */ { unsigned int adapter_index; VERIFY_PERMISSION (OPT_P_GENERAL); @@ -6137,12 +6142,12 @@ add_option (struct options *options, dhcp_renew_by_adapter_index (adapter_index); openvpn_exit (OPENVPN_EXIT_STATUS_GOOD); /* exit point */ } - else if (streq (p[0], "register-dns")) + else if (streq (p[0], "register-dns") && !p[1]) { VERIFY_PERMISSION (OPT_P_IPWIN32); options->tuntap_options.register_dns = true; } - else if (streq (p[0], "rdns-internal")) + else if (streq (p[0], "rdns-internal") && !p[1]) /* standalone method for internal use * * (if --register-dns is set, openvpn needs to call itself in a @@ -6156,18 +6161,18 @@ add_option (struct options *options, ipconfig_register_dns (NULL); openvpn_exit (OPENVPN_EXIT_STATUS_GOOD); /* exit point */ } - else if (streq (p[0], "show-valid-subnets")) + else if (streq (p[0], "show-valid-subnets") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); show_valid_win32_tun_subnets (); openvpn_exit (OPENVPN_EXIT_STATUS_GOOD); /* exit point */ } - else if (streq (p[0], "pause-exit")) + else if (streq (p[0], "pause-exit") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); set_pause_exit_win32 (); } - else if (streq (p[0], "service") && p[1]) + else if (streq (p[0], "service") && p[1] && !p[3]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->exit_event_name = p[1]; @@ -6176,52 +6181,52 @@ add_option (struct options *options, options->exit_event_initial_state = (atoi(p[2]) != 0); } } - else if (streq (p[0], "allow-nonadmin")) + else if (streq (p[0], "allow-nonadmin") && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); tap_allow_nonadmin_access (p[1]); openvpn_exit (OPENVPN_EXIT_STATUS_GOOD); /* exit point */ } - else if (streq (p[0], "user") && p[1]) + else if (streq (p[0], "user") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); msg (M_WARN, "NOTE: --user option is not implemented on Windows"); } - else if (streq (p[0], "group") && p[1]) + else if (streq (p[0], "group") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); msg (M_WARN, "NOTE: --group option is not implemented on Windows"); } #else - else if (streq (p[0], "user") && p[1]) + else if (streq (p[0], "user") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->username = p[1]; } - else if (streq (p[0], "group") && p[1]) + else if (streq (p[0], "group") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->groupname = p[1]; } - else if (streq (p[0], "dhcp-option") && p[1]) + else if (streq (p[0], "dhcp-option") && p[1] && !p[3]) { VERIFY_PERMISSION (OPT_P_IPWIN32); foreign_option (options, p, 3, es); } - else if (streq (p[0], "route-method") && p[1]) /* ignore when pushed to non-Windows OS */ + else if (streq (p[0], "route-method") && p[1] && !p[2]) /* ignore when pushed to non-Windows OS */ { VERIFY_PERMISSION (OPT_P_ROUTE_EXTRAS); } #endif #if PASSTOS_CAPABILITY - else if (streq (p[0], "passtos")) + else if (streq (p[0], "passtos") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->passtos = true; } #endif #if defined(USE_COMP) - else if (streq (p[0], "comp-lzo")) + else if (streq (p[0], "comp-lzo") && !p[2]) { VERIFY_PERMISSION (OPT_P_COMP); @@ -6258,12 +6263,12 @@ add_option (struct options *options, } #endif } - else if (streq (p[0], "comp-noadapt")) + else if (streq (p[0], "comp-noadapt") && !p[1]) { VERIFY_PERMISSION (OPT_P_COMP); options->comp.flags &= ~COMP_F_ADAPTIVE; } - else if (streq (p[0], "compress")) + else if (streq (p[0], "compress") && !p[2]) { VERIFY_PERMISSION (OPT_P_COMP); if (p[1]) @@ -6308,22 +6313,22 @@ add_option (struct options *options, } #endif /* USE_COMP */ #ifdef ENABLE_CRYPTO - else if (streq (p[0], "show-ciphers")) + else if (streq (p[0], "show-ciphers") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->show_ciphers = true; } - else if (streq (p[0], "show-digests")) + else if (streq (p[0], "show-digests") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->show_digests = true; } - else if (streq (p[0], "show-engines")) + else if (streq (p[0], "show-engines") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->show_engines = true; } - else if (streq (p[0], "key-direction") && p[1]) + else if (streq (p[0], "key-direction") && p[1] && !p[2]) { int key_direction; @@ -6333,7 +6338,7 @@ add_option (struct options *options, else goto err; } - else if (streq (p[0], "secret") && p[1]) + else if (streq (p[0], "secret") && p[1] && !p[3]) { VERIFY_PERMISSION (OPT_P_GENERAL); if (streq (p[1], INLINE_FILE_TAG) && p[2]) @@ -6353,12 +6358,12 @@ add_option (struct options *options, } options->shared_secret_file = p[1]; } - else if (streq (p[0], "genkey")) + else if (streq (p[0], "genkey") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->genkey = true; } - else if (streq (p[0], "auth") && p[1]) + else if (streq (p[0], "auth") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_CRYPTO); options->authname_defined = true; @@ -6369,12 +6374,12 @@ add_option (struct options *options, options->authname = NULL; } } - else if (streq (p[0], "auth")) + else if (streq (p[0], "auth") && !p[1]) { VERIFY_PERMISSION (OPT_P_CRYPTO); options->authname_defined = true; } - else if (streq (p[0], "cipher") && p[1]) + else if (streq (p[0], "cipher") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_CRYPTO); options->ciphername_defined = true; @@ -6385,12 +6390,12 @@ add_option (struct options *options, options->ciphername = NULL; } } - else if (streq (p[0], "cipher")) + else if (streq (p[0], "cipher") && !p[1]) { VERIFY_PERMISSION (OPT_P_CRYPTO); options->ciphername_defined = true; } - else if (streq (p[0], "prng") && p[1]) + else if (streq (p[0], "prng") && p[1] && !p[3]) { VERIFY_PERMISSION (OPT_P_CRYPTO); if (streq (p[1], "none")) @@ -6412,12 +6417,12 @@ add_option (struct options *options, } } } - else if (streq (p[0], "no-replay")) + else if (streq (p[0], "no-replay") && !p[1]) { VERIFY_PERMISSION (OPT_P_CRYPTO); options->replay = false; } - else if (streq (p[0], "replay-window")) + else if (streq (p[0], "replay-window") && !p[3]) { VERIFY_PERMISSION (OPT_P_CRYPTO); if (p[1]) @@ -6457,28 +6462,28 @@ add_option (struct options *options, goto err; } } - else if (streq (p[0], "mute-replay-warnings")) + else if (streq (p[0], "mute-replay-warnings") && !p[1]) { VERIFY_PERMISSION (OPT_P_CRYPTO); options->mute_replay_warnings = true; } - else if (streq (p[0], "no-iv")) + else if (streq (p[0], "no-iv") && !p[1]) { VERIFY_PERMISSION (OPT_P_CRYPTO); options->use_iv = false; } - else if (streq (p[0], "replay-persist") && p[1]) + else if (streq (p[0], "replay-persist") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->packet_id_file = p[1]; } - else if (streq (p[0], "test-crypto")) + else if (streq (p[0], "test-crypto") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->test_crypto = true; } #ifndef ENABLE_CRYPTO_POLARSSL - else if (streq (p[0], "engine")) + else if (streq (p[0], "engine") && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); if (p[1]) @@ -6490,7 +6495,7 @@ add_option (struct options *options, } #endif /* ENABLE_CRYPTO_POLARSSL */ #ifdef HAVE_EVP_CIPHER_CTX_SET_KEY_LENGTH - else if (streq (p[0], "keysize") && p[1]) + else if (streq (p[0], "keysize") && p[1] && !p[2]) { int keysize; @@ -6505,38 +6510,38 @@ add_option (struct options *options, } #endif #ifdef ENABLE_PREDICTION_RESISTANCE - else if (streq (p[0], "use-prediction-resistance")) + else if (streq (p[0], "use-prediction-resistance") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->use_prediction_resistance = true; } #endif - else if (streq (p[0], "show-tls")) + else if (streq (p[0], "show-tls") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->show_tls_ciphers = true; } - else if (streq (p[0], "show-curves")) + else if (streq (p[0], "show-curves") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->show_curves = true; } - else if (streq (p[0], "ecdh-curve") && p[1]) + else if (streq (p[0], "ecdh-curve") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_CRYPTO); options->ecdh_curve= p[1]; } - else if (streq (p[0], "tls-server")) + else if (streq (p[0], "tls-server") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->tls_server = true; } - else if (streq (p[0], "tls-client")) + else if (streq (p[0], "tls-client") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->tls_client = true; } - else if (streq (p[0], "ca") && p[1]) + else if (streq (p[0], "ca") && p[1] && ((streq (p[1], INLINE_FILE_TAG) && p[2]) || !p[2]) && !p[3]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->ca_file = p[1]; @@ -6546,13 +6551,13 @@ add_option (struct options *options, } } #ifndef ENABLE_CRYPTO_POLARSSL - else if (streq (p[0], "capath") && p[1]) + else if (streq (p[0], "capath") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->ca_path = p[1]; } #endif /* ENABLE_CRYPTO_POLARSSL */ - else if (streq (p[0], "dh") && p[1]) + else if (streq (p[0], "dh") && p[1] && ((streq (p[1], INLINE_FILE_TAG) && p[2]) || !p[2]) && !p[3]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->dh_file = p[1]; @@ -6561,7 +6566,7 @@ add_option (struct options *options, options->dh_file_inline = p[2]; } } - else if (streq (p[0], "cert") && p[1]) + else if (streq (p[0], "cert") && p[1] && ((streq (p[1], INLINE_FILE_TAG) && p[2]) || !p[2]) && !p[3]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->cert_file = p[1]; @@ -6570,7 +6575,7 @@ add_option (struct options *options, options->cert_file_inline = p[2]; } } - else if (streq (p[0], "extra-certs") && p[1]) + else if (streq (p[0], "extra-certs") && p[1] && ((streq (p[1], INLINE_FILE_TAG) && p[2]) || !p[2]) && !p[3]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->extra_certs_file = p[1]; @@ -6579,19 +6584,19 @@ add_option (struct options *options, options->extra_certs_file_inline = p[2]; } } - else if (streq (p[0], "verify-hash") && p[1]) + else if (streq (p[0], "verify-hash") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->verify_hash = parse_hash_fingerprint(p[1], SHA_DIGEST_LENGTH, msglevel, &options->gc); } #ifdef ENABLE_CRYPTOAPI - else if (streq (p[0], "cryptoapicert") && p[1]) + else if (streq (p[0], "cryptoapicert") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->cryptoapi_cert = p[1]; } #endif - else if (streq (p[0], "key") && p[1]) + else if (streq (p[0], "key") && p[1] && ((streq (p[1], INLINE_FILE_TAG) && p[2]) || !p[2]) && !p[3]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->priv_key_file = p[1]; @@ -6600,7 +6605,7 @@ add_option (struct options *options, options->priv_key_file_inline = p[2]; } } - else if (streq (p[0], "tls-version-min") && p[1]) + else if (streq (p[0], "tls-version-min") && p[1] && !p[3]) { int ver; VERIFY_PERMISSION (OPT_P_GENERAL); @@ -6614,7 +6619,7 @@ add_option (struct options *options, ~(SSLF_TLS_VERSION_MIN_MASK << SSLF_TLS_VERSION_MIN_SHIFT); options->ssl_flags |= (ver << SSLF_TLS_VERSION_MIN_SHIFT); } - else if (streq (p[0], "tls-version-max") && p[1]) + else if (streq (p[0], "tls-version-max") && p[1] && !p[2]) { int ver; VERIFY_PERMISSION (OPT_P_GENERAL); @@ -6629,7 +6634,7 @@ add_option (struct options *options, options->ssl_flags |= (ver << SSLF_TLS_VERSION_MAX_SHIFT); } #ifndef ENABLE_CRYPTO_POLARSSL - else if (streq (p[0], "pkcs12") && p[1]) + else if (streq (p[0], "pkcs12") && p[1] && ((streq (p[1], INLINE_FILE_TAG) && p[2]) || !p[2]) && !p[3]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->pkcs12_file = p[1]; @@ -6639,7 +6644,7 @@ add_option (struct options *options, } } #endif /* ENABLE_CRYPTO_POLARSSL */ - else if (streq (p[0], "askpass")) + else if (streq (p[0], "askpass") && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); if (p[1]) @@ -6649,12 +6654,12 @@ add_option (struct options *options, else options->key_pass_file = "stdin"; } - else if (streq (p[0], "auth-nocache")) + else if (streq (p[0], "auth-nocache") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); ssl_set_auth_nocache (); } - else if (streq (p[0], "auth-token") && p[1]) + else if (streq (p[0], "auth-token") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_ECHO); ssl_set_auth_token(p[1]); @@ -6663,29 +6668,29 @@ add_option (struct options *options, management_auth_token (management, p[1]); #endif } - else if (streq (p[0], "single-session")) + else if (streq (p[0], "single-session") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->single_session = true; } #ifdef ENABLE_PUSH_PEER_INFO - else if (streq (p[0], "push-peer-info")) + else if (streq (p[0], "push-peer-info") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->push_peer_info = true; } #endif - else if (streq (p[0], "tls-exit")) + else if (streq (p[0], "tls-exit") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->tls_exit = true; } - else if (streq (p[0], "tls-cipher") && p[1]) + else if (streq (p[0], "tls-cipher") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->cipher_list = p[1]; } - else if (streq (p[0], "crl-verify") && p[1]) + else if (streq (p[0], "crl-verify") && p[1] && ((p[2] && streq(p[2], "dir")) || !p[2]) && !p[3]) { VERIFY_PERMISSION (OPT_P_GENERAL); if (p[2] && streq(p[2], "dir")) @@ -6702,13 +6707,17 @@ add_option (struct options *options, "tls-verify", true); } #ifndef ENABLE_CRYPTO_POLARSSL - else if (streq (p[0], "tls-export-cert") && p[1]) + else if (streq (p[0], "tls-export-cert") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->tls_export_cert = p[1]; } #endif - else if (streq (p[0], "compat-names")) +#if P2MP_SERVER + else if (streq (p[0], "compat-names") && ((p[1] && streq (p[1], "no-remapping")) || !p[1]) && !p[2]) +#else + else if (streq (p[0], "compat-names") && !p[1]) +#endif { VERIFY_PERMISSION (OPT_P_GENERAL); if (options->verify_x509_type != VERIFY_X509_NONE && @@ -6724,7 +6733,7 @@ add_option (struct options *options, if (p[1] && streq (p[1], "no-remapping")) compat_flag (COMPAT_FLAG_SET | COMPAT_NO_NAME_REMAPPING); } - else if (streq (p[0], "no-name-remapping")) + else if (streq (p[0], "no-name-remapping") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); if (options->verify_x509_type != VERIFY_X509_NONE && @@ -6739,7 +6748,7 @@ add_option (struct options *options, compat_flag (COMPAT_FLAG_SET | COMPAT_NO_NAME_REMAPPING); #endif } - else if (streq (p[0], "tls-remote") && p[1]) + else if (streq (p[0], "tls-remote") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); @@ -6770,7 +6779,7 @@ add_option (struct options *options, options->verify_x509_name = p[1]; } } - else if (streq (p[0], "verify-x509-name") && p[1] && strlen (p[1])) + else if (streq (p[0], "verify-x509-name") && p[1] && strlen (p[1]) && !p[3]) { int type = VERIFY_X509_SUBJECT_DN; VERIFY_PERMISSION (OPT_P_GENERAL); @@ -6803,7 +6812,7 @@ add_option (struct options *options, options->verify_x509_type = type; options->verify_x509_name = p[1]; } - else if (streq (p[0], "ns-cert-type") && p[1]) + else if (streq (p[0], "ns-cert-type") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); if (streq (p[1], "server")) @@ -6825,12 +6834,12 @@ add_option (struct options *options, for (j = 1; j < MAX_PARMS && p[j] != NULL; ++j) sscanf (p[j], "%x", &(options->remote_cert_ku[j-1])); } - else if (streq (p[0], "remote-cert-eku") && p[1]) + else if (streq (p[0], "remote-cert-eku") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->remote_cert_eku = p[1]; } - else if (streq (p[0], "remote-cert-tls") && p[1]) + else if (streq (p[0], "remote-cert-tls") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); @@ -6853,37 +6862,37 @@ add_option (struct options *options, goto err; } } - else if (streq (p[0], "tls-timeout") && p[1]) + else if (streq (p[0], "tls-timeout") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_TLS_PARMS); options->tls_timeout = positive_atoi (p[1]); } - else if (streq (p[0], "reneg-bytes") && p[1]) + else if (streq (p[0], "reneg-bytes") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_TLS_PARMS); options->renegotiate_bytes = positive_atoi (p[1]); } - else if (streq (p[0], "reneg-pkts") && p[1]) + else if (streq (p[0], "reneg-pkts") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_TLS_PARMS); options->renegotiate_packets = positive_atoi (p[1]); } - else if (streq (p[0], "reneg-sec") && p[1]) + else if (streq (p[0], "reneg-sec") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_TLS_PARMS); options->renegotiate_seconds = positive_atoi (p[1]); } - else if (streq (p[0], "hand-window") && p[1]) + else if (streq (p[0], "hand-window") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_TLS_PARMS); options->handshake_window = positive_atoi (p[1]); } - else if (streq (p[0], "tran-window") && p[1]) + else if (streq (p[0], "tran-window") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_TLS_PARMS); options->transition_window = positive_atoi (p[1]); } - else if (streq (p[0], "tls-auth") && p[1]) + else if (streq (p[0], "tls-auth") && p[1] && !p[3]) { VERIFY_PERMISSION (OPT_P_GENERAL); if (streq (p[1], INLINE_FILE_TAG) && p[2]) @@ -6903,7 +6912,7 @@ add_option (struct options *options, } options->tls_auth_file = p[1]; } - else if (streq (p[0], "key-method") && p[1]) + else if (streq (p[0], "key-method") && p[1] && !p[2]) { int key_method; @@ -6920,7 +6929,7 @@ add_option (struct options *options, options->key_method = key_method; } #ifdef ENABLE_X509ALTUSERNAME - else if (streq (p[0], "x509-username-field") && p[1]) + else if (streq (p[0], "x509-username-field") && p[1] && !p[2]) { /* This option used to automatically upcase the fieldname passed as the * option argument, e.g., "ou" became "OU". Now, this "helpfulness" is @@ -6949,7 +6958,7 @@ add_option (struct options *options, #endif /* ENABLE_X509ALTUSERNAME */ #endif /* ENABLE_CRYPTO */ #ifdef ENABLE_PKCS11 - else if (streq (p[0], "show-pkcs11-ids")) + else if (streq (p[0], "show-pkcs11-ids") && !p[3]) { char *provider = p[1]; bool cert_private = (p[2] == NULL ? false : ( atoi (p[2]) != 0 )); @@ -7019,35 +7028,35 @@ add_option (struct options *options, for (j = 1; j < MAX_PARMS && p[j] != NULL; ++j) options->pkcs11_cert_private[j-1] = atoi (p[j]) != 0 ? 1 : 0; } - else if (streq (p[0], "pkcs11-pin-cache") && p[1]) + else if (streq (p[0], "pkcs11-pin-cache") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->pkcs11_pin_cache_period = atoi (p[1]); } - else if (streq (p[0], "pkcs11-id") && p[1]) + else if (streq (p[0], "pkcs11-id") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->pkcs11_id = p[1]; } - else if (streq (p[0], "pkcs11-id-management")) + else if (streq (p[0], "pkcs11-id-management") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->pkcs11_id_management = true; } #endif - else if (streq (p[0], "rmtun")) + else if (streq (p[0], "rmtun") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->persist_config = true; options->persist_mode = 0; } - else if (streq (p[0], "mktun")) + else if (streq (p[0], "mktun") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->persist_config = true; options->persist_mode = 1; } - else if (streq (p[0], "peer-id") && p[1]) + else if (streq (p[0], "peer-id") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_PEER_ID); options->use_peer_id = true; @@ -7068,9 +7077,9 @@ add_option (struct options *options, } } if (file) - msg (msglevel, "Unrecognized option or missing parameter(s) in %s:%d: %s (%s)", file, line, p[0], PACKAGE_VERSION); + msg (msglevel, "Unrecognized option or missing or extra parameter(s) in %s:%d: %s (%s)", file, line, p[0], PACKAGE_VERSION); else - msg (msglevel, "Unrecognized option or missing parameter(s): --%s (%s)", p[0], PACKAGE_VERSION); + msg (msglevel, "Unrecognized option or missing or extra parameter(s): --%s (%s)", p[0], PACKAGE_VERSION); } err: gc_free (&gc); From e5f71d674e3b119d6a252d7cef1c17b5c2b36a9a Mon Sep 17 00:00:00 2001 From: Holger Kummert Date: Thu, 25 Jun 2015 18:01:20 +0200 Subject: [PATCH 055/643] Del ipv6 addr on close of linux tun interface When a linux tun interface is closed (e.g. on disconnect) an optional ipv6 addr that was previously set is deleted now. Without this patch a later reconnect could fail with 'Linux ip -6 addr add failed: external program exited with error status: 2' and openvpn would exit. This is mainly relevant for persistant tun devices (staying around after openvpn exits) but can also happen at reconnect. If addresses are *supposed* to stay around on openvpn exit, run openvpn with --ifconfig-noexec and configure IPv4/IPv6 addresses manually before openvpn starts (or using an --up script). Trac #141 Acked-by: Gert Doering Message-Id: <1435248080-12670-1-git-send-email-Holger.Kummert@Sophos.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/9810 Signed-off-by: Gert Doering --- src/openvpn/tun.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index 59e7436bf66..13e38267307 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -1860,6 +1860,32 @@ close_tun (struct tuntap *tt) argv_msg (M_INFO, &argv); openvpn_execve_check (&argv, NULL, 0, "Linux ip addr del failed"); + if (tt->ipv6 && tt->did_ifconfig_ipv6_setup) + { + const char * ifconfig_ipv6_local = print_in6_addr (tt->local_ipv6, 0, &gc); + +#ifdef ENABLE_IPROUTE + argv_printf (&argv, "%s -6 addr del %s/%d dev %s", + iproute_path, + ifconfig_ipv6_local, + tt->netbits_ipv6, + tt->actual_name + ); + argv_msg (M_INFO, &argv); + openvpn_execve_check (&argv, NULL, 0, "Linux ip -6 addr del failed"); +#else + argv_printf (&argv, + "%s %s del %s/%d", + IFCONFIG_PATH, + tt->actual_name, + ifconfig_ipv6_local, + tt->netbits_ipv6 + ); + argv_msg (M_INFO, &argv); + openvpn_execve_check (&argv, NULL, 0, "Linux ifconfig inet6 del failed"); +#endif + } + argv_reset (&argv); gc_free (&gc); } From 68eecf76978a80bd5d88e944e4ed5e42bf2fd8e4 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Mon, 29 Jun 2015 14:46:35 +0200 Subject: [PATCH 056/643] Report missing end-tags of inline files as errors (2.3 reports as warning only, 2.4 reports as M_FATAL) trac #568 Acked-by: Gert Doering Message-Id: <1435581995-11820-1-git-send-email-arne@rfc2549.org> URL: http://article.gmane.org/gmane.network.openvpn.devel/9830 Signed-off-by: Gert Doering --- src/openvpn/options.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 74276d453a3..4165ec7d28d 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -3703,10 +3703,15 @@ read_inline_file (struct in_src *is, const char *close_tag, struct gc_arena *gc) char line[OPTION_LINE_SIZE]; struct buffer buf = alloc_buf (8*OPTION_LINE_SIZE); char *ret; + bool endtagfound = false; + while (in_src_get (is, line, sizeof (line))) { if (!strncmp (line, close_tag, strlen (close_tag))) - break; + { + endtagfound = true; + break; + } if (!buf_safe (&buf, strlen(line))) { /* Increase buffer size */ @@ -3718,6 +3723,8 @@ read_inline_file (struct in_src *is, const char *close_tag, struct gc_arena *gc) } buf_printf (&buf, "%s", line); } + if (!endtagfound) + msg (M_FATAL, "ERROR: Endtag %s missing", close_tag); ret = string_alloc (BSTR (&buf), gc); buf_clear (&buf); free_buf (&buf); From fc91d4b0071178e298052078431fb86f03be84fc Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Tue, 30 Jun 2015 21:44:56 +0200 Subject: [PATCH 057/643] Increase control channel packet size for faster handshakes Instead of limiting the control channel TCP/UDP packet payload size at '100 bytes + real control channel overhead' (~140 bytes ethernet payload), increase the max TCP/UDP payload size to '1250 bytes - calculated overhead' (~1210 bytes ethernet payload). Note that this patch does *not* yield an optimal solution, but it is a simple and rather safe change that will improve connection setup times significantly. v2: use the mininum value of --link-mtu and 1250 to give the user a way to reduce control packet size if really needed. trac #545 Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1435693496-10931-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/9841 Signed-off-by: Gert Doering --- src/openvpn/ssl.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index ebb2f0db93e..4e44410ef6c 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -298,8 +298,9 @@ tls_init_control_channel_frame_parameters(const struct frame *data_channel_frame reliable_ack_adjust_frame_parameters (frame, CONTROL_SEND_ACK_MAX); frame_add_to_extra_frame (frame, SID_SIZE + sizeof (packet_id_type)); - /* set dynamic link MTU to minimum value */ - frame_set_mtu_dynamic (frame, 0, SET_MTU_TUN); + /* set dynamic link MTU to cap control channel packets at 1250 bytes */ + ASSERT (TUN_LINK_DELTA (frame) < min_int (frame->link_mtu, 1250)); + frame->link_mtu_dynamic = min_int (frame->link_mtu, 1250) - TUN_LINK_DELTA (frame); } void From 9884e20810bda737c7708ff587e09cc0bb8475c7 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Wed, 1 Jul 2015 23:25:56 +0200 Subject: [PATCH 058/643] Make __func__ work with Visual Studio too Because even VS2013 is incapable of doing C99. Signed-off-by: Steffan Karger Tested-by: Fish Wang Acked-by: Gert Doering Message-Id: URL: http://article.gmane.org/gmane.network.openvpn.devel/9859 Signed-off-by: Gert Doering --- src/openvpn/syshead.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/openvpn/syshead.h b/src/openvpn/syshead.h index cf29131f2bc..ff0bf419b56 100644 --- a/src/openvpn/syshead.h +++ b/src/openvpn/syshead.h @@ -45,6 +45,10 @@ #define srandom srand #endif +#ifdef _MSC_VER // Visual Studio +#define __func__ __FUNCTION__ +#endif + #if defined(__APPLE__) #if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1070 #define __APPLE_USE_RFC_3542 1 From 315f6fbc7f657a7f1127628bd714f468709d5185 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Thu, 9 Jul 2015 23:35:59 +0200 Subject: [PATCH 059/643] fix regression: query password before becoming daemon The init sequence was changed to daemonize before the crypto init to fix issues on FreeBSD some commits ago. This introduced a regression where we would no longer query for passwords before daemonizing, as described in trac #574 and #576. This commit restores the correct order, and adds a bit of const correctness since we're touching this now code anyway. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1436477759-5884-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/9901 Signed-off-by: Gert Doering --- src/openvpn/init.c | 6 ++---- src/openvpn/init.h | 5 +++++ src/openvpn/openvpn.c | 5 ++++- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 13f5612d193..c24a646f366 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -407,8 +407,8 @@ next_connection_entry (struct context *c) /* * Query for private key and auth-user-pass username/passwords */ -static void -init_query_passwords (struct context *c) +void +init_query_passwords (const struct context *c) { #ifdef ENABLE_CRYPTO /* Certificate password input */ @@ -502,8 +502,6 @@ context_init_1 (struct context *c) init_connection_list (c); - init_query_passwords (c); - #if defined(ENABLE_PKCS11) if (c->first_time) { int i; diff --git a/src/openvpn/init.h b/src/openvpn/init.h index d1908ed128c..a819bd2ce78 100644 --- a/src/openvpn/init.h +++ b/src/openvpn/init.h @@ -63,6 +63,11 @@ void init_instance_handle_signals (struct context *c, const struct env_set *env, void init_instance (struct context *c, const struct env_set *env, const unsigned int flags); +/** + * Query for private key and auth-user-pass username/passwords. + */ +void init_query_passwords (const struct context *c); + void do_route (const struct options *options, struct route_list *route_list, struct route_ipv6_list *route_ipv6_list, diff --git a/src/openvpn/openvpn.c b/src/openvpn/openvpn.c index 00bd5703c36..d05acde3c1c 100644 --- a/src/openvpn/openvpn.c +++ b/src/openvpn/openvpn.c @@ -228,7 +228,10 @@ openvpn_main (int argc, char *argv[]) /* test crypto? */ if (do_test_crypto (&c.options)) break; - + + /* Query passwords before becoming a daemon */ + init_query_passwords (&c); + /* become a daemon if --daemon */ if (c.first_time) { From 079e5b9c13bf81d7afc6f932b5417d2f08f8e64b Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Mon, 13 Jul 2015 21:10:07 +0200 Subject: [PATCH 060/643] Produce a meaningful error message if --daemon gets in the way of asking for passwords. With the --daemon / SSL init reordering in da9b292733, we fail if we daemonize first and then try to ask for a private key passphrase (or, for that matter, username+password if --auth-nocache is set) - but no meaningful error message was printed, instead depending on operating system and library versions, either we looped around "ssl init failed" or died with an unspecified "fatal error". So: check if get_user_pass_cr() is called in a context that needs "from_stdin", but both stdin and stderr are not connected to a tty device (which getpass() needs). In that case, print a meaningful error message pointing to --askpass, and die. Trac #574 and #576 Signed-off-by: Gert Doering Acked-by: Steffan Karger Message-Id: <1436814607-16707-1-git-send-email-gert@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/9916 --- src/openvpn/misc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/openvpn/misc.c b/src/openvpn/misc.c index 4fdbf1753ee..c4438b6de9a 100644 --- a/src/openvpn/misc.c +++ b/src/openvpn/misc.c @@ -1056,6 +1056,10 @@ get_user_pass_cr (struct user_pass *up, */ else if (from_stdin) { + /* did we --daemon'ize before asking for passwords? */ + if ( !isatty(0) && !isatty(2) ) + { msg(M_FATAL, "neither stdin nor stderr are a tty device, can't ask for %s password. If you used --daemon, you need to use --askpass to make passphrase-protected keys work, and you can not use --auth-nocache.", prefix ); } + #ifdef ENABLE_CLIENT_CR if (auth_challenge && (flags & GET_USER_PASS_DYNAMIC_CHALLENGE)) { From 4e1e3ba1d8582a1e95dd6f9564e97c99784959a7 Mon Sep 17 00:00:00 2001 From: James Geboski Date: Tue, 8 Jan 2013 17:52:57 -0500 Subject: [PATCH 061/643] Fix --askpass not allowing for password input via stdin This resolves --askpass treating stdin as a file during the file access check. In turn, this leads to openvpn failing to start if this option is set to stdin. By default, --askpass reads the certificate's password from stdin rather than a file. Without passing the CHKACC_ACPTSTDIN flag to check_file_access(), stdin is marked as being a nonexistent file. Trac #248 Signed-off-by: James Geboski Acked-by: Steffan Karger Message-Id: <55A41225.2020705@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/9918 Signed-off-by: Gert Doering --- src/openvpn/options.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 4165ec7d28d..76e6b6522bd 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -2738,8 +2738,8 @@ options_postprocess_filechecks (struct options *options) options->packet_id_file, R_OK|W_OK, "--replay-persist"); /* ** Password files ** */ - errs |= check_file_access (CHKACC_FILE, options->key_pass_file, R_OK, - "--askpass"); + errs |= check_file_access (CHKACC_FILE|CHKACC_ACPTSTDIN, + options->key_pass_file, R_OK, "--askpass"); #endif /* ENABLE_CRYPTO */ #ifdef ENABLE_MANAGEMENT errs |= check_file_access (CHKACC_FILE|CHKACC_ACPTSTDIN, From b6ec7fbe96f4e200b8962ef6bb572bbb2228133e Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Tue, 14 Jul 2015 09:09:54 +0200 Subject: [PATCH 062/643] Document --daemon changes and consequences (--askpass, --auth-nocache). Trac #574, #576 Signed-off-by: Gert Doering Acked-by: Steffan Karger Message-Id: <1436857794-29419-1-git-send-email-gert@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/9923 --- doc/openvpn.8 | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 3eb2493a8f4..0692a801750 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -2208,6 +2208,22 @@ openvpn command for a fairly reliable indication of whether the command has correctly initialized and entered the packet forwarding event loop. In OpenVPN, the vast majority of errors which occur after initialization are non-fatal. + +Note: as soon as OpenVPN has daemonized, it can not ask for usernames, +passwords, or key pass phrases anymore. This has certain consequences, +namely that using a password-protected private key will fail unless the +.B \-\-askpass +option is used to tell OpenVPN to ask for the pass phrase (this +requirement is new in 2.3.7, and is a consequence of calling daemon() +before initializing the crypto layer). + +Further, using +.B \-\-daemon +together with +.B \-\-auth-user-pass +(entered on console) and +.B \-\-auth-nocache +will fail as soon as key renegotiation (and reauthentication) occurs. .\"********************************************************* .TP .B \-\-syslog [progname] From d4fbe287fc2ddbef05fdfe22adc641859a8a7412 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Wed, 15 Jul 2015 22:13:52 +0200 Subject: [PATCH 063/643] Fix using management interface to get passwords. Commits da9b292733e929a2900dc32d37f0424c3d588366 and 315f6fbc7f657a7f1127628bd714f468709d5185 broke the use case where we are asking password from the management client. The password is always asked before daemonization. With this fix we avoid this and ask it via management interface in the same spot as before the mentioned commits. Tested on Linux. v2: This patch was first submitted by Christian Pellegrin (from Google), and reworked by Steffan Karger (from the OpenVPN team) to also work for setups with --management-query-passwords but without --auth-user-pass. Signed-off-by: Steffan Karger Signed-off-by: Christian Pellegrin Tested-by: Christian Pellegrin Acked-by: Gert Doering Message-Id: <55A6C46C.5080601@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/9927 Signed-off-by: Gert Doering --- src/openvpn/openvpn.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/openvpn/openvpn.c b/src/openvpn/openvpn.c index d05acde3c1c..32e326e9c65 100644 --- a/src/openvpn/openvpn.c +++ b/src/openvpn/openvpn.c @@ -229,8 +229,12 @@ openvpn_main (int argc, char *argv[]) if (do_test_crypto (&c.options)) break; - /* Query passwords before becoming a daemon */ - init_query_passwords (&c); + /* Query passwords before becoming a daemon if we don't use the + * management interface to get them. */ +#ifdef ENABLE_MANAGEMENT + if (!(c.options.management_flags & MF_QUERY_PASSWORDS)) +#endif + init_query_passwords (&c); /* become a daemon if --daemon */ if (c.first_time) @@ -243,6 +247,9 @@ openvpn_main (int argc, char *argv[]) /* open management subsystem */ if (!open_management (&c)) break; + /* query for passwords through management interface, if needed */ + if (c.options.management_flags & MF_QUERY_PASSWORDS) + init_query_passwords (&c); #endif /* set certain options as environmental variables */ From 82acf2163412aae9259e2202dbe001a2ac797b99 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Sun, 19 Jul 2015 21:55:22 +0200 Subject: [PATCH 064/643] options: fix option check for "plugin" The "plugin" option has one required argument, and an optional one. This fixes a regression in 3d6a4cd (https://community.openvpn.net/openvpn/ticket/557). Signed-off-by: Daniel Hahler Acked-by: Gert Doering Message-Id: <20150721100836.GV382@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/9932 Signed-off-by: Gert Doering --- src/openvpn/options.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 76e6b6522bd..93baa2b0d8b 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -4325,7 +4325,7 @@ add_option (struct options *options, } #endif #ifdef ENABLE_PLUGIN - else if (streq (p[0], "plugin") && p[1] && !p[2]) + else if (streq (p[0], "plugin") && p[1] && !p[3]) { VERIFY_PERMISSION (OPT_P_PLUGIN); if (!options->plugin_list) From 2dd6501e3d679046a1ed488f22d62defdf737cf3 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sun, 26 Jul 2015 13:27:19 +0200 Subject: [PATCH 065/643] reintroduce md5_digest wrapper struct to fix gcc warnings I was wrong to assume that adding the const qualifier to the pointer-to- fixed-size-array contruction used in options_hash_changed_or_zero() was allowed. GCC actually warns about this, but I was using clang and clang seems to be fine with the contruction. To make GCC happy too, reintroduce the md5_digest wrapped struct, and use that when passing around the digest. This reverts the "struct md5_digest" parts of 827de237860813d2859a, but keeps the rest. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1437910039-30101-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/9949 Signed-off-by: Gert Doering --- src/openvpn/crypto.h | 5 +++++ src/openvpn/init.c | 12 ++++++------ src/openvpn/openvpn.h | 4 ++-- src/openvpn/push.c | 2 +- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/openvpn/crypto.h b/src/openvpn/crypto.h index 504896dee13..b32a90018b1 100644 --- a/src/openvpn/crypto.h +++ b/src/openvpn/crypto.h @@ -108,6 +108,11 @@ #include "packet_id.h" #include "mtu.h" +/** Wrapper struct to pass around MD5 digests */ +struct md5_digest { + uint8_t digest[MD5_DIGEST_LENGTH]; +}; + /* * Defines a key type and key length for both cipher and HMAC. */ diff --git a/src/openvpn/init.c b/src/openvpn/init.c index c24a646f366..fe0091865bf 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -1620,11 +1620,12 @@ tun_abort() * equal, or either one is all-zeroes. */ static bool -options_hash_changed_or_zero(const uint8_t (*a)[MD5_DIGEST_LENGTH], - const uint8_t (*b)[MD5_DIGEST_LENGTH]) +options_hash_changed_or_zero(const struct md5_digest *a, + const struct md5_digest *b) { - const uint8_t zero[MD5_DIGEST_LENGTH] = {0}; - return memcmp (*a, *b, MD5_DIGEST_LENGTH) || memcmp (*a, zero, MD5_DIGEST_LENGTH); + const struct md5_digest zero = {{0}}; + return memcmp (a, b, sizeof(struct md5_digest)) || + memcmp (a, &zero, sizeof(struct md5_digest)); } #endif /* P2MP */ @@ -1668,8 +1669,7 @@ do_up (struct context *c, bool pulled_options, unsigned int option_types_found) if (c->c2.did_open_tun) { #if P2MP - memcpy(c->c1.pulled_options_digest_save, c->c2.pulled_options_digest, - sizeof(c->c1.pulled_options_digest_save)); + c->c1.pulled_options_digest_save = c->c2.pulled_options_digest; #endif /* if --route-delay was specified, start timer */ diff --git a/src/openvpn/openvpn.h b/src/openvpn/openvpn.h index ef7ca1d027f..1c2a80b3528 100644 --- a/src/openvpn/openvpn.h +++ b/src/openvpn/openvpn.h @@ -199,7 +199,7 @@ struct context_1 #endif /* if client mode, hash of option strings we pulled from server */ - uint8_t pulled_options_digest_save[MD5_DIGEST_LENGTH]; + struct md5_digest pulled_options_digest_save; /**< Hash of option strings received from the * remote OpenVPN server. Only used in * client-mode. */ @@ -465,7 +465,7 @@ struct context_2 /* hash of pulled options, so we can compare when options change */ bool pulled_options_md5_init_done; md_ctx_t pulled_options_state; - uint8_t pulled_options_digest[MD5_DIGEST_LENGTH]; + struct md5_digest pulled_options_digest; struct event_timeout server_poll_interval; diff --git a/src/openvpn/push.c b/src/openvpn/push.c index c99a097d188..870616618d1 100644 --- a/src/openvpn/push.c +++ b/src/openvpn/push.c @@ -483,7 +483,7 @@ process_incoming_push_msg (struct context *c, case 0: case 1: md_ctx_update (&c->c2.pulled_options_state, BPTR(&buf_orig), BLEN(&buf_orig)); - md_ctx_final (&c->c2.pulled_options_state, c->c2.pulled_options_digest); + md_ctx_final (&c->c2.pulled_options_state, c->c2.pulled_options_digest.digest); md_ctx_cleanup (&c->c2.pulled_options_state); c->c2.pulled_options_md5_init_done = false; ret = PUSH_MSG_REPLY; From d40cbf0e2601b35bfb1c0551c6f3907b5c5178ff Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Mon, 27 Jul 2015 17:33:11 +0200 Subject: [PATCH 066/643] Fix commit e473b7c if an inline file happens to have a line break exactly at buffer limit The check does only for strlen(line) space and buf_printf will only use at most space -1 and not print the final character ('\n') in this corner. Since a missing \n only breaks certificates at the start and end marker, missing line breaks otherwise do not trigger this error. Acked-by: Steffan Karger Message-Id: <1438011191-19389-1-git-send-email-arne@rfc2549.org> URL: http://article.gmane.org/gmane.network.openvpn.devel/9956 Signed-off-by: Gert Doering --- src/openvpn/buffer.h | 5 ++++- src/openvpn/options.c | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/openvpn/buffer.h b/src/openvpn/buffer.h index 5695f64f380..0dc511b0ff8 100644 --- a/src/openvpn/buffer.h +++ b/src/openvpn/buffer.h @@ -329,7 +329,10 @@ has_digit (const unsigned char* src) } /* - * printf append to a buffer with overflow check + * printf append to a buffer with overflow check, + * due to usage of vsnprintf, it will leave space for + * a final null character and thus use only + * capacity - 1 */ bool buf_printf (struct buffer *buf, const char *format, ...) #ifdef __GNUC__ diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 93baa2b0d8b..9eb8e7648f9 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -3712,7 +3712,7 @@ read_inline_file (struct in_src *is, const char *close_tag, struct gc_arena *gc) endtagfound = true; break; } - if (!buf_safe (&buf, strlen(line))) + if (!buf_safe (&buf, strlen(line)+1)) { /* Increase buffer size */ struct buffer buf2 = alloc_buf (buf.capacity * 2); From 9de35d4633ce3035b048957b2e20b81e31a40cd6 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Fri, 10 Jul 2015 15:22:27 +0200 Subject: [PATCH 067/643] Provide compile time OpenVPN version information to plug-ins This is to provide more fine grained information to plug-ins about the OpenVPN environment when OpenVPN was built. Signed-off-by: David Sommerseth Acked-by: Steffan Karger Message-Id: <1436534548-21507-2-git-send-email-openvpn.list@topphemmelig.net> URL: http://article.gmane.org/gmane.network.openvpn.devel/9905 Signed-off-by: Gert Doering --- .gitignore | 1 + configure.ac | 4 ++++ include/Makefile.am | 1 + include/{openvpn-plugin.h => openvpn-plugin.h.in} | 7 +++++++ version.m4 | 7 ++++++- 5 files changed, 19 insertions(+), 1 deletion(-) rename include/{openvpn-plugin.h => openvpn-plugin.h.in} (98%) diff --git a/.gitignore b/.gitignore index 06ff7c664bf..0403ae86556 100644 --- a/.gitignore +++ b/.gitignore @@ -54,6 +54,7 @@ distro/rpm/openvpn.spec tests/t_client.sh tests/t_client-*-20??????-??????/ src/openvpn/openvpn +include/openvpn-plugin.h config-version.h nbproject test-driver diff --git a/configure.ac b/configure.ac index cd450d39aec..c7354f6c135 100644 --- a/configure.ac +++ b/configure.ac @@ -30,6 +30,9 @@ m4_include(version.m4) AC_INIT([PRODUCT_NAME], [PRODUCT_VERSION], [PRODUCT_BUGREPORT], [PRODUCT_TARNAME]) m4_include(compat.m4) AC_DEFINE([OPENVPN_VERSION_RESOURCE], [PRODUCT_VERSION_RESOURCE], [Version in windows resource format]) +AC_SUBST([OPENVPN_VERSION_MAJOR], [PRODUCT_VERSION_MAJOR], [OpenVPN major version]) +AC_SUBST([OPENVPN_VERSION_MINOR], [PRODUCT_VERSION_MINOR], [OpenVPN minor version]) +AC_SUBST([OPENVPN_VERSION_PATCH], [PRODUCT_VERSION_PATCH], [OpenVPN patch level - may be a string or integer]) AC_CONFIG_AUX_DIR([.]) AC_CONFIG_HEADERS([config.h]) @@ -1223,6 +1226,7 @@ AC_CONFIG_FILES([ distro/rpm/Makefile distro/rpm/openvpn.spec include/Makefile + include/openvpn-plugin.h src/Makefile src/compat/Makefile src/openvpn/Makefile diff --git a/include/Makefile.am b/include/Makefile.am index 13dee61d91b..70f20e9098c 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -11,5 +11,6 @@ MAINTAINERCLEANFILES = \ $(srcdir)/Makefile.in + $(srcdir)/openvpn-plugin.h.in include_HEADERS = openvpn-plugin.h diff --git a/include/openvpn-plugin.h b/include/openvpn-plugin.h.in similarity index 98% rename from include/openvpn-plugin.h rename to include/openvpn-plugin.h.in index 080ffff2e78..ddf32988402 100644 --- a/include/openvpn-plugin.h +++ b/include/openvpn-plugin.h.in @@ -49,6 +49,13 @@ typedef X509 openvpn_x509_cert_t; extern "C" { #endif +/* Provide some basic version information to plug-ins at OpenVPN compile time + * This is will not be the complete version + */ +#define OPENVPN_VERSION_MAJOR @OPENVPN_VERSION_MAJOR@ +#define OPENVPN_VERSION_MINOR @OPENVPN_VERSION_MINOR@ +#define OPENVPN_VERSION_PATCH "@OPENVPN_VERSION_PATCH@" + /* * Plug-in types. These types correspond to the set of script callbacks * supported by OpenVPN. diff --git a/version.m4 b/version.m4 index 376661f7c46..1157be44295 100644 --- a/version.m4 +++ b/version.m4 @@ -1,7 +1,12 @@ dnl define the OpenVPN version define([PRODUCT_NAME], [OpenVPN]) define([PRODUCT_TARNAME], [openvpn]) -define([PRODUCT_VERSION], [2.3_git]) +define([PRODUCT_VERSION_MAJOR], [2]) +define([PRODUCT_VERSION_MINOR], [3]) +define([PRODUCT_VERSION_PATCH], [_git]) +m4_append([PRODUCT_VERSION], [PRODUCT_VERSION_MAJOR]) +m4_append([PRODUCT_VERSION], [PRODUCT_VERSION_MINOR], [[.]]) +m4_append([PRODUCT_VERSION], [PRODUCT_VERSION_PATCH], [[]]) define([PRODUCT_BUGREPORT], [openvpn-users@lists.sourceforge.net]) define([PRODUCT_VERSION_RESOURCE], [2,3,0,0]) dnl define the TAP version From 6a40276c7500c2d0a2fe44b1a450ffe9cb2f37cd Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Fri, 10 Jul 2015 15:22:28 +0200 Subject: [PATCH 068/643] Provide OpenVPN runtime version information to plug-ins Also updated the log_v3 sample-plugin to demonstrate how this works. $ openvpn --plugin log_v3.so --dev tun Fri Jul 10 15:17:28 2015 OpenVPN 2.3_git [git:dev/plugin-version/f05d8623a29078bf+]..... ...more.openvpn.logging... log_v3: OpenVPN 2.3_git (Major: 2, Minor: 3, Patch: git:dev/plugin-version/f05d8623a29078bf+) ...more.openvpn.logging... $ Signed-off-by: David Sommerseth Acked-by: Gert Doering Message-Id: <1436534548-21507-3-git-send-email-openvpn.list@topphemmelig.net> URL: http://article.gmane.org/gmane.network.openvpn.devel/9904 Signed-off-by: Gert Doering --- configure.ac | 3 +++ include/openvpn-plugin.h.in | 9 ++++++++- sample/sample-plugins/log/log_v3.c | 6 ++++++ src/openvpn/plugin.c | 21 ++++++++++++++++++++- 4 files changed, 37 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index c7354f6c135..7bcbb7c2854 100644 --- a/configure.ac +++ b/configure.ac @@ -33,6 +33,9 @@ AC_DEFINE([OPENVPN_VERSION_RESOURCE], [PRODUCT_VERSION_RESOURCE], [Version in wi AC_SUBST([OPENVPN_VERSION_MAJOR], [PRODUCT_VERSION_MAJOR], [OpenVPN major version]) AC_SUBST([OPENVPN_VERSION_MINOR], [PRODUCT_VERSION_MINOR], [OpenVPN minor version]) AC_SUBST([OPENVPN_VERSION_PATCH], [PRODUCT_VERSION_PATCH], [OpenVPN patch level - may be a string or integer]) +AC_DEFINE([OPENVPN_VERSION_MAJOR], [PRODUCT_VERSION_MAJOR], [OpenVPN major version - integer]) +AC_DEFINE([OPENVPN_VERSION_MINOR], [PRODUCT_VERSION_MINOR], [OpenVPN minor version - integer]) +AC_DEFINE([OPENVPN_VERSION_PATCH], ["PRODUCT_VERSION_PATCH"], [OpenVPN patch level - may be a string or integer]) AC_CONFIG_AUX_DIR([.]) AC_CONFIG_HEADERS([config.h]) diff --git a/include/openvpn-plugin.h.in b/include/openvpn-plugin.h.in index ddf32988402..d4bf62277da 100644 --- a/include/openvpn-plugin.h.in +++ b/include/openvpn-plugin.h.in @@ -215,8 +215,11 @@ struct openvpn_plugin_string_list * which identifies the SSL implementation OpenVPN is compiled * against. * + * 3 Added ovpn_version, ovpn_version_major, ovpn_version_minor + * and ovpn_version_patch to provide the runtime version of + * OpenVPN to plug-ins. */ -#define OPENVPN_PLUGINv3_STRUCTVER 2 +#define OPENVPN_PLUGINv3_STRUCTVER 3 /** * Definitions needed for the plug-in callback functions. @@ -311,6 +314,10 @@ struct openvpn_plugin_args_open_in const char ** const envp; struct openvpn_plugin_callbacks *callbacks; const ovpnSSLAPI ssl_api; + const char *ovpn_version; + const unsigned int ovpn_version_major; + const unsigned int ovpn_version_minor; + const char * const ovpn_version_patch; }; diff --git a/sample/sample-plugins/log/log_v3.c b/sample/sample-plugins/log/log_v3.c index bf1a15c82a7..275b1e7a107 100644 --- a/sample/sample-plugins/log/log_v3.c +++ b/sample/sample-plugins/log/log_v3.c @@ -82,6 +82,7 @@ openvpn_plugin_open_v3 (const int v3structver, /* Check that we are API compatible */ if( v3structver != OPENVPN_PLUGINv3_STRUCTVER ) { + printf("log_v3: ** ERROR ** Incompatible plug-in interface between this plug-in and OpenVPN\n"); return OPENVPN_PLUGIN_FUNC_ERROR; } @@ -90,6 +91,11 @@ openvpn_plugin_open_v3 (const int v3structver, return OPENVPN_PLUGIN_FUNC_ERROR; } + /* Print some version information about the OpenVPN process using this plug-in */ + printf("log_v3: OpenVPN %s (Major: %i, Minor: %i, Patch: %s)\n", + args->ovpn_version, args->ovpn_version_major, + args->ovpn_version_minor, args->ovpn_version_patch); + /* Which callbacks to intercept. */ ret->type_mask = OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_UP) | diff --git a/src/openvpn/plugin.c b/src/openvpn/plugin.c index 60dd2ee79b0..9be0b0c5ed7 100644 --- a/src/openvpn/plugin.c +++ b/src/openvpn/plugin.c @@ -27,6 +27,9 @@ #elif defined(_MSC_VER) #include "config-msvc.h" #endif +#ifdef HAVE_CONFIG_VERSION_H +#include "config-version.h" +#endif #include "syshead.h" @@ -347,6 +350,17 @@ static struct openvpn_plugin_callbacks callbacks = { plugin_vlog }; + +/* Provide a wrapper macro for a version patch level string to plug-ins. + * This is located here purely to not make the code too messy with #ifndef + * inside a struct declaration + */ +#ifndef CONFIGURE_GIT_REVISION +# define _OPENVPN_PATCH_LEVEL OPENVPN_VERSION_PATCH +#else +# define _OPENVPN_PATCH_LEVEL "git:" CONFIGURE_GIT_REVISION CONFIGURE_GIT_FLAGS +#endif + static void plugin_open_item (struct plugin *p, const struct plugin_option *o, @@ -375,7 +389,12 @@ plugin_open_item (struct plugin *p, (const char ** const) o->argv, (const char ** const) envp, &callbacks, - SSLAPI }; + SSLAPI, + PACKAGE_VERSION, + OPENVPN_VERSION_MAJOR, + OPENVPN_VERSION_MINOR, + _OPENVPN_PATCH_LEVEL + }; struct openvpn_plugin_args_open_return retargs; CLEAR(retargs); From 0a51c4f152d0f695a6fb8b605dbfefca65e63838 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Mon, 27 Jul 2015 21:59:58 +0200 Subject: [PATCH 069/643] Fix out-of-tree builds; openvpn-plugin.h should be in AC_CONFIG_HEADERS Was broken in commit 9de35d4. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1438027198-23305-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/9964 Signed-off-by: Gert Doering --- configure.ac | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 7bcbb7c2854..51ef93b0b62 100644 --- a/configure.ac +++ b/configure.ac @@ -38,7 +38,7 @@ AC_DEFINE([OPENVPN_VERSION_MINOR], [PRODUCT_VERSION_MINOR], [OpenVPN minor versi AC_DEFINE([OPENVPN_VERSION_PATCH], ["PRODUCT_VERSION_PATCH"], [OpenVPN patch level - may be a string or integer]) AC_CONFIG_AUX_DIR([.]) -AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_HEADERS([config.h include/openvpn-plugin.h]) AC_CONFIG_SRCDIR([src/openvpn/syshead.h]) AC_CONFIG_MACRO_DIR([m4]) @@ -1229,7 +1229,6 @@ AC_CONFIG_FILES([ distro/rpm/Makefile distro/rpm/openvpn.spec include/Makefile - include/openvpn-plugin.h src/Makefile src/compat/Makefile src/openvpn/Makefile From 710c439817522ac8f4dfa7411baa787c5e2e2f89 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Mon, 27 Jul 2015 22:46:50 +0200 Subject: [PATCH 070/643] Fix build on OpenSolaris (non-gmake) Was broken in commit 9de35d4, missing backslash in include/Makefile.am Signed-off-by: Gert Doering Acked-by: Steffan Karger Message-Id: <1438030010-953-1-git-send-email-gert@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/9967 --- include/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/Makefile.am b/include/Makefile.am index 70f20e9098c..c5a91b1fb8c 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -10,7 +10,7 @@ # MAINTAINERCLEANFILES = \ - $(srcdir)/Makefile.in + $(srcdir)/Makefile.in \ $(srcdir)/openvpn-plugin.h.in include_HEADERS = openvpn-plugin.h From cc377dec820f9e6e7e72981013eb3857aa6ea5ce Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Wed, 29 Jul 2015 12:30:26 +0200 Subject: [PATCH 071/643] Fix overflow check in openvpn_decrypt() Sebastian Krahmer from the SuSE security team reported that the buffer overflow check in openvpn_decrypt() was too strict according to the cipher update function contract: "The amount of data written depends on the block alignment of the encrypted data: as a result the amount of data written may be anything from zero bytes to (inl + cipher_block_size - 1) so outl should contain sufficient room." This stems from the way CBC mode works, which caches input and 'flushes' it block-wise to the output buffer. We do allocate enough space for this extra block in the output buffer for CBC mode, but not for CFB/OFB modes. This patch: * updates the overflow check to also verify that the extra block required according to the function contract is available. * uses buf_inc_len() to double-check for overflows during en/decryption. * also reserves the extra block for non-CBC cipher modes. In practice, I could not find a way in which this would fail. The plaintext is never longer than the ciphertext, and the implementations of CBC/OFB/CBC for AES and BF in both OpenSSL and PolarSSL/mbed TLS do not use the buffer beyond the plaintext length when decrypting. However, some funky OpenSSL engine I did not check *might* use the buffer space required by the function contract. So we should still make sure we have enough room anyway. v2 - always ASSERT() on buf_inc_len(). It is a double-check so should really not fail, but if it fails there has been a buffer overflow. At that point the best thing we can do is assert out. (The primary check *is* handled gracefully, and just drops the packet.) Signed-off-by: Steffan Karger Acked-by: Arne Schwabe Message-Id: <1438165826-32762-1-git-send-email-steffan.karger@fox-it.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/9974 Signed-off-by: Gert Doering --- src/openvpn/crypto.c | 19 +++++++++---------- src/openvpn/crypto_backend.h | 2 +- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c index 588d9f05436..1ceb411a4e5 100644 --- a/src/openvpn/crypto.c +++ b/src/openvpn/crypto.c @@ -166,11 +166,11 @@ openvpn_encrypt (struct buffer *buf, struct buffer work, /* Encrypt packet ID, payload */ ASSERT (cipher_ctx_update (ctx->cipher, BPTR (&work), &outlen, BPTR (buf), BLEN (buf))); - work.len += outlen; + ASSERT (buf_inc_len(&work, outlen)); /* Flush the encryption buffer */ - ASSERT(cipher_ctx_final(ctx->cipher, BPTR (&work) + outlen, &outlen)); - work.len += outlen; + ASSERT (cipher_ctx_final(ctx->cipher, BPTR (&work) + outlen, &outlen)); + ASSERT (buf_inc_len(&work, outlen)); /* For all CBC mode ciphers, check the last block is complete */ ASSERT (cipher_kt_mode (cipher_kt) != OPENVPN_MODE_CBC || @@ -305,18 +305,18 @@ openvpn_decrypt (struct buffer *buf, struct buffer work, CRYPT_ERROR ("cipher init failed"); /* Buffer overflow check (should never happen) */ - if (!buf_safe (&work, buf->len)) - CRYPT_ERROR ("buffer overflow"); + if (!buf_safe (&work, buf->len + cipher_ctx_block_size(ctx->cipher))) + CRYPT_ERROR ("potential buffer overflow"); /* Decrypt packet ID, payload */ if (!cipher_ctx_update (ctx->cipher, BPTR (&work), &outlen, BPTR (buf), BLEN (buf))) CRYPT_ERROR ("cipher update failed"); - work.len += outlen; + ASSERT (buf_inc_len(&work, outlen)); /* Flush the decryption buffer */ if (!cipher_ctx_final (ctx->cipher, BPTR (&work) + outlen, &outlen)) CRYPT_ERROR ("cipher final failed"); - work.len += outlen; + ASSERT (buf_inc_len(&work, outlen)); dmsg (D_PACKET_CONTENT, "DECRYPT TO: %s", format_hex (BPTR (&work), BLEN (&work), 80, &gc)); @@ -413,9 +413,8 @@ crypto_adjust_frame_parameters(struct frame *frame, if (use_iv) crypto_overhead += cipher_kt_iv_size (kt->cipher); - if (cipher_kt_mode_cbc (kt->cipher)) - /* worst case padding expansion */ - crypto_overhead += cipher_kt_block_size (kt->cipher); + /* extra block required by cipher_ctx_update() */ + crypto_overhead += cipher_kt_block_size (kt->cipher); } crypto_overhead += kt->hmac_length; diff --git a/src/openvpn/crypto_backend.h b/src/openvpn/crypto_backend.h index 4e45df00a04..4c1ce9fa6aa 100644 --- a/src/openvpn/crypto_backend.h +++ b/src/openvpn/crypto_backend.h @@ -333,7 +333,7 @@ int cipher_ctx_reset (cipher_ctx_t *ctx, uint8_t *iv_buf); * Note that if a complete block cannot be written, data is cached in the * context, and emitted at a later call to \c cipher_ctx_update, or by a call * to \c cipher_ctx_final(). This implies that dst should have enough room for - * src_len + \c cipher_ctx_block_size() - 1. + * src_len + \c cipher_ctx_block_size(). * * @param ctx Cipher's context. May not be NULL. * @param dst Destination buffer From 0ffd744332f51878c4df430ab14aca3126bdfc8a Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Tue, 4 Aug 2015 14:53:16 +0200 Subject: [PATCH 072/643] Un-break --auth-user-pass on windows Commit b131c7b974d9d4d3f0 introduced a check to create a meaningful warning if we try to read a password after daemon()izing (by checking whether stdin or stderr is connected to a tty). For some reason this breaks on Windows builds if run under GUI control - but since Windows doesn't have this particular daemon() issue anyway, just #ifndef WIN32 the offending code. Signed-off-by: Gert Doering Acked-by: Steffan Karger Message-Id: <1438692796-14663-1-git-send-email-gert@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/10000 --- src/openvpn/misc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/openvpn/misc.c b/src/openvpn/misc.c index c4438b6de9a..895e9facf94 100644 --- a/src/openvpn/misc.c +++ b/src/openvpn/misc.c @@ -1056,9 +1056,11 @@ get_user_pass_cr (struct user_pass *up, */ else if (from_stdin) { +#ifndef WIN32 /* did we --daemon'ize before asking for passwords? */ if ( !isatty(0) && !isatty(2) ) { msg(M_FATAL, "neither stdin nor stderr are a tty device, can't ask for %s password. If you used --daemon, you need to use --askpass to make passphrase-protected keys work, and you can not use --auth-nocache.", prefix ); } +#endif #ifdef ENABLE_CLIENT_CR if (auth_challenge && (flags & GET_USER_PASS_DYNAMIC_CHALLENGE)) From 291c227d2ccecaa92602eaa5259a23c7093e30e5 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Thu, 6 Aug 2015 13:17:15 +0200 Subject: [PATCH 073/643] Show extra-certs in current parameters, fix clang warning and logic error in preresolve Closes ticket #591 Acked-by: Gert Doering Message-Id: <1438859835-3977-1-git-send-email-arne@rfc2549.org> URL: http://article.gmane.org/gmane.network.openvpn.devel/10005 Signed-off-by: Gert Doering --- src/openvpn/options.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 9eb8e7648f9..caf1394cb26 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -1582,6 +1582,7 @@ show_settings (const struct options *o) else #endif SHOW_STR (cert_file); + SHOW_STR (extra_certs_file); #ifdef MANAGMENT_EXTERNAL_KEY if((o->management_flags & MF_EXTERNAL_KEY)) @@ -4574,7 +4575,7 @@ add_option (struct options *options, else options->resolve_retry_seconds = positive_atoi (p[1]); } - else if (streq (p[0], "preresolve") || streq (p[0], "ip-remote-hint") && !p[2]) + else if ((streq (p[0], "preresolve") || streq (p[0], "ip-remote-hint")) && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->resolve_in_advance = true; From c3ef2d2333fb73f8a6d460d96523d23f89e56ba2 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Fri, 11 Sep 2015 17:33:38 +0200 Subject: [PATCH 074/643] refactor struct route_ipv6, bring in line with struct route_ipv4 again adjust "struct route_ipv6" (and all users) to reflect changes to "struct route_ipv4" done in commit 7fb0e07e, namely: - new member "r6->flags" - "r6->defined" becomes "r6->flags & RT_DEFINED" - "r6->metric_defined" becomes "r6->flags & RT_METRIC_DEFINED" - route addition status is stored in "r6->flags & RT_ADDED" Signed-off-by: Gert Doering Acked-by: Arne Schwabe Message-Id: <1441985627-14822-2-git-send-email-gert@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/10083 --- src/openvpn/route.c | 35 ++++++++++++++++++----------------- src/openvpn/route.h | 3 +-- src/openvpn/tun.c | 6 ++---- 3 files changed, 21 insertions(+), 23 deletions(-) diff --git a/src/openvpn/route.c b/src/openvpn/route.c index ee7c0def89b..0f916525d73 100644 --- a/src/openvpn/route.c +++ b/src/openvpn/route.c @@ -374,7 +374,7 @@ init_route_ipv6 (struct route_ipv6 *r6, const struct route_ipv6_option *r6o, const struct route_ipv6_list *rl6 ) { - r6->defined = false; + CLEAR (*r6); if ( !get_ipv6_addr( r6o->prefix, &r6->network, &r6->netbits, NULL, M_WARN )) goto fail; @@ -399,7 +399,6 @@ init_route_ipv6 (struct route_ipv6 *r6, /* metric */ - r6->metric_defined = false; r6->metric = -1; if (is_route_parm_defined (r6o->metric)) { @@ -411,22 +410,21 @@ init_route_ipv6 (struct route_ipv6 *r6, r6o->metric); goto fail; } - r6->metric_defined = true; + r6->flags |= RT_METRIC_DEFINED; } else if (rl6->default_metric_defined) { r6->metric = rl6->default_metric; - r6->metric_defined = true; + r6->flags |= RT_METRIC_DEFINED; } - r6->defined = true; + r6->flags |= RT_DEFINED; return true; fail: msg (M_WARN, PACKAGE_NAME " ROUTE: failed to parse/resolve route for host/network: %s", r6o->prefix); - r6->defined = false; return false; } @@ -1168,7 +1166,7 @@ static void setenv_route_ipv6 (struct env_set *es, const struct route_ipv6 *r6, int i) { struct gc_arena gc = gc_new (); - if (r6->defined) + if (r6->flags & RT_DEFINED) { struct buffer name1 = alloc_buf_gc( 256, &gc ); struct buffer val = alloc_buf_gc( 256, &gc ); @@ -1545,7 +1543,7 @@ add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int fla bool gateway_needed = false; - if (!r6->defined) + if (! (r6->flags & RT_DEFINED) ) return; gc_init (&gc); @@ -1576,7 +1574,7 @@ add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int fla * gateway unless the route is to be an on-link network */ if ( tt->type == DEV_TYPE_TAP && - !(r6->metric_defined && r6->metric == 0 ) ) + !( (r6->flags & RT_METRIC_DEFINED) && r6->metric == 0 ) ) { gateway_needed = true; } @@ -1590,7 +1588,7 @@ add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int fla device); if (gateway_needed) argv_printf_cat (&argv, "via %s", gateway); - if (r6->metric_defined && r6->metric > 0 ) + if ( (r6->flags & RT_METRIC_DEFINED) && r6->metric > 0 ) argv_printf_cat (&argv, " metric %d", r6->metric); #else @@ -1601,7 +1599,7 @@ add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int fla device); if (gateway_needed) argv_printf_cat (&argv, "gw %s", gateway); - if (r6->metric_defined && r6->metric > 0 ) + if ( (r6->flags & RT_METRIC_DEFINED) && r6->metric > 0 ) argv_printf_cat (&argv, " metric %d", r6->metric); #endif /*ENABLE_IPROUTE*/ argv_msg (D_ROUTE, &argv); @@ -1635,7 +1633,7 @@ add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int fla argv_printf_cat( &argv, " %s", gateway ); #if 0 - if (r->metric_defined) + if (r6->flags & RT_METRIC_DEFINED) argv_printf_cat (&argv, " METRIC %d", r->metric); #endif @@ -1727,7 +1725,10 @@ add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int fla msg (M_FATAL, "Sorry, but I don't know how to do 'route ipv6' commands on this operating system. Try putting your routes in a --route-up script"); #endif - r6->defined = status; + if (status) + r6->flags |= RT_ADDED; + else + r6->flags &= ~RT_ADDED; argv_reset (&argv); gc_free (&gc); } @@ -1916,7 +1917,7 @@ delete_route_ipv6 (const struct route_ipv6 *r6, const struct tuntap *tt, unsigne const char *device = tt->actual_name; bool gateway_needed = false; - if (!r6->defined) + if ((r6->flags & (RT_DEFINED|RT_ADDED)) != (RT_DEFINED|RT_ADDED)) return; gc_init (&gc); @@ -1938,7 +1939,7 @@ delete_route_ipv6 (const struct route_ipv6 *r6, const struct tuntap *tt, unsigne * delete, otherwise some OSes will refuse to delete the route */ if ( tt->type == DEV_TYPE_TAP && - !(r6->metric_defined && r6->metric == 0 ) ) + !( (r6->flags & RT_METRIC_DEFINED) && r6->metric == 0 ) ) { gateway_needed = true; } @@ -1961,7 +1962,7 @@ delete_route_ipv6 (const struct route_ipv6 *r6, const struct tuntap *tt, unsigne device); if (gateway_needed) argv_printf_cat (&argv, "gw %s", gateway); - if (r6->metric_defined && r6->metric > 0 ) + if ( (r6->flags & RT_METRIC_DEFINED) && r6->metric > 0 ) argv_printf_cat (&argv, " metric %d", r6->metric); #endif /*ENABLE_IPROUTE*/ argv_msg (D_ROUTE, &argv); @@ -1989,7 +1990,7 @@ delete_route_ipv6 (const struct route_ipv6 *r6, const struct tuntap *tt, unsigne argv_printf_cat( &argv, " %s", gateway ); #if 0 - if (r->metric_defined) + if (r6->flags & RT_METRIC_DEFINED) argv_printf_cat (&argv, "METRIC %d", r->metric); #endif diff --git a/src/openvpn/route.h b/src/openvpn/route.h index 3cec08dfb35..13882a4e35d 100644 --- a/src/openvpn/route.h +++ b/src/openvpn/route.h @@ -123,11 +123,10 @@ struct route_ipv4 { struct route_ipv6 { struct route_ipv6 *next; - bool defined; + unsigned int flags; /* RT_ flags, see route_ipv4 */ struct in6_addr network; unsigned int netbits; struct in6_addr gateway; - bool metric_defined; int metric; }; diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index 13e38267307..766a73c6e4a 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -607,12 +607,11 @@ void add_route_connected_v6_net(struct tuntap * tt, { struct route_ipv6 r6; - r6.defined = true; r6.network = tt->local_ipv6; r6.netbits = tt->netbits_ipv6; r6.gateway = tt->local_ipv6; r6.metric = 0; /* connected route */ - r6.metric_defined = true; + r6.flags = RT_DEFINED | RT_METRIC_DEFINED; add_route_ipv6 (&r6, tt, 0, es); } @@ -621,12 +620,11 @@ void delete_route_connected_v6_net(struct tuntap * tt, { struct route_ipv6 r6; - r6.defined = true; r6.network = tt->local_ipv6; r6.netbits = tt->netbits_ipv6; r6.gateway = tt->local_ipv6; r6.metric = 0; /* connected route */ - r6.metric_defined = true; + r6.flags = RT_DEFINED | RT_ADDED | RT_METRIC_DEFINED; delete_route_ipv6 (&r6, tt, 0, es); } #endif From 0ad73859420379ec45e159e5e7bd5bb7be9382fe Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Fri, 11 Sep 2015 17:33:39 +0200 Subject: [PATCH 075/643] refactor struct route_ipv6_list, bring in line with struct route_list again adjust "struct route_ipv6_list" (and all users) to reflect changes to "struct route_list" done in commit 7fb0e07e, namely: - new member "rl6->iflags" (RL_* flags) - new member "rl6->spec_flags" (RTSA_* flags) - new member "rl6->remote_host_ipv6" (--remote address we're talking to) - "rl6->routes_added" --> "rl6->iflags & RL_ROUTES_ADDED" - "rl6->did_redirect_default_gateway" --> "rl6->iflags & RL_DID_REDIRECT_DEFAULT_GATEWAY" - "rl6->did_local" --> "rl6->iflags & RL_DID_LOCAL" - "rl6->remote_endpoint_defined" --> "rl6->spec_flags & RTSA_REMOTE_ENDPOINT" - "rl6->default_metric_defined" --> "rl6->spec_flags & RTSA_DEFAULT_METRIC" deviating from IPv4 route_list, there is no "route_special_addr spec" sub-struct, because it's not considered useful (rl->spec.flags becomes rl6->spec_flags, the IPv6 equivalent of everything else in rl->spec just lives inside struct route_ipv6_list) Signed-off-by: Gert Doering Acked-by: Arne Schwabe Message-Id: <1441985627-14822-3-git-send-email-gert@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/10084 --- src/openvpn/route.c | 19 ++++++++----------- src/openvpn/route.h | 16 ++++++++-------- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/src/openvpn/route.c b/src/openvpn/route.c index 0f916525d73..6b2af3c6f66 100644 --- a/src/openvpn/route.c +++ b/src/openvpn/route.c @@ -387,7 +387,7 @@ init_route_ipv6 (struct route_ipv6 *r6, msg( M_WARN, PACKAGE_NAME "ROUTE6: cannot parse gateway spec '%s'", r6o->gateway ); } } - else if (rl6->remote_endpoint_defined) + else if (rl6->spec_flags & RTSA_REMOTE_ENDPOINT) { r6->gateway = rl6->remote_endpoint_ipv6; } @@ -412,7 +412,7 @@ init_route_ipv6 (struct route_ipv6 *r6, } r6->flags |= RT_METRIC_DEFINED; } - else if (rl6->default_metric_defined) + else if (rl6->spec_flags & RTSA_DEFAULT_METRIC) { r6->metric = rl6->default_metric; r6->flags |= RT_METRIC_DEFINED; @@ -671,7 +671,7 @@ init_route_ipv6_list (struct route_ipv6_list *rl6, if (default_metric >= 0 ) { rl6->default_metric = default_metric; - rl6->default_metric_defined = true; + rl6->spec_flags |= RTSA_DEFAULT_METRIC; } /* "default_gateway" is stuff for "redirect-gateway", which we don't @@ -686,7 +686,7 @@ init_route_ipv6_list (struct route_ipv6_list *rl6, if ( inet_pton( AF_INET6, remote_endpoint, &rl6->remote_endpoint_ipv6) == 1 ) { - rl6->remote_endpoint_defined = true; + rl6->spec_flags |= RTSA_REMOTE_ENDPOINT; } else { @@ -694,9 +694,6 @@ init_route_ipv6_list (struct route_ipv6_list *rl6, ret = false; } } - else - rl6->remote_endpoint_defined = false; - /* parse the routes from opt6 to rl6 */ { @@ -1003,7 +1000,7 @@ add_routes (struct route_list *rl, struct route_ipv6_list *rl6, const struct tun } rl->iflags |= RL_ROUTES_ADDED; } - if (rl6 && !rl6->routes_added) + if (rl6 && !(rl6->iflags & RL_ROUTES_ADDED) ) { struct route_ipv6 *r; for (r = rl6->routes_ipv6; r; r = r->next) @@ -1012,7 +1009,7 @@ add_routes (struct route_list *rl, struct route_ipv6_list *rl6, const struct tun delete_route_ipv6 (r, tt, flags, es); add_route_ipv6 (r, tt, flags, es); } - rl6->routes_added = true; + rl6->iflags |= RL_ROUTES_ADDED; } } @@ -1037,14 +1034,14 @@ delete_routes (struct route_list *rl, struct route_ipv6_list *rl6, clear_route_list (rl); } - if ( rl6 && rl6->routes_added ) + if ( rl6 && (rl6->iflags & RL_ROUTES_ADDED) ) { struct route_ipv6 *r6; for (r6 = rl6->routes_ipv6; r6; r6 = r6->next) { delete_route_ipv6 (r6, tt, flags, es); } - rl6->routes_added = false; + rl6->iflags &= ~RL_ROUTES_ADDED; } if ( rl6 ) diff --git a/src/openvpn/route.h b/src/openvpn/route.h index 13882a4e35d..7e96a2fe407 100644 --- a/src/openvpn/route.h +++ b/src/openvpn/route.h @@ -103,7 +103,7 @@ struct route_ipv6_option { }; struct route_ipv6_option_list { - unsigned int flags; + unsigned int flags; /* RG_x flags, see route_option-list */ struct route_ipv6_option *routes_ipv6; struct gc_arena *gc; }; @@ -131,14 +131,14 @@ struct route_ipv6 { }; struct route_ipv6_list { - bool routes_added; - unsigned int flags; + unsigned int iflags; /* RL_ flags, see route_list */ + + unsigned int spec_flags; /* RTSA_ flags, route_special_addr */ + struct in6_addr remote_endpoint_ipv6; /* inside tun */ + struct in6_addr remote_host_ipv6; /* --remote address */ int default_metric; - bool default_metric_defined; - struct in6_addr remote_endpoint_ipv6; - bool remote_endpoint_defined; - bool did_redirect_default_gateway; /* TODO (?) */ - bool did_local; /* TODO (?) */ + + unsigned int flags; /* RG_x flags, see route_option_list */ struct route_ipv6 *routes_ipv6; struct gc_arena gc; }; From c0da18cd7cca481fd918620331540e565f11ce23 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Fri, 11 Sep 2015 17:33:40 +0200 Subject: [PATCH 076/643] Add route_ipv6_gateway* data structures for rgi6 support. route_gateway_address -> route_ipv6_gateway_address route_gateway_info -> route_ipv6_gateway_info Signed-off-by: Gert Doering Acked-by: Arne Schwabe Message-Id: <1441985627-14822-4-git-send-email-gert@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/10088 --- src/openvpn/route.h | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/openvpn/route.h b/src/openvpn/route.h index 7e96a2fe407..5ab5f98b5df 100644 --- a/src/openvpn/route.h +++ b/src/openvpn/route.h @@ -177,6 +177,34 @@ struct route_gateway_info { struct route_gateway_address addrs[RGI_N_ADDRESSES]; /* local addresses attached to iface */ }; +struct route_ipv6_gateway_address { + struct in6_addr addr_ipv6; + int netbits_ipv6; +}; + +struct route_ipv6_gateway_info { +/* RGI_ flags used as in route_gateway_info */ + unsigned int flags; + + /* gateway interface */ +# ifdef WIN32 + DWORD adapter_index; /* interface or ~0 if undefined */ +#else + char iface[16]; /* interface name (null terminated), may be empty */ +#endif + + /* gateway interface hardware address */ + uint8_t hwaddr[6]; + + /* gateway/router address */ + struct route_ipv6_gateway_address gateway; + + /* address/netmask pairs bound to interface */ +# define RGI_N_ADDRESSES 8 + int n_addrs; /* len of addrs, may be 0 */ + struct route_ipv6_gateway_address addrs[RGI_N_ADDRESSES]; /* local addresses attached to iface */ +}; + struct route_list { # define RL_DID_REDIRECT_DEFAULT_GATEWAY (1<<0) # define RL_DID_LOCAL (1<<1) From d8a8656f1a8721f56a08439afe24916beadfef55 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Fri, 11 Sep 2015 17:33:41 +0200 Subject: [PATCH 077/643] Create basic infrastructure for IPv6 default gateway handling / redirection. - introduce get_default_gateway_ipv6() and add stub functions with the implementation plan to the 4 major code blocks here (Windows, Linux/Android, *BSD and Solaris, "others") - add &rgi6 to print_default_gateway(), and teach it to print v4, v6 or both, depending on the calling environment - unlike IPv4 (today), get_default_gateway_ipv6() is passed the actual target IPv6 address of the server we're looking for, so we can handle more complicated routing setups ("default to eth0, vpn server to ppp0") correctly - consequently, --show-gateway has an optional parameter now, the IPv6 address to look up (for debugging) - document --show-gateway and the extra option in openvpn.8 Acked-by: Arne Schwabe Message-Id: <1441985627-14822-5-git-send-email-gert@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/10087 Signed-off-by: Gert Doering --- doc/openvpn.8 | 9 +++++ src/openvpn/init.c | 4 ++- src/openvpn/options.c | 9 +++-- src/openvpn/route.c | 76 +++++++++++++++++++++++++++++++++++++++++-- src/openvpn/route.h | 6 +++- 5 files changed, 97 insertions(+), 7 deletions(-) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 0692a801750..3a0d4e0dbcf 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -5616,6 +5616,15 @@ module will be queried. .B \-\-verb option can be used BEFORE this option to produce debugging information. .\"********************************************************* +.SS Standalone Debug Options: +.\"********************************************************* +.TP +.B \-\-show\-gateway [v6target] +(Standalone) +Show current IPv4 and IPv6 default gateway and interface towards the +gateway (if the protocol in question is enabled). If an IPv6 address +is passed as argument, the IPv6 route for this host is reported. +.\"********************************************************* .SS IPv6 Related Options .\"********************************************************* The following options exist to support IPv6 tunneling in peer-to-peer diff --git a/src/openvpn/init.c b/src/openvpn/init.c index fe0091865bf..4c17905abb0 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -639,8 +639,10 @@ init_static (void) #ifdef TEST_GET_DEFAULT_GATEWAY { struct route_gateway_info rgi; + struct route_ipv6_gateway_info rgi6; get_default_gateway(&rgi); - print_default_gateway(M_INFO, &rgi); + get_default_gateway_ipv6(&rgi6, NULL); + print_default_gateway(M_INFO, &rgi, &rgi6); return false; } #endif diff --git a/src/openvpn/options.c b/src/openvpn/options.c index caf1394cb26..93ea4154186 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -4156,12 +4156,17 @@ add_option (struct options *options, read_config_file (options, p[1], level, file, line, msglevel, permission_mask, option_types_found, es); } #if defined(ENABLE_DEBUG) && !defined(ENABLE_SMALL) - else if (streq (p[0], "show-gateway") && !p[1]) + else if (streq (p[0], "show-gateway") && !p[2]) { struct route_gateway_info rgi; + struct route_ipv6_gateway_info rgi6; + struct in6_addr remote = IN6ADDR_ANY_INIT; VERIFY_PERMISSION (OPT_P_GENERAL); + if (p[1]) + get_ipv6_addr (p[1], &remote, NULL, NULL, M_WARN); get_default_gateway(&rgi); - print_default_gateway(M_INFO, &rgi); + get_default_gateway_ipv6(&rgi6, &remote); + print_default_gateway(M_INFO, &rgi, &rgi6); openvpn_exit (OPENVPN_EXIT_STATUS_GOOD); /* exit point */ } #endif diff --git a/src/openvpn/route.c b/src/openvpn/route.c index 6b2af3c6f66..3e161404c8c 100644 --- a/src/openvpn/route.c +++ b/src/openvpn/route.c @@ -578,7 +578,7 @@ init_route_list (struct route_list *rl, { setenv_route_addr (es, "net_gateway", rl->rgi.gateway.addr, -1); #if defined(ENABLE_DEBUG) && !defined(ENABLE_SMALL) - print_default_gateway (D_ROUTE, &rl->rgi); + print_default_gateway (D_ROUTE, &rl->rgi, NULL); #endif } else @@ -1084,10 +1084,12 @@ print_route_options (const struct route_option_list *rol, } void -print_default_gateway(const int msglevel, const struct route_gateway_info *rgi) +print_default_gateway(const int msglevel, + const struct route_gateway_info *rgi, + const struct route_ipv6_gateway_info *rgi6) { struct gc_arena gc = gc_new (); - if (rgi->flags & RGI_ADDR_DEFINED) + if (rgi && (rgi->flags & RGI_ADDR_DEFINED)) { struct buffer out = alloc_buf_gc (256, &gc); buf_printf (&out, "ROUTE_GATEWAY"); @@ -1108,6 +1110,28 @@ print_default_gateway(const int msglevel, const struct route_gateway_info *rgi) buf_printf (&out, " HWADDR=%s", format_hex_ex (rgi->hwaddr, 6, 0, 1, ":", &gc)); msg (msglevel, "%s", BSTR (&out)); } + + if (rgi6 && (rgi6->flags & RGI_ADDR_DEFINED)) + { + struct buffer out = alloc_buf_gc (256, &gc); + buf_printf (&out, "ROUTE6_GATEWAY"); + if (rgi6->flags & RGI_ON_LINK) + buf_printf (&out, " ON_LINK"); + else + buf_printf (&out, " %s", print_in6_addr (rgi6->gateway.addr_ipv6, 0, &gc)); + if (rgi6->flags & RGI_NETMASK_DEFINED) + buf_printf (&out, "/%d", rgi6->gateway.netbits_ipv6); +#ifdef WIN32 + if (rgi6->flags & RGI_IFACE_DEFINED) + buf_printf (&out, " I=%u", (unsigned int)rgi6->adapter_index); +#else + if (rgi6->flags & RGI_IFACE_DEFINED) + buf_printf (&out, " IFACE=%s", rgi6->iface); +#endif + if (rgi6->flags & RGI_HWADDR_DEFINED) + buf_printf (&out, " HWADDR=%s", format_hex_ex (rgi6->hwaddr, 6, 0, 1, ":", &gc)); + msg (msglevel, "%s", BSTR (&out)); + } gc_free (&gc); } @@ -2308,6 +2332,17 @@ windows_route_find_if_index (const struct route_ipv4 *r, const struct tuntap *tt return ret; } +/* IPv6 implementation using GetIpForwardTable2() and dynamic linking (TBD) + * https://msdn.microsoft.com/en-us/library/windows/desktop/aa814416(v=vs.85).aspx + */ +void +get_default_gateway_ipv6(struct route_ipv6_gateway_info *rgi6, + struct in6_addr *dest) +{ + msg(D_ROUTE, "no support for get_default_gateway_ipv6() on this system (windows)"); + CLEAR(*rgi6); +} + bool add_route_ipapi (const struct route_ipv4 *r, const struct tuntap *tt, DWORD adapter_index) { @@ -2624,6 +2659,24 @@ get_default_gateway (struct route_gateway_info *rgi) gc_free (&gc); } +/* IPv6 implementation using netlink (TBD) + */ +void +get_default_gateway_ipv6(struct route_ipv6_gateway_info *rgi6, + struct in6_addr *dest) +{ + msg(D_ROUTE, "no support for get_default_gateway_ipv6() on this system (Linux and Android)"); + CLEAR(*rgi6); + struct in6_addr g = IN6ADDR_LOOPBACK_INIT; + + rgi6->flags = RGI_ADDR_DEFINED | RGI_IFACE_DEFINED | RGI_HWADDR_DEFINED | + RGI_NETMASK_DEFINED; + rgi6->gateway.addr_ipv6 = g; + rgi6->gateway.netbits_ipv6 = 64; + memcpy( rgi6->hwaddr, "\1\2\3\4\5\6", 6 ); + strcpy( rgi6->iface, "eth1" ); +} + #elif defined(TARGET_DARWIN) || defined(TARGET_SOLARIS) || \ defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY) || \ defined(TARGET_OPENBSD) || defined(TARGET_NETBSD) @@ -2866,6 +2919,16 @@ get_default_gateway (struct route_gateway_info *rgi) gc_free (&gc); } +/* BSD implementation using routing socket (as does IPv4) (TBD) + */ +void +get_default_gateway_ipv6(struct route_ipv6_gateway_info *rgi6, + struct in6_addr *dest) +{ + msg(D_ROUTE, "no support for get_default_gateway_ipv6() on this system (BSD and OSX)"); + CLEAR(*rgi6); +} + #undef max #else @@ -2899,6 +2962,13 @@ get_default_gateway (struct route_gateway_info *rgi) { CLEAR(*rgi); } +void +get_default_gateway_ipv6(struct route_ipv6_gateway_info *rgi6, + struct in6_addr *dest) +{ + msg(D_ROUTE, "no support for get_default_gateway_ipv6() on this system"); + CLEAR(*rgi6); +} #endif diff --git a/src/openvpn/route.h b/src/openvpn/route.h index 5ab5f98b5df..95cf99f9301 100644 --- a/src/openvpn/route.h +++ b/src/openvpn/route.h @@ -300,7 +300,11 @@ void setenv_routes_ipv6 (struct env_set *es, const struct route_ipv6_list *rl6); bool is_special_addr (const char *addr_str); void get_default_gateway (struct route_gateway_info *rgi); -void print_default_gateway(const int msglevel, const struct route_gateway_info *rgi); +void get_default_gateway_ipv6 (struct route_ipv6_gateway_info *rgi, + struct in6_addr *dest); +void print_default_gateway(const int msglevel, + const struct route_gateway_info *rgi, + const struct route_ipv6_gateway_info *rgi6); /* * Test if addr is reachable via a local interface (return ILA_LOCAL), From 1d11134feee33689904ded0c6a0108e865d17d7e Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Tue, 15 Sep 2015 11:23:38 +0200 Subject: [PATCH 078/643] Remove unused function h_errno_msg Acked-by: Gert Doering Message-Id: <1442309019-7586-8-git-send-email-arne@rfc2549.org> URL: http://article.gmane.org/gmane.network.openvpn.devel/10108 Signed-off-by: Gert Doering --- src/openvpn/socket.c | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c index 7f889b1fecb..20edf41a79f 100644 --- a/src/openvpn/socket.c +++ b/src/openvpn/socket.c @@ -71,23 +71,6 @@ sf2gaf(const unsigned int getaddr_flags, * Functions related to the translation of DNS names to IP addresses. */ -static const char* -h_errno_msg(int h_errno_err) -{ - switch (h_errno_err) - { - case HOST_NOT_FOUND: - return "[HOST_NOT_FOUND] The specified host is unknown."; - case NO_DATA: - return "[NO_DATA] The requested name is valid but does not have an IP address."; - case NO_RECOVERY: - return "[NO_RECOVERY] A non-recoverable name server error occurred."; - case TRY_AGAIN: - return "[TRY_AGAIN] A temporary error occurred on an authoritative name server."; - } - return "[unknown h_errno value]"; -} - /* * Translate IP addr or hostname to in_addr_t. * If resolve error, try again for From 300039789b23216f1733890063cef3120722f4cf Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Tue, 15 Sep 2015 11:23:32 +0200 Subject: [PATCH 079/643] Add support for requesting the fd again to rebind to the next interface. This not done via android_control since calling management from management leads to an infinitive loop Acked-by: Gert Doering Message-Id: <1442309019-7586-2-git-send-email-arne@rfc2549.org> URL: http://article.gmane.org/gmane.network.openvpn.devel/10110 Signed-off-by: Gert Doering --- src/openvpn/init.c | 34 ++++++++++++++++++++++++++++++++++ src/openvpn/manage.c | 26 ++++++++++++++++++++++++++ src/openvpn/manage.h | 3 +++ 3 files changed, 63 insertions(+) diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 4c17905abb0..b6cfecee1fd 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -3160,6 +3160,37 @@ management_show_net_callback (void *arg, const int msglevel) #endif } +#ifdef TARGET_ANDROID +int +management_callback_network_change (void *arg) +{ + /* Check if the client should translate the network change to a SIGUSR1 to + reestablish the connection or just reprotect the socket + + At the moment just assume that, for all settings that use pull (not + --static) and are not using peer-id reestablishing the connection is + required + + The function returns -1 on invalid fd and -2 if the socket cannot be + reused. On the -2 return value the man_network_change function triggers + a SIGUSR1 to force a reconnect. + */ + + int socketfd=-1; + struct context *c = (struct context *) arg; + if (!c->c2.link_socket) + return -1; + if (c->c2.link_socket->sd == SOCKET_UNDEFINED) + return -1; + + socketfd = c->c2.link_socket->sd; + if (!c->options.pull || c->c2.tls_multi->use_peer_id) + return socketfd; + else + return -2; +} +#endif + #endif void @@ -3175,6 +3206,9 @@ init_management_callback_p2p (struct context *c) cb.show_net = management_show_net_callback; cb.proxy_cmd = management_callback_proxy_cmd; cb.remote_cmd = management_callback_remote_cmd; +#ifdef TARGET_ANDROID + cb.network_change = management_callback_network_change; +#endif management_set_callback (management, &cb); } #endif diff --git a/src/openvpn/manage.c b/src/openvpn/manage.c index 4f0945ca5c6..af4aa44f207 100644 --- a/src/openvpn/manage.c +++ b/src/openvpn/manage.c @@ -1127,6 +1127,26 @@ man_remote (struct management *man, const char **p) } } +#ifdef TARGET_ANDROID +static void +man_network_change (struct management *man) +{ + /* Called to signal the OpenVPN that the network configuration has changed and + the client should either float or reconnect. + + The code is currently only used by ics-openvpn + */ + if (man->persist.callback.network_change) + { + int fd = (*man->persist.callback.network_change)(man->persist.callback.arg); + man->connection.fdtosend = fd; + msg (M_CLIENT, "PROTECTFD: fd '%d' sent to be protected", fd); + if (fd == -2) + man_signal (man, "SIGUSR1"); + } +} +#endif + static void man_dispatch_command (struct management *man, struct status_output *so, const char **p, const int nparms) { @@ -1170,6 +1190,12 @@ man_dispatch_command (struct management *man, struct status_output *so, const ch if (man_need (man, p, 1, 0)) man_signal (man, p[1]); } +#ifdef TARGET_ANDROID + else if (streq (p[0], "network-change")) + { + man_network_change(man); + } +#endif else if (streq (p[0], "load-stats")) { man_load_stats (man); diff --git a/src/openvpn/manage.h b/src/openvpn/manage.h index 8d6e87efa06..73183777a77 100644 --- a/src/openvpn/manage.h +++ b/src/openvpn/manage.h @@ -173,6 +173,9 @@ struct management_callback #endif bool (*proxy_cmd) (void *arg, const char **p); bool (*remote_cmd) (void *arg, const char **p); +#ifdef TARGET_ANDROID + int (*network_change) (void *arg); +#endif }; /* From ad80d6779488e77bc81f395f61d4052184f9a589 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Tue, 15 Sep 2015 11:23:34 +0200 Subject: [PATCH 080/643] Don't redirect the gateway on Android even if requested Routing loops are avoided using the VPNService API Acked-by: Gert Doering Message-Id: <1442309019-7586-4-git-send-email-arne@rfc2549.org> URL: http://article.gmane.org/gmane.network.openvpn.devel/10113 Signed-off-by: Gert Doering --- src/openvpn/route.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/openvpn/route.c b/src/openvpn/route.c index 3e161404c8c..d7d2eeea22f 100644 --- a/src/openvpn/route.c +++ b/src/openvpn/route.c @@ -528,8 +528,10 @@ add_block_local (struct route_list *rl) { size_t i; +#ifndef TARGET_ANDROID /* add bypass for gateway addr */ add_bypass_address (&rl->spec.bypass, rl->rgi.gateway.addr); +#endif /* block access to local subnet */ add_block_local_item (rl, &rl->rgi.gateway, rl->spec.remote_endpoint); @@ -817,6 +819,7 @@ redirect_default_route_to_vpn (struct route_list *rl, const struct tuntap *tt, u } else { +#ifndef TARGET_ANDROID bool local = BOOL_CAST(rl->flags & RG_LOCAL); if (rl->flags & RG_AUTO_LOCAL) { const int tla = rl->spec.remote_host_local; @@ -849,6 +852,7 @@ redirect_default_route_to_vpn (struct route_list *rl, const struct tuntap *tt, u dmsg (D_ROUTE, "ROUTE remote_host protocol differs from tunneled"); } } +#endif /* route DHCP/DNS server traffic through original default gateway */ add_bypass_routes (&rl->spec.bypass, rl->rgi.gateway.addr, tt, flags, &rl->rgi, es); From acd487d0f3597e67f451aa23b73ad03dc19842b0 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Tue, 15 Sep 2015 11:23:36 +0200 Subject: [PATCH 081/643] Fix loglevel of protect socket message Acked-by: Gert Doering Message-Id: <1442309019-7586-6-git-send-email-arne@rfc2549.org> URL: http://article.gmane.org/gmane.network.openvpn.devel/10112 Signed-off-by: Gert Doering --- src/openvpn/socket.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c index 20edf41a79f..57d5962e4f0 100644 --- a/src/openvpn/socket.c +++ b/src/openvpn/socket.c @@ -881,11 +881,11 @@ static void protect_fd_nonlocal (int fd, const struct sockaddr* addr) * as "protected socket" (exempt from being routed into tunnel) */ if (addr_local (addr)) { - msg(M_DEBUG, "Address is local, not protecting socket fd %d", fd); + msg(D_SOCKET_DEBUG, "Address is local, not protecting socket fd %d", fd); return; } - msg(M_DEBUG, "Protecting socket fd %d", fd); + msg(D_SOCKET_DEBUG, "Protecting socket fd %d", fd); management->connection.fdtosend = fd; management_android_control (management, "PROTECTFD", __func__); } From d967ec289df5c5196f68a3708a9f36a5ba354833 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Tue, 15 Sep 2015 11:23:37 +0200 Subject: [PATCH 082/643] Extend network-change command to allow reprotecting on the same network (for short connection losses) Acked-by: Gert Doering Message-Id: <1442309019-7586-7-git-send-email-arne@rfc2549.org> URL: http://article.gmane.org/gmane.network.openvpn.devel/10106 Signed-off-by: Gert Doering --- src/openvpn/init.c | 6 +++--- src/openvpn/manage.c | 11 ++++++++--- src/openvpn/manage.h | 2 +- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/openvpn/init.c b/src/openvpn/init.c index b6cfecee1fd..48542c9c394 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -3162,14 +3162,14 @@ management_show_net_callback (void *arg, const int msglevel) #ifdef TARGET_ANDROID int -management_callback_network_change (void *arg) +management_callback_network_change (void *arg, bool samenetwork) { /* Check if the client should translate the network change to a SIGUSR1 to reestablish the connection or just reprotect the socket At the moment just assume that, for all settings that use pull (not --static) and are not using peer-id reestablishing the connection is - required + required (unless the network is the same) The function returns -1 on invalid fd and -2 if the socket cannot be reused. On the -2 return value the man_network_change function triggers @@ -3184,7 +3184,7 @@ management_callback_network_change (void *arg) return -1; socketfd = c->c2.link_socket->sd; - if (!c->options.pull || c->c2.tls_multi->use_peer_id) + if (!c->options.pull || c->c2.tls_multi->use_peer_id || samenetwork) return socketfd; else return -2; diff --git a/src/openvpn/manage.c b/src/openvpn/manage.c index af4aa44f207..d02dac9c6ac 100644 --- a/src/openvpn/manage.c +++ b/src/openvpn/manage.c @@ -1129,7 +1129,7 @@ man_remote (struct management *man, const char **p) #ifdef TARGET_ANDROID static void -man_network_change (struct management *man) +man_network_change (struct management *man, bool samenetwork) { /* Called to signal the OpenVPN that the network configuration has changed and the client should either float or reconnect. @@ -1138,7 +1138,8 @@ man_network_change (struct management *man) */ if (man->persist.callback.network_change) { - int fd = (*man->persist.callback.network_change)(man->persist.callback.arg); + int fd = (*man->persist.callback.network_change) + (man->persist.callback.arg, samenetwork); man->connection.fdtosend = fd; msg (M_CLIENT, "PROTECTFD: fd '%d' sent to be protected", fd); if (fd == -2) @@ -1193,7 +1194,11 @@ man_dispatch_command (struct management *man, struct status_output *so, const ch #ifdef TARGET_ANDROID else if (streq (p[0], "network-change")) { - man_network_change(man); + bool samenetwork = false; + if (p[1] && streq(p[1], "samenetwork")) + samenetwork = true; + + man_network_change(man, samenetwork); } #endif else if (streq (p[0], "load-stats")) diff --git a/src/openvpn/manage.h b/src/openvpn/manage.h index 73183777a77..a97e8a23458 100644 --- a/src/openvpn/manage.h +++ b/src/openvpn/manage.h @@ -174,7 +174,7 @@ struct management_callback bool (*proxy_cmd) (void *arg, const char **p); bool (*remote_cmd) (void *arg, const char **p); #ifdef TARGET_ANDROID - int (*network_change) (void *arg); + int (*network_change) (void *arg, bool samenetwork); #endif }; From 429f0560e3a908ffa00f18ba1a81af03ba05751e Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Tue, 15 Sep 2015 11:23:35 +0200 Subject: [PATCH 083/643] Use pseudo gw as default gw on Android as a workaround for not being able to read /proc/net/route Acked-by: Gert Doering Message-Id: <1442309019-7586-5-git-send-email-arne@rfc2549.org> URL: http://article.gmane.org/gmane.network.openvpn.devel/10111 Signed-off-by: Gert Doering --- src/openvpn/route.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/openvpn/route.c b/src/openvpn/route.c index d7d2eeea22f..baa4a232b3a 100644 --- a/src/openvpn/route.c +++ b/src/openvpn/route.c @@ -2509,6 +2509,7 @@ get_default_gateway (struct route_gateway_info *rgi) CLEAR(*rgi); +#ifndef TARGET_ANDROID /* get default gateway IP addr */ { FILE *fp = fopen ("/proc/net/route", "r"); @@ -2565,6 +2566,19 @@ get_default_gateway (struct route_gateway_info *rgi) } } } +#else + /* Android, set some pseudo GW, addr is in host byte order, + * Determining the default GW on Android 5.0+ is non trivial + * and serves almost no purpose since OpenVPN only uses the + * default GW address to add routes for networks that should + * NOT be routed over the VPN. Using a well known address + * (127.'d'.'g'.'w') for the default GW make detecting + * these routes easier from the controlling app. + */ + rgi->gateway.addr = 127 << 24 | 'd' << 16 | 'g' << 8 | 'w'; + rgi->flags |= RGI_ADDR_DEFINED; + strcpy(best_name, "android-gw"); +#endif /* scan adapter list */ if (rgi->flags & RGI_ADDR_DEFINED) From 8db23a57c878abd5b01c784c7db570176de555ef Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Tue, 15 Sep 2015 11:23:33 +0200 Subject: [PATCH 084/643] Remove #ifdefs for client nat support. The client-nat feature was always unconditionally enabled Acked-by: Gert Doering Message-Id: <1442309019-7586-3-git-send-email-arne@rfc2549.org> URL: http://article.gmane.org/gmane.network.openvpn.devel/10109 Signed-off-by: Gert Doering --- src/openvpn/clinat.c | 4 ---- src/openvpn/clinat.h | 2 +- src/openvpn/forward.c | 12 +++++++----- src/openvpn/multi.c | 2 -- src/openvpn/openvpn.h | 2 -- src/openvpn/options.c | 18 +----------------- src/openvpn/options.h | 7 ------- src/openvpn/push.c | 2 -- src/openvpn/syshead.h | 5 ----- 9 files changed, 9 insertions(+), 45 deletions(-) diff --git a/src/openvpn/clinat.c b/src/openvpn/clinat.c index af75fc9d9d8..ddefe123fb1 100644 --- a/src/openvpn/clinat.c +++ b/src/openvpn/clinat.c @@ -30,8 +30,6 @@ #include "syshead.h" -#if defined(ENABLE_CLIENT_NAT) - #include "clinat.h" #include "proto.h" #include "socket.h" @@ -265,5 +263,3 @@ client_nat_transform (const struct client_nat_option_list *list, } } } - -#endif diff --git a/src/openvpn/clinat.h b/src/openvpn/clinat.h index d55a727aa58..a5779e15dc3 100644 --- a/src/openvpn/clinat.h +++ b/src/openvpn/clinat.h @@ -22,7 +22,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#if !defined(CLINAT_H) && defined(ENABLE_CLIENT_NAT) +#if !defined(CLINAT_H) #define CLINAT_H #include "buffer.h" diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c index 6d459d2db50..92e443ac8fc 100644 --- a/src/openvpn/forward.c +++ b/src/openvpn/forward.c @@ -1029,6 +1029,8 @@ process_ip_header (struct context *c, unsigned int flags, struct buffer *buf) if (!c->options.passtos) flags &= ~PIPV4_PASSTOS; #endif + if (!c->options.client_nat) + flags &= ~PIPV4_CLIENT_NAT; if (!c->options.route_gateway_via_dhcp) flags &= ~PIPV4_EXTRACT_DHCP_ROUTER; @@ -1038,11 +1040,13 @@ process_ip_header (struct context *c, unsigned int flags, struct buffer *buf) * The --passtos and --mssfix options require * us to examine the IPv4 header. */ + + if (flags & (PIP_MSSFIX #if PASSTOS_CAPABILITY - if (flags & (PIPV4_PASSTOS|PIP_MSSFIX)) -#else - if (flags & PIP_MSSFIX) + | PIPV4_PASSTOS #endif + | PIPV4_CLIENT_NAT + )) { struct buffer ipbuf = *buf; if (is_ipv4 (TUNNEL_TYPE (c->c1.tuntap), &ipbuf)) @@ -1057,14 +1061,12 @@ process_ip_header (struct context *c, unsigned int flags, struct buffer *buf) if (flags & PIP_MSSFIX) mss_fixup_ipv4 (&ipbuf, MTU_TO_MSS (TUN_MTU_SIZE_DYNAMIC (&c->c2.frame))); -#ifdef ENABLE_CLIENT_NAT /* possibly do NAT on packet */ if ((flags & PIPV4_CLIENT_NAT) && c->options.client_nat) { const int direction = (flags & PIPV4_OUTGOING) ? CN_INCOMING : CN_OUTGOING; client_nat_transform (c->options.client_nat, &ipbuf, direction); } -#endif /* possibly extract a DHCP router message */ if (flags & PIPV4_EXTRACT_DHCP_ROUTER) { diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index b0f66ca2796..902c4dc35c8 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -1311,9 +1311,7 @@ multi_select_virtual_addr (struct multi_context *m, struct multi_instance *mi) mi->context.c2.push_ifconfig_defined = true; mi->context.c2.push_ifconfig_local = mi->context.options.push_ifconfig_local; mi->context.c2.push_ifconfig_remote_netmask = mi->context.options.push_ifconfig_remote_netmask; -#ifdef ENABLE_CLIENT_NAT mi->context.c2.push_ifconfig_local_alias = mi->context.options.push_ifconfig_local_alias; -#endif /* the current implementation does not allow "static IPv4, pool IPv6", * (see below) so issue a warning if that happens - don't break the diff --git a/src/openvpn/openvpn.h b/src/openvpn/openvpn.h index 1c2a80b3528..ef2226927cf 100644 --- a/src/openvpn/openvpn.h +++ b/src/openvpn/openvpn.h @@ -440,9 +440,7 @@ struct context_2 time_t sent_push_reply_expiry; in_addr_t push_ifconfig_local; in_addr_t push_ifconfig_remote_netmask; -#ifdef ENABLE_CLIENT_NAT in_addr_t push_ifconfig_local_alias; -#endif bool push_ifconfig_ipv6_defined; struct in6_addr push_ifconfig_ipv6_local; diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 93ea4154186..581db52edfb 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -225,9 +225,7 @@ static const char usage_message[] = " Add 'bypass-dns' flag to similarly bypass tunnel for DNS.\n" "--redirect-private [flags]: Like --redirect-gateway, but omit actually changing\n" " the default gateway. Useful when pushing private subnets.\n" -#ifdef ENABLE_CLIENT_NAT "--client-nat snat|dnat network netmask alias : on client add 1-to-1 NAT rule.\n" -#endif #ifdef ENABLE_PUSH_PEER_INFO "--push-peer-info : (client only) push client info to server.\n" #endif @@ -1299,9 +1297,7 @@ options_detach (struct options *o) { gc_detach (&o->gc); o->routes = NULL; -#ifdef ENABLE_CLIENT_NAT o->client_nat = NULL; -#endif #if P2MP_SERVER clone_push_list(o); #endif @@ -1321,14 +1317,12 @@ rol6_check_alloc (struct options *options) options->routes_ipv6 = new_route_ipv6_option_list (&options->gc); } -#ifdef ENABLE_CLIENT_NAT static void cnol_check_alloc (struct options *options) { if (!options->client_nat) options->client_nat = new_client_nat_list (&options->gc); } -#endif #ifndef ENABLE_SMALL static void @@ -1524,11 +1518,9 @@ show_settings (const struct options *o) SHOW_BOOL (allow_pull_fqdn); if (o->routes) print_route_options (o->routes, D_SHOW_PARMS); - -#ifdef ENABLE_CLIENT_NAT + if (o->client_nat) print_client_nat_list(o->client_nat, D_SHOW_PARMS); -#endif #ifdef ENABLE_MANAGEMENT SHOW_STR (management_addr); @@ -2821,13 +2813,11 @@ pre_pull_save (struct options *o) o->pre_pull->routes_ipv6 = clone_route_ipv6_option_list(o->routes_ipv6, &o->gc); o->pre_pull->routes_ipv6_defined = true; } -#ifdef ENABLE_CLIENT_NAT if (o->client_nat) { o->pre_pull->client_nat = clone_client_nat_option_list(o->client_nat, &o->gc); o->pre_pull->client_nat_defined = true; } -#endif } } @@ -2857,7 +2847,6 @@ pre_pull_restore (struct options *o, struct gc_arena *gc) else o->routes_ipv6 = NULL; -#ifdef ENABLE_CLIENT_NAT if (pp->client_nat_defined) { cnol_check_alloc (o); @@ -2865,7 +2854,6 @@ pre_pull_restore (struct options *o, struct gc_arena *gc) } else o->client_nat = NULL; -#endif o->foreign_option_index = pp->foreign_option_index; } @@ -5226,14 +5214,12 @@ add_option (struct options *options, VERIFY_PERMISSION (OPT_P_PERSIST_IP); options->persist_remote_ip = true; } -#ifdef ENABLE_CLIENT_NAT else if (streq (p[0], "client-nat") && p[1] && p[2] && p[3] && p[4] && !p[5]) { VERIFY_PERMISSION (OPT_P_ROUTE); cnol_check_alloc (options); add_client_nat_to_option_list(options->client_nat, p[1], p[2], p[3], p[4], msglevel); } -#endif else if (streq (p[0], "route") && p[1] && !p[5]) { VERIFY_PERMISSION (OPT_P_ROUTE); @@ -5819,10 +5805,8 @@ add_option (struct options *options, options->push_ifconfig_defined = true; options->push_ifconfig_local = local; options->push_ifconfig_remote_netmask = remote_netmask; -#ifdef ENABLE_CLIENT_NAT if (p[3]) options->push_ifconfig_local_alias = getaddr (GETADDR_HOST_ORDER|GETADDR_RESOLVE, p[3], 0, NULL, NULL); -#endif } else { diff --git a/src/openvpn/options.h b/src/openvpn/options.h index 25b9e3c0613..abec83f7ebb 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -71,10 +71,8 @@ struct options_pre_pull bool routes_ipv6_defined; struct route_ipv6_option_list *routes_ipv6; -#ifdef ENABLE_CLIENT_NAT bool client_nat_defined; struct client_nat_option_list *client_nat; -#endif int foreign_option_index; }; @@ -346,10 +344,7 @@ struct options bool route_nopull; bool route_gateway_via_dhcp; bool allow_pull_fqdn; /* as a client, allow server to push a FQDN for certain parameters */ - -#ifdef ENABLE_CLIENT_NAT struct client_nat_option_list *client_nat; -#endif #ifdef ENABLE_OCC /* Enable options consistency check between peers */ @@ -431,9 +426,7 @@ struct options bool push_ifconfig_defined; in_addr_t push_ifconfig_local; in_addr_t push_ifconfig_remote_netmask; -#ifdef ENABLE_CLIENT_NAT in_addr_t push_ifconfig_local_alias; -#endif bool push_ifconfig_constraint_defined; in_addr_t push_ifconfig_constraint_network; in_addr_t push_ifconfig_constraint_netmask; diff --git a/src/openvpn/push.c b/src/openvpn/push.c index 870616618d1..b9d0c4c5eac 100644 --- a/src/openvpn/push.c +++ b/src/openvpn/push.c @@ -294,10 +294,8 @@ send_push_reply (struct context *c) if (c->c2.push_ifconfig_defined && c->c2.push_ifconfig_local && c->c2.push_ifconfig_remote_netmask) { in_addr_t ifconfig_local = c->c2.push_ifconfig_local; -#ifdef ENABLE_CLIENT_NAT if (c->c2.push_ifconfig_local_alias) ifconfig_local = c->c2.push_ifconfig_local_alias; -#endif buf_printf (&buf, ",ifconfig %s %s", print_in_addr_t (ifconfig_local, 0, &gc), print_in_addr_t (c->c2.push_ifconfig_remote_netmask, 0, &gc)); diff --git a/src/openvpn/syshead.h b/src/openvpn/syshead.h index ff0bf419b56..4bebb25a5c8 100644 --- a/src/openvpn/syshead.h +++ b/src/openvpn/syshead.h @@ -701,11 +701,6 @@ socket_defined (const socket_descriptor_t sd) #define ENABLE_PUSH_PEER_INFO #endif -/* - * Do we support internal client-side NAT? - */ -#define ENABLE_CLIENT_NAT - /* * Compression support */ From afb93fac803fbab7406d3b2dff6d1f39365bca74 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Wed, 1 Jul 2015 17:40:39 +0200 Subject: [PATCH 085/643] Make client delay less before sending PUSH_REQUEST Speed up PUSH_REQUEST handling on the client side by reducing the amount of dependent 1s-coarse-timers to "just one". After "TLS is up!", one timer needs to fire to wakeup "check_connection_established_dowork()", and that one used to setup another 1s timer before sending PUSH_REQUEST - which is just dead time where we sit idly... So, fire immediately. Acked-by: Arne Schwabe Message-Id: <20150701154039.GG382@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/9851 Signed-off-by: Gert Doering --- src/openvpn/forward.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c index 92e443ac8fc..7a5d3838536 100644 --- a/src/openvpn/forward.c +++ b/src/openvpn/forward.c @@ -212,8 +212,8 @@ check_connection_established_dowork (struct context *c) 0); } #endif - /* send push request in 1 sec */ - event_timeout_init (&c->c2.push_request_interval, 1, now); + /* fire up push request right away (already 1s delayed) */ + event_timeout_init (&c->c2.push_request_interval, 0, now); reset_coarse_timers (c); } else From 3128abcfdd1eb293b10e4d0bfdb0805728538563 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Fri, 11 Sep 2015 17:33:42 +0200 Subject: [PATCH 086/643] get_default_gateway_ipv6(): Linux / Netlink implementation. Using "netlink socket" directly, without external netlink helper libraries. For this very simple case, it's easy enough. Signed-off-by: Gert Doering Acked-by: Arne Schwabe Message-Id: <1441985627-14822-6-git-send-email-gert@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/10091 --- src/openvpn/route.c | 148 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 136 insertions(+), 12 deletions(-) diff --git a/src/openvpn/route.c b/src/openvpn/route.c index baa4a232b3a..ed21d1508f4 100644 --- a/src/openvpn/route.c +++ b/src/openvpn/route.c @@ -45,6 +45,10 @@ #include "memdbg.h" +#if defined(TARGET_LINUX) || defined(TARGET_ANDROID) +#include /* RTM_GETROUTE etc. */ +#endif + #ifdef WIN32 #define METRIC_NOT_USED ((DWORD)-1) #endif @@ -1119,10 +1123,9 @@ print_default_gateway(const int msglevel, { struct buffer out = alloc_buf_gc (256, &gc); buf_printf (&out, "ROUTE6_GATEWAY"); + buf_printf (&out, " %s", print_in6_addr (rgi6->gateway.addr_ipv6, 0, &gc)); if (rgi6->flags & RGI_ON_LINK) buf_printf (&out, " ON_LINK"); - else - buf_printf (&out, " %s", print_in6_addr (rgi6->gateway.addr_ipv6, 0, &gc)); if (rgi6->flags & RGI_NETMASK_DEFINED) buf_printf (&out, "/%d", rgi6->gateway.netbits_ipv6); #ifdef WIN32 @@ -2677,22 +2680,143 @@ get_default_gateway (struct route_gateway_info *rgi) gc_free (&gc); } -/* IPv6 implementation using netlink (TBD) +/* IPv6 implementation using netlink + * http://www.linuxjournal.com/article/7356 + * netlink(3), netlink(7), rtnetlink(7) + * http://www.virtualbox.org/svn/vbox/trunk/src/VBox/NetworkServices/NAT/rtmon_linux.c */ +struct rtreq { + struct nlmsghdr nh; + struct rtmsg rtm; + char attrbuf[512]; +}; + void get_default_gateway_ipv6(struct route_ipv6_gateway_info *rgi6, struct in6_addr *dest) { - msg(D_ROUTE, "no support for get_default_gateway_ipv6() on this system (Linux and Android)"); + int nls = -1; + struct rtreq rtreq; + struct rtattr *rta; + + char rtbuf[2000]; + ssize_t ssize; + CLEAR(*rgi6); - struct in6_addr g = IN6ADDR_LOOPBACK_INIT; - - rgi6->flags = RGI_ADDR_DEFINED | RGI_IFACE_DEFINED | RGI_HWADDR_DEFINED | - RGI_NETMASK_DEFINED; - rgi6->gateway.addr_ipv6 = g; - rgi6->gateway.netbits_ipv6 = 64; - memcpy( rgi6->hwaddr, "\1\2\3\4\5\6", 6 ); - strcpy( rgi6->iface, "eth1" ); + + nls = socket( PF_NETLINK, SOCK_RAW, NETLINK_ROUTE ); + if ( nls < 0 ) + { msg(M_WARN|M_ERRNO, "GDG6: socket() failed" ); goto done; } + + /* bind() is not needed, no unsolicited msgs coming in */ + + /* request best matching route, see netlink(7) for explanations + */ + CLEAR(rtreq); + rtreq.nh.nlmsg_type = RTM_GETROUTE; + rtreq.nh.nlmsg_flags = NLM_F_REQUEST; /* best match only */ + rtreq.rtm.rtm_family = AF_INET6; + rtreq.rtm.rtm_src_len = 0; /* not source dependent */ + rtreq.rtm.rtm_dst_len = 128; /* exact dst */ + rtreq.rtm.rtm_table = RT_TABLE_MAIN; + rtreq.rtm.rtm_protocol = RTPROT_UNSPEC; + rtreq.nh.nlmsg_len = NLMSG_SPACE(sizeof(rtreq.rtm)); + + /* set RTA_DST for target IPv6 address we want */ + rta = (struct rtattr *)(((char *) &rtreq)+NLMSG_ALIGN(rtreq.nh.nlmsg_len)); + rta->rta_type = RTA_DST; + rta->rta_len = RTA_LENGTH(16); + rtreq.nh.nlmsg_len = NLMSG_ALIGN(rtreq.nh.nlmsg_len) + + RTA_LENGTH(16); + + if ( dest == NULL ) /* ::, unspecified */ + memset( RTA_DATA(rta), 0, 16 ); /* :: = all-zero */ + else + memcpy( RTA_DATA(rta), (void *)dest, 16 ); + + /* send and receive reply */ + if ( send( nls, &rtreq, rtreq.nh.nlmsg_len, 0 ) < 0 ) + { msg(M_WARN|M_ERRNO, "GDG6: send() failed" ); goto done; } + + ssize = recv(nls, rtbuf, sizeof(rtbuf), MSG_TRUNC); + + if (ssize < 0) + { msg(M_WARN|M_ERRNO, "GDG6: recv() failed" ); goto done; } + + if (ssize > sizeof(rtbuf)) + { + msg(M_WARN, "get_default_gateway_ipv6: returned message too big for buffer (%d>%d)", (int)ssize, (int)sizeof(rtbuf) ); + goto done; + } + + struct nlmsghdr *nh; + + for (nh = (struct nlmsghdr *)rtbuf; + NLMSG_OK(nh, ssize); + nh = NLMSG_NEXT(nh, ssize)) + { + struct rtmsg *rtm; + int attrlen; + + if (nh->nlmsg_type == NLMSG_DONE) { break; } + + if (nh->nlmsg_type == NLMSG_ERROR) { + struct nlmsgerr *ne = (struct nlmsgerr *)NLMSG_DATA(nh); + msg(M_WARN, "GDG6: NLSMG_ERROR: error %d\n", ne->error); + break; + } + + if (nh->nlmsg_type != RTM_NEWROUTE) { + /* shouldn't happen */ + msg(M_WARN, "GDG6: unexpected msg_type %d", nh->nlmsg_type ); + continue; + } + + rtm = (struct rtmsg *)NLMSG_DATA(nh); + attrlen = RTM_PAYLOAD(nh); + + /* we're only looking for routes in the main table, as "we have + * no IPv6" will lead to a lookup result in "Local" (::/0 reject) + */ + if (rtm->rtm_family != AF_INET6 || + rtm->rtm_table != RT_TABLE_MAIN) + { continue; } /* we're not interested */ + + for (rta = RTM_RTA(rtm); + RTA_OK(rta, attrlen); + rta = RTA_NEXT(rta, attrlen)) + { + if (rta->rta_type == RTA_GATEWAY) { + if ( RTA_PAYLOAD(rta) != sizeof(struct in6_addr) ) + { msg(M_WARN, "GDG6: RTA_GW size mismatch"); continue; } + rgi6->gateway.addr_ipv6 = *(struct in6_addr*) RTA_DATA(rta); + rgi6->flags |= RGI_ADDR_DEFINED; + } + else if (rta->rta_type == RTA_OIF) { + char ifname[IF_NAMESIZE+1]; + int oif; + if ( RTA_PAYLOAD(rta) != sizeof(oif) ) + { msg(M_WARN, "GDG6: oif size mismatch"); continue; } + + memcpy(&oif, RTA_DATA(rta), sizeof(oif)); + if_indextoname(oif,ifname); + strncpy( rgi6->iface, ifname, sizeof(rgi6->iface)-1 ); + rgi6->flags |= RGI_IFACE_DEFINED; + } + } + } + + /* if we have an interface but no gateway, the destination is on-link */ + if ( ( rgi6->flags & (RGI_IFACE_DEFINED|RGI_ADDR_DEFINED) ) == + RGI_IFACE_DEFINED ) + { + rgi6->flags |= (RGI_ADDR_DEFINED | RGI_ON_LINK); + rgi6->gateway.addr_ipv6 = *dest; + } + + done: + if (nls >= 0) + close (nls); } #elif defined(TARGET_DARWIN) || defined(TARGET_SOLARIS) || \ From 3ddb56433b1fa0f20565dfda13a647459c06251a Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Fri, 11 Sep 2015 17:33:43 +0200 Subject: [PATCH 087/643] Implement handling of overlapping IPv6 routes with IPv6 remote VPN server address - socket.[ch]: add link_socket_current_remote_ipv6() helper to extract current address of remote VPN server (if IPv6, NULL otherwise), IPv6 equivalent to link_socket_current_remote() - init.c: pass remote VPN server address to init_route_ipv6_list() (link_socket_current_remote_ipv6()) - route.h: add route_ipv6_gateway_info to route_ipv6_list, and reorder structures so that this actually compiles. Add iface/adapter_index to struct route_ipv6 (for non-tun/tap routes). - route.[ch]: add "const" to *dest argument to get_default_gateway_ipv6() - route.c: add route_ipv6_match_host() helper to check whether an IPv6 address is matched by a given "route_ipv6" IPv6 route) - route.c: init_route_ipv6_list() - call get_default_gateway_ipv6() - check to-be-installed IPv6 routes against VPN server address (if IPv6) - if an overlap is seen, add a host route for the VPN server address via the just-discovered gateway to the list of IPv6 routes to be installed (rl6->routes_ipv6) - warn if overlap is detected but platform code has not been able to discover IPv6 default gateway - route.c: add_route_ipv6() / delete_route_ipv6(): set "device" to "external default gateway interface" (r6->iface) instead of TUN/TAP device (if set), which nicely enables arbitrary gateway/interface combinations for Linux - ssl.c: add "IV_RGI6=1" to push-peer-info data to let server know we can handle pushed IPv6 routes that overlap with server IPv6 address - tun.c: when adding/removing on-link routes, CLEAR(r6) first to ensure new struct route_ipv6 members are cleared Tested on Linux with iproute2 and /bin/route, on eth and tun routes. Signed-off-by: Gert Doering Acked-by: Arne Schwabe Message-Id: <1441985627-14822-7-git-send-email-gert@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/10089 --- src/openvpn/init.c | 4 +- src/openvpn/route.c | 132 +++++++++++++++++++++++++++++++++++++++---- src/openvpn/route.h | 36 +++++++----- src/openvpn/socket.c | 22 ++++++++ src/openvpn/socket.h | 2 + src/openvpn/ssl.c | 3 + src/openvpn/tun.c | 2 + 7 files changed, 175 insertions(+), 26 deletions(-) diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 48542c9c394..922308dfa3b 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -1179,6 +1179,7 @@ do_init_route_list (const struct options *options, static void do_init_route_ipv6_list (const struct options *options, struct route_ipv6_list *route_ipv6_list, + const struct link_socket_info *link_socket_info, bool fatal, struct env_set *es) { @@ -1198,6 +1199,7 @@ do_init_route_ipv6_list (const struct options *options, options->routes_ipv6, gw, metric, + link_socket_current_remote_ipv6 (link_socket_info), es)) { if (fatal) @@ -1391,7 +1393,7 @@ do_open_tun (struct context *c) if (c->options.routes && c->c1.route_list && c->c2.link_socket) do_init_route_list (&c->options, c->c1.route_list, &c->c2.link_socket->info, false, c->c2.es); if (c->options.routes_ipv6 && c->c1.route_ipv6_list ) - do_init_route_ipv6_list (&c->options, c->c1.route_ipv6_list, false, c->c2.es); + do_init_route_ipv6_list (&c->options, c->c1.route_ipv6_list, &c->c2.link_socket->info, false, c->c2.es); /* do ifconfig */ if (!c->options.ifconfig_noexec diff --git a/src/openvpn/route.c b/src/openvpn/route.c index ed21d1508f4..db4657e2749 100644 --- a/src/openvpn/route.c +++ b/src/openvpn/route.c @@ -660,29 +660,78 @@ init_route_list (struct route_list *rl, return ret; } +/* check whether an IPv6 host address is covered by a given route_ipv6 + * (not the most beautiful implementation in the world, but portable and + * "good enough") + */ +static bool +route_ipv6_match_host( const struct route_ipv6 *r6, + const struct in6_addr *host ) +{ + unsigned int bits = r6->netbits; + int i; + unsigned int mask; + + if ( bits>128 ) + return false; + + for( i=0; bits >= 8; i++, bits -= 8 ) + { + if ( r6->network.s6_addr[i] != host->s6_addr[i] ) + return false; + } + + if ( bits == 0 ) + return true; + + mask = 0xff << (8-bits); + + if ( (r6->network.s6_addr[i] & mask) == (host->s6_addr[i] & mask )) + return true; + + return false; +} + bool init_route_ipv6_list (struct route_ipv6_list *rl6, const struct route_ipv6_option_list *opt6, const char *remote_endpoint, int default_metric, + const struct in6_addr *remote_host_ipv6, struct env_set *es) { struct gc_arena gc = gc_new (); bool ret = true; + bool need_remote_ipv6_route; clear_route_ipv6_list (rl6); rl6->flags = opt6->flags; + if (remote_host_ipv6) + { + rl6->remote_host_ipv6 = *remote_host_ipv6; + rl6->spec_flags |= RTSA_REMOTE_HOST; + } + if (default_metric >= 0 ) { rl6->default_metric = default_metric; rl6->spec_flags |= RTSA_DEFAULT_METRIC; } - /* "default_gateway" is stuff for "redirect-gateway", which we don't - * do for IPv6 yet -> TODO - */ + msg (D_ROUTE, "GDG6: remote_host_ipv6=%s", + remote_host_ipv6? print_in6_addr (*remote_host_ipv6, 0, &gc): "n/a" ); + + get_default_gateway_ipv6 (&rl6->rgi6, remote_host_ipv6); + if (rl6->rgi6.flags & RGI_ADDR_DEFINED) + { + setenv_str (es, "net_gateway_ipv6", print_in6_addr (rl6->rgi6.gateway.addr_ipv6, 0, &gc)); +#if defined(ENABLE_DEBUG) && !defined(ENABLE_SMALL) + print_default_gateway (D_ROUTE, NULL, &rl6->rgi6); +#endif + } + else { dmsg (D_ROUTE, "ROUTE6: default_gateway=UNDEF"); } @@ -696,12 +745,16 @@ init_route_ipv6_list (struct route_ipv6_list *rl6, } else { - msg (M_WARN, PACKAGE_NAME " ROUTE: failed to parse/resolve default gateway: %s", remote_endpoint); + msg (M_WARN, PACKAGE_NAME " ROUTE: failed to parse/resolve VPN endpoint: %s", remote_endpoint); ret = false; } } - /* parse the routes from opt6 to rl6 */ + /* parse the routes from opt6 to rl6 + * discovering potential overlaps with remote_host_ipv6 in the process + */ + need_remote_ipv6_route = false; + { struct route_ipv6_option *ro6; for (ro6 = opt6->routes_ipv6; ro6; ro6 = ro6->next) @@ -714,10 +767,49 @@ init_route_ipv6_list (struct route_ipv6_list *rl6, { r6->next = rl6->routes_ipv6; rl6->routes_ipv6 = r6; + + if ( remote_host_ipv6 && + route_ipv6_match_host( r6, remote_host_ipv6 ) ) + { + need_remote_ipv6_route = true; + msg (D_ROUTE, "ROUTE6: %s/%d overlaps IPv6 remote %s, adding host route to VPN endpoint", + print_in6_addr (r6->network, 0, &gc), r6->netbits, + print_in6_addr (*remote_host_ipv6, 0, &gc)); + } } } } + /* add VPN server host route if needed */ + if ( need_remote_ipv6_route ) + { + if ( (rl6->rgi6.flags & (RGI_ADDR_DEFINED|RGI_IFACE_DEFINED) ) == + (RGI_ADDR_DEFINED|RGI_IFACE_DEFINED) ) + { + struct route_ipv6 *r6; + ALLOC_OBJ_CLEAR_GC (r6, struct route_ipv6, &rl6->gc); + + r6->network = *remote_host_ipv6; + r6->netbits = 128; + if ( !(rl6->rgi6.flags & RGI_ON_LINK) ) + { r6->gateway = rl6->rgi6.gateway.addr_ipv6; } + r6->metric = 1; +#ifdef WIN32 + r6->adapter_index = rl6->rgi6.adapter_index; +#else + r6->iface = rl6->rgi6.iface; +#endif + r6->flags = RT_DEFINED | RT_METRIC_DEFINED; + + r6->next = rl6->routes_ipv6; + rl6->routes_ipv6 = r6; + } + else + { + msg (M_WARN, "ROUTE6: IPv6 route overlaps with IPv6 remote address, but could not determine IPv6 gateway address + interface, expect failure\n" ); + } + } + gc_free (&gc); return ret; } @@ -1574,6 +1666,15 @@ add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int fla if (! (r6->flags & RT_DEFINED) ) return; +#ifndef WIN32 + if ( r6->iface != NULL ) /* vpn server special route */ + { + device = r6->iface; + if ( !IN6_IS_ADDR_UNSPECIFIED(&r6->gateway) ) + gateway_needed = true; + } +#endif + gc_init (&gc); argv_init (&argv); @@ -1655,7 +1756,7 @@ add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int fla * - in TUN mode we use a special-case link-local address that the tapdrvr * knows about and will answer ND (neighbor discovery) packets for */ - if ( tt->type == DEV_TYPE_TUN ) + if ( tt->type == DEV_TYPE_TUN && !gateway_needed ) argv_printf_cat( &argv, " %s", "fe80::8" ); else argv_printf_cat( &argv, " %s", gateway ); @@ -1948,6 +2049,14 @@ delete_route_ipv6 (const struct route_ipv6 *r6, const struct tuntap *tt, unsigne if ((r6->flags & (RT_DEFINED|RT_ADDED)) != (RT_DEFINED|RT_ADDED)) return; +#ifndef WIN32 + if ( r6->iface != NULL ) /* vpn server special route */ + { + device = r6->iface; + gateway_needed = true; + } +#endif + gc_init (&gc); argv_init (&argv); @@ -2344,7 +2453,7 @@ windows_route_find_if_index (const struct route_ipv4 *r, const struct tuntap *tt */ void get_default_gateway_ipv6(struct route_ipv6_gateway_info *rgi6, - struct in6_addr *dest) + const struct in6_addr *dest) { msg(D_ROUTE, "no support for get_default_gateway_ipv6() on this system (windows)"); CLEAR(*rgi6); @@ -2693,7 +2802,7 @@ struct rtreq { void get_default_gateway_ipv6(struct route_ipv6_gateway_info *rgi6, - struct in6_addr *dest) + const struct in6_addr *dest) { int nls = -1; struct rtreq rtreq; @@ -2811,7 +2920,8 @@ get_default_gateway_ipv6(struct route_ipv6_gateway_info *rgi6, RGI_IFACE_DEFINED ) { rgi6->flags |= (RGI_ADDR_DEFINED | RGI_ON_LINK); - rgi6->gateway.addr_ipv6 = *dest; + if ( dest ) + rgi6->gateway.addr_ipv6 = *dest; } done: @@ -3065,7 +3175,7 @@ get_default_gateway (struct route_gateway_info *rgi) */ void get_default_gateway_ipv6(struct route_ipv6_gateway_info *rgi6, - struct in6_addr *dest) + const struct in6_addr *dest) { msg(D_ROUTE, "no support for get_default_gateway_ipv6() on this system (BSD and OSX)"); CLEAR(*rgi6); @@ -3106,7 +3216,7 @@ get_default_gateway (struct route_gateway_info *rgi) } void get_default_gateway_ipv6(struct route_ipv6_gateway_info *rgi6, - struct in6_addr *dest) + const struct in6_addr *dest) { msg(D_ROUTE, "no support for get_default_gateway_ipv6() on this system"); CLEAR(*rgi6); diff --git a/src/openvpn/route.h b/src/openvpn/route.h index 95cf99f9301..4bbcdb74d47 100644 --- a/src/openvpn/route.h +++ b/src/openvpn/route.h @@ -128,19 +128,12 @@ struct route_ipv6 { unsigned int netbits; struct in6_addr gateway; int metric; -}; - -struct route_ipv6_list { - unsigned int iflags; /* RL_ flags, see route_list */ - - unsigned int spec_flags; /* RTSA_ flags, route_special_addr */ - struct in6_addr remote_endpoint_ipv6; /* inside tun */ - struct in6_addr remote_host_ipv6; /* --remote address */ - int default_metric; - - unsigned int flags; /* RG_x flags, see route_option_list */ - struct route_ipv6 *routes_ipv6; - struct gc_arena gc; + /* gateway interface */ +# ifdef WIN32 + DWORD adapter_index; /* interface or ~0 if undefined */ +#else + char * iface; /* interface name (null terminated) */ +#endif }; @@ -218,6 +211,20 @@ struct route_list { struct gc_arena gc; }; +struct route_ipv6_list { + unsigned int iflags; /* RL_ flags, see route_list */ + + unsigned int spec_flags; /* RTSA_ flags, route_special_addr */ + struct in6_addr remote_endpoint_ipv6; /* inside tun */ + struct in6_addr remote_host_ipv6; /* --remote address */ + int default_metric; + + struct route_ipv6_gateway_info rgi6; + unsigned int flags; /* RG_x flags, see route_option_list */ + struct route_ipv6 *routes_ipv6; + struct gc_arena gc; +}; + #if P2MP /* internal OpenVPN route */ struct iroute { @@ -274,6 +281,7 @@ bool init_route_ipv6_list (struct route_ipv6_list *rl6, const struct route_ipv6_option_list *opt6, const char *remote_endpoint, int default_metric, + const struct in6_addr *remote_host, struct env_set *es); void route_list_add_vpn_gateway (struct route_list *rl, @@ -301,7 +309,7 @@ bool is_special_addr (const char *addr_str); void get_default_gateway (struct route_gateway_info *rgi); void get_default_gateway_ipv6 (struct route_ipv6_gateway_info *rgi, - struct in6_addr *dest); + const struct in6_addr *dest); void print_default_gateway(const int msglevel, const struct route_gateway_info *rgi, const struct route_ipv6_gateway_info *rgi6); diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c index 57d5962e4f0..bd8dcb1bcdb 100644 --- a/src/openvpn/socket.c +++ b/src/openvpn/socket.c @@ -2126,6 +2126,28 @@ link_socket_current_remote (const struct link_socket_info *info) return 0; } +const struct in6_addr * +link_socket_current_remote_ipv6 (const struct link_socket_info *info) +{ + const struct link_socket_addr *lsa = info->lsa; + +/* This logic supports "redirect-gateway" semantic, + * for PF_INET6 routes over PF_INET6 endpoints + * + * For --remote entries with multiple addresses this + * only return the actual endpoint we have sucessfully connected to + */ + if (lsa->actual.dest.addr.sa.sa_family != AF_INET6) + return NULL; + + if (link_socket_actual_defined (&lsa->actual)) + return &(lsa->actual.dest.addr.in6.sin6_addr); + else if (lsa->current_remote) + return &(((struct sockaddr_in6*)lsa->current_remote->ai_addr) ->sin6_addr); + else + return NULL; +} + /* * Return a status string describing socket state. */ diff --git a/src/openvpn/socket.h b/src/openvpn/socket.h index 8e157c67af8..49cfab680fd 100644 --- a/src/openvpn/socket.h +++ b/src/openvpn/socket.h @@ -419,6 +419,8 @@ void bad_address_length (int actual, int expected); */ #define IPV4_INVALID_ADDR 0xffffffff in_addr_t link_socket_current_remote (const struct link_socket_info *info); +const struct in6_addr * link_socket_current_remote_ipv6 + (const struct link_socket_info *info); void link_socket_connection_initiated (const struct buffer *buf, struct link_socket_info *info, diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 4e44410ef6c..54a3e094cf3 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -1853,6 +1853,9 @@ push_peer_info(struct buffer *buf, struct tls_session *session) comp_generate_peer_info_string(&session->opt->comp_options, &out); #endif + /* support for redirecting IPv6 gateway */ + buf_printf(&out, "IV_RGI6=1\n"); + if (session->opt->push_peer_info_detail >= 2) { /* push mac addr */ diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index 766a73c6e4a..24a61eccfd6 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -607,6 +607,7 @@ void add_route_connected_v6_net(struct tuntap * tt, { struct route_ipv6 r6; + CLEAR(r6); r6.network = tt->local_ipv6; r6.netbits = tt->netbits_ipv6; r6.gateway = tt->local_ipv6; @@ -620,6 +621,7 @@ void delete_route_connected_v6_net(struct tuntap * tt, { struct route_ipv6 r6; + CLEAR(r6); r6.network = tt->local_ipv6; r6.netbits = tt->netbits_ipv6; r6.gateway = tt->local_ipv6; From 1ff39cff4e644103607f0266cd4666dab18716c5 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Thu, 17 Sep 2015 12:23:58 +0200 Subject: [PATCH 088/643] Do not install a host route for the VPN on Android Routing loops are avoided using the VPNService API protect API Acked-by: Gert Doering Message-Id: <1442485438-15704-1-git-send-email-arne@rfc2549.org> URL: http://article.gmane.org/gmane.network.openvpn.devel/10135 Signed-off-by: Gert Doering --- src/openvpn/route.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/openvpn/route.c b/src/openvpn/route.c index db4657e2749..ab8eb27f657 100644 --- a/src/openvpn/route.c +++ b/src/openvpn/route.c @@ -768,6 +768,11 @@ init_route_ipv6_list (struct route_ipv6_list *rl6, r6->next = rl6->routes_ipv6; rl6->routes_ipv6 = r6; +#ifndef TARGET_ANDROID + /* On Android the VPNService protect function call will take of + * avoiding routing loops, so ignore this part and let + * need_remote_ipv6_route always evaluate to false + */ if ( remote_host_ipv6 && route_ipv6_match_host( r6, remote_host_ipv6 ) ) { @@ -776,7 +781,8 @@ init_route_ipv6_list (struct route_ipv6_list *rl6, print_in6_addr (r6->network, 0, &gc), r6->netbits, print_in6_addr (*remote_host_ipv6, 0, &gc)); } - } +#endif + } } } From d227929b5db049ca6efbef9fb7d84be5e545b41d Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Fri, 11 Sep 2015 17:33:44 +0200 Subject: [PATCH 089/643] Implement '--redirect-gateway ipv6' Add "ipv6" and "!ipv4" sub-options to "--redirect-gateway" option. This is done in the same way as in the OpenVPN 3 code base, so "--redirect-gateway ipv6" will redirect both IPv4 and IPv6 - if you want v6-only, use "--redirect-gateway ipv6 !ipv4". The actual implementation is much simpler than for IPv4 - we just add a few extra routes to the route_ipv6_option_list and leave it to init_route_ipv6_list() to figure out whether there is an overlap with IPv6 transport, and if yes, insert a host route to the VPN server via the current IPv6 default gateway. Signed-off-by: Gert Doering Acked-by: Arne Schwabe Message-Id: <1441985627-14822-8-git-send-email-gert@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/10086 --- doc/openvpn.8 | 11 +++++++++++ src/openvpn/init.c | 15 +++++++++++++++ src/openvpn/options.c | 7 +++++++ 3 files changed, 33 insertions(+) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 3a0d4e0dbcf..e213f5afb42 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -1240,6 +1240,17 @@ on non-Windows clients). Block access to local LAN when the tunnel is active, except for the LAN gateway itself. This is accomplished by routing the local LAN (except for the LAN gateway address) into the tunnel. + +.B ipv6 -- +Redirect IPv6 routing into the tunnel. This works similar to the +.B def1 +flag, that is, more specific IPv6 routes are added (2000::/4, 3000::/4), +covering the whole IPv6 unicast space. + +.B !ipv4 -- +Do not redirect IPv4 traffic - typically used in the flag pair +.B "ipv6 !ipv4" +to redirect IPv6-only. .\"********************************************************* .TP .B \-\-link\-mtu n diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 922308dfa3b..f568d8745f7 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -1195,6 +1195,21 @@ do_init_route_ipv6_list (const struct options *options, if (options->route_default_metric) metric = options->route_default_metric; + /* redirect (IPv6) gateway to VPN? if yes, add a few more specifics + */ + if ( options->routes_ipv6->flags & RG_REROUTE_GW ) + { + char *opt_list[] = { "::/3", "2000::/4", "3000::/4", "fc00::/7", NULL }; + int i; + + for (i=0; opt_list[i]; i++) + { + add_route_ipv6_to_option_list( options->routes_ipv6, + string_alloc (opt_list[i], options->routes_ipv6->gc), + NULL, NULL ); + } + } + if (!init_route_ipv6_list (route_ipv6_list, options->routes_ipv6, gw, diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 581db52edfb..5ace1f34710 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -5366,6 +5366,13 @@ add_option (struct options *options, options->routes->flags |= RG_BYPASS_DNS; else if (streq (p[j], "block-local")) options->routes->flags |= RG_BLOCK_LOCAL; + else if (streq (p[j], "ipv6")) + { + rol6_check_alloc (options); + options->routes_ipv6->flags |= RG_REROUTE_GW; + } + else if (streq (p[j], "!ipv4")) + options->routes->flags &= ~RG_REROUTE_GW; else { msg (msglevel, "unknown --%s flag: %s", p[0], p[j]); From 2ff366f78a2bf8d0a2744db9b59f7274b671a042 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Fri, 11 Sep 2015 17:33:45 +0200 Subject: [PATCH 090/643] get_default_gateway_ipv6(): *BSD / MacOS / Solaris PF_ROUTE implementation As for IPv4, a common implementation for all (supported) BSD families and Solaris. Supporting the latter requires separate implementations for IPv4 and IPv6, unfortunately, so it's quite a bit of duplicate code. Further, extend add_route_ipv6() and delete_route_ipv6() to handle link-local gateway addresses that require "gateway + interface" in scoped notation ("fe80::1%em0"). Tested on FreeBSD 7.4/amd64, 9.3/sparc64, 10.0/amd64, NetBSD 5.1/amd64, OpenBSD 4.9/i386, MacOS X 10.5/32 and 10.10/64 and OpenSolaris 10.11/i386. Signed-off-by: Gert Doering Acked-by: Arne Schwabe Message-Id: <1441985627-14822-9-git-send-email-gert@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/10082 --- src/openvpn/route.c | 187 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 183 insertions(+), 4 deletions(-) diff --git a/src/openvpn/route.c b/src/openvpn/route.c index ab8eb27f657..5f8a44d6964 100644 --- a/src/openvpn/route.c +++ b/src/openvpn/route.c @@ -1687,6 +1687,24 @@ add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int fla network = print_in6_addr_netbits_only( r6->network, r6->netbits, &gc); gateway = print_in6_addr( r6->gateway, 0, &gc); +#if defined(TARGET_DARWIN) || \ + defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY) || \ + defined(TARGET_OPENBSD) || defined(TARGET_NETBSD) + + /* the BSD platforms cannot specify gateway and interface independently, + * but for link-local destinations, we MUST specify the interface, so + * we build a combined "$gateway%$interface" gateway string + */ + if ( r6->iface != NULL && gateway_needed && + IN6_IS_ADDR_LINKLOCAL(&r6->gateway) ) /* fe80::...%intf */ + { + int len = strlen(gateway) + 1 + strlen(r6->iface)+1; + char * tmp = gc_malloc( len, true, &gc ); + snprintf( tmp, len, "%s%%%s", gateway, r6->iface ); + gateway = tmp; + } +#endif + if ( !tt->ipv6 ) { msg( M_INFO, "add_route_ipv6(): not adding %s/%d, no IPv6 on if %s", @@ -2069,6 +2087,24 @@ delete_route_ipv6 (const struct route_ipv6 *r6, const struct tuntap *tt, unsigne network = print_in6_addr_netbits_only( r6->network, r6->netbits, &gc); gateway = print_in6_addr( r6->gateway, 0, &gc); +#if defined(TARGET_DARWIN) || \ + defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY) || \ + defined(TARGET_OPENBSD) || defined(TARGET_NETBSD) + + /* the BSD platforms cannot specify gateway and interface independently, + * but for link-local destinations, we MUST specify the interface, so + * we build a combined "$gateway%$interface" gateway string + */ + if ( r6->iface != NULL && gateway_needed && + IN6_IS_ADDR_LINKLOCAL(&r6->gateway) ) /* fe80::...%intf */ + { + int len = strlen(gateway) + 1 + strlen(r6->iface)+1; + char * tmp = gc_malloc( len, true, &gc ); + snprintf( tmp, len, "%s%%%s", gateway, r6->iface ); + gateway = tmp; + } +#endif + if ( !tt->ipv6 ) { msg( M_INFO, "delete_route_ipv6(): not deleting %s/%d, no IPv6 on if %s", @@ -2973,14 +3009,14 @@ struct rtmsg { #if defined(TARGET_SOLARIS) #define NEXTADDR(w, u) \ if (rtm_addrs & (w)) {\ - l = ROUNDUP(sizeof(struct sockaddr_in)); memmove(cp, &(u), l); cp += l;\ + l = ROUNDUP(sizeof(u)); memmove(cp, &(u), l); cp += l;\ } #define ADVANCE(x, n) (x += ROUNDUP(sizeof(struct sockaddr_in))) #else #define NEXTADDR(w, u) \ if (rtm_addrs & (w)) {\ - l = ROUNDUP(u.sa_len); memmove(cp, &(u), l); cp += l;\ + l = ROUNDUP( ((struct sockaddr *)&(u))->sa_len); memmove(cp, &(u), l); cp += l;\ } #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) @@ -3177,14 +3213,157 @@ get_default_gateway (struct route_gateway_info *rgi) gc_free (&gc); } -/* BSD implementation using routing socket (as does IPv4) (TBD) +/* BSD implementation using routing socket (as does IPv4) + * (the code duplication is somewhat unavoidable if we want this to + * work on OpenSolaris as well. *sigh*) */ + +/* Solaris has no length field - this is ugly, but less #ifdef in total + */ +#if defined(TARGET_SOLARIS) +# undef ADVANCE +# define ADVANCE(x, n) (x += ROUNDUP(sizeof(struct sockaddr_in6))) +#endif + void get_default_gateway_ipv6(struct route_ipv6_gateway_info *rgi6, const struct in6_addr *dest) { - msg(D_ROUTE, "no support for get_default_gateway_ipv6() on this system (BSD and OSX)"); + + struct rtmsg m_rtmsg; + int sockfd = -1; + int seq, l, pid, rtm_addrs, i; + struct sockaddr_in6 so_dst, so_mask; + char *cp = m_rtmsg.m_space; + struct sockaddr *gate = NULL, *ifp = NULL, *sa; + struct rt_msghdr *rtm_aux; + CLEAR(*rgi6); + + /* setup data to send to routing socket */ + pid = getpid(); + seq = 0; + rtm_addrs = RTA_DST | RTA_NETMASK | RTA_IFP; + + bzero(&m_rtmsg, sizeof(m_rtmsg)); + bzero(&so_dst, sizeof(so_dst)); + bzero(&so_mask, sizeof(so_mask)); + bzero(&rtm, sizeof(struct rt_msghdr)); + + rtm.rtm_type = RTM_GET; + rtm.rtm_flags = RTF_UP; + rtm.rtm_version = RTM_VERSION; + rtm.rtm_seq = ++seq; + + so_dst.sin6_family = AF_INET6; + so_mask.sin6_family = AF_INET6; + + if ( dest != NULL && /* specific host? */ + !IN6_IS_ADDR_UNSPECIFIED(dest) ) + { + so_dst.sin6_addr = *dest; + /* :: needs /0 "netmask", host route wants "no netmask */ + rtm_addrs &= ~RTA_NETMASK; + } + + rtm.rtm_addrs = rtm_addrs; + +#ifndef TARGET_SOLARIS + so_dst.sin6_len = sizeof(struct sockaddr_in6); + so_mask.sin6_len = sizeof(struct sockaddr_in6); +#endif + + NEXTADDR(RTA_DST, so_dst); + NEXTADDR(RTA_NETMASK, so_mask); + + rtm.rtm_msglen = l = cp - (char *)&m_rtmsg; + + /* transact with routing socket */ + sockfd = socket(PF_ROUTE, SOCK_RAW, 0); + if (sockfd < 0) + { + msg (M_WARN, "GDG6: socket #1 failed"); + goto done; + } + if (write(sockfd, (char *)&m_rtmsg, l) < 0) + { + msg (M_WARN, "GDG6: problem writing to routing socket"); + goto done; + } + + do + { + l = read(sockfd, (char *)&m_rtmsg, sizeof(m_rtmsg)); + } + while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid)); + + close(sockfd); + sockfd = -1; + + /* extract return data from routing socket */ + rtm_aux = &rtm; + cp = ((char *)(rtm_aux + 1)); + if (rtm_aux->rtm_addrs) + { + for (i = 1; i; i <<= 1) + { + if (i & rtm_aux->rtm_addrs) + { + sa = (struct sockaddr *)cp; + if (i == RTA_GATEWAY ) + gate = sa; + else if (i == RTA_IFP) + ifp = sa; + ADVANCE(cp, sa); + } + } + } + else + goto done; + + /* get gateway addr and interface name */ + if (gate != NULL ) + { + struct sockaddr_in6 * s6 = (struct sockaddr_in6 *)gate; + struct in6_addr gw = s6->sin6_addr; + +#ifndef TARGET_SOLARIS + /* You do not really want to know... from FreeBSD's route.c + * (KAME encodes the 16 bit scope_id in s6_addr[2] + [3], + * but for a correct link-local address these must be :0000: ) + */ + if ( gate->sa_len == sizeof(struct sockaddr_in6) && + IN6_IS_ADDR_LINKLOCAL(&gw) ) + { + gw.s6_addr[2] = gw.s6_addr[3] = 0; + } + + if ( gate->sa_len != sizeof(struct sockaddr_in6) || + IN6_IS_ADDR_UNSPECIFIED(&gw) ) + { + rgi6->flags |= RGI_ON_LINK; + } + else +#endif + + rgi6->gateway.addr_ipv6 = gw; + rgi6->flags |= RGI_ADDR_DEFINED; + + if (ifp) + { + /* get interface name */ + const struct sockaddr_dl *adl = (struct sockaddr_dl *) ifp; + if (adl->sdl_nlen && adl->sdl_nlen < sizeof(rgi6->iface)) + { + memcpy (rgi6->iface, adl->sdl_data, adl->sdl_nlen); + rgi6->flags |= RGI_IFACE_DEFINED; + } + } + } + + done: + if (sockfd >= 0) + close(sockfd); } #undef max From fa5697f022110f557710f709c9ac0a3420bb073c Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Fri, 11 Sep 2015 17:33:46 +0200 Subject: [PATCH 091/643] Fix IPv6 host routes to LAN gateway on OpenSolaris The tun/tap routes need to be set with "metric 0", while this will prevent routes to LAN gateways from being installed. So, set metric 0 only if no other interface is requested... (Note: OpenSolaris can not specify host+interface gateways, so we just use the GW addresses - it seems to still work for fe80:: addresses, however it is done internally. NUD maybe?) Signed-off-by: Gert Doering Acked-by: Arne Schwabe Message-Id: <1441985627-14822-10-git-send-email-gert@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/10092 --- src/openvpn/route.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/openvpn/route.c b/src/openvpn/route.c index 5f8a44d6964..c011f993e9b 100644 --- a/src/openvpn/route.c +++ b/src/openvpn/route.c @@ -1805,17 +1805,25 @@ add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int fla /* example: route add -inet6 2001:db8::/32 somegateway 0 */ - /* for some weird reason, this does not work for me unless I set + /* for some reason, routes to tun/tap do not work for me unless I set * "metric 0" - otherwise, the routes will be nicely installed, but - * packets will just disappear somewhere. So we use "0" now... + * packets will just disappear somewhere. So we always use "0" now, + * unless the route points to "gateway on other interface"... + * + * (Note: OpenSolaris can not specify host%interface gateways, so we just + * use the GW addresses - it seems to still work for fe80:: addresses, + * however this is done internally. NUD maybe?) */ - - argv_printf (&argv, "%s add -inet6 %s/%d %s 0", + argv_printf (&argv, "%s add -inet6 %s/%d %s", ROUTE_PATH, network, r6->netbits, gateway ); + /* on tun/tap, not "elsewhere"? -> metric 0 */ + if ( !r6->iface ) + argv_printf_cat (&argv, "0"); + argv_msg (D_ROUTE, &argv); status = openvpn_execve_check (&argv, es, 0, "ERROR: Solaris route add -inet6 command failed"); @@ -2188,7 +2196,6 @@ delete_route_ipv6 (const struct route_ipv6 *r6, const struct tuntap *tt, unsigne #elif defined (TARGET_SOLARIS) /* example: route delete -inet6 2001:db8::/32 somegateway */ - /* GERT-TODO: this is untested, but should work */ argv_printf (&argv, "%s delete -inet6 %s/%d %s", ROUTE_PATH, From 767e4c56becbfeea525e4695a810593f373883cd Mon Sep 17 00:00:00 2001 From: Boris Lytochkin Date: Sun, 20 Sep 2015 17:05:22 +0300 Subject: [PATCH 092/643] Log serial number of revoked certificate In most of situations admin of OpenVPN server needs to know which particular certificate is used by client. In the case when certificate is OK, environment variable can be used for that but once it is revoked, no user scripts are invoked so there is no way to get serial number: only subject is printed in logs. So we log certificate serial in case it is revoked. Sponsored-by: Yandex LLC Signed-off-by: Boris Lytochkin Acked-by: Steffan Karger Message-Id: <55FEBF7E.3010209@yandex-team.ru> URL: http://article.gmane.org/gmane.network.openvpn.devel/10154 Signed-off-by: Gert Doering --- src/openvpn/ssl_verify_openssl.c | 6 +++++- src/openvpn/ssl_verify_polarssl.c | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/openvpn/ssl_verify_openssl.c b/src/openvpn/ssl_verify_openssl.c index 81b2e38da81..bf535227d50 100644 --- a/src/openvpn/ssl_verify_openssl.c +++ b/src/openvpn/ssl_verify_openssl.c @@ -585,6 +585,8 @@ x509_verify_crl(const char *crl_file, X509 *peer_cert, const char *subject) BIO *in=NULL; int n,i; result_t retval = FAILURE; + struct gc_arena gc = gc_new(); + char *serial; in = BIO_new_file (crl_file, "r"); @@ -609,7 +611,8 @@ x509_verify_crl(const char *crl_file, X509 *peer_cert, const char *subject) for (i = 0; i < n; i++) { revoked = (X509_REVOKED *)sk_X509_REVOKED_value(X509_CRL_get_REVOKED(crl), i); if (ASN1_INTEGER_cmp(revoked->serialNumber, X509_get_serialNumber(peer_cert)) == 0) { - msg (D_HANDSHAKE, "CRL CHECK FAILED: %s is REVOKED",subject); + serial = backend_x509_get_serial_hex(peer_cert, &gc); + msg (D_HANDSHAKE, "CRL CHECK FAILED: %s (serial %s) is REVOKED", subject, (serial ? serial : "NOT AVAILABLE")); goto end; } } @@ -618,6 +621,7 @@ x509_verify_crl(const char *crl_file, X509 *peer_cert, const char *subject) msg (D_HANDSHAKE, "CRL CHECK OK: %s",subject); end: + gc_free(&gc); BIO_free(in); if (crl) X509_CRL_free (crl); diff --git a/src/openvpn/ssl_verify_polarssl.c b/src/openvpn/ssl_verify_polarssl.c index 2edf21dd3dd..4852243e240 100644 --- a/src/openvpn/ssl_verify_polarssl.c +++ b/src/openvpn/ssl_verify_polarssl.c @@ -373,6 +373,8 @@ x509_verify_crl(const char *crl_file, x509_crt *cert, const char *subject) { result_t retval = FAILURE; x509_crl crl = {0}; + struct gc_arena gc = gc_new(); + char *serial; int polar_retval = x509_crl_parse_file(&crl, crl_file); if (polar_retval != 0) @@ -394,7 +396,8 @@ x509_verify_crl(const char *crl_file, x509_crt *cert, const char *subject) if (0 != x509_crt_revoked(cert, &crl)) { - msg (D_HANDSHAKE, "CRL CHECK FAILED: %s is REVOKED", subject); + serial = backend_x509_get_serial_hex(cert, &gc); + msg (D_HANDSHAKE, "CRL CHECK FAILED: %s (serial %s) is REVOKED", subject, (serial ? serial : "NOT AVAILABLE")); goto end; } @@ -402,6 +405,7 @@ x509_verify_crl(const char *crl_file, x509_crt *cert, const char *subject) msg (D_HANDSHAKE, "CRL CHECK OK: %s",subject); end: + gc_free(&gc); x509_crl_free(&crl); return retval; } From 2e2a34181962b33d70c34c28dcb1e1977c2fd54e Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Thu, 27 Aug 2015 15:00:02 +0200 Subject: [PATCH 093/643] Replace unaligned 16bit access to TCP MSS value with bytewise access TCP options are not always word-aligned, and accessing a 16bit value at an odd memory address will cause a "bus error" crash on some architectures, e.g. Linux/Sparc(64) Trac #497 Signed-off-by: Gert Doering Acked-by: Steffan Karger Message-Id: <1440680402-96548-1-git-send-email-gert@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/10056 --- src/openvpn/mss.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/openvpn/mss.c b/src/openvpn/mss.c index 64fd722feba..7298c7bb5db 100644 --- a/src/openvpn/mss.c +++ b/src/openvpn/mss.c @@ -129,7 +129,7 @@ mss_fixup_dowork (struct buffer *buf, uint16_t maxmss) { int hlen, olen, optlen; uint8_t *opt; - uint16_t *mss; + uint16_t mssval; int accumulate; struct openvpn_tcphdr *tc; @@ -159,14 +159,13 @@ mss_fixup_dowork (struct buffer *buf, uint16_t maxmss) if (*opt == OPENVPN_TCPOPT_MAXSEG) { if (optlen != OPENVPN_TCPOLEN_MAXSEG) continue; - mss = (uint16_t *)(opt + 2); - if (ntohs (*mss) > maxmss) { - dmsg (D_MSS, "MSS: %d -> %d", - (int) ntohs (*mss), - (int) maxmss); - accumulate = *mss; - *mss = htons (maxmss); - accumulate -= *mss; + mssval = (opt[2]<<8)+opt[3]; + if (mssval > maxmss) { + dmsg (D_MSS, "MSS: %d -> %d", (int) mssval, (int) maxmss); + accumulate = htons(mssval); + opt[2] = (maxmss>>8)&0xff; + opt[3] = maxmss&0xff; + accumulate -= htons(maxmss); ADJUST_CHECKSUM (accumulate, tc->check); } } From c40f088e52132273f6d4e83d05fa64bbaedd860f Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Fri, 25 Sep 2015 08:36:10 +0200 Subject: [PATCH 094/643] Repair test_local_addr() on WIN32 Intermediate result was stored in a "bool" variable, but the actual range of results is 0/1/2 - so "2" (TLA_LOCAL) never worked. Change to "int". Diagnosed by "dferbas" in trac #609 (thanks). Signed-off-by: Gert Doering Acked-by: Steffan Karger Message-Id: <1443162970-38210-1-git-send-email-gert@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/10168 --- src/openvpn/route.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openvpn/route.c b/src/openvpn/route.c index c011f993e9b..1b35396457d 100644 --- a/src/openvpn/route.c +++ b/src/openvpn/route.c @@ -3547,7 +3547,7 @@ test_local_addr (const in_addr_t addr, const struct route_gateway_info *rgi) { struct gc_arena gc = gc_new (); const in_addr_t nonlocal_netmask = 0x80000000L; /* routes with netmask <= to this are considered non-local */ - bool ret = TLA_NONLOCAL; + int ret = TLA_NONLOCAL; /* get full routing table */ const MIB_IPFORWARDTABLE *rt = get_windows_routing_table (&gc); From ddc7692d245017c71adc40ad5cc195617e39fce0 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Mon, 21 Sep 2015 20:48:33 +0200 Subject: [PATCH 095/643] Replace strdup() calls for string_alloc() calls As reported by Bill Parker in trac #600, strdup() return values are not always correctly checked for failed allocations. This patch adds missing checks by using string_alloc(), which performs the required checks. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <561130FC.8090008@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/10176 Signed-off-by: Gert Doering --- src/openvpn/buffer.h | 2 +- src/openvpn/cryptoapi.c | 4 +++- src/openvpn/init.c | 2 +- src/openvpn/misc.c | 2 +- src/openvpn/options.c | 2 +- src/openvpn/ssl_polarssl.c | 2 +- 6 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/openvpn/buffer.h b/src/openvpn/buffer.h index 0dc511b0ff8..24f52aa389a 100644 --- a/src/openvpn/buffer.h +++ b/src/openvpn/buffer.h @@ -898,7 +898,7 @@ gc_reset (struct gc_arena *a) } static inline void -check_malloc_return (void *p) +check_malloc_return (const void *p) { if (!p) out_of_memory (); diff --git a/src/openvpn/cryptoapi.c b/src/openvpn/cryptoapi.c index b7fc11e0701..1d54ee7276a 100644 --- a/src/openvpn/cryptoapi.c +++ b/src/openvpn/cryptoapi.c @@ -46,6 +46,8 @@ #include #include +#include "buffer.h" + /* MinGW w32api 3.17 is still incomplete when it comes to CryptoAPI while * MinGW32-w64 defines all macros used. This is a hack around that problem. */ @@ -116,7 +118,7 @@ static char *ms_error_text(DWORD ms_err) (LPTSTR) &lpMsgBuf, 0, NULL); if (lpMsgBuf) { char *p; - rv = strdup(lpMsgBuf); + rv = string_alloc(lpMsgBuf, NULL); LocalFree(lpMsgBuf); /* trim to the left */ if (rv) diff --git a/src/openvpn/init.c b/src/openvpn/init.c index f568d8745f7..3decd2367c1 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -822,7 +822,7 @@ void init_options_dev (struct options *options) { if (!options->dev && options->dev_node) { - char *dev_node = strdup(options->dev_node); /* POSIX basename() implementaions may modify its arguments */ + char *dev_node = string_alloc(options->dev_node, NULL); /* POSIX basename() implementaions may modify its arguments */ options->dev = basename (dev_node); } } diff --git a/src/openvpn/misc.c b/src/openvpn/misc.c index 895e9facf94..fd1930ae42a 100644 --- a/src/openvpn/misc.c +++ b/src/openvpn/misc.c @@ -1615,7 +1615,7 @@ argv_extract_cmd_name (const char *path) { if (path) { - char *path_cp = strdup(path); /* POSIX basename() implementaions may modify its arguments */ + char *path_cp = string_alloc(path, NULL); /* POSIX basename() implementaions may modify its arguments */ const char *bn = basename (path_cp); if (bn) { diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 5ace1f34710..de4fa38ebe7 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -2578,7 +2578,7 @@ check_file_access(const int type, const char *file, const int mode, const char * /* Is the directory path leading to the given file accessible? */ if (type & CHKACC_DIRPATH) { - char *fullpath = strdup(file); /* POSIX dirname() implementaion may modify its arguments */ + char *fullpath = string_alloc (file, NULL); /* POSIX dirname() implementaion may modify its arguments */ char *dirpath = dirname(fullpath); if (platform_access (dirpath, mode|X_OK) != 0) diff --git a/src/openvpn/ssl_polarssl.c b/src/openvpn/ssl_polarssl.c index dd0fab0bd33..11c9ffbc779 100644 --- a/src/openvpn/ssl_polarssl.c +++ b/src/openvpn/ssl_polarssl.c @@ -197,7 +197,7 @@ tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers) /* Parse allowed ciphers, getting IDs */ i = 0; - tmp_ciphers_orig = tmp_ciphers = strdup(ciphers); + tmp_ciphers_orig = tmp_ciphers = string_alloc (ciphers, NULL); token = strtok (tmp_ciphers, ":"); while(token) From 5584b738a332d0abc740d9303c275764c2ca13f1 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Mon, 21 Sep 2015 22:04:19 +0200 Subject: [PATCH 096/643] Check return value of ms_error_text() ms_error_text() may return NULL, and it is unclear (or, at least undocumented) whether the OpenSSL ERR code (and our code using the ERR code) can deal with esd->string being NULL. So, just to be sure, check that ms_error_text() succeeded before passing the result to ERR_load_strings(). Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <561130FC.8090008@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/10176 Signed-off-by: Gert Doering --- src/openvpn/cryptoapi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/openvpn/cryptoapi.c b/src/openvpn/cryptoapi.c index 1d54ee7276a..853c07b19c0 100644 --- a/src/openvpn/cryptoapi.c +++ b/src/openvpn/cryptoapi.c @@ -164,6 +164,7 @@ static void err_put_ms_error(DWORD ms_err, int func, const char *file, int line) err_map[i].ms_err = ms_err; err_map[i].err = esd->error = i + 100; esd->string = ms_error_text(ms_err); + check_malloc_return(esd->string); ERR_load_strings(ERR_LIB_CRYPTOAPI, esd); ERR_PUT_error(ERR_LIB_CRYPTOAPI, func, err_map[i].err, file, line); break; From f96baabc6cf10edddedda1819a27a6927f274d8e Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Tue, 22 Sep 2015 22:31:24 +0200 Subject: [PATCH 097/643] Add custom check for inet_pton()/inet_ntop() on MinGW/WIN32 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit More recent MinGW versions have these functions (if compiling at _VISTA level or higher), but the normal AC_CHECK_FUNCS() check does not find them because the necessary header file is not #include'd and the libws2_32 not linked - and our compat functions are incompatible with the definitions in , so compilation fails. Fix with a custom AC_LINK_IFELSE()/AC_LANG_PROGRAM() construct. Signed-off-by: Gert Doering Tested-by: Heiko Hund Tested-by: Samuli Seppänen Lazy-ACK-by: Gert Doering Message-Id: <1442953884-54602-1-git-send-email-gert@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/10165 --- configure.ac | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 51ef93b0b62..31cff257af7 100644 --- a/configure.ac +++ b/configure.ac @@ -632,7 +632,7 @@ AC_SUBST([SOCKETS_LIBS]) old_LIBS="${LIBS}" LIBS="${LIBS} ${SOCKETS_LIBS}" -AC_CHECK_FUNCS([sendmsg recvmsg inet_ntop inet_pton]) +AC_CHECK_FUNCS([sendmsg recvmsg]) # Windows use stdcall for winsock so we cannot auto detect these m4_define( [SOCKET_FUNCS], @@ -644,6 +644,27 @@ m4_define( [setsockopt getsockopt getsockname poll]dnl ) if test "${WIN32}" = "yes"; then +# normal autoconf function checking does not find inet_ntop/inet_pton +# because they need to include the actual header file and link ws2_32.dll + LIBS="${LIBS} -lws2_32" + AC_MSG_CHECKING([for MinGW inet_ntop()/inet_pton()]) + AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [[ +#include + ]], + [[ +int r = (int) inet_ntop (0, NULL, NULL, 0); + r += inet_pton(AF_INET, NULL, NULL); +return r; + ]] + )], + [AC_MSG_RESULT([OK]) + AC_DEFINE([HAVE_INET_NTOP],[1],[MinGW inet_ntop]) + AC_DEFINE([HAVE_INET_PTON],[1],[MinGW inet_pton]) + ], + [AC_MSG_RESULT([not found])] + ) m4_foreach( [F], m4_split(SOCKET_FUNCS SOCKET_OPT_FUNCS), @@ -651,6 +672,7 @@ if test "${WIN32}" = "yes"; then AC_DEFINE([UF], [1], [Win32 builtin]) ) else + AC_CHECK_FUNCS([inet_ntop inet_pton]) AC_CHECK_FUNCS( SOCKET_FUNCS, , From 5fcd49336812053aa1503078c0ebb72a2737a6b8 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Fri, 11 Sep 2015 17:33:47 +0200 Subject: [PATCH 098/643] get_default_gateway_ipv6(): Win32 implementation using GetBestRoute2() To get access to that functionality, bump Windows API level for MinGW compilation from NTDDI_WINXP/_WIN32_WINNT_WINXP to ..._VISTA, and shuffle around WIN32 includes a bit in syshead.h MinGW 32 seems to be broken regarding MIB_TCP_STATE enum, so add typedef for that - surrounding #ifdefs found by googling do not work yet -> TODO! Extend add_route_ipv6() and delete_route_ipv6() to handle routes not on the tap adapter but on ifindex-addressed interfaces ("interface=nn"), and while at it, fix deletion of IPv6 routes with gateway address. NOTE: this breaks Windows XP compatibility as GetBestRoute2() is not available there, so even when not using IPv6, the binary will not run. (Lightly) tested on Win7/64. Signed-off-by: Gert Doering Lazy-ACK-by: Gert Doering Message-Id: <1441985627-14822-11-git-send-email-gert@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/10085 --- configure.ac | 2 +- src/openvpn/route.c | 92 ++++++++++++++++++++++++++++++++++++++++--- src/openvpn/syshead.h | 7 +++- 3 files changed, 93 insertions(+), 8 deletions(-) diff --git a/configure.ac b/configure.ac index 31cff257af7..2e651d8e8e6 100644 --- a/configure.ac +++ b/configure.ac @@ -348,7 +348,7 @@ case "$host" in AC_DEFINE([TARGET_WIN32], [1], [Are we running WIN32?]) AC_DEFINE_UNQUOTED([TARGET_PREFIX], ["W"], [Target prefix]) CPPFLAGS="${CPPFLAGS} -DWIN32_LEAN_AND_MEAN" - CPPFLAGS="${CPPFLAGS} -DNTDDI_VERSION=NTDDI_WINXP -D_WIN32_WINNT=_WIN32_WINNT_WINXP" + CPPFLAGS="${CPPFLAGS} -DNTDDI_VERSION=NTDDI_VISTA -D_WIN32_WINNT=_WIN32_WINNT_VISTA" WIN32=yes ;; *-*-dragonfly*) diff --git a/src/openvpn/route.c b/src/openvpn/route.c index 1b35396457d..096e3bc3d68 100644 --- a/src/openvpn/route.c +++ b/src/openvpn/route.c @@ -1767,6 +1767,14 @@ add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int fla #elif defined (WIN32) + if ( r6->adapter_index ) /* vpn server special route */ + { + struct buffer out = alloc_buf_gc (64, &gc); + buf_printf (&out, "interface=%d", r6->adapter_index ); + device = buf_bptr(&out); + gateway_needed = true; + } + /* netsh interface ipv6 add route 2001:db8::/32 MyTunDevice */ argv_printf (&argv, "%s%sc interface ipv6 add route %s/%d %s", get_win_sys_path(), @@ -1782,7 +1790,7 @@ add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int fla */ if ( tt->type == DEV_TYPE_TUN && !gateway_needed ) argv_printf_cat( &argv, " %s", "fe80::8" ); - else + else if ( !IN6_IS_ADDR_UNSPECIFIED(&r6->gateway) ) argv_printf_cat( &argv, " %s", gateway ); #if 0 @@ -2157,6 +2165,14 @@ delete_route_ipv6 (const struct route_ipv6 *r6, const struct tuntap *tt, unsigne #elif defined (WIN32) + if ( r6->adapter_index ) /* vpn server special route */ + { + struct buffer out = alloc_buf_gc (64, &gc); + buf_printf (&out, "interface=%d", r6->adapter_index ); + device = buf_bptr(&out); + gateway_needed = true; + } + /* netsh interface ipv6 delete route 2001:db8::/32 MyTunDevice */ argv_printf (&argv, "%s%sc interface ipv6 delete route %s/%d %s", get_win_sys_path(), @@ -2171,9 +2187,9 @@ delete_route_ipv6 (const struct route_ipv6 *r6, const struct tuntap *tt, unsigne * knows about and will answer ND (neighbor discovery) packets for * (and "route deletion without specifying next-hop" does not work...) */ - if ( tt->type == DEV_TYPE_TUN ) + if ( tt->type == DEV_TYPE_TUN && !gateway_needed ) argv_printf_cat( &argv, " %s", "fe80::8" ); - else + else if ( !IN6_IS_ADDR_UNSPECIFIED(&r6->gateway) ) argv_printf_cat( &argv, " %s", gateway ); #if 0 @@ -2497,15 +2513,79 @@ windows_route_find_if_index (const struct route_ipv4 *r, const struct tuntap *tt return ret; } -/* IPv6 implementation using GetIpForwardTable2() and dynamic linking (TBD) - * https://msdn.microsoft.com/en-us/library/windows/desktop/aa814416(v=vs.85).aspx +/* IPv6 implementation using GetBestRoute2() + * (TBD: dynamic linking so the binary can still run on XP?) + * https://msdn.microsoft.com/en-us/library/windows/desktop/aa365922(v=vs.85).aspx + * https://msdn.microsoft.com/en-us/library/windows/desktop/aa814411(v=vs.85).aspx */ void get_default_gateway_ipv6(struct route_ipv6_gateway_info *rgi6, const struct in6_addr *dest) { - msg(D_ROUTE, "no support for get_default_gateway_ipv6() on this system (windows)"); + struct gc_arena gc = gc_new (); + MIB_IPFORWARD_ROW2 BestRoute; + SOCKADDR_INET DestinationAddress, BestSourceAddress; + DWORD BestIfIndex; + DWORD status; + NET_LUID InterfaceLuid; + CLEAR(*rgi6); + CLEAR(InterfaceLuid); // cleared = not used for lookup + CLEAR(DestinationAddress); + + DestinationAddress.si_family = AF_INET6; + if ( dest ) + { + DestinationAddress.Ipv6.sin6_addr = *dest; + } + + status = GetBestInterfaceEx( &DestinationAddress, &BestIfIndex ); + + if (status != NO_ERROR) + { + msg (D_ROUTE, "NOTE: GetBestInterfaceEx returned error: %s (code=%u)", + strerror_win32 (status, &gc), + (unsigned int)status); + goto done; + } + + msg( D_ROUTE, "GetBestInterfaceEx() returned if=%d", (int) BestIfIndex ); + + status = GetBestRoute2( &InterfaceLuid, BestIfIndex, NULL, + &DestinationAddress, 0, + &BestRoute, &BestSourceAddress ); + + if (status != NO_ERROR) + { + msg (D_ROUTE, "NOTE: GetIpForwardEntry2 returned error: %s (code=%u)", + strerror_win32 (status, &gc), + (unsigned int)status); + goto done; + } + + msg( D_ROUTE, "GDG6: II=%d DP=%s/%d NH=%s", + BestRoute.InterfaceIndex, + print_in6_addr( BestRoute.DestinationPrefix.Prefix.Ipv6.sin6_addr, 0, &gc), + BestRoute.DestinationPrefix.PrefixLength, + print_in6_addr( BestRoute.NextHop.Ipv6.sin6_addr, 0, &gc) ); + msg( D_ROUTE, "GDG6: Metric=%d, Loopback=%d, AA=%d, I=%d", + (int) BestRoute.Metric, + (int) BestRoute.Loopback, + (int) BestRoute.AutoconfigureAddress, + (int) BestRoute.Immortal ); + + rgi6->gateway.addr_ipv6 = BestRoute.NextHop.Ipv6.sin6_addr; + rgi6->adapter_index = BestRoute.InterfaceIndex; + rgi6->flags |= RGI_ADDR_DEFINED | RGI_IFACE_DEFINED; + + /* on-link is signalled by receiving an empty (::) NextHop */ + if ( IN6_IS_ADDR_UNSPECIFIED(&BestRoute.NextHop.Ipv6.sin6_addr) ) + { + rgi6->flags |= RGI_ON_LINK; + } + + done: + gc_free (&gc); } bool diff --git a/src/openvpn/syshead.h b/src/openvpn/syshead.h index 4bebb25a5c8..ba3b7e4a643 100644 --- a/src/openvpn/syshead.h +++ b/src/openvpn/syshead.h @@ -358,8 +358,13 @@ #endif /* TARGET_DARWIN */ #ifdef WIN32 -#include + // Missing declarations for MinGW 32. + // #if !defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 2 + typedef int MIB_TCP_STATE; + // #endif +#include #include +#include #include #include /* The following two headers are needed of PF_INET6 */ From 123092a7a95f13f0509d2dc52ec049f91a02686d Mon Sep 17 00:00:00 2001 From: Lev Stipakov Date: Fri, 2 Oct 2015 14:46:41 +0300 Subject: [PATCH 099/643] This fixes MSVS 2013 compilation. * Tools version changed to 12 * Added comp.c/h and compat.c/h to project files * Workaround for missing __attribute__ support Also, as a preparation for MSVS2015, ensured that snprintf is not defined for that VS version. Acked-by: Gert Doering Message-Id: <1443786401-30416-1-git-send-email-lstipakov@gmail.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/10174 Signed-off-by: Gert Doering --- config-msvc.h | 3 +++ src/compat/compat.vcxproj | 6 ++++-- src/openvpn/openvpn.vcxproj | 10 ++++++++-- src/openvpn/syshead.h | 1 + src/openvpnserv/openvpnserv.vcxproj | 6 ++++-- 5 files changed, 20 insertions(+), 6 deletions(-) diff --git a/config-msvc.h b/config-msvc.h index 8294c2c7c62..ffd35f4f4a0 100644 --- a/config-msvc.h +++ b/config-msvc.h @@ -90,7 +90,10 @@ #define strncasecmp strnicmp #define strcasecmp _stricmp + +#if _MSC_VER<1900 #define snprintf _snprintf +#endif #if _MSC_VER < 1800 #define strtoull strtoul diff --git a/src/compat/compat.vcxproj b/src/compat/compat.vcxproj index 42979c11904..7fca62fc03d 100644 --- a/src/compat/compat.vcxproj +++ b/src/compat/compat.vcxproj @@ -1,5 +1,5 @@  - + Debug @@ -20,10 +20,12 @@ StaticLibrary MultiByte true + v120 StaticLibrary MultiByte + v120 @@ -84,4 +86,4 @@ - \ No newline at end of file + diff --git a/src/openvpn/openvpn.vcxproj b/src/openvpn/openvpn.vcxproj index 3b2340ee482..b117b0b640c 100755 --- a/src/openvpn/openvpn.vcxproj +++ b/src/openvpn/openvpn.vcxproj @@ -1,5 +1,5 @@  - + Debug @@ -20,10 +20,12 @@ Application true Unicode + v120 Application Unicode + v120 @@ -100,6 +102,8 @@ + + @@ -168,6 +172,8 @@ + + @@ -260,4 +266,4 @@ - \ No newline at end of file + diff --git a/src/openvpn/syshead.h b/src/openvpn/syshead.h index ba3b7e4a643..3aa5c5f1963 100644 --- a/src/openvpn/syshead.h +++ b/src/openvpn/syshead.h @@ -47,6 +47,7 @@ #ifdef _MSC_VER // Visual Studio #define __func__ __FUNCTION__ +#define __attribute__(x) #endif #if defined(__APPLE__) diff --git a/src/openvpnserv/openvpnserv.vcxproj b/src/openvpnserv/openvpnserv.vcxproj index 0b75ed01d46..c6760daf5b5 100644 --- a/src/openvpnserv/openvpnserv.vcxproj +++ b/src/openvpnserv/openvpnserv.vcxproj @@ -1,5 +1,5 @@  - + Debug @@ -20,10 +20,12 @@ Application MultiByte true + v120 Application MultiByte + v120 @@ -109,4 +111,4 @@ - \ No newline at end of file + From 6ef5df14917500f107fd843a6dba61355edaeea0 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sun, 8 Mar 2015 11:20:04 +0100 Subject: [PATCH 100/643] polarssl: add easy logging for PolarSSL errors Add the functions polar_log_err(), polar_log_func_line() and a macro polar_ok(), to easily log human-readable PolarSSL errors from polarssl-specific code. This does not provide the full logging interface as msg(), because I would have to add a lot more of macro-magic to achieve that on the various supported compilers and platforms, and this suffices too (for now at least). Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1425810005-11893-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/9528 Signed-off-by: Gert Doering --- src/openvpn/crypto_polarssl.c | 27 +++++++++++++++++++++++ src/openvpn/crypto_polarssl.h | 40 +++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/src/openvpn/crypto_polarssl.c b/src/openvpn/crypto_polarssl.c index e083398fe22..263b4dc2da1 100644 --- a/src/openvpn/crypto_polarssl.c +++ b/src/openvpn/crypto_polarssl.c @@ -46,6 +46,7 @@ #include "misc.h" #include +#include #include #include #include @@ -86,6 +87,32 @@ crypto_clear_error (void) { } +bool polar_log_err(unsigned int flags, int errval, const char *prefix) +{ + if (0 != errval) + { + char errstr[256]; + polarssl_strerror(errval, errstr, sizeof(errstr)); + + if (NULL == prefix) prefix = "PolarSSL error"; + msg (flags, "%s: %s", prefix, errstr); + } + + return 0 == errval; +} + +bool polar_log_func_line(unsigned int flags, int errval, const char *func, + int line) +{ + char prefix[256]; + + if (!openvpn_snprintf(prefix, sizeof(prefix), "%s:%d", func, line)) + return polar_log_err(flags, errval, func); + + return polar_log_err(flags, errval, prefix); +} + + #ifdef DMALLOC void crypto_init_dmalloc (void) diff --git a/src/openvpn/crypto_polarssl.h b/src/openvpn/crypto_polarssl.h index b6da43636be..bd0f8b865d9 100644 --- a/src/openvpn/crypto_polarssl.h +++ b/src/openvpn/crypto_polarssl.h @@ -91,4 +91,44 @@ ctr_drbg_context * rand_ctx_get(); void rand_ctx_enable_prediction_resistance(); #endif +/** + * Log the supplied PolarSSL error, prefixed by supplied prefix. + * + * @param flags Flags to indicate error type and priority. + * @param errval PolarSSL error code to convert to error message. + * @param prefix Prefix to PolarSSL error message. + * + * @returns true if no errors are detected, false otherwise. + */ +bool polar_log_err(unsigned int flags, int errval, const char *prefix); + +/** + * Log the supplied PolarSSL error, prefixed by function name and line number. + * + * @param flags Flags to indicate error type and priority. + * @param errval PolarSSL error code to convert to error message. + * @param func Function name where error was reported. + * @param line Line number where error was reported. + * + * @returns true if no errors are detected, false otherwise. + */ +bool polar_log_func_line(unsigned int flags, int errval, const char *func, + int line); + +/** + * Check errval and log on error. + * + * Convenience wrapper to put around polarssl library calls, e.g. + * if (!polar_ok(polarssl_func())) return 0; + * or + * ASSERT (polar_ok(polarssl_func())); + * + * @param errval PolarSSL error code to convert to error message. + * + * @returns true if no errors are detected, false otherwise. + */ +#define polar_ok(errval) \ + polar_log_func_line(D_CRYPT_ERRORS, errval, __func__, __LINE__) + + #endif /* CRYPTO_POLARSSL_H_ */ From b0fe94115fc4a75094d15452b7b89a0c0849087c Mon Sep 17 00:00:00 2001 From: Lev Stipakov Date: Tue, 6 Oct 2015 14:15:13 +0300 Subject: [PATCH 101/643] Continuation of MSVS fixes * Upgrade API level to Vista to implement get_default_gateway_ipv6 * Define HAVE_INET_NTOP/PTON since Vista has its own implementation of those Signed-off-by: Lev Stipakov Acked-by: Gert Doering Message-Id: <1444130113-23387-1-git-send-email-lstipakov@gmail.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/10194 Signed-off-by: Gert Doering --- config-msvc.h | 5 +++++ msvc-env.bat | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/config-msvc.h b/config-msvc.h index ffd35f4f4a0..aa0eefff5b7 100644 --- a/config-msvc.h +++ b/config-msvc.h @@ -128,3 +128,8 @@ typedef __int8 int8_t; #include #endif +// Vista and above has implementation of inet_ntop / inet_pton +#if _WIN32_WINNT >= _WIN32_WINNT_VISTA + #define HAVE_INET_NTOP + #define HAVE_INET_PTON +#endif diff --git a/msvc-env.bat b/msvc-env.bat index 2dd0f00d6ee..aabed750e93 100644 --- a/msvc-env.bat +++ b/msvc-env.bat @@ -12,7 +12,7 @@ if "%VCHOME%"=="" SET VCHOME=%VSHOME%\VC set SOURCEBASE=%cd% set SOLUTION=openvpn.sln set CPPFLAGS=%CPPFLAGS%;_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS -set CPPFLAGS=%CPPFLAGS%;NTDDI_VERSION=NTDDI_WINXP;_WIN32_WINNT=_WIN32_WINNT_WINXP +set CPPFLAGS=%CPPFLAGS%;NTDDI_VERSION=NTDDI_VISTA;_WIN32_WINNT=_WIN32_WINNT_VISTA set CPPFLAGS=%CPPFLAGS%;_USE_32BIT_TIME_T set CPPFLAGS=%CPPFLAGS%;%EXTRA_CPPFLAGS% From d17d362dfec1abc5bedcea2f1154470018c82eca Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Tue, 6 Oct 2015 18:20:40 +0200 Subject: [PATCH 102/643] polarssl: Improve PolarSSL logging Use the new polar_log_err() and polar_ok() functions introduced in the previous commit to provide more log/debug output for polarssl errors. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1444148440-10564-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/10197 Signed-off-by: Gert Doering --- src/openvpn/crypto_polarssl.c | 35 ++++++------ src/openvpn/ssl_polarssl.c | 89 +++++++++++++------------------ src/openvpn/ssl_verify_polarssl.c | 26 +++------ 3 files changed, 64 insertions(+), 86 deletions(-) diff --git a/src/openvpn/crypto_polarssl.c b/src/openvpn/crypto_polarssl.c index 263b4dc2da1..c038f8e2601 100644 --- a/src/openvpn/crypto_polarssl.c +++ b/src/openvpn/crypto_polarssl.c @@ -261,7 +261,8 @@ ctr_drbg_context * rand_ctx_get() /* Initialise PolarSSL RNG, and built-in entropy sources */ entropy_init(&ec); - if (0 != ctr_drbg_init(&cd_ctx, entropy_func, &ec, BPTR(&pers_string), BLEN(&pers_string))) + if (!polar_ok(ctr_drbg_init(&cd_ctx, entropy_func, &ec, + BPTR(&pers_string), BLEN(&pers_string)))) msg (M_FATAL, "Failed to initialize random generator"); gc_free(&gc); @@ -472,10 +473,10 @@ cipher_ctx_init (cipher_context_t *ctx, uint8_t *key, int key_len, CLEAR (*ctx); - if (0 != cipher_init_ctx(ctx, kt)) + if (!polar_ok(cipher_init_ctx(ctx, kt))) msg (M_FATAL, "PolarSSL cipher context init #1"); - if (0 != cipher_setkey(ctx, key, key_len*8, enc)) + if (!polar_ok(cipher_setkey(ctx, key, key_len*8, enc))) msg (M_FATAL, "PolarSSL cipher set key"); /* make sure we used a big enough key */ @@ -484,7 +485,7 @@ cipher_ctx_init (cipher_context_t *ctx, uint8_t *key, int key_len, void cipher_ctx_cleanup (cipher_context_t *ctx) { - cipher_free_ctx(ctx); + ASSERT (polar_ok(cipher_free_ctx(ctx))); } int cipher_ctx_iv_length (const cipher_context_t *ctx) @@ -514,36 +515,38 @@ cipher_ctx_get_cipher_kt (const cipher_ctx_t *ctx) int cipher_ctx_reset (cipher_context_t *ctx, uint8_t *iv_buf) { - int retval = cipher_reset(ctx); + if (!polar_ok(cipher_reset(ctx))) + return 0; - if (0 == retval) - retval = cipher_set_iv(ctx, iv_buf, ctx->cipher_info->iv_size); + if (!polar_ok(cipher_set_iv(ctx, iv_buf, ctx->cipher_info->iv_size))) + return 0; - return 0 == retval; + return 1; } int cipher_ctx_update (cipher_context_t *ctx, uint8_t *dst, int *dst_len, uint8_t *src, int src_len) { - int retval = 0; size_t s_dst_len = *dst_len; - retval = cipher_update(ctx, src, (size_t)src_len, dst, &s_dst_len); + if (!polar_ok(cipher_update(ctx, src, (size_t)src_len, dst, &s_dst_len))) + return 0; *dst_len = s_dst_len; - return 0 == retval; + return 1; } int cipher_ctx_final (cipher_context_t *ctx, uint8_t *dst, int *dst_len) { - int retval = 0; size_t s_dst_len = *dst_len; - retval = cipher_finish(ctx, dst, &s_dst_len); + if (!polar_ok(cipher_finish(ctx, dst, &s_dst_len))) + return 0; + *dst_len = s_dst_len; - return 0 == retval; + return 1; } void @@ -553,8 +556,8 @@ cipher_des_encrypt_ecb (const unsigned char key[DES_KEY_LENGTH], { des_context ctx; - des_setkey_enc(&ctx, key); - des_crypt_ecb(&ctx, src, dst); + ASSERT (polar_ok(des_setkey_enc(&ctx, key))); + ASSERT (polar_ok(des_crypt_ecb(&ctx, src, dst))); } diff --git a/src/openvpn/ssl_polarssl.c b/src/openvpn/ssl_polarssl.c index 11c9ffbc779..20567354d57 100644 --- a/src/openvpn/ssl_polarssl.c +++ b/src/openvpn/ssl_polarssl.c @@ -218,13 +218,13 @@ tls_ctx_load_dh_params (struct tls_root_ctx *ctx, const char *dh_file, { if (!strcmp (dh_file, INLINE_FILE_TAG) && dh_inline) { - if (0 != dhm_parse_dhm(ctx->dhm_ctx, (const unsigned char *) dh_inline, - strlen(dh_inline))) + if (!polar_ok(dhm_parse_dhm(ctx->dhm_ctx, + (const unsigned char *) dh_inline, strlen(dh_inline)))) msg (M_FATAL, "Cannot read inline DH parameters"); } else { - if (0 != dhm_parse_dhmfile(ctx->dhm_ctx, dh_file)) + if (!polar_ok(dhm_parse_dhmfile(ctx->dhm_ctx, dh_file))) msg (M_FATAL, "Cannot read DH parameters from file %s", dh_file); } @@ -268,18 +268,15 @@ tls_ctx_load_cert_file (struct tls_root_ctx *ctx, const char *cert_file, if (!strcmp (cert_file, INLINE_FILE_TAG) && cert_inline) { - if (0 != x509_crt_parse(ctx->crt_chain, - (const unsigned char *) cert_inline, strlen(cert_inline))) + if (!polar_ok(x509_crt_parse(ctx->crt_chain, + (const unsigned char *) cert_inline, strlen(cert_inline)))) msg (M_FATAL, "Cannot load inline certificate file"); } else { - int retval = x509_crt_parse_file(ctx->crt_chain, cert_file); - if (0 != retval) + if (!polar_ok(x509_crt_parse_file(ctx->crt_chain, cert_file))) { - char errstr[128]; - polarssl_strerror(retval, errstr, sizeof(errstr)); - msg (M_FATAL, "Cannot load certificate file %s (%s)", cert_file, errstr); + msg (M_FATAL, "Cannot load certificate file %s", cert_file); } } } @@ -317,7 +314,7 @@ tls_ctx_load_priv_file (struct tls_root_ctx *ctx, const char *priv_key_file, status = pk_parse_keyfile(ctx->priv_key, priv_key_file, passbuf); } } - if (0 != status) + if (!polar_ok(status)) { #ifdef ENABLE_MANAGEMENT if (management && (POLARSSL_ERR_PK_PASSWORD_MISMATCH == status)) @@ -412,7 +409,7 @@ static inline int external_pkcs1_sign( void *ctx_voidptr, if( md_info == NULL ) return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); - if( oid_get_oid_by_md( md_alg, &oid, &oid_size ) != 0 ) + if (!polar_ok(oid_get_oid_by_md( md_alg, &oid, &oid_size ))) return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); hashlen = md_get_size( md_info ); @@ -497,49 +494,43 @@ static inline size_t external_key_len(void *vctx) #endif void tls_ctx_load_ca (struct tls_root_ctx *ctx, const char *ca_file, - const char *ca_file_inline, - const char *ca_path, bool tls_server + const char *ca_inline, const char *ca_path, bool tls_server ) { if (ca_path) msg(M_FATAL, "ERROR: PolarSSL cannot handle the capath directive"); - if (ca_file && !strcmp (ca_file, INLINE_FILE_TAG) && ca_file_inline) + if (ca_file && !strcmp (ca_file, INLINE_FILE_TAG) && ca_inline) { - if (0 != x509_crt_parse(ctx->ca_chain, (unsigned char *) ca_file_inline, - strlen(ca_file_inline))) + if (!polar_ok(x509_crt_parse(ctx->ca_chain, + (const unsigned char *) ca_inline, strlen(ca_inline)))) msg (M_FATAL, "Cannot load inline CA certificates"); } else { /* Load CA file for verifying peer supplied certificate */ - int retval = x509_crt_parse_file(ctx->ca_chain, ca_file); - if (0 != retval) - { - char errstr[128]; - polarssl_strerror(retval, errstr, sizeof(errstr)); - msg (M_FATAL, "Cannot load CA certificate file %s (%s)", ca_file, errstr); - } + if (!polar_ok(x509_crt_parse_file(ctx->ca_chain, ca_file))) + msg (M_FATAL, "Cannot load CA certificate file %s", ca_file); } } void tls_ctx_load_extra_certs (struct tls_root_ctx *ctx, const char *extra_certs_file, - const char *extra_certs_file_inline + const char *extra_certs_inline ) { ASSERT(NULL != ctx); - if (!strcmp (extra_certs_file, INLINE_FILE_TAG) && extra_certs_file_inline) + if (!strcmp (extra_certs_file, INLINE_FILE_TAG) && extra_certs_inline) { - if (0 != x509_crt_parse(ctx->crt_chain, - (unsigned char *) extra_certs_file_inline, - strlen(extra_certs_file_inline))) + if (!polar_ok(x509_crt_parse(ctx->crt_chain, + (const unsigned char *) extra_certs_inline, + strlen(extra_certs_inline)))) msg (M_FATAL, "Cannot load inline extra-certs file"); } else { - if (0 != x509_crt_parse_file(ctx->crt_chain, extra_certs_file)) + if (!polar_ok(x509_crt_parse_file(ctx->crt_chain, extra_certs_file))) msg (M_FATAL, "Cannot load extra-certs file: %s", extra_certs_file); } } @@ -645,10 +636,8 @@ static int endless_buf_write( void *ctx, const unsigned char *in, size_t len ) static void my_debug( void *ctx, int level, const char *str ) { - if (level == 1) - { - dmsg (D_HANDSHAKE_VERBOSE, "PolarSSL alert: %s", str); - } + int my_loglevel = (level < 2) ? D_TLS_DEBUG_MED : D_TLS_DEBUG; + msg (my_loglevel, "PolarSSL alert: %s", str); } /* @@ -727,7 +716,7 @@ void key_state_ssl_init(struct key_state_ssl *ks_ssl, CLEAR(*ks_ssl); ALLOC_OBJ_CLEAR(ks_ssl->ctx, ssl_context); - if (0 == ssl_init(ks_ssl->ctx)) + if (polar_ok(ssl_init(ks_ssl->ctx))) { /* Initialise SSL context */ ssl_set_dbg (ks_ssl->ctx, my_debug, NULL); @@ -748,22 +737,23 @@ void key_state_ssl_init(struct key_state_ssl *ks_ssl, /* Initialise authentication information */ if (is_server) - ssl_set_dh_param_ctx (ks_ssl->ctx, ssl_ctx->dhm_ctx ); + polar_ok(ssl_set_dh_param_ctx(ks_ssl->ctx, ssl_ctx->dhm_ctx)); #if defined(ENABLE_PKCS11) if (ssl_ctx->priv_key_pkcs11 != NULL) - ssl_set_own_cert_alt( ks_ssl->ctx, ssl_ctx->crt_chain, + polar_ok(ssl_set_own_cert_alt(ks_ssl->ctx, ssl_ctx->crt_chain, ssl_ctx->priv_key_pkcs11, ssl_pkcs11_decrypt, ssl_pkcs11_sign, - ssl_pkcs11_key_len ); + ssl_pkcs11_key_len)); else #endif #if defined(MANAGMENT_EXTERNAL_KEY) if (ssl_ctx->external_key != NULL) - ssl_set_own_cert_alt( ks_ssl->ctx, ssl_ctx->crt_chain, + polar_ok(ssl_set_own_cert_alt(ks_ssl->ctx, ssl_ctx->crt_chain, ssl_ctx->external_key, NULL, external_pkcs1_sign, - external_key_len ); + external_key_len)); else #endif - ssl_set_own_cert( ks_ssl->ctx, ssl_ctx->crt_chain, ssl_ctx->priv_key ); + polar_ok(ssl_set_own_cert(ks_ssl->ctx, ssl_ctx->crt_chain, + ssl_ctx->priv_key)); /* Initialise SSL verification */ #if P2MP_SERVER @@ -884,7 +874,8 @@ key_state_write_plaintext_const (struct key_state_ssl *ks, const uint8_t *data, perf_pop (); if (POLARSSL_ERR_NET_WANT_WRITE == retval || POLARSSL_ERR_NET_WANT_READ == retval) return 0; - msg (D_TLS_ERRORS, "TLS ERROR: write tls_write_plaintext_const error"); + polar_log_err (D_TLS_ERRORS, retval, + "TLS ERROR: write tls_write_plaintext_const error"); return -1; } @@ -910,7 +901,6 @@ key_state_read_ciphertext (struct key_state_ssl *ks, struct buffer *buf, { int retval = 0; int len = 0; - char error_message[1024]; perf_push (PERF_BIO_READ_CIPHERTEXT); @@ -936,8 +926,7 @@ key_state_read_ciphertext (struct key_state_ssl *ks, struct buffer *buf, perf_pop (); if (POLARSSL_ERR_NET_WANT_WRITE == retval || POLARSSL_ERR_NET_WANT_READ == retval) return 0; - error_strerror(retval, error_message, sizeof(error_message)); - msg (D_TLS_ERRORS, "TLS_ERROR: read tls_read_ciphertext error: %d %s", retval, error_message); + polar_log_err (D_TLS_ERRORS, retval, "TLS_ERROR: read tls_read_ciphertext error"); buf->len = 0; return -1; } @@ -980,14 +969,14 @@ key_state_write_ciphertext (struct key_state_ssl *ks, struct buffer *buf) if (POLARSSL_ERR_NET_WANT_WRITE == retval || POLARSSL_ERR_NET_WANT_READ == retval) return 0; - msg (D_TLS_ERRORS, "TLS ERROR: write tls_write_ciphertext error"); + polar_log_err (D_TLS_ERRORS, retval, + "TLS ERROR: write tls_write_ciphertext error"); return -1; } if (retval != buf->len) { - msg (D_TLS_ERRORS, - "TLS ERROR: write tls_write_ciphertext incomplete %d/%d", + msg (D_TLS_ERRORS, "TLS ERROR: write tls_write_ciphertext incomplete %d/%d", retval, buf->len); perf_pop (); return -1; @@ -1009,7 +998,6 @@ key_state_read_plaintext (struct key_state_ssl *ks, struct buffer *buf, { int retval = 0; int len = 0; - char error_message[1024]; perf_push (PERF_BIO_READ_PLAINTEXT); @@ -1034,8 +1022,7 @@ key_state_read_plaintext (struct key_state_ssl *ks, struct buffer *buf, { if (POLARSSL_ERR_NET_WANT_WRITE == retval || POLARSSL_ERR_NET_WANT_READ == retval) return 0; - error_strerror(retval, error_message, sizeof(error_message)); - msg (D_TLS_ERRORS, "TLS_ERROR: read tls_read_plaintext error: %d %s", retval, error_message); + polar_log_err (D_TLS_ERRORS, retval, "TLS_ERROR: read tls_read_plaintext error"); buf->len = 0; perf_pop (); return -1; diff --git a/src/openvpn/ssl_verify_polarssl.c b/src/openvpn/ssl_verify_polarssl.c index 4852243e240..fa313ac1721 100644 --- a/src/openvpn/ssl_verify_polarssl.c +++ b/src/openvpn/ssl_verify_polarssl.c @@ -134,17 +134,12 @@ backend_x509_get_serial (openvpn_x509_cert_t *cert, struct gc_arena *gc) char *buf = NULL; size_t buflen = 0; mpi serial_mpi = { 0 }; - int retval = 0; /* Transform asn1 integer serial into PolarSSL MPI */ mpi_init(&serial_mpi); - retval = mpi_read_binary(&serial_mpi, cert->serial.p, cert->serial.len); - if (retval < 0) + if (!polar_ok(mpi_read_binary(&serial_mpi, cert->serial.p, cert->serial.len))) { - char errbuf[128]; - polarssl_strerror(retval, errbuf, sizeof(errbuf)); - - msg(M_WARN, "Failed to retrieve serial from certificate: %s.", errbuf); + msg(M_WARN, "Failed to retrieve serial from certificate."); return NULL; } @@ -153,13 +148,9 @@ backend_x509_get_serial (openvpn_x509_cert_t *cert, struct gc_arena *gc) buf = gc_malloc(buflen, true, gc); /* Write MPI serial as decimal string into buffer */ - retval = mpi_write_string(&serial_mpi, 10, buf, &buflen); - if (retval < 0) + if (!polar_ok(mpi_write_string(&serial_mpi, 10, buf, &buflen))) { - char errbuf[128]; - polarssl_strerror(retval, errbuf, sizeof(errbuf)); - - msg(M_WARN, "Failed to write serial to string: %s.", errbuf); + msg(M_WARN, "Failed to write serial to string."); return NULL; } @@ -376,12 +367,9 @@ x509_verify_crl(const char *crl_file, x509_crt *cert, const char *subject) struct gc_arena gc = gc_new(); char *serial; - int polar_retval = x509_crl_parse_file(&crl, crl_file); - if (polar_retval != 0) + if (!polar_ok(x509_crl_parse_file(&crl, crl_file))) { - char errstr[128]; - polarssl_strerror(polar_retval, errstr, sizeof(errstr)); - msg (M_WARN, "CRL: cannot read CRL from file %s (%s)", crl_file, errstr); + msg (M_WARN, "CRL: cannot read CRL from file %s", crl_file); goto end; } @@ -394,7 +382,7 @@ x509_verify_crl(const char *crl_file, x509_crt *cert, const char *subject) goto end; } - if (0 != x509_crt_revoked(cert, &crl)) + if (!polar_ok(x509_crt_revoked(cert, &crl))) { serial = backend_x509_get_serial_hex(cert, &gc); msg (D_HANDSHAKE, "CRL CHECK FAILED: %s (serial %s) is REVOKED", subject, (serial ? serial : "NOT AVAILABLE")); From 7246ccfdbe6039c5c578ecaa07505307d53b8e84 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Tue, 6 Oct 2015 20:38:27 +0200 Subject: [PATCH 103/643] openssl: be less verbose about cipher translation errors Translation errors are usually not a real problem, since we don't maintain the complete list of ciphers OpenSSL supports. So, be less verbose if we can not find a translation. Also, add 'translations' for commonly used negated cipher suites to suppress messages about those completely. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1444156707-14087-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/10198 Signed-off-by: Gert Doering --- src/openvpn/ssl.c | 21 +++++++++++---------- src/openvpn/ssl_openssl.c | 2 +- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 54a3e094cf3..529d14dae4b 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -232,18 +232,19 @@ static const tls_cipher_name_pair tls_cipher_name_translation_table[] = { {"SRP-RSA-AES-128-CBC-SHA", "TLS-SRP-SHA-RSA-WITH-AES-128-CBC-SHA"}, {"SRP-RSA-AES-256-CBC-SHA", "TLS-SRP-SHA-RSA-WITH-AES-256-CBC-SHA"}, #ifdef ENABLE_CRYPTO_OPENSSL + /* OpenSSL-specific group names */ {"DEFAULT", "DEFAULT"}, {"ALL", "ALL"}, - {"HIGH", "HIGH"}, - {"MEDIUM", "MEDIUM"}, - {"LOW", "LOW"}, - {"ECDH", "ECDH"}, - {"ECDSA", "ECDSA"}, - {"EDH", "EDH"}, - {"EXP", "EXP"}, - {"RSA", "RSA"}, - {"kRSA", "kRSA"}, - {"SRP", "SRP"}, + {"HIGH", "HIGH"}, {"!HIGH", "!HIGH"}, + {"MEDIUM", "MEDIUM"}, {"!MEDIUM", "!MEDIUM"}, + {"LOW", "LOW"}, {"!LOW", "!LOW"}, + {"ECDH", "ECDH"}, {"!ECDH", "!ECDH"}, + {"ECDSA", "ECDSA"}, {"!ECDSA", "!ECDSA"}, + {"EDH", "EDH"}, {"!EDH", "!EDH"}, + {"EXP", "EXP"}, {"!EXP", "!EXP"}, + {"RSA", "RSA"}, {"!RSA", "!RSA"}, + {"kRSA", "kRSA"}, {"!kRSA", "!kRSA"}, + {"SRP", "SRP"}, {"!SRP", "!SRP"}, #endif {NULL, NULL} }; diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c index df9fa8734cb..a38c41b8172 100644 --- a/src/openvpn/ssl_openssl.c +++ b/src/openvpn/ssl_openssl.c @@ -272,7 +272,7 @@ tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers) // Issue warning on missing translation // %.*s format specifier expects length of type int, so guarantee // that length is small enough and cast to int. - msg (M_WARN, "No valid translation found for TLS cipher '%.*s'", + msg (D_LOW, "No valid translation found for TLS cipher '%.*s'", constrain_int(current_cipher_len, 0, 256), current_cipher); } else From 685e486e8b8f70c25f09590c24762ff734f94a51 Mon Sep 17 00:00:00 2001 From: Daniel Kubec Date: Thu, 12 Mar 2015 15:14:20 +0100 Subject: [PATCH 104/643] Added support for TLS Keying Material Exporters [RFC-5705] Keying Material Exporter [RFC-5705] allow additional keying material to be derived from existing TLS channel. This exported keying material can then be used for a variety of purposes. [DS: Updated man page to document both upper and lower length boundaries] Signed-off-by: Daniel Kubec Signed-off-by: David Sommerseth Acked-by: Steffan Karger --- doc/openvpn.8 | 12 ++++++++++++ src/openvpn/init.c | 16 ++++++++++++++++ src/openvpn/options.c | 27 +++++++++++++++++++++++++++ src/openvpn/options.h | 6 ++++++ src/openvpn/ssl.c | 4 ++++ src/openvpn/ssl_backend.h | 13 +++++++++++++ src/openvpn/ssl_common.h | 5 +++++ src/openvpn/ssl_openssl.c | 33 +++++++++++++++++++++++++++++++++ src/openvpn/ssl_polarssl.c | 6 ++++++ 9 files changed, 122 insertions(+) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index e213f5afb42..829b09cd83f 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -2757,6 +2757,18 @@ client\-connect), then every module and script must return success (0) in order for the connection to be authenticated. .\"********************************************************* +.TP +.B \-\-keying-material-exporter label len +Save Exported Keying Material [RFC5705] of len bytes (must be +between 16 and 4095 bytes) using label in environment +(exported_keying_material) for use by plugins in +OPENVPN_PLUGIN_TLS_FINAL callback. + +Note that exporter labels have the potential to collide with existing PRF +labels. In order to prevent this, labels MUST begin with "EXPORTER". + +This option requires OpenSSL 1.0.1 or newer. +.\"********************************************************* .SS Server Mode Starting with OpenVPN 2.0, a multi-client TCP/UDP server mode is supported, and can be enabled with the diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 3decd2367c1..c32a809d6d1 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -2279,6 +2279,22 @@ do_init_crypto_tls (struct context *c, const unsigned int flags) to.comp_options = options->comp; #endif +#if defined(ENABLE_CRYPTO_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10001000 + if (options->keying_material_exporter_label) + { + to.ekm_size = options->keying_material_exporter_length; + if (to.ekm_size < 16 || to.ekm_size > 4095) + to.ekm_size = 0; + + to.ekm_label = options->keying_material_exporter_label; + to.ekm_label_size = strlen(to.ekm_label); + } + else + { + to.ekm_size = 0; + } +#endif + /* TLS handshake authentication (--tls-auth) */ if (options->tls_auth_file) { diff --git a/src/openvpn/options.c b/src/openvpn/options.c index de4fa38ebe7..7906f46fd69 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -610,6 +610,10 @@ static const char usage_message[] = #ifdef ENABLE_X509_TRACK "--x509-track x : Save peer X509 attribute x in environment for use by\n" " plugins and management interface.\n" +#endif +#if defined(ENABLE_CRYPTO_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10001000 + "--keying-material-exporter label len : Save Exported Keying Material (RFC5705)\n" + " of len bytes (min. 16 bytes) using label in environment for use by plugins.\n" #endif "--remote-cert-ku v ... : Require that the peer certificate was signed with\n" " explicit key usage, you can specify more than one value.\n" @@ -7066,6 +7070,29 @@ add_option (struct options *options, options->use_peer_id = true; options->peer_id = atoi(p[1]); } +#if defined(ENABLE_CRYPTO_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10001000 + else if (streq (p[0], "keying-material-exporter") && p[1] && p[2]) + { + int ekm_length = positive_atoi (p[2]); + + VERIFY_PERMISSION (OPT_P_GENERAL); + + if (strncmp(p[1], "EXPORTER", 8)) + { + msg (msglevel, "Keying material exporter label must begin with " + "\"EXPORTER\""); + goto err; + } + if (ekm_length < 16 || ekm_length > 4095) + { + msg (msglevel, "Invalid keying material exporter length"); + goto err; + } + + options->keying_material_exporter_label = p[1]; + options->keying_material_exporter_length = ekm_length; + } +#endif else { int i; diff --git a/src/openvpn/options.h b/src/openvpn/options.h index abec83f7ebb..c642aa0df62 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -591,6 +591,12 @@ struct options bool use_peer_id; uint32_t peer_id; + +#if defined(ENABLE_CRYPTO_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10001000 + /* Keying Material Exporters [RFC 5705] */ + const char *keying_material_exporter_label; + int keying_material_exporter_length; +#endif }; #define streq(x, y) (!strcmp((x), (y))) diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 529d14dae4b..86eda77c09a 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -2160,8 +2160,12 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi */ if (ks->authenticated && plugin_defined (session->opt->plugins, OPENVPN_PLUGIN_TLS_FINAL)) { + key_state_export_keying_material(&ks->ks_ssl, session); + if (plugin_call (session->opt->plugins, OPENVPN_PLUGIN_TLS_FINAL, NULL, NULL, session->opt->es) != OPENVPN_PLUGIN_FUNC_SUCCESS) ks->authenticated = false; + + setenv_del (session->opt->es, "exported_keying_material"); } /* diff --git a/src/openvpn/ssl_backend.h b/src/openvpn/ssl_backend.h index b0777bf54df..99930e58611 100644 --- a/src/openvpn/ssl_backend.h +++ b/src/openvpn/ssl_backend.h @@ -334,6 +334,19 @@ void key_state_ssl_init(struct key_state_ssl *ks_ssl, */ void key_state_ssl_free(struct key_state_ssl *ks_ssl); +/** + * Keying Material Exporters [RFC 5705] allows additional keying material to be + * derived from existing TLS channel. This exported keying material can then be + * used for a variety of purposes. + * + * @param ks_ssl The SSL channel's state info + * @param session The session associated with the given key_state + */ + +void +key_state_export_keying_material(struct key_state_ssl *ks_ssl, + struct tls_session *session) __attribute__((nonnull)); + /**************************************************************************/ /** @addtogroup control_tls * @{ */ diff --git a/src/openvpn/ssl_common.h b/src/openvpn/ssl_common.h index 95cd2f7d93d..86e4ac8adea 100644 --- a/src/openvpn/ssl_common.h +++ b/src/openvpn/ssl_common.h @@ -317,6 +317,11 @@ struct tls_options /* --gremlin bits */ int gremlin; + + /* Keying Material Exporter [RFC 5705] parameters */ + const char *ekm_label; + size_t ekm_label_size; + size_t ekm_size; }; /** @addtogroup control_processor diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c index a38c41b8172..c08d4fe41e6 100644 --- a/src/openvpn/ssl_openssl.c +++ b/src/openvpn/ssl_openssl.c @@ -133,6 +133,39 @@ bool tls_ctx_initialised(struct tls_root_ctx *ctx) return NULL != ctx->ctx; } +void +key_state_export_keying_material(struct key_state_ssl *ssl, + struct tls_session *session) +{ + if (session->opt->ekm_size > 0) + { +#if (OPENSSL_VERSION_NUMBER >= 0x10001000) + unsigned int size = session->opt->ekm_size; + unsigned char ekm[size]; + + if (SSL_export_keying_material(ssl->ssl, ekm, sizeof(ekm), + session->opt->ekm_label, session->opt->ekm_label_size, NULL, 0, 0)) + { + struct gc_arena gc = gc_new(); + unsigned int len = (size * 2) + 2; + + const char *key = format_hex_ex (ekm, size, len, 0, NULL, &gc); + setenv_str (session->opt->es, "exported_keying_material", key); + + dmsg(D_TLS_DEBUG_MED, "%s: exported keying material: %s", + __func__, key); + + gc_free(&gc); + } + else + { + msg (M_WARN, "WARNING: Export keying material failed!"); + setenv_del (session->opt->es, "exported_keying_material"); + } +#endif + } +} + /* * Print debugging information on SSL/TLS session negotiation. */ diff --git a/src/openvpn/ssl_polarssl.c b/src/openvpn/ssl_polarssl.c index 20567354d57..cd77aa57692 100644 --- a/src/openvpn/ssl_polarssl.c +++ b/src/openvpn/ssl_polarssl.c @@ -148,6 +148,12 @@ tls_ctx_initialised(struct tls_root_ctx *ctx) return ctx->initialised; } +void +key_state_export_keying_material(struct key_state_ssl *ssl, + struct tls_session *session) +{ +} + void tls_ctx_set_options (struct tls_root_ctx *ctx, unsigned int ssl_flags) { From 84604e0bae7216b46642d5a1a443b86f712d53aa Mon Sep 17 00:00:00 2001 From: Daniel Kubec Date: Thu, 12 Mar 2015 15:25:42 +0100 Subject: [PATCH 105/643] Added document for TLS Keying Material Exporters [RFC-5705] [DS: Fixed option prefix from '-' to '--'] Signed-off-by: Daniel Kubec Signed-off-by: David Sommerseth Acked-by: Steffan Karger --- doc/keying-material-exporter.txt | 137 +++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 doc/keying-material-exporter.txt diff --git a/doc/keying-material-exporter.txt b/doc/keying-material-exporter.txt new file mode 100644 index 00000000000..4187d8280c1 --- /dev/null +++ b/doc/keying-material-exporter.txt @@ -0,0 +1,137 @@ +OpenVPN Daniel Kubec +RFC-5705 February 2015 + + + Added support for TLS Keying Material Exporters + +Keying Material Exporter [RFC-5705] allow additional keying material to be +derived from existing TLS channel. This exported keying material can then be +used for a variety of purposes. TLS allows client and server to establish +keying material for use in the upper layers between the TLS end-points and +channel bindings is straightforward and well-defined mechanism how to +authenticate other layers. + + +OpenVPN Configuration + +--keying-material-exporter label len + +Export Keying Material [RFC-5705] of len bytes (min. 16 bytes) using label in +environment (exported_keying_material) for use by plugins in +OPENVPN_PLUGIN_TLS_FINAL callback. + +Note that exporter labels have the potential to collide with existing PRF +labels. In order to prevent this, labels MUST begin with "EXPORTER". +(This option requires OpenSSL 1.0.1 or newer.) + + +Use Cases: + +Secure bindings of AAA information to application layer + + OpenVPN Client <------> OpenVPN Server + [KeyAgreement] [KeyAgreement] + + [TLSExportedKeyingMaterial] [TLSExportedKeyingMaterial] + [AAASessionKey] [AAASessionKey] + Client <------> Server + [Authenticated layer on top of (D)TLS] + + +TLS side channel authentication and straightforward bindings of AAA information +to application layer using well-defined mechanism. + + OpenVPN Client <------> OpenVPN Server + [KeyAgreement] [KeyAgreement] + + [TLSExportedKeyingMaterial] [TLSExportedKeyingMaterial] + [DerivedAAABindingKey] [DerivedAAABindingKey] + [AuthenticateBindingKeys] + Client -------> Server + [Confidental channel] + + +TLS Message flow for a full handshake + + ClientHello --------> + ServerHello + Certificate* + ServerKeyExchange* + CertificateRequest* + <-------- ServerHelloDone + Certificate* + ClientKeyExchange + CertificateVerify* + [ChangeCipherSpec] + Finished --------> + [ChangeCipherSpec] + <-------- Finished + + GenerateTLSBindingKey GenerateTLSBindingKey + + Application Data <-------> Application Data + + +Terminology + + AAA Authentication, Authorization, and Accounting: + functions that are generally required to control + access to a service and support auditing. + + Secure channel a packet, datagram, octet stream connection, or + sequence of connections between two end-points that + affords cryptographic integrity and confidentiality + to data exchanged over it. + + Channel binding the process of establishing that no man-in-the-middle + exists between two end-points that have been + authenticated using secure channel. + + TLS Binding Key Exported Keying Material [RFC5705] + + If no context is provided, it then computes: + PRF(SecurityParameters.master_secret, label, + SecurityParameters.client_random + + SecurityParameters.server_random + )[length] + + If context is provided, it computes: + PRF(SecurityParameters.master_secret, label, + SecurityParameters.client_random + + SecurityParameters.server_random + + context_value_length + context_value + )[length] + + AAA Binding Key TLS side channel authentication based on secure + channel bindings requires one more key derivation. + + SHA1(TLSExportedKeyingMaterial + ServerPublicKey) + +Reference + + [OPENAAA] "TLS side channel authentication and straightforward + bindings of AAA information to application + layer using well-defined mechanism." + Daniel Kubec March 2013 + https://github.com/n13l/openaaa + + [RFC5705] "Keying Material Exporters for TLS" + E. Rescorla, RFC 5705 March 2010 + http://tools.ietf.org/html/rfc5705 + + [RFC5929] "Channel Bindings for TLS" + J. Altman, N. Williams, L. Zhu, RFC 5929, July 2010 + http://tools.ietf.org/html/rfc5929 + + [RFC4680] "TLS Handshake Message for Supplemental Data" + S. Santesson, RFC 4680, September 2006 + http://tools.ietf.org/html/rfc4680 + + [RFC5878] "TLS Authorization Extension" + M. Brown, R. Housley, RFC 5878, May 2010 + http://tools.ietf.org/html/rfc5878 + + [RFC5746] "TLS Renegotiation Indication Extension" + E. Rescorla, M. Raym, S. Dispensa, N. Oskov + RFC 5746, February 2010 + http://tools.ietf.org/html/rfc5746 From f7ef7522f5c7e6d4abfa5a0378c2e2ad265c65ec Mon Sep 17 00:00:00 2001 From: Daniel Kubec Date: Sun, 5 Apr 2015 00:10:37 +0200 Subject: [PATCH 106/643] sample-plugin: TLS Keying Material Exporter [RFC-5705] demonstration plug-in A simple plug-in with a corresponding HTTP server and client which can authenticate an HTTP user based on the authentication already done via an established OpenVPN connection [DS: Renamed the module at commit time from sso to keyingmaterialexporter to avoid confusion with other Single-Sign-On solutions. Updated documentation and commits accordingly. Added --pull to the client config] Signed-off-by: Daniel Kubec Signed-off-by: David Sommerseth Acked-by: David Sommerseth --- .../keying-material-exporter-demo/README | 68 +++++ .../keying-material-exporter-demo/build | 15 + .../keying-material-exporter-demo/client.ovpn | 18 ++ .../http-client.py | 20 ++ .../http-server.py | 41 +++ .../keyingmaterialexporter.c | 269 ++++++++++++++++++ .../keying-material-exporter-demo/server.ovpn | 18 ++ 7 files changed, 449 insertions(+) create mode 100644 sample/sample-plugins/keying-material-exporter-demo/README create mode 100755 sample/sample-plugins/keying-material-exporter-demo/build create mode 100644 sample/sample-plugins/keying-material-exporter-demo/client.ovpn create mode 100755 sample/sample-plugins/keying-material-exporter-demo/http-client.py create mode 100755 sample/sample-plugins/keying-material-exporter-demo/http-server.py create mode 100644 sample/sample-plugins/keying-material-exporter-demo/keyingmaterialexporter.c create mode 100644 sample/sample-plugins/keying-material-exporter-demo/server.ovpn diff --git a/sample/sample-plugins/keying-material-exporter-demo/README b/sample/sample-plugins/keying-material-exporter-demo/README new file mode 100644 index 00000000000..a245d23add6 --- /dev/null +++ b/sample/sample-plugins/keying-material-exporter-demo/README @@ -0,0 +1,68 @@ +OpenVPN plugin examples. Daniel Kubec + +Examples provided: + +keyingmaterialexporter.c -- Example based on TLS Keying Material Exporters over HTTP [RFC-5705] + (openvpn/doc/keying-material-exporter.txt) + +This example demonstrates authenticating a user over HTTP who have already +established an OpenVPN connecting using the --keying-material-exporter +feature. + +Requires: +OpenVPN RFC-5705 Support, OpenSSL >= 1.0.1 + +Files: + http-server.py -- Example HTTP Server listen 0.0.0.0:8080 + http-client.py -- Example HTTP Client connect 10.8.0.1:8080 [GET /$SESSIONID] + + server.ovpn -- Example HTTP SSO VPN Server configuration + client.ovpn -- Example HTTP SSO VPN Client configuration + + keyingmaterialexporter.c, + keyingmaterialexporter.so -- Example OpenVPN Client and Server plugin + +To build: + ./build keyingmaterialexporter + +To use in OpenVPN: + +Enter openvpn/sample/sample-plugins/keyingmaterialexporter directory +and in separate terminals, start these four processes: + +$ openvpn --config ./server.ovpn +$ openvpn --config ./client.ovpn +$ ./http-server.py +$ ./http-client.py + +Test: + +openvpn --config ./server.ovpn +############################## + +PLUGIN SSO: app session created +PLUGIN_CALL: POST ./keyingmaterialexporter.so/PLUGIN_TLS_VERIFY status=0 +PLUGIN SSO: app session key: a5885abc84d361803f58ede1ef9c0adf99e720cd +PLUGIN SSO: app session file: /tmp/openvpn_sso_a5885abc84d361803f58ede1ef9c0adf99e720cd +PLUGIN SSO: app session user: Test-Client + +openvpn --config ./client.ovpn +############################## +PLUGIN SSO: app session created +PLUGIN_CALL: POST ./keyingmaterialexporter.so/PLUGIN_TLS_VERIFY status=0 +PLUGIN SSO: app session key: a5885abc84d361803f58ede1ef9c0adf99e720cd +PLUGIN SSO: app session file: /tmp/openvpn_sso_user +PLUGIN_CALL: POST ./keyingmaterialexporter.so/PLUGIN_TLS_FINAL status=0 + +HTTP_SERVER: +http-server.py +################ +http server started +session file: /tmp/openvpn_sso_a5885abc84d361803f58ede1ef9c0adf99e720cd +10.8.0.1 - - [02/Apr/2015 15:03:33] "GET /a5885abc84d361803f58ede1ef9c0adf99e720cd HTTP/1.1" 200 - +session user: Test-Client +session key: a5885abc84d361803f58ede1ef9c0adf99e720cd + +HTTP_SERVER: +http-client.py +

Greetings Test-Client. You are authorized

diff --git a/sample/sample-plugins/keying-material-exporter-demo/build b/sample/sample-plugins/keying-material-exporter-demo/build new file mode 100755 index 00000000000..bbb05f7c786 --- /dev/null +++ b/sample/sample-plugins/keying-material-exporter-demo/build @@ -0,0 +1,15 @@ +#!/bin/sh + +# +# Build an OpenVPN plugin module on *nix. The argument should +# be the base name of the C source file (without the .c). +# + +# This directory is where we will look for openvpn-plugin.h +CPPFLAGS="${CPPFLAGS:--I../../..}" + +CC="${CC:-gcc}" +CFLAGS="${CFLAGS:--O2 -Wall -g}" + +$CC $CPPFLAGS $CFLAGS -fPIC -c $1.c && \ +$CC $CFLAGS -fPIC -shared $LDFLAGS -Wl,-soname,$1.so -o $1.so $1.o -lc diff --git a/sample/sample-plugins/keying-material-exporter-demo/client.ovpn b/sample/sample-plugins/keying-material-exporter-demo/client.ovpn new file mode 100644 index 00000000000..f02087b3e8e --- /dev/null +++ b/sample/sample-plugins/keying-material-exporter-demo/client.ovpn @@ -0,0 +1,18 @@ +tls-client +pull + +keying-material-exporter "EXPORTER_SSO_TEST" 16 +reneg-sec 0 + +ca ../../sample-keys/ca.crt +cert ../../sample-keys/client.crt +key ../../sample-keys/client.key + +plugin ./keyingmaterialexporter.so + +remote 127.0.0.1 1194 +proto udp +dev tun +nobind + +verb 4 diff --git a/sample/sample-plugins/keying-material-exporter-demo/http-client.py b/sample/sample-plugins/keying-material-exporter-demo/http-client.py new file mode 100755 index 00000000000..e0570b398c2 --- /dev/null +++ b/sample/sample-plugins/keying-material-exporter-demo/http-client.py @@ -0,0 +1,20 @@ +#!/usr/bin/python +import sys +import os +import httplib + +f = '/tmp/openvpn_sso_user' +with open (f, "r") as myfile: + session_key = myfile.read().replace('\n', '') + +conn = httplib.HTTPConnection("10.8.0.1:8080") +conn.request("GET", "/" + session_key) +r1 = conn.getresponse() + +if r1.status == 200: + body = r1.read().rstrip() + print body +elif r1.status == 404: + print "Authentication failed" +else: + print r1.status, r1.reason diff --git a/sample/sample-plugins/keying-material-exporter-demo/http-server.py b/sample/sample-plugins/keying-material-exporter-demo/http-server.py new file mode 100755 index 00000000000..45381b5f36b --- /dev/null +++ b/sample/sample-plugins/keying-material-exporter-demo/http-server.py @@ -0,0 +1,41 @@ +#!/usr/bin/python +from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer +import os + +class ExampleHTTPRequestHandler(BaseHTTPRequestHandler): + + def do_GET(self): + session_key = os.path.basename(self.path) + file = '/tmp/openvpn_sso_' + session_key + print 'session file: ' + file + try: + f = open(file) + #send code 200 response + self.send_response(200) + #send header first + self.send_header('Content-type','text-html') + self.end_headers() + #send file content to client + user = f.read().rstrip() + print 'session user: ' + user + print 'session key: ' + session_key + self.wfile.write('

Greetings ' + user \ + + '. You are authorized' \ + '

' \ + '') + f.close() + return + except IOError: + self.send_error(404, 'authentication failed') + +def run(): + #ip and port of servr + #by default http server port is 80 + server_address = ('0.0.0.0', 8080) + httpd = HTTPServer(server_address, ExampleHTTPRequestHandler) + print('http server started') + httpd.serve_forever() + print('http server stopped') + +if __name__ == '__main__': + run() diff --git a/sample/sample-plugins/keying-material-exporter-demo/keyingmaterialexporter.c b/sample/sample-plugins/keying-material-exporter-demo/keyingmaterialexporter.c new file mode 100644 index 00000000000..b0240b8c937 --- /dev/null +++ b/sample/sample-plugins/keying-material-exporter-demo/keyingmaterialexporter.c @@ -0,0 +1,269 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single TCP/UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * + * 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 + */ + +/* + * This file implements a Sample (HTTP) SSO OpenVPN plugin module + * + * See the README file for build instructions. + */ + +#define ENABLE_CRYPTO + +#include +#include +#include + +#include "openvpn-plugin.h" + +#ifndef MAXPATH +#define MAXPATH 1024 +#endif + +#define ovpn_err(fmt, ...) \ + plugin->log(PLOG_ERR, "SSO", fmt , ## __VA_ARGS__) +#define ovpn_dbg(fmt, ...) \ + plugin->log(PLOG_DEBUG, "SSO", fmt , ## __VA_ARGS__) +#define ovpn_note(fmt, ...) \ + plugin->log(PLOG_NOTE, "SSO", fmt , ## __VA_ARGS__) + +enum endpoint { CLIENT = 1, SERVER = 2 }; + +struct plugin { + plugin_log_t log; + enum endpoint type; + int mask; +}; + +struct session { + char user[48]; + char key [48]; +}; + +/* + * Given an environmental variable name, search + * the envp array for its value, returning it + * if found or NULL otherwise. + */ + +static const char * +get_env(const char *name, const char *envp[]) +{ + if (envp) + { + int i; + const int namelen = strlen (name); + for (i = 0; envp[i]; ++i) + { + if (!strncmp (envp[i], name, namelen)) + { + const char *cp = envp[i] + namelen; + if (*cp == '=') + return cp + 1; + } + } + } + return NULL; +} + +OPENVPN_EXPORT int +openvpn_plugin_open_v3 (const int version, + struct openvpn_plugin_args_open_in const *args, + struct openvpn_plugin_args_open_return *rv) +{ + struct plugin *plugin = calloc (1, sizeof(*plugin)); + + plugin->type = get_env ("remote_1", args->envp) ? CLIENT : SERVER; + plugin->log = args->callbacks->plugin_log; + + plugin->mask = OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_TLS_FINAL); + plugin->mask |= OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_TLS_VERIFY); + + ovpn_note("vpn endpoint type=%s",plugin->type == CLIENT ? "client":"server"); + + rv->type_mask = plugin->mask; + rv->handle = (void *)plugin; + + return OPENVPN_PLUGIN_FUNC_SUCCESS; +} + +static void +session_user_set(struct session *sess, X509 *x509) +{ + int fn_nid; + ASN1_OBJECT *fn; + ASN1_STRING *val; + X509_NAME *x509_name; + X509_NAME_ENTRY *ent; + const char *objbuf; + + x509_name = X509_get_subject_name (x509); + int i, n = X509_NAME_entry_count (x509_name); + for (i = 0; i < n; ++i) + { + if (!(ent = X509_NAME_get_entry (x509_name, i))) + continue; + if (!(fn = X509_NAME_ENTRY_get_object (ent))) + continue; + if (!(val = X509_NAME_ENTRY_get_data (ent))) + continue; + if ((fn_nid = OBJ_obj2nid (fn)) == NID_undef) + continue; + if (!(objbuf = OBJ_nid2sn (fn_nid))) + continue; + /* bug in OpenSSL 0.9.6b ASN1_STRING_to_UTF8 requires this workaround */ + unsigned char *buf = (unsigned char *)1; + if (ASN1_STRING_to_UTF8 (&buf, val) <= 0) + continue; + + if (!strncasecmp(objbuf, "CN", 2)) + snprintf(sess->user, sizeof(sess->user) - 1, (char *)buf); + + OPENSSL_free (buf); + } +} + +static int +tls_verify(struct openvpn_plugin_args_func_in const *args) +{ + struct plugin *plugin = (struct plugin *)args->handle; + struct session *sess = (struct session *)args->per_client_context; + + /* we store cert subject for the server end point only */ + if (plugin->type != SERVER) + return OPENVPN_PLUGIN_FUNC_SUCCESS; + + if (!args->current_cert) { + ovpn_err("this example plugin requires client certificate"); + return OPENVPN_PLUGIN_FUNC_ERROR; + } + + session_user_set(sess, args->current_cert); + + return OPENVPN_PLUGIN_FUNC_SUCCESS; +} + +static void +file_store(char *file, char *content) +{ + FILE *f; + if (!(f = fopen(file, "w+"))) + return; + + fprintf(f, "%s", content); + fclose(f); +} + +static void +server_store(struct openvpn_plugin_args_func_in const *args) +{ + struct plugin *plugin = (struct plugin *)args->handle; + struct session *sess = (struct session *)args->per_client_context; + + char file[MAXPATH]; + snprintf(file, sizeof(file) - 1, "/tmp/openvpn_sso_%s", sess->key); + ovpn_note("app session file: %s", file); + file_store(file, sess->user); +} + +static void +client_store(struct openvpn_plugin_args_func_in const *args) +{ + struct plugin *plugin = (struct plugin *)args->handle; + struct session *sess = (struct session *)args->per_client_context; + + char *file = "/tmp/openvpn_sso_user"; + ovpn_note("app session file: %s", file); + file_store(file, sess->key); +} + +static int +tls_final(struct openvpn_plugin_args_func_in const *args, + struct openvpn_plugin_args_func_return *rv) +{ + struct plugin *plugin = (struct plugin *)args->handle; + struct session *sess = (struct session *)args->per_client_context; + + const char *key; + if (!(key = get_env ("exported_keying_material", args->envp))) + return OPENVPN_PLUGIN_FUNC_ERROR; + + snprintf(sess->key, sizeof(sess->key) - 1, "%s", key); + ovpn_note("app session key: %s", sess->key); + + switch (plugin->type) { + case SERVER: + server_store(args); + break; + case CLIENT: + client_store(args); + return OPENVPN_PLUGIN_FUNC_SUCCESS; + } + + ovpn_note("app session user: %s", sess->user); + return OPENVPN_PLUGIN_FUNC_SUCCESS; +} + +OPENVPN_EXPORT int +openvpn_plugin_func_v3 (const int version, + struct openvpn_plugin_args_func_in const *args, + struct openvpn_plugin_args_func_return *rv) +{ + switch(args->type) { + case OPENVPN_PLUGIN_TLS_VERIFY: + return tls_verify(args); + case OPENVPN_PLUGIN_TLS_FINAL: + return tls_final(args, rv); + } + return OPENVPN_PLUGIN_FUNC_SUCCESS; +} + +OPENVPN_EXPORT void * +openvpn_plugin_client_constructor_v1(openvpn_plugin_handle_t handle) +{ + struct plugin *plugin = (struct plugin *)handle; + struct session *sess = calloc (1, sizeof(*sess)); + + ovpn_note("app session created"); + + return (void *)sess; +} + +OPENVPN_EXPORT void +openvpn_plugin_client_destructor_v1(openvpn_plugin_handle_t handle, void *ctx) +{ + struct plugin *plugin = (struct plugin *)handle; + struct session *sess = (struct session *)ctx; + + ovpn_note("app session key: %s", sess->key); + ovpn_note("app session destroyed"); + + free (sess); +} + +OPENVPN_EXPORT void +openvpn_plugin_close_v1 (openvpn_plugin_handle_t handle) +{ + struct plugin *plugin = (struct plugin *)handle; + free (plugin); +} diff --git a/sample/sample-plugins/keying-material-exporter-demo/server.ovpn b/sample/sample-plugins/keying-material-exporter-demo/server.ovpn new file mode 100644 index 00000000000..5c670b135b6 --- /dev/null +++ b/sample/sample-plugins/keying-material-exporter-demo/server.ovpn @@ -0,0 +1,18 @@ +tls-server +reneg-sec 0 + +keying-material-exporter "EXPORTER_SSO_TEST" 16 +duplicate-cn + +plugin ./keyingmaterialexporter.so +ca ../../sample-keys/ca.crt +cert ../../sample-keys/server.crt +key ../../sample-keys/server.key +dh ../../sample-keys/dh2048.pem + +server 10.8.0.0 255.255.255.0 +port 1194 +proto udp +dev tun + +verb 4 From 99daa6b19270775006f034f21936c98a9005477d Mon Sep 17 00:00:00 2001 From: Lev Stipakov Date: Mon, 2 Mar 2015 19:58:31 +0200 Subject: [PATCH 107/643] Fast recovery when host is in unreachable network When client connects to the server which is in unreachable network (for example hostname got resolved into ipv6 address and client has no ipv6), throw SIGUSR1 and connect to the next server without waiting 60 seconds for "TLS key negotiation failed". Acked-by: Arne Schwabe Message-Id: <1425319111-21291-1-git-send-email-lstipakov@gmail.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/9498 Signed-off-by: Gert Doering --- src/openvpn/forward.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c index 7a5d3838536..513fbae9bc5 100644 --- a/src/openvpn/forward.c +++ b/src/openvpn/forward.c @@ -1093,6 +1093,7 @@ void process_outgoing_link (struct context *c) { struct gc_arena gc = gc_new (); + int error_code = 0; perf_push (PERF_PROC_OUT_LINK); @@ -1180,6 +1181,7 @@ process_outgoing_link (struct context *c) } /* Check return status */ + error_code = openvpn_errno(); check_status (size, "write", c->c2.link_socket, NULL); if (size > 0) @@ -1196,6 +1198,14 @@ process_outgoing_link (struct context *c) /* if not a ping/control message, indicate activity regarding --inactive parameter */ if (c->c2.buf.len > 0 ) register_activity (c, size); + + /* for unreachable network and "connecting" state switch to the next host */ + if (size < 0 && ENETUNREACH == error_code && !tls_initial_packet_received (c->c2.tls_multi) + && c->options.mode == MODE_POINT_TO_POINT) + { + msg (M_INFO, "Network unreachable, restarting"); + register_signal (c, SIGUSR1, "network-unreachable"); + } } else { From 2bed089d31a12c2d0277e36a64964ebab6640f75 Mon Sep 17 00:00:00 2001 From: Julien Muchembled Date: Sat, 10 Oct 2015 11:44:51 +0200 Subject: [PATCH 108/643] Fix --mtu-disc option with IPv6 transport Socket configuration of MTU discovery was done unconditionally at IP level, which has no effect for other protocols. This fixes the issue of OpenVPN sending fragmented tcp6/udp6 packets even when 'mtu-disc yes' option is passed. Patch V2 (by Arne Schwabe): Rebase to current master and have separate #ifdefs for IPv4 an IPv6 Signed-off-by: Julien Muchembled Acked-by: Arne Schwabe Acked-by: Gert Doering Message-Id: <1444470291-2980-1-git-send-email-arne@rfc2549.org> URL: http://article.gmane.org/gmane.network.openvpn.devel/10229 Signed-off-by: Gert Doering --- src/openvpn/mtu.c | 29 ++++++++++++++++++++++------- src/openvpn/mtu.h | 2 +- src/openvpn/socket.c | 2 +- 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/openvpn/mtu.c b/src/openvpn/mtu.c index 3665a34ddd0..24531c92a8b 100644 --- a/src/openvpn/mtu.c +++ b/src/openvpn/mtu.c @@ -153,17 +153,32 @@ frame_print (const struct frame *frame, #define MTUDISC_NOT_SUPPORTED_MSG "--mtu-disc is not supported on this OS" void -set_mtu_discover_type (int sd, int mtu_type) +set_mtu_discover_type (int sd, int mtu_type, sa_family_t proto_af) { if (mtu_type >= 0) { -#if defined(HAVE_SETSOCKOPT) && defined(SOL_IP) && defined(IP_MTU_DISCOVER) - if (setsockopt (sd, SOL_IP, IP_MTU_DISCOVER, (void *) &mtu_type, sizeof (mtu_type))) - msg (M_ERR, "Error setting IP_MTU_DISCOVER type=%d on TCP/UDP socket", - mtu_type); -#else - msg (M_FATAL, MTUDISC_NOT_SUPPORTED_MSG); + switch (proto_af) + { +#if defined(HAVE_SETSOCKOPT) && defined(IP_MTU_DISCOVER) + case AF_INET: + if (setsockopt + (sd, IPPROTO_IP, IP_MTU_DISCOVER, &mtu_type, sizeof (mtu_type))) + msg (M_ERR, "Error setting IP_MTU_DISCOVER type=%d on TCP/UDP socket", + mtu_type); + break; +#endif +#if defined(HAVE_SETSOCKOPT) && defined(IPV6_MTU_DISCOVER) + case AF_INET6: + if (setsockopt + (sd, IPPROTO_IPV6, IPV6_MTU_DISCOVER, &mtu_type, sizeof (mtu_type))) + msg (M_ERR, "Error setting IPV6_MTU_DISCOVER type=%d on TCP6/UDP6 socket", + mtu_type); + break; #endif + default: + msg (M_FATAL, MTUDISC_NOT_SUPPORTED_MSG); + break; + } } } diff --git a/src/openvpn/mtu.h b/src/openvpn/mtu.h index bccd6810fde..f94de89b73c 100644 --- a/src/openvpn/mtu.h +++ b/src/openvpn/mtu.h @@ -207,7 +207,7 @@ void frame_print (const struct frame *frame, int level, const char *prefix); -void set_mtu_discover_type (int sd, int mtu_type); +void set_mtu_discover_type (int sd, int mtu_type, sa_family_t proto_af); int translate_mtu_discover_type_name (const char *name); /* diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c index bd8dcb1bcdb..925665c5213 100644 --- a/src/openvpn/socket.c +++ b/src/openvpn/socket.c @@ -1676,7 +1676,7 @@ phase2_set_socket_flags (struct link_socket* sock) set_cloexec (sock->ctrl_sd); /* set Path MTU discovery options on the socket */ - set_mtu_discover_type (sock->sd, sock->mtu_discover_type); + set_mtu_discover_type (sock->sd, sock->mtu_discover_type, sock->info.af); #if EXTENDED_SOCKET_ERROR_CAPABILITY /* if the OS supports it, enable extended error passing on the socket */ From b05a453be5dd21326e79f42b0a363f2f23eaa29a Mon Sep 17 00:00:00 2001 From: Lev Stipakov Date: Sat, 10 Oct 2015 13:14:29 +0300 Subject: [PATCH 109/643] Fix compilation error with --disable-crypto Also disable "ENETUNREACH -> restart" behavior for static key setup. Acked-by: Arne Schwabe Message-Id: <1444472069-32036-1-git-send-email-lstipakov@gmail.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/10231 Signed-off-by: Gert Doering --- src/openvpn/forward.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c index 513fbae9bc5..c17be3514e5 100644 --- a/src/openvpn/forward.c +++ b/src/openvpn/forward.c @@ -1199,13 +1199,16 @@ process_outgoing_link (struct context *c) if (c->c2.buf.len > 0 ) register_activity (c, size); + +#ifdef ENABLE_CRYPTO /* for unreachable network and "connecting" state switch to the next host */ - if (size < 0 && ENETUNREACH == error_code && !tls_initial_packet_received (c->c2.tls_multi) - && c->options.mode == MODE_POINT_TO_POINT) + if (size < 0 && ENETUNREACH == error_code && c->c2.tls_multi && + !tls_initial_packet_received (c->c2.tls_multi) && c->options.mode == MODE_POINT_TO_POINT) { msg (M_INFO, "Network unreachable, restarting"); register_signal (c, SIGUSR1, "network-unreachable"); } +#endif } else { From b51a024a7b26e691e6459964d4d29f15b70089bd Mon Sep 17 00:00:00 2001 From: Thomas Veerman Date: Wed, 22 Jan 2014 09:27:29 +0100 Subject: [PATCH 110/643] Update expiry date in management event loop When there are events from the management console with an interval shorter than 1 second, the event loop never stops as it keeps resetting event_wait. Acked-by: Arne Schwabe Message-Id: URL: http://article.gmane.org/gmane.network.openvpn.devel/8253 Signed-off-by: Gert Doering --- src/openvpn/manage.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/openvpn/manage.c b/src/openvpn/manage.c index d02dac9c6ac..97d6f0fa240 100644 --- a/src/openvpn/manage.c +++ b/src/openvpn/manage.c @@ -3015,7 +3015,8 @@ management_event_loop_n_seconds (struct management *man, int sec) man_check_for_signals (&signal_received); if (signal_received) return; - } while (expire); + update_time(); + } while (expire && expire > now); /* revert state */ man->persist.standalone_disabled = standalone_disabled_save; From 0c1d92291e4c1829bf503067e1f9d39328d01ee9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuli=20Sepp=C3=A4nen?= Date: Sat, 10 Oct 2015 16:41:14 +0300 Subject: [PATCH 111/643] Add CONTRIBUTING.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Samuli Seppänen Acked-by: Gert Doering Message-Id: <1444484474-6471-1-git-send-email-samuli@openvpn.net> Signed-off-by: Gert Doering --- CONTRIBUTING.rst | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 CONTRIBUTING.rst diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst new file mode 100644 index 00000000000..6033097f4ad --- /dev/null +++ b/CONTRIBUTING.rst @@ -0,0 +1,30 @@ +CONTRIBUTING TO THE OPENVPN PROJECT +=================================== + +Patches should be written against the Git "master" branch. Some patches may get +backported to a release branch. + +We do not currently accept GitHub pull requests for the core OpenVPN project. +Instead, all patches must be sent to "openvpn-devel" mailing list for review: + +- https://lists.sourceforge.net/lists/listinfo/openvpn-devel + +The subject line should preferably be prefixed with [PATCH]. To avoid merging +issues the patches should be generated with git-format-patch or sent using +git-send-email. Try to split large patches into small, atomic pieces to make +reviews easier. + +If you want quick feedback on a patch before sending it to openvpn-devel mailing +list, you can visit the #openvpn-devel channel on irc.freenode.net. Note that +you need to be logged in to Freenode to join the channel: + +- http://freenode.net/faq.shtml#nicksetup + +More detailed contribution instructions are available here: + +- https://community.openvpn.net/openvpn/wiki/DeveloperDocumentation + +Note that the process for contributing to other OpenVPN projects such as +openvpn-build, openvpn-gui, tap-windows6 and easy-rsa may differ from what was +described above. Please refer to the contribution instructions of each +respective project. From c67acea173dc9ee37220f5b9ff14ede081181992 Mon Sep 17 00:00:00 2001 From: janjust Date: Sat, 10 Oct 2015 18:12:49 +0200 Subject: [PATCH 112/643] Fix "White space before end tags can break the config parser" trac #569 Acked-by: Arne Schwabe Message-Id: <1444493569-24026-1-git-send-email-janjust@nikhef.nl> URL: http://article.gmane.org/gmane.network.openvpn.devel/10249 Signed-off-by: Gert Doering --- src/openvpn/options.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 7906f46fd69..11e327c1f45 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -3694,13 +3694,16 @@ static char * read_inline_file (struct in_src *is, const char *close_tag, struct gc_arena *gc) { char line[OPTION_LINE_SIZE]; + char *line_ptr = line; struct buffer buf = alloc_buf (8*OPTION_LINE_SIZE); char *ret; bool endtagfound = false; while (in_src_get (is, line, sizeof (line))) { - if (!strncmp (line, close_tag, strlen (close_tag))) + /* Remove leading spaces */ + while (isspace(*line_ptr)) line_ptr++; + if (!strncmp (line_ptr, close_tag, strlen (close_tag))) { endtagfound = true; break; From 9403e3f4b510fbc4187044f31be8f7dccbde1cf1 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Sat, 10 Oct 2015 18:34:49 +0200 Subject: [PATCH 113/643] Remove support for snappy compression. LZ4 is using less CPU at similar performance, and it is easier to build and support for binary installs (as it does not require C++ and a C++ runtime). Since it was never supported in any formally released OpenVPN version, just drop it again. This leaves in the compression opcode for Snappy for documentation purposes. trac #617 Signed-off-by: Gert Doering Acked-by: Arne Schwabe Message-Id: <1444494889-28925-1-git-send-email-gert@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/10251 --- configure.ac | 48 ---------- doc/openvpn.8 | 6 +- src/openvpn/Makefile.am | 3 - src/openvpn/comp.c | 11 --- src/openvpn/comp.h | 11 +-- src/openvpn/init.c | 6 +- src/openvpn/options.c | 10 --- src/openvpn/snappy.c | 189 ---------------------------------------- src/openvpn/snappy.h | 39 --------- src/openvpn/syshead.h | 2 +- 10 files changed, 9 insertions(+), 316 deletions(-) delete mode 100644 src/openvpn/snappy.c delete mode 100644 src/openvpn/snappy.h diff --git a/configure.ac b/configure.ac index 2e651d8e8e6..77b49154c58 100644 --- a/configure.ac +++ b/configure.ac @@ -66,12 +66,6 @@ AC_ARG_ENABLE( [enable_lzo="yes"] ) -AC_ARG_ENABLE(snappy, - [ --disable-snappy Disable Snappy compression support], - [enable_snappy="$enableval"], - [enable_snappy="yes"] -) - AC_ARG_ENABLE(lz4, [ --disable-lz4 Disable LZ4 compression support], [enable_lz4="$enableval"], @@ -951,45 +945,6 @@ if test "${have_lzo}" = "yes"; then CFLAGS="${saved_CFLAGS}" fi -dnl -dnl check for Snappy library -dnl - -AC_ARG_VAR([SNAPPY_CFLAGS], [C compiler flags for snappy]) -AC_ARG_VAR([SNAPPY_LIBS], [linker flags for snappy]) -if test "$enable_snappy" = "yes" && test "$enable_comp_stub" = "no"; then - AC_CHECKING([for Snappy Library and Header files]) - havesnappylib=1 - - # if SNAPPY_LIBS is set, we assume it will work, otherwise test - if test -z "${SNAPPY_LIBS}"; then - AC_CHECK_LIB(snappy, snappy_compress, - [ SNAPPY_LIBS="-lsnappy" ], - [ - AC_MSG_RESULT([Snappy library not found.]) - havesnappylib=0 - ]) - fi - - saved_CFLAGS="${CFLAGS}" - CFLAGS="${CFLAGS} ${SNAPPY_CFLAGS}" - AC_CHECK_HEADERS(snappy-c.h, - , - [ - AC_MSG_RESULT([Snappy headers not found.]) - havesnappylib=0 - ]) - - if test $havesnappylib = 0 ; then - AC_MSG_RESULT([Snappy library available from http://code.google.com/p/snappy/]) - AC_MSG_ERROR([Or try ./configure --disable-snappy OR ./configure --enable-comp-stub]) - fi - OPTIONAL_SNAPPY_CFLAGS="${SNAPPY_CFLAGS}" - OPTIONAL_SNAPPY_LIBS="${SNAPPY_LIBS}" - AC_DEFINE(ENABLE_SNAPPY, 1, [Enable Snappy compression library]) - CFLAGS="${saved_CFLAGS}" -fi - dnl dnl check for LZ4 library dnl @@ -1154,7 +1109,6 @@ if test "${enable_lzo}" = "yes"; then fi if test "${enable_comp_stub}" = "yes"; then test "${enable_lzo}" = "yes" && AC_MSG_ERROR([Cannot have both comp stub and lzo enabled (use --disable-lzo)]) - test "${enable_snappy}" = "yes" && AC_MSG_ERROR([Cannot have both comp stub and snappy enabled (use --disable-snappy)]) test "${enable_lz4}" = "yes" && AC_MSG_ERROR([Cannot have both comp stub and LZ4 enabled (use --disable-lz4)]) AC_DEFINE([ENABLE_COMP_STUB], [1], [Enable compression stub capability]) fi @@ -1220,8 +1174,6 @@ AC_SUBST([OPTIONAL_CRYPTO_CFLAGS]) AC_SUBST([OPTIONAL_CRYPTO_LIBS]) AC_SUBST([OPTIONAL_LZO_CFLAGS]) AC_SUBST([OPTIONAL_LZO_LIBS]) -AC_SUBST([OPTIONAL_SNAPPY_CFLAGS]) -AC_SUBST([OPTIONAL_SNAPPY_LIBS]) AC_SUBST([OPTIONAL_LZ4_CFLAGS]) AC_SUBST([OPTIONAL_LZ4_LIBS]) AC_SUBST([OPTIONAL_SYSTEMD_LIBS]) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 829b09cd83f..3a864094b09 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -2495,9 +2495,9 @@ Enable a compression algorithm. The .B algorithm -parameter may be "snappy", "lzo", "lz4", or empty. Snappy, LZO and LZ4 -are different compression algorithms, with Snappy generally -offering the best performance while LZ4 is faster with less CPU usage. +parameter may be "lzo", "lz4", or empty. LZO and LZ4 +are different compression algorithms, with LZ4 generally +offering the best performance with least CPU usage. For backwards compatibility with OpenVPN versions before 2.4, use "lzo" (which is identical to the older option "\-\-comp\-lzo yes"). diff --git a/src/openvpn/Makefile.am b/src/openvpn/Makefile.am index d089f50ff1c..c840f1677b1 100644 --- a/src/openvpn/Makefile.am +++ b/src/openvpn/Makefile.am @@ -26,7 +26,6 @@ AM_CFLAGS = \ $(TAP_CFLAGS) \ $(OPTIONAL_CRYPTO_CFLAGS) \ $(OPTIONAL_LZO_CFLAGS) \ - $(OPTIONAL_SNAPPY_CFLAGS) \ $(OPTIONAL_LZ4_CFLAGS) \ $(OPTIONAL_PKCS11_HELPER_CFLAGS) if WIN32 @@ -102,7 +101,6 @@ openvpn_SOURCES = \ session_id.c session_id.h \ shaper.c shaper.h \ sig.c sig.h \ - snappy.c snappy.h \ socket.c socket.h \ socks.c socks.h \ ssl.c ssl.h ssl_backend.h \ @@ -121,7 +119,6 @@ openvpn_LDADD = \ $(top_builddir)/src/compat/libcompat.la \ $(SOCKETS_LIBS) \ $(OPTIONAL_LZO_LIBS) \ - $(OPTIONAL_SNAPPY_LIBS) \ $(OPTIONAL_LZ4_LIBS) \ $(OPTIONAL_PKCS11_HELPER_LIBS) \ $(OPTIONAL_CRYPTO_LIBS) \ diff --git a/src/openvpn/comp.c b/src/openvpn/comp.c index 4ac589f95c0..706ad7ea8e7 100644 --- a/src/openvpn/comp.c +++ b/src/openvpn/comp.c @@ -58,14 +58,6 @@ comp_init(const struct compress_options *opt) (*compctx->alg.compress_init)(compctx); break; #endif -#ifdef ENABLE_SNAPPY - case COMP_ALG_SNAPPY: - ALLOC_OBJ_CLEAR (compctx, struct compress_context); - compctx->flags = opt->flags; - compctx->alg = snappy_alg; - (*compctx->alg.compress_init)(compctx); - break; -#endif #ifdef ENABLE_LZ4 case COMP_ALG_LZ4: ALLOC_OBJ_CLEAR (compctx, struct compress_context); @@ -129,9 +121,6 @@ comp_generate_peer_info_string(const struct compress_options *opt, struct buffer #if defined(ENABLE_LZ4) buf_printf (out, "IV_LZ4=1\n"); #endif -#if defined(ENABLE_SNAPPY) - buf_printf (out, "IV_SNAPPY=1\n"); -#endif #if defined(ENABLE_LZO) buf_printf (out, "IV_LZO=1\n"); lzo_avail = true; diff --git a/src/openvpn/comp.h b/src/openvpn/comp.h index bfa25fd3efa..716b1c0a8df 100644 --- a/src/openvpn/comp.h +++ b/src/openvpn/comp.h @@ -24,7 +24,7 @@ /* * Generic compression support. Currently we support - * Snappy, LZO 2 and LZ4. + * LZO 2 and LZ4. */ #ifndef OPENVPN_COMP_H #define OPENVPN_COMP_H @@ -40,7 +40,7 @@ #define COMP_ALG_UNDEF 0 #define COMP_ALG_STUB 1 /* support compression command byte and framing without actual compression */ #define COMP_ALG_LZO 2 /* LZO algorithm */ -#define COMP_ALG_SNAPPY 3 /* Snappy algorithm */ +#define COMP_ALG_SNAPPY 3 /* Snappy algorithm (no longer supported) */ #define COMP_ALG_LZ4 4 /* LZ4 algorithm */ /* Compression flags */ @@ -101,10 +101,6 @@ struct compress_alg #include "lzo.h" #endif -#ifdef ENABLE_SNAPPY -#include "snappy.h" -#endif - #ifdef ENABLE_LZ4 #include "comp-lz4.h" #endif @@ -127,9 +123,6 @@ union compress_workspace_union #ifdef ENABLE_LZO struct lzo_compress_workspace lzo; #endif -#ifdef ENABLE_SNAPPY - struct snappy_workspace snappy; -#endif #ifdef ENABLE_LZ4 struct lz4_workspace lz4; #endif diff --git a/src/openvpn/init.c b/src/openvpn/init.c index c32a809d6d1..5dd87815b32 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -2379,11 +2379,11 @@ do_init_frame (struct context *c) { comp_add_to_extra_frame (&c->c2.frame); -#if !defined(ENABLE_SNAPPY) && !defined(ENABLE_LZ4) +#if !defined(ENABLE_LZ4) /* * Compression usage affects buffer alignment when non-swapped algs * such as LZO is used. - * Newer algs like Snappy and comp-stub with COMP_F_SWAP don't need + * Newer algs like LZ4 and comp-stub with COMP_F_SWAP don't need * any special alignment because of the control-byte swap approach. * LZO alignment (on the other hand) is problematic because * the presence of the control byte means that either the output of @@ -2394,7 +2394,7 @@ do_init_frame (struct context *c) * dispatch if packet is uncompressed) at the cost of requiring * decryption output to be written to an unaligned buffer, so * it's more of a tradeoff than an optimal solution and we don't - * include it when we are doing a modern build with Snappy or LZ4. + * include it when we are doing a modern build with LZ4. * Strictly speaking, on the server it would be better to execute * this code for every connection after we decide the compression * method, but currently the frame code doesn't appear to be diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 11e327c1f45..cfba7286725 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -80,9 +80,6 @@ const char title_string[] = #ifdef ENABLE_LZO " [LZO]" #endif -#ifdef ENABLE_SNAPPY - " [SNAPPY]" -#endif #ifdef ENABLE_LZ4 " [LZ4]" #endif @@ -6296,13 +6293,6 @@ add_option (struct options *options, options->comp.flags = 0; } #endif -#if defined(ENABLE_SNAPPY) - else if (streq (p[1], "snappy")) - { - options->comp.alg = COMP_ALG_SNAPPY; - options->comp.flags = COMP_F_SWAP; - } -#endif #if defined(ENABLE_LZ4) else if (streq (p[1], "lz4")) { diff --git a/src/openvpn/snappy.c b/src/openvpn/snappy.c deleted file mode 100644 index 24440bae993..00000000000 --- a/src/openvpn/snappy.c +++ /dev/null @@ -1,189 +0,0 @@ -/* - * OpenVPN -- An application to securely tunnel IP networks - * over a single UDP port, with support for SSL/TLS-based - * session authentication and key exchange, - * packet encryption, packet authentication, and - * packet compression. - * - * Copyright (C) 2002-2012 OpenVPN Technologies, Inc. - * - * 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 - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#elif defined(_MSC_VER) -#include "config-msvc.h" -#endif - -#include "syshead.h" - -#if defined(ENABLE_SNAPPY) - -#include "snappy-c.h" - -#include "comp.h" -#include "error.h" -#include "otime.h" - -#include "memdbg.h" - -/* Initial command byte to tell our peer if we compressed */ -#define SNAPPY_COMPRESS_BYTE 0x68 - -static void -snap_compress_init (struct compress_context *compctx) -{ - msg (D_INIT_MEDIUM, "Snappy compression initializing"); - ASSERT(compctx->flags & COMP_F_SWAP); -} - -static void -snap_compress_uninit (struct compress_context *compctx) -{ -} - -static void -snap_compress (struct buffer *buf, struct buffer work, - struct compress_context *compctx, - const struct frame* frame) -{ - snappy_status status; - bool compressed = false; - - if (buf->len <= 0) - return; - - /* - * In order to attempt compression, length must be at least COMPRESS_THRESHOLD. - */ - if (buf->len >= COMPRESS_THRESHOLD) - { - const size_t ps = PAYLOAD_SIZE (frame); - size_t zlen = ps + COMP_EXTRA_BUFFER (ps); - - ASSERT (buf_init (&work, FRAME_HEADROOM (frame))); - ASSERT (buf_safe (&work, zlen)); - - if (buf->len > ps) - { - dmsg (D_COMP_ERRORS, "Snappy compression buffer overflow"); - buf->len = 0; - return; - } - - status = snappy_compress((const char *)BPTR(buf), (size_t)BLEN(buf), (char *)BPTR(&work), &zlen); - if (status != SNAPPY_OK) - { - dmsg (D_COMP_ERRORS, "Snappy compression error: %d", status); - buf->len = 0; - return; - } - - ASSERT (buf_safe (&work, zlen)); - work.len = zlen; - compressed = true; - - dmsg (D_COMP, "Snappy compress %d -> %d", buf->len, work.len); - compctx->pre_compress += buf->len; - compctx->post_compress += work.len; - } - - /* did compression save us anything? */ - { - uint8_t comp_head_byte = NO_COMPRESS_BYTE_SWAP; - if (compressed && work.len < buf->len) - { - *buf = work; - comp_head_byte = SNAPPY_COMPRESS_BYTE; - } - - { - uint8_t *head = BPTR (buf); - uint8_t *tail = BEND (buf); - ASSERT (buf_safe (buf, 1)); - ++buf->len; - - /* move head byte of payload to tail */ - *tail = *head; - *head = comp_head_byte; - } - } -} - -static void -snap_decompress (struct buffer *buf, struct buffer work, - struct compress_context *compctx, - const struct frame* frame) -{ - size_t zlen = EXPANDED_SIZE (frame); - snappy_status status; - uint8_t c; /* flag indicating whether or not our peer compressed */ - - if (buf->len <= 0) - return; - - ASSERT (buf_init (&work, FRAME_HEADROOM (frame))); - - /* do unframing/swap (assumes buf->len > 0) */ - { - uint8_t *head = BPTR (buf); - c = *head; - --buf->len; - *head = *BEND (buf); - } - - if (c == SNAPPY_COMPRESS_BYTE) /* packet was compressed */ - { - ASSERT (buf_safe (&work, zlen)); - status = snappy_uncompress((const char *)BPTR(buf), (size_t)BLEN(buf), (char *)BPTR(&work), &zlen); - if (status != SNAPPY_OK) - { - dmsg (D_COMP_ERRORS, "Snappy decompression error: %d", status); - buf->len = 0; - return; - } - - ASSERT (buf_safe (&work, zlen)); - work.len = zlen; - - dmsg (D_COMP, "Snappy decompress %d -> %d", buf->len, work.len); - compctx->pre_decompress += buf->len; - compctx->post_decompress += work.len; - - *buf = work; - } - else if (c == NO_COMPRESS_BYTE_SWAP) /* packet was not compressed */ - { - ; - } - else - { - dmsg (D_COMP_ERRORS, "Bad Snappy decompression header byte: %d", c); - buf->len = 0; - } -} - -const struct compress_alg snappy_alg = { - "snappy", - snap_compress_init, - snap_compress_uninit, - snap_compress, - snap_decompress -}; - -#else -static void dummy(void) {} -#endif /* ENABLE_SNAPPY */ diff --git a/src/openvpn/snappy.h b/src/openvpn/snappy.h deleted file mode 100644 index 361a6317da1..00000000000 --- a/src/openvpn/snappy.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * OpenVPN -- An application to securely tunnel IP networks - * over a single UDP port, with support for SSL/TLS-based - * session authentication and key exchange, - * packet encryption, packet authentication, and - * packet compression. - * - * Copyright (C) 2002-2012 OpenVPN Technologies, Inc. - * - * 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 OPENVPN_SNAPPY_H -#define OPENVPN_SNAPPY_H - -#if defined(ENABLE_SNAPPY) - -#include "buffer.h" - -extern const struct compress_alg snappy_alg; - -struct snappy_workspace -{ -}; - -#endif /* ENABLE_SNAPPY */ -#endif diff --git a/src/openvpn/syshead.h b/src/openvpn/syshead.h index 3aa5c5f1963..7e77b6cdefb 100644 --- a/src/openvpn/syshead.h +++ b/src/openvpn/syshead.h @@ -710,7 +710,7 @@ socket_defined (const socket_descriptor_t sd) /* * Compression support */ -#if defined(ENABLE_SNAPPY) || defined(ENABLE_LZO) || defined(ENABLE_LZ4) || \ +#if defined(ENABLE_LZO) || defined(ENABLE_LZ4) || \ defined(ENABLE_COMP_STUB) #define USE_COMP #endif From 0d1a75bfe241466230c41a52c6013494135c5935 Mon Sep 17 00:00:00 2001 From: Lev Stipakov Date: Sat, 10 Oct 2015 19:04:25 +0300 Subject: [PATCH 114/643] Send push reply right after async auth complete v3: * better comments * better variable naming * include sys/inotify.h if HAVE_SYS_INOTIFY_H is defined v2: More careful inotify_watchers handling * Ensure that same multi_instance is added only once * Ensure that multi_instance is always removed v1: This feature speeds up connection establishment in cases when async authentication result is not ready when first push request arrives. At the moment server sends push reply only when it receives next push request, which comes 5 seconds later. Implementation overview. Add new configure option ENABLE_ASYNC_PUSH, which can be enabled if system supports inotify. Add inotify descriptor to an event loop. Add inotify watch for a authentication control file. Store mapping between watch descriptor and multi_instance in a dictionary. When file is closed, inotify fires an event and we continue with connection establishment - call client- connect etc and send push reply. Inotify watch descriptor got automatically deleted after file is closed or when file is removed. We catch that event and remove it from the dictionary. Feature is easily tested with sample "defer" plugin and following settings: auth-user-pass-optional setenv test_deferred_auth 3 plugin simple.so Signed-off-by: Lev Stipakov Add doxygen comment Acked-by: David Sommerseth Message-Id: <1444493065-13506-1-git-send-email-lstipakov@gmail.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/10248 Signed-off-by: David Sommerseth --- configure.ac | 15 ++++ src/openvpn/forward.c | 8 +++ src/openvpn/mtcp.c | 28 ++++++++ src/openvpn/mudp.c | 27 ++++++++ src/openvpn/multi.c | 155 +++++++++++++++++++++++++++++++++++++++++- src/openvpn/multi.h | 21 ++++++ src/openvpn/openvpn.h | 10 +++ src/openvpn/push.c | 69 +++++++++++-------- src/openvpn/push.h | 2 + 9 files changed, 304 insertions(+), 31 deletions(-) diff --git a/configure.ac b/configure.ac index 77b49154c58..342458433e4 100644 --- a/configure.ac +++ b/configure.ac @@ -271,6 +271,13 @@ AC_ARG_ENABLE( [enable_systemd="no"] ) +AC_ARG_ENABLE( + [async-push], + [AS_HELP_STRING([--enable-async-push], [enable async-push support @<:@default=no@:>@])], + [enable_async_push="yes"], + [enable_async_push="no"] +) + AC_ARG_WITH( [special-build], [AS_HELP_STRING([--with-special-build=STRING], [specify special build string])], @@ -1155,6 +1162,14 @@ if test "${enable_plugin_auth_pam}" = "yes"; then fi fi +if test "${enable_async_push}" = "yes"; then + AC_CHECK_HEADERS( + [sys/inotify.h], + AC_DEFINE([ENABLE_ASYNC_PUSH], [1], [Enable async push]), + AC_MSG_ERROR([inotify.h not found.]) + ) +fi + CONFIGURE_DEFINES="`set | grep '^enable_.*=' ; set | grep '^with_.*='`" AC_DEFINE_UNQUOTED([CONFIGURE_DEFINES], ["`echo ${CONFIGURE_DEFINES}`"], [Configuration settings]) diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c index c17be3514e5..62eb6fc22eb 100644 --- a/src/openvpn/forward.c +++ b/src/openvpn/forward.c @@ -1384,6 +1384,9 @@ io_wait_dowork (struct context *c, const unsigned int flags) #ifdef ENABLE_MANAGEMENT static int management_shift = 6; /* depends on MANAGEMENT_READ and MANAGEMENT_WRITE */ #endif +#ifdef ENABLE_ASYNC_PUSH + static int file_shift = 8; /* listening inotify events */ +#endif /* * Decide what kind of events we want to wait for. @@ -1478,6 +1481,11 @@ io_wait_dowork (struct context *c, const unsigned int flags) management_socket_set (management, c->c2.event_set, (void*)&management_shift, NULL); #endif +#ifdef ENABLE_ASYNC_PUSH + /* arm inotify watcher */ + event_ctl (c->c2.event_set, c->c2.inotify_fd, EVENT_READ, (void*)&file_shift); +#endif + /* * Possible scenarios: * (1) tcp/udp port has data available to read diff --git a/src/openvpn/mtcp.c b/src/openvpn/mtcp.c index dc15f092a7b..b27c5eb7b6e 100644 --- a/src/openvpn/mtcp.c +++ b/src/openvpn/mtcp.c @@ -62,6 +62,10 @@ # define MTCP_MANAGEMENT ((void*)4) #endif +#ifdef ENABLE_ASYNC_PUSH +#define MTCP_FILE_CLOSE_WRITE ((void*)5) +#endif + #define MTCP_N ((void*)16) /* upper bound on MTCP_x */ struct ta_iow_flags @@ -245,6 +249,12 @@ multi_tcp_wait (const struct context *c, if (management) management_socket_set (management, mtcp->es, MTCP_MANAGEMENT, &mtcp->management_persist_flags); #endif + +#ifdef ENABLE_ASYNC_PUSH + /* arm inotify watcher */ + event_ctl (mtcp->es, c->c2.inotify_fd, EVENT_READ, MTCP_FILE_CLOSE_WRITE); +#endif + status = event_wait (mtcp->es, &c->c2.timeval, mtcp->esr, mtcp->maxevents); update_time (); mtcp->n_esr = 0; @@ -636,6 +646,12 @@ multi_tcp_process_io (struct multi_context *m) { get_signal (&m->top.sig->signal_received); } +#ifdef ENABLE_ASYNC_PUSH + else if (e->arg == MTCP_FILE_CLOSE_WRITE) + { + multi_process_file_closed (m, MPP_PRE_SELECT | MPP_RECORD_TOUCH); + } +#endif } if (IS_SIG (&m->top)) break; @@ -684,6 +700,14 @@ tunnel_server_tcp (struct context *top) /* finished with initialization */ initialization_sequence_completed (top, ISC_SERVER); /* --mode server --proto tcp-server */ +#ifdef ENABLE_ASYNC_PUSH + multi.top.c2.inotify_fd = inotify_init(); + if (multi.top.c2.inotify_fd < 0) + { + msg (D_MULTI_ERRORS, "MULTI: inotify_init error: %s", strerror(errno)); + } +#endif + /* per-packet event loop */ while (true) { @@ -712,6 +736,10 @@ tunnel_server_tcp (struct context *top) perf_pop (); } +#ifdef ENABLE_ASYNC_PUSH + close(top->c2.inotify_fd); +#endif + /* shut down management interface */ uninit_management_callback_multi (&multi); diff --git a/src/openvpn/mudp.c b/src/openvpn/mudp.c index 57118f879c3..3aed3a0a015 100644 --- a/src/openvpn/mudp.c +++ b/src/openvpn/mudp.c @@ -38,6 +38,10 @@ #include "memdbg.h" +#ifdef HAVE_SYS_INOTIFY_H +#include +#endif + /* * Get a client instance based on real address. If * the instance doesn't exist, create it while @@ -177,6 +181,10 @@ multi_process_io_udp (struct multi_context *m) strcat (buf, "TR/"); else if (status & TUN_WRITE) strcat (buf, "TW/"); +#ifdef ENABLE_ASYNC_PUSH + else if (status & FILE_CLOSED) + strcat (buf, "FC/"); +#endif printf ("IO %s\n", buf); #endif @@ -214,6 +222,13 @@ multi_process_io_udp (struct multi_context *m) if (!IS_SIG (&m->top)) multi_process_incoming_tun (m, mpp_flags); } +#ifdef ENABLE_ASYNC_PUSH + /* INOTIFY callback */ + else if (status & FILE_CLOSED) + { + multi_process_file_closed(m, mpp_flags); + } +#endif } /* @@ -276,6 +291,14 @@ tunnel_server_udp_single_threaded (struct context *top) /* finished with initialization */ initialization_sequence_completed (top, ISC_SERVER); /* --mode server --proto udp */ +#ifdef ENABLE_ASYNC_PUSH + multi.top.c2.inotify_fd = inotify_init(); + if (multi.top.c2.inotify_fd < 0) + { + msg (D_MULTI_ERRORS, "MULTI: inotify_init error: %s", strerror(errno)); + } +#endif + /* per-packet event loop */ while (true) { @@ -304,6 +327,10 @@ tunnel_server_udp_single_threaded (struct context *top) perf_pop (); } +#ifdef ENABLE_ASYNC_PUSH + close(top->c2.inotify_fd); +#endif + /* shut down management interface */ uninit_management_callback_multi (&multi); diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index 902c4dc35c8..05c36db4b0a 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -28,6 +28,11 @@ #include "config-msvc.h" #endif +#ifdef HAVE_SYS_INOTIFY_H +#include +#define INOTIFY_EVENT_BUFFER_SIZE 16384 +#endif + #include "syshead.h" #if P2MP_SERVER @@ -243,6 +248,23 @@ cid_compare_function (const void *key1, const void *key2) #endif +#ifdef ENABLE_ASYNC_PUSH +static uint32_t +/* + * inotify watcher descriptors are used as hash value + */ +int_hash_function (const void *key, uint32_t iv) +{ + return (unsigned long)key; +} + +static bool +int_compare_function (const void *key1, const void *key2) +{ + return (unsigned long)key1 == (unsigned long)key2; +} +#endif + /* * Main initialization function, init multi_context object. */ @@ -304,6 +326,17 @@ multi_init (struct multi_context *m, struct context *t, bool tcp_mode, int threa cid_compare_function); #endif +#ifdef ENABLE_ASYNC_PUSH + /* + * Mapping between inotify watch descriptors and + * multi_instances. + */ + m->inotify_watchers = hash_init (t->options.real_hash_size, + get_random(), + int_hash_function, + int_compare_function); +#endif + /* * This is our scheduler, for time-based wakeup * events. @@ -562,6 +595,14 @@ multi_close_instance (struct multi_context *m, } #endif +#ifdef ENABLE_ASYNC_PUSH + if (mi->inotify_watch != -1) + { + hash_remove(m->inotify_watchers, (void*) (unsigned long)mi->inotify_watch); + mi->inotify_watch = -1; + } +#endif + m->instances[mi->context.c2.tls_multi->peer_id] = NULL; schedule_remove_entry (m->schedule, (struct schedule_entry *) mi); @@ -642,6 +683,11 @@ multi_uninit (struct multi_context *m) free(m->instances); +#ifdef ENABLE_ASYNC_PUSH + hash_free (m->inotify_watchers); + m->inotify_watchers = NULL; +#endif + schedule_free (m->schedule); mbuf_free (m->mbuf); ifconfig_pool_free (m->ifconfig_pool); @@ -718,6 +764,11 @@ multi_create_instance (struct multi_context *m, const struct mroute_addr *real) mi->context.c2.push_reply_deferred = true; +#ifdef ENABLE_ASYNC_PUSH + mi->context.c2.push_request_received = false; + mi->inotify_watch = -1; +#endif + if (!multi_process_post (m, mi, MPP_PRE_SELECT)) { msg (D_MULTI_ERRORS, "MULTI: signal occurred during client instance initialization"); @@ -923,6 +974,13 @@ multi_print_status (struct multi_context *m, struct status_output *so, const int status_flush (so); gc_free (&gc_top); } + +#ifdef ENABLE_ASYNC_PUSH + if (m->inotify_watchers) + { + msg (D_MULTI_DEBUG, "inotify watchers count: %d\n", hash_n_elements(m->inotify_watchers)); + } +#endif } /* @@ -1877,6 +1935,14 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi /* set context-level authentication flag */ mi->context.c2.context_auth = CAS_SUCCEEDED; + +#ifdef ENABLE_ASYNC_PUSH + /* authentication complete, send push reply */ + if (mi->context.c2.push_request_received) + { + process_incoming_push_request(&mi->context); + } +#endif } else { @@ -1906,6 +1972,58 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi mi->context.c2.push_reply_deferred = false; } +#ifdef ENABLE_ASYNC_PUSH +/* + * Called when inotify event is fired, which happens when acf file is closed or deleted. + * Continues authentication and sends push_reply. + */ +void +multi_process_file_closed (struct multi_context *m, const unsigned int mpp_flags) +{ + char buffer[INOTIFY_EVENT_BUFFER_SIZE]; + size_t buffer_i = 0; + int r = read (m->top.c2.inotify_fd, buffer, INOTIFY_EVENT_BUFFER_SIZE); + + while (buffer_i < r) + { + /* parse inotify events */ + struct inotify_event *pevent = (struct inotify_event *) &buffer[buffer_i]; + size_t event_size = sizeof (struct inotify_event) + pevent->len; + buffer_i += event_size; + + msg(D_MULTI_DEBUG, "MULTI: modified fd %d, mask %d", pevent->wd, pevent->mask); + + struct multi_instance* mi = hash_lookup(m->inotify_watchers, (void*) (unsigned long) pevent->wd); + + if (pevent->mask & IN_CLOSE_WRITE) + { + if (mi) + { + /* continue authentication and send push_reply */ + multi_process_post (m, mi, mpp_flags); + } + else + { + msg(D_MULTI_ERRORS, "MULTI: multi_instance not found!"); + } + } + else if (pevent->mask & IN_IGNORED) + { + /* this event is _always_ fired when watch is removed or file is deleted */ + if (mi) + { + hash_remove(m->inotify_watchers, (void*) (unsigned long) pevent->wd); + mi->inotify_watch = -1; + } + } + else + { + msg(D_MULTI_ERRORS, "MULTI: unknown mask %d", pevent->mask); + } + } +} +#endif + /* * Add a mbuf buffer to a particular * instance. @@ -2066,19 +2184,50 @@ multi_process_post (struct multi_context *m, struct multi_instance *mi, const un if (!IS_SIG (&mi->context) && ((flags & MPP_PRE_SELECT) || ((flags & MPP_CONDITIONAL_PRE_SELECT) && !ANY_OUT (&mi->context)))) { +#if defined(ENABLE_ASYNC_PUSH) && defined(ENABLE_DEF_AUTH) + bool was_authenticated = false; + struct key_state *ks = NULL; + if (mi->context.c2.tls_multi) + { + ks = &mi->context.c2.tls_multi->session[TM_ACTIVE].key[KS_PRIMARY]; + was_authenticated = ks->authenticated; + } +#endif + /* figure timeouts and fetch possible outgoing to_link packets (such as ping or TLS control) */ pre_select (&mi->context); - if (!IS_SIG (&mi->context)) +#if defined(ENABLE_ASYNC_PUSH) && defined(ENABLE_DEF_AUTH) + if (ks && ks->auth_control_file && ks->auth_deferred && !was_authenticated) { - /* tell scheduler to wake us up at some point in the future */ - multi_schedule_context_wakeup(m, mi); + /* watch acf file */ + long watch_descriptor = inotify_add_watch(m->top.c2.inotify_fd, ks->auth_control_file, IN_CLOSE_WRITE | IN_ONESHOT); + if (watch_descriptor >= 0) + { + if (mi->inotify_watch != -1) + { + hash_remove(m->inotify_watchers, (void*) (unsigned long)mi->inotify_watch); + } + hash_add (m->inotify_watchers, (const uintptr_t*)watch_descriptor, mi, true); + mi->inotify_watch = watch_descriptor; + } + else + { + msg(M_NONFATAL, "MULTI: inotify_add_watch error: %s", strerror(errno)); + } + } +#endif + if (!IS_SIG (&mi->context)) + { /* connection is "established" when SSL/TLS key negotiation succeeds and (if specified) auth user/pass succeeds */ if (!mi->connection_established_flag && CONNECTION_ESTABLISHED (&mi->context)) multi_connection_established (m, mi); + + /* tell scheduler to wake us up at some point in the future */ + multi_schedule_context_wakeup(m, mi); } } diff --git a/src/openvpn/multi.h b/src/openvpn/multi.h index 32b89d25e1c..69ed85e6687 100644 --- a/src/openvpn/multi.h +++ b/src/openvpn/multi.h @@ -105,6 +105,10 @@ struct multi_instance { struct context context; /**< The context structure storing state * for this VPN tunnel. */ + +#ifdef ENABLE_ASYNC_PUSH + int inotify_watch; /* watch descriptor for acf */ +#endif }; @@ -172,6 +176,11 @@ struct multi_context { * Timer object for stale route check */ struct event_timeout stale_routes_check_et; + +#ifdef ENABLE_ASYNC_PUSH + /* mapping between inotify watch descriptors and multi_instances */ + struct hash *inotify_watchers; +#endif }; /* @@ -327,6 +336,18 @@ void multi_close_instance_on_signal (struct multi_context *m, struct multi_insta void init_management_callback_multi (struct multi_context *m); void uninit_management_callback_multi (struct multi_context *m); + +#ifdef ENABLE_ASYNC_PUSH +/** + * Called when inotify event is fired, which happens when acf file is closed or deleted. + * Continues authentication and sends push_repl + * + * @param m multi_context + * @param mpp_flags + */ +void multi_process_file_closed (struct multi_context *m, const unsigned int mpp_flags); +#endif + /* * Return true if our output queue is not full */ diff --git a/src/openvpn/openvpn.h b/src/openvpn/openvpn.h index ef2226927cf..4fab00be0ac 100644 --- a/src/openvpn/openvpn.h +++ b/src/openvpn/openvpn.h @@ -241,6 +241,9 @@ struct context_2 # define MANAGEMENT_READ (1<<6) # define MANAGEMENT_WRITE (1<<7) # endif +#ifdef ENABLE_ASYNC_PUSH +# define FILE_CLOSED (1<<8) +#endif unsigned int event_set_status; @@ -436,6 +439,9 @@ struct context_2 #if P2MP_SERVER /* --ifconfig endpoints to be pushed to client */ bool push_reply_deferred; +#ifdef ENABLE_ASYNC_PUSH + bool push_request_received; +#endif bool push_ifconfig_defined; time_t sent_push_reply_expiry; in_addr_t push_ifconfig_local; @@ -479,6 +485,10 @@ struct context_2 #ifdef MANAGEMENT_DEF_AUTH struct man_def_auth_context mda_context; #endif + +#ifdef ENABLE_ASYNC_PUSH + int inotify_fd; /* descriptor for monitoring file changes */ +#endif }; diff --git a/src/openvpn/push.c b/src/openvpn/push.c index b9d0c4c5eac..704818dec8e 100644 --- a/src/openvpn/push.c +++ b/src/openvpn/push.c @@ -410,6 +410,46 @@ push_reset (struct options *o) } #endif +int +process_incoming_push_request (struct context *c) +{ + int ret = PUSH_MSG_ERROR; + +#ifdef ENABLE_ASYNC_PUSH + c->c2.push_request_received = true; +#endif + if (tls_authentication_status (c->c2.tls_multi, 0) == TLS_AUTHENTICATION_FAILED || c->c2.context_auth == CAS_FAILED) + { + const char *client_reason = tls_client_reason (c->c2.tls_multi); + send_auth_failed (c, client_reason); + ret = PUSH_MSG_AUTH_FAILURE; + } + else if (!c->c2.push_reply_deferred && c->c2.context_auth == CAS_SUCCEEDED) + { + time_t now; + + openvpn_time (&now); + if (c->c2.sent_push_reply_expiry > now) + { + ret = PUSH_MSG_ALREADY_REPLIED; + } + else + { + if (send_push_reply (c)) + { + ret = PUSH_MSG_REQUEST; + c->c2.sent_push_reply_expiry = now + 30; + } + } + } + else + { + ret = PUSH_MSG_REQUEST_DEFERRED; + } + + return ret; +} + int process_incoming_push_msg (struct context *c, const struct buffer *buffer, @@ -423,34 +463,7 @@ process_incoming_push_msg (struct context *c, #if P2MP_SERVER if (buf_string_compare_advance (&buf, "PUSH_REQUEST")) { - if (tls_authentication_status (c->c2.tls_multi, 0) == TLS_AUTHENTICATION_FAILED || c->c2.context_auth == CAS_FAILED) - { - const char *client_reason = tls_client_reason (c->c2.tls_multi); - send_auth_failed (c, client_reason); - ret = PUSH_MSG_AUTH_FAILURE; - } - else if (!c->c2.push_reply_deferred && c->c2.context_auth == CAS_SUCCEEDED) - { - time_t now; - - openvpn_time(&now); - if (c->c2.sent_push_reply_expiry > now) - { - ret = PUSH_MSG_ALREADY_REPLIED; - } - else - { - if (send_push_reply (c)) - { - ret = PUSH_MSG_REQUEST; - c->c2.sent_push_reply_expiry = now + 30; - } - } - } - else - { - ret = PUSH_MSG_REQUEST_DEFERRED; - } + ret = process_incoming_push_request(c); } else #endif diff --git a/src/openvpn/push.h b/src/openvpn/push.h index 8c3f1575baa..5eca45f4ca1 100644 --- a/src/openvpn/push.h +++ b/src/openvpn/push.h @@ -40,6 +40,8 @@ void incoming_push_message (struct context *c, const struct buffer *buffer); +int process_incoming_push_request (struct context *c); + int process_incoming_push_msg (struct context *c, const struct buffer *buffer, bool honor_received_options, From 8929a395c7e9ad41872d9d25b654a14e1bb37e9c Mon Sep 17 00:00:00 2001 From: Lev Stipakov Date: Sun, 11 Oct 2015 13:15:31 +0300 Subject: [PATCH 115/643] Fix compilation with --disable-server Add missing #if P2MP_SERVER Acked-by: David Sommerseth Message-Id: <1444558531-18241-1-git-send-email-lstipakov@gmail.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/10259 Signed-off-by: David Sommerseth --- src/openvpn/push.c | 2 ++ src/openvpn/push.h | 5 ++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/openvpn/push.c b/src/openvpn/push.c index 704818dec8e..a4cb726d0ca 100644 --- a/src/openvpn/push.c +++ b/src/openvpn/push.c @@ -410,6 +410,7 @@ push_reset (struct options *o) } #endif +#if P2MP_SERVER int process_incoming_push_request (struct context *c) { @@ -449,6 +450,7 @@ process_incoming_push_request (struct context *c) return ret; } +#endif int process_incoming_push_msg (struct context *c, diff --git a/src/openvpn/push.h b/src/openvpn/push.h index 5eca45f4ca1..fa06e080bd8 100644 --- a/src/openvpn/push.h +++ b/src/openvpn/push.h @@ -37,9 +37,6 @@ #define PUSH_MSG_CONTINUATION 5 #define PUSH_MSG_ALREADY_REPLIED 6 -void incoming_push_message (struct context *c, - const struct buffer *buffer); - int process_incoming_push_request (struct context *c); int process_incoming_push_msg (struct context *c, @@ -56,6 +53,8 @@ void server_pushed_signal (struct context *c, const struct buffer *buffer, const #if P2MP_SERVER +void incoming_push_message (struct context *c, const struct buffer *buffer); + void clone_push_list (struct options *o); void push_option (struct options *o, const char *opt, int msglevel); From cba33989101175ac07434b9c5cceba116bf38127 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Wed, 14 Oct 2015 15:05:56 +0200 Subject: [PATCH 116/643] Fix commit c67acea173dc9ee37220f5b9ff14ede081181992 Move things to the proper place, ensure that line_ptr is actually properly initialized for *every* line read, not just for the first one Acked-by: Lev Stipakov Message-Id: 1444827956-2169-1-git-send-email-arne@rfc2549.org URL: http://article.gmane.org/gmane.network.openvpn.devel/10271 Signed-off-by: David Sommerseth --- src/openvpn/options.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openvpn/options.c b/src/openvpn/options.c index cfba7286725..56548307976 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -3691,13 +3691,13 @@ static char * read_inline_file (struct in_src *is, const char *close_tag, struct gc_arena *gc) { char line[OPTION_LINE_SIZE]; - char *line_ptr = line; struct buffer buf = alloc_buf (8*OPTION_LINE_SIZE); char *ret; bool endtagfound = false; while (in_src_get (is, line, sizeof (line))) { + char *line_ptr = line; /* Remove leading spaces */ while (isspace(*line_ptr)) line_ptr++; if (!strncmp (line_ptr, close_tag, strlen (close_tag))) From 5203d8094f38a9d23d983377171c11b1d3a82ad2 Mon Sep 17 00:00:00 2001 From: Lev Stipakov Date: Thu, 15 Oct 2015 14:39:42 +0300 Subject: [PATCH 117/643] Refine float logging v2: * Bump log level for attack attempt message * More clear message for float event v1: * Decrease log level for peer float message Signed-off-by: Lev Stipakov Acked-by: Steffan Karger Message-Id: 1444909182-11785-1-git-send-email-lstipakov@gmail.com URL: http://article.gmane.org/gmane.network.openvpn.devel/10276 Signed-off-by: David Sommerseth --- src/openvpn/mudp.c | 2 +- src/openvpn/multi.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/openvpn/mudp.c b/src/openvpn/mudp.c index 3aed3a0a015..ce6720604f9 100644 --- a/src/openvpn/mudp.c +++ b/src/openvpn/mudp.c @@ -79,7 +79,7 @@ multi_get_create_instance_udp (struct multi_context *m, bool *floated) { /* reset prefix, since here we are not sure peer is the one it claims to be */ ungenerate_prefix(mi); - msg (D_MULTI_ERRORS, "Untrusted peer %" PRIu32 " wants to float to %s", peer_id, + msg (D_MULTI_MEDIUM, "Float requested for peer %" PRIu32 " to %s", peer_id, mroute_addr_print (&real, &gc)); } } diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index 05c36db4b0a..7c3aaaca4a7 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -2286,7 +2286,7 @@ void multi_process_float (struct multi_context* m, struct multi_instance* mi) /* do not float if target address is taken by client with another cert */ if (!cert_hash_compare(m1->locked_cert_hash_set, m2->locked_cert_hash_set)) { - msg (D_MULTI_MEDIUM, "Disallow float to an address taken by another client %s", + msg (D_MULTI_LOW, "Disallow float to an address taken by another client %s", multi_instance_string (ex_mi, false, &gc)); mi->context.c2.buf.len = 0; From 825b3272acb353e04b37f38299d4df7e63e87d9e Mon Sep 17 00:00:00 2001 From: Lukasz Kutyla Date: Sat, 17 Oct 2015 21:15:15 +0200 Subject: [PATCH 118/643] Fix privilege drop if first connection attempt fails OpenVPN does not drop privileges (UID/GID/chroot) as requested according to the configuration file and/or passed arguments if the first connection attempt is not established successfully, this also includes applying SELinux context. Signals and restarts are processed after "context.first_time" is set to "false", which results in omitting entire privilege dropping block in "do_uid_gid_chroot()" when successful connection is finally made (everything is initialized correctly and said function is called), since "context.first_time" is used as block entry condition. We modify "do_uid_gid_chroot()" in such a way that allows us to drop privileges even when first connection attempt was unsuccessful. Signed-off-by: Lukasz Kutyla Acked-by: Steffan Karger Message-Id: <20151018103446.5fed9f97.movrax-dev@cryptolab.net> URL: http://article.gmane.org/gmane.network.openvpn.devel/10301 Acked-by: Steffan Karger Message-Id: <20151018103446.5fed9f97.movrax-dev@cryptolab.net 20151018103446.5fed9f97.movrax-dev@cryptolab.net> URL: http://article.gmane.org/gmane.network.openvpn.devel/10301 Signed-off-by: Gert Doering --- src/openvpn/init.c | 31 ++++++++++++++++++------------- src/openvpn/openvpn.h | 6 ++++-- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 5dd87815b32..c5c0ab6dd9e 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -950,31 +950,30 @@ do_uid_gid_chroot (struct context *c, bool no_delay) static const char why_not[] = "will be delayed because of --client, --pull, or --up-delay"; struct context_0 *c0 = c->c0; - if (c->first_time && c0 && !c0->uid_gid_set) + if (c0 && !c0->uid_gid_chroot_set) { /* chroot if requested */ if (c->options.chroot_dir) { if (no_delay) platform_chroot (c->options.chroot_dir); - else + else if (c->first_time) msg (M_INFO, "NOTE: chroot %s", why_not); } - /* set user and/or group that we want to setuid/setgid to */ - if (no_delay) + /* set user and/or group if we want to setuid/setgid */ + if (c0->uid_gid_specified) { - platform_group_set (&c0->platform_state_group); - platform_user_set (&c0->platform_state_user); - c0->uid_gid_set = true; - } - else if (c0->uid_gid_specified) - { - msg (M_INFO, "NOTE: UID/GID downgrade %s", why_not); + if (no_delay) { + platform_group_set (&c0->platform_state_group); + platform_user_set (&c0->platform_state_user); + } + else if (c->first_time) + msg (M_INFO, "NOTE: UID/GID downgrade %s", why_not); } #ifdef ENABLE_MEMSTATS - if (c->options.memstats_fn) + if (c->first_time && c->options.memstats_fn) mstats_open(c->options.memstats_fn); #endif @@ -993,10 +992,16 @@ do_uid_gid_chroot (struct context *c, bool no_delay) else msg (M_INFO, "setcon to '%s' succeeded", c->options.selinux_context); } - else + else if (c->first_time) msg (M_INFO, "NOTE: setcon %s", why_not); } #endif + + /* Privileges are going to be dropped by now (if requested), be sure + * to prevent any future privilege dropping attempts from now on. + */ + if (no_delay) + c0->uid_gid_chroot_set = true; } } diff --git a/src/openvpn/openvpn.h b/src/openvpn/openvpn.h index 4fab00be0ac..3f1df6ec44f 100644 --- a/src/openvpn/openvpn.h +++ b/src/openvpn/openvpn.h @@ -130,13 +130,15 @@ struct context_persist * * Level 0 state is initialized once at program startup, and then remains * throughout the lifetime of the OpenVPN process. This structure - * contains information related to the process's PID, user, and group. + * contains information related to the process's PID, user, group, and + * privileges. */ struct context_0 { /* workspace for --user/--group */ bool uid_gid_specified; - bool uid_gid_set; + /* helper which tells us whether we should keep trying to drop privileges */ + bool uid_gid_chroot_set; struct platform_state_user platform_state_user; struct platform_state_group platform_state_group; }; From f0b64e5dc00f35e3b0fe8c53a316ee74c9cbf15f Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Thu, 15 Oct 2015 16:38:38 +0200 Subject: [PATCH 119/643] Do not set the buffer size by default but rely on the operation system default. Also remove SOCKET_SND_RCV_BUF_MAX since limiting the buffer to 1000k is arbitrary and all OSes impose a maximum that can be set anyway. closes trac ticket #461 V2: SOCKET_SND_RCV_BUF_MAX removal Acked-by: Gert Doering Message-Id: <1444919918-4525-1-git-send-email-arne@rfc2549.org> URL: http://article.gmane.org/gmane.network.openvpn.devel/10280 Signed-off-by: Gert Doering --- doc/openvpn.8 | 4 ++-- src/openvpn/options.c | 4 ---- src/openvpn/socket.c | 16 +++++----------- src/openvpn/socket.h | 5 ----- 4 files changed, 7 insertions(+), 22 deletions(-) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 3a864094b09..b6d5aedce00 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -1433,12 +1433,12 @@ connection problems) with the following options: .TP .B \-\-sndbuf size Set the TCP/UDP socket send buffer size. -Currently defaults to 65536 bytes. +Defaults to operation system default. .\"********************************************************* .TP .B \-\-rcvbuf size Set the TCP/UDP socket receive buffer size. -Currently defaults to 65536 bytes. +Defaults to operation system default. .\"********************************************************* .TP .B \-\-mark value diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 56548307976..2f8915daa08 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -785,10 +785,6 @@ init_options (struct options *o, const bool init_gc) #ifdef ENABLE_FEATURE_TUN_PERSIST o->persist_mode = 1; #endif -#ifndef WIN32 - o->rcvbuf = 65536; - o->sndbuf = 65536; -#endif #ifdef TARGET_LINUX o->tuntap_options.txqueuelen = 100; #endif diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c index 925665c5213..b24d9ad5f37 100644 --- a/src/openvpn/socket.c +++ b/src/openvpn/socket.c @@ -623,12 +623,9 @@ static void socket_set_sndbuf (int sd, int size) { #if defined(HAVE_SETSOCKOPT) && defined(SOL_SOCKET) && defined(SO_SNDBUF) - if (size > 0 && size < SOCKET_SND_RCV_BUF_MAX) + if (setsockopt (sd, SOL_SOCKET, SO_SNDBUF, (void *) &size, sizeof (size)) != 0) { - if (setsockopt (sd, SOL_SOCKET, SO_SNDBUF, (void *) &size, sizeof (size)) != 0) - { - msg (M_WARN, "NOTE: setsockopt SO_SNDBUF=%d failed", size); - } + msg (M_WARN, "NOTE: setsockopt SO_SNDBUF=%d failed", size); } #endif } @@ -652,13 +649,10 @@ static bool socket_set_rcvbuf (int sd, int size) { #if defined(HAVE_SETSOCKOPT) && defined(SOL_SOCKET) && defined(SO_RCVBUF) - if (size > 0 && size < SOCKET_SND_RCV_BUF_MAX) + if (setsockopt (sd, SOL_SOCKET, SO_RCVBUF, (void *) &size, sizeof (size)) != 0) { - if (setsockopt (sd, SOL_SOCKET, SO_RCVBUF, (void *) &size, sizeof (size)) != 0) - { - msg (M_WARN, "NOTE: setsockopt SO_RCVBUF=%d failed", size); - return false; - } + msg (M_WARN, "NOTE: setsockopt SO_RCVBUF=%d failed", size); + return false; } return true; #endif diff --git a/src/openvpn/socket.h b/src/openvpn/socket.h index 49cfab680fd..54cdc8878a3 100644 --- a/src/openvpn/socket.h +++ b/src/openvpn/socket.h @@ -41,11 +41,6 @@ */ #define OPENVPN_PORT "1194" -/* - * Maximum size passed passed to setsockopt SNDBUF/RCVBUF - */ -#define SOCKET_SND_RCV_BUF_MAX 1000000 - /* * Number of seconds that "resolv-retry infinite" * represents. From c345ffb34c48a8df8d2728303864d5e1884c00f0 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Thu, 15 Oct 2015 16:44:58 +0200 Subject: [PATCH 120/643] Start Changes.rst that lists changes in 2.4.0 This list is proably incomplete but should give a good starting point Acked-by: Gert Doering Message-Id: <1444920298-5972-1-git-send-email-arne@rfc2549.org> URL: http://article.gmane.org/gmane.network.openvpn.devel/10283 Signed-off-by: Gert Doering --- Changes.rst | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 Changes.rst diff --git a/Changes.rst b/Changes.rst new file mode 100644 index 00000000000..41629bdbd2f --- /dev/null +++ b/Changes.rst @@ -0,0 +1,67 @@ +Version 2.4.0 +============= + + +New features +------------ + +keying-material-exporter + Keying Material Exporter [RFC-5705] allow additional keying material to be + derived from existing TLS channel. + +redirect-gateway ipv6 + OpenVPN has now feature parity between IPv4 and IPv6 for redirect + gateway including the handling of overlapping IPv6 routes with + IPv6 remote VPN server address + +Mac OS X Keychain management client + add contrib/keychain-mcd which allows to use Mac OS X keychain + certificates with OpenVPN + +Peer ID support + Added new packet format P_DATA_V2, which includes peer-id. If + server and client support it, client sends all data packets in + the new format. When data packet arrives, server identifies peer + by peer-id. If peer's ip/port has changed, server assumes that + client has floated, verifies HMAC and updates ip/port in internal structs. + +Dualstack client connect + Instead of only using the first address of each --remote OpenVPN + will now try all addresses (IPv6 and IPv4) of a --remote entry. + +LZ4 Compression + Additionally to LZO compression OpenVPN now also supports LZ4 + compression. + + +User-visible Changes +-------------------- +- proto udp and proto tcp specify to use IPv4 and IPv6. The new + options proto udp4 and tcp4 specify to use IPv4 only. + +- connect-timeout specifies now the timeout until the first TLS packet + is received (identical to server-poll-timeout) and this timeout now + includes the removed socks proxy timeout and http proxy timeout. + + In --static mode connect-timeout specifies the timeout for TCP and + proxy connection establishment + + +- connect-retry now specifies the maximum number of unsucessfully + trying all remote/connection entries before exiting. + +- sndbuf and recvbuf default now to OS default instead of 64k + +- OpenVPN exits with an error if an option has extra parameters; + previously they were silently ignored + +- The default of tls-cipher is now "DEFAULT:!EXP:!PSK:!SRP:!kRSA" + instead of "DEFAULT" to always select perfect forward security + cipher suites + +- --tls-auth always requires OpenVPN static key files and will no + longer work with free form files + +- proto udp6/tcp6 in server mode will now try to always listen to + both IPv4 and IPv6 on platforms that allow it. Use bind ipv6only + to explicitly listen only on IPv6. From e8a9e3203bf00605dae000d31095076ae038491c Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Wed, 21 Oct 2015 10:08:06 +0200 Subject: [PATCH 121/643] hardening: add insurance to exit on a failed ASSERT() The code behind our ASSERT() macro is pretty complex. Although it seems to be correct, make it trivially clear we will never return from a failed assert by adding an _exit(1) call. As was suggested by Sebastian Krahmer of the SuSE security team. To make sure they that tools like clang static analyzer and coverity understand that assert_failed() will not return, add an __attribute__((__noreturn__)) annotation. v2: use __attribute__ instead of inline to convince static analysers. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1445414886-11052-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/10349 Signed-off-by: Gert Doering --- src/openvpn/error.c | 1 + src/openvpn/error.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/openvpn/error.c b/src/openvpn/error.c index 77b6cec06ba..66f37f3b9a4 100644 --- a/src/openvpn/error.c +++ b/src/openvpn/error.c @@ -397,6 +397,7 @@ void assert_failed (const char *filename, int line) { msg (M_FATAL, "Assertion failed at %s:%d", filename, line); + _exit(1); } /* diff --git a/src/openvpn/error.h b/src/openvpn/error.h index d5204f3f380..4d338439d74 100644 --- a/src/openvpn/error.h +++ b/src/openvpn/error.h @@ -210,7 +210,7 @@ FILE *msg_fp(const unsigned int flags); /* Fatal logic errors */ #define ASSERT(x) do { if (!(x)) assert_failed(__FILE__, __LINE__); } while (false) -void assert_failed (const char *filename, int line); +void assert_failed (const char *filename, int line) __attribute__((__noreturn__)); #ifdef ENABLE_DEBUG void crash (void); /* force a segfault (debugging only) */ From dd8d351dbc92ede6726b7090ed4eceb9b95318c6 Mon Sep 17 00:00:00 2001 From: Lev Stipakov Date: Thu, 22 Oct 2015 10:51:22 +0300 Subject: [PATCH 122/643] Generate openvpn-plugin.h for MSVC build openvpn-plugin.h was not generated for MSVC build since it has been removed from sources and made generated by configure script. This fix generates it for MSVC build and substitutes macroses like @OPENVPN_VERSION_MAJOR@ with actual values. Signed-off-by: Lev Stipakov Acked-by: Gert Doering Message-Id: <1445500282-23129-1-git-send-email-lstipakov@gmail.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/10360 Signed-off-by: Gert Doering --- build/msvc/msvc-generate/Makefile.mak | 27 ++++++++++++++++++++------ build/msvc/msvc-generate/version.m4.in | 3 +++ 2 files changed, 24 insertions(+), 6 deletions(-) mode change 100755 => 100644 build/msvc/msvc-generate/Makefile.mak create mode 100644 build/msvc/msvc-generate/version.m4.in diff --git a/build/msvc/msvc-generate/Makefile.mak b/build/msvc/msvc-generate/Makefile.mak old mode 100755 new mode 100644 index 72415f17398..59fc9f0ed33 --- a/build/msvc/msvc-generate/Makefile.mak +++ b/build/msvc/msvc-generate/Makefile.mak @@ -1,13 +1,28 @@ # Copyright (C) 2008-2012 Alon Bar-Lev CONFIG=$(SOURCEBASE)/version.m4 -INPUT=$(SOURCEBASE)/config-msvc-version.h.in -OUTPUT=$(SOURCEBASE)/config-msvc-version.h -all: $(OUTPUT) +INPUT_MSVC_VER=$(SOURCEBASE)/config-msvc-version.h.in +OUTPUT_MSVC_VER=$(SOURCEBASE)/config-msvc-version.h -$(OUTPUT): $(INPUT) $(CONFIG) - cscript //nologo msvc-generate.js --config="$(CONFIG)" --input="$(INPUT)" --output="$(OUTPUT)" +INPUT_PLUGIN=$(SOURCEBASE)/include/openvpn-plugin.h.in +OUTPUT_PLUGIN=$(SOURCEBASE)/include/openvpn-plugin.h + +INPUT_PLUGIN_CONFIG=version.m4.in +OUTPUT_PLUGIN_CONFIG=version.m4 + +all: $(OUTPUT_MSVC_VER) $(OUTPUT_PLUGIN) + +$(OUTPUT_MSVC_VER): $(INPUT_MSVC_VER) $(CONFIG) + cscript //nologo msvc-generate.js --config="$(CONFIG)" --input="$(INPUT_MSVC_VER)" --output="$(OUTPUT_MSVC_VER)" + +$(OUTPUT_PLUGIN_CONFIG): $(INPUT_PLUGIN_CONFIG) + cscript //nologo msvc-generate.js --config="$(CONFIG)" --input="$(INPUT_PLUGIN_CONFIG)" --output="$(OUTPUT_PLUGIN_CONFIG)" + +$(OUTPUT_PLUGIN): $(INPUT_PLUGIN) $(OUTPUT_PLUGIN_CONFIG) + cscript //nologo msvc-generate.js --config="$(OUTPUT_PLUGIN_CONFIG)" --input="$(INPUT_PLUGIN)" --output="$(OUTPUT_PLUGIN)" clean: - -del "$(OUTPUT)" + -del "$(OUTPUT_MSVC_VER)" + -del "$(OUTPUT_PLUGIN)" + -del "$(OUTPUT_PLUGIN_CONFIG)" diff --git a/build/msvc/msvc-generate/version.m4.in b/build/msvc/msvc-generate/version.m4.in new file mode 100644 index 00000000000..cbb4fef1f88 --- /dev/null +++ b/build/msvc/msvc-generate/version.m4.in @@ -0,0 +1,3 @@ +define([OPENVPN_VERSION_MAJOR], [@PRODUCT_VERSION_MAJOR@]) +define([OPENVPN_VERSION_MINOR], [@PRODUCT_VERSION_MINOR@]) +define([OPENVPN_VERSION_PATCH], [@PRODUCT_VERSION_PATCH@]) From cfc13b38bc6504b9768e4cc43311807d6b074672 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Wed, 21 Oct 2015 00:38:26 +0200 Subject: [PATCH 123/643] Fix memory leak in auth-pam plugin As it says on the tin. aresp would not be free'd nor returned by my_conv() on errors. Note that we never reach this code if allocation of aresp failed. Found with the Clang static analyzer. Signed-off-by: Steffan Karger Acked-by: Lev Stipakov Message-Id: <1445380706-20864-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/10338 Signed-off-by: Gert Doering --- src/plugins/auth-pam/auth-pam.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/plugins/auth-pam/auth-pam.c b/src/plugins/auth-pam/auth-pam.c index bd71792711c..95692ab229f 100644 --- a/src/plugins/auth-pam/auth-pam.c +++ b/src/plugins/auth-pam/auth-pam.c @@ -642,6 +642,9 @@ my_conv (int n, const struct pam_message **msg_array, if (ret == PAM_SUCCESS) *response_array = aresp; + else + free(aresp); + return ret; } From 470eb8b6b6a9970a68cb17a185359adffbaeabf5 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Wed, 21 Oct 2015 00:39:04 +0200 Subject: [PATCH 124/643] openssl: remove usage of OPENSSL_malloc() from show_available_curves There is no need to use OPENSSL_malloc(), so use our own functions that automatically check for NULL and remove the now redundant NULL check. Signed-off-by: Steffan Karger Acked-by: Lev Stipakov Message-Id: <1445380744-21086-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/10339 Signed-off-by: Gert Doering --- src/openvpn/ssl_openssl.c | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c index c08d4fe41e6..c5543fe1c1a 100644 --- a/src/openvpn/ssl_openssl.c +++ b/src/openvpn/ssl_openssl.c @@ -1447,31 +1447,24 @@ show_available_curves() size_t n = 0; crv_len = EC_get_builtin_curves(NULL, 0); - - curves = OPENSSL_malloc((int)(sizeof(EC_builtin_curve) * crv_len)); - - if (curves == NULL) - crypto_msg (M_FATAL, "Cannot create EC_builtin_curve object"); - else + ALLOC_ARRAY(curves, EC_builtin_curve, crv_len); + if (EC_get_builtin_curves(curves, crv_len)) { - if (EC_get_builtin_curves(curves, crv_len)) + printf ("Available Elliptic curves:\n"); + for (n = 0; n < crv_len; n++) { - printf ("Available Elliptic curves:\n"); - for (n = 0; n < crv_len; n++) - { - const char *sname; - sname = OBJ_nid2sn(curves[n].nid); - if (sname == NULL) sname = ""; + const char *sname; + sname = OBJ_nid2sn(curves[n].nid); + if (sname == NULL) sname = ""; - printf("%s\n", sname); - } + printf("%s\n", sname); } - else - { - crypto_msg (M_FATAL, "Cannot get list of builtin curves"); - } - OPENSSL_free(curves); } + else + { + crypto_msg (M_FATAL, "Cannot get list of builtin curves"); + } + free(curves); #else msg (M_WARN, "Your OpenSSL library was built without elliptic curve support. " "No curves available."); From 41e4b67a229e774ebc57a882c386e10d80e10e7e Mon Sep 17 00:00:00 2001 From: Lev Stipakov Date: Wed, 21 Oct 2015 10:13:26 +0300 Subject: [PATCH 125/643] Replace variable length array with malloc Commit https://github.com/OpenVPN/openvpn/commit/685e486e8b8f70c25f09590c24762ff73 4f94a51 introduced a variable length array. Although C99 supports that, MSVS 2013 still requires size of array to be compiler time constant. As a fix, use malloc/free. v2: Replace OPENSSL_malloc with gc_malloc Signed-off-by: Lev Stipakov Acked-by: Gert Doering Message-Id: <1445411606-13369-1-git-send-email-lstipakov@gmail.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/10344 Signed-off-by: Gert Doering --- src/openvpn/ssl_openssl.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c index c5543fe1c1a..f05f95ff504 100644 --- a/src/openvpn/ssl_openssl.c +++ b/src/openvpn/ssl_openssl.c @@ -141,12 +141,12 @@ key_state_export_keying_material(struct key_state_ssl *ssl, { #if (OPENSSL_VERSION_NUMBER >= 0x10001000) unsigned int size = session->opt->ekm_size; - unsigned char ekm[size]; + struct gc_arena gc = gc_new(); + unsigned char* ekm = (unsigned char*) gc_malloc(size, true, &gc); if (SSL_export_keying_material(ssl->ssl, ekm, sizeof(ekm), session->opt->ekm_label, session->opt->ekm_label_size, NULL, 0, 0)) { - struct gc_arena gc = gc_new(); unsigned int len = (size * 2) + 2; const char *key = format_hex_ex (ekm, size, len, 0, NULL, &gc); @@ -154,14 +154,13 @@ key_state_export_keying_material(struct key_state_ssl *ssl, dmsg(D_TLS_DEBUG_MED, "%s: exported keying material: %s", __func__, key); - - gc_free(&gc); } else { msg (M_WARN, "WARNING: Export keying material failed!"); setenv_del (session->opt->es, "exported_keying_material"); } + gc_free(&gc); #endif } } From 444a93eab38d117d4f802e95a318d71ea886bcc6 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Fri, 16 Oct 2015 00:43:14 +0200 Subject: [PATCH 126/643] polarssl: fix --client-cert-not-required PolarSSL 1.3 determines whether to use a client key/cert based on the private key and/or certificate structs being allocated or not. We previously would always allocate the structs in tls_ctx_{client,server}_new(), which made polarssl clients without a client key/cert (can also be mgmt-external-key or pkcs11) fail to connect. Note that this bug is not present in OpenVPN 2.3, because PolarSSL 1.2 does not contain the 'pk' abtraction layer and therefore behaves slightly different. Signed-off-by: Steffan Karger Acked-by: Arne Schwabe Message-Id: <1444948995-18720-2-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/10287 Signed-off-by: Gert Doering --- src/openvpn/ssl_polarssl.c | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/src/openvpn/ssl_polarssl.c b/src/openvpn/ssl_polarssl.c index cd77aa57692..27cd7355d9a 100644 --- a/src/openvpn/ssl_polarssl.c +++ b/src/openvpn/ssl_polarssl.c @@ -77,11 +77,8 @@ tls_ctx_server_new(struct tls_root_ctx *ctx) CLEAR(*ctx); ALLOC_OBJ_CLEAR(ctx->dhm_ctx, dhm_context); - ALLOC_OBJ_CLEAR(ctx->priv_key, pk_context); ALLOC_OBJ_CLEAR(ctx->ca_chain, x509_crt); - ALLOC_OBJ_CLEAR(ctx->crt_chain, x509_crt); - ctx->endpoint = SSL_IS_SERVER; ctx->initialised = true; @@ -94,10 +91,7 @@ tls_ctx_client_new(struct tls_root_ctx *ctx) CLEAR(*ctx); ALLOC_OBJ_CLEAR(ctx->dhm_ctx, dhm_context); - ALLOC_OBJ_CLEAR(ctx->priv_key, pk_context); - ALLOC_OBJ_CLEAR(ctx->ca_chain, x509_crt); - ALLOC_OBJ_CLEAR(ctx->crt_chain, x509_crt); ctx->endpoint = SSL_IS_CLIENT; ctx->initialised = true; @@ -109,16 +103,20 @@ tls_ctx_free(struct tls_root_ctx *ctx) if (ctx) { pk_free(ctx->priv_key); - free(ctx->priv_key); + if (ctx->priv_key) + free(ctx->priv_key); x509_crt_free(ctx->ca_chain); - free(ctx->ca_chain); + if (ctx->ca_chain) + free(ctx->ca_chain); x509_crt_free(ctx->crt_chain); - free(ctx->crt_chain); + if (ctx->crt_chain) + free(ctx->crt_chain); dhm_free(ctx->dhm_ctx); - free(ctx->dhm_ctx); + if (ctx->dhm_ctx) + free(ctx->dhm_ctx); #if defined(ENABLE_PKCS11) if (ctx->priv_key_pkcs11 != NULL) { @@ -272,6 +270,11 @@ tls_ctx_load_cert_file (struct tls_root_ctx *ctx, const char *cert_file, { ASSERT(NULL != ctx); + if (!ctx->crt_chain) + { + ALLOC_OBJ_CLEAR(ctx->crt_chain, x509_crt); + } + if (!strcmp (cert_file, INLINE_FILE_TAG) && cert_inline) { if (!polar_ok(x509_crt_parse(ctx->crt_chain, @@ -295,6 +298,11 @@ tls_ctx_load_priv_file (struct tls_root_ctx *ctx, const char *priv_key_file, int status; ASSERT(NULL != ctx); + if (!ctx->priv_key) + { + ALLOC_OBJ_CLEAR(ctx->priv_key, pk_context); + } + if (!strcmp (priv_key_file, INLINE_FILE_TAG) && priv_key_inline) { status = pk_parse_key(ctx->priv_key, @@ -527,6 +535,11 @@ tls_ctx_load_extra_certs (struct tls_root_ctx *ctx, const char *extra_certs_file { ASSERT(NULL != ctx); + if (!ctx->crt_chain) + { + ALLOC_OBJ_CLEAR (ctx->crt_chain, x509_crt); + } + if (!strcmp (extra_certs_file, INLINE_FILE_TAG) && extra_certs_inline) { if (!polar_ok(x509_crt_parse(ctx->crt_chain, From ea66a2b5cdb21422139c421b4d3733e1c1c3937e Mon Sep 17 00:00:00 2001 From: Selva Nair Date: Wed, 4 Nov 2015 13:59:38 -0500 Subject: [PATCH 127/643] Fix termination when windows suspends/sleeps When TUN/TAP I/O operation is aborted, restart with a SIGHUP instead of terminate. The abort error from TAP is often triggered by system suspend which is fully recoverable on resume. Catastrophic events will get caught later during the restart. This solves the abnormal termination during suspend/resume. Signed-off-by: Selva Nair Acked-by: Gert Doering Message-Id: <1446663578-14471-1-git-send-email-selva.nair@gmail.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/10438 Signed-off-by: Gert Doering --- src/openvpn/forward.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c index 62eb6fc22eb..cef063d9c30 100644 --- a/src/openvpn/forward.c +++ b/src/openvpn/forward.c @@ -958,8 +958,9 @@ read_incoming_tun (struct context *c) /* Was TUN/TAP I/O operation aborted? */ if (tuntap_abort(c->c2.buf.len)) { - register_signal(c, SIGTERM, "tun-abort"); - msg(M_FATAL, "TUN/TAP I/O operation aborted, exiting"); + register_signal(c, SIGHUP, "tun-abort"); + c->persist.restart_sleep_seconds = 10; + msg(M_INFO, "TUN/TAP I/O operation aborted, restarting"); perf_pop(); return; } From b8cdb213d4fa5a56074115faceb2e0da373bab8f Mon Sep 17 00:00:00 2001 From: Jan Just Keijser Date: Fri, 9 Oct 2015 11:39:19 +0200 Subject: [PATCH 128/643] Author: Jan Just Keijser Add extended client certificate verification support. Replace --client-cert-not-required with a more flexible option, that allows for no, optional or mandatory client certificate verification. Signed-off-by: Jan Just Keijser Acked-by: Steffan Karger Message-Id: <1444383559-15788-1-git-send-email-janjust@nikhef.nl> URL: http://article.gmane.org/gmane.network.openvpn.devel/10213 Signed-off-by: Gert Doering --- doc/openvpn.8 | 49 +++++++++++++++++++++++++++++++++++++-- src/openvpn/options.c | 28 ++++++++++++++++++++-- src/openvpn/ssl_common.h | 5 ++-- src/openvpn/ssl_openssl.c | 15 ++++++++---- 4 files changed, 86 insertions(+), 11 deletions(-) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index b6d5aedce00..2978b7fd502 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -3588,18 +3588,63 @@ to empty strings (""). The authentication module/script MUST have logic to detect this condition and respond accordingly. .\"********************************************************* .TP -.B \-\-client\-cert\-not\-required +.B \-\-client\-cert\-not\-required (DEPRECATED) Don't require client certificate, client will authenticate using username/password only. Be aware that using this directive is less secure than requiring certificates from all clients. + +.B Please note: +This option is now deprecated and will be removed in OpenVPN v2.5. +It is replaced by +.B \-\-verify\-client\-cert +which allows for more flexibility. The option +.B \-\-verify\-client\-cert none +is functionally equivalent to +.B \-\-client\-cert\-not\-required +. + +.\"********************************************************* +.TP +.B \-\-verify\-client\-cert none|optional|require +Specify whether the client is required to supply a valid certificate. + +Possible options are + +.B none +: a client certificate is not required. the client need to authenticate +using username/password only. Be aware that using this directive +is less secure than requiring certificates from all clients. + If you use this directive, the entire responsibility of authentication will rest on your .B \-\-auth\-user\-pass\-verify script, so keep in mind that bugs in your script could potentially compromise the security of your VPN. -If you don't use this directive, but you also specify an +.B \-\-verify\-client\-cert none +is functionally equivalent to +.B \-\-client\-cert\-not\-required. + +.B optional +: a client may present a certificate but it is not required to do so. +When using this directive, you should also use a +.B \-\-auth\-user\-pass\-verify +script to ensure that clients are authenticated using a +certificate, a username and password, or possibly even both. + +Again, the entire responsibility of authentication will rest on your +.B \-\-auth\-user\-pass\-verify +script, so keep in mind that bugs in your script +could potentially compromise the security of your VPN. + +.B require +: this is the default option. A client is required to present a +certificate, otherwise VPN access is refused. + +If you don't use this directive (or use +.B \-\-verify\-client\-cert require +) but you also specify an .B \-\-auth\-user\-pass\-verify script, then OpenVPN will perform double authentication. The client certificate verification AND the diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 2f8915daa08..8de4c3cc2ed 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -432,6 +432,9 @@ static const char usage_message[] = " Only valid in a client-specific config file.\n" "--client-cert-not-required : Don't require client certificate, client\n" " will authenticate using username/password.\n" + "--verify-client-cert [none|optional|require] : perform no, optional or\n" + " mandatory client certificate verification.\n" + " Default is to require the client to supply a certificate.\n" "--username-as-common-name : For auth-user-pass authentication, use\n" " the authenticated username as the common name,\n" " rather than the common name from the client cert.\n" @@ -2081,8 +2084,8 @@ options_postprocess_verify_ce (const struct options *options, const struct conne msg (M_USAGE, "--duplicate-cn requires --mode server"); if (options->cf_max || options->cf_per) msg (M_USAGE, "--connect-freq requires --mode server"); - if (options->ssl_flags & SSLF_CLIENT_CERT_NOT_REQUIRED) - msg (M_USAGE, "--client-cert-not-required requires --mode server"); + if (options->ssl_flags & SSLF_CLIENT_CERT_NOT_REQUIRED || options->ssl_flags & SSLF_CLIENT_CERT_OPTIONAL) + msg (M_USAGE, "--client-cert-not-required and --verify-client-cert require --mode server"); if (options->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) msg (M_USAGE, "--username-as-common-name requires --mode server"); if (options->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL) @@ -5664,6 +5667,27 @@ add_option (struct options *options, { VERIFY_PERMISSION (OPT_P_GENERAL); options->ssl_flags |= SSLF_CLIENT_CERT_NOT_REQUIRED; + msg (M_WARN, "DEPRECATED OPTION: --client-cert-not-required, use --verify-client-cert instead"); + } + else if (streq (p[0], "verify-client-cert") && !p[2]) + { + VERIFY_PERMISSION (OPT_P_GENERAL); + + /* Reset any existing flags */ + options->ssl_flags &= ~SSLF_CLIENT_CERT_OPTIONAL; + options->ssl_flags &= ~SSLF_CLIENT_CERT_NOT_REQUIRED; + if (p[1]) + { + if (streq (p[1], "none")) + options->ssl_flags |= SSLF_CLIENT_CERT_NOT_REQUIRED; + else if (streq (p[1], "optional")) + options->ssl_flags |= SSLF_CLIENT_CERT_OPTIONAL; + else if (!streq (p[1], "require")) + { + msg (msglevel, "parameter to --verify-client-cert must be 'none', 'optional' or 'require'"); + goto err; + } + } } else if (streq (p[0], "username-as-common-name") && !p[1]) { diff --git a/src/openvpn/ssl_common.h b/src/openvpn/ssl_common.h index 86e4ac8adea..e2b0ebf0f74 100644 --- a/src/openvpn/ssl_common.h +++ b/src/openvpn/ssl_common.h @@ -293,8 +293,9 @@ struct tls_options /* configuration file SSL-related boolean and low-permutation options */ # define SSLF_CLIENT_CERT_NOT_REQUIRED (1<<0) -# define SSLF_USERNAME_AS_COMMON_NAME (1<<1) -# define SSLF_AUTH_USER_PASS_OPTIONAL (1<<2) +# define SSLF_CLIENT_CERT_OPTIONAL (1<<1) +# define SSLF_USERNAME_AS_COMMON_NAME (1<<2) +# define SSLF_AUTH_USER_PASS_OPTIONAL (1<<3) # define SSLF_OPT_VERIFY (1<<4) # define SSLF_CRL_VERIFY_DIR (1<<5) # define SSLF_TLS_VERSION_MIN_SHIFT 6 diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c index f05f95ff504..0bf15b3e1e8 100644 --- a/src/openvpn/ssl_openssl.c +++ b/src/openvpn/ssl_openssl.c @@ -213,6 +213,9 @@ tls_ctx_set_options (struct tls_root_ctx *ctx, unsigned int ssl_flags) { ASSERT(NULL != ctx); + /* default certificate verification flags */ + int flags = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT; + /* process SSL options including minimum TLS version we will accept from peer */ { long sslopt = SSL_OP_SINGLE_DH_USE | SSL_OP_NO_TICKET | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3; @@ -253,13 +256,15 @@ tls_ctx_set_options (struct tls_root_ctx *ctx, unsigned int ssl_flags) if (ssl_flags & SSLF_CLIENT_CERT_NOT_REQUIRED) { msg (M_WARN, "WARNING: POTENTIALLY DANGEROUS OPTION " - "--client-cert-not-required may accept clients which do not present " - "a certificate"); + "--client-cert-not-required and --verify-client-cert none " + "may accept clients which do not present a certificate"); + + flags = 0; } - else + else if (ssl_flags & SSLF_CLIENT_CERT_OPTIONAL) + flags = SSL_VERIFY_PEER; #endif - SSL_CTX_set_verify (ctx->ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, - verify_callback); + SSL_CTX_set_verify (ctx->ctx, flags, verify_callback); SSL_CTX_set_info_callback (ctx->ctx, info_callback); } From f107c62051ebbf4a2b661fcba8703fe26485c7af Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Fri, 16 Oct 2015 00:43:15 +0200 Subject: [PATCH 129/643] polarssl: add --verify-client-cert optional support This adds support for the --verify-client-cert optional option in PolarSSL builds, as was earlier added for OpenSSL builds by Jan-Just Keijser. This patch also adds an additional sanity check that this option may only be used in combination with some other authentication method, and changes the warning message about this option to be displayed only once on startup, instead of for each connecting client. Signed-off-by: Steffan Karger Acked-by: Jan Just Keijser Message-Id: <1444948995-18720-3-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/10288 Signed-off-by: Gert Doering --- src/openvpn/options.c | 13 ++++++++++--- src/openvpn/ssl_openssl.c | 8 +++----- src/openvpn/ssl_polarssl.c | 10 ++++------ 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 8de4c3cc2ed..901d7102012 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -2049,8 +2049,8 @@ options_postprocess_verify_ce (const struct options *options, const struct conne || PLUGIN_OPTION_LIST (options) || MAN_CLIENT_AUTH_ENABLED (options)); const char *postfix = "must be used with --management-client-auth, an --auth-user-pass-verify script, or plugin"; - if ((options->ssl_flags & SSLF_CLIENT_CERT_NOT_REQUIRED) && !ccnr) - msg (M_USAGE, "--client-cert-not-required %s", postfix); + if ((options->ssl_flags & (SSLF_CLIENT_CERT_NOT_REQUIRED|SSLF_CLIENT_CERT_OPTIONAL)) && !ccnr) + msg (M_USAGE, "--verify-client-cert none|optional %s", postfix); if ((options->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) && !ccnr) msg (M_USAGE, "--username-as-common-name %s", postfix); if ((options->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL) && !ccnr) @@ -2084,7 +2084,7 @@ options_postprocess_verify_ce (const struct options *options, const struct conne msg (M_USAGE, "--duplicate-cn requires --mode server"); if (options->cf_max || options->cf_per) msg (M_USAGE, "--connect-freq requires --mode server"); - if (options->ssl_flags & SSLF_CLIENT_CERT_NOT_REQUIRED || options->ssl_flags & SSLF_CLIENT_CERT_OPTIONAL) + if (options->ssl_flags & (SSLF_CLIENT_CERT_NOT_REQUIRED|SSLF_CLIENT_CERT_OPTIONAL)) msg (M_USAGE, "--client-cert-not-required and --verify-client-cert require --mode server"); if (options->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) msg (M_USAGE, "--username-as-common-name requires --mode server"); @@ -2132,6 +2132,13 @@ options_postprocess_verify_ce (const struct options *options, const struct conne (options->shared_secret_file != NULL) > 1) msg (M_USAGE, "specify only one of --tls-server, --tls-client, or --secret"); + if (options->ssl_flags & (SSLF_CLIENT_CERT_NOT_REQUIRED|SSLF_CLIENT_CERT_OPTIONAL)) + { + msg (M_WARN, "WARNING: POTENTIALLY DANGEROUS OPTION " + "--verify-client-cert none|optional (or --client-cert-not-required) " + "may accept clients which do not present a certificate"); + } + if (options->tls_server || options->tls_client) { #ifdef ENABLE_PKCS11 diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c index 0bf15b3e1e8..4430fec2d35 100644 --- a/src/openvpn/ssl_openssl.c +++ b/src/openvpn/ssl_openssl.c @@ -255,14 +255,12 @@ tls_ctx_set_options (struct tls_root_ctx *ctx, unsigned int ssl_flags) #if P2MP_SERVER if (ssl_flags & SSLF_CLIENT_CERT_NOT_REQUIRED) { - msg (M_WARN, "WARNING: POTENTIALLY DANGEROUS OPTION " - "--client-cert-not-required and --verify-client-cert none " - "may accept clients which do not present a certificate"); - flags = 0; } else if (ssl_flags & SSLF_CLIENT_CERT_OPTIONAL) - flags = SSL_VERIFY_PEER; + { + flags = SSL_VERIFY_PEER; + } #endif SSL_CTX_set_verify (ctx->ctx, flags, verify_callback); diff --git a/src/openvpn/ssl_polarssl.c b/src/openvpn/ssl_polarssl.c index 27cd7355d9a..cf38e69437b 100644 --- a/src/openvpn/ssl_polarssl.c +++ b/src/openvpn/ssl_polarssl.c @@ -776,18 +776,16 @@ void key_state_ssl_init(struct key_state_ssl *ks_ssl, /* Initialise SSL verification */ #if P2MP_SERVER - if (session->opt->ssl_flags & SSLF_CLIENT_CERT_NOT_REQUIRED) + if (session->opt->ssl_flags & SSLF_CLIENT_CERT_OPTIONAL) { - msg (M_WARN, "WARNING: POTENTIALLY DANGEROUS OPTION " - "--client-cert-not-required may accept clients which do not present " - "a certificate"); + ssl_set_authmode(ks_ssl->ctx, SSL_VERIFY_OPTIONAL); } - else + else if (!(session->opt->ssl_flags & SSLF_CLIENT_CERT_NOT_REQUIRED)) #endif { ssl_set_authmode (ks_ssl->ctx, SSL_VERIFY_REQUIRED); - ssl_set_verify (ks_ssl->ctx, verify_callback, session); } + ssl_set_verify (ks_ssl->ctx, verify_callback, session); /* TODO: PolarSSL does not currently support sending the CA chain to the client */ ssl_set_ca_chain (ks_ssl->ctx, ssl_ctx->ca_chain, NULL, NULL ); From 3671bd185a914dc1d91c8a967e1c3a14dedacd32 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Fri, 6 Nov 2015 08:42:39 +0100 Subject: [PATCH 130/643] Fix (potential) memory leak in init_route_list() init_route() can allocate memory in netlist, but fail in many more ways than just fail to allocate. Thus, always check and clean up netlist if needed, instead of just when init_route() succeeds. This fix is for master only. The release/2.3 branch cleans up netlist immediately, and needs a different patch for a similar problem. Found using coverity. v2: initialize netlist to NULL Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1446795759-3288-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/10443 Signed-off-by: Gert Doering --- src/openvpn/route.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/openvpn/route.c b/src/openvpn/route.c index 096e3bc3d68..58b16c0f84b 100644 --- a/src/openvpn/route.c +++ b/src/openvpn/route.c @@ -634,7 +634,7 @@ init_route_list (struct route_list *rl, struct route_option *ro; for (ro = opt->routes; ro; ro = ro->next) { - struct addrinfo* netlist; + struct addrinfo* netlist = NULL; struct route_ipv4 r; if (!init_route (&r, &netlist, ro, rl)) @@ -642,7 +642,6 @@ init_route_list (struct route_list *rl, else { struct addrinfo* curele; - gc_addspecial(netlist, &gc_freeaddrinfo_callback, &gc); for (curele = netlist; curele; curele = curele->ai_next) { struct route_ipv4 *new; @@ -653,6 +652,8 @@ init_route_list (struct route_list *rl, rl->routes = new; } } + if (netlist) + gc_addspecial(netlist, &gc_freeaddrinfo_callback, &gc); } } From 9aebc37c45e440bda5f71b717146b5dc330d5277 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Thu, 5 Nov 2015 22:03:01 +0100 Subject: [PATCH 131/643] Add macro to ensure we exit on fatal errors Also prevents false positives in static analysis tools. (Note that the current x_msg() code does properly exit, this is just a way to make it trivial to see we will not return from msg() on fatal errors, even for static analysis tools.) Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1446757381-27863-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/10440 Signed-off-by: Gert Doering --- src/openvpn/error.h | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/openvpn/error.h b/src/openvpn/error.h index 4d338439d74..e6c55f02b41 100644 --- a/src/openvpn/error.h +++ b/src/openvpn/error.h @@ -139,19 +139,22 @@ bool dont_mute (unsigned int flags); /* check muting filter */ #define MSG_TEST(flags) (unlikely((((unsigned int)flags) & M_DEBUG_LEVEL) <= x_debug_level) && dont_mute (flags)) +/* Macro to ensure (and teach static analysis tools) we exit on fatal errors */ +#define EXIT_FATAL(flags) do { if ((flags) & M_FATAL) _exit(1); } while (false) + #if defined(HAVE_CPP_VARARG_MACRO_ISO) && !defined(__LCLINT__) # define HAVE_VARARG_MACROS -# define msg(flags, ...) do { if (MSG_TEST(flags)) x_msg((flags), __VA_ARGS__); } while (false) +# define msg(flags, ...) do { if (MSG_TEST(flags)) x_msg((flags), __VA_ARGS__); EXIT_FATAL(flags); } while (false) # ifdef ENABLE_DEBUG -# define dmsg(flags, ...) do { if (MSG_TEST(flags)) x_msg((flags), __VA_ARGS__); } while (false) +# define dmsg(flags, ...) do { if (MSG_TEST(flags)) x_msg((flags), __VA_ARGS__); EXIT_FATAL(flags); } while (false) # else # define dmsg(flags, ...) # endif #elif defined(HAVE_CPP_VARARG_MACRO_GCC) && !defined(__LCLINT__) # define HAVE_VARARG_MACROS -# define msg(flags, args...) do { if (MSG_TEST(flags)) x_msg((flags), args); } while (false) +# define msg(flags, args...) do { if (MSG_TEST(flags)) x_msg((flags), args); EXIT_FATAL(flags); } while (false) # ifdef ENABLE_DEBUG -# define dmsg(flags, args...) do { if (MSG_TEST(flags)) x_msg((flags), args); } while (false) +# define dmsg(flags, args...) do { if (MSG_TEST(flags)) x_msg((flags), args); EXIT_FATAL(flags); } while (false) # else # define dmsg(flags, args...) # endif From efeaf947c9c5c88d77d16ac4917c1350c447c8dc Mon Sep 17 00:00:00 2001 From: Lev Stipakov Date: Wed, 11 Nov 2015 13:48:07 +0200 Subject: [PATCH 132/643] Use adapter index instead of name for windows IPv6 interface config Some windows machines get weird issues with netsh when using adapter name on "netsh.exe interface ipv6 set address" command. Changed logic to get adapter index and use it instead of adapter name for netsh set address command. v2: * Remove netsh call which uses adapter name. After thoughtful testing turns out that "adapter name" code branch is never used. v3: * Use interface= syntax. * Add forward declaration of get_adapter_index_flexible to get rid of warning. * NOTE: temp variable is needed because argv_printf() does not handle combined strings like "interface=%lu" today Signed-off-by: Olli Mannisto Signed-off-by: Lev Stipakov Acked-by: Gert Doering Message-Id: <1447242487-30243-1-git-send-email-lstipakov@gmail.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/10484 Signed-off-by: Gert Doering --- src/openvpn/tun.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index 24a61eccfd6..070fd188991 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -67,6 +67,8 @@ static void netsh_command (const struct argv *a, int n); static const char *netsh_get_id (const char *dev_node, struct gc_arena *gc); +static DWORD get_adapter_index_flexible (const char *name); + #endif #ifdef TARGET_SOLARIS @@ -1301,18 +1303,20 @@ do_ifconfig (struct tuntap *tt, if ( do_ipv6 ) { char * saved_actual; + char iface[64]; if (!strcmp (actual, "NULL")) msg (M_FATAL, "Error: When using --tun-ipv6, if you have more than one TAP-Windows adapter, you must also specify --dev-node"); - /* example: netsh interface ipv6 set address MyTap 2001:608:8003::d store=active */ + openvpn_snprintf(iface, sizeof(iface), "interface=%lu", get_adapter_index_flexible(actual)); + + /* example: netsh interface ipv6 set address interface=42 2001:608:8003::d store=active */ argv_printf (&argv, - "%s%sc interface ipv6 set address %s %s store=active", + "%s%sc interface ipv6 set address %s %s store=active", get_win_sys_path(), NETSH_PATH_SUFFIX, - actual, - ifconfig_ipv6_local ); - + iface, + ifconfig_ipv6_local); netsh_command (&argv, 4); /* explicit route needed */ From 7546cba4761b24f2195034dcd3407aecd43fd3be Mon Sep 17 00:00:00 2001 From: Selva Nair Date: Thu, 12 Nov 2015 21:41:27 -0500 Subject: [PATCH 133/643] Do not hard-code windows systemroot in env_block FWIW, fixes trac #500 Signed-off-by: Selva Nair Acked-by: Gert Doering Message-Id: <1447382487-26031-1-git-send-email-selva.nair@gmail.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/10492 Signed-off-by: Gert Doering --- src/openvpn/win32.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/openvpn/win32.c b/src/openvpn/win32.c index 7c89a5a9ce3..d06b41f1641 100644 --- a/src/openvpn/win32.c +++ b/src/openvpn/win32.c @@ -763,7 +763,12 @@ win_safe_filename (const char *fn) static char * env_block (const struct env_set *es) { - char * force_path = "PATH=C:\\Windows\\System32;C:\\WINDOWS;C:\\WINDOWS\\System32\\Wbem"; + char force_path[256]; + char *sysroot = get_win_sys_path(); + + if (!openvpn_snprintf(force_path, sizeof(force_path), "PATH=%s\\System32;%s;%s\\System32\\Wbem", + sysroot, sysroot, sysroot)) + msg(M_WARN, "env_block: default path truncated to %s", force_path); if (es) { From 6e9373c84639382c16d9eb8f1f78f60079bb89df Mon Sep 17 00:00:00 2001 From: Michal Ludvig Date: Sun, 11 Oct 2015 10:44:20 +0200 Subject: [PATCH 134/643] Support for username-only auth file. Make OpenVPN read the username from the auth file parameter of --auth-user-pass and prompt for a password if it's not in the file. Rationale: Prior to this change OpenVPN either required both username and password present in the auth file or prompted for both on the console. Unlike passwords usernames usually don't change and can therefore be "hardcoded" in the config. Signed-off-by: Michal Ludvig Reviewed and updated to current master. Signed-off-by: Adriaan de Jong Acked-by: Gert Doering Message-Id: <1444553060-15946-1-git-send-email-dejong@fox-it.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/10255 --- doc/openvpn.8 | 3 +- src/openvpn/misc.c | 110 ++++++++++++++++++++++-------------------- src/openvpn/options.c | 6 ++- 3 files changed, 64 insertions(+), 55 deletions(-) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 2978b7fd502..37b0f2bf7f6 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -3799,7 +3799,8 @@ over the client's routing table. .B \-\-auth\-user\-pass [up] Authenticate with server using username/password. .B up -is a file containing username/password on 2 lines (Note: OpenVPN +is a file containing username/password on 2 lines. If the +password line is missing, OpenVPN will prompt for one. (Note: OpenVPN will only read passwords from a file if it has been built with the \-\-enable\-password\-save configure option, or on Windows by defining ENABLE_PASSWORD_SAVE in win/settings.in). diff --git a/src/openvpn/misc.c b/src/openvpn/misc.c index fd1930ae42a..b6c88547b57 100644 --- a/src/openvpn/misc.c +++ b/src/openvpn/misc.c @@ -1003,7 +1003,9 @@ get_user_pass_cr (struct user_pass *up, if (!up->defined) { - const bool from_stdin = (!auth_file || !strcmp (auth_file, "stdin")); + bool from_authfile = (auth_file && !streq (auth_file, "stdin")); + bool username_from_stdin = !from_authfile; + bool password_from_stdin = !from_authfile; if (flags & GET_USER_PASS_PREVIOUS_CREDS_FAILED) msg (M_WARN, "Note: previous '%s' credentials failed", prefix); @@ -1013,7 +1015,7 @@ get_user_pass_cr (struct user_pass *up, * Get username/password from management interface? */ if (management - && ((auth_file && streq (auth_file, "management")) || (from_stdin && (flags & GET_USER_PASS_MANAGEMENT))) + && ((auth_file && streq (auth_file, "management")) || (!from_authfile && (flags & GET_USER_PASS_MANAGEMENT))) && management_query_user_pass_enabled (management)) { const char *sc = NULL; @@ -1050,11 +1052,61 @@ get_user_pass_cr (struct user_pass *up, if (!strlen (up->password)) strcpy (up->password, "ok"); } - + else if (from_authfile) + { + /* + * Try to get username/password from a file. + */ + FILE *fp; + char password_buf[USER_PASS_LEN] = { '\0' }; + + warn_if_group_others_accessible (auth_file); + + fp = platform_fopen (auth_file, "r"); + if (!fp) + msg (M_ERR, "Error opening '%s' auth file: %s", prefix, auth_file); + + if ((flags & GET_USER_PASS_PASSWORD_ONLY) == 0) + { + /* Read username first */ + if (fgets (up->username, USER_PASS_LEN, fp) == NULL) + msg (M_FATAL, "Error reading username from %s authfile: %s", + prefix, + auth_file); + } + chomp (up->username); + + if (fgets (password_buf, USER_PASS_LEN, fp) != NULL) + { +#ifndef ENABLE_PASSWORD_SAVE + /* + * Unless ENABLE_PASSWORD_SAVE is defined, don't allow sensitive passwords + * to be read from a file. + */ + if (flags & GET_USER_PASS_SENSITIVE) + msg (M_FATAL, "Sorry, '%s' password cannot be read from a file", prefix); +#endif + chomp (password_buf); + } + + if (flags & GET_USER_PASS_PASSWORD_ONLY && !password_buf[0]) + msg (M_FATAL, "Error reading password from %s authfile: %s", prefix, auth_file); + + if (password_buf[0]) + strncpy(up->password, password_buf, USER_PASS_LEN); + else + password_from_stdin = 1; + + fclose (fp); + + if (!(flags & GET_USER_PASS_PASSWORD_ONLY) && strlen (up->username) == 0) + msg (M_FATAL, "ERROR: username from %s authfile '%s' is empty", prefix, auth_file); + } + /* * Get username/password from standard input? */ - else if (from_stdin) + if (username_from_stdin || password_from_stdin) { #ifndef WIN32 /* did we --daemon'ize before asking for passwords? */ @@ -1092,7 +1144,7 @@ get_user_pass_cr (struct user_pass *up, buf_printf (&user_prompt, "Enter %s Username:", prefix); buf_printf (&pass_prompt, "Enter %s Password:", prefix); - if (!(flags & GET_USER_PASS_PASSWORD_ONLY)) + if (username_from_stdin && !(flags & GET_USER_PASS_PASSWORD_ONLY)) { if (!get_console_input (BSTR (&user_prompt), true, up->username, USER_PASS_LEN)) msg (M_FATAL, "ERROR: could not read %s username from stdin", prefix); @@ -1100,7 +1152,7 @@ get_user_pass_cr (struct user_pass *up, msg (M_FATAL, "ERROR: %s username is empty", prefix); } - if (!get_console_input (BSTR (&pass_prompt), false, up->password, USER_PASS_LEN)) + if (password_from_stdin && !get_console_input (BSTR (&pass_prompt), false, up->password, USER_PASS_LEN)) msg (M_FATAL, "ERROR: could not not read %s password from stdin", prefix); #ifdef ENABLE_CLIENT_CR @@ -1126,52 +1178,6 @@ get_user_pass_cr (struct user_pass *up, #endif } } - else - { - /* - * Get username/password from a file. - */ - FILE *fp; - -#ifndef ENABLE_PASSWORD_SAVE - /* - * Unless ENABLE_PASSWORD_SAVE is defined, don't allow sensitive passwords - * to be read from a file. - */ - if (flags & GET_USER_PASS_SENSITIVE) - msg (M_FATAL, "Sorry, '%s' password cannot be read from a file", prefix); -#endif - - warn_if_group_others_accessible (auth_file); - - fp = platform_fopen (auth_file, "r"); - if (!fp) - msg (M_ERR, "Error opening '%s' auth file: %s", prefix, auth_file); - - if (flags & GET_USER_PASS_PASSWORD_ONLY) - { - if (fgets (up->password, USER_PASS_LEN, fp) == NULL) - msg (M_FATAL, "Error reading password from %s authfile: %s", - prefix, - auth_file); - } - else - { - if (fgets (up->username, USER_PASS_LEN, fp) == NULL - || fgets (up->password, USER_PASS_LEN, fp) == NULL) - msg (M_FATAL, "Error reading username and password (must be on two consecutive lines) from %s authfile: %s", - prefix, - auth_file); - } - - fclose (fp); - - chomp (up->username); - chomp (up->password); - - if (!(flags & GET_USER_PASS_PASSWORD_ONLY) && strlen (up->username) == 0) - msg (M_FATAL, "ERROR: username from %s authfile '%s' is empty", prefix, auth_file); - } string_mod (up->username, CC_PRINT, CC_CRLF, 0); string_mod (up->password, CC_PRINT, CC_CRLF, 0); diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 901d7102012..808cef471b4 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -479,8 +479,10 @@ static const char usage_message[] = "Client options (when connecting to a multi-client server):\n" "--client : Helper option to easily configure client mode.\n" "--auth-user-pass [up] : Authenticate with server using username/password.\n" - " up is a file containing username/password on 2 lines,\n" - " or omit to prompt from console.\n" + " up is a file containing the username on the first line,\n" + " and a password on the second. If either the password or both\n" + " the username and the password are omitted OpenVPN will prompt\n" + " for them from console.\n" "--pull : Accept certain config file options from the peer as if they\n" " were part of the local config file. Must be specified\n" " when connecting to a '--mode server' remote host.\n" From 9571010a14533a0f8abc6b25834fe3413755f2e8 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sat, 21 Nov 2015 11:22:04 +0100 Subject: [PATCH 135/643] polarssl: also allocate PKCS#11 certificate object on demand Commit 444a93ea changed certificate allocation to be postponed until actual usage to fix --client-cert-not-required / --verify-client-cert for PolarSSL builds. However, I forgot to allocate when using pkcs11 (because that code does not use the tls_ctx_load_cert_file() function). And while we're at it, use ALLOC_OBJ_CLEAR() instead of malloc + manual check. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1448101324-20310-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/10543 Signed-off-by: Gert Doering --- src/openvpn/pkcs11_polarssl.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/openvpn/pkcs11_polarssl.c b/src/openvpn/pkcs11_polarssl.c index be4e9737eec..4018b22a559 100644 --- a/src/openvpn/pkcs11_polarssl.c +++ b/src/openvpn/pkcs11_polarssl.c @@ -50,18 +50,13 @@ pkcs11_init_tls_session(pkcs11h_certificate_t certificate, ASSERT (NULL != ssl_ctx); + ALLOC_OBJ_CLEAR (ssl_ctx->crt_chain, x509_crt); if (pkcs11_x509_cert_init(ssl_ctx->crt_chain, certificate)) { msg (M_FATAL, "PKCS#11: Cannot retrieve PolarSSL certificate object"); goto cleanup; } - ssl_ctx->priv_key_pkcs11 = malloc(sizeof(pkcs11_context)); - - if (ssl_ctx->priv_key_pkcs11 == NULL) { - msg (M_FATAL, "PKCS#11: Cannot allocate PolarSSL private key object"); - goto cleanup; - } - + ALLOC_OBJ_CLEAR (ssl_ctx->priv_key_pkcs11, pkcs11_context); if (pkcs11_priv_key_init(ssl_ctx->priv_key_pkcs11, certificate)) { msg (M_FATAL, "PKCS#11: Cannot initialize PolarSSL private key object"); goto cleanup; From e60849a708c7b70f0d7d2363489863e4c5c9c893 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Thu, 19 Nov 2015 14:47:23 +0200 Subject: [PATCH 136/643] Adjust server-ipv6 documentation ifconfig-ipv6-pool starts at 0x1000 and not 0x10000 since v2.3 c55e9562: Implement IPv6 interface config with non-/64 prefix lengths Signed-off-by: Christos Trochalakis Acked-by: Gert Doering Message-Id: <20151119124723.GA10830@luke.ws.skroutz.gr> URL: http://article.gmane.org/gmane.network.openvpn.devel/10537 Signed-off-by: Gert Doering --- src/openvpn/helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openvpn/helper.c b/src/openvpn/helper.c index 339e2aea8b8..62f88eccc36 100644 --- a/src/openvpn/helper.c +++ b/src/openvpn/helper.c @@ -167,7 +167,7 @@ helper_client_server (struct options *o) * push "tun-ipv6" * ifconfig-ipv6 2001:db8::1 2001:db8::2 * if !nopool: - * ifconfig-ipv6-pool 2001:db8::1:0/64 + * ifconfig-ipv6-pool 2001:db8::1000/64 * */ if ( o->server_ipv6_defined ) From 67a67e39895d9c2c7af08e7fb38ba341e6be8fb6 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sat, 21 Nov 2015 12:41:00 +0100 Subject: [PATCH 137/643] polarssl: don't use deprecated functions anymore A number of functions were deprecated in polarssl 1.3.11. Stop using these, and use their alternatives instead. This enables (and also almost forces) us to move the pkcs11 and external key logic from the per-connection setup (key_state_ssl_init()) to the per-instance setup (tls_ctx_use_{pkcs11,external_private_key}()). Note that tls_ctx_use_external_private_key() is now placed right below external_pkcs1_sign() and external_key_len(), instead of right above, because it now needs to be aware of those static functions. Tested with: * PEM key files * pkcs11 * management-external-key Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1448106060-19469-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/10544 Signed-off-by: Gert Doering --- src/openvpn/crypto_polarssl.c | 6 ++-- src/openvpn/pkcs11_polarssl.c | 6 ++++ src/openvpn/ssl_polarssl.c | 59 +++++++++++++------------------ src/openvpn/ssl_verify_polarssl.c | 5 ++- 4 files changed, 36 insertions(+), 40 deletions(-) diff --git a/src/openvpn/crypto_polarssl.c b/src/openvpn/crypto_polarssl.c index c038f8e2601..92fdb787acc 100644 --- a/src/openvpn/crypto_polarssl.c +++ b/src/openvpn/crypto_polarssl.c @@ -485,7 +485,7 @@ cipher_ctx_init (cipher_context_t *ctx, uint8_t *key, int key_len, void cipher_ctx_cleanup (cipher_context_t *ctx) { - ASSERT (polar_ok(cipher_free_ctx(ctx))); + cipher_free(ctx); } int cipher_ctx_iv_length (const cipher_context_t *ctx) @@ -649,7 +649,7 @@ void md_ctx_final (md_context_t *ctx, uint8_t *dst) { ASSERT(0 == md_finish(ctx, dst)); - ASSERT(0 == md_free_ctx(ctx)); + md_free(ctx); } @@ -680,7 +680,7 @@ hmac_ctx_init (md_context_t *ctx, const uint8_t *key, int key_len, const md_info void hmac_ctx_cleanup(md_context_t *ctx) { - ASSERT(0 == md_free_ctx(ctx)); + md_free(ctx); } int diff --git a/src/openvpn/pkcs11_polarssl.c b/src/openvpn/pkcs11_polarssl.c index 4018b22a559..ccb6f8caf40 100644 --- a/src/openvpn/pkcs11_polarssl.c +++ b/src/openvpn/pkcs11_polarssl.c @@ -62,6 +62,12 @@ pkcs11_init_tls_session(pkcs11h_certificate_t certificate, goto cleanup; } + ALLOC_OBJ_CLEAR (ssl_ctx->priv_key, pk_context); + if (!polar_ok(pk_init_ctx_rsa_alt(ssl_ctx->priv_key, ssl_ctx->priv_key_pkcs11, + ssl_pkcs11_decrypt, ssl_pkcs11_sign, ssl_pkcs11_key_len))) { + goto cleanup; + } + ret = 0; cleanup: diff --git a/src/openvpn/ssl_polarssl.c b/src/openvpn/ssl_polarssl.c index cf38e69437b..cfdeb52151a 100644 --- a/src/openvpn/ssl_polarssl.c +++ b/src/openvpn/ssl_polarssl.c @@ -355,24 +355,6 @@ struct external_context { size_t signature_length; }; -int -tls_ctx_use_external_private_key (struct tls_root_ctx *ctx, - const char *cert_file, const char *cert_file_inline) -{ - ASSERT(NULL != ctx); - - tls_ctx_load_cert_file(ctx, cert_file, cert_file_inline); - - if (ctx->crt_chain == NULL) - return 0; - - /* Most of the initialization happens in key_state_ssl_init() */ - ALLOC_OBJ_CLEAR (ctx->external_key, struct external_context); - ctx->external_key->signature_length = pk_get_len(&ctx->crt_chain->pk); - - return 1; -} - /** * external_pkcs1_sign implements a PolarSSL rsa_sign_func callback, that uses * the management interface to request an RSA signature for the supplied hash. @@ -505,6 +487,28 @@ static inline size_t external_key_len(void *vctx) return ctx->signature_length; } + +int +tls_ctx_use_external_private_key (struct tls_root_ctx *ctx, + const char *cert_file, const char *cert_file_inline) +{ + ASSERT(NULL != ctx); + + tls_ctx_load_cert_file(ctx, cert_file, cert_file_inline); + + if (ctx->crt_chain == NULL) + return 0; + + ALLOC_OBJ_CLEAR (ctx->external_key, struct external_context); + ctx->external_key->signature_length = pk_get_len(&ctx->crt_chain->pk); + + ALLOC_OBJ_CLEAR (ctx->priv_key, pk_context); + if (!polar_ok(pk_init_ctx_rsa_alt(ctx->priv_key, ctx->external_key, + NULL, external_pkcs1_sign, external_key_len))) + return 0; + + return 1; +} #endif void tls_ctx_load_ca (struct tls_root_ctx *ctx, const char *ca_file, @@ -757,22 +761,9 @@ void key_state_ssl_init(struct key_state_ssl *ks_ssl, /* Initialise authentication information */ if (is_server) polar_ok(ssl_set_dh_param_ctx(ks_ssl->ctx, ssl_ctx->dhm_ctx)); -#if defined(ENABLE_PKCS11) - if (ssl_ctx->priv_key_pkcs11 != NULL) - polar_ok(ssl_set_own_cert_alt(ks_ssl->ctx, ssl_ctx->crt_chain, - ssl_ctx->priv_key_pkcs11, ssl_pkcs11_decrypt, ssl_pkcs11_sign, - ssl_pkcs11_key_len)); - else -#endif -#if defined(MANAGMENT_EXTERNAL_KEY) - if (ssl_ctx->external_key != NULL) - polar_ok(ssl_set_own_cert_alt(ks_ssl->ctx, ssl_ctx->crt_chain, - ssl_ctx->external_key, NULL, external_pkcs1_sign, - external_key_len)); - else -#endif - polar_ok(ssl_set_own_cert(ks_ssl->ctx, ssl_ctx->crt_chain, - ssl_ctx->priv_key)); + + polar_ok(ssl_set_own_cert(ks_ssl->ctx, ssl_ctx->crt_chain, + ssl_ctx->priv_key)); /* Initialise SSL verification */ #if P2MP_SERVER diff --git a/src/openvpn/ssl_verify_polarssl.c b/src/openvpn/ssl_verify_polarssl.c index fa313ac1721..62818adcbdf 100644 --- a/src/openvpn/ssl_verify_polarssl.c +++ b/src/openvpn/ssl_verify_polarssl.c @@ -319,8 +319,7 @@ x509_verify_cert_eku (x509_crt *cert, const char * const expected_oid) char oid_num_str[1024]; const char *oid_str; - oid_str = x509_oid_get_description(oid); - if (oid_str != NULL) + if (0 == oid_get_extended_key_usage( oid, &oid_str )) { msg (D_HANDSHAKE, "++ Certificate has EKU (str) %s, expects %s", oid_str, expected_oid); @@ -331,7 +330,7 @@ x509_verify_cert_eku (x509_crt *cert, const char * const expected_oid) } } - if (0 < x509_oid_get_numeric_string( oid_num_str, + if (0 < oid_get_numeric_string( oid_num_str, sizeof (oid_num_str), oid)) { msg (D_HANDSHAKE, "++ Certificate has EKU (oid) %s, expects %s", From 87f1be66e88303c51520925f169dc5a8aa58a7f2 Mon Sep 17 00:00:00 2001 From: Selva Nair Date: Mon, 16 Nov 2015 21:48:09 -0500 Subject: [PATCH 138/643] Handle ctrl-C and ctrl-break events on Windows v2 changes - cleaner, hopefully easier to get a code review :) - handles both console mode and service mode -- >8 -- Handle ctrl-C or ctrl-Break sent to the console as a SIGTERM. Depending on the console mode, windows delivers ctrl-C as a keyboard input or as a signal. We handle both cases. This allows graceful termination of openvpn from programs such as nssm. Works in both console mode and service mode. Signed-off-by: Selva Nair Acked-by: Gert Doering Message-Id: <1447728489-14991-1-git-send-email-selva.nair@gmail.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/10513 Signed-off-by: Gert Doering --- src/openvpn/win32.c | 53 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/src/openvpn/win32.c b/src/openvpn/win32.c index d06b41f1641..1f9bda05624 100644 --- a/src/openvpn/win32.c +++ b/src/openvpn/win32.c @@ -324,6 +324,53 @@ net_event_win32_close (struct net_event_win32 *ne) * (2) Service mode -- map Windows event object to SIGTERM */ +static void +win_trigger_event(struct win32_signal *ws) +{ + if (ws->mode == WSO_MODE_SERVICE && HANDLE_DEFINED(ws->in.read)) + SetEvent (ws->in.read); + else /* generate a key-press event */ + { + DWORD tmp; + INPUT_RECORD ir; + HANDLE stdin_handle = GetStdHandle(STD_INPUT_HANDLE); + + CLEAR(ir); + ir.EventType = KEY_EVENT; + ir.Event.KeyEvent.bKeyDown = true; + if (!stdin_handle || !WriteConsoleInput(stdin_handle, &ir, 1, &tmp)) + msg(M_WARN|M_ERRNO, "WARN: win_trigger_event: WriteConsoleInput"); + } +} + +/* + * Callback to handle console ctrl events + */ +static bool WINAPI +win_ctrl_handler (DWORD signum) +{ + msg(D_LOW, "win_ctrl_handler: signal received (code=%lu)", (unsigned long) signum); + + if (siginfo_static.signal_received == SIGTERM) + return true; + + switch (signum) + { + case CTRL_C_EVENT: + case CTRL_BREAK_EVENT: + throw_signal(SIGTERM); + /* trigget the win32_signal to interrupt the event loop */ + win_trigger_event(&win32_signal); + return true; + break; + default: + msg(D_LOW, "win_ctrl_handler: signal (code=%lu) not handled", (unsigned long) signum); + break; + } + /* pass all other signals to the next handler */ + return false; +} + void win32_signal_clear (struct win32_signal *ws) { @@ -403,6 +450,9 @@ win32_signal_open (struct win32_signal *ws, ws->mode = WSO_MODE_SERVICE; } } + /* set the ctrl handler in both console and service modes */ + if (!SetConsoleCtrlHandler ((PHANDLER_ROUTINE) win_ctrl_handler, true)) + msg (M_WARN|M_ERRNO, "WARN: SetConsoleCtrlHandler failed"); } static bool @@ -512,6 +562,9 @@ win32_signal_get (struct win32_signal *ws) case 0x3E: /* F4 -> TERM */ ret = SIGTERM; break; + case 0x03: /* CTRL-C -> TERM */ + ret = SIGTERM; + break; } } if (ret) From 8dd9ff8ca062de34bcd16e34847d106ee9b992ff Mon Sep 17 00:00:00 2001 From: Lev Stipakov Date: Tue, 17 Nov 2015 11:33:47 +0200 Subject: [PATCH 139/643] Notify clients about server's exit/restart When server exits / restarts (gets SIGUSR1, SIGTERM, SIGHUP, SIGINT) and explicit-exit-notify is set, server sends RESTART control channel command to all clients and reschedules received signal in 2 secs. When client receives RESTART command, it either reconnects to the same server or advances to the new one, depends on parameter comes with RESTART command - behavior is controlled by explicit-exit-notify in the server config. v4: - Rebase on top of master - Remove #ifdef ENABLE_OCC around connection_entry->explicit_exit_notification since it is also used outside of OCC context - Update usage message v3: - Use control channel "RESTART" command instead of new OCC code to notify clients - Configure on the server side (by value of explicit-exit-notify) if client should reconnect to the same server or advance to the next one - Fix compilation when OCC is disabled (--enable-small) - Update man page v2: - Take into use explicit-exit-notify on the server side - OCC_SHUTTING_DOWN renamed to OCC_SERVER_EXIT - Code prettifying Signed-off-by: Lev Stipakov Acked-by: Arne Schwabe Acked-by: Gert Doering Message-Id: <1447752827-16720-1-git-send-email-lstipakov@gmail.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/10515 Signed-off-by: Gert Doering --- doc/openvpn.8 | 13 ++++++++- src/openvpn/multi.c | 66 +++++++++++++++++++++++++++++++++++++++++-- src/openvpn/multi.h | 9 ++++++ src/openvpn/options.c | 7 ++--- src/openvpn/options.h | 4 +-- src/openvpn/push.c | 6 ++++ 6 files changed, 94 insertions(+), 11 deletions(-) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 37b0f2bf7f6..9889540c04a 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -3887,7 +3887,18 @@ option will tell the server to immediately close its client instance object rather than waiting for a timeout. The .B n parameter (default=1) controls the maximum number of attempts that the client -will try to resend the exit notification message. OpenVPN will not send any exit +will try to resend the exit notification message. + +In UDP server mode, send RESTART control channel command to connected clients. The +.B n +parameter (default=1) controls client behavior. With +.B n += 1 client will attempt to reconnect +to the same server, with +.B n += 2 client will advance to the next server. + +OpenVPN will not send any exit notifications unless this option is enabled. .\"********************************************************* .SS Data Channel Encryption Options: diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index 7c3aaaca4a7..e153be73782 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -429,6 +429,8 @@ multi_init (struct multi_context *m, struct context *t, bool tcp_mode, int threa t->options.stale_routes_check_interval, t->options.stale_routes_ageing_time); event_timeout_init (&m->stale_routes_check_et, t->options.stale_routes_check_interval, 0); } + + m->deferred_shutdown_signal.signal_received = 0; } const char * @@ -2721,10 +2723,18 @@ multi_process_timeout (struct multi_context *m, const unsigned int mpp_flags) /* instance marked for wakeup? */ if (m->earliest_wakeup) { - set_prefix (m->earliest_wakeup); - ret = multi_process_post (m, m->earliest_wakeup, mpp_flags); + if (m->earliest_wakeup == (struct multi_instance*)&m->deferred_shutdown_signal) + { + schedule_remove_entry(m->schedule, (struct schedule_entry*) &m->deferred_shutdown_signal); + throw_signal(m->deferred_shutdown_signal.signal_received); + } + else + { + set_prefix (m->earliest_wakeup); + ret = multi_process_post (m, m->earliest_wakeup, mpp_flags); + clear_prefix (); + } m->earliest_wakeup = NULL; - clear_prefix (); } return ret; } @@ -2849,6 +2859,48 @@ multi_top_free (struct multi_context *m) free_context_buffers (m->top.c2.buffers); } +static bool +is_exit_restart(int sig) +{ + return (sig == SIGUSR1 || sig == SIGTERM || sig == SIGHUP || sig == SIGINT); +} + +static void +multi_push_restart_schedule_exit(struct multi_context *m, bool next_server) +{ + struct hash_iterator hi; + struct hash_element *he; + struct timeval tv; + + /* tell all clients to restart */ + hash_iterator_init (m->iter, &hi); + while ((he = hash_iterator_next (&hi))) + { + struct multi_instance *mi = (struct multi_instance *) he->value; + if (!mi->halt) + { + send_control_channel_string (&mi->context, next_server ? "RESTART,[N]" : "RESTART", D_PUSH); + multi_schedule_context_wakeup(m, mi); + } + } + hash_iterator_free (&hi); + + /* reschedule signal */ + ASSERT (!openvpn_gettimeofday (&m->deferred_shutdown_signal.wakeup, NULL)); + tv.tv_sec = 2; + tv.tv_usec = 0; + tv_add (&m->deferred_shutdown_signal.wakeup, &tv); + + m->deferred_shutdown_signal.signal_received = m->top.sig->signal_received; + + schedule_add_entry (m->schedule, + (struct schedule_entry *) &m->deferred_shutdown_signal, + &m->deferred_shutdown_signal.wakeup, + compute_wakeup_sigma (&m->deferred_shutdown_signal.wakeup)); + + m->top.sig->signal_received = 0; +} + /* * Return true if event loop should break, * false if it should continue. @@ -2864,6 +2916,14 @@ multi_process_signal (struct multi_context *m) m->top.sig->signal_received = 0; return false; } + else if (proto_is_dgram(m->top.options.ce.proto) && + is_exit_restart(m->top.sig->signal_received) && + (m->deferred_shutdown_signal.signal_received == 0) && + m->top.options.ce.explicit_exit_notification != 0) + { + multi_push_restart_schedule_exit(m, m->top.options.ce.explicit_exit_notification == 2); + return false; + } return true; } diff --git a/src/openvpn/multi.h b/src/openvpn/multi.h index 69ed85e6687..ec1e7ab0242 100644 --- a/src/openvpn/multi.h +++ b/src/openvpn/multi.h @@ -57,6 +57,13 @@ struct multi_reap }; +struct deferred_signal_schedule_entry +{ + struct schedule_entry se; + int signal_received; + struct timeval wakeup; +}; + /** * Server-mode state structure for one single VPN tunnel. * @@ -181,6 +188,8 @@ struct multi_context { /* mapping between inotify watch descriptors and multi_instances */ struct hash *inotify_watchers; #endif + + struct deferred_signal_schedule_entry deferred_shutdown_signal; }; /* diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 808cef471b4..207e9daae23 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -469,6 +469,9 @@ static const char usage_message[] = "--stale-routes-check n [t] : Remove routes with a last activity timestamp\n" " older than n seconds. Run this check every t\n" " seconds (defaults to n).\n" + "--explicit-exit-notify [n] : In UDP server mode send [RESTART] command on exit/restart to connected\n" + " clients. n = 1 - reconnect to same server,\n" + " 2 - advance to next server, default=1.\n" #if PORT_SHARE "--port-share host port [dir] : When run in TCP mode, proxy incoming HTTPS\n" " sessions to a web server at host:port. dir specifies an\n" @@ -2022,10 +2025,6 @@ options_postprocess_verify_ce (const struct options *options, const struct conne msg (M_USAGE, "--connect-freq only works with --mode server --proto udp. Try --max-clients instead."); if (!(dev == DEV_TYPE_TAP || (dev == DEV_TYPE_TUN && options->topology == TOP_SUBNET)) && options->ifconfig_pool_netmask) msg (M_USAGE, "The third parameter to --ifconfig-pool (netmask) is only valid in --dev tap mode"); -#ifdef ENABLE_OCC - if (ce->explicit_exit_notification) - msg (M_USAGE, "--explicit-exit-notify cannot be used with --mode server"); -#endif if (options->routes && (options->routes->flags & RG_ENABLE)) msg (M_USAGE, "--redirect-gateway cannot be used with --mode server (however --push \"redirect-gateway\" is fine)"); if (options->route_delay_defined) diff --git a/src/openvpn/options.h b/src/openvpn/options.h index c642aa0df62..d1333d38af5 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -118,9 +118,7 @@ struct connection_entry int mssfix; /* Upper bound on TCP MSS */ bool mssfix_default; /* true if --mssfix was supplied without a parameter */ -#ifdef ENABLE_OCC - int explicit_exit_notification; /* Explicitly tell peer when we are exiting via OCC_EXIT message */ -#endif + int explicit_exit_notification; /* Explicitly tell peer when we are exiting via OCC_EXIT or [RESTART] message */ # define CE_DISABLED (1<<0) # define CE_MAN_QUERY_PROXY (1<<1) diff --git a/src/openvpn/push.c b/src/openvpn/push.c index a4cb726d0ca..d4f3cb6d349 100644 --- a/src/openvpn/push.c +++ b/src/openvpn/push.c @@ -105,6 +105,7 @@ server_pushed_signal (struct context *c, const struct buffer *buffer, const bool m = BSTR (&buf); /* preserve cached passwords? */ + /* advance to next server? */ { bool purge = true; @@ -115,6 +116,11 @@ server_pushed_signal (struct context *c, const struct buffer *buffer, const bool { if (m[i] == 'P') purge = false; + else if (m[i] == 'N') + { + /* next server? */ + c->options.no_advance = false; + } } } if (purge) From 9d3b7cec5270b2aebf62e80ccaa564aab93fcb37 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Mon, 23 Nov 2015 11:26:24 +0100 Subject: [PATCH 140/643] polarssl: require >= 1.3.8 Since commit 67a67e39, we use API calls that were introduced in polarssl 1.3.8. Update the configure check to reflect that. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1448274384-22953-1-git-send-email-steffan.karger@fox-it.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/10563 Signed-off-by: Gert Doering --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 342458433e4..d3cacc88ad4 100644 --- a/configure.ac +++ b/configure.ac @@ -871,13 +871,13 @@ if test "${with_crypto_library}" = "polarssl" ; then #include ]], [[ -#if POLARSSL_VERSION_NUMBER < 0x01030300 || POLARSSL_VERSION_NUMBER >= 0x01040000 +#if POLARSSL_VERSION_NUMBER < 0x01030800 || POLARSSL_VERSION_NUMBER >= 0x01040000 #error invalid version #endif ]] )], [AC_MSG_RESULT([ok])], - [AC_MSG_ERROR([PolarSSL 1.3.x required and must be 1.3.3 or later])] + [AC_MSG_ERROR([PolarSSL 1.3.x required and must be 1.3.8 or later])] ) polarssl_with_pkcs11="no" From ed5d0fe5097a26206a6a7d4463622461a0987655 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Mon, 23 Nov 2015 20:47:42 +0100 Subject: [PATCH 141/643] Fix info.af == AF_UNSPEC case for server with --mtu-disc Commit 2bed089d31a12c2 introduced "AF_UNSPEC" sockets when we do not know the actual address family yet - for the "bind local" case, getaddrinfo() will tell us what to do, but that information never made it into sock->info.af - so, make it. Otherwise, trying to call --mtu-disc on an OpenVPN server will cause a M_FATAL error in set_mtu_discovery()) Signed-off-by: Gert Doering Acked-by: Christian Pellegrin Message-ID: <20151121200637.GD24952@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/10547 --- src/openvpn/socket.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c index b24d9ad5f37..8e6b4bcac69 100644 --- a/src/openvpn/socket.c +++ b/src/openvpn/socket.c @@ -1887,8 +1887,11 @@ link_socket_init_phase2 (struct link_socket *sock, /* Warn if this is because neither v4 or v6 was specified * and we should not connect a remote */ if (sock->info.af == AF_UNSPEC) - msg (M_WARN, "Could not determine IPv4/IPv6 protocol. Using %s", + { + msg (M_WARN, "Could not determine IPv4/IPv6 protocol. Using %s", addr_family_name(sock->info.lsa->bind_local->ai_family)); + sock->info.af = sock->info.lsa->bind_local->ai_family; + } create_socket (sock, sock->info.lsa->bind_local); } From b33e1355765bbf83f4c8b744c442c7d98df808fa Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Tue, 10 Nov 2015 22:17:03 +0100 Subject: [PATCH 142/643] Fix FreeBSD-specific mishandling of gc arena pointer in create_arbitrary_remote() ... and while at it, fix warning about losing "const" qualifier on return. Signed-off-by: Gert Doering Acked-by: Steffan Karger Message-Id: <1447190223-8065-1-git-send-email-gert@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/10478 --- src/openvpn/tun.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index 070fd188991..8139afc18a4 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -643,7 +643,7 @@ void delete_route_connected_v6_net(struct tuntap * tt, * is still point to point and no layer 2 resolution is done... */ -char * +const char * create_arbitrary_remote( struct tuntap *tt, struct gc_arena * gc ) { in_addr_t remote; @@ -652,7 +652,7 @@ create_arbitrary_remote( struct tuntap *tt, struct gc_arena * gc ) if ( remote == tt->local ) remote ++; - return print_in_addr_t (remote, 0, &gc); + return print_in_addr_t (remote, 0, gc); } #endif From 4f19cd1ddde3929d4a715ad59cd603eff16c66bf Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Mon, 23 Nov 2015 21:58:55 +0100 Subject: [PATCH 143/643] Fix memory leak in add_option() by simplifying get_ipv6_addr If get_ipv6_addr() would fail *after* allocating memory for ipv6_local, add_option() would fail to free that memory. The fix here is to remove the allocation from get_ipv6_addr(), and create a separate function for the strip-and-allocate, such that failures are easier to handle. v2 - remove free(options->ifconfig_ipv6_local), since that is now handled by a garbage collector. Memory leak found by coverity (in 2011!). Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1448312335-25908-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/10573 Signed-off-by: Gert Doering (cherry picked from commit 7e618994f3112ff4b29b9f08d087fb558636a6af) --- src/openvpn/options.c | 65 ++++++++++++++++++++++++------------------- src/openvpn/options.h | 3 +- src/openvpn/route.c | 2 +- 3 files changed, 39 insertions(+), 31 deletions(-) diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 207e9daae23..36290a01546 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -949,13 +949,11 @@ get_ip_addr (const char *ip_string, int msglevel, bool *error) * "/nn" is optional, default to /64 if missing * * return true if parsing succeeded, modify *network and *netbits - * return address part without "/nn" in *printable_ipv6 (if != NULL) */ bool get_ipv6_addr( const char * prefix_str, struct in6_addr *network, - unsigned int * netbits, char ** printable_ipv6, int msglevel ) + unsigned int * netbits, int msglevel) { - int rc; char * sep, * endp; int bits; struct in6_addr t_network; @@ -982,21 +980,14 @@ get_ipv6_addr( const char * prefix_str, struct in6_addr *network, if ( sep != NULL ) *sep = '\0'; - rc = inet_pton( AF_INET6, prefix_str, &t_network ); - - if ( rc == 1 && printable_ipv6 != NULL ) - { - *printable_ipv6 = string_alloc( prefix_str, NULL ); - } - - if ( sep != NULL ) *sep = '/'; - - if ( rc != 1 ) + if ( inet_pton( AF_INET6, prefix_str, &t_network ) != 1 ) { msg (msglevel, "IPv6 prefix '%s': invalid IPv6 address", prefix_str); return false; } + if ( sep != NULL ) *sep = '/'; + if ( netbits != NULL ) { *netbits = bits; @@ -1008,12 +999,35 @@ get_ipv6_addr( const char * prefix_str, struct in6_addr *network, return true; /* parsing OK, values set */ } +/** + * Returns newly allocated string containing address part without "/nn". + * + * If gc != NULL, the allocated memory is registered in the supplied gc. + */ +static char * +get_ipv6_addr_no_netbits (const char *addr, struct gc_arena *gc) +{ + const char *end = strchr (addr, '/'); + char *ret = NULL; + if (NULL == end) + { + ret = string_alloc (addr, gc); + } + else + { + size_t len = end - addr; + ret = gc_malloc (len + 1, true, gc); + memcpy (ret, addr, len); + } + return ret; +} + static bool ipv6_addr_safe_hexplusbits( const char * ipv6_prefix_spec ) { struct in6_addr t_addr; unsigned int t_bits; - return get_ipv6_addr( ipv6_prefix_spec, &t_addr, &t_bits, NULL, M_WARN ); + return get_ipv6_addr( ipv6_prefix_spec, &t_addr, &t_bits, M_WARN ); } static char * @@ -1257,7 +1271,7 @@ option_iroute_ipv6 (struct options *o, ALLOC_OBJ_GC (ir, struct iroute_ipv6, &o->gc); - if ( !get_ipv6_addr (prefix_str, &ir->network, &ir->netbits, NULL, msglevel )) + if ( !get_ipv6_addr (prefix_str, &ir->network, &ir->netbits, msglevel )) { msg (msglevel, "in --iroute-ipv6 %s: Bad IPv6 prefix specification", prefix_str); @@ -4162,7 +4176,7 @@ add_option (struct options *options, struct in6_addr remote = IN6ADDR_ANY_INIT; VERIFY_PERMISSION (OPT_P_GENERAL); if (p[1]) - get_ipv6_addr (p[1], &remote, NULL, NULL, M_WARN); + get_ipv6_addr (p[1], &remote, NULL, M_WARN); get_default_gateway(&rgi); get_default_gateway_ipv6(&rgi6, &remote); print_default_gateway(M_INFO, &rgi, &rgi6); @@ -4417,10 +4431,9 @@ add_option (struct options *options, else if (streq (p[0], "ifconfig-ipv6") && p[1] && p[2] && !p[3]) { unsigned int netbits; - char * ipv6_local; VERIFY_PERMISSION (OPT_P_UP); - if ( get_ipv6_addr( p[1], NULL, &netbits, &ipv6_local, msglevel ) && + if ( get_ipv6_addr( p[1], NULL, &netbits, msglevel ) && ipv6_addr_safe( p[2] ) ) { if ( netbits < 64 || netbits > 124 ) @@ -4429,11 +4442,7 @@ add_option (struct options *options, goto err; } - if (options->ifconfig_ipv6_local) - /* explicitly ignoring this is a const char */ - free ((char *) options->ifconfig_ipv6_local); - - options->ifconfig_ipv6_local = ipv6_local; + options->ifconfig_ipv6_local = get_ipv6_addr_no_netbits (p[1], &options->gc); options->ifconfig_ipv6_netbits = netbits; options->ifconfig_ipv6_remote = p[2]; } @@ -5497,7 +5506,7 @@ add_option (struct options *options, unsigned int netbits = 0; VERIFY_PERMISSION (OPT_P_GENERAL); - if ( ! get_ipv6_addr (p[1], &network, &netbits, NULL, lev) ) + if ( ! get_ipv6_addr (p[1], &network, &netbits, lev) ) { msg (msglevel, "error parsing --server-ipv6 parameter"); goto err; @@ -5608,7 +5617,7 @@ add_option (struct options *options, unsigned int netbits = 0; VERIFY_PERMISSION (OPT_P_GENERAL); - if ( ! get_ipv6_addr (p[1], &network, &netbits, NULL, lev ) ) + if ( ! get_ipv6_addr (p[1], &network, &netbits, lev ) ) { msg (msglevel, "error parsing --ifconfig-ipv6-pool parameters"); goto err; @@ -5879,7 +5888,7 @@ add_option (struct options *options, VERIFY_PERMISSION (OPT_P_INSTANCE); - if ( ! get_ipv6_addr( p[1], &local, &netbits, NULL, msglevel ) ) + if ( ! get_ipv6_addr( p[1], &local, &netbits, msglevel ) ) { msg (msglevel, "cannot parse --ifconfig-ipv6-push addresses"); goto err; @@ -5887,7 +5896,7 @@ add_option (struct options *options, if ( p[2] ) { - if ( !get_ipv6_addr( p[2], &remote, NULL, NULL, msglevel ) ) + if ( !get_ipv6_addr( p[2], &remote, NULL, msglevel ) ) { msg( msglevel, "cannot parse --ifconfig-ipv6-push addresses"); goto err; @@ -5897,7 +5906,7 @@ add_option (struct options *options, { if ( ! options->ifconfig_ipv6_local || ! get_ipv6_addr( options->ifconfig_ipv6_local, &remote, - NULL, NULL, msglevel ) ) + NULL, msglevel ) ) { msg( msglevel, "second argument to --ifconfig-ipv6-push missing and no global --ifconfig-ipv6 address set"); goto err; diff --git a/src/openvpn/options.h b/src/openvpn/options.h index d1333d38af5..ebc0591f51b 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -775,8 +775,7 @@ void options_string_import (struct options *options, struct env_set *es); bool get_ipv6_addr( const char * prefix_str, struct in6_addr *network, - unsigned int * netbits, char ** printable_ipv6, - int msglevel ); + unsigned int * netbits, int msglevel ); #endif diff --git a/src/openvpn/route.c b/src/openvpn/route.c index 58b16c0f84b..d06018730ff 100644 --- a/src/openvpn/route.c +++ b/src/openvpn/route.c @@ -380,7 +380,7 @@ init_route_ipv6 (struct route_ipv6 *r6, { CLEAR (*r6); - if ( !get_ipv6_addr( r6o->prefix, &r6->network, &r6->netbits, NULL, M_WARN )) + if ( !get_ipv6_addr( r6o->prefix, &r6->network, &r6->netbits, M_WARN )) goto fail; /* gateway */ From f544e388527066dcf17ea0e257b9182a7286e821 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Tue, 24 Nov 2015 15:00:35 +0100 Subject: [PATCH 144/643] remove nonsense const specifier in nonfatal() return value Return values are rvalues, and can not be changed anyway. Adding const does not make sense here at all. (What was I thinking...?) Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1448373635-21649-1-git-send-email-steffan.karger@fox-it.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/10583 Signed-off-by: Gert Doering --- src/openvpn/error.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openvpn/error.h b/src/openvpn/error.h index e6c55f02b41..1dc08640718 100644 --- a/src/openvpn/error.h +++ b/src/openvpn/error.h @@ -353,7 +353,7 @@ ignore_sys_error (const int err) } /** Convert fatal errors to nonfatal, don't touch other errors */ -static inline const unsigned int +static inline unsigned int nonfatal(const unsigned int err) { return err & M_FATAL ? (err ^ M_FATAL) | M_NONFATAL : err; } From cef57449b98c38deb35e885bd8958fe09f6a2b02 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Tue, 24 Nov 2015 14:09:10 +0100 Subject: [PATCH 145/643] remove unused gc_arena in FreeBSD close_tun() not used, and a small mem leak on every tunnel close... Signed-off-by: Gert Doering Acked-by: Steffan Karger Message-Id: <1448370550-23897-1-git-send-email-gert@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/10581 --- src/openvpn/tun.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index 8139afc18a4..c293e1ecd1b 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -2539,7 +2539,6 @@ close_tun (struct tuntap *tt) } else if (tt) /* close and destroy */ { - struct gc_arena gc = gc_new (); struct argv argv; /* setup command, close tun dev (clears tt->actual_name!), run command From 6c2d790ad8f10029e95aecb0d39377ef06ea8b2a Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Wed, 11 Nov 2015 14:01:39 +0100 Subject: [PATCH 146/643] Avoid partial authentication state when using --disabled in CCD configs If an openvpn server is configured with --client-config-dir and a client configuration file contains 'disabled', it is supposed to tell the client it is not authorized to use the service. This patch will ensure that the internal state in this scenario is a complete CAS_FAILED state, and not CAS_PARTIAL if other authorization steps passed. Trac: #521 Tested-by: Eric Crist Signed-off-by: David Sommerseth Acked-by: Gert Doering Message-Id: <1447246899-22769-1-git-send-email-openvpn@sf.lists.topphemmelig.net> URL: http://article.gmane.org/gmane.network.openvpn.devel/10486 Signed-off-by: Gert Doering --- src/openvpn/multi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index e153be73782..a2ab16ecbb7 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -1860,6 +1860,7 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi { msg (D_MULTI_ERRORS, "MULTI: client has been rejected due to 'disable' directive"); cc_succeeded = false; + cc_succeeded_count = 0; } if (cc_succeeded) From 756602e7da11362f25be04743cd09f798b6f528a Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sat, 28 Nov 2015 11:38:24 +0100 Subject: [PATCH 147/643] openssl: properly check return value of RAND_bytes() This patch is in response to an off-list report by Sebastian Krahmer of the SuSE security team. Sebastian noticed we do not check the return value of RAND_bytes() correctly. The RAND_bytes() man page first says "RAND_bytes() returns 1 on success, 0 otherwise.", but then a bit later "Both functions return -1 if they are not supported by the current RAND method.". This second case was not covered by our return value checking. Note that if RAND_bytes() would return -1, it would *always* return -1 and fail to generate random. Also note that if RAND_bytes() would return -1, it would do so too in the openssl internal ssl funtions. The openssl internal function do check the return value properly, and connection setup would fail all together. If that would be at least somewhat common, we would have received a *lot* of bug reports. In other words, the error affects static key setups only, and seems highly unlikely to occur in actual setups. Only builds using OpenSSL as the crypto backend are affected. This patch: 1. Changes the behaviour of rand_bytes() in openssl builds to match what the doxygen claims (and polarssl builds already do). 2. Adds error reporting for RAND_bytes() failures. Signed-off-by: Steffan Karger Acked-by: Arne Schwabe Acked-by: Gert Doering Message-Id: <1448707105-10753-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/10637 Signed-off-by: Gert Doering --- src/openvpn/crypto_openssl.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/openvpn/crypto_openssl.c b/src/openvpn/crypto_openssl.c index 2d81a6d8677..1d686623af8 100644 --- a/src/openvpn/crypto_openssl.c +++ b/src/openvpn/crypto_openssl.c @@ -352,7 +352,12 @@ show_available_engines () int rand_bytes(uint8_t *output, int len) { - return RAND_bytes (output, len); + if (unlikely(1 != RAND_bytes (output, len))) + { + crypto_msg(D_CRYPT_ERRORS, "RAND_bytes() failed"); + return 0; + } + return 1; } /* From 5a73356ae5d0bf94ec81a33c7dcda6a41651ca6c Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sat, 28 Nov 2015 11:38:25 +0100 Subject: [PATCH 148/643] Fix rand_bytes return value checking This patch is in response to an off-list report by Sebastian Krahmer of the SuSE security team. Sebastian noticed we do not check the return value of rand_bytes() in prng_bytes(), which we really should. Failing to check the return value occurs if no prng is used (i.e. in static key mode, or when explicitly disabled using --prng none). prng_bytes() is used for generating IVs, session IDs and filenames. The impact of failing to check the return value seems very limited: Not generating random file names or session IDs could cause collisions in (temporary) file names and/or session IDs. These in turn could cause availability issues, but would not result in a breach in confidentiality and/or integrity. Our CBC mode protocol uses a packet id (timestamp + packet counter in static key mode, or just the packet counter in TLS mode) at the start of each packet (by default, but can be disabled using --no-iv and --no-replay). Because the timestamp and packet counter are not controllable by an attacker, it is not clear how predictable or even repeating IVs could be used to mount an attack. (Note that the fact that *I* can't find or come up with an attack is not a very strong argument, this remains somewhat worrisome.) CFB and OFB modes are not affected, because they do not rely on the prng for IVS. Finally, RAND_bytes() actually failing is quite unlikely, as that would result in all sorts of other problems we should have heard about. Of course, we still really should fix this, so this patch adds return value checking of rand_bytes() inside prng_bytes(). The ASSERT() might be a bit crude, so a follow-up patch that adds a return value to prng_bytes() and proper return value checking probably makes sense. But at least this is a quick and simple fix for the issue at hand. Signed-off-by: Steffan Karger Acked-by: Arne Schwabe Acked-by: Gert Doering Message-Id: <1448707105-10753-2-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/10636 Signed-off-by: Gert Doering --- src/openvpn/crypto.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c index 1ceb411a4e5..c18d88bb22b 100644 --- a/src/openvpn/crypto.c +++ b/src/openvpn/crypto.c @@ -1320,7 +1320,7 @@ prng_bytes (uint8_t *output, int len) } } else - rand_bytes (output, len); + ASSERT (rand_bytes (output, len)); } /* an analogue to the random() function, but use prng_bytes */ From 2191c4716537b3d3e81b0e746f666dd365b65abd Mon Sep 17 00:00:00 2001 From: Heiko Hund Date: Wed, 25 Nov 2015 13:57:00 +0100 Subject: [PATCH 149/643] extend management interface command "state" Currently the state command shows only the tun/tap IPv4 address. The IPv4 address of the remote peer is also displayed. In case you connect via IPv6 it just shows the first 4 bytes of the address in IPv4 notation. This patch extends the state command, so it handles IPv6 addresses. In addition it also displays the local address and the both port numbers of the connection, e.g. 1447250958,CONNECTED,SUCCESS,10.0.0.2,fd00::1,1193,fd00::2,6492,fdff::1002 Signed-off-by: Heiko Hund Acked-by: Arne Schwabe Message-Id: <1448456220-2042-1-git-send-email-heiko.hund@sophos.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/10603 Signed-off-by: Gert Doering --- doc/management-notes.txt | 17 ++++++++++--- src/openvpn/forward.c | 6 +++-- src/openvpn/init.c | 55 +++++++++++++++++++++++++++++----------- src/openvpn/manage.c | 27 +++++++++++++++----- src/openvpn/manage.h | 10 +++++--- src/openvpn/route.c | 6 +++-- src/openvpn/sig.c | 6 +++-- src/openvpn/socket.c | 23 ++++++++++++----- src/openvpn/socket.h | 1 + src/openvpn/ssl.c | 12 ++++++--- src/openvpn/tun.c | 6 +++-- 11 files changed, 122 insertions(+), 47 deletions(-) diff --git a/doc/management-notes.txt b/doc/management-notes.txt index 0265d5579d3..f68f3db98a8 100644 --- a/doc/management-notes.txt +++ b/doc/management-notes.txt @@ -366,14 +366,23 @@ Command examples: same time enable real-time state notification of future state transitions. -The output format consists of 4 comma-separated parameters: +The output format consists of up to 9 comma-separated parameters: (a) the integer unix date/time, (b) the state name, (c) optional descriptive string (used mostly on RECONNECTING and EXITING to show the reason for the disconnect), - (d) optional TUN/TAP local IP address (shown for ASSIGN_IP - and CONNECTED), and - (e) optional address of remote server (OpenVPN 2.1 or higher). + (d) optional TUN/TAP local IPv4 address + (e) optional address of remote server, + (f) optional port of remote server, + (g) optional local address, + (h) optional local port, and + (i) optional TUN/TAP local IPv6 address. + +Fields (e)-(h) are shown for CONNECTED state, +(d) and (i) are shown for ASSIGN_IP and CONNECTED states. + +(e) is available starting from OpenVPN 2.1 +(f)-(i) are available starting from OpenVPN 2.4 Real-time state notifications will have a ">STATE:" prefix prepended to them. diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c index cef063d9c30..36a99e6f7df 100644 --- a/src/openvpn/forward.c +++ b/src/openvpn/forward.c @@ -208,8 +208,10 @@ check_connection_established_dowork (struct context *c) management_set_state (management, OPENVPN_STATE_GET_CONFIG, NULL, - 0, - 0); + NULL, + NULL, + NULL, + NULL); } #endif /* fire up push request right away (already 1s delayed) */ diff --git a/src/openvpn/init.c b/src/openvpn/init.c index c5c0ab6dd9e..5c170879682 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -44,6 +44,7 @@ #include "ping.h" #include "mstats.h" #include "ssl_verify.h" +#include "forward-inline.h" #include "memdbg.h" @@ -1273,26 +1274,48 @@ initialization_sequence_completed (struct context *c, const unsigned int flags) /* Tell management interface that we initialized */ if (management) { - in_addr_t tun_local = 0; - in_addr_t tun_remote = 0; /* FKS */ + in_addr_t *tun_local = NULL; + struct in6_addr *tun_local6 = NULL; + struct openvpn_sockaddr local, remote; + struct link_socket_actual *actual; + socklen_t sa_len = sizeof(local); const char *detail = "SUCCESS"; - if (c->c1.tuntap) - tun_local = c->c1.tuntap->local; - /* TODO(jjo): for ipv6 this will convert some 32bits in the ipv6 addr - * to a meaningless ipv4 address. - * In any case, is somewhat inconsistent to send local tunnel - * addr with remote _endpoint_ addr (?) - */ - tun_remote = htonl (c->c1.link_socket_addr.actual.dest.addr.in4.sin_addr.s_addr); if (flags & ISC_ERRORS) - detail = "ERROR"; + detail = "ERROR"; + + CLEAR (local); + actual = &get_link_socket_info(c)->lsa->actual; + remote = actual->dest; + getsockname(c->c2.link_socket->sd, &local.addr.sa, &sa_len); +#if ENABLE_IP_PKTINFO + if (!addr_defined(&local)) + { + switch (local.addr.sa.sa_family) + { + case AF_INET: + local.addr.in4.sin_addr = actual->pi.in4.ipi_spec_dst; + break; + case AF_INET6: + local.addr.in6.sin6_addr = actual->pi.in6.ipi6_addr; + break; + } + } +#endif + + if (c->c1.tuntap) + { + tun_local = &c->c1.tuntap->local; + tun_local6 = &c->c1.tuntap->local_ipv6; + } management_set_state (management, OPENVPN_STATE_CONNECTED, detail, tun_local, - tun_remote); + tun_local6, + &local, + &remote); if (tun_local) - management_post_tunnel_open (management, tun_local); + management_post_tunnel_open (management, *tun_local); } #endif } @@ -3288,8 +3311,10 @@ open_management (struct context *c) management_set_state (management, OPENVPN_STATE_CONNECTING, NULL, - (in_addr_t)0, - (in_addr_t)0); + NULL, + NULL, + NULL, + NULL); } /* initial management hold, called early, before first context initialization */ diff --git a/src/openvpn/manage.c b/src/openvpn/manage.c index 97d6f0fa240..dcb1bc18757 100644 --- a/src/openvpn/manage.c +++ b/src/openvpn/manage.c @@ -2422,8 +2422,10 @@ 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) + const in_addr_t *tun_local_ip, + const struct in6_addr *tun_local_ip6, + const struct openvpn_sockaddr *local, + const struct openvpn_sockaddr *remote) { if (man->persist.state && (!(man->settings.flags & MF_SERVER) || state < OPENVPN_STATE_CLIENT_BASE)) { @@ -2436,9 +2438,15 @@ management_set_state (struct management *man, e.timestamp = now; e.u.state = state; e.string = detail; - e.local_ip = tun_local_ip; - e.remote_ip = tun_remote_ip; - + if (tun_local_ip) + e.local_ip = *tun_local_ip; + if (tun_local_ip6) + e.local_ip6 = *tun_local_ip6; + if (local) + e.local_sock = *local; + if (remote) + e.remote_sock = *remote; + log_history_add (man->persist.state, &e); if (man->connection.state_realtime) @@ -3460,7 +3468,14 @@ log_entry_print (const struct log_entry *e, unsigned int flags, struct gc_arena if (flags & LOG_PRINT_LOCAL_IP) 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)); + { + buf_printf (&out, ",%s", (!addr_defined (&e->remote_sock) ? "," : + print_sockaddr_ex (&e->remote_sock.addr.sa, ",", PS_DONT_SHOW_FAMILY|PS_SHOW_PORT, gc))); + buf_printf (&out, ",%s", (!addr_defined (&e->local_sock) ? "," : + print_sockaddr_ex (&e->local_sock.addr.sa, ",", PS_DONT_SHOW_FAMILY|PS_SHOW_PORT, gc))); + } + if (flags & LOG_PRINT_LOCAL_IP && !IN6_IS_ADDR_UNSPECIFIED(&e->local_ip6)) + buf_printf (&out, ",%s", print_in6_addr (e->local_ip6, IA_EMPTY_IF_UNDEF, gc)); 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 a97e8a23458..988600f5e29 100644 --- a/src/openvpn/manage.h +++ b/src/openvpn/manage.h @@ -88,7 +88,9 @@ struct log_entry time_t timestamp; const char *string; in_addr_t local_ip; - in_addr_t remote_ip; + struct in6_addr local_ip6; + struct openvpn_sockaddr local_sock; + struct openvpn_sockaddr remote_sock; union log_entry_union u; }; @@ -496,8 +498,10 @@ management_enable_def_auth (const 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); + const in_addr_t *tun_local_ip, + const struct in6_addr *tun_local_ip6, + const struct openvpn_sockaddr *local_addr, + const struct openvpn_sockaddr *remote_addr); /* * The management object keeps track of OpenVPN --echo diff --git a/src/openvpn/route.c b/src/openvpn/route.c index d06018730ff..4a60345d451 100644 --- a/src/openvpn/route.c +++ b/src/openvpn/route.c @@ -1093,8 +1093,10 @@ add_routes (struct route_list *rl, struct route_ipv6_list *rl6, const struct tun management_set_state (management, OPENVPN_STATE_ADD_ROUTES, NULL, - 0, - 0); + NULL, + NULL, + NULL, + NULL); } #endif diff --git a/src/openvpn/sig.c b/src/openvpn/sig.c index a3d29de0d52..f903fc0efae 100644 --- a/src/openvpn/sig.c +++ b/src/openvpn/sig.c @@ -189,8 +189,10 @@ signal_restart_status (const struct signal_info *si) management_set_state (management, state, si->signal_text ? si->signal_text : signal_name (si->signal_received, true), - (in_addr_t)0, - (in_addr_t)0); + NULL, + NULL, + NULL, + NULL); } #endif } diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c index 8e6b4bcac69..13c05e0762f 100644 --- a/src/openvpn/socket.c +++ b/src/openvpn/socket.c @@ -363,8 +363,10 @@ openvpn_getaddrinfo (unsigned int flags, management_set_state (management, OPENVPN_STATE_RESOLVE, NULL, - (in_addr_t)0, - (in_addr_t)0); + NULL, + NULL, + NULL, + NULL); } #endif @@ -1244,8 +1246,10 @@ socket_connect (socket_descriptor_t* sd, management_set_state (management, OPENVPN_STATE_TCP_CONNECT, NULL, - (in_addr_t)0, - (in_addr_t)0); + NULL, + NULL, + NULL, + NULL); #endif /* Set the actual address */ @@ -2371,17 +2375,22 @@ print_sockaddr_ex (const struct sockaddr *sa, switch(sa->sa_family) { case AF_INET: - buf_puts (&out, "[AF_INET]"); + if (!(flags & PS_DONT_SHOW_FAMILY)) + buf_puts (&out, "[AF_INET]"); salen = sizeof (struct sockaddr_in); addr_is_defined = ((struct sockaddr_in*) sa)->sin_addr.s_addr != 0; break; case AF_INET6: - buf_puts (&out, "[AF_INET6]"); + if (!(flags & PS_DONT_SHOW_FAMILY)) + buf_puts (&out, "[AF_INET6]"); salen = sizeof (struct sockaddr_in6); addr_is_defined = !IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6*) sa)->sin6_addr); break; case AF_UNSPEC: - return "[AF_UNSPEC]"; + if (!(flags & PS_DONT_SHOW_FAMILY)) + return "[AF_UNSPEC]"; + else + return ""; default: ASSERT(0); } diff --git a/src/openvpn/socket.h b/src/openvpn/socket.h index 54cdc8878a3..a8e0e816cd8 100644 --- a/src/openvpn/socket.h +++ b/src/openvpn/socket.h @@ -344,6 +344,7 @@ void sd_close (socket_descriptor_t *sd); #define PS_SHOW_PORT (1<<1) #define PS_SHOW_PKTINFO (1<<2) #define PS_DONT_SHOW_ADDR (1<<3) +#define PS_DONT_SHOW_FAMILY (1<<4) const char *print_sockaddr_ex (const struct sockaddr *addr, const char* separator, diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 86eda77c09a..817bc49d52e 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -2307,8 +2307,10 @@ tls_process (struct tls_multi *multi, management_set_state (management, OPENVPN_STATE_WAIT, NULL, - 0, - 0); + NULL, + NULL, + NULL, + NULL); } #endif } @@ -3016,8 +3018,10 @@ tls_pre_decrypt (struct tls_multi *multi, management_set_state (management, OPENVPN_STATE_AUTH, NULL, - 0, - 0); + NULL, + NULL, + NULL, + NULL); } #endif diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index c293e1ecd1b..014d988541b 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -711,8 +711,10 @@ do_ifconfig (struct tuntap *tt, management_set_state (management, OPENVPN_STATE_ASSIGN_IP, NULL, - tt->local, - 0); + &tt->local, + &tt->local_ipv6, + NULL, + NULL); } #endif From 4a82a9ac0bef6db58858a42b4dc500ae9e09682d Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Sat, 28 Nov 2015 20:58:37 +0100 Subject: [PATCH 150/643] Un-break compilation on *BSD Commit 2191c47165 introduced code to handle IP address query on multihoming hosts for IP_PKTINFO-supporting OSes, but all the BSDs need the "#elsif IP_RECVDSTADDR" variant... add code equivalent to what we have in socket.c/print_link_socket_actual_ex() Tested on FreeBSD 9.3/sparc64 Signed-off-by: Gert Doering Acked-by: Arne Schwabe Message-Id: <1448740717-60914-1-git-send-email-gert@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/10648 --- src/openvpn/init.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 5c170879682..179c7efba5a 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -1293,7 +1293,11 @@ initialization_sequence_completed (struct context *c, const unsigned int flags) switch (local.addr.sa.sa_family) { case AF_INET: +#ifdef IP_PKTINFO local.addr.in4.sin_addr = actual->pi.in4.ipi_spec_dst; +#else + local.addr.in4.sin_addr = actual->pi.in4; +#endif break; case AF_INET6: local.addr.in6.sin6_addr = actual->pi.in6.ipi6_addr; From 09f2670ce27158f81b4983c06f63870a5188d4aa Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sat, 28 Nov 2015 23:48:01 +0100 Subject: [PATCH 151/643] Fix openssl builds with custom-built library: specify most-dependent first Libraries should be specified from left-to-right as most-dependent to least-dependent. Thus, -lssl comes first, then -lcrypto. (This does not fail when pkg-config finds your libraries for you, since we tell it '-lssl needs -lcrypto' and we then end up with "-lcrypto -lssl -lcrypto", which is not pretty but does work.) Signed-off-by: Steffan Karger Acked-by: Arne Schwabe Message-Id: <1448750881-10767-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/10649 Signed-off-by: Gert Doering --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index d3cacc88ad4..a8675fedd8f 100644 --- a/configure.ac +++ b/configure.ac @@ -1080,7 +1080,7 @@ if test "${enable_crypto}" = "yes"; then test "${have_crypto_crypto}" != "yes" && AC_MSG_ERROR([${with_crypto_library} crypto is required but missing]) test "${enable_crypto_ofb_cfb}" = "yes" && AC_DEFINE([ENABLE_OFB_CFB_MODE], [1], [Enable OFB and CFB cipher modes]) OPTIONAL_CRYPTO_CFLAGS="${OPTIONAL_CRYPTO_CFLAGS} ${CRYPTO_CRYPTO_CFLAGS} ${CRYPTO_SSL_CFLAGS}" - OPTIONAL_CRYPTO_LIBS="${OPTIONAL_CRYPTO_LIBS} ${CRYPTO_CRYPTO_LIBS} ${CRYPTO_SSL_LIBS}" + OPTIONAL_CRYPTO_LIBS="${OPTIONAL_CRYPTO_LIBS} ${CRYPTO_SSL_LIBS} ${CRYPTO_CRYPTO_LIBS}" AC_DEFINE([ENABLE_CRYPTO], [1], [Enable crypto library]) fi From 13b585e8a4c6f9681ff23bc7fb0af71ce9d0162f Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sun, 29 Nov 2015 10:39:24 +0100 Subject: [PATCH 152/643] Support duplicate x509 field values in environment As reported in trac #387, an x509 DN can contain duplicate fields. Previously, we would overwrite any previous field value with a new one if we would process a second same-name field. Now, instead, append _$N, starting at N=1 to the name for each consequent field to export all fields to the enviroment. v2 - make better use of const qualifiers in env_set_get(), and use strcpy() instead of memcpy() in setenv_str_incr() Signed-off-by: Steffan Karger Acked-by: Selva Nair Acked-by: Gert Doering Message-Id: URL: http://article.gmane.org/gmane.network.openvpn.devel/10654 Signed-off-by: Gert Doering --- Changes.rst | 7 +++++++ src/openvpn/misc.c | 32 +++++++++++++++++++++++++++++++ src/openvpn/misc.h | 7 +++++++ src/openvpn/ssl_verify_openssl.c | 2 +- src/openvpn/ssl_verify_polarssl.c | 2 +- 5 files changed, 48 insertions(+), 2 deletions(-) diff --git a/Changes.rst b/Changes.rst index 41629bdbd2f..a791ca32fc3 100644 --- a/Changes.rst +++ b/Changes.rst @@ -36,6 +36,13 @@ LZ4 Compression User-visible Changes -------------------- +- For certificate DNs with duplicate fields, e.g. "OU=one,OU=two", both fields + are now exported to the environment, where each second and later occurrence + of a field get _$N appended to it's field name, starting at N=1. For the + example above, that would result in e.g. X509_0_OU=one, X509_0_OU_1=two. + Note that this breaks setups that rely on the fact that OpenVPN would + previously (incorrectly) only export the last occurence of a field. + - proto udp and proto tcp specify to use IPv4 and IPv6. The new options proto udp4 and tcp4 specify to use IPv4 only. diff --git a/src/openvpn/misc.c b/src/openvpn/misc.c index b6c88547b57..14bb0e6b642 100644 --- a/src/openvpn/misc.c +++ b/src/openvpn/misc.c @@ -607,6 +607,16 @@ env_set_add (struct env_set *es, const char *str) env_set_add_nolock (es, str); } +const char* +env_set_get (const struct env_set *es, const char *name) +{ + const struct env_item *item = es->list; + while (item && !env_string_equal(item->string, name)) { + item = item->next; + } + return item ? item->string : NULL; +} + void env_set_print (int msglevel, const struct env_set *es) { @@ -741,6 +751,28 @@ setenv_str_safe (struct env_set *es, const char *name, const char *value) msg (M_WARN, "setenv_str_safe: name overflow"); } +void setenv_str_incr(struct env_set *es, const char *name, const char *value) +{ + unsigned int counter = 1; + const size_t tmpname_len = strlen(name) + 5; /* 3 digits counter max */ + char *tmpname = gc_malloc(tmpname_len, true, NULL); + strcpy(tmpname, name); + while (NULL != env_set_get(es, tmpname) && counter < 1000) + { + ASSERT (openvpn_snprintf (tmpname, tmpname_len, "%s_%u", name, counter)); + counter++; + } + if (counter < 1000) + { + setenv_str (es, tmpname, value); + } + else + { + msg (D_TLS_DEBUG_MED, "Too many same-name env variables, ignoring: %s", name); + } + free (tmpname); +} + void setenv_del (struct env_set *es, const char *name) { diff --git a/src/openvpn/misc.h b/src/openvpn/misc.h index 7c2691257b0..be93daa549a 100644 --- a/src/openvpn/misc.h +++ b/src/openvpn/misc.h @@ -133,6 +133,12 @@ void setenv_str (struct env_set *es, const char *name, const char *value); void setenv_str_safe (struct env_set *es, const char *name, const char *value); void setenv_del (struct env_set *es, const char *name); +/** + * Store the supplied name value pair in the env_set. If the variable with the + * supplied name already exists, append _N to the name, starting at N=1. + */ +void setenv_str_incr(struct env_set *es, const char *name, const char *value); + void setenv_int_i (struct env_set *es, const char *name, const int value, const int i); void setenv_str_i (struct env_set *es, const char *name, const char *value, const int i); @@ -142,6 +148,7 @@ struct env_set *env_set_create (struct gc_arena *gc); void env_set_destroy (struct env_set *es); bool env_set_del (struct env_set *es, const char *str); void env_set_add (struct env_set *es, const char *str); +const char* env_set_get (const struct env_set *es, const char *name); void env_set_print (int msglevel, const struct env_set *es); diff --git a/src/openvpn/ssl_verify_openssl.c b/src/openvpn/ssl_verify_openssl.c index bf535227d50..d014f9d334b 100644 --- a/src/openvpn/ssl_verify_openssl.c +++ b/src/openvpn/ssl_verify_openssl.c @@ -448,7 +448,7 @@ x509_setenv (struct env_set *es, int cert_depth, openvpn_x509_cert_t *peer_cert) objbuf); string_mod (name_expand, CC_PRINT, CC_CRLF, '_'); string_mod ((char*)buf, CC_PRINT, CC_CRLF, '_'); - setenv_str (es, name_expand, (char*)buf); + setenv_str_incr (es, name_expand, (char*)buf); free (name_expand); OPENSSL_free (buf); } diff --git a/src/openvpn/ssl_verify_polarssl.c b/src/openvpn/ssl_verify_polarssl.c index 62818adcbdf..a2e6a8ec017 100644 --- a/src/openvpn/ssl_verify_polarssl.c +++ b/src/openvpn/ssl_verify_polarssl.c @@ -245,7 +245,7 @@ x509_setenv (struct env_set *es, int cert_depth, openvpn_x509_cert_t *cert) /* Check both strings, set environment variable */ string_mod (name_expand, CC_PRINT, CC_CRLF, '_'); string_mod ((char*)s, CC_PRINT, CC_CRLF, '_'); - setenv_str (es, name_expand, (char*)s); + setenv_str_incr (es, name_expand, (char*)s); name = name->next; } From cdd69bb7f1c207fb5a9648f36440d7c6e2dcaa76 Mon Sep 17 00:00:00 2001 From: Selva Nair Date: Thu, 26 Nov 2015 21:20:53 -0500 Subject: [PATCH 153/643] Unbreak read username password from management Commit 6e9373c846.. introduced a bug by which auth-user-pass or need-ok input falls back to read-from-stdin after successfully reading from management or console. Fix by treating stdin as the last option for input. Signed-off-by: Selva Nair Acked-by: Gert Doering Message-Id: <1448590853-26862-1-git-send-email-selva.nair@gmail.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/10630 Signed-off-by: Gert Doering --- src/openvpn/misc.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/openvpn/misc.c b/src/openvpn/misc.c index 14bb0e6b642..31815cb54a0 100644 --- a/src/openvpn/misc.c +++ b/src/openvpn/misc.c @@ -1036,8 +1036,8 @@ get_user_pass_cr (struct user_pass *up, if (!up->defined) { bool from_authfile = (auth_file && !streq (auth_file, "stdin")); - bool username_from_stdin = !from_authfile; - bool password_from_stdin = !from_authfile; + bool username_from_stdin = false; + bool password_from_stdin = false; if (flags & GET_USER_PASS_PREVIOUS_CREDS_FAILED) msg (M_WARN, "Note: previous '%s' credentials failed", prefix); @@ -1134,6 +1134,11 @@ get_user_pass_cr (struct user_pass *up, if (!(flags & GET_USER_PASS_PASSWORD_ONLY) && strlen (up->username) == 0) msg (M_FATAL, "ERROR: username from %s authfile '%s' is empty", prefix, auth_file); } + else + { + username_from_stdin = true; + password_from_stdin = true; + } /* * Get username/password from standard input? From a8f8b9267183c3cfc065f344d61effe6c55c3da6 Mon Sep 17 00:00:00 2001 From: Heiko Hund Date: Wed, 25 Nov 2015 17:46:49 +0100 Subject: [PATCH 154/643] put virtual IPv6 addresses into env Add missing environment variables for IPv6 virtual addresses: * ifconfig_pool_local_ip6 * ifconfig_pool_remote_ip6 * ifconfig_pool_ip6_netbits Signed-off-by: Heiko Hund Acked-by: Gert Doering Message-Id: <1448470009-5243-1-git-send-email-heiko.hund@sophos.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/10613 Signed-off-by: Gert Doering --- src/openvpn/multi.c | 22 ++++++++++++++++++---- src/openvpn/socket.c | 16 ++++++++++++++++ src/openvpn/socket.h | 5 +++++ 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index a2ab16ecbb7..6e6d45772bf 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -1506,10 +1506,24 @@ multi_set_virtual_addr_env (struct multi_context *m, struct multi_instance *mi) } } - /* TODO: I'm not exactly sure what these environment variables are - * used for, but if we have them for IPv4, we should also have - * them for IPv6, no? - */ + setenv_del (mi->context.c2.es, "ifconfig_pool_local_ip6"); + setenv_del (mi->context.c2.es, "ifconfig_pool_remote_ip6"); + setenv_del (mi->context.c2.es, "ifconfig_pool_ip6_netbits"); + + if (mi->context.c1.tuntap->ipv6 && mi->context.c2.push_ifconfig_ipv6_defined) + { + setenv_in6_addr (mi->context.c2.es, + "ifconfig_pool_remote", + &mi->context.c2.push_ifconfig_ipv6_local, + SA_SET_IF_NONZERO); + setenv_in6_addr (mi->context.c2.es, + "ifconfig_pool_local", + &mi->context.c2.push_ifconfig_ipv6_remote, + SA_SET_IF_NONZERO); + setenv_int (mi->context.c2.es, + "ifconfig_pool_ip6_netbits", + mi->context.c2.push_ifconfig_ipv6_netbits); + } } /* diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c index 13c05e0762f..396fa5427b8 100644 --- a/src/openvpn/socket.c +++ b/src/openvpn/socket.c @@ -2619,6 +2619,22 @@ setenv_in_addr_t (struct env_set *es, const char *name_prefix, in_addr_t addr, c } } +void +setenv_in6_addr (struct env_set *es, + const char *name_prefix, + const struct in6_addr *addr, + const unsigned int flags) +{ + if (!IN6_IS_ADDR_UNSPECIFIED (addr) || !(flags & SA_SET_IF_NONZERO)) + { + struct openvpn_sockaddr si; + CLEAR (si); + si.addr.in6.sin6_family = AF_INET6; + si.addr.in6.sin6_addr = *addr; + setenv_sockaddr (es, name_prefix, &si, flags); + } +} + void setenv_link_socket_actual (struct env_set *es, const char *name_prefix, diff --git a/src/openvpn/socket.h b/src/openvpn/socket.h index a8e0e816cd8..b154bc021ea 100644 --- a/src/openvpn/socket.h +++ b/src/openvpn/socket.h @@ -403,6 +403,11 @@ void setenv_in_addr_t (struct env_set *es, in_addr_t addr, const unsigned int flags); +void setenv_in6_addr (struct env_set *es, + const char *name_prefix, + const struct in6_addr *addr, + const unsigned int flags); + void setenv_link_socket_actual (struct env_set *es, const char *name_prefix, const struct link_socket_actual *act, From 9ffd00e7541d83571b9eec087c6b3545ff68441f Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Sun, 29 Nov 2015 15:55:59 +0100 Subject: [PATCH 155/643] Remove --enable-password-save option This options is enabled in virtually all distributions and gives no real security benefit. Acked-by: Gert Doering Message-Id: <1448808959-10565-1-git-send-email-arne@rfc2549.org> URL: http://article.gmane.org/gmane.network.openvpn.devel/10661 Signed-off-by: Gert Doering --- configure.ac | 8 -------- src/openvpn/misc.c | 8 -------- src/openvpn/misc.h | 2 +- src/openvpn/ssl.c | 8 ++++---- 4 files changed, 5 insertions(+), 21 deletions(-) diff --git a/configure.ac b/configure.ac index a8675fedd8f..721395db2b3 100644 --- a/configure.ac +++ b/configure.ac @@ -169,13 +169,6 @@ AC_ARG_ENABLE( [enable_small="no"] ) -AC_ARG_ENABLE( - [password-save], - [AS_HELP_STRING([--enable-password-save], [allow --askpass and --auth-user-pass passwords to be read from a file @<:@default=no@:>@])], - , - [enable_password_save="no"] -) - AC_ARG_ENABLE( [iproute2], [AS_HELP_STRING([--enable-iproute2], [enable support for iproute2 @<:@default=no@:>@])], @@ -1054,7 +1047,6 @@ test "${enable_port_share}" = "yes" && AC_DEFINE([ENABLE_PORT_SHARE], [1], [Enab test "${enable_def_auth}" = "yes" && AC_DEFINE([ENABLE_DEF_AUTH], [1], [Enable deferred authentication]) test "${enable_pf}" = "yes" && AC_DEFINE([ENABLE_PF], [1], [Enable internal packet filter]) test "${enable_strict_options}" = "yes" && AC_DEFINE([ENABLE_STRICT_OPTIONS_CHECK], [1], [Enable strict options check between peers]) -test "${enable_password_save}" = "yes" && AC_DEFINE([ENABLE_PASSWORD_SAVE], [1], [Allow --askpass and --auth-user-pass passwords to be read from a file]) case "${with_crypto_library}" in openssl) diff --git a/src/openvpn/misc.c b/src/openvpn/misc.c index 31815cb54a0..5713d2e8942 100644 --- a/src/openvpn/misc.c +++ b/src/openvpn/misc.c @@ -1110,14 +1110,6 @@ get_user_pass_cr (struct user_pass *up, if (fgets (password_buf, USER_PASS_LEN, fp) != NULL) { -#ifndef ENABLE_PASSWORD_SAVE - /* - * Unless ENABLE_PASSWORD_SAVE is defined, don't allow sensitive passwords - * to be read from a file. - */ - if (flags & GET_USER_PASS_SENSITIVE) - msg (M_FATAL, "Sorry, '%s' password cannot be read from a file", prefix); -#endif chomp (password_buf); } diff --git a/src/openvpn/misc.h b/src/openvpn/misc.h index be93daa549a..dbe899e9b78 100644 --- a/src/openvpn/misc.h +++ b/src/openvpn/misc.h @@ -242,7 +242,7 @@ struct static_challenge_info {}; * Flags for get_user_pass and management_query_user_pass */ #define GET_USER_PASS_MANAGEMENT (1<<0) -#define GET_USER_PASS_SENSITIVE (1<<1) +/* GET_USER_PASS_SENSITIVE (1<<1) not used anymore */ #define GET_USER_PASS_PASSWORD_ONLY (1<<2) #define GET_USER_PASS_NEED_OK (1<<3) #define GET_USER_PASS_NOFATAL (1<<4) diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 817bc49d52e..887bd75e637 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -332,7 +332,7 @@ void pem_password_setup (const char *auth_file) { if (!strlen (passbuf.password)) - get_user_pass (&passbuf, auth_file, UP_TYPE_PRIVATE_KEY, GET_USER_PASS_MANAGEMENT|GET_USER_PASS_SENSITIVE|GET_USER_PASS_PASSWORD_ONLY); + get_user_pass (&passbuf, auth_file, UP_TYPE_PRIVATE_KEY, GET_USER_PASS_MANAGEMENT|GET_USER_PASS_PASSWORD_ONLY); } int @@ -375,11 +375,11 @@ auth_user_pass_setup (const char *auth_file, const struct static_challenge_info get_user_pass_cr (&auth_user_pass, auth_file, UP_TYPE_AUTH, - GET_USER_PASS_MANAGEMENT|GET_USER_PASS_SENSITIVE|GET_USER_PASS_DYNAMIC_CHALLENGE, + GET_USER_PASS_MANAGEMENT|GET_USER_PASS_DYNAMIC_CHALLENGE, auth_challenge); else if (sci) /* static challenge response */ { - int flags = GET_USER_PASS_MANAGEMENT|GET_USER_PASS_SENSITIVE|GET_USER_PASS_STATIC_CHALLENGE; + int flags = GET_USER_PASS_MANAGEMENT|GET_USER_PASS_STATIC_CHALLENGE; if (sci->flags & SC_ECHO) flags |= GET_USER_PASS_STATIC_CHALLENGE_ECHO; get_user_pass_cr (&auth_user_pass, @@ -390,7 +390,7 @@ auth_user_pass_setup (const char *auth_file, const struct static_challenge_info } else # endif - get_user_pass (&auth_user_pass, auth_file, UP_TYPE_AUTH, GET_USER_PASS_MANAGEMENT|GET_USER_PASS_SENSITIVE); + get_user_pass (&auth_user_pass, auth_file, UP_TYPE_AUTH, GET_USER_PASS_MANAGEMENT); #endif } } From 1e9c1f09cba95ebf72083c746cf847056a61c761 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Sun, 29 Nov 2015 19:52:24 +0100 Subject: [PATCH 156/643] Reflect enable-password-save change in documentation Acked-by: Gert Doering Message-Id: <1448823144-1497-1-git-send-email-arne@rfc2549.org> URL: http://article.gmane.org/gmane.network.openvpn.devel/10665 Signed-off-by: Gert Doering --- Changes.rst | 3 +++ doc/openvpn.8 | 5 +---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Changes.rst b/Changes.rst index a791ca32fc3..c2142fa2331 100644 --- a/Changes.rst +++ b/Changes.rst @@ -72,3 +72,6 @@ User-visible Changes - proto udp6/tcp6 in server mode will now try to always listen to both IPv4 and IPv6 on platforms that allow it. Use bind ipv6only to explicitly listen only on IPv6. + +- Removed --enable-password-save from configure. This option is now + always enabled. diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 9889540c04a..3519e7d9eea 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -3800,10 +3800,7 @@ over the client's routing table. Authenticate with server using username/password. .B up is a file containing username/password on 2 lines. If the -password line is missing, OpenVPN will prompt for one. (Note: OpenVPN -will only read passwords from a file if it has been built -with the \-\-enable\-password\-save configure option, or on Windows -by defining ENABLE_PASSWORD_SAVE in win/settings.in). +password line is missing, OpenVPN will prompt for one. If .B up From 80442aeed408f26700ea7570ced2409e7dd3e98b Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Sun, 29 Nov 2015 20:38:21 +0100 Subject: [PATCH 157/643] Also remove second instance of enable-password-save in the man page Acked-by: Selva Nair Message-Id: <1448825901-12294-1-git-send-email-arne@rfc2549.org> URL: http://article.gmane.org/gmane.network.openvpn.devel/10671 Signed-off-by: Gert Doering --- doc/openvpn.8 | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 3519e7d9eea..1b9dcaede2d 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -4886,10 +4886,7 @@ is specified, read the password from the first line of .B file. Keep in mind that storing your password in a file to a certain extent invalidates the extra security provided by -using an encrypted key (Note: OpenVPN -will only read passwords from a file if it has been built -with the \-\-enable\-password\-save configure option, or on Windows -by defining ENABLE_PASSWORD_SAVE in win/settings.in). +using an encrypted key. .\"********************************************************* .TP .B \-\-auth\-nocache From 015fe7177181fb4944ddf33debcfcd20c62ba55a Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Wed, 9 Dec 2015 21:03:55 +0100 Subject: [PATCH 158/643] Fix isatty() check for good. Commit 079e5b9c13 introduced a check to see if we --daemon'ized before trying to ask for a password (which would then fail with a non-intuitive error), breaking querying systemd under certain conditions. Move check from get_user_pass_cr() to get_console_input() and make it "full featured" by not only checking isatty() for stdin/stderr but also trying to open /dev/tty in case we still have a controlling tty - which is what getpass() does under the hood, so if either of this works, we're fine. Trac #618 and #630 Signed-off-by: Gert Doering Acked-by: Selva Nair Message-Id: <1449691435-5928-1-git-send-email-gert@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/10709 --- src/openvpn/console.c | 13 +++++++++++++ src/openvpn/misc.c | 6 ------ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/openvpn/console.c b/src/openvpn/console.c index d66d408721b..e1d46c413e4 100644 --- a/src/openvpn/console.c +++ b/src/openvpn/console.c @@ -208,6 +208,19 @@ get_console_input (const char *prompt, const bool echo, char *input, const int c #if defined(WIN32) return get_console_input_win32 (prompt, echo, input, capacity); #elif defined(HAVE_GETPASS) + + /* did we --daemon'ize before asking for passwords? + * (in which case neither stdin or stderr are connected to a tty and + * /dev/tty can not be open()ed anymore) + */ + if ( !isatty(0) && !isatty(2) ) + { + int fd = open( "/dev/tty", O_RDWR ); + if ( fd < 0 ) + { msg(M_FATAL, "neither stdin nor stderr are a tty device and you have neither a controlling tty nor systemd - can't ask for '%s'. If you used --daemon, you need to use --askpass to make passphrase-protected keys work, and you can not use --auth-nocache.", prompt ); } + close(fd); + } + if (echo) { FILE *fp; diff --git a/src/openvpn/misc.c b/src/openvpn/misc.c index 5713d2e8942..bc411bf12ee 100644 --- a/src/openvpn/misc.c +++ b/src/openvpn/misc.c @@ -1137,12 +1137,6 @@ get_user_pass_cr (struct user_pass *up, */ if (username_from_stdin || password_from_stdin) { -#ifndef WIN32 - /* did we --daemon'ize before asking for passwords? */ - if ( !isatty(0) && !isatty(2) ) - { msg(M_FATAL, "neither stdin nor stderr are a tty device, can't ask for %s password. If you used --daemon, you need to use --askpass to make passphrase-protected keys work, and you can not use --auth-nocache.", prefix ); } -#endif - #ifdef ENABLE_CLIENT_CR if (auth_challenge && (flags & GET_USER_PASS_DYNAMIC_CHALLENGE)) { From 4baec3ee10b8d6826d5f076a9832a92a5cfe3676 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Thu, 10 Dec 2015 13:37:10 +0100 Subject: [PATCH 159/643] Detect config lines that are too long and give a warning/error Trac #631 Acked-by: Gert Doering Message-Id: <1449751030-10703-1-git-send-email-arne@rfc2549.org> URL: http://article.gmane.org/gmane.network.openvpn.devel/10723 Signed-off-by: Gert Doering --- src/openvpn/options.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 36290a01546..c70a9b634b9 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -3813,7 +3813,7 @@ read_config_file (struct options *options, const int max_recursive_levels = 10; FILE *fp; int line_num; - char line[OPTION_LINE_SIZE]; + char line[OPTION_LINE_SIZE+1]; char *p[MAX_PARMS]; ++level; @@ -3831,6 +3831,10 @@ read_config_file (struct options *options, int offset = 0; CLEAR (p); ++line_num; + if (strlen(line) == OPTION_LINE_SIZE) + msg (msglevel, "In %s:%d: Maximum optione line length (%d) exceeded, line starts with %s", + file, line_num, OPTION_LINE_SIZE, line); + /* Ignore UTF-8 BOM at start of stream */ if (line_num == 1 && strncmp (line, "\xEF\xBB\xBF", 3) == 0) offset = 3; From 6417a6f8a01c702e7c8f19f01b696c3b0d2dc1f1 Mon Sep 17 00:00:00 2001 From: Lev Stipakov Date: Sat, 12 Dec 2015 00:37:52 +0200 Subject: [PATCH 160/643] Use adapter index for add/delete_route_ipv6 Trac #637 Signed-off-by: Lev Stipakov Acked-by: Gert Doering Message-Id: <1449873472-14954-1-git-send-email-lstipakov@gmail.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/10759 Signed-off-by: Gert Doering --- src/openvpn/route.c | 16 ++++++++++++---- src/openvpn/tun.c | 6 +++++- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/openvpn/route.c b/src/openvpn/route.c index 4a60345d451..2012b5c0f5e 100644 --- a/src/openvpn/route.c +++ b/src/openvpn/route.c @@ -1770,13 +1770,17 @@ add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int fla #elif defined (WIN32) + struct buffer out = alloc_buf_gc (64, &gc); if ( r6->adapter_index ) /* vpn server special route */ { - struct buffer out = alloc_buf_gc (64, &gc); buf_printf (&out, "interface=%d", r6->adapter_index ); - device = buf_bptr(&out); gateway_needed = true; } + else + { + buf_printf (&out, "interface=%d", tt->adapter_index ); + } + device = buf_bptr(&out); /* netsh interface ipv6 add route 2001:db8::/32 MyTunDevice */ argv_printf (&argv, "%s%sc interface ipv6 add route %s/%d %s", @@ -2168,13 +2172,17 @@ delete_route_ipv6 (const struct route_ipv6 *r6, const struct tuntap *tt, unsigne #elif defined (WIN32) + struct buffer out = alloc_buf_gc (64, &gc); if ( r6->adapter_index ) /* vpn server special route */ { - struct buffer out = alloc_buf_gc (64, &gc); buf_printf (&out, "interface=%d", r6->adapter_index ); - device = buf_bptr(&out); gateway_needed = true; } + else + { + buf_printf (&out, "interface=%d", tt->adapter_index ); + } + device = buf_bptr(&out); /* netsh interface ipv6 delete route 2001:db8::/32 MyTunDevice */ argv_printf (&argv, "%s%sc interface ipv6 delete route %s/%d %s", diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index 014d988541b..efcd22541cf 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -1306,11 +1306,13 @@ do_ifconfig (struct tuntap *tt, { char * saved_actual; char iface[64]; + DWORD idx; if (!strcmp (actual, "NULL")) msg (M_FATAL, "Error: When using --tun-ipv6, if you have more than one TAP-Windows adapter, you must also specify --dev-node"); - openvpn_snprintf(iface, sizeof(iface), "interface=%lu", get_adapter_index_flexible(actual)); + idx = get_adapter_index_flexible(actual); + openvpn_snprintf(iface, sizeof(iface), "interface=%lu", idx); /* example: netsh interface ipv6 set address interface=42 2001:608:8003::d store=active */ argv_printf (&argv, @@ -1328,6 +1330,8 @@ do_ifconfig (struct tuntap *tt, */ saved_actual = tt->actual_name; tt->actual_name = (char*) actual; + /* we use adapter_index in add_route_ipv6 */ + tt->adapter_index = idx; add_route_connected_v6_net(tt, es); tt->actual_name = saved_actual; } From 38c8565810f892a41a2ea0d18a707676119f1af0 Mon Sep 17 00:00:00 2001 From: ValdikSS Date: Thu, 10 Dec 2015 23:51:55 +0300 Subject: [PATCH 161/643] Add Windows DNS Leak fix using WFP ('block-outside-dns') This option blocks all out-of-tunnel communication on TCP/UDP port 53 (except for OpenVPN itself), preventing DNS Leaks on Windows 8.1 and 10. This is the same patch as dd628d2e0d786e4 in release/2.3, except that it is always compiled (on WIN32) here - we already require compilation for Vista+ in master (-> 2.4). Reviewed-by: Selva Nair Reviewed-by: Lev Stipakov Reviewed-by: James Yonan Acked-by: Gert Doering Message-Id: <1449780715-4027-1-git-send-email-iam@valdikss.org.ru> URL: http://article.gmane.org/gmane.network.openvpn.devel/10744 Signed-off-by: Gert Doering --- doc/openvpn.8 | 12 +- src/openvpn/Makefile.am | 2 +- src/openvpn/init.c | 17 +++ src/openvpn/openvpn.vcxproj | 4 +- src/openvpn/options.c | 10 ++ src/openvpn/options.h | 1 + src/openvpn/win32.c | 211 ++++++++++++++++++++++++++++++++++++ src/openvpn/win32.h | 3 + 8 files changed, 255 insertions(+), 5 deletions(-) mode change 100755 => 100644 src/openvpn/openvpn.vcxproj diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 1b9dcaede2d..3c0d70bf1a8 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -1129,8 +1129,8 @@ When used with .B \-\-client or .B \-\-pull, -accept options pushed by server EXCEPT for routes and dhcp options -like DNS servers. +accept options pushed by server EXCEPT for routes, block-outside-dns and dhcp +options like DNS servers. When used on the client, this option effectively bars the server from adding routes to the client's routing table, @@ -5568,6 +5568,14 @@ adapter list to the syslog or log file after the TUN/TAP adapter has been brought up and any routes have been added. .\"********************************************************* .TP +.B \-\-block\-outside\-dns +Block DNS servers on other network adapters to prevent +DNS leaks. This option prevents any application from accessing +TCP or UDP port 53 except one inside the tunnel. It uses +Windows Filtering Platform (WFP) and works on Windows Vista or +later. +.\"********************************************************* +.TP .B \-\-dhcp\-renew Ask Windows to renew the TAP adapter lease on startup. This option is normally unnecessary, as Windows automatically diff --git a/src/openvpn/Makefile.am b/src/openvpn/Makefile.am index c840f1677b1..c55a520132f 100644 --- a/src/openvpn/Makefile.am +++ b/src/openvpn/Makefile.am @@ -127,5 +127,5 @@ openvpn_LDADD = \ $(OPTIONAL_DL_LIBS) if WIN32 openvpn_SOURCES += openvpn_win32_resources.rc -openvpn_LDADD += -lgdi32 -lws2_32 -lwininet -lcrypt32 -liphlpapi -lwinmm +openvpn_LDADD += -lgdi32 -lws2_32 -lwininet -lcrypt32 -liphlpapi -lwinmm -lfwpuclnt -lrpcrt4 endif diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 179c7efba5a..e7e9532efbf 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -1495,6 +1495,15 @@ do_open_tun (struct context *c) "up", c->c2.es); +#if defined(WIN32) + if (c->options.block_outside_dns) + { + dmsg (D_LOW, "Blocking outside DNS"); + if (!win_wfp_block_dns(c->c1.tuntap->adapter_index)) + msg (M_FATAL, "Blocking DNS failed!"); + } +#endif + /* possibly add routes */ if ((route_order() == ROUTE_AFTER_TUN) && (!c->options.route_delay_defined)) do_route (&c->options, c->c1.route_list, c->c1.route_ipv6_list, @@ -1623,6 +1632,14 @@ do_close_tun (struct context *c, bool force) "down", c->c2.es); +#if defined(WIN32) + if (c->options.block_outside_dns) + { + if (!win_wfp_uninit()) + msg (M_FATAL, "Uninitialising WFP failed!"); + } +#endif + /* actually close tun/tap device based on --down-pre flag */ if (c->options.down_pre) do_close_tun_simple (c); diff --git a/src/openvpn/openvpn.vcxproj b/src/openvpn/openvpn.vcxproj old mode 100755 new mode 100644 index b117b0b640c..821c46c2fab --- a/src/openvpn/openvpn.vcxproj +++ b/src/openvpn/openvpn.vcxproj @@ -64,7 +64,7 @@ $(SOURCEBASE);%(AdditionalIncludeDirectories) - libeay32.lib;ssleay32.lib;lzo2.lib;pkcs11-helper.dll.lib;gdi32.lib;ws2_32.lib;wininet.lib;crypt32.lib;iphlpapi.lib;winmm.lib;%(AdditionalDependencies) + libeay32.lib;ssleay32.lib;lzo2.lib;pkcs11-helper.dll.lib;gdi32.lib;ws2_32.lib;wininet.lib;crypt32.lib;iphlpapi.lib;winmm.lib;Fwpuclnt.lib;Rpcrt4.lib;%(AdditionalDependencies) $(OPENSSL_HOME)/lib;$(LZO_HOME)/lib;$(PKCS11H_HOME)/lib;%(AdditionalLibraryDirectories) true Console @@ -89,7 +89,7 @@ $(SOURCEBASE);%(AdditionalIncludeDirectories) - libeay32.lib;ssleay32.lib;lzo2.lib;pkcs11-helper.dll.lib;gdi32.lib;ws2_32.lib;wininet.lib;crypt32.lib;iphlpapi.lib;winmm.lib;%(AdditionalDependencies) + libeay32.lib;ssleay32.lib;lzo2.lib;pkcs11-helper.dll.lib;gdi32.lib;ws2_32.lib;wininet.lib;crypt32.lib;iphlpapi.lib;winmm.lib;Fwpuclnt.lib;Rpcrt4.lib;%(AdditionalDependencies) $(OPENSSL_HOME)/lib;$(LZO_HOME)/lib;$(PKCS11H_HOME)/lib;%(AdditionalLibraryDirectories) true Console diff --git a/src/openvpn/options.c b/src/openvpn/options.c index c70a9b634b9..46aa824fbb1 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -704,6 +704,9 @@ static const char usage_message[] = " optional parameter controls the initial state of ex.\n" "--show-net-up : Show " PACKAGE_NAME "'s view of routing table and net adapter list\n" " after TAP adapter is up and routes have been added.\n" +#ifdef WIN32 + "--block-outside-dns : Block DNS on other network adapters to prevent DNS leaks\n" +#endif "Windows Standalone Options:\n" "\n" "--show-adapters : Show all TAP-Windows adapters.\n" @@ -805,6 +808,7 @@ init_options (struct options *o, const bool init_gc) o->tuntap_options.dhcp_lease_time = 31536000; /* one year */ o->tuntap_options.dhcp_masq_offset = 0; /* use network address as internal DHCP server address */ o->route_method = ROUTE_METHOD_ADAPTIVE; + o->block_outside_dns = false; #endif #if P2MP_SERVER o->real_hash_size = 256; @@ -1673,6 +1677,7 @@ show_settings (const struct options *o) #ifdef WIN32 SHOW_BOOL (show_net_up); SHOW_INT (route_method); + SHOW_BOOL (block_outside_dns); show_tuntap_options (&o->tuntap_options); #endif #endif @@ -6196,6 +6201,11 @@ add_option (struct options *options, VERIFY_PERMISSION (OPT_P_IPWIN32); options->tuntap_options.register_dns = true; } + else if (streq (p[0], "block-outside-dns") && !p[1]) + { + VERIFY_PERMISSION (OPT_P_IPWIN32); + options->block_outside_dns = true; + } else if (streq (p[0], "rdns-internal") && !p[1]) /* standalone method for internal use * diff --git a/src/openvpn/options.h b/src/openvpn/options.h index ebc0591f51b..2f6c8b4a9f0 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -585,6 +585,7 @@ struct options bool exit_event_initial_state; bool show_net_up; int route_method; + bool block_outside_dns; #endif bool use_peer_id; diff --git a/src/openvpn/win32.c b/src/openvpn/win32.c index 1f9bda05624..64dc1f75a05 100644 --- a/src/openvpn/win32.c +++ b/src/openvpn/win32.c @@ -46,6 +46,73 @@ #include "memdbg.h" +/* + * WFP-related defines and GUIDs. + */ +#include +#include +#include +#include + +#ifndef FWPM_SESSION_FLAG_DYNAMIC +#define FWPM_SESSION_FLAG_DYNAMIC 0x00000001 +#endif + +// c38d57d1-05a7-4c33-904f-7fbceee60e82 +DEFINE_GUID( + FWPM_LAYER_ALE_AUTH_CONNECT_V4, + 0xc38d57d1, + 0x05a7, + 0x4c33, + 0x90, 0x4f, 0x7f, 0xbc, 0xee, 0xe6, 0x0e, 0x82 +); + +// 4a72393b-319f-44bc-84c3-ba54dcb3b6b4 +DEFINE_GUID( + FWPM_LAYER_ALE_AUTH_CONNECT_V6, + 0x4a72393b, + 0x319f, + 0x44bc, + 0x84, 0xc3, 0xba, 0x54, 0xdc, 0xb3, 0xb6, 0xb4 +); + +// d78e1e87-8644-4ea5-9437-d809ecefc971 +DEFINE_GUID( + FWPM_CONDITION_ALE_APP_ID, + 0xd78e1e87, + 0x8644, + 0x4ea5, + 0x94, 0x37, 0xd8, 0x09, 0xec, 0xef, 0xc9, 0x71 +); + +// c35a604d-d22b-4e1a-91b4-68f674ee674b +DEFINE_GUID( + FWPM_CONDITION_IP_REMOTE_PORT, + 0xc35a604d, + 0xd22b, + 0x4e1a, + 0x91, 0xb4, 0x68, 0xf6, 0x74, 0xee, 0x67, 0x4b +); + +// 4cd62a49-59c3-4969-b7f3-bda5d32890a4 +DEFINE_GUID( + FWPM_CONDITION_IP_LOCAL_INTERFACE, + 0x4cd62a49, + 0x59c3, + 0x4969, + 0xb7, 0xf3, 0xbd, 0xa5, 0xd3, 0x28, 0x90, 0xa4 +); + +/* + * WFP firewall name. + */ +WCHAR * FIREWALL_NAME = L"OpenVPN"; /* GLOBAL */ + +/* + * WFP handle and GUID. + */ +static HANDLE m_hEngineHandle = NULL; /* GLOBAL */ + /* * Windows internal socket API state (opaque). */ @@ -1077,4 +1144,148 @@ win_get_tempdir() WideCharToMultiByte (CP_UTF8, 0, wtmpdir, -1, tmpdir, sizeof (tmpdir), NULL, NULL); return tmpdir; } + +bool +win_wfp_add_filter (HANDLE engineHandle, + const FWPM_FILTER0 *filter, + PSECURITY_DESCRIPTOR sd, + UINT64 *id) +{ + if (FwpmFilterAdd0(engineHandle, filter, sd, id) != ERROR_SUCCESS) + { + msg (M_NONFATAL, "Can't add WFP filter"); + return false; + } + return true; +} + +bool +win_wfp_block_dns (const NET_IFINDEX index) +{ + FWPM_SESSION0 session = {0}; + FWPM_SUBLAYER0 SubLayer = {0}; + NET_LUID tapluid; + UINT64 filterid; + WCHAR openvpnpath[MAX_PATH]; + FWP_BYTE_BLOB *openvpnblob = NULL; + FWPM_FILTER0 Filter = {0}; + FWPM_FILTER_CONDITION0 Condition[2] = {0}; + + /* Add temporary filters which don't survive reboots or crashes. */ + session.flags = FWPM_SESSION_FLAG_DYNAMIC; + + dmsg (D_LOW, "Opening WFP engine"); + + if (FwpmEngineOpen0(NULL, RPC_C_AUTHN_WINNT, NULL, &session, &m_hEngineHandle) != ERROR_SUCCESS) + { + msg (M_NONFATAL, "Can't open WFP engine"); + return false; + } + + if (UuidCreate(&SubLayer.subLayerKey) != NO_ERROR) + return false; + + /* Populate packet filter layer information. */ + SubLayer.displayData.name = FIREWALL_NAME; + SubLayer.displayData.description = FIREWALL_NAME; + SubLayer.flags = 0; + SubLayer.weight = 0x100; + + /* Add packet filter to our interface. */ + dmsg (D_LOW, "Adding WFP sublayer"); + if (FwpmSubLayerAdd0(m_hEngineHandle, &SubLayer, NULL) != ERROR_SUCCESS) + { + msg (M_NONFATAL, "Can't add WFP sublayer"); + return false; + } + + dmsg (D_LOW, "Blocking DNS using WFP"); + if (ConvertInterfaceIndexToLuid(index, &tapluid) != NO_ERROR) + { + msg (M_NONFATAL, "Can't convert interface index to LUID"); + return false; + } + dmsg (D_LOW, "Tap Luid: %I64d", tapluid.Value); + + /* Get OpenVPN path. */ + GetModuleFileNameW(NULL, openvpnpath, MAX_PATH); + + if (FwpmGetAppIdFromFileName0(openvpnpath, &openvpnblob) != ERROR_SUCCESS) + return false; + + /* Prepare filter. */ + Filter.subLayerKey = SubLayer.subLayerKey; + Filter.displayData.name = FIREWALL_NAME; + Filter.weight.type = FWP_EMPTY; + Filter.filterCondition = Condition; + Filter.numFilterConditions = 2; + + /* First filter. Block IPv4 DNS queries except from OpenVPN itself. */ + Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4; + Filter.action.type = FWP_ACTION_BLOCK; + + Condition[0].fieldKey = FWPM_CONDITION_IP_REMOTE_PORT; + Condition[0].matchType = FWP_MATCH_EQUAL; + Condition[0].conditionValue.type = FWP_UINT16; + Condition[0].conditionValue.uint16 = 53; + + Condition[1].fieldKey = FWPM_CONDITION_ALE_APP_ID; + Condition[1].matchType = FWP_MATCH_NOT_EQUAL; + Condition[1].conditionValue.type = FWP_BYTE_BLOB_TYPE; + Condition[1].conditionValue.byteBlob = openvpnblob; + + /* Add filter condition to our interface. */ + if (!win_wfp_add_filter(m_hEngineHandle, &Filter, NULL, &filterid)) + goto err; + dmsg (D_LOW, "Filter (Block IPv4 DNS) added with ID=%I64d", filterid); + + /* Second filter. Block IPv6 DNS queries except from OpenVPN itself. */ + Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V6; + + /* Add filter condition to our interface. */ + if (!win_wfp_add_filter(m_hEngineHandle, &Filter, NULL, &filterid)) + goto err; + dmsg (D_LOW, "Filter (Block IPv6 DNS) added with ID=%I64d", filterid); + + /* Third filter. Permit IPv4 DNS queries from TAP. */ + Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4; + Filter.action.type = FWP_ACTION_PERMIT; + + Condition[1].fieldKey = FWPM_CONDITION_IP_LOCAL_INTERFACE; + Condition[1].matchType = FWP_MATCH_EQUAL; + Condition[1].conditionValue.type = FWP_UINT64; + Condition[1].conditionValue.uint64 = &tapluid.Value; + + /* Add filter condition to our interface. */ + if (!win_wfp_add_filter(m_hEngineHandle, &Filter, NULL, &filterid)) + goto err; + dmsg (D_LOW, "Filter (Permit IPv4 DNS queries from TAP) added with ID=%I64d", filterid); + + /* Forth filter. Permit IPv6 DNS queries from TAP. */ + Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V6; + + /* Add filter condition to our interface. */ + if (!win_wfp_add_filter(m_hEngineHandle, &Filter, NULL, &filterid)) + goto err; + dmsg (D_LOW, "Filter (Permit IPv6 DNS queries from TAP) added with ID=%I64d", filterid); + + FwpmFreeMemory0((void **)&openvpnblob); + return true; + + err: + FwpmFreeMemory0((void **)&openvpnblob); + return false; +} + +bool +win_wfp_uninit() +{ + dmsg (D_LOW, "Uninitializing WFP"); + if (m_hEngineHandle) { + FwpmEngineClose0(m_hEngineHandle); + m_hEngineHandle = NULL; + } + return true; +} + #endif diff --git a/src/openvpn/win32.h b/src/openvpn/win32.h index cc18f027057..a5baebdb673 100644 --- a/src/openvpn/win32.h +++ b/src/openvpn/win32.h @@ -271,5 +271,8 @@ const char *win_get_tempdir(); /* Convert a string from UTF-8 to UCS-2 */ WCHAR *wide_string (const char* utf8, struct gc_arena *gc); +bool win_wfp_block_dns(const NET_IFINDEX index); +bool win_wfp_uninit(); + #endif #endif From 9dff2c1f106865a72a1d505076751dde170e88dc Mon Sep 17 00:00:00 2001 From: Lev Stipakov Date: Sat, 12 Dec 2015 14:34:20 +0200 Subject: [PATCH 162/643] Pass adapter index to up/down scripts Trac #637 Signed-off-by: Lev Stipakov Acked-by: Gert Doering Message-Id: <1449923660-27363-1-git-send-email-lstipakov@gmail.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/10762 Signed-off-by: Gert Doering --- doc/openvpn.8 | 11 +++++++++++ src/openvpn/init.c | 18 ++++++++++++++++++ src/openvpn/misc.c | 6 ++++++ src/openvpn/misc.h | 3 +++ 4 files changed, 38 insertions(+) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 3c0d70bf1a8..94b52220954 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -5954,6 +5954,17 @@ or script execution. .\"********************************************************* .TP +.B dev_idx +On Windows, the device index of the TUN/TAP adapter (to +be used in netsh.exe calls which sometimes just do not work +right with interface names). +Set prior to +.B \-\-up +or +.B \-\-down +script execution. +.\"********************************************************* +.TP .B foreign_option_{n} An option pushed via .B \-\-push diff --git a/src/openvpn/init.c b/src/openvpn/init.c index e7e9532efbf..2beec72203f 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -1485,6 +1485,9 @@ do_open_tun (struct context *c) c->plugins, OPENVPN_PLUGIN_UP, c->c1.tuntap->actual_name, +#ifdef WIN32 + c->c1.tuntap->adapter_index, +#endif dev_type_string (c->options.dev, c->options.dev_type), TUN_MTU_SIZE (&c->c2.frame), EXPANDED_SIZE (&c->c2.frame), @@ -1535,6 +1538,9 @@ do_open_tun (struct context *c) c->plugins, OPENVPN_PLUGIN_UP, c->c1.tuntap->actual_name, +#ifdef WIN32 + c->c1.tuntap->adapter_index, +#endif dev_type_string (c->options.dev, c->options.dev_type), TUN_MTU_SIZE (&c->c2.frame), EXPANDED_SIZE (&c->c2.frame), @@ -1573,6 +1579,9 @@ do_close_tun (struct context *c, bool force) if (c->c1.tuntap && c->c1.tuntap_owned) { const char *tuntap_actual = string_alloc (c->c1.tuntap->actual_name, &gc); +#ifdef WIN32 + DWORD adapter_index = c->c1.tuntap->adapter_index; +#endif const in_addr_t local = c->c1.tuntap->local; const in_addr_t remote_netmask = c->c1.tuntap->remote_netmask; @@ -1596,6 +1605,9 @@ do_close_tun (struct context *c, bool force) c->plugins, OPENVPN_PLUGIN_ROUTE_PREDOWN, tuntap_actual, +#ifdef WIN32 + adapter_index, +#endif NULL, TUN_MTU_SIZE (&c->c2.frame), EXPANDED_SIZE (&c->c2.frame), @@ -1621,6 +1633,9 @@ do_close_tun (struct context *c, bool force) c->plugins, OPENVPN_PLUGIN_DOWN, tuntap_actual, +#ifdef WIN32 + adapter_index, +#endif NULL, TUN_MTU_SIZE (&c->c2.frame), EXPANDED_SIZE (&c->c2.frame), @@ -1652,6 +1667,9 @@ do_close_tun (struct context *c, bool force) c->plugins, OPENVPN_PLUGIN_DOWN, tuntap_actual, +#ifdef WIN32 + adapter_index, +#endif NULL, TUN_MTU_SIZE (&c->c2.frame), EXPANDED_SIZE (&c->c2.frame), diff --git a/src/openvpn/misc.c b/src/openvpn/misc.c index bc411bf12ee..05ed0738d1f 100644 --- a/src/openvpn/misc.c +++ b/src/openvpn/misc.c @@ -62,6 +62,9 @@ run_up_down (const char *command, const struct plugin_list *plugins, int plugin_type, const char *arg, +#ifdef WIN32 + DWORD adapter_index, +#endif const char *dev_type, int tun_mtu, int link_mtu, @@ -82,6 +85,9 @@ run_up_down (const char *command, setenv_str (es, "dev", arg); if (dev_type) setenv_str (es, "dev_type", dev_type); +#ifdef WIN32 + setenv_int (es, "dev_idx", adapter_index); +#endif if (!ifconfig_local) ifconfig_local = ""; diff --git a/src/openvpn/misc.h b/src/openvpn/misc.h index dbe899e9b78..65a6e55a00b 100644 --- a/src/openvpn/misc.h +++ b/src/openvpn/misc.h @@ -63,6 +63,9 @@ void run_up_down (const char *command, const struct plugin_list *plugins, int plugin_type, const char *arg, +#ifdef WIN32 + DWORD adapter_index, +#endif const char *dev_type, int tun_mtu, int link_mtu, From 091edd8e2996867447eeb665af957547aa8b3107 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Mon, 14 Dec 2015 21:09:18 +0100 Subject: [PATCH 163/643] Warn user if their certificate has expired Previously, client certificate expiry warnings would only visible in the server log, and server certificate expiry warnings in the client log. Both after a (failed) connection attempt. This patch adds a warning to log when a users own certificate has expired (or is not yet valid) to ease problem diagnosis / error reporting. Note that this is just a warning, since on some systems (notably embedded devices) there might be no correct time available. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1450123758-31641-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/10794 Signed-off-by: Gert Doering --- src/openvpn/ssl.c | 3 +++ src/openvpn/ssl_backend.h | 9 +++++++++ src/openvpn/ssl_openssl.c | 27 +++++++++++++++++++++++++++ src/openvpn/ssl_polarssl.c | 14 ++++++++++++++ 4 files changed, 53 insertions(+) diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 887bd75e637..665fdd7d1a7 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -566,6 +566,9 @@ init_ssl (const struct options *options, struct tls_root_ctx *new_ctx) tls_ctx_load_extra_certs(new_ctx, options->extra_certs_file, options->extra_certs_file_inline); } + /* Check certificate notBefore and notAfter */ + tls_ctx_check_cert_time(new_ctx); + /* Once keys and cert are loaded, load ECDH parameters */ if (options->tls_server) tls_ctx_load_ecdh_params(new_ctx, options->ecdh_curve); diff --git a/src/openvpn/ssl_backend.h b/src/openvpn/ssl_backend.h index 99930e58611..ac28f5fefd6 100644 --- a/src/openvpn/ssl_backend.h +++ b/src/openvpn/ssl_backend.h @@ -174,6 +174,15 @@ void tls_ctx_set_options (struct tls_root_ctx *ctx, unsigned int ssl_flags); */ void tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers); +/** + * Check our certificate notBefore and notAfter fields, and warn if the cert is + * either not yet valid or has expired. Note that this is a non-fatal error, + * since we compare against the system time, which might be incorrect. + * + * @param ctx TLS context to get our certificate from. + */ +void tls_ctx_check_cert_time (const struct tls_root_ctx *ctx); + /** * Load Diffie Hellman Parameters, and load them into the library-specific * TLS context. diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c index 4430fec2d35..2b74818baea 100644 --- a/src/openvpn/ssl_openssl.c +++ b/src/openvpn/ssl_openssl.c @@ -350,6 +350,33 @@ tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers) crypto_msg (M_FATAL, "Failed to set restricted TLS cipher list: %s", openssl_ciphers); } +void +tls_ctx_check_cert_time (const struct tls_root_ctx *ctx) +{ + int ret; + const X509 *cert = SSL_CTX_get0_certificate(ctx->ctx); + + ret = X509_cmp_time (X509_get_notBefore (cert), NULL); + if (ret == 0) + { + msg (D_TLS_DEBUG_MED, "Failed to read certificate notBefore field."); + } + if (ret > 0) + { + msg (M_WARN, "WARNING: Your certificate is not yet valid!"); + } + + ret = X509_cmp_time (X509_get_notAfter (cert), NULL); + if (ret == 0) + { + msg (D_TLS_DEBUG_MED, "Failed to read certificate notAfter field."); + } + if (ret < 0) + { + msg (M_WARN, "WARNING: Your certificate has expired!"); + } +} + void tls_ctx_load_dh_params (struct tls_root_ctx *ctx, const char *dh_file, const char *dh_file_inline diff --git a/src/openvpn/ssl_polarssl.c b/src/openvpn/ssl_polarssl.c index cfdeb52151a..d7a40d772a7 100644 --- a/src/openvpn/ssl_polarssl.c +++ b/src/openvpn/ssl_polarssl.c @@ -215,6 +215,20 @@ tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers) free(tmp_ciphers_orig); } +void +tls_ctx_check_cert_time (const struct tls_root_ctx *ctx) +{ + if (x509_time_future (&ctx->crt_chain->valid_from)) + { + msg (M_WARN, "WARNING: Your certificate is not yet valid!"); + } + + if (x509_time_expired (&ctx->crt_chain->valid_to)) + { + msg (M_WARN, "WARNING: Your certificate has expired!"); + } +} + void tls_ctx_load_dh_params (struct tls_root_ctx *ctx, const char *dh_file, const char *dh_inline From 644f2cdd13f49cd374aebc1fc506474104aac372 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Mon, 14 Dec 2015 23:14:45 +0100 Subject: [PATCH 164/643] Disable certificate notBefore/notAfter sanity check on OpenSSL < 1.0.2 The SSL_CTX_get0_certificate() function I used in 091edd8e is available in OpenSSL 1.0.2+ only. Older versions seem to not have a useful alternative. The remaining option would then be to create a cache for our parsed certificate, but that would mean adding more struct members and code for the select group of people that do use an up-to-date openvpn, but do not update their openssl. I don't think that's worth it. So just disable the code for older openssl versions. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1450131285-30182-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/10802 Signed-off-by: Gert Doering --- src/openvpn/ssl_openssl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c index 2b74818baea..4792b088c96 100644 --- a/src/openvpn/ssl_openssl.c +++ b/src/openvpn/ssl_openssl.c @@ -353,6 +353,7 @@ tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers) void tls_ctx_check_cert_time (const struct tls_root_ctx *ctx) { +#if OPENSSL_VERSION_NUMBER >= 0x10002000L int ret; const X509 *cert = SSL_CTX_get0_certificate(ctx->ctx); @@ -375,6 +376,7 @@ tls_ctx_check_cert_time (const struct tls_root_ctx *ctx) { msg (M_WARN, "WARNING: Your certificate has expired!"); } +#endif } void From 9b36bd40d393620cce83392f4a56392ba391fb7c Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sun, 20 Dec 2015 11:44:09 +0100 Subject: [PATCH 165/643] Make assert_failed() print the failed condition Easy change to make logging output more useful. v2: don't print the failed condition if ENABLE_SMALL is defined. Signed-off-by: Steffan Karger Acked-by: Arne Schwabe Acked-by: Gert Doering Message-Id: <1450608249-9947-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/10862 Signed-off-by: Gert Doering --- src/openvpn/error.c | 7 +++++-- src/openvpn/error.h | 9 +++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/openvpn/error.c b/src/openvpn/error.c index 66f37f3b9a4..cfd5a418e62 100644 --- a/src/openvpn/error.c +++ b/src/openvpn/error.c @@ -394,9 +394,12 @@ dont_mute (unsigned int flags) } void -assert_failed (const char *filename, int line) +assert_failed (const char *filename, int line, const char *condition) { - msg (M_FATAL, "Assertion failed at %s:%d", filename, line); + if (condition) + msg (M_FATAL, "Assertion failed at %s:%d (%s)", filename, line, condition); + else + msg (M_FATAL, "Assertion failed at %s:%d", filename, line); _exit(1); } diff --git a/src/openvpn/error.h b/src/openvpn/error.h index 1dc08640718..dd5ccf70177 100644 --- a/src/openvpn/error.h +++ b/src/openvpn/error.h @@ -211,9 +211,14 @@ const char *msg_flags_string (const unsigned int flags, struct gc_arena *gc); FILE *msg_fp(const unsigned int flags); /* Fatal logic errors */ -#define ASSERT(x) do { if (!(x)) assert_failed(__FILE__, __LINE__); } while (false) +#ifndef ENABLE_SMALL +#define ASSERT(x) do { if (!(x)) assert_failed(__FILE__, __LINE__, #x); } while (false) +#else +#define ASSERT(x) do { if (!(x)) assert_failed(__FILE__, __LINE__, NULL); } while (false) +#endif -void assert_failed (const char *filename, int line) __attribute__((__noreturn__)); +void assert_failed (const char *filename, int line, const char *condition) + __attribute__((__noreturn__)); #ifdef ENABLE_DEBUG void crash (void); /* force a segfault (debugging only) */ From 0385cd4804c133d48857e4b3fbfe93a75ecc68a5 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sun, 20 Dec 2015 22:27:48 +0100 Subject: [PATCH 166/643] cleanup: get rid of httpdigest.c type warnings When I compile with --enable-strict, I only want to see warnings that are relevant. So, change httpdigest.c to make the casts explicit. This commit should not change behaviour. v2: as discussed on #openvpn-devel, make colon a const uint8_t *, instead of uint8_t. v3: as further discussed on #openvpn-devel, don't use a 'colon' var, but just add casts. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1450646868-15346-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/10871 Signed-off-by: Gert Doering --- src/openvpn/httpdigest.c | 44 ++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/openvpn/httpdigest.c b/src/openvpn/httpdigest.c index 78b8344d7c6..99bbda4675c 100644 --- a/src/openvpn/httpdigest.c +++ b/src/openvpn/httpdigest.c @@ -76,20 +76,20 @@ DigestCalcHA1( const md_kt_t *md5_kt = md_kt_get("MD5"); md_ctx_init(&md5_ctx, md5_kt); - md_ctx_update(&md5_ctx, pszUserName, strlen(pszUserName)); - md_ctx_update(&md5_ctx, ":", 1); - md_ctx_update(&md5_ctx, pszRealm, strlen(pszRealm)); - md_ctx_update(&md5_ctx, ":", 1); - md_ctx_update(&md5_ctx, pszPassword, strlen(pszPassword)); + md_ctx_update(&md5_ctx, (const uint8_t *) pszUserName, strlen(pszUserName)); + md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1); + md_ctx_update(&md5_ctx, (const uint8_t *) pszRealm, strlen(pszRealm)); + md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1); + md_ctx_update(&md5_ctx, (const uint8_t *) pszPassword, strlen(pszPassword)); md_ctx_final(&md5_ctx, HA1); if (pszAlg && strcasecmp(pszAlg, "md5-sess") == 0) { md_ctx_init(&md5_ctx, md5_kt); md_ctx_update(&md5_ctx, HA1, HASHLEN); - md_ctx_update(&md5_ctx, ":", 1); - md_ctx_update(&md5_ctx, pszNonce, strlen(pszNonce)); - md_ctx_update(&md5_ctx, ":", 1); - md_ctx_update(&md5_ctx, pszCNonce, strlen(pszCNonce)); + md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1); + md_ctx_update(&md5_ctx, (const uint8_t *) pszNonce, strlen(pszNonce)); + md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1); + md_ctx_update(&md5_ctx, (const uint8_t *) pszCNonce, strlen(pszCNonce)); md_ctx_final(&md5_ctx, HA1); }; md_ctx_cleanup(&md5_ctx); @@ -119,12 +119,12 @@ DigestCalcResponse( /* calculate H(A2) */ md_ctx_init(&md5_ctx, md5_kt); - md_ctx_update(&md5_ctx, pszMethod, strlen(pszMethod)); - md_ctx_update(&md5_ctx, ":", 1); - md_ctx_update(&md5_ctx, pszDigestUri, strlen(pszDigestUri)); + md_ctx_update(&md5_ctx, (const uint8_t *) pszMethod, strlen(pszMethod)); + md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1); + md_ctx_update(&md5_ctx, (const uint8_t *) pszDigestUri, strlen(pszDigestUri)); if (strcasecmp(pszQop, "auth-int") == 0) { - md_ctx_update(&md5_ctx, ":", 1); + md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1); md_ctx_update(&md5_ctx, HEntity, HASHHEXLEN); }; md_ctx_final(&md5_ctx, HA2); @@ -133,17 +133,17 @@ DigestCalcResponse( /* calculate response */ md_ctx_init(&md5_ctx, md5_kt); md_ctx_update(&md5_ctx, HA1, HASHHEXLEN); - md_ctx_update(&md5_ctx, ":", 1); - md_ctx_update(&md5_ctx, pszNonce, strlen(pszNonce)); - md_ctx_update(&md5_ctx, ":", 1); + md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1); + md_ctx_update(&md5_ctx, (const uint8_t *) pszNonce, strlen(pszNonce)); + md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1); if (*pszQop) { - md_ctx_update(&md5_ctx, pszNonceCount, strlen(pszNonceCount)); - md_ctx_update(&md5_ctx, ":", 1); - md_ctx_update(&md5_ctx, pszCNonce, strlen(pszCNonce)); - md_ctx_update(&md5_ctx, ":", 1); - md_ctx_update(&md5_ctx, pszQop, strlen(pszQop)); - md_ctx_update(&md5_ctx, ":", 1); + md_ctx_update(&md5_ctx, (const uint8_t *) pszNonceCount, strlen(pszNonceCount)); + md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1); + md_ctx_update(&md5_ctx, (const uint8_t *) pszCNonce, strlen(pszCNonce)); + md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1); + md_ctx_update(&md5_ctx, (const uint8_t *) pszQop, strlen(pszQop)); + md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1); }; md_ctx_update(&md5_ctx, HA2Hex, HASHHEXLEN); md_ctx_final(&md5_ctx, RespHash); From 0f7319906a9dff58226821b1686fd80f4e4e3b35 Mon Sep 17 00:00:00 2001 From: Phillip Smith Date: Tue, 22 Dec 2015 11:12:26 +1100 Subject: [PATCH 167/643] Use bob.example.com and alice.example.com to improve clarity of documentation This patch uses generic "bob.example.com" and "alice.example.com" hostnames to replace the current "may" and "june" examples. Generic names chosen rather than other names like "server"/"client" or "head-office"/"remote-office" etc which may create other unintended or implicit meanings to the reader. The example.com domain is set aside defined by IANA for use as documentation examples. Refer to: http://www.iana.org/domains/reserved Using this well-known domain makes comprehension of documentation easier. This patch incorporates feedback from Gert Doering and Selva Nair. Signed-off-by: Phillip Smith Acked-by: Steffan Karger Message-Id: <1450743146-9050-1-git-send-email-fukawi2@gmail.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/10875 Signed-off-by: Gert Doering --- doc/openvpn.8 | 74 +++++++++++++++++++++++++-------------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 94b52220954..368bd4c2b08 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -6601,13 +6601,13 @@ for use with OpenVPN. .SS VPN Address Setup: For purposes of our example, our two machines will be called -.B may.kg +.B bob.example.com and -.B june.kg. +.B alice.example.com. If you are constructing a VPN over the internet, then replace -.B may.kg +.B bob.example.com and -.B june.kg +.B alice.example.com with the internet hostname or IP address that each machine will use to contact the other over the internet. @@ -6615,8 +6615,8 @@ Now we will choose the tunnel endpoints. Tunnel endpoints are private IP addresses that only have meaning in the context of the VPN. Each machine will use the tunnel endpoint of the other machine to access it over the VPN. In our example, -the tunnel endpoint for may.kg -will be 10.4.0.1 and for june.kg, 10.4.0.2. +the tunnel endpoint for bob.example.com +will be 10.4.0.1 and for alice.example.com, 10.4.0.2. Once the VPN is established, you have essentially created a secure alternate path between the two hosts @@ -6625,16 +6625,16 @@ control which network traffic passes between the hosts (a) over the VPN or (b) independently of the VPN, by choosing whether to use (a) the VPN endpoint address or (b) the public internet address, -to access the remote host. For example if you are on may.kg and you wish to connect to june.kg +to access the remote host. For example if you are on bob.example.com and you wish to connect to alice.example.com via .B ssh without using the VPN (since .B ssh has its own built-in security) you would use the command -.B ssh june.kg. +.B ssh alice.example.com. However in the same scenario, you could also use the command .B telnet 10.4.0.2 -to create a telnet session with june.kg over the VPN, that would +to create a telnet session with alice.example.com over the VPN, that would use the VPN to secure the session rather than .B ssh. @@ -6649,21 +6649,21 @@ you will get a weird feedback loop. .\"********************************************************* .SS Example 1: A simple tunnel without security .LP -On may: +On bob: .IP -.B openvpn \-\-remote june.kg \-\-dev tun1 \-\-ifconfig 10.4.0.1 10.4.0.2 \-\-verb 9 +.B openvpn \-\-remote alice.example.com \-\-dev tun1 \-\-ifconfig 10.4.0.1 10.4.0.2 \-\-verb 9 .LP -On june: +On alice: .IP -.B openvpn \-\-remote may.kg \-\-dev tun1 \-\-ifconfig 10.4.0.2 10.4.0.1 \-\-verb 9 +.B openvpn \-\-remote bob.example.com \-\-dev tun1 \-\-ifconfig 10.4.0.2 10.4.0.1 \-\-verb 9 .LP Now verify the tunnel is working by pinging across the tunnel. .LP -On may: +On bob: .IP .B ping 10.4.0.2 .LP -On june: +On alice: .IP .B ping 10.4.0.1 .LP @@ -6676,7 +6676,7 @@ program. Omit the option to have OpenVPN run quietly. .\"********************************************************* .SS Example 2: A tunnel with static-key security (i.e. using a pre-shared secret) -First build a static key on may. +First build a static key on bob. .IP .B openvpn \-\-genkey \-\-secret key .LP @@ -6685,39 +6685,39 @@ This command will build a random key file called (in ascii format). Now copy .B key -to june over a secure medium such as by +to alice over a secure medium such as by using the .BR scp (1) program. .LP -On may: +On bob: .IP -.B openvpn \-\-remote june.kg \-\-dev tun1 \-\-ifconfig 10.4.0.1 10.4.0.2 \-\-verb 5 \-\-secret key +.B openvpn \-\-remote alice.example.com \-\-dev tun1 \-\-ifconfig 10.4.0.1 10.4.0.2 \-\-verb 5 \-\-secret key .LP -On june: +On alice: .IP -.B openvpn \-\-remote may.kg \-\-dev tun1 \-\-ifconfig 10.4.0.2 10.4.0.1 \-\-verb 5 \-\-secret key +.B openvpn \-\-remote bob.example.com \-\-dev tun1 \-\-ifconfig 10.4.0.2 10.4.0.1 \-\-verb 5 \-\-secret key .LP Now verify the tunnel is working by pinging across the tunnel. .LP -On may: +On bob: .IP .B ping 10.4.0.2 .LP -On june: +On alice: .IP .B ping 10.4.0.1 .\"********************************************************* .SS Example 3: A tunnel with full TLS-based security For this test, we will designate -.B may +.B bob as the TLS client and -.B june +.B alice as the TLS server. .I Note that client or server designation only has meaning for the TLS subsystem. It has no bearing on OpenVPN's peer-to-peer, UDP-based communication model. First, build a separate certificate/key pair -for both may and june (see above where +for both bob and alice (see above where .B \-\-cert is discussed for more info). Then construct Diffie Hellman parameters (see above where @@ -6732,21 +6732,21 @@ client.crt and server.crt. For Diffie Hellman parameters you can use the included file dh1024.pem. .I Note that all client, server, and certificate authority certificates and keys included in the OpenVPN distribution are totally insecure and should be used for testing only. .LP -On may: +On bob: .IP -.B openvpn \-\-remote june.kg \-\-dev tun1 \-\-ifconfig 10.4.0.1 10.4.0.2 \-\-tls\-client \-\-ca ca.crt \-\-cert client.crt \-\-key client.key \-\-reneg\-sec 60 \-\-verb 5 +.B openvpn \-\-remote alice.example.com \-\-dev tun1 \-\-ifconfig 10.4.0.1 10.4.0.2 \-\-tls\-client \-\-ca ca.crt \-\-cert client.crt \-\-key client.key \-\-reneg\-sec 60 \-\-verb 5 .LP -On june: +On alice: .IP -.B openvpn \-\-remote may.kg \-\-dev tun1 \-\-ifconfig 10.4.0.2 10.4.0.1 \-\-tls\-server \-\-dh dh1024.pem \-\-ca ca.crt \-\-cert server.crt \-\-key server.key \-\-reneg\-sec 60 \-\-verb 5 +.B openvpn \-\-remote bob.example.com \-\-dev tun1 \-\-ifconfig 10.4.0.2 10.4.0.1 \-\-tls\-server \-\-dh dh1024.pem \-\-ca ca.crt \-\-cert server.crt \-\-key server.key \-\-reneg\-sec 60 \-\-verb 5 .LP Now verify the tunnel is working by pinging across the tunnel. .LP -On may: +On bob: .IP .B ping 10.4.0.2 .LP -On june: +On alice: .IP .B ping 10.4.0.1 .LP @@ -6766,12 +6766,12 @@ option to use OpenVPN's default key renegotiation interval of one hour. .SS Routing: Assuming you can ping across the tunnel, the next step is to route a real subnet over -the secure tunnel. Suppose that may and june have two network +the secure tunnel. Suppose that bob and alice have two network interfaces each, one connected to the internet, and the other to a private network. Our goal is to securely connect -both private networks. We will assume that may's private subnet -is 10.0.0.0/24 and june's is 10.0.1.0/24. +both private networks. We will assume that bob's private subnet +is 10.0.0.0/24 and alice's is 10.0.1.0/24. .LP First, ensure that IP forwarding is enabled on both peers. On Linux, enable routing: @@ -6782,11 +6782,11 @@ and enable TUN packet forwarding through the firewall: .IP .B iptables \-A FORWARD \-i tun+ \-j ACCEPT .LP -On may: +On bob: .IP .B route add \-net 10.0.1.0 netmask 255.255.255.0 gw 10.4.0.2 .LP -On june: +On alice: .IP .B route add \-net 10.0.0.0 netmask 255.255.255.0 gw 10.4.0.1 .LP From 0e591a2fce325e2b91d429ea18aa6ed383330383 Mon Sep 17 00:00:00 2001 From: Jan Just Keijser Date: Sat, 26 Dec 2015 10:15:04 +0100 Subject: [PATCH 168/643] Make certificate expiry warning patch (091edd8e299686) work on OpenSSL 1.0.1 and earlier. Integrating feedback from Steffan Karger, tested by Gert Doering on FreeBSD 7.4 / OpenSSL 0.9.8. Signed-off-by: Gert Doering Acked-by: Steffan Karger Message-Id: <20151226091900.GU24952@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/10881 --- src/openvpn/ssl_openssl.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c index 4792b088c96..0a7f14b0bec 100644 --- a/src/openvpn/ssl_openssl.c +++ b/src/openvpn/ssl_openssl.c @@ -353,9 +353,17 @@ tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers) void tls_ctx_check_cert_time (const struct tls_root_ctx *ctx) { -#if OPENSSL_VERSION_NUMBER >= 0x10002000L int ret; - const X509 *cert = SSL_CTX_get0_certificate(ctx->ctx); + const X509 *cert; + +#if OPENSSL_VERSION_NUMBER >= 0x10002000L + /* OpenSSL 1.0.2 and up */ + cert = SSL_CTX_get0_certificate(ctx->ctx); +#else + /* OpenSSL 1.0.1 and earlier need an SSL object to get at the certificate */ + SSL *ssl = SSL_new(ctx->ctx); + cert = SSL_get_certificate(ssl); +#endif ret = X509_cmp_time (X509_get_notBefore (cert), NULL); if (ret == 0) @@ -376,6 +384,8 @@ tls_ctx_check_cert_time (const struct tls_root_ctx *ctx) { msg (M_WARN, "WARNING: Your certificate has expired!"); } +#if OPENSSL_VERSION_NUMBER < 0x10002000L + SSL_free(ssl); #endif } From cdc65ea0f1f94974f55352d794627561c78c4151 Mon Sep 17 00:00:00 2001 From: Lev Stipakov Date: Tue, 29 Dec 2015 23:02:37 +0200 Subject: [PATCH 169/643] Detecting and logging Windows versions Also send it with peer-info as IV_PLAT_VER. Signed-off-by: Lev Stipakov Acked-by: Gert Doering Message-Id: <1451422957-23951-1-git-send-email-lstipakov@gmail.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/10904 Signed-off-by: Gert Doering --- Changes.rst | 3 ++ config-msvc.h | 1 + configure.ac | 1 + src/compat/Makefile.am | 3 +- src/compat/compat-versionhelpers.h | 81 ++++++++++++++++++++++++++++++ src/openvpn/openvpn.c | 3 ++ src/openvpn/options.c | 12 +++++ src/openvpn/options.h | 4 ++ src/openvpn/ssl.c | 4 ++ src/openvpn/win32.c | 63 +++++++++++++++++++++++ src/openvpn/win32.h | 13 +++++ 11 files changed, 187 insertions(+), 1 deletion(-) create mode 100644 src/compat/compat-versionhelpers.h diff --git a/Changes.rst b/Changes.rst index c2142fa2331..f27d7f048f2 100644 --- a/Changes.rst +++ b/Changes.rst @@ -33,6 +33,9 @@ LZ4 Compression Additionally to LZO compression OpenVPN now also supports LZ4 compression. +Windows version + Windows version is detected, logged and possibly signalled to server + (IV_PLAT_VER= if --push-peer-info is set on client) User-visible Changes -------------------- diff --git a/config-msvc.h b/config-msvc.h index aa0eefff5b7..0bcf719502a 100644 --- a/config-msvc.h +++ b/config-msvc.h @@ -44,6 +44,7 @@ #define HAVE_SYS_STAT_H 1 #define HAVE_LZO_LZO1X_H 1 #define HAVE_LZO_LZOUTIL_H 1 +#define HAVE_VERSIONHELPERS_H 1 #define HAVE_ACCESS 1 #define HAVE_CHDIR 1 diff --git a/configure.ac b/configure.ac index 721395db2b3..4b2eb01d739 100644 --- a/configure.ac +++ b/configure.ac @@ -434,6 +434,7 @@ AC_CHECK_HEADERS([ \ netinet/in.h netinet/in_systm.h \ netinet/tcp.h arpa/inet.h netdb.h \ windows.h winsock2.h ws2tcpip.h \ + versionhelpers.h \ ]) AC_CHECK_HEADERS([ \ sys/time.h sys/ioctl.h sys/stat.h \ diff --git a/src/compat/Makefile.am b/src/compat/Makefile.am index 4591b8511d1..06bab5c2e80 100644 --- a/src/compat/Makefile.am +++ b/src/compat/Makefile.am @@ -27,4 +27,5 @@ libcompat_la_SOURCES = \ compat-daemon.c \ compat-inet_ntop.c \ compat-inet_pton.c \ - compat-lz4.c compat-lz4.h + compat-lz4.c compat-lz4.h \ + compat-versionhelpers.h diff --git a/src/compat/compat-versionhelpers.h b/src/compat/compat-versionhelpers.h new file mode 100644 index 00000000000..f634091a0fd --- /dev/null +++ b/src/compat/compat-versionhelpers.h @@ -0,0 +1,81 @@ +/** + * This file is part of the mingw-w64 runtime package. + * No warranty is given; refer to the file DISCLAIMER within this package. + */ + +#ifndef _INC_VERSIONHELPERS +#define _INC_VERSIONHELPERS + +#include + +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && !defined(__WIDL__) + +#ifdef __cplusplus +#define VERSIONHELPERAPI inline bool +#else +#define VERSIONHELPERAPI FORCEINLINE BOOL +#endif + +#define _WIN32_WINNT_WINBLUE 0x0603 + +VERSIONHELPERAPI IsWindowsVersionOrGreater(WORD major, WORD minor, WORD servpack) +{ + OSVERSIONINFOEXW vi = {sizeof(vi),major,minor,0,0,{0},servpack}; + return VerifyVersionInfoW(&vi, VER_MAJORVERSION|VER_MINORVERSION|VER_SERVICEPACKMAJOR, + VerSetConditionMask(VerSetConditionMask(VerSetConditionMask(0, + VER_MAJORVERSION,VER_GREATER_EQUAL), + VER_MINORVERSION,VER_GREATER_EQUAL), + VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL)); +} + +VERSIONHELPERAPI IsWindowsXPOrGreater(void) { + return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 0); +} + +VERSIONHELPERAPI IsWindowsXPSP1OrGreater(void) { + return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 1); +} + +VERSIONHELPERAPI IsWindowsXPSP2OrGreater(void) { + return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 2); +} + +VERSIONHELPERAPI IsWindowsXPSP3OrGreater(void) { + return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 3); +} + +VERSIONHELPERAPI IsWindowsVistaOrGreater(void) { + return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 0); +} + +VERSIONHELPERAPI IsWindowsVistaSP1OrGreater(void) { + return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 1); +} + +VERSIONHELPERAPI IsWindowsVistaSP2OrGreater(void) { + return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 2); +} + +VERSIONHELPERAPI IsWindows7OrGreater(void) { + return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN7), LOBYTE(_WIN32_WINNT_WIN7), 0); +} + +VERSIONHELPERAPI IsWindows7SP1OrGreater(void) { + return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN7), LOBYTE(_WIN32_WINNT_WIN7), 1); +} + +VERSIONHELPERAPI IsWindows8OrGreater(void) { + return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN8), LOBYTE(_WIN32_WINNT_WIN8), 0); +} + +VERSIONHELPERAPI IsWindows8Point1OrGreater(void) { + return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINBLUE), LOBYTE(_WIN32_WINNT_WINBLUE), 0); +} + +VERSIONHELPERAPI IsWindowsServer(void) { + OSVERSIONINFOEXW vi = {sizeof(vi),0,0,0,0,{0},0,0,0,VER_NT_WORKSTATION}; + return !VerifyVersionInfoW(&vi, VER_PRODUCT_TYPE, VerSetConditionMask(0, VER_PRODUCT_TYPE, VER_EQUAL)); +} + +#endif +#endif diff --git a/src/openvpn/openvpn.c b/src/openvpn/openvpn.c index 32e326e9c65..823c3dd13d4 100644 --- a/src/openvpn/openvpn.c +++ b/src/openvpn/openvpn.c @@ -220,6 +220,9 @@ openvpn_main (int argc, char *argv[]) /* print version number */ msg (M_INFO, "%s", title_string); +#ifdef WIN32 + show_windows_version(M_INFO); +#endif show_library_versions(M_INFO); /* misc stuff */ diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 46aa824fbb1..6861149b3cb 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -3438,6 +3438,15 @@ usage_small (void) openvpn_exit (OPENVPN_EXIT_STATUS_USAGE); /* exit point */ } +#ifdef WIN32 +void show_windows_version(const unsigned int flags) +{ + struct gc_arena gc = gc_new (); + msg (flags, "Windows version %s", win32_version_string (&gc, true)); + gc_free (&gc); +} +#endif + void show_library_versions(const unsigned int flags) { @@ -3463,6 +3472,9 @@ usage_version (void) { msg (M_INFO|M_NOPREFIX, "%s", title_string); show_library_versions( M_INFO|M_NOPREFIX ); +#ifdef WIN32 + show_windows_version( M_INFO|M_NOPREFIX ); +#endif msg (M_INFO|M_NOPREFIX, "Originally developed by James Yonan"); msg (M_INFO|M_NOPREFIX, "Copyright (C) 2002-2010 OpenVPN Technologies, Inc. "); #ifndef ENABLE_SMALL diff --git a/src/openvpn/options.h b/src/openvpn/options.h index 2f6c8b4a9f0..9e8a6a052c0 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -688,6 +688,10 @@ void usage_small (void); void show_library_versions(const unsigned int flags); +#ifdef WIN32 +void show_windows_version(const unsigned int flags); +#endif + void init_options (struct options *o, const bool init_gc); void uninit_options (struct options *o); diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 665fdd7d1a7..d39f131dba8 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -42,6 +42,7 @@ #endif #include "syshead.h" +#include "win32.h" #if defined(ENABLE_CRYPTO) @@ -1868,6 +1869,9 @@ push_peer_info(struct buffer *buf, struct tls_session *session) if (rgi.flags & RGI_HWADDR_DEFINED) buf_printf (&out, "IV_HWADDR=%s\n", format_hex_ex (rgi.hwaddr, 6, 0, 1, ":", &gc)); buf_printf (&out, "IV_SSL=%s\n", get_ssl_library_version() ); +#if defined(WIN32) + buf_printf (&out, "IV_PLAT_VER=%s\n", win32_version_string (&gc, false)); +#endif } /* push env vars that begin with UV_ and IV_GUI_VER */ diff --git a/src/openvpn/win32.c b/src/openvpn/win32.c index 64dc1f75a05..a01121b98bb 100644 --- a/src/openvpn/win32.c +++ b/src/openvpn/win32.c @@ -46,6 +46,12 @@ #include "memdbg.h" +#ifdef HAVE_VERSIONHELPERS_H +#include +#else +#include "compat-versionhelpers.h" +#endif + /* * WFP-related defines and GUIDs. */ @@ -1288,4 +1294,61 @@ win_wfp_uninit() return true; } +int +win32_version_info() +{ + if (!IsWindowsXPOrGreater()) + { + msg (M_FATAL, "Error: Windows version must be XP or greater."); + } + + if (!IsWindowsVistaOrGreater()) + { + return WIN_XP; + } + + if (!IsWindows7OrGreater()) + { + return WIN_VISTA; + } + + if (!IsWindows8OrGreater()) + { + return WIN_7; + } + else + { + return WIN_8; + } +} + +const char * +win32_version_string(struct gc_arena *gc, bool add_name) +{ + int version = win32_version_info(); + struct buffer out = alloc_buf_gc (256, gc); + + switch (version) + { + case WIN_XP: + buf_printf (&out, "5.1%s", add_name ? " (Windows XP)" : ""); + break; + case WIN_VISTA: + buf_printf (&out, "6.0%s", add_name ? " (Windows Vista)" : ""); + break; + case WIN_7: + buf_printf (&out, "6.1%s", add_name ? " (Windows 7)" : ""); + break; + case WIN_8: + buf_printf (&out, "6.2%s", add_name ? " (Windows 8 or greater)" : ""); + break; + default: + msg (M_NONFATAL, "Unknown Windows version: %d", version); + buf_printf (&out, "0.0%s", add_name ? " (unknown)" : ""); + break; + } + + return (const char *)out.data; +} + #endif diff --git a/src/openvpn/win32.h b/src/openvpn/win32.h index a5baebdb673..1e982071d6b 100644 --- a/src/openvpn/win32.h +++ b/src/openvpn/win32.h @@ -274,5 +274,18 @@ WCHAR *wide_string (const char* utf8, struct gc_arena *gc); bool win_wfp_block_dns(const NET_IFINDEX index); bool win_wfp_uninit(); +#define WIN_XP 0 +#define WIN_VISTA 1 +#define WIN_7 2 +#define WIN_8 3 + +int win32_version_info(); + +/* +String representation of Windows version number and name, see +https://msdn.microsoft.com/en-us/library/windows/desktop/ms724832(v=vs.85).aspx +*/ +const char * win32_version_string(struct gc_arena *gc, bool add_name); + #endif #endif From 868d9d01802da9bbbb3a758981f3c7310a905813 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sun, 3 Jan 2016 10:47:56 +0100 Subject: [PATCH 170/643] Fix regression in setups without a client certificate This fixes a null-pointer dereference in tls_ctx_cert_time(), which will occur on clients that do not use a client certificate (ie that only have auth-user-pass in the config, but no key and cert). This bug was introduced by commit 091edd8e on the master branch, and commit dfd940bb on the release/2.3 branch. This bug was found by chipitsine and reported in trac ticket #644. While touching this function, I also made this function conform to the openvpn coding style. v2 - fix memory leak in builds using pre-1.0.2 openssl Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1451814476-32574-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/10921 Signed-off-by: Gert Doering --- src/openvpn/ssl_openssl.c | 18 ++++++++++++++---- src/openvpn/ssl_polarssl.c | 6 ++++++ 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c index 0a7f14b0bec..d2f40e7788d 100644 --- a/src/openvpn/ssl_openssl.c +++ b/src/openvpn/ssl_openssl.c @@ -356,15 +356,22 @@ tls_ctx_check_cert_time (const struct tls_root_ctx *ctx) int ret; const X509 *cert; + ASSERT (ctx); + #if OPENSSL_VERSION_NUMBER >= 0x10002000L /* OpenSSL 1.0.2 and up */ - cert = SSL_CTX_get0_certificate(ctx->ctx); + cert = SSL_CTX_get0_certificate (ctx->ctx); #else /* OpenSSL 1.0.1 and earlier need an SSL object to get at the certificate */ - SSL *ssl = SSL_new(ctx->ctx); - cert = SSL_get_certificate(ssl); + SSL *ssl = SSL_new (ctx->ctx); + cert = SSL_get_certificate (ssl); #endif + if (cert == NULL) + { + goto cleanup; /* Nothing to check if there is no certificate */ + } + ret = X509_cmp_time (X509_get_notBefore (cert), NULL); if (ret == 0) { @@ -384,9 +391,12 @@ tls_ctx_check_cert_time (const struct tls_root_ctx *ctx) { msg (M_WARN, "WARNING: Your certificate has expired!"); } + +cleanup: #if OPENSSL_VERSION_NUMBER < 0x10002000L - SSL_free(ssl); + SSL_free (ssl); #endif + return; } void diff --git a/src/openvpn/ssl_polarssl.c b/src/openvpn/ssl_polarssl.c index d7a40d772a7..339d1fb194f 100644 --- a/src/openvpn/ssl_polarssl.c +++ b/src/openvpn/ssl_polarssl.c @@ -218,6 +218,12 @@ tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers) void tls_ctx_check_cert_time (const struct tls_root_ctx *ctx) { + ASSERT (ctx); + if (ctx->crt_chain == NULL) + { + return; /* Nothing to check if there is no certificate */ + } + if (x509_time_future (&ctx->crt_chain->valid_from)) { msg (M_WARN, "WARNING: Your certificate is not yet valid!"); From a75bb2e40a431e053ea1ef328ec022aaf851ccc0 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Sun, 3 Jan 2016 18:27:46 +0100 Subject: [PATCH 171/643] Implement the compression V2 data format for stub and lz4. Patch V2: Fix minor issues found by Steffan Patch V3: split wire codes and compression flags Patch V4: Fix further issues reported by Gert Patch V5: really fix the issues that should be fixed in v2 Patch V6: fix more minor things It has been tested against v3 server and again itself. From James Mail: Compression V2 I have observed that compression in many cases, even when enabled, often does not produce packet size reduction because much of the packet data typically generated by web sessions is already compressed. Further, the single byte that precedes the packet and indicates whether or not compression occurred has the unfortunate side effect of misaligning the IP packet in cases where compression did not occur. To remedy this, I propose a Compression V2 header that is optimized for the case where compression does not occur. a. No compression occurred and first byte of IP/Ethernet packet is NOT 0x50 (0 bytes of overhead and maintains alignment): [ uncompressed IP/Ethernet packet ] b. No compression occurred and first byte of IP/Ethernet packet is 0x50 (2 bytes of overhead but unlikely since no known IP packet can begin with 0x50): [ 0x50 ] [ 0x00 ] [ uncompressed IP/Ethernet packet ] c. Compression occurred (2 bytes of overhead): [ 0x50 ] [ compression Alg ID ] [ compressed IP/Ethernet packet ] Compression Alg ID is one-byte algorithm identifier for LZ4 (0x1), LZO (0x2), or Snappy (0x3). This approach has several beneficial effects: 1. In the common case where compression does not occur, no compression op is required, therefore there is zero overhead. 2. When compression does not occur, the IP/Ethernet packet alignment is retained. 3. This technique does not require any byte swapping with the tail of the packet which can potentially incur an expensive cache miss. Acked-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1451842066-13475-1-git-send-email-arne@rfc2549.org> URL: http://article.gmane.org/gmane.network.openvpn.devel/10925 Signed-off-by: Gert Doering --- src/openvpn/comp-lz4.c | 195 ++++++++++++++++++++++++++++++++--------- src/openvpn/comp-lz4.h | 1 + src/openvpn/comp.c | 31 +++++++ src/openvpn/comp.h | 25 ++++++ src/openvpn/compstub.c | 51 +++++++++++ src/openvpn/lzo.c | 3 - src/openvpn/options.c | 11 ++- 7 files changed, 272 insertions(+), 45 deletions(-) diff --git a/src/openvpn/comp-lz4.c b/src/openvpn/comp-lz4.c index 4651148579b..395f3d2f180 100644 --- a/src/openvpn/comp-lz4.c +++ b/src/openvpn/comp-lz4.c @@ -44,9 +44,6 @@ #include "memdbg.h" -/* Initial command byte to tell our peer if we compressed */ -#define LZ4_COMPRESS_BYTE 0x69 - static void lz4_compress_init (struct compress_context *compctx) { @@ -55,20 +52,22 @@ lz4_compress_init (struct compress_context *compctx) } static void -lz4_compress_uninit (struct compress_context *compctx) +lz4v2_compress_init (struct compress_context *compctx) { + msg (D_INIT_MEDIUM, "LZ4v2 compression initializing"); } static void -lz4_compress (struct buffer *buf, struct buffer work, - struct compress_context *compctx, - const struct frame* frame) +lz4_compress_uninit (struct compress_context *compctx) { - bool compressed = false; - - if (buf->len <= 0) - return; +} +static bool +do_lz4_compress (struct buffer *buf, + struct buffer *work, + struct compress_context *compctx, + const struct frame* frame) +{ /* * In order to attempt compression, length must be at least COMPRESS_THRESHOLD. */ @@ -78,33 +77,52 @@ lz4_compress (struct buffer *buf, struct buffer work, int zlen_max = ps + COMP_EXTRA_BUFFER (ps); int zlen; - ASSERT (buf_init (&work, FRAME_HEADROOM (frame))); - ASSERT (buf_safe (&work, zlen_max)); + ASSERT (buf_init (work, FRAME_HEADROOM (frame))); + ASSERT (buf_safe (work, zlen_max)); if (buf->len > ps) { dmsg (D_COMP_ERRORS, "LZ4 compression buffer overflow"); buf->len = 0; - return; + return false; } - zlen = LZ4_compress_limitedOutput((const char *)BPTR(buf), (char *)BPTR(&work), BLEN(buf), zlen_max ); + zlen = LZ4_compress_limitedOutput((const char *)BPTR(buf), (char *)BPTR(work), BLEN(buf), zlen_max ); if (zlen <= 0) { dmsg (D_COMP_ERRORS, "LZ4 compression error"); buf->len = 0; - return; + return false; } - ASSERT (buf_safe (&work, zlen)); - work.len = zlen; - compressed = true; + ASSERT (buf_safe (work, zlen)); + work->len = zlen; + - dmsg (D_COMP, "LZ4 compress %d -> %d", buf->len, work.len); + dmsg (D_COMP, "LZ4 compress %d -> %d", buf->len, work->len); compctx->pre_compress += buf->len; - compctx->post_compress += work.len; + compctx->post_compress += work->len; + return true; } + return false; +} + + +static void +lz4_compress (struct buffer *buf, struct buffer work, + struct compress_context *compctx, + const struct frame* frame) +{ + bool compressed; + if (buf->len <= 0) + return; + + compressed = do_lz4_compress(buf, &work, compctx, frame); + + /* On error do_lz4_compress sets buf len to zero, just return */ + if (buf->len == 0) + return; /* did compression save us anything? */ { @@ -128,13 +146,70 @@ lz4_compress (struct buffer *buf, struct buffer work, } } + +static void +lz4v2_compress (struct buffer *buf, struct buffer work, + struct compress_context *compctx, + const struct frame* frame) +{ + bool compressed; + if (buf->len <= 0) + return; + + compressed = do_lz4_compress(buf, &work, compctx, frame); + + /* On Error just return */ + if (buf->len == 0) + return; + + /* did compression save us anything? Include 2 byte compression header + in calculation */ + if (compressed && work.len + 2 < buf->len) + { + ASSERT(buf_prepend(&work, 2)); + uint8_t *head = BPTR (&work); + head[0] = COMP_ALGV2_INDICATOR_BYTE; + head[1] = COMP_ALGV2_LZ4_BYTE; + *buf = work; + } + else + { + compv2_escape_data_ifneeded(buf); + } +} + +void +do_lz4_decompress(size_t zlen_max, + struct buffer *work, + struct buffer *buf, + struct compress_context *compctx) +{ + int uncomp_len; + ASSERT (buf_safe (work, zlen_max)); + uncomp_len = LZ4_decompress_safe((const char *)BPTR(buf), (char *)BPTR(work), (size_t)BLEN(buf), zlen_max); + if (uncomp_len <= 0) + { + dmsg (D_COMP_ERRORS, "LZ4 decompression error: %d", uncomp_len); + buf->len = 0; + return; + } + + ASSERT (buf_safe (work, uncomp_len)); + work->len = uncomp_len; + + dmsg (D_COMP, "LZ4 decompress %d -> %d", buf->len, work->len); + compctx->pre_decompress += buf->len; + compctx->post_decompress += work->len; + + *buf = *work; +} + static void lz4_decompress (struct buffer *buf, struct buffer work, - struct compress_context *compctx, - const struct frame* frame) + struct compress_context *compctx, + const struct frame* frame) { size_t zlen_max = EXPANDED_SIZE (frame); - int uncomp_len; uint8_t c; /* flag indicating whether or not our peer compressed */ if (buf->len <= 0) @@ -152,23 +227,7 @@ lz4_decompress (struct buffer *buf, struct buffer work, if (c == LZ4_COMPRESS_BYTE) /* packet was compressed */ { - ASSERT (buf_safe (&work, zlen_max)); - uncomp_len = LZ4_decompress_safe((const char *)BPTR(buf), (char *)BPTR(&work), (size_t)BLEN(buf), zlen_max); - if (uncomp_len <= 0) - { - dmsg (D_COMP_ERRORS, "LZ4 decompression error: %d", uncomp_len); - buf->len = 0; - return; - } - - ASSERT (buf_safe (&work, uncomp_len)); - work.len = uncomp_len; - - dmsg (D_COMP, "LZ4 decompress %d -> %d", buf->len, work.len); - compctx->pre_decompress += buf->len; - compctx->post_decompress += work.len; - - *buf = work; + do_lz4_decompress(zlen_max, &work, buf, compctx); } else if (c == NO_COMPRESS_BYTE_SWAP) /* packet was not compressed */ { @@ -181,6 +240,52 @@ lz4_decompress (struct buffer *buf, struct buffer work, } } +static void +lz4v2_decompress (struct buffer *buf, struct buffer work, + struct compress_context *compctx, + const struct frame* frame) +{ + size_t zlen_max = EXPANDED_SIZE (frame); + uint8_t c; /* flag indicating whether or not our peer compressed */ + + if (buf->len <= 0) + return; + + ASSERT (buf_init (&work, FRAME_HEADROOM (frame))); + + /* do unframing/swap (assumes buf->len > 0) */ + uint8_t *head = BPTR (buf); + c = *head; + + /* Not compressed */ + if (c != COMP_ALGV2_INDICATOR_BYTE) { + return; + } + + /* Packet to short to make sense */ + if (buf->len <= 1) + { + buf->len=0; + return; + } + + c = head[1]; + if (c == COMP_ALGV2_LZ4_BYTE) /* packet was compressed */ + { + buf_advance(buf,2); + do_lz4_decompress(zlen_max, &work, buf, compctx); + } + else if (c == COMP_ALGV2_UNCOMPRESSED_BYTE) + { + buf_advance(buf,2); + } + else + { + dmsg (D_COMP_ERRORS, "Bad LZ4v2 decompression header byte: %d", c); + buf->len = 0; + } +} + const struct compress_alg lz4_alg = { "lz4", lz4_compress_init, @@ -189,6 +294,14 @@ const struct compress_alg lz4_alg = { lz4_decompress }; +const struct compress_alg lz4v2_alg = { + "lz4v2", + lz4v2_compress_init, + lz4_compress_uninit, + lz4v2_compress, + lz4v2_decompress +}; + #else static void dummy(void) {} #endif /* ENABLE_LZ4 */ diff --git a/src/openvpn/comp-lz4.h b/src/openvpn/comp-lz4.h index ca1dfa9bc76..9d3c6644f65 100644 --- a/src/openvpn/comp-lz4.h +++ b/src/openvpn/comp-lz4.h @@ -31,6 +31,7 @@ #include "buffer.h" extern const struct compress_alg lz4_alg; +extern const struct compress_alg lz4v2_alg; struct lz4_workspace { diff --git a/src/openvpn/comp.c b/src/openvpn/comp.c index 706ad7ea8e7..b420ea530da 100644 --- a/src/openvpn/comp.c +++ b/src/openvpn/comp.c @@ -50,6 +50,11 @@ comp_init(const struct compress_options *opt) compctx->alg = comp_stub_alg; (*compctx->alg.compress_init)(compctx); break; + case COMP_ALGV2_UNCOMPRESSED: + ALLOC_OBJ_CLEAR (compctx, struct compress_context); + compctx->flags = opt->flags; + compctx->alg = compv2_stub_alg; + break; #ifdef ENABLE_LZO case COMP_ALG_LZO: ALLOC_OBJ_CLEAR (compctx, struct compress_context); @@ -65,11 +70,35 @@ comp_init(const struct compress_options *opt) compctx->alg = lz4_alg; (*compctx->alg.compress_init)(compctx); break; + case COMP_ALGV2_LZ4: + ALLOC_OBJ_CLEAR (compctx, struct compress_context); + compctx->flags = opt->flags; + compctx->alg = lz4v2_alg; + break; #endif } return compctx; } +/* In the v2 compression schemes, an uncompressed packet has + * has no opcode in front, unless the first byte is 0x50. In this + * case the packet needs to be escaped */ +void +compv2_escape_data_ifneeded (struct buffer *buf) +{ + uint8_t *head = BPTR (buf); + if (head[0] != COMP_ALGV2_INDICATOR_BYTE) + return; + + /* Header is 0x50 */ + ASSERT(buf_prepend(buf, 2)); + + head = BPTR (buf); + head[0] = COMP_ALGV2_INDICATOR_BYTE; + head[1] = COMP_ALGV2_UNCOMPRESSED; +} + + void comp_uninit(struct compress_context *compctx) { @@ -120,6 +149,7 @@ comp_generate_peer_info_string(const struct compress_options *opt, struct buffer { #if defined(ENABLE_LZ4) buf_printf (out, "IV_LZ4=1\n"); + buf_printf (out, "IV_LZ4v2=1\n"); #endif #if defined(ENABLE_LZO) buf_printf (out, "IV_LZO=1\n"); @@ -129,6 +159,7 @@ comp_generate_peer_info_string(const struct compress_options *opt, struct buffer if (!lzo_avail) buf_printf (out, "IV_LZO_STUB=1\n"); buf_printf (out, "IV_COMP_STUB=1\n"); + buf_printf (out, "IV_COMP_STUBv2=1\n"); } } diff --git a/src/openvpn/comp.h b/src/openvpn/comp.h index 716b1c0a8df..9ed9532939c 100644 --- a/src/openvpn/comp.h +++ b/src/openvpn/comp.h @@ -43,12 +43,22 @@ #define COMP_ALG_SNAPPY 3 /* Snappy algorithm (no longer supported) */ #define COMP_ALG_LZ4 4 /* LZ4 algorithm */ + +/* algorithm v2 */ +#define COMP_ALGV2_UNCOMPRESSED 10 +#define COMP_ALGV2_LZ4 11 +/* +#define COMP_ALGV2_LZO 12 +#define COMP_ALGV2_SNAPPY 13 +*/ + /* Compression flags */ #define COMP_F_ADAPTIVE (1<<0) /* COMP_ALG_LZO only */ #define COMP_F_ASYM (1<<1) /* only downlink is compressed, not uplink */ #define COMP_F_SWAP (1<<2) /* initial command byte is swapped with last byte in buffer to preserve payload alignment */ #define COMP_F_ADVERTISE_STUBS_ONLY (1<<3) /* tell server that we only support compression stubs */ + /* * Length of prepended prefix on compressed packets */ @@ -57,9 +67,21 @@ /* * Prefix bytes */ + +/* V1 on wire codes */ +/* Initial command byte to tell our peer if we compressed */ +#define LZO_COMPRESS_BYTE 0x66 +#define LZ4_COMPRESS_BYTE 0x69 #define NO_COMPRESS_BYTE 0xFA #define NO_COMPRESS_BYTE_SWAP 0xFB /* to maintain payload alignment, replace this byte with last byte of packet */ +/* V2 on wire code */ +#define COMP_ALGV2_INDICATOR_BYTE 0x50 +#define COMP_ALGV2_UNCOMPRESSED_BYTE 0 +#define COMP_ALGV2_LZ4_BYTE 1 +#define COMP_ALGV2_LZO_BYTE 2 +#define COMP_ALGV2_SNAPPY_BYTE 3 + /* * Compress worst case size expansion (for any algorithm) * @@ -145,6 +167,7 @@ struct compress_context }; extern const struct compress_alg comp_stub_alg; +extern const struct compress_alg compv2_stub_alg; struct compress_context *comp_init(const struct compress_options *opt); @@ -157,6 +180,8 @@ void comp_print_stats (const struct compress_context *compctx, struct status_out void comp_generate_peer_info_string(const struct compress_options *opt, struct buffer *out); +void compv2_escape_data_ifneeded (struct buffer *buf); + static inline bool comp_enabled(const struct compress_options *info) { diff --git a/src/openvpn/compstub.c b/src/openvpn/compstub.c index 2ab7163edd6..9c6aad2de70 100644 --- a/src/openvpn/compstub.c +++ b/src/openvpn/compstub.c @@ -105,6 +105,57 @@ stub_decompress (struct buffer *buf, struct buffer work, } } + +static void +stubv2_compress (struct buffer *buf, struct buffer work, + struct compress_context *compctx, + const struct frame* frame) +{ + if (buf->len <= 0) + return; + + compv2_escape_data_ifneeded (buf); +} + +static void +stubv2_decompress (struct buffer *buf, struct buffer work, + struct compress_context *compctx, + const struct frame* frame) +{ + if (buf->len <= 0) + return; + + uint8_t *head = BPTR (buf); + + /* no compression or packet to short*/ + if (head[0] != COMP_ALGV2_INDICATOR_BYTE) + return; + + /* compression header (0x50) is present */ + buf_advance(buf, 1); + + /* Packet buffer too short (only 1 byte) */ + if (buf->len <= 0) + return; + + head = BPTR (buf); + buf_advance(buf, 1); + + if (head[0] != COMP_ALGV2_UNCOMPRESSED_BYTE) { + dmsg (D_COMP_ERRORS, "Bad compression stubv2 decompression header byte: %d", *head); + buf->len = 0; + return; + } +} + +const struct compress_alg compv2_stub_alg = { + "stubv2", + stub_compress_init, + stub_compress_uninit, + stubv2_compress, + stubv2_decompress +}; + const struct compress_alg comp_stub_alg = { "stub", stub_compress_init, diff --git a/src/openvpn/lzo.c b/src/openvpn/lzo.c index daa02ed0e74..25a839bad0f 100644 --- a/src/openvpn/lzo.c +++ b/src/openvpn/lzo.c @@ -42,9 +42,6 @@ #include "memdbg.h" -/* Initial command byte to tell our peer if we compressed */ -#define LZO_COMPRESS_BYTE 0x66 - /** * Perform adaptive compression housekeeping. * diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 6861149b3cb..f154c62ad09 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -6344,16 +6344,21 @@ add_option (struct options *options, VERIFY_PERMISSION (OPT_P_COMP); if (p[1]) { + options->comp.flags = 0; if (streq (p[1], "stub")) { options->comp.alg = COMP_ALG_STUB; options->comp.flags = (COMP_F_SWAP|COMP_F_ADVERTISE_STUBS_ONLY); } + else if (streq(p[1], "stub-v2")) + { + options->comp.alg = COMP_ALGV2_UNCOMPRESSED; + options->comp.flags = COMP_F_ADVERTISE_STUBS_ONLY; + } #if defined(ENABLE_LZO) else if (streq (p[1], "lzo")) { options->comp.alg = COMP_ALG_LZO; - options->comp.flags = 0; } #endif #if defined(ENABLE_LZ4) @@ -6362,6 +6367,10 @@ add_option (struct options *options, options->comp.alg = COMP_ALG_LZ4; options->comp.flags = COMP_F_SWAP; } + else if (streq (p[1], "lz4-v2")) + { + options->comp.alg = COMP_ALGV2_LZ4; + } #endif else { From 67b3de98e3b5327a9330b499d6cff179624b8ec2 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Tue, 5 Jan 2016 15:56:01 +0100 Subject: [PATCH 172/643] Fix assert when comp is called with unknown algorithm, always call comp init method Acked-by: Gert Doering Message-Id: <1452005761-5503-1-git-send-email-arne@rfc2549.org> URL: http://article.gmane.org/gmane.network.openvpn.devel/10939 Signed-off-by: Gert Doering --- src/openvpn/comp.c | 6 +++--- src/openvpn/options.c | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/openvpn/comp.c b/src/openvpn/comp.c index b420ea530da..3a32c62814d 100644 --- a/src/openvpn/comp.c +++ b/src/openvpn/comp.c @@ -48,7 +48,6 @@ comp_init(const struct compress_options *opt) ALLOC_OBJ_CLEAR (compctx, struct compress_context); compctx->flags = opt->flags; compctx->alg = comp_stub_alg; - (*compctx->alg.compress_init)(compctx); break; case COMP_ALGV2_UNCOMPRESSED: ALLOC_OBJ_CLEAR (compctx, struct compress_context); @@ -60,7 +59,6 @@ comp_init(const struct compress_options *opt) ALLOC_OBJ_CLEAR (compctx, struct compress_context); compctx->flags = opt->flags; compctx->alg = lzo_alg; - (*compctx->alg.compress_init)(compctx); break; #endif #ifdef ENABLE_LZ4 @@ -68,7 +66,6 @@ comp_init(const struct compress_options *opt) ALLOC_OBJ_CLEAR (compctx, struct compress_context); compctx->flags = opt->flags; compctx->alg = lz4_alg; - (*compctx->alg.compress_init)(compctx); break; case COMP_ALGV2_LZ4: ALLOC_OBJ_CLEAR (compctx, struct compress_context); @@ -77,6 +74,9 @@ comp_init(const struct compress_options *opt) break; #endif } + if (compctx) + (*compctx->alg.compress_init)(compctx); + return compctx; } diff --git a/src/openvpn/options.c b/src/openvpn/options.c index f154c62ad09..b710c9cdbda 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -6344,7 +6344,6 @@ add_option (struct options *options, VERIFY_PERMISSION (OPT_P_COMP); if (p[1]) { - options->comp.flags = 0; if (streq (p[1], "stub")) { options->comp.alg = COMP_ALG_STUB; @@ -6359,6 +6358,7 @@ add_option (struct options *options, else if (streq (p[1], "lzo")) { options->comp.alg = COMP_ALG_LZO; + options->comp.flags = 0; } #endif #if defined(ENABLE_LZ4) @@ -6370,6 +6370,7 @@ add_option (struct options *options, else if (streq (p[1], "lz4-v2")) { options->comp.alg = COMP_ALGV2_LZ4; + options->comp.flags = 0; } #endif else From aa416be9500441313c703ad7cb848c289378bbd3 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Wed, 6 Jan 2016 21:59:03 +0100 Subject: [PATCH 173/643] polarssl: actually use polarssl debug logging We had the machinery in place, but did not actually use it because nothing will be logged untill the debug threshold is increased. This commit makes --verb 8 result is level 2 polar logging (which is verbose, and --verb 9 result in level 3 polar logging (which is very verbose). There are higher levels, but those are extremely verbose. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1452113943-30684-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/10945 Signed-off-by: Gert Doering --- src/openvpn/ssl_polarssl.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/openvpn/ssl_polarssl.c b/src/openvpn/ssl_polarssl.c index 339d1fb194f..58b211648c8 100644 --- a/src/openvpn/ssl_polarssl.c +++ b/src/openvpn/ssl_polarssl.c @@ -49,6 +49,7 @@ #include #include "ssl_verify_polarssl.h" +#include #include #include #include @@ -679,8 +680,8 @@ static int endless_buf_write( void *ctx, const unsigned char *in, size_t len ) static void my_debug( void *ctx, int level, const char *str ) { - int my_loglevel = (level < 2) ? D_TLS_DEBUG_MED : D_TLS_DEBUG; - msg (my_loglevel, "PolarSSL alert: %s", str); + int my_loglevel = (level < 3) ? D_TLS_DEBUG_MED : D_TLS_DEBUG; + msg (my_loglevel, "PolarSSL msg: %s", str); } /* @@ -762,6 +763,7 @@ void key_state_ssl_init(struct key_state_ssl *ks_ssl, if (polar_ok(ssl_init(ks_ssl->ctx))) { /* Initialise SSL context */ + debug_set_threshold(3); ssl_set_dbg (ks_ssl->ctx, my_debug, NULL); ssl_set_endpoint (ks_ssl->ctx, ssl_ctx->endpoint); From 3a39bf7dfe5a57fe8bc43c073b2a009bb6994e78 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Thu, 7 Jan 2016 10:15:16 +0100 Subject: [PATCH 174/643] polarssl: optimize polar_ok() for non-errors Adding polar_ok() was a good plan for improving error reporting, but also added two function calls (one to polar_log_func_line() and one to polar_log_err()) for each function call wrapped with polar_ok(). Especially in the critical path, this is a waste of time. To avoid this overhead, add a simple static inline wrapper to reduce it to a single branch. v2 - use a static inline wrapper to prevent evaluating 'errval' twice in the macro. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1452158116-17363-1-git-send-email-steffan.karger@fox-it.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/10949 Signed-off-by: Gert Doering --- src/openvpn/crypto_polarssl.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/openvpn/crypto_polarssl.h b/src/openvpn/crypto_polarssl.h index bd0f8b865d9..94306eddcea 100644 --- a/src/openvpn/crypto_polarssl.h +++ b/src/openvpn/crypto_polarssl.h @@ -115,6 +115,15 @@ bool polar_log_err(unsigned int flags, int errval, const char *prefix); bool polar_log_func_line(unsigned int flags, int errval, const char *func, int line); +/** Wraps polar_log_func_line() to prevent function calls for non-errors */ +static inline bool polar_log_func_line_lite(unsigned int flags, int errval, + const char *func, int line) { + if (errval) { + return polar_log_func_line (flags, errval, func, line); + } + return true; +} + /** * Check errval and log on error. * @@ -128,7 +137,7 @@ bool polar_log_func_line(unsigned int flags, int errval, const char *func, * @returns true if no errors are detected, false otherwise. */ #define polar_ok(errval) \ - polar_log_func_line(D_CRYPT_ERRORS, errval, __func__, __LINE__) + polar_log_func_line_lite(D_CRYPT_ERRORS, errval, __func__, __LINE__) #endif /* CRYPTO_POLARSSL_H_ */ From 0609eb477bdcd7b23bd8072f69714592323cab2e Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Thu, 7 Jan 2016 20:52:44 +0100 Subject: [PATCH 175/643] Update manpage: OpenSSL might also need /dev/urandom inside chroot As reported in trac ticket #646, OpenSSL might also need /dev/urandom to be available in the chroot. This depends on OS, OS version and ssl library configuration. Update the manpage to better explain this. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1452196364-18786-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/10954 Signed-off-by: Gert Doering --- doc/openvpn.8 | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 368bd4c2b08..9760e8b9b03 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -2139,15 +2139,12 @@ parameter can point to an empty directory, however complications can result when scripts or restarts are executed after the chroot operation. -Note: if OpenVPN is built using the PolarSSL SSL -library, -.B \-\-chroot -will only work if a /dev/urandom device node is available -inside the chroot directory +Note: The SSL library will probably need /dev/urandom to be available inside +the chroot directory .B dir. -This is due to the way PolarSSL works (it wants to open -/dev/urandom every time randomness is needed, not just once -at startup) and nothing OpenVPN can influence. +This is because SSL libraries occasionally need to collect fresh random. Newer +linux kernels and some BSDs implement a getrandom() or getentropy() syscall +that removes the need for /dev/urandom to be available. .\"********************************************************* .TP .B \-\-setcon context From 072fdcd00688d2d16d17745fb7d7b385795d5de1 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Thu, 7 Jan 2016 21:22:12 +0100 Subject: [PATCH 176/643] polarssl: use wrappers to access md_info_t member functions The md_info_t will become an opaque struct in mbed TLS 2.x, start using the wrapper function in preparation to a future upgrade to 2.x. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1452198132-25560-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/10955 Signed-off-by: Gert Doering --- src/openvpn/crypto_polarssl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/openvpn/crypto_polarssl.c b/src/openvpn/crypto_polarssl.c index 92fdb787acc..f0ad81a0733 100644 --- a/src/openvpn/crypto_polarssl.c +++ b/src/openvpn/crypto_polarssl.c @@ -214,7 +214,7 @@ show_available_digests () if (info) printf ("%s %d bit default key\n", - info->name, info->size * 8); + md_get_name(info), md_get_size(info) * 8); digests++; } printf ("\n"); @@ -578,10 +578,10 @@ md_kt_get (const char *digest) md = md_info_from_string(digest); if (!md) msg (M_FATAL, "Message hash algorithm '%s' not found", digest); - if (md->size > MAX_HMAC_KEY_LENGTH) + if (md_get_size(md) > MAX_HMAC_KEY_LENGTH) msg (M_FATAL, "Message hash algorithm '%s' uses a default hash size (%d bytes) which is larger than " PACKAGE_NAME "'s current maximum hash size (%d bytes)", digest, - md->size, + md_get_size(md), MAX_HMAC_KEY_LENGTH); return md; } From 52012d651624f870e9dd1587c5fbf324d392dcf8 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Thu, 7 Jan 2016 21:24:33 +0100 Subject: [PATCH 177/643] polarssl: remove now redundant 128-bit blowfish key override As of 1.3.0, polarssl/mbedtls now by default uses a 128 bit key for the blowfish cipher (as opposed to the 32-bit (!) default they had previously). Since we require polar 1.3+, we no longer need this fixup code. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1452198273-26493-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/10956 Signed-off-by: Gert Doering --- src/openvpn/crypto_polarssl.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/openvpn/crypto_polarssl.c b/src/openvpn/crypto_polarssl.c index f0ad81a0733..407a1769dac 100644 --- a/src/openvpn/crypto_polarssl.c +++ b/src/openvpn/crypto_polarssl.c @@ -415,8 +415,6 @@ cipher_kt_key_size (const cipher_info_t *cipher_kt) { if (NULL == cipher_kt) return 0; - if (POLARSSL_CIPHER_ID_BLOWFISH == cipher_kt->base->cipher) - return 128/8; /* Override PolarSSL 32 bit default key size with sane 128 bit default */ return cipher_kt->key_length/8; } From 36f3a479a7d5ab01c30e8ca1a99bd2430b30893f Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Thu, 10 Dec 2015 13:37:15 +0100 Subject: [PATCH 178/643] Ignore stamp-h2 we generate during build process Acked-by: Gert Doering Message-Id: <1449751035-10757-1-git-send-email-arne@rfc2549.org> URL: http://article.gmane.org/gmane.network.openvpn.devel/10721 Signed-off-by: Gert Doering --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 0403ae86556..e154092f29e 100644 --- a/.gitignore +++ b/.gitignore @@ -59,3 +59,4 @@ config-version.h nbproject test-driver compile +stamp-h2 From 982ab2364a68f2fca0cb9219b31bdabcd5aa4b49 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Wed, 13 Jan 2016 17:09:08 +0100 Subject: [PATCH 179/643] socks.c: fix check on get_user_pass() return value(s) My compiler rightfully complains that the checks on creds.username and creds.password always evaluate to true, so remove those checks. Judging from the code, they were meant to check the returned values by get_user_pass(). So instead of these non-functioning checks, just check the return value of get_user_pass(). Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1452701348-9577-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/10993 Signed-off-by: Gert Doering --- src/openvpn/socks.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/openvpn/socks.c b/src/openvpn/socks.c index 72bdf55033d..cef7a35e7f2 100644 --- a/src/openvpn/socks.c +++ b/src/openvpn/socks.c @@ -103,10 +103,13 @@ socks_username_password_auth (struct socks_proxy_info *p, ssize_t size; creds.defined = 0; - get_user_pass (&creds, p->authfile, UP_TYPE_SOCKS, GET_USER_PASS_MANAGEMENT); + if (!get_user_pass (&creds, p->authfile, UP_TYPE_SOCKS, GET_USER_PASS_MANAGEMENT)) + { + msg (M_NONFATAL, "SOCKS failed to get username/password."); + return false; + } - if( !creds.username || (strlen(creds.username) > 255) - || !creds.password || (strlen(creds.password) > 255) ) { + if( (strlen(creds.username) > 255) || (strlen(creds.password) > 255) ) { msg (M_NONFATAL, "SOCKS username and/or password exceeds 255 characters. " "Authentication not possible."); From 9dfc2309c6b4143892137844197f5f84755f6580 Mon Sep 17 00:00:00 2001 From: Niels Ole Salscheider Date: Sun, 10 Jan 2016 14:44:35 +0100 Subject: [PATCH 180/643] Fix build with libressl Signed-off-by: Niels Ole Salscheider Acked-by: Steffan Karger Message-Id: <1452433475-16779-1-git-send-email-niels_ole@salscheider-online.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/10975 Signed-off-by: Gert Doering --- src/openvpn/ssl_openssl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c index d2f40e7788d..e390f4d0e4a 100644 --- a/src/openvpn/ssl_openssl.c +++ b/src/openvpn/ssl_openssl.c @@ -358,7 +358,7 @@ tls_ctx_check_cert_time (const struct tls_root_ctx *ctx) ASSERT (ctx); -#if OPENSSL_VERSION_NUMBER >= 0x10002000L +#if OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(LIBRESSL_VERSION_NUMBER) /* OpenSSL 1.0.2 and up */ cert = SSL_CTX_get0_certificate (ctx->ctx); #else @@ -393,7 +393,7 @@ tls_ctx_check_cert_time (const struct tls_root_ctx *ctx) } cleanup: -#if OPENSSL_VERSION_NUMBER < 0x10002000L +#if OPENSSL_VERSION_NUMBER < 0x10002000L || defined(LIBRESSL_VERSION_NUMBER) SSL_free (ssl); #endif return; From 651591525ee933c69f442d51d2b6064f2893181d Mon Sep 17 00:00:00 2001 From: ValdikSS Date: Sat, 9 Jan 2016 18:53:45 +0300 Subject: [PATCH 181/643] Clarify mssfix documentation Acked-by: Jan Just Keijser Message-Id: <1452354825-5096-1-git-send-email-iam@valdikss.org.ru> URL: http://article.gmane.org/gmane.network.openvpn.devel/10969 Signed-off-by: Gert Doering --- doc/openvpn.8 | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 9760e8b9b03..ef77b29c180 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -1381,7 +1381,11 @@ parameter is interpreted in the same way as the .B \-\-link\-mtu parameter, i.e. the UDP packet size after encapsulation overhead has been added in, but not including -the UDP header itself. +the UDP header itself. Resulting packet would be at most 28 +bytes larger for IPv4 and 48 bytes for IPv6 (20/40 bytes for IP +header and 8 bytes for UDP header). Default value of 1450 allows +IPv4 packets to be transmitted over a link with MTU 1473 or higher +without IP level fragmentation. The .B \-\-mssfix From cc4761fcafdeceea1a4b004f91c9fb47ef8b19c1 Mon Sep 17 00:00:00 2001 From: ValdikSS Date: Sat, 16 Jan 2016 17:05:26 +0300 Subject: [PATCH 182/643] Clarify --block-outside-dns documentation Acked-by: Gert Doering Message-Id: <1452953126-6283-1-git-send-email-iam@valdikss.org.ru> URL: http://article.gmane.org/gmane.network.openvpn.devel/11001 Signed-off-by: Gert Doering --- doc/openvpn.8 | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index ef77b29c180..76650e96aa4 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -5575,6 +5575,16 @@ DNS leaks. This option prevents any application from accessing TCP or UDP port 53 except one inside the tunnel. It uses Windows Filtering Platform (WFP) and works on Windows Vista or later. + +This option is considered unknown on non-Windows platforms +and unsupported on Windows XP, resulting in fatal error. +You may want to use +.B \-\-setenv opt +or +.B \-\-ignore\-unknown\-option +(not suitable for Windows XP) to ignore said error. +Note that pushing unknown options from server does not trigger +fatal errors. .\"********************************************************* .TP .B \-\-dhcp\-renew From 31b0bebef61413151af9ded55aa985798d4f7666 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sun, 10 Jan 2016 15:37:19 +0100 Subject: [PATCH 183/643] configure.ac: simplify crypto library configuration This reworks the crypto library configuration, to make it both simpler to understand and more usable: * Only check for OpenSSL when building against OpenSSL (and similar for PolarSSL/mbed TLS). * Bail out early if a problem with the library is detected. * Set CRYPTO_{LIBS,FLAGS} immediately after the crypto library checks, removing the need for an extra switch-case later on. * We no longer support building openvpn with crypto but without ssl, so we can also simplify the logic in configure.ac accordingly. As a 'side effect' (this actually triggered me), this fixes a bug that would cause a user-specified OPENSSL_{CRYPTO,SSL}_LIBS to be overwritten by AC_CHECK_LIB if there are openssl headers available in the PATH. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1452436639-16838-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/10978 Signed-off-by: Gert Doering --- Changes.rst | 8 +++ INSTALL | 12 ++--- configure.ac | 148 +++++++++++++++++++++++---------------------------- 3 files changed, 78 insertions(+), 90 deletions(-) diff --git a/Changes.rst b/Changes.rst index f27d7f048f2..dd9b9b2c26d 100644 --- a/Changes.rst +++ b/Changes.rst @@ -78,3 +78,11 @@ User-visible Changes - Removed --enable-password-save from configure. This option is now always enabled. + +Maintainer-visible changes +-------------------------- +- OpenVPN no longer supports building with crypto support, but without TLS + support. As a consequence, OPENSSL_CRYPTO_{CFLAGS,LIBS} and + OPENSSL_SSL_{CFLAGS,LIBS} have been merged into OPENSSL_{CFLAGS,LIBS}. This + is particularly relevant for maintainers who build their own OpenSSL library, + e.g. when cross-compiling. diff --git a/INSTALL b/INSTALL index 2ef7904ba58..2401f7ca9bd 100644 --- a/INSTALL +++ b/INSTALL @@ -210,14 +210,10 @@ ENVIRONMENT for ./configure: MAN2HTML path to man2html utility GIT path to git utility TAP_CFLAGS C compiler flags for tap - OPENSSL_CRYPTO_CFLAGS - C compiler flags for OPENSSL_CRYPTO, overriding pkg-config - OPENSSL_CRYPTO_LIBS - linker flags for OPENSSL_CRYPTO, overriding pkg-config - OPENSSL_SSL_CFLAGS - C compiler flags for OPENSSL_SSL, overriding pkg-config - OPENSSL_SSL_LIBS - linker flags for OPENSSL_SSL, overriding pkg-config + OPENSSL_CFLAGS + C compiler flags for OpenSSL, overriding pkg-config + OPENSSL_LIBS + linker flags for OpenSSL, overriding pkg-config POLARSSL_CFLAGS C compiler flags for polarssl POLARSSL_LIBS diff --git a/configure.ac b/configure.ac index 4b2eb01d739..73dd0325a7c 100644 --- a/configure.ac +++ b/configure.ac @@ -781,42 +781,32 @@ PKG_CHECK_MODULES( [] ) -PKG_CHECK_MODULES( - [OPENSSL_CRYPTO], - [libcrypto >= 0.9.8], - [have_openssl_crypto="yes"], - [AC_CHECK_LIB( - [crypto], - [RSA_new], - [ - have_openssl_crypto="yes" - OPENSSL_CRYPTO_LIBS="-lcrypto" - ] - )] -) +if test "${with_crypto_library}" = "openssl"; then + AC_ARG_VAR([OPENSSL_CFLAGS], [C compiler flags for OpenSSL]) + AC_ARG_VAR([OPENSSL_LIBS], [linker flags for OpenSSL]) + + if test -z "${OPENSSL_CFLAGS}" -a -z "${OPENSSL_LIBS}"; then + # if the user did not explicitly specify flags, try to autodetect + PKG_CHECK_MODULES( + [OPENSSL], + [libcrypto >= 0.9.8, libssl >= 0.9.8], + [have_openssl="yes"], + [have_openssl="no"] # Provide if-not-found to prevent erroring out + ) -PKG_CHECK_MODULES( - [OPENSSL_SSL], - [libssl >= 0.9.8], - [have_openssl_ssl="yes"], - [AC_CHECK_LIB( - [ssl], - [SSL_CTX_new], - [ - have_openssl_ssl="yes" - OPENSSL_SSL_LIBS="-lssl" - ], - [], - [-lcrypto] - )] -) + OPENSSL_LIBS=${OPENSSL_LIBS:--lssl -lcrypto} + fi -if test "${have_openssl_crypto}" = "yes"; then saved_CFLAGS="${CFLAGS}" saved_LIBS="${LIBS}" - CFLAGS="${CFLAGS} ${OPENSSL_CRYPTO_CFLAGS}" - LIBS="${LIBS} ${OPENSSL_CRYPTO_LIBS}" - AC_CHECK_FUNCS([EVP_CIPHER_CTX_set_key_length]) + CFLAGS="${CFLAGS} ${OPENSSL_CFLAGS}" + LIBS="${LIBS} ${OPENSSL_LIBS}" + + AC_CHECK_FUNCS([SSL_CTX_new EVP_CIPHER_CTX_set_key_length], + , + [AC_MSG_ERROR([openssl check failed])] + ) + have_openssl_engine="yes" AC_CHECK_FUNCS( [ \ @@ -827,38 +817,45 @@ if test "${have_openssl_crypto}" = "yes"; then , [have_openssl_engine="no"; break] ) + if test "${have_openssl_engine}" = "yes"; then + AC_DEFINE([HAVE_OPENSSL_ENGINE], [1], [OpenSSL engine support available]) + fi CFLAGS="${saved_CFLAGS}" LIBS="${saved_LIBS}" -fi -AC_ARG_VAR([POLARSSL_CFLAGS], [C compiler flags for polarssl]) -AC_ARG_VAR([POLARSSL_LIBS], [linker flags for polarssl]) -have_polarssl_ssl="yes" -have_polarssl_crypto="yes" -if test -z "${POLARSSL_LIBS}"; then - AC_CHECK_LIB( - [polarssl], - [ssl_init], - [POLARSSL_LIBS="-lpolarssl"], - [ - have_polarssl_ssl="no" - AC_CHECK_LIB( - [polarssl], - [aes_crypt_cbc], - , - [have_polarssl_crypto="no"], - [${PKCS11_HELPER_LIBS}] - ) - ], - [${PKCS11_HELPER_LIBS}] - ) -fi + have_crypto="yes" + AC_DEFINE([ENABLE_CRYPTO_OPENSSL], [1], [Use OpenSSL library]) + CRYPTO_CFLAGS="${OPENSSL_CFLAGS}" + CRYPTO_LIBS="${OPENSSL_LIBS}" +elif test "${with_crypto_library}" = "polarssl"; then + AC_ARG_VAR([POLARSSL_CFLAGS], [C compiler flags for polarssl]) + AC_ARG_VAR([POLARSSL_LIBS], [linker flags for polarssl]) + + if test -z "${POLARSSL_CFLAGS}" -a -z "${POLARSSL_LIBS}"; then + # if the user did not explicitly specify flags, try to autodetect + AC_SEARCH_LIBS( + [ssl_init], + [mbedtls], + [POLARSSL_LIBS=-lmbedtls] + [ + AC_SEARCH_LIBS( + [ssl_init], + [polarssl], + [POLARSSL_LIBS=-lpolarssl] + [], + [${PKCS11_HELPER_LIBS}] + ) + ], + [${PKCS11_HELPER_LIBS}] + ) + fi -if test "${with_crypto_library}" = "polarssl" ; then AC_MSG_CHECKING([polarssl version]) - old_CFLAGS="${CFLAGS}" - CFLAGS="${POLARSSL_CFLAGS} ${CFLAGS}" + saved_CFLAGS="${CFLAGS}" + saved_LIBS="${LIBS}" + CFLAGS="${POLARSSL_CFLAGS} ${PKCS11_HELPER_CFLAGS} ${CFLAGS}" + LIBS="${POLARSSL_LIBS} ${PKCS11_HELPER_LIBS} ${LIBS}" AC_COMPILE_IFELSE( [AC_LANG_PROGRAM( [[ @@ -887,7 +884,6 @@ if test "${with_crypto_library}" = "polarssl" ; then ]] )], polarssl_with_pkcs11="yes") - CFLAGS="${old_CFLAGS}" AC_MSG_CHECKING([polarssl pkcs11 support]) if test "${enable_pkcs11}" = "yes"; then @@ -903,7 +899,15 @@ if test "${with_crypto_library}" = "polarssl" ; then AC_MSG_ERROR([PolarSSL compiled with PKCS11, while OpenVPN is not]) fi fi + CFLAGS="${saved_CFLAGS}" + LIBS="${saved_LIBS}" + have_crypto="yes" + AC_DEFINE([ENABLE_CRYPTO_POLARSSL], [1], [Use PolarSSL library]) + CRYPTO_CFLAGS="${POLARSSL_CFLAGS}" + CRYPTO_LIBS="${POLARSSL_LIBS}" +else + AC_MSG_ERROR([Invalid crypto library: ${with_crypto_library}]) fi AC_ARG_VAR([LZO_CFLAGS], [C compiler flags for lzo]) @@ -1049,31 +1053,11 @@ test "${enable_def_auth}" = "yes" && AC_DEFINE([ENABLE_DEF_AUTH], [1], [Enable d test "${enable_pf}" = "yes" && AC_DEFINE([ENABLE_PF], [1], [Enable internal packet filter]) test "${enable_strict_options}" = "yes" && AC_DEFINE([ENABLE_STRICT_OPTIONS_CHECK], [1], [Enable strict options check between peers]) -case "${with_crypto_library}" in - openssl) - have_crypto_crypto="${have_openssl_crypto}" - have_crypto_ssl="${have_openssl_ssl}" - CRYPTO_CRYPTO_CFLAGS="${OPENSSL_CRYPTO_CFLAGS}" - CRYPTO_CRYPTO_LIBS="${OPENSSL_CRYPTO_LIBS}" - CRYPTO_SSL_CFLAGS="${OPENSSL_SSL_CFLAGS}" - CRYPTO_SSL_LIBS="${OPENSSL_SSL_LIBS}" - AC_DEFINE([ENABLE_CRYPTO_OPENSSL], [1], [Use OpenSSL library]) - test "${have_openssl_engine}" = "yes" && AC_DEFINE([HAVE_OPENSSL_ENGINE], [1], [Use crypto library]) - ;; - polarssl) - have_crypto_crypto="${have_polarssl_crypto}" - have_crypto_ssl="${have_polarssl_ssl}" - CRYPTO_CRYPTO_CFLAGS="${POLARSSL_CFLAGS}" - CRYPTO_CRYPTO_LIBS="${POLARSSL_LIBS}" - AC_DEFINE([ENABLE_CRYPTO_POLARSSL], [1], [Use PolarSSL library]) - ;; -esac - if test "${enable_crypto}" = "yes"; then - test "${have_crypto_crypto}" != "yes" && AC_MSG_ERROR([${with_crypto_library} crypto is required but missing]) + test "${have_crypto}" != "yes" && AC_MSG_ERROR([${with_crypto_library} crypto is required but missing]) test "${enable_crypto_ofb_cfb}" = "yes" && AC_DEFINE([ENABLE_OFB_CFB_MODE], [1], [Enable OFB and CFB cipher modes]) - OPTIONAL_CRYPTO_CFLAGS="${OPTIONAL_CRYPTO_CFLAGS} ${CRYPTO_CRYPTO_CFLAGS} ${CRYPTO_SSL_CFLAGS}" - OPTIONAL_CRYPTO_LIBS="${OPTIONAL_CRYPTO_LIBS} ${CRYPTO_SSL_LIBS} ${CRYPTO_CRYPTO_LIBS}" + OPTIONAL_CRYPTO_CFLAGS="${OPTIONAL_CRYPTO_CFLAGS} ${CRYPTO_CFLAGS}" + OPTIONAL_CRYPTO_LIBS="${OPTIONAL_CRYPTO_LIBS} ${CRYPTO_LIBS}" AC_DEFINE([ENABLE_CRYPTO], [1], [Enable crypto library]) fi From 417fe4a72c82accca8d95fb0488427f5b6dc4157 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Mon, 18 Jan 2016 21:49:40 +0100 Subject: [PATCH 184/643] configure.ac: fix polarssl autodetection A missing , in the previous configure.ac patch caused the autodetection to fail. While fixing that, I noticed I can simplify the check by using the documented ${ac_cv_search_function} cache variable instead of the nested AC_SEARCH_LIBS. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1453150181-21453-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/11010 Signed-off-by: Gert Doering --- configure.ac | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/configure.ac b/configure.ac index 73dd0325a7c..7ff2435ac95 100644 --- a/configure.ac +++ b/configure.ac @@ -832,30 +832,28 @@ elif test "${with_crypto_library}" = "polarssl"; then AC_ARG_VAR([POLARSSL_CFLAGS], [C compiler flags for polarssl]) AC_ARG_VAR([POLARSSL_LIBS], [linker flags for polarssl]) + saved_CFLAGS="${CFLAGS}" + saved_LIBS="${LIBS}" + if test -z "${POLARSSL_CFLAGS}" -a -z "${POLARSSL_LIBS}"; then # if the user did not explicitly specify flags, try to autodetect AC_SEARCH_LIBS( [ssl_init], - [mbedtls], - [POLARSSL_LIBS=-lmbedtls] + [mbedtls polarssl], [ - AC_SEARCH_LIBS( - [ssl_init], - [polarssl], - [POLARSSL_LIBS=-lpolarssl] - [], - [${PKCS11_HELPER_LIBS}] - ) + if test "${ac_cv_search_ssl_init}" != "none required"; then + POLARSSL_LIBS=${ac_cv_search_ssl_init} + fi ], + [AC_MSG_ERROR([Could not find PolarSSL/mbed TLS.])], [${PKCS11_HELPER_LIBS}] ) fi - AC_MSG_CHECKING([polarssl version]) - saved_CFLAGS="${CFLAGS}" - saved_LIBS="${LIBS}" CFLAGS="${POLARSSL_CFLAGS} ${PKCS11_HELPER_CFLAGS} ${CFLAGS}" LIBS="${POLARSSL_LIBS} ${PKCS11_HELPER_LIBS} ${LIBS}" + + AC_MSG_CHECKING([polarssl version]) AC_COMPILE_IFELSE( [AC_LANG_PROGRAM( [[ From d4d5d9259aeba152d5969fea048267fc97ca7530 Mon Sep 17 00:00:00 2001 From: Michael McConville Date: Tue, 2 Feb 2016 14:11:22 -0500 Subject: [PATCH 185/643] Fix undefined signed shift overflow Originally discussed here: https://github.com/OpenVPN/openvpn/pull/42 Thanks for your time, Michael Acked-by: Gert Doering Message-Id: <20160202191122.GE1675@thinkpad.swarthmore.edu> URL: http://article.gmane.org/gmane.network.openvpn.devel/11050 Signed-off-by: Gert Doering --- src/openvpn/route.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/openvpn/route.c b/src/openvpn/route.c index 2012b5c0f5e..f4dee78d19a 100644 --- a/src/openvpn/route.c +++ b/src/openvpn/route.c @@ -3128,7 +3128,8 @@ get_default_gateway (struct route_gateway_info *rgi) struct gc_arena gc = gc_new (); struct rtmsg m_rtmsg; int sockfd = -1; - int seq, l, pid, rtm_addrs, i; + int seq, l, pid, rtm_addrs; + unsigned int i; struct sockaddr so_dst, so_mask; char *cp = m_rtmsg.m_space; struct sockaddr *gate = NULL, *ifp = NULL, *sa; @@ -3330,7 +3331,8 @@ get_default_gateway_ipv6(struct route_ipv6_gateway_info *rgi6, struct rtmsg m_rtmsg; int sockfd = -1; - int seq, l, pid, rtm_addrs, i; + int seq, l, pid, rtm_addrs; + unsigned int i; struct sockaddr_in6 so_dst, so_mask; char *cp = m_rtmsg.m_space; struct sockaddr *gate = NULL, *ifp = NULL, *sa; From a24dd2e31f196c76594666f37c130817402acb15 Mon Sep 17 00:00:00 2001 From: Heiko Hund Date: Tue, 26 Jan 2016 20:11:48 +0100 Subject: [PATCH 186/643] interactive service v3 v1: Heiko Hund - Message-ID: <2215306.x9ci9DhAZ9@de-gn-40970> - extend openvpn service to provide "automatic service" and "interactive service" (which is used by GUI and OpenVPN to run openvpn non-privileged and still be able to install routes and configure IPv6 addresses) - add --msg-channel option to openvpn to tell it which pipe to use to talk to the interactive service (used in tun.c for ifconfig + ARP flush, and route.c for routing) - add openvpn-msg.h with message definitions for talking to interactive service - routing in openvpn uses message-pipe automatically if --msg-channel is configured, no other option needed - today, the integration in route.c and tun.c is windows-only, but could be adapted to other platforms v2: Steffan Karger - Message-ID: <548D9046.5000600@karger.me> - include "openvpn-msg.h" not "include/openvpn-msg.h" - add $(top_srcdir)/include to openvpnsrv build for out-of-tree builds v3: Gert Doering, rebasing and integrating review feedback - rebased to 417fe4a72c - r->metric_defined is now r->flags & RT_METRIC_DEFINED (c3ef2d2333fb) - move "openvpn-msg.h" include inside #ifdef WIN32 (windows-only right now) - hide "msg_channel" extra option inside tt->tuntap_options, so we do not need an extra argument to all the add/del_route...() functions - do_route_ipv6_service(): use r->adapter index (if set) for RGI6 routes Signed-off-by: Heiko Hund Signed-off-by: Gert Doering Acked-by: Selva Nair (Service changes) Acked-by: Arne Schwabe (OpenVPN changes) Message-Id: <1453835508-26119-1-git-send-email-gert@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/11027 Signed-off-by: Gert Doering --- include/Makefile.am | 4 +- include/openvpn-msg.h | 108 +++ src/openvpn/buffer.c | 2 +- src/openvpn/init.c | 6 + src/openvpn/options.c | 18 + src/openvpn/options.h | 1 + src/openvpn/route.c | 317 +++++--- src/openvpn/route.h | 1 + src/openvpn/tun.c | 171 ++++- src/openvpn/tun.h | 4 + src/openvpnserv/Makefile.am | 14 +- src/openvpnserv/automatic.c | 415 +++++++++++ src/openvpnserv/common.c | 211 ++++++ src/openvpnserv/interactive.c | 1272 +++++++++++++++++++++++++++++++++ src/openvpnserv/openvpnserv.c | 534 -------------- src/openvpnserv/service.c | 861 ++++++---------------- src/openvpnserv/service.h | 213 +++--- 17 files changed, 2703 insertions(+), 1449 deletions(-) create mode 100644 include/openvpn-msg.h create mode 100644 src/openvpnserv/automatic.c create mode 100644 src/openvpnserv/common.c create mode 100644 src/openvpnserv/interactive.c delete mode 100755 src/openvpnserv/openvpnserv.c diff --git a/include/Makefile.am b/include/Makefile.am index c5a91b1fb8c..498b3b54d56 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -13,4 +13,6 @@ MAINTAINERCLEANFILES = \ $(srcdir)/Makefile.in \ $(srcdir)/openvpn-plugin.h.in -include_HEADERS = openvpn-plugin.h +include_HEADERS = \ + openvpn-plugin.h \ + openvpn-msg.h diff --git a/include/openvpn-msg.h b/include/openvpn-msg.h new file mode 100644 index 00000000000..0dcc72fa915 --- /dev/null +++ b/include/openvpn-msg.h @@ -0,0 +1,108 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single TCP/UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2013 Heiko Hund + * + * 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 OPENVPN_MSG_H_ +#define OPENVPN_MSG_H_ + +typedef enum { + msg_acknowledgement, + msg_add_address, + msg_del_address, + msg_add_route, + msg_del_route, + msg_add_dns_cfg, + msg_del_dns_cfg, + msg_add_nbt_cfg, + msg_del_nbt_cfg, + msg_flush_neighbors +} message_type_t; + +typedef struct { + message_type_t type; + size_t size; + int message_id; +} message_header_t; + +typedef union { + struct in_addr ipv4; + struct in6_addr ipv6; +} inet_address_t; + +typedef struct { + int index; + char name[256]; +} interface_t; + +typedef struct { + message_header_t header; + short family; + inet_address_t address; + int prefix_len; + interface_t iface; +} address_message_t; + +typedef struct { + message_header_t header; + short family; + inet_address_t prefix; + int prefix_len; + inet_address_t gateway; + interface_t iface; + int metric; +} route_message_t; + +typedef struct { + message_header_t header; + interface_t iface; + char domains[512]; + struct in_addr primary_ipv4; + struct in_addr secondary_ipv4; + struct in_addr6 primary_ipv6; + struct in_addr6 secondary_ipv6; +} dns_cfg_message_t; + +typedef struct { + message_header_t header; + interface_t iface; + int disable_nbt; + int nbt_type; + char scope_id[256]; + struct in_addr primary_nbns; + struct in_addr secondary_nbns; +} nbt_cfg_message_t; + +// TODO: NTP + +typedef struct { + message_header_t header; + short family; + interface_t iface; +} flush_neighbors_message_t; + +typedef struct { + message_header_t header; + int error_number; +} ack_message_t; + +#endif diff --git a/src/openvpn/buffer.c b/src/openvpn/buffer.c index 421d60e94ec..bc67d6503ab 100644 --- a/src/openvpn/buffer.c +++ b/src/openvpn/buffer.c @@ -254,7 +254,7 @@ buf_puts(struct buffer *buf, const char *str) * * Return false on overflow. * - * This function is duplicated into service-win32/openvpnserv.c + * This functionality is duplicated in src/openvpnserv/common.c * Any modifications here should be done to the other place as well. */ diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 2beec72203f..d0020b76bb7 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -1433,6 +1433,12 @@ do_open_tun (struct context *c) /* initialize (but do not open) tun/tap object */ do_init_tun (c); +#ifdef WIN32 + /* store (hide) interactive service handle in tuntap_options */ + c->c1.tuntap->options.msg_channel = c->options.msg_channel; + msg (D_ROUTE, "interactive service msg_channel=%u", (unsigned int) c->options.msg_channel); +#endif + /* allocate route list structure */ do_alloc_route_list (c); diff --git a/src/openvpn/options.c b/src/openvpn/options.c index b710c9cdbda..6d97b4f74c1 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -6015,6 +6015,24 @@ add_option (struct options *options, } #endif #endif + else if (streq (p[0], "msg-channel") && p[1]) + { +#ifdef WIN32 + VERIFY_PERMISSION (OPT_P_GENERAL); + HANDLE process = GetCurrentProcess (); + HANDLE handle = (HANDLE) atoi (p[1]); + if (!DuplicateHandle (process, handle, process, &options->msg_channel, 0, + FALSE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) + { + msg (msglevel, "could not duplicate service pipe handle"); + goto err; + } + options->route_method = ROUTE_METHOD_SERVICE; +#else + msg (msglevel, "--msg-channel is only supported on Windows"); + goto err; +#endif + } #ifdef WIN32 else if (streq (p[0], "win-sys") && p[1] && !p[2]) { diff --git a/src/openvpn/options.h b/src/openvpn/options.h index 9e8a6a052c0..23d3992e0ef 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -581,6 +581,7 @@ struct options int foreign_option_index; #ifdef WIN32 + HANDLE msg_channel; const char *exit_event_name; bool exit_event_initial_state; bool show_net_up; diff --git a/src/openvpn/route.c b/src/openvpn/route.c index f4dee78d19a..a90195f4bf9 100644 --- a/src/openvpn/route.c +++ b/src/openvpn/route.c @@ -50,7 +50,13 @@ #endif #ifdef WIN32 +#include "openvpn-msg.h" + #define METRIC_NOT_USED ((DWORD)-1) +static bool add_route_service (const struct route_ipv4 *, const struct tuntap *); +static bool del_route_service (const struct route_ipv4 *, const struct tuntap *); +static bool add_route_ipv6_service (const struct route_ipv6 *, const struct tuntap *); +static bool del_route_ipv6_service (const struct route_ipv6 *, const struct tuntap *); #endif static void delete_route (struct route_ipv4 *r, const struct tuntap *tt, unsigned int flags, const struct route_gateway_info *rgi, const struct env_set *es); @@ -1468,7 +1474,12 @@ add_route (struct route_ipv4 *r, argv_msg (D_ROUTE, &argv); - if ((flags & ROUTE_METHOD_MASK) == ROUTE_METHOD_IPAPI) + if ((flags & ROUTE_METHOD_MASK) == ROUTE_METHOD_SERVICE) + { + status = add_route_service (r, tt); + msg (D_ROUTE, "Route addition via service %s", status ? "succeeded" : "failed"); + } + else if ((flags & ROUTE_METHOD_MASK) == ROUTE_METHOD_IPAPI) { status = add_route_ipapi (r, tt, ai); msg (D_ROUTE, "Route addition via IPAPI %s", status ? "succeeded" : "failed"); @@ -1637,26 +1648,23 @@ add_route (struct route_ipv4 *r, } -static const char * -print_in6_addr_netbits_only( struct in6_addr network_copy, int netbits, - struct gc_arena * gc) +static void +route_ipv6_clear_host_bits( struct route_ipv6 *r6 ) { /* clear host bit parts of route * (needed if routes are specified improperly, or if we need to * explicitely setup/clear the "connected" network routes on some OSes) */ int byte = 15; - int bits_to_clear = 128 - netbits; + int bits_to_clear = 128 - r6->netbits; while( byte >= 0 && bits_to_clear > 0 ) { if ( bits_to_clear >= 8 ) - { network_copy.s6_addr[byte--] = 0; bits_to_clear -= 8; } + { r6->network.s6_addr[byte--] = 0; bits_to_clear -= 8; } else - { network_copy.s6_addr[byte--] &= (0xff << bits_to_clear); bits_to_clear = 0; } + { r6->network.s6_addr[byte--] &= (0xff << bits_to_clear); bits_to_clear = 0; } } - - return print_in6_addr( network_copy, 0, gc); } void @@ -1687,7 +1695,9 @@ add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int fla gc_init (&gc); argv_init (&argv); - network = print_in6_addr_netbits_only( r6->network, r6->netbits, &gc); + route_ipv6_clear_host_bits (r6); + + network = print_in6_addr( r6->network, 0, &gc); gateway = print_in6_addr( r6->gateway, 0, &gc); #if defined(TARGET_DARWIN) || \ @@ -1770,51 +1780,56 @@ add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int fla #elif defined (WIN32) - struct buffer out = alloc_buf_gc (64, &gc); - if ( r6->adapter_index ) /* vpn server special route */ - { - buf_printf (&out, "interface=%d", r6->adapter_index ); - gateway_needed = true; - } + if (tt->options.msg_channel) + status = add_route_ipv6_service (r6, tt); else { - buf_printf (&out, "interface=%d", tt->adapter_index ); - } - device = buf_bptr(&out); - - /* netsh interface ipv6 add route 2001:db8::/32 MyTunDevice */ - argv_printf (&argv, "%s%sc interface ipv6 add route %s/%d %s", - get_win_sys_path(), - NETSH_PATH_SUFFIX, - network, - r6->netbits, - device); + struct buffer out = alloc_buf_gc (64, &gc); + if ( r6->adapter_index ) /* vpn server special route */ + { + buf_printf (&out, "interface=%d", r6->adapter_index ); + gateway_needed = true; + } + else + { + buf_printf (&out, "interface=%d", tt->adapter_index ); + } + device = buf_bptr(&out); - /* next-hop depends on TUN or TAP mode: - * - in TAP mode, we use the "real" next-hop - * - in TUN mode we use a special-case link-local address that the tapdrvr - * knows about and will answer ND (neighbor discovery) packets for - */ - if ( tt->type == DEV_TYPE_TUN && !gateway_needed ) - argv_printf_cat( &argv, " %s", "fe80::8" ); - else if ( !IN6_IS_ADDR_UNSPECIFIED(&r6->gateway) ) - argv_printf_cat( &argv, " %s", gateway ); + /* netsh interface ipv6 add route 2001:db8::/32 MyTunDevice */ + argv_printf (&argv, "%s%sc interface ipv6 add route %s/%d %s", + get_win_sys_path(), + NETSH_PATH_SUFFIX, + network, + r6->netbits, + device); + + /* next-hop depends on TUN or TAP mode: + * - in TAP mode, we use the "real" next-hop + * - in TUN mode we use a special-case link-local address that the tapdrvr + * knows about and will answer ND (neighbor discovery) packets for + */ + if ( tt->type == DEV_TYPE_TUN && !gateway_needed ) + argv_printf_cat( &argv, " %s", "fe80::8" ); + else if ( !IN6_IS_ADDR_UNSPECIFIED(&r6->gateway) ) + argv_printf_cat( &argv, " %s", gateway ); #if 0 - if (r6->flags & RT_METRIC_DEFINED) - argv_printf_cat (&argv, " METRIC %d", r->metric); + if (r6->flags & RT_METRIC_DEFINED) + argv_printf_cat (&argv, " METRIC %d", r->metric); #endif - /* in some versions of Windows, routes are persistent across reboots by - * default, unless "store=active" is set (pointed out by Tony Lim, thanks) - */ - argv_printf_cat( &argv, " store=active" ); + /* in some versions of Windows, routes are persistent across reboots by + * default, unless "store=active" is set (pointed out by Tony Lim, thanks) + */ + argv_printf_cat( &argv, " store=active" ); - argv_msg (D_ROUTE, &argv); + argv_msg (D_ROUTE, &argv); - netcmd_semaphore_lock (); - status = openvpn_execve_check (&argv, es, 0, "ERROR: Windows route add ipv6 command failed"); - netcmd_semaphore_release (); + netcmd_semaphore_lock (); + status = openvpn_execve_check (&argv, es, 0, "ERROR: Windows route add ipv6 command failed"); + netcmd_semaphore_release (); + } #elif defined (TARGET_SOLARIS) @@ -1965,7 +1980,12 @@ delete_route (struct route_ipv4 *r, argv_msg (D_ROUTE, &argv); - if ((flags & ROUTE_METHOD_MASK) == ROUTE_METHOD_IPAPI) + if ((flags & ROUTE_METHOD_MASK) == ROUTE_METHOD_SERVICE) + { + const bool status = del_route_service (r, tt); + msg (D_ROUTE, "Route deletion via service %s", status ? "succeeded" : "failed"); + } + else if ((flags & ROUTE_METHOD_MASK) == ROUTE_METHOD_IPAPI) { const bool status = del_route_ipapi (r, tt); msg (D_ROUTE, "Route deletion via IPAPI %s", status ? "succeeded" : "failed"); @@ -2107,7 +2127,7 @@ delete_route_ipv6 (const struct route_ipv6 *r6, const struct tuntap *tt, unsigne gc_init (&gc); argv_init (&argv); - network = print_in6_addr_netbits_only( r6->network, r6->netbits, &gc); + network = print_in6_addr( r6->network, 0, &gc); gateway = print_in6_addr( r6->gateway, 0, &gc); #if defined(TARGET_DARWIN) || \ @@ -2172,53 +2192,58 @@ delete_route_ipv6 (const struct route_ipv6 *r6, const struct tuntap *tt, unsigne #elif defined (WIN32) - struct buffer out = alloc_buf_gc (64, &gc); - if ( r6->adapter_index ) /* vpn server special route */ - { - buf_printf (&out, "interface=%d", r6->adapter_index ); - gateway_needed = true; - } + if (tt->options.msg_channel) + del_route_ipv6_service (r6, tt); else { - buf_printf (&out, "interface=%d", tt->adapter_index ); - } - device = buf_bptr(&out); + struct buffer out = alloc_buf_gc (64, &gc); + if ( r6->adapter_index ) /* vpn server special route */ + { + buf_printf (&out, "interface=%d", r6->adapter_index ); + gateway_needed = true; + } + else + { + buf_printf (&out, "interface=%d", tt->adapter_index ); + } + device = buf_bptr(&out); - /* netsh interface ipv6 delete route 2001:db8::/32 MyTunDevice */ - argv_printf (&argv, "%s%sc interface ipv6 delete route %s/%d %s", - get_win_sys_path(), - NETSH_PATH_SUFFIX, - network, - r6->netbits, - device); - - /* next-hop depends on TUN or TAP mode: - * - in TAP mode, we use the "real" next-hop - * - in TUN mode we use a special-case link-local address that the tapdrvr - * knows about and will answer ND (neighbor discovery) packets for - * (and "route deletion without specifying next-hop" does not work...) - */ - if ( tt->type == DEV_TYPE_TUN && !gateway_needed ) - argv_printf_cat( &argv, " %s", "fe80::8" ); - else if ( !IN6_IS_ADDR_UNSPECIFIED(&r6->gateway) ) - argv_printf_cat( &argv, " %s", gateway ); + /* netsh interface ipv6 delete route 2001:db8::/32 MyTunDevice */ + argv_printf (&argv, "%s%sc interface ipv6 delete route %s/%d %s", + get_win_sys_path(), + NETSH_PATH_SUFFIX, + network, + r6->netbits, + device); + + /* next-hop depends on TUN or TAP mode: + * - in TAP mode, we use the "real" next-hop + * - in TUN mode we use a special-case link-local address that the tapdrvr + * knows about and will answer ND (neighbor discovery) packets for + * (and "route deletion without specifying next-hop" does not work...) + */ + if ( tt->type == DEV_TYPE_TUN && !gateway_needed ) + argv_printf_cat( &argv, " %s", "fe80::8" ); + else if ( !IN6_IS_ADDR_UNSPECIFIED(&r6->gateway) ) + argv_printf_cat( &argv, " %s", gateway ); #if 0 - if (r6->flags & RT_METRIC_DEFINED) - argv_printf_cat (&argv, "METRIC %d", r->metric); + if (r6->flags & RT_METRIC_DEFINED) + argv_printf_cat (&argv, "METRIC %d", r->metric); #endif - /* Windows XP to 7 "just delete" routes, wherever they came from, but - * in Windows 8(.1?), if you create them with "store=active", this is - * how you should delete them as well (pointed out by Cedric Tabary) - */ - argv_printf_cat( &argv, " store=active" ); + /* Windows XP to 7 "just delete" routes, wherever they came from, but + * in Windows 8(.1?), if you create them with "store=active", this is + * how you should delete them as well (pointed out by Cedric Tabary) + */ + argv_printf_cat( &argv, " store=active" ); - argv_msg (D_ROUTE, &argv); + argv_msg (D_ROUTE, &argv); - netcmd_semaphore_lock (); - openvpn_execve_check (&argv, es, 0, "ERROR: Windows route delete ipv6 command failed"); - netcmd_semaphore_release (); + netcmd_semaphore_lock (); + openvpn_execve_check (&argv, es, 0, "ERROR: Windows route delete ipv6 command failed"); + netcmd_semaphore_release (); + } #elif defined (TARGET_SOLARIS) @@ -2705,6 +2730,126 @@ del_route_ipapi (const struct route_ipv4 *r, const struct tuntap *tt) return ret; } +static bool +do_route_service (const bool add, const route_message_t *rt, const size_t size, HANDLE pipe) +{ + DWORD len; + bool ret = false; + ack_message_t ack; + struct gc_arena gc = gc_new (); + + if (!WriteFile (pipe, rt, size, &len, NULL) || + !ReadFile (pipe, &ack, sizeof (ack), &len, NULL)) + { + msg (M_WARN, "ROUTE: could not talk to service: %s [%lu]", + strerror_win32 (GetLastError (), &gc), GetLastError ()); + goto out; + } + + if (ack.error_number != NO_ERROR) + { + msg (M_WARN, "ROUTE: route %s failed using service: %s [status=%u if_index=%lu]", + (add ? "addition" : "deletion"), strerror_win32 (ack.error_number, &gc), + ack.error_number, rt->iface.index); + goto out; + } + + ret = true; + +out: + gc_free (&gc); + return ret; +} + +static bool +do_route_ipv4_service (const bool add, const struct route_ipv4 *r, const struct tuntap *tt) +{ + DWORD if_index = windows_route_find_if_index (r, tt); + if (if_index == ~0) + return false; + + route_message_t msg = { + .header = { + (add ? msg_add_route : msg_del_route), + sizeof (route_message_t), + 0 }, + .family = AF_INET, + .prefix.ipv4.s_addr = htonl(r->network), + .gateway.ipv4.s_addr = htonl(r->gateway), + .iface = { .index = if_index, .name = "" }, + .metric = (r->flags & RT_METRIC_DEFINED ? r->metric : -1) + }; + + netmask_to_netbits (r->network, r->netmask, &msg.prefix_len); + if (msg.prefix_len == -1) + msg.prefix_len = 32; + + return do_route_service (add, &msg, sizeof (msg), tt->options.msg_channel); +} + +static bool +do_route_ipv6_service (const bool add, const struct route_ipv6 *r, const struct tuntap *tt) +{ + bool status; + route_message_t msg = { + .header = { + (add ? msg_add_route : msg_del_route), + sizeof (route_message_t), + 0 }, + .family = AF_INET6, + .prefix.ipv6 = r->network, + .prefix_len = r->netbits, + .gateway.ipv6 = r->gateway, + .iface = { .index = tt->adapter_index, .name = "" }, + .metric = ( (r->flags & RT_METRIC_DEFINED) ? r->metric : -1) + }; + + if ( r->adapter_index ) /* vpn server special route */ + msg.iface.index = r->adapter_index; + + /* In TUN mode we use a special link-local address as the next hop. + * The tapdrvr knows about it and will answer neighbor discovery packets. + */ + if (tt->type == DEV_TYPE_TUN) + inet_pton (AF_INET6, "fe80::8", &msg.gateway.ipv6); + + if (msg.iface.index == TUN_ADAPTER_INDEX_INVALID) + { + strncpy (msg.iface.name, tt->actual_name, sizeof (msg.iface.name)); + msg.iface.name[sizeof (msg.iface.name) - 1] = '\0'; + } + + status = do_route_service (add, &msg, sizeof (msg), tt->options.msg_channel); + msg (D_ROUTE, "IPv6 route %s via service %s", + add ? "addition" : "deletion", + status ? "succeeded" : "failed"); + return status; +} + +static bool +add_route_service (const struct route_ipv4 *r, const struct tuntap *tt) +{ + return do_route_ipv4_service (true, r, tt); +} + +static bool +del_route_service (const struct route_ipv4 *r, const struct tuntap *tt) +{ + return do_route_ipv4_service (false, r, tt); +} + +static bool +add_route_ipv6_service (const struct route_ipv6 *r, const struct tuntap *tt) +{ + return do_route_ipv6_service (true, r, tt); +} + +static bool +del_route_ipv6_service (const struct route_ipv6 *r, const struct tuntap *tt) +{ + return do_route_ipv6_service (false, r, tt); +} + static const char * format_route_entry (const MIB_IPFORWARDROW *r, struct gc_arena *gc) { diff --git a/src/openvpn/route.h b/src/openvpn/route.h index 4bbcdb74d47..58a57484ac0 100644 --- a/src/openvpn/route.h +++ b/src/openvpn/route.h @@ -40,6 +40,7 @@ #define ROUTE_METHOD_ADAPTIVE 0 /* try IP helper first then route.exe */ #define ROUTE_METHOD_IPAPI 1 /* use IP helper API */ #define ROUTE_METHOD_EXE 2 /* use route.exe */ +#define ROUTE_METHOD_SERVICE 3 /* use the privileged Windows service */ #define ROUTE_METHOD_MASK 3 #endif diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index efcd22541cf..eaeb6cc059e 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -48,6 +48,11 @@ #include "win32.h" #include "memdbg.h" + +#ifdef WIN32 +#include "openvpn-msg.h" +#endif + #include #ifdef WIN32 @@ -69,6 +74,64 @@ static const char *netsh_get_id (const char *dev_node, struct gc_arena *gc); static DWORD get_adapter_index_flexible (const char *name); +static bool +do_address_service (const bool add, const short family, const struct tuntap *tt) +{ + DWORD len; + bool ret = false; + ack_message_t ack; + struct gc_arena gc = gc_new (); + HANDLE pipe = tt->options.msg_channel; + + address_message_t addr = { + .header = { + (add ? msg_add_address : msg_del_address), + sizeof (address_message_t), + 0 }, + .family = family, + .iface = { .index = tt->adapter_index, .name = "" } + }; + + if (addr.iface.index == TUN_ADAPTER_INDEX_INVALID) + { + strncpy (addr.iface.name, tt->actual_name, sizeof (addr.iface.name)); + addr.iface.name[sizeof (addr.iface.name) - 1] = '\0'; + } + + if (addr.family == AF_INET) + { + addr.address.ipv4.s_addr = tt->local; + addr.prefix_len = 32; + } + else + { + addr.address.ipv6 = tt->local_ipv6; + addr.prefix_len = tt->netbits_ipv6; + } + + if (!WriteFile (pipe, &addr, sizeof (addr), &len, NULL) || + !ReadFile (pipe, &ack, sizeof (ack), &len, NULL)) + { + msg (M_WARN, "TUN: could not talk to service: %s [%lu]", + strerror_win32 (GetLastError (), &gc), GetLastError ()); + goto out; + } + + if (ack.error_number != NO_ERROR) + { + msg (M_WARN, "TUN: %s address failed using service: %s [status=%u if_index=%lu]", + (add ? "adding" : "deleting"), strerror_win32 (ack.error_number, &gc), + ack.error_number, addr.iface.index); + goto out; + } + + ret = true; + +out: + gc_free (&gc); + return ret; +} + #endif #ifdef TARGET_SOLARIS @@ -1301,7 +1364,6 @@ do_ifconfig (struct tuntap *tt, tt->did_ifconfig = true; } - /* IPv6 always uses "netsh" interface */ if ( do_ipv6 ) { char * saved_actual; @@ -1314,16 +1376,6 @@ do_ifconfig (struct tuntap *tt, idx = get_adapter_index_flexible(actual); openvpn_snprintf(iface, sizeof(iface), "interface=%lu", idx); - /* example: netsh interface ipv6 set address interface=42 2001:608:8003::d store=active */ - argv_printf (&argv, - "%s%sc interface ipv6 set address %s %s store=active", - get_win_sys_path(), - NETSH_PATH_SUFFIX, - iface, - ifconfig_ipv6_local); - netsh_command (&argv, 4); - - /* explicit route needed */ /* on windows, OpenVPN does ifconfig first, open_tun later, so * tt->actual_name might not yet be initialized, but routing code * needs to know interface name - point to "actual", restore later @@ -1332,6 +1384,24 @@ do_ifconfig (struct tuntap *tt, tt->actual_name = (char*) actual; /* we use adapter_index in add_route_ipv6 */ tt->adapter_index = idx; + + if (tt->options.msg_channel) + { + do_address_service (true, AF_INET6, tt); + } + else + { + /* example: netsh interface ipv6 set address interface=42 2001:608:8003::d store=active */ + argv_printf (&argv, + "%s%sc interface ipv6 set address %s %s store=active", + get_win_sys_path(), + NETSH_PATH_SUFFIX, + iface, + ifconfig_ipv6_local ); + netsh_command (&argv, 4); + } + + /* explicit route needed */ add_route_connected_v6_net(tt, es); tt->actual_name = saved_actual; } @@ -5403,13 +5473,35 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tu /* flush arp cache */ if (index != TUN_ADAPTER_INDEX_INVALID) { - DWORD status; + DWORD status = -1; - if ((status = FlushIpNetTable (index)) == NO_ERROR) + if (tt->options.msg_channel) + { + ack_message_t ack; + flush_neighbors_message_t msg = { + .header = { + msg_flush_neighbors, + sizeof (flush_neighbors_message_t), + 0 }, + .family = AF_INET, + .iface = { .index = index, .name = "" } + }; + + if (!WriteFile (tt->options.msg_channel, &msg, sizeof (msg), &len, NULL) || + !ReadFile (tt->options.msg_channel, &ack, sizeof (ack), &len, NULL)) + msg (M_WARN, "TUN: could not talk to service: %s [%lu]", + strerror_win32 (GetLastError (), &gc), GetLastError ()); + + status = ack.error_number; + } + else + status = FlushIpNetTable (index); + + if (status == NO_ERROR) msg (M_INFO, "Successful ARP Flush on interface [%u] %s", (unsigned int)index, device_guid); - else + else if (status != -1) msg (D_TUNTAP_INFO, "NOTE: FlushIpNetTable failed on interface [%u] %s (status=%u) : %s", (unsigned int)index, device_guid, @@ -5530,28 +5622,35 @@ close_tun (struct tuntap *tt) { if ( tt->ipv6 && tt->did_ifconfig_ipv6_setup ) { - const char *ifconfig_ipv6_local; - struct argv argv; - argv_init (&argv); - - /* remove route pointing to interface */ - delete_route_connected_v6_net(tt, NULL); - - /* "store=active" is needed in Windows 8(.1) to delete the - * address we added (pointed out by Cedric Tabary). - */ - - /* netsh interface ipv6 delete address \"%s\" %s */ - ifconfig_ipv6_local = print_in6_addr (tt->local_ipv6, 0, &gc); - argv_printf (&argv, - "%s%sc interface ipv6 delete address %s %s store=active", - get_win_sys_path(), - NETSH_PATH_SUFFIX, - tt->actual_name, - ifconfig_ipv6_local ); - - netsh_command (&argv, 1); - argv_reset (&argv); + if (tt->options.msg_channel) + { + do_address_service (false, AF_INET6, tt); + } + else + { + const char *ifconfig_ipv6_local; + struct argv argv; + argv_init (&argv); + + /* remove route pointing to interface */ + delete_route_connected_v6_net(tt, NULL); + + /* "store=active" is needed in Windows 8(.1) to delete the + * address we added (pointed out by Cedric Tabary). + */ + + /* netsh interface ipv6 delete address \"%s\" %s */ + ifconfig_ipv6_local = print_in6_addr (tt->local_ipv6, 0, &gc); + argv_printf (&argv, + "%s%sc interface ipv6 delete address %s %s store=active", + get_win_sys_path(), + NETSH_PATH_SUFFIX, + tt->actual_name, + ifconfig_ipv6_local); + + netsh_command (&argv, 1); + argv_reset (&argv); + } } #if 1 if (tt->ipapi_context_defined) diff --git a/src/openvpn/tun.h b/src/openvpn/tun.h index 65bacac0556..4e93a3fd43d 100644 --- a/src/openvpn/tun.h +++ b/src/openvpn/tun.h @@ -58,6 +58,10 @@ struct tuntap_options { # define IPW32_SET_N 5 int ip_win32_type; +#ifdef WIN32 + HANDLE msg_channel; +#endif + /* --ip-win32 dynamic options */ bool dhcp_masq_custom_offset; int dhcp_masq_offset; diff --git a/src/openvpnserv/Makefile.am b/src/openvpnserv/Makefile.am index a989c25ca9d..4bb1c275014 100644 --- a/src/openvpnserv/Makefile.am +++ b/src/openvpnserv/Makefile.am @@ -17,11 +17,21 @@ EXTRA_DIST = \ openvpnserv.vcxproj \ openvpnserv.vcxproj.filters +AM_CPPFLAGS = \ + -I$(top_srcdir)/include + if WIN32 sbin_PROGRAMS = openvpnserv +openvpnserv_CFLAGS = \ + -municode -D_UNICODE \ + -UNTDDI_VERSION -U_WIN32_WINNT \ + -D_WIN32_WINNT=_WIN32_WINNT_VISTA +openvpnserv_LDADD = -ladvapi32 -luserenv -liphlpapi -lws2_32 endif openvpnserv_SOURCES = \ - openvpnserv.c \ - service.h service.c \ + common.c \ + automatic.c \ + interactive.c \ + service.c service.h \ openvpnserv_resources.rc diff --git a/src/openvpnserv/automatic.c b/src/openvpnserv/automatic.c new file mode 100644 index 00000000000..9b424e95252 --- /dev/null +++ b/src/openvpnserv/automatic.c @@ -0,0 +1,415 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single TCP/UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * + * 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 + */ + +/* + * This program allows one or more OpenVPN processes to be started + * as a service. To build, you must get the service sample from the + * Platform SDK and replace Simple.c with this file. + * + * You should also apply service.patch to + * service.c and service.h from the Platform SDK service sample. + * + * This code is designed to be built with the mingw compiler. + */ + +#include "service.h" + +#include +#include +#include + +/* bool definitions */ +#define bool int +#define true 1 +#define false 0 + +static SERVICE_STATUS_HANDLE service; +static SERVICE_STATUS status; + +openvpn_service_t automatic_service = { + automatic, + TEXT(PACKAGE_NAME "Service"), + TEXT(PACKAGE_NAME " Service"), + TEXT(SERVICE_DEPENDENCIES), + SERVICE_DEMAND_START +}; + +struct security_attributes +{ + SECURITY_ATTRIBUTES sa; + SECURITY_DESCRIPTOR sd; +}; + +/* + * Which registry key in HKLM should + * we get config info from? + */ +#define REG_KEY "SOFTWARE\\" PACKAGE_NAME + +static HANDLE exit_event = NULL; + +/* clear an object */ +#define CLEAR(x) memset(&(x), 0, sizeof(x)) + + +bool +init_security_attributes_allow_all (struct security_attributes *obj) +{ + CLEAR (*obj); + + obj->sa.nLength = sizeof (SECURITY_ATTRIBUTES); + obj->sa.lpSecurityDescriptor = &obj->sd; + obj->sa.bInheritHandle = TRUE; + if (!InitializeSecurityDescriptor (&obj->sd, SECURITY_DESCRIPTOR_REVISION)) + return false; + if (!SetSecurityDescriptorDacl (&obj->sd, TRUE, NULL, FALSE)) + return false; + return true; +} + +/* + * This event is initially created in the non-signaled + * state. It will transition to the signaled state when + * we have received a terminate signal from the Service + * Control Manager which will cause an asynchronous call + * of ServiceStop below. + */ +#define EXIT_EVENT_NAME TEXT(PACKAGE "_exit_1") + +HANDLE +create_event (LPCTSTR name, bool allow_all, bool initial_state, bool manual_reset) +{ + if (allow_all) + { + struct security_attributes sa; + if (!init_security_attributes_allow_all (&sa)) + return NULL; + return CreateEvent (&sa.sa, (BOOL)manual_reset, (BOOL)initial_state, name); + } + else + return CreateEvent (NULL, (BOOL)manual_reset, (BOOL)initial_state, name); +} + +void +close_if_open (HANDLE h) +{ + if (h != NULL) + CloseHandle (h); +} + +static bool +match (const WIN32_FIND_DATA *find, LPCTSTR ext) +{ + int i; + + if (find->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + return false; + + if (!_tcslen (ext)) + return true; + + i = _tcslen (find->cFileName) - _tcslen (ext) - 1; + if (i < 1) + return false; + + return find->cFileName[i] == '.' && !_tcsicmp (find->cFileName + i + 1, ext); +} + +/* + * Modify the extension on a filename. + */ +static bool +modext (LPTSTR dest, int size, LPCTSTR src, LPCTSTR newext) +{ + int i; + + if (size > 0 && (_tcslen (src) + 1) <= size) + { + _tcscpy (dest, src); + dest [size - 1] = TEXT('\0'); + i = _tcslen (dest); + while (--i >= 0) + { + if (dest[i] == TEXT('\\')) + break; + if (dest[i] == TEXT('.')) + { + dest[i] = TEXT('\0'); + break; + } + } + if (_tcslen (dest) + _tcslen(newext) + 2 <= size) + { + _tcscat (dest, TEXT(".")); + _tcscat (dest, newext); + return true; + } + dest[0] = TEXT('\0'); + } + return false; +} + +static DWORD WINAPI +ServiceCtrlAutomatic (DWORD ctrl_code, DWORD event, LPVOID data, LPVOID ctx) +{ + SERVICE_STATUS *status = ctx; + switch (ctrl_code) + { + case SERVICE_CONTROL_STOP: + status->dwCurrentState = SERVICE_STOP_PENDING; + ReportStatusToSCMgr (service, status); + if (exit_event) + SetEvent (exit_event); + return NO_ERROR; + + case SERVICE_CONTROL_INTERROGATE: + return NO_ERROR; + + default: + return ERROR_CALL_NOT_IMPLEMENTED; + } +} + + +VOID WINAPI +ServiceStartAutomatic (DWORD dwArgc, LPTSTR *lpszArgv) +{ + DWORD error = NO_ERROR; + settings_t settings; + + service = RegisterServiceCtrlHandlerEx (automatic_service.name, ServiceCtrlAutomatic, &status); + if (!service) + return; + + status.dwServiceType = SERVICE_WIN32_SHARE_PROCESS; + status.dwCurrentState = SERVICE_START_PENDING; + status.dwServiceSpecificExitCode = NO_ERROR; + status.dwWin32ExitCode = NO_ERROR; + status.dwWaitHint = 3000; + + if (!ReportStatusToSCMgr(service, &status)) + { + MsgToEventLog (M_ERR, TEXT("ReportStatusToSCMgr #1 failed")); + goto finish; + } + + /* + * Create our exit event + */ + exit_event = create_event (EXIT_EVENT_NAME, false, false, true); + if (!exit_event) + { + MsgToEventLog (M_ERR, TEXT("CreateEvent failed")); + goto finish; + } + + /* + * If exit event is already signaled, it means we were not + * shut down properly. + */ + if (WaitForSingleObject (exit_event, 0) != WAIT_TIMEOUT) + { + MsgToEventLog (M_ERR, TEXT("Exit event is already signaled -- we were not shut down properly")); + goto finish; + } + + if (!ReportStatusToSCMgr(service, &status)) + { + MsgToEventLog (M_ERR, TEXT("ReportStatusToSCMgr #2 failed")); + goto finish; + } + + /* + * Read info from registry in key HKLM\SOFTWARE\OpenVPN + */ + error = GetOpenvpnSettings (&settings); + if (error != ERROR_SUCCESS) + goto finish; + + /* + * Instantiate an OpenVPN process for each configuration + * file found. + */ + { + WIN32_FIND_DATA find_obj; + HANDLE find_handle; + BOOL more_files; + TCHAR find_string[MAX_PATH]; + + openvpn_sntprintf (find_string, MAX_PATH, TEXT("%s\\*"), settings.config_dir); + + find_handle = FindFirstFile (find_string, &find_obj); + if (find_handle == INVALID_HANDLE_VALUE) + { + MsgToEventLog (M_ERR, TEXT("Cannot get configuration file list using: %s"), find_string); + goto finish; + } + + /* + * Loop over each config file + */ + do { + HANDLE log_handle = NULL; + STARTUPINFO start_info; + PROCESS_INFORMATION proc_info; + struct security_attributes sa; + TCHAR log_file[MAX_PATH]; + TCHAR log_path[MAX_PATH]; + TCHAR command_line[256]; + + CLEAR (start_info); + CLEAR (proc_info); + CLEAR (sa); + + if (!ReportStatusToSCMgr(service, &status)) + { + MsgToEventLog (M_ERR, TEXT("ReportStatusToSCMgr #3 failed")); + FindClose (find_handle); + goto finish; + } + + /* does file have the correct type and extension? */ + if (match (&find_obj, settings.ext_string)) + { + /* get log file pathname */ + if (!modext (log_file, _countof (log_file), find_obj.cFileName, TEXT("log"))) + { + MsgToEventLog (M_ERR, TEXT("Cannot construct logfile name based on: %s"), find_obj.cFileName); + FindClose (find_handle); + goto finish; + } + openvpn_sntprintf (log_path, _countof (log_path), + TEXT("%s\\%s"), settings.log_dir, log_file); + + /* construct command line */ + openvpn_sntprintf (command_line, _countof (command_line), TEXT(PACKAGE " --service %s 1 --config \"%s\""), + EXIT_EVENT_NAME, + find_obj.cFileName); + + /* Make security attributes struct for logfile handle so it can + be inherited. */ + if (!init_security_attributes_allow_all (&sa)) + { + error = MsgToEventLog (M_SYSERR, TEXT("InitializeSecurityDescriptor start_" PACKAGE " failed")); + goto finish; + } + + /* open logfile as stdout/stderr for soon-to-be-spawned subprocess */ + log_handle = CreateFile (log_path, + GENERIC_WRITE, + FILE_SHARE_READ, + &sa.sa, + settings.append ? OPEN_ALWAYS : CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if (log_handle == INVALID_HANDLE_VALUE) + { + error = MsgToEventLog (M_SYSERR, TEXT("Cannot open logfile: %s"), log_path); + FindClose (find_handle); + goto finish; + } + + /* append to logfile? */ + if (settings.append) + { + if (SetFilePointer (log_handle, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER) + { + error = MsgToEventLog (M_SYSERR, TEXT("Cannot seek to end of logfile: %s"), log_path); + FindClose (find_handle); + goto finish; + } + } + + /* fill in STARTUPINFO struct */ + GetStartupInfo(&start_info); + start_info.cb = sizeof(start_info); + start_info.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW; + start_info.wShowWindow = SW_HIDE; + start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE); + start_info.hStdOutput = start_info.hStdError = log_handle; + + /* create an OpenVPN process for one config file */ + if (!CreateProcess(settings.exe_path, + command_line, + NULL, + NULL, + TRUE, + settings.priority | CREATE_NEW_CONSOLE, + NULL, + settings.config_dir, + &start_info, + &proc_info)) + { + error = MsgToEventLog (M_SYSERR, TEXT("CreateProcess failed, exe='%s' cmdline='%s' dir='%s'"), + settings.exe_path, + command_line, + settings.config_dir); + + FindClose (find_handle); + CloseHandle (log_handle); + goto finish; + } + + /* close unneeded handles */ + Sleep (1000); /* try to prevent race if we close logfile + handle before child process DUPs it */ + if (!CloseHandle (proc_info.hProcess) + || !CloseHandle (proc_info.hThread) + || !CloseHandle (log_handle)) + { + error = MsgToEventLog (M_SYSERR, TEXT("CloseHandle failed")); + goto finish; + } + } + + /* more files to process? */ + more_files = FindNextFile (find_handle, &find_obj); + + } while (more_files); + + FindClose (find_handle); + } + + /* we are now fully started */ + status.dwCurrentState = SERVICE_RUNNING; + status.dwWaitHint = 0; + if (!ReportStatusToSCMgr(service, &status)) + { + MsgToEventLog (M_ERR, TEXT("ReportStatusToSCMgr SERVICE_RUNNING failed")); + goto finish; + } + + /* wait for our shutdown signal */ + if (WaitForSingleObject (exit_event, INFINITE) != WAIT_OBJECT_0) + MsgToEventLog (M_ERR, TEXT("wait for shutdown signal failed")); + +finish: + if (exit_event) + CloseHandle (exit_event); + + status.dwCurrentState = SERVICE_STOPPED; + status.dwWin32ExitCode = error; + ReportStatusToSCMgr (service, &status); +} diff --git a/src/openvpnserv/common.c b/src/openvpnserv/common.c new file mode 100644 index 00000000000..a2937964c2c --- /dev/null +++ b/src/openvpnserv/common.c @@ -0,0 +1,211 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single TCP/UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2011 Heiko Hund + * + * 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 + */ + +#include + +/* + * These are necessary due to certain buggy implementations of (v)snprintf, + * that don't guarantee null termination for size > 0. + */ +int +openvpn_vsntprintf (LPTSTR str, size_t size, LPCTSTR format, va_list arglist) +{ + int len = -1; + if (size > 0) + { + len = _vsntprintf (str, size, format, arglist); + str[size - 1] = 0; + } + return (len >= 0 && len < size); +} +int +openvpn_sntprintf (LPTSTR str, size_t size, LPCTSTR format, ...) +{ + va_list arglist; + int len = -1; + if (size > 0) + { + va_start (arglist, format); + len = openvpn_vsntprintf (str, size, format, arglist); + va_end (arglist); + } + return len; +} + + +#define REG_KEY TEXT("SOFTWARE\\" PACKAGE_NAME) + +static DWORD +GetRegString (HKEY key, LPCTSTR value, LPTSTR data, DWORD size) +{ + DWORD type; + LONG status = RegQueryValueEx (key, value, NULL, &type, (LPBYTE) data, &size); + + if (status == ERROR_SUCCESS && type != REG_SZ) + status = ERROR_DATATYPE_MISMATCH; + + if (status != ERROR_SUCCESS) + { + SetLastError (status); + return MsgToEventLog (M_SYSERR, TEXT("Error querying registry value: HKLM\\%s\\%s"), REG_KEY, value); + } + + return ERROR_SUCCESS; +} + + +DWORD +GetOpenvpnSettings (settings_t *s) +{ + TCHAR priority[64]; + TCHAR append[2]; + DWORD error; + HKEY key; + + LONG status = RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_KEY, 0, KEY_READ, &key); + if (status != ERROR_SUCCESS) + { + SetLastError (status); + return MsgToEventLog (M_SYSERR, TEXT("Could not open Registry key HKLM\\%s not found"), REG_KEY); + } + + error = GetRegString (key, TEXT("exe_path"), s->exe_path, sizeof (s->exe_path)); + if (error != ERROR_SUCCESS) + goto out; + + error = GetRegString (key, TEXT("config_dir"), s->config_dir, sizeof (s->config_dir)); + if (error != ERROR_SUCCESS) + goto out; + + error = GetRegString (key, TEXT("config_ext"), s->ext_string, sizeof (s->ext_string)); + if (error != ERROR_SUCCESS) + goto out; + + error = GetRegString (key, TEXT("log_dir"), s->log_dir, sizeof (s->log_dir)); + if (error != ERROR_SUCCESS) + goto out; + + error = GetRegString (key, TEXT("priority"), priority, sizeof (priority)); + if (error != ERROR_SUCCESS) + goto out; + + error = GetRegString (key, TEXT("log_append"), append, sizeof (append)); + if (error != ERROR_SUCCESS) + goto out; + + /* set process priority */ + if (!_tcsicmp (priority, TEXT("IDLE_PRIORITY_CLASS"))) + s->priority = IDLE_PRIORITY_CLASS; + else if (!_tcsicmp (priority, TEXT("BELOW_NORMAL_PRIORITY_CLASS"))) + s->priority = BELOW_NORMAL_PRIORITY_CLASS; + else if (!_tcsicmp (priority, TEXT("NORMAL_PRIORITY_CLASS"))) + s->priority = NORMAL_PRIORITY_CLASS; + else if (!_tcsicmp (priority, TEXT("ABOVE_NORMAL_PRIORITY_CLASS"))) + s->priority = ABOVE_NORMAL_PRIORITY_CLASS; + else if (!_tcsicmp (priority, TEXT("HIGH_PRIORITY_CLASS"))) + s->priority = HIGH_PRIORITY_CLASS; + else + { + SetLastError (ERROR_INVALID_DATA); + error = MsgToEventLog (M_SYSERR, TEXT("Unknown priority name: %s"), priority); + goto out; + } + + /* set log file append/truncate flag */ + if (append[0] == TEXT('0')) + s->append = FALSE; + else if (append[0] == TEXT('1')) + s->append = TRUE; + else + { + SetLastError (ERROR_INVALID_DATA); + error = MsgToEventLog (M_ERR, TEXT("Log file append flag (given as '%s') must be '0' or '1'"), append); + goto out; + } + +out: + RegCloseKey (key); + return error; +} + + +LPCTSTR +GetLastErrorText () +{ + static TCHAR buf[256]; + DWORD len; + LPTSTR tmp = NULL; + + len = FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY, + NULL, GetLastError(), LANG_NEUTRAL, (LPTSTR)&tmp, 0, NULL); + + if (len == 0 || (long) _countof (buf) < (long) len + 14) + buf[0] = TEXT('\0'); + else + { + tmp[_tcslen (tmp) - 2] = TEXT('\0'); /* remove CR/LF characters */ + openvpn_sntprintf (buf, _countof (buf), TEXT("%s (0x%x)"), tmp, GetLastError()); + } + + if (tmp) + LocalFree (tmp); + + return buf; +} + + +DWORD +MsgToEventLog (DWORD flags, LPCTSTR format, ...) +{ + HANDLE hEventSource; + TCHAR msg[2][256]; + DWORD error = 0; + LPCTSTR err_msg = TEXT(""); + va_list arglist; + + if (flags & MSG_FLAGS_SYS_CODE) + { + error = GetLastError (); + err_msg = GetLastErrorText (); + } + + hEventSource = RegisterEventSource (NULL, APPNAME); + if (hEventSource != NULL) + { + openvpn_sntprintf (msg[0], _countof (msg[0]), + TEXT("%s error: %s"), APPNAME, err_msg); + + va_start (arglist, format); + openvpn_vsntprintf (msg[1], _countof (msg[1]), format, arglist); + va_end (arglist); + + const TCHAR *mesg[] = { msg[0], msg[1] }; + ReportEvent (hEventSource, flags & MSG_FLAGS_ERROR ? + EVENTLOG_ERROR_TYPE : EVENTLOG_INFORMATION_TYPE, + 0, 0, NULL, 2, 0, mesg, NULL); + DeregisterEventSource (hEventSource); + } + + return error; +} diff --git a/src/openvpnserv/interactive.c b/src/openvpnserv/interactive.c new file mode 100644 index 00000000000..0f3d1d47aa0 --- /dev/null +++ b/src/openvpnserv/interactive.c @@ -0,0 +1,1272 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single TCP/UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2012 Heiko Hund + * + * 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 + */ + + +#include "service.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "openvpn-msg.h" + +#define IO_TIMEOUT 2000 /*ms*/ + +#define ERROR_OPENVPN_STARTUP 0x20000000 +#define ERROR_STARTUP_DATA 0x20000001 +#define ERROR_MESSAGE_DATA 0x20000002 +#define ERROR_MESSAGE_TYPE 0x20000003 + +static SERVICE_STATUS_HANDLE service; +static SERVICE_STATUS status; +static HANDLE exit_event = NULL; +static settings_t settings; + +openvpn_service_t interactive_service = { + interactive, + TEXT(PACKAGE_NAME "ServiceInteractive"), + TEXT(PACKAGE_NAME " Interactive Service"), + TEXT(SERVICE_DEPENDENCIES), + SERVICE_AUTO_START +}; + + +typedef struct { + WCHAR *directory; + WCHAR *options; + WCHAR *std_input; +} STARTUP_DATA; + + +/* Datatype for linked lists */ +typedef struct _list_item { + struct _list_item *next; + LPVOID data; +} list_item_t; + + +/* Datatypes for undo information */ +typedef enum { + address, + route, + _undo_type_max +} undo_type_t; +typedef list_item_t* undo_lists_t[_undo_type_max]; + + +static DWORD +AddListItem (list_item_t **pfirst, LPVOID data) +{ + list_item_t *new_item = malloc (sizeof (list_item_t)); + if (new_item == NULL) + return ERROR_OUTOFMEMORY; + + new_item->next = *pfirst; + new_item->data = data; + + *pfirst = new_item; + return NO_ERROR; +} + +typedef BOOL (*match_fn_t) (LPVOID item, LPVOID ctx); + +static LPVOID +RemoveListItem (list_item_t **pfirst, match_fn_t match, LPVOID ctx) +{ + LPVOID data = NULL; + list_item_t **pnext; + + for (pnext = pfirst; *pnext; pnext = &(*pnext)->next) + { + list_item_t *item = *pnext; + if (!match (item->data, ctx)) + continue; + + /* Found item, remove from the list and free memory */ + *pnext = item->next; + data = item->data; + free (item); + break; + } + return data; +} + + +static HANDLE +CloseHandleEx (LPHANDLE handle) +{ + if (handle && *handle && *handle != INVALID_HANDLE_VALUE) + { + CloseHandle (*handle); + *handle = INVALID_HANDLE_VALUE; + } + return INVALID_HANDLE_VALUE; +} + + +static HANDLE +InitOverlapped (LPOVERLAPPED overlapped) +{ + ZeroMemory (overlapped, sizeof (OVERLAPPED)); + overlapped->hEvent = CreateEvent (NULL, TRUE, FALSE, NULL); + return overlapped->hEvent; +} + + +static BOOL +ResetOverlapped (LPOVERLAPPED overlapped) +{ + HANDLE io_event = overlapped->hEvent; + if (!ResetEvent (io_event)) + return FALSE; + ZeroMemory (overlapped, sizeof (OVERLAPPED)); + overlapped->hEvent = io_event; + return TRUE; +} + + +typedef enum { + peek, + read, + write +} async_op_t; + +static DWORD +AsyncPipeOp (async_op_t op, HANDLE pipe, LPVOID buffer, DWORD size, DWORD count, LPHANDLE events) +{ + int i; + BOOL success; + HANDLE io_event; + DWORD res, bytes = 0; + OVERLAPPED overlapped; + LPHANDLE handles = NULL; + + io_event = InitOverlapped (&overlapped); + if (!io_event) + goto out; + + handles = malloc ((count + 1) * sizeof (HANDLE)); + if (!handles) + goto out; + + if (op == write) + success = WriteFile (pipe, buffer, size, NULL, &overlapped); + else + success = ReadFile (pipe, buffer, size, NULL, &overlapped); + if (!success && GetLastError () != ERROR_IO_PENDING && GetLastError () != ERROR_MORE_DATA) + goto out; + + handles[0] = io_event; + for (i = 0; i < count; i++) + handles[i + 1] = events[i]; + + res = WaitForMultipleObjects (count + 1, handles, FALSE, + op == peek ? INFINITE : IO_TIMEOUT); + if (res != WAIT_OBJECT_0) + { + CancelIo (pipe); + goto out; + } + + if (op == peek) + PeekNamedPipe (pipe, NULL, 0, NULL, &bytes, NULL); + else + GetOverlappedResult (pipe, &overlapped, &bytes, TRUE); + +out: + CloseHandleEx (&io_event); + free (handles); + return bytes; +} + +static DWORD +PeekNamedPipeAsync (HANDLE pipe, DWORD count, LPHANDLE events) +{ + return AsyncPipeOp (peek, pipe, NULL, 0, count, events); +} + +static DWORD +ReadPipeAsync (HANDLE pipe, LPVOID buffer, DWORD size, DWORD count, LPHANDLE events) +{ + return AsyncPipeOp (read, pipe, buffer, size, count, events); +} + +static DWORD +WritePipeAsync (HANDLE pipe, LPVOID data, DWORD size, DWORD count, LPHANDLE events) +{ + return AsyncPipeOp (write, pipe, data, size, count, events); +} + + +static VOID +ReturnError (HANDLE pipe, DWORD error, LPCWSTR func, DWORD count, LPHANDLE events) +{ + DWORD result_len; + LPWSTR result = L"0xffffffff\nFormatMessage failed\nCould not return result"; + DWORD_PTR args[] = { + (DWORD_PTR) error, + (DWORD_PTR) func, + (DWORD_PTR) "" + }; + + if (error != ERROR_OPENVPN_STARTUP) + { + FormatMessageW (FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_IGNORE_INSERTS, + 0, error, 0, (LPWSTR) &args[2], 0, NULL); + } + + result_len = FormatMessageW (FORMAT_MESSAGE_FROM_STRING | + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_ARGUMENT_ARRAY, + L"0x%1!08x!\n%2!s!\n%3!s!", 0, 0, + (LPWSTR) &result, 0, (va_list*) args); + + WritePipeAsync (pipe, result, wcslen (result) * 2, count, events); +#ifdef UNICODE + MsgToEventLog (MSG_FLAGS_ERROR, result); +#else + MsgToEventLog (MSG_FLAGS_ERROR, "%S", result); +#endif + + if (error != ERROR_OPENVPN_STARTUP) + LocalFree ((LPVOID) args[2]); + if (result_len) + LocalFree (result); +} + + +static VOID +ReturnLastError (HANDLE pipe, LPCWSTR func) +{ + ReturnError (pipe, GetLastError (), func, 1, &exit_event); +} + + +static VOID +ReturnOpenvpnOutput (HANDLE pipe, HANDLE ovpn_output, DWORD count, LPHANDLE events) +{ + WCHAR *wide_output = NULL; + CHAR output[512]; + DWORD size; + + ReadFile (ovpn_output, output, sizeof (output), &size, NULL); + if (size == 0) + return; + + wide_output = malloc ((size) * sizeof (WCHAR)); + if (wide_output) + { + MultiByteToWideChar (CP_UTF8, 0, output, size, wide_output, size); + wide_output[size - 1] = 0; + } + + ReturnError (pipe, ERROR_OPENVPN_STARTUP, wide_output, count, events); + free (wide_output); +} + + +static BOOL +GetStartupData (HANDLE pipe, STARTUP_DATA *sud) +{ + size_t len; + BOOL ret = FALSE; + WCHAR *data = NULL; + DWORD size, bytes, read; + + bytes = PeekNamedPipeAsync (pipe, 1, &exit_event); + if (bytes == 0) + { + MsgToEventLog (M_SYSERR, TEXT("PeekNamedPipeAsync failed")); + ReturnLastError (pipe, L"PeekNamedPipeAsync"); + goto out; + } + + size = bytes / sizeof (*data); + data = malloc (bytes); + if (data == NULL) + { + MsgToEventLog (M_SYSERR, TEXT("malloc failed")); + ReturnLastError (pipe, L"malloc"); + goto out; + } + + read = ReadPipeAsync (pipe, data, bytes, 1, &exit_event); + if (bytes != read) + { + MsgToEventLog (M_SYSERR, TEXT("ReadPipeAsync failed")); + ReturnLastError (pipe, L"ReadPipeAsync"); + goto out; + } + + if (data[size - 1] != 0) + { + MsgToEventLog (M_ERR, TEXT("Startup data is not NULL terminated")); + ReturnError (pipe, ERROR_STARTUP_DATA, L"GetStartupData", 1, &exit_event); + goto out; + } + + sud->directory = data; + len = wcslen (sud->directory) + 1; + size -= len; + if (size <= 0) + { + MsgToEventLog (M_ERR, TEXT("Startup data ends at working directory")); + ReturnError (pipe, ERROR_STARTUP_DATA, L"GetStartupData", 1, &exit_event); + goto out; + } + + sud->options = sud->directory + len; + len = wcslen (sud->options) + 1; + size -= len; + if (size <= 0) + { + MsgToEventLog (M_ERR, TEXT("Startup data ends at command line options")); + ReturnError (pipe, ERROR_STARTUP_DATA, L"GetStartupData", 1, &exit_event); + goto out; + } + + sud->std_input = sud->options + len; + data = NULL; /* don't free data */ + ret = TRUE; + +out: + free (data); + return ret; +} + + +static VOID +FreeStartupData (STARTUP_DATA *sud) +{ + free (sud->directory); +} + + +static SOCKADDR_INET +sockaddr_inet (short family, inet_address_t *addr) +{ + SOCKADDR_INET sa_inet; + ZeroMemory (&sa_inet, sizeof (sa_inet)); + sa_inet.si_family = family; + if (family == AF_INET) + sa_inet.Ipv4.sin_addr = addr->ipv4; + else if (family == AF_INET6) + sa_inet.Ipv6.sin6_addr = addr->ipv6; + return sa_inet; +} + +static DWORD +InterfaceLuid (const char *iface_name, PNET_LUID luid) +{ + NETIO_STATUS status; + LPWSTR wide_name; + int n; + + typedef NETIO_STATUS WINAPI (*ConvertInterfaceAliasToLuidFn) (LPCWSTR, PNET_LUID); + static ConvertInterfaceAliasToLuidFn ConvertInterfaceAliasToLuid = NULL; + if (!ConvertInterfaceAliasToLuid) + { + HMODULE iphlpapi = GetModuleHandle (TEXT("iphlpapi.dll")); + if (iphlpapi == NULL) + return GetLastError (); + + ConvertInterfaceAliasToLuid = (ConvertInterfaceAliasToLuidFn) GetProcAddress (iphlpapi, "ConvertInterfaceAliasToLuid"); + if (!ConvertInterfaceAliasToLuid) + return GetLastError (); + } + + n = MultiByteToWideChar (CP_UTF8, 0, iface_name, -1, NULL, 0); + wide_name = malloc (n * sizeof (WCHAR)); + MultiByteToWideChar (CP_UTF8, 0, iface_name, -1, wide_name, n); + status = ConvertInterfaceAliasToLuid (wide_name, luid); + free (wide_name); + + return status; +} + +static BOOL +CmpAddress (LPVOID item, LPVOID address) +{ + return memcmp (item, address, sizeof (MIB_UNICASTIPADDRESS_ROW)) == 0 ? TRUE : FALSE; +} + +static DWORD +DeleteAddress (PMIB_UNICASTIPADDRESS_ROW addr_row) +{ + typedef NETIOAPI_API (*DeleteUnicastIpAddressEntryFn) (const PMIB_UNICASTIPADDRESS_ROW); + static DeleteUnicastIpAddressEntryFn DeleteUnicastIpAddressEntry = NULL; + + if (!DeleteUnicastIpAddressEntry) + { + HMODULE iphlpapi = GetModuleHandle (TEXT("iphlpapi.dll")); + if (iphlpapi == NULL) + return GetLastError (); + + DeleteUnicastIpAddressEntry = (DeleteUnicastIpAddressEntryFn) GetProcAddress (iphlpapi, "DeleteUnicastIpAddressEntry"); + if (!DeleteUnicastIpAddressEntry) + return GetLastError (); + } + + return DeleteUnicastIpAddressEntry (addr_row); +} + +static DWORD +HandleAddressMessage (address_message_t *msg, undo_lists_t *lists) +{ + DWORD err; + PMIB_UNICASTIPADDRESS_ROW addr_row; + BOOL add = msg->header.type == msg_add_address; + + typedef NETIOAPI_API (*CreateUnicastIpAddressEntryFn) (const PMIB_UNICASTIPADDRESS_ROW); + typedef NETIOAPI_API (*InitializeUnicastIpAddressEntryFn) (PMIB_UNICASTIPADDRESS_ROW); + static CreateUnicastIpAddressEntryFn CreateUnicastIpAddressEntry = NULL; + static InitializeUnicastIpAddressEntryFn InitializeUnicastIpAddressEntry = NULL; + + if (!CreateUnicastIpAddressEntry || !InitializeUnicastIpAddressEntry) + { + HMODULE iphlpapi = GetModuleHandle (TEXT("iphlpapi.dll")); + if (iphlpapi == NULL) + return GetLastError (); + + CreateUnicastIpAddressEntry = (CreateUnicastIpAddressEntryFn) GetProcAddress (iphlpapi, "CreateUnicastIpAddressEntry"); + if (!CreateUnicastIpAddressEntry) + return GetLastError (); + + InitializeUnicastIpAddressEntry = (InitializeUnicastIpAddressEntryFn) GetProcAddress (iphlpapi, "InitializeUnicastIpAddressEntry"); + if (!InitializeUnicastIpAddressEntry) + return GetLastError (); + } + + addr_row = malloc (sizeof (*addr_row)); + if (addr_row == NULL) + return ERROR_OUTOFMEMORY; + + InitializeUnicastIpAddressEntry (addr_row); + addr_row->Address = sockaddr_inet (msg->family, &msg->address); + addr_row->OnLinkPrefixLength = (UINT8) msg->prefix_len; + + if (msg->iface.index != -1) + { + addr_row->InterfaceIndex = msg->iface.index; + } + else + { + NET_LUID luid; + err = InterfaceLuid (msg->iface.name, &luid); + if (err) + goto out; + addr_row->InterfaceLuid = luid; + } + + if (add) + { + err = CreateUnicastIpAddressEntry (addr_row); + if (err) + goto out; + + err = AddListItem (&(*lists)[address], addr_row); + if (err) + DeleteAddress (addr_row); + } + else + { + err = DeleteAddress (addr_row); + if (err) + goto out; + + free (RemoveListItem (&(*lists)[address], CmpAddress, addr_row)); + } + +out: + if (!add || err) + free (addr_row); + + return err; +} + + +static BOOL +CmpRoute (LPVOID item, LPVOID route) +{ + return memcmp (item, route, sizeof (MIB_IPFORWARD_ROW2)) == 0 ? TRUE : FALSE; +} + +static DWORD +DeleteRoute (PMIB_IPFORWARD_ROW2 fwd_row) +{ + typedef NETIOAPI_API (*DeleteIpForwardEntry2Fn) (PMIB_IPFORWARD_ROW2); + static DeleteIpForwardEntry2Fn DeleteIpForwardEntry2 = NULL; + + if (!DeleteIpForwardEntry2) + { + HMODULE iphlpapi = GetModuleHandle (TEXT("iphlpapi.dll")); + if (iphlpapi == NULL) + return GetLastError (); + + DeleteIpForwardEntry2 = (DeleteIpForwardEntry2Fn) GetProcAddress (iphlpapi, "DeleteIpForwardEntry2"); + if (!DeleteIpForwardEntry2) + return GetLastError (); + } + + return DeleteIpForwardEntry2 (fwd_row); +} + +static DWORD +HandleRouteMessage (route_message_t *msg, undo_lists_t *lists) +{ + DWORD err; + PMIB_IPFORWARD_ROW2 fwd_row; + BOOL add = msg->header.type == msg_add_route; + + typedef NETIOAPI_API (*CreateIpForwardEntry2Fn) (PMIB_IPFORWARD_ROW2); + static CreateIpForwardEntry2Fn CreateIpForwardEntry2 = NULL; + + if (!CreateIpForwardEntry2) + { + HMODULE iphlpapi = GetModuleHandle (TEXT("iphlpapi.dll")); + if (iphlpapi == NULL) + return GetLastError (); + + CreateIpForwardEntry2 = (CreateIpForwardEntry2Fn) GetProcAddress (iphlpapi, "CreateIpForwardEntry2"); + if (!CreateIpForwardEntry2) + return GetLastError (); + } + + fwd_row = malloc (sizeof (*fwd_row)); + if (fwd_row == NULL) + return ERROR_OUTOFMEMORY; + + ZeroMemory (fwd_row, sizeof (*fwd_row)); + fwd_row->ValidLifetime = 0xffffffff; + fwd_row->PreferredLifetime = 0xffffffff; + fwd_row->Protocol = MIB_IPPROTO_NETMGMT; + fwd_row->Metric = msg->metric; + fwd_row->DestinationPrefix.Prefix = sockaddr_inet (msg->family, &msg->prefix); + fwd_row->DestinationPrefix.PrefixLength = (UINT8) msg->prefix_len; + fwd_row->NextHop = sockaddr_inet (msg->family, &msg->gateway); + + if (msg->iface.index != -1) + { + fwd_row->InterfaceIndex = msg->iface.index; + } + else if (strlen (msg->iface.name)) + { + NET_LUID luid; + err = InterfaceLuid (msg->iface.name, &luid); + if (err) + goto out; + fwd_row->InterfaceLuid = luid; + } + + if (add) + { + err = CreateIpForwardEntry2 (fwd_row); + if (err) + goto out; + + err = AddListItem (&(*lists)[route], fwd_row); + if (err) + DeleteRoute (fwd_row); + } + else + { + err = DeleteRoute (fwd_row); + if (err) + goto out; + + free (RemoveListItem (&(*lists)[route], CmpRoute, fwd_row)); + } + +out: + if (!add || err) + free (fwd_row); + + return err; +} + + +static DWORD +HandleFlushNeighborsMessage (flush_neighbors_message_t *msg) +{ + typedef NETIOAPI_API (*FlushIpNetTable2Fn) (ADDRESS_FAMILY, NET_IFINDEX); + static FlushIpNetTable2Fn flush_fn = NULL; + + if (msg->family == AF_INET) + return FlushIpNetTable (msg->iface.index); + + if (!flush_fn) + { + HMODULE iphlpapi = GetModuleHandle (TEXT("iphlpapi.dll")); + if (iphlpapi == NULL) + return GetLastError (); + + flush_fn = (FlushIpNetTable2Fn) GetProcAddress (iphlpapi, "FlushIpNetTable2"); + if (!flush_fn) + { + if (GetLastError () == ERROR_PROC_NOT_FOUND) + return WSAEPFNOSUPPORT; + else + return GetLastError (); + } + } + return flush_fn (msg->family, msg->iface.index); +} + + +static VOID +HandleMessage (HANDLE pipe, DWORD bytes, DWORD count, LPHANDLE events, undo_lists_t *lists) +{ + DWORD read; + union { + message_header_t header; + address_message_t address; + route_message_t route; + flush_neighbors_message_t flush_neighbors; + } msg; + ack_message_t ack = { + .header = { + .type = msg_acknowledgement, + .size = sizeof (ack), + .message_id = -1 + }, + .error_number = ERROR_MESSAGE_DATA + }; + + read = ReadPipeAsync (pipe, &msg, bytes, count, events); + if (read != bytes || read < sizeof (msg.header) || read != msg.header.size) + goto out; + + ack.header.message_id = msg.header.message_id; + + switch (msg.header.type) + { + case msg_add_address: + case msg_del_address: + if (msg.header.size == sizeof (msg.address)) + ack.error_number = HandleAddressMessage (&msg.address, lists); + break; + + case msg_add_route: + case msg_del_route: + if (msg.header.size == sizeof (msg.route)) + ack.error_number = HandleRouteMessage (&msg.route, lists); + break; + + case msg_flush_neighbors: + if (msg.header.size == sizeof (msg.flush_neighbors)) + ack.error_number = HandleFlushNeighborsMessage (&msg.flush_neighbors); + break; + + default: + ack.error_number = ERROR_MESSAGE_TYPE; + break; + } + +out: + WritePipeAsync (pipe, &ack, sizeof (ack), count, events); +} + + +static VOID +Undo (undo_lists_t *lists) +{ + undo_type_t type; + for (type = 0; type < _undo_type_max; type++) + { + list_item_t **pnext = &(*lists)[type]; + while (*pnext) + { + list_item_t *item = *pnext; + switch (type) + { + case address: + DeleteAddress (item->data); + break; + + case route: + DeleteRoute (item->data); + break; + } + + /* Remove from the list and free memory */ + *pnext = item->next; + free (item->data); + free (item); + } + } +} + +static DWORD WINAPI +RunOpenvpn (LPVOID p) +{ + HANDLE pipe = p; + HANDLE ovpn_pipe, svc_pipe; + PTOKEN_USER svc_user, ovpn_user; + HANDLE svc_token = NULL, imp_token = NULL, pri_token = NULL; + HANDLE stdin_read = NULL, stdin_write = NULL; + HANDLE stdout_read = NULL, stdout_write = NULL; + DWORD pipe_mode, len, exit_code = 0; + STARTUP_DATA sud = { 0, 0, 0 }; + STARTUPINFOW startup_info; + PROCESS_INFORMATION proc_info; + LPVOID user_env = NULL; + TCHAR ovpn_pipe_name[36]; + LPCWSTR exe_path; + WCHAR *cmdline = NULL; + size_t cmdline_size; + undo_lists_t undo_lists; + + SECURITY_ATTRIBUTES inheritable = { + .nLength = sizeof (inheritable), + .lpSecurityDescriptor = NULL, + .bInheritHandle = TRUE + }; + + PACL ovpn_dacl; + EXPLICIT_ACCESS ea[2]; + SECURITY_DESCRIPTOR ovpn_sd; + SECURITY_ATTRIBUTES ovpn_sa = { + .nLength = sizeof (ovpn_sa), + .lpSecurityDescriptor = &ovpn_sd, + .bInheritHandle = FALSE + }; + + ZeroMemory (&ea, sizeof (ea)); + ZeroMemory (&startup_info, sizeof (startup_info)); + ZeroMemory (&undo_lists, sizeof (undo_lists)); + ZeroMemory (&proc_info, sizeof (proc_info)); + + if (!GetStartupData (pipe, &sud)) + goto out; + + if (!InitializeSecurityDescriptor (&ovpn_sd, SECURITY_DESCRIPTOR_REVISION)) + { + ReturnLastError (pipe, L"InitializeSecurityDescriptor"); + goto out; + } + + /* Get SID of user the service is running under */ + if (!OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &svc_token)) + { + ReturnLastError (pipe, L"OpenProcessToken"); + goto out; + } + len = 0; + svc_user = NULL; + while (!GetTokenInformation (svc_token, TokenUser, svc_user, len, &len)) + { + if (GetLastError () != ERROR_INSUFFICIENT_BUFFER) + { + ReturnLastError (pipe, L"GetTokenInformation (service token)"); + goto out; + } + free (svc_user); + svc_user = malloc (len); + if (svc_user == NULL) + { + ReturnLastError (pipe, L"malloc (service token user)"); + goto out; + } + } + if (!IsValidSid (svc_user->User.Sid)) + { + ReturnLastError (pipe, L"IsValidSid (service token user)"); + goto out; + } + + if (!ImpersonateNamedPipeClient (pipe)) + { + ReturnLastError (pipe, L"ImpersonateNamedPipeClient"); + goto out; + } + if (!OpenThreadToken (GetCurrentThread (), TOKEN_ALL_ACCESS, FALSE, &imp_token)) + { + ReturnLastError (pipe, L"OpenThreadToken"); + goto out; + } + len = 0; + ovpn_user = NULL; + while (!GetTokenInformation (imp_token, TokenUser, ovpn_user, len, &len)) + { + if (GetLastError () != ERROR_INSUFFICIENT_BUFFER) + { + ReturnLastError (pipe, L"GetTokenInformation (impersonation token)"); + goto out; + } + free (ovpn_user); + ovpn_user = malloc (len); + if (ovpn_user == NULL) + { + ReturnLastError (pipe, L"malloc (impersonation token user)"); + goto out; + } + } + if (!IsValidSid (ovpn_user->User.Sid)) + { + ReturnLastError (pipe, L"IsValidSid (impersonation token user)"); + goto out; + } + + /* OpenVPN process DACL entry for access by service and user */ + ea[0].grfAccessPermissions = SPECIFIC_RIGHTS_ALL | STANDARD_RIGHTS_ALL; + ea[0].grfAccessMode = SET_ACCESS; + ea[0].grfInheritance = NO_INHERITANCE; + ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID; + ea[0].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN; + ea[0].Trustee.ptstrName = (LPTSTR) svc_user->User.Sid; + ea[1].grfAccessPermissions = READ_CONTROL | SYNCHRONIZE | PROCESS_VM_READ | + SYNCHRONIZE | PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION; + ea[1].grfAccessMode = SET_ACCESS; + ea[1].grfInheritance = NO_INHERITANCE; + ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID; + ea[1].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN; + ea[1].Trustee.ptstrName = (LPTSTR) ovpn_user->User.Sid; + + /* Set owner and DACL of OpenVPN security descriptor */ + if (!SetSecurityDescriptorOwner (&ovpn_sd, svc_user->User.Sid, FALSE)) + { + ReturnLastError (pipe, L"SetSecurityDescriptorOwner"); + goto out; + } + if (SetEntriesInAcl (2, ea, NULL, &ovpn_dacl) != ERROR_SUCCESS) + { + ReturnLastError (pipe, L"SetEntriesInAcl"); + goto out; + } + if (!SetSecurityDescriptorDacl (&ovpn_sd, TRUE, ovpn_dacl, FALSE)) + { + ReturnLastError (pipe, L"SetSecurityDescriptorDacl"); + goto out; + } + + /* Create primary token from impersonation token */ + if (!DuplicateTokenEx (imp_token, TOKEN_ALL_ACCESS, NULL, 0, TokenPrimary, &pri_token)) + { + ReturnLastError (pipe, L"DuplicateTokenEx"); + goto out; + } + + if (!CreatePipe(&stdin_read, &stdin_write, &inheritable, 0) || + !CreatePipe(&stdout_read, &stdout_write, &inheritable, 0) || + !SetHandleInformation(stdin_write, HANDLE_FLAG_INHERIT, 0) || + !SetHandleInformation(stdout_read, HANDLE_FLAG_INHERIT, 0)) + { + ReturnLastError (pipe, L"CreatePipe"); + goto out; + } + + openvpn_sntprintf (ovpn_pipe_name, _countof (ovpn_pipe_name), + TEXT("\\\\.\\pipe\\openvpn\\service_%lu"), GetCurrentThreadId ()); + ovpn_pipe = CreateNamedPipe (ovpn_pipe_name, + PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_OVERLAPPED, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 1, 128, 128, 0, NULL); + if (ovpn_pipe == INVALID_HANDLE_VALUE) + { + ReturnLastError (pipe, L"CreateNamedPipe"); + goto out; + } + + svc_pipe = CreateFile (ovpn_pipe_name, GENERIC_READ | GENERIC_WRITE, 0, + &inheritable, OPEN_EXISTING, 0, NULL); + if (svc_pipe == INVALID_HANDLE_VALUE) + { + ReturnLastError (pipe, L"CreateFile"); + goto out; + } + + pipe_mode = PIPE_READMODE_MESSAGE; + if (!SetNamedPipeHandleState (svc_pipe, &pipe_mode, NULL, NULL)) + { + ReturnLastError (pipe, L"SetNamedPipeHandleState"); + goto out; + } + + cmdline_size = wcslen (sud.options) + 128; + cmdline = malloc (cmdline_size * sizeof (*cmdline)); + if (cmdline == NULL) + { + ReturnLastError (pipe, L"malloc"); + goto out; + } + openvpn_sntprintf (cmdline, cmdline_size, L"openvpn %s --msg-channel %lu", + sud.options, svc_pipe); + + if (!CreateEnvironmentBlock (&user_env, imp_token, FALSE)) + { + ReturnLastError (pipe, L"CreateEnvironmentBlock"); + goto out; + } + + startup_info.cb = sizeof (startup_info); + startup_info.lpDesktop = L"winsta0\\default"; + startup_info.dwFlags = STARTF_USESTDHANDLES; + startup_info.hStdInput = stdin_read; + startup_info.hStdOutput = stdout_write; + startup_info.hStdError = stdout_write; + +#ifdef UNICODE + exe_path = settings.exe_path; +#else + WCHAR wide_path[MAX_PATH]; + MultiByteToWideChar (CP_UTF8, 0, settings.exe_path, MAX_PATH, wide_path, MAX_PATH); + exe_path = wide_path; +#endif + + // TODO: make sure HKCU is correct or call LoadUserProfile() + if (!CreateProcessAsUserW (pri_token, exe_path, cmdline, &ovpn_sa, NULL, TRUE, + settings.priority | CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT, + user_env, sud.directory, &startup_info, &proc_info)) + { + ReturnLastError (pipe, L"CreateProcessAsUser"); + goto out; + } + + if (!RevertToSelf ()) + { + TerminateProcess (proc_info.hProcess, 1); + ReturnLastError (pipe, L"RevertToSelf"); + goto out; + } + + CloseHandleEx (&stdout_write); + CloseHandleEx (&stdin_read); + CloseHandleEx (&svc_pipe); + + DWORD input_size = wcslen (sud.std_input) * 2; + if (input_size) + { + DWORD written; + LPSTR input = malloc (input_size); + WideCharToMultiByte (CP_UTF8, 0, sud.std_input, -1, input, input_size, NULL, NULL); + WriteFile (stdin_write, input, strlen (input), &written, NULL); + free (input); + } + + + while (TRUE) + { + DWORD bytes = PeekNamedPipeAsync (ovpn_pipe, 1, &exit_event); + if (bytes == 0) + break; + + HandleMessage (ovpn_pipe, bytes, 1, &exit_event, &undo_lists); + } + + WaitForSingleObject (proc_info.hProcess, IO_TIMEOUT); + GetExitCodeProcess (proc_info.hProcess, &exit_code); + if (exit_code == STILL_ACTIVE) + TerminateProcess (proc_info.hProcess, 1); + else if (exit_code != 0) + ReturnOpenvpnOutput (pipe, stdout_read, 1, &exit_event); + + Undo (&undo_lists); + +out: + FlushFileBuffers (pipe); + DisconnectNamedPipe (pipe); + + free (ovpn_user); + free (svc_user); + free (cmdline); + DestroyEnvironmentBlock (user_env); + FreeStartupData (&sud); + CloseHandleEx (&proc_info.hProcess); + CloseHandleEx (&proc_info.hThread); + CloseHandleEx (&stdin_read); + CloseHandleEx (&stdin_write); + CloseHandleEx (&stdout_read); + CloseHandleEx (&stdout_write); + CloseHandleEx (&svc_token); + CloseHandleEx (&imp_token); + CloseHandleEx (&pri_token); + CloseHandleEx (&ovpn_pipe); + CloseHandleEx (&svc_pipe); + CloseHandleEx (&pipe); + + return 0; +} + + +static DWORD WINAPI +ServiceCtrlInteractive (DWORD ctrl_code, DWORD event, LPVOID data, LPVOID ctx) +{ + SERVICE_STATUS *status = ctx; + switch (ctrl_code) + { + case SERVICE_CONTROL_STOP: + status->dwCurrentState = SERVICE_STOP_PENDING; + ReportStatusToSCMgr (service, status); + if (exit_event) + SetEvent (exit_event); + return NO_ERROR; + + case SERVICE_CONTROL_INTERROGATE: + return NO_ERROR; + + default: + return ERROR_CALL_NOT_IMPLEMENTED; + } +} + + +static HANDLE +CreateClientPipeInstance (VOID) +{ + HANDLE pipe = NULL; + PACL old_dacl, new_dacl; + PSECURITY_DESCRIPTOR sd; + static EXPLICIT_ACCESS ea[2]; + static BOOL initialized = FALSE; + DWORD flags = PIPE_ACCESS_DUPLEX | WRITE_DAC | FILE_FLAG_OVERLAPPED; + + if (!initialized) + { + PSID everyone, anonymous; + + ConvertStringSidToSid (TEXT("S-1-1-0"), &everyone); + ConvertStringSidToSid (TEXT("S-1-5-7"), &anonymous); + + ea[0].grfAccessPermissions = FILE_GENERIC_WRITE; + ea[0].grfAccessMode = GRANT_ACCESS; + ea[0].grfInheritance = NO_INHERITANCE; + ea[0].Trustee.pMultipleTrustee = NULL; + ea[0].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE; + ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID; + ea[0].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN; + ea[0].Trustee.ptstrName = (LPTSTR) everyone; + + ea[1].grfAccessPermissions = 0; + ea[1].grfAccessMode = REVOKE_ACCESS; + ea[1].grfInheritance = NO_INHERITANCE; + ea[1].Trustee.pMultipleTrustee = NULL; + ea[1].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE; + ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID; + ea[1].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN; + ea[1].Trustee.ptstrName = (LPTSTR) anonymous; + + flags |= FILE_FLAG_FIRST_PIPE_INSTANCE; + initialized = TRUE; + } + + pipe = CreateNamedPipe (TEXT("\\\\.\\pipe\\openvpn\\service"), flags, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, + PIPE_UNLIMITED_INSTANCES, 1024, 1024, 0, NULL); + if (pipe == INVALID_HANDLE_VALUE) + { + MsgToEventLog (M_SYSERR, TEXT("Could not create named pipe")); + return INVALID_HANDLE_VALUE; + } + + if (GetSecurityInfo (pipe, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, + NULL, NULL, &old_dacl, NULL, &sd) != ERROR_SUCCESS) + { + MsgToEventLog (M_SYSERR, TEXT("Could not get pipe security info")); + return CloseHandleEx (&pipe); + } + + if (SetEntriesInAcl (2, ea, old_dacl, &new_dacl) != ERROR_SUCCESS) + { + MsgToEventLog (M_SYSERR, TEXT("Could not set entries in new acl")); + return CloseHandleEx (&pipe); + } + + if (SetSecurityInfo (pipe, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, + NULL, NULL, new_dacl, NULL) != ERROR_SUCCESS) + { + MsgToEventLog (M_SYSERR, TEXT("Could not set pipe security info")); + return CloseHandleEx (&pipe); + } + + return pipe; +} + + +static DWORD +UpdateWaitHandles (LPHANDLE *handles_ptr, LPDWORD count, + HANDLE io_event, HANDLE exit_event, list_item_t *threads) +{ + static DWORD size = 10; + static LPHANDLE handles = NULL; + DWORD pos = 0; + + if (handles == NULL) + { + handles = malloc (size * sizeof (HANDLE)); + if (handles == NULL) + return ERROR_OUTOFMEMORY; + } + + handles[pos++] = io_event; + + if (!threads) + handles[pos++] = exit_event; + + while (threads) + { + if (pos == size) + { + size += 10; + handles = realloc (handles, size * sizeof (HANDLE)); + if (handles == NULL) + return ERROR_OUTOFMEMORY; + } + handles[pos++] = threads->data; + threads = threads->next; + } + + *handles_ptr = handles; + *count = pos; + return NO_ERROR; +} + + +static VOID +FreeWaitHandles (LPHANDLE h) +{ + free (h); +} + + +VOID WINAPI +ServiceStartInteractive (DWORD dwArgc, LPTSTR *lpszArgv) +{ + HANDLE pipe, io_event = NULL; + OVERLAPPED overlapped; + DWORD error = NO_ERROR; + list_item_t *threads = NULL; + PHANDLE handles; + DWORD handle_count; + + service = RegisterServiceCtrlHandlerEx (interactive_service.name, ServiceCtrlInteractive, &status); + if (!service) + return; + + status.dwServiceType = SERVICE_WIN32_SHARE_PROCESS; + status.dwCurrentState = SERVICE_START_PENDING; + status.dwServiceSpecificExitCode = NO_ERROR; + status.dwWin32ExitCode = NO_ERROR; + status.dwWaitHint = 3000; + ReportStatusToSCMgr (service, &status); + + /* Read info from registry in key HKLM\SOFTWARE\OpenVPN */ + error = GetOpenvpnSettings (&settings); + if (error != ERROR_SUCCESS) + goto out; + + io_event = InitOverlapped (&overlapped); + exit_event = CreateEvent (NULL, FALSE, FALSE, NULL); + if (!exit_event || !io_event) + { + error = MsgToEventLog (M_SYSERR, TEXT("Could not create event")); + goto out; + } + + error = UpdateWaitHandles (&handles, &handle_count, io_event, exit_event, threads); + if (error != NO_ERROR) + goto out; + + pipe = CreateClientPipeInstance (); + if (pipe == INVALID_HANDLE_VALUE) + goto out; + + status.dwCurrentState = SERVICE_RUNNING; + status.dwWaitHint = 0; + ReportStatusToSCMgr (service, &status); + + while (TRUE) + { + if (ConnectNamedPipe (pipe, &overlapped) == FALSE && + GetLastError () != ERROR_PIPE_CONNECTED && + GetLastError () != ERROR_IO_PENDING) + { + MsgToEventLog (M_SYSERR, TEXT("Could not connect pipe")); + break; + } + + error = WaitForMultipleObjects (handle_count, handles, FALSE, INFINITE); + if (error == WAIT_OBJECT_0) + { + /* Client connected, spawn a worker thread for it */ + HANDLE next_pipe = CreateClientPipeInstance (); + HANDLE thread = CreateThread (NULL, 0, RunOpenvpn, pipe, CREATE_SUSPENDED, NULL); + if (thread) + { + error = AddListItem (&threads, thread) || + UpdateWaitHandles (&handles, &handle_count, io_event, exit_event, threads); + if (error) + { + TerminateThread (thread, 1); + CloseHandleEx (&thread); + CloseHandleEx (&pipe); + SetEvent (exit_event); + } + else + ResumeThread (thread); + } + else + CloseHandleEx (&pipe); + + ResetOverlapped (&overlapped); + pipe = next_pipe; + } + else + { + CancelIo (pipe); + if (error == WAIT_FAILED) + { + MsgToEventLog (M_SYSERR, TEXT("WaitForMultipleObjects failed")); + continue; + } + if (!threads) + { + /* exit event signaled */ + CloseHandleEx (&pipe); + error = NO_ERROR; + break; + } + + /* Worker thread ended */ + BOOL CmpHandle (LPVOID item, LPVOID hnd) { return item == hnd; } + HANDLE thread = RemoveListItem (&threads, CmpHandle, handles[error]); + UpdateWaitHandles (&handles, &handle_count, io_event, exit_event, threads); + CloseHandleEx (&thread); + } + } + +out: + FreeWaitHandles (handles); + CloseHandleEx (&io_event); + CloseHandleEx (&exit_event); + + status.dwCurrentState = SERVICE_STOPPED; + status.dwWin32ExitCode = error; + ReportStatusToSCMgr (service, &status); +} diff --git a/src/openvpnserv/openvpnserv.c b/src/openvpnserv/openvpnserv.c deleted file mode 100755 index 56f5a0250f7..00000000000 --- a/src/openvpnserv/openvpnserv.c +++ /dev/null @@ -1,534 +0,0 @@ -/* - * OpenVPN -- An application to securely tunnel IP networks - * over a single TCP/UDP port, with support for SSL/TLS-based - * session authentication and key exchange, - * packet encryption, packet authentication, and - * packet compression. - * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. - * - * 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 - */ - -/* - * This program allows one or more OpenVPN processes to be started - * as a service. To build, you must get the service sample from the - * Platform SDK and replace Simple.c with this file. - * - * You should also apply service.patch to - * service.c and service.h from the Platform SDK service sample. - * - * This code is designed to be built with the mingw compiler. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#elif defined(_MSC_VER) -#include "config-msvc.h" -#endif -#include -#include -#include -#include -#include -#include "service.h" - -/* bool definitions */ -#define bool int -#define true 1 -#define false 0 - -/* These are new for 2000/XP, so they aren't in the mingw headers yet */ -#ifndef BELOW_NORMAL_PRIORITY_CLASS -#define BELOW_NORMAL_PRIORITY_CLASS 0x00004000 -#endif -#ifndef ABOVE_NORMAL_PRIORITY_CLASS -#define ABOVE_NORMAL_PRIORITY_CLASS 0x00008000 -#endif - -struct security_attributes -{ - SECURITY_ATTRIBUTES sa; - SECURITY_DESCRIPTOR sd; -}; - -/* - * This event is initially created in the non-signaled - * state. It will transition to the signaled state when - * we have received a terminate signal from the Service - * Control Manager which will cause an asynchronous call - * of ServiceStop below. - */ -#define EXIT_EVENT_NAME PACKAGE "_exit_1" - -/* - * Which registry key in HKLM should - * we get config info from? - */ -#define REG_KEY "SOFTWARE\\" PACKAGE_NAME - -static HANDLE exit_event = NULL; - -/* clear an object */ -#define CLEAR(x) memset(&(x), 0, sizeof(x)) - -/* - * Message handling - */ -#define M_INFO (0) /* informational */ -#define M_SYSERR (MSG_FLAGS_ERROR|MSG_FLAGS_SYS_CODE) /* error + system code */ -#define M_ERR (MSG_FLAGS_ERROR) /* error */ - -/* write error to event log */ -#define MSG(flags, ...) \ - { \ - char x_msg[256]; \ - openvpn_snprintf (x_msg, sizeof(x_msg), __VA_ARGS__); \ - AddToMessageLog ((flags), x_msg); \ - } - -/* get a registry string */ -#define QUERY_REG_STRING(name, data) \ - { \ - len = sizeof (data); \ - status = RegQueryValueEx(openvpn_key, name, NULL, &type, data, &len); \ - if (status != ERROR_SUCCESS || type != REG_SZ) \ - { \ - SetLastError (status); \ - MSG (M_SYSERR, error_format_str, name); \ - RegCloseKey (openvpn_key); \ - goto finish; \ - } \ - } - -/* get a registry string */ -#define QUERY_REG_DWORD(name, data) \ - { \ - len = sizeof (DWORD); \ - status = RegQueryValueEx(openvpn_key, name, NULL, &type, (LPBYTE)&data, &len); \ - if (status != ERROR_SUCCESS || type != REG_DWORD || len != sizeof (DWORD)) \ - { \ - SetLastError (status); \ - MSG (M_SYSERR, error_format_dword, name); \ - RegCloseKey (openvpn_key); \ - goto finish; \ - } \ - } - -/* - * This is necessary due to certain buggy implementations of snprintf, - * that don't guarantee null termination for size > 0. - * (copied from ../buffer.c, line 217) - * (git: 100644 blob e2f8caab0a5b2a870092c6cd508a1a50c21c3ba3 buffer.c) - */ - -int openvpn_snprintf(char *str, size_t size, const char *format, ...) -{ - va_list arglist; - int len = -1; - if (size > 0) - { - va_start (arglist, format); - len = vsnprintf (str, size, format, arglist); - va_end (arglist); - str[size - 1] = 0; - } - return (len >= 0 && len < size); -} - - -bool -init_security_attributes_allow_all (struct security_attributes *obj) -{ - CLEAR (*obj); - - obj->sa.nLength = sizeof (SECURITY_ATTRIBUTES); - obj->sa.lpSecurityDescriptor = &obj->sd; - obj->sa.bInheritHandle = TRUE; - if (!InitializeSecurityDescriptor (&obj->sd, SECURITY_DESCRIPTOR_REVISION)) - return false; - if (!SetSecurityDescriptorDacl (&obj->sd, TRUE, NULL, FALSE)) - return false; - return true; -} - -HANDLE -create_event (const char *name, bool allow_all, bool initial_state, bool manual_reset) -{ - if (allow_all) - { - struct security_attributes sa; - if (!init_security_attributes_allow_all (&sa)) - return NULL; - return CreateEvent (&sa.sa, (BOOL)manual_reset, (BOOL)initial_state, name); - } - else - return CreateEvent (NULL, (BOOL)manual_reset, (BOOL)initial_state, name); -} - -void -close_if_open (HANDLE h) -{ - if (h != NULL) - CloseHandle (h); -} - -static bool -match (const WIN32_FIND_DATA *find, const char *ext) -{ - int i; - - if (find->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - return false; - - if (!strlen (ext)) - return true; - - i = strlen (find->cFileName) - strlen (ext) - 1; - if (i < 1) - return false; - - return find->cFileName[i] == '.' && !_stricmp (find->cFileName + i + 1, ext); -} - -/* - * Modify the extension on a filename. - */ -static bool -modext (char *dest, int size, const char *src, const char *newext) -{ - int i; - - if (size > 0 && (strlen (src) + 1) <= size) - { - strcpy (dest, src); - dest [size - 1] = '\0'; - i = strlen (dest); - while (--i >= 0) - { - if (dest[i] == '\\') - break; - if (dest[i] == '.') - { - dest[i] = '\0'; - break; - } - } - if (strlen (dest) + strlen(newext) + 2 <= size) - { - strcat (dest, "."); - strcat (dest, newext); - return true; - } - dest [0] = '\0'; - } - return false; -} - -VOID ServiceStart (DWORD dwArgc, LPTSTR *lpszArgv) -{ - char exe_path[MAX_PATH]; - char config_dir[MAX_PATH]; - char ext_string[16]; - char log_dir[MAX_PATH]; - char priority_string[64]; - char append_string[2]; - - DWORD priority; - bool append; - - ResetError (); - - if (!ReportStatusToSCMgr(SERVICE_START_PENDING, NO_ERROR, 3000)) - { - MSG (M_ERR, "ReportStatusToSCMgr #1 failed"); - goto finish; - } - - /* - * Create our exit event - */ - exit_event = create_event (EXIT_EVENT_NAME, false, false, true); - if (!exit_event) - { - MSG (M_ERR, "CreateEvent failed"); - goto finish; - } - - /* - * If exit event is already signaled, it means we were not - * shut down properly. - */ - if (WaitForSingleObject (exit_event, 0) != WAIT_TIMEOUT) - { - MSG (M_ERR, "Exit event is already signaled -- we were not shut down properly"); - goto finish; - } - - if (!ReportStatusToSCMgr(SERVICE_START_PENDING, NO_ERROR, 3000)) - { - MSG (M_ERR, "ReportStatusToSCMgr #2 failed"); - goto finish; - } - - /* - * Read info from registry in key HKLM\SOFTWARE\OpenVPN - */ - { - HKEY openvpn_key; - LONG status; - DWORD len; - DWORD type; - - static const char error_format_str[] = - "Error querying registry key of type REG_SZ: HKLM\\" REG_KEY "\\%s"; - - static const char error_format_dword[] = - "Error querying registry key of type REG_DWORD: HKLM\\" REG_KEY "\\%s"; - - status = RegOpenKeyEx( - HKEY_LOCAL_MACHINE, - REG_KEY, - 0, - KEY_READ, - &openvpn_key); - - if (status != ERROR_SUCCESS) - { - SetLastError (status); - MSG (M_SYSERR, "Registry key HKLM\\" REG_KEY " not found"); - goto finish; - } - - /* get path to openvpn.exe */ - QUERY_REG_STRING ("exe_path", exe_path); - - /* get path to configuration directory */ - QUERY_REG_STRING ("config_dir", config_dir); - - /* get extension on configuration files */ - QUERY_REG_STRING ("config_ext", ext_string); - - /* get path to log directory */ - QUERY_REG_STRING ("log_dir", log_dir); - - /* get priority for spawned OpenVPN subprocesses */ - QUERY_REG_STRING ("priority", priority_string); - - /* should we truncate or append to logfile? */ - QUERY_REG_STRING ("log_append", append_string); - - RegCloseKey (openvpn_key); - } - - /* set process priority */ - priority = NORMAL_PRIORITY_CLASS; - if (!_stricmp (priority_string, "IDLE_PRIORITY_CLASS")) - priority = IDLE_PRIORITY_CLASS; - else if (!_stricmp (priority_string, "BELOW_NORMAL_PRIORITY_CLASS")) - priority = BELOW_NORMAL_PRIORITY_CLASS; - else if (!_stricmp (priority_string, "NORMAL_PRIORITY_CLASS")) - priority = NORMAL_PRIORITY_CLASS; - else if (!_stricmp (priority_string, "ABOVE_NORMAL_PRIORITY_CLASS")) - priority = ABOVE_NORMAL_PRIORITY_CLASS; - else if (!_stricmp (priority_string, "HIGH_PRIORITY_CLASS")) - priority = HIGH_PRIORITY_CLASS; - else - { - MSG (M_ERR, "Unknown priority name: %s", priority_string); - goto finish; - } - - /* set log file append/truncate flag */ - append = false; - if (append_string[0] == '0') - append = false; - else if (append_string[0] == '1') - append = true; - else - { - MSG (M_ERR, "Log file append flag (given as '%s') must be '0' or '1'", append_string); - goto finish; - } - - /* - * Instantiate an OpenVPN process for each configuration - * file found. - */ - { - WIN32_FIND_DATA find_obj; - HANDLE find_handle; - BOOL more_files; - char find_string[MAX_PATH]; - - openvpn_snprintf (find_string, MAX_PATH, "%s\\*", config_dir); - - find_handle = FindFirstFile (find_string, &find_obj); - if (find_handle == INVALID_HANDLE_VALUE) - { - MSG (M_ERR, "Cannot get configuration file list using: %s", find_string); - goto finish; - } - - /* - * Loop over each config file - */ - do { - HANDLE log_handle = NULL; - STARTUPINFO start_info; - PROCESS_INFORMATION proc_info; - struct security_attributes sa; - char log_file[MAX_PATH]; - char log_path[MAX_PATH]; - char command_line[256]; - - CLEAR (start_info); - CLEAR (proc_info); - CLEAR (sa); - - if (!ReportStatusToSCMgr(SERVICE_START_PENDING, NO_ERROR, 3000)) - { - MSG (M_ERR, "ReportStatusToSCMgr #3 failed"); - FindClose (find_handle); - goto finish; - } - - /* does file have the correct type and extension? */ - if (match (&find_obj, ext_string)) - { - /* get log file pathname */ - if (!modext (log_file, sizeof (log_file), find_obj.cFileName, "log")) - { - MSG (M_ERR, "Cannot construct logfile name based on: %s", find_obj.cFileName); - FindClose (find_handle); - goto finish; - } - openvpn_snprintf (log_path, sizeof(log_path), - "%s\\%s", log_dir, log_file); - - /* construct command line */ - openvpn_snprintf (command_line, sizeof(command_line), PACKAGE " --service %s 1 --config \"%s\"", - EXIT_EVENT_NAME, - find_obj.cFileName); - - /* Make security attributes struct for logfile handle so it can - be inherited. */ - if (!init_security_attributes_allow_all (&sa)) - { - MSG (M_SYSERR, "InitializeSecurityDescriptor start_" PACKAGE " failed"); - goto finish; - } - - /* open logfile as stdout/stderr for soon-to-be-spawned subprocess */ - log_handle = CreateFile (log_path, - GENERIC_WRITE, - FILE_SHARE_READ, - &sa.sa, - append ? OPEN_ALWAYS : CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL, - NULL); - - if (log_handle == INVALID_HANDLE_VALUE) - { - MSG (M_SYSERR, "Cannot open logfile: %s", log_path); - FindClose (find_handle); - goto finish; - } - - /* append to logfile? */ - if (append) - { - if (SetFilePointer (log_handle, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER) - { - MSG (M_SYSERR, "Cannot seek to end of logfile: %s", log_path); - FindClose (find_handle); - goto finish; - } - } - - /* fill in STARTUPINFO struct */ - GetStartupInfo(&start_info); - start_info.cb = sizeof(start_info); - start_info.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW; - start_info.wShowWindow = SW_HIDE; - start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE); - start_info.hStdOutput = start_info.hStdError = log_handle; - - /* create an OpenVPN process for one config file */ - if (!CreateProcess(exe_path, - command_line, - NULL, - NULL, - TRUE, - priority | CREATE_NEW_CONSOLE, - NULL, - config_dir, - &start_info, - &proc_info)) - { - MSG (M_SYSERR, "CreateProcess failed, exe='%s' cmdline='%s' dir='%s'", - exe_path, - command_line, - config_dir); - - FindClose (find_handle); - CloseHandle (log_handle); - goto finish; - } - - /* close unneeded handles */ - Sleep (1000); /* try to prevent race if we close logfile - handle before child process DUPs it */ - if (!CloseHandle (proc_info.hProcess) - || !CloseHandle (proc_info.hThread) - || !CloseHandle (log_handle)) - { - MSG (M_SYSERR, "CloseHandle failed"); - goto finish; - } - } - - /* more files to process? */ - more_files = FindNextFile (find_handle, &find_obj); - - } while (more_files); - - FindClose (find_handle); - } - - /* we are now fully started */ - if (!ReportStatusToSCMgr(SERVICE_RUNNING, NO_ERROR, 0)) - { - MSG (M_ERR, "ReportStatusToSCMgr SERVICE_RUNNING failed"); - goto finish; - } - - /* wait for our shutdown signal */ - if (WaitForSingleObject (exit_event, INFINITE) != WAIT_OBJECT_0) - { - MSG (M_ERR, "wait for shutdown signal failed"); - } - - finish: - ServiceStop (); - if (exit_event) - CloseHandle (exit_event); -} - -VOID ServiceStop() -{ - if (exit_event) - SetEvent(exit_event); -} diff --git a/src/openvpnserv/service.c b/src/openvpnserv/service.c index d7562b38e9c..82f55512fc8 100644 --- a/src/openvpnserv/service.c +++ b/src/openvpnserv/service.c @@ -1,700 +1,245 @@ -/*--------------------------------------------------------------------------- -THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF -ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A -PARTICULAR PURPOSE. - -Copyright (C) 1993 - 2000. Microsoft Corporation. All rights reserved. - -MODULE: service.c - -PURPOSE: Implements functions required by all Windows NT services - -FUNCTIONS: - main(int argc, char **argv); - service_ctrl(DWORD dwCtrlCode); - service_main(DWORD dwArgc, LPTSTR *lpszArgv); - CmdInstallService(); - CmdRemoveService(); - CmdStartService(); - CmdDebugService(int argc, char **argv); - ControlHandler ( DWORD dwCtrlType ); - GetLastErrorText( LPTSTR lpszBuf, DWORD dwSize ); - ----------------------------------------------------------------------------*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#elif defined(_MSC_VER) -#include "config-msvc.h" -#endif -#include -#include -#include -#include -#include +/* + * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF + * ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED + * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A + * PARTICULAR PURPOSE. + * + * Copyright (C) 1993 - 2000. Microsoft Corporation. All rights reserved. + * 2013 Heiko Hund + */ #include "service.h" -// internal variables -SERVICE_STATUS ssStatus; // current status of the service -SERVICE_STATUS_HANDLE sshStatusHandle; -DWORD dwErr = 0; -BOOL bDebug = FALSE; -TCHAR szErr[256]; - -// internal function prototypes -VOID WINAPI service_ctrl(DWORD dwCtrlCode); -VOID WINAPI service_main(DWORD dwArgc, LPTSTR *lpszArgv); -int CmdInstallService(); -int CmdRemoveService(); -int CmdStartService(); -VOID CmdDebugService(int argc, char **argv); -BOOL WINAPI ControlHandler ( DWORD dwCtrlType ); -LPTSTR GetLastErrorText( LPTSTR lpszBuf, DWORD dwSize ); - -// -// FUNCTION: main -// -// PURPOSE: entrypoint for service -// -// PARAMETERS: -// argc - number of command line arguments -// argv - array of command line arguments -// -// RETURN VALUE: -// none -// -// COMMENTS: -// main() either performs the command line task, or -// call StartServiceCtrlDispatcher to register the -// main service thread. When the this call returns, -// the service has stopped, so exit. -// -int __cdecl main(int argc, char **argv) -{ - SERVICE_TABLE_ENTRY dispatchTable[] = - { - { TEXT(SZSERVICENAME), (LPSERVICE_MAIN_FUNCTION)service_main}, - { NULL, NULL} - }; - - if ( (argc > 1) && - ((*argv[1] == '-') || (*argv[1] == '/')) ) - { - if ( _stricmp( "install", argv[1]+1 ) == 0 ) - { - return CmdInstallService(); - } - else if ( _stricmp( "remove", argv[1]+1 ) == 0 ) - { - return CmdRemoveService(); - } - else if ( _stricmp( "start", argv[1]+1 ) == 0) - { - return CmdStartService(); - } - else if ( _stricmp( "debug", argv[1]+1 ) == 0 ) - { - bDebug = TRUE; - CmdDebugService(argc, argv); - } - else - { - goto dispatch; - } - return 0; - } - - // if it doesn't match any of the above parameters - // the service control manager may be starting the service - // so we must call StartServiceCtrlDispatcher - dispatch: - // this is just to be friendly - printf( "%s -install to install the service\n", SZAPPNAME ); - printf( "%s -start to start the service\n", SZAPPNAME ); - printf( "%s -remove to remove the service\n", SZAPPNAME ); - printf( "%s -debug to run as a console app for debugging\n", SZAPPNAME ); - printf( "\nStartServiceCtrlDispatcher being called.\n" ); - printf( "This may take several seconds. Please wait.\n" ); - - if (!StartServiceCtrlDispatcher(dispatchTable)) - AddToMessageLog(MSG_FLAGS_ERROR, TEXT("StartServiceCtrlDispatcher failed.")); - - return 0; -} - - - -// -// FUNCTION: service_main -// -// PURPOSE: To perform actual initialization of the service -// -// PARAMETERS: -// dwArgc - number of command line arguments -// lpszArgv - array of command line arguments -// -// RETURN VALUE: -// none -// -// COMMENTS: -// This routine performs the service initialization and then calls -// the user defined ServiceStart() routine to perform majority -// of the work. -// -void WINAPI service_main(DWORD dwArgc, LPTSTR *lpszArgv) -{ - - // register our service control handler: - // - sshStatusHandle = RegisterServiceCtrlHandler( TEXT(SZSERVICENAME), service_ctrl); - - if (!sshStatusHandle) - goto cleanup; - - // SERVICE_STATUS members that don't change in example - // - ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; - ssStatus.dwServiceSpecificExitCode = 0; - - - // report the status to the service control manager. - // - if (!ReportStatusToSCMgr( - SERVICE_START_PENDING, // service state - NO_ERROR, // exit code - 3000)) // wait hint - goto cleanup; - - - ServiceStart( dwArgc, lpszArgv ); - - cleanup: +#include +#include +#include - // try to report the stopped status to the service control manager. - // - if (sshStatusHandle) - (VOID)ReportStatusToSCMgr( - SERVICE_STOPPED, - dwErr, - 0); - return; -} +openvpn_service_t openvpn_service[_service_max]; - -// -// FUNCTION: service_ctrl -// -// PURPOSE: This function is called by the SCM whenever -// ControlService() is called on this service. -// -// PARAMETERS: -// dwCtrlCode - type of control requested -// -// RETURN VALUE: -// none -// -// COMMENTS: -// -VOID WINAPI service_ctrl(DWORD dwCtrlCode) +BOOL +ReportStatusToSCMgr (SERVICE_STATUS_HANDLE service, SERVICE_STATUS *status) { - // Handle the requested control code. - // - switch (dwCtrlCode) - { - // Stop the service. - // - // SERVICE_STOP_PENDING should be reported before - // setting the Stop Event - hServerStopEvent - in - // ServiceStop(). This avoids a race condition - // which may result in a 1053 - The Service did not respond... - // error. - case SERVICE_CONTROL_STOP: - ReportStatusToSCMgr(SERVICE_STOP_PENDING, NO_ERROR, 0); - ServiceStop(); - return; - - // Update the service status. - // - case SERVICE_CONTROL_INTERROGATE: - break; - - // invalid control code - // - default: - break; - - } - - ReportStatusToSCMgr(ssStatus.dwCurrentState, NO_ERROR, 0); + static DWORD dwCheckPoint = 1; + BOOL res = TRUE; + + if (status->dwCurrentState == SERVICE_START_PENDING) + status->dwControlsAccepted = 0; + else + status->dwControlsAccepted = SERVICE_ACCEPT_STOP; + + if (status->dwCurrentState == SERVICE_RUNNING || + status->dwCurrentState == SERVICE_STOPPED) + status->dwCheckPoint = 0; + else + status->dwCheckPoint = dwCheckPoint++; + + /* Report the status of the service to the service control manager. */ + res = SetServiceStatus (service, status); + if (!res) + MsgToEventLog(MSG_FLAGS_ERROR, TEXT("SetServiceStatus")); + + return res; } - - -// -// FUNCTION: ReportStatusToSCMgr() -// -// PURPOSE: Sets the current status of the service and -// reports it to the Service Control Manager -// -// PARAMETERS: -// dwCurrentState - the state of the service -// dwWin32ExitCode - error code to report -// dwWaitHint - worst case estimate to next checkpoint -// -// RETURN VALUE: -// TRUE - success -// FALSE - failure -// -// COMMENTS: -// -BOOL ReportStatusToSCMgr(DWORD dwCurrentState, - DWORD dwWin32ExitCode, - DWORD dwWaitHint) +static int +CmdInstallServices () { - static DWORD dwCheckPoint = 1; - BOOL fResult = TRUE; - - - if ( !bDebug ) // when debugging we don't report to the SCM - { - if (dwCurrentState == SERVICE_START_PENDING) - ssStatus.dwControlsAccepted = 0; - else - ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP; - - ssStatus.dwCurrentState = dwCurrentState; - ssStatus.dwWin32ExitCode = dwWin32ExitCode; - ssStatus.dwWaitHint = dwWaitHint; + SC_HANDLE service; + SC_HANDLE svc_ctl_mgr; + TCHAR path[512]; + int i, ret = _service_max; + + if (GetModuleFileName (NULL, path + 1, 510) == 0) + { + _tprintf (TEXT("Unable to install service - %s\n"), GetLastErrorText ()); + return 1; + } + + path[0] = TEXT('\"'); + _tcscat (path, TEXT("\"")); + + svc_ctl_mgr = OpenSCManager (NULL, NULL, SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE); + if (svc_ctl_mgr == NULL) + { + _tprintf (TEXT("OpenSCManager failed - %s\n"), GetLastErrorText ()); + return 1; + } - if ( ( dwCurrentState == SERVICE_RUNNING ) || - ( dwCurrentState == SERVICE_STOPPED ) ) - ssStatus.dwCheckPoint = 0; + for (i = 0; i < _service_max; i++) + { + service = CreateService (svc_ctl_mgr, + openvpn_service[i].name, + openvpn_service[i].display_name, + SERVICE_QUERY_STATUS, + SERVICE_WIN32_SHARE_PROCESS, + openvpn_service[i].start_type, + SERVICE_ERROR_NORMAL, + path, NULL, NULL, + openvpn_service[i].dependencies, + NULL, NULL); + if (service) + { + _tprintf (TEXT("%s installed.\n"), openvpn_service[i].display_name); + CloseServiceHandle (service); + --ret; + } else - ssStatus.dwCheckPoint = dwCheckPoint++; - + _tprintf (TEXT("CreateService failed - %s\n"), GetLastErrorText ()); + } - // Report the status of the service to the service control manager. - // - if (!(fResult = SetServiceStatus( sshStatusHandle, &ssStatus))) - { - AddToMessageLog(MSG_FLAGS_ERROR, TEXT("SetServiceStatus")); - } - } - return fResult; + CloseServiceHandle (svc_ctl_mgr); + return ret; } - -// -// FUNCTION: AddToMessageLog(LPTSTR lpszMsg) -// -// PURPOSE: Allows any thread to log an error message -// -// PARAMETERS: -// lpszMsg - text for message -// -// RETURN VALUE: -// none -// -// COMMENTS: -// -void AddToMessageLog(DWORD flags, LPTSTR lpszMsg) +static int +CmdStartService (openvpn_service_type type) { - TCHAR szMsg [(sizeof(SZSERVICENAME) / sizeof(TCHAR)) + 100 ]; - HANDLE hEventSource; - LPCSTR lpszStrings[2]; - - if ( !bDebug ) - { - if (flags & MSG_FLAGS_SYS_CODE) - dwErr = GetLastError(); - else - dwErr = 0; - - // Use event logging to log the error. - // - hEventSource = RegisterEventSource(NULL, TEXT(SZSERVICENAME)); - - _stprintf(szMsg, TEXT("%s error: %d"), TEXT(SZSERVICENAME), (int)dwErr); - lpszStrings[0] = szMsg; - lpszStrings[1] = lpszMsg; - - if (hEventSource != NULL) - { - ReportEvent(hEventSource, // handle of event source - // event type - (flags & MSG_FLAGS_ERROR) - ? EVENTLOG_ERROR_TYPE : EVENTLOG_INFORMATION_TYPE, - 0, // event category - 0, // event ID - NULL, // current user's SID - 2, // strings in lpszStrings - 0, // no bytes of raw data - lpszStrings, // array of error strings - NULL); // no raw data - - (VOID) DeregisterEventSource(hEventSource); - } - } -} - -void ResetError (void) -{ - dwErr = 0; -} + int ret = 1; + SC_HANDLE svc_ctl_mgr; + SC_HANDLE service; -/////////////////////////////////////////////////////////////////// -// -// The following code handles service installation and removal -// - - -// -// FUNCTION: CmdInstallService() -// -// PURPOSE: Installs the service -// -// PARAMETERS: -// none -// -// RETURN VALUE: -// 0 if success -// -// COMMENTS: -// -int CmdInstallService() -{ - SC_HANDLE schService; - SC_HANDLE schSCManager; - - TCHAR szPath[512]; - - int ret = 0; - - if ( GetModuleFileName( NULL, szPath+1, 510 ) == 0 ) - { - _tprintf(TEXT("Unable to install %s - %s\n"), TEXT(SZSERVICEDISPLAYNAME), GetLastErrorText(szErr, 256)); + svc_ctl_mgr = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS); + if (svc_ctl_mgr == NULL) + { + _tprintf (TEXT("OpenSCManager failed - %s\n"), GetLastErrorText ()); return 1; - } - szPath[0] = '\"'; - strcat(szPath, "\""); - - schSCManager = OpenSCManager( - NULL, // machine (NULL == local) - NULL, // database (NULL == default) - SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE // access required - ); - if ( schSCManager ) - { - schService = CreateService( - schSCManager, // SCManager database - TEXT(SZSERVICENAME), // name of service - TEXT(SZSERVICEDISPLAYNAME), // name to display - SERVICE_QUERY_STATUS, // desired access - SERVICE_WIN32_OWN_PROCESS, // service type - SERVICE_DEMAND_START, // start type -- alternative: SERVICE_AUTO_START - SERVICE_ERROR_NORMAL, // error control type - szPath, // service's binary - NULL, // no load ordering group - NULL, // no tag identifier - TEXT(SZDEPENDENCIES), // dependencies - NULL, // LocalSystem account - NULL); // no password - - if ( schService ) - { - _tprintf(TEXT("%s installed.\n"), TEXT(SZSERVICEDISPLAYNAME) ); - CloseServiceHandle(schService); - } - else - { - _tprintf(TEXT("CreateService failed - %s\n"), GetLastErrorText(szErr, 256)); - ret = 1; - } - - CloseServiceHandle(schSCManager); - } - else - { - _tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText(szErr,256)); - ret = 1; - } - return ret; -} - -// -// FUNCTION: CmdStartService() -// -// PURPOSE: Start the service -// -// PARAMETERS: -// none -// -// RETURN VALUE: -// 0 if success -// -// COMMENTS: - -int CmdStartService() -{ - int ret = 0; - - SC_HANDLE schSCManager; - SC_HANDLE schService; - - - // Open a handle to the SC Manager database. - schSCManager = OpenSCManager( - NULL, // local machine - NULL, // ServicesActive database - SC_MANAGER_ALL_ACCESS); // full access rights - - if (NULL == schSCManager) { - _tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText(szErr,256)); - ret = 1; } - schService = OpenService( - schSCManager, // SCM database - SZSERVICENAME, // service name - SERVICE_ALL_ACCESS); + service = OpenService (svc_ctl_mgr, openvpn_service[type].name, SERVICE_ALL_ACCESS); + if (service) + { + if (StartService (service, 0, NULL)) + { + _tprintf (TEXT("Service Started\n")); + ret = 0; + } + else + _tprintf (TEXT("StartService failed - %s\n"), GetLastErrorText ()); - if (schService == NULL) { - _tprintf(TEXT("OpenService failed - %s\n"), GetLastErrorText(szErr,256)); - ret = 1; + CloseServiceHandle(service); } - - if (!StartService( - schService, // handle to service - 0, // number of arguments - NULL) ) // no arguments + else { - _tprintf(TEXT("StartService failed - %s\n"), GetLastErrorText(szErr,256)); - ret = 1; + _tprintf (TEXT("OpenService failed - %s\n"), GetLastErrorText ()); } - else - { - _tprintf(TEXT("Service Started\n")); - ret = 0; - } - CloseServiceHandle(schService); - CloseServiceHandle(schSCManager); - return ret; -} -// -// FUNCTION: CmdRemoveService() -// -// PURPOSE: Stops and removes the service -// -// PARAMETERS: -// none -// -// RETURN VALUE: -// 0 if success -// -// COMMENTS: -// -int CmdRemoveService() -{ - SC_HANDLE schService; - SC_HANDLE schSCManager; + CloseServiceHandle(svc_ctl_mgr); + return ret; +} - int ret = 0; - schSCManager = OpenSCManager( - NULL, // machine (NULL == local) - NULL, // database (NULL == default) - SC_MANAGER_CONNECT // access required - ); - if ( schSCManager ) - { - schService = OpenService(schSCManager, TEXT(SZSERVICENAME), DELETE | SERVICE_STOP | SERVICE_QUERY_STATUS); +static int +CmdRemoveServices () +{ + SC_HANDLE service; + SC_HANDLE svc_ctl_mgr; + SERVICE_STATUS status; + int i, ret = _service_max; - if (schService) - { - // try to stop the service - if ( ControlService( schService, SERVICE_CONTROL_STOP, &ssStatus ) ) - { - _tprintf(TEXT("Stopping %s."), TEXT(SZSERVICEDISPLAYNAME)); - Sleep( 1000 ); + svc_ctl_mgr = OpenSCManager (NULL, NULL, SC_MANAGER_CONNECT); + if (svc_ctl_mgr == NULL) + { + _tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText ()); + return 1; + } - while ( QueryServiceStatus( schService, &ssStatus ) ) + for (i = 0; i < _service_max; i++) + { + openvpn_service_t *ovpn_svc = &openvpn_service[i]; + service = OpenService (svc_ctl_mgr, ovpn_svc->name, + DELETE | SERVICE_STOP | SERVICE_QUERY_STATUS); + if (service == NULL) + { + _tprintf (TEXT("OpenService failed - %s\n"), GetLastErrorText ()); + goto out; + } + + /* try to stop the service */ + if (ControlService (service, SERVICE_CONTROL_STOP, &status)) + { + _tprintf (TEXT("Stopping %s."), ovpn_svc->display_name); + Sleep (1000); + + while (QueryServiceStatus (service, &status)) { - if ( ssStatus.dwCurrentState == SERVICE_STOP_PENDING ) - { - _tprintf(TEXT(".")); - Sleep( 1000 ); - } - else - break; + if (status.dwCurrentState == SERVICE_STOP_PENDING) + { + _tprintf (TEXT(".")); + Sleep (1000); + } + else + break; } - if ( ssStatus.dwCurrentState == SERVICE_STOPPED ) - _tprintf(TEXT("\n%s stopped.\n"), TEXT(SZSERVICEDISPLAYNAME) ); - else - { - _tprintf(TEXT("\n%s failed to stop.\n"), TEXT(SZSERVICEDISPLAYNAME) ); - ret = 1; - } - - } - - // now remove the service - if ( DeleteService(schService) ) - _tprintf(TEXT("%s removed.\n"), TEXT(SZSERVICEDISPLAYNAME) ); - else - { - _tprintf(TEXT("DeleteService failed - %s\n"), GetLastErrorText(szErr,256)); - ret = 1; - } - - - CloseServiceHandle(schService); - } + if (status.dwCurrentState == SERVICE_STOPPED) + _tprintf (TEXT("\n%s stopped.\n"), ovpn_svc->display_name); + else + _tprintf (TEXT("\n%s failed to stop.\n"), ovpn_svc->display_name); + } + + /* now remove the service */ + if (DeleteService (service)) + { + _tprintf (TEXT("%s removed.\n"), ovpn_svc->display_name); + --ret; + } else - { - _tprintf(TEXT("OpenService failed - %s\n"), GetLastErrorText(szErr,256)); - ret = 1; - } - - CloseServiceHandle(schSCManager); - } - else - { - _tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText(szErr,256)); - ret = 1; - } - return ret; -} - - - - -/////////////////////////////////////////////////////////////////// -// -// The following code is for running the service as a console app -// - - -// -// FUNCTION: CmdDebugService(int argc, char ** argv) -// -// PURPOSE: Runs the service as a console application -// -// PARAMETERS: -// argc - number of command line arguments -// argv - array of command line arguments -// -// RETURN VALUE: -// none -// -// COMMENTS: -// -void CmdDebugService(int argc, char ** argv) -{ - DWORD dwArgc; - LPTSTR *lpszArgv; - -#ifdef UNICODE - lpszArgv = CommandLineToArgvW(GetCommandLineW(), &(dwArgc) ); - if (NULL == lpszArgv) - { - // CommandLineToArvW failed!! - _tprintf(TEXT("CmdDebugService CommandLineToArgvW returned NULL\n")); - return; - } -#else - dwArgc = (DWORD) argc; - lpszArgv = argv; -#endif - - _tprintf(TEXT("Debugging %s.\n"), TEXT(SZSERVICEDISPLAYNAME)); - - SetConsoleCtrlHandler( ControlHandler, TRUE ); + _tprintf (TEXT("DeleteService failed - %s\n"), GetLastErrorText ()); - ServiceStart( dwArgc, lpszArgv ); - -#ifdef UNICODE -// Must free memory allocated for arguments - - GlobalFree(lpszArgv); -#endif // UNICODE + CloseServiceHandle (service); + } +out: + CloseServiceHandle (svc_ctl_mgr); + return ret; } -// -// FUNCTION: ControlHandler ( DWORD dwCtrlType ) -// -// PURPOSE: Handled console control events -// -// PARAMETERS: -// dwCtrlType - type of control event -// -// RETURN VALUE: -// True - handled -// False - unhandled -// -// COMMENTS: -// -BOOL WINAPI ControlHandler ( DWORD dwCtrlType ) +int +_tmain (int argc, TCHAR *argv[]) { - switch ( dwCtrlType ) - { - case CTRL_BREAK_EVENT: // use Ctrl+C or Ctrl+Break to simulate - case CTRL_C_EVENT: // SERVICE_CONTROL_STOP in debug mode - _tprintf(TEXT("Stopping %s.\n"), TEXT(SZSERVICEDISPLAYNAME)); - ServiceStop(); - return TRUE; - break; - - } - return FALSE; -} - -// -// FUNCTION: GetLastErrorText -// -// PURPOSE: copies error message text to string -// -// PARAMETERS: -// lpszBuf - destination buffer -// dwSize - size of buffer -// -// RETURN VALUE: -// destination buffer -// -// COMMENTS: -// -LPTSTR GetLastErrorText( LPTSTR lpszBuf, DWORD dwSize ) -{ - DWORD dwRet; - LPTSTR lpszTemp = NULL; - - dwRet = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_ARGUMENT_ARRAY, - NULL, - GetLastError(), - LANG_NEUTRAL, - (LPTSTR)&lpszTemp, - 0, - NULL ); - - // supplied buffer is not long enough - if ( !dwRet || ( (long)dwSize < (long)dwRet+14 ) ) - lpszBuf[0] = TEXT('\0'); - else - { - lpszTemp[lstrlen(lpszTemp)-2] = TEXT('\0'); //remove cr and newline character - _stprintf( lpszBuf, TEXT("%s (0x%x)"), lpszTemp, (int)GetLastError() ); - } - - if ( lpszTemp ) - LocalFree((HLOCAL) lpszTemp ); - - return lpszBuf; + SERVICE_TABLE_ENTRY dispatchTable[] = { + { automatic_service.name, ServiceStartAutomatic }, + { interactive_service.name, ServiceStartInteractive }, + { NULL, NULL } + }; + + openvpn_service[0] = automatic_service; + openvpn_service[1] = interactive_service; + + if (argc > 1 && (*argv[1] == TEXT('-') || *argv[1] == TEXT('/'))) + { + if (_tcsicmp (TEXT("install"), argv[1] + 1) == 0) + return CmdInstallServices (); + else if (_tcsicmp (TEXT("remove"), argv[1] + 1) == 0) + return CmdRemoveServices (); + else if (_tcsicmp (TEXT("start"), argv[1] + 1) == 0) + { + BOOL is_auto = argc < 3 || _tcsicmp (TEXT("interactive"), argv[2]) != 0; + return CmdStartService (is_auto ? automatic : interactive); + } + else + goto dispatch; + + return 0; + } + + /* If it doesn't match any of the above parameters + * the service control manager may be starting the service + * so we must call StartServiceCtrlDispatcher + */ +dispatch: + _tprintf (TEXT("%s -install to install the services\n"), APPNAME); + _tprintf (TEXT("%s -start to start a service (\"automatic\" or \"interactive\")\n"), APPNAME); + _tprintf (TEXT("%s -remove to remove the services\n"), APPNAME); + _tprintf (TEXT("\nStartServiceCtrlDispatcher being called.\n")); + _tprintf (TEXT("This may take several seconds. Please wait.\n")); + + if (!StartServiceCtrlDispatcher (dispatchTable)) + MsgToEventLog (MSG_FLAGS_ERROR, TEXT("StartServiceCtrlDispatcher failed.")); + + return 0; } diff --git a/src/openvpnserv/service.h b/src/openvpnserv/service.h index e89a89fb51c..5249b316773 100644 --- a/src/openvpnserv/service.h +++ b/src/openvpnserv/service.h @@ -1,139 +1,90 @@ -/*--------------------------------------------------------------------------- -THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF -ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A -PARTICULAR PURPOSE. - -Copyright (C) 1993 - 2000. Microsoft Corporation. All rights reserved. - - MODULE: service.h - - Comments: The use of this header file and the accompanying service.c - file simplifies the process of writting a service. You as a developer - simply need to follow the TODO's outlined in this header file, and - implement the ServiceStart() and ServiceStop() functions. - - There is no need to modify the code in service.c. Just add service.c - to your project and link with the following libraries... - - libcmt.lib kernel32.lib advapi.lib shell32.lib - - This code also supports unicode. Be sure to compile both service.c and - and code #include "service.h" with the same Unicode setting. - - Upon completion, your code will have the following command line interface - - -? to display this list - -install to install the service - -remove to remove the service - -debug to run as a console app for debugging - - Note: This code also implements Ctrl+C and Ctrl+Break handlers - when using the debug option. These console events cause - your ServiceStop routine to be called - - Also, this code only handles the OWN_SERVICE service type - running in the LOCAL_SYSTEM security context. - - To control your service ( start, stop, etc ) you may use the - Services control panel applet or the NET.EXE program. - - To aid in writing/debugging service, the - SDK contains a utility (MSTOOLS\BIN\SC.EXE) that - can be used to control, configure, or obtain service status. - SC displays complete status for any service/driver - in the service database, and allows any of the configuration - parameters to be easily changed at the command line. - For more information on SC.EXE, type SC at the command line. - - -------------------------------------------------------------------------------*/ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single TCP/UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2013 Heiko Hund + * + * 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 _SERVICE_H #define _SERVICE_H - -#ifdef __cplusplus -extern "C" { +#ifdef HAVE_CONFIG_H +#include "config.h" +#elif defined(_MSC_VER) +#include "config-msvc.h" #endif -////////////////////////////////////////////////////////////////////////////// -//// todo: change to desired strings -//// -// name of the executable -#define SZAPPNAME PACKAGE "serv" -// internal name of the service -#define SZSERVICENAME PACKAGE_NAME "Service" -// displayed name of the service -#define SZSERVICEDISPLAYNAME PACKAGE_NAME " Service" -// list of service dependencies - "dep1\0dep2\0\0" -#define SZDEPENDENCIES TAP_WIN_COMPONENT_ID "\0Dhcp\0\0" -////////////////////////////////////////////////////////////////////////////// - - - -////////////////////////////////////////////////////////////////////////////// -//// todo: ServiceStart()must be defined by in your code. -//// The service should use ReportStatusToSCMgr to indicate -//// progress. This routine must also be used by StartService() -//// to report to the SCM when the service is running. -//// -//// If a ServiceStop procedure is going to take longer than -//// 3 seconds to execute, it should spawn a thread to -//// execute the stop code, and return. Otherwise, the -//// ServiceControlManager will believe that the service has -//// stopped responding -//// - VOID ServiceStart(DWORD dwArgc, LPTSTR *lpszArgv); - VOID ServiceStop(); -////////////////////////////////////////////////////////////////////////////// - - - -////////////////////////////////////////////////////////////////////////////// -//// The following are procedures which -//// may be useful to call within the above procedures, -//// but require no implementation by the user. -//// They are implemented in service.c - -// -// FUNCTION: ReportStatusToSCMgr() -// -// PURPOSE: Sets the current status of the service and -// reports it to the Service Control Manager -// -// PARAMETERS: -// dwCurrentState - the state of the service -// dwWin32ExitCode - error code to report -// dwWaitHint - worst case estimate to next checkpoint -// -// RETURN VALUE: -// TRUE - success -// FALSE - failure -// - BOOL ReportStatusToSCMgr(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint); - - -// -// FUNCTION: AddToMessageLog(LPTSTR lpszMsg) -// -// PURPOSE: Allows any thread to log an error message -// -// PARAMETERS: -// lpszMsg - text for message -// -// RETURN VALUE: -// none -// -# define MSG_FLAGS_ERROR (1<<0) -# define MSG_FLAGS_SYS_CODE (1<<1) - void AddToMessageLog(DWORD flags, LPTSTR lpszMsg); - void ResetError (void); -////////////////////////////////////////////////////////////////////////////// - - -#ifdef __cplusplus -} -#endif +#include +#include +#include + +#define APPNAME TEXT(PACKAGE "serv") +#define SERVICE_DEPENDENCIES TAP_WIN_COMPONENT_ID "\0Dhcp\0\0" + +/* + * Message handling + */ +#define MSG_FLAGS_ERROR (1<<0) +#define MSG_FLAGS_SYS_CODE (1<<1) +#define M_INFO (0) /* informational */ +#define M_SYSERR (MSG_FLAGS_ERROR|MSG_FLAGS_SYS_CODE) /* error + system code */ +#define M_ERR (MSG_FLAGS_ERROR) /* error */ + +typedef enum { + automatic, + interactive, + _service_max +} openvpn_service_type; + +typedef struct { + openvpn_service_type type; + TCHAR *name; + TCHAR *display_name; + TCHAR *dependencies; + DWORD start_type; +} openvpn_service_t; + +typedef struct { + TCHAR exe_path[MAX_PATH]; + TCHAR config_dir[MAX_PATH]; + TCHAR ext_string[16]; + TCHAR log_dir[MAX_PATH]; + DWORD priority; + BOOL append; +} settings_t; + +extern openvpn_service_t automatic_service; +extern openvpn_service_t interactive_service; + + +VOID WINAPI ServiceStartAutomatic (DWORD argc, LPTSTR *argv); +VOID WINAPI ServiceStartInteractive (DWORD argc, LPTSTR *argv); + +int openvpn_vsntprintf (LPTSTR str, size_t size, LPCTSTR format, va_list arglist); +int openvpn_sntprintf (LPTSTR str, size_t size, LPCTSTR format, ...); + +DWORD GetOpenvpnSettings (settings_t *s); + +BOOL ReportStatusToSCMgr (SERVICE_STATUS_HANDLE service, SERVICE_STATUS *status); + +LPCTSTR GetLastErrorText (); +DWORD MsgToEventLog (DWORD flags, LPCTSTR lpszMsg, ...); #endif From 70fbc5be209635739458267abde31b5cd4f770d0 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sun, 7 Feb 2016 20:47:09 +0100 Subject: [PATCH 187/643] Allow NULL argument in cipher_ctx_get_cipher_kt() Since otherwise we'll have to perform the check before each call. Signed-off-by: Steffan Karger Acked-by: Arne Schwabe Message-Id: <1454874438-5081-2-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/11079 Signed-off-by: Gert Doering --- src/openvpn/crypto_backend.h | 8 ++++---- src/openvpn/crypto_openssl.c | 2 +- src/openvpn/crypto_polarssl.c | 4 +--- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/openvpn/crypto_backend.h b/src/openvpn/crypto_backend.h index 4c1ce9fa6aa..1c23436485a 100644 --- a/src/openvpn/crypto_backend.h +++ b/src/openvpn/crypto_backend.h @@ -308,12 +308,12 @@ int cipher_ctx_mode (const cipher_ctx_t *ctx); /** * Returns the static cipher parameters for this context. * - * @param ctx Cipher's context. May not be NULL. + * @param ctx Cipher's context. * - * @return Static cipher parameters for the supplied context. + * @return Static cipher parameters for the supplied context, or + * NULL if unable to determine cipher parameters. */ -const cipher_kt_t *cipher_ctx_get_cipher_kt (const cipher_ctx_t *ctx) - __attribute__((nonnull)); +const cipher_kt_t *cipher_ctx_get_cipher_kt (const cipher_ctx_t *ctx); /** * Resets the given cipher context, setting the IV to the specified value. diff --git a/src/openvpn/crypto_openssl.c b/src/openvpn/crypto_openssl.c index 1d686623af8..7dabe5dfa48 100644 --- a/src/openvpn/crypto_openssl.c +++ b/src/openvpn/crypto_openssl.c @@ -585,7 +585,7 @@ cipher_ctx_mode (const EVP_CIPHER_CTX *ctx) const cipher_kt_t * cipher_ctx_get_cipher_kt (const cipher_ctx_t *ctx) { - return EVP_CIPHER_CTX_cipher(ctx); + return ctx ? EVP_CIPHER_CTX_cipher(ctx) : NULL; } diff --git a/src/openvpn/crypto_polarssl.c b/src/openvpn/crypto_polarssl.c index 407a1769dac..0e4c08839d5 100644 --- a/src/openvpn/crypto_polarssl.c +++ b/src/openvpn/crypto_polarssl.c @@ -506,9 +506,7 @@ int cipher_ctx_mode (const cipher_context_t *ctx) const cipher_kt_t * cipher_ctx_get_cipher_kt (const cipher_ctx_t *ctx) { - ASSERT(NULL != ctx); - - return ctx->cipher_info; + return ctx ? ctx->cipher_info : NULL; } int cipher_ctx_reset (cipher_context_t *ctx, uint8_t *iv_buf) From e7d78e407d41d48fbd91a71b2edfedcd2879b778 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sun, 7 Feb 2016 20:47:10 +0100 Subject: [PATCH 188/643] Remove reuse of key_type during init of data channel auth and tls-auth Prepare for using AEAD cipher modes + tls-auth, as tls-auth might want to use an HMAC, while the data channel uses e.g. GCM tags. This separates the two initialisations. Also, error out (and give a clear error message) if a user specifies tls-auth but no valid auth algorithm, which makes no sense at all. Signed-off-by: Steffan Karger Acked-by: Arne Schwabe Message-Id: <1454874438-5081-3-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/11073 Signed-off-by: Gert Doering --- src/openvpn/crypto.c | 9 ++------- src/openvpn/init.c | 25 +++++++++++++++++++------ src/openvpn/openvpn.h | 1 + 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c index c18d88bb22b..806a9950b71 100644 --- a/src/openvpn/crypto.c +++ b/src/openvpn/crypto.c @@ -751,13 +751,8 @@ get_tls_handshake_key (const struct key_type *key_type, if (passphrase_file && key_type->hmac_length) { struct key2 key2; - struct key_type kt = *key_type; struct key_direction_state kds; - /* for control channel we are only authenticating, not encrypting */ - kt.cipher_length = 0; - kt.cipher = NULL; - if (flags & GHK_INLINE) { /* key was specified inline, key text is in passphrase_file */ @@ -800,9 +795,9 @@ get_tls_handshake_key (const struct key_type *key_type, /* initialize hmac key in both directions */ - init_key_ctx (&ctx->encrypt, &key2.keys[kds.out_key], &kt, OPENVPN_OP_ENCRYPT, + init_key_ctx (&ctx->encrypt, &key2.keys[kds.out_key], key_type, OPENVPN_OP_ENCRYPT, "Outgoing Control Channel Authentication"); - init_key_ctx (&ctx->decrypt, &key2.keys[kds.in_key], &kt, OPENVPN_OP_DECRYPT, + init_key_ctx (&ctx->decrypt, &key2.keys[kds.in_key], key_type, OPENVPN_OP_DECRYPT, "Incoming Control Channel Authentication"); CLEAR (key2); diff --git a/src/openvpn/init.c b/src/openvpn/init.c index d0020b76bb7..7e6e448101c 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -2206,11 +2206,23 @@ do_init_crypto_tls_c1 (struct context *c) flags |= GHK_INLINE; file = options->tls_auth_file_inline; } - get_tls_handshake_key (&c->c1.ks.key_type, - &c->c1.ks.tls_auth_key, - file, - options->key_direction, - flags); + + /* Initialize key_type for tls-auth with auth only */ + CLEAR (c->c1.ks.tls_auth_key_type); + if (options->authname && options->authname_defined) + { + c->c1.ks.tls_auth_key_type.digest = md_kt_get (options->authname); + c->c1.ks.tls_auth_key_type.hmac_length = + md_kt_size (c->c1.ks.tls_auth_key_type.digest); + } + else + { + msg (M_FATAL, "ERROR: tls-auth enabled, but no valid --auth " + "algorithm specified ('%s')", options->authname); + } + + get_tls_handshake_key (&c->c1.ks.tls_auth_key_type, + &c->c1.ks.tls_auth_key, file, options->key_direction, flags); } #if 0 /* was: #if ENABLE_INLINE_FILES -- Note that enabling this code will break restarts */ @@ -2375,7 +2387,7 @@ do_init_crypto_tls (struct context *c, const unsigned int flags) to.tls_auth.pid_persist = &c->c1.pid_persist; to.tls_auth.flags |= CO_PACKET_ID_LONG_FORM; crypto_adjust_frame_parameters (&to.frame, - &c->c1.ks.key_type, + &c->c1.ks.tls_auth_key_type, false, false, true, true); } @@ -3758,6 +3770,7 @@ inherit_context_child (struct context *dest, /* inherit SSL context */ dest->c1.ks.ssl_ctx = src->c1.ks.ssl_ctx; dest->c1.ks.tls_auth_key = src->c1.ks.tls_auth_key; + dest->c1.ks.tls_auth_key_type = src->c1.ks.tls_auth_key_type; #endif /* options */ diff --git a/src/openvpn/openvpn.h b/src/openvpn/openvpn.h index 3f1df6ec44f..71adf4814e4 100644 --- a/src/openvpn/openvpn.h +++ b/src/openvpn/openvpn.h @@ -66,6 +66,7 @@ struct key_schedule struct tls_root_ctx ssl_ctx; /* optional authentication HMAC key for TLS control channel */ + struct key_type tls_auth_key_type; struct key_ctx_bi tls_auth_key; #else /* ENABLE_CRYPTO */ int dummy; From 2d9c6d20e6e98f852930ea96dae9bd912d34068e Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sun, 7 Feb 2016 20:47:11 +0100 Subject: [PATCH 189/643] Move crypto_options into key_state and stop using context in SSL-mode. Moving crypto_options into key_state enables us to stop using the global context for each packet encrypt/decrypt operation. Decoupling the crypto from the global context removes the need to copy the relevant parts of crypto_options for each processed packet, but instead enables us to just pass along a pointer to the related crypto_options. This paves the way for an efficient GCM cipher mode implementation, but is probably fruitful too for threading and/or cipher negotiation. Signed-off-by: Steffan Karger Acked-by: Arne Schwabe Message-Id: <1454874438-5081-4-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/11075 Signed-off-by: Gert Doering --- src/openvpn/forward.c | 18 ++++++++++++++---- src/openvpn/init.c | 21 +++++++++++++-------- src/openvpn/ssl.c | 36 +++++++++++++++--------------------- src/openvpn/ssl.h | 15 +++++++-------- src/openvpn/ssl_common.h | 2 ++ 5 files changed, 51 insertions(+), 41 deletions(-) diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c index 36a99e6f7df..75cd21decef 100644 --- a/src/openvpn/forward.c +++ b/src/openvpn/forward.c @@ -432,6 +432,7 @@ encrypt_sign (struct context *c, bool comp_frag) { struct context_buffers *b = c->c2.buffers; const uint8_t *orig_buf = c->c2.buf.data; + struct crypto_options *co = NULL; #if P2MP_SERVER /* @@ -462,14 +463,18 @@ encrypt_sign (struct context *c, bool comp_frag) */ if (c->c2.tls_multi) { - tls_pre_encrypt (c->c2.tls_multi, &c->c2.buf, &c->c2.crypto_options); + tls_pre_encrypt (c->c2.tls_multi, &c->c2.buf, &co); + } + else + { + co = &c->c2.crypto_options; } /* * Encrypt the packet and write an optional * HMAC signature. */ - openvpn_encrypt (&c->c2.buf, b->encrypt_buf, &c->c2.crypto_options, &c->c2.frame); + openvpn_encrypt (&c->c2.buf, b->encrypt_buf, co, &c->c2.frame); #endif /* * Get the address we will be sending the packet to. @@ -774,6 +779,7 @@ process_incoming_link_part1 (struct context *c, struct link_socket_info *lsi, bo */ if (c->c2.buf.len > 0) { + struct crypto_options *co = NULL; if (!link_socket_verify_incoming_addr (&c->c2.buf, lsi, &c->c2.from)) link_socket_bad_incoming_addr (&c->c2.buf, lsi, &c->c2.from); @@ -790,7 +796,7 @@ process_incoming_link_part1 (struct context *c, struct link_socket_info *lsi, bo * will load crypto_options with the correct encryption key * and return false. */ - if (tls_pre_decrypt (c->c2.tls_multi, &c->c2.from, &c->c2.buf, &c->c2.crypto_options, floated)) + if (tls_pre_decrypt (c->c2.tls_multi, &c->c2.from, &c->c2.buf, &co, floated)) { interval_action (&c->c2.tmp_int); @@ -799,6 +805,10 @@ process_incoming_link_part1 (struct context *c, struct link_socket_info *lsi, bo event_timeout_reset (&c->c2.ping_rec_interval); } } + else + { + co = &c->c2.crypto_options; + } #if P2MP_SERVER /* * Drop non-TLS packet if client-connect script/plugin has not @@ -809,7 +819,7 @@ process_incoming_link_part1 (struct context *c, struct link_socket_info *lsi, bo #endif /* authenticate and decrypt the incoming packet */ - decrypt_status = openvpn_decrypt (&c->c2.buf, c->c2.buffers->decrypt_buf, &c->c2.crypto_options, &c->c2.frame); + decrypt_status = openvpn_decrypt (&c->c2.buf, c->c2.buffers->decrypt_buf, co, &c->c2.frame); if (!decrypt_status && link_socket_connection_oriented (c->c2.link_socket)) { diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 7e6e448101c..8fc5c5dfcb7 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -2048,14 +2048,6 @@ init_crypto_pre (struct context *c, const unsigned int flags) packet_id_persist_load (&c->c1.pid_persist, c->options.packet_id_file); } - /* Initialize crypto options */ - - if (c->options.use_iv) - c->c2.crypto_options.flags |= CO_USE_IV; - - if (c->options.mute_replay_warnings) - c->c2.crypto_options.flags |= CO_MUTE_REPLAY_WARNINGS; - #ifdef ENABLE_PREDICTION_RESISTANCE if (c->options.use_prediction_resistance) rand_ctx_enable_prediction_resistance(); @@ -2074,6 +2066,13 @@ do_init_crypto_static (struct context *c, const unsigned int flags) init_crypto_pre (c, flags); + /* Initialize flags */ + if (c->options.use_iv) + c->c2.crypto_options.flags |= CO_USE_IV; + + if (c->options.mute_replay_warnings) + c->c2.crypto_options.flags |= CO_MUTE_REPLAY_WARNINGS; + /* Initialize packet ID tracking */ if (options->replay) { @@ -2277,6 +2276,12 @@ do_init_crypto_tls (struct context *c, const unsigned int flags) /* Set all command-line TLS-related options */ CLEAR (to); + if (options->use_iv) + to.crypto_flags |= CO_USE_IV; + + if (options->mute_replay_warnings) + to.crypto_flags |= CO_MUTE_REPLAY_WARNINGS; + to.crypto_flags_and = ~(CO_PACKET_ID_LONG_FORM); if (packet_id_long_form) to.crypto_flags_or = CO_PACKET_ID_LONG_FORM; diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index d39f131dba8..6aa92844900 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -786,6 +786,13 @@ key_state_init (struct tls_session *session, struct key_state *ks) session->opt->replay_time, "SSL", ks->key_id); + ks->crypto_options.key_ctx_bi = &ks->key; + ks->crypto_options.packet_id = session->opt->replay ? &ks->packet_id : NULL; + ks->crypto_options.pid_persist = NULL; + ks->crypto_options.flags = session->opt->crypto_flags; + ks->crypto_options.flags &= session->opt->crypto_flags_and; + ks->crypto_options.flags |= session->opt->crypto_flags_or; + #ifdef MANAGEMENT_DEF_AUTH ks->mda_key_id = session->opt->mda_context->mda_key_id_counter++; #endif @@ -1700,6 +1707,8 @@ key_state_soft_reset (struct tls_session *session) ks->must_die = now + session->opt->transition_window; /* remaining lifetime of old key */ key_state_free (ks_lame, false); *ks_lame = *ks; + ks_lame->crypto_options.key_ctx_bi = &ks_lame->key; + ks_lame->crypto_options.packet_id = &ks_lame->packet_id; key_state_init (session, ks); ks->session_id_remote = ks_lame->session_id_remote; @@ -2808,7 +2817,7 @@ bool tls_pre_decrypt (struct tls_multi *multi, const struct link_socket_actual *from, struct buffer *buf, - struct crypto_options *opt, + struct crypto_options **opt, bool floated) { struct gc_arena gc = gc_new (); @@ -2856,12 +2865,7 @@ tls_pre_decrypt (struct tls_multi *multi, && (floated || link_socket_actual_match (from, &ks->remote_addr))) { /* return appropriate data channel decrypt key in opt */ - opt->key_ctx_bi = &ks->key; - opt->packet_id = multi->opt.replay ? &ks->packet_id : NULL; - opt->pid_persist = NULL; - opt->flags &= multi->opt.crypto_flags_and; - opt->flags |= multi->opt.crypto_flags_or; - + *opt = &ks->crypto_options; ASSERT (buf_advance (buf, 1)); if (op == P_DATA_V2) { @@ -3251,10 +3255,7 @@ tls_pre_decrypt (struct tls_multi *multi, done: buf->len = 0; - opt->key_ctx_bi = NULL; - opt->packet_id = NULL; - opt->pid_persist = NULL; - opt->flags &= multi->opt.crypto_flags_and; + *opt = NULL; gc_free (&gc); return ret; @@ -3380,7 +3381,7 @@ tls_pre_decrypt_lite (const struct tls_auth_standalone *tas, /* Choose the key with which to encrypt a data packet */ void tls_pre_encrypt (struct tls_multi *multi, - struct buffer *buf, struct crypto_options *opt) + struct buffer *buf, struct crypto_options **opt) { multi->save_ks = NULL; if (buf->len > 0) @@ -3409,11 +3410,7 @@ tls_pre_encrypt (struct tls_multi *multi, if (ks_select) { - opt->key_ctx_bi = &ks_select->key; - opt->packet_id = multi->opt.replay ? &ks_select->packet_id : NULL; - opt->pid_persist = NULL; - opt->flags &= multi->opt.crypto_flags_and; - opt->flags |= multi->opt.crypto_flags_or; + *opt = &ks_select->crypto_options; multi->save_ks = ks_select; dmsg (D_TLS_KEYSELECT, "TLS: tls_pre_encrypt: key_id=%d", ks_select->key_id); return; @@ -3428,10 +3425,7 @@ tls_pre_encrypt (struct tls_multi *multi, } buf->len = 0; - opt->key_ctx_bi = NULL; - opt->packet_id = NULL; - opt->pid_persist = NULL; - opt->flags &= multi->opt.crypto_flags_and; + *opt = NULL; } /* Prepend the appropriate opcode to encrypted buffer prior to TCP/UDP send */ diff --git a/src/openvpn/ssl.h b/src/openvpn/ssl.h index 797c3e5d540..e9d0f28bc8b 100644 --- a/src/openvpn/ssl.h +++ b/src/openvpn/ssl.h @@ -293,9 +293,8 @@ int tls_multi_process (struct tls_multi *multi, * of this packet. * @param from - The source address of the packet. * @param buf - A buffer structure containing the incoming packet. - * @param opt - A crypto options structure that will be loaded with the - * appropriate security parameters to handle the packet if it is a - * data channel packet. + * @param opt - Returns a crypto options structure with the appropriate security + * parameters to handle the packet if it is a data channel packet. * * @return * @li True if the packet is a control channel packet that has been @@ -306,7 +305,7 @@ int tls_multi_process (struct tls_multi *multi, bool tls_pre_decrypt (struct tls_multi *multi, const struct link_socket_actual *from, struct buffer *buf, - struct crypto_options *opt, + struct crypto_options **opt, bool floated); @@ -356,15 +355,15 @@ bool tls_pre_decrypt_lite (const struct tls_auth_standalone *tas, * @ingroup data_crypto * * If no appropriate security parameters can be found, or if some other - * error occurs, then the buffer is set to empty. + * error occurs, then the buffer is set to empty, and the parameters to a NULL + * pointer. * * @param multi - The TLS state for this packet's destination VPN tunnel. * @param buf - The buffer containing the outgoing packet. - * @param opt - The crypto options structure into which the appropriate - * security parameters should be loaded. + * @param opt - Returns a crypto options structure with the security parameters. */ void tls_pre_encrypt (struct tls_multi *multi, - struct buffer *buf, struct crypto_options *opt); + struct buffer *buf, struct crypto_options **opt); /** diff --git a/src/openvpn/ssl_common.h b/src/openvpn/ssl_common.h index e2b0ebf0f74..00d2ce87bff 100644 --- a/src/openvpn/ssl_common.h +++ b/src/openvpn/ssl_common.h @@ -162,6 +162,7 @@ struct key_state struct link_socket_actual remote_addr; /* peer's IP addr */ struct packet_id packet_id; /* for data channel, to prevent replay attacks */ + struct crypto_options crypto_options;/* data channel crypto options */ struct key_ctx_bi key; /* data channel keys for encrypt/decrypt/hmac */ struct key_source2 *key_src; /* source entropy for key expansion */ @@ -259,6 +260,7 @@ struct tls_options bool pass_config_info; /* struct crypto_option flags */ + unsigned int crypto_flags; unsigned int crypto_flags_and; unsigned int crypto_flags_or; From 8b1a00ca4be11f03238c27b0f9a54573b707ba89 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sun, 7 Feb 2016 20:47:12 +0100 Subject: [PATCH 190/643] Move key_ctx_bi into crypto_options The encrypt and decrypt routines use struct crypto_options as their main information source. A struct crypto_options would have a pointer to a struct key_ctx_bi, which had to be updated at the correct moments to keep them correct. Instead of doing this administration, just put the struct key_ctx_bi inside crypto_options. Makes the code a little simpler too. Signed-off-by: Steffan Karger Acked-by: Arne Schwabe Message-Id: <1454874438-5081-5-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/11078 Signed-off-by: Gert Doering --- src/openvpn/crypto.c | 8 ++++---- src/openvpn/crypto.h | 2 +- src/openvpn/init.c | 4 ++-- src/openvpn/ssl.c | 32 ++++++++++++++------------------ src/openvpn/ssl.h | 1 - src/openvpn/ssl_common.h | 2 -- 6 files changed, 21 insertions(+), 28 deletions(-) diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c index 806a9950b71..9679fd0da95 100644 --- a/src/openvpn/crypto.c +++ b/src/openvpn/crypto.c @@ -91,9 +91,9 @@ openvpn_encrypt (struct buffer *buf, struct buffer work, struct gc_arena gc; gc_init (&gc); - if (buf->len > 0 && opt->key_ctx_bi) + if (buf->len > 0 && opt) { - struct key_ctx *ctx = &opt->key_ctx_bi->encrypt; + const struct key_ctx *ctx = &opt->key_ctx_bi.encrypt; /* Do Encrypt from buf -> work */ if (ctx->cipher) @@ -240,9 +240,9 @@ openvpn_decrypt (struct buffer *buf, struct buffer work, struct gc_arena gc; gc_init (&gc); - if (buf->len > 0 && opt->key_ctx_bi) + if (buf->len > 0 && opt) { - struct key_ctx *ctx = &opt->key_ctx_bi->decrypt; + const struct key_ctx *ctx = &opt->key_ctx_bi.decrypt; struct packet_id_net pin; bool have_pin = false; diff --git a/src/openvpn/crypto.h b/src/openvpn/crypto.h index b32a90018b1..1f84284dcea 100644 --- a/src/openvpn/crypto.h +++ b/src/openvpn/crypto.h @@ -207,7 +207,7 @@ struct key_ctx_bi */ struct crypto_options { - struct key_ctx_bi *key_ctx_bi; + struct key_ctx_bi key_ctx_bi; /**< OpenSSL cipher and HMAC contexts for * both sending and receiving * directions. */ diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 8fc5c5dfcb7..dcc3ccbbeac 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -2134,7 +2134,7 @@ do_init_crypto_static (struct context *c, const unsigned int flags) } /* Get key schedule */ - c->c2.crypto_options.key_ctx_bi = &c->c1.ks.static_key; + c->c2.crypto_options.key_ctx_bi = c->c1.ks.static_key; /* Compute MTU parameters */ crypto_adjust_frame_parameters (&c->c2.frame, @@ -2388,7 +2388,7 @@ do_init_crypto_tls (struct context *c, const unsigned int flags) /* TLS handshake authentication (--tls-auth) */ if (options->tls_auth_file) { - to.tls_auth_key = c->c1.ks.tls_auth_key; + to.tls_auth.key_ctx_bi = c->c1.ks.tls_auth_key; to.tls_auth.pid_persist = &c->c1.pid_persist; to.tls_auth.flags |= CO_PACKET_ID_LONG_FORM; crypto_adjust_frame_parameters (&to.frame, diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 6aa92844900..e3a745d1d84 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -786,7 +786,6 @@ key_state_init (struct tls_session *session, struct key_state *ks) session->opt->replay_time, "SSL", ks->key_id); - ks->crypto_options.key_ctx_bi = &ks->key; ks->crypto_options.packet_id = session->opt->replay ? &ks->packet_id : NULL; ks->crypto_options.pid_persist = NULL; ks->crypto_options.flags = session->opt->crypto_flags; @@ -819,7 +818,7 @@ key_state_free (struct key_state *ks, bool clear) key_state_ssl_free(&ks->ks_ssl); - free_key_ctx_bi (&ks->key); + free_key_ctx_bi (&ks->crypto_options.key_ctx_bi); free_buf (&ks->plaintext_read_buf); free_buf (&ks->plaintext_write_buf); free_buf (&ks->ack_write_buf); @@ -1072,9 +1071,6 @@ tls_multi_init (struct tls_options *tls_options) /* get command line derived options */ ret->opt = *tls_options; - /* set up pointer to HMAC object for TLS packet authentication */ - ret->opt.tls_auth.key_ctx_bi = &ret->opt.tls_auth_key; - /* set up list of keys to be scanned by data channel encrypt and decrypt routines */ ASSERT (SIZE (ret->key_scan) == 3); ret->key_scan[0] = &ret->session[TM_ACTIVE].key[KS_PRIMARY]; @@ -1113,8 +1109,7 @@ tls_auth_standalone_init (struct tls_options *tls_options, ALLOC_OBJ_CLEAR_GC (tas, struct tls_auth_standalone, gc); /* set up pointer to HMAC object for TLS packet authentication */ - tas->tls_auth_key = tls_options->tls_auth_key; - tas->tls_auth_options.key_ctx_bi = &tas->tls_auth_key; + tas->tls_auth_options.key_ctx_bi = tls_options->tls_auth.key_ctx_bi; tas->tls_auth_options.flags |= CO_PACKET_ID_LONG_FORM; /* get initial frame parms, still need to finalize */ @@ -1197,11 +1192,11 @@ tls_multi_free (struct tls_multi *multi, bool clear) static bool swap_hmac (struct buffer *buf, const struct crypto_options *co, bool incoming) { - struct key_ctx *ctx; + const struct key_ctx *ctx; ASSERT (co); - ctx = (incoming ? &co->key_ctx_bi->decrypt : &co->key_ctx_bi->encrypt); + ctx = (incoming ? &co->key_ctx_bi.decrypt : &co->key_ctx_bi.encrypt); ASSERT (ctx->hmac); { @@ -1265,7 +1260,7 @@ write_control_auth (struct tls_session *session, ASSERT (session_id_write_prepend (&session->session_id, buf)); ASSERT (header = buf_prepend (buf, 1)); *header = ks->key_id | (opcode << P_OPCODE_SHIFT); - if (session->tls_auth.key_ctx_bi->encrypt.hmac) + if (session->tls_auth.key_ctx_bi.encrypt.hmac) { /* no encryption, only write hmac */ openvpn_encrypt (buf, null, &session->tls_auth, NULL); @@ -1284,7 +1279,7 @@ read_control_auth (struct buffer *buf, { struct gc_arena gc = gc_new (); - if (co->key_ctx_bi->decrypt.hmac) + if (co->key_ctx_bi.decrypt.hmac) { struct buffer null = clear_buf (); @@ -1707,7 +1702,6 @@ key_state_soft_reset (struct tls_session *session) ks->must_die = now + session->opt->transition_window; /* remaining lifetime of old key */ key_state_free (ks_lame, false); *ks_lame = *ks; - ks_lame->crypto_options.key_ctx_bi = &ks_lame->key; ks_lame->crypto_options.packet_id = &ks_lame->packet_id; key_state_init (session, ks); @@ -1806,8 +1800,9 @@ key_method_1_write (struct buffer *buf, struct tls_session *session) return false; } - init_key_ctx (&ks->key.encrypt, &key, &session->opt->key_type, - OPENVPN_OP_ENCRYPT, "Data Channel Encrypt"); + init_key_ctx (&ks->crypto_options.key_ctx_bi.encrypt, &key, + &session->opt->key_type, OPENVPN_OP_ENCRYPT, + "Data Channel Encrypt"); CLEAR (key); /* send local options string */ @@ -1969,7 +1964,7 @@ key_method_2_write (struct buffer *buf, struct tls_session *session) { if (ks->authenticated) { - if (!generate_key_expansion (&ks->key, + if (!generate_key_expansion (&ks->crypto_options.key_ctx_bi, &session->opt->key_type, ks->key_src, &ks->session_id_remote, @@ -2040,8 +2035,9 @@ key_method_1_read (struct buffer *buf, struct tls_session *session) buf_clear (buf); - init_key_ctx (&ks->key.decrypt, &key, &session->opt->key_type, - OPENVPN_OP_DECRYPT, "Data Channel Decrypt"); + init_key_ctx (&ks->crypto_options.key_ctx_bi.decrypt, &key, + &session->opt->key_type, OPENVPN_OP_DECRYPT, + "Data Channel Decrypt"); CLEAR (key); ks->authenticated = true; return true; @@ -2189,7 +2185,7 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi */ if (!session->opt->server) { - if (!generate_key_expansion (&ks->key, + if (!generate_key_expansion (&ks->crypto_options.key_ctx_bi, &session->opt->key_type, ks->key_src, &session->session_id, diff --git a/src/openvpn/ssl.h b/src/openvpn/ssl.h index e9d0f28bc8b..20991cc99bc 100644 --- a/src/openvpn/ssl.h +++ b/src/openvpn/ssl.h @@ -136,7 +136,6 @@ */ struct tls_auth_standalone { - struct key_ctx_bi tls_auth_key; struct crypto_options tls_auth_options; struct frame frame; }; diff --git a/src/openvpn/ssl_common.h b/src/openvpn/ssl_common.h index 00d2ce87bff..b40aec2e60f 100644 --- a/src/openvpn/ssl_common.h +++ b/src/openvpn/ssl_common.h @@ -163,7 +163,6 @@ struct key_state struct packet_id packet_id; /* for data channel, to prevent replay attacks */ struct crypto_options crypto_options;/* data channel crypto options */ - struct key_ctx_bi key; /* data channel keys for encrypt/decrypt/hmac */ struct key_source2 *key_src; /* source entropy for key expansion */ @@ -270,7 +269,6 @@ struct tls_options /* packet authentication for TLS handshake */ struct crypto_options tls_auth; - struct key_ctx_bi tls_auth_key; /* frame parameters for TLS control channel */ struct frame frame; From 3ebc31f9591ce11b0673dc20e76022c13bdb2c37 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sun, 7 Feb 2016 20:47:13 +0100 Subject: [PATCH 191/643] Move packet_id into crypto_options Decouples struct key_state and struct crypto_options. No longer updating self-referential pointers! Signed-off-by: Steffan Karger Acked-by: Arne Schwabe Message-Id: <1454874438-5081-6-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/11082 Signed-off-by: Gert Doering --- src/openvpn/crypto.c | 45 +++++++++++++++++++++------------------- src/openvpn/crypto.h | 10 ++++----- src/openvpn/init.c | 11 +++++----- src/openvpn/openvpn.h | 2 -- src/openvpn/packet_id.h | 6 ++++++ src/openvpn/ssl.c | 38 ++++++++++++--------------------- src/openvpn/ssl_common.h | 2 -- 7 files changed, 52 insertions(+), 62 deletions(-) diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c index 9679fd0da95..db52182688b 100644 --- a/src/openvpn/crypto.c +++ b/src/openvpn/crypto.c @@ -85,8 +85,7 @@ memcmp_constant_time (const void *a, const void *b, size_t size) { void openvpn_encrypt (struct buffer *buf, struct buffer work, - const struct crypto_options *opt, - const struct frame* frame) + struct crypto_options *opt, const struct frame* frame) { struct gc_arena gc; gc_init (&gc); @@ -111,11 +110,11 @@ openvpn_encrypt (struct buffer *buf, struct buffer work, if (opt->flags & CO_USE_IV) prng_bytes (iv_buf, iv_size); - /* Put packet ID in plaintext buffer or IV, depending on cipher mode */ - if (opt->packet_id) + /* Put packet ID in plaintext buffer */ + if (packet_id_initialized(&opt->packet_id)) { struct packet_id_net pin; - packet_id_alloc_outgoing (&opt->packet_id->send, &pin, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM)); + packet_id_alloc_outgoing (&opt->packet_id.send, &pin, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM)); ASSERT (packet_id_write (&pin, buf, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM), true)); } } @@ -124,10 +123,11 @@ openvpn_encrypt (struct buffer *buf, struct buffer work, struct packet_id_net pin; struct buffer b; - ASSERT (opt->flags & CO_USE_IV); /* IV and packet-ID required */ - ASSERT (opt->packet_id); /* for this mode. */ + /* IV and packet-ID required for this mode. */ + ASSERT (opt->flags & CO_USE_IV); + ASSERT (packet_id_initialized(&opt->packet_id)); - packet_id_alloc_outgoing (&opt->packet_id->send, &pin, true); + packet_id_alloc_outgoing (&opt->packet_id.send, &pin, true); memset (iv_buf, 0, iv_size); buf_set_write (&b, iv_buf, iv_size); ASSERT (packet_id_write (&pin, &b, true, false)); @@ -189,10 +189,10 @@ openvpn_encrypt (struct buffer *buf, struct buffer work, } else /* No Encryption */ { - if (opt->packet_id) + if (packet_id_initialized(&opt->packet_id)) { struct packet_id_net pin; - packet_id_alloc_outgoing (&opt->packet_id->send, &pin, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM)); + packet_id_alloc_outgoing (&opt->packet_id.send, &pin, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM)); ASSERT (packet_id_write (&pin, buf, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM), true)); } work = *buf; @@ -233,8 +233,7 @@ openvpn_encrypt (struct buffer *buf, struct buffer work, */ bool openvpn_decrypt (struct buffer *buf, struct buffer work, - const struct crypto_options *opt, - const struct frame* frame) + struct crypto_options *opt, const struct frame* frame) { static const char error_prefix[] = "Authenticate/Decrypt packet error"; struct gc_arena gc; @@ -246,6 +245,9 @@ openvpn_decrypt (struct buffer *buf, struct buffer work, struct packet_id_net pin; bool have_pin = false; + dmsg (D_PACKET_CONTENT, "DECRYPT FROM: %s", + format_hex (BPTR (buf), BLEN (buf), 80, &gc)); + /* Verify the HMAC */ if (ctx->hmac) { @@ -325,7 +327,7 @@ openvpn_decrypt (struct buffer *buf, struct buffer work, { if (cipher_kt_mode_cbc(cipher_kt)) { - if (opt->packet_id) + if (packet_id_initialized(&opt->packet_id)) { if (!packet_id_read (&pin, &work, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM))) CRYPT_ERROR ("error reading CBC packet-id"); @@ -336,8 +338,9 @@ openvpn_decrypt (struct buffer *buf, struct buffer work, { struct buffer b; - ASSERT (opt->flags & CO_USE_IV); /* IV and packet-ID required */ - ASSERT (opt->packet_id); /* for this mode. */ + /* IV and packet-ID required for this mode. */ + ASSERT (opt->flags & CO_USE_IV); + ASSERT (packet_id_initialized(&opt->packet_id)); buf_set_read (&b, iv_buf, iv_size); if (!packet_id_read (&pin, &b, true)) @@ -353,7 +356,7 @@ openvpn_decrypt (struct buffer *buf, struct buffer work, else { work = *buf; - if (opt->packet_id) + if (packet_id_initialized(&opt->packet_id)) { if (!packet_id_read (&pin, &work, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM))) CRYPT_ERROR ("error reading packet-id"); @@ -363,12 +366,12 @@ openvpn_decrypt (struct buffer *buf, struct buffer work, if (have_pin) { - packet_id_reap_test (&opt->packet_id->rec); - if (packet_id_test (&opt->packet_id->rec, &pin)) + packet_id_reap_test (&opt->packet_id.rec); + if (packet_id_test (&opt->packet_id.rec, &pin)) { - packet_id_add (&opt->packet_id->rec, &pin); + packet_id_add (&opt->packet_id.rec, &pin); if (opt->pid_persist && (opt->flags & CO_PACKET_ID_LONG_FORM)) - packet_id_persist_save_obj (opt->pid_persist, opt->packet_id); + packet_id_persist_save_obj (opt->pid_persist, &opt->packet_id); } else { @@ -688,7 +691,7 @@ key2_print (const struct key2* k, } void -test_crypto (const struct crypto_options *co, struct frame* frame) +test_crypto (struct crypto_options *co, struct frame* frame) { int i, j; struct gc_arena gc = gc_new (); diff --git a/src/openvpn/crypto.h b/src/openvpn/crypto.h index 1f84284dcea..aac50c430c4 100644 --- a/src/openvpn/crypto.h +++ b/src/openvpn/crypto.h @@ -211,7 +211,7 @@ struct crypto_options /**< OpenSSL cipher and HMAC contexts for * both sending and receiving * directions. */ - struct packet_id *packet_id; /**< Current packet ID state for both + struct packet_id packet_id; /**< Current packet ID state for both * sending and receiving directions. */ struct packet_id_persist *pid_persist; /**< Persistent packet ID state for @@ -311,8 +311,7 @@ void free_key_ctx_bi (struct key_ctx_bi *ctx); * error occurred. */ void openvpn_encrypt (struct buffer *buf, struct buffer work, - const struct crypto_options *opt, - const struct frame* frame); + struct crypto_options *opt, const struct frame* frame); /** @@ -347,8 +346,7 @@ void openvpn_encrypt (struct buffer *buf, struct buffer work, * an error occurred. */ bool openvpn_decrypt (struct buffer *buf, struct buffer work, - const struct crypto_options *opt, - const struct frame* frame); + struct crypto_options *opt, const struct frame* frame); /** @} name Functions for performing security operations on data channel packets */ @@ -397,7 +395,7 @@ void prng_bytes (uint8_t *output, int len); void prng_uninit (); -void test_crypto (const struct crypto_options *co, struct frame* f); +void test_crypto (struct crypto_options *co, struct frame* f); /* key direction functions */ diff --git a/src/openvpn/init.c b/src/openvpn/init.c index dcc3ccbbeac..cb73a3df2be 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -2076,16 +2076,15 @@ do_init_crypto_static (struct context *c, const unsigned int flags) /* Initialize packet ID tracking */ if (options->replay) { - packet_id_init (&c->c2.packet_id, + packet_id_init (&c->c2.crypto_options.packet_id, link_socket_proto_connection_oriented (options->ce.proto), options->replay_window, options->replay_time, "STATIC", 0); - c->c2.crypto_options.packet_id = &c->c2.packet_id; c->c2.crypto_options.pid_persist = &c->c1.pid_persist; c->c2.crypto_options.flags |= CO_PACKET_ID_LONG_FORM; packet_id_persist_load_obj (&c->c1.pid_persist, - c->c2.crypto_options.packet_id); + &c->c2.crypto_options.packet_id); } if (!key_ctx_bi_defined (&c->c1.ks.static_key)) @@ -3007,7 +3006,7 @@ static void do_close_packet_id (struct context *c) { #ifdef ENABLE_CRYPTO - packet_id_free (&c->c2.packet_id); + packet_id_free (&c->c2.crypto_options.packet_id); packet_id_persist_save (&c->c1.pid_persist); if (!(c->sig->signal_received == SIGUSR1)) packet_id_persist_close (&c->c1.pid_persist); @@ -3923,13 +3922,13 @@ test_crypto_thread (void *arg) test_crypto (&c->c2.crypto_options, &c->c2.frame); key_schedule_free (&c->c1.ks, true); - packet_id_free (&c->c2.packet_id); + packet_id_free (&c->c2.crypto_options.packet_id); context_gc_free (c); return NULL; } -#endif +#endif /* ENABLE_CRYPTO */ bool do_test_crypto (const struct options *o) diff --git a/src/openvpn/openvpn.h b/src/openvpn/openvpn.h index 71adf4814e4..3281fd7d29e 100644 --- a/src/openvpn/openvpn.h +++ b/src/openvpn/openvpn.h @@ -361,8 +361,6 @@ struct context_2 * Channel Crypto module\endlink to * process data channel packet. */ - /* used to keep track of data channel packet sequence numbers */ - struct packet_id packet_id; struct event_timeout packet_id_persist_interval; #endif /* ENABLE_CRYPTO */ diff --git a/src/openvpn/packet_id.h b/src/openvpn/packet_id.h index 3ddaab6affa..5eb501d1084 100644 --- a/src/openvpn/packet_id.h +++ b/src/openvpn/packet_id.h @@ -258,6 +258,12 @@ bool packet_id_write (const struct packet_id_net *pin, struct buffer *buf, bool * Inline functions. */ +/** Is this struct packet_id initialized? */ +static inline bool packet_id_initialized (const struct packet_id *pid) +{ + return pid->rec.initialized; +} + /* are we in enabled state? */ static inline bool packet_id_persist_enabled (const struct packet_id_persist *p) diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index e3a745d1d84..7f99ee9c2bf 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -780,13 +780,13 @@ key_state_init (struct tls_session *session, struct key_state *ks) reliable_set_timeout (ks->send_reliable, session->opt->packet_timeout); /* init packet ID tracker */ - packet_id_init (&ks->packet_id, - session->opt->tcp_mode, - session->opt->replay_window, - session->opt->replay_time, - "SSL", ks->key_id); + if (session->opt->replay) + { + packet_id_init (&ks->crypto_options.packet_id, session->opt->tcp_mode, + session->opt->replay_window, session->opt->replay_time, "SSL", + ks->key_id); + } - ks->crypto_options.packet_id = session->opt->replay ? &ks->packet_id : NULL; ks->crypto_options.pid_persist = NULL; ks->crypto_options.flags = session->opt->crypto_flags; ks->crypto_options.flags &= session->opt->crypto_flags_and; @@ -842,7 +842,7 @@ key_state_free (struct key_state *ks, bool clear) if (ks->key_src) free (ks->key_src); - packet_id_free (&ks->packet_id); + packet_id_free (&ks->crypto_options.packet_id); #ifdef PLUGIN_DEF_AUTH key_state_rm_auth_control_file (ks); @@ -857,13 +857,6 @@ key_state_free (struct key_state *ks, bool clear) /** @} addtogroup control_processor */ -/* - * Must be called if we move a tls_session in memory. - */ -static inline void tls_session_set_self_referential_pointers (struct tls_session* session) { - session->tls_auth.packet_id = &session->tls_auth_pid; -} - /** * Returns whether or not the server should check for username/password * @@ -936,18 +929,15 @@ tls_session_init (struct tls_multi *multi, struct tls_session *session) /* Initialize control channel authentication parameters */ session->tls_auth = session->opt->tls_auth; - /* Set session internal pointers (also called if session object is moved in memory) */ - tls_session_set_self_referential_pointers (session); - /* initialize packet ID replay window for --tls-auth */ - packet_id_init (session->tls_auth.packet_id, + packet_id_init (&session->tls_auth.packet_id, session->opt->tcp_mode, session->opt->replay_window, session->opt->replay_time, "TLS_AUTH", session->key_id); /* load most recent packet-id to replay protect on --tls-auth */ - packet_id_persist_load_obj (session->tls_auth.pid_persist, session->tls_auth.packet_id); + packet_id_persist_load_obj (session->tls_auth.pid_persist, &session->tls_auth.packet_id); key_state_init (session, &session->key[KS_PRIMARY]); @@ -974,8 +964,8 @@ tls_session_free (struct tls_session *session, bool clear) { int i; - if (session->tls_auth.packet_id) - packet_id_free (session->tls_auth.packet_id); + if (packet_id_initialized(&session->tls_auth.packet_id)) + packet_id_free (&session->tls_auth.packet_id); for (i = 0; i < KS_SIZE; ++i) key_state_free (&session->key[i], false); @@ -1006,7 +996,6 @@ move_session (struct tls_multi* multi, int dest, int src, bool reinit_src) ASSERT (dest >= 0 && dest < TM_SIZE); tls_session_free (&multi->session[dest], false); multi->session[dest] = multi->session[src]; - tls_session_set_self_referential_pointers (&multi->session[dest]); if (reinit_src) tls_session_init (multi, &multi->session[src]); @@ -1274,7 +1263,7 @@ write_control_auth (struct tls_session *session, */ static bool read_control_auth (struct buffer *buf, - const struct crypto_options *co, + struct crypto_options *co, const struct link_socket_actual *from) { struct gc_arena gc = gc_new (); @@ -1702,7 +1691,6 @@ key_state_soft_reset (struct tls_session *session) ks->must_die = now + session->opt->transition_window; /* remaining lifetime of old key */ key_state_free (ks_lame, false); *ks_lame = *ks; - ks_lame->crypto_options.packet_id = &ks_lame->packet_id; key_state_init (session, ks); ks->session_id_remote = ks_lame->session_id_remote; @@ -2257,7 +2245,7 @@ tls_process (struct tls_multi *multi, && ks->n_bytes >= session->opt->renegotiate_bytes) || (session->opt->renegotiate_packets && ks->n_packets >= session->opt->renegotiate_packets) - || (packet_id_close_to_wrapping (&ks->packet_id.send)))) + || (packet_id_close_to_wrapping (&ks->crypto_options.packet_id.send)))) { msg (D_TLS_DEBUG_LOW, "TLS: soft reset sec=%d bytes=" counter_format "/%d pkts=" counter_format "/%d", diff --git a/src/openvpn/ssl_common.h b/src/openvpn/ssl_common.h index b40aec2e60f..eaf4a919fda 100644 --- a/src/openvpn/ssl_common.h +++ b/src/openvpn/ssl_common.h @@ -160,7 +160,6 @@ struct key_state int initial_opcode; /* our initial P_ opcode */ struct session_id session_id_remote; /* peer's random session ID */ struct link_socket_actual remote_addr; /* peer's IP addr */ - struct packet_id packet_id; /* for data channel, to prevent replay attacks */ struct crypto_options crypto_options;/* data channel crypto options */ @@ -366,7 +365,6 @@ struct tls_session /* authenticate control packets */ struct crypto_options tls_auth; - struct packet_id tls_auth_pid; int initial_opcode; /* our initial P_ opcode */ struct session_id session_id; /* our random session ID */ From a070f75b7dbb06161b9e2009124ad82277054524 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sun, 7 Feb 2016 20:47:14 +0100 Subject: [PATCH 192/643] Change openvpn_encrypt() to append to work buffer only Preparation for AEAD cipher modes, which also have to authenticate the opcode and peer-id of packets. To supply that information to openvpn_encrypt(), I want to simply write those to the work buffer before calling openvpn_encrypt(). That however requires that openvpn_encrypt() never prepends something to the work buffer. Signed-off-by: Steffan Karger Acked-by: Arne Schwabe Message-Id: <1454874438-5081-7-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/11074 Signed-off-by: Gert Doering --- src/openvpn/crypto.c | 55 ++++++++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c index db52182688b..e92125e748d 100644 --- a/src/openvpn/crypto.c +++ b/src/openvpn/crypto.c @@ -93,6 +93,8 @@ openvpn_encrypt (struct buffer *buf, struct buffer work, if (buf->len > 0 && opt) { const struct key_ctx *ctx = &opt->key_ctx_bi.encrypt; + uint8_t *mac_out = NULL; + const uint8_t *hmac_start = NULL; /* Do Encrypt from buf -> work */ if (ctx->cipher) @@ -102,6 +104,17 @@ openvpn_encrypt (struct buffer *buf, struct buffer work, const cipher_kt_t *cipher_kt = cipher_ctx_get_cipher_kt (ctx->cipher); int outlen; + /* initialize work buffer with FRAME_HEADROOM bytes of prepend capacity */ + ASSERT (buf_init (&work, FRAME_HEADROOM (frame))); + + /* Reserve space for HMAC */ + if (ctx->hmac) + { + mac_out = buf_write_alloc (&work, hmac_ctx_size(ctx->hmac)); + ASSERT (mac_out); + hmac_start = BEND(&work); + } + if (cipher_kt_mode_cbc(cipher_kt)) { CLEAR (iv_buf); @@ -137,12 +150,12 @@ openvpn_encrypt (struct buffer *buf, struct buffer work, ASSERT (0); } - /* initialize work buffer with FRAME_HEADROOM bytes of prepend capacity */ - ASSERT (buf_init (&work, FRAME_HEADROOM (frame))); - /* set the IV pseudo-randomly */ if (opt->flags & CO_USE_IV) - dmsg (D_PACKET_CONTENT, "ENCRYPT IV: %s", format_hex (iv_buf, iv_size, 0, &gc)); + { + ASSERT (buf_write(&work, iv_buf, iv_size)); + dmsg (D_PACKET_CONTENT, "ENCRYPT IV: %s", format_hex (iv_buf, iv_size, 0, &gc)); + } dmsg (D_PACKET_CONTENT, "ENCRYPT FROM: %s", format_hex (BPTR (buf), BLEN (buf), 80, &gc)); @@ -165,27 +178,16 @@ openvpn_encrypt (struct buffer *buf, struct buffer work, } /* Encrypt packet ID, payload */ - ASSERT (cipher_ctx_update (ctx->cipher, BPTR (&work), &outlen, BPTR (buf), BLEN (buf))); + ASSERT (cipher_ctx_update (ctx->cipher, BEND (&work), &outlen, BPTR (buf), BLEN (buf))); ASSERT (buf_inc_len(&work, outlen)); /* Flush the encryption buffer */ - ASSERT (cipher_ctx_final(ctx->cipher, BPTR (&work) + outlen, &outlen)); + ASSERT (cipher_ctx_final(ctx->cipher, BEND (&work), &outlen)); ASSERT (buf_inc_len(&work, outlen)); /* For all CBC mode ciphers, check the last block is complete */ ASSERT (cipher_kt_mode (cipher_kt) != OPENVPN_MODE_CBC || outlen == iv_size); - - /* prepend the IV to the ciphertext */ - if (opt->flags & CO_USE_IV) - { - uint8_t *output = buf_prepend (&work, iv_size); - ASSERT (output); - memcpy (output, iv_buf, iv_size); - } - - dmsg (D_PACKET_CONTENT, "ENCRYPT TO: %s", - format_hex (BPTR (&work), BLEN (&work), 80, &gc)); } else /* No Encryption */ { @@ -195,22 +197,29 @@ openvpn_encrypt (struct buffer *buf, struct buffer work, packet_id_alloc_outgoing (&opt->packet_id.send, &pin, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM)); ASSERT (packet_id_write (&pin, buf, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM), true)); } + if (ctx->hmac) + { + hmac_start = BPTR(buf); + ASSERT (mac_out = buf_prepend (buf, hmac_ctx_size(ctx->hmac))); + } + buf_write_prepend(buf, BPTR(&work), BLEN(&work)); work = *buf; } /* HMAC the ciphertext (or plaintext if !cipher) */ if (ctx->hmac) { - uint8_t *output = NULL; - hmac_ctx_reset (ctx->hmac); - hmac_ctx_update (ctx->hmac, BPTR(&work), BLEN(&work)); - output = buf_prepend (&work, hmac_ctx_size(ctx->hmac)); - ASSERT (output); - hmac_ctx_final (ctx->hmac, output); + hmac_ctx_update (ctx->hmac, hmac_start, BEND(&work) - hmac_start); + hmac_ctx_final (ctx->hmac, mac_out); + dmsg (D_PACKET_CONTENT, "ENCRYPT HMAC: %s", + format_hex (mac_out, hmac_ctx_size(ctx->hmac), 80, &gc)); } *buf = work; + + dmsg (D_PACKET_CONTENT, "ENCRYPT TO: %s", + format_hex (BPTR (&work), BLEN (&work), 80, &gc)); } gc_free (&gc); From de4cbd62b7d120e1ec083eaf7688ef3d18e03288 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sun, 7 Feb 2016 20:47:15 +0100 Subject: [PATCH 193/643] Create separate function for replay check In preparation for AEAD cipher modes, which will need the same functionality. Should not change any behaviour. Signed-off-by: Steffan Karger Acked-by: Arne Schwabe Message-Id: <1454874438-5081-8-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/11076 Signed-off-by: Gert Doering --- src/openvpn/crypto.c | 52 +++++++++++++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 15 deletions(-) diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c index e92125e748d..9c0c3530ad8 100644 --- a/src/openvpn/crypto.c +++ b/src/openvpn/crypto.c @@ -232,6 +232,41 @@ openvpn_encrypt (struct buffer *buf, struct buffer work, return; } +/** + * Check packet ID for replay, and perform replay administration. + * + * @param opt Crypto options for this packet, contains replay state. + * @param pin Packet ID read from packet. + * @param error_prefix Prefix to use when printing error messages. + * @param gc Garbage collector to use. + * + * @return true if packet ID is validated to be not a replay, false otherwise. + */ +static bool crypto_check_replay(struct crypto_options *opt, + const struct packet_id_net *pin, const char *error_prefix, + struct gc_arena *gc) { + bool ret = false; + packet_id_reap_test (&opt->packet_id.rec); + if (packet_id_test (&opt->packet_id.rec, pin)) + { + packet_id_add (&opt->packet_id.rec, pin); + if (opt->pid_persist && (opt->flags & CO_PACKET_ID_LONG_FORM)) + packet_id_persist_save_obj (opt->pid_persist, &opt->packet_id); + ret = true; + } + else + { + if (!(opt->flags & CO_MUTE_REPLAY_WARNINGS)) + { + msg (D_REPLAY_ERRORS, "%s: bad packet ID (may be a replay): %s -- " + "see the man page entry for --no-replay and --replay-window for " + "more info or silence this warning with --mute-replay-warnings", + error_prefix, packet_id_net_print (pin, true, gc)); + } + } + return ret; +} + /* * If (opt->flags & CO_USE_IV) is not NULL, we will read an IV from the packet. * @@ -373,22 +408,9 @@ openvpn_decrypt (struct buffer *buf, struct buffer work, } } - if (have_pin) + if (have_pin && !crypto_check_replay(opt, &pin, error_prefix, &gc)) { - packet_id_reap_test (&opt->packet_id.rec); - if (packet_id_test (&opt->packet_id.rec, &pin)) - { - packet_id_add (&opt->packet_id.rec, &pin); - if (opt->pid_persist && (opt->flags & CO_PACKET_ID_LONG_FORM)) - packet_id_persist_save_obj (opt->pid_persist, &opt->packet_id); - } - else - { - if (!(opt->flags & CO_MUTE_REPLAY_WARNINGS)) - msg (D_REPLAY_ERRORS, "%s: bad packet ID (may be a replay): %s -- see the man page entry for --no-replay and --replay-window for more info or silence this warning with --mute-replay-warnings", - error_prefix, packet_id_net_print (&pin, true, &gc)); - goto error_exit; - } + goto error_exit; } *buf = work; } From 15f78acfae2f99b74a72b5766559f28c2d1d3cac Mon Sep 17 00:00:00 2001 From: Lev Stipakov Date: Sun, 7 Feb 2016 22:21:32 +0200 Subject: [PATCH 194/643] Report Windows bitness Trac #599 Signed-off-by: Lev Stipakov Acked-by: Gert Doering Message-Id: <1454876492-6588-1-git-send-email-lstipakov@gmail.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/11086 Signed-off-by: Gert Doering --- src/openvpn/win32.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/openvpn/win32.c b/src/openvpn/win32.c index a01121b98bb..6b7a6ae451b 100644 --- a/src/openvpn/win32.c +++ b/src/openvpn/win32.c @@ -1322,6 +1322,20 @@ win32_version_info() } } +bool +win32_is_64bit() +{ +#if defined(_WIN64) + return true; // 64-bit programs run only on Win64 +#elif defined(_WIN32) + // 32-bit programs run on both 32-bit and 64-bit Windows + BOOL f64 = FALSE; + return IsWow64Process(GetCurrentProcess(), &f64) && f64; +#else + return false; // Win64 does not support Win16 +#endif +} + const char * win32_version_string(struct gc_arena *gc, bool add_name) { @@ -1348,6 +1362,8 @@ win32_version_string(struct gc_arena *gc, bool add_name) break; } + buf_printf (&out, win32_is_64bit() ? " 64bit" : " 32bit"); + return (const char *)out.data; } From 5f5229e41d134b659e502bb2597c711aedaf8096 Mon Sep 17 00:00:00 2001 From: Leonardo Basilio Date: Wed, 10 Feb 2016 11:19:39 +0100 Subject: [PATCH 195/643] Correctly report TCP connection timeout on windows. On nonblocking TCP connects, we set status = ETIMEOUT on failure. On windows, depending on which header files are included, ETIMEOUT is defined differently, and this leads to incomprehensible error messages - so, always use WSAETIMEDOUT here. Trac #651 Signed-off-by: Leonardo Basilio Acked-by: Arne Schwabe Message-Id: URL: http://article.gmane.org/gmane.network.openvpn.devel/11085 Signed-off-by: Gert Doering --- src/openvpn/socket.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c index 396fa5427b8..714a847a96b 100644 --- a/src/openvpn/socket.c +++ b/src/openvpn/socket.c @@ -1177,7 +1177,11 @@ openvpn_connect (socket_descriptor_t sd, { if (--connect_timeout < 0) { +#ifdef WIN32 + status = WSAETIMEDOUT; +#else status = ETIMEDOUT; +#endif break; } openvpn_sleep (1); From 66407e11c4746e564bd4285e9c1a1805ecfd82bd Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sat, 24 Oct 2015 16:44:09 +0200 Subject: [PATCH 196/643] Add AEAD cipher support (GCM) Add Authenticated Encryption with Additional Data (AEAD) support for ciphers, which removes the need for a separate HMAC step. The MAC is integrated into the cipher and the MAC tag is prepended to the payload. This patch is inspired by the patch originally submitted by Kenny Root on the openvpn-devel mailinglist, but does a number things differently: * Don't support XTS (makes no sense for VPN) * Don't support CCM (needs extra code to make it actually work) * Don't force the user to specify "auth none" (that would break tls-auth) * Add support for PolarSSL (and change internal API for this) * Update openvpn frame size ('link mtu') calculation for AEAD modes * Use the HMAC key as an implicit part of the IV to save 8 bytes per data channel network packet. * Also authenticate the opcode/peer-id as AD in P_DATA_V2 packets. By using the negotiated HMAC key as an implicit part of the IV for AEAD-mode ciphers in TLS mode, we can save (at least) 8 bytes on each packet sent. This is particularly interesting for connections which transfer many small packets, such as remote desktop or voip connections. The current AEAD-mode ciphers (for now GCM) are based on CTR-mode cipher operation, which requires the IV to be unique (but does not require unpredictability). IV uniqueness is guaranteed by using a combination of at least 64-bits of the HMAC key (unique per TLS session), and a 32-bit packet counter. The last 32-bit word of the 128-bit cipher block is not part of the IV, but is used as a block counter. AEAD cipher mode is not available for static key mode, since IV uniqueness is harder the guarantee over sessions, and I believe supporting AEAD in static key mode too is not worth the extra complexity. Modern setups should simply use TLS mode. OpenSSL 1.0.1-1.0.1c will not work with AEAD mode, because those versions have an unnecessary check that fails to update the cipher if the tag was not already set. 1.0.1d, which fixes that, was released in February 2013. People should have updated, and distros should have backported the fix by now. Changes in v2: * Remove extra code that was just for making OpenSSL 1.0.1-1.0.1c work in AEAD mode. * Do not make AEAD support configurable in ./configure. * Get rid of '12' magic constant in openvpn_encrypt_aead(). * Update manpage to explain that --auth is ignored for the data channel when using an AEAD cipher. * Move setting the IV in AEAD cipher modes to the IV generation code. This is a more natural place and now we can pull iv[] into the IV generation scope. * Read packet ID directly from packet buffer instead of from iv buffer, to remove the need for an extra buffer. Signed-off-by: Steffan Karger Acked-by: Arne Schwabe Message-Id: URL: http://article.gmane.org/gmane.network.openvpn.devel/11162 Signed-off-by: Gert Doering --- Changes.rst | 7 + configure.ac | 20 +- doc/openvpn.8 | 17 +- src/openvpn/crypto.c | 347 +++++++++++++++++++++++++++++++--- src/openvpn/crypto.h | 68 +++++-- src/openvpn/crypto_backend.h | 59 ++++++ src/openvpn/crypto_openssl.c | 74 +++++++- src/openvpn/crypto_openssl.h | 7 + src/openvpn/crypto_polarssl.c | 98 +++++++++- src/openvpn/crypto_polarssl.h | 3 + src/openvpn/forward.c | 49 ++--- src/openvpn/ssl.c | 101 ++++++++-- src/openvpn/ssl.h | 42 +++- 13 files changed, 789 insertions(+), 103 deletions(-) diff --git a/Changes.rst b/Changes.rst index dd9b9b2c26d..af70d1419fe 100644 --- a/Changes.rst +++ b/Changes.rst @@ -37,6 +37,13 @@ Windows version Windows version is detected, logged and possibly signalled to server (IV_PLAT_VER= if --push-peer-info is set on client) +AEAD (GCM) data channel cipher support + The data channel now supports AEAD ciphers (currently only GCM). The AEAD + packet format has a smaller overhead than the CBC packet format, (e.g. 20 + bytes per packet for AES-128-GCM instead of 36 bytes per packet for + AES-128-CBC + HMAC-SHA1). + + User-visible Changes -------------------- - For certificate DNs with duplicate fields, e.g. "OU=one,OU=two", both fields diff --git a/configure.ac b/configure.ac index 7ff2435ac95..b75d51f6e89 100644 --- a/configure.ac +++ b/configure.ac @@ -821,6 +821,13 @@ if test "${with_crypto_library}" = "openssl"; then AC_DEFINE([HAVE_OPENSSL_ENGINE], [1], [OpenSSL engine support available]) fi + have_crypto_aead_modes="yes" + AC_CHECK_FUNCS( + [EVP_aes_256_gcm], + , + [have_crypto_aead_modes="no"; break] + ) + CFLAGS="${saved_CFLAGS}" LIBS="${saved_LIBS}" @@ -897,9 +904,19 @@ elif test "${with_crypto_library}" = "polarssl"; then AC_MSG_ERROR([PolarSSL compiled with PKCS11, while OpenVPN is not]) fi fi + + have_crypto_aead_modes="yes" + AC_CHECK_FUNCS( + [ \ + cipher_write_tag \ + cipher_check_tag \ + ], + , + [have_crypto_aead_modes="no"; break] + ) + CFLAGS="${saved_CFLAGS}" LIBS="${saved_LIBS}" - have_crypto="yes" AC_DEFINE([ENABLE_CRYPTO_POLARSSL], [1], [Use PolarSSL library]) CRYPTO_CFLAGS="${POLARSSL_CFLAGS}" @@ -1054,6 +1071,7 @@ test "${enable_strict_options}" = "yes" && AC_DEFINE([ENABLE_STRICT_OPTIONS_CHEC if test "${enable_crypto}" = "yes"; then test "${have_crypto}" != "yes" && AC_MSG_ERROR([${with_crypto_library} crypto is required but missing]) test "${enable_crypto_ofb_cfb}" = "yes" && AC_DEFINE([ENABLE_OFB_CFB_MODE], [1], [Enable OFB and CFB cipher modes]) + test "${have_crypto_aead_modes}" = "yes" && AC_DEFINE([HAVE_AEAD_CIPHER_MODES], [1], [Use crypto library]) OPTIONAL_CRYPTO_CFLAGS="${OPTIONAL_CRYPTO_CFLAGS} ${CRYPTO_CFLAGS}" OPTIONAL_CRYPTO_LIBS="${OPTIONAL_CRYPTO_LIBS} ${CRYPTO_LIBS}" AC_DEFINE([ENABLE_CRYPTO], [1], [Enable crypto library]) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 76650e96aa4..628d8772fba 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -3979,8 +3979,9 @@ options. Useful when using inline files (See section on inline files). .\"********************************************************* .TP .B \-\-auth alg -Authenticate packets with HMAC using message -digest algorithm +Authenticate data channel packets and (if enabled) +.B tls-auth +control channel packets with HMAC using message digest algorithm .B alg. (The default is .B SHA1 @@ -3989,7 +3990,17 @@ HMAC is a commonly used message authentication algorithm (MAC) that uses a data string, a secure hash algorithm, and a key, to produce a digital signature. -OpenVPN's usage of HMAC is to first encrypt a packet, then HMAC the resulting ciphertext. +The OpenVPN data channel protocol uses encrypt-then-mac (i.e. first encrypt a +packet, then HMAC the resulting ciphertext), which prevents padding oracle +attacks. + +If an AEAD cipher mode (e.g. GCM) is chosen, the specified +.B \-\-auth +algorithm is ignored for the data channel, and the authentication method of the +AEAD cipher is used instead. Note that +.B alg +still specifies the digest used for +.B tls-auth\fR. In static-key encryption mode, the HMAC key is included in the key file generated by diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c index 9c0c3530ad8..3e94470ee84 100644 --- a/src/openvpn/crypto.c +++ b/src/openvpn/crypto.c @@ -83,9 +83,101 @@ memcmp_constant_time (const void *a, const void *b, size_t size) { return ret; } -void -openvpn_encrypt (struct buffer *buf, struct buffer work, - struct crypto_options *opt, const struct frame* frame) +static void +openvpn_encrypt_aead (struct buffer *buf, struct buffer work, + struct crypto_options *opt) { + struct gc_arena gc; + int outlen = 0; + const struct key_ctx *ctx = &opt->key_ctx_bi.encrypt; + uint8_t *mac_out = NULL; + const cipher_kt_t *cipher_kt = cipher_ctx_get_cipher_kt (ctx->cipher); + const int mac_len = cipher_kt_tag_size (cipher_kt); + + /* IV, packet-ID and implicit IV required for this mode. */ + ASSERT (ctx->cipher); + ASSERT (cipher_kt_mode_aead (cipher_kt)); + ASSERT (opt->flags & CO_USE_IV); + ASSERT (packet_id_initialized(&opt->packet_id)); + + gc_init (&gc); + + /* Prepare IV */ + { + struct buffer iv_buffer; + struct packet_id_net pin; + uint8_t iv[OPENVPN_MAX_IV_LENGTH]; + const int iv_len = cipher_ctx_iv_length (ctx->cipher); + + ASSERT (iv_len >= OPENVPN_AEAD_MIN_IV_LEN && iv_len <= OPENVPN_MAX_IV_LENGTH); + + memset(iv, 0, sizeof(iv)); + buf_set_write (&iv_buffer, iv, iv_len); + + /* IV starts with packet id to make the IV unique for packet */ + packet_id_alloc_outgoing (&opt->packet_id.send, &pin, false); + ASSERT (packet_id_write (&pin, &iv_buffer, false, false)); + + /* Remainder of IV consists of implicit part (unique per session) */ + ASSERT (buf_write (&iv_buffer, ctx->implicit_iv, ctx->implicit_iv_len)); + ASSERT (iv_buffer.len == iv_len); + + /* Write explicit part of IV to work buffer */ + ASSERT (buf_write(&work, iv, iv_len - ctx->implicit_iv_len)); + dmsg (D_PACKET_CONTENT, "ENCRYPT IV: %s", format_hex (iv, iv_len, 0, &gc)); + + /* Init cipher_ctx with IV. key & keylen are already initialized */ + ASSERT (cipher_ctx_reset(ctx->cipher, iv)); + } + + /* Reserve space for authentication tag */ + mac_out = buf_write_alloc (&work, mac_len); + ASSERT (mac_out); + + dmsg (D_PACKET_CONTENT, "ENCRYPT FROM: %s", format_hex (BPTR (buf), BLEN (buf), 80, &gc)); + + /* Buffer overflow check */ + if (!buf_safe (&work, buf->len + cipher_ctx_block_size(ctx->cipher))) + { + msg (D_CRYPT_ERRORS, + "ENCRYPT: buffer size error, bc=%d bo=%d bl=%d wc=%d wo=%d wl=%d", + buf->capacity, buf->offset, buf->len, work.capacity, work.offset, + work.len); + goto err; + } + + /* For AEAD ciphers, authenticate Additional Data, including opcode */ + ASSERT (cipher_ctx_update_ad (ctx->cipher, BPTR (&work), BLEN (&work) - mac_len)); + dmsg (D_PACKET_CONTENT, "ENCRYPT AD: %s", + format_hex (BPTR (&work), BLEN (&work) - mac_len, 0, &gc)); + + /* Encrypt packet ID, payload */ + ASSERT (cipher_ctx_update (ctx->cipher, BEND (&work), &outlen, BPTR (buf), BLEN (buf))); + ASSERT (buf_inc_len (&work, outlen)); + + /* Flush the encryption buffer */ + ASSERT (cipher_ctx_final (ctx->cipher, BEND (&work), &outlen)); + ASSERT (buf_inc_len (&work, outlen)); + + /* Write authentication tag */ + ASSERT (cipher_ctx_get_tag (ctx->cipher, mac_out, mac_len)); + + dmsg (D_PACKET_CONTENT, "ENCRYPT TO: %s", format_hex (BPTR (buf), BLEN (buf), 80, &gc)); + + *buf = work; + +cleanup: + gc_free (&gc); + return; + +err: + crypto_clear_error(); + buf->len = 0; + goto cleanup; +} + +static void +openvpn_encrypt_v1 (struct buffer *buf, struct buffer work, + struct crypto_options *opt) { struct gc_arena gc; gc_init (&gc); @@ -104,9 +196,6 @@ openvpn_encrypt (struct buffer *buf, struct buffer work, const cipher_kt_t *cipher_kt = cipher_ctx_get_cipher_kt (ctx->cipher); int outlen; - /* initialize work buffer with FRAME_HEADROOM bytes of prepend capacity */ - ASSERT (buf_init (&work, FRAME_HEADROOM (frame))); - /* Reserve space for HMAC */ if (ctx->hmac) { @@ -232,6 +321,22 @@ openvpn_encrypt (struct buffer *buf, struct buffer work, return; } +void +openvpn_encrypt (struct buffer *buf, struct buffer work, + struct crypto_options *opt) +{ + if (buf->len > 0 && opt) + { + const cipher_kt_t *cipher_kt = + cipher_ctx_get_cipher_kt(opt->key_ctx_bi.encrypt.cipher); + + if (cipher_kt_mode_aead (cipher_kt)) + openvpn_encrypt_aead(buf, work, opt); + else + openvpn_encrypt_v1(buf, work, opt); + } +} + /** * Check packet ID for replay, and perform replay administration. * @@ -275,8 +380,141 @@ static bool crypto_check_replay(struct crypto_options *opt, * On success, buf is set to point to plaintext, true * is returned. */ -bool -openvpn_decrypt (struct buffer *buf, struct buffer work, +static bool +openvpn_decrypt_aead (struct buffer *buf, struct buffer work, + struct crypto_options *opt, const struct frame* frame, + const uint8_t *ad_start) +{ + static const char error_prefix[] = "AEAD Decrypt error"; + struct packet_id_net pin = { 0 }; + const struct key_ctx *ctx = &opt->key_ctx_bi.decrypt; + const cipher_kt_t *cipher_kt = cipher_ctx_get_cipher_kt (ctx->cipher); + uint8_t *tag_ptr = NULL; + int tag_size = 0; + int outlen; + struct gc_arena gc; + + gc_init (&gc); + + ASSERT (opt); + ASSERT (buf->len > 0); + ASSERT (ctx->cipher); + ASSERT (cipher_kt_mode_aead (cipher_kt)); + + dmsg (D_PACKET_CONTENT, "DECRYPT FROM: %s", + format_hex (BPTR (buf), BLEN (buf), 80, &gc)); + + ASSERT (ad_start >= buf->data && ad_start <= BPTR (buf)); + + ASSERT (buf_init (&work, FRAME_HEADROOM_ADJ (frame, FRAME_HEADROOM_MARKER_DECRYPT))); + + /* IV and Packet ID required for this mode */ + ASSERT (packet_id_initialized (&opt->packet_id)); + ASSERT (opt->flags & CO_USE_IV); + + /* Combine IV from explicit part from packet and implicit part from context */ + { + uint8_t iv[OPENVPN_MAX_IV_LENGTH] = { 0 }; + const int iv_len = cipher_ctx_iv_length (ctx->cipher); + const size_t packet_iv_len = iv_len - ctx->implicit_iv_len; + + ASSERT (ctx->implicit_iv_len <= iv_len); + if (buf->len + ctx->implicit_iv_len < iv_len) + CRYPT_ERROR ("missing IV info"); + + memcpy (iv, BPTR(buf), packet_iv_len); + memcpy (iv + packet_iv_len, ctx->implicit_iv, ctx->implicit_iv_len); + + dmsg (D_PACKET_CONTENT, "DECRYPT IV: %s", format_hex (iv, iv_len, 0, &gc)); + + /* Load IV, ctx->cipher was already initialized with key & keylen */ + if (!cipher_ctx_reset (ctx->cipher, iv)) + { + CRYPT_ERROR ("cipher init failed"); + } + } + + /* Read packet ID from packet */ + if (!packet_id_read (&pin, buf, false)) + { + CRYPT_ERROR ("error reading packet-id"); + } + + /* keep the tag value to feed in later */ + tag_size = cipher_kt_tag_size(cipher_kt); + if (buf->len < tag_size) + { + CRYPT_ERROR ("missing tag"); + } + tag_ptr = BPTR(buf); + ASSERT (buf_advance (buf, tag_size)); + dmsg (D_PACKET_CONTENT, "DECRYPT MAC: %s", format_hex (tag_ptr, tag_size, 0, &gc)); + + if (buf->len < 1) + { + CRYPT_ERROR ("missing payload"); + } + + dmsg (D_PACKET_CONTENT, "DECRYPT FROM: %s", format_hex (BPTR(buf), BLEN(buf), 0, &gc)); + + /* Buffer overflow check (should never fail) */ + if (!buf_safe (&work, buf->len + cipher_ctx_block_size(ctx->cipher))) + { + CRYPT_ERROR ("potential buffer overflow"); + } + + { + /* feed in tag and the authenticated data */ + const int ad_size = BPTR (buf) - ad_start - tag_size; + ASSERT (cipher_ctx_update_ad (ctx->cipher, ad_start, ad_size)); + dmsg (D_PACKET_CONTENT, "DECRYPT AD: %s", + format_hex (BPTR (buf) - ad_size - tag_size, ad_size, 0, &gc)); + } + + /* Decrypt and authenticate packet */ + if (!cipher_ctx_update (ctx->cipher, BPTR (&work), &outlen, BPTR (buf), + BLEN (buf))) + { + CRYPT_ERROR ("cipher update failed"); + } + ASSERT (buf_inc_len (&work, outlen)); + if (!cipher_ctx_final_check_tag (ctx->cipher, BPTR (&work) + outlen, + &outlen, tag_ptr, tag_size)) + { + CRYPT_ERROR ("cipher final failed"); + } + ASSERT (buf_inc_len (&work, outlen)); + + dmsg (D_PACKET_CONTENT, "DECRYPT TO: %s", + format_hex (BPTR (&work), BLEN (&work), 80, &gc)); + + if (!crypto_check_replay (opt, &pin, error_prefix, &gc)) + { + goto error_exit; + } + + *buf = work; + + gc_free (&gc); + return true; + + error_exit: + crypto_clear_error(); + buf->len = 0; + gc_free (&gc); + return false; +} + +/* + * If (opt->flags & CO_USE_IV) is not NULL, we will read an IV from the packet. + * + * Set buf->len to 0 and return false on decrypt error. + * + * On success, buf is set to point to plaintext, true + * is returned. + */ +static bool +openvpn_decrypt_v1 (struct buffer *buf, struct buffer work, struct crypto_options *opt, const struct frame* frame) { static const char error_prefix[] = "Authenticate/Decrypt packet error"; @@ -425,6 +663,33 @@ openvpn_decrypt (struct buffer *buf, struct buffer work, return false; } + +bool +openvpn_decrypt (struct buffer *buf, struct buffer work, + struct crypto_options *opt, const struct frame* frame, + const uint8_t *ad_start) +{ + bool ret = false; + + if (buf->len > 0 && opt) + { + const struct key_ctx *ctx = &opt->key_ctx_bi.decrypt; + if (cipher_kt_mode_aead (cipher_ctx_get_cipher_kt (ctx->cipher))) + { + ret = openvpn_decrypt_aead (buf, work, opt, frame, ad_start); + } + else + { + ret = openvpn_decrypt_v1 (buf, work, opt, frame); + } + } + else + { + ret = true; + } + return ret; +} + /* * How many bytes will we add to frame buffer for a given * set of crypto options? @@ -447,6 +712,9 @@ crypto_adjust_frame_parameters(struct frame *frame, if (use_iv) crypto_overhead += cipher_kt_iv_size (kt->cipher); + if (cipher_kt_mode_aead (kt->cipher)) + crypto_overhead += cipher_kt_tag_size (kt->cipher); + /* extra block required by cipher_ctx_update() */ crypto_overhead += cipher_kt_block_size (kt->cipher); } @@ -466,8 +734,10 @@ void init_key_type (struct key_type *kt, const char *ciphername, bool ciphername_defined, const char *authname, bool authname_defined, int keysize, - bool cfb_ofb_allowed, bool warn) + bool tls_mode, bool warn) { + bool aead_cipher = false; + CLEAR (*kt); if (ciphername && ciphername_defined) { @@ -477,14 +747,14 @@ init_key_type (struct key_type *kt, const char *ciphername, kt->cipher_length = keysize; /* check legal cipher mode */ - { - if (!(cipher_kt_mode_cbc(kt->cipher) + aead_cipher = cipher_kt_mode_aead(kt->cipher); + if (!(cipher_kt_mode_cbc(kt->cipher) + || (tls_mode && aead_cipher) #ifdef ENABLE_OFB_CFB_MODE - || (cfb_ofb_allowed && cipher_kt_mode_ofb_cfb(kt->cipher)) + || (tls_mode && cipher_kt_mode_ofb_cfb(kt->cipher)) #endif - )) - msg (M_FATAL, "Cipher '%s' mode not supported", ciphername); - } + )) + msg (M_FATAL, "Cipher '%s' mode not supported", ciphername); } else { @@ -493,10 +763,12 @@ init_key_type (struct key_type *kt, const char *ciphername, } if (authname && authname_defined) { - kt->digest = md_kt_get (authname); - kt->hmac_length = md_kt_size (kt->digest); + if (!aead_cipher) { /* Ignore auth for AEAD ciphers */ + kt->digest = md_kt_get (authname); + kt->hmac_length = md_kt_size (kt->digest); + } } - else + else if (!aead_cipher) { if (warn) msg (M_WARN, "******* WARNING *******: null MAC specified, no authentication will be used"); @@ -566,6 +838,7 @@ free_key_ctx (struct key_ctx *ctx) free(ctx->hmac); ctx->hmac = NULL; } + ctx->implicit_iv_len = 0; } void @@ -575,7 +848,6 @@ free_key_ctx_bi (struct key_ctx_bi *ctx) free_key_ctx(&ctx->decrypt); } - static bool key_is_zero (struct key *key, const struct key_type *kt) { @@ -655,8 +927,10 @@ check_replay_iv_consistency (const struct key_type *kt, bool packet_id, bool use { ASSERT(kt); - if (cipher_kt_mode_ofb_cfb(kt->cipher) && !(packet_id && use_iv)) - msg (M_FATAL, "--no-replay or --no-iv cannot be used with a CFB or OFB mode cipher"); + if (!(packet_id && use_iv) && (cipher_kt_mode_ofb_cfb(kt->cipher) || + cipher_kt_mode_aead(kt->cipher))) + msg (M_FATAL, "--no-replay or --no-iv cannot be used with a CFB, OFB or " + "AEAD mode cipher"); } /* @@ -735,6 +1009,30 @@ test_crypto (struct crypto_options *co, struct frame* frame) /* init work */ ASSERT (buf_init (&work, FRAME_HEADROOM (frame))); +#ifdef HAVE_AEAD_CIPHER_MODES + /* init implicit IV */ + { + const cipher_kt_t *cipher = + cipher_ctx_get_cipher_kt(co->key_ctx_bi.encrypt.cipher); + + if (cipher_kt_mode_aead(cipher)) + { + size_t impl_iv_len = cipher_kt_iv_size(cipher) - sizeof(packet_id_type); + ASSERT (cipher_kt_iv_size(cipher) <= OPENVPN_MAX_IV_LENGTH); + ASSERT (cipher_kt_iv_size(cipher) >= OPENVPN_AEAD_MIN_IV_LEN); + + /* Generate dummy implicit IV */ + ASSERT (rand_bytes(co->key_ctx_bi.encrypt.implicit_iv, + OPENVPN_MAX_IV_LENGTH)); + co->key_ctx_bi.encrypt.implicit_iv_len = impl_iv_len; + + memcpy(co->key_ctx_bi.decrypt.implicit_iv, + co->key_ctx_bi.encrypt.implicit_iv, OPENVPN_MAX_IV_LENGTH); + co->key_ctx_bi.decrypt.implicit_iv_len = impl_iv_len; + } + } +#endif + msg (M_INFO, "Entering " PACKAGE_NAME " crypto self-test mode."); for (i = 1; i <= TUN_MTU_SIZE (frame); ++i) { @@ -754,11 +1052,14 @@ test_crypto (struct crypto_options *co, struct frame* frame) buf = work; memcpy (buf_write_alloc (&buf, BLEN (&src)), BPTR (&src), BLEN (&src)); + /* initialize work buffer with FRAME_HEADROOM bytes of prepend capacity */ + ASSERT (buf_init (&encrypt_workspace, FRAME_HEADROOM (frame))); + /* encrypt */ - openvpn_encrypt (&buf, encrypt_workspace, co, frame); + openvpn_encrypt (&buf, encrypt_workspace, co); /* decrypt */ - openvpn_decrypt (&buf, decrypt_workspace, co, frame); + openvpn_decrypt (&buf, decrypt_workspace, co, frame, BPTR (&buf)); /* compare */ if (buf.len != src.len) diff --git a/src/openvpn/crypto.h b/src/openvpn/crypto.h index aac50c430c4..14b6ab7cb03 100644 --- a/src/openvpn/crypto.h +++ b/src/openvpn/crypto.h @@ -86,6 +86,30 @@ * [ HMAC ] [ - IV - ] [ * packet payload * ] * * @par + * GCM data channel crypto format \n + * GCM modes are only supported in TLS mode. In these modes, the IV consists of + * the 32-bit packet counter followed by data from the HMAC key. The HMAC key + * can be used as IV, since in GCM and CCM modes the HMAC key is not used for + * the HMAC. The packet counter may not roll over within a single TLS sessions. + * This results in a unique IV for each packet, as required by GCM. + * + * @par + * The HMAC key data is pre-shared during the connection setup, and thus can be + * omitted in on-the-wire packets, saving 8 bytes per packet (for GCM and CCM). + * + * @par + * In GCM mode, P_DATA_V2 headers (the opcode and peer-id) are also + * authenticated as Additional Data. + * + * @par + * GCM IV format: \n + * [ - packet ID - ] [ - HMAC key data - ] \n + * P_DATA_V1 GCM data channel crypto format: \n + * [ opcode ] [ - packet ID - ] [ TAG ] [ * packet payload * ] + * P_DATA_V2 GCM data channel crypto format: \n + * [ - opcode/peer-id - ] [ - packet ID - ] [ TAG ] [ * packet payload * ] + * + * @par * No-crypto data channel format \n * In no-crypto mode (\c \-\-cipher \c none is specified), both TLS-mode and * static key mode are supported. No encryption will be performed on the packet, @@ -138,13 +162,16 @@ struct key /** - * Container for one set of OpenSSL cipher and/or HMAC contexts. + * Container for one set of cipher and/or HMAC contexts. * @ingroup control_processor */ struct key_ctx { cipher_ctx_t *cipher; /**< Generic cipher %context. */ - hmac_ctx_t *hmac; /**< Generic HMAC %context. */ + hmac_ctx_t *hmac; /**< Generic HMAC %context. */ + uint8_t implicit_iv[OPENVPN_MAX_IV_LENGTH]; + /**< The implicit part of the IV */ + size_t implicit_iv_len; /**< The length of implicit_iv */ }; #define KEY_DIRECTION_BIDIRECTIONAL 0 /* same keys for both directions */ @@ -195,10 +222,10 @@ struct key_direction_state */ struct key_ctx_bi { - struct key_ctx encrypt; /**< OpenSSL cipher and/or HMAC contexts - * for sending direction. */ - struct key_ctx decrypt; /**< OpenSSL cipher and/or HMAC contexts - * for receiving direction. */ + struct key_ctx encrypt; /**< Cipher and/or HMAC contexts for sending + * direction. */ + struct key_ctx decrypt; /**< cipher and/or HMAC contexts for + * receiving direction. */ }; /** @@ -238,6 +265,12 @@ struct crypto_options * security operation functions. */ }; +/** + * Minimal IV length for AEAD mode ciphers (in bytes): + * 4-byte packet id + 8 bytes implicit IV. + */ +#define OPENVPN_AEAD_MIN_IV_LEN (sizeof (packet_id_type) + 8) + #define RKF_MUST_SUCCEED (1<<0) #define RKF_INLINE (1<<1) void read_key_file (struct key2 *key2, const char *file, const unsigned int flags); @@ -278,6 +311,17 @@ void free_key_ctx (struct key_ctx *ctx); void free_key_ctx_bi (struct key_ctx_bi *ctx); +/** + * Set an implicit IV for a key context. + * + * @param ctx The key context to update + * @param iv The implicit IV to load into ctx + * @param len The length (in bytes) of iv + */ +bool key_ctx_set_implicit_iv (struct key_ctx *ctx, const uint8_t *iv, + size_t len); + + /**************************************************************************/ /** @name Functions for performing security operations on data channel packets @@ -301,17 +345,16 @@ void free_key_ctx_bi (struct key_ctx_bi *ctx); * * @param buf - The %buffer containing the packet on which to * perform security operations. - * @param work - A working %buffer. + * @param work - An initialized working %buffer. * @param opt - The security parameter state for this VPN tunnel. - * @param frame - The packet geometry parameters for this VPN - * tunnel. + * * @return This function returns void.\n On return, the \a buf argument * will point to the resulting %buffer. This %buffer will either * contain the processed packet ready for sending, or be empty if an * error occurred. */ void openvpn_encrypt (struct buffer *buf, struct buffer work, - struct crypto_options *opt, const struct frame* frame); + struct crypto_options *opt); /** @@ -337,6 +380,8 @@ void openvpn_encrypt (struct buffer *buf, struct buffer work, * @param opt - The security parameter state for this VPN tunnel. * @param frame - The packet geometry parameters for this VPN * tunnel. + * @param ad_start - A pointer into buf, indicating from where to start + * authenticating additional data (AEAD mode only). * * @return * @li True, if the packet was authenticated and decrypted successfully. @@ -346,7 +391,8 @@ void openvpn_encrypt (struct buffer *buf, struct buffer work, * an error occurred. */ bool openvpn_decrypt (struct buffer *buf, struct buffer work, - struct crypto_options *opt, const struct frame* frame); + struct crypto_options *opt, const struct frame* frame, + const uint8_t *ad_start); /** @} name Functions for performing security operations on data channel packets */ diff --git a/src/openvpn/crypto_backend.h b/src/openvpn/crypto_backend.h index 1c23436485a..c5ff3669ddc 100644 --- a/src/openvpn/crypto_backend.h +++ b/src/openvpn/crypto_backend.h @@ -38,6 +38,8 @@ #endif #include "basic.h" +/* TLS uses a tag of 128 bytes, let's do the same for OpenVPN */ +#define OPENVPN_AEAD_TAG_LENGTH 16 /* * This routine should have additional OpenSSL crypto library initialisations @@ -220,6 +222,16 @@ int cipher_kt_iv_size (const cipher_kt_t *cipher_kt); */ int cipher_kt_block_size (const cipher_kt_t *cipher_kt); +/** + * Returns the MAC tag size of the cipher, in bytes. + * + * @param ctx Static cipher parameters. + * + * @return Tag size in bytes, or 0 if the tag size could not be + * determined. + */ +int cipher_kt_tag_size (const cipher_kt_t *cipher_kt); + /** * Returns the mode that the cipher runs in. * @@ -248,6 +260,15 @@ bool cipher_kt_mode_cbc(const cipher_kt_t *cipher); */ bool cipher_kt_mode_ofb_cfb(const cipher_kt_t *cipher); +/** + * Check if the supplied cipher is a supported AEAD mode cipher. + * + * @param cipher Static cipher parameters. + * + * @return true iff the cipher is a AEAD mode cipher. + */ +bool cipher_kt_mode_aead(const cipher_kt_t *cipher); + /** * @@ -286,6 +307,15 @@ void cipher_ctx_cleanup (cipher_ctx_t *ctx); */ int cipher_ctx_iv_length (const cipher_ctx_t *ctx); +/** + * Gets the computed message authenticated code (MAC) tag for this cipher. + * + * @param ctx The cipher's context + * @param tag The buffer to write computed tag in. + * @param tag_size The tag buffer size, in bytes. + */ +int cipher_ctx_get_tag (cipher_ctx_t *ctx, uint8_t* tag, int tag_len); + /** * Returns the block size of the cipher, in bytes. * @@ -326,6 +356,18 @@ const cipher_kt_t *cipher_ctx_get_cipher_kt (const cipher_ctx_t *ctx); */ int cipher_ctx_reset (cipher_ctx_t *ctx, uint8_t *iv_buf); +/** + * Updates the given cipher context, providing additional data (AD) for + * authenticated encryption with additional data (AEAD) cipher modes. + * + * @param ctx Cipher's context. May not be NULL. + * @param src Source buffer + * @param src_len Length of the source buffer, in bytes + * + * @return \c 0 on failure, \c 1 on success. + */ +int cipher_ctx_update_ad (cipher_ctx_t *ctx, const uint8_t *src, int src_len); + /** * Updates the given cipher context, encrypting data in the source buffer, and * placing any complete blocks in the destination buffer. @@ -358,6 +400,23 @@ int cipher_ctx_update (cipher_ctx_t *ctx, uint8_t *dst, int *dst_len, */ int cipher_ctx_final (cipher_ctx_t *ctx, uint8_t *dst, int *dst_len); +/** + * Like \c cipher_ctx_final, but check the computed authentication tag against + * the supplied (expected) tag. This function reports failure when the tags + * don't match. + * + * @param ctx Cipher's context. May not be NULL. + * @param dst Destination buffer. + * @param dst_len Length of the destination buffer, in bytes. + * @param tag The expected authentication tag. + * @param tag_len The length of tag, in bytes. + * + * @return \c 0 on failure, \c 1 on success. + */ +int cipher_ctx_final_check_tag (cipher_ctx_t *ctx, uint8_t *dst, int *dst_len, + uint8_t *tag, size_t tag_len); + + /* * * Generic message digest information functions diff --git a/src/openvpn/crypto_openssl.c b/src/openvpn/crypto_openssl.c index 7dabe5dfa48..56b662569e8 100644 --- a/src/openvpn/crypto_openssl.c +++ b/src/openvpn/crypto_openssl.c @@ -258,12 +258,12 @@ show_available_ciphers () int nid; #ifndef ENABLE_SMALL - printf ("The following ciphers and cipher modes are available\n" - "for use with " PACKAGE_NAME ". Each cipher shown below may be\n" - "used as a parameter to the --cipher option. The default\n" - "key size is shown as well as whether or not it can be\n" - "changed with the --keysize directive. Using a CBC mode\n" - "is recommended. In static key mode only CBC mode is allowed.\n\n"); + printf ("The following ciphers and cipher modes are available for use\n" + "with " PACKAGE_NAME ". Each cipher shown below may be use as a\n" + "parameter to the --cipher option. The default key size is\n" + "shown as well as whether or not it can be changed with the\n" + "--keysize directive. Using a CBC or GCM mode is recommended.\n" + "In static key mode only CBC mode is allowed.\n\n"); #endif for (nid = 0; nid < 10000; ++nid) /* is there a better way to get the size of the nid list? */ @@ -274,14 +274,17 @@ show_available_ciphers () if (cipher_kt_mode_cbc(cipher) #ifdef ENABLE_OFB_CFB_MODE || cipher_kt_mode_ofb_cfb(cipher) +#endif +#ifdef HAVE_AEAD_CIPHER_MODES + || cipher_kt_mode_aead(cipher) #endif ) { const char *var_key_size = (EVP_CIPHER_flags (cipher) & EVP_CIPH_VARIABLE_LENGTH) ? "variable" : "fixed"; - const char *ssl_only = cipher_kt_mode_ofb_cfb(cipher) ? - " (TLS client/server mode)" : ""; + const char *ssl_only = cipher_kt_mode_cbc(cipher) ? + "" : " (TLS client/server mode)"; printf ("%s %d bit default key (%s)%s\n", OBJ_nid2sn (nid), EVP_CIPHER_key_length (cipher) * 8, var_key_size, @@ -499,6 +502,15 @@ cipher_kt_block_size (const EVP_CIPHER *cipher_kt) return EVP_CIPHER_block_size (cipher_kt); } +int +cipher_kt_tag_size (const EVP_CIPHER *cipher_kt) +{ + if (cipher_kt_mode_aead(cipher_kt)) + return OPENVPN_AEAD_TAG_LENGTH; + else + return 0; +} + int cipher_kt_mode (const EVP_CIPHER *cipher_kt) { @@ -529,6 +541,16 @@ cipher_kt_mode_ofb_cfb(const cipher_kt_t *cipher) ; } +bool +cipher_kt_mode_aead(const cipher_kt_t *cipher) +{ +#ifdef HAVE_AEAD_CIPHER_MODES + return cipher && (cipher_kt_mode(cipher) == OPENVPN_MODE_GCM); +#else + return false; +#endif +} + /* * * Generic cipher context functions @@ -570,6 +592,15 @@ cipher_ctx_iv_length (const EVP_CIPHER_CTX *ctx) return EVP_CIPHER_CTX_iv_length (ctx); } +int cipher_ctx_get_tag (EVP_CIPHER_CTX *ctx, uint8_t *tag_buf, int tag_size) +{ +#ifdef HAVE_AEAD_CIPHER_MODES + return EVP_CIPHER_CTX_ctrl (ctx, EVP_CTRL_GCM_GET_TAG, tag_size, tag_buf); +#else + ASSERT (0); +#endif +} + int cipher_ctx_block_size(const EVP_CIPHER_CTX *ctx) { @@ -595,6 +626,19 @@ cipher_ctx_reset (EVP_CIPHER_CTX *ctx, uint8_t *iv_buf) return EVP_CipherInit (ctx, NULL, NULL, iv_buf, -1); } +int +cipher_ctx_update_ad (EVP_CIPHER_CTX *ctx, const uint8_t *src, int src_len) +{ +#ifdef HAVE_AEAD_CIPHER_MODES + int len; + if (!EVP_CipherUpdate (ctx, NULL, &len, src, src_len)) + crypto_msg(M_FATAL, "%s: EVP_CipherUpdate() failed", __func__); + return 1; +#else + ASSERT (0); +#endif +} + int cipher_ctx_update (EVP_CIPHER_CTX *ctx, uint8_t *dst, int *dst_len, uint8_t *src, int src_len) @@ -610,6 +654,20 @@ cipher_ctx_final (EVP_CIPHER_CTX *ctx, uint8_t *dst, int *dst_len) return EVP_CipherFinal (ctx, dst, dst_len); } +int +cipher_ctx_final_check_tag (EVP_CIPHER_CTX *ctx, uint8_t *dst, int *dst_len, + uint8_t *tag, size_t tag_len) +{ +#ifdef HAVE_AEAD_CIPHER_MODES + ASSERT (tag_len < SIZE_MAX); + if (!EVP_CIPHER_CTX_ctrl (ctx, EVP_CTRL_GCM_SET_TAG, tag_len, tag)) + return 0; + + return cipher_ctx_final (ctx, dst, dst_len); +#else + ASSERT (0); +#endif +} void cipher_des_encrypt_ecb (const unsigned char key[DES_KEY_LENGTH], diff --git a/src/openvpn/crypto_openssl.h b/src/openvpn/crypto_openssl.h index 42c7e9a99f3..f157041713e 100644 --- a/src/openvpn/crypto_openssl.h +++ b/src/openvpn/crypto_openssl.h @@ -61,6 +61,13 @@ typedef HMAC_CTX hmac_ctx_t; /** Cipher is in CFB mode */ #define OPENVPN_MODE_CFB EVP_CIPH_CFB_MODE +#ifdef HAVE_AEAD_CIPHER_MODES + +/** Cipher is in GCM mode */ +#define OPENVPN_MODE_GCM EVP_CIPH_GCM_MODE + +#endif /* HAVE_AEAD_CIPHER_MODES */ + /** Cipher should encrypt */ #define OPENVPN_OP_ENCRYPT 1 diff --git a/src/openvpn/crypto_polarssl.c b/src/openvpn/crypto_polarssl.c index 0e4c08839d5..09cb1292dc0 100644 --- a/src/openvpn/crypto_polarssl.c +++ b/src/openvpn/crypto_polarssl.c @@ -174,21 +174,28 @@ show_available_ciphers () const int *ciphers = cipher_list(); #ifndef ENABLE_SMALL - printf ("The following ciphers and cipher modes are available\n" - "for use with " PACKAGE_NAME ". Each cipher shown below may be\n" - "used as a parameter to the --cipher option. The default\n" - "key size is shown as well as whether or not it can be\n" - "changed with the --keysize directive. Using a CBC mode\n" - "is recommended.\n\n"); + printf ("The following ciphers and cipher modes are available for use\n" + "with " PACKAGE_NAME ". Each cipher shown below may be used as a\n" + "parameter to the --cipher option. Using a CBC or GCM mode is\n" + "recommended. In static key mode only CBC mode is allowed.\n\n"); #endif while (*ciphers != 0) { - const cipher_info_t *info = cipher_info_from_type(*ciphers); + const cipher_kt_t *info = cipher_info_from_type(*ciphers); - if (info && info->mode == POLARSSL_MODE_CBC) - printf ("%s %d bit default key\n", - cipher_kt_name(info), cipher_kt_key_size(info) * 8); + if (info && (cipher_kt_mode_cbc(info) +#ifdef HAVE_AEAD_CIPHER_MODES + || cipher_kt_mode_aead(info) +#endif + )) + { + const char *ssl_only = cipher_kt_mode_cbc(info) ? + "" : " (TLS client/server mode)"; + + printf ("%s %d bit default key%s\n", + cipher_kt_name(info), cipher_kt_key_size(info) * 8, ssl_only); + } ciphers++; } @@ -435,6 +442,16 @@ cipher_kt_block_size (const cipher_info_t *cipher_kt) return cipher_kt->block_size; } +int +cipher_kt_tag_size (const cipher_info_t *cipher_kt) +{ +#ifdef HAVE_AEAD_CIPHER_MODES + if (cipher_kt && cipher_kt_mode_aead(cipher_kt)) + return OPENVPN_AEAD_TAG_LENGTH; +#endif + return 0; +} + int cipher_kt_mode (const cipher_info_t *cipher_kt) { @@ -455,6 +472,12 @@ cipher_kt_mode_ofb_cfb(const cipher_kt_t *cipher) cipher_kt_mode(cipher) == OPENVPN_MODE_CFB); } +bool +cipher_kt_mode_aead(const cipher_kt_t *cipher) +{ + return cipher && cipher_kt_mode(cipher) == OPENVPN_MODE_GCM; +} + /* * @@ -491,6 +514,21 @@ int cipher_ctx_iv_length (const cipher_context_t *ctx) return cipher_get_iv_size(ctx); } +int cipher_ctx_get_tag (cipher_ctx_t *ctx, uint8_t* tag, int tag_len) +{ +#ifdef HAVE_AEAD_CIPHER_MODES + if (tag_len > SIZE_MAX) + return 0; + + if (!polar_ok (cipher_write_tag (ctx, (unsigned char *) tag, tag_len))) + return 0; + + return 1; +#else + ASSERT(0); +#endif /* HAVE_AEAD_CIPHER_MODES */ +} + int cipher_ctx_block_size(const cipher_context_t *ctx) { return cipher_get_block_size(ctx); @@ -520,6 +558,21 @@ int cipher_ctx_reset (cipher_context_t *ctx, uint8_t *iv_buf) return 1; } +int cipher_ctx_update_ad (cipher_ctx_t *ctx, const uint8_t *src, int src_len) +{ +#ifdef HAVE_AEAD_CIPHER_MODES + if (src_len > SIZE_MAX) + return 0; + + if (!polar_ok (cipher_update_ad (ctx, src, src_len))) + return 0; + + return 1; +#else + ASSERT(0); +#endif /* HAVE_AEAD_CIPHER_MODES */ +} + int cipher_ctx_update (cipher_context_t *ctx, uint8_t *dst, int *dst_len, uint8_t *src, int src_len) { @@ -545,6 +598,31 @@ int cipher_ctx_final (cipher_context_t *ctx, uint8_t *dst, int *dst_len) return 1; } +int cipher_ctx_final_check_tag (cipher_context_t *ctx, uint8_t *dst, + int *dst_len, uint8_t *tag, size_t tag_len) +{ +#ifdef HAVE_AEAD_CIPHER_MODES + if (POLARSSL_DECRYPT != ctx->operation) + return 0; + + if (tag_len > SIZE_MAX) + return 0; + + if (!cipher_ctx_final (ctx, dst, dst_len)) + { + msg (D_CRYPT_ERRORS, "%s: cipher_ctx_final() failed", __func__); + return 0; + } + + if (!polar_ok (cipher_check_tag (ctx, (const unsigned char *) tag, tag_len))) + return 0; + + return 1; +#else + ASSERT(0); +#endif /* HAVE_AEAD_CIPHER_MODES */ +} + void cipher_des_encrypt_ecb (const unsigned char key[DES_KEY_LENGTH], unsigned char *src, diff --git a/src/openvpn/crypto_polarssl.h b/src/openvpn/crypto_polarssl.h index 94306eddcea..7be0862424b 100644 --- a/src/openvpn/crypto_polarssl.h +++ b/src/openvpn/crypto_polarssl.h @@ -61,6 +61,9 @@ typedef md_context_t hmac_ctx_t; /** Cipher is in CFB mode */ #define OPENVPN_MODE_CFB POLARSSL_MODE_CFB +/** Cipher is in GCM mode */ +#define OPENVPN_MODE_GCM POLARSSL_MODE_GCM + /** Cipher should encrypt */ #define OPENVPN_OP_ENCRYPT POLARSSL_ENCRYPT diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c index 75cd21decef..4a91f9206af 100644 --- a/src/openvpn/forward.c +++ b/src/openvpn/forward.c @@ -457,43 +457,41 @@ encrypt_sign (struct context *c, bool comp_frag) } #ifdef ENABLE_CRYPTO - /* - * If TLS mode, get the key we will use to encrypt - * the packet. - */ + /* initialize work buffer with FRAME_HEADROOM bytes of prepend capacity */ + ASSERT (buf_init (&b->encrypt_buf, FRAME_HEADROOM (&c->c2.frame))); + if (c->c2.tls_multi) { + /* Get the key we will use to encrypt the packet. */ tls_pre_encrypt (c->c2.tls_multi, &c->c2.buf, &co); + /* If using P_DATA_V2, prepend the 1-byte opcode and 3-byte peer-id to the + * packet before openvpn_encrypt(), so we can authenticate the opcode too. + */ + if (c->c2.buf.len > 0 && !c->c2.tls_multi->opt.server && c->c2.tls_multi->use_peer_id) + tls_prepend_opcode_v2 (c->c2.tls_multi, &b->encrypt_buf); } else { co = &c->c2.crypto_options; } - /* - * Encrypt the packet and write an optional - * HMAC signature. - */ - openvpn_encrypt (&c->c2.buf, b->encrypt_buf, co, &c->c2.frame); + /* Encrypt and authenticate the packet */ + openvpn_encrypt (&c->c2.buf, b->encrypt_buf, co); + + /* Do packet administration */ + if (c->c2.tls_multi) + { + if (c->c2.buf.len > 0 && (c->c2.tls_multi->opt.server || !c->c2.tls_multi->use_peer_id)) + tls_prepend_opcode_v1(c->c2.tls_multi, &c->c2.buf); + tls_post_encrypt (c->c2.tls_multi, &c->c2.buf); + } #endif + /* * Get the address we will be sending the packet to. */ link_socket_get_outgoing_addr (&c->c2.buf, get_link_socket_info (c), &c->c2.to_link_addr); -#ifdef ENABLE_CRYPTO - /* - * In TLS mode, prepend the appropriate one-byte opcode - * to the packet which identifies it as a data channel - * packet and gives the low-permutation version of - * the key-id to the recipient so it knows which - * decrypt key to use. - */ - if (c->c2.tls_multi) - { - tls_post_encrypt (c->c2.tls_multi, &c->c2.buf); - } -#endif /* if null encryption, copy result to read_tun_buf */ buffer_turnover (orig_buf, &c->c2.to_link, &c->c2.buf, &b->read_tun_buf); @@ -780,6 +778,7 @@ process_incoming_link_part1 (struct context *c, struct link_socket_info *lsi, bo if (c->c2.buf.len > 0) { struct crypto_options *co = NULL; + const uint8_t *ad_start = NULL; if (!link_socket_verify_incoming_addr (&c->c2.buf, lsi, &c->c2.from)) link_socket_bad_incoming_addr (&c->c2.buf, lsi, &c->c2.from); @@ -796,7 +795,8 @@ process_incoming_link_part1 (struct context *c, struct link_socket_info *lsi, bo * will load crypto_options with the correct encryption key * and return false. */ - if (tls_pre_decrypt (c->c2.tls_multi, &c->c2.from, &c->c2.buf, &co, floated)) + if (tls_pre_decrypt (c->c2.tls_multi, &c->c2.from, &c->c2.buf, &co, + floated, &ad_start)) { interval_action (&c->c2.tmp_int); @@ -819,7 +819,8 @@ process_incoming_link_part1 (struct context *c, struct link_socket_info *lsi, bo #endif /* authenticate and decrypt the incoming packet */ - decrypt_status = openvpn_decrypt (&c->c2.buf, c->c2.buffers->decrypt_buf, co, &c->c2.frame); + decrypt_status = openvpn_decrypt (&c->c2.buf, c->c2.buffers->decrypt_buf, + co, &c->c2.frame, ad_start); if (!decrypt_status && link_socket_connection_oriented (c->c2.link_socket)) { diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 7f99ee9c2bf..d1a6fa83b6a 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -250,6 +250,20 @@ static const tls_cipher_name_pair tls_cipher_name_translation_table[] = { {NULL, NULL} }; +/** + * Update the implicit IV for a key_ctx_bi based on TLS session ids and cipher + * used. + * + * Note that the implicit IV is based on the HMAC key, but only in AEAD modes + * where the HMAC key is not used for an actual HMAC. + * + * @param ctx Encrypt/decrypt key context + * @param key HMAC key, used to calculate implicit IV + * @param key_len HMAC key length + */ +static void +key_ctx_update_implicit_iv(struct key_ctx *ctx, uint8_t *key, size_t key_len); + const tls_cipher_name_pair * tls_get_cipher_name_pair (const char * cipher_name, size_t len) { const tls_cipher_name_pair * pair = tls_cipher_name_translation_table; @@ -1252,7 +1266,7 @@ write_control_auth (struct tls_session *session, if (session->tls_auth.key_ctx_bi.encrypt.hmac) { /* no encryption, only write hmac */ - openvpn_encrypt (buf, null, &session->tls_auth, NULL); + openvpn_encrypt (buf, null, &session->tls_auth); ASSERT (swap_hmac (buf, &session->tls_auth, false)); } *to_link_addr = &ks->remote_addr; @@ -1284,7 +1298,7 @@ read_control_auth (struct buffer *buf, /* authenticate only (no decrypt) and remove the hmac record from the head of the buffer */ - openvpn_decrypt (buf, null, co, NULL); + openvpn_decrypt (buf, null, co, NULL, BPTR (buf)); if (!buf->len) { msg (D_TLS_ERRORS, @@ -1438,7 +1452,7 @@ tls1_P_hash(const md_kt_t *md_kt, * (2) The pre-master secret is generated by the client. */ static void -tls1_PRF(uint8_t *label, +tls1_PRF(const uint8_t *label, int label_len, const uint8_t *sec, int slen, @@ -1590,6 +1604,12 @@ generate_key_expansion (struct key_ctx_bi *key, OPENVPN_OP_DECRYPT, "Data Channel Decrypt"); + /* Initialize implicit IVs */ + key_ctx_update_implicit_iv (&key->encrypt, key2.keys[(int)server].hmac, + MAX_HMAC_KEY_LENGTH); + key_ctx_update_implicit_iv (&key->decrypt, key2.keys[1-(int)server].hmac, + MAX_HMAC_KEY_LENGTH); + ret = true; exit: @@ -1599,6 +1619,23 @@ generate_key_expansion (struct key_ctx_bi *key, return ret; } +static void +key_ctx_update_implicit_iv(struct key_ctx *ctx, uint8_t *key, size_t key_len) { + const cipher_kt_t *cipher_kt = cipher_ctx_get_cipher_kt (ctx->cipher); + + /* Only use implicit IV in AEAD cipher mode, where HMAC key is not used */ + if (cipher_kt_mode_aead (cipher_kt)) + { + size_t impl_iv_len = 0; + ASSERT (cipher_kt_iv_size (cipher_kt) >= OPENVPN_AEAD_MIN_IV_LEN); + impl_iv_len = cipher_kt_iv_size (cipher_kt) - sizeof (packet_id_type); + ASSERT (impl_iv_len <= OPENVPN_MAX_IV_LENGTH); + ASSERT (impl_iv_len <= key_len); + memcpy (ctx->implicit_iv, key, impl_iv_len); + ctx->implicit_iv_len = impl_iv_len; + } +} + static bool random_bytes_to_buf (struct buffer *buf, uint8_t *out, @@ -2802,7 +2839,8 @@ tls_pre_decrypt (struct tls_multi *multi, const struct link_socket_actual *from, struct buffer *buf, struct crypto_options **opt, - bool floated) + bool floated, + const uint8_t **ad_start) { struct gc_arena gc = gc_new (); bool ret = false; @@ -2850,8 +2888,16 @@ tls_pre_decrypt (struct tls_multi *multi, { /* return appropriate data channel decrypt key in opt */ *opt = &ks->crypto_options; - ASSERT (buf_advance (buf, 1)); if (op == P_DATA_V2) + { + *ad_start = BPTR(buf); + } + ASSERT (buf_advance (buf, 1)); + if (op == P_DATA_V1) + { + *ad_start = BPTR(buf); + } + else if (op == P_DATA_V2) { if (buf->len < 4) { @@ -3412,30 +3458,45 @@ tls_pre_encrypt (struct tls_multi *multi, *opt = NULL; } -/* Prepend the appropriate opcode to encrypted buffer prior to TCP/UDP send */ void -tls_post_encrypt (struct tls_multi *multi, struct buffer *buf) +tls_prepend_opcode_v1 (const struct tls_multi *multi, struct buffer *buf) { - struct key_state *ks; - uint8_t *op; + struct key_state *ks = multi->save_ks; + uint8_t op; + + msg (D_TLS_DEBUG, __func__); + + ASSERT (ks); + + op = (P_DATA_V1 << P_OPCODE_SHIFT) | ks->key_id; + ASSERT (buf_write_prepend (buf, &op, 1)); +} + +void +tls_prepend_opcode_v2 (const struct tls_multi *multi, struct buffer *buf) +{ + struct key_state *ks = multi->save_ks; uint32_t peer; - ks = multi->save_ks; + msg (D_TLS_DEBUG, __func__); + + ASSERT (ks); + + peer = htonl(((P_DATA_V2 << P_OPCODE_SHIFT) | ks->key_id) << 24 + | (multi->peer_id & 0xFFFFFF)); + ASSERT (buf_write_prepend (buf, &peer, 4)); +} + +void +tls_post_encrypt (struct tls_multi *multi, struct buffer *buf) +{ + struct key_state *ks = multi->save_ks; multi->save_ks = NULL; + if (buf->len > 0) { ASSERT (ks); - if (!multi->opt.server && multi->use_peer_id) - { - peer = htonl(((P_DATA_V2 << P_OPCODE_SHIFT) | ks->key_id) << 24 | (multi->peer_id & 0xFFFFFF)); - ASSERT (buf_write_prepend (buf, &peer, 4)); - } - else - { - ASSERT (op = buf_prepend (buf, 1)); - *op = (P_DATA_V1 << P_OPCODE_SHIFT) | ks->key_id; - } ++ks->n_packets; ks->n_bytes += buf->len; } diff --git a/src/openvpn/ssl.h b/src/openvpn/ssl.h index 20991cc99bc..d9ff8d0128f 100644 --- a/src/openvpn/ssl.h +++ b/src/openvpn/ssl.h @@ -294,6 +294,8 @@ int tls_multi_process (struct tls_multi *multi, * @param buf - A buffer structure containing the incoming packet. * @param opt - Returns a crypto options structure with the appropriate security * parameters to handle the packet if it is a data channel packet. + * @param ad_start - Returns a pointer to the start of the authenticated data of + * of this packet * * @return * @li True if the packet is a control channel packet that has been @@ -305,7 +307,8 @@ bool tls_pre_decrypt (struct tls_multi *multi, const struct link_socket_actual *from, struct buffer *buf, struct crypto_options **opt, - bool floated); + bool floated, + const uint8_t **ad_start); /**************************************************************************/ @@ -366,8 +369,41 @@ void tls_pre_encrypt (struct tls_multi *multi, /** - * Prepend the one-byte OpenVPN header to the packet, and perform some - * accounting for the key state used. + * Prepend a one-byte OpenVPN data channel P_DATA_V1 opcode to the packet. + * + * The opcode identifies the packet as a V1 data channel packet and gives the + * low-permutation version of the key-id to the recipient, so it knows which + * decrypt key to use. + * + * @param multi - The TLS state for this packet's destination VPN tunnel. + * @param buf - The buffer to write the header to. + * + * @ingroup data_crypto + */ +void +tls_prepend_opcode_v1 (const struct tls_multi *multi, struct buffer *buf); + +/** + * Prepend an OpenVPN data channel P_DATA_V2 header to the packet. The + * P_DATA_V2 header consists of a 1-byte opcode, followed by a 3-byte peer-id. + * + * The opcode identifies the packet as a V2 data channel packet and gives the + * low-permutation version of the key-id to the recipient, so it knows which + * decrypt key to use. + * + * The peer-id is sent by clients to servers to help the server determine to + * select the decrypt key when the client is roaming between addresses/ports. + * + * @param multi - The TLS state for this packet's destination VPN tunnel. + * @param buf - The buffer to write the header to. + * + * @ingroup data_crypto + */ +void +tls_prepend_opcode_v2 (const struct tls_multi *multi, struct buffer *buf); + +/** + * Perform some accounting for the key state used. * @ingroup data_crypto * * @param multi - The TLS state for this packet's destination VPN tunnel. From 44dc5d309cf04ebd9fc35b5f97be631fd99e22d6 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sun, 7 Feb 2016 20:47:17 +0100 Subject: [PATCH 197/643] Add cipher name translation for OpenSSL. This keeps naming consistent. For example, instead of id-aes128-GCM use AES-128-GCM, which is more like AES-128-CBC. Signed-off-by: Steffan Karger Acked-by: Arne Schwabe Message-Id: <1454874438-5081-10-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/11081 Signed-off-by: Gert Doering --- src/openvpn/crypto.c | 40 +++++++++++++++++++++++++++++++- src/openvpn/crypto_backend.h | 30 ++++++++++++++++++++++++ src/openvpn/crypto_openssl.c | 23 ++++++++----------- src/openvpn/crypto_polarssl.c | 43 +++-------------------------------- src/openvpn/options.c | 3 ++- 5 files changed, 84 insertions(+), 55 deletions(-) diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c index 3e94470ee84..e8ab27a8fba 100644 --- a/src/openvpn/crypto.c +++ b/src/openvpn/crypto.c @@ -792,7 +792,7 @@ init_key_ctx (struct key_ctx *ctx, struct key *key, msg (D_HANDSHAKE, "%s: Cipher '%s' initialized with %d bit key", prefix, - cipher_kt_name(kt->cipher), + translate_cipher_name_to_openvpn(cipher_kt_name(kt->cipher)), kt->cipher_length *8); dmsg (D_SHOW_KEYS, "%s: CIPHER KEY: %s", prefix, @@ -1664,4 +1664,42 @@ get_random() return l; } +static const cipher_name_pair * +get_cipher_name_pair(const char *cipher_name) { + const cipher_name_pair *pair; + size_t i = 0; + + /* Search for a cipher name translation */ + for (; i < cipher_name_translation_table_count; i++) + { + pair = &cipher_name_translation_table[i]; + if (0 == strcmp (cipher_name, pair->openvpn_name) || + 0 == strcmp (cipher_name, pair->lib_name)) + return pair; + } + + /* Nothing found, return null */ + return NULL; +} + +const char * +translate_cipher_name_from_openvpn (const char *cipher_name) { + const cipher_name_pair *pair = get_cipher_name_pair(cipher_name); + + if (NULL == pair) + return cipher_name; + + return pair->lib_name; +} + +const char * +translate_cipher_name_to_openvpn (const char *cipher_name) { + const cipher_name_pair *pair = get_cipher_name_pair(cipher_name); + + if (NULL == pair) + return cipher_name; + + return pair->openvpn_name; +} + #endif /* ENABLE_CRYPTO */ diff --git a/src/openvpn/crypto_backend.h b/src/openvpn/crypto_backend.h index c5ff3669ddc..fb7c351322a 100644 --- a/src/openvpn/crypto_backend.h +++ b/src/openvpn/crypto_backend.h @@ -41,6 +41,16 @@ /* TLS uses a tag of 128 bytes, let's do the same for OpenVPN */ #define OPENVPN_AEAD_TAG_LENGTH 16 +/** Struct used in cipher name translation table */ +typedef struct { + const char *openvpn_name; /**< Cipher name used by OpenVPN */ + const char *lib_name; /**< Cipher name used by crypto library */ +} cipher_name_pair; + +/** Cipher name translation table */ +extern const cipher_name_pair cipher_name_translation_table[]; +extern const size_t cipher_name_translation_table_count; + /* * This routine should have additional OpenSSL crypto library initialisations * used by both crypto and ssl components of OpenVPN. @@ -584,4 +594,24 @@ void hmac_ctx_update (hmac_ctx_t *ctx, const uint8_t *src, int src_len); */ void hmac_ctx_final (hmac_ctx_t *ctx, uint8_t *dst); +/** + * Translate an OpenVPN cipher name to a crypto library cipher name. + * + * @param cipher_name An OpenVPN cipher name + * + * @return The corresponding crypto library cipher name, or NULL + * if no matching cipher name was found. + */ +const char * translate_cipher_name_from_openvpn (const char *cipher_name); + +/** + * Translate a crypto library cipher name to an OpenVPN cipher name. + * + * @param cipher_name A crypto library cipher name + * + * @return The corresponding OpenVPN cipher name, or NULL if no + * matching cipher name was found. + */ +const char * translate_cipher_name_to_openvpn (const char *cipher_name); + #endif /* CRYPTO_BACKEND_H_ */ diff --git a/src/openvpn/crypto_openssl.c b/src/openvpn/crypto_openssl.c index 56b662569e8..376c8befa02 100644 --- a/src/openvpn/crypto_openssl.c +++ b/src/openvpn/crypto_openssl.c @@ -240,17 +240,14 @@ crypto_init_dmalloc (void) } #endif /* DMALLOC */ -const char * -translate_cipher_name_from_openvpn (const char *cipher_name) { - // OpenSSL doesn't require any translation - return cipher_name; -} +const cipher_name_pair cipher_name_translation_table[] = { + { "AES-128-GCM", "id-aes128-GCM" }, + { "AES-192-GCM", "id-aes192-GCM" }, + { "AES-256-GCM", "id-aes256-GCM" }, +}; +const size_t cipher_name_translation_table_count = + sizeof (cipher_name_translation_table) / sizeof (*cipher_name_translation_table); -const char * -translate_cipher_name_to_openvpn (const char *cipher_name) { - // OpenSSL doesn't require any translation - return cipher_name; -} void show_available_ciphers () @@ -286,9 +283,9 @@ show_available_ciphers () const char *ssl_only = cipher_kt_mode_cbc(cipher) ? "" : " (TLS client/server mode)"; - printf ("%s %d bit default key (%s)%s\n", OBJ_nid2sn (nid), - EVP_CIPHER_key_length (cipher) * 8, var_key_size, - ssl_only); + printf ("%s %d bit default key (%s)%s\n", + translate_cipher_name_to_openvpn(OBJ_nid2sn (nid)), + EVP_CIPHER_key_length (cipher) * 8, var_key_size, ssl_only); } } } diff --git a/src/openvpn/crypto_polarssl.c b/src/openvpn/crypto_polarssl.c index 09cb1292dc0..fc6f6c34021 100644 --- a/src/openvpn/crypto_polarssl.c +++ b/src/openvpn/crypto_polarssl.c @@ -121,52 +121,15 @@ crypto_init_dmalloc (void) } #endif /* DMALLOC */ -typedef struct { const char * openvpn_name; const char * polarssl_name; } cipher_name_pair; -cipher_name_pair cipher_name_translation_table[] = { +const cipher_name_pair cipher_name_translation_table[] = { { "BF-CBC", "BLOWFISH-CBC" }, { "BF-CFB", "BLOWFISH-CFB64" }, { "CAMELLIA-128-CFB", "CAMELLIA-128-CFB128" }, { "CAMELLIA-192-CFB", "CAMELLIA-192-CFB128" }, { "CAMELLIA-256-CFB", "CAMELLIA-256-CFB128" } }; - -const cipher_name_pair * -get_cipher_name_pair(const char *cipher_name) { - cipher_name_pair *pair; - size_t i = 0; - - /* Search for a cipher name translation */ - for (; i < sizeof (cipher_name_translation_table) / sizeof (*cipher_name_translation_table); i++) - { - pair = &cipher_name_translation_table[i]; - if (0 == strcmp (cipher_name, pair->openvpn_name) || - 0 == strcmp (cipher_name, pair->polarssl_name)) - return pair; - } - - /* Nothing found, return null */ - return NULL; -} - -const char * -translate_cipher_name_from_openvpn (const char *cipher_name) { - const cipher_name_pair *pair = get_cipher_name_pair(cipher_name); - - if (NULL == pair) - return cipher_name; - - return pair->polarssl_name; -} - -const char * -translate_cipher_name_to_openvpn (const char *cipher_name) { - const cipher_name_pair *pair = get_cipher_name_pair(cipher_name); - - if (NULL == pair) - return cipher_name; - - return pair->openvpn_name; -} +const size_t cipher_name_translation_table_count = + sizeof (cipher_name_translation_table) / sizeof (*cipher_name_translation_table); void show_available_ciphers () diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 6d97b4f74c1..02def3a8271 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -3039,7 +3039,8 @@ options_string (const struct options *o, o->authname, o->authname_defined, o->keysize, true, false); - buf_printf (&out, ",cipher %s", cipher_kt_name (kt.cipher)); + buf_printf (&out, ",cipher %s", + translate_cipher_name_to_openvpn(cipher_kt_name (kt.cipher))); buf_printf (&out, ",auth %s", md_kt_name (kt.digest)); buf_printf (&out, ",keysize %d", kt.cipher_length * 8); if (o->shared_secret_file) From 3a5a46cf2b7f6a8b8520c2513a8054deb48bfcbe Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Mon, 15 Feb 2016 21:07:11 +0100 Subject: [PATCH 198/643] Add preliminary server-side support for negotiable crypto parameters Add preliminary support for Negotiable Crypto Parameters 'level 2' (IV_NCP=2), as proposed by James Yonan on the openvpn-devel mailinglist: http://comments.gmane.org/gmane.network.openvpn.devel/9385 This patch makes a server push a 'cipher XXX' directive to the client, if the client advertises "IV_NCP=2", where XXX is the cipher set in the server config file. This enables clients that have support for IV_NCP to connect to a server, even when the client does not have the correct cipher specified in it's config file. Since pushing the cipher directive is quite similar to pushing peer-id, I moved peer-id pushing to the same prepare_push_reply() function I created for pushing cipher. Adding these directives as regular push options allows us to use the existing 'push-continuation' infrastructure. Note that we should not reduce safe_cap in send_push_reply, because it was never increased to account for peer-id. This is a preliminary patch, which will be followed by more patches to add client support, and configurability. v2: * Reword doxygen of push_options_fmt() * No longer push IV_NCP as a server Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: URL: http://article.gmane.org/gmane.network.openvpn.devel/11170 Signed-off-by: Gert Doering --- src/openvpn/push.c | 97 +++++++++++++++++++++++++++++++++++++++------- src/openvpn/push.h | 2 - 2 files changed, 82 insertions(+), 17 deletions(-) diff --git a/src/openvpn/push.c b/src/openvpn/push.c index d4f3cb6d349..c29093b4ecc 100644 --- a/src/openvpn/push.c +++ b/src/openvpn/push.c @@ -40,6 +40,30 @@ #if P2MP +/** + * Add an option to the push list by providing a format string. + * + * The string added to the push options is allocated in o->gc, so the caller + * does not have to preserve anything. + * + * @param o The current connection's options + * @param msglevel The message level to use when printing errors + * @param fmt Format string for the option + * @param ... Format string arguments + * + * @return true on success, false on failure. + */ +static bool push_option_fmt(struct options *o, int msglevel, + const char *fmt, ...) +#ifdef __GNUC__ +#if __USE_MINGW_ANSI_STDIO + __attribute__ ((format (gnu_printf, 3, 4))) +#else + __attribute__ ((format (__printf__, 3, 4))) +#endif +#endif + ; + /* * Auth username/password * @@ -239,7 +263,47 @@ send_push_request (struct context *c) #if P2MP_SERVER -bool +/** + * Prepare push options, based on local options and available peer info. + * + * @param options Connection options + * @param tls_multi TLS state structure for the current tunnel + * + * @return true on success, false on failure. + */ +static bool +prepare_push_reply (struct options *o, struct tls_multi *tls_multi) +{ + const char *optstr = NULL; + const char * const peer_info = tls_multi->peer_info; + + /* Send peer-id if client supports it */ + optstr = peer_info ? strstr(peer_info, "IV_PROTO=") : NULL; + if (optstr) + { + int proto = 0; + int r = sscanf(optstr, "IV_PROTO=%d", &proto); + if ((r == 1) && (proto >= 2)) + { + push_option_fmt(o, M_USAGE, "peer-id %d", tls_multi->peer_id); + } + } + + /* Push cipher if client supports Negotiable Crypto Parameters */ + optstr = peer_info ? strstr(peer_info, "IV_NCP=") : NULL; + if (optstr) + { + int ncp = 0; + int r = sscanf(optstr, "IV_NCP=%d", &ncp); + if ((r == 1) && (ncp == 2)) + { + push_option_fmt(o, M_USAGE, "cipher %s", o->ciphername); + } + } + return true; +} + +static bool send_push_reply (struct context *c) { struct gc_arena gc = gc_new (); @@ -309,19 +373,6 @@ send_push_reply (struct context *c) if (multi_push) buf_printf (&buf, ",push-continuation 1"); - /* Send peer-id if client supports it */ - if (c->c2.tls_multi->peer_info) - { - const char* proto_str = strstr(c->c2.tls_multi->peer_info, "IV_PROTO="); - if (proto_str) - { - int proto = 0; - int r = sscanf(proto_str, "IV_PROTO=%d", &proto); - if ((r == 1) && (proto >= 2)) - buf_printf(&buf, ",peer-id %d", c->c2.tls_multi->peer_id); - } - } - if (BLEN (&buf) > sizeof(cmd)-1) { const bool status = send_control_channel_string (c, BSTR (&buf), D_PUSH); @@ -409,6 +460,21 @@ push_options (struct options *o, char **p, int msglevel, struct gc_arena *gc) push_option (o, opt, msglevel); } +static bool push_option_fmt(struct options *o, int msglevel, + const char *format, ...) +{ + va_list arglist; + char tmp[256] = {0}; + int len = -1; + va_start (arglist, format); + len = vsnprintf (tmp, sizeof(tmp), format, arglist); + va_end (arglist); + if (len > sizeof(tmp)-1) + return false; + push_option (o, string_alloc (tmp, &o->gc), msglevel); + return true; +} + void push_reset (struct options *o) { @@ -442,7 +508,8 @@ process_incoming_push_request (struct context *c) } else { - if (send_push_reply (c)) + if (prepare_push_reply(&c->options, c->c2.tls_multi) && + send_push_reply (c)) { ret = PUSH_MSG_REQUEST; c->c2.sent_push_reply_expiry = now + 30; diff --git a/src/openvpn/push.h b/src/openvpn/push.h index fa06e080bd8..19bbf5e1fcd 100644 --- a/src/openvpn/push.h +++ b/src/openvpn/push.h @@ -62,8 +62,6 @@ void push_options (struct options *o, char **p, int msglevel, struct gc_arena *g void push_reset (struct options *o); -bool send_push_reply (struct context *c); - void remove_iroutes_from_push_route_list (struct options *o); void send_auth_failed (struct context *c, const char *client_reason); From b3560c98d7e4877f3ff6283dde1751654e6f7d6d Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sun, 21 Feb 2016 02:08:11 +0100 Subject: [PATCH 199/643] Minor AEAD patch cleanup * Remove stale function declaration. This slipped into the AEAD cipher modes patch, but the function is now implemented as a static function is ssl.c. * Add ASSERT() to ensure frame is not NULL. * Fix "ENCRYPT TO" log message in openvpn_encrypt_aead(). Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1456016892-8671-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/11233 Signed-off-by: Gert Doering --- src/openvpn/crypto.c | 5 +++-- src/openvpn/crypto.h | 11 ----------- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c index e8ab27a8fba..6d9c119414c 100644 --- a/src/openvpn/crypto.c +++ b/src/openvpn/crypto.c @@ -161,10 +161,10 @@ openvpn_encrypt_aead (struct buffer *buf, struct buffer work, /* Write authentication tag */ ASSERT (cipher_ctx_get_tag (ctx->cipher, mac_out, mac_len)); - dmsg (D_PACKET_CONTENT, "ENCRYPT TO: %s", format_hex (BPTR (buf), BLEN (buf), 80, &gc)); - *buf = work; + dmsg (D_PACKET_CONTENT, "ENCRYPT TO: %s", format_hex (BPTR (buf), BLEN (buf), 80, &gc)); + cleanup: gc_free (&gc); return; @@ -397,6 +397,7 @@ openvpn_decrypt_aead (struct buffer *buf, struct buffer work, gc_init (&gc); ASSERT (opt); + ASSERT (frame); ASSERT (buf->len > 0); ASSERT (ctx->cipher); ASSERT (cipher_kt_mode_aead (cipher_kt)); diff --git a/src/openvpn/crypto.h b/src/openvpn/crypto.h index 14b6ab7cb03..d3e08c1e6da 100644 --- a/src/openvpn/crypto.h +++ b/src/openvpn/crypto.h @@ -311,17 +311,6 @@ void free_key_ctx (struct key_ctx *ctx); void free_key_ctx_bi (struct key_ctx_bi *ctx); -/** - * Set an implicit IV for a key context. - * - * @param ctx The key context to update - * @param iv The implicit IV to load into ctx - * @param len The length (in bytes) of iv - */ -bool key_ctx_set_implicit_iv (struct key_ctx *ctx, const uint8_t *iv, - size_t len); - - /**************************************************************************/ /** @name Functions for performing security operations on data channel packets From 463ea2bc90555efdcd8b2591a18aad2d47eb1d25 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Mon, 22 Feb 2016 15:24:06 +0100 Subject: [PATCH 200/643] Clean up get_tls_handhake_key() This function has *much* more code than required. This commit cleans up the function: * Merge the handling of inline and non-inline code. * Don't double-check key.2, since must_have_n_keys() already does that (but keep the message about dropped passphrase support in 2.4). * Remove stale references to 'passphrase' - we no longer support those This commit should not change any behaviour except for log messages. v2: Leave message about dropped passphrase support in place - this option was dropped in 2.4, so it is indeed better to be clear about it. Signed-off-by: Steffan Karger Acked-by: Arne Schwabe Message-Id: <1456151046-16047-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/11238 Signed-off-by: Gert Doering --- src/openvpn/crypto.c | 46 ++++++++++++-------------------------------- 1 file changed, 12 insertions(+), 34 deletions(-) diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c index 6d9c119414c..bd866799b37 100644 --- a/src/openvpn/crypto.c +++ b/src/openvpn/crypto.c @@ -1080,57 +1080,35 @@ test_crypto (struct crypto_options *co, struct frame* frame) void get_tls_handshake_key (const struct key_type *key_type, struct key_ctx_bi *ctx, - const char *passphrase_file, + const char *key_file, const int key_direction, const unsigned int flags) { - if (passphrase_file && key_type->hmac_length) + if (key_file) { struct key2 key2; struct key_direction_state kds; if (flags & GHK_INLINE) { - /* key was specified inline, key text is in passphrase_file */ - read_key_file (&key2, passphrase_file, RKF_INLINE|RKF_MUST_SUCCEED); - - /* succeeded? */ - if (key2.n == 2) - msg (M_INFO, "Control Channel Authentication: tls-auth using INLINE static key file"); - else - msg (M_FATAL, "INLINE tls-auth file lacks the requisite 2 keys"); + read_key_file (&key2, key_file, RKF_INLINE|RKF_MUST_SUCCEED); } else - { - /* first try to parse as an OpenVPN static key file */ - read_key_file (&key2, passphrase_file, 0); + { + read_key_file (&key2, key_file, RKF_MUST_SUCCEED); + } - /* succeeded? */ - if (key2.n == 2) + if (key2.n != 2) { - msg (M_INFO, - "Control Channel Authentication: using '%s' as a " PACKAGE_NAME " static key file", - passphrase_file); + msg (M_ERR, "Control Channel Authentication: File '%s' does not " + "have OpenVPN Static Key format. Using free-form passphrase " + "file is not supported anymore.", key_file); } - else - { - CLEAR (key2); - - /* failed, now bail out */ - - msg (M_ERR, - "Control Channel Authentication: File '%s' does not have OpenVPN Static Key format. " - "Using free-form passphrase file is not supported anymore", - passphrase_file); - } - } /* handle key direction */ - key_direction_state_init (&kds, key_direction); - must_have_n_keys (passphrase_file, "tls-auth", &key2, kds.need_keys); - - /* initialize hmac key in both directions */ + must_have_n_keys (key_file, "tls-auth", &key2, kds.need_keys); + /* initialize key in both directions */ init_key_ctx (&ctx->encrypt, &key2.keys[kds.out_key], key_type, OPENVPN_OP_ENCRYPT, "Outgoing Control Channel Authentication"); init_key_ctx (&ctx->decrypt, &key2.keys[kds.in_key], key_type, OPENVPN_OP_DECRYPT, From f3c8a04d60216d532f239c951a4694d7c1d5eaa8 Mon Sep 17 00:00:00 2001 From: Selva Nair Date: Fri, 19 Feb 2016 22:13:08 -0500 Subject: [PATCH 201/643] Restrict options/configs for startup through interactive service Windows only: - Allow only a set of whitelisted options in the command line options passed by interactive service clients unless (i) user is the local Adminsitrator group AND/OR (ii) in a predefined group (see below) Only the group membership is checked, the client process need not be running with any elevated privileges available to those groups. - Restrict config files to config_dir or it sub directories unless (i) and/or (ii) above is true (config_dir is as defined in HKLM\Software\OpenVPN\config_dir) - The predefined group may be set in the registry HKLM\Software\OpenVPN\ovpn_admin_group (default: "OpenVPN Administrators") - The white-list of options is a simple flat array of option strings (without leading --) defined in validate.c - Further options may be added to the whitelist without breaking the GUI -- the startup data is passed from the GUI to the service the same way as before. Notes to GUI developers: (i) If the user is an administrator, the service will grant all privileges even if the GUI is not running elevated. This is practically equivalent to 'highestAvailable' without the risks of running the GUI elevated. (ii) If the option checks fail, openvpn is not started, but an error message is passed back to the service pipe and written to event log. Currently the GUI does not read from the service pipe -- this needs fixing. v2 changes: - checked non-unicode build and fixed an error -- in case anyone builds non-unicode - added an info message to event log when user auth succeeds Signed-off-by: Selva Nair Acked-by: Gert Doering Message-Id: <1455937988-12414-1-git-send-email-selva.nair@gmail.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/11225 Signed-off-by: Gert Doering --- src/openvpnserv/Makefile.am | 3 +- src/openvpnserv/common.c | 13 ++- src/openvpnserv/interactive.c | 96 ++++++++++++++++ src/openvpnserv/service.h | 2 + src/openvpnserv/validate.c | 208 ++++++++++++++++++++++++++++++++++ src/openvpnserv/validate.h | 48 ++++++++ 6 files changed, 366 insertions(+), 4 deletions(-) create mode 100644 src/openvpnserv/validate.c create mode 100644 src/openvpnserv/validate.h diff --git a/src/openvpnserv/Makefile.am b/src/openvpnserv/Makefile.am index 4bb1c275014..5aba53a4a50 100644 --- a/src/openvpnserv/Makefile.am +++ b/src/openvpnserv/Makefile.am @@ -26,7 +26,7 @@ openvpnserv_CFLAGS = \ -municode -D_UNICODE \ -UNTDDI_VERSION -U_WIN32_WINNT \ -D_WIN32_WINNT=_WIN32_WINNT_VISTA -openvpnserv_LDADD = -ladvapi32 -luserenv -liphlpapi -lws2_32 +openvpnserv_LDADD = -ladvapi32 -luserenv -liphlpapi -lshlwapi -lnetapi32 -lws2_32 endif openvpnserv_SOURCES = \ @@ -34,4 +34,5 @@ openvpnserv_SOURCES = \ automatic.c \ interactive.c \ service.c service.h \ + validate.c validate.h \ openvpnserv_resources.rc diff --git a/src/openvpnserv/common.c b/src/openvpnserv/common.c index a2937964c2c..dba4724e021 100644 --- a/src/openvpnserv/common.c +++ b/src/openvpnserv/common.c @@ -23,7 +23,7 @@ */ #include - +#include /* * These are necessary due to certain buggy implementations of (v)snprintf, * that don't guarantee null termination for size > 0. @@ -53,7 +53,6 @@ openvpn_sntprintf (LPTSTR str, size_t size, LPCTSTR format, ...) return len; } - #define REG_KEY TEXT("SOFTWARE\\" PACKAGE_NAME) static DWORD @@ -114,6 +113,13 @@ GetOpenvpnSettings (settings_t *s) if (error != ERROR_SUCCESS) goto out; + /* read if present, else use default */ + error = GetRegString (key, TEXT("ovpn_admin_group"), s->ovpn_admin_group, sizeof (s->ovpn_admin_group)); + if (error != ERROR_SUCCESS) + { + openvpn_sntprintf(s->ovpn_admin_group, _countof(s->ovpn_admin_group), OVPN_ADMIN_GROUP); + error = 0; /* this error is not fatal */ + } /* set process priority */ if (!_tcsicmp (priority, TEXT("IDLE_PRIORITY_CLASS"))) s->priority = IDLE_PRIORITY_CLASS; @@ -194,7 +200,8 @@ MsgToEventLog (DWORD flags, LPCTSTR format, ...) if (hEventSource != NULL) { openvpn_sntprintf (msg[0], _countof (msg[0]), - TEXT("%s error: %s"), APPNAME, err_msg); + TEXT("%s%s: %s"), APPNAME, + (flags & MSG_FLAGS_ERROR) ? TEXT(" error") : TEXT(""), err_msg); va_start (arglist, format); openvpn_vsntprintf (msg[1], _countof (msg[1]), format, arglist); diff --git a/src/openvpnserv/interactive.c b/src/openvpnserv/interactive.c index 0f3d1d47aa0..97853a7353c 100644 --- a/src/openvpnserv/interactive.c +++ b/src/openvpnserv/interactive.c @@ -33,8 +33,10 @@ #include #include #include +#include #include "openvpn-msg.h" +#include "validate.h" #define IO_TIMEOUT 2000 /*ms*/ @@ -292,6 +294,93 @@ ReturnOpenvpnOutput (HANDLE pipe, HANDLE ovpn_output, DWORD count, LPHANDLE even free (wide_output); } +/* + * Validate options against a white list. Also check the config_file is + * inside the config_dir. The white list is defined in validate.c + * Returns true on success + */ +static BOOL +ValidateOptions (HANDLE pipe, const WCHAR *workdir, const WCHAR *options) +{ + WCHAR **argv; + int argc; + WCHAR buf[256]; + BOOL ret = FALSE; + int i; + const WCHAR *msg1 = L"You have specified a config file location (%s relative to %s)" + " that requires admin approval. This error may be avoided" + " by adding your account to the \"%s\" group"; + + const WCHAR *msg2 = L"You have specified an option (%s) that may be used" + " only with admin approval. This error may be avoided" + " by adding your account to the \"%s\" group"; + + argv = CommandLineToArgvW (options, &argc); + + if (!argv) + { + ReturnLastError (pipe, L"CommandLineToArgvW"); + ReturnError (pipe, ERROR_STARTUP_DATA, L"Cannot validate options", 1, &exit_event); + goto out; + } + + /* Note: argv[0] is the first option */ + if (argc < 1) /* no options */ + { + ret = TRUE; + goto out; + } + + /* + * If only one argument, it is the config file + */ + if (argc == 1) + { + WCHAR *argv_tmp[2] = { L"--config", argv[0] }; + + if (!CheckOption (workdir, 2, argv_tmp, &settings)) + { + snwprintf (buf, _countof(buf), msg1, argv[0], workdir, + settings.ovpn_admin_group); + buf[_countof(buf) - 1] = L'\0'; + ReturnError (pipe, ERROR_STARTUP_DATA, buf, 1, &exit_event); + } + goto out; + } + + for (i = 0; i < argc; ++i) + { + if (!IsOption(argv[i])) + continue; + + if (!CheckOption (workdir, argc-i, &argv[i], &settings)) + { + if (wcscmp(L"--config", argv[i]) == 0 && argc-i > 1) + { + snwprintf (buf, _countof(buf), msg1, argv[i+1], workdir, + settings.ovpn_admin_group); + buf[_countof(buf) - 1] = L'\0'; + ReturnError (pipe, ERROR_STARTUP_DATA, buf, 1, &exit_event); + } + else + { + snwprintf (buf, _countof(buf), msg2, argv[i], + settings.ovpn_admin_group); + buf[_countof(buf) - 1] = L'\0'; + ReturnError (pipe, ERROR_STARTUP_DATA, buf, 1, &exit_event); + } + goto out; + } + } + + /* all options passed */ + ret = TRUE; + +out: + if (argv) + LocalFree (argv); + return ret; +} static BOOL GetStartupData (HANDLE pipe, STARTUP_DATA *sud) @@ -835,6 +924,13 @@ RunOpenvpn (LPVOID p) goto out; } + /* Check user is authorized or options are white-listed */ + if (!IsAuthorizedUser (ovpn_user->User.Sid, &settings) && + !ValidateOptions (pipe, sud.directory, sud.options)) + { + goto out; + } + /* OpenVPN process DACL entry for access by service and user */ ea[0].grfAccessPermissions = SPECIFIC_RIGHTS_ALL | STANDARD_RIGHTS_ALL; ea[0].grfAccessMode = SET_ACCESS; diff --git a/src/openvpnserv/service.h b/src/openvpnserv/service.h index 5249b316773..94bfb0794e1 100644 --- a/src/openvpnserv/service.h +++ b/src/openvpnserv/service.h @@ -61,11 +61,13 @@ typedef struct { DWORD start_type; } openvpn_service_t; +#define MAX_NAME 256 typedef struct { TCHAR exe_path[MAX_PATH]; TCHAR config_dir[MAX_PATH]; TCHAR ext_string[16]; TCHAR log_dir[MAX_PATH]; + TCHAR ovpn_admin_group[MAX_NAME]; DWORD priority; BOOL append; } settings_t; diff --git a/src/openvpnserv/validate.c b/src/openvpnserv/validate.c new file mode 100644 index 00000000000..d7446de4794 --- /dev/null +++ b/src/openvpnserv/validate.c @@ -0,0 +1,208 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single TCP/UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2016 Selva Nair + * + * 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 + */ + +#include "validate.h" + +#include + +static const WCHAR *white_list[] = + { + L"auth-retry", + L"config", + L"log", + L"log-append", + L"management", + L"management-forget-disconnect", + L"management-hold", + L"management-query-passwords", + L"management-query-proxy", + L"management-signal", + L"management-up-down", + L"mute", + L"setenv", + L"service", + L"verb", + + NULL /* last value */ + }; + +/* + * Check workdir\fname is inside config_dir + * The logic here is simple: we may reject some valid paths if ..\ is in any of the strings + */ +static BOOL +CheckConfigPath (const WCHAR *workdir, const WCHAR *fname, const settings_t *s) +{ + WCHAR tmp[MAX_PATH]; + WCHAR widepath[MAX_PATH]; + WCHAR relpath[MAX_PATH]; + const WCHAR *config_file = NULL; + const WCHAR *config_dir = NULL; + + /* convert fname to full path */ + if (PathIsRelativeW (fname) ) + { + snwprintf (tmp, _countof(tmp), L"%s\\%s", workdir, fname); + tmp[_countof(tmp)-1] = L'\0'; + config_file = tmp; + } + else + { + config_file = fname; + } + +#ifdef UNICODE + config_dir = s->config_dir; +#else + if (MultiByteToWideChar (CP_UTF8, 0, s->config_dir, -1, widepath, MAX_PATH) == 0) + { + MsgToEventLog (M_SYSERR, TEXT("Failed to convert config_dir name to WideChar")); + return FALSE; + } + config_dir = widepath; +#endif + + if (wcsncmp (config_dir, config_file, wcslen(config_dir)) == 0 && + wcsstr (config_file + wcslen(config_dir), L"..") == NULL ) + return TRUE; + + return FALSE; +} + + +/* + * A simple linear search meant for a small wchar_t *array. + * Returns index to the item if found, -1 otherwise. + */ +static int +OptionLookup (const WCHAR *name, const WCHAR *white_list[]) +{ + int i; + + for (i = 0 ; white_list[i]; i++) + { + if ( wcscmp(white_list[i], name) == 0 ) + return i; + } + + return -1; +} + +/* + * Check whether user is a member of Administrators group or + * the group specified in s->ovpn_admin_group + */ +BOOL +IsAuthorizedUser (SID *sid, settings_t *s) +{ + LOCALGROUP_USERS_INFO_0 *groups = NULL; + DWORD nread; + DWORD nmax; + WCHAR *tmp = NULL; + const WCHAR *admin_group[2]; + WCHAR username[MAX_NAME]; + WCHAR domain[MAX_NAME]; + DWORD err, len = MAX_NAME; + int i; + BOOL ret = FALSE; + SID_NAME_USE sid_type; + + /* Get username */ + if (!LookupAccountSidW (NULL, sid, username, &len, domain, &len, &sid_type)) + { + MsgToEventLog (M_SYSERR, TEXT("LookupAccountSid")); + goto out; + } + + /* Get an array of groups the user is member of */ + err = NetUserGetLocalGroups (NULL, username, 0, LG_INCLUDE_INDIRECT, (LPBYTE *) &groups, + MAX_PREFERRED_LENGTH, &nread, &nmax); + if (err && err != ERROR_MORE_DATA) + { + SetLastError (err); + MsgToEventLog (M_SYSERR, TEXT("NetUserGetLocalGroups")); + goto out; + } + + admin_group[0] = SYSTEM_ADMIN_GROUP; +#ifdef UNICODE + admin_group[1] = s->ovpn_admin_group; +#else + tmp = NULL; + len = MultiByteToWideChar (CP_UTF8, 0, s->ovpn_admin_group, -1, NULL, 0); + if (len == 0 || (tmp = malloc (len*sizeof(WCHAR))) == NULL) + { + MsgToEventLog (M_SYSERR, TEXT("Failed to convert admin group name to WideChar")); + goto out; + } + MultiByteToWideChar (CP_UTF8, 0, s->ovpn_admin_group, -1, tmp, len); + admin_group[1] = tmp; +#endif + + /* Check if user's groups include any of the admin groups */ + for (i = 0; i < nread; i++) + { + if ( wcscmp (groups[i].lgrui0_name, admin_group[0]) == 0 || + wcscmp (groups[i].lgrui0_name, admin_group[1]) == 0 + ) + { + MsgToEventLog (M_INFO, TEXT("Authorizing user %s by virtue of membership in group %s"), + username, groups[i].lgrui0_name); + ret = TRUE; + break; + } + } + +out: + if (groups) + NetApiBufferFree (groups); + free (tmp); + + return ret; +} + +/* + * Check whether option argv[0] is white-listed. If argv[0] == "--config", + * also check that argv[1], if present, passes CheckConfigPath(). + * The caller should set argc to the number of valid elements in argv[] array. + */ +BOOL +CheckOption (const WCHAR *workdir, int argc, WCHAR *argv[], const settings_t *s) +{ + /* Do not modify argv or *argv -- ideally it should be const WCHAR *const *, but alas...*/ + + if ( wcscmp (argv[0], L"--config") == 0 && + argc > 1 && + !CheckConfigPath (workdir, argv[1], s) + ) + { + return FALSE; + } + + /* option name starts at 2 characters from argv[i] */ + if (OptionLookup (argv[0] + 2, white_list) == -1) /* not found */ + return FALSE; + + return TRUE; +} diff --git a/src/openvpnserv/validate.h b/src/openvpnserv/validate.h new file mode 100644 index 00000000000..0d0270a9c41 --- /dev/null +++ b/src/openvpnserv/validate.h @@ -0,0 +1,48 @@ + +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single TCP/UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2016 Selva Nair + * + * 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 VALIDATE_H +#define VALIDATE_H + +#include "service.h" + +/* Authorized groups who can use any options and config locations */ +#define SYSTEM_ADMIN_GROUP TEXT("Administrators") +#define OVPN_ADMIN_GROUP TEXT("OpenVPN Administrators") +/* The last one may be reset in registry: HKLM\Software\OpenVPN\ovpn_admin_group */ + +BOOL +IsAuthorizedUser (SID *sid, settings_t *s); + +BOOL +CheckOption (const WCHAR *workdir, int narg, WCHAR *argv[], const settings_t *s); + +static inline BOOL +IsOption (const WCHAR *o) +{ + return (wcsncmp (o, L"--", 2) == 0); +} + +#endif From 236769150f64087c590c718c76916ee3c8c9d3b5 Mon Sep 17 00:00:00 2001 From: ValdikSS Date: Sat, 16 Jan 2016 02:35:38 +0300 Subject: [PATCH 202/643] Update --block-outside-dns to work on Windows Vista Windows Vista doesn't support non-equal matching of application name, it is available only since Windows 7. This commit splits 2 filtering conditions with non-equal matching to 2 filters each with 1 filtering condition: permit IPv4 (first filter) and IPv6 (second filter) port 53 traffic from openvpn.exe instead of blocking all non-openvpn.exe traffic on port 53 for both protocols. Trac #648 Acked-by: Selva Nair Message-Id: <1452900938-3636-1-git-send-email-iam@valdikss.org.ru> URL: http://article.gmane.org/gmane.network.openvpn.devel/10998 Signed-off-by: Gert Doering --- src/openvpn/win32.c | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/src/openvpn/win32.c b/src/openvpn/win32.c index 6b7a6ae451b..72243a81b48 100644 --- a/src/openvpn/win32.c +++ b/src/openvpn/win32.c @@ -1222,13 +1222,14 @@ win_wfp_block_dns (const NET_IFINDEX index) /* Prepare filter. */ Filter.subLayerKey = SubLayer.subLayerKey; Filter.displayData.name = FIREWALL_NAME; - Filter.weight.type = FWP_EMPTY; + Filter.weight.type = FWP_UINT8; + Filter.weight.uint8 = 0xF; Filter.filterCondition = Condition; Filter.numFilterConditions = 2; - /* First filter. Block IPv4 DNS queries except from OpenVPN itself. */ + /* First filter. Permit IPv4 DNS queries from OpenVPN itself. */ Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4; - Filter.action.type = FWP_ACTION_BLOCK; + Filter.action.type = FWP_ACTION_PERMIT; Condition[0].fieldKey = FWPM_CONDITION_IP_REMOTE_PORT; Condition[0].matchType = FWP_MATCH_EQUAL; @@ -1236,26 +1237,44 @@ win_wfp_block_dns (const NET_IFINDEX index) Condition[0].conditionValue.uint16 = 53; Condition[1].fieldKey = FWPM_CONDITION_ALE_APP_ID; - Condition[1].matchType = FWP_MATCH_NOT_EQUAL; + Condition[1].matchType = FWP_MATCH_EQUAL; Condition[1].conditionValue.type = FWP_BYTE_BLOB_TYPE; Condition[1].conditionValue.byteBlob = openvpnblob; /* Add filter condition to our interface. */ if (!win_wfp_add_filter(m_hEngineHandle, &Filter, NULL, &filterid)) goto err; - dmsg (D_LOW, "Filter (Block IPv4 DNS) added with ID=%I64d", filterid); + dmsg (D_LOW, "Filter (Permit OpenVPN IPv4 DNS) added with ID=%I64d", filterid); - /* Second filter. Block IPv6 DNS queries except from OpenVPN itself. */ + /* Second filter. Permit IPv6 DNS queries from OpenVPN itself. */ Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V6; /* Add filter condition to our interface. */ + if (!win_wfp_add_filter(m_hEngineHandle, &Filter, NULL, &filterid)) + goto err; + dmsg (D_LOW, "Filter (Permit OpenVPN IPv6 DNS) added with ID=%I64d", filterid); + + /* Third filter. Block all IPv4 DNS queries. */ + Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4; + Filter.action.type = FWP_ACTION_BLOCK; + Filter.weight.type = FWP_EMPTY; + Filter.numFilterConditions = 1; + + if (!win_wfp_add_filter(m_hEngineHandle, &Filter, NULL, &filterid)) + goto err; + dmsg (D_LOW, "Filter (Block IPv4 DNS) added with ID=%I64d", filterid); + + /* Forth filter. Block all IPv6 DNS queries. */ + Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V6; + if (!win_wfp_add_filter(m_hEngineHandle, &Filter, NULL, &filterid)) goto err; dmsg (D_LOW, "Filter (Block IPv6 DNS) added with ID=%I64d", filterid); - /* Third filter. Permit IPv4 DNS queries from TAP. */ + /* Fifth filter. Permit IPv4 DNS queries from TAP. */ Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4; Filter.action.type = FWP_ACTION_PERMIT; + Filter.numFilterConditions = 2; Condition[1].fieldKey = FWPM_CONDITION_IP_LOCAL_INTERFACE; Condition[1].matchType = FWP_MATCH_EQUAL; @@ -1267,7 +1286,7 @@ win_wfp_block_dns (const NET_IFINDEX index) goto err; dmsg (D_LOW, "Filter (Permit IPv4 DNS queries from TAP) added with ID=%I64d", filterid); - /* Forth filter. Permit IPv6 DNS queries from TAP. */ + /* Sixth filter. Permit IPv6 DNS queries from TAP. */ Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V6; /* Add filter condition to our interface. */ From 852f1e49c7e692c6392fe07160cfbc8d6b17f0d0 Mon Sep 17 00:00:00 2001 From: Selva Nair Date: Sun, 14 Feb 2016 12:28:01 -0500 Subject: [PATCH 203/643] Send stdout and stderr of OpenVPN started by interactive service to NUL Currently the service directs stdout/stderr of openvpn process to a pipe. The service never reads from it unless the process exits with an error. This causes the process to hang when large amount of log is written to stdout. - Direct stdout/stderr to NUL - Write the exit code (if nonzero) to the event log Signed-off-by: Selva Nair Acked-by: Gert Doering Message-Id: <1455470881-32341-1-git-send-email-selva.nair@gmail.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/11161 Signed-off-by: Gert Doering --- src/openvpnserv/interactive.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/openvpnserv/interactive.c b/src/openvpnserv/interactive.c index 97853a7353c..22239b273d3 100644 --- a/src/openvpnserv/interactive.c +++ b/src/openvpnserv/interactive.c @@ -821,7 +821,7 @@ RunOpenvpn (LPVOID p) PTOKEN_USER svc_user, ovpn_user; HANDLE svc_token = NULL, imp_token = NULL, pri_token = NULL; HANDLE stdin_read = NULL, stdin_write = NULL; - HANDLE stdout_read = NULL, stdout_write = NULL; + HANDLE stdout_write = NULL; DWORD pipe_mode, len, exit_code = 0; STARTUP_DATA sud = { 0, 0, 0 }; STARTUPINFOW startup_info; @@ -970,10 +970,17 @@ RunOpenvpn (LPVOID p) goto out; } + /* use /dev/null for stdout of openvpn (client should use --log for output) */ + stdout_write = CreateFile(_T("NUL"), GENERIC_WRITE, FILE_SHARE_WRITE, + &inheritable, OPEN_EXISTING, 0, NULL); + if (stdout_write == INVALID_HANDLE_VALUE) + { + ReturnLastError (pipe, L"CreateFile for stdout"); + goto out; + } + if (!CreatePipe(&stdin_read, &stdin_write, &inheritable, 0) || - !CreatePipe(&stdout_read, &stdout_write, &inheritable, 0) || - !SetHandleInformation(stdin_write, HANDLE_FLAG_INHERIT, 0) || - !SetHandleInformation(stdout_read, HANDLE_FLAG_INHERIT, 0)) + !SetHandleInformation(stdin_write, HANDLE_FLAG_INHERIT, 0)) { ReturnLastError (pipe, L"CreatePipe"); goto out; @@ -1081,8 +1088,13 @@ RunOpenvpn (LPVOID p) if (exit_code == STILL_ACTIVE) TerminateProcess (proc_info.hProcess, 1); else if (exit_code != 0) - ReturnOpenvpnOutput (pipe, stdout_read, 1, &exit_event); - + { + WCHAR buf[256]; + int len = _snwprintf (buf, _countof (buf), + L"OpenVPN exited with error: exit code = %lu", exit_code); + buf[_countof (buf) - 1] = L'\0'; + ReturnError (pipe, ERROR_OPENVPN_STARTUP, buf, 1, &exit_event); + } Undo (&undo_lists); out: @@ -1098,7 +1110,6 @@ RunOpenvpn (LPVOID p) CloseHandleEx (&proc_info.hThread); CloseHandleEx (&stdin_read); CloseHandleEx (&stdin_write); - CloseHandleEx (&stdout_read); CloseHandleEx (&stdout_write); CloseHandleEx (&svc_token); CloseHandleEx (&imp_token); From ab0f846de6991345c30f5b69817304183d347e0e Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Thu, 25 Feb 2016 15:10:34 +0100 Subject: [PATCH 204/643] Fix OCSP_check.sh As reported in trac #582, the OCSP_check.sh script should use grep -E, instead of grep -F when it uses ^ in the expression. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1456409434-14784-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/11254 Signed-off-by: Gert Doering --- contrib/OCSP_check/OCSP_check.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/OCSP_check/OCSP_check.sh b/contrib/OCSP_check/OCSP_check.sh index 6876c6d8c40..26757889d4a 100644 --- a/contrib/OCSP_check/OCSP_check.sh +++ b/contrib/OCSP_check/OCSP_check.sh @@ -105,9 +105,9 @@ if [ $check_depth -eq -1 ] || [ $cur_depth -eq $check_depth ]; then exit 1 fi # check that the reported status of certificate is ok - if echo "$status" | grep -Fq "^${serial}: good"; then + if echo "$status" | grep -Eq "^${serial}: good"; then # check if signature on the OCSP response verified correctly - if echo "$status" | grep -Fq "^Response verify OK"; then + if echo "$status" | grep -Eq "^Response verify OK"; then exit 0 fi fi From 9b9187031b742258b518dbde648326b3e3a8d8d8 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Thu, 25 Feb 2016 15:58:32 +0100 Subject: [PATCH 205/643] Fix openserv/validate.o linking issues on mingw. MinGW fails linking after f3c8a04d6021 if the right header files ( and ) are not included. Signed-off-by: Gert Doering Acked-by: Selva Nair Message-Id: <1456412312-21936-1-git-send-email-gert@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/11255 --- src/openvpnserv/validate.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/openvpnserv/validate.c b/src/openvpnserv/validate.c index d7446de4794..b5809b3dd0a 100644 --- a/src/openvpnserv/validate.c +++ b/src/openvpnserv/validate.c @@ -25,6 +25,8 @@ #include "validate.h" #include +#include +#include static const WCHAR *white_list[] = { From 6a4edc7fc09d6a321f87d4dcf331c7d5c3082a8f Mon Sep 17 00:00:00 2001 From: Fish Date: Thu, 25 Feb 2016 16:14:42 -0500 Subject: [PATCH 206/643] Add lz4 support to MSVC. - Include lz4 code and header in VC project files. - Fix an issue in comp-lz4.h that prevents it from compiling under MSVC. Signed-off-by: Fish Acked-by: Gert Doering Message-Id: <1456434882-6009-1-git-send-email-fish.thss@gmail.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/11262 Signed-off-by: Gert Doering --- config-msvc.h | 2 ++ src/compat/compat.vcxproj | 1 + src/compat/compat.vcxproj.filters | 3 +++ src/openvpn/comp-lz4.h | 1 + src/openvpn/openvpn.vcxproj | 4 +++- src/openvpn/openvpn.vcxproj.filters | 17 ++++++++++++++++- 6 files changed, 26 insertions(+), 2 deletions(-) diff --git a/config-msvc.h b/config-msvc.h index 0bcf719502a..9c8d4237aa1 100644 --- a/config-msvc.h +++ b/config-msvc.h @@ -12,6 +12,8 @@ #define ENABLE_FRAGMENT 1 #define ENABLE_HTTP_PROXY 1 #define ENABLE_LZO 1 +#define ENABLE_LZ4 1 +#define NEED_COMPAT_LZ4 1 #define ENABLE_MANAGEMENT 1 #define ENABLE_MULTIHOME 1 #define ENABLE_PKCS11 1 diff --git a/src/compat/compat.vcxproj b/src/compat/compat.vcxproj index 7fca62fc03d..d2695e6bb20 100644 --- a/src/compat/compat.vcxproj +++ b/src/compat/compat.vcxproj @@ -79,6 +79,7 @@ + diff --git a/src/compat/compat.vcxproj.filters b/src/compat/compat.vcxproj.filters index 00bb0ffa70c..0f78e86ed71 100644 --- a/src/compat/compat.vcxproj.filters +++ b/src/compat/compat.vcxproj.filters @@ -33,6 +33,9 @@ Source Files + + Source Files + diff --git a/src/openvpn/comp-lz4.h b/src/openvpn/comp-lz4.h index 9d3c6644f65..7774ca5aacd 100644 --- a/src/openvpn/comp-lz4.h +++ b/src/openvpn/comp-lz4.h @@ -35,6 +35,7 @@ extern const struct compress_alg lz4v2_alg; struct lz4_workspace { + int dummy; }; #endif /* ENABLE_LZ4 */ diff --git a/src/openvpn/openvpn.vcxproj b/src/openvpn/openvpn.vcxproj index 821c46c2fab..8dfbea520a9 100644 --- a/src/openvpn/openvpn.vcxproj +++ b/src/openvpn/openvpn.vcxproj @@ -102,6 +102,7 @@ + @@ -172,9 +173,10 @@ + + - diff --git a/src/openvpn/openvpn.vcxproj.filters b/src/openvpn/openvpn.vcxproj.filters index 40336ba8ade..8b6a2696204 100644 --- a/src/openvpn/openvpn.vcxproj.filters +++ b/src/openvpn/openvpn.vcxproj.filters @@ -207,6 +207,15 @@ Source Files + + Source Files + + + Source Files + + + Source Files + @@ -227,6 +236,12 @@ Header Files + + Header Files + + + Header Files + Header Files @@ -455,4 +470,4 @@ Resource Files - \ No newline at end of file + From 6370f703573c6284e0b3c5935ab204285cdda8e6 Mon Sep 17 00:00:00 2001 From: Selva Nair Date: Sat, 5 Mar 2016 14:39:56 -0500 Subject: [PATCH 207/643] Handle localized Administrators group name in windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Interactive service allows all configs and options if the user is in "Administrators" group. This patch makes it work even if the admin group is renamed or localized. While at it, also remove two unused variables in validate.c. Thanks to Leonardo Basilio for testing the patch on a localized version of windows and Samuli Seppänen for pointing out this issue. Signed-off-by: Selva Nair Acked-by: Gert Doering Message-Id: <1457206796-11863-1-git-send-email-selva.nair@gmail.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/11316 Signed-off-by: Gert Doering --- src/openvpnserv/validate.c | 45 +++++++++++++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/src/openvpnserv/validate.c b/src/openvpnserv/validate.c index b5809b3dd0a..7458d75a4ec 100644 --- a/src/openvpnserv/validate.c +++ b/src/openvpnserv/validate.c @@ -57,8 +57,6 @@ static BOOL CheckConfigPath (const WCHAR *workdir, const WCHAR *fname, const settings_t *s) { WCHAR tmp[MAX_PATH]; - WCHAR widepath[MAX_PATH]; - WCHAR relpath[MAX_PATH]; const WCHAR *config_file = NULL; const WCHAR *config_dir = NULL; @@ -111,6 +109,36 @@ OptionLookup (const WCHAR *name, const WCHAR *white_list[]) return -1; } +/* + * The Administrators group may be localized or renamed by admins. + * Get the local name of the group using the SID. + */ +static BOOL +GetBuiltinAdminGroupName (WCHAR *name, DWORD nlen) +{ + BOOL b = FALSE; + PSID admin_sid = NULL; + DWORD sid_size = SECURITY_MAX_SID_SIZE; + SID_NAME_USE snu; + + WCHAR domain[MAX_NAME]; + DWORD dlen = _countof(domain); + + admin_sid = malloc(sid_size); + if (!admin_sid) + return FALSE; + + b = CreateWellKnownSid(WinBuiltinAdministratorsSid, NULL, admin_sid, &sid_size); + if(b) + { + b = LookupAccountSidW(NULL, admin_sid, name, &nlen, domain, &dlen, &snu); + } + + free (admin_sid); + + return b; +} + /* * Check whether user is a member of Administrators group or * the group specified in s->ovpn_admin_group @@ -125,6 +153,7 @@ IsAuthorizedUser (SID *sid, settings_t *s) const WCHAR *admin_group[2]; WCHAR username[MAX_NAME]; WCHAR domain[MAX_NAME]; + WCHAR sysadmin_group[MAX_NAME]; DWORD err, len = MAX_NAME; int i; BOOL ret = FALSE; @@ -147,7 +176,17 @@ IsAuthorizedUser (SID *sid, settings_t *s) goto out; } - admin_group[0] = SYSTEM_ADMIN_GROUP; + if (GetBuiltinAdminGroupName(sysadmin_group, _countof(sysadmin_group))) + { + admin_group[0] = sysadmin_group; + } + else + { + MsgToEventLog (M_SYSERR, TEXT("Failed to get the name of Administrators group. Using the default.")); + /* use the default value */ + admin_group[0] = SYSTEM_ADMIN_GROUP; + } + #ifdef UNICODE admin_group[1] = s->ovpn_admin_group; #else From 239d09938b300f8eafa12bfb8c43373f0215f7bd Mon Sep 17 00:00:00 2001 From: Selva Nair Date: Sun, 6 Mar 2016 00:19:19 -0500 Subject: [PATCH 208/643] Fix interactive service ignoring stop command if openvpn is running Make the exit event not auto-reset so that the signal propagates to all worker threads and finally to the main thread. Fixes Trac #666 Signed-off-by: Selva Nair Acked-by: Gert Doering Message-Id: <1457241559-23374-1-git-send-email-selva.nair@gmail.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/11317 Signed-off-by: Gert Doering --- src/openvpnserv/interactive.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/openvpnserv/interactive.c b/src/openvpnserv/interactive.c index 22239b273d3..39397d12a6f 100644 --- a/src/openvpnserv/interactive.c +++ b/src/openvpnserv/interactive.c @@ -1289,7 +1289,7 @@ ServiceStartInteractive (DWORD dwArgc, LPTSTR *lpszArgv) goto out; io_event = InitOverlapped (&overlapped); - exit_event = CreateEvent (NULL, FALSE, FALSE, NULL); + exit_event = CreateEvent (NULL, TRUE, FALSE, NULL); if (!exit_event || !io_event) { error = MsgToEventLog (M_SYSERR, TEXT("Could not create event")); @@ -1356,6 +1356,7 @@ ServiceStartInteractive (DWORD dwArgc, LPTSTR *lpszArgv) { /* exit event signaled */ CloseHandleEx (&pipe); + ResetEvent (exit_event); error = NO_ERROR; break; } From 3654d953eb0bf40fb8c9e1fbaa3de1dd898dcbab Mon Sep 17 00:00:00 2001 From: Selva Nair Date: Sun, 6 Mar 2016 00:22:02 -0500 Subject: [PATCH 209/643] Use appropriate buffer size for WideCharToMultiByte output in interactive.c A widechar can potentially take more than 2 bytes in UTF-8. Signed-off-by: Selva Nair Acked-by: Gert Doering Message-Id: <1457241722-23433-1-git-send-email-selva.nair@gmail.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/11318 Signed-off-by: Gert Doering --- src/openvpnserv/interactive.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/openvpnserv/interactive.c b/src/openvpnserv/interactive.c index 39397d12a6f..6a7227b7ea4 100644 --- a/src/openvpnserv/interactive.c +++ b/src/openvpnserv/interactive.c @@ -1063,17 +1063,16 @@ RunOpenvpn (LPVOID p) CloseHandleEx (&stdin_read); CloseHandleEx (&svc_pipe); - DWORD input_size = wcslen (sud.std_input) * 2; - if (input_size) + DWORD input_size = WideCharToMultiByte (CP_UTF8, 0, sud.std_input, -1, NULL, 0, NULL, NULL); + LPSTR input = NULL; + if (input_size && (input = malloc (input_size))) { DWORD written; - LPSTR input = malloc (input_size); WideCharToMultiByte (CP_UTF8, 0, sud.std_input, -1, input, input_size, NULL, NULL); WriteFile (stdin_write, input, strlen (input), &written, NULL); free (input); } - while (TRUE) { DWORD bytes = PeekNamedPipeAsync (ovpn_pipe, 1, &exit_event); From 13de0103ea361e2be24ab8b16f5be269c6ab7496 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sun, 6 Mar 2016 10:31:55 +0100 Subject: [PATCH 210/643] Make AEAD modes work with OpenSSL 1.0.1-1.0.1c The 'nobody uses OpenSSL 1.0.1-1.0.1c'-gamble in commit 66407e11 (add AEAD support) did not turn out well; apparently Ubuntu 12.04 LTS ships with a broken OpenSSL 1.0.1. Since this is still a popular platform, re-add the fixup code, now with a clear version check so it's easy to remove once we drop support for OpenSSL 1.0.1. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1457256715-4467-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/11322 Signed-off-by: Gert Doering --- src/openvpn/crypto.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c index bd866799b37..269ec4b536c 100644 --- a/src/openvpn/crypto.c +++ b/src/openvpn/crypto.c @@ -450,6 +450,13 @@ openvpn_decrypt_aead (struct buffer *buf, struct buffer work, tag_ptr = BPTR(buf); ASSERT (buf_advance (buf, tag_size)); dmsg (D_PACKET_CONTENT, "DECRYPT MAC: %s", format_hex (tag_ptr, tag_size, 0, &gc)); +#if defined(ENABLE_CRYPTO_OPENSSL) && OPENSSL_VERSION_NUMBER < 0x10001040L + /* OpenSSL <= 1.0.1c bug requires set tag before processing ciphertext */ + if (!EVP_CIPHER_CTX_ctrl (ctx->cipher, EVP_CTRL_GCM_SET_TAG, tag_size, tag_ptr)) + { + CRYPT_ERROR ("setting tag failed"); + } +#endif if (buf->len < 1) { From e0b3fd49e2b5bba8cb57419a13cb75b56ac91b94 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Thu, 3 Mar 2016 10:22:48 +0100 Subject: [PATCH 211/643] hardening: add safe FD_SET() wrapper openvpn_fd_set() On many platforms (not Windows, for once), FD_SET() can write outside the given fd_set if an fd >= FD_SETSIZE is given. To make sure we don't do that, add an ASSERT() to error out with a clear error message when this does happen. This patch was inspired by remarks about FD_SET() from Sebastian Krahmer of the SuSE Security Team. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1456996968-29472-1-git-send-email-steffan.karger@fox-it.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/11285 Signed-off-by: Gert Doering --- src/openvpn/event.c | 8 ++++---- src/openvpn/fdmisc.h | 16 ++++++++++++++++ src/openvpn/proxy.c | 2 +- src/openvpn/socket.c | 4 ++-- src/openvpn/socks.c | 6 +++--- 5 files changed, 26 insertions(+), 10 deletions(-) diff --git a/src/openvpn/event.c b/src/openvpn/event.c index 34a3c451ff7..c6426911f24 100644 --- a/src/openvpn/event.c +++ b/src/openvpn/event.c @@ -873,18 +873,18 @@ se_ctl (struct event_set *es, event_t event, unsigned int rwflags, void *arg) if (ses->fast) { if (rwflags & EVENT_READ) - FD_SET (event, &ses->readfds); + openvpn_fd_set (event, &ses->readfds); if (rwflags & EVENT_WRITE) - FD_SET (event, &ses->writefds); + openvpn_fd_set (event, &ses->writefds); } else { if (rwflags & EVENT_READ) - FD_SET (event, &ses->readfds); + openvpn_fd_set (event, &ses->readfds); else FD_CLR (event, &ses->readfds); if (rwflags & EVENT_WRITE) - FD_SET (event, &ses->writefds); + openvpn_fd_set (event, &ses->writefds); else FD_CLR (event, &ses->writefds); } diff --git a/src/openvpn/fdmisc.h b/src/openvpn/fdmisc.h index 4b6b6d04f7a..13d6552d29c 100644 --- a/src/openvpn/fdmisc.h +++ b/src/openvpn/fdmisc.h @@ -22,10 +22,26 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifndef FD_MISC_H +#define FD_MISC_H + #include "basic.h" +#include "error.h" +#include "syshead.h" bool set_nonblock_action (int fd); bool set_cloexec_action (int fd); void set_nonblock (int fd); void set_cloexec (int fd); + +static inline void openvpn_fd_set(int fd, fd_set *setp) +{ +#ifndef WIN32 /* The Windows FD_SET() implementation does not overflow */ + ASSERT (fd >= 0 && fd < FD_SETSIZE); +#endif + FD_SET (fd, setp); +} +#undef FD_SET /* prevent direct use of FD_SET() */ + +#endif /* FD_MISC_H */ diff --git a/src/openvpn/proxy.c b/src/openvpn/proxy.c index 2568e19149d..8ff6458098b 100644 --- a/src/openvpn/proxy.c +++ b/src/openvpn/proxy.c @@ -92,7 +92,7 @@ recv_line (socket_descriptor_t sd, } FD_ZERO (&reads); - FD_SET (sd, &reads); + openvpn_fd_set (sd, &reads); tv.tv_sec = timeout_sec; tv.tv_usec = 0; diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c index 714a847a96b..9bcf4d43953 100644 --- a/src/openvpn/socket.c +++ b/src/openvpn/socket.c @@ -1003,7 +1003,7 @@ socket_listen_accept (socket_descriptor_t sd, struct timeval tv; FD_ZERO (&reads); - FD_SET (sd, &reads); + openvpn_fd_set (sd, &reads); tv.tv_sec = 0; tv.tv_usec = 0; @@ -1153,7 +1153,7 @@ openvpn_connect (socket_descriptor_t sd, struct timeval tv; FD_ZERO (&writes); - FD_SET (sd, &writes); + openvpn_fd_set (sd, &writes); tv.tv_sec = 0; tv.tv_usec = 0; diff --git a/src/openvpn/socks.c b/src/openvpn/socks.c index cef7a35e7f2..a9d04aef3f0 100644 --- a/src/openvpn/socks.c +++ b/src/openvpn/socks.c @@ -134,7 +134,7 @@ socks_username_password_auth (struct socks_proxy_info *p, char c; FD_ZERO (&reads); - FD_SET (sd, &reads); + openvpn_fd_set (sd, &reads); tv.tv_sec = timeout_sec; tv.tv_usec = 0; @@ -213,7 +213,7 @@ socks_handshake (struct socks_proxy_info *p, char c; FD_ZERO (&reads); - FD_SET (sd, &reads); + openvpn_fd_set (sd, &reads); tv.tv_sec = timeout_sec; tv.tv_usec = 0; @@ -319,7 +319,7 @@ recv_socks_reply (socket_descriptor_t sd, char c; FD_ZERO (&reads); - FD_SET (sd, &reads); + openvpn_fd_set (sd, &reads); tv.tv_sec = timeout_sec; tv.tv_usec = 0; From 71d89065ad56dda19996deeeffeddcea632b8349 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sun, 6 Mar 2016 13:09:50 +0100 Subject: [PATCH 212/643] Only include aead encrypt/decrypt functions if AEAD modes are supported This fixes the build for OpenSSL < 1.0.1 (broken by commit 3654d953), which has no AEAD support. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1457266190-27228-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/11325 Signed-off-by: Gert Doering --- src/openvpn/crypto.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c index 269ec4b536c..f15ac351101 100644 --- a/src/openvpn/crypto.c +++ b/src/openvpn/crypto.c @@ -86,6 +86,7 @@ memcmp_constant_time (const void *a, const void *b, size_t size) { static void openvpn_encrypt_aead (struct buffer *buf, struct buffer work, struct crypto_options *opt) { +#ifdef HAVE_AEAD_CIPHER_MODES struct gc_arena gc; int outlen = 0; const struct key_ctx *ctx = &opt->key_ctx_bi.encrypt; @@ -173,6 +174,9 @@ openvpn_encrypt_aead (struct buffer *buf, struct buffer work, crypto_clear_error(); buf->len = 0; goto cleanup; +#else /* HAVE_AEAD_CIPHER_MODES */ + ASSERT (0); +#endif } static void @@ -385,6 +389,7 @@ openvpn_decrypt_aead (struct buffer *buf, struct buffer work, struct crypto_options *opt, const struct frame* frame, const uint8_t *ad_start) { +#ifdef HAVE_AEAD_CIPHER_MODES static const char error_prefix[] = "AEAD Decrypt error"; struct packet_id_net pin = { 0 }; const struct key_ctx *ctx = &opt->key_ctx_bi.decrypt; @@ -511,6 +516,10 @@ openvpn_decrypt_aead (struct buffer *buf, struct buffer work, buf->len = 0; gc_free (&gc); return false; +#else /* HAVE_AEAD_CIPHER_MODES */ + ASSERT (0); + return false; +#endif } /* From 6a33a34dee8f3b574275d8df1635fb550ec054f3 Mon Sep 17 00:00:00 2001 From: Selva Nair Date: Thu, 25 Feb 2016 22:24:50 -0500 Subject: [PATCH 213/643] Refactor and move the block-outside-dns code to a new file (block_dns.[ch]) - Move the core of win_wfp_block_dns() to a new function - Remove globals and make it independent of the rest of the code This facilitates implementing support for block-outside-dns through the interactive service. Should not change any functionality. v2 changes: - In comments, correct DeleteBlockDNS() to delete_block_dns_filters v2a: added and (Gert Doering) Signed-off-by: Selva Nair Acked-by: Gert Doering Message-Id: <1456457091-3872-1-git-send-email-selva.nair@gmail.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/11264 Signed-off-by: Gert Doering --- src/openvpn/Makefile.am | 2 +- src/openvpn/block_dns.c | 267 ++++++++++++++++++++++++++++++++++++++++ src/openvpn/block_dns.h | 40 ++++++ src/openvpn/win32.c | 232 +++++----------------------------- 4 files changed, 339 insertions(+), 202 deletions(-) create mode 100644 src/openvpn/block_dns.c create mode 100644 src/openvpn/block_dns.h diff --git a/src/openvpn/Makefile.am b/src/openvpn/Makefile.am index c55a520132f..bf1d749da4f 100644 --- a/src/openvpn/Makefile.am +++ b/src/openvpn/Makefile.am @@ -126,6 +126,6 @@ openvpn_LDADD = \ $(OPTIONAL_SYSTEMD_LIBS) \ $(OPTIONAL_DL_LIBS) if WIN32 -openvpn_SOURCES += openvpn_win32_resources.rc +openvpn_SOURCES += openvpn_win32_resources.rc block_dns.c block_dns.h openvpn_LDADD += -lgdi32 -lws2_32 -lwininet -lcrypt32 -liphlpapi -lwinmm -lfwpuclnt -lrpcrt4 endif diff --git a/src/openvpn/block_dns.c b/src/openvpn/block_dns.c new file mode 100644 index 00000000000..af2db1892c9 --- /dev/null +++ b/src/openvpn/block_dns.c @@ -0,0 +1,267 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single TCP/UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * 2015-2016 + * 2016 Selva Nair + * + * 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 + */ + +#ifdef WIN32 + +#include +#include +#include +#include +#include +#include +#include "block_dns.h" + +/* + * WFP-related defines and GUIDs not in mingw32 + */ + +#ifndef FWPM_SESSION_FLAG_DYNAMIC +#define FWPM_SESSION_FLAG_DYNAMIC 0x00000001 +#endif + +// c38d57d1-05a7-4c33-904f-7fbceee60e82 +DEFINE_GUID( + FWPM_LAYER_ALE_AUTH_CONNECT_V4, + 0xc38d57d1, + 0x05a7, + 0x4c33, + 0x90, 0x4f, 0x7f, 0xbc, 0xee, 0xe6, 0x0e, 0x82 +); + +// 4a72393b-319f-44bc-84c3-ba54dcb3b6b4 +DEFINE_GUID( + FWPM_LAYER_ALE_AUTH_CONNECT_V6, + 0x4a72393b, + 0x319f, + 0x44bc, + 0x84, 0xc3, 0xba, 0x54, 0xdc, 0xb3, 0xb6, 0xb4 +); + +// d78e1e87-8644-4ea5-9437-d809ecefc971 +DEFINE_GUID( + FWPM_CONDITION_ALE_APP_ID, + 0xd78e1e87, + 0x8644, + 0x4ea5, + 0x94, 0x37, 0xd8, 0x09, 0xec, 0xef, 0xc9, 0x71 +); + +// c35a604d-d22b-4e1a-91b4-68f674ee674b +DEFINE_GUID( + FWPM_CONDITION_IP_REMOTE_PORT, + 0xc35a604d, + 0xd22b, + 0x4e1a, + 0x91, 0xb4, 0x68, 0xf6, 0x74, 0xee, 0x67, 0x4b +); + +// 4cd62a49-59c3-4969-b7f3-bda5d32890a4 +DEFINE_GUID( + FWPM_CONDITION_IP_LOCAL_INTERFACE, + 0x4cd62a49, + 0x59c3, + 0x4969, + 0xb7, 0xf3, 0xbd, 0xa5, 0xd3, 0x28, 0x90, 0xa4 +); + +/* + * Default msg handler does nothing + */ +static inline void +default_msg_handler (DWORD err, const char *msg) +{ + return; +} + +#define CHECK_ERROR(err, msg) \ + if (err) { msg_handler (err, msg); goto out; } + +/* + * Block outgoing port 53 traffic except for + * (i) adapter with the specified index + * OR + * (ii) processes with the specified executable path + * The firewall filters added here are automatically removed when the process exits or + * on calling delete_block_dns_filters(). + * Arguments: + * engine_handle : On successful return contains the handle for a newly opened fwp session + * in which the filters are added. + * May be closed by passing to delete_block_dns_filters to remove the filters. + * index : The index of adapter for which traffic is permitted. + * exe_path : Path of executable for which traffic is permitted. + * msg_handler : An optional callback function for error reporting. + * Returns 0 on success, a non-zero status code of the last failed action on failure. + */ + +DWORD +add_block_dns_filters (HANDLE *engine_handle, + int index, + const WCHAR *exe_path, + block_dns_msg_handler_t msg_handler + ) +{ + FWPM_SESSION0 session = {0}; + FWPM_SUBLAYER0 SubLayer = {0}; + NET_LUID tapluid; + UINT64 filterid; + FWP_BYTE_BLOB *openvpnblob = NULL; + FWPM_FILTER0 Filter = {0}; + FWPM_FILTER_CONDITION0 Condition[2] = {0}; + WCHAR *FIREWALL_NAME = L"OpenVPN"; + DWORD err = 0; + + if (!msg_handler) + msg_handler = default_msg_handler; + + /* Add temporary filters which don't survive reboots or crashes. */ + session.flags = FWPM_SESSION_FLAG_DYNAMIC; + + *engine_handle = NULL; + + err = FwpmEngineOpen0 (NULL, RPC_C_AUTHN_WINNT, NULL, &session, engine_handle); + CHECK_ERROR (err, "FwpEngineOpen: open fwp session failed"); + + err = UuidCreate (&SubLayer.subLayerKey); + CHECK_ERROR (err, "UuidCreate: create sublayer key failed"); + + /* Populate packet filter layer information. */ + SubLayer.displayData.name = FIREWALL_NAME; + SubLayer.displayData.description = FIREWALL_NAME; + SubLayer.flags = 0; + SubLayer.weight = 0x100; + + /* Add sublayer to the session */ + err = FwpmSubLayerAdd0 (*engine_handle, &SubLayer, NULL); + CHECK_ERROR (err, "FwpmSubLayerAdd: add sublayer to session failed"); + + msg_handler (0, "Block_DNS: WFP engine opened"); + + err = ConvertInterfaceIndexToLuid (index, &tapluid); + CHECK_ERROR (err, "Convert interface index to luid failed"); + + err = FwpmGetAppIdFromFileName0 (exe_path, &openvpnblob); + CHECK_ERROR (err, "Get byte blob for openvpn executable name failed"); + + /* Prepare filter. */ + Filter.subLayerKey = SubLayer.subLayerKey; + Filter.displayData.name = FIREWALL_NAME; + Filter.weight.type = FWP_UINT8; + Filter.weight.uint8 = 0xF; + Filter.filterCondition = Condition; + Filter.numFilterConditions = 2; + + /* First filter. Permit IPv4 DNS queries from OpenVPN itself. */ + Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4; + Filter.action.type = FWP_ACTION_PERMIT; + + Condition[0].fieldKey = FWPM_CONDITION_IP_REMOTE_PORT; + Condition[0].matchType = FWP_MATCH_EQUAL; + Condition[0].conditionValue.type = FWP_UINT16; + Condition[0].conditionValue.uint16 = 53; + + Condition[1].fieldKey = FWPM_CONDITION_ALE_APP_ID; + Condition[1].matchType = FWP_MATCH_EQUAL; + Condition[1].conditionValue.type = FWP_BYTE_BLOB_TYPE; + Condition[1].conditionValue.byteBlob = openvpnblob; + + err = FwpmFilterAdd0(*engine_handle, &Filter, NULL, &filterid); + CHECK_ERROR (err, "Add filter to permit IPv4 port 53 traffic from OpenVPN failed"); + + /* Second filter. Permit IPv6 DNS queries from OpenVPN itself. */ + Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V6; + + err = FwpmFilterAdd0(*engine_handle, &Filter, NULL, &filterid); + CHECK_ERROR (err, "Add filter to permit IPv6 port 53 traffic from OpenVPN failed"); + + msg_handler (0, "Block_DNS: Added permit filters for exe_path"); + + /* Third filter. Block all IPv4 DNS queries. */ + Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4; + Filter.action.type = FWP_ACTION_BLOCK; + Filter.weight.type = FWP_EMPTY; + Filter.numFilterConditions = 1; + + err = FwpmFilterAdd0(*engine_handle, &Filter, NULL, &filterid); + CHECK_ERROR (err, "Add filter to block IPv4 DNS traffic failed"); + + msg_handler (0, "Block_DNS: Added block filters for all"); + + /* Forth filter. Block all IPv6 DNS queries. */ + Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V6; + + err = FwpmFilterAdd0(*engine_handle, &Filter, NULL, &filterid); + CHECK_ERROR (err, "Add filter to block IPv6 DNS traffic failed"); + + /* Fifth filter. Permit IPv4 DNS queries from TAP. */ + Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4; + Filter.action.type = FWP_ACTION_PERMIT; + Filter.numFilterConditions = 2; + + Condition[1].fieldKey = FWPM_CONDITION_IP_LOCAL_INTERFACE; + Condition[1].matchType = FWP_MATCH_EQUAL; + Condition[1].conditionValue.type = FWP_UINT64; + Condition[1].conditionValue.uint64 = &tapluid.Value; + + err = FwpmFilterAdd0(*engine_handle, &Filter, NULL, &filterid); + CHECK_ERROR (err, "Add filter to permit IPv4 DNS traffic through TAP failed"); + + /* Sixth filter. Permit IPv6 DNS queries from TAP. */ + Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V6; + + err = FwpmFilterAdd0(*engine_handle, &Filter, NULL, &filterid); + CHECK_ERROR (err, "Add filter to permit IPv6 DNS traffic through TAP failed"); + + msg_handler (0, "Block_DNS: Added permit filters for TAP interface"); + +out: + + if (openvpnblob) + FwpmFreeMemory0 ((void **)&openvpnblob); + + if (err && *engine_handle) + { + FwpmEngineClose0 (*engine_handle); + *engine_handle = NULL; + } + + return err; +} + +DWORD +delete_block_dns_filters (HANDLE engine_handle) +{ + DWORD err = 0; + /* + * For dynamic sessions closing the engine removes all filters added in the session + */ + if (engine_handle) + { + err = FwpmEngineClose0(engine_handle); + } + return err; +} + +#endif diff --git a/src/openvpn/block_dns.h b/src/openvpn/block_dns.h new file mode 100644 index 00000000000..e94535160f3 --- /dev/null +++ b/src/openvpn/block_dns.h @@ -0,0 +1,40 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single TCP/UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2016 Selva Nair + * + * 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 + */ + +#ifdef WIN32 + +#ifndef OPENVPN_BLOCK_DNS_H +#define OPENVPN_BLOCK_DNS_H + +typedef void (*block_dns_msg_handler_t) (DWORD err, const char *msg); + +DWORD +delete_block_dns_filters (HANDLE engine); + +DWORD +add_block_dns_filters (HANDLE *engine, int iface_index, const WCHAR *exe_path, + block_dns_msg_handler_t msg_handler_callback); + +#endif +#endif diff --git a/src/openvpn/win32.c b/src/openvpn/win32.c index 72243a81b48..9efc0bcfa97 100644 --- a/src/openvpn/win32.c +++ b/src/openvpn/win32.c @@ -43,6 +43,7 @@ #include "sig.h" #include "win32.h" #include "misc.h" +#include "openvpn-msg.h" #include "memdbg.h" @@ -52,70 +53,10 @@ #include "compat-versionhelpers.h" #endif -/* - * WFP-related defines and GUIDs. - */ -#include -#include -#include -#include - -#ifndef FWPM_SESSION_FLAG_DYNAMIC -#define FWPM_SESSION_FLAG_DYNAMIC 0x00000001 -#endif - -// c38d57d1-05a7-4c33-904f-7fbceee60e82 -DEFINE_GUID( - FWPM_LAYER_ALE_AUTH_CONNECT_V4, - 0xc38d57d1, - 0x05a7, - 0x4c33, - 0x90, 0x4f, 0x7f, 0xbc, 0xee, 0xe6, 0x0e, 0x82 -); - -// 4a72393b-319f-44bc-84c3-ba54dcb3b6b4 -DEFINE_GUID( - FWPM_LAYER_ALE_AUTH_CONNECT_V6, - 0x4a72393b, - 0x319f, - 0x44bc, - 0x84, 0xc3, 0xba, 0x54, 0xdc, 0xb3, 0xb6, 0xb4 -); - -// d78e1e87-8644-4ea5-9437-d809ecefc971 -DEFINE_GUID( - FWPM_CONDITION_ALE_APP_ID, - 0xd78e1e87, - 0x8644, - 0x4ea5, - 0x94, 0x37, 0xd8, 0x09, 0xec, 0xef, 0xc9, 0x71 -); - -// c35a604d-d22b-4e1a-91b4-68f674ee674b -DEFINE_GUID( - FWPM_CONDITION_IP_REMOTE_PORT, - 0xc35a604d, - 0xd22b, - 0x4e1a, - 0x91, 0xb4, 0x68, 0xf6, 0x74, 0xee, 0x67, 0x4b -); - -// 4cd62a49-59c3-4969-b7f3-bda5d32890a4 -DEFINE_GUID( - FWPM_CONDITION_IP_LOCAL_INTERFACE, - 0x4cd62a49, - 0x59c3, - 0x4969, - 0xb7, 0xf3, 0xbd, 0xa5, 0xd3, 0x28, 0x90, 0xa4 -); - -/* - * WFP firewall name. - */ -WCHAR * FIREWALL_NAME = L"OpenVPN"; /* GLOBAL */ +#include "block_dns.h" /* - * WFP handle and GUID. + * WFP handle */ static HANDLE m_hEngineHandle = NULL; /* GLOBAL */ @@ -1151,165 +1092,54 @@ win_get_tempdir() return tmpdir; } -bool -win_wfp_add_filter (HANDLE engineHandle, - const FWPM_FILTER0 *filter, - PSECURITY_DESCRIPTOR sd, - UINT64 *id) +static void +block_dns_msg_handler (DWORD err, const char *msg) { - if (FwpmFilterAdd0(engineHandle, filter, sd, id) != ERROR_SUCCESS) + struct gc_arena gc = gc_new (); + + if (err == 0) { - msg (M_NONFATAL, "Can't add WFP filter"); - return false; + msg (M_INFO, "%s", msg); } - return true; + else + { + msg (M_WARN, "Error in add_block_dns_filters(): %s : %s [status=%lu]", + msg, strerror_win32 (err, &gc), err); + } + + gc_free (&gc); } bool win_wfp_block_dns (const NET_IFINDEX index) { - FWPM_SESSION0 session = {0}; - FWPM_SUBLAYER0 SubLayer = {0}; - NET_LUID tapluid; - UINT64 filterid; - WCHAR openvpnpath[MAX_PATH]; - FWP_BYTE_BLOB *openvpnblob = NULL; - FWPM_FILTER0 Filter = {0}; - FWPM_FILTER_CONDITION0 Condition[2] = {0}; - - /* Add temporary filters which don't survive reboots or crashes. */ - session.flags = FWPM_SESSION_FLAG_DYNAMIC; - - dmsg (D_LOW, "Opening WFP engine"); + WCHAR openvpnpath[MAX_PATH]; + bool ret = false; + DWORD status; - if (FwpmEngineOpen0(NULL, RPC_C_AUTHN_WINNT, NULL, &session, &m_hEngineHandle) != ERROR_SUCCESS) + status = GetModuleFileNameW (NULL, openvpnpath, sizeof(openvpnpath)); + if (status == 0 || status == sizeof(openvpnpath)) { - msg (M_NONFATAL, "Can't open WFP engine"); - return false; + msg (M_WARN|M_ERRNO, "block_dns: cannot get executable path"); + goto out; } - if (UuidCreate(&SubLayer.subLayerKey) != NO_ERROR) - return false; - - /* Populate packet filter layer information. */ - SubLayer.displayData.name = FIREWALL_NAME; - SubLayer.displayData.description = FIREWALL_NAME; - SubLayer.flags = 0; - SubLayer.weight = 0x100; - - /* Add packet filter to our interface. */ - dmsg (D_LOW, "Adding WFP sublayer"); - if (FwpmSubLayerAdd0(m_hEngineHandle, &SubLayer, NULL) != ERROR_SUCCESS) - { - msg (M_NONFATAL, "Can't add WFP sublayer"); - return false; - } + status = add_block_dns_filters (&m_hEngineHandle, index, openvpnpath, + block_dns_msg_handler); + ret = (status == 0); - dmsg (D_LOW, "Blocking DNS using WFP"); - if (ConvertInterfaceIndexToLuid(index, &tapluid) != NO_ERROR) - { - msg (M_NONFATAL, "Can't convert interface index to LUID"); - return false; - } - dmsg (D_LOW, "Tap Luid: %I64d", tapluid.Value); - - /* Get OpenVPN path. */ - GetModuleFileNameW(NULL, openvpnpath, MAX_PATH); - - if (FwpmGetAppIdFromFileName0(openvpnpath, &openvpnblob) != ERROR_SUCCESS) - return false; - - /* Prepare filter. */ - Filter.subLayerKey = SubLayer.subLayerKey; - Filter.displayData.name = FIREWALL_NAME; - Filter.weight.type = FWP_UINT8; - Filter.weight.uint8 = 0xF; - Filter.filterCondition = Condition; - Filter.numFilterConditions = 2; - - /* First filter. Permit IPv4 DNS queries from OpenVPN itself. */ - Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4; - Filter.action.type = FWP_ACTION_PERMIT; - - Condition[0].fieldKey = FWPM_CONDITION_IP_REMOTE_PORT; - Condition[0].matchType = FWP_MATCH_EQUAL; - Condition[0].conditionValue.type = FWP_UINT16; - Condition[0].conditionValue.uint16 = 53; - - Condition[1].fieldKey = FWPM_CONDITION_ALE_APP_ID; - Condition[1].matchType = FWP_MATCH_EQUAL; - Condition[1].conditionValue.type = FWP_BYTE_BLOB_TYPE; - Condition[1].conditionValue.byteBlob = openvpnblob; - - /* Add filter condition to our interface. */ - if (!win_wfp_add_filter(m_hEngineHandle, &Filter, NULL, &filterid)) - goto err; - dmsg (D_LOW, "Filter (Permit OpenVPN IPv4 DNS) added with ID=%I64d", filterid); - - /* Second filter. Permit IPv6 DNS queries from OpenVPN itself. */ - Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V6; - - /* Add filter condition to our interface. */ - if (!win_wfp_add_filter(m_hEngineHandle, &Filter, NULL, &filterid)) - goto err; - dmsg (D_LOW, "Filter (Permit OpenVPN IPv6 DNS) added with ID=%I64d", filterid); - - /* Third filter. Block all IPv4 DNS queries. */ - Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4; - Filter.action.type = FWP_ACTION_BLOCK; - Filter.weight.type = FWP_EMPTY; - Filter.numFilterConditions = 1; - - if (!win_wfp_add_filter(m_hEngineHandle, &Filter, NULL, &filterid)) - goto err; - dmsg (D_LOW, "Filter (Block IPv4 DNS) added with ID=%I64d", filterid); - - /* Forth filter. Block all IPv6 DNS queries. */ - Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V6; - - if (!win_wfp_add_filter(m_hEngineHandle, &Filter, NULL, &filterid)) - goto err; - dmsg (D_LOW, "Filter (Block IPv6 DNS) added with ID=%I64d", filterid); - - /* Fifth filter. Permit IPv4 DNS queries from TAP. */ - Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4; - Filter.action.type = FWP_ACTION_PERMIT; - Filter.numFilterConditions = 2; - - Condition[1].fieldKey = FWPM_CONDITION_IP_LOCAL_INTERFACE; - Condition[1].matchType = FWP_MATCH_EQUAL; - Condition[1].conditionValue.type = FWP_UINT64; - Condition[1].conditionValue.uint64 = &tapluid.Value; - - /* Add filter condition to our interface. */ - if (!win_wfp_add_filter(m_hEngineHandle, &Filter, NULL, &filterid)) - goto err; - dmsg (D_LOW, "Filter (Permit IPv4 DNS queries from TAP) added with ID=%I64d", filterid); - - /* Sixth filter. Permit IPv6 DNS queries from TAP. */ - Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V6; - - /* Add filter condition to our interface. */ - if (!win_wfp_add_filter(m_hEngineHandle, &Filter, NULL, &filterid)) - goto err; - dmsg (D_LOW, "Filter (Permit IPv6 DNS queries from TAP) added with ID=%I64d", filterid); - - FwpmFreeMemory0((void **)&openvpnblob); - return true; +out: - err: - FwpmFreeMemory0((void **)&openvpnblob); - return false; + return ret; } bool win_wfp_uninit() { dmsg (D_LOW, "Uninitializing WFP"); - if (m_hEngineHandle) { - FwpmEngineClose0(m_hEngineHandle); - m_hEngineHandle = NULL; - } + + delete_block_dns_filters (m_hEngineHandle); + return true; } From 2282b1be7968ef44accde705ccc64addab6d77ba Mon Sep 17 00:00:00 2001 From: Selva Nair Date: Thu, 25 Feb 2016 22:24:51 -0500 Subject: [PATCH 214/643] Add support for block-outside-dns through the interactive service - Add a new message type in openvpn-msg.h - Pass msg_channel HANDLE to win_wfp_block_dns and win_wfp_uninit - Add a handler in interactive.c for block_dns request The service build now depends on block_dns.[ch] in src/openvpn v2 changes: - Make CmpEngine non-nested (be nice with non-gcc compilers) - Print error code in hex Signed-off-by: Selva Nair Acked-by: Gert Doering Message-Id: <1456457091-3872-2-git-send-email-selva.nair@gmail.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/11265 Signed-off-by: Gert Doering --- include/openvpn-msg.h | 9 +++- src/openvpn/init.c | 4 +- src/openvpn/win32.c | 62 ++++++++++++++++++++++-- src/openvpn/win32.h | 4 +- src/openvpnserv/Makefile.am | 7 +-- src/openvpnserv/interactive.c | 88 ++++++++++++++++++++++++++++++++++- 6 files changed, 161 insertions(+), 13 deletions(-) diff --git a/include/openvpn-msg.h b/include/openvpn-msg.h index 0dcc72fa915..7470512a7e8 100644 --- a/include/openvpn-msg.h +++ b/include/openvpn-msg.h @@ -35,7 +35,9 @@ typedef enum { msg_del_dns_cfg, msg_add_nbt_cfg, msg_del_nbt_cfg, - msg_flush_neighbors + msg_flush_neighbors, + msg_add_block_dns, + msg_del_block_dns } message_type_t; typedef struct { @@ -105,4 +107,9 @@ typedef struct { int error_number; } ack_message_t; +typedef struct { + message_header_t header; + interface_t iface; +} block_dns_message_t; + #endif diff --git a/src/openvpn/init.c b/src/openvpn/init.c index cb73a3df2be..7f54c3ca783 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -1508,7 +1508,7 @@ do_open_tun (struct context *c) if (c->options.block_outside_dns) { dmsg (D_LOW, "Blocking outside DNS"); - if (!win_wfp_block_dns(c->c1.tuntap->adapter_index)) + if (!win_wfp_block_dns(c->c1.tuntap->adapter_index, c->options.msg_channel)) msg (M_FATAL, "Blocking DNS failed!"); } #endif @@ -1656,7 +1656,7 @@ do_close_tun (struct context *c, bool force) #if defined(WIN32) if (c->options.block_outside_dns) { - if (!win_wfp_uninit()) + if (!win_wfp_uninit(c->options.msg_channel)) msg (M_FATAL, "Uninitialising WFP failed!"); } #endif diff --git a/src/openvpn/win32.c b/src/openvpn/win32.c index 9efc0bcfa97..f4d3237f093 100644 --- a/src/openvpn/win32.c +++ b/src/openvpn/win32.c @@ -1092,6 +1092,45 @@ win_get_tempdir() return tmpdir; } +static bool +win_block_dns_service (bool add, int index, const HANDLE pipe) +{ + DWORD len; + bool ret = false; + ack_message_t ack; + struct gc_arena gc = gc_new (); + + block_dns_message_t data = { + .header = { + (add ? msg_add_block_dns : msg_del_block_dns), + sizeof (block_dns_message_t), + 0 }, + .iface = { .index = index, .name = "" } + }; + + if (!WriteFile (pipe, &data, sizeof (data), &len, NULL) || + !ReadFile (pipe, &ack, sizeof (ack), &len, NULL)) + { + msg (M_WARN, "Block_DNS: could not talk to service: %s [%lu]", + strerror_win32 (GetLastError (), &gc), GetLastError ()); + goto out; + } + + if (ack.error_number != NO_ERROR) + { + msg (M_WARN, "Block_DNS: %s block dns filters using service failed: %s [status=0x%x if_index=%d]", + (add ? "adding" : "deleting"), strerror_win32 (ack.error_number, &gc), + ack.error_number, data.iface.index); + goto out; + } + + ret = true; + msg (M_INFO, "%s outside dns using service succeeded.", (add ? "Blocking" : "Unblocking")); +out: + gc_free (&gc); + return ret; +} + static void block_dns_msg_handler (DWORD err, const char *msg) { @@ -1103,7 +1142,7 @@ block_dns_msg_handler (DWORD err, const char *msg) } else { - msg (M_WARN, "Error in add_block_dns_filters(): %s : %s [status=%lu]", + msg (M_WARN, "Error in add_block_dns_filters(): %s : %s [status=0x%lx]", msg, strerror_win32 (err, &gc), err); } @@ -1111,12 +1150,19 @@ block_dns_msg_handler (DWORD err, const char *msg) } bool -win_wfp_block_dns (const NET_IFINDEX index) +win_wfp_block_dns (const NET_IFINDEX index, const HANDLE msg_channel) { WCHAR openvpnpath[MAX_PATH]; bool ret = false; DWORD status; + if (msg_channel) + { + dmsg (D_LOW, "Using service to add block dns filters"); + ret = win_block_dns_service (true, index, msg_channel); + goto out; + } + status = GetModuleFileNameW (NULL, openvpnpath, sizeof(openvpnpath)); if (status == 0 || status == sizeof(openvpnpath)) { @@ -1134,11 +1180,19 @@ win_wfp_block_dns (const NET_IFINDEX index) } bool -win_wfp_uninit() +win_wfp_uninit(const HANDLE msg_channel) { dmsg (D_LOW, "Uninitializing WFP"); - delete_block_dns_filters (m_hEngineHandle); + if (msg_channel) + { + msg (D_LOW, "Using service to delete block dns filters"); + win_block_dns_service (false, -1, msg_channel); + } + else + { + delete_block_dns_filters (m_hEngineHandle); + } return true; } diff --git a/src/openvpn/win32.h b/src/openvpn/win32.h index 1e982071d6b..619878f6572 100644 --- a/src/openvpn/win32.h +++ b/src/openvpn/win32.h @@ -271,8 +271,8 @@ const char *win_get_tempdir(); /* Convert a string from UTF-8 to UCS-2 */ WCHAR *wide_string (const char* utf8, struct gc_arena *gc); -bool win_wfp_block_dns(const NET_IFINDEX index); -bool win_wfp_uninit(); +bool win_wfp_block_dns(const NET_IFINDEX index, const HANDLE msg_channel); +bool win_wfp_uninit(const HANDLE msg_channel); #define WIN_XP 0 #define WIN_VISTA 1 diff --git a/src/openvpnserv/Makefile.am b/src/openvpnserv/Makefile.am index 5aba53a4a50..3c757d644f0 100644 --- a/src/openvpnserv/Makefile.am +++ b/src/openvpnserv/Makefile.am @@ -18,7 +18,7 @@ EXTRA_DIST = \ openvpnserv.vcxproj.filters AM_CPPFLAGS = \ - -I$(top_srcdir)/include + -I$(top_srcdir)/include -I$(top_srcdir)/src/openvpn if WIN32 sbin_PROGRAMS = openvpnserv @@ -26,7 +26,7 @@ openvpnserv_CFLAGS = \ -municode -D_UNICODE \ -UNTDDI_VERSION -U_WIN32_WINNT \ -D_WIN32_WINNT=_WIN32_WINNT_VISTA -openvpnserv_LDADD = -ladvapi32 -luserenv -liphlpapi -lshlwapi -lnetapi32 -lws2_32 +openvpnserv_LDADD = -ladvapi32 -luserenv -liphlpapi -lfwpuclnt -lrpcrt4 -lshlwapi -lnetapi32 -lws2_32 endif openvpnserv_SOURCES = \ @@ -34,5 +34,6 @@ openvpnserv_SOURCES = \ automatic.c \ interactive.c \ service.c service.h \ - validate.c validate.h \ + validate.c validate.h \ + $(top_srcdir)/src/openvpn/block_dns.c $(top_srcdir)/src/openvpn/block_dns.h \ openvpnserv_resources.rc diff --git a/src/openvpnserv/interactive.c b/src/openvpnserv/interactive.c index 6a7227b7ea4..d83ea656050 100644 --- a/src/openvpnserv/interactive.c +++ b/src/openvpnserv/interactive.c @@ -37,6 +37,7 @@ #include "openvpn-msg.h" #include "validate.h" +#include "block_dns.h" #define IO_TIMEOUT 2000 /*ms*/ @@ -77,6 +78,7 @@ typedef struct _list_item { typedef enum { address, route, + block_dns, _undo_type_max } undo_type_t; typedef list_item_t* undo_lists_t[_undo_type_max]; @@ -601,7 +603,6 @@ HandleAddressMessage (address_message_t *msg, undo_lists_t *lists) return err; } - static BOOL CmpRoute (LPVOID item, LPVOID route) { @@ -729,6 +730,78 @@ HandleFlushNeighborsMessage (flush_neighbors_message_t *msg) return flush_fn (msg->family, msg->iface.index); } +static void +BlockDNSErrHandler (DWORD err, const char *msg) +{ + TCHAR buf[256]; + LPCTSTR err_str; + + if (!err) return; + + err_str = TEXT("Unknown Win32 Error"); + + if (FormatMessage (FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_ARGUMENT_ARRAY, + NULL, err, 0, buf, sizeof (buf), NULL)) + { + err_str = buf; + } + +#ifdef UNICODE + MsgToEventLog (M_ERR, L"%S (status = %lu): %s", msg, err, err_str); +#else + MsgToEventLog (M_ERR, "%s (status = %lu): %s", msg, err, err_str); +#endif + +} + +/* Use an always-true match_fn to get the head of the list */ +static BOOL +CmpEngine (LPVOID item, LPVOID any) +{ + return TRUE; +} + +static DWORD +HandleBlockDNSMessage (const block_dns_message_t *msg, undo_lists_t *lists) +{ + DWORD err = 0; + HANDLE engine = NULL; + LPCWSTR exe_path; + +#ifdef UNICODE + exe_path = settings.exe_path; +#else + WCHAR wide_path[MAX_PATH]; + MultiByteToWideChar (CP_UTF8, 0, settings.exe_path, MAX_PATH, wide_path, MAX_PATH); + exe_path = wide_path; +#endif + + if (msg->header.type == msg_add_block_dns) + { + err = add_block_dns_filters (&engine, msg->iface.index, exe_path, BlockDNSErrHandler); + if (!err) + err = AddListItem (&(*lists)[block_dns], engine); + } + else + { + engine = RemoveListItem (&(*lists)[block_dns], CmpEngine, NULL); + if (engine) + { + err = delete_block_dns_filters (engine); + engine = NULL; + } + else + MsgToEventLog (M_ERR, TEXT("No previous block DNS filters to delete")); + } + + if (err && engine) + { + delete_block_dns_filters (engine); + } + + return err; +} static VOID HandleMessage (HANDLE pipe, DWORD bytes, DWORD count, LPHANDLE events, undo_lists_t *lists) @@ -739,6 +812,7 @@ HandleMessage (HANDLE pipe, DWORD bytes, DWORD count, LPHANDLE events, undo_list address_message_t address; route_message_t route; flush_neighbors_message_t flush_neighbors; + block_dns_message_t block_dns; } msg; ack_message_t ack = { .header = { @@ -774,8 +848,15 @@ HandleMessage (HANDLE pipe, DWORD bytes, DWORD count, LPHANDLE events, undo_list ack.error_number = HandleFlushNeighborsMessage (&msg.flush_neighbors); break; + case msg_add_block_dns: + case msg_del_block_dns: + if (msg.header.size == sizeof (msg.block_dns)) + ack.error_number = HandleBlockDNSMessage (&msg.block_dns, lists); + break; + default: ack.error_number = ERROR_MESSAGE_TYPE; + MsgToEventLog (MSG_FLAGS_ERROR, TEXT("Unknown message type %d"), msg.header.type); break; } @@ -803,6 +884,11 @@ Undo (undo_lists_t *lists) case route: DeleteRoute (item->data); break; + + case block_dns: + delete_block_dns_filters (item->data); + item->data = NULL; + break; } /* Remove from the list and free memory */ From b064b8111c718f3c4f996f256674ccd3ab62217f Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Fri, 1 Apr 2016 18:43:00 +0200 Subject: [PATCH 215/643] Fix potential null-pointer dereference Commit a070f75b (master branch only) changed the openvpn_encrypt logic and now prepends the contents of the work buffer to buf if no encryption is used (which is the case for tls-auth packets). In that case, the code would potentially dereference a null-pointer in a memcpy(some-dest, 0, 0) call. Fortunately, memcpy() inplementations usually do not actually derefence the src (or dst) pointer for zero-length copies. And since I'm touching this code now anyway, remove a slightly confusing jump back to a cleanup label in openvpn_encrypt_aead(). Issue spotted by Daniel Hirche. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1459528980-8304-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/11372 Signed-off-by: Gert Doering --- src/openvpn/crypto.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c index f15ac351101..5c392aad342 100644 --- a/src/openvpn/crypto.c +++ b/src/openvpn/crypto.c @@ -166,14 +166,14 @@ openvpn_encrypt_aead (struct buffer *buf, struct buffer work, dmsg (D_PACKET_CONTENT, "ENCRYPT TO: %s", format_hex (BPTR (buf), BLEN (buf), 80, &gc)); -cleanup: gc_free (&gc); return; err: crypto_clear_error(); buf->len = 0; - goto cleanup; + gc_free (&gc); + return; #else /* HAVE_AEAD_CIPHER_MODES */ ASSERT (0); #endif @@ -295,7 +295,9 @@ openvpn_encrypt_v1 (struct buffer *buf, struct buffer work, hmac_start = BPTR(buf); ASSERT (mac_out = buf_prepend (buf, hmac_ctx_size(ctx->hmac))); } - buf_write_prepend(buf, BPTR(&work), BLEN(&work)); + if (BLEN(&work)) { + buf_write_prepend(buf, BPTR(&work), BLEN(&work)); + } work = *buf; } From be16d5f6b050248f503455e4a0e8f3aaaa38bdc7 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sun, 27 Mar 2016 17:22:10 +0200 Subject: [PATCH 216/643] Fix memory leak in argv_extract_cmd_name() Reported by coverity (in 2009!): 1648 static char * 1649 argv_extract_cmd_name (const char *path) 1650 { 1. Condition path, taking true branch 1651 if (path) 1652 { 1653 char *path_cp = string_alloc(path, NULL); /* POSIX basename() implementaions may modify its arguments */ 1654 const char *bn = basename (path_cp); 2. Condition bn, taking true branch 1655 if (bn) 1656 { 3. alloc_fn: Storage is returned from allocation function string_alloc. [show details] 4. var_assign: Assigning: ret = storage returned from string_alloc(bn, NULL). 1657 char *ret = string_alloc (bn, NULL); 5. noescape: Resource ret is not freed or pointed-to in strrchr. 1658 char *dot = strrchr (ret, '.'); 6. Condition dot, taking false branch 1659 if (dot) 1660 *dot = '\0'; 1661 free(path_cp); 7. Condition ret[0] != 0, taking false branch 1662 if (ret[0] != '\0') 1663 return ret; CID 27023 (#2-1 of 2): Resource leak (RESOURCE_LEAK)8. leaked_storage: Variable ret going out of scope leaks the storage it points to. 1664 } 1665 } 1666 return NULL; 1667 } This function is only used by argv_printf_arglist(), and in a very specific case, so it might be that this leak can not even occur. But coverity is clearly right that this is a bug, so let's just fix it. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1459092130-19905-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/11369 Signed-off-by: Gert Doering --- src/openvpn/misc.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/openvpn/misc.c b/src/openvpn/misc.c index 05ed0738d1f..f76c2e579a0 100644 --- a/src/openvpn/misc.c +++ b/src/openvpn/misc.c @@ -1648,22 +1648,27 @@ argv_system_str_append (struct argv *a, const char *str, const bool enquote) static char * argv_extract_cmd_name (const char *path) { + char *ret = NULL; if (path) { char *path_cp = string_alloc(path, NULL); /* POSIX basename() implementaions may modify its arguments */ const char *bn = basename (path_cp); if (bn) { - char *ret = string_alloc (bn, NULL); - char *dot = strrchr (ret, '.'); + char *dot = NULL; + ret = string_alloc (bn, NULL); + dot = strrchr (ret, '.'); if (dot) *dot = '\0'; free(path_cp); - if (ret[0] != '\0') - return ret; + if (ret[0] == '\0') + { + free(ret); + ret = NULL; + } } } - return NULL; + return ret; } const char * From bbde0a766c69f573746461415c6f5cd289272fff Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sun, 27 Mar 2016 16:18:16 +0200 Subject: [PATCH 217/643] Replace MSG_TEST() macro for static inline msg_test() Using a static inline function instead of a macro has the advantages that (1) 'flags' is not evaluated twice and (2) coverity will stop complaining that 'Macro compares unsigned to 0 (NO_EFFECT)' each time we use flags with loglevel 0 (e.g. M_FATAL or M_WARN). This has a performance impact when compiler optimizations are fully disabled ('-O0'), but should otherwise be as fast as using a macro. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1459088296-5046-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/11368 Signed-off-by: Gert Doering --- src/openvpn/error.c | 2 +- src/openvpn/error.h | 17 +++++++++++------ src/openvpn/plugin.c | 2 +- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/openvpn/error.c b/src/openvpn/error.c index cfd5a418e62..bb0ab5b9203 100644 --- a/src/openvpn/error.c +++ b/src/openvpn/error.c @@ -228,7 +228,7 @@ void x_msg_va (const unsigned int flags, const char *format, va_list arglist) #ifndef HAVE_VARARG_MACROS /* the macro has checked this otherwise */ - if (!MSG_TEST (flags)) + if (!msg_test (flags)) return; #endif diff --git a/src/openvpn/error.h b/src/openvpn/error.h index dd5ccf70177..76515d6e07a 100644 --- a/src/openvpn/error.h +++ b/src/openvpn/error.h @@ -135,26 +135,31 @@ extern int x_msg_line_num; * msg() as a macro for optimization win. */ -bool dont_mute (unsigned int flags); /* check muting filter */ +/** Check muting filter */ +bool dont_mute (unsigned int flags); -#define MSG_TEST(flags) (unlikely((((unsigned int)flags) & M_DEBUG_LEVEL) <= x_debug_level) && dont_mute (flags)) +/** Return true if flags represent an enabled, not muted log level */ +static inline bool msg_test (unsigned int flags) +{ + return ((flags & M_DEBUG_LEVEL) <= x_debug_level) && dont_mute (flags); +} /* Macro to ensure (and teach static analysis tools) we exit on fatal errors */ #define EXIT_FATAL(flags) do { if ((flags) & M_FATAL) _exit(1); } while (false) #if defined(HAVE_CPP_VARARG_MACRO_ISO) && !defined(__LCLINT__) # define HAVE_VARARG_MACROS -# define msg(flags, ...) do { if (MSG_TEST(flags)) x_msg((flags), __VA_ARGS__); EXIT_FATAL(flags); } while (false) +# define msg(flags, ...) do { if (msg_test(flags)) x_msg((flags), __VA_ARGS__); EXIT_FATAL(flags); } while (false) # ifdef ENABLE_DEBUG -# define dmsg(flags, ...) do { if (MSG_TEST(flags)) x_msg((flags), __VA_ARGS__); EXIT_FATAL(flags); } while (false) +# define dmsg(flags, ...) do { if (msg_test(flags)) x_msg((flags), __VA_ARGS__); EXIT_FATAL(flags); } while (false) # else # define dmsg(flags, ...) # endif #elif defined(HAVE_CPP_VARARG_MACRO_GCC) && !defined(__LCLINT__) # define HAVE_VARARG_MACROS -# define msg(flags, args...) do { if (MSG_TEST(flags)) x_msg((flags), args); EXIT_FATAL(flags); } while (false) +# define msg(flags, args...) do { if (msg_test(flags)) x_msg((flags), args); EXIT_FATAL(flags); } while (false) # ifdef ENABLE_DEBUG -# define dmsg(flags, args...) do { if (MSG_TEST(flags)) x_msg((flags), args); EXIT_FATAL(flags); } while (false) +# define dmsg(flags, args...) do { if (msg_test(flags)) x_msg((flags), args); EXIT_FATAL(flags); } while (false) # else # define dmsg(flags, args...) # endif diff --git a/src/openvpn/plugin.c b/src/openvpn/plugin.c index 9be0b0c5ed7..542e5b1f2b6 100644 --- a/src/openvpn/plugin.c +++ b/src/openvpn/plugin.c @@ -319,7 +319,7 @@ plugin_vlog (openvpn_plugin_log_flags_t flags, const char *name, const char *for if (flags & PLOG_NOMUTE) msg_flags |= M_NOMUTE; - if (MSG_TEST (msg_flags)) + if (msg_test (msg_flags)) { struct gc_arena gc; char* msg_fmt; From 0a6a80156ee60705f7856100da7a2a61f018e2a0 Mon Sep 17 00:00:00 2001 From: James Yonan Date: Thu, 3 Mar 2016 01:19:00 -0700 Subject: [PATCH 218/643] Added flags parameter to format_hex_ex. We add the flags parameter without changing the signature of the function by repurposing the space_break parameter into space_break_flags where the lower 8 bits are used for the previous space_break parameter and the higher bits are used for flag values. Added new flag FHE_CAPS that formats the generated hex string in upper case. Signed-off-by: James Yonan Acked-by: Steffan Karger Message-Id: <1456993146-63968-4-git-send-email-james@openvpn.net> URL: http://article.gmane.org/gmane.network.openvpn.devel/11275 Signed-off-by: Gert Doering --- src/openvpn/buffer.c | 11 +++++++---- src/openvpn/buffer.h | 4 +++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/openvpn/buffer.c b/src/openvpn/buffer.c index bc67d6503ab..52c6ab92f8d 100644 --- a/src/openvpn/buffer.c +++ b/src/openvpn/buffer.c @@ -435,18 +435,21 @@ gc_transfer (struct gc_arena *dest, struct gc_arena *src) char * format_hex_ex (const uint8_t *data, int size, int maxoutput, - int space_break, const char* separator, + unsigned int space_break_flags, const char* separator, struct gc_arena *gc) { struct buffer out = alloc_buf_gc (maxoutput ? maxoutput : - ((size * 2) + (size / space_break) * (int) strlen (separator) + 2), + ((size * 2) + (size / (space_break_flags & FHE_SPACE_BREAK_MASK)) * (int) strlen (separator) + 2), gc); int i; for (i = 0; i < size; ++i) { - if (separator && i && !(i % space_break)) + if (separator && i && !(i % (space_break_flags & FHE_SPACE_BREAK_MASK))) buf_printf (&out, "%s", separator); - buf_printf (&out, "%02x", data[i]); + if (space_break_flags & FHE_CAPS) + buf_printf (&out, "%02X", data[i]); + else + buf_printf (&out, "%02x", data[i]); } buf_catrunc (&out, "[more...]"); return (char *)out.data; diff --git a/src/openvpn/buffer.h b/src/openvpn/buffer.h index 24f52aa389a..8070439a5d8 100644 --- a/src/openvpn/buffer.h +++ b/src/openvpn/buffer.h @@ -403,9 +403,11 @@ bool buf_parse (struct buffer *buf, const int delim, char *line, const int size) /* * Hex dump -- Output a binary buffer to a hex string and return it. */ +#define FHE_SPACE_BREAK_MASK 0xFF /* space_break parameter in lower 8 bits */ +#define FHE_CAPS 0x100 /* output hex in caps */ char * format_hex_ex (const uint8_t *data, int size, int maxoutput, - int space_break, const char* separator, + unsigned int space_break_flags, const char* separator, struct gc_arena *gc); static inline char * From f6608a15efab027e25553da3026c172dbc3aa73e Mon Sep 17 00:00:00 2001 From: James Yonan Date: Thu, 3 Mar 2016 01:19:01 -0700 Subject: [PATCH 219/643] Extended x509-track for OpenSSL to report SHA1 fingerprint. For example: x509-track "+SHA1" will extract the SHA1 fingerprints for all certs in the peer chain. This patch is ported from OpenVPN 2.1. Signed-off-by: James Yonan Acked-by: Steffan Karger Message-Id: <1456993146-63968-5-git-send-email-james@openvpn.net> URL: http://article.gmane.org/gmane.network.openvpn.devel/11281 Signed-off-by: Gert Doering --- src/openvpn/ssl_verify_openssl.c | 115 ++++++++++++++++++++----------- 1 file changed, 75 insertions(+), 40 deletions(-) diff --git a/src/openvpn/ssl_verify_openssl.c b/src/openvpn/ssl_verify_openssl.c index d014f9d334b..7046f02a218 100644 --- a/src/openvpn/ssl_verify_openssl.c +++ b/src/openvpn/ssl_verify_openssl.c @@ -305,6 +305,27 @@ x509_get_subject (X509 *cert, struct gc_arena *gc) #ifdef ENABLE_X509_TRACK +/* + * x509-track implementation -- save X509 fields to environment, + * using the naming convention: + * + * X509_{cert_depth}_{name}={value} + * + * This function differs from x509_setenv below in the following ways: + * + * (1) Only explicitly named attributes in xt are saved, per usage + * of "x509-track" program options. + * (2) Only the level 0 cert info is saved unless the XT_FULL_CHAIN + * flag is set in xt->flags (corresponds with prepending a '+' + * to the name when specified by "x509-track" program option). + * (3) This function supports both X509 subject name fields as + * well as X509 V3 extensions. + * (4) This function can return the SHA1 fingerprint of a cert, e.g. + * x509-track "+SHA1" + * will return the SHA1 fingerprint for each certificate in the + * peer chain. + */ + void x509_track_add (const struct x509_track **ll_head, const char *name, int msglevel, struct gc_arena *gc) { @@ -346,58 +367,72 @@ do_setenv_x509 (struct env_set *es, const char *name, char *value, int depth) void x509_setenv_track (const struct x509_track *xt, struct env_set *es, const int depth, X509 *x509) { + struct gc_arena gc = gc_new(); X509_NAME *x509_name = X509_get_subject_name (x509); const char nullc = '\0'; - int i; while (xt) { if (depth == 0 || (xt->flags & XT_FULL_CHAIN)) { - i = X509_NAME_get_index_by_NID(x509_name, xt->nid, -1); - if (i >= 0) + switch (xt->nid) { - X509_NAME_ENTRY *ent = X509_NAME_get_entry(x509_name, i); - if (ent) - { - ASN1_STRING *val = X509_NAME_ENTRY_get_data (ent); - unsigned char *buf; - buf = (unsigned char *)1; /* bug in OpenSSL 0.9.6b ASN1_STRING_to_UTF8 requires this workaround */ - if (ASN1_STRING_to_UTF8 (&buf, val) > 0) - { - do_setenv_x509(es, xt->name, (char *)buf, depth); - OPENSSL_free (buf); - } - } - } - else - { - i = X509_get_ext_by_NID(x509, xt->nid, -1); - if (i >= 0) - { - X509_EXTENSION *ext = X509_get_ext(x509, i); - if (ext) - { - BIO *bio = BIO_new(BIO_s_mem()); - if (bio) - { - if (X509V3_EXT_print(bio, ext, 0, 0)) - { - if (BIO_write(bio, &nullc, 1) == 1) - { - char *str; - BIO_get_mem_data(bio, &str); - do_setenv_x509(es, xt->name, str, depth); - } - } - BIO_free(bio); - } - } - } + case NID_sha1: + { + char *sha1_fingerprint = format_hex_ex(x509->sha1_hash, + SHA_DIGEST_LENGTH, 0, 1 | FHE_CAPS, ":", &gc); + do_setenv_x509(es, xt->name, sha1_fingerprint, depth); + } + break; + default: + { + int i = X509_NAME_get_index_by_NID(x509_name, xt->nid, -1); + if (i >= 0) + { + X509_NAME_ENTRY *ent = X509_NAME_get_entry(x509_name, i); + if (ent) + { + ASN1_STRING *val = X509_NAME_ENTRY_get_data (ent); + unsigned char *buf; + buf = (unsigned char *)1; /* bug in OpenSSL 0.9.6b ASN1_STRING_to_UTF8 requires this workaround */ + if (ASN1_STRING_to_UTF8 (&buf, val) > 0) + { + do_setenv_x509(es, xt->name, (char *)buf, depth); + OPENSSL_free (buf); + } + } + } + else + { + i = X509_get_ext_by_NID(x509, xt->nid, -1); + if (i >= 0) + { + X509_EXTENSION *ext = X509_get_ext(x509, i); + if (ext) + { + BIO *bio = BIO_new(BIO_s_mem()); + if (bio) + { + if (X509V3_EXT_print(bio, ext, 0, 0)) + { + if (BIO_write(bio, &nullc, 1) == 1) + { + char *str; + BIO_get_mem_data(bio, &str); + do_setenv_x509(es, xt->name, str, depth); + } + } + BIO_free(bio); + } + } + } + } + } } } xt = xt->next; } + gc_free(&gc); } #endif From 7a7a79f62eb04b0089ae304d558f15c5532c0e61 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Sun, 6 Mar 2016 20:39:09 +0100 Subject: [PATCH 220/643] Implement inlining of crl files While crl files can change regulary and it is usually not a good idea to statically include them into config files, handling multiple files and updating files on mobile devices is tiresome/problematic. Inlining a static version of the crl file is better in these use cases than to use no crl at all. OpenVPN 3 already supports inlining crl-verify, so is already used in config files. V2: Fixed PolarSSL and made formatting respect the 80 column limit V3: Accidentally reverted one change too much in V2 Acked-by: Steffan Karger Message-Id: <1457293149-10526-1-git-send-email-arne@rfc2549.org> URL: http://article.gmane.org/gmane.network.openvpn.devel/11337 Signed-off-by: Gert Doering --- doc/openvpn.8 | 3 ++- src/openvpn/init.c | 1 + src/openvpn/options.c | 11 ++++++++--- src/openvpn/options.h | 1 + src/openvpn/ssl_common.h | 1 + src/openvpn/ssl_verify.c | 2 +- src/openvpn/ssl_verify_backend.h | 5 +++-- src/openvpn/ssl_verify_openssl.c | 8 ++++++-- src/openvpn/ssl_verify_polarssl.c | 20 ++++++++++++++++---- 9 files changed, 39 insertions(+), 13 deletions(-) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 628d8772fba..decffc77685 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -6490,7 +6490,8 @@ X509_1_C=KG .\"********************************************************* .SH INLINE FILE SUPPORT OpenVPN allows including files in the main configuration for the -.B \-\-ca, \-\-cert, \-\-dh, \-\-extra\-certs, \-\-key, \-\-pkcs12, \-\-secret +.B \-\-ca, \-\-cert, \-\-dh, \-\-extra\-certs, \-\-key, \-\-pkcs12, \-\-secret, +.B \-\-crl-verify and .B \-\-tls\-auth options. diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 7f54c3ca783..84fac0783f7 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -2323,6 +2323,7 @@ do_init_crypto_tls (struct context *c, const unsigned int flags) to.verify_x509_type = (options->verify_x509_type & 0xff); to.verify_x509_name = options->verify_x509_name; to.crl_file = options->crl_file; + to.crl_file_inline = options->crl_file_inline; to.ssl_flags = options->ssl_flags; to.ns_cert_type = options->ns_cert_type; memmove (to.remote_cert_ku, options->remote_cert_ku, sizeof (to.remote_cert_ku)); diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 02def3a8271..57f3dc536af 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -2747,8 +2747,8 @@ options_postprocess_filechecks (struct options *options) errs |= check_file_access_chroot (options->chroot_dir, CHKACC_FILE, options->crl_file, R_OK|X_OK, "--crl-verify directory"); else - errs |= check_file_access_chroot (options->chroot_dir, CHKACC_FILE, options->crl_file, R_OK, - "--crl-verify"); + errs |= check_file_access_chroot (options->chroot_dir, CHKACC_FILE|CHKACC_INLINE, + options->crl_file, R_OK, "--crl-verify"); errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE, options->tls_auth_file, R_OK, "--tls-auth"); @@ -6783,12 +6783,17 @@ add_option (struct options *options, VERIFY_PERMISSION (OPT_P_GENERAL); options->cipher_list = p[1]; } - else if (streq (p[0], "crl-verify") && p[1] && ((p[2] && streq(p[2], "dir")) || !p[2]) && !p[3]) + else if (streq (p[0], "crl-verify") && p[1] && ((p[2] && streq(p[2], "dir")) + || (p[2] && streq (p[1], INLINE_FILE_TAG) ) || !p[2]) && !p[3]) { VERIFY_PERMISSION (OPT_P_GENERAL); if (p[2] && streq(p[2], "dir")) options->ssl_flags |= SSLF_CRL_VERIFY_DIR; options->crl_file = p[1]; + if (streq (p[1], INLINE_FILE_TAG) && p[2]) + { + options->crl_file_inline = p[2]; + } } else if (streq (p[0], "tls-verify") && p[1]) { diff --git a/src/openvpn/options.h b/src/openvpn/options.h index 23d3992e0ef..8a26e147799 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -511,6 +511,7 @@ struct options const char *ca_file_inline; const char *cert_file_inline; const char *extra_certs_file_inline; + const char *crl_file_inline; char *priv_key_file_inline; const char *dh_file_inline; const char *pkcs12_file_inline; /* contains the base64 encoding of pkcs12 file */ diff --git a/src/openvpn/ssl_common.h b/src/openvpn/ssl_common.h index eaf4a919fda..334ccb0739c 100644 --- a/src/openvpn/ssl_common.h +++ b/src/openvpn/ssl_common.h @@ -247,6 +247,7 @@ struct tls_options int verify_x509_type; const char *verify_x509_name; const char *crl_file; + const char *crl_file_inline; int ns_cert_type; unsigned remote_cert_ku[MAX_PARMS]; const char *remote_cert_eku; diff --git a/src/openvpn/ssl_verify.c b/src/openvpn/ssl_verify.c index ccfa9d26256..ea381f83462 100644 --- a/src/openvpn/ssl_verify.c +++ b/src/openvpn/ssl_verify.c @@ -690,7 +690,7 @@ verify_cert(struct tls_session *session, openvpn_x509_cert_t *cert, int cert_dep } else { - if (SUCCESS != x509_verify_crl(opt->crl_file, cert, subject)) + if (SUCCESS != x509_verify_crl(opt->crl_file, opt->crl_file_inline, cert, subject)) goto cleanup; } } diff --git a/src/openvpn/ssl_verify_backend.h b/src/openvpn/ssl_verify_backend.h index 4e9ad60f714..17e88fb36fe 100644 --- a/src/openvpn/ssl_verify_backend.h +++ b/src/openvpn/ssl_verify_backend.h @@ -248,13 +248,14 @@ result_t x509_write_pem(FILE *peercert_file, openvpn_x509_cert_t *peercert); * * @param crl_file File name of the CRL file * @param cert Certificate to verify + * @param crl_inline Contents of the crl file if it is inlined * @param subject Subject of the given certificate * * @return \c SUCCESS if the CRL was not signed by the issuer of the * certificate or does not contain an entry for it. * \c FAILURE otherwise. */ -result_t x509_verify_crl(const char *crl_file, openvpn_x509_cert_t *cert, - const char *subject); +result_t x509_verify_crl(const char *crl_file, const char *crl_inline, + openvpn_x509_cert_t *cert, const char *subject); #endif /* SSL_VERIFY_BACKEND_H_ */ diff --git a/src/openvpn/ssl_verify_openssl.c b/src/openvpn/ssl_verify_openssl.c index 7046f02a218..4020fb9e847 100644 --- a/src/openvpn/ssl_verify_openssl.c +++ b/src/openvpn/ssl_verify_openssl.c @@ -613,7 +613,8 @@ x509_write_pem(FILE *peercert_file, X509 *peercert) * check peer cert against CRL */ result_t -x509_verify_crl(const char *crl_file, X509 *peer_cert, const char *subject) +x509_verify_crl(const char *crl_file, const char* crl_inline, + X509 *peer_cert, const char *subject) { X509_CRL *crl=NULL; X509_REVOKED *revoked; @@ -623,7 +624,10 @@ x509_verify_crl(const char *crl_file, X509 *peer_cert, const char *subject) struct gc_arena gc = gc_new(); char *serial; - in = BIO_new_file (crl_file, "r"); + if (!strcmp (crl_file, INLINE_FILE_TAG) && crl_inline) + in = BIO_new_mem_buf ((char *)crl_inline, -1); + else + in = BIO_new_file (crl_file, "r"); if (in == NULL) { msg (M_WARN, "CRL: cannot read: %s", crl_file); diff --git a/src/openvpn/ssl_verify_polarssl.c b/src/openvpn/ssl_verify_polarssl.c index a2e6a8ec017..d1b9f02fb48 100644 --- a/src/openvpn/ssl_verify_polarssl.c +++ b/src/openvpn/ssl_verify_polarssl.c @@ -359,18 +359,30 @@ x509_write_pem(FILE *peercert_file, x509_crt *peercert) * check peer cert against CRL */ result_t -x509_verify_crl(const char *crl_file, x509_crt *cert, const char *subject) +x509_verify_crl(const char *crl_file, const char* crl_inline, + x509_crt *cert, const char *subject) { result_t retval = FAILURE; x509_crl crl = {0}; struct gc_arena gc = gc_new(); char *serial; - if (!polar_ok(x509_crl_parse_file(&crl, crl_file))) + if (!strcmp (crl_file, INLINE_FILE_TAG) && crl_inline) { - msg (M_WARN, "CRL: cannot read CRL from file %s", crl_file); - goto end; + if (!polar_ok(x509_crl_parse(&crl, crl_inline, strlen(crl_inline)))) + { + msg (M_WARN, "CRL: cannot parse inline CRL"); + goto end; + } } + else + { + if (!polar_ok(x509_crl_parse_file(&crl, crl_file))) + { + msg (M_WARN, "CRL: cannot read CRL from file %s", crl_file); + goto end; + } + } if(cert->issuer_raw.len != crl.issuer_raw.len || memcmp(crl.issuer_raw.p, cert->issuer_raw.p, crl.issuer_raw.len) != 0) From d09fbf958f1c0b15372b3e87d784ae666b91a96b Mon Sep 17 00:00:00 2001 From: Selva Nair Date: Wed, 13 Apr 2016 23:53:33 -0400 Subject: [PATCH 221/643] Ensure input read using systemd-ask-password is null terminated Also properly check the return value of read() and leave room for termination. Fixes junk data occasionally seen in strings read through systemd. Signed-off-by: Selva Nair Acked-by: Gert Doering Message-Id: <1460606013-4983-1-git-send-email-selva.nair@gmail.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/11437 Signed-off-by: Gert Doering --- src/openvpn/console.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/openvpn/console.c b/src/openvpn/console.c index e1d46c413e4..86331a11c23 100644 --- a/src/openvpn/console.c +++ b/src/openvpn/console.c @@ -172,8 +172,9 @@ get_console_input_systemd (const char *prompt, const bool echo, char *input, con if ((std_out = openvpn_popen (&argv, NULL)) < 0) { return false; } - CLEAR (*input); - if (read (std_out, input, capacity) != 0) + + memset (input, 0, capacity); + if (read (std_out, input, capacity-1) > 0) { chomp (input); ret = true; From 0f99269711e2aa8a2f88c5991381ea7e52c7485e Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sun, 17 Apr 2016 11:56:20 +0200 Subject: [PATCH 222/643] fixup: change init_key_type() param name in declaration too Commit 66407e11 changed the name of the cfb_ofb_allowed parameter of the init_key_type() implementation to 'tls_mode', but forgot to do the same in the function declaration. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1460886980-12925-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/11445 Signed-off-by: Gert Doering --- src/openvpn/crypto.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openvpn/crypto.h b/src/openvpn/crypto.h index d3e08c1e6da..63d7040d83b 100644 --- a/src/openvpn/crypto.h +++ b/src/openvpn/crypto.h @@ -297,7 +297,7 @@ int read_key (struct key *key, const struct key_type *kt, struct buffer *buf); void init_key_type (struct key_type *kt, const char *ciphername, bool ciphername_defined, const char *authname, bool authname_defined, - int keysize, bool cfb_ofb_allowed, bool warn); + int keysize, bool tls_mode, bool warn); /* * Key context functions From 6be0f0015d7485f0bf3c14a3a381a6f6496270a5 Mon Sep 17 00:00:00 2001 From: Jens Neuhalfen Date: Thu, 14 Apr 2016 19:58:07 +0200 Subject: [PATCH 223/643] Make intent of utun device name validation clear Make intend of the validation clear when validating utun parameter in open_darwin_utun. The program logic remains unchanged. Fixes the following compiler warning on Mac OS X: tun.c:2847:19: warning: logical not is only applied to the left hand side of this comparison [-Wlogical-not-parentheses] if (dev_node && !strcmp ("utun", dev_node)==0) ^ ~~ tun.c:2847:19: note: add parentheses after the '!' to evaluate the comparison first if (dev_node && !strcmp ("utun", dev_node)==0) ^ ( ) tun.c:2847:19: note: add parentheses around left hand side expression to silence this warning if (dev_node && !strcmp ("utun", dev_node)==0) ^ ( ) tun.c:2849:11: warning: logical not is only applied to the left hand side of this comparison [-Wlogical-not-parentheses] if (!sscanf (dev_node, "utun%d", &utunnum)==1) ^ ~~ tun.c:2849:11: note: add parentheses after the '!' to evaluate the comparison first if (!sscanf (dev_node, "utun%d", &utunnum)==1) ^ ( ) tun.c:2849:11: note: add parentheses around left hand side expression to silence this warning if (!sscanf (dev_node, "utun%d", &utunnum)==1) ^ ( ) Signed-off-by: Jens Neuhalfen Acked-by: Arne Schwabe Message-Id: <3365AB24-33FD-4D9D-A57C-BF9240DC3D69@neuhalfen.name> URL: http://article.gmane.org/gmane.network.openvpn.devel/11440 Signed-off-by: Gert Doering --- src/openvpn/tun.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index eaeb6cc059e..c87fb366736 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -2844,9 +2844,9 @@ open_darwin_utun (const char *dev, const char *dev_type, const char *dev_node, s /* dev_node is simply utun, do the normal dynamic utun * otherwise try to parse the utun number */ - if (dev_node && !strcmp ("utun", dev_node)==0) + if (dev_node && (strcmp("utun", dev_node) != 0 )) { - if (!sscanf (dev_node, "utun%d", &utunnum)==1) + if (sscanf(dev_node, "utun%d", &utunnum) != 1 ) msg (M_FATAL, "Cannot parse 'dev-node %s' please use 'dev-node utunX'" "to use a utun device number X", dev_node); } From a44eac2bf47416b35609c37b10eb803dd61945ed Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sun, 17 Apr 2016 20:32:07 +0200 Subject: [PATCH 224/643] Further restrict default cipher list In the past years, the internet has been moving forward wrt deprecating older and less secure ciphers. Let's follow this example in OpenVPN and further restrict the default list of negotiable TLS ciphers. Compared to earlier, this disables the following: * Ciphers in the LOW and MEDIUM security cipher list of OpenSSL The LOW suite will be completely removed from OpenSSL in 1.1.0, the MEDIUM suite contains ciphers like RC4 and SEED. * Ciphers that do not provide forward secrecy (static DH/ECDH keys) * DSA private keys (rarely used, and usually restricted to 1024 bits) v2: added Changes.rst entry. Signed-off-by: Steffan Karger Acked-by: Arne Schwabe Message-Id: <1460917927-31645-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/11457 Signed-off-by: Gert Doering --- Changes.rst | 7 +++++++ doc/openvpn.8 | 4 +++- src/openvpn/ssl_openssl.c | 14 ++++++++++++-- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/Changes.rst b/Changes.rst index af70d1419fe..93e4bd9dabb 100644 --- a/Changes.rst +++ b/Changes.rst @@ -86,6 +86,13 @@ User-visible Changes - Removed --enable-password-save from configure. This option is now always enabled. +- Stricter default TLS cipher list (override with ``--tls-cipher``), that now + also disables: + + * Non-ephemeral key exchange using static (EC)DH keys + * DSS private keys + + Maintainer-visible changes -------------------------- - OpenVPN no longer supports building with crypto support, but without TLS diff --git a/doc/openvpn.8 b/doc/openvpn.8 index decffc77685..6f4f21f994f 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -4696,7 +4696,9 @@ your VPN connection. But it is also easy to unwittingly use it to carefully align a gun with your foot, or just break your connection. Use with care! The default for \-\-tls\-cipher is to use PolarSSL's default cipher list -when using PolarSSL or "DEFAULT:!EXP:!PSK:!SRP:!kRSA" when using OpenSSL. +when using PolarSSL or +"DEFAULT:!EXP:!LOW:!MEDIUM:!kDH:!kECDH:!DSS:!PSK:!SRP:!kRSA" when using +OpenSSL. .\"********************************************************* .TP .B \-\-tls\-timeout n diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c index e390f4d0e4a..ca9b67ba7f1 100644 --- a/src/openvpn/ssl_openssl.c +++ b/src/openvpn/ssl_openssl.c @@ -272,8 +272,18 @@ tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers) { if (ciphers == NULL) { - /* Use sane default (disable export, and unsupported cipher modes) */ - if(!SSL_CTX_set_cipher_list(ctx->ctx, "DEFAULT:!EXP:!PSK:!SRP:!kRSA")) + /* Use sane default TLS cipher list */ + if(!SSL_CTX_set_cipher_list(ctx->ctx, + /* Use openssl's default list as a basis */ + "DEFAULT" + /* Disable export ciphers and openssl's 'low' and 'medium' ciphers */ + ":!EXP:!LOW:!MEDIUM" + /* Disable static (EC)DH keys (no forward secrecy) */ + ":!kDH:!kECDH" + /* Disable DSA private keys */ + ":!DSS" + /* Disable unsupported TLS modes */ + ":!PSK:!SRP:!kRSA")) crypto_msg (M_FATAL, "Failed to set default TLS cipher list."); return; } From 9b0f1df2560441ab5ea80f053acd0161de8b6c7a Mon Sep 17 00:00:00 2001 From: Selva Nair Date: Sun, 20 Dec 2015 14:12:53 -0500 Subject: [PATCH 225/643] Support reading the challenge-response from console Trying to keep the footrpint small, this patch adds to the convoluted code-flow in get_user_pass_cr(). Cleanup left for later. -----8<----- Currently prompting for a response to static-challenge gets skipped when the username and passowrd are read from a file. Further, dynamic challenge gets wrongly handled as if its a username/password request. The Fix: - Add yet another flag in get_user_pass_cr() to set when prompting of response from console is needed. - In receive_auth_failed(), the challenge text received from server _always_ copied to the auth_challenge buffer: this is needed to trigger prompting from console when required. - Also show the challenge text instead of an opaque "Response:" at the prompt. While at it, also remove the special treatment of authfile == "management" in get_user_pass_cr(). The feature implied by that test does not exist. Tested: - username and optionally password from file, rest from console - the above with a static challenge - the above with a dynamic challenge - all of the above with systemd in place of console - all from management with and without static/dynamic challenge. Thanks to Wayne Davison for pointing out the issue with challenge-response, and an initial patch. Signed-off-by: Selva Nair Acked-by: Steffan Karger Message-Id: <1450638773-11376-1-git-send-email-selva.nair@gmail.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/10868 Signed-off-by: Gert Doering --- src/openvpn/misc.c | 22 +++++++++++++++------- src/openvpn/push.c | 5 ++++- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/openvpn/misc.c b/src/openvpn/misc.c index f76c2e579a0..1e0088fe672 100644 --- a/src/openvpn/misc.c +++ b/src/openvpn/misc.c @@ -1044,6 +1044,7 @@ get_user_pass_cr (struct user_pass *up, bool from_authfile = (auth_file && !streq (auth_file, "stdin")); bool username_from_stdin = false; bool password_from_stdin = false; + bool response_from_stdin = true; if (flags & GET_USER_PASS_PREVIOUS_CREDS_FAILED) msg (M_WARN, "Note: previous '%s' credentials failed", prefix); @@ -1053,10 +1054,11 @@ get_user_pass_cr (struct user_pass *up, * Get username/password from management interface? */ if (management - && ((auth_file && streq (auth_file, "management")) || (!from_authfile && (flags & GET_USER_PASS_MANAGEMENT))) + && (!from_authfile && (flags & GET_USER_PASS_MANAGEMENT)) && management_query_user_pass_enabled (management)) { const char *sc = NULL; + response_from_stdin = false; if (flags & GET_USER_PASS_PREVIOUS_CREDS_FAILED) management_auth_failure (management, prefix, "previous auth credentials failed"); @@ -1090,7 +1092,10 @@ get_user_pass_cr (struct user_pass *up, if (!strlen (up->password)) strcpy (up->password, "ok"); } - else if (from_authfile) + /* + * Read from auth file unless this is a dynamic challenge request. + */ + else if (from_authfile && !(flags & GET_USER_PASS_DYNAMIC_CHALLENGE)) { /* * Try to get username/password from a file. @@ -1141,10 +1146,10 @@ get_user_pass_cr (struct user_pass *up, /* * Get username/password from standard input? */ - if (username_from_stdin || password_from_stdin) + if (username_from_stdin || password_from_stdin || response_from_stdin) { #ifdef ENABLE_CLIENT_CR - if (auth_challenge && (flags & GET_USER_PASS_DYNAMIC_CHALLENGE)) + if (auth_challenge && (flags & GET_USER_PASS_DYNAMIC_CHALLENGE) && response_from_stdin) { struct auth_challenge_info *ac = get_auth_challenge (auth_challenge, &gc); if (ac) @@ -1154,7 +1159,8 @@ get_user_pass_cr (struct user_pass *up, buf_set_write (&packed_resp, (uint8_t*)up->password, USER_PASS_LEN); msg (M_INFO|M_NOPREFIX, "CHALLENGE: %s", ac->challenge_text); - if (!get_console_input ("Response:", BOOL_CAST(ac->flags&CR_ECHO), response, USER_PASS_LEN)) + if (!get_console_input (ac->challenge_text, BOOL_CAST(ac->flags&CR_ECHO), + response, USER_PASS_LEN)) msg (M_FATAL, "ERROR: could not read challenge response from stdin"); strncpynt (up->username, ac->user, USER_PASS_LEN); buf_printf (&packed_resp, "CRV1::%s::%s", ac->state_id, response); @@ -1185,14 +1191,16 @@ get_user_pass_cr (struct user_pass *up, msg (M_FATAL, "ERROR: could not not read %s password from stdin", prefix); #ifdef ENABLE_CLIENT_CR - if (auth_challenge && (flags & GET_USER_PASS_STATIC_CHALLENGE)) + if (auth_challenge && (flags & GET_USER_PASS_STATIC_CHALLENGE) && response_from_stdin) { char *response = (char *) gc_malloc (USER_PASS_LEN, false, &gc); struct buffer packed_resp; char *pw64=NULL, *resp64=NULL; msg (M_INFO|M_NOPREFIX, "CHALLENGE: %s", auth_challenge); - if (!get_console_input ("Response:", BOOL_CAST(flags & GET_USER_PASS_STATIC_CHALLENGE_ECHO), response, USER_PASS_LEN)) + + if (!get_console_input (auth_challenge, BOOL_CAST(flags & GET_USER_PASS_STATIC_CHALLENGE_ECHO), + response, USER_PASS_LEN)) msg (M_FATAL, "ERROR: could not read static challenge response from stdin"); if (openvpn_base64_encode(up->password, strlen(up->password), &pw64) == -1 || openvpn_base64_encode(response, strlen(response), &resp64) == -1) diff --git a/src/openvpn/push.c b/src/openvpn/push.c index c29093b4ecc..be4daa1b382 100644 --- a/src/openvpn/push.c +++ b/src/openvpn/push.c @@ -100,8 +100,11 @@ receive_auth_failed (struct context *c, const struct buffer *buffer) if (buf_string_compare_advance (&buf, "AUTH_FAILED,") && BLEN (&buf)) reason = BSTR (&buf); management_auth_failure (management, UP_TYPE_AUTH, reason); - } else + } #endif + /* + * Save the dynamic-challenge text even when management is defined + */ { #ifdef ENABLE_CLIENT_CR struct buffer buf = *buffer; From 7c0ecd1191e66fa242708f93baa4006ba0a73c7a Mon Sep 17 00:00:00 2001 From: Jens Neuhalfen Date: Tue, 19 Apr 2016 20:42:55 +0200 Subject: [PATCH 226/643] Fix buffer overflow by user supplied data Passing very long usernames/passwords for pam authentication could possibly lead to a stack based buffer overrun in the auth-pam plugin. Adds a dependency to C99 (includes stdbool.h) Signed-off-by: Jens Neuhalfen Acked-by: Steffan Karger Message-Id: URL: http://article.gmane.org/gmane.network.openvpn.devel/11477 Signed-off-by: Gert Doering --- src/plugins/auth-pam/auth-pam.c | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/src/plugins/auth-pam/auth-pam.c b/src/plugins/auth-pam/auth-pam.c index 95692ab229f..710acccbf96 100644 --- a/src/plugins/auth-pam/auth-pam.c +++ b/src/plugins/auth-pam/auth-pam.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -47,6 +48,7 @@ #include #include #include +#include #include @@ -119,17 +121,37 @@ static void pam_server (int fd, const char *service, int verb, const struct name * a pointer to the NEW string. Does not modify the input strings. Will not enter an * infinite loop with clever 'searchfor' and 'replacewith' strings. * Daniel Johnson - Progman2000@usa.net / djohnson@progman.us + * + * Retuns NULL when + * - any parameter is NULL + * - the worst-case result is to large ( >= SIZE_MAX) */ static char * searchandreplace(const char *tosearch, const char *searchfor, const char *replacewith) { + if (!tosearch || !searchfor || !replacewith) return NULL; + + size_t tosearchlen = strlen(tosearch); + size_t replacewithlen = strlen(replacewith); + size_t templen = tosearchlen * replacewithlen; + + if (tosearchlen == 0 || strlen(searchfor) == 0 || replacewithlen == 0) { + return NULL; + } + + bool is_potential_integer_overflow = (templen == SIZE_MAX) || (templen / tosearchlen != replacewithlen); + + if (is_potential_integer_overflow) { + return NULL; + } + + // state: all parameters are valid + const char *searching=tosearch; char *scratch; - char temp[strlen(tosearch)*10]; - temp[0]=0; - if (!tosearch || !searchfor || !replacewith) return 0; - if (!strlen(tosearch) || !strlen(searchfor) || !strlen(replacewith)) return 0; + char temp[templen+1]; + temp[0]=0; scratch = strstr(searching,searchfor); if (!scratch) return strdup(tosearch); From 13a882ae39efb7144d9a9c5ac61100b1e27b1003 Mon Sep 17 00:00:00 2001 From: Daniel Kubec Date: Wed, 27 Apr 2016 08:00:34 +0200 Subject: [PATCH 227/643] Fix buffer size parameter for exported keying material. Commit 41e4b67a229e774ebc57a882c386e10d80e10e7e broke the exported keying material functionality while addressing lack of variable-length arrays in MSVC compilers - turning an array into a gc_malloc()'ed pointer, but still using "sizeof(ekm)" for buffer size - which is now "4" (unsigned char *), not the actual buffer length... Fixed! Acked-by: Gert Doering Message-Id: <49496.109.81.184.65.1461736834.squirrel@mail.actumg2.cz> URL: http://article.gmane.org/gmane.network.openvpn.devel/11509 Signed-off-by: Gert Doering --- src/openvpn/ssl_openssl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c index ca9b67ba7f1..8909ca3b864 100644 --- a/src/openvpn/ssl_openssl.c +++ b/src/openvpn/ssl_openssl.c @@ -144,7 +144,7 @@ key_state_export_keying_material(struct key_state_ssl *ssl, struct gc_arena gc = gc_new(); unsigned char* ekm = (unsigned char*) gc_malloc(size, true, &gc); - if (SSL_export_keying_material(ssl->ssl, ekm, sizeof(ekm), + if (SSL_export_keying_material(ssl->ssl, ekm, size, session->opt->ekm_label, session->opt->ekm_label_size, NULL, 0, 0)) { unsigned int len = (size * 2) + 2; From 4e37af92f5729cc29e5abdc873bac529c5a42ef9 Mon Sep 17 00:00:00 2001 From: Lev Stipakov Date: Wed, 11 Nov 2015 15:00:49 +0200 Subject: [PATCH 228/643] Fix "implicit declaration" compiler warning Add missing "include" directive. Signed-off-by: Lev Stipakov Acked-by: Arne Schwabe Message-Id: <1447246849-11602-1-git-send-email-lstipakov@gmail.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/10485 Signed-off-by: Gert Doering --- src/openvpn/mtcp.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/openvpn/mtcp.c b/src/openvpn/mtcp.c index b27c5eb7b6e..9926d476117 100644 --- a/src/openvpn/mtcp.c +++ b/src/openvpn/mtcp.c @@ -37,6 +37,10 @@ #include "memdbg.h" +#ifdef HAVE_SYS_INOTIFY_H +#include +#endif + /* * TCP States */ From dd2fbc26eb7b32325793ae3f7d215f46e881e68c Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Mon, 4 Apr 2016 21:59:38 +0200 Subject: [PATCH 229/643] PolarSSL x509_get_sha1_hash now returns correct SHA1 fingerprint. 509_get_sha1_hash() is supposed to return the certificate fingerprint, which is the hash of the entire certificate - including the signature - and not just the 'to be signed' data (cert->tbs in polarssl). This changes externally visible behavior for polarssl builds: it will change the value of the tls_digest_N values exported to the environment for scripts. v2 Steffan Karger: added commit message and Changes.rst entry. Code unchanged from v1 by James. Signed-off-by: James Yonan Signed-off-by: Steffan Karger Acked-by: Arne Schwabe Message-Id: URL: http://article.gmane.org/gmane.network.openvpn.devel/11396 Signed-off-by: Gert Doering --- Changes.rst | 5 ++++- src/openvpn/ssl_verify_polarssl.c | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Changes.rst b/Changes.rst index 93e4bd9dabb..5034b156b3e 100644 --- a/Changes.rst +++ b/Changes.rst @@ -63,7 +63,6 @@ User-visible Changes In --static mode connect-timeout specifies the timeout for TCP and proxy connection establishment - - connect-retry now specifies the maximum number of unsucessfully trying all remote/connection entries before exiting. @@ -92,6 +91,10 @@ User-visible Changes * Non-ephemeral key exchange using static (EC)DH keys * DSS private keys +- PolarSSL builds: changed the tls_digest_N values exported to the script + environment to be equal to the ones exported by OpenSSL builds, namely + the certificate fingerprint (was the hash of the 'to be signed' data). + Maintainer-visible changes -------------------------- diff --git a/src/openvpn/ssl_verify_polarssl.c b/src/openvpn/ssl_verify_polarssl.c index d1b9f02fb48..73a9af1f738 100644 --- a/src/openvpn/ssl_verify_polarssl.c +++ b/src/openvpn/ssl_verify_polarssl.c @@ -175,7 +175,7 @@ unsigned char * x509_get_sha1_hash (x509_crt *cert, struct gc_arena *gc) { unsigned char *sha1_hash = gc_malloc(SHA_DIGEST_LENGTH, false, gc); - sha1(cert->tbs.p, cert->tbs.len, sha1_hash); + sha1(cert->raw.p, cert->raw.len, sha1_hash); return sha1_hash; } From fab49d17d36053189cf504d57e53a8b0cb907f6f Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sat, 5 Mar 2016 17:08:22 +0100 Subject: [PATCH 230/643] Implemented x509-track for PolarSSL. This patch is a variant of the patch to implement x509-track for PolarSSL that was sent to openvpn-devel@ by James Yonan (<1456993146-63968-7-git-send-email-james@openvpn.net>). It still uses some of the original code from James, but proposes a different implementation. This patch does the following things differently: * Do not introduce NID_* defines that need to be maintained. Instead, just use the short name of the attribute for identification. This has the advantage that we automatically support everything that PolarSSL supports, it is less code and we do not have maintain the list. But the disadvantage is that this approach will not error out when an unknown attribute name is supplied. PolarSSL (at least 1.3, I didn't check 2.x) does not provide the functions required to do that. Instead of erroring out, this implementation will just silently ignore the unknown --x509-track attribute name. * Remove the ENABLE_X509_TRACK define completely - it depended just on ENABLE_CRYPTO anyway. * Move the --x509-track option parsing out of ENABLE_MANAGEMENT, since it does not depend on management functionality. Signed-off-by: Steffan Karger Acked-by: Arne Schwabe Message-Id: URL: http://article.gmane.org/gmane.network.openvpn.devel/11350 Signed-off-by: Gert Doering --- doc/openvpn.8 | 1 - src/openvpn/init.c | 2 - src/openvpn/options.c | 14 ++--- src/openvpn/options.h | 2 - src/openvpn/ssl_common.h | 2 - src/openvpn/ssl_verify.c | 16 ++---- src/openvpn/ssl_verify.h | 6 --- src/openvpn/ssl_verify_backend.h | 4 -- src/openvpn/ssl_verify_openssl.c | 3 -- src/openvpn/ssl_verify_polarssl.c | 90 +++++++++++++++++++++++++++++++ src/openvpn/syshead.h | 7 --- 11 files changed, 99 insertions(+), 48 deletions(-) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 6f4f21f994f..7d5dc5bf2b0 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -5114,7 +5114,6 @@ to save values from full cert chain. Values will be encoded as X509__=. Multiple .B \-\-x509\-track options can be defined to track multiple attributes. -Not available with PolarSSL. .\"********************************************************* .TP .B \-\-ns\-cert\-type client|server diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 84fac0783f7..42baf97f020 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -2355,9 +2355,7 @@ do_init_crypto_tls (struct context *c, const unsigned int flags) to.auth_user_pass_file = options->auth_user_pass_file; #endif -#ifdef ENABLE_X509_TRACK to.x509_track = options->x509_track; -#endif #if P2MP #ifdef ENABLE_CLIENT_CR diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 57f3dc536af..564e706020e 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -612,10 +612,8 @@ static const char usage_message[] = " of verification.\n" "--ns-cert-type t: Require that peer certificate was signed with an explicit\n" " nsCertType designation t = 'client' | 'server'.\n" -#ifdef ENABLE_X509_TRACK "--x509-track x : Save peer X509 attribute x in environment for use by\n" " plugins and management interface.\n" -#endif #if defined(ENABLE_CRYPTO_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10001000 "--keying-material-exporter label len : Save Exported Keying Material (RFC5705)\n" " of len bytes (min. 16 bytes) using label in environment for use by plugins.\n" @@ -4337,13 +4335,6 @@ add_option (struct options *options, options->management_flags |= MF_CLIENT_AUTH; } #endif -#ifdef ENABLE_X509_TRACK - else if (streq (p[0], "x509-track") && p[1] && !p[2]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - x509_track_add (&options->x509_track, p[1], msglevel, &options->gc); - } -#endif #ifdef MANAGEMENT_PF else if (streq (p[0], "management-client-pf") && !p[1]) { @@ -7026,6 +7017,11 @@ add_option (struct options *options, } options->key_method = key_method; } + else if (streq (p[0], "x509-track") && p[1] && !p[2]) + { + VERIFY_PERMISSION (OPT_P_GENERAL); + x509_track_add (&options->x509_track, p[1], msglevel, &options->gc); + } #ifdef ENABLE_X509ALTUSERNAME else if (streq (p[0], "x509-username-field") && p[1] && !p[2]) { diff --git a/src/openvpn/options.h b/src/openvpn/options.h index 8a26e147799..ffbe5e11bbe 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -574,9 +574,7 @@ struct options #endif /* ENABLE_CRYPTO */ -#ifdef ENABLE_X509_TRACK const struct x509_track *x509_track; -#endif /* special state parms */ int foreign_option_index; diff --git a/src/openvpn/ssl_common.h b/src/openvpn/ssl_common.h index 334ccb0739c..a0df0ffb8f8 100644 --- a/src/openvpn/ssl_common.h +++ b/src/openvpn/ssl_common.h @@ -308,9 +308,7 @@ struct tls_options struct man_def_auth_context *mda_context; #endif -#ifdef ENABLE_X509_TRACK const struct x509_track *x509_track; -#endif #ifdef ENABLE_CLIENT_CR const struct static_challenge_info *sci; diff --git a/src/openvpn/ssl_verify.c b/src/openvpn/ssl_verify.c index ea381f83462..b373bed1ada 100644 --- a/src/openvpn/ssl_verify.c +++ b/src/openvpn/ssl_verify.c @@ -393,22 +393,17 @@ verify_peer_cert(const struct tls_options *opt, openvpn_x509_cert_t *peer_cert, */ static void verify_cert_set_env(struct env_set *es, openvpn_x509_cert_t *peer_cert, int cert_depth, - const char *subject, const char *common_name -#ifdef ENABLE_X509_TRACK - , const struct x509_track *x509_track -#endif - ) + const char *subject, const char *common_name, + const struct x509_track *x509_track) { char envname[64]; char *serial = NULL; struct gc_arena gc = gc_new (); /* Save X509 fields in environment */ -#ifdef ENABLE_X509_TRACK if (x509_track) x509_setenv_track (x509_track, es, cert_depth, peer_cert); else -#endif x509_setenv (es, cert_depth, peer_cert); /* export subject name string as environmental variable */ @@ -658,11 +653,8 @@ verify_cert(struct tls_session *session, openvpn_x509_cert_t *cert, int cert_dep session->verify_maxlevel = max_int (session->verify_maxlevel, cert_depth); /* export certificate values to the environment */ - verify_cert_set_env(opt->es, cert, cert_depth, subject, common_name -#ifdef ENABLE_X509_TRACK - , opt->x509_track -#endif - ); + verify_cert_set_env(opt->es, cert, cert_depth, subject, common_name, + opt->x509_track); /* export current untrusted IP */ setenv_untrusted (session); diff --git a/src/openvpn/ssl_verify.h b/src/openvpn/ssl_verify.h index d5bf22e51ca..8527415f85e 100644 --- a/src/openvpn/ssl_verify.h +++ b/src/openvpn/ssl_verify.h @@ -201,8 +201,6 @@ void verify_user_pass(struct user_pass *up, struct tls_multi *multi, */ void verify_final_auth_checks(struct tls_multi *multi, struct tls_session *session); -#ifdef ENABLE_X509_TRACK - struct x509_track { const struct x509_track *next; @@ -212,10 +210,6 @@ struct x509_track int nid; }; -void x509_track_add (const struct x509_track **ll_head, const char *name, int msglevel, struct gc_arena *gc); - -#endif - /* * Certificate checking for verify_nsCertType */ diff --git a/src/openvpn/ssl_verify_backend.h b/src/openvpn/ssl_verify_backend.h index 17e88fb36fe..9d2057b558d 100644 --- a/src/openvpn/ssl_verify_backend.h +++ b/src/openvpn/ssl_verify_backend.h @@ -150,8 +150,6 @@ char *backend_x509_get_serial_hex (openvpn_x509_cert_t *cert, */ void x509_setenv (struct env_set *es, int cert_depth, openvpn_x509_cert_t *cert); -#ifdef ENABLE_X509_TRACK - /* * Start tracking the given attribute. * @@ -189,8 +187,6 @@ void x509_track_add (const struct x509_track **ll_head, const char *name, void x509_setenv_track (const struct x509_track *xt, struct env_set *es, const int depth, openvpn_x509_cert_t *x509); -#endif - /* * Check X.509 Netscape certificate type field, if available. * diff --git a/src/openvpn/ssl_verify_openssl.c b/src/openvpn/ssl_verify_openssl.c index 4020fb9e847..5817a05eeda 100644 --- a/src/openvpn/ssl_verify_openssl.c +++ b/src/openvpn/ssl_verify_openssl.c @@ -303,8 +303,6 @@ x509_get_subject (X509 *cert, struct gc_arena *gc) } -#ifdef ENABLE_X509_TRACK - /* * x509-track implementation -- save X509 fields to environment, * using the naming convention: @@ -434,7 +432,6 @@ x509_setenv_track (const struct x509_track *xt, struct env_set *es, const int de } gc_free(&gc); } -#endif /* * Save X509 fields to environment, using the naming convention: diff --git a/src/openvpn/ssl_verify_polarssl.c b/src/openvpn/ssl_verify_polarssl.c index 73a9af1f738..d52713369eb 100644 --- a/src/openvpn/ssl_verify_polarssl.c +++ b/src/openvpn/ssl_verify_polarssl.c @@ -37,7 +37,9 @@ #if defined(ENABLE_CRYPTO) && defined(ENABLE_CRYPTO_POLARSSL) +#include "crypto_polarssl.h" #include "ssl_verify.h" +#include #include #include #include @@ -197,6 +199,94 @@ x509_get_subject(x509_crt *cert, struct gc_arena *gc) return subject; } +static void +do_setenv_x509 (struct env_set *es, const char *name, char *value, int depth) +{ + char *name_expand; + size_t name_expand_size; + + string_mod (value, CC_ANY, CC_CRLF, '?'); + msg (D_X509_ATTR, "X509 ATTRIBUTE name='%s' value='%s' depth=%d", name, value, depth); + name_expand_size = 64 + strlen (name); + name_expand = (char *) malloc (name_expand_size); + check_malloc_return (name_expand); + openvpn_snprintf (name_expand, name_expand_size, "X509_%d_%s", depth, name); + setenv_str (es, name_expand, value); + free (name_expand); +} + +static char * +asn1_buf_to_c_string(const asn1_buf *orig, struct gc_arena *gc) +{ + size_t i; + char *val; + + for (i = 0; i < orig->len; ++i) + if (orig->p[i] == '\0') + return "ERROR: embedded null value"; + val = gc_malloc(orig->len+1, false, gc); + memcpy(val, orig->p, orig->len); + val[orig->len] = '\0'; + return val; +} + +static void +do_setenv_name(struct env_set *es, const struct x509_track *xt, + const x509_crt *cert, int depth, struct gc_arena *gc) +{ + const x509_name *xn; + for (xn = &cert->subject; xn != NULL; xn = xn->next) + { + const char *xn_short_name = NULL; + if (0 == oid_get_attr_short_name (&xn->oid, &xn_short_name) && + 0 == strcmp (xt->name, xn_short_name)) + { + char *val_str = asn1_buf_to_c_string (&xn->val, gc); + do_setenv_x509 (es, xt->name, val_str, depth); + } + } +} + +void +x509_track_add (const struct x509_track **ll_head, const char *name, int msglevel, struct gc_arena *gc) +{ + struct x509_track *xt; + ALLOC_OBJ_CLEAR_GC (xt, struct x509_track, gc); + if (*name == '+') + { + xt->flags |= XT_FULL_CHAIN; + ++name; + } + xt->name = name; + xt->next = *ll_head; + *ll_head = xt; +} + +void +x509_setenv_track (const struct x509_track *xt, struct env_set *es, const int depth, x509_crt *cert) +{ + struct gc_arena gc = gc_new(); + while (xt) + { + if (depth == 0 || (xt->flags & XT_FULL_CHAIN)) + { + if (0 == strcmp(xt->name, "SHA1")) + { + /* SHA1 fingerprint is not part of X509 structure */ + unsigned char *sha1_hash = x509_get_sha1_hash(cert, &gc); + char *sha1_fingerprint = format_hex_ex(sha1_hash, SHA_DIGEST_LENGTH, 0, 1 | FHE_CAPS, ":", &gc); + do_setenv_x509(es, xt->name, sha1_fingerprint, depth); + } + else + { + do_setenv_name(es, xt, cert, depth, &gc); + } + } + xt = xt->next; + } + gc_free(&gc); +} + /* * Save X509 fields to environment, using the naming convention: * diff --git a/src/openvpn/syshead.h b/src/openvpn/syshead.h index 7e77b6cdefb..1c9248fb260 100644 --- a/src/openvpn/syshead.h +++ b/src/openvpn/syshead.h @@ -631,13 +631,6 @@ socket_defined (const socket_descriptor_t sd) #define ENABLE_CRYPTOAPI #endif -/* - * Enable x509-track feature? - */ -#if defined(ENABLE_CRYPTO) && defined (ENABLE_CRYPTO_OPENSSL) -#define ENABLE_X509_TRACK -#endif - /* * Is poll available on this platform? */ From 86d8cd6860dfc74cb1a040ff8fe03140ebe7f930 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sun, 17 Apr 2016 20:35:42 +0200 Subject: [PATCH 231/643] Migrate to mbed TLS 2.x PolarSSL / mbed TLS 1.3 is going end-of-life by 2016-12-31, so let's move the master branch on to the 2.x series. This patch purges all references to polarssl, except for file names and some comments referring to 1.2 and earlier, which were never released as 'mbed TLS'. A separate patch for the file names follows, so the real changes are easier to spot without git-fu. This patch intends to not change any behaviour. The vast majority of this patch is just renaming functions and structs. There are some small changes in the implementation: * In ssl_polarssl.c: the debug callback prototype changed, so our implementation changed a bit too. * in ssl_polarssl.c: the old polarssl ssl_context is now split into a mbedtls_ssl_config and mbedtls_ssl_context. The intention is that mbedtls_ssl_config is shared among connections, and mbedtls_ssl_context contains the per-connection state. That doesn't work for us, because we use per-connection verify callback data, while the verify callback is registered on mbed_tls_config. Therefore we still need to init a mbed_tls_config struct for each connection. * in ssl_polarssl.c: the mbed bio handling changed, so our implementation changed a bit too. * in ssl_polarssl.c and ssl_verify_polarssl.c: the mbedtls x509 parse functions now fail if we don't provide a NUL-terminated string, so use strlen()+1 as the length argument to include the terminating NUL. I tested this patch to work with: * 'make check' (with 2.0.0 and 2.2.1, other tests just with 2.2.1) * static key mode * TLS mode with PEM key file * TLS mode with password protected PEM key file * TLS mode with management-external-key * TLS mode with PKCS#11 * TLS mode with inline ca/key/cert/dh Signed-off-by: Steffan Karger Acked-by: Arne Schwabe Message-Id: <1460918143-408-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/11458 Signed-off-by: Gert Doering --- configure.ac | 74 +++-- include/openvpn-plugin.h.in | 10 +- src/openvpn/crypto_backend.h | 4 +- src/openvpn/crypto_polarssl.c | 263 +++++++++--------- src/openvpn/crypto_polarssl.h | 76 +++--- src/openvpn/options.c | 44 +-- src/openvpn/options.h | 4 +- src/openvpn/pkcs11_polarssl.c | 53 ++-- src/openvpn/plugin.h | 2 +- src/openvpn/ssl.c | 2 +- src/openvpn/ssl_backend.h | 8 +- src/openvpn/ssl_polarssl.c | 433 +++++++++++++++--------------- src/openvpn/ssl_polarssl.h | 35 +-- src/openvpn/ssl_verify.h | 2 +- src/openvpn/ssl_verify_polarssl.c | 124 +++++---- src/openvpn/ssl_verify_polarssl.h | 20 +- src/openvpn/syshead.h | 6 +- 17 files changed, 595 insertions(+), 565 deletions(-) diff --git a/configure.ac b/configure.ac index b75d51f6e89..f2c61fee2d0 100644 --- a/configure.ac +++ b/configure.ac @@ -291,10 +291,10 @@ AC_ARG_WITH( AC_ARG_WITH( [crypto-library], - [AS_HELP_STRING([--with-crypto-library=library], [build with the given crypto library, TYPE=openssl|polarssl @<:@default=openssl@:>@])], + [AS_HELP_STRING([--with-crypto-library=library], [build with the given crypto library, TYPE=openssl|mbedtls @<:@default=openssl@:>@])], [ - case "${withval}" in - openssl|polarssl) ;; + case "${withval}" in + openssl|mbedtls) ;; *) AC_MSG_ERROR([bad value ${withval} for --with-crypto-library]) ;; esac ], @@ -835,81 +835,77 @@ if test "${with_crypto_library}" = "openssl"; then AC_DEFINE([ENABLE_CRYPTO_OPENSSL], [1], [Use OpenSSL library]) CRYPTO_CFLAGS="${OPENSSL_CFLAGS}" CRYPTO_LIBS="${OPENSSL_LIBS}" -elif test "${with_crypto_library}" = "polarssl"; then - AC_ARG_VAR([POLARSSL_CFLAGS], [C compiler flags for polarssl]) - AC_ARG_VAR([POLARSSL_LIBS], [linker flags for polarssl]) +elif test "${with_crypto_library}" = "mbedtls"; then + AC_ARG_VAR([MBEDTLS_CFLAGS], [C compiler flags for mbedtls]) + AC_ARG_VAR([MBEDTLS_LIBS], [linker flags for mbedtls]) saved_CFLAGS="${CFLAGS}" saved_LIBS="${LIBS}" - if test -z "${POLARSSL_CFLAGS}" -a -z "${POLARSSL_LIBS}"; then - # if the user did not explicitly specify flags, try to autodetect - AC_SEARCH_LIBS( - [ssl_init], - [mbedtls polarssl], - [ - if test "${ac_cv_search_ssl_init}" != "none required"; then - POLARSSL_LIBS=${ac_cv_search_ssl_init} - fi - ], - [AC_MSG_ERROR([Could not find PolarSSL/mbed TLS.])], + if test -z "${MBEDTLS_CFLAGS}" -a -z "${MBEDTLS_LIBS}"; then + # if the user did not explicitly specify flags, try to autodetect + AC_CHECK_LIB( + [mbedtls], + [mbedtls_ssl_init], + [MBEDTLS_LIBS="-lmbedtls -lmbedcrypto -lmbedx509"], + [AC_MSG_ERROR([Could not find mbed TLS.])], [${PKCS11_HELPER_LIBS}] ) fi - CFLAGS="${POLARSSL_CFLAGS} ${PKCS11_HELPER_CFLAGS} ${CFLAGS}" - LIBS="${POLARSSL_LIBS} ${PKCS11_HELPER_LIBS} ${LIBS}" + CFLAGS="${MBEDTLS_CFLAGS} ${PKCS11_HELPER_CFLAGS} ${CFLAGS}" + LIBS="${MBEDTLS_LIBS} ${PKCS11_HELPER_LIBS} ${LIBS}" - AC_MSG_CHECKING([polarssl version]) + AC_MSG_CHECKING([mbedtls version]) AC_COMPILE_IFELSE( [AC_LANG_PROGRAM( [[ -#include +#include ]], [[ -#if POLARSSL_VERSION_NUMBER < 0x01030800 || POLARSSL_VERSION_NUMBER >= 0x01040000 +#if MBEDTLS_VERSION_NUMBER < 0x02000000 || MBEDTLS_VERSION_NUMBER >= 0x03000000 #error invalid version #endif ]] )], [AC_MSG_RESULT([ok])], - [AC_MSG_ERROR([PolarSSL 1.3.x required and must be 1.3.8 or later])] + [AC_MSG_ERROR([mbed TLS 2.y.z required])] ) - polarssl_with_pkcs11="no" + mbedtls_with_pkcs11="no" AC_COMPILE_IFELSE( [AC_LANG_PROGRAM( [[ -#include +#include ]], [[ -#ifndef POLARSSL_PKCS11_C +#ifndef MBEDTLS_PKCS11_C #error pkcs11 wrapper missing #endif ]] )], - polarssl_with_pkcs11="yes") + mbedtls_with_pkcs11="yes") - AC_MSG_CHECKING([polarssl pkcs11 support]) + AC_MSG_CHECKING([mbedtls pkcs11 support]) if test "${enable_pkcs11}" = "yes"; then - if test "${polarssl_with_pkcs11}" = "yes"; then + if test "${mbedtls_with_pkcs11}" = "yes"; then AC_MSG_RESULT([ok]) else - AC_MSG_ERROR([polarssl has no pkcs11 wrapper compiled in]) + AC_MSG_ERROR([mbedtls has no pkcs11 wrapper compiled in]) fi else - if test "${polarssl_with_pkcs11}" != "yes"; then + if test "${mbedtls_with_pkcs11}" != "yes"; then AC_MSG_RESULT([ok]) else - AC_MSG_ERROR([PolarSSL compiled with PKCS11, while OpenVPN is not]) + AC_MSG_ERROR([mbed TLS compiled with PKCS11, while OpenVPN is not]) fi fi have_crypto_aead_modes="yes" AC_CHECK_FUNCS( [ \ - cipher_write_tag \ - cipher_check_tag \ + mbedtls_cipher_write_tag \ + mbedtls_cipher_check_tag \ ], , [have_crypto_aead_modes="no"; break] @@ -918,9 +914,9 @@ elif test "${with_crypto_library}" = "polarssl"; then CFLAGS="${saved_CFLAGS}" LIBS="${saved_LIBS}" have_crypto="yes" - AC_DEFINE([ENABLE_CRYPTO_POLARSSL], [1], [Use PolarSSL library]) - CRYPTO_CFLAGS="${POLARSSL_CFLAGS}" - CRYPTO_LIBS="${POLARSSL_LIBS}" + AC_DEFINE([ENABLE_CRYPTO_MBEDTLS], [1], [Use mbed TLS library]) + CRYPTO_CFLAGS="${MBEDTLS_CFLAGS}" + CRYPTO_LIBS="${MBEDTLS_LIBS}" else AC_MSG_ERROR([Invalid crypto library: ${with_crypto_library}]) fi @@ -1048,8 +1044,8 @@ fi dnl enable --x509-username-field feature if requested if test "${enable_x509_alt_username}" = "yes"; then - if test "${with_crypto_library}" = "polarssl" ; then - AC_MSG_ERROR([PolarSSL does not support the --x509-username-field feature]) + if test "${with_crypto_library}" = "mbedtls" ; then + AC_MSG_ERROR([mbed TLS does not support the --x509-username-field feature]) fi AC_DEFINE([ENABLE_X509ALTUSERNAME], [1], [Enable --x509-username-field feature]) diff --git a/include/openvpn-plugin.h.in b/include/openvpn-plugin.h.in index d4bf62277da..b03a9df7db1 100644 --- a/include/openvpn-plugin.h.in +++ b/include/openvpn-plugin.h.in @@ -28,11 +28,11 @@ #define OPENVPN_PLUGIN_VERSION 3 #ifdef ENABLE_CRYPTO -#ifdef ENABLE_CRYPTO_POLARSSL -#include +#ifdef ENABLE_CRYPTO_MBEDTLS +#include #ifndef __OPENVPN_X509_CERT_T_DECLARED #define __OPENVPN_X509_CERT_T_DECLARED -typedef x509_crt openvpn_x509_cert_t; +typedef mbedtls_x509_crt openvpn_x509_cert_t; #endif #else #include @@ -277,13 +277,13 @@ struct openvpn_plugin_callbacks /** * Used by the openvpn_plugin_open_v3() function to indicate to the * plug-in what kind of SSL implementation OpenVPN uses. This is - * to avoid SEGV issues when OpenVPN is complied against PolarSSL + * to avoid SEGV issues when OpenVPN is complied against mbed TLS * and the plug-in against OpenSSL. */ typedef enum { SSLAPI_NONE, SSLAPI_OPENSSL, - SSLAPI_POLARSSL + SSLAPI_MBEDTLS } ovpnSSLAPI; /** diff --git a/src/openvpn/crypto_backend.h b/src/openvpn/crypto_backend.h index fb7c351322a..c4986f558e5 100644 --- a/src/openvpn/crypto_backend.h +++ b/src/openvpn/crypto_backend.h @@ -33,7 +33,7 @@ #ifdef ENABLE_CRYPTO_OPENSSL #include "crypto_openssl.h" #endif -#ifdef ENABLE_CRYPTO_POLARSSL +#ifdef ENABLE_CRYPTO_MBEDTLS #include "crypto_polarssl.h" #endif #include "basic.h" @@ -294,7 +294,7 @@ bool cipher_kt_mode_aead(const cipher_kt_t *cipher); * @param key_len Length of the key, in bytes * @param kt Static cipher parameters to use * @param enc Whether to encrypt or decrypt (either - * \c POLARSSL_OP_ENCRYPT or \c POLARSSL_OP_DECRYPT). + * \c MBEDTLS_OP_ENCRYPT or \c MBEDTLS_OP_DECRYPT). */ void cipher_ctx_init (cipher_ctx_t *ctx, uint8_t *key, int key_len, const cipher_kt_t *kt, int enc); diff --git a/src/openvpn/crypto_polarssl.c b/src/openvpn/crypto_polarssl.c index fc6f6c34021..da1b4176690 100644 --- a/src/openvpn/crypto_polarssl.c +++ b/src/openvpn/crypto_polarssl.c @@ -24,7 +24,7 @@ */ /** - * @file Data Channel Cryptography PolarSSL-specific backend interface + * @file Data Channel Cryptography mbed TLS-specific backend interface */ #ifdef HAVE_CONFIG_H @@ -35,7 +35,7 @@ #include "syshead.h" -#if defined(ENABLE_CRYPTO) && defined(ENABLE_CRYPTO_POLARSSL) +#if defined(ENABLE_CRYPTO) && defined(ENABLE_CRYPTO_MBEDTLS) #include "errlevel.h" #include "basic.h" @@ -45,13 +45,14 @@ #include "otime.h" #include "misc.h" -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include + +#include -#include /* * @@ -62,7 +63,7 @@ void crypto_init_lib_engine (const char *engine_name) { - msg (M_WARN, "Note: PolarSSL hardware crypto engine functionality is not " + msg (M_WARN, "Note: mbed TLS hardware crypto engine functionality is not " "available"); } @@ -87,29 +88,29 @@ crypto_clear_error (void) { } -bool polar_log_err(unsigned int flags, int errval, const char *prefix) +bool mbed_log_err(unsigned int flags, int errval, const char *prefix) { if (0 != errval) { char errstr[256]; - polarssl_strerror(errval, errstr, sizeof(errstr)); + mbedtls_strerror(errval, errstr, sizeof(errstr)); - if (NULL == prefix) prefix = "PolarSSL error"; + if (NULL == prefix) prefix = "mbed TLS error"; msg (flags, "%s: %s", prefix, errstr); } return 0 == errval; } -bool polar_log_func_line(unsigned int flags, int errval, const char *func, +bool mbed_log_func_line(unsigned int flags, int errval, const char *func, int line) { char prefix[256]; if (!openvpn_snprintf(prefix, sizeof(prefix), "%s:%d", func, line)) - return polar_log_err(flags, errval, func); + return mbed_log_err(flags, errval, func); - return polar_log_err(flags, errval, prefix); + return mbed_log_err(flags, errval, prefix); } @@ -117,7 +118,7 @@ bool polar_log_func_line(unsigned int flags, int errval, const char *func, void crypto_init_dmalloc (void) { - msg (M_ERR, "Error: dmalloc support is not available for PolarSSL."); + msg (M_ERR, "Error: dmalloc support is not available for mbed TLS."); } #endif /* DMALLOC */ @@ -134,7 +135,7 @@ const size_t cipher_name_translation_table_count = void show_available_ciphers () { - const int *ciphers = cipher_list(); + const int *ciphers = mbedtls_cipher_list(); #ifndef ENABLE_SMALL printf ("The following ciphers and cipher modes are available for use\n" @@ -145,7 +146,7 @@ show_available_ciphers () while (*ciphers != 0) { - const cipher_kt_t *info = cipher_info_from_type(*ciphers); + const cipher_kt_t *info = mbedtls_cipher_info_from_type(*ciphers); if (info && (cipher_kt_mode_cbc(info) #ifdef HAVE_AEAD_CIPHER_MODES @@ -168,7 +169,7 @@ show_available_ciphers () void show_available_digests () { - const int *digests = md_list(); + const int *digests = mbedtls_md_list(); #ifndef ENABLE_SMALL printf ("The following message digests are available for use with\n" @@ -180,11 +181,11 @@ show_available_digests () while (*digests != 0) { - const md_info_t *info = md_info_from_type(*digests); + const mbedtls_md_info_t *info = mbedtls_md_info_from_type(*digests); if (info) - printf ("%s %d bit default key\n", - md_get_name(info), md_get_size(info) * 8); + printf ("%s %d bit default key\n", mbedtls_md_get_name(info), + mbedtls_md_get_size(info) * 8); digests++; } printf ("\n"); @@ -193,7 +194,7 @@ show_available_digests () void show_available_engines () { - printf ("Sorry, PolarSSL hardware crypto engine functionality is not " + printf ("Sorry, mbed TLS hardware crypto engine functionality is not " "available\n"); } @@ -210,10 +211,10 @@ show_available_engines () * Initialise the given ctr_drbg context, using a personalisation string and an * entropy gathering function. */ -ctr_drbg_context * rand_ctx_get() +mbedtls_ctr_drbg_context * rand_ctx_get() { - static entropy_context ec = {0}; - static ctr_drbg_context cd_ctx = {0}; + static mbedtls_entropy_context ec = {0}; + static mbedtls_ctr_drbg_context cd_ctx = {0}; static bool rand_initialised = false; if (!rand_initialised) @@ -228,10 +229,11 @@ ctr_drbg_context * rand_ctx_get() */ buf_printf(&pers_string, "OpenVPN %0u %p %s", platform_getpid(), &cd_ctx, time_string(0, 0, 0, &gc)); - /* Initialise PolarSSL RNG, and built-in entropy sources */ - entropy_init(&ec); + /* Initialise mbed TLS RNG, and built-in entropy sources */ + mbedtls_entropy_init(&ec); - if (!polar_ok(ctr_drbg_init(&cd_ctx, entropy_func, &ec, + mbedtls_ctr_drbg_init(&cd_ctx); + if (!mbed_ok(mbedtls_ctr_drbg_seed(&cd_ctx, mbedtls_entropy_func, &ec, BPTR(&pers_string), BLEN(&pers_string)))) msg (M_FATAL, "Failed to initialize random generator"); @@ -245,21 +247,21 @@ ctr_drbg_context * rand_ctx_get() #ifdef ENABLE_PREDICTION_RESISTANCE void rand_ctx_enable_prediction_resistance() { - ctr_drbg_context *cd_ctx = rand_ctx_get(); + mbedtls_ctr_drbg_context *cd_ctx = rand_ctx_get(); - ctr_drbg_set_prediction_resistance(cd_ctx, 1); + mbedtls_ctr_drbg_set_prediction_resistance(cd_ctx, 1); } #endif /* ENABLE_PREDICTION_RESISTANCE */ int rand_bytes (uint8_t *output, int len) { - ctr_drbg_context *rng_ctx = rand_ctx_get(); + mbedtls_ctr_drbg_context *rng_ctx = rand_ctx_get(); while (len > 0) { - const size_t blen = min_int (len, CTR_DRBG_MAX_REQUEST); - if (0 != ctr_drbg_random(rng_ctx, output, blen)) + const size_t blen = min_int (len, MBEDTLS_CTR_DRBG_MAX_REQUEST); + if (0 != mbedtls_ctr_drbg_random(rng_ctx, output, blen)) return 0; output += blen; @@ -277,14 +279,14 @@ rand_bytes (uint8_t *output, int len) int -key_des_num_cblocks (const cipher_info_t *kt) +key_des_num_cblocks (const mbedtls_cipher_info_t *kt) { int ret = 0; - if (kt->type == POLARSSL_CIPHER_DES_CBC) + if (kt->type == MBEDTLS_CIPHER_DES_CBC) ret = 1; - if (kt->type == POLARSSL_CIPHER_DES_EDE_CBC) + if (kt->type == MBEDTLS_CIPHER_DES_EDE_CBC) ret = 2; - if (kt->type == POLARSSL_CIPHER_DES_EDE3_CBC) + if (kt->type == MBEDTLS_CIPHER_DES_EDE3_CBC) ret = 3; dmsg (D_CRYPTO_DEBUG, "CRYPTO INFO: n_DES_cblocks=%d", ret); @@ -301,18 +303,18 @@ key_des_check (uint8_t *key, int key_len, int ndc) for (i = 0; i < ndc; ++i) { - unsigned char *key = buf_read_alloc(&b, DES_KEY_SIZE); + unsigned char *key = buf_read_alloc(&b, MBEDTLS_DES_KEY_SIZE); if (!key) { msg (D_CRYPT_ERRORS, "CRYPTO INFO: check_key_DES: insufficient key material"); goto err; } - if (0 != des_key_check_weak(key)) + if (0 != mbedtls_des_key_check_weak(key)) { msg (D_CRYPT_ERRORS, "CRYPTO INFO: check_key_DES: weak key detected"); goto err; } - if (0 != des_key_check_key_parity(key)) + if (0 != mbedtls_des_key_check_key_parity(key)) { msg (D_CRYPT_ERRORS, "CRYPTO INFO: check_key_DES: bad parity detected"); goto err; @@ -333,13 +335,13 @@ key_des_fixup (uint8_t *key, int key_len, int ndc) buf_set_read (&b, key, key_len); for (i = 0; i < ndc; ++i) { - unsigned char *key = buf_read_alloc(&b, DES_KEY_SIZE); + unsigned char *key = buf_read_alloc(&b, MBEDTLS_DES_KEY_SIZE); if (!key) { msg (D_CRYPT_ERRORS, "CRYPTO INFO: fixup_key_DES: insufficient key material"); return; } - des_key_set_parity(key); + mbedtls_des_key_set_parity(key); } } @@ -350,29 +352,29 @@ key_des_fixup (uint8_t *key, int key_len, int ndc) */ -const cipher_info_t * +const mbedtls_cipher_info_t * cipher_kt_get (const char *ciphername) { - const cipher_info_t *cipher = NULL; + const mbedtls_cipher_info_t *cipher = NULL; ASSERT (ciphername); - cipher = cipher_info_from_string(ciphername); + cipher = mbedtls_cipher_info_from_string(ciphername); if (NULL == cipher) msg (M_FATAL, "Cipher algorithm '%s' not found", ciphername); - if (cipher->key_length/8 > MAX_CIPHER_KEY_LENGTH) + if (cipher->key_bitlen/8 > MAX_CIPHER_KEY_LENGTH) msg (M_FATAL, "Cipher algorithm '%s' uses a default key size (%d bytes) which is larger than " PACKAGE_NAME "'s current maximum key size (%d bytes)", ciphername, - cipher->key_length/8, + cipher->key_bitlen/8, MAX_CIPHER_KEY_LENGTH); return cipher; } const char * -cipher_kt_name (const cipher_info_t *cipher_kt) +cipher_kt_name (const mbedtls_cipher_info_t *cipher_kt) { if (NULL == cipher_kt) return "[null-cipher]"; @@ -381,16 +383,16 @@ cipher_kt_name (const cipher_info_t *cipher_kt) } int -cipher_kt_key_size (const cipher_info_t *cipher_kt) +cipher_kt_key_size (const mbedtls_cipher_info_t *cipher_kt) { if (NULL == cipher_kt) return 0; - return cipher_kt->key_length/8; + return cipher_kt->key_bitlen/8; } int -cipher_kt_iv_size (const cipher_info_t *cipher_kt) +cipher_kt_iv_size (const mbedtls_cipher_info_t *cipher_kt) { if (NULL == cipher_kt) return 0; @@ -398,7 +400,7 @@ cipher_kt_iv_size (const cipher_info_t *cipher_kt) } int -cipher_kt_block_size (const cipher_info_t *cipher_kt) +cipher_kt_block_size (const mbedtls_cipher_info_t *cipher_kt) { if (NULL == cipher_kt) return 0; @@ -406,7 +408,7 @@ cipher_kt_block_size (const cipher_info_t *cipher_kt) } int -cipher_kt_tag_size (const cipher_info_t *cipher_kt) +cipher_kt_tag_size (const mbedtls_cipher_info_t *cipher_kt) { #ifdef HAVE_AEAD_CIPHER_MODES if (cipher_kt && cipher_kt_mode_aead(cipher_kt)) @@ -416,7 +418,7 @@ cipher_kt_tag_size (const cipher_info_t *cipher_kt) } int -cipher_kt_mode (const cipher_info_t *cipher_kt) +cipher_kt_mode (const mbedtls_cipher_info_t *cipher_kt) { ASSERT(NULL != cipher_kt); return cipher_kt->mode; @@ -432,7 +434,7 @@ bool cipher_kt_mode_ofb_cfb(const cipher_kt_t *cipher) { return cipher && (cipher_kt_mode(cipher) == OPENVPN_MODE_OFB || - cipher_kt_mode(cipher) == OPENVPN_MODE_CFB); + cipher_kt_mode(cipher) == OPENVPN_MODE_CFB); } bool @@ -450,31 +452,31 @@ cipher_kt_mode_aead(const cipher_kt_t *cipher) void -cipher_ctx_init (cipher_context_t *ctx, uint8_t *key, int key_len, - const cipher_info_t *kt, int enc) +cipher_ctx_init (mbedtls_cipher_context_t *ctx, uint8_t *key, int key_len, + const mbedtls_cipher_info_t *kt, const mbedtls_operation_t operation) { ASSERT(NULL != kt && NULL != ctx); CLEAR (*ctx); - if (!polar_ok(cipher_init_ctx(ctx, kt))) - msg (M_FATAL, "PolarSSL cipher context init #1"); + if (!mbed_ok(mbedtls_cipher_setup(ctx, kt))) + msg (M_FATAL, "mbed TLS cipher context init #1"); - if (!polar_ok(cipher_setkey(ctx, key, key_len*8, enc))) - msg (M_FATAL, "PolarSSL cipher set key"); + if (!mbed_ok(mbedtls_cipher_setkey(ctx, key, key_len*8, operation))) + msg (M_FATAL, "mbed TLS cipher set key"); /* make sure we used a big enough key */ - ASSERT (ctx->key_length <= key_len*8); + ASSERT (ctx->key_bitlen <= key_len*8); } -void cipher_ctx_cleanup (cipher_context_t *ctx) +void cipher_ctx_cleanup (mbedtls_cipher_context_t *ctx) { - cipher_free(ctx); + mbedtls_cipher_free(ctx); } -int cipher_ctx_iv_length (const cipher_context_t *ctx) +int cipher_ctx_iv_length (const mbedtls_cipher_context_t *ctx) { - return cipher_get_iv_size(ctx); + return mbedtls_cipher_get_iv_size(ctx); } int cipher_ctx_get_tag (cipher_ctx_t *ctx, uint8_t* tag, int tag_len) @@ -483,7 +485,7 @@ int cipher_ctx_get_tag (cipher_ctx_t *ctx, uint8_t* tag, int tag_len) if (tag_len > SIZE_MAX) return 0; - if (!polar_ok (cipher_write_tag (ctx, (unsigned char *) tag, tag_len))) + if (!mbed_ok (mbedtls_cipher_write_tag (ctx, (unsigned char *) tag, tag_len))) return 0; return 1; @@ -492,12 +494,12 @@ int cipher_ctx_get_tag (cipher_ctx_t *ctx, uint8_t* tag, int tag_len) #endif /* HAVE_AEAD_CIPHER_MODES */ } -int cipher_ctx_block_size(const cipher_context_t *ctx) +int cipher_ctx_block_size(const mbedtls_cipher_context_t *ctx) { - return cipher_get_block_size(ctx); + return mbedtls_cipher_get_block_size(ctx); } -int cipher_ctx_mode (const cipher_context_t *ctx) +int cipher_ctx_mode (const mbedtls_cipher_context_t *ctx) { ASSERT(NULL != ctx); @@ -510,12 +512,12 @@ cipher_ctx_get_cipher_kt (const cipher_ctx_t *ctx) return ctx ? ctx->cipher_info : NULL; } -int cipher_ctx_reset (cipher_context_t *ctx, uint8_t *iv_buf) +int cipher_ctx_reset (mbedtls_cipher_context_t *ctx, uint8_t *iv_buf) { - if (!polar_ok(cipher_reset(ctx))) + if (!mbed_ok(mbedtls_cipher_reset(ctx))) return 0; - if (!polar_ok(cipher_set_iv(ctx, iv_buf, ctx->cipher_info->iv_size))) + if (!mbed_ok(mbedtls_cipher_set_iv(ctx, iv_buf, ctx->cipher_info->iv_size))) return 0; return 1; @@ -527,7 +529,7 @@ int cipher_ctx_update_ad (cipher_ctx_t *ctx, const uint8_t *src, int src_len) if (src_len > SIZE_MAX) return 0; - if (!polar_ok (cipher_update_ad (ctx, src, src_len))) + if (!mbed_ok (mbedtls_cipher_update_ad (ctx, src, src_len))) return 0; return 1; @@ -536,12 +538,13 @@ int cipher_ctx_update_ad (cipher_ctx_t *ctx, const uint8_t *src, int src_len) #endif /* HAVE_AEAD_CIPHER_MODES */ } -int cipher_ctx_update (cipher_context_t *ctx, uint8_t *dst, int *dst_len, - uint8_t *src, int src_len) +int cipher_ctx_update (mbedtls_cipher_context_t *ctx, uint8_t *dst, + int *dst_len, uint8_t *src, int src_len) { size_t s_dst_len = *dst_len; - if (!polar_ok(cipher_update(ctx, src, (size_t)src_len, dst, &s_dst_len))) + if (!mbed_ok(mbedtls_cipher_update(ctx, src, (size_t) src_len, dst, + &s_dst_len))) return 0; *dst_len = s_dst_len; @@ -549,11 +552,11 @@ int cipher_ctx_update (cipher_context_t *ctx, uint8_t *dst, int *dst_len, return 1; } -int cipher_ctx_final (cipher_context_t *ctx, uint8_t *dst, int *dst_len) +int cipher_ctx_final (mbedtls_cipher_context_t *ctx, uint8_t *dst, int *dst_len) { size_t s_dst_len = *dst_len; - if (!polar_ok(cipher_finish(ctx, dst, &s_dst_len))) + if (!mbed_ok(mbedtls_cipher_finish(ctx, dst, &s_dst_len))) return 0; *dst_len = s_dst_len; @@ -561,23 +564,30 @@ int cipher_ctx_final (cipher_context_t *ctx, uint8_t *dst, int *dst_len) return 1; } -int cipher_ctx_final_check_tag (cipher_context_t *ctx, uint8_t *dst, +int cipher_ctx_final_check_tag (mbedtls_cipher_context_t *ctx, uint8_t *dst, int *dst_len, uint8_t *tag, size_t tag_len) { #ifdef HAVE_AEAD_CIPHER_MODES - if (POLARSSL_DECRYPT != ctx->operation) + size_t olen = 0; + + if (MBEDTLS_DECRYPT != ctx->operation) return 0; if (tag_len > SIZE_MAX) return 0; - if (!cipher_ctx_final (ctx, dst, dst_len)) + if (!mbed_ok (mbedtls_cipher_finish (ctx, dst, &olen))) { msg (D_CRYPT_ERRORS, "%s: cipher_ctx_final() failed", __func__); return 0; } - if (!polar_ok (cipher_check_tag (ctx, (const unsigned char *) tag, tag_len))) + if (olen > INT_MAX) + return 0; + *dst_len = olen; + + if (!mbed_ok (mbedtls_cipher_check_tag (ctx, (const unsigned char *) tag, + tag_len))) return 0; return 1; @@ -591,10 +601,10 @@ cipher_des_encrypt_ecb (const unsigned char key[DES_KEY_LENGTH], unsigned char *src, unsigned char *dst) { - des_context ctx; + mbedtls_des_context ctx; - ASSERT (polar_ok(des_setkey_enc(&ctx, key))); - ASSERT (polar_ok(des_crypt_ecb(&ctx, src, dst))); + ASSERT (mbed_ok(mbedtls_des_setkey_enc(&ctx, key))); + ASSERT (mbed_ok(mbedtls_des_crypt_ecb(&ctx, src, dst))); } @@ -606,37 +616,37 @@ cipher_des_encrypt_ecb (const unsigned char key[DES_KEY_LENGTH], */ -const md_info_t * +const mbedtls_md_info_t * md_kt_get (const char *digest) { - const md_info_t *md = NULL; + const mbedtls_md_info_t *md = NULL; ASSERT (digest); - md = md_info_from_string(digest); + md = mbedtls_md_info_from_string(digest); if (!md) msg (M_FATAL, "Message hash algorithm '%s' not found", digest); - if (md_get_size(md) > MAX_HMAC_KEY_LENGTH) + if (mbedtls_md_get_size(md) > MAX_HMAC_KEY_LENGTH) msg (M_FATAL, "Message hash algorithm '%s' uses a default hash size (%d bytes) which is larger than " PACKAGE_NAME "'s current maximum hash size (%d bytes)", digest, - md_get_size(md), + mbedtls_md_get_size(md), MAX_HMAC_KEY_LENGTH); return md; } const char * -md_kt_name (const md_info_t *kt) +md_kt_name (const mbedtls_md_info_t *kt) { if (NULL == kt) return "[null-digest]"; - return md_get_name (kt); + return mbedtls_md_get_name (kt); } int -md_kt_size (const md_info_t *kt) +md_kt_size (const mbedtls_md_info_t *kt) { if (NULL == kt) return 0; - return md_get_size(kt); + return mbedtls_md_get_size(kt); } /* @@ -648,45 +658,44 @@ md_kt_size (const md_info_t *kt) int md_full (const md_kt_t *kt, const uint8_t *src, int src_len, uint8_t *dst) { - return 0 == md(kt, src, src_len, dst); + return 0 == mbedtls_md(kt, src, src_len, dst); } void -md_ctx_init (md_context_t *ctx, const md_info_t *kt) +md_ctx_init (mbedtls_md_context_t *ctx, const mbedtls_md_info_t *kt) { ASSERT(NULL != ctx && NULL != kt); - CLEAR(*ctx); - - ASSERT(0 == md_init_ctx(ctx, kt)); - ASSERT(0 == md_starts(ctx)); + mbedtls_md_init(ctx); + ASSERT(0 == mbedtls_md_setup(ctx, kt, 0)); + ASSERT(0 == mbedtls_md_starts(ctx)); } void -md_ctx_cleanup(md_context_t *ctx) +md_ctx_cleanup(mbedtls_md_context_t *ctx) { } int -md_ctx_size (const md_context_t *ctx) +md_ctx_size (const mbedtls_md_context_t *ctx) { if (NULL == ctx) return 0; - return md_get_size(ctx->md_info); + return mbedtls_md_get_size(ctx->md_info); } void -md_ctx_update (md_context_t *ctx, const uint8_t *src, int src_len) +md_ctx_update (mbedtls_md_context_t *ctx, const uint8_t *src, int src_len) { - ASSERT(0 == md_update(ctx, src, src_len)); + ASSERT(0 == mbedtls_md_update(ctx, src, src_len)); } void -md_ctx_final (md_context_t *ctx, uint8_t *dst) +md_ctx_final (mbedtls_md_context_t *ctx, uint8_t *dst) { - ASSERT(0 == md_finish(ctx, dst)); - md_free(ctx); + ASSERT(0 == mbedtls_md_finish(ctx, dst)); + mbedtls_md_free(ctx); } @@ -701,49 +710,49 @@ md_ctx_final (md_context_t *ctx, uint8_t *dst) * TODO: re-enable dmsg for crypto debug */ void -hmac_ctx_init (md_context_t *ctx, const uint8_t *key, int key_len, const md_info_t *kt) +hmac_ctx_init (mbedtls_md_context_t *ctx, const uint8_t *key, int key_len, + const mbedtls_md_info_t *kt) { ASSERT(NULL != kt && NULL != ctx); - CLEAR(*ctx); - - ASSERT(0 == md_init_ctx(ctx, kt)); - ASSERT(0 == md_hmac_starts(ctx, key, key_len)); + mbedtls_md_init(ctx); + ASSERT(0 == mbedtls_md_setup(ctx, kt, 1)); + ASSERT(0 == mbedtls_md_hmac_starts(ctx, key, key_len)); /* make sure we used a big enough key */ - ASSERT (md_get_size(kt) <= key_len); + ASSERT (mbedtls_md_get_size(kt) <= key_len); } void -hmac_ctx_cleanup(md_context_t *ctx) +hmac_ctx_cleanup(mbedtls_md_context_t *ctx) { - md_free(ctx); + mbedtls_md_free(ctx); } int -hmac_ctx_size (const md_context_t *ctx) +hmac_ctx_size (const mbedtls_md_context_t *ctx) { if (NULL == ctx) return 0; - return md_get_size(ctx->md_info); + return mbedtls_md_get_size(ctx->md_info); } void -hmac_ctx_reset (md_context_t *ctx) +hmac_ctx_reset (mbedtls_md_context_t *ctx) { - ASSERT(0 == md_hmac_reset(ctx)); + ASSERT(0 == mbedtls_md_hmac_reset(ctx)); } void -hmac_ctx_update (md_context_t *ctx, const uint8_t *src, int src_len) +hmac_ctx_update (mbedtls_md_context_t *ctx, const uint8_t *src, int src_len) { - ASSERT(0 == md_hmac_update(ctx, src, src_len)); + ASSERT(0 == mbedtls_md_hmac_update(ctx, src, src_len)); } void -hmac_ctx_final (md_context_t *ctx, uint8_t *dst) +hmac_ctx_final (mbedtls_md_context_t *ctx, uint8_t *dst) { - ASSERT(0 == md_hmac_finish(ctx, dst)); + ASSERT(0 == mbedtls_md_hmac_finish(ctx, dst)); } -#endif /* ENABLE_CRYPTO && ENABLE_CRYPTO_POLARSSL */ +#endif /* ENABLE_CRYPTO && ENABLE_CRYPTO_MBEDTLS */ diff --git a/src/openvpn/crypto_polarssl.h b/src/openvpn/crypto_polarssl.h index 7be0862424b..574a63f127b 100644 --- a/src/openvpn/crypto_polarssl.h +++ b/src/openvpn/crypto_polarssl.h @@ -24,51 +24,51 @@ */ /** - * @file Data Channel Cryptography PolarSSL-specific backend interface + * @file Data Channel Cryptography mbed TLS-specific backend interface */ -#ifndef CRYPTO_POLARSSL_H_ -#define CRYPTO_POLARSSL_H_ +#ifndef CRYPTO_MBEDTLS_H_ +#define CRYPTO_MBEDTLS_H_ -#include -#include -#include +#include +#include +#include /** Generic cipher key type %context. */ -typedef cipher_info_t cipher_kt_t; +typedef mbedtls_cipher_info_t cipher_kt_t; /** Generic message digest key type %context. */ -typedef md_info_t md_kt_t; +typedef mbedtls_md_info_t md_kt_t; /** Generic cipher %context. */ -typedef cipher_context_t cipher_ctx_t; +typedef mbedtls_cipher_context_t cipher_ctx_t; /** Generic message digest %context. */ -typedef md_context_t md_ctx_t; +typedef mbedtls_md_context_t md_ctx_t; /** Generic HMAC %context. */ -typedef md_context_t hmac_ctx_t; +typedef mbedtls_md_context_t hmac_ctx_t; /** Maximum length of an IV */ -#define OPENVPN_MAX_IV_LENGTH POLARSSL_MAX_IV_LENGTH +#define OPENVPN_MAX_IV_LENGTH MBEDTLS_MAX_IV_LENGTH /** Cipher is in CBC mode */ -#define OPENVPN_MODE_CBC POLARSSL_MODE_CBC +#define OPENVPN_MODE_CBC MBEDTLS_MODE_CBC /** Cipher is in OFB mode */ -#define OPENVPN_MODE_OFB POLARSSL_MODE_OFB +#define OPENVPN_MODE_OFB MBEDTLS_MODE_OFB /** Cipher is in CFB mode */ -#define OPENVPN_MODE_CFB POLARSSL_MODE_CFB +#define OPENVPN_MODE_CFB MBEDTLS_MODE_CFB /** Cipher is in GCM mode */ -#define OPENVPN_MODE_GCM POLARSSL_MODE_GCM +#define OPENVPN_MODE_GCM MBEDTLS_MODE_GCM /** Cipher should encrypt */ -#define OPENVPN_OP_ENCRYPT POLARSSL_ENCRYPT +#define OPENVPN_OP_ENCRYPT MBEDTLS_ENCRYPT /** Cipher should decrypt */ -#define OPENVPN_OP_DECRYPT POLARSSL_DECRYPT +#define OPENVPN_OP_DECRYPT MBEDTLS_DECRYPT #define MD4_DIGEST_LENGTH 16 #define MD5_DIGEST_LENGTH 16 @@ -76,16 +76,16 @@ typedef md_context_t hmac_ctx_t; #define DES_KEY_LENGTH 8 /** - * Returns a singleton instance of the PolarSSL random number generator. + * Returns a singleton instance of the mbed TLS random number generator. * - * For PolarSSL 1.1+, this is the CTR_DRBG random number generator. If it + * For PolarSSL/mbed TLS 1.1+, this is the CTR_DRBG random number generator. If it * hasn't been initialised yet, the RNG will be initialised using the default * entropy sources. Aside from the default platform entropy sources, an * additional entropy source, the HAVEGE random number generator will also be * added. During initialisation, a personalisation string will be added based * on the time, the PID, and a pointer to the random context. */ -ctr_drbg_context * rand_ctx_get(); +mbedtls_ctr_drbg_context *rand_ctx_get(); #ifdef ENABLE_PREDICTION_RESISTANCE /** @@ -95,34 +95,34 @@ void rand_ctx_enable_prediction_resistance(); #endif /** - * Log the supplied PolarSSL error, prefixed by supplied prefix. + * Log the supplied mbed TLS error, prefixed by supplied prefix. * * @param flags Flags to indicate error type and priority. - * @param errval PolarSSL error code to convert to error message. - * @param prefix Prefix to PolarSSL error message. + * @param errval mbed TLS error code to convert to error message. + * @param prefix Prefix to mbed TLS error message. * * @returns true if no errors are detected, false otherwise. */ -bool polar_log_err(unsigned int flags, int errval, const char *prefix); +bool mbed_log_err(unsigned int flags, int errval, const char *prefix); /** - * Log the supplied PolarSSL error, prefixed by function name and line number. + * Log the supplied mbed TLS error, prefixed by function name and line number. * * @param flags Flags to indicate error type and priority. - * @param errval PolarSSL error code to convert to error message. + * @param errval mbed TLS error code to convert to error message. * @param func Function name where error was reported. * @param line Line number where error was reported. * * @returns true if no errors are detected, false otherwise. */ -bool polar_log_func_line(unsigned int flags, int errval, const char *func, +bool mbed_log_func_line(unsigned int flags, int errval, const char *func, int line); -/** Wraps polar_log_func_line() to prevent function calls for non-errors */ -static inline bool polar_log_func_line_lite(unsigned int flags, int errval, +/** Wraps mbed_log_func_line() to prevent function calls for non-errors */ +static inline bool mbed_log_func_line_lite(unsigned int flags, int errval, const char *func, int line) { if (errval) { - return polar_log_func_line (flags, errval, func, line); + return mbed_log_func_line (flags, errval, func, line); } return true; } @@ -130,17 +130,17 @@ static inline bool polar_log_func_line_lite(unsigned int flags, int errval, /** * Check errval and log on error. * - * Convenience wrapper to put around polarssl library calls, e.g. - * if (!polar_ok(polarssl_func())) return 0; + * Convenience wrapper to put around mbed TLS library calls, e.g. + * if (!mbed_ok (mbedtls_ssl_func())) return 0; * or - * ASSERT (polar_ok(polarssl_func())); + * ASSERT (mbed_ok (mbedtls_ssl_func())); * - * @param errval PolarSSL error code to convert to error message. + * @param errval mbed TLS error code to convert to error message. * * @returns true if no errors are detected, false otherwise. */ -#define polar_ok(errval) \ - polar_log_func_line_lite(D_CRYPT_ERRORS, errval, __func__, __LINE__) +#define mbed_ok(errval) \ + mbed_log_func_line_lite(D_CRYPT_ERRORS, errval, __func__, __LINE__) -#endif /* CRYPTO_POLARSSL_H_ */ +#endif /* CRYPTO_MBEDTLS_H_ */ diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 564e706020e..764ca7407ba 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -68,13 +68,13 @@ const char title_string[] = #endif " " TARGET_ALIAS #ifdef ENABLE_CRYPTO -#if defined(ENABLE_CRYPTO_POLARSSL) - " [SSL (PolarSSL)]" +#if defined(ENABLE_CRYPTO_MBEDTLS) + " [SSL (mbed TLS)]" #elif defined(ENABLE_CRYPTO_OPENSSL) " [SSL (OpenSSL)]" #else " [SSL]" -#endif /* defined(ENABLE_CRYPTO_POLARSSL) */ +#endif /* defined(ENABLE_CRYPTO_MBEDTLS) */ #endif /* ENABLE_CRYPTO */ #ifdef USE_COMP #ifdef ENABLE_LZO @@ -524,7 +524,7 @@ static const char usage_message[] = "--keysize n : Size of cipher key in bits (optional).\n" " If unspecified, defaults to cipher-specific default.\n" #endif -#ifndef ENABLE_CRYPTO_POLARSSL +#ifndef ENABLE_CRYPTO_MBEDTLS "--engine [name] : Enable OpenSSL hardware crypto engine functionality.\n" #endif "--no-replay : Disable replay protection.\n" @@ -550,10 +550,10 @@ static const char usage_message[] = " number, such as 1 (default), 2, etc.\n" "--ca file : Certificate authority file in .pem format containing\n" " root certificate.\n" -#ifndef ENABLE_CRYPTO_POLARSSL +#ifndef ENABLE_CRYPTO_MBEDTLS "--capath dir : A directory of trusted certificates (CAs" " and CRLs).\n" -#endif /* ENABLE_CRYPTO_POLARSSL */ +#endif /* ENABLE_CRYPTO_MBEDTLS */ "--dh file : File containing Diffie Hellman parameters\n" " in .pem format (for --tls-server only).\n" " Use \"openssl dhparam -out dh1024.pem 1024\" to generate.\n" @@ -565,7 +565,7 @@ static const char usage_message[] = " will accept from the peer. If version is unrecognized and 'or-highest'\n" " is specified, require max TLS version supported by SSL implementation.\n" "--tls-version-max : sets the maximum TLS version we will use.\n" -#ifndef ENABLE_CRYPTO_POLARSSL +#ifndef ENABLE_CRYPTO_MBEDTLS "--pkcs12 file : PKCS#12 file containing local private key, local certificate\n" " and optionally the root CA certificate.\n" #endif @@ -1569,9 +1569,9 @@ show_settings (const struct options *o) SHOW_STR (prng_hash); SHOW_INT (prng_nonce_secret_len); SHOW_INT (keysize); -#ifndef ENABLE_CRYPTO_POLARSSL +#ifndef ENABLE_CRYPTO_MBEDTLS SHOW_BOOL (engine); -#endif /* ENABLE_CRYPTO_POLARSSL */ +#endif /* ENABLE_CRYPTO_MBEDTLS */ SHOW_BOOL (replay); SHOW_BOOL (mute_replay_warnings); SHOW_INT (replay_window); @@ -1603,7 +1603,7 @@ show_settings (const struct options *o) else #endif SHOW_STR (priv_key_file); -#ifndef ENABLE_CRYPTO_POLARSSL +#ifndef ENABLE_CRYPTO_MBEDTLS SHOW_STR (pkcs12_file); #endif #ifdef ENABLE_CRYPTOAPI @@ -2216,8 +2216,8 @@ options_postprocess_verify_ce (const struct options *options, const struct conne #endif if (options->pkcs12_file) { -#ifdef ENABLE_CRYPTO_POLARSSL - msg(M_USAGE, "Parameter --pkcs12 cannot be used with the PolarSSL version version of OpenVPN."); +#ifdef ENABLE_CRYPTO_MBEDTLS + msg(M_USAGE, "Parameter --pkcs12 cannot be used with the mbed TLS version version of OpenVPN."); #else if (options->ca_path) msg(M_USAGE, "Parameter --capath cannot be used when --pkcs12 is also specified."); @@ -2235,11 +2235,11 @@ options_postprocess_verify_ce (const struct options *options, const struct conne } else { -#ifdef ENABLE_CRYPTO_POLARSSL +#ifdef ENABLE_CRYPTO_MBEDTLS if (!(options->ca_file)) msg(M_USAGE, "You must define CA file (--ca)"); if (options->ca_path) - msg(M_USAGE, "Parameter --capath cannot be used with the PolarSSL version version of OpenVPN."); + msg(M_USAGE, "Parameter --capath cannot be used with the mbed TLS version version of OpenVPN."); #else if ((!(options->ca_file)) && (!(options->ca_path))) msg(M_USAGE, "You must define CA file (--ca) or CA path (--capath)"); @@ -2298,7 +2298,7 @@ options_postprocess_verify_ce (const struct options *options, const struct conne MUST_BE_UNDEF (dh_file); MUST_BE_UNDEF (cert_file); MUST_BE_UNDEF (priv_key_file); -#ifndef ENABLE_CRYPTO_POLARSSL +#ifndef ENABLE_CRYPTO_MBEDTLS MUST_BE_UNDEF (pkcs12_file); #endif MUST_BE_UNDEF (cipher_list); @@ -6566,7 +6566,7 @@ add_option (struct options *options, VERIFY_PERMISSION (OPT_P_GENERAL); options->test_crypto = true; } -#ifndef ENABLE_CRYPTO_POLARSSL +#ifndef ENABLE_CRYPTO_MBEDTLS else if (streq (p[0], "engine") && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); @@ -6577,7 +6577,7 @@ add_option (struct options *options, else options->engine = "auto"; } -#endif /* ENABLE_CRYPTO_POLARSSL */ +#endif /* ENABLE_CRYPTO_MBEDTLS */ #ifdef HAVE_EVP_CIPHER_CTX_SET_KEY_LENGTH else if (streq (p[0], "keysize") && p[1] && !p[2]) { @@ -6634,13 +6634,13 @@ add_option (struct options *options, options->ca_file_inline = p[2]; } } -#ifndef ENABLE_CRYPTO_POLARSSL +#ifndef ENABLE_CRYPTO_MBEDTLS else if (streq (p[0], "capath") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); options->ca_path = p[1]; } -#endif /* ENABLE_CRYPTO_POLARSSL */ +#endif /* ENABLE_CRYPTO_MBEDTLS */ else if (streq (p[0], "dh") && p[1] && ((streq (p[1], INLINE_FILE_TAG) && p[2]) || !p[2]) && !p[3]) { VERIFY_PERMISSION (OPT_P_GENERAL); @@ -6717,7 +6717,7 @@ add_option (struct options *options, ~(SSLF_TLS_VERSION_MAX_MASK << SSLF_TLS_VERSION_MAX_SHIFT); options->ssl_flags |= (ver << SSLF_TLS_VERSION_MAX_SHIFT); } -#ifndef ENABLE_CRYPTO_POLARSSL +#ifndef ENABLE_CRYPTO_MBEDTLS else if (streq (p[0], "pkcs12") && p[1] && ((streq (p[1], INLINE_FILE_TAG) && p[2]) || !p[2]) && !p[3]) { VERIFY_PERMISSION (OPT_P_GENERAL); @@ -6727,7 +6727,7 @@ add_option (struct options *options, options->pkcs12_file_inline = p[2]; } } -#endif /* ENABLE_CRYPTO_POLARSSL */ +#endif /* ENABLE_CRYPTO_MBEDTLS */ else if (streq (p[0], "askpass") && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); @@ -6795,7 +6795,7 @@ add_option (struct options *options, string_substitute (p[1], ',', ' ', &options->gc), "tls-verify", true); } -#ifndef ENABLE_CRYPTO_POLARSSL +#ifndef ENABLE_CRYPTO_MBEDTLS else if (streq (p[0], "tls-export-cert") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); diff --git a/src/openvpn/options.h b/src/openvpn/options.h index ffbe5e11bbe..18d8376a378 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -78,8 +78,8 @@ struct options_pre_pull }; #endif -#if defined(ENABLE_CRYPTO) && !defined(ENABLE_CRYPTO_OPENSSL) && !defined(ENABLE_CRYPTO_POLARSSL) -# error "At least one of OpenSSL or PolarSSL needs to be defined." +#if defined(ENABLE_CRYPTO) && !defined(ENABLE_CRYPTO_OPENSSL) && !defined(ENABLE_CRYPTO_MBEDTLS) +# error "At least one of OpenSSL or mbed TLS needs to be defined." #endif struct connection_entry diff --git a/src/openvpn/pkcs11_polarssl.c b/src/openvpn/pkcs11_polarssl.c index ccb6f8caf40..e208b61f1ab 100644 --- a/src/openvpn/pkcs11_polarssl.c +++ b/src/openvpn/pkcs11_polarssl.c @@ -24,7 +24,7 @@ */ /** - * @file PKCS #11 PolarSSL backend + * @file PKCS #11 mbed TLS backend */ #ifdef HAVE_CONFIG_H @@ -35,12 +35,12 @@ #include "syshead.h" -#if defined(ENABLE_PKCS11) && defined(ENABLE_CRYPTO_POLARSSL) +#if defined(ENABLE_PKCS11) && defined(ENABLE_CRYPTO_MBEDTLS) #include "errlevel.h" #include "pkcs11_backend.h" -#include -#include +#include +#include int pkcs11_init_tls_session(pkcs11h_certificate_t certificate, @@ -50,21 +50,22 @@ pkcs11_init_tls_session(pkcs11h_certificate_t certificate, ASSERT (NULL != ssl_ctx); - ALLOC_OBJ_CLEAR (ssl_ctx->crt_chain, x509_crt); - if (pkcs11_x509_cert_init(ssl_ctx->crt_chain, certificate)) { - msg (M_FATAL, "PKCS#11: Cannot retrieve PolarSSL certificate object"); + ALLOC_OBJ_CLEAR (ssl_ctx->crt_chain, mbedtls_x509_crt); + if (mbedtls_pkcs11_x509_cert_bind(ssl_ctx->crt_chain, certificate)) { + msg (M_FATAL, "PKCS#11: Cannot retrieve mbed TLS certificate object"); goto cleanup; } - ALLOC_OBJ_CLEAR (ssl_ctx->priv_key_pkcs11, pkcs11_context); - if (pkcs11_priv_key_init(ssl_ctx->priv_key_pkcs11, certificate)) { - msg (M_FATAL, "PKCS#11: Cannot initialize PolarSSL private key object"); + ALLOC_OBJ_CLEAR (ssl_ctx->priv_key_pkcs11, mbedtls_pkcs11_context); + if (mbedtls_pkcs11_priv_key_bind(ssl_ctx->priv_key_pkcs11, certificate)) { + msg (M_FATAL, "PKCS#11: Cannot initialize mbed TLS private key object"); goto cleanup; } - ALLOC_OBJ_CLEAR (ssl_ctx->priv_key, pk_context); - if (!polar_ok(pk_init_ctx_rsa_alt(ssl_ctx->priv_key, ssl_ctx->priv_key_pkcs11, - ssl_pkcs11_decrypt, ssl_pkcs11_sign, ssl_pkcs11_key_len))) { + ALLOC_OBJ_CLEAR (ssl_ctx->priv_key, mbedtls_pk_context); + if (!mbed_ok(mbedtls_pk_setup_rsa_alt(ssl_ctx->priv_key, + ssl_ctx->priv_key_pkcs11, mbedtls_ssl_pkcs11_decrypt, + mbedtls_ssl_pkcs11_sign, mbedtls_ssl_pkcs11_key_len))) { goto cleanup; } @@ -80,22 +81,22 @@ pkcs11_certificate_dn (pkcs11h_certificate_t cert, struct gc_arena *gc) char *ret = NULL; char dn[1024] = {0}; - x509_crt polar_cert = {0}; + mbedtls_x509_crt mbed_crt = {0}; - if (pkcs11_x509_cert_init(&polar_cert, cert)) { - msg (M_FATAL, "PKCS#11: Cannot retrieve PolarSSL certificate object"); + if (mbedtls_pkcs11_x509_cert_bind(&mbed_crt, cert)) { + msg (M_FATAL, "PKCS#11: Cannot retrieve mbed TLS certificate object"); goto cleanup; } - if (-1 == x509_dn_gets (dn, sizeof(dn), &polar_cert.subject)) { - msg (M_FATAL, "PKCS#11: PolarSSL cannot parse subject"); + if (-1 == mbedtls_x509_dn_gets (dn, sizeof(dn), &mbed_crt.subject)) { + msg (M_FATAL, "PKCS#11: mbed TLS cannot parse subject"); goto cleanup; } ret = string_alloc(dn, gc); cleanup: - x509_crt_free(&polar_cert); + mbedtls_x509_crt_free(&mbed_crt); return ret; } @@ -106,23 +107,23 @@ pkcs11_certificate_serial (pkcs11h_certificate_t cert, char *serial, { int ret = 1; - x509_crt polar_cert = {0}; + mbedtls_x509_crt mbed_crt = {0}; - if (pkcs11_x509_cert_init(&polar_cert, cert)) { - msg (M_FATAL, "PKCS#11: Cannot retrieve PolarSSL certificate object"); + if (mbedtls_pkcs11_x509_cert_bind(&mbed_crt, cert)) { + msg (M_FATAL, "PKCS#11: Cannot retrieve mbed TLS certificate object"); goto cleanup; } - if (-1 == x509_serial_gets (serial, serial_len, &polar_cert.serial)) { - msg (M_FATAL, "PKCS#11: PolarSSL cannot parse serial"); + if (-1 == mbedtls_x509_serial_gets (serial, serial_len, &mbed_crt.serial)) { + msg (M_FATAL, "PKCS#11: mbed TLS cannot parse serial"); goto cleanup; } ret = 0; cleanup: - x509_crt_free(&polar_cert); + mbedtls_x509_crt_free(&mbed_crt); return ret; } -#endif /* defined(ENABLE_PKCS11) && defined(ENABLE_CRYPTO_POLARSSL) */ +#endif /* defined(ENABLE_PKCS11) && defined(ENABLE_CRYPTO_MBEDTLS) */ diff --git a/src/openvpn/plugin.h b/src/openvpn/plugin.h index 77b6e818e00..74ac8b1e566 100644 --- a/src/openvpn/plugin.h +++ b/src/openvpn/plugin.h @@ -32,7 +32,7 @@ #ifdef ENABLE_CRYPTO_OPENSSL #include "ssl_verify_openssl.h" #endif -#ifdef ENABLE_CRYPTO_POLARSSL +#ifdef ENABLE_CRYPTO_MBEDTLS #include "ssl_verify_polarssl.h" #endif #include "openvpn-plugin.h" diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index d1a6fa83b6a..ddd0c9bc502 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -591,7 +591,7 @@ init_ssl (const struct options *options, struct tls_root_ctx *new_ctx) /* Allowable ciphers */ tls_ctx_restrict_ciphers(new_ctx, options->cipher_list); -#ifdef ENABLE_CRYPTO_POLARSSL +#ifdef ENABLE_CRYPTO_MBEDTLS /* Personalise the random by mixing in the certificate */ tls_ctx_personalise_random (new_ctx); #endif diff --git a/src/openvpn/ssl_backend.h b/src/openvpn/ssl_backend.h index ac28f5fefd6..dfccb4472cd 100644 --- a/src/openvpn/ssl_backend.h +++ b/src/openvpn/ssl_backend.h @@ -38,10 +38,10 @@ #include "ssl_verify_openssl.h" #define SSLAPI SSLAPI_OPENSSL #endif -#ifdef ENABLE_CRYPTO_POLARSSL +#ifdef ENABLE_CRYPTO_MBEDTLS #include "ssl_polarssl.h" #include "ssl_verify_polarssl.h" -#define SSLAPI SSLAPI_POLARSSL +#define SSLAPI SSLAPI_MBEDTLS #endif /* Ensure that SSLAPI got a sane value if SSL is disabled or unknown */ @@ -308,9 +308,9 @@ void tls_ctx_load_extra_certs (struct tls_root_ctx *ctx, const char *extra_certs const char *extra_certs_file_inline ); -#ifdef ENABLE_CRYPTO_POLARSSL +#ifdef ENABLE_CRYPTO_MBEDTLS /** - * Add a personalisation string to the PolarSSL RNG, based on the certificate + * Add a personalisation string to the mbed TLS RNG, based on the certificate * loaded into the given context. * * @param ctx TLS context to use diff --git a/src/openvpn/ssl_polarssl.c b/src/openvpn/ssl_polarssl.c index 58b211648c8..483ec1cd38a 100644 --- a/src/openvpn/ssl_polarssl.c +++ b/src/openvpn/ssl_polarssl.c @@ -25,7 +25,7 @@ */ /** - * @file Control Channel PolarSSL Backend + * @file Control Channel mbed TLS Backend */ #ifdef HAVE_CONFIG_H @@ -36,7 +36,7 @@ #include "syshead.h" -#if defined(ENABLE_CRYPTO) && defined(ENABLE_CRYPTO_POLARSSL) +#if defined(ENABLE_CRYPTO) && defined(ENABLE_CRYPTO_MBEDTLS) #include "errlevel.h" #include "ssl_backend.h" @@ -46,15 +46,16 @@ #include "manage.h" #include "ssl_common.h" -#include +#include #include "ssl_verify_polarssl.h" -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include void tls_init_lib() @@ -77,11 +78,11 @@ tls_ctx_server_new(struct tls_root_ctx *ctx) ASSERT(NULL != ctx); CLEAR(*ctx); - ALLOC_OBJ_CLEAR(ctx->dhm_ctx, dhm_context); + ALLOC_OBJ_CLEAR(ctx->dhm_ctx, mbedtls_dhm_context); - ALLOC_OBJ_CLEAR(ctx->ca_chain, x509_crt); + ALLOC_OBJ_CLEAR(ctx->ca_chain, mbedtls_x509_crt); - ctx->endpoint = SSL_IS_SERVER; + ctx->endpoint = MBEDTLS_SSL_IS_SERVER; ctx->initialised = true; } @@ -91,10 +92,10 @@ tls_ctx_client_new(struct tls_root_ctx *ctx) ASSERT(NULL != ctx); CLEAR(*ctx); - ALLOC_OBJ_CLEAR(ctx->dhm_ctx, dhm_context); - ALLOC_OBJ_CLEAR(ctx->ca_chain, x509_crt); + ALLOC_OBJ_CLEAR(ctx->dhm_ctx, mbedtls_dhm_context); + ALLOC_OBJ_CLEAR(ctx->ca_chain, mbedtls_x509_crt); - ctx->endpoint = SSL_IS_CLIENT; + ctx->endpoint = MBEDTLS_SSL_IS_CLIENT; ctx->initialised = true; } @@ -103,25 +104,25 @@ tls_ctx_free(struct tls_root_ctx *ctx) { if (ctx) { - pk_free(ctx->priv_key); + mbedtls_pk_free(ctx->priv_key); if (ctx->priv_key) free(ctx->priv_key); - x509_crt_free(ctx->ca_chain); + mbedtls_x509_crt_free(ctx->ca_chain); if (ctx->ca_chain) free(ctx->ca_chain); - x509_crt_free(ctx->crt_chain); + mbedtls_x509_crt_free(ctx->crt_chain); if (ctx->crt_chain) free(ctx->crt_chain); - dhm_free(ctx->dhm_ctx); + mbedtls_dhm_free(ctx->dhm_ctx); if (ctx->dhm_ctx) free(ctx->dhm_ctx); #if defined(ENABLE_PKCS11) if (ctx->priv_key_pkcs11 != NULL) { - pkcs11_priv_key_free(ctx->priv_key_pkcs11); + mbedtls_pkcs11_priv_key_free(ctx->priv_key_pkcs11); free(ctx->priv_key_pkcs11); } #endif @@ -207,7 +208,7 @@ tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers) token = strtok (tmp_ciphers, ":"); while(token) { - ctx->allowed_ciphers[i] = ssl_get_ciphersuite_id ( + ctx->allowed_ciphers[i] = mbedtls_ssl_get_ciphersuite_id ( tls_translate_cipher_name (token)); if (0 != ctx->allowed_ciphers[i]) i++; @@ -225,12 +226,12 @@ tls_ctx_check_cert_time (const struct tls_root_ctx *ctx) return; /* Nothing to check if there is no certificate */ } - if (x509_time_future (&ctx->crt_chain->valid_from)) + if (mbedtls_x509_time_is_future (&ctx->crt_chain->valid_from)) { msg (M_WARN, "WARNING: Your certificate is not yet valid!"); } - if (x509_time_expired (&ctx->crt_chain->valid_to)) + if (mbedtls_x509_time_is_past (&ctx->crt_chain->valid_to)) { msg (M_WARN, "WARNING: Your certificate has expired!"); } @@ -243,18 +244,18 @@ tls_ctx_load_dh_params (struct tls_root_ctx *ctx, const char *dh_file, { if (!strcmp (dh_file, INLINE_FILE_TAG) && dh_inline) { - if (!polar_ok(dhm_parse_dhm(ctx->dhm_ctx, - (const unsigned char *) dh_inline, strlen(dh_inline)))) + if (!mbed_ok(mbedtls_dhm_parse_dhm(ctx->dhm_ctx, + (const unsigned char *) dh_inline, strlen(dh_inline)+1))) msg (M_FATAL, "Cannot read inline DH parameters"); } else { - if (!polar_ok(dhm_parse_dhmfile(ctx->dhm_ctx, dh_file))) + if (!mbed_ok(mbedtls_dhm_parse_dhmfile(ctx->dhm_ctx, dh_file))) msg (M_FATAL, "Cannot read DH parameters from file %s", dh_file); } msg (D_TLS_DEBUG_LOW, "Diffie-Hellman initialized with " counter_format " bit key", - (counter_type) 8 * mpi_size(&ctx->dhm_ctx->P)); + (counter_type) 8 * mbedtls_mpi_size(&ctx->dhm_ctx->P)); } void @@ -262,7 +263,7 @@ tls_ctx_load_ecdh_params (struct tls_root_ctx *ctx, const char *curve_name ) { if (NULL != curve_name) - msg(M_WARN, "WARNING: PolarSSL builds do not support specifying an ECDH " + msg(M_WARN, "WARNING: mbed TLS builds do not support specifying an ECDH " "curve, using default curves."); } @@ -272,7 +273,7 @@ tls_ctx_load_pkcs12(struct tls_root_ctx *ctx, const char *pkcs12_file, bool load_ca_file ) { - msg(M_FATAL, "PKCS #12 files not yet supported for PolarSSL."); + msg(M_FATAL, "PKCS #12 files not yet supported for mbed TLS."); return 0; } @@ -280,7 +281,7 @@ tls_ctx_load_pkcs12(struct tls_root_ctx *ctx, const char *pkcs12_file, void tls_ctx_load_cryptoapi(struct tls_root_ctx *ctx, const char *cryptoapi_cert) { - msg(M_FATAL, "Windows CryptoAPI not yet supported for PolarSSL."); + msg(M_FATAL, "Windows CryptoAPI not yet supported for mbed TLS."); } #endif /* WIN32 */ @@ -293,18 +294,18 @@ tls_ctx_load_cert_file (struct tls_root_ctx *ctx, const char *cert_file, if (!ctx->crt_chain) { - ALLOC_OBJ_CLEAR(ctx->crt_chain, x509_crt); + ALLOC_OBJ_CLEAR(ctx->crt_chain, mbedtls_x509_crt); } if (!strcmp (cert_file, INLINE_FILE_TAG) && cert_inline) { - if (!polar_ok(x509_crt_parse(ctx->crt_chain, - (const unsigned char *) cert_inline, strlen(cert_inline)))) + if (!mbed_ok(mbedtls_x509_crt_parse(ctx->crt_chain, + (const unsigned char *) cert_inline, strlen(cert_inline)+1))) msg (M_FATAL, "Cannot load inline certificate file"); } else { - if (!polar_ok(x509_crt_parse_file(ctx->crt_chain, cert_file))) + if (!mbed_ok(mbedtls_x509_crt_parse_file(ctx->crt_chain, cert_file))) { msg (M_FATAL, "Cannot load certificate file %s", cert_file); } @@ -321,38 +322,39 @@ tls_ctx_load_priv_file (struct tls_root_ctx *ctx, const char *priv_key_file, if (!ctx->priv_key) { - ALLOC_OBJ_CLEAR(ctx->priv_key, pk_context); + ALLOC_OBJ_CLEAR(ctx->priv_key, mbedtls_pk_context); } if (!strcmp (priv_key_file, INLINE_FILE_TAG) && priv_key_inline) { - status = pk_parse_key(ctx->priv_key, - (const unsigned char *) priv_key_inline, strlen(priv_key_inline), + status = mbedtls_pk_parse_key(ctx->priv_key, + (const unsigned char *) priv_key_inline, strlen(priv_key_inline)+1, NULL, 0); - if (POLARSSL_ERR_PK_PASSWORD_REQUIRED == status) + if (MBEDTLS_ERR_PK_PASSWORD_REQUIRED == status) { char passbuf[512] = {0}; pem_password_callback(passbuf, 512, 0, NULL); - status = pk_parse_key(ctx->priv_key, - (const unsigned char *) priv_key_inline, strlen(priv_key_inline), - (unsigned char *) passbuf, strlen(passbuf)); + status = mbedtls_pk_parse_key(ctx->priv_key, + (const unsigned char *) priv_key_inline, + strlen(priv_key_inline)+1, (unsigned char *) passbuf, + strlen(passbuf)); } } else { - status = pk_parse_keyfile(ctx->priv_key, priv_key_file, NULL); - if (POLARSSL_ERR_PK_PASSWORD_REQUIRED == status) + status = mbedtls_pk_parse_keyfile(ctx->priv_key, priv_key_file, NULL); + if (MBEDTLS_ERR_PK_PASSWORD_REQUIRED == status) { char passbuf[512] = {0}; pem_password_callback(passbuf, 512, 0, NULL); - status = pk_parse_keyfile(ctx->priv_key, priv_key_file, passbuf); + status = mbedtls_pk_parse_keyfile(ctx->priv_key, priv_key_file, passbuf); } } - if (!polar_ok(status)) + if (!mbed_ok(status)) { #ifdef ENABLE_MANAGEMENT - if (management && (POLARSSL_ERR_PK_PASSWORD_MISMATCH == status)) + if (management && (MBEDTLS_ERR_PK_PASSWORD_MISMATCH == status)) management_auth_failure (management, UP_TYPE_PRIVATE_KEY, NULL); #endif msg (M_WARN, "Cannot load private key file %s", priv_key_file); @@ -377,7 +379,7 @@ struct external_context { }; /** - * external_pkcs1_sign implements a PolarSSL rsa_sign_func callback, that uses + * external_pkcs1_sign implements a mbed TLS rsa_sign_func callback, that uses * the management interface to request an RSA signature for the supplied hash. * * @param ctx_voidptr Management external key context. @@ -386,18 +388,18 @@ struct external_context { * @param mode RSA mode (should be RSA_PRIVATE). * @param md_alg Message digest ('hash') algorithm type. * @param hashlen Length of hash (overridden by length specified by md_alg - * if md_alg != POLARSSL_MD_NONE). + * if md_alg != MBEDTLS_MD_NONE). * @param hash The digest ('hash') to sign. Should have a size - * matching the length of md_alg (if != POLARSSL_MD_NONE), + * matching the length of md_alg (if != MBEDTLS_MD_NONE), * or hashlen otherwise. * @param sig Buffer that returns the signature. Should be at least of * size ctx->signature_length. * - * @return 0 on success, non-zero polarssl error code on failure. + * @return 0 on success, non-zero mbed TLS error code on failure. */ static inline int external_pkcs1_sign( void *ctx_voidptr, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, int mode, - md_type_t md_alg, unsigned int hashlen, const unsigned char *hash, + mbedtls_md_type_t md_alg, unsigned int hashlen, const unsigned char *hash, unsigned char *sig ) { struct external_context * const ctx = ctx_voidptr; @@ -409,35 +411,35 @@ static inline int external_pkcs1_sign( void *ctx_voidptr, const char *oid = NULL; if( NULL == ctx ) - return POLARSSL_ERR_RSA_BAD_INPUT_DATA; + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; - if( RSA_PRIVATE != mode ) - return POLARSSL_ERR_RSA_BAD_INPUT_DATA; + if( MBEDTLS_RSA_PRIVATE != mode ) + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; /* * Support a wide range of hashes. TLSv1.1 and before only need SIG_RSA_RAW, * but TLSv1.2 needs the full suite of hashes. * - * This code has been taken from PolarSSL pkcs11_sign(), under the GPLv2.0+. + * This code has been taken from mbed TLS pkcs11_sign(), under the GPLv2.0+. */ - if( md_alg != POLARSSL_MD_NONE ) + if( md_alg != MBEDTLS_MD_NONE ) { - const md_info_t *md_info = md_info_from_type( md_alg ); + const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type( md_alg ); if( md_info == NULL ) - return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); - if (!polar_ok(oid_get_oid_by_md( md_alg, &oid, &oid_size ))) - return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); + if (!mbed_ok(mbedtls_oid_get_oid_by_md( md_alg, &oid, &oid_size ))) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); - hashlen = md_get_size( md_info ); + hashlen = mbedtls_md_get_size( md_info ); asn_len = 10 + oid_size; } sig_len = ctx->signature_length; if ( (SIZE_MAX - hashlen) < asn_len || (hashlen + asn_len) > sig_len ) - return POLARSSL_ERR_RSA_BAD_INPUT_DATA; + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; - if( md_alg != POLARSSL_MD_NONE ) + if( md_alg != MBEDTLS_MD_NONE ) { /* * DigestInfo ::= SEQUENCE { @@ -448,17 +450,17 @@ static inline int external_pkcs1_sign( void *ctx_voidptr, * * Digest ::= OCTET STRING */ - *p++ = ASN1_SEQUENCE | ASN1_CONSTRUCTED; + *p++ = MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED; *p++ = (unsigned char) ( 0x08 + oid_size + hashlen ); - *p++ = ASN1_SEQUENCE | ASN1_CONSTRUCTED; + *p++ = MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED; *p++ = (unsigned char) ( 0x04 + oid_size ); - *p++ = ASN1_OID; + *p++ = MBEDTLS_ASN1_OID; *p++ = oid_size & 0xFF; memcpy( p, oid, oid_size ); p += oid_size; - *p++ = ASN1_NULL; + *p++ = MBEDTLS_ASN1_NULL; *p++ = 0x00; - *p++ = ASN1_OCTET_STRING; + *p++ = MBEDTLS_ASN1_OCTET_STRING; *p++ = hashlen; /* Determine added ASN length */ @@ -471,7 +473,7 @@ static inline int external_pkcs1_sign( void *ctx_voidptr, /* convert 'from' to base64 */ if (openvpn_base64_encode (sig, asn_len + hashlen, &in_b64) <= 0) { - rv = POLARSSL_ERR_RSA_BAD_INPUT_DATA; + rv = MBEDTLS_ERR_RSA_BAD_INPUT_DATA; goto done; } @@ -480,7 +482,7 @@ static inline int external_pkcs1_sign( void *ctx_voidptr, out_b64 = management_query_rsa_sig (management, in_b64); if (!out_b64) { - rv = POLARSSL_ERR_RSA_PRIVATE_FAILED; + rv = MBEDTLS_ERR_RSA_PRIVATE_FAILED; goto done; } @@ -488,7 +490,7 @@ static inline int external_pkcs1_sign( void *ctx_voidptr, if ( openvpn_base64_decode (out_b64, sig, ctx->signature_length) != ctx->signature_length ) { - rv = POLARSSL_ERR_RSA_PRIVATE_FAILED; + rv = MBEDTLS_ERR_RSA_PRIVATE_FAILED; goto done; } @@ -521,10 +523,10 @@ tls_ctx_use_external_private_key (struct tls_root_ctx *ctx, return 0; ALLOC_OBJ_CLEAR (ctx->external_key, struct external_context); - ctx->external_key->signature_length = pk_get_len(&ctx->crt_chain->pk); + ctx->external_key->signature_length = mbedtls_pk_get_len (&ctx->crt_chain->pk); - ALLOC_OBJ_CLEAR (ctx->priv_key, pk_context); - if (!polar_ok(pk_init_ctx_rsa_alt(ctx->priv_key, ctx->external_key, + ALLOC_OBJ_CLEAR (ctx->priv_key, mbedtls_pk_context); + if (!mbed_ok (mbedtls_pk_setup_rsa_alt (ctx->priv_key, ctx->external_key, NULL, external_pkcs1_sign, external_key_len))) return 0; @@ -537,18 +539,18 @@ void tls_ctx_load_ca (struct tls_root_ctx *ctx, const char *ca_file, ) { if (ca_path) - msg(M_FATAL, "ERROR: PolarSSL cannot handle the capath directive"); + msg(M_FATAL, "ERROR: mbed TLS cannot handle the capath directive"); if (ca_file && !strcmp (ca_file, INLINE_FILE_TAG) && ca_inline) { - if (!polar_ok(x509_crt_parse(ctx->ca_chain, - (const unsigned char *) ca_inline, strlen(ca_inline)))) + if (!mbed_ok (mbedtls_x509_crt_parse (ctx->ca_chain, + (const unsigned char *) ca_inline, strlen(ca_inline)+1))) msg (M_FATAL, "Cannot load inline CA certificates"); } else { /* Load CA file for verifying peer supplied certificate */ - if (!polar_ok(x509_crt_parse_file(ctx->ca_chain, ca_file))) + if (!mbed_ok (mbedtls_x509_crt_parse_file (ctx->ca_chain, ca_file))) msg (M_FATAL, "Cannot load CA certificate file %s", ca_file); } } @@ -562,19 +564,19 @@ tls_ctx_load_extra_certs (struct tls_root_ctx *ctx, const char *extra_certs_file if (!ctx->crt_chain) { - ALLOC_OBJ_CLEAR (ctx->crt_chain, x509_crt); + ALLOC_OBJ_CLEAR (ctx->crt_chain, mbedtls_x509_crt); } if (!strcmp (extra_certs_file, INLINE_FILE_TAG) && extra_certs_inline) { - if (!polar_ok(x509_crt_parse(ctx->crt_chain, + if (!mbed_ok(mbedtls_x509_crt_parse(ctx->crt_chain, (const unsigned char *) extra_certs_inline, - strlen(extra_certs_inline)))) + strlen(extra_certs_inline)+1))) msg (M_FATAL, "Cannot load inline extra-certs file"); } else { - if (!polar_ok(x509_crt_parse_file(ctx->crt_chain, extra_certs_file))) + if (!mbed_ok(mbedtls_x509_crt_parse_file(ctx->crt_chain, extra_certs_file))) msg (M_FATAL, "Cannot load extra-certs file: %s", extra_certs_file); } } @@ -609,13 +611,12 @@ static void buf_free_entries(endless_buffer *buf) buf->last_block = NULL; } -static int endless_buf_read( void * ctx, unsigned char * out, size_t out_len ) +static int endless_buf_read( endless_buffer *in, unsigned char * out, size_t out_len ) { - endless_buffer *in = (endless_buffer *) ctx; size_t read_len = 0; if (in->first_block == NULL) - return POLARSSL_ERR_NET_WANT_READ; + return MBEDTLS_ERR_SSL_WANT_READ; while (in->first_block != NULL && read_len < out_len) { @@ -648,18 +649,17 @@ static int endless_buf_read( void * ctx, unsigned char * out, size_t out_len ) return read_len; } -static int endless_buf_write( void *ctx, const unsigned char *in, size_t len ) +static int endless_buf_write( endless_buffer *out, const unsigned char *in, size_t len ) { - endless_buffer *out = (endless_buffer *) ctx; buffer_entry *new_block = malloc(sizeof(buffer_entry)); if (NULL == new_block) - return POLARSSL_ERR_NET_SEND_FAILED; + return MBEDTLS_ERR_NET_SEND_FAILED; new_block->data = malloc(len); if (NULL == new_block->data) { free(new_block); - return POLARSSL_ERR_NET_SEND_FAILED; + return MBEDTLS_ERR_NET_SEND_FAILED; } new_block->length = len; @@ -678,10 +678,23 @@ static int endless_buf_write( void *ctx, const unsigned char *in, size_t len ) return len; } -static void my_debug( void *ctx, int level, const char *str ) +static int ssl_bio_read( void *ctx, unsigned char *out, size_t out_len) +{ + bio_ctx *my_ctx = (bio_ctx *) ctx; + return endless_buf_read (&my_ctx->in, out, out_len); +} + +static int ssl_bio_write( void *ctx, const unsigned char *in, size_t in_len) +{ + bio_ctx *my_ctx = (bio_ctx *) ctx; + return endless_buf_write (&my_ctx->out, in, in_len); +} + +static void my_debug( void *ctx, int level, const char *file, int line, + const char *str ) { int my_loglevel = (level < 3) ? D_TLS_DEBUG_MED : D_TLS_DEBUG; - msg (my_loglevel, "PolarSSL msg: %s", str); + msg (my_loglevel, "mbed TLS msg (%s:%d): %s", file, line, str); } /* @@ -691,16 +704,16 @@ void tls_ctx_personalise_random(struct tls_root_ctx *ctx) { static char old_sha256_hash[32] = {0}; unsigned char sha256_hash[32] = {0}; - ctr_drbg_context *cd_ctx = rand_ctx_get(); + mbedtls_ctr_drbg_context *cd_ctx = rand_ctx_get(); if (NULL != ctx->crt_chain) { - x509_crt *cert = ctx->crt_chain; + mbedtls_x509_crt *cert = ctx->crt_chain; - sha256(cert->tbs.p, cert->tbs.len, sha256_hash, false); + mbedtls_sha256(cert->tbs.p, cert->tbs.len, sha256_hash, false); if ( 0 != memcmp(old_sha256_hash, sha256_hash, sizeof(sha256_hash))) { - ctr_drbg_update(cd_ctx, sha256_hash, 32); + mbedtls_ctr_drbg_update(cd_ctx, sha256_hash, 32); memcpy(old_sha256_hash, sha256_hash, sizeof(old_sha256_hash)); } } @@ -719,13 +732,13 @@ tls_version_max(void) } /** - * Convert an OpenVPN tls-version variable to PolarSSl format (i.e. a major and + * Convert an OpenVPN tls-version variable to mbed TLS format (i.e. a major and * minor ssl version number). * * @param tls_ver The tls-version variable to convert. - * @param major Returns the TLS major version in polarssl format. + * @param major Returns the TLS major version in mbed TLS format. * Must be a valid pointer. - * @param minor Returns the TLS minor version in polarssl format. + * @param minor Returns the TLS minor version in mbed TLS format. * Must be a valid pointer. */ static void tls_version_to_major_minor(int tls_ver, int *major, int *minor) { @@ -735,16 +748,16 @@ static void tls_version_to_major_minor(int tls_ver, int *major, int *minor) { switch (tls_ver) { case TLS_VER_1_0: - *major = SSL_MAJOR_VERSION_3; - *minor = SSL_MINOR_VERSION_1; + *major = MBEDTLS_SSL_MAJOR_VERSION_3; + *minor = MBEDTLS_SSL_MINOR_VERSION_1; break; case TLS_VER_1_1: - *major = SSL_MAJOR_VERSION_3; - *minor = SSL_MINOR_VERSION_2; + *major = MBEDTLS_SSL_MAJOR_VERSION_3; + *minor = MBEDTLS_SSL_MINOR_VERSION_2; break; case TLS_VER_1_2: - *major = SSL_MAJOR_VERSION_3; - *minor = SSL_MINOR_VERSION_3; + *major = MBEDTLS_SSL_MAJOR_VERSION_3; + *minor = MBEDTLS_SSL_MINOR_VERSION_3; break; default: msg(M_FATAL, "%s: invalid TLS version %d", __func__, tls_ver); @@ -759,86 +772,90 @@ void key_state_ssl_init(struct key_state_ssl *ks_ssl, ASSERT(ks_ssl); CLEAR(*ks_ssl); - ALLOC_OBJ_CLEAR(ks_ssl->ctx, ssl_context); - if (polar_ok(ssl_init(ks_ssl->ctx))) + /* Initialise SSL config */ + mbedtls_ssl_config_init(&ks_ssl->ssl_config); + mbedtls_ssl_config_defaults(&ks_ssl->ssl_config, ssl_ctx->endpoint, + MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT); + mbedtls_debug_set_threshold(3); + mbedtls_ssl_conf_dbg (&ks_ssl->ssl_config, my_debug, NULL); + mbedtls_ssl_conf_rng (&ks_ssl->ssl_config, mbedtls_ctr_drbg_random, + rand_ctx_get()); + + if (ssl_ctx->allowed_ciphers) + mbedtls_ssl_conf_ciphersuites (&ks_ssl->ssl_config, ssl_ctx->allowed_ciphers); + + /* Disable record splitting (for now). OpenVPN assumes records are sent + * unfragmented, and changing that will require thorough review and + * testing. Since OpenVPN is not susceptible to BEAST, we can just + * disable record splitting as a quick fix. */ +#if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING) + mbedtls_ssl_conf_cbc_record_splitting (&ks_ssl->ssl_config, + MBEDTLS_SSL_CBC_RECORD_SPLITTING_DISABLED); +#endif /* MBEDTLS_SSL_CBC_RECORD_SPLITTING */ + + /* Initialise authentication information */ + if (is_server) + mbed_ok (mbedtls_ssl_conf_dh_param_ctx(&ks_ssl->ssl_config, + ssl_ctx->dhm_ctx)); + + mbed_ok (mbedtls_ssl_conf_own_cert(&ks_ssl->ssl_config, ssl_ctx->crt_chain, + ssl_ctx->priv_key)); + + /* Initialise SSL verification */ +#if P2MP_SERVER + if (session->opt->ssl_flags & SSLF_CLIENT_CERT_OPTIONAL) { - /* Initialise SSL context */ - debug_set_threshold(3); - ssl_set_dbg (ks_ssl->ctx, my_debug, NULL); - ssl_set_endpoint (ks_ssl->ctx, ssl_ctx->endpoint); - - ssl_set_rng (ks_ssl->ctx, ctr_drbg_random, rand_ctx_get()); + mbedtls_ssl_conf_authmode(&ks_ssl->ssl_config, MBEDTLS_SSL_VERIFY_OPTIONAL); + } + else if (!(session->opt->ssl_flags & SSLF_CLIENT_CERT_NOT_REQUIRED)) +#endif + { + mbedtls_ssl_conf_authmode (&ks_ssl->ssl_config, MBEDTLS_SSL_VERIFY_REQUIRED); + } + mbedtls_ssl_conf_verify (&ks_ssl->ssl_config, verify_callback, session); - if (ssl_ctx->allowed_ciphers) - ssl_set_ciphersuites (ks_ssl->ctx, ssl_ctx->allowed_ciphers); + /* TODO: mbed TLS does not currently support sending the CA chain to the client */ + mbedtls_ssl_conf_ca_chain (&ks_ssl->ssl_config, ssl_ctx->ca_chain, NULL ); - /* Disable record splitting (for now). OpenVPN assumes records are sent - * unfragmented, and changing that will require thorough review and - * testing. Since OpenVPN is not susceptible to BEAST, we can just - * disable record splitting as a quick fix. */ -#if defined(POLARSSL_SSL_CBC_RECORD_SPLITTING) - ssl_set_cbc_record_splitting (ks_ssl->ctx, SSL_CBC_RECORD_SPLITTING_DISABLED); -#endif /* POLARSSL_SSL_CBC_RECORD_SPLITTING */ + /* Initialize minimum TLS version */ + { + const int tls_version_min = + (session->opt->ssl_flags >> SSLF_TLS_VERSION_MIN_SHIFT) & + SSLF_TLS_VERSION_MIN_MASK; - /* Initialise authentication information */ - if (is_server) - polar_ok(ssl_set_dh_param_ctx(ks_ssl->ctx, ssl_ctx->dhm_ctx)); + /* default to TLS 1.0 */ + int major = MBEDTLS_SSL_MAJOR_VERSION_3; + int minor = MBEDTLS_SSL_MINOR_VERSION_1; - polar_ok(ssl_set_own_cert(ks_ssl->ctx, ssl_ctx->crt_chain, - ssl_ctx->priv_key)); + if (tls_version_min > TLS_VER_UNSPEC) + tls_version_to_major_minor(tls_version_min, &major, &minor); - /* Initialise SSL verification */ -#if P2MP_SERVER - if (session->opt->ssl_flags & SSLF_CLIENT_CERT_OPTIONAL) - { - ssl_set_authmode(ks_ssl->ctx, SSL_VERIFY_OPTIONAL); - } - else if (!(session->opt->ssl_flags & SSLF_CLIENT_CERT_NOT_REQUIRED)) -#endif - { - ssl_set_authmode (ks_ssl->ctx, SSL_VERIFY_REQUIRED); - } - ssl_set_verify (ks_ssl->ctx, verify_callback, session); + mbedtls_ssl_conf_min_version(&ks_ssl->ssl_config, major, minor); + } - /* TODO: PolarSSL does not currently support sending the CA chain to the client */ - ssl_set_ca_chain (ks_ssl->ctx, ssl_ctx->ca_chain, NULL, NULL ); + /* Initialize maximum TLS version */ + { + const int tls_version_max = + (session->opt->ssl_flags >> SSLF_TLS_VERSION_MAX_SHIFT) & + SSLF_TLS_VERSION_MAX_MASK; - /* Initialize minimum TLS version */ + if (tls_version_max > TLS_VER_UNSPEC) { - const int tls_version_min = - (session->opt->ssl_flags >> SSLF_TLS_VERSION_MIN_SHIFT) & - SSLF_TLS_VERSION_MIN_MASK; - - /* default to TLS 1.0 */ - int major = SSL_MAJOR_VERSION_3; - int minor = SSL_MINOR_VERSION_1; - - if (tls_version_min > TLS_VER_UNSPEC) - tls_version_to_major_minor(tls_version_min, &major, &minor); - - ssl_set_min_version(ks_ssl->ctx, major, minor); + int major, minor; + tls_version_to_major_minor(tls_version_max, &major, &minor); + mbedtls_ssl_conf_max_version(&ks_ssl->ssl_config, major, minor); } + } - /* Initialize maximum TLS version */ - { - const int tls_version_max = - (session->opt->ssl_flags >> SSLF_TLS_VERSION_MAX_SHIFT) & - SSLF_TLS_VERSION_MAX_MASK; - - if (tls_version_max > TLS_VER_UNSPEC) - { - int major, minor; - tls_version_to_major_minor(tls_version_max, &major, &minor); - ssl_set_max_version(ks_ssl->ctx, major, minor); - } - } + /* Initialise SSL context */ + ALLOC_OBJ_CLEAR(ks_ssl->ctx, mbedtls_ssl_context); + mbedtls_ssl_init(ks_ssl->ctx); + mbedtls_ssl_setup(ks_ssl->ctx, &ks_ssl->ssl_config); - /* Initialise BIOs */ - ALLOC_OBJ_CLEAR (ks_ssl->ct_in, endless_buffer); - ALLOC_OBJ_CLEAR (ks_ssl->ct_out, endless_buffer); - ssl_set_bio (ks_ssl->ctx, endless_buf_read, ks_ssl->ct_in, - endless_buf_write, ks_ssl->ct_out); - } + /* Initialise BIOs */ + CLEAR (ks_ssl->bio_ctx); + mbedtls_ssl_set_bio (ks_ssl->ctx, &ks_ssl->bio_ctx, ssl_bio_write, + ssl_bio_read, NULL); } void @@ -847,17 +864,12 @@ key_state_ssl_free(struct key_state_ssl *ks_ssl) if (ks_ssl) { if (ks_ssl->ctx) { - ssl_free(ks_ssl->ctx); + mbedtls_ssl_free(ks_ssl->ctx); free(ks_ssl->ctx); } - if (ks_ssl->ct_in) { - buf_free_entries(ks_ssl->ct_in); - free(ks_ssl->ct_in); - } - if (ks_ssl->ct_out) { - buf_free_entries(ks_ssl->ct_out); - free(ks_ssl->ct_out); - } + mbedtls_ssl_config_free(&ks_ssl->ssl_config); + buf_free_entries(&ks_ssl->bio_ctx.in); + buf_free_entries(&ks_ssl->bio_ctx.out); CLEAR(*ks_ssl); } } @@ -897,14 +909,14 @@ key_state_write_plaintext_const (struct key_state_ssl *ks, const uint8_t *data, ASSERT (data); - retval = ssl_write(ks->ctx, data, len); + retval = mbedtls_ssl_write(ks->ctx, data, len); if (retval < 0) { perf_pop (); - if (POLARSSL_ERR_NET_WANT_WRITE == retval || POLARSSL_ERR_NET_WANT_READ == retval) + if (MBEDTLS_ERR_SSL_WANT_WRITE == retval || MBEDTLS_ERR_SSL_WANT_READ == retval) return 0; - polar_log_err (D_TLS_ERRORS, retval, + mbed_log_err (D_TLS_ERRORS, retval, "TLS ERROR: write tls_write_plaintext_const error"); return -1; } @@ -948,15 +960,15 @@ key_state_read_ciphertext (struct key_state_ssl *ks, struct buffer *buf, if (maxlen < len) len = maxlen; - retval = endless_buf_read(ks->ct_out, BPTR(buf), len); + retval = endless_buf_read(&ks->bio_ctx.out, BPTR(buf), len); /* Error during read, check for retry error */ if (retval < 0) { perf_pop (); - if (POLARSSL_ERR_NET_WANT_WRITE == retval || POLARSSL_ERR_NET_WANT_READ == retval) + if (MBEDTLS_ERR_SSL_WANT_WRITE == retval || MBEDTLS_ERR_SSL_WANT_READ == retval) return 0; - polar_log_err (D_TLS_ERRORS, retval, "TLS_ERROR: read tls_read_ciphertext error"); + mbed_log_err (D_TLS_ERRORS, retval, "TLS_ERROR: read tls_read_ciphertext error"); buf->len = 0; return -1; } @@ -991,15 +1003,15 @@ key_state_write_ciphertext (struct key_state_ssl *ks, struct buffer *buf) return 0; } - retval = endless_buf_write(ks->ct_in, BPTR(buf), buf->len); + retval = endless_buf_write(&ks->bio_ctx.in, BPTR(buf), buf->len); if (retval < 0) { perf_pop (); - if (POLARSSL_ERR_NET_WANT_WRITE == retval || POLARSSL_ERR_NET_WANT_READ == retval) + if (MBEDTLS_ERR_SSL_WANT_WRITE == retval || MBEDTLS_ERR_SSL_WANT_READ == retval) return 0; - polar_log_err (D_TLS_ERRORS, retval, + mbed_log_err (D_TLS_ERRORS, retval, "TLS ERROR: write tls_write_ciphertext error"); return -1; } @@ -1045,14 +1057,14 @@ key_state_read_plaintext (struct key_state_ssl *ks, struct buffer *buf, if (maxlen < len) len = maxlen; - retval = ssl_read(ks->ctx, BPTR(buf), len); + retval = mbedtls_ssl_read(ks->ctx, BPTR(buf), len); /* Error during read, check for retry error */ if (retval < 0) { - if (POLARSSL_ERR_NET_WANT_WRITE == retval || POLARSSL_ERR_NET_WANT_READ == retval) + if (MBEDTLS_ERR_SSL_WANT_WRITE == retval || MBEDTLS_ERR_SSL_WANT_READ == retval) return 0; - polar_log_err (D_TLS_ERRORS, retval, "TLS_ERROR: read tls_read_plaintext error"); + mbed_log_err (D_TLS_ERRORS, retval, "TLS_ERROR: read tls_read_plaintext error"); buf->len = 0; perf_pop (); return -1; @@ -1083,20 +1095,21 @@ key_state_read_plaintext (struct key_state_ssl *ks, struct buffer *buf, void print_details (struct key_state_ssl * ks_ssl, const char *prefix) { - const x509_crt *cert; + const mbedtls_x509_crt *cert; char s1[256]; char s2[256]; s1[0] = s2[0] = 0; openvpn_snprintf (s1, sizeof (s1), "%s %s, cipher %s", prefix, - ssl_get_version (ks_ssl->ctx), - ssl_get_ciphersuite(ks_ssl->ctx)); + mbedtls_ssl_get_version (ks_ssl->ctx), + mbedtls_ssl_get_ciphersuite (ks_ssl->ctx)); - cert = ssl_get_peer_cert(ks_ssl->ctx); + cert = mbedtls_ssl_get_peer_cert (ks_ssl->ctx); if (cert != NULL) { - openvpn_snprintf (s2, sizeof (s2), ", %zu bit key", pk_get_size(&cert->pk)); + openvpn_snprintf (s2, sizeof (s2), ", %zu bit key", + mbedtls_pk_get_bitlen (&cert->pk)); } msg (D_HANDSHAKE, "%s%s", s1, s2); @@ -1106,7 +1119,7 @@ void show_available_tls_ciphers (const char *cipher_list) { struct tls_root_ctx tls_ctx; - const int *ciphers = ssl_list_ciphersuites(); + const int *ciphers = mbedtls_ssl_list_ciphersuites (); tls_ctx_server_new(&tls_ctx); tls_ctx_restrict_ciphers(&tls_ctx, cipher_list); @@ -1121,7 +1134,7 @@ show_available_tls_ciphers (const char *cipher_list) while (*ciphers != 0) { - printf ("%s\n", ssl_get_ciphersuite_name(*ciphers)); + printf ("%s\n", mbedtls_ssl_get_ciphersuite_name (*ciphers)); ciphers++; } printf ("\n" SHOW_TLS_CIPHER_LIST_WARNING); @@ -1132,14 +1145,14 @@ show_available_tls_ciphers (const char *cipher_list) void show_available_curves (void) { - const ecp_curve_info *pcurve = ecp_curve_list(); + const mbedtls_ecp_curve_info *pcurve = mbedtls_ecp_curve_list (); if (NULL == pcurve) - msg (M_FATAL, "Cannot retrieve curve list from PolarSSL"); + msg (M_FATAL, "Cannot retrieve curve list from mbed TLS"); /* Print curve list */ printf ("Available Elliptic curves, listed in order of preference:\n\n"); - while (POLARSSL_ECP_DP_NONE != pcurve->grp_id) + while (MBEDTLS_ECP_DP_NONE != pcurve->grp_id) { printf("%s\n", pcurve->name); pcurve++; @@ -1150,22 +1163,22 @@ void get_highest_preference_tls_cipher (char *buf, int size) { const char *cipher_name; - const int *ciphers = ssl_list_ciphersuites(); + const int *ciphers = mbedtls_ssl_list_ciphersuites(); if (*ciphers == 0) msg (M_FATAL, "Cannot retrieve list of supported SSL ciphers."); - cipher_name = ssl_get_ciphersuite_name(*ciphers); + cipher_name = mbedtls_ssl_get_ciphersuite_name(*ciphers); strncpynt (buf, cipher_name, size); } const char * get_ssl_library_version(void) { - static char polar_version[30]; - unsigned int pv = version_get_number(); - sprintf( polar_version, "PolarSSL %d.%d.%d", + static char mbedtls_version[30]; + unsigned int pv = mbedtls_version_get_number(); + sprintf( mbedtls_version, "mbed TLS %d.%d.%d", (pv>>24)&0xff, (pv>>16)&0xff, (pv>>8)&0xff ); - return polar_version; + return mbedtls_version; } -#endif /* defined(ENABLE_CRYPTO) && defined(ENABLE_CRYPTO_POLARSSL) */ +#endif /* defined(ENABLE_CRYPTO) && defined(ENABLE_CRYPTO_MBEDTLS) */ diff --git a/src/openvpn/ssl_polarssl.h b/src/openvpn/ssl_polarssl.h index b80a509eed1..6f778efbe5d 100644 --- a/src/openvpn/ssl_polarssl.h +++ b/src/openvpn/ssl_polarssl.h @@ -24,19 +24,19 @@ */ /** - * @file Control Channel PolarSSL Backend + * @file Control Channel mbed TLS Backend */ -#ifndef SSL_POLARSSL_H_ -#define SSL_POLARSSL_H_ +#ifndef SSL_MBEDTLS_H_ +#define SSL_MBEDTLS_H_ #include "syshead.h" -#include -#include +#include +#include #if defined(ENABLE_PKCS11) -#include +#include #endif typedef struct _buffer_entry buffer_entry; @@ -53,6 +53,11 @@ typedef struct { buffer_entry *last_block; } endless_buffer; +typedef struct { + endless_buffer in; + endless_buffer out; +} bio_ctx; + /** * Structure that wraps the TLS context. Contents differ depending on the * SSL library used. @@ -64,12 +69,12 @@ struct tls_root_ctx { int endpoint; /**< Whether or not this is a server or a client */ - dhm_context *dhm_ctx; /**< Diffie-Helmann-Merkle context */ - x509_crt *crt_chain; /**< Local Certificate chain */ - x509_crt *ca_chain; /**< CA chain for remote verification */ - pk_context *priv_key; /**< Local private key */ + mbedtls_dhm_context *dhm_ctx; /**< Diffie-Helmann-Merkle context */ + mbedtls_x509_crt *crt_chain; /**< Local Certificate chain */ + mbedtls_x509_crt *ca_chain; /**< CA chain for remote verification */ + mbedtls_pk_context *priv_key; /**< Local private key */ #if defined(ENABLE_PKCS11) - pkcs11_context *priv_key_pkcs11; /**< PKCS11 private key */ + mbedtls_pkcs11_context *priv_key_pkcs11; /**< PKCS11 private key */ #endif #ifdef MANAGMENT_EXTERNAL_KEY struct external_context *external_key; /**< Management external key */ @@ -78,10 +83,10 @@ struct tls_root_ctx { }; struct key_state_ssl { - ssl_context *ctx; - endless_buffer *ct_in; - endless_buffer *ct_out; + mbedtls_ssl_config ssl_config; /**< mbedTLS global ssl config */ + mbedtls_ssl_context *ctx; /**< mbedTLS connection context */ + bio_ctx bio_ctx; }; -#endif /* SSL_POLARSSL_H_ */ +#endif /* SSL_MBEDTLS_H_ */ diff --git a/src/openvpn/ssl_verify.h b/src/openvpn/ssl_verify.h index 8527415f85e..5eb18435295 100644 --- a/src/openvpn/ssl_verify.h +++ b/src/openvpn/ssl_verify.h @@ -40,7 +40,7 @@ #ifdef ENABLE_CRYPTO_OPENSSL #include "ssl_verify_openssl.h" #endif -#ifdef ENABLE_CRYPTO_POLARSSL +#ifdef ENABLE_CRYPTO_MBEDTLS #include "ssl_verify_polarssl.h" #endif diff --git a/src/openvpn/ssl_verify_polarssl.c b/src/openvpn/ssl_verify_polarssl.c index d52713369eb..ff76d3d38b9 100644 --- a/src/openvpn/ssl_verify_polarssl.c +++ b/src/openvpn/ssl_verify_polarssl.c @@ -24,7 +24,7 @@ */ /** - * @file Control Channel Verification Module PolarSSL backend + * @file Control Channel Verification Module mbed TLS backend */ #ifdef HAVE_CONFIG_H @@ -35,21 +35,21 @@ #include "syshead.h" -#if defined(ENABLE_CRYPTO) && defined(ENABLE_CRYPTO_POLARSSL) +#if defined(ENABLE_CRYPTO) && defined(ENABLE_CRYPTO_MBEDTLS) #include "crypto_polarssl.h" #include "ssl_verify.h" -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #define MAX_SUBJECT_LENGTH 256 int -verify_callback (void *session_obj, x509_crt *cert, int cert_depth, - int *flags) +verify_callback (void *session_obj, mbedtls_x509_crt *cert, int cert_depth, + uint32_t *flags) { struct tls_session *session = (struct tls_session *) session_obj; struct gc_arena gc = gc_new(); @@ -77,26 +77,26 @@ verify_callback (void *session_obj, x509_crt *cert, int cert_depth, } else if (SUCCESS != verify_cert(session, cert, cert_depth)) { - *flags |= BADCERT_OTHER; + *flags |= MBEDTLS_X509_BADCERT_OTHER; } gc_free(&gc); /* - * PolarSSL-1.2.0+ expects 0 on anything except fatal errors. + * PolarSSL/mbed TLS-1.2.0+ expects 0 on anything except fatal errors. */ return 0; } #ifdef ENABLE_X509ALTUSERNAME -# warning "X509 alt user name not yet supported for PolarSSL" +# warning "X509 alt user name not yet supported for mbed TLS" #endif result_t backend_x509_get_username (char *cn, int cn_len, - char *x509_username_field, x509_crt *cert) + char *x509_username_field, mbedtls_x509_crt *cert) { - x509_name *name; + mbedtls_x509_name *name; ASSERT( cn != NULL ); @@ -105,7 +105,8 @@ backend_x509_get_username (char *cn, int cn_len, /* Find common name */ while( name != NULL ) { - if( memcmp( name->oid.p, OID_AT_CN, OID_SIZE(OID_AT_CN) ) == 0) + if (0 == memcmp (name->oid.p, MBEDTLS_OID_AT_CN, + MBEDTLS_OID_SIZE (MBEDTLS_OID_AT_CN))) break; name = name->next; @@ -131,26 +132,27 @@ backend_x509_get_username (char *cn, int cn_len, } char * -backend_x509_get_serial (openvpn_x509_cert_t *cert, struct gc_arena *gc) +backend_x509_get_serial (mbedtls_x509_crt *cert, struct gc_arena *gc) { char *buf = NULL; size_t buflen = 0; - mpi serial_mpi = { 0 }; + mbedtls_mpi serial_mpi = { 0 }; - /* Transform asn1 integer serial into PolarSSL MPI */ - mpi_init(&serial_mpi); - if (!polar_ok(mpi_read_binary(&serial_mpi, cert->serial.p, cert->serial.len))) + /* Transform asn1 integer serial into mbed TLS MPI */ + mbedtls_mpi_init(&serial_mpi); + if (!mbed_ok(mbedtls_mpi_read_binary(&serial_mpi, cert->serial.p, + cert->serial.len))) { msg(M_WARN, "Failed to retrieve serial from certificate."); return NULL; } /* Determine decimal representation length, allocate buffer */ - mpi_write_string(&serial_mpi, 10, buf, &buflen); + mbedtls_mpi_write_string(&serial_mpi, 10, NULL, 0, &buflen); buf = gc_malloc(buflen, true, gc); /* Write MPI serial as decimal string into buffer */ - if (!polar_ok(mpi_write_string(&serial_mpi, 10, buf, &buflen))) + if (!mbed_ok(mbedtls_mpi_write_string(&serial_mpi, 10, buf, buflen, &buflen))) { msg(M_WARN, "Failed to write serial to string."); return NULL; @@ -160,36 +162,36 @@ backend_x509_get_serial (openvpn_x509_cert_t *cert, struct gc_arena *gc) } char * -backend_x509_get_serial_hex (openvpn_x509_cert_t *cert, struct gc_arena *gc) +backend_x509_get_serial_hex (mbedtls_x509_crt *cert, struct gc_arena *gc) { char *buf = NULL; size_t len = cert->serial.len * 3 + 1; buf = gc_malloc(len, true, gc); - if(x509_serial_gets(buf, len-1, &cert->serial) < 0) + if(mbedtls_x509_serial_gets(buf, len-1, &cert->serial) < 0) buf = NULL; return buf; } unsigned char * -x509_get_sha1_hash (x509_crt *cert, struct gc_arena *gc) +x509_get_sha1_hash (mbedtls_x509_crt *cert, struct gc_arena *gc) { unsigned char *sha1_hash = gc_malloc(SHA_DIGEST_LENGTH, false, gc); - sha1(cert->raw.p, cert->raw.len, sha1_hash); + mbedtls_sha1(cert->raw.p, cert->tbs.len, sha1_hash); return sha1_hash; } char * -x509_get_subject(x509_crt *cert, struct gc_arena *gc) +x509_get_subject(mbedtls_x509_crt *cert, struct gc_arena *gc) { char tmp_subject[MAX_SUBJECT_LENGTH] = {0}; char *subject = NULL; int ret = 0; - ret = x509_dn_gets( tmp_subject, MAX_SUBJECT_LENGTH-1, &cert->subject ); + ret = mbedtls_x509_dn_gets( tmp_subject, MAX_SUBJECT_LENGTH-1, &cert->subject ); if (ret > 0) { /* Allocate the required space for the subject */ @@ -216,7 +218,7 @@ do_setenv_x509 (struct env_set *es, const char *name, char *value, int depth) } static char * -asn1_buf_to_c_string(const asn1_buf *orig, struct gc_arena *gc) +asn1_buf_to_c_string(const mbedtls_asn1_buf *orig, struct gc_arena *gc) { size_t i; char *val; @@ -232,13 +234,13 @@ asn1_buf_to_c_string(const asn1_buf *orig, struct gc_arena *gc) static void do_setenv_name(struct env_set *es, const struct x509_track *xt, - const x509_crt *cert, int depth, struct gc_arena *gc) + const mbedtls_x509_crt *cert, int depth, struct gc_arena *gc) { - const x509_name *xn; + const mbedtls_x509_name *xn; for (xn = &cert->subject; xn != NULL; xn = xn->next) { const char *xn_short_name = NULL; - if (0 == oid_get_attr_short_name (&xn->oid, &xn_short_name) && + if (0 == mbedtls_oid_get_attr_short_name (&xn->oid, &xn_short_name) && 0 == strcmp (xt->name, xn_short_name)) { char *val_str = asn1_buf_to_c_string (&xn->val, gc); @@ -263,7 +265,8 @@ x509_track_add (const struct x509_track **ll_head, const char *name, int msgleve } void -x509_setenv_track (const struct x509_track *xt, struct env_set *es, const int depth, x509_crt *cert) +x509_setenv_track (const struct x509_track *xt, struct env_set *es, + const int depth, mbedtls_x509_crt *cert) { struct gc_arena gc = gc_new(); while (xt) @@ -293,11 +296,11 @@ x509_setenv_track (const struct x509_track *xt, struct env_set *es, const int de * X509_{cert_depth}_{name}={value} */ void -x509_setenv (struct env_set *es, int cert_depth, openvpn_x509_cert_t *cert) +x509_setenv (struct env_set *es, int cert_depth, mbedtls_x509_crt *cert) { int i; unsigned char c; - const x509_name *name; + const mbedtls_x509_name *name; char s[128]; name = &cert->subject; @@ -309,7 +312,7 @@ x509_setenv (struct env_set *es, int cert_depth, openvpn_x509_cert_t *cert) char name_expand[64+8]; const char *shortname; - if( 0 == oid_get_attr_short_name(&name->oid, &shortname) ) + if( 0 == mbedtls_oid_get_attr_short_name(&name->oid, &shortname) ) { openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_%s", cert_depth, shortname); @@ -342,27 +345,29 @@ x509_setenv (struct env_set *es, int cert_depth, openvpn_x509_cert_t *cert) } result_t -x509_verify_ns_cert_type(const x509_crt *cert, const int usage) +x509_verify_ns_cert_type(const mbedtls_x509_crt *cert, const int usage) { if (usage == NS_CERT_CHECK_NONE) return SUCCESS; if (usage == NS_CERT_CHECK_CLIENT) - return ((cert->ext_types & EXT_NS_CERT_TYPE) - && (cert->ns_cert_type & NS_CERT_TYPE_SSL_CLIENT)) ? SUCCESS : FAILURE; + return ((cert->ext_types & MBEDTLS_X509_EXT_NS_CERT_TYPE) + && (cert->ns_cert_type & MBEDTLS_X509_NS_CERT_TYPE_SSL_CLIENT)) ? + SUCCESS : FAILURE; if (usage == NS_CERT_CHECK_SERVER) - return ((cert->ext_types & EXT_NS_CERT_TYPE) - && (cert->ns_cert_type & NS_CERT_TYPE_SSL_SERVER)) ? SUCCESS : FAILURE; + return ((cert->ext_types & MBEDTLS_X509_EXT_NS_CERT_TYPE) + && (cert->ns_cert_type & MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER)) ? + SUCCESS : FAILURE; return FAILURE; } result_t -x509_verify_cert_ku (x509_crt *cert, const unsigned * const expected_ku, +x509_verify_cert_ku (mbedtls_x509_crt *cert, const unsigned * const expected_ku, int expected_len) { result_t fFound = FAILURE; - if(!(cert->ext_types & EXT_KEY_USAGE)) + if(!(cert->ext_types & MBEDTLS_X509_EXT_KEY_USAGE)) { msg (D_HANDSHAKE, "Certificate does not have key usage extension"); } @@ -390,26 +395,26 @@ x509_verify_cert_ku (x509_crt *cert, const unsigned * const expected_ku, } result_t -x509_verify_cert_eku (x509_crt *cert, const char * const expected_oid) +x509_verify_cert_eku (mbedtls_x509_crt *cert, const char * const expected_oid) { result_t fFound = FAILURE; - if (!(cert->ext_types & EXT_EXTENDED_KEY_USAGE)) + if (!(cert->ext_types & MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE)) { msg (D_HANDSHAKE, "Certificate does not have extended key usage extension"); } else { - x509_sequence *oid_seq = &(cert->ext_key_usage); + mbedtls_x509_sequence *oid_seq = &(cert->ext_key_usage); msg (D_HANDSHAKE, "Validating certificate extended key usage"); while (oid_seq != NULL) { - x509_buf *oid = &oid_seq->buf; + mbedtls_x509_buf *oid = &oid_seq->buf; char oid_num_str[1024]; const char *oid_str; - if (0 == oid_get_extended_key_usage( oid, &oid_str )) + if (0 == mbedtls_oid_get_extended_key_usage( oid, &oid_str )) { msg (D_HANDSHAKE, "++ Certificate has EKU (str) %s, expects %s", oid_str, expected_oid); @@ -420,7 +425,7 @@ x509_verify_cert_eku (x509_crt *cert, const char * const expected_oid) } } - if (0 < oid_get_numeric_string( oid_num_str, + if (0 < mbedtls_oid_get_numeric_string( oid_num_str, sizeof (oid_num_str), oid)) { msg (D_HANDSHAKE, "++ Certificate has EKU (oid) %s, expects %s", @@ -439,9 +444,9 @@ x509_verify_cert_eku (x509_crt *cert, const char * const expected_oid) } result_t -x509_write_pem(FILE *peercert_file, x509_crt *peercert) +x509_write_pem(FILE *peercert_file, mbedtls_x509_crt *peercert) { - msg (M_WARN, "PolarSSL does not support writing peer certificate in PEM format"); + msg (M_WARN, "mbed TLS does not support writing peer certificate in PEM format"); return FAILURE; } @@ -449,17 +454,18 @@ x509_write_pem(FILE *peercert_file, x509_crt *peercert) * check peer cert against CRL */ result_t -x509_verify_crl(const char *crl_file, const char* crl_inline, - x509_crt *cert, const char *subject) +x509_verify_crl(const char *crl_file, const char *crl_inline, + mbedtls_x509_crt *cert, const char *subject) { result_t retval = FAILURE; - x509_crl crl = {0}; + mbedtls_x509_crl crl = {0}; struct gc_arena gc = gc_new(); char *serial; if (!strcmp (crl_file, INLINE_FILE_TAG) && crl_inline) { - if (!polar_ok(x509_crl_parse(&crl, crl_inline, strlen(crl_inline)))) + if (!mbed_ok(mbedtls_x509_crl_parse(&crl, + (const unsigned char *)crl_inline, strlen(crl_inline)+1))) { msg (M_WARN, "CRL: cannot parse inline CRL"); goto end; @@ -467,7 +473,7 @@ x509_verify_crl(const char *crl_file, const char* crl_inline, } else { - if (!polar_ok(x509_crl_parse_file(&crl, crl_file))) + if (!mbed_ok(mbedtls_x509_crl_parse_file(&crl, crl_file))) { msg (M_WARN, "CRL: cannot read CRL from file %s", crl_file); goto end; @@ -483,7 +489,7 @@ x509_verify_crl(const char *crl_file, const char* crl_inline, goto end; } - if (!polar_ok(x509_crt_revoked(cert, &crl))) + if (!mbed_ok(mbedtls_x509_crt_is_revoked(cert, &crl))) { serial = backend_x509_get_serial_hex(cert, &gc); msg (D_HANDSHAKE, "CRL CHECK FAILED: %s (serial %s) is REVOKED", subject, (serial ? serial : "NOT AVAILABLE")); @@ -495,8 +501,8 @@ x509_verify_crl(const char *crl_file, const char* crl_inline, end: gc_free(&gc); - x509_crl_free(&crl); + mbedtls_x509_crl_free(&crl); return retval; } -#endif /* #if defined(ENABLE_CRYPTO) && defined(ENABLE_CRYPTO_POLARSSL) */ +#endif /* #if defined(ENABLE_CRYPTO) && defined(ENABLE_CRYPTO_MBEDTLS) */ diff --git a/src/openvpn/ssl_verify_polarssl.h b/src/openvpn/ssl_verify_polarssl.h index 2076f2ef8d8..e26d08f89bb 100644 --- a/src/openvpn/ssl_verify_polarssl.h +++ b/src/openvpn/ssl_verify_polarssl.h @@ -24,18 +24,18 @@ */ /** - * @file Control Channel Verification Module PolarSSL backend + * @file Control Channel Verification Module mbed TLS backend */ -#ifndef SSL_VERIFY_POLARSSL_H_ -#define SSL_VERIFY_POLARSSL_H_ +#ifndef SSL_VERIFY_MBEDTLS_H_ +#define SSL_VERIFY_MBEDTLS_H_ #include "syshead.h" -#include +#include #ifndef __OPENVPN_X509_CERT_T_DECLARED #define __OPENVPN_X509_CERT_T_DECLARED -typedef x509_crt openvpn_x509_cert_t; +typedef mbedtls_x509_crt openvpn_x509_cert_t; #endif /** @name Function for authenticating a new connection from a remote OpenVPN peer @@ -50,7 +50,7 @@ typedef x509_crt openvpn_x509_cert_t; * determine whether the remote OpenVPN peer's certificate is allowed to * connect. It is called for once for every certificate in the chain. The * callback functionality is configured in the \c init_ssl() function, which - * calls the PolarSSL library's \c ssl_set_verify_callback() function with \c + * calls the mbed TLS library's \c ssl_set_verify_callback() function with \c * verify_callback() as its callback argument. * * It checks *flags and registers the certificate hash. If these steps succeed, @@ -59,7 +59,7 @@ typedef x509_crt openvpn_x509_cert_t; * * @param session_obj - The OpenVPN \c tls_session associated with this object, * as set during SSL session setup. - * @param cert - The certificate used by PolarSSL. + * @param cert - The certificate used by mbed TLS. * @param cert_depth - The depth of the current certificate in the chain, with * 0 being the actual certificate. * @param flags - Whether the remote OpenVPN peer's certificate @@ -70,9 +70,9 @@ typedef x509_crt openvpn_x509_cert_t; * * @return The return value is 0 unless a fatal error occurred. */ -int verify_callback (void *session_obj, x509_crt *cert, int cert_depth, - int *flags); +int verify_callback (void *session_obj, mbedtls_x509_crt *cert, int cert_depth, + uint32_t *flags); /** @} name Function for authenticating a new connection from a remote OpenVPN peer */ -#endif /* SSL_VERIFY_POLARSSL_H_ */ +#endif /* SSL_VERIFY_MBEDTLS_H_ */ diff --git a/src/openvpn/syshead.h b/src/openvpn/syshead.h index 1c9248fb260..c8391ca3bea 100644 --- a/src/openvpn/syshead.h +++ b/src/openvpn/syshead.h @@ -564,10 +564,10 @@ socket_defined (const socket_descriptor_t sd) #define MANAGMENT_EXTERNAL_KEY #endif -/* Enable PolarSSL RNG prediction resistance support */ -#ifdef ENABLE_CRYPTO_POLARSSL +/* Enable mbed TLS RNG prediction resistance support */ +#ifdef ENABLE_CRYPTO_MBEDTLS #define ENABLE_PREDICTION_RESISTANCE -#endif /* ENABLE_CRYPTO_POLARSSL */ +#endif /* ENABLE_CRYPTO_MBEDTLS */ /* * MANAGEMENT_IN_EXTRA allows the management interface to From 74586c6508e5dd283eaef9d098644a7800beec01 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sun, 17 Apr 2016 20:35:43 +0200 Subject: [PATCH 232/643] Rename files with 'polarssl' in the name to 'mbedtls' The patch looks huge, but it's just file renames, and required changes in includes / Makefiles. Use 'git diff -C' or a tool like gitk to easily review this patch. Signed-off-by: Steffan Karger Acked-by: Arne Schwabe Message-Id: <1460918143-408-2-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/11459 Signed-off-by: Gert Doering --- src/openvpn/Makefile.am | 8 ++++---- src/openvpn/crypto_backend.h | 2 +- src/openvpn/{crypto_polarssl.c => crypto_mbedtls.c} | 0 src/openvpn/{crypto_polarssl.h => crypto_mbedtls.h} | 0 src/openvpn/{pkcs11_polarssl.c => pkcs11_mbedtls.c} | 0 src/openvpn/plugin.h | 2 +- src/openvpn/ssl_backend.h | 4 ++-- src/openvpn/{ssl_polarssl.c => ssl_mbedtls.c} | 2 +- src/openvpn/{ssl_polarssl.h => ssl_mbedtls.h} | 0 src/openvpn/ssl_verify.h | 2 +- .../{ssl_verify_polarssl.c => ssl_verify_mbedtls.c} | 2 +- .../{ssl_verify_polarssl.h => ssl_verify_mbedtls.h} | 0 12 files changed, 11 insertions(+), 11 deletions(-) rename src/openvpn/{crypto_polarssl.c => crypto_mbedtls.c} (100%) rename src/openvpn/{crypto_polarssl.h => crypto_mbedtls.h} (100%) rename src/openvpn/{pkcs11_polarssl.c => pkcs11_mbedtls.c} (100%) rename src/openvpn/{ssl_polarssl.c => ssl_mbedtls.c} (99%) rename src/openvpn/{ssl_polarssl.h => ssl_mbedtls.h} (100%) rename src/openvpn/{ssl_verify_polarssl.c => ssl_verify_mbedtls.c} (99%) rename src/openvpn/{ssl_verify_polarssl.h => ssl_verify_mbedtls.h} (100%) diff --git a/src/openvpn/Makefile.am b/src/openvpn/Makefile.am index bf1d749da4f..9d4bf618237 100644 --- a/src/openvpn/Makefile.am +++ b/src/openvpn/Makefile.am @@ -46,7 +46,7 @@ openvpn_SOURCES = \ comp-lz4.c comp-lz4.h \ crypto.c crypto.h crypto_backend.h \ crypto_openssl.c crypto_openssl.h \ - crypto_polarssl.c crypto_polarssl.h \ + crypto_mbedtls.c crypto_mbedtls.h \ dhcp.c dhcp.h \ errlevel.h \ error.c error.h \ @@ -80,7 +80,7 @@ openvpn_SOURCES = \ occ.c occ.h occ-inline.h \ pkcs11.c pkcs11.h pkcs11_backend.h \ pkcs11_openssl.c \ - pkcs11_polarssl.c \ + pkcs11_mbedtls.c \ openvpn.c openvpn.h \ options.c options.h \ otime.c otime.h \ @@ -105,11 +105,11 @@ openvpn_SOURCES = \ socks.c socks.h \ ssl.c ssl.h ssl_backend.h \ ssl_openssl.c ssl_openssl.h \ - ssl_polarssl.c ssl_polarssl.h \ + ssl_mbedtls.c ssl_mbedtls.h \ ssl_common.h \ ssl_verify.c ssl_verify.h ssl_verify_backend.h \ ssl_verify_openssl.c ssl_verify_openssl.h \ - ssl_verify_polarssl.c ssl_verify_polarssl.h \ + ssl_verify_mbedtls.c ssl_verify_mbedtls.h \ status.c status.h \ syshead.h \ tun.c tun.h \ diff --git a/src/openvpn/crypto_backend.h b/src/openvpn/crypto_backend.h index c4986f558e5..3893f140244 100644 --- a/src/openvpn/crypto_backend.h +++ b/src/openvpn/crypto_backend.h @@ -34,7 +34,7 @@ #include "crypto_openssl.h" #endif #ifdef ENABLE_CRYPTO_MBEDTLS -#include "crypto_polarssl.h" +#include "crypto_mbedtls.h" #endif #include "basic.h" diff --git a/src/openvpn/crypto_polarssl.c b/src/openvpn/crypto_mbedtls.c similarity index 100% rename from src/openvpn/crypto_polarssl.c rename to src/openvpn/crypto_mbedtls.c diff --git a/src/openvpn/crypto_polarssl.h b/src/openvpn/crypto_mbedtls.h similarity index 100% rename from src/openvpn/crypto_polarssl.h rename to src/openvpn/crypto_mbedtls.h diff --git a/src/openvpn/pkcs11_polarssl.c b/src/openvpn/pkcs11_mbedtls.c similarity index 100% rename from src/openvpn/pkcs11_polarssl.c rename to src/openvpn/pkcs11_mbedtls.c diff --git a/src/openvpn/plugin.h b/src/openvpn/plugin.h index 74ac8b1e566..3c010476afe 100644 --- a/src/openvpn/plugin.h +++ b/src/openvpn/plugin.h @@ -33,7 +33,7 @@ #include "ssl_verify_openssl.h" #endif #ifdef ENABLE_CRYPTO_MBEDTLS -#include "ssl_verify_polarssl.h" +#include "ssl_verify_mbedtls.h" #endif #include "openvpn-plugin.h" diff --git a/src/openvpn/ssl_backend.h b/src/openvpn/ssl_backend.h index dfccb4472cd..542c373d6f4 100644 --- a/src/openvpn/ssl_backend.h +++ b/src/openvpn/ssl_backend.h @@ -39,8 +39,8 @@ #define SSLAPI SSLAPI_OPENSSL #endif #ifdef ENABLE_CRYPTO_MBEDTLS -#include "ssl_polarssl.h" -#include "ssl_verify_polarssl.h" +#include "ssl_mbedtls.h" +#include "ssl_verify_mbedtls.h" #define SSLAPI SSLAPI_MBEDTLS #endif diff --git a/src/openvpn/ssl_polarssl.c b/src/openvpn/ssl_mbedtls.c similarity index 99% rename from src/openvpn/ssl_polarssl.c rename to src/openvpn/ssl_mbedtls.c index 483ec1cd38a..9da33adfea9 100644 --- a/src/openvpn/ssl_polarssl.c +++ b/src/openvpn/ssl_mbedtls.c @@ -48,7 +48,7 @@ #include -#include "ssl_verify_polarssl.h" +#include "ssl_verify_mbedtls.h" #include #include #include diff --git a/src/openvpn/ssl_polarssl.h b/src/openvpn/ssl_mbedtls.h similarity index 100% rename from src/openvpn/ssl_polarssl.h rename to src/openvpn/ssl_mbedtls.h diff --git a/src/openvpn/ssl_verify.h b/src/openvpn/ssl_verify.h index 5eb18435295..f693b2a4874 100644 --- a/src/openvpn/ssl_verify.h +++ b/src/openvpn/ssl_verify.h @@ -41,7 +41,7 @@ #include "ssl_verify_openssl.h" #endif #ifdef ENABLE_CRYPTO_MBEDTLS -#include "ssl_verify_polarssl.h" +#include "ssl_verify_mbedtls.h" #endif #include "ssl_verify_backend.h" diff --git a/src/openvpn/ssl_verify_polarssl.c b/src/openvpn/ssl_verify_mbedtls.c similarity index 99% rename from src/openvpn/ssl_verify_polarssl.c rename to src/openvpn/ssl_verify_mbedtls.c index ff76d3d38b9..ffe196ec08f 100644 --- a/src/openvpn/ssl_verify_polarssl.c +++ b/src/openvpn/ssl_verify_mbedtls.c @@ -37,7 +37,7 @@ #if defined(ENABLE_CRYPTO) && defined(ENABLE_CRYPTO_MBEDTLS) -#include "crypto_polarssl.h" +#include "crypto_mbedtls.h" #include "ssl_verify.h" #include #include diff --git a/src/openvpn/ssl_verify_polarssl.h b/src/openvpn/ssl_verify_mbedtls.h similarity index 100% rename from src/openvpn/ssl_verify_polarssl.h rename to src/openvpn/ssl_verify_mbedtls.h From 645071ae9fac091a62eecd43d6ac5d5fdd4ab91c Mon Sep 17 00:00:00 2001 From: Jens Neuhalfen Date: Fri, 29 Apr 2016 13:16:36 +0200 Subject: [PATCH 233/643] ignore the local config file t_client.rc in git t_client.rc is a config file used in integration tests (t_client.sh). It is a local (developer/machine) specific file not intended to be verisonized. A template file can be found at ./tests/t_client.rc-sample Signed-off-by: Jens Neuhalfen Acked-by: Steffan Karger Message-Id: <80711231-C760-410A-B8A5-F2B1D46C22CE@neuhalfen.name> Signed-off-by: Gert Doering --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index e154092f29e..0eea06e0109 100644 --- a/.gitignore +++ b/.gitignore @@ -51,8 +51,11 @@ config-msvc-local.h config-msvc-version.h doc/openvpn.8.html distro/rpm/openvpn.spec + tests/t_client.sh tests/t_client-*-20??????-??????/ +t_client.rc + src/openvpn/openvpn include/openvpn-plugin.h config-version.h From e860059baa912ced7acf00f9b1e85a3d80dc0b1f Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sun, 1 May 2016 20:23:06 +0200 Subject: [PATCH 234/643] configure.ac: link to all mbed TLS libs during library detection When for some reason the dependencies of the compiled mbed TLS libaries (libmbedtls, libmbedcrypto and libmbedx509) are not correct, the configure script will fail to link against libmbedcrypto and/or libmbedx509. This is reported to happen after using 'make install' to install mbedtls. This patch makes sure the configure tests link to all three. The build process itself already did. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1462126986-2686-1-git-send-email-steffan@karger.me> Signed-off-by: Gert Doering --- configure.ac | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index f2c61fee2d0..30f6cfcbdbb 100644 --- a/configure.ac +++ b/configure.ac @@ -843,7 +843,8 @@ elif test "${with_crypto_library}" = "mbedtls"; then saved_LIBS="${LIBS}" if test -z "${MBEDTLS_CFLAGS}" -a -z "${MBEDTLS_LIBS}"; then - # if the user did not explicitly specify flags, try to autodetect + # if the user did not explicitly specify flags, try to autodetect + LIBS="${LIBS} -lmbedtls -lmbedcrypto -lmbedx509" AC_CHECK_LIB( [mbedtls], [mbedtls_ssl_init], From 5c4acf3f7b2885270a9fb2d051a18759ab458c32 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Thu, 5 May 2016 11:02:13 +0200 Subject: [PATCH 235/643] mbedtls: check that private key and certificate match on start Implement a long standing todo in the code, now that we use mbed TLS 2.x, which provides an interface for the check. v2: bail out immediately on failure. Signed-off-by: Steffan Karger Acked-by: Arne Schwabe Message-Id: <1462438933-14902-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/11599 Signed-off-by: Gert Doering --- src/openvpn/ssl_mbedtls.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/openvpn/ssl_mbedtls.c b/src/openvpn/ssl_mbedtls.c index 9da33adfea9..b5e7a6a72cc 100644 --- a/src/openvpn/ssl_mbedtls.c +++ b/src/openvpn/ssl_mbedtls.c @@ -363,11 +363,12 @@ tls_ctx_load_priv_file (struct tls_root_ctx *ctx, const char *priv_key_file, warn_if_group_others_accessible (priv_key_file); - /* TODO: Check Private Key */ -#if 0 - if (!SSL_CTX_check_private_key (ctx)) - msg (M_SSLERR, "Private key does not match the certificate"); -#endif + if (!mbed_ok(mbedtls_pk_check_pair(&ctx->crt_chain->pk, ctx->priv_key))) + { + msg (M_WARN, "Private key does not match the certificate"); + return 1; + } + return 0; } From 524999ab35c79f0d9732647756ad6e4d4e11d73d Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Tue, 3 May 2016 22:14:38 +0200 Subject: [PATCH 236/643] mbedtls: improve error reporting in tls verify callback Instead of just printing the contents of the flags variable, try to convert it to a human-readable error string and print that instead. This will for example print "The certificate is signed with an unacceptable key (eg bad curve, RSA too short).", instead of "flags=10000". Signed-off-by: Steffan Karger Acked-by: Arne Schwabe Acked-by: Gert Doering Message-Id: <1462306478-21059-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/11594 Signed-off-by: Gert Doering --- Changes.rst | 5 ++++- src/openvpn/ssl_verify_mbedtls.c | 20 +++++++++++++++++--- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/Changes.rst b/Changes.rst index 5034b156b3e..dc9131b8426 100644 --- a/Changes.rst +++ b/Changes.rst @@ -91,10 +91,13 @@ User-visible Changes * Non-ephemeral key exchange using static (EC)DH keys * DSS private keys -- PolarSSL builds: changed the tls_digest_N values exported to the script +- mbed TLS builds: changed the tls_digest_N values exported to the script environment to be equal to the ones exported by OpenSSL builds, namely the certificate fingerprint (was the hash of the 'to be signed' data). +- mbed TLS builds: minimum RSA key size is now 2048 bits. Shorter keys will + not be accepted, both local and from the peer. + Maintainer-visible changes -------------------------- diff --git a/src/openvpn/ssl_verify_mbedtls.c b/src/openvpn/ssl_verify_mbedtls.c index ffe196ec08f..e59dedbc1d8 100644 --- a/src/openvpn/ssl_verify_mbedtls.c +++ b/src/openvpn/ssl_verify_mbedtls.c @@ -65,13 +65,27 @@ verify_callback (void *session_obj, mbedtls_x509_crt *cert, int cert_depth, /* did peer present cert which was signed by our root cert? */ if (*flags != 0) { + int ret = 0; + char errstr[512] = { 0 }; char *subject = x509_get_subject(cert, &gc); + ret = mbedtls_x509_crt_verify_info (errstr, sizeof(errstr)-1, "", *flags); + if (ret <= 0 && !openvpn_snprintf(errstr, sizeof(errstr), + "Could not retrieve error string, flags=%"PRIx32, *flags)) + { + errstr[0] = '\0'; + } + if (subject) - msg (D_TLS_ERRORS, "VERIFY ERROR: depth=%d, flags=%x, %s", cert_depth, *flags, subject); + { + msg (D_TLS_ERRORS, "VERIFY ERROR: depth=%d, subject=%s: %s", + cert_depth, subject, errstr); + } else - msg (D_TLS_ERRORS, "VERIFY ERROR: depth=%d, flags=%x, could not extract X509 " - "subject string from certificate", *flags, cert_depth); + { + msg (D_TLS_ERRORS, "VERIFY ERROR: depth=%d, (could not extract X509 " + "subject string from certificate): %s", cert_depth, errstr); + } /* Leave flags set to non-zero to indicate that the cert is not ok */ } From 1ae17b7e97881ab57352b0bd525f15e6e9b60011 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Thu, 5 May 2016 13:48:16 +0200 Subject: [PATCH 237/643] Fix library order in -lmbedtls test. -lmbedx509 needs to be before -lmbedcrypto, otherwise you end up with unresolved symbols mbedtls_pk_load_file and mbedtls_pk_parse_subpubkey on systems with static mbedtls libraries and a linker that only does one left-to-right resolving pass through these. Signed-off-by: Gert Doering Acked-by: Steffan Karger Message-Id: <20160505115050.GA81579@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/11605 Signed-off-by: Gert Doering --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 30f6cfcbdbb..97ad85606f9 100644 --- a/configure.ac +++ b/configure.ac @@ -844,11 +844,11 @@ elif test "${with_crypto_library}" = "mbedtls"; then if test -z "${MBEDTLS_CFLAGS}" -a -z "${MBEDTLS_LIBS}"; then # if the user did not explicitly specify flags, try to autodetect - LIBS="${LIBS} -lmbedtls -lmbedcrypto -lmbedx509" + LIBS="${LIBS} -lmbedtls -lmbedx509 -lmbedcrypto" AC_CHECK_LIB( [mbedtls], [mbedtls_ssl_init], - [MBEDTLS_LIBS="-lmbedtls -lmbedcrypto -lmbedx509"], + [MBEDTLS_LIBS="-lmbedtls -lmbedx509 -lmbedcrypto"], [AC_MSG_ERROR([Could not find mbed TLS.])], [${PKCS11_HELPER_LIBS}] ) From d54a2488a0b7a678817b50e1518d0f31397b2e7b Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Thu, 5 May 2016 15:02:27 +0200 Subject: [PATCH 238/643] Remove trailing newline from verify callback error messages Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1462453347-3272-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/11609 Signed-off-by: Gert Doering --- src/openvpn/ssl_verify_mbedtls.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/openvpn/ssl_verify_mbedtls.c b/src/openvpn/ssl_verify_mbedtls.c index e59dedbc1d8..9c4b51a7871 100644 --- a/src/openvpn/ssl_verify_mbedtls.c +++ b/src/openvpn/ssl_verify_mbedtls.c @@ -75,6 +75,10 @@ verify_callback (void *session_obj, mbedtls_x509_crt *cert, int cert_depth, { errstr[0] = '\0'; } + else + { + chomp(errstr); + } if (subject) { From f40f10ea9607934faeb2b8cd84aefff0e0790189 Mon Sep 17 00:00:00 2001 From: Jens Neuhalfen Date: Sun, 8 May 2016 18:17:48 +0200 Subject: [PATCH 239/643] Prevent integration test timeout bc. of sudo Integration tests run by t_client.sh use sudo to run openvpn as root. If the t_client.sh script is configured to use sudo then the user must enter the password quickly because t_client assumes a startup failure if openvpn does not start quick enough. If the user is not quick enough, then the tests fails. This change will refresh the sudo timestamp at the start of the script. Tested on MacOS X & Ubuntu Precise Signed-off-by: Jens Neuhalfen Acked-by: Gert Doering Message-Id: <280154CA-9468-429B-BCAC-DB632C0AFB32@neuhalfen.name> URL: http://article.gmane.org/gmane.network.openvpn.devel/11622 Signed-off-by: Gert Doering --- tests/t_client.sh.in | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/t_client.sh.in b/tests/t_client.sh.in index d4f7c4ab330..9a0af93a0d1 100755 --- a/tests/t_client.sh.in +++ b/tests/t_client.sh.in @@ -69,6 +69,11 @@ else echo "$0: this test must run be as root, or RUN_SUDO=... " >&2 echo " must be set correctly in 't_client.rc'. SKIP." >&2 exit 77 + else + # We have to use sudo. Make sure that we (hopefully) do not have + # to ask the users password during the test. This is done to + # prevent timing issues, e.g. when the waits for openvpn to start + $RUN_SUDO \true fi fi From 007738e9d6030c8989713543e4f7308ff57be30f Mon Sep 17 00:00:00 2001 From: James Yonan Date: Thu, 3 Mar 2016 00:48:12 -0700 Subject: [PATCH 240/643] Fixed port-share bug with DoS potential Fixed port-share bug that can cause segfault when the number of concurrent connections is large. The issue is that the port-share code calls openvpn_connect() which in turn calls select(). When there are a high number of concurrent port-share connections, the fd passed to select can potentially exceed FD_SETSIZE, causing undefined behavior. The fix is to use poll() (if available) instead of select(). Signed-off-by: James Yonan Acked-by: Steffan Karger Acked-by: Gert Doering Message-Id: URL: http://article.gmane.org/gmane.network.openvpn.devel/11626 Signed-off-by: Gert Doering --- src/openvpn/socket.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c index 9bcf4d43953..f7264ef6223 100644 --- a/src/openvpn/socket.c +++ b/src/openvpn/socket.c @@ -1149,6 +1149,12 @@ openvpn_connect (socket_descriptor_t sd, { while (true) { +#if POLL + struct pollfd fds[1]; + fds[0].fd = sd; + fds[0].events = POLLOUT; + status = poll(fds, 1, 0); +#else fd_set writes; struct timeval tv; @@ -1158,7 +1164,7 @@ openvpn_connect (socket_descriptor_t sd, tv.tv_usec = 0; status = select (sd + 1, NULL, &writes, NULL, &tv); - +#endif if (signal_received) { get_signal (signal_received); From e7ec6a3a11ecee54cb10de789668dd37c3f9fc54 Mon Sep 17 00:00:00 2001 From: Dorian Harmans Date: Fri, 13 May 2016 18:44:52 +0200 Subject: [PATCH 241/643] Add CHACHA20-POLY1305 ciphersuite IANA name translations. Acked-by: Steffan Karger Message-Id: <1463157892-701-1-git-send-email-dorian@woohooyeah.nl> URL: http://article.gmane.org/gmane.network.openvpn.devel/11651 Signed-off-by: Gert Doering --- src/openvpn/ssl.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index ddd0c9bc502..429131480de 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -146,6 +146,7 @@ static const tls_cipher_name_pair tls_cipher_name_translation_table[] = { {"DHE-RSA-CAMELLIA128-SHA", "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA"}, {"DHE-RSA-CAMELLIA256-SHA256", "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256"}, {"DHE-RSA-CAMELLIA256-SHA", "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA"}, + {"DHE-RSA-CHACHA20-POLY1305", "TLS-DHE-RSA-WITH-CHACHA20-POLY1305-SHA256"}, {"DHE-RSA-SEED-SHA", "TLS-DHE-RSA-WITH-SEED-CBC-SHA"}, {"DH-RSA-SEED-SHA", "TLS-DH-RSA-WITH-SEED-CBC-SHA"}, {"ECDH-ECDSA-AES128-GCM-SHA256", "TLS-ECDH-ECDSA-WITH-AES-128-GCM-SHA256"}, @@ -174,6 +175,7 @@ static const tls_cipher_name_pair tls_cipher_name_translation_table[] = { {"ECDHE-ECDSA-CAMELLIA128-SHA", "TLS-ECDHE-ECDSA-WITH-CAMELLIA-128-CBC-SHA"}, {"ECDHE-ECDSA-CAMELLIA256-SHA256", "TLS-ECDHE-ECDSA-WITH-CAMELLIA-256-CBC-SHA256"}, {"ECDHE-ECDSA-CAMELLIA256-SHA", "TLS-ECDHE-ECDSA-WITH-CAMELLIA-256-CBC-SHA"}, + {"ECDHE-ECDSA-CHACHA20-POLY1305", "TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256"}, {"ECDHE-ECDSA-DES-CBC3-SHA", "TLS-ECDHE-ECDSA-WITH-3DES-EDE-CBC-SHA"}, {"ECDHE-ECDSA-DES-CBC-SHA", "TLS-ECDHE-ECDSA-WITH-DES-CBC-SHA"}, {"ECDHE-ECDSA-RC4-SHA", "TLS-ECDHE-ECDSA-WITH-RC4-128-SHA"}, @@ -189,6 +191,7 @@ static const tls_cipher_name_pair tls_cipher_name_translation_table[] = { {"ECDHE-RSA-CAMELLIA128-SHA", "TLS-ECDHE-RSA-WITH-CAMELLIA-128-CBC-SHA"}, {"ECDHE-RSA-CAMELLIA256-SHA256", "TLS-ECDHE-RSA-WITH-CAMELLIA-256-CBC-SHA256"}, {"ECDHE-RSA-CAMELLIA256-SHA", "TLS-ECDHE-RSA-WITH-CAMELLIA-256-CBC-SHA"}, + {"ECDHE-RSA-CHACHA20-POLY1305", "TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256"}, {"ECDHE-RSA-DES-CBC3-SHA", "TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA"}, {"ECDHE-RSA-DES-CBC-SHA", "TLS-ECDHE-RSA-WITH-DES-CBC-SHA"}, {"ECDHE-RSA-RC4-SHA", "TLS-ECDHE-RSA-WITH-RC4-128-SHA"}, From e3420d5683ffcc4386f78485bae3288a48f5cc17 Mon Sep 17 00:00:00 2001 From: Selva Nair Date: Fri, 13 May 2016 20:31:24 -0400 Subject: [PATCH 242/643] Make error non-fatal while deleting address using netsh During windows power events such as sleep or suspend, the TUN/TAP I/O aborts and openvpn signals SIGHUP so as to automatically reconnect on resume (since commit ea66a2b5cdb2..). During the SIGHUP processing operations such as address and route deletion are expected to fail. Such failures should be treated as non-fatal to allow for this automatic recovery logic to work. Currently, when the address deletion is handled by netsh, errors are treated as M_FATAL. This patch changes the error level to M_WARN. Resolves Trac #71 (comments 37 to 43) Signed-off-by: Selva Nair Acked-by: Gert Doering Message-Id: <1463185884-4355-2-git-send-email-selva.nair@gmail.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/11656 Signed-off-by: Gert Doering --- src/openvpn/tun.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index c87fb366736..f79d067a311 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -68,7 +68,7 @@ static void netsh_ifconfig (const struct tuntap_options *to, const in_addr_t ip, const in_addr_t netmask, const unsigned int flags); -static void netsh_command (const struct argv *a, int n); +static void netsh_command (const struct argv *a, int n, int msglevel); static const char *netsh_get_id (const char *dev_node, struct gc_arena *gc); @@ -1398,7 +1398,7 @@ do_ifconfig (struct tuntap *tt, NETSH_PATH_SUFFIX, iface, ifconfig_ipv6_local ); - netsh_command (&argv, 4); + netsh_command (&argv, 4, M_FATAL); } /* explicit route needed */ @@ -4597,7 +4597,7 @@ dhcp_renew (const struct tuntap *tt) */ static void -netsh_command (const struct argv *a, int n) +netsh_command (const struct argv *a, int n, int msglevel) { int i; for (i = 0; i < n; ++i) @@ -4612,7 +4612,7 @@ netsh_command (const struct argv *a, int n) return; openvpn_sleep (4); } - msg (M_FATAL, "NETSH: command failed"); + msg (msglevel, "NETSH: command failed"); } void @@ -4762,7 +4762,7 @@ netsh_ifconfig_options (const char *type, NETSH_PATH_SUFFIX, type, flex_name); - netsh_command (&argv, 2); + netsh_command (&argv, 2, M_FATAL); } /* add new DNS/WINS settings to TAP interface */ @@ -4783,7 +4783,7 @@ netsh_ifconfig_options (const char *type, type, flex_name, print_in_addr_t (addr_list[i], 0, &gc)); - netsh_command (&argv, 2); + netsh_command (&argv, 2, M_FATAL); ++count; } @@ -4858,7 +4858,7 @@ netsh_ifconfig (const struct tuntap_options *to, print_in_addr_t (ip, 0, &gc), print_in_addr_t (netmask, 0, &gc)); - netsh_command (&argv, 4); + netsh_command (&argv, 4, M_FATAL); } } @@ -4904,7 +4904,7 @@ netsh_enable_dhcp (const struct tuntap_options *to, NETSH_PATH_SUFFIX, actual_name); - netsh_command (&argv, 4); + netsh_command (&argv, 4, M_FATAL); argv_reset (&argv); } @@ -5648,7 +5648,7 @@ close_tun (struct tuntap *tt) tt->actual_name, ifconfig_ipv6_local); - netsh_command (&argv, 1); + netsh_command (&argv, 1, M_WARN); argv_reset (&argv); } } From 3e42a558103e4e3f45ed28ccb761cefed20e8247 Mon Sep 17 00:00:00 2001 From: Selva Nair Date: Thu, 10 Mar 2016 23:47:26 -0500 Subject: [PATCH 243/643] Add support for register-dns through interactive service The call to the service returns promptly after delegating the job to a thread, before the task is completed. In the thread, "net stop dnscache", "net start dnscache", "ipconfig /flushdns" and "ipconfig /register-dns" are executed in that order. Parallel execution of these commands is prevented by a lock that is common to all connections started by the service. Note: "net stop .." is used instead of "sc stop.." as the latter can return before the service has fully stopped (in STOP_PENDING state), causing the subsequent start to fail. Signed-off-by: Selva Nair Acked-by: Gert Doering Message-Id: <1457671646-4322-1-git-send-email-selva.nair@gmail.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/11354 Signed-off-by: Gert Doering --- include/openvpn-msg.h | 3 +- src/openvpn/tun.c | 35 +++++++- src/openvpnserv/interactive.c | 156 ++++++++++++++++++++++++++++++++++ 3 files changed, 192 insertions(+), 2 deletions(-) diff --git a/include/openvpn-msg.h b/include/openvpn-msg.h index 7470512a7e8..4c13acf3532 100644 --- a/include/openvpn-msg.h +++ b/include/openvpn-msg.h @@ -37,7 +37,8 @@ typedef enum { msg_del_nbt_cfg, msg_flush_neighbors, msg_add_block_dns, - msg_del_block_dns + msg_del_block_dns, + msg_register_dns } message_type_t; typedef struct { diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index f79d067a311..b7a29f718c1 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -5101,10 +5101,43 @@ fork_dhcp_action (struct tuntap *tt) } } +static void +register_dns_service (const struct tuntap *tt) +{ + DWORD len; + HANDLE msg_channel = tt->options.msg_channel; + ack_message_t ack; + struct gc_arena gc = gc_new (); + + message_header_t rdns = { msg_register_dns, sizeof(message_header_t), 0 }; + + if (!WriteFile (msg_channel, &rdns, sizeof (rdns), &len, NULL) || + !ReadFile (msg_channel, &ack, sizeof (ack), &len, NULL)) + { + msg (M_WARN, "Register_dns: could not talk to service: %s [status=0x%lx]", + strerror_win32 (GetLastError (), &gc), GetLastError ()); + } + + else if (ack.error_number != NO_ERROR) + { + msg (M_WARN, "Register_dns failed using service: %s [status=0x%x]", + strerror_win32 (ack.error_number, &gc), ack.error_number); + } + + else + msg (M_INFO, "Register_dns request sent to the service"); + + gc_free (&gc); +} + void fork_register_dns_action (struct tuntap *tt) { - if (tt && tt->options.register_dns) + if (tt && tt->options.register_dns && tt->options.msg_channel) + { + register_dns_service (tt); + } + else if (tt && tt->options.register_dns) { struct gc_arena gc = gc_new (); struct buffer cmd = alloc_buf_gc (256, &gc); diff --git a/src/openvpnserv/interactive.c b/src/openvpnserv/interactive.c index d83ea656050..df30ad7ca9e 100644 --- a/src/openvpnserv/interactive.c +++ b/src/openvpnserv/interactive.c @@ -50,6 +50,9 @@ static SERVICE_STATUS_HANDLE service; static SERVICE_STATUS status; static HANDLE exit_event = NULL; static settings_t settings; +static HANDLE rdns_semaphore = NULL; +#define RDNS_TIMEOUT 600 /* seconds to wait for the semaphore */ + openvpn_service_t interactive_service = { interactive, @@ -803,6 +806,147 @@ HandleBlockDNSMessage (const block_dns_message_t *msg, undo_lists_t *lists) return err; } +/* + * Execute a command and return its exit code. If timeout > 0, terminate + * the process if still running after timeout milliseconds. In that case + * the return value is the windows error code WAIT_TIMEOUT = 0x102 + */ +static DWORD +ExecCommand (const WCHAR *argv0, const WCHAR *cmdline, DWORD timeout) +{ + DWORD exit_code; + STARTUPINFOW si; + PROCESS_INFORMATION pi; + DWORD proc_flags = CREATE_NO_WINDOW|CREATE_UNICODE_ENVIRONMENT; + WCHAR *cmdline_dup = NULL; + + ZeroMemory (&si, sizeof(si)); + ZeroMemory (&pi, sizeof(pi)); + + si.cb = sizeof(si); + + /* CreateProcess needs a modifiable cmdline: make a copy */ + cmdline_dup = wcsdup (cmdline); + if ( cmdline_dup && CreateProcessW (argv0, cmdline_dup, NULL, NULL, FALSE, + proc_flags, NULL, NULL, &si, &pi) ) + { + WaitForSingleObject (pi.hProcess, timeout ? timeout : INFINITE); + if (!GetExitCodeProcess (pi.hProcess, &exit_code)) + { + MsgToEventLog (M_SYSERR, TEXT("ExecCommand: Error getting exit_code:")); + exit_code = GetLastError(); + } + else if (exit_code == STILL_ACTIVE) + { + exit_code = WAIT_TIMEOUT; /* Windows error code 0x102 */ + + /* kill without impunity */ + TerminateProcess (pi.hProcess, exit_code); + MsgToEventLog (M_ERR, TEXT("ExecCommand: \"%s %s\" killed after timeout"), + argv0, cmdline); + } + else if (exit_code) + MsgToEventLog (M_ERR, TEXT("ExecCommand: \"%s %s\" exited with status = %lu"), + argv0, cmdline, exit_code); + else + MsgToEventLog (M_INFO, TEXT("ExecCommand: \"%s %s\" completed"), argv0, cmdline); + + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + } + else + { + exit_code = GetLastError(); + MsgToEventLog (M_SYSERR, TEXT("ExecCommand: could not run \"%s %s\" :"), + argv0, cmdline); + } + + free (cmdline_dup); + return exit_code; +} + +/* + * Entry point for register-dns thread. + */ +static DWORD WINAPI +RegisterDNS (LPVOID unused) +{ + DWORD err; + DWORD i; + WCHAR sys_path[MAX_PATH]; + DWORD timeout = RDNS_TIMEOUT * 1000; /* in milliseconds */ + + /* default paths of net and ipconfig commands */ + WCHAR net[MAX_PATH] = L"C:\\Windows\\system32\\net.exe"; + WCHAR ipcfg[MAX_PATH] = L"C:\\Windows\\system32\\ipconfig.exe"; + + struct + { + WCHAR *argv0; + WCHAR *cmdline; + DWORD timeout; + } cmds [] = { + { net, L"net stop dnscache", timeout }, + { net, L"net start dnscache", timeout }, + { ipcfg, L"ipconfig /flushdns", timeout }, + { ipcfg, L"ipconfig /registerdns", timeout }, + }; + int ncmds = sizeof (cmds) / sizeof (cmds[0]); + + HANDLE wait_handles[2] = {rdns_semaphore, exit_event}; + + if(GetSystemDirectory(sys_path, MAX_PATH)) + { + _snwprintf (net, MAX_PATH, L"%s\\%s", sys_path, L"net.exe"); + net[MAX_PATH-1] = L'\0'; + + _snwprintf (ipcfg, MAX_PATH, L"%s\\%s", sys_path, L"ipconfig.exe"); + ipcfg[MAX_PATH-1] = L'\0'; + } + + if (WaitForMultipleObjects (2, wait_handles, FALSE, timeout) == WAIT_OBJECT_0) + { + /* Semaphore locked */ + for (i = 0; i < ncmds; ++i) + { + ExecCommand (cmds[i].argv0, cmds[i].cmdline, cmds[i].timeout); + } + err = 0; + if ( !ReleaseSemaphore (rdns_semaphore, 1, NULL) ) + err = MsgToEventLog (M_SYSERR, TEXT("RegisterDNS: Failed to release regsiter-dns semaphore:")); + } + else + { + MsgToEventLog (M_ERR, TEXT("RegisterDNS: Failed to lock register-dns semaphore")); + err = ERROR_SEM_TIMEOUT; /* Windows error code 0x79 */ + } + return err; +} + +static DWORD +HandleRegisterDNSMessage (void) +{ + DWORD err; + HANDLE thread = NULL; + + /* Delegate this job to a sub-thread */ + thread = CreateThread (NULL, 0, RegisterDNS, NULL, 0, NULL); + + /* + * We don't add these thread handles to the undo list -- the thread and + * processes it spawns are all supposed to terminate or timeout by themselves. + */ + if (thread) + { + err = 0; + CloseHandle (thread); + } + else + err = GetLastError(); + + return err; +} + static VOID HandleMessage (HANDLE pipe, DWORD bytes, DWORD count, LPHANDLE events, undo_lists_t *lists) { @@ -854,6 +998,10 @@ HandleMessage (HANDLE pipe, DWORD bytes, DWORD count, LPHANDLE events, undo_list ack.error_number = HandleBlockDNSMessage (&msg.block_dns, lists); break; + case msg_register_dns: + ack.error_number = HandleRegisterDNSMessage (); + break; + default: ack.error_number = ERROR_MESSAGE_TYPE; MsgToEventLog (MSG_FLAGS_ERROR, TEXT("Unknown message type %d"), msg.header.type); @@ -1381,6 +1529,13 @@ ServiceStartInteractive (DWORD dwArgc, LPTSTR *lpszArgv) goto out; } + rdns_semaphore = CreateSemaphoreW (NULL, 1, 1, NULL); + if (!rdns_semaphore) + { + error = MsgToEventLog (M_SYSERR, TEXT("Could not create semaphore for register-dns")); + goto out; + } + error = UpdateWaitHandles (&handles, &handle_count, io_event, exit_event, threads); if (error != NO_ERROR) goto out; @@ -1458,6 +1613,7 @@ ServiceStartInteractive (DWORD dwArgc, LPTSTR *lpszArgv) FreeWaitHandles (handles); CloseHandleEx (&io_event); CloseHandleEx (&exit_event); + CloseHandleEx (&rdns_semaphore); status.dwCurrentState = SERVICE_STOPPED; status.dwWin32ExitCode = error; From 970312f185012341cc5bcc9492ab3e1413c7b3c7 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Mon, 16 May 2016 12:13:04 +0200 Subject: [PATCH 244/643] Implement push-remove option to selectively remove pushed options. With this option, the server can remove individual options from the set pushed to a client (call from --client-config-dir file, or from --client-connect script or plugin). Options are removed at parse time, so it is possible to do stuff like: push-remove route-ipv6 push "route-ipv6 fd00::/8" to first remove all IPv6 route options set so far, then add something specific (what "push-reset" does to all the options). Arguments to push-remove are strncmp()'ed to option string, so partial matches like push-remove "route-ipv6 2001:" are possible ("remove all IPv6 routes starting with 2001:"). Implementation of remove_iroutes_from_push_route_list() had to be changed slightly to stop it from re-enabling all disabled options again. v2: documentation (Changes.rst, doc/openvpn.8) remove surplus gc_arena implement filtering of "ifconfig-ipv6" v3: correct quoting in commit message only handle a single argument per push-remove statement - if multiple options are to be removed, just use multiple push-remove statements Trac #29, #614 Signed-off-by: Gert Doering Acked-by: Arne Schwabe Message-Id: <1463393584-8318-1-git-send-email-gert@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/11665 Signed-off-by: Gert Doering --- Changes.rst | 4 ++++ doc/openvpn.8 | 35 +++++++++++++++++++++++++++++++- src/openvpn/options.c | 6 ++++++ src/openvpn/options.h | 1 + src/openvpn/push.c | 47 ++++++++++++++++++++++++++++++++++++------- src/openvpn/push.h | 1 + 6 files changed, 86 insertions(+), 8 deletions(-) diff --git a/Changes.rst b/Changes.rst index dc9131b8426..a6bb2a54701 100644 --- a/Changes.rst +++ b/Changes.rst @@ -5,6 +5,10 @@ Version 2.4.0 New features ------------ +push-remove + new option to remove options on a per-client basis from the "push" list + (more fine-grained than "push-reset") + keying-material-exporter Keying Material Exporter [RFC-5705] allow additional keying material to be derived from existing TLS channel. diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 7d5dc5bf2b0..8d1b0622347 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -2965,6 +2965,39 @@ as with a configuration file. This option will ignore .B \-\-push options at the global config file level. +.\"********************************************************* +.TP +.B \-\-push\-remove opt +selectively remove all +.B \-\-push +options matching "opt" from the option list for a client. "opt" is matched +as a substring against the whole option string to-be-pushed to the client, so +.B \-\-push\-remove route +would remove all +.B \-\-push route ... +and +.B \-\-push route-ipv6 ... +statements, while +.B \-\-push\-remove 'route-ipv6 2001:' +would only remove IPv6 routes for 2001:... networks. + +.B \-\-push\-remove +can only be used in a client-specific context, like in a +.B \-\-client\-config\-dir +file, or +.B \-\-client\-connect +script or plugin -- similar to +.B \-\-push\-reset, +just more selective. + +NOTE: to +.I change +an option, +.B \-\-push\-remove +can be used to first remove the old value, and then add a new +.B \-\-push +option with the new value. +.\"********************************************************* .TP .B \-\-push\-peer\-info Push additional information about the client to server. The additional information @@ -3289,7 +3322,7 @@ without needing to restart the server. The following options are legal in a client-specific context: -.B \-\-push, \-\-push\-reset, \-\-iroute, \-\-ifconfig\-push, +.B \-\-push, \-\-push\-reset, \-\-push\-remove, \-\-iroute, \-\-ifconfig\-push, and .B \-\-config. .\"********************************************************* diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 764ca7407ba..55630c72878 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -5582,6 +5582,11 @@ add_option (struct options *options, VERIFY_PERMISSION (OPT_P_INSTANCE); push_reset (options); } + else if (streq (p[0], "push-remove") && p[1] && !p[2]) + { + VERIFY_PERMISSION (OPT_P_INSTANCE); + push_remove_option (options,p[1]); + } else if (streq (p[0], "ifconfig-pool") && p[1] && p[2] && !p[4]) { const int lev = M_WARN; @@ -5930,6 +5935,7 @@ add_option (struct options *options, options->push_ifconfig_ipv6_local = local; options->push_ifconfig_ipv6_netbits = netbits; options->push_ifconfig_ipv6_remote = remote; + options->push_ifconfig_ipv6_blocked = false; } else if (streq (p[0], "disable") && !p[1]) { diff --git a/src/openvpn/options.h b/src/openvpn/options.h index 18d8376a378..2fa375fd2b4 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -432,6 +432,7 @@ struct options struct in6_addr push_ifconfig_ipv6_local; /* IPv6 */ int push_ifconfig_ipv6_netbits; /* IPv6 */ struct in6_addr push_ifconfig_ipv6_remote; /* IPv6 */ + bool push_ifconfig_ipv6_blocked; /* IPv6 */ bool enable_c2c; bool duplicate_cn; int cf_max; diff --git a/src/openvpn/push.c b/src/openvpn/push.c index be4daa1b382..38ac59ee998 100644 --- a/src/openvpn/push.c +++ b/src/openvpn/push.c @@ -322,7 +322,8 @@ send_push_reply (struct context *c) buf_printf (&buf, "%s", cmd); - if ( c->c2.push_ifconfig_ipv6_defined ) + if ( c->c2.push_ifconfig_ipv6_defined && + !c->options.push_ifconfig_ipv6_blocked ) { /* IPv6 is put into buffer first, could be lengthy */ buf_printf( &buf, ",ifconfig-ipv6 %s/%d %s", @@ -483,6 +484,37 @@ push_reset (struct options *o) { CLEAR (o->push_list); } + +void +push_remove_option (struct options *o, const char *p) +{ + msg( D_PUSH, "PUSH_REMOVE '%s'", p ); + + /* ifconfig-ipv6 is special, as not part of the push list */ + if ( streq( p, "ifconfig-ipv6" )) + { + o->push_ifconfig_ipv6_blocked = true; + return; + } + + if (o && o->push_list.head ) + { + struct push_entry *e = o->push_list.head; + + /* cycle through the push list */ + while (e) + { + if ( e->enable && + strncmp( e->option, p, strlen(p) ) == 0 ) + { + msg (D_PUSH, "PUSH_REMOVE removing: '%s'", e->option); + e->enable = false; + } + + e = e->next; + } + } +} #endif #if P2MP_SERVER @@ -613,7 +645,8 @@ remove_iroutes_from_push_route_list (struct options *o) /* parse the push item */ CLEAR (p); - if (parse_line (e->option, p, SIZE (p), "[PUSH_ROUTE_REMOVE]", 1, D_ROUTE_DEBUG, &gc)) + if ( e->enable && + parse_line (e->option, p, SIZE (p), "[PUSH_ROUTE_REMOVE]", 1, D_ROUTE_DEBUG, &gc)) { /* is the push item a route directive? */ if (p[0] && !strcmp (p[0], "route") && !p[3]) @@ -639,12 +672,12 @@ remove_iroutes_from_push_route_list (struct options *o) } } } - } - /* should we copy the push item? */ - e->enable = enable; - if (!enable) - msg (D_PUSH, "REMOVE PUSH ROUTE: '%s'", e->option); + /* should we copy the push item? */ + e->enable = enable; + if (!enable) + msg (D_PUSH, "REMOVE PUSH ROUTE: '%s'", e->option); + } e = e->next; } diff --git a/src/openvpn/push.h b/src/openvpn/push.h index 19bbf5e1fcd..d6cb4b1e0e8 100644 --- a/src/openvpn/push.h +++ b/src/openvpn/push.h @@ -61,6 +61,7 @@ void push_option (struct options *o, const char *opt, int msglevel); void push_options (struct options *o, char **p, int msglevel, struct gc_arena *gc); void push_reset (struct options *o); +void push_remove_option (struct options *o, const char *p); void remove_iroutes_from_push_route_list (struct options *o); From 0d8a4ffa2293dda8139189725a5c49fbe0eb500b Mon Sep 17 00:00:00 2001 From: Josh Cepek Date: Mon, 18 Aug 2014 05:51:01 -0500 Subject: [PATCH 245/643] Push an IPv6 CIDR mask used by the server, not the pool's size Correctly handle CIDR masks when pushing clients addressing from an IPv6 pool. This change ignores the incorrectly used `bits` argument to the --ifconfig-ipv6-pool option. The code to save any provided CIDR mask after the pool IP is left in; this may someday become useful when we move to allow IPv6 pools without relying on an IPv4 pool assignment. Signed-off-by: Josh Cepek Acked-by: Arne Schwabe Acked-by: Gert Doering Message-Id: <53F1DA95.7020701@usa.net> URL: http://article.gmane.org/gmane.network.openvpn.devel/8990 Signed-off-by: Gert Doering --- doc/openvpn.8 | 5 +---- src/openvpn/multi.c | 6 +++--- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 8d1b0622347..e1dd7cde3cb 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -5799,10 +5799,7 @@ Is only accepted if ``\-\-mode server'' or ``\-\-server'' is set. Specify an IPv6 address pool for dynamic assignment to clients. The pool starts at .B ipv6addr -and increments by +1 for every new client (linear mode). The -.B /bits -setting controls the size of the pool. Due to implementation details, -the pool size must be between /64 and /112. +and matches the offset determined from the start of the IPv4 pool. .TP .B \-\-ifconfig\-ipv6\-push ipv6addr/bits ipv6remote for ccd/ per-client static IPv6 interface configuration, see diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index 6e6d45772bf..4c43fcc5b93 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -1431,10 +1431,10 @@ multi_select_virtual_addr (struct multi_context *m, struct multi_instance *mi) if ( mi->context.options.ifconfig_ipv6_pool_defined ) { mi->context.c2.push_ifconfig_ipv6_local = remote_ipv6; - mi->context.c2.push_ifconfig_ipv6_remote = + mi->context.c2.push_ifconfig_ipv6_remote = mi->context.c1.tuntap->local_ipv6; - mi->context.c2.push_ifconfig_ipv6_netbits = - mi->context.options.ifconfig_ipv6_pool_netbits; + mi->context.c2.push_ifconfig_ipv6_netbits = + mi->context.options.ifconfig_ipv6_netbits; mi->context.c2.push_ifconfig_ipv6_defined = true; } } From 698f0dab76741f4ce8c1a98236786d59eca338ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuli=20Sepp=C3=A4nen?= Date: Thu, 19 May 2016 11:51:49 +0300 Subject: [PATCH 246/643] Update CONTRIBUTING.rst to allow GitHub PRs for code review purposes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Samuli Seppänen Acked-by: Gert Doering Message-Id: <1463647909-18383-1-git-send-email-samuli@openvpn.net> URL: http://article.gmane.org/gmane.network.openvpn.devel/11679 Signed-off-by: Gert Doering --- CONTRIBUTING.rst | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 6033097f4ad..f87293ca5f5 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -4,15 +4,19 @@ CONTRIBUTING TO THE OPENVPN PROJECT Patches should be written against the Git "master" branch. Some patches may get backported to a release branch. -We do not currently accept GitHub pull requests for the core OpenVPN project. -Instead, all patches must be sent to "openvpn-devel" mailing list for review: +The preferred procedure to send patches to the "openvpn-devel" mailing list: - https://lists.sourceforge.net/lists/listinfo/openvpn-devel -The subject line should preferably be prefixed with [PATCH]. To avoid merging -issues the patches should be generated with git-format-patch or sent using -git-send-email. Try to split large patches into small, atomic pieces to make -reviews easier. +While we do not merge GitHub pull requests as-is, we do allow their use for code +review purposes. After the patch has been ACKed (reviewed and accepted), it must +be sent to the mailing list. This last step does not necessarily need to be done +by the patch author, although that is definitely recommended. + +When sending patches to "openvpn-devel" the subject line should be prefixed with +[PATCH]. To avoid merging issues the patches should be generated with +git-format-patch or sent using git-send-email. Try to split large patches into +small, atomic pieces to make reviews easier. If you want quick feedback on a patch before sending it to openvpn-devel mailing list, you can visit the #openvpn-devel channel on irc.freenode.net. Note that From 600dd9a16fc61ff6e595f500fba5daf14248b739 Mon Sep 17 00:00:00 2001 From: Selva Nair Date: Sun, 22 May 2016 14:39:32 -0400 Subject: [PATCH 247/643] Fix handling of out of memory error in interactive service Currently realloc failure in UpdateWaitHandles() is handled by triggering exit_event and waiting for all active worker threads to terminate. However, at this point the wait handles array will contain an invalid value (handle of the latest thread that is terminated), causing a cycle of WAIT_FAILED <-> continue and trashing of the eventlog. Fix: - Update the wait handles again after removing the last thread: this should not fail as no extra memory is needed. Do not set the exit event; existing connections are not terminated. - In case of WAIT_FAILED, break out of the while loop and exit instead of continue. This usually happens when one or more handles are invalid, which is hard to recover from. Other changes: - Use minimal initial allocation size so that the realloc code path gets exercised (2 or more connections will cause realloc). - Use a temp variable to check the return value of realloc(). - Initialize handles array pointer to NULL. v2 changes: - Increased initial allocation to 10 (warn: now 10 or more connections needed to exercise the realloc code path). - Moved up the declaration of "LPHANDLE tmp" to please stone-age MSVC. Tested using a dummy realloc that returns NULL. Signed-off-by: Selva Nair Acked-by: Gert Doering Message-Id: <1463942372-26958-1-git-send-email-selva.nair@gmail.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/11708 Signed-off-by: Gert Doering --- src/openvpnserv/interactive.c | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/src/openvpnserv/interactive.c b/src/openvpnserv/interactive.c index df30ad7ca9e..2453f176646 100644 --- a/src/openvpnserv/interactive.c +++ b/src/openvpnserv/interactive.c @@ -1460,6 +1460,7 @@ UpdateWaitHandles (LPHANDLE *handles_ptr, LPDWORD count, if (handles == NULL) { handles = malloc (size * sizeof (HANDLE)); + *handles_ptr = handles; if (handles == NULL) return ERROR_OUTOFMEMORY; } @@ -1473,16 +1474,22 @@ UpdateWaitHandles (LPHANDLE *handles_ptr, LPDWORD count, { if (pos == size) { + LPHANDLE tmp; size += 10; - handles = realloc (handles, size * sizeof (HANDLE)); - if (handles == NULL) - return ERROR_OUTOFMEMORY; + tmp = realloc (handles, size * sizeof (HANDLE)); + if (tmp == NULL) + { + size -= 10; + *count = pos; + return ERROR_OUTOFMEMORY; + } + handles = tmp; + *handles_ptr = handles; } handles[pos++] = threads->data; threads = threads->next; } - *handles_ptr = handles; *count = pos; return NO_ERROR; } @@ -1502,8 +1509,9 @@ ServiceStartInteractive (DWORD dwArgc, LPTSTR *lpszArgv) OVERLAPPED overlapped; DWORD error = NO_ERROR; list_item_t *threads = NULL; - PHANDLE handles; + PHANDLE handles = NULL; DWORD handle_count; + BOOL CmpHandle (LPVOID item, LPVOID hnd) { return item == hnd; } service = RegisterServiceCtrlHandlerEx (interactive_service.name, ServiceCtrlInteractive, &status); if (!service) @@ -1566,14 +1574,18 @@ ServiceStartInteractive (DWORD dwArgc, LPTSTR *lpszArgv) HANDLE thread = CreateThread (NULL, 0, RunOpenvpn, pipe, CREATE_SUSPENDED, NULL); if (thread) { - error = AddListItem (&threads, thread) || - UpdateWaitHandles (&handles, &handle_count, io_event, exit_event, threads); + error = AddListItem (&threads, thread); + if (!error) + error = UpdateWaitHandles (&handles, &handle_count, io_event, exit_event, threads); if (error) { + ReturnError (pipe, error, L"Insufficient resources to service new clients", 1, &exit_event); + /* Update wait handles again after removing the last worker thread */ + RemoveListItem (&threads, CmpHandle, thread); + UpdateWaitHandles (&handles, &handle_count, io_event, exit_event, threads); TerminateThread (thread, 1); CloseHandleEx (&thread); CloseHandleEx (&pipe); - SetEvent (exit_event); } else ResumeThread (thread); @@ -1590,7 +1602,10 @@ ServiceStartInteractive (DWORD dwArgc, LPTSTR *lpszArgv) if (error == WAIT_FAILED) { MsgToEventLog (M_SYSERR, TEXT("WaitForMultipleObjects failed")); - continue; + SetEvent (exit_event); + /* Give some time for worker threads to exit and then terminate */ + Sleep (1000); + break; } if (!threads) { @@ -1602,7 +1617,6 @@ ServiceStartInteractive (DWORD dwArgc, LPTSTR *lpszArgv) } /* Worker thread ended */ - BOOL CmpHandle (LPVOID item, LPVOID hnd) { return item == hnd; } HANDLE thread = RemoveListItem (&threads, CmpHandle, handles[error]); UpdateWaitHandles (&handles, &handle_count, io_event, exit_event, threads); CloseHandleEx (&thread); From 40cb4cfc5d011102daec61ab39583cba0eeb3077 Mon Sep 17 00:00:00 2001 From: Jens Neuhalfen Date: Wed, 25 May 2016 19:57:55 +0200 Subject: [PATCH 248/643] Add unit testing support via cmocka cmocka [1,2] is a testing framework for C. Adding unit test capabilities to the openvpn repository will greatly ease the task of writing correct code. cmocka source code is added as git submodule in ./vendor. A submodule approach has been chosen over a classical library dependency because libcmocka is not available, or only available in very old versions (e.g. on Ubuntu). cmocka is build during 'make check' and installed in vendor/dist/. [1] https://cmocka.org/ [2] https://lwn.net/Articles/558106/ Signed-off-by: Jens Neuhalfen Acked-by: Steffan Karger Message-Id: <20160525175756.56186-2-openvpn-devel@neuhalfen.name> URL: http://article.gmane.org/gmane.network.openvpn.devel/11725 Signed-off-by: David Sommerseth --- .gitmodules | 4 ++ Makefile.am | 2 +- configure.ac | 16 ++++++++ tests/Makefile.am | 3 +- tests/unit_tests/.gitignore | 1 + tests/unit_tests/Makefile.am | 3 ++ tests/unit_tests/README.md | 40 ++++++++++++++++++++ tests/unit_tests/example_test/Makefile.am | 13 +++++++ tests/unit_tests/example_test/README.md | 3 ++ tests/unit_tests/example_test/test.c | 46 +++++++++++++++++++++++ tests/unit_tests/example_test/test2.c | 21 +++++++++++ vendor/.gitignore | 2 + vendor/Makefile.am | 24 ++++++++++++ vendor/README.md | 8 ++++ vendor/cmocka | 1 + 15 files changed, 185 insertions(+), 2 deletions(-) create mode 100644 .gitmodules create mode 100644 tests/unit_tests/.gitignore create mode 100644 tests/unit_tests/Makefile.am create mode 100644 tests/unit_tests/README.md create mode 100644 tests/unit_tests/example_test/Makefile.am create mode 100644 tests/unit_tests/example_test/README.md create mode 100644 tests/unit_tests/example_test/test.c create mode 100644 tests/unit_tests/example_test/test2.c create mode 100644 vendor/.gitignore create mode 100644 vendor/Makefile.am create mode 100644 vendor/README.md create mode 160000 vendor/cmocka diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000000..e9c63884c72 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "vendor/cmocka"] + path = vendor/cmocka + url = git://git.cryptomilk.org/projects/cmocka.git + branch = master diff --git a/Makefile.am b/Makefile.am index 66d9f23a230..364785c40be 100644 --- a/Makefile.am +++ b/Makefile.am @@ -54,7 +54,7 @@ BUILT_SOURCES = \ config-version.h endif -SUBDIRS = build distro include src sample doc tests +SUBDIRS = build distro include src sample doc vendor tests dist_doc_DATA = \ README \ diff --git a/configure.ac b/configure.ac index 97ad85606f9..fb3fa3cdd8e 100644 --- a/configure.ac +++ b/configure.ac @@ -1198,6 +1198,19 @@ sampledir="\$(docdir)/sample" AC_SUBST([plugindir]) AC_SUBST([sampledir]) +VENDOR_SRC_ROOT="\$(abs_top_srcdir)/vendor/" +VENDOR_DIST_ROOT="\$(abs_top_builddir)/vendor/dist" +VENDOR_BUILD_ROOT="\$(abs_top_builddir)/vendor/.build" +AC_SUBST([VENDOR_SRC_ROOT]) +AC_SUBST([VENDOR_BUILD_ROOT]) +AC_SUBST([VENDOR_DIST_ROOT]) + +TEST_LDFLAGS="-lcmocka -L\$(abs_top_builddir)/vendor/dist/lib -Wl,-rpath,\$(abs_top_builddir)/vendor/dist/lib" +TEST_CFLAGS="-I\$(top_srcdir)/include -I\$(abs_top_builddir)/vendor/dist/include" + +AC_SUBST([TEST_LDFLAGS]) +AC_SUBST([TEST_CFLAGS]) + AC_CONFIG_FILES([ version.sh Makefile @@ -1216,6 +1229,9 @@ AC_CONFIG_FILES([ src/plugins/auth-pam/Makefile src/plugins/down-root/Makefile tests/Makefile + tests/unit_tests/Makefile + tests/unit_tests/example_test/Makefile + vendor/Makefile sample/Makefile doc/Makefile ]) diff --git a/tests/Makefile.am b/tests/Makefile.am index b7980e04b8b..2cba9e66d63 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -12,6 +12,8 @@ MAINTAINERCLEANFILES = \ $(srcdir)/Makefile.in +SUBDIRS = unit_tests + test_scripts = t_client.sh t_lpback.sh t_cltsrv.sh TESTS_ENVIRONMENT = top_srcdir="$(top_srcdir)" @@ -20,4 +22,3 @@ TESTS = $(test_scripts) dist_noinst_SCRIPTS = \ $(test_scripts) \ t_cltsrv-down.sh - diff --git a/tests/unit_tests/.gitignore b/tests/unit_tests/.gitignore new file mode 100644 index 00000000000..8655de8341f --- /dev/null +++ b/tests/unit_tests/.gitignore @@ -0,0 +1 @@ +*_testdriver diff --git a/tests/unit_tests/Makefile.am b/tests/unit_tests/Makefile.am new file mode 100644 index 00000000000..18267bd0ce7 --- /dev/null +++ b/tests/unit_tests/Makefile.am @@ -0,0 +1,3 @@ +AUTOMAKE_OPTIONS = foreign + +SUBDIRS = example_test diff --git a/tests/unit_tests/README.md b/tests/unit_tests/README.md new file mode 100644 index 00000000000..de8adb40d97 --- /dev/null +++ b/tests/unit_tests/README.md @@ -0,0 +1,40 @@ +Unit Tests +=========== + +This directory contains unit tests for openvpn. New features/bugfixes should be written in a test friendly way and come with corresponding tests. + +Run tests +---------- + +Tests are run by `make check`. A failed tests stops test execution. To run all +tests regardless of errors call `make -k check`. + +Add new tests to existing test suite +------------------------------------- + +Test suites are organized in directories. [example_test/](example_test/) is an example +for a test suite with two test executables. Feel free to use it as a template for new tests. + +Test suites +-------------------- + +Test suites live inside a subdirectory of `$ROOT/tests/unit_tests`, e.g. `$ROOT/tests/unit_tests/my_feature`. + +Test suites are configured by a `Makefile.am`. Tests are executed by testdrivers. One testsuite can contain more than one testdriver. + +### Hints +* Name suites & testdrivers in a way that the name of the driver says something about which component/feature is tested +* Name the testdriver executable `*_testdriver`. This way it gets picked up by the default `.gitignore` + * If this is not feasible: Add all output to a `.gitignore`* Use descriptive test names: `coffee_brewing__with_no_beans__fails` vs. `test34` +* Testing a configurable feature? Wrap test execution with a conditional (see [auth_pam](plugins/auth-pam/Makefile.am) for an example) +* Add multiple test-drivers when one testdriver looks crowded with tests + +### New Test Suites +1. Organize tests in folders for features. +2. Add the new test directory to `SUBDIRS` in `Makefile.am` +3. Edit `configure.ac` and add the new `Makefile` to `AC_CONFIG_FILES` +4. Run `./configure`, and *enable* the feature you'd like to test +5. Make sure that `make check` runs your tests +6. Check: Would a stranger be able to easily find your tests by you looking at the test output? +7. Run `./configure`, and *disable* the feature you'd like to test +8. Make sure that `make check` does *not run* your tests diff --git a/tests/unit_tests/example_test/Makefile.am b/tests/unit_tests/example_test/Makefile.am new file mode 100644 index 00000000000..04a5ad3564c --- /dev/null +++ b/tests/unit_tests/example_test/Makefile.am @@ -0,0 +1,13 @@ +AUTOMAKE_OPTIONS = foreign + +check_PROGRAMS = example_testdriver example2_testdriver + +TESTS = $(check_PROGRAMS) + +example_testdriver_CFLAGS = @TEST_CFLAGS@ +example_testdriver_LDFLAGS = @TEST_LDFLAGS@ +example_testdriver_SOURCES = test.c + +example2_testdriver_CFLAGS = @TEST_CFLAGS@ +example2_testdriver_LDFLAGS = @TEST_LDFLAGS@ +example2_testdriver_SOURCES = test2.c diff --git a/tests/unit_tests/example_test/README.md b/tests/unit_tests/example_test/README.md new file mode 100644 index 00000000000..cb75d684df2 --- /dev/null +++ b/tests/unit_tests/example_test/README.md @@ -0,0 +1,3 @@ +This test only checks that test compilation works. This example contains two test executables. + +These tests can be used as template for 'real' tests. diff --git a/tests/unit_tests/example_test/test.c b/tests/unit_tests/example_test/test.c new file mode 100644 index 00000000000..9986898f0b5 --- /dev/null +++ b/tests/unit_tests/example_test/test.c @@ -0,0 +1,46 @@ +#include +#include +#include +#include +#include +#include +#include + +static int setup(void **state) { + int *answer = malloc(sizeof(int)); + + *answer=42; + *state=answer; + + return 0; +} + +static int teardown(void **state) { + free(*state); + + return 0; +} + +static void null_test_success(void **state) { + (void) state; +} + +static void int_test_success(void **state) { + int *answer = *state; + assert_int_equal(*answer, 42); +} + +static void failing_test(void **state) { + // This tests fails to test that make check fails + assert_int_equal(0, 42); +} + +int main(void) { + const struct CMUnitTest tests[] = { + cmocka_unit_test(null_test_success), + cmocka_unit_test_setup_teardown(int_test_success, setup, teardown), +// cmocka_unit_test(failing_test), + }; + + return cmocka_run_group_tests_name("success_test", tests, NULL, NULL); +} diff --git a/tests/unit_tests/example_test/test2.c b/tests/unit_tests/example_test/test2.c new file mode 100644 index 00000000000..f99da9e6a97 --- /dev/null +++ b/tests/unit_tests/example_test/test2.c @@ -0,0 +1,21 @@ +#include +#include +#include +#include +#include +#include +#include + + +static void test_true(void **state) { + (void) state; +} + + +int main(void) { + const struct CMUnitTest tests[] = { + cmocka_unit_test(test_true), + }; + + return cmocka_run_group_tests_name("success_test2", tests, NULL, NULL); +} diff --git a/vendor/.gitignore b/vendor/.gitignore new file mode 100644 index 00000000000..e11dfecddf4 --- /dev/null +++ b/vendor/.gitignore @@ -0,0 +1,2 @@ +.build/ +dist/ diff --git a/vendor/Makefile.am b/vendor/Makefile.am new file mode 100644 index 00000000000..f68240e9062 --- /dev/null +++ b/vendor/Makefile.am @@ -0,0 +1,24 @@ +AUTOMAKE_OPTIONS = foreign + +cmockasrc = @VENDOR_SRC_ROOT@/cmocka # needs an absolute path bc. of the cmake invocation +cmockabuild = @VENDOR_BUILD_ROOT@/cmocka +cmockainstall = @VENDOR_DIST_ROOT@ + +MAINTAINERCLEANFILES = \ + $(srcdir)/Makefile.in \ + $(cmockabuild) \ + $(cmockainstall) \ + @VENDOR_BUILD_ROOT@ + +distdir: + mkdir -p $(cmockainstall) + +libcmocka: distdir + mkdir -p $(cmockabuild) + (cd $(cmockabuild) && cmake -DCMAKE_INSTALL_PREFIX=$(cmockainstall) $(cmockasrc) && make && make install) + +check: libcmocka + +clean: + rm -rf $(cmockabuild) + rm -rf $(cmockainstall) diff --git a/vendor/README.md b/vendor/README.md new file mode 100644 index 00000000000..cede99b6f1a --- /dev/null +++ b/vendor/README.md @@ -0,0 +1,8 @@ +Vendor +======== + +Vendor source libraries are included in this directory. Libraries are included +when there is no good way to ensure that the package is available on all +systems. + +`Makefile.am` compiles these libraries and installs them into ./dist. diff --git a/vendor/cmocka b/vendor/cmocka new file mode 160000 index 00000000000..b2732b52202 --- /dev/null +++ b/vendor/cmocka @@ -0,0 +1 @@ +Subproject commit b2732b52202ae48f866a024c633466efdbb8e85a From 4507bb6cd11799f72f1ede602315a60e03bb449c Mon Sep 17 00:00:00 2001 From: Jens Neuhalfen Date: Wed, 25 May 2016 19:57:56 +0200 Subject: [PATCH 249/643] Add a test for auth-pam searchandreplace No functional changes. Utility functions of auth-pam are split into a dedicated file. This allows the test programs to easily test these functions without adding dependencies. Add a minimal test for searchandreplace as a proof of concept. [ Modified during commit: Enhanced documentation of functions in utils.h to comply with doxygen standards ] Signed-off-by: Jens Neuhalfen Acked-by: Steffan Karger Message-Id: <20160525175756.56186-3-openvpn-devel@neuhalfen.name> URL: http://article.gmane.org/gmane.network.openvpn.devel/11724 Signed-off-by: David Sommerseth --- configure.ac | 2 + src/plugins/auth-pam/Makefile.am | 1 + src/plugins/auth-pam/auth-pam.c | 91 +------------- src/plugins/auth-pam/utils.c | 113 ++++++++++++++++++ src/plugins/auth-pam/utils.h | 66 ++++++++++ tests/unit_tests/Makefile.am | 2 +- tests/unit_tests/plugins/Makefile.am | 3 + tests/unit_tests/plugins/auth-pam/Makefile.am | 12 ++ .../auth-pam/test_search_and_replace.c | 78 ++++++++++++ 9 files changed, 277 insertions(+), 91 deletions(-) create mode 100644 src/plugins/auth-pam/utils.c create mode 100644 src/plugins/auth-pam/utils.h create mode 100644 tests/unit_tests/plugins/Makefile.am create mode 100644 tests/unit_tests/plugins/auth-pam/Makefile.am create mode 100644 tests/unit_tests/plugins/auth-pam/test_search_and_replace.c diff --git a/configure.ac b/configure.ac index fb3fa3cdd8e..5e69f91c91e 100644 --- a/configure.ac +++ b/configure.ac @@ -1230,6 +1230,8 @@ AC_CONFIG_FILES([ src/plugins/down-root/Makefile tests/Makefile tests/unit_tests/Makefile + tests/unit_tests/plugins/Makefile + tests/unit_tests/plugins/auth-pam/Makefile tests/unit_tests/example_test/Makefile vendor/Makefile sample/Makefile diff --git a/src/plugins/auth-pam/Makefile.am b/src/plugins/auth-pam/Makefile.am index 2aef311a90f..e6dc27e8488 100644 --- a/src/plugins/auth-pam/Makefile.am +++ b/src/plugins/auth-pam/Makefile.am @@ -18,6 +18,7 @@ dist_doc_DATA = README.auth-pam endif openvpn_plugin_auth_pam_la_SOURCES = \ + utils.c \ auth-pam.c \ pamdl.c pamdl.h \ auth-pam.exports diff --git a/src/plugins/auth-pam/auth-pam.c b/src/plugins/auth-pam/auth-pam.c index 710acccbf96..5ad3ec8ec28 100644 --- a/src/plugins/auth-pam/auth-pam.c +++ b/src/plugins/auth-pam/auth-pam.c @@ -39,7 +39,6 @@ #include #include #include -#include #include #include #include @@ -48,7 +47,7 @@ #include #include #include -#include +#include "utils.h" #include @@ -117,94 +116,6 @@ struct user_pass { /* Background process function */ static void pam_server (int fd, const char *service, int verb, const struct name_value_list *name_value_list); -/* Read 'tosearch', replace all occurences of 'searchfor' with 'replacewith' and return - * a pointer to the NEW string. Does not modify the input strings. Will not enter an - * infinite loop with clever 'searchfor' and 'replacewith' strings. - * Daniel Johnson - Progman2000@usa.net / djohnson@progman.us - * - * Retuns NULL when - * - any parameter is NULL - * - the worst-case result is to large ( >= SIZE_MAX) - */ -static char * -searchandreplace(const char *tosearch, const char *searchfor, const char *replacewith) -{ - if (!tosearch || !searchfor || !replacewith) return NULL; - - size_t tosearchlen = strlen(tosearch); - size_t replacewithlen = strlen(replacewith); - size_t templen = tosearchlen * replacewithlen; - - if (tosearchlen == 0 || strlen(searchfor) == 0 || replacewithlen == 0) { - return NULL; - } - - bool is_potential_integer_overflow = (templen == SIZE_MAX) || (templen / tosearchlen != replacewithlen); - - if (is_potential_integer_overflow) { - return NULL; - } - - // state: all parameters are valid - - const char *searching=tosearch; - char *scratch; - - char temp[templen+1]; - temp[0]=0; - - scratch = strstr(searching,searchfor); - if (!scratch) return strdup(tosearch); - - while (scratch) { - strncat(temp,searching,scratch-searching); - strcat(temp,replacewith); - - searching=scratch+strlen(searchfor); - scratch = strstr(searching,searchfor); - } - return strdup(temp); -} - -/* - * Given an environmental variable name, search - * the envp array for its value, returning it - * if found or NULL otherwise. - */ -static const char * -get_env (const char *name, const char *envp[]) -{ - if (envp) - { - int i; - const int namelen = strlen (name); - for (i = 0; envp[i]; ++i) - { - if (!strncmp (envp[i], name, namelen)) - { - const char *cp = envp[i] + namelen; - if (*cp == '=') - return cp + 1; - } - } - } - return NULL; -} - -/* - * Return the length of a string array - */ -static int -string_array_len (const char *array[]) -{ - int i = 0; - if (array) - { - while (array[i]) - ++i; - } - return i; -} /* * Socket read/write functions. diff --git a/src/plugins/auth-pam/utils.c b/src/plugins/auth-pam/utils.c new file mode 100644 index 00000000000..4f2bec1e5f9 --- /dev/null +++ b/src/plugins/auth-pam/utils.c @@ -0,0 +1,113 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single TCP/UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * + * 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 + */ + +/* + * OpenVPN plugin module to do PAM authentication using a split + * privilege model. + */ +#ifdef HAVE_CONFIG_H +#include +#endif + + +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +char * +searchandreplace(const char *tosearch, const char *searchfor, const char *replacewith) +{ + if (!tosearch || !searchfor || !replacewith) return NULL; + + size_t tosearchlen = strlen(tosearch); + size_t replacewithlen = strlen(replacewith); + size_t templen = tosearchlen * replacewithlen; + + if (tosearchlen == 0 || strlen(searchfor) == 0 || replacewithlen == 0) { + return NULL; + } + + bool is_potential_integer_overflow = (templen == SIZE_MAX) || (templen / tosearchlen != replacewithlen); + + if (is_potential_integer_overflow) { + return NULL; + } + + // state: all parameters are valid + + const char *searching=tosearch; + char *scratch; + + char temp[templen+1]; + temp[0]=0; + + scratch = strstr(searching,searchfor); + if (!scratch) return strdup(tosearch); + + while (scratch) { + strncat(temp,searching,scratch-searching); + strcat(temp,replacewith); + + searching=scratch+strlen(searchfor); + scratch = strstr(searching,searchfor); + } + return strdup(temp); +} + +const char * +get_env (const char *name, const char *envp[]) +{ + if (envp) + { + int i; + const int namelen = strlen (name); + for (i = 0; envp[i]; ++i) + { + if (!strncmp (envp[i], name, namelen)) + { + const char *cp = envp[i] + namelen; + if (*cp == '=') + return cp + 1; + } + } + } + return NULL; +} + +int +string_array_len (const char *array[]) +{ + int i = 0; + if (array) + { + while (array[i]) + ++i; + } + return i; +} diff --git a/src/plugins/auth-pam/utils.h b/src/plugins/auth-pam/utils.h new file mode 100644 index 00000000000..2f7204030e7 --- /dev/null +++ b/src/plugins/auth-pam/utils.h @@ -0,0 +1,66 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single TCP/UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * + * 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 _PLUGIN_AUTH_PAM_UTILS__H +#define _PLUGIN_AUTH_PAM_UTILS__H + +/** + * Read 'tosearch', replace all occurences of 'searchfor' with 'replacewith' and return + * a pointer to the NEW string. Does not modify the input strings. Will not enter an + * infinite loop with clever 'searchfor' and 'replacewith' strings. + * + * @author Daniel Johnson - Progman2000@usa.net / djohnson@progman.us + * + * @param tosearch haystack to search in + * @param searchfor needle to search for in the haystack + * @param replacewith when a match is found, replace needle with this string + * + * @return Retuns NULL when any parameter is NULL or the worst-case result is to large ( >= SIZE_MAX). + * Otherwise it returns a pointer to a new buffer containing the modified input + */ +char * +searchandreplace(const char *tosearch, const char *searchfor, const char *replacewith); + +/** + * Given an environmental variable name, search + * the envp array for its value + * + * @param name Environment variable to look up + * @param envp Environment variable table with all key/value pairs + * + * @return Returns a pointer to the value of the enviroment variable if found, otherwise NULL is returned. + */ +const char * +get_env (const char *name, const char *envp[]); + +/** + * Return the length of a string array + * + * @param array Pointer to the array to calculate size of + * + */ +int +string_array_len (const char *array[]); + +#endif diff --git a/tests/unit_tests/Makefile.am b/tests/unit_tests/Makefile.am index 18267bd0ce7..e076db82c76 100644 --- a/tests/unit_tests/Makefile.am +++ b/tests/unit_tests/Makefile.am @@ -1,3 +1,3 @@ AUTOMAKE_OPTIONS = foreign -SUBDIRS = example_test +SUBDIRS = example_test plugins diff --git a/tests/unit_tests/plugins/Makefile.am b/tests/unit_tests/plugins/Makefile.am new file mode 100644 index 00000000000..a3696d5cfe3 --- /dev/null +++ b/tests/unit_tests/plugins/Makefile.am @@ -0,0 +1,3 @@ +AUTOMAKE_OPTIONS = foreign + +SUBDIRS = auth-pam diff --git a/tests/unit_tests/plugins/auth-pam/Makefile.am b/tests/unit_tests/plugins/auth-pam/Makefile.am new file mode 100644 index 00000000000..07233eee77e --- /dev/null +++ b/tests/unit_tests/plugins/auth-pam/Makefile.am @@ -0,0 +1,12 @@ +AUTOMAKE_OPTIONS = foreign + +if ENABLE_PLUGIN_AUTH_PAM +check_PROGRAMS = auth_pam_testdriver +TESTS = $(check_PROGRAMS) +endif + +sut_sourcedir = $(top_srcdir)/src/plugins/auth-pam + +auth_pam_testdriver_SOURCES = test_search_and_replace.c $(sut_sourcedir)/utils.h $(sut_sourcedir)/utils.c +auth_pam_testdriver_CFLAGS = @TEST_CFLAGS@ -I$(sut_sourcedir) +auth_pam_testdriver_LDFLAGS = @TEST_LDFLAGS@ diff --git a/tests/unit_tests/plugins/auth-pam/test_search_and_replace.c b/tests/unit_tests/plugins/auth-pam/test_search_and_replace.c new file mode 100644 index 00000000000..70e472f32fc --- /dev/null +++ b/tests/unit_tests/plugins/auth-pam/test_search_and_replace.c @@ -0,0 +1,78 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +static void pass_any_null_param__returns_null() { + + char DUMMY[] = "DUMMY"; + + assert_null(searchandreplace(NULL,DUMMY,DUMMY)); + assert_null(searchandreplace(DUMMY,NULL,DUMMY)); + assert_null(searchandreplace(DUMMY,DUMMY,NULL)); +} + +static void pass_any_empty_string__returns_null() { + + char DUMMY[] = "DUMMY"; + char EMPTY[] = ""; + + assert_null(searchandreplace(EMPTY,DUMMY,DUMMY)); + assert_null(searchandreplace(DUMMY,EMPTY,DUMMY)); + assert_null(searchandreplace(DUMMY,DUMMY,EMPTY)); +} + +static void replace_single_char__one_time__match_is_replaced() { + char *replaced = searchandreplace("X","X","Y"); + + assert_non_null(replaced); + assert_string_equal("Y", replaced); + + free(replaced); +} + +static void replace_single_char__multiple_times__match_all_matches_are_replaced() { + char *replaced = searchandreplace("XaX","X","Y"); + + assert_non_null(replaced); + assert_string_equal ("YaY", replaced); + + free(replaced); +} + +static void replace_longer_text__multiple_times__match_all_matches_are_replaced() { + char *replaced = searchandreplace("XXaXX","XX","YY"); + + assert_non_null(replaced); + assert_string_equal ("YYaYY", replaced); + + free(replaced); +} + +static void pattern_not_found__returns_original() { + char *replaced = searchandreplace("abc","X","Y"); + + assert_non_null(replaced); + assert_string_equal ("abc", replaced); + + free(replaced); +} + + +int main(void) { + const struct CMUnitTest tests[] = { + cmocka_unit_test(pass_any_null_param__returns_null), + cmocka_unit_test(pass_any_empty_string__returns_null), + cmocka_unit_test(replace_single_char__one_time__match_is_replaced), + cmocka_unit_test(replace_single_char__multiple_times__match_all_matches_are_replaced), + cmocka_unit_test(replace_longer_text__multiple_times__match_all_matches_are_replaced), + cmocka_unit_test(pattern_not_found__returns_original), + }; + + return cmocka_run_group_tests_name("searchandreplace", tests, NULL, NULL); +} From ac2309b889552f2a0382414ff46b2682c2101674 Mon Sep 17 00:00:00 2001 From: Leon Klingele Date: Mon, 30 May 2016 22:54:58 +0300 Subject: [PATCH 250/643] Add link to bug tracker MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit URL: https://github.com/OpenVPN/openvpn/pull/25 Signed-off-by: Samuli Seppänen Acked-by: David Sommerseth Message-Id: <1464638098-19187-1-git-send-email-samuli@openvpn.net> URL: http://article.gmane.org/gmane.network.openvpn.devel/11735 Signed-off-by: David Sommerseth --- README | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README b/README index 349e08afc64..81424d110ea 100644 --- a/README +++ b/README @@ -27,6 +27,9 @@ For detailed information on OpenVPN, including examples, see the man page For a sample VPN configuration, see http://openvpn.net/howto.html +To report an issue, see + https://community.openvpn.net/openvpn/report + For a description of OpenVPN's underlying protocol, see the file ssl.h included in the source distribution. From 4a506b9ca2d8bbfaa5d49c6fe9a073d8ff3e59d1 Mon Sep 17 00:00:00 2001 From: Jeffrey Cutter Date: Fri, 20 May 2016 12:25:10 +0300 Subject: [PATCH 251/643] Update contrib/pull-resolv-conf/client.up for no DOMAIN MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When no DOMAIN is received from push/pull, do not add either domain or search to the resolv.conf. Fix typo in comment resolv.con[f]. Only add new line when using domain or search. URL: https://github.com/OpenVPN/openvpn/pull/34 Acked-by: Steffan Karger Signed-off-by: Samuli Seppänen Acked-by: Steffan Karger Message-Id: <1463736310-17846-1-git-send-email-samuli@openvpn.net> URL: http://article.gmane.org/gmane.network.openvpn.devel/11682 Signed-off-by: David Sommerseth --- contrib/pull-resolv-conf/client.up | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/contrib/pull-resolv-conf/client.up b/contrib/pull-resolv-conf/client.up index b28d4d19171..8858b4766d9 100644 --- a/contrib/pull-resolv-conf/client.up +++ b/contrib/pull-resolv-conf/client.up @@ -50,9 +50,10 @@ nl=' # or # "dhcp-option DNS 10.10.10.10" (multiple allowed) -# each DNS option becomes a "nameserver" option in resolv.con +# each DNS option becomes a "nameserver" option in resolv.conf # if we get one DOMAIN, that becomes "domain" in resolv.conf # if we get multiple DOMAINS, those become "search" lines in resolv.conf +# if we get no DOMAINS, then don't use either domain or search. while true; do eval fopt=\$foreign_option_${i} @@ -78,13 +79,15 @@ while true; do i=$((i + 1)) done -ds=domain -if [ $ndoms -gt 1 ]; then - ds=search +ds="" +if [ $ndoms -eq 1 ]; then + ds="${nl}domain" +elif [ $ndoms -gt 1 ]; then + ds="${nl}search" fi # This is the complete file - "$domains" has a leading space already -out="# resolv.conf autogenerated by ${0} (${1})${nl}${dns}${nl}${ds}${domains}" +out="# resolv.conf autogenerated by ${0} (${1})${nl}${dns}${ds}${domains}" # use resolvconf if it's available if type resolvconf >/dev/null 2>&1; then From 45f6e7991cfa3bb8a44f981b6cf1e794d617d51e Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Tue, 31 May 2016 12:28:46 +0200 Subject: [PATCH 252/643] Only build and run cmocka unit tests if its submodule is initialized Commit 40cb4cfc5d01110 added infrastructure to write unit tests using cmocka. This was implemented using a git submodule to fetch an up-to-date cmocka test framework. The issue which appeared was that 'make check' stopped working if the cmocka submodule was not initialized and updated. As we do not want this to be a hard depenency, this patch makes running these unit tests conditional. If cmocka has not been initialized, skip them or if it has been initialized all unit tests will be run. [v2 - Also check if cmake is available, as cmocka depends on that to be built ] Signed-off-by: David Sommerseth Acked-by: Gert Doering Message-Id: <1464703645-26640-1-git-send-email-openvpn@sf.lists.topphemmelig.net> URL: http://article.gmane.org/gmane.network.openvpn.devel/11758 --- configure.ac | 16 ++++++++++++++++ tests/unit_tests/Makefile.am | 2 ++ vendor/Makefile.am | 2 ++ 3 files changed, 20 insertions(+) diff --git a/configure.ac b/configure.ac index 5e69f91c91e..d73302345e2 100644 --- a/configure.ac +++ b/configure.ac @@ -1211,6 +1211,22 @@ TEST_CFLAGS="-I\$(top_srcdir)/include -I\$(abs_top_builddir)/vendor/dist/include AC_SUBST([TEST_LDFLAGS]) AC_SUBST([TEST_CFLAGS]) +# Check if cmake is available and cmocka git submodule is initialized, +# needed for unit testing +AC_CHECK_PROGS([CMAKE], [cmake]) +if test -n "${CMAKE}"; then + if test -f vendor/cmocka/CMakeLists.txt; then + AM_CONDITIONAL([CMOCKA_INITIALIZED], [true]) + else + AM_CONDITIONAL([CMOCKA_INITIALIZED], [false]) + AC_MSG_RESULT([!! WARNING !! The cmoka git submodule has not been initialized or updated. Unit testing cannot be performed.]) + fi +else + AC_MSG_RESULT([!! WARNING !! CMake is NOT available. Unit testing cannot be performed.]) + AM_CONDITIONAL([CMOCKA_INITIALIZED], [false]) +fi + + AC_CONFIG_FILES([ version.sh Makefile diff --git a/tests/unit_tests/Makefile.am b/tests/unit_tests/Makefile.am index e076db82c76..8868c1cb4f6 100644 --- a/tests/unit_tests/Makefile.am +++ b/tests/unit_tests/Makefile.am @@ -1,3 +1,5 @@ AUTOMAKE_OPTIONS = foreign +if CMOCKA_INITIALIZED SUBDIRS = example_test plugins +endif diff --git a/vendor/Makefile.am b/vendor/Makefile.am index f68240e9062..84656a11511 100644 --- a/vendor/Makefile.am +++ b/vendor/Makefile.am @@ -15,7 +15,9 @@ distdir: libcmocka: distdir mkdir -p $(cmockabuild) +if CMOCKA_INITIALIZED (cd $(cmockabuild) && cmake -DCMAKE_INSTALL_PREFIX=$(cmockainstall) $(cmockasrc) && make && make install) +endif check: libcmocka From cd538f2c7a128395284d23f9c30741217075503f Mon Sep 17 00:00:00 2001 From: Ivo Manca Date: Tue, 31 May 2016 13:42:00 +0200 Subject: [PATCH 253/643] Plug memory leak in mbedTLS backend Signed-off-by: Ivo Manca Acked-by: Steffan Karger Acked-by: Arne Schwabe Acked-by: Gert Doering Message-Id: <1464694920-3624-1-git-send-email-pinkel@gmail.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/11751 Signed-off-by: David Sommerseth --- src/openvpn/ssl_verify_mbedtls.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/openvpn/ssl_verify_mbedtls.c b/src/openvpn/ssl_verify_mbedtls.c index 9c4b51a7871..522ff68c4af 100644 --- a/src/openvpn/ssl_verify_mbedtls.c +++ b/src/openvpn/ssl_verify_mbedtls.c @@ -162,7 +162,7 @@ backend_x509_get_serial (mbedtls_x509_crt *cert, struct gc_arena *gc) cert->serial.len))) { msg(M_WARN, "Failed to retrieve serial from certificate."); - return NULL; + goto end; } /* Determine decimal representation length, allocate buffer */ @@ -173,9 +173,12 @@ backend_x509_get_serial (mbedtls_x509_crt *cert, struct gc_arena *gc) if (!mbed_ok(mbedtls_mpi_write_string(&serial_mpi, 10, buf, buflen, &buflen))) { msg(M_WARN, "Failed to write serial to string."); - return NULL; + buf = NULL; + goto end; } +end: + mbedtls_mpi_free(&serial_mpi); return buf; } From fdc24f1e986c5d8ecdf37c3d0f913f3549087852 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuli=20Sepp=C3=A4nen?= Date: Tue, 31 May 2016 09:53:55 +0300 Subject: [PATCH 254/643] Clarify the fact that build instructions in README are for release tarballs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit URL: https://github.com/OpenVPN/openvpn/pull/51 Signed-off-by: Samuli Seppänen Acked-by: David Sommerseth Message-Id: <1464677635-24251-1-git-send-email-samuli@openvpn.net> URL: http://article.gmane.org/gmane.network.openvpn.devel/11746 Signed-off-by: David Sommerseth --- README | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README b/README index 81424d110ea..ee7695163a6 100644 --- a/README +++ b/README @@ -7,12 +7,14 @@ as published by the Free Software Foundation. ************************************************************************* -For the latest version of OpenVPN, go to: +To get the latest release of OpenVPN, go to: - http://openvpn.net/ + https://openvpn.net/index.php/download/community-downloads.html To Build and Install, + tar -zxf openvpn-.tar.gz + cd openvpn- ./configure make make install From 41ab12f06253cadc34fc47da865178de3db0bbdc Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Fri, 3 Jun 2016 18:56:20 +0200 Subject: [PATCH 255/643] Another fix related to unit test framework Continuing to fix breakage caused by commit 40cb4cfc5d011102. It seems it was a conflict in vendor/Makefile.am's distdir target, confusing autotools so it wouldn't actually parse that directory properly. The result was that 'make distcheck' would fail and tarballs created would just ship with an empty vendor/ directory. Also remove the 'foreign' AUTOMAKE_OPTIONS flag, as we don't use that many places at all. Things work well without this flag. The comment had to be moved to a single line, otherwise the white spaces between the end of the variable assignment and the hash character got added to the variable. [v3 - Further improve white space issues, now 'make clean' should work too] [v2 - Fix white space issues in path variables] Signed-off-by: David Sommerseth Acked-by: Gert Doering Message-Id: <1464976163-6162-1-git-send-email-openvpn@sf.lists.topphemmelig.net> URL: http://article.gmane.org/gmane.network.openvpn.devel/11778 --- vendor/Makefile.am | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/vendor/Makefile.am b/vendor/Makefile.am index 84656a11511..674784ab335 100644 --- a/vendor/Makefile.am +++ b/vendor/Makefile.am @@ -1,21 +1,17 @@ -AUTOMAKE_OPTIONS = foreign - -cmockasrc = @VENDOR_SRC_ROOT@/cmocka # needs an absolute path bc. of the cmake invocation -cmockabuild = @VENDOR_BUILD_ROOT@/cmocka -cmockainstall = @VENDOR_DIST_ROOT@ +# needs an absolute path bc. of the cmake invocation +cmockasrc = "@VENDOR_SRC_ROOT@/cmocka" +cmockabuild = "@VENDOR_BUILD_ROOT@/cmocka" +cmockainstall = "@VENDOR_DIST_ROOT@" MAINTAINERCLEANFILES = \ $(srcdir)/Makefile.in \ - $(cmockabuild) \ - $(cmockainstall) \ - @VENDOR_BUILD_ROOT@ - -distdir: - mkdir -p $(cmockainstall) + "$(cmockabuild)" \ + "$(cmockainstall)" \ + "@VENDOR_BUILD_ROOT@" -libcmocka: distdir - mkdir -p $(cmockabuild) +libcmocka: if CMOCKA_INITIALIZED + mkdir -p $(cmockabuild) $(cmockainstall) (cd $(cmockabuild) && cmake -DCMAKE_INSTALL_PREFIX=$(cmockainstall) $(cmockasrc) && make && make install) endif From 1899393543caa3cd5191c96176e8ecaa8e690eeb Mon Sep 17 00:00:00 2001 From: Selva Nair Date: Sat, 4 Jun 2016 00:57:43 -0400 Subject: [PATCH 256/643] Fix the comparison of pull options hash on restart Signed-off-by: Selva Nair Acked-by: Steffan Karger Message-Id: <1465016263-23048-1-git-send-email-selva.nair@gmail.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/11783 Signed-off-by: Gert Doering --- src/openvpn/init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 42baf97f020..4b044f4758f 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -1717,7 +1717,7 @@ options_hash_changed_or_zero(const struct md5_digest *a, { const struct md5_digest zero = {{0}}; return memcmp (a, b, sizeof(struct md5_digest)) || - memcmp (a, &zero, sizeof(struct md5_digest)); + !memcmp (a, &zero, sizeof(struct md5_digest)); } #endif /* P2MP */ From 895d75cf99bf8f3b95b01d6e19df30208cec27a9 Mon Sep 17 00:00:00 2001 From: Selva Nair Date: Sat, 4 Jun 2016 16:09:05 -0400 Subject: [PATCH 257/643] Set WFP engine handle to NULL in win_wfp_uninit() This was missed by commit 6a33a34dee8f3 Signed-off-by: Selva Nair Acked-by: Gert Doering Message-Id: <1465070945-5426-1-git-send-email-selva.nair@gmail.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/11789 Signed-off-by: Gert Doering --- src/openvpn/win32.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/openvpn/win32.c b/src/openvpn/win32.c index f4d3237f093..8a2f9578577 100644 --- a/src/openvpn/win32.c +++ b/src/openvpn/win32.c @@ -1192,6 +1192,7 @@ win_wfp_uninit(const HANDLE msg_channel) else { delete_block_dns_filters (m_hEngineHandle); + m_hEngineHandle = NULL; } return true; From 451d2177d762e93677cad52bb2360a8dfb389ac7 Mon Sep 17 00:00:00 2001 From: Selva Nair Date: Sat, 4 Jun 2016 11:57:13 -0400 Subject: [PATCH 258/643] Make block-outside-dns work with persist-tun - Remove and recreate WFP filters during restart even when tun/tap is not re-opened. This is needed for resolving the remote. Patch same as for v2.3 except for passing 'msg_channel'. See also: http://article.gmane.org/gmane.network.openvpn.user/36990 Signed-off-by: Selva Nair Acked-by: Gert Doering Message-Id: <1465055833-13681-1-git-send-email-selva.nair@gmail.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/11788 Signed-off-by: Gert Doering --- src/openvpn/init.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 4b044f4758f..50cbf902ea8 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -1556,6 +1556,15 @@ do_open_tun (struct context *c) NULL, "up", c->c2.es); +#if defined(WIN32) + if (c->options.block_outside_dns) + { + dmsg (D_LOW, "Blocking outside DNS"); + if (!win_wfp_block_dns(c->c1.tuntap->adapter_index, c->options.msg_channel)) + msg (M_FATAL, "Blocking DNS failed!"); + } +#endif + } #endif gc_free (&gc); @@ -1686,6 +1695,15 @@ do_close_tun (struct context *c, bool force) c->sig->signal_text), "down", c->c2.es); + +#if defined(WIN32) + if (c->options.block_outside_dns) + { + if (!win_wfp_uninit(c->options.msg_channel)) + msg (M_FATAL, "Uninitialising WFP failed!"); + } +#endif + } } gc_free (&gc); From 7f74c27e105a365d278181d00708c55a299398a0 Mon Sep 17 00:00:00 2001 From: Selva Nair Date: Sun, 5 Jun 2016 17:41:23 -0400 Subject: [PATCH 259/643] Add an option to filter options received from server v2 changes: - Add the flag "ignore" and have "reject" trigger a restart. - Unlimited number of filters: yes, going against the consensus, but the code looks simpler and cleaner this way. - New commit message to reflect the changes. Usage: --pull-filter accept|ignore|reject "option" Permit a client to selectively accept, ignore or reject options pushed by the server. May be used multiple times. The filters are applied in the order specified to each pushed option received. The filtering stops as soon as a match is found. The action "ignore" removes the option and continues processing the next option, while "reject" flags an error and restarts the connection with SIGUSR1. Prefix matching is used so that all options starting with the specified "option" string are filtered. Example: pull-filter accept "route 192.168." pull-filter ignore "route " pull-filter accept "ifconfig 10.9.0." pull-filter reject "ifconfig " will ignore all pushed routes except those starting with "192.168." and reject the assigned ip unless its in the "10.9.0.0/24" range. A match of the reject filter will trigger a restart. SIGUSR1 restart is used instead of SIGHUP so as to try the next remote for reconnection. Note the space at the end of "route " to not reject "route-gateway", for example. All options not matched by any filter are accepted. Acknowledges shameless imitation of --push-remove. Inspired by Trac #682. Signed-off-by: Selva Nair Acked-by: Gert Doering Message-Id: <1465162884-32520-1-git-send-email-selva.nair@gmail.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/11808 Signed-off-by: Gert Doering --- Changes.rst | 4 ++ doc/openvpn.8 | 51 +++++++++++++++ src/openvpn/options.c | 146 ++++++++++++++++++++++++++++++++++++++++++ src/openvpn/options.h | 2 + 4 files changed, 203 insertions(+) diff --git a/Changes.rst b/Changes.rst index a6bb2a54701..1ac3c2be41c 100644 --- a/Changes.rst +++ b/Changes.rst @@ -5,6 +5,10 @@ Version 2.4.0 New features ------------ +pull-filter + New option to explicitly allow or reject options pushed by the server. + May be used multiple times and is applied in the order specified. + push-remove new option to remove options on a per-client basis from the "push" list (more fine-grained than "push-reset") diff --git a/doc/openvpn.8 b/doc/openvpn.8 index e1dd7cde3cb..03f31bb4042 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -3830,6 +3830,57 @@ in situations where you don't trust the server to have control over the client's routing table. .\"********************************************************* .TP +.B \-\-pull\-filter accept|ignore|reject \fItext\fR +Filter options received from the server if the option starts with +\fItext\fR. Runs on client. The action flag +.B accept +allows the option, +.B ignore +removes it and +.B reject +flags an error and triggers a SIGUSR1 restart. +The filters may be specified multiple times, and each filter is +applied in the order it is specified. The filtering of each +option stops as soon as a match is found. Unmatched options are accepted +by default. + +Prefix comparison is used to match \fItext\fR against the +received option so that + +.nf +.ft 3 +.in +4 +\-\-pull\-filter ignore "route" +.in -4 +.ft +.fi + +would remove all pushed options starting with +.B route +which would include, for example, +.B route\-gateway. +Enclose \fItext\fR in quotes to embed spaces. + +.nf +.ft 3 +.in +4 +\-\-pull\-filter accept "route 192.168.1." +\-\-pull\-filter ignore "route " +.in -4 +.ft +.fi + +would remove all routes that do not start with 192.168.1. + +This option may be used only on clients. +Note that +.B reject +may result in a repeated cycle of failure and reconnect, +unless multiple remotes are specified and connection to the next remote +succeeds. To silently ignore an option pushed by the server, use +.B ignore. +.\"********************************************************* +.TP .B \-\-auth\-user\-pass [up] Authenticate with server using username/password. .B up diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 55630c72878..23f407c0e51 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -489,6 +489,11 @@ static const char usage_message[] = "--pull : Accept certain config file options from the peer as if they\n" " were part of the local config file. Must be specified\n" " when connecting to a '--mode server' remote host.\n" + "--pull-filter accept|ignore|reject t : Filter each option received from the\n" + " server if it starts with the text t. The action flag accept,\n" + " ignore or reject causes the option to be allowed, removed or\n" + " rejected with error. May be specified multiple times, and\n" + " each filter is applied in the order of appearance.\n" "--auth-retry t : How to handle auth failures. Set t to\n" " none (default), interact, or nointeract.\n" "--static-challenge t e : Enable static challenge/response protocol using\n" @@ -876,6 +881,37 @@ uninit_options (struct options *o) } } +struct pull_filter +{ +# define PUF_TYPE_UNDEF 0 /** undefined filter type */ +# define PUF_TYPE_ACCEPT 1 /** filter type to accept a matching option */ +# define PUF_TYPE_IGNORE 2 /** filter type to ignore a matching option */ +# define PUF_TYPE_REJECT 3 /** filter type to reject and trigger SIGUSR1 */ + int type; + int size; + char *pattern; + struct pull_filter *next; +}; + +struct pull_filter_list +{ + struct pull_filter *head; + struct pull_filter *tail; +}; + +static const char * +pull_filter_type_name (int type) +{ + if (type == PUF_TYPE_ACCEPT) + return "accept"; + if (type == PUF_TYPE_IGNORE) + return "ignore"; + if (type == PUF_TYPE_REJECT) + return "reject"; + else + return "???"; +} + #ifndef ENABLE_SMALL #define SHOW_PARM(name, value, format) msg(D_SHOW_PARMS, " " #name " = " format, (value)) @@ -1407,6 +1443,20 @@ show_connection_entries (const struct options *o) msg (D_SHOW_PARMS, "Connection profiles END"); } +static void +show_pull_filter_list (const struct pull_filter_list *l) +{ + struct pull_filter *f; + if (!l) + return; + + msg (D_SHOW_PARMS, " Pull filters:"); + for (f = l->head; f; f = f->next) + { + msg (D_SHOW_PARMS, " %s \"%s\"", pull_filter_type_name(f->type), f->pattern); + } +} + #endif void @@ -1537,6 +1587,8 @@ show_settings (const struct options *o) SHOW_BOOL (route_nopull); SHOW_BOOL (route_gateway_via_dhcp); SHOW_BOOL (allow_pull_fqdn); + show_pull_filter_list (o->pull_filter_list); + if (o->routes) print_route_options (o->routes, D_SHOW_PARMS); @@ -1797,6 +1849,35 @@ alloc_remote_entry (struct options *options, const int msglevel) return e; } +static struct pull_filter_list * +alloc_pull_filter_list (struct options *o) +{ + if (!o->pull_filter_list) + ALLOC_OBJ_CLEAR_GC (o->pull_filter_list, struct pull_filter_list, &o->gc); + return o->pull_filter_list; +} + +static struct pull_filter * +alloc_pull_filter (struct options *o, const int msglevel) +{ + struct pull_filter_list *l = alloc_pull_filter_list (o); + struct pull_filter *f; + + ALLOC_OBJ_CLEAR_GC (f, struct pull_filter, &o->gc); + if (l->head) + { + ASSERT (l->tail); + l->tail->next = f; + } + else + { + ASSERT (!l->tail); + l->head = f; + } + l->tail = f; + return f; +} + void connection_entry_load_re (struct connection_entry *ce, const struct remote_entry *re) { @@ -2000,6 +2081,8 @@ options_postprocess_verify_ce (const struct options *options, const struct conne msg (M_USAGE, "--mode server only works with --dev tun or --dev tap"); if (options->pull) msg (M_USAGE, "--pull cannot be used with --mode server"); + if (options->pull_filter_list) + msg (M_USAGE, "--pull-filter cannot be used with --mode server"); if (!(proto_is_udp(ce->proto) || ce->proto == PROTO_TCP_SERVER)) msg (M_USAGE, "--mode server currently only supports " "--proto udp or --proto tcp-server or proto tcp6-server"); @@ -3964,6 +4047,45 @@ parse_argv (struct options *options, } } +/** + * Filter an option line by all pull filters. + * + * If a match is found, the line is modified depending on + * the filter type, and returns true. If the filter type is + * reject, SIGUSR1 is triggered and the return value is false. + * In that case the caller must end the push processing. + */ +static bool +apply_pull_filter (const struct options *o, char *line) +{ + struct pull_filter *f; + + if (!o->pull_filter_list) return true; + + for (f = o->pull_filter_list->head; f; f = f->next) + { + if (f->type == PUF_TYPE_ACCEPT && strncmp (line, f->pattern, f->size) == 0) + { + msg (D_LOW, "Pushed option accepted by filter: '%s'", line); + return true; + } + else if (f->type == PUF_TYPE_IGNORE && strncmp (line, f->pattern, f->size) == 0) + { + msg (D_PUSH, "Pushed option removed by filter: '%s'", line); + *line = '\0'; + return true; + } + else if (f->type == PUF_TYPE_REJECT && strncmp (line, f->pattern, f->size) == 0) + { + msg (M_WARN, "Pushed option rejected by filter: '%s'. Restarting.", line); + *line = '\0'; + throw_signal_soft (SIGUSR1, "Offending option received from server"); + return false; + } + } + return true; +} + bool apply_push_options (struct options *options, struct buffer *buf, @@ -3981,6 +4103,10 @@ apply_push_options (struct options *options, char *p[MAX_PARMS]; CLEAR (p); ++line_num; + if (!apply_pull_filter(options, line)) + { + return false; /* Cause push/pull error and stop push processing */ + } if (parse_line (line, p, SIZE (p), file, line_num, msglevel, &options->gc)) { add_option (options, p, file, line_num, 0, msglevel, permission_mask, option_types_found, es); @@ -5373,6 +5499,26 @@ add_option (struct options *options, VERIFY_PERMISSION (OPT_P_GENERAL); options->route_nopull = true; } + else if (streq (p[0], "pull-filter") && p[1] && p[2] && !p[3]) + { + struct pull_filter *f; + VERIFY_PERMISSION (OPT_P_GENERAL) + f = alloc_pull_filter (options, msglevel); + + if (strcmp ("accept", p[1]) == 0) + f->type = PUF_TYPE_ACCEPT; + else if (strcmp ("ignore", p[1]) == 0) + f->type = PUF_TYPE_IGNORE; + else if (strcmp ("reject", p[1]) == 0) + f->type = PUF_TYPE_REJECT; + else + { + msg (msglevel, "Unknown --pull-filter type: %s", p[1]); + goto err; + } + f->pattern = p[2]; + f->size = strlen(p[2]); + } else if (streq (p[0], "allow-pull-fqdn") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); diff --git a/src/openvpn/options.h b/src/openvpn/options.h index 2fa375fd2b4..514511b7180 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -597,6 +597,8 @@ struct options const char *keying_material_exporter_label; int keying_material_exporter_length; #endif + + struct pull_filter_list *pull_filter_list; }; #define streq(x, y) (!strcmp((x), (y))) From 63b3e000c9141f4ca03a374354da26334257bc18 Mon Sep 17 00:00:00 2001 From: Selva Nair Date: Tue, 7 Jun 2016 00:44:20 -0400 Subject: [PATCH 260/643] Ignore SIGUSR1/SIGHUP during exit notification This allows exit notification to complete and finally trigger SIGTERM. The current practice of allowing a restart in this state clears the exit notification timer data and thus loses the SIGTERM. Trac #687 Signed-off-by: Selva Nair Acked-by: Gert Doering Message-Id: <1465274660-11009-2-git-send-email-selva.nair@gmail.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/11814 Signed-off-by: Gert Doering --- src/openvpn/sig.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/openvpn/sig.c b/src/openvpn/sig.c index f903fc0efae..718b78600e3 100644 --- a/src/openvpn/sig.c +++ b/src/openvpn/sig.c @@ -376,12 +376,35 @@ process_sigterm (struct context *c) return ret; } +/** + * If a restart signal is received during exit-notification, reset the + * signal and return true. + */ +static bool +ignore_restart_signals (struct context *c) +{ + bool ret = false; +#ifdef ENABLE_OCC + if ( (c->sig->signal_received == SIGUSR1 || c->sig->signal_received == SIGHUP) && + event_timeout_defined(&c->c2.explicit_exit_notification_interval) ) + { + msg (M_INFO, "Ignoring %s received during exit notification", + signal_name(c->sig->signal_received, true)); + signal_reset (c->sig); + ret = true; + } +#endif + return ret; +} + bool process_signal (struct context *c) { bool ret = true; - if (c->sig->signal_received == SIGTERM || c->sig->signal_received == SIGINT) + if (ignore_restart_signals (c)) + ret = false; + else if (c->sig->signal_received == SIGTERM || c->sig->signal_received == SIGINT) { ret = process_sigterm (c); } From 3c1b19e04745177185decd14da82c71458442b82 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Wed, 8 Jun 2016 14:20:39 +0200 Subject: [PATCH 261/643] Don't limit max incoming message size based on c2->frame "Be conservative in what you send, be liberal in what you accept" When receiving packets, the real limitation of how much data we can accept is the size of our internal buffers, not the maximum size we expect incoming packets to have. I ran into this while working on cipher negotiation, which will need separate bookkeeping for the required internal buffer size, and the link/tun MTU. Basing this code on the buffer size instead of c2->frame makes that easier. A nice side-effect of this change is that it simplifies the code. This should also reduce the impact of using asymmetric tun/link MTU's, such as in trac ticket #647. Signed-off-by: Steffan Karger Acked-by: Arne Schwabe Acked-by: Gert Doering Message-Id: <1465388443-15484-2-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/11850 Signed-off-by: Gert Doering --- src/openvpn/forward.c | 1 - src/openvpn/socket.c | 9 +++------ src/openvpn/socket.h | 4 +--- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c index 4a91f9206af..2c9a0826fc6 100644 --- a/src/openvpn/forward.c +++ b/src/openvpn/forward.c @@ -669,7 +669,6 @@ read_incoming_link (struct context *c) status = link_socket_read (c->c2.link_socket, &c->c2.buf, - MAX_RW_SIZE_LINK (&c->c2.frame), &c->c2.from); if (socket_connection_reset (c->c2.link_socket, status)) diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c index f7264ef6223..d2872bedf97 100644 --- a/src/openvpn/socket.c +++ b/src/openvpn/socket.c @@ -2886,7 +2886,6 @@ union openvpn_pktinfo { static socklen_t link_socket_read_udp_posix_recvmsg (struct link_socket *sock, struct buffer *buf, - int maxsize, struct link_socket_actual *from) { struct iovec iov; @@ -2895,7 +2894,7 @@ link_socket_read_udp_posix_recvmsg (struct link_socket *sock, socklen_t fromlen = sizeof (from->dest.addr); iov.iov_base = BPTR (buf); - iov.iov_len = maxsize; + iov.iov_len = buf_forward_capacity_total (buf); mesg.msg_iov = &iov; mesg.msg_iovlen = 1; mesg.msg_name = &from->dest.addr; @@ -2954,20 +2953,18 @@ link_socket_read_udp_posix_recvmsg (struct link_socket *sock, int link_socket_read_udp_posix (struct link_socket *sock, struct buffer *buf, - int maxsize, struct link_socket_actual *from) { socklen_t fromlen = sizeof (from->dest.addr); socklen_t expectedlen = af_addr_size(sock->info.af); addr_zero_host(&from->dest); - ASSERT (buf_safe (buf, maxsize)); #if ENABLE_IP_PKTINFO /* Both PROTO_UDPv4 and PROTO_UDPv6 */ if (sock->info.proto == PROTO_UDP && sock->sockflags & SF_USE_IP_PKTINFO) - fromlen = link_socket_read_udp_posix_recvmsg (sock, buf, maxsize, from); + fromlen = link_socket_read_udp_posix_recvmsg (sock, buf, from); else #endif - buf->len = recvfrom (sock->sd, BPTR (buf), maxsize, 0, + buf->len = recvfrom (sock->sd, BPTR (buf), buf_forward_capacity(buf), 0, &from->dest.addr.sa, &fromlen); /* FIXME: won't do anything when sock->info.af == AF_UNSPEC */ if (buf->len >= 0 && expectedlen && fromlen != expectedlen) diff --git a/src/openvpn/socket.h b/src/openvpn/socket.h index b154bc021ea..6f4d34f12a0 100644 --- a/src/openvpn/socket.h +++ b/src/openvpn/socket.h @@ -961,7 +961,6 @@ link_socket_read_udp_win32 (struct link_socket *sock, int link_socket_read_udp_posix (struct link_socket *sock, struct buffer *buf, - int maxsize, struct link_socket_actual *from); #endif @@ -970,7 +969,6 @@ int link_socket_read_udp_posix (struct link_socket *sock, static inline int link_socket_read (struct link_socket *sock, struct buffer *buf, - int maxsize, struct link_socket_actual *from) { if (proto_is_udp(sock->info.proto)) /* unified UDPv4 and UDPv6 */ @@ -980,7 +978,7 @@ link_socket_read (struct link_socket *sock, #ifdef WIN32 res = link_socket_read_udp_win32 (sock, buf, from); #else - res = link_socket_read_udp_posix (sock, buf, maxsize, from); + res = link_socket_read_udp_posix (sock, buf, from); #endif return res; } From d92718141287a0f9adcffec5c2fa7d76213162cc Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Wed, 8 Jun 2016 14:20:40 +0200 Subject: [PATCH 262/643] cleanup: remove alloc_buffers argument from multi_top_init() multi_top_init() is always called with alloc_buffers=true, so just remove the argument and alloc unconditionally. Signed-off-by: Steffan Karger Acked-by: Arne Schwabe Acked-by: Gert Doering Message-Id: <1465388443-15484-3-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/11851 Signed-off-by: Gert Doering --- src/openvpn/mtcp.c | 2 +- src/openvpn/mudp.c | 2 +- src/openvpn/multi.c | 6 ++---- src/openvpn/multi.h | 2 +- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/openvpn/mtcp.c b/src/openvpn/mtcp.c index 9926d476117..78e5ccd0a0e 100644 --- a/src/openvpn/mtcp.c +++ b/src/openvpn/mtcp.c @@ -696,7 +696,7 @@ tunnel_server_tcp (struct context *top) multi_init (&multi, top, true, MC_SINGLE_THREADED); /* initialize our cloned top object */ - multi_top_init (&multi, top, true); + multi_top_init (&multi, top); /* initialize management interface */ init_management_callback_multi (&multi); diff --git a/src/openvpn/mudp.c b/src/openvpn/mudp.c index ce6720604f9..6e0568e36ba 100644 --- a/src/openvpn/mudp.c +++ b/src/openvpn/mudp.c @@ -283,7 +283,7 @@ tunnel_server_udp_single_threaded (struct context *top) multi_init (&multi, top, false, MC_SINGLE_THREADED); /* initialize our cloned top object */ - multi_top_init (&multi, top, true); + multi_top_init (&multi, top); /* initialize management interface */ init_management_callback_multi (&multi); diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index 4c43fcc5b93..ba7f2c0a40b 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -2859,12 +2859,10 @@ multi_process_per_second_timers_dowork (struct multi_context *m) } void -multi_top_init (struct multi_context *m, const struct context *top, const bool alloc_buffers) +multi_top_init (struct multi_context *m, const struct context *top) { inherit_context_top (&m->top, top); - m->top.c2.buffers = NULL; - if (alloc_buffers) - m->top.c2.buffers = init_context_buffers (&top->c2.frame); + m->top.c2.buffers = init_context_buffers (&top->c2.frame); } void diff --git a/src/openvpn/multi.h b/src/openvpn/multi.h index ec1e7ab0242..9d8185d4983 100644 --- a/src/openvpn/multi.h +++ b/src/openvpn/multi.h @@ -233,7 +233,7 @@ const char *multi_instance_string (const struct multi_instance *mi, bool null, s void multi_init (struct multi_context *m, struct context *t, bool tcp_mode, int thread_mode); void multi_uninit (struct multi_context *m); -void multi_top_init (struct multi_context *m, const struct context *top, const bool alloc_buffers); +void multi_top_init (struct multi_context *m, const struct context *top); void multi_top_free (struct multi_context *m); struct multi_instance *multi_create_instance (struct multi_context *m, const struct mroute_addr *real); From 46e4b6639a950c56a08261b6610e7fe17404213d Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Thu, 9 Jun 2016 13:51:29 +0200 Subject: [PATCH 263/643] Upgrade bundled compat-lz4 to upstream release r131. Take upstream release from https://github.com/Cyan4973/lz4/releases, copy lz4-r131/lib/lz4.c to src/compat/compat-lz4.c copy lz4-r131/lib/lz4.h to src/compat/compat-lz4.h change #include line in compat-lz4.c to use "compat-lz4.h" not "lz4.h" add "config.h" block and wrap in #ifdef NEED_COMPAT_LZ4 / #endif No other changes to upstream code. This commit is quite huge, but this is because we bundled a fairly old version and upstream refactored quite a lot of code, changed // comments to /* */ style, etc - to review, compare compat-lz4.* files to upstream. v2: add missing #ifdef NEED_COMPAT_LZ4 wrapping Signed-off-by: Gert Doering Acked-by: Steffan Karger Message-Id: <1465473089-20754-1-git-send-email-gert@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/11879 Signed-off-by: Gert Doering --- src/compat/compat-lz4.c | 1704 +++++++++++++++++++++++++++------------ src/compat/compat-lz4.h | 375 ++++++--- 2 files changed, 1464 insertions(+), 615 deletions(-) diff --git a/src/compat/compat-lz4.c b/src/compat/compat-lz4.c index c63c18ba906..5855ca10b4d 100644 --- a/src/compat/compat-lz4.c +++ b/src/compat/compat-lz4.c @@ -1,6 +1,7 @@ /* LZ4 - Fast LZ compression algorithm - Copyright (C) 2011-2013, Yann Collet. + Copyright (C) 2011-2015, Yann Collet. + BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) Redistribution and use in source and binary forms, with or without @@ -27,7 +28,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at : - - LZ4 source repository : http://code.google.com/p/lz4/ + - LZ4 source repository : https://github.com/Cyan4973/lz4 - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c */ @@ -39,109 +40,63 @@ #ifdef NEED_COMPAT_LZ4 -//************************************** -// Tuning parameters -//************************************** -// MEMORY_USAGE : -// Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.) -// Increasing memory usage improves compression ratio -// Reduced memory usage can improve speed, due to cache effect -// Default value is 14, for 16KB, which nicely fits into Intel x86 L1 cache -#define MEMORY_USAGE 14 - -// HEAPMODE : -// Select how default compression functions will allocate memory for their hash table, -// in memory stack (0:default, fastest), or in memory heap (1:requires memory allocation (malloc)). +/************************************** +* Tuning parameters +**************************************/ +/* + * HEAPMODE : + * Select how default compression functions will allocate memory for their hash table, + * in memory stack (0:default, fastest), or in memory heap (1:requires malloc()). + */ #define HEAPMODE 0 +/* + * ACCELERATION_DEFAULT : + * Select "acceleration" for LZ4_compress_fast() when parameter value <= 0 + */ +#define ACCELERATION_DEFAULT 1 -//************************************** -// CPU Feature Detection -//************************************** -// 32 or 64 bits ? -#if (defined(__x86_64__) || defined(_M_X64) || defined(_WIN64) \ - || defined(__powerpc64__) || defined(__ppc64__) || defined(__PPC64__) \ - || defined(__64BIT__) || defined(_LP64) || defined(__LP64__) \ - || defined(__ia64) || defined(__itanium__) || defined(_M_IA64) ) // Detects 64 bits mode -# define LZ4_ARCH64 1 -#else -# define LZ4_ARCH64 0 -#endif - -// Little Endian or Big Endian ? -// Overwrite the #define below if you know your architecture endianess -#if defined (__GLIBC__) -# include -# if (__BYTE_ORDER == __BIG_ENDIAN) -# define LZ4_BIG_ENDIAN 1 -# endif -#elif (defined(__BIG_ENDIAN__) || defined(__BIG_ENDIAN) || defined(_BIG_ENDIAN)) && !(defined(__LITTLE_ENDIAN__) || defined(__LITTLE_ENDIAN) || defined(_LITTLE_ENDIAN)) -# define LZ4_BIG_ENDIAN 1 -#elif defined(__sparc) || defined(__sparc__) \ - || defined(__powerpc__) || defined(__ppc__) || defined(__PPC__) \ - || defined(__hpux) || defined(__hppa) \ - || defined(_MIPSEB) || defined(__s390__) -# define LZ4_BIG_ENDIAN 1 -#else -// Little Endian assumed. PDP Endian and other very rare endian format are unsupported. -#endif - -// Unaligned memory access is automatically enabled for "common" CPU, such as x86. -// For others CPU, such as ARM, the compiler may be more cautious, inserting unnecessary extra code to ensure aligned access property -// If you know your target CPU supports unaligned memory access, you want to force this option manually to improve performance -#if defined(__ARM_FEATURE_UNALIGNED) -# define LZ4_FORCE_UNALIGNED_ACCESS 1 -#endif -// Define this parameter if your target system or compiler does not support hardware bit count -#if defined(_MSC_VER) && defined(_WIN32_WCE) // Visual Studio for Windows CE does not support Hardware bit count +/************************************** +* CPU Feature Detection +**************************************/ +/* + * LZ4_FORCE_SW_BITCOUNT + * Define this parameter if your target system or compiler does not support hardware bit count + */ +#if defined(_MSC_VER) && defined(_WIN32_WCE) /* Visual Studio for Windows CE does not support Hardware bit count */ # define LZ4_FORCE_SW_BITCOUNT #endif -// BIG_ENDIAN_NATIVE_BUT_INCOMPATIBLE : -// This option may provide a small boost to performance for some big endian cpu, although probably modest. -// You may set this option to 1 if data will remain within closed environment. -// This option is useless on Little_Endian CPU (such as x86) -//#define BIG_ENDIAN_NATIVE_BUT_INCOMPATIBLE 1 +/************************************** +* Includes +**************************************/ +#include "compat-lz4.h" -//************************************** -// Compiler Options -//************************************** -#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) // C99 -/* "restrict" is a known keyword */ -#else -# define restrict // Disable restrict -#endif -#ifdef _MSC_VER // Visual Studio +/************************************** +* Compiler Options +**************************************/ +#ifdef _MSC_VER /* Visual Studio */ # define FORCE_INLINE static __forceinline -# include // For Visual 2005 -# if LZ4_ARCH64 // 64-bits -# pragma intrinsic(_BitScanForward64) // For Visual 2005 -# pragma intrinsic(_BitScanReverse64) // For Visual 2005 -# else // 32-bits -# pragma intrinsic(_BitScanForward) // For Visual 2005 -# pragma intrinsic(_BitScanReverse) // For Visual 2005 -# endif -# pragma warning(disable : 4127) // disable: C4127: conditional expression is constant +# include +# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ +# pragma warning(disable : 4293) /* disable: C4293: too large shift (32-bits) */ #else -# ifdef __GNUC__ -# define FORCE_INLINE static inline __attribute__((always_inline)) +# if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */ +# if defined(__GNUC__) || defined(__clang__) +# define FORCE_INLINE static inline __attribute__((always_inline)) +# else +# define FORCE_INLINE static inline +# endif # else -# define FORCE_INLINE static inline -# endif -#endif - -#ifdef _MSC_VER -# define lz4_bswap16(x) _byteswap_ushort(x) -#else -# define lz4_bswap16(x) ((unsigned short int) ((((x) >> 8) & 0xffu) | (((x) & 0xffu) << 8))) -#endif - -#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) +# define FORCE_INLINE static +# endif /* __STDC_VERSION__ */ +#endif /* _MSC_VER */ -#if (GCC_VERSION >= 302) || (__INTEL_COMPILER >= 800) || defined(__clang__) +/* LZ4_GCC_VERSION is defined into lz4.h */ +#if (LZ4_GCC_VERSION >= 302) || (__INTEL_COMPILER >= 800) || defined(__clang__) # define expect(expr,value) (__builtin_expect ((expr),(value)) ) #else # define expect(expr,value) (expr) @@ -151,26 +106,20 @@ #define unlikely(expr) expect((expr) != 0, 0) -//************************************** -// Memory routines -//************************************** -#include // malloc, calloc, free +/************************************** +* Memory routines +**************************************/ +#include /* malloc, calloc, free */ #define ALLOCATOR(n,s) calloc(n,s) #define FREEMEM free -#include // memset, memcpy +#include /* memset, memcpy */ #define MEM_INIT memset -//************************************** -// Includes -//************************************** -#include "compat-lz4.h" - - -//************************************** -// Basic Types -//************************************** -#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L // C99 +/************************************** +* Basic Types +**************************************/ +#if defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */ # include typedef uint8_t BYTE; typedef uint16_t U16; @@ -185,55 +134,105 @@ typedef unsigned long long U64; #endif -#if defined(__GNUC__) && !defined(LZ4_FORCE_UNALIGNED_ACCESS) -# define _PACKED __attribute__ ((packed)) -#else -# define _PACKED -#endif -#if !defined(LZ4_FORCE_UNALIGNED_ACCESS) && !defined(__GNUC__) -# if defined(__IBMC__) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) -# pragma pack(1) -# else -# pragma pack(push, 1) -# endif -#endif +/************************************** +* Reading and writing into memory +**************************************/ +#define STEPSIZE sizeof(size_t) -typedef struct { U16 v; } _PACKED U16_S; -typedef struct { U32 v; } _PACKED U32_S; -typedef struct { U64 v; } _PACKED U64_S; -typedef struct {size_t v;} _PACKED size_t_S; +static unsigned LZ4_64bits(void) { return sizeof(void*)==8; } -#if !defined(LZ4_FORCE_UNALIGNED_ACCESS) && !defined(__GNUC__) -# if defined(__SUNPRO_C) || defined(__SUNPRO_CC) -# pragma pack(0) -# else -# pragma pack(pop) -# endif -#endif +static unsigned LZ4_isLittleEndian(void) +{ + const union { U32 i; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */ + return one.c[0]; +} + + +static U16 LZ4_read16(const void* memPtr) +{ + U16 val16; + memcpy(&val16, memPtr, 2); + return val16; +} + +static U16 LZ4_readLE16(const void* memPtr) +{ + if (LZ4_isLittleEndian()) + { + return LZ4_read16(memPtr); + } + else + { + const BYTE* p = (const BYTE*)memPtr; + return (U16)((U16)p[0] + (p[1]<<8)); + } +} + +static void LZ4_writeLE16(void* memPtr, U16 value) +{ + if (LZ4_isLittleEndian()) + { + memcpy(memPtr, &value, 2); + } + else + { + BYTE* p = (BYTE*)memPtr; + p[0] = (BYTE) value; + p[1] = (BYTE)(value>>8); + } +} -#define A16(x) (((U16_S *)(x))->v) -#define A32(x) (((U32_S *)(x))->v) -#define A64(x) (((U64_S *)(x))->v) -#define AARCH(x) (((size_t_S *)(x))->v) +static U32 LZ4_read32(const void* memPtr) +{ + U32 val32; + memcpy(&val32, memPtr, 4); + return val32; +} +static U64 LZ4_read64(const void* memPtr) +{ + U64 val64; + memcpy(&val64, memPtr, 8); + return val64; +} -//************************************** -// Constants -//************************************** -#define LZ4_HASHLOG (MEMORY_USAGE-2) -#define HASHTABLESIZE (1 << MEMORY_USAGE) -#define HASHNBCELLS4 (1 << LZ4_HASHLOG) +static size_t LZ4_read_ARCH(const void* p) +{ + if (LZ4_64bits()) + return (size_t)LZ4_read64(p); + else + return (size_t)LZ4_read32(p); +} + + +static void LZ4_copy4(void* dstPtr, const void* srcPtr) { memcpy(dstPtr, srcPtr, 4); } + +static void LZ4_copy8(void* dstPtr, const void* srcPtr) { memcpy(dstPtr, srcPtr, 8); } + +/* customized version of memcpy, which may overwrite up to 7 bytes beyond dstEnd */ +static void LZ4_wildCopy(void* dstPtr, const void* srcPtr, void* dstEnd) +{ + BYTE* d = (BYTE*)dstPtr; + const BYTE* s = (const BYTE*)srcPtr; + BYTE* e = (BYTE*)dstEnd; + do { LZ4_copy8(d,s); d+=8; s+=8; } while (d>3); +# elif (defined(__clang__) || (LZ4_GCC_VERSION >= 304)) && !defined(LZ4_FORCE_SW_BITCOUNT) + return (__builtin_ctzll((U64)val) >> 3); +# else + static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, 0, 2, 3, 6, 1, 5, 3, 5, 1, 3, 4, 4, 2, 5, 6, 7, 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5, 5, 3, 4, 5, 6, 7, 1, 2, 4, 6, 4, 4, 5, 7, 2, 6, 5, 7, 6, 7, 7 }; + return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58]; +# endif + } + else /* 32 bits */ + { +# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) + unsigned long r; + _BitScanForward( &r, (U32)val ); + return (int)(r>>3); +# elif (defined(__clang__) || (LZ4_GCC_VERSION >= 304)) && !defined(LZ4_FORCE_SW_BITCOUNT) + return (__builtin_ctz((U32)val) >> 3); +# else + static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 }; + return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27]; +# endif + } + } + else /* Big Endian CPU */ + { + if (LZ4_64bits()) + { +# if defined(_MSC_VER) && defined(_WIN64) && !defined(LZ4_FORCE_SW_BITCOUNT) + unsigned long r = 0; + _BitScanReverse64( &r, val ); + return (unsigned)(r>>3); +# elif (defined(__clang__) || (LZ4_GCC_VERSION >= 304)) && !defined(LZ4_FORCE_SW_BITCOUNT) + return (__builtin_clzll((U64)val) >> 3); +# else + unsigned r; + if (!(val>>32)) { r=4; } else { r=0; val>>=32; } + if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; } + r += (!val); + return r; +# endif + } + else /* 32 bits */ + { +# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) + unsigned long r = 0; + _BitScanReverse( &r, (unsigned long)val ); + return (unsigned)(r>>3); +# elif (defined(__clang__) || (LZ4_GCC_VERSION >= 304)) && !defined(LZ4_FORCE_SW_BITCOUNT) + return (__builtin_clz((U32)val) >> 3); +# else + unsigned r; + if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; } + r += (!val); + return r; +# endif + } + } +} -typedef enum { notLimited = 0, limited = 1 } limitedOutput_directive; -typedef enum { byPtr, byU32, byU16 } tableType_t; +static unsigned LZ4_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* pInLimit) +{ + const BYTE* const pStart = pIn; -typedef enum { noPrefix = 0, withPrefix = 1 } prefix64k_directive; + while (likely(pIn compression run slower on incompressible data */ -//************************************** -// Macros -//************************************** -#define LZ4_WILDCOPY(d,s,e) { do { LZ4_COPY8(d,s) } while (d=e; - - -//**************************** -// Private functions -//**************************** -#if LZ4_ARCH64 - -FORCE_INLINE int LZ4_NbCommonBytes (register U64 val) -{ -# if defined(LZ4_BIG_ENDIAN) -# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) - unsigned long r = 0; - _BitScanReverse64( &r, val ); - return (int)(r>>3); -# elif defined(__GNUC__) && (GCC_VERSION >= 304) && !defined(LZ4_FORCE_SW_BITCOUNT) - return (__builtin_clzll(val) >> 3); -# else - int r; - if (!(val>>32)) { r=4; } else { r=0; val>>=32; } - if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; } - r += (!val); - return r; -# endif -# else -# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) - unsigned long r = 0; - _BitScanForward64( &r, val ); - return (int)(r>>3); -# elif defined(__GNUC__) && (GCC_VERSION >= 304) && !defined(LZ4_FORCE_SW_BITCOUNT) - return (__builtin_ctzll(val) >> 3); -# else - static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, 0, 2, 3, 6, 1, 5, 3, 5, 1, 3, 4, 4, 2, 5, 6, 7, 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5, 5, 3, 4, 5, 6, 7, 1, 2, 4, 6, 4, 4, 5, 7, 2, 6, 5, 7, 6, 7, 7 }; - return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58]; -# endif -# endif -} +/************************************** +* Local Structures and types +**************************************/ +typedef struct { + U32 hashTable[HASH_SIZE_U32]; + U32 currentOffset; + U32 initCheck; + const BYTE* dictionary; + BYTE* bufferStart; /* obsolete, used for slideInputBuffer */ + U32 dictSize; +} LZ4_stream_t_internal; + +typedef enum { notLimited = 0, limitedOutput = 1 } limitedOutput_directive; +typedef enum { byPtr, byU32, byU16 } tableType_t; -#else +typedef enum { noDict = 0, withPrefix64k, usingExtDict } dict_directive; +typedef enum { noDictIssue = 0, dictSmall } dictIssue_directive; -FORCE_INLINE int LZ4_NbCommonBytes (register U32 val) -{ -# if defined(LZ4_BIG_ENDIAN) -# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) - unsigned long r = 0; - _BitScanReverse( &r, val ); - return (int)(r>>3); -# elif defined(__GNUC__) && (GCC_VERSION >= 304) && !defined(LZ4_FORCE_SW_BITCOUNT) - return (__builtin_clz(val) >> 3); -# else - int r; - if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; } - r += (!val); - return r; -# endif -# else -# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) - unsigned long r; - _BitScanForward( &r, val ); - return (int)(r>>3); -# elif defined(__GNUC__) && (GCC_VERSION >= 304) && !defined(LZ4_FORCE_SW_BITCOUNT) - return (__builtin_ctz(val) >> 3); -# else - static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 }; - return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27]; -# endif -# endif -} +typedef enum { endOnOutputSize = 0, endOnInputSize = 1 } endCondition_directive; +typedef enum { full = 0, partial = 1 } earlyEnd_directive; -#endif + +/************************************** +* Local Utils +**************************************/ +int LZ4_versionNumber (void) { return LZ4_VERSION_NUMBER; } +int LZ4_compressBound(int isize) { return LZ4_COMPRESSBOUND(isize); } +int LZ4_sizeofState() { return LZ4_STREAMSIZE; } -//**************************** -// Compression functions -//**************************** -FORCE_INLINE int LZ4_hashSequence(U32 sequence, tableType_t tableType) + +/******************************** +* Compression functions +********************************/ + +static U32 LZ4_hashSequence(U32 sequence, tableType_t const tableType) { if (tableType == byU16) return (((sequence) * 2654435761U) >> ((MINMATCH*8)-(LZ4_HASHLOG+1))); @@ -379,220 +393,539 @@ FORCE_INLINE int LZ4_hashSequence(U32 sequence, tableType_t tableType) return (((sequence) * 2654435761U) >> ((MINMATCH*8)-LZ4_HASHLOG)); } -FORCE_INLINE int LZ4_hashPosition(const BYTE* p, tableType_t tableType) { return LZ4_hashSequence(A32(p), tableType); } +static const U64 prime5bytes = 889523592379ULL; +static U32 LZ4_hashSequence64(size_t sequence, tableType_t const tableType) +{ + const U32 hashLog = (tableType == byU16) ? LZ4_HASHLOG+1 : LZ4_HASHLOG; + const U32 hashMask = (1<> (40 - hashLog)) & hashMask; +} -FORCE_INLINE void LZ4_putPositionOnHash(const BYTE* p, U32 h, void* tableBase, tableType_t tableType, const BYTE* srcBase) +static U32 LZ4_hashSequenceT(size_t sequence, tableType_t const tableType) +{ + if (LZ4_64bits()) + return LZ4_hashSequence64(sequence, tableType); + return LZ4_hashSequence((U32)sequence, tableType); +} + +static U32 LZ4_hashPosition(const void* p, tableType_t tableType) { return LZ4_hashSequenceT(LZ4_read_ARCH(p), tableType); } + +static void LZ4_putPositionOnHash(const BYTE* p, U32 h, void* tableBase, tableType_t const tableType, const BYTE* srcBase) { switch (tableType) { - case byPtr: { const BYTE** hashTable = (const BYTE**) tableBase; hashTable[h] = p; break; } - case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = (U32)(p-srcBase); break; } - case byU16: { U16* hashTable = (U16*) tableBase; hashTable[h] = (U16)(p-srcBase); break; } + case byPtr: { const BYTE** hashTable = (const BYTE**)tableBase; hashTable[h] = p; return; } + case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = (U32)(p-srcBase); return; } + case byU16: { U16* hashTable = (U16*) tableBase; hashTable[h] = (U16)(p-srcBase); return; } } } -FORCE_INLINE void LZ4_putPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase) +static void LZ4_putPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase) { U32 h = LZ4_hashPosition(p, tableType); LZ4_putPositionOnHash(p, h, tableBase, tableType, srcBase); } -FORCE_INLINE const BYTE* LZ4_getPositionOnHash(U32 h, void* tableBase, tableType_t tableType, const BYTE* srcBase) +static const BYTE* LZ4_getPositionOnHash(U32 h, void* tableBase, tableType_t tableType, const BYTE* srcBase) { if (tableType == byPtr) { const BYTE** hashTable = (const BYTE**) tableBase; return hashTable[h]; } if (tableType == byU32) { U32* hashTable = (U32*) tableBase; return hashTable[h] + srcBase; } - { U16* hashTable = (U16*) tableBase; return hashTable[h] + srcBase; } // default, to ensure a return + { U16* hashTable = (U16*) tableBase; return hashTable[h] + srcBase; } /* default, to ensure a return */ } -FORCE_INLINE const BYTE* LZ4_getPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase) +static const BYTE* LZ4_getPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase) { U32 h = LZ4_hashPosition(p, tableType); return LZ4_getPositionOnHash(h, tableBase, tableType, srcBase); } - FORCE_INLINE int LZ4_compress_generic( - void* ctx, - const char* source, - char* dest, - int inputSize, - int maxOutputSize, - - limitedOutput_directive limitedOutput, - tableType_t tableType, - prefix64k_directive prefix) + void* const ctx, + const char* const source, + char* const dest, + const int inputSize, + const int maxOutputSize, + const limitedOutput_directive outputLimited, + const tableType_t tableType, + const dict_directive dict, + const dictIssue_directive dictIssue, + const U32 acceleration) { + LZ4_stream_t_internal* const dictPtr = (LZ4_stream_t_internal*)ctx; + const BYTE* ip = (const BYTE*) source; - const BYTE* const base = (prefix==withPrefix) ? ((LZ4_Data_Structure*)ctx)->base : (const BYTE*) source; - const BYTE* const lowLimit = ((prefix==withPrefix) ? ((LZ4_Data_Structure*)ctx)->bufferStart : (const BYTE*)source); + const BYTE* base; + const BYTE* lowLimit; + const BYTE* const lowRefLimit = ip - dictPtr->dictSize; + const BYTE* const dictionary = dictPtr->dictionary; + const BYTE* const dictEnd = dictionary + dictPtr->dictSize; + const size_t dictDelta = dictEnd - (const BYTE*)source; const BYTE* anchor = (const BYTE*) source; const BYTE* const iend = ip + inputSize; const BYTE* const mflimit = iend - MFLIMIT; const BYTE* const matchlimit = iend - LASTLITERALS; BYTE* op = (BYTE*) dest; - BYTE* const oend = op + maxOutputSize; + BYTE* const olimit = op + maxOutputSize; - int length; - const int skipStrength = SKIPSTRENGTH; U32 forwardH; + size_t refDelta=0; - // Init conditions - if ((U32)inputSize > (U32)LZ4_MAX_INPUT_SIZE) return 0; // Unsupported input size, too large (or negative) - if ((prefix==withPrefix) && (ip != ((LZ4_Data_Structure*)ctx)->nextBlock)) return 0; // must continue from end of previous block - if (prefix==withPrefix) ((LZ4_Data_Structure*)ctx)->nextBlock=iend; // do it now, due to potential early exit - if ((tableType == byU16) && (inputSize>=LZ4_64KLIMIT)) return 0; // Size too large (not within 64K limit) - if (inputSize (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported input size, too large (or negative) */ + switch(dict) + { + case noDict: + default: + base = (const BYTE*)source; + lowLimit = (const BYTE*)source; + break; + case withPrefix64k: + base = (const BYTE*)source - dictPtr->currentOffset; + lowLimit = (const BYTE*)source - dictPtr->dictSize; + break; + case usingExtDict: + base = (const BYTE*)source - dictPtr->currentOffset; + lowLimit = (const BYTE*)source; + break; + } + if ((tableType == byU16) && (inputSize>=LZ4_64Klimit)) return 0; /* Size too large (not within 64K limit) */ + if (inputSize> LZ4_skipTrigger); + + if (unlikely(forwardIp > mflimit)) goto _last_literals; + + match = LZ4_getPositionOnHash(h, ctx, tableType, base); + if (dict==usingExtDict) + { + if (match<(const BYTE*)source) + { + refDelta = dictDelta; + lowLimit = dictionary; + } + else + { + refDelta = 0; + lowLimit = (const BYTE*)source; + } + } + forwardH = LZ4_hashPosition(forwardIp, tableType); + LZ4_putPositionOnHash(ip, h, ctx, tableType, base); + + } while ( ((dictIssue==dictSmall) ? (match < lowRefLimit) : 0) + || ((tableType==byU16) ? 0 : (match + MAX_DISTANCE < ip)) + || (LZ4_read32(match+refDelta) != LZ4_read32(ip)) ); + } - // Find a match - do { - U32 h = forwardH; - int step = findMatchAttempts++ >> skipStrength; - ip = forwardIp; - forwardIp = ip + step; - - if unlikely(forwardIp > mflimit) { goto _last_literals; } + /* Catch up */ + while ((ip>anchor) && (match+refDelta > lowLimit) && (unlikely(ip[-1]==match[refDelta-1]))) { ip--; match--; } - forwardH = LZ4_hashPosition(forwardIp, tableType); - ref = LZ4_getPositionOnHash(h, ctx, tableType, base); - LZ4_putPositionOnHash(ip, h, ctx, tableType, base); + { + /* Encode Literal length */ + unsigned litLength = (unsigned)(ip - anchor); + token = op++; + if ((outputLimited) && (unlikely(op + litLength + (2 + 1 + LASTLITERALS) + (litLength/255) > olimit))) + return 0; /* Check output limit */ + if (litLength>=RUN_MASK) + { + int len = (int)litLength-RUN_MASK; + *token=(RUN_MASK<= 255 ; len-=255) *op++ = 255; + *op++ = (BYTE)len; + } + else *token = (BYTE)(litLength<anchor) && (ref > lowLimit) && unlikely(ip[-1]==ref[-1])) { ip--; ref--; } +_next_match: + /* Encode Offset */ + LZ4_writeLE16(op, (U16)(ip-match)); op+=2; - // Encode Literal length - length = (int)(ip - anchor); - token = op++; - if ((limitedOutput) && unlikely(op + length + (2 + 1 + LASTLITERALS) + (length/255) > oend)) return 0; // Check output limit - if (length>=(int)RUN_MASK) + /* Encode MatchLength */ { - int len = length-RUN_MASK; - *token=(RUN_MASK<= 255 ; len-=255) *op++ = 255; - *op++ = (BYTE)len; - } - else *token = (BYTE)(length< matchlimit) limit = matchlimit; + matchLength = LZ4_count(ip+MINMATCH, match+MINMATCH, limit); + ip += MINMATCH + matchLength; + if (ip==limit) + { + unsigned more = LZ4_count(ip, (const BYTE*)source, matchlimit); + matchLength += more; + ip += more; + } + } + else + { + matchLength = LZ4_count(ip+MINMATCH, match+MINMATCH, matchlimit); + ip += MINMATCH + matchLength; + } -_next_match: - // Encode Offset - LZ4_WRITE_LITTLEENDIAN_16(op,(U16)(ip-ref)); + if ((outputLimited) && (unlikely(op + (1 + LASTLITERALS) + (matchLength>>8) > olimit))) + return 0; /* Check output limit */ + if (matchLength>=ML_MASK) + { + *token += ML_MASK; + matchLength -= ML_MASK; + for (; matchLength >= 510 ; matchLength-=510) { *op++ = 255; *op++ = 255; } + if (matchLength >= 255) { matchLength-=255; *op++ = 255; } + *op++ = (BYTE)matchLength; + } + else *token += (BYTE)(matchLength); + } - // Start Counting - ip+=MINMATCH; ref+=MINMATCH; // MinMatch already verified anchor = ip; - while likely(ip>8) > oend)) return 0; // Check output limit - if (length>=(int)ML_MASK) - { - *token += ML_MASK; - length -= ML_MASK; - for (; length > 509 ; length-=510) { *op++ = 255; *op++ = 255; } - if (length >= 255) { length-=255; *op++ = 255; } - *op++ = (BYTE)length; - } - else *token += (BYTE)(length); - // Test end of chunk - if (ip > mflimit) { anchor = ip; break; } + /* Test end of chunk */ + if (ip > mflimit) break; - // Fill table + /* Fill table */ LZ4_putPosition(ip-2, ctx, tableType, base); - // Test next position - ref = LZ4_getPosition(ip, ctx, tableType, base); + /* Test next position */ + match = LZ4_getPosition(ip, ctx, tableType, base); + if (dict==usingExtDict) + { + if (match<(const BYTE*)source) + { + refDelta = dictDelta; + lowLimit = dictionary; + } + else + { + refDelta = 0; + lowLimit = (const BYTE*)source; + } + } LZ4_putPosition(ip, ctx, tableType, base); - if ((ref + MAX_DISTANCE >= ip) && (A32(ref) == A32(ip))) { token = op++; *token=0; goto _next_match; } + if ( ((dictIssue==dictSmall) ? (match>=lowRefLimit) : 1) + && (match+MAX_DISTANCE>=ip) + && (LZ4_read32(match+refDelta)==LZ4_read32(ip)) ) + { token=op++; *token=0; goto _next_match; } - // Prepare next loop - anchor = ip++; - forwardH = LZ4_hashPosition(ip, tableType); + /* Prepare next loop */ + forwardH = LZ4_hashPosition(++ip, tableType); } _last_literals: - // Encode Last Literals + /* Encode Last Literals */ { - int lastRun = (int)(iend - anchor); - if ((limitedOutput) && (((char*)op - dest) + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > (U32)maxOutputSize)) return 0; // Check output limit - if (lastRun>=(int)RUN_MASK) { *op++=(RUN_MASK<= 255 ; lastRun-=255) *op++ = 255; *op++ = (BYTE) lastRun; } - else *op++ = (BYTE)(lastRun< (U32)maxOutputSize)) + return 0; /* Check output limit */ + if (lastRun >= RUN_MASK) + { + size_t accumulator = lastRun - RUN_MASK; + *op++ = RUN_MASK << ML_BITS; + for(; accumulator >= 255 ; accumulator-=255) *op++ = 255; + *op++ = (BYTE) accumulator; + } + else + { + *op++ = (BYTE)(lastRun<= LZ4_compressBound(inputSize)) + { + if (inputSize < LZ4_64Klimit) + return LZ4_compress_generic(state, source, dest, inputSize, 0, notLimited, byU16, noDict, noDictIssue, acceleration); + else + return LZ4_compress_generic(state, source, dest, inputSize, 0, notLimited, LZ4_64bits() ? byU32 : byPtr, noDict, noDictIssue, acceleration); + } + else + { + if (inputSize < LZ4_64Klimit) + return LZ4_compress_generic(state, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration); + else + return LZ4_compress_generic(state, source, dest, inputSize, maxOutputSize, limitedOutput, LZ4_64bits() ? byU32 : byPtr, noDict, noDictIssue, acceleration); + } +} + + +int LZ4_compress_fast(const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration) { #if (HEAPMODE) - void* ctx = ALLOCATOR(HASHNBCELLS4, 4); // Aligned on 4-bytes boundaries + void* ctxPtr = ALLOCATOR(1, sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */ #else - U32 ctx[1U<<(MEMORY_USAGE-2)] = {0}; // Ensure data is aligned on 4-bytes boundaries + LZ4_stream_t ctx; + void* ctxPtr = &ctx; #endif - int result; - if (inputSize < (int)LZ4_64KLIMIT) - result = LZ4_compress_generic((void*)ctx, source, dest, inputSize, 0, notLimited, byU16, noPrefix); - else - result = LZ4_compress_generic((void*)ctx, source, dest, inputSize, 0, notLimited, (sizeof(void*)==8) ? byU32 : byPtr, noPrefix); + int result = LZ4_compress_fast_extState(ctxPtr, source, dest, inputSize, maxOutputSize, acceleration); #if (HEAPMODE) - FREEMEM(ctx); + FREEMEM(ctxPtr); #endif return result; } -int LZ4_compress_continue (void* LZ4_Data, const char* source, char* dest, int inputSize) + +int LZ4_compress_default(const char* source, char* dest, int inputSize, int maxOutputSize) +{ + return LZ4_compress_fast(source, dest, inputSize, maxOutputSize, 1); +} + + +/* hidden debug function */ +/* strangely enough, gcc generates faster code when this function is uncommented, even if unused */ +int LZ4_compress_fast_force(const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration) +{ + LZ4_stream_t ctx; + + LZ4_resetStream(&ctx); + + if (inputSize < LZ4_64Klimit) + return LZ4_compress_generic(&ctx, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration); + else + return LZ4_compress_generic(&ctx, source, dest, inputSize, maxOutputSize, limitedOutput, LZ4_64bits() ? byU32 : byPtr, noDict, noDictIssue, acceleration); +} + + +/******************************** +* destSize variant +********************************/ + +static int LZ4_compress_destSize_generic( + void* const ctx, + const char* const src, + char* const dst, + int* const srcSizePtr, + const int targetDstSize, + const tableType_t tableType) +{ + const BYTE* ip = (const BYTE*) src; + const BYTE* base = (const BYTE*) src; + const BYTE* lowLimit = (const BYTE*) src; + const BYTE* anchor = ip; + const BYTE* const iend = ip + *srcSizePtr; + const BYTE* const mflimit = iend - MFLIMIT; + const BYTE* const matchlimit = iend - LASTLITERALS; + + BYTE* op = (BYTE*) dst; + BYTE* const oend = op + targetDstSize; + BYTE* const oMaxLit = op + targetDstSize - 2 /* offset */ - 8 /* because 8+MINMATCH==MFLIMIT */ - 1 /* token */; + BYTE* const oMaxMatch = op + targetDstSize - (LASTLITERALS + 1 /* token */); + BYTE* const oMaxSeq = oMaxLit - 1 /* token */; + + U32 forwardH; + + + /* Init conditions */ + if (targetDstSize < 1) return 0; /* Impossible to store anything */ + if ((U32)*srcSizePtr > (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported input size, too large (or negative) */ + if ((tableType == byU16) && (*srcSizePtr>=LZ4_64Klimit)) return 0; /* Size too large (not within 64K limit) */ + if (*srcSizePtr> LZ4_skipTrigger); + + if (unlikely(forwardIp > mflimit)) + goto _last_literals; + + match = LZ4_getPositionOnHash(h, ctx, tableType, base); + forwardH = LZ4_hashPosition(forwardIp, tableType); + LZ4_putPositionOnHash(ip, h, ctx, tableType, base); + + } while ( ((tableType==byU16) ? 0 : (match + MAX_DISTANCE < ip)) + || (LZ4_read32(match) != LZ4_read32(ip)) ); + } + + /* Catch up */ + while ((ip>anchor) && (match > lowLimit) && (unlikely(ip[-1]==match[-1]))) { ip--; match--; } + + { + /* Encode Literal length */ + unsigned litLength = (unsigned)(ip - anchor); + token = op++; + if (op + ((litLength+240)/255) + litLength > oMaxLit) + { + /* Not enough space for a last match */ + op--; + goto _last_literals; + } + if (litLength>=RUN_MASK) + { + unsigned len = litLength - RUN_MASK; + *token=(RUN_MASK<= 255 ; len-=255) *op++ = 255; + *op++ = (BYTE)len; + } + else *token = (BYTE)(litLength< oMaxMatch) + { + /* Match description too long : reduce it */ + matchLength = (15-1) + (oMaxMatch-op) * 255; + } + //printf("offset %5i, matchLength%5i \n", (int)(ip-match), matchLength + MINMATCH); + ip += MINMATCH + matchLength; + + if (matchLength>=ML_MASK) + { + *token += ML_MASK; + matchLength -= ML_MASK; + while (matchLength >= 255) { matchLength-=255; *op++ = 255; } + *op++ = (BYTE)matchLength; + } + else *token += (BYTE)(matchLength); + } + + anchor = ip; + + /* Test end of block */ + if (ip > mflimit) break; + if (op > oMaxSeq) break; + + /* Fill table */ + LZ4_putPosition(ip-2, ctx, tableType, base); + + /* Test next position */ + match = LZ4_getPosition(ip, ctx, tableType, base); + LZ4_putPosition(ip, ctx, tableType, base); + if ( (match+MAX_DISTANCE>=ip) + && (LZ4_read32(match)==LZ4_read32(ip)) ) + { token=op++; *token=0; goto _next_match; } + + /* Prepare next loop */ + forwardH = LZ4_hashPosition(++ip, tableType); + } + +_last_literals: + /* Encode Last Literals */ + { + size_t lastRunSize = (size_t)(iend - anchor); + if (op + 1 /* token */ + ((lastRunSize+240)/255) /* litLength */ + lastRunSize /* literals */ > oend) + { + /* adapt lastRunSize to fill 'dst' */ + lastRunSize = (oend-op) - 1; + lastRunSize -= (lastRunSize+240)/255; + } + ip = anchor + lastRunSize; + + if (lastRunSize >= RUN_MASK) + { + size_t accumulator = lastRunSize - RUN_MASK; + *op++ = RUN_MASK << ML_BITS; + for(; accumulator >= 255 ; accumulator-=255) *op++ = 255; + *op++ = (BYTE) accumulator; + } + else + { + *op++ = (BYTE)(lastRunSize<= LZ4_compressBound(*srcSizePtr)) /* compression success is guaranteed */ + { + return LZ4_compress_fast_extState(state, src, dst, *srcSizePtr, targetDstSize, 1); + } + else + { + if (*srcSizePtr < LZ4_64Klimit) + return LZ4_compress_destSize_generic(state, src, dst, srcSizePtr, targetDstSize, byU16); + else + return LZ4_compress_destSize_generic(state, src, dst, srcSizePtr, targetDstSize, LZ4_64bits() ? byU32 : byPtr); + } } -int LZ4_compress_limitedOutput(const char* source, char* dest, int inputSize, int maxOutputSize) +int LZ4_compress_destSize(const char* src, char* dst, int* srcSizePtr, int targetDstSize) { #if (HEAPMODE) - void* ctx = ALLOCATOR(HASHNBCELLS4, 4); // Aligned on 4-bytes boundaries + void* ctx = ALLOCATOR(1, sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */ #else - U32 ctx[1U<<(MEMORY_USAGE-2)] = {0}; // Ensure data is aligned on 4-bytes boundaries + LZ4_stream_t ctxBody; + void* ctx = &ctxBody; #endif - int result; - if (inputSize < (int)LZ4_64KLIMIT) - result = LZ4_compress_generic((void*)ctx, source, dest, inputSize, maxOutputSize, limited, byU16, noPrefix); - else - result = LZ4_compress_generic((void*)ctx, source, dest, inputSize, maxOutputSize, limited, (sizeof(void*)==8) ? byU32 : byPtr, noPrefix); + int result = LZ4_compress_destSize_extState(ctx, src, dst, srcSizePtr, targetDstSize); #if (HEAPMODE) FREEMEM(ctx); @@ -600,231 +933,592 @@ int LZ4_compress_limitedOutput(const char* source, char* dest, int inputSize, in return result; } -int LZ4_compress_limitedOutput_continue (void* LZ4_Data, const char* source, char* dest, int inputSize, int maxOutputSize) + + +/******************************** +* Streaming functions +********************************/ + +LZ4_stream_t* LZ4_createStream(void) { - return LZ4_compress_generic(LZ4_Data, source, dest, inputSize, maxOutputSize, limited, byU32, withPrefix); + LZ4_stream_t* lz4s = (LZ4_stream_t*)ALLOCATOR(8, LZ4_STREAMSIZE_U64); + LZ4_STATIC_ASSERT(LZ4_STREAMSIZE >= sizeof(LZ4_stream_t_internal)); /* A compilation error here means LZ4_STREAMSIZE is not large enough */ + LZ4_resetStream(lz4s); + return lz4s; } +void LZ4_resetStream (LZ4_stream_t* LZ4_stream) +{ + MEM_INIT(LZ4_stream, 0, sizeof(LZ4_stream_t)); +} -//**************************** -// Stream functions -//**************************** - -FORCE_INLINE void LZ4_init(LZ4_Data_Structure* lz4ds, const BYTE* base) +int LZ4_freeStream (LZ4_stream_t* LZ4_stream) { - MEM_INIT(lz4ds->hashTable, 0, sizeof(lz4ds->hashTable)); - lz4ds->bufferStart = base; - lz4ds->base = base; - lz4ds->nextBlock = base; + FREEMEM(LZ4_stream); + return (0); } -void* LZ4_create (const char* inputBuffer) +#define HASH_UNIT sizeof(size_t) +int LZ4_loadDict (LZ4_stream_t* LZ4_dict, const char* dictionary, int dictSize) { - void* lz4ds = ALLOCATOR(1, sizeof(LZ4_Data_Structure)); - LZ4_init ((LZ4_Data_Structure*)lz4ds, (const BYTE*)inputBuffer); - return lz4ds; + LZ4_stream_t_internal* dict = (LZ4_stream_t_internal*) LZ4_dict; + const BYTE* p = (const BYTE*)dictionary; + const BYTE* const dictEnd = p + dictSize; + const BYTE* base; + + if ((dict->initCheck) || (dict->currentOffset > 1 GB)) /* Uninitialized structure, or reuse overflow */ + LZ4_resetStream(LZ4_dict); + + if (dictSize < (int)HASH_UNIT) + { + dict->dictionary = NULL; + dict->dictSize = 0; + return 0; + } + + if ((dictEnd - p) > 64 KB) p = dictEnd - 64 KB; + dict->currentOffset += 64 KB; + base = p - dict->currentOffset; + dict->dictionary = p; + dict->dictSize = (U32)(dictEnd - p); + dict->currentOffset += dict->dictSize; + + while (p <= dictEnd-HASH_UNIT) + { + LZ4_putPosition(p, dict->hashTable, byU32, base); + p+=3; + } + + return dict->dictSize; } -int LZ4_free (void* LZ4_Data) +static void LZ4_renormDictT(LZ4_stream_t_internal* LZ4_dict, const BYTE* src) { - FREEMEM(LZ4_Data); - return (0); + if ((LZ4_dict->currentOffset > 0x80000000) || + ((size_t)LZ4_dict->currentOffset > (size_t)src)) /* address space overflow */ + { + /* rescale hash table */ + U32 delta = LZ4_dict->currentOffset - 64 KB; + const BYTE* dictEnd = LZ4_dict->dictionary + LZ4_dict->dictSize; + int i; + for (i=0; ihashTable[i] < delta) LZ4_dict->hashTable[i]=0; + else LZ4_dict->hashTable[i] -= delta; + } + LZ4_dict->currentOffset = 64 KB; + if (LZ4_dict->dictSize > 64 KB) LZ4_dict->dictSize = 64 KB; + LZ4_dict->dictionary = dictEnd - LZ4_dict->dictSize; + } } -char* LZ4_slideInputBuffer (void* LZ4_Data) +int LZ4_compress_fast_continue (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration) { - LZ4_Data_Structure* lz4ds = (LZ4_Data_Structure*)LZ4_Data; - size_t delta = lz4ds->nextBlock - (lz4ds->bufferStart + 64 KB); + LZ4_stream_t_internal* streamPtr = (LZ4_stream_t_internal*)LZ4_stream; + const BYTE* const dictEnd = streamPtr->dictionary + streamPtr->dictSize; - if ( (lz4ds->base - delta > lz4ds->base) // underflow control - || ((size_t)(lz4ds->nextBlock - lz4ds->base) > 0xE0000000) ) // close to 32-bits limit - { - size_t deltaLimit = (lz4ds->nextBlock - 64 KB) - lz4ds->base; - int nH; + const BYTE* smallest = (const BYTE*) source; + if (streamPtr->initCheck) return 0; /* Uninitialized structure detected */ + if ((streamPtr->dictSize>0) && (smallest>dictEnd)) smallest = dictEnd; + LZ4_renormDictT(streamPtr, smallest); + if (acceleration < 1) acceleration = ACCELERATION_DEFAULT; - for (nH=0; nH < HASHNBCELLS4; nH++) + /* Check overlapping input/dictionary space */ + { + const BYTE* sourceEnd = (const BYTE*) source + inputSize; + if ((sourceEnd > streamPtr->dictionary) && (sourceEnd < dictEnd)) { - if ((size_t)(lz4ds->hashTable[nH]) < deltaLimit) lz4ds->hashTable[nH] = 0; - else lz4ds->hashTable[nH] -= (U32)deltaLimit; + streamPtr->dictSize = (U32)(dictEnd - sourceEnd); + if (streamPtr->dictSize > 64 KB) streamPtr->dictSize = 64 KB; + if (streamPtr->dictSize < 4) streamPtr->dictSize = 0; + streamPtr->dictionary = dictEnd - streamPtr->dictSize; } - memcpy((void*)(lz4ds->bufferStart), (const void*)(lz4ds->nextBlock - 64 KB), 64 KB); - lz4ds->base = lz4ds->bufferStart; - lz4ds->nextBlock = lz4ds->base + 64 KB; } - else + + /* prefix mode : source data follows dictionary */ + if (dictEnd == (const BYTE*)source) + { + int result; + if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) + result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, withPrefix64k, dictSmall, acceleration); + else + result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, withPrefix64k, noDictIssue, acceleration); + streamPtr->dictSize += (U32)inputSize; + streamPtr->currentOffset += (U32)inputSize; + return result; + } + + /* external dictionary mode */ { - memcpy((void*)(lz4ds->bufferStart), (const void*)(lz4ds->nextBlock - 64 KB), 64 KB); - lz4ds->nextBlock -= delta; - lz4ds->base -= delta; + int result; + if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) + result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, usingExtDict, dictSmall, acceleration); + else + result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, usingExtDict, noDictIssue, acceleration); + streamPtr->dictionary = (const BYTE*)source; + streamPtr->dictSize = (U32)inputSize; + streamPtr->currentOffset += (U32)inputSize; + return result; } +} + + +/* Hidden debug function, to force external dictionary mode */ +int LZ4_compress_forceExtDict (LZ4_stream_t* LZ4_dict, const char* source, char* dest, int inputSize) +{ + LZ4_stream_t_internal* streamPtr = (LZ4_stream_t_internal*)LZ4_dict; + int result; + const BYTE* const dictEnd = streamPtr->dictionary + streamPtr->dictSize; - return (char*)(lz4ds->nextBlock); + const BYTE* smallest = dictEnd; + if (smallest > (const BYTE*) source) smallest = (const BYTE*) source; + LZ4_renormDictT((LZ4_stream_t_internal*)LZ4_dict, smallest); + + result = LZ4_compress_generic(LZ4_dict, source, dest, inputSize, 0, notLimited, byU32, usingExtDict, noDictIssue, 1); + + streamPtr->dictionary = (const BYTE*)source; + streamPtr->dictSize = (U32)inputSize; + streamPtr->currentOffset += (U32)inputSize; + + return result; } -//**************************** -// Decompression functions -//**************************** +int LZ4_saveDict (LZ4_stream_t* LZ4_dict, char* safeBuffer, int dictSize) +{ + LZ4_stream_t_internal* dict = (LZ4_stream_t_internal*) LZ4_dict; + const BYTE* previousDictEnd = dict->dictionary + dict->dictSize; + + if ((U32)dictSize > 64 KB) dictSize = 64 KB; /* useless to define a dictionary > 64 KB */ + if ((U32)dictSize > dict->dictSize) dictSize = dict->dictSize; -// This generic decompression function cover all use cases. -// It shall be instanciated several times, using different sets of directives -// Note that it is essential this generic function is really inlined, -// in order to remove useless branches during compilation optimisation. + memmove(safeBuffer, previousDictEnd - dictSize, dictSize); + + dict->dictionary = (const BYTE*)safeBuffer; + dict->dictSize = (U32)dictSize; + + return dictSize; +} + + + +/******************************* +* Decompression functions +*******************************/ +/* + * This generic decompression function cover all use cases. + * It shall be instantiated several times, using different sets of directives + * Note that it is essential this generic function is really inlined, + * in order to remove useless branches during compilation optimization. + */ FORCE_INLINE int LZ4_decompress_generic( - const char* source, - char* dest, - int inputSize, // - int outputSize, // If endOnInput==endOnInputSize, this value is the max size of Output Buffer. - - int endOnInput, // endOnOutputSize, endOnInputSize - int prefix64k, // noPrefix, withPrefix - int partialDecoding, // full, partial - int targetOutputSize // only used if partialDecoding==partial + const char* const source, + char* const dest, + int inputSize, + int outputSize, /* If endOnInput==endOnInputSize, this value is the max size of Output Buffer. */ + + int endOnInput, /* endOnOutputSize, endOnInputSize */ + int partialDecoding, /* full, partial */ + int targetOutputSize, /* only used if partialDecoding==partial */ + int dict, /* noDict, withPrefix64k, usingExtDict */ + const BYTE* const lowPrefix, /* == dest if dict == noDict */ + const BYTE* const dictStart, /* only if dict==usingExtDict */ + const size_t dictSize /* note : = 0 if noDict */ ) { - // Local Variables - const BYTE* restrict ip = (const BYTE*) source; - const BYTE* ref; + /* Local Variables */ + const BYTE* ip = (const BYTE*) source; const BYTE* const iend = ip + inputSize; BYTE* op = (BYTE*) dest; BYTE* const oend = op + outputSize; BYTE* cpy; BYTE* oexit = op + targetOutputSize; + const BYTE* const lowLimit = lowPrefix - dictSize; - const size_t dec32table[] = {0, 3, 2, 3, 0, 0, 0, 0}; // static reduces speed for LZ4_decompress_safe() on GCC64 - static const size_t dec64table[] = {0, 0, 0, (size_t)-1, 0, 1, 2, 3}; + const BYTE* const dictEnd = (const BYTE*)dictStart + dictSize; + const size_t dec32table[] = {4, 1, 2, 1, 4, 4, 4, 4}; + const size_t dec64table[] = {0, 0, 0, (size_t)-1, 0, 1, 2, 3}; + const int safeDecode = (endOnInput==endOnInputSize); + const int checkOffset = ((safeDecode) && (dictSize < (int)(64 KB))); - // Special cases - if ((partialDecoding) && (oexit> oend-MFLIMIT)) oexit = oend-MFLIMIT; // targetOutputSize too high => decode everything - if ((endOnInput) && unlikely(outputSize==0)) return ((inputSize==1) && (*ip==0)) ? 0 : -1; // Empty output buffer - if ((!endOnInput) && unlikely(outputSize==0)) return (*ip==0?1:-1); + /* Special cases */ + if ((partialDecoding) && (oexit> oend-MFLIMIT)) oexit = oend-MFLIMIT; /* targetOutputSize too high => decode everything */ + if ((endOnInput) && (unlikely(outputSize==0))) return ((inputSize==1) && (*ip==0)) ? 0 : -1; /* Empty output buffer */ + if ((!endOnInput) && (unlikely(outputSize==0))) return (*ip==0?1:-1); - // Main Loop + + /* Main Loop */ while (1) { unsigned token; size_t length; + const BYTE* match; - // get runlength + /* get literal length */ token = *ip++; if ((length=(token>>ML_BITS)) == RUN_MASK) { - unsigned s=255; - while (((endOnInput)?ip(partialDecoding?oexit:oend-MFLIMIT)) || (ip+length>iend-(2+1+LASTLITERALS))) ) || ((!endOnInput) && (cpy>oend-COPYLENGTH))) { if (partialDecoding) { - if (cpy > oend) goto _output_error; // Error : write attempt beyond end of output buffer - if ((endOnInput) && (ip+length > iend)) goto _output_error; // Error : read attempt beyond end of input buffer + if (cpy > oend) goto _output_error; /* Error : write attempt beyond end of output buffer */ + if ((endOnInput) && (ip+length > iend)) goto _output_error; /* Error : read attempt beyond end of input buffer */ } else { - if ((!endOnInput) && (cpy != oend)) goto _output_error; // Error : block decoding must stop exactly there - if ((endOnInput) && ((ip+length != iend) || (cpy > oend))) goto _output_error; // Error : input must be consumed + if ((!endOnInput) && (cpy != oend)) goto _output_error; /* Error : block decoding must stop exactly there */ + if ((endOnInput) && ((ip+length != iend) || (cpy > oend))) goto _output_error; /* Error : input must be consumed */ } memcpy(op, ip, length); ip += length; op += length; - break; // Necessarily EOF, due to parsing restrictions + break; /* Necessarily EOF, due to parsing restrictions */ } - LZ4_WILDCOPY(op, ip, cpy); ip -= (op-cpy); op = cpy; + LZ4_wildCopy(op, ip, cpy); + ip += length; op = cpy; - // get offset - LZ4_READ_LITTLEENDIAN_16(ref,cpy,ip); ip+=2; - if ((prefix64k==noPrefix) && unlikely(ref < (BYTE* const)dest)) goto _output_error; // Error : offset outside destination buffer + /* get offset */ + match = cpy - LZ4_readLE16(ip); ip+=2; + if ((checkOffset) && (unlikely(match < lowLimit))) goto _output_error; /* Error : offset outside destination buffer */ - // get matchlength - if ((length=(token&ML_MASK)) == ML_MASK) + /* get matchlength */ + length = token & ML_MASK; + if (length == ML_MASK) { - while ((!endOnInput) || (ip iend-LASTLITERALS)) goto _output_error; + s = *ip++; length += s; - if (s==255) continue; - break; + } while (s==255); + if ((safeDecode) && unlikely((size_t)(op+length)<(size_t)op)) goto _output_error; /* overflow detection */ + } + length += MINMATCH; + + /* check external dictionary */ + if ((dict==usingExtDict) && (match < lowPrefix)) + { + if (unlikely(op+length > oend-LASTLITERALS)) goto _output_error; /* doesn't respect parsing restriction */ + + if (length <= (size_t)(lowPrefix-match)) + { + /* match can be copied as a single segment from external dictionary */ + match = dictEnd - (lowPrefix-match); + memmove(op, match, length); op += length; + } + else + { + /* match encompass external dictionary and current segment */ + size_t copySize = (size_t)(lowPrefix-match); + memcpy(op, dictEnd - copySize, copySize); + op += copySize; + copySize = length - copySize; + if (copySize > (size_t)(op-lowPrefix)) /* overlap within current segment */ + { + BYTE* const endOfMatch = op + copySize; + const BYTE* copyFrom = lowPrefix; + while (op < endOfMatch) *op++ = *copyFrom++; + } + else + { + memcpy(op, lowPrefix, copySize); + op += copySize; + } } + continue; } - // copy repeated sequence - if unlikely((op-ref)<(int)STEPSIZE) + /* copy repeated sequence */ + cpy = op + length; + if (unlikely((op-match)<8)) { - const size_t dec64 = dec64table[(sizeof(void*)==4) ? 0 : op-ref]; - op[0] = ref[0]; - op[1] = ref[1]; - op[2] = ref[2]; - op[3] = ref[3]; - op += 4, ref += 4; ref -= dec32table[op-ref]; - A32(op) = A32(ref); - op += STEPSIZE-4; ref -= dec64; - } else { LZ4_COPYSTEP(op,ref); } - cpy = op + length - (STEPSIZE-4); - - if unlikely(cpy>oend-COPYLENGTH-(STEPSIZE-4)) + const size_t dec64 = dec64table[op-match]; + op[0] = match[0]; + op[1] = match[1]; + op[2] = match[2]; + op[3] = match[3]; + match += dec32table[op-match]; + LZ4_copy4(op+4, match); + op += 8; match -= dec64; + } else { LZ4_copy8(op, match); op+=8; match+=8; } + + if (unlikely(cpy>oend-12)) { - if (cpy > oend-LASTLITERALS) goto _output_error; // Error : last 5 bytes must be literals - LZ4_SECURECOPY(op, ref, (oend-COPYLENGTH)); - while(op oend-LASTLITERALS) goto _output_error; /* Error : last LASTLITERALS bytes must be literals */ + if (op < oend-8) + { + LZ4_wildCopy(op, match, oend-8); + match += (oend-8) - op; + op = oend-8; + } + while (opprefixSize = (size_t) dictSize; + lz4sd->prefixEnd = (const BYTE*) dictionary + dictSize; + lz4sd->externalDict = NULL; + lz4sd->extDictSize = 0; + return 1; +} + +/* +*_continue() : + These decoding functions allow decompression of multiple blocks in "streaming" mode. + Previously decoded blocks must still be available at the memory position where they were decoded. + If it's not possible, save the relevant part of decoded data into a safe buffer, + and indicate where it stands using LZ4_setStreamDecode() +*/ +int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int compressedSize, int maxOutputSize) +{ + LZ4_streamDecode_t_internal* lz4sd = (LZ4_streamDecode_t_internal*) LZ4_streamDecode; + int result; + + if (lz4sd->prefixEnd == (BYTE*)dest) + { + result = LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, + endOnInputSize, full, 0, + usingExtDict, lz4sd->prefixEnd - lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize); + if (result <= 0) return result; + lz4sd->prefixSize += result; + lz4sd->prefixEnd += result; + } + else + { + lz4sd->extDictSize = lz4sd->prefixSize; + lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize; + result = LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, + endOnInputSize, full, 0, + usingExtDict, (BYTE*)dest, lz4sd->externalDict, lz4sd->extDictSize); + if (result <= 0) return result; + lz4sd->prefixSize = result; + lz4sd->prefixEnd = (BYTE*)dest + result; + } + + return result; +} + +int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int originalSize) +{ + LZ4_streamDecode_t_internal* lz4sd = (LZ4_streamDecode_t_internal*) LZ4_streamDecode; + int result; + + if (lz4sd->prefixEnd == (BYTE*)dest) + { + result = LZ4_decompress_generic(source, dest, 0, originalSize, + endOnOutputSize, full, 0, + usingExtDict, lz4sd->prefixEnd - lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize); + if (result <= 0) return result; + lz4sd->prefixSize += originalSize; + lz4sd->prefixEnd += originalSize; + } + else + { + lz4sd->extDictSize = lz4sd->prefixSize; + lz4sd->externalDict = (BYTE*)dest - lz4sd->extDictSize; + result = LZ4_decompress_generic(source, dest, 0, originalSize, + endOnOutputSize, full, 0, + usingExtDict, (BYTE*)dest, lz4sd->externalDict, lz4sd->extDictSize); + if (result <= 0) return result; + lz4sd->prefixSize = originalSize; + lz4sd->prefixEnd = (BYTE*)dest + originalSize; + } + + return result; +} + + +/* +Advanced decoding functions : +*_usingDict() : + These decoding functions work the same as "_continue" ones, + the dictionary must be explicitly provided within parameters +*/ + +FORCE_INLINE int LZ4_decompress_usingDict_generic(const char* source, char* dest, int compressedSize, int maxOutputSize, int safe, const char* dictStart, int dictSize) +{ + if (dictSize==0) + return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, noDict, (BYTE*)dest, NULL, 0); + if (dictStart+dictSize == dest) + { + if (dictSize >= (int)(64 KB - 1)) + return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, withPrefix64k, (BYTE*)dest-64 KB, NULL, 0); + return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, noDict, (BYTE*)dest-dictSize, NULL, 0); + } + return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, usingExtDict, (BYTE*)dest, (const BYTE*)dictStart, dictSize); +} + +int LZ4_decompress_safe_usingDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const char* dictStart, int dictSize) +{ + return LZ4_decompress_usingDict_generic(source, dest, compressedSize, maxOutputSize, 1, dictStart, dictSize); +} + +int LZ4_decompress_fast_usingDict(const char* source, char* dest, int originalSize, const char* dictStart, int dictSize) +{ + return LZ4_decompress_usingDict_generic(source, dest, 0, originalSize, 0, dictStart, dictSize); +} + +/* debug function */ +int LZ4_decompress_safe_forceExtDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const char* dictStart, int dictSize) +{ + return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, usingExtDict, (BYTE*)dest, (const BYTE*)dictStart, dictSize); +} + + +/*************************************************** +* Obsolete Functions +***************************************************/ +/* obsolete compression functions */ +int LZ4_compress_limitedOutput(const char* source, char* dest, int inputSize, int maxOutputSize) { return LZ4_compress_default(source, dest, inputSize, maxOutputSize); } +int LZ4_compress(const char* source, char* dest, int inputSize) { return LZ4_compress_default(source, dest, inputSize, LZ4_compressBound(inputSize)); } +int LZ4_compress_limitedOutput_withState (void* state, const char* src, char* dst, int srcSize, int dstSize) { return LZ4_compress_fast_extState(state, src, dst, srcSize, dstSize, 1); } +int LZ4_compress_withState (void* state, const char* src, char* dst, int srcSize) { return LZ4_compress_fast_extState(state, src, dst, srcSize, LZ4_compressBound(srcSize), 1); } +int LZ4_compress_limitedOutput_continue (LZ4_stream_t* LZ4_stream, const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_fast_continue(LZ4_stream, src, dst, srcSize, maxDstSize, 1); } +int LZ4_compress_continue (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize) { return LZ4_compress_fast_continue(LZ4_stream, source, dest, inputSize, LZ4_compressBound(inputSize), 1); } + +/* +These function names are deprecated and should no longer be used. +They are only provided here for compatibility with older user programs. +- LZ4_uncompress is totally equivalent to LZ4_decompress_fast +- LZ4_uncompress_unknownOutputSize is totally equivalent to LZ4_decompress_safe +*/ +int LZ4_uncompress (const char* source, char* dest, int outputSize) { return LZ4_decompress_fast(source, dest, outputSize); } +int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize) { return LZ4_decompress_safe(source, dest, isize, maxOutputSize); } + + +/* Obsolete Streaming functions */ + +int LZ4_sizeofStreamState() { return LZ4_STREAMSIZE; } + +static void LZ4_init(LZ4_stream_t_internal* lz4ds, BYTE* base) +{ + MEM_INIT(lz4ds, 0, LZ4_STREAMSIZE); + lz4ds->bufferStart = base; +} + +int LZ4_resetStreamState(void* state, char* inputBuffer) +{ + if ((((size_t)state) & 3) != 0) return 1; /* Error : pointer is not aligned on 4-bytes boundary */ + LZ4_init((LZ4_stream_t_internal*)state, (BYTE*)inputBuffer); + return 0; +} + +void* LZ4_create (char* inputBuffer) +{ + void* lz4ds = ALLOCATOR(8, LZ4_STREAMSIZE_U64); + LZ4_init ((LZ4_stream_t_internal*)lz4ds, (BYTE*)inputBuffer); + return lz4ds; +} + +char* LZ4_slideInputBuffer (void* LZ4_Data) +{ + LZ4_stream_t_internal* ctx = (LZ4_stream_t_internal*)LZ4_Data; + int dictSize = LZ4_saveDict((LZ4_stream_t*)LZ4_Data, (char*)ctx->bufferStart, 64 KB); + return (char*)(ctx->bufferStart + dictSize); +} + +/* Obsolete streaming decompression functions */ + +int LZ4_decompress_safe_withPrefix64k(const char* source, char* dest, int compressedSize, int maxOutputSize) +{ + return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, withPrefix64k, (BYTE*)dest - 64 KB, NULL, 64 KB); +} + +int LZ4_decompress_fast_withPrefix64k(const char* source, char* dest, int originalSize) +{ + return LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, withPrefix64k, (BYTE*)dest - 64 KB, NULL, 64 KB); +} + +#endif /* LZ4_COMMONDEFS_ONLY */ + +#endif /* NEED_COMPAT_LZ4 */ diff --git a/src/compat/compat-lz4.h b/src/compat/compat-lz4.h index a289fcfdcc3..3e740022561 100644 --- a/src/compat/compat-lz4.h +++ b/src/compat/compat-lz4.h @@ -1,7 +1,8 @@ /* LZ4 - Fast LZ compression algorithm Header File - Copyright (C) 2011-2013, Yann Collet. + Copyright (C) 2011-2015, Yann Collet. + BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) Redistribution and use in source and binary forms, with or without @@ -28,8 +29,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at : - - LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html - - LZ4 source repository : http://code.google.com/p/lz4/ + - LZ4 source repository : https://github.com/Cyan4973/lz4 + - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c */ #pragma once @@ -37,167 +38,321 @@ extern "C" { #endif +/* + * lz4.h provides block compression functions, and gives full buffer control to programmer. + * If you need to generate inter-operable compressed data (respecting LZ4 frame specification), + * and can let the library handle its own memory, please use lz4frame.h instead. +*/ -//************************************** -// Compiler Options -//************************************** -#if defined(_MSC_VER) && !defined(__cplusplus) // Visual Studio -# define inline __inline // Visual C is not C99, but supports some kind of inline -#endif +/************************************** +* Version +**************************************/ +#define LZ4_VERSION_MAJOR 1 /* for breaking interface changes */ +#define LZ4_VERSION_MINOR 7 /* for new (non-breaking) interface capabilities */ +#define LZ4_VERSION_RELEASE 1 /* for tweaks, bug-fixes, or development */ +#define LZ4_VERSION_NUMBER (LZ4_VERSION_MAJOR *100*100 + LZ4_VERSION_MINOR *100 + LZ4_VERSION_RELEASE) +int LZ4_versionNumber (void); + +/************************************** +* Tuning parameter +**************************************/ +/* + * LZ4_MEMORY_USAGE : + * Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.) + * Increasing memory usage improves compression ratio + * Reduced memory usage can improve speed, due to cache effect + * Default value is 14, for 16KB, which nicely fits into Intel x86 L1 cache + */ +#define LZ4_MEMORY_USAGE 14 -//**************************** -// Simple Functions -//**************************** +/************************************** +* Simple Functions +**************************************/ -int LZ4_compress (const char* source, char* dest, int inputSize); -int LZ4_decompress_safe (const char* source, char* dest, int inputSize, int maxOutputSize); +int LZ4_compress_default(const char* source, char* dest, int sourceSize, int maxDestSize); +int LZ4_decompress_safe (const char* source, char* dest, int compressedSize, int maxDecompressedSize); /* -LZ4_compress() : - Compresses 'inputSize' bytes from 'source' into 'dest'. - Destination buffer must be already allocated, - and must be sized to handle worst cases situations (input data not compressible) - Worst case size evaluation is provided by function LZ4_compressBound() - inputSize : Max supported value is LZ4_MAX_INPUT_VALUE - return : the number of bytes written in buffer dest - or 0 if the compression fails +LZ4_compress_default() : + Compresses 'sourceSize' bytes from buffer 'source' + into already allocated 'dest' buffer of size 'maxDestSize'. + Compression is guaranteed to succeed if 'maxDestSize' >= LZ4_compressBound(sourceSize). + It also runs faster, so it's a recommended setting. + If the function cannot compress 'source' into a more limited 'dest' budget, + compression stops *immediately*, and the function result is zero. + As a consequence, 'dest' content is not valid. + This function never writes outside 'dest' buffer, nor read outside 'source' buffer. + sourceSize : Max supported value is LZ4_MAX_INPUT_VALUE + maxDestSize : full or partial size of buffer 'dest' (which must be already allocated) + return : the number of bytes written into buffer 'dest' (necessarily <= maxOutputSize) + or 0 if compression fails LZ4_decompress_safe() : - maxOutputSize : is the size of the destination buffer (which must be already allocated) - return : the number of bytes decoded in the destination buffer (necessarily <= maxOutputSize) + compressedSize : is the precise full size of the compressed block. + maxDecompressedSize : is the size of destination buffer, which must be already allocated. + return : the number of bytes decompressed into destination buffer (necessarily <= maxDecompressedSize) + If destination buffer is not large enough, decoding will stop and output an error code (<0). If the source stream is detected malformed, the function will stop decoding and return a negative result. - This function is protected against buffer overflow exploits (never writes outside of output buffer, and never reads outside of input buffer). Therefore, it is protected against malicious data packets + This function is protected against buffer overflow exploits, including malicious data packets. + It never writes outside output buffer, nor reads outside input buffer. */ -//**************************** -// Advanced Functions -//**************************** -#define LZ4_MAX_INPUT_SIZE 0x7E000000 // 2 113 929 216 bytes -#define LZ4_COMPRESSBOUND(isize) ((unsigned int)(isize) > (unsigned int)LZ4_MAX_INPUT_SIZE ? 0 : (isize) + ((isize)/255) + 16) -static inline int LZ4_compressBound(int isize) { return LZ4_COMPRESSBOUND(isize); } +/************************************** +* Advanced Functions +**************************************/ +#define LZ4_MAX_INPUT_SIZE 0x7E000000 /* 2 113 929 216 bytes */ +#define LZ4_COMPRESSBOUND(isize) ((unsigned)(isize) > (unsigned)LZ4_MAX_INPUT_SIZE ? 0 : (isize) + ((isize)/255) + 16) /* LZ4_compressBound() : - Provides the maximum size that LZ4 may output in a "worst case" scenario (input data not compressible) - primarily useful for memory allocation of output buffer. - inline function is recommended for the general case, - macro is also provided when result needs to be evaluated at compilation (such as stack memory allocation). - - isize : is the input size. Max supported value is LZ4_MAX_INPUT_SIZE - return : maximum output size in a "worst case" scenario - or 0, if input size is too large ( > LZ4_MAX_INPUT_SIZE) + Provides the maximum size that LZ4 compression may output in a "worst case" scenario (input data not compressible) + This function is primarily useful for memory allocation purposes (destination buffer size). + Macro LZ4_COMPRESSBOUND() is also provided for compilation-time evaluation (stack memory allocation for example). + Note that LZ4_compress_default() compress faster when dest buffer size is >= LZ4_compressBound(srcSize) + inputSize : max supported value is LZ4_MAX_INPUT_SIZE + return : maximum output size in a "worst case" scenario + or 0, if input size is too large ( > LZ4_MAX_INPUT_SIZE) */ +int LZ4_compressBound(int inputSize); +/* +LZ4_compress_fast() : + Same as LZ4_compress_default(), but allows to select an "acceleration" factor. + The larger the acceleration value, the faster the algorithm, but also the lesser the compression. + It's a trade-off. It can be fine tuned, with each successive value providing roughly +~3% to speed. + An acceleration value of "1" is the same as regular LZ4_compress_default() + Values <= 0 will be replaced by ACCELERATION_DEFAULT (see lz4.c), which is 1. +*/ +int LZ4_compress_fast (const char* source, char* dest, int sourceSize, int maxDestSize, int acceleration); -int LZ4_compress_limitedOutput (const char* source, char* dest, int inputSize, int maxOutputSize); /* -LZ4_compress_limitedOutput() : - Compress 'inputSize' bytes from 'source' into an output buffer 'dest' of maximum size 'maxOutputSize'. - If it cannot achieve it, compression will stop, and result of the function will be zero. - This function never writes outside of provided output buffer. - - inputSize : Max supported value is LZ4_MAX_INPUT_VALUE - maxOutputSize : is the size of the destination buffer (which must be already allocated) - return : the number of bytes written in buffer 'dest' - or 0 if the compression fails +LZ4_compress_fast_extState() : + Same compression function, just using an externally allocated memory space to store compression state. + Use LZ4_sizeofState() to know how much memory must be allocated, + and allocate it on 8-bytes boundaries (using malloc() typically). + Then, provide it as 'void* state' to compression function. */ +int LZ4_sizeofState(void); +int LZ4_compress_fast_extState (void* state, const char* source, char* dest, int inputSize, int maxDestSize, int acceleration); + +/* +LZ4_compress_destSize() : + Reverse the logic, by compressing as much data as possible from 'source' buffer + into already allocated buffer 'dest' of size 'targetDestSize'. + This function either compresses the entire 'source' content into 'dest' if it's large enough, + or fill 'dest' buffer completely with as much data as possible from 'source'. + *sourceSizePtr : will be modified to indicate how many bytes where read from 'source' to fill 'dest'. + New value is necessarily <= old value. + return : Nb bytes written into 'dest' (necessarily <= targetDestSize) + or 0 if compression fails +*/ +int LZ4_compress_destSize (const char* source, char* dest, int* sourceSizePtr, int targetDestSize); -int LZ4_decompress_fast (const char* source, char* dest, int outputSize); /* LZ4_decompress_fast() : - outputSize : is the original (uncompressed) size + originalSize : is the original and therefore uncompressed size return : the number of bytes read from the source buffer (in other words, the compressed size) - If the source stream is malformed, the function will stop decoding and return a negative result. - note : This function is a bit faster than LZ4_decompress_safe() - This function never writes outside of output buffers, but may read beyond input buffer in case of malicious data packet. - Use this function preferably into a trusted environment (data to decode comes from a trusted source). - Destination buffer must be already allocated. Its size must be a minimum of 'outputSize' bytes. + If the source stream is detected malformed, the function will stop decoding and return a negative result. + Destination buffer must be already allocated. Its size must be a minimum of 'originalSize' bytes. + note : This function fully respect memory boundaries for properly formed compressed data. + It is a bit faster than LZ4_decompress_safe(). + However, it does not provide any protection against intentionally modified data stream (malicious input). + Use this function in trusted environment only (data to decode comes from a trusted source). */ - -int LZ4_decompress_safe_partial (const char* source, char* dest, int inputSize, int targetOutputSize, int maxOutputSize); +int LZ4_decompress_fast (const char* source, char* dest, int originalSize); /* LZ4_decompress_safe_partial() : - This function decompress a compressed block of size 'inputSize' at position 'source' - into output buffer 'dest' of size 'maxOutputSize'. + This function decompress a compressed block of size 'compressedSize' at position 'source' + into destination buffer 'dest' of size 'maxDecompressedSize'. The function tries to stop decompressing operation as soon as 'targetOutputSize' has been reached, reducing decompression time. - return : the number of bytes decoded in the destination buffer (necessarily <= maxOutputSize) + return : the number of bytes decoded in the destination buffer (necessarily <= maxDecompressedSize) Note : this number can be < 'targetOutputSize' should the compressed block to decode be smaller. Always control how many bytes were decoded. If the source stream is detected malformed, the function will stop decoding and return a negative result. This function never writes outside of output buffer, and never reads outside of input buffer. It is therefore protected against malicious data packets */ +int LZ4_decompress_safe_partial (const char* source, char* dest, int compressedSize, int targetOutputSize, int maxDecompressedSize); -//**************************** -// Stream Functions -//**************************** - -void* LZ4_create (const char* inputBuffer); -int LZ4_compress_continue (void* LZ4_Data, const char* source, char* dest, int inputSize); -int LZ4_compress_limitedOutput_continue (void* LZ4_Data, const char* source, char* dest, int inputSize, int maxOutputSize); -char* LZ4_slideInputBuffer (void* LZ4_Data); -int LZ4_free (void* LZ4_Data); - +/*********************************************** +* Streaming Compression Functions +***********************************************/ +#define LZ4_STREAMSIZE_U64 ((1 << (LZ4_MEMORY_USAGE-3)) + 4) +#define LZ4_STREAMSIZE (LZ4_STREAMSIZE_U64 * sizeof(long long)) /* -These functions allow the compression of dependent blocks, where each block benefits from prior 64 KB within preceding blocks. -In order to achieve this, it is necessary to start creating the LZ4 Data Structure, thanks to the function : - -void* LZ4_create (const char* inputBuffer); -The result of the function is the (void*) pointer on the LZ4 Data Structure. -This pointer will be needed in all other functions. -If the pointer returned is NULL, then the allocation has failed, and compression must be aborted. -The only parameter 'const char* inputBuffer' must, obviously, point at the beginning of input buffer. -The input buffer must be already allocated, and size at least 192KB. -'inputBuffer' will also be the 'const char* source' of the first block. + * LZ4_stream_t + * information structure to track an LZ4 stream. + * important : init this structure content before first use ! + * note : only allocated directly the structure if you are statically linking LZ4 + * If you are using liblz4 as a DLL, please use below construction methods instead. + */ +typedef struct { long long table[LZ4_STREAMSIZE_U64]; } LZ4_stream_t; -All blocks are expected to lay next to each other within the input buffer, starting from 'inputBuffer'. -To compress each block, use either LZ4_compress_continue() or LZ4_compress_limitedOutput_continue(). -Their behavior are identical to LZ4_compress() or LZ4_compress_limitedOutput(), -but require the LZ4 Data Structure as their first argument, and check that each block starts right after the previous one. -If next block does not begin immediately after the previous one, the compression will fail (return 0). +/* + * LZ4_resetStream + * Use this function to init an allocated LZ4_stream_t structure + */ +void LZ4_resetStream (LZ4_stream_t* streamPtr); -When it's no longer possible to lay the next block after the previous one (not enough space left into input buffer), a call to : -char* LZ4_slideInputBuffer(void* LZ4_Data); -must be performed. It will typically copy the latest 64KB of input at the beginning of input buffer. -Note that, for this function to work properly, minimum size of an input buffer must be 192KB. -==> The memory position where the next input data block must start is provided as the result of the function. +/* + * LZ4_createStream will allocate and initialize an LZ4_stream_t structure + * LZ4_freeStream releases its memory. + * In the context of a DLL (liblz4), please use these methods rather than the static struct. + * They are more future proof, in case of a change of LZ4_stream_t size. + */ +LZ4_stream_t* LZ4_createStream(void); +int LZ4_freeStream (LZ4_stream_t* streamPtr); -Compression can then resume, using LZ4_compress_continue() or LZ4_compress_limitedOutput_continue(), as usual. +/* + * LZ4_loadDict + * Use this function to load a static dictionary into LZ4_stream. + * Any previous data will be forgotten, only 'dictionary' will remain in memory. + * Loading a size of 0 is allowed. + * Return : dictionary size, in bytes (necessarily <= 64 KB) + */ +int LZ4_loadDict (LZ4_stream_t* streamPtr, const char* dictionary, int dictSize); -When compression is completed, a call to LZ4_free() will release the memory used by the LZ4 Data Structure. -*/ +/* + * LZ4_compress_fast_continue + * Compress buffer content 'src', using data from previously compressed blocks as dictionary to improve compression ratio. + * Important : Previous data blocks are assumed to still be present and unmodified ! + * 'dst' buffer must be already allocated. + * If maxDstSize >= LZ4_compressBound(srcSize), compression is guaranteed to succeed, and runs faster. + * If not, and if compressed data cannot fit into 'dst' buffer size, compression stops, and function returns a zero. + */ +int LZ4_compress_fast_continue (LZ4_stream_t* streamPtr, const char* src, char* dst, int srcSize, int maxDstSize, int acceleration); +/* + * LZ4_saveDict + * If previously compressed data block is not guaranteed to remain available at its memory location + * save it into a safer place (char* safeBuffer) + * Note : you don't need to call LZ4_loadDict() afterwards, + * dictionary is immediately usable, you can therefore call LZ4_compress_fast_continue() + * Return : saved dictionary size in bytes (necessarily <= dictSize), or 0 if error + */ +int LZ4_saveDict (LZ4_stream_t* streamPtr, char* safeBuffer, int dictSize); + + +/************************************************ +* Streaming Decompression Functions +************************************************/ + +#define LZ4_STREAMDECODESIZE_U64 4 +#define LZ4_STREAMDECODESIZE (LZ4_STREAMDECODESIZE_U64 * sizeof(unsigned long long)) +typedef struct { unsigned long long table[LZ4_STREAMDECODESIZE_U64]; } LZ4_streamDecode_t; +/* + * LZ4_streamDecode_t + * information structure to track an LZ4 stream. + * init this structure content using LZ4_setStreamDecode or memset() before first use ! + * + * In the context of a DLL (liblz4) please prefer usage of construction methods below. + * They are more future proof, in case of a change of LZ4_streamDecode_t size in the future. + * LZ4_createStreamDecode will allocate and initialize an LZ4_streamDecode_t structure + * LZ4_freeStreamDecode releases its memory. + */ +LZ4_streamDecode_t* LZ4_createStreamDecode(void); +int LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream); -int LZ4_decompress_safe_withPrefix64k (const char* source, char* dest, int inputSize, int maxOutputSize); -int LZ4_decompress_fast_withPrefix64k (const char* source, char* dest, int outputSize); +/* + * LZ4_setStreamDecode + * Use this function to instruct where to find the dictionary. + * Setting a size of 0 is allowed (same effect as reset). + * Return : 1 if OK, 0 if error + */ +int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dictionary, int dictSize); /* -*_withPrefix64k() : - These decoding functions work the same as their "normal name" versions, - but can use up to 64KB of data in front of 'char* dest'. - These functions are necessary to decode inter-dependant blocks. +*_continue() : + These decoding functions allow decompression of multiple blocks in "streaming" mode. + Previously decoded blocks *must* remain available at the memory position where they were decoded (up to 64 KB) + In the case of a ring buffers, decoding buffer must be either : + - Exactly same size as encoding buffer, with same update rule (block boundaries at same positions) + In which case, the decoding & encoding ring buffer can have any size, including very small ones ( < 64 KB). + - Larger than encoding buffer, by a minimum of maxBlockSize more bytes. + maxBlockSize is implementation dependent. It's the maximum size you intend to compress into a single block. + In which case, encoding and decoding buffers do not need to be synchronized, + and encoding ring buffer can have any size, including small ones ( < 64 KB). + - _At least_ 64 KB + 8 bytes + maxBlockSize. + In which case, encoding and decoding buffers do not need to be synchronized, + and encoding ring buffer can have any size, including larger than decoding buffer. + Whenever these conditions are not possible, save the last 64KB of decoded data into a safe buffer, + and indicate where it is saved using LZ4_setStreamDecode() */ +int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int compressedSize, int maxDecompressedSize); +int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int originalSize); -//**************************** -// Obsolete Functions -//**************************** - -static inline int LZ4_uncompress (const char* source, char* dest, int outputSize) { return LZ4_decompress_fast(source, dest, outputSize); } -static inline int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize) { return LZ4_decompress_safe(source, dest, isize, maxOutputSize); } - /* -These functions are deprecated and should no longer be used. -They are provided here for compatibility with existing user programs. +Advanced decoding functions : +*_usingDict() : + These decoding functions work the same as + a combination of LZ4_setStreamDecode() followed by LZ4_decompress_x_continue() + They are stand-alone. They don't need nor update an LZ4_streamDecode_t structure. */ - +int LZ4_decompress_safe_usingDict (const char* source, char* dest, int compressedSize, int maxDecompressedSize, const char* dictStart, int dictSize); +int LZ4_decompress_fast_usingDict (const char* source, char* dest, int originalSize, const char* dictStart, int dictSize); + + + +/************************************** +* Obsolete Functions +**************************************/ +/* Deprecate Warnings */ +/* Should these warnings messages be a problem, + it is generally possible to disable them, + with -Wno-deprecated-declarations for gcc + or _CRT_SECURE_NO_WARNINGS in Visual for example. + You can also define LZ4_DEPRECATE_WARNING_DEFBLOCK. */ +#ifndef LZ4_DEPRECATE_WARNING_DEFBLOCK +# define LZ4_DEPRECATE_WARNING_DEFBLOCK +# define LZ4_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) +# if (LZ4_GCC_VERSION >= 405) || defined(__clang__) +# define LZ4_DEPRECATED(message) __attribute__((deprecated(message))) +# elif (LZ4_GCC_VERSION >= 301) +# define LZ4_DEPRECATED(message) __attribute__((deprecated)) +# elif defined(_MSC_VER) +# define LZ4_DEPRECATED(message) __declspec(deprecated(message)) +# else +# pragma message("WARNING: You need to implement LZ4_DEPRECATED for this compiler") +# define LZ4_DEPRECATED(message) +# endif +#endif /* LZ4_DEPRECATE_WARNING_DEFBLOCK */ + +/* Obsolete compression functions */ +/* These functions are planned to start generate warnings by r131 approximately */ +int LZ4_compress (const char* source, char* dest, int sourceSize); +int LZ4_compress_limitedOutput (const char* source, char* dest, int sourceSize, int maxOutputSize); +int LZ4_compress_withState (void* state, const char* source, char* dest, int inputSize); +int LZ4_compress_limitedOutput_withState (void* state, const char* source, char* dest, int inputSize, int maxOutputSize); +int LZ4_compress_continue (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize); +int LZ4_compress_limitedOutput_continue (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize, int maxOutputSize); + +/* Obsolete decompression functions */ +/* These function names are completely deprecated and must no longer be used. + They are only provided here for compatibility with older programs. + - LZ4_uncompress is the same as LZ4_decompress_fast + - LZ4_uncompress_unknownOutputSize is the same as LZ4_decompress_safe + These function prototypes are now disabled; uncomment them only if you really need them. + It is highly recommended to stop using these prototypes and migrate to maintained ones */ +/* int LZ4_uncompress (const char* source, char* dest, int outputSize); */ +/* int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize); */ + +/* Obsolete streaming functions; use new streaming interface whenever possible */ +LZ4_DEPRECATED("use LZ4_createStream() instead") void* LZ4_create (char* inputBuffer); +LZ4_DEPRECATED("use LZ4_createStream() instead") int LZ4_sizeofStreamState(void); +LZ4_DEPRECATED("use LZ4_resetStream() instead") int LZ4_resetStreamState(void* state, char* inputBuffer); +LZ4_DEPRECATED("use LZ4_saveDict() instead") char* LZ4_slideInputBuffer (void* state); + +/* Obsolete streaming decoding functions */ +LZ4_DEPRECATED("use LZ4_decompress_safe_usingDict() instead") int LZ4_decompress_safe_withPrefix64k (const char* src, char* dst, int compressedSize, int maxDstSize); +LZ4_DEPRECATED("use LZ4_decompress_fast_usingDict() instead") int LZ4_decompress_fast_withPrefix64k (const char* src, char* dst, int originalSize); #if defined (__cplusplus) From d16072cf17ce8debcf796565841a54f1253a9923 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Thu, 9 Jun 2016 15:00:32 +0200 Subject: [PATCH 264/643] Change --enable-pedantic to use -std=c99 and not -ansi (C90). There's quite a bit of our code that fails compilation with "gcc -pedantic -ansi" and should not be changed - like, LZ4 using "long long" variables which C90 does not have. Be pragmatic. trac #616 Signed-off-by: Gert Doering Acked-by: Gert Doering Message-Id: <1465477232-25826-1-git-send-email-gert@greenie.muc.de> URL: http://article.gmane.org/gmane.network.openvpn.devel/11882 Signed-off-by: Gert Doering --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index d73302345e2..4f14ebd006a 100644 --- a/configure.ac +++ b/configure.ac @@ -1128,7 +1128,7 @@ fi if test "${enable_pedantic}" = "yes"; then enable_strict="yes" CFLAGS="${CFLAGS} -pedantic" - test "${WIN32}" != "yes" && CFLAGS="${CFLAGS} -ansi" + test "${WIN32}" != "yes" && CFLAGS="${CFLAGS} -std=c99" fi if test "${enable_strict}" = "yes"; then CFLAGS="${CFLAGS} -Wall -Wno-unused-parameter -Wno-unused-function" From 960524a9af899c83dbf2de255e063b7c66536d3e Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Tue, 16 Feb 2016 13:04:40 +0100 Subject: [PATCH 265/643] Complete push-peer-info documentation and allow IV_PLAT_VER for other platforms than Windows if the client UI supplies it. Acked-by: Gert Doering Message-Id: <1455624280-3165-1-git-send-email-arne@rfc2549.org> URL: http://article.gmane.org/gmane.network.openvpn.devel/11175 Signed-off-by: Gert Doering --- doc/openvpn.8 | 31 ++++++++++++++++++++++++++++--- src/openvpn/ssl.c | 6 ++++-- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 03f31bb4042..4cea79f5004 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -3000,16 +3000,41 @@ option with the new value. .\"********************************************************* .TP .B \-\-push\-peer\-info -Push additional information about the client to server. The additional information -consists of the following data: +Push additional information about the client to server. +The following data is always pushed to the server: IV_VER= -- the client OpenVPN version IV_PLAT=[linux|solaris|openbsd|mac|netbsd|freebsd|win] -- the client OS platform +IV_LZO_STUB=1 -- if client was built with LZO stub capability + +IV_LZ4=1 -- if the client supports LZ4 compressions. + +IV_RGI6=1 -- if the client supports +.B \-\-redirect\-gateway +for ipv6 + +IV_PROTO=2 -- if the client supports peer-id floating mechansim + +IV_NCP=2 -- negotiable ciphers, client supports +.B \-\-cipher +pushed by the server, a value of 2 or greater indicates client +supports AES-GCM-128 and AES-GCM-256. + +IV_UI_VER= -- the UI version of a UI if one is +running, for example "de.blinkt.openvpn 0.5.47" for the +Android app. + +When +.B \-\-push\-peer\-info +is enabled the additional information consists of the following data: + IV_HWADDR= -- the MAC address of clients default gateway -IV_LZO_STUB=1 -- if client was built with LZO stub capability +IV_SSL= -- the ssl version used by the client, e.g. "OpenSSL 1.0.2f 28 Jan 2016". + +IV_PLAT_VER=x.y - the version of the operating system, e.g. 6.1 for Windows 7. UV_= -- client environment variables whose names start with "UV_" .\"********************************************************* diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 429131480de..a48c8ec6ceb 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -1906,12 +1906,14 @@ push_peer_info(struct buffer *buf, struct tls_session *session) #endif } - /* push env vars that begin with UV_ and IV_GUI_VER */ + /* push env vars that begin with UV_, IV_PLAT_VER and IV_GUI_VER */ for (e=es->list; e != NULL; e=e->next) { if (e->string) { - if (((strncmp(e->string, "UV_", 3)==0 && session->opt->push_peer_info_detail >= 2) + if ((((strncmp(e->string, "UV_", 3)==0 || + strncmp(e->string, "IV_PLAT_VER=", sizeof("IV_PLAT_VER=")-1)==0) + && session->opt->push_peer_info_detail >= 2) || (strncmp(e->string,"IV_GUI_VER=",sizeof("IV_GUI_VER=")-1)==0)) && buf_safe(&out, strlen(e->string)+1)) buf_printf (&out, "%s\n", e->string); From f2134b7bea37df15756c599b94f16d4bffafbbd6 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Sat, 11 Jun 2016 16:43:15 +0200 Subject: [PATCH 266/643] Remove http-proxy-timeout, socks timeout and set default of server-poll-timeout to 120s With this change all timeouts before the first packet from the OpenVPN server are unified into the server-poll-timeout option. The default of 120s has been chosen to be a safe value is larger as it is larger the sums of the old small timeouts. V3: fix some whitespace/typos problems Acked-by: Gert Doering Message-Id: <1465656195-12722-1-git-send-email-arne@rfc2549.org> URL: http://article.gmane.org/gmane.network.openvpn.devel/11899 Signed-off-by: Gert Doering --- Changes.rst | 7 +++++++ doc/openvpn.8 | 25 ++++-------------------- src/openvpn/forward-inline.h | 2 +- src/openvpn/forward.c | 22 +++++++++++++++------ src/openvpn/forward.h | 2 +- src/openvpn/init.c | 33 ++++++++++++++++--------------- src/openvpn/interval.h | 9 +++++++++ src/openvpn/openvpn.h | 6 ++++-- src/openvpn/options.c | 38 +++++++----------------------------- src/openvpn/options.h | 3 --- src/openvpn/proxy.c | 20 +++++++++++-------- src/openvpn/proxy.h | 2 +- src/openvpn/socket.c | 10 ++++++---- src/openvpn/socket.h | 7 +++++-- 14 files changed, 90 insertions(+), 96 deletions(-) diff --git a/Changes.rst b/Changes.rst index 1ac3c2be41c..ab322e2df63 100644 --- a/Changes.rst +++ b/Changes.rst @@ -106,6 +106,13 @@ User-visible Changes - mbed TLS builds: minimum RSA key size is now 2048 bits. Shorter keys will not be accepted, both local and from the peer. +- --http-proxy-timeout and the static non-changeable socks timeout (5s) + have been folded into a "unified" --connect-timeout which covers all + steps needed to connect to the server, up to the start of the TLS exchange. + The default value has been raised to 120s, to handle slow http/socks + proxies graciously. The old "fail TCP fast" behaviour can be achieved by + adding "--connect-timeout 10" to the client config. + Maintainer-visible changes -------------------------- diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 4cea79f5004..f1a43614921 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -357,7 +357,6 @@ block: .B http\-proxy, .B http\-proxy\-option, .B http\-proxy\-retry, -.B http\-proxy\-timeout, .B link\-mtu, .B local, .B lport, @@ -473,14 +472,6 @@ Wait seconds between connection attempts (default=5). .\"********************************************************* .TP -.B \-\-connect\-timeout n -For -.B \-\-proto tcp\-client, -set connection timeout to -.B n -seconds (default=10). -.\"********************************************************* -.TP .B \-\-connect\-retry\-max n .B n specifies the number of times all @@ -538,12 +529,6 @@ Retry indefinitely on HTTP proxy errors. If an HTTP proxy error occurs, simulate a SIGUSR1 reset. .\"********************************************************* .TP -.B \-\-http\-proxy\-timeout n -Set proxy timeout to -.B n -seconds, default=5. -.\"********************************************************* -.TP .B \-\-http\-proxy\-option type [parm] Set extended HTTP proxy options. Repeat to set multiple options. @@ -3976,14 +3961,12 @@ description of the OpenVPN challenge/response protocol. .\"********************************************************* .TP .B \-\-server\-poll\-timeout n -when polling possible remote servers to connect to -in a round-robin fashion, spend no more than +.B \-\-connect\-timeout n +when connecting to a remote server do not wait for more than .B n seconds waiting for a response before trying the next server. -As this only makes sense in client-to-server setups, it cannot -be used in point-to-point setups using -.B \-\-secret -symmetrical key mode. +The default value is 120s. This timeout includes proxy and TCP +connect timeouts. .\"********************************************************* .TP .B \-\-explicit\-exit\-notify [n] diff --git a/src/openvpn/forward-inline.h b/src/openvpn/forward-inline.h index 0ca66929bc4..5d4e3089977 100644 --- a/src/openvpn/forward-inline.h +++ b/src/openvpn/forward-inline.h @@ -125,7 +125,7 @@ check_server_poll_timeout (struct context *c) { void check_server_poll_timeout_dowork (struct context *c); - if (c->options.server_poll_timeout + if (c->options.ce.connect_timeout && event_timeout_trigger (&c->c2.server_poll_interval, &c->c2.timeval, ETT_DEFAULT)) check_server_poll_timeout_dowork (c); } diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c index 2c9a0826fc6..6c114391dfd 100644 --- a/src/openvpn/forward.c +++ b/src/openvpn/forward.c @@ -324,6 +324,13 @@ check_inactivity_timeout_dowork (struct context *c) register_signal (c, SIGTERM, "inactive"); } +int +get_server_poll_remaining_time (struct event_timeout* server_poll_timeout) +{ + update_time(); + int remaining = event_timeout_remaining(server_poll_timeout); + return max_int (0, remaining); +} #if P2MP void @@ -538,13 +545,16 @@ process_coarse_timers (struct context *c) return; #if P2MP - check_server_poll_timeout (c); - if (c->sig->signal_received) - return; + if (c->c2.tls_multi) + { + check_server_poll_timeout (c); + if (c->sig->signal_received) + return; - check_scheduled_exit (c); - if (c->sig->signal_received) - return; + check_scheduled_exit (c); + if (c->sig->signal_received) + return; + } #endif #ifdef ENABLE_OCC diff --git a/src/openvpn/forward.h b/src/openvpn/forward.h index af3b0a67c4a..0856aa73081 100644 --- a/src/openvpn/forward.h +++ b/src/openvpn/forward.h @@ -103,7 +103,7 @@ void show_wait_status (struct context *c); * once for each remaining fragment with this parameter set to false. */ void encrypt_sign (struct context *c, bool comp_frag); - +int get_server_poll_remaining_time (struct event_timeout* server_poll_timeout); /**********************************************************************/ /** diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 50cbf902ea8..58b95aad0ed 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -1057,6 +1057,19 @@ reset_coarse_timers (struct context *c) c->c2.coarse_timer_wakeup = 0; } +/* + * Initialise the server poll timeout timer + * This timer is used in the http/socks proxy setup so it needs to be setup + * before + */ +static void +do_init_server_poll_timeout (struct context *c) +{ + update_time (); + if (c->options.ce.connect_timeout) + event_timeout_init (&c->c2.server_poll_interval, c->options.ce.connect_timeout, now); +} + /* * Initialize timers */ @@ -1078,11 +1091,6 @@ do_init_timers (struct context *c, bool deferred) if (c->options.ping_rec_timeout) event_timeout_init (&c->c2.ping_rec_interval, c->options.ping_rec_timeout, now); -#if P2MP - if (c->options.server_poll_timeout) - event_timeout_init (&c->c2.server_poll_interval, c->options.server_poll_timeout, now); -#endif - if (!deferred) { /* initialize connection establishment timer */ @@ -1969,11 +1977,6 @@ socket_restart_pause (struct context *c) #if P2MP if (auth_retry_get () == AR_NOINTERACT) sec = 10; - -#if 0 /* not really needed because of c->persist.restart_sleep_seconds */ - if (c->options.server_poll_timeout && sec > 1) - sec = 1; -#endif #endif if (c->persist.restart_sleep_seconds > 0 && c->persist.restart_sleep_seconds > sec) @@ -2660,11 +2663,6 @@ do_option_warnings (struct context *c) msg (M_WARN, "WARNING: No server certificate verification method has been enabled. See http://openvpn.net/howto.html#mitm for more info."); #endif -#ifndef CONNECT_NONBLOCK - if (o->ce.connect_timeout_defined) - msg (M_WARN, "NOTE: --connect-timeout option is not supported on this OS"); -#endif - /* If a script is used, print appropiate warnings */ if (o->user_script_used) { @@ -2819,11 +2817,11 @@ do_init_socket_1 (struct context *c, const int mode) c->options.ipchange, c->plugins, c->options.resolve_retry_seconds, - c->options.ce.connect_timeout, c->options.ce.mtu_discover_type, c->options.rcvbuf, c->options.sndbuf, c->options.mark, + &c->c2.server_poll_interval, sockflags); } @@ -3653,6 +3651,9 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int */ do_uid_gid_chroot (c, c->c2.did_open_tun); + /* initialise connect timeout timer */ + do_init_server_poll_timeout(c); + /* finalize the TCP/UDP socket */ if (c->mode == CM_P2P || c->mode == CM_TOP || c->mode == CM_CHILD_TCP) do_init_socket_2 (c); diff --git a/src/openvpn/interval.h b/src/openvpn/interval.h index 4814ec924c7..59eb1f64d57 100644 --- a/src/openvpn/interval.h +++ b/src/openvpn/interval.h @@ -185,6 +185,15 @@ event_timeout_modify_wakeup (struct event_timeout* et, interval_t n) et->n = (n >= 0) ? n : 0; } +/* + * Will return the time left for a timeout, this function does not check + * if the timeout is actually valid + */ +static inline interval_t event_timeout_remaining (struct event_timeout* et) +{ + return (int) et->last + et->n - now; +} + /* * This is the principal function for testing and triggering recurring * timers and will return true on a timer signal event. diff --git a/src/openvpn/openvpn.h b/src/openvpn/openvpn.h index 3281fd7d29e..01533d30b25 100644 --- a/src/openvpn/openvpn.h +++ b/src/openvpn/openvpn.h @@ -417,6 +417,10 @@ struct context_2 time_t update_timeout_random_component; struct timeval timeout_random_component; + /* Timer for everything up to the first packet from the *OpenVPN* server + * socks, http proxy, and tcp packets do not count */ + struct event_timeout server_poll_interval; + /* indicates that the do_up_delay function has run */ bool do_up_ran; @@ -472,8 +476,6 @@ struct context_2 md_ctx_t pulled_options_state; struct md5_digest pulled_options_digest; - struct event_timeout server_poll_interval; - struct event_timeout scheduled_exit; int scheduled_exit_signal; #endif diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 23f407c0e51..313fd943178 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -125,7 +125,6 @@ static const char usage_message[] = " p = udp6, tcp6-server, or tcp6-client (ipv6)\n" "--connect-retry n : For --proto tcp-client, number of seconds to wait\n" " between connection retries (default=%d).\n" - "--connect-timeout n : For --proto tcp-client, connection timeout (in seconds).\n" "--connect-retry-max n : Maximum connection attempt retries, default infinite.\n" "--http-proxy s p [up] [auth] : Connect to remote host\n" " through an HTTP proxy at address s and port p.\n" @@ -137,7 +136,6 @@ static const char usage_message[] = " determine auth method and query for username/password\n" " if needed. auto-nct disables weak proxy auth methods.\n" "--http-proxy-retry : Retry indefinitely on HTTP proxy errors.\n" - "--http-proxy-timeout n : Proxy timeout in seconds, default=5.\n" "--http-proxy-option type [parm] : Set extended HTTP proxy options.\n" " Repeat to set multiple options.\n" " VERSION version (default=1.0)\n" @@ -498,7 +496,7 @@ static const char usage_message[] = " none (default), interact, or nointeract.\n" "--static-challenge t e : Enable static challenge/response protocol using\n" " challenge text t, with e indicating echo flag (0|1)\n" - "--server-poll-timeout n : when polling possible remote servers to connect to\n" + "--connect-timeout n : when polling possible remote servers to connect to\n" " in a round-robin fashion, spend no more than n seconds\n" " waiting for a response before trying the next server.\n" #endif @@ -773,7 +771,7 @@ init_options (struct options *o, const bool init_gc) o->ce.af = AF_UNSPEC; o->ce.bind_ipv6_only = false; o->ce.connect_retry_seconds = 5; - o->ce.connect_timeout = 10; + o->ce.connect_timeout = 120; o->connect_retry_max = 0; o->ce.local_port = o->ce.remote_port = OPENVPN_PORT; o->verbosity = 1; @@ -825,7 +823,6 @@ init_options (struct options *o, const bool init_gc) #endif #if P2MP o->scheduled_exit_interval = 5; - o->server_poll_timeout = 0; #endif #ifdef ENABLE_CRYPTO o->ciphername = "BF-CBC"; @@ -1333,7 +1330,6 @@ show_http_proxy_options (const struct http_proxy_options *o) SHOW_STR (auth_method_string); SHOW_STR (auth_file); SHOW_BOOL (retry); - SHOW_INT (timeout); SHOW_STR (http_version); SHOW_STR (user_agent); for (i=0; i < MAX_CUSTOM_HTTP_HEADER && o->custom_headers[i].name;i++) @@ -1754,7 +1750,6 @@ parse_http_proxy_override (const char *server, ho->server = string_alloc(server, gc); ho->port = port; ho->retry = true; - ho->timeout = 5; if (flags && !strcmp(flags, "nct")) ho->auth_retry = PAR_NCT; else @@ -1951,13 +1946,6 @@ options_postprocess_verify_ce (const struct options *options, const struct conne if (options->lladdr && dev != DEV_TYPE_TAP) msg (M_USAGE, "--lladdr can only be used in --dev tap mode"); - /* - * Sanity check on TCP mode options - */ - if (ce->connect_timeout_defined && ce->proto != PROTO_TCP_CLIENT) - msg (M_USAGE, "--connect-timeout doesn't make sense unless also used with " - "--proto tcp-client or tcp6-client"); - /* * Sanity check on MTU parameters */ @@ -2411,9 +2399,6 @@ options_postprocess_verify_ce (const struct options *options, const struct conne MUST_BE_UNDEF (pkcs11_id); MUST_BE_UNDEF (pkcs11_id_management); #endif -#if P2MP - MUST_BE_UNDEF (server_poll_timeout); -#endif if (pull) msg (M_USAGE, err, "--pull"); @@ -4741,11 +4726,11 @@ add_option (struct options *options, VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); options->ce.connect_retry_seconds = positive_atoi (p[1]); } - else if (streq (p[0], "connect-timeout") && p[1] && !p[2]) + else if ((streq (p[0], "connect-timeout") || streq (p[0], "server-poll-timeout")) + && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); options->ce.connect_timeout = positive_atoi (p[1]); - options->ce.connect_timeout_defined = true; } else if (streq (p[0], "connect-retry-max") && p[1] && !p[2]) { @@ -5238,11 +5223,9 @@ add_option (struct options *options, } else if (streq (p[0], "http-proxy-timeout") && p[1] && !p[2]) { - struct http_proxy_options *ho; - VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); - ho = init_http_proxy_options_once (&options->ce.http_proxy_options, &options->gc); - ho->timeout = positive_atoi (p[1]); + msg (M_WARN, "DEPRECATED OPTION: http-proxy-timeout: In OpenVPN 2.4 the timeout until a connection to a " + "server is established is managed with a single timeout set by connect-timeout"); } else if (streq (p[0], "http-proxy-option") && p[1] && !p[4]) { @@ -5583,12 +5566,10 @@ add_option (struct options *options, options->push_peer_info = true; } #endif -#if P2MP else if (streq (p[1], "SERVER_POLL_TIMEOUT") && p[2]) { - options->server_poll_timeout = positive_atoi(p[2]); + options->ce.connect_timeout = positive_atoi(p[2]); } -#endif else { if (streq (p[1], "FORWARD_COMPATIBLE") && p[2] && streq (p[2], "1")) @@ -6129,11 +6110,6 @@ add_option (struct options *options, VERIFY_PERMISSION (OPT_P_PULL_MODE); options->push_continuation = atoi(p[1]); } - else if (streq (p[0], "server-poll-timeout") && p[1] && !p[2]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->server_poll_timeout = positive_atoi(p[1]); - } else if (streq (p[0], "auth-user-pass") && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); diff --git a/src/openvpn/options.h b/src/openvpn/options.h index 514511b7180..78e4fe088dc 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -97,7 +97,6 @@ struct connection_entry bool bind_local; int connect_retry_seconds; int connect_timeout; - bool connect_timeout_defined; struct http_proxy_options *http_proxy_options; const char *socks_proxy_server; const char *socks_proxy_port; @@ -458,8 +457,6 @@ struct options const char *auth_user_pass_file; struct options_pre_pull *pre_pull; - int server_poll_timeout; - int scheduled_exit_interval; #ifdef ENABLE_CLIENT_CR diff --git a/src/openvpn/proxy.c b/src/openvpn/proxy.c index 8ff6458098b..b051355ac0f 100644 --- a/src/openvpn/proxy.c +++ b/src/openvpn/proxy.c @@ -41,6 +41,7 @@ #include "httpdigest.h" #include "ntlm.h" #include "memdbg.h" +#include "forward.h" #define UP_TYPE_PROXY "HTTP Proxy" @@ -52,7 +53,6 @@ init_http_proxy_options_once (struct http_proxy_options **hpo, { ALLOC_OBJ_CLEAR_GC (*hpo, struct http_proxy_options, gc); /* http proxy defaults */ - (*hpo)->timeout = 5; (*hpo)->http_version = "1.0"; } return *hpo; @@ -255,6 +255,8 @@ clear_user_pass_http (void) purge_user_pass (&static_proxy_user_pass, true); } +#if 0 +/* function only used in #if 0 debug statement */ static void dump_residual (socket_descriptor_t sd, int timeout, @@ -269,6 +271,7 @@ dump_residual (socket_descriptor_t sd, msg (D_PROXY, "PROXY HEADER: '%s'", buf); } } +#endif /* * Extract the Proxy-Authenticate header from the stream. @@ -552,6 +555,7 @@ establish_http_proxy_passthru (struct http_proxy_info *p, socket_descriptor_t sd, /* already open to proxy */ const char *host, /* openvpn server remote */ const char *port, /* openvpn server port */ + struct event_timeout* server_poll_timeout, struct buffer *lookahead, volatile int *signal_received) { @@ -634,7 +638,7 @@ establish_http_proxy_passthru (struct http_proxy_info *p, goto error; /* receive reply from proxy */ - if (!recv_line (sd, buf, sizeof(buf), p->options.timeout, true, NULL, signal_received)) + if (!recv_line (sd, buf, sizeof(buf), get_server_poll_remaining_time (server_poll_timeout), true, NULL, signal_received)) goto error; /* remove trailing CR, LF */ @@ -663,7 +667,7 @@ establish_http_proxy_passthru (struct http_proxy_info *p, while (true) { - if (!recv_line (sd, buf, sizeof(buf), p->options.timeout, true, NULL, signal_received)) + if (!recv_line (sd, buf, sizeof(buf), get_server_poll_remaining_time (server_poll_timeout), true, NULL, signal_received)) goto error; chomp (buf); msg (D_PROXY, "HTTP proxy returned: '%s'", buf); @@ -730,7 +734,7 @@ establish_http_proxy_passthru (struct http_proxy_info *p, goto error; /* receive reply from proxy */ - if (!recv_line (sd, buf, sizeof(buf), p->options.timeout, true, NULL, signal_received)) + if (!recv_line (sd, buf, sizeof(buf), get_server_poll_remaining_time (server_poll_timeout), true, NULL, signal_received)) goto error; /* remove trailing CR, LF */ @@ -838,7 +842,7 @@ establish_http_proxy_passthru (struct http_proxy_info *p, goto error; /* receive reply from proxy */ - if (!recv_line (sd, buf, sizeof(buf), p->options.timeout, true, NULL, signal_received)) + if (!recv_line (sd, buf, sizeof(buf), get_server_poll_remaining_time (server_poll_timeout), true, NULL, signal_received)) goto error; /* remove trailing CR, LF */ @@ -862,7 +866,7 @@ establish_http_proxy_passthru (struct http_proxy_info *p, /* figure out what kind of authentication the proxy needs */ char *pa = NULL; const int method = get_proxy_authenticate(sd, - p->options.timeout, + get_server_poll_remaining_time (server_poll_timeout), &pa, NULL, signal_received); @@ -906,7 +910,7 @@ establish_http_proxy_passthru (struct http_proxy_info *p, msg (D_LINK_ERRORS, "HTTP proxy returned bad status"); #if 0 /* DEBUGGING -- show a multi-line HTTP error response */ - dump_residual(sd, p->options.timeout, signal_received); + dump_residual(sd, get_server_poll_remaining_time (server_poll_timeout), signal_received); #endif goto error; } @@ -914,7 +918,7 @@ establish_http_proxy_passthru (struct http_proxy_info *p, /* SUCCESS */ /* receive line from proxy and discard */ - if (!recv_line (sd, NULL, 0, p->options.timeout, true, NULL, signal_received)) + if (!recv_line (sd, NULL, 0, get_server_poll_remaining_time (server_poll_timeout), true, NULL, signal_received)) goto error; /* diff --git a/src/openvpn/proxy.h b/src/openvpn/proxy.h index 4715940c5ba..f5b45198120 100644 --- a/src/openvpn/proxy.h +++ b/src/openvpn/proxy.h @@ -46,7 +46,6 @@ struct http_proxy_options { const char *server; const char *port; bool retry; - int timeout; # define PAR_NO 0 /* don't support any auth retries */ # define PAR_ALL 1 /* allow all proxy auth protocols */ @@ -86,6 +85,7 @@ bool establish_http_proxy_passthru (struct http_proxy_info *p, socket_descriptor_t sd, /* already open to proxy */ const char *host, /* openvpn server remote */ const char *port, /* openvpn server port */ + struct event_timeout* server_poll_timeout, struct buffer *lookahead, volatile int *signal_received); diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c index d2872bedf97..0ea4a3d07ee 100644 --- a/src/openvpn/socket.c +++ b/src/openvpn/socket.c @@ -40,6 +40,7 @@ #include "misc.h" #include "manage.h" #include "openvpn.h" +#include "forward.h" #include "memdbg.h" @@ -1519,11 +1520,11 @@ link_socket_init_phase1 (struct link_socket *sock, const char *ipchange_command, const struct plugin_list *plugins, int resolve_retry_seconds, - int connect_timeout, int mtu_discover_type, int rcvbuf, int sndbuf, int mark, + struct event_timeout* server_poll_timeout, unsigned int sockflags) { ASSERT (sock); @@ -1538,7 +1539,6 @@ link_socket_init_phase1 (struct link_socket *sock, sock->bind_local = bind_local; sock->inetd = inetd; sock->resolve_retry_seconds = resolve_retry_seconds; - sock->connect_timeout = connect_timeout; sock->mtu_discover_type = mtu_discover_type; #ifdef ENABLE_DEBUG @@ -1558,6 +1558,7 @@ link_socket_init_phase1 (struct link_socket *sock, sock->info.bind_ipv6_only = bind_ipv6_only; sock->info.ipchange_command = ipchange_command; sock->info.plugins = plugins; + sock->server_poll_timeout = server_poll_timeout; sock->mode = mode; if (mode == LS_MODE_TCP_ACCEPT_FROM) @@ -1778,7 +1779,7 @@ phase2_tcp_client (struct link_socket *sock, struct signal_info *sig_info) do { socket_connect (&sock->sd, sock->info.lsa->current_remote->ai_addr, - sock->connect_timeout, + get_server_poll_remaining_time (sock->server_poll_timeout), sig_info); if (sig_info->signal_received) @@ -1790,6 +1791,7 @@ phase2_tcp_client (struct link_socket *sock, struct signal_info *sig_info) sock->sd, sock->proxy_dest_host, sock->proxy_dest_port, + sock->server_poll_timeout, &sock->stream_buf.residual, &sig_info->signal_received); } @@ -1816,7 +1818,7 @@ phase2_socks_client (struct link_socket *sock, struct signal_info *sig_info) { socket_connect (&sock->ctrl_sd, sock->info.lsa->current_remote->ai_addr, - sock->connect_timeout, + get_server_poll_remaining_time (sock->server_poll_timeout), sig_info); if (sig_info->signal_received) diff --git a/src/openvpn/socket.h b/src/openvpn/socket.h index 6f4d34f12a0..66824c7e2e7 100644 --- a/src/openvpn/socket.h +++ b/src/openvpn/socket.h @@ -200,7 +200,6 @@ struct link_socket int mode; int resolve_retry_seconds; - int connect_timeout; int mtu_discover_type; struct socket_buffer_size socket_buffer_sizes; @@ -231,6 +230,10 @@ struct link_socket const char *proxy_dest_host; const char *proxy_dest_port; + /* Pointer to the server-poll to trigger the timeout in function which have + * their own loop instead of using the main oop */ + struct event_timeout* server_poll_timeout; + #if PASSTOS_CAPABILITY /* used to get/set TOS. */ #if defined(TARGET_LINUX) @@ -319,11 +322,11 @@ link_socket_init_phase1 (struct link_socket *sock, const char *ipchange_command, const struct plugin_list *plugins, int resolve_retry_seconds, - int connect_timeout, int mtu_discover_type, int rcvbuf, int sndbuf, int mark, + struct event_timeout* server_poll_timeout, unsigned int sockflags); void link_socket_init_phase2 (struct link_socket *sock, From b63f98633dbe2ca92cd43fc6f8597ab283a600bf Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Tue, 14 Jun 2016 22:00:03 +0200 Subject: [PATCH 267/643] mbedtls: don't set debug threshold if compiled without MBEDTLS_DEBUG_C For targets with space constraints, one might want to compile mbed TLS without MBEDTLS_DEBUG_C defined, to save some tens of kilobytes. Make sure OpenVPN still compiles if that is the case. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1465934403-22226-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/11922 Signed-off-by: Gert Doering --- src/openvpn/ssl_mbedtls.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/openvpn/ssl_mbedtls.c b/src/openvpn/ssl_mbedtls.c index b5e7a6a72cc..e20ec02dd54 100644 --- a/src/openvpn/ssl_mbedtls.c +++ b/src/openvpn/ssl_mbedtls.c @@ -777,7 +777,9 @@ void key_state_ssl_init(struct key_state_ssl *ks_ssl, mbedtls_ssl_config_init(&ks_ssl->ssl_config); mbedtls_ssl_config_defaults(&ks_ssl->ssl_config, ssl_ctx->endpoint, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT); +#ifdef MBEDTLS_DEBUG_C mbedtls_debug_set_threshold(3); +#endif mbedtls_ssl_conf_dbg (&ks_ssl->ssl_config, my_debug, NULL); mbedtls_ssl_conf_rng (&ks_ssl->ssl_config, mbedtls_ctr_drbg_random, rand_ctx_get()); From c9a35a20812aafdacc3682a0379f52126bd567ae Mon Sep 17 00:00:00 2001 From: James Yonan Date: Thu, 3 Mar 2016 01:19:05 -0700 Subject: [PATCH 268/643] Added directive to specify HTTP proxy credentials in config. The inline directive http-proxy-user-pass can be used to specify proxy credentials in config, e.g.: http-proxy proxy.tld 3128 auto-nct foo bar This usage is already supported by OpenVPN 3. Signed-off-by: James Yonan Acked-by: Arne Schwabe Acked-by: Gert Doering Message-Id: <1456993146-63968-9-git-send-email-james@openvpn.net> URL: http://article.gmane.org/gmane.network.openvpn.devel/11283 Signed-off-by: Gert Doering --- src/openvpn/misc.c | 8 ++++++++ src/openvpn/misc.h | 2 ++ src/openvpn/options.c | 13 +++++++++++++ src/openvpn/proxy.c | 2 ++ src/openvpn/proxy.h | 1 + 5 files changed, 26 insertions(+) diff --git a/src/openvpn/misc.c b/src/openvpn/misc.c index 1e0088fe672..0991d791707 100644 --- a/src/openvpn/misc.c +++ b/src/openvpn/misc.c @@ -1092,6 +1092,14 @@ get_user_pass_cr (struct user_pass *up, if (!strlen (up->password)) strcpy (up->password, "ok"); } + else if (flags & GET_USER_PASS_INLINE_CREDS) + { + struct buffer buf; + buf_set_read (&buf, (uint8_t*) auth_file, strlen (auth_file) + 1); + if (!(flags & GET_USER_PASS_PASSWORD_ONLY)) + buf_parse (&buf, '\n', up->username, USER_PASS_LEN); + buf_parse (&buf, '\n', up->password, USER_PASS_LEN); + } /* * Read from auth file unless this is a dynamic challenge request. */ diff --git a/src/openvpn/misc.h b/src/openvpn/misc.h index 65a6e55a00b..b69409684a8 100644 --- a/src/openvpn/misc.h +++ b/src/openvpn/misc.h @@ -256,6 +256,8 @@ struct static_challenge_info {}; #define GET_USER_PASS_STATIC_CHALLENGE (1<<8) /* SCRV1 protocol -- static challenge */ #define GET_USER_PASS_STATIC_CHALLENGE_ECHO (1<<9) /* SCRV1 protocol -- echo response */ +#define GET_USER_PASS_INLINE_CREDS (1<<10) /* indicates that auth_file is actually inline creds */ + bool get_user_pass_cr (struct user_pass *up, const char *auth_file, const char *prefix, diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 313fd943178..c6477932d2f 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -5214,6 +5214,19 @@ add_option (struct options *options, ho->auth_method_string = "none"; } } + else if (streq (p[0], "http-proxy-user-pass") && p[1]) + { + struct http_proxy_options *ho; + VERIFY_PERMISSION (OPT_P_GENERAL); + ho = init_http_proxy_options_once (&options->ce.http_proxy_options, &options->gc); + if (streq (p[1], INLINE_FILE_TAG) && p[2]) + { + ho->auth_file = p[2]; + ho->inline_creds = true; + } + else + ho->auth_file = p[1]; + } else if (streq (p[0], "http-proxy-retry") && !p[1]) { struct http_proxy_options *ho; diff --git a/src/openvpn/proxy.c b/src/openvpn/proxy.c index b051355ac0f..4853193f003 100644 --- a/src/openvpn/proxy.c +++ b/src/openvpn/proxy.c @@ -241,6 +241,8 @@ get_user_pass_http (struct http_proxy_info *p, const bool force) unsigned int flags = GET_USER_PASS_MANAGEMENT; if (p->queried_creds) flags |= GET_USER_PASS_PREVIOUS_CREDS_FAILED; + if (p->options.inline_creds) + flags |= GET_USER_PASS_INLINE_CREDS; get_user_pass (&static_proxy_user_pass, p->options.auth_file, UP_TYPE_PROXY, diff --git a/src/openvpn/proxy.h b/src/openvpn/proxy.h index f5b45198120..9a52e7e5970 100644 --- a/src/openvpn/proxy.h +++ b/src/openvpn/proxy.h @@ -57,6 +57,7 @@ struct http_proxy_options { const char *http_version; const char *user_agent; struct http_custom_header custom_headers[MAX_CUSTOM_HTTP_HEADER]; + bool inline_creds; }; struct http_proxy_options_simple { From ec0c1dcabd1d31cd4bd452db6d099b4df0739778 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Fri, 17 Jun 2016 14:49:46 +0200 Subject: [PATCH 269/643] Add documentation for http-proxy-user-pass option Patch V2: fix formatting problems Acked-by: Selva Nair Message-Id: <1466167786-13748-1-git-send-email-arne@rfc2549.org> URL: http://article.gmane.org/gmane.network.openvpn.devel/11933 Signed-off-by: Gert Doering --- Changes.rst | 4 ++++ doc/openvpn.8 | 7 +++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Changes.rst b/Changes.rst index ab322e2df63..f945ad72aa4 100644 --- a/Changes.rst +++ b/Changes.rst @@ -51,6 +51,10 @@ AEAD (GCM) data channel cipher support bytes per packet for AES-128-GCM instead of 36 bytes per packet for AES-128-CBC + HMAC-SHA1). +Http proxy password inside config file + Http proxy passwords can be specified with the inline file option + http-proxy-user-pass + User-visible Changes -------------------- diff --git a/doc/openvpn.8 b/doc/openvpn.8 index f1a43614921..7e9f9a042ab 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -497,7 +497,10 @@ and port If HTTP Proxy-Authenticate is required, .B authfile is a file containing a username and password on 2 lines, or -"stdin" to prompt from console. +"stdin" to prompt from console. Its content can also be specified +in the config file with the +.B \-\-http\-proxy\-user\-pass +option. (See section on inline files) .B auth\-method should be one of "none", "basic", or "ntlm". @@ -6581,7 +6584,7 @@ X509_1_C=KG .SH INLINE FILE SUPPORT OpenVPN allows including files in the main configuration for the .B \-\-ca, \-\-cert, \-\-dh, \-\-extra\-certs, \-\-key, \-\-pkcs12, \-\-secret, -.B \-\-crl-verify +.B \-\-crl\-verify, \-\-http\-proxy\-user\-pass and .B \-\-tls\-auth options. From ac341e6dc63273fc3864357c60a5c9939c8105ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuli=20Sepp=C3=A4nen?= Date: Wed, 22 Jun 2016 20:06:02 +0300 Subject: [PATCH 270/643] Mention tap-windows6 in INSTALL file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Samuli Seppänen Acked-by: Gert Doering Message-Id: <1466615164-15527-1-git-send-email-samuli@openvpn.net> URL: http://article.gmane.org/gmane.network.openvpn.devel/11956 Signed-off-by: Gert Doering --- INSTALL | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/INSTALL b/INSTALL index 2401f7ca9bd..42f78d830e4 100644 --- a/INSTALL +++ b/INSTALL @@ -30,10 +30,14 @@ To download easy-rsa go to: https://github.com/OpenVPN/easy-rsa -To download tap-windows driver source code go to: +To download tap-windows (NDIS 5) driver source code go to: https://github.com/OpenVPN/tap-windows +To download tap-windows (NDIS 6) driver source code go to: + + https://github.com/OpenVPN/tap-windows6 + To get the cross-compilation environment go to: https://github.com/OpenVPN/openvpn-build From d16ea8ba5ab12b211ba7eb15ef8951ba1f9d4f19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuli=20Sepp=C3=A4nen?= Date: Wed, 22 Jun 2016 20:06:03 +0300 Subject: [PATCH 271/643] Use an up-to-date easy-rsa URL on the man-page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Samuli Seppänen Acked-by: Gert Doering Message-Id: <1466615164-15527-2-git-send-email-samuli@openvpn.net> URL: http://article.gmane.org/gmane.network.openvpn.devel/11955 Signed-off-by: Gert Doering --- doc/openvpn.8 | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 7e9f9a042ab..c2169cf9d85 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -4435,14 +4435,9 @@ will succeed, both OpenVPN peers will exchange temporary session keys, and the tunnel will begin passing data. -The OpenVPN distribution contains a set of scripts for -managing RSA certificates & keys, -located in the -.I easy-rsa -subdirectory. - -The easy-rsa package is also rendered in web form here: -.I http://openvpn.net/easyrsa.html +The OpenVPN project provides a set of scripts for +managing RSA certificates & keys: +.I https://github.com/OpenVPN/easy-rsa .\"********************************************************* .TP .B \-\-tls\-server From 3f0edd8a5a51774775dcda88064ed99fd0bf51d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuli=20Sepp=C3=A4nen?= Date: Thu, 23 Jun 2016 10:06:50 +0300 Subject: [PATCH 272/643] Clarify which Windows versions require which TUN/TAP driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Samuli Seppänen Acked-by: Gert Doering Message-Id: <1466665610-19289-1-git-send-email-samuli@openvpn.net> URL: http://article.gmane.org/gmane.network.openvpn.devel/11966 Signed-off-by: Gert Doering --- INSTALL | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/INSTALL b/INSTALL index 42f78d830e4..f0965c79b2a 100644 --- a/INSTALL +++ b/INSTALL @@ -298,13 +298,13 @@ TUN/TAP Driver Configuration: http://www.whiteboard.ne.jp/~admin2/tuntap/ -* Windows XP/2003/Vista/7: +* Windows OpenVPN on Windows needs a TUN/TAP kernel driver to work. OpenVPN installers include this driver, so installing it separately is not usually required. - The driver source code is available here: - - https://github.com/OpenVPN/tap-windows + Windows XP/2003 must use the NDIS 5 (tap-windows) driver, whereas on more + recent Windows versions it is recommended to use the NDIS 6 driver + (tap-windows6) instead. ************************************************************************* From d023fb661cca578dc977c9bd5e7d681de15e38a3 Mon Sep 17 00:00:00 2001 From: Selva Nair Date: Thu, 16 Jun 2016 22:54:53 -0400 Subject: [PATCH 273/643] Fix management-external-cert option parsing error - Allow --management-external-cert as an alternative to --cert - Also make sure --cert and --management-external-cert are not both specified, and clarify in the man page that the latter must be used with --management-external-key. Signed-off-by: Selva Nair Acked-by: Gert Doering Message-Id: <1466132093-1178-1-git-send-email-selva.nair@gmail.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/11929 Signed-off-by: Gert Doering --- doc/openvpn.8 | 1 + src/openvpn/options.c | 15 +++++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index c2169cf9d85..ac8036ffb7d 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -2650,6 +2650,7 @@ option (client-only). .B certificate-hint is an arbitrary string which is passed to a management interface client as an argument of NEED-CERTIFICATE notification. +Requires \-\-management\-external\-key. .\"********************************************************* .TP .B \-\-management\-forget\-disconnect diff --git a/src/openvpn/options.c b/src/openvpn/options.c index c6477932d2f..3adeb155fe2 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -2263,6 +2263,13 @@ options_postprocess_verify_ce (const struct options *options, const struct conne { msg (M_USAGE, "--key and --management-external-key are mutually exclusive"); } + else if((options->management_flags & MF_EXTERNAL_CERT)) + { + if (options->cert_file) + msg (M_USAGE, "--cert and --management-external-cert are mutually exclusive"); + else if(!(options->management_flags & MF_EXTERNAL_KEY)) + msg (M_USAGE, "--management-external-cert must be used with --management-external-key"); + } else #endif #ifdef ENABLE_CRYPTOAPI @@ -2318,14 +2325,14 @@ options_postprocess_verify_ce (const struct options *options, const struct conne if (pull) { - const int sum = (options->cert_file != NULL) + + const int sum = #ifdef MANAGMENT_EXTERNAL_KEY - ((options->priv_key_file != NULL) || (options->management_flags & MF_EXTERNAL_KEY)); + ((options->cert_file != NULL) || (options->management_flags & MF_EXTERNAL_CERT)) + + ((options->priv_key_file != NULL) || (options->management_flags & MF_EXTERNAL_KEY)); #else - (options->priv_key_file != NULL); + (options->cert_file != NULL) + (options->priv_key_file != NULL); #endif - if (sum == 0) { #if P2MP From e4c9bbe6c367132c8570fe747d85a6075ff04245 Mon Sep 17 00:00:00 2001 From: Selva Nair Date: Thu, 23 Jun 2016 22:50:56 -0400 Subject: [PATCH 274/643] Return process id of openvpn from interactive service to client - The process id is returned as a message formatted in the same manner as error messages from the service to the client: i.e., a three-line message with error number formatted as 0x%08x on line 1, followed by the PID in format 0x%08x on line 2 and a description that reads as "Process ID" on line 3. Error number is set to zero to indicate this is an informational message. This provides a way for service clients to check the status of openvpn and terminate it without needing management interface or exit event. Useful when the interactive service is used from a launch script, or to force-terminate openvpn from the GUI if/when needed. v2 changes: format of the message changed as described above. Signed-off-by: Selva Nair Acked-by: Gert Doering Message-Id: <1466736656-27501-1-git-send-email-selva.nair@gmail.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/11984 Signed-off-by: Gert Doering --- src/openvpnserv/interactive.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/openvpnserv/interactive.c b/src/openvpnserv/interactive.c index 2453f176646..ffaa1710cf0 100644 --- a/src/openvpnserv/interactive.c +++ b/src/openvpnserv/interactive.c @@ -230,6 +230,21 @@ WritePipeAsync (HANDLE pipe, LPVOID data, DWORD size, DWORD count, LPHANDLE even return AsyncPipeOp (write, pipe, data, size, count, events); } +static VOID +ReturnProcessId (HANDLE pipe, DWORD pid, DWORD count, LPHANDLE events) +{ + const WCHAR msg[] = L"Process ID"; + WCHAR buf[22 + _countof(msg)]; /* 10 chars each for error and PID and 2 for line breaks */ + + /* + * Same format as error messages (3 line string) with error = 0 in + * 0x%08x format, PID on line 2 and a description "Process ID" on line 3 + */ + _snwprintf (buf, _countof(buf), L"0x%08x\n0x%08x\n%s", 0, pid, msg); + buf[_countof(buf) - 1] = '\0'; + + WritePipeAsync (pipe, buf, wcslen (buf) * 2, count, events); +} static VOID ReturnError (HANDLE pipe, DWORD error, LPCWSTR func, DWORD count, LPHANDLE events) @@ -1293,6 +1308,8 @@ RunOpenvpn (LPVOID p) goto out; } + ReturnProcessId (pipe, proc_info.dwProcessId, 1, &exit_event); + CloseHandleEx (&stdout_write); CloseHandleEx (&stdin_read); CloseHandleEx (&svc_pipe); From 2011b8324feca30df753a4a0a116d37c04742520 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Fri, 24 Jun 2016 14:27:10 +0200 Subject: [PATCH 275/643] Remove http-proxy-retry and socks-proxy-retry. These options were probably introduced long before we had multiple remote/connection entries. For all other connection entries, OpenVPN will go on with the next connection if it fails. For proxies, if it fails in some ways it works the same, for other failures it completely stops. Removing the *-proxy-retry and defaulting to retry makes the behavior more predictiable. Stopping after one try (regardless of reason) can be achieved with --max-connect-retry 1 V2: Add reason for removing, remove from manpage, give a hint at --max-connet-retry V3: Collapse the two ifs in options.c to one block Acked-by: Gert Doering Message-Id: <1466771230-5266-1-git-send-email-arne@rfc2549.org> URL: http://article.gmane.org/gmane.network.openvpn.devel/11988 Signed-off-by: Gert Doering --- Changes.rst | 2 ++ doc/openvpn.8 | 14 -------------- src/openvpn/init.c | 4 +--- src/openvpn/options.c | 17 ++++------------- src/openvpn/options.h | 1 - src/openvpn/proxy.c | 3 +-- src/openvpn/proxy.h | 1 - src/openvpn/socks.c | 10 +++------- src/openvpn/socks.h | 4 +--- 9 files changed, 12 insertions(+), 44 deletions(-) diff --git a/Changes.rst b/Changes.rst index f945ad72aa4..d12cdad77e1 100644 --- a/Changes.rst +++ b/Changes.rst @@ -117,6 +117,8 @@ User-visible Changes proxies graciously. The old "fail TCP fast" behaviour can be achieved by adding "--connect-timeout 10" to the client config. +- --http-proxy-retry and --sock-proxy-retry have been removed. Proxy connections + will now behave like regular connection entries and generate a USR1 on failure. Maintainer-visible changes -------------------------- diff --git a/doc/openvpn.8 b/doc/openvpn.8 index ac8036ffb7d..64cc934dc93 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -317,13 +317,11 @@ remote 198.19.34.56 443 tcp remote 198.19.34.56 443 tcp http\-proxy 192.168.0.8 8080 -http\-proxy\-retry remote 198.19.36.99 443 tcp http\-proxy 192.168.0.8 8080 -http\-proxy\-retry persist\-key @@ -356,7 +354,6 @@ block: .B fragment, .B http\-proxy, .B http\-proxy\-option, -.B http\-proxy\-retry, .B link\-mtu, .B local, .B lport, @@ -368,7 +365,6 @@ block: .B remote, .B rport, .B socks\-proxy, -.B socks\-proxy\-retry, .B tun\-mtu and .B tun\-mtu\-extra. @@ -527,11 +523,6 @@ determine the authentication method, but to reject weak authentication protocols such as HTTP Basic Authentication. .\"********************************************************* .TP -.B \-\-http\-proxy\-retry -Retry indefinitely on HTTP proxy errors. If an HTTP proxy error -occurs, simulate a SIGUSR1 reset. -.\"********************************************************* -.TP .B \-\-http\-proxy\-option type [parm] Set extended HTTP proxy options. Repeat to set multiple options. @@ -564,11 +555,6 @@ and port "stdin" to prompt from console. .\"********************************************************* .TP -.B \-\-socks\-proxy\-retry -Retry indefinitely on Socks proxy errors. If a Socks proxy error -occurs, simulate a SIGUSR1 reset. -.\"********************************************************* -.TP .B \-\-resolv\-retry n If hostname resolve fails for .B \-\-remote, diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 58b95aad0ed..498d36f4e3a 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -138,7 +138,6 @@ management_callback_proxy_cmd (void *arg, const char **p) ho = init_http_proxy_options_once (&ce->http_proxy_options, gc); ho->server = string_alloc (p[2], gc); ho->port = string_alloc (p[3], gc); - ho->retry = true; ho->auth_retry = (p[4] && streq (p[4], "nct") ? PAR_NCT : PAR_ALL); ret = true; } @@ -473,8 +472,7 @@ init_proxy_dowork (struct context *c) { c->c1.socks_proxy = socks_proxy_new (c->options.ce.socks_proxy_server, c->options.ce.socks_proxy_port, - c->options.ce.socks_proxy_authfile, - c->options.ce.socks_proxy_retry); + c->options.ce.socks_proxy_authfile); if (c->c1.socks_proxy) { c->c1.socks_proxy_owned = true; diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 3adeb155fe2..cf971a68644 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -135,7 +135,6 @@ static const char usage_message[] = "--http-proxy s p 'auto[-nct]' : Like the above directive, but automatically\n" " determine auth method and query for username/password\n" " if needed. auto-nct disables weak proxy auth methods.\n" - "--http-proxy-retry : Retry indefinitely on HTTP proxy errors.\n" "--http-proxy-option type [parm] : Set extended HTTP proxy options.\n" " Repeat to set multiple options.\n" " VERSION version (default=1.0)\n" @@ -1329,7 +1328,6 @@ show_http_proxy_options (const struct http_proxy_options *o) SHOW_STR (port); SHOW_STR (auth_method_string); SHOW_STR (auth_file); - SHOW_BOOL (retry); SHOW_STR (http_version); SHOW_STR (user_agent); for (i=0; i < MAX_CUSTOM_HTTP_HEADER && o->custom_headers[i].name;i++) @@ -1397,7 +1395,6 @@ show_connection_entry (const struct connection_entry *o) show_http_proxy_options (o->http_proxy_options); SHOW_STR (socks_proxy_server); SHOW_STR (socks_proxy_port); - SHOW_BOOL (socks_proxy_retry); SHOW_INT (tun_mtu); SHOW_BOOL (tun_mtu_defined); SHOW_INT (link_mtu); @@ -1749,7 +1746,6 @@ parse_http_proxy_override (const char *server, ALLOC_OBJ_CLEAR_GC (ho, struct http_proxy_options, gc); ho->server = string_alloc(server, gc); ho->port = port; - ho->retry = true; if (flags && !strcmp(flags, "nct")) ho->auth_retry = PAR_NCT; else @@ -5234,12 +5230,12 @@ add_option (struct options *options, else ho->auth_file = p[1]; } - else if (streq (p[0], "http-proxy-retry") && !p[1]) + else if (streq (p[0], "http-proxy-retry") || streq (p[0], "socks-proxy-retry")) { - struct http_proxy_options *ho; VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); - ho = init_http_proxy_options_once (&options->ce.http_proxy_options, &options->gc); - ho->retry = true; + msg (M_WARN, "DEPRECATED OPTION: http-proxy-retry and socks-proxy-retry: " + "In OpenVPN 2.4 proxy connection retries are handled like regular connections. " + "Use connect-retry-max 1 to get a similar behavior as before."); } else if (streq (p[0], "http-proxy-timeout") && p[1] && !p[2]) { @@ -5309,11 +5305,6 @@ add_option (struct options *options, options->ce.socks_proxy_server = p[1]; options->ce.socks_proxy_authfile = p[3]; /* might be NULL */ } - else if (streq (p[0], "socks-proxy-retry") && !p[1]) - { - VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); - options->ce.socks_proxy_retry = true; - } else if (streq (p[0], "keepalive") && p[1] && p[2] && !p[3]) { VERIFY_PERMISSION (OPT_P_GENERAL); diff --git a/src/openvpn/options.h b/src/openvpn/options.h index 78e4fe088dc..7bb36c9ea86 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -101,7 +101,6 @@ struct connection_entry const char *socks_proxy_server; const char *socks_proxy_port; const char *socks_proxy_authfile; - bool socks_proxy_retry; int tun_mtu; /* MTU of tun device */ bool tun_mtu_defined; /* true if user overriding parm with command line option */ diff --git a/src/openvpn/proxy.c b/src/openvpn/proxy.c index 4853193f003..0f780202a0b 100644 --- a/src/openvpn/proxy.c +++ b/src/openvpn/proxy.c @@ -943,9 +943,8 @@ establish_http_proxy_passthru (struct http_proxy_info *p, return ret; error: - /* on error, should we exit or restart? */ if (!*signal_received) - *signal_received = (p->options.retry ? SIGUSR1 : SIGTERM); /* SOFT-SIGUSR1 -- HTTP proxy error */ + *signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- HTTP proxy error */ gc_free (&gc); return ret; } diff --git a/src/openvpn/proxy.h b/src/openvpn/proxy.h index 9a52e7e5970..7d2581ce327 100644 --- a/src/openvpn/proxy.h +++ b/src/openvpn/proxy.h @@ -45,7 +45,6 @@ struct http_custom_header { struct http_proxy_options { const char *server; const char *port; - bool retry; # define PAR_NO 0 /* don't support any auth retries */ # define PAR_ALL 1 /* allow all proxy auth protocols */ diff --git a/src/openvpn/socks.c b/src/openvpn/socks.c index a9d04aef3f0..5a9ea6cdefe 100644 --- a/src/openvpn/socks.c +++ b/src/openvpn/socks.c @@ -60,8 +60,7 @@ socks_adjust_frame_parameters (struct frame *frame, int proto) struct socks_proxy_info * socks_proxy_new (const char *server, const char *port, - const char *authfile, - bool retry) + const char *authfile) { struct socks_proxy_info *p; @@ -78,7 +77,6 @@ socks_proxy_new (const char *server, else p->authfile[0] = 0; - p->retry = retry; p->defined = true; return p; @@ -470,9 +468,8 @@ establish_socks_proxy_passthru (struct socks_proxy_info *p, return; error: - /* on error, should we exit or restart? */ if (!*signal_received) - *signal_received = (p->retry ? SIGUSR1 : SIGTERM); /* SOFT-SIGUSR1 -- socks error */ + *signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- socks error */ return; } @@ -508,9 +505,8 @@ establish_socks_proxy_udpassoc (struct socks_proxy_info *p, return; error: - /* on error, should we exit or restart? */ if (!*signal_received) - *signal_received = (p->retry ? SIGUSR1 : SIGTERM); /* SOFT-SIGUSR1 -- socks error */ + *signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- socks error */ return; } diff --git a/src/openvpn/socks.h b/src/openvpn/socks.h index 2475261f790..a2843b9b446 100644 --- a/src/openvpn/socks.h +++ b/src/openvpn/socks.h @@ -37,7 +37,6 @@ struct link_socket_actual; struct socks_proxy_info { bool defined; - bool retry; char server[128]; const char *port; @@ -48,8 +47,7 @@ void socks_adjust_frame_parameters (struct frame *frame, int proto); struct socks_proxy_info *socks_proxy_new (const char *server, const char *port, - const char *authfile, - bool retry); + const char *authfile); void socks_proxy_close (struct socks_proxy_info *sp); From 365506d1704f91f827f6e063dc87b325c40e9f29 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Thu, 7 Jul 2016 13:03:16 +0200 Subject: [PATCH 276/643] Remove NOP function and callers multi_release_io_lock() and the calls to this function are not providing anything at all. Lets remove it and make the overall code less suprising. Signed-off-by: David Sommerseth Acked-by: Arne Schwabe Message-Id: <1467889519-8193-1-git-send-email-openvpn@sf.lists.topphemmelig.net> URL: http://article.gmane.org/gmane.network.openvpn.devel/12058 --- src/openvpn/mudp.c | 2 -- src/openvpn/multi.h | 5 ----- 2 files changed, 7 deletions(-) diff --git a/src/openvpn/mudp.c b/src/openvpn/mudp.c index 6e0568e36ba..21a7e97f73b 100644 --- a/src/openvpn/mudp.c +++ b/src/openvpn/mudp.c @@ -210,7 +210,6 @@ multi_process_io_udp (struct multi_context *m) else if (status & SOCKET_READ) { read_incoming_link (&m->top); - multi_release_io_lock (m); if (!IS_SIG (&m->top)) multi_process_incoming_link (m, NULL, mpp_flags); } @@ -218,7 +217,6 @@ multi_process_io_udp (struct multi_context *m) else if (status & TUN_READ) { read_incoming_tun (&m->top); - multi_release_io_lock (m); if (!IS_SIG (&m->top)) multi_process_incoming_tun (m, mpp_flags); } diff --git a/src/openvpn/multi.h b/src/openvpn/multi.h index 9d8185d4983..0d369f34856 100644 --- a/src/openvpn/multi.h +++ b/src/openvpn/multi.h @@ -625,10 +625,5 @@ multi_set_pending (struct multi_context *m, struct multi_instance *mi) m->pending = mi; } -static inline void -multi_release_io_lock (struct multi_context *m) -{ -} - #endif /* P2MP_SERVER */ #endif /* MULTI_H */ From 5d429efd9720109b9c9f1265f5d351a75a401942 Mon Sep 17 00:00:00 2001 From: Selva Nair Date: Tue, 5 Jul 2016 11:32:50 -0400 Subject: [PATCH 277/643] Exponentially back off on repeated connect retries - When the number of retries per remote exceeds a limit (hard coded to 5), double the restart pause interval for each additional retry per remote. - Trigger a SIGHUP to reset the retry count when the pause interval exceeds 1024 times the base value of restart pause. (removed in v2 of the patch) The base value of restart pause is set using --connect-retry (5 seconds by default). v2 changes (based on suggestions from Arne Schwabe ) - Do not throw SIGHUP. - Add an optional argument to "--connect-retry n [m]" where 'm' specifies the max value of restart pause interval (default 300 sec). E.g., "--connect-retry 5 1800" will cause the restart pause to scale up starting at 5 until it exceeds 1800 seconds at which point it gets capped at 1800. - If n == m no slow down will occur. - While at it, fix typos and clarify the description of connect-retry-max in the man page and Changes.rst v3 changes (on further feedback from arne@rfc2549.org): - Limiting the base value of retry wait interval to 16 bits moved to options.c - Apply backoff only in the udp and tcp-client modes. Backing off on tcp-server could be exploited by a client in p2p-mode to maliciously slow it down (thanks to Arne Schwabe for pointing this out. - Fix typo in Changes.rst: "third argument" -> "second argument" Signed-off-by: Selva Nair Acked-by: Arne Schwabe Acked-by: Gert Doering Message-Id: <1467732770-19110-1-git-send-email-selva.nair@gmail.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/12050 Signed-off-by: Gert Doering --- Changes.rst | 8 ++++++-- doc/openvpn.8 | 19 ++++++++++++------- src/openvpn/init.c | 15 +++++++++++++++ src/openvpn/options.c | 24 +++++++++++++++++++++--- src/openvpn/options.h | 1 + 5 files changed, 55 insertions(+), 12 deletions(-) diff --git a/Changes.rst b/Changes.rst index d12cdad77e1..55fca958ed1 100644 --- a/Changes.rst +++ b/Changes.rst @@ -75,8 +75,8 @@ User-visible Changes In --static mode connect-timeout specifies the timeout for TCP and proxy connection establishment -- connect-retry now specifies the maximum number of unsucessfully - trying all remote/connection entries before exiting. +- connect-retry-max now specifies the maximum number of unsuccessful + attempts of each remote/connection entry before exiting. - sndbuf and recvbuf default now to OS default instead of 64k @@ -120,6 +120,10 @@ User-visible Changes - --http-proxy-retry and --sock-proxy-retry have been removed. Proxy connections will now behave like regular connection entries and generate a USR1 on failure. +- --connect-retry gets an optional second argument that specifies the maximum + time in seconds to wait between reconnection attempts when an exponential + backoff is triggered due to repeated retries. Default = 300 seconds. + Maintainer-visible changes -------------------------- - OpenVPN no longer supports building with crypto support, but without TLS diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 64cc934dc93..3ca6f503785 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -462,22 +462,27 @@ application-level UDP protocols, or tunneling protocols which don't possess a built-in reliability layer. .\"********************************************************* .TP -.B \-\-connect\-retry n +.B \-\-connect\-retry n [max] Wait .B n -seconds between connection attempts (default=5). +seconds between connection attempts (default=5). Repeated reconnection +attempts are slowed down after 5 retries per remote by doubling the wait +time after each unsuccessful attempt. The optional argument +.B max +specifies the maximum value of wait time in seconds at which it gets +capped (default=300). .\"********************************************************* .TP .B \-\-connect\-retry\-max n .B n -specifies the number of times all +specifies the number of times each .B \-\-remote -respectively +or .B -statements are tried. Specifiying +entry is tried. Specifying .B n -as one would try each entry exactly once. A sucessful connection -resets the counter. (default=umlimited). +as one would try each entry exactly once. A successful connection +resets the counter. (default=unlimited). .\"********************************************************* .TP .B \-\-show\-proxy\-settings diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 498d36f4e3a..091c2990040 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -1955,6 +1955,7 @@ static void socket_restart_pause (struct context *c) { int sec = 2; + int backoff = 0; switch (c->options.ce.proto) { @@ -1977,6 +1978,20 @@ socket_restart_pause (struct context *c) sec = 10; #endif + /* Slow down reconnection after 5 retries per remote -- for tcp only in client mode */ + if (c->options.ce.proto != PROTO_TCP_SERVER) + { + backoff = (c->options.unsuccessful_attempts / c->options.connection_list->len) - 4; + if (backoff > 0) + { + /* sec is less than 2^16; we can left shift it by up to 15 bits without overflow */ + sec = max_int (sec, 1) << min_int (backoff, 15); + } + + if (sec > c->options.ce.connect_retry_seconds_max) + sec = c->options.ce.connect_retry_seconds_max; + } + if (c->persist.restart_sleep_seconds > 0 && c->persist.restart_sleep_seconds > sec) sec = c->persist.restart_sleep_seconds; else if (c->persist.restart_sleep_seconds == -1) diff --git a/src/openvpn/options.c b/src/openvpn/options.c index cf971a68644..bcbaba33bce 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -123,8 +123,10 @@ static const char usage_message[] = " p = udp (default), tcp-server, or tcp-client\n" "--proto-force p : only consider protocol p in list of connection profiles.\n" " p = udp6, tcp6-server, or tcp6-client (ipv6)\n" - "--connect-retry n : For --proto tcp-client, number of seconds to wait\n" - " between connection retries (default=%d).\n" + "--connect-retry n [m] : For client, number of seconds to wait between\n" + " connection retries (default=%d). On repeated retries\n" + " the wait time is exponentially increased to a maximum of m\n" + " (default=%d).\n" "--connect-retry-max n : Maximum connection attempt retries, default infinite.\n" "--http-proxy s p [up] [auth] : Connect to remote host\n" " through an HTTP proxy at address s and port p.\n" @@ -770,6 +772,7 @@ init_options (struct options *o, const bool init_gc) o->ce.af = AF_UNSPEC; o->ce.bind_ipv6_only = false; o->ce.connect_retry_seconds = 5; + o->ce.connect_retry_seconds_max = 300; o->ce.connect_timeout = 120; o->connect_retry_max = 0; o->ce.local_port = o->ce.remote_port = OPENVPN_PORT; @@ -3479,6 +3482,7 @@ usage (void) fprintf (fp, usage_message, title_string, o.ce.connect_retry_seconds, + o.ce.connect_retry_seconds_max, o.ce.local_port, o.ce.remote_port, TUN_MTU_DEFAULT, TAP_MTU_EXTRA_DEFAULT, o.verbosity, @@ -4724,10 +4728,24 @@ add_option (struct options *options, if (p[1]) options->ip_remote_hint=p[1]; } - else if (streq (p[0], "connect-retry") && p[1] && !p[2]) + else if (streq (p[0], "connect-retry") && p[1] && !p[3]) { VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); options->ce.connect_retry_seconds = positive_atoi (p[1]); + /* + * Limit the base value of retry wait interval to 16 bits to avoid + * overflow when scaled up for exponential backoff + */ + if (options->ce.connect_retry_seconds > 0xFFFF) + { + options->ce.connect_retry_seconds = 0xFFFF; + msg (M_WARN, "connect retry wait interval truncated to %d", + options->ce.connect_retry_seconds); + } + + if (p[2]) + options->ce.connect_retry_seconds_max = + max_int (positive_atoi (p[2]), options->ce.connect_retry_seconds); } else if ((streq (p[0], "connect-timeout") || streq (p[0], "server-poll-timeout")) && p[1] && !p[2]) diff --git a/src/openvpn/options.h b/src/openvpn/options.h index 7bb36c9ea86..486bf5d3d7d 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -96,6 +96,7 @@ struct connection_entry bool bind_ipv6_only; bool bind_local; int connect_retry_seconds; + int connect_retry_seconds_max; int connect_timeout; struct http_proxy_options *http_proxy_options; const char *socks_proxy_server; From 6aa4c9091300f62fae0bf7a9198de0edd2d8b7c7 Mon Sep 17 00:00:00 2001 From: Selva Nair Date: Mon, 13 Jun 2016 22:34:49 -0400 Subject: [PATCH 278/643] Promptly close the netcmd_semaphore handle after use If more than one openvpn processes are running and one aborts without releasing the semaphore, subsequent processes fail to get a lock for the semaphore. This may be avoided by not keeping open handles to the semaphore so that Windows can destroy it when no open handles remain. See also: http://article.gmane.org/gmane.network.openvpn.devel/11913 Signed-off-by: Selva Nair Acked-by: Gert Doering Message-Id: <1465871689-13533-1-git-send-email-selva.nair@gmail.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/11919 Signed-off-by: Gert Doering --- src/openvpn/win32.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/openvpn/win32.c b/src/openvpn/win32.c index 8a2f9578577..ad721cdb3ad 100644 --- a/src/openvpn/win32.c +++ b/src/openvpn/win32.c @@ -105,7 +105,6 @@ init_win32 (void) } window_title_clear (&window_title); win32_signal_clear (&win32_signal); - netcmd_semaphore_init (); } void @@ -751,6 +750,10 @@ void netcmd_semaphore_lock (void) { const int timeout_seconds = 600; + + if (!netcmd_semaphore.hand) + netcmd_semaphore_init (); + if (!semaphore_lock (&netcmd_semaphore, timeout_seconds * 1000)) msg (M_FATAL, "Cannot lock net command semaphore"); } @@ -759,6 +762,8 @@ void netcmd_semaphore_release (void) { semaphore_release (&netcmd_semaphore); + /* netcmd_semaphore has max count of 1 - safe to close after release */ + semaphore_close (&netcmd_semaphore); } /* From 6dd307c8640d851c6241a27f434c53a6aee0cace Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuli=20Sepp=C3=A4nen?= Date: Mon, 4 Jul 2016 12:29:45 +0300 Subject: [PATCH 279/643] Deprecate the automatic part of openvpnserv.exe in favor of openvpnserv2.exe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Samuli Seppänen Acked-by: Gert Doering Message-Id: <1467624585-23515-1-git-send-email-samuli@openvpn.net> URL: http://article.gmane.org/gmane.network.openvpn.devel/12036 Signed-off-by: Gert Doering --- src/openvpnserv/automatic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/openvpnserv/automatic.c b/src/openvpnserv/automatic.c index 9b424e95252..aa7618f4724 100644 --- a/src/openvpnserv/automatic.c +++ b/src/openvpnserv/automatic.c @@ -49,8 +49,8 @@ static SERVICE_STATUS status; openvpn_service_t automatic_service = { automatic, - TEXT(PACKAGE_NAME "Service"), - TEXT(PACKAGE_NAME " Service"), + TEXT(PACKAGE_NAME "ServiceLegacy"), + TEXT(PACKAGE_NAME " Legacy Service"), TEXT(SERVICE_DEPENDENCIES), SERVICE_DEMAND_START }; From 97894360fa537945e07fd6a85d0659e094b693a5 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Tue, 28 Jun 2016 23:33:55 +0200 Subject: [PATCH 280/643] Add client-side support for cipher negotiation Based on the 'IV_NCP=2' mechanism described in http://permalink.gmane.org/gmane.network.openvpn.devel/9385. This is the first patch of a set that adds support for cipher negotiation. Follow-up patches will add ways to restrict or disable the mechanism, and add server-side support. v2: * Account for crypto overhead through struct frame. This is less transparant, but the code has been built to work this way. The previous approach didn't work with TCP mode (or --port-share). * Calculate the link-mtu sent in the options string based on the crypto parameters specified in the config file (prevents link-mtu warnings in older peers when connecting). v3: * Use existing max_int() function, instead of new MAX() macro. * Fix typo in comment. * Do not regenerate keys if the server sends a second push msg * Only push IV_NCP if we're pull-client (and thus can do NCP) v4: * Fix rebase errors (OPT_P_NCP sneaked in, but is not introduced till 4/5, and tls_peer_info_ncp_ver() is not needed until 5/5). * Don't remove comment about key_id increment behaviour in init.c (but still add the extra comments in the .h files). Signed-off-by: Steffan Karger Acked-by: Arne Schwabe Acked-by: Gert Doering Message-Id: <1467149635-9726-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/12007 Signed-off-by: Gert Doering --- src/openvpn/crypto.c | 19 ++++++++--- src/openvpn/crypto.h | 4 +++ src/openvpn/crypto_backend.h | 6 ++++ src/openvpn/init.c | 34 +++++++++++++++---- src/openvpn/mtu.c | 2 -- src/openvpn/options.c | 35 +++++++++++++++++-- src/openvpn/ssl.c | 66 ++++++++++++++++++++++++++++++++++-- src/openvpn/ssl.h | 14 ++++++++ src/openvpn/ssl_common.h | 16 +++++++-- 9 files changed, 177 insertions(+), 19 deletions(-) diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c index 5c392aad342..f9cf62aead6 100644 --- a/src/openvpn/crypto.c +++ b/src/openvpn/crypto.c @@ -35,6 +35,7 @@ #include "crypto.h" #include "error.h" +#include "integer.h" #include "misc.h" #include "memdbg.h" @@ -709,10 +710,6 @@ openvpn_decrypt (struct buffer *buf, struct buffer work, return ret; } -/* - * How many bytes will we add to frame buffer for a given - * set of crypto options? - */ void crypto_adjust_frame_parameters(struct frame *frame, const struct key_type* kt, @@ -746,6 +743,14 @@ crypto_adjust_frame_parameters(struct frame *frame, __func__, crypto_overhead); } +size_t +crypto_max_overhead(void) +{ + return packet_id_size(true) + OPENVPN_MAX_IV_LENGTH + + OPENVPN_MAX_CIPHER_BLOCK_SIZE + + max_int (OPENVPN_MAX_HMAC_SIZE, OPENVPN_AEAD_TAG_LENGTH); +} + /* * Build a struct key_type. */ @@ -774,6 +779,9 @@ init_key_type (struct key_type *kt, const char *ciphername, #endif )) msg (M_FATAL, "Cipher '%s' mode not supported", ciphername); + + if (OPENVPN_MAX_CIPHER_BLOCK_SIZE < cipher_kt_block_size(kt->cipher)) + msg (M_FATAL, "Cipher '%s' not allowed: block size too big.", ciphername); } else { @@ -785,6 +793,9 @@ init_key_type (struct key_type *kt, const char *ciphername, if (!aead_cipher) { /* Ignore auth for AEAD ciphers */ kt->digest = md_kt_get (authname); kt->hmac_length = md_kt_size (kt->digest); + + if (OPENVPN_MAX_HMAC_SIZE < kt->hmac_length) + msg (M_FATAL, "HMAC '%s' not allowed: digest size too big.", authname); } } else if (!aead_cipher) diff --git a/src/openvpn/crypto.h b/src/openvpn/crypto.h index 63d7040d83b..de433ae8e54 100644 --- a/src/openvpn/crypto.h +++ b/src/openvpn/crypto.h @@ -226,6 +226,7 @@ struct key_ctx_bi * direction. */ struct key_ctx decrypt; /**< cipher and/or HMAC contexts for * receiving direction. */ + bool initialized; }; /** @@ -385,6 +386,7 @@ bool openvpn_decrypt (struct buffer *buf, struct buffer work, /** @} name Functions for performing security operations on data channel packets */ +/** Calculate crypto overhead and adjust frame to account for that */ void crypto_adjust_frame_parameters(struct frame *frame, const struct key_type* kt, bool cipher_defined, @@ -392,6 +394,8 @@ void crypto_adjust_frame_parameters(struct frame *frame, bool packet_id, bool packet_id_long_form); +/** Return the worst-case OpenVPN crypto overhead (in bytes) */ +size_t crypto_max_overhead(void); /* Minimum length of the nonce used by the PRNG */ #define NONCE_SECRET_LEN_MIN 16 diff --git a/src/openvpn/crypto_backend.h b/src/openvpn/crypto_backend.h index 3893f140244..a69967376cc 100644 --- a/src/openvpn/crypto_backend.h +++ b/src/openvpn/crypto_backend.h @@ -41,6 +41,12 @@ /* TLS uses a tag of 128 bytes, let's do the same for OpenVPN */ #define OPENVPN_AEAD_TAG_LENGTH 16 +/* Maximum cipher block size (bytes) */ +#define OPENVPN_MAX_CIPHER_BLOCK_SIZE 32 + +/* Maximum HMAC digest size (bytes) */ +#define OPENVPN_MAX_HMAC_SIZE 64 + /** Struct used in cipher name translation table */ typedef struct { const char *openvpn_name; /**< Cipher name used by OpenVPN */ diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 091c2990040..55d64366c75 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -1825,6 +1825,7 @@ pull_permission_mask (const struct context *c) | OPT_P_SHAPER | OPT_P_TIMER | OPT_P_COMP + | OPT_P_CRYPTO | OPT_P_PERSIST | OPT_P_MESSAGES | OPT_P_EXPLICIT_NOTIFY @@ -1928,6 +1929,19 @@ do_deferred_options (struct context *c, const unsigned int found) " MTU problems", TUN_MTU_SIZE(&c->c2.frame) ); } } + + /* process (potentially pushed) crypto options */ + if (c->options.pull) + { + struct tls_session *session = &c->c2.tls_multi->session[TM_ACTIVE]; + if (found & OPT_P_CRYPTO) + msg (D_PUSH, "OPTIONS IMPORT: data channel crypto options modified"); + /* Do not regenerate keys if server sends an extra push request */ + if (!session->key[KS_PRIMARY].crypto_options.key_ctx_bi.initialized) + { + tls_session_update_crypto_params(session, &c->options, &c->c2.frame); + } + } #endif } @@ -2043,6 +2057,7 @@ frame_finalize_options (struct context *c, const struct options *o) |FRAME_HEADROOM_MARKER_READ_STREAM); } + frame_add_to_extra_buffer (&c->c2.frame, PAYLOAD_ALIGN); frame_finalize (&c->c2.frame, o->ce.link_mtu_defined, o->ce.link_mtu, @@ -2298,12 +2313,18 @@ do_init_crypto_tls (struct context *c, const unsigned int flags) /* In short form, unique datagram identifier is 32 bits, in long form 64 bits */ packet_id_long_form = cipher_kt_mode_ofb_cfb (c->c1.ks.key_type.cipher); - /* Compute MTU parameters */ - crypto_adjust_frame_parameters (&c->c2.frame, - &c->c1.ks.key_type, - options->ciphername_defined, - options->use_iv, - options->replay, packet_id_long_form); + /* Compute MTU parameters (postpone if we pull options) */ + if (c->options.pull) + { + /* Account for worst-case crypto overhead before allocating buffers */ + frame_add_to_extra_frame (&c->c2.frame, crypto_max_overhead()); + } + else + { + crypto_adjust_frame_parameters(&c->c2.frame, &c->c1.ks.key_type, + options->ciphername_defined, options->use_iv, options->replay, + packet_id_long_form); + } tls_adjust_frame_parameters (&c->c2.frame); /* Set all command-line TLS-related options */ @@ -2334,6 +2355,7 @@ do_init_crypto_tls (struct context *c, const unsigned int flags) to.renegotiate_packets = options->renegotiate_packets; to.renegotiate_seconds = options->renegotiate_seconds; to.single_session = options->single_session; + to.pull = options->pull; #ifdef ENABLE_PUSH_PEER_INFO if (options->push_peer_info) /* all there is */ to.push_peer_info_detail = 2; diff --git a/src/openvpn/mtu.c b/src/openvpn/mtu.c index 24531c92a8b..64d1cf3c5a7 100644 --- a/src/openvpn/mtu.c +++ b/src/openvpn/mtu.c @@ -78,8 +78,6 @@ frame_finalize (struct frame *frame, } frame->link_mtu_dynamic = frame->link_mtu; - - frame->extra_buffer += PAYLOAD_ALIGN; } /* diff --git a/src/openvpn/options.c b/src/openvpn/options.c index bcbaba33bce..a9dbc0be17b 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -2965,6 +2965,38 @@ pre_pull_restore (struct options *o, struct gc_arena *gc) #ifdef ENABLE_OCC +/** + * Calculate the link-mtu to advertise to our peer. The actual value is not + * relevant, because we will possibly perform data channel cipher negotiation + * after this, but older clients will log warnings if we do not supply them the + * value they expect. This assumes that the traditional cipher/auth directives + * in the config match the config of the peer. + */ +static size_t +calc_options_string_link_mtu(const struct options *o, const struct frame *frame) +{ + size_t link_mtu = EXPANDED_SIZE (frame); +#ifdef ENABLE_CRYPTO + if (o->pull || o->mode == MODE_SERVER) + { + struct frame fake_frame = *frame; + struct key_type fake_kt; + init_key_type (&fake_kt, o->ciphername, o->ciphername_defined, + o->authname, o->authname_defined, o->keysize, true, false); + frame_add_to_extra_frame (&fake_frame, -(crypto_max_overhead())); + crypto_adjust_frame_parameters (&fake_frame, &fake_kt, + o->ciphername_defined, o->use_iv, o->replay, + cipher_kt_mode_ofb_cfb (fake_kt.cipher)); + frame_finalize(&fake_frame, o->ce.link_mtu_defined, o->ce.link_mtu, + o->ce.tun_mtu_defined, o->ce.tun_mtu); + msg (D_MTU_DEBUG, "%s: link-mtu %zu -> %d", __func__, link_mtu, + EXPANDED_SIZE (&fake_frame)); + link_mtu = EXPANDED_SIZE (&fake_frame); + } +#endif + return link_mtu; +} + /* * Build an options string to represent data channel encryption options. * This string must match exactly between peers. The keysize is checked @@ -3009,7 +3041,6 @@ pre_pull_restore (struct options *o, struct gc_arena *gc) * --tls-server [matched with --tls-client on * the other end of the connection] */ - char * options_string (const struct options *o, const struct frame *frame, @@ -3027,7 +3058,7 @@ options_string (const struct options *o, */ buf_printf (&out, ",dev-type %s", dev_type_string (o->dev, o->dev_type)); - buf_printf (&out, ",link-mtu %d", EXPANDED_SIZE (frame)); + buf_printf (&out, ",link-mtu %zu", calc_options_string_link_mtu(o, frame)); buf_printf (&out, ",tun-mtu %d", PAYLOAD_SIZE (frame)); buf_printf (&out, ",proto %s", proto_remote (o->ce.proto, remote)); diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index a48c8ec6ceb..4f9fc276868 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -1613,6 +1613,7 @@ generate_key_expansion (struct key_ctx_bi *key, key_ctx_update_implicit_iv (&key->decrypt, key2.keys[1-(int)server].hmac, MAX_HMAC_KEY_LENGTH); + key->initialized = true; ret = true; exit: @@ -1639,6 +1640,50 @@ key_ctx_update_implicit_iv(struct key_ctx *ctx, uint8_t *key, size_t key_len) { } } +bool +tls_session_update_crypto_params(struct tls_session *session, + const struct options *options, struct frame *frame) +{ + bool ret = false; + struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */ + + ASSERT (!session->opt->server); + ASSERT (ks->authenticated); + + init_key_type (&session->opt->key_type, options->ciphername, + options->ciphername_defined, options->authname, options->authname_defined, + options->keysize, true, true); + + bool packet_id_long_form = cipher_kt_mode_ofb_cfb (session->opt->key_type.cipher); + session->opt->crypto_flags_and &= ~(CO_PACKET_ID_LONG_FORM); + if (packet_id_long_form) + session->opt->crypto_flags_and = CO_PACKET_ID_LONG_FORM; + + /* Update frame parameters: undo worst-case overhead, add actual overhead */ + frame_add_to_extra_frame (frame, -(crypto_max_overhead())); + crypto_adjust_frame_parameters (frame, &session->opt->key_type, + options->ciphername_defined, options->use_iv, options->replay, + packet_id_long_form); + frame_finalize(frame, options->ce.link_mtu_defined, options->ce.link_mtu, + options->ce.tun_mtu_defined, options->ce.tun_mtu); + frame_print (frame, D_MTU_INFO, "Data Channel MTU parms"); + + if (!generate_key_expansion (&ks->crypto_options.key_ctx_bi, + &session->opt->key_type, + ks->key_src, + &session->session_id, + &ks->session_id_remote, + false)) + { + msg (D_TLS_ERRORS, "TLS Error: server generate_key_expansion failed"); + goto cleanup; + } + ret = true; +cleanup: + CLEAR (*ks->key_src); + return ret; +} + static bool random_bytes_to_buf (struct buffer *buf, uint8_t *out, @@ -1885,6 +1930,10 @@ push_peer_info(struct buffer *buf, struct tls_session *session) /* support for P_DATA_V2 */ buf_printf(&out, "IV_PROTO=2\n"); + /* support for Negotiable Crypto Paramters */ + if (session->opt->pull) + buf_printf(&out, "IV_NCP=2\n"); + /* push compression status */ #ifdef USE_COMP comp_generate_peer_info_string(&session->opt->comp_options, &out); @@ -2211,9 +2260,11 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi } /* - * Generate tunnel keys if client + * Generate tunnel keys if we're a client. + * If --pull is enabled, the first key generation is postponed until after the + * pull/push, so we can process pushed cipher directives. */ - if (!session->opt->server) + if (!session->opt->server && (!session->opt->pull || ks->key_id > 0)) { if (!generate_key_expansion (&ks->crypto_options.key_ctx_bi, &session->opt->key_type, @@ -2225,7 +2276,7 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi msg (D_TLS_ERRORS, "TLS Error: client generate_key_expansion failed"); goto error; } - + CLEAR (*ks->key_src); } @@ -2891,6 +2942,14 @@ tls_pre_decrypt (struct tls_multi *multi, #endif && (floated || link_socket_actual_match (from, &ks->remote_addr))) { + if (!ks->crypto_options.key_ctx_bi.initialized) + { + msg (D_TLS_DEBUG_LOW, + "Key %s [%d] not initialized (yet), dropping packet.", + print_link_socket_actual (from, &gc), key_id); + goto error_lite; + } + /* return appropriate data channel decrypt key in opt */ *opt = &ks->crypto_options; if (op == P_DATA_V2) @@ -3428,6 +3487,7 @@ tls_pre_encrypt (struct tls_multi *multi, struct key_state *ks = multi->key_scan[i]; if (ks->state >= S_ACTIVE && ks->authenticated + && ks->crypto_options.key_ctx_bi.initialized #ifdef ENABLE_DEF_AUTH && !ks->auth_deferred #endif diff --git a/src/openvpn/ssl.h b/src/openvpn/ssl.h index d9ff8d0128f..416f4263687 100644 --- a/src/openvpn/ssl.h +++ b/src/openvpn/ssl.h @@ -475,6 +475,20 @@ bool tls_rec_payload (struct tls_multi *multi, void tls_update_remote_addr (struct tls_multi *multi, const struct link_socket_actual *addr); +/** + * Update TLS session crypto parameters (cipher and auth) and derive data + * channel keys based on the supplied options. + * + * @param session The TLS session to update. + * @param options The options to use when updating session. + * @param frame The frame options for this session (frame overhead is + * adjusted based on the selected cipher/auth). + * + * @return true if updating succeeded, false otherwise. + */ +bool tls_session_update_crypto_params(struct tls_session *session, + const struct options *options, struct frame *frame); + #ifdef MANAGEMENT_DEF_AUTH static inline char * tls_get_peer_info(const struct tls_multi *multi) diff --git a/src/openvpn/ssl_common.h b/src/openvpn/ssl_common.h index a0df0ffb8f8..9183dabc7e4 100644 --- a/src/openvpn/ssl_common.h +++ b/src/openvpn/ssl_common.h @@ -149,7 +149,12 @@ struct key_source2 { struct key_state { int state; - int key_id; /* inherited from struct tls_session below */ + + /** + * Key id for this key_state, inherited from struct tls_session. + * @see tls_session::key_id. + */ + int key_id; struct key_state_ssl ks_ssl; /* contains SSL object and BIOs for the control channel */ @@ -231,6 +236,7 @@ struct tls_options #ifdef ENABLE_OCC bool disable_occ; #endif + bool pull; #ifdef ENABLE_PUSH_PEER_INFO int push_peer_info_detail; #endif @@ -367,7 +373,13 @@ struct tls_session int initial_opcode; /* our initial P_ opcode */ struct session_id session_id; /* our random session ID */ - int key_id; /* increments with each soft reset (for key renegotiation) */ + + /** + * The current active key id, used to keep track of renegotiations. + * key_id increments with each soft reset to KEY_ID_MASK then recycles back + * to 1. This way you know that if key_id is 0, it is the first key. + */ + int key_id; int limit_next; /* used for traffic shaping on the control channel */ From 49817bf0ad599b8f9e8d52be9c0bb007aece0d48 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Mon, 11 Jul 2016 16:50:59 +0200 Subject: [PATCH 281/643] Update android documentation to match source code Acked-by: Gert Doering Message-Id: <1468248659-27123-1-git-send-email-arne@rfc2549.org> URL: http://article.gmane.org/gmane.network.openvpn.devel/12074 Signed-off-by: Gert Doering --- doc/android.txt | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/doc/android.txt b/doc/android.txt index 137edfc5642..3a096ddc32e 100644 --- a/doc/android.txt +++ b/doc/android.txt @@ -2,7 +2,7 @@ This file documents the support in OpenVPN for Android 4.0 and up. This support is primarily used in the "OpenVPN for Android" app (http://code.google.com/p/ics-openvpn/). For building see the developer -README: http://code.google.com/p/ics-openvpn/source/browse/doc/README.txt. +README: https://github.com/schwabe/ics-openvpn/blob/master/doc/README.txt Android provides the VPNService API (http://developer.android.com/reference/android/net/VpnService.html) @@ -89,3 +89,12 @@ are not specific to Android but are rarely used on other platform. For example using SIGUSR1 and management-hold to restart, pause, continue the VPN on network changes or the external key management --management-external-key option and inline files. + +To better support handover between networks, a the management command + +network-change [samenetwork] + +is used on the Android platform. It tells OpenVPN to do the necessary +action when the network changes. Currently this is just calling +the protect callback when using peer-id regardless of the samenetwork. +Without peer-id OpenVPN will generate USR1 when samenetwork is not set. From d728ebeda8c94fe401dc41b9fbda682ea0d780c9 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Tue, 28 Jun 2016 23:35:00 +0200 Subject: [PATCH 282/643] Add options to restrict cipher negotiation Add --ncp-disable to completely disable cipher negotiation, and --ncp-ciphers to specify which ciphers to accept from the server. v2: * fix --disable-crypto builds * use register_signal() instead of operating directly on c->sig * add man-page entry for new options v3: * rebased on client-side NCP v3 v4: * rebased on client-side NCP v4 Signed-off-by: Steffan Karger Acked-by: Arne Schwabe Acked-by: Gert Doering Message-Id: <1467149700-10042-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/12008 Signed-off-by: Gert Doering --- doc/openvpn.8 | 13 +++++++++++++ src/openvpn/init.c | 34 +++++++++++++++++++++++++++------- src/openvpn/init.h | 4 ++-- src/openvpn/openvpn.h | 3 +++ src/openvpn/options.c | 40 +++++++++++++++++++++++++++++----------- src/openvpn/options.h | 4 +++- src/openvpn/push.c | 11 ++++++++++- src/openvpn/ssl.c | 29 ++++++++++++++++++++++++++++- src/openvpn/ssl_common.h | 4 ++++ 9 files changed, 119 insertions(+), 23 deletions(-) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 3ca6f503785..4f7353bc7c7 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -4131,6 +4131,19 @@ Set to disable encryption. .\"********************************************************* .TP +.B \-\-ncp\-ciphers cipher_list +Restrict the allowed ciphers to be negotiated to the ciphers in +.B cipher_list\fR. +.B cipher_list +is a colon-separated list of ciphers, and defaults to +"AES-256-GCM:AES-128-GCM". +.\"********************************************************* +.TP +.B \-\-ncp\-disable +Disable "negotiable crypto parameters". This completely disables cipher +negotiation. +.\"********************************************************* +.TP .B \-\-keysize n Size of cipher key in bits (optional). If unspecified, defaults to cipher-specific default. The diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 55d64366c75..b96f22eab93 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -1745,7 +1745,7 @@ options_hash_changed_or_zero(const struct md5_digest *a, } #endif /* P2MP */ -void +bool do_up (struct context *c, bool pulled_options, unsigned int option_types_found) { if (!c->c2.do_up_ran) @@ -1753,7 +1753,13 @@ do_up (struct context *c, bool pulled_options, unsigned int option_types_found) reset_coarse_timers (c); if (pulled_options && option_types_found) - do_deferred_options (c, option_types_found); + { + if (!do_deferred_options (c, option_types_found)) + { + msg (D_PUSH_ERRORS, "ERROR: Failed to apply push options"); + return false; + } + } /* if --up-delay specified, open tun, do ifconfig, and run up script now */ if (c->options.up_delay || PULL_DEFINED (&c->options)) @@ -1808,6 +1814,7 @@ do_up (struct context *c, bool pulled_options, unsigned int option_types_found) c->c2.do_up_ran = true; } + return true; } /* @@ -1825,7 +1832,6 @@ pull_permission_mask (const struct context *c) | OPT_P_SHAPER | OPT_P_TIMER | OPT_P_COMP - | OPT_P_CRYPTO | OPT_P_PERSIST | OPT_P_MESSAGES | OPT_P_EXPLICIT_NOTIFY @@ -1836,13 +1842,18 @@ pull_permission_mask (const struct context *c) if (!c->options.route_nopull) flags |= (OPT_P_ROUTE | OPT_P_IPWIN32); +#ifdef ENABLE_CRYPTO + if (c->options.ncp_enabled) + flags |= OPT_P_NCP; +#endif + return flags; } /* * Handle non-tun-related pulled options. */ -void +bool do_deferred_options (struct context *c, const unsigned int found) { if (found & OPT_P_MESSAGES) @@ -1934,15 +1945,18 @@ do_deferred_options (struct context *c, const unsigned int found) if (c->options.pull) { struct tls_session *session = &c->c2.tls_multi->session[TM_ACTIVE]; - if (found & OPT_P_CRYPTO) + if (found & OPT_P_NCP) msg (D_PUSH, "OPTIONS IMPORT: data channel crypto options modified"); /* Do not regenerate keys if server sends an extra push request */ - if (!session->key[KS_PRIMARY].crypto_options.key_ctx_bi.initialized) + if (!session->key[KS_PRIMARY].crypto_options.key_ctx_bi.initialized && + !tls_session_update_crypto_params(session, &c->options, &c->c2.frame)) { - tls_session_update_crypto_params(session, &c->options, &c->c2.frame); + msg (D_TLS_ERRORS, "OPTIONS ERROR: failed to import crypto options"); + return false; } } #endif + return true; } /* @@ -2272,6 +2286,9 @@ do_init_crypto_tls_c1 (struct context *c) &c->c1.ks.tls_auth_key, file, options->key_direction, flags); } + c->c1.ciphername = options->ciphername; + c->c1.authname = options->authname; + #if 0 /* was: #if ENABLE_INLINE_FILES -- Note that enabling this code will break restarts */ if (options->priv_key_file_inline) { @@ -2348,6 +2365,9 @@ do_init_crypto_tls (struct context *c, const unsigned int flags) to.replay_window = options->replay_window; to.replay_time = options->replay_time; to.tcp_mode = link_socket_proto_connection_oriented (options->ce.proto); + to.config_ciphername = c->c1.ciphername; + to.config_authname = c->c1.authname; + to.ncp_enabled = options->ncp_enabled; to.transition_window = options->transition_window; to.handshake_window = options->handshake_window; to.packet_timeout = options->tls_timeout; diff --git a/src/openvpn/init.h b/src/openvpn/init.h index a819bd2ce78..524bc64b147 100644 --- a/src/openvpn/init.h +++ b/src/openvpn/init.h @@ -81,7 +81,7 @@ bool do_test_crypto (const struct options *o); void context_gc_free (struct context *c); -void do_up (struct context *c, +bool do_up (struct context *c, bool pulled_options, unsigned int option_types_found); @@ -91,7 +91,7 @@ const char *format_common_name (struct context *c, struct gc_arena *gc); void reset_coarse_timers (struct context *c); -void do_deferred_options (struct context *c, const unsigned int found); +bool do_deferred_options (struct context *c, const unsigned int found); void inherit_context_child (struct context *dest, const struct context *src); diff --git a/src/openvpn/openvpn.h b/src/openvpn/openvpn.h index 01533d30b25..1a458f1c1c2 100644 --- a/src/openvpn/openvpn.h +++ b/src/openvpn/openvpn.h @@ -210,6 +210,9 @@ struct context_1 struct user_pass *auth_user_pass; /**< Username and password for * authentication. */ + + const char *ciphername; /**< Data channel cipher from config file */ + const char *authname; /**< Data channel auth from config file */ #endif }; diff --git a/src/openvpn/options.c b/src/openvpn/options.c index a9dbc0be17b..56479dc7aac 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -522,6 +522,8 @@ static const char usage_message[] = "--cipher alg : Encrypt packets with cipher algorithm alg\n" " (default=%s).\n" " Set alg=none to disable encryption.\n" + "--ncp-ciphers list : List of ciphers that are allowed to be negotiated.\n" + "--ncp-disable : Disable cipher negotiation.\n" "--prng alg [nsl] : For PRNG, use digest algorithm alg, and\n" " nonce_secret_len=nsl. Set alg=none to disable PRNG.\n" #ifdef HAVE_EVP_CIPHER_CTX_SET_KEY_LENGTH @@ -829,6 +831,12 @@ init_options (struct options *o, const bool init_gc) #ifdef ENABLE_CRYPTO o->ciphername = "BF-CBC"; o->ciphername_defined = true; +#ifdef HAVE_AEAD_CIPHER_MODES /* IV_NCP=2 requires GCM support */ + o->ncp_enabled = true; +#else + o->ncp_enabled = false; +#endif + o->ncp_ciphers = "AES-256-GCM:AES-128-GCM"; o->authname = "SHA1"; o->authname_defined = true; o->prng_hash = "SHA1"; @@ -6637,7 +6645,7 @@ add_option (struct options *options, } else if (streq (p[0], "auth") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_CRYPTO); + VERIFY_PERMISSION (OPT_P_GENERAL); options->authname_defined = true; options->authname = p[1]; if (streq (options->authname, "none")) @@ -6648,12 +6656,12 @@ add_option (struct options *options, } else if (streq (p[0], "auth") && !p[1]) { - VERIFY_PERMISSION (OPT_P_CRYPTO); + VERIFY_PERMISSION (OPT_P_GENERAL); options->authname_defined = true; } else if (streq (p[0], "cipher") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_CRYPTO); + VERIFY_PERMISSION (OPT_P_NCP); options->ciphername_defined = true; options->ciphername = p[1]; if (streq (options->ciphername, "none")) @@ -6664,12 +6672,22 @@ add_option (struct options *options, } else if (streq (p[0], "cipher") && !p[1]) { - VERIFY_PERMISSION (OPT_P_CRYPTO); + VERIFY_PERMISSION (OPT_P_GENERAL); options->ciphername_defined = true; } + else if (streq (p[0], "ncp-ciphers") && p[1] && !p[2]) + { + VERIFY_PERMISSION (OPT_P_GENERAL); + options->ncp_ciphers = p[1]; + } + else if (streq (p[0], "ncp-disable") && !p[1]) + { + VERIFY_PERMISSION (OPT_P_GENERAL); + options->ncp_enabled = false; + } else if (streq (p[0], "prng") && p[1] && !p[3]) { - VERIFY_PERMISSION (OPT_P_CRYPTO); + VERIFY_PERMISSION (OPT_P_GENERAL); if (streq (p[1], "none")) options->prng_hash = NULL; else @@ -6691,12 +6709,12 @@ add_option (struct options *options, } else if (streq (p[0], "no-replay") && !p[1]) { - VERIFY_PERMISSION (OPT_P_CRYPTO); + VERIFY_PERMISSION (OPT_P_GENERAL); options->replay = false; } else if (streq (p[0], "replay-window") && !p[3]) { - VERIFY_PERMISSION (OPT_P_CRYPTO); + VERIFY_PERMISSION (OPT_P_GENERAL); if (p[1]) { int replay_window; @@ -6736,12 +6754,12 @@ add_option (struct options *options, } else if (streq (p[0], "mute-replay-warnings") && !p[1]) { - VERIFY_PERMISSION (OPT_P_CRYPTO); + VERIFY_PERMISSION (OPT_P_GENERAL); options->mute_replay_warnings = true; } else if (streq (p[0], "no-iv") && !p[1]) { - VERIFY_PERMISSION (OPT_P_CRYPTO); + VERIFY_PERMISSION (OPT_P_GENERAL); options->use_iv = false; } else if (streq (p[0], "replay-persist") && p[1] && !p[2]) @@ -6771,7 +6789,7 @@ add_option (struct options *options, { int keysize; - VERIFY_PERMISSION (OPT_P_CRYPTO); + VERIFY_PERMISSION (OPT_P_NCP); keysize = atoi (p[1]) / 8; if (keysize < 0 || keysize > MAX_CIPHER_KEY_LENGTH) { @@ -6800,7 +6818,7 @@ add_option (struct options *options, } else if (streq (p[0], "ecdh-curve") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_CRYPTO); + VERIFY_PERMISSION (OPT_P_GENERAL); options->ecdh_curve= p[1]; } else if (streq (p[0], "tls-server") && !p[1]) diff --git a/src/openvpn/options.h b/src/openvpn/options.h index 486bf5d3d7d..3d644b7b95f 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -471,6 +471,8 @@ struct options int key_direction; bool ciphername_defined; const char *ciphername; + bool ncp_enabled; + const char *ncp_ciphers; bool authname_defined; const char *authname; int keysize; @@ -615,7 +617,7 @@ struct options #define OPT_P_PERSIST_IP (1<<9) #define OPT_P_COMP (1<<10) /* TODO */ #define OPT_P_MESSAGES (1<<11) -#define OPT_P_CRYPTO (1<<12) /* TODO */ +#define OPT_P_NCP (1<<12) /**< Negotiable crypto parameters */ #define OPT_P_TLS_PARMS (1<<13) /* TODO */ #define OPT_P_MTU (1<<14) /* TODO */ #define OPT_P_NICE (1<<15) diff --git a/src/openvpn/push.c b/src/openvpn/push.c index 38ac59ee998..4239e3ef92b 100644 --- a/src/openvpn/push.c +++ b/src/openvpn/push.c @@ -239,11 +239,20 @@ incoming_push_message (struct context *c, const struct buffer *buffer) { c->options.push_option_types_found |= option_types_found; + /* delay bringing tun/tap up until --push parms received from remote */ if (status == PUSH_MSG_REPLY) - do_up (c, true, c->options.push_option_types_found ); /* delay bringing tun/tap up until --push parms received from remote */ + { + if (!do_up (c, true, c->options.push_option_types_found)) + { + msg (D_PUSH_ERRORS, "Failed to open tun/tap interface"); + register_signal (c, SIGUSR1, "do_up-failed"); + goto cleanup; + } + } event_timeout_clear (&c->c2.push_request_interval); } +cleanup: gc_free (&gc); } diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 4f9fc276868..8717324ab9d 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -1640,6 +1640,24 @@ key_ctx_update_implicit_iv(struct key_ctx *ctx, uint8_t *key, size_t key_len) { } } +static bool +item_in_list(const char *item, const char *list) +{ + char *tmp_ciphers = string_alloc (list, NULL); + char *tmp_ciphers_orig = tmp_ciphers; + + const char *token = strtok (tmp_ciphers, ":"); + while(token) + { + if (0 == strcmp (token, item)) + break; + token = strtok (NULL, ":"); + } + free(tmp_ciphers_orig); + + return token != NULL; +} + bool tls_session_update_crypto_params(struct tls_session *session, const struct options *options, struct frame *frame) @@ -1650,6 +1668,15 @@ tls_session_update_crypto_params(struct tls_session *session, ASSERT (!session->opt->server); ASSERT (ks->authenticated); + if (0 != strcmp(options->ciphername, session->opt->config_ciphername) && + !item_in_list(options->ciphername, options->ncp_ciphers)) + { + msg (D_TLS_ERRORS, "Error: pushed cipher not allowed - %s not in %s or %s", + options->ciphername, session->opt->config_ciphername, + options->ncp_ciphers); + return false; + } + init_key_type (&session->opt->key_type, options->ciphername, options->ciphername_defined, options->authname, options->authname_defined, options->keysize, true, true); @@ -1931,7 +1958,7 @@ push_peer_info(struct buffer *buf, struct tls_session *session) buf_printf(&out, "IV_PROTO=2\n"); /* support for Negotiable Crypto Paramters */ - if (session->opt->pull) + if (session->opt->ncp_enabled && session->opt->pull) buf_printf(&out, "IV_NCP=2\n"); /* push compression status */ diff --git a/src/openvpn/ssl_common.h b/src/openvpn/ssl_common.h index 9183dabc7e4..6bfde6baeee 100644 --- a/src/openvpn/ssl_common.h +++ b/src/openvpn/ssl_common.h @@ -273,6 +273,10 @@ struct tls_options int replay_time; /* --replay-window parm */ bool tcp_mode; + const char *config_ciphername; + const char *config_authname; + bool ncp_enabled; + /* packet authentication for TLS handshake */ struct crypto_options tls_auth; From a17aa98180319f34c3240aea617bf8114d0bcaf7 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Tue, 28 Jun 2016 23:36:11 +0200 Subject: [PATCH 283/643] Add server-side support for cipher negotiation Pushes AES-256-GCM when a connection client advertises IV_NCP=2, and supports serving connections to clients with different data channel cipher configuration simultaneously. v2: * Update manpage * Add Changes.rst entry v3: * Do not regenerate keys if the client sends a second pull request * Don't postpone key generation if client has no IV_NCP support v4: * rebase on client-side NCP v4 Signed-off-by: Steffan Karger Acked-by: Arne Schwabe Acked-by: Gert Doering Message-Id: <1467149771-10374-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/12009 Signed-off-by: Gert Doering --- Changes.rst | 12 ++++++++++ doc/openvpn.8 | 4 ++++ src/openvpn/init.c | 5 ++-- src/openvpn/push.c | 35 +++++++++++++++++++-------- src/openvpn/ssl.c | 51 ++++++++++++++++++++++++++++++---------- src/openvpn/ssl.h | 6 +++++ src/openvpn/ssl_common.h | 1 + 7 files changed, 90 insertions(+), 24 deletions(-) diff --git a/Changes.rst b/Changes.rst index 55fca958ed1..9fcba75cf7e 100644 --- a/Changes.rst +++ b/Changes.rst @@ -55,6 +55,13 @@ Http proxy password inside config file Http proxy passwords can be specified with the inline file option http-proxy-user-pass +Cipher negotiation + Data channel ciphers are now by default negotiated. If a client advertises + support for Negotiable Crypto Parameters (NCP), the server will choose a + cipher (by default AES-256-GCM) for the data channel, and tell the client + to use that cipher. Data channel cipher negotiation can be controlled + using --ncp-ciphers and --ncp-disable. + User-visible Changes -------------------- @@ -124,6 +131,11 @@ User-visible Changes time in seconds to wait between reconnection attempts when an exponential backoff is triggered due to repeated retries. Default = 300 seconds. +- Data channel cipher negotiation (see New features section) can override + ciphers configured in the config file. Use --ncp-disable if you don't want + that. + + Maintainer-visible changes -------------------------- - OpenVPN no longer supports building with crypto support, but without TLS diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 4f7353bc7c7..2f4263608d5 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -4137,6 +4137,10 @@ Restrict the allowed ciphers to be negotiated to the ciphers in .B cipher_list is a colon-separated list of ciphers, and defaults to "AES-256-GCM:AES-128-GCM". + +For servers, the first cipher from +.B cipher_list +will be pushed to clients that support cipher negotiation. .\"********************************************************* .TP .B \-\-ncp\-disable diff --git a/src/openvpn/init.c b/src/openvpn/init.c index b96f22eab93..5a47b923e13 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -2330,8 +2330,8 @@ do_init_crypto_tls (struct context *c, const unsigned int flags) /* In short form, unique datagram identifier is 32 bits, in long form 64 bits */ packet_id_long_form = cipher_kt_mode_ofb_cfb (c->c1.ks.key_type.cipher); - /* Compute MTU parameters (postpone if we pull options) */ - if (c->options.pull) + /* Compute MTU parameters (postpone if we push/pull options) */ + if (c->options.pull || c->options.mode == MODE_SERVER) { /* Account for worst-case crypto overhead before allocating buffers */ frame_add_to_extra_frame (&c->c2.frame, crypto_max_overhead()); @@ -2375,6 +2375,7 @@ do_init_crypto_tls (struct context *c, const unsigned int flags) to.renegotiate_packets = options->renegotiate_packets; to.renegotiate_seconds = options->renegotiate_seconds; to.single_session = options->single_session; + to.mode = options->mode; to.pull = options->pull; #ifdef ENABLE_PUSH_PEER_INFO if (options->push_peer_info) /* all there is */ diff --git a/src/openvpn/push.c b/src/openvpn/push.c index 4239e3ef92b..000c82f93f3 100644 --- a/src/openvpn/push.c +++ b/src/openvpn/push.c @@ -245,13 +245,30 @@ incoming_push_message (struct context *c, const struct buffer *buffer) if (!do_up (c, true, c->options.push_option_types_found)) { msg (D_PUSH_ERRORS, "Failed to open tun/tap interface"); - register_signal (c, SIGUSR1, "do_up-failed"); - goto cleanup; + goto error; } } event_timeout_clear (&c->c2.push_request_interval); } + else if (status == PUSH_MSG_REQUEST) + { + if (c->options.mode == MODE_SERVER) + { + struct tls_session *session = &c->c2.tls_multi->session[TM_ACTIVE]; + /* Do not regenerate keys if client send a second push request */ + if (!session->key[KS_PRIMARY].crypto_options.key_ctx_bi.initialized && + !tls_session_update_crypto_params (session, &c->options, + &c->c2.frame)) + { + msg (D_TLS_ERRORS, "TLS Error: server generate_key_expansion failed"); + goto error; + } + } + } + goto cleanup; +error: + register_signal (c, SIGUSR1, "process-push-msg-failed"); cleanup: gc_free (&gc); } @@ -302,15 +319,13 @@ prepare_push_reply (struct options *o, struct tls_multi *tls_multi) } /* Push cipher if client supports Negotiable Crypto Parameters */ - optstr = peer_info ? strstr(peer_info, "IV_NCP=") : NULL; - if (optstr) + if (tls_peer_info_ncp_ver (peer_info) >= 2 && o->ncp_enabled) { - int ncp = 0; - int r = sscanf(optstr, "IV_NCP=%d", &ncp); - if ((r == 1) && (ncp == 2)) - { - push_option_fmt(o, M_USAGE, "cipher %s", o->ciphername); - } + /* Push the first cipher from --ncp-ciphers to the client. + * TODO: actual negotiation, instead of server dictatorship. */ + char *push_cipher = string_alloc(o->ncp_ciphers, &o->gc); + o->ciphername = strtok (push_cipher, ":"); + push_option_fmt(o, M_USAGE, "cipher %s", o->ciphername); } return true; } diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 8717324ab9d..72001a3c2ce 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -1665,10 +1665,10 @@ tls_session_update_crypto_params(struct tls_session *session, bool ret = false; struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */ - ASSERT (!session->opt->server); ASSERT (ks->authenticated); - if (0 != strcmp(options->ciphername, session->opt->config_ciphername) && + if (!session->opt->server && + 0 != strcmp(options->ciphername, session->opt->config_ciphername) && !item_in_list(options->ciphername, options->ncp_ciphers)) { msg (D_TLS_ERRORS, "Error: pushed cipher not allowed - %s not in %s or %s", @@ -1695,12 +1695,13 @@ tls_session_update_crypto_params(struct tls_session *session, options->ce.tun_mtu_defined, options->ce.tun_mtu); frame_print (frame, D_MTU_INFO, "Data Channel MTU parms"); + const struct session_id *client_sid = session->opt->server ? + &ks->session_id_remote : &session->session_id; + const struct session_id *server_sid = !session->opt->server ? + &ks->session_id_remote : &session->session_id; if (!generate_key_expansion (&ks->crypto_options.key_ctx_bi, - &session->opt->key_type, - ks->key_src, - &session->session_id, - &ks->session_id_remote, - false)) + &session->opt->key_type, ks->key_src, client_sid, server_sid, + session->opt->server)) { msg (D_TLS_ERRORS, "TLS Error: server generate_key_expansion failed"); goto cleanup; @@ -1958,8 +1959,11 @@ push_peer_info(struct buffer *buf, struct tls_session *session) buf_printf(&out, "IV_PROTO=2\n"); /* support for Negotiable Crypto Paramters */ - if (session->opt->ncp_enabled && session->opt->pull) - buf_printf(&out, "IV_NCP=2\n"); + if (session->opt->ncp_enabled && + (session->opt->mode == MODE_SERVER || session->opt->pull)) + { + buf_printf(&out, "IV_NCP=2\n"); + } /* push compression status */ #ifdef USE_COMP @@ -2063,10 +2067,13 @@ key_method_2_write (struct buffer *buf, struct tls_session *session) if (!push_peer_info (buf, session)) goto error; - /* - * generate tunnel keys if server + /* Generate tunnel keys if we're a TLS server. + * If we're a p2mp server and IV_NCP >= 2 is negotiated, the first key + * generation is postponed until after the pull/push, so we can process pushed + * cipher directives. */ - if (session->opt->server) + if (session->opt->server && !(session->opt->ncp_enabled && + session->opt->mode == MODE_SERVER && ks->key_id <= 0)) { if (ks->authenticated) { @@ -2218,6 +2225,12 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi multi->peer_info = read_string_alloc (buf); if ( multi->peer_info ) output_peer_info_env (session->opt->es, multi->peer_info); + + if (tls_peer_info_ncp_ver (multi->peer_info) < 2) + { + /* Peer does not support NCP */ + session->opt->ncp_enabled = false; + } #endif if (tls_session_user_pass_enabled(session)) @@ -3689,6 +3702,20 @@ tls_update_remote_addr (struct tls_multi *multi, const struct link_socket_actual gc_free (&gc); } +int +tls_peer_info_ncp_ver(const char *peer_info) +{ + const char *ncpstr = peer_info ? strstr (peer_info, "IV_NCP=") : NULL; + if (ncpstr) + { + int ncp = 0; + int r = sscanf(ncpstr, "IV_NCP=%d", &ncp); + if (r == 1) + return ncp; + } + return 0; +} + /* * Dump a human-readable rendition of an openvpn packet * into a garbage collectable string which is returned. diff --git a/src/openvpn/ssl.h b/src/openvpn/ssl.h index 416f4263687..de68b69e93f 100644 --- a/src/openvpn/ssl.h +++ b/src/openvpn/ssl.h @@ -497,6 +497,12 @@ tls_get_peer_info(const struct tls_multi *multi) } #endif +/** + * Return the Negotiable Crypto Parameters version advertised in the peer info + * string, or 0 if none specified. + */ +int tls_peer_info_ncp_ver(const char *peer_info); + /* * inline functions */ diff --git a/src/openvpn/ssl_common.h b/src/openvpn/ssl_common.h index 6bfde6baeee..eb2ad6f956d 100644 --- a/src/openvpn/ssl_common.h +++ b/src/openvpn/ssl_common.h @@ -236,6 +236,7 @@ struct tls_options #ifdef ENABLE_OCC bool disable_occ; #endif + int mode; bool pull; #ifdef ENABLE_PUSH_PEER_INFO int push_peer_info_detail; From 834f602fd069118b5d00a9042c9fdb20930257eb Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Mon, 25 Jul 2016 20:52:46 +0200 Subject: [PATCH 284/643] Allow ncp-disable and ncp-ciphers to be specified in ccd files This allows the ncp-disable and ncp-ciphers options to be used in 'client config dir' files, to disable or change the negotiable crypto parameter settings for specific clients. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1469472766-25131-1-git-send-email-steffan@karger.me> URL: http://article.gmane.org/gmane.network.openvpn.devel/12096 Signed-off-by: Gert Doering --- src/openvpn/options.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 56479dc7aac..3d4a6455d5f 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -6677,12 +6677,12 @@ add_option (struct options *options, } else if (streq (p[0], "ncp-ciphers") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_GENERAL); + VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_INSTANCE); options->ncp_ciphers = p[1]; } else if (streq (p[0], "ncp-disable") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); + VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_INSTANCE); options->ncp_enabled = false; } else if (streq (p[0], "prng") && p[1] && !p[3]) From dea8917a032e2303b39cce23e60f2348516d5a12 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Tue, 26 Jul 2016 15:55:38 +0200 Subject: [PATCH 285/643] Fix '--cipher none --cipher' crash As reported in trac #699, OpenVPN crashes when an "--cipher none" option is followed by "--cipher" (without arguments). Fix this by removing the redudant ciphername_defined and authname_defined members of struct options, and remove support to specify --cipher or --auth without an argument. That not only fixes the issue, but also cleans up the code a bit. v2: don't print a deprecating warning (we'll do that in the 2.3 branch), but just rip out support for --cipher and --auth without an argument. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1469541338-1530-1-git-send-email-steffan.karger@fox-it.com> URL: http://article.gmane.org/gmane.network.openvpn.devel/12106 Signed-off-by: Gert Doering --- src/openvpn/crypto.c | 11 ++++------- src/openvpn/crypto.h | 16 +++++++++++++--- src/openvpn/init.c | 19 +++++++------------ src/openvpn/options.c | 32 ++++++-------------------------- src/openvpn/options.h | 2 -- src/openvpn/ssl.c | 6 ++---- 6 files changed, 32 insertions(+), 54 deletions(-) diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c index f9cf62aead6..d94896ce64c 100644 --- a/src/openvpn/crypto.c +++ b/src/openvpn/crypto.c @@ -713,7 +713,6 @@ openvpn_decrypt (struct buffer *buf, struct buffer work, void crypto_adjust_frame_parameters(struct frame *frame, const struct key_type* kt, - bool cipher_defined, bool use_iv, bool packet_id, bool packet_id_long_form) @@ -723,7 +722,7 @@ crypto_adjust_frame_parameters(struct frame *frame, if (packet_id) crypto_overhead += packet_id_size (packet_id_long_form); - if (cipher_defined) + if (kt->cipher) { if (use_iv) crypto_overhead += cipher_kt_iv_size (kt->cipher); @@ -756,14 +755,12 @@ crypto_max_overhead(void) */ void init_key_type (struct key_type *kt, const char *ciphername, - bool ciphername_defined, const char *authname, - bool authname_defined, int keysize, - bool tls_mode, bool warn) + const char *authname, int keysize, bool tls_mode, bool warn) { bool aead_cipher = false; CLEAR (*kt); - if (ciphername && ciphername_defined) + if (ciphername) { kt->cipher = cipher_kt_get (translate_cipher_name_from_openvpn(ciphername)); kt->cipher_length = cipher_kt_key_size (kt->cipher); @@ -788,7 +785,7 @@ init_key_type (struct key_type *kt, const char *ciphername, if (warn) msg (M_WARN, "******* WARNING *******: null cipher specified, no encryption will be used"); } - if (authname && authname_defined) + if (authname) { if (!aead_cipher) { /* Ignore auth for AEAD ciphers */ kt->digest = md_kt_get (authname); diff --git a/src/openvpn/crypto.h b/src/openvpn/crypto.h index de433ae8e54..3b6bb98057b 100644 --- a/src/openvpn/crypto.h +++ b/src/openvpn/crypto.h @@ -296,9 +296,20 @@ bool write_key (const struct key *key, const struct key_type *kt, int read_key (struct key *key, const struct key_type *kt, struct buffer *buf); +/** + * Initialize a key_type structure with. + * + * @param kt The struct key_type to initialize + * @param ciphername The name of the cipher to use + * @param authname The name of the HMAC digest to use + * @param keysize The length of the cipher key to use, in bytes. Only valid + * for ciphers that support variable length keys. + * @param tls_mode Specifies wether we are running in TLS mode, which allows + * more ciphers than static key mode. + * @param warn Print warnings when null cipher / auth is used. + */ void init_key_type (struct key_type *kt, const char *ciphername, - bool ciphername_defined, const char *authname, bool authname_defined, - int keysize, bool tls_mode, bool warn); + const char *authname, int keysize, bool tls_mode, bool warn); /* * Key context functions @@ -389,7 +400,6 @@ bool openvpn_decrypt (struct buffer *buf, struct buffer work, /** Calculate crypto overhead and adjust frame to account for that */ void crypto_adjust_frame_parameters(struct frame *frame, const struct key_type* kt, - bool cipher_defined, bool use_iv, bool packet_id, bool packet_id_long_form); diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 5a47b923e13..87a0e32b21d 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -2156,10 +2156,8 @@ do_init_crypto_static (struct context *c, const unsigned int flags) struct key_direction_state kds; /* Get cipher & hash algorithms */ - init_key_type (&c->c1.ks.key_type, options->ciphername, - options->ciphername_defined, options->authname, - options->authname_defined, options->keysize, - options->test_crypto, true); + init_key_type (&c->c1.ks.key_type, options->ciphername, options->authname, + options->keysize, options->test_crypto, true); /* Read cipher and hmac keys from shared secret file */ { @@ -2201,7 +2199,6 @@ do_init_crypto_static (struct context *c, const unsigned int flags) /* Compute MTU parameters */ crypto_adjust_frame_parameters (&c->c2.frame, &c->c1.ks.key_type, - options->ciphername_defined, options->use_iv, options->replay, true); /* Sanity check on IV, sequence number, and cipher mode options */ @@ -2249,9 +2246,8 @@ do_init_crypto_tls_c1 (struct context *c) } /* Get cipher & hash algorithms */ - init_key_type (&c->c1.ks.key_type, options->ciphername, - options->ciphername_defined, options->authname, - options->authname_defined, options->keysize, true, true); + init_key_type (&c->c1.ks.key_type, options->ciphername, options->authname, + options->keysize, true, true); /* Initialize PRNG with config-specified digest */ prng_init (options->prng_hash, options->prng_nonce_secret_len); @@ -2270,7 +2266,7 @@ do_init_crypto_tls_c1 (struct context *c) /* Initialize key_type for tls-auth with auth only */ CLEAR (c->c1.ks.tls_auth_key_type); - if (options->authname && options->authname_defined) + if (options->authname) { c->c1.ks.tls_auth_key_type.digest = md_kt_get (options->authname); c->c1.ks.tls_auth_key_type.hmac_length = @@ -2339,8 +2335,7 @@ do_init_crypto_tls (struct context *c, const unsigned int flags) else { crypto_adjust_frame_parameters(&c->c2.frame, &c->c1.ks.key_type, - options->ciphername_defined, options->use_iv, options->replay, - packet_id_long_form); + options->use_iv, options->replay, packet_id_long_form); } tls_adjust_frame_parameters (&c->c2.frame); @@ -2468,7 +2463,7 @@ do_init_crypto_tls (struct context *c, const unsigned int flags) to.tls_auth.flags |= CO_PACKET_ID_LONG_FORM; crypto_adjust_frame_parameters (&to.frame, &c->c1.ks.tls_auth_key_type, - false, false, true, true); + false, true, true); } /* If we are running over TCP, allow for diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 3d4a6455d5f..7e08fcdabb1 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -830,7 +830,6 @@ init_options (struct options *o, const bool init_gc) #endif #ifdef ENABLE_CRYPTO o->ciphername = "BF-CBC"; - o->ciphername_defined = true; #ifdef HAVE_AEAD_CIPHER_MODES /* IV_NCP=2 requires GCM support */ o->ncp_enabled = true; #else @@ -838,7 +837,6 @@ init_options (struct options *o, const bool init_gc) #endif o->ncp_ciphers = "AES-256-GCM:AES-128-GCM"; o->authname = "SHA1"; - o->authname_defined = true; o->prng_hash = "SHA1"; o->prng_nonce_secret_len = 16; o->replay = true; @@ -1618,9 +1616,7 @@ show_settings (const struct options *o) #ifdef ENABLE_CRYPTO SHOW_STR (shared_secret_file); SHOW_INT (key_direction); - SHOW_BOOL (ciphername_defined); SHOW_STR (ciphername); - SHOW_BOOL (authname_defined); SHOW_STR (authname); SHOW_STR (prng_hash); SHOW_INT (prng_nonce_secret_len); @@ -2989,12 +2985,11 @@ calc_options_string_link_mtu(const struct options *o, const struct frame *frame) { struct frame fake_frame = *frame; struct key_type fake_kt; - init_key_type (&fake_kt, o->ciphername, o->ciphername_defined, - o->authname, o->authname_defined, o->keysize, true, false); + init_key_type (&fake_kt, o->ciphername, o->authname, o->keysize, true, + false); frame_add_to_extra_frame (&fake_frame, -(crypto_max_overhead())); - crypto_adjust_frame_parameters (&fake_frame, &fake_kt, - o->ciphername_defined, o->use_iv, o->replay, - cipher_kt_mode_ofb_cfb (fake_kt.cipher)); + crypto_adjust_frame_parameters (&fake_frame, &fake_kt, o->use_iv, + o->replay, cipher_kt_mode_ofb_cfb (fake_kt.cipher)); frame_finalize(&fake_frame, o->ce.link_mtu_defined, o->ce.link_mtu, o->ce.tun_mtu_defined, o->ce.tun_mtu); msg (D_MTU_DEBUG, "%s: link-mtu %zu -> %d", __func__, link_mtu, @@ -3146,9 +3141,8 @@ options_string (const struct options *o, + (TLS_SERVER == true) <= 1); - init_key_type (&kt, o->ciphername, o->ciphername_defined, - o->authname, o->authname_defined, - o->keysize, true, false); + init_key_type (&kt, o->ciphername, o->authname, o->keysize, true, + false); buf_printf (&out, ",cipher %s", translate_cipher_name_to_openvpn(cipher_kt_name (kt.cipher))); @@ -6646,35 +6640,21 @@ add_option (struct options *options, else if (streq (p[0], "auth") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); - options->authname_defined = true; options->authname = p[1]; if (streq (options->authname, "none")) { - options->authname_defined = false; options->authname = NULL; } } - else if (streq (p[0], "auth") && !p[1]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->authname_defined = true; - } else if (streq (p[0], "cipher") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_NCP); - options->ciphername_defined = true; options->ciphername = p[1]; if (streq (options->ciphername, "none")) { - options->ciphername_defined = false; options->ciphername = NULL; } } - else if (streq (p[0], "cipher") && !p[1]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->ciphername_defined = true; - } else if (streq (p[0], "ncp-ciphers") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_INSTANCE); diff --git a/src/openvpn/options.h b/src/openvpn/options.h index 3d644b7b95f..9b7b57cf036 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -469,11 +469,9 @@ struct options const char *shared_secret_file; const char *shared_secret_file_inline; int key_direction; - bool ciphername_defined; const char *ciphername; bool ncp_enabled; const char *ncp_ciphers; - bool authname_defined; const char *authname; int keysize; const char *prng_hash; diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 72001a3c2ce..a220b79a541 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -1678,8 +1678,7 @@ tls_session_update_crypto_params(struct tls_session *session, } init_key_type (&session->opt->key_type, options->ciphername, - options->ciphername_defined, options->authname, options->authname_defined, - options->keysize, true, true); + options->authname, options->keysize, true, true); bool packet_id_long_form = cipher_kt_mode_ofb_cfb (session->opt->key_type.cipher); session->opt->crypto_flags_and &= ~(CO_PACKET_ID_LONG_FORM); @@ -1689,8 +1688,7 @@ tls_session_update_crypto_params(struct tls_session *session, /* Update frame parameters: undo worst-case overhead, add actual overhead */ frame_add_to_extra_frame (frame, -(crypto_max_overhead())); crypto_adjust_frame_parameters (frame, &session->opt->key_type, - options->ciphername_defined, options->use_iv, options->replay, - packet_id_long_form); + options->use_iv, options->replay, packet_id_long_form); frame_finalize(frame, options->ce.link_mtu_defined, options->ce.link_mtu, options->ce.tun_mtu_defined, options->ce.tun_mtu); frame_print (frame, D_MTU_INFO, "Data Channel MTU parms"); From d1bd37fd508ee0462daa21011e781198964be921 Mon Sep 17 00:00:00 2001 From: Selva Nair Date: Thu, 11 Aug 2016 18:58:29 -0400 Subject: [PATCH 286/643] Avoid format specifier %zu for Windows compatibility - Replace %zu by %u and cast the size_t variable to (unsigned int). The cast should be safe as in all instances the number involved is small. Note: mingw64 targets msvcrt.dll runtime that doesn't support %zu and print "zu" instead of the number. With -Wformat the compiler does warn that z is an unknown conversion type. v2: Cast to (unsigned int) instead of (int). Signed-off-by: Selva Nair Acked-by: Gert Doering Acked-by: David Sommerseth Message-Id: <1470956309-31268-1-git-send-email-selva.nair@gmail.com> URL: https://sourceforge.net/p/openvpn/mailman/message/35274787/ Signed-off-by: David Sommerseth --- src/openvpn/crypto.c | 4 ++-- src/openvpn/options.c | 4 ++-- src/openvpn/ssl_mbedtls.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c index d94896ce64c..d6d025122f6 100644 --- a/src/openvpn/crypto.c +++ b/src/openvpn/crypto.c @@ -738,8 +738,8 @@ crypto_adjust_frame_parameters(struct frame *frame, frame_add_to_extra_frame (frame, crypto_overhead); - msg(D_MTU_DEBUG, "%s: Adjusting frame parameters for crypto by %zu bytes", - __func__, crypto_overhead); + msg(D_MTU_DEBUG, "%s: Adjusting frame parameters for crypto by %u bytes", + __func__, (unsigned int) crypto_overhead); } size_t diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 7e08fcdabb1..c100d4ca0f1 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -2992,7 +2992,7 @@ calc_options_string_link_mtu(const struct options *o, const struct frame *frame) o->replay, cipher_kt_mode_ofb_cfb (fake_kt.cipher)); frame_finalize(&fake_frame, o->ce.link_mtu_defined, o->ce.link_mtu, o->ce.tun_mtu_defined, o->ce.tun_mtu); - msg (D_MTU_DEBUG, "%s: link-mtu %zu -> %d", __func__, link_mtu, + msg (D_MTU_DEBUG, "%s: link-mtu %u -> %d", __func__, (unsigned int) link_mtu, EXPANDED_SIZE (&fake_frame)); link_mtu = EXPANDED_SIZE (&fake_frame); } @@ -3061,7 +3061,7 @@ options_string (const struct options *o, */ buf_printf (&out, ",dev-type %s", dev_type_string (o->dev, o->dev_type)); - buf_printf (&out, ",link-mtu %zu", calc_options_string_link_mtu(o, frame)); + buf_printf (&out, ",link-mtu %u", (unsigned int) calc_options_string_link_mtu(o, frame)); buf_printf (&out, ",tun-mtu %d", PAYLOAD_SIZE (frame)); buf_printf (&out, ",proto %s", proto_remote (o->ce.proto, remote)); diff --git a/src/openvpn/ssl_mbedtls.c b/src/openvpn/ssl_mbedtls.c index e20ec02dd54..8a761a45a45 100644 --- a/src/openvpn/ssl_mbedtls.c +++ b/src/openvpn/ssl_mbedtls.c @@ -1111,8 +1111,8 @@ print_details (struct key_state_ssl * ks_ssl, const char *prefix) cert = mbedtls_ssl_get_peer_cert (ks_ssl->ctx); if (cert != NULL) { - openvpn_snprintf (s2, sizeof (s2), ", %zu bit key", - mbedtls_pk_get_bitlen (&cert->pk)); + openvpn_snprintf (s2, sizeof (s2), ", %u bit key", + (unsigned int) mbedtls_pk_get_bitlen (&cert->pk)); } msg (D_HANDSHAKE, "%s%s", s1, s2); From c94b3ff0f5f1dbd4949f18f69ed3611f82a29021 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Tue, 16 Aug 2016 16:45:42 +0200 Subject: [PATCH 287/643] Discourage using 64-bit block ciphers As discussed with the development team, we should start moving away from ciphers with a small block size. For OpenVPN in particular this means moving away from 64-bit block ciphers, towards 128-bit block ciphers. This patch makes a start with that by moving ciphers with a block size < 128 bits to the bottom of the --show-ciphers output, and printing a warning in the connection phase if such a cipher is used. While touching this function, improve the output of --show-ciphers by ordering the output alphabetically, and changing the output format slightly. [DS: Fixed C89 issues in patch, moving 'int nid' and 'size_t i' declaration to begining of function instead of in the for-loops. This is also required to not break building on stricter compiler setups where C99 must be enabled explicitly ] Signed-off-by: Steffan Karger Acked-by: Arne Schwabe Message-Id: <1471358742-8773-1-git-send-email-steffan@karger.me> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg00029.html CVE: 2016-6329 Signed-off-by: David Sommerseth --- src/openvpn/crypto.c | 11 +++- src/openvpn/crypto_mbedtls.c | 44 ++++++++++---- src/openvpn/crypto_openssl.c | 110 ++++++++++++++++++++++++++++------- tests/t_lpback.sh | 2 +- 4 files changed, 132 insertions(+), 35 deletions(-) diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c index d6d025122f6..6f578419adb 100644 --- a/src/openvpn/crypto.c +++ b/src/openvpn/crypto.c @@ -825,9 +825,14 @@ init_key_ctx (struct key_ctx *ctx, struct key *key, dmsg (D_SHOW_KEYS, "%s: CIPHER KEY: %s", prefix, format_hex (key->cipher, kt->cipher_length, 0, &gc)); dmsg (D_CRYPTO_DEBUG, "%s: CIPHER block_size=%d iv_size=%d", - prefix, - cipher_kt_block_size(kt->cipher), - cipher_kt_iv_size(kt->cipher)); + prefix, cipher_kt_block_size(kt->cipher), + cipher_kt_iv_size(kt->cipher)); + if (cipher_kt_block_size(kt->cipher) < 128/8) + { + msg (M_WARN, "WARNING: this cipher's block size is less than 128 bit " + "(%d bit). Consider using a --cipher with a larger block size.", + cipher_kt_block_size(kt->cipher)*8); + } } if (kt->digest && kt->hmac_length > 0) { diff --git a/src/openvpn/crypto_mbedtls.c b/src/openvpn/crypto_mbedtls.c index da1b4176690..92cba492ffd 100644 --- a/src/openvpn/crypto_mbedtls.c +++ b/src/openvpn/crypto_mbedtls.c @@ -132,6 +132,25 @@ const cipher_name_pair cipher_name_translation_table[] = { const size_t cipher_name_translation_table_count = sizeof (cipher_name_translation_table) / sizeof (*cipher_name_translation_table); +static void print_cipher(const cipher_kt_t *info) +{ + if (info && (cipher_kt_mode_cbc(info) +#ifdef HAVE_AEAD_CIPHER_MODES + || cipher_kt_mode_aead(info) +#endif + )) + { + const char *ssl_only = cipher_kt_mode_cbc(info) ? + "" : ", TLS client/server mode only"; + const char *var_key_size = info->flags & MBEDTLS_CIPHER_VARIABLE_KEY_LEN ? + " by default" : ""; + + printf ("%s (%d bit key%s, %d bit block%s)\n", + cipher_kt_name(info), cipher_kt_key_size(info) * 8, var_key_size, + cipher_kt_block_size(info) * 8, ssl_only); + } +} + void show_available_ciphers () { @@ -147,20 +166,23 @@ show_available_ciphers () while (*ciphers != 0) { const cipher_kt_t *info = mbedtls_cipher_info_from_type(*ciphers); - - if (info && (cipher_kt_mode_cbc(info) -#ifdef HAVE_AEAD_CIPHER_MODES - || cipher_kt_mode_aead(info) -#endif - )) + if (info && cipher_kt_block_size(info) >= 128/8) { - const char *ssl_only = cipher_kt_mode_cbc(info) ? - "" : " (TLS client/server mode)"; - - printf ("%s %d bit default key%s\n", - cipher_kt_name(info), cipher_kt_key_size(info) * 8, ssl_only); + print_cipher(info); } + ciphers++; + } + printf ("\nThe following ciphers have a block size of less than 128 bits, \n" + "and are therefore deprecated. Do not use unless you have to.\n\n"); + ciphers = mbedtls_cipher_list(); + while (*ciphers != 0) + { + const cipher_kt_t *info = mbedtls_cipher_info_from_type(*ciphers); + if (info && cipher_kt_block_size(info) < 128/8) + { + print_cipher(info); + } ciphers++; } printf ("\n"); diff --git a/src/openvpn/crypto_openssl.c b/src/openvpn/crypto_openssl.c index 376c8befa02..3484c77112e 100644 --- a/src/openvpn/crypto_openssl.c +++ b/src/openvpn/crypto_openssl.c @@ -249,11 +249,45 @@ const size_t cipher_name_translation_table_count = sizeof (cipher_name_translation_table) / sizeof (*cipher_name_translation_table); +static int +cipher_name_cmp(const void *a, const void *b) +{ + const EVP_CIPHER * const *cipher_a = a; + const EVP_CIPHER * const *cipher_b = b; + + const char *cipher_name_a = + translate_cipher_name_to_openvpn(EVP_CIPHER_name(*cipher_a)); + const char *cipher_name_b = + translate_cipher_name_to_openvpn(EVP_CIPHER_name(*cipher_b)); + + return strcmp(cipher_name_a, cipher_name_b); +} + +static void +print_cipher(const EVP_CIPHER *cipher) +{ + const char *var_key_size = + (EVP_CIPHER_flags (cipher) & EVP_CIPH_VARIABLE_LENGTH) ? + " by default" : ""; + const char *ssl_only = cipher_kt_mode_cbc(cipher) ? + "" : ", TLS client/server mode only"; + + printf ("%s (%d bit key%s, %d bit block%s)\n", + translate_cipher_name_to_openvpn (EVP_CIPHER_name (cipher)), + EVP_CIPHER_key_length (cipher) * 8, var_key_size, + cipher_kt_block_size (cipher) * 8, ssl_only); +} + void show_available_ciphers () { int nid; + size_t i; + /* If we ever exceed this, we must be more selective */ + const size_t cipher_list_len = 1000; + const EVP_CIPHER *cipher_list[cipher_list_len]; + size_t num_ciphers = 0; #ifndef ENABLE_SMALL printf ("The following ciphers and cipher modes are available for use\n" "with " PACKAGE_NAME ". Each cipher shown below may be use as a\n" @@ -263,32 +297,40 @@ show_available_ciphers () "In static key mode only CBC mode is allowed.\n\n"); #endif - for (nid = 0; nid < 10000; ++nid) /* is there a better way to get the size of the nid list? */ + for (nid = 0; nid < 10000; ++nid) { - const EVP_CIPHER *cipher = EVP_get_cipherbynid (nid); - if (cipher) - { - if (cipher_kt_mode_cbc(cipher) + const EVP_CIPHER *cipher = EVP_get_cipherbynid(nid); + if (cipher && (cipher_kt_mode_cbc(cipher) #ifdef ENABLE_OFB_CFB_MODE || cipher_kt_mode_ofb_cfb(cipher) #endif #ifdef HAVE_AEAD_CIPHER_MODES || cipher_kt_mode_aead(cipher) #endif - ) - { - const char *var_key_size = - (EVP_CIPHER_flags (cipher) & EVP_CIPH_VARIABLE_LENGTH) ? - "variable" : "fixed"; - const char *ssl_only = cipher_kt_mode_cbc(cipher) ? - "" : " (TLS client/server mode)"; - - printf ("%s %d bit default key (%s)%s\n", - translate_cipher_name_to_openvpn(OBJ_nid2sn (nid)), - EVP_CIPHER_key_length (cipher) * 8, var_key_size, ssl_only); - } + )) + { + cipher_list[num_ciphers++] = cipher; + } + if (num_ciphers == cipher_list_len) + { + msg (M_WARN, "WARNING: Too many ciphers, not showing all"); + break; } } + + qsort (cipher_list, num_ciphers, sizeof(*cipher_list), cipher_name_cmp); + + for (i = 0; i < num_ciphers; i++) { + if (cipher_kt_block_size(cipher_list[i]) >= 128/8) + print_cipher(cipher_list[i]); + } + + printf ("\nThe following ciphers have a block size of less than 128 bits, \n" + "and are therefore deprecated. Do not use unless you have to.\n\n"); + for (i = 0; i < num_ciphers; i++) { + if (cipher_kt_block_size(cipher_list[i]) < 128/8) + print_cipher(cipher_list[i]); + } printf ("\n"); } @@ -494,9 +536,37 @@ cipher_kt_iv_size (const EVP_CIPHER *cipher_kt) } int -cipher_kt_block_size (const EVP_CIPHER *cipher_kt) -{ - return EVP_CIPHER_block_size (cipher_kt); +cipher_kt_block_size (const EVP_CIPHER *cipher) { + /* OpenSSL reports OFB/CFB/GCM cipher block sizes as '1 byte'. To work + * around that, try to replace the mode with 'CBC' and return the block size + * reported for that cipher, if possible. If that doesn't work, just return + * the value reported by OpenSSL. + */ + char *name = NULL; + char *mode_str = NULL; + const char *orig_name = NULL; + const EVP_CIPHER *cbc_cipher = NULL; + + int block_size = EVP_CIPHER_block_size(cipher); + + orig_name = cipher_kt_name(cipher); + if (!orig_name) + goto cleanup; + + name = string_alloc(translate_cipher_name_to_openvpn(orig_name), NULL); + mode_str = strrchr (name, '-'); + if (!mode_str || strlen(mode_str) < 4) + goto cleanup; + + strcpy (mode_str, "-CBC"); + + cbc_cipher = EVP_get_cipherbyname(translate_cipher_name_from_openvpn(name)); + if (cbc_cipher) + block_size = EVP_CIPHER_block_size(cbc_cipher); + +cleanup: + free (name); + return block_size; } int diff --git a/tests/t_lpback.sh b/tests/t_lpback.sh index d7792cd379f..2052c626097 100755 --- a/tests/t_lpback.sh +++ b/tests/t_lpback.sh @@ -26,7 +26,7 @@ trap "rm -f key.$$ log.$$ ; exit 1" 0 3 # Get list of supported ciphers from openvpn --show-ciphers output CIPHERS=$(${top_builddir}/src/openvpn/openvpn --show-ciphers | \ - sed -e '1,/^$/d' -e s'/ .*//' -e '/^\s*$/d' | sort) + sed -e '/The following/,/^$/d' -e s'/ .*//' -e '/^\s*$/d') # SK, 2014-06-04: currently the DES-EDE3-CFB1 implementation of OpenSSL is # broken (see http://rt.openssl.org/Ticket/Display.html?id=2867), so exclude From e9d64bc03742c96a3d7fe2a473c43d40e5ba2001 Mon Sep 17 00:00:00 2001 From: Lev Stipakov Date: Mon, 4 Jan 2016 14:43:44 +0200 Subject: [PATCH 288/643] Drop recursively routed packets v2: better method naming On certain OSes (Windows, OS X) when network adapter is disabled (ethernet cable pulled off, Wi-Fi hardware switch disabled), operating system starts to use tun as an external interface. Outgoing packets are routed to tun, UDP encapsulated, given to routing table and sent to.. tun. As a consequence, system starts talking to itself on full power, traffic counters skyrocket and user is not happy. To prevent that, drop packets which have gateway IP as destination address. Tested on Win7/10, OS X. Signed-off-by: Lev Stipakov Trac: 642 Tested-by: ValdikSS Acked-by: Gert Doering Message-Id: <1451911424-12970-1-git-send-email-lstipakov@gmail.com> URL: https://sourceforge.net/p/openvpn/mailman/message/34737757/ Signed-off-by: David Sommerseth --- src/openvpn/forward.c | 63 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c index 6c114391dfd..04f462c1987 100644 --- a/src/openvpn/forward.c +++ b/src/openvpn/forward.c @@ -993,6 +993,68 @@ read_incoming_tun (struct context *c) perf_pop (); } +/** + * Drops UDP packets which OS decided to route via tun. + * + * On Windows and OS X when netwotk adapter is disabled or + * disconnected, platform starts to use tun as external interface. + * When packet is sent to tun, it comes to openvpn, encapsulated + * and sent to routing table, which sends it again to tun. + */ +static void +drop_if_recursive_routing (struct context *c, struct buffer *buf) +{ + bool drop = false; + struct openvpn_sockaddr tun_sa = c->c2.to_link_addr->dest; + + if (is_ipv4 (TUNNEL_TYPE (c->c1.tuntap), buf)) + { + const struct openvpn_iphdr *pip; + + /* make sure we got whole IP header */ + if (BLEN (buf) < (int) sizeof (struct openvpn_iphdr)) + return; + + /* skip ipv4 packets for ipv6 tun */ + if (tun_sa.addr.sa.sa_family != AF_INET) + return; + + pip = (struct openvpn_iphdr *) BPTR (buf); + + /* drop packets with same dest addr as gateway */ + if (tun_sa.addr.in4.sin_addr.s_addr == pip->daddr) + drop = true; + } + else if (is_ipv6 (TUNNEL_TYPE (c->c1.tuntap), buf)) + { + const struct openvpn_ipv6hdr *pip6; + + /* make sure we got whole IPv6 header */ + if (BLEN (buf) < (int) sizeof (struct openvpn_ipv6hdr)) + return; + + /* skip ipv6 packets for ipv4 tun */ + if (tun_sa.addr.sa.sa_family != AF_INET6) + return; + + /* drop packets with same dest addr as gateway */ + pip6 = (struct openvpn_ipv6hdr *) BPTR(buf); + if (IN6_ARE_ADDR_EQUAL(&tun_sa.addr.in6.sin6_addr, &pip6->daddr)) + drop = true; + } + + if (drop) + { + struct gc_arena gc = gc_new (); + + c->c2.buf.len = 0; + + msg(D_LOW, "Recursive routing detected, drop tun packet to %s", + print_link_socket_actual(c->c2.to_link_addr, &gc)); + gc_free (&gc); + } +} + /* * Input: c->c2.buf * Output: c->c2.to_link @@ -1018,6 +1080,7 @@ process_incoming_tun (struct context *c) if (c->c2.buf.len > 0) { + drop_if_recursive_routing (c, &c->c2.buf); /* * The --passtos and --mssfix options require * us to examine the IP header (IPv4 or IPv6). From d90249f73353c175ed9e7dd0a450cd084a729e20 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Mon, 22 Aug 2016 22:24:47 +0200 Subject: [PATCH 289/643] Fix problems with NCP and --inetd. NCP only works with --pull or --mode server, leading to breakage in --inetd mode (because that has --tls-server, but not --mode server, but clients can still ask for PUSH_REQUEST). Fix by turning off o->ncp_enable unless (pull or mode server), and double-fix by logging an appropriate message and refusing to change ciphers if the server has already set up its keys. v2: wrap long msg() text lines Trac: 715 Signed-off-by: Gert Doering Acked-by: Steffan Karger Message-Id: 1471897487-8354-1-git-send-email-gert@greenie.muc.de URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg00060.html Signed-off-by: David Sommerseth --- src/openvpn/options.c | 9 +++++++++ src/openvpn/push.c | 23 ++++++++++++++++++----- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/openvpn/options.c b/src/openvpn/options.c index c100d4ca0f1..e052042f367 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -2614,6 +2614,15 @@ options_postprocess_mutate (struct options *o) if (streq (o->dh_file, "none")) o->dh_file = NULL; } + + /* cipher negotiation (NCP) currently assumes --pull or --mode server */ + if ( o->ncp_enabled && + ! (o->pull || o->mode == MODE_SERVER) ) + { + msg( M_WARN, "disabling NCP mode (--ncp-disable) because not " + "in P2MP client or server mode" ); + o->ncp_enabled = false; + } #endif #if ENABLE_MANAGEMENT diff --git a/src/openvpn/push.c b/src/openvpn/push.c index 000c82f93f3..a1b999e2d97 100644 --- a/src/openvpn/push.c +++ b/src/openvpn/push.c @@ -321,11 +321,24 @@ prepare_push_reply (struct options *o, struct tls_multi *tls_multi) /* Push cipher if client supports Negotiable Crypto Parameters */ if (tls_peer_info_ncp_ver (peer_info) >= 2 && o->ncp_enabled) { - /* Push the first cipher from --ncp-ciphers to the client. - * TODO: actual negotiation, instead of server dictatorship. */ - char *push_cipher = string_alloc(o->ncp_ciphers, &o->gc); - o->ciphername = strtok (push_cipher, ":"); - push_option_fmt(o, M_USAGE, "cipher %s", o->ciphername); + /* if we have already created our key, we cannot change our own + * cipher, so disable NCP and warn = explain why + */ + struct tls_session *session = &tls_multi->session[TM_ACTIVE]; + if ( session->key[KS_PRIMARY].crypto_options.key_ctx_bi.initialized ) + { + msg( M_INFO, "PUSH: client wants to negotiate cipher (NCP), but " + "server has already generated data channel keys, " + "ignoring client request" ); + } + else + { + /* Push the first cipher from --ncp-ciphers to the client. + * TODO: actual negotiation, instead of server dictatorship. */ + char *push_cipher = string_alloc(o->ncp_ciphers, &o->gc); + o->ciphername = strtok (push_cipher, ":"); + push_option_fmt(o, M_USAGE, "cipher %s", o->ciphername); + } } return true; } From 8cba9ffc57739eefa8e56b0738acd1dee2ff2396 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Tue, 23 Aug 2016 21:58:32 +0200 Subject: [PATCH 290/643] Revert "Drop recursively routed packets" This reverts commit e9d64bc03742c96a3d7fe2a473c43d40e5ba2001. It was found that this breaks setups using TAP interfaces and possibly also p2p configurations. Signed-off-by: David Sommerseth --- src/openvpn/forward.c | 63 ------------------------------------------- 1 file changed, 63 deletions(-) diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c index 04f462c1987..6c114391dfd 100644 --- a/src/openvpn/forward.c +++ b/src/openvpn/forward.c @@ -993,68 +993,6 @@ read_incoming_tun (struct context *c) perf_pop (); } -/** - * Drops UDP packets which OS decided to route via tun. - * - * On Windows and OS X when netwotk adapter is disabled or - * disconnected, platform starts to use tun as external interface. - * When packet is sent to tun, it comes to openvpn, encapsulated - * and sent to routing table, which sends it again to tun. - */ -static void -drop_if_recursive_routing (struct context *c, struct buffer *buf) -{ - bool drop = false; - struct openvpn_sockaddr tun_sa = c->c2.to_link_addr->dest; - - if (is_ipv4 (TUNNEL_TYPE (c->c1.tuntap), buf)) - { - const struct openvpn_iphdr *pip; - - /* make sure we got whole IP header */ - if (BLEN (buf) < (int) sizeof (struct openvpn_iphdr)) - return; - - /* skip ipv4 packets for ipv6 tun */ - if (tun_sa.addr.sa.sa_family != AF_INET) - return; - - pip = (struct openvpn_iphdr *) BPTR (buf); - - /* drop packets with same dest addr as gateway */ - if (tun_sa.addr.in4.sin_addr.s_addr == pip->daddr) - drop = true; - } - else if (is_ipv6 (TUNNEL_TYPE (c->c1.tuntap), buf)) - { - const struct openvpn_ipv6hdr *pip6; - - /* make sure we got whole IPv6 header */ - if (BLEN (buf) < (int) sizeof (struct openvpn_ipv6hdr)) - return; - - /* skip ipv6 packets for ipv4 tun */ - if (tun_sa.addr.sa.sa_family != AF_INET6) - return; - - /* drop packets with same dest addr as gateway */ - pip6 = (struct openvpn_ipv6hdr *) BPTR(buf); - if (IN6_ARE_ADDR_EQUAL(&tun_sa.addr.in6.sin6_addr, &pip6->daddr)) - drop = true; - } - - if (drop) - { - struct gc_arena gc = gc_new (); - - c->c2.buf.len = 0; - - msg(D_LOW, "Recursive routing detected, drop tun packet to %s", - print_link_socket_actual(c->c2.to_link_addr, &gc)); - gc_free (&gc); - } -} - /* * Input: c->c2.buf * Output: c->c2.to_link @@ -1080,7 +1018,6 @@ process_incoming_tun (struct context *c) if (c->c2.buf.len > 0) { - drop_if_recursive_routing (c, &c->c2.buf); /* * The --passtos and --mssfix options require * us to examine the IP header (IPv4 or IPv6). From ee4f37c3533667aee87fd39ba131e80f3c1cfde7 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Mon, 15 Aug 2016 20:02:36 +0200 Subject: [PATCH 291/643] Fix unittests for out-of-source builds Signed-off-by: Steffan Karger Acked-by: Matthias Andree Message-Id: 1471284156-2324-1-git-send-email-steffan@karger.me URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg00027.html Signed-off-by: David Sommerseth --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 4f14ebd006a..9189c94e526 100644 --- a/configure.ac +++ b/configure.ac @@ -1215,7 +1215,7 @@ AC_SUBST([TEST_CFLAGS]) # needed for unit testing AC_CHECK_PROGS([CMAKE], [cmake]) if test -n "${CMAKE}"; then - if test -f vendor/cmocka/CMakeLists.txt; then + if test -f "${srcdir}/vendor/cmocka/CMakeLists.txt"; then AM_CONDITIONAL([CMOCKA_INITIALIZED], [true]) else AM_CONDITIONAL([CMOCKA_INITIALIZED], [false]) From bde1b90da0db2d68d13d274102986f0ca7096c00 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Tue, 12 Jul 2016 11:14:08 +0200 Subject: [PATCH 292/643] Use AES ciphers in our sample configuration files and add a few modern 2.4 examples [ DS: Fixed typos and removed added extra blank line, all commented by Steffan ] Acked-by: Steffan Karger Message-Id: 1468314848-11820-1-git-send-email-arne@rfc2549.org URL: http://www.mail-archive.com/search?l=mid&q=1468314848-11820-1-git-send-email-arne@rfc2549.org Signed-off-by: David Sommerseth --- sample/sample-config-files/client.conf | 7 ++++-- sample/sample-config-files/server.conf | 23 ++++++++++++++----- sample/sample-config-files/static-home.conf | 3 +++ sample/sample-config-files/static-office.conf | 3 +++ 4 files changed, 28 insertions(+), 8 deletions(-) diff --git a/sample/sample-config-files/client.conf b/sample/sample-config-files/client.conf index fedcbd6e8dc..f5c69e34ba5 100644 --- a/sample/sample-config-files/client.conf +++ b/sample/sample-config-files/client.conf @@ -110,12 +110,15 @@ tls-auth ta.key 1 # Select a cryptographic cipher. # If the cipher option is used on the server # then you must also specify it here. -;cipher x +# Note that 2.4 client/server will automatically +# negotiate AES-256-GCM in TLS mode. +# See also the ncp-cipher option in the manpage +cipher AES-256-CBC # Enable compression on the VPN link. # Don't enable this unless it is also # enabled in the server config file. -comp-lzo +#comp-lzo # Set log file verbosity. verb 3 diff --git a/sample/sample-config-files/server.conf b/sample/sample-config-files/server.conf index c85ca0ffdb0..aa7d5b39a43 100644 --- a/sample/sample-config-files/server.conf +++ b/sample/sample-config-files/server.conf @@ -246,14 +246,21 @@ tls-auth ta.key 0 # This file is secret # Select a cryptographic cipher. # This config item must be copied to # the client config file as well. -;cipher BF-CBC # Blowfish (default) -;cipher AES-128-CBC # AES -;cipher DES-EDE3-CBC # Triple-DES - -# Enable compression on the VPN link. +# Note that 2.4 client/server will automatically +# negotiate AES-256-GCM in TLS mode. +# See also the ncp-cipher option in the manpage +cipher AES-256-CBC + +# Enable compression on the VPN link and push the +# option to the client (2.4+ only, for earlier +# versions see below) +;compress lz4-v2 +;push "compress lz4-v2" + +# For compression compatible with older clients use comp-lzo # If you enable it here, you must also # enable it in the client config file. -comp-lzo +;comp-lzo # The maximum number of concurrently connected # clients we want to allow. @@ -302,3 +309,7 @@ verb 3 # sequential messages of the same message # category will be output to the log. ;mute 20 + +# Notify the client that when the server restarts so it +# can automatically reconnect. +explicit-exit-notify 1 \ No newline at end of file diff --git a/sample/sample-config-files/static-home.conf b/sample/sample-config-files/static-home.conf index c9666874668..ed0c6726395 100644 --- a/sample/sample-config-files/static-home.conf +++ b/sample/sample-config-files/static-home.conf @@ -26,6 +26,9 @@ up ./home.up # Our pre-shared static key secret static.key +# Cipher to use +cipher AES-256-CBC + # OpenVPN 2.0 uses UDP port 1194 by default # (official port assignment by iana.org 11/04). # OpenVPN 1.x uses UDP port 5000 by default. diff --git a/sample/sample-config-files/static-office.conf b/sample/sample-config-files/static-office.conf index 68030cc944d..609ddd02f58 100644 --- a/sample/sample-config-files/static-office.conf +++ b/sample/sample-config-files/static-office.conf @@ -23,6 +23,9 @@ up ./office.up # Our pre-shared static key secret static.key +# Cipher to use +cipher AES-256-CBC + # OpenVPN 2.0 uses UDP port 1194 by default # (official port assignment by iana.org 11/04). # OpenVPN 1.x uses UDP port 5000 by default. From b3e975824ea9ebae8dbea5b451c8d02525c83ffe Mon Sep 17 00:00:00 2001 From: James Yonan Date: Thu, 3 Mar 2016 01:19:06 -0700 Subject: [PATCH 293/643] Bind to local socket before dropping privileges Bind the local TCP/UDP socket before UID/GID downgrade, otherwise we cannot bind to ports < 1024. Signed-off-by: James Yonan Acked-by: David Sommerseth Message-Id: 1456993146-63968-10-git-send-email-james@openvpn.net URL: http://www.mail-archive.com/search?l=mid&q=1456993146-63968-10-git-send-email-james@openvpn.net Signed-off-by: David Sommerseth --- src/openvpn/init.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 87a0e32b21d..ad4ebc33d6d 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -3696,6 +3696,10 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int open_plugins (c, false, OPENVPN_PLUGIN_INIT_POST_DAEMON); #endif + /* finalize the TCP/UDP socket */ + if (c->mode == CM_P2P || c->mode == CM_TOP || c->mode == CM_CHILD_TCP) + do_init_socket_2 (c); + /* * Actually do UID/GID downgrade, and chroot, if requested. * May be delayed by --client, --pull, or --up-delay. @@ -3705,10 +3709,6 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int /* initialise connect timeout timer */ do_init_server_poll_timeout(c); - /* finalize the TCP/UDP socket */ - if (c->mode == CM_P2P || c->mode == CM_TOP || c->mode == CM_CHILD_TCP) - do_init_socket_2 (c); - /* initialize timers */ if (c->mode == CM_P2P || child) do_init_timers (c, false); From 4db062901fba790ac35cbf0cdd360306d8f2b81f Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Thu, 25 Aug 2016 22:42:03 +0200 Subject: [PATCH 294/643] Fix client connection instant timeout Commit b3e975824ea9ebae8dbea5b451c8d02525c83ffe moved the finalizing of TCP/UDP sockets before the UID/GID where dropped. But this did not factor that the timeout code had been revamped [1] in the mean time. This ensures the timout initialization is done before the the socket finalizing has been completed. [1] commit f2134b7bea37df15756c599b94f16d4bffafbbd6 Signed-off-by: David Sommerseth Acked-by: Gert Doering Message-Id: 1472162097-17855-1-git-send-email-davids@openvpn.net URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg00125.html --- src/openvpn/init.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/openvpn/init.c b/src/openvpn/init.c index ad4ebc33d6d..5b6d2468436 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -3696,6 +3696,9 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int open_plugins (c, false, OPENVPN_PLUGIN_INIT_POST_DAEMON); #endif + /* initialise connect timeout timer */ + do_init_server_poll_timeout(c); + /* finalize the TCP/UDP socket */ if (c->mode == CM_P2P || c->mode == CM_TOP || c->mode == CM_CHILD_TCP) do_init_socket_2 (c); @@ -3706,9 +3709,6 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int */ do_uid_gid_chroot (c, c->c2.did_open_tun); - /* initialise connect timeout timer */ - do_init_server_poll_timeout(c); - /* initialize timers */ if (c->mode == CM_P2P || child) do_init_timers (c, false); From cbc3c5a9831b44ec7f59e8cb21e19ea364e6c0ee Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sat, 10 Sep 2016 08:11:12 +0200 Subject: [PATCH 295/643] Fix --mssfix when using NCP As reported in trac #716, cipher negotiation (NCP) broke --mssfix. This patch now also restores the mssfix value after the crypto negotiation. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1473487872-13119-1-git-send-email-steffan@karger.me> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12436.html Signed-off-by: Gert Doering --- src/openvpn/init.c | 15 +-------------- src/openvpn/mtu.c | 10 ++++++++++ src/openvpn/mtu.h | 6 ++++++ src/openvpn/ssl.c | 1 + 4 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 5b6d2468436..c4d904de7db 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -2808,19 +2808,6 @@ do_init_fragment (struct context *c) } #endif -/* - * Set the --mssfix option. - */ -static void -do_init_mssfix (struct context *c) -{ - if (c->options.ce.mssfix) - { - frame_set_mtu_dynamic (&c->c2.frame, - c->options.ce.mssfix, SET_MTU_UPPER_BOUND); - } -} - /* * Allocate our socket object. */ @@ -3663,7 +3650,7 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int #endif /* initialize dynamic MTU variable */ - do_init_mssfix (c); + frame_init_mssfix (&c->c2.frame, &c->options); /* bind the TCP/UDP socket */ if (c->mode == CM_P2P || c->mode == CM_TOP || c->mode == CM_CHILD_TCP) diff --git a/src/openvpn/mtu.c b/src/openvpn/mtu.c index 64d1cf3c5a7..8cbaa863b65 100644 --- a/src/openvpn/mtu.c +++ b/src/openvpn/mtu.c @@ -35,6 +35,7 @@ #include "error.h" #include "integer.h" #include "mtu.h" +#include "options.h" #include "memdbg.h" @@ -124,6 +125,15 @@ frame_subtract_extra (struct frame *frame, const struct frame *src) frame->extra_tun += src->extra_frame; } +void +frame_init_mssfix (struct frame *frame, const struct options *options) +{ + if (options->ce.mssfix) + { + frame_set_mtu_dynamic (frame, options->ce.mssfix, SET_MTU_UPPER_BOUND); + } +} + void frame_print (const struct frame *frame, int level, diff --git a/src/openvpn/mtu.h b/src/openvpn/mtu.h index f94de89b73c..0320545b15c 100644 --- a/src/openvpn/mtu.h +++ b/src/openvpn/mtu.h @@ -135,6 +135,9 @@ struct frame { int align_adjust; }; +/* Forward declarations, to prevent includes */ +struct options; + /* Routines which read struct frame should use the macros below */ /* @@ -227,6 +230,9 @@ void alloc_buf_sock_tun (struct buffer *buf, const bool tuntap_buffer, const unsigned int align_mask); +/** Set the --mssfix option. */ +void frame_init_mssfix (struct frame *frame, const struct options *options); + /* * EXTENDED_SOCKET_ERROR_CAPABILITY functions -- print extra error info * on socket errors, such as PMTU size. As of 2003.05.11, only works diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index a220b79a541..caf3b1f6264 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -1691,6 +1691,7 @@ tls_session_update_crypto_params(struct tls_session *session, options->use_iv, options->replay, packet_id_long_form); frame_finalize(frame, options->ce.link_mtu_defined, options->ce.link_mtu, options->ce.tun_mtu_defined, options->ce.tun_mtu); + frame_init_mssfix(frame, options); frame_print (frame, D_MTU_INFO, "Data Channel MTU parms"); const struct session_id *client_sid = session->opt->server ? From 058f0efdec63aba911addee9ab205382c4762d06 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Thu, 1 Sep 2016 22:14:30 +0200 Subject: [PATCH 296/643] Drop gnu89/c89 support, switch to c99 Previously, we would use the compiler's default C version, which defaults to gnu89 for GCC < 5, gnu11 for GCC > 5, and c11 for clang, but might even differ per distro. One of the reasons to accept the gnu89 default of GCC < 4.9, was that MSVC didn't support c99. But in MSVC 2015, MS finanally fixed that. Having to support c89 in the codebase occasionally forces us to write less readable code, for example by forcing all declaration to be at the starting of a block (which includes 'for loop initial declarations'). Let's be clear about what standard we obey, and stop punishing ourselves with c89/gnu89. Let's switch the master branch to c99. v2: don't try to detect pedantic mode based on __STRICT_ANSI__, since that will be defined when using -std=c99. v3: only set -std=c99 if there is no -std= already present in CFLAGS Signed-off-by: Steffan Karger Acked-by: David Sommerseth Message-Id: 1472760870-11769-1-git-send-email-steffan@karger.me URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg00194.html Signed-off-by: David Sommerseth --- configure.ac | 8 +++++++- src/openvpn/syshead.h | 5 +---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index 9189c94e526..5c5cdf841ab 100644 --- a/configure.ac +++ b/configure.ac @@ -1125,10 +1125,16 @@ if test "${enable_pkcs11}" = "yes"; then ) fi +# Set -std=c99 unless user already specified a -std= +case "${CFLAGS}" in + *-std=*) ;; + *) CFLAGS="${CFLAGS} -std=c99" ;; +esac + if test "${enable_pedantic}" = "yes"; then enable_strict="yes" CFLAGS="${CFLAGS} -pedantic" - test "${WIN32}" != "yes" && CFLAGS="${CFLAGS} -std=c99" + AC_DEFINE([PEDANTIC], [1], [Enable pedantic mode]) fi if test "${enable_strict}" = "yes"; then CFLAGS="${CFLAGS} -Wall -Wno-unused-parameter -Wno-unused-function" diff --git a/src/openvpn/syshead.h b/src/openvpn/syshead.h index c8391ca3bea..e969ccfa635 100644 --- a/src/openvpn/syshead.h +++ b/src/openvpn/syshead.h @@ -384,16 +384,13 @@ * Pedantic mode is meant to accomplish lint-style program checking, * not to build a working executable. */ -#ifdef __STRICT_ANSI__ -# define PEDANTIC 1 +#ifdef PEDANTIC # undef HAVE_CPP_VARARG_MACRO_GCC # undef HAVE_CPP_VARARG_MACRO_ISO # undef EMPTY_ARRAY_SIZE # define EMPTY_ARRAY_SIZE 1 # undef inline # define inline -#else -# define PEDANTIC 0 #endif /* From a7b02f7f660707f765881f35867b4d23d89b390f Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Tue, 13 Sep 2016 22:04:58 +0200 Subject: [PATCH 297/643] Do not abort t_client run if OpenVPN instance does not start. Basically, an oversight - if one test instance does not start at all (due to "tap driver not loaded") the whole script would exit, instead of logging the failing instance and proceeding to the next test run. Signed-off-by: Gert Doering Acked-by: David Sommerseth Message-Id: 20160913200458.9906-1-gert@greenie.muc.de URL: http://www.mail-archive.com/search?l=mid&q=20160913200458.9906-1-gert@greenie.muc.de Signed-off-by: David Sommerseth --- tests/t_client.sh.in | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tests/t_client.sh.in b/tests/t_client.sh.in index 9a0af93a0d1..62d67307107 100755 --- a/tests/t_client.sh.in +++ b/tests/t_client.sh.in @@ -279,10 +279,14 @@ do if $RUN_SUDO kill -0 $opid then : else - echo -e "OpenVPN process has failed to start up, check log ($LOGDIR/$SUF:openvpn.log). FAIL.\ntail of logfile follows:\n..." >&2 - tail $LOGDIR/$SUF:openvpn.log >&2 + fail "OpenVPN process has failed to start up, check log ($LOGDIR/$SUF:openvpn.log)." + echo "tail -5 $SUF:openvpn.log" >&2 + tail -5 $LOGDIR/$SUF:openvpn.log >&2 + echo -e "\nFAIL. skip rest of sub-tests for test run $SUF.\n" >&2 trap - 0 1 2 3 15 - exit 10 + SUMMARY_FAIL="$SUMMARY_FAIL $SUF" + exit_code=30 + continue fi # compare whether anything changed in ifconfig/route setup? From d7ce876841d1d5b01940251f92780fdbb05b4df0 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Thu, 1 Sep 2016 21:13:27 +0200 Subject: [PATCH 298/643] cleanup: remove code duplication in msg_test() Use check_debug_level() instead of writing out the exact same check in msg_test(). Signed-off-by: Steffan Karger Acked-by: David Sommerseth Message-Id: 1472757207-17900-1-git-send-email-steffan@karger.me URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg00192.html Signed-off-by: David Sommerseth --- src/openvpn/error.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/openvpn/error.h b/src/openvpn/error.h index 76515d6e07a..ced2fdfff9c 100644 --- a/src/openvpn/error.h +++ b/src/openvpn/error.h @@ -138,12 +138,6 @@ extern int x_msg_line_num; /** Check muting filter */ bool dont_mute (unsigned int flags); -/** Return true if flags represent an enabled, not muted log level */ -static inline bool msg_test (unsigned int flags) -{ - return ((flags & M_DEBUG_LEVEL) <= x_debug_level) && dont_mute (flags); -} - /* Macro to ensure (and teach static analysis tools) we exit on fatal errors */ #define EXIT_FATAL(flags) do { if ((flags) & M_FATAL) _exit(1); } while (false) @@ -237,6 +231,12 @@ check_debug_level (unsigned int level) return (level & M_DEBUG_LEVEL) <= x_debug_level; } +/** Return true if flags represent an enabled, not muted log level */ +static inline bool msg_test (unsigned int flags) +{ + return check_debug_level (flags) && dont_mute (flags); +} + /* Call if we forked */ void msg_forked (void); From 368991264d82f038bde30a67910ac6c7681a4ba9 Mon Sep 17 00:00:00 2001 From: Ilya Shipitsin Date: Thu, 15 Sep 2016 16:26:48 +0500 Subject: [PATCH 299/643] initial travis-ci support including refactoring by Steffan Karger, merged into a single commit. Acked-by: Gert Doering Message-Id: <1473938808-3312-1-git-send-email-chipitsine@gmail.com> URL: http://www.mail-archive.com/search?l=mid&q=1473938808-3312-1-git-send-email-chipitsine@gmail.com Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1473938818-3375-1-git-send-email-chipitsine@gmail.com> URL: http://www.mail-archive.com/search?l=mid&q=1473938818-3375-1-git-send-email-chipitsine@gmail.com Signed-off-by: Gert Doering --- .travis.yml | 90 ++++++++++++++++++++++++++++++++++ .travis/build-deps.sh | 85 ++++++++++++++++++++++++++++++++ .travis/build-mbedtls-linux.sh | 9 ++++ .travis/build-mbedtls-osx.sh | 9 ++++ .travis/build-openssl-linux.sh | 12 +++++ .travis/build-openssl-osx.sh | 11 +++++ 6 files changed, 216 insertions(+) create mode 100644 .travis.yml create mode 100755 .travis/build-deps.sh create mode 100755 .travis/build-mbedtls-linux.sh create mode 100755 .travis/build-mbedtls-osx.sh create mode 100755 .travis/build-openssl-linux.sh create mode 100755 .travis/build-openssl-osx.sh diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000000..452c48e7f12 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,90 @@ +sudo: required +dist: trusty + +os: linux + +language: c + +compiler: + - gcc + +env: + global: + - JOBS=3 + - PREFIX="${HOME}/opt" + - MBEDTLS_VERSION="2.2.1" + - MBEDTLS_CFLAGS="-I${PREFIX}/include" + - MBEDTLS_LIBS="-L${PREFIX}/lib -lmbedtls -lmbedx509 -lmbedcrypto" + - OPENSSL_VERSION="1.0.1t" + - OPENSSL_CFLAGS="-I${PREFIX}/include" + - OPENSSL_LIBS="-L${PREFIX}/lib -lssl -lcrypto" + - LD_LIBRARY_PATH="${PREFIX}/lib:${LD_LIBRARY_PATH}" + +matrix: + include: + - env: SSLLIB="openssl" + os: linux + compiler: gcc + - env: SSLLIB="openssl" + os: linux + compiler: clang + - env: SSLLIB="mbedtls" + os: linux + compiler: gcc + - env: SSLLIB="mbedtls" + os: linux + compiler: clang + - env: SSLLIB="openssl" EXTRA_CONFIG="--disable-crypto" + os: linux + compiler: clang + - env: SSLLIB="openssl" EXTRA_CONFIG="--disable-lzo" + os: linux + compiler: clang + - env: SSLLIB="openssl" EXTRA_CONFIG="--enable-small" + os: linux + compiler: clang + - env: SSLLIB="openssl" + os: osx + osx_image: xcode7.3 + compiler: clang + - env: SSLLIB="mbedtls" + os: osx + osx_image: xcode7.3 + compiler: clang + allow_failures: + - env: SSLLIB="openssl" EXTRA_CONFIG="--disable-crypto" + os: linux + compiler: clang + exclude: + - compiler: gcc + +addons: + apt: + packages: + - liblzo2-dev + - libpam0g-dev + - liblz4-dev + - linux-libc-dev + +cache: + apt: true + ccache: true + directories: + - download-cache + - ${HOME}/opt + +before_install: + - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then brew update ; fi + - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then brew install lzo; fi + +install: + - .travis/build-deps.sh > build-deps.log 2>&1 || (cat build-deps.log && exit 1) + +script: + - autoreconf -vi + - ./configure --with-crypto-library="${SSLLIB}" ${EXTRA_CONFIG} || (cat config.log && exit 1) + - make -j$JOBS + - src/openvpn/openvpn --version || true + - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ldd src/openvpn/openvpn; fi + - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then otool -L src/openvpn/openvpn; fi + - make check diff --git a/.travis/build-deps.sh b/.travis/build-deps.sh new file mode 100755 index 00000000000..bda54eea394 --- /dev/null +++ b/.travis/build-deps.sh @@ -0,0 +1,85 @@ +#!/bin/sh +set -eux + +# Set defaults +MBEDTLS_VERSION="${MBEDTLS_VERSION:-2.2.1}" +OPENSSL_VERSION="${OPENSSL_VERION:-1.0.2h}" +PREFIX="${PREFIX:-${HOME}/opt}" + +download_mbedtls () { + if [ ! -f "download-cache/mbedtls-${MBEDTLS_VERSION}-apache.tgz" ]; then + wget -P download-cache/ \ + "https://tls.mbed.org/download/mbedtls-${MBEDTLS_VERSION}-apache.tgz" + fi +} + +build_mbedtls () { + if [ "$(cat ${PREFIX}/.mbedtls-version)" != "${MBEDTLS_VERSION}" ]; then + tar zxf download-cache/mbedtls-${MBEDTLS_VERSION}-apache.tgz + ( + cd "mbedtls-${MBEDTLS_VERSION}" + make + make install DESTDIR="${PREFIX}" + ) + echo "${MBEDTLS_VERSION}" > "${PREFIX}/.mbedtls-version" + fi +} + +download_openssl () { + if [ ! -f "download-cache/openssl-${OPENSSL_VERSION}.tar.gz" ]; then + wget -P download-cache/ \ + "https://www.openssl.org/source/openssl-${OPENSSL_VERSION}.tar.gz" + fi +} + +build_openssl_linux () { + tar zxf "download-cache/openssl-${OPENSSL_VERSION}.tar.gz" + ( + cd "openssl-${OPENSSL_VERSION}/" + ./config shared --openssldir="${PREFIX}" -DPURIFY + make all install_sw + ) +} + +build_openssl_osx () { + tar zxf "download-cache/openssl-${OPENSSL_VERSION}.tar.gz" + ( + cd "openssl-${OPENSSL_VERSION}/" + ./Configure darwin64-x86_64-cc shared \ + --openssldir="${PREFIX}" -DPURIFY + make depend all install_sw + ) +} + +build_openssl () { + if [ "$(cat ${PREFIX}/.openssl-version)" != "${OPENSSL_VERSION}" ]; then + if [ "${TRAVIS_OS_NAME}" = "osx" ]; then + build_openssl_osx + elif [ "${TRAVIS_OS_NAME}" = "linux" ]; then + build_openssl_linux + fi + echo "${OPENSSL_VERSION}" > "${PREFIX}/.openssl-version" + fi +} + +# Enable ccache +if [ "${TRAVIS_OS_NAME}" != "osx" ]; then + # ccache not available on osx, see: + # https://github.com/travis-ci/travis-ci/issues/5567 + mkdir -p "${HOME}/bin" + ln -s "$(which ccache)" "${HOME}/bin/${CC}" + PATH="${HOME}/bin:${PATH}" +fi + +# Download and build crypto lib +mkdir -p download-cache +if [ "${SSLLIB}" = "openssl" ]; then + download_openssl + build_openssl +elif [ "${SSLLIB}" = "mbedtls" ]; then + download_mbedtls + build_mbedtls +else + echo "Invalid crypto lib: ${SSLLIB}" + exit 1 +fi diff --git a/.travis/build-mbedtls-linux.sh b/.travis/build-mbedtls-linux.sh new file mode 100755 index 00000000000..dc92aafe6af --- /dev/null +++ b/.travis/build-mbedtls-linux.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +if [ ! -f download-cache/mbedtls-${MBEDTLS_VERSION}-apache.tgz ]; then + wget -O download-cache/mbedtls-${MBEDTLS_VERSION}-apache.tgz https://tls.mbed.org/download/mbedtls-${MBEDTLS_VERSION}-apache.tgz; +fi + +tar zxf download-cache/mbedtls-${MBEDTLS_VERSION}-apache.tgz +cd mbedtls-${MBEDTLS_VERSION} && make > build.log 2>&1 || (cat build.log && exit 1) +make install DESTDIR=$MBEDTLS_PREFIX && cd .. diff --git a/.travis/build-mbedtls-osx.sh b/.travis/build-mbedtls-osx.sh new file mode 100755 index 00000000000..dc92aafe6af --- /dev/null +++ b/.travis/build-mbedtls-osx.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +if [ ! -f download-cache/mbedtls-${MBEDTLS_VERSION}-apache.tgz ]; then + wget -O download-cache/mbedtls-${MBEDTLS_VERSION}-apache.tgz https://tls.mbed.org/download/mbedtls-${MBEDTLS_VERSION}-apache.tgz; +fi + +tar zxf download-cache/mbedtls-${MBEDTLS_VERSION}-apache.tgz +cd mbedtls-${MBEDTLS_VERSION} && make > build.log 2>&1 || (cat build.log && exit 1) +make install DESTDIR=$MBEDTLS_PREFIX && cd .. diff --git a/.travis/build-openssl-linux.sh b/.travis/build-openssl-linux.sh new file mode 100755 index 00000000000..84f4aaeba04 --- /dev/null +++ b/.travis/build-openssl-linux.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +if [ ! -f download-cache/openssl-${OPENSSL_VERSION}.tar.gz ]; then + wget -O download-cache/openssl-${OPENSSL_VERSION}.tar.gz https://www.openssl.org/source/openssl-${OPENSSL_VERSION}.tar.gz; +fi + +tar zxf download-cache/openssl-${OPENSSL_VERSION}.tar.gz +cd openssl-${OPENSSL_VERSION}/ +./config shared --prefix=$OPENSSL_PREFIX -DPURIFY > build.log 2>&1 || (cat build.log && exit 1) +make > build.log 2>&1 || (cat build.log && exit 1) +make install_sw > build.log 2>&1 || (cat build.log && exit 1) +cd .. diff --git a/.travis/build-openssl-osx.sh b/.travis/build-openssl-osx.sh new file mode 100755 index 00000000000..61c80168ab9 --- /dev/null +++ b/.travis/build-openssl-osx.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +if [ ! -f download-cache/openssl-${OPENSSL_VERSION}.tar.gz ]; then + wget -O download-cache/openssl-${OPENSSL_VERSION}.tar.gz https://www.openssl.org/source/openssl-${OPENSSL_VERSION}.tar.gz; +fi + +tar zxf download-cache/openssl-${OPENSSL_VERSION}.tar.gz +cd openssl-${OPENSSL_VERSION}/ +./Configure darwin64-x86_64-cc shared --prefix=$OPENSSL_PREFIX -DPURIFY > build.log 2>&1 || (cat build.log && exit 1) +make depend install > build.log 2>&1 || (cat build.log && exit 1) +cd .. From e0926ebfe55347843af701216be9598827a1367a Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Sat, 17 Sep 2016 12:20:26 +0300 Subject: [PATCH 300/643] t_client.sh: Make OpenVPN write PID file to avoid various sudo issues This resolves an issue where $! returns the PID of the sudo process instead of the PID of OpenVPN and when sudo does not properly propagate signales down to OpenVPN. Trac: #738 Signed-off-by: David Sommerseth Acked-by: Gert Doering Message-Id: <1474104026-20615-1-git-send-email-davids@openvpn.net> URL: http://www.mail-archive.com/search?l=mid&q=1474104026-20615-1-git-send-email-davids@openvpn.net Signed-off-by: Gert Doering --- tests/t_client.sh.in | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/t_client.sh.in b/tests/t_client.sh.in index 62d67307107..fc82cdb7b71 100755 --- a/tests/t_client.sh.in +++ b/tests/t_client.sh.in @@ -263,10 +263,14 @@ do continue fi + pidfile="${top_builddir}/tests/$LOGDIR/openvpn-$SUF.pid" + openvpn_conf="$openvpn_conf --writepid $pidfile" echo " run openvpn $openvpn_conf" echo "# src/openvpn/openvpn $openvpn_conf" >$LOGDIR/$SUF:openvpn.log $RUN_SUDO "${top_builddir}/src/openvpn/openvpn" $openvpn_conf >>$LOGDIR/$SUF:openvpn.log & - opid=$! + sleep 3 # Wait for OpenVPN to initialize and have had time to write the pid file + opid=`cat $pidfile` + echo " OpenVPN running with PID $opid" # make sure openvpn client is terminated in case shell exits trap "$RUN_SUDO kill $opid" 0 From a85ba0e06badf9932e80deb53b68f50611943c6e Mon Sep 17 00:00:00 2001 From: Ilya Shipitsin Date: Sat, 17 Sep 2016 14:33:09 +0500 Subject: [PATCH 301/643] skip t_lpback.sh and t_cltsrv.sh if openvpn configured --disable-crypto Acked-by: Steffan Karger Message-Id: <1474104789-31735-1-git-send-email-chipitsine@gmail.com> URL: http://www.mail-archive.com/search?l=mid&q=1474104789-31735-1-git-send-email-chipitsine@gmail.com Signed-off-by: Gert Doering --- configure.ac | 1 + tests/Makefile.am | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 5c5cdf841ab..f21c37a3e34 100644 --- a/configure.ac +++ b/configure.ac @@ -1198,6 +1198,7 @@ AM_CONDITIONAL([WIN32], [test "${WIN32}" = "yes"]) AM_CONDITIONAL([GIT_CHECKOUT], [test "${GIT_CHECKOUT}" = "yes"]) AM_CONDITIONAL([ENABLE_PLUGIN_AUTH_PAM], [test "${enable_plugin_auth_pam}" = "yes"]) AM_CONDITIONAL([ENABLE_PLUGIN_DOWN_ROOT], [test "${enable_plugin_down_root}" = "yes"]) +AM_CONDITIONAL([ENABLE_CRYPTO], [test "${enable_crypto}" = "yes"]) plugindir="${with_plugindir}" sampledir="\$(docdir)/sample" diff --git a/tests/Makefile.am b/tests/Makefile.am index 2cba9e66d63..235cd1328a9 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -14,7 +14,10 @@ MAINTAINERCLEANFILES = \ SUBDIRS = unit_tests -test_scripts = t_client.sh t_lpback.sh t_cltsrv.sh +test_scripts = t_client.sh +if ENABLE_CRYPTO +test_scripts += t_lpback.sh t_cltsrv.sh +endif TESTS_ENVIRONMENT = top_srcdir="$(top_srcdir)" TESTS = $(test_scripts) From 7efa60d9790e029b8f9efd6a0ca06312d31d3420 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Fri, 16 Sep 2016 21:02:42 +0200 Subject: [PATCH 302/643] Fix IP_PKTINFO related compilation failure on NetBSD 7.0 NetBSD has introduced IP_PKTINFO and struct in_pktinfo, but does not have the "ipi_spec_dst" structure element, causing compilation errors. Introduce a check for that (AC_CHECK_MEMBER) in configure.ac, and change all "#ifdef HAVE_IN_PKTINFO" to also check "HAVE_IPI_SPEC_DST". Patch inspired by NetBSD pkgsrc patch set. (Note: with that patch, OpenVPN --multihome is still broken for IPv4 on NetBSD 7.0.1 / amd64, but that's a different issue) Signed-off-by: Gert Doering Acked-by: Arne Schwabe Message-Id: <20160916190242.44897-1-gert@greenie.muc.de> URL: http://www.mail-archive.com/search?l=mid&q=20160916190242.44897-1-gert@greenie.muc.de Signed-off-by: Gert Doering --- configure.ac | 9 +++++++++ src/openvpn/init.c | 2 +- src/openvpn/socket.c | 12 ++++++------ src/openvpn/socket.h | 4 ++-- 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/configure.ac b/configure.ac index f21c37a3e34..2d578f41d76 100644 --- a/configure.ac +++ b/configure.ac @@ -455,6 +455,9 @@ SOCKET_INCLUDES=" #ifdef HAVE_SYS_SOCKET_H #include #endif +#ifdef HAVE_NET_IF_H +#include +#endif #ifdef HAVE_NETINET_IN_H #include #endif @@ -524,6 +527,12 @@ AC_CHECK_TYPE( , [[${SOCKET_INCLUDES}]] ) +AC_CHECK_MEMBER( + [struct in_pktinfo.ipi_spec_dst], + [AC_DEFINE([HAVE_IPI_SPEC_DST], [1], [struct in_pktinfo.ipi_spec_dst needed for IP_PKTINFO support])], + , + [[${SOCKET_INCLUDES}]] +) AC_CHECK_TYPE( [struct sockaddr_in6], , diff --git a/src/openvpn/init.c b/src/openvpn/init.c index c4d904de7db..45ce025ee52 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -1299,7 +1299,7 @@ initialization_sequence_completed (struct context *c, const unsigned int flags) switch (local.addr.sa.sa_family) { case AF_INET: -#ifdef IP_PKTINFO +#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) local.addr.in4.sin_addr = actual->pi.in4.ipi_spec_dst; #else local.addr.in4.sin_addr = actual->pi.in4; diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c index 0ea4a3d07ee..e0961323270 100644 --- a/src/openvpn/socket.c +++ b/src/openvpn/socket.c @@ -790,7 +790,7 @@ create_socket_udp (struct addrinfo* addrinfo, const unsigned int flags) int pad = 1; if(addrinfo->ai_family == AF_INET) { -#ifdef IP_PKTINFO +#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) if (setsockopt (sd, SOL_IP, IP_PKTINFO, (void*)&pad, sizeof(pad)) < 0) msg(M_ERR, "UDP: failed setsockopt for IP_PKTINFO"); @@ -2465,7 +2465,7 @@ print_link_socket_actual_ex (const struct link_socket_actual *act, struct openvpn_sockaddr sa; CLEAR (sa); sa.addr.in4.sin_family = AF_INET; -#ifdef IP_PKTINFO +#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) sa.addr.in4.sin_addr = act->pi.in4.ipi_spec_dst; if_indextoname(act->pi.in4.ipi_ifindex, ifname); #elif defined(IP_RECVDSTADDR) @@ -2867,7 +2867,7 @@ link_socket_read_tcp (struct link_socket *sock, struct openvpn_in4_pktinfo { struct cmsghdr cmsghdr; -#ifdef HAVE_IN_PKTINFO +#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) struct in_pktinfo pi4; #elif defined(IP_RECVDSTADDR) struct in_addr pi4; @@ -2911,7 +2911,7 @@ link_socket_read_udp_posix_recvmsg (struct link_socket *sock, cmsg = CMSG_FIRSTHDR (&mesg); if (cmsg != NULL && CMSG_NXTHDR (&mesg, cmsg) == NULL -#ifdef IP_PKTINFO +#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) && cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_PKTINFO #elif defined(IP_RECVDSTADDR) @@ -2922,7 +2922,7 @@ link_socket_read_udp_posix_recvmsg (struct link_socket *sock, #endif && cmsg->cmsg_len >= sizeof (struct openvpn_in4_pktinfo)) { -#ifdef IP_PKTINFO +#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) struct in_pktinfo *pkti = (struct in_pktinfo *) CMSG_DATA (cmsg); from->pi.in4.ipi_ifindex = pkti->ipi_ifindex; from->pi.in4.ipi_spec_dst = pkti->ipi_spec_dst; @@ -3021,7 +3021,7 @@ link_socket_write_udp_posix_sendmsg (struct link_socket *sock, mesg.msg_namelen = sizeof (struct sockaddr_in); mesg.msg_control = &opi; mesg.msg_flags = 0; -#ifdef HAVE_IN_PKTINFO +#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) mesg.msg_controllen = sizeof (struct openvpn_in4_pktinfo); cmsg = CMSG_FIRSTHDR (&mesg); cmsg->cmsg_len = sizeof (struct openvpn_in4_pktinfo); diff --git a/src/openvpn/socket.h b/src/openvpn/socket.h index 66824c7e2e7..e1607f4e736 100644 --- a/src/openvpn/socket.h +++ b/src/openvpn/socket.h @@ -90,7 +90,7 @@ struct link_socket_actual struct openvpn_sockaddr dest; #if ENABLE_IP_PKTINFO union { -#ifdef HAVE_IN_PKTINFO +#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) struct in_pktinfo in4; #elif defined(IP_RECVDSTADDR) struct in_addr in4; @@ -626,7 +626,7 @@ addr_defined_ipi (const struct link_socket_actual *lsa) #if ENABLE_IP_PKTINFO if (!lsa) return 0; switch (lsa->dest.addr.sa.sa_family) { -#ifdef HAVE_IN_PKTINFO +#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) case AF_INET: return lsa->pi.in4.ipi_spec_dst.s_addr != 0; #elif defined(IP_RECVDSTADDR) case AF_INET: return lsa->pi.in4.s_addr != 0; From d7c15ff12a8790c2ad2e0adc0e191c32f081463f Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Fri, 16 Sep 2016 21:45:11 +0200 Subject: [PATCH 303/643] Show compile-time variant for --multihome in --version output. Instead of just [MH], show [MH/PKTINFO] or [MH/RECVDA], to see more easily which compile-time variant was chosen by configure and syshead.h Signed-off-by: Gert Doering Acked-by: Arne Schwabe Message-Id: <20160916194511.46137-1-gert@greenie.muc.de> URL: http://www.mail-archive.com/search?l=mid&q=20160916194511.46137-1-gert@greenie.muc.de Signed-off-by: Gert Doering --- src/openvpn/options.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/openvpn/options.c b/src/openvpn/options.c index e052042f367..c9688c37263 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -97,7 +97,11 @@ const char title_string[] = " [PKCS11]" #endif #if ENABLE_IP_PKTINFO - " [MH]" +# if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) + " [MH/PKTINFO]" +# elif defined(IP_RECVDSTADDR) + " [MH/RECVDA]" +# endif #endif " [IPv6]" " built on " __DATE__ From 6b25b99fe4b8bdf5cdba4a0fb247df40277d0525 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Sat, 17 Sep 2016 13:50:33 +0300 Subject: [PATCH 304/643] t_client.sh: Add support for Kerberos/ksu If the t_client.rc have PREFER_KSU=1 configured, t_client.sh will check if you have a valid Kerberos ticket and if so it will do all execution via ksu instead of sudo. If PREFER_KSU is not set or a Kerberos ticket is not found, it will fallback to the configured RUN_SUDO approach. When using ksu it needs the full path to the program being executed, so there is also additional code to find the full path of true and kill. [ v2 - Remove $* from RUN_SUDO for ksu config. Old cruft which survived last review before patch submission. - Improve known state declaration of PREFER_KSU ] [ v3 - Kick out bashism - '&>' redirect ] Signed-off-by: David Sommerseth Acked-by: Gert Doering Message-Id: <1474109433-4710-1-git-send-email-davids@openvpn.net> URL: http://www.mail-archive.com/search?l=mid&q=1474109433-4710-1-git-send-email-davids@openvpn.net Signed-off-by: Gert Doering --- tests/t_client.sh.in | 40 +++++++++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/tests/t_client.sh.in b/tests/t_client.sh.in index fc82cdb7b71..64a3b9a9245 100755 --- a/tests/t_client.sh.in +++ b/tests/t_client.sh.in @@ -36,6 +36,18 @@ if [ $? -ne 0 ]; then exit 77 fi +KILL_EXEC=`which kill` +if [ $? -ne 0 ]; then + echo "$0: kill not found in \$PATH" >&2 + exit 77 +fi + +TRUE_EXEC=`which true` +if [ $? -ne 0 ]; then + echo "$0: true not found in \$PATH" >&2 + exit 77 +fi + if [ ! -x "${top_builddir}/src/openvpn/openvpn" ] then echo "no (executable) openvpn binary in current build tree. FAIL." >&2 @@ -58,12 +70,29 @@ if [ -z "$TEST_RUN_LIST" ] ; then exit 77 fi +# Ensure PREFER_KSU is in a known state +PREFER_KSU="${PREFER_KSU:-0}" + # make sure we have permissions to run ifconfig/route from OpenVPN # can't use "id -u" here - doesn't work on Solaris ID=`id` if expr "$ID" : "uid=0" >/dev/null then : else + if [ "${PREFER_KSU}" -eq 1 ]; + then + # Check if we have a valid kerberos ticket + klist -l 1>/dev/null 2>/dev/null + if [ $? -ne 0 ]; + then + # No kerberos ticket found, skip ksu and fallback to RUN_SUDO + PREFER_KSU=0 + echo "$0: No Kerberos ticket available. Will not use ksu." + else + RUN_SUDO="ksu -q -e" + fi + fi + if [ -z "$RUN_SUDO" ] then echo "$0: this test must run be as root, or RUN_SUDO=... " >&2 @@ -73,7 +102,7 @@ else # We have to use sudo. Make sure that we (hopefully) do not have # to ask the users password during the test. This is done to # prevent timing issues, e.g. when the waits for openvpn to start - $RUN_SUDO \true + $RUN_SUDO $TRUE_EXEC fi fi @@ -90,6 +119,7 @@ exit_code=0 # ---------------------------------------------------------- # helper functions # ---------------------------------------------------------- + # print failure message, increase FAIL counter fail() { @@ -273,14 +303,14 @@ do echo " OpenVPN running with PID $opid" # make sure openvpn client is terminated in case shell exits - trap "$RUN_SUDO kill $opid" 0 - trap "$RUN_SUDO kill $opid ; trap - 0 ; exit 1" 1 2 3 15 + trap "$RUN_SUDO $KILL_EXEC $opid" 0 + trap "$RUN_SUDO $KILL_EXEC $opid ; trap - 0 ; exit 1" 1 2 3 15 echo "wait for connection to establish..." sleep ${SETUP_TIME_WAIT:-10} # test whether OpenVPN process is still there - if $RUN_SUDO kill -0 $opid + if $RUN_SUDO $KILL_EXEC -0 $opid then : else fail "OpenVPN process has failed to start up, check log ($LOGDIR/$SUF:openvpn.log)." @@ -315,7 +345,7 @@ do echo -e "ping tests done.\n" echo "stopping OpenVPN" - $RUN_SUDO kill $opid + $RUN_SUDO $KILL_EXEC $opid wait $! rc=$? if [ $rc != 0 ] ; then From 3712322ee1219e55640f2f4e5f822799edacd7cc Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Sat, 17 Sep 2016 14:18:05 +0300 Subject: [PATCH 305/643] t_client.sh: Improve detection if the OpenVPN process did start during tests This will check the OpenVPN log file if the process initialized successfully. It will check the log file for 30 seconds before aborting the test run. This also has the advantage of starting the testing quicker if the initialization goes faster than 10 seconds (which was the old sleep time). The umask is also set to a more permissive mode to ensure the test script is capable of reading the OpenVPN PID file, as that will be created by root. Signed-off-by: David Sommerseth Acked-by: Gert Doering Message-Id: <1474111085-10678-1-git-send-email-davids@openvpn.net> URL: http://www.mail-archive.com/search?l=mid&q=1474111085-10678-1-git-send-email-davids@openvpn.net Signed-off-by: Gert Doering --- tests/t_client.sh.in | 46 +++++++++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/tests/t_client.sh.in b/tests/t_client.sh.in index 64a3b9a9245..bde07a6edfc 100755 --- a/tests/t_client.sh.in +++ b/tests/t_client.sh.in @@ -297,23 +297,39 @@ do openvpn_conf="$openvpn_conf --writepid $pidfile" echo " run openvpn $openvpn_conf" echo "# src/openvpn/openvpn $openvpn_conf" >$LOGDIR/$SUF:openvpn.log + umask 022 $RUN_SUDO "${top_builddir}/src/openvpn/openvpn" $openvpn_conf >>$LOGDIR/$SUF:openvpn.log & - sleep 3 # Wait for OpenVPN to initialize and have had time to write the pid file - opid=`cat $pidfile` - echo " OpenVPN running with PID $opid" - - # make sure openvpn client is terminated in case shell exits - trap "$RUN_SUDO $KILL_EXEC $opid" 0 - trap "$RUN_SUDO $KILL_EXEC $opid ; trap - 0 ; exit 1" 1 2 3 15 + sudopid=$! - echo "wait for connection to establish..." - sleep ${SETUP_TIME_WAIT:-10} + # Check if OpenVPN has initialized before continuing. It will check every 3rd second up + # to $ovpn_init_check times. + ovpn_init_check=10 + ovpn_init_success=0 + while [ $ovpn_init_check -gt 0 ]; + do + sleep 3 # Wait for OpenVPN to initialize and have had time to write the pid file + grep -q "Initialization Sequence Completed" $LOGDIR/$SUF:openvpn.log + if [ $? -eq 0 ]; then + ovpn_init_check=0 + ovpn_init_success=1 + fi + ovpn_init_check=$(( $ovpn_init_check - 1 )) + done - # test whether OpenVPN process is still there - if $RUN_SUDO $KILL_EXEC -0 $opid - then : + opid=`cat $pidfile` + if [ -n "$opid" ]; then + echo " OpenVPN running with PID $opid" else - fail "OpenVPN process has failed to start up, check log ($LOGDIR/$SUF:openvpn.log)." + echo " Could not read OpenVPN PID file" >&2 + fi + + # If OpenVPN did not start + if [ $ovpn_init_success -ne 1 -o -z "$opid" ]; then + echo "$0: OpenVPN did not initialize in a reasonable time" >&2 + if [ -n "$opid" ]; then + $RUN_SUDO $KILL_EXEC $opid + fi + $RUN_SUDO $KILL_EXEC $sudopid echo "tail -5 $SUF:openvpn.log" >&2 tail -5 $LOGDIR/$SUF:openvpn.log >&2 echo -e "\nFAIL. skip rest of sub-tests for test run $SUF.\n" >&2 @@ -323,6 +339,10 @@ do continue fi + # make sure openvpn client is terminated in case shell exits + trap "$RUN_SUDO $KILL_EXEC $opid" 0 + trap "$RUN_SUDO $KILL_EXEC $opid ; trap - 0 ; exit 1" 1 2 3 15 + # compare whether anything changed in ifconfig/route setup? echo "save ifconfig+route" get_ifconfig_route >$LOGDIR/$SUF:ifconfig_route.txt From d13a40a4a477bae3efede6945174df1cb2c3aa69 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Sat, 17 Sep 2016 13:16:46 +0200 Subject: [PATCH 306/643] Fix ENABLE_CRYPTO_OPENSSL set to YES even with --disable-crypto set On OS X openssl/x509.h is not in the standard include path and the files still try to include since the includes only depend on on ENABLE_CRYPTO_OPENSSL. Acked-by: Gert Doering Message-Id: <1474111006-16401-1-git-send-email-arne@rfc2549.org> URL: http://www.mail-archive.com/search?l=mid&q=1474111006-16401-1-git-send-email-arne@rfc2549.org Signed-off-by: Gert Doering --- configure.ac | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 2d578f41d76..1337f84e679 100644 --- a/configure.ac +++ b/configure.ac @@ -790,7 +790,7 @@ PKG_CHECK_MODULES( [] ) -if test "${with_crypto_library}" = "openssl"; then +if test "${enable_crypto}" = "yes" -a "${with_crypto_library}" = "openssl"; then AC_ARG_VAR([OPENSSL_CFLAGS], [C compiler flags for OpenSSL]) AC_ARG_VAR([OPENSSL_LIBS], [linker flags for OpenSSL]) @@ -844,7 +844,7 @@ if test "${with_crypto_library}" = "openssl"; then AC_DEFINE([ENABLE_CRYPTO_OPENSSL], [1], [Use OpenSSL library]) CRYPTO_CFLAGS="${OPENSSL_CFLAGS}" CRYPTO_LIBS="${OPENSSL_LIBS}" -elif test "${with_crypto_library}" = "mbedtls"; then +elif test "${enable_crypto}" = "yes" -a "${with_crypto_library}" = "mbedtls"; then AC_ARG_VAR([MBEDTLS_CFLAGS], [C compiler flags for mbedtls]) AC_ARG_VAR([MBEDTLS_LIBS], [linker flags for mbedtls]) @@ -927,7 +927,7 @@ elif test "${with_crypto_library}" = "mbedtls"; then AC_DEFINE([ENABLE_CRYPTO_MBEDTLS], [1], [Use mbed TLS library]) CRYPTO_CFLAGS="${MBEDTLS_CFLAGS}" CRYPTO_LIBS="${MBEDTLS_LIBS}" -else +elif test "${enable_crypto}" = "yes"; then AC_MSG_ERROR([Invalid crypto library: ${with_crypto_library}]) fi From af1e4d26ab65bd71de168ea621ca55d0e40a0bc1 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Thu, 5 May 2016 22:14:07 +0200 Subject: [PATCH 307/643] Add SHA256 fingerprint support Add SHA256 fingerprint support for both the normal exported fingerprints (tls_digest_n -> tls_digest_sha256_n), as well as for --x509-track. Also switch to using the SHA256 fingerprint instead of the SHA1 fingerprint internally, in cert_hash_remember() / cert_hash_compare(). And instead of updating an #if 0'd code block that has been disabled since 2009, just remove that. This should take care of trac #675. v2: update openvpn.8 accordingly [ DS: This commit squashes in the clean-up cert_hash_remember scoping patch, as it is highly related and tied to this primary patch ] Signed-off-by: Steffan Karger Acked-by: David Sommerseth Message-Id: 1462479247-21854-1-git-send-email-steffan@karger.me Message-Id: 1474055635-7427-1-git-send-email-steffan@karger.me URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg11859.html URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12464.html Signed-off-by: David Sommerseth --- doc/openvpn.8 | 5 ++- src/openvpn/ssl_verify.c | 59 ++++++++++++++------------------ src/openvpn/ssl_verify.h | 2 +- src/openvpn/ssl_verify_backend.h | 25 ++++++++++---- src/openvpn/ssl_verify_mbedtls.c | 48 ++++++++++++++++++++------ src/openvpn/ssl_verify_openssl.c | 37 +++++++++++++++----- 6 files changed, 113 insertions(+), 63 deletions(-) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 2f4263608d5..163bdf4bad3 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -6443,9 +6443,8 @@ Set prior to execution of the script. .\"********************************************************* .TP -.B tls_digest_{n} -Contains the certificate SHA1 fingerprint/digest hash value, -where +.B tls_digest_{n} / tls_digest_sha256_{n} +Contains the certificate SHA1 / SHA256 fingerprint, where .B n is the verification level. Only set for TLS connections. Set prior to execution of diff --git a/src/openvpn/ssl_verify.c b/src/openvpn/ssl_verify.c index b373bed1ada..d0c22b84ece 100644 --- a/src/openvpn/ssl_verify.c +++ b/src/openvpn/ssl_verify.c @@ -191,40 +191,25 @@ tls_username (const struct tls_multi *multi, const bool null) } void -cert_hash_remember (struct tls_session *session, const int error_depth, const unsigned char *sha1_hash) +cert_hash_remember (struct tls_session *session, const int error_depth, + const struct buffer *cert_hash) { if (error_depth >= 0 && error_depth < MAX_CERT_DEPTH) { if (!session->cert_hash_set) - ALLOC_OBJ_CLEAR (session->cert_hash_set, struct cert_hash_set); + { + ALLOC_OBJ_CLEAR (session->cert_hash_set, struct cert_hash_set); + } if (!session->cert_hash_set->ch[error_depth]) - ALLOC_OBJ (session->cert_hash_set->ch[error_depth], struct cert_hash); - { - struct cert_hash *ch = session->cert_hash_set->ch[error_depth]; - memcpy (ch->sha1_hash, sha1_hash, SHA_DIGEST_LENGTH); - } - } -} - -#if 0 -static void -cert_hash_print (const struct cert_hash_set *chs, int msglevel) -{ - struct gc_arena gc = gc_new (); - msg (msglevel, "CERT_HASH"); - if (chs) - { - int i; - for (i = 0; i < MAX_CERT_DEPTH; ++i) { - const struct cert_hash *ch = chs->ch[i]; - if (ch) - msg (msglevel, "%d:%s", i, format_hex(ch->sha1_hash, SHA_DIGEST_LENGTH, 0, &gc)); + ALLOC_OBJ (session->cert_hash_set->ch[error_depth], struct cert_hash); } + + struct cert_hash *ch = session->cert_hash_set->ch[error_depth]; + ASSERT (sizeof (ch->sha256_hash) == BLEN (cert_hash)); + memcpy (ch->sha256_hash, BPTR (cert_hash), sizeof (ch->sha256_hash)); } - gc_free (&gc); } -#endif void cert_hash_free (struct cert_hash_set *chs) @@ -251,7 +236,8 @@ cert_hash_compare (const struct cert_hash_set *chs1, const struct cert_hash_set if (!ch1 && !ch2) continue; - else if (ch1 && ch2 && !memcmp (ch1->sha1_hash, ch2->sha1_hash, SHA_DIGEST_LENGTH)) + else if (ch1 && ch2 && !memcmp (ch1->sha256_hash, ch2->sha256_hash, + sizeof(ch1->sha256_hash))) continue; else return false; @@ -278,7 +264,8 @@ cert_hash_copy (const struct cert_hash_set *chs) if (ch) { ALLOC_OBJ (dest->ch[i], struct cert_hash); - memcpy (dest->ch[i]->sha1_hash, ch->sha1_hash, SHA_DIGEST_LENGTH); + memcpy (dest->ch[i]->sha256_hash, ch->sha256_hash, + sizeof(dest->ch[i]->sha256_hash)); } } } @@ -416,13 +403,19 @@ verify_cert_set_env(struct env_set *es, openvpn_x509_cert_t *peer_cert, int cert setenv_str (es, envname, common_name); #endif - /* export X509 cert SHA1 fingerprint */ + /* export X509 cert fingerprints */ { - unsigned char *sha1_hash = x509_get_sha1_hash(peer_cert, &gc); + struct buffer sha1 = x509_get_sha1_fingerprint(peer_cert, &gc); + struct buffer sha256 = x509_get_sha256_fingerprint(peer_cert, &gc); openvpn_snprintf (envname, sizeof(envname), "tls_digest_%d", cert_depth); - setenv_str (es, envname, format_hex_ex(sha1_hash, SHA_DIGEST_LENGTH, 0, 1, - ":", &gc)); + setenv_str (es, envname, + format_hex_ex(BPTR(&sha1), BLEN(&sha1), 0, 1, ":", &gc)); + + openvpn_snprintf (envname, sizeof(envname), "tls_digest_sha256_%d", + cert_depth); + setenv_str (es, envname, + format_hex_ex(BPTR(&sha256), BLEN(&sha256), 0, 1, ":", &gc)); } /* export serial number as environmental variable */ @@ -638,8 +631,8 @@ verify_cert(struct tls_session *session, openvpn_x509_cert_t *cert, int cert_dep /* verify level 1 cert, i.e. the CA that signed our leaf cert */ if (cert_depth == 1 && opt->verify_hash) { - unsigned char *sha1_hash = x509_get_sha1_hash(cert, &gc); - if (memcmp (sha1_hash, opt->verify_hash, SHA_DIGEST_LENGTH)) + struct buffer sha1_hash = x509_get_sha1_fingerprint(cert, &gc); + if (memcmp (BPTR (&sha1_hash), opt->verify_hash, BLEN(&sha1_hash))) { msg (D_TLS_ERRORS, "TLS Error: level-1 certificate hash verification failed"); goto cleanup; diff --git a/src/openvpn/ssl_verify.h b/src/openvpn/ssl_verify.h index f693b2a4874..e5b5950a0f1 100644 --- a/src/openvpn/ssl_verify.h +++ b/src/openvpn/ssl_verify.h @@ -55,7 +55,7 @@ /** Structure containing the hash for a single certificate */ struct cert_hash { - unsigned char sha1_hash[SHA_DIGEST_LENGTH]; /**< The SHA1 hash for a certificate */ + unsigned char sha256_hash[256/8]; }; /** Structure containing the hashes for a full certificate chain */ diff --git a/src/openvpn/ssl_verify_backend.h b/src/openvpn/ssl_verify_backend.h index 9d2057b558d..91e6ec9300d 100644 --- a/src/openvpn/ssl_verify_backend.h +++ b/src/openvpn/ssl_verify_backend.h @@ -66,10 +66,10 @@ result_t verify_cert(struct tls_session *session, openvpn_x509_cert_t *cert, int * * @param session TLS Session associated with this tunnel * @param cert_depth Depth of the current certificate - * @param sha1_hash Hash of the current certificate + * @param cert_hash Hash of the current certificate */ void cert_hash_remember (struct tls_session *session, const int cert_depth, - const unsigned char *sha1_hash); + const struct buffer *cert_hash); /* * Library-specific functions. @@ -87,14 +87,27 @@ void cert_hash_remember (struct tls_session *session, const int cert_depth, */ char *x509_get_subject (openvpn_x509_cert_t *cert, struct gc_arena *gc); -/* Retrieve the certificate's SHA1 hash. +/** + * Retrieve the certificate's SHA1 fingerprint. * - * @param cert Certificate to retrieve the hash from. + * @param cert Certificate to retrieve the fingerprint from. * @param gc Garbage collection arena to use when allocating string. * - * @return a string containing the SHA1 hash of the certificate + * @return a string containing the certificate fingerprint */ -unsigned char *x509_get_sha1_hash (openvpn_x509_cert_t *cert, struct gc_arena *gc); +struct buffer x509_get_sha1_fingerprint (openvpn_x509_cert_t *cert, + struct gc_arena *gc); + +/** + * Retrieve the certificate's SHA256 fingerprint. + * + * @param cert Certificate to retrieve the fingerprint from. + * @param gc Garbage collection arena to use when allocating string. + * + * @return a string containing the certificate fingerprint + */ +struct buffer x509_get_sha256_fingerprint (openvpn_x509_cert_t *cert, + struct gc_arena *gc); /* * Retrieve the certificate's username from the specified field. diff --git a/src/openvpn/ssl_verify_mbedtls.c b/src/openvpn/ssl_verify_mbedtls.c index 522ff68c4af..92b0804bb5c 100644 --- a/src/openvpn/ssl_verify_mbedtls.c +++ b/src/openvpn/ssl_verify_mbedtls.c @@ -60,7 +60,8 @@ verify_callback (void *session_obj, mbedtls_x509_crt *cert, int cert_depth, session->verified = false; /* Remember certificate hash */ - cert_hash_remember (session, cert_depth, x509_get_sha1_hash(cert, &gc)); + struct buffer cert_fingerprint = x509_get_sha256_fingerprint (cert, &gc); + cert_hash_remember (session, cert_depth, &cert_fingerprint); /* did peer present cert which was signed by our root cert? */ if (*flags != 0) @@ -196,12 +197,29 @@ backend_x509_get_serial_hex (mbedtls_x509_crt *cert, struct gc_arena *gc) return buf; } -unsigned char * -x509_get_sha1_hash (mbedtls_x509_crt *cert, struct gc_arena *gc) +static struct buffer +x509_get_fingerprint (const mbedtls_md_info_t *md_info, mbedtls_x509_crt *cert, + struct gc_arena *gc) { - unsigned char *sha1_hash = gc_malloc(SHA_DIGEST_LENGTH, false, gc); - mbedtls_sha1(cert->raw.p, cert->tbs.len, sha1_hash); - return sha1_hash; + const size_t md_size = mbedtls_md_get_size (md_info); + struct buffer fingerprint = alloc_buf_gc (md_size, gc); + mbedtls_md(md_info, cert->raw.p, cert->tbs.len, BPTR (&fingerprint)); + ASSERT (buf_inc_len(&fingerprint, md_size)); + return fingerprint; +} + +struct buffer +x509_get_sha1_fingerprint (mbedtls_x509_crt *cert, struct gc_arena *gc) +{ + return x509_get_fingerprint(mbedtls_md_info_from_type(MBEDTLS_MD_SHA1), + cert, gc); +} + +struct buffer +x509_get_sha256_fingerprint (mbedtls_x509_crt *cert, struct gc_arena *gc) +{ + return x509_get_fingerprint(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), + cert, gc); } char * @@ -294,12 +312,20 @@ x509_setenv_track (const struct x509_track *xt, struct env_set *es, { if (depth == 0 || (xt->flags & XT_FULL_CHAIN)) { - if (0 == strcmp(xt->name, "SHA1")) + if (0 == strcmp(xt->name, "SHA1") || 0 == strcmp(xt->name, "SHA256")) { - /* SHA1 fingerprint is not part of X509 structure */ - unsigned char *sha1_hash = x509_get_sha1_hash(cert, &gc); - char *sha1_fingerprint = format_hex_ex(sha1_hash, SHA_DIGEST_LENGTH, 0, 1 | FHE_CAPS, ":", &gc); - do_setenv_x509(es, xt->name, sha1_fingerprint, depth); + /* Fingerprint is not part of X509 structure */ + struct buffer cert_hash; + char *fingerprint; + + if (0 == strcmp(xt->name, "SHA1")) + cert_hash = x509_get_sha1_fingerprint(cert, &gc); + else + cert_hash = x509_get_sha256_fingerprint(cert, &gc); + + fingerprint = format_hex_ex(BPTR(&cert_hash), + BLEN(&cert_hash), 0, 1 | FHE_CAPS, ":", &gc); + do_setenv_x509(es, xt->name, fingerprint, depth); } else { diff --git a/src/openvpn/ssl_verify_openssl.c b/src/openvpn/ssl_verify_openssl.c index 5817a05eeda..a4b94328b36 100644 --- a/src/openvpn/ssl_verify_openssl.c +++ b/src/openvpn/ssl_verify_openssl.c @@ -61,8 +61,8 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx) session = (struct tls_session *) SSL_get_ex_data (ssl, mydata_index); ASSERT (session); - cert_hash_remember (session, ctx->error_depth, - x509_get_sha1_hash(ctx->current_cert, &gc)); + struct buffer cert_hash = x509_get_sha256_fingerprint(ctx->current_cert, &gc); + cert_hash_remember (session, ctx->error_depth, &cert_hash); /* did peer present cert which was signed by our root cert? */ if (!preverify_ok) @@ -248,11 +248,21 @@ backend_x509_get_serial_hex (openvpn_x509_cert_t *cert, struct gc_arena *gc) return format_hex_ex(asn1_i->data, asn1_i->length, 0, 1, ":", gc); } -unsigned char * -x509_get_sha1_hash (X509 *cert, struct gc_arena *gc) +struct buffer +x509_get_sha1_fingerprint (X509 *cert, struct gc_arena *gc) { - unsigned char *hash = gc_malloc(SHA_DIGEST_LENGTH, false, gc); - memcpy(hash, cert->sha1_hash, SHA_DIGEST_LENGTH); + struct buffer hash = alloc_buf_gc(sizeof(cert->sha1_hash), gc); + memcpy(BPTR(&hash), cert->sha1_hash, sizeof(cert->sha1_hash)); + ASSERT (buf_inc_len(&hash, sizeof (cert->sha1_hash))); + return hash; +} + +struct buffer +x509_get_sha256_fingerprint (X509 *cert, struct gc_arena *gc) +{ + struct buffer hash = alloc_buf_gc((EVP_sha256())->md_size, gc); + X509_digest(cert, EVP_sha256(), BPTR(&hash), NULL); + ASSERT (buf_inc_len(&hash, (EVP_sha256())->md_size)); return hash; } @@ -376,10 +386,19 @@ x509_setenv_track (const struct x509_track *xt, struct env_set *es, const int de switch (xt->nid) { case NID_sha1: + case NID_sha256: { - char *sha1_fingerprint = format_hex_ex(x509->sha1_hash, - SHA_DIGEST_LENGTH, 0, 1 | FHE_CAPS, ":", &gc); - do_setenv_x509(es, xt->name, sha1_fingerprint, depth); + struct buffer fp_buf; + char *fp_str = NULL; + + if (xt->nid == NID_sha1) + fp_buf = x509_get_sha1_fingerprint(x509, &gc); + else + fp_buf = x509_get_sha256_fingerprint(x509, &gc); + + fp_str = format_hex_ex(BPTR(&fp_buf), BLEN(&fp_buf), 0, + 1 | FHE_CAPS, ":", &gc); + do_setenv_x509(es, xt->name, fp_str, depth); } break; default: From e7303ace6f101bbe61c3251c080975cf5c261f71 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Sat, 17 Sep 2016 11:00:35 +0200 Subject: [PATCH 308/643] Prefer RECVDSTADDR to PKTINFO for IPv4 in OS X since it actually works (unlike PKTINFO) Acked-by: Gert Doering Message-Id: <1474102835-13402-1-git-send-email-arne@rfc2549.org> URL: http://www.mail-archive.com/search?l=mid&q=1474102835-13402-1-git-send-email-arne@rfc2549.org Signed-off-by: Gert Doering --- configure.ac | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.ac b/configure.ac index 1337f84e679..a03abbaac04 100644 --- a/configure.ac +++ b/configure.ac @@ -337,6 +337,7 @@ case "$host" in have_tap_header="yes" dnl some Mac OS X tendering (we use vararg macros...) CPPFLAGS="$CPPFLAGS -no-cpp-precomp" + ac_cv_type_struct_in_pktinfo=no ;; *-mingw*) AC_DEFINE([TARGET_WIN32], [1], [Are we running WIN32?]) From e8e1377d0fc3f11b65e415b68e6065d2e9eb836e Mon Sep 17 00:00:00 2001 From: Lev Stipakov Date: Sun, 18 Sep 2016 09:51:36 +0300 Subject: [PATCH 309/643] Support for disabled peer-id v5: * Few more nickpicks v4: * replace magic number with define * show user a decimal value instead of hex v3: * move assert outside of loop * add max-clients value check to options v2: * Add round brackets for clarity * Rephrase comment Support for disabled peer-id When peer-id value is 0xFFFFFF, server should ignore it and treat packet in a same way as P_DATA_V1. Acked-by: Steffan Karger Message-Id: <1474181496-24846-1-git-send-email-lstipakov@gmail.com> URL: http://www.mail-archive.com/search?l=mid&q=1474181496-24846-1-git-send-email-lstipakov@gmail.com Signed-off-by: Gert Doering --- src/openvpn/mudp.c | 13 ++++++++++--- src/openvpn/multi.c | 3 ++- src/openvpn/openvpn.h | 3 +++ src/openvpn/options.c | 5 +++++ 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/openvpn/mudp.c b/src/openvpn/mudp.c index 21a7e97f73b..fec5e8d9244 100644 --- a/src/openvpn/mudp.c +++ b/src/openvpn/mudp.c @@ -64,12 +64,16 @@ multi_get_create_instance_udp (struct multi_context *m, bool *floated) struct hash_bucket *bucket = hash_bucket (hash, hv); uint8_t* ptr = BPTR(&m->top.c2.buf); uint8_t op = ptr[0] >> P_OPCODE_SHIFT; + bool v2 = (op == P_DATA_V2) && (m->top.c2.buf.len >= (1 + 3)); + bool peer_id_disabled = false; /* make sure buffer has enough length to read opcode (1 byte) and peer-id (3 bytes) */ - if (op == P_DATA_V2 && m->top.c2.buf.len >= (1 + 3)) + if (v2) { uint32_t peer_id = ntohl(*(uint32_t*)ptr) & 0xFFFFFF; - if ((peer_id < m->max_clients) && (m->instances[peer_id])) + peer_id_disabled = (peer_id == MAX_PEER_ID); + + if (!peer_id_disabled && (peer_id < m->max_clients) && (m->instances[peer_id])) { mi = m->instances[peer_id]; @@ -84,7 +88,7 @@ multi_get_create_instance_udp (struct multi_context *m, bool *floated) } } } - else + if (!v2 || peer_id_disabled) { he = hash_lookup_fast (hash, bucket, &real, hv); if (he) @@ -107,6 +111,9 @@ multi_get_create_instance_udp (struct multi_context *m, bool *floated) hash_add_fast (hash, bucket, &mi->real, hv, mi); mi->did_real_hash = true; + /* max_clients must be less then max peer-id value */ + ASSERT(m->max_clients < MAX_PEER_ID); + for (i = 0; i < m->max_clients; ++i) { if (!m->instances[i]) diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index ba7f2c0a40b..3bc6ee91da6 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -605,7 +605,8 @@ multi_close_instance (struct multi_context *m, } #endif - m->instances[mi->context.c2.tls_multi->peer_id] = NULL; + if (mi->context.c2.tls_multi->peer_id != MAX_PEER_ID) + m->instances[mi->context.c2.tls_multi->peer_id] = NULL; schedule_remove_entry (m->schedule, (struct schedule_entry *) mi); diff --git a/src/openvpn/openvpn.h b/src/openvpn/openvpn.h index 1a458f1c1c2..65a183a736d 100644 --- a/src/openvpn/openvpn.h +++ b/src/openvpn/openvpn.h @@ -595,4 +595,7 @@ struct context #define CIPHER_ENABLED(c) (false) #endif +/* this represents "disabled peer-id" */ +#define MAX_PEER_ID 0xFFFFFF + #endif diff --git a/src/openvpn/options.c b/src/openvpn/options.c index c9688c37263..4b7203d9ba3 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -5893,6 +5893,11 @@ add_option (struct options *options, msg (msglevel, "--max-clients must be at least 1"); goto err; } + if (max_clients >= MAX_PEER_ID) /* max peer-id value */ + { + msg (msglevel, "--max-clients must be less than %d", MAX_PEER_ID); + goto err; + } options->max_clients = max_clients; } else if (streq (p[0], "max-routes-per-client") && p[1] && !p[2]) From c42fcbfe708f4c97da063642cf8874f0d4d1a645 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Thu, 14 Jul 2016 13:25:19 +0200 Subject: [PATCH 310/643] Incorporate the Debian typo fixes where appropriate and make show_opt default message clearer Debian also incorrectly changes that the default for route parameters can be specified by using "nil" instead of "default. The confusion is probably coming from show_opt printing "nil" instead of "default". Change show_opt to show "default (not set)" instead of "nil" Original author: Alberto Gonzalez Iniesta Acked-by: Gert Doering Message-Id: <1468495519-25102-1-git-send-email-arne@rfc2549.org> URL: http://www.mail-archive.com/search?l=mid&q=1468495519-25102-1-git-send-email-arne@rfc2549.org Signed-off-by: Gert Doering --- doc/openvpn.8 | 8 ++++---- src/openvpn/occ.c | 2 +- src/openvpn/route.c | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 163bdf4bad3..2d159440d9a 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -21,13 +21,13 @@ .\" 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA .\" .\" Manual page for openvpn -.\ +.\" .\" SH section heading .\" SS subsection heading .\" LP paragraph .\" IP indented paragraph .\" TP hanging label -.\ +.\" .\" .nf -- no formatting .\" .fi -- resume formatting .\" .ft 3 -- boldface @@ -4248,7 +4248,7 @@ is 15 seconds. This option is only relevant in UDP mode, i.e. when either .B \-\-proto udp -is specifed, or no +is specified, or no .B \-\-proto option is specified. @@ -5509,7 +5509,7 @@ virtual DHCP server address. In .B \-\-dev tun mode, OpenVPN will cause the DHCP server to masquerade as if it were coming from the remote endpoint. The optional offset parameter is -an integer which is > -256 and < 256 and which defaults to 0. +an integer which is > \-256 and < 256 and which defaults to 0. If offset is positive, the DHCP server will masquerade as the IP address at network address + offset. If offset is negative, the DHCP server will masquerade as the IP diff --git a/src/openvpn/occ.c b/src/openvpn/occ.c index ff487069625..d71381df699 100644 --- a/src/openvpn/occ.c +++ b/src/openvpn/occ.c @@ -379,7 +379,7 @@ process_received_occ_msg (struct context *c) && c->c2.max_send_size_local > TUN_MTU_MIN && (c->c2.max_recv_size_remote < c->c2.max_send_size_local || c->c2.max_recv_size_local < c->c2.max_send_size_remote)) - msg (M_INFO, "NOTE: This connection is unable to accomodate a UDP packet size of %d. Consider using --fragment or --mssfix options as a workaround.", + msg (M_INFO, "NOTE: This connection is unable to accommodate a UDP packet size of %d. Consider using --fragment or --mssfix options as a workaround.", c->c2.max_send_size_local); } event_timeout_clear (&c->c2.occ_mtu_load_test_interval); diff --git a/src/openvpn/route.c b/src/openvpn/route.c index a90195f4bf9..307366625b5 100644 --- a/src/openvpn/route.c +++ b/src/openvpn/route.c @@ -1171,7 +1171,7 @@ static const char * show_opt (const char *option) { if (!option) - return "nil"; + return "default (not set)"; else return option; } From 6cd7e08d89cc9c39d00989866fb4782d5e7041dc Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Sun, 18 Sep 2016 14:14:23 +0200 Subject: [PATCH 311/643] Fix win32 building with C99 mode In -std=c99 mode, WIN32 is not defined to be "1" anymore, but just "#define WIN32" - so the "#if WIN32" breaks, needs to be "#ifdef WIN32" v2: also fix block_dns.c (include config.h + compat.h) (Selva Nair) Signed-off-by: Gert Doering Acked-by: Selva Nair Message-Id: <20160918121423.52139-1-gert@greenie.muc.de> URL: http://www.mail-archive.com/search?l=mid&q=20160918121423.52139-1-gert@greenie.muc.de Signed-off-by: Gert Doering --- src/openvpn/block_dns.c | 11 +++++++++++ src/openvpn/misc.c | 2 +- src/openvpnserv/Makefile.am | 2 +- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/openvpn/block_dns.c b/src/openvpn/block_dns.c index af2db1892c9..ee20c6812b4 100644 --- a/src/openvpn/block_dns.c +++ b/src/openvpn/block_dns.c @@ -24,6 +24,17 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#elif defined(_MSC_VER) +#include "config-msvc.h" +#endif +#ifdef HAVE_CONFIG_VERSION_H +#include "config-version.h" +#endif + +#include "syshead.h" + #ifdef WIN32 #include diff --git a/src/openvpn/misc.c b/src/openvpn/misc.c index 0991d791707..2982cd0d195 100644 --- a/src/openvpn/misc.c +++ b/src/openvpn/misc.c @@ -977,7 +977,7 @@ hostname_randomize(const char *hostname, struct gc_arena *gc) const char * gen_path (const char *directory, const char *filename, struct gc_arena *gc) { -#if WIN32 +#ifdef WIN32 const int CC_PATH_RESERVED = CC_LESS_THAN|CC_GREATER_THAN|CC_COLON| CC_DOUBLE_QUOTE|CC_SLASH|CC_BACKSLASH|CC_PIPE|CC_QUESTION_MARK|CC_ASTERISK; #else diff --git a/src/openvpnserv/Makefile.am b/src/openvpnserv/Makefile.am index 3c757d644f0..3521a342e04 100644 --- a/src/openvpnserv/Makefile.am +++ b/src/openvpnserv/Makefile.am @@ -18,7 +18,7 @@ EXTRA_DIST = \ openvpnserv.vcxproj.filters AM_CPPFLAGS = \ - -I$(top_srcdir)/include -I$(top_srcdir)/src/openvpn + -I$(top_srcdir)/include -I$(top_srcdir)/src/openvpn -I$(top_srcdir)/src/compat if WIN32 sbin_PROGRAMS = openvpnserv From 38f98fdccd3eb6995b972fabb0ce4e00d3e3cb76 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Tue, 20 Sep 2016 11:19:14 +0200 Subject: [PATCH 312/643] Fix t_client runs on OpenSolaris "grep -q" is not portable to non-GNU grep. Replace with ">/dev/null". Signed-off-by: Gert Doering Acked-by: David Sommerseth Message-Id: 20160920091914.37585-1-gert@greenie.muc.de URL: http://www.mail-archive.com/search?l=mid&q=20160920091914.37585-1-gert@greenie.muc.de Signed-off-by: David Sommerseth --- tests/t_client.sh.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/t_client.sh.in b/tests/t_client.sh.in index bde07a6edfc..2b9bacf581d 100755 --- a/tests/t_client.sh.in +++ b/tests/t_client.sh.in @@ -308,7 +308,7 @@ do while [ $ovpn_init_check -gt 0 ]; do sleep 3 # Wait for OpenVPN to initialize and have had time to write the pid file - grep -q "Initialization Sequence Completed" $LOGDIR/$SUF:openvpn.log + grep "Initialization Sequence Completed" $LOGDIR/$SUF:openvpn.log >/dev/null if [ $? -eq 0 ]; then ovpn_init_check=0 ovpn_init_success=1 From 0c72e29c990a766e6952455d23151dabf79ed22b Mon Sep 17 00:00:00 2001 From: Ilya Shipitsin Date: Sat, 17 Sep 2016 15:54:39 +0500 Subject: [PATCH 313/643] enable "--disable-crypto" build configuration for travis Previously, 'make test' failed for --disable-crypto builds. Since that is now fixed, we should no longer accept --disable-crypto builds to fail 'make test' on travis. Acked-by: Steffan Karger Message-Id: <1474109679-4982-1-git-send-email-chipitsine@gmail.com> URL: http://www.mail-archive.com/search?l=mid&q=1474109679-4982-1-git-send-email-chipitsine@gmail.com Signed-off-by: Gert Doering --- .travis.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 452c48e7f12..369db97c970 100644 --- a/.travis.yml +++ b/.travis.yml @@ -51,10 +51,6 @@ matrix: os: osx osx_image: xcode7.3 compiler: clang - allow_failures: - - env: SSLLIB="openssl" EXTRA_CONFIG="--disable-crypto" - os: linux - compiler: clang exclude: - compiler: gcc From 348c416face9a025b618ebcae9d3a74c5a4a242b Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Wed, 28 Sep 2016 12:40:51 +0200 Subject: [PATCH 314/643] Make sure options->ciphername and options->authname are always defined The NCP code does a strcmp(options->ciphername, ...) without first checking whether options->ciphername is NULL. This could cause a crash when using "--cipher none". This patch fixes that problem by ensuring that options->ciphername (and options->authname) are never NULL. Ensuring that options->ciphername is never null prevents us from having to write null checks everywhere. Signed-off-by: Steffan Karger Acked-by: Arne Schwabe Acked-by: Gert Doering Message-Id: <1475055231-1778-1-git-send-email-steffan@karger.me> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12576.html Signed-off-by: Gert Doering --- src/openvpn/crypto.c | 7 +++++-- src/openvpn/init.c | 2 +- src/openvpn/options.c | 8 -------- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c index 6f578419adb..4ea0082c423 100644 --- a/src/openvpn/crypto.c +++ b/src/openvpn/crypto.c @@ -759,8 +759,11 @@ init_key_type (struct key_type *kt, const char *ciphername, { bool aead_cipher = false; + ASSERT(ciphername); + ASSERT(authname); + CLEAR (*kt); - if (ciphername) + if (strcmp (ciphername, "none") != 0) { kt->cipher = cipher_kt_get (translate_cipher_name_from_openvpn(ciphername)); kt->cipher_length = cipher_kt_key_size (kt->cipher); @@ -785,7 +788,7 @@ init_key_type (struct key_type *kt, const char *ciphername, if (warn) msg (M_WARN, "******* WARNING *******: null cipher specified, no encryption will be used"); } - if (authname) + if (strcmp (authname, "none") != 0) { if (!aead_cipher) { /* Ignore auth for AEAD ciphers */ kt->digest = md_kt_get (authname); diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 45ce025ee52..e3206b05e9b 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -2266,7 +2266,7 @@ do_init_crypto_tls_c1 (struct context *c) /* Initialize key_type for tls-auth with auth only */ CLEAR (c->c1.ks.tls_auth_key_type); - if (options->authname) + if (!streq (options->authname, "none")) { c->c1.ks.tls_auth_key_type.digest = md_kt_get (options->authname); c->c1.ks.tls_auth_key_type.hmac_length = diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 4b7203d9ba3..9f6099c20e0 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -6659,19 +6659,11 @@ add_option (struct options *options, { VERIFY_PERMISSION (OPT_P_GENERAL); options->authname = p[1]; - if (streq (options->authname, "none")) - { - options->authname = NULL; - } } else if (streq (p[0], "cipher") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_NCP); options->ciphername = p[1]; - if (streq (options->ciphername, "none")) - { - options->ciphername = NULL; - } } else if (streq (p[0], "ncp-ciphers") && p[1] && !p[2]) { From df0b00c253e41cce9567be79dbd3faa14c60473b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuli=20Sepp=C3=A4nen?= Date: Mon, 3 Oct 2016 13:51:27 +0300 Subject: [PATCH 315/643] Automatically cache expected IPs for t_client.sh on the first run MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously one had to manually define correct values for the EXPECT_IFCONFIG* variables based on what IPv4 and IPv6 addresses the test VPN server handed out. This was a tedious process especially with large number of tests, as the IPs changed for every test client and for every test. With this patch t_client.sh figures out the correct IP addresses using an --up script and caches them to a separate file for later use. Signed-off-by: Samuli Seppänen Acked-by: Arne Schwabe Message-Id: <1475491887-740-1-git-send-email-samuli@openvpn.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12587.html Signed-off-by: Gert Doering --- .gitignore | 1 + tests/t_client.rc-sample | 12 ++++++++---- tests/t_client.sh.in | 8 +++++++- tests/update_t_client_ips.sh | 7 +++++++ 4 files changed, 23 insertions(+), 5 deletions(-) create mode 100755 tests/update_t_client_ips.sh diff --git a/.gitignore b/.gitignore index 0eea06e0109..fc1e223aecf 100644 --- a/.gitignore +++ b/.gitignore @@ -55,6 +55,7 @@ distro/rpm/openvpn.spec tests/t_client.sh tests/t_client-*-20??????-??????/ t_client.rc +t_client_ips.rc src/openvpn/openvpn include/openvpn-plugin.h diff --git a/tests/t_client.rc-sample b/tests/t_client.rc-sample index 6e6660774fb..fb2abfae24f 100644 --- a/tests/t_client.rc-sample +++ b/tests/t_client.rc-sample @@ -11,6 +11,14 @@ top_srcdir="${top_srcdir:-..}" CA_CERT="${top_srcdir}/sample/sample-keys/ca.crt" CLIENT_KEY="${top_srcdir}/sample/sample-keys/client.key" CLIENT_CERT="${top_srcdir}/sample/sample-keys/client.crt" + +# Load EXPECT_IFCONFIG* parameters from cache +if [ -r "${top_srcdir}/t_client_ips.rc" ]; then + . "${top_srcdir}/t_client_ips.rc" +else + echo "NOTICE: missing t_client_ips.rc will be auto-generated" +fi + # # remote host (used as macro below) # @@ -58,8 +66,6 @@ OPENVPN_BASE_P2P="..." # RUN_TITLE_1="testing tun/udp/ipv4+ipv6" OPENVPN_CONF_1="$OPENVPN_BASE_P2MP --dev tun --proto udp --remote $REMOTE --port 51194" -EXPECT_IFCONFIG4_1="10.100.50.6" -EXPECT_IFCONFIG6_1="2001:db8:a050::1:0" PING4_HOSTS_1="10.100.50.1 10.100.0.1" PING6_HOSTS_1="2001:db8::1 2001:db8:a050::1" @@ -67,8 +73,6 @@ PING6_HOSTS_1="2001:db8::1 2001:db8:a050::1" # RUN_TITLE_2="testing tun/tcp/ipv4+ipv6" OPENVPN_CONF_2="$OPENVPN_BASE_P2MP --dev tun --proto tcp --remote $REMOTE --port 51194" -EXPECT_IFCONFIG4_2="10.100.51.6" -EXPECT_IFCONFIG6_2="2001:db8:a051::1:0" PING4_HOSTS_2="10.100.51.1 10.100.0.1" PING6_HOSTS_2="2001:db8::1 2001:db8:a051::1" diff --git a/tests/t_client.sh.in b/tests/t_client.sh.in index 2b9bacf581d..d1c5d873734 100755 --- a/tests/t_client.sh.in +++ b/tests/t_client.sh.in @@ -271,6 +271,12 @@ do eval ping4_hosts=\"\$PING4_HOSTS_$SUF\" eval ping6_hosts=\"\$PING6_HOSTS_$SUF\" + # If EXCEPT_IFCONFIG* variables for this test are missing, run an --up + # script to generate them dynamically. + if [ -z "$expect_ifconfig4" ] || [ -z "$expect_ifconfig6" ]; then + up="--setenv TESTNUM $SUF --setenv TOP_BUILDDIR ${top_builddir} --script-security 2 --up ${top_builddir}/tests/update_t_client_ips.sh" + fi + echo -e "\n### test run $SUF: '$test_run_title' ###\n" fail_count=0 @@ -294,7 +300,7 @@ do fi pidfile="${top_builddir}/tests/$LOGDIR/openvpn-$SUF.pid" - openvpn_conf="$openvpn_conf --writepid $pidfile" + openvpn_conf="$openvpn_conf --writepid $pidfile $up" echo " run openvpn $openvpn_conf" echo "# src/openvpn/openvpn $openvpn_conf" >$LOGDIR/$SUF:openvpn.log umask 022 diff --git a/tests/update_t_client_ips.sh b/tests/update_t_client_ips.sh new file mode 100755 index 00000000000..e7b58ba2a23 --- /dev/null +++ b/tests/update_t_client_ips.sh @@ -0,0 +1,7 @@ +#!/bin/sh +# +# This --up script caches the IPs handed out by the test VPN server to a file +# for later use. + +echo "EXPECT_IFCONFIG4_$TESTNUM=$ifconfig_local" >> $TOP_BUILDDIR/t_client_ips.rc +echo "EXPECT_IFCONFIG6_$TESTNUM=$ifconfig_ipv6_local" >> $TOP_BUILDDIR/t_client_ips.rc From 8ca29af7c6d4759ce019ec9d0cd3eae4511a6804 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Sun, 2 Oct 2016 15:19:23 +0200 Subject: [PATCH 316/643] make t_client robust against sudoers misconfiguration Instead of testing (and priming) sudo with "true", prime with "kill -0 $$" (just test signalling ourselves). If this fails, we won't be able to kill the openvpn process we're going to start later on -> thus, SKIP on failure. This helps with misconfigured setups (especially on the buildbots) that can correctly start openvpn but then not stop it later on - leaving openvpn processes dangling around, requiring manual intervention. Signed-off-by: Gert Doering Acked-by: Arne Schwabe Message-Id: <20161002131923.36681-1-gert@greenie.muc.de> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12585.html Signed-off-by: Gert Doering --- tests/t_client.sh.in | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/t_client.sh.in b/tests/t_client.sh.in index d1c5d873734..b2428b96aaa 100755 --- a/tests/t_client.sh.in +++ b/tests/t_client.sh.in @@ -42,12 +42,6 @@ if [ $? -ne 0 ]; then exit 77 fi -TRUE_EXEC=`which true` -if [ $? -ne 0 ]; then - echo "$0: true not found in \$PATH" >&2 - exit 77 -fi - if [ ! -x "${top_builddir}/src/openvpn/openvpn" ] then echo "no (executable) openvpn binary in current build tree. FAIL." >&2 @@ -102,7 +96,13 @@ else # We have to use sudo. Make sure that we (hopefully) do not have # to ask the users password during the test. This is done to # prevent timing issues, e.g. when the waits for openvpn to start - $RUN_SUDO $TRUE_EXEC + if $RUN_SUDO $KILL_EXEC -0 $$ + then + echo "$0: $RUN_SUDO $KILL_EXEC -0 succeeded, good." + else + echo "$0: $RUN_SUDO $KILL_EXEC -0 failed, cannot go on. SKIP." >&2 + exit 77 + fi fi fi From 5a1daf533ae283e258732260c96461e820e61fe6 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sun, 11 Sep 2016 16:50:31 +0200 Subject: [PATCH 317/643] Update cipher-related man page text As reported in trac #732, the man page text for --cipher is no longer accurate. Update the text to represent current knowledge, about NCP and SWEET32. This does not hint at changing the default cipher, because we did not make a decision on that yet. If we do change the default cipher, we'll have to update the text to reflect that. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1473605431-20842-1-git-send-email-steffan@karger.me> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12439.html Signed-off-by: Gert Doering --- doc/openvpn.8 | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 2d159440d9a..1c341ae7d49 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -4110,25 +4110,26 @@ Encrypt data channel packets with cipher algorithm The default is .B BF-CBC, an abbreviation for Blowfish in Cipher Block Chaining mode. -Blowfish has the advantages of being fast, very secure, and allowing key sizes -of up to 448 bits. Blowfish is designed to be used in situations where -keys are changed infrequently. -For more information on blowfish, see -.I http://www.counterpane.com/blowfish.html +Using BF-CBC is no longer recommended, because of it's 64-bit block size. This +small block size allows attacks based on collisions, as demonstrated by SWEET32. -To see other ciphers that are available with -OpenVPN, use the +To see other ciphers that are available with OpenVPN, use the .B \-\-show\-ciphers option. -OpenVPN supports the CBC, CFB, and OFB cipher modes, -however CBC is recommended and CFB and OFB should -be considered advanced modes. - Set .B alg=none to disable encryption. + +As of OpenVPN 2.4, cipher negotiation (NCP) can override the cipher specified by +.B \-\-cipher\fR. +See +.B \-\-ncp-ciphers +and +.B \-\-ncp-disable +for more on NCP. + .\"********************************************************* .TP .B \-\-ncp\-ciphers cipher_list @@ -4141,6 +4142,19 @@ is a colon-separated list of ciphers, and defaults to For servers, the first cipher from .B cipher_list will be pushed to clients that support cipher negotiation. + +Cipher negotiation is enabled in client-server mode only. I.e. if +.B \-\-mode +is set to 'server' (server-side, implied by setting +.B \-\-server +), or if +.B \-\-pull +is specified (client-side, implied by setting \-\-client). + +If both peers support and do not disable NCP, the negotiated cipher will +override the cipher specified by +.B \-\-cipher\fR. + .\"********************************************************* .TP .B \-\-ncp\-disable From bae1ad7005fd9a1fadeed56370a9ac5422a33fee Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Tue, 4 Oct 2016 13:38:54 +0200 Subject: [PATCH 318/643] add POSTINIT_CMD_suf to t_client.sh and sample config We have pre-init and cleanup commands, but some test cases might need or want to run a shell script after openvpn has initialized, but before executing any tests (ifconfig comparison and ping). Example: POSTINIT_CMD_4="sleep 5" on MacOS X for tap tests (IPv6 DAD) Signed-off-by: Gert Doering Acked-by: Arne Schwabe Message-Id: <20161004113854.42470-1-gert@greenie.muc.de> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12594.html Signed-off-by: Gert Doering --- tests/t_client.rc-sample | 3 +++ tests/t_client.sh.in | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/tests/t_client.rc-sample b/tests/t_client.rc-sample index fb2abfae24f..59f34c7f27e 100644 --- a/tests/t_client.rc-sample +++ b/tests/t_client.rc-sample @@ -75,6 +75,9 @@ RUN_TITLE_2="testing tun/tcp/ipv4+ipv6" OPENVPN_CONF_2="$OPENVPN_BASE_P2MP --dev tun --proto tcp --remote $REMOTE --port 51194" PING4_HOSTS_2="10.100.51.1 10.100.0.1" PING6_HOSTS_2="2001:db8::1 2001:db8:a051::1" +# +# run command after openvpn initialization is done - here: delay 5 seconds +POSTINIT_CMD_2="sleep 5" # Test 3: UDP / p2p tun # ... diff --git a/tests/t_client.sh.in b/tests/t_client.sh.in index b2428b96aaa..6c81bc41292 100755 --- a/tests/t_client.sh.in +++ b/tests/t_client.sh.in @@ -263,6 +263,7 @@ for SUF in $TEST_RUN_LIST do # get config variables eval test_prep=\"\$PREPARE_$SUF\" + eval test_postinit=\"\$POSTINIT_CMD_$SUF\" eval test_cleanup=\"\$CLEANUP_$SUF\" eval test_run_title=\"\$RUN_TITLE_$SUF\" eval openvpn_conf=\"\$OPENVPN_CONF_$SUF\" @@ -362,6 +363,12 @@ do echo -e " OK!\n" fi + # post init script needed? + if [ -n "$test_postinit" ]; then + echo -e "running post-init cmd: '$test_postinit'" + eval $test_postinit + fi + # expected ifconfig values in there? check_ifconfig 4 "$expect_ifconfig4" check_ifconfig 6 "$expect_ifconfig6" From 3fb246e38fc670c7dfff8ce4521c75c95c766c9e Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Sun, 9 Oct 2016 12:09:29 +0200 Subject: [PATCH 319/643] Fix --multihome for IPv6 on 64bit BSD systems. The old code only worked if "struct openvpn*pktinfo" happened to use the same structure packing as the CMSG_SPACE() / CMSG_LEN() macros (which are part of the official API, see RFC 2292). Get rid of "struct openvpn_*_pktinfo" definitions, replace them by an opaque buffer sized large enough to fit IPv4 and IPv6 packet info messages, as defined by CMSG_SPACE(sizeof(struct ...)). On 32 bit platforms, the net result is the same. On 64 bit platforms, the new buffer is bigger than openvpn_pktinfo was, fixing an overflow with ipi6_ifindex corruption on reception, and EINVAL on sendmsg(). The IPv4 related changes are only side effects of using the new buffer. Fixes: FreeBSD 10.3/amd64, FreeBSD 9.3/sparc64, OpenBSD 6.0/amd64, NetBSD 7.0.1/i386. Note: --multihome for IPv4 on NetBSD is still broken and non-fixable(!) as NetBSD lacks the necessary kernel code for the sendmsg() side. Verified that "--multihome works as well as before" on FreeBSD 7.4/amd64, NetBSD 5.1/amd64, OpenBSD 4.9/i386, Linux/x86_64, Linux/i386, OpenSolaris 10 (--multihome needs -D_XPG4_2, see trac #750) See also: ip(4), ip6(4), recv(2) Trac #634, #327, #28 Signed-off-by: Gert Doering Acked-by: Arne Schwabe Message-Id: <20161009100929.46472-1-gert@greenie.muc.de> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12626.html Signed-off-by: Gert Doering --- src/openvpn/socket.c | 57 +++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 32 deletions(-) diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c index e0961323270..184c7ad9b36 100644 --- a/src/openvpn/socket.c +++ b/src/openvpn/socket.c @@ -2863,27 +2863,16 @@ link_socket_read_tcp (struct link_socket *sock, #if ENABLE_IP_PKTINFO -#pragma pack(1) /* needed to keep structure size consistent for 32 vs. 64-bit architectures */ -struct openvpn_in4_pktinfo -{ - struct cmsghdr cmsghdr; +/* make the buffer large enough to handle ancilliary socket data for + * both IPv4 and IPv6 destination addresses, plus padding (see RFC 2292) + */ #if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) - struct in_pktinfo pi4; -#elif defined(IP_RECVDSTADDR) - struct in_addr pi4; +#define PKTINFO_BUF_SIZE max_int( CMSG_SPACE(sizeof (struct in6_pktinfo)), \ + CMSG_SPACE(sizeof (struct in_pktinfo)) ) +#else +#define PKTINFO_BUF_SIZE max_int( CMSG_SPACE(sizeof (struct in6_pktinfo)), \ + CMSG_SPACE(sizeof (struct in_addr)) ) #endif -}; -struct openvpn_in6_pktinfo -{ - struct cmsghdr cmsghdr; - struct in6_pktinfo pi6; -}; - -union openvpn_pktinfo { - struct openvpn_in4_pktinfo msgpi4; - struct openvpn_in6_pktinfo msgpi6; -}; -#pragma pack() static socklen_t link_socket_read_udp_posix_recvmsg (struct link_socket *sock, @@ -2891,7 +2880,7 @@ link_socket_read_udp_posix_recvmsg (struct link_socket *sock, struct link_socket_actual *from) { struct iovec iov; - union openvpn_pktinfo opi; + uint8_t pktinfo_buf[PKTINFO_BUF_SIZE]; struct msghdr mesg; socklen_t fromlen = sizeof (from->dest.addr); @@ -2901,8 +2890,8 @@ link_socket_read_udp_posix_recvmsg (struct link_socket *sock, mesg.msg_iovlen = 1; mesg.msg_name = &from->dest.addr; mesg.msg_namelen = fromlen; - mesg.msg_control = &opi; - mesg.msg_controllen = sizeof opi; + mesg.msg_control = pktinfo_buf; + mesg.msg_controllen = sizeof pktinfo_buf; buf->len = recvmsg (sock->sd, &mesg, 0); if (buf->len >= 0) { @@ -2914,13 +2903,14 @@ link_socket_read_udp_posix_recvmsg (struct link_socket *sock, #if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) && cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_PKTINFO + && cmsg->cmsg_len >= CMSG_LEN(sizeof(struct in_pktinfo)) ) #elif defined(IP_RECVDSTADDR) && cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_RECVDSTADDR + && cmsg->cmsg_len >= CMSG_LEN(sizeof(struct in_addr)) ) #else #error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h) #endif - && cmsg->cmsg_len >= sizeof (struct openvpn_in4_pktinfo)) { #if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) struct in_pktinfo *pkti = (struct in_pktinfo *) CMSG_DATA (cmsg); @@ -2936,7 +2926,7 @@ link_socket_read_udp_posix_recvmsg (struct link_socket *sock, && CMSG_NXTHDR (&mesg, cmsg) == NULL && cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO - && cmsg->cmsg_len >= sizeof (struct openvpn_in6_pktinfo)) + && cmsg->cmsg_len >= CMSG_LEN(sizeof(struct in6_pktinfo)) ) { struct in6_pktinfo *pkti6 = (struct in6_pktinfo *) CMSG_DATA (cmsg); from->pi.in6.ipi6_ifindex = pkti6->ipi6_ifindex; @@ -3007,7 +2997,7 @@ link_socket_write_udp_posix_sendmsg (struct link_socket *sock, struct iovec iov; struct msghdr mesg; struct cmsghdr *cmsg; - union openvpn_pktinfo opi; + uint8_t pktinfo_buf[PKTINFO_BUF_SIZE]; iov.iov_base = BPTR (buf); iov.iov_len = BLEN (buf); @@ -3019,12 +3009,12 @@ link_socket_write_udp_posix_sendmsg (struct link_socket *sock, { mesg.msg_name = &to->dest.addr.sa; mesg.msg_namelen = sizeof (struct sockaddr_in); - mesg.msg_control = &opi; + mesg.msg_control = pktinfo_buf; mesg.msg_flags = 0; #if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) - mesg.msg_controllen = sizeof (struct openvpn_in4_pktinfo); + mesg.msg_controllen = CMSG_SPACE(sizeof (struct in_pktinfo)); cmsg = CMSG_FIRSTHDR (&mesg); - cmsg->cmsg_len = sizeof (struct openvpn_in4_pktinfo); + cmsg->cmsg_len = CMSG_LEN(sizeof (struct in_pktinfo)); cmsg->cmsg_level = SOL_IP; cmsg->cmsg_type = IP_PKTINFO; { @@ -3035,7 +3025,7 @@ link_socket_write_udp_posix_sendmsg (struct link_socket *sock, pkti->ipi_addr.s_addr = 0; } #elif defined(IP_RECVDSTADDR) - ASSERT( CMSG_SPACE(sizeof (struct in_addr)) <= sizeof(opi) ); + ASSERT( CMSG_SPACE(sizeof (struct in_addr)) <= sizeof(pktinfo_buf) ); mesg.msg_controllen = CMSG_SPACE(sizeof (struct in_addr)); cmsg = CMSG_FIRSTHDR (&mesg); cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr)); @@ -3052,13 +3042,16 @@ link_socket_write_udp_posix_sendmsg (struct link_socket *sock, struct in6_pktinfo *pkti6; mesg.msg_name = &to->dest.addr.sa; mesg.msg_namelen = sizeof (struct sockaddr_in6); - mesg.msg_control = &opi; - mesg.msg_controllen = sizeof (struct openvpn_in6_pktinfo); + + ASSERT( CMSG_SPACE(sizeof (struct in6_pktinfo)) <= sizeof(pktinfo_buf) ); + mesg.msg_control = pktinfo_buf; + mesg.msg_controllen = CMSG_SPACE(sizeof (struct in6_pktinfo)); mesg.msg_flags = 0; cmsg = CMSG_FIRSTHDR (&mesg); - cmsg->cmsg_len = sizeof (struct openvpn_in6_pktinfo); + cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); cmsg->cmsg_level = IPPROTO_IPV6; cmsg->cmsg_type = IPV6_PKTINFO; + pkti6 = (struct in6_pktinfo *) CMSG_DATA (cmsg); pkti6->ipi6_ifindex = to->pi.in6.ipi6_ifindex; pkti6->ipi6_addr = to->pi.in6.ipi6_addr; From 6eaa70e80aea7dfd1b3114fcb369a8f72c19ceee Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Mon, 10 Oct 2016 09:39:31 +0200 Subject: [PATCH 320/643] Enable -D_SVR4_2 for compilation on Solaris Solaris' header files to not make necessary macros (like CMSG_SPACE) available unless told "this is the API level we want" - thus, do so. This fixes --multihome on OpenSolaris 11 (at least). trac #750 Signed-off-by: Gert Doering Acked-by: Arne Schwabe Message-Id: <20161010073931.54469-1-gert@greenie.muc.de> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12634.html Signed-off-by: Gert Doering --- configure.ac | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.ac b/configure.ac index a03abbaac04..24b2e468c13 100644 --- a/configure.ac +++ b/configure.ac @@ -318,6 +318,7 @@ case "$host" in *-*-solaris*) AC_DEFINE([TARGET_SOLARIS], [1], [Are we running on Solaris?]) AC_DEFINE_UNQUOTED([TARGET_PREFIX], ["S"], [Target prefix]) + CPPFLAGS="$CPPFLAGS -D_XPG4_2" ;; *-*-openbsd*) AC_DEFINE([TARGET_OPENBSD], [1], [Are we running on OpenBSD?]) From 3cf51f613c4d0ac0982826cd2e27e1f34bcd1a83 Mon Sep 17 00:00:00 2001 From: Lev Stipakov Date: Tue, 4 Oct 2016 23:20:03 +0300 Subject: [PATCH 321/643] Exclude peer-id from pulled options digest v2: - Move digest update to separate method Peer-id might change on restart and this should not trigger reopening tun. Trac #649 Acked-by: Steffan Karger Message-Id: <1475612403-1266-1-git-send-email-lstipakov@gmail.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12599.html Signed-off-by: Gert Doering --- src/openvpn/push.c | 45 ++++++++++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/src/openvpn/push.c b/src/openvpn/push.c index a1b999e2d97..c0c78a02955 100644 --- a/src/openvpn/push.c +++ b/src/openvpn/push.c @@ -597,6 +597,20 @@ process_incoming_push_request (struct context *c) } #endif +static void +push_update_digest(md_ctx_t *ctx, struct buffer *buf) +{ + char line[OPTION_PARM_SIZE]; + while (buf_parse (buf, ',', line, sizeof (line))) + { + /* peer-id might change on restart and this should not trigger reopening tun */ + if (strstr (line, "peer-id ") != line) + { + md_ctx_update (ctx, (const uint8_t *) line, strlen(line)); + } + } +} + int process_incoming_push_msg (struct context *c, const struct buffer *buffer, @@ -636,21 +650,22 @@ process_incoming_push_msg (struct context *c, permission_mask, option_types_found, c->c2.es)) - switch (c->options.push_continuation) - { - case 0: - case 1: - md_ctx_update (&c->c2.pulled_options_state, BPTR(&buf_orig), BLEN(&buf_orig)); - md_ctx_final (&c->c2.pulled_options_state, c->c2.pulled_options_digest.digest); - md_ctx_cleanup (&c->c2.pulled_options_state); - c->c2.pulled_options_md5_init_done = false; - ret = PUSH_MSG_REPLY; - break; - case 2: - md_ctx_update (&c->c2.pulled_options_state, BPTR(&buf_orig), BLEN(&buf_orig)); - ret = PUSH_MSG_CONTINUATION; - break; - } + { + push_update_digest (&c->c2.pulled_options_state, &buf_orig); + switch (c->options.push_continuation) + { + case 0: + case 1: + md_ctx_final (&c->c2.pulled_options_state, c->c2.pulled_options_digest.digest); + md_ctx_cleanup (&c->c2.pulled_options_state); + c->c2.pulled_options_md5_init_done = false; + ret = PUSH_MSG_REPLY; + break; + case 2: + ret = PUSH_MSG_CONTINUATION; + break; + } + } } else if (ch == '\0') { From 974ec19daa6c9d4e954912b3743c7101637f1d33 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Thu, 29 Sep 2016 19:48:29 +0200 Subject: [PATCH 322/643] Fix duplicate PUSH_REPLY options As reported by Lev Stipakov, starting from 3a5a46cf we add peer-id and cipher values to context->options->push_list instead of adding those directly to buf. Since push_list is preserved over sigusr1 restarts, we add duplicate values for peer-id and cipher. Fixed by removing the previous values from the list before adding new ones. Signed-off-by: Steffan Karger Acked-by: Lev Stipakov Message-Id: URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12642.html Signed-off-by: Gert Doering --- src/openvpn/errlevel.h | 1 + src/openvpn/options.c | 1 + src/openvpn/push.c | 6 ++++-- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/openvpn/errlevel.h b/src/openvpn/errlevel.h index da600ab8a18..ae1f8f49768 100644 --- a/src/openvpn/errlevel.h +++ b/src/openvpn/errlevel.h @@ -147,6 +147,7 @@ #define D_PID_DEBUG LOGLEV(7, 70, M_DEBUG) /* show packet-id debugging info */ #define D_PF_DROPPED_BCAST LOGLEV(7, 71, M_DEBUG) /* packet filter dropped a broadcast packet */ #define D_PF_DEBUG LOGLEV(7, 72, M_DEBUG) /* packet filter debugging, must also define PF_DEBUG in pf.h */ +#define D_PUSH_DEBUG LOGLEV(7, 73, M_DEBUG) /* show push/pull debugging info */ #define D_HANDSHAKE_VERBOSE LOGLEV(8, 70, M_DEBUG) /* show detailed description of each handshake */ #define D_TLS_DEBUG_MED LOGLEV(8, 70, M_DEBUG) /* limited info from tls_session routines */ diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 9f6099c20e0..e1ff5849074 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -5787,6 +5787,7 @@ add_option (struct options *options, else if (streq (p[0], "push-remove") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_INSTANCE); + msg (D_PUSH, "PUSH_REMOVE '%s'", p[1]); push_remove_option (options,p[1]); } else if (streq (p[0], "ifconfig-pool") && p[1] && p[2] && !p[4]) diff --git a/src/openvpn/push.c b/src/openvpn/push.c index c0c78a02955..df4f596a1c9 100644 --- a/src/openvpn/push.c +++ b/src/openvpn/push.c @@ -314,6 +314,7 @@ prepare_push_reply (struct options *o, struct tls_multi *tls_multi) int r = sscanf(optstr, "IV_PROTO=%d", &proto); if ((r == 1) && (proto >= 2)) { + push_remove_option(o, "peer-id"); push_option_fmt(o, M_USAGE, "peer-id %d", tls_multi->peer_id); } } @@ -337,6 +338,7 @@ prepare_push_reply (struct options *o, struct tls_multi *tls_multi) * TODO: actual negotiation, instead of server dictatorship. */ char *push_cipher = string_alloc(o->ncp_ciphers, &o->gc); o->ciphername = strtok (push_cipher, ":"); + push_remove_option(o, "cipher"); push_option_fmt(o, M_USAGE, "cipher %s", o->ciphername); } } @@ -525,7 +527,7 @@ push_reset (struct options *o) void push_remove_option (struct options *o, const char *p) { - msg( D_PUSH, "PUSH_REMOVE '%s'", p ); + msg (D_PUSH_DEBUG, "PUSH_REMOVE searching for: '%s'", p); /* ifconfig-ipv6 is special, as not part of the push list */ if ( streq( p, "ifconfig-ipv6" )) @@ -544,7 +546,7 @@ push_remove_option (struct options *o, const char *p) if ( e->enable && strncmp( e->option, p, strlen(p) ) == 0 ) { - msg (D_PUSH, "PUSH_REMOVE removing: '%s'", e->option); + msg (D_PUSH_DEBUG, "PUSH_REMOVE removing: '%s'", e->option); e->enable = false; } From e25d03a4cc0664f6ece067facb1bc8e38134f396 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Mon, 10 Oct 2016 19:36:20 +0200 Subject: [PATCH 323/643] Revert "Enable -D_SVR4_2 for compilation on Solaris" This reverts commit 6eaa70e80aea7dfd1b3114fcb369a8f72c19ceee. (the description was incorrect and the patch was already pushed out) --- configure.ac | 1 - 1 file changed, 1 deletion(-) diff --git a/configure.ac b/configure.ac index 24b2e468c13..a03abbaac04 100644 --- a/configure.ac +++ b/configure.ac @@ -318,7 +318,6 @@ case "$host" in *-*-solaris*) AC_DEFINE([TARGET_SOLARIS], [1], [Are we running on Solaris?]) AC_DEFINE_UNQUOTED([TARGET_PREFIX], ["S"], [Target prefix]) - CPPFLAGS="$CPPFLAGS -D_XPG4_2" ;; *-*-openbsd*) AC_DEFINE([TARGET_OPENBSD], [1], [Are we running on OpenBSD?]) From 4e2038ed2e77aa7189852304d802382bad140f53 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Mon, 10 Oct 2016 09:39:31 +0200 Subject: [PATCH 324/643] Enable -D_XPG4_2 for compilation on Solaris Solaris' header files to not make necessary macros (like CMSG_SPACE) available unless told "this is the API level we want" - thus, do so. This fixes --multihome on OpenSolaris 11 (at least). (v2: same patch as in 6eaa70e80aea7, reverted in e25d03a4cc0, and now with correct description) trac #750 Signed-off-by: Gert Doering Acked-by: Arne Schwabe Message-Id: <20161010073931.54469-1-gert@greenie.muc.de> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12634.html Signed-off-by: Gert Doering --- configure.ac | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.ac b/configure.ac index a03abbaac04..24b2e468c13 100644 --- a/configure.ac +++ b/configure.ac @@ -318,6 +318,7 @@ case "$host" in *-*-solaris*) AC_DEFINE([TARGET_SOLARIS], [1], [Are we running on Solaris?]) AC_DEFINE_UNQUOTED([TARGET_PREFIX], ["S"], [Target prefix]) + CPPFLAGS="$CPPFLAGS -D_XPG4_2" ;; *-*-openbsd*) AC_DEFINE([TARGET_OPENBSD], [1], [Are we running on OpenBSD?]) From 55755e6ee56516c96525e6bf313c173653af1a4b Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Sat, 17 Sep 2016 16:15:38 +0200 Subject: [PATCH 325/643] Enable TCP non-linear packet ID Implementation with multiple threads needs that to be able run encryption in parallel. Tested with James' OpenVPN 3 server. Acked-by: Gert Doering Message-Id: <1474121738-19420-1-git-send-email-arne@rfc2549.org> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12513.html Signed-off-by: Gert Doering --- src/openvpn/comp.c | 1 + src/openvpn/init.c | 1 - src/openvpn/options.c | 5 ----- src/openvpn/packet_id.c | 7 +++---- src/openvpn/packet_id.h | 2 +- src/openvpn/ssl.c | 3 +-- 6 files changed, 6 insertions(+), 13 deletions(-) diff --git a/src/openvpn/comp.c b/src/openvpn/comp.c index 3a32c62814d..499fef98d86 100644 --- a/src/openvpn/comp.c +++ b/src/openvpn/comp.c @@ -160,6 +160,7 @@ comp_generate_peer_info_string(const struct compress_options *opt, struct buffer buf_printf (out, "IV_LZO_STUB=1\n"); buf_printf (out, "IV_COMP_STUB=1\n"); buf_printf (out, "IV_COMP_STUBv2=1\n"); + buf_printf (out, "IV_TCPNL=1\n"); } } diff --git a/src/openvpn/init.c b/src/openvpn/init.c index e3206b05e9b..af5d4913066 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -2140,7 +2140,6 @@ do_init_crypto_static (struct context *c, const unsigned int flags) if (options->replay) { packet_id_init (&c->c2.crypto_options.packet_id, - link_socket_proto_connection_oriented (options->ce.proto), options->replay_window, options->replay_time, "STATIC", 0); diff --git a/src/openvpn/options.c b/src/openvpn/options.c index e1ff5849074..2998f06ed62 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -2211,11 +2211,6 @@ options_postprocess_verify_ce (const struct options *options, const struct conne /* * Check consistency of replay options */ - if ((!proto_is_udp(ce->proto)) - && (options->replay_window != defaults.replay_window - || options->replay_time != defaults.replay_time)) - msg (M_USAGE, "--replay-window only makes sense with --proto udp"); - if (!options->replay && (options->replay_window != defaults.replay_window || options->replay_time != defaults.replay_time)) diff --git a/src/openvpn/packet_id.c b/src/openvpn/packet_id.c index baa496643c2..987451929c7 100644 --- a/src/openvpn/packet_id.c +++ b/src/openvpn/packet_id.c @@ -76,10 +76,9 @@ packet_id_debug (int msglevel, } void -packet_id_init (struct packet_id *p, bool tcp_mode, int seq_backtrack, int time_backtrack, const char *name, int unit) +packet_id_init (struct packet_id *p, int seq_backtrack, int time_backtrack, const char *name, int unit) { - dmsg (D_PID_DEBUG, "PID packet_id_init tcp_mode=%d seq_backtrack=%d time_backtrack=%d", - tcp_mode, + dmsg (D_PID_DEBUG, "PID packet_id_init seq_backtrack=%d time_backtrack=%d", seq_backtrack, time_backtrack); @@ -88,7 +87,7 @@ packet_id_init (struct packet_id *p, bool tcp_mode, int seq_backtrack, int time_ p->rec.name = name; p->rec.unit = unit; - if (seq_backtrack && !tcp_mode) + if (seq_backtrack) { ASSERT (MIN_SEQ_BACKTRACK <= seq_backtrack && seq_backtrack <= MAX_SEQ_BACKTRACK); ASSERT (MIN_TIME_BACKTRACK <= time_backtrack && time_backtrack <= MAX_TIME_BACKTRACK); diff --git a/src/openvpn/packet_id.h b/src/openvpn/packet_id.h index 5eb501d1084..fb059b7d16f 100644 --- a/src/openvpn/packet_id.h +++ b/src/openvpn/packet_id.h @@ -210,7 +210,7 @@ struct packet_id struct packet_id_rec rec; }; -void packet_id_init (struct packet_id *p, bool tcp_mode, int seq_backtrack, int time_backtrack, const char *name, int unit); +void packet_id_init (struct packet_id *p, int seq_backtrack, int time_backtrack, const char *name, int unit); void packet_id_free (struct packet_id *p); /* should we accept an incoming packet id ? */ diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index caf3b1f6264..420164e7726 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -799,7 +799,7 @@ key_state_init (struct tls_session *session, struct key_state *ks) /* init packet ID tracker */ if (session->opt->replay) { - packet_id_init (&ks->crypto_options.packet_id, session->opt->tcp_mode, + packet_id_init (&ks->crypto_options.packet_id, session->opt->replay_window, session->opt->replay_time, "SSL", ks->key_id); } @@ -948,7 +948,6 @@ tls_session_init (struct tls_multi *multi, struct tls_session *session) /* initialize packet ID replay window for --tls-auth */ packet_id_init (&session->tls_auth.packet_id, - session->opt->tcp_mode, session->opt->replay_window, session->opt->replay_time, "TLS_AUTH", session->key_id); From 430ce8bd03b23717ec42a8a34aa66e804ca97287 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Fri, 26 Aug 2016 19:48:52 +0200 Subject: [PATCH 326/643] Rework the user input interface to make it more modular This is will provide an interface for other mechanisms to be used to query the user for information, such as usernames, passwords, etc. It has also been a goal to make it possible to query for all the information in one call and not do it sequencially as before. [v5 - Ensure password prompt is only displayed if we should read from stdin ] [v4 - add a simple wrapper combining query_user_{init,add,exec}() - change disapproved &= syntax ] [v3 - Avoid the dynamic list, use a static list of QUERY_USER_NUMSLOTS - The list of query_user data is now a global variable - Replaced query_user_init() with query_user_clear() - Make query_user_add() a void function - Rebased against master/600dd9a16fc61 ] [v2 - Removed the QUERY_USER_FOREACH macro - Avoided using underscore prefix in function names - Make query_user_init() do M_FATAL and become a void function instead of returning false in these unlikely situations ] Signed-off-by: David Sommerseth Acked-by: Selva Nair Message-Id: 1472233732-27074-1-git-send-email-davids@openvpn.net URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg00137.html --- src/openvpn/Makefile.am | 2 +- src/openvpn/console.c | 228 ++++------------------------- src/openvpn/console.h | 89 +++++++++++- src/openvpn/console_builtin.c | 261 ++++++++++++++++++++++++++++++++++ src/openvpn/misc.c | 61 +++++--- src/openvpn/pkcs11.c | 7 +- 6 files changed, 423 insertions(+), 225 deletions(-) create mode 100644 src/openvpn/console_builtin.c diff --git a/src/openvpn/Makefile.am b/src/openvpn/Makefile.am index 9d4bf618237..8d6d39ffefe 100644 --- a/src/openvpn/Makefile.am +++ b/src/openvpn/Makefile.am @@ -68,7 +68,7 @@ openvpn_SOURCES = \ memdbg.h \ misc.c misc.h \ platform.c platform.h \ - console.c console.h \ + console.c console.h console_builtin.c \ mroute.c mroute.h \ mss.c mss.h \ mstats.c mstats.h \ diff --git a/src/openvpn/console.c b/src/openvpn/console.c index 86331a11c23..c3bb7c3de41 100644 --- a/src/openvpn/console.c +++ b/src/openvpn/console.c @@ -6,6 +6,8 @@ * packet compression. * * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2014-2015 David Sommerseth + * Copyright (C) 2016 David Sommerseth * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -38,219 +40,43 @@ #include #endif -#ifdef WIN32 -#include "win32.h" +struct _query_user query_user[QUERY_USER_NUMSLOTS]; /* GLOBAL */ -/* - * Get input from console. - * - * Return false on input error, or if service - * exit event is signaled. - */ - -static bool -get_console_input_win32 (const char *prompt, const bool echo, char *input, const int capacity) -{ - HANDLE in = INVALID_HANDLE_VALUE; - HANDLE err = INVALID_HANDLE_VALUE; - DWORD len = 0; - - ASSERT (prompt); - ASSERT (input); - ASSERT (capacity > 0); - - input[0] = '\0'; - - in = GetStdHandle (STD_INPUT_HANDLE); - err = get_orig_stderr (); - - if (in != INVALID_HANDLE_VALUE - && err != INVALID_HANDLE_VALUE - && !win32_service_interrupt (&win32_signal) - && WriteFile (err, prompt, strlen (prompt), &len, NULL)) - { - bool is_console = (GetFileType (in) == FILE_TYPE_CHAR); - DWORD flags_save = 0; - int status = 0; - WCHAR *winput; - - if (is_console) - { - if (GetConsoleMode (in, &flags_save)) - { - DWORD flags = ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT; - if (echo) - flags |= ENABLE_ECHO_INPUT; - SetConsoleMode (in, flags); - } - else - is_console = 0; - } - - if (is_console) - { - winput = malloc (capacity * sizeof (WCHAR)); - if (winput == NULL) - return false; - - status = ReadConsoleW (in, winput, capacity, &len, NULL); - WideCharToMultiByte (CP_UTF8, 0, winput, len, input, capacity, NULL, NULL); - free (winput); - } - else - status = ReadFile (in, input, capacity, &len, NULL); - - string_null_terminate (input, (int)len, capacity); - chomp (input); - - if (!echo) - WriteFile (err, "\r\n", 2, &len, NULL); - if (is_console) - SetConsoleMode (in, flags_save); - if (status && !win32_service_interrupt (&win32_signal)) - return true; - } - - return false; -} - -#endif - -#ifdef HAVE_GETPASS - -static FILE * -open_tty (const bool write) -{ - FILE *ret; - ret = fopen ("/dev/tty", write ? "w" : "r"); - if (!ret) - ret = write ? stderr : stdin; - return ret; -} - -static void -close_tty (FILE *fp) -{ - if (fp != stderr && fp != stdin) - fclose (fp); -} - -#endif -#ifdef ENABLE_SYSTEMD - -/* - * is systemd running - */ - -static bool -check_systemd_running () +void query_user_clear() { - struct stat c; - - /* We simply test whether the systemd cgroup hierarchy is - * mounted, as well as the systemd-ask-password executable - * being available */ + int i; - return (sd_booted() > 0) - && (stat(SYSTEMD_ASK_PASSWORD_PATH, &c) == 0); - -} - -static bool -get_console_input_systemd (const char *prompt, const bool echo, char *input, const int capacity) -{ - int std_out; - bool ret = false; - struct argv argv; - - argv_init (&argv); - argv_printf (&argv, SYSTEMD_ASK_PASSWORD_PATH); - argv_printf_cat (&argv, "%s", prompt); - - if ((std_out = openvpn_popen (&argv, NULL)) < 0) { - return false; - } - - memset (input, 0, capacity); - if (read (std_out, input, capacity-1) > 0) - { - chomp (input); - ret = true; + for( i = 0; i < QUERY_USER_NUMSLOTS; i++ ) { + CLEAR(query_user[i]); } - close (std_out); - - argv_reset (&argv); - - return ret; } -#endif - -/* - * Get input from console - */ -bool -get_console_input (const char *prompt, const bool echo, char *input, const int capacity) +void query_user_add(char *prompt, size_t prompt_len, + char *resp, size_t resp_len, + bool echo) { - bool ret = false; - ASSERT (prompt); - ASSERT (input); - ASSERT (capacity > 0); - input[0] = '\0'; - -#ifdef ENABLE_SYSTEMD - if (check_systemd_running ()) - return get_console_input_systemd (prompt, echo, input, capacity); -#endif + int i; -#if defined(WIN32) - return get_console_input_win32 (prompt, echo, input, capacity); -#elif defined(HAVE_GETPASS) + /* Ensure input is sane. All these must be present otherwise it is + * a programming error. + */ + ASSERT( prompt_len > 0 && prompt != NULL && resp_len > 0 && resp != NULL ); - /* did we --daemon'ize before asking for passwords? - * (in which case neither stdin or stderr are connected to a tty and - * /dev/tty can not be open()ed anymore) - */ - if ( !isatty(0) && !isatty(2) ) - { - int fd = open( "/dev/tty", O_RDWR ); - if ( fd < 0 ) - { msg(M_FATAL, "neither stdin nor stderr are a tty device and you have neither a controlling tty nor systemd - can't ask for '%s'. If you used --daemon, you need to use --askpass to make passphrase-protected keys work, and you can not use --auth-nocache.", prompt ); } - close(fd); - } - - if (echo) - { - FILE *fp; - - fp = open_tty (true); - fprintf (fp, "%s", prompt); - fflush (fp); - close_tty (fp); - - fp = open_tty (false); - if (fgets (input, capacity, fp) != NULL) - { - chomp (input); - ret = true; + /* Seek to the last unused slot */ + for (i = 0; i < QUERY_USER_NUMSLOTS; i++) { + if( query_user[i].prompt == NULL ) { + break; } - close_tty (fp); } - else - { - char *gp = getpass (prompt); - if (gp) - { - strncpynt (input, gp, capacity); - memset (gp, 0, strlen (gp)); - ret = true; - } - } -#else - msg (M_FATAL, "Sorry, but I can't get console input on this OS (%s)", prompt); -#endif - return ret; + ASSERT( i < QUERY_USER_NUMSLOTS ); /* Unlikely, but we want to panic if it happens */ + + /* Save the information needed for the user interaction */ + query_user[i].prompt = prompt; + query_user[i].prompt_len = prompt_len; + query_user[i].response = resp; + query_user[i].response_len = resp_len; + query_user[i].echo = echo; } diff --git a/src/openvpn/console.h b/src/openvpn/console.h index 268f3febf3e..44d49efe238 100644 --- a/src/openvpn/console.h +++ b/src/openvpn/console.h @@ -6,6 +6,8 @@ * packet compression. * * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2014-2015 David Sommerseth + * Copyright (C) 2016 David Sommerseth * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -27,7 +29,90 @@ #include "basic.h" -bool -get_console_input (const char *prompt, const bool echo, char *input, const int capacity); +/** + * Configuration setup for declaring what kind of information to ask a user for + */ +struct _query_user { + char *prompt; /**< Prompt to present to the user */ + size_t prompt_len; /**< Lenght of the prompt string */ + char *response; /**< The user's response */ + size_t response_len; /**< Lenght the of the user reposone */ + bool echo; /**< True: The user should see what is being typed, otherwise mask it */ +}; + +#define QUERY_USER_NUMSLOTS 10 +extern struct _query_user query_user[]; /**< Global variable, declared in console.c */ + +/** + * Wipes all data put into all of the query_user structs + * + */ +void query_user_clear (); + + +/** + * Adds an item to ask the user for + * + * @param prompt Prompt to display to the user + * @param prompt_len Length of the prompt string + * @param resp String containing the user response + * @param resp_len Lenght of the response string + * @param echo Should the user input be echoed to the user? If False, input will be masked + * + */ +void query_user_add (char *prompt, size_t prompt_len, + char *resp, size_t resp_len, + bool echo); + + +/** + * Executes a configured setup, using the built-in method for querying the user. + * This method uses the console/TTY directly. + * + * @param setup Pointer to the setup defining what to ask the user + * + * @return True if executing all the defined steps completed successfully + */ +bool query_user_exec_builtin (); + + +#ifdef QUERY_USER_EXEC_ALTERNATIVE +/** + * Executes a configured setup, using the compiled method for querying the user + * + * @param setup Pointer to the setup defining what to ask the user + * + * @return True if executing all the defined steps completed successfully + */ +bool query_user_exec (); + +#else /* QUERY_USER_EXEC_ALTERNATIVE not defined*/ +/** + * Wrapper function enabling query_user_exec() if no alternative methods have + * been enabled + * + */ +static bool query_user_exec () +{ + return query_user_exec_builtin(); +} +#endif /* QUERY_USER_EXEC_ALTERNATIVE */ + + +/** + * A plain "make Gert happy" wrapper. Same arguments as @query_user_add + * + * FIXME/TODO: Remove this when refactoring the complete user query process + * to be called at start-up initialization of OpenVPN. + * + */ +static bool query_user_SINGLE (char *prompt, size_t prompt_len, + char *resp, size_t resp_len, + bool echo) +{ + query_user_clear(); + query_user_add(prompt, prompt_len, resp, resp_len, echo); + return query_user_exec(); +} #endif diff --git a/src/openvpn/console_builtin.c b/src/openvpn/console_builtin.c new file mode 100644 index 00000000000..0434f604d8a --- /dev/null +++ b/src/openvpn/console_builtin.c @@ -0,0 +1,261 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2002-2016 OpenVPN Technologies, Inc. + * Copyright (C) 2014-2015 David Sommerseth + * Copyright (C) 2016 David Sommerseth + * + * 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 + */ + +/* + * These functions covers handing user input/output using the default consoles + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#elif defined(_MSC_VER) +#include "config-msvc.h" +#endif + +#include "syshead.h" +#include "console.h" +#include "error.h" +#include "buffer.h" +#include "misc.h" + +#ifdef WIN32 + +#include "win32.h" + +/** + * Get input from a Windows console. + * + * @param prompt Prompt to display to the user + * @param echo Should the user input be displayed in the console + * @param input Pointer to the buffer the user input will be saved + * @param capacity Size of the buffer for the user input + * + * @return Return false on input error, or if service + * exit event is signaled. + */ +static bool get_console_input_win32 (const char *prompt, const bool echo, char *input, const int capacity) +{ + HANDLE in = INVALID_HANDLE_VALUE; + HANDLE err = INVALID_HANDLE_VALUE; + DWORD len = 0; + + ASSERT (prompt); + ASSERT (input); + ASSERT (capacity > 0); + + input[0] = '\0'; + + in = GetStdHandle (STD_INPUT_HANDLE); + err = get_orig_stderr (); + + if (in != INVALID_HANDLE_VALUE + && err != INVALID_HANDLE_VALUE + && !win32_service_interrupt (&win32_signal) + && WriteFile (err, prompt, strlen (prompt), &len, NULL)) + { + bool is_console = (GetFileType (in) == FILE_TYPE_CHAR); + DWORD flags_save = 0; + int status = 0; + WCHAR *winput; + + if (is_console) + { + if (GetConsoleMode (in, &flags_save)) + { + DWORD flags = ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT; + if (echo) + flags |= ENABLE_ECHO_INPUT; + SetConsoleMode (in, flags); + } else + is_console = 0; + } + + if (is_console) + { + winput = malloc (capacity * sizeof (WCHAR)); + if (winput == NULL) + return false; + + status = ReadConsoleW (in, winput, capacity, &len, NULL); + WideCharToMultiByte (CP_UTF8, 0, winput, len, input, capacity, NULL, NULL); + free (winput); + } else + status = ReadFile (in, input, capacity, &len, NULL); + + string_null_terminate (input, (int)len, capacity); + chomp (input); + + if (!echo) + WriteFile (err, "\r\n", 2, &len, NULL); + if (is_console) + SetConsoleMode (in, flags_save); + if (status && !win32_service_interrupt (&win32_signal)) + return true; + } + + return false; +} + +#endif /* WIN32 */ + + +#ifdef HAVE_GETPASS + +/** + * Open the current console TTY for read/write operations + * + * @params write If true, the user wants to write to the console + * otherwise read from the console + * + * @returns Returns a FILE pointer to either the TTY in read or write mode + * or stdin/stderr, depending on the write flag + * + */ +static FILE * open_tty (const bool write) +{ + FILE *ret; + ret = fopen ("/dev/tty", write ? "w" : "r"); + if (!ret) + ret = write ? stderr : stdin; + return ret; +} + +/** + * Closes the TTY FILE pointer, but only if it is not a stdin/stderr FILE object. + * + * @params fp FILE pointer to close + * + */ +static void close_tty (FILE *fp) +{ + if (fp != stderr && fp != stdin) + fclose (fp); +} + +#endif /* HAVE_GETPASS */ + + +/** + * Core function for getting input from console + * + * @params prompt The prompt to present to the user + * @params echo Should the user see what is being typed + * @params input Pointer to the buffer used to save the user input + * @params capacity Size of the input buffer + * + * @returns Returns True if user input was gathered + */ +static bool get_console_input (const char *prompt, const bool echo, char *input, const int capacity) +{ + bool ret = false; + ASSERT (prompt); + ASSERT (input); + ASSERT (capacity > 0); + input[0] = '\0'; + +#if defined(WIN32) + return get_console_input_win32 (prompt, echo, input, capacity); +#elif defined(HAVE_GETPASS) + + /* did we --daemon'ize before asking for passwords? + * (in which case neither stdin or stderr are connected to a tty and + * /dev/tty can not be open()ed anymore) + */ + if ( !isatty(0) && !isatty(2) ) + { + int fd = open( "/dev/tty", O_RDWR ); + if ( fd < 0 ) + { + msg(M_FATAL, "neither stdin nor stderr are a tty device and you have neither a " + "controlling tty nor systemd - can't ask for '%s'. If you used --daemon, " + "you need to use --askpass to make passphrase-protected keys work, and you " + "can not use --auth-nocache.", prompt ); + } + close(fd); + } + + if (echo) + { + FILE *fp; + + fp = open_tty (true); + fprintf (fp, "%s", prompt); + fflush (fp); + close_tty (fp); + + fp = open_tty (false); + if (fgets (input, capacity, fp) != NULL) + { + chomp (input); + ret = true; + } + close_tty (fp); + } else { + char *gp = getpass (prompt); + if (gp) + { + strncpynt (input, gp, capacity); + memset (gp, 0, strlen (gp)); + ret = true; + } + } +#else + msg (M_FATAL, "Sorry, but I can't get console input on this OS (%s)", prompt); +#endif + return ret; +} + + +/** + * @copydoc query_user_exec() + * + * Default method for querying user using default stdin/stdout on a console. + * This needs to be available as a backup interface for the alternative + * implementations in case they cannot query through their implementation + * specific methods. + * + * If no alternative implementation is declared, a wrapper in console.h will ensure + * query_user_exec() will call this function instead. + * + */ +bool query_user_exec_builtin() +{ + bool ret = true; /* Presume everything goes okay */ + int i; + + /* Loop through configured query_user slots */ + for (i = 0; i < QUERY_USER_NUMSLOTS && query_user[i].response != NULL; i++) + { + if (!get_console_input(query_user[i].prompt, query_user[i].echo, + query_user[i].response, query_user[i].response_len) ) + { + /* Force the final result state to failed on failure */ + ret = false; + } + } + + return ret; +} diff --git a/src/openvpn/misc.c b/src/openvpn/misc.c index 2982cd0d195..225f0bfbefb 100644 --- a/src/openvpn/misc.c +++ b/src/openvpn/misc.c @@ -6,6 +6,8 @@ * packet compression. * * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2014-2015 David Sommerseth + * Copyright (C) 2016 David Sommerseth * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -1085,9 +1087,11 @@ get_user_pass_cr (struct user_pass *up, struct buffer user_prompt = alloc_buf_gc (128, &gc); buf_printf (&user_prompt, "NEED-OK|%s|%s:", prefix, up->username); - - if (!get_console_input (BSTR (&user_prompt), true, up->password, USER_PASS_LEN)) - msg (M_FATAL, "ERROR: could not read %s ok-confirmation from stdin", prefix); + if (!query_user_SINGLE (BSTR(&user_prompt), BLEN(&user_prompt), + up->password, USER_PASS_LEN, false)) + { + msg (M_FATAL, "ERROR: could not read %s ok-confirmation from stdin", prefix); + } if (!strlen (up->password)) strcpy (up->password, "ok"); @@ -1163,13 +1167,17 @@ get_user_pass_cr (struct user_pass *up, if (ac) { char *response = (char *) gc_malloc (USER_PASS_LEN, false, &gc); - struct buffer packed_resp; + struct buffer packed_resp, challenge; + challenge = alloc_buf_gc (14+strlen(ac->challenge_text), &gc); + buf_printf (&challenge, "CHALLENGE: %s", ac->challenge_text); buf_set_write (&packed_resp, (uint8_t*)up->password, USER_PASS_LEN); - msg (M_INFO|M_NOPREFIX, "CHALLENGE: %s", ac->challenge_text); - if (!get_console_input (ac->challenge_text, BOOL_CAST(ac->flags&CR_ECHO), - response, USER_PASS_LEN)) - msg (M_FATAL, "ERROR: could not read challenge response from stdin"); + + if (!query_user_SINGLE (BSTR(&challenge), BLEN(&challenge), + response, USER_PASS_LEN, BOOL_CAST(ac->flags&CR_ECHO))) + { + msg (M_FATAL, "ERROR: could not read challenge response from stdin"); + } strncpynt (up->username, ac->user, USER_PASS_LEN); buf_printf (&packed_resp, "CRV1::%s::%s", ac->state_id, response); } @@ -1184,32 +1192,49 @@ get_user_pass_cr (struct user_pass *up, struct buffer user_prompt = alloc_buf_gc (128, &gc); struct buffer pass_prompt = alloc_buf_gc (128, &gc); + query_user_clear (); buf_printf (&user_prompt, "Enter %s Username:", prefix); buf_printf (&pass_prompt, "Enter %s Password:", prefix); if (username_from_stdin && !(flags & GET_USER_PASS_PASSWORD_ONLY)) { - if (!get_console_input (BSTR (&user_prompt), true, up->username, USER_PASS_LEN)) - msg (M_FATAL, "ERROR: could not read %s username from stdin", prefix); + query_user_add (BSTR(&user_prompt), BLEN(&user_prompt), + up->username, USER_PASS_LEN, true); + } + + if (password_from_stdin) + { + query_user_add (BSTR(&pass_prompt), BLEN(&pass_prompt), + up->password, USER_PASS_LEN, false); + } + + if( !query_user_exec () ) + { + msg(M_FATAL, "ERROR: Failed retrieving username or password"); + } + + if (!(flags & GET_USER_PASS_PASSWORD_ONLY)) + { if (strlen (up->username) == 0) msg (M_FATAL, "ERROR: %s username is empty", prefix); } - if (password_from_stdin && !get_console_input (BSTR (&pass_prompt), false, up->password, USER_PASS_LEN)) - msg (M_FATAL, "ERROR: could not not read %s password from stdin", prefix); - #ifdef ENABLE_CLIENT_CR if (auth_challenge && (flags & GET_USER_PASS_STATIC_CHALLENGE) && response_from_stdin) { char *response = (char *) gc_malloc (USER_PASS_LEN, false, &gc); - struct buffer packed_resp; + struct buffer packed_resp, challenge; char *pw64=NULL, *resp64=NULL; - msg (M_INFO|M_NOPREFIX, "CHALLENGE: %s", auth_challenge); + challenge = alloc_buf_gc (14+strlen(auth_challenge), &gc); + buf_printf (&challenge, "CHALLENGE: %s", auth_challenge); - if (!get_console_input (auth_challenge, BOOL_CAST(flags & GET_USER_PASS_STATIC_CHALLENGE_ECHO), - response, USER_PASS_LEN)) - msg (M_FATAL, "ERROR: could not read static challenge response from stdin"); + if (!query_user_SINGLE (BSTR(&challenge), BLEN(&challenge), + response, USER_PASS_LEN, + BOOL_CAST(flags & GET_USER_PASS_STATIC_CHALLENGE_ECHO))) + { + msg (M_FATAL, "ERROR: could not retrieve static challenge response"); + } if (openvpn_base64_encode(up->password, strlen(up->password), &pw64) == -1 || openvpn_base64_encode(response, strlen(response), &resp64) == -1) msg (M_FATAL, "ERROR: could not base64-encode password/static_response"); diff --git a/src/openvpn/pkcs11.c b/src/openvpn/pkcs11.c index a1f13c5a759..26210589792 100644 --- a/src/openvpn/pkcs11.c +++ b/src/openvpn/pkcs11.c @@ -744,9 +744,10 @@ _pkcs11_openvpn_show_pkcs11_ids_pin_prompt ( ASSERT (token!=NULL); buf_printf (&pass_prompt, "Please enter '%s' token PIN or 'cancel': ", token->display); - - if (!get_console_input (BSTR (&pass_prompt), false, pin, pin_max)) { - msg (M_FATAL, "Cannot read password from stdin"); + if (!query_user_SINGLE(BSTR(&pass_prompt), BLEN(&pass_prompt), + pin, pin_max, false)) + { + msg (M_FATAL, "Could not retrieve the PIN"); } gc_free (&gc); From 3280d8c8f3583d03fed923837447ef45c8f83d52 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Fri, 12 Aug 2016 12:57:25 +0200 Subject: [PATCH 327/643] Re-implement the systemd support using the new query user API This provides exactly the same systemd functionality which existed before the query user infrastructure got implemented. [v5 - Ensure NULL termination fix in d09fbf958f1c is included ] [v4 - change disapproved &= syntax ] [v3 - Remove QUERY_USER_EXEC_ALTERNATIVE macro, simplify alternatives definition directly in console.h. For now only depend on ENABLE_SYSTEMD] [v2 - Removed the QUERY_USER_FOREACH macro] Signed-off-by: David Sommerseth Acked-by: Selva Nair Message-Id: 1470999445-4288-1-git-send-email-davids@openvpn.net URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12424.html --- configure.ac | 2 +- src/openvpn/Makefile.am | 2 +- src/openvpn/console.h | 6 +- src/openvpn/console_systemd.c | 115 ++++++++++++++++++++++++++++++++++ 4 files changed, 120 insertions(+), 5 deletions(-) create mode 100644 src/openvpn/console_systemd.c diff --git a/configure.ac b/configure.ac index 24b2e468c13..770c24da432 100644 --- a/configure.ac +++ b/configure.ac @@ -1017,7 +1017,7 @@ fi dnl dnl Check for systemd dnl - +AM_CONDITIONAL([ENABLE_SYSTEMD], [test "${enable_systemd}" = "yes"]) if test "$enable_systemd" = "yes" ; then PKG_CHECK_MODULES([libsystemd], [systemd libsystemd], [], diff --git a/src/openvpn/Makefile.am b/src/openvpn/Makefile.am index 8d6d39ffefe..a306726a897 100644 --- a/src/openvpn/Makefile.am +++ b/src/openvpn/Makefile.am @@ -68,7 +68,7 @@ openvpn_SOURCES = \ memdbg.h \ misc.c misc.h \ platform.c platform.h \ - console.c console.h console_builtin.c \ + console.c console.h console_builtin.c console_systemd.c \ mroute.c mroute.h \ mss.c mss.h \ mstats.c mstats.h \ diff --git a/src/openvpn/console.h b/src/openvpn/console.h index 44d49efe238..41f2b8c2485 100644 --- a/src/openvpn/console.h +++ b/src/openvpn/console.h @@ -76,7 +76,7 @@ void query_user_add (char *prompt, size_t prompt_len, bool query_user_exec_builtin (); -#ifdef QUERY_USER_EXEC_ALTERNATIVE +#if defined(ENABLE_SYSTEMD) /** * Executes a configured setup, using the compiled method for querying the user * @@ -86,7 +86,7 @@ bool query_user_exec_builtin (); */ bool query_user_exec (); -#else /* QUERY_USER_EXEC_ALTERNATIVE not defined*/ +#else /* ENABLE_SYSTEMD not defined*/ /** * Wrapper function enabling query_user_exec() if no alternative methods have * been enabled @@ -96,7 +96,7 @@ static bool query_user_exec () { return query_user_exec_builtin(); } -#endif /* QUERY_USER_EXEC_ALTERNATIVE */ +#endif /* defined(ENABLE_SYSTEMD) */ /** diff --git a/src/openvpn/console_systemd.c b/src/openvpn/console_systemd.c new file mode 100644 index 00000000000..67cb51bfd07 --- /dev/null +++ b/src/openvpn/console_systemd.c @@ -0,0 +1,115 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2014-2015 David Sommerseth + * Copyright (C) 2016 David Sommerseth + * + * 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 + */ + +/** + * @file Alternative method to query for user input, using systemd + * + */ + +#include "config.h" + +#ifdef ENABLE_SYSTEMD +#include "syshead.h" +#include "console.h" +#include "misc.h" + +#include + +/* + * is systemd running + */ + +static bool +check_systemd_running () +{ + struct stat c; + + /* We simply test whether the systemd cgroup hierarchy is + * mounted, as well as the systemd-ask-password executable + * being available */ + + return (sd_booted() > 0) + && (stat(SYSTEMD_ASK_PASSWORD_PATH, &c) == 0); + +} + +static bool +get_console_input_systemd (const char *prompt, const bool echo, char *input, const int capacity) +{ + int std_out; + bool ret = false; + struct argv argv; + + argv_init (&argv); + argv_printf (&argv, SYSTEMD_ASK_PASSWORD_PATH); + argv_printf_cat (&argv, "%s", prompt); + + if ((std_out = openvpn_popen (&argv, NULL)) < 0) { + return false; + } + memset (input, 0, capacity); + if (read (std_out, input, capacity-1) != 0) + { + chomp (input); + ret = true; + } + close (std_out); + + argv_reset (&argv); + + return ret; +} + +/** + * Systemd aware implementation of query_user_exec(). If systemd is not running + * it will fall back to use query_user_exec_builtin() instead. + * + */ +bool query_user_exec() +{ + bool ret = true; /* Presume everything goes okay */ + int i; + + /* If systemd is not available, use the default built-in mechanism */ + if (!check_systemd_running()) + { + return query_user_exec_builtin(); + } + + /* Loop through the complete query setup and when needed, collect the information */ + for (i = 0; i < QUERY_USER_NUMSLOTS && query_user[i].response != NULL; i++) + { + if (!get_console_input_systemd(query_user[i].prompt, query_user[i].echo, + query_user[i].response, query_user[i].response_len) ) + { + /* Force the final result state to failed on failure */ + ret = false; + } + } + + return ret; +} + +#endif /* ENABLE_SYSTEMD */ From 8ba3e25897af5c7bd7b4f706961e9528d6988d83 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Thu, 11 Aug 2016 16:33:55 +0200 Subject: [PATCH 328/643] systemd: Do not mask usernames when querying for it via systemd-ask-password In systemd after version 216, systemd-ask-password will support --echo which will avoid masking the user input. As OpenVPN uses this mechanism collecting usernames when systemd is available, this will avoid the input of usernames to be masked. This patch also adds the --icon argument, which is aimed at graphical inputs. For example when OpenVPN is started at system boot-time using a graphical boot interface such as Plymouth. [v2 - Avoid pkg.m4 hacks and use pkgconfig/autoconf methods to flag if systemd is recent enough for --echo support] Signed-off-by: David Sommerseth Acked-by: Selva Nair Message-Id: 1470926035-434-1-git-send-email-davids@openvpn.net URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12405.html --- configure.ac | 6 ++++++ src/openvpn/console_systemd.c | 8 ++++++++ 2 files changed, 14 insertions(+) diff --git a/configure.ac b/configure.ac index 770c24da432..357ba29e83d 100644 --- a/configure.ac +++ b/configure.ac @@ -1023,6 +1023,12 @@ if test "$enable_systemd" = "yes" ; then [], [PKG_CHECK_MODULES([libsystemd], [libsystemd-daemon])] ) + + PKG_CHECK_EXISTS( [libsystemd > 216], + [AC_DEFINE([SYSTEMD_NEWER_THAN_216], [1], + [systemd is newer than v216])] + ) + AC_CHECK_HEADERS(systemd/sd-daemon.h, , [ diff --git a/src/openvpn/console_systemd.c b/src/openvpn/console_systemd.c index 67cb51bfd07..9cd7575b147 100644 --- a/src/openvpn/console_systemd.c +++ b/src/openvpn/console_systemd.c @@ -64,6 +64,14 @@ get_console_input_systemd (const char *prompt, const bool echo, char *input, con argv_init (&argv); argv_printf (&argv, SYSTEMD_ASK_PASSWORD_PATH); +#ifdef SYSTEMD_NEWER_THAN_216 + /* the --echo support arrived in upstream systemd 217 */ + if( echo ) + { + argv_printf_cat(&argv, "--echo"); + } +#endif + argv_printf_cat (&argv, "--icon network-vpn"); argv_printf_cat (&argv, "%s", prompt); if ((std_out = openvpn_popen (&argv, NULL)) < 0) { From 88c4b9d6ad1d346931d9090b247e9e3d2d86bce7 Mon Sep 17 00:00:00 2001 From: Lev Stipakov Date: Tue, 11 Oct 2016 11:03:50 +0300 Subject: [PATCH 329/643] Use separate list for per-client push options v4: - fix whitespaces, wrap long lines v3: - rebase on master v2: - Also move ifconfig and ipv6-ifconfig to separate options list Move client-specific push options (currently peer-id and cipher) to separate list, which is deallocated after push_reply has been send. This makes sure that options fit into buf, not duplicated nor leak memory on renegotiation. Signed-off-by: Lev Stipakov Acked-by: Steffan Karger Message-Id: <1476173030-2171-1-git-send-email-lstipakov@gmail.com> URL: http://www.mail-archive.com/search?l=mid&q=1476173030-2171-1-git-send-email-lstipakov@gmail.com Signed-off-by: David Sommerseth --- src/openvpn/push.c | 206 ++++++++++++++++++++++++++------------------- 1 file changed, 118 insertions(+), 88 deletions(-) diff --git a/src/openvpn/push.c b/src/openvpn/push.c index df4f596a1c9..ee2eda47948 100644 --- a/src/openvpn/push.c +++ b/src/openvpn/push.c @@ -40,26 +40,29 @@ #if P2MP +static char push_reply_cmd[] = "PUSH_REPLY"; + /** - * Add an option to the push list by providing a format string. + * Add an option to the given push list by providing a format string. * * The string added to the push options is allocated in o->gc, so the caller * does not have to preserve anything. * - * @param o The current connection's options - * @param msglevel The message level to use when printing errors - * @param fmt Format string for the option - * @param ... Format string arguments + * @param gc GC arena where options are allocated + * @param push_list Push list containing options + * @param msglevel The message level to use when printing errors + * @param fmt Format string for the option + * @param ... Format string arguments * * @return true on success, false on failure. */ -static bool push_option_fmt(struct options *o, int msglevel, - const char *fmt, ...) +static bool push_option_fmt(struct gc_arena *gc, struct push_list *push_list, + int msglevel, const char *fmt, ...) #ifdef __GNUC__ #if __USE_MINGW_ANSI_STDIO - __attribute__ ((format (gnu_printf, 3, 4))) + __attribute__ ((format (gnu_printf, 4, 5))) #else - __attribute__ ((format (__printf__, 3, 4))) + __attribute__ ((format (__printf__, 4, 5))) #endif #endif ; @@ -295,16 +298,43 @@ send_push_request (struct context *c) /** * Prepare push options, based on local options and available peer info. * - * @param options Connection options - * @param tls_multi TLS state structure for the current tunnel + * @param context context structure storing data for VPN tunnel + * @param gc gc arena for allocating push options + * @param push_list push list to where options are added * * @return true on success, false on failure. */ static bool -prepare_push_reply (struct options *o, struct tls_multi *tls_multi) +prepare_push_reply (struct context *c, struct gc_arena *gc, + struct push_list *push_list) { const char *optstr = NULL; + const struct tls_multi *tls_multi = c->c2.tls_multi; const char * const peer_info = tls_multi->peer_info; + struct options *o = &c->options; + + /* ipv6 */ + if (c->c2.push_ifconfig_ipv6_defined && !o->push_ifconfig_ipv6_blocked) + { + push_option_fmt (gc, push_list, M_USAGE, "ifconfig-ipv6 %s/%d %s", + print_in6_addr (c->c2.push_ifconfig_ipv6_local, 0, gc), + c->c2.push_ifconfig_ipv6_netbits, + print_in6_addr (c->c2.push_ifconfig_ipv6_remote, + 0, gc)); + } + + /* ipv4 */ + if (c->c2.push_ifconfig_defined && c->c2.push_ifconfig_local && + c->c2.push_ifconfig_remote_netmask) + { + in_addr_t ifconfig_local = c->c2.push_ifconfig_local; + if (c->c2.push_ifconfig_local_alias) + ifconfig_local = c->c2.push_ifconfig_local_alias; + push_option_fmt (gc, push_list, M_USAGE, "ifconfig %s %s", + print_in_addr_t (ifconfig_local, 0, gc), + print_in_addr_t (c->c2.push_ifconfig_remote_netmask, + 0, gc)); + } /* Send peer-id if client supports it */ optstr = peer_info ? strstr(peer_info, "IV_PROTO=") : NULL; @@ -314,8 +344,8 @@ prepare_push_reply (struct options *o, struct tls_multi *tls_multi) int r = sscanf(optstr, "IV_PROTO=%d", &proto); if ((r == 1) && (proto >= 2)) { - push_remove_option(o, "peer-id"); - push_option_fmt(o, M_USAGE, "peer-id %d", tls_multi->peer_id); + push_option_fmt(gc, push_list, M_USAGE, "peer-id %d", + tls_multi->peer_id); } } @@ -325,7 +355,7 @@ prepare_push_reply (struct options *o, struct tls_multi *tls_multi) /* if we have already created our key, we cannot change our own * cipher, so disable NCP and warn = explain why */ - struct tls_session *session = &tls_multi->session[TM_ACTIVE]; + const struct tls_session *session = &tls_multi->session[TM_ACTIVE]; if ( session->key[KS_PRIMARY].crypto_options.key_ctx_bi.initialized ) { msg( M_INFO, "PUSH: client wants to negotiate cipher (NCP), but " @@ -336,87 +366,79 @@ prepare_push_reply (struct options *o, struct tls_multi *tls_multi) { /* Push the first cipher from --ncp-ciphers to the client. * TODO: actual negotiation, instead of server dictatorship. */ - char *push_cipher = string_alloc(o->ncp_ciphers, &o->gc); + char *push_cipher = string_alloc(o->ncp_ciphers, gc); o->ciphername = strtok (push_cipher, ":"); - push_remove_option(o, "cipher"); - push_option_fmt(o, M_USAGE, "cipher %s", o->ciphername); + push_option_fmt(gc, push_list, M_USAGE, "cipher %s", o->ciphername); } } return true; } static bool -send_push_reply (struct context *c) +send_push_options (struct context *c, struct buffer *buf, + struct push_list *push_list, int safe_cap, + bool *push_sent, bool *multi_push) { - struct gc_arena gc = gc_new (); - struct buffer buf = alloc_buf_gc (PUSH_BUNDLE_SIZE, &gc); - struct push_entry *e = c->options.push_list.head; - bool multi_push = false; - static char cmd[] = "PUSH_REPLY"; - const int extra = 84; /* extra space for possible trailing ifconfig and push-continuation */ - const int safe_cap = BCAP (&buf) - extra; - bool push_sent = false; - - msg( M_INFO, "send_push_reply(): safe_cap=%d", safe_cap ); - - buf_printf (&buf, "%s", cmd); - - if ( c->c2.push_ifconfig_ipv6_defined && - !c->options.push_ifconfig_ipv6_blocked ) - { - /* IPv6 is put into buffer first, could be lengthy */ - buf_printf( &buf, ",ifconfig-ipv6 %s/%d %s", - print_in6_addr( c->c2.push_ifconfig_ipv6_local, 0, &gc), - c->c2.push_ifconfig_ipv6_netbits, - print_in6_addr( c->c2.push_ifconfig_ipv6_remote, 0, &gc) ); - if (BLEN (&buf) >= safe_cap) - { - msg (M_WARN, "--push ifconfig-ipv6 option is too long"); - goto fail; - } - } + struct push_entry *e = push_list->head; while (e) { if (e->enable) { const int l = strlen (e->option); - if (BLEN (&buf) + l >= safe_cap) + if (BLEN (buf) + l >= safe_cap) { - buf_printf (&buf, ",push-continuation 2"); - { - const bool status = send_control_channel_string (c, BSTR (&buf), D_PUSH); - if (!status) - goto fail; - push_sent = true; - multi_push = true; - buf_reset_len (&buf); - buf_printf (&buf, "%s", cmd); - } + buf_printf (buf, ",push-continuation 2"); + { + const bool status = send_control_channel_string (c, BSTR (buf), D_PUSH); + if (!status) + return false; + *push_sent = true; + *multi_push = true; + buf_reset_len (buf); + buf_printf (buf, "%s", push_reply_cmd); + } } - if (BLEN (&buf) + l >= safe_cap) + if (BLEN (buf) + l >= safe_cap) { msg (M_WARN, "--push option is too long"); - goto fail; + return false; } - buf_printf (&buf, ",%s", e->option); + buf_printf (buf, ",%s", e->option); } e = e->next; } + return true; +} + +static bool +send_push_reply (struct context *c, struct push_list *per_client_push_list) +{ + struct gc_arena gc = gc_new (); + struct buffer buf = alloc_buf_gc (PUSH_BUNDLE_SIZE, &gc); + bool multi_push = false; + const int extra = 84; /* extra space for possible trailing ifconfig and push-continuation */ + const int safe_cap = BCAP (&buf) - extra; + bool push_sent = false; + + msg( M_INFO, "send_push_reply(): safe_cap=%d", safe_cap ); + + buf_printf (&buf, "%s", push_reply_cmd); + + /* send options which are common to all clients */ + if (!send_push_options (c, &buf, &c->options.push_list, safe_cap, + &push_sent, &multi_push)) + goto fail; + + /* send client-specific options */ + if (!send_push_options (c, &buf, per_client_push_list, safe_cap, + &push_sent, &multi_push)) + goto fail; - if (c->c2.push_ifconfig_defined && c->c2.push_ifconfig_local && c->c2.push_ifconfig_remote_netmask) - { - in_addr_t ifconfig_local = c->c2.push_ifconfig_local; - if (c->c2.push_ifconfig_local_alias) - ifconfig_local = c->c2.push_ifconfig_local_alias; - buf_printf (&buf, ",ifconfig %s %s", - print_in_addr_t (ifconfig_local, 0, &gc), - print_in_addr_t (c->c2.push_ifconfig_remote_netmask, 0, &gc)); - } if (multi_push) buf_printf (&buf, ",push-continuation 1"); - if (BLEN (&buf) > sizeof(cmd)-1) + if (BLEN (&buf) > sizeof(push_reply_cmd)-1) { const bool status = send_control_channel_string (c, BSTR (&buf), D_PUSH); if (!status) @@ -432,7 +454,7 @@ send_push_reply (struct context *c) bool status = false; buf_reset_len (&buf); - buf_printf (&buf, "%s", cmd); + buf_printf (&buf, "%s", push_reply_cmd); status = send_control_channel_string (c, BSTR(&buf), D_PUSH); if (!status) goto fail; @@ -447,7 +469,8 @@ send_push_reply (struct context *c) } static void -push_option_ex (struct options *o, const char *opt, bool enable, int msglevel) +push_option_ex (struct gc_arena *gc, struct push_list *push_list, + const char *opt, bool enable, int msglevel) { if (!string_class (opt, CC_ANY, CC_COMMA)) { @@ -456,20 +479,20 @@ push_option_ex (struct options *o, const char *opt, bool enable, int msglevel) else { struct push_entry *e; - ALLOC_OBJ_CLEAR_GC (e, struct push_entry, &o->gc); + ALLOC_OBJ_CLEAR_GC (e, struct push_entry, gc); e->enable = true; e->option = opt; - if (o->push_list.head) + if (push_list->head) { - ASSERT(o->push_list.tail); - o->push_list.tail->next = e; - o->push_list.tail = e; + ASSERT(push_list->tail); + push_list->tail->next = e; + push_list->tail = e; } else { - ASSERT(!o->push_list.tail); - o->push_list.head = e; - o->push_list.tail = e; + ASSERT(!push_list->tail); + push_list->head = e; + push_list->tail = e; } } } @@ -477,7 +500,7 @@ push_option_ex (struct options *o, const char *opt, bool enable, int msglevel) void push_option (struct options *o, const char *opt, int msglevel) { - push_option_ex (o, opt, true, msglevel); + push_option_ex (&o->gc, &o->push_list, opt, true, msglevel); } void @@ -489,7 +512,8 @@ clone_push_list (struct options *o) push_reset (o); while (e) { - push_option_ex (o, string_alloc (e->option, &o->gc), true, M_FATAL); + push_option_ex (&o->gc, &o->push_list, + string_alloc (e->option, &o->gc), true, M_FATAL); e = e->next; } } @@ -503,18 +527,18 @@ push_options (struct options *o, char **p, int msglevel, struct gc_arena *gc) push_option (o, opt, msglevel); } -static bool push_option_fmt(struct options *o, int msglevel, - const char *format, ...) +static bool push_option_fmt(struct gc_arena *gc, struct push_list *push_list, + int msglevel, const char *format, ...) { va_list arglist; char tmp[256] = {0}; - int len = -1; + int len; va_start (arglist, format); len = vsnprintf (tmp, sizeof(tmp), format, arglist); va_end (arglist); if (len > sizeof(tmp)-1) return false; - push_option (o, string_alloc (tmp, &o->gc), msglevel); + push_option_ex (gc, push_list, string_alloc (tmp, gc), true, msglevel); return true; } @@ -582,12 +606,18 @@ process_incoming_push_request (struct context *c) } else { - if (prepare_push_reply(&c->options, c->c2.tls_multi) && - send_push_reply (c)) + /* per-client push options - peer-id, cipher, ifconfig, ipv6-ifconfig */ + struct push_list push_list; + struct gc_arena gc = gc_new (); + + CLEAR (push_list); + if (prepare_push_reply (c, &gc, &push_list) && + send_push_reply (c, &push_list)) { ret = PUSH_MSG_REQUEST; c->c2.sent_push_reply_expiry = now + 30; } + gc_free(&gc); } } else From 396d30c264e6cb6b9f57c3e566f3b71879999662 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Wed, 12 Oct 2016 12:47:07 +0200 Subject: [PATCH 330/643] Change the hold command to communicate the time that OpenVPN would wait to the UI. Before the connect-retry change to do exponential backup this was not necessary since the time was fixed. With the exponential backoff the UI needs either to implement its own exponential backoff mechanism or needs a way of knowing the value of OpenVPN internal mechansim. Patch V2: Fixed typos noticed by Selva [DS: Fixed a couple of whitespace errors in management_hold() at commit time] Acked-by: Selva Nair Message-Id: <1476269227-13290-1-git-send-email-arne@rfc2549.org> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12675.html Signed-off-by: David Sommerseth --- doc/management-notes.txt | 7 +++++-- src/openvpn/init.c | 15 +++++++++------ src/openvpn/manage.c | 8 ++++++-- src/openvpn/manage.h | 2 +- 4 files changed, 21 insertions(+), 11 deletions(-) diff --git a/doc/management-notes.txt b/doc/management-notes.txt index f68f3db98a8..dd870ebc75a 100644 --- a/doc/management-notes.txt +++ b/doc/management-notes.txt @@ -168,9 +168,12 @@ be reset by restarts. OpenVPN will indicate that it is in a hold state by sending a real-time notification to the management -client: +client, the parameter indicates how long OpenVPN would +wait without UI (as influenced by connect-retry exponential +backoff). The UI needs to wait for releasing the hold if it +wants similar behavior: - >HOLD:Waiting for hold release + >HOLD:Waiting for hold release:10 Command examples: diff --git a/src/openvpn/init.c b/src/openvpn/init.c index af5d4913066..cc8e94551bf 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -1960,16 +1960,17 @@ do_deferred_options (struct context *c, const unsigned int found) } /* - * Possible hold on initialization + * Possible hold on initialization, holdtime is the + * time OpenVPN would wait without management */ static bool -do_hold (void) +do_hold (int holdtime) { #ifdef ENABLE_MANAGEMENT if (management) { /* block until management hold is released */ - if (management_hold (management)) + if (management_hold (management, holdtime)) return true; } #endif @@ -2027,8 +2028,10 @@ socket_restart_pause (struct context *c) c->persist.restart_sleep_seconds = 0; /* do managment hold on context restart, i.e. second, third, fourth, etc. initialization */ - if (do_hold ()) + if (do_hold (sec)) + { sec = 0; + } if (sec) { @@ -2046,7 +2049,7 @@ do_startup_pause (struct context *c) if (!c->first_time) socket_restart_pause (c); else - do_hold (); /* do management hold on first context initialization */ + do_hold (0); /* do management hold on first context initialization */ } /* @@ -3431,7 +3434,7 @@ open_management (struct context *c) } /* initial management hold, called early, before first context initialization */ - do_hold (); + do_hold (0); if (IS_SIG (c)) { msg (M_WARN, "Signal received from management interface, exiting"); diff --git a/src/openvpn/manage.c b/src/openvpn/manage.c index dcb1bc18757..26a2f7ea18e 100644 --- a/src/openvpn/manage.c +++ b/src/openvpn/manage.c @@ -3332,12 +3332,13 @@ management_should_daemonize (struct management *man) * Return true if the caller should not sleep for an additional time interval. */ bool -management_hold (struct management *man) +management_hold (struct management *man, int holdtime) { if (management_would_hold (man)) { volatile int signal_received = 0; const bool standalone_disabled_save = man->persist.standalone_disabled; + struct gc_arena gc = gc_new (); man->persist.standalone_disabled = false; /* This is so M_CLIENT messages will be correctly passed through msg() */ man->persist.special_state_msg = NULL; @@ -3347,7 +3348,9 @@ management_hold (struct management *man) if (!signal_received) { - man->persist.special_state_msg = ">HOLD:Waiting for hold release"; + struct buffer out = alloc_buf_gc (128, &gc); + buf_printf (&out, ">HOLD:Waiting for hold release:%d", holdtime); + man->persist.special_state_msg = BSTR (&out); msg (M_CLIENT, "%s", man->persist.special_state_msg); /* run command processing event loop until we get our username/password */ @@ -3366,6 +3369,7 @@ management_hold (struct management *man) man->persist.special_state_msg = NULL; man->settings.mansig &= ~MANSIG_IGNORE_USR1_HUP; + gc_free (&gc); return true; } return false; diff --git a/src/openvpn/manage.h b/src/openvpn/manage.h index 988600f5e29..50db38cd555 100644 --- a/src/openvpn/manage.h +++ b/src/openvpn/manage.h @@ -396,7 +396,7 @@ int managment_android_persisttun_action (struct management *man); bool management_should_daemonize (struct management *man); bool management_would_hold (struct management *man); -bool management_hold (struct management *man); +bool management_hold (struct management *man, int holdtime); void management_event_loop_n_seconds (struct management *man, int sec); From dc4fa3c4656b92aff3f26d4134c509410add142e Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Wed, 12 Oct 2016 09:32:49 +0200 Subject: [PATCH 331/643] Check --ncp-ciphers list on startup Currently, if --ncp-ciphers contains an invalid cipher, OpenVPN will only error out when that cipher is selected by negotiation. That's not very friendly to the user, so check the list on startup, and give a clear error message immediately. This patches changes the cipher_kt_get() to let the caller decide what action to take if no valid cipher was found. This enables us to print all invalid ciphers in the list, instead of just the first invalid cipher. This should fix trac #737. v2: improve tls_check_ncp_cipher_list() with Selva's review suggestions. Signed-off-by: Steffan Karger Acked-by: Selva Nair Message-Id: <1476257569-16301-1-git-send-email-steffan@karger.me> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12671.html Trac: #737 Signed-off-by: David Sommerseth --- src/openvpn/crypto.c | 5 +++++ src/openvpn/crypto_backend.h | 3 ++- src/openvpn/crypto_mbedtls.c | 15 ++++++++++----- src/openvpn/crypto_openssl.c | 17 ++++++++++++----- src/openvpn/options.c | 5 +++++ src/openvpn/ssl.c | 22 ++++++++++++++++++++++ src/openvpn/ssl.h | 9 +++++++++ 7 files changed, 65 insertions(+), 11 deletions(-) diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c index 4ea0082c423..3dd4a9ebc05 100644 --- a/src/openvpn/crypto.c +++ b/src/openvpn/crypto.c @@ -766,6 +766,11 @@ init_key_type (struct key_type *kt, const char *ciphername, if (strcmp (ciphername, "none") != 0) { kt->cipher = cipher_kt_get (translate_cipher_name_from_openvpn(ciphername)); + if (!kt->cipher) + { + msg (M_FATAL, "Cipher %s not supported", ciphername); + } + kt->cipher_length = cipher_kt_key_size (kt->cipher); if (keysize > 0 && keysize <= MAX_CIPHER_KEY_LENGTH) kt->cipher_length = keysize; diff --git a/src/openvpn/crypto_backend.h b/src/openvpn/crypto_backend.h index a69967376cc..bf7d78c4e41 100644 --- a/src/openvpn/crypto_backend.h +++ b/src/openvpn/crypto_backend.h @@ -195,7 +195,8 @@ void cipher_des_encrypt_ecb (const unsigned char key[DES_KEY_LENGTH], * \c AES-128-CBC). * * @return A statically allocated structure containing parameters - * for the given cipher. + * for the given cipher, or NULL if no matching parameters + * were found. */ const cipher_kt_t * cipher_kt_get (const char *ciphername); diff --git a/src/openvpn/crypto_mbedtls.c b/src/openvpn/crypto_mbedtls.c index 92cba492ffd..6ad5924782a 100644 --- a/src/openvpn/crypto_mbedtls.c +++ b/src/openvpn/crypto_mbedtls.c @@ -384,13 +384,18 @@ cipher_kt_get (const char *ciphername) cipher = mbedtls_cipher_info_from_string(ciphername); if (NULL == cipher) - msg (M_FATAL, "Cipher algorithm '%s' not found", ciphername); + { + msg (D_LOW, "Cipher algorithm '%s' not found", ciphername); + return NULL; + } if (cipher->key_bitlen/8 > MAX_CIPHER_KEY_LENGTH) - msg (M_FATAL, "Cipher algorithm '%s' uses a default key size (%d bytes) which is larger than " PACKAGE_NAME "'s current maximum key size (%d bytes)", - ciphername, - cipher->key_bitlen/8, - MAX_CIPHER_KEY_LENGTH); + { + msg (D_LOW, "Cipher algorithm '%s' uses a default key size (%d bytes) " + "which is larger than " PACKAGE_NAME "'s current maximum key size " + "(%d bytes)", ciphername, cipher->key_bitlen/8, MAX_CIPHER_KEY_LENGTH); + return NULL; + } return cipher; } diff --git a/src/openvpn/crypto_openssl.c b/src/openvpn/crypto_openssl.c index 3484c77112e..1ea06bba1f3 100644 --- a/src/openvpn/crypto_openssl.c +++ b/src/openvpn/crypto_openssl.c @@ -504,13 +504,20 @@ cipher_kt_get (const char *ciphername) cipher = EVP_get_cipherbyname (ciphername); if (NULL == cipher) - crypto_msg (M_FATAL, "Cipher algorithm '%s' not found", ciphername); + { + crypto_msg (D_LOW, "Cipher algorithm '%s' not found", ciphername); + return NULL; + } + if (EVP_CIPHER_key_length (cipher) > MAX_CIPHER_KEY_LENGTH) - msg (M_FATAL, "Cipher algorithm '%s' uses a default key size (%d bytes) which is larger than " PACKAGE_NAME "'s current maximum key size (%d bytes)", - ciphername, - EVP_CIPHER_key_length (cipher), - MAX_CIPHER_KEY_LENGTH); + { + msg (D_LOW, "Cipher algorithm '%s' uses a default key size (%d bytes) " + "which is larger than " PACKAGE_NAME "'s current maximum key size " + "(%d bytes)", ciphername, EVP_CIPHER_key_length (cipher), + MAX_CIPHER_KEY_LENGTH); + return NULL; + } return cipher; } diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 2998f06ed62..1ed14b0da99 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -2208,6 +2208,11 @@ options_postprocess_verify_ce (const struct options *options, const struct conne #ifdef ENABLE_CRYPTO + if (options->ncp_enabled && !tls_check_ncp_cipher_list(options->ncp_ciphers)) + { + msg (M_USAGE, "NCP cipher list contains unsupported ciphers."); + } + /* * Check consistency of replay options */ diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 420164e7726..c7cf78df968 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -3714,6 +3714,28 @@ tls_peer_info_ncp_ver(const char *peer_info) return 0; } +bool +tls_check_ncp_cipher_list(const char *list) { + bool unsupported_cipher_found = false; + + ASSERT (list); + + char * const tmp_ciphers = string_alloc (list, NULL); + const char *token = strtok (tmp_ciphers, ":"); + while (token) + { + if (!cipher_kt_get (translate_cipher_name_from_openvpn (token))) + { + msg (M_WARN, "Unsupported cipher in --ncp-ciphers: %s", token); + unsupported_cipher_found = true; + } + token = strtok (NULL, ":"); + } + free (tmp_ciphers); + + return 0 < strlen(list) && !unsupported_cipher_found; +} + /* * Dump a human-readable rendition of an openvpn packet * into a garbage collectable string which is returned. diff --git a/src/openvpn/ssl.h b/src/openvpn/ssl.h index de68b69e93f..e6963a4c274 100644 --- a/src/openvpn/ssl.h +++ b/src/openvpn/ssl.h @@ -503,6 +503,15 @@ tls_get_peer_info(const struct tls_multi *multi) */ int tls_peer_info_ncp_ver(const char *peer_info); +/** + * Check whether the ciphers in the supplied list are supported. + * + * @param list Colon-separated list of ciphers + * + * @returns true iff all ciphers in list are supported. + */ +bool tls_check_ncp_cipher_list(const char *list); + /* * inline functions */ From b891e57e1fe794483c08296e32c15751f2676a2d Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Thu, 13 Oct 2016 21:59:27 +0200 Subject: [PATCH 332/643] Move memcmp_constant_time() to crypto.h This function is quite useful other places, so make it generally accessible. [DS: changed function declaration to static inline during commit] Signed-off-by: David Sommerseth Acked-by: Steffan Karger Message-Id: <1476388771-16492-2-git-send-email-davids@openvpn.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12698.html --- src/openvpn/crypto.c | 18 ------------------ src/openvpn/crypto.h | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c index 3dd4a9ebc05..026d9aeb2a0 100644 --- a/src/openvpn/crypto.c +++ b/src/openvpn/crypto.c @@ -66,24 +66,6 @@ #define CRYPT_ERROR(format) \ do { msg (D_CRYPT_ERRORS, "%s: " format, error_prefix); goto error_exit; } while (false) -/** - * As memcmp(), but constant-time. - * Returns 0 when data is equal, non-zero otherwise. - */ -static int -memcmp_constant_time (const void *a, const void *b, size_t size) { - const uint8_t * a1 = a; - const uint8_t * b1 = b; - int ret = 0; - size_t i; - - for (i = 0; i < size; i++) { - ret |= *a1++ ^ *b1++; - } - - return ret; -} - static void openvpn_encrypt_aead (struct buffer *buf, struct buffer work, struct crypto_options *opt) { diff --git a/src/openvpn/crypto.h b/src/openvpn/crypto.h index 3b6bb98057b..4b90c674eb0 100644 --- a/src/openvpn/crypto.h +++ b/src/openvpn/crypto.h @@ -476,6 +476,24 @@ void get_tls_handshake_key (const struct key_type *key_type, * Inline functions */ +/** + * As memcmp(), but constant-time. + * Returns 0 when data is equal, non-zero otherwise. + */ +static inline int +memcmp_constant_time (const void *a, const void *b, size_t size) { + const uint8_t * a1 = a; + const uint8_t * b1 = b; + int ret = 0; + size_t i; + + for (i = 0; i < size; i++) { + ret |= *a1++ ^ *b1++; + } + + return ret; +} + static inline bool key_ctx_bi_defined(const struct key_ctx_bi* key) { From 86e2fa5597fd1ad8e0102f134c63d6bc8cb7c291 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Thu, 13 Oct 2016 18:54:16 +0200 Subject: [PATCH 333/643] Remove tun-ipv6 Option. Instead assume that IPv6 is always supported. This option was useful when IPv6 tun support was non standard and was an internal/user specified flag that tracked the Ipv6 capability of the tun device. All supported OS support IPv6. Also tun-ipv6 is pushable by the remote so not putting tun-ipv6 does not forbid ipv6 addresses. This commit also clean up a bit of the ipv6 related tun.c. Changes for most platforms are minimal. For linux a bit more cleanup is done: - Remove compatibility defines that were added 2008 - Always use IFF_NO_PI for the linux tun and not only for IPv4 only tun setups (Android also always IFF_NO_PI works fine with Ipv6). This commit also remove a non ipv6 fallback for tap driver from OpenVPN 2.2-beta or earlier and only warns. Patch V2: Integrate Gert's comments Patch V3: Remove tun_ipv4 option. It only used for MTU discovery and there it was wrong since it should on the transport protocol if at all Patch V4: Completely remove support for NetBSD <= 4.0 and remove NETBSD_MULTI_AF defines Patch V5: Assume generic OS in tun.c is also IPv6 capable. Add changes to man page. Fix typos/change message as suggest by David. Signed-off-by: Arne Schwabe Acked-by: David Sommerseth Acked-by: Gert Doering Message-Id: <1476377656-3150-1-git-send-email-arne@rfc2549.org> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12695.html Signed-off-by: David Sommerseth --- Changes.rst | 4 ++ doc/openvpn.8 | 21 ++---- src/openvpn/forward.c | 2 +- src/openvpn/helper.c | 2 - src/openvpn/init.c | 6 -- src/openvpn/multi.c | 8 +-- src/openvpn/openvpn.h | 5 -- src/openvpn/options.c | 13 +--- src/openvpn/options.h | 1 - src/openvpn/route.c | 14 ++-- src/openvpn/tun.c | 160 +++++++----------------------------------- src/openvpn/tun.h | 2 - 12 files changed, 47 insertions(+), 191 deletions(-) diff --git a/Changes.rst b/Changes.rst index 9fcba75cf7e..27dc99e8f93 100644 --- a/Changes.rst +++ b/Changes.rst @@ -135,6 +135,10 @@ User-visible Changes ciphers configured in the config file. Use --ncp-disable if you don't want that. +- All tun devices on all platforms are always considered to be IPv6 + capable. The --tun-ipv6 option is ignored (behaves like it is always + on). + Maintainer-visible changes -------------------------- diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 1c341ae7d49..2e58f33df0b 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -797,18 +797,6 @@ changes the interpretation of the arguments of to mean "address netmask", no longer "local remote". .\"********************************************************* .TP -.B \-\-tun\-ipv6 -Build a tun link capable of forwarding IPv6 traffic. -Should be used in conjunction with -.B \-\-dev tun -or -.B \-\-dev tunX. -A warning will be displayed -if no specific IPv6 TUN support for your OS has been compiled into OpenVPN. - -See below for further IPv6-related configuration options. -.\"********************************************************* -.TP .B \-\-dev\-node node Explicitly set the device node rather than using /dev/net/tun, /dev/tun, /dev/tap, etc. If OpenVPN @@ -3600,7 +3588,7 @@ Clients that connect with options that are incompatible with those of the server will be disconnected. Options that will be compared for compatibility include -dev\-type, link\-mtu, tun\-mtu, proto, tun\-ipv6, ifconfig, +dev\-type, link\-mtu, tun\-mtu, proto, ifconfig, comp\-lzo, fragment, keydir, cipher, auth, keysize, secret, no\-replay, no\-iv, tls\-auth, key\-method, tls\-server, and tls\-client. @@ -5870,10 +5858,13 @@ is used. .B \-\-server\-ipv6 ipv6addr/bits convenience-function to enable a number of IPv6 related options at once, namely -.B \-\-ifconfig\-ipv6, \-\-ifconfig\-ipv6\-pool, \-\-tun\-ipv6 +.B \-\-ifconfig\-ipv6, \-\-ifconfig\-ipv6\-pool and .B \-\-push tun\-ipv6 -Is only accepted if ``\-\-mode server'' or ``\-\-server'' is set. +Is only accepted if ``\-\-mode server'' or ``\-\-server'' is set. Pushing of the +.B \-\-tun\-ipv6 +directive is done for older clients which require an explicit +``\-\-tun\-ipv6'' in their configuration. .TP .B \-\-ifconfig\-ipv6\-pool ipv6addr/bits Specify an IPv6 address pool for dynamic assignment to clients. The diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c index 6c114391dfd..b3077ed6a5b 100644 --- a/src/openvpn/forward.c +++ b/src/openvpn/forward.c @@ -391,7 +391,7 @@ check_fragment_dowork (struct context *c) struct link_socket_info *lsi = get_link_socket_info (c); /* OS MTU Hint? */ - if (lsi->mtu_changed && c->c2.ipv4_tun) + if (lsi->mtu_changed) { frame_adjust_path_mtu (&c->c2.frame_fragment, c->c2.link_socket->mtu, c->options.ce.proto); diff --git a/src/openvpn/helper.c b/src/openvpn/helper.c index 62f88eccc36..229523dbd1e 100644 --- a/src/openvpn/helper.c +++ b/src/openvpn/helper.c @@ -200,8 +200,6 @@ helper_client_server (struct options *o) add_in6_addr( o->server_network_ipv6, 0x1000 ); o->ifconfig_ipv6_pool_netbits = o->server_netbits_ipv6; - o->tun_ipv6 = true; - push_option( o, "tun-ipv6", M_USAGE ); } diff --git a/src/openvpn/init.c b/src/openvpn/init.c index cc8e94551bf..73f8c6d69af 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -1400,9 +1400,6 @@ do_init_tun (struct context *c) !c->options.ifconfig_nowarn, c->c2.es); - /* flag tunnel for IPv6 config if --tun-ipv6 is set */ - c->c1.tuntap->ipv6 = c->options.tun_ipv6; - init_tun_post (c->c1.tuntap, &c->c2.frame, &c->options.tuntap_options); @@ -1420,9 +1417,6 @@ do_open_tun (struct context *c) struct gc_arena gc = gc_new (); bool ret = false; - c->c2.ipv4_tun = (!c->options.tun_ipv6 - && is_dev_type (c->options.dev, c->options.dev_type, "tun")); - #ifndef TARGET_ANDROID if (!c->c1.tuntap) { diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index 3bc6ee91da6..93a554d0a37 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -1378,8 +1378,7 @@ multi_select_virtual_addr (struct multi_context *m, struct multi_instance *mi) * (see below) so issue a warning if that happens - don't break the * session, though, as we don't even know if this client WANTS IPv6 */ - if ( mi->context.c1.tuntap->ipv6 && - mi->context.options.ifconfig_ipv6_pool_defined && + if ( mi->context.options.ifconfig_ipv6_pool_defined && ! mi->context.options.push_ifconfig_ipv6_defined ) { msg( M_INFO, "MULTI_sva: WARNING: if --ifconfig-push is used for IPv4, automatic IPv6 assignment from --ifconfig-ipv6-pool does not work. Use --ifconfig-ipv6-push for IPv6 then." ); @@ -1452,8 +1451,7 @@ multi_select_virtual_addr (struct multi_context *m, struct multi_instance *mi) * way round ("dynamic IPv4, static IPv6") or "both static" makes sense * -> and so it's implemented right now */ - if ( mi->context.c1.tuntap->ipv6 && - mi->context.options.push_ifconfig_ipv6_defined ) + if ( mi->context.options.push_ifconfig_ipv6_defined ) { mi->context.c2.push_ifconfig_ipv6_local = mi->context.options.push_ifconfig_ipv6_local; @@ -1511,7 +1509,7 @@ multi_set_virtual_addr_env (struct multi_context *m, struct multi_instance *mi) setenv_del (mi->context.c2.es, "ifconfig_pool_remote_ip6"); setenv_del (mi->context.c2.es, "ifconfig_pool_ip6_netbits"); - if (mi->context.c1.tuntap->ipv6 && mi->context.c2.push_ifconfig_ipv6_defined) + if (mi->context.c2.push_ifconfig_ipv6_defined) { setenv_in6_addr (mi->context.c2.es, "ifconfig_pool_remote", diff --git a/src/openvpn/openvpn.h b/src/openvpn/openvpn.h index 65a183a736d..5cda7b4519a 100644 --- a/src/openvpn/openvpn.h +++ b/src/openvpn/openvpn.h @@ -390,11 +390,6 @@ struct context_2 struct buffer to_tun; struct buffer to_link; - /* - * IPv4 TUN device? - */ - bool ipv4_tun; - /* should we print R|W|r|w to console on packet transfers? */ bool log_rw; diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 1ed14b0da99..281ef0b5e59 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -175,7 +175,6 @@ static const char usage_message[] = " /dev/net/tun, /dev/tun, /dev/tap, etc.\n" "--lladdr hw : Set the link layer address of the tap device.\n" "--topology t : Set --dev tun topology: 'net30', 'p2p', or 'subnet'.\n" - "--tun-ipv6 : Build tun link capable of forwarding IPv6 traffic.\n" #ifdef ENABLE_IPROUTE "--iproute cmd : Use this command instead of default " IPROUTE_PATH ".\n" #endif @@ -1500,7 +1499,6 @@ show_settings (const struct options *o) SHOW_STR (dev_node); SHOW_STR (lladdr); SHOW_INT (topology); - SHOW_BOOL (tun_ipv6); SHOW_STR (ifconfig_local); SHOW_STR (ifconfig_remote_netmask); SHOW_BOOL (ifconfig_noexec); @@ -2103,10 +2101,6 @@ options_postprocess_verify_ce (const struct options *options, const struct conne options->connection_list->array[0]->remote) msg (M_USAGE, " cannot be used with --mode server"); -#if 0 - if (options->tun_ipv6) - msg (M_USAGE, "--tun-ipv6 cannot be used with --mode server"); -#endif if (options->shaper) msg (M_USAGE, "--shaper cannot be used with --mode server"); if (options->inetd) @@ -2130,9 +2124,6 @@ options_postprocess_verify_ce (const struct options *options, const struct conne msg (M_USAGE, "--ifconfig-pool-persist must be used with --ifconfig-pool"); if (options->ifconfig_ipv6_pool_defined && !options->ifconfig_ipv6_local ) msg (M_USAGE, "--ifconfig-ipv6-pool needs --ifconfig-ipv6"); - if (options->ifconfig_ipv6_local && !options->tun_ipv6 ) - msg (M_INFO, "Warning: --ifconfig-ipv6 without --tun-ipv6 will not do IPv6"); - if (options->auth_user_pass_file) msg (M_USAGE, "--auth-user-pass cannot be used with --mode server (it should be used on the client side only)"); if (options->ccd_exclusive && !options->client_config_dir) @@ -3081,7 +3072,7 @@ options_string (const struct options *o, /* send tun_ipv6 only in peer2peer mode - in client/server mode, it * is usually pushed by the server, triggering a non-helpful warning */ - if (o->tun_ipv6 && o->mode == MODE_POINT_TO_POINT && !PULL_DEFINED(o)) + if (o->ifconfig_ipv6_local && o->mode == MODE_POINT_TO_POINT && !PULL_DEFINED(o)) buf_printf (&out, ",tun-ipv6"); /* @@ -4582,7 +4573,7 @@ add_option (struct options *options, else if (streq (p[0], "tun-ipv6") && !p[1]) { VERIFY_PERMISSION (OPT_P_UP); - options->tun_ipv6 = true; + msg (M_WARN, "Note: option tun-ipv6 is ignored because modern operating systems do not need special IPv6 tun handling anymore."); } #ifdef ENABLE_IPROUTE else if (streq (p[0], "iproute") && p[1] && !p[2]) diff --git a/src/openvpn/options.h b/src/openvpn/options.h index 9b7b57cf036..b7453a033a0 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -251,7 +251,6 @@ struct options int ping_send_timeout; /* Send a TCP/UDP ping to remote every n seconds */ int ping_rec_timeout; /* Expect a TCP/UDP ping from remote at least once every n seconds */ bool ping_timer_remote; /* Run ping timer only if we have a remote address */ - bool tun_ipv6; /* Build tun dev that supports IPv6 */ # define PING_UNDEF 0 # define PING_EXIT 1 diff --git a/src/openvpn/route.c b/src/openvpn/route.c index 307366625b5..96d4e11e352 100644 --- a/src/openvpn/route.c +++ b/src/openvpn/route.c @@ -1718,10 +1718,11 @@ add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int fla } #endif - if ( !tt->ipv6 ) + if (!tt->did_ifconfig_ipv6_setup) { - msg( M_INFO, "add_route_ipv6(): not adding %s/%d, no IPv6 on if %s", - network, r6->netbits, device ); + msg( M_INFO, "add_route_ipv6(): not adding %s/%d: " + "no IPv6 address been configured on interface %s", + network, r6->netbits, device); return; } @@ -2148,13 +2149,6 @@ delete_route_ipv6 (const struct route_ipv6 *r6, const struct tuntap *tt, unsigne } #endif - if ( !tt->ipv6 ) - { - msg( M_INFO, "delete_route_ipv6(): not deleting %s/%d, no IPv6 on if %s", - network, r6->netbits, device ); - return; - } - msg( M_INFO, "delete_route_ipv6(%s/%d)", network, r6->netbits ); /* if we used a gateway on "add route", we also need to specify it on diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index b7a29f718c1..103112f86e4 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -741,8 +741,8 @@ do_ifconfig (struct tuntap *tt, argv_init (&argv); - msg( M_INFO, "do_ifconfig, tt->ipv6=%d, tt->did_ifconfig_ipv6_setup=%d", - tt->ipv6, tt->did_ifconfig_ipv6_setup ); + msg( M_DEBUG, "do_ifconfig, tt->did_ifconfig_ipv6_setup=%d", + tt->did_ifconfig_ipv6_setup ); /* * We only handle TUN/TAP devices here, not --dev null devices. @@ -755,7 +755,7 @@ do_ifconfig (struct tuntap *tt, ifconfig_local = print_in_addr_t (tt->local, 0, &gc); ifconfig_remote_netmask = print_in_addr_t (tt->remote_netmask, 0, &gc); - if ( tt->ipv6 && tt->did_ifconfig_ipv6_setup ) + if (tt->did_ifconfig_ipv6_setup ) { ifconfig_ipv6_local = print_in6_addr (tt->local_ipv6, 0, &gc); ifconfig_ipv6_remote = print_in6_addr (tt->remote_ipv6, 0, &gc); @@ -1077,13 +1077,6 @@ do_ifconfig (struct tuntap *tt, #elif defined(TARGET_NETBSD) -/* whether or not NetBSD can do IPv6 can be seen by the availability of - * the TUNSIFHEAD ioctl() - see next TARGET_NETBSD block for more details - */ -#ifdef TUNSIFHEAD -# define NETBSD_MULTI_AF -#endif - if (tun) argv_printf (&argv, "%s %s %s %s mtu %d netmask 255.255.255.255 up", @@ -1126,7 +1119,6 @@ do_ifconfig (struct tuntap *tt, if ( do_ipv6 ) { -#ifdef NETBSD_MULTI_AF argv_printf (&argv, "%s %s inet6 %s/%d", IFCONFIG_PATH, @@ -1139,10 +1131,6 @@ do_ifconfig (struct tuntap *tt, /* and, hooray, we explicitely need to add a route... */ add_route_connected_v6_net(tt, es); -#else - msg( M_INFO, "no IPv6 support for tun interfaces on NetBSD before 4.0 (if your system is newer, recompile openvpn)" ); - tt->ipv6 = false; -#endif } tt->did_ifconfig = true; @@ -1425,7 +1413,6 @@ clear_tuntap (struct tuntap *tuntap) #ifdef TARGET_SOLARIS tuntap->ip_fd = -1; #endif - tuntap->ipv6 = false; } static void @@ -1478,7 +1465,7 @@ write_tun_header (struct tuntap* tt, uint8_t *buf, int len) iph = (struct ip *) buf; - if (tt->ipv6 && iph->ip_v == 6) + if (iph->ip_v == 6) type = htonl (AF_INET6); else type = htonl (AF_INET); @@ -1518,17 +1505,12 @@ read_tun_header (struct tuntap* tt, uint8_t *buf, int len) #ifndef WIN32 static void open_tun_generic (const char *dev, const char *dev_type, const char *dev_node, - bool ipv6_explicitly_supported, bool dynamic, - struct tuntap *tt) + bool dynamic, struct tuntap *tt) { char tunname[256]; char dynamic_name[256]; bool dynamic_opened = false; - - if ( tt->ipv6 && ! ipv6_explicitly_supported ) - msg (M_WARN, "NOTE: explicit support for IPv6 tun devices is not provided for this OS"); - if (tt->type == DEV_TYPE_NULL) { open_null (tt); @@ -1710,7 +1692,6 @@ read_tun (struct tuntap* tt, uint8_t *buf, int len) } #elif defined(TARGET_LINUX) -#ifdef HAVE_LINUX_IF_TUN_H /* New driver support */ #ifndef HAVE_LINUX_SOCKIOS_H #error header file linux/sockios.h required @@ -1751,8 +1732,7 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tu * Process --tun-ipv6 */ CLEAR (ifr); - if (!tt->ipv6) - ifr.ifr_flags = IFF_NO_PI; + ifr.ifr_flags = IFF_NO_PI; #if defined(IFF_ONE_QUEUE) && defined(SIOCSIFTXQLEN) ifr.ifr_flags |= IFF_ONE_QUEUE; @@ -1833,32 +1813,10 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tu ASSERT (0); } -#endif - -#else - -void -open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) -{ - open_tun_generic (dev, dev_type, dev_node, false, true, tt); -} - -#endif /* HAVE_LINUX_IF_TUN_H */ +#endif /* !PENDANTIC */ #ifdef ENABLE_FEATURE_TUN_PERSIST -/* - * This can be removed in future - * when all systems will use newer - * linux-headers - */ -#ifndef TUNSETOWNER -#define TUNSETOWNER _IOW('T', 204, int) -#endif -#ifndef TUNSETGROUP -#define TUNSETGROUP _IOW('T', 206, int) -#endif - void tuncfg (const char *dev, const char *dev_type, const char *dev_node, int persist_mode, const char *username, const char *groupname, const struct tuntap_options *options) { @@ -1940,7 +1898,7 @@ close_tun (struct tuntap *tt) argv_msg (M_INFO, &argv); openvpn_execve_check (&argv, NULL, 0, "Linux ip addr del failed"); - if (tt->ipv6 && tt->did_ifconfig_ipv6_setup) + if (tt->did_ifconfig_ipv6_setup) { const char * ifconfig_ipv6_local = print_in6_addr (tt->local_ipv6, 0, &gc); @@ -1977,53 +1935,13 @@ close_tun (struct tuntap *tt) int write_tun (struct tuntap* tt, uint8_t *buf, int len) { - if (tt->ipv6) - { - struct tun_pi pi; - struct iphdr *iph; - struct iovec vect[2]; - int ret; - - iph = (struct iphdr *)buf; - - pi.flags = 0; - - if(iph->version == 6) - pi.proto = htons(OPENVPN_ETH_P_IPV6); - else - pi.proto = htons(OPENVPN_ETH_P_IPV4); - - vect[0].iov_len = sizeof(pi); - vect[0].iov_base = π - vect[1].iov_len = len; - vect[1].iov_base = buf; - - ret = writev(tt->fd, vect, 2); - return(ret - sizeof(pi)); - } - else - return write (tt->fd, buf, len); + return write (tt->fd, buf, len); } int read_tun (struct tuntap* tt, uint8_t *buf, int len) { - if (tt->ipv6) - { - struct iovec vect[2]; - struct tun_pi pi; - int ret; - - vect[0].iov_len = sizeof(pi); - vect[0].iov_base = π - vect[1].iov_len = len; - vect[1].iov_base = buf; - - ret = readv(tt->fd, vect, 2); - return(ret - sizeof(pi)); - } - else - return read (tt->fd, buf, len); + return read (tt->fd, buf, len); } #elif defined(TARGET_SOLARIS) @@ -2227,7 +2145,7 @@ solaris_close_tun (struct tuntap *tt) if (tt) { /* IPv6 interfaces need to be 'manually' de-configured */ - if ( tt->ipv6 && tt->did_ifconfig_ipv6_setup ) + if ( tt->did_ifconfig_ipv6_setup ) { struct argv argv; argv_init (&argv); @@ -2341,7 +2259,7 @@ read_tun (struct tuntap* tt, uint8_t *buf, int len) void open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) { - open_tun_generic (dev, dev_type, dev_node, true, true, tt); + open_tun_generic (dev, dev_type, dev_node, true, tt); /* Enable multicast on the interface */ if (tt->fd >= 0) @@ -2435,11 +2353,7 @@ read_tun (struct tuntap *tt, uint8_t *buf, int len) void open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) { -#ifdef NETBSD_MULTI_AF - open_tun_generic (dev, dev_type, dev_node, true, true, tt); -#else - open_tun_generic (dev, dev_type, dev_node, false, true, tt); -#endif + open_tun_generic (dev, dev_type, dev_node, true, tt); if (tt->fd >= 0) { @@ -2448,7 +2362,6 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tu i = 0; ioctl (tt->fd, TUNSLMODE, &i); /* link layer mode off */ -#ifdef NETBSD_MULTI_AF if ( tt->type == DEV_TYPE_TUN ) { i = 1; @@ -2457,7 +2370,6 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tu msg (M_WARN | M_ERRNO, "ioctl(TUNSIFHEAD): %s", strerror(errno)); } } -#endif } } @@ -2496,8 +2408,6 @@ close_tun (struct tuntap *tt) } } -#ifdef NETBSD_MULTI_AF - static inline int netbsd_modify_read_write_return (int len) { @@ -2518,7 +2428,7 @@ write_tun (struct tuntap* tt, uint8_t *buf, int len) iph = (struct openvpn_iphdr *) buf; - if (tt->ipv6 && OPENVPN_IPH_GET_VER(iph->version_len) == 6) + if (OPENVPN_IPH_GET_VER(iph->version_len) == 6) type = htonl (AF_INET6); else type = htonl (AF_INET); @@ -2553,21 +2463,6 @@ read_tun (struct tuntap* tt, uint8_t *buf, int len) return read (tt->fd, buf, len); } -#else /* not NETBSD_MULTI_AF -> older code, IPv4 only */ - -int -write_tun (struct tuntap* tt, uint8_t *buf, int len) -{ - return write (tt->fd, buf, len); -} - -int -read_tun (struct tuntap* tt, uint8_t *buf, int len) -{ - return read (tt->fd, buf, len); -} -#endif /* NETBSD_MULTI_AF */ - #elif defined(TARGET_FREEBSD) static inline int @@ -2582,7 +2477,7 @@ freebsd_modify_read_write_return (int len) void open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) { - open_tun_generic (dev, dev_type, dev_node, true, true, tt); + open_tun_generic (dev, dev_type, dev_node, true, tt); if (tt->fd >= 0 && tt->type == DEV_TYPE_TUN) { @@ -2644,7 +2539,7 @@ write_tun (struct tuntap* tt, uint8_t *buf, int len) iph = (struct ip *) buf; - if (tt->ipv6 && iph->ip_v == 6) + if (iph->ip_v == 6) type = htonl (AF_INET6); else type = htonl (AF_INET); @@ -2693,7 +2588,7 @@ dragonfly_modify_read_write_return (int len) void open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) { - open_tun_generic (dev, dev_type, dev_node, true, true, tt); + open_tun_generic (dev, dev_type, dev_node, true, tt); if (tt->fd >= 0) { @@ -2727,7 +2622,7 @@ write_tun (struct tuntap* tt, uint8_t *buf, int len) iph = (struct ip *) buf; - if (tt->ipv6 && iph->ip_v == 6) + if (iph->ip_v == 6) type = htonl (AF_INET6); else type = htonl (AF_INET); @@ -2920,7 +2815,7 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tu { /* No explicit utun and utun failed, try the generic way) */ msg (M_INFO, "Failed to open utun device. Falling back to /dev/tun device"); - open_tun_generic (dev, dev_type, NULL, true, true, tt); + open_tun_generic (dev, dev_type, NULL, true, tt); } else { @@ -2941,7 +2836,7 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tu if (dev_node && strcmp (dev_node, "tun")==0) dev_node=NULL; - open_tun_generic (dev, dev_type, dev_node, true, true, tt); + open_tun_generic (dev, dev_type, dev_node, true, tt); } } @@ -2954,7 +2849,7 @@ close_tun (struct tuntap* tt) struct argv argv; argv_init (&argv); - if ( tt->ipv6 && tt->did_ifconfig_ipv6_setup ) + if (tt->did_ifconfig_ipv6_setup ) { const char * ifconfig_ipv6_local = print_in6_addr (tt->local_ipv6, 0, &gc); @@ -5182,7 +5077,7 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tu /*netcmd_semaphore_lock ();*/ - msg( M_INFO, "open_tun, tt->ipv6=%d", tt->ipv6 ); + msg( M_INFO, "open_tun"); if (tt->type == DEV_TYPE_NULL) { @@ -5308,11 +5203,10 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tu /* usage of numeric constants is ugly, but this is really tied to * *this* version of the driver */ - if ( tt->ipv6 && tt->type == DEV_TYPE_TUN && + if (tt->type == DEV_TYPE_TUN && info[0] == 9 && info[1] < 8) { - msg( M_INFO, "WARNING: Tap-Win32 driver version %d.%d does not support IPv6 in TUN mode. IPv6 will be disabled. Upgrade to Tap-Win32 9.8 (2.2-beta3 release or later) or use TAP mode to get IPv6", (int) info[0], (int) info[1] ); - tt->ipv6 = false; + msg( M_INFO, "WARNING: Tap-Win32 driver version %d.%d does not support IPv6 in TUN mode. IPv6 will not work. Upgrade your Tap-Win32 driver.", (int) info[0], (int) info[1] ); } /* tap driver 9.8 (2.2.0 and 2.2.1 release) is buggy @@ -5320,7 +5214,7 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tu if ( tt->type == DEV_TYPE_TUN && info[0] == 9 && info[1] == 8) { - msg( M_FATAL, "ERROR: Tap-Win32 driver version %d.%d is buggy regarding small IPv4 packets in TUN mode. Upgrade to Tap-Win32 9.9 (2.2.2 release or later) or use TAP mode", (int) info[0], (int) info[1] ); + msg( M_FATAL, "ERROR: Tap-Win32 driver version %d.%d is buggy regarding small IPv4 packets in TUN mode. Upgrade your Tap-Win32 driver.", (int) info[0], (int) info[1] ); } } @@ -5653,7 +5547,7 @@ close_tun (struct tuntap *tt) if (tt) { - if ( tt->ipv6 && tt->did_ifconfig_ipv6_setup ) + if ( tt->did_ifconfig_ipv6_setup ) { if (tt->options.msg_channel) { @@ -5790,7 +5684,7 @@ ipset2ascii_all (struct gc_arena *gc) void open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) { - open_tun_generic (dev, dev_type, dev_node, false, true, tt); + open_tun_generic (dev, dev_type, dev_node, true, tt); } void diff --git a/src/openvpn/tun.h b/src/openvpn/tun.h index 4e93a3fd43d..88431fbe0a4 100644 --- a/src/openvpn/tun.h +++ b/src/openvpn/tun.h @@ -139,8 +139,6 @@ struct tuntap bool did_ifconfig_ipv6_setup; bool did_ifconfig; - bool ipv6; - bool persistent_if; /* if existed before, keep on program end */ struct tuntap_options options; /* options set on command line */ From 533495298bd93ddaaf4418dc666922779ce5ef9b Mon Sep 17 00:00:00 2001 From: Heiko Hund Date: Fri, 24 Jun 2016 18:01:41 +0200 Subject: [PATCH 334/643] Windows: do_ifconfig() after open_tun() When you had multiple TAP adapters and IPv6 configured you got an error message about "you must also specify --dev-node" and openvpn exited. Very inconvenient especially since this is only due to the fact that Windows tries to set the adapter address before it is opened; for no good reason. This patch changes the order to IFCONFIG_AFTER_TUN_OPEN, moves some initialization code to init_tun, where it belongs, and removes duplicate code that is now no longer needed. v2: do not use "%lu" in argv_printf(), crashes non-iservice usage Signed-off-by: Heiko Hund Signed-off-by: Gert Doering Acked-by: Gert Doering Acked-by: Heiko Hund Message-Id: <20161009152550.GQ78279@greenie.muc.de> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12631.html Signed-off-by: Gert Doering --- src/openvpn/tun.c | 54 ++++++++++++++++------------------------------- src/openvpn/tun.h | 2 +- 2 files changed, 19 insertions(+), 37 deletions(-) diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index 103112f86e4..af685de37eb 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -611,6 +611,21 @@ init_tun (const char *dev, /* --dev option */ tt->broadcast = generate_ifconfig_broadcast_addr (tt->local, tt->remote_netmask); } +#ifdef WIN32 + /* + * Make sure that both ifconfig addresses are part of the + * same .252 subnet. + */ + if (tun) + { + verify_255_255_255_252 (tt->local, tt->remote_netmask); + tt->adapter_netmask = ~3; + } + else + { + tt->adapter_netmask = tt->remote_netmask; + } +#endif tt->did_ifconfig_setup = true; } @@ -1315,19 +1330,7 @@ do_ifconfig (struct tuntap *tt, } #elif defined (WIN32) { - /* - * Make sure that both ifconfig addresses are part of the - * same .252 subnet. - */ - if (tun) - { - verify_255_255_255_252 (tt->local, tt->remote_netmask); - tt->adapter_netmask = ~3; - } - else - { - tt->adapter_netmask = tt->remote_netmask; - } + ASSERT (actual != NULL); switch (tt->options.ip_win32_type) { @@ -1338,9 +1341,6 @@ do_ifconfig (struct tuntap *tt, print_in_addr_t (tt->adapter_netmask, 0, &gc)); break; case IPW32_SET_NETSH: - if (!strcmp (actual, "NULL")) - msg (M_FATAL, "Error: When using --ip-win32 netsh, if you have more than one TAP-Windows adapter, you must also specify --dev-node"); - netsh_ifconfig (&tt->options, actual, tt->local, @@ -1354,25 +1354,6 @@ do_ifconfig (struct tuntap *tt, if ( do_ipv6 ) { - char * saved_actual; - char iface[64]; - DWORD idx; - - if (!strcmp (actual, "NULL")) - msg (M_FATAL, "Error: When using --tun-ipv6, if you have more than one TAP-Windows adapter, you must also specify --dev-node"); - - idx = get_adapter_index_flexible(actual); - openvpn_snprintf(iface, sizeof(iface), "interface=%lu", idx); - - /* on windows, OpenVPN does ifconfig first, open_tun later, so - * tt->actual_name might not yet be initialized, but routing code - * needs to know interface name - point to "actual", restore later - */ - saved_actual = tt->actual_name; - tt->actual_name = (char*) actual; - /* we use adapter_index in add_route_ipv6 */ - tt->adapter_index = idx; - if (tt->options.msg_channel) { do_address_service (true, AF_INET6, tt); @@ -1380,6 +1361,8 @@ do_ifconfig (struct tuntap *tt, else { /* example: netsh interface ipv6 set address interface=42 2001:608:8003::d store=active */ + char iface[64]; + openvpn_snprintf(iface, sizeof(iface), "interface=%lu", tt->adapter_index ); argv_printf (&argv, "%s%sc interface ipv6 set address %s %s store=active", get_win_sys_path(), @@ -1391,7 +1374,6 @@ do_ifconfig (struct tuntap *tt, /* explicit route needed */ add_route_connected_v6_net(tt, es); - tt->actual_name = saved_actual; } #else msg (M_FATAL, "Sorry, but I don't know how to do 'ifconfig' commands on this operating system. You should ifconfig your TUN/TAP device manually or use an --up script."); diff --git a/src/openvpn/tun.h b/src/openvpn/tun.h index 88431fbe0a4..6e3086c7228 100644 --- a/src/openvpn/tun.h +++ b/src/openvpn/tun.h @@ -299,7 +299,7 @@ ifconfig_order(void) #elif defined(TARGET_NETBSD) return IFCONFIG_AFTER_TUN_OPEN; #elif defined(WIN32) - return IFCONFIG_BEFORE_TUN_OPEN; + return IFCONFIG_AFTER_TUN_OPEN; #elif defined(TARGET_ANDROID) return IFCONFIG_BEFORE_TUN_OPEN; #else From a6479b4814d38d3003b1f5ea4b041f6c72785851 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Mon, 17 Oct 2016 15:16:06 +0200 Subject: [PATCH 335/643] Preparing for release v2.4_alpha1 (ChangeLog, version.m4) Signed-off-by: Gert Doering --- ChangeLog | 781 ++++++++++++++++++++++++++++++++++++++++++++++++++++- version.m4 | 6 +- 2 files changed, 783 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index 7b945c80104..23ee03f6bec 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,784 @@ OpenVPN Change Log -Copyright (C) 2002-2012 OpenVPN Technologies, Inc. +Copyright (C) 2002-2016 OpenVPN Technologies, Inc. + +2016.10.17 -- Version 2.4_alpha1 + +Adriaan de Jong (2): + Fixed a bug where PolarSSL gave an error when using an inline file tag. + Fix --show-pkcs11-ids (Bug #239) + +Alexander Pyhalov (1): + Default gateway can't be determined on illumos/Solaris platforms + +Alon Bar-Lev (1): + pkcs11: use generic evp key instead of rsa + +Andris Kalnozols (3): + Fix some typos in the man page. + Do not upcase x509-username-field for mixed-case arguments. + extract_x509_extension(): hide status message during normal operation. + +Arne Schwabe (100): + Document man agent-external-key + Options parsing demands unnecessary configuration if PKCS11 is used + Error message if max-routes used incorrectly + Properly require --key even if defined(MANAGMENT_EXTERNAL_KEY) + Remove dnsflags_to_socktype, it is not used anywhere + Fix the proto is used inconsistently warning + Remove dead code path and putenv functionality + Remove unused function xor + Move static prototype definition from header into c file + Remove unused function no_tap_ifconfig + Add the client id (CID) to the output of the status command + Print client id only if compiled with man agent support. Otherwise print an empty string. + Allow routes to be set before opening tun, similar to ifconfig before opening tun + Add ability to send/receive file descriptors via management interface + Android platform specific changes. + Emulate persist-tun on Android + Document the Android implementation in OpenVPN + Only print script warnings when a script is used. Remove stray mention of script-security system. + Fix #ifdefs for P2MP_SERVER + Move settings of user script into set_user_script function + Move checking of script file access into set_user_script + Fix another #ifdef/#if P2MP_SERVER + PATCHv3 Remove unused variables or put them to the defines they are being used in + Add support of utun devices under Mac OS X + Add support to ignore specific options. + Add a note what setenv opt does for OpenVPN < 2.3.3 + Implement custom HTTP header for http-proxy, and always send user-agent: + Add reporting of UI version to basic push-peer-info set. + Change the type of all ports in openvpn to const char* and let getaddrinfo resolve the port together with the hostname. + Fix compile error in ssl_openssl introduced by polar external-management patch + Simplify print_sockaddr_ex function, merge duplicate ipv4/ipv6 logic. + Split the PROTO_UDP_xx options into AF_INET/AF_INET6 and PROTO_TCP/PROTO_UDP part. + Fix two instances of asserting AF_INET + Fix assertion when SIGUSR1 is received while getaddrinfo is successful + Split link_socket_init_phase1 and link_socket_init_phase2 into smaller more managable/readable functions. No functional changes + Change proto_remote() function to return a constant string + Remove the ip-remote-hint option. + change the type of 'remote' to addrinfo*, and rename to 'remote_list'. + When resolving fails print the error message from socket layer + Implement dual stack client support for OpenVPN + Move ASSERT so external-key with OpenSSL works again + Implement listing on IPv4/IPv6 dual socket on all platform + Add warning for using connection block variables after connection blocks + Update IPv6 related readme files + Introduce safety check for http proxy options + Fix warning for max-routes: do not quit when parsing an old configuration. Format the message to be more like the other deprecated options + Fix connecting to localhost on Android + Move the initialization of the environment to the top so c2.es is initialized + Workaround broken Android 4.4 VpnService API for persist-tun mode + Implement an easy parsable log output that allows access to flags of the log message + Introduce an option to resolve dns names in advance for --remote, --local and --http-proxy + Fix for server selecting address family + Don't show the connection profile store in options->ce if there is a connection_list defined. + Add gateway and device to android control messages + Clean up of socket code. + Fix assert when using port-share + Work around Solaris getaddrinfo() returing ai_protocol=0 + Fix man page and OSCP script: tls_serial_{n} is decimal + Remove ENABLE_BUFFER_LIST + Fix server routes not working in topology subnet with --server [v3] + Always enable http-proxy and socks-proxy + Remove deprecated --max-routes option from manual + Add documentation for PERSIST_TUN_ACTION (Android specific) + Remove possibility of using --tls-auth with non OpenVPN Static key files + Remove unused function sock_addr_set + Document the default for tls-cipher. + Report missing end-tags of inline files as errors + Fix commit e473b7c if an inline file happens to have a line break exactly at buffer limit + Show extra-certs in current parameters, fix clang warning and logic error in preresolve + Remove unused function h_errno_msg + Add support for requesting the fd again to rebind to the next interface. + Don't redirect the gateway on Android even if requested + Fix loglevel of protect socket message + Extend network-change command to allow reprotecting on the same network (for short connection losses) + Use pseudo gw as default gw on Android as a workaround for not being able to read /proc/net/route + Remove #ifdefs for client nat support. + Do not install a host route for the VPN on Android + Fix commit c67acea173dc9ee37220f5b9ff14ede081181992 + Do not set the buffer size by default but rely on the operation system default. + Start Changes.rst that lists changes in 2.4.0 + Remove --enable-password-save option + Reflect enable-password-save change in documentation + Also remove second instance of enable-password-save in the man page + Detect config lines that are too long and give a warning/error + Implement the compression V2 data format for stub and lz4. + Fix assert when comp is called with unknown algorithm, always call comp init method + Ignore stamp-h2 we generate during build process + Implement inlining of crl files + Complete push-peer-info documentation and allow IV_PLAT_VER for other platforms than Windows if the client UI supplies it. + Remove http-proxy-timeout, socks timeout and set default of server-poll-timeout to 120s + Add documentation for http-proxy-user-pass option + Remove http-proxy-retry and socks-proxy-retry. + Update android documentation to match source code + Use AES ciphers in our sample configuration files and add a few modern 2.4 examples + Fix ENABLE_CRYPTO_OPENSSL set to YES even with --disable-crypto set + Prefer RECVDSTADDR to PKTINFO for IPv4 in OS X since it actually works (unlike PKTINFO) + Incorporate the Debian typo fixes where appropriate and make show_opt default message clearer + Enable TCP non-linear packet ID + Change the hold command to communicate the time that OpenVPN would wait to the UI. + Remove tun-ipv6 Option. Instead assume that IPv6 is always supported. + +Boris Lytochkin (1): + Log serial number of revoked certificate + +Christian Hesse (1): + fix build with automake 1.13(.1) + +Christian Niessner (1): + Fix corner case in NTLM authentication (trac #172) + +Christos Trochalakis (1): + Adjust server-ipv6 documentation + +Cristian Rodriguez (1): + Use SSL_MODE_RELEASE_BUFFERS if available + +Daniel Hahler (1): + options: fix option check for "plugin" + +Daniel Kubec (4): + Added support for TLS Keying Material Exporters [RFC-5705] + Added document for TLS Keying Material Exporters [RFC-5705] + sample-plugin: TLS Keying Material Exporter [RFC-5705] demonstration plug-in + Fix buffer size parameter for exported keying material. + +David Sommerseth (44): + Make git ignore some more files + Remove the support for using system() when executing external programs or scripts + Fix double-free issue in pf_destroy_context() + Reset the version.m4 version for the master branch + Avoid recursion in virtual_output_callback_func() + The get_default_gateway() function uses warn() instead of msg() + Improve the git revision tracking + man page: Update man page about the tls_digest_{n} environment variable + Remove the --disable-eurephia configure option + plugin: Extend the plug-in v3 API to identify the SSL implementation used + autoconf: Fix typo + t_client.sh: Check for fping/fping6 availability + t_client.sh: Write errors to stderr and document requirements + t_client.sh: Add prepare/cleanup possibilties for each test case + Fix file checks when --chroot is being used + Adjusted autotools files to build more cleanly on newer autoconf/automake versions + Improve error reporting on file access to --client-config-dir and --ccd-exclusive + Don't let openvpn_popen() keep zombies around + Don't try to use systemd-ask-password if it is not available + Clean up the pipe closing in openvpn_popen() + Add systemd unit file for OpenVPN + systemd: Use systemd functions to consider systemd availability + systemd: Reworked the systemd unit file to handle server and client configs better + autotools: Fix wrong ./configure help screen default values + down-root plugin: Replaced system() calls with execve() + down-root: Improve error messages + plugin, down-root: Fix compiler warnings + sockets: Remove the limitation of --tcp-nodelay to be server-only + plugins, down-root: Code style clean-up + Provide compile time OpenVPN version information to plug-ins + Provide OpenVPN runtime version information to plug-ins + Avoid partial authentication state when using --disabled in CCD configs + Only build and run cmocka unit tests if its submodule is initialized + Another fix related to unit test framework + Remove NOP function and callers + Revert "Drop recursively routed packets" + Fix client connection instant timeout + t_client.sh: Make OpenVPN write PID file to avoid various sudo issues + t_client.sh: Add support for Kerberos/ksu + t_client.sh: Improve detection if the OpenVPN process did start during tests + Rework the user input interface to make it more modular + Re-implement the systemd support using the new query user API + systemd: Do not mask usernames when querying for it via systemd-ask-password + Move memcmp_constant_time() to crypto.h + +David Woodhouse (2): + pkcs11: Load p11-kit-proxy.so module by default + Make 'provider' option to --show-pkcs11-ids optional where p11-kit is present + +Davide Brini (2): + Provide more accurate warning message + Document authfile for socks server + +Dmitrij Tejblum (1): + Fix is_ipv6 in case of tap interface. + +Dorian Harmans (1): + Add CHACHA20-POLY1305 ciphersuite IANA name translations. + +Felix Janda (1): + Use OPENVPN_ETH_P_* so that is unecessary + +Fish (1): + Add lz4 support to MSVC. + +Gert Doering (110): + Implement --mssfix handling for IPv6 packets. + Fix option inconsistency warnings about "proto" and "tun-ipv6" + Fix parameter type for IP_TOS setsockopt on non-Linux systems. + Fix client crash on double PUSH_REPLY. + Update README.IPv6 to match what is in 2.3.0 + Repair "tcp server queue overflow" brokenness, more fallout. + Permit pool size of /64.../112 for ifconfig-ipv6-pool + Add MIN() compatibility macro + Fix directly connected routes for "topology subnet" on Solaris. + Print "Virtual IPv6 Address" on management interface queries [v4] + Use constrain_int() instead of MIN()+syshead.c compat definition - v2. + Fix NULL-pointer crash in route_list_add_vpn_gateway(). + Fix usage of 'compression ...' from global config. + Make push-peer-info visible in "normal" per-instance environment. + Fix problem with UDP tunneling due to mishandled pktinfo structures. + Improve documentation and help text for --route-ipv6. + Fix argument type warning introduced by http extra proxy header patch. + Fix IPv6 examples in t_client.rc-sample + Fix slow memory drain on each client renegotiation. + t_client.sh: ignore fields from "ip -6 route show" output that distort results. + Fix IPv6_V6ONLY logic. + Implement LZ4 compression. + Provide LZ4 sources in src/compat/ and use if no system lz4 library found. + Document "lz4" argument to "compress" config option. + Make code and documentation for --remote-random-hostname consistent. + Reduce IV_OPENVPN_GUI_VERSION= to IV_GUI_VER= + remove some 'unused variable' warnings + Cleanup ir6->netbits handling. + Document issue with --chroot, /dev/urandom and PolarSSL. + Rename 'struct route' to 'struct route_ipv4' + Replace copied structure elements with including + Add "test-driver" and "compile" to .gitignore + Fix crash when using --inetd. + IPv6 address/route delete fix for Win8 + Add SSL library version reporting. + Minor t_client.sh cleanups + Repair --multihome on FreeBSD for IPv4 sockets. + Rewrite manpage section about --multihome + More IPv6-related updates to the openvpn man page. + Conditionalize calls to print_default_gateway on !ENABLE_SMALL + Merge get_default_gateway() implementation for all 4+1 BSD variants. + Drop incoming fe80:: packets silently now. + Recognize AIX, define TARGET_AIX + Add tap driver initialization and ifconfig for AIX. + implement adding/deleting routes on AIX, for IPv4 and IPv6 + Make t_client.sh work on AIX. + Fix t_lpback.sh platform-dependent failures + Call init script helpers with explicit path (./) + Fix windows build on older mingw versions. + New approach to handle peer-id related changes to link-mtu. + Print remote IPv4 address on a dual-stack v6 socket in IPv4 format + Fix incorrect use of get_ipv6_addr() for iroute options. + Remove count_netmask_bits(), convert users to use netmask_to_netbits2() + Fix leftover 'if (false) ;' statements + Print helpful error message on --mktun/--rmtun if not available. + explain effect of --topology subnet on --ifconfig + Add note about file permissions and --crl-verify to manpage. + repair --dev null breakage caused by db950be85d37 + assume res_init() is always there. + Correct note about DNS randomization in openvpn.8 + Disallow usage of --server-poll-timeout in --secret key mode. + slightly enhance documentation about --cipher + Enforce "serial-tests" behaviour for tests/Makefile + Revert "Enforce "serial-tests" behaviour for tests/Makefile" + On signal reception, return EAI_SYSTEM from openvpn_getaddrinfo(). + Use configure.ac hack to apply serial_test AM option only if supported. + Use EAI_AGAIN instead of EAI_SYSTEM for openvpn_getaddrinfo(). + Move res_init() call to inner openvpn_getaddrinfo() loop + Fix FreeBSD ifconfig for topology subnet tunnels. + Produce a meaningful error message if --daemon gets in the way of asking for passwords. + Document --daemon changes and consequences (--askpass, --auth-nocache). + Fix build on OpenSolaris (non-gmake) + Un-break --auth-user-pass on windows + refactor struct route_ipv6, bring in line with struct route_ipv4 again + refactor struct route_ipv6_list, bring in line with struct route_list again + Add route_ipv6_gateway* data structures for rgi6 support. + Create basic infrastructure for IPv6 default gateway handling / redirection. + Make client delay less before sending PUSH_REQUEST + get_default_gateway_ipv6(): Linux / Netlink implementation. + Implement handling of overlapping IPv6 routes with IPv6 remote VPN server address + Implement '--redirect-gateway ipv6' + get_default_gateway_ipv6(): *BSD / MacOS / Solaris PF_ROUTE implementation + Fix IPv6 host routes to LAN gateway on OpenSolaris + Replace unaligned 16bit access to TCP MSS value with bytewise access + Repair test_local_addr() on WIN32 + Add custom check for inet_pton()/inet_ntop() on MinGW/WIN32 + get_default_gateway_ipv6(): Win32 implementation using GetBestRoute2() + Remove support for snappy compression. + Fix info.af == AF_UNSPEC case for server with --mtu-disc + Fix FreeBSD-specific mishandling of gc arena pointer in create_arbitrary_remote() + remove unused gc_arena in FreeBSD close_tun() + Un-break compilation on *BSD + Fix isatty() check for good. + Fix openserv/validate.o linking issues on mingw. + Fix library order in -lmbedtls test. + Implement push-remove option to selectively remove pushed options. + Upgrade bundled compat-lz4 to upstream release r131. + Change --enable-pedantic to use -std=c99 and not -ansi (C90). + Fix problems with NCP and --inetd. + Do not abort t_client run if OpenVPN instance does not start. + Fix IP_PKTINFO related compilation failure on NetBSD 7.0 + Show compile-time variant for --multihome in --version output. + Fix win32 building with C99 mode + Fix t_client runs on OpenSolaris + make t_client robust against sudoers misconfiguration + add POSTINIT_CMD_suf to t_client.sh and sample config + Fix --multihome for IPv6 on 64bit BSD systems. + Enable -D_SVR4_2 for compilation on Solaris + Revert "Enable -D_SVR4_2 for compilation on Solaris" + Enable -D_XPG4_2 for compilation on Solaris + +Guy Yur (1): + Fix --redirect-private in --dev tap mode. + +Heikki Hannikainen (1): + Always load intermediate certificates from a PKCS#12 file + +Heiko Hund (20): + Fix display of plugin hook types + Support UTF-8 --client-config-dir + close more file descriptors on exec + Ignore UTF-8 byte order mark + reintroduce --no-name-remapping option + make --tls-remote compatible with pre 2.3 configs + add new option for X.509 name verification + Support non-ASCII TAP adapter names on Windows + Support non-ASCII characters in Windows tmp path + make sure sa_family_t is defined + convert struct signal_info element + grow route lists dynamically + fix route struct name + refine assertion to allow other modes than CBC + Fix compilation on Windows + fix warnings on Windows + extend management interface command "state" + put virtual IPv6 addresses into env + interactive service v3 + Windows: do_ifconfig() after open_tun() + +Holger Kummert (1): + Del ipv6 addr on close of linux tun interface + +Hubert Kario (2): + ocsp_check - signature verification and cert staus results are separate + ocsp_check - double check if ocsp didn't report any errors in execution + +Ilya Shipitsin (3): + initial travis-ci support + skip t_lpback.sh and t_cltsrv.sh if openvpn configured --disable-crypto + enable "--disable-crypto" build configuration for travis + +Ivo Manca (1): + Plug memory leak in mbedTLS backend + +James Bekkema (1): + Fix socket-flag/TCP_NODELAY on Mac OS X + +James Geboski (1): + Fix --askpass not allowing for password input via stdin + +James Yonan (14): + Added support for the Snappy compression algorithm + Always push basic set of peer info values to server. + TLS version negotiation + Added "setenv opt" directive prefix. If present, and if the directive that follows is recognized, it will be processed as if the "setenv opt" prefix was absent. If present and if the directive that follows is not recognized, the directive will be ignored rather than cause a fatal error. + MSVC fixes + Set SSL_OP_NO_TICKET flag in SSL context for OpenSSL builds, to disable TLS stateless session resumption. + Use native strtoull() with MSVC 2013. + Define PATH_SEPARATOR for MSVC builds. + Fixed some compile issues with show_library_versions() + Added flags parameter to format_hex_ex. + Extended x509-track for OpenSSL to report SHA1 fingerprint. + Fixed port-share bug with DoS potential + Added directive to specify HTTP proxy credentials in config. + Bind to local socket before dropping privileges + +Jan Just Keijser (5): + man page patch for missing options + make 'explicit-exit-notify' pullable again + include ifconfig_ environment variables in --up-restart env set + Author: Jan Just Keijser + Make certificate expiry warning patch (091edd8e299686) work on OpenSSL 1.0.1 and earlier. + +Jann Horn (1): + Remove quadratic complexity from openvpn_base64_decode() + +Jeffrey Cutter (1): + Update contrib/pull-resolv-conf/client.up for no DOMAIN + +Jens Neuhalfen (6): + Make intent of utun device name validation clear + Fix buffer overflow by user supplied data + ignore the local config file t_client.rc in git + Prevent integration test timeout bc. of sudo + Add unit testing support via cmocka + Add a test for auth-pam searchandreplace + +Jens Wagner (1): + Fix spurious ignoring of pushed config options (trac#349). + +Jesse Glick (1): + Allow use of NetBeans without saving nbproject/ directory. + +Joachim Schipper (5): + doc/management-notes.txt: fix typo + Fix typo in ./configure message + Refactor tls_ctx_use_external_private_key() + --management-external-key for PolarSSL + external_pkcs1_sign: Support non-RSA_SIG_RAW hash_ids + +Jonathan K. Bullard (3): + Fix mismatch of fprintf format specifier and argument type + Fix null pointer dereference in options.c + Fail if options have extra parameters [v2] + +Josh Cepek (7): + Fix parameter listing in non-debug builds at verb 4 + (updated) [PATCH] Warn when using verb levels >=7 without debug + Fix proto tcp6 for server & non-P2MP modes + Fix Windows script execution when called from script hooks + Correct error text when no Windows TAP device is present + Require a 1.2.x PolarSSL version + Push an IPv6 CIDR mask used by the server, not the pool's size + +Julien Muchembled (1): + Fix --mtu-disc option with IPv6 transport + +Kenneth Rose (1): + Fix v3 plugins to support returning values back to OpenVPN. + +Klee Dienes (1): + tls_ctx_load_ca: Improve certificate error messages + +Leon Klingele (1): + Add link to bug tracker + +Leonardo Basilio (1): + Correctly report TCP connection timeout on windows. + +Lev Stipakov (26): + Peer-id patch v7 + Add the peer-id to the output of the status command + Prevent memory drain for long lasting floating sessions + Disallow lameduck's float to an address taken by another client + Fix NULL dereferencing + Fix mssfix default value in connection_list context + This fixes MSVS 2013 compilation. + Continuation of MSVS fixes + Fast recovery when host is in unreachable network + Fix compilation error with --disable-crypto + Send push reply right after async auth complete + Fix compilation with --disable-server + Refine float logging + Generate openvpn-plugin.h for MSVC build + Replace variable length array with malloc + Use adapter index instead of name for windows IPv6 interface config + Notify clients about server's exit/restart + Use adapter index for add/delete_route_ipv6 + Pass adapter index to up/down scripts + Detecting and logging Windows versions + Report Windows bitness + Fix "implicit declaration" compiler warning + Drop recursively routed packets + Support for disabled peer-id + Exclude peer-id from pulled options digest + Use separate list for per-client push options + +Lukasz Kutyla (1): + Fix privilege drop if first connection attempt fails + +Matthias Andree (1): + Enable TCP_NODELAY configuration on FreeBSD. + +Max Muster (1): + Remove duplicate cipher entries from TLS translation table. + +Michael McConville (1): + Fix undefined signed shift overflow + +Michal Ludvig (1): + Support for username-only auth file. + +Mike Gilbert (2): + Add configure check for the path to systemd-ask-password + Include systemd units in the source tarball (make dist) + +Niels Ole Salscheider (1): + Fix build with libressl + +Peter Sagerson (1): + Fix configure interaction with static OpenSSL libraries + +Philipp Hagemeister (2): + Add topology in sample server configuration file + Implement on-link route adding for iproute2 + +Phillip Smith (1): + Use bob.example.com and alice.example.com to improve clarity of documentation + +Robert Fischer (1): + Updated manpage for --rport and --lport + +Samuel Thibault (1): + Ensure that client-connect files are always deleted + +Samuli Sepp�nen (15): + Removed ChangeLog.IPv6 + Added cross-compilation information INSTALL-win32.txt + Updated README + Cleaned up and updated INSTALL + Fix to --shaper documentation on the man-page + Properly escape dashes on the man-page + Improve documentation in --script-security section of the man-page + Add CONTRIBUTING.rst + Update CONTRIBUTING.rst to allow GitHub PRs for code review purposes + Clarify the fact that build instructions in README are for release tarballs + Mention tap-windows6 in INSTALL file + Use an up-to-date easy-rsa URL on the man-page + Clarify which Windows versions require which TUN/TAP driver + Deprecate the automatic part of openvpnserv.exe in favor of openvpnserv2.exe + Automatically cache expected IPs for t_client.sh on the first run + +Selva Nair (26): + Fix termination when windows suspends/sleeps + Do not hard-code windows systemroot in env_block + Handle ctrl-C and ctrl-break events on Windows + Unbreak read username password from management + Restrict options/configs for startup through interactive service + Send stdout and stderr of OpenVPN started by interactive service to NUL + Handle localized Administrators group name in windows + Fix interactive service ignoring stop command if openvpn is running + Use appropriate buffer size for WideCharToMultiByte output in interactive.c + Refactor and move the block-outside-dns code to a new file (block_dns.[ch]) + Add support for block-outside-dns through the interactive service + Ensure input read using systemd-ask-password is null terminated + Support reading the challenge-response from console + Make error non-fatal while deleting address using netsh + Add support for register-dns through interactive service + Fix handling of out of memory error in interactive service + Fix the comparison of pull options hash on restart + Set WFP engine handle to NULL in win_wfp_uninit() + Make block-outside-dns work with persist-tun + Add an option to filter options received from server + Ignore SIGUSR1/SIGHUP during exit notification + Fix management-external-cert option parsing error + Return process id of openvpn from interactive service to client + Exponentially back off on repeated connect retries + Promptly close the netcmd_semaphore handle after use + Avoid format specifier %zu for Windows compatibility + +Steffan Karger (180): + PolarSSL-1.2 support + Improve PolarSSL key_state_read_{cipher, plain}text messages + Improve verify_callback messages + Config compatibility patch. Added translate_cipher_name. + Switch to IANA names for TLS ciphers. + Fixed autoconf script to properly detect missing pkcs11 with polarssl. + Use constant time memcmp when comparing HMACs in openvpn_decrypt. + Fixed tls-cipher translation bug in openssl-build + Fixed usage of stale define USE_SSL to ENABLE_SSL + Do not pass struct tls_session* as void* in key_state_ssl_init(). + Require polarssl >= 1.2.10 for polarssl-builds, which fixes CVE-2013-5915. + Also update TLSv1_method() calls in support code to SSLv23_method() calls. + Update TLSv1 error messages to SSLv23 to reflect changes from commit 4b67f98 + If --tls-cipher is supplied, make --show-tls parse the list. + Remove OpenSSL tmp_rsa_callback. Removes support for ephemeral RSA in TLS. + Make tls_ctx_restrict_ciphers accept NULL as char *cipher_list. + Disable export ciphers by default for OpenSSL builds. + Fix compiler warning for unused result of write() + Remove unused variables from ssl_verify_polarssl.c's x509_get_serial() + Fix compiler warnings in ssl_polarssl.c + Bump minimum OpenSSL version to 0.9.8 + Add openssl-specific common cipher list names to ssl.c. + Disable unsupported TLS cipher modes by default, cleans --show-tls output. + configure.ac: check for SSL_OP_NO_TICKET flag in OpenSSL + configure.ac: use CPPFLAGS for SSL_OP_NO_TICKET check + Upgrade to PolarSSL 1.3 + Improve error reporting during key/cert loading with PolarSSL. + Update openvpn-plugin.h for PolarSSL 1.3. + Add support for elliptic curve diffie-hellmann key exchange (ECDH) + Add an elliptic curve testing cert chain to the sample keys + Change signedness of hash in x509_get_sha1_hash(), fixes compiler warning. + Fix OCSP_check.sh to also use decimal for stdout verification. + Make serial env exporting consistent amongst OpenSSL and PolarSSL builds. + Fix build system to accept non-system crypto library locations for plugins. + Remove function without effect (cipher_ok() always returned true). + Remove unneeded wrapper functions in crypto_openssl.c + Remove unneeded defines (were needed for pre-0.9.7 OpenSSL). + Fix merge error in a6c573d, the ssl ctx is now abstracted. + Use generic openvpn_x509_cert_t in ssl_verify_polarssl.c + Fix ssl.c, ssl_verify_* includes + Move #include "ssl_verify.h" from ssl.h to the source files that need it. + Remove dependency on manage.h from ssl_verify.h + Remove unused variable 'proxy' from socket_restart_pause() + Add (default disabled) --enable-werror option to configure + Fix --disable-ssl builds, were broken by cleanup in 63dc03d. + configure.ac: fix SSL_OP_NO_TICKET check + Fix bug that incorrectly refuses oid representation eku's in polar builds + Update README.polarssl + cleanup: remove #if 0'ed function initiate_untrusted_session() from ssl.c. + Rename ALLOW_NON_CBC_CIPHERS to ENABLE_OFB_CFB_MODE, and add to configure. + Add proper check for crypto modes (CBC or OFB/CFB) + Improve --show-ciphers to show if a cipher can be used in static key mode + Extend t_lpback tests to test all ciphers reported by --show-ciphers + Don't issue warning for 'translate to self' tls-ciphers + Don't exit daemon if opening or parsing the CRL fails. + Define dummy SSL_OP_NO_TICKET flag if not present in OpenSSL. + Fix typo in cipher_kt_mode_{cbc, ofb_cfb}() doxygen. + Fix some unintialized variable warnings + Fix clang warning in options.c + Fix compiler warnings in ssl_polarssl.c. + Fix regression with password protected private keys (polarssl) + Remove unused variables from ssl_verify_openssl.c extract_x509_extension() + Fix assertion error when using --cipher none + Add --tls-version-max + Modernize sample keys and sample configs + Drop too-short control channel packets instead of asserting out. + Really fix '--cipher none' regression + Update doxygen (a bit) + Set tls-version-max to 1.1 if cryptoapicert is used + openssl: add crypto_msg(), to easily log openssl errors + openssl: add more descriptive message for 'no shared cipher' error + Remove ENABLE_SSL define (and --disable-ssl configure option) + openssl: use crypto_msg(), get rid of openssl-specific code in error.c + Add option to disable Diffie Hellman key exchange by setting '--dh none' + Account for peer-id in frame size calculation + Disable SSL compression + Use tls-auth in sample config files + Fix frame size calculation for non-CBC modes. + Get rid of old OpenSSL workarounds. + polarssl: make sure to always null-terminate the cn + Allow for CN/username of 64 characters (fixes off-by-one) + Change float log message to include common name, if available. + Remove unneeded parameter 'first_time' from possibly_become_daemon() + Remove size limit for files inlined in config + polarssl: remove code duplication in key_state_write_plaintext{, _const}() + Improve --tls-cipher and --show-tls man page description + polarssl: disable 1/n-1 record splitting + cleanup: remove md5 helper functions + Re-read auth-user-pass file on (re)connect if required + Clarify --capath option in manpage + Call daemon() before initializing crypto library + write pid file immediately after daemonizing + Increase control channel packet size for faster handshakes + Make __func__ work with Visual Studio too + fix regression: query password before becoming daemon + Fix using management interface to get passwords. + reintroduce md5_digest wrapper struct to fix gcc warnings + Fix out-of-tree builds; openvpn-plugin.h should be in AC_CONFIG_HEADERS + Fix overflow check in openvpn_decrypt() + Replace strdup() calls for string_alloc() calls + Check return value of ms_error_text() + polarssl: add easy logging for PolarSSL errors + polarssl: Improve PolarSSL logging + openssl: be less verbose about cipher translation errors + hardening: add insurance to exit on a failed ASSERT() + Fix memory leak in auth-pam plugin + openssl: remove usage of OPENSSL_malloc() from show_available_curves + polarssl: fix --client-cert-not-required + polarssl: add --verify-client-cert optional support + Fix (potential) memory leak in init_route_list() + Add macro to ensure we exit on fatal errors + polarssl: also allocate PKCS#11 certificate object on demand + polarssl: don't use deprecated functions anymore + polarssl: require >= 1.3.8 + Fix memory leak in add_option() by simplifying get_ipv6_addr + remove nonsense const specifier in nonfatal() return value + openssl: properly check return value of RAND_bytes() + Fix rand_bytes return value checking + Fix openssl builds with custom-built library: specify most-dependent first + Support duplicate x509 field values in environment + Warn user if their certificate has expired + Disable certificate notBefore/notAfter sanity check on OpenSSL < 1.0.2 + Make assert_failed() print the failed condition + cleanup: get rid of httpdigest.c type warnings + Fix regression in setups without a client certificate + polarssl: actually use polarssl debug logging + polarssl: optimize polar_ok() for non-errors + Update manpage: OpenSSL might also need /dev/urandom inside chroot + polarssl: use wrappers to access md_info_t member functions + polarssl: remove now redundant 128-bit blowfish key override + socks.c: fix check on get_user_pass() return value(s) + configure.ac: simplify crypto library configuration + configure.ac: fix polarssl autodetection + Allow NULL argument in cipher_ctx_get_cipher_kt() + Remove reuse of key_type during init of data channel auth and tls-auth + Move crypto_options into key_state and stop using context in SSL-mode. + Move key_ctx_bi into crypto_options + Move packet_id into crypto_options + Change openvpn_encrypt() to append to work buffer only + Create separate function for replay check + Add AEAD cipher support (GCM) + Add cipher name translation for OpenSSL. + Add preliminary server-side support for negotiable crypto parameters + Minor AEAD patch cleanup + Clean up get_tls_handhake_key() + Fix OCSP_check.sh + Make AEAD modes work with OpenSSL 1.0.1-1.0.1c + hardening: add safe FD_SET() wrapper openvpn_fd_set() + Only include aead encrypt/decrypt functions if AEAD modes are supported + Fix potential null-pointer dereference + Fix memory leak in argv_extract_cmd_name() + Replace MSG_TEST() macro for static inline msg_test() + fixup: change init_key_type() param name in declaration too + Further restrict default cipher list + PolarSSL x509_get_sha1_hash now returns correct SHA1 fingerprint. + Implemented x509-track for PolarSSL. + Migrate to mbed TLS 2.x + Rename files with 'polarssl' in the name to 'mbedtls' + configure.ac: link to all mbed TLS libs during library detection + mbedtls: check that private key and certificate match on start + mbedtls: improve error reporting in tls verify callback + Remove trailing newline from verify callback error messages + Don't limit max incoming message size based on c2->frame + cleanup: remove alloc_buffers argument from multi_top_init() + mbedtls: don't set debug threshold if compiled without MBEDTLS_DEBUG_C + Add client-side support for cipher negotiation + Add options to restrict cipher negotiation + Add server-side support for cipher negotiation + Allow ncp-disable and ncp-ciphers to be specified in ccd files + Fix '--cipher none --cipher' crash + Discourage using 64-bit block ciphers + Fix unittests for out-of-source builds + Fix --mssfix when using NCP + Drop gnu89/c89 support, switch to c99 + cleanup: remove code duplication in msg_test() + Add SHA256 fingerprint support + Make sure options->ciphername and options->authname are always defined + Update cipher-related man page text + Fix duplicate PUSH_REPLY options + Check --ncp-ciphers list on startup + +TDivine (1): + Fix "code=995" bug with windows NDIS6 tap driver. + +Tamas TEVESZ (1): + Add support for client-cert-not-required for PolarSSL. + +Thomas Veerman (2): + Fix "." in description of utun. + Update expiry date in management event loop + +ValdikSS (4): + Add Windows DNS Leak fix using WFP ('block-outside-dns') + Clarify mssfix documentation + Clarify --block-outside-dns documentation + Update --block-outside-dns to work on Windows Vista + +Vasily Kulikov (1): + Mac OS X Keychain management client + +Yawning Angel (1): + Fix SOCKSv5 method selection + +Yegor Yefremov (3): + socket: remove duplicate expression + polarssl: fix unreachable code + cert_data: fix memory leak + +janjust (1): + Fix "White space before end tags can break the config parser" + +kangsterizer (1): + Fix typo in sample build script to use LDFLAGS + +svimik (1): + Fix segfault when enabling pf plug-ins + 2012.09.12 -- Version 2.3_beta1 Arne Schwabe (7): diff --git a/version.m4 b/version.m4 index 1157be44295..6124cbfb4ee 100644 --- a/version.m4 +++ b/version.m4 @@ -2,13 +2,13 @@ dnl define the OpenVPN version define([PRODUCT_NAME], [OpenVPN]) define([PRODUCT_TARNAME], [openvpn]) define([PRODUCT_VERSION_MAJOR], [2]) -define([PRODUCT_VERSION_MINOR], [3]) -define([PRODUCT_VERSION_PATCH], [_git]) +define([PRODUCT_VERSION_MINOR], [4]) +define([PRODUCT_VERSION_PATCH], [_alpha1]) m4_append([PRODUCT_VERSION], [PRODUCT_VERSION_MAJOR]) m4_append([PRODUCT_VERSION], [PRODUCT_VERSION_MINOR], [[.]]) m4_append([PRODUCT_VERSION], [PRODUCT_VERSION_PATCH], [[]]) define([PRODUCT_BUGREPORT], [openvpn-users@lists.sourceforge.net]) -define([PRODUCT_VERSION_RESOURCE], [2,3,0,0]) +define([PRODUCT_VERSION_RESOURCE], [2,4,0,0]) dnl define the TAP version define([PRODUCT_TAP_WIN_COMPONENT_ID], [tap0901]) define([PRODUCT_TAP_WIN_MIN_MAJOR], [9]) From a47d34920a4e6e522592ba7bd0e6ff755aab8c5b Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Tue, 18 Oct 2016 13:46:04 +0200 Subject: [PATCH 336/643] Update .mailmap to unify and clean up odd names and e-mail addresses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To make the best use of this, have a look at the --use-mailmap option. In particular git-log and git-shortlog makes use of it. Also search for mailmap in the git-log man page, for more ways to use this remapping (format strings to --pretty). Otherwise, to make use of the mailmap remapping by default do: $ git config [--global] log.mailmap true --- .mailmap | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/.mailmap b/.mailmap index 91ff5537c2d..67739672ef1 100644 --- a/.mailmap +++ b/.mailmap @@ -1 +1,13 @@ -James Yonan james +Adriaan de Jong +David Sommerseth +Gert Doering +Gert Doering +Gert Doering +Gert Doering +James Yonan +Jan Just Keijser +JuanJo Ciarlante +Karl O. Pinc +Robert Fischer +Samuli Seppänen +Seth Mos From 83fdae3e9c482a3d3ceca484d96e1241359a0450 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Wed, 19 Oct 2016 21:24:20 +0200 Subject: [PATCH 337/643] Fix use-after-free bug in prepare_push_reply() This was introduced by commit dfd3513e, which changes the push_cipher memory allocation from the options gc to a temporary gc. For the ciphername in the options structure, which has to be available longer, change this back to using the options gc. Apologies for not spotting this during patch review. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1476905060-29896-1-git-send-email-steffan@karger.me> URL: http://www.mail-archive.com/search?l=mid&q=1476905060-29896-1-git-send-email-steffan@karger.me Signed-off-by: Gert Doering --- src/openvpn/push.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openvpn/push.c b/src/openvpn/push.c index ee2eda47948..a3de2a2a7c5 100644 --- a/src/openvpn/push.c +++ b/src/openvpn/push.c @@ -366,7 +366,7 @@ prepare_push_reply (struct context *c, struct gc_arena *gc, { /* Push the first cipher from --ncp-ciphers to the client. * TODO: actual negotiation, instead of server dictatorship. */ - char *push_cipher = string_alloc(o->ncp_ciphers, gc); + char *push_cipher = string_alloc(o->ncp_ciphers, &o->gc); o->ciphername = strtok (push_cipher, ":"); push_option_fmt(gc, push_list, M_USAGE, "cipher %s", o->ciphername); } From d600b2c8817c01c96408e765bc6d63fd362d5bd4 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Wed, 19 Oct 2016 22:53:02 +0200 Subject: [PATCH 338/643] Preparing for release v2.4_alpha2 (ChangeLog, version.m4) Signed-off-by: Gert Doering --- ChangeLog | 9 +++++++++ version.m4 | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 23ee03f6bec..cf76d7d677c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,15 @@ OpenVPN Change Log Copyright (C) 2002-2016 OpenVPN Technologies, Inc. +2016.10.19 -- Version 2.4_alpha2 + +David Sommerseth (1): + Update .mailmap to unify and clean up odd names and e-mail addresses + +Steffan Karger (1): + Fix use-after-free bug in prepare_push_reply() + + 2016.10.17 -- Version 2.4_alpha1 Adriaan de Jong (2): diff --git a/version.m4 b/version.m4 index 6124cbfb4ee..dccd58f4446 100644 --- a/version.m4 +++ b/version.m4 @@ -3,7 +3,7 @@ define([PRODUCT_NAME], [OpenVPN]) define([PRODUCT_TARNAME], [openvpn]) define([PRODUCT_VERSION_MAJOR], [2]) define([PRODUCT_VERSION_MINOR], [4]) -define([PRODUCT_VERSION_PATCH], [_alpha1]) +define([PRODUCT_VERSION_PATCH], [_alpha2]) m4_append([PRODUCT_VERSION], [PRODUCT_VERSION_MAJOR]) m4_append([PRODUCT_VERSION], [PRODUCT_VERSION_MINOR], [[.]]) m4_append([PRODUCT_VERSION], [PRODUCT_VERSION_PATCH], [[]]) From f3145272584ac60e061ade0325bb72bada674957 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Wed, 19 Oct 2016 21:03:27 +0200 Subject: [PATCH 339/643] Remove verbose msg() from send_push_reply() Probably committed by lev by accident, and then overlooked by me during review. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1476903807-28763-1-git-send-email-steffan@karger.me> URL: http://www.mail-archive.com/search?l=mid&q=1476903807-28763-1-git-send-email-steffan@karger.me Signed-off-by: Gert Doering --- src/openvpn/push.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/openvpn/push.c b/src/openvpn/push.c index a3de2a2a7c5..4f24b581d3d 100644 --- a/src/openvpn/push.c +++ b/src/openvpn/push.c @@ -421,8 +421,6 @@ send_push_reply (struct context *c, struct push_list *per_client_push_list) const int safe_cap = BCAP (&buf) - extra; bool push_sent = false; - msg( M_INFO, "send_push_reply(): safe_cap=%d", safe_cap ); - buf_printf (&buf, "%s", push_reply_cmd); /* send options which are common to all clients */ From c5da6dbf3f532bcae5f8c20e3dcf0311b8718d5c Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Thu, 27 Oct 2016 16:37:39 +0200 Subject: [PATCH 340/643] cleanup: Remove NOP code sections in ssl.c:tls_process() In tls_process() there is an if (true) {} block, which is completely unneeded. Even though compilers will optimize this away, it clutters the code. Also removed two #if 0 blocks within the same scope which is truly only used for really low-level debugging. The last of these blocks even includes some #ifdef nesting, making the code somewhat more unstructured. It is hard to see any argument why to presever these blocks s the information they provide won't normally be that useful. It is aimed at very special corner case debugging. This patch seems bigger than it really is, due to the needed re-indenting when removing the if(true) scope. Signed-off-by: David Sommerseth Acked-by: Steffan Karger Message-Id: <1477579059-9596-1-git-send-email-davids@openvpn.net> URL: http://www.mail-archive.com/search?l=mid&q=1477579059-9596-1-git-send-email-davids@openvpn.net --- src/openvpn/ssl.c | 439 ++++++++++++++++++++++------------------------ 1 file changed, 208 insertions(+), 231 deletions(-) diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index c7cf78df968..6703fa2da88 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -2412,271 +2412,265 @@ tls_process (struct tls_multi *multi, * CHANGED with 2.0 -> now we may send tunnel configuration * info over the control channel. */ - if (true) + + /* Initial handshake */ + if (ks->state == S_INITIAL) { - /* Initial handshake */ - if (ks->state == S_INITIAL) + buf = reliable_get_buf_output_sequenced (ks->send_reliable); + if (buf) { - buf = reliable_get_buf_output_sequenced (ks->send_reliable); - if (buf) - { - ks->must_negotiate = now + session->opt->handshake_window; - ks->auth_deferred_expire = now + auth_deferred_expire_window (session->opt); + ks->must_negotiate = now + session->opt->handshake_window; + ks->auth_deferred_expire = now + auth_deferred_expire_window (session->opt); - /* null buffer */ - reliable_mark_active_outgoing (ks->send_reliable, buf, ks->initial_opcode); - INCR_GENERATED; + /* null buffer */ + reliable_mark_active_outgoing (ks->send_reliable, buf, ks->initial_opcode); + INCR_GENERATED; - ks->state = S_PRE_START; - state_change = true; - dmsg (D_TLS_DEBUG, "TLS: Initial Handshake, sid=%s", - session_id_print (&session->session_id, &gc)); + ks->state = S_PRE_START; + state_change = true; + dmsg (D_TLS_DEBUG, "TLS: Initial Handshake, sid=%s", + session_id_print (&session->session_id, &gc)); #ifdef ENABLE_MANAGEMENT - if (management && ks->initial_opcode != P_CONTROL_SOFT_RESET_V1) - { - management_set_state (management, - OPENVPN_STATE_WAIT, - NULL, - NULL, - NULL, - NULL, - NULL); - } -#endif + if (management && ks->initial_opcode != P_CONTROL_SOFT_RESET_V1) + { + management_set_state (management, + OPENVPN_STATE_WAIT, + NULL, + NULL, + NULL, + NULL, + NULL); } +#endif } + } - /* Are we timed out on receive? */ - if (now >= ks->must_negotiate) + /* Are we timed out on receive? */ + if (now >= ks->must_negotiate) + { + if (ks->state < S_ACTIVE) { - if (ks->state < S_ACTIVE) - { - msg (D_TLS_ERRORS, - "TLS Error: TLS key negotiation failed to occur within %d seconds (check your network connectivity)", - session->opt->handshake_window); - goto error; - } - else /* assume that ks->state == S_ACTIVE */ - { - dmsg (D_TLS_DEBUG_MED, "STATE S_NORMAL_OP"); - ks->state = S_NORMAL_OP; - ks->must_negotiate = 0; - } + msg (D_TLS_ERRORS, + "TLS Error: TLS key negotiation failed to occur within %d seconds (check your network connectivity)", + session->opt->handshake_window); + goto error; } - - /* Wait for Initial Handshake ACK */ - if (ks->state == S_PRE_START && FULL_SYNC) + else /* assume that ks->state == S_ACTIVE */ { - ks->state = S_START; - state_change = true; - dmsg (D_TLS_DEBUG_MED, "STATE S_START"); + dmsg (D_TLS_DEBUG_MED, "STATE S_NORMAL_OP"); + ks->state = S_NORMAL_OP; + ks->must_negotiate = 0; } + } + + /* Wait for Initial Handshake ACK */ + if (ks->state == S_PRE_START && FULL_SYNC) + { + ks->state = S_START; + state_change = true; + dmsg (D_TLS_DEBUG_MED, "STATE S_START"); + } - /* Wait for ACK */ - if (((ks->state == S_GOT_KEY && !session->opt->server) || - (ks->state == S_SENT_KEY && session->opt->server))) + /* Wait for ACK */ + if (((ks->state == S_GOT_KEY && !session->opt->server) || + (ks->state == S_SENT_KEY && session->opt->server))) + { + if (FULL_SYNC) { - if (FULL_SYNC) - { - ks->established = now; - dmsg (D_TLS_DEBUG_MED, "STATE S_ACTIVE"); - if (check_debug_level (D_HANDSHAKE)) - print_details (&ks->ks_ssl, "Control Channel:"); - state_change = true; - ks->state = S_ACTIVE; - INCR_SUCCESS; + ks->established = now; + dmsg (D_TLS_DEBUG_MED, "STATE S_ACTIVE"); + if (check_debug_level (D_HANDSHAKE)) + print_details (&ks->ks_ssl, "Control Channel:"); + state_change = true; + ks->state = S_ACTIVE; + INCR_SUCCESS; - /* Set outgoing address for data channel packets */ - link_socket_set_outgoing_addr (NULL, to_link_socket_info, &ks->remote_addr, session->common_name, session->opt->es); + /* Set outgoing address for data channel packets */ + link_socket_set_outgoing_addr (NULL, to_link_socket_info, &ks->remote_addr, session->common_name, session->opt->es); - /* Flush any payload packets that were buffered before our state transitioned to S_ACTIVE */ - flush_payload_buffer (ks); + /* Flush any payload packets that were buffered before our state transitioned to S_ACTIVE */ + flush_payload_buffer (ks); #ifdef MEASURE_TLS_HANDSHAKE_STATS - show_tls_performance_stats(); + show_tls_performance_stats(); #endif - } } + } - /* Reliable buffer to outgoing TCP/UDP (send up to CONTROL_SEND_ACK_MAX ACKs - for previously received packets) */ - if (!to_link->len && reliable_can_send (ks->send_reliable)) - { - int opcode; - struct buffer b; - - buf = reliable_send (ks->send_reliable, &opcode); - ASSERT (buf); - b = *buf; - INCR_SENT; - - write_control_auth (session, ks, &b, to_link_addr, opcode, - CONTROL_SEND_ACK_MAX, true); - *to_link = b; - active = true; - state_change = true; - dmsg (D_TLS_DEBUG, "Reliable -> TCP/UDP"); - break; - } + /* Reliable buffer to outgoing TCP/UDP (send up to CONTROL_SEND_ACK_MAX ACKs + for previously received packets) */ + if (!to_link->len && reliable_can_send (ks->send_reliable)) + { + int opcode; + struct buffer b; + + buf = reliable_send (ks->send_reliable, &opcode); + ASSERT (buf); + b = *buf; + INCR_SENT; + + write_control_auth (session, ks, &b, to_link_addr, opcode, + CONTROL_SEND_ACK_MAX, true); + *to_link = b; + active = true; + state_change = true; + dmsg (D_TLS_DEBUG, "Reliable -> TCP/UDP"); + break; + } #ifndef TLS_AGGREGATE_ACK - /* Send 1 or more ACKs (each received control packet gets one ACK) */ - if (!to_link->len && !reliable_ack_empty (ks->rec_ack)) - { - buf = &ks->ack_write_buf; - ASSERT (buf_init (buf, FRAME_HEADROOM (&multi->opt.frame))); - write_control_auth (session, ks, buf, to_link_addr, P_ACK_V1, - RELIABLE_ACK_SIZE, false); - *to_link = *buf; - active = true; - state_change = true; - dmsg (D_TLS_DEBUG, "Dedicated ACK -> TCP/UDP"); - break; - } + /* Send 1 or more ACKs (each received control packet gets one ACK) */ + if (!to_link->len && !reliable_ack_empty (ks->rec_ack)) + { + buf = &ks->ack_write_buf; + ASSERT (buf_init (buf, FRAME_HEADROOM (&multi->opt.frame))); + write_control_auth (session, ks, buf, to_link_addr, P_ACK_V1, + RELIABLE_ACK_SIZE, false); + *to_link = *buf; + active = true; + state_change = true; + dmsg (D_TLS_DEBUG, "Dedicated ACK -> TCP/UDP"); + break; + } #endif - /* Write incoming ciphertext to TLS object */ - buf = reliable_get_buf_sequenced (ks->rec_reliable); - if (buf) - { - int status = 0; - if (buf->len) - { - status = key_state_write_ciphertext (&ks->ks_ssl, buf); - if (status == -1) - { - msg (D_TLS_ERRORS, - "TLS Error: Incoming Ciphertext -> TLS object write error"); - goto error; - } - } - else - { - status = 1; - } - if (status == 1) - { - reliable_mark_deleted (ks->rec_reliable, buf, true); - state_change = true; - dmsg (D_TLS_DEBUG, "Incoming Ciphertext -> TLS"); - } - } - - /* Read incoming plaintext from TLS object */ - buf = &ks->plaintext_read_buf; - if (!buf->len) + /* Write incoming ciphertext to TLS object */ + buf = reliable_get_buf_sequenced (ks->rec_reliable); + if (buf) + { + int status = 0; + if (buf->len) { - int status; - - ASSERT (buf_init (buf, 0)); - status = key_state_read_plaintext (&ks->ks_ssl, buf, TLS_CHANNEL_BUF_SIZE); - update_time (); + status = key_state_write_ciphertext (&ks->ks_ssl, buf); if (status == -1) { - msg (D_TLS_ERRORS, "TLS Error: TLS object -> incoming plaintext read error"); + msg (D_TLS_ERRORS, + "TLS Error: Incoming Ciphertext -> TLS object write error"); goto error; } - if (status == 1) - { - state_change = true; - dmsg (D_TLS_DEBUG, "TLS -> Incoming Plaintext"); - } -#if 0 /* show null plaintext reads */ - if (!status) - msg (M_INFO, "TLS plaintext read -> NULL return"); -#endif } - - /* Send Key */ - buf = &ks->plaintext_write_buf; - if (!buf->len && ((ks->state == S_START && !session->opt->server) || - (ks->state == S_GOT_KEY && session->opt->server))) + else { - if (session->opt->key_method == 1) - { - if (!key_method_1_write (buf, session)) - goto error; - } - else if (session->opt->key_method == 2) - { - if (!key_method_2_write (buf, session)) - goto error; - } - else - { - ASSERT (0); - } + status = 1; + } + if (status == 1) + { + reliable_mark_deleted (ks->rec_reliable, buf, true); + state_change = true; + dmsg (D_TLS_DEBUG, "Incoming Ciphertext -> TLS"); + } + } + /* Read incoming plaintext from TLS object */ + buf = &ks->plaintext_read_buf; + if (!buf->len) + { + int status; + + ASSERT (buf_init (buf, 0)); + status = key_state_read_plaintext (&ks->ks_ssl, buf, TLS_CHANNEL_BUF_SIZE); + update_time (); + if (status == -1) + { + msg (D_TLS_ERRORS, "TLS Error: TLS object -> incoming plaintext read error"); + goto error; + } + if (status == 1) + { state_change = true; - dmsg (D_TLS_DEBUG_MED, "STATE S_SENT_KEY"); - ks->state = S_SENT_KEY; + dmsg (D_TLS_DEBUG, "TLS -> Incoming Plaintext"); } + } - /* Receive Key */ - buf = &ks->plaintext_read_buf; - if (buf->len - && ((ks->state == S_SENT_KEY && !session->opt->server) - || (ks->state == S_START && session->opt->server))) + /* Send Key */ + buf = &ks->plaintext_write_buf; + if (!buf->len && ((ks->state == S_START && !session->opt->server) || + (ks->state == S_GOT_KEY && session->opt->server))) + { + if (session->opt->key_method == 1) { - if (session->opt->key_method == 1) - { - if (!key_method_1_read (buf, session)) - goto error; - } - else if (session->opt->key_method == 2) - { - if (!key_method_2_read (buf, multi, session)) - goto error; - } - else - { - ASSERT (0); - } + if (!key_method_1_write (buf, session)) + goto error; + } + else if (session->opt->key_method == 2) + { + if (!key_method_2_write (buf, session)) + goto error; + } + else + { + ASSERT (0); + } + + state_change = true; + dmsg (D_TLS_DEBUG_MED, "STATE S_SENT_KEY"); + ks->state = S_SENT_KEY; + } + + /* Receive Key */ + buf = &ks->plaintext_read_buf; + if (buf->len + && ((ks->state == S_SENT_KEY && !session->opt->server) + || (ks->state == S_START && session->opt->server))) + { + if (session->opt->key_method == 1) + { + if (!key_method_1_read (buf, session)) + goto error; + } + else if (session->opt->key_method == 2) + { + if (!key_method_2_read (buf, multi, session)) + goto error; + } + else + { + ASSERT (0); + } + state_change = true; + dmsg (D_TLS_DEBUG_MED, "STATE S_GOT_KEY"); + ks->state = S_GOT_KEY; + } + + /* Write outgoing plaintext to TLS object */ + buf = &ks->plaintext_write_buf; + if (buf->len) + { + int status = key_state_write_plaintext (&ks->ks_ssl, buf); + if (status == -1) + { + msg (D_TLS_ERRORS, + "TLS ERROR: Outgoing Plaintext -> TLS object write error"); + goto error; + } + if (status == 1) + { state_change = true; - dmsg (D_TLS_DEBUG_MED, "STATE S_GOT_KEY"); - ks->state = S_GOT_KEY; + dmsg (D_TLS_DEBUG, "Outgoing Plaintext -> TLS"); } + } - /* Write outgoing plaintext to TLS object */ - buf = &ks->plaintext_write_buf; - if (buf->len) + /* Outgoing Ciphertext to reliable buffer */ + if (ks->state >= S_START) + { + buf = reliable_get_buf_output_sequenced (ks->send_reliable); + if (buf) { - int status = key_state_write_plaintext (&ks->ks_ssl, buf); + int status = key_state_read_ciphertext (&ks->ks_ssl, buf, PAYLOAD_SIZE_DYNAMIC (&multi->opt.frame)); if (status == -1) { msg (D_TLS_ERRORS, - "TLS ERROR: Outgoing Plaintext -> TLS object write error"); + "TLS Error: Ciphertext -> reliable TCP/UDP transport read error"); goto error; } if (status == 1) { + reliable_mark_active_outgoing (ks->send_reliable, buf, P_CONTROL_V1); + INCR_GENERATED; state_change = true; - dmsg (D_TLS_DEBUG, "Outgoing Plaintext -> TLS"); - } - } - - /* Outgoing Ciphertext to reliable buffer */ - if (ks->state >= S_START) - { - buf = reliable_get_buf_output_sequenced (ks->send_reliable); - if (buf) - { - int status = key_state_read_ciphertext (&ks->ks_ssl, buf, PAYLOAD_SIZE_DYNAMIC (&multi->opt.frame)); - if (status == -1) - { - msg (D_TLS_ERRORS, - "TLS Error: Ciphertext -> reliable TCP/UDP transport read error"); - goto error; - } - if (status == 1) - { - reliable_mark_active_outgoing (ks->send_reliable, buf, P_CONTROL_V1); - INCR_GENERATED; - state_change = true; - dmsg (D_TLS_DEBUG, "Outgoing Ciphertext -> Reliable"); - } + dmsg (D_TLS_DEBUG, "Outgoing Ciphertext -> Reliable"); } } } @@ -3018,23 +3012,6 @@ tls_pre_decrypt (struct tls_multi *multi, gc_free (&gc); return ret; } -#if 0 /* keys out of sync? */ - else - { - dmsg (D_TLS_ERRORS, "TLS_PRE_DECRYPT: [%d] dken=%d rkid=%d lkid=%d auth=%d def=%d match=%d", - i, - DECRYPT_KEY_ENABLED (multi, ks), - key_id, - ks->key_id, - ks->authenticated, -#ifdef ENABLE_DEF_AUTH - ks->auth_deferred, -#else - -1, -#endif - link_socket_actual_match (from, &ks->remote_addr)); - } -#endif } msg (D_TLS_ERRORS, From 04341beb1d8e0fad3425bfec5f281fe431895cd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuli=20Sepp=C3=A4nen?= Date: Tue, 25 Oct 2016 14:55:39 +0300 Subject: [PATCH 341/643] Remove INSTALL-win32.txt that is now hosted in openvpn-build MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The contents of INSTALL-win32.txt mostly just describe how to use OpenVPN-GUI, OpenVPN Windows services and openvpn-build. These are only loosely coupled with OpenVPN, and may change independently of it. Thus hosting the file in openvpn-build (which brings all of these components together) makes most sense. URL: https://github.com/OpenVPN/openvpn-build/pull/35 URL: https://github.com/OpenVPN/openvpn-build/pull/38 Signed-off-by: Samuli Seppänen Acked-by: David Sommerseth Message-Id: <1477396539-1293-1-git-send-email-samuli@openvpn.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12771.html Signed-off-by: David Sommerseth --- INSTALL-win32.txt | 77 ----------------------------------------------- 1 file changed, 77 deletions(-) delete mode 100644 INSTALL-win32.txt diff --git a/INSTALL-win32.txt b/INSTALL-win32.txt deleted file mode 100644 index 7c056858eb3..00000000000 --- a/INSTALL-win32.txt +++ /dev/null @@ -1,77 +0,0 @@ -UPGRADING FROM 2.3-ALPHA1 AND EARLIER - -OpenVPN Windows installer went through major changes in -2.3-alpha2. To avoid any unexpected behavior, it is strongly -suggested to upgrade as follows. - -First backup configuration files and certificates from your -current installation; by default they're in - - C:\Program Files\OpenVPN\config (32-bit Windows) - C:\Program Files (x86)\OpenVPN\config (64-bit Windows) - -After this, stop the openvpn-gui or the openvpn service -wrapper, if either of them is running and uninstall OpenVPN. -Finally, remove the OpenVPN install directory entirely (e.g. -using Windows Explorer as administrator). - -Finally, install the new version of OpenVPN and copy over -your configuration files and certificates, which now go to - - C:\Program Files\OpenVPN\config - -provided you did not install the 32-bit version on 64-bit -Windows. - -IMPORTANT NOTE FOR WINDOWS VISTA/7 USERS - -Note that on Windows Vista, you will need to run the OpenVPN -GUI with administrator privileges, so that it can add routes -to the routing table that are pulled from the OpenVPN server. -You can do this by right-clicking on the OpenVPN GUI -desktop icon, and selecting "Run as administrator". - -GENERAL QUICKSTART FOR WINDOWS - -The OpenVPN Client requires a configuration file -and key/certificate files. You should obtain -these and save them to OpenVPN's configuration -directory, usually C:\Program Files\OpenVPN\config. - -You can run OpenVPN as a Windows system service or by using -the client GUI. To use the OpenVPN GUI, double click on the -desktop icon or start menu icon. The OpenVPN GUI is a -system-tray applet, so an icon for the GUI will appear in -the lower-right corner of the screen. Right click on the -system tray icon, and a menu should appear showing the names -of your OpenVPN configuration files, and giving you the -option to connect. - -BUILDING OPENVPN FOR WINDOWS - -Official OpenVPN Windows releases are cross-compiled on Linux using the -openvpn-build buildsystem: - - https://community.openvpn.net/openvpn/wiki/BuildingUsingGenericBuildsystem - -First setup the build environment as shown in the above article. Then fetch the -openvpn-build repository: - - git clone https://github.com/OpenVPN/openvpn-build.git - -Review the build configuration: - - openvpn-build/generic/build.vars - openvpn-build/windows-nsis/build-complete.vars - -Build (unsigned): - - cd openvpn-build/windows-nsis - ./build-complete - -Build (signed): - - cd openvpn-build/windows-nsis - ./build-complete --sign --sign-pkcs12=\ - --sign-pkcs12-pass= \ - --sign-timestamp="" From f93b76398003769685ae1053ec978fffe17f6cd6 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Thu, 27 Oct 2016 18:49:41 +0200 Subject: [PATCH 342/643] Remove last rest of INSTALL-win32.txt references Commit 04341beb1d8e0fad3425bfec5f281fe431895cd6 removed the INSTALL-win32.txt file. But there were crucial parts left in Makefile.am which broke building OpenVPN. In addition, removed other references in INSTALL and README to the same file to be complete. Signed-off-by: David Sommerseth Acked-by: Gert Doering Message-Id: <1477586981-5047-1-git-send-email-davids@openvpn.net> URL: http://www.mail-archive.com/search?l=mid&q=1477586981-5047-1-git-send-email-davids@openvpn.net --- INSTALL | 4 ---- Makefile.am | 6 ------ README | 3 --- 3 files changed, 13 deletions(-) diff --git a/INSTALL b/INSTALL index f0965c79b2a..4c6d21f45dd 100644 --- a/INSTALL +++ b/INSTALL @@ -12,10 +12,6 @@ QUICK START: Unix: ./configure && make && make-install - Cross-compile for Windows on Unix - - See INSTALL-win32.txt - ************************************************************************* To download OpenVPN, go to: diff --git a/Makefile.am b/Makefile.am index 364785c40be..8e9581b33ec 100644 --- a/Makefile.am +++ b/Makefile.am @@ -74,12 +74,6 @@ dist_noinst_DATA = \ msvc-dev.bat \ msvc-build.bat -if WIN32 -dist_doc_DATA += INSTALL-win32.txt -else -dist_noinst_DATA += INSTALL-win32.txt -endif - dist_noinst_HEADERS = \ config-msvc.h \ config-msvc-version.h.in diff --git a/README b/README index ee7695163a6..103a75a6966 100644 --- a/README +++ b/README @@ -39,9 +39,6 @@ For a description of OpenVPN's underlying protocol, Other Files & Directories: -* INSTALL-win32.txt -- installation instructions - for Windows - * configure.ac -- script to rebuild our configure script and makefile. From 752caece99a61e516386f94823e82ddf13fcbcab Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Fri, 28 Oct 2016 13:57:01 +0200 Subject: [PATCH 343/643] Limit --reneg-bytes to 64MB when using small block ciphers Following the earlier warning about small block ciphers, now limit the --reneg-bytes value when using a cipher that susceptible to SWEET32-like attacks. The 64 MB value has been selected with the researchers who published the SWEET32 paper. Note that this will not change a user-set --reneg-bytes value, to allow a user to align a gun with his feet^w^w^w^w^w^w override this behaviour if really needed. v2: obey user-set --reneg-bytes 0 to revert to old behaviour, use more firm language in warning message, and add URL to man page. Signed-off-by: Steffan Karger Acked-by: David Sommerseth Message-Id: <1477655821-6711-1-git-send-email-steffan.karger@fox-it.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12798.html Signed-off-by: David Sommerseth --- doc/openvpn.8 | 1 + src/openvpn/crypto.c | 5 +++-- src/openvpn/options.c | 1 + src/openvpn/ssl.c | 29 ++++++++++++++++++++++++++++- 4 files changed, 33 insertions(+), 3 deletions(-) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 2e58f33df0b..0ac81847932 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -4101,6 +4101,7 @@ an abbreviation for Blowfish in Cipher Block Chaining mode. Using BF-CBC is no longer recommended, because of it's 64-bit block size. This small block size allows attacks based on collisions, as demonstrated by SWEET32. +See https://community.openvpn.net/openvpn/wiki/SWEET32 for details. To see other ciphers that are available with OpenVPN, use the .B \-\-show\-ciphers diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c index 026d9aeb2a0..6e1e46bd1c1 100644 --- a/src/openvpn/crypto.c +++ b/src/openvpn/crypto.c @@ -819,8 +819,9 @@ init_key_ctx (struct key_ctx *ctx, struct key *key, cipher_kt_iv_size(kt->cipher)); if (cipher_kt_block_size(kt->cipher) < 128/8) { - msg (M_WARN, "WARNING: this cipher's block size is less than 128 bit " - "(%d bit). Consider using a --cipher with a larger block size.", + msg (M_WARN, "WARNING: INSECURE cipher with block size less than 128" + " bit (%d bit). This allows attacks like SWEET32. Mitigate by " + "using a --cipher with a larger block size (e.g. AES-256-CBC).", cipher_kt_block_size(kt->cipher)*8); } } diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 281ef0b5e59..996c26e4476 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -852,6 +852,7 @@ init_options (struct options *o, const bool init_gc) #endif o->key_method = 2; o->tls_timeout = 2; + o->renegotiate_bytes = -1; o->renegotiate_seconds = 3600; o->handshake_window = 60; o->transition_window = 3600; diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 6703fa2da88..cbe925f2b05 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -283,6 +283,27 @@ tls_get_cipher_name_pair (const char * cipher_name, size_t len) { return NULL; } +/** + * Limit the reneg_bytes value when using a small-block (<128 bytes) cipher. + * + * @param cipher The current cipher (may be NULL). + * @param reneg_bytes Pointer to the current reneg_bytes, updated if needed. + * May *not* be NULL. + */ +static void +tls_limit_reneg_bytes (const cipher_kt_t *cipher, int *reneg_bytes) +{ + if (cipher && (cipher_kt_block_size(cipher) < 128/8)) + { + if (*reneg_bytes == -1) /* Not user-specified */ + { + msg (M_WARN, "WARNING: cipher with small block size in use, " + "reducing reneg-bytes to 64MB to mitigate SWEET32 attacks."); + *reneg_bytes = 64 * 1024 * 1024; + } + } +} + /* * Max number of bytes we will add * for data structures common to both @@ -1704,6 +1725,8 @@ tls_session_update_crypto_params(struct tls_session *session, msg (D_TLS_ERRORS, "TLS Error: server generate_key_expansion failed"); goto cleanup; } + tls_limit_reneg_bytes (session->opt->key_type.cipher, + &session->opt->renegotiate_bytes); ret = true; cleanup: CLEAR (*ks->key_src); @@ -2088,6 +2111,8 @@ key_method_2_write (struct buffer *buf, struct tls_session *session) } CLEAR (*ks->key_src); + tls_limit_reneg_bytes (session->opt->key_type.cipher, + &session->opt->renegotiate_bytes); } return true; @@ -2316,6 +2341,8 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi } CLEAR (*ks->key_src); + tls_limit_reneg_bytes (session->opt->key_type.cipher, + &session->opt->renegotiate_bytes); } gc_free (&gc); @@ -2372,7 +2399,7 @@ tls_process (struct tls_multi *multi, if (ks->state >= S_ACTIVE && ((session->opt->renegotiate_seconds && now >= ks->established + session->opt->renegotiate_seconds) - || (session->opt->renegotiate_bytes + || (session->opt->renegotiate_bytes > 0 && ks->n_bytes >= session->opt->renegotiate_bytes) || (session->opt->renegotiate_packets && ks->n_packets >= session->opt->renegotiate_packets) From a64d76e246042fde40189033b87b126627db5b6b Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Wed, 26 Oct 2016 21:29:19 +0200 Subject: [PATCH 344/643] Add a revoked cert to the sample keys Allows for easier testing of the revocation functionality. Signed-off-by: Steffan Karger Acked-by: Arne Schwabe Message-Id: <1477510159-5067-1-git-send-email-steffan@karger.me> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12784.html Signed-off-by: David Sommerseth --- sample/sample-keys/gen-sample-keys.sh | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sample/sample-keys/gen-sample-keys.sh b/sample/sample-keys/gen-sample-keys.sh index 725cfc970c1..301cff2808a 100755 --- a/sample/sample-keys/gen-sample-keys.sh +++ b/sample/sample-keys/gen-sample-keys.sh @@ -52,6 +52,14 @@ openssl pkcs12 -export -nodes -password pass:password \ -out sample-ca/client.p12 -inkey sample-ca/client.key \ -in sample-ca/client.crt -certfile sample-ca/ca.crt +# Create a client cert, revoke it, generate CRL +openssl req -new -nodes -config openssl.cnf \ + -keyout sample-ca/client-revoked.key -out sample-ca/client-revoked.csr \ + -subj "/C=KG/ST=NA/O=OpenVPN-TEST/CN=client-revoked/emailAddress=me@myhost.mydomain" +openssl ca -batch -config openssl.cnf \ + -out sample-ca/client-revoked.crt -in sample-ca/client-revoked.csr +openssl ca -config openssl.cnf -revoke sample-ca/client-revoked.crt +openssl ca -config openssl.cnf -gencrl -out sample-ca/ca.crl # Create EC server and client cert (signed by 'regular' RSA CA) openssl ecparam -out sample-ca/secp256k1.pem -name secp256k1 @@ -76,3 +84,4 @@ openssl dhparam -out dh2048.pem 2048 cp sample-ca/*.key . cp sample-ca/*.crt . cp sample-ca/*.p12 . +cp sample-ca/*.crl . From ffe508e1082000531c9dc3a60abb9b6ba448f519 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Fri, 21 Oct 2016 16:42:37 +0200 Subject: [PATCH 345/643] Make Changes.rst nicer for 2.4 release - Add `` to all options - Sort and group new features - Group changes a bit better - Fix some formatting/formulation Patch V2: - add missing quote, noticed by Samuli - add new windows services - add ECDH - add pushable compression - add Android and AIX platform support Acked-by: David Sommerseth Message-Id: <1477060957-6423-1-git-send-email-arne@rfc2549.org> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12766.html Signed-off-by: David Sommerseth --- Changes.rst | 162 +++++++++++++++++++++++++++++------------------- doc/android.txt | 2 +- 2 files changed, 99 insertions(+), 65 deletions(-) diff --git a/Changes.rst b/Changes.rst index 27dc99e8f93..0118e78f9ba 100644 --- a/Changes.rst +++ b/Changes.rst @@ -4,63 +4,97 @@ Version 2.4.0 New features ------------ +Peer ID support + Added new packet format P_DATA_V2, which includes peer-id. If + server and client support it, client sends all data packets in + the new format. When data packet arrives, server identifies peer + by peer-id. If peer's ip/port has changed, server assumes that + client has floated, verifies HMAC and updates ip/port in internal structs. -pull-filter - New option to explicitly allow or reject options pushed by the server. - May be used multiple times and is applied in the order specified. +Cipher negotiation + Data channel ciphers are now by default negotiated. If a client advertises + support for Negotiable Crypto Parameters (NCP), the server will choose a + cipher (by default AES-256-GCM) for the data channel, and tell the client + to use that cipher. Data channel cipher negotiation can be controlled + using ``--ncp-ciphers`` and ``--ncp-disable``. -push-remove - new option to remove options on a per-client basis from the "push" list - (more fine-grained than "push-reset") +AEAD (GCM) data channel cipher support + The data channel now supports AEAD ciphers (currently only GCM). The AEAD + packet format has a smaller overhead than the CBC packet format, (e.g. 20 + bytes per packet for AES-128-GCM instead of 36 bytes per packet for + AES-128-CBC + HMAC-SHA1). -keying-material-exporter - Keying Material Exporter [RFC-5705] allow additional keying material to be - derived from existing TLS channel. +ECDH key exchange + The TLS control channel now supports for elliptic curve diffie-hellmann + key exchange (ECDH). + +Dualstack client connect + Instead of only using the first address of each ``--remote`` OpenVPN + will now try all addresses (IPv6 and IPv4) of a ``--remote`` entry. + +New improved Windows Background service + The new OpenVPNService is based on openvpnserv2, a complete rewrite of the OpenVPN + service wrapper. It is intended for launching OpenVPN instances that should be + up at all times, instead of being manually launched by a user. OpenVPNService is + able to restart individual OpenVPN processes if they crash, and it also works + properly on recent Windows versions. OpenVPNServiceLegacy tends to work poorly, + if at all, on newer Windows versions (8+) and its use is not recommended. + +New interactive Windows service + The installer starts OpenVPNServiceInteractive automatically and configures + it to start at system startup. + + The interactive Windows service allows unprivileged users to start + OpenVPN connections in the global config directory (usually + C:\Program Files\OpenVPN\config) using OpenVPN GUI without any + extra configuration. + + Users who belong to the built-in Administrator group or to the + local "OpenVPN Administrator" group can also store configuration + files under %USERPROFILE%\OpenVPN\config for use with the + interactive service. redirect-gateway ipv6 OpenVPN has now feature parity between IPv4 and IPv6 for redirect gateway including the handling of overlapping IPv6 routes with IPv6 remote VPN server address -Mac OS X Keychain management client - add contrib/keychain-mcd which allows to use Mac OS X keychain - certificates with OpenVPN +LZ4 Compression and pushable compression + Additionally to LZO compression OpenVPN now also supports LZ4 compression. + Compression options are now pushable from the server. -Peer ID support - Added new packet format P_DATA_V2, which includes peer-id. If - server and client support it, client sends all data packets in - the new format. When data packet arrives, server identifies peer - by peer-id. If peer's ip/port has changed, server assumes that - client has floated, verifies HMAC and updates ip/port in internal structs. +pull-filter + New option to explicitly allow or reject options pushed by the server. + May be used multiple times and is applied in the order specified. -Dualstack client connect - Instead of only using the first address of each --remote OpenVPN - will now try all addresses (IPv6 and IPv4) of a --remote entry. +push-remove + new option to remove options on a per-client basis from the "push" list + (more fine-grained than ``--push-reset``) -LZ4 Compression - Additionally to LZO compression OpenVPN now also supports LZ4 - compression. +Http proxy password inside config file + Http proxy passwords can be specified with the inline file option + ```` .. ```` Windows version Windows version is detected, logged and possibly signalled to server - (IV_PLAT_VER= if --push-peer-info is set on client) + (IV_PLAT_VER= if ``--push-peer-info`` is set on client) -AEAD (GCM) data channel cipher support - The data channel now supports AEAD ciphers (currently only GCM). The AEAD - packet format has a smaller overhead than the CBC packet format, (e.g. 20 - bytes per packet for AES-128-GCM instead of 36 bytes per packet for - AES-128-CBC + HMAC-SHA1). +keying-material-exporter + Keying Material Exporter [RFC-5705] allow additional keying material to be + derived from existing TLS channel. -Http proxy password inside config file - Http proxy passwords can be specified with the inline file option - http-proxy-user-pass +Mac OS X Keychain management client + added contrib/keychain-mcd which allows to use Mac OS X keychain + certificates with OpenVPN -Cipher negotiation - Data channel ciphers are now by default negotiated. If a client advertises - support for Negotiable Crypto Parameters (NCP), the server will choose a - cipher (by default AES-256-GCM) for the data channel, and tell the client - to use that cipher. Data channel cipher negotiation can be controlled - using --ncp-ciphers and --ncp-disable. +Android platform support + Support for running on Android using Android's VPNService API has been added. + See doc/android.txt for more details. This support is primarily used in + the OpenVPN for Android app (https://github.com/schwabe/ics-openvpn) + +AIX platform support + AIX platform support has been added. The support only includes tap + devices since AIX does not provide tun interface. User-visible Changes @@ -75,33 +109,23 @@ User-visible Changes - proto udp and proto tcp specify to use IPv4 and IPv6. The new options proto udp4 and tcp4 specify to use IPv4 only. -- connect-timeout specifies now the timeout until the first TLS packet - is received (identical to server-poll-timeout) and this timeout now - includes the removed socks proxy timeout and http proxy timeout. - - In --static mode connect-timeout specifies the timeout for TCP and - proxy connection establishment - -- connect-retry-max now specifies the maximum number of unsuccessful - attempts of each remote/connection entry before exiting. - -- sndbuf and recvbuf default now to OS default instead of 64k +- ``--sndbuf`` and ``--recvbuf`` default now to OS defaults instead of 64k - OpenVPN exits with an error if an option has extra parameters; previously they were silently ignored -- The default of tls-cipher is now "DEFAULT:!EXP:!PSK:!SRP:!kRSA" +- The default of ``--tls-cipher`` is now "DEFAULT:!EXP:!PSK:!SRP:!kRSA" instead of "DEFAULT" to always select perfect forward security cipher suites -- --tls-auth always requires OpenVPN static key files and will no +- ``--tls-auth`` always requires OpenVPN static key files and will no longer work with free form files -- proto udp6/tcp6 in server mode will now try to always listen to - both IPv4 and IPv6 on platforms that allow it. Use bind ipv6only +- ``--proto udp6/tcp6`` in server mode will now try to always listen to + both IPv4 and IPv6 on platforms that allow it. Use ``--bind ipv6only`` to explicitly listen only on IPv6. -- Removed --enable-password-save from configure. This option is now +- Removed ``--enable-password-save`` from configure. This option is now always enabled. - Stricter default TLS cipher list (override with ``--tls-cipher``), that now @@ -117,26 +141,36 @@ User-visible Changes - mbed TLS builds: minimum RSA key size is now 2048 bits. Shorter keys will not be accepted, both local and from the peer. -- --http-proxy-timeout and the static non-changeable socks timeout (5s) - have been folded into a "unified" --connect-timeout which covers all +- ``--connect-timeout`` specifies now the timeout until the first TLS packet + is received (identical to ``--server-poll-timeout``) and this timeout now + includes the removed socks proxy timeout and http proxy timeout. + + In ``--static`` mode connect-timeout specifies the timeout for TCP and + proxy connection establishment + +- ``--connect-retry-max`` now specifies the maximum number of unsuccessful + attempts of each remote/connection entry before exiting. + +- ``--http-proxy-timeout`` and the static non-changeable socks timeout (5s) + have been folded into a "unified" ``--connect-timeout`` which covers all steps needed to connect to the server, up to the start of the TLS exchange. The default value has been raised to 120s, to handle slow http/socks proxies graciously. The old "fail TCP fast" behaviour can be achieved by - adding "--connect-timeout 10" to the client config. + adding "``--connect-timeout 10``" to the client config. -- --http-proxy-retry and --sock-proxy-retry have been removed. Proxy connections - will now behave like regular connection entries and generate a USR1 on failure. +- ``--http-proxy-retry`` and ``--sock-proxy-retry`` have been removed. Proxy connections + will now behave like regular connection entries and generate a USR1 on failure. -- --connect-retry gets an optional second argument that specifies the maximum +- ``--connect-retry`` gets an optional second argument that specifies the maximum time in seconds to wait between reconnection attempts when an exponential backoff is triggered due to repeated retries. Default = 300 seconds. - Data channel cipher negotiation (see New features section) can override - ciphers configured in the config file. Use --ncp-disable if you don't want - that. + ciphers configured in the config file. Use ``--ncp-disable`` if you do not want + this behavior. - All tun devices on all platforms are always considered to be IPv6 - capable. The --tun-ipv6 option is ignored (behaves like it is always + capable. The ``--tun-ipv6`` option is ignored (behaves like it is always on). diff --git a/doc/android.txt b/doc/android.txt index 3a096ddc32e..5f4ee95290e 100644 --- a/doc/android.txt +++ b/doc/android.txt @@ -1,7 +1,7 @@ This file documents the support in OpenVPN for Android 4.0 and up. This support is primarily used in the "OpenVPN for Android" app -(http://code.google.com/p/ics-openvpn/). For building see the developer +(https://github.com/schwabe/ics-openvpn). For building see the developer README: https://github.com/schwabe/ics-openvpn/blob/master/doc/README.txt Android provides the VPNService API From 58066d04036bf29107f67ca38c6e964ec11f9dfd Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Fri, 28 Oct 2016 21:48:40 +0200 Subject: [PATCH 346/643] auth-gen-token: Add --auth-gen-token option This sets the flag if the OpenVPN server should create authentication tokens on-the-fly on successful --auth-user-pass-verify or --plugin with OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY processing. If an OpenVPN server is running without this option, it should behave as before. Next patches will implement the auth-token generation and passing it on to the clients. The --auth-gen-token can be given an optional integer argument which defines the lifetime of generated tokens. The lifetime argument must be given in number of seconds. v2 - Update Changes.rst - Improve man page in regards to lifetime argument - Rename struct member auth_generate_token to auth_token_generate to have a consistent naming scheme Signed-off-by: David Sommerseth Acked-by: Steffan Karger Message-Id: <1477684124-26083-2-git-send-email-davids@openvpn.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12825.html --- Changes.rst | 15 +++++++++++++++ doc/openvpn.8 | 22 ++++++++++++++++++++++ src/openvpn/init.c | 2 ++ src/openvpn/options.c | 16 ++++++++++++++++ src/openvpn/options.h | 2 ++ src/openvpn/ssl_common.h | 3 +++ 6 files changed, 60 insertions(+) diff --git a/Changes.rst b/Changes.rst index 0118e78f9ba..8fd58593e1b 100644 --- a/Changes.rst +++ b/Changes.rst @@ -79,6 +79,21 @@ Windows version Windows version is detected, logged and possibly signalled to server (IV_PLAT_VER= if ``--push-peer-info`` is set on client) +Authentication tokens + In situations where it is not suitable to save users passwords on the client + OpenVPN have since v2.3 had support for --auth-token. This option is + pushed from the server to the client with a token value to be used instead + of the users password. For this to work, the authentication plug-in would + need to implement this support as well. In OpenVPN 2.4 --auth-gen-token + is introduced, which will allow the OpenVPN server to generate a random + token and push it to the client without any changes to the authentication + modules. When the clients need to re-authenticate the OpenVPN server will + instead of sending the re-authentication request to the authentication + module do the authentication internally. This feature is especially + useful in configurations which adds One Time Password (OTP) authentication + schemes, as this allows the tunnel to be renegotiated regularly without + any need to supply new OTP codes. + keying-material-exporter Keying Material Exporter [RFC-5705] allow additional keying material to be derived from existing TLS channel. diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 0ac81847932..e73517a4685 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -3583,6 +3583,28 @@ For a sample script that performs PAM authentication, see in the OpenVPN source distribution. .\"********************************************************* .TP +.B \-\-auth\-gen\-token [lifetime] +After successful user/password authentication, the OpenVPN +server will with this option generate a temporary +authentication token and push that to client. On the following +renegotiations, the OpenVPN client will pass this token instead +of the users password. On the server side the server will do +the token authentication internally and it will NOT do any +additional authentications against configured external +user/password authentication mechanisms. + +The +.B lifetime +argument defines how long the generated token is valid. The +lifetime is defined in seconds. If lifetime is not set +or it is set to 0, the token will never expire. + +This feature is useful for environments which is configured +to use One Time Passwords (OTP) as part of the user/password +authentications and that authentication mechanism does not +implement any auth-token support. +.\"********************************************************* +.TP .B \-\-opt\-verify Clients that connect with options that are incompatible with those of the server will be disconnected. diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 73f8c6d69af..3ec3b184f40 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -2421,6 +2421,8 @@ do_init_crypto_tls (struct context *c, const unsigned int flags) if (options->ccd_exclusive) to.client_config_dir_exclusive = options->client_config_dir; to.auth_user_pass_file = options->auth_user_pass_file; + to.auth_token_generate = options->auth_token_generate; + to.auth_token_lifetime = options->auth_token_lifetime; #endif to.x509_track = options->x509_track; diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 996c26e4476..f88e94d8f1f 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -444,6 +444,11 @@ static const char usage_message[] = " run command cmd to verify. If method='via-env', pass\n" " user/pass via environment, if method='via-file', pass\n" " user/pass via temporary file.\n" + "--auth-gen-token [lifetime] Generate a random authentication token which is pushed\n" + " to each client, replacing the password. Usefull when\n" + " OTP based two-factor auth mechanisms are in use and\n" + " --reneg-* options are enabled. Optionally a lifetime in seconds\n" + " for generated tokens can be set.\n" "--opt-verify : Clients that connect with options that are incompatible\n" " with those of the server will be disconnected.\n" "--auth-user-pass-optional : Allow connections by clients that don't\n" @@ -864,6 +869,7 @@ init_options (struct options *o, const bool init_gc) #ifdef ENABLE_PKCS11 o->pkcs11_pin_cache_period = -1; #endif /* ENABLE_PKCS11 */ + o->auth_token_generate = false; /* tmp is only used in P2MP server context */ #if P2MP_SERVER @@ -1264,6 +1270,8 @@ show_p2mp_parms (const struct options *o) SHOW_INT (max_routes_per_client); SHOW_STR (auth_user_pass_verify_script); SHOW_BOOL (auth_user_pass_verify_script_via_file); + SHOW_BOOL (auth_token_generate); + SHOW_INT (auth_token_lifetime); #if PORT_SHARE SHOW_STR (port_share_host); SHOW_STR (port_share_port); @@ -2186,6 +2194,8 @@ options_postprocess_verify_ce (const struct options *options, const struct conne "tcp-nodelay in the server configuration instead."); if (options->auth_user_pass_verify_script) msg (M_USAGE, "--auth-user-pass-verify requires --mode server"); + if (options->auth_token_generate) + msg (M_USAGE, "--auth-gen-token requires --mode server"); #if PORT_SHARE if (options->port_share_host || options->port_share_port) msg (M_USAGE, "--port-share requires TCP server mode (--mode server --proto tcp-server)"); @@ -5965,6 +5975,12 @@ add_option (struct options *options, &options->auth_user_pass_verify_script, p[1], "auth-user-pass-verify", true); } + else if (streq (p[0], "auth-gen-token")) + { + VERIFY_PERMISSION (OPT_P_GENERAL); + options->auth_token_generate = true; + options->auth_token_lifetime = p[1] ? positive_atoi (p[1]) : 0; + } else if (streq (p[0], "client-connect") && p[1]) { VERIFY_PERMISSION (OPT_P_SCRIPT); diff --git a/src/openvpn/options.h b/src/openvpn/options.h index b7453a033a0..2f91a521a59 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -442,6 +442,8 @@ struct options const char *auth_user_pass_verify_script; bool auth_user_pass_verify_script_via_file; + bool auth_token_generate; + unsigned int auth_token_lifetime; #if PORT_SHARE char *port_share_host; char *port_share_port; diff --git a/src/openvpn/ssl_common.h b/src/openvpn/ssl_common.h index eb2ad6f956d..50c4a9ca359 100644 --- a/src/openvpn/ssl_common.h +++ b/src/openvpn/ssl_common.h @@ -289,6 +289,9 @@ struct tls_options bool auth_user_pass_verify_script_via_file; const char *tmp_dir; const char *auth_user_pass_file; + bool auth_token_generate; /**< Generate auth-tokens on successful user/pass auth, + * set via options->auth_token_generate. */ + unsigned int auth_token_lifetime; /* use the client-config-dir as a positive authenticator */ const char *client_config_dir_exclusive; From 270dc91164013eb7ace34d7b098fa11a97aef847 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Fri, 28 Oct 2016 21:48:42 +0200 Subject: [PATCH 347/643] auth-gen-token: Generate an auth-token per client When --auth-gen-token is used a random token key is generated for each client after a successful user/password authentication. This token is expected to be returned in the password field on the following authentications. The token is 256 bits long and BASE64 encoded before it is stored. v2 - Fix Doxygen comment typo - Don't exceed 80 chars line length Signed-off-by: David Sommerseth Acked-by: Steffan Karger Message-Id: <1477684124-26083-4-git-send-email-davids@openvpn.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12820.html --- src/openvpn/ssl.c | 6 ++++++ src/openvpn/ssl_common.h | 8 ++++++++ src/openvpn/ssl_verify.c | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+) diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index cbe925f2b05..4a0cd6f3fd7 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -1194,6 +1194,12 @@ tls_multi_free (struct tls_multi *multi, bool clear) cert_hash_free (multi->locked_cert_hash_set); + if (multi->auth_token) + { + memset (multi->auth_token, 0, AUTH_TOKEN_SIZE); + free (multi->auth_token); + } + for (i = 0; i < TM_SIZE; ++i) tls_session_free (&multi->session[i], false); diff --git a/src/openvpn/ssl_common.h b/src/openvpn/ssl_common.h index 50c4a9ca359..9b63a1293eb 100644 --- a/src/openvpn/ssl_common.h +++ b/src/openvpn/ssl_common.h @@ -351,6 +351,9 @@ struct tls_options /** @} name Index of key_state objects within a tls_session structure */ /** @} addtogroup control_processor */ +#define AUTH_TOKEN_SIZE 32 /**< Size of server side generated auth tokens. + * 32 bytes == 256 bits + */ /** * Security parameter state of a single session within a VPN tunnel. @@ -525,6 +528,11 @@ struct tls_multi uint32_t peer_id; bool use_peer_id; + char *auth_token; /**< If server sends a generated auth-token, + * this is the token to use for future + * user/pass authentications in this session. + */ + time_t auth_token_tstamp; /**< timestamp of the generated token */ /* * Our session objects. */ diff --git a/src/openvpn/ssl_verify.c b/src/openvpn/ssl_verify.c index d0c22b84ece..0ac5689fbb1 100644 --- a/src/openvpn/ssl_verify.c +++ b/src/openvpn/ssl_verify.c @@ -39,6 +39,8 @@ #include "misc.h" #include "manage.h" +#include "otime.h" +#include "base64.h" #include "ssl_verify.h" #include "ssl_verify_backend.h" @@ -1174,6 +1176,43 @@ verify_user_pass(struct user_pass *up, struct tls_multi *multi, if (man_def_auth != KMDA_UNDEF) ks->auth_deferred = true; #endif + + if ((session->opt->auth_token_generate) && (NULL == multi->auth_token)) + { + /* Server is configured with --auth-gen-token but no token has yet + * been generated for this client. Generate one and save it. + */ + uint8_t tok[AUTH_TOKEN_SIZE]; + + if (!rand_bytes(tok, AUTH_TOKEN_SIZE)) + { + msg( M_FATAL, "Failed to get enough randomness for " + "authentication token"); + } + + /* The token should be longer than the input when + * being base64 encoded + */ + if( openvpn_base64_encode(tok, AUTH_TOKEN_SIZE, + &multi->auth_token) < AUTH_TOKEN_SIZE) + { + msg(D_TLS_ERRORS, "BASE64 encoding of token failed. " + "No auth-token will be activated now"); + if (multi->auth_token) + { + memset (multi->auth_token, 0, AUTH_TOKEN_SIZE); + free (multi->auth_token); + multi->auth_token = NULL; + } + } + else + { + multi->auth_token_tstamp = now; + dmsg (D_SHOW_KEYS, "Generated token for client: %s", + multi->auth_token); + } + } + if ((session->opt->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME)) set_common_name (session, up->username); #ifdef ENABLE_DEF_AUTH From 2c0403ac359097bbcb1e97b777120e218e29014f Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Fri, 28 Oct 2016 21:48:43 +0200 Subject: [PATCH 348/643] auth-gen-token: Push generated auth-tokens to the client If --auth-gen-token has been enabled and a token has been generated, ensure this token is pushed to the client using the 'auth-token' option. This patch will also remove the logging of auth-token values being pushed, unless --verb level is 7 or higher. v2 - Don't exceed 80 chars line length - Clarify the magic in sanitize_control_message() - Relocate auth_token_sent struct member slightly Signed-off-by: David Sommerseth Acked-by: Steffan Karger Message-Id: <1477684124-26083-5-git-send-email-davids@openvpn.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12824.html --- src/openvpn/misc.c | 9 +++++++++ src/openvpn/push.c | 12 +++++++++++- src/openvpn/ssl_common.h | 2 ++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/openvpn/misc.c b/src/openvpn/misc.c index 225f0bfbefb..b06d446b702 100644 --- a/src/openvpn/misc.c +++ b/src/openvpn/misc.c @@ -2073,6 +2073,15 @@ sanitize_control_message(const char *src, struct gc_arena *gc) skip = 4; redact = true; } + else if (!check_debug_level(D_SHOW_KEYS) + && (c == 'a' && !strncmp(src, "auth-token ", 11))) + { + /* Unless --verb is 7 or higher (D_SHOW_KEYS), hide + * the auth-token value coming in the src string + */ + skip = 10; + redact = true; + } if (c == ',') /* end of redacted item? */ { diff --git a/src/openvpn/push.c b/src/openvpn/push.c index 4f24b581d3d..f86bdd37613 100644 --- a/src/openvpn/push.c +++ b/src/openvpn/push.c @@ -309,7 +309,7 @@ prepare_push_reply (struct context *c, struct gc_arena *gc, struct push_list *push_list) { const char *optstr = NULL; - const struct tls_multi *tls_multi = c->c2.tls_multi; + struct tls_multi *tls_multi = c->c2.tls_multi; const char * const peer_info = tls_multi->peer_info; struct options *o = &c->options; @@ -371,6 +371,16 @@ prepare_push_reply (struct context *c, struct gc_arena *gc, push_option_fmt(gc, push_list, M_USAGE, "cipher %s", o->ciphername); } } + + /* If server uses --auth-gen-token and we have an auth token + * to send to the client + */ + if (false == tls_multi->auth_token_sent && NULL != tls_multi->auth_token) + { + push_option_fmt(gc, push_list, M_USAGE, + "auth-token %s", tls_multi->auth_token); + tls_multi->auth_token_sent = true; + } return true; } diff --git a/src/openvpn/ssl_common.h b/src/openvpn/ssl_common.h index 9b63a1293eb..b04a24c3dc1 100644 --- a/src/openvpn/ssl_common.h +++ b/src/openvpn/ssl_common.h @@ -533,6 +533,8 @@ struct tls_multi * user/pass authentications in this session. */ time_t auth_token_tstamp; /**< timestamp of the generated token */ + bool auth_token_sent; /**< If server uses --auth-gen-token and + * token has been sent to client */ /* * Our session objects. */ From 703c9784f4dcd4f77166201074c21c6ea4aeb033 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Fri, 28 Oct 2016 21:48:44 +0200 Subject: [PATCH 349/643] auth-gen-token: Authenticate generated auth-tokens when client re-authenticates On a server with --auth-gen-token enabled, the server will have created a random token and pushed it to the client. When the client needs to renegotiate the connection or otherwise reconnect, it will at this point use the auth-token as password. Here we check if we have a token generated and that it has been pushed to the client, if so, then we check if the token matches the locally stored token. If everything matches, we're done and the connection is still authenticated. If the auth-token authentication fails, we delete our local copy of the token and changes the connection to not being authenticated. From this moment of, the client needs to do a full reconnect providing the users password again. This token authentication also considers the token lifetime, if that have been set via --auth-gen-token. If the token have expired, the client is rejected and needs to do a full reconnect with a new authentication using the users password. v2 - Rename auth_generate_token to auth_token_generate - Wrap lines exceeding 80 chars - Improved several comments (rephrasing, grammar) Signed-off-by: David Sommerseth Acked-by: Steffan Karger Message-Id: <1477684124-26083-6-git-send-email-davids@openvpn.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12822.html --- src/openvpn/ssl_verify.c | 58 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/src/openvpn/ssl_verify.c b/src/openvpn/ssl_verify.c index 0ac5689fbb1..99a2f70ec9d 100644 --- a/src/openvpn/ssl_verify.c +++ b/src/openvpn/ssl_verify.c @@ -1139,6 +1139,63 @@ verify_user_pass(struct user_pass *up, struct tls_multi *multi, string_mod_remap_name (up->username, COMMON_NAME_CHAR_CLASS); string_mod (up->password, CC_PRINT, CC_CRLF, '_'); + /* If server is configured with --auth-gen-token and we have an + * authentication token for this client, this authentication + * round will be done internally using the token instead of + * calling any external authentication modules. + */ + if (session->opt->auth_token_generate && multi->auth_token_sent + && NULL != multi->auth_token) + { + unsigned int ssl_flags = session->opt->ssl_flags; + + /* Ensure that the username has not changed */ + if (!tls_lock_username(multi, up->username)) + { + ks->authenticated = false; + goto done; + } + + /* If auth-token lifetime has been enabled, + * ensure the token has not expired + */ + if (session->opt->auth_token_lifetime > 0 + && (multi->auth_token_tstamp + session->opt->auth_token_lifetime) < now) + { + msg (D_HANDSHAKE, "Auth-token for client expired\n"); + ks->authenticated = false; + goto done; + } + + /* The core authentication of the token itself */ + if (memcmp_constant_time(multi->auth_token, up->password, + strlen(multi->auth_token)) != 0) + { + memset (multi->auth_token, 0, AUTH_TOKEN_SIZE); + free (multi->auth_token); + multi->auth_token = NULL; + multi->auth_token_sent = false; + ks->authenticated = false; + tls_deauthenticate (multi); + + msg (D_TLS_ERRORS, "TLS Auth Error: Auth-token verification " + "failed for username '%s' %s", up->username, + (ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) ? "[CN SET]" : ""); + } + else + { + ks->authenticated = true; + + if (ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) + set_common_name (session, up->username); + msg (D_HANDSHAKE, "TLS: Username/auth-token authentication " + "succeeded for username '%s' %s", + up->username, + (ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) ? "[CN SET]" : ""); + } + goto done; + } + /* call plugin(s) and/or script */ #ifdef MANAGEMENT_DEF_AUTH if (man_def_auth == KMDA_DEF) @@ -1232,6 +1289,7 @@ verify_user_pass(struct user_pass *up, struct tls_multi *multi, msg (D_TLS_ERRORS, "TLS Auth Error: Auth Username/Password verification failed for peer"); } + done: gc_free (&gc); } From 51d4d1543a64158cc24f176a8d45e51cbda8cd91 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Tue, 1 Nov 2016 00:07:09 +0100 Subject: [PATCH 350/643] Fix builds with --disable-crypto When building with --disable-crypto the P2MP_SERVER is not defined, thus breaking one place where the struct options auth_token_generate was provided with a default value. Also remove a lot of compiler warnings from ssl_backend.h due to various undefined structs when doing the same build type. Signed-off-by: David Sommerseth Acked-by: Gert Doering Message-Id: <1477955229-20164-1-git-send-email-davids@openvpn.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12857.html Signed-off-by: Gert Doering --- src/openvpn/options.c | 5 +++-- src/openvpn/ssl_backend.h | 3 +++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/openvpn/options.c b/src/openvpn/options.c index f88e94d8f1f..be31ed3792c 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -869,10 +869,11 @@ init_options (struct options *o, const bool init_gc) #ifdef ENABLE_PKCS11 o->pkcs11_pin_cache_period = -1; #endif /* ENABLE_PKCS11 */ - o->auth_token_generate = false; -/* tmp is only used in P2MP server context */ +/* P2MP server context features */ #if P2MP_SERVER + o->auth_token_generate = false; + /* Set default --tmp-dir */ #ifdef WIN32 /* On Windows, find temp dir via enviroment variables */ diff --git a/src/openvpn/ssl_backend.h b/src/openvpn/ssl_backend.h index 542c373d6f4..a61f03a7cba 100644 --- a/src/openvpn/ssl_backend.h +++ b/src/openvpn/ssl_backend.h @@ -124,6 +124,8 @@ int tls_version_parse(const char *vstr, const char *extra); */ int tls_version_max(void); +#ifdef ENABLE_CRYPTO + /** * Initialise a library-specific TLS context for a server. * @@ -510,4 +512,5 @@ void get_highest_preference_tls_cipher (char *buf, int size); */ const char * get_ssl_library_version(void); +#endif /* ENABLE_CRYPTO */ #endif /* SSL_BACKEND_H_ */ From beaa6564a7ce3e48473a8bde7b4f9291df490d62 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Tue, 1 Nov 2016 14:38:09 +0100 Subject: [PATCH 351/643] man: Improve the --keepalive section Just minor clarifications and corrections of the --keepalive option. v2 - Changed from ps/pto to interval/timeout - Rephrased the server-side timeout doubling parapgraph Signed-off-by: David Sommerseth Acked-by: Gert Doering Message-Id: <1478007489-17163-1-git-send-email-davids@openvpn.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12866.html Signed-off-by: Gert Doering --- doc/openvpn.8 | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index e73517a4685..3a4ab21707d 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -1614,16 +1614,25 @@ and are mutually exclusive and cannot be used together. .\"********************************************************* .TP -.B \-\-keepalive n m +.B \-\-keepalive interval timeout A helper directive designed to simplify the expression of .B \-\-ping and +.B \-\-ping\-restart. + +This option can be used on both client and server side, but it is +in enough to add this on the server side as it will push appropriate +.B \-\-ping +and .B \-\-ping\-restart -in server mode configurations. +options to the client. If used on both server and client, +the values pushed from server will override the client local values. -The server timeout is set twice the value of the second argument. -This ensures that a timeout is detected on client side -before the server side drops the connection. +The +.B timeout +argument will be twice as long on the server side. This ensures that +a timeout is detected on client side before the server side drops +the connection. For example, .B \-\-keepalive 10 60 @@ -1633,13 +1642,13 @@ expands as follows: .ft 3 .in +4 if mode server: - ping 10 - ping\-restart 120 - push "ping 10" - push "ping\-restart 60" + ping 10 # Argument: interval + ping\-restart 120 # Argument: timeout*2 + push "ping 10" # Argument: interval + push "ping\-restart 60" # Argument: timeout else - ping 10 - ping\-restart 60 + ping 10 # Argument: interval + ping\-restart 60 # Argument: timeout .in -4 .ft .fi From e8c42658ff8df10ad56659788a73900648b9d92d Mon Sep 17 00:00:00 2001 From: Lev Stipakov Date: Thu, 3 Nov 2016 23:28:23 +0200 Subject: [PATCH 352/643] Drop recursively routed packets v4: - Account for IP header offset in TAP mode - Correct handle of non-IP protocols in TAP mode v3: Use better way of figuring out IP proto version which does not break TAP mode. Add an option to allow recursive routing, could be useful when packets sent by openvpn itself are not subject to the routing tables that would move packets into the tunnel. v2: better method naming On certain OSes (Windows, OS X) when network adapter is disabled (ethernet cable pulled off, Wi-Fi hardware switch disabled), operating system starts to use tun as an external interface. Outgoing packets are routed to tun, UDP encapsulated, given to routing table and sent to.. tun. As a consequence, system starts talking to itself on full power, traffic counters skyrocket and user is not happy. To prevent that, drop packets which have gateway IP as destination address. Tested on Win7/10, OS X, Linux. Trac #642 Acked-by: Gert Doering Message-Id: <1478208503-25929-1-git-send-email-lstipakov@gmail.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12894.html Signed-off-by: Gert Doering --- Changes.rst | 3 ++ doc/openvpn.8 | 4 +++ src/openvpn/forward.c | 72 +++++++++++++++++++++++++++++++++++++++++++ src/openvpn/options.c | 10 ++++++ src/openvpn/options.h | 4 +++ src/openvpn/proto.h | 39 +++++++++++++++++++++++ 6 files changed, 132 insertions(+) diff --git a/Changes.rst b/Changes.rst index 8fd58593e1b..c0f14a18a3c 100644 --- a/Changes.rst +++ b/Changes.rst @@ -188,6 +188,9 @@ User-visible Changes capable. The ``--tun-ipv6`` option is ignored (behaves like it is always on). +- On the client side recursively routed packets, which have same destination + as the VPN server, are dropped. This could be disabled with + --allow-recursive-routing option. Maintainer-visible changes -------------------------- diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 3a4ab21707d..863dcf94009 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -4004,6 +4004,10 @@ to the same server, with OpenVPN will not send any exit notifications unless this option is enabled. +.TP +.B \-\-allow\-recursive\-routing +When this option is set, OpenVPN will not drop incoming tun packets +with same destination as host. .\"********************************************************* .SS Data Channel Encryption Options: These options are meaningful for both Static & TLS-negotiated key modes diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c index b3077ed6a5b..3a4c26a9692 100644 --- a/src/openvpn/forward.c +++ b/src/openvpn/forward.c @@ -993,6 +993,76 @@ read_incoming_tun (struct context *c) perf_pop (); } +/** + * Drops UDP packets which OS decided to route via tun. + * + * On Windows and OS X when netwotk adapter is disabled or + * disconnected, platform starts to use tun as external interface. + * When packet is sent to tun, it comes to openvpn, encapsulated + * and sent to routing table, which sends it again to tun. + */ +static void +drop_if_recursive_routing (struct context *c, struct buffer *buf) +{ + bool drop = false; + struct openvpn_sockaddr tun_sa; + int ip_hdr_offset = 0; + + if (c->c2.to_link_addr == NULL) /* no remote addr known */ + return; + + tun_sa = c->c2.to_link_addr->dest; + + int proto_ver = get_tun_ip_ver (TUNNEL_TYPE (c->c1.tuntap), &c->c2.buf, &ip_hdr_offset); + + if (proto_ver == 4) + { + const struct openvpn_iphdr *pip; + + /* make sure we got whole IP header */ + if (BLEN (buf) < ((int) sizeof (struct openvpn_iphdr) + ip_hdr_offset)) + return; + + /* skip ipv4 packets for ipv6 tun */ + if (tun_sa.addr.sa.sa_family != AF_INET) + return; + + pip = (struct openvpn_iphdr *) (BPTR (buf) + ip_hdr_offset); + + /* drop packets with same dest addr as gateway */ + if (tun_sa.addr.in4.sin_addr.s_addr == pip->daddr) + drop = true; + } + else if (proto_ver == 6) + { + const struct openvpn_ipv6hdr *pip6; + + /* make sure we got whole IPv6 header */ + if (BLEN (buf) < ((int) sizeof (struct openvpn_ipv6hdr) + ip_hdr_offset)) + return; + + /* skip ipv6 packets for ipv4 tun */ + if (tun_sa.addr.sa.sa_family != AF_INET6) + return; + + /* drop packets with same dest addr as gateway */ + pip6 = (struct openvpn_ipv6hdr *) (BPTR (buf) + ip_hdr_offset); + if (IN6_ARE_ADDR_EQUAL(&tun_sa.addr.in6.sin6_addr, &pip6->daddr)) + drop = true; + } + + if (drop) + { + struct gc_arena gc = gc_new (); + + c->c2.buf.len = 0; + + msg(D_LOW, "Recursive routing detected, drop tun packet to %s", + print_link_socket_actual(c->c2.to_link_addr, &gc)); + gc_free (&gc); + } +} + /* * Input: c->c2.buf * Output: c->c2.to_link @@ -1018,6 +1088,8 @@ process_incoming_tun (struct context *c) if (c->c2.buf.len > 0) { + if ((c->options.mode == MODE_POINT_TO_POINT) && (!c->options.allow_recursive_routing)) + drop_if_recursive_routing (c, &c->c2.buf); /* * The --passtos and --mssfix options require * us to examine the IP header (IPv4 or IPv6). diff --git a/src/openvpn/options.c b/src/openvpn/options.c index be31ed3792c..552bf5ab85e 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -508,6 +508,8 @@ static const char usage_message[] = "--connect-timeout n : when polling possible remote servers to connect to\n" " in a round-robin fashion, spend no more than n seconds\n" " waiting for a response before trying the next server.\n" + "--allow-recursive-routing : When this option is set, OpenVPN will not drop\n" + " incoming tun packets with same destination as host.\n" #endif #ifdef ENABLE_OCC "--explicit-exit-notify [n] : On exit/restart, send exit signal to\n" @@ -886,6 +888,7 @@ init_options (struct options *o, const bool init_gc) } #endif /* WIN32 */ #endif /* P2MP_SERVER */ + o->allow_recursive_routing = false; } void @@ -2134,6 +2137,8 @@ options_postprocess_verify_ce (const struct options *options, const struct conne msg (M_USAGE, "--ifconfig-pool-persist must be used with --ifconfig-pool"); if (options->ifconfig_ipv6_pool_defined && !options->ifconfig_ipv6_local ) msg (M_USAGE, "--ifconfig-ipv6-pool needs --ifconfig-ipv6"); + if (options->allow_recursive_routing) + msg (M_USAGE, "--allow-recursive-routing cannot be used with --mode server"); if (options->auth_user_pass_file) msg (M_USAGE, "--auth-user-pass cannot be used with --mode server (it should be used on the client side only)"); if (options->ccd_exclusive && !options->client_config_dir) @@ -7385,6 +7390,11 @@ add_option (struct options *options, options->keying_material_exporter_length = ekm_length; } #endif + else if (streq (p[0], "allow-recursive-routing") && !p[1]) + { + VERIFY_PERMISSION (OPT_P_GENERAL); + options->allow_recursive_routing = true; + } else { int i; diff --git a/src/openvpn/options.h b/src/openvpn/options.h index 2f91a521a59..0ebea30c4cf 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -597,6 +597,10 @@ struct options #endif struct pull_filter_list *pull_filter_list; + + /* Useful when packets sent by openvpn itself are not subject + to the routing tables that would move packets into the tunnel. */ + bool allow_recursive_routing; }; #define streq(x, y) (!strcmp((x), (y))) diff --git a/src/openvpn/proto.h b/src/openvpn/proto.h index f91e787ecbe..07612c8732a 100644 --- a/src/openvpn/proto.h +++ b/src/openvpn/proto.h @@ -218,6 +218,45 @@ struct ip_tcp_udp_hdr { #define MTU_TO_MSS(mtu) (mtu - sizeof(struct openvpn_iphdr) \ - sizeof(struct openvpn_tcphdr)) +/* + * This returns an ip protocol version of packet inside tun + * and offset of IP header (via parameter). + */ +inline static int get_tun_ip_ver(int tunnel_type, struct buffer *buf, int *ip_hdr_offset) +{ + int ip_ver = -1; + + /* for tun get ip version from ip header */ + if (tunnel_type == DEV_TYPE_TUN) + { + *ip_hdr_offset = 0; + if (likely(BLEN (buf) >= (int) sizeof (struct openvpn_iphdr))) + { + ip_ver = OPENVPN_IPH_GET_VER (*BPTR(buf)); + } + } + else if (tunnel_type == DEV_TYPE_TAP) + { + *ip_hdr_offset = (int)(sizeof (struct openvpn_ethhdr)); + /* for tap get ip version from eth header */ + if (likely(BLEN (buf) >= *ip_hdr_offset)) + { + const struct openvpn_ethhdr *eh = (const struct openvpn_ethhdr *) BPTR (buf); + uint16_t proto = ntohs (eh->proto); + if (proto == OPENVPN_ETH_P_IPV6) + { + ip_ver = 6; + } + else if (proto == OPENVPN_ETH_P_IPV4) + { + ip_ver = 4; + } + } + } + + return ip_ver; +} + /* * If raw tunnel packet is IPv4 or IPv6, return true and increment * buffer offset to start of IP header. From 8215b7a873400b85137f6e42cd7999dd12b00b71 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Fri, 4 Nov 2016 21:03:44 +0100 Subject: [PATCH 353/643] Fix --tls-version-max in mbed TLS builds These define renames were missed in the migration to 2.x, causing the maximum TLS version to be detected incorrectly. [DS: mbedTLS mapps supported SSL/TLS protocol version in the library through these macros. TLSv1.1 = 3.2, TLSv1.2 = 3.3, etc ] Signed-off-by: Steffan Karger Acked-by: David Sommerseth Message-Id: <1478289824-9244-1-git-send-email-steffan@karger.me> URL: http://www.mail-archive.com/search?l=mid&q=1478289824-9244-1-git-send-email-steffan@karger.me Signed-off-by: David Sommerseth --- src/openvpn/ssl_mbedtls.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/openvpn/ssl_mbedtls.c b/src/openvpn/ssl_mbedtls.c index 8a761a45a45..a6c90b1f1cc 100644 --- a/src/openvpn/ssl_mbedtls.c +++ b/src/openvpn/ssl_mbedtls.c @@ -723,9 +723,9 @@ void tls_ctx_personalise_random(struct tls_root_ctx *ctx) int tls_version_max(void) { -#if defined(SSL_MAJOR_VERSION_3) && defined(SSL_MINOR_VERSION_3) +#if defined(MBEDTLS_SSL_MAJOR_VERSION_3) && defined(MBEDTLS_SSL_MINOR_VERSION_3) return TLS_VER_1_2; -#elif defined(SSL_MAJOR_VERSION_3) && defined(SSL_MINOR_VERSION_2) +#elif defined(MBEDTLS_SSL_MAJOR_VERSION_3) && defined(MBEDTLS_SSL_MINOR_VERSION_2) return TLS_VER_1_1; #else return TLS_VER_1_0; From 2391a3ab08227a061a7f561e26b9688f6ba80e70 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Mon, 7 Nov 2016 11:50:52 +0100 Subject: [PATCH 354/643] openvpn version line: remove [IPv6], add [AEAD] if available Printing [IPv6] is no longer relevant information, as IPv6 support is always build in. So, "2.4 = has IPv6, always". [AEAD] is relevant information, as the underlying SSL library might be too old to have support for it (OpenSSL 0.9.x) and this eases figuring out why NCP is not upgrading a connection to AES-256-GCM. Trac #762 Signed-off-by: Gert Doering Acked-by: Steffan Karger Message-Id: <1478515852-17381-1-git-send-email-gert@greenie.muc.de> URL: http://www.mail-archive.com/search?l=mid&q=1478515852-17381-1-git-send-email-gert@greenie.muc.de Signed-off-by: Gert Doering --- src/openvpn/options.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 552bf5ab85e..5a5e7ef5717 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -103,7 +103,9 @@ const char title_string[] = " [MH/RECVDA]" # endif #endif - " [IPv6]" +#ifdef HAVE_AEAD_CIPHER_MODES + " [AEAD]" +#endif " built on " __DATE__ ; From 238cd6440312c59353a40a97b3c45d272561457f Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Mon, 7 Nov 2016 22:44:02 +0100 Subject: [PATCH 355/643] clean up *sig_info handling in link_socket_init_phase2() The code was a mix of "assume that it is not NULL" and "check that it is not NULL before using" - it cannot be NULL (due to the single call graph, referencing c->sig with the global context), but for good measure, add an ASSERT() upon function entry and get rid of all the individual checks. Found by Coverity. Signed-off-by: Gert Doering Acked-by: Steffan Karger Message-Id: <1478555042-31299-1-git-send-email-gert@greenie.muc.de> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12931.html Signed-off-by: Gert Doering --- src/openvpn/socket.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c index 184c7ad9b36..18e64097386 100644 --- a/src/openvpn/socket.c +++ b/src/openvpn/socket.c @@ -1857,8 +1857,9 @@ link_socket_init_phase2 (struct link_socket *sock, int sig_save = 0; ASSERT (sock); + ASSERT (sig_info); - if (sig_info && sig_info->signal_received) + if (sig_info->signal_received) { sig_save = sig_info->signal_received; sig_info->signal_received = 0; @@ -1879,7 +1880,7 @@ link_socket_init_phase2 (struct link_socket *sock, if (sock->inetd) { phase2_inetd (sock, frame, remote_dynamic, &sig_info->signal_received); - if (sig_info && sig_info->signal_received) + if (sig_info->signal_received) goto done; } @@ -1921,7 +1922,7 @@ link_socket_init_phase2 (struct link_socket *sock, goto done; } - if (sig_info && sig_info->signal_received) + if (sig_info->signal_received) goto done; if (sock->info.proto == PROTO_TCP_SERVER) @@ -1942,7 +1943,7 @@ link_socket_init_phase2 (struct link_socket *sock, if (sock->sd != -1) protect_fd_nonlocal (sock->sd, &sock->info.lsa->actual.dest.addr.sa); #endif - if (sig_info && sig_info->signal_received) + if (sig_info->signal_received) goto done; } @@ -1950,7 +1951,7 @@ link_socket_init_phase2 (struct link_socket *sock, linksock_print_addr(sock); done: - if (sig_save && sig_info) + if (sig_save) { if (!sig_info->signal_received) sig_info->signal_received = sig_save; From 71e7c5f25174a3046a32720d3d6eb77f87458217 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Tue, 8 Nov 2016 09:39:23 +0100 Subject: [PATCH 356/643] check c->c2.link_socket before calling do_init_route_ipv6_list() There was an asymmetry in checks before calling do_init_route*_list(), checking c2.link_socket for IPv4 but not for IPv6 - mainly an oversight from the time when do_init_route_ipv6_list() did not yet look at the remote address to determine v6-over-v6 overlaps (2.3 code). c2.link_socket should never be NULL here, so remove the "silently not call stuff" condition and replace with ASSERT(c2.link_socket) so we will notice if the assumption is ever wrong. Tested in client UDP/TCP mode and server UDP/TCP/P2P and --inetd mode. Found by Coverity. While at it, remove "fatal" argument to do_init_route*_list(), which was "false" in all cases (single invocation each), and remove the error exit code related to it. Signed-off-by: Gert Doering Acked-by: Steffan Karger Message-Id: <1478594363-12752-1-git-send-email-gert@greenie.muc.de> URL: http://www.mail-archive.com/search?l=mid&q=1478594363-12752-1-git-send-email-gert@greenie.muc.de Signed-off-by: Gert Doering --- src/openvpn/init.c | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 3ec3b184f40..91c53f51bb4 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -1157,7 +1157,6 @@ static void do_init_route_list (const struct options *options, struct route_list *route_list, const struct link_socket_info *link_socket_info, - bool fatal, struct env_set *es) { const char *gw = NULL; @@ -1171,17 +1170,12 @@ do_init_route_list (const struct options *options, if (options->route_default_metric) metric = options->route_default_metric; - if (!init_route_list (route_list, + if (init_route_list (route_list, options->routes, gw, metric, link_socket_current_remote (link_socket_info), es)) - { - if (fatal) - openvpn_exit (OPENVPN_EXIT_STATUS_ERROR); /* exit point */ - } - else { /* copy routes to environment */ setenv_routes (es, route_list); @@ -1192,7 +1186,6 @@ static void do_init_route_ipv6_list (const struct options *options, struct route_ipv6_list *route_ipv6_list, const struct link_socket_info *link_socket_info, - bool fatal, struct env_set *es) { const char *gw = NULL; @@ -1222,17 +1215,12 @@ do_init_route_ipv6_list (const struct options *options, } } - if (!init_route_ipv6_list (route_ipv6_list, + if (init_route_ipv6_list (route_ipv6_list, options->routes_ipv6, gw, metric, link_socket_current_remote_ipv6 (link_socket_info), es)) - { - if (fatal) - openvpn_exit (OPENVPN_EXIT_STATUS_ERROR); /* exit point */ - } - else { /* copy routes to environment */ setenv_routes_ipv6 (es, route_ipv6_list); @@ -1443,10 +1431,13 @@ do_open_tun (struct context *c) do_alloc_route_list (c); /* parse and resolve the route option list */ - if (c->options.routes && c->c1.route_list && c->c2.link_socket) - do_init_route_list (&c->options, c->c1.route_list, &c->c2.link_socket->info, false, c->c2.es); - if (c->options.routes_ipv6 && c->c1.route_ipv6_list ) - do_init_route_ipv6_list (&c->options, c->c1.route_ipv6_list, &c->c2.link_socket->info, false, c->c2.es); + ASSERT(c->c2.link_socket); + if (c->options.routes && c->c1.route_list) + do_init_route_list (&c->options, c->c1.route_list, + &c->c2.link_socket->info, c->c2.es); + if (c->options.routes_ipv6 && c->c1.route_ipv6_list) + do_init_route_ipv6_list (&c->options, c->c1.route_ipv6_list, + &c->c2.link_socket->info, c->c2.es); /* do ifconfig */ if (!c->options.ifconfig_noexec From 63bdc6ce66a970f0584bbb1d4a8cae98b36ee831 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Tue, 8 Nov 2016 10:17:12 +0100 Subject: [PATCH 357/643] Check previously-unchecked buf_alloc_write() call in crypto self-test. "It cannot be NULL", but since this is self-test infrastructure, assume the worst - add ASSERT() check to ensure assumptions are true. Found by Coverity. Signed-off-by: Gert Doering Acked-by: Steffan Karger Message-Id: <1478596632-22842-1-git-send-email-gert@greenie.muc.de> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12940.html Signed-off-by: Gert Doering --- src/openvpn/crypto.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c index 6e1e46bd1c1..0212450be8a 100644 --- a/src/openvpn/crypto.c +++ b/src/openvpn/crypto.c @@ -1028,6 +1028,7 @@ test_crypto (struct crypto_options *co, struct frame* frame) struct buffer encrypt_workspace = alloc_buf_gc (BUF_SIZE (frame), &gc); struct buffer decrypt_workspace = alloc_buf_gc (BUF_SIZE (frame), &gc); struct buffer buf = clear_buf(); + void *buf_p; /* init work */ ASSERT (buf_init (&work, FRAME_HEADROOM (frame))); @@ -1073,7 +1074,9 @@ test_crypto (struct crypto_options *co, struct frame* frame) /* copy source to input buf */ buf = work; - memcpy (buf_write_alloc (&buf, BLEN (&src)), BPTR (&src), BLEN (&src)); + buf_p = buf_write_alloc (&buf, BLEN (&src)); + ASSERT(buf_p); + memcpy (buf_p, BPTR (&src), BLEN (&src)); /* initialize work buffer with FRAME_HEADROOM bytes of prepend capacity */ ASSERT (buf_init (&encrypt_workspace, FRAME_HEADROOM (frame))); From 9c3a9335ee77d8447bf47e464f4ab15964fb6f1b Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Tue, 8 Nov 2016 10:44:02 +0100 Subject: [PATCH 358/643] Fix potential division by zero in shaper_reset() shaper_reset() is only ever called with "bytes_per_second" set to a non-zero value - so the whole check "is it zero? if not, use constrain_int() to make sure it is within bounds" is not needed -> reduce check to just constrain_int() so even if somebody would call shaper_reset(..., 0) it would not lead to a div-by-zero. Found by Coverity. Signed-off-by: Gert Doering Acked-by: Steffan Karger Message-Id: <1478598242-23514-1-git-send-email-gert@greenie.muc.de> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12942.html Signed-off-by: Gert Doering --- src/openvpn/shaper.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openvpn/shaper.h b/src/openvpn/shaper.h index afeb9c3cd04..fa132c40bf1 100644 --- a/src/openvpn/shaper.h +++ b/src/openvpn/shaper.h @@ -75,7 +75,7 @@ bool shaper_soonest_event (struct timeval *tv, int delay); static inline void shaper_reset (struct shaper *s, int bytes_per_second) { - s->bytes_per_second = bytes_per_second ? constrain_int (bytes_per_second, SHAPER_MIN, SHAPER_MAX) : 0; + s->bytes_per_second = constrain_int (bytes_per_second, SHAPER_MIN, SHAPER_MAX); #ifdef SHAPER_USE_FP s->factor = 1000000.0 / (double)s->bytes_per_second; From 2af1fa8b19e9723b29f4a4c198f61478ae9e688e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuli=20Sepp=C3=A4nen?= Date: Tue, 8 Nov 2016 14:55:26 +0200 Subject: [PATCH 359/643] Fix update_t_client_ips.sh for out of tree builds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Samuli Seppänen Acked-by: Gert Doering Message-Id: <1478609729-25222-2-git-send-email-samuli@openvpn.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12952.html Signed-off-by: Gert Doering --- tests/t_client.rc-sample | 4 ++-- tests/t_client.sh.in | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/t_client.rc-sample b/tests/t_client.rc-sample index 59f34c7f27e..31dfafac02b 100644 --- a/tests/t_client.rc-sample +++ b/tests/t_client.rc-sample @@ -13,8 +13,8 @@ CLIENT_KEY="${top_srcdir}/sample/sample-keys/client.key" CLIENT_CERT="${top_srcdir}/sample/sample-keys/client.crt" # Load EXPECT_IFCONFIG* parameters from cache -if [ -r "${top_srcdir}/t_client_ips.rc" ]; then - . "${top_srcdir}/t_client_ips.rc" +if [ -r "${top_builddir}/t_client_ips.rc" ]; then + . "${top_builddir}/t_client_ips.rc" else echo "NOTICE: missing t_client_ips.rc will be auto-generated" fi diff --git a/tests/t_client.sh.in b/tests/t_client.sh.in index 6c81bc41292..408703ee5f5 100755 --- a/tests/t_client.sh.in +++ b/tests/t_client.sh.in @@ -275,7 +275,7 @@ do # If EXCEPT_IFCONFIG* variables for this test are missing, run an --up # script to generate them dynamically. if [ -z "$expect_ifconfig4" ] || [ -z "$expect_ifconfig6" ]; then - up="--setenv TESTNUM $SUF --setenv TOP_BUILDDIR ${top_builddir} --script-security 2 --up ${top_builddir}/tests/update_t_client_ips.sh" + up="--setenv TESTNUM $SUF --setenv TOP_BUILDDIR ${top_builddir} --script-security 2 --up ${srcdir}/update_t_client_ips.sh" fi echo -e "\n### test run $SUF: '$test_run_title' ###\n" From e81023f00bbc503c41cea0a988a0ac00edae754a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuli=20Sepp=C3=A4nen?= Date: Tue, 8 Nov 2016 14:55:28 +0200 Subject: [PATCH 360/643] Make sure that all relevant files under test go to release tarballs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Samuli Seppänen Acked-by: Gert Doering Message-Id: <1478609729-25222-4-git-send-email-samuli@openvpn.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12955.html Signed-off-by: Gert Doering --- tests/Makefile.am | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/Makefile.am b/tests/Makefile.am index 235cd1328a9..e55928b5747 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -24,4 +24,8 @@ TESTS = $(test_scripts) dist_noinst_SCRIPTS = \ $(test_scripts) \ - t_cltsrv-down.sh + t_cltsrv-down.sh \ + update_t_client_ips.sh + +dist_noinst_DATA = \ + t_client.rc-sample From 6f17e18be0d6ab801704400abcc6b17d4fed9650 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuli=20Sepp=C3=A4nen?= Date: Tue, 8 Nov 2016 15:50:43 +0200 Subject: [PATCH 361/643] Allow passing extra arguments to fping/fping6 in t_client.rc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This can be useful, for example, in preventing fping failures caused by external network issues. v2: - Allow override of the default parameters Signed-off-by: Samuli Seppänen Acked-by: Gert Doering Message-Id: <1478613043-27033-1-git-send-email-samuli@openvpn.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12962.html Signed-off-by: Gert Doering --- tests/t_client.rc-sample | 1 + tests/t_client.sh.in | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/t_client.rc-sample b/tests/t_client.rc-sample index 31dfafac02b..4fdea487658 100644 --- a/tests/t_client.rc-sample +++ b/tests/t_client.rc-sample @@ -11,6 +11,7 @@ top_srcdir="${top_srcdir:-..}" CA_CERT="${top_srcdir}/sample/sample-keys/ca.crt" CLIENT_KEY="${top_srcdir}/sample/sample-keys/client.key" CLIENT_CERT="${top_srcdir}/sample/sample-keys/client.crt" +#FPING_EXTRA_ARGS="-t 1000" # Load EXPECT_IFCONFIG* parameters from cache if [ -r "${top_builddir}/t_client_ips.rc" ]; then diff --git a/tests/t_client.sh.in b/tests/t_client.sh.in index 408703ee5f5..076f6bd86e7 100755 --- a/tests/t_client.sh.in +++ b/tests/t_client.sh.in @@ -231,8 +231,8 @@ run_ping_tests() do echo "run IPv$proto ping tests ($want), $bytes byte packets..." - echo "$cmd -b $bytes -C 20 -p 250 -q $targetlist" >>$LOGDIR/$SUF:fping.out - $cmd -b $bytes -C 20 -p 250 -q $targetlist >>$LOGDIR/$SUF:fping.out 2>&1 + echo "$cmd -b $bytes -C 20 -p 250 -q $FPING_EXTRA_ARGS $targetlist" >>$LOGDIR/$SUF:fping.out + $cmd -b $bytes -C 20 -p 250 -q $FPING_EXTRA_ARGS $targetlist >>$LOGDIR/$SUF:fping.out 2>&1 # while OpenVPN is running, pings must succeed (want='want_ok') # before OpenVPN is up, pings must NOT succeed (want='want_fail') From 82a601f1e23d1c37bc2120dca12cadc4dbf2b4fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuli=20Sepp=C3=A4nen?= Date: Tue, 8 Nov 2016 16:06:03 +0200 Subject: [PATCH 362/643] Prevent generation of duplicate EXPECT_IFCONFIG entries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, if t_client.rc did not source t_client_ips.rc, update_t_client_ips.sh would add (the same) EXPECT_IFCONFIG entries to t_client_ips.rc on every run. This patch makes update_t_client_ips.sh check if the entry exists before trying to add it. v2: prevent partial matches of the EXCEPT_IFCONFIG variable name Signed-off-by: Samuli Seppänen Acked-by: Gert Doering Message-Id: <1478613963-28077-1-git-send-email-samuli@openvpn.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12965.html Signed-off-by: Gert Doering --- tests/update_t_client_ips.sh | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/tests/update_t_client_ips.sh b/tests/update_t_client_ips.sh index e7b58ba2a23..96e38260737 100755 --- a/tests/update_t_client_ips.sh +++ b/tests/update_t_client_ips.sh @@ -3,5 +3,14 @@ # This --up script caches the IPs handed out by the test VPN server to a file # for later use. -echo "EXPECT_IFCONFIG4_$TESTNUM=$ifconfig_local" >> $TOP_BUILDDIR/t_client_ips.rc -echo "EXPECT_IFCONFIG6_$TESTNUM=$ifconfig_ipv6_local" >> $TOP_BUILDDIR/t_client_ips.rc +RC="$TOP_BUILDDIR/t_client_ips.rc" + +grep EXPECT_IFCONFIG4_$TESTNUM= $RC > /dev/null 2>&1 +if [ $? -ne 0 ]; then + echo "EXPECT_IFCONFIG4_$TESTNUM=$ifconfig_local" >> $RC +fi + +grep EXPECT_IFCONFIG6_$TESTNUM= $RC > /dev/null 2>&1 +if [ $? -ne 0 ]; then + echo "EXPECT_IFCONFIG6_$TESTNUM=$ifconfig_ipv6_local" >> $RC +fi From dd9a4f0ecf06e907c57f4fa7ab035b897268d54a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuli=20Sepp=C3=A4nen?= Date: Wed, 9 Nov 2016 14:42:05 +0200 Subject: [PATCH 363/643] Fix a logic problem in handling of --up scripts in t_client.sh MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously the $up variable was never reset after being set. This mean that "--up update_t_client_ips.sh" was appended to all subsequent openvpn command-lines, even if cached IPs existed. Signed-off-by: Samuli Seppänen Acked-by: Gert Doering Message-Id: <1478695325-18038-1-git-send-email-samuli@openvpn.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12979.html Signed-off-by: Gert Doering --- tests/t_client.sh.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/t_client.sh.in b/tests/t_client.sh.in index 076f6bd86e7..b92cb65deab 100755 --- a/tests/t_client.sh.in +++ b/tests/t_client.sh.in @@ -276,6 +276,8 @@ do # script to generate them dynamically. if [ -z "$expect_ifconfig4" ] || [ -z "$expect_ifconfig6" ]; then up="--setenv TESTNUM $SUF --setenv TOP_BUILDDIR ${top_builddir} --script-security 2 --up ${srcdir}/update_t_client_ips.sh" + else + up="" fi echo -e "\n### test run $SUF: '$test_run_title' ###\n" From a433b3813d8c38b491d2baa7b433973f2d6cd7c6 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Tue, 8 Nov 2016 13:45:06 +0100 Subject: [PATCH 364/643] Repair topology subnet on FreeBSD 11 We used to add "route for this subnet" by using our own address as the gateway address, which used to mean "connected to the interface, no gateway". FreeBSD commit 293159 changed the kernel side of that assumption so "my address" is now always bound to "lo0" - thus, our subnet route also ended up pointing to "lo0", breaking connectivity for all hosts in the subnet except the one we used as "remote". commit 60fd44e501f200 already introduced a "remote address" we use for the "ifconfig tunX " part - extend that to be used as gateway address for the "tunX subnet" as well, and things will work more robustly. Tested on FreeBSD 11.0-RELEASE and 7.4-RELEASE (client and server) (this particular issue is not present before 11.0, but "adding the subnet route" never worked right, not even in 7.4 - 11.0 just made the problem manifest more clearly) Trac #425 URL: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=207831 Signed-off-by: Gert Doering Acked-by: Steffan Karger Message-Id: <20161108124506.32559-1-gert@greenie.muc.de> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12950.html Signed-off-by: Gert Doering --- src/openvpn/tun.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index af685de37eb..a6d38d5db86 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -721,8 +721,8 @@ void delete_route_connected_v6_net(struct tuntap * tt, * is still point to point and no layer 2 resolution is done... */ -const char * -create_arbitrary_remote( struct tuntap *tt, struct gc_arena * gc ) +in_addr_t +create_arbitrary_remote( struct tuntap *tt ) { in_addr_t remote; @@ -730,7 +730,7 @@ create_arbitrary_remote( struct tuntap *tt, struct gc_arena * gc ) if ( remote == tt->local ) remote ++; - return print_in_addr_t (remote, 0, gc); + return remote; } #endif @@ -1230,6 +1230,8 @@ do_ifconfig (struct tuntap *tt, #elif defined(TARGET_FREEBSD)||defined(TARGET_DRAGONFLY) + in_addr_t remote_end; /* for "virtual" subnet topology */ + /* example: ifconfig tun2 10.2.0.2 10.2.0.1 mtu 1450 netmask 255.255.255.255 up */ if (tun) argv_printf (&argv, @@ -1242,12 +1244,13 @@ do_ifconfig (struct tuntap *tt, ); else if ( tt->topology == TOP_SUBNET ) { + remote_end = create_arbitrary_remote( tt ); argv_printf (&argv, "%s %s %s %s mtu %d netmask %s up", IFCONFIG_PATH, actual, ifconfig_local, - create_arbitrary_remote( tt, &gc ), + print_in_addr_t (remote_end, 0, &gc), tun_mtu, ifconfig_remote_netmask ); @@ -1274,7 +1277,7 @@ do_ifconfig (struct tuntap *tt, r.flags = RT_DEFINED; r.network = tt->local & tt->remote_netmask; r.netmask = tt->remote_netmask; - r.gateway = tt->local; + r.gateway = remote_end; add_route (&r, tt, 0, NULL, es); } From 7f444dee52321c0f0294e99695150a7f69522715 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Wed, 9 Nov 2016 21:19:32 +0100 Subject: [PATCH 365/643] Repair topology subnet on OpenBSD Turns out that "topology subnet" never worked totally right on OpenBSD - the "netmask" parameter to ifconfig is ignored, and one needs to add a subnet route (and this issue is hidden if an encompassing route is pushed, like, by using --redirect-gateway). While add it, apply the hack used for FreeBSD where "an arbitrary address from the subnet" is used to set the "remote" end of the tunnel, and point the route to that - so if OpenBSD decides to change their kernel routing structure the same way, our code still works (copying from commit 433b3813d8c38b4, trac #425 and commit 60fd44e501f2002, trac #481). Tested on OpenBSD 6.0 and 4.9 Trac: #710 Signed-off-by: Gert Doering Acked-by: David Sommerseth Message-Id: <20161109201932.80991-1-gert@greenie.muc.de> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12983.html Signed-off-by: David Sommerseth --- src/openvpn/tun.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index a6d38d5db86..a312d911267 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -711,7 +711,8 @@ void delete_route_connected_v6_net(struct tuntap * tt, } #endif -#if defined(TARGET_FREEBSD)||defined(TARGET_DRAGONFLY) +#if defined(TARGET_FREEBSD)||defined(TARGET_DRAGONFLY)||\ + defined(TARGET_OPENBSD) /* we can't use true subnet mode on tun on all platforms, as that * conflicts with IPv6 (wants to use ND then, which we don't do), * but the OSes want "a remote address that is different from ours" @@ -1032,6 +1033,8 @@ do_ifconfig (struct tuntap *tt, #elif defined(TARGET_OPENBSD) + in_addr_t remote_end; /* for "virtual" subnet topology */ + /* * On OpenBSD, tun interfaces are persistent if created with * "ifconfig tunX create", and auto-destroyed if created by @@ -1051,12 +1054,13 @@ do_ifconfig (struct tuntap *tt, else if ( tt->topology == TOP_SUBNET ) { + remote_end = create_arbitrary_remote( tt ); argv_printf (&argv, "%s %s %s %s mtu %d netmask %s up -link0", IFCONFIG_PATH, actual, ifconfig_local, - ifconfig_local, + print_in_addr_t (remote_end, 0, &gc), tun_mtu, ifconfig_remote_netmask ); @@ -1073,6 +1077,19 @@ do_ifconfig (struct tuntap *tt, ); argv_msg (M_INFO, &argv); openvpn_execve_check (&argv, es, S_FATAL, "OpenBSD ifconfig failed"); + + /* Add a network route for the local tun interface */ + if (!tun && tt->topology == TOP_SUBNET) + { + struct route_ipv4 r; + CLEAR (r); + r.flags = RT_DEFINED; + r.network = tt->local & tt->remote_netmask; + r.netmask = tt->remote_netmask; + r.gateway = remote_end; + add_route (&r, tt, 0, NULL, es); + } + if ( do_ipv6 ) { argv_printf (&argv, From 14cb1639f7694cdd461bace5e273acd7722cd3cf Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Fri, 11 Nov 2016 14:30:07 +0100 Subject: [PATCH 366/643] console: Fix compiler warning Building with -O2, the compiler warned about query_user_SINGLE() being declared and not used in console.c. This function, defined in console.h, should have been declared as 'static inline'. This also removes that warning. Signed-off-by: David Sommerseth Acked-by: Gert Doering Message-Id: <1478871007-25998-1-git-send-email-davids@openvpn.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13005.html Signed-off-by: Gert Doering --- src/openvpn/console.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openvpn/console.h b/src/openvpn/console.h index 41f2b8c2485..ec32cf6491f 100644 --- a/src/openvpn/console.h +++ b/src/openvpn/console.h @@ -106,7 +106,7 @@ static bool query_user_exec () * to be called at start-up initialization of OpenVPN. * */ -static bool query_user_SINGLE (char *prompt, size_t prompt_len, +static inline bool query_user_SINGLE (char *prompt, size_t prompt_len, char *resp, size_t resp_len, bool echo) { From 8cac9b98d58b97fbd5a23dd9f172a9843ecf5b50 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sun, 13 Nov 2016 14:17:27 +0100 Subject: [PATCH 367/643] Don't deference type-punned pointers Dereferencing type-punned pointers is undefined behaviour according to the C standard. We should either obey the standard, or ensure that all supported compilers deal with dereferencing type-punned pointers as we want them to. I think just obeying the standard is the easiest solution. See e.g. http://blog.regehr.org/archives/959. This commit refactors the offending code to use unions or memcpy() to comply to strict aliasing rules. Note that this also slightly changes mroute_addr_mask_host_bits(), to behave as it was probably intended to: only mask the address part, not also the port part of IPv6 adresses if MR_WITH_PORT is used (ie ma->len is sizeof(struct in6_addr)+2). v2: fix all strict aliasing occurrences, not just those in mroute.h v3: add missing ntohs() in mroute_addr_print_ex() Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1479043047-25883-1-git-send-email-steffan@karger.me> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13017.html Signed-off-by: Gert Doering --- src/openvpn/error.h | 10 ++++++ src/openvpn/mroute.c | 85 +++++++++++++++++++++----------------------- src/openvpn/mroute.h | 41 +++++++++++++++++---- src/openvpn/multi.c | 4 +-- src/openvpn/ps.c | 10 +++--- src/openvpn/socket.c | 3 +- 6 files changed, 96 insertions(+), 57 deletions(-) diff --git a/src/openvpn/error.h b/src/openvpn/error.h index ced2fdfff9c..c90b36be25e 100644 --- a/src/openvpn/error.h +++ b/src/openvpn/error.h @@ -27,6 +27,8 @@ #include "basic.h" +#include + /* #define ABORT_ON_ERROR */ #ifdef ENABLE_PKCS11 @@ -219,6 +221,14 @@ FILE *msg_fp(const unsigned int flags); void assert_failed (const char *filename, int line, const char *condition) __attribute__((__noreturn__)); +/* Poor-man's static_assert() for when not supplied by assert.h, taken from + * Linux's sys/cdefs.h under GPLv2 */ +#ifndef static_assert +#define static_assert(expr, diagnostic) \ + extern int (*__OpenVPN_static_assert_function (void)) \ + [!!sizeof (struct { int __error_if_negative: (expr) ? 2 : -1; })] +#endif + #ifdef ENABLE_DEBUG void crash (void); /* force a segfault (debugging only) */ #endif diff --git a/src/openvpn/mroute.c b/src/openvpn/mroute.c index 972f1dd5e45..c905af78626 100644 --- a/src/openvpn/mroute.c +++ b/src/openvpn/mroute.c @@ -58,7 +58,8 @@ is_mac_mcast_addr (const uint8_t *mac) static inline bool is_mac_mcast_maddr (const struct mroute_addr *addr) { - return (addr->type & MR_ADDR_MASK) == MR_ADDR_ETHER && is_mac_mcast_addr (addr->addr); + return (addr->type & MR_ADDR_MASK) == MR_ADDR_ETHER && + is_mac_mcast_addr (addr->eth_addr); } /* @@ -73,7 +74,7 @@ mroute_learnable_address (const struct mroute_addr *addr) for (i = 0; i < addr->len; ++i) { - int b = addr->addr[i]; + int b = addr->raw_addr[i]; if (b != 0x00) not_all_zeros = true; if (b != 0xFF) @@ -90,7 +91,7 @@ mroute_get_in_addr_t (struct mroute_addr *ma, const in_addr_t src, unsigned int ma->type = MR_ADDR_IPV4 | mask; ma->netbits = 0; ma->len = 4; - *(in_addr_t*)ma->addr = src; + ma->v4.addr = src; } } @@ -102,7 +103,7 @@ mroute_get_in6_addr (struct mroute_addr *ma, const struct in6_addr src, unsigned ma->type = MR_ADDR_IPV6 | mask; ma->netbits = 0; ma->len = 16; - *(struct in6_addr *)ma->addr = src; + ma->v6.addr = src; } } @@ -226,14 +227,14 @@ mroute_extract_addr_ether (struct mroute_addr *src, src->type = MR_ADDR_ETHER; src->netbits = 0; src->len = 6; - memcpy (src->addr, eth->source, 6); + memcpy (src->eth_addr, eth->source, sizeof(dest->eth_addr)); } if (dest) { dest->type = MR_ADDR_ETHER; dest->netbits = 0; dest->len = 6; - memcpy (dest->addr, eth->dest, 6); + memcpy (dest->eth_addr, eth->dest, sizeof(dest->eth_addr)); /* ethernet broadcast/multicast packet? */ if (is_mac_mcast_addr (eth->dest)) @@ -281,15 +282,15 @@ bool mroute_extract_openvpn_sockaddr (struct mroute_addr *addr, addr->type = MR_ADDR_IPV4 | MR_WITH_PORT; addr->netbits = 0; addr->len = 6; - memcpy (addr->addr, &osaddr->addr.in4.sin_addr.s_addr, 4); - memcpy (addr->addr + 4, &osaddr->addr.in4.sin_port, 2); + addr->v4.addr = osaddr->addr.in4.sin_addr.s_addr; + addr->v4.port = osaddr->addr.in4.sin_port; } else { addr->type = MR_ADDR_IPV4; addr->netbits = 0; addr->len = 4; - memcpy (addr->addr, &osaddr->addr.in4.sin_addr.s_addr, 4); + addr->v4.addr = osaddr->addr.in4.sin_addr.s_addr; } return true; } @@ -299,15 +300,15 @@ bool mroute_extract_openvpn_sockaddr (struct mroute_addr *addr, addr->type = MR_ADDR_IPV6 | MR_WITH_PORT; addr->netbits = 0; addr->len = 18; - memcpy (addr->addr, &osaddr->addr.in6.sin6_addr, 16); - memcpy (addr->addr + 16, &osaddr->addr.in6.sin6_port, 2); + addr->v6.addr = osaddr->addr.in6.sin6_addr; + addr->v6.port = osaddr->addr.in6.sin6_port; } else { addr->type = MR_ADDR_IPV6; addr->netbits = 0; addr->len = 16; - memcpy (addr->addr, &osaddr->addr.in6.sin6_addr, 16); + addr->v6.addr = osaddr->addr.in6.sin6_addr; } return true; } @@ -326,23 +327,29 @@ bool mroute_extract_openvpn_sockaddr (struct mroute_addr *addr, void mroute_addr_mask_host_bits (struct mroute_addr *ma) { - in_addr_t addr = ntohl(*(in_addr_t*)ma->addr); if ((ma->type & MR_ADDR_MASK) == MR_ADDR_IPV4) { + in_addr_t addr = ntohl (ma->v4.addr); addr &= netbits_to_netmask (ma->netbits); - *(in_addr_t*)ma->addr = htonl (addr); + ma->v4.addr = htonl (addr); } else if ((ma->type & MR_ADDR_MASK) == MR_ADDR_IPV6) { - int byte = ma->len-1; /* rightmost byte in address */ + int byte = sizeof (ma->v6.addr) - 1; /* rightmost byte in address */ int bits_to_clear = 128 - ma->netbits; while( byte >= 0 && bits_to_clear > 0 ) { if ( bits_to_clear >= 8 ) - { ma->addr[byte--] = 0; bits_to_clear -= 8; } + { + ma->v6.addr.s6_addr[byte--] = 0; + bits_to_clear -= 8; + } else - { ma->addr[byte--] &= (IPV4_NETMASK_HOST << bits_to_clear); bits_to_clear = 0; } + { + ma->v6.addr.s6_addr[byte--] &= (IPV4_NETMASK_HOST << bits_to_clear); + bits_to_clear = 0; + } } ASSERT( bits_to_clear == 0 ); } @@ -390,51 +397,41 @@ mroute_addr_print_ex (const struct mroute_addr *ma, switch (maddr.type & MR_ADDR_MASK) { case MR_ADDR_ETHER: - buf_printf (&out, "%s", format_hex_ex (ma->addr, 6, 0, 1, ":", gc)); + buf_printf (&out, "%s", format_hex_ex (ma->eth_addr, + sizeof(ma->eth_addr), 0, 1, ":", gc)); break; case MR_ADDR_IPV4: { - struct buffer buf; - in_addr_t addr; - int port; - bool status; - buf_set_read (&buf, maddr.addr, maddr.len); - addr = buf_read_u32 (&buf, &status); - if (status) + if ((flags & MAPF_SHOW_ARP) && (maddr.type & MR_ARP)) + buf_printf (&out, "ARP/"); + buf_printf (&out, "%s", print_in_addr_t (ntohl (maddr.v4.addr), + (flags & MAPF_IA_EMPTY_IF_UNDEF) ? IA_EMPTY_IF_UNDEF : 0, gc)); + if (maddr.type & MR_WITH_NETBITS) { - if ((flags & MAPF_SHOW_ARP) && (maddr.type & MR_ARP)) - buf_printf (&out, "ARP/"); - buf_printf (&out, "%s", print_in_addr_t (addr, (flags & MAPF_IA_EMPTY_IF_UNDEF) ? IA_EMPTY_IF_UNDEF : 0, gc)); - if (maddr.type & MR_WITH_NETBITS) + if (flags & MAPF_SUBNET) { - if (flags & MAPF_SUBNET) - { - const in_addr_t netmask = netbits_to_netmask (maddr.netbits); - buf_printf (&out, "/%s", print_in_addr_t (netmask, 0, gc)); - } - else - buf_printf (&out, "/%d", maddr.netbits); + const in_addr_t netmask = netbits_to_netmask (maddr.netbits); + buf_printf (&out, "/%s", print_in_addr_t (netmask, 0, gc)); } + else + buf_printf (&out, "/%d", maddr.netbits); } if (maddr.type & MR_WITH_PORT) { - port = buf_read_u16 (&buf); - if (port >= 0) - buf_printf (&out, ":%d", port); + buf_printf (&out, ":%d", ntohs (maddr.v4.port)); } } break; case MR_ADDR_IPV6: { - if ( IN6_IS_ADDR_V4MAPPED( (struct in6_addr*)&maddr.addr ) ) + if ( IN6_IS_ADDR_V4MAPPED( &maddr.v6.addr ) ) { - buf_printf (&out, "%s", - print_in_addr_t( *(in_addr_t*)(&maddr.addr[12]), IA_NET_ORDER, gc)); + buf_printf (&out, "%s", print_in_addr_t (maddr.v4mappedv6.addr, + IA_NET_ORDER, gc)); } else { - buf_printf (&out, "%s", - print_in6_addr( *(struct in6_addr*)&maddr.addr, 0, gc)); + buf_printf (&out, "%s", print_in6_addr (maddr.v6.addr, 0, gc)); } if (maddr.type & MR_WITH_NETBITS) { diff --git a/src/openvpn/mroute.h b/src/openvpn/mroute.h index 608f70bef2a..5fe17e7f31e 100644 --- a/src/openvpn/mroute.h +++ b/src/openvpn/mroute.h @@ -31,6 +31,8 @@ #include "list.h" #include "route.h" +#include + #define IP_MCAST_SUBNET_MASK ((in_addr_t)240<<24) #define IP_MCAST_NETWORK ((in_addr_t)224<<24) @@ -79,9 +81,35 @@ struct mroute_addr { uint8_t type; /* MR_ADDR/MR_WITH flags */ uint8_t netbits; /* number of bits in network part of address, valid if MR_WITH_NETBITS is set */ - uint8_t addr[MR_MAX_ADDR_LEN]; /* actual address */ + union { + uint8_t raw_addr[MR_MAX_ADDR_LEN]; /* actual address */ + uint8_t eth_addr[OPENVPN_ETH_ALEN]; + struct { + in_addr_t addr; /* _network order_ IPv4 address */ + in_port_t port; /* _network order_ TCP/UDP port */ + } v4; + struct { + struct in6_addr addr; + in_port_t port; /* _network order_ TCP/UDP port */ + } v6; + struct { + uint8_t prefix[12]; + in_addr_t addr; /* _network order_ IPv4 address */ + } v4mappedv6; + }; }; +/* Double-check that struct packing works as expected */ +static_assert (offsetof(struct mroute_addr, v4.port) == + offsetof(struct mroute_addr, v4) + 4, + "Unexpected struct packing of v4"); +static_assert (offsetof(struct mroute_addr, v6.port) == + offsetof(struct mroute_addr, v6) + 16, + "Unexpected struct packing of v6"); +static_assert (offsetof(struct mroute_addr, v4mappedv6.addr) == + offsetof(struct mroute_addr, v4mappedv6) + 12, + "Unexpected struct packing of v4mappedv6"); + /* * Number of bits in an address. Should be raised for IPv6. */ @@ -167,7 +195,7 @@ mroute_addr_equal (const struct mroute_addr *a1, const struct mroute_addr *a2) return false; if (a1->len != a2->len) return false; - return memcmp (a1->addr, a2->addr, a1->len) == 0; + return memcmp (a1->raw_addr, a2->raw_addr, a1->len) == 0; } static inline const uint8_t * @@ -189,16 +217,17 @@ mroute_extract_in_addr_t (struct mroute_addr *dest, const in_addr_t src) dest->type = MR_ADDR_IPV4; dest->netbits = 0; dest->len = 4; - *(in_addr_t*)dest->addr = htonl (src); + dest->v4.addr = htonl (src); } static inline in_addr_t in_addr_t_from_mroute_addr (const struct mroute_addr *addr) { - if ((addr->type & MR_ADDR_MASK) == MR_ADDR_IPV4 && addr->netbits == 0 && addr->len == 4) - return ntohl(*(in_addr_t*)addr->addr); - else + if ((addr->type & MR_ADDR_MASK) == MR_ADDR_IPV4 && addr->netbits == 0 && addr->len == 4) { + return ntohl(addr->v4.addr); + } else { return 0; + } } static inline void diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index 93a554d0a37..dc4cff47e07 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -1201,7 +1201,7 @@ multi_learn_in6_addr (struct multi_context *m, addr.len = 16; addr.type = MR_ADDR_IPV6; addr.netbits = 0; - memcpy( &addr.addr, &a6, sizeof(a6) ); + addr.v6.addr = a6; if (netbits >= 0) { @@ -2435,7 +2435,7 @@ multi_process_incoming_link (struct multi_context *m, struct multi_instance *ins { /* IPv6 link-local address (fe80::xxx)? */ if ( (src.type & MR_ADDR_MASK) == MR_ADDR_IPV6 && - src.addr[0] == 0xfe && src.addr[1] == 0x80 ) + IN6_IS_ADDR_LINKLOCAL (&src.v6.addr) ) { /* do nothing, for now. TODO: add address learning */ } diff --git a/src/openvpn/ps.c b/src/openvpn/ps.c index fe18a9df535..2cb68f170a5 100644 --- a/src/openvpn/ps.c +++ b/src/openvpn/ps.c @@ -223,12 +223,12 @@ port_share_sendmsg (const socket_descriptor_t sd, if (socket_defined (sd_send)) { - *((socket_descriptor_t*)CMSG_DATA(h)) = sd_send; + memcpy (CMSG_DATA(h), &sd_send, sizeof (sd_send)); } else { socketpair (PF_UNIX, SOCK_DGRAM, 0, sd_null); - *((socket_descriptor_t*)CMSG_DATA(h)) = sd_null[0]; + memcpy (CMSG_DATA(h), &sd_null[0], sizeof (sd_null[0])); } status = sendmsg (sd, &mesg, MSG_NOSIGNAL); @@ -502,7 +502,8 @@ control_message_from_parent (const socket_descriptor_t sd_control, h->cmsg_len = CMSG_LEN(sizeof(socket_descriptor_t)); h->cmsg_level = SOL_SOCKET; h->cmsg_type = SCM_RIGHTS; - *((socket_descriptor_t*)CMSG_DATA(h)) = SOCKET_UNDEFINED; + static const socket_descriptor_t socket_undefined = SOCKET_UNDEFINED; + memcpy (CMSG_DATA(h), &socket_undefined, sizeof(socket_undefined)); status = recvmsg (sd_control, &mesg, MSG_NOSIGNAL); if (status != -1) @@ -516,7 +517,8 @@ control_message_from_parent (const socket_descriptor_t sd_control, } else { - const socket_descriptor_t received_fd = *((socket_descriptor_t*)CMSG_DATA(h)); + socket_descriptor_t received_fd; + memcpy (&received_fd, CMSG_DATA(h), sizeof(received_fd)); dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: RECEIVED sd=%d", (int)received_fd); if (status >= 2 && command == COMMAND_REDIRECT) diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c index 18e64097386..1fbb415300a 100644 --- a/src/openvpn/socket.c +++ b/src/openvpn/socket.c @@ -2598,7 +2598,8 @@ setenv_sockaddr (struct env_set *es, const char *name_prefix, const struct openv if ( IN6_IS_ADDR_V4MAPPED( &addr->addr.in6.sin6_addr )) { struct in_addr ia; - ia.s_addr = *(in_addr_t *)&addr->addr.in6.sin6_addr.s6_addr[12] ; + memcpy (&ia.s_addr, &addr->addr.in6.sin6_addr.s6_addr[12], + sizeof (ia.s_addr)); openvpn_snprintf (name_buf, sizeof (name_buf), "%s_ip", name_prefix); openvpn_snprintf (buf, sizeof(buf), "%s", inet_ntoa(ia) ); } From dd6714ae0a47a9401898ccc0dd7079f58ba29901 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Sun, 13 Nov 2016 16:55:35 +0100 Subject: [PATCH 368/643] Add in_port_t check to configure.ac commit 8cac9b98d58b97 introduced using in_port_t which is not available on (all?) mingw build environments. Add configure check, falling back to uint16_t. Signed-off-by: Gert Doering Acked-by: Steffan Karger Message-Id: <20161113155535.68355-1-gert@greenie.muc.de> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13021.html Signed-off-by: Gert Doering --- configure.ac | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/configure.ac b/configure.ac index 357ba29e83d..e44f619330b 100644 --- a/configure.ac +++ b/configure.ac @@ -493,6 +493,12 @@ AC_CHECK_TYPES( [AC_DEFINE([in_addr_t], [uint32_t], [Workaround missing in_addr_t])], [[${SOCKET_INCLUDES}]] ) +AC_CHECK_TYPES( + [in_port_t], + , + [AC_DEFINE([in_port_t], [uint16_t], [Workaround missing in_port_t])], + [[${SOCKET_INCLUDES}]] +) AC_CHECK_TYPE( [struct iphdr], [AC_DEFINE([HAVE_IPHDR], [1], [struct iphdr needed for IPv6 support])], From fc30dc5f20d455242ed8489fb1a99446287ba9cb Mon Sep 17 00:00:00 2001 From: Selva Nair Date: Sat, 17 Sep 2016 00:10:38 -0400 Subject: [PATCH 369/643] Support --block-outside-dns on multiple tunnels v2: Simplify the "add sublayer" code. Currently each instance of openvpn adds WFP filters into an independent sublayer. As a block in one sublayer can over-ride a permit in another, this causes all DNS traffic to block when --block-outside-dns is used in multiple tunnels. Fix using a common sublayer for adding firewall rules (filters) from all instances of openvpn and interactive service. - The sublayer is added in a persistent session so that it could be accessed from multiple sessions. - The sublayer is identified by a fixed UUID defined in block_dns.c shared between openvpn.exe and openvpnserv.exe. - Permit filters for tun/tap interfaces are added with higher priority than filters that block all DNS traffic. This is not strictly necessary as WFP assigns higher priority to specific filters over generic ones, but it may be safer not to rely on that feature. - All filters are added in dynamic sessions as before. They get automatically removed when the process exits. The sublayer will, however, persist until reboot. Resolves Trac 718 Tested on Windows 7, 10 with/without interactive service Signed-off-by: Selva Nair Acked-by: Gert Doering Message-Id: <1474085439-28766-1-git-send-email-selva.nair@gmail.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12465.html Signed-off-by: Gert Doering --- src/openvpn/block_dns.c | 96 ++++++++++++++++++++++++++++++++--------- 1 file changed, 75 insertions(+), 21 deletions(-) diff --git a/src/openvpn/block_dns.c b/src/openvpn/block_dns.c index ee20c6812b4..1ca57ba2ab7 100644 --- a/src/openvpn/block_dns.c +++ b/src/openvpn/block_dns.c @@ -98,6 +98,18 @@ DEFINE_GUID( 0xb7, 0xf3, 0xbd, 0xa5, 0xd3, 0x28, 0x90, 0xa4 ); +/* UUID of WFP sublayer used by all instances of openvpn + 2f660d7e-6a37-11e6-a181-001e8c6e04a2 */ +DEFINE_GUID( + OPENVPN_BLOCK_OUTSIDE_DNS_SUBLAYER, + 0x2f660d7e, + 0x6a37, + 0x11e6, + 0xa1, 0x81, 0x00, 0x1e, 0x8c, 0x6e, 0x04, 0xa2 +); + +static WCHAR *FIREWALL_NAME = L"OpenVPN"; + /* * Default msg handler does nothing */ @@ -110,6 +122,39 @@ default_msg_handler (DWORD err, const char *msg) #define CHECK_ERROR(err, msg) \ if (err) { msg_handler (err, msg); goto out; } +/* + * Add a persistent sublayer with specified uuid. + */ +static DWORD +add_sublayer (GUID uuid) +{ + FWPM_SESSION0 session; + HANDLE engine = NULL; + DWORD err = 0; + FWPM_SUBLAYER0 sublayer; + + memset (&session, 0, sizeof(session)); + memset (&sublayer, 0, sizeof(sublayer)); + + err = FwpmEngineOpen0 (NULL, RPC_C_AUTHN_WINNT, NULL, &session, &engine); + if (err != ERROR_SUCCESS) + goto out; + + sublayer.subLayerKey = uuid; + sublayer.displayData.name = FIREWALL_NAME; + sublayer.displayData.description = FIREWALL_NAME; + sublayer.flags = 0; + sublayer.weight = 0x100; + + /* Add sublayer to the session */ + err = FwpmSubLayerAdd0 (engine, &sublayer, NULL); + +out: + if (engine) + FwpmEngineClose0 (engine); + return err; +} + /* * Block outgoing port 53 traffic except for * (i) adapter with the specified index @@ -135,13 +180,12 @@ add_block_dns_filters (HANDLE *engine_handle, ) { FWPM_SESSION0 session = {0}; - FWPM_SUBLAYER0 SubLayer = {0}; + FWPM_SUBLAYER0 *sublayer_ptr = NULL; NET_LUID tapluid; UINT64 filterid; FWP_BYTE_BLOB *openvpnblob = NULL; FWPM_FILTER0 Filter = {0}; FWPM_FILTER_CONDITION0 Condition[2] = {0}; - WCHAR *FIREWALL_NAME = L"OpenVPN"; DWORD err = 0; if (!msg_handler) @@ -154,22 +198,26 @@ add_block_dns_filters (HANDLE *engine_handle, err = FwpmEngineOpen0 (NULL, RPC_C_AUTHN_WINNT, NULL, &session, engine_handle); CHECK_ERROR (err, "FwpEngineOpen: open fwp session failed"); - - err = UuidCreate (&SubLayer.subLayerKey); - CHECK_ERROR (err, "UuidCreate: create sublayer key failed"); - - /* Populate packet filter layer information. */ - SubLayer.displayData.name = FIREWALL_NAME; - SubLayer.displayData.description = FIREWALL_NAME; - SubLayer.flags = 0; - SubLayer.weight = 0x100; - - /* Add sublayer to the session */ - err = FwpmSubLayerAdd0 (*engine_handle, &SubLayer, NULL); - CHECK_ERROR (err, "FwpmSubLayerAdd: add sublayer to session failed"); - msg_handler (0, "Block_DNS: WFP engine opened"); + /* Check sublayer exists and add one if it does not. */ + if (FwpmSubLayerGetByKey0 (*engine_handle, &OPENVPN_BLOCK_OUTSIDE_DNS_SUBLAYER, &sublayer_ptr) + == ERROR_SUCCESS) + { + msg_handler (0, "Block_DNS: Using existing sublayer"); + FwpmFreeMemory0 ((void **)&sublayer_ptr); + } + else + { /* Add a new sublayer -- as another process may add it in the meantime, + do not treat "already exists" as an error */ + err = add_sublayer (OPENVPN_BLOCK_OUTSIDE_DNS_SUBLAYER); + + if (err == FWP_E_ALREADY_EXISTS || err == ERROR_SUCCESS) + msg_handler (0, "Block_DNS: Added a persistent sublayer with pre-defined UUID"); + else + CHECK_ERROR (err, "add_sublayer: failed to add persistent sublayer"); + } + err = ConvertInterfaceIndexToLuid (index, &tapluid); CHECK_ERROR (err, "Convert interface index to luid failed"); @@ -177,7 +225,7 @@ add_block_dns_filters (HANDLE *engine_handle, CHECK_ERROR (err, "Get byte blob for openvpn executable name failed"); /* Prepare filter. */ - Filter.subLayerKey = SubLayer.subLayerKey; + Filter.subLayerKey = OPENVPN_BLOCK_OUTSIDE_DNS_SUBLAYER; Filter.displayData.name = FIREWALL_NAME; Filter.weight.type = FWP_UINT8; Filter.weight.uint8 = 0xF; @@ -218,15 +266,20 @@ add_block_dns_filters (HANDLE *engine_handle, err = FwpmFilterAdd0(*engine_handle, &Filter, NULL, &filterid); CHECK_ERROR (err, "Add filter to block IPv4 DNS traffic failed"); - msg_handler (0, "Block_DNS: Added block filters for all"); - /* Forth filter. Block all IPv6 DNS queries. */ Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V6; err = FwpmFilterAdd0(*engine_handle, &Filter, NULL, &filterid); CHECK_ERROR (err, "Add filter to block IPv6 DNS traffic failed"); - /* Fifth filter. Permit IPv4 DNS queries from TAP. */ + msg_handler (0, "Block_DNS: Added block filters for all interfaces"); + + /* Fifth filter. Permit IPv4 DNS queries from TAP. + * Use a non-zero weight so that the permit filters get higher priority + * over the block filter added with automatic weighting */ + + Filter.weight.type = FWP_UINT8; + Filter.weight.uint8 = 0xE; Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4; Filter.action.type = FWP_ACTION_PERMIT; Filter.numFilterConditions = 2; @@ -239,7 +292,8 @@ add_block_dns_filters (HANDLE *engine_handle, err = FwpmFilterAdd0(*engine_handle, &Filter, NULL, &filterid); CHECK_ERROR (err, "Add filter to permit IPv4 DNS traffic through TAP failed"); - /* Sixth filter. Permit IPv6 DNS queries from TAP. */ + /* Sixth filter. Permit IPv6 DNS queries from TAP. + * Use same weight as IPv4 filter */ Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V6; err = FwpmFilterAdd0(*engine_handle, &Filter, NULL, &filterid); From 9223336a88bc065348d0ce37621bbf2b1087ba0e Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sun, 13 Nov 2016 19:03:23 +0100 Subject: [PATCH 370/643] Fix builds on compilers without anonymous union support The "Don't dereference type-punned pointers" patch introduced an anonymous union, which older compilers do not support (or refuse to support when -std=c99 is defined). Add a configure check, and some wrapper defines to repair builds on those compilers. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1479060203-4472-1-git-send-email-steffan@karger.me> URL: http://www.mail-archive.com/search?l=mid&q=1479060203-4472-1-git-send-email-steffan@karger.me Signed-off-by: Gert Doering --- configure.ac | 34 ++++++++++++++++++++++++++++------ src/openvpn/mroute.h | 12 +++++++++++- 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/configure.ac b/configure.ac index e44f619330b..18c772d6235 100644 --- a/configure.ac +++ b/configure.ac @@ -390,6 +390,12 @@ AC_DEFINE_UNQUOTED([IPROUTE_PATH], ["$IPROUTE"], [Path to iproute tool]) AC_DEFINE_UNQUOTED([ROUTE_PATH], ["$ROUTE"], [Path to route tool]) AC_DEFINE_UNQUOTED([SYSTEMD_ASK_PASSWORD_PATH], ["$SYSTEMD_ASK_PASSWORD"], [Path to systemd-ask-password tool]) +# Set -std=c99 unless user already specified a -std= +case "${CFLAGS}" in + *-std=*) ;; + *) CFLAGS="${CFLAGS} -std=c99" ;; +esac + # # Libtool # @@ -553,6 +559,28 @@ AC_CHECK_DECLS( , [[${SOCKET_INCLUDES}]] ) +AC_CHECKING([anonymous union support]) +AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[ + struct mystruct { + union { + int m1; + char m2; + }; + }; + ]], + [[ + struct mystruct s; + s.m1 = 1; s.m2 = 2; + ]] + )], + [ + AC_MSG_RESULT([yes]) + AC_DEFINE([HAVE_ANONYMOUS_UNION_SUPPORT], [], [Compiler supports anonymous unions]) + ], + [AC_MSG_RESULT([no])] +) dnl We emulate signals in Windows AC_CHECK_DECLS( @@ -1148,12 +1176,6 @@ if test "${enable_pkcs11}" = "yes"; then ) fi -# Set -std=c99 unless user already specified a -std= -case "${CFLAGS}" in - *-std=*) ;; - *) CFLAGS="${CFLAGS} -std=c99" ;; -esac - if test "${enable_pedantic}" = "yes"; then enable_strict="yes" CFLAGS="${CFLAGS} -pedantic" diff --git a/src/openvpn/mroute.h b/src/openvpn/mroute.h index 5fe17e7f31e..8f7a064231f 100644 --- a/src/openvpn/mroute.h +++ b/src/openvpn/mroute.h @@ -96,7 +96,17 @@ struct mroute_addr { uint8_t prefix[12]; in_addr_t addr; /* _network order_ IPv4 address */ } v4mappedv6; - }; + } +#ifndef HAVE_ANONYMOUS_UNION_SUPPORT +/* Wrappers to support compilers that do not grok anonymous unions */ + mroute_union +#define raw_addr mroute_union.raw_addr +#define eth_addr mroute_union.eth_addr +#define v4 mroute_union.v4 +#define v6 mroute_union.v6 +#define v4mappedv6 mroute_union.v4mappedv6 +#endif + ; }; /* Double-check that struct packing works as expected */ From 11eedcd0071e7185fc3011cda4703f5cc75fe979 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Sun, 13 Nov 2016 20:36:45 +0100 Subject: [PATCH 371/643] Fix compilation on MinGW with -std=c99 commit 9223336a88bc moved the CFLAGS="-std=c99" bit in configure.ac before the "socklen_t" test, which relies on #ifdef WIN32 to decide whether to include or - which is no longer defined then, and things explode in interesting ways. Change to _WIN32, which is the "always defined on all compilers" define for this. Signed-off-by: Gert Doering Acked-by: Steffan Karger Message-Id: <20161113193645.73523-1-gert@greenie.muc.de> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13032.html Signed-off-by: Gert Doering --- m4/ax_socklen_t.m4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/m4/ax_socklen_t.m4 b/m4/ax_socklen_t.m4 index cd7cad8acf8..b420a170ed5 100644 --- a/m4/ax_socklen_t.m4 +++ b/m4/ax_socklen_t.m4 @@ -55,7 +55,7 @@ getpeername(0,0,&len); ], [[ #include -#ifdef WIN32 +#ifdef _WIN32 #include #else #include From 28c115e401636432b1da2365b8f144523d9d7c53 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Tue, 8 Nov 2016 21:18:18 +0100 Subject: [PATCH 372/643] Refactor static/tls-auth key loading Remove duplicate code, in preparation for adding --tls-crypt, which otherwise would have to duplicate this code again. This should be equivalent to the old code, except for two things: * The log lines for static key initialization change slightly, from "Static Encrypt/Decrypt" to "Incoming/Outgoing Static Key Encryption" * We also 'check and fix highly unlikely key problems' for tls-auth keys (boils down to a sanity-check for an all-zero key). Signed-off-by: Steffan Karger Acked-by: Arne Schwabe Message-Id: <1478636302-9678-2-git-send-email-steffan.karger@fox-it.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12969.html Signed-off-by: Gert Doering --- src/openvpn/crypto.c | 69 +++++++++++++++++++++----------------------- src/openvpn/crypto.h | 9 ++---- src/openvpn/init.c | 47 ++++++------------------------ 3 files changed, 45 insertions(+), 80 deletions(-) diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c index 0212450be8a..749b7da8c70 100644 --- a/src/openvpn/crypto.c +++ b/src/openvpn/crypto.c @@ -1103,48 +1103,45 @@ test_crypto (struct crypto_options *co, struct frame* frame) } void -get_tls_handshake_key (const struct key_type *key_type, - struct key_ctx_bi *ctx, - const char *key_file, - const int key_direction, - const unsigned int flags) +crypto_read_openvpn_key (const struct key_type *key_type, + struct key_ctx_bi *ctx, const char *key_file, const char *key_inline, + const int key_direction, const char *key_name, const char *opt_name) { - if (key_file) - { - struct key2 key2; - struct key_direction_state kds; - - if (flags & GHK_INLINE) - { - read_key_file (&key2, key_file, RKF_INLINE|RKF_MUST_SUCCEED); - } - else - { - read_key_file (&key2, key_file, RKF_MUST_SUCCEED); - } - - if (key2.n != 2) - { - msg (M_ERR, "Control Channel Authentication: File '%s' does not " - "have OpenVPN Static Key format. Using free-form passphrase " - "file is not supported anymore.", key_file); - } - /* handle key direction */ - key_direction_state_init (&kds, key_direction); - must_have_n_keys (key_file, "tls-auth", &key2, kds.need_keys); + struct key2 key2; + struct key_direction_state kds; + char log_prefix[128] = { 0 }; - /* initialize key in both directions */ - init_key_ctx (&ctx->encrypt, &key2.keys[kds.out_key], key_type, OPENVPN_OP_ENCRYPT, - "Outgoing Control Channel Authentication"); - init_key_ctx (&ctx->decrypt, &key2.keys[kds.in_key], key_type, OPENVPN_OP_DECRYPT, - "Incoming Control Channel Authentication"); - - CLEAR (key2); + if (key_inline) + { + read_key_file (&key2, key_inline, RKF_MUST_SUCCEED|RKF_INLINE); } else { - CLEAR (*ctx); + read_key_file (&key2, key_file, RKF_MUST_SUCCEED); + } + + if (key2.n != 2) + { + msg (M_ERR, "File '%s' does not have OpenVPN Static Key format. Using " + "free-form passphrase file is not supported anymore.", key_file); } + + /* check for and fix highly unlikely key problems */ + verify_fix_key2 (&key2, key_type, key_file); + + /* handle key direction */ + key_direction_state_init (&kds, key_direction); + must_have_n_keys (key_file, opt_name, &key2, kds.need_keys); + + /* initialize key in both directions */ + openvpn_snprintf (log_prefix, sizeof (log_prefix), "Outgoing %s", key_name); + init_key_ctx (&ctx->encrypt, &key2.keys[kds.out_key], key_type, + OPENVPN_OP_ENCRYPT, log_prefix); + openvpn_snprintf (log_prefix, sizeof (log_prefix), "Incoming %s", key_name); + init_key_ctx (&ctx->decrypt, &key2.keys[kds.in_key], key_type, + OPENVPN_OP_DECRYPT, log_prefix); + + CLEAR (key2); } /* header and footer for static key file */ diff --git a/src/openvpn/crypto.h b/src/openvpn/crypto.h index 4b90c674eb0..bc9630a7f17 100644 --- a/src/openvpn/crypto.h +++ b/src/openvpn/crypto.h @@ -465,12 +465,9 @@ void key2_print (const struct key2* k, const char* prefix0, const char* prefix1); -#define GHK_INLINE (1<<0) -void get_tls_handshake_key (const struct key_type *key_type, - struct key_ctx_bi *ctx, - const char *passphrase_file, - const int key_direction, - const unsigned int flags); +void crypto_read_openvpn_key (const struct key_type *key_type, + struct key_ctx_bi *ctx, const char *key_file, const char *key_inline, + const int key_direction, const char *key_name, const char *opt_name); /* * Inline functions diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 91c53f51bb4..1a9340ce0c6 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -2147,33 +2147,11 @@ do_init_crypto_static (struct context *c, const unsigned int flags) options->keysize, options->test_crypto, true); /* Read cipher and hmac keys from shared secret file */ - { - unsigned int rkf_flags = RKF_MUST_SUCCEED; - const char *rkf_file = options->shared_secret_file; - - if (options->shared_secret_file_inline) - { - rkf_file = options->shared_secret_file_inline; - rkf_flags |= RKF_INLINE; - } - read_key_file (&key2, rkf_file, rkf_flags); - } - - /* Check for and fix highly unlikely key problems */ - verify_fix_key2 (&key2, &c->c1.ks.key_type, - options->shared_secret_file); - - /* Initialize OpenSSL key objects */ - key_direction_state_init (&kds, options->key_direction); - must_have_n_keys (options->shared_secret_file, "secret", &key2, - kds.need_keys); - init_key_ctx (&c->c1.ks.static_key.encrypt, &key2.keys[kds.out_key], - &c->c1.ks.key_type, OPENVPN_OP_ENCRYPT, "Static Encrypt"); - init_key_ctx (&c->c1.ks.static_key.decrypt, &key2.keys[kds.in_key], - &c->c1.ks.key_type, OPENVPN_OP_DECRYPT, "Static Decrypt"); - - /* Erase the temporary copy of key */ - CLEAR (key2); + crypto_read_openvpn_key (&c->c1.ks.key_type, &c->c1.ks.static_key, + options->shared_secret_file, + options->shared_secret_file_inline, + options->key_direction, "Static Key Encryption", + "secret"); } else { @@ -2242,15 +2220,6 @@ do_init_crypto_tls_c1 (struct context *c) /* TLS handshake authentication (--tls-auth) */ if (options->tls_auth_file) { - unsigned int flags = 0; - const char *file = options->tls_auth_file; - - if (options->tls_auth_file_inline) - { - flags |= GHK_INLINE; - file = options->tls_auth_file_inline; - } - /* Initialize key_type for tls-auth with auth only */ CLEAR (c->c1.ks.tls_auth_key_type); if (!streq (options->authname, "none")) @@ -2265,8 +2234,10 @@ do_init_crypto_tls_c1 (struct context *c) "algorithm specified ('%s')", options->authname); } - get_tls_handshake_key (&c->c1.ks.tls_auth_key_type, - &c->c1.ks.tls_auth_key, file, options->key_direction, flags); + crypto_read_openvpn_key (&c->c1.ks.tls_auth_key_type, + &c->c1.ks.tls_auth_key, options->tls_auth_file, + options->tls_auth_file_inline, options->key_direction, + "Control Channel Authentication", "tls-auth"); } c->c1.ciphername = options->ciphername; From b7e51b137929e325e2ac3c14f751c3f642063cd5 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Tue, 8 Nov 2016 21:18:20 +0100 Subject: [PATCH 373/643] Add missing includes in error.h error.h depends on these, but is apparently never used by files that do not include them. When implementing the --tls-crypt unit tests, I ran into this. Signed-off-by: Steffan Karger Acked-by: David Sommerseth Acked-by: Arne Schwabe Message-Id: <1478636302-9678-4-git-send-email-steffan.karger@fox-it.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12972.html Signed-off-by: Gert Doering --- src/openvpn/error.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/openvpn/error.h b/src/openvpn/error.h index c90b36be25e..2d8fa131ff8 100644 --- a/src/openvpn/error.h +++ b/src/openvpn/error.h @@ -27,6 +27,9 @@ #include "basic.h" +#include +#include + #include /* #define ABORT_ON_ERROR */ From 698e268afb53014614f8e90ac8ff0667ce5e555d Mon Sep 17 00:00:00 2001 From: Heiko Hund Date: Fri, 28 Oct 2016 18:42:37 +0200 Subject: [PATCH 374/643] put argv_* functions into own file, add unit tests misc.c is too crowded with different things to perform any sane unit testing due to its dependencies. So, in order to re-write the #ifdef'ed tests for the argv_* family of functions into unit tests I moved them into a dedicated file. Signed-off-by: Heiko Hund Acked-by: David Sommerseth Message-Id: <1477672963-5724-2-git-send-email-heiko.hund@sophos.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12811.html Signed-off-by: Gert Doering --- configure.ac | 1 + src/openvpn/Makefile.am | 1 + src/openvpn/argv.c | 411 ++++++++++++++++++++++++ src/openvpn/argv.h | 76 +++++ src/openvpn/misc.c | 459 --------------------------- src/openvpn/misc.h | 48 +-- tests/unit_tests/Makefile.am | 2 +- tests/unit_tests/openvpn/Makefile.am | 15 + tests/unit_tests/openvpn/test_argv.c | 194 +++++++++++ 9 files changed, 700 insertions(+), 507 deletions(-) create mode 100644 src/openvpn/argv.c create mode 100644 src/openvpn/argv.h create mode 100644 tests/unit_tests/openvpn/Makefile.am create mode 100644 tests/unit_tests/openvpn/test_argv.c diff --git a/configure.ac b/configure.ac index 18c772d6235..8ea9de8a700 100644 --- a/configure.ac +++ b/configure.ac @@ -1301,6 +1301,7 @@ AC_CONFIG_FILES([ tests/unit_tests/plugins/Makefile tests/unit_tests/plugins/auth-pam/Makefile tests/unit_tests/example_test/Makefile + tests/unit_tests/openvpn/Makefile vendor/Makefile sample/Makefile doc/Makefile diff --git a/src/openvpn/Makefile.am b/src/openvpn/Makefile.am index a306726a897..12b9ebf4091 100644 --- a/src/openvpn/Makefile.am +++ b/src/openvpn/Makefile.am @@ -36,6 +36,7 @@ endif sbin_PROGRAMS = openvpn openvpn_SOURCES = \ + argv.c argv.h \ base64.c base64.h \ basic.h \ buffer.c buffer.h \ diff --git a/src/openvpn/argv.c b/src/openvpn/argv.c new file mode 100644 index 00000000000..2f2a5f504fd --- /dev/null +++ b/src/openvpn/argv.c @@ -0,0 +1,411 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single TCP/UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * + * 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 + * + * + * A printf-like function (that only recognizes a subset of standard printf + * format operators) that prints arguments to an argv list instead + * of a standard string. This is used to build up argv arrays for passing + * to execve. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#elif defined(_MSC_VER) +#include "config-msvc.h" +#endif + +#include "syshead.h" + +#include "argv.h" +#include "options.h" + +void +argv_init (struct argv *a) +{ + a->capacity = 0; + a->argc = 0; + a->argv = NULL; + a->system_str = NULL; +} + +struct argv +argv_new (void) +{ + struct argv ret; + argv_init (&ret); + return ret; +} + +void +argv_reset (struct argv *a) +{ + size_t i; + for (i = 0; i < a->argc; ++i) + free (a->argv[i]); + free (a->argv); + free (a->system_str); + argv_init (a); +} + +static void +argv_extend (struct argv *a, const size_t newcap) +{ + if (newcap > a->capacity) + { + char **newargv; + size_t i; + ALLOC_ARRAY_CLEAR (newargv, char *, newcap); + for (i = 0; i < a->argc; ++i) + newargv[i] = a->argv[i]; + free (a->argv); + a->argv = newargv; + a->capacity = newcap; + } +} + +static void +argv_grow (struct argv *a, const size_t add) +{ + const size_t newargc = a->argc + add + 1; + ASSERT (newargc > a->argc); + argv_extend (a, adjust_power_of_2 (newargc)); +} + +static void +argv_append (struct argv *a, char *str) /* str must have been malloced or be NULL */ +{ + argv_grow (a, 1); + a->argv[a->argc++] = str; +} + +static void +argv_system_str_append (struct argv *a, const char *str, const bool enquote) +{ + if (str) + { + char *newstr; + + /* compute length of new system_str */ + size_t l = strlen (str) + 1; /* space for new string plus trailing '\0' */ + if (a->system_str) + l += strlen (a->system_str) + 1; /* space for existing string + space (" ") separator */ + if (enquote) + l += 2; /* space for two quotes */ + + /* build new system_str */ + newstr = (char *) malloc (l); + newstr[0] = '\0'; + check_malloc_return (newstr); + if (a->system_str) + { + strcpy (newstr, a->system_str); + strcat (newstr, " "); + } + if (enquote) + strcat (newstr, "\""); + strcat (newstr, str); + if (enquote) + strcat (newstr, "\""); + free (a->system_str); + a->system_str = newstr; + } +} + +static char * +argv_extract_cmd_name (const char *path) +{ + char *ret = NULL; + if (path) + { + char *path_cp = string_alloc(path, NULL); /* POSIX basename() implementaions may modify its arguments */ + const char *bn = basename (path_cp); + if (bn) + { + char *dot = NULL; + ret = string_alloc (bn, NULL); + dot = strrchr (ret, '.'); + if (dot) + *dot = '\0'; + free(path_cp); + if (ret[0] == '\0') + { + free(ret); + ret = NULL; + } + } + } + return ret; +} + +const char * +argv_system_str (const struct argv *a) +{ + return a->system_str; +} + +static struct argv +argv_clone (const struct argv *a, const size_t headroom) +{ + struct argv r; + size_t i; + + argv_init (&r); + for (i = 0; i < headroom; ++i) + argv_append (&r, NULL); + if (a) + { + for (i = 0; i < a->argc; ++i) + argv_append (&r, string_alloc (a->argv[i], NULL)); + r.system_str = string_alloc (a->system_str, NULL); + } + return r; +} + +struct argv +argv_insert_head (const struct argv *a, const char *head) +{ + struct argv r; + char *s; + + r = argv_clone (a, 1); + r.argv[0] = string_alloc (head, NULL); + s = r.system_str; + r.system_str = string_alloc (head, NULL); + if (s) + { + argv_system_str_append (&r, s, false); + free (s); + } + return r; +} + +char * +argv_term (const char **f) +{ + const char *p = *f; + const char *term = NULL; + size_t termlen = 0; + + if (*p == '\0') + return NULL; + + while (true) + { + const int c = *p; + if (c == '\0') + break; + if (term) + { + if (!isspace (c)) + ++termlen; + else + break; + } + else + { + if (!isspace (c)) + { + term = p; + termlen = 1; + } + } + ++p; + } + *f = p; + + if (term) + { + char *ret; + ASSERT (termlen > 0); + ret = malloc (termlen + 1); + check_malloc_return (ret); + memcpy (ret, term, termlen); + ret[termlen] = '\0'; + return ret; + } + else + return NULL; +} + +const char * +argv_str (const struct argv *a, struct gc_arena *gc, const unsigned int flags) +{ + if (a->argv) + return print_argv ((const char **)a->argv, gc, flags); + else + return ""; +} + +void +argv_msg (const int msglev, const struct argv *a) +{ + struct gc_arena gc = gc_new (); + msg (msglev, "%s", argv_str (a, &gc, 0)); + gc_free (&gc); +} + +void +argv_msg_prefix (const int msglev, const struct argv *a, const char *prefix) +{ + struct gc_arena gc = gc_new (); + msg (msglev, "%s: %s", prefix, argv_str (a, &gc, 0)); + gc_free (&gc); +} + +void +argv_printf (struct argv *a, const char *format, ...) +{ + va_list arglist; + va_start (arglist, format); + argv_printf_arglist (a, format, 0, arglist); + va_end (arglist); + } + +void +argv_printf_cat (struct argv *a, const char *format, ...) +{ + va_list arglist; + va_start (arglist, format); + argv_printf_arglist (a, format, APA_CAT, arglist); + va_end (arglist); +} + +void +argv_printf_arglist (struct argv *a, const char *format, const unsigned int flags, va_list arglist) +{ + struct gc_arena gc = gc_new (); + char *term; + const char *f = format; + + if (!(flags & APA_CAT)) + argv_reset (a); + argv_extend (a, 1); /* ensure trailing NULL */ + + while ((term = argv_term (&f)) != NULL) + { + if (term[0] == '%') + { + if (!strcmp (term, "%s")) + { + char *s = va_arg (arglist, char *); + if (!s) + s = ""; + argv_append (a, string_alloc (s, NULL)); + argv_system_str_append (a, s, true); + } + else if (!strcmp (term, "%sc")) + { + char *s = va_arg (arglist, char *); + if (s) + { + int nparms; + char *parms[MAX_PARMS+1]; + int i; + + nparms = parse_line (s, parms, MAX_PARMS, "SCRIPT-ARGV", 0, D_ARGV_PARSE_CMD, &gc); + if (nparms) + { + for (i = 0; i < nparms; ++i) + argv_append (a, string_alloc (parms[i], NULL)); + } + else + argv_append (a, string_alloc (s, NULL)); + + argv_system_str_append (a, s, false); + } + else + { + argv_append (a, string_alloc ("", NULL)); + argv_system_str_append (a, "echo", false); + } + } + else if (!strcmp (term, "%d")) + { + char numstr[64]; + openvpn_snprintf (numstr, sizeof (numstr), "%d", va_arg (arglist, int)); + argv_append (a, string_alloc (numstr, NULL)); + argv_system_str_append (a, numstr, false); + } + else if (!strcmp (term, "%u")) + { + char numstr[64]; + openvpn_snprintf (numstr, sizeof (numstr), "%u", va_arg (arglist, unsigned int)); + argv_append (a, string_alloc (numstr, NULL)); + argv_system_str_append (a, numstr, false); + } + else if (!strcmp (term, "%s/%d")) + { + char numstr[64]; + char *s = va_arg (arglist, char *); + + if (!s) + s = ""; + + openvpn_snprintf (numstr, sizeof (numstr), "%d", va_arg (arglist, int)); + + { + const size_t len = strlen(s) + strlen(numstr) + 2; + char *combined = (char *) malloc (len); + check_malloc_return (combined); + + strcpy (combined, s); + strcat (combined, "/"); + strcat (combined, numstr); + argv_append (a, combined); + argv_system_str_append (a, combined, false); + } + } + else if (!strcmp (term, "%s%sc")) + { + char *s1 = va_arg (arglist, char *); + char *s2 = va_arg (arglist, char *); + char *combined; + char *cmd_name; + + if (!s1) s1 = ""; + if (!s2) s2 = ""; + combined = (char *) malloc (strlen(s1) + strlen(s2) + 1); + check_malloc_return (combined); + strcpy (combined, s1); + strcat (combined, s2); + argv_append (a, combined); + + cmd_name = argv_extract_cmd_name (combined); + if (cmd_name) + { + argv_system_str_append (a, cmd_name, false); + free (cmd_name); + } + } + else + ASSERT (0); + free (term); + } + else + { + argv_append (a, term); + argv_system_str_append (a, term, false); + } + } + gc_free (&gc); +} diff --git a/src/openvpn/argv.h b/src/openvpn/argv.h new file mode 100644 index 00000000000..df658a03784 --- /dev/null +++ b/src/openvpn/argv.h @@ -0,0 +1,76 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single TCP/UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * + * 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 + * + * + * A printf-like function (that only recognizes a subset of standard printf + * format operators) that prints arguments to an argv list instead + * of a standard string. This is used to build up argv arrays for passing + * to execve. + */ + +#ifndef ARGV_H +#define ARGV_H + +#include "buffer.h" + +struct argv { + size_t capacity; + size_t argc; + char **argv; + char *system_str; +}; + +void argv_init (struct argv *a); +struct argv argv_new (void); +void argv_reset (struct argv *a); +char *argv_term (const char **f); +const char *argv_str (const struct argv *a, struct gc_arena *gc, const unsigned int flags); +struct argv argv_insert_head (const struct argv *a, const char *head); +void argv_msg (const int msglev, const struct argv *a); +void argv_msg_prefix (const int msglev, const struct argv *a, const char *prefix); +const char *argv_system_str (const struct argv *a); + +#define APA_CAT (1<<0) /* concatentate onto existing struct argv list */ +void argv_printf_arglist (struct argv *a, const char *format, const unsigned int flags, va_list arglist); + +void argv_printf (struct argv *a, const char *format, ...) +#ifdef __GNUC__ +#if __USE_MINGW_ANSI_STDIO + __attribute__ ((format (gnu_printf, 2, 3))) +#else + __attribute__ ((format (__printf__, 2, 3))) +#endif +#endif + ; + +void argv_printf_cat (struct argv *a, const char *format, ...) +#ifdef __GNUC__ +#if __USE_MINGW_ANSI_STDIO + __attribute__ ((format (gnu_printf, 2, 3))) +#else + __attribute__ ((format (__printf__, 2, 3))) +#endif +#endif + ; + +#endif diff --git a/src/openvpn/misc.c b/src/openvpn/misc.c index b06d446b702..3d40f0bfe9a 100644 --- a/src/openvpn/misc.c +++ b/src/openvpn/misc.c @@ -1587,465 +1587,6 @@ adjust_power_of_2 (size_t u) return ret; } -/* - * A printf-like function (that only recognizes a subset of standard printf - * format operators) that prints arguments to an argv list instead - * of a standard string. This is used to build up argv arrays for passing - * to execve. - */ - -void -argv_init (struct argv *a) -{ - a->capacity = 0; - a->argc = 0; - a->argv = NULL; - a->system_str = NULL; -} - -struct argv -argv_new (void) -{ - struct argv ret; - argv_init (&ret); - return ret; -} - -void -argv_reset (struct argv *a) -{ - size_t i; - for (i = 0; i < a->argc; ++i) - free (a->argv[i]); - free (a->argv); - free (a->system_str); - argv_init (a); -} - -static void -argv_extend (struct argv *a, const size_t newcap) -{ - if (newcap > a->capacity) - { - char **newargv; - size_t i; - ALLOC_ARRAY_CLEAR (newargv, char *, newcap); - for (i = 0; i < a->argc; ++i) - newargv[i] = a->argv[i]; - free (a->argv); - a->argv = newargv; - a->capacity = newcap; - } -} - -static void -argv_grow (struct argv *a, const size_t add) -{ - const size_t newargc = a->argc + add + 1; - ASSERT (newargc > a->argc); - argv_extend (a, adjust_power_of_2 (newargc)); -} - -static void -argv_append (struct argv *a, char *str) /* str must have been malloced or be NULL */ -{ - argv_grow (a, 1); - a->argv[a->argc++] = str; -} - -static void -argv_system_str_append (struct argv *a, const char *str, const bool enquote) -{ - if (str) - { - char *newstr; - - /* compute length of new system_str */ - size_t l = strlen (str) + 1; /* space for new string plus trailing '\0' */ - if (a->system_str) - l += strlen (a->system_str) + 1; /* space for existing string + space (" ") separator */ - if (enquote) - l += 2; /* space for two quotes */ - - /* build new system_str */ - newstr = (char *) malloc (l); - newstr[0] = '\0'; - check_malloc_return (newstr); - if (a->system_str) - { - strcpy (newstr, a->system_str); - strcat (newstr, " "); - } - if (enquote) - strcat (newstr, "\""); - strcat (newstr, str); - if (enquote) - strcat (newstr, "\""); - free (a->system_str); - a->system_str = newstr; - } -} - -static char * -argv_extract_cmd_name (const char *path) -{ - char *ret = NULL; - if (path) - { - char *path_cp = string_alloc(path, NULL); /* POSIX basename() implementaions may modify its arguments */ - const char *bn = basename (path_cp); - if (bn) - { - char *dot = NULL; - ret = string_alloc (bn, NULL); - dot = strrchr (ret, '.'); - if (dot) - *dot = '\0'; - free(path_cp); - if (ret[0] == '\0') - { - free(ret); - ret = NULL; - } - } - } - return ret; -} - -const char * -argv_system_str (const struct argv *a) -{ - return a->system_str; -} - -struct argv -argv_clone (const struct argv *a, const size_t headroom) -{ - struct argv r; - size_t i; - - argv_init (&r); - for (i = 0; i < headroom; ++i) - argv_append (&r, NULL); - if (a) - { - for (i = 0; i < a->argc; ++i) - argv_append (&r, string_alloc (a->argv[i], NULL)); - r.system_str = string_alloc (a->system_str, NULL); - } - return r; -} - -struct argv -argv_insert_head (const struct argv *a, const char *head) -{ - struct argv r; - char *s; - - r = argv_clone (a, 1); - r.argv[0] = string_alloc (head, NULL); - s = r.system_str; - r.system_str = string_alloc (head, NULL); - if (s) - { - argv_system_str_append (&r, s, false); - free (s); - } - return r; -} - -char * -argv_term (const char **f) -{ - const char *p = *f; - const char *term = NULL; - size_t termlen = 0; - - if (*p == '\0') - return NULL; - - while (true) - { - const int c = *p; - if (c == '\0') - break; - if (term) - { - if (!isspace (c)) - ++termlen; - else - break; - } - else - { - if (!isspace (c)) - { - term = p; - termlen = 1; - } - } - ++p; - } - *f = p; - - if (term) - { - char *ret; - ASSERT (termlen > 0); - ret = malloc (termlen + 1); - check_malloc_return (ret); - memcpy (ret, term, termlen); - ret[termlen] = '\0'; - return ret; - } - else - return NULL; -} - -const char * -argv_str (const struct argv *a, struct gc_arena *gc, const unsigned int flags) -{ - if (a->argv) - return print_argv ((const char **)a->argv, gc, flags); - else - return ""; -} - -void -argv_msg (const int msglev, const struct argv *a) -{ - struct gc_arena gc = gc_new (); - msg (msglev, "%s", argv_str (a, &gc, 0)); - gc_free (&gc); -} - -void -argv_msg_prefix (const int msglev, const struct argv *a, const char *prefix) -{ - struct gc_arena gc = gc_new (); - msg (msglev, "%s: %s", prefix, argv_str (a, &gc, 0)); - gc_free (&gc); -} - -void -argv_printf (struct argv *a, const char *format, ...) -{ - va_list arglist; - va_start (arglist, format); - argv_printf_arglist (a, format, 0, arglist); - va_end (arglist); - } - -void -argv_printf_cat (struct argv *a, const char *format, ...) -{ - va_list arglist; - va_start (arglist, format); - argv_printf_arglist (a, format, APA_CAT, arglist); - va_end (arglist); -} - -void -argv_printf_arglist (struct argv *a, const char *format, const unsigned int flags, va_list arglist) -{ - struct gc_arena gc = gc_new (); - char *term; - const char *f = format; - - if (!(flags & APA_CAT)) - argv_reset (a); - argv_extend (a, 1); /* ensure trailing NULL */ - - while ((term = argv_term (&f)) != NULL) - { - if (term[0] == '%') - { - if (!strcmp (term, "%s")) - { - char *s = va_arg (arglist, char *); - if (!s) - s = ""; - argv_append (a, string_alloc (s, NULL)); - argv_system_str_append (a, s, true); - } - else if (!strcmp (term, "%sc")) - { - char *s = va_arg (arglist, char *); - if (s) - { - int nparms; - char *parms[MAX_PARMS+1]; - int i; - - nparms = parse_line (s, parms, MAX_PARMS, "SCRIPT-ARGV", 0, D_ARGV_PARSE_CMD, &gc); - if (nparms) - { - for (i = 0; i < nparms; ++i) - argv_append (a, string_alloc (parms[i], NULL)); - } - else - argv_append (a, string_alloc (s, NULL)); - - argv_system_str_append (a, s, false); - } - else - { - argv_append (a, string_alloc ("", NULL)); - argv_system_str_append (a, "echo", false); - } - } - else if (!strcmp (term, "%d")) - { - char numstr[64]; - openvpn_snprintf (numstr, sizeof (numstr), "%d", va_arg (arglist, int)); - argv_append (a, string_alloc (numstr, NULL)); - argv_system_str_append (a, numstr, false); - } - else if (!strcmp (term, "%u")) - { - char numstr[64]; - openvpn_snprintf (numstr, sizeof (numstr), "%u", va_arg (arglist, unsigned int)); - argv_append (a, string_alloc (numstr, NULL)); - argv_system_str_append (a, numstr, false); - } - else if (!strcmp (term, "%s/%d")) - { - char numstr[64]; - char *s = va_arg (arglist, char *); - - if (!s) - s = ""; - - openvpn_snprintf (numstr, sizeof (numstr), "%d", va_arg (arglist, int)); - - { - const size_t len = strlen(s) + strlen(numstr) + 2; - char *combined = (char *) malloc (len); - check_malloc_return (combined); - - strcpy (combined, s); - strcat (combined, "/"); - strcat (combined, numstr); - argv_append (a, combined); - argv_system_str_append (a, combined, false); - } - } - else if (!strcmp (term, "%s%sc")) - { - char *s1 = va_arg (arglist, char *); - char *s2 = va_arg (arglist, char *); - char *combined; - char *cmd_name; - - if (!s1) s1 = ""; - if (!s2) s2 = ""; - combined = (char *) malloc (strlen(s1) + strlen(s2) + 1); - check_malloc_return (combined); - strcpy (combined, s1); - strcat (combined, s2); - argv_append (a, combined); - - cmd_name = argv_extract_cmd_name (combined); - if (cmd_name) - { - argv_system_str_append (a, cmd_name, false); - free (cmd_name); - } - } - else - ASSERT (0); - free (term); - } - else - { - argv_append (a, term); - argv_system_str_append (a, term, false); - } - } - gc_free (&gc); -} - -#ifdef ARGV_TEST -void -argv_test (void) -{ - struct gc_arena gc = gc_new (); - const char *s; - - struct argv a; - - argv_init (&a); - argv_printf (&a, "%sc foo bar %s", "c:\\\\src\\\\test\\\\jyargs.exe", "foo bar"); - argv_msg_prefix (M_INFO, &a, "ARGV"); - msg (M_INFO, "ARGV-S: %s", argv_system_str(&a)); - /*openvpn_execve_check (&a, NULL, 0, "command failed");*/ - - argv_printf (&a, "%sc %s %s", "c:\\\\src\\\\test files\\\\batargs.bat", "foo", "bar"); - argv_msg_prefix (M_INFO, &a, "ARGV"); - msg (M_INFO, "ARGV-S: %s", argv_system_str(&a)); - /*openvpn_execve_check (&a, NULL, 0, "command failed");*/ - - argv_printf (&a, "%s%sc foo bar %s %s/%d %d %u", "/foo", "/bar.exe", "one two", "1.2.3.4", 24, -69, 96); - argv_msg_prefix (M_INFO, &a, "ARGV"); - msg (M_INFO, "ARGV-S: %s", argv_system_str(&a)); - /*openvpn_execve_check (&a, NULL, 0, "command failed");*/ - - argv_printf (&a, "this is a %s test of int %d unsigned %u", "FOO", -69, 42); - s = argv_str (&a, &gc, PA_BRACKET); - printf ("PF: %s\n", s); - printf ("PF-S: %s\n", argv_system_str(&a)); - - { - struct argv b = argv_insert_head (&a, "MARK"); - s = argv_str (&b, &gc, PA_BRACKET); - printf ("PF: %s\n", s); - printf ("PF-S: %s\n", argv_system_str(&b)); - argv_reset (&b); - } - - argv_printf (&a, "%sc foo bar %d", "\"multi term\" command following \\\"spaces", 99); - s = argv_str (&a, &gc, PA_BRACKET); - printf ("PF: %s\n", s); - printf ("PF-S: %s\n", argv_system_str(&a)); - argv_reset (&a); - - s = argv_str (&a, &gc, PA_BRACKET); - printf ("PF: %s\n", s); - printf ("PF-S: %s\n", argv_system_str(&a)); - argv_reset (&a); - - argv_printf (&a, "foo bar %d", 99); - argv_printf_cat (&a, "bar %d foo %sc", 42, "nonesuch"); - argv_printf_cat (&a, "cool %s %d u %s/%d end", "frood", 4, "hello", 7); - s = argv_str (&a, &gc, PA_BRACKET); - printf ("PF: %s\n", s); - printf ("PF-S: %s\n", argv_system_str(&a)); - argv_reset (&a); - -#if 0 - { - char line[512]; - while (fgets (line, sizeof(line), stdin) != NULL) - { - char *term; - const char *f = line; - int i = 0; - - while ((term = argv_term (&f)) != NULL) - { - printf ("[%d] '%s'\n", i, term); - ++i; - free (term); - } - } - } -#endif - - argv_reset (&a); - gc_free (&gc); -} -#endif - /* * Remove security-sensitive strings from control message * so that they will not be output to log file. diff --git a/src/openvpn/misc.h b/src/openvpn/misc.h index b69409684a8..ceda3235f62 100644 --- a/src/openvpn/misc.h +++ b/src/openvpn/misc.h @@ -25,6 +25,7 @@ #ifndef MISC_H #define MISC_H +#include "argv.h" #include "basic.h" #include "common.h" #include "integer.h" @@ -37,14 +38,6 @@ /* forward declarations */ struct plugin_list; -/* used by argv_x functions */ -struct argv { - size_t capacity; - size_t argc; - char **argv; - char *system_str; -}; - /* * Handle environmental variable lists */ @@ -325,45 +318,6 @@ extern int script_security; /* GLOBAL */ /* return the next largest power of 2 */ size_t adjust_power_of_2 (size_t u); -/* - * A printf-like function (that only recognizes a subset of standard printf - * format operators) that prints arguments to an argv list instead - * of a standard string. This is used to build up argv arrays for passing - * to execve. - */ -void argv_init (struct argv *a); -struct argv argv_new (void); -void argv_reset (struct argv *a); -char *argv_term (const char **f); -const char *argv_str (const struct argv *a, struct gc_arena *gc, const unsigned int flags); -struct argv argv_insert_head (const struct argv *a, const char *head); -void argv_msg (const int msglev, const struct argv *a); -void argv_msg_prefix (const int msglev, const struct argv *a, const char *prefix); -const char *argv_system_str (const struct argv *a); - -#define APA_CAT (1<<0) /* concatentate onto existing struct argv list */ -void argv_printf_arglist (struct argv *a, const char *format, const unsigned int flags, va_list arglist); - -void argv_printf (struct argv *a, const char *format, ...) -#ifdef __GNUC__ -#if __USE_MINGW_ANSI_STDIO - __attribute__ ((format (gnu_printf, 2, 3))) -#else - __attribute__ ((format (__printf__, 2, 3))) -#endif -#endif - ; - -void argv_printf_cat (struct argv *a, const char *format, ...) -#ifdef __GNUC__ -#if __USE_MINGW_ANSI_STDIO - __attribute__ ((format (gnu_printf, 2, 3))) -#else - __attribute__ ((format (__printf__, 2, 3))) -#endif -#endif - ; - #define COMPAT_FLAG_QUERY 0 /** compat_flags operator: Query for a flag */ #define COMPAT_FLAG_SET (1<<0) /** compat_flags operator: Set a compat flag */ #define COMPAT_NAMES (1<<1) /** compat flag: --compat-names set */ diff --git a/tests/unit_tests/Makefile.am b/tests/unit_tests/Makefile.am index 8868c1cb4f6..44ab26bd82d 100644 --- a/tests/unit_tests/Makefile.am +++ b/tests/unit_tests/Makefile.am @@ -1,5 +1,5 @@ AUTOMAKE_OPTIONS = foreign if CMOCKA_INITIALIZED -SUBDIRS = example_test plugins +SUBDIRS = example_test plugins openvpn endif diff --git a/tests/unit_tests/openvpn/Makefile.am b/tests/unit_tests/openvpn/Makefile.am new file mode 100644 index 00000000000..af7f12f192e --- /dev/null +++ b/tests/unit_tests/openvpn/Makefile.am @@ -0,0 +1,15 @@ +AUTOMAKE_OPTIONS = foreign + +check_PROGRAMS = argv_testdriver + +TESTS = $(check_PROGRAMS) + +openvpn_srcdir = $(top_srcdir)/src/openvpn +compat_srcdir = $(top_srcdir)/src/compat + +argv_testdriver_CFLAGS = @TEST_CFLAGS@ -I$(openvpn_srcdir) -I$(compat_srcdir) +argv_testdriver_LDFLAGS = @TEST_LDFLAGS@ -L$(openvpn_srcdir) -Wl,--wrap=parse_line +argv_testdriver_SOURCES = test_argv.c \ + $(openvpn_srcdir)/platform.c \ + $(openvpn_srcdir)/buffer.c \ + $(openvpn_srcdir)/argv.c diff --git a/tests/unit_tests/openvpn/test_argv.c b/tests/unit_tests/openvpn/test_argv.c new file mode 100644 index 00000000000..f07a5fb49e8 --- /dev/null +++ b/tests/unit_tests/openvpn/test_argv.c @@ -0,0 +1,194 @@ +#include "config.h" +#include "syshead.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "argv.h" +#include "buffer.h" + +/* + * Dummy symbols that need to be defined due to them being + * referenced in #include'd header files and their includes + */ +unsigned int x_debug_level; +bool dont_mute (unsigned int flags) { return true; } +void assert_failed (const char *filename, int line, const char *condition) { exit(0); } +void out_of_memory (void) { } +void x_msg (const unsigned int flags, const char *format, ...) { } + +/* + * This is defined here to prevent #include'ing misc.h + * which makes things difficult beyond any recognition + */ +size_t +adjust_power_of_2 (size_t u) +{ + size_t ret = 1; + + while (ret < u) + { + ret <<= 1; + assert (ret > 0); + } + + return ret; +} + +/* Defines for use in the tests and the mock parse_line() */ +#define PATH1 "/s p a c e" +#define PATH2 "/foo bar/baz" +#define PARAM1 "param1" +#define PARAM2 "param two" +#define SCRIPT_CMD "\"" PATH1 PATH2 "\"" PARAM1 "\"" PARAM2 "\"" + +int +__wrap_parse_line (const char *line, char **p, const int n, const char *file, + const int line_num, int msglevel, struct gc_arena *gc) +{ + p[0] = PATH1 PATH2; + p[1] = PARAM1; + p[2] = PARAM2; + return 3; +} + +static void +argv_printf__multiple_spaces_in_format__parsed_as_one (void **state) +{ + struct argv a = argv_new (); + + argv_printf (&a, " %s %s %d ", PATH1, PATH2, 42); + assert_int_equal (a.argc, 3); + + argv_reset (&a); +} + +static void +argv_printf_cat__multiple_spaces_in_format__parsed_as_one (void **state) +{ + struct argv a = argv_new (); + + argv_printf (&a, "%s ", PATH1); + argv_printf_cat (&a, " %s %s", PATH2, PARAM1); + assert_int_equal (a.argc, 3); + + argv_reset (&a); +} + +static void +argv_printf__combined_path_with_spaces__argc_correct (void **state) +{ + struct argv a = argv_new (); + + argv_printf (&a, "%s%sc", PATH1, PATH2); + assert_int_equal (a.argc, 1); + + argv_printf (&a, "%s%sc %d", PATH1, PATH2, 42); + assert_int_equal (a.argc, 2); + + argv_printf (&a, "foo %s%sc %s x y", PATH2, PATH1, "foo"); + assert_int_equal (a.argc, 5); + + argv_reset (&a); +} + +static void +argv_printf__script_command__argc_correct (void **state) +{ + struct argv a = argv_new (); + + argv_printf (&a, "%sc", SCRIPT_CMD); + assert_int_equal (a.argc, 3); + + argv_printf (&a, "bar baz %sc %d %s", SCRIPT_CMD, 42, PATH1); + assert_int_equal (a.argc, 7); + + argv_reset (&a); +} + +static void +argv_printf_cat__used_twice__argc_correct (void **state) +{ + struct argv a = argv_new (); + + argv_printf (&a, "%s %s %s", PATH1, PATH2, PARAM1); + argv_printf_cat (&a, "%s", PARAM2); + argv_printf_cat (&a, "foo"); + assert_int_equal (a.argc, 5); + + argv_reset (&a); +} + +static void +argv_str__multiple_argv__correct_output (void **state) +{ + struct argv a = argv_new (); + struct gc_arena gc = gc_new (); + const char *output; + + argv_printf (&a, "%s%sc", PATH1, PATH2); + argv_printf_cat (&a, "%s", PARAM1); + argv_printf_cat (&a, "%s", PARAM2); + output = argv_str (&a, &gc, PA_BRACKET); + assert_string_equal (output, "[" PATH1 PATH2 "] [" PARAM1 "] [" PARAM2 "]"); + + argv_reset (&a); + gc_free (&gc); +} + +static void +argv_insert_head__empty_argv__head_only (void **state) +{ + struct argv a = argv_new (); + struct argv b; + + b = argv_insert_head (&a, PATH1); + assert_int_equal (b.argc, 1); + assert_string_equal (b.argv[0], PATH1); + argv_reset (&b); + + argv_reset (&a); +} + +static void +argv_insert_head__non_empty_argv__head_added (void **state) +{ + struct argv a = argv_new (); + struct argv b; + int i; + + argv_printf (&a, "%s", PATH2); + b = argv_insert_head (&a, PATH1); + assert_int_equal (b.argc, a.argc + 1); + for (i = 0; i < b.argc; i++) { + if (i == 0) + assert_string_equal (b.argv[i], PATH1); + else + assert_string_equal (b.argv[i], a.argv[i - 1]); + } + argv_reset (&b); + + argv_reset (&a); +} + +int +main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test (argv_printf__multiple_spaces_in_format__parsed_as_one), + cmocka_unit_test (argv_printf_cat__multiple_spaces_in_format__parsed_as_one), + cmocka_unit_test (argv_printf__combined_path_with_spaces__argc_correct), + cmocka_unit_test (argv_printf__script_command__argc_correct), + cmocka_unit_test (argv_printf_cat__used_twice__argc_correct), + cmocka_unit_test (argv_str__multiple_argv__correct_output), + cmocka_unit_test (argv_insert_head__non_empty_argv__head_added), + }; + + return cmocka_run_group_tests_name ("argv", tests, NULL, NULL); +} From aed5ef40c47c58b3b7bc624113396a26e5e2cba5 Mon Sep 17 00:00:00 2001 From: Heiko Hund Date: Fri, 28 Oct 2016 18:42:38 +0200 Subject: [PATCH 375/643] Remove unused and unecessary argv interfaces Signed-off-by: Heiko Hund Acked-by: David Sommerseth Message-Id: <1477672963-5724-3-git-send-email-heiko.hund@sophos.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12812.html Signed-off-by: Gert Doering --- src/openvpn/argv.c | 53 +++++++++++++++-------------------- src/openvpn/argv.h | 6 ---- src/openvpn/console_systemd.c | 3 +- src/openvpn/route.c | 12 +++----- src/openvpn/tun.c | 42 +++++++++------------------ 5 files changed, 41 insertions(+), 75 deletions(-) diff --git a/src/openvpn/argv.c b/src/openvpn/argv.c index 2f2a5f504fd..19ae3ed0b24 100644 --- a/src/openvpn/argv.c +++ b/src/openvpn/argv.c @@ -39,7 +39,7 @@ #include "argv.h" #include "options.h" -void +static void argv_init (struct argv *a) { a->capacity = 0; @@ -157,12 +157,6 @@ argv_extract_cmd_name (const char *path) return ret; } -const char * -argv_system_str (const struct argv *a) -{ - return a->system_str; -} - static struct argv argv_clone (const struct argv *a, const size_t headroom) { @@ -199,7 +193,7 @@ argv_insert_head (const struct argv *a, const char *head) return r; } -char * +static char * argv_term (const char **f) { const char *p = *f; @@ -272,33 +266,13 @@ argv_msg_prefix (const int msglev, const struct argv *a, const char *prefix) gc_free (&gc); } -void -argv_printf (struct argv *a, const char *format, ...) -{ - va_list arglist; - va_start (arglist, format); - argv_printf_arglist (a, format, 0, arglist); - va_end (arglist); - } - -void -argv_printf_cat (struct argv *a, const char *format, ...) -{ - va_list arglist; - va_start (arglist, format); - argv_printf_arglist (a, format, APA_CAT, arglist); - va_end (arglist); -} - -void -argv_printf_arglist (struct argv *a, const char *format, const unsigned int flags, va_list arglist) +static void +argv_printf_arglist (struct argv *a, const char *format, va_list arglist) { struct gc_arena gc = gc_new (); char *term; const char *f = format; - if (!(flags & APA_CAT)) - argv_reset (a); argv_extend (a, 1); /* ensure trailing NULL */ while ((term = argv_term (&f)) != NULL) @@ -409,3 +383,22 @@ argv_printf_arglist (struct argv *a, const char *format, const unsigned int flag } gc_free (&gc); } + +void +argv_printf (struct argv *a, const char *format, ...) +{ + va_list arglist; + argv_reset (a); + va_start (arglist, format); + argv_printf_arglist (a, format, arglist); + va_end (arglist); + } + +void +argv_printf_cat (struct argv *a, const char *format, ...) +{ + va_list arglist; + va_start (arglist, format); + argv_printf_arglist (a, format, arglist); + va_end (arglist); +} diff --git a/src/openvpn/argv.h b/src/openvpn/argv.h index df658a03784..5f8e21c51e8 100644 --- a/src/openvpn/argv.h +++ b/src/openvpn/argv.h @@ -40,18 +40,12 @@ struct argv { char *system_str; }; -void argv_init (struct argv *a); struct argv argv_new (void); void argv_reset (struct argv *a); -char *argv_term (const char **f); const char *argv_str (const struct argv *a, struct gc_arena *gc, const unsigned int flags); struct argv argv_insert_head (const struct argv *a, const char *head); void argv_msg (const int msglev, const struct argv *a); void argv_msg_prefix (const int msglev, const struct argv *a, const char *prefix); -const char *argv_system_str (const struct argv *a); - -#define APA_CAT (1<<0) /* concatentate onto existing struct argv list */ -void argv_printf_arglist (struct argv *a, const char *format, const unsigned int flags, va_list arglist); void argv_printf (struct argv *a, const char *format, ...) #ifdef __GNUC__ diff --git a/src/openvpn/console_systemd.c b/src/openvpn/console_systemd.c index 9cd7575b147..8a953c97efb 100644 --- a/src/openvpn/console_systemd.c +++ b/src/openvpn/console_systemd.c @@ -60,9 +60,8 @@ get_console_input_systemd (const char *prompt, const bool echo, char *input, con { int std_out; bool ret = false; - struct argv argv; + struct argv argv = argv_new (); - argv_init (&argv); argv_printf (&argv, SYSTEMD_ASK_PASSWORD_PATH); #ifdef SYSTEMD_NEWER_THAN_216 /* the --echo support arrived in upstream systemd 217 */ diff --git a/src/openvpn/route.c b/src/openvpn/route.c index 96d4e11e352..98bb228f715 100644 --- a/src/openvpn/route.c +++ b/src/openvpn/route.c @@ -1395,7 +1395,7 @@ add_route (struct route_ipv4 *r, const struct env_set *es) { struct gc_arena gc; - struct argv argv; + struct argv argv = argv_new (); const char *network; const char *netmask; const char *gateway; @@ -1406,7 +1406,6 @@ add_route (struct route_ipv4 *r, return; gc_init (&gc); - argv_init (&argv); network = print_in_addr_t (r->network, 0, &gc); netmask = print_in_addr_t (r->netmask, 0, &gc); @@ -1671,7 +1670,7 @@ void add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int flags, const struct env_set *es) { struct gc_arena gc; - struct argv argv; + struct argv argv = argv_new (); const char *network; const char *gateway; @@ -1693,7 +1692,6 @@ add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int fla #endif gc_init (&gc); - argv_init (&argv); route_ipv6_clear_host_bits (r6); @@ -1933,7 +1931,7 @@ delete_route (struct route_ipv4 *r, const struct env_set *es) { struct gc_arena gc; - struct argv argv; + struct argv argv = argv_new (); const char *network; const char *netmask; const char *gateway; @@ -1943,7 +1941,6 @@ delete_route (struct route_ipv4 *r, return; gc_init (&gc); - argv_init (&argv); network = print_in_addr_t (r->network, 0, &gc); netmask = print_in_addr_t (r->netmask, 0, &gc); @@ -2108,7 +2105,7 @@ void delete_route_ipv6 (const struct route_ipv6 *r6, const struct tuntap *tt, unsigned int flags, const struct env_set *es) { struct gc_arena gc; - struct argv argv; + struct argv argv = argv_new (); const char *network; const char *gateway; const char *device = tt->actual_name; @@ -2126,7 +2123,6 @@ delete_route_ipv6 (const struct route_ipv6 *r6, const struct tuntap *tt, unsigne #endif gc_init (&gc); - argv_init (&argv); network = print_in6_addr( r6->network, 0, &gc); gateway = print_in6_addr( r6->gateway, 0, &gc); diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index a312d911267..2a87e09b350 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -753,9 +753,7 @@ do_ifconfig (struct tuntap *tt, const char *ifconfig_ipv6_local = NULL; const char *ifconfig_ipv6_remote = NULL; bool do_ipv6 = false; - struct argv argv; - - argv_init (&argv); + struct argv argv = argv_new (); msg( M_DEBUG, "do_ifconfig, tt->did_ifconfig_ipv6_setup=%d", tt->did_ifconfig_ipv6_setup ); @@ -1864,9 +1862,8 @@ close_tun (struct tuntap *tt) { if (tt->type != DEV_TYPE_NULL && tt->did_ifconfig) { - struct argv argv; + struct argv argv = argv_new (); struct gc_arena gc = gc_new (); - argv_init (&argv); #ifdef ENABLE_IPROUTE if (is_tun_p2p (tt)) @@ -2149,8 +2146,7 @@ solaris_close_tun (struct tuntap *tt) /* IPv6 interfaces need to be 'manually' de-configured */ if ( tt->did_ifconfig_ipv6_setup ) { - struct argv argv; - argv_init (&argv); + struct argv argv = argv_new (); argv_printf( &argv, "%s %s inet6 unplumb", IFCONFIG_PATH, tt->actual_name ); argv_msg (M_INFO, &argv); @@ -2213,8 +2209,7 @@ static void solaris_error_close (struct tuntap *tt, const struct env_set *es, const char *actual, bool unplumb_inet6 ) { - struct argv argv; - argv_init (&argv); + struct argv argv = argv_new (); if (unplumb_inet6) { @@ -2306,12 +2301,11 @@ close_tun (struct tuntap* tt) else if (tt) { struct gc_arena gc = gc_new (); - struct argv argv; + struct argv argv = argv_new (); /* setup command, close tun dev (clears tt->actual_name!), run command */ - argv_init (&argv); argv_printf (&argv, "%s %s destroy", IFCONFIG_PATH, tt->actual_name); @@ -2392,12 +2386,11 @@ close_tun (struct tuntap *tt) else if (tt) { struct gc_arena gc = gc_new (); - struct argv argv; + struct argv argv = argv_new (); /* setup command, close tun dev (clears tt->actual_name!), run command */ - argv_init (&argv); argv_printf (&argv, "%s %s destroy", IFCONFIG_PATH, tt->actual_name); @@ -2512,12 +2505,11 @@ close_tun (struct tuntap *tt) } else if (tt) /* close and destroy */ { - struct argv argv; + struct argv argv = argv_new (); /* setup command, close tun dev (clears tt->actual_name!), run command */ - argv_init (&argv); argv_printf (&argv, "%s %s destroy", IFCONFIG_PATH, tt->actual_name); @@ -2848,8 +2840,7 @@ close_tun (struct tuntap* tt) if (tt) { struct gc_arena gc = gc_new (); - struct argv argv; - argv_init (&argv); + struct argv argv = argv_new (); if (tt->did_ifconfig_ipv6_setup ) { @@ -2899,7 +2890,6 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tu char tunname[256]; char dynamic_name[20]; const char *p; - struct argv argv; if (tt->type == DEV_TYPE_NULL) { @@ -2950,8 +2940,8 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tu /* tunnel device must be created with 'ifconfig tapN create' */ + struct argv argv = argv_new (); struct env_set *es = env_set_create (NULL); - argv_init (&argv); argv_printf (&argv, "%s %s create", IFCONFIG_PATH, dev); argv_msg (M_INFO, &argv); env_set_add( es, "ODMDIR=/etc/objrepos" ); @@ -2983,15 +2973,13 @@ void close_tun (struct tuntap* tt) { struct gc_arena gc = gc_new (); - struct argv argv; + struct argv argv = argv_new (); struct env_set *es = env_set_create (NULL); if (!tt) return; /* persistent devices need IP address unconfig, others need destroyal */ - argv_init (&argv); - if (tt->persistent_if) { argv_printf (&argv, "%s %s 0.0.0.0 down", @@ -4515,15 +4503,13 @@ netsh_command (const struct argv *a, int n, int msglevel) void ipconfig_register_dns (const struct env_set *es) { - struct argv argv; + struct argv argv = argv_new (); bool status; const char err[] = "ERROR: Windows ipconfig command failed"; msg (D_TUNTAP_INFO, "Start net commands..."); netcmd_semaphore_lock (); - argv_init (&argv); - argv_printf (&argv, "%s%sc stop dnscache", get_win_sys_path(), WIN_NET_PATH_SUFFIX); @@ -4791,8 +4777,7 @@ static void netsh_enable_dhcp (const struct tuntap_options *to, const char *actual_name) { - struct argv argv; - argv_init (&argv); + struct argv argv = argv_new (); /* example: netsh interface ip set address my-tap dhcp */ argv_printf (&argv, @@ -5558,8 +5543,7 @@ close_tun (struct tuntap *tt) else { const char *ifconfig_ipv6_local; - struct argv argv; - argv_init (&argv); + struct argv argv = argv_new (); /* remove route pointing to interface */ delete_route_connected_v6_net(tt, NULL); From d6ab1dc49e5c8018f58e7c3c9fe64f4289ccc77b Mon Sep 17 00:00:00 2001 From: Heiko Hund Date: Fri, 28 Oct 2016 18:42:39 +0200 Subject: [PATCH 376/643] remove unused system_str from struct argv Signed-off-by: Heiko Hund Acked-by: David Sommerseth Message-Id: <1477672963-5724-4-git-send-email-heiko.hund@sophos.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12813.html Signed-off-by: Gert Doering --- src/openvpn/argv.c | 86 ---------------------------------------------- src/openvpn/argv.h | 1 - 2 files changed, 87 deletions(-) diff --git a/src/openvpn/argv.c b/src/openvpn/argv.c index 19ae3ed0b24..e8bb09fe502 100644 --- a/src/openvpn/argv.c +++ b/src/openvpn/argv.c @@ -45,7 +45,6 @@ argv_init (struct argv *a) a->capacity = 0; a->argc = 0; a->argv = NULL; - a->system_str = NULL; } struct argv @@ -63,7 +62,6 @@ argv_reset (struct argv *a) for (i = 0; i < a->argc; ++i) free (a->argv[i]); free (a->argv); - free (a->system_str); argv_init (a); } @@ -98,65 +96,6 @@ argv_append (struct argv *a, char *str) /* str must have been malloced or be NUL a->argv[a->argc++] = str; } -static void -argv_system_str_append (struct argv *a, const char *str, const bool enquote) -{ - if (str) - { - char *newstr; - - /* compute length of new system_str */ - size_t l = strlen (str) + 1; /* space for new string plus trailing '\0' */ - if (a->system_str) - l += strlen (a->system_str) + 1; /* space for existing string + space (" ") separator */ - if (enquote) - l += 2; /* space for two quotes */ - - /* build new system_str */ - newstr = (char *) malloc (l); - newstr[0] = '\0'; - check_malloc_return (newstr); - if (a->system_str) - { - strcpy (newstr, a->system_str); - strcat (newstr, " "); - } - if (enquote) - strcat (newstr, "\""); - strcat (newstr, str); - if (enquote) - strcat (newstr, "\""); - free (a->system_str); - a->system_str = newstr; - } -} - -static char * -argv_extract_cmd_name (const char *path) -{ - char *ret = NULL; - if (path) - { - char *path_cp = string_alloc(path, NULL); /* POSIX basename() implementaions may modify its arguments */ - const char *bn = basename (path_cp); - if (bn) - { - char *dot = NULL; - ret = string_alloc (bn, NULL); - dot = strrchr (ret, '.'); - if (dot) - *dot = '\0'; - free(path_cp); - if (ret[0] == '\0') - { - free(ret); - ret = NULL; - } - } - } - return ret; -} - static struct argv argv_clone (const struct argv *a, const size_t headroom) { @@ -170,7 +109,6 @@ argv_clone (const struct argv *a, const size_t headroom) { for (i = 0; i < a->argc; ++i) argv_append (&r, string_alloc (a->argv[i], NULL)); - r.system_str = string_alloc (a->system_str, NULL); } return r; } @@ -179,17 +117,8 @@ struct argv argv_insert_head (const struct argv *a, const char *head) { struct argv r; - char *s; - r = argv_clone (a, 1); r.argv[0] = string_alloc (head, NULL); - s = r.system_str; - r.system_str = string_alloc (head, NULL); - if (s) - { - argv_system_str_append (&r, s, false); - free (s); - } return r; } @@ -285,7 +214,6 @@ argv_printf_arglist (struct argv *a, const char *format, va_list arglist) if (!s) s = ""; argv_append (a, string_alloc (s, NULL)); - argv_system_str_append (a, s, true); } else if (!strcmp (term, "%sc")) { @@ -304,13 +232,10 @@ argv_printf_arglist (struct argv *a, const char *format, va_list arglist) } else argv_append (a, string_alloc (s, NULL)); - - argv_system_str_append (a, s, false); } else { argv_append (a, string_alloc ("", NULL)); - argv_system_str_append (a, "echo", false); } } else if (!strcmp (term, "%d")) @@ -318,14 +243,12 @@ argv_printf_arglist (struct argv *a, const char *format, va_list arglist) char numstr[64]; openvpn_snprintf (numstr, sizeof (numstr), "%d", va_arg (arglist, int)); argv_append (a, string_alloc (numstr, NULL)); - argv_system_str_append (a, numstr, false); } else if (!strcmp (term, "%u")) { char numstr[64]; openvpn_snprintf (numstr, sizeof (numstr), "%u", va_arg (arglist, unsigned int)); argv_append (a, string_alloc (numstr, NULL)); - argv_system_str_append (a, numstr, false); } else if (!strcmp (term, "%s/%d")) { @@ -346,7 +269,6 @@ argv_printf_arglist (struct argv *a, const char *format, va_list arglist) strcat (combined, "/"); strcat (combined, numstr); argv_append (a, combined); - argv_system_str_append (a, combined, false); } } else if (!strcmp (term, "%s%sc")) @@ -363,13 +285,6 @@ argv_printf_arglist (struct argv *a, const char *format, va_list arglist) strcpy (combined, s1); strcat (combined, s2); argv_append (a, combined); - - cmd_name = argv_extract_cmd_name (combined); - if (cmd_name) - { - argv_system_str_append (a, cmd_name, false); - free (cmd_name); - } } else ASSERT (0); @@ -378,7 +293,6 @@ argv_printf_arglist (struct argv *a, const char *format, va_list arglist) else { argv_append (a, term); - argv_system_str_append (a, term, false); } } gc_free (&gc); diff --git a/src/openvpn/argv.h b/src/openvpn/argv.h index 5f8e21c51e8..c45bec82d68 100644 --- a/src/openvpn/argv.h +++ b/src/openvpn/argv.h @@ -37,7 +37,6 @@ struct argv { size_t capacity; size_t argc; char **argv; - char *system_str; }; struct argv argv_new (void); From 253609124459f8df96e059bba9c164299a32318e Mon Sep 17 00:00:00 2001 From: Heiko Hund Date: Fri, 28 Oct 2016 18:42:40 +0200 Subject: [PATCH 377/643] Factor out %sc handling from argv_printf() Move functionality to parse command strings into argv_parse_cmd(). That is a preparation for the upcoming refactoring of argv_printf(). Signed-off-by: Heiko Hund Acked-by: David Sommerseth Message-Id: <1477672963-5724-5-git-send-email-heiko.hund@sophos.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12816.html Signed-off-by: Gert Doering --- src/openvpn/argv.c | 48 +++++++++++++--------------- src/openvpn/argv.h | 1 + src/openvpn/errlevel.h | 2 +- src/openvpn/init.c | 2 +- src/openvpn/misc.c | 10 ++---- src/openvpn/multi.c | 13 +++----- src/openvpn/options.c | 2 +- src/openvpn/socket.c | 7 ++-- src/openvpn/ssl_verify.c | 6 ++-- tests/unit_tests/openvpn/test_argv.c | 18 ++++++++--- 10 files changed, 57 insertions(+), 52 deletions(-) diff --git a/src/openvpn/argv.c b/src/openvpn/argv.c index e8bb09fe502..f8287b794ca 100644 --- a/src/openvpn/argv.c +++ b/src/openvpn/argv.c @@ -198,7 +198,6 @@ argv_msg_prefix (const int msglev, const struct argv *a, const char *prefix) static void argv_printf_arglist (struct argv *a, const char *format, va_list arglist) { - struct gc_arena gc = gc_new (); char *term; const char *f = format; @@ -215,29 +214,6 @@ argv_printf_arglist (struct argv *a, const char *format, va_list arglist) s = ""; argv_append (a, string_alloc (s, NULL)); } - else if (!strcmp (term, "%sc")) - { - char *s = va_arg (arglist, char *); - if (s) - { - int nparms; - char *parms[MAX_PARMS+1]; - int i; - - nparms = parse_line (s, parms, MAX_PARMS, "SCRIPT-ARGV", 0, D_ARGV_PARSE_CMD, &gc); - if (nparms) - { - for (i = 0; i < nparms; ++i) - argv_append (a, string_alloc (parms[i], NULL)); - } - else - argv_append (a, string_alloc (s, NULL)); - } - else - { - argv_append (a, string_alloc ("", NULL)); - } - } else if (!strcmp (term, "%d")) { char numstr[64]; @@ -295,7 +271,6 @@ argv_printf_arglist (struct argv *a, const char *format, va_list arglist) argv_append (a, term); } } - gc_free (&gc); } void @@ -316,3 +291,26 @@ argv_printf_cat (struct argv *a, const char *format, ...) argv_printf_arglist (a, format, arglist); va_end (arglist); } + +void +argv_parse_cmd (struct argv *a, const char *s) +{ + int nparms; + char *parms[MAX_PARMS + 1]; + struct gc_arena gc = gc_new (); + + argv_reset (a); + argv_extend (a, 1); /* ensure trailing NULL */ + + nparms = parse_line (s, parms, MAX_PARMS, "SCRIPT-ARGV", 0, D_ARGV_PARSE_CMD, &gc); + if (nparms) + { + int i; + for (i = 0; i < nparms; ++i) + argv_append (a, string_alloc (parms[i], NULL)); + } + else + argv_append (a, string_alloc (s, NULL)); + + gc_free (&gc); +} diff --git a/src/openvpn/argv.h b/src/openvpn/argv.h index c45bec82d68..9aee641a698 100644 --- a/src/openvpn/argv.h +++ b/src/openvpn/argv.h @@ -45,6 +45,7 @@ const char *argv_str (const struct argv *a, struct gc_arena *gc, const unsigned struct argv argv_insert_head (const struct argv *a, const char *head); void argv_msg (const int msglev, const struct argv *a); void argv_msg_prefix (const int msglev, const struct argv *a, const char *prefix); +void argv_parse_cmd (struct argv *a, const char *s); void argv_printf (struct argv *a, const char *format, ...) #ifdef __GNUC__ diff --git a/src/openvpn/errlevel.h b/src/openvpn/errlevel.h index ae1f8f49768..9d56eb4984e 100644 --- a/src/openvpn/errlevel.h +++ b/src/openvpn/errlevel.h @@ -142,7 +142,7 @@ #define D_PS_PROXY_DEBUG LOGLEV(7, 70, M_DEBUG) /* port share proxy debug */ #define D_AUTO_USERID LOGLEV(7, 70, M_DEBUG) /* AUTO_USERID debugging */ #define D_TLS_KEYSELECT LOGLEV(7, 70, M_DEBUG) /* show information on key selection for data channel */ -#define D_ARGV_PARSE_CMD LOGLEV(7, 70, M_DEBUG) /* show parse_line() errors in argv_printf %sc */ +#define D_ARGV_PARSE_CMD LOGLEV(7, 70, M_DEBUG) /* show parse_line() errors in argv_parse_cmd */ #define D_CRYPTO_DEBUG LOGLEV(7, 70, M_DEBUG) /* show detailed info from crypto.c routines */ #define D_PID_DEBUG LOGLEV(7, 70, M_DEBUG) /* show packet-id debugging info */ #define D_PF_DROPPED_BCAST LOGLEV(7, 71, M_DEBUG) /* packet filter dropped a broadcast packet */ diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 1a9340ce0c6..d3cf7ab9b51 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -1350,7 +1350,7 @@ do_route (const struct options *options, { struct argv argv = argv_new (); setenv_str (es, "script_type", "route-up"); - argv_printf (&argv, "%sc", options->route_script); + argv_parse_cmd (&argv, options->route_script); openvpn_run_script (&argv, es, 0, "--route-up"); argv_reset (&argv); } diff --git a/src/openvpn/misc.c b/src/openvpn/misc.c index 3d40f0bfe9a..bc8b33cb7e1 100644 --- a/src/openvpn/misc.c +++ b/src/openvpn/misc.c @@ -120,13 +120,9 @@ run_up_down (const char *command, struct argv argv = argv_new (); ASSERT (arg); setenv_str (es, "script_type", script_type); - argv_printf (&argv, - "%sc %s %d %d %s %s %s", - command, - arg, - tun_mtu, link_mtu, - ifconfig_local, ifconfig_remote, - context); + argv_parse_cmd (&argv, command); + argv_printf_cat (&argv, "%s %d %d %s %s %s", arg, tun_mtu, link_mtu, + ifconfig_local, ifconfig_remote, context); argv_msg (M_INFO, &argv); openvpn_run_script (&argv, es, S_FATAL, "--up/--down"); argv_reset (&argv); diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index dc4cff47e07..b497f6ad6d8 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -126,10 +126,8 @@ learn_address_script (const struct multi_context *m, { struct argv argv = argv_new (); setenv_str (es, "script_type", "learn-address"); - argv_printf (&argv, "%sc %s %s", - m->top.options.learn_address_script, - op, - mroute_addr_print (addr, &gc)); + argv_parse_cmd (&argv, m->top.options.learn_address_script); + argv_printf_cat (&argv, "%s %s", op, mroute_addr_print (addr, &gc)); if (mi) argv_printf_cat (&argv, "%s", tls_common_name (mi->context.c2.tls_multi, false)); if (!openvpn_run_script (&argv, es, 0, "--learn-address")) @@ -545,7 +543,7 @@ multi_client_disconnect_script (struct multi_context *m, { struct argv argv = argv_new (); setenv_str (mi->context.c2.es, "script_type", "client-disconnect"); - argv_printf (&argv, "%sc", mi->context.options.client_disconnect_script); + argv_parse_cmd (&argv, mi->context.options.client_disconnect_script); openvpn_run_script (&argv, mi->context.c2.es, 0, "--client-disconnect"); argv_reset (&argv); } @@ -1834,9 +1832,8 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi goto script_failed; } - argv_printf (&argv, "%sc %s", - mi->context.options.client_connect_script, - dc_file); + argv_parse_cmd (&argv, mi->context.options.client_connect_script); + argv_printf_cat (&argv, "%s", dc_file); if (openvpn_run_script (&argv, mi->context.c2.es, 0, "--client-connect")) { diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 5a5e7ef5717..1b9294aff74 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -2796,7 +2796,7 @@ check_cmd_access(const char *command, const char *opt, const char *chroot) /* Extract executable path and arguments */ argv = argv_new (); - argv_printf (&argv, "%sc", command); + argv_parse_cmd (&argv, command); /* if an executable is specified then check it; otherwise, complain */ if (argv.argv[0]) diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c index 1fbb415300a..a9aaa2a267a 100644 --- a/src/openvpn/socket.c +++ b/src/openvpn/socket.c @@ -2023,9 +2023,10 @@ ipchange_fmt (const bool include_cmd, struct argv *argv, const struct link_socke { const char *host = print_sockaddr_ex (&info->lsa->actual.dest.addr.sa, " ", PS_SHOW_PORT , gc); if (include_cmd) - argv_printf (argv, "%sc %s", - info->ipchange_command, - host); + { + argv_parse_cmd (argv, info->ipchange_command); + argv_printf_cat (argv, "%s", host); + } else argv_printf (argv, "%s", host); diff --git a/src/openvpn/ssl_verify.c b/src/openvpn/ssl_verify.c index 99a2f70ec9d..0b45972320c 100644 --- a/src/openvpn/ssl_verify.c +++ b/src/openvpn/ssl_verify.c @@ -516,7 +516,8 @@ verify_cert_call_command(const char *verify_command, struct env_set *es, } } - argv_printf (&argv, "%sc %d %s", verify_command, cert_depth, subject); + argv_parse_cmd (&argv, verify_command); + argv_printf_cat (&argv, "%d %s", cert_depth, subject); argv_msg_prefix (D_TLS_DEBUG, &argv, "TLS: executing verify command"); ret = openvpn_run_script (&argv, es, 0, "--tls-verify script"); @@ -983,7 +984,8 @@ verify_user_pass_script (struct tls_session *session, const struct user_pass *up setenv_untrusted (session); /* format command line */ - argv_printf (&argv, "%sc %s", session->opt->auth_user_pass_verify_script, tmp_file); + argv_parse_cmd (&argv, session->opt->auth_user_pass_verify_script); + argv_printf_cat (&argv, "%s", tmp_file); /* call command */ ret = openvpn_run_script (&argv, session->opt->es, 0, diff --git a/tests/unit_tests/openvpn/test_argv.c b/tests/unit_tests/openvpn/test_argv.c index f07a5fb49e8..3945634b01e 100644 --- a/tests/unit_tests/openvpn/test_argv.c +++ b/tests/unit_tests/openvpn/test_argv.c @@ -99,14 +99,23 @@ argv_printf__combined_path_with_spaces__argc_correct (void **state) } static void -argv_printf__script_command__argc_correct (void **state) +argv_parse_cmd__command_string__argc_correct (void **state) { struct argv a = argv_new (); - argv_printf (&a, "%sc", SCRIPT_CMD); + argv_parse_cmd (&a, SCRIPT_CMD); assert_int_equal (a.argc, 3); - argv_printf (&a, "bar baz %sc %d %s", SCRIPT_CMD, 42, PATH1); + argv_reset (&a); +} + +static void +argv_parse_cmd__command_and_extra_options__argc_correct (void **state) +{ + struct argv a = argv_new (); + + argv_parse_cmd (&a, SCRIPT_CMD); + argv_printf_cat (&a, "bar baz %d %s", 42, PATH1); assert_int_equal (a.argc, 7); argv_reset (&a); @@ -184,7 +193,8 @@ main(void) cmocka_unit_test (argv_printf__multiple_spaces_in_format__parsed_as_one), cmocka_unit_test (argv_printf_cat__multiple_spaces_in_format__parsed_as_one), cmocka_unit_test (argv_printf__combined_path_with_spaces__argc_correct), - cmocka_unit_test (argv_printf__script_command__argc_correct), + cmocka_unit_test (argv_parse_cmd__command_string__argc_correct), + cmocka_unit_test (argv_parse_cmd__command_and_extra_options__argc_correct), cmocka_unit_test (argv_printf_cat__used_twice__argc_correct), cmocka_unit_test (argv_str__multiple_argv__correct_output), cmocka_unit_test (argv_insert_head__non_empty_argv__head_added), From ac42df1a2e53e84c67397989df3f0650bed3ae7a Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Mon, 14 Nov 2016 20:43:23 +0100 Subject: [PATCH 378/643] Make argv unit tests obey {MBEDTLS, OPENSSL}_{LIBS, CFLAGS} Fixes builds that use MBEDTLS_CFLAGS and friends to tell the build where the header files and libraries are. Also alphabetically orders some of the listed files in relates Makefile.am files. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1479152603-5103-1-git-send-email-steffan@karger.me> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13050.html Signed-off-by: Gert Doering --- configure.ac | 4 ++-- tests/unit_tests/Makefile.am | 2 +- tests/unit_tests/openvpn/Makefile.am | 6 ++++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index 8ea9de8a700..4a45f057cad 100644 --- a/configure.ac +++ b/configure.ac @@ -1298,10 +1298,10 @@ AC_CONFIG_FILES([ src/plugins/down-root/Makefile tests/Makefile tests/unit_tests/Makefile - tests/unit_tests/plugins/Makefile - tests/unit_tests/plugins/auth-pam/Makefile tests/unit_tests/example_test/Makefile tests/unit_tests/openvpn/Makefile + tests/unit_tests/plugins/Makefile + tests/unit_tests/plugins/auth-pam/Makefile vendor/Makefile sample/Makefile doc/Makefile diff --git a/tests/unit_tests/Makefile.am b/tests/unit_tests/Makefile.am index 44ab26bd82d..31d37b891b2 100644 --- a/tests/unit_tests/Makefile.am +++ b/tests/unit_tests/Makefile.am @@ -1,5 +1,5 @@ AUTOMAKE_OPTIONS = foreign if CMOCKA_INITIALIZED -SUBDIRS = example_test plugins openvpn +SUBDIRS = example_test openvpn plugins endif diff --git a/tests/unit_tests/openvpn/Makefile.am b/tests/unit_tests/openvpn/Makefile.am index af7f12f192e..b706faed02c 100644 --- a/tests/unit_tests/openvpn/Makefile.am +++ b/tests/unit_tests/openvpn/Makefile.am @@ -7,8 +7,10 @@ TESTS = $(check_PROGRAMS) openvpn_srcdir = $(top_srcdir)/src/openvpn compat_srcdir = $(top_srcdir)/src/compat -argv_testdriver_CFLAGS = @TEST_CFLAGS@ -I$(openvpn_srcdir) -I$(compat_srcdir) -argv_testdriver_LDFLAGS = @TEST_LDFLAGS@ -L$(openvpn_srcdir) -Wl,--wrap=parse_line +argv_testdriver_CFLAGS = @TEST_CFLAGS@ -I$(openvpn_srcdir) -I$(compat_srcdir) \ + $(OPTIONAL_CRYPTO_CFLAGS) +argv_testdriver_LDFLAGS = @TEST_LDFLAGS@ -L$(openvpn_srcdir) -Wl,--wrap=parse_line \ + $(OPTIONAL_CRYPTO_LIBS) argv_testdriver_SOURCES = test_argv.c \ $(openvpn_srcdir)/platform.c \ $(openvpn_srcdir)/buffer.c \ From 825e2ec1f358f2e81b623f2770fbbf76748b0739 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sun, 13 Nov 2016 15:02:31 +0100 Subject: [PATCH 379/643] Move private file access checks to options_postprocess_filechecks() This removes the dependency of crypto.c on misc.c, which makes testing (stuff that needs) crypto.c functionality easier. Apart from that, testing file access really belongs in options_postprocess_filechecks(), and moving it there enables us to perform the same check for other private files too. v2: change indenting, remove remaining warn_if_group_others_accessible() calls and move function to options.c. [ DS: This patch is a slightly modified version of the one sent to the mailing list. It removes all references to --tls-crypt, so it can be applied eariler to the tree as it contains a good clean-up as well ] Signed-off-by: Steffan Karger Acked-by: David Sommerseth Message-Id: <1479045751-22297-1-git-send-email-steffan.karger@fox-it.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13019.html Signed-off-by: David Sommerseth --- src/openvpn/crypto.c | 5 +--- src/openvpn/misc.c | 27 ------------------- src/openvpn/misc.h | 3 --- src/openvpn/options.c | 57 ++++++++++++++++++++++++++++++--------- src/openvpn/ssl_mbedtls.c | 2 -- src/openvpn/ssl_openssl.c | 2 -- 6 files changed, 46 insertions(+), 50 deletions(-) diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c index 749b7da8c70..8b2f460e3ac 100644 --- a/src/openvpn/crypto.c +++ b/src/openvpn/crypto.c @@ -36,7 +36,7 @@ #include "crypto.h" #include "error.h" #include "integer.h" -#include "misc.h" +#include "platform.h" #include "memdbg.h" @@ -1320,9 +1320,6 @@ read_key_file (struct key2 *key2, const char *file, const unsigned int flags) if (!(flags & RKF_INLINE)) buf_clear (&in); - if (key2->n) - warn_if_group_others_accessible (error_filename); - #if 0 /* DEBUGGING */ { diff --git a/src/openvpn/misc.c b/src/openvpn/misc.c index bc8b33cb7e1..fdee663581d 100644 --- a/src/openvpn/misc.c +++ b/src/openvpn/misc.c @@ -189,31 +189,6 @@ save_inetd_socket_descriptor (void) #endif } -/* - * Warn if a given file is group/others accessible. - */ -void -warn_if_group_others_accessible (const char* filename) -{ -#ifndef WIN32 -#ifdef HAVE_STAT - if (strcmp (filename, INLINE_FILE_TAG)) - { - struct stat st; - if (stat (filename, &st)) - { - msg (M_WARN | M_ERRNO, "WARNING: cannot stat file '%s'", filename); - } - else - { - if (st.st_mode & (S_IRWXG|S_IRWXO)) - msg (M_WARN, "WARNING: file '%s' is group or others accessible", filename); - } - } -#endif -#endif -} - /* * Print an error message based on the status code returned by system(). */ @@ -1111,8 +1086,6 @@ get_user_pass_cr (struct user_pass *up, FILE *fp; char password_buf[USER_PASS_LEN] = { '\0' }; - warn_if_group_others_accessible (auth_file); - fp = platform_fopen (auth_file, "r"); if (!fp) msg (M_ERR, "Error opening '%s' auth file: %s", prefix, auth_file); diff --git a/src/openvpn/misc.h b/src/openvpn/misc.h index ceda3235f62..cc0a474dd16 100644 --- a/src/openvpn/misc.h +++ b/src/openvpn/misc.h @@ -71,9 +71,6 @@ void run_up_down (const char *command, void write_pid (const char *filename); -/* check file protections */ -void warn_if_group_others_accessible(const char* filename); - /* system flags */ #define S_SCRIPT (1<<0) #define S_FATAL (1<<1) diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 1b9294aff74..32826f509ec 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -2676,11 +2676,37 @@ options_postprocess_mutate (struct options *o) */ #ifndef ENABLE_SMALL /** Expect people using the stripped down version to know what they do */ +/* + * Warn if a given file is group/others accessible. + */ +static void +warn_if_group_others_accessible (const char* filename) +{ +#ifndef WIN32 +#ifdef HAVE_STAT + if (strcmp (filename, INLINE_FILE_TAG)) + { + struct stat st; + if (stat (filename, &st)) + { + msg (M_WARN | M_ERRNO, "WARNING: cannot stat file '%s'", filename); + } + else + { + if (st.st_mode & (S_IRWXG|S_IRWXO)) + msg (M_WARN, "WARNING: file '%s' is group or others accessible", filename); + } + } +#endif +#endif +} + #define CHKACC_FILE (1<<0) /** Check for a file/directory precense */ #define CHKACC_DIRPATH (1<<1) /** Check for directory precense where a file should reside */ #define CHKACC_FILEXSTWR (1<<2) /** If file exists, is it writable? */ #define CHKACC_INLINE (1<<3) /** File is present if it's an inline file */ #define CHKACC_ACPTSTDIN (1<<4) /** If filename is stdin, it's allowed and "exists" */ +#define CHKACC_PRIVATE (1<<5) /** Warn if this (private) file is group/others accessible */ static bool check_file_access(const int type, const char *file, const int mode, const char *opt) @@ -2721,6 +2747,11 @@ check_file_access(const int type, const char *file, const int mode, const char * if (platform_access (file, W_OK) != 0) errcode = errno; + if (type & CHKACC_PRIVATE) + { + warn_if_group_others_accessible (file); + } + /* Scream if an error is found */ if( errcode > 0 ) msg (M_NOPREFIX|M_OPTERR, "%s fails with '%s': %s", @@ -2837,10 +2868,12 @@ options_postprocess_filechecks (struct options *options) #ifdef MANAGMENT_EXTERNAL_KEY if(!(options->management_flags & MF_EXTERNAL_KEY)) #endif - errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE, options->priv_key_file, R_OK, - "--key"); - errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE, options->pkcs12_file, R_OK, - "--pkcs12"); + { + errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE|CHKACC_PRIVATE, + options->priv_key_file, R_OK, "--key"); + } + errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE|CHKACC_PRIVATE, + options->pkcs12_file, R_OK, "--pkcs12"); if (options->ssl_flags & SSLF_CRL_VERIFY_DIR) errs |= check_file_access_chroot (options->chroot_dir, CHKACC_FILE, options->crl_file, R_OK|X_OK, @@ -2849,24 +2882,24 @@ options_postprocess_filechecks (struct options *options) errs |= check_file_access_chroot (options->chroot_dir, CHKACC_FILE|CHKACC_INLINE, options->crl_file, R_OK, "--crl-verify"); - errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE, options->tls_auth_file, R_OK, - "--tls-auth"); - errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE, options->shared_secret_file, R_OK, - "--secret"); + errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE|CHKACC_PRIVATE, + options->tls_auth_file, R_OK, "--tls-auth"); + errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE|CHKACC_PRIVATE, + options->shared_secret_file, R_OK, "--secret"); errs |= check_file_access (CHKACC_DIRPATH|CHKACC_FILEXSTWR, - options->packet_id_file, R_OK|W_OK, "--replay-persist"); + options->packet_id_file, R_OK|W_OK, "--replay-persist"); /* ** Password files ** */ - errs |= check_file_access (CHKACC_FILE|CHKACC_ACPTSTDIN, + errs |= check_file_access (CHKACC_FILE|CHKACC_ACPTSTDIN|CHKACC_PRIVATE, options->key_pass_file, R_OK, "--askpass"); #endif /* ENABLE_CRYPTO */ #ifdef ENABLE_MANAGEMENT - errs |= check_file_access (CHKACC_FILE|CHKACC_ACPTSTDIN, + errs |= check_file_access (CHKACC_FILE|CHKACC_ACPTSTDIN|CHKACC_PRIVATE, options->management_user_pass, R_OK, "--management user/password file"); #endif /* ENABLE_MANAGEMENT */ #if P2MP - errs |= check_file_access (CHKACC_FILE|CHKACC_ACPTSTDIN, + errs |= check_file_access (CHKACC_FILE|CHKACC_ACPTSTDIN|CHKACC_PRIVATE, options->auth_user_pass_file, R_OK, "--auth-user-pass"); #endif /* P2MP */ diff --git a/src/openvpn/ssl_mbedtls.c b/src/openvpn/ssl_mbedtls.c index a6c90b1f1cc..c2aff405a92 100644 --- a/src/openvpn/ssl_mbedtls.c +++ b/src/openvpn/ssl_mbedtls.c @@ -361,8 +361,6 @@ tls_ctx_load_priv_file (struct tls_root_ctx *ctx, const char *priv_key_file, return 1; } - warn_if_group_others_accessible (priv_key_file); - if (!mbed_ok(mbedtls_pk_check_pair(&ctx->crt_chain->pk, ctx->priv_key))) { msg (M_WARN, "Private key does not match the certificate"); diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c index 8909ca3b864..171cd02a6eb 100644 --- a/src/openvpn/ssl_openssl.c +++ b/src/openvpn/ssl_openssl.c @@ -582,7 +582,6 @@ tls_ctx_load_pkcs12(struct tls_root_ctx *ctx, const char *pkcs12_file, /* Load Private Key */ if (!SSL_CTX_use_PrivateKey (ctx->ctx, pkey)) crypto_msg (M_FATAL, "Cannot use private key"); - warn_if_group_others_accessible (pkcs12_file); /* Check Private Key */ if (!SSL_CTX_check_private_key (ctx->ctx)) @@ -758,7 +757,6 @@ tls_ctx_load_priv_file (struct tls_root_ctx *ctx, const char *priv_key_file, crypto_msg (M_WARN, "Cannot load private key file %s", priv_key_file); goto end; } - warn_if_group_others_accessible (priv_key_file); /* Check Private Key */ if (!SSL_CTX_check_private_key (ssl_ctx)) From 1ce0638627eb35631af9bfaa569468573568ec65 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Mon, 14 Nov 2016 21:06:07 +0100 Subject: [PATCH 380/643] Deprecate key-method 1 Key method 2 has been the default since OpenVPN 2.0, and is both more functional and secure. Also, key method 1 was only ever supported for peer-to-peer connections (i.e. not for client-server). Let's get rid of some legacy and phase out key method 1. v2: add Changes.rst entry, and update man page [ DS: Slightly modified patch, rewored the warning message and the Changes.rst note to encourage not to set --key-method at all ] Signed-off-by: Steffan Karger Acked-by: David Sommerseth Message-Id: <1479153967-6788-1-git-send-email-steffan@karger.me> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13054.html Signed-off-by: David Sommerseth --- Changes.rst | 9 +++++++++ doc/openvpn.8 | 5 ++++- src/openvpn/options.c | 7 +++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/Changes.rst b/Changes.rst index c0f14a18a3c..2b99a1d0df7 100644 --- a/Changes.rst +++ b/Changes.rst @@ -112,6 +112,15 @@ AIX platform support devices since AIX does not provide tun interface. +Deprecated features +------------------- +- ``--key-method 1`` is deprecated in 2.4 and will be removed in 2.5. Migrate + away from ``--key-method 1`` as soon as possible. The recommended approach + is to remove the ``--key-method`` option from the configuration files, OpenVPN + will then use ``--key-method 2`` by default. Note that this requires changing + the option in both the client and server side configs. + + User-visible Changes -------------------- - For certificate DNs with duplicate fields, e.g. "OU=one,OU=two", both fields diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 863dcf94009..7227d224606 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -4782,7 +4782,10 @@ exchanged over the TLS session. In method 1 (the default for OpenVPN 1.x), both sides generate random encrypt and HMAC-send keys which are forwarded to -the other host over the TLS channel. +the other host over the TLS channel. Method 1 is +.B deprecated in OpenVPN 2.4 +, and +.B will be removed in OpenVPN 2.5\fR. In method 2, (the default for OpenVPN 2.0) the client generates a random key. Both client diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 32826f509ec..4d31e4c0b7a 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -2245,6 +2245,13 @@ options_postprocess_verify_ce (const struct options *options, const struct conne "may accept clients which do not present a certificate"); } + if (options->key_method == 1) + { + msg (M_WARN, "WARNING: --key-method 1 is deprecated and will be removed " + "in OpenVPN 2.5. By default --key-method 2 will be used if not set " + "in the configuration file, which is the recommended approach."); + } + if (options->tls_server || options->tls_client) { #ifdef ENABLE_PKCS11 From 445b192a7c31187c7b5c66c8250a1886b04a2b2c Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Sun, 13 Nov 2016 20:52:28 +0100 Subject: [PATCH 381/643] Replace WIN32 by _WIN32 With c99, "WIN32" is no longer automatically defined when (cross-)building for Windows, and proper compilation relies on including , before checking the macro. "_WIN32" is the official define that is guaranteed to be defined by the compiler itself, no includes are needed. So, mechanically change all occurrances of "WIN32" to "_WIN32". While at it, get rid of unused WIN32_0_1 #define in syshead.h See also: http://nadeausoftware.com/articles/2012/01/c_c_tip_how_use_compiler_predefi ned_macros_detect_operating_system#WindowsCygwinnonPOSIXandMinGW Trac #746 v2: rebased to master, merge the console[_builtin].c changes Signed-off-by: Gert Doering Acked-by: Steffan Karger Message-Id: <20161113195228.74090-1-gert@greenie.muc.de> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13035.html Signed-off-by: Gert Doering --- doc/doxygen/openvpn.doxyfile | 2 +- include/openvpn-plugin.h.in | 2 +- src/compat/compat-gettimeofday.c | 4 +-- src/compat/compat-inet_ntop.c | 2 +- src/compat/compat-inet_pton.c | 2 +- src/openvpn/block_dns.c | 2 +- src/openvpn/block_dns.h | 2 +- src/openvpn/common.h | 2 +- src/openvpn/console_builtin.c | 6 ++--- src/openvpn/cryptoapi.c | 2 +- src/openvpn/error.c | 10 ++++---- src/openvpn/error.h | 6 ++--- src/openvpn/event.c | 8 +++--- src/openvpn/event.h | 4 +-- src/openvpn/fdmisc.c | 4 +-- src/openvpn/fdmisc.h | 2 +- src/openvpn/forward.c | 4 +-- src/openvpn/init.c | 36 +++++++++++++-------------- src/openvpn/manage.c | 18 +++++++------- src/openvpn/manage.h | 2 +- src/openvpn/misc.c | 14 +++++------ src/openvpn/misc.h | 2 +- src/openvpn/openvpn.c | 8 +++--- src/openvpn/options.c | 42 ++++++++++++++++---------------- src/openvpn/options.h | 6 ++--- src/openvpn/otime.h | 8 +++--- src/openvpn/platform.c | 20 +++++++-------- src/openvpn/platform.h | 2 +- src/openvpn/plugin.c | 8 +++--- src/openvpn/plugin.h | 2 +- src/openvpn/route.c | 26 ++++++++++---------- src/openvpn/route.h | 10 ++++---- src/openvpn/sig.c | 8 +++--- src/openvpn/sig.h | 2 +- src/openvpn/socket.c | 40 +++++++++++++++--------------- src/openvpn/socket.h | 18 +++++++------- src/openvpn/ssl.c | 4 +-- src/openvpn/ssl_backend.h | 2 +- src/openvpn/ssl_mbedtls.c | 2 +- src/openvpn/ssl_openssl.c | 2 +- src/openvpn/syshead.h | 26 ++++++-------------- src/openvpn/tun.c | 24 +++++++++--------- src/openvpn/tun.h | 18 +++++++------- src/openvpn/win32.c | 2 +- src/openvpn/win32.h | 2 +- 45 files changed, 204 insertions(+), 214 deletions(-) diff --git a/doc/doxygen/openvpn.doxyfile b/doc/doxygen/openvpn.doxyfile index 7a02028a1a3..a7d9728ead4 100644 --- a/doc/doxygen/openvpn.doxyfile +++ b/doc/doxygen/openvpn.doxyfile @@ -235,7 +235,7 @@ EXPAND_ONLY_PREDEF = NO SEARCH_INCLUDES = YES INCLUDE_PATH = INCLUDE_FILE_PATTERNS = -PREDEFINED = WIN32 NTLM USE_LZO ENABLE_FRAGMENT P2MP P2MP_SERVER ENABLE_CRYPTO ENABLE_CRYPTO_OPENSSL ENABLE_PLUGIN ENABLE_MANAGEMENT ENABLE_OCC HAVE_GETTIMEOFDAY +PREDEFINED = _WIN32 NTLM USE_LZO ENABLE_FRAGMENT P2MP P2MP_SERVER ENABLE_CRYPTO ENABLE_CRYPTO_OPENSSL ENABLE_PLUGIN ENABLE_MANAGEMENT ENABLE_OCC HAVE_GETTIMEOFDAY EXPAND_AS_DEFINED = SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- diff --git a/include/openvpn-plugin.h.in b/include/openvpn-plugin.h.in index b03a9df7db1..34ad18b42c1 100644 --- a/include/openvpn-plugin.h.in +++ b/include/openvpn-plugin.h.in @@ -154,7 +154,7 @@ typedef void *openvpn_plugin_handle_t; /* * For Windows (needs to be modified for MSVC) */ -#if defined(WIN32) && !defined(OPENVPN_PLUGIN_H) +#if defined(_WIN32) && !defined(OPENVPN_PLUGIN_H) # define OPENVPN_EXPORT __declspec(dllexport) #else # define OPENVPN_EXPORT diff --git a/src/compat/compat-gettimeofday.c b/src/compat/compat-gettimeofday.c index 0f32d5d106b..19feaae1f2e 100644 --- a/src/compat/compat-gettimeofday.c +++ b/src/compat/compat-gettimeofday.c @@ -32,7 +32,7 @@ #include "compat.h" -#ifdef WIN32 +#ifdef _WIN32 /* * NOTICE: mingw has much faster gettimeofday! * autoconf will set HAVE_GETTIMEOFDAY @@ -126,6 +126,6 @@ gettimeofday (struct timeval *tv, void *tz) return 0; } -#endif /* WIN32 */ +#endif /* _WIN32 */ #endif /* HAVE_GETTIMEOFDAY */ diff --git a/src/compat/compat-inet_ntop.c b/src/compat/compat-inet_ntop.c index 0d5214255a5..786c973c710 100644 --- a/src/compat/compat-inet_ntop.c +++ b/src/compat/compat-inet_ntop.c @@ -32,7 +32,7 @@ #include "compat.h" -#ifdef WIN32 +#ifdef _WIN32 #include diff --git a/src/compat/compat-inet_pton.c b/src/compat/compat-inet_pton.c index cdc8d4b073b..5965f0d6c5f 100644 --- a/src/compat/compat-inet_pton.c +++ b/src/compat/compat-inet_pton.c @@ -32,7 +32,7 @@ #include "compat.h" -#ifdef WIN32 +#ifdef _WIN32 #include #include diff --git a/src/openvpn/block_dns.c b/src/openvpn/block_dns.c index 1ca57ba2ab7..cb3ce88e2b7 100644 --- a/src/openvpn/block_dns.c +++ b/src/openvpn/block_dns.c @@ -35,7 +35,7 @@ #include "syshead.h" -#ifdef WIN32 +#ifdef _WIN32 #include #include diff --git a/src/openvpn/block_dns.h b/src/openvpn/block_dns.h index e94535160f3..f8b6d4fbbc9 100644 --- a/src/openvpn/block_dns.h +++ b/src/openvpn/block_dns.h @@ -22,7 +22,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifdef WIN32 +#ifdef _WIN32 #ifndef OPENVPN_BLOCK_DNS_H #define OPENVPN_BLOCK_DNS_H diff --git a/src/openvpn/common.h b/src/openvpn/common.h index 2f85bec2b70..1134101dc38 100644 --- a/src/openvpn/common.h +++ b/src/openvpn/common.h @@ -30,7 +30,7 @@ */ #ifdef USE_64_BIT_COUNTERS typedef unsigned long long int counter_type; -# ifdef WIN32 +# ifdef _WIN32 # define counter_format "%I64u" # else # define counter_format "%llu" diff --git a/src/openvpn/console_builtin.c b/src/openvpn/console_builtin.c index 0434f604d8a..6b0211d9eb9 100644 --- a/src/openvpn/console_builtin.c +++ b/src/openvpn/console_builtin.c @@ -41,7 +41,7 @@ #include "buffer.h" #include "misc.h" -#ifdef WIN32 +#ifdef _WIN32 #include "win32.h" @@ -119,7 +119,7 @@ static bool get_console_input_win32 (const char *prompt, const bool echo, char * return false; } -#endif /* WIN32 */ +#endif /* _WIN32 */ #ifdef HAVE_GETPASS @@ -176,7 +176,7 @@ static bool get_console_input (const char *prompt, const bool echo, char *input, ASSERT (capacity > 0); input[0] = '\0'; -#if defined(WIN32) +#if defined(_WIN32) return get_console_input_win32 (prompt, echo, input, capacity); #elif defined(HAVE_GETPASS) diff --git a/src/openvpn/cryptoapi.c b/src/openvpn/cryptoapi.c index 853c07b19c0..e107bd3f761 100644 --- a/src/openvpn/cryptoapi.c +++ b/src/openvpn/cryptoapi.c @@ -465,4 +465,4 @@ int SSL_CTX_use_CryptoAPI_certificate(SSL_CTX *ssl_ctx, const char *cert_prop) #ifdef _MSC_VER /* Dummy function needed to avoid empty file compiler warning in Microsoft VC */ static void dummy (void) {} #endif -#endif /* WIN32 */ +#endif /* _WIN32 */ diff --git a/src/openvpn/error.c b/src/openvpn/error.c index bb0ab5b9203..425bc30525f 100644 --- a/src/openvpn/error.c +++ b/src/openvpn/error.c @@ -453,7 +453,7 @@ close_syslog () #endif } -#ifdef WIN32 +#ifdef _WIN32 static HANDLE orig_stderr; @@ -471,7 +471,7 @@ get_orig_stderr (void) void redirect_stdout_stderr (const char *file, bool append) { -#if defined(WIN32) +#if defined(_WIN32) if (!std_redir) { struct gc_arena gc = gc_new (); @@ -622,7 +622,7 @@ x_check_status (int status, sock->info.mtu_changed = true; } } -#elif defined(WIN32) +#elif defined(_WIN32) /* get possible driver error from TAP-Windows driver */ extended_msg = tap_win_getinfo (tt, &gc); #endif @@ -677,7 +677,7 @@ openvpn_exit (const int status) tun_abort(); -#ifdef WIN32 +#ifdef _WIN32 uninit_win32 (); #endif @@ -737,7 +737,7 @@ crash (void) } #endif -#ifdef WIN32 +#ifdef _WIN32 const char * strerror_win32 (DWORD errnum, struct gc_arena *gc) diff --git a/src/openvpn/error.h b/src/openvpn/error.h index 2d8fa131ff8..f43bc38d8a7 100644 --- a/src/openvpn/error.h +++ b/src/openvpn/error.h @@ -71,7 +71,7 @@ struct gc_arena; /* String and Error functions */ -#ifdef WIN32 +#ifdef _WIN32 # define openvpn_errno() GetLastError() # define openvpn_strerror(e, gc) strerror_win32(e, gc) const char *strerror_win32 (DWORD errnum, struct gc_arena *gc); @@ -261,7 +261,7 @@ void close_syslog (); /* log file output */ void redirect_stdout_stderr (const char *file, bool append); -#ifdef WIN32 +#ifdef _WIN32 /* get original stderr handle, even if redirected by --log/--log-append */ HANDLE get_orig_stderr (void); #endif @@ -356,7 +356,7 @@ static inline bool ignore_sys_error (const int err) { /* I/O operation pending */ -#ifdef WIN32 +#ifdef _WIN32 if (err == WSAEWOULDBLOCK || err == WSAEINVAL) return true; #else diff --git a/src/openvpn/event.c b/src/openvpn/event.c index c6426911f24..409ad13199d 100644 --- a/src/openvpn/event.c +++ b/src/openvpn/event.c @@ -49,7 +49,7 @@ /* * All non-windows OSes are assumed to have select() */ -#ifdef WIN32 +#ifdef _WIN32 #define SELECT 0 #else #define SELECT 1 @@ -74,7 +74,7 @@ tv_to_ms_timeout (const struct timeval *tv) return max_int (tv->tv_sec * 1000 + (tv->tv_usec + 500) / 1000, 1); } -#ifdef WIN32 +#ifdef _WIN32 struct we_set { @@ -462,7 +462,7 @@ we_init (int *maxevents, unsigned int flags) return (struct event_set *) wes; } -#endif /* WIN32 */ +#endif /* _WIN32 */ #if EPOLL @@ -1007,7 +1007,7 @@ static struct event_set * event_set_init_simple (int *maxevents, unsigned int flags) { struct event_set *ret = NULL; -#ifdef WIN32 +#ifdef _WIN32 ret = we_init (maxevents, flags); #elif POLL && SELECT #if 0 /* Define to 1 if EVENT_METHOD_US_TIMEOUT should cause select to be favored over poll */ diff --git a/src/openvpn/event.h b/src/openvpn/event.h index bd29fdc1b26..565343d3f30 100644 --- a/src/openvpn/event.h +++ b/src/openvpn/event.h @@ -42,7 +42,7 @@ #define EVENT_METHOD_US_TIMEOUT (1<<0) #define EVENT_METHOD_FAST (1<<1) -#ifdef WIN32 +#ifdef _WIN32 typedef const struct rw_handle *event_t; @@ -137,7 +137,7 @@ event_set_return_init (struct event_set_return *esr) esr->arg = NULL; } -#ifdef WIN32 +#ifdef _WIN32 static inline void wait_signal (struct event_set *es, void *arg) diff --git a/src/openvpn/fdmisc.c b/src/openvpn/fdmisc.c index 7fe449c5e2c..ce01319713a 100644 --- a/src/openvpn/fdmisc.c +++ b/src/openvpn/fdmisc.c @@ -39,7 +39,7 @@ bool set_nonblock_action (int fd) { -#ifdef WIN32 +#ifdef _WIN32 u_long arg = 1; if (ioctlsocket (fd, FIONBIO, &arg)) return false; @@ -54,7 +54,7 @@ set_nonblock_action (int fd) bool set_cloexec_action (int fd) { -#ifndef WIN32 +#ifndef _WIN32 if (fcntl (fd, F_SETFD, FD_CLOEXEC) < 0) return false; #endif diff --git a/src/openvpn/fdmisc.h b/src/openvpn/fdmisc.h index 13d6552d29c..d34db9bd194 100644 --- a/src/openvpn/fdmisc.h +++ b/src/openvpn/fdmisc.h @@ -37,7 +37,7 @@ void set_cloexec (int fd); static inline void openvpn_fd_set(int fd, fd_set *setp) { -#ifndef WIN32 /* The Windows FD_SET() implementation does not overflow */ +#ifndef _WIN32 /* The Windows FD_SET() implementation does not overflow */ ASSERT (fd >= 0 && fd < FD_SETSIZE); #endif FD_SET (fd, setp); diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c index 3a4c26a9692..b50a2e02577 100644 --- a/src/openvpn/forward.c +++ b/src/openvpn/forward.c @@ -301,7 +301,7 @@ check_add_routes_dowork (struct context *c) { register_signal (c, SIGHUP, "ip-fail"); c->persist.restart_sleep_seconds = 10; -#ifdef WIN32 +#ifdef _WIN32 show_routes (M_INFO|M_NOPREFIX); show_adapters (M_INFO|M_NOPREFIX); #endif @@ -1420,7 +1420,7 @@ pre_select (struct context *c) c->c2.timeval.tv_sec = BIG_TIMEOUT; c->c2.timeval.tv_usec = 0; -#if defined(WIN32) +#if defined(_WIN32) if (check_debug_level (D_TAP_WIN_DEBUG)) { c->c2.timeval.tv_sec = 1; diff --git a/src/openvpn/init.c b/src/openvpn/init.c index d3cf7ab9b51..eaa5e7993d4 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -577,7 +577,7 @@ init_static (void) error_reset (); /* initialize error.c */ reset_check_status (); /* initialize status check code in socket.c */ -#ifdef WIN32 +#ifdef _WIN32 init_win32 (); #endif @@ -1024,7 +1024,7 @@ format_common_name (struct context *c, struct gc_arena *gc) void pre_setup (const struct options *options) { -#ifdef WIN32 +#ifdef _WIN32 if (options->exit_event_name) { win32_signal_open (&win32_signal, @@ -1245,7 +1245,7 @@ initialization_sequence_completed (struct context *c, const unsigned int flags) /* Test if errors */ if (flags & ISC_ERRORS) { -#ifdef WIN32 +#ifdef _WIN32 show_routes (M_INFO|M_NOPREFIX); show_adapters (M_INFO|M_NOPREFIX); msg (M_INFO, "%s With Errors ( see http://openvpn.net/faq.html#dhcpclientserv )", message); @@ -1260,7 +1260,7 @@ initialization_sequence_completed (struct context *c, const unsigned int flags) if ((flags & (ISC_ERRORS|ISC_SERVER)) == 0) c->options.no_advance=true; -#ifdef WIN32 +#ifdef _WIN32 fork_register_dns_action (c->c1.tuntap); #endif @@ -1355,7 +1355,7 @@ do_route (const struct options *options, argv_reset (&argv); } -#ifdef WIN32 +#ifdef _WIN32 if (options->show_net_up) { show_routes (M_INFO|M_NOPREFIX); @@ -1421,7 +1421,7 @@ do_open_tun (struct context *c) /* initialize (but do not open) tun/tap object */ do_init_tun (c); -#ifdef WIN32 +#ifdef _WIN32 /* store (hide) interactive service handle in tuntap_options */ c->c1.tuntap->options.msg_channel = c->options.msg_channel; msg (D_ROUTE, "interactive service msg_channel=%u", (unsigned int) c->options.msg_channel); @@ -1482,7 +1482,7 @@ do_open_tun (struct context *c) c->plugins, OPENVPN_PLUGIN_UP, c->c1.tuntap->actual_name, -#ifdef WIN32 +#ifdef _WIN32 c->c1.tuntap->adapter_index, #endif dev_type_string (c->options.dev, c->options.dev_type), @@ -1495,7 +1495,7 @@ do_open_tun (struct context *c) "up", c->c2.es); -#if defined(WIN32) +#if defined(_WIN32) if (c->options.block_outside_dns) { dmsg (D_LOW, "Blocking outside DNS"); @@ -1535,7 +1535,7 @@ do_open_tun (struct context *c) c->plugins, OPENVPN_PLUGIN_UP, c->c1.tuntap->actual_name, -#ifdef WIN32 +#ifdef _WIN32 c->c1.tuntap->adapter_index, #endif dev_type_string (c->options.dev, c->options.dev_type), @@ -1547,7 +1547,7 @@ do_open_tun (struct context *c) NULL, "up", c->c2.es); -#if defined(WIN32) +#if defined(_WIN32) if (c->options.block_outside_dns) { dmsg (D_LOW, "Blocking outside DNS"); @@ -1585,7 +1585,7 @@ do_close_tun (struct context *c, bool force) if (c->c1.tuntap && c->c1.tuntap_owned) { const char *tuntap_actual = string_alloc (c->c1.tuntap->actual_name, &gc); -#ifdef WIN32 +#ifdef _WIN32 DWORD adapter_index = c->c1.tuntap->adapter_index; #endif const in_addr_t local = c->c1.tuntap->local; @@ -1611,7 +1611,7 @@ do_close_tun (struct context *c, bool force) c->plugins, OPENVPN_PLUGIN_ROUTE_PREDOWN, tuntap_actual, -#ifdef WIN32 +#ifdef _WIN32 adapter_index, #endif NULL, @@ -1639,7 +1639,7 @@ do_close_tun (struct context *c, bool force) c->plugins, OPENVPN_PLUGIN_DOWN, tuntap_actual, -#ifdef WIN32 +#ifdef _WIN32 adapter_index, #endif NULL, @@ -1653,7 +1653,7 @@ do_close_tun (struct context *c, bool force) "down", c->c2.es); -#if defined(WIN32) +#if defined(_WIN32) if (c->options.block_outside_dns) { if (!win_wfp_uninit(c->options.msg_channel)) @@ -1673,7 +1673,7 @@ do_close_tun (struct context *c, bool force) c->plugins, OPENVPN_PLUGIN_DOWN, tuntap_actual, -#ifdef WIN32 +#ifdef _WIN32 adapter_index, #endif NULL, @@ -1687,7 +1687,7 @@ do_close_tun (struct context *c, bool force) "down", c->c2.es); -#if defined(WIN32) +#if defined(_WIN32) if (c->options.block_outside_dns) { if (!win_wfp_uninit(c->options.msg_channel)) @@ -3173,7 +3173,7 @@ do_setup_fast_io (struct context *c) { if (c->options.fast_io) { -#ifdef WIN32 +#ifdef _WIN32 msg (M_INFO, "NOTE: --fast-io is disabled since we are running on Windows"); #else if (!proto_is_udp(c->options.ce.proto)) @@ -3286,7 +3286,7 @@ management_callback_status_p2p (void *arg, const int version, struct status_outp void management_show_net_callback (void *arg, const int msglevel) { -#ifdef WIN32 +#ifdef _WIN32 show_routes (msglevel); show_adapters (msglevel); msg (msglevel, "END"); diff --git a/src/openvpn/manage.c b/src/openvpn/manage.c index 26a2f7ea18e..77a80061e5d 100644 --- a/src/openvpn/manage.c +++ b/src/openvpn/manage.c @@ -270,7 +270,7 @@ man_delete_unix_socket (struct management *man) static void man_close_socket (struct management *man, const socket_descriptor_t sd) { -#ifndef WIN32 +#ifndef _WIN32 /* * Windows doesn't need this because the ne32 event is permanently * enabled at struct management scope. @@ -1413,7 +1413,7 @@ man_dispatch_command (struct management *man, struct status_output *so, const ch gc_free (&gc); } -#ifdef WIN32 +#ifdef _WIN32 static void man_start_ne32 (struct management *man) @@ -1503,7 +1503,7 @@ man_new_connection_post (struct management *man, const char *description) man_connection_settings_reset (man); -#ifdef WIN32 +#ifdef _WIN32 man_start_ne32 (man); #endif @@ -1590,7 +1590,7 @@ man_accept (struct management *man) if (socket_defined (man->connection.sd_top)) { -#ifdef WIN32 +#ifdef _WIN32 man_stop_ne32 (man); #endif } @@ -1654,7 +1654,7 @@ man_listen (struct management *man) print_sockaddr (man->settings.local->ai_addr, &gc)); } -#ifdef WIN32 +#ifdef _WIN32 man_start_ne32 (man); #endif @@ -1737,7 +1737,7 @@ man_reset_client_socket (struct management *man, const bool exiting) { if (socket_defined (man->connection.sd_cli)) { -#ifdef WIN32 +#ifdef _WIN32 man_stop_ne32 (man); #endif man_close_socket (man, man->connection.sd_cli); @@ -2254,7 +2254,7 @@ man_connection_init (struct management *man) { if (man->connection.state == MS_INITIAL) { -#ifdef WIN32 +#ifdef _WIN32 /* * This object is a sort of TCP/IP helper * for Windows. @@ -2295,7 +2295,7 @@ man_connection_close (struct management *man) if (mc->es) event_free (mc->es); -#ifdef WIN32 +#ifdef _WIN32 net_event_win32_close (&mc->ne32); #endif if (socket_defined (mc->sd_top)) @@ -2731,7 +2731,7 @@ man_persist_state (unsigned int *persistent, const int n) return true; } -#ifdef WIN32 +#ifdef _WIN32 void management_socket_set (struct management *man, diff --git a/src/openvpn/manage.h b/src/openvpn/manage.h index 50db38cd555..3ffced07a52 100644 --- a/src/openvpn/manage.h +++ b/src/openvpn/manage.h @@ -257,7 +257,7 @@ struct man_connection { socket_descriptor_t sd_cli; struct openvpn_sockaddr remote; -#ifdef WIN32 +#ifdef _WIN32 struct net_event_win32 ne32; #endif diff --git a/src/openvpn/misc.c b/src/openvpn/misc.c index fdee663581d..56d43e0a637 100644 --- a/src/openvpn/misc.c +++ b/src/openvpn/misc.c @@ -64,7 +64,7 @@ run_up_down (const char *command, const struct plugin_list *plugins, int plugin_type, const char *arg, -#ifdef WIN32 +#ifdef _WIN32 DWORD adapter_index, #endif const char *dev_type, @@ -87,7 +87,7 @@ run_up_down (const char *command, setenv_str (es, "dev", arg); if (dev_type) setenv_str (es, "dev_type", dev_type); -#ifdef WIN32 +#ifdef _WIN32 setenv_int (es, "dev_idx", adapter_index); #endif @@ -196,7 +196,7 @@ const char * system_error_message (int stat, struct gc_arena *gc) { struct buffer out = alloc_buf_gc (256, gc); -#ifdef WIN32 +#ifdef _WIN32 if (stat == -1) buf_printf (&out, "external program did not execute -- "); buf_printf (&out, "returned error code %d", stat); @@ -252,7 +252,7 @@ openvpn_execve_allowed (const unsigned int flags) } -#ifndef WIN32 +#ifndef _WIN32 /* * Run execve() inside a fork(). Designed to replicate the semantics of system() but * in a safer way that doesn't require the invocation of a shell or the risks @@ -950,7 +950,7 @@ hostname_randomize(const char *hostname, struct gc_arena *gc) const char * gen_path (const char *directory, const char *filename, struct gc_arena *gc) { -#ifdef WIN32 +#ifdef _WIN32 const int CC_PATH_RESERVED = CC_LESS_THAN|CC_GREATER_THAN|CC_COLON| CC_DOUBLE_QUOTE|CC_SLASH|CC_BACKSLASH|CC_PIPE|CC_QUESTION_MARK|CC_ASTERISK; #else @@ -961,7 +961,7 @@ gen_path (const char *directory, const char *filename, struct gc_arena *gc) if (safe_filename && strcmp (safe_filename, ".") && strcmp (safe_filename, "..") -#ifdef WIN32 +#ifdef _WIN32 && win_safe_filename (safe_filename) #endif ) @@ -989,7 +989,7 @@ absolute_pathname (const char *pathname) if (pathname) { const int c = pathname[0]; -#ifdef WIN32 +#ifdef _WIN32 return c == '\\' || (isalpha(c) && pathname[1] == ':' && pathname[2] == '\\'); #else return c == '/'; diff --git a/src/openvpn/misc.h b/src/openvpn/misc.h index cc0a474dd16..b8bbaa7fe09 100644 --- a/src/openvpn/misc.h +++ b/src/openvpn/misc.h @@ -56,7 +56,7 @@ void run_up_down (const char *command, const struct plugin_list *plugins, int plugin_type, const char *arg, -#ifdef WIN32 +#ifdef _WIN32 DWORD adapter_index, #endif const char *dev_type, diff --git a/src/openvpn/openvpn.c b/src/openvpn/openvpn.c index 823c3dd13d4..5fb2fd9cfaf 100644 --- a/src/openvpn/openvpn.c +++ b/src/openvpn/openvpn.c @@ -138,7 +138,7 @@ openvpn_main (int argc, char *argv[]) return 1; #endif -#ifdef WIN32 +#ifdef _WIN32 SetConsoleOutputCP (CP_UTF8); #endif @@ -172,7 +172,7 @@ openvpn_main (int argc, char *argv[]) /* initialize environmental variable store */ c.es = env_set_create (NULL); -#ifdef WIN32 +#ifdef _WIN32 set_win_sys_path_via_env (c.es); #endif @@ -220,7 +220,7 @@ openvpn_main (int argc, char *argv[]) /* print version number */ msg (M_INFO, "%s", title_string); -#ifdef WIN32 +#ifdef _WIN32 show_windows_version(M_INFO); #endif show_library_versions(M_INFO); @@ -312,7 +312,7 @@ openvpn_main (int argc, char *argv[]) return 0; /* NOTREACHED */ } -#ifdef WIN32 +#ifdef _WIN32 int wmain (int argc, wchar_t *wargv[]) { char **argv; diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 4d31e4c0b7a..443f96b15d9 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -592,7 +592,7 @@ static const char usage_message[] = " Default is CN in the Subject field.\n" #endif "--verify-hash : Specify SHA1 fingerprint for level-1 cert.\n" -#ifdef WIN32 +#ifdef _WIN32 "--cryptoapicert select-string : Load the certificate and private key from the\n" " Windows Certificate System Store.\n" #endif @@ -670,7 +670,7 @@ static const char usage_message[] = "--show-digests : Show message digest algorithms to use with --auth option.\n" "--show-engines : Show hardware crypto accelerator engines (if available).\n" "--show-tls : Show all TLS ciphers (TLS used only as a control channel).\n" -#ifdef WIN32 +#ifdef _WIN32 "\n" "Windows Specific:\n" "--win-sys path : Pathname of Windows system directory. Default is the pathname\n" @@ -720,7 +720,7 @@ static const char usage_message[] = " optional parameter controls the initial state of ex.\n" "--show-net-up : Show " PACKAGE_NAME "'s view of routing table and net adapter list\n" " after TAP adapter is up and routes have been added.\n" -#ifdef WIN32 +#ifdef _WIN32 "--block-outside-dns : Block DNS on other network adapters to prevent DNS leaks\n" #endif "Windows Standalone Options:\n" @@ -816,7 +816,7 @@ init_options (struct options *o, const bool init_gc) #ifdef TARGET_LINUX o->tuntap_options.txqueuelen = 100; #endif -#ifdef WIN32 +#ifdef _WIN32 #if 0 o->tuntap_options.ip_win32_type = IPW32_SET_ADAPTIVE; #else @@ -879,7 +879,7 @@ init_options (struct options *o, const bool init_gc) o->auth_token_generate = false; /* Set default --tmp-dir */ -#ifdef WIN32 +#ifdef _WIN32 /* On Windows, find temp dir via enviroment variables */ o->tmp_dir = win_get_tempdir(); #else @@ -888,7 +888,7 @@ init_options (struct options *o, const bool init_gc) if( !o->tmp_dir ) { o->tmp_dir = "/tmp"; } -#endif /* WIN32 */ +#endif /* _WIN32 */ #endif /* P2MP_SERVER */ o->allow_recursive_routing = false; } @@ -1141,7 +1141,7 @@ parse_hash_fingerprint(const char *str, int nbytes, int msglevel, struct gc_aren } #endif -#ifdef WIN32 +#ifdef _WIN32 #ifndef ENABLE_SMALL @@ -1186,7 +1186,7 @@ show_tuntap_options (const struct tuntap_options *o) #endif #endif -#if defined(WIN32) || defined(TARGET_ANDROID) +#if defined(_WIN32) || defined(TARGET_ANDROID) static void dhcp_option_address_parse (const char *name, const char *parm, in_addr_t *array, int *len, int msglevel) { @@ -1741,7 +1741,7 @@ show_settings (const struct options *o) show_p2mp_parms (o); #endif -#ifdef WIN32 +#ifdef _WIN32 SHOW_BOOL (show_net_up); SHOW_INT (route_method); SHOW_BOOL (block_outside_dns); @@ -2033,7 +2033,7 @@ options_postprocess_verify_ce (const struct options *options, const struct conne * Windows-specific options. */ -#ifdef WIN32 +#ifdef _WIN32 if (dev == DEV_TYPE_TUN && !(pull || (options->ifconfig_local && options->ifconfig_remote_netmask))) msg (M_USAGE, "On Windows, --ifconfig is required when --dev tun is used"); @@ -2512,7 +2512,7 @@ options_postprocess_mutate_ce (struct options *o, struct connection_entry *ce) static void options_postprocess_mutate_invariant (struct options *options) { -#ifdef WIN32 +#ifdef _WIN32 const int dev = dev_type_enum (options->dev, options->dev_type); #endif @@ -2523,7 +2523,7 @@ options_postprocess_mutate_invariant (struct options *options) if (options->inetd == INETD_NOWAIT) options->ifconfig_noexec = true; -#ifdef WIN32 +#ifdef _WIN32 if ((dev == DEV_TYPE_TUN || dev == DEV_TYPE_TAP) && !options->route_delay_defined) { if (options->mode == MODE_POINT_TO_POINT) @@ -2546,7 +2546,7 @@ options_postprocess_mutate_invariant (struct options *options) */ if (options->mode == MODE_SERVER) { -#ifdef WIN32 +#ifdef _WIN32 /* * We need to explicitly set --tap-sleep because * we do not schedule event timers in the top-level context. @@ -2689,7 +2689,7 @@ options_postprocess_mutate (struct options *o) static void warn_if_group_others_accessible (const char* filename) { -#ifndef WIN32 +#ifndef _WIN32 #ifdef HAVE_STAT if (strcmp (filename, INLINE_FILE_TAG)) { @@ -3608,7 +3608,7 @@ usage_small (void) openvpn_exit (OPENVPN_EXIT_STATUS_USAGE); /* exit point */ } -#ifdef WIN32 +#ifdef _WIN32 void show_windows_version(const unsigned int flags) { struct gc_arena gc = gc_new (); @@ -3642,7 +3642,7 @@ usage_version (void) { msg (M_INFO|M_NOPREFIX, "%s", title_string); show_library_versions( M_INFO|M_NOPREFIX ); -#ifdef WIN32 +#ifdef _WIN32 show_windows_version( M_INFO|M_NOPREFIX ); #endif msg (M_INFO|M_NOPREFIX, "Originally developed by James Yonan"); @@ -3689,7 +3689,7 @@ positive_atoi (const char *str) return i < 0 ? 0 : i; } -#ifdef WIN32 /* This function is only used when compiling on Windows */ +#ifdef _WIN32 /* This function is only used when compiling on Windows */ static unsigned int atou (const char *str) { @@ -6274,7 +6274,7 @@ add_option (struct options *options, #endif else if (streq (p[0], "msg-channel") && p[1]) { -#ifdef WIN32 +#ifdef _WIN32 VERIFY_PERMISSION (OPT_P_GENERAL); HANDLE process = GetCurrentProcess (); HANDLE handle = (HANDLE) atoi (p[1]); @@ -6290,7 +6290,7 @@ add_option (struct options *options, goto err; #endif } -#ifdef WIN32 +#ifdef _WIN32 else if (streq (p[0], "win-sys") && p[1] && !p[2]) { VERIFY_PERMISSION (OPT_P_GENERAL); @@ -6371,7 +6371,7 @@ add_option (struct options *options, to->ip_win32_defined = true; } #endif -#if defined(WIN32) || defined(TARGET_ANDROID) +#if defined(_WIN32) || defined(TARGET_ANDROID) else if (streq (p[0], "dhcp-option") && p[1] && !p[3]) { struct tuntap_options *o = &options->tuntap_options; @@ -6424,7 +6424,7 @@ add_option (struct options *options, o->dhcp_options = true; } #endif -#ifdef WIN32 +#ifdef _WIN32 else if (streq (p[0], "show-adapters") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); diff --git a/src/openvpn/options.h b/src/openvpn/options.h index 0ebea30c4cf..d51150bf89e 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -578,7 +578,7 @@ struct options /* special state parms */ int foreign_option_index; -#ifdef WIN32 +#ifdef _WIN32 HANDLE msg_channel; const char *exit_event_name; bool exit_event_initial_state; @@ -655,7 +655,7 @@ struct options #define PUSH_DEFINED(opt) (false) #endif -#ifdef WIN32 +#ifdef _WIN32 #define ROUTE_OPTION_FLAGS(o) ((o)->route_method & ROUTE_METHOD_MASK) #else #define ROUTE_OPTION_FLAGS(o) (0) @@ -693,7 +693,7 @@ void usage_small (void); void show_library_versions(const unsigned int flags); -#ifdef WIN32 +#ifdef _WIN32 void show_windows_version(const unsigned int flags); #endif diff --git a/src/openvpn/otime.h b/src/openvpn/otime.h index 4ca103266c5..c0b0f38c949 100644 --- a/src/openvpn/otime.h +++ b/src/openvpn/otime.h @@ -76,8 +76,8 @@ openvpn_gettimeofday (struct timeval *tv, void *tz) static inline void update_time (void) { -#ifdef WIN32 - /* on WIN32, gettimeofday is faster than time(NULL) */ +#ifdef _WIN32 + /* on _WIN32, gettimeofday is faster than time(NULL) */ struct timeval tv; openvpn_gettimeofday (&tv, NULL); #else @@ -90,8 +90,8 @@ update_time (void) static inline void update_time (void) { -#if defined(WIN32) - /* on WIN32, gettimeofday is faster than time(NULL) */ +#if defined(_WIN32) + /* on _WIN32, gettimeofday is faster than time(NULL) */ struct timeval tv; if (!gettimeofday (&tv, NULL)) { diff --git a/src/openvpn/platform.c b/src/openvpn/platform.c index 16d4daca6f3..634364726c9 100644 --- a/src/openvpn/platform.c +++ b/src/openvpn/platform.c @@ -158,7 +158,7 @@ platform_nice (int niceval) unsigned int platform_getpid () { -#ifdef WIN32 +#ifdef _WIN32 return (unsigned int) GetCurrentProcessId (); #else #ifdef HAVE_GETPID @@ -190,7 +190,7 @@ int platform_chdir (const char* dir) { #ifdef HAVE_CHDIR -#ifdef WIN32 +#ifdef _WIN32 int res; struct gc_arena gc = gc_new (); res = _wchdir (wide_string (dir, &gc)); @@ -210,7 +210,7 @@ platform_chdir (const char* dir) bool platform_system_ok (int stat) { -#ifdef WIN32 +#ifdef _WIN32 return stat == 0; #else return stat != -1 && WIFEXITED (stat) && WEXITSTATUS (stat) == 0; @@ -220,7 +220,7 @@ platform_system_ok (int stat) int platform_access (const char *path, int mode) { -#ifdef WIN32 +#ifdef _WIN32 struct gc_arena gc = gc_new (); int ret = _waccess (wide_string (path, &gc), mode & ~X_OK); gc_free (&gc); @@ -236,7 +236,7 @@ platform_access (const char *path, int mode) void platform_sleep_milliseconds (unsigned int n) { -#ifdef WIN32 +#ifdef _WIN32 Sleep (n); #else struct timeval tv; @@ -252,7 +252,7 @@ platform_sleep_milliseconds (unsigned int n) void platform_sleep_until_signal (void) { -#ifdef WIN32 +#ifdef _WIN32 ASSERT (0); #else select (0, NULL, NULL, NULL, NULL); @@ -263,7 +263,7 @@ platform_sleep_until_signal (void) bool platform_unlink (const char *filename) { -#if defined(WIN32) +#if defined(_WIN32) struct gc_arena gc = gc_new (); BOOL ret = DeleteFileW (wide_string (filename, &gc)); gc_free (&gc); @@ -278,7 +278,7 @@ platform_unlink (const char *filename) FILE * platform_fopen (const char *path, const char *mode) { -#ifdef WIN32 +#ifdef _WIN32 struct gc_arena gc = gc_new (); FILE *f = _wfopen (wide_string (path, &gc), wide_string (mode, &gc)); gc_free (&gc); @@ -291,7 +291,7 @@ platform_fopen (const char *path, const char *mode) int platform_open (const char *path, int flags, int mode) { -#ifdef WIN32 +#ifdef _WIN32 struct gc_arena gc = gc_new (); int fd = _wopen (wide_string (path, &gc), flags, mode); gc_free (&gc); @@ -304,7 +304,7 @@ platform_open (const char *path, int flags, int mode) int platform_stat (const char *path, platform_stat_t *buf) { -#ifdef WIN32 +#ifdef _WIN32 struct gc_arena gc = gc_new (); int res = _wstat (wide_string (path, &gc), buf); gc_free (&gc); diff --git a/src/openvpn/platform.h b/src/openvpn/platform.h index 7c0a4d723a6..fe2685aeef1 100644 --- a/src/openvpn/platform.h +++ b/src/openvpn/platform.h @@ -130,7 +130,7 @@ int platform_putenv (char *string); FILE *platform_fopen (const char *path, const char *mode); int platform_open (const char *path, int flags, int mode); -#ifdef WIN32 +#ifdef _WIN32 typedef struct _stat platform_stat_t; #else typedef struct stat platform_stat_t; diff --git a/src/openvpn/plugin.c b/src/openvpn/plugin.c index 542e5b1f2b6..24434383d32 100644 --- a/src/openvpn/plugin.c +++ b/src/openvpn/plugin.c @@ -175,7 +175,7 @@ plugin_option_list_print (const struct plugin_option_list *list, int msglevel) } #endif -#ifndef WIN32 +#ifndef _WIN32 static void libdl_resolve_symbol (void *handle, void **dest, const char *symbol, const char *plugin_name, const unsigned int flags) @@ -206,7 +206,7 @@ plugin_init_item (struct plugin *p, const struct plugin_option *o) p->so_pathname = o->so_pathname; p->plugin_type_mask = plugin_supported_types (); -#ifndef WIN32 +#ifndef _WIN32 p->handle = NULL; #if defined(PLUGIN_LIBDIR) @@ -519,10 +519,10 @@ plugin_close_item (struct plugin *p) if (p->plugin_handle) (*p->close)(p->plugin_handle); -#ifndef WIN32 +#ifndef _WIN32 if (dlclose (p->handle)) msg (M_WARN, "PLUGIN_CLOSE: dlclose() failed on plugin: %s", p->so_pathname); -#elif defined(WIN32) +#elif defined(_WIN32) if (!FreeLibrary (p->module)) msg (M_WARN, "PLUGIN_CLOSE: FreeLibrary() failed on plugin: %s", p->so_pathname); #endif diff --git a/src/openvpn/plugin.h b/src/openvpn/plugin.h index 3c010476afe..b1e045889d0 100644 --- a/src/openvpn/plugin.h +++ b/src/openvpn/plugin.h @@ -59,7 +59,7 @@ struct plugin { unsigned int plugin_type_mask; int requested_initialization_point; -#ifndef WIN32 +#ifndef _WIN32 void *handle; #else HMODULE module; diff --git a/src/openvpn/route.c b/src/openvpn/route.c index 98bb228f715..fec12c11bee 100644 --- a/src/openvpn/route.c +++ b/src/openvpn/route.c @@ -49,7 +49,7 @@ #include /* RTM_GETROUTE etc. */ #endif -#ifdef WIN32 +#ifdef _WIN32 #include "openvpn-msg.h" #define METRIC_NOT_USED ((DWORD)-1) @@ -807,7 +807,7 @@ init_route_ipv6_list (struct route_ipv6_list *rl6, if ( !(rl6->rgi6.flags & RGI_ON_LINK) ) { r6->gateway = rl6->rgi6.gateway.addr_ipv6; } r6->metric = 1; -#ifdef WIN32 +#ifdef _WIN32 r6->adapter_index = rl6->rgi6.adapter_index; #else r6->iface = rl6->rgi6.iface; @@ -1214,7 +1214,7 @@ print_default_gateway(const int msglevel, buf_printf (&out, " %s", print_in_addr_t (rgi->gateway.addr, 0, &gc)); if (rgi->flags & RGI_NETMASK_DEFINED) buf_printf (&out, "/%s", print_in_addr_t (rgi->gateway.netmask, 0, &gc)); -#ifdef WIN32 +#ifdef _WIN32 if (rgi->flags & RGI_IFACE_DEFINED) buf_printf (&out, " I=%u", (unsigned int)rgi->adapter_index); #else @@ -1235,7 +1235,7 @@ print_default_gateway(const int msglevel, buf_printf (&out, " ON_LINK"); if (rgi6->flags & RGI_NETMASK_DEFINED) buf_printf (&out, "/%d", rgi6->gateway.netbits_ipv6); -#ifdef WIN32 +#ifdef _WIN32 if (rgi6->flags & RGI_IFACE_DEFINED) buf_printf (&out, " I=%u", (unsigned int)rgi6->adapter_index); #else @@ -1454,7 +1454,7 @@ add_route (struct route_ipv4 *r, buf_printf (&out, "%s %s %s", network, netmask, gateway); management_android_control (management, "ROUTE", buf_bptr(&out)); -#elif defined (WIN32) +#elif defined (_WIN32) { DWORD ai = TUN_ADAPTER_INDEX_INVALID; argv_printf (&argv, "%s%sc ADD %s MASK %s %s", @@ -1682,7 +1682,7 @@ add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int fla if (! (r6->flags & RT_DEFINED) ) return; -#ifndef WIN32 +#ifndef _WIN32 if ( r6->iface != NULL ) /* vpn server special route */ { device = r6->iface; @@ -1777,7 +1777,7 @@ add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int fla management_android_control (management, "ROUTE6", buf_bptr(&out)); -#elif defined (WIN32) +#elif defined (_WIN32) if (tt->options.msg_channel) status = add_route_ipv6_service (r6, tt); @@ -1967,7 +1967,7 @@ delete_route (struct route_ipv4 *r, argv_msg (D_ROUTE, &argv); openvpn_execve_check (&argv, es, 0, "ERROR: Linux route delete command failed"); -#elif defined (WIN32) +#elif defined (_WIN32) argv_printf (&argv, "%s%sc DELETE %s MASK %s %s", get_win_sys_path(), @@ -2114,7 +2114,7 @@ delete_route_ipv6 (const struct route_ipv6 *r6, const struct tuntap *tt, unsigne if ((r6->flags & (RT_DEFINED|RT_ADDED)) != (RT_DEFINED|RT_ADDED)) return; -#ifndef WIN32 +#ifndef _WIN32 if ( r6->iface != NULL ) /* vpn server special route */ { device = r6->iface; @@ -2180,7 +2180,7 @@ delete_route_ipv6 (const struct route_ipv6 *r6, const struct tuntap *tt, unsigne argv_msg (D_ROUTE, &argv); openvpn_execve_check (&argv, es, 0, "ERROR: Linux route -6/-A inet6 del command failed"); -#elif defined (WIN32) +#elif defined (_WIN32) if (tt->options.msg_channel) del_route_ipv6_service (r6, tt); @@ -2316,7 +2316,7 @@ delete_route_ipv6 (const struct route_ipv6 *r6, const struct tuntap *tt, unsigne * to get the current default gateway. */ -#if defined(WIN32) +#if defined(_WIN32) static const MIB_IPFORWARDTABLE * get_windows_routing_table (struct gc_arena *gc) @@ -3694,7 +3694,7 @@ int netmask_to_netbits2 (in_addr_t netmask) * so that outgoing packets to these servers don't end up in the tunnel. */ -#if defined(WIN32) +#if defined(_WIN32) static void add_host_route_if_nonlocal (struct route_bypass *rb, const in_addr_t addr) @@ -3768,7 +3768,7 @@ get_bypass_addresses (struct route_bypass *rb, const unsigned int flags) /* PLA * Used by redirect-gateway autolocal feature */ -#if defined(WIN32) +#if defined(_WIN32) int test_local_addr (const in_addr_t addr, const struct route_gateway_info *rgi) diff --git a/src/openvpn/route.h b/src/openvpn/route.h index 58a57484ac0..c358681e548 100644 --- a/src/openvpn/route.h +++ b/src/openvpn/route.h @@ -33,7 +33,7 @@ #include "tun.h" #include "misc.h" -#ifdef WIN32 +#ifdef _WIN32 /* * Windows route methods */ @@ -130,7 +130,7 @@ struct route_ipv6 { struct in6_addr gateway; int metric; /* gateway interface */ -# ifdef WIN32 +# ifdef _WIN32 DWORD adapter_index; /* interface or ~0 if undefined */ #else char * iface; /* interface name (null terminated) */ @@ -153,7 +153,7 @@ struct route_gateway_info { unsigned int flags; /* gateway interface */ -# ifdef WIN32 +# ifdef _WIN32 DWORD adapter_index; /* interface or ~0 if undefined */ #else char iface[16]; /* interface name (null terminated), may be empty */ @@ -181,7 +181,7 @@ struct route_ipv6_gateway_info { unsigned int flags; /* gateway interface */ -# ifdef WIN32 +# ifdef _WIN32 DWORD adapter_index; /* interface or ~0 if undefined */ #else char iface[16]; /* interface name (null terminated), may be empty */ @@ -333,7 +333,7 @@ void print_route_options (const struct route_option_list *rol, void print_routes (const struct route_list *rl, int level); -#ifdef WIN32 +#ifdef _WIN32 void show_routes (int msglev); bool test_routes (const struct route_list *rl, const struct tuntap *tt); diff --git a/src/openvpn/sig.c b/src/openvpn/sig.c index 718b78600e3..0ff14379569 100644 --- a/src/openvpn/sig.c +++ b/src/openvpn/sig.c @@ -221,7 +221,7 @@ static int signal_mode; /* GLOBAL */ void pre_init_signal_catch (void) { -#ifndef WIN32 +#ifndef _WIN32 #ifdef HAVE_SIGNAL_H signal_mode = SM_PRE_INIT; signal (SIGINT, signal_handler); @@ -231,13 +231,13 @@ pre_init_signal_catch (void) signal (SIGUSR2, SIG_IGN); signal (SIGPIPE, SIG_IGN); #endif /* HAVE_SIGNAL_H */ -#endif /* WIN32 */ +#endif /* _WIN32 */ } void post_init_signal_catch (void) { -#ifndef WIN32 +#ifndef _WIN32 #ifdef HAVE_SIGNAL_H signal_mode = SM_POST_INIT; signal (SIGINT, signal_handler); @@ -291,7 +291,7 @@ print_status (const struct context *c, struct status_output *so) status_printf (so, "Pre-encrypt truncations," counter_format, c->c2.n_trunc_pre_encrypt); status_printf (so, "Post-decrypt truncations," counter_format, c->c2.n_trunc_post_decrypt); #endif -#ifdef WIN32 +#ifdef _WIN32 if (tuntap_defined (c->c1.tuntap)) status_printf (so, "TAP-WIN32 driver status,\"%s\"", tap_win_getinfo (c->c1.tuntap, &gc)); diff --git a/src/openvpn/sig.h b/src/openvpn/sig.h index c2c7b54e1cf..2875a4c9c79 100644 --- a/src/openvpn/sig.h +++ b/src/openvpn/sig.h @@ -79,7 +79,7 @@ void register_signal (struct context *c, int sig, const char *text); void process_explicit_exit_notification_timer_wakeup (struct context *c); #endif -#ifdef WIN32 +#ifdef _WIN32 static inline void get_signal (volatile int *sig) diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c index a9aaa2a267a..c233f2b6f7d 100644 --- a/src/openvpn/socket.c +++ b/src/openvpn/socket.c @@ -376,7 +376,7 @@ openvpn_getaddrinfo (unsigned int flags, */ while (true) { -#ifndef WIN32 +#ifndef _WIN32 res_init (); #endif /* try hostname lookup */ @@ -690,7 +690,7 @@ socket_set_buffers (int fd, const struct socket_buffer_size *sbs) static bool socket_set_tcp_nodelay (int sd, int state) { -#if defined(WIN32) || (defined(HAVE_SETSOCKOPT) && defined(IPPROTO_TCP) && defined(TCP_NODELAY)) +#if defined(_WIN32) || (defined(HAVE_SETSOCKOPT) && defined(IPPROTO_TCP) && defined(TCP_NODELAY)) if (setsockopt (sd, IPPROTO_TCP, TCP_NODELAY, (void *) &state, sizeof (state)) != 0) { msg (M_WARN, "NOTE: setsockopt TCP_NODELAY=%d failed", state); @@ -761,7 +761,7 @@ create_socket_tcp (struct addrinfo* addrinfo) if ((sd = socket (addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol)) < 0) msg (M_ERR, "Cannot create TCP socket"); -#ifndef WIN32 /* using SO_REUSEADDR on Windows will cause bind to succeed on port conflicts! */ +#ifndef _WIN32 /* using SO_REUSEADDR on Windows will cause bind to succeed on port conflicts! */ /* set SO_REUSEADDR on socket */ { int on = 1; @@ -1066,7 +1066,7 @@ socket_listen_accept (socket_descriptor_t sd, /* older mingw versions and WinXP do not have this define, * but Vista and up support the functionality - just define it here */ -#ifdef WIN32 +#ifdef _WIN32 # ifndef IPV6_V6ONLY # define IPV6_V6ONLY 27 # endif @@ -1141,7 +1141,7 @@ openvpn_connect (socket_descriptor_t sd, if (status) status = openvpn_errno (); if ( -#ifdef WIN32 +#ifdef _WIN32 status == WSAEWOULDBLOCK #else status == EINPROGRESS @@ -1184,7 +1184,7 @@ openvpn_connect (socket_descriptor_t sd, { if (--connect_timeout < 0) { -#ifdef WIN32 +#ifdef _WIN32 status = WSAETIMEDOUT; #else status = ETIMEDOUT; @@ -1296,7 +1296,7 @@ socket_connect (socket_descriptor_t* sd, static void socket_frame_init (const struct frame *frame, struct link_socket *sock) { -#ifdef WIN32 +#ifdef _WIN32 overlapped_io_init (&sock->reads, frame, FALSE, false); overlapped_io_init (&sock->writes, frame, TRUE, false); sock->rw_handle.read = sock->reads.overlapped.hEvent; @@ -1305,7 +1305,7 @@ socket_frame_init (const struct frame *frame, struct link_socket *sock) if (link_socket_connection_oriented (sock)) { -#ifdef WIN32 +#ifdef _WIN32 stream_buf_init (&sock->stream_buf, &sock->reads.buf_init, sock->sockflags, @@ -1971,7 +1971,7 @@ link_socket_close (struct link_socket *sock) if (socket_defined (sock->sd)) { -#ifdef WIN32 +#ifdef _WIN32 close_net_event_win32 (&sock->listen_handle, sock->sd, 0); #endif if (!gremlin) @@ -1981,7 +1981,7 @@ link_socket_close (struct link_socket *sock) msg (M_WARN | M_ERRNO, "TCP/UDP: Close Socket failed"); } sock->sd = SOCKET_UNDEFINED; -#ifdef WIN32 +#ifdef _WIN32 if (!gremlin) { overlapped_io_close (&sock->reads); @@ -2176,7 +2176,7 @@ socket_stat (const struct link_socket *s, unsigned int rwflags, struct gc_arena { buf_printf (&out, "S%s", (s->rwflags_debug & EVENT_READ) ? "R" : "r"); -#ifdef WIN32 +#ifdef _WIN32 buf_printf (&out, "%s", overlapped_io_state_ascii (&s->reads)); #endif @@ -2185,7 +2185,7 @@ socket_stat (const struct link_socket *s, unsigned int rwflags, struct gc_arena { buf_printf (&out, "S%s", (s->rwflags_debug & EVENT_WRITE) ? "W" : "w"); -#ifdef WIN32 +#ifdef _WIN32 buf_printf (&out, "%s", overlapped_io_state_ascii (&s->writes)); #endif @@ -2360,7 +2360,7 @@ stream_buf_close (struct stream_buf* sb) event_t socket_listen_event_handle (struct link_socket *s) { -#ifdef WIN32 +#ifdef _WIN32 if (!defined_net_event_win32 (&s->listen_handle)) init_net_event_win32 (&s->listen_handle, FD_ACCEPT, s->sd, 0); return &s->listen_handle; @@ -2837,7 +2837,7 @@ link_socket_read_tcp (struct link_socket *sock, if (!sock->stream_buf.residual_fully_formed) { -#ifdef WIN32 +#ifdef _WIN32 len = socket_finalize (sock->sd, &sock->reads, buf, NULL); #else struct buffer frag; @@ -2862,7 +2862,7 @@ link_socket_read_tcp (struct link_socket *sock, return buf->len = 0; /* no error, but packet is still incomplete */ } -#ifndef WIN32 +#ifndef _WIN32 #if ENABLE_IP_PKTINFO @@ -2983,7 +2983,7 @@ link_socket_write_tcp (struct link_socket *sock, ASSERT (len <= sock->stream_buf.maxlen); len = htonps (len); ASSERT (buf_write_prepend (buf, &len, sizeof (len))); -#ifdef WIN32 +#ifdef _WIN32 return link_socket_write_win32 (sock, buf, to); #else return link_socket_write_tcp_posix (sock, buf, to); @@ -3071,7 +3071,7 @@ link_socket_write_udp_posix_sendmsg (struct link_socket *sock, * Win32 overlapped socket I/O functions. */ -#ifdef WIN32 +#ifdef _WIN32 int socket_recv_queue (struct link_socket *sock, int maxsize) @@ -3379,7 +3379,7 @@ socket_finalize (SOCKET s, case sizeof(struct sockaddr_in): case sizeof(struct sockaddr_in6): /* TODO(jjo): for some reason (?) I'm getting 24,28 for AF_INET6 - * under WIN32*/ + * under _WIN32*/ case sizeof(struct sockaddr_in6)-4: break; default: @@ -3405,7 +3405,7 @@ socket_finalize (SOCKET s, return ret; } -#endif /* WIN32 */ +#endif /* _WIN32 */ /* * Socket event notification @@ -3426,7 +3426,7 @@ socket_set (struct link_socket *s, rwflags &= ~EVENT_READ; } -#ifdef WIN32 +#ifdef _WIN32 if (rwflags & EVENT_READ) socket_recv_queue (s, 0); #endif diff --git a/src/openvpn/socket.h b/src/openvpn/socket.h index e1607f4e736..2a82d8894f6 100644 --- a/src/openvpn/socket.h +++ b/src/openvpn/socket.h @@ -169,7 +169,7 @@ struct link_socket socket_descriptor_t sd; socket_descriptor_t ctrl_sd; /* only used for UDP over Socks */ -#ifdef WIN32 +#ifdef _WIN32 struct overlapped_io reads; struct overlapped_io writes; struct rw_handle rw_handle; @@ -257,7 +257,7 @@ struct link_socket #define MSG_NOSIGNAL 0 #endif -#ifdef WIN32 +#ifdef _WIN32 #define openvpn_close_socket(s) closesocket(s) @@ -842,7 +842,7 @@ socket_connection_reset (const struct link_socket *sock, int status) else if (status < 0) { const int err = openvpn_errno (); -#ifdef WIN32 +#ifdef _WIN32 return err == WSAECONNRESET || err == WSAECONNABORTED; #else return err == ECONNRESET; @@ -950,7 +950,7 @@ stream_buf_read_setup (struct link_socket* sock) int link_socket_read_tcp (struct link_socket *sock, struct buffer *buf); -#ifdef WIN32 +#ifdef _WIN32 static inline int link_socket_read_udp_win32 (struct link_socket *sock, @@ -978,7 +978,7 @@ link_socket_read (struct link_socket *sock, { int res; -#ifdef WIN32 +#ifdef _WIN32 res = link_socket_read_udp_win32 (sock, buf, from); #else res = link_socket_read_udp_posix (sock, buf, from); @@ -1006,7 +1006,7 @@ int link_socket_write_tcp (struct link_socket *sock, struct buffer *buf, struct link_socket_actual *to); -#ifdef WIN32 +#ifdef _WIN32 static inline int link_socket_write_win32 (struct link_socket *sock, @@ -1068,7 +1068,7 @@ link_socket_write_udp (struct link_socket *sock, struct buffer *buf, struct link_socket_actual *to) { -#ifdef WIN32 +#ifdef _WIN32 return link_socket_write_win32 (sock, buf, to); #else return link_socket_write_udp_posix (sock, buf, to); @@ -1138,7 +1138,7 @@ socket_read_residual (const struct link_socket *s) static inline event_t socket_event_handle (const struct link_socket *s) { -#ifdef WIN32 +#ifdef _WIN32 return &s->rw_handle; #else return s->sd; @@ -1169,7 +1169,7 @@ socket_set_listen_persistent (struct link_socket *s, static inline void socket_reset_listen_persistent (struct link_socket *s) { -#ifdef WIN32 +#ifdef _WIN32 reset_net_event_win32 (&s->listen_handle, s->sd); #endif } diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 4a0cd6f3fd7..0c279ccdbbf 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -1978,7 +1978,7 @@ push_peer_info(struct buffer *buf, struct tls_session *session) buf_printf (&out, "IV_PLAT=freebsd\n"); #elif defined(TARGET_ANDROID) buf_printf (&out, "IV_PLAT=android\n"); -#elif defined(WIN32) +#elif defined(_WIN32) buf_printf (&out, "IV_PLAT=win\n"); #endif @@ -2008,7 +2008,7 @@ push_peer_info(struct buffer *buf, struct tls_session *session) if (rgi.flags & RGI_HWADDR_DEFINED) buf_printf (&out, "IV_HWADDR=%s\n", format_hex_ex (rgi.hwaddr, 6, 0, 1, ":", &gc)); buf_printf (&out, "IV_SSL=%s\n", get_ssl_library_version() ); -#if defined(WIN32) +#if defined(_WIN32) buf_printf (&out, "IV_PLAT_VER=%s\n", win32_version_string (&gc, false)); #endif } diff --git a/src/openvpn/ssl_backend.h b/src/openvpn/ssl_backend.h index a61f03a7cba..726a621e0a2 100644 --- a/src/openvpn/ssl_backend.h +++ b/src/openvpn/ssl_backend.h @@ -232,7 +232,7 @@ int tls_ctx_load_pkcs12(struct tls_root_ctx *ctx, const char *pkcs12_file, */ #ifdef ENABLE_CRYPTOAPI void tls_ctx_load_cryptoapi(struct tls_root_ctx *ctx, const char *cryptoapi_cert); -#endif /* WIN32 */ +#endif /* _WIN32 */ /** * Load certificate file into the given TLS context. If the given certificate diff --git a/src/openvpn/ssl_mbedtls.c b/src/openvpn/ssl_mbedtls.c index c2aff405a92..7f95f14508e 100644 --- a/src/openvpn/ssl_mbedtls.c +++ b/src/openvpn/ssl_mbedtls.c @@ -283,7 +283,7 @@ tls_ctx_load_cryptoapi(struct tls_root_ctx *ctx, const char *cryptoapi_cert) { msg(M_FATAL, "Windows CryptoAPI not yet supported for mbed TLS."); } -#endif /* WIN32 */ +#endif /* _WIN32 */ void tls_ctx_load_cert_file (struct tls_root_ctx *ctx, const char *cert_file, diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c index 171cd02a6eb..48ca4090b58 100644 --- a/src/openvpn/ssl_openssl.c +++ b/src/openvpn/ssl_openssl.c @@ -632,7 +632,7 @@ tls_ctx_load_cryptoapi(struct tls_root_ctx *ctx, const char *cryptoapi_cert) if (!SSL_CTX_use_CryptoAPI_certificate (ctx->ctx, cryptoapi_cert)) crypto_msg (M_FATAL, "Cannot load certificate \"%s\" from Microsoft Certificate Store", cryptoapi_cert); } -#endif /* WIN32 */ +#endif /* ENABLE_CRYPTOAPI */ static void tls_ctx_add_extra_certs (struct tls_root_ctx *ctx, BIO *bio) diff --git a/src/openvpn/syshead.h b/src/openvpn/syshead.h index e969ccfa635..8de7d87293d 100644 --- a/src/openvpn/syshead.h +++ b/src/openvpn/syshead.h @@ -37,7 +37,7 @@ # define unlikely(x) (x) #endif -#ifdef WIN32 +#ifdef _WIN32 #include #include #define sleep(x) Sleep((x)*1000) @@ -64,7 +64,7 @@ # include #endif -#ifndef WIN32 +#ifndef _WIN32 #ifndef WEXITSTATUS # define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) #endif @@ -358,7 +358,7 @@ #endif /* TARGET_DARWIN */ -#ifdef WIN32 +#ifdef _WIN32 // Missing declarations for MinGW 32. // #if !defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 2 typedef int MIB_TCP_STATE; @@ -405,7 +405,7 @@ /* * Do we have nanoseconds gettimeofday? */ -#if defined(HAVE_GETTIMEOFDAY) || defined(WIN32) +#if defined(HAVE_GETTIMEOFDAY) || defined(_WIN32) #define HAVE_GETTIMEOFDAY_NANOSECONDS 1 #endif @@ -470,26 +470,16 @@ typedef unsigned short sa_family_t; /* * Directory separation char */ -#ifdef WIN32 +#ifdef _WIN32 #define OS_SPECIFIC_DIRSEP '\\' #else #define OS_SPECIFIC_DIRSEP '/' #endif -/* - * Define a boolean value based - * on Win32 status. - */ -#ifdef WIN32 -#define WIN32_0_1 1 -#else -#define WIN32_0_1 0 -#endif - /* * Our socket descriptor type. */ -#ifdef WIN32 +#ifdef _WIN32 #define SOCKET_UNDEFINED (INVALID_SOCKET) typedef SOCKET socket_descriptor_t; #else @@ -590,7 +580,7 @@ socket_defined (const socket_descriptor_t sd) /* * Do we support Unix domain sockets? */ -#if defined(PF_UNIX) && !defined(WIN32) +#if defined(PF_UNIX) && !defined(_WIN32) #define UNIX_SOCK_SUPPORT 1 #else #define UNIX_SOCK_SUPPORT 0 @@ -624,7 +614,7 @@ socket_defined (const socket_descriptor_t sd) /* * Do we have CryptoAPI capability? */ -#if defined(WIN32) && defined(ENABLE_CRYPTO) && defined(ENABLE_CRYPTO_OPENSSL) +#if defined(_WIN32) && defined(ENABLE_CRYPTO) && defined(ENABLE_CRYPTO_OPENSSL) #define ENABLE_CRYPTOAPI #endif diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index 2a87e09b350..d37e27e763a 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -49,13 +49,13 @@ #include "memdbg.h" -#ifdef WIN32 +#ifdef _WIN32 #include "openvpn-msg.h" #endif #include -#ifdef WIN32 +#ifdef _WIN32 /* #define SIMULATE_DHCP_FAILED */ /* simulate bad DHCP negotiation */ @@ -198,7 +198,7 @@ guess_tuntap_dev (const char *dev, const char *dev_node, struct gc_arena *gc) { -#ifdef WIN32 +#ifdef _WIN32 const int dt = dev_type_enum (dev, dev_type); if (dt == DEV_TYPE_TUN || dt == DEV_TYPE_TAP) { @@ -421,7 +421,7 @@ tun_stat (const struct tuntap *tt, unsigned int rwflags, struct gc_arena *gc) { buf_printf (&out, "T%s", (tt->rwflags_debug & EVENT_READ) ? "R" : "r"); -#ifdef WIN32 +#ifdef _WIN32 buf_printf (&out, "%s", overlapped_io_state_ascii (&tt->reads)); #endif @@ -430,7 +430,7 @@ tun_stat (const struct tuntap *tt, unsigned int rwflags, struct gc_arena *gc) { buf_printf (&out, "T%s", (tt->rwflags_debug & EVENT_WRITE) ? "W" : "w"); -#ifdef WIN32 +#ifdef _WIN32 buf_printf (&out, "%s", overlapped_io_state_ascii (&tt->writes)); #endif @@ -611,7 +611,7 @@ init_tun (const char *dev, /* --dev option */ tt->broadcast = generate_ifconfig_broadcast_addr (tt->local, tt->remote_netmask); } -#ifdef WIN32 +#ifdef _WIN32 /* * Make sure that both ifconfig addresses are part of the * same .252 subnet. @@ -665,7 +665,7 @@ init_tun_post (struct tuntap *tt, const struct tuntap_options *options) { tt->options = *options; -#ifdef WIN32 +#ifdef _WIN32 overlapped_io_init (&tt->reads, frame, FALSE, true); overlapped_io_init (&tt->writes, frame, TRUE, true); tt->rw_handle.read = tt->reads.overlapped.hEvent; @@ -674,7 +674,7 @@ init_tun_post (struct tuntap *tt, #endif } -#if defined(WIN32) || \ +#if defined(_WIN32) || \ defined(TARGET_DARWIN) || defined(TARGET_NETBSD) || defined(TARGET_OPENBSD) /* some of the platforms will auto-add a "network route" pointing @@ -1346,7 +1346,7 @@ do_ifconfig (struct tuntap *tt, } env_set_destroy (aix_es); } -#elif defined (WIN32) +#elif defined (_WIN32) { ASSERT (actual != NULL); @@ -1405,7 +1405,7 @@ static void clear_tuntap (struct tuntap *tuntap) { CLEAR (*tuntap); -#ifdef WIN32 +#ifdef _WIN32 tuntap->hand = NULL; #else tuntap->fd = -1; @@ -1502,7 +1502,7 @@ read_tun_header (struct tuntap* tt, uint8_t *buf, int len) #endif -#ifndef WIN32 +#ifndef _WIN32 static void open_tun_generic (const char *dev, const char *dev_type, const char *dev_node, bool dynamic, struct tuntap *tt) @@ -3012,7 +3012,7 @@ read_tun (struct tuntap* tt, uint8_t *buf, int len) return read (tt->fd, buf, len); } -#elif defined(WIN32) +#elif defined(_WIN32) int tun_read_queue (struct tuntap *tt, int maxsize) diff --git a/src/openvpn/tun.h b/src/openvpn/tun.h index 6e3086c7228..dedd915c350 100644 --- a/src/openvpn/tun.h +++ b/src/openvpn/tun.h @@ -25,7 +25,7 @@ #ifndef TUN_H #define TUN_H -#ifdef WIN32 +#ifdef _WIN32 #include #include #endif @@ -38,7 +38,7 @@ #include "proto.h" #include "misc.h" -#if defined(WIN32) || defined(TARGET_ANDROID) +#if defined(_WIN32) || defined(TARGET_ANDROID) #define TUN_ADAPTER_INDEX_INVALID ((DWORD)-1) @@ -58,7 +58,7 @@ struct tuntap_options { # define IPW32_SET_N 5 int ip_win32_type; -#ifdef WIN32 +#ifdef _WIN32 HANDLE msg_channel; #endif @@ -157,7 +157,7 @@ struct tuntap struct in6_addr remote_ipv6; int netbits_ipv6; -#ifdef WIN32 +#ifdef _WIN32 HANDLE hand; struct overlapped_io reads; struct overlapped_io writes; @@ -197,7 +197,7 @@ struct tuntap static inline bool tuntap_defined (const struct tuntap *tt) { -#ifdef WIN32 +#ifdef _WIN32 return tt && tt->hand != NULL; #else return tt && tt->fd >= 0; @@ -298,7 +298,7 @@ ifconfig_order(void) return IFCONFIG_AFTER_TUN_OPEN; #elif defined(TARGET_NETBSD) return IFCONFIG_AFTER_TUN_OPEN; -#elif defined(WIN32) +#elif defined(_WIN32) return IFCONFIG_AFTER_TUN_OPEN; #elif defined(TARGET_ANDROID) return IFCONFIG_BEFORE_TUN_OPEN; @@ -322,7 +322,7 @@ route_order(void) } -#ifdef WIN32 +#ifdef _WIN32 #define TUN_PASS_BUFFER @@ -476,7 +476,7 @@ tun_standby (struct tuntap *tt) static inline event_t tun_event_handle (const struct tuntap *tt) { -#ifdef WIN32 +#ifdef _WIN32 return &tt->rw_handle; #else return tt->fd; @@ -499,7 +499,7 @@ tun_set (struct tuntap *tt, if (persistent) *persistent = rwflags; } -#ifdef WIN32 +#ifdef _WIN32 if (rwflags & EVENT_READ) tun_read_queue (tt, 0); #endif diff --git a/src/openvpn/win32.c b/src/openvpn/win32.c index ad721cdb3ad..00bc7ac2ed9 100644 --- a/src/openvpn/win32.c +++ b/src/openvpn/win32.c @@ -35,7 +35,7 @@ #include "syshead.h" -#ifdef WIN32 +#ifdef _WIN32 #include "buffer.h" #include "error.h" diff --git a/src/openvpn/win32.h b/src/openvpn/win32.h index 619878f6572..11e42f4b4eb 100644 --- a/src/openvpn/win32.h +++ b/src/openvpn/win32.h @@ -22,7 +22,7 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifdef WIN32 +#ifdef _WIN32 #ifndef OPENVPN_WIN32_H #define OPENVPN_WIN32_H From 8b42c197626430118ed126c1b8256ba5ae1f699a Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Mon, 14 Nov 2016 12:20:08 +0100 Subject: [PATCH 382/643] systemd: Improve the systemd unit files There are several changes which allows systemd to take care of several aspects of hardening the execution of OpenVPN. - Let systemd take care of the process tracking directly, instead of doing that via PID files - Make systemd prepare proper runtime directories for the OpenVPN process. - Let systemd do the chdir() before starting OpenVPN. This allows us to avoid using the --cd option when executing openvpn. - CAP_DAC_OVERRIDE was needed when using --chroot. Otherwise the root user would not be allowed to access files/directories not owned by root. This will change in the future, when we find better ways to avoid calling chroot() in OpenVPN and rather let systemd prepare a more isolated namespace. - Client configurations are now started with --nobind and the OpenVPN client process have lost the CAP_NET_BIND_SERVICE capability which allows binding to port < 1024. - Documentation URL now points at the OpenVPN 2.4 man page URL The majority of these changes have been proposed by Elias Probst (eliasp) in the GitHub PR #22. v3 - Add ExecPreStart= to check if OpenVPN configuration contains 'daemon'. That can break the process tracking as we now use Type=simple (default) v2 - Change RuntimeDirectory= to a profile specific (client, server) directory to avoid clashing with older distro unit files Commit note: As this is not a critical security change, we apply this without any formal ACKs. It has been thoroghly tested by several users. See mailing list for details. Contribution-by: Elias Probst Signed-off-by: David Sommerseth Message-Id: <1479122408-6867-1-git-send-email-davids@openvpn.net> URL: http://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13039.html --- distro/systemd/openvpn-client@.service | 12 +++++++----- distro/systemd/openvpn-server@.service | 15 +++++++++------ 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/distro/systemd/openvpn-client@.service b/distro/systemd/openvpn-client@.service index 56d93a932e6..18b84dd1c9a 100644 --- a/distro/systemd/openvpn-client@.service +++ b/distro/systemd/openvpn-client@.service @@ -3,15 +3,17 @@ Description=OpenVPN tunnel for %I After=syslog.target network-online.target Wants=network-online.target Documentation=man:openvpn(8) -Documentation=https://community.openvpn.net/openvpn/wiki/Openvpn23ManPage +Documentation=https://community.openvpn.net/openvpn/wiki/Openvpn24ManPage Documentation=https://community.openvpn.net/openvpn/wiki/HOWTO [Service] PrivateTmp=true -Type=forking -PIDFile=/var/run/openvpn/client_%i.pid -ExecStart=/usr/sbin/openvpn --cd /etc/openvpn/client --config %i.conf --daemon --writepid /var/run/openvpn/client_%i.pid -CapabilityBoundingSet=CAP_IPC_LOCK CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW CAP_SETGID CAP_SETUID CAP_SYS_CHROOT CAP_DAC_READ_SEARCH +RuntimeDirectory=openvpn-client +RuntimeDirectoryMode=0710 +WorkingDirectory=/etc/openvpn/client +ExecStartPre=/bin/sh -c 'grep -q -E ^daemon %i.conf || exit 0 && /usr/bin/echo "OpenVPN configuration cannot contain --daemon when being managed by systemd" ; exit 1' +ExecStart=/usr/sbin/openvpn --suppress-timestamps --nobind --config %i.conf +CapabilityBoundingSet=CAP_IPC_LOCK CAP_NET_ADMIN CAP_NET_RAW CAP_SETGID CAP_SETUID CAP_SYS_CHROOT CAP_DAC_OVERRIDE LimitNPROC=10 DeviceAllow=/dev/null rw DeviceAllow=/dev/net/tun rw diff --git a/distro/systemd/openvpn-server@.service b/distro/systemd/openvpn-server@.service index c4c9a1233d3..a2b7b52b85b 100644 --- a/distro/systemd/openvpn-server@.service +++ b/distro/systemd/openvpn-server@.service @@ -1,16 +1,19 @@ [Unit] Description=OpenVPN service for %I -After=syslog.target network.target +After=syslog.target network-online.target +Wants=network-online.target Documentation=man:openvpn(8) -Documentation=https://community.openvpn.net/openvpn/wiki/Openvpn23ManPage +Documentation=https://community.openvpn.net/openvpn/wiki/Openvpn24ManPage Documentation=https://community.openvpn.net/openvpn/wiki/HOWTO [Service] PrivateTmp=true -Type=forking -PIDFile=/var/run/openvpn/server_%i.pid -ExecStart=/usr/sbin/openvpn --cd /etc/openvpn/server --status /var/run/openvpn/server_%i-status.log --status-version 2 --config %i.conf --daemon --writepid /var/run/openvpn/server_%i.pid -CapabilityBoundingSet=CAP_IPC_LOCK CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW CAP_SETGID CAP_SETUID CAP_SYS_CHROOT CAP_DAC_READ_SEARCH +RuntimeDirectory=openvpn-server +RuntimeDirectoryMode=0710 +WorkingDirectory=/etc/openvpn/server +ExecStartPre=/bin/sh -c 'grep -q -E ^daemon %i.conf || exit 0 && /usr/bin/echo "OpenVPN configuration cannot contain --daemon when being managed by systemd" ; exit 1' +ExecStart=/usr/sbin/openvpn --status %t/openvpn-server/status-%i.log --status-version 2 --suppress-timestamps --config %i.conf +CapabilityBoundingSet=CAP_IPC_LOCK CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW CAP_SETGID CAP_SETUID CAP_SYS_CHROOT CAP_DAC_OVERRIDE LimitNPROC=10 DeviceAllow=/dev/null rw DeviceAllow=/dev/net/tun rw From 160504a2955c4478cd2c0323452929e07016a336 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Fri, 28 Oct 2016 17:54:47 +0200 Subject: [PATCH 383/643] Refactor CRL handling This patch refactors the CRL handling to rely more on the implementation of the crypto library. It will insert the CRL at the correct time to keep it up to date, but all additional verification logic is removed from ssl_verify_.c. "Less code of our own, less bugs of our own." In practice, this means extra checks will be performed on the CRL, such as checking it validBefore and validAfter fields. This patch was originally written by Ivo Manca, and then molded by Steffan before sending to the list. All bugs are Steffan's fault. Thanks also go to Antonio Quartulli for useful feedback. He'll send follow-up patches to improve CRL handling performance. Signed-off-by: Ivo Manca Signed-off-by: Steffan Karger Acked-by: David Sommerseth Acked-by: Gert Doering Message-Id: <1477670087-30063-1-git-send-email-steffan.karger@fox-it.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12809.html Signed-off-by: David Sommerseth --- Changes.rst | 6 ++ src/openvpn/ssl.c | 15 +++++ src/openvpn/ssl_backend.h | 11 ++++ src/openvpn/ssl_mbedtls.c | 43 +++++++++++++- src/openvpn/ssl_mbedtls.h | 1 + src/openvpn/ssl_openssl.c | 58 +++++++++++++++++++ src/openvpn/ssl_verify.c | 19 ++++--- src/openvpn/ssl_verify_backend.h | 19 ++----- src/openvpn/ssl_verify_mbedtls.c | 56 ++----------------- src/openvpn/ssl_verify_openssl.c | 96 ++++++++++++-------------------- 10 files changed, 193 insertions(+), 131 deletions(-) diff --git a/Changes.rst b/Changes.rst index 2b99a1d0df7..f57b750c4ef 100644 --- a/Changes.rst +++ b/Changes.rst @@ -120,6 +120,12 @@ Deprecated features will then use ``--key-method 2`` by default. Note that this requires changing the option in both the client and server side configs. +- CRLs are now handled by the crypto library (OpenSSL or mbed TLS), instead of + inside OpenVPN itself. The crypto library implementations are more strict + than the OpenVPN implementation was. This might reject peer certificates + that would previously be accepted. If this occurs, OpenVPN will log the + crypto library's error description. + User-visible Changes -------------------- diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 0c279ccdbbf..88aeaadac32 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -608,6 +608,12 @@ init_ssl (const struct options *options, struct tls_root_ctx *new_ctx) /* Check certificate notBefore and notAfter */ tls_ctx_check_cert_time(new_ctx); + /* Read CRL */ + if (options->crl_file && !(options->ssl_flags & SSLF_CRL_VERIFY_DIR)) + { + tls_ctx_reload_crl(new_ctx, options->crl_file, options->crl_file_inline); + } + /* Once keys and cert are loaded, load ECDH parameters */ if (options->tls_server) tls_ctx_load_ecdh_params(new_ctx, options->ecdh_curve); @@ -2502,6 +2508,15 @@ tls_process (struct tls_multi *multi, { ks->state = S_START; state_change = true; + + /* Reload the CRL before TLS negotiation */ + if (session->opt->crl_file && + !(session->opt->ssl_flags & SSLF_CRL_VERIFY_DIR)) + { + tls_ctx_reload_crl(&session->opt->ssl_ctx, + session->opt->crl_file, session->opt->crl_file_inline); + } + dmsg (D_TLS_DEBUG_MED, "STATE S_START"); } diff --git a/src/openvpn/ssl_backend.h b/src/openvpn/ssl_backend.h index 726a621e0a2..0777c61cec1 100644 --- a/src/openvpn/ssl_backend.h +++ b/src/openvpn/ssl_backend.h @@ -345,6 +345,17 @@ void key_state_ssl_init(struct key_state_ssl *ks_ssl, */ void key_state_ssl_free(struct key_state_ssl *ks_ssl); +/** + * Reload the Certificate Revocation List for the SSL channel + * + * @param ssl_ctx The TLS context to use when reloading the CRL + * @param crl_file The file name to load the CRL from, or + * "[[INLINE]]" in the case of inline files. + * @param crl_inline A string containing the CRL + */ +void tls_ctx_reload_crl(struct tls_root_ctx *ssl_ctx, + const char *crl_file, const char *crl_inline); + /** * Keying Material Exporters [RFC 5705] allows additional keying material to be * derived from existing TLS channel. This exported keying material can then be diff --git a/src/openvpn/ssl_mbedtls.c b/src/openvpn/ssl_mbedtls.c index 7f95f14508e..7fa35a70f30 100644 --- a/src/openvpn/ssl_mbedtls.c +++ b/src/openvpn/ssl_mbedtls.c @@ -120,6 +120,12 @@ tls_ctx_free(struct tls_root_ctx *ctx) if (ctx->dhm_ctx) free(ctx->dhm_ctx); + mbedtls_x509_crl_free(ctx->crl); + if (ctx->crl) + { + free(ctx->crl); + } + #if defined(ENABLE_PKCS11) if (ctx->priv_key_pkcs11 != NULL) { mbedtls_pkcs11_priv_key_free(ctx->priv_key_pkcs11); @@ -764,6 +770,41 @@ static void tls_version_to_major_minor(int tls_ver, int *major, int *minor) { } } +void +tls_ctx_reload_crl(struct tls_root_ctx *ctx, const char *crl_file, + const char *crl_inline) +{ + ASSERT (crl_file); + + if (ctx->crl == NULL) + { + ALLOC_OBJ_CLEAR(ctx->crl, mbedtls_x509_crl); + } + mbedtls_x509_crl_free(ctx->crl); + + if (!strcmp (crl_file, INLINE_FILE_TAG) && crl_inline) + { + if (!mbed_ok(mbedtls_x509_crl_parse(ctx->crl, + (const unsigned char *)crl_inline, strlen(crl_inline)+1))) + { + msg (M_WARN, "CRL: cannot parse inline CRL"); + goto err; + } + } + else + { + if (!mbed_ok(mbedtls_x509_crl_parse_file(ctx->crl, crl_file))) + { + msg (M_WARN, "CRL: cannot read CRL from file %s", crl_file); + goto err; + } + } + return; + +err: + mbedtls_x509_crl_free(ctx->crl); +} + void key_state_ssl_init(struct key_state_ssl *ks_ssl, const struct tls_root_ctx *ssl_ctx, bool is_server, struct tls_session *session) { @@ -816,7 +857,7 @@ void key_state_ssl_init(struct key_state_ssl *ks_ssl, mbedtls_ssl_conf_verify (&ks_ssl->ssl_config, verify_callback, session); /* TODO: mbed TLS does not currently support sending the CA chain to the client */ - mbedtls_ssl_conf_ca_chain (&ks_ssl->ssl_config, ssl_ctx->ca_chain, NULL ); + mbedtls_ssl_conf_ca_chain (&ks_ssl->ssl_config, ssl_ctx->ca_chain, ssl_ctx->crl); /* Initialize minimum TLS version */ { diff --git a/src/openvpn/ssl_mbedtls.h b/src/openvpn/ssl_mbedtls.h index 6f778efbe5d..3edeedc4889 100644 --- a/src/openvpn/ssl_mbedtls.h +++ b/src/openvpn/ssl_mbedtls.h @@ -73,6 +73,7 @@ struct tls_root_ctx { mbedtls_x509_crt *crt_chain; /**< Local Certificate chain */ mbedtls_x509_crt *ca_chain; /**< CA chain for remote verification */ mbedtls_pk_context *priv_key; /**< Local private key */ + mbedtls_x509_crl *crl; /**< Certificate Revocation List */ #if defined(ENABLE_PKCS11) mbedtls_pkcs11_context *priv_key_pkcs11; /**< PKCS11 private key */ #endif diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c index 48ca4090b58..51669fcf376 100644 --- a/src/openvpn/ssl_openssl.c +++ b/src/openvpn/ssl_openssl.c @@ -771,6 +771,64 @@ tls_ctx_load_priv_file (struct tls_root_ctx *ctx, const char *priv_key_file, return ret; } +void +tls_ctx_reload_crl(struct tls_root_ctx *ssl_ctx, const char *crl_file, + const char *crl_inline) +{ + X509_CRL *crl = NULL; + BIO *in = NULL; + + X509_STORE *store = SSL_CTX_get_cert_store(ssl_ctx->ctx); + if (!store) + crypto_msg (M_FATAL, "Cannot get certificate store"); + + /* Always start with a cleared CRL list, for that we + * we need to manually find the CRL object from the stack + * and remove it */ + for (int i = 0; i < sk_X509_OBJECT_num(store->objs); i++) + { + X509_OBJECT* obj = sk_X509_OBJECT_value(store->objs, i); + ASSERT(obj); + if (obj->type == X509_LU_CRL) + { + sk_X509_OBJECT_delete(store->objs, i); + X509_OBJECT_free_contents(obj); + OPENSSL_free(obj); + } + } + + X509_STORE_set_flags (store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); + + if (!strcmp (crl_file, INLINE_FILE_TAG) && crl_inline) + in = BIO_new_mem_buf ((char *)crl_inline, -1); + else + in = BIO_new_file (crl_file, "r"); + + if (in == NULL) + { + msg (M_WARN, "CRL: cannot read: %s", crl_file); + goto end; + } + + crl = PEM_read_bio_X509_CRL(in, NULL, NULL, NULL); + if (crl == NULL) + { + msg (M_WARN, "CRL: cannot read CRL from file %s", crl_file); + goto end; + } + + if (!X509_STORE_add_crl(store, crl)) + { + msg (M_WARN, "CRL: cannot add %s to store", crl_file); + goto end; + } + +end: + X509_CRL_free(crl); + BIO_free(in); +} + + #ifdef MANAGMENT_EXTERNAL_KEY /* encrypt */ diff --git a/src/openvpn/ssl_verify.c b/src/openvpn/ssl_verify.c index 0b45972320c..a099776fdc4 100644 --- a/src/openvpn/ssl_verify.c +++ b/src/openvpn/ssl_verify.c @@ -672,15 +672,18 @@ verify_cert(struct tls_session *session, openvpn_x509_cert_t *cert, int cert_dep if (opt->crl_file) { if (opt->ssl_flags & SSLF_CRL_VERIFY_DIR) - { - if (SUCCESS != verify_check_crl_dir(opt->crl_file, cert)) - goto cleanup; - } + { + if (SUCCESS != verify_check_crl_dir(opt->crl_file, cert)) + goto cleanup; + } else - { - if (SUCCESS != x509_verify_crl(opt->crl_file, opt->crl_file_inline, cert, subject)) - goto cleanup; - } + { + if (tls_verify_crl_missing (opt)) + { + msg (D_TLS_ERRORS, "VERIFY ERROR: CRL not loaded"); + goto cleanup; + } + } } msg (D_HANDSHAKE, "VERIFY OK: depth=%d, %s", cert_depth, subject); diff --git a/src/openvpn/ssl_verify_backend.h b/src/openvpn/ssl_verify_backend.h index 91e6ec9300d..de304b9c29f 100644 --- a/src/openvpn/ssl_verify_backend.h +++ b/src/openvpn/ssl_verify_backend.h @@ -252,19 +252,12 @@ result_t x509_verify_cert_eku (openvpn_x509_cert_t *x509, const char * const exp */ result_t x509_write_pem(FILE *peercert_file, openvpn_x509_cert_t *peercert); -/* - * Check the certificate against a CRL file. - * - * @param crl_file File name of the CRL file - * @param cert Certificate to verify - * @param crl_inline Contents of the crl file if it is inlined - * @param subject Subject of the given certificate - * - * @return \c SUCCESS if the CRL was not signed by the issuer of the - * certificate or does not contain an entry for it. - * \c FAILURE otherwise. +/** + * Return true iff a CRL is configured, but is not loaded. This can be caused + * by e.g. a CRL parsing error, a missing CRL file or CRL file permission + * errors. (These conditions are checked upon startup, but the CRL might be + * updated and reloaded during runtime.) */ -result_t x509_verify_crl(const char *crl_file, const char *crl_inline, - openvpn_x509_cert_t *cert, const char *subject); +bool tls_verify_crl_missing(const struct tls_options *opt); #endif /* SSL_VERIFY_BACKEND_H_ */ diff --git a/src/openvpn/ssl_verify_mbedtls.c b/src/openvpn/ssl_verify_mbedtls.c index 92b0804bb5c..332f04bafba 100644 --- a/src/openvpn/ssl_verify_mbedtls.c +++ b/src/openvpn/ssl_verify_mbedtls.c @@ -497,59 +497,15 @@ x509_write_pem(FILE *peercert_file, mbedtls_x509_crt *peercert) return FAILURE; } -/* - * check peer cert against CRL - */ -result_t -x509_verify_crl(const char *crl_file, const char *crl_inline, - mbedtls_x509_crt *cert, const char *subject) +bool +tls_verify_crl_missing(const struct tls_options *opt) { - result_t retval = FAILURE; - mbedtls_x509_crl crl = {0}; - struct gc_arena gc = gc_new(); - char *serial; - - if (!strcmp (crl_file, INLINE_FILE_TAG) && crl_inline) - { - if (!mbed_ok(mbedtls_x509_crl_parse(&crl, - (const unsigned char *)crl_inline, strlen(crl_inline)+1))) - { - msg (M_WARN, "CRL: cannot parse inline CRL"); - goto end; - } - } - else - { - if (!mbed_ok(mbedtls_x509_crl_parse_file(&crl, crl_file))) - { - msg (M_WARN, "CRL: cannot read CRL from file %s", crl_file); - goto end; - } - } - - if(cert->issuer_raw.len != crl.issuer_raw.len || - memcmp(crl.issuer_raw.p, cert->issuer_raw.p, crl.issuer_raw.len) != 0) - { - msg (M_WARN, "CRL: CRL %s is from a different issuer than the issuer of " - "certificate %s", crl_file, subject); - retval = SUCCESS; - goto end; - } - - if (!mbed_ok(mbedtls_x509_crt_is_revoked(cert, &crl))) + if (opt->crl_file && !(opt->ssl_flags & SSLF_CRL_VERIFY_DIR) + && (opt->ssl_ctx.crl == NULL || opt->ssl_ctx.crl->version == 0)) { - serial = backend_x509_get_serial_hex(cert, &gc); - msg (D_HANDSHAKE, "CRL CHECK FAILED: %s (serial %s) is REVOKED", subject, (serial ? serial : "NOT AVAILABLE")); - goto end; + return true; } - - retval = SUCCESS; - msg (D_HANDSHAKE, "CRL CHECK OK: %s",subject); - -end: - gc_free(&gc); - mbedtls_x509_crl_free(&crl); - return retval; + return false; } #endif /* #if defined(ENABLE_CRYPTO) && defined(ENABLE_CRYPTO_MBEDTLS) */ diff --git a/src/openvpn/ssl_verify_openssl.c b/src/openvpn/ssl_verify_openssl.c index a4b94328b36..3d1c85e1119 100644 --- a/src/openvpn/ssl_verify_openssl.c +++ b/src/openvpn/ssl_verify_openssl.c @@ -70,15 +70,28 @@ verify_callback (int preverify_ok, X509_STORE_CTX * ctx) /* get the X509 name */ char *subject = x509_get_subject(ctx->current_cert, &gc); - if (subject) + if (!subject) { - /* Remote site specified a certificate, but it's not correct */ - msg (D_TLS_ERRORS, "VERIFY ERROR: depth=%d, error=%s: %s", - ctx->error_depth, - X509_verify_cert_error_string (ctx->error), - subject); + subject = "(Failed to retrieve certificate subject)"; } + /* Log and ignore missing CRL errors */ + if (ctx->error == X509_V_ERR_UNABLE_TO_GET_CRL) + { + msg (D_TLS_DEBUG_LOW, "VERIFY WARNING: depth=%d, %s: %s", + ctx->error_depth, + X509_verify_cert_error_string (ctx->error), + subject); + ret = 1; + goto cleanup; + } + + /* Remote site specified a certificate, but it's not correct */ + msg (D_TLS_ERRORS, "VERIFY ERROR: depth=%d, error=%s: %s", + ctx->error_depth, + X509_verify_cert_error_string (ctx->error), + subject); + ERR_clear_error(); session->verified = false; @@ -625,63 +638,28 @@ x509_write_pem(FILE *peercert_file, X509 *peercert) return SUCCESS; } -/* - * check peer cert against CRL - */ -result_t -x509_verify_crl(const char *crl_file, const char* crl_inline, - X509 *peer_cert, const char *subject) +bool +tls_verify_crl_missing(const struct tls_options *opt) { - X509_CRL *crl=NULL; - X509_REVOKED *revoked; - BIO *in=NULL; - int n,i; - result_t retval = FAILURE; - struct gc_arena gc = gc_new(); - char *serial; - - if (!strcmp (crl_file, INLINE_FILE_TAG) && crl_inline) - in = BIO_new_mem_buf ((char *)crl_inline, -1); - else - in = BIO_new_file (crl_file, "r"); - - if (in == NULL) { - msg (M_WARN, "CRL: cannot read: %s", crl_file); - goto end; - } - crl=PEM_read_bio_X509_CRL(in,NULL,NULL,NULL); - if (crl == NULL) { - msg (M_WARN, "CRL: cannot read CRL from file %s", crl_file); - goto end; - } - - if (X509_NAME_cmp(X509_CRL_get_issuer(crl), X509_get_issuer_name(peer_cert)) != 0) { - msg (M_WARN, "CRL: CRL %s is from a different issuer than the issuer of " - "certificate %s", crl_file, subject); - retval = SUCCESS; - goto end; - } - - n = sk_X509_REVOKED_num(X509_CRL_get_REVOKED(crl)); - for (i = 0; i < n; i++) { - revoked = (X509_REVOKED *)sk_X509_REVOKED_value(X509_CRL_get_REVOKED(crl), i); - if (ASN1_INTEGER_cmp(revoked->serialNumber, X509_get_serialNumber(peer_cert)) == 0) { - serial = backend_x509_get_serial_hex(peer_cert, &gc); - msg (D_HANDSHAKE, "CRL CHECK FAILED: %s (serial %s) is REVOKED", subject, (serial ? serial : "NOT AVAILABLE")); - goto end; + if (!opt->crl_file || (opt->ssl_flags & SSLF_CRL_VERIFY_DIR)) + { + return false; } - } - - retval = SUCCESS; - msg (D_HANDSHAKE, "CRL CHECK OK: %s",subject); -end: - gc_free(&gc); - BIO_free(in); - if (crl) - X509_CRL_free (crl); + X509_STORE *store = SSL_CTX_get_cert_store(opt->ssl_ctx.ctx); + if (!store) + crypto_msg (M_FATAL, "Cannot get certificate store"); - return retval; + for (int i = 0; i < sk_X509_OBJECT_num(store->objs); i++) + { + X509_OBJECT* obj = sk_X509_OBJECT_value(store->objs, i); + ASSERT(obj); + if (obj->type == X509_LU_CRL) + { + return false; + } + } + return true; } #endif /* defined(ENABLE_CRYPTO) && defined(ENABLE_CRYPTO_OPENSSL) */ From 8d5b06e6fc46e214e1498352603a95028aa5c113 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Tue, 8 Nov 2016 22:28:27 +0100 Subject: [PATCH 384/643] Remove unneeded check for extra_certs_file_inline As with all the file/file_inline variable, the _inline variable is only relevant if the file variable is equal to INLINE_FILE_TAG. The tls_ctx_load_extra_certs() function nicely follows this mantra. Removing this unneeded check silences a coverity 'dereference after null check' warning (tls_ctx_load_extra_certs() always dereferences options->extra_cert_file, and the check implies it might be null). In reality, this cannot occur, because if options->extra_cert_file_inline is non-null, so is options->extra_cert_file. Still, coverity is correct this this check is a bit weird, so let's fix it and make coverity happy. Signed-off-by: Steffan Karger Acked-by: David Sommerseth Message-Id: <1478640507-14415-1-git-send-email-steffan@karger.me> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12978.html Signed-off-by: David Sommerseth --- src/openvpn/ssl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 88aeaadac32..c1951adcc20 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -600,7 +600,7 @@ init_ssl (const struct options *options, struct tls_root_ctx *new_ctx) /* Load extra certificates that are part of our own certificate chain but shouldn't be included in the verify chain */ - if (options->extra_certs_file || options->extra_certs_file_inline) + if (options->extra_certs_file) { tls_ctx_load_extra_certs(new_ctx, options->extra_certs_file, options->extra_certs_file_inline); } From b59fc7f42137a0474c069ab226c4d67c148e504f Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Tue, 8 Nov 2016 21:07:43 +0100 Subject: [PATCH 385/643] Fix missing return value checks in multi_process_float() Fix the missing return value checks on hash_remove() and hash_add() by replacing the calls with an single hash_add() call with the replace parameters set to true so that is can't fail. Then just ASSERT() that this is indeed the case. This also replaces the other add/remove combinations with a single add-replace, because that should be slightly faster (and this is in the 'hot path'). Signed-off-by: Steffan Karger Acked-by: David Sommerseth Message-Id: <1478635663-5837-1-git-send-email-steffan@karger.me> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12968.html Signed-off-by: David Sommerseth --- src/openvpn/multi.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index b497f6ad6d8..8f3d34e160b 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -2317,9 +2317,6 @@ void multi_process_float (struct multi_context* m, struct multi_instance* mi) mroute_addr_print (&mi->real, &gc), print_link_socket_actual (&m->top.c2.from, &gc)); - ASSERT (hash_remove(m->hash, &mi->real)); - ASSERT (hash_remove(m->iter, &mi->real)); - /* change external network address of the remote peer */ mi->real = real; generate_prefix (mi); @@ -2333,12 +2330,11 @@ void multi_process_float (struct multi_context* m, struct multi_instance* mi) tls_update_remote_addr (mi->context.c2.tls_multi, &mi->context.c2.from); - ASSERT (hash_add (m->hash, &mi->real, mi, false)); - ASSERT (hash_add (m->iter, &mi->real, mi, false)); + ASSERT (hash_add (m->hash, &mi->real, mi, true)); + ASSERT (hash_add (m->iter, &mi->real, mi, true)); #ifdef MANAGEMENT_DEF_AUTH - hash_remove (m->cid_hash, &mi->context.c2.mda_context.cid); - hash_add (m->cid_hash, &mi->context.c2.mda_context.cid, mi, false); + ASSERT (hash_add (m->cid_hash, &mi->context.c2.mda_context.cid, mi, true)); #endif done: From 129d2924bb4179b7df4a157a0443c45f2279e92d Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Tue, 1 Nov 2016 20:06:47 +0100 Subject: [PATCH 386/643] Restore pre-NCP cipher options on SIGUSR1 As reported by debbie10t on the openvpn-devel list (Message-ID: <326b8ff7-39a6-1974-c0b0-82fd2abdc7b7@gmail.com>), an NCP client will attempt to reconnect with the previously pushed cipher, instead of the cipher from the config file, after a sigusr1 restart. This can be a problem when the server is reconfigured (as debbie10t explainted), or when roaming to a differently-configured server. Fix this by restoring the cipher options from the config file after a sigusr1 restart. This makes the cipher options behaviour different from other pushable options, because those are also cached until a sighup restart. We might want to change this behaviour in general, but for now let's just fix the issue at hand. v2: also cache and restore keysize, as that parameter is relevant too. v3: inherit cached cipher options from parent context. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1478027207-28651-1-git-send-email-steffan@karger.me> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12869.html Signed-off-by: David Sommerseth --- src/openvpn/init.c | 10 ++++++++++ src/openvpn/openvpn.h | 1 + 2 files changed, 11 insertions(+) diff --git a/src/openvpn/init.c b/src/openvpn/init.c index eaa5e7993d4..a0281475bd4 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -2242,6 +2242,7 @@ do_init_crypto_tls_c1 (struct context *c) c->c1.ciphername = options->ciphername; c->c1.authname = options->authname; + c->c1.keysize = options->keysize; #if 0 /* was: #if ENABLE_INLINE_FILES -- Note that enabling this code will break restarts */ if (options->priv_key_file_inline) @@ -2254,6 +2255,11 @@ do_init_crypto_tls_c1 (struct context *c) else { msg (D_INIT_MEDIUM, "Re-using SSL/TLS context"); + + /* Restore pre-NCP cipher options */ + c->options.ciphername = c->c1.ciphername; + c->options.authname = c->c1.authname; + c->options.keysize = c->c1.keysize; } } @@ -3791,6 +3797,10 @@ inherit_context_child (struct context *dest, dest->c1.ks.ssl_ctx = src->c1.ks.ssl_ctx; dest->c1.ks.tls_auth_key = src->c1.ks.tls_auth_key; dest->c1.ks.tls_auth_key_type = src->c1.ks.tls_auth_key_type; + /* inherit pre-NCP ciphers */ + dest->c1.ciphername = src->c1.ciphername; + dest->c1.authname = src->c1.authname; + dest->c1.keysize = src->c1.keysize; #endif /* options */ diff --git a/src/openvpn/openvpn.h b/src/openvpn/openvpn.h index 5cda7b4519a..4366a42240a 100644 --- a/src/openvpn/openvpn.h +++ b/src/openvpn/openvpn.h @@ -213,6 +213,7 @@ struct context_1 const char *ciphername; /**< Data channel cipher from config file */ const char *authname; /**< Data channel auth from config file */ + int keysize; /**< Data channel keysize from config file */ #endif }; From 4066f1ce602c2404fa4d80ba237e9d24d79e26cd Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Wed, 16 Nov 2016 14:23:04 +0100 Subject: [PATCH 387/643] Remove unused variables from do_init_crypto_static() Commit 28c115e4 refactored the key loading, but forgot to remove these variables from do_init_crypto_static(). Fix that. Signed-off-by: Steffan Karger Acked-by: David Sommerseth Message-Id: <1479302584-28598-1-git-send-email-steffan.karger@fox-it.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13079.html Signed-off-by: David Sommerseth --- src/openvpn/init.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/openvpn/init.c b/src/openvpn/init.c index a0281475bd4..b9693e46fe8 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -2139,9 +2139,6 @@ do_init_crypto_static (struct context *c, const unsigned int flags) if (!key_ctx_bi_defined (&c->c1.ks.static_key)) { - struct key2 key2; - struct key_direction_state kds; - /* Get cipher & hash algorithms */ init_key_type (&c->c1.ks.key_type, options->ciphername, options->authname, options->keysize, options->test_crypto, true); From 7756043c01dd0b23252682f085f3d9a1f4b057de Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Fri, 11 Nov 2016 14:11:13 +0100 Subject: [PATCH 388/643] tun: Fix compiler warnings Fixes two compiler warnings identified by using CFLAGS=-O2 1) ifconfig_ipv6_remote is only used on Solaris, move the declaration and assignment of this variable into the TARGET_SOLARIS block. 2) Linux have it's own open_tun() function and does not depend on open_tun_generic() at all. So exclude open_tun_generic() if TARGET_LINUX is defined. v2 - Move changes from 1) into the proper if() block directly - Fix up incorrect comment tags related to changes in 2) v3 - Minor coding style adjustments and change WIN32 to _WIN32 Signed-off-by: David Sommerseth Acked-by: Gert Doering Message-Id: <1479165185-11730-1-git-send-email-davids@openvpn.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13063.html --- src/openvpn/tun.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index d37e27e763a..3815f0fc8c2 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -751,7 +751,6 @@ do_ifconfig (struct tuntap *tt, const char *ifconfig_remote_netmask = NULL; const char *ifconfig_broadcast = NULL; const char *ifconfig_ipv6_local = NULL; - const char *ifconfig_ipv6_remote = NULL; bool do_ipv6 = false; struct argv argv = argv_new (); @@ -772,7 +771,6 @@ do_ifconfig (struct tuntap *tt, if (tt->did_ifconfig_ipv6_setup ) { ifconfig_ipv6_local = print_in6_addr (tt->local_ipv6, 0, &gc); - ifconfig_ipv6_remote = print_in6_addr (tt->remote_ipv6, 0, &gc); do_ipv6 = true; } @@ -915,7 +913,6 @@ do_ifconfig (struct tuntap *tt, management_android_control (management, "IFCONFIG", buf_bptr(&out)); #elif defined(TARGET_SOLARIS) - /* Solaris 2.6 (and 7?) cannot set all parameters in one go... * example: * ifconfig tun2 10.2.0.2 10.2.0.1 mtu 1450 up @@ -977,6 +974,9 @@ do_ifconfig (struct tuntap *tt, if ( tt->type == DEV_TYPE_TUN ) { + const char *ifconfig_ipv6_remote = + ifconfig_ipv6_remote = print_in6_addr (tt->remote_ipv6, 0, &gc); + argv_printf (&argv, "%s %s inet6 plumb %s/%d %s up", IFCONFIG_PATH, @@ -1502,7 +1502,7 @@ read_tun_header (struct tuntap* tt, uint8_t *buf, int len) #endif -#ifndef _WIN32 +#if !(defined(_WIN32) || defined(TARGET_LINUX)) static void open_tun_generic (const char *dev, const char *dev_type, const char *dev_node, bool dynamic, struct tuntap *tt) @@ -1604,7 +1604,9 @@ open_tun_generic (const char *dev, const char *dev_type, const char *dev_node, tt->actual_name = string_alloc (dynamic_opened ? dynamic_name : dev, NULL); } } +#endif /* !_WIN32 && !TARGET_LINUX */ +#if !defined(_WIN32) static void close_tun_generic (struct tuntap *tt) { @@ -1614,8 +1616,7 @@ close_tun_generic (struct tuntap *tt) free (tt->actual_name); clear_tuntap (tt); } - -#endif +#endif /* !_WIN32 */ #if defined (TARGET_ANDROID) void From 05de0a6e8fb675e309d599a185e70a1c54b8e7e9 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Mon, 14 Nov 2016 23:45:08 +0100 Subject: [PATCH 389/643] file checks: Merge warn_if_group_others_accessible() into check_file_access() Commit 825e2ec1f358f2e8 cleaned up the usage of warn_if_group_others_accessible() and moved it into options.c. At this point there is only one caller of this function, check_file_access(). This takes that clean-up one step further and merges everything into check_file_access(). In addition it removes some no longer needed #ifdefs and uses platform_stat() to allow a similar check to happen on the Windows platform as well. Signed-off-by: David Sommerseth Acked-by: Steffan Karger Message-Id: <1479163508-19435-1-git-send-email-davids@openvpn.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13062.html --- src/openvpn/options.c | 38 ++++++++++++-------------------------- 1 file changed, 12 insertions(+), 26 deletions(-) diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 443f96b15d9..e88aa958f91 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -57,6 +57,7 @@ #include "manage.h" #include "forward.h" #include "ssl_verify.h" +#include "platform.h" #include #include "memdbg.h" @@ -2683,31 +2684,6 @@ options_postprocess_mutate (struct options *o) */ #ifndef ENABLE_SMALL /** Expect people using the stripped down version to know what they do */ -/* - * Warn if a given file is group/others accessible. - */ -static void -warn_if_group_others_accessible (const char* filename) -{ -#ifndef _WIN32 -#ifdef HAVE_STAT - if (strcmp (filename, INLINE_FILE_TAG)) - { - struct stat st; - if (stat (filename, &st)) - { - msg (M_WARN | M_ERRNO, "WARNING: cannot stat file '%s'", filename); - } - else - { - if (st.st_mode & (S_IRWXG|S_IRWXO)) - msg (M_WARN, "WARNING: file '%s' is group or others accessible", filename); - } - } -#endif -#endif -} - #define CHKACC_FILE (1<<0) /** Check for a file/directory precense */ #define CHKACC_DIRPATH (1<<1) /** Check for directory precense where a file should reside */ #define CHKACC_FILEXSTWR (1<<2) /** If file exists, is it writable? */ @@ -2754,9 +2730,19 @@ check_file_access(const int type, const char *file, const int mode, const char * if (platform_access (file, W_OK) != 0) errcode = errno; + /* Warn if a given private file is group/others accessible. */ if (type & CHKACC_PRIVATE) { - warn_if_group_others_accessible (file); + platform_stat_t st; + if (platform_stat (file, &st)) + { + msg (M_WARN | M_ERRNO, "WARNING: cannot stat file '%s'", file); + } + else + { + if (st.st_mode & (S_IRWXG|S_IRWXO)) + msg (M_WARN, "WARNING: file '%s' is group or others accessible", file); + } } /* Scream if an error is found */ From 7aea4901034c436a539a997b6a504c009496f6f5 Mon Sep 17 00:00:00 2001 From: Selva Nair Date: Wed, 16 Nov 2016 13:23:13 -0500 Subject: [PATCH 390/643] Unbreak windows build S_IRWXG, S_IRWXO are not defined in mingw headers. Anyway these bits are not defined in st_mode on Windows, so just skip the test. Signed-off-by: Selva Nair Acked-by: Gert Doering Message-Id: <1479320593-27099-1-git-send-email-selva.nair@gmail.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13100.html Signed-off-by: Gert Doering --- src/openvpn/options.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/openvpn/options.c b/src/openvpn/options.c index e88aa958f91..44402a94a21 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -2738,11 +2738,13 @@ check_file_access(const int type, const char *file, const int mode, const char * { msg (M_WARN | M_ERRNO, "WARNING: cannot stat file '%s'", file); } +#ifndef _WIN32 else { if (st.st_mode & (S_IRWXG|S_IRWXO)) msg (M_WARN, "WARNING: file '%s' is group or others accessible", file); } +#endif } /* Scream if an error is found */ From 1de37f3b194e56ff3245b9e6cf22eaff54ca3efe Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Wed, 16 Nov 2016 19:38:15 +0100 Subject: [PATCH 391/643] tun: Fix weird commit error causing a double assignment When committing 7756043c01dd0b, something odd happened causing the patch to have a duplicate 'ifconfig_ipv6_remote =' assignment. Signed-off-by: David Sommerseth Acked-by: Gert Doering Message-Id: <1479321495-1339-1-git-send-email-davids@openvpn.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13103.html Signed-off-by: Gert Doering --- src/openvpn/tun.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index 3815f0fc8c2..77ae72fa804 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -975,7 +975,7 @@ do_ifconfig (struct tuntap *tt, if ( tt->type == DEV_TYPE_TUN ) { const char *ifconfig_ipv6_remote = - ifconfig_ipv6_remote = print_in6_addr (tt->remote_ipv6, 0, &gc); + print_in6_addr (tt->remote_ipv6, 0, &gc); argv_printf (&argv, "%s %s inet6 plumb %s/%d %s up", From c6e24fa3e16c32f9b427e360fd07102f613aa5c6 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Tue, 15 Nov 2016 14:29:46 +0100 Subject: [PATCH 392/643] Add control channel encryption (--tls-crypt) This adds a --tls-crypt option, which uses a pre-shared static key (like the --tls-auth key) to encrypt control channel packets. Encrypting control channel packets has three main advantages: * It provides more privacy by hiding the certificate used for the TLS connection. * It is harder to identify OpenVPN traffic as such. * It provides "poor-man's" post-quantum security, against attackers who will never know the pre-shared key (i.e. no forward secrecy). Control channel packet encryption --------------------------------- We propose to use the following encryption method, based on the SIV construction [0], to achieve nonce misuse-resistant authenticated encryption: msg = control channel plaintext header = opcode (1 byte) || session_id (8 bytes) || packet_id (8 bytes) Ka = authentication key (256 bits) Ke = encryption key (256 bits) (Ka and Ke are pre-shared keys, like with --tls-auth) auth_tag = HMAC-SHA256(Ka, header || msg) IV = 128 most-significant bits of auth_tag ciph = AES256-CTR(Ke, IV, msg) output = Header || Tag || Ciph This boils down to the following on-the-wire packet format: -opcode- || -session_id- || -packet_id- || auth_tag || * payload * Where - XXX - means authenticated, and * XXX * means authenticated and encrypted. Which is very similar to the current tls-auth packet format, and has the same overhead as "--tls-auth" with "--auth SHA256". The use of a nonce misuse-resistant authenticated encryption scheme allows us to worry less about the risks of nonce collisions. This is important, because in contrast with the data channel in TLS mode, we will not be able to rotate tls-crypt keys often or fully guarantee nonce uniqueness. For non misuse-resistant modes such as GCM [1], [2], the data channel in TLS mode only has to ensure that the packet counter never rolls over, while tls-crypt would have to provide nonce uniqueness over all control channel packets sent by all clients, for the lifetime of the tls-crypt key. Unlike with tls-auth, no --key-direction has to be specified for tls-crypt. TLS servers always use key direction 1, and TLS clients always use key direction 2, which means that client->server traffic and server->client traffic always use different keys, without requiring configuration. Using fixed, secure, encryption and authentication algorithms makes both implementation and configuration easier. If we ever want to, we can extend this to support other crypto primitives. Since tls-crypt should provide privacy as well as DoS protection, these should not be made negotiable. Security considerations: ------------------------ tls-crypt is a best-effort mechanism that aims to provide as much privacy and security as possible, while staying as simple as possible. The following are some security considerations for this scheme. 1. The same tls-crypt key is potentially shared by a lot of peers, so it is quite likely to get compromised. Once an attacker acquires the tls-crypt key, this mechanism no longer provides any security against the attacker. 2. Since many peers potentially use the tls-crypt key for a long time, a lot of data might be encrypted under the tls-crypt key. This leads to two potential problems: * The "opcode || session id || packet id" combination might collide. This might happen in larger setups, because the session id contains just 64 bits or random. Using the uniqueness requirement from the GCM spec [3] (a collision probability of less than 2^(-32)), uniqueness is achieved when using the tls-crypt key for at most 2^16 (65536) connections per process start. (The packet id includes the daemon start time in the packet ID, which should be different after stopping and (re)starting OpenPVN.) And if a collision happens, an attacker can *only* learn whether colliding packets contain the same plaintext. Attackers will not be able to learn anything else about the plaintext (unless the attacker knows the plaintext of one of these packets, of course). Since the impact is limited, I consider this an acceptable remaining risk. * The IVs used in encryption might collide. When two IVs collide, an attacker can learn the xor of the two plaintexts by xorring the ciphertexts. This is a serious loss of confidentiality. The IVs are 128-bit, so when HMAC-SHA256 is a secure PRF (an assumption that must also hold for TLS), and we use the same uniqueness requirement from [3], this limits the total amount of control channel messages for all peers in the setup to 2^48. Assuming a large setup of 2^16 (65536) clients, and a (conservative) number of 2^16 control channel packets per connection on average, this means that clients may set up 2^16 connections on average. I think these numbers are reasonable. (I have a follow-up proposal to use client-specific tls-auth/tls-crypt keys to partially mitigate these issues, but let's tackle this patch first.) References: ----------- [0] Rogaway & Shrimpton, A Provable-Security Treatment of the Key-Wrap Problem, 2006 (https://www.iacr.org/archive/eurocrypt2006/40040377/40040377.pdf) [1] Ferguson, Authentication weaknesses in GCM, 2005 (http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/comments/CWC-GCM/Ferg uson2.pdf) [2] Joux, Authentication Failures in NIST version of GCM, 2006 (http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/comments/800-38_Serie s-Drafts/GCM/Joux_comments.pdf) [3] Dworking, Recommendation for Block Cipher Modes of Operation: Galois/Counter Mode (GCM) and GMAC, 2007 (http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf) Patch history: -------------- v2 - processed Arne's review comments: * Error out early with a clear error message when AES-256-CTR or HMAC-SHA-256 are not supported by the crypto library. * Clarify that cipher_ctx_reset() sets the IV. v3 - actually add error messages promised in v2... Signed-off-by: Steffan Karger Acked-by: Arne Schwabe Message-Id: <1479216586-20078-1-git-send-email-steffan.karger@fox-it.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13069.html Signed-off-by: Gert Doering --- Changes.rst | 5 + doc/openvpn.8 | 39 +++++- src/openvpn/Makefile.am | 1 + src/openvpn/crypto.c | 17 +-- src/openvpn/crypto.h | 18 +++ src/openvpn/init.c | 30 ++++- src/openvpn/openvpn.h | 4 +- src/openvpn/options.c | 31 ++++- src/openvpn/options.h | 8 +- src/openvpn/ssl.c | 119 +++++++++++------- src/openvpn/ssl.h | 2 +- src/openvpn/ssl_common.h | 18 ++- src/openvpn/tls_crypt.c | 254 +++++++++++++++++++++++++++++++++++++++ src/openvpn/tls_crypt.h | 144 ++++++++++++++++++++++ 14 files changed, 612 insertions(+), 78 deletions(-) create mode 100644 src/openvpn/tls_crypt.c create mode 100644 src/openvpn/tls_crypt.h diff --git a/Changes.rst b/Changes.rst index f57b750c4ef..0d1ff40c739 100644 --- a/Changes.rst +++ b/Changes.rst @@ -111,6 +111,11 @@ AIX platform support AIX platform support has been added. The support only includes tap devices since AIX does not provide tun interface. +Control channel encryption (``--tls-crypt``) + Use a pre-shared static key (like the ``--tls-auth`` key) to encrypt control + channel packets. Provides more privacy, some obfuscation and poor-man's + post-quantum security. + Deprecated features ------------------- diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 7227d224606..4c52cb6a1c8 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -3471,8 +3471,10 @@ DoS scenario, legitimate connections might also be refused. For the best protection against DoS attacks in server mode, use .B \-\-proto udp -and -.B \-\-tls\-auth. +and either +.B \-\-tls\-auth +or +.B \-\-tls\-crypt\fR. .\"********************************************************* .TP .B \-\-learn\-address cmd @@ -4938,8 +4940,8 @@ Exit on TLS negotiation failure. .\"********************************************************* .TP .B \-\-tls\-auth file [direction] -Add an additional layer of HMAC authentication on top of the TLS -control channel to protect against DoS attacks. +Add an additional layer of HMAC authentication on top of the TLS control channel +to mitigate DoS attacks and attacks on the TLS stack. In a nutshell, .B \-\-tls\-auth @@ -5010,12 +5012,39 @@ option which will keep OpenVPN's replay protection state in a file so that it is not lost across restarts. It should be emphasized that this feature is optional and that the -passphrase/key file used with +key file used with .B \-\-tls\-auth gives a peer nothing more than the power to initiate a TLS handshake. It is not used to encrypt or authenticate any tunnel data. .\"********************************************************* .TP +.B \-\-tls\-crypt keyfile + +Encrypt and authenticate all control channel packets with the key from +.B keyfile. +(See +.B \-\-tls\-auth +for more background.) + +Encrypting (and authenticating) control channel packets: +.RS +.IP \[bu] 2 +provides more privacy by hiding the certificate used for the TLS connection, +.IP \[bu] +makes it harder to identify OpenVPN traffic as such, +.IP \[bu] +provides "poor-man's" post-quantum security, against attackers who will never +know the pre-shared key (i.e. no forward secrecy). +.RE + +.IP +In contrast to +.B \-\-tls\-auth\fR, +.B \-\-tls\-crypt +does *not* require the user to set +.B \-\-key\-direction\fR. +.\"********************************************************* +.TP .B \-\-askpass [file] Get certificate password from console or .B file diff --git a/src/openvpn/Makefile.am b/src/openvpn/Makefile.am index 12b9ebf4091..4c18449b5ed 100644 --- a/src/openvpn/Makefile.am +++ b/src/openvpn/Makefile.am @@ -113,6 +113,7 @@ openvpn_SOURCES = \ ssl_verify_mbedtls.c ssl_verify_mbedtls.h \ status.c status.h \ syshead.h \ + tls_crypt.c tls_crypt.h \ tun.c tun.h \ win32.h win32.c \ cryptoapi.h cryptoapi.c diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c index 8b2f460e3ac..05622ceea48 100644 --- a/src/openvpn/crypto.c +++ b/src/openvpn/crypto.c @@ -6,7 +6,7 @@ * packet compression. * * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. - * Copyright (C) 2010 Fox Crypto B.V. + * Copyright (C) 2010-2016 Fox Crypto B.V. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -63,9 +63,6 @@ * happen unless the frame parameters are wrong. */ -#define CRYPT_ERROR(format) \ - do { msg (D_CRYPT_ERRORS, "%s: " format, error_prefix); goto error_exit; } while (false) - static void openvpn_encrypt_aead (struct buffer *buf, struct buffer work, struct crypto_options *opt) { @@ -326,17 +323,7 @@ openvpn_encrypt (struct buffer *buf, struct buffer work, } } -/** - * Check packet ID for replay, and perform replay administration. - * - * @param opt Crypto options for this packet, contains replay state. - * @param pin Packet ID read from packet. - * @param error_prefix Prefix to use when printing error messages. - * @param gc Garbage collector to use. - * - * @return true if packet ID is validated to be not a replay, false otherwise. - */ -static bool crypto_check_replay(struct crypto_options *opt, +bool crypto_check_replay(struct crypto_options *opt, const struct packet_id_net *pin, const char *error_prefix, struct gc_arena *gc) { bool ret = false; diff --git a/src/openvpn/crypto.h b/src/openvpn/crypto.h index bc9630a7f17..ff9074579bd 100644 --- a/src/openvpn/crypto.h +++ b/src/openvpn/crypto.h @@ -266,6 +266,9 @@ struct crypto_options * security operation functions. */ }; +#define CRYPT_ERROR(format) \ + do { msg (D_CRYPT_ERRORS, "%s: " format, error_prefix); goto error_exit; } while (false) + /** * Minimal IV length for AEAD mode ciphers (in bytes): * 4-byte packet id + 8 bytes implicit IV. @@ -397,6 +400,21 @@ bool openvpn_decrypt (struct buffer *buf, struct buffer work, /** @} name Functions for performing security operations on data channel packets */ +/** + * Check packet ID for replay, and perform replay administration. + * + * @param opt Crypto options for this packet, contains replay state. + * @param pin Packet ID read from packet. + * @param error_prefix Prefix to use when printing error messages. + * @param gc Garbage collector to use. + * + * @return true if packet ID is validated to be not a replay, false otherwise. + */ +bool crypto_check_replay(struct crypto_options *opt, + const struct packet_id_net *pin, const char *error_prefix, + struct gc_arena *gc); + + /** Calculate crypto overhead and adjust frame to account for that */ void crypto_adjust_frame_parameters(struct frame *frame, const struct key_type* kt, diff --git a/src/openvpn/init.c b/src/openvpn/init.c index b9693e46fe8..470dc89af03 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -44,6 +44,7 @@ #include "ping.h" #include "mstats.h" #include "ssl_verify.h" +#include "tls_crypt.h" #include "forward-inline.h" #include "memdbg.h" @@ -2078,7 +2079,7 @@ key_schedule_free (struct key_schedule *ks, bool free_ssl_ctx) if (tls_ctx_initialised(&ks->ssl_ctx) && free_ssl_ctx) { tls_ctx_free (&ks->ssl_ctx); - free_key_ctx_bi (&ks->tls_auth_key); + free_key_ctx_bi (&ks->tls_wrap_key); } #endif /* ENABLE_CRYPTO */ CLEAR (*ks); @@ -2232,11 +2233,17 @@ do_init_crypto_tls_c1 (struct context *c) } crypto_read_openvpn_key (&c->c1.ks.tls_auth_key_type, - &c->c1.ks.tls_auth_key, options->tls_auth_file, + &c->c1.ks.tls_wrap_key, options->tls_auth_file, options->tls_auth_file_inline, options->key_direction, "Control Channel Authentication", "tls-auth"); } + /* TLS handshake encryption+authentication (--tls-crypt) */ + if (options->tls_crypt_file) { + tls_crypt_init_key (&c->c1.ks.tls_wrap_key, options->tls_crypt_file, + options->tls_crypt_inline, options->tls_server); + } + c->c1.ciphername = options->ciphername; c->c1.authname = options->authname; c->c1.keysize = options->keysize; @@ -2421,14 +2428,25 @@ do_init_crypto_tls (struct context *c, const unsigned int flags) /* TLS handshake authentication (--tls-auth) */ if (options->tls_auth_file) { - to.tls_auth.key_ctx_bi = c->c1.ks.tls_auth_key; - to.tls_auth.pid_persist = &c->c1.pid_persist; - to.tls_auth.flags |= CO_PACKET_ID_LONG_FORM; + to.tls_wrap.mode = TLS_WRAP_AUTH; + to.tls_wrap.opt.key_ctx_bi = c->c1.ks.tls_wrap_key; + to.tls_wrap.opt.pid_persist = &c->c1.pid_persist; + to.tls_wrap.opt.flags |= CO_PACKET_ID_LONG_FORM; crypto_adjust_frame_parameters (&to.frame, &c->c1.ks.tls_auth_key_type, false, true, true); } + /* TLS handshake encryption (--tls-crypt) */ + if (options->tls_crypt_file) + { + to.tls_wrap.mode = TLS_WRAP_CRYPT; + to.tls_wrap.opt.key_ctx_bi = c->c1.ks.tls_wrap_key; + to.tls_wrap.opt.pid_persist = &c->c1.pid_persist; + to.tls_wrap.opt.flags |= CO_PACKET_ID_LONG_FORM; + tls_crypt_adjust_frame_parameters (&to.frame); + } + /* If we are running over TCP, allow for length prefix */ socket_adjust_frame_parameters (&to.frame, options->ce.proto); @@ -3792,7 +3810,7 @@ inherit_context_child (struct context *dest, dest->c1.ks.key_type = src->c1.ks.key_type; /* inherit SSL context */ dest->c1.ks.ssl_ctx = src->c1.ks.ssl_ctx; - dest->c1.ks.tls_auth_key = src->c1.ks.tls_auth_key; + dest->c1.ks.tls_wrap_key = src->c1.ks.tls_wrap_key; dest->c1.ks.tls_auth_key_type = src->c1.ks.tls_auth_key_type; /* inherit pre-NCP ciphers */ dest->c1.ciphername = src->c1.ciphername; diff --git a/src/openvpn/openvpn.h b/src/openvpn/openvpn.h index 4366a42240a..fa5cc1d58a8 100644 --- a/src/openvpn/openvpn.h +++ b/src/openvpn/openvpn.h @@ -65,9 +65,9 @@ struct key_schedule /* our global SSL context */ struct tls_root_ctx ssl_ctx; - /* optional authentication HMAC key for TLS control channel */ + /* optional TLS control channel wrapping */ struct key_type tls_auth_key_type; - struct key_ctx_bi tls_auth_key; + struct key_ctx_bi tls_wrap_key; #else /* ENABLE_CRYPTO */ int dummy; #endif /* ENABLE_CRYPTO */ diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 44402a94a21..21c8b84d2a6 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -611,10 +611,17 @@ static const char usage_message[] = "--single-session: Allow only one session (reset state on restart).\n" "--tls-exit : Exit on TLS negotiation failure.\n" "--tls-auth f [d]: Add an additional layer of authentication on top of the TLS\n" - " control channel to protect against DoS attacks.\n" - " f (required) is a shared-secret passphrase file.\n" + " control channel to protect against attacks on the TLS stack\n" + " and DoS attacks.\n" + " f (required) is a shared-secret key file.\n" " The optional d parameter controls key directionality,\n" " see --secret option for more info.\n" + "--tls-crypt key : Add an additional layer of authenticated encryption on top\n" + " of the TLS control channel to hide the TLS certificate,\n" + " provide basic post-quantum security and protect against\n" + " attacks on the TLS stack and DoS attacks.\n" + " key (required) provides the pre-shared key file.\n" + " see --secret option for more info.\n" "--askpass [file]: Get PEM password from controlling tty before we daemonize.\n" "--auth-nocache : Don't cache --askpass or --auth-user-pass passwords.\n" "--crl-verify crl ['dir']: Check peer certificate against a CRL.\n" @@ -1710,6 +1717,7 @@ show_settings (const struct options *o) SHOW_BOOL (tls_exit); SHOW_STR (tls_auth_file); + SHOW_STR (tls_crypt_file); #endif /* ENABLE_CRYPTO */ #ifdef ENABLE_PKCS11 @@ -2384,6 +2392,10 @@ options_postprocess_verify_ce (const struct options *options, const struct conne notnull (options->priv_key_file, "private key file (--key) or PKCS#12 file (--pkcs12)"); } } + if (options->tls_auth_file && options->tls_crypt_file) + { + msg (M_USAGE, "--tls-auth and --tls-crypt are mutually exclusive"); + } } else { @@ -2415,6 +2427,7 @@ options_postprocess_verify_ce (const struct options *options, const struct conne MUST_BE_UNDEF (handshake_window); MUST_BE_UNDEF (transition_window); MUST_BE_UNDEF (tls_auth_file); + MUST_BE_UNDEF (tls_crypt_file); MUST_BE_UNDEF (single_session); #ifdef ENABLE_PUSH_PEER_INFO MUST_BE_UNDEF (push_peer_info); @@ -2879,6 +2892,8 @@ options_postprocess_filechecks (struct options *options) errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE|CHKACC_PRIVATE, options->tls_auth_file, R_OK, "--tls-auth"); + errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE|CHKACC_PRIVATE, + options->tls_crypt_file, R_OK, "--tls-crypt"); errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE|CHKACC_PRIVATE, options->shared_secret_file, R_OK, "--secret"); errs |= check_file_access (CHKACC_DIRPATH|CHKACC_FILEXSTWR, @@ -3220,6 +3235,9 @@ options_string (const struct options *o, { if (o->tls_auth_file) buf_printf (&out, ",tls-auth"); + /* Not adding tls-crypt here, because we won't reach this code if + * tls-auth/tls-crypt does not match. Removing tls-auth here would + * break stuff, so leaving that in place. */ if (o->key_method > 1) buf_printf (&out, ",key-method %d", o->key_method); @@ -7242,6 +7260,15 @@ add_option (struct options *options, } options->tls_auth_file = p[1]; } + else if (streq (p[0], "tls-crypt") && p[1] && !p[3]) + { + VERIFY_PERMISSION (OPT_P_GENERAL); + if (streq (p[1], INLINE_FILE_TAG) && p[2]) + { + options->tls_crypt_inline = p[2]; + } + options->tls_crypt_file = p[1]; + } else if (streq (p[0], "key-method") && p[1] && !p[2]) { int key_method; diff --git a/src/openvpn/options.h b/src/openvpn/options.h index d51150bf89e..a02855613b3 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -558,10 +558,14 @@ struct options /* Old key allowed to live n seconds after new key goes active */ int transition_window; - /* Special authentication MAC for TLS control channel */ - const char *tls_auth_file; /* shared secret */ + /* Shared secret used for TLS control channel authentication */ + const char *tls_auth_file; const char *tls_auth_file_inline; + /* Shared secret used for TLS control channel authenticated encryption */ + const char *tls_crypt_file; + const char *tls_crypt_inline; + /* Allow only one session */ bool single_session; diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index c1951adcc20..dc063501d47 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -57,6 +57,7 @@ #include "gremlin.h" #include "pkcs11.h" #include "route.h" +#include "tls_crypt.h" #include "ssl.h" #include "ssl_verify.h" @@ -971,16 +972,18 @@ tls_session_init (struct tls_multi *multi, struct tls_session *session) } /* Initialize control channel authentication parameters */ - session->tls_auth = session->opt->tls_auth; + session->tls_wrap = session->opt->tls_wrap; + session->tls_wrap.work = alloc_buf (TLS_CHANNEL_BUF_SIZE); /* initialize packet ID replay window for --tls-auth */ - packet_id_init (&session->tls_auth.packet_id, + packet_id_init (&session->tls_wrap.opt.packet_id, session->opt->replay_window, session->opt->replay_time, - "TLS_AUTH", session->key_id); + "TLS_WRAP", session->key_id); /* load most recent packet-id to replay protect on --tls-auth */ - packet_id_persist_load_obj (session->tls_auth.pid_persist, &session->tls_auth.packet_id); + packet_id_persist_load_obj (session->tls_wrap.opt.pid_persist, + &session->tls_wrap.opt.packet_id); key_state_init (session, &session->key[KS_PRIMARY]); @@ -1007,8 +1010,10 @@ tls_session_free (struct tls_session *session, bool clear) { int i; - if (packet_id_initialized(&session->tls_auth.packet_id)) - packet_id_free (&session->tls_auth.packet_id); + if (packet_id_initialized(&session->tls_wrap.opt.packet_id)) + packet_id_free (&session->tls_wrap.opt.packet_id); + + free_buf (&session->tls_wrap.work); for (i = 0; i < KS_SIZE; ++i) key_state_free (&session->key[i], false); @@ -1140,9 +1145,14 @@ tls_auth_standalone_init (struct tls_options *tls_options, ALLOC_OBJ_CLEAR_GC (tas, struct tls_auth_standalone, gc); - /* set up pointer to HMAC object for TLS packet authentication */ - tas->tls_auth_options.key_ctx_bi = tls_options->tls_auth.key_ctx_bi; - tas->tls_auth_options.flags |= CO_PACKET_ID_LONG_FORM; + tas->tls_wrap = tls_options->tls_wrap; + + /* + * Standalone tls-auth is in read-only mode with respect to TLS + * control channel state. After we build a new client instance + * object, we will process this session-initiating packet for real. + */ + tas->tls_wrap.opt.flags |= CO_IGNORE_PACKET_ID; /* get initial frame parms, still need to finalize */ tas->frame = tls_options->frame; @@ -1289,20 +1299,34 @@ write_control_auth (struct tls_session *session, int max_ack, bool prepend_ack) { - uint8_t *header; + uint8_t header = ks->key_id | (opcode << P_OPCODE_SHIFT); struct buffer null = clear_buf (); ASSERT (link_socket_actual_defined (&ks->remote_addr)); ASSERT (reliable_ack_write (ks->rec_ack, buf, &ks->session_id_remote, max_ack, prepend_ack)); - ASSERT (session_id_write_prepend (&session->session_id, buf)); - ASSERT (header = buf_prepend (buf, 1)); - *header = ks->key_id | (opcode << P_OPCODE_SHIFT); - if (session->tls_auth.key_ctx_bi.encrypt.hmac) + + if (session->tls_wrap.mode == TLS_WRAP_AUTH || + session->tls_wrap.mode == TLS_WRAP_NONE) + { + ASSERT (session_id_write_prepend (&session->session_id, buf)); + ASSERT (buf_write_prepend (buf, &header, sizeof(header))); + } + if (session->tls_wrap.mode == TLS_WRAP_AUTH) { /* no encryption, only write hmac */ - openvpn_encrypt (buf, null, &session->tls_auth); - ASSERT (swap_hmac (buf, &session->tls_auth, false)); + openvpn_encrypt (buf, null, &session->tls_wrap.opt); + ASSERT (swap_hmac (buf, &session->tls_wrap.opt, false)); + } + else if (session->tls_wrap.mode == TLS_WRAP_CRYPT) + { + buf_init (&session->tls_wrap.work, buf->offset); + ASSERT (buf_write (&session->tls_wrap.work, &header, sizeof(header))); + ASSERT (session_id_write (&session->session_id, &session->tls_wrap.work)); + ASSERT (tls_crypt_wrap (buf, &session->tls_wrap.work, &session->tls_wrap.opt)); + /* Don't change the original data in buf, it's used by the reliability + * layer to resend on failure. */ + *buf = session->tls_wrap.work; } *to_link_addr = &ks->remote_addr; } @@ -1312,17 +1336,18 @@ write_control_auth (struct tls_session *session, */ static bool read_control_auth (struct buffer *buf, - struct crypto_options *co, + struct tls_wrap_ctx *ctx, const struct link_socket_actual *from) { struct gc_arena gc = gc_new (); + bool ret = false; - if (co->key_ctx_bi.decrypt.hmac) + if (ctx->mode == TLS_WRAP_AUTH) { struct buffer null = clear_buf (); /* move the hmac record to the front of the packet */ - if (!swap_hmac (buf, co, true)) + if (!swap_hmac (buf, &ctx->opt, true)) { msg (D_TLS_ERRORS, "TLS Error: cannot locate HMAC in incoming packet from %s", @@ -1333,24 +1358,41 @@ read_control_auth (struct buffer *buf, /* authenticate only (no decrypt) and remove the hmac record from the head of the buffer */ - openvpn_decrypt (buf, null, co, NULL, BPTR (buf)); + openvpn_decrypt (buf, null, &ctx->opt, NULL, BPTR (buf)); if (!buf->len) { msg (D_TLS_ERRORS, "TLS Error: incoming packet authentication failed from %s", print_link_socket_actual (from, &gc)); - gc_free (&gc); - return false; + goto cleanup; } } + else if (ctx->mode == TLS_WRAP_CRYPT) + { + struct buffer tmp = alloc_buf (buf_forward_capacity_total (buf)); + if (!tls_crypt_unwrap (buf, &tmp, &ctx->opt)) + { + msg (D_TLS_ERRORS, "TLS Error: tls-crypt unwrapping failed from %s", + print_link_socket_actual (from, &gc)); + goto cleanup; + } + ASSERT (buf_init (buf, buf->offset)); + ASSERT (buf_copy (buf, &tmp)); + free_buf (&tmp); + } - /* advance buffer pointer past opcode & session_id since our caller - already read it */ - buf_advance (buf, SID_SIZE + 1); + if (ctx->mode == TLS_WRAP_NONE || ctx->mode == TLS_WRAP_AUTH) + { + /* advance buffer pointer past opcode & session_id since our caller + already read it */ + buf_advance (buf, SID_SIZE + 1); + } + ret = true; +cleanup: gc_free (&gc); - return true; + return ret; } /* @@ -2731,11 +2773,11 @@ tls_process (struct tls_multi *multi, /* Send 1 or more ACKs (each received control packet gets one ACK) */ if (!to_link->len && !reliable_ack_empty (ks->rec_ack)) { - buf = &ks->ack_write_buf; - ASSERT (buf_init (buf, FRAME_HEADROOM (&multi->opt.frame))); - write_control_auth (session, ks, buf, to_link_addr, P_ACK_V1, + struct buffer buf = ks->ack_write_buf; + ASSERT (buf_init (&buf, FRAME_HEADROOM (&multi->opt.frame))); + write_control_auth (session, ks, &buf, to_link_addr, P_ACK_V1, RELIABLE_ACK_SIZE, false); - *to_link = *buf; + *to_link = buf; active = true; state_change = true; dmsg (D_TLS_DEBUG, "Dedicated ACK -> TCP/UDP"); @@ -3233,7 +3275,7 @@ tls_pre_decrypt (struct tls_multi *multi, goto error; } - if (!read_control_auth (buf, &session->tls_auth, from)) + if (!read_control_auth (buf, &session->tls_wrap, from)) goto error; /* @@ -3284,7 +3326,7 @@ tls_pre_decrypt (struct tls_multi *multi, if (op == P_CONTROL_SOFT_RESET_V1 && DECRYPT_KEY_ENABLED (multi, ks)) { - if (!read_control_auth (buf, &session->tls_auth, from)) + if (!read_control_auth (buf, &session->tls_wrap, from)) goto error; key_state_soft_reset (session); @@ -3301,7 +3343,7 @@ tls_pre_decrypt (struct tls_multi *multi, if (op == P_CONTROL_SOFT_RESET_V1) do_burst = true; - if (!read_control_auth (buf, &session->tls_auth, from)) + if (!read_control_auth (buf, &session->tls_wrap, from)) goto error; dmsg (D_TLS_DEBUG, @@ -3491,18 +3533,11 @@ tls_pre_decrypt_lite (const struct tls_auth_standalone *tas, { struct buffer newbuf = clone_buf (buf); - struct crypto_options co = tas->tls_auth_options; + struct tls_wrap_ctx tls_wrap_tmp = tas->tls_wrap; bool status; - /* - * We are in read-only mode at this point with respect to TLS - * control channel state. After we build a new client instance - * object, we will process this session-initiating packet for real. - */ - co.flags |= CO_IGNORE_PACKET_ID; - /* HMAC test, if --tls-auth was specified */ - status = read_control_auth (&newbuf, &co, from); + status = read_control_auth (&newbuf, &tls_wrap_tmp, from); free_buf (&newbuf); if (!status) goto error; diff --git a/src/openvpn/ssl.h b/src/openvpn/ssl.h index e6963a4c274..777b62165c9 100644 --- a/src/openvpn/ssl.h +++ b/src/openvpn/ssl.h @@ -136,7 +136,7 @@ */ struct tls_auth_standalone { - struct crypto_options tls_auth_options; + struct tls_wrap_ctx tls_wrap; struct frame frame; }; diff --git a/src/openvpn/ssl_common.h b/src/openvpn/ssl_common.h index b04a24c3dc1..28702af1d7c 100644 --- a/src/openvpn/ssl_common.h +++ b/src/openvpn/ssl_common.h @@ -204,6 +204,18 @@ struct key_state #endif }; +/** Control channel wrapping (--tls-auth/--tls-crypt) context */ +struct tls_wrap_ctx +{ + enum { + TLS_WRAP_NONE = 0, /**< No control channel wrapping */ + TLS_WRAP_AUTH, /**< Control channel authentication */ + TLS_WRAP_CRYPT, /**< Control channel encryption and authentication */ + } mode; /**< Control channel wrapping mode */ + struct crypto_options opt; /**< Crypto state */ + struct buffer work; /**< Work buffer (only for --tls-crypt) */ +}; + /* * Our const options, obtained directly or derived from * command line options. @@ -278,8 +290,8 @@ struct tls_options const char *config_authname; bool ncp_enabled; - /* packet authentication for TLS handshake */ - struct crypto_options tls_auth; + /** TLS handshake wrapping state */ + struct tls_wrap_ctx tls_wrap; /* frame parameters for TLS control channel */ struct frame frame; @@ -380,7 +392,7 @@ struct tls_session bool burst; /* authenticate control packets */ - struct crypto_options tls_auth; + struct tls_wrap_ctx tls_wrap; int initial_opcode; /* our initial P_ opcode */ struct session_id session_id; /* our random session ID */ diff --git a/src/openvpn/tls_crypt.c b/src/openvpn/tls_crypt.c new file mode 100644 index 00000000000..d40532e89db --- /dev/null +++ b/src/openvpn/tls_crypt.c @@ -0,0 +1,254 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single TCP/UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2016 Fox Crypto B.V. + * + * 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 + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#elif defined(_MSC_VER) +#include "config-msvc.h" +#endif + +#include "syshead.h" + +#ifdef ENABLE_CRYPTO +#include "crypto.h" +#include "session_id.h" + +#include "tls_crypt.h" + +int tls_crypt_buf_overhead(void) +{ + return packet_id_size (true) + TLS_CRYPT_TAG_SIZE + TLS_CRYPT_BLOCK_SIZE; +} + +void +tls_crypt_init_key (struct key_ctx_bi *key, const char *key_file, + const char *key_inline, bool tls_server) { + const int key_direction = tls_server ? + KEY_DIRECTION_NORMAL : KEY_DIRECTION_INVERSE; + + struct key_type kt; + kt.cipher = cipher_kt_get ("AES-256-CTR"); + kt.cipher_length = cipher_kt_key_size (kt.cipher); + kt.digest = md_kt_get ("SHA256"); + kt.hmac_length = md_kt_size (kt.digest); + + if (!kt.cipher) + { + msg (M_FATAL, "ERROR: --tls-crypt requires AES-256-CTR support."); + } + if (!kt.digest) + { + msg (M_FATAL, "ERROR: --tls-crypt requires HMAC-SHA-256 support."); + } + + crypto_read_openvpn_key (&kt, key, key_file, key_inline, key_direction, + "Control Channel Encryption", "tls-crypt"); +} + +void +tls_crypt_adjust_frame_parameters(struct frame *frame) +{ + frame_add_to_extra_frame (frame, tls_crypt_buf_overhead()); + + msg(D_MTU_DEBUG, "%s: Adjusting frame parameters for tls-crypt by %i bytes", + __func__, tls_crypt_buf_overhead()); +} + + +bool +tls_crypt_wrap (const struct buffer *src, struct buffer *dst, + struct crypto_options *opt) { + const struct key_ctx *ctx = &opt->key_ctx_bi.encrypt; + struct gc_arena gc; + + /* IV, packet-ID and implicit IV required for this mode. */ + ASSERT (ctx->cipher); + ASSERT (ctx->hmac); + ASSERT (packet_id_initialized(&opt->packet_id)); + ASSERT (hmac_ctx_size(ctx->hmac) == 256/8); + + gc_init (&gc); + + dmsg (D_PACKET_CONTENT, "TLS-CRYPT WRAP FROM: %s", + format_hex (BPTR (src), BLEN (src), 80, &gc)); + + /* Get packet ID */ + { + struct packet_id_net pin; + packet_id_alloc_outgoing (&opt->packet_id.send, &pin, true); + packet_id_write (&pin, dst, true, false); + } + + dmsg (D_PACKET_CONTENT, "TLS-CRYPT WRAP AD: %s", + format_hex (BPTR (dst), BLEN (dst), 0, &gc)); + + /* Buffer overflow check */ + if (!buf_safe (dst, BLEN (src) + TLS_CRYPT_BLOCK_SIZE + TLS_CRYPT_TAG_SIZE)) + { + msg (D_CRYPT_ERRORS, "TLS-CRYPT WRAP: buffer size error, " + "sc=%d so=%d sl=%d dc=%d do=%d dl=%d", src->capacity, src->offset, + src->len, dst->capacity, dst->offset, dst->len); + goto err; + } + + /* Calculate auth tag and synthetic IV */ + { + uint8_t *tag = NULL; + hmac_ctx_reset (ctx->hmac); + hmac_ctx_update (ctx->hmac, BPTR (dst), BLEN (dst)); + hmac_ctx_update (ctx->hmac, BPTR (src), BLEN (src)); + + ASSERT (tag = buf_write_alloc (dst, TLS_CRYPT_TAG_SIZE)); + hmac_ctx_final (ctx->hmac, tag); + + dmsg (D_PACKET_CONTENT, "TLS-CRYPT WRAP TAG: %s", + format_hex (tag, TLS_CRYPT_TAG_SIZE, 0, &gc)); + + /* Use the 128 most significant bits of the tag as IV */ + ASSERT (cipher_ctx_reset (ctx->cipher, tag)); + } + + /* Encrypt src */ + { + int outlen = 0; + ASSERT (cipher_ctx_update (ctx->cipher, BEND (dst), &outlen, + BPTR (src), BLEN(src))); + ASSERT (buf_inc_len (dst, outlen)); + ASSERT (cipher_ctx_final (ctx->cipher, BPTR (dst), &outlen)); + ASSERT (buf_inc_len (dst, outlen)); + } + + dmsg (D_PACKET_CONTENT, "TLS-CRYPT WRAP TO: %s", + format_hex (BPTR (dst), BLEN (dst), 80, &gc)); + + gc_free (&gc); + return true; + +err: + crypto_clear_error(); + dst->len = 0; + gc_free (&gc); + return false; +} + +bool +tls_crypt_unwrap (const struct buffer *src, struct buffer *dst, + struct crypto_options *opt) +{ + static const char error_prefix[] = "tls-crypt unwrap error"; + const struct key_ctx *ctx = &opt->key_ctx_bi.decrypt; + struct gc_arena gc; + + gc_init (&gc); + + ASSERT (opt); + ASSERT (src->len > 0); + ASSERT (ctx->cipher); + ASSERT (packet_id_initialized (&opt->packet_id) || + (opt->flags & CO_IGNORE_PACKET_ID)); + + dmsg (D_PACKET_CONTENT, "TLS-CRYPT UNWRAP FROM: %s", + format_hex (BPTR (src), BLEN (src), 80, &gc)); + + if (buf_len (src) < TLS_CRYPT_OFF_CT) + { + CRYPT_ERROR ("packet too short"); + } + + /* Decrypt cipher text */ + { + int outlen = 0; + + /* Buffer overflow check (should never fail) */ + if (!buf_safe (dst, BLEN (src) - TLS_CRYPT_OFF_CT + TLS_CRYPT_BLOCK_SIZE)) + { + CRYPT_ERROR ("potential buffer overflow"); + } + + if (!cipher_ctx_reset (ctx->cipher, BPTR (src) + TLS_CRYPT_OFF_TAG)) + { + CRYPT_ERROR ("cipher reset failed"); + } + if (!cipher_ctx_update (ctx->cipher, BPTR (dst), &outlen, + BPTR (src) + TLS_CRYPT_OFF_CT, BLEN (src) - TLS_CRYPT_OFF_CT)) + { + CRYPT_ERROR ("cipher update failed"); + } + ASSERT (buf_inc_len (dst, outlen)); + if (!cipher_ctx_final (ctx->cipher, BPTR(dst), &outlen)) + { + CRYPT_ERROR ("cipher final failed"); + } + ASSERT (buf_inc_len (dst, outlen)); + } + + /* Check authentication */ + { + const uint8_t *tag = BPTR (src) + TLS_CRYPT_OFF_TAG; + uint8_t tag_check[TLS_CRYPT_TAG_SIZE] = { 0 }; + + dmsg (D_PACKET_CONTENT, "TLS-CRYPT UNWRAP AD: %s", + format_hex (BPTR (src), TLS_CRYPT_OFF_TAG, 0, &gc)); + dmsg (D_PACKET_CONTENT, "TLS-CRYPT UNWRAP TO: %s", + format_hex (BPTR (dst), BLEN (dst), 80, &gc)); + + hmac_ctx_reset (ctx->hmac); + hmac_ctx_update (ctx->hmac, BPTR (src), TLS_CRYPT_OFF_TAG); + hmac_ctx_update (ctx->hmac, BPTR (dst), BLEN (dst)); + hmac_ctx_final (ctx->hmac, tag_check); + + if (memcmp_constant_time (tag, tag_check, sizeof(tag_check))) + { + dmsg (D_CRYPTO_DEBUG, "tag : %s", + format_hex (tag, sizeof(tag_check), 0, &gc)); + dmsg (D_CRYPTO_DEBUG, "tag_check: %s", + format_hex (tag_check, sizeof(tag_check), 0, &gc)); + CRYPT_ERROR ("packet authentication failed"); + } + } + + /* Check replay */ + if (!(opt->flags & CO_IGNORE_PACKET_ID)) + { + struct packet_id_net pin; + struct buffer tmp = *src; + ASSERT (buf_advance (&tmp, TLS_CRYPT_OFF_PID)); + ASSERT (packet_id_read (&pin, &tmp, true)); + if (!crypto_check_replay (opt, &pin, error_prefix, &gc)) + { + CRYPT_ERROR ("packet replay"); + } + } + + gc_free (&gc); + return true; + + error_exit: + crypto_clear_error(); + dst->len = 0; + gc_free (&gc); + return false; +} + +#endif /* EMABLE_CRYPTO */ diff --git a/src/openvpn/tls_crypt.h b/src/openvpn/tls_crypt.h new file mode 100644 index 00000000000..d1962c969c1 --- /dev/null +++ b/src/openvpn/tls_crypt.h @@ -0,0 +1,144 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single TCP/UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2016 Fox Crypto B.V. + * + * 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 + */ + +/** + * @defgroup tls_crypt Control channel encryption (--tls-crypt) + * @ingroup control_tls + * @{ + * + * @par + * Control channel encryption uses a pre-shared static key (like the --tls-auth + * key) to encrypt control channel packets. + * + * @par + * Encrypting control channel packets has three main advantages: + * - It provides more privacy by hiding the certificate used for the TLS + * connection. + * - It is harder to identify OpenVPN traffic as such. + * - It provides "poor-man's" post-quantum security, against attackers who + * will never know the pre-shared key (i.e. no forward secrecy). + * + * @par Specification + * Control channel encryption is based on the SIV construction [0], to achieve + * nonce misuse-resistant authenticated encryption: + * + * @par + * \code{.unparsed} + * msg = control channel plaintext + * header = opcode (1 byte) || session_id (8 bytes) || packet_id (8 bytes) + * Ka = authentication key (256 bits) + * Ke = encryption key (256 bits) + * (Ka and Ke are pre-shared keys, like with --tls-auth) + * + * auth_tag = HMAC-SHA256(Ka, header || msg) + * IV = 128 most-significant bits of auth_tag + * ciph = AES256-CTR(Ke, IV, msg) + * + * output = Header || Tag || Ciph + * \endcode + * + * @par + * This boils down to the following on-the-wire packet format: + * + * @par + * \code{.unparsed} + * - opcode - || - session_id - || - packet_id - || auth_tag || * payload * + * \endcode + * + * @par + * Where + * - XXX - means authenticated, and + * * XXX * means authenticated and encrypted. + */ + +#ifndef TLSCRYPT_H +#define TLSCRYPT_H + +#include "buffer.h" +#include "crypto.h" +#include "session_id.h" + +#define TLS_CRYPT_TAG_SIZE (256/8) +#define TLS_CRYPT_PID_SIZE (sizeof (packet_id_type) + sizeof (net_time_t)) +#define TLS_CRYPT_BLOCK_SIZE (128/8) + +#define TLS_CRYPT_OFF_PID (1 + SID_SIZE) +#define TLS_CRYPT_OFF_TAG (TLS_CRYPT_OFF_PID + TLS_CRYPT_PID_SIZE) +#define TLS_CRYPT_OFF_CT (TLS_CRYPT_OFF_TAG + TLS_CRYPT_TAG_SIZE) + +/** + * Initialize a key_ctx_bi structure for use with --tls-crypt. + * + * @param key The key context to initialize + * @param key_file The file to read the key from (or the inline tag to + * indicate and inline key). + * @param key_inline Array containing (zero-terminated) inline key, or NULL + * if not used. + * @param tls_server Must be set to true is this is a TLS server instance. + */ +void tls_crypt_init_key (struct key_ctx_bi *key, const char *key_file, + const char *key_inline, bool tls_server); + +/** + * Returns the maximum overhead (in bytes) added to the destination buffer by + * tls_crypt_wrap(). + */ +int tls_crypt_buf_overhead(void); + +/** + * Adjust frame parameters for --tls-crypt overhead. + */ +void tls_crypt_adjust_frame_parameters(struct frame *frame); + +/** + * Wrap a control channel packet (both authenticates and encrypts the data). + * + * @param src Data to authenticate and encrypt. + * @param dst Any data present in this buffer is first authenticated, then + * the wrapped packet id and data from the src buffer are appended. + * Must have at least tls_crypt_buf_overhead()+BLEN(src) headroom. + * @param opt The crypto state for this --tls-crypt instance. + * + * @returns true iff wrapping succeeded. + */ +bool tls_crypt_wrap (const struct buffer *src, struct buffer *dst, + struct crypto_options *opt); + +/** + * Unwrap a control channel packet (decrypts, authenticates and performs + * replay checks). + * + * @param src Data to decrypt and authenticate. + * @param dst Returns the decrypted data, if unwrapping was successful. + * @param opt The crypto state for this --tls-crypt instance. + * + * @returns true iff unwrapping succeeded (data authenticated correctly and was + * no replay). + */ +bool tls_crypt_unwrap (const struct buffer *src, struct buffer *dst, + struct crypto_options *opt); + +/** @} */ + +#endif /* TLSCRYPT_H */ From 3b185161de1254af746494007b7e81d17f632d4b Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Tue, 8 Nov 2016 21:18:22 +0100 Subject: [PATCH 393/643] Add --tls-crypt unit tests These help verify the tls-crypt functionality - they already caught a bug during development. We should however probably also add some t_client tests once this feature is in. To test --tls-crypt with as few dependencies as possible, this adds a mock implementation of msg() (or actually x_msg()). For debugging purposes, the mock implementation can be made to really log by calling mock_set_debug_level(), but defaults to (almost) no logging. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1478636302-9678-6-git-send-email-steffan.karger@fox-it.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12973.html Signed-off-by: Gert Doering --- tests/unit_tests/openvpn/Makefile.am | 22 +- tests/unit_tests/openvpn/mock_msg.c | 92 ++++++++ tests/unit_tests/openvpn/mock_msg.h | 35 ++++ tests/unit_tests/openvpn/test_argv.c | 10 - tests/unit_tests/openvpn/test_tls_crypt.c | 242 ++++++++++++++++++++++ 5 files changed, 390 insertions(+), 11 deletions(-) create mode 100644 tests/unit_tests/openvpn/mock_msg.c create mode 100644 tests/unit_tests/openvpn/mock_msg.h create mode 100644 tests/unit_tests/openvpn/test_tls_crypt.c diff --git a/tests/unit_tests/openvpn/Makefile.am b/tests/unit_tests/openvpn/Makefile.am index b706faed02c..632ff587eff 100644 --- a/tests/unit_tests/openvpn/Makefile.am +++ b/tests/unit_tests/openvpn/Makefile.am @@ -2,8 +2,13 @@ AUTOMAKE_OPTIONS = foreign check_PROGRAMS = argv_testdriver +if ENABLE_CRYPTO +check_PROGRAMS += tls_crypt_testdriver +endif + TESTS = $(check_PROGRAMS) +openvpn_includedir = $(top_srcdir)/include openvpn_srcdir = $(top_srcdir)/src/openvpn compat_srcdir = $(top_srcdir)/src/compat @@ -11,7 +16,22 @@ argv_testdriver_CFLAGS = @TEST_CFLAGS@ -I$(openvpn_srcdir) -I$(compat_srcdir) \ $(OPTIONAL_CRYPTO_CFLAGS) argv_testdriver_LDFLAGS = @TEST_LDFLAGS@ -L$(openvpn_srcdir) -Wl,--wrap=parse_line \ $(OPTIONAL_CRYPTO_LIBS) -argv_testdriver_SOURCES = test_argv.c \ +argv_testdriver_SOURCES = test_argv.c mock_msg.c \ $(openvpn_srcdir)/platform.c \ $(openvpn_srcdir)/buffer.c \ $(openvpn_srcdir)/argv.c + +tls_crypt_testdriver_CFLAGS = @TEST_CFLAGS@ \ + -I$(openvpn_includedir) -I$(compat_srcdir) -I$(openvpn_srcdir) \ + $(OPTIONAL_CRYPTO_CFLAGS) +tls_crypt_testdriver_LDFLAGS = @TEST_LDFLAGS@ \ + $(OPTIONAL_CRYPTO_LIBS) +tls_crypt_testdriver_SOURCES = test_tls_crypt.c mock_msg.c \ + $(openvpn_srcdir)/buffer.c \ + $(openvpn_srcdir)/crypto.c \ + $(openvpn_srcdir)/crypto_mbedtls.c \ + $(openvpn_srcdir)/crypto_openssl.c \ + $(openvpn_srcdir)/otime.c \ + $(openvpn_srcdir)/packet_id.c \ + $(openvpn_srcdir)/platform.c \ + $(openvpn_srcdir)/tls_crypt.c diff --git a/tests/unit_tests/openvpn/mock_msg.c b/tests/unit_tests/openvpn/mock_msg.c new file mode 100644 index 00000000000..54b60176167 --- /dev/null +++ b/tests/unit_tests/openvpn/mock_msg.c @@ -0,0 +1,92 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2016 Fox Crypto B.V. + * + * 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 + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#elif defined(_MSC_VER) +#include "config-msvc.h" +#endif + +#include +#include +#include +#include + +#include "errlevel.h" +#include "error.h" + +unsigned int x_debug_level = 0; /* Default to (almost) no debugging output */ +bool fatal_error_triggered = false; + +void mock_set_debug_level(int level) +{ + x_debug_level = level; +} + +void x_msg_va (const unsigned int flags, const char *format, + va_list arglist) +{ + if (flags & M_FATAL) + { + fatal_error_triggered = true; + printf("FATAL ERROR:"); + } + vprintf(format, arglist); + printf("\n"); +} + +void x_msg (const unsigned int flags, const char *format, ...) +{ + va_list arglist; + va_start (arglist, format); + x_msg_va (flags, format, arglist); + va_end (arglist); +} + +void +assert_failed (const char *filename, int line, const char *condition) +{ + if (condition) + printf ("Assertion failed at %s:%d (%s)", filename, line, condition); + else + printf ("Assertion failed at %s:%d", filename, line); + exit (1); +} + +/* + * Fail memory allocation. Don't use msg() because it tries + * to allocate memory as part of its operation. + */ +void +out_of_memory (void) +{ + fprintf (stderr, "Out of Memory\n"); + exit (1); +} + +bool +dont_mute (unsigned int flags) +{ + return true; +} diff --git a/tests/unit_tests/openvpn/mock_msg.h b/tests/unit_tests/openvpn/mock_msg.h new file mode 100644 index 00000000000..5d93a1a33e7 --- /dev/null +++ b/tests/unit_tests/openvpn/mock_msg.h @@ -0,0 +1,35 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2016 Fox Crypto B.V. + * + * 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 MOCK_MSG_H +#define MOCK_MSG_H + +/** + * Mock debug level defaults to 0, which gives clean(-ish) test reports. Call + * this function from your test driver to increase debug output when you + * need debug output. + */ +void mock_set_debug_level(int level); + +#endif /* MOCK_MSG */ diff --git a/tests/unit_tests/openvpn/test_argv.c b/tests/unit_tests/openvpn/test_argv.c index 3945634b01e..4d17557485c 100644 --- a/tests/unit_tests/openvpn/test_argv.c +++ b/tests/unit_tests/openvpn/test_argv.c @@ -13,16 +13,6 @@ #include "argv.h" #include "buffer.h" -/* - * Dummy symbols that need to be defined due to them being - * referenced in #include'd header files and their includes - */ -unsigned int x_debug_level; -bool dont_mute (unsigned int flags) { return true; } -void assert_failed (const char *filename, int line, const char *condition) { exit(0); } -void out_of_memory (void) { } -void x_msg (const unsigned int flags, const char *format, ...) { } - /* * This is defined here to prevent #include'ing misc.h * which makes things difficult beyond any recognition diff --git a/tests/unit_tests/openvpn/test_tls_crypt.c b/tests/unit_tests/openvpn/test_tls_crypt.c new file mode 100644 index 00000000000..473a232f145 --- /dev/null +++ b/tests/unit_tests/openvpn/test_tls_crypt.c @@ -0,0 +1,242 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2016 Fox Crypto B.V. + * + * 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 + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#elif defined(_MSC_VER) +#include "config-msvc.h" +#endif + +#ifdef ENABLE_CRYPTO + +#include "syshead.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "tls_crypt.h" + +#include "mock_msg.h" + +#define TESTBUF_SIZE 128 + +const char plaintext_short[1]; + +struct test_context { + struct crypto_options co; + struct key_type kt; + struct buffer source; + struct buffer ciphertext; + struct buffer unwrapped; +}; + +static int setup(void **state) { + struct test_context *ctx = calloc(1, sizeof(*ctx)); + + ctx->kt.cipher = cipher_kt_get ("AES-256-CTR"); + ctx->kt.cipher_length = cipher_kt_key_size (ctx->kt.cipher); + ctx->kt.digest = md_kt_get ("SHA256"); + ctx->kt.hmac_length = md_kt_size (ctx->kt.digest); + + struct key key = { 0 }; + + init_key_ctx (&ctx->co.key_ctx_bi.encrypt, &key, &ctx->kt, true, "TEST"); + init_key_ctx (&ctx->co.key_ctx_bi.decrypt, &key, &ctx->kt, false, "TEST"); + + packet_id_init (&ctx->co.packet_id, 0, 0, "test", 0); + + ctx->source = alloc_buf(TESTBUF_SIZE); + ctx->ciphertext = alloc_buf(TESTBUF_SIZE); + ctx->unwrapped = alloc_buf(TESTBUF_SIZE); + + /* Write test plaintext */ + buf_write(&ctx->source, plaintext_short, sizeof(plaintext_short)); + + /* Write dummy opcode and session id */ + buf_write(&ctx->ciphertext, "012345678", 1 + 8); + + *state = ctx; + + return 0; +} + +static int teardown(void **state) { + struct test_context *ctx = (struct test_context *) *state; + + free_buf (&ctx->source); + free_buf (&ctx->ciphertext); + free_buf (&ctx->unwrapped); + + free_key_ctx_bi (&ctx->co.key_ctx_bi); + + free(ctx); + + return 0; +} + +/** + * Check that short messages are successfully wrapped-and-unwrapped. + */ +static void tls_crypt_loopback(void **state) { + struct test_context *ctx = (struct test_context *) *state; + + assert_true (tls_crypt_wrap (&ctx->source, &ctx->ciphertext, &ctx->co)); + assert_true (BLEN(&ctx->source) < BLEN(&ctx->ciphertext)); + assert_true (tls_crypt_unwrap (&ctx->ciphertext, &ctx->unwrapped, &ctx->co)); + assert_int_equal(BLEN(&ctx->source), BLEN(&ctx->unwrapped)); + assert_memory_equal(BPTR(&ctx->source), BPTR(&ctx->unwrapped), + BLEN(&ctx->source)); +} + +/** + * Check that zero-byte messages are successfully wrapped-and-unwrapped. + */ +static void tls_crypt_loopback_zero_len(void **state) { + struct test_context *ctx = (struct test_context *) *state; + + buf_clear(&ctx->source); + + assert_true (tls_crypt_wrap (&ctx->source, &ctx->ciphertext, &ctx->co)); + assert_true (BLEN(&ctx->source) < BLEN(&ctx->ciphertext)); + assert_true (tls_crypt_unwrap (&ctx->ciphertext, &ctx->unwrapped, &ctx->co)); + assert_int_equal(BLEN(&ctx->source), BLEN(&ctx->unwrapped)); + assert_memory_equal(BPTR(&ctx->source), BPTR(&ctx->unwrapped), + BLEN(&ctx->source)); +} + +/** + * Check that max-length messages are successfully wrapped-and-unwrapped. + */ +static void tls_crypt_loopback_max_len(void **state) { + struct test_context *ctx = (struct test_context *) *state; + + buf_clear(&ctx->source); + assert_non_null (buf_write_alloc (&ctx->source, + TESTBUF_SIZE - BLEN (&ctx->ciphertext) - tls_crypt_buf_overhead())); + + assert_true (tls_crypt_wrap (&ctx->source, &ctx->ciphertext, &ctx->co)); + assert_true (BLEN(&ctx->source) < BLEN(&ctx->ciphertext)); + assert_true (tls_crypt_unwrap (&ctx->ciphertext, &ctx->unwrapped, &ctx->co)); + assert_int_equal(BLEN(&ctx->source), BLEN(&ctx->unwrapped)); + assert_memory_equal(BPTR(&ctx->source), BPTR(&ctx->unwrapped), + BLEN(&ctx->source)); +} + +/** + * Check that too-long messages are gracefully rejected. + */ +static void tls_crypt_fail_msg_too_long(void **state) { + struct test_context *ctx = (struct test_context *) *state; + + buf_clear(&ctx->source); + assert_non_null (buf_write_alloc (&ctx->source, + TESTBUF_SIZE - BLEN (&ctx->ciphertext) - tls_crypt_buf_overhead() + 1)); + assert_false (tls_crypt_wrap (&ctx->source, &ctx->ciphertext, &ctx->co)); +} + +/** + * Check that packets that were wrapped (or unwrapped) with a different key + * are not accepted. + */ +static void tls_crypt_fail_invalid_key(void **state) { + struct test_context *ctx = (struct test_context *) *state; + + /* Change decrypt key */ + struct key key = { { 1 } }; + free_key_ctx (&ctx->co.key_ctx_bi.decrypt); + init_key_ctx (&ctx->co.key_ctx_bi.decrypt, &key, &ctx->kt, false, "TEST"); + + assert_true (tls_crypt_wrap (&ctx->source, &ctx->ciphertext, &ctx->co)); + assert_true (BLEN(&ctx->source) < BLEN(&ctx->ciphertext)); + assert_false (tls_crypt_unwrap (&ctx->ciphertext, &ctx->unwrapped, &ctx->co)); +} + +/** + * Check that replayed packets are not accepted. + */ +static void tls_crypt_fail_replay(void **state) { + struct test_context *ctx = (struct test_context *) *state; + + assert_true (tls_crypt_wrap (&ctx->source, &ctx->ciphertext, &ctx->co)); + assert_true (BLEN(&ctx->source) < BLEN(&ctx->ciphertext)); + struct buffer tmp = ctx->ciphertext; + assert_true (tls_crypt_unwrap (&tmp, &ctx->unwrapped, &ctx->co)); + buf_clear (&ctx->unwrapped); + assert_false (tls_crypt_unwrap (&ctx->ciphertext, &ctx->unwrapped, &ctx->co)); +} + +/** + * Check that packet replays are accepted when CO_IGNORE_PACKET_ID is set. This + * is used for the first control channel packet that arrives, because we don't + * know the packet ID yet. + */ +static void tls_crypt_ignore_replay(void **state) { + struct test_context *ctx = (struct test_context *) *state; + + ctx->co.flags |= CO_IGNORE_PACKET_ID; + + assert_true (tls_crypt_wrap (&ctx->source, &ctx->ciphertext, &ctx->co)); + assert_true (BLEN(&ctx->source) < BLEN(&ctx->ciphertext)); + struct buffer tmp = ctx->ciphertext; + assert_true (tls_crypt_unwrap (&tmp, &ctx->unwrapped, &ctx->co)); + buf_clear (&ctx->unwrapped); + assert_true (tls_crypt_unwrap (&ctx->ciphertext, &ctx->unwrapped, &ctx->co)); +} + +int main(void) { + const struct CMUnitTest tests[] = { + cmocka_unit_test_setup_teardown(tls_crypt_loopback, setup, teardown), + cmocka_unit_test_setup_teardown(tls_crypt_loopback_zero_len, + setup, teardown), + cmocka_unit_test_setup_teardown(tls_crypt_loopback_max_len, + setup, teardown), + cmocka_unit_test_setup_teardown(tls_crypt_fail_msg_too_long, + setup, teardown), + cmocka_unit_test_setup_teardown(tls_crypt_fail_invalid_key, + setup, teardown), + cmocka_unit_test_setup_teardown(tls_crypt_fail_replay, + setup, teardown), + cmocka_unit_test_setup_teardown(tls_crypt_ignore_replay, + setup, teardown), + }; + +#if defined(ENABLE_CRYPTO_OPENSSL) + OpenSSL_add_all_algorithms(); +#endif + + int ret = cmocka_run_group_tests_name("tls-crypt tests", tests, NULL, NULL); + +#if defined(ENABLE_CRYPTO_OPENSSL) + EVP_cleanup(); +#endif + + return ret; +} + +#endif /* ENABLE_CRYPTO */ From 10ce637066f44e8ad9f4af000b8d0c2a4012236d Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Tue, 15 Nov 2016 14:40:56 +0100 Subject: [PATCH 394/643] options: Remove --tls-remote In OpenVPN 2.3 --tls-remote got deprecated in favour of --verify-x509-name. The new option solves the same task as --tls-remote but in a more flexible and improved way. This new option was introduced in commit 9f0fc745664fd0 (release/2.3: f6e12862cefd054eb1). Removing --tls-remote will only require a minor configuration file change. The removal of this option has been documented in the man pages since the release of OpenVPN v2.3, where also the deprecation of --compat-names and --no-name-remapping was included. However, those two will first be removed in OpenVPN v2.5. The reason not to remove --compat-names and --no-name-remapping now is that such a change will require TLS verification scripts and plug-ins to be updated to support the new X.509 subject formatting; which --verify-x509-name already uses. Signed-off-by: David Sommerseth Acked-by: Gert Doering Message-Id: <1479217256-21298-1-git-send-email-davids@openvpn.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13070.html Signed-off-by: Gert Doering --- Changes.rst | 8 ++++++ doc/openvpn.8 | 53 +++------------------------------------- src/openvpn/options.c | 49 +++---------------------------------- src/openvpn/ssl_verify.h | 2 -- 4 files changed, 15 insertions(+), 97 deletions(-) diff --git a/Changes.rst b/Changes.rst index 0d1ff40c739..0341b0b0abf 100644 --- a/Changes.rst +++ b/Changes.rst @@ -131,6 +131,14 @@ Deprecated features that would previously be accepted. If this occurs, OpenVPN will log the crypto library's error description. +- ``--tls-remote`` is removed in 2.4, as indicated in the 2.3 man-pages. A similar + functionality is provided via ``--verify-x509-name`` which does the same job in + a better way. + +- ``--compat-names`` and ``--no-name-remapping`` was deprecated in 2.3 and will + be removed in 2.5. All scripts and plug-ins depending on the old non-standard + X.509 subject formatting must be updated to the standardized formatting. See + the man page for more information. User-visible Changes -------------------- diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 4c52cb6a1c8..e997b096e1c 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -3766,11 +3766,7 @@ carriage-return. no-remapping is only available on the server side. .B Please note: This option is immediately deprecated. It is only implemented to make the transition to the new formatting less intrusive. It will be -removed either in OpenVPN v2.4 or v2.5. So please make sure you use the -.B \-\-verify\-x509\-name -option instead of -.B \-\-tls\-remote -as soon as possible and update your scripts where necessary. +removed in OpenVPN v2.5. So please update your scripts/plug-ins where necessary. .\"********************************************************* .TP .B \-\-no\-name\-remapping (DEPRECATED) @@ -3783,8 +3779,8 @@ It ensures compatibility with server configurations using the option. .B Please note: -This option is now deprecated. It will be removed either in OpenVPN v2.4 -or v2.5. So please make sure you support the new X.509 name formatting +This option is now deprecated. It will be removed in OpenVPN v2.5. +So please make sure you support the new X.509 name formatting described with the .B \-\-compat\-names option as soon as possible. @@ -5186,49 +5182,6 @@ prefix will be left as-is. This automatic upcasing feature is deprecated and will be removed in a future release. .\"********************************************************* .TP -.B \-\-tls\-remote name (DEPRECATED) -Accept connections only from a host with X509 name -or common name equal to -.B name. -The remote host must also pass all other tests -of verification. - -.B NOTE: -Because tls\-remote may test against a common name prefix, -only use this option when you are using OpenVPN with a custom CA -certificate that is under your control. -Never use this option when your client certificates are signed by -a third party, such as a commercial web CA. - -Name can also be a common name prefix, for example if you -want a client to only accept connections to "Server-1", -"Server-2", etc., you can simply use -.B \-\-tls\-remote Server - -Using a common name prefix is a useful alternative to managing -a CRL (Certificate Revocation List) on the client, since it allows the client -to refuse all certificates except for those associated -with designated servers. - -.B \-\-tls\-remote -is a useful replacement for the -.B \-\-tls\-verify -option to verify the remote host, because -.B \-\-tls\-remote -works in a -.B \-\-chroot -environment too. - -.B Please also note: -This option is now deprecated. It will be removed either in OpenVPN v2.4 -or v2.5. So please make sure you support the new X.509 name formatting -described with the -.B \-\-compat\-names -option as soon as possible by updating your configurations to use -.B \-\-verify\-x509\-name -instead. -.\"********************************************************* -.TP .B \-\-verify\-x509\-name name type Accept connections only if a host's X.509 name is equal to .B name. diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 21c8b84d2a6..7f128c36eb6 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -7068,14 +7068,12 @@ add_option (struct options *options, #endif { VERIFY_PERMISSION (OPT_P_GENERAL); - if (options->verify_x509_type != VERIFY_X509_NONE && - options->verify_x509_type != TLS_REMOTE_SUBJECT_DN && - options->verify_x509_type != TLS_REMOTE_SUBJECT_RDN_PREFIX) + if (options->verify_x509_type != VERIFY_X509_NONE) { msg (msglevel, "you cannot use --compat-names with --verify-x509-name"); goto err; } - msg (M_WARN, "DEPRECATED OPTION: --compat-names, please update your configuration"); + msg (M_WARN, "DEPRECATED OPTION: --compat-names, please update your configuration. This will be removed in OpenVPN v2.5."); compat_flag (COMPAT_FLAG_SET | COMPAT_NAMES); #if P2MP_SERVER if (p[1] && streq (p[1], "no-remapping")) @@ -7084,59 +7082,20 @@ add_option (struct options *options, else if (streq (p[0], "no-name-remapping") && !p[1]) { VERIFY_PERMISSION (OPT_P_GENERAL); - if (options->verify_x509_type != VERIFY_X509_NONE && - options->verify_x509_type != TLS_REMOTE_SUBJECT_DN && - options->verify_x509_type != TLS_REMOTE_SUBJECT_RDN_PREFIX) + if (options->verify_x509_type != VERIFY_X509_NONE) { msg (msglevel, "you cannot use --no-name-remapping with --verify-x509-name"); goto err; } - msg (M_WARN, "DEPRECATED OPTION: --no-name-remapping, please update your configuration"); + msg (M_WARN, "DEPRECATED OPTION: --no-name-remapping, please update your configuration. This will be removed in OpenVPN v2.5."); compat_flag (COMPAT_FLAG_SET | COMPAT_NAMES); compat_flag (COMPAT_FLAG_SET | COMPAT_NO_NAME_REMAPPING); #endif } - else if (streq (p[0], "tls-remote") && p[1] && !p[2]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - - if (options->verify_x509_type != VERIFY_X509_NONE && - options->verify_x509_type != TLS_REMOTE_SUBJECT_DN && - options->verify_x509_type != TLS_REMOTE_SUBJECT_RDN_PREFIX) - { - msg (msglevel, "you cannot use --tls-remote with --verify-x509-name"); - goto err; - } - msg (M_WARN, "DEPRECATED OPTION: --tls-remote, please update your configuration"); - - if (strlen (p[1])) - { - int is_username = (!strchr (p[1], '=') || !strstr (p[1], ", ")); - int type = TLS_REMOTE_SUBJECT_DN; - if (p[1][0] != '/' && is_username) - type = TLS_REMOTE_SUBJECT_RDN_PREFIX; - - /* - * Enable legacy openvpn format for DNs that have not been converted - * yet and --x509-username-field (not containing an '=' or ', ') - */ - if (p[1][0] == '/' || is_username) - compat_flag (COMPAT_FLAG_SET | COMPAT_NAMES); - - options->verify_x509_type = type; - options->verify_x509_name = p[1]; - } - } else if (streq (p[0], "verify-x509-name") && p[1] && strlen (p[1]) && !p[3]) { int type = VERIFY_X509_SUBJECT_DN; VERIFY_PERMISSION (OPT_P_GENERAL); - if (options->verify_x509_type == TLS_REMOTE_SUBJECT_DN || - options->verify_x509_type == TLS_REMOTE_SUBJECT_RDN_PREFIX) - { - msg (msglevel, "you cannot use --verify-x509-name with --tls-remote"); - goto err; - } if (compat_flag (COMPAT_FLAG_QUERY | COMPAT_NAMES)) { msg (msglevel, "you cannot use --verify-x509-name with " diff --git a/src/openvpn/ssl_verify.h b/src/openvpn/ssl_verify.h index e5b5950a0f1..98312fd96e9 100644 --- a/src/openvpn/ssl_verify.h +++ b/src/openvpn/ssl_verify.h @@ -67,8 +67,6 @@ struct cert_hash_set { #define VERIFY_X509_SUBJECT_DN 1 #define VERIFY_X509_SUBJECT_RDN 2 #define VERIFY_X509_SUBJECT_RDN_PREFIX 3 -#define TLS_REMOTE_SUBJECT_DN 1 + 0x100 -#define TLS_REMOTE_SUBJECT_RDN_PREFIX 3 + 0x100 #define TLS_AUTHENTICATION_SUCCEEDED 0 #define TLS_AUTHENTICATION_FAILED 1 From 95bcf135f5aff0a3dc3f9208628fd18b8f2ee326 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Wed, 16 Nov 2016 21:18:44 +0100 Subject: [PATCH 395/643] Remove unused variable in argv_printf_arglist() Signed-off-by: David Sommerseth Acked-by: Gert Doering Message-Id: <1479327524-25415-1-git-send-email-davids@openvpn.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13110.html Signed-off-by: Gert Doering --- src/openvpn/argv.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/openvpn/argv.c b/src/openvpn/argv.c index f8287b794ca..596e59c93e7 100644 --- a/src/openvpn/argv.c +++ b/src/openvpn/argv.c @@ -252,7 +252,6 @@ argv_printf_arglist (struct argv *a, const char *format, va_list arglist) char *s1 = va_arg (arglist, char *); char *s2 = va_arg (arglist, char *); char *combined; - char *cmd_name; if (!s1) s1 = ""; if (!s2) s2 = ""; From 8a1f5354d03b034537f5c40a2e2371c1a9140218 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Thu, 17 Nov 2016 11:40:37 +0100 Subject: [PATCH 396/643] Preparing for release v2.4_beta1 (ChangeLog, version.m4) Also ensuring the ChangeLog is completely UTF-8 encoded; discovered one ChangeLog entry had ISO-8859-1 encoding. Signed-off-by: David Sommerseth --- ChangeLog | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++- version.m4 | 2 +- 2 files changed, 79 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index cf76d7d677c..991aeb6a64d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,83 @@ OpenVPN Change Log Copyright (C) 2002-2016 OpenVPN Technologies, Inc. +2016.11.17 -- Version 2.4_beta1 +Arne Schwabe (1): + Make Changes.rst nicer for 2.4 release + +David Sommerseth (16): + Update .mailmap to unify and clean up odd names and e-mail addresses + cleanup: Remove NOP code sections in ssl.c:tls_process() + Remove last rest of INSTALL-win32.txt references + auth-gen-token: Add --auth-gen-token option + auth-gen-token: Generate an auth-token per client + auth-gen-token: Push generated auth-tokens to the client + auth-gen-token: Authenticate generated auth-tokens when client re-authenticates + Fix builds with --disable-crypto + man: Improve the --keepalive section + console: Fix compiler warning + systemd: Improve the systemd unit files + tun: Fix compiler warnings + file checks: Merge warn_if_group_others_accessible() into check_file_access() + tun: Fix weird commit error causing a double assignment + options: Remove --tls-remote + Remove unused variable in argv_printf_arglist() + +Gert Doering (10): + openvpn version line: remove [IPv6], add [AEAD] if available + clean up *sig_info handling in link_socket_init_phase2() + check c->c2.link_socket before calling do_init_route_ipv6_list() + Check previously-unchecked buf_alloc_write() call in crypto self-test. + Fix potential division by zero in shaper_reset() + Repair topology subnet on FreeBSD 11 + Repair topology subnet on OpenBSD + Add in_port_t check to configure.ac + Fix compilation on MinGW with -std=c99 + Replace WIN32 by _WIN32 + +Heiko Hund (4): + put argv_* functions into own file, add unit tests + Remove unused and unecessary argv interfaces + remove unused system_str from struct argv + Factor out %sc handling from argv_printf() + +Lev Stipakov (1): + Drop recursively routed packets + +Samuli Seppänen (6): + Remove INSTALL-win32.txt that is now hosted in openvpn-build + Fix update_t_client_ips.sh for out of tree builds + Make sure that all relevant files under test go to release tarballs + Allow passing extra arguments to fping/fping6 in t_client.rc + Prevent generation of duplicate EXPECT_IFCONFIG entries + Fix a logic problem in handling of --up scripts in t_client.sh + +Selva Nair (2): + Support --block-outside-dns on multiple tunnels + Unbreak windows build + +Steffan Karger (19): + Fix use-after-free bug in prepare_push_reply() + Remove verbose msg() from send_push_reply() + Limit --reneg-bytes to 64MB when using small block ciphers + Add a revoked cert to the sample keys + Fix --tls-version-max in mbed TLS builds + Don't deference type-punned pointers + Fix builds on compilers without anonymous union support + Refactor static/tls-auth key loading + Add missing includes in error.h + Make argv unit tests obey {MBEDTLS, OPENSSL}_{LIBS, CFLAGS} + Move private file access checks to options_postprocess_filechecks() + Deprecate key-method 1 + Refactor CRL handling + Remove unneeded check for extra_certs_file_inline + Fix missing return value checks in multi_process_float() + Restore pre-NCP cipher options on SIGUSR1 + Remove unused variables from do_init_crypto_static() + Add control channel encryption (--tls-crypt) + Add --tls-crypt unit tests + + 2016.10.19 -- Version 2.4_alpha2 David Sommerseth (1): @@ -525,7 +602,7 @@ Robert Fischer (1): Samuel Thibault (1): Ensure that client-connect files are always deleted -Samuli Sepp�nen (15): +Samuli Seppänen (15): Removed ChangeLog.IPv6 Added cross-compilation information INSTALL-win32.txt Updated README diff --git a/version.m4 b/version.m4 index dccd58f4446..ab8ea426529 100644 --- a/version.m4 +++ b/version.m4 @@ -3,7 +3,7 @@ define([PRODUCT_NAME], [OpenVPN]) define([PRODUCT_TARNAME], [openvpn]) define([PRODUCT_VERSION_MAJOR], [2]) define([PRODUCT_VERSION_MINOR], [4]) -define([PRODUCT_VERSION_PATCH], [_alpha2]) +define([PRODUCT_VERSION_PATCH], [_beta1]) m4_append([PRODUCT_VERSION], [PRODUCT_VERSION_MAJOR]) m4_append([PRODUCT_VERSION], [PRODUCT_VERSION_MINOR], [[.]]) m4_append([PRODUCT_VERSION], [PRODUCT_VERSION_PATCH], [[]]) From 237fd7f3f08b267d2be101f1d8f3989f3c5b3afb Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Fri, 18 Nov 2016 14:35:01 +0100 Subject: [PATCH 397/643] Changes.rst: Fixing wrong formatting Some places tabs had snuck in instead of spaces, making the rendering on GitHub odd. Signed-off-by: David Sommerseth --- Changes.rst | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Changes.rst b/Changes.rst index 0341b0b0abf..90c37722835 100644 --- a/Changes.rst +++ b/Changes.rst @@ -25,7 +25,7 @@ AEAD (GCM) data channel cipher support AES-128-CBC + HMAC-SHA1). ECDH key exchange - The TLS control channel now supports for elliptic curve diffie-hellmann + The TLS control channel now supports for elliptic curve diffie-hellmann key exchange (ECDH). Dualstack client connect @@ -33,7 +33,7 @@ Dualstack client connect will now try all addresses (IPv6 and IPv4) of a ``--remote`` entry. New improved Windows Background service - The new OpenVPNService is based on openvpnserv2, a complete rewrite of the OpenVPN + The new OpenVPNService is based on openvpnserv2, a complete rewrite of the OpenVPN service wrapper. It is intended for launching OpenVPN instances that should be up at all times, instead of being manually launched by a user. OpenVPNService is able to restart individual OpenVPN processes if they crash, and it also works @@ -41,18 +41,18 @@ New improved Windows Background service if at all, on newer Windows versions (8+) and its use is not recommended. New interactive Windows service - The installer starts OpenVPNServiceInteractive automatically and configures + The installer starts OpenVPNServiceInteractive automatically and configures it to start at system startup. The interactive Windows service allows unprivileged users to start - OpenVPN connections in the global config directory (usually - C:\Program Files\OpenVPN\config) using OpenVPN GUI without any - extra configuration. + OpenVPN connections in the global config directory (usually + C:\Program Files\OpenVPN\config) using OpenVPN GUI without any + extra configuration. - Users who belong to the built-in Administrator group or to the - local "OpenVPN Administrator" group can also store configuration - files under %USERPROFILE%\OpenVPN\config for use with the - interactive service. + Users who belong to the built-in Administrator group or to the + local "OpenVPN Administrator" group can also store configuration + files under %USERPROFILE%\OpenVPN\config for use with the + interactive service. redirect-gateway ipv6 OpenVPN has now feature parity between IPv4 and IPv6 for redirect @@ -60,7 +60,7 @@ redirect-gateway ipv6 IPv6 remote VPN server address LZ4 Compression and pushable compression - Additionally to LZO compression OpenVPN now also supports LZ4 compression. + Additionally to LZO compression OpenVPN now also supports LZ4 compression. Compression options are now pushable from the server. pull-filter @@ -108,7 +108,7 @@ Android platform support the OpenVPN for Android app (https://github.com/schwabe/ics-openvpn) AIX platform support - AIX platform support has been added. The support only includes tap + AIX platform support has been added. The support only includes tap devices since AIX does not provide tun interface. Control channel encryption (``--tls-crypt``) From 8025a62c63193d9a3c70033956342b86e01f01fc Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Sat, 19 Nov 2016 04:03:44 +0100 Subject: [PATCH 398/643] Document that tls-crypt also supports inline Acked-by: Steffan Karger Message-Id: <1479524624-13863-1-git-send-email-arne@rfc2549.org> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13120.html Signed-off-by: Gert Doering --- doc/openvpn.8 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index e997b096e1c..11564afca8d 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -6613,9 +6613,9 @@ X509_1_C=KG .SH INLINE FILE SUPPORT OpenVPN allows including files in the main configuration for the .B \-\-ca, \-\-cert, \-\-dh, \-\-extra\-certs, \-\-key, \-\-pkcs12, \-\-secret, -.B \-\-crl\-verify, \-\-http\-proxy\-user\-pass +.B \-\-crl\-verify, \-\-http\-proxy\-user\-pass, \-\-tls-auth and -.B \-\-tls\-auth +.B \-\-tls\-crypt options. Each inline file started by the line From c593885997e32a683f718138f7b9273d720c63e3 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sat, 19 Nov 2016 18:12:46 +0100 Subject: [PATCH 399/643] multi_process_float: revert part of c14c4a9e Commit c14c4a9e merged the hash_remove() and hash_add() calls in multi_process_float(), but didn't notice that the hash key (mi->real) was updated between these calls. So we now try to remove the *new* address instead of the *old* address from the hash table. This leaks memory and might break stuff when a different client floats to the old address/port of this client. Restore that. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1479575566-21198-1-git-send-email-steffan@karger.me> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13128.html Signed-off-by: Gert Doering --- src/openvpn/multi.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index 8f3d34e160b..4fc8b026480 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -2317,6 +2317,10 @@ void multi_process_float (struct multi_context* m, struct multi_instance* mi) mroute_addr_print (&mi->real, &gc), print_link_socket_actual (&m->top.c2.from, &gc)); + /* remove old address from hash table before changing address */ + ASSERT (hash_remove (m->hash, &mi->real)); + ASSERT (hash_remove (m->iter, &mi->real)); + /* change external network address of the remote peer */ mi->real = real; generate_prefix (mi); @@ -2330,8 +2334,8 @@ void multi_process_float (struct multi_context* m, struct multi_instance* mi) tls_update_remote_addr (mi->context.c2.tls_multi, &mi->context.c2.from); - ASSERT (hash_add (m->hash, &mi->real, mi, true)); - ASSERT (hash_add (m->iter, &mi->real, mi, true)); + ASSERT (hash_add (m->hash, &mi->real, mi, false)); + ASSERT (hash_add (m->iter, &mi->real, mi, false)); #ifdef MANAGEMENT_DEF_AUTH ASSERT (hash_add (m->cid_hash, &mi->context.c2.mda_context.cid, mi, true)); From 6ede22c4f58c7d32967299d6a71cda93c88dd656 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Sat, 19 Nov 2016 16:51:00 +0100 Subject: [PATCH 400/643] Fix warning that RAND_bytes is undeclared Acked-by: Gert Doering Message-Id: <1479570660-23630-1-git-send-email-arne@rfc2549.org> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13125.html Signed-off-by: Gert Doering --- src/openvpn/crypto_openssl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/openvpn/crypto_openssl.c b/src/openvpn/crypto_openssl.c index 1ea06bba1f3..306b6c6cf1e 100644 --- a/src/openvpn/crypto_openssl.c +++ b/src/openvpn/crypto_openssl.c @@ -47,6 +47,7 @@ #include #include #include +#include #include /* From 35be7e0d556a6b76e30f1e7348319e9dedf829aa Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Sat, 19 Nov 2016 16:35:56 +0100 Subject: [PATCH 401/643] Remove compat-stdbool.h. Since we use C99, we are guaranteed to have stdbool.h available Acked-by: Gert Doering Message-Id: <1479569756-23302-1-git-send-email-arne@rfc2549.org> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13123.html Signed-off-by: Gert Doering --- src/compat/compat-stdbool.h | 12 ------------ src/openvpn/syshead.h | 2 +- 2 files changed, 1 insertion(+), 13 deletions(-) delete mode 100644 src/compat/compat-stdbool.h diff --git a/src/compat/compat-stdbool.h b/src/compat/compat-stdbool.h deleted file mode 100644 index 99412188fe5..00000000000 --- a/src/compat/compat-stdbool.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef __COMPAT_STDBOOL_H -#define __COMPAT_STDBOOL_H - -#ifdef HAVE_STDBOOL_H -#include -#else -typedef int bool; -#define false 0 -#define true 1 -#endif - -#endif diff --git a/src/openvpn/syshead.h b/src/openvpn/syshead.h index 8de7d87293d..f5008b792bb 100644 --- a/src/openvpn/syshead.h +++ b/src/openvpn/syshead.h @@ -26,7 +26,7 @@ #define SYSHEAD_H #include "compat.h" -#include "compat-stdbool.h" +#include /* branch prediction hints */ #if defined(__GNUC__) From 3212d0c0a5caac6607b30effb584887eb3325942 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Sat, 19 Nov 2016 16:42:44 +0100 Subject: [PATCH 402/643] Fix various compiler warnings - move p2mp only push_option_fmt to p2mp only section to avoid warning that struct push_list being defined in the argument list - incoming_push_message not declared on client without server by putting it into the right define block Acked-by: Gert Doering Message-Id: <1479570164-23522-1-git-send-email-arne@rfc2549.org> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13124.html Signed-off-by: Gert Doering --- src/openvpn/push.c | 49 +++++++++++++++++++++++----------------------- src/openvpn/push.h | 3 +-- 2 files changed, 25 insertions(+), 27 deletions(-) diff --git a/src/openvpn/push.c b/src/openvpn/push.c index f86bdd37613..b7539e6def9 100644 --- a/src/openvpn/push.c +++ b/src/openvpn/push.c @@ -42,31 +42,6 @@ static char push_reply_cmd[] = "PUSH_REPLY"; -/** - * Add an option to the given push list by providing a format string. - * - * The string added to the push options is allocated in o->gc, so the caller - * does not have to preserve anything. - * - * @param gc GC arena where options are allocated - * @param push_list Push list containing options - * @param msglevel The message level to use when printing errors - * @param fmt Format string for the option - * @param ... Format string arguments - * - * @return true on success, false on failure. - */ -static bool push_option_fmt(struct gc_arena *gc, struct push_list *push_list, - int msglevel, const char *fmt, ...) -#ifdef __GNUC__ -#if __USE_MINGW_ANSI_STDIO - __attribute__ ((format (gnu_printf, 4, 5))) -#else - __attribute__ ((format (__printf__, 4, 5))) -#endif -#endif - ; - /* * Auth username/password * @@ -177,6 +152,30 @@ server_pushed_signal (struct context *c, const struct buffer *buffer, const bool } #if P2MP_SERVER +/** + * Add an option to the given push list by providing a format string. + * + * The string added to the push options is allocated in o->gc, so the caller + * does not have to preserve anything. + * + * @param gc GC arena where options are allocated + * @param push_list Push list containing options + * @param msglevel The message level to use when printing errors + * @param fmt Format string for the option + * @param ... Format string arguments + * + * @return true on success, false on failure. + */ +static bool push_option_fmt(struct gc_arena *gc, struct push_list *push_list, + int msglevel, const char *fmt, ...) +#ifdef __GNUC__ +#if __USE_MINGW_ANSI_STDIO + __attribute__ ((format (gnu_printf, 4, 5))) +#else + __attribute__ ((format (__printf__, 4, 5))) +#endif +#endif + ; /* * Send auth failed message from server to client. diff --git a/src/openvpn/push.h b/src/openvpn/push.h index d6cb4b1e0e8..1dfd80e5b2b 100644 --- a/src/openvpn/push.h +++ b/src/openvpn/push.h @@ -51,10 +51,9 @@ void receive_auth_failed (struct context *c, const struct buffer *buffer); void server_pushed_signal (struct context *c, const struct buffer *buffer, const bool restart, const int adv); -#if P2MP_SERVER - void incoming_push_message (struct context *c, const struct buffer *buffer); +#if P2MP_SERVER void clone_push_list (struct options *o); void push_option (struct options *o, const char *opt, int msglevel); From e5fc56a77ee08d10974ab7a245ceb94e13761a1b Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Sun, 20 Nov 2016 08:47:40 +0100 Subject: [PATCH 403/643] Remove remaining traces of compat-stdbool.h commit 35be7e0d5 removed most references to compat-stdbool.h but overlooked configure and "make dist" Signed-off-by: Gert Doering Acked-by: Selva Nair Message-Id: <1479628060-32673-1-git-send-email-gert@greenie.muc.de> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13135.html Signed-off-by: Gert Doering --- configure.ac | 2 +- src/compat/Makefile.am | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 4a45f057cad..f4073d051e8 100644 --- a/configure.ac +++ b/configure.ac @@ -435,7 +435,7 @@ AX_EMPTY_ARRAY AC_CHECK_SIZEOF([unsigned int]) AC_CHECK_SIZEOF([unsigned long]) AC_CHECK_HEADERS([ \ - stdio.h stdarg.h stdbool.h limits.h \ + stdio.h stdarg.h limits.h \ time.h errno.h fcntl.h io.h direct.h \ ctype.h sys/types.h sys/socket.h \ signal.h unistd.h dlfcn.h \ diff --git a/src/compat/Makefile.am b/src/compat/Makefile.am index 06bab5c2e80..0a9d1c25edf 100644 --- a/src/compat/Makefile.am +++ b/src/compat/Makefile.am @@ -20,7 +20,6 @@ noinst_LTLIBRARIES = libcompat.la libcompat_la_SOURCES = \ compat.h \ - compat-stdbool.h \ compat-dirname.c \ compat-basename.c \ compat-gettimeofday.c \ From d6ad8cac443f7f7540da595a3dbe7082d0f0a0cf Mon Sep 17 00:00:00 2001 From: Selva Nair Date: Sun, 20 Nov 2016 16:18:54 -0500 Subject: [PATCH 404/643] Do not set ipv6 address if '--ip-win32 manual' is used This also applies to --ifconfig-noexec. Resolves Trac #723 Signed-off-by: Selva Nair Acked-by: Gert Doering Message-Id: <1479676734-21630-1-git-send-email-selva.nair@gmail.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13143.html Signed-off-by: Gert Doering --- src/openvpn/tun.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index 77ae72fa804..36e0b15be10 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -1372,7 +1372,13 @@ do_ifconfig (struct tuntap *tt, if ( do_ipv6 ) { - if (tt->options.msg_channel) + if (tt->options.ip_win32_type == IPW32_SET_MANUAL) + { + msg (M_INFO, "******** NOTE: Please manually set the v6 IP of '%s' to %s (if it is not already set)", + actual, + ifconfig_ipv6_local); + } + else if (tt->options.msg_channel) { do_address_service (true, AF_INET6, tt); } @@ -1391,7 +1397,10 @@ do_ifconfig (struct tuntap *tt, } /* explicit route needed */ - add_route_connected_v6_net(tt, es); + if (tt->options.ip_win32_type != IPW32_SET_MANUAL) + { + add_route_connected_v6_net(tt, es); + } } #else msg (M_FATAL, "Sorry, but I don't know how to do 'ifconfig' commands on this operating system. You should ifconfig your TUN/TAP device manually or use an --up script."); From 94bfc256d4e96e6e91fa5a518352d758c09800f3 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Mon, 21 Nov 2016 17:42:42 +0100 Subject: [PATCH 405/643] Stub implementation of "--dhcp-option DNS6 " This defines a new DHCP suboption "DNS6", but does not actually implement anything but "document the option and understand it". If received, it will be put into an "foreign_option_" environment variable where an --up script or plugin could receive and act upon it. On non-Windows platforms, all "dhcp-option" sub-options end up there, so v4 and v6 DNS options will be reflected like this: foreign_option_1=dhcp-option DNS6 2001:608::2 foreign_option_2=dhcp-option DNS 195.30.0.2 v2: do not set o->dhcp_options if DNS6 is the single dhcp-option seen (spotted by Selva Nair) Signed-off-by: Gert Doering Acked-by: Selva Nair Message-Id: <1479746562-751-1-git-send-email-gert@greenie.muc.de> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13174.html Signed-off-by: Gert Doering --- doc/openvpn.8 | 14 +++++++++++++- src/openvpn/options.c | 20 ++++++++++++++++++-- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 11564afca8d..d454a3659d7 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -5627,9 +5627,21 @@ across the VPN. Set Connection-specific DNS Suffix. .B DNS addr \-\- -Set primary domain name server address. Repeat +Set primary domain name server IPv4 address. Repeat this option to set secondary DNS server addresses. +.B DNS6 addr \-\- +Set primary domain name server IPv6 address. Repeat +this option to set secondary DNS server IPv6 addresses. + +Note: currently this is somewhat of a placeholder option - it is +understood, but OpenVPN has no code to tell Windows about it (the +existing DHCP code can only do IPv4 DHCP, and that protocol only +permits IPv4 addresses anywhere). The option will be put into the +environment, so an +.B \-\-up +script could act upon it. + .B WINS addr \-\- Set primary WINS server address (NetBIOS over TCP/IP Name Server). Repeat this option to set secondary WINS server addresses. diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 7f128c36eb6..f30e62dd7bd 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -704,7 +704,8 @@ static const char usage_message[] = " which allow multiple addresses,\n" " --dhcp-option must be repeated.\n" " DOMAIN name : Set DNS suffix\n" - " DNS addr : Set domain name server address(es)\n" + " DNS addr : Set domain name server address(es) (IPv4)\n" + " DNS6 addr : Set domain name server address(es) (IPv6)\n" " NTP : Set NTP server address(es)\n" " NBDD : Set NBDD server address(es)\n" " WINS addr : Set WINS server address(es)\n" @@ -6406,6 +6407,14 @@ add_option (struct options *options, { dhcp_option_address_parse ("DNS", p[2], o->dns, &o->dns_len, msglevel); } + else if (streq (p[1], "DNS6") && p[2]) + { + /* this is somewhat of a placeholder - we understand the option, + * but cannot act upon it - so we'll just accept it and put it + * into the environment, as we would do on all non-win32 platforms + */ + foreign_option (options, p, 3, es); + } else if (streq (p[1], "WINS") && p[2]) { dhcp_option_address_parse ("WINS", p[2], o->wins, &o->wins_len, msglevel); @@ -6427,7 +6436,14 @@ add_option (struct options *options, msg (msglevel, "--dhcp-option: unknown option type '%s' or missing or unknown parameter", p[1]); goto err; } - o->dhcp_options = true; + + /* flag that we have options to give to the TAP driver's DHCPv4 server + * - skipped for "DNS6", as that's not a DHCPv4 option + */ + if (!streq (p[1], "DNS6")) + { + o->dhcp_options = true; + } } #endif #ifdef _WIN32 From 786e06ade9f5dfad8ac360499187fa8e536d15cb Mon Sep 17 00:00:00 2001 From: Selva Nair Date: Mon, 21 Nov 2016 22:12:12 -0500 Subject: [PATCH 406/643] Handle --dhcp-option DNS6 on Windows using netsh v2: On closing tun delete the ipv6 dns addresses (if any were set). Also use "validate=no" only in Windows 7 and higher where it is supported. Its used to skip the time consuming automatic address validation which is on by default on those platforms. Tested on Windows Server 2008 (i686), Win 7 (x64) and Win 10 (x64) TODO: set dns servers using the interactive service Signed-off-by: Selva Nair Acked-by: Gert Doering Message-Id: <1479784332-21680-1-git-send-email-selva.nair@gmail.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13193.html Signed-off-by: Gert Doering --- doc/openvpn.8 | 5 ++--- src/openvpn/options.c | 16 ++++++++----- src/openvpn/tun.c | 52 +++++++++++++++++++++++++++++++++++++++++++ src/openvpn/tun.h | 3 +++ 4 files changed, 68 insertions(+), 8 deletions(-) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index d454a3659d7..171bd724354 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -5634,13 +5634,12 @@ this option to set secondary DNS server addresses. Set primary domain name server IPv6 address. Repeat this option to set secondary DNS server IPv6 addresses. -Note: currently this is somewhat of a placeholder option - it is -understood, but OpenVPN has no code to tell Windows about it (the +Note: currently this is handled using netsh and requires admin rights (the existing DHCP code can only do IPv4 DHCP, and that protocol only permits IPv4 addresses anywhere). The option will be put into the environment, so an .B \-\-up -script could act upon it. +script could act upon it if needed. .B WINS addr \-\- Set primary WINS server address (NetBIOS over TCP/IP Name Server). diff --git a/src/openvpn/options.c b/src/openvpn/options.c index f30e62dd7bd..8e09e4a00b6 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -6407,13 +6407,19 @@ add_option (struct options *options, { dhcp_option_address_parse ("DNS", p[2], o->dns, &o->dns_len, msglevel); } - else if (streq (p[1], "DNS6") && p[2]) + else if (streq (p[1], "DNS6") && p[2] && ipv6_addr_safe(p[2])) { - /* this is somewhat of a placeholder - we understand the option, - * but cannot act upon it - so we'll just accept it and put it - * into the environment, as we would do on all non-win32 platforms - */ + struct in6_addr addr; foreign_option (options, p, 3, es); + if (o->dns6_len >= N_DHCP_ADDR) + { + msg (msglevel, "--dhcp-option DNS6: maximum of %d dns servers can be specified", + N_DHCP_ADDR); + } + else if (get_ipv6_addr (p[2], &addr, NULL, msglevel)) + { + o->dns6[o->dns6_len++] = addr; + } } else if (streq (p[1], "WINS") && p[2]) { diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index 36e0b15be10..a079f4718d2 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -68,6 +68,9 @@ static void netsh_ifconfig (const struct tuntap_options *to, const in_addr_t ip, const in_addr_t netmask, const unsigned int flags); +static void netsh_set_dns6_servers (const struct in6_addr *addr_list, + const int addr_len, + const char *flex_name); static void netsh_command (const struct argv *a, int n, int msglevel); static const char *netsh_get_id (const char *dev_node, struct gc_arena *gc); @@ -1381,6 +1384,7 @@ do_ifconfig (struct tuntap *tt, else if (tt->options.msg_channel) { do_address_service (true, AF_INET6, tt); + /* TODO: do_dns6_service() */ } else { @@ -1394,6 +1398,8 @@ do_ifconfig (struct tuntap *tt, iface, ifconfig_ipv6_local ); netsh_command (&argv, 4, M_FATAL); + /* set ipv6 dns servers if any are specified */ + netsh_set_dns6_servers(tt->options.dns6, tt->options.dns6_len, actual); } /* explicit route needed */ @@ -4626,6 +4632,41 @@ ip_addr_member_of (const in_addr_t addr, const IP_ADDR_STRING *ias) return false; } +/** + * Set the ipv6 dns servers on the specified interface. + * The list of dns servers currently set on the interface + * are cleared first. + * No action is taken if number of addresses (addr_len) < 1. + */ +static void +netsh_set_dns6_servers (const struct in6_addr *addr_list, + const int addr_len, + const char *flex_name) +{ + struct gc_arena gc = gc_new (); + struct argv argv = argv_new (); + + for (int i = 0; i < addr_len; ++i) + { + const char *fmt = (i == 0) ? + "%s%sc interface ipv6 set dns %s static %s" + : "%s%sc interface ipv6 add dns %s %s"; + argv_printf (&argv, fmt, get_win_sys_path(), + NETSH_PATH_SUFFIX, flex_name, + print_in6_addr (addr_list[i], 0, &gc)); + + /* disable slow address validation on Windows 7 and higher */ + if (win32_version_info() >= WIN_7) + argv_printf_cat (&argv, "%s", "validate=no"); + + /* Treat errors while adding as non-fatal as we do not check for duplicates */ + netsh_command (&argv, 1, (i==0)? M_FATAL : M_NONFATAL); + } + + argv_reset (&argv); + gc_free (&gc); +} + static void netsh_ifconfig_options (const char *type, const in_addr_t *addr_list, @@ -5572,6 +5613,17 @@ close_tun (struct tuntap *tt) ifconfig_ipv6_local); netsh_command (&argv, 1, M_WARN); + + /* delete ipv6 dns servers if any were set */ + if (tt->options.dns6_len > 0) + { + argv_printf (&argv, + "%s%sc interface ipv6 delete dns %s all", + get_win_sys_path(), + NETSH_PATH_SUFFIX, + tt->actual_name); + netsh_command (&argv, 1, M_WARN); + } argv_reset (&argv); } } diff --git a/src/openvpn/tun.h b/src/openvpn/tun.h index dedd915c350..9b5a1b7cca6 100644 --- a/src/openvpn/tun.h +++ b/src/openvpn/tun.h @@ -107,6 +107,9 @@ struct tuntap_options { bool dhcp_release; bool register_dns; + + struct in6_addr dns6[N_DHCP_ADDR]; + int dns6_len; }; #elif TARGET_LINUX From 39b7d4da02c40e76640c4da96ef7da7a6354cc00 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Tue, 22 Nov 2016 12:38:36 +0100 Subject: [PATCH 407/643] Handle DNS6 option on Android Patch V2: Prefer IPv6 DNS servers Acked-by: Gert Doering Message-Id: <1479814716-20116-1-git-send-email-arne@rfc2549.org> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13195.html Signed-off-by: Gert Doering --- doc/android.txt | 3 ++- src/openvpn/tun.c | 10 ++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/doc/android.txt b/doc/android.txt index 5f4ee95290e..e287be0a8b2 100644 --- a/doc/android.txt +++ b/doc/android.txt @@ -47,7 +47,8 @@ ROUTE network netmask To tell the UI which routes should be set on the tun interface. -DNSSERVER serverip +DNSSERVER IP server address +DNS6SERVER IPv6 server address DNSDOMAIN searchdomain To set the DNS server and search domain. diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index a079f4718d2..3ebf2b2b531 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -1638,14 +1638,20 @@ void open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) { #define ANDROID_TUNNAME "vpnservice-tun" - int i; struct user_pass up; struct gc_arena gc = gc_new (); bool opentun; int oldtunfd = tt->fd; - for (i = 0; i < tt->options.dns_len; ++i) { + /* Prefer IPv6 DNS servers, + * Android will use the DNS server in the order we specify*/ + for (int i = 0; i < tt->options.dns6_len; i++) { + management_android_control (management, "DNS6SERVER", + print_in6_addr (tt->options.dns6[i], 0, &gc)); + } + + for (int i = 0; i < tt->options.dns_len; i++) { management_android_control (management, "DNSSERVER", print_in_addr_t(tt->options.dns[i], 0, &gc)); } From 418d2d98489dfe7afafcaf21828541d034afb7f4 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Tue, 22 Nov 2016 21:41:26 +0100 Subject: [PATCH 408/643] --tls-crypt fixes * Check return value of buf_init() (found by coverity) * Use the TLS frame to determine the buffer size, as is done for the reliability buffers used for tls-auth. (We previously incorrectly used the TLS *plaintext* buffer size, which is bigger for typical setups with tun-mtu <= 1500. Using the frame to calculate the size saves some bytes for typical setups, and doesn't break setups with big tun-mtu.) * More carefully handle errors in tls_crypt_wrap() - just drop the packet instead of ASSERT()ing out (should not happen in the first place, but this is a bit more friendly if it happens somehow anyway). Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1479847286-17518-1-git-send-email-steffan@karger.me> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13204.html Signed-off-by: Gert Doering --- src/openvpn/ssl.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index dc063501d47..97e9aaba276 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -973,7 +973,7 @@ tls_session_init (struct tls_multi *multi, struct tls_session *session) /* Initialize control channel authentication parameters */ session->tls_wrap = session->opt->tls_wrap; - session->tls_wrap.work = alloc_buf (TLS_CHANNEL_BUF_SIZE); + session->tls_wrap.work = alloc_buf (BUF_SIZE (&session->opt->frame)); /* initialize packet ID replay window for --tls-auth */ packet_id_init (&session->tls_wrap.opt.packet_id, @@ -1320,13 +1320,20 @@ write_control_auth (struct tls_session *session, } else if (session->tls_wrap.mode == TLS_WRAP_CRYPT) { - buf_init (&session->tls_wrap.work, buf->offset); + ASSERT (buf_init (&session->tls_wrap.work, buf->offset)); ASSERT (buf_write (&session->tls_wrap.work, &header, sizeof(header))); ASSERT (session_id_write (&session->session_id, &session->tls_wrap.work)); - ASSERT (tls_crypt_wrap (buf, &session->tls_wrap.work, &session->tls_wrap.opt)); - /* Don't change the original data in buf, it's used by the reliability - * layer to resend on failure. */ - *buf = session->tls_wrap.work; + if (tls_crypt_wrap (buf, &session->tls_wrap.work, &session->tls_wrap.opt)) + { + /* Don't change the original data in buf, it's used by the reliability + * layer to resend on failure. */ + *buf = session->tls_wrap.work; + } + else + { + buf->len = 0; + return; + } } *to_link_addr = &ks->remote_addr; } From da941141f34935f2c362b262a83de3cd722b65d6 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Tue, 22 Nov 2016 21:12:08 +0100 Subject: [PATCH 409/643] Change cmocka remote to use https in stead of git protocol Allows to clone the cmocka submodule from networks where 'anything but web and mail' is firewalled. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1479845528-16068-1-git-send-email-steffan@karger.me> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13203.html Signed-off-by: Gert Doering --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index e9c63884c72..c1ff36e1be8 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "vendor/cmocka"] path = vendor/cmocka - url = git://git.cryptomilk.org/projects/cmocka.git + url = https://git.cryptomilk.org/projects/cmocka.git branch = master From 48d41413c4b181e00769cdb83ccfe179299ad8e4 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Tue, 22 Nov 2016 21:09:26 +0100 Subject: [PATCH 410/643] generate_key_expansion: make assumption explicit, use C99 features This function potentially allocates memory, and can therefor not be run again on an initialized key_ctx_bi. Make this explicit by adding an error if someone tries do to this anyway. While touching the function, cleanup it up a bit to make up for the added lines of code. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1479845366-15774-1-git-send-email-steffan@karger.me> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13202.html Signed-off-by: Gert Doering --- src/openvpn/ssl.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 97e9aaba276..16b9cb7b092 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -1620,13 +1620,15 @@ generate_key_expansion (struct key_ctx_bi *key, const struct session_id *server_sid, bool server) { - uint8_t master[48]; - struct key2 key2; + uint8_t master[48] = { 0 }; + struct key2 key2 = { 0 }; bool ret = false; - int i; - CLEAR (master); - CLEAR (key2); + if (key->initialized) + { + msg (D_TLS_ERRORS, "TLS Error: key already initialized"); + goto exit; + } /* debugging print of source key material */ key_source2_print (key_src); @@ -1662,7 +1664,7 @@ generate_key_expansion (struct key_ctx_bi *key, key2_print (&key2, key_type, "Master Encrypt", "Master Decrypt"); /* check for weak keys */ - for (i = 0; i < 2; ++i) + for (int i = 0; i < 2; ++i) { fixup_key (&key2.keys[i], key_type); if (!check_key (&key2.keys[i], key_type)) From f8a367f7c51af5482013fa3d783cade376b047ed Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Sat, 17 Sep 2016 16:20:15 +0300 Subject: [PATCH 411/643] Document the --auth-token option This isn't an option to be used directly in any configuration files, but to be used via --client-connect scripts or --plugin making use of OPENVPN_PLUGIN_CLIENT_CONNECT or OPENVPN_PLUGIN_CLIENT_CONNECT_V2. [v2 - Added lacking .B styling of options - Clarified the token life time ] Signed-off-by: David Sommerseth Acked-by: Gert Doering Message-Id: <1474118415-14666-1-git-send-email-davids@openvpn.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg12506.html Signed-off-by: Gert Doering --- doc/openvpn.8 | 56 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 171bd724354..ffb0f7dd811 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -4,7 +4,7 @@ .\" packet encryption, packet authentication, and .\" packet compression. .\" -.\" Copyright (C) 2002-2010 OpenVPN Technologies, Inc. +.\" Copyright (C) 2002-2016 OpenVPN Technologies, Inc. .\" .\" This program is free software; you can redistribute it and/or modify .\" it under the terms of the GNU General Public License version 2 @@ -34,7 +34,7 @@ .\" .ft -- normal face .\" .in +|-{n} -- indent .\" -.TH openvpn 8 "17 November 2008" +.TH openvpn 8 "25 August 2016" .\"********************************************************* .SH NAME openvpn \- secure IP tunnel daemon. @@ -2928,6 +2928,7 @@ This is a partial list of options which can currently be pushed: .B \-\-ip\-win32, \-\-dhcp\-option, .B \-\-inactive, \-\-ping, \-\-ping\-exit, \-\-ping\-restart, .B \-\-setenv, +.B \-\-auth\-token, .B \-\-persist\-key, \-\-persist\-tun, \-\-echo, .B \-\-comp\-lzo, .B \-\-socket\-flags, @@ -5089,6 +5090,57 @@ This directive does not affect the username/password. It is always cached. .\"********************************************************* .TP +.B \-\-auth\-token token +This is not an option to be used directly in any configuration files, +but rather push this option from a +.B \-\-client\-connect +script or a +.B \-\-plugin +which hooks into the OPENVPN_PLUGIN_CLIENT_CONNECT or +OPENVPN_PLUGIN_CLIENT_CONNECT_V2 calls. This option provides +a possibility to replace the clients password with an authentication +token during the lifetime of the OpenVPN client. + +Whenever the connection is renegotiated and the +.B \-\-auth\-user\-pass\-verify +script or +.B \-\-plugin +making use of the OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY hook is +triggered, it will pass over this token as the password +instead of the password the user provided. The authentication +token can only be reset by a full reconnect where the server +can push new options to the client. The password the user entered +is never preserved once an authentication token have been set. If +the OpenVPN server side rejects the authentication token, the +client will receive an AUTH_FAIL and disconnect. + +The purpose of this is to enable two factor authentication +methods, such as HOTP or TOTP, to be used without needing to +retrieve a new OTP code each time the connection is renegotiated. +Another use case is to cache authentication data on the client +without needing to have the users password cached in memory +during the life time of the session. + +To make use of this feature, the +.B \-\-client\-connect +script or +.B \-\-plugin +needs to put + +.nf +.ft 3 +.in +4 +push "auth\-token UNIQUE_TOKEN_VALUE" +.in -4 +.ft +.fi + +into the file/buffer for dynamic configuration data. This +will then make the OpenVPN server to push this value to the +client, which replaces the local password with the +UNIQUE_TOKEN_VALUE. +.\"********************************************************* +.TP .B \-\-tls\-verify cmd Run command .B cmd From 6e5ad2fa0b1e7ca2e05e0a38f47ed5561cda63b0 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Wed, 23 Nov 2016 22:21:44 +0100 Subject: [PATCH 412/643] Poor man's NCP for non-NCP peers Allows non-NCP peers (<= 2.3, or 2.4+ with --ncp-disable) to specify a --cipher that is different from the one in our config, as long as the new cipher value is allowed (i.e. in --ncp-ciphers at our side). This works both client-to-server and server-to-client. I.e. a 2.4 client with "cipher BF-CBC" and "ncp-ciphers AES-256-GCM:AES-256-CBC" can connect to both a 2.3 server with "cipher BF-CBC" as well as a server with "cipher AES-256-CBC" in its config. The other way around, a 2.3 client with either "cipher BF-CBC" or "cipher AES-256-CBC" can connect to a 2.4 server with e.g. "cipher BF-CBC" and "ncp-ciphers AES-256-GCM:AES-256-CBC" in its config. This patch was inspired by Gert's "Poor man's NCP for 2.3 clients" patch, but takes a different approach to avoid the need for server-side scripts or client-side 'setenv UV_*' tricks. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1479936104-4045-1-git-send-email-steffan@karger.me> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13218.html Signed-off-by: Gert Doering --- doc/openvpn.8 | 14 ++++++++++++-- src/openvpn/init.c | 10 ++++++++-- src/openvpn/options.c | 32 ++++++++++++++++++++++++++++++++ src/openvpn/options.h | 14 ++++++++++++++ src/openvpn/push.c | 6 +++++- src/openvpn/ssl.c | 36 +++++++++++++++++++++++++++++++----- src/openvpn/ssl.h | 16 ++++++++++++++++ src/openvpn/ssl_common.h | 2 ++ 8 files changed, 120 insertions(+), 10 deletions(-) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index ffb0f7dd811..0aa04449de7 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -4148,9 +4148,9 @@ to disable encryption. As of OpenVPN 2.4, cipher negotiation (NCP) can override the cipher specified by .B \-\-cipher\fR. See -.B \-\-ncp-ciphers +.B \-\-ncp\-ciphers and -.B \-\-ncp-disable +.B \-\-ncp\-disable for more on NCP. .\"********************************************************* @@ -4178,6 +4178,16 @@ If both peers support and do not disable NCP, the negotiated cipher will override the cipher specified by .B \-\-cipher\fR. +Additionally, to allow for more smooth transition, if NCP is enabled, OpenVPN +will inherit the cipher of the peer if that cipher is different from the local +.B \-\-cipher +setting, but the peer cipher is one of the ciphers specified in +.B \-\-ncp\-ciphers\fR. +E.g. a non-NCP client (<=2.3, or with \-\-ncp\-disabled set) connecting to a +NCP server (2.4+) with "\-\-cipher BF-CBC" and "\-\-ncp-ciphers +AES-256-GCM:AES-256-CBC" set can either specify "\-\-cipher BF-CBC" or +"\-\-cipher AES-256-CBC" and both will work. + .\"********************************************************* .TP .B \-\-ncp\-disable diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 470dc89af03..2ccbab2f788 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -1932,8 +1932,14 @@ do_deferred_options (struct context *c, const unsigned int found) { struct tls_session *session = &c->c2.tls_multi->session[TM_ACTIVE]; if (found & OPT_P_NCP) - msg (D_PUSH, "OPTIONS IMPORT: data channel crypto options modified"); - /* Do not regenerate keys if server sends an extra push request */ + { + msg (D_PUSH, "OPTIONS IMPORT: data channel crypto options modified"); + } + else if (c->options.ncp_enabled) + { + tls_poor_mans_ncp(&c->options, c->c2.tls_multi->remote_ciphername); + } + /* Do not regenerate keys if server sends an extra push reply */ if (!session->key[KS_PRIMARY].crypto_options.key_ctx_bi.initialized && !tls_session_update_crypto_params(session, &c->options, &c->c2.frame)) { diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 8e09e4a00b6..7c2b989d828 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -1643,6 +1643,8 @@ show_settings (const struct options *o) SHOW_STR (shared_secret_file); SHOW_INT (key_direction); SHOW_STR (ciphername); + SHOW_BOOL (ncp_enabled); + SHOW_STR (ncp_ciphers); SHOW_STR (authname); SHOW_STR (prng_hash); SHOW_INT (prng_nonce_secret_len); @@ -3445,6 +3447,36 @@ options_string_version (const char* s, struct gc_arena *gc) #endif /* ENABLE_OCC */ +char * +options_string_extract_option (const char *options_string,const char *opt_name, + struct gc_arena *gc) +{ + char *ret = NULL; + const size_t opt_name_len = strlen(opt_name); + + const char *p = options_string; + while (p) + { + if (0 == strncmp(p, opt_name, opt_name_len) && + strlen(p) > (opt_name_len+1) && p[opt_name_len] == ' ') + { + /* option found, extract value */ + const char *start = &p[opt_name_len+1]; + const char *end = strchr (p, ','); + size_t val_len = end ? end - start : strlen (start); + ret = gc_malloc (val_len+1, true, gc); + memcpy (ret, start, val_len); + break; + } + p = strchr (p, ','); + if (p) + { + p++; /* skip delimiter */ + } + } + return ret; +} + static void foreign_option (struct options *o, char *argv[], int len, struct env_set *es) { diff --git a/src/openvpn/options.h b/src/openvpn/options.h index a02855613b3..067728a070f 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -726,6 +726,20 @@ void options_warning (char *actual, const char *expected); #endif +/** + * Given an OpenVPN options string, extract the value of an option. + * + * @param options_string Zero-terminated, comma-separated options string + * @param opt_name The name of the option to extract + * @param gc The gc to allocate the return value + * + * @return gc-allocated value of option with name opt_name if option was found, + * or NULL otherwise. + */ +char *options_string_extract_option (const char *options_string, + const char *opt_name, struct gc_arena *gc); + + void options_postprocess (struct options *options); void pre_pull_save (struct options *o); diff --git a/src/openvpn/push.c b/src/openvpn/push.c index b7539e6def9..9953079c603 100644 --- a/src/openvpn/push.c +++ b/src/openvpn/push.c @@ -262,7 +262,7 @@ incoming_push_message (struct context *c, const struct buffer *buffer) !tls_session_update_crypto_params (session, &c->options, &c->c2.frame)) { - msg (D_TLS_ERRORS, "TLS Error: server generate_key_expansion failed"); + msg (D_TLS_ERRORS, "TLS Error: initializing data channel failed"); goto error; } } @@ -370,6 +370,10 @@ prepare_push_reply (struct context *c, struct gc_arena *gc, push_option_fmt(gc, push_list, M_USAGE, "cipher %s", o->ciphername); } } + else if (o->ncp_enabled) + { + tls_poor_mans_ncp (o, tls_multi->remote_ciphername); + } /* If server uses --auth-gen-token and we have an auth token * to send to the client diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 16b9cb7b092..8259292e75b 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -1216,6 +1216,8 @@ tls_multi_free (struct tls_multi *multi, bool clear) free (multi->auth_token); } + free (multi->remote_ciphername); + for (i = 0; i < TM_SIZE; ++i) tls_session_free (&multi->session[i], false); @@ -1723,8 +1725,8 @@ key_ctx_update_implicit_iv(struct key_ctx *ctx, uint8_t *key, size_t key_len) { } } -static bool -item_in_list(const char *item, const char *list) +bool +tls_item_in_cipher_list(const char *item, const char *list) { char *tmp_ciphers = string_alloc (list, NULL); char *tmp_ciphers_orig = tmp_ciphers; @@ -1741,6 +1743,20 @@ item_in_list(const char *item, const char *list) return token != NULL; } +void +tls_poor_mans_ncp(struct options *o, const char *remote_ciphername) +{ + if (o->ncp_enabled && remote_ciphername && + 0 != strcmp(o->ciphername, remote_ciphername)) + { + if (tls_item_in_cipher_list(remote_ciphername, o->ncp_ciphers)) + { + o->ciphername = string_alloc(remote_ciphername, &o->gc); + msg (D_TLS_DEBUG_LOW, "Using peer cipher '%s'", o->ciphername); + } + } +} + bool tls_session_update_crypto_params(struct tls_session *session, const struct options *options, struct frame *frame) @@ -1752,7 +1768,7 @@ tls_session_update_crypto_params(struct tls_session *session, if (!session->opt->server && 0 != strcmp(options->ciphername, session->opt->config_ciphername) && - !item_in_list(options->ciphername, options->ncp_ciphers)) + !tls_item_in_cipher_list(options->ciphername, options->ncp_ciphers)) { msg (D_TLS_ERRORS, "Error: pushed cipher not allowed - %s not in %s or %s", options->ciphername, session->opt->config_ciphername, @@ -2312,10 +2328,20 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi if ( multi->peer_info ) output_peer_info_env (session->opt->es, multi->peer_info); + free (multi->remote_ciphername); + multi->remote_ciphername = + options_string_extract_option (options, "cipher", NULL); + if (tls_peer_info_ncp_ver (multi->peer_info) < 2) { - /* Peer does not support NCP */ - session->opt->ncp_enabled = false; + /* Peer does not support NCP, but leave NCP enabled if the local and + * remote cipher do not match to attempt 'poor-man's NCP'. + */ + if (multi->remote_ciphername == NULL || + 0 == strcmp(multi->remote_ciphername, multi->opt.config_ciphername)) + { + session->opt->ncp_enabled = false; + } } #endif diff --git a/src/openvpn/ssl.h b/src/openvpn/ssl.h index 777b62165c9..047eb248d63 100644 --- a/src/openvpn/ssl.h +++ b/src/openvpn/ssl.h @@ -489,6 +489,15 @@ void tls_update_remote_addr (struct tls_multi *multi, bool tls_session_update_crypto_params(struct tls_session *session, const struct options *options, struct frame *frame); +/** + * "Poor man's NCP": Use peer cipher if it is an allowed (NCP) cipher. + * Allows non-NCP peers to upgrade their cipher individually. + * + * Make sure to call tls_session_update_crypto_params() after calling this + * function. + */ +void tls_poor_mans_ncp(struct options *o, const char *remote_ciphername); + #ifdef MANAGEMENT_DEF_AUTH static inline char * tls_get_peer_info(const struct tls_multi *multi) @@ -512,6 +521,13 @@ int tls_peer_info_ncp_ver(const char *peer_info); */ bool tls_check_ncp_cipher_list(const char *list); +/** + * Return true iff item is present in the colon-separated zero-terminated + * cipher list. + */ +bool tls_item_in_cipher_list(const char *item, const char *list); + + /* * inline functions */ diff --git a/src/openvpn/ssl_common.h b/src/openvpn/ssl_common.h index 28702af1d7c..7938f41f5f8 100644 --- a/src/openvpn/ssl_common.h +++ b/src/openvpn/ssl_common.h @@ -540,6 +540,8 @@ struct tls_multi uint32_t peer_id; bool use_peer_id; + char *remote_ciphername; /**< cipher specified in peer's config file */ + char *auth_token; /**< If server sends a generated auth-token, * this is the token to use for future * user/pass authentications in this session. From e2ffdb7c83faaee6541c248e8d83eb3dfb5a32f1 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Wed, 23 Nov 2016 21:02:05 +0100 Subject: [PATCH 413/643] Refactor data channel key generation API Originally for "poor man's NCP", I introduced a simpler API for generating data channel keys. That refactoring is no longer needed for that patch, but I believe still worth a patch on it's own. This patch should not change any functionality. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1479931325-25919-2-git-send-email-steffan@karger.me> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13216.html Signed-off-by: Gert Doering --- src/openvpn/ssl.c | 75 ++++++++++++++++++++++------------------------- 1 file changed, 35 insertions(+), 40 deletions(-) diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 8259292e75b..7347a787113 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -1757,15 +1757,44 @@ tls_poor_mans_ncp(struct options *o, const char *remote_ciphername) } } -bool -tls_session_update_crypto_params(struct tls_session *session, - const struct options *options, struct frame *frame) +/** + * Generate data channel keys for the supplied TLS session. + * + * This erases the source material used to generate the data channel keys, and + * can thus be called only once per session. + */ +static bool +tls_session_generate_data_channel_keys(struct tls_session *session) { bool ret = false; struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */ + const struct session_id *client_sid = session->opt->server ? + &ks->session_id_remote : &session->session_id; + const struct session_id *server_sid = !session->opt->server ? + &ks->session_id_remote : &session->session_id; ASSERT (ks->authenticated); + if (!generate_key_expansion (&ks->crypto_options.key_ctx_bi, + &session->opt->key_type, ks->key_src, client_sid, server_sid, + session->opt->server)) + { + msg (D_TLS_ERRORS, "TLS Error: generate_key_expansion failed"); + goto cleanup; + } + tls_limit_reneg_bytes (session->opt->key_type.cipher, + &session->opt->renegotiate_bytes); + + ret = true; +cleanup: + CLEAR (*ks->key_src); + return ret; +} + +bool +tls_session_update_crypto_params(struct tls_session *session, + const struct options *options, struct frame *frame) +{ if (!session->opt->server && 0 != strcmp(options->ciphername, session->opt->config_ciphername) && !tls_item_in_cipher_list(options->ciphername, options->ncp_ciphers)) @@ -1793,23 +1822,7 @@ tls_session_update_crypto_params(struct tls_session *session, frame_init_mssfix(frame, options); frame_print (frame, D_MTU_INFO, "Data Channel MTU parms"); - const struct session_id *client_sid = session->opt->server ? - &ks->session_id_remote : &session->session_id; - const struct session_id *server_sid = !session->opt->server ? - &ks->session_id_remote : &session->session_id; - if (!generate_key_expansion (&ks->crypto_options.key_ctx_bi, - &session->opt->key_type, ks->key_src, client_sid, server_sid, - session->opt->server)) - { - msg (D_TLS_ERRORS, "TLS Error: server generate_key_expansion failed"); - goto cleanup; - } - tls_limit_reneg_bytes (session->opt->key_type.cipher, - &session->opt->renegotiate_bytes); - ret = true; -cleanup: - CLEAR (*ks->key_src); - return ret; + return tls_session_generate_data_channel_keys (session); } static bool @@ -2177,21 +2190,12 @@ key_method_2_write (struct buffer *buf, struct tls_session *session) { if (ks->authenticated) { - if (!generate_key_expansion (&ks->crypto_options.key_ctx_bi, - &session->opt->key_type, - ks->key_src, - &ks->session_id_remote, - &session->session_id, - true)) + if (!tls_session_generate_data_channel_keys (session)) { msg (D_TLS_ERRORS, "TLS Error: server generate_key_expansion failed"); goto error; } } - - CLEAR (*ks->key_src); - tls_limit_reneg_bytes (session->opt->key_type.cipher, - &session->opt->renegotiate_bytes); } return true; @@ -2418,20 +2422,11 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi */ if (!session->opt->server && (!session->opt->pull || ks->key_id > 0)) { - if (!generate_key_expansion (&ks->crypto_options.key_ctx_bi, - &session->opt->key_type, - ks->key_src, - &session->session_id, - &ks->session_id_remote, - false)) + if (!tls_session_generate_data_channel_keys (session)) { msg (D_TLS_ERRORS, "TLS Error: client generate_key_expansion failed"); goto error; } - - CLEAR (*ks->key_src); - tls_limit_reneg_bytes (session->opt->key_type.cipher, - &session->opt->renegotiate_bytes); } gc_free (&gc); From c098016a22e90575e9c3e7c27d7b457ed9d1b5d3 Mon Sep 17 00:00:00 2001 From: Selva Nair Date: Wed, 23 Nov 2016 22:35:27 -0500 Subject: [PATCH 414/643] Set IPv6 DNS servers using interactive service - Any existing addresses are deleted before adding - On close_tun all addresses are deleted (only if any were added) Signed-off-by: Selva Nair Acked-by: Gert Doering Message-Id: <1479958527-29491-1-git-send-email-selva.nair@gmail.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13222.html Signed-off-by: Gert Doering --- doc/openvpn.8 | 2 +- include/openvpn-msg.h | 7 +- src/openvpn/tun.c | 72 +++++++++++++- src/openvpnserv/Makefile.am | 2 +- src/openvpnserv/common.c | 12 +++ src/openvpnserv/interactive.c | 172 ++++++++++++++++++++++++++++++++++ src/openvpnserv/service.h | 3 + 7 files changed, 263 insertions(+), 7 deletions(-) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 0aa04449de7..dd09c703e7d 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -5696,7 +5696,7 @@ this option to set secondary DNS server addresses. Set primary domain name server IPv6 address. Repeat this option to set secondary DNS server IPv6 addresses. -Note: currently this is handled using netsh and requires admin rights (the +Note: currently this is handled using netsh (the existing DHCP code can only do IPv4 DHCP, and that protocol only permits IPv4 addresses anywhere). The option will be put into the environment, so an diff --git a/include/openvpn-msg.h b/include/openvpn-msg.h index 4c13acf3532..f7fbdd2dce0 100644 --- a/include/openvpn-msg.h +++ b/include/openvpn-msg.h @@ -79,10 +79,9 @@ typedef struct { message_header_t header; interface_t iface; char domains[512]; - struct in_addr primary_ipv4; - struct in_addr secondary_ipv4; - struct in_addr6 primary_ipv6; - struct in_addr6 secondary_ipv6; + short family; + int addr_len; + inet_address_t addr[4]; /* support up to 4 dns addresses */ } dns_cfg_message_t; typedef struct { diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index 3ebf2b2b531..560b1a8e153 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -135,6 +135,74 @@ do_address_service (const bool add, const short family, const struct tuntap *tt) return ret; } +static bool +do_dns6_service (bool add, const struct tuntap *tt) +{ + DWORD len; + bool ret = false; + ack_message_t ack; + struct gc_arena gc = gc_new (); + HANDLE pipe = tt->options.msg_channel; + int addr_len = add ? tt->options.dns6_len : 0; + + if (addr_len == 0 && add) /* no addresses to add */ + return true; + + dns_cfg_message_t dns = { + .header = { + (add ? msg_add_dns_cfg : msg_del_dns_cfg), + sizeof (dns_cfg_message_t), + 0 }, + .iface = { .index = tt->adapter_index, .name = "" }, + .domains = "", + .family = AF_INET6, + .addr_len = addr_len + }; + + /* interface name is required */ + strncpy (dns.iface.name, tt->actual_name, sizeof (dns.iface.name)); + dns.iface.name[sizeof (dns.iface.name) - 1] = '\0'; + + if (addr_len > _countof(dns.addr)) + { + addr_len = _countof(dns.addr); + dns.addr_len = addr_len; + msg(M_WARN, "Number of IPv6 DNS addresses sent to service truncated to %d", + addr_len); + } + + for (int i = 0; i < addr_len; ++i) + { + dns.addr[i].ipv6 = tt->options.dns6[i]; + } + + msg (D_LOW, "%s IPv6 dns servers on '%s' (if_index = %d) using service", + (add ? "Setting" : "Deleting"), dns.iface.name, dns.iface.index); + + if (!WriteFile (pipe, &dns, sizeof (dns), &len, NULL) || + !ReadFile (pipe, &ack, sizeof (ack), &len, NULL)) + { + msg (M_WARN, "TUN: could not talk to service: %s [%lu]", + strerror_win32 (GetLastError (), &gc), GetLastError ()); + goto out; + } + + if (ack.error_number != NO_ERROR) + { + msg (M_WARN, "TUN: %s IPv6 dns failed using service: %s [status=%u if_name=%s]", + (add ? "adding" : "deleting"), strerror_win32 (ack.error_number, &gc), + ack.error_number, dns.iface.name); + goto out; + } + + msg (M_INFO, "IPv6 dns servers %s using service", (add ? "set" : "deleted")); + ret = true; + +out: + gc_free (&gc); + return ret; +} + #endif #ifdef TARGET_SOLARIS @@ -1384,7 +1452,7 @@ do_ifconfig (struct tuntap *tt, else if (tt->options.msg_channel) { do_address_service (true, AF_INET6, tt); - /* TODO: do_dns6_service() */ + do_dns6_service (true, tt); } else { @@ -5596,6 +5664,8 @@ close_tun (struct tuntap *tt) if (tt->options.msg_channel) { do_address_service (false, AF_INET6, tt); + if (tt->options.dns6_len > 0) + do_dns6_service (false, tt); } else { diff --git a/src/openvpnserv/Makefile.am b/src/openvpnserv/Makefile.am index 3521a342e04..58ecd91198f 100644 --- a/src/openvpnserv/Makefile.am +++ b/src/openvpnserv/Makefile.am @@ -26,7 +26,7 @@ openvpnserv_CFLAGS = \ -municode -D_UNICODE \ -UNTDDI_VERSION -U_WIN32_WINNT \ -D_WIN32_WINNT=_WIN32_WINNT_VISTA -openvpnserv_LDADD = -ladvapi32 -luserenv -liphlpapi -lfwpuclnt -lrpcrt4 -lshlwapi -lnetapi32 -lws2_32 +openvpnserv_LDADD = -ladvapi32 -luserenv -liphlpapi -lfwpuclnt -lrpcrt4 -lshlwapi -lnetapi32 -lws2_32 -lntdll endif openvpnserv_SOURCES = \ diff --git a/src/openvpnserv/common.c b/src/openvpnserv/common.c index dba4724e021..eafee205d25 100644 --- a/src/openvpnserv/common.c +++ b/src/openvpnserv/common.c @@ -216,3 +216,15 @@ MsgToEventLog (DWORD flags, LPCTSTR format, ...) return error; } + +/* Convert a utf8 string to utf16. Caller should free the result */ +wchar_t * +utf8to16 (const char *utf8) +{ + int n = MultiByteToWideChar (CP_UTF8, 0, utf8, -1, NULL, 0); + wchar_t *utf16 = malloc (n * sizeof (wchar_t)); + if (!utf16) + return NULL; + MultiByteToWideChar (CP_UTF8, 0, utf8, -1, utf16, n); + return utf16; +} diff --git a/src/openvpnserv/interactive.c b/src/openvpnserv/interactive.c index ffaa1710cf0..608bb0c3778 100644 --- a/src/openvpnserv/interactive.c +++ b/src/openvpnserv/interactive.c @@ -35,6 +35,12 @@ #include #include +#ifdef HAVE_VERSIONHELPERS_H +#include +#else +#include "compat-versionhelpers.h" +#endif + #include "openvpn-msg.h" #include "validate.h" #include "block_dns.h" @@ -82,6 +88,8 @@ typedef enum { address, route, block_dns, + undo_dns4, + undo_dns6, _undo_type_max } undo_type_t; typedef list_item_t* undo_lists_t[_undo_type_max]; @@ -962,6 +970,156 @@ HandleRegisterDNSMessage (void) return err; } +/** + * Run the command: netsh interface $proto $action dns $if_name $addr [validate=no] + * @param action "delete" or "add" + * @param proto "ipv6" or "ip" + * @param if_name "name_of_interface" + * @param addr IPv4 (for proto = ip) or IPv6 address as a string + * + * If addr is null and action = "delete" all addresses are deleted. + */ +static DWORD +netsh_dns_cmd (const wchar_t *action, const wchar_t *proto, const wchar_t *if_name, const wchar_t *addr) +{ + DWORD err = 0; + int timeout = 30000; /* in msec */ + wchar_t argv0[MAX_PATH]; + + if (!addr) + { + if (wcscmp(action, L"delete") == 0) + addr = L"all"; + else /* nothing to do -- return success*/ + goto out; + } + + /* Path of netsh */ + int n = GetSystemDirectory (argv0, MAX_PATH); + if (n > 0 && n < MAX_PATH) /* got system directory */ + { + wcsncat(argv0, L"\\netsh.exe", MAX_PATH - n - 1); + } + else + { + wcsncpy(argv0, L"C:\\Windows\\system32\\netsh.exe", MAX_PATH); + } + + /* cmd template: + * netsh interface $proto $action dns $if_name $addr [validate=no] + */ + const wchar_t *fmt = L"netsh interface %s %s dns \"%s\" %s"; + + /* max cmdline length in wchars -- include room for worst case and some */ + int ncmdline = wcslen(fmt) + wcslen(if_name) + wcslen(addr) + 32 + 1; + wchar_t *cmdline = malloc(ncmdline*sizeof(wchar_t)); + if (!cmdline) + { + err = ERROR_OUTOFMEMORY; + goto out; + } + + openvpn_sntprintf (cmdline, ncmdline, fmt, proto, action, if_name, addr); + + if (IsWindows7OrGreater()) + { + wcsncat(cmdline, L" validate=no", ncmdline - wcslen(cmdline) - 1); + } + err = ExecCommand (argv0, cmdline, timeout); + +out: + free (cmdline); + return err; +} + +/* Delete all IPv4 or IPv6 dns servers for an interface */ +static DWORD +DeleteDNS(short family, wchar_t *if_name) +{ + wchar_t *proto = (family == AF_INET6) ? L"ipv6" : L"ip"; + return netsh_dns_cmd (L"delete", proto, if_name, NULL); +} + +/* Add an IPv4 or IPv6 dns server to an interface */ +static DWORD +AddDNS(short family, wchar_t *if_name, wchar_t *addr) +{ + wchar_t *proto = (family == AF_INET6) ? L"ipv6" : L"ip"; + return netsh_dns_cmd (L"add", proto, if_name, addr); +} + +static BOOL +CmpWString (LPVOID item, LPVOID str) +{ + return (wcscmp (item, str) == 0) ? TRUE : FALSE; +} + +static DWORD +HandleDNSConfigMessage (const dns_cfg_message_t *msg, undo_lists_t *lists) +{ + DWORD err = 0; + wchar_t addr[46]; /* large enough to hold string representation of an ipv4 / ipv6 address */ + undo_type_t undo_type = (msg->family == AF_INET6) ? undo_dns4 : undo_dns6; + int addr_len = msg->addr_len; + + /* sanity check */ + if (addr_len > _countof(msg->addr)) + addr_len = _countof(msg->addr); + + if (!msg->iface.name[0]) /* interface name is required */ + return ERROR_MESSAGE_DATA; + + wchar_t *wide_name = utf8to16(msg->iface.name); /* utf8 to wide-char */ + if (!wide_name) + return ERROR_OUTOFMEMORY; + + /* We delete all current addresses before adding any + * OR if the message type is del_dns_cfg + */ + if (addr_len > 0 || msg->header.type == msg_del_dns_cfg) + { + err = DeleteDNS(msg->family, wide_name); + if (err) + goto out; + free (RemoveListItem (&(*lists)[undo_type], CmpWString, wide_name)); + } + + if (msg->header.type == msg_del_dns_cfg) /* job done */ + goto out; + + for (int i = 0; i < addr_len; ++i) + { + if (msg->family == AF_INET6) + RtlIpv6AddressToStringW (&msg->addr[i].ipv6, addr); + else + RtlIpv4AddressToStringW (&msg->addr[i].ipv4, addr); + err = AddDNS(msg->family, wide_name, addr); + if (i == 0 && err) + goto out; + /* We do not check for duplicate addresses, so any error in adding + * additional addresses is ignored. + */ + } + + if (msg->addr_len > 0) + { + wchar_t *tmp_name = wcsdup(wide_name); + if (!tmp_name || AddListItem(&(*lists)[undo_type], tmp_name)) + { + free(tmp_name); + DeleteDNS(msg->family, wide_name); + err = ERROR_OUTOFMEMORY; + goto out; + } + } + + err = 0; + +out: + free(wide_name); + return err; +} + static VOID HandleMessage (HANDLE pipe, DWORD bytes, DWORD count, LPHANDLE events, undo_lists_t *lists) { @@ -972,6 +1130,7 @@ HandleMessage (HANDLE pipe, DWORD bytes, DWORD count, LPHANDLE events, undo_list route_message_t route; flush_neighbors_message_t flush_neighbors; block_dns_message_t block_dns; + dns_cfg_message_t dns; } msg; ack_message_t ack = { .header = { @@ -1017,6 +1176,11 @@ HandleMessage (HANDLE pipe, DWORD bytes, DWORD count, LPHANDLE events, undo_list ack.error_number = HandleRegisterDNSMessage (); break; + case msg_add_dns_cfg: + case msg_del_dns_cfg: + ack.error_number = HandleDNSConfigMessage (&msg.dns, lists); + break; + default: ack.error_number = ERROR_MESSAGE_TYPE; MsgToEventLog (MSG_FLAGS_ERROR, TEXT("Unknown message type %d"), msg.header.type); @@ -1048,6 +1212,14 @@ Undo (undo_lists_t *lists) DeleteRoute (item->data); break; + case undo_dns4: + DeleteDNS(AF_INET, item->data); + break; + + case undo_dns6: + DeleteDNS(AF_INET6, item->data); + break; + case block_dns: delete_block_dns_filters (item->data); item->data = NULL; diff --git a/src/openvpnserv/service.h b/src/openvpnserv/service.h index 94bfb0794e1..c5d745f6d8b 100644 --- a/src/openvpnserv/service.h +++ b/src/openvpnserv/service.h @@ -89,4 +89,7 @@ BOOL ReportStatusToSCMgr (SERVICE_STATUS_HANDLE service, SERVICE_STATUS *status) LPCTSTR GetLastErrorText (); DWORD MsgToEventLog (DWORD flags, LPCTSTR lpszMsg, ...); +/* Convert a utf8 string to utf16. Caller should free the result */ +wchar_t *utf8to16 (const char *utf8); + #endif From 9bc2be7b4f6bf760dc5f3257374d749c4eb2f658 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Thu, 24 Nov 2016 15:04:51 +0100 Subject: [PATCH 415/643] Preparing OpenVPN v2.4_beta2 release This also adds a few missing details from Changes.rst Signed-off-by: David Sommerseth --- ChangeLog | 30 ++++++++++++++++++++++++++++++ Changes.rst | 25 +++++++++++++++++++++++++ version.m4 | 2 +- 3 files changed, 56 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 991aeb6a64d..abb9d385feb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,36 @@ OpenVPN Change Log Copyright (C) 2002-2016 OpenVPN Technologies, Inc. +2016.11.24 -- Version 2.4_beta2 +Arne Schwabe (5): + Document that tls-crypt also supports inline + Fix warning that RAND_bytes is undeclared + Remove compat-stdbool.h. + Fix various compiler warnings + Handle DNS6 option on Android + +David Sommerseth (2): + Changes.rst: Fixing wrong formatting + Document the --auth-token option + +Gert Doering (2): + Remove remaining traces of compat-stdbool.h + Stub implementation of "--dhcp-option DNS6 " + +Selva Nair (3): + Do not set ipv6 address if '--ip-win32 manual' is used + Handle --dhcp-option DNS6 on Windows using netsh + Set IPv6 DNS servers using interactive service + +Steffan Karger (6): + multi_process_float: revert part of c14c4a9e + --tls-crypt fixes + Change cmocka remote to use https in stead of git protocol + generate_key_expansion: make assumption explicit, use C99 features + Poor man's NCP for non-NCP peers + Refactor data channel key generation API + + 2016.11.17 -- Version 2.4_beta1 Arne Schwabe (1): Make Changes.rst nicer for 2.4 release diff --git a/Changes.rst b/Changes.rst index 90c37722835..6d7bd69b7c6 100644 --- a/Changes.rst +++ b/Changes.rst @@ -18,6 +18,19 @@ Cipher negotiation to use that cipher. Data channel cipher negotiation can be controlled using ``--ncp-ciphers`` and ``--ncp-disable``. + A more limited version also works in client-to-server and server-to-client + scenarios where one of the end points uses a v2.4 client or server and the + other side uses an older version. In such scenarios the v2.4 side will + change to the ``--cipher`` set by the remote side, if permitted by by + ``--ncp-ciphers``. For example, a v2.4 client with ``--cipher BF-CBC`` + and ``ncp-ciphers AES-256-GCM:AES-256-CBC`` can connect to both a v2.3 + server with ``cipher BF-CBC`` as well as a server with + ``cipher AES-256-CBC`` in its config. The other way around, a v2.3 client + with either ``cipher BF-CBC`` or ``cipher AES-256-CBC`` can connect to a + v2.4 server with e.g. ``cipher BF-CBC`` and + ``ncp-ciphers AES-256-GCM:AES-256-CBC`` in its config. For this to work + it requires that OpenVPN was built without disabling OCC support. + AEAD (GCM) data channel cipher support The data channel now supports AEAD ciphers (currently only GCM). The AEAD packet format has a smaller overhead than the CBC packet format, (e.g. 20 @@ -32,6 +45,18 @@ Dualstack client connect Instead of only using the first address of each ``--remote`` OpenVPN will now try all addresses (IPv6 and IPv4) of a ``--remote`` entry. +Support for providing IPv6 DNS servers + A new DHCP sub-options ``DNS6`` is added alongside with the already existing + ``DNS`` sub-option. This is used to provide DNS resolvers available over + IPv6. This will be pushed to clients and `` --up`` scripts and ``--plugin`` + can act upon it through the ``foreign_option_`` environment variables. + + Support for the Windows client picking up this new sub-option is added, + however IPv6 DNS resolvers needs to be configured via ``netsh`` which requires + administrator privileges if the new interactive services on Windows is not + being used. If the interactive services is used, this service will execute + ``netsh`` in the background with the proper privileges. + New improved Windows Background service The new OpenVPNService is based on openvpnserv2, a complete rewrite of the OpenVPN service wrapper. It is intended for launching OpenVPN instances that should be diff --git a/version.m4 b/version.m4 index ab8ea426529..b5fb2341e16 100644 --- a/version.m4 +++ b/version.m4 @@ -3,7 +3,7 @@ define([PRODUCT_NAME], [OpenVPN]) define([PRODUCT_TARNAME], [openvpn]) define([PRODUCT_VERSION_MAJOR], [2]) define([PRODUCT_VERSION_MINOR], [4]) -define([PRODUCT_VERSION_PATCH], [_beta1]) +define([PRODUCT_VERSION_PATCH], [_beta2]) m4_append([PRODUCT_VERSION], [PRODUCT_VERSION_MAJOR]) m4_append([PRODUCT_VERSION], [PRODUCT_VERSION_MINOR], [[.]]) m4_append([PRODUCT_VERSION], [PRODUCT_VERSION_PATCH], [[]]) From 06c54466c86ee3beff9b6cd75f40de5e431d8235 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Mon, 28 Nov 2016 15:53:20 +0100 Subject: [PATCH 416/643] tls_process: don't set variable that's never read Found by the clang static analyzer: the state_change variable is set, but never read afterwards. This code has been like this since 2005, makes sense without setting state_change to true, and has worked fine for the past 11 years. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1480344801-27855-1-git-send-email-steffan.karger@fox-it.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13260.html Signed-off-by: Gert Doering --- src/openvpn/ssl.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 7347a787113..d9de380008b 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -2809,7 +2809,6 @@ tls_process (struct tls_multi *multi, RELIABLE_ACK_SIZE, false); *to_link = buf; active = true; - state_change = true; dmsg (D_TLS_DEBUG, "Dedicated ACK -> TCP/UDP"); } #endif From 718257811b42b2bf4a7ee325a38c3cb147c53cc2 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Mon, 28 Nov 2016 15:53:21 +0100 Subject: [PATCH 417/643] Unconditionally enable TLS_AGGREGATE_ACK This define has been enabled by default since 2005, and was not configurable through ./configure (but just by changing ssl.h). Let's get rid of it. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1480344801-27855-2-git-send-email-steffan.karger@fox-it.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13261.html Signed-off-by: Gert Doering --- src/openvpn/ssl.c | 18 ------------------ src/openvpn/ssl.h | 9 +-------- 2 files changed, 1 insertion(+), 26 deletions(-) diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index d9de380008b..4885031730e 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -2639,22 +2639,6 @@ tls_process (struct tls_multi *multi, break; } -#ifndef TLS_AGGREGATE_ACK - /* Send 1 or more ACKs (each received control packet gets one ACK) */ - if (!to_link->len && !reliable_ack_empty (ks->rec_ack)) - { - buf = &ks->ack_write_buf; - ASSERT (buf_init (buf, FRAME_HEADROOM (&multi->opt.frame))); - write_control_auth (session, ks, buf, to_link_addr, P_ACK_V1, - RELIABLE_ACK_SIZE, false); - *to_link = *buf; - active = true; - state_change = true; - dmsg (D_TLS_DEBUG, "Dedicated ACK -> TCP/UDP"); - break; - } -#endif - /* Write incoming ciphertext to TLS object */ buf = reliable_get_buf_sequenced (ks->rec_reliable); if (buf) @@ -2799,7 +2783,6 @@ tls_process (struct tls_multi *multi, update_time (); -#ifdef TLS_AGGREGATE_ACK /* Send 1 or more ACKs (each received control packet gets one ACK) */ if (!to_link->len && !reliable_ack_empty (ks->rec_ack)) { @@ -2811,7 +2794,6 @@ tls_process (struct tls_multi *multi, active = true; dmsg (D_TLS_DEBUG, "Dedicated ACK -> TCP/UDP"); } -#endif /* When should we wake up again? */ { diff --git a/src/openvpn/ssl.h b/src/openvpn/ssl.h index 047eb248d63..c971b758670 100644 --- a/src/openvpn/ssl.h +++ b/src/openvpn/ssl.h @@ -70,15 +70,8 @@ #define P_FIRST_OPCODE 1 #define P_LAST_OPCODE 9 -/* Should we aggregate TLS - * acknowledgements, and tack them onto - * control packets? */ -#define TLS_AGGREGATE_ACK - /* - * If TLS_AGGREGATE_ACK, set the - * max number of acknowledgments that - * can "hitch a ride" on an outgoing + * Set the max number of acknowledgments that can "hitch a ride" on an outgoing * non-P_ACK_V1 control packet. */ #define CONTROL_SEND_ACK_MAX 4 From 294040102fbceb4be320a45ba3c340ace1804a49 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Mon, 28 Nov 2016 15:26:40 +0100 Subject: [PATCH 418/643] Clean up format_hex_ex() Fix a potential null-pointer dereference, and make the code a bit more readable while doing so. The NULL dereference could not be triggered, because the current code never called format_hex_ex() with maxouput == 0 and separator == NULL. But it's nicer to not depend on that. Our use of int vs size_t for lengths needs some attention too, but I'm not pulling that into this patch. Instead I decided to just make the (previously existing) assumption that INT_MAX <= SIZE_MAX explicit by adding a static_assert(). Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1480343200-25908-1-git-send-email-steffan.karger@fox-it.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13259.html Signed-off-by: Gert Doering --- src/openvpn/buffer.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/openvpn/buffer.c b/src/openvpn/buffer.c index 52c6ab92f8d..5341d35e25f 100644 --- a/src/openvpn/buffer.c +++ b/src/openvpn/buffer.c @@ -438,13 +438,16 @@ format_hex_ex (const uint8_t *data, int size, int maxoutput, unsigned int space_break_flags, const char* separator, struct gc_arena *gc) { - struct buffer out = alloc_buf_gc (maxoutput ? maxoutput : - ((size * 2) + (size / (space_break_flags & FHE_SPACE_BREAK_MASK)) * (int) strlen (separator) + 2), - gc); - int i; - for (i = 0; i < size; ++i) + const size_t bytes_per_hexblock = space_break_flags & FHE_SPACE_BREAK_MASK; + const size_t separator_len = separator ? strlen (separator) : 0; + static_assert (INT_MAX <= SIZE_MAX, "Code assumes INT_MAX <= SIZE_MAX"); + const size_t out_len = maxoutput > 0 ? maxoutput : + ((size * 2) + ((size / bytes_per_hexblock) * separator_len) + 2); + + struct buffer out = alloc_buf_gc (out_len, gc); + for (int i = 0; i < size; ++i) { - if (separator && i && !(i % (space_break_flags & FHE_SPACE_BREAK_MASK))) + if (separator && i && !(i % bytes_per_hexblock)) buf_printf (&out, "%s", separator); if (space_break_flags & FHE_CAPS) buf_printf (&out, "%02X", data[i]); From 7f7d6b2eb0f69f0e8952028488d7aa02619ad76f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 28 Nov 2016 18:08:20 +0100 Subject: [PATCH 419/643] update year in copyright message This line has not been touched in a long time... Let's update the copyright message with recent year. Signed-off-by: Christian Hesse Acked-by: Gert Doering Message-Id: <20161128170820.20371-1-list@eworm.de> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13270.html Signed-off-by: Gert Doering --- src/openvpn/options.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 7c2b989d828..63dcc242706 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -3685,7 +3685,7 @@ usage_version (void) show_windows_version( M_INFO|M_NOPREFIX ); #endif msg (M_INFO|M_NOPREFIX, "Originally developed by James Yonan"); - msg (M_INFO|M_NOPREFIX, "Copyright (C) 2002-2010 OpenVPN Technologies, Inc. "); + msg (M_INFO|M_NOPREFIX, "Copyright (C) 2002-2016 OpenVPN Technologies, Inc. "); #ifndef ENABLE_SMALL #ifdef CONFIGURE_DEFINES msg (M_INFO|M_NOPREFIX, "Compile time defines: %s", CONFIGURE_DEFINES); From 6c6456f4384ec76649febba8ada7806905d84bc4 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Mon, 28 Nov 2016 20:06:52 +0100 Subject: [PATCH 420/643] Fix windows path in Changes.rst Escape backslash characters in windows path names. Signed-off-by: Gert Doering Acked-by: Selva Nair Message-Id: <1480360012-9479-1-git-send-email-gert@greenie.muc.de> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13274.html Signed-off-by: Gert Doering --- Changes.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Changes.rst b/Changes.rst index 6d7bd69b7c6..aa80c103530 100644 --- a/Changes.rst +++ b/Changes.rst @@ -71,12 +71,12 @@ New interactive Windows service The interactive Windows service allows unprivileged users to start OpenVPN connections in the global config directory (usually - C:\Program Files\OpenVPN\config) using OpenVPN GUI without any + C:\\Program Files\\OpenVPN\\config) using OpenVPN GUI without any extra configuration. Users who belong to the built-in Administrator group or to the local "OpenVPN Administrator" group can also store configuration - files under %USERPROFILE%\OpenVPN\config for use with the + files under %USERPROFILE%\\OpenVPN\\config for use with the interactive service. redirect-gateway ipv6 From f25a0217e35f53c3110ebb226e1d1f3528152cb5 Mon Sep 17 00:00:00 2001 From: Selva Nair Date: Mon, 28 Nov 2016 21:27:04 -0500 Subject: [PATCH 421/643] Map restart signals from event loop to SIGTERM during exit-notification wait Commit 63b3e000c9.. fixed SIGTERM getting lost during exit notification by ignoring any restart signals triggered during this interval. However, as reported in Trac 777, this could result in repeated triggering of restart signals when the event loop cannot continue without restart due to IO errors or timeout. Avoid by converting soft SIGUSR1 and SIGHUP signals received during exit-notify wait period to SIGTERM. Trac #777 Signed-off-by: Selva Nair Acked-by: Gert Doering Message-Id: <1480386424-30876-1-git-send-email-selva.nair@gmail.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13284.html Signed-off-by: Gert Doering --- src/openvpn/sig.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/openvpn/sig.c b/src/openvpn/sig.c index 0ff14379569..b3ae645e2b2 100644 --- a/src/openvpn/sig.c +++ b/src/openvpn/sig.c @@ -378,7 +378,8 @@ process_sigterm (struct context *c) /** * If a restart signal is received during exit-notification, reset the - * signal and return true. + * signal and return true. If its a soft restart signal from the event loop + * which implies the loop cannot continue, remap to SIGTERM to exit promptly. */ static bool ignore_restart_signals (struct context *c) @@ -388,10 +389,20 @@ ignore_restart_signals (struct context *c) if ( (c->sig->signal_received == SIGUSR1 || c->sig->signal_received == SIGHUP) && event_timeout_defined(&c->c2.explicit_exit_notification_interval) ) { - msg (M_INFO, "Ignoring %s received during exit notification", - signal_name(c->sig->signal_received, true)); - signal_reset (c->sig); - ret = true; + if (c->sig->source == SIG_SOURCE_HARD) + { + msg (M_INFO, "Ignoring %s received during exit notification", + signal_name(c->sig->signal_received, true)); + signal_reset (c->sig); + ret = true; + } + else + { + msg (M_INFO, "Converting soft %s received during exit notification to SIGTERM", + signal_name(c->sig->signal_received, true)); + register_signal(c, SIGTERM, "exit-with-notification"); + ret = false; + } } #endif return ret; From 009521ac8ae613084b23b9e3e5dc4ebeccd4c6c8 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Mon, 28 Nov 2016 23:14:12 +0100 Subject: [PATCH 422/643] Introduce and use secure_memzero() to erase secrets As described in trac #751, and shortly after reported by Zhaomo Yang, of the University of California, San Diego, we use memset() (often through the CLEAR() macro) to erase secrets after use. In some cases however, the compiler might optimize these calls away. This patch replaces these memset() calls on secrets by calls to a new secure_memzero() function, that will not be optimized away. Since we use CLEAR() a LOT of times, I'm not changing that to use secure_memzero() to prevent performance impact. I did annotate the macro to point people at secure_memzero(). This patch also replaces some CLEAR() or memset() calls with a zero- initialization using "= { 0 }" if that has the same effect, because that better captures the intend of that code. Trac: #751 Signed-off-by: Steffan Karger Acked-by: Selva Nair Acked-by: Gert Doering Message-Id: <1480371252-3880-1-git-send-email-steffan@karger.me> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13278.html Signed-off-by: Gert Doering --- src/openvpn/basic.h | 2 +- src/openvpn/buffer.c | 8 +++--- src/openvpn/buffer.h | 43 ++++++++++++++++++++++++++++++++ src/openvpn/console_builtin.c | 2 +- src/openvpn/crypto.c | 17 +++++-------- src/openvpn/manage.c | 2 +- src/openvpn/misc.c | 4 +-- src/openvpn/options.c | 6 ++--- src/openvpn/ssl.c | 32 ++++++++++++------------ src/openvpn/ssl_verify.c | 4 +-- src/openvpn/ssl_verify_mbedtls.c | 4 +-- 11 files changed, 80 insertions(+), 44 deletions(-) diff --git a/src/openvpn/basic.h b/src/openvpn/basic.h index 298cf103734..48d4d9bd6e6 100644 --- a/src/openvpn/basic.h +++ b/src/openvpn/basic.h @@ -30,7 +30,7 @@ /* size of an array */ #define SIZE(x) (sizeof(x)/sizeof(x[0])) -/* clear an object */ +/* clear an object (may be optimized away, use secure_memzero() to erase secrets) */ #define CLEAR(x) memset(&(x), 0, sizeof(x)) #define IPV4_NETMASK_HOST 0xffffffffU diff --git a/src/openvpn/buffer.c b/src/openvpn/buffer.c index 5341d35e25f..6af8dbb037f 100644 --- a/src/openvpn/buffer.c +++ b/src/openvpn/buffer.c @@ -155,7 +155,9 @@ void buf_clear (struct buffer *buf) { if (buf->capacity > 0) - memset (buf->data, 0, buf->capacity); + { + secure_memzero (buf->data, buf->capacity); + } buf->len = 0; buf->offset = 0; } @@ -619,9 +621,7 @@ string_clear (char *str) { if (str) { - const int len = strlen (str); - if (len > 0) - memset (str, 0, len); + secure_memzero (str, strlen (str)); } } diff --git a/src/openvpn/buffer.h b/src/openvpn/buffer.h index 8070439a5d8..7747003f2c8 100644 --- a/src/openvpn/buffer.h +++ b/src/openvpn/buffer.h @@ -328,6 +328,49 @@ has_digit (const unsigned char* src) return false; } +/** + * Securely zeroise memory. + * + * This code and description are based on code supplied by Zhaomo Yang, of the + * University of California, San Diego (which was released into the public + * domain). + * + * The secure_memzero function attempts to ensure that an optimizing compiler + * does not remove the intended operation if cleared memory is not accessed + * again by the program. This code has been tested under Clang 3.9.0 and GCC + * 6.2 with optimization flags -O, -Os, -O0, -O1, -O2, and -O3 on + * Ubuntu 16.04.1 LTS; under Clang 3.9.0 with optimization flags -O, -Os, + * -O0, -O1, -O2, and -O3 on FreeBSD 10.2-RELEASE; under Microsoft Visual Studio + * 2015 with optimization flags /O1, /O2 and /Ox on Windows 10. + * + * Theory of operation: + * + * 1. On Windows, use the SecureZeroMemory which ensures that data is + * overwritten. + * 2. Under GCC or Clang, use a memory barrier, which forces the preceding + * memset to be carried out. The overhead of a memory barrier is usually + * negligible. + * 3. If none of the above are available, use the volatile pointer + * technique to zero memory one byte at a time. + * + * @param data Pointer to data to zeroise. + * @param len Length of data, in bytes. + */ +static inline void +secure_memzero (void *data, size_t len) +{ +#if defined(_WIN32) + SecureZeroMemory (data, len); +#elif defined(__GNUC__) || defined(__clang__) + memset(data, 0, len); + __asm__ __volatile__("" : : "r"(data) : "memory"); +#else + volatile char *p = (volatile char *) data; + while (len--) + *p++ = 0; +#endif +} + /* * printf append to a buffer with overflow check, * due to usage of vsnprintf, it will leave space for diff --git a/src/openvpn/console_builtin.c b/src/openvpn/console_builtin.c index 6b0211d9eb9..06994fd5af5 100644 --- a/src/openvpn/console_builtin.c +++ b/src/openvpn/console_builtin.c @@ -218,7 +218,7 @@ static bool get_console_input (const char *prompt, const bool echo, char *input, if (gp) { strncpynt (input, gp, capacity); - memset (gp, 0, strlen (gp)); + secure_memzero (gp, strlen (gp)); ret = true; } } diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c index 05622ceea48..708cc9240e0 100644 --- a/src/openvpn/crypto.c +++ b/src/openvpn/crypto.c @@ -86,12 +86,11 @@ openvpn_encrypt_aead (struct buffer *buf, struct buffer work, { struct buffer iv_buffer; struct packet_id_net pin; - uint8_t iv[OPENVPN_MAX_IV_LENGTH]; + uint8_t iv[OPENVPN_MAX_IV_LENGTH] = {0}; const int iv_len = cipher_ctx_iv_length (ctx->cipher); ASSERT (iv_len >= OPENVPN_AEAD_MIN_IV_LEN && iv_len <= OPENVPN_MAX_IV_LENGTH); - memset(iv, 0, sizeof(iv)); buf_set_write (&iv_buffer, iv, iv_len); /* IV starts with packet id to make the IV unique for packet */ @@ -175,7 +174,7 @@ openvpn_encrypt_v1 (struct buffer *buf, struct buffer work, /* Do Encrypt from buf -> work */ if (ctx->cipher) { - uint8_t iv_buf[OPENVPN_MAX_IV_LENGTH]; + uint8_t iv_buf[OPENVPN_MAX_IV_LENGTH] = {0}; const int iv_size = cipher_ctx_iv_length (ctx->cipher); const cipher_kt_t *cipher_kt = cipher_ctx_get_cipher_kt (ctx->cipher); int outlen; @@ -190,8 +189,6 @@ openvpn_encrypt_v1 (struct buffer *buf, struct buffer work, if (cipher_kt_mode_cbc(cipher_kt)) { - CLEAR (iv_buf); - /* generate pseudo-random IV */ if (opt->flags & CO_USE_IV) prng_bytes (iv_buf, iv_size); @@ -214,7 +211,6 @@ openvpn_encrypt_v1 (struct buffer *buf, struct buffer work, ASSERT (packet_id_initialized(&opt->packet_id)); packet_id_alloc_outgoing (&opt->packet_id.send, &pin, true); - memset (iv_buf, 0, iv_size); buf_set_write (&b, iv_buf, iv_size); ASSERT (packet_id_write (&pin, &b, true, false)); } @@ -550,14 +546,13 @@ openvpn_decrypt_v1 (struct buffer *buf, struct buffer work, { const int iv_size = cipher_ctx_iv_length (ctx->cipher); const cipher_kt_t *cipher_kt = cipher_ctx_get_cipher_kt (ctx->cipher); - uint8_t iv_buf[OPENVPN_MAX_IV_LENGTH]; + uint8_t iv_buf[OPENVPN_MAX_IV_LENGTH] = { 0 }; int outlen; /* initialize work buffer with FRAME_HEADROOM bytes of prepend capacity */ ASSERT (buf_init (&work, FRAME_HEADROOM_ADJ (frame, FRAME_HEADROOM_MARKER_DECRYPT))); /* use IV if user requested it */ - CLEAR (iv_buf); if (opt->flags & CO_USE_IV) { if (buf->len < iv_size) @@ -1128,7 +1123,7 @@ crypto_read_openvpn_key (const struct key_type *key_type, init_key_ctx (&ctx->decrypt, &key2.keys[kds.in_key], key_type, OPENVPN_OP_DECRYPT, log_prefix); - CLEAR (key2); + secure_memzero (&key2, sizeof (key2)); } /* header and footer for static key file */ @@ -1380,8 +1375,8 @@ write_key_file (const int nkeys, const char *filename) buf_printf (&out, "%s\n", fmt); /* zero memory which held key component (will be freed by GC) */ - memset (fmt, 0, strlen(fmt)); - CLEAR (key); + secure_memzero (fmt, strlen (fmt)); + secure_memzero (&key, sizeof (key)); } buf_printf (&out, "%s\n", static_key_foot); diff --git a/src/openvpn/manage.c b/src/openvpn/manage.c index 77a80061e5d..4918ed2caf7 100644 --- a/src/openvpn/manage.c +++ b/src/openvpn/manage.c @@ -3154,7 +3154,7 @@ management_query_user_pass (struct management *man, man->connection.up_query.nocache = up->nocache; /* preserve caller's nocache setting */ *up = man->connection.up_query; } - CLEAR (man->connection.up_query); + secure_memzero (&man->connection.up_query, sizeof (man->connection.up_query)); } gc_free (&gc); diff --git a/src/openvpn/misc.c b/src/openvpn/misc.c index 56d43e0a637..4e06c91d531 100644 --- a/src/openvpn/misc.c +++ b/src/openvpn/misc.c @@ -501,7 +501,7 @@ remove_env_item (const char *str, const bool do_free, struct env_item **list) *list = current->next; if (do_free) { - memset (current->string, 0, strlen (current->string)); + secure_memzero (current->string, strlen (current->string)); free (current->string); free (current); } @@ -1342,7 +1342,7 @@ purge_user_pass (struct user_pass *up, const bool force) static bool warn_shown = false; if (nocache || force) { - CLEAR (*up); + secure_memzero (up, sizeof(*up)); up->nocache = nocache; } else if (!warn_shown) diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 63dcc242706..a7a1f9a4c86 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -3968,7 +3968,7 @@ read_inline_file (struct in_src *is, const char *close_tag, struct gc_arena *gc) ret = string_alloc (BSTR (&buf), gc); buf_clear (&buf); free_buf (&buf); - CLEAR (line); + secure_memzero (line, sizeof (line)); return ret; } @@ -4083,7 +4083,7 @@ read_config_file (struct options *options, { msg (msglevel, "In %s:%d: Maximum recursive include levels exceeded in include attempt of file %s -- probably you have a configuration file that tries to include itself.", top_file, top_line, file); } - CLEAR (line); + secure_memzero (line, sizeof (line)); CLEAR (p); } @@ -4115,7 +4115,7 @@ read_config_string (const char *prefix, } CLEAR (p); } - CLEAR (line); + secure_memzero (line, sizeof (line)); } void diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 4885031730e..14d13312982 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -894,7 +894,7 @@ key_state_free (struct key_state *ks, bool clear) #endif if (clear) - CLEAR (*ks); + secure_memzero (ks, sizeof (*ks)); } /** @} name Functions for initialization and cleanup of key_state structures */ @@ -1024,7 +1024,7 @@ tls_session_free (struct tls_session *session, bool clear) cert_hash_free (session->cert_hash_set); if (clear) - CLEAR (*session); + secure_memzero (session, sizeof (*session)); } /** @} name Functions for initialization and cleanup of tls_session structures */ @@ -1048,7 +1048,7 @@ move_session (struct tls_multi* multi, int dest, int src, bool reinit_src) if (reinit_src) tls_session_init (multi, &multi->session[src]); else - CLEAR (multi->session[src]); + secure_memzero (&multi->session[src], sizeof (multi->session[src])); dmsg (D_TLS_DEBUG, "TLS: move_session: exit"); } @@ -1212,7 +1212,7 @@ tls_multi_free (struct tls_multi *multi, bool clear) if (multi->auth_token) { - memset (multi->auth_token, 0, AUTH_TOKEN_SIZE); + secure_memzero (multi->auth_token, AUTH_TOKEN_SIZE); free (multi->auth_token); } @@ -1222,7 +1222,7 @@ tls_multi_free (struct tls_multi *multi, bool clear) tls_session_free (&multi->session[i], false); if (clear) - CLEAR (*multi); + secure_memzero (multi, sizeof (*multi)); free(multi); } @@ -1512,7 +1512,7 @@ tls1_P_hash(const md_kt_t *md_kt, } hmac_ctx_cleanup(&ctx); hmac_ctx_cleanup(&ctx_tmp); - CLEAR (A1); + secure_memzero (A1, sizeof (A1)); dmsg (D_SHOW_KEY_SOURCE, "tls1_P_hash out: %s", format_hex (out_orig, olen_orig, 0, &gc)); gc_free (&gc); @@ -1565,7 +1565,7 @@ tls1_PRF(const uint8_t *label, for (i=0; ikey_src); + secure_memzero (ks->key_src, sizeof (*ks->key_src)); return ret; } @@ -2017,7 +2017,7 @@ key_method_1_write (struct buffer *buf, struct tls_session *session) init_key_ctx (&ks->crypto_options.key_ctx_bi.encrypt, &key, &session->opt->key_type, OPENVPN_OP_ENCRYPT, "Data Channel Encrypt"); - CLEAR (key); + secure_memzero (&key, sizeof (key)); /* send local options string */ { @@ -2202,7 +2202,7 @@ key_method_2_write (struct buffer *buf, struct tls_session *session) error: msg (D_TLS_ERRORS, "TLS Error: Key Method #2 write failed"); - CLEAR (*ks->key_src); + secure_memzero (ks->key_src, sizeof (*ks->key_src)); return false; } @@ -2257,13 +2257,13 @@ key_method_1_read (struct buffer *buf, struct tls_session *session) init_key_ctx (&ks->crypto_options.key_ctx_bi.decrypt, &key, &session->opt->key_type, OPENVPN_OP_DECRYPT, "Data Channel Decrypt"); - CLEAR (key); + secure_memzero (&key, sizeof (key)); ks->authenticated = true; return true; error: buf_clear (buf); - CLEAR (key); + secure_memzero (&key, sizeof (key)); return false; } @@ -2377,7 +2377,7 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi } /* clear username and password from memory */ - CLEAR (*up); + secure_memzero (up, sizeof (*up)); /* Perform final authentication checks */ if (ks->authenticated) @@ -2433,7 +2433,7 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi return true; error: - CLEAR (*ks->key_src); + secure_memzero (ks->key_src, sizeof (*ks->key_src)); buf_clear (buf); gc_free (&gc); return false; diff --git a/src/openvpn/ssl_verify.c b/src/openvpn/ssl_verify.c index a099776fdc4..4328828bed2 100644 --- a/src/openvpn/ssl_verify.c +++ b/src/openvpn/ssl_verify.c @@ -1176,7 +1176,7 @@ verify_user_pass(struct user_pass *up, struct tls_multi *multi, if (memcmp_constant_time(multi->auth_token, up->password, strlen(multi->auth_token)) != 0) { - memset (multi->auth_token, 0, AUTH_TOKEN_SIZE); + secure_memzero (multi->auth_token, AUTH_TOKEN_SIZE); free (multi->auth_token); multi->auth_token = NULL; multi->auth_token_sent = false; @@ -1262,7 +1262,7 @@ verify_user_pass(struct user_pass *up, struct tls_multi *multi, "No auth-token will be activated now"); if (multi->auth_token) { - memset (multi->auth_token, 0, AUTH_TOKEN_SIZE); + secure_memzero (multi->auth_token, AUTH_TOKEN_SIZE); free (multi->auth_token); multi->auth_token = NULL; } diff --git a/src/openvpn/ssl_verify_mbedtls.c b/src/openvpn/ssl_verify_mbedtls.c index 332f04bafba..42608235359 100644 --- a/src/openvpn/ssl_verify_mbedtls.c +++ b/src/openvpn/ssl_verify_mbedtls.c @@ -348,12 +348,10 @@ x509_setenv (struct env_set *es, int cert_depth, mbedtls_x509_crt *cert) int i; unsigned char c; const mbedtls_x509_name *name; - char s[128]; + char s[128] = { 0 }; name = &cert->subject; - memset( s, 0, sizeof( s ) ); - while( name != NULL ) { char name_expand[64+8]; From 997795353916ffcb413a2da02dc7f210fd621954 Mon Sep 17 00:00:00 2001 From: Selva Nair Date: Tue, 29 Nov 2016 20:53:14 -0500 Subject: [PATCH 423/643] When parsing '--setenv opt xx ..' make sure a third parameter is present When no parameters are present, set it to "setenv opt" to trigger a descriptive error message. And, thus get rid of the pesky NULL pointer dereferencing. Trac: #779 Signed-off-by: Selva Nair Acked-by: Gert Doering Message-Id: <1480470794-6349-1-git-send-email-selva.nair@gmail.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13311.html Signed-off-by: Gert Doering --- src/openvpn/options.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/openvpn/options.c b/src/openvpn/options.c index a7a1f9a4c86..eac80232707 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -4407,6 +4407,8 @@ add_option (struct options *options, */ if (streq (p[0], "setenv") && p[1] && streq (p[1], "opt") && !(permission_mask & OPT_P_PULL_MODE)) { + if (!p[2]) + p[2] = "setenv opt"; /* will trigger an error that includes setenv opt */ p += 2; msglevel_fc = M_WARN; } From 788e5e4a08e0df7206d17e9cbc135764d6fc385f Mon Sep 17 00:00:00 2001 From: Selva Nair Date: Tue, 29 Nov 2016 19:39:32 -0500 Subject: [PATCH 424/643] Force 'def1' method when --redirect-gateway is done through service The service deletes all added routes when the client process (openvpn) exits, causing the re-instated default route to disappear. Fix by rewriting "--redirect-gateway" to "--redirect-gateway def1" when routes are set using interactive service. Only the behaviour on Windows with intereactive service is affected. Trac: #778 Signed-off-by: Selva Nair Acked-by: Gert Doering Message-Id: <1480466372-2396-1-git-send-email-selva.nair@gmail.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13307.html Signed-off-by: Gert Doering --- Changes.rst | 6 ++++++ src/openvpn/options.c | 22 ++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/Changes.rst b/Changes.rst index aa80c103530..1343034e1bf 100644 --- a/Changes.rst +++ b/Changes.rst @@ -79,6 +79,12 @@ New interactive Windows service files under %USERPROFILE%\\OpenVPN\\config for use with the interactive service. +redirect-gateway + if no flags are given, and the interactive service is used, "def1" + is implicitly set (because "delete and later reinstall the existing + default route" does not work well here). If not using the service, + the old behaviour is kept. + redirect-gateway ipv6 OpenVPN has now feature parity between IPv4 and IPv6 for redirect gateway including the handling of overlapping IPv6 routes with diff --git a/src/openvpn/options.c b/src/openvpn/options.c index eac80232707..038fcd3820d 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -2526,6 +2526,22 @@ options_postprocess_mutate_ce (struct options *o, struct connection_entry *ce) } +#ifdef _WIN32 +/* If iservice is in use, we need def1 method for redirect-gateway */ +static void +remap_redirect_gateway_flags (struct options *opt) +{ + if (opt->routes + && opt->route_method == ROUTE_METHOD_SERVICE + && opt->routes->flags & RG_REROUTE_GW + && !(opt->routes->flags & RG_DEF1)) + { + msg (M_INFO, "Flag 'def1' added to --redirect-gateway (iservice is in use)"); + opt->routes->flags |= RG_DEF1; + } +} +#endif + static void options_postprocess_mutate_invariant (struct options *options) { @@ -2555,6 +2571,8 @@ options_postprocess_mutate_invariant (struct options *options) options->tuntap_options.ip_win32_type = IPW32_SET_MANUAL; options->ifconfig_noexec = false; } + + remap_redirect_gateway_flags (options); #endif #if P2MP_SERVER @@ -5707,6 +5725,10 @@ add_option (struct options *options, goto err; } } +#ifdef _WIN32 + /* we need this here to handle pushed --redirect-gateway */ + remap_redirect_gateway_flags (options); +#endif options->routes->flags |= RG_ENABLE; } else if (streq (p[0], "remote-random-hostname") && !p[1]) From fb56058a98dcc81b34cffbdc46417d672b8926e1 Mon Sep 17 00:00:00 2001 From: Selva Nair Date: Wed, 30 Nov 2016 16:51:36 -0500 Subject: [PATCH 425/643] Do not restart dns client service as a part of --register-dns processing As reported and discussed on Trac #775, restarting dns service has unwanted side effects when there are dependent services. And it appears unnecessary to restart this service to get DNS registered on Windows. Resolve by removing two actions from --register-dns: 'net stop dnscache' and 'net start dnscache' run through the service or directly. Trac: #775 Signed-off-by: Selva Nair Acked-by: Gert Doering Message-Id: <1480542696-7123-1-git-send-email-selva.nair@gmail.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13331.html Signed-off-by: Gert Doering --- Changes.rst | 4 ++++ doc/openvpn.8 | 3 +-- src/openvpn/options.c | 4 ++-- src/openvpn/tun.c | 18 ++---------------- src/openvpnserv/interactive.c | 8 +------- 5 files changed, 10 insertions(+), 27 deletions(-) diff --git a/Changes.rst b/Changes.rst index 1343034e1bf..abd72586253 100644 --- a/Changes.rst +++ b/Changes.rst @@ -251,6 +251,10 @@ User-visible Changes as the VPN server, are dropped. This could be disabled with --allow-recursive-routing option. +- on Windows, when the ``--register-dns`` option is set, OpenVPN no longer + restarts the ``dnscache`` service - this had unwanted side effects, and + seems to be no longer necessary with currently supported Windows versions. + Maintainer-visible changes -------------------------- - OpenVPN no longer supports building with crypto support, but without TLS diff --git a/doc/openvpn.8 b/doc/openvpn.8 index dd09c703e7d..e61b6bbcd73 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -5811,8 +5811,7 @@ above. .\"********************************************************* .TP .B \-\-register\-dns -Run net stop dnscache, net start dnscache, ipconfig /flushdns -and ipconfig /registerdns on connection initiation. +Run ipconfig /flushdns and ipconfig /registerdns on connection initiation. This is known to kick Windows into recognizing pushed DNS servers. .\"********************************************************* diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 038fcd3820d..47acd97c458 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -717,8 +717,8 @@ static const char usage_message[] = "--dhcp-pre-release : Ask Windows to release the previous TAP adapter lease on\n" " startup.\n" "--dhcp-release : Ask Windows to release the TAP adapter lease on shutdown.\n" - "--register-dns : Run net stop dnscache, net start dnscache, ipconfig /flushdns\n" - " and ipconfig /registerdns on connection initiation.\n" + "--register-dns : Run ipconfig /flushdns and ipconfig /registerdns\n" + " on connection initiation.\n" "--tap-sleep n : Sleep for n seconds after TAP adapter open before\n" " attempting to set adapter properties.\n" "--pause-exit : When run from a console window, pause before exiting.\n" diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index 560b1a8e153..572e168b153 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -4597,23 +4597,9 @@ ipconfig_register_dns (const struct env_set *es) bool status; const char err[] = "ERROR: Windows ipconfig command failed"; - msg (D_TUNTAP_INFO, "Start net commands..."); + msg (D_TUNTAP_INFO, "Start ipconfig commands for register-dns..."); netcmd_semaphore_lock (); - argv_printf (&argv, "%s%sc stop dnscache", - get_win_sys_path(), - WIN_NET_PATH_SUFFIX); - argv_msg (D_TUNTAP_INFO, &argv); - status = openvpn_execve_check (&argv, es, 0, err); - argv_reset(&argv); - - argv_printf (&argv, "%s%sc start dnscache", - get_win_sys_path(), - WIN_NET_PATH_SUFFIX); - argv_msg (D_TUNTAP_INFO, &argv); - status = openvpn_execve_check (&argv, es, 0, err); - argv_reset(&argv); - argv_printf (&argv, "%s%sc /flushdns", get_win_sys_path(), WIN_IPCONFIG_PATH_SUFFIX); @@ -4629,7 +4615,7 @@ ipconfig_register_dns (const struct env_set *es) argv_reset(&argv); netcmd_semaphore_release (); - msg (D_TUNTAP_INFO, "End net commands..."); + msg (D_TUNTAP_INFO, "End ipconfig commands for register-dns..."); } void diff --git a/src/openvpnserv/interactive.c b/src/openvpnserv/interactive.c index 608bb0c3778..ec54216bb44 100644 --- a/src/openvpnserv/interactive.c +++ b/src/openvpnserv/interactive.c @@ -899,8 +899,7 @@ RegisterDNS (LPVOID unused) WCHAR sys_path[MAX_PATH]; DWORD timeout = RDNS_TIMEOUT * 1000; /* in milliseconds */ - /* default paths of net and ipconfig commands */ - WCHAR net[MAX_PATH] = L"C:\\Windows\\system32\\net.exe"; + /* default path of ipconfig command */ WCHAR ipcfg[MAX_PATH] = L"C:\\Windows\\system32\\ipconfig.exe"; struct @@ -909,8 +908,6 @@ RegisterDNS (LPVOID unused) WCHAR *cmdline; DWORD timeout; } cmds [] = { - { net, L"net stop dnscache", timeout }, - { net, L"net start dnscache", timeout }, { ipcfg, L"ipconfig /flushdns", timeout }, { ipcfg, L"ipconfig /registerdns", timeout }, }; @@ -920,9 +917,6 @@ RegisterDNS (LPVOID unused) if(GetSystemDirectory(sys_path, MAX_PATH)) { - _snwprintf (net, MAX_PATH, L"%s\\%s", sys_path, L"net.exe"); - net[MAX_PATH-1] = L'\0'; - _snwprintf (ipcfg, MAX_PATH, L"%s\\%s", sys_path, L"ipconfig.exe"); ipcfg[MAX_PATH-1] = L'\0'; } From ce91c187ee0dd73aa4dbe4468181db90403951ce Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Thu, 1 Dec 2016 18:41:45 +0800 Subject: [PATCH 426/643] reload CRL only if file was modified In order to prevent annoying delays upon client connection, reload the CRL file only if it was modified since the last reload operation. If not, keep on using the already stored CRL. This change will boost client connection time in instances where the CRL file is quite large (dropping from several seconds to few milliseconds). Cc: Steffan Karger Signed-off-by: Antonio Quartulli Acked-by: Steffan Karger Message-Id: <20161201104145.23821-1-a@unstable.cc> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13345.html Signed-off-by: Gert Doering --- Changes.rst | 5 ++++ src/openvpn/ssl.c | 53 ++++++++++++++++++++++++++++++++++++++- src/openvpn/ssl_backend.h | 2 +- src/openvpn/ssl_mbedtls.c | 2 +- src/openvpn/ssl_mbedtls.h | 2 ++ src/openvpn/ssl_openssl.c | 2 +- src/openvpn/ssl_openssl.h | 2 ++ 7 files changed, 64 insertions(+), 4 deletions(-) diff --git a/Changes.rst b/Changes.rst index abd72586253..0594731d514 100644 --- a/Changes.rst +++ b/Changes.rst @@ -255,6 +255,11 @@ User-visible Changes restarts the ``dnscache`` service - this had unwanted side effects, and seems to be no longer necessary with currently supported Windows versions. +- OpenVPN now reloads a CRL only if the modication time or file size has + changed, instead of for each new connection. This reduces the connection + setup time, in particular when using large CRLs. + + Maintainer-visible changes -------------------------- - OpenVPN no longer supports building with crypto support, but without TLS diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 14d13312982..34d163f622a 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -512,6 +512,54 @@ tls_version_parse(const char *vstr, const char *extra) return TLS_VER_BAD; } +/** + * Load (or possibly reload) the CRL file into the SSL context. + * No reload is performed under the following conditions: + * - the CRL file was passed inline + * - the CRL file was not modified since the last (re)load + * + * @param ssl_ctx The TLS context to use when reloading the CRL + * @param crl_file The file name to load the CRL from, or + * "[[INLINE]]" in the case of inline files. + * @param crl_inline A string containing the CRL + */ +static void +tls_ctx_reload_crl(struct tls_root_ctx *ssl_ctx, const char *crl_file, + const char *crl_file_inline) +{ + /* if something goes wrong with stat(), we'll store 0 as mtime */ + platform_stat_t crl_stat = {0}; + + /* + * an inline CRL can't change at runtime, therefore there is no need to + * reload it. It will be reloaded upon config change + SIGHUP. + * Use always '1' as dummy timestamp in this case: it will trigger the + * first load, but will prevent any future reload. + */ + if (crl_file_inline) + { + crl_stat.st_mtime = 1; + } + else if (platform_stat(crl_file, &crl_stat) < 0) + { + msg(M_WARN, "WARNING: Failed to stat CRL file, not (re)loading CRL."); + return; + } + + /* + * Store the CRL if this is the first time or if the file was changed since + * the last load. + * Note: Windows does not support tv_nsec. + */ + if ((ssl_ctx->crl_last_size == crl_stat.st_size) && + (ssl_ctx->crl_last_mtime.tv_sec == crl_stat.st_mtime)) + return; + + ssl_ctx->crl_last_mtime.tv_sec = crl_stat.st_mtime; + ssl_ctx->crl_last_size = crl_stat.st_size; + backend_tls_ctx_reload_crl(ssl_ctx, crl_file, crl_file_inline); +} + /* * Initialize SSL context. * All files are in PEM format. @@ -2581,7 +2629,10 @@ tls_process (struct tls_multi *multi, ks->state = S_START; state_change = true; - /* Reload the CRL before TLS negotiation */ + /* + * Attempt CRL reload before TLS negotiation. Won't be performed if + * the file was not modified since the last reload + */ if (session->opt->crl_file && !(session->opt->ssl_flags & SSLF_CRL_VERIFY_DIR)) { diff --git a/src/openvpn/ssl_backend.h b/src/openvpn/ssl_backend.h index 0777c61cec1..3fbd2b4fbef 100644 --- a/src/openvpn/ssl_backend.h +++ b/src/openvpn/ssl_backend.h @@ -353,7 +353,7 @@ void key_state_ssl_free(struct key_state_ssl *ks_ssl); * "[[INLINE]]" in the case of inline files. * @param crl_inline A string containing the CRL */ -void tls_ctx_reload_crl(struct tls_root_ctx *ssl_ctx, +void backend_tls_ctx_reload_crl(struct tls_root_ctx *ssl_ctx, const char *crl_file, const char *crl_inline); /** diff --git a/src/openvpn/ssl_mbedtls.c b/src/openvpn/ssl_mbedtls.c index 7fa35a70f30..11ee65b77c6 100644 --- a/src/openvpn/ssl_mbedtls.c +++ b/src/openvpn/ssl_mbedtls.c @@ -771,7 +771,7 @@ static void tls_version_to_major_minor(int tls_ver, int *major, int *minor) { } void -tls_ctx_reload_crl(struct tls_root_ctx *ctx, const char *crl_file, +backend_tls_ctx_reload_crl(struct tls_root_ctx *ctx, const char *crl_file, const char *crl_inline) { ASSERT (crl_file); diff --git a/src/openvpn/ssl_mbedtls.h b/src/openvpn/ssl_mbedtls.h index 3edeedc4889..a4a7f05c7b1 100644 --- a/src/openvpn/ssl_mbedtls.h +++ b/src/openvpn/ssl_mbedtls.h @@ -74,6 +74,8 @@ struct tls_root_ctx { mbedtls_x509_crt *ca_chain; /**< CA chain for remote verification */ mbedtls_pk_context *priv_key; /**< Local private key */ mbedtls_x509_crl *crl; /**< Certificate Revocation List */ + struct timespec crl_last_mtime; /**< CRL last modification time */ + off_t crl_last_size; /**< size of last loaded CRL */ #if defined(ENABLE_PKCS11) mbedtls_pkcs11_context *priv_key_pkcs11; /**< PKCS11 private key */ #endif diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c index 51669fcf376..4f472ffc9f9 100644 --- a/src/openvpn/ssl_openssl.c +++ b/src/openvpn/ssl_openssl.c @@ -772,7 +772,7 @@ tls_ctx_load_priv_file (struct tls_root_ctx *ctx, const char *priv_key_file, } void -tls_ctx_reload_crl(struct tls_root_ctx *ssl_ctx, const char *crl_file, +backend_tls_ctx_reload_crl(struct tls_root_ctx *ssl_ctx, const char *crl_file, const char *crl_inline) { X509_CRL *crl = NULL; diff --git a/src/openvpn/ssl_openssl.h b/src/openvpn/ssl_openssl.h index 97dc7422c94..115ac43eef7 100644 --- a/src/openvpn/ssl_openssl.h +++ b/src/openvpn/ssl_openssl.h @@ -49,6 +49,8 @@ */ struct tls_root_ctx { SSL_CTX *ctx; + struct timespec crl_last_mtime; + off_t crl_last_size; }; struct key_state_ssl { From 1c587a11122206186098c2014d407d0eb469656e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuli=20Sepp=C3=A4nen?= Date: Thu, 1 Dec 2016 16:03:05 +0200 Subject: [PATCH 427/643] Mention that OpenVPN 2.4 requires Windows Vista or higher MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Trac: #610 Signed-off-by: Samuli Seppänen Acked-by: Gert Doering Message-Id: <1480600985-25074-1-git-send-email-samuli@openvpn.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13357.html Signed-off-by: Gert Doering --- INSTALL | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/INSTALL b/INSTALL index 4c6d21f45dd..97070604695 100644 --- a/INSTALL +++ b/INSTALL @@ -59,7 +59,8 @@ SUPPORTED PLATFORMS: (4) Mac OS X Darwin 10.5+ (5) FreeBSD 7.4+ (6) NetBSD 5.0+ - (7) Windows (WinXP and higher) + (7) Windows Vista or later for OpenVPN 2.4 + (8) Windows XP or later for OpenVPN 2.3 SUPPORTED PROCESSOR ARCHITECTURES: In general, OpenVPN is word size and endian independent, so From c5931897ae8d663e7e6244764fc6379d7b4740f3 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 1 Dec 2016 22:31:03 +0100 Subject: [PATCH 428/643] Use systemd service manager notification Notify systemd service manager when our initialization sequence completed. This helps ordering services as dependencies can rely on vpn being available. v2: Add curly brackets (and indention) to block the else-part, msg() call was non-conditional before. v3: Move systemd header include from init.h to init.c. Signed-off-by: Christian Hesse Tested-By: Richard Bonhomme Acked-by: David Sommerseth Message-Id: <20161201213104.5667-1-list@eworm.de> URL: http://www.mail-archive.com/search?l=mid&q=20161201213104.5667-1-list@eworm.de Signed-off-by: David Sommerseth --- distro/systemd/openvpn-client@.service | 1 + distro/systemd/openvpn-server@.service | 1 + src/openvpn/init.c | 14 +++++++++++++- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/distro/systemd/openvpn-client@.service b/distro/systemd/openvpn-client@.service index 18b84dd1c9a..f64a2396574 100644 --- a/distro/systemd/openvpn-client@.service +++ b/distro/systemd/openvpn-client@.service @@ -7,6 +7,7 @@ Documentation=https://community.openvpn.net/openvpn/wiki/Openvpn24ManPage Documentation=https://community.openvpn.net/openvpn/wiki/HOWTO [Service] +Type=notify PrivateTmp=true RuntimeDirectory=openvpn-client RuntimeDirectoryMode=0710 diff --git a/distro/systemd/openvpn-server@.service b/distro/systemd/openvpn-server@.service index a2b7b52b85b..890e6a9ff2d 100644 --- a/distro/systemd/openvpn-server@.service +++ b/distro/systemd/openvpn-server@.service @@ -7,6 +7,7 @@ Documentation=https://community.openvpn.net/openvpn/wiki/Openvpn24ManPage Documentation=https://community.openvpn.net/openvpn/wiki/HOWTO [Service] +Type=notify PrivateTmp=true RuntimeDirectory=openvpn-server RuntimeDirectoryMode=0710 diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 2ccbab2f788..f99c934bf4e 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -30,6 +30,10 @@ #include "syshead.h" +#ifdef ENABLE_SYSTEMD +#include +#endif + #include "win32.h" #include "init.h" #include "sig.h" @@ -1251,11 +1255,19 @@ initialization_sequence_completed (struct context *c, const unsigned int flags) show_adapters (M_INFO|M_NOPREFIX); msg (M_INFO, "%s With Errors ( see http://openvpn.net/faq.html#dhcpclientserv )", message); #else +#ifdef ENABLE_SYSTEMD + sd_notifyf(0, "STATUS=Failed to start up: %s With Errors\nERRNO=1", message); +#endif /* HAVE_SYSTEMD_SD_DAEMON_H */ msg (M_INFO, "%s With Errors", message); #endif } else - msg (M_INFO, "%s", message); + { +#ifdef ENABLE_SYSTEMD + sd_notifyf(0, "READY=1\nSTATUS=%s\nMAINPID=%lu", message, (unsigned long) getpid()); +#endif + msg (M_INFO, "%s", message); + } /* Flag that we initialized */ if ((flags & (ISC_ERRORS|ISC_SERVER)) == 0) From 7660bba111f739f9cc7017c392c1434f201b8c44 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Thu, 1 Dec 2016 22:31:04 +0100 Subject: [PATCH 429/643] Refuse to daemonize when running from systemd We start with systemd Type=notify, so refuse to daemonize. This does not affect starting openvpn from script or command line. v2: Update commit message about script and command line. Signed-off-by: Christian Hesse Tested-By: Richard Bonhomme Acked-by: David Sommerseth Message-Id: <20161201213104.5667-2-list@eworm.de> URL: http://www.mail-archive.com/search?l=mid&q=20161201213104.5667-2-list@eworm.de Signed-off-by: David Sommerseth --- distro/systemd/openvpn-client@.service | 1 - distro/systemd/openvpn-server@.service | 1 - src/openvpn/init.c | 7 +++++++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/distro/systemd/openvpn-client@.service b/distro/systemd/openvpn-client@.service index f64a2396574..5618af3a37b 100644 --- a/distro/systemd/openvpn-client@.service +++ b/distro/systemd/openvpn-client@.service @@ -12,7 +12,6 @@ PrivateTmp=true RuntimeDirectory=openvpn-client RuntimeDirectoryMode=0710 WorkingDirectory=/etc/openvpn/client -ExecStartPre=/bin/sh -c 'grep -q -E ^daemon %i.conf || exit 0 && /usr/bin/echo "OpenVPN configuration cannot contain --daemon when being managed by systemd" ; exit 1' ExecStart=/usr/sbin/openvpn --suppress-timestamps --nobind --config %i.conf CapabilityBoundingSet=CAP_IPC_LOCK CAP_NET_ADMIN CAP_NET_RAW CAP_SETGID CAP_SETUID CAP_SYS_CHROOT CAP_DAC_OVERRIDE LimitNPROC=10 diff --git a/distro/systemd/openvpn-server@.service b/distro/systemd/openvpn-server@.service index 890e6a9ff2d..b9b4dba18bb 100644 --- a/distro/systemd/openvpn-server@.service +++ b/distro/systemd/openvpn-server@.service @@ -12,7 +12,6 @@ PrivateTmp=true RuntimeDirectory=openvpn-server RuntimeDirectoryMode=0710 WorkingDirectory=/etc/openvpn/server -ExecStartPre=/bin/sh -c 'grep -q -E ^daemon %i.conf || exit 0 && /usr/bin/echo "OpenVPN configuration cannot contain --daemon when being managed by systemd" ; exit 1' ExecStart=/usr/sbin/openvpn --status %t/openvpn-server/status-%i.log --status-version 2 --suppress-timestamps --config %i.conf CapabilityBoundingSet=CAP_IPC_LOCK CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW CAP_SETGID CAP_SETUID CAP_SYS_CHROOT CAP_DAC_OVERRIDE LimitNPROC=10 diff --git a/src/openvpn/init.c b/src/openvpn/init.c index f99c934bf4e..74f1139563f 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -930,6 +930,13 @@ bool possibly_become_daemon (const struct options *options) { bool ret = false; + +#ifdef ENABLE_SYSTEMD + /* return without forking if we are running from systemd */ + if (sd_notify(0, "READY=0") > 0) + return ret; +#endif + if (options->daemon) { ASSERT (!options->inetd); From e739d7f445abc36277f60b2fb048809cdbeb7df1 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Fri, 2 Dec 2016 00:09:00 +0100 Subject: [PATCH 430/643] Preparing OpenVPN v2.4_rc1 release Signed-off-by: David Sommerseth --- ChangeLog | 28 ++++++++++++++++++++++++++++ Changes.rst | 10 ++++++++++ version.m4 | 2 +- 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index abb9d385feb..59e679d4476 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,34 @@ OpenVPN Change Log Copyright (C) 2002-2016 OpenVPN Technologies, Inc. +2016.12.01 -- Version 2.4_rc1 +Antonio Quartulli (1): + reload CRL only if file was modified + +Christian Hesse (3): + update year in copyright message + Use systemd service manager notification + Refuse to daemonize when running from systemd + +Gert Doering (1): + Fix windows path in Changes.rst + +Samuli Seppänen (1): + Mention that OpenVPN 2.4 requires Windows Vista or higher + +Selva Nair (4): + Map restart signals from event loop to SIGTERM during exit-notification wait + When parsing '--setenv opt xx ..' make sure a third parameter is present + Force 'def1' method when --redirect-gateway is done through service + Do not restart dns client service as a part of --register-dns processing + +Steffan Karger (4): + tls_process: don't set variable that's never read + Unconditionally enable TLS_AGGREGATE_ACK + Clean up format_hex_ex() + Introduce and use secure_memzero() to erase secrets + + 2016.11.24 -- Version 2.4_beta2 Arne Schwabe (5): Document that tls-crypt also supports inline diff --git a/Changes.rst b/Changes.rst index 0594731d514..843f2bd5f08 100644 --- a/Changes.rst +++ b/Changes.rst @@ -259,6 +259,12 @@ User-visible Changes changed, instead of for each new connection. This reduces the connection setup time, in particular when using large CRLs. +- OpenVPN now ships with more up-to-date systemd unit files which takes advantage + of the improved service management as well as some hardening steps. The + configuration files are picked up from /etc/openvpn/server and + /etc/openvpn/client (depending on unit file). This also avoids these new + unit files and how they work to collide with older pre-existing unit files. + Maintainer-visible changes -------------------------- @@ -267,3 +273,7 @@ Maintainer-visible changes OPENSSL_SSL_{CFLAGS,LIBS} have been merged into OPENSSL_{CFLAGS,LIBS}. This is particularly relevant for maintainers who build their own OpenSSL library, e.g. when cross-compiling. + +- Linux distributions using systemd is highly encouraged to ship these new unit + files instead of older ones, to provide a unified behaviour across systemd + based Linux distributions. diff --git a/version.m4 b/version.m4 index b5fb2341e16..60313a3611c 100644 --- a/version.m4 +++ b/version.m4 @@ -3,7 +3,7 @@ define([PRODUCT_NAME], [OpenVPN]) define([PRODUCT_TARNAME], [openvpn]) define([PRODUCT_VERSION_MAJOR], [2]) define([PRODUCT_VERSION_MINOR], [4]) -define([PRODUCT_VERSION_PATCH], [_beta2]) +define([PRODUCT_VERSION_PATCH], [_rc1]) m4_append([PRODUCT_VERSION], [PRODUCT_VERSION_MAJOR]) m4_append([PRODUCT_VERSION], [PRODUCT_VERSION_MINOR], [[.]]) m4_append([PRODUCT_VERSION], [PRODUCT_VERSION_PATCH], [[]]) From 251cc8f2042cc0cb8281230f7fb33f2cdec5b809 Mon Sep 17 00:00:00 2001 From: Selva Nair Date: Fri, 2 Dec 2016 14:42:09 -0500 Subject: [PATCH 431/643] Correctly state the default dhcp server address in man page Also correct the default ifconfig-pool end in docs and comments Signed-off-by: Selva Nair Acked-by: Gert Doering Message-Id: <1480707729-19578-1-git-send-email-selva.nair@gmail.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13387.html Signed-off-by: Gert Doering --- doc/openvpn.8 | 4 ++-- src/openvpn/helper.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index e61b6bbcd73..290a441ad0d 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -2793,7 +2793,7 @@ expands as follows: if dev tap OR (dev tun AND topology == subnet): ifconfig 10.8.0.1 255.255.255.0 if !nopool: - ifconfig\-pool 10.8.0.2 10.8.0.254 255.255.255.0 + ifconfig\-pool 10.8.0.2 10.8.0.253 255.255.255.0 push "route\-gateway 10.8.0.1" if route\-gateway unset: route\-gateway 10.8.0.2 @@ -5594,7 +5594,7 @@ virtual DHCP server address. In .B \-\-dev tun mode, OpenVPN will cause the DHCP server to masquerade as if it were coming from the remote endpoint. The optional offset parameter is -an integer which is > \-256 and < 256 and which defaults to 0. +an integer which is > \-256 and < 256 and which defaults to -1. If offset is positive, the DHCP server will masquerade as the IP address at network address + offset. If offset is negative, the DHCP server will masquerade as the IP diff --git a/src/openvpn/helper.c b/src/openvpn/helper.c index 229523dbd1e..319c71634f4 100644 --- a/src/openvpn/helper.c +++ b/src/openvpn/helper.c @@ -228,7 +228,7 @@ helper_client_server (struct options *o) * if tap OR (tun AND topology == subnet): * ifconfig 10.8.0.1 255.255.255.0 * if !nopool: - * ifconfig-pool 10.8.0.2 10.8.0.254 255.255.255.0 + * ifconfig-pool 10.8.0.2 10.8.0.253 255.255.255.0 * push "route-gateway 10.8.0.1" * if route-gateway unset: * route-gateway 10.8.0.2 From e62eccf025aa60ec268787d2aa4a46310ed1cd60 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Tue, 6 Dec 2016 23:10:51 +0100 Subject: [PATCH 432/643] Fix wrong configure.ac parsing of --enable-async-push AC_ARG_ENABLE() was used wrong, which led enable_async_push to always be set, regardless if --enable-async-push or --disable-async-push was used. Also spotted the exact same patch when writing this commit message as GitHub PR#70. Trac: #786 Signed-off-by: David Sommerseth Acked-by: Lev Stipakov Message-Id: <1481062251-18349-1-git-send-email-davids@openvpn.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13411.html --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index f4073d051e8..27bdcc3a111 100644 --- a/configure.ac +++ b/configure.ac @@ -267,7 +267,7 @@ AC_ARG_ENABLE( AC_ARG_ENABLE( [async-push], [AS_HELP_STRING([--enable-async-push], [enable async-push support @<:@default=no@:>@])], - [enable_async_push="yes"], + , [enable_async_push="no"] ) From 7084a3993fa35c6fb71abe8aac7b30f442205e2a Mon Sep 17 00:00:00 2001 From: Lev Stipakov Date: Wed, 7 Dec 2016 01:45:51 +0200 Subject: [PATCH 433/643] Arm inotify only in server mode Async-push is a server side feature and inotify_fd is initialized in server mode. Trac: #786 Signed-off-by: Lev Stipakov Acked-by: David Sommerseth Message-Id: <1481067951-28917-1-git-send-email-lstipakov@gmail.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13415.html Signed-off-by: David Sommerseth --- src/openvpn/forward.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c index b50a2e02577..4502e10127c 100644 --- a/src/openvpn/forward.c +++ b/src/openvpn/forward.c @@ -1578,7 +1578,8 @@ io_wait_dowork (struct context *c, const unsigned int flags) #ifdef ENABLE_ASYNC_PUSH /* arm inotify watcher */ - event_ctl (c->c2.event_set, c->c2.inotify_fd, EVENT_READ, (void*)&file_shift); + if (c->options.mode == MODE_SERVER) + event_ctl (c->c2.event_set, c->c2.inotify_fd, EVENT_READ, (void*)&file_shift); #endif /* From 212ef1a409b375174dd81d52da34678ebab685ae Mon Sep 17 00:00:00 2001 From: Lev Stipakov Date: Wed, 7 Dec 2016 11:56:57 +0200 Subject: [PATCH 434/643] Add "async push" feature to Changes.rst [DS: slightly enhanced the --enable-async-push remark to make it even more clear it is a build time configuration] Acked-by: David Sommerseth Message-Id: <1481104617-3675-1-git-send-email-lstipakov@gmail.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13420.html Signed-off-by: David Sommerseth --- Changes.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Changes.rst b/Changes.rst index 843f2bd5f08..de2d8b0087b 100644 --- a/Changes.rst +++ b/Changes.rst @@ -147,6 +147,12 @@ Control channel encryption (``--tls-crypt``) channel packets. Provides more privacy, some obfuscation and poor-man's post-quantum security. +Asynchronous push reply + If asynchronous authentication is enabled and completed after server received + PUSH_REQUEST message, server sends PUSH_REPLY immediately without waiting for next + PUSH_REQUEST. Requires use of ``--enable-async-push`` as ./configure parameter at + build time. + Deprecated features ------------------- From e35a788339497ec5c179a5d0a23f63824989ec3e Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Tue, 6 Dec 2016 13:26:02 +0100 Subject: [PATCH 435/643] Refactor setting close-on-exec for socket FDs The existing code can leak socket FDs to the "--up" script, which is not desired. Brought up by Alberto Gonzalez Iniesta, based on debian bug 367716. Since different sockets get create at different times, just moving the set_cloexec() to link_socket_init_phase1() is not good enough - so move the call into create_socket_(), so we will catch ALL socket creations, no matter when or under which conditions they will be created (SOCKS proxy socket, listening socket, ...). --inetd gets an extra fd_cloexec() call, as socket FD is inherited. URL: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=367716 v2: remove set_cloexec() calls from manage.c v3: add set_cloexec() calls to accept()ed TCP/unix child sockets Signed-off-by: Gert Doering Acked-by: Arne Schwabe Message-Id: <1481027162-12165-1-git-send-email-gert@greenie.muc.de> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13405.html Signed-off-by: Gert Doering --- src/openvpn/manage.c | 2 -- src/openvpn/socket.c | 34 +++++++++++++++++++++++++++------- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/src/openvpn/manage.c b/src/openvpn/manage.c index 4918ed2caf7..aab42249656 100644 --- a/src/openvpn/manage.c +++ b/src/openvpn/manage.c @@ -1499,7 +1499,6 @@ man_new_connection_post (struct management *man, const char *description) struct gc_arena gc = gc_new (); set_nonblock (man->connection.sd_cli); - set_cloexec (man->connection.sd_cli); man_connection_settings_reset (man); @@ -1640,7 +1639,6 @@ man_listen (struct management *man) * Set misc socket properties */ set_nonblock (man->connection.sd_top); - set_cloexec (man->connection.sd_top); #if UNIX_SOCK_SUPPORT if (man->settings.flags & MF_UNIX_SOCK) diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c index c233f2b6f7d..ce53ee88eeb 100644 --- a/src/openvpn/socket.c +++ b/src/openvpn/socket.c @@ -771,6 +771,10 @@ create_socket_tcp (struct addrinfo* addrinfo) } #endif + /* set socket file descriptor to not pass across execs, so that + scripts don't have access to it */ + set_cloexec (sd); + return sd; } @@ -815,6 +819,11 @@ create_socket_udp (struct addrinfo* addrinfo, const unsigned int flags) } } #endif + + /* set socket file descriptor to not pass across execs, so that + scripts don't have access to it */ + set_cloexec (sd); + return sd; } @@ -968,6 +977,12 @@ socket_do_accept (socket_descriptor_t sd, openvpn_close_socket (new_sd); new_sd = SOCKET_UNDEFINED; } + else + { + /* set socket file descriptor to not pass across execs, so that + scripts don't have access to it */ + set_cloexec (sd); + } return new_sd; } @@ -1617,6 +1632,7 @@ link_socket_init_phase1 (struct link_socket *sock, ASSERT (sock->info.proto != PROTO_TCP_CLIENT); ASSERT (socket_defined (inetd_socket_descriptor)); sock->sd = inetd_socket_descriptor; + set_cloexec (sock->sd); /* not created by create_socket*() */ } else if (mode != LS_MODE_TCP_ACCEPT_FROM) { @@ -1677,13 +1693,6 @@ phase2_set_socket_flags (struct link_socket* sock) /* set socket to non-blocking mode */ set_nonblock (sock->sd); - /* set socket file descriptor to not pass across execs, so that - scripts don't have access to it */ - set_cloexec (sock->sd); - - if (socket_defined (sock->ctrl_sd)) - set_cloexec (sock->ctrl_sd); - /* set Path MTU discovery options on the socket */ set_mtu_discover_type (sock->sd, sock->mtu_discover_type, sock->info.af); @@ -3476,6 +3485,11 @@ create_socket_unix (void) if ((sd = socket (PF_UNIX, SOCK_STREAM, 0)) < 0) msg (M_ERR, "Cannot create unix domain socket"); + + /* set socket file descriptor to not pass across execs, so that + scripts don't have access to it */ + set_cloexec (sd); + return sd; } @@ -3516,6 +3530,12 @@ socket_accept_unix (socket_descriptor_t sd, CLEAR (*remote); ret = accept (sd, (struct sockaddr *) remote, &remote_len); + if ( ret >= 0 ) + { + /* set socket file descriptor to not pass across execs, so that + scripts don't have access to it */ + set_cloexec (ret); + } return ret; } From 84f88ca4d57cd0dc40fd945e09ab1cea1b2cd0b7 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Wed, 7 Dec 2016 19:01:24 +0100 Subject: [PATCH 436/643] Fix (and cleanup) crypto flags in combination with NCP tls_session_update_crypto_params() did not properly set crypto_flags_or, but instead set crypto_flags_and twice if a OFB/CFB mode was selected. Also, the crypto flags in ks->crypto_options.flags were set before tls_session_update_crypto_params() was called, causing those to not be adjusted. To fix this, set the crypto flags in tls_session_generate_data_channel_keys() instead of key_state_init(). While touching that code, remove the to _or and _and variables, which are not needed at all. Finally, refuse to accept --no-iv if NCP is enabled (we might otherwise negotiate invalid combinations and ASSERT out later, and using --no-iv is a bad idea anyway). Trac: #784 Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1481133684-5325-1-git-send-email-steffan@karger.me> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13428.html Signed-off-by: Gert Doering --- Changes.rst | 5 +++++ src/openvpn/init.c | 4 ++-- src/openvpn/options.c | 4 ++++ src/openvpn/ssl.c | 8 +++----- src/openvpn/ssl_common.h | 2 -- 5 files changed, 14 insertions(+), 9 deletions(-) diff --git a/Changes.rst b/Changes.rst index de2d8b0087b..9258230f1df 100644 --- a/Changes.rst +++ b/Changes.rst @@ -271,6 +271,11 @@ User-visible Changes /etc/openvpn/client (depending on unit file). This also avoids these new unit files and how they work to collide with older pre-existing unit files. +- using ``--no-iv`` (which is generally not a recommended setup) will + require explicitly disabling NCP with ``--disable-ncp``. This is + intentional because NCP will by default use AES-GCM, which requires + an IV - so we want users of that option to consciously reconsider. + Maintainer-visible changes -------------------------- diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 74f1139563f..fb0d0dec4b2 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -2341,9 +2341,9 @@ do_init_crypto_tls (struct context *c, const unsigned int flags) if (options->mute_replay_warnings) to.crypto_flags |= CO_MUTE_REPLAY_WARNINGS; - to.crypto_flags_and = ~(CO_PACKET_ID_LONG_FORM); + to.crypto_flags &= ~(CO_PACKET_ID_LONG_FORM); if (packet_id_long_form) - to.crypto_flags_or = CO_PACKET_ID_LONG_FORM; + to.crypto_flags |= CO_PACKET_ID_LONG_FORM; to.ssl_ctx = c->c1.ks.ssl_ctx; to.key_type = c->c1.ks.key_type; diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 47acd97c458..db1cfe35e0f 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -2234,6 +2234,10 @@ options_postprocess_verify_ce (const struct options *options, const struct conne { msg (M_USAGE, "NCP cipher list contains unsupported ciphers."); } + if (options->ncp_enabled && !options->use_iv) + { + msg (M_USAGE, "--no-iv not allowed when NCP is enabled."); + } /* * Check consistency of replay options diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 34d163f622a..f7217d38a4c 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -881,9 +881,6 @@ key_state_init (struct tls_session *session, struct key_state *ks) } ks->crypto_options.pid_persist = NULL; - ks->crypto_options.flags = session->opt->crypto_flags; - ks->crypto_options.flags &= session->opt->crypto_flags_and; - ks->crypto_options.flags |= session->opt->crypto_flags_or; #ifdef MANAGEMENT_DEF_AUTH ks->mda_key_id = session->opt->mda_context->mda_key_id_counter++; @@ -1823,6 +1820,7 @@ tls_session_generate_data_channel_keys(struct tls_session *session) ASSERT (ks->authenticated); + ks->crypto_options.flags = session->opt->crypto_flags; if (!generate_key_expansion (&ks->crypto_options.key_ctx_bi, &session->opt->key_type, ks->key_src, client_sid, server_sid, session->opt->server)) @@ -1857,9 +1855,9 @@ tls_session_update_crypto_params(struct tls_session *session, options->authname, options->keysize, true, true); bool packet_id_long_form = cipher_kt_mode_ofb_cfb (session->opt->key_type.cipher); - session->opt->crypto_flags_and &= ~(CO_PACKET_ID_LONG_FORM); + session->opt->crypto_flags &= ~(CO_PACKET_ID_LONG_FORM); if (packet_id_long_form) - session->opt->crypto_flags_and = CO_PACKET_ID_LONG_FORM; + session->opt->crypto_flags |= CO_PACKET_ID_LONG_FORM; /* Update frame parameters: undo worst-case overhead, add actual overhead */ frame_add_to_extra_frame (frame, -(crypto_max_overhead())); diff --git a/src/openvpn/ssl_common.h b/src/openvpn/ssl_common.h index 7938f41f5f8..8164bbcd4eb 100644 --- a/src/openvpn/ssl_common.h +++ b/src/openvpn/ssl_common.h @@ -279,8 +279,6 @@ struct tls_options /* struct crypto_option flags */ unsigned int crypto_flags; - unsigned int crypto_flags_and; - unsigned int crypto_flags_or; int replay_window; /* --replay-window parm */ int replay_time; /* --replay-window parm */ From 4969f0d6bba8a82d411f0700c2e8e4efbeccb6c8 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Wed, 7 Dec 2016 20:20:47 +0100 Subject: [PATCH 437/643] Deprecate --no-iv This fixes the bug of supporting --no-iv (since we're only accepting bugfixes in the current release phase ;) ). The --no-iv function decreases security if used (CBC *requires* unpredictable IVs, other modes don't allow --no-iv at all), and even marginally decreases other user's security by adding unwanted complexity to our code. Let's get rid of this. Signed-off-by: Steffan Karger Acked-by: Gert Doering Acked-by: Arne Schwabe Message-Id: <1481138447-6292-1-git-send-email-steffan@karger.me> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13430.html Signed-off-by: Gert Doering --- Changes.rst | 2 ++ doc/openvpn.8 | 4 ++++ src/openvpn/options.c | 4 ++++ 3 files changed, 10 insertions(+) diff --git a/Changes.rst b/Changes.rst index 9258230f1df..a21c0946fd8 100644 --- a/Changes.rst +++ b/Changes.rst @@ -177,6 +177,8 @@ Deprecated features X.509 subject formatting must be updated to the standardized formatting. See the man page for more information. +- ``--no-iv`` is deprecated in 2.4 and will be remove in 2.5. + User-visible Changes -------------------- - For certificate DNs with duplicate fields, e.g. "OU=one,OU=two", both fields diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 290a441ad0d..e5619c02854 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -4399,6 +4399,10 @@ This option only makes sense when replay protection is enabled .\"********************************************************* .TP .B \-\-no\-iv + +.B DEPRECATED +This option will be removed in OpenVPN 2.5. + (Advanced) Disable OpenVPN's use of IV (cipher initialization vector). Don't use this option unless you are prepared to make a tradeoff of greater efficiency in exchange for less diff --git a/src/openvpn/options.c b/src/openvpn/options.c index db1cfe35e0f..f6e0f138a53 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -2238,6 +2238,10 @@ options_postprocess_verify_ce (const struct options *options, const struct conne { msg (M_USAGE, "--no-iv not allowed when NCP is enabled."); } + if (!options->use_iv) + { + msg (M_WARN, "WARNING: --no-iv is deprecated and will be removed in 2.5"); + } /* * Check consistency of replay options From c00919e8bd6a4e36d9fa009f3b1a93b262a59fc6 Mon Sep 17 00:00:00 2001 From: Magnus Kroken Date: Fri, 9 Dec 2016 10:07:35 +0100 Subject: [PATCH 438/643] mbedtls: include correct net/net_sockets header according to version is deprecated as of mbedTLS 2.4.0, it is renamed . OpenVPN will fail to build with mbedTLS 2.4.0 with MBEDTLS_DEPRECATED_REMOVED defined. Check MBEDTLS_VERSION_NUMBER, and include net.h for < 2.4.0 and net_sockets.h for >= 2.4.0. Signed-off-by: Magnus Kroken Acked-by: Steffan Karger Message-Id: <1481274455-657-1-git-send-email-mkroken@gmail.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13451.html Signed-off-by: Gert Doering --- src/openvpn/ssl_mbedtls.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/openvpn/ssl_mbedtls.c b/src/openvpn/ssl_mbedtls.c index 11ee65b77c6..985a39fefd4 100644 --- a/src/openvpn/ssl_mbedtls.c +++ b/src/openvpn/ssl_mbedtls.c @@ -51,11 +51,17 @@ #include "ssl_verify_mbedtls.h" #include #include -#include +#include + +#if MBEDTLS_VERSION_NUMBER >= 0x02040000 + #include +#else + #include +#endif + #include #include #include -#include void tls_init_lib() From 54e386b4a89b33947314e1192f7d34a3e16c451b Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Fri, 9 Dec 2016 20:52:17 +0100 Subject: [PATCH 439/643] Changes: Further improve systemd unit file updates There were some reports that the directories mentioned should have trailing /, to make it clearer they are directories and not files. Also rephrased that sentence slightly to be even clearer in this aspect. Signed-off-by: David Sommerseth --- Changes.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Changes.rst b/Changes.rst index a21c0946fd8..a5002dd431e 100644 --- a/Changes.rst +++ b/Changes.rst @@ -269,9 +269,10 @@ User-visible Changes - OpenVPN now ships with more up-to-date systemd unit files which takes advantage of the improved service management as well as some hardening steps. The - configuration files are picked up from /etc/openvpn/server and - /etc/openvpn/client (depending on unit file). This also avoids these new - unit files and how they work to collide with older pre-existing unit files. + configuration files are picked up from the /etc/openvpn/server/ and + /etc/openvpn/client/ directories (depending on unit file). This also avoids + these new unit files and how they work to collide with older pre-existing + unit files. - using ``--no-iv`` (which is generally not a recommended setup) will require explicitly disabling NCP with ``--disable-ncp``. This is From 65140a3acfa42e5d42cdfcf8108f00a62d5767ff Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Wed, 7 Dec 2016 03:51:52 +0100 Subject: [PATCH 440/643] systemd: Intermediate --chroot fix with the new sd_notify() implementation Commit c5931897ae8d663e7e introduced support for talking directly to the systemd service manager about the situation for the OpenVPN tunnel. This approach makes a lot of sense and is mostly the proper way to do it. But it was discovered that it breaks OpenVPN configurations using --chroot. The reason sd_notify() calls fails when using chroot() is that sd_notify() expects to have access to a file as declared in the $NOTIFY_SOCKET environment variable. It is the main systemd instance which is responsible to provide both the environment variable as well as the socket file sd_nodify() should use. When --chroot comes into play, the $NOTIFY_SOCKET file will not be available for OpenVPN any more. As things are getting close to the 2.4_rc2 release we will not dare to bring a too invasive fix. As well we need some time to discuss an approrpriate solution. So this intermediate fix will only provide a "successful start" message to the systemd service manager right before chroot() happens. This will at least resolve the issue in a safe and non-intrusive way. Signed-off-by: David Sommerseth Acked-by: Christian Hesse Message-Id: <1481079112-22990-1-git-send-email-davids@openvpn.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13416.html --- src/openvpn/init.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/openvpn/init.c b/src/openvpn/init.c index fb0d0dec4b2..26b236de055 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -967,7 +967,27 @@ do_uid_gid_chroot (struct context *c, bool no_delay) if (c->options.chroot_dir) { if (no_delay) - platform_chroot (c->options.chroot_dir); + { +#ifdef ENABLE_SYSTEMD + /* If OpenVPN is started by systemd, the OpenVPN process needs + * to provide a preliminary status report to systemd. This is + * needed as $NOTIFY_SOCKET will not be available inside the + * chroot, which sd_notify()/sd_notifyf() depends on. + * + * This approach is the simplest and the most non-intrusive + * solution right before the 2.4_rc2 release. + * + * TODO: Consider altnernative solutions - bind mount? + * systemd does not grok OpenVPN configuration files, thus cannot + * have a sane way to know if OpenVPN will chroot or not and to + * which subdirectory it will chroot into. + */ + sd_notifyf(0, "READY=1\n" + "STATUS=Entering chroot, most of the init completed successfully\n" + "MAINPID=%lu", (unsigned long) getpid()); +#endif + platform_chroot (c->options.chroot_dir); + } else if (c->first_time) msg (M_INFO, "NOTE: chroot %s", why_not); } From c22428fb609a0f4ec451200a421b5d1090a962a5 Mon Sep 17 00:00:00 2001 From: Selva Nair Date: Tue, 13 Dec 2016 11:11:38 -0500 Subject: [PATCH 441/643] Unhide a line in man page by fixing a typo Signed-off-by: Selva Nair Acked-by: Steffan Karger Message-Id: <1481645498-22043-1-git-send-email-selva.nair@gmail.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13520.html Signed-off-by: David Sommerseth --- doc/openvpn.8 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index e5619c02854..42ccd989a00 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -4575,8 +4575,8 @@ public. .B \-\-ecdh\-curve name Specify the curve to use for elliptic curve Diffie Hellman. Available curves can be listed with -.B \-\-show\-curves -. The specified curve will only be used for ECDH TLS-ciphers. +.BR \-\-show\-curves . +The specified curve will only be used for ECDH TLS-ciphers. .\"********************************************************* .TP .B \-\-cert file From 07d0d73a38326c0e935ea35eb12452b69abafada Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Tue, 13 Dec 2016 20:51:12 +0100 Subject: [PATCH 442/643] man: mention that --ecdh-curve does not work on mbed TLS builds Not needed either, because mbed TLS automatically selects the curve based on the certificate. Trac: #789 Signed-off-by: Steffan Karger Acked-by: David Sommerseth Message-Id: <1481658672-5110-1-git-send-email-steffan@karger.me> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13523.html Signed-off-by: David Sommerseth --- doc/openvpn.8 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 42ccd989a00..f0797998cc2 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -4577,6 +4577,8 @@ Specify the curve to use for elliptic curve Diffie Hellman. Available curves can be listed with .BR \-\-show\-curves . The specified curve will only be used for ECDH TLS-ciphers. + +This option is not supported in mbed TLS builds of OpenVPN. .\"********************************************************* .TP .B \-\-cert file From 1a8f6b9159708a943ebdb64404de4c5fc887303b Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Wed, 14 Dec 2016 13:23:30 +0100 Subject: [PATCH 443/643] Further enhance async-push feature description Signed-off-by: David Sommerseth Acked-by: Steffan Karger Message-Id: <1481718210-15673-1-git-send-email-davids@openvpn.net> URL: http://www.mail-archive.com/search?l=mid&q=1481718210-15673-1-git-send-email-davids@openvpn.net --- Changes.rst | 9 +++++---- configure.ac | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Changes.rst b/Changes.rst index a5002dd431e..7da111926ed 100644 --- a/Changes.rst +++ b/Changes.rst @@ -148,10 +148,11 @@ Control channel encryption (``--tls-crypt``) post-quantum security. Asynchronous push reply - If asynchronous authentication is enabled and completed after server received - PUSH_REQUEST message, server sends PUSH_REPLY immediately without waiting for next - PUSH_REQUEST. Requires use of ``--enable-async-push`` as ./configure parameter at - build time. + Plug-ins providing support for deferred authentication can benefit from a more + responsive authentication where the server sends PUSH_REPLY immediately once + the authentication result is ready instead of waiting for the the client to + to send PUSH_REQUEST once more. This requires OpenVPN to be built with + ``./configure --enable-async-push``. This is a compile-time only switch. Deprecated features diff --git a/configure.ac b/configure.ac index 27bdcc3a111..4f086eab230 100644 --- a/configure.ac +++ b/configure.ac @@ -266,7 +266,7 @@ AC_ARG_ENABLE( AC_ARG_ENABLE( [async-push], - [AS_HELP_STRING([--enable-async-push], [enable async-push support @<:@default=no@:>@])], + [AS_HELP_STRING([--enable-async-push], [enable async-push support for plugins providing deferred authentication @<:@default=no@:>@])], , [enable_async_push="no"] ) From a7acb6b48e31c5b83983f7eb9caf308adb7b76f1 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Tue, 13 Dec 2016 13:16:56 +0100 Subject: [PATCH 444/643] Changes.rst: Mainatiner update on C99 Mention for maintainers that we've moved to build with -std=c99 by default. Also document that 32-bit RHEL5 builds will need -std=gnu99 to be buildable. Acked-by: Gert Doering Message-Id: <1481631416-15377-1-git-send-email-davids@openvpn.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13518.html Signed-off-by: David Sommerseth --- Changes.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Changes.rst b/Changes.rst index 7da111926ed..8508fa3fa4d 100644 --- a/Changes.rst +++ b/Changes.rst @@ -292,3 +292,9 @@ Maintainer-visible changes - Linux distributions using systemd is highly encouraged to ship these new unit files instead of older ones, to provide a unified behaviour across systemd based Linux distributions. + +- With OpenVPN v2.4, the project have moved over to depend on and actively use + the official C99 standard (-std=c99). This may on some older compiler/libc + headers combinations fail. On most of these situations it is recommended to + do use -std=gnu99 in CFLAGS. This is known to be needed when doing + i386/i686 builds on RHEL5. From 2417d55c4945d491e528dd0e4cf24047da5ceae9 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Wed, 14 Dec 2016 22:05:00 +0100 Subject: [PATCH 445/643] dev-tools: Add reformat-all.sh for code style unification This script will run all files related to the currently checked out git branch through uncrustify using a standardized style configuration. Due to a bug in uncrustify 0.64, it is needed to add a special treatment to one of the files at the moment. So this both pre- and post-patched before/after uncrustify is run. This is to simply to assure that all file processing will happen consistently each time. Also added doc/doxygen/doc_key_generation.h to an ignore list, as it carries some specific Doxygen formatting we should be careful with. This file is anyhow not so critical and can be managed manually. The src/compat/compat-lz4.[ch] files are also not touched, as they are based on upstream formatting. This makes it easier to update to a newer LZ4 version later on and even see what the differences are. v2 - Include updated config from CodeStyle wiki page Remove line lenght restriction for The Great Reformatting Update the script with improvements by krzee v3 - Update with a fixed config from the CodeStyle wiki page Corrected a typo in the commit message (0.63->0.64) Minor changes to the reformat script (no pushd/popd, some new lines moved around, bash->sh) Signed-off-by: David Sommerseth Acked-by: Steffan Karger Message-Id: <1481749500-8795-1-git-send-email-davids@openvpn.net> URL: http://www.mail-archive.com/search?l=mid&q=1481749500-8795-1-git-send-email-davids@openvpn.net --- dev-tools/reformat-all.sh | 136 ++++++++++++++++++ .../after_include_openvpn-plugin.h.in.patch | 13 ++ .../before_include_openvpn-plugin.h.in.patch | 13 ++ dev-tools/special-files.lst | 4 + dev-tools/uncrustify.conf | 65 +++++++++ 5 files changed, 231 insertions(+) create mode 100755 dev-tools/reformat-all.sh create mode 100644 dev-tools/reformat-patches/after_include_openvpn-plugin.h.in.patch create mode 100644 dev-tools/reformat-patches/before_include_openvpn-plugin.h.in.patch create mode 100644 dev-tools/special-files.lst create mode 100644 dev-tools/uncrustify.conf diff --git a/dev-tools/reformat-all.sh b/dev-tools/reformat-all.sh new file mode 100755 index 00000000000..cf42bd028cd --- /dev/null +++ b/dev-tools/reformat-all.sh @@ -0,0 +1,136 @@ +#!/bin/sh +# reformat-all.sh - Reformat all git files in the checked out +# git branch using uncrustify. +# +# Copyright (C) 2016 - David Sommerseth +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License. +# +# 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; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# + +tstamp="$(date +%Y%m%d-%H%M%S)" +files="$(pwd)/reformat-all_files-$tstamp.lst" +log="$(pwd)/reformat-all_log-$tstamp.txt" + +srcroot="$(git rev-parse --show-toplevel)" +cfg="$srcroot/dev-tools/uncrustify.conf" +specialfiles="$srcroot/dev-tools/special-files.lst" + +export gitfiles=0 +export procfiles=0 + +# Go to the root of the source tree +cd "$srcroot" + +{ + echo -n "** Starting $0: " + date + + # Find all C source/header files + git ls-files | grep -E ".*\.[ch](\.in$|$)" > "${files}.git" + + # Manage files which needs special treatment + awk -F\# '{gsub("\n| ", "", $1); print $1}' "$specialfiles" > "${files}.sp" + while read srcfile + do + res=$(grep "$srcfile" "${files}.sp" 2>/dev/null) + if [ $? -ne 0 ]; then + # If grep didn't find the file among special files, + # process it normally + echo "$srcfile" >> "$files" + else + mode=$(echo "$res" | cut -d: -f1) + case "$mode" in + E) + echo "** INFO ** Excluding '$srcfile'" + ;; + P) + echo "** INFO ** Pre-patching '$srcfile'" + patchfile="${srcroot}"/dev-tools/reformat-patches/before_$(echo "$srcfile" | tr "/" "_").patch + if [ -r "$patchfile" ]; then + git apply "$patchfile" + if [ $? -ne 0 ]; then + echo "** ERROR ** Failed to apply pre-patch file: $patchfile" + exit 2 + fi + else + echo "** WARN ** Pre-patch file for $srcfile is missing: $patchfile" + fi + echo "$srcfile" >> "${files}.postpatch" + echo "$srcfile" >> "$files" + ;; + *) + echo "** WARN ** Unknown mode '$mode' for file '$srcfile'" + ;; + esac + fi + done < "${files}.git" + rm -f "${files}.git" "${files}.sp" + + # Kick off uncrustify + echo + echo "** INFO ** Running: uncrustify -c $cfg --no-backup -l C -p debug.uncr -F $files" + uncrustify -c "$cfg" --no-backup -l C -p debug.uncr -F "$files" 2>&1 + res=$? + echo "** INFO ** Uncrustify completed (exit code $res)" +} | tee "${log}-1" # Log needs to be closed here, to be processed in next block + +{ + # Check the results + gitfiles=$(wc -l "$files" | cut -d\ -f1) + procfiles=$(grep "Parsing: " "${log}-1" | wc -l) + echo + echo "C source/header files checked into git: $gitfiles" + echo "Files processed by uncrustify: $procfiles" + echo + + # Post-Patch files modified after we uncrustify have adjusted them + if [ -r "${files}.postpatch" ]; then + while read srcfile; + do + patchfile="${srcroot}"/dev-tools/reformat-patches/after_$(echo "$srcfile" | tr "/" "_").patch + if [ -r "$patchfile" ]; then + echo "** INFO ** Post-patching '$srcfile'" + git apply "$patchfile" + if [ $? -ne 0 ]; then + echo "** WARN ** Failed to apply $patchfile" + fi + else + echo "** WARN ** Post-patch file for $srcfile is missing: $patchfile" + fi + done < "${files}.postpatch" + rm -f "${files}.postpatch" + fi +} | tee "${log}-2" # Log needs to be closed here, to be processed in next block + +cat "${log}-1" "${log}-2" > "$log" + +{ + ec=1 + echo + if [ "$gitfiles" -eq "$procfiles" ]; then + echo "Reformatting completed successfully" + ec=0 + else + last=$(tail -n1 "${log}-1") + echo "** ERROR ** Reformating failed to process all files." + echo " uncrustify exit code: $res" + echo " Last log line: $last" + echo + fi + rm -f "${log}-1" "${log}-2" +} | tee -a "$log" +rm -f "${files}" + +exit $ec diff --git a/dev-tools/reformat-patches/after_include_openvpn-plugin.h.in.patch b/dev-tools/reformat-patches/after_include_openvpn-plugin.h.in.patch new file mode 100644 index 00000000000..100da078ce7 --- /dev/null +++ b/dev-tools/reformat-patches/after_include_openvpn-plugin.h.in.patch @@ -0,0 +1,13 @@ +diff --git a/include/openvpn-plugin.h.in b/include/openvpn-plugin.h.in +index 05bffab..05b4b6a 100644 +--- a/include/openvpn-plugin.h.in ++++ b/include/openvpn-plugin.h.in +@@ -169,7 +169,7 @@ typedef void *openvpn_plugin_handle_t; + /* + * We are compiling OpenVPN. + */ +-/* #define OPENVPN_PLUGIN_DEF typedef */ ++#define OPENVPN_PLUGIN_DEF typedef + #define OPENVPN_PLUGIN_FUNC(name) (*name) + + #else /* ifdef OPENVPN_PLUGIN_H */ diff --git a/dev-tools/reformat-patches/before_include_openvpn-plugin.h.in.patch b/dev-tools/reformat-patches/before_include_openvpn-plugin.h.in.patch new file mode 100644 index 00000000000..679c414971d --- /dev/null +++ b/dev-tools/reformat-patches/before_include_openvpn-plugin.h.in.patch @@ -0,0 +1,13 @@ +diff --git a/include/openvpn-plugin.h.in b/include/openvpn-plugin.h.in +index 34ad18b..f4c5472 100644 +--- a/include/openvpn-plugin.h.in ++++ b/include/openvpn-plugin.h.in +@@ -169,7 +169,7 @@ typedef void *openvpn_plugin_handle_t; + /* + * We are compiling OpenVPN. + */ +-#define OPENVPN_PLUGIN_DEF typedef ++// #define OPENVPN_PLUGIN_DEF typedef + #define OPENVPN_PLUGIN_FUNC(name) (*name) + + #else diff --git a/dev-tools/special-files.lst b/dev-tools/special-files.lst new file mode 100644 index 00000000000..f3f77ea3b3b --- /dev/null +++ b/dev-tools/special-files.lst @@ -0,0 +1,4 @@ +E:doc/doxygen/doc_key_generation.h # @verbatim section gets mistreated, exclude it +E:src/compat/compat-lz4.c # Preserve LZ4 upstream formatting +E:src/compat/compat-lz4.h # Preserve LZ4 upstream formatting +P:include/openvpn-plugin.h.in # uncrustify segfaults, patch it before+after diff --git a/dev-tools/uncrustify.conf b/dev-tools/uncrustify.conf new file mode 100644 index 00000000000..95e0b2a1444 --- /dev/null +++ b/dev-tools/uncrustify.conf @@ -0,0 +1,65 @@ +# Use Allman-style +indent_columns=4 +indent_braces=false +indent_else_if=false +indent_switch_case=4 +indent_label=1 +nl_if_brace=add +nl_brace_else=add +nl_elseif_brace=add +nl_else_brace=add +nl_else_if=remove +sp_func_proto_paren=Remove +sp_func_def_paren=Remove +sp_func_call_paren=Remove +sp_sizeof_paren=Remove + +# No tabs, spaces only +indent_with_tabs=0 +align_with_tabs=false +cmt_convert_tab_to_spaces=true + +# Do not put spaces between the # and preprocessor statements +pp_space=remove + +# Various whitespace fiddling +sp_assign=add +sp_before_sparen=add +sp_inside_sparen=remove +sp_cond_colon=add +sp_cond_question=add +sp_bool=add +sp_else_brace=add +sp_brace_else=add +pos_arith=Lead +pos_bool=Lead +nl_func_type_name=add +nl_before_case=true +nl_assign_leave_one_liners=true +nl_enum_leave_one_liners=true +nl_brace_fparen=add +nl_max=4 +nl_after_func_proto=2 + +# Always use scoping braces for conditionals +mod_full_brace_if=add +mod_full_brace_if_chain=false + +# Annotate #else and #endif statements +mod_add_long_ifdef_endif_comment=20 +mod_add_long_ifdef_else_comment=5 + +# Misc cleanup +mod_remove_extra_semicolon=true + +# Use C-style comments (/* .. */) +cmt_c_nl_end=true +cmt_star_cont=true +cmt_cpp_to_c=true + +# Use "char **a"-style pointer stars/dereferences +sp_before_ptr_star=Add +sp_between_ptr_star=Remove +sp_after_ptr_star=Remove +sp_before_byref=Add +sp_after_byref=Remove From 81d882d5302b8b647202a6893b57dfdc61fd6df2 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Wed, 14 Dec 2016 22:33:21 +0100 Subject: [PATCH 446/643] The Great Reformatting - first phase This is the first commit of the big reformatting task. This is performed by running the ./dev-tools/reformat-all.sh script. This is based upon the v3 reformat-all.sh/uncrustify.conf version which is now applied to git master. Signed-off-by: David Sommerseth --- config-msvc.h | 18 +- contrib/keychain-mcd/cert_data.c | 1057 +- contrib/keychain-mcd/cert_data.h | 15 +- contrib/keychain-mcd/common_osx.c | 87 +- contrib/keychain-mcd/common_osx.h | 7 +- contrib/keychain-mcd/crypto_osx.c | 57 +- contrib/keychain-mcd/crypto_osx.h | 19 +- contrib/keychain-mcd/main.c | 98 +- include/openvpn-msg.h | 108 +- include/openvpn-plugin.h.in | 182 +- sample/sample-plugins/defer/simple.c | 391 +- .../keyingmaterialexporter.c | 287 +- sample/sample-plugins/log/log.c | 232 +- sample/sample-plugins/log/log_v3.c | 367 +- sample/sample-plugins/simple/simple.c | 100 +- src/compat/compat-basename.c | 15 +- src/compat/compat-daemon.c | 79 +- src/compat/compat-dirname.c | 151 +- src/compat/compat-gettimeofday.c | 96 +- src/compat/compat-inet_ntop.c | 42 +- src/compat/compat-inet_pton.c | 42 +- src/compat/compat-versionhelpers.h | 51 +- src/compat/compat.h | 14 +- src/openvpn/argv.c | 368 +- src/openvpn/argv.h | 44 +- src/openvpn/base64.c | 144 +- src/openvpn/base64.h | 11 +- src/openvpn/block_dns.c | 378 +- src/openvpn/block_dns.h | 6 +- src/openvpn/buffer.c | 1449 +- src/openvpn/buffer.h | 915 +- src/openvpn/circ_list.h | 62 +- src/openvpn/clinat.c | 318 +- src/openvpn/clinat.h | 45 +- src/openvpn/common.h | 18 +- src/openvpn/comp-lz4.c | 344 +- src/openvpn/comp-lz4.h | 2 +- src/openvpn/comp.c | 134 +- src/openvpn/comp.h | 75 +- src/openvpn/compstub.c | 177 +- src/openvpn/console.c | 21 +- src/openvpn/console.h | 24 +- src/openvpn/console_builtin.c | 145 +- src/openvpn/console_systemd.c | 50 +- src/openvpn/crypto.c | 2556 ++-- src/openvpn/crypto.h | 234 +- src/openvpn/crypto_backend.h | 359 +- src/openvpn/crypto_mbedtls.c | 762 +- src/openvpn/crypto_mbedtls.h | 55 +- src/openvpn/crypto_openssl.c | 840 +- src/openvpn/crypto_openssl.h | 34 +- src/openvpn/cryptoapi.c | 479 +- src/openvpn/dhcp.c | 319 +- src/openvpn/dhcp.h | 48 +- src/openvpn/errlevel.h | 2 +- src/openvpn/error.c | 1216 +- src/openvpn/error.h | 213 +- src/openvpn/event.c | 1501 +- src/openvpn/event.h | 86 +- src/openvpn/fdmisc.c | 46 +- src/openvpn/fdmisc.h | 17 +- src/openvpn/forward-inline.h | 260 +- src/openvpn/forward.c | 2244 +-- src/openvpn/forward.h | 38 +- src/openvpn/fragment.c | 564 +- src/openvpn/fragment.h | 162 +- src/openvpn/gremlin.c | 202 +- src/openvpn/gremlin.h | 16 +- src/openvpn/helper.c | 820 +- src/openvpn/helper.h | 8 +- src/openvpn/httpdigest.c | 194 +- src/openvpn/httpdigest.h | 26 +- src/openvpn/init.c | 5370 +++---- src/openvpn/init.h | 111 +- src/openvpn/integer.h | 100 +- src/openvpn/interval.c | 64 +- src/openvpn/interval.h | 149 +- src/openvpn/list.c | 922 +- src/openvpn/list.h | 185 +- src/openvpn/lladdr.c | 87 +- src/openvpn/lladdr.h | 4 +- src/openvpn/lzo.c | 309 +- src/openvpn/lzo.h | 54 +- src/openvpn/manage.c | 5267 ++++--- src/openvpn/manage.h | 523 +- src/openvpn/mbuf.c | 178 +- src/openvpn/mbuf.h | 71 +- src/openvpn/memdbg.h | 2 +- src/openvpn/misc.c | 2220 +-- src/openvpn/misc.h | 248 +- src/openvpn/mroute.c | 684 +- src/openvpn/mroute.h | 224 +- src/openvpn/mss.c | 229 +- src/openvpn/mss.h | 8 +- src/openvpn/mstats.c | 94 +- src/openvpn/mstats.h | 19 +- src/openvpn/mtcp.c | 1151 +- src/openvpn/mtcp.h | 35 +- src/openvpn/mtu.c | 409 +- src/openvpn/mtu.h | 120 +- src/openvpn/mudp.c | 446 +- src/openvpn/mudp.h | 4 +- src/openvpn/multi.c | 4811 +++--- src/openvpn/multi.h | 443 +- src/openvpn/ntlm.c | 542 +- src/openvpn/ntlm.h | 5 +- src/openvpn/occ-inline.h | 61 +- src/openvpn/occ.c | 632 +- src/openvpn/occ.h | 32 +- src/openvpn/openvpn.c | 382 +- src/openvpn/openvpn.h | 616 +- src/openvpn/options.c | 12214 ++++++++-------- src/openvpn/options.h | 954 +- src/openvpn/otime.c | 166 +- src/openvpn/otime.h | 275 +- src/openvpn/packet_id.c | 858 +- src/openvpn/packet_id.h | 168 +- src/openvpn/perf.c | 356 +- src/openvpn/perf.h | 26 +- src/openvpn/pf-inline.h | 31 +- src/openvpn/pf.c | 1077 +- src/openvpn/pf.h | 61 +- src/openvpn/ping-inline.h | 40 +- src/openvpn/ping.c | 70 +- src/openvpn/ping.h | 4 +- src/openvpn/pkcs11.c | 1666 ++- src/openvpn/pkcs11.h | 56 +- src/openvpn/pkcs11_backend.h | 28 +- src/openvpn/pkcs11_mbedtls.c | 119 +- src/openvpn/pkcs11_openssl.c | 169 +- src/openvpn/platform.c | 270 +- src/openvpn/platform.h | 73 +- src/openvpn/plugin.c | 1213 +- src/openvpn/plugin.h | 178 +- src/openvpn/pool.c | 782 +- src/openvpn/pool.h | 58 +- src/openvpn/proto.c | 158 +- src/openvpn/proto.h | 261 +- src/openvpn/proxy.c | 1511 +- src/openvpn/proxy.h | 77 +- src/openvpn/ps.c | 1328 +- src/openvpn/ps.h | 29 +- src/openvpn/push.c | 1137 +- src/openvpn/push.h | 42 +- src/openvpn/pushlist.h | 10 +- src/openvpn/reliable.c | 952 +- src/openvpn/reliable.h | 96 +- src/openvpn/route.c | 5417 +++---- src/openvpn/route.h | 434 +- src/openvpn/schedule.c | 844 +- src/openvpn/schedule.h | 77 +- src/openvpn/session_id.c | 14 +- src/openvpn/session_id.h | 30 +- src/openvpn/shaper.c | 84 +- src/openvpn/shaper.h | 97 +- src/openvpn/sig.c | 452 +- src/openvpn/sig.h | 70 +- src/openvpn/socket.c | 5363 +++---- src/openvpn/socket.h | 1226 +- src/openvpn/socks.c | 847 +- src/openvpn/socks.h | 48 +- src/openvpn/ssl.c | 5466 +++---- src/openvpn/ssl.h | 161 +- src/openvpn/ssl_backend.h | 210 +- src/openvpn/ssl_common.h | 462 +- src/openvpn/ssl_mbedtls.c | 1500 +- src/openvpn/ssl_mbedtls.h | 22 +- src/openvpn/ssl_openssl.c | 2176 +-- src/openvpn/ssl_openssl.h | 12 +- src/openvpn/ssl_verify.c | 1783 +-- src/openvpn/ssl_verify.h | 96 +- src/openvpn/ssl_verify_backend.h | 164 +- src/openvpn/ssl_verify_mbedtls.c | 639 +- src/openvpn/ssl_verify_mbedtls.h | 4 +- src/openvpn/ssl_verify_openssl.c | 932 +- src/openvpn/ssl_verify_openssl.h | 2 +- src/openvpn/status.c | 399 +- src/openvpn/status.h | 83 +- src/openvpn/syshead.h | 50 +- src/openvpn/tls_crypt.c | 337 +- src/openvpn/tls_crypt.h | 42 +- src/openvpn/tun.c | 9027 ++++++------ src/openvpn/tun.h | 506 +- src/openvpn/win32.c | 1620 +- src/openvpn/win32.h | 225 +- src/openvpnserv/automatic.c | 518 +- src/openvpnserv/common.c | 320 +- src/openvpnserv/interactive.c | 2350 +-- src/openvpnserv/service.c | 340 +- src/openvpnserv/service.h | 53 +- src/openvpnserv/validate.c | 124 +- src/openvpnserv/validate.h | 10 +- src/plugins/auth-pam/auth-pam.c | 1026 +- src/plugins/auth-pam/pamdl.c | 113 +- src/plugins/auth-pam/pamdl.h | 6 +- src/plugins/auth-pam/utils.c | 100 +- src/plugins/auth-pam/utils.h | 4 +- src/plugins/down-root/down-root.c | 258 +- tests/unit_tests/example_test/test.c | 40 +- tests/unit_tests/example_test/test2.c | 6 +- tests/unit_tests/openvpn/mock_msg.c | 57 +- tests/unit_tests/openvpn/test_argv.c | 204 +- tests/unit_tests/openvpn/test_tls_crypt.c | 204 +- .../auth-pam/test_search_and_replace.c | 71 +- 204 files changed, 64778 insertions(+), 56817 deletions(-) diff --git a/config-msvc.h b/config-msvc.h index 9c8d4237aa1..3e71c854077 100644 --- a/config-msvc.h +++ b/config-msvc.h @@ -118,20 +118,20 @@ #define SIGUSR2 12 #define SIGTERM 15 -typedef unsigned __int64 uint64_t; -typedef unsigned __int32 uint32_t; -typedef unsigned __int16 uint16_t; -typedef unsigned __int8 uint8_t; -typedef __int64 int64_t; -typedef __int32 int32_t; -typedef __int16 int16_t; -typedef __int8 int8_t; +typedef unsigned __int64 uint64_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int16 uint16_t; +typedef unsigned __int8 uint8_t; +typedef __int64 int64_t; +typedef __int32 int32_t; +typedef __int16 int16_t; +typedef __int8 int8_t; #ifdef HAVE_CONFIG_MSVC_LOCAL_H #include #endif -// Vista and above has implementation of inet_ntop / inet_pton +/* Vista and above has implementation of inet_ntop / inet_pton */ #if _WIN32_WINNT >= _WIN32_WINNT_VISTA #define HAVE_INET_NTOP #define HAVE_INET_PTON diff --git a/contrib/keychain-mcd/cert_data.c b/contrib/keychain-mcd/cert_data.c index a04bf79c307..b84f3fc3102 100644 --- a/contrib/keychain-mcd/cert_data.c +++ b/contrib/keychain-mcd/cert_data.c @@ -51,684 +51,817 @@ CFStringRef kStringSpace = CFSTR(" "), typedef struct _CertName { - CFArrayRef countryName, organization, organizationalUnit, commonName, description, emailAddress, - stateName, localityName; + CFArrayRef countryName, organization, organizationalUnit, commonName, description, emailAddress, + stateName, localityName; } CertName, *CertNameRef; typedef struct _DescData { - CFStringRef name, value; + CFStringRef name, value; } DescData, *DescDataRef; void destroyDescData(DescDataRef pData); -CertNameRef createCertName() +CertNameRef +createCertName() { - CertNameRef pCertName = (CertNameRef)malloc(sizeof(CertName)); - pCertName->countryName = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - pCertName->organization = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - pCertName->organizationalUnit = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - pCertName->commonName = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - pCertName->description = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - pCertName->emailAddress = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - pCertName->stateName = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - pCertName->localityName = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - return pCertName; + CertNameRef pCertName = (CertNameRef)malloc(sizeof(CertName)); + pCertName->countryName = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + pCertName->organization = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + pCertName->organizationalUnit = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + pCertName->commonName = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + pCertName->description = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + pCertName->emailAddress = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + pCertName->stateName = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + pCertName->localityName = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + return pCertName; } -void destroyCertName(CertNameRef pCertName) +void +destroyCertName(CertNameRef pCertName) { - if (!pCertName) - return; - - CFRelease(pCertName->countryName); - CFRelease(pCertName->organization); - CFRelease(pCertName->organizationalUnit); - CFRelease(pCertName->commonName); - CFRelease(pCertName->description); - CFRelease(pCertName->emailAddress); - CFRelease(pCertName->stateName); - CFRelease(pCertName->localityName); - free(pCertName); + if (!pCertName) + { + return; + } + + CFRelease(pCertName->countryName); + CFRelease(pCertName->organization); + CFRelease(pCertName->organizationalUnit); + CFRelease(pCertName->commonName); + CFRelease(pCertName->description); + CFRelease(pCertName->emailAddress); + CFRelease(pCertName->stateName); + CFRelease(pCertName->localityName); + free(pCertName); } -bool CFStringRefCmpCString(CFStringRef cfstr, const char *str) +bool +CFStringRefCmpCString(CFStringRef cfstr, const char *str) { - CFStringRef tmp = CFStringCreateWithCStringNoCopy(NULL, str, kCFStringEncodingUTF8, kCFAllocatorNull); - CFComparisonResult cresult = CFStringCompare(cfstr, tmp, 0); - bool result = cresult == kCFCompareEqualTo; - CFRelease(tmp); - return result; + CFStringRef tmp = CFStringCreateWithCStringNoCopy(NULL, str, kCFStringEncodingUTF8, kCFAllocatorNull); + CFComparisonResult cresult = CFStringCompare(cfstr, tmp, 0); + bool result = cresult == kCFCompareEqualTo; + CFRelease(tmp); + return result; } -CFDateRef GetDateFieldFromCertificate(SecCertificateRef certificate, CFTypeRef oid) +CFDateRef +GetDateFieldFromCertificate(SecCertificateRef certificate, CFTypeRef oid) { - const void *keys[] = { oid }; - CFDictionaryRef dict = NULL; - CFErrorRef error; - CFDateRef date = NULL; - - CFArrayRef keySelection = CFArrayCreate(NULL, keys , sizeof(keys)/sizeof(keys[0]), &kCFTypeArrayCallBacks); - dict = SecCertificateCopyValues(certificate, keySelection, &error); - if (dict == NULL) + const void *keys[] = { oid }; + CFDictionaryRef dict = NULL; + CFErrorRef error; + CFDateRef date = NULL; + + CFArrayRef keySelection = CFArrayCreate(NULL, keys, sizeof(keys)/sizeof(keys[0]), &kCFTypeArrayCallBacks); + dict = SecCertificateCopyValues(certificate, keySelection, &error); + if (dict == NULL) + { + printErrorMsg("GetDateFieldFromCertificate: SecCertificateCopyValues", error); + goto release_ks; + } + CFDictionaryRef vals = dict ? CFDictionaryGetValue(dict, oid) : NULL; + CFNumberRef vals2 = vals ? CFDictionaryGetValue(vals, kSecPropertyKeyValue) : NULL; + if (vals2 == NULL) { - printErrorMsg("GetDateFieldFromCertificate: SecCertificateCopyValues", error); - goto release_ks; + goto release_dict; } - CFDictionaryRef vals = dict ? CFDictionaryGetValue(dict, oid) : NULL; - CFNumberRef vals2 = vals ? CFDictionaryGetValue(vals, kSecPropertyKeyValue) : NULL; - if (vals2 == NULL) - goto release_dict; - CFAbsoluteTime validityNotBefore; - if (CFNumberGetValue(vals2, kCFNumberDoubleType, &validityNotBefore)) - date = CFDateCreate(kCFAllocatorDefault,validityNotBefore); + CFAbsoluteTime validityNotBefore; + if (CFNumberGetValue(vals2, kCFNumberDoubleType, &validityNotBefore)) + { + date = CFDateCreate(kCFAllocatorDefault,validityNotBefore); + } release_dict: - CFRelease(dict); + CFRelease(dict); release_ks: - CFRelease(keySelection); - return date; + CFRelease(keySelection); + return date; } -CFArrayRef GetFieldsFromCertificate(SecCertificateRef certificate, CFTypeRef oid) +CFArrayRef +GetFieldsFromCertificate(SecCertificateRef certificate, CFTypeRef oid) { - CFMutableArrayRef fields = CFArrayCreateMutable(NULL, 0, NULL); - CertNameRef pCertName = createCertName(); - const void* keys[] = { oid, }; - CFDictionaryRef dict; - CFErrorRef error; - - CFArrayRef keySelection = CFArrayCreate(NULL, keys , 1, NULL); - - dict = SecCertificateCopyValues(certificate, keySelection, &error); - if (dict == NULL) { - printErrorMsg("GetFieldsFromCertificate: SecCertificateCopyValues", error); - CFRelease(keySelection); - CFRelease(fields); - destroyCertName(pCertName); - return NULL; - } - CFDictionaryRef vals = CFDictionaryGetValue(dict, oid); - CFArrayRef vals2 = vals ? CFDictionaryGetValue(vals, kSecPropertyKeyValue) : NULL; - if (vals2) - { - for(int i = 0; i < CFArrayGetCount(vals2); i++) { - CFDictionaryRef subDict = CFArrayGetValueAtIndex(vals2, i); - CFStringRef label = CFDictionaryGetValue(subDict, kSecPropertyKeyLabel); - CFStringRef value = CFDictionaryGetValue(subDict, kSecPropertyKeyValue); - - if (CFStringCompare(label, kSecOIDEmailAddress, 0) == kCFCompareEqualTo) - CFArrayAppendValue((CFMutableArrayRef)pCertName->emailAddress, value); - else if (CFStringCompare(label, kSecOIDCountryName, 0) == kCFCompareEqualTo) - CFArrayAppendValue((CFMutableArrayRef)pCertName->countryName, value); - else if (CFStringCompare(label, kSecOIDOrganizationName, 0) == kCFCompareEqualTo) - CFArrayAppendValue((CFMutableArrayRef)pCertName->organization, value); - else if (CFStringCompare(label, kSecOIDOrganizationalUnitName, 0) == kCFCompareEqualTo) - CFArrayAppendValue((CFMutableArrayRef)pCertName->organizationalUnit, value); - else if (CFStringCompare(label, kSecOIDCommonName, 0) == kCFCompareEqualTo) - CFArrayAppendValue((CFMutableArrayRef)pCertName->commonName, value); - else if (CFStringCompare(label, kSecOIDDescription, 0) == kCFCompareEqualTo) - CFArrayAppendValue((CFMutableArrayRef)pCertName->description, value); - else if (CFStringCompare(label, kSecOIDStateProvinceName, 0) == kCFCompareEqualTo) - CFArrayAppendValue((CFMutableArrayRef)pCertName->stateName, value); - else if (CFStringCompare(label, kSecOIDLocalityName, 0) == kCFCompareEqualTo) - CFArrayAppendValue((CFMutableArrayRef)pCertName->localityName, value); - } - CFArrayAppendValue(fields, pCertName); - } - - CFRelease(dict); - CFRelease(keySelection); - return fields; + CFMutableArrayRef fields = CFArrayCreateMutable(NULL, 0, NULL); + CertNameRef pCertName = createCertName(); + const void *keys[] = { oid, }; + CFDictionaryRef dict; + CFErrorRef error; + + CFArrayRef keySelection = CFArrayCreate(NULL, keys, 1, NULL); + + dict = SecCertificateCopyValues(certificate, keySelection, &error); + if (dict == NULL) + { + printErrorMsg("GetFieldsFromCertificate: SecCertificateCopyValues", error); + CFRelease(keySelection); + CFRelease(fields); + destroyCertName(pCertName); + return NULL; + } + CFDictionaryRef vals = CFDictionaryGetValue(dict, oid); + CFArrayRef vals2 = vals ? CFDictionaryGetValue(vals, kSecPropertyKeyValue) : NULL; + if (vals2) + { + for (int i = 0; i < CFArrayGetCount(vals2); i++) { + CFDictionaryRef subDict = CFArrayGetValueAtIndex(vals2, i); + CFStringRef label = CFDictionaryGetValue(subDict, kSecPropertyKeyLabel); + CFStringRef value = CFDictionaryGetValue(subDict, kSecPropertyKeyValue); + + if (CFStringCompare(label, kSecOIDEmailAddress, 0) == kCFCompareEqualTo) + { + CFArrayAppendValue((CFMutableArrayRef)pCertName->emailAddress, value); + } + else if (CFStringCompare(label, kSecOIDCountryName, 0) == kCFCompareEqualTo) + { + CFArrayAppendValue((CFMutableArrayRef)pCertName->countryName, value); + } + else if (CFStringCompare(label, kSecOIDOrganizationName, 0) == kCFCompareEqualTo) + { + CFArrayAppendValue((CFMutableArrayRef)pCertName->organization, value); + } + else if (CFStringCompare(label, kSecOIDOrganizationalUnitName, 0) == kCFCompareEqualTo) + { + CFArrayAppendValue((CFMutableArrayRef)pCertName->organizationalUnit, value); + } + else if (CFStringCompare(label, kSecOIDCommonName, 0) == kCFCompareEqualTo) + { + CFArrayAppendValue((CFMutableArrayRef)pCertName->commonName, value); + } + else if (CFStringCompare(label, kSecOIDDescription, 0) == kCFCompareEqualTo) + { + CFArrayAppendValue((CFMutableArrayRef)pCertName->description, value); + } + else if (CFStringCompare(label, kSecOIDStateProvinceName, 0) == kCFCompareEqualTo) + { + CFArrayAppendValue((CFMutableArrayRef)pCertName->stateName, value); + } + else if (CFStringCompare(label, kSecOIDLocalityName, 0) == kCFCompareEqualTo) + { + CFArrayAppendValue((CFMutableArrayRef)pCertName->localityName, value); + } + } + CFArrayAppendValue(fields, pCertName); + } + + CFRelease(dict); + CFRelease(keySelection); + return fields; } -CertDataRef createCertDataFromCertificate(SecCertificateRef certificate) +CertDataRef +createCertDataFromCertificate(SecCertificateRef certificate) { - CertDataRef pCertData = (CertDataRef)malloc(sizeof(CertData)); - pCertData->subject = GetFieldsFromCertificate(certificate, kSecOIDX509V1SubjectName); - pCertData->issuer = GetFieldsFromCertificate(certificate, kSecOIDX509V1IssuerName); + CertDataRef pCertData = (CertDataRef)malloc(sizeof(CertData)); + pCertData->subject = GetFieldsFromCertificate(certificate, kSecOIDX509V1SubjectName); + pCertData->issuer = GetFieldsFromCertificate(certificate, kSecOIDX509V1IssuerName); - CFDataRef data = SecCertificateCopyData(certificate); - if (data == NULL) + CFDataRef data = SecCertificateCopyData(certificate); + if (data == NULL) { - warnx("SecCertificateCopyData() returned NULL"); - destroyCertData(pCertData); - return NULL; + warnx("SecCertificateCopyData() returned NULL"); + destroyCertData(pCertData); + return NULL; } - unsigned char sha1[CC_SHA1_DIGEST_LENGTH]; - CC_SHA1(CFDataGetBytePtr(data), CFDataGetLength(data), sha1); - pCertData->sha1 = createHexString(sha1, CC_SHA1_DIGEST_LENGTH); + unsigned char sha1[CC_SHA1_DIGEST_LENGTH]; + CC_SHA1(CFDataGetBytePtr(data), CFDataGetLength(data), sha1); + pCertData->sha1 = createHexString(sha1, CC_SHA1_DIGEST_LENGTH); - unsigned char md5[CC_MD5_DIGEST_LENGTH]; - CC_MD5(CFDataGetBytePtr(data), CFDataGetLength(data), md5); - pCertData->md5 = createHexString((unsigned char*)md5, CC_MD5_DIGEST_LENGTH); + unsigned char md5[CC_MD5_DIGEST_LENGTH]; + CC_MD5(CFDataGetBytePtr(data), CFDataGetLength(data), md5); + pCertData->md5 = createHexString((unsigned char *)md5, CC_MD5_DIGEST_LENGTH); - CFDataRef serial = SecCertificateCopySerialNumber(certificate, NULL); - pCertData->serial = createHexString((unsigned char *)CFDataGetBytePtr(serial), CFDataGetLength(serial)); - CFRelease(serial); + CFDataRef serial = SecCertificateCopySerialNumber(certificate, NULL); + pCertData->serial = createHexString((unsigned char *)CFDataGetBytePtr(serial), CFDataGetLength(serial)); + CFRelease(serial); - return pCertData; + return pCertData; } -CFStringRef stringFromRange(const char *cstring, CFRange range) +CFStringRef +stringFromRange(const char *cstring, CFRange range) { - CFStringRef str = CFStringCreateWithBytes (NULL, (uint8*)&cstring[range.location], range.length, kCFStringEncodingUTF8, false); - CFMutableStringRef mutableStr = CFStringCreateMutableCopy(NULL, 0, str); - CFStringTrimWhitespace(mutableStr); - CFRelease(str); - return mutableStr; + CFStringRef str = CFStringCreateWithBytes(NULL, (uint8 *)&cstring[range.location], range.length, kCFStringEncodingUTF8, false); + CFMutableStringRef mutableStr = CFStringCreateMutableCopy(NULL, 0, str); + CFStringTrimWhitespace(mutableStr); + CFRelease(str); + return mutableStr; } -DescDataRef createDescData(const char *description, CFRange nameRange, CFRange valueRange) +DescDataRef +createDescData(const char *description, CFRange nameRange, CFRange valueRange) { - DescDataRef pRetVal = (DescDataRef)malloc(sizeof(DescData)); + DescDataRef pRetVal = (DescDataRef)malloc(sizeof(DescData)); - memset(pRetVal, 0, sizeof(DescData)); + memset(pRetVal, 0, sizeof(DescData)); - if (nameRange.length > 0) - pRetVal->name = stringFromRange(description, nameRange); + if (nameRange.length > 0) + { + pRetVal->name = stringFromRange(description, nameRange); + } - if (valueRange.length > 0) - pRetVal->value = stringFromRange(description, valueRange); + if (valueRange.length > 0) + { + pRetVal->value = stringFromRange(description, valueRange); + } #if 0 - fprintf(stderr, "name = '%s', value = '%s'\n", - CFStringGetCStringPtr(pRetVal->name, kCFStringEncodingUTF8), - CFStringGetCStringPtr(pRetVal->value, kCFStringEncodingUTF8)); + fprintf(stderr, "name = '%s', value = '%s'\n", + CFStringGetCStringPtr(pRetVal->name, kCFStringEncodingUTF8), + CFStringGetCStringPtr(pRetVal->value, kCFStringEncodingUTF8)); #endif - return pRetVal; + return pRetVal; } -void destroyDescData(DescDataRef pData) +void +destroyDescData(DescDataRef pData) { - if (pData->name) - CFRelease(pData->name); + if (pData->name) + { + CFRelease(pData->name); + } - if (pData->value) - CFRelease(pData->value); + if (pData->value) + { + CFRelease(pData->value); + } - free(pData); + free(pData); } -CFArrayRef createDescDataPairs(const char *description) +CFArrayRef +createDescDataPairs(const char *description) { - int numChars = strlen(description); - CFRange nameRange, valueRange; - DescDataRef pData; - CFMutableArrayRef retVal = CFArrayCreateMutable(NULL, 0, NULL); + int numChars = strlen(description); + CFRange nameRange, valueRange; + DescDataRef pData; + CFMutableArrayRef retVal = CFArrayCreateMutable(NULL, 0, NULL); - int i = 0; + int i = 0; - nameRange = CFRangeMake(0, 0); - valueRange = CFRangeMake(0, 0); - bool bInValue = false; + nameRange = CFRangeMake(0, 0); + valueRange = CFRangeMake(0, 0); + bool bInValue = false; - while(i < numChars) + while (i < numChars) { - if (!bInValue && (description[i] != ':')) + if (!bInValue && (description[i] != ':')) { - nameRange.length++; + nameRange.length++; } - else if (bInValue && (description[i] != ':')) + else if (bInValue && (description[i] != ':')) { - valueRange.length++; + valueRange.length++; } - else if(!bInValue) + else if (!bInValue) { - bInValue = true; - valueRange.location = i + 1; - valueRange.length = 0; + bInValue = true; + valueRange.location = i + 1; + valueRange.length = 0; } - else //(bInValue) + else /*(bInValue) */ { - bInValue = false; - while(description[i] != ' ') + bInValue = false; + while (description[i] != ' ') { - valueRange.length--; - i--; + valueRange.length--; + i--; } - pData = createDescData(description, nameRange, valueRange); - CFArrayAppendValue(retVal, pData); + pData = createDescData(description, nameRange, valueRange); + CFArrayAppendValue(retVal, pData); - nameRange.location = i + 1; - nameRange.length = 0; + nameRange.location = i + 1; + nameRange.length = 0; } - i++; + i++; } - pData = createDescData(description, nameRange, valueRange); - CFArrayAppendValue(retVal, pData); - return retVal; + pData = createDescData(description, nameRange, valueRange); + CFArrayAppendValue(retVal, pData); + return retVal; } -void arrayDestroyDescData(const void *val, void *context) +void +arrayDestroyDescData(const void *val, void *context) { - DescDataRef pData = (DescDataRef) val; - destroyDescData(pData); + DescDataRef pData = (DescDataRef) val; + destroyDescData(pData); } -int parseNameComponent(CFStringRef dn, CFStringRef *pName, CFStringRef *pValue) +int +parseNameComponent(CFStringRef dn, CFStringRef *pName, CFStringRef *pValue) { - CFArrayRef nameStrings = CFStringCreateArrayBySeparatingStrings(NULL, dn, kCertNameEquals); + CFArrayRef nameStrings = CFStringCreateArrayBySeparatingStrings(NULL, dn, kCertNameEquals); - *pName = *pValue = NULL; + *pName = *pValue = NULL; - if (CFArrayGetCount(nameStrings) != 2) - return 0; + if (CFArrayGetCount(nameStrings) != 2) + { + return 0; + } - CFMutableStringRef str; + CFMutableStringRef str; - str = CFStringCreateMutableCopy(NULL, 0, CFArrayGetValueAtIndex(nameStrings, 0)); - CFStringTrimWhitespace(str); - *pName = str; + str = CFStringCreateMutableCopy(NULL, 0, CFArrayGetValueAtIndex(nameStrings, 0)); + CFStringTrimWhitespace(str); + *pName = str; - str = CFStringCreateMutableCopy(NULL, 0, CFArrayGetValueAtIndex(nameStrings, 1)); - CFStringTrimWhitespace(str); - *pValue = str; + str = CFStringCreateMutableCopy(NULL, 0, CFArrayGetValueAtIndex(nameStrings, 1)); + CFStringTrimWhitespace(str); + *pValue = str; - CFRelease(nameStrings); - return 1; + CFRelease(nameStrings); + return 1; } -int tryAppendSingleCertField(CertNameRef pCertName, CFArrayRef where, CFStringRef key, - CFStringRef name, CFStringRef value) +int +tryAppendSingleCertField(CertNameRef pCertName, CFArrayRef where, CFStringRef key, + CFStringRef name, CFStringRef value) { - if (CFStringCompareWithOptions(name, key, CFRangeMake(0, CFStringGetLength(name)), kCFCompareCaseInsensitive) - == kCFCompareEqualTo) { - CFArrayAppendValue((CFMutableArrayRef)where, value); - return 1; - } - return 0; + if (CFStringCompareWithOptions(name, key, CFRangeMake(0, CFStringGetLength(name)), kCFCompareCaseInsensitive) + == kCFCompareEqualTo) + { + CFArrayAppendValue((CFMutableArrayRef)where, value); + return 1; + } + return 0; } -int appendCertField(CertNameRef pCert, CFStringRef name, CFStringRef value) +int +appendCertField(CertNameRef pCert, CFStringRef name, CFStringRef value) { - struct { - CFArrayRef field; - CFStringRef key; - } fields[] = { - { pCert->organization, kCertNameOrganization}, - { pCert->organizationalUnit, kCertNameOrganizationalUnit}, - { pCert->countryName, kCertNameCountry}, - { pCert->localityName, kCertNameLocality}, - { pCert->stateName, kCertNameState}, - { pCert->commonName, kCertNameCommonName}, - { pCert->emailAddress, kCertNameEmail}, - }; - int i; - int ret = 0; - - for (i=0; iorganization, kCertNameOrganization}, + { pCert->organizationalUnit, kCertNameOrganizationalUnit}, + { pCert->countryName, kCertNameCountry}, + { pCert->localityName, kCertNameLocality}, + { pCert->stateName, kCertNameState}, + { pCert->commonName, kCertNameCommonName}, + { pCert->emailAddress, kCertNameEmail}, + }; + int i; + int ret = 0; + + for (i = 0; iname || !pDescData->value) - return 0; + if (!pDescData->name || !pDescData->value) + { + return 0; + } - if (CFStringCompareWithOptions(pDescData->name, kCertDataSubjectName, CFRangeMake(0, CFStringGetLength(pDescData->name)), kCFCompareCaseInsensitive) == kCFCompareEqualTo) - ret = parseCertName(pDescData->value, (CFMutableArrayRef)pCertData->subject); - else if (CFStringCompareWithOptions(pDescData->name, kCertDataIssuerName, CFRangeMake(0, CFStringGetLength(pDescData->name)), kCFCompareCaseInsensitive) == kCFCompareEqualTo) - ret = parseCertName(pDescData->value, (CFMutableArrayRef)pCertData->issuer); - else if (CFStringCompareWithOptions(pDescData->name, kCertDataSha1Name, CFRangeMake(0, CFStringGetLength(pDescData->name)), kCFCompareCaseInsensitive) == kCFCompareEqualTo) - pCertData->sha1 = CFRetain(pDescData->value); - else if (CFStringCompareWithOptions(pDescData->name, kCertDataMd5Name, CFRangeMake(0, CFStringGetLength(pDescData->name)), kCFCompareCaseInsensitive) == kCFCompareEqualTo) - pCertData->md5 = CFRetain(pDescData->value); - else if (CFStringCompareWithOptions(pDescData->name, kCertDataSerialName, CFRangeMake(0, CFStringGetLength(pDescData->name)), kCFCompareCaseInsensitive) == kCFCompareEqualTo) - pCertData->serial = CFRetain(pDescData->value); - else - return 0; + if (CFStringCompareWithOptions(pDescData->name, kCertDataSubjectName, CFRangeMake(0, CFStringGetLength(pDescData->name)), kCFCompareCaseInsensitive) == kCFCompareEqualTo) + { + ret = parseCertName(pDescData->value, (CFMutableArrayRef)pCertData->subject); + } + else if (CFStringCompareWithOptions(pDescData->name, kCertDataIssuerName, CFRangeMake(0, CFStringGetLength(pDescData->name)), kCFCompareCaseInsensitive) == kCFCompareEqualTo) + { + ret = parseCertName(pDescData->value, (CFMutableArrayRef)pCertData->issuer); + } + else if (CFStringCompareWithOptions(pDescData->name, kCertDataSha1Name, CFRangeMake(0, CFStringGetLength(pDescData->name)), kCFCompareCaseInsensitive) == kCFCompareEqualTo) + { + pCertData->sha1 = CFRetain(pDescData->value); + } + else if (CFStringCompareWithOptions(pDescData->name, kCertDataMd5Name, CFRangeMake(0, CFStringGetLength(pDescData->name)), kCFCompareCaseInsensitive) == kCFCompareEqualTo) + { + pCertData->md5 = CFRetain(pDescData->value); + } + else if (CFStringCompareWithOptions(pDescData->name, kCertDataSerialName, CFRangeMake(0, CFStringGetLength(pDescData->name)), kCFCompareCaseInsensitive) == kCFCompareEqualTo) + { + pCertData->serial = CFRetain(pDescData->value); + } + else + { + return 0; + } - return ret; + return ret; } -CertDataRef createCertDataFromString(const char *description) +CertDataRef +createCertDataFromString(const char *description) { - CertDataRef pCertData = (CertDataRef)malloc(sizeof(CertData)); - pCertData->subject = CFArrayCreateMutable(NULL, 0, NULL); - pCertData->issuer = CFArrayCreateMutable(NULL, 0, NULL); - pCertData->sha1 = NULL; - pCertData->md5 = NULL; - pCertData->serial = NULL; - - CFArrayRef pairs = createDescDataPairs(description); - for (int i=0; isubject = CFArrayCreateMutable(NULL, 0, NULL); + pCertData->issuer = CFArrayCreateMutable(NULL, 0, NULL); + pCertData->sha1 = NULL; + pCertData->md5 = NULL; + pCertData->serial = NULL; + + CFArrayRef pairs = createDescDataPairs(description); + for (int i = 0; isubject) + if (pCertData->subject) { - CFArrayApplyFunction(pCertData->subject, CFRangeMake(0, CFArrayGetCount(pCertData->subject)), arrayDestroyCertName, NULL); - CFRelease(pCertData->subject); + CFArrayApplyFunction(pCertData->subject, CFRangeMake(0, CFArrayGetCount(pCertData->subject)), arrayDestroyCertName, NULL); + CFRelease(pCertData->subject); } - if (pCertData->issuer) + if (pCertData->issuer) { - CFArrayApplyFunction(pCertData->issuer, CFRangeMake(0, CFArrayGetCount(pCertData->issuer)), arrayDestroyCertName, NULL); - CFRelease(pCertData->issuer); + CFArrayApplyFunction(pCertData->issuer, CFRangeMake(0, CFArrayGetCount(pCertData->issuer)), arrayDestroyCertName, NULL); + CFRelease(pCertData->issuer); } - if (pCertData->sha1) - CFRelease(pCertData->sha1); + if (pCertData->sha1) + { + CFRelease(pCertData->sha1); + } - if (pCertData->md5) - CFRelease(pCertData->md5); + if (pCertData->md5) + { + CFRelease(pCertData->md5); + } - if (pCertData->serial) - CFRelease(pCertData->serial); + if (pCertData->serial) + { + CFRelease(pCertData->serial); + } - free(pCertData); + free(pCertData); } -bool stringArrayMatchesTemplate(CFArrayRef strings, CFArrayRef templateArray) +bool +stringArrayMatchesTemplate(CFArrayRef strings, CFArrayRef templateArray) { - int templateCount, stringCount, i; + int templateCount, stringCount, i; - templateCount = CFArrayGetCount(templateArray); + templateCount = CFArrayGetCount(templateArray); - if (templateCount > 0) + if (templateCount > 0) { - stringCount = CFArrayGetCount(strings); - if (stringCount != templateCount) - return false; + stringCount = CFArrayGetCount(strings); + if (stringCount != templateCount) + { + return false; + } - for(i = 0;i < stringCount;i++) + for (i = 0; i < stringCount; i++) { - CFStringRef str, template; + CFStringRef str, template; - template = (CFStringRef)CFArrayGetValueAtIndex(templateArray, i); - str = (CFStringRef)CFArrayGetValueAtIndex(strings, i); + template = (CFStringRef)CFArrayGetValueAtIndex(templateArray, i); + str = (CFStringRef)CFArrayGetValueAtIndex(strings, i); - if (CFStringCompareWithOptions(template, str, CFRangeMake(0, CFStringGetLength(template)), kCFCompareCaseInsensitive) != kCFCompareEqualTo) - return false; + if (CFStringCompareWithOptions(template, str, CFRangeMake(0, CFStringGetLength(template)), kCFCompareCaseInsensitive) != kCFCompareEqualTo) + { + return false; + } } } - return true; + return true; } -bool certNameMatchesTemplate(CertNameRef pCertName, CertNameRef pTemplate) +bool +certNameMatchesTemplate(CertNameRef pCertName, CertNameRef pTemplate) { - if (!stringArrayMatchesTemplate(pCertName->countryName, pTemplate->countryName)) - return false; - else if (!stringArrayMatchesTemplate(pCertName->organization, pTemplate->organization)) - return false; - else if (!stringArrayMatchesTemplate(pCertName->organizationalUnit, pTemplate->organizationalUnit)) - return false; - else if (!stringArrayMatchesTemplate(pCertName->commonName, pTemplate->commonName)) - return false; - else if (!stringArrayMatchesTemplate(pCertName->emailAddress, pTemplate->emailAddress)) - return false; - else if (!stringArrayMatchesTemplate(pCertName->stateName, pTemplate->stateName)) - return false; - else if (!stringArrayMatchesTemplate(pCertName->localityName, pTemplate->localityName)) - return false; - else - return true; + if (!stringArrayMatchesTemplate(pCertName->countryName, pTemplate->countryName)) + { + return false; + } + else if (!stringArrayMatchesTemplate(pCertName->organization, pTemplate->organization)) + { + return false; + } + else if (!stringArrayMatchesTemplate(pCertName->organizationalUnit, pTemplate->organizationalUnit)) + { + return false; + } + else if (!stringArrayMatchesTemplate(pCertName->commonName, pTemplate->commonName)) + { + return false; + } + else if (!stringArrayMatchesTemplate(pCertName->emailAddress, pTemplate->emailAddress)) + { + return false; + } + else if (!stringArrayMatchesTemplate(pCertName->stateName, pTemplate->stateName)) + { + return false; + } + else if (!stringArrayMatchesTemplate(pCertName->localityName, pTemplate->localityName)) + { + return false; + } + else + { + return true; + } } -bool certNameArrayMatchesTemplate(CFArrayRef certNameArray, CFArrayRef templateArray) +bool +certNameArrayMatchesTemplate(CFArrayRef certNameArray, CFArrayRef templateArray) { - int templateCount, certCount, i; + int templateCount, certCount, i; - templateCount = CFArrayGetCount(templateArray); + templateCount = CFArrayGetCount(templateArray); - if (templateCount > 0) + if (templateCount > 0) { - certCount = CFArrayGetCount(certNameArray); - if (certCount != templateCount) - return false; + certCount = CFArrayGetCount(certNameArray); + if (certCount != templateCount) + { + return false; + } - for(i = 0;i < certCount;i++) + for (i = 0; i < certCount; i++) { - CertNameRef pName, pTemplateName; + CertNameRef pName, pTemplateName; - pTemplateName = (CertNameRef)CFArrayGetValueAtIndex(templateArray, i); - pName = (CertNameRef)CFArrayGetValueAtIndex(certNameArray, i); + pTemplateName = (CertNameRef)CFArrayGetValueAtIndex(templateArray, i); + pName = (CertNameRef)CFArrayGetValueAtIndex(certNameArray, i); - if (!certNameMatchesTemplate(pName, pTemplateName)) - return false; + if (!certNameMatchesTemplate(pName, pTemplateName)) + { + return false; + } } } - return true; + return true; } -bool hexStringMatchesTemplate(CFStringRef str, CFStringRef template) +bool +hexStringMatchesTemplate(CFStringRef str, CFStringRef template) { - if (template) + if (template) { - if (!str) - return false; + if (!str) + { + return false; + } - CFMutableStringRef strMutable, templateMutable; + CFMutableStringRef strMutable, templateMutable; - strMutable = CFStringCreateMutableCopy(NULL, 0, str); - templateMutable = CFStringCreateMutableCopy(NULL, 0, template); + strMutable = CFStringCreateMutableCopy(NULL, 0, str); + templateMutable = CFStringCreateMutableCopy(NULL, 0, template); - CFStringFindAndReplace(strMutable, kStringSpace, kStringEmpty, CFRangeMake(0, CFStringGetLength(strMutable)), 0); - CFStringFindAndReplace(templateMutable, kStringSpace, kStringEmpty, CFRangeMake(0, CFStringGetLength(templateMutable)), 0); + CFStringFindAndReplace(strMutable, kStringSpace, kStringEmpty, CFRangeMake(0, CFStringGetLength(strMutable)), 0); + CFStringFindAndReplace(templateMutable, kStringSpace, kStringEmpty, CFRangeMake(0, CFStringGetLength(templateMutable)), 0); - CFComparisonResult result = CFStringCompareWithOptions(templateMutable, strMutable, CFRangeMake(0, CFStringGetLength(templateMutable)), kCFCompareCaseInsensitive); + CFComparisonResult result = CFStringCompareWithOptions(templateMutable, strMutable, CFRangeMake(0, CFStringGetLength(templateMutable)), kCFCompareCaseInsensitive); - CFRelease(strMutable); - CFRelease(templateMutable); + CFRelease(strMutable); + CFRelease(templateMutable); - if (result != kCFCompareEqualTo) - return false; + if (result != kCFCompareEqualTo) + { + return false; + } } - return true; + return true; } -bool certDataMatchesTemplate(CertDataRef pCertData, CertDataRef pTemplate) +bool +certDataMatchesTemplate(CertDataRef pCertData, CertDataRef pTemplate) { - if (!certNameArrayMatchesTemplate(pCertData->subject, pTemplate->subject)) - return false; + if (!certNameArrayMatchesTemplate(pCertData->subject, pTemplate->subject)) + { + return false; + } - if (!certNameArrayMatchesTemplate(pCertData->issuer, pTemplate->issuer)) - return false; + if (!certNameArrayMatchesTemplate(pCertData->issuer, pTemplate->issuer)) + { + return false; + } - if (!hexStringMatchesTemplate(pCertData->sha1, pTemplate->sha1)) - return false; + if (!hexStringMatchesTemplate(pCertData->sha1, pTemplate->sha1)) + { + return false; + } - if (!hexStringMatchesTemplate(pCertData->md5, pTemplate->md5)) - return false; + if (!hexStringMatchesTemplate(pCertData->md5, pTemplate->md5)) + { + return false; + } - if (!hexStringMatchesTemplate(pCertData->serial, pTemplate->serial)) - return false; + if (!hexStringMatchesTemplate(pCertData->serial, pTemplate->serial)) + { + return false; + } - return true; + return true; } -bool certExpired(SecCertificateRef certificate) +bool +certExpired(SecCertificateRef certificate) { - bool result; - CFDateRef notAfter = GetDateFieldFromCertificate(certificate, kSecOIDX509V1ValidityNotAfter); - CFDateRef notBefore = GetDateFieldFromCertificate(certificate, kSecOIDX509V1ValidityNotBefore); - CFDateRef now = CFDateCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent()); + bool result; + CFDateRef notAfter = GetDateFieldFromCertificate(certificate, kSecOIDX509V1ValidityNotAfter); + CFDateRef notBefore = GetDateFieldFromCertificate(certificate, kSecOIDX509V1ValidityNotBefore); + CFDateRef now = CFDateCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent()); - if (!notAfter || !notBefore || !now) + if (!notAfter || !notBefore || !now) { - warnx("GetDateFieldFromCertificate() returned NULL"); - result = true; + warnx("GetDateFieldFromCertificate() returned NULL"); + result = true; } - else + else { - if (CFDateCompare(notBefore, now, NULL) != kCFCompareLessThan || - CFDateCompare(now, notAfter, NULL) != kCFCompareLessThan) - result = true; - else - result = false; + if (CFDateCompare(notBefore, now, NULL) != kCFCompareLessThan + || CFDateCompare(now, notAfter, NULL) != kCFCompareLessThan) + { + result = true; + } + else + { + result = false; + } } - CFRelease(notAfter); - CFRelease(notBefore); - CFRelease(now); - return result; + CFRelease(notAfter); + CFRelease(notBefore); + CFRelease(now); + return result; } -SecIdentityRef findIdentity(CertDataRef pCertDataTemplate) +SecIdentityRef +findIdentity(CertDataRef pCertDataTemplate) { - const void *keys[] = { - kSecClass, - kSecReturnRef, - kSecMatchLimit - }; - const void *values[] = { - kSecClassIdentity, - kCFBooleanTrue, - kSecMatchLimitAll - }; - CFArrayRef result = NULL; - - CFDictionaryRef query = CFDictionaryCreate(NULL, keys, values, - sizeof(keys) / sizeof(*keys), - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - OSStatus status = SecItemCopyMatching(query, (CFTypeRef*)&result); - CFRelease(query); - if (status != noErr) - { - warnx ("No identities in keychain found"); - return NULL; - } - - SecIdentityRef bestIdentity = NULL; - CFDateRef bestNotBeforeDate = NULL; - - for (int i=0; i -void printCFString(CFStringRef str) +void +printCFString(CFStringRef str) { - CFIndex bufferLength = CFStringGetLength(str) + 1; - char *pBuffer = (char*)malloc(sizeof(char) * bufferLength); - CFStringGetCString(str, pBuffer, bufferLength, kCFStringEncodingUTF8); - warnx("%s\n", pBuffer); - free(pBuffer); + CFIndex bufferLength = CFStringGetLength(str) + 1; + char *pBuffer = (char *)malloc(sizeof(char) * bufferLength); + CFStringGetCString(str, pBuffer, bufferLength, kCFStringEncodingUTF8); + warnx("%s\n", pBuffer); + free(pBuffer); } -char* cfstringToCstr(CFStringRef str) +char * +cfstringToCstr(CFStringRef str) { - CFIndex bufferLength = CFStringGetLength(str) + 1; - char *pBuffer = (char*)malloc(sizeof(char) * bufferLength); - CFStringGetCString(str, pBuffer, bufferLength, kCFStringEncodingUTF8); - return pBuffer; + CFIndex bufferLength = CFStringGetLength(str) + 1; + char *pBuffer = (char *)malloc(sizeof(char) * bufferLength); + CFStringGetCString(str, pBuffer, bufferLength, kCFStringEncodingUTF8); + return pBuffer; } -void appendHexChar(CFMutableStringRef str, unsigned char halfByte) +void +appendHexChar(CFMutableStringRef str, unsigned char halfByte) { - if (halfByte < 10) + if (halfByte < 10) { - CFStringAppendFormat (str, NULL, CFSTR("%d"), halfByte); + CFStringAppendFormat(str, NULL, CFSTR("%d"), halfByte); } - else + else { - char tmp[2] = {'A'+halfByte-10, 0}; - CFStringAppendCString(str, tmp, kCFStringEncodingUTF8); + char tmp[2] = {'A'+halfByte-10, 0}; + CFStringAppendCString(str, tmp, kCFStringEncodingUTF8); } } -CFStringRef createHexString(unsigned char *pData, int length) +CFStringRef +createHexString(unsigned char *pData, int length) { - unsigned char byte, low, high; - int i; - CFMutableStringRef str = CFStringCreateMutable(NULL, 0); + unsigned char byte, low, high; + int i; + CFMutableStringRef str = CFStringCreateMutable(NULL, 0); - for(i = 0;i < length;i++) + for (i = 0; i < length; i++) { - byte = pData[i]; - low = byte & 0x0F; - high = (byte >> 4); + byte = pData[i]; + low = byte & 0x0F; + high = (byte >> 4); - appendHexChar(str, high); - appendHexChar(str, low); + appendHexChar(str, high); + appendHexChar(str, low); - if (i != (length - 1)) - CFStringAppendCString(str, " ", kCFStringEncodingUTF8); + if (i != (length - 1)) + { + CFStringAppendCString(str, " ", kCFStringEncodingUTF8); + } } - return str; + return str; } -void printHex(unsigned char *pData, int length) +void +printHex(unsigned char *pData, int length) { - CFStringRef hexStr = createHexString(pData, length); - printCFString(hexStr); - CFRelease(hexStr); + CFStringRef hexStr = createHexString(pData, length); + printCFString(hexStr); + CFRelease(hexStr); } diff --git a/contrib/keychain-mcd/common_osx.h b/contrib/keychain-mcd/common_osx.h index 42735486981..965d4fa471b 100644 --- a/contrib/keychain-mcd/common_osx.h +++ b/contrib/keychain-mcd/common_osx.h @@ -29,8 +29,11 @@ #include void printCFString(CFStringRef str); -char* cfstringToCstr(CFStringRef str); + +char *cfstringToCstr(CFStringRef str); + CFStringRef createHexString(unsigned char *pData, int length); + void printHex(unsigned char *pData, int length); -#endif //__Common_osx_h__ +#endif /*__Common_osx_h__ */ diff --git a/contrib/keychain-mcd/crypto_osx.c b/contrib/keychain-mcd/crypto_osx.c index 87ba09ba6cc..092e64fff24 100644 --- a/contrib/keychain-mcd/crypto_osx.c +++ b/contrib/keychain-mcd/crypto_osx.c @@ -31,45 +31,50 @@ #include "crypto_osx.h" #include -void printErrorMsg(const char *func, CFErrorRef error) +void +printErrorMsg(const char *func, CFErrorRef error) { - CFStringRef desc = CFErrorCopyDescription(error); - warnx("%s failed: %s", func, CFStringGetCStringPtr(desc, kCFStringEncodingUTF8)); - CFRelease(desc); + CFStringRef desc = CFErrorCopyDescription(error); + warnx("%s failed: %s", func, CFStringGetCStringPtr(desc, kCFStringEncodingUTF8)); + CFRelease(desc); } -void printErrorStatusMsg(const char *func, OSStatus status) +void +printErrorStatusMsg(const char *func, OSStatus status) { - CFStringRef error; - error = SecCopyErrorMessageString(status, NULL); - if (error) + CFStringRef error; + error = SecCopyErrorMessageString(status, NULL); + if (error) { - warnx("%s failed: %s", func, CFStringGetCStringPtr(error, kCFStringEncodingUTF8)); - CFRelease(error); + warnx("%s failed: %s", func, CFStringGetCStringPtr(error, kCFStringEncodingUTF8)); + CFRelease(error); + } + else + { + warnx("%s failed: %X", func, (int)status); } - else - warnx("%s failed: %X", func, (int)status); } -void signData(SecIdentityRef identity, const uint8_t *from, int flen, uint8_t *to, size_t *tlen) +void +signData(SecIdentityRef identity, const uint8_t *from, int flen, uint8_t *to, size_t *tlen) { - SecKeyRef privateKey = NULL; - OSStatus status; + SecKeyRef privateKey = NULL; + OSStatus status; - status = SecIdentityCopyPrivateKey(identity, &privateKey); - if (status != noErr) + status = SecIdentityCopyPrivateKey(identity, &privateKey); + if (status != noErr) { - printErrorStatusMsg("signData: SecIdentityCopyPrivateKey", status); - *tlen = 0; - return; + printErrorStatusMsg("signData: SecIdentityCopyPrivateKey", status); + *tlen = 0; + return; } - status = SecKeyRawSign(privateKey, kSecPaddingPKCS1, from, flen, to, tlen); - CFRelease(privateKey); - if (status != noErr) + status = SecKeyRawSign(privateKey, kSecPaddingPKCS1, from, flen, to, tlen); + CFRelease(privateKey); + if (status != noErr) { - printErrorStatusMsg("signData: SecKeyRawSign", status); - *tlen = 0; - return; + printErrorStatusMsg("signData: SecKeyRawSign", status); + *tlen = 0; + return; } } diff --git a/contrib/keychain-mcd/crypto_osx.h b/contrib/keychain-mcd/crypto_osx.h index 0da58b60acd..115ec18e7fb 100644 --- a/contrib/keychain-mcd/crypto_osx.h +++ b/contrib/keychain-mcd/crypto_osx.h @@ -29,16 +29,17 @@ #include #include -extern OSStatus SecKeyRawSign ( - SecKeyRef key, - SecPadding padding, - const uint8_t *dataToSign, - size_t dataToSignLen, - uint8_t *sig, - size_t *sigLen -); +extern OSStatus SecKeyRawSign( + SecKeyRef key, + SecPadding padding, + const uint8_t *dataToSign, + size_t dataToSignLen, + uint8_t *sig, + size_t *sigLen + ); void signData(SecIdentityRef identity, const uint8_t *from, int flen, uint8_t *to, size_t *tlen); + void printErrorMsg(const char *func, CFErrorRef error); -#endif //__crypto_osx_h__ +#endif /*__crypto_osx_h__ */ diff --git a/contrib/keychain-mcd/main.c b/contrib/keychain-mcd/main.c index 2263b7d3ea0..7d8fc83debe 100644 --- a/contrib/keychain-mcd/main.c +++ b/contrib/keychain-mcd/main.c @@ -38,36 +38,44 @@ #include "../../src/openvpn/base64.h" -SecIdentityRef template_to_identity(const char *template) +SecIdentityRef +template_to_identity(const char *template) { SecIdentityRef identity; CertDataRef pCertDataTemplate = createCertDataFromString(template); if (pCertDataTemplate == NULL) + { errx(1, "Bad certificate template"); + } identity = findIdentity(pCertDataTemplate); if (identity == NULL) + { errx(1, "No such identify"); + } fprintf(stderr, "Identity found\n"); destroyCertData(pCertDataTemplate); return identity; } -int connect_to_management_server(const char *ip, const char *port) +int +connect_to_management_server(const char *ip, const char *port) { int fd; struct sockaddr_un addr_un; struct sockaddr *addr; size_t addr_len; - if (strcmp(port, "unix") == 0) { - addr = (struct sockaddr*)&addr_un; + if (strcmp(port, "unix") == 0) + { + addr = (struct sockaddr *)&addr_un; addr_len = sizeof(addr_un); addr_un.sun_family = AF_UNIX; strncpy(addr_un.sun_path, ip, sizeof(addr_un.sun_path)); fd = socket(AF_UNIX, SOCK_STREAM, 0); } - else { + else + { int rv; struct addrinfo *result; struct addrinfo hints; @@ -78,9 +86,13 @@ int connect_to_management_server(const char *ip, const char *port) rv = getaddrinfo(ip, port, &hints, &result); if (rv < 0) + { errx(1, "getaddrinfo: %s", gai_strerror(rv)); + } if (result == NULL) + { errx(1, "getaddrinfo returned 0 addressed"); + } /* Use the first found address */ fd = socket(result->ai_family, result->ai_socktype, result->ai_protocol); @@ -88,20 +100,26 @@ int connect_to_management_server(const char *ip, const char *port) addr_len = result->ai_addrlen; } if (fd < 0) + { err(1, "socket"); + } if (connect(fd, addr, addr_len) < 0) + { err(1, "connect"); + } return fd; } -int is_prefix(const char *s, const char *prefix) +int +is_prefix(const char *s, const char *prefix) { return strncmp(s, prefix, strlen(prefix)) == 0; } -void handle_rsasign(FILE *man_file, SecIdentityRef identity, const char *input) +void +handle_rsasign(FILE *man_file, SecIdentityRef identity, const char *input) { const char *input_b64 = strchr(input, ':') + 1; char *input_binary; @@ -114,13 +132,17 @@ void handle_rsasign(FILE *man_file, SecIdentityRef identity, const char *input) input_binary = malloc(input_len); input_len = openvpn_base64_decode(input_b64, input_binary, input_len); if (input_len < 0) + { errx(1, "openvpn_base64_decode: overflow"); + } output_len = 1024; output_binary = malloc(output_len); signData(identity, (const uint8_t *)input_binary, input_len, (uint8_t *)output_binary, &output_len); if (output_len == 0) + { errx(1, "handle_rsasign: failed to sign data"); + } openvpn_base64_encode(output_binary, output_len, &output_b64); fprintf(man_file, "rsa-sig\n%s\nEND\n", output_b64); @@ -131,7 +153,8 @@ void handle_rsasign(FILE *man_file, SecIdentityRef identity, const char *input) fprintf(stderr, "Handled RSA_SIGN command\n"); } -void handle_needcertificate(FILE *man_file, SecIdentityRef identity) +void +handle_needcertificate(FILE *man_file, SecIdentityRef identity) { OSStatus status; SecCertificateRef certificate = NULL; @@ -141,14 +164,17 @@ void handle_needcertificate(FILE *man_file, SecIdentityRef identity) char *result_b64, *tmp_b64; status = SecIdentityCopyCertificate(identity, &certificate); - if (status != noErr) { + if (status != noErr) + { const char *msg = GetMacOSStatusErrorString(status); err(1, "SecIdentityCopyCertificate() failed: %s", msg); } data = SecCertificateCopyData(certificate); if (data == NULL) + { err(1, "SecCertificateCopyData() returned NULL"); + } cert = CFDataGetBytePtr(data); cert_len = CFDataGetLength(data); @@ -162,11 +188,13 @@ void handle_needcertificate(FILE *man_file, SecIdentityRef identity) fprintf(man_file, "-----BEGIN CERTIFICATE-----\n"); tmp_b64 = result_b64; while (strlen(tmp_b64) > 64) { - fprintf(man_file, "%.64s\n", tmp_b64); - tmp_b64 += 64; + fprintf(man_file, "%.64s\n", tmp_b64); + tmp_b64 += 64; } if (*tmp_b64) - fprintf(man_file, "%s\n", tmp_b64); + { + fprintf(man_file, "%s\n", tmp_b64); + } fprintf(man_file, "-----END CERTIFICATE-----\n"); fprintf(man_file, "END\n"); @@ -177,62 +205,87 @@ void handle_needcertificate(FILE *man_file, SecIdentityRef identity) fprintf(stderr, "Handled NEED 'cert' command\n"); } -void management_loop(SecIdentityRef identity, int man_fd, const char *password) +void +management_loop(SecIdentityRef identity, int man_fd, const char *password) { char *buffer = NULL; size_t buffer_len = 0; FILE *man = fdopen(man_fd, "w+"); if (man == 0) + { err(1, "fdopen"); + } if (password) + { fprintf(man, "%s\n", password); + } while (1) { if (getline(&buffer, &buffer_len, man) < 0) + { err(1, "getline"); + } #if 0 fprintf(stderr, "M: %s", buffer); #endif if (is_prefix(buffer, ">RSA_SIGN:")) + { handle_rsasign(man, identity, buffer); - if (is_prefix(buffer, ">NEED-CERTIFICATE")) { - if (!identity) { + } + if (is_prefix(buffer, ">NEED-CERTIFICATE")) + { + if (!identity) + { const char prefix[] = ">NEED-CERTIFICATE:macosx-keychain:"; if (!is_prefix(buffer, prefix)) - errx(1, "No identity template is passed via command line and " \ - "NEED-CERTIFICATE management interface command " \ - "misses 'macosx-keychain' prefix."); + { + errx(1, "No identity template is passed via command line and " \ + "NEED-CERTIFICATE management interface command " \ + "misses 'macosx-keychain' prefix."); + } identity = template_to_identity(buffer+strlen(prefix)); } handle_needcertificate(man, identity); } if (is_prefix(buffer, ">FATAL")) + { fprintf(stderr, "Fatal message from OpenVPN: %s\n", buffer+7); + } if (is_prefix(buffer, ">INFO")) + { fprintf(stderr, "INFO message from OpenVPN: %s\n", buffer+6); + } } } -char *read_password(const char *fname) +char * +read_password(const char *fname) { char *password = NULL; FILE *pwf = fopen(fname, "r"); size_t n = 0; if (pwf == NULL) + { errx(1, "fopen(%s) failed", fname); + } if (getline(&password, &n, pwf) < 0) + { err(1, "getline"); + } fclose(pwf); return password; } -int main(int argc, char* argv[]) +int +main(int argc, char *argv[]) { if (argc < 4) + { err(1, "usage: %s []", argv[0]); + } char *identity_template = argv[1]; char *s_ip = argv[2]; @@ -240,14 +293,17 @@ int main(int argc, char* argv[]) char *password = NULL; int man_fd; - if (argc > 4) { + if (argc > 4) + { char *s_pw_file = argv[4]; password = read_password(s_pw_file); } SecIdentityRef identity = NULL; if (strcmp(identity_template, "auto")) + { identity = template_to_identity(identity_template); + } man_fd = connect_to_management_server(s_ip, s_port); fprintf(stderr, "Successfully connected to openvpn\n"); diff --git a/include/openvpn-msg.h b/include/openvpn-msg.h index f7fbdd2dce0..4c9e63c7a5f 100644 --- a/include/openvpn-msg.h +++ b/include/openvpn-msg.h @@ -26,90 +26,90 @@ #define OPENVPN_MSG_H_ typedef enum { - msg_acknowledgement, - msg_add_address, - msg_del_address, - msg_add_route, - msg_del_route, - msg_add_dns_cfg, - msg_del_dns_cfg, - msg_add_nbt_cfg, - msg_del_nbt_cfg, - msg_flush_neighbors, - msg_add_block_dns, - msg_del_block_dns, - msg_register_dns + msg_acknowledgement, + msg_add_address, + msg_del_address, + msg_add_route, + msg_del_route, + msg_add_dns_cfg, + msg_del_dns_cfg, + msg_add_nbt_cfg, + msg_del_nbt_cfg, + msg_flush_neighbors, + msg_add_block_dns, + msg_del_block_dns, + msg_register_dns } message_type_t; typedef struct { - message_type_t type; - size_t size; - int message_id; + message_type_t type; + size_t size; + int message_id; } message_header_t; typedef union { - struct in_addr ipv4; - struct in6_addr ipv6; + struct in_addr ipv4; + struct in6_addr ipv6; } inet_address_t; typedef struct { - int index; - char name[256]; + int index; + char name[256]; } interface_t; typedef struct { - message_header_t header; - short family; - inet_address_t address; - int prefix_len; - interface_t iface; + message_header_t header; + short family; + inet_address_t address; + int prefix_len; + interface_t iface; } address_message_t; typedef struct { - message_header_t header; - short family; - inet_address_t prefix; - int prefix_len; - inet_address_t gateway; - interface_t iface; - int metric; + message_header_t header; + short family; + inet_address_t prefix; + int prefix_len; + inet_address_t gateway; + interface_t iface; + int metric; } route_message_t; typedef struct { - message_header_t header; - interface_t iface; - char domains[512]; - short family; - int addr_len; - inet_address_t addr[4]; /* support up to 4 dns addresses */ + message_header_t header; + interface_t iface; + char domains[512]; + short family; + int addr_len; + inet_address_t addr[4]; /* support up to 4 dns addresses */ } dns_cfg_message_t; typedef struct { - message_header_t header; - interface_t iface; - int disable_nbt; - int nbt_type; - char scope_id[256]; - struct in_addr primary_nbns; - struct in_addr secondary_nbns; + message_header_t header; + interface_t iface; + int disable_nbt; + int nbt_type; + char scope_id[256]; + struct in_addr primary_nbns; + struct in_addr secondary_nbns; } nbt_cfg_message_t; -// TODO: NTP +/* TODO: NTP */ typedef struct { - message_header_t header; - short family; - interface_t iface; + message_header_t header; + short family; + interface_t iface; } flush_neighbors_message_t; typedef struct { - message_header_t header; - int error_number; + message_header_t header; + int error_number; } ack_message_t; typedef struct { - message_header_t header; - interface_t iface; + message_header_t header; + interface_t iface; } block_dns_message_t; -#endif +#endif /* ifndef OPENVPN_MSG_H_ */ diff --git a/include/openvpn-plugin.h.in b/include/openvpn-plugin.h.in index 34ad18b42c1..f17b7535936 100644 --- a/include/openvpn-plugin.h.in +++ b/include/openvpn-plugin.h.in @@ -34,7 +34,7 @@ #define __OPENVPN_X509_CERT_T_DECLARED typedef mbedtls_x509_crt openvpn_x509_cert_t; #endif -#else +#else /* ifdef ENABLE_CRYPTO_MBEDTLS */ #include #ifndef __OPENVPN_X509_CERT_T_DECLARED #define __OPENVPN_X509_CERT_T_DECLARED @@ -85,7 +85,7 @@ extern "C" { * * FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_CLIENT_CONNECT_V2 * FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_LEARN_ADDRESS - * + * * [Client session ensues] * * For each "TLS soft reset", according to reneg-sec option (or similar): @@ -96,7 +96,7 @@ extern "C" { * in the server chain) * FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY * FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_TLS_FINAL - * + * * [If OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY returned OPENVPN_PLUGIN_FUNC_DEFERRED, * we expect that authentication is verified via auth_control_file within * the number of seconds defined by the "hand-window" option. Data channel traffic @@ -155,9 +155,9 @@ typedef void *openvpn_plugin_handle_t; * For Windows (needs to be modified for MSVC) */ #if defined(_WIN32) && !defined(OPENVPN_PLUGIN_H) -# define OPENVPN_EXPORT __declspec(dllexport) +#define OPENVPN_EXPORT __declspec(dllexport) #else -# define OPENVPN_EXPORT +#define OPENVPN_EXPORT #endif /* @@ -172,7 +172,7 @@ typedef void *openvpn_plugin_handle_t; #define OPENVPN_PLUGIN_DEF typedef #define OPENVPN_PLUGIN_FUNC(name) (*name) -#else +#else /* ifdef OPENVPN_PLUGIN_H */ /* * We are compiling plugin. @@ -191,9 +191,9 @@ typedef void *openvpn_plugin_handle_t; */ struct openvpn_plugin_string_list { - struct openvpn_plugin_string_list *next; - char *name; - char *value; + struct openvpn_plugin_string_list *next; + char *name; + char *value; }; @@ -226,35 +226,35 @@ struct openvpn_plugin_string_list */ typedef enum { - PLOG_ERR = (1 << 0), /* Error condition message */ - PLOG_WARN = (1 << 1), /* General warning message */ - PLOG_NOTE = (1 << 2), /* Informational message */ - PLOG_DEBUG = (1 << 3), /* Debug message, displayed if verb >= 7 */ + PLOG_ERR = (1 << 0),/* Error condition message */ + PLOG_WARN = (1 << 1),/* General warning message */ + PLOG_NOTE = (1 << 2),/* Informational message */ + PLOG_DEBUG = (1 << 3),/* Debug message, displayed if verb >= 7 */ - PLOG_ERRNO = (1 << 8), /* Add error description to message */ - PLOG_NOMUTE = (1 << 9), /* Mute setting does not apply for message */ + PLOG_ERRNO = (1 << 8),/* Add error description to message */ + PLOG_NOMUTE = (1 << 9), /* Mute setting does not apply for message */ } openvpn_plugin_log_flags_t; #ifdef __GNUC__ #if __USE_MINGW_ANSI_STDIO -# define _ovpn_chk_fmt(a, b) __attribute__ ((format(gnu_printf, (a), (b)))) +#define _ovpn_chk_fmt(a, b) __attribute__ ((format(gnu_printf, (a), (b)))) #else -# define _ovpn_chk_fmt(a, b) __attribute__ ((format(__printf__, (a), (b)))) +#define _ovpn_chk_fmt(a, b) __attribute__ ((format(__printf__, (a), (b)))) #endif -#else -# define _ovpn_chk_fmt(a, b) +#else /* ifdef __GNUC__ */ +#define _ovpn_chk_fmt(a, b) #endif -typedef void (*plugin_log_t) (openvpn_plugin_log_flags_t flags, - const char *plugin_name, - const char *format, ...) _ovpn_chk_fmt(3, 4); +typedef void (*plugin_log_t)(openvpn_plugin_log_flags_t flags, + const char *plugin_name, + const char *format, ...) _ovpn_chk_fmt (3, 4); -typedef void (*plugin_vlog_t) (openvpn_plugin_log_flags_t flags, - const char *plugin_name, - const char *format, - va_list arglist) _ovpn_chk_fmt(3, 0); +typedef void (*plugin_vlog_t)(openvpn_plugin_log_flags_t flags, + const char *plugin_name, + const char *format, + va_list arglist) _ovpn_chk_fmt (3, 0); #undef _ovpn_chk_fmt @@ -270,8 +270,8 @@ typedef void (*plugin_vlog_t) (openvpn_plugin_log_flags_t flags, */ struct openvpn_plugin_callbacks { - plugin_log_t plugin_log; - plugin_vlog_t plugin_vlog; + plugin_log_t plugin_log; + plugin_vlog_t plugin_vlog; }; /** @@ -281,9 +281,9 @@ struct openvpn_plugin_callbacks * and the plug-in against OpenSSL. */ typedef enum { - SSLAPI_NONE, - SSLAPI_OPENSSL, - SSLAPI_MBEDTLS + SSLAPI_NONE, + SSLAPI_OPENSSL, + SSLAPI_MBEDTLS } ovpnSSLAPI; /** @@ -309,15 +309,15 @@ typedef enum { */ struct openvpn_plugin_args_open_in { - const int type_mask; - const char ** const argv; - const char ** const envp; - struct openvpn_plugin_callbacks *callbacks; - const ovpnSSLAPI ssl_api; - const char *ovpn_version; - const unsigned int ovpn_version_major; - const unsigned int ovpn_version_minor; - const char * const ovpn_version_patch; + const int type_mask; + const char **const argv; + const char **const envp; + struct openvpn_plugin_callbacks *callbacks; + const ovpnSSLAPI ssl_api; + const char *ovpn_version; + const unsigned int ovpn_version_major; + const unsigned int ovpn_version_minor; + const char *const ovpn_version_patch; }; @@ -344,9 +344,9 @@ struct openvpn_plugin_args_open_in */ struct openvpn_plugin_args_open_return { - int type_mask; - openvpn_plugin_handle_t *handle; - struct openvpn_plugin_string_list **return_list; + int type_mask; + openvpn_plugin_handle_t *handle; + struct openvpn_plugin_string_list **return_list; }; /** @@ -379,17 +379,17 @@ struct openvpn_plugin_args_open_return */ struct openvpn_plugin_args_func_in { - const int type; - const char ** const argv; - const char ** const envp; - openvpn_plugin_handle_t handle; - void *per_client_context; + const int type; + const char **const argv; + const char **const envp; + openvpn_plugin_handle_t handle; + void *per_client_context; #ifdef ENABLE_CRYPTO - int current_cert_depth; - openvpn_x509_cert_t *current_cert; + int current_cert_depth; + openvpn_x509_cert_t *current_cert; #else - int __current_cert_depth_disabled; /* Unused, for compatibility purposes only */ - void *__current_cert_disabled; /* Unused, for compatibility purposes only */ + int __current_cert_depth_disabled; /* Unused, for compatibility purposes only */ + void *__current_cert_disabled; /* Unused, for compatibility purposes only */ #endif }; @@ -407,7 +407,7 @@ struct openvpn_plugin_args_func_in */ struct openvpn_plugin_args_func_return { - struct openvpn_plugin_string_list **return_list; + struct openvpn_plugin_string_list **return_list; }; /* @@ -441,7 +441,7 @@ struct openvpn_plugin_args_func_return * FUNCTION: openvpn_plugin_open_v2 * * REQUIRED: YES - * + * * Called on initial plug-in load. OpenVPN will preserve plug-in state * across SIGUSR1 restarts but not across SIGHUP restarts. A SIGHUP reset * will cause the plugin to be closed and reopened. @@ -473,10 +473,10 @@ struct openvpn_plugin_args_func_return * An openvpn_plugin_handle_t value on success, NULL on failure */ OPENVPN_PLUGIN_DEF openvpn_plugin_handle_t OPENVPN_PLUGIN_FUNC(openvpn_plugin_open_v2) - (unsigned int *type_mask, - const char *argv[], - const char *envp[], - struct openvpn_plugin_string_list **return_list); + (unsigned int *type_mask, + const char *argv[], + const char *envp[], + struct openvpn_plugin_string_list **return_list); /* * FUNCTION: openvpn_plugin_func_v2 @@ -484,7 +484,7 @@ OPENVPN_PLUGIN_DEF openvpn_plugin_handle_t OPENVPN_PLUGIN_FUNC(openvpn_plugin_op * Called to perform the work of a given script type. * * REQUIRED: YES - * + * * ARGUMENTS * * handle : the openvpn_plugin_handle_t value which was returned by @@ -569,12 +569,12 @@ OPENVPN_PLUGIN_DEF openvpn_plugin_handle_t OPENVPN_PLUGIN_FUNC(openvpn_plugin_op * authentication and client-specific packet filtering. */ OPENVPN_PLUGIN_DEF int OPENVPN_PLUGIN_FUNC(openvpn_plugin_func_v2) - (openvpn_plugin_handle_t handle, - const int type, - const char *argv[], - const char *envp[], - void *per_client_context, - struct openvpn_plugin_string_list **return_list); + (openvpn_plugin_handle_t handle, + const int type, + const char *argv[], + const char *envp[], + void *per_client_context, + struct openvpn_plugin_string_list **return_list); /* @@ -589,8 +589,8 @@ OPENVPN_PLUGIN_DEF int OPENVPN_PLUGIN_FUNC(openvpn_plugin_func_v2) * ARGUMENTS * * version : fixed value, defines the API version of the OpenVPN plug-in API. The plug-in - * should validate that this value is matching the OPENVPN_PLUGINv3_STRUCTVER - * value. + * should validate that this value is matching the OPENVPN_PLUGINv3_STRUCTVER + * value. * * arguments : Structure with all arguments available to the plug-in. * @@ -601,9 +601,9 @@ OPENVPN_PLUGIN_DEF int OPENVPN_PLUGIN_FUNC(openvpn_plugin_func_v2) * OPENVPN_PLUGIN_FUNC_SUCCESS on success, OPENVPN_PLUGIN_FUNC_ERROR on failure */ OPENVPN_PLUGIN_DEF int OPENVPN_PLUGIN_FUNC(openvpn_plugin_open_v3) - (const int version, - struct openvpn_plugin_args_open_in const *arguments, - struct openvpn_plugin_args_open_return *retptr); + (const int version, + struct openvpn_plugin_args_open_in const *arguments, + struct openvpn_plugin_args_open_return *retptr); /* * FUNCTION: openvpn_plugin_func_v3 @@ -685,15 +685,15 @@ OPENVPN_PLUGIN_DEF int OPENVPN_PLUGIN_FUNC(openvpn_plugin_open_v3) * authentication and client-specific packet filtering. */ OPENVPN_PLUGIN_DEF int OPENVPN_PLUGIN_FUNC(openvpn_plugin_func_v3) - (const int version, - struct openvpn_plugin_args_func_in const *arguments, - struct openvpn_plugin_args_func_return *retptr); + (const int version, + struct openvpn_plugin_args_func_in const *arguments, + struct openvpn_plugin_args_func_return *retptr); /* * FUNCTION: openvpn_plugin_close_v1 * * REQUIRED: YES - * + * * ARGUMENTS * * handle : the openvpn_plugin_handle_t value which was returned by @@ -702,13 +702,13 @@ OPENVPN_PLUGIN_DEF int OPENVPN_PLUGIN_FUNC(openvpn_plugin_func_v3) * Called immediately prior to plug-in unload. */ OPENVPN_PLUGIN_DEF void OPENVPN_PLUGIN_FUNC(openvpn_plugin_close_v1) - (openvpn_plugin_handle_t handle); + (openvpn_plugin_handle_t handle); /* * FUNCTION: openvpn_plugin_abort_v1 * * REQUIRED: NO - * + * * ARGUMENTS * * handle : the openvpn_plugin_handle_t value which was returned by @@ -719,7 +719,7 @@ OPENVPN_PLUGIN_DEF void OPENVPN_PLUGIN_FUNC(openvpn_plugin_close_v1) * openvpn_plugin_open callback. */ OPENVPN_PLUGIN_DEF void OPENVPN_PLUGIN_FUNC(openvpn_plugin_abort_v1) - (openvpn_plugin_handle_t handle); + (openvpn_plugin_handle_t handle); /* * FUNCTION: openvpn_plugin_client_constructor_v1 @@ -736,7 +736,7 @@ OPENVPN_PLUGIN_DEF void OPENVPN_PLUGIN_FUNC(openvpn_plugin_abort_v1) * return a void * to this memory region. * * REQUIRED: NO - * + * * ARGUMENTS * * handle : the openvpn_plugin_handle_t value which was returned by @@ -747,8 +747,8 @@ OPENVPN_PLUGIN_DEF void OPENVPN_PLUGIN_FUNC(openvpn_plugin_abort_v1) * void * pointer to plugin's private per-client memory region, or NULL * if no memory region is required. */ -OPENVPN_PLUGIN_DEF void * OPENVPN_PLUGIN_FUNC(openvpn_plugin_client_constructor_v1) - (openvpn_plugin_handle_t handle); +OPENVPN_PLUGIN_DEF void *OPENVPN_PLUGIN_FUNC(openvpn_plugin_client_constructor_v1) + (openvpn_plugin_handle_t handle); /* * FUNCTION: openvpn_plugin_client_destructor_v1 @@ -756,7 +756,7 @@ OPENVPN_PLUGIN_DEF void * OPENVPN_PLUGIN_FUNC(openvpn_plugin_client_constructor_ * This function is called on client instance object destruction. * * REQUIRED: NO - * + * * ARGUMENTS * * handle : the openvpn_plugin_handle_t value which was returned by @@ -766,7 +766,7 @@ OPENVPN_PLUGIN_DEF void * OPENVPN_PLUGIN_FUNC(openvpn_plugin_client_constructor_ * openvpn_plugin_client_constructor_v1, if defined. */ OPENVPN_PLUGIN_DEF void OPENVPN_PLUGIN_FUNC(openvpn_plugin_client_destructor_v1) - (openvpn_plugin_handle_t handle, void *per_client_context); + (openvpn_plugin_handle_t handle, void *per_client_context); /* * FUNCTION: openvpn_plugin_select_initialization_point_v1 @@ -779,7 +779,7 @@ OPENVPN_PLUGIN_DEF void OPENVPN_PLUGIN_FUNC(openvpn_plugin_client_destructor_v1) * OPENVPN_PLUGIN_INIT_PRE_CONFIG_PARSE. * * REQUIRED: NO - * + * * RETURN VALUE: * * An OPENVPN_PLUGIN_INIT_x value. @@ -790,35 +790,35 @@ OPENVPN_PLUGIN_DEF void OPENVPN_PLUGIN_FUNC(openvpn_plugin_client_destructor_v1) #define OPENVPN_PLUGIN_INIT_POST_UID_CHANGE 4 OPENVPN_PLUGIN_DEF int OPENVPN_PLUGIN_FUNC(openvpn_plugin_select_initialization_point_v1) - (void); + (void); /* * FUNCTION: openvpn_plugin_min_version_required_v1 * * This function is called by OpenVPN to query the minimum - plugin interface version number required by the plugin. + * plugin interface version number required by the plugin. * * REQUIRED: NO - * + * * RETURN VALUE * * The minimum OpenVPN plugin interface version number necessary to support * this plugin. */ OPENVPN_PLUGIN_DEF int OPENVPN_PLUGIN_FUNC(openvpn_plugin_min_version_required_v1) - (void); + (void); /* * Deprecated functions which are still supported for backward compatibility. */ OPENVPN_PLUGIN_DEF openvpn_plugin_handle_t OPENVPN_PLUGIN_FUNC(openvpn_plugin_open_v1) - (unsigned int *type_mask, - const char *argv[], - const char *envp[]); + (unsigned int *type_mask, + const char *argv[], + const char *envp[]); OPENVPN_PLUGIN_DEF int OPENVPN_PLUGIN_FUNC(openvpn_plugin_func_v1) - (openvpn_plugin_handle_t handle, const int type, const char *argv[], const char *envp[]); + (openvpn_plugin_handle_t handle, const int type, const char *argv[], const char *envp[]); #ifdef __cplusplus } diff --git a/sample/sample-plugins/defer/simple.c b/sample/sample-plugins/defer/simple.c index 65398657d10..1d70ad1dec2 100644 --- a/sample/sample-plugins/defer/simple.c +++ b/sample/sample-plugins/defer/simple.c @@ -25,7 +25,7 @@ /* * This file implements a simple OpenVPN plugin module which * will test deferred authentication and packet filtering. - * + * * Will run on Windows or *nix. * * Sample usage: @@ -68,13 +68,13 @@ */ struct plugin_context { - int test_deferred_auth; - int test_packet_filter; + int test_deferred_auth; + int test_packet_filter; }; struct plugin_per_client_context { - int n_calls; - bool generated_pf_file; + int n_calls; + bool generated_pf_file; }; /* @@ -83,223 +83,258 @@ struct plugin_per_client_context { * if found or NULL otherwise. */ static const char * -get_env (const char *name, const char *envp[]) +get_env(const char *name, const char *envp[]) { - if (envp) + if (envp) { - int i; - const int namelen = strlen (name); - for (i = 0; envp[i]; ++i) - { - if (!strncmp (envp[i], name, namelen)) - { - const char *cp = envp[i] + namelen; - if (*cp == '=') - return cp + 1; - } - } + int i; + const int namelen = strlen(name); + for (i = 0; envp[i]; ++i) + { + if (!strncmp(envp[i], name, namelen)) + { + const char *cp = envp[i] + namelen; + if (*cp == '=') + { + return cp + 1; + } + } + } } - return NULL; + return NULL; } /* used for safe printf of possible NULL strings */ static const char * -np (const char *str) +np(const char *str) { - if (str) - return str; - else - return "[NULL]"; + if (str) + { + return str; + } + else + { + return "[NULL]"; + } } static int -atoi_null0 (const char *str) +atoi_null0(const char *str) { - if (str) - return atoi (str); - else - return 0; + if (str) + { + return atoi(str); + } + else + { + return 0; + } } OPENVPN_EXPORT openvpn_plugin_handle_t -openvpn_plugin_open_v1 (unsigned int *type_mask, const char *argv[], const char *envp[]) +openvpn_plugin_open_v1(unsigned int *type_mask, const char *argv[], const char *envp[]) { - struct plugin_context *context; - - printf ("FUNC: openvpn_plugin_open_v1\n"); - - /* - * Allocate our context - */ - context = (struct plugin_context *) calloc (1, sizeof (struct plugin_context)); - - context->test_deferred_auth = atoi_null0 (get_env ("test_deferred_auth", envp)); - printf ("TEST_DEFERRED_AUTH %d\n", context->test_deferred_auth); - - context->test_packet_filter = atoi_null0 (get_env ("test_packet_filter", envp)); - printf ("TEST_PACKET_FILTER %d\n", context->test_packet_filter); - - /* - * Which callbacks to intercept. - */ - *type_mask = - OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_UP) | - OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_DOWN) | - OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_ROUTE_UP) | - OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_IPCHANGE) | - OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_TLS_VERIFY) | - OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY) | - OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_CLIENT_CONNECT_V2) | - OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_CLIENT_DISCONNECT) | - OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_LEARN_ADDRESS) | - OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_TLS_FINAL) | - OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_ENABLE_PF); - - return (openvpn_plugin_handle_t) context; + struct plugin_context *context; + + printf("FUNC: openvpn_plugin_open_v1\n"); + + /* + * Allocate our context + */ + context = (struct plugin_context *) calloc(1, sizeof(struct plugin_context)); + + context->test_deferred_auth = atoi_null0(get_env("test_deferred_auth", envp)); + printf("TEST_DEFERRED_AUTH %d\n", context->test_deferred_auth); + + context->test_packet_filter = atoi_null0(get_env("test_packet_filter", envp)); + printf("TEST_PACKET_FILTER %d\n", context->test_packet_filter); + + /* + * Which callbacks to intercept. + */ + *type_mask = + OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_UP) + |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_DOWN) + |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_ROUTE_UP) + |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_IPCHANGE) + |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_TLS_VERIFY) + |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY) + |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_CLIENT_CONNECT_V2) + |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_CLIENT_DISCONNECT) + |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_LEARN_ADDRESS) + |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_TLS_FINAL) + |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_ENABLE_PF); + + return (openvpn_plugin_handle_t) context; } static int -auth_user_pass_verify (struct plugin_context *context, struct plugin_per_client_context *pcc, const char *argv[], const char *envp[]) +auth_user_pass_verify(struct plugin_context *context, struct plugin_per_client_context *pcc, const char *argv[], const char *envp[]) { - if (context->test_deferred_auth) + if (context->test_deferred_auth) { - /* get username/password from envp string array */ - const char *username = get_env ("username", envp); - const char *password = get_env ("password", envp); - - /* get auth_control_file filename from envp string array*/ - const char *auth_control_file = get_env ("auth_control_file", envp); - - printf ("DEFER u='%s' p='%s' acf='%s'\n", - np(username), - np(password), - np(auth_control_file)); - - /* Authenticate asynchronously in n seconds */ - if (auth_control_file) - { - char buf[256]; - int auth = 2; - sscanf (username, "%d", &auth); - snprintf (buf, sizeof(buf), "( sleep %d ; echo AUTH %s %d ; echo %d >%s ) &", - context->test_deferred_auth, - auth_control_file, - auth, - pcc->n_calls < auth, - auth_control_file); - printf ("%s\n", buf); - system (buf); - pcc->n_calls++; - return OPENVPN_PLUGIN_FUNC_DEFERRED; - } - else - return OPENVPN_PLUGIN_FUNC_ERROR; + /* get username/password from envp string array */ + const char *username = get_env("username", envp); + const char *password = get_env("password", envp); + + /* get auth_control_file filename from envp string array*/ + const char *auth_control_file = get_env("auth_control_file", envp); + + printf("DEFER u='%s' p='%s' acf='%s'\n", + np(username), + np(password), + np(auth_control_file)); + + /* Authenticate asynchronously in n seconds */ + if (auth_control_file) + { + char buf[256]; + int auth = 2; + sscanf(username, "%d", &auth); + snprintf(buf, sizeof(buf), "( sleep %d ; echo AUTH %s %d ; echo %d >%s ) &", + context->test_deferred_auth, + auth_control_file, + auth, + pcc->n_calls < auth, + auth_control_file); + printf("%s\n", buf); + system(buf); + pcc->n_calls++; + return OPENVPN_PLUGIN_FUNC_DEFERRED; + } + else + { + return OPENVPN_PLUGIN_FUNC_ERROR; + } + } + else + { + return OPENVPN_PLUGIN_FUNC_SUCCESS; } - else - return OPENVPN_PLUGIN_FUNC_SUCCESS; } static int -tls_final (struct plugin_context *context, struct plugin_per_client_context *pcc, const char *argv[], const char *envp[]) +tls_final(struct plugin_context *context, struct plugin_per_client_context *pcc, const char *argv[], const char *envp[]) { - if (context->test_packet_filter) + if (context->test_packet_filter) + { + if (!pcc->generated_pf_file) + { + const char *pff = get_env("pf_file", envp); + const char *cn = get_env("username", envp); + if (pff && cn) + { + char buf[256]; + snprintf(buf, sizeof(buf), "( sleep %d ; echo PF %s/%s ; cp \"%s.pf\" \"%s\" ) &", + context->test_packet_filter, cn, pff, cn, pff); + printf("%s\n", buf); + system(buf); + pcc->generated_pf_file = true; + return OPENVPN_PLUGIN_FUNC_SUCCESS; + } + else + { + return OPENVPN_PLUGIN_FUNC_ERROR; + } + } + else + { + return OPENVPN_PLUGIN_FUNC_ERROR; + } + } + else { - if (!pcc->generated_pf_file) - { - const char *pff = get_env ("pf_file", envp); - const char *cn = get_env ("username", envp); - if (pff && cn) - { - char buf[256]; - snprintf (buf, sizeof(buf), "( sleep %d ; echo PF %s/%s ; cp \"%s.pf\" \"%s\" ) &", - context->test_packet_filter, cn, pff, cn, pff); - printf ("%s\n", buf); - system (buf); - pcc->generated_pf_file = true; - return OPENVPN_PLUGIN_FUNC_SUCCESS; - } - else - return OPENVPN_PLUGIN_FUNC_ERROR; - } - else - return OPENVPN_PLUGIN_FUNC_ERROR; + return OPENVPN_PLUGIN_FUNC_SUCCESS; } - else - return OPENVPN_PLUGIN_FUNC_SUCCESS; } OPENVPN_EXPORT int -openvpn_plugin_func_v2 (openvpn_plugin_handle_t handle, - const int type, - const char *argv[], - const char *envp[], - void *per_client_context, - struct openvpn_plugin_string_list **return_list) +openvpn_plugin_func_v2(openvpn_plugin_handle_t handle, + const int type, + const char *argv[], + const char *envp[], + void *per_client_context, + struct openvpn_plugin_string_list **return_list) { - struct plugin_context *context = (struct plugin_context *) handle; - struct plugin_per_client_context *pcc = (struct plugin_per_client_context *) per_client_context; - switch (type) + struct plugin_context *context = (struct plugin_context *) handle; + struct plugin_per_client_context *pcc = (struct plugin_per_client_context *) per_client_context; + switch (type) { - case OPENVPN_PLUGIN_UP: - printf ("OPENVPN_PLUGIN_UP\n"); - return OPENVPN_PLUGIN_FUNC_SUCCESS; - case OPENVPN_PLUGIN_DOWN: - printf ("OPENVPN_PLUGIN_DOWN\n"); - return OPENVPN_PLUGIN_FUNC_SUCCESS; - case OPENVPN_PLUGIN_ROUTE_UP: - printf ("OPENVPN_PLUGIN_ROUTE_UP\n"); - return OPENVPN_PLUGIN_FUNC_SUCCESS; - case OPENVPN_PLUGIN_IPCHANGE: - printf ("OPENVPN_PLUGIN_IPCHANGE\n"); - return OPENVPN_PLUGIN_FUNC_SUCCESS; - case OPENVPN_PLUGIN_TLS_VERIFY: - printf ("OPENVPN_PLUGIN_TLS_VERIFY\n"); - return OPENVPN_PLUGIN_FUNC_SUCCESS; - case OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY: - printf ("OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY\n"); - return auth_user_pass_verify (context, pcc, argv, envp); - case OPENVPN_PLUGIN_CLIENT_CONNECT_V2: - printf ("OPENVPN_PLUGIN_CLIENT_CONNECT_V2\n"); - return OPENVPN_PLUGIN_FUNC_SUCCESS; - case OPENVPN_PLUGIN_CLIENT_DISCONNECT: - printf ("OPENVPN_PLUGIN_CLIENT_DISCONNECT\n"); - return OPENVPN_PLUGIN_FUNC_SUCCESS; - case OPENVPN_PLUGIN_LEARN_ADDRESS: - printf ("OPENVPN_PLUGIN_LEARN_ADDRESS\n"); - return OPENVPN_PLUGIN_FUNC_SUCCESS; - case OPENVPN_PLUGIN_TLS_FINAL: - printf ("OPENVPN_PLUGIN_TLS_FINAL\n"); - return tls_final (context, pcc, argv, envp); - case OPENVPN_PLUGIN_ENABLE_PF: - printf ("OPENVPN_PLUGIN_ENABLE_PF\n"); - if (context->test_packet_filter) - return OPENVPN_PLUGIN_FUNC_SUCCESS; - else - return OPENVPN_PLUGIN_FUNC_ERROR; - default: - printf ("OPENVPN_PLUGIN_?\n"); - return OPENVPN_PLUGIN_FUNC_ERROR; + case OPENVPN_PLUGIN_UP: + printf("OPENVPN_PLUGIN_UP\n"); + return OPENVPN_PLUGIN_FUNC_SUCCESS; + + case OPENVPN_PLUGIN_DOWN: + printf("OPENVPN_PLUGIN_DOWN\n"); + return OPENVPN_PLUGIN_FUNC_SUCCESS; + + case OPENVPN_PLUGIN_ROUTE_UP: + printf("OPENVPN_PLUGIN_ROUTE_UP\n"); + return OPENVPN_PLUGIN_FUNC_SUCCESS; + + case OPENVPN_PLUGIN_IPCHANGE: + printf("OPENVPN_PLUGIN_IPCHANGE\n"); + return OPENVPN_PLUGIN_FUNC_SUCCESS; + + case OPENVPN_PLUGIN_TLS_VERIFY: + printf("OPENVPN_PLUGIN_TLS_VERIFY\n"); + return OPENVPN_PLUGIN_FUNC_SUCCESS; + + case OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY: + printf("OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY\n"); + return auth_user_pass_verify(context, pcc, argv, envp); + + case OPENVPN_PLUGIN_CLIENT_CONNECT_V2: + printf("OPENVPN_PLUGIN_CLIENT_CONNECT_V2\n"); + return OPENVPN_PLUGIN_FUNC_SUCCESS; + + case OPENVPN_PLUGIN_CLIENT_DISCONNECT: + printf("OPENVPN_PLUGIN_CLIENT_DISCONNECT\n"); + return OPENVPN_PLUGIN_FUNC_SUCCESS; + + case OPENVPN_PLUGIN_LEARN_ADDRESS: + printf("OPENVPN_PLUGIN_LEARN_ADDRESS\n"); + return OPENVPN_PLUGIN_FUNC_SUCCESS; + + case OPENVPN_PLUGIN_TLS_FINAL: + printf("OPENVPN_PLUGIN_TLS_FINAL\n"); + return tls_final(context, pcc, argv, envp); + + case OPENVPN_PLUGIN_ENABLE_PF: + printf("OPENVPN_PLUGIN_ENABLE_PF\n"); + if (context->test_packet_filter) + { + return OPENVPN_PLUGIN_FUNC_SUCCESS; + } + else + { + return OPENVPN_PLUGIN_FUNC_ERROR; + } + + default: + printf("OPENVPN_PLUGIN_?\n"); + return OPENVPN_PLUGIN_FUNC_ERROR; } } OPENVPN_EXPORT void * -openvpn_plugin_client_constructor_v1 (openvpn_plugin_handle_t handle) +openvpn_plugin_client_constructor_v1(openvpn_plugin_handle_t handle) { - printf ("FUNC: openvpn_plugin_client_constructor_v1\n"); - return calloc (1, sizeof (struct plugin_per_client_context)); + printf("FUNC: openvpn_plugin_client_constructor_v1\n"); + return calloc(1, sizeof(struct plugin_per_client_context)); } OPENVPN_EXPORT void -openvpn_plugin_client_destructor_v1 (openvpn_plugin_handle_t handle, void *per_client_context) +openvpn_plugin_client_destructor_v1(openvpn_plugin_handle_t handle, void *per_client_context) { - printf ("FUNC: openvpn_plugin_client_destructor_v1\n"); - free (per_client_context); + printf("FUNC: openvpn_plugin_client_destructor_v1\n"); + free(per_client_context); } OPENVPN_EXPORT void -openvpn_plugin_close_v1 (openvpn_plugin_handle_t handle) +openvpn_plugin_close_v1(openvpn_plugin_handle_t handle) { - struct plugin_context *context = (struct plugin_context *) handle; - printf ("FUNC: openvpn_plugin_close_v1\n"); - free (context); + struct plugin_context *context = (struct plugin_context *) handle; + printf("FUNC: openvpn_plugin_close_v1\n"); + free(context); } diff --git a/sample/sample-plugins/keying-material-exporter-demo/keyingmaterialexporter.c b/sample/sample-plugins/keying-material-exporter-demo/keyingmaterialexporter.c index b0240b8c937..9827ed1822e 100644 --- a/sample/sample-plugins/keying-material-exporter-demo/keyingmaterialexporter.c +++ b/sample/sample-plugins/keying-material-exporter-demo/keyingmaterialexporter.c @@ -41,23 +41,23 @@ #endif #define ovpn_err(fmt, ...) \ - plugin->log(PLOG_ERR, "SSO", fmt , ## __VA_ARGS__) + plugin->log(PLOG_ERR, "SSO", fmt, ## __VA_ARGS__) #define ovpn_dbg(fmt, ...) \ - plugin->log(PLOG_DEBUG, "SSO", fmt , ## __VA_ARGS__) + plugin->log(PLOG_DEBUG, "SSO", fmt, ## __VA_ARGS__) #define ovpn_note(fmt, ...) \ - plugin->log(PLOG_NOTE, "SSO", fmt , ## __VA_ARGS__) + plugin->log(PLOG_NOTE, "SSO", fmt, ## __VA_ARGS__) enum endpoint { CLIENT = 1, SERVER = 2 }; struct plugin { - plugin_log_t log; - enum endpoint type; - int mask; + plugin_log_t log; + enum endpoint type; + int mask; }; struct session { - char user[48]; - char key [48]; + char user[48]; + char key [48]; }; /* @@ -69,201 +69,226 @@ struct session { static const char * get_env(const char *name, const char *envp[]) { - if (envp) + if (envp) { - int i; - const int namelen = strlen (name); - for (i = 0; envp[i]; ++i) - { - if (!strncmp (envp[i], name, namelen)) - { - const char *cp = envp[i] + namelen; - if (*cp == '=') - return cp + 1; - } - } + int i; + const int namelen = strlen(name); + for (i = 0; envp[i]; ++i) + { + if (!strncmp(envp[i], name, namelen)) + { + const char *cp = envp[i] + namelen; + if (*cp == '=') + { + return cp + 1; + } + } + } } - return NULL; + return NULL; } OPENVPN_EXPORT int -openvpn_plugin_open_v3 (const int version, - struct openvpn_plugin_args_open_in const *args, - struct openvpn_plugin_args_open_return *rv) +openvpn_plugin_open_v3(const int version, + struct openvpn_plugin_args_open_in const *args, + struct openvpn_plugin_args_open_return *rv) { - struct plugin *plugin = calloc (1, sizeof(*plugin)); + struct plugin *plugin = calloc(1, sizeof(*plugin)); - plugin->type = get_env ("remote_1", args->envp) ? CLIENT : SERVER; - plugin->log = args->callbacks->plugin_log; + plugin->type = get_env("remote_1", args->envp) ? CLIENT : SERVER; + plugin->log = args->callbacks->plugin_log; - plugin->mask = OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_TLS_FINAL); - plugin->mask |= OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_TLS_VERIFY); + plugin->mask = OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_TLS_FINAL); + plugin->mask |= OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_TLS_VERIFY); - ovpn_note("vpn endpoint type=%s",plugin->type == CLIENT ? "client":"server"); + ovpn_note("vpn endpoint type=%s",plugin->type == CLIENT ? "client" : "server"); - rv->type_mask = plugin->mask; - rv->handle = (void *)plugin; + rv->type_mask = plugin->mask; + rv->handle = (void *)plugin; - return OPENVPN_PLUGIN_FUNC_SUCCESS; + return OPENVPN_PLUGIN_FUNC_SUCCESS; } static void session_user_set(struct session *sess, X509 *x509) { - int fn_nid; - ASN1_OBJECT *fn; - ASN1_STRING *val; - X509_NAME *x509_name; - X509_NAME_ENTRY *ent; - const char *objbuf; - - x509_name = X509_get_subject_name (x509); - int i, n = X509_NAME_entry_count (x509_name); - for (i = 0; i < n; ++i) + int fn_nid; + ASN1_OBJECT *fn; + ASN1_STRING *val; + X509_NAME *x509_name; + X509_NAME_ENTRY *ent; + const char *objbuf; + + x509_name = X509_get_subject_name(x509); + int i, n = X509_NAME_entry_count(x509_name); + for (i = 0; i < n; ++i) { - if (!(ent = X509_NAME_get_entry (x509_name, i))) - continue; - if (!(fn = X509_NAME_ENTRY_get_object (ent))) - continue; - if (!(val = X509_NAME_ENTRY_get_data (ent))) - continue; - if ((fn_nid = OBJ_obj2nid (fn)) == NID_undef) - continue; - if (!(objbuf = OBJ_nid2sn (fn_nid))) - continue; - /* bug in OpenSSL 0.9.6b ASN1_STRING_to_UTF8 requires this workaround */ - unsigned char *buf = (unsigned char *)1; - if (ASN1_STRING_to_UTF8 (&buf, val) <= 0) - continue; - - if (!strncasecmp(objbuf, "CN", 2)) - snprintf(sess->user, sizeof(sess->user) - 1, (char *)buf); - - OPENSSL_free (buf); + if (!(ent = X509_NAME_get_entry(x509_name, i))) + { + continue; + } + if (!(fn = X509_NAME_ENTRY_get_object(ent))) + { + continue; + } + if (!(val = X509_NAME_ENTRY_get_data(ent))) + { + continue; + } + if ((fn_nid = OBJ_obj2nid(fn)) == NID_undef) + { + continue; + } + if (!(objbuf = OBJ_nid2sn(fn_nid))) + { + continue; + } + /* bug in OpenSSL 0.9.6b ASN1_STRING_to_UTF8 requires this workaround */ + unsigned char *buf = (unsigned char *)1; + if (ASN1_STRING_to_UTF8(&buf, val) <= 0) + { + continue; + } + + if (!strncasecmp(objbuf, "CN", 2)) + { + snprintf(sess->user, sizeof(sess->user) - 1, (char *)buf); + } + + OPENSSL_free(buf); } } static int tls_verify(struct openvpn_plugin_args_func_in const *args) { - struct plugin *plugin = (struct plugin *)args->handle; - struct session *sess = (struct session *)args->per_client_context; + struct plugin *plugin = (struct plugin *)args->handle; + struct session *sess = (struct session *)args->per_client_context; - /* we store cert subject for the server end point only */ - if (plugin->type != SERVER) - return OPENVPN_PLUGIN_FUNC_SUCCESS; + /* we store cert subject for the server end point only */ + if (plugin->type != SERVER) + { + return OPENVPN_PLUGIN_FUNC_SUCCESS; + } - if (!args->current_cert) { - ovpn_err("this example plugin requires client certificate"); - return OPENVPN_PLUGIN_FUNC_ERROR; - } + if (!args->current_cert) + { + ovpn_err("this example plugin requires client certificate"); + return OPENVPN_PLUGIN_FUNC_ERROR; + } - session_user_set(sess, args->current_cert); + session_user_set(sess, args->current_cert); - return OPENVPN_PLUGIN_FUNC_SUCCESS; + return OPENVPN_PLUGIN_FUNC_SUCCESS; } static void file_store(char *file, char *content) { - FILE *f; - if (!(f = fopen(file, "w+"))) - return; + FILE *f; + if (!(f = fopen(file, "w+"))) + { + return; + } - fprintf(f, "%s", content); - fclose(f); + fprintf(f, "%s", content); + fclose(f); } static void server_store(struct openvpn_plugin_args_func_in const *args) { - struct plugin *plugin = (struct plugin *)args->handle; - struct session *sess = (struct session *)args->per_client_context; + struct plugin *plugin = (struct plugin *)args->handle; + struct session *sess = (struct session *)args->per_client_context; - char file[MAXPATH]; - snprintf(file, sizeof(file) - 1, "/tmp/openvpn_sso_%s", sess->key); - ovpn_note("app session file: %s", file); - file_store(file, sess->user); + char file[MAXPATH]; + snprintf(file, sizeof(file) - 1, "/tmp/openvpn_sso_%s", sess->key); + ovpn_note("app session file: %s", file); + file_store(file, sess->user); } static void client_store(struct openvpn_plugin_args_func_in const *args) { - struct plugin *plugin = (struct plugin *)args->handle; - struct session *sess = (struct session *)args->per_client_context; + struct plugin *plugin = (struct plugin *)args->handle; + struct session *sess = (struct session *)args->per_client_context; - char *file = "/tmp/openvpn_sso_user"; - ovpn_note("app session file: %s", file); - file_store(file, sess->key); + char *file = "/tmp/openvpn_sso_user"; + ovpn_note("app session file: %s", file); + file_store(file, sess->key); } static int tls_final(struct openvpn_plugin_args_func_in const *args, struct openvpn_plugin_args_func_return *rv) { - struct plugin *plugin = (struct plugin *)args->handle; - struct session *sess = (struct session *)args->per_client_context; - - const char *key; - if (!(key = get_env ("exported_keying_material", args->envp))) - return OPENVPN_PLUGIN_FUNC_ERROR; - - snprintf(sess->key, sizeof(sess->key) - 1, "%s", key); - ovpn_note("app session key: %s", sess->key); - - switch (plugin->type) { - case SERVER: - server_store(args); - break; - case CLIENT: - client_store(args); - return OPENVPN_PLUGIN_FUNC_SUCCESS; - } + struct plugin *plugin = (struct plugin *)args->handle; + struct session *sess = (struct session *)args->per_client_context; - ovpn_note("app session user: %s", sess->user); - return OPENVPN_PLUGIN_FUNC_SUCCESS; + const char *key; + if (!(key = get_env("exported_keying_material", args->envp))) + { + return OPENVPN_PLUGIN_FUNC_ERROR; + } + + snprintf(sess->key, sizeof(sess->key) - 1, "%s", key); + ovpn_note("app session key: %s", sess->key); + + switch (plugin->type) { + case SERVER: + server_store(args); + break; + + case CLIENT: + client_store(args); + return OPENVPN_PLUGIN_FUNC_SUCCESS; + } + + ovpn_note("app session user: %s", sess->user); + return OPENVPN_PLUGIN_FUNC_SUCCESS; } OPENVPN_EXPORT int -openvpn_plugin_func_v3 (const int version, - struct openvpn_plugin_args_func_in const *args, - struct openvpn_plugin_args_func_return *rv) +openvpn_plugin_func_v3(const int version, + struct openvpn_plugin_args_func_in const *args, + struct openvpn_plugin_args_func_return *rv) { - switch(args->type) { - case OPENVPN_PLUGIN_TLS_VERIFY: - return tls_verify(args); - case OPENVPN_PLUGIN_TLS_FINAL: - return tls_final(args, rv); - } - return OPENVPN_PLUGIN_FUNC_SUCCESS; + switch (args->type) { + case OPENVPN_PLUGIN_TLS_VERIFY: + return tls_verify(args); + + case OPENVPN_PLUGIN_TLS_FINAL: + return tls_final(args, rv); + } + return OPENVPN_PLUGIN_FUNC_SUCCESS; } OPENVPN_EXPORT void * openvpn_plugin_client_constructor_v1(openvpn_plugin_handle_t handle) { - struct plugin *plugin = (struct plugin *)handle; - struct session *sess = calloc (1, sizeof(*sess)); + struct plugin *plugin = (struct plugin *)handle; + struct session *sess = calloc(1, sizeof(*sess)); - ovpn_note("app session created"); + ovpn_note("app session created"); - return (void *)sess; + return (void *)sess; } OPENVPN_EXPORT void openvpn_plugin_client_destructor_v1(openvpn_plugin_handle_t handle, void *ctx) { - struct plugin *plugin = (struct plugin *)handle; - struct session *sess = (struct session *)ctx; + struct plugin *plugin = (struct plugin *)handle; + struct session *sess = (struct session *)ctx; - ovpn_note("app session key: %s", sess->key); - ovpn_note("app session destroyed"); + ovpn_note("app session key: %s", sess->key); + ovpn_note("app session destroyed"); - free (sess); + free(sess); } OPENVPN_EXPORT void -openvpn_plugin_close_v1 (openvpn_plugin_handle_t handle) +openvpn_plugin_close_v1(openvpn_plugin_handle_t handle) { - struct plugin *plugin = (struct plugin *)handle; - free (plugin); + struct plugin *plugin = (struct plugin *)handle; + free(plugin); } diff --git a/sample/sample-plugins/log/log.c b/sample/sample-plugins/log/log.c index 1cc4650e507..390c37f0c47 100644 --- a/sample/sample-plugins/log/log.c +++ b/sample/sample-plugins/log/log.c @@ -39,8 +39,8 @@ * Our context, where we keep our state. */ struct plugin_context { - const char *username; - const char *password; + const char *username; + const char *password; }; /* @@ -49,136 +49,154 @@ struct plugin_context { * if found or NULL otherwise. */ static const char * -get_env (const char *name, const char *envp[]) +get_env(const char *name, const char *envp[]) { - if (envp) + if (envp) { - int i; - const int namelen = strlen (name); - for (i = 0; envp[i]; ++i) - { - if (!strncmp (envp[i], name, namelen)) - { - const char *cp = envp[i] + namelen; - if (*cp == '=') - return cp + 1; - } - } + int i; + const int namelen = strlen(name); + for (i = 0; envp[i]; ++i) + { + if (!strncmp(envp[i], name, namelen)) + { + const char *cp = envp[i] + namelen; + if (*cp == '=') + { + return cp + 1; + } + } + } } - return NULL; + return NULL; } OPENVPN_EXPORT openvpn_plugin_handle_t -openvpn_plugin_open_v1 (unsigned int *type_mask, const char *argv[], const char *envp[]) +openvpn_plugin_open_v1(unsigned int *type_mask, const char *argv[], const char *envp[]) { - struct plugin_context *context; - - /* - * Allocate our context - */ - context = (struct plugin_context *) calloc (1, sizeof (struct plugin_context)); - - /* - * Set the username/password we will require. - */ - context->username = "foo"; - context->password = "bar"; - - /* - * Which callbacks to intercept. - */ - *type_mask = - OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_UP) | - OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_DOWN) | - OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_ROUTE_UP) | - OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_IPCHANGE) | - OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_TLS_VERIFY) | - OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY) | - OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_CLIENT_CONNECT_V2) | - OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_CLIENT_DISCONNECT) | - OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_LEARN_ADDRESS) | - OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_TLS_FINAL); - - return (openvpn_plugin_handle_t) context; + struct plugin_context *context; + + /* + * Allocate our context + */ + context = (struct plugin_context *) calloc(1, sizeof(struct plugin_context)); + + /* + * Set the username/password we will require. + */ + context->username = "foo"; + context->password = "bar"; + + /* + * Which callbacks to intercept. + */ + *type_mask = + OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_UP) + |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_DOWN) + |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_ROUTE_UP) + |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_IPCHANGE) + |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_TLS_VERIFY) + |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY) + |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_CLIENT_CONNECT_V2) + |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_CLIENT_DISCONNECT) + |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_LEARN_ADDRESS) + |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_TLS_FINAL); + + return (openvpn_plugin_handle_t) context; } void -show (const int type, const char *argv[], const char *envp[]) +show(const int type, const char *argv[], const char *envp[]) { - size_t i; - switch (type) + size_t i; + switch (type) { - case OPENVPN_PLUGIN_UP: - printf ("OPENVPN_PLUGIN_UP\n"); - break; - case OPENVPN_PLUGIN_DOWN: - printf ("OPENVPN_PLUGIN_DOWN\n"); - break; - case OPENVPN_PLUGIN_ROUTE_UP: - printf ("OPENVPN_PLUGIN_ROUTE_UP\n"); - break; - case OPENVPN_PLUGIN_IPCHANGE: - printf ("OPENVPN_PLUGIN_IPCHANGE\n"); - break; - case OPENVPN_PLUGIN_TLS_VERIFY: - printf ("OPENVPN_PLUGIN_TLS_VERIFY\n"); - break; - case OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY: - printf ("OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY\n"); - break; - case OPENVPN_PLUGIN_CLIENT_CONNECT_V2: - printf ("OPENVPN_PLUGIN_CLIENT_CONNECT_V2\n"); - break; - case OPENVPN_PLUGIN_CLIENT_DISCONNECT: - printf ("OPENVPN_PLUGIN_CLIENT_DISCONNECT\n"); - break; - case OPENVPN_PLUGIN_LEARN_ADDRESS: - printf ("OPENVPN_PLUGIN_LEARN_ADDRESS\n"); - break; - case OPENVPN_PLUGIN_TLS_FINAL: - printf ("OPENVPN_PLUGIN_TLS_FINAL\n"); - break; - default: - printf ("OPENVPN_PLUGIN_?\n"); - break; + case OPENVPN_PLUGIN_UP: + printf("OPENVPN_PLUGIN_UP\n"); + break; + + case OPENVPN_PLUGIN_DOWN: + printf("OPENVPN_PLUGIN_DOWN\n"); + break; + + case OPENVPN_PLUGIN_ROUTE_UP: + printf("OPENVPN_PLUGIN_ROUTE_UP\n"); + break; + + case OPENVPN_PLUGIN_IPCHANGE: + printf("OPENVPN_PLUGIN_IPCHANGE\n"); + break; + + case OPENVPN_PLUGIN_TLS_VERIFY: + printf("OPENVPN_PLUGIN_TLS_VERIFY\n"); + break; + + case OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY: + printf("OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY\n"); + break; + + case OPENVPN_PLUGIN_CLIENT_CONNECT_V2: + printf("OPENVPN_PLUGIN_CLIENT_CONNECT_V2\n"); + break; + + case OPENVPN_PLUGIN_CLIENT_DISCONNECT: + printf("OPENVPN_PLUGIN_CLIENT_DISCONNECT\n"); + break; + + case OPENVPN_PLUGIN_LEARN_ADDRESS: + printf("OPENVPN_PLUGIN_LEARN_ADDRESS\n"); + break; + + case OPENVPN_PLUGIN_TLS_FINAL: + printf("OPENVPN_PLUGIN_TLS_FINAL\n"); + break; + + default: + printf("OPENVPN_PLUGIN_?\n"); + break; } - printf ("ARGV\n"); - for (i = 0; argv[i] != NULL; ++i) - printf ("%d '%s'\n", (int)i, argv[i]); + printf("ARGV\n"); + for (i = 0; argv[i] != NULL; ++i) + printf("%d '%s'\n", (int)i, argv[i]); - printf ("ENVP\n"); - for (i = 0; envp[i] != NULL; ++i) - printf ("%d '%s'\n", (int)i, envp[i]); + printf("ENVP\n"); + for (i = 0; envp[i] != NULL; ++i) + printf("%d '%s'\n", (int)i, envp[i]); } OPENVPN_EXPORT int -openvpn_plugin_func_v1 (openvpn_plugin_handle_t handle, const int type, const char *argv[], const char *envp[]) +openvpn_plugin_func_v1(openvpn_plugin_handle_t handle, const int type, const char *argv[], const char *envp[]) { - struct plugin_context *context = (struct plugin_context *) handle; + struct plugin_context *context = (struct plugin_context *) handle; - show (type, argv, envp); + show(type, argv, envp); - /* check entered username/password against what we require */ - if (type == OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY) + /* check entered username/password against what we require */ + if (type == OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY) + { + /* get username/password from envp string array */ + const char *username = get_env("username", envp); + const char *password = get_env("password", envp); + + if (username && !strcmp(username, context->username) + && password && !strcmp(password, context->password)) + { + return OPENVPN_PLUGIN_FUNC_SUCCESS; + } + else + { + return OPENVPN_PLUGIN_FUNC_ERROR; + } + } + else { - /* get username/password from envp string array */ - const char *username = get_env ("username", envp); - const char *password = get_env ("password", envp); - - if (username && !strcmp (username, context->username) - && password && !strcmp (password, context->password)) - return OPENVPN_PLUGIN_FUNC_SUCCESS; - else - return OPENVPN_PLUGIN_FUNC_ERROR; + return OPENVPN_PLUGIN_FUNC_SUCCESS; } - else - return OPENVPN_PLUGIN_FUNC_SUCCESS; } OPENVPN_EXPORT void -openvpn_plugin_close_v1 (openvpn_plugin_handle_t handle) +openvpn_plugin_close_v1(openvpn_plugin_handle_t handle) { - struct plugin_context *context = (struct plugin_context *) handle; - free (context); + struct plugin_context *context = (struct plugin_context *) handle; + free(context); } diff --git a/sample/sample-plugins/log/log_v3.c b/sample/sample-plugins/log/log_v3.c index 275b1e7a107..317604d1e8a 100644 --- a/sample/sample-plugins/log/log_v3.c +++ b/sample/sample-plugins/log/log_v3.c @@ -44,8 +44,8 @@ * Our context, where we keep our state. */ struct plugin_context { - const char *username; - const char *password; + const char *username; + const char *password; }; /* @@ -54,205 +54,238 @@ struct plugin_context { * if found or NULL otherwise. */ static const char * -get_env (const char *name, const char *envp[]) +get_env(const char *name, const char *envp[]) { - if (envp) + if (envp) { - int i; - const int namelen = strlen (name); - for (i = 0; envp[i]; ++i) - { - if (!strncmp (envp[i], name, namelen)) - { - const char *cp = envp[i] + namelen; - if (*cp == '=') - return cp + 1; - } - } + int i; + const int namelen = strlen(name); + for (i = 0; envp[i]; ++i) + { + if (!strncmp(envp[i], name, namelen)) + { + const char *cp = envp[i] + namelen; + if (*cp == '=') + { + return cp + 1; + } + } + } } - return NULL; + return NULL; } OPENVPN_EXPORT int -openvpn_plugin_open_v3 (const int v3structver, - struct openvpn_plugin_args_open_in const *args, - struct openvpn_plugin_args_open_return *ret) +openvpn_plugin_open_v3(const int v3structver, + struct openvpn_plugin_args_open_in const *args, + struct openvpn_plugin_args_open_return *ret) { - struct plugin_context *context = NULL; - - /* Check that we are API compatible */ - if( v3structver != OPENVPN_PLUGINv3_STRUCTVER ) { - printf("log_v3: ** ERROR ** Incompatible plug-in interface between this plug-in and OpenVPN\n"); - return OPENVPN_PLUGIN_FUNC_ERROR; - } - - if( args->ssl_api != SSLAPI_OPENSSL ) { - printf("This plug-in can only be used against OpenVPN with OpenSSL\n"); - return OPENVPN_PLUGIN_FUNC_ERROR; - } - - /* Print some version information about the OpenVPN process using this plug-in */ - printf("log_v3: OpenVPN %s (Major: %i, Minor: %i, Patch: %s)\n", - args->ovpn_version, args->ovpn_version_major, - args->ovpn_version_minor, args->ovpn_version_patch); - - /* Which callbacks to intercept. */ - ret->type_mask = - OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_UP) | - OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_DOWN) | - OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_ROUTE_UP) | - OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_IPCHANGE) | - OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_TLS_VERIFY) | - OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY) | - OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_CLIENT_CONNECT_V2) | - OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_CLIENT_DISCONNECT) | - OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_LEARN_ADDRESS) | - OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_TLS_FINAL); - - - /* Allocate our context */ - context = (struct plugin_context *) calloc (1, sizeof (struct plugin_context)); - - /* Set the username/password we will require. */ - context->username = "foo"; - context->password = "bar"; - - /* Point the global context handle to our newly created context */ - ret->handle = (void *) context; - - return OPENVPN_PLUGIN_FUNC_SUCCESS; + struct plugin_context *context = NULL; + + /* Check that we are API compatible */ + if (v3structver != OPENVPN_PLUGINv3_STRUCTVER) + { + printf("log_v3: ** ERROR ** Incompatible plug-in interface between this plug-in and OpenVPN\n"); + return OPENVPN_PLUGIN_FUNC_ERROR; + } + + if (args->ssl_api != SSLAPI_OPENSSL) + { + printf("This plug-in can only be used against OpenVPN with OpenSSL\n"); + return OPENVPN_PLUGIN_FUNC_ERROR; + } + + /* Print some version information about the OpenVPN process using this plug-in */ + printf("log_v3: OpenVPN %s (Major: %i, Minor: %i, Patch: %s)\n", + args->ovpn_version, args->ovpn_version_major, + args->ovpn_version_minor, args->ovpn_version_patch); + + /* Which callbacks to intercept. */ + ret->type_mask = + OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_UP) + |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_DOWN) + |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_ROUTE_UP) + |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_IPCHANGE) + |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_TLS_VERIFY) + |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY) + |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_CLIENT_CONNECT_V2) + |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_CLIENT_DISCONNECT) + |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_LEARN_ADDRESS) + |OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_TLS_FINAL); + + + /* Allocate our context */ + context = (struct plugin_context *) calloc(1, sizeof(struct plugin_context)); + + /* Set the username/password we will require. */ + context->username = "foo"; + context->password = "bar"; + + /* Point the global context handle to our newly created context */ + ret->handle = (void *) context; + + return OPENVPN_PLUGIN_FUNC_SUCCESS; } void -show (const int type, const char *argv[], const char *envp[]) +show(const int type, const char *argv[], const char *envp[]) { - size_t i; - switch (type) + size_t i; + switch (type) { - case OPENVPN_PLUGIN_UP: - printf ("OPENVPN_PLUGIN_UP\n"); - break; - case OPENVPN_PLUGIN_DOWN: - printf ("OPENVPN_PLUGIN_DOWN\n"); - break; - case OPENVPN_PLUGIN_ROUTE_UP: - printf ("OPENVPN_PLUGIN_ROUTE_UP\n"); - break; - case OPENVPN_PLUGIN_IPCHANGE: - printf ("OPENVPN_PLUGIN_IPCHANGE\n"); - break; - case OPENVPN_PLUGIN_TLS_VERIFY: - printf ("OPENVPN_PLUGIN_TLS_VERIFY\n"); - break; - case OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY: - printf ("OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY\n"); - break; - case OPENVPN_PLUGIN_CLIENT_CONNECT_V2: - printf ("OPENVPN_PLUGIN_CLIENT_CONNECT_V2\n"); - break; - case OPENVPN_PLUGIN_CLIENT_DISCONNECT: - printf ("OPENVPN_PLUGIN_CLIENT_DISCONNECT\n"); - break; - case OPENVPN_PLUGIN_LEARN_ADDRESS: - printf ("OPENVPN_PLUGIN_LEARN_ADDRESS\n"); - break; - case OPENVPN_PLUGIN_TLS_FINAL: - printf ("OPENVPN_PLUGIN_TLS_FINAL\n"); - break; - default: - printf ("OPENVPN_PLUGIN_?\n"); - break; + case OPENVPN_PLUGIN_UP: + printf("OPENVPN_PLUGIN_UP\n"); + break; + + case OPENVPN_PLUGIN_DOWN: + printf("OPENVPN_PLUGIN_DOWN\n"); + break; + + case OPENVPN_PLUGIN_ROUTE_UP: + printf("OPENVPN_PLUGIN_ROUTE_UP\n"); + break; + + case OPENVPN_PLUGIN_IPCHANGE: + printf("OPENVPN_PLUGIN_IPCHANGE\n"); + break; + + case OPENVPN_PLUGIN_TLS_VERIFY: + printf("OPENVPN_PLUGIN_TLS_VERIFY\n"); + break; + + case OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY: + printf("OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY\n"); + break; + + case OPENVPN_PLUGIN_CLIENT_CONNECT_V2: + printf("OPENVPN_PLUGIN_CLIENT_CONNECT_V2\n"); + break; + + case OPENVPN_PLUGIN_CLIENT_DISCONNECT: + printf("OPENVPN_PLUGIN_CLIENT_DISCONNECT\n"); + break; + + case OPENVPN_PLUGIN_LEARN_ADDRESS: + printf("OPENVPN_PLUGIN_LEARN_ADDRESS\n"); + break; + + case OPENVPN_PLUGIN_TLS_FINAL: + printf("OPENVPN_PLUGIN_TLS_FINAL\n"); + break; + + default: + printf("OPENVPN_PLUGIN_?\n"); + break; } - printf ("ARGV\n"); - for (i = 0; argv[i] != NULL; ++i) - printf ("%d '%s'\n", (int)i, argv[i]); + printf("ARGV\n"); + for (i = 0; argv[i] != NULL; ++i) + printf("%d '%s'\n", (int)i, argv[i]); - printf ("ENVP\n"); - for (i = 0; envp[i] != NULL; ++i) - printf ("%d '%s'\n", (int)i, envp[i]); + printf("ENVP\n"); + for (i = 0; envp[i] != NULL; ++i) + printf("%d '%s'\n", (int)i, envp[i]); } static void -x509_print_info (X509 *x509crt) +x509_print_info(X509 *x509crt) { - int i, n; - int fn_nid; - ASN1_OBJECT *fn; - ASN1_STRING *val; - X509_NAME *x509_name; - X509_NAME_ENTRY *ent; - const char *objbuf; - unsigned char *buf; - - x509_name = X509_get_subject_name (x509crt); - n = X509_NAME_entry_count (x509_name); - for (i = 0; i < n; ++i) + int i, n; + int fn_nid; + ASN1_OBJECT *fn; + ASN1_STRING *val; + X509_NAME *x509_name; + X509_NAME_ENTRY *ent; + const char *objbuf; + unsigned char *buf; + + x509_name = X509_get_subject_name(x509crt); + n = X509_NAME_entry_count(x509_name); + for (i = 0; i < n; ++i) { - ent = X509_NAME_get_entry (x509_name, i); - if (!ent) - continue; - fn = X509_NAME_ENTRY_get_object (ent); - if (!fn) - continue; - val = X509_NAME_ENTRY_get_data (ent); - if (!val) - continue; - fn_nid = OBJ_obj2nid (fn); - if (fn_nid == NID_undef) - continue; - objbuf = OBJ_nid2sn (fn_nid); - if (!objbuf) - continue; - buf = (unsigned char *)1; /* bug in OpenSSL 0.9.6b ASN1_STRING_to_UTF8 requires this workaround */ - if (ASN1_STRING_to_UTF8 (&buf, val) <= 0) - continue; - - printf("X509 %s: %s\n", objbuf, (char *)buf); - OPENSSL_free (buf); + ent = X509_NAME_get_entry(x509_name, i); + if (!ent) + { + continue; + } + fn = X509_NAME_ENTRY_get_object(ent); + if (!fn) + { + continue; + } + val = X509_NAME_ENTRY_get_data(ent); + if (!val) + { + continue; + } + fn_nid = OBJ_obj2nid(fn); + if (fn_nid == NID_undef) + { + continue; + } + objbuf = OBJ_nid2sn(fn_nid); + if (!objbuf) + { + continue; + } + buf = (unsigned char *)1; /* bug in OpenSSL 0.9.6b ASN1_STRING_to_UTF8 requires this workaround */ + if (ASN1_STRING_to_UTF8(&buf, val) <= 0) + { + continue; + } + + printf("X509 %s: %s\n", objbuf, (char *)buf); + OPENSSL_free(buf); } } OPENVPN_EXPORT int -openvpn_plugin_func_v3 (const int version, - struct openvpn_plugin_args_func_in const *args, - struct openvpn_plugin_args_func_return *retptr) +openvpn_plugin_func_v3(const int version, + struct openvpn_plugin_args_func_in const *args, + struct openvpn_plugin_args_func_return *retptr) { - struct plugin_context *context = (struct plugin_context *) args->handle; + struct plugin_context *context = (struct plugin_context *) args->handle; - printf("\nopenvpn_plugin_func_v3() :::::>> "); - show (args->type, args->argv, args->envp); + printf("\nopenvpn_plugin_func_v3() :::::>> "); + show(args->type, args->argv, args->envp); + + /* Dump some X509 information if we're in the TLS_VERIFY phase */ + if ((args->type == OPENVPN_PLUGIN_TLS_VERIFY) && args->current_cert) + { + printf("---- X509 Subject information ----\n"); + printf("Certificate depth: %i\n", args->current_cert_depth); + x509_print_info(args->current_cert); + printf("----------------------------------\n"); + } - /* Dump some X509 information if we're in the TLS_VERIFY phase */ - if ((args->type == OPENVPN_PLUGIN_TLS_VERIFY) && args->current_cert ) { - printf("---- X509 Subject information ----\n"); - printf("Certificate depth: %i\n", args->current_cert_depth); - x509_print_info(args->current_cert); - printf("----------------------------------\n"); - } + /* check entered username/password against what we require */ + if (args->type == OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY) + { + /* get username/password from envp string array */ + const char *username = get_env("username", args->envp); + const char *password = get_env("password", args->envp); - /* check entered username/password against what we require */ - if (args->type == OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY) + if (username && !strcmp(username, context->username) + && password && !strcmp(password, context->password)) + { + return OPENVPN_PLUGIN_FUNC_SUCCESS; + } + else + { + return OPENVPN_PLUGIN_FUNC_ERROR; + } + } + else { - /* get username/password from envp string array */ - const char *username = get_env ("username", args->envp); - const char *password = get_env ("password", args->envp); - - if (username && !strcmp (username, context->username) - && password && !strcmp (password, context->password)) - return OPENVPN_PLUGIN_FUNC_SUCCESS; - else - return OPENVPN_PLUGIN_FUNC_ERROR; + return OPENVPN_PLUGIN_FUNC_SUCCESS; } - else - return OPENVPN_PLUGIN_FUNC_SUCCESS; } OPENVPN_EXPORT void -openvpn_plugin_close_v1 (openvpn_plugin_handle_t handle) +openvpn_plugin_close_v1(openvpn_plugin_handle_t handle) { - struct plugin_context *context = (struct plugin_context *) handle; - free (context); + struct plugin_context *context = (struct plugin_context *) handle; + free(context); } diff --git a/sample/sample-plugins/simple/simple.c b/sample/sample-plugins/simple/simple.c index f26d89f691b..4beab48cf32 100644 --- a/sample/sample-plugins/simple/simple.c +++ b/sample/sample-plugins/simple/simple.c @@ -41,8 +41,8 @@ * Our context, where we keep our state. */ struct plugin_context { - const char *username; - const char *password; + const char *username; + const char *password; }; /* @@ -51,70 +51,76 @@ struct plugin_context { * if found or NULL otherwise. */ static const char * -get_env (const char *name, const char *envp[]) +get_env(const char *name, const char *envp[]) { - if (envp) + if (envp) { - int i; - const int namelen = strlen (name); - for (i = 0; envp[i]; ++i) - { - if (!strncmp (envp[i], name, namelen)) - { - const char *cp = envp[i] + namelen; - if (*cp == '=') - return cp + 1; - } - } + int i; + const int namelen = strlen(name); + for (i = 0; envp[i]; ++i) + { + if (!strncmp(envp[i], name, namelen)) + { + const char *cp = envp[i] + namelen; + if (*cp == '=') + { + return cp + 1; + } + } + } } - return NULL; + return NULL; } OPENVPN_EXPORT openvpn_plugin_handle_t -openvpn_plugin_open_v1 (unsigned int *type_mask, const char *argv[], const char *envp[]) +openvpn_plugin_open_v1(unsigned int *type_mask, const char *argv[], const char *envp[]) { - struct plugin_context *context; + struct plugin_context *context; - /* - * Allocate our context - */ - context = (struct plugin_context *) calloc (1, sizeof (struct plugin_context)); + /* + * Allocate our context + */ + context = (struct plugin_context *) calloc(1, sizeof(struct plugin_context)); - /* - * Set the username/password we will require. - */ - context->username = "foo"; - context->password = "bar"; + /* + * Set the username/password we will require. + */ + context->username = "foo"; + context->password = "bar"; - /* - * We are only interested in intercepting the - * --auth-user-pass-verify callback. - */ - *type_mask = OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY); + /* + * We are only interested in intercepting the + * --auth-user-pass-verify callback. + */ + *type_mask = OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY); - return (openvpn_plugin_handle_t) context; + return (openvpn_plugin_handle_t) context; } OPENVPN_EXPORT int -openvpn_plugin_func_v1 (openvpn_plugin_handle_t handle, const int type, const char *argv[], const char *envp[]) +openvpn_plugin_func_v1(openvpn_plugin_handle_t handle, const int type, const char *argv[], const char *envp[]) { - struct plugin_context *context = (struct plugin_context *) handle; + struct plugin_context *context = (struct plugin_context *) handle; - /* get username/password from envp string array */ - const char *username = get_env ("username", envp); - const char *password = get_env ("password", envp); + /* get username/password from envp string array */ + const char *username = get_env("username", envp); + const char *password = get_env("password", envp); - /* check entered username/password against what we require */ - if (username && !strcmp (username, context->username) - && password && !strcmp (password, context->password)) - return OPENVPN_PLUGIN_FUNC_SUCCESS; - else - return OPENVPN_PLUGIN_FUNC_ERROR; + /* check entered username/password against what we require */ + if (username && !strcmp(username, context->username) + && password && !strcmp(password, context->password)) + { + return OPENVPN_PLUGIN_FUNC_SUCCESS; + } + else + { + return OPENVPN_PLUGIN_FUNC_ERROR; + } } OPENVPN_EXPORT void -openvpn_plugin_close_v1 (openvpn_plugin_handle_t handle) +openvpn_plugin_close_v1(openvpn_plugin_handle_t handle) { - struct plugin_context *context = (struct plugin_context *) handle; - free (context); + struct plugin_context *context = (struct plugin_context *) handle; + free(context); } diff --git a/src/compat/compat-basename.c b/src/compat/compat-basename.c index a0576919ff8..b7b5c4386d2 100644 --- a/src/compat/compat-basename.c +++ b/src/compat/compat-basename.c @@ -37,14 +37,15 @@ * This version is extended to handle both / and \ in path names */ char * -basename (char *filename) +basename(char *filename) { - char *p = strrchr (filename, '/'); - if (!p) { - /* If NULL, check for \ instead ... might be Windows a path */ - p = strrchr (filename, '\\'); - } - return p ? p + 1 : (char *) filename; + char *p = strrchr(filename, '/'); + if (!p) + { + /* If NULL, check for \ instead ... might be Windows a path */ + p = strrchr(filename, '\\'); + } + return p ? p + 1 : (char *) filename; } #endif /* HAVE_BASENAME */ diff --git a/src/compat/compat-daemon.c b/src/compat/compat-daemon.c index dde96a20cb7..509394254ae 100644 --- a/src/compat/compat-daemon.c +++ b/src/compat/compat-daemon.c @@ -58,43 +58,52 @@ int daemon(int nochdir, int noclose) { #if defined(HAVE_FORK) && defined(HAVE_SETSID) - switch (fork()) { - case -1: - return (-1); - case 0: - break; - default: - exit(0); - } - - if (setsid() == -1) - return (-1); - - if (!nochdir) - chdir("/"); - - if (!noclose) { + switch (fork()) { + case -1: + return (-1); + + case 0: + break; + + default: + exit(0); + } + + if (setsid() == -1) + { + return (-1); + } + + if (!nochdir) + { + chdir("/"); + } + + if (!noclose) + { #if defined(HAVE_DUP) && defined(HAVE_DUP2) - int fd; - if ((fd = open ("/dev/null", O_RDWR, 0)) != -1) { - dup2 (fd, 0); - dup2 (fd, 1); - dup2 (fd, 2); - if (fd > 2) { - close (fd); - } - } -#endif - } - - return 0; -#else - (void)nochdir; - (void)noclose; - errno = EFAULT; - return -1; + int fd; + if ((fd = open("/dev/null", O_RDWR, 0)) != -1) + { + dup2(fd, 0); + dup2(fd, 1); + dup2(fd, 2); + if (fd > 2) + { + close(fd); + } + } #endif + } + + return 0; +#else /* if defined(HAVE_FORK) && defined(HAVE_SETSID) */ + (void)nochdir; + (void)noclose; + errno = EFAULT; + return -1; +#endif /* if defined(HAVE_FORK) && defined(HAVE_SETSID) */ } -#endif +#endif /* ifndef HAVE_DAEMON */ diff --git a/src/compat/compat-dirname.c b/src/compat/compat-dirname.c index 88785950837..7687108a98c 100644 --- a/src/compat/compat-dirname.c +++ b/src/compat/compat-dirname.c @@ -41,79 +41,102 @@ static const char * __memrchr(const char *str, int c, size_t n) { - const char *end = str; - - end += n - 1; /* Go to the end of the string */ - while (end >= str) { - if(c == *end) - return end; - else - end--; - } - return NULL; + const char *end = str; + + end += n - 1; /* Go to the end of the string */ + while (end >= str) { + if (c == *end) + { + return end; + } + else + { + end--; + } + } + return NULL; } /* Modified version based on glibc-2.14.1 by Ulrich Drepper * This version is extended to handle both / and \ in path names. */ char * -dirname (char *path) +dirname(char *path) { - static const char dot[] = "."; - char *last_slash; - char separator = '/'; - - /* Find last '/'. */ - last_slash = path != NULL ? strrchr (path, '/') : NULL; - /* If NULL, check for \ instead ... might be Windows a path */ - if (!last_slash) { - last_slash = path != NULL ? strrchr (path, '\\') : NULL; - separator = last_slash ? '\\' : '/'; /* Change the separator if \ was found */ - } - - if (last_slash != NULL && last_slash != path && last_slash[1] == '\0') { - /* Determine whether all remaining characters are slashes. */ - char *runp; - - for (runp = last_slash; runp != path; --runp) - if (runp[-1] != separator) - break; - - /* The '/' is the last character, we have to look further. */ - if (runp != path) - last_slash = (char *) __memrchr (path, separator, runp - path); + static const char dot[] = "."; + char *last_slash; + char separator = '/'; + + /* Find last '/'. */ + last_slash = path != NULL ? strrchr(path, '/') : NULL; + /* If NULL, check for \ instead ... might be Windows a path */ + if (!last_slash) + { + last_slash = path != NULL ? strrchr(path, '\\') : NULL; + separator = last_slash ? '\\' : '/'; /* Change the separator if \ was found */ + } + + if (last_slash != NULL && last_slash != path && last_slash[1] == '\0') + { + /* Determine whether all remaining characters are slashes. */ + char *runp; + + for (runp = last_slash; runp != path; --runp) + if (runp[-1] != separator) + { + break; + } + + /* The '/' is the last character, we have to look further. */ + if (runp != path) + { + last_slash = (char *) __memrchr(path, separator, runp - path); + } + } + + if (last_slash != NULL) + { + /* Determine whether all remaining characters are slashes. */ + char *runp; + + for (runp = last_slash; runp != path; --runp) + if (runp[-1] != separator) + { + break; + } + + /* Terminate the path. */ + if (runp == path) + { + /* The last slash is the first character in the string. We have to + * return "/". As a special case we have to return "//" if there + * are exactly two slashes at the beginning of the string. See + * XBD 4.10 Path Name Resolution for more information. */ + if (last_slash == path + 1) + { + ++last_slash; + } + else + { + last_slash = path + 1; + } + } + else + { + last_slash = runp; + } + + last_slash[0] = '\0'; + } + else + { + /* This assignment is ill-designed but the XPG specs require to + * return a string containing "." in any case no directory part is + * found and so a static and constant string is required. */ + path = (char *) dot; } - if (last_slash != NULL) { - /* Determine whether all remaining characters are slashes. */ - char *runp; - - for (runp = last_slash; runp != path; --runp) - if (runp[-1] != separator) - break; - - /* Terminate the path. */ - if (runp == path) { - /* The last slash is the first character in the string. We have to - return "/". As a special case we have to return "//" if there - are exactly two slashes at the beginning of the string. See - XBD 4.10 Path Name Resolution for more information. */ - if (last_slash == path + 1) - ++last_slash; - else - last_slash = path + 1; - } - else - last_slash = runp; - - last_slash[0] = '\0'; - } else - /* This assignment is ill-designed but the XPG specs require to - return a string containing "." in any case no directory part is - found and so a static and constant string is required. */ - path = (char *) dot; - - return path; + return path; } #endif /* HAVE_DIRNAME */ diff --git a/src/compat/compat-gettimeofday.c b/src/compat/compat-gettimeofday.c index 19feaae1f2e..027bc4a092f 100644 --- a/src/compat/compat-gettimeofday.c +++ b/src/compat/compat-gettimeofday.c @@ -48,12 +48,12 @@ static unsigned int last_msec = 0; static int bt_last = 0; static void -gettimeofday_calibrate (void) +gettimeofday_calibrate(void) { - const time_t t = time(NULL); - const DWORD gtc = GetTickCount(); - gtc_base = t - gtc/1000; - gtc_last = gtc; + const time_t t = time(NULL); + const DWORD gtc = GetTickCount(); + gtc_base = t - gtc/1000; + gtc_last = gtc; } /* @@ -62,68 +62,72 @@ gettimeofday_calibrate (void) * more processor cycles than GetTickCount. */ int -gettimeofday (struct timeval *tv, void *tz) +gettimeofday(struct timeval *tv, void *tz) { - const DWORD gtc = GetTickCount(); - int bt = 0; - time_t sec; - unsigned int msec; - const int backtrack_hold_seconds = 10; + const DWORD gtc = GetTickCount(); + int bt = 0; + time_t sec; + unsigned int msec; + const int backtrack_hold_seconds = 10; - (void)tz; + (void)tz; - /* recalibrate at the dreaded 49.7 day mark */ - if (!gtc_base || gtc < gtc_last) - gettimeofday_calibrate (); - gtc_last = gtc; + /* recalibrate at the dreaded 49.7 day mark */ + if (!gtc_base || gtc < gtc_last) + { + gettimeofday_calibrate(); + } + gtc_last = gtc; - sec = gtc_base + gtc / 1000; - msec = gtc % 1000; + sec = gtc_base + gtc / 1000; + msec = gtc % 1000; - if (sec == last_sec) + if (sec == last_sec) { - if (msec < last_msec) - { - msec = last_msec; - bt = 1; - } + if (msec < last_msec) + { + msec = last_msec; + bt = 1; + } } - else if (sec < last_sec) + else if (sec < last_sec) { - /* We try to dampen out backtracks of less than backtrack_hold_seconds. - Larger backtracks will be passed through and dealt with by the - TIME_BACKTRACK_PROTECTION code (if enabled) */ - if (sec > last_sec - backtrack_hold_seconds) - { - sec = last_sec; - msec = last_msec; - } - bt = 1; + /* We try to dampen out backtracks of less than backtrack_hold_seconds. + * Larger backtracks will be passed through and dealt with by the + * TIME_BACKTRACK_PROTECTION code (if enabled) */ + if (sec > last_sec - backtrack_hold_seconds) + { + sec = last_sec; + msec = last_msec; + } + bt = 1; } - tv->tv_sec = (long)last_sec = (long)sec; - tv->tv_usec = (last_msec = msec) * 1000; + tv->tv_sec = (long)last_sec = (long)sec; + tv->tv_usec = (last_msec = msec) * 1000; - if (bt && !bt_last) - gettimeofday_calibrate (); - bt_last = bt; + if (bt && !bt_last) + { + gettimeofday_calibrate(); + } + bt_last = bt; - return 0; + return 0; } -#else +#else /* ifdef _WIN32 */ #ifdef HAVE_TIME_H #include #endif int -gettimeofday (struct timeval *tv, void *tz) +gettimeofday(struct timeval *tv, void *tz) { - (void)tz; - tv->tv_sec = time(NULL); - tv->tv_usec = 0; - return 0; + (void)tz; + tv->tv_sec = time(NULL); + tv->tv_usec = 0; + return 0; } #endif /* _WIN32 */ diff --git a/src/compat/compat-inet_ntop.c b/src/compat/compat-inet_ntop.c index 786c973c710..dd7abb5aab3 100644 --- a/src/compat/compat-inet_ntop.c +++ b/src/compat/compat-inet_ntop.c @@ -46,31 +46,33 @@ const char * inet_ntop(int af, const void *src, char *dst, socklen_t size) { - struct sockaddr_storage ss; - unsigned long s = size; + struct sockaddr_storage ss; + unsigned long s = size; - ZeroMemory(&ss, sizeof(ss)); - ss.ss_family = af; + ZeroMemory(&ss, sizeof(ss)); + ss.ss_family = af; - switch(af) { - case AF_INET: - ((struct sockaddr_in *)&ss)->sin_addr = *(struct in_addr *)src; - break; - case AF_INET6: - ((struct sockaddr_in6 *)&ss)->sin6_addr = *(struct in6_addr *)src; - break; - default: - return NULL; - } - /* cannot direclty use &size because of strict aliasing rules */ - return (WSAAddressToString((struct sockaddr *)&ss, sizeof(ss), NULL, dst, &s) == 0)? - dst : NULL; + switch (af) { + case AF_INET: + ((struct sockaddr_in *)&ss)->sin_addr = *(struct in_addr *)src; + break; + + case AF_INET6: + ((struct sockaddr_in6 *)&ss)->sin6_addr = *(struct in6_addr *)src; + break; + + default: + return NULL; + } + /* cannot direclty use &size because of strict aliasing rules */ + return (WSAAddressToString((struct sockaddr *)&ss, sizeof(ss), NULL, dst, &s) == 0) ? + dst : NULL; } -#else +#else /* ifdef _WIN32 */ #error no emulation for inet_ntop -#endif +#endif /* ifdef _WIN32 */ -#endif +#endif /* ifndef HAVE_INET_NTOP */ diff --git a/src/compat/compat-inet_pton.c b/src/compat/compat-inet_pton.c index 5965f0d6c5f..1e41fa27496 100644 --- a/src/compat/compat-inet_pton.c +++ b/src/compat/compat-inet_pton.c @@ -48,32 +48,34 @@ int inet_pton(int af, const char *src, void *dst) { - struct sockaddr_storage ss; - int size = sizeof(ss); - char src_copy[INET6_ADDRSTRLEN+1]; + struct sockaddr_storage ss; + int size = sizeof(ss); + char src_copy[INET6_ADDRSTRLEN+1]; - ZeroMemory(&ss, sizeof(ss)); - /* stupid non-const API */ - strncpy (src_copy, src, INET6_ADDRSTRLEN+1); - src_copy[INET6_ADDRSTRLEN] = 0; + ZeroMemory(&ss, sizeof(ss)); + /* stupid non-const API */ + strncpy(src_copy, src, INET6_ADDRSTRLEN+1); + src_copy[INET6_ADDRSTRLEN] = 0; - if (WSAStringToAddress(src_copy, af, NULL, (struct sockaddr *)&ss, &size) == 0) { - switch(af) { - case AF_INET: - *(struct in_addr *)dst = ((struct sockaddr_in *)&ss)->sin_addr; - return 1; - case AF_INET6: - *(struct in6_addr *)dst = ((struct sockaddr_in6 *)&ss)->sin6_addr; - return 1; + if (WSAStringToAddress(src_copy, af, NULL, (struct sockaddr *)&ss, &size) == 0) + { + switch (af) { + case AF_INET: + *(struct in_addr *)dst = ((struct sockaddr_in *)&ss)->sin_addr; + return 1; + + case AF_INET6: + *(struct in6_addr *)dst = ((struct sockaddr_in6 *)&ss)->sin6_addr; + return 1; + } } - } - return 0; + return 0; } -#else +#else /* ifdef _WIN32 */ #error no emulation for inet_ntop -#endif +#endif /* ifdef _WIN32 */ -#endif +#endif /* ifndef HAVE_INET_PTON */ diff --git a/src/compat/compat-versionhelpers.h b/src/compat/compat-versionhelpers.h index f634091a0fd..a7930564610 100644 --- a/src/compat/compat-versionhelpers.h +++ b/src/compat/compat-versionhelpers.h @@ -18,64 +18,77 @@ #define _WIN32_WINNT_WINBLUE 0x0603 -VERSIONHELPERAPI IsWindowsVersionOrGreater(WORD major, WORD minor, WORD servpack) +VERSIONHELPERAPI +IsWindowsVersionOrGreater(WORD major, WORD minor, WORD servpack) { OSVERSIONINFOEXW vi = {sizeof(vi),major,minor,0,0,{0},servpack}; return VerifyVersionInfoW(&vi, VER_MAJORVERSION|VER_MINORVERSION|VER_SERVICEPACKMAJOR, - VerSetConditionMask(VerSetConditionMask(VerSetConditionMask(0, - VER_MAJORVERSION,VER_GREATER_EQUAL), - VER_MINORVERSION,VER_GREATER_EQUAL), - VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL)); + VerSetConditionMask(VerSetConditionMask(VerSetConditionMask(0, + VER_MAJORVERSION,VER_GREATER_EQUAL), + VER_MINORVERSION,VER_GREATER_EQUAL), + VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL)); } -VERSIONHELPERAPI IsWindowsXPOrGreater(void) { +VERSIONHELPERAPI +IsWindowsXPOrGreater(void) { return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 0); } -VERSIONHELPERAPI IsWindowsXPSP1OrGreater(void) { +VERSIONHELPERAPI +IsWindowsXPSP1OrGreater(void) { return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 1); } -VERSIONHELPERAPI IsWindowsXPSP2OrGreater(void) { +VERSIONHELPERAPI +IsWindowsXPSP2OrGreater(void) { return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 2); } -VERSIONHELPERAPI IsWindowsXPSP3OrGreater(void) { +VERSIONHELPERAPI +IsWindowsXPSP3OrGreater(void) { return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 3); } -VERSIONHELPERAPI IsWindowsVistaOrGreater(void) { +VERSIONHELPERAPI +IsWindowsVistaOrGreater(void) { return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 0); } -VERSIONHELPERAPI IsWindowsVistaSP1OrGreater(void) { +VERSIONHELPERAPI +IsWindowsVistaSP1OrGreater(void) { return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 1); } -VERSIONHELPERAPI IsWindowsVistaSP2OrGreater(void) { +VERSIONHELPERAPI +IsWindowsVistaSP2OrGreater(void) { return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 2); } -VERSIONHELPERAPI IsWindows7OrGreater(void) { +VERSIONHELPERAPI +IsWindows7OrGreater(void) { return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN7), LOBYTE(_WIN32_WINNT_WIN7), 0); } -VERSIONHELPERAPI IsWindows7SP1OrGreater(void) { +VERSIONHELPERAPI +IsWindows7SP1OrGreater(void) { return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN7), LOBYTE(_WIN32_WINNT_WIN7), 1); } -VERSIONHELPERAPI IsWindows8OrGreater(void) { +VERSIONHELPERAPI +IsWindows8OrGreater(void) { return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN8), LOBYTE(_WIN32_WINNT_WIN8), 0); } -VERSIONHELPERAPI IsWindows8Point1OrGreater(void) { +VERSIONHELPERAPI +IsWindows8Point1OrGreater(void) { return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINBLUE), LOBYTE(_WIN32_WINNT_WINBLUE), 0); } -VERSIONHELPERAPI IsWindowsServer(void) { +VERSIONHELPERAPI +IsWindowsServer(void) { OSVERSIONINFOEXW vi = {sizeof(vi),0,0,0,0,{0},0,0,0,VER_NT_WORKSTATION}; return !VerifyVersionInfoW(&vi, VER_PRODUCT_TYPE, VerSetConditionMask(0, VER_PRODUCT_TYPE, VER_EQUAL)); } -#endif -#endif +#endif /* if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && !defined(__WIDL__) */ +#endif /* ifndef _INC_VERSIONHELPERS */ diff --git a/src/compat/compat.h b/src/compat/compat.h index 021573eb9eb..75bfaeda850 100644 --- a/src/compat/compat.h +++ b/src/compat/compat.h @@ -42,27 +42,33 @@ #endif #ifndef HAVE_DIRNAME -char * dirname(char *str); +char *dirname(char *str); + #endif /* HAVE_DIRNAME */ #ifndef HAVE_BASENAME -char * basename(char *str); +char *basename(char *str); + #endif /* HAVE_BASENAME */ #ifndef HAVE_GETTIMEOFDAY -int gettimeofday (struct timeval *tv, void *tz); +int gettimeofday(struct timeval *tv, void *tz); + #endif #ifndef HAVE_DAEMON int daemon(int nochdir, int noclose); + #endif #ifndef HAVE_INET_NTOP -const char * inet_ntop(int af, const void *src, char *dst, socklen_t size); +const char *inet_ntop(int af, const void *src, char *dst, socklen_t size); + #endif #ifndef HAVE_INET_PTON int inet_pton(int af, const char *src, void *dst); + #endif #endif /* COMPAT_H */ diff --git a/src/openvpn/argv.c b/src/openvpn/argv.c index 596e59c93e7..27cda0c6254 100644 --- a/src/openvpn/argv.c +++ b/src/openvpn/argv.c @@ -40,276 +40,304 @@ #include "options.h" static void -argv_init (struct argv *a) +argv_init(struct argv *a) { - a->capacity = 0; - a->argc = 0; - a->argv = NULL; + a->capacity = 0; + a->argc = 0; + a->argv = NULL; } struct argv -argv_new (void) +argv_new(void) { - struct argv ret; - argv_init (&ret); - return ret; + struct argv ret; + argv_init(&ret); + return ret; } void -argv_reset (struct argv *a) +argv_reset(struct argv *a) { - size_t i; - for (i = 0; i < a->argc; ++i) - free (a->argv[i]); - free (a->argv); - argv_init (a); + size_t i; + for (i = 0; i < a->argc; ++i) + free(a->argv[i]); + free(a->argv); + argv_init(a); } static void -argv_extend (struct argv *a, const size_t newcap) +argv_extend(struct argv *a, const size_t newcap) { - if (newcap > a->capacity) + if (newcap > a->capacity) { - char **newargv; - size_t i; - ALLOC_ARRAY_CLEAR (newargv, char *, newcap); - for (i = 0; i < a->argc; ++i) - newargv[i] = a->argv[i]; - free (a->argv); - a->argv = newargv; - a->capacity = newcap; + char **newargv; + size_t i; + ALLOC_ARRAY_CLEAR(newargv, char *, newcap); + for (i = 0; i < a->argc; ++i) + newargv[i] = a->argv[i]; + free(a->argv); + a->argv = newargv; + a->capacity = newcap; } } static void -argv_grow (struct argv *a, const size_t add) +argv_grow(struct argv *a, const size_t add) { - const size_t newargc = a->argc + add + 1; - ASSERT (newargc > a->argc); - argv_extend (a, adjust_power_of_2 (newargc)); + const size_t newargc = a->argc + add + 1; + ASSERT(newargc > a->argc); + argv_extend(a, adjust_power_of_2(newargc)); } static void -argv_append (struct argv *a, char *str) /* str must have been malloced or be NULL */ +argv_append(struct argv *a, char *str) /* str must have been malloced or be NULL */ { - argv_grow (a, 1); - a->argv[a->argc++] = str; + argv_grow(a, 1); + a->argv[a->argc++] = str; } static struct argv -argv_clone (const struct argv *a, const size_t headroom) +argv_clone(const struct argv *a, const size_t headroom) { - struct argv r; - size_t i; + struct argv r; + size_t i; - argv_init (&r); - for (i = 0; i < headroom; ++i) - argv_append (&r, NULL); - if (a) + argv_init(&r); + for (i = 0; i < headroom; ++i) + argv_append(&r, NULL); + if (a) { - for (i = 0; i < a->argc; ++i) - argv_append (&r, string_alloc (a->argv[i], NULL)); + for (i = 0; i < a->argc; ++i) + argv_append(&r, string_alloc(a->argv[i], NULL)); } - return r; + return r; } struct argv -argv_insert_head (const struct argv *a, const char *head) +argv_insert_head(const struct argv *a, const char *head) { - struct argv r; - r = argv_clone (a, 1); - r.argv[0] = string_alloc (head, NULL); - return r; + struct argv r; + r = argv_clone(a, 1); + r.argv[0] = string_alloc(head, NULL); + return r; } static char * -argv_term (const char **f) +argv_term(const char **f) { - const char *p = *f; - const char *term = NULL; - size_t termlen = 0; + const char *p = *f; + const char *term = NULL; + size_t termlen = 0; - if (*p == '\0') - return NULL; + if (*p == '\0') + { + return NULL; + } - while (true) + while (true) { - const int c = *p; - if (c == '\0') - break; - if (term) + const int c = *p; + if (c == '\0') { - if (!isspace (c)) - ++termlen; - else break; } - else + if (term) + { + if (!isspace(c)) + { + ++termlen; + } + else + { + break; + } + } + else { - if (!isspace (c)) + if (!isspace(c)) { - term = p; - termlen = 1; + term = p; + termlen = 1; } } - ++p; + ++p; } - *f = p; + *f = p; - if (term) + if (term) + { + char *ret; + ASSERT(termlen > 0); + ret = malloc(termlen + 1); + check_malloc_return(ret); + memcpy(ret, term, termlen); + ret[termlen] = '\0'; + return ret; + } + else { - char *ret; - ASSERT (termlen > 0); - ret = malloc (termlen + 1); - check_malloc_return (ret); - memcpy (ret, term, termlen); - ret[termlen] = '\0'; - return ret; + return NULL; } - else - return NULL; } const char * -argv_str (const struct argv *a, struct gc_arena *gc, const unsigned int flags) +argv_str(const struct argv *a, struct gc_arena *gc, const unsigned int flags) { - if (a->argv) - return print_argv ((const char **)a->argv, gc, flags); - else - return ""; + if (a->argv) + { + return print_argv((const char **)a->argv, gc, flags); + } + else + { + return ""; + } } void -argv_msg (const int msglev, const struct argv *a) +argv_msg(const int msglev, const struct argv *a) { - struct gc_arena gc = gc_new (); - msg (msglev, "%s", argv_str (a, &gc, 0)); - gc_free (&gc); + struct gc_arena gc = gc_new(); + msg(msglev, "%s", argv_str(a, &gc, 0)); + gc_free(&gc); } void -argv_msg_prefix (const int msglev, const struct argv *a, const char *prefix) +argv_msg_prefix(const int msglev, const struct argv *a, const char *prefix) { - struct gc_arena gc = gc_new (); - msg (msglev, "%s: %s", prefix, argv_str (a, &gc, 0)); - gc_free (&gc); + struct gc_arena gc = gc_new(); + msg(msglev, "%s: %s", prefix, argv_str(a, &gc, 0)); + gc_free(&gc); } static void -argv_printf_arglist (struct argv *a, const char *format, va_list arglist) +argv_printf_arglist(struct argv *a, const char *format, va_list arglist) { - char *term; - const char *f = format; + char *term; + const char *f = format; - argv_extend (a, 1); /* ensure trailing NULL */ + argv_extend(a, 1); /* ensure trailing NULL */ - while ((term = argv_term (&f)) != NULL) + while ((term = argv_term(&f)) != NULL) { - if (term[0] == '%') + if (term[0] == '%') { - if (!strcmp (term, "%s")) + if (!strcmp(term, "%s")) { - char *s = va_arg (arglist, char *); - if (!s) - s = ""; - argv_append (a, string_alloc (s, NULL)); + char *s = va_arg(arglist, char *); + if (!s) + { + s = ""; + } + argv_append(a, string_alloc(s, NULL)); } - else if (!strcmp (term, "%d")) + else if (!strcmp(term, "%d")) { - char numstr[64]; - openvpn_snprintf (numstr, sizeof (numstr), "%d", va_arg (arglist, int)); - argv_append (a, string_alloc (numstr, NULL)); + char numstr[64]; + openvpn_snprintf(numstr, sizeof(numstr), "%d", va_arg(arglist, int)); + argv_append(a, string_alloc(numstr, NULL)); } - else if (!strcmp (term, "%u")) + else if (!strcmp(term, "%u")) { - char numstr[64]; - openvpn_snprintf (numstr, sizeof (numstr), "%u", va_arg (arglist, unsigned int)); - argv_append (a, string_alloc (numstr, NULL)); + char numstr[64]; + openvpn_snprintf(numstr, sizeof(numstr), "%u", va_arg(arglist, unsigned int)); + argv_append(a, string_alloc(numstr, NULL)); } - else if (!strcmp (term, "%s/%d")) + else if (!strcmp(term, "%s/%d")) { - char numstr[64]; - char *s = va_arg (arglist, char *); - - if (!s) - s = ""; - - openvpn_snprintf (numstr, sizeof (numstr), "%d", va_arg (arglist, int)); - - { - const size_t len = strlen(s) + strlen(numstr) + 2; - char *combined = (char *) malloc (len); - check_malloc_return (combined); - - strcpy (combined, s); - strcat (combined, "/"); - strcat (combined, numstr); - argv_append (a, combined); - } + char numstr[64]; + char *s = va_arg(arglist, char *); + + if (!s) + { + s = ""; + } + + openvpn_snprintf(numstr, sizeof(numstr), "%d", va_arg(arglist, int)); + + { + const size_t len = strlen(s) + strlen(numstr) + 2; + char *combined = (char *) malloc(len); + check_malloc_return(combined); + + strcpy(combined, s); + strcat(combined, "/"); + strcat(combined, numstr); + argv_append(a, combined); + } } - else if (!strcmp (term, "%s%sc")) + else if (!strcmp(term, "%s%sc")) { - char *s1 = va_arg (arglist, char *); - char *s2 = va_arg (arglist, char *); - char *combined; - - if (!s1) s1 = ""; - if (!s2) s2 = ""; - combined = (char *) malloc (strlen(s1) + strlen(s2) + 1); - check_malloc_return (combined); - strcpy (combined, s1); - strcat (combined, s2); - argv_append (a, combined); + char *s1 = va_arg(arglist, char *); + char *s2 = va_arg(arglist, char *); + char *combined; + + if (!s1) + { + s1 = ""; + } + if (!s2) + { + s2 = ""; + } + combined = (char *) malloc(strlen(s1) + strlen(s2) + 1); + check_malloc_return(combined); + strcpy(combined, s1); + strcat(combined, s2); + argv_append(a, combined); } - else - ASSERT (0); - free (term); + else + { + ASSERT(0); + } + free(term); } - else + else { - argv_append (a, term); + argv_append(a, term); } } } void -argv_printf (struct argv *a, const char *format, ...) +argv_printf(struct argv *a, const char *format, ...) { - va_list arglist; - argv_reset (a); - va_start (arglist, format); - argv_printf_arglist (a, format, arglist); - va_end (arglist); - } + va_list arglist; + argv_reset(a); + va_start(arglist, format); + argv_printf_arglist(a, format, arglist); + va_end(arglist); +} void -argv_printf_cat (struct argv *a, const char *format, ...) +argv_printf_cat(struct argv *a, const char *format, ...) { - va_list arglist; - va_start (arglist, format); - argv_printf_arglist (a, format, arglist); - va_end (arglist); + va_list arglist; + va_start(arglist, format); + argv_printf_arglist(a, format, arglist); + va_end(arglist); } void -argv_parse_cmd (struct argv *a, const char *s) +argv_parse_cmd(struct argv *a, const char *s) { - int nparms; - char *parms[MAX_PARMS + 1]; - struct gc_arena gc = gc_new (); + int nparms; + char *parms[MAX_PARMS + 1]; + struct gc_arena gc = gc_new(); - argv_reset (a); - argv_extend (a, 1); /* ensure trailing NULL */ + argv_reset(a); + argv_extend(a, 1); /* ensure trailing NULL */ - nparms = parse_line (s, parms, MAX_PARMS, "SCRIPT-ARGV", 0, D_ARGV_PARSE_CMD, &gc); - if (nparms) + nparms = parse_line(s, parms, MAX_PARMS, "SCRIPT-ARGV", 0, D_ARGV_PARSE_CMD, &gc); + if (nparms) + { + int i; + for (i = 0; i < nparms; ++i) + argv_append(a, string_alloc(parms[i], NULL)); + } + else { - int i; - for (i = 0; i < nparms; ++i) - argv_append (a, string_alloc (parms[i], NULL)); + argv_append(a, string_alloc(s, NULL)); } - else - argv_append (a, string_alloc (s, NULL)); - gc_free (&gc); + gc_free(&gc); } diff --git a/src/openvpn/argv.h b/src/openvpn/argv.h index 9aee641a698..8e263e1eb12 100644 --- a/src/openvpn/argv.h +++ b/src/openvpn/argv.h @@ -34,37 +34,43 @@ #include "buffer.h" struct argv { - size_t capacity; - size_t argc; - char **argv; + size_t capacity; + size_t argc; + char **argv; }; -struct argv argv_new (void); -void argv_reset (struct argv *a); -const char *argv_str (const struct argv *a, struct gc_arena *gc, const unsigned int flags); -struct argv argv_insert_head (const struct argv *a, const char *head); -void argv_msg (const int msglev, const struct argv *a); -void argv_msg_prefix (const int msglev, const struct argv *a, const char *prefix); -void argv_parse_cmd (struct argv *a, const char *s); +struct argv argv_new(void); -void argv_printf (struct argv *a, const char *format, ...) +void argv_reset(struct argv *a); + +const char *argv_str(const struct argv *a, struct gc_arena *gc, const unsigned int flags); + +struct argv argv_insert_head(const struct argv *a, const char *head); + +void argv_msg(const int msglev, const struct argv *a); + +void argv_msg_prefix(const int msglev, const struct argv *a, const char *prefix); + +void argv_parse_cmd(struct argv *a, const char *s); + +void argv_printf(struct argv *a, const char *format, ...) #ifdef __GNUC__ #if __USE_MINGW_ANSI_STDIO - __attribute__ ((format (gnu_printf, 2, 3))) +__attribute__ ((format(gnu_printf, 2, 3))) #else - __attribute__ ((format (__printf__, 2, 3))) +__attribute__ ((format(__printf__, 2, 3))) #endif #endif - ; +; -void argv_printf_cat (struct argv *a, const char *format, ...) +void argv_printf_cat(struct argv *a, const char *format, ...) #ifdef __GNUC__ #if __USE_MINGW_ANSI_STDIO - __attribute__ ((format (gnu_printf, 2, 3))) +__attribute__ ((format(gnu_printf, 2, 3))) #else - __attribute__ ((format (__printf__, 2, 3))) +__attribute__ ((format(__printf__, 2, 3))) #endif #endif - ; +; -#endif +#endif /* ifndef ARGV_H */ diff --git a/src/openvpn/base64.c b/src/openvpn/base64.c index 258b258e20c..c799ede17f6 100644 --- a/src/openvpn/base64.c +++ b/src/openvpn/base64.c @@ -43,14 +43,14 @@ #include "memdbg.h" -static char base64_chars[] = +static char base64_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /* * base64 encode input data of length size to malloced * buffer which is returned as *str. Returns string * length of *str. */ -int +int openvpn_base64_encode(const void *data, int size, char **str) { char *s, *p; @@ -59,44 +59,58 @@ openvpn_base64_encode(const void *data, int size, char **str) const unsigned char *q; if (size < 0) - return -1; + { + return -1; + } p = s = (char *) malloc(size * 4 / 3 + 4); if (p == NULL) - return -1; + { + return -1; + } q = (const unsigned char *) data; i = 0; - for (i = 0; i < size;) { - c = q[i++]; - c *= 256; - if (i < size) - c += q[i]; - i++; - c *= 256; - if (i < size) - c += q[i]; - i++; - p[0] = base64_chars[(c & 0x00fc0000) >> 18]; - p[1] = base64_chars[(c & 0x0003f000) >> 12]; - p[2] = base64_chars[(c & 0x00000fc0) >> 6]; - p[3] = base64_chars[(c & 0x0000003f) >> 0]; - if (i > size) - p[3] = '='; - if (i > size + 1) - p[2] = '='; - p += 4; + for (i = 0; i < size; ) { + c = q[i++]; + c *= 256; + if (i < size) + { + c += q[i]; + } + i++; + c *= 256; + if (i < size) + { + c += q[i]; + } + i++; + p[0] = base64_chars[(c & 0x00fc0000) >> 18]; + p[1] = base64_chars[(c & 0x0003f000) >> 12]; + p[2] = base64_chars[(c & 0x00000fc0) >> 6]; + p[3] = base64_chars[(c & 0x0000003f) >> 0]; + if (i > size) + { + p[3] = '='; + } + if (i > size + 1) + { + p[2] = '='; + } + p += 4; } *p = 0; *str = s; return strlen(s); } -static int +static int pos(char c) { char *p; for (p = base64_chars; *p; p++) - if (*p == c) - return p - base64_chars; + if (*p == c) + { + return p - base64_chars; + } return -1; } @@ -109,18 +123,28 @@ token_decode(const char *token) unsigned int val = 0; int marker = 0; if (!token[0] || !token[1] || !token[2] || !token[3]) - return DECODE_ERROR; + { + return DECODE_ERROR; + } for (i = 0; i < 4; i++) { - val *= 64; - if (token[i] == '=') - marker++; - else if (marker > 0) - return DECODE_ERROR; - else - val += pos(token[i]); + val *= 64; + if (token[i] == '=') + { + marker++; + } + else if (marker > 0) + { + return DECODE_ERROR; + } + else + { + val += pos(token[i]); + } } if (marker > 2) - return DECODE_ERROR; + { + return DECODE_ERROR; + } return (marker << 24) | val; } /* @@ -137,27 +161,37 @@ openvpn_base64_decode(const char *str, void *data, int size) q = data; if (size >= 0) - e = q + size; + { + e = q + size; + } for (p = str; *p && (*p == '=' || strchr(base64_chars, *p)); p += 4) { - unsigned int val = token_decode(p); - unsigned int marker = (val >> 24) & 0xff; - if (val == DECODE_ERROR) - return -1; - if (e && q >= e) - return -1; - *q++ = (val >> 16) & 0xff; - if (marker < 2) - { - if (e && q >= e) - return -1; - *q++ = (val >> 8) & 0xff; - } - if (marker < 1) - { - if (e && q >= e) - return -1; - *q++ = val & 0xff; - } + unsigned int val = token_decode(p); + unsigned int marker = (val >> 24) & 0xff; + if (val == DECODE_ERROR) + { + return -1; + } + if (e && q >= e) + { + return -1; + } + *q++ = (val >> 16) & 0xff; + if (marker < 2) + { + if (e && q >= e) + { + return -1; + } + *q++ = (val >> 8) & 0xff; + } + if (marker < 1) + { + if (e && q >= e) + { + return -1; + } + *q++ = val & 0xff; + } } return q - (unsigned char *) data; } diff --git a/src/openvpn/base64.h b/src/openvpn/base64.h index 92a195aa4c0..5679bc90ff6 100644 --- a/src/openvpn/base64.h +++ b/src/openvpn/base64.h @@ -2,22 +2,22 @@ * Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: - * + * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * + * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * + * * 3. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -35,6 +35,7 @@ #define _BASE64_H_ int openvpn_base64_encode(const void *data, int size, char **str); + int openvpn_base64_decode(const char *str, void *data, int size); #endif diff --git a/src/openvpn/block_dns.c b/src/openvpn/block_dns.c index cb3ce88e2b7..81c2929bbb0 100644 --- a/src/openvpn/block_dns.c +++ b/src/openvpn/block_dns.c @@ -53,60 +53,60 @@ #define FWPM_SESSION_FLAG_DYNAMIC 0x00000001 #endif -// c38d57d1-05a7-4c33-904f-7fbceee60e82 +/* c38d57d1-05a7-4c33-904f-7fbceee60e82 */ DEFINE_GUID( - FWPM_LAYER_ALE_AUTH_CONNECT_V4, - 0xc38d57d1, - 0x05a7, - 0x4c33, - 0x90, 0x4f, 0x7f, 0xbc, 0xee, 0xe6, 0x0e, 0x82 -); - -// 4a72393b-319f-44bc-84c3-ba54dcb3b6b4 + FWPM_LAYER_ALE_AUTH_CONNECT_V4, + 0xc38d57d1, + 0x05a7, + 0x4c33, + 0x90, 0x4f, 0x7f, 0xbc, 0xee, 0xe6, 0x0e, 0x82 + ); + +/* 4a72393b-319f-44bc-84c3-ba54dcb3b6b4 */ DEFINE_GUID( - FWPM_LAYER_ALE_AUTH_CONNECT_V6, - 0x4a72393b, - 0x319f, - 0x44bc, - 0x84, 0xc3, 0xba, 0x54, 0xdc, 0xb3, 0xb6, 0xb4 -); - -// d78e1e87-8644-4ea5-9437-d809ecefc971 + FWPM_LAYER_ALE_AUTH_CONNECT_V6, + 0x4a72393b, + 0x319f, + 0x44bc, + 0x84, 0xc3, 0xba, 0x54, 0xdc, 0xb3, 0xb6, 0xb4 + ); + +/* d78e1e87-8644-4ea5-9437-d809ecefc971 */ DEFINE_GUID( - FWPM_CONDITION_ALE_APP_ID, - 0xd78e1e87, - 0x8644, - 0x4ea5, - 0x94, 0x37, 0xd8, 0x09, 0xec, 0xef, 0xc9, 0x71 -); - -// c35a604d-d22b-4e1a-91b4-68f674ee674b + FWPM_CONDITION_ALE_APP_ID, + 0xd78e1e87, + 0x8644, + 0x4ea5, + 0x94, 0x37, 0xd8, 0x09, 0xec, 0xef, 0xc9, 0x71 + ); + +/* c35a604d-d22b-4e1a-91b4-68f674ee674b */ DEFINE_GUID( - FWPM_CONDITION_IP_REMOTE_PORT, - 0xc35a604d, - 0xd22b, - 0x4e1a, - 0x91, 0xb4, 0x68, 0xf6, 0x74, 0xee, 0x67, 0x4b -); - -// 4cd62a49-59c3-4969-b7f3-bda5d32890a4 + FWPM_CONDITION_IP_REMOTE_PORT, + 0xc35a604d, + 0xd22b, + 0x4e1a, + 0x91, 0xb4, 0x68, 0xf6, 0x74, 0xee, 0x67, 0x4b + ); + +/* 4cd62a49-59c3-4969-b7f3-bda5d32890a4 */ DEFINE_GUID( - FWPM_CONDITION_IP_LOCAL_INTERFACE, - 0x4cd62a49, - 0x59c3, - 0x4969, - 0xb7, 0xf3, 0xbd, 0xa5, 0xd3, 0x28, 0x90, 0xa4 -); + FWPM_CONDITION_IP_LOCAL_INTERFACE, + 0x4cd62a49, + 0x59c3, + 0x4969, + 0xb7, 0xf3, 0xbd, 0xa5, 0xd3, 0x28, 0x90, 0xa4 + ); /* UUID of WFP sublayer used by all instances of openvpn - 2f660d7e-6a37-11e6-a181-001e8c6e04a2 */ + * 2f660d7e-6a37-11e6-a181-001e8c6e04a2 */ DEFINE_GUID( - OPENVPN_BLOCK_OUTSIDE_DNS_SUBLAYER, - 0x2f660d7e, - 0x6a37, - 0x11e6, - 0xa1, 0x81, 0x00, 0x1e, 0x8c, 0x6e, 0x04, 0xa2 -); + OPENVPN_BLOCK_OUTSIDE_DNS_SUBLAYER, + 0x2f660d7e, + 0x6a37, + 0x11e6, + 0xa1, 0x81, 0x00, 0x1e, 0x8c, 0x6e, 0x04, 0xa2 + ); static WCHAR *FIREWALL_NAME = L"OpenVPN"; @@ -114,45 +114,49 @@ static WCHAR *FIREWALL_NAME = L"OpenVPN"; * Default msg handler does nothing */ static inline void -default_msg_handler (DWORD err, const char *msg) +default_msg_handler(DWORD err, const char *msg) { - return; + return; } #define CHECK_ERROR(err, msg) \ - if (err) { msg_handler (err, msg); goto out; } + if (err) { msg_handler(err, msg); goto out; } /* * Add a persistent sublayer with specified uuid. */ static DWORD -add_sublayer (GUID uuid) +add_sublayer(GUID uuid) { - FWPM_SESSION0 session; - HANDLE engine = NULL; - DWORD err = 0; - FWPM_SUBLAYER0 sublayer; + FWPM_SESSION0 session; + HANDLE engine = NULL; + DWORD err = 0; + FWPM_SUBLAYER0 sublayer; - memset (&session, 0, sizeof(session)); - memset (&sublayer, 0, sizeof(sublayer)); + memset(&session, 0, sizeof(session)); + memset(&sublayer, 0, sizeof(sublayer)); - err = FwpmEngineOpen0 (NULL, RPC_C_AUTHN_WINNT, NULL, &session, &engine); - if (err != ERROR_SUCCESS) - goto out; + err = FwpmEngineOpen0(NULL, RPC_C_AUTHN_WINNT, NULL, &session, &engine); + if (err != ERROR_SUCCESS) + { + goto out; + } - sublayer.subLayerKey = uuid; - sublayer.displayData.name = FIREWALL_NAME; - sublayer.displayData.description = FIREWALL_NAME; - sublayer.flags = 0; - sublayer.weight = 0x100; + sublayer.subLayerKey = uuid; + sublayer.displayData.name = FIREWALL_NAME; + sublayer.displayData.description = FIREWALL_NAME; + sublayer.flags = 0; + sublayer.weight = 0x100; - /* Add sublayer to the session */ - err = FwpmSubLayerAdd0 (engine, &sublayer, NULL); + /* Add sublayer to the session */ + err = FwpmSubLayerAdd0(engine, &sublayer, NULL); out: - if (engine) - FwpmEngineClose0 (engine); - return err; + if (engine) + { + FwpmEngineClose0(engine); + } + return err; } /* @@ -173,160 +177,168 @@ add_sublayer (GUID uuid) */ DWORD -add_block_dns_filters (HANDLE *engine_handle, - int index, - const WCHAR *exe_path, - block_dns_msg_handler_t msg_handler +add_block_dns_filters(HANDLE *engine_handle, + int index, + const WCHAR *exe_path, + block_dns_msg_handler_t msg_handler ) { - FWPM_SESSION0 session = {0}; - FWPM_SUBLAYER0 *sublayer_ptr = NULL; - NET_LUID tapluid; - UINT64 filterid; - FWP_BYTE_BLOB *openvpnblob = NULL; - FWPM_FILTER0 Filter = {0}; - FWPM_FILTER_CONDITION0 Condition[2] = {0}; - DWORD err = 0; - - if (!msg_handler) - msg_handler = default_msg_handler; - - /* Add temporary filters which don't survive reboots or crashes. */ - session.flags = FWPM_SESSION_FLAG_DYNAMIC; - - *engine_handle = NULL; - - err = FwpmEngineOpen0 (NULL, RPC_C_AUTHN_WINNT, NULL, &session, engine_handle); - CHECK_ERROR (err, "FwpEngineOpen: open fwp session failed"); - msg_handler (0, "Block_DNS: WFP engine opened"); - - /* Check sublayer exists and add one if it does not. */ - if (FwpmSubLayerGetByKey0 (*engine_handle, &OPENVPN_BLOCK_OUTSIDE_DNS_SUBLAYER, &sublayer_ptr) - == ERROR_SUCCESS) + FWPM_SESSION0 session = {0}; + FWPM_SUBLAYER0 *sublayer_ptr = NULL; + NET_LUID tapluid; + UINT64 filterid; + FWP_BYTE_BLOB *openvpnblob = NULL; + FWPM_FILTER0 Filter = {0}; + FWPM_FILTER_CONDITION0 Condition[2] = {0}; + DWORD err = 0; + + if (!msg_handler) { - msg_handler (0, "Block_DNS: Using existing sublayer"); - FwpmFreeMemory0 ((void **)&sublayer_ptr); + msg_handler = default_msg_handler; } - else - { /* Add a new sublayer -- as another process may add it in the meantime, - do not treat "already exists" as an error */ - err = add_sublayer (OPENVPN_BLOCK_OUTSIDE_DNS_SUBLAYER); - if (err == FWP_E_ALREADY_EXISTS || err == ERROR_SUCCESS) - msg_handler (0, "Block_DNS: Added a persistent sublayer with pre-defined UUID"); - else - CHECK_ERROR (err, "add_sublayer: failed to add persistent sublayer"); + /* Add temporary filters which don't survive reboots or crashes. */ + session.flags = FWPM_SESSION_FLAG_DYNAMIC; + + *engine_handle = NULL; + + err = FwpmEngineOpen0(NULL, RPC_C_AUTHN_WINNT, NULL, &session, engine_handle); + CHECK_ERROR(err, "FwpEngineOpen: open fwp session failed"); + msg_handler(0, "Block_DNS: WFP engine opened"); + + /* Check sublayer exists and add one if it does not. */ + if (FwpmSubLayerGetByKey0(*engine_handle, &OPENVPN_BLOCK_OUTSIDE_DNS_SUBLAYER, &sublayer_ptr) + == ERROR_SUCCESS) + { + msg_handler(0, "Block_DNS: Using existing sublayer"); + FwpmFreeMemory0((void **)&sublayer_ptr); + } + else + { /* Add a new sublayer -- as another process may add it in the meantime, + * do not treat "already exists" as an error */ + err = add_sublayer(OPENVPN_BLOCK_OUTSIDE_DNS_SUBLAYER); + + if (err == FWP_E_ALREADY_EXISTS || err == ERROR_SUCCESS) + { + msg_handler(0, "Block_DNS: Added a persistent sublayer with pre-defined UUID"); + } + else + { + CHECK_ERROR(err, "add_sublayer: failed to add persistent sublayer"); + } } - err = ConvertInterfaceIndexToLuid (index, &tapluid); - CHECK_ERROR (err, "Convert interface index to luid failed"); + err = ConvertInterfaceIndexToLuid(index, &tapluid); + CHECK_ERROR(err, "Convert interface index to luid failed"); - err = FwpmGetAppIdFromFileName0 (exe_path, &openvpnblob); - CHECK_ERROR (err, "Get byte blob for openvpn executable name failed"); + err = FwpmGetAppIdFromFileName0(exe_path, &openvpnblob); + CHECK_ERROR(err, "Get byte blob for openvpn executable name failed"); - /* Prepare filter. */ - Filter.subLayerKey = OPENVPN_BLOCK_OUTSIDE_DNS_SUBLAYER; - Filter.displayData.name = FIREWALL_NAME; - Filter.weight.type = FWP_UINT8; - Filter.weight.uint8 = 0xF; - Filter.filterCondition = Condition; - Filter.numFilterConditions = 2; + /* Prepare filter. */ + Filter.subLayerKey = OPENVPN_BLOCK_OUTSIDE_DNS_SUBLAYER; + Filter.displayData.name = FIREWALL_NAME; + Filter.weight.type = FWP_UINT8; + Filter.weight.uint8 = 0xF; + Filter.filterCondition = Condition; + Filter.numFilterConditions = 2; - /* First filter. Permit IPv4 DNS queries from OpenVPN itself. */ - Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4; - Filter.action.type = FWP_ACTION_PERMIT; + /* First filter. Permit IPv4 DNS queries from OpenVPN itself. */ + Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4; + Filter.action.type = FWP_ACTION_PERMIT; - Condition[0].fieldKey = FWPM_CONDITION_IP_REMOTE_PORT; - Condition[0].matchType = FWP_MATCH_EQUAL; - Condition[0].conditionValue.type = FWP_UINT16; - Condition[0].conditionValue.uint16 = 53; + Condition[0].fieldKey = FWPM_CONDITION_IP_REMOTE_PORT; + Condition[0].matchType = FWP_MATCH_EQUAL; + Condition[0].conditionValue.type = FWP_UINT16; + Condition[0].conditionValue.uint16 = 53; - Condition[1].fieldKey = FWPM_CONDITION_ALE_APP_ID; - Condition[1].matchType = FWP_MATCH_EQUAL; - Condition[1].conditionValue.type = FWP_BYTE_BLOB_TYPE; - Condition[1].conditionValue.byteBlob = openvpnblob; + Condition[1].fieldKey = FWPM_CONDITION_ALE_APP_ID; + Condition[1].matchType = FWP_MATCH_EQUAL; + Condition[1].conditionValue.type = FWP_BYTE_BLOB_TYPE; + Condition[1].conditionValue.byteBlob = openvpnblob; - err = FwpmFilterAdd0(*engine_handle, &Filter, NULL, &filterid); - CHECK_ERROR (err, "Add filter to permit IPv4 port 53 traffic from OpenVPN failed"); + err = FwpmFilterAdd0(*engine_handle, &Filter, NULL, &filterid); + CHECK_ERROR(err, "Add filter to permit IPv4 port 53 traffic from OpenVPN failed"); - /* Second filter. Permit IPv6 DNS queries from OpenVPN itself. */ - Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V6; + /* Second filter. Permit IPv6 DNS queries from OpenVPN itself. */ + Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V6; - err = FwpmFilterAdd0(*engine_handle, &Filter, NULL, &filterid); - CHECK_ERROR (err, "Add filter to permit IPv6 port 53 traffic from OpenVPN failed"); + err = FwpmFilterAdd0(*engine_handle, &Filter, NULL, &filterid); + CHECK_ERROR(err, "Add filter to permit IPv6 port 53 traffic from OpenVPN failed"); - msg_handler (0, "Block_DNS: Added permit filters for exe_path"); + msg_handler(0, "Block_DNS: Added permit filters for exe_path"); - /* Third filter. Block all IPv4 DNS queries. */ - Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4; - Filter.action.type = FWP_ACTION_BLOCK; - Filter.weight.type = FWP_EMPTY; - Filter.numFilterConditions = 1; + /* Third filter. Block all IPv4 DNS queries. */ + Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4; + Filter.action.type = FWP_ACTION_BLOCK; + Filter.weight.type = FWP_EMPTY; + Filter.numFilterConditions = 1; - err = FwpmFilterAdd0(*engine_handle, &Filter, NULL, &filterid); - CHECK_ERROR (err, "Add filter to block IPv4 DNS traffic failed"); + err = FwpmFilterAdd0(*engine_handle, &Filter, NULL, &filterid); + CHECK_ERROR(err, "Add filter to block IPv4 DNS traffic failed"); - /* Forth filter. Block all IPv6 DNS queries. */ - Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V6; + /* Forth filter. Block all IPv6 DNS queries. */ + Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V6; - err = FwpmFilterAdd0(*engine_handle, &Filter, NULL, &filterid); - CHECK_ERROR (err, "Add filter to block IPv6 DNS traffic failed"); + err = FwpmFilterAdd0(*engine_handle, &Filter, NULL, &filterid); + CHECK_ERROR(err, "Add filter to block IPv6 DNS traffic failed"); - msg_handler (0, "Block_DNS: Added block filters for all interfaces"); + msg_handler(0, "Block_DNS: Added block filters for all interfaces"); - /* Fifth filter. Permit IPv4 DNS queries from TAP. - * Use a non-zero weight so that the permit filters get higher priority - * over the block filter added with automatic weighting */ + /* Fifth filter. Permit IPv4 DNS queries from TAP. + * Use a non-zero weight so that the permit filters get higher priority + * over the block filter added with automatic weighting */ - Filter.weight.type = FWP_UINT8; - Filter.weight.uint8 = 0xE; - Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4; - Filter.action.type = FWP_ACTION_PERMIT; - Filter.numFilterConditions = 2; + Filter.weight.type = FWP_UINT8; + Filter.weight.uint8 = 0xE; + Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4; + Filter.action.type = FWP_ACTION_PERMIT; + Filter.numFilterConditions = 2; - Condition[1].fieldKey = FWPM_CONDITION_IP_LOCAL_INTERFACE; - Condition[1].matchType = FWP_MATCH_EQUAL; - Condition[1].conditionValue.type = FWP_UINT64; - Condition[1].conditionValue.uint64 = &tapluid.Value; + Condition[1].fieldKey = FWPM_CONDITION_IP_LOCAL_INTERFACE; + Condition[1].matchType = FWP_MATCH_EQUAL; + Condition[1].conditionValue.type = FWP_UINT64; + Condition[1].conditionValue.uint64 = &tapluid.Value; - err = FwpmFilterAdd0(*engine_handle, &Filter, NULL, &filterid); - CHECK_ERROR (err, "Add filter to permit IPv4 DNS traffic through TAP failed"); + err = FwpmFilterAdd0(*engine_handle, &Filter, NULL, &filterid); + CHECK_ERROR(err, "Add filter to permit IPv4 DNS traffic through TAP failed"); - /* Sixth filter. Permit IPv6 DNS queries from TAP. - * Use same weight as IPv4 filter */ - Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V6; + /* Sixth filter. Permit IPv6 DNS queries from TAP. + * Use same weight as IPv4 filter */ + Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V6; - err = FwpmFilterAdd0(*engine_handle, &Filter, NULL, &filterid); - CHECK_ERROR (err, "Add filter to permit IPv6 DNS traffic through TAP failed"); + err = FwpmFilterAdd0(*engine_handle, &Filter, NULL, &filterid); + CHECK_ERROR(err, "Add filter to permit IPv6 DNS traffic through TAP failed"); - msg_handler (0, "Block_DNS: Added permit filters for TAP interface"); + msg_handler(0, "Block_DNS: Added permit filters for TAP interface"); out: - if (openvpnblob) - FwpmFreeMemory0 ((void **)&openvpnblob); + if (openvpnblob) + { + FwpmFreeMemory0((void **)&openvpnblob); + } - if (err && *engine_handle) + if (err && *engine_handle) { - FwpmEngineClose0 (*engine_handle); - *engine_handle = NULL; + FwpmEngineClose0(*engine_handle); + *engine_handle = NULL; } - return err; + return err; } DWORD -delete_block_dns_filters (HANDLE engine_handle) +delete_block_dns_filters(HANDLE engine_handle) { - DWORD err = 0; - /* - * For dynamic sessions closing the engine removes all filters added in the session - */ - if (engine_handle) + DWORD err = 0; + /* + * For dynamic sessions closing the engine removes all filters added in the session + */ + if (engine_handle) { - err = FwpmEngineClose0(engine_handle); + err = FwpmEngineClose0(engine_handle); } - return err; + return err; } -#endif +#endif /* ifdef _WIN32 */ diff --git a/src/openvpn/block_dns.h b/src/openvpn/block_dns.h index f8b6d4fbbc9..a7dadc46812 100644 --- a/src/openvpn/block_dns.h +++ b/src/openvpn/block_dns.h @@ -30,11 +30,11 @@ typedef void (*block_dns_msg_handler_t) (DWORD err, const char *msg); DWORD -delete_block_dns_filters (HANDLE engine); +delete_block_dns_filters(HANDLE engine); DWORD -add_block_dns_filters (HANDLE *engine, int iface_index, const WCHAR *exe_path, - block_dns_msg_handler_t msg_handler_callback); +add_block_dns_filters(HANDLE *engine, int iface_index, const WCHAR *exe_path, + block_dns_msg_handler_t msg_handler_callback); #endif #endif diff --git a/src/openvpn/buffer.c b/src/openvpn/buffer.c index 6af8dbb037f..b1d2fbf739f 100644 --- a/src/openvpn/buffer.c +++ b/src/openvpn/buffer.c @@ -39,216 +39,230 @@ #include "memdbg.h" size_t -array_mult_safe (const size_t m1, const size_t m2, const size_t extra) +array_mult_safe(const size_t m1, const size_t m2, const size_t extra) { - const size_t limit = 0xFFFFFFFF; - unsigned long long res = (unsigned long long)m1 * (unsigned long long)m2 + (unsigned long long)extra; - if (unlikely(m1 > limit) || unlikely(m2 > limit) || unlikely(extra > limit) || unlikely(res > (unsigned long long)limit)) - msg (M_FATAL, "attemped allocation of excessively large array"); - return (size_t) res; + const size_t limit = 0xFFFFFFFF; + unsigned long long res = (unsigned long long)m1 * (unsigned long long)m2 + (unsigned long long)extra; + if (unlikely(m1 > limit) || unlikely(m2 > limit) || unlikely(extra > limit) || unlikely(res > (unsigned long long)limit)) + { + msg(M_FATAL, "attemped allocation of excessively large array"); + } + return (size_t) res; } void -buf_size_error (const size_t size) +buf_size_error(const size_t size) { - msg (M_FATAL, "fatal buffer size error, size=%lu", (unsigned long)size); + msg(M_FATAL, "fatal buffer size error, size=%lu", (unsigned long)size); } struct buffer #ifdef DMALLOC -alloc_buf_debug (size_t size, const char *file, int line) +alloc_buf_debug(size_t size, const char *file, int line) #else -alloc_buf (size_t size) +alloc_buf(size_t size) #endif { - struct buffer buf; + struct buffer buf; - if (!buf_size_valid (size)) - buf_size_error (size); - buf.capacity = (int)size; - buf.offset = 0; - buf.len = 0; + if (!buf_size_valid(size)) + { + buf_size_error(size); + } + buf.capacity = (int)size; + buf.offset = 0; + buf.len = 0; #ifdef DMALLOC - buf.data = openvpn_dmalloc (file, line, size); + buf.data = openvpn_dmalloc(file, line, size); #else - buf.data = calloc (1, size); + buf.data = calloc(1, size); #endif - check_malloc_return(buf.data); + check_malloc_return(buf.data); - return buf; + return buf; } struct buffer #ifdef DMALLOC -alloc_buf_gc_debug (size_t size, struct gc_arena *gc, const char *file, int line) +alloc_buf_gc_debug(size_t size, struct gc_arena *gc, const char *file, int line) #else -alloc_buf_gc (size_t size, struct gc_arena *gc) +alloc_buf_gc(size_t size, struct gc_arena *gc) #endif { - struct buffer buf; - if (!buf_size_valid (size)) - buf_size_error (size); - buf.capacity = (int)size; - buf.offset = 0; - buf.len = 0; + struct buffer buf; + if (!buf_size_valid(size)) + { + buf_size_error(size); + } + buf.capacity = (int)size; + buf.offset = 0; + buf.len = 0; #ifdef DMALLOC - buf.data = (uint8_t *) gc_malloc_debug (size, false, gc, file, line); + buf.data = (uint8_t *) gc_malloc_debug(size, false, gc, file, line); #else - buf.data = (uint8_t *) gc_malloc (size, false, gc); + buf.data = (uint8_t *) gc_malloc(size, false, gc); #endif - if (size) - *buf.data = 0; - return buf; + if (size) + { + *buf.data = 0; + } + return buf; } struct buffer #ifdef DMALLOC -clone_buf_debug (const struct buffer* buf, const char *file, int line) +clone_buf_debug(const struct buffer *buf, const char *file, int line) #else -clone_buf (const struct buffer* buf) +clone_buf(const struct buffer *buf) #endif { - struct buffer ret; - ret.capacity = buf->capacity; - ret.offset = buf->offset; - ret.len = buf->len; + struct buffer ret; + ret.capacity = buf->capacity; + ret.offset = buf->offset; + ret.len = buf->len; #ifdef DMALLOC - ret.data = (uint8_t *) openvpn_dmalloc (file, line, buf->capacity); + ret.data = (uint8_t *) openvpn_dmalloc(file, line, buf->capacity); #else - ret.data = (uint8_t *) malloc (buf->capacity); + ret.data = (uint8_t *) malloc(buf->capacity); #endif - check_malloc_return (ret.data); - memcpy (BPTR (&ret), BPTR (buf), BLEN (buf)); - return ret; + check_malloc_return(ret.data); + memcpy(BPTR(&ret), BPTR(buf), BLEN(buf)); + return ret; } #ifdef BUF_INIT_TRACKING bool -buf_init_debug (struct buffer *buf, int offset, const char *file, int line) +buf_init_debug(struct buffer *buf, int offset, const char *file, int line) { - buf->debug_file = file; - buf->debug_line = line; - return buf_init_dowork (buf, offset); + buf->debug_file = file; + buf->debug_line = line; + return buf_init_dowork(buf, offset); } static inline int -buf_debug_line (const struct buffer *buf) +buf_debug_line(const struct buffer *buf) { - return buf->debug_line; + return buf->debug_line; } static const char * -buf_debug_file (const struct buffer *buf) +buf_debug_file(const struct buffer *buf) { - return buf->debug_file; + return buf->debug_file; } -#else +#else /* ifdef BUF_INIT_TRACKING */ #define buf_debug_line(buf) 0 #define buf_debug_file(buf) "[UNDEF]" -#endif +#endif /* ifdef BUF_INIT_TRACKING */ void -buf_clear (struct buffer *buf) +buf_clear(struct buffer *buf) { - if (buf->capacity > 0) + if (buf->capacity > 0) { - secure_memzero (buf->data, buf->capacity); + secure_memzero(buf->data, buf->capacity); } - buf->len = 0; - buf->offset = 0; + buf->len = 0; + buf->offset = 0; } bool -buf_assign (struct buffer *dest, const struct buffer *src) +buf_assign(struct buffer *dest, const struct buffer *src) { - if (!buf_init (dest, src->offset)) - return false; - return buf_write (dest, BPTR (src), BLEN (src)); + if (!buf_init(dest, src->offset)) + { + return false; + } + return buf_write(dest, BPTR(src), BLEN(src)); } struct buffer -clear_buf () +clear_buf() { - struct buffer buf; - CLEAR (buf); - return buf; + struct buffer buf; + CLEAR(buf); + return buf; } void -free_buf (struct buffer *buf) +free_buf(struct buffer *buf) { - if (buf->data) - free (buf->data); - CLEAR (*buf); + if (buf->data) + { + free(buf->data); + } + CLEAR(*buf); } /* * Return a buffer for write that is a subset of another buffer */ struct buffer -buf_sub (struct buffer *buf, int size, bool prepend) +buf_sub(struct buffer *buf, int size, bool prepend) { - struct buffer ret; - uint8_t *data; + struct buffer ret; + uint8_t *data; - CLEAR (ret); - data = prepend ? buf_prepend (buf, size) : buf_write_alloc (buf, size); - if (data) + CLEAR(ret); + data = prepend ? buf_prepend(buf, size) : buf_write_alloc(buf, size); + if (data) { - ret.capacity = size; - ret.data = data; + ret.capacity = size; + ret.data = data; } - return ret; + return ret; } /* * printf append to a buffer with overflow check */ bool -buf_printf (struct buffer *buf, const char *format, ...) +buf_printf(struct buffer *buf, const char *format, ...) { - int ret = false; - if (buf_defined (buf)) - { - va_list arglist; - uint8_t *ptr = BEND (buf); - int cap = buf_forward_capacity (buf); - - if (cap > 0) - { - int stat; - va_start (arglist, format); - stat = vsnprintf ((char *)ptr, cap, format, arglist); - va_end (arglist); - *(buf->data + buf->capacity - 1) = 0; /* windows vsnprintf needs this */ - buf->len += (int) strlen ((char *)ptr); - if (stat >= 0 && stat < cap) - ret = true; - } - } - return ret; + int ret = false; + if (buf_defined(buf)) + { + va_list arglist; + uint8_t *ptr = BEND(buf); + int cap = buf_forward_capacity(buf); + + if (cap > 0) + { + int stat; + va_start(arglist, format); + stat = vsnprintf((char *)ptr, cap, format, arglist); + va_end(arglist); + *(buf->data + buf->capacity - 1) = 0; /* windows vsnprintf needs this */ + buf->len += (int) strlen((char *)ptr); + if (stat >= 0 && stat < cap) + { + ret = true; + } + } + } + return ret; } bool buf_puts(struct buffer *buf, const char *str) { - int ret = false; - uint8_t *ptr = BEND (buf); - int cap = buf_forward_capacity (buf); - if (cap > 0) + int ret = false; + uint8_t *ptr = BEND(buf); + int cap = buf_forward_capacity(buf); + if (cap > 0) { - strncpynt ((char *)ptr,str, cap); - *(buf->data + buf->capacity - 1) = 0; /* windows vsnprintf needs this */ - buf->len += (int) strlen ((char *)ptr); - ret = true; + strncpynt((char *)ptr,str, cap); + *(buf->data + buf->capacity - 1) = 0; /* windows vsnprintf needs this */ + buf->len += (int) strlen((char *)ptr); + ret = true; } - return ret; + return ret; } - + /* * This is necessary due to certain buggy implementations of snprintf, @@ -260,18 +274,19 @@ buf_puts(struct buffer *buf, const char *str) * Any modifications here should be done to the other place as well. */ -bool openvpn_snprintf(char *str, size_t size, const char *format, ...) +bool +openvpn_snprintf(char *str, size_t size, const char *format, ...) { - va_list arglist; - int len = -1; - if (size > 0) + va_list arglist; + int len = -1; + if (size > 0) { - va_start (arglist, format); - len = vsnprintf (str, size, format, arglist); - va_end (arglist); - str[size - 1] = 0; + va_start(arglist, format); + len = vsnprintf(str, size, format, arglist); + va_end(arglist); + str[size - 1] = 0; } - return (len >= 0 && len < size); + return (len >= 0 && len < size); } /* @@ -279,15 +294,15 @@ bool openvpn_snprintf(char *str, size_t size, const char *format, ...) * truncated by buf_printf */ void -buf_catrunc (struct buffer *buf, const char *str) +buf_catrunc(struct buffer *buf, const char *str) { - if (buf_forward_capacity (buf) <= 1) + if (buf_forward_capacity(buf) <= 1) { - int len = (int) strlen (str) + 1; - if (len < buf_forward_capacity_total (buf)) - { - strncpynt ((char *)(buf->data + buf->capacity - len), str, len); - } + int len = (int) strlen(str) + 1; + if (len < buf_forward_capacity_total(buf)) + { + strncpynt((char *)(buf->data + buf->capacity - len), str, len); + } } } @@ -295,26 +310,30 @@ buf_catrunc (struct buffer *buf, const char *str) * convert a multi-line output to one line */ void -convert_to_one_line (struct buffer *buf) +convert_to_one_line(struct buffer *buf) { - uint8_t *cp = BPTR(buf); - int len = BLEN(buf); - while (len--) + uint8_t *cp = BPTR(buf); + int len = BLEN(buf); + while (len--) { - if (*cp == '\n') - *cp = '|'; - ++cp; + if (*cp == '\n') + { + *cp = '|'; + } + ++cp; } } /* NOTE: requires that string be null terminated */ void -buf_write_string_file (const struct buffer *buf, const char *filename, int fd) +buf_write_string_file(const struct buffer *buf, const char *filename, int fd) { - const int len = strlen ((char *) BPTR (buf)); - const int size = write (fd, BPTR (buf), len); - if (size != len) - msg (M_ERR, "Write error on file '%s'", filename); + const int len = strlen((char *) BPTR(buf)); + const int size = write(fd, BPTR(buf), len); + if (size != len) + { + msg(M_ERR, "Write error on file '%s'", filename); + } } /* @@ -323,53 +342,53 @@ buf_write_string_file (const struct buffer *buf, const char *filename, int fd) void * #ifdef DMALLOC -gc_malloc_debug (size_t size, bool clear, struct gc_arena *a, const char *file, int line) +gc_malloc_debug(size_t size, bool clear, struct gc_arena *a, const char *file, int line) #else -gc_malloc (size_t size, bool clear, struct gc_arena *a) +gc_malloc(size_t size, bool clear, struct gc_arena *a) #endif { - void *ret; - if (a) + void *ret; + if (a) { - struct gc_entry *e; + struct gc_entry *e; #ifdef DMALLOC - e = (struct gc_entry *) openvpn_dmalloc (file, line, size + sizeof (struct gc_entry)); + e = (struct gc_entry *) openvpn_dmalloc(file, line, size + sizeof(struct gc_entry)); #else - e = (struct gc_entry *) malloc (size + sizeof (struct gc_entry)); + e = (struct gc_entry *) malloc(size + sizeof(struct gc_entry)); #endif - check_malloc_return (e); - ret = (char *) e + sizeof (struct gc_entry); - e->next = a->list; - a->list = e; + check_malloc_return(e); + ret = (char *) e + sizeof(struct gc_entry); + e->next = a->list; + a->list = e; } - else + else { #ifdef DMALLOC - ret = openvpn_dmalloc (file, line, size); + ret = openvpn_dmalloc(file, line, size); #else - ret = malloc (size); + ret = malloc(size); #endif - check_malloc_return (ret); + check_malloc_return(ret); } #ifndef ZERO_BUFFER_ON_ALLOC - if (clear) + if (clear) #endif - memset (ret, 0, size); - return ret; + memset(ret, 0, size); + return ret; } void -x_gc_free (struct gc_arena *a) +x_gc_free(struct gc_arena *a) { - struct gc_entry *e; - e = a->list; - a->list = NULL; - - while (e != NULL) + struct gc_entry *e; + e = a->list; + a->list = NULL; + + while (e != NULL) { - struct gc_entry *next = e->next; - free (e); - e = next; + struct gc_entry *next = e->next; + free(e); + e = next; } } @@ -378,36 +397,37 @@ x_gc_free (struct gc_arena *a) */ void -x_gc_freespecial (struct gc_arena *a) +x_gc_freespecial(struct gc_arena *a) { - struct gc_entry_special *e; - e = a->list_special; - a->list_special = NULL; + struct gc_entry_special *e; + e = a->list_special; + a->list_special = NULL; - while (e != NULL) + while (e != NULL) { - struct gc_entry_special *next = e->next; - e->free_fnc (e->addr); - free(e); - e = next; + struct gc_entry_special *next = e->next; + e->free_fnc(e->addr); + free(e); + e = next; } } -void gc_addspecial (void *addr, void (free_function)(void*), struct gc_arena *a) +void +gc_addspecial(void *addr, void(free_function)(void *), struct gc_arena *a) { - ASSERT(a); - struct gc_entry_special *e; + ASSERT(a); + struct gc_entry_special *e; #ifdef DMALLOC - e = (struct gc_entry_special *) openvpn_dmalloc (file, line, sizeof (struct gc_entry_special)); + e = (struct gc_entry_special *) openvpn_dmalloc(file, line, sizeof(struct gc_entry_special)); #else - e = (struct gc_entry_special *) malloc (sizeof (struct gc_entry_special)); + e = (struct gc_entry_special *) malloc(sizeof(struct gc_entry_special)); #endif - check_malloc_return (e); - e->free_fnc = free_function; - e->addr = addr; + check_malloc_return(e); + e->free_fnc = free_function; + e->addr = addr; - e->next = a->list_special; - a->list_special = e; + e->next = a->list_special; + a->list_special = e; } @@ -415,19 +435,19 @@ void gc_addspecial (void *addr, void (free_function)(void*), struct gc_arena *a) * Transfer src arena to dest, resetting src to an empty arena. */ void -gc_transfer (struct gc_arena *dest, struct gc_arena *src) +gc_transfer(struct gc_arena *dest, struct gc_arena *src) { - if (dest && src) - { - struct gc_entry *e = src->list; - if (e) - { - while (e->next != NULL) - e = e->next; - e->next = dest->list; - dest->list = src->list; - src->list = NULL; - } + if (dest && src) + { + struct gc_entry *e = src->list; + if (e) + { + while (e->next != NULL) + e = e->next; + e->next = dest->list; + dest->list = src->list; + src->list = NULL; + } } } @@ -436,28 +456,34 @@ gc_transfer (struct gc_arena *dest, struct gc_arena *src) */ char * -format_hex_ex (const uint8_t *data, int size, int maxoutput, - unsigned int space_break_flags, const char* separator, - struct gc_arena *gc) +format_hex_ex(const uint8_t *data, int size, int maxoutput, + unsigned int space_break_flags, const char *separator, + struct gc_arena *gc) { - const size_t bytes_per_hexblock = space_break_flags & FHE_SPACE_BREAK_MASK; - const size_t separator_len = separator ? strlen (separator) : 0; - static_assert (INT_MAX <= SIZE_MAX, "Code assumes INT_MAX <= SIZE_MAX"); - const size_t out_len = maxoutput > 0 ? maxoutput : - ((size * 2) + ((size / bytes_per_hexblock) * separator_len) + 2); - - struct buffer out = alloc_buf_gc (out_len, gc); - for (int i = 0; i < size; ++i) - { - if (separator && i && !(i % bytes_per_hexblock)) - buf_printf (&out, "%s", separator); - if (space_break_flags & FHE_CAPS) - buf_printf (&out, "%02X", data[i]); - else - buf_printf (&out, "%02x", data[i]); - } - buf_catrunc (&out, "[more...]"); - return (char *)out.data; + const size_t bytes_per_hexblock = space_break_flags & FHE_SPACE_BREAK_MASK; + const size_t separator_len = separator ? strlen(separator) : 0; + static_assert(INT_MAX <= SIZE_MAX, "Code assumes INT_MAX <= SIZE_MAX"); + const size_t out_len = maxoutput > 0 ? maxoutput : + ((size * 2) + ((size / bytes_per_hexblock) * separator_len) + 2); + + struct buffer out = alloc_buf_gc(out_len, gc); + for (int i = 0; i < size; ++i) + { + if (separator && i && !(i % bytes_per_hexblock)) + { + buf_printf(&out, "%s", separator); + } + if (space_break_flags & FHE_CAPS) + { + buf_printf(&out, "%02X", data[i]); + } + else + { + buf_printf(&out, "%02x", data[i]); + } + } + buf_catrunc(&out, "[more...]"); + return (char *)out.data; } /* @@ -465,13 +491,13 @@ format_hex_ex (const uint8_t *data, int size, int maxoutput, */ void -buf_rmtail (struct buffer *buf, uint8_t remove) +buf_rmtail(struct buffer *buf, uint8_t remove) { - uint8_t *cp = BLAST(buf); - if (cp && *cp == remove) + uint8_t *cp = BLAST(buf); + if (cp && *cp == remove) { - *cp = '\0'; - --buf->len; + *cp = '\0'; + --buf->len; } } @@ -480,16 +506,20 @@ buf_rmtail (struct buffer *buf, uint8_t remove) * truncation of the last char. */ void -buf_null_terminate (struct buffer *buf) +buf_null_terminate(struct buffer *buf) { - char *last = (char *) BLAST (buf); - if (last && *last == '\0') /* already terminated? */ - return; + char *last = (char *) BLAST(buf); + if (last && *last == '\0') /* already terminated? */ + { + return; + } - if (!buf_safe (buf, 1)) /* make space for trailing null */ - buf_inc_len (buf, -1); + if (!buf_safe(buf, 1)) /* make space for trailing null */ + { + buf_inc_len(buf, -1); + } - buf_write_u8 (buf, 0); + buf_write_u8(buf, 0); } /* @@ -497,79 +527,91 @@ buf_null_terminate (struct buffer *buf) * null termination. */ void -buf_chomp (struct buffer *buf) +buf_chomp(struct buffer *buf) { - while (true) - { - char *last = (char *) BLAST (buf); - if (!last) - break; - if (char_class (*last, CC_CRLF|CC_NULL)) - { - if (!buf_inc_len (buf, -1)) - break; - } - else - break; - } - buf_null_terminate (buf); + while (true) + { + char *last = (char *) BLAST(buf); + if (!last) + { + break; + } + if (char_class(*last, CC_CRLF|CC_NULL)) + { + if (!buf_inc_len(buf, -1)) + { + break; + } + } + else + { + break; + } + } + buf_null_terminate(buf); } const char * -skip_leading_whitespace (const char *str) +skip_leading_whitespace(const char *str) { - while (*str) + while (*str) { - const char c = *str; - if (!(c == ' ' || c == '\t')) - break; - ++str; + const char c = *str; + if (!(c == ' ' || c == '\t')) + { + break; + } + ++str; } - return str; + return str; } /* * like buf_null_terminate, but operate on strings */ void -string_null_terminate (char *str, int len, int capacity) +string_null_terminate(char *str, int len, int capacity) { - ASSERT (len >= 0 && len <= capacity && capacity > 0); - if (len < capacity) - *(str + len) = '\0'; - else if (len == capacity) - *(str + len - 1) = '\0'; + ASSERT(len >= 0 && len <= capacity && capacity > 0); + if (len < capacity) + { + *(str + len) = '\0'; + } + else if (len == capacity) + { + *(str + len - 1) = '\0'; + } } /* * Remove trailing \r and \n chars. */ void -chomp (char *str) +chomp(char *str) { - rm_trailing_chars (str, "\r\n"); + rm_trailing_chars(str, "\r\n"); } /* * Remove trailing chars */ void -rm_trailing_chars (char *str, const char *what_to_delete) +rm_trailing_chars(char *str, const char *what_to_delete) { - bool modified; - do { - const int len = strlen (str); - modified = false; - if (len > 0) - { - char *cp = str + (len - 1); - if (strchr (what_to_delete, *cp) != NULL) - { - *cp = '\0'; - modified = true; - } - } - } while (modified); + bool modified; + do { + const int len = strlen(str); + modified = false; + if (len > 0) + { + char *cp = str + (len - 1); + if (strchr(what_to_delete, *cp) != NULL) + { + *cp = '\0'; + modified = true; + } + } + } while (modified); } /* @@ -577,51 +619,56 @@ rm_trailing_chars (char *str, const char *what_to_delete) */ char * #ifdef DMALLOC -string_alloc_debug (const char *str, struct gc_arena *gc, const char *file, int line) +string_alloc_debug(const char *str, struct gc_arena *gc, const char *file, int line) #else -string_alloc (const char *str, struct gc_arena *gc) +string_alloc(const char *str, struct gc_arena *gc) #endif { - if (str) + if (str) { - const int n = strlen (str) + 1; - char *ret; + const int n = strlen(str) + 1; + char *ret; - if (gc) { + if (gc) + { #ifdef DMALLOC - ret = (char *) gc_malloc_debug (n, false, gc, file, line); + ret = (char *) gc_malloc_debug(n, false, gc, file, line); #else - ret = (char *) gc_malloc (n, false, gc); + ret = (char *) gc_malloc(n, false, gc); #endif - } else { - /* If there are no garbage collector available, it's expected - * that the caller cleans up afterwards. This is coherent with the - * earlier behaviour when gc_malloc() would be called with gc == NULL - */ + } + else + { + /* If there are no garbage collector available, it's expected + * that the caller cleans up afterwards. This is coherent with the + * earlier behaviour when gc_malloc() would be called with gc == NULL + */ #ifdef DMALLOC - ret = openvpn_dmalloc (file, line, n); - memset(ret, 0, n); + ret = openvpn_dmalloc(file, line, n); + memset(ret, 0, n); #else - ret = calloc(1, n); + ret = calloc(1, n); #endif - check_malloc_return(ret); - } - memcpy (ret, str, n); - return ret; + check_malloc_return(ret); + } + memcpy(ret, str, n); + return ret; + } + else + { + return NULL; } - else - return NULL; } /* * Erase all characters in a string */ void -string_clear (char *str) +string_clear(char *str) { - if (str) + if (str) { - secure_memzero (str, strlen (str)); + secure_memzero(str, strlen(str)); } } @@ -629,36 +676,44 @@ string_clear (char *str) * Return the length of a string array */ int -string_array_len (const char **array) +string_array_len(const char **array) { - int i = 0; - if (array) + int i = 0; + if (array) { - while (array[i]) - ++i; + while (array[i]) + ++i; } - return i; + return i; } char * -print_argv (const char **p, struct gc_arena *gc, const unsigned int flags) +print_argv(const char **p, struct gc_arena *gc, const unsigned int flags) { - struct buffer out = alloc_buf_gc (256, gc); - int i = 0; - for (;;) - { - const char *cp = *p++; - if (!cp) - break; - if (i) - buf_printf (&out, " "); - if (flags & PA_BRACKET) - buf_printf (&out, "[%s]", cp); - else - buf_printf (&out, "%s", cp); - ++i; - } - return BSTR (&out); + struct buffer out = alloc_buf_gc(256, gc); + int i = 0; + for (;; ) + { + const char *cp = *p++; + if (!cp) + { + break; + } + if (i) + { + buf_printf(&out, " "); + } + if (flags & PA_BRACKET) + { + buf_printf(&out, "[%s]", cp); + } + else + { + buf_printf(&out, "%s", cp); + } + ++i; + } + return BSTR(&out); } /* @@ -666,25 +721,27 @@ print_argv (const char **p, struct gc_arena *gc, const unsigned int flags) */ struct buffer #ifdef DMALLOC -string_alloc_buf_debug (const char *str, struct gc_arena *gc, const char *file, int line) +string_alloc_buf_debug(const char *str, struct gc_arena *gc, const char *file, int line) #else -string_alloc_buf (const char *str, struct gc_arena *gc) +string_alloc_buf(const char *str, struct gc_arena *gc) #endif { - struct buffer buf; + struct buffer buf; - ASSERT (str); + ASSERT(str); #ifdef DMALLOC - buf_set_read (&buf, (uint8_t*) string_alloc_debug (str, gc, file, line), strlen (str) + 1); + buf_set_read(&buf, (uint8_t *) string_alloc_debug(str, gc, file, line), strlen(str) + 1); #else - buf_set_read (&buf, (uint8_t*) string_alloc (str, gc), strlen (str) + 1); + buf_set_read(&buf, (uint8_t *) string_alloc(str, gc), strlen(str) + 1); #endif - if (buf.len > 0) /* Don't count trailing '\0' as part of length */ - --buf.len; + if (buf.len > 0) /* Don't count trailing '\0' as part of length */ + { + --buf.len; + } - return buf; + return buf; } /* @@ -692,40 +749,46 @@ string_alloc_buf (const char *str, struct gc_arena *gc) */ bool -buf_string_match_head_str (const struct buffer *src, const char *match) +buf_string_match_head_str(const struct buffer *src, const char *match) { - const int size = strlen (match); - if (size < 0 || size > src->len) - return false; - return memcmp (BPTR (src), match, size) == 0; + const int size = strlen(match); + if (size < 0 || size > src->len) + { + return false; + } + return memcmp(BPTR(src), match, size) == 0; } bool -buf_string_compare_advance (struct buffer *src, const char *match) +buf_string_compare_advance(struct buffer *src, const char *match) { - if (buf_string_match_head_str (src, match)) + if (buf_string_match_head_str(src, match)) { - buf_advance (src, strlen (match)); - return true; + buf_advance(src, strlen(match)); + return true; + } + else + { + return false; } - else - return false; } int -buf_substring_len (const struct buffer *buf, int delim) +buf_substring_len(const struct buffer *buf, int delim) { - int i = 0; - struct buffer tmp = *buf; - int c; + int i = 0; + struct buffer tmp = *buf; + int c; - while ((c = buf_read_u8 (&tmp)) >= 0) + while ((c = buf_read_u8(&tmp)) >= 0) { - ++i; - if (c == delim) - return i; + ++i; + if (c == delim) + { + return i; + } } - return -1; + return -1; } /* @@ -733,41 +796,51 @@ buf_substring_len (const struct buffer *buf, int delim) */ bool -buf_parse (struct buffer *buf, const int delim, char *line, const int size) +buf_parse(struct buffer *buf, const int delim, char *line, const int size) { - bool eol = false; - int n = 0; - int c; + bool eol = false; + int n = 0; + int c; - ASSERT (size > 0); + ASSERT(size > 0); - do + do { - c = buf_read_u8 (buf); - if (c < 0) - eol = true; - if (c <= 0 || c == delim) - c = 0; - if (n >= size) - break; - line[n++] = c; + c = buf_read_u8(buf); + if (c < 0) + { + eol = true; + } + if (c <= 0 || c == delim) + { + c = 0; + } + if (n >= size) + { + break; + } + line[n++] = c; } - while (c); + while (c); - line[size-1] = '\0'; - return !(eol && !strlen (line)); + line[size-1] = '\0'; + return !(eol && !strlen(line)); } /* * Print a string which might be NULL */ const char * -np (const char *str) +np(const char *str) { - if (str) - return str; - else - return "[NULL]"; + if (str) + { + return str; + } + else + { + return "[NULL]"; + } } /* @@ -775,97 +848,163 @@ np (const char *str) */ bool -char_class (const unsigned char c, const unsigned int flags) +char_class(const unsigned char c, const unsigned int flags) { - if (!flags) - return false; - if (flags & CC_ANY) - return true; + if (!flags) + { + return false; + } + if (flags & CC_ANY) + { + return true; + } - if ((flags & CC_NULL) && c == '\0') - return true; + if ((flags & CC_NULL) && c == '\0') + { + return true; + } - if ((flags & CC_ALNUM) && isalnum (c)) - return true; - if ((flags & CC_ALPHA) && isalpha (c)) - return true; - if ((flags & CC_ASCII) && isascii (c)) - return true; - if ((flags & CC_CNTRL) && iscntrl (c)) - return true; - if ((flags & CC_DIGIT) && isdigit (c)) - return true; - if ((flags & CC_PRINT) && (c >= 32 && c != 127)) /* allow ascii non-control and UTF-8, consider DEL to be a control */ - return true; - if ((flags & CC_PUNCT) && ispunct (c)) - return true; - if ((flags & CC_SPACE) && isspace (c)) - return true; - if ((flags & CC_XDIGIT) && isxdigit (c)) - return true; + if ((flags & CC_ALNUM) && isalnum(c)) + { + return true; + } + if ((flags & CC_ALPHA) && isalpha(c)) + { + return true; + } + if ((flags & CC_ASCII) && isascii(c)) + { + return true; + } + if ((flags & CC_CNTRL) && iscntrl(c)) + { + return true; + } + if ((flags & CC_DIGIT) && isdigit(c)) + { + return true; + } + if ((flags & CC_PRINT) && (c >= 32 && c != 127)) /* allow ascii non-control and UTF-8, consider DEL to be a control */ + { + return true; + } + if ((flags & CC_PUNCT) && ispunct(c)) + { + return true; + } + if ((flags & CC_SPACE) && isspace(c)) + { + return true; + } + if ((flags & CC_XDIGIT) && isxdigit(c)) + { + return true; + } - if ((flags & CC_BLANK) && (c == ' ' || c == '\t')) - return true; - if ((flags & CC_NEWLINE) && c == '\n') - return true; - if ((flags & CC_CR) && c == '\r') - return true; + if ((flags & CC_BLANK) && (c == ' ' || c == '\t')) + { + return true; + } + if ((flags & CC_NEWLINE) && c == '\n') + { + return true; + } + if ((flags & CC_CR) && c == '\r') + { + return true; + } - if ((flags & CC_BACKSLASH) && c == '\\') - return true; - if ((flags & CC_UNDERBAR) && c == '_') - return true; - if ((flags & CC_DASH) && c == '-') - return true; - if ((flags & CC_DOT) && c == '.') - return true; - if ((flags & CC_COMMA) && c == ',') - return true; - if ((flags & CC_COLON) && c == ':') - return true; - if ((flags & CC_SLASH) && c == '/') - return true; - if ((flags & CC_SINGLE_QUOTE) && c == '\'') - return true; - if ((flags & CC_DOUBLE_QUOTE) && c == '\"') - return true; - if ((flags & CC_REVERSE_QUOTE) && c == '`') - return true; - if ((flags & CC_AT) && c == '@') - return true; - if ((flags & CC_EQUAL) && c == '=') - return true; - if ((flags & CC_LESS_THAN) && c == '<') - return true; - if ((flags & CC_GREATER_THAN) && c == '>') - return true; - if ((flags & CC_PIPE) && c == '|') - return true; - if ((flags & CC_QUESTION_MARK) && c == '?') - return true; - if ((flags & CC_ASTERISK) && c == '*') - return true; + if ((flags & CC_BACKSLASH) && c == '\\') + { + return true; + } + if ((flags & CC_UNDERBAR) && c == '_') + { + return true; + } + if ((flags & CC_DASH) && c == '-') + { + return true; + } + if ((flags & CC_DOT) && c == '.') + { + return true; + } + if ((flags & CC_COMMA) && c == ',') + { + return true; + } + if ((flags & CC_COLON) && c == ':') + { + return true; + } + if ((flags & CC_SLASH) && c == '/') + { + return true; + } + if ((flags & CC_SINGLE_QUOTE) && c == '\'') + { + return true; + } + if ((flags & CC_DOUBLE_QUOTE) && c == '\"') + { + return true; + } + if ((flags & CC_REVERSE_QUOTE) && c == '`') + { + return true; + } + if ((flags & CC_AT) && c == '@') + { + return true; + } + if ((flags & CC_EQUAL) && c == '=') + { + return true; + } + if ((flags & CC_LESS_THAN) && c == '<') + { + return true; + } + if ((flags & CC_GREATER_THAN) && c == '>') + { + return true; + } + if ((flags & CC_PIPE) && c == '|') + { + return true; + } + if ((flags & CC_QUESTION_MARK) && c == '?') + { + return true; + } + if ((flags & CC_ASTERISK) && c == '*') + { + return true; + } - return false; + return false; } static inline bool -char_inc_exc (const char c, const unsigned int inclusive, const unsigned int exclusive) +char_inc_exc(const char c, const unsigned int inclusive, const unsigned int exclusive) { - return char_class (c, inclusive) && !char_class (c, exclusive); + return char_class(c, inclusive) && !char_class(c, exclusive); } bool -string_class (const char *str, const unsigned int inclusive, const unsigned int exclusive) +string_class(const char *str, const unsigned int inclusive, const unsigned int exclusive) { - char c; - ASSERT (str); - while ((c = *str++)) + char c; + ASSERT(str); + while ((c = *str++)) { - if (!char_inc_exc (c, inclusive, exclusive)) - return false; + if (!char_inc_exc(c, inclusive, exclusive)) + { + return false; + } } - return true; + return true; } /* @@ -873,63 +1012,71 @@ string_class (const char *str, const unsigned int inclusive, const unsigned int * Guaranteed to not increase string length. */ bool -string_mod (char *str, const unsigned int inclusive, const unsigned int exclusive, const char replace) +string_mod(char *str, const unsigned int inclusive, const unsigned int exclusive, const char replace) { - const char *in = str; - bool ret = true; - - ASSERT (str); - - while (true) - { - char c = *in++; - if (c) - { - if (!char_inc_exc (c, inclusive, exclusive)) - { - c = replace; - ret = false; - } - if (c) - *str++ = c; - } - else - { - *str = '\0'; - break; - } - } - return ret; + const char *in = str; + bool ret = true; + + ASSERT(str); + + while (true) + { + char c = *in++; + if (c) + { + if (!char_inc_exc(c, inclusive, exclusive)) + { + c = replace; + ret = false; + } + if (c) + { + *str++ = c; + } + } + else + { + *str = '\0'; + break; + } + } + return ret; } const char * -string_mod_const (const char *str, - const unsigned int inclusive, - const unsigned int exclusive, - const char replace, - struct gc_arena *gc) +string_mod_const(const char *str, + const unsigned int inclusive, + const unsigned int exclusive, + const char replace, + struct gc_arena *gc) { - if (str) + if (str) { - char *buf = string_alloc (str, gc); - string_mod (buf, inclusive, exclusive, replace); - return buf; + char *buf = string_alloc(str, gc); + string_mod(buf, inclusive, exclusive, replace); + return buf; + } + else + { + return NULL; } - else - return NULL; } void -string_replace_leading (char *str, const char match, const char replace) +string_replace_leading(char *str, const char match, const char replace) { - ASSERT (match != '\0'); - while (*str) + ASSERT(match != '\0'); + while (*str) { - if (*str == match) - *str = replace; - else - break; - ++str; + if (*str == match) + { + *str = replace; + } + else + { + break; + } + ++str; } } @@ -940,14 +1087,14 @@ string_replace_leading (char *str, const char match, const char replace) #define CC_REPLACE ('.') void -character_class_debug (void) +character_class_debug(void) { - char buf[256]; + char buf[256]; - while (fgets (buf, sizeof (buf), stdin) != NULL) + while (fgets(buf, sizeof(buf), stdin) != NULL) { - string_mod (buf, CC_INCLUDE, CC_EXCLUDE, CC_REPLACE); - printf ("%s", buf); + string_mod(buf, CC_INCLUDE, CC_EXCLUDE, CC_REPLACE); + printf("%s", buf); } } @@ -955,214 +1102,228 @@ character_class_debug (void) #ifdef VERIFY_ALIGNMENT void -valign4 (const struct buffer *buf, const char *file, const int line) +valign4(const struct buffer *buf, const char *file, const int line) { - if (buf && buf->len) + if (buf && buf->len) { - int msglevel = D_ALIGN_DEBUG; - const unsigned int u = (unsigned int) BPTR (buf); - - if (u & (PAYLOAD_ALIGN-1)) - msglevel = D_ALIGN_ERRORS; - - msg (msglevel, "%sAlignment at %s/%d ptr=" ptr_format " OLC=%d/%d/%d I=%s/%d", - (msglevel == D_ALIGN_ERRORS) ? "ERROR: " : "", - file, - line, - (ptr_type)buf->data, - buf->offset, - buf->len, - buf->capacity, - buf_debug_file (buf), - buf_debug_line (buf)); + int msglevel = D_ALIGN_DEBUG; + const unsigned int u = (unsigned int) BPTR(buf); + + if (u & (PAYLOAD_ALIGN-1)) + { + msglevel = D_ALIGN_ERRORS; + } + + msg(msglevel, "%sAlignment at %s/%d ptr=" ptr_format " OLC=%d/%d/%d I=%s/%d", + (msglevel == D_ALIGN_ERRORS) ? "ERROR: " : "", + file, + line, + (ptr_type)buf->data, + buf->offset, + buf->len, + buf->capacity, + buf_debug_file(buf), + buf_debug_line(buf)); } } -#endif +#endif /* ifdef VERIFY_ALIGNMENT */ /* * struct buffer_list */ struct buffer_list * -buffer_list_new (const int max_size) +buffer_list_new(const int max_size) { - struct buffer_list *ret; - ALLOC_OBJ_CLEAR (ret, struct buffer_list); - ret->max_size = max_size; - ret->size = 0; - return ret; + struct buffer_list *ret; + ALLOC_OBJ_CLEAR(ret, struct buffer_list); + ret->max_size = max_size; + ret->size = 0; + return ret; } void -buffer_list_free (struct buffer_list *ol) +buffer_list_free(struct buffer_list *ol) { - if (ol) + if (ol) { - buffer_list_reset (ol); - free (ol); + buffer_list_reset(ol); + free(ol); } } bool -buffer_list_defined (const struct buffer_list *ol) +buffer_list_defined(const struct buffer_list *ol) { - return ol && ol->head != NULL; + return ol && ol->head != NULL; } void -buffer_list_reset (struct buffer_list *ol) +buffer_list_reset(struct buffer_list *ol) { - struct buffer_entry *e = ol->head; - while (e) + struct buffer_entry *e = ol->head; + while (e) { - struct buffer_entry *next = e->next; - free_buf (&e->buf); - free (e); - e = next; + struct buffer_entry *next = e->next; + free_buf(&e->buf); + free(e); + e = next; } - ol->head = ol->tail = NULL; - ol->size = 0; + ol->head = ol->tail = NULL; + ol->size = 0; } void -buffer_list_push (struct buffer_list *ol, const unsigned char *str) +buffer_list_push(struct buffer_list *ol, const unsigned char *str) { - if (str) + if (str) { - const size_t len = strlen ((const char *)str); - struct buffer_entry *e = buffer_list_push_data (ol, str, len+1); - if (e) - e->buf.len = len; /* Don't count trailing '\0' as part of length */ + const size_t len = strlen((const char *)str); + struct buffer_entry *e = buffer_list_push_data(ol, str, len+1); + if (e) + { + e->buf.len = len; /* Don't count trailing '\0' as part of length */ + } } } struct buffer_entry * -buffer_list_push_data (struct buffer_list *ol, const uint8_t *data, size_t size) +buffer_list_push_data(struct buffer_list *ol, const uint8_t *data, size_t size) { - struct buffer_entry *e = NULL; - if (data && (!ol->max_size || ol->size < ol->max_size)) - { - ALLOC_OBJ_CLEAR (e, struct buffer_entry); - - ++ol->size; - if (ol->tail) - { - ASSERT (ol->head); - ol->tail->next = e; - } - else - { - ASSERT (!ol->head); - ol->head = e; - } - e->buf = alloc_buf (size); - memcpy (e->buf.data, data, size); - e->buf.len = (int)size; - ol->tail = e; - } - return e; + struct buffer_entry *e = NULL; + if (data && (!ol->max_size || ol->size < ol->max_size)) + { + ALLOC_OBJ_CLEAR(e, struct buffer_entry); + + ++ol->size; + if (ol->tail) + { + ASSERT(ol->head); + ol->tail->next = e; + } + else + { + ASSERT(!ol->head); + ol->head = e; + } + e->buf = alloc_buf(size); + memcpy(e->buf.data, data, size); + e->buf.len = (int)size; + ol->tail = e; + } + return e; } struct buffer * -buffer_list_peek (struct buffer_list *ol) +buffer_list_peek(struct buffer_list *ol) { - if (ol && ol->head) - return &ol->head->buf; - else - return NULL; + if (ol && ol->head) + { + return &ol->head->buf; + } + else + { + return NULL; + } } void -buffer_list_aggregate_separator (struct buffer_list *bl, const size_t max, const char *sep) +buffer_list_aggregate_separator(struct buffer_list *bl, const size_t max, const char *sep) { - int sep_len = strlen(sep); - - if (bl->head) - { - struct buffer_entry *more = bl->head; - size_t size = 0; - int count = 0; - for (count = 0; more && size <= max; ++count) - { - size += BLEN(&more->buf) + sep_len; - more = more->next; - } - - if (count >= 2) - { - int i; - struct buffer_entry *e = bl->head, *f; - - ALLOC_OBJ_CLEAR (f, struct buffer_entry); - f->buf.data = malloc (size); - check_malloc_return (f->buf.data); - f->buf.capacity = size; - for (i = 0; e && i < count; ++i) - { - struct buffer_entry *next = e->next; - buf_copy (&f->buf, &e->buf); - buf_write(&f->buf, sep, sep_len); - free_buf (&e->buf); - free (e); - e = next; - } - bl->head = f; - f->next = more; - if (!more) - bl->tail = f; - } + int sep_len = strlen(sep); + + if (bl->head) + { + struct buffer_entry *more = bl->head; + size_t size = 0; + int count = 0; + for (count = 0; more && size <= max; ++count) + { + size += BLEN(&more->buf) + sep_len; + more = more->next; + } + + if (count >= 2) + { + int i; + struct buffer_entry *e = bl->head, *f; + + ALLOC_OBJ_CLEAR(f, struct buffer_entry); + f->buf.data = malloc(size); + check_malloc_return(f->buf.data); + f->buf.capacity = size; + for (i = 0; e && i < count; ++i) + { + struct buffer_entry *next = e->next; + buf_copy(&f->buf, &e->buf); + buf_write(&f->buf, sep, sep_len); + free_buf(&e->buf); + free(e); + e = next; + } + bl->head = f; + f->next = more; + if (!more) + { + bl->tail = f; + } + } } } void -buffer_list_aggregate (struct buffer_list *bl, const size_t max) +buffer_list_aggregate(struct buffer_list *bl, const size_t max) { - buffer_list_aggregate_separator(bl, max, ""); + buffer_list_aggregate_separator(bl, max, ""); } void -buffer_list_pop (struct buffer_list *ol) +buffer_list_pop(struct buffer_list *ol) { - if (ol && ol->head) + if (ol && ol->head) { - struct buffer_entry *e = ol->head->next; - free_buf (&ol->head->buf); - free (ol->head); - ol->head = e; - --ol->size; - if (!e) - ol->tail = NULL; + struct buffer_entry *e = ol->head->next; + free_buf(&ol->head->buf); + free(ol->head); + ol->head = e; + --ol->size; + if (!e) + { + ol->tail = NULL; + } } } void -buffer_list_advance (struct buffer_list *ol, int n) +buffer_list_advance(struct buffer_list *ol, int n) { - if (ol->head) + if (ol->head) { - struct buffer *buf = &ol->head->buf; - ASSERT (buf_advance (buf, n)); - if (!BLEN (buf)) - buffer_list_pop (ol); + struct buffer *buf = &ol->head->buf; + ASSERT(buf_advance(buf, n)); + if (!BLEN(buf)) + { + buffer_list_pop(ol); + } } } struct buffer_list * -buffer_list_file (const char *fn, int max_line_len) +buffer_list_file(const char *fn, int max_line_len) { - FILE *fp = platform_fopen (fn, "r"); - struct buffer_list *bl = NULL; - - if (fp) - { - char *line = (char *) malloc (max_line_len); - if (line) - { - bl = buffer_list_new (0); - while (fgets (line, max_line_len, fp) != NULL) - buffer_list_push (bl, (unsigned char *)line); - free (line); - } - fclose (fp); - } - return bl; + FILE *fp = platform_fopen(fn, "r"); + struct buffer_list *bl = NULL; + + if (fp) + { + char *line = (char *) malloc(max_line_len); + if (line) + { + bl = buffer_list_new(0); + while (fgets(line, max_line_len, fp) != NULL) + buffer_list_push(bl, (unsigned char *)line); + free(line); + } + fclose(fp); + } + return bl; } diff --git a/src/openvpn/buffer.h b/src/openvpn/buffer.h index 7747003f2c8..6bd5e206c51 100644 --- a/src/openvpn/buffer.h +++ b/src/openvpn/buffer.h @@ -51,26 +51,26 @@ * location \c buffer.data \c + \c buffer.offset, and has a length of \c * buffer.len bytes. This, together with the space available before and * after the content, is represented in the pseudocode below: -@code -uint8_t *content_start = buffer.data + buffer.offset; -uint8_t *content_end = buffer.data + buffer.offset + buffer.len; -int prepend_capacity = buffer.offset; -int append_capacity = buffer.capacity - (buffer.offset + buffer.len); -@endcode + * @code + * uint8_t *content_start = buffer.data + buffer.offset; + * uint8_t *content_end = buffer.data + buffer.offset + buffer.len; + * int prepend_capacity = buffer.offset; + * int append_capacity = buffer.capacity - (buffer.offset + buffer.len); + * @endcode */ struct buffer { - int capacity; /**< Size in bytes of memory allocated by + int capacity; /**< Size in bytes of memory allocated by * \c malloc(). */ - int offset; /**< Offset in bytes of the actual content + int offset; /**< Offset in bytes of the actual content * within the allocated memory. */ - int len; /**< Length in bytes of the actual content + int len; /**< Length in bytes of the actual content * within the allocated memory. */ - uint8_t *data; /**< Pointer to the allocated memory. */ + uint8_t *data; /**< Pointer to the allocated memory. */ #ifdef BUF_INIT_TRACKING - const char *debug_file; - int debug_line; + const char *debug_file; + int debug_line; #endif }; @@ -87,7 +87,7 @@ struct buffer */ struct gc_entry { - struct gc_entry *next; /**< Pointer to the next item in the + struct gc_entry *next; /**< Pointer to the next item in the * linked list. */ }; @@ -98,9 +98,9 @@ struct gc_entry */ struct gc_entry_special { - struct gc_entry_special *next; - void (*free_fnc)(void*); - void *addr; + struct gc_entry_special *next; + void (*free_fnc)(void *); + void *addr; }; @@ -116,9 +116,9 @@ struct gc_entry_special */ struct gc_arena { - struct gc_entry *list; /**< First element of the linked list of + struct gc_entry *list; /**< First element of the linked list of * \c gc_entry structures. */ - struct gc_entry_special *list_special; + struct gc_entry_special *list_special; }; @@ -128,204 +128,241 @@ struct gc_arena #define BLEN(buf) (buf_len(buf)) #define BDEF(buf) (buf_defined(buf)) #define BSTR(buf) (buf_str(buf)) -#define BCAP(buf) (buf_forward_capacity (buf)) +#define BCAP(buf) (buf_forward_capacity(buf)) -void buf_clear (struct buffer *buf); +void buf_clear(struct buffer *buf); -struct buffer clear_buf (void); -void free_buf (struct buffer *buf); +struct buffer clear_buf(void); -bool buf_assign (struct buffer *dest, const struct buffer *src); +void free_buf(struct buffer *buf); -void string_clear (char *str); -int string_array_len (const char **array); +bool buf_assign(struct buffer *dest, const struct buffer *src); -size_t array_mult_safe (const size_t m1, const size_t m2, const size_t extra); +void string_clear(char *str); + +int string_array_len(const char **array); + +size_t array_mult_safe(const size_t m1, const size_t m2, const size_t extra); #define PA_BRACKET (1<<0) -char *print_argv (const char **p, struct gc_arena *gc, const unsigned int flags); +char *print_argv(const char **p, struct gc_arena *gc, const unsigned int flags); -void buf_size_error (const size_t size); +void buf_size_error(const size_t size); /* for dmalloc debugging */ #ifdef DMALLOC -#define alloc_buf(size) alloc_buf_debug (size, __FILE__, __LINE__) -#define alloc_buf_gc(size, gc) alloc_buf_gc_debug (size, gc, __FILE__, __LINE__); -#define clone_buf(buf) clone_buf_debug (buf, __FILE__, __LINE__); -#define gc_malloc(size, clear, arena) gc_malloc_debug (size, clear, arena, __FILE__, __LINE__) -#define string_alloc(str, gc) string_alloc_debug (str, gc, __FILE__, __LINE__) -#define string_alloc_buf(str, gc) string_alloc_buf_debug (str, gc, __FILE__, __LINE__) +#define alloc_buf(size) alloc_buf_debug(size, __FILE__, __LINE__) +#define alloc_buf_gc(size, gc) alloc_buf_gc_debug(size, gc, __FILE__, __LINE__); +#define clone_buf(buf) clone_buf_debug(buf, __FILE__, __LINE__); +#define gc_malloc(size, clear, arena) gc_malloc_debug(size, clear, arena, __FILE__, __LINE__) +#define string_alloc(str, gc) string_alloc_debug(str, gc, __FILE__, __LINE__) +#define string_alloc_buf(str, gc) string_alloc_buf_debug(str, gc, __FILE__, __LINE__) -struct buffer alloc_buf_debug (size_t size, const char *file, int line); -struct buffer alloc_buf_gc_debug (size_t size, struct gc_arena *gc, const char *file, int line); -struct buffer clone_buf_debug (const struct buffer* buf, const char *file, int line); -void *gc_malloc_debug (size_t size, bool clear, struct gc_arena *a, const char *file, int line); -char *string_alloc_debug (const char *str, struct gc_arena *gc, const char *file, int line); -struct buffer string_alloc_buf_debug (const char *str, struct gc_arena *gc, const char *file, int line); +struct buffer alloc_buf_debug(size_t size, const char *file, int line); -#else +struct buffer alloc_buf_gc_debug(size_t size, struct gc_arena *gc, const char *file, int line); -struct buffer alloc_buf (size_t size); -struct buffer alloc_buf_gc (size_t size, struct gc_arena *gc); /* allocate buffer with garbage collection */ -struct buffer clone_buf (const struct buffer* buf); -void *gc_malloc (size_t size, bool clear, struct gc_arena *a); -char *string_alloc (const char *str, struct gc_arena *gc); -struct buffer string_alloc_buf (const char *str, struct gc_arena *gc); +struct buffer clone_buf_debug(const struct buffer *buf, const char *file, int line); -#endif +void *gc_malloc_debug(size_t size, bool clear, struct gc_arena *a, const char *file, int line); + +char *string_alloc_debug(const char *str, struct gc_arena *gc, const char *file, int line); + +struct buffer string_alloc_buf_debug(const char *str, struct gc_arena *gc, const char *file, int line); + +#else /* ifdef DMALLOC */ + +struct buffer alloc_buf(size_t size); + +struct buffer alloc_buf_gc(size_t size, struct gc_arena *gc); /* allocate buffer with garbage collection */ -void gc_addspecial (void *addr, void (*free_function)(void*), struct gc_arena *a); +struct buffer clone_buf(const struct buffer *buf); + +void *gc_malloc(size_t size, bool clear, struct gc_arena *a); + +char *string_alloc(const char *str, struct gc_arena *gc); + +struct buffer string_alloc_buf(const char *str, struct gc_arena *gc); + +#endif /* ifdef DMALLOC */ + +void gc_addspecial(void *addr, void (*free_function)(void *), struct gc_arena *a); #ifdef BUF_INIT_TRACKING -#define buf_init(buf, offset) buf_init_debug (buf, offset, __FILE__, __LINE__) -bool buf_init_debug (struct buffer *buf, int offset, const char *file, int line); +#define buf_init(buf, offset) buf_init_debug(buf, offset, __FILE__, __LINE__) +bool buf_init_debug(struct buffer *buf, int offset, const char *file, int line); + #else -#define buf_init(buf, offset) buf_init_dowork (buf, offset) +#define buf_init(buf, offset) buf_init_dowork(buf, offset) #endif /* inline functions */ inline static void -gc_freeaddrinfo_callback (void *addr) +gc_freeaddrinfo_callback(void *addr) { - freeaddrinfo((struct addrinfo*) addr); + freeaddrinfo((struct addrinfo *) addr); } static inline bool -buf_defined (const struct buffer *buf) +buf_defined(const struct buffer *buf) { - return buf->data != NULL; + return buf->data != NULL; } static inline bool -buf_valid (const struct buffer *buf) +buf_valid(const struct buffer *buf) { - return likely (buf->data != NULL) && likely (buf->len >= 0); + return likely(buf->data != NULL) && likely(buf->len >= 0); } static inline uint8_t * -buf_bptr (const struct buffer *buf) +buf_bptr(const struct buffer *buf) { - if (buf_valid (buf)) - return buf->data + buf->offset; - else - return NULL; + if (buf_valid(buf)) + { + return buf->data + buf->offset; + } + else + { + return NULL; + } } static int -buf_len (const struct buffer *buf) +buf_len(const struct buffer *buf) { - if (buf_valid (buf)) - return buf->len; - else - return 0; + if (buf_valid(buf)) + { + return buf->len; + } + else + { + return 0; + } } static inline uint8_t * -buf_bend (const struct buffer *buf) +buf_bend(const struct buffer *buf) { - return buf_bptr (buf) + buf_len (buf); + return buf_bptr(buf) + buf_len(buf); } static inline uint8_t * -buf_blast (const struct buffer *buf) +buf_blast(const struct buffer *buf) { - if (buf_len (buf) > 0) - return buf_bptr (buf) + buf_len (buf) - 1; - else - return NULL; + if (buf_len(buf) > 0) + { + return buf_bptr(buf) + buf_len(buf) - 1; + } + else + { + return NULL; + } } static inline bool -buf_size_valid (const size_t size) +buf_size_valid(const size_t size) { - return likely (size < BUF_SIZE_MAX); + return likely(size < BUF_SIZE_MAX); } static inline bool -buf_size_valid_signed (const int size) +buf_size_valid_signed(const int size) { - return likely (size >= -BUF_SIZE_MAX) && likely (size < BUF_SIZE_MAX); + return likely(size >= -BUF_SIZE_MAX) && likely(size < BUF_SIZE_MAX); } static inline char * -buf_str (const struct buffer *buf) +buf_str(const struct buffer *buf) { - return (char *)buf_bptr(buf); + return (char *)buf_bptr(buf); } static inline void -buf_reset (struct buffer *buf) +buf_reset(struct buffer *buf) { - buf->capacity = 0; - buf->offset = 0; - buf->len = 0; - buf->data = NULL; + buf->capacity = 0; + buf->offset = 0; + buf->len = 0; + buf->data = NULL; } static inline void -buf_reset_len (struct buffer *buf) +buf_reset_len(struct buffer *buf) { - buf->len = 0; - buf->offset = 0; + buf->len = 0; + buf->offset = 0; } static inline bool -buf_init_dowork (struct buffer *buf, int offset) +buf_init_dowork(struct buffer *buf, int offset) { - if (offset < 0 || offset > buf->capacity || buf->data == NULL) - return false; - buf->len = 0; - buf->offset = offset; - return true; + if (offset < 0 || offset > buf->capacity || buf->data == NULL) + { + return false; + } + buf->len = 0; + buf->offset = offset; + return true; } static inline void -buf_set_write (struct buffer *buf, uint8_t *data, int size) +buf_set_write(struct buffer *buf, uint8_t *data, int size) { - if (!buf_size_valid (size)) - buf_size_error (size); - buf->len = 0; - buf->offset = 0; - buf->capacity = size; - buf->data = data; - if (size > 0 && data) - *data = 0; + if (!buf_size_valid(size)) + { + buf_size_error(size); + } + buf->len = 0; + buf->offset = 0; + buf->capacity = size; + buf->data = data; + if (size > 0 && data) + { + *data = 0; + } } static inline void -buf_set_read (struct buffer *buf, const uint8_t *data, int size) +buf_set_read(struct buffer *buf, const uint8_t *data, int size) { - if (!buf_size_valid (size)) - buf_size_error (size); - buf->len = buf->capacity = size; - buf->offset = 0; - buf->data = (uint8_t *)data; + if (!buf_size_valid(size)) + { + buf_size_error(size); + } + buf->len = buf->capacity = size; + buf->offset = 0; + buf->data = (uint8_t *)data; } /* Like strncpy but makes sure dest is always null terminated */ static inline void -strncpynt (char *dest, const char *src, size_t maxlen) +strncpynt(char *dest, const char *src, size_t maxlen) { - strncpy (dest, src, maxlen); - if (maxlen > 0) - dest[maxlen - 1] = 0; + strncpy(dest, src, maxlen); + if (maxlen > 0) + { + dest[maxlen - 1] = 0; + } } /* return true if string contains at least one numerical digit */ static inline bool -has_digit (const unsigned char* src) +has_digit(const unsigned char *src) { - unsigned char c; - while ((c = *src++)) + unsigned char c; + while ((c = *src++)) { - if (isdigit(c)) - return true; + if (isdigit(c)) + { + return true; + } } - return false; + return false; } /** @@ -353,21 +390,21 @@ has_digit (const unsigned char* src) * 3. If none of the above are available, use the volatile pointer * technique to zero memory one byte at a time. * - * @param data Pointer to data to zeroise. - * @param len Length of data, in bytes. + * @param data Pointer to data to zeroise. + * @param len Length of data, in bytes. */ static inline void -secure_memzero (void *data, size_t len) +secure_memzero(void *data, size_t len) { #if defined(_WIN32) - SecureZeroMemory (data, len); + SecureZeroMemory(data, len); #elif defined(__GNUC__) || defined(__clang__) - memset(data, 0, len); - __asm__ __volatile__("" : : "r"(data) : "memory"); + memset(data, 0, len); + __asm__ __volatile__ ("" : : "r" (data) : "memory"); #else - volatile char *p = (volatile char *) data; - while (len--) - *p++ = 0; + volatile char *p = (volatile char *) data; + while (len--) + *p++ = 0; #endif } @@ -377,20 +414,20 @@ secure_memzero (void *data, size_t len) * a final null character and thus use only * capacity - 1 */ -bool buf_printf (struct buffer *buf, const char *format, ...) +bool buf_printf(struct buffer *buf, const char *format, ...) #ifdef __GNUC__ #if __USE_MINGW_ANSI_STDIO - __attribute__ ((format (gnu_printf, 2, 3))) +__attribute__ ((format(gnu_printf, 2, 3))) #else - __attribute__ ((format (__printf__, 2, 3))) +__attribute__ ((format(__printf__, 2, 3))) #endif #endif - ; +; /* * puts append to a buffer with overflow check */ -bool buf_puts (struct buffer *buf, const char *str); +bool buf_puts(struct buffer *buf, const char *str); /* * Like snprintf but guarantees null termination for size > 0 @@ -398,50 +435,55 @@ bool buf_puts (struct buffer *buf, const char *str); bool openvpn_snprintf(char *str, size_t size, const char *format, ...) #ifdef __GNUC__ #if __USE_MINGW_ANSI_STDIO - __attribute__ ((format (gnu_printf, 3, 4))) +__attribute__ ((format(gnu_printf, 3, 4))) #else - __attribute__ ((format (__printf__, 3, 4))) +__attribute__ ((format(__printf__, 3, 4))) #endif #endif - ; +; /* * remove/add trailing characters */ -void buf_null_terminate (struct buffer *buf); -void buf_chomp (struct buffer *buf); -void buf_rmtail (struct buffer *buf, uint8_t remove); +void buf_null_terminate(struct buffer *buf); + +void buf_chomp(struct buffer *buf); + +void buf_rmtail(struct buffer *buf, uint8_t remove); /* * non-buffer string functions */ -void chomp (char *str); -void rm_trailing_chars (char *str, const char *what_to_delete); -const char *skip_leading_whitespace (const char *str); -void string_null_terminate (char *str, int len, int capacity); +void chomp(char *str); + +void rm_trailing_chars(char *str, const char *what_to_delete); + +const char *skip_leading_whitespace(const char *str); + +void string_null_terminate(char *str, int len, int capacity); /* * Write string in buf to file descriptor fd. * NOTE: requires that string be null terminated. */ -void buf_write_string_file (const struct buffer *buf, const char *filename, int fd); +void buf_write_string_file(const struct buffer *buf, const char *filename, int fd); /* * write a string to the end of a buffer that was * truncated by buf_printf */ -void buf_catrunc (struct buffer *buf, const char *str); +void buf_catrunc(struct buffer *buf, const char *str); /* * convert a multi-line output to one line */ -void convert_to_one_line (struct buffer *buf); +void convert_to_one_line(struct buffer *buf); /* * Parse a string based on a given delimiter char */ -bool buf_parse (struct buffer *buf, const int delim, char *line, const int size); +bool buf_parse(struct buffer *buf, const int delim, char *line, const int size); /* * Hex dump -- Output a binary buffer to a hex string and return it. @@ -449,88 +491,104 @@ bool buf_parse (struct buffer *buf, const int delim, char *line, const int size) #define FHE_SPACE_BREAK_MASK 0xFF /* space_break parameter in lower 8 bits */ #define FHE_CAPS 0x100 /* output hex in caps */ char * -format_hex_ex (const uint8_t *data, int size, int maxoutput, - unsigned int space_break_flags, const char* separator, - struct gc_arena *gc); +format_hex_ex(const uint8_t *data, int size, int maxoutput, + unsigned int space_break_flags, const char *separator, + struct gc_arena *gc); static inline char * -format_hex (const uint8_t *data, int size, int maxoutput, struct gc_arena *gc) +format_hex(const uint8_t *data, int size, int maxoutput, struct gc_arena *gc) { - return format_hex_ex (data, size, maxoutput, 4, " ", gc); + return format_hex_ex(data, size, maxoutput, 4, " ", gc); } /* * Return a buffer that is a subset of another buffer. */ -struct buffer buf_sub (struct buffer *buf, int size, bool prepend); +struct buffer buf_sub(struct buffer *buf, int size, bool prepend); /* * Check if sufficient space to append to buffer. */ static inline bool -buf_safe (const struct buffer *buf, int len) +buf_safe(const struct buffer *buf, int len) { - return buf_valid (buf) && buf_size_valid (len) - && buf->offset + buf->len + len <= buf->capacity; + return buf_valid(buf) && buf_size_valid(len) + && buf->offset + buf->len + len <= buf->capacity; } static inline bool -buf_safe_bidir (const struct buffer *buf, int len) +buf_safe_bidir(const struct buffer *buf, int len) { - if (buf_valid (buf) && buf_size_valid_signed (len)) + if (buf_valid(buf) && buf_size_valid_signed(len)) { - const int newlen = buf->len + len; - return newlen >= 0 && buf->offset + newlen <= buf->capacity; + const int newlen = buf->len + len; + return newlen >= 0 && buf->offset + newlen <= buf->capacity; + } + else + { + return false; } - else - return false; } static inline int -buf_forward_capacity (const struct buffer *buf) +buf_forward_capacity(const struct buffer *buf) { - if (buf_valid (buf)) + if (buf_valid(buf)) + { + int ret = buf->capacity - (buf->offset + buf->len); + if (ret < 0) + { + ret = 0; + } + return ret; + } + else { - int ret = buf->capacity - (buf->offset + buf->len); - if (ret < 0) - ret = 0; - return ret; + return 0; } - else - return 0; } static inline int -buf_forward_capacity_total (const struct buffer *buf) +buf_forward_capacity_total(const struct buffer *buf) { - if (buf_valid (buf)) + if (buf_valid(buf)) + { + int ret = buf->capacity - buf->offset; + if (ret < 0) + { + ret = 0; + } + return ret; + } + else { - int ret = buf->capacity - buf->offset; - if (ret < 0) - ret = 0; - return ret; + return 0; } - else - return 0; } static inline int -buf_reverse_capacity (const struct buffer *buf) +buf_reverse_capacity(const struct buffer *buf) { - if (buf_valid (buf)) - return buf->offset; - else - return 0; + if (buf_valid(buf)) + { + return buf->offset; + } + else + { + return 0; + } } static inline bool -buf_inc_len (struct buffer *buf, int inc) +buf_inc_len(struct buffer *buf, int inc) { - if (!buf_safe_bidir (buf, inc)) - return false; - buf->len += inc; - return true; + if (!buf_safe_bidir(buf, inc)) + { + return false; + } + buf->len += inc; + return true; } /* @@ -539,23 +597,27 @@ buf_inc_len (struct buffer *buf, int inc) */ static inline uint8_t * -buf_prepend (struct buffer *buf, int size) +buf_prepend(struct buffer *buf, int size) { - if (!buf_valid (buf) || size < 0 || size > buf->offset) - return NULL; - buf->offset -= size; - buf->len += size; - return BPTR (buf); + if (!buf_valid(buf) || size < 0 || size > buf->offset) + { + return NULL; + } + buf->offset -= size; + buf->len += size; + return BPTR(buf); } static inline bool -buf_advance (struct buffer *buf, int size) +buf_advance(struct buffer *buf, int size) { - if (!buf_valid (buf) || size < 0 || buf->len < size) - return false; - buf->offset += size; - buf->len -= size; - return true; + if (!buf_valid(buf) || size < 0 || buf->len < size) + { + return false; + } + buf->offset += size; + buf->len -= size; + return true; } /* @@ -564,176 +626,204 @@ buf_advance (struct buffer *buf, int size) */ static inline uint8_t * -buf_write_alloc (struct buffer *buf, int size) +buf_write_alloc(struct buffer *buf, int size) { - uint8_t *ret; - if (!buf_safe (buf, size)) - return NULL; - ret = BPTR (buf) + buf->len; - buf->len += size; - return ret; + uint8_t *ret; + if (!buf_safe(buf, size)) + { + return NULL; + } + ret = BPTR(buf) + buf->len; + buf->len += size; + return ret; } static inline uint8_t * -buf_write_alloc_prepend (struct buffer *buf, int size, bool prepend) +buf_write_alloc_prepend(struct buffer *buf, int size, bool prepend) { - return prepend ? buf_prepend (buf, size) : buf_write_alloc (buf, size); + return prepend ? buf_prepend(buf, size) : buf_write_alloc(buf, size); } static inline uint8_t * -buf_read_alloc (struct buffer *buf, int size) +buf_read_alloc(struct buffer *buf, int size) { - uint8_t *ret; - if (size < 0 || buf->len < size) - return NULL; - ret = BPTR (buf); - buf->offset += size; - buf->len -= size; - return ret; + uint8_t *ret; + if (size < 0 || buf->len < size) + { + return NULL; + } + ret = BPTR(buf); + buf->offset += size; + buf->len -= size; + return ret; } static inline bool -buf_write (struct buffer *dest, const void *src, int size) +buf_write(struct buffer *dest, const void *src, int size) { - uint8_t *cp = buf_write_alloc (dest, size); - if (!cp) - return false; - memcpy (cp, src, size); - return true; + uint8_t *cp = buf_write_alloc(dest, size); + if (!cp) + { + return false; + } + memcpy(cp, src, size); + return true; } static inline bool -buf_write_prepend (struct buffer *dest, const void *src, int size) +buf_write_prepend(struct buffer *dest, const void *src, int size) { - uint8_t *cp = buf_prepend (dest, size); - if (!cp) - return false; - memcpy (cp, src, size); - return true; + uint8_t *cp = buf_prepend(dest, size); + if (!cp) + { + return false; + } + memcpy(cp, src, size); + return true; } static inline bool -buf_write_u8 (struct buffer *dest, int data) +buf_write_u8(struct buffer *dest, int data) { - uint8_t u8 = (uint8_t) data; - return buf_write (dest, &u8, sizeof (uint8_t)); + uint8_t u8 = (uint8_t) data; + return buf_write(dest, &u8, sizeof(uint8_t)); } static inline bool -buf_write_u16 (struct buffer *dest, int data) +buf_write_u16(struct buffer *dest, int data) { - uint16_t u16 = htons ((uint16_t) data); - return buf_write (dest, &u16, sizeof (uint16_t)); + uint16_t u16 = htons((uint16_t) data); + return buf_write(dest, &u16, sizeof(uint16_t)); } static inline bool -buf_write_u32 (struct buffer *dest, int data) +buf_write_u32(struct buffer *dest, int data) { - uint32_t u32 = htonl ((uint32_t) data); - return buf_write (dest, &u32, sizeof (uint32_t)); + uint32_t u32 = htonl((uint32_t) data); + return buf_write(dest, &u32, sizeof(uint32_t)); } static inline bool -buf_copy (struct buffer *dest, const struct buffer *src) +buf_copy(struct buffer *dest, const struct buffer *src) { - return buf_write (dest, BPTR (src), BLEN (src)); + return buf_write(dest, BPTR(src), BLEN(src)); } static inline bool -buf_copy_n (struct buffer *dest, struct buffer *src, int n) +buf_copy_n(struct buffer *dest, struct buffer *src, int n) { - uint8_t *cp = buf_read_alloc (src, n); - if (!cp) - return false; - return buf_write (dest, cp, n); + uint8_t *cp = buf_read_alloc(src, n); + if (!cp) + { + return false; + } + return buf_write(dest, cp, n); } static inline bool -buf_copy_range (struct buffer *dest, - int dest_index, - const struct buffer *src, - int src_index, - int src_len) -{ - if (src_index < 0 - || src_len < 0 - || src_index + src_len > src->len - || dest_index < 0 - || dest->offset + dest_index + src_len > dest->capacity) - return false; - memcpy (dest->data + dest->offset + dest_index, src->data + src->offset + src_index, src_len); - if (dest_index + src_len > dest->len) - dest->len = dest_index + src_len; - return true; +buf_copy_range(struct buffer *dest, + int dest_index, + const struct buffer *src, + int src_index, + int src_len) +{ + if (src_index < 0 + || src_len < 0 + || src_index + src_len > src->len + || dest_index < 0 + || dest->offset + dest_index + src_len > dest->capacity) + { + return false; + } + memcpy(dest->data + dest->offset + dest_index, src->data + src->offset + src_index, src_len); + if (dest_index + src_len > dest->len) + { + dest->len = dest_index + src_len; + } + return true; } /* truncate src to len, copy excess data beyond len to dest */ static inline bool -buf_copy_excess (struct buffer *dest, - struct buffer *src, - int len) +buf_copy_excess(struct buffer *dest, + struct buffer *src, + int len) { - if (len < 0) - return false; - if (src->len > len) + if (len < 0) + { + return false; + } + if (src->len > len) { - struct buffer b = *src; - src->len = len; - if (!buf_advance (&b, len)) - return false; - return buf_copy (dest, &b); + struct buffer b = *src; + src->len = len; + if (!buf_advance(&b, len)) + { + return false; + } + return buf_copy(dest, &b); } - else + else { - return true; + return true; } } static inline bool -buf_read (struct buffer *src, void *dest, int size) +buf_read(struct buffer *src, void *dest, int size) { - uint8_t *cp = buf_read_alloc (src, size); - if (!cp) - return false; - memcpy (dest, cp, size); - return true; + uint8_t *cp = buf_read_alloc(src, size); + if (!cp) + { + return false; + } + memcpy(dest, cp, size); + return true; } static inline int -buf_read_u8 (struct buffer *buf) +buf_read_u8(struct buffer *buf) { - int ret; - if (BLEN (buf) < 1) - return -1; - ret = *BPTR(buf); - buf_advance (buf, 1); - return ret; + int ret; + if (BLEN(buf) < 1) + { + return -1; + } + ret = *BPTR(buf); + buf_advance(buf, 1); + return ret; } static inline int -buf_read_u16 (struct buffer *buf) +buf_read_u16(struct buffer *buf) { - uint16_t ret; - if (!buf_read (buf, &ret, sizeof (uint16_t))) - return -1; - return ntohs (ret); + uint16_t ret; + if (!buf_read(buf, &ret, sizeof(uint16_t))) + { + return -1; + } + return ntohs(ret); } static inline uint32_t -buf_read_u32 (struct buffer *buf, bool *good) +buf_read_u32(struct buffer *buf, bool *good) { - uint32_t ret; - if (!buf_read (buf, &ret, sizeof (uint32_t))) + uint32_t ret; + if (!buf_read(buf, &ret, sizeof(uint32_t))) { - if (good) - *good = false; - return 0; + if (good) + { + *good = false; + } + return 0; } - else + else { - if (good) - *good = true; - return ntohl (ret); + if (good) + { + *good = true; + } + return ntohl(ret); } } @@ -742,11 +832,13 @@ buf_read_u32 (struct buffer *buf, bool *good) * *NOT* constant time. Do not use when comparing HMACs. */ static inline bool -buf_string_match (const struct buffer *src, const void *match, int size) +buf_string_match(const struct buffer *src, const void *match, int size) { - if (size != src->len) - return false; - return memcmp (BPTR (src), match, size) == 0; + if (size != src->len) + { + return false; + } + return memcmp(BPTR(src), match, size) == 0; } /** @@ -754,21 +846,25 @@ buf_string_match (const struct buffer *src, const void *match, int size) * *NOT* constant time. Do not use when comparing HMACs. */ static inline bool -buf_string_match_head (const struct buffer *src, const void *match, int size) +buf_string_match_head(const struct buffer *src, const void *match, int size) { - if (size < 0 || size > src->len) - return false; - return memcmp (BPTR (src), match, size) == 0; + if (size < 0 || size > src->len) + { + return false; + } + return memcmp(BPTR(src), match, size) == 0; } -bool buf_string_match_head_str (const struct buffer *src, const char *match); -bool buf_string_compare_advance (struct buffer *src, const char *match); -int buf_substring_len (const struct buffer *buf, int delim); +bool buf_string_match_head_str(const struct buffer *src, const char *match); + +bool buf_string_compare_advance(struct buffer *src, const char *match); + +int buf_substring_len(const struct buffer *buf, int delim); /* * Print a string which might be NULL */ -const char *np (const char *str); +const char *np(const char *str); /*#define CHARACTER_CLASS_DEBUG*/ @@ -813,30 +909,34 @@ const char *np (const char *str); #define CC_NAME (CC_ALNUM|CC_UNDERBAR) #define CC_CRLF (CC_CR|CC_NEWLINE) -bool char_class (const unsigned char c, const unsigned int flags); -bool string_class (const char *str, const unsigned int inclusive, const unsigned int exclusive); -bool string_mod (char *str, const unsigned int inclusive, const unsigned int exclusive, const char replace); +bool char_class(const unsigned char c, const unsigned int flags); + +bool string_class(const char *str, const unsigned int inclusive, const unsigned int exclusive); -const char *string_mod_const (const char *str, - const unsigned int inclusive, - const unsigned int exclusive, - const char replace, - struct gc_arena *gc); +bool string_mod(char *str, const unsigned int inclusive, const unsigned int exclusive, const char replace); -void string_replace_leading (char *str, const char match, const char replace); +const char *string_mod_const(const char *str, + const unsigned int inclusive, + const unsigned int exclusive, + const char replace, + struct gc_arena *gc); + +void string_replace_leading(char *str, const char match, const char replace); #ifdef CHARACTER_CLASS_DEBUG -void character_class_debug (void); +void character_class_debug(void); + #endif /* * Verify that a pointer is correctly aligned */ #ifdef VERIFY_ALIGNMENT - void valign4 (const struct buffer *buf, const char *file, const int line); -# define verify_align_4(ptr) valign4(buf, __FILE__, __LINE__) +void valign4(const struct buffer *buf, const char *file, const int line); + +#define verify_align_4(ptr) valign4(buf, __FILE__, __LINE__) #else -# define verify_align_4(ptr) +#define verify_align_4(ptr) #endif /* @@ -844,51 +944,56 @@ void character_class_debug (void); * char ptrs to malloced strings. */ -void gc_transfer (struct gc_arena *dest, struct gc_arena *src); +void gc_transfer(struct gc_arena *dest, struct gc_arena *src); + +void x_gc_free(struct gc_arena *a); -void x_gc_free (struct gc_arena *a); -void x_gc_freespecial (struct gc_arena *a); +void x_gc_freespecial(struct gc_arena *a); static inline bool -gc_defined (struct gc_arena *a) +gc_defined(struct gc_arena *a) { - return a->list != NULL; + return a->list != NULL; } static inline void -gc_init (struct gc_arena *a) +gc_init(struct gc_arena *a) { - a->list = NULL; - a->list_special = NULL; + a->list = NULL; + a->list_special = NULL; } static inline void -gc_detach (struct gc_arena *a) +gc_detach(struct gc_arena *a) { - gc_init (a); + gc_init(a); } static inline struct gc_arena -gc_new (void) +gc_new(void) { - struct gc_arena ret; - gc_init (&ret); - return ret; + struct gc_arena ret; + gc_init(&ret); + return ret; } static inline void -gc_free (struct gc_arena *a) +gc_free(struct gc_arena *a) { - if (a->list) - x_gc_free (a); - if (a->list_special) - x_gc_freespecial(a); + if (a->list) + { + x_gc_free(a); + } + if (a->list_special) + { + x_gc_freespecial(a); + } } static inline void -gc_reset (struct gc_arena *a) +gc_reset(struct gc_arena *a) { - gc_free (a); + gc_free(a); } /* @@ -896,57 +1001,59 @@ gc_reset (struct gc_arena *a) */ #define ALLOC_OBJ(dptr, type) \ -{ \ - check_malloc_return ((dptr) = (type *) malloc (sizeof (type))); \ -} + { \ + check_malloc_return((dptr) = (type *) malloc(sizeof(type))); \ + } #define ALLOC_OBJ_CLEAR(dptr, type) \ -{ \ - ALLOC_OBJ (dptr, type); \ - memset ((dptr), 0, sizeof(type)); \ -} + { \ + ALLOC_OBJ(dptr, type); \ + memset((dptr), 0, sizeof(type)); \ + } #define ALLOC_ARRAY(dptr, type, n) \ -{ \ - check_malloc_return ((dptr) = (type *) malloc (array_mult_safe (sizeof (type), (n), 0))); \ -} + { \ + check_malloc_return((dptr) = (type *) malloc(array_mult_safe(sizeof(type), (n), 0))); \ + } #define ALLOC_ARRAY_GC(dptr, type, n, gc) \ -{ \ - (dptr) = (type *) gc_malloc (array_mult_safe (sizeof (type), (n), 0), false, (gc)); \ -} + { \ + (dptr) = (type *) gc_malloc(array_mult_safe(sizeof(type), (n), 0), false, (gc)); \ + } #define ALLOC_ARRAY_CLEAR(dptr, type, n) \ -{ \ - ALLOC_ARRAY (dptr, type, n); \ - memset ((dptr), 0, (array_mult_safe (sizeof(type), (n), 0))); \ -} + { \ + ALLOC_ARRAY(dptr, type, n); \ + memset((dptr), 0, (array_mult_safe(sizeof(type), (n), 0))); \ + } #define ALLOC_ARRAY_CLEAR_GC(dptr, type, n, gc) \ -{ \ - (dptr) = (type *) gc_malloc (array_mult_safe (sizeof (type), (n), 0), true, (gc)); \ -} + { \ + (dptr) = (type *) gc_malloc(array_mult_safe(sizeof(type), (n), 0), true, (gc)); \ + } -#define ALLOC_VAR_ARRAY_CLEAR_GC(dptr, type, atype, n, gc) \ -{ \ - (dptr) = (type *) gc_malloc (array_mult_safe (sizeof (atype), (n), sizeof (type)), true, (gc)); \ -} +#define ALLOC_VAR_ARRAY_CLEAR_GC(dptr, type, atype, n, gc) \ + { \ + (dptr) = (type *) gc_malloc(array_mult_safe(sizeof(atype), (n), sizeof(type)), true, (gc)); \ + } #define ALLOC_OBJ_GC(dptr, type, gc) \ -{ \ - (dptr) = (type *) gc_malloc (sizeof (type), false, (gc)); \ -} + { \ + (dptr) = (type *) gc_malloc(sizeof(type), false, (gc)); \ + } #define ALLOC_OBJ_CLEAR_GC(dptr, type, gc) \ -{ \ - (dptr) = (type *) gc_malloc (sizeof (type), true, (gc)); \ -} + { \ + (dptr) = (type *) gc_malloc(sizeof(type), true, (gc)); \ + } static inline void -check_malloc_return (const void *p) +check_malloc_return(const void *p) { - if (!p) - out_of_memory (); + if (!p) + { + out_of_memory(); + } } /* @@ -954,32 +1061,40 @@ check_malloc_return (const void *p) */ struct buffer_entry { - struct buffer buf; - struct buffer_entry *next; + struct buffer buf; + struct buffer_entry *next; }; struct buffer_list { - struct buffer_entry *head; /* next item to pop/peek */ - struct buffer_entry *tail; /* last item pushed */ - int size; /* current number of entries */ - int max_size; /* maximum size list should grow to */ + struct buffer_entry *head; /* next item to pop/peek */ + struct buffer_entry *tail; /* last item pushed */ + int size; /* current number of entries */ + int max_size; /* maximum size list should grow to */ }; -struct buffer_list *buffer_list_new (const int max_size); -void buffer_list_free (struct buffer_list *ol); +struct buffer_list *buffer_list_new(const int max_size); + +void buffer_list_free(struct buffer_list *ol); + +bool buffer_list_defined(const struct buffer_list *ol); + +void buffer_list_reset(struct buffer_list *ol); + +void buffer_list_push(struct buffer_list *ol, const unsigned char *str); + +struct buffer_entry *buffer_list_push_data(struct buffer_list *ol, const uint8_t *data, size_t size); + +struct buffer *buffer_list_peek(struct buffer_list *ol); + +void buffer_list_advance(struct buffer_list *ol, int n); + +void buffer_list_pop(struct buffer_list *ol); -bool buffer_list_defined (const struct buffer_list *ol); -void buffer_list_reset (struct buffer_list *ol); +void buffer_list_aggregate(struct buffer_list *bl, const size_t max); -void buffer_list_push (struct buffer_list *ol, const unsigned char *str); -struct buffer_entry *buffer_list_push_data (struct buffer_list *ol, const uint8_t *data, size_t size); -struct buffer *buffer_list_peek (struct buffer_list *ol); -void buffer_list_advance (struct buffer_list *ol, int n); -void buffer_list_pop (struct buffer_list *ol); +void buffer_list_aggregate_separator(struct buffer_list *bl, const size_t max, const char *sep); -void buffer_list_aggregate (struct buffer_list *bl, const size_t max); -void buffer_list_aggregate_separator (struct buffer_list *bl, const size_t max, const char *sep); +struct buffer_list *buffer_list_file(const char *fn, int max_line_len); -struct buffer_list *buffer_list_file (const char *fn, int max_line_len); #endif /* BUFFER_H */ diff --git a/src/openvpn/circ_list.h b/src/openvpn/circ_list.h index 583701a5076..b4324d8e50a 100644 --- a/src/openvpn/circ_list.h +++ b/src/openvpn/circ_list.h @@ -30,49 +30,49 @@ #include "error.h" #define CIRC_LIST(name, type) \ -struct name { \ - int x_head; \ - int x_size; \ - int x_cap; \ - int x_sizeof; \ - type x_list[EMPTY_ARRAY_SIZE]; \ -} + struct name { \ + int x_head; \ + int x_size; \ + int x_cap; \ + int x_sizeof; \ + type x_list[EMPTY_ARRAY_SIZE]; \ + } #define CIRC_LIST_PUSH(obj, item) \ -{ \ - (obj)->x_head = modulo_add ((obj)->x_head, -1, (obj)->x_cap); \ - (obj)->x_list[(obj)->x_head] = (item); \ - (obj)->x_size = min_int ((obj)->x_size + 1, (obj)->x_cap); \ -} + { \ + (obj)->x_head = modulo_add((obj)->x_head, -1, (obj)->x_cap); \ + (obj)->x_list[(obj)->x_head] = (item); \ + (obj)->x_size = min_int((obj)->x_size + 1, (obj)->x_cap); \ + } #define CIRC_LIST_SIZE(obj) \ - ((obj)->x_size) + ((obj)->x_size) #define CIRC_LIST_INDEX(obj, index) \ - modulo_add ((obj)->x_head, \ - index_verify ((index), (obj)->x_size, __FILE__, __LINE__), \ - (obj)->x_cap) + modulo_add((obj)->x_head, \ + index_verify((index), (obj)->x_size, __FILE__, __LINE__), \ + (obj)->x_cap) #define CIRC_LIST_ITEM(obj, index) \ - ((obj)->x_list[CIRC_LIST_INDEX((obj), (index))]) + ((obj)->x_list[CIRC_LIST_INDEX((obj), (index))]) #define CIRC_LIST_RESET(obj) \ -{ \ - (obj)->x_head = 0; \ - (obj)->x_size = 0; \ -} + { \ + (obj)->x_head = 0; \ + (obj)->x_size = 0; \ + } #define CIRC_LIST_ALLOC(dest, list_type, size) \ -{ \ - const int so = sizeof (list_type) + sizeof ((dest)->x_list[0]) * (size); \ - (dest) = (list_type *) malloc (so); \ - check_malloc_return (dest); \ - memset ((dest), 0, so); \ - (dest)->x_cap = size; \ - (dest)->x_sizeof = so; \ -} + { \ + const int so = sizeof(list_type) + sizeof((dest)->x_list[0]) * (size); \ + (dest) = (list_type *) malloc(so); \ + check_malloc_return(dest); \ + memset((dest), 0, so); \ + (dest)->x_cap = size; \ + (dest)->x_sizeof = so; \ + } #define CIRC_LIST_FREE(dest) \ - free (dest) + free(dest) -#endif +#endif /* ifndef CIRC_LIST_H */ diff --git a/src/openvpn/clinat.c b/src/openvpn/clinat.c index ddefe123fb1..08d7acf42fa 100644 --- a/src/openvpn/clinat.c +++ b/src/openvpn/clinat.c @@ -37,229 +37,243 @@ static bool add_entry(struct client_nat_option_list *dest, - const struct client_nat_entry *e) + const struct client_nat_entry *e) { - if (dest->n >= MAX_CLIENT_NAT) + if (dest->n >= MAX_CLIENT_NAT) { - msg (M_WARN, "WARNING: client-nat table overflow (max %d entries)", MAX_CLIENT_NAT); - return false; + msg(M_WARN, "WARNING: client-nat table overflow (max %d entries)", MAX_CLIENT_NAT); + return false; } - else + else { - dest->entries[dest->n++] = *e; - return true; + dest->entries[dest->n++] = *e; + return true; } } void print_client_nat_list(const struct client_nat_option_list *list, int msglevel) { - struct gc_arena gc = gc_new (); - int i; + struct gc_arena gc = gc_new(); + int i; - msg (msglevel, "*** CNAT list"); - if (list) + msg(msglevel, "*** CNAT list"); + if (list) { - for (i = 0; i < list->n; ++i) - { - const struct client_nat_entry *e = &list->entries[i]; - msg (msglevel, " CNAT[%d] t=%d %s/%s/%s", - i, - e->type, - print_in_addr_t (e->network, IA_NET_ORDER, &gc), - print_in_addr_t (e->netmask, IA_NET_ORDER, &gc), - print_in_addr_t (e->foreign_network, IA_NET_ORDER, &gc)); - } + for (i = 0; i < list->n; ++i) + { + const struct client_nat_entry *e = &list->entries[i]; + msg(msglevel, " CNAT[%d] t=%d %s/%s/%s", + i, + e->type, + print_in_addr_t(e->network, IA_NET_ORDER, &gc), + print_in_addr_t(e->netmask, IA_NET_ORDER, &gc), + print_in_addr_t(e->foreign_network, IA_NET_ORDER, &gc)); + } } - gc_free (&gc); + gc_free(&gc); } struct client_nat_option_list * -new_client_nat_list (struct gc_arena *gc) +new_client_nat_list(struct gc_arena *gc) { - struct client_nat_option_list *ret; - ALLOC_OBJ_CLEAR_GC (ret, struct client_nat_option_list, gc); - return ret; + struct client_nat_option_list *ret; + ALLOC_OBJ_CLEAR_GC(ret, struct client_nat_option_list, gc); + return ret; } struct client_nat_option_list * -clone_client_nat_option_list (const struct client_nat_option_list *src, struct gc_arena *gc) +clone_client_nat_option_list(const struct client_nat_option_list *src, struct gc_arena *gc) { - struct client_nat_option_list *ret; - ALLOC_OBJ_GC (ret, struct client_nat_option_list, gc); - *ret = *src; - return ret; + struct client_nat_option_list *ret; + ALLOC_OBJ_GC(ret, struct client_nat_option_list, gc); + *ret = *src; + return ret; } void -copy_client_nat_option_list (struct client_nat_option_list *dest, - const struct client_nat_option_list *src) +copy_client_nat_option_list(struct client_nat_option_list *dest, + const struct client_nat_option_list *src) { - int i; - for (i = 0; i < src->n; ++i) + int i; + for (i = 0; i < src->n; ++i) { - if (!add_entry(dest, &src->entries[i])) - break; + if (!add_entry(dest, &src->entries[i])) + { + break; + } } } void -add_client_nat_to_option_list (struct client_nat_option_list *dest, - const char *type, - const char *network, - const char *netmask, - const char *foreign_network, - int msglevel) +add_client_nat_to_option_list(struct client_nat_option_list *dest, + const char *type, + const char *network, + const char *netmask, + const char *foreign_network, + int msglevel) { - struct client_nat_entry e; - bool ok; + struct client_nat_entry e; + bool ok; - if (!strcmp(type, "snat")) - e.type = CN_SNAT; - else if (!strcmp(type, "dnat")) - e.type = CN_DNAT; - else + if (!strcmp(type, "snat")) { - msg(msglevel, "client-nat: type must be 'snat' or 'dnat'"); - return; + e.type = CN_SNAT; + } + else if (!strcmp(type, "dnat")) + { + e.type = CN_DNAT; + } + else + { + msg(msglevel, "client-nat: type must be 'snat' or 'dnat'"); + return; } - e.network = getaddr(0, network, 0, &ok, NULL); - if (!ok) + e.network = getaddr(0, network, 0, &ok, NULL); + if (!ok) { - msg(msglevel, "client-nat: bad network: %s", network); - return; + msg(msglevel, "client-nat: bad network: %s", network); + return; } - e.netmask = getaddr(0, netmask, 0, &ok, NULL); - if (!ok) + e.netmask = getaddr(0, netmask, 0, &ok, NULL); + if (!ok) { - msg(msglevel, "client-nat: bad netmask: %s", netmask); - return; + msg(msglevel, "client-nat: bad netmask: %s", netmask); + return; } - e.foreign_network = getaddr(0, foreign_network, 0, &ok, NULL); - if (!ok) + e.foreign_network = getaddr(0, foreign_network, 0, &ok, NULL); + if (!ok) { - msg(msglevel, "client-nat: bad foreign network: %s", foreign_network); - return; + msg(msglevel, "client-nat: bad foreign network: %s", foreign_network); + return; } - add_entry(dest, &e); + add_entry(dest, &e); } #if 0 static void -print_checksum (struct openvpn_iphdr *iph, const char *prefix) +print_checksum(struct openvpn_iphdr *iph, const char *prefix) { - uint16_t *sptr; - unsigned int sum = 0; - int i = 0; - for (sptr = (uint16_t *)iph; (uint8_t *)sptr < (uint8_t *)iph + sizeof(struct openvpn_iphdr); sptr++) + uint16_t *sptr; + unsigned int sum = 0; + int i = 0; + for (sptr = (uint16_t *)iph; (uint8_t *)sptr < (uint8_t *)iph + sizeof(struct openvpn_iphdr); sptr++) { - i += 1; - sum += *sptr; + i += 1; + sum += *sptr; } - msg (M_INFO, "** CKSUM[%d] %s %08x", i, prefix, sum); + msg(M_INFO, "** CKSUM[%d] %s %08x", i, prefix, sum); } #endif static void -print_pkt (struct openvpn_iphdr *iph, const char *prefix, const int direction, const int msglevel) +print_pkt(struct openvpn_iphdr *iph, const char *prefix, const int direction, const int msglevel) { - struct gc_arena gc = gc_new (); + struct gc_arena gc = gc_new(); - char *dirstr = "???"; - if (direction == CN_OUTGOING) - dirstr = "OUT"; - else if (direction == CN_INCOMING) - dirstr = "IN"; + char *dirstr = "???"; + if (direction == CN_OUTGOING) + { + dirstr = "OUT"; + } + else if (direction == CN_INCOMING) + { + dirstr = "IN"; + } + + msg(msglevel, "** CNAT %s %s %s -> %s", + dirstr, + prefix, + print_in_addr_t(iph->saddr, IA_NET_ORDER, &gc), + print_in_addr_t(iph->daddr, IA_NET_ORDER, &gc)); - msg(msglevel, "** CNAT %s %s %s -> %s", - dirstr, - prefix, - print_in_addr_t (iph->saddr, IA_NET_ORDER, &gc), - print_in_addr_t (iph->daddr, IA_NET_ORDER, &gc)); - - gc_free (&gc); + gc_free(&gc); } void -client_nat_transform (const struct client_nat_option_list *list, - struct buffer *ipbuf, - const int direction) +client_nat_transform(const struct client_nat_option_list *list, + struct buffer *ipbuf, + const int direction) { - struct ip_tcp_udp_hdr *h = (struct ip_tcp_udp_hdr *) BPTR (ipbuf); - int i; - uint32_t addr, *addr_ptr; - const uint32_t *from, *to; - int accumulate = 0; - unsigned int amask; - unsigned int alog = 0; + struct ip_tcp_udp_hdr *h = (struct ip_tcp_udp_hdr *) BPTR(ipbuf); + int i; + uint32_t addr, *addr_ptr; + const uint32_t *from, *to; + int accumulate = 0; + unsigned int amask; + unsigned int alog = 0; - if (check_debug_level (D_CLIENT_NAT)) - print_pkt (&h->ip, "BEFORE", direction, D_CLIENT_NAT); + if (check_debug_level(D_CLIENT_NAT)) + { + print_pkt(&h->ip, "BEFORE", direction, D_CLIENT_NAT); + } - for (i = 0; i < list->n; ++i) + for (i = 0; i < list->n; ++i) { - const struct client_nat_entry *e = &list->entries[i]; /* current NAT rule */ - if (e->type ^ direction) - { - addr = *(addr_ptr = &h->ip.daddr); - amask = 2; - } - else - { - addr = *(addr_ptr = &h->ip.saddr); - amask = 1; - } - if (direction) - { - from = &e->foreign_network; - to = &e->network; - } - else - { - from = &e->network; - to = &e->foreign_network; - } + const struct client_nat_entry *e = &list->entries[i]; /* current NAT rule */ + if (e->type ^ direction) + { + addr = *(addr_ptr = &h->ip.daddr); + amask = 2; + } + else + { + addr = *(addr_ptr = &h->ip.saddr); + amask = 1; + } + if (direction) + { + from = &e->foreign_network; + to = &e->network; + } + else + { + from = &e->network; + to = &e->foreign_network; + } - if (((addr & e->netmask) == *from) && !(amask & alog)) - { - /* pre-adjust IP checksum */ - ADD_CHECKSUM_32(accumulate, addr); + if (((addr & e->netmask) == *from) && !(amask & alog)) + { + /* pre-adjust IP checksum */ + ADD_CHECKSUM_32(accumulate, addr); - /* do NAT transform */ - addr = (addr & ~e->netmask) | *to; + /* do NAT transform */ + addr = (addr & ~e->netmask) | *to; - /* post-adjust IP checksum */ - SUB_CHECKSUM_32(accumulate, addr); + /* post-adjust IP checksum */ + SUB_CHECKSUM_32(accumulate, addr); - /* write the modified address to packet */ - *addr_ptr = addr; + /* write the modified address to packet */ + *addr_ptr = addr; - /* mark as modified */ - alog |= amask; - } + /* mark as modified */ + alog |= amask; + } } - if (alog) + if (alog) { - if (check_debug_level (D_CLIENT_NAT)) - print_pkt (&h->ip, "AFTER", direction, D_CLIENT_NAT); + if (check_debug_level(D_CLIENT_NAT)) + { + print_pkt(&h->ip, "AFTER", direction, D_CLIENT_NAT); + } - ADJUST_CHECKSUM(accumulate, h->ip.check); + ADJUST_CHECKSUM(accumulate, h->ip.check); - if (h->ip.protocol == OPENVPN_IPPROTO_TCP) - { - if (BLEN(ipbuf) >= sizeof(struct openvpn_iphdr) + sizeof(struct openvpn_tcphdr)) - { - ADJUST_CHECKSUM(accumulate, h->u.tcp.check); - } - } - else if (h->ip.protocol == OPENVPN_IPPROTO_UDP) - { - if (BLEN(ipbuf) >= sizeof(struct openvpn_iphdr) + sizeof(struct openvpn_udphdr)) - { - ADJUST_CHECKSUM(accumulate, h->u.udp.check); - } - } + if (h->ip.protocol == OPENVPN_IPPROTO_TCP) + { + if (BLEN(ipbuf) >= sizeof(struct openvpn_iphdr) + sizeof(struct openvpn_tcphdr)) + { + ADJUST_CHECKSUM(accumulate, h->u.tcp.check); + } + } + else if (h->ip.protocol == OPENVPN_IPPROTO_UDP) + { + if (BLEN(ipbuf) >= sizeof(struct openvpn_iphdr) + sizeof(struct openvpn_udphdr)) + { + ADJUST_CHECKSUM(accumulate, h->u.udp.check); + } + } } } diff --git a/src/openvpn/clinat.h b/src/openvpn/clinat.h index a5779e15dc3..e0c8ec51765 100644 --- a/src/openvpn/clinat.h +++ b/src/openvpn/clinat.h @@ -33,33 +33,36 @@ #define CN_INCOMING 1 struct client_nat_entry { -# define CN_SNAT 0 -# define CN_DNAT 1 - int type; - in_addr_t network; - in_addr_t netmask; - in_addr_t foreign_network; +#define CN_SNAT 0 +#define CN_DNAT 1 + int type; + in_addr_t network; + in_addr_t netmask; + in_addr_t foreign_network; }; struct client_nat_option_list { - int n; - struct client_nat_entry entries[MAX_CLIENT_NAT]; + int n; + struct client_nat_entry entries[MAX_CLIENT_NAT]; }; -struct client_nat_option_list *new_client_nat_list (struct gc_arena *gc); -struct client_nat_option_list *clone_client_nat_option_list (const struct client_nat_option_list *src, struct gc_arena *gc); -void copy_client_nat_option_list (struct client_nat_option_list *dest, const struct client_nat_option_list *src); +struct client_nat_option_list *new_client_nat_list(struct gc_arena *gc); + +struct client_nat_option_list *clone_client_nat_option_list(const struct client_nat_option_list *src, struct gc_arena *gc); + +void copy_client_nat_option_list(struct client_nat_option_list *dest, const struct client_nat_option_list *src); + void print_client_nat_list(const struct client_nat_option_list *list, int msglevel); -void add_client_nat_to_option_list (struct client_nat_option_list *dest, - const char *type, - const char *network, - const char *netmask, - const char *foreign_network, - int msglevel); +void add_client_nat_to_option_list(struct client_nat_option_list *dest, + const char *type, + const char *network, + const char *netmask, + const char *foreign_network, + int msglevel); -void client_nat_transform (const struct client_nat_option_list *list, - struct buffer *ipbuf, - const int direction); +void client_nat_transform(const struct client_nat_option_list *list, + struct buffer *ipbuf, + const int direction); -#endif +#endif /* if !defined(CLINAT_H) */ diff --git a/src/openvpn/common.h b/src/openvpn/common.h index 1134101dc38..6352b01f274 100644 --- a/src/openvpn/common.h +++ b/src/openvpn/common.h @@ -29,15 +29,15 @@ * Statistics counters and associated printf formats. */ #ifdef USE_64_BIT_COUNTERS - typedef unsigned long long int counter_type; -# ifdef _WIN32 -# define counter_format "%I64u" -# else -# define counter_format "%llu" -# endif +typedef unsigned long long int counter_type; +#ifdef _WIN32 +#define counter_format "%I64u" #else - typedef unsigned int counter_type; -# define counter_format "%u" +#define counter_format "%llu" +#endif +#else /* ifdef USE_64_BIT_COUNTERS */ +typedef unsigned int counter_type; +#define counter_format "%u" #endif /* @@ -102,4 +102,4 @@ typedef unsigned long ptr_type; */ #define SCRIPT_SECURITY_WARNING "WARNING: External program may not be called unless '--script-security 2' or higher is enabled. See --help text or man page for detailed info." -#endif +#endif /* ifndef COMMON_H */ diff --git a/src/openvpn/comp-lz4.c b/src/openvpn/comp-lz4.c index 395f3d2f180..6b7c49b60f2 100644 --- a/src/openvpn/comp-lz4.c +++ b/src/openvpn/comp-lz4.c @@ -45,263 +45,277 @@ #include "memdbg.h" static void -lz4_compress_init (struct compress_context *compctx) +lz4_compress_init(struct compress_context *compctx) { - msg (D_INIT_MEDIUM, "LZ4 compression initializing"); - ASSERT(compctx->flags & COMP_F_SWAP); + msg(D_INIT_MEDIUM, "LZ4 compression initializing"); + ASSERT(compctx->flags & COMP_F_SWAP); } static void -lz4v2_compress_init (struct compress_context *compctx) +lz4v2_compress_init(struct compress_context *compctx) { - msg (D_INIT_MEDIUM, "LZ4v2 compression initializing"); + msg(D_INIT_MEDIUM, "LZ4v2 compression initializing"); } static void -lz4_compress_uninit (struct compress_context *compctx) +lz4_compress_uninit(struct compress_context *compctx) { } static bool -do_lz4_compress (struct buffer *buf, - struct buffer *work, - struct compress_context *compctx, - const struct frame* frame) +do_lz4_compress(struct buffer *buf, + struct buffer *work, + struct compress_context *compctx, + const struct frame *frame) { - /* - * In order to attempt compression, length must be at least COMPRESS_THRESHOLD. - */ - if (buf->len >= COMPRESS_THRESHOLD) + /* + * In order to attempt compression, length must be at least COMPRESS_THRESHOLD. + */ + if (buf->len >= COMPRESS_THRESHOLD) { - const size_t ps = PAYLOAD_SIZE (frame); - int zlen_max = ps + COMP_EXTRA_BUFFER (ps); - int zlen; + const size_t ps = PAYLOAD_SIZE(frame); + int zlen_max = ps + COMP_EXTRA_BUFFER(ps); + int zlen; - ASSERT (buf_init (work, FRAME_HEADROOM (frame))); - ASSERT (buf_safe (work, zlen_max)); + ASSERT(buf_init(work, FRAME_HEADROOM(frame))); + ASSERT(buf_safe(work, zlen_max)); - if (buf->len > ps) - { - dmsg (D_COMP_ERRORS, "LZ4 compression buffer overflow"); - buf->len = 0; - return false; - } + if (buf->len > ps) + { + dmsg(D_COMP_ERRORS, "LZ4 compression buffer overflow"); + buf->len = 0; + return false; + } - zlen = LZ4_compress_limitedOutput((const char *)BPTR(buf), (char *)BPTR(work), BLEN(buf), zlen_max ); + zlen = LZ4_compress_limitedOutput((const char *)BPTR(buf), (char *)BPTR(work), BLEN(buf), zlen_max ); - if (zlen <= 0) - { - dmsg (D_COMP_ERRORS, "LZ4 compression error"); - buf->len = 0; - return false; - } + if (zlen <= 0) + { + dmsg(D_COMP_ERRORS, "LZ4 compression error"); + buf->len = 0; + return false; + } - ASSERT (buf_safe (work, zlen)); - work->len = zlen; + ASSERT(buf_safe(work, zlen)); + work->len = zlen; - dmsg (D_COMP, "LZ4 compress %d -> %d", buf->len, work->len); - compctx->pre_compress += buf->len; - compctx->post_compress += work->len; - return true; + dmsg(D_COMP, "LZ4 compress %d -> %d", buf->len, work->len); + compctx->pre_compress += buf->len; + compctx->post_compress += work->len; + return true; } - return false; + return false; } static void -lz4_compress (struct buffer *buf, struct buffer work, - struct compress_context *compctx, - const struct frame* frame) +lz4_compress(struct buffer *buf, struct buffer work, + struct compress_context *compctx, + const struct frame *frame) { - bool compressed; - if (buf->len <= 0) - return; - - compressed = do_lz4_compress(buf, &work, compctx, frame); + bool compressed; + if (buf->len <= 0) + { + return; + } - /* On error do_lz4_compress sets buf len to zero, just return */ - if (buf->len == 0) - return; + compressed = do_lz4_compress(buf, &work, compctx, frame); - /* did compression save us anything? */ - { - uint8_t comp_head_byte = NO_COMPRESS_BYTE_SWAP; - if (compressed && work.len < buf->len) - { - *buf = work; - comp_head_byte = LZ4_COMPRESS_BYTE; - } + /* On error do_lz4_compress sets buf len to zero, just return */ + if (buf->len == 0) + { + return; + } + /* did compression save us anything? */ { - uint8_t *head = BPTR (buf); - uint8_t *tail = BEND (buf); - ASSERT (buf_safe (buf, 1)); - ++buf->len; - - /* move head byte of payload to tail */ - *tail = *head; - *head = comp_head_byte; + uint8_t comp_head_byte = NO_COMPRESS_BYTE_SWAP; + if (compressed && work.len < buf->len) + { + *buf = work; + comp_head_byte = LZ4_COMPRESS_BYTE; + } + + { + uint8_t *head = BPTR(buf); + uint8_t *tail = BEND(buf); + ASSERT(buf_safe(buf, 1)); + ++buf->len; + + /* move head byte of payload to tail */ + *tail = *head; + *head = comp_head_byte; + } } - } } static void -lz4v2_compress (struct buffer *buf, struct buffer work, - struct compress_context *compctx, - const struct frame* frame) +lz4v2_compress(struct buffer *buf, struct buffer work, + struct compress_context *compctx, + const struct frame *frame) { - bool compressed; - if (buf->len <= 0) - return; + bool compressed; + if (buf->len <= 0) + { + return; + } - compressed = do_lz4_compress(buf, &work, compctx, frame); + compressed = do_lz4_compress(buf, &work, compctx, frame); - /* On Error just return */ - if (buf->len == 0) - return; + /* On Error just return */ + if (buf->len == 0) + { + return; + } - /* did compression save us anything? Include 2 byte compression header - in calculation */ - if (compressed && work.len + 2 < buf->len) + /* did compression save us anything? Include 2 byte compression header + * in calculation */ + if (compressed && work.len + 2 < buf->len) { - ASSERT(buf_prepend(&work, 2)); - uint8_t *head = BPTR (&work); - head[0] = COMP_ALGV2_INDICATOR_BYTE; - head[1] = COMP_ALGV2_LZ4_BYTE; - *buf = work; + ASSERT(buf_prepend(&work, 2)); + uint8_t *head = BPTR(&work); + head[0] = COMP_ALGV2_INDICATOR_BYTE; + head[1] = COMP_ALGV2_LZ4_BYTE; + *buf = work; } - else + else { - compv2_escape_data_ifneeded(buf); + compv2_escape_data_ifneeded(buf); } } void do_lz4_decompress(size_t zlen_max, - struct buffer *work, - struct buffer *buf, - struct compress_context *compctx) + struct buffer *work, + struct buffer *buf, + struct compress_context *compctx) { - int uncomp_len; - ASSERT (buf_safe (work, zlen_max)); - uncomp_len = LZ4_decompress_safe((const char *)BPTR(buf), (char *)BPTR(work), (size_t)BLEN(buf), zlen_max); - if (uncomp_len <= 0) + int uncomp_len; + ASSERT(buf_safe(work, zlen_max)); + uncomp_len = LZ4_decompress_safe((const char *)BPTR(buf), (char *)BPTR(work), (size_t)BLEN(buf), zlen_max); + if (uncomp_len <= 0) { - dmsg (D_COMP_ERRORS, "LZ4 decompression error: %d", uncomp_len); - buf->len = 0; - return; + dmsg(D_COMP_ERRORS, "LZ4 decompression error: %d", uncomp_len); + buf->len = 0; + return; } - ASSERT (buf_safe (work, uncomp_len)); - work->len = uncomp_len; + ASSERT(buf_safe(work, uncomp_len)); + work->len = uncomp_len; - dmsg (D_COMP, "LZ4 decompress %d -> %d", buf->len, work->len); - compctx->pre_decompress += buf->len; - compctx->post_decompress += work->len; + dmsg(D_COMP, "LZ4 decompress %d -> %d", buf->len, work->len); + compctx->pre_decompress += buf->len; + compctx->post_decompress += work->len; - *buf = *work; + *buf = *work; } static void -lz4_decompress (struct buffer *buf, struct buffer work, - struct compress_context *compctx, - const struct frame* frame) +lz4_decompress(struct buffer *buf, struct buffer work, + struct compress_context *compctx, + const struct frame *frame) { - size_t zlen_max = EXPANDED_SIZE (frame); - uint8_t c; /* flag indicating whether or not our peer compressed */ + size_t zlen_max = EXPANDED_SIZE(frame); + uint8_t c; /* flag indicating whether or not our peer compressed */ - if (buf->len <= 0) - return; + if (buf->len <= 0) + { + return; + } - ASSERT (buf_init (&work, FRAME_HEADROOM (frame))); + ASSERT(buf_init(&work, FRAME_HEADROOM(frame))); - /* do unframing/swap (assumes buf->len > 0) */ - { - uint8_t *head = BPTR (buf); - c = *head; - --buf->len; - *head = *BEND (buf); - } + /* do unframing/swap (assumes buf->len > 0) */ + { + uint8_t *head = BPTR(buf); + c = *head; + --buf->len; + *head = *BEND(buf); + } - if (c == LZ4_COMPRESS_BYTE) /* packet was compressed */ + if (c == LZ4_COMPRESS_BYTE) /* packet was compressed */ { - do_lz4_decompress(zlen_max, &work, buf, compctx); + do_lz4_decompress(zlen_max, &work, buf, compctx); } - else if (c == NO_COMPRESS_BYTE_SWAP) /* packet was not compressed */ + else if (c == NO_COMPRESS_BYTE_SWAP) /* packet was not compressed */ { - ; } - else + else { - dmsg (D_COMP_ERRORS, "Bad LZ4 decompression header byte: %d", c); - buf->len = 0; + dmsg(D_COMP_ERRORS, "Bad LZ4 decompression header byte: %d", c); + buf->len = 0; } } static void -lz4v2_decompress (struct buffer *buf, struct buffer work, - struct compress_context *compctx, - const struct frame* frame) +lz4v2_decompress(struct buffer *buf, struct buffer work, + struct compress_context *compctx, + const struct frame *frame) { - size_t zlen_max = EXPANDED_SIZE (frame); - uint8_t c; /* flag indicating whether or not our peer compressed */ + size_t zlen_max = EXPANDED_SIZE(frame); + uint8_t c; /* flag indicating whether or not our peer compressed */ - if (buf->len <= 0) - return; + if (buf->len <= 0) + { + return; + } - ASSERT (buf_init (&work, FRAME_HEADROOM (frame))); + ASSERT(buf_init(&work, FRAME_HEADROOM(frame))); - /* do unframing/swap (assumes buf->len > 0) */ - uint8_t *head = BPTR (buf); - c = *head; + /* do unframing/swap (assumes buf->len > 0) */ + uint8_t *head = BPTR(buf); + c = *head; - /* Not compressed */ - if (c != COMP_ALGV2_INDICATOR_BYTE) { - return; - } + /* Not compressed */ + if (c != COMP_ALGV2_INDICATOR_BYTE) + { + return; + } - /* Packet to short to make sense */ - if (buf->len <= 1) + /* Packet to short to make sense */ + if (buf->len <= 1) { - buf->len=0; - return; + buf->len = 0; + return; } - c = head[1]; - if (c == COMP_ALGV2_LZ4_BYTE) /* packet was compressed */ + c = head[1]; + if (c == COMP_ALGV2_LZ4_BYTE) /* packet was compressed */ { - buf_advance(buf,2); - do_lz4_decompress(zlen_max, &work, buf, compctx); + buf_advance(buf,2); + do_lz4_decompress(zlen_max, &work, buf, compctx); } - else if (c == COMP_ALGV2_UNCOMPRESSED_BYTE) + else if (c == COMP_ALGV2_UNCOMPRESSED_BYTE) { - buf_advance(buf,2); + buf_advance(buf,2); } - else + else { - dmsg (D_COMP_ERRORS, "Bad LZ4v2 decompression header byte: %d", c); - buf->len = 0; + dmsg(D_COMP_ERRORS, "Bad LZ4v2 decompression header byte: %d", c); + buf->len = 0; } } const struct compress_alg lz4_alg = { - "lz4", - lz4_compress_init, - lz4_compress_uninit, - lz4_compress, - lz4_decompress + "lz4", + lz4_compress_init, + lz4_compress_uninit, + lz4_compress, + lz4_decompress }; const struct compress_alg lz4v2_alg = { - "lz4v2", - lz4v2_compress_init, - lz4_compress_uninit, - lz4v2_compress, - lz4v2_decompress + "lz4v2", + lz4v2_compress_init, + lz4_compress_uninit, + lz4v2_compress, + lz4v2_decompress }; -#else -static void dummy(void) {} +#else /* if defined(ENABLE_LZ4) */ +static void +dummy(void) { +} #endif /* ENABLE_LZ4 */ diff --git a/src/openvpn/comp-lz4.h b/src/openvpn/comp-lz4.h index 7774ca5aacd..65f4f8ec367 100644 --- a/src/openvpn/comp-lz4.h +++ b/src/openvpn/comp-lz4.h @@ -35,7 +35,7 @@ extern const struct compress_alg lz4v2_alg; struct lz4_workspace { - int dummy; + int dummy; }; #endif /* ENABLE_LZ4 */ diff --git a/src/openvpn/comp.c b/src/openvpn/comp.c index 499fef98d86..5f563aed838 100644 --- a/src/openvpn/comp.c +++ b/src/openvpn/comp.c @@ -41,59 +41,67 @@ struct compress_context * comp_init(const struct compress_options *opt) { - struct compress_context *compctx = NULL; - switch (opt->alg) + struct compress_context *compctx = NULL; + switch (opt->alg) { - case COMP_ALG_STUB: - ALLOC_OBJ_CLEAR (compctx, struct compress_context); - compctx->flags = opt->flags; - compctx->alg = comp_stub_alg; - break; - case COMP_ALGV2_UNCOMPRESSED: - ALLOC_OBJ_CLEAR (compctx, struct compress_context); - compctx->flags = opt->flags; - compctx->alg = compv2_stub_alg; - break; + case COMP_ALG_STUB: + ALLOC_OBJ_CLEAR(compctx, struct compress_context); + compctx->flags = opt->flags; + compctx->alg = comp_stub_alg; + break; + + case COMP_ALGV2_UNCOMPRESSED: + ALLOC_OBJ_CLEAR(compctx, struct compress_context); + compctx->flags = opt->flags; + compctx->alg = compv2_stub_alg; + break; + #ifdef ENABLE_LZO - case COMP_ALG_LZO: - ALLOC_OBJ_CLEAR (compctx, struct compress_context); - compctx->flags = opt->flags; - compctx->alg = lzo_alg; - break; + case COMP_ALG_LZO: + ALLOC_OBJ_CLEAR(compctx, struct compress_context); + compctx->flags = opt->flags; + compctx->alg = lzo_alg; + break; + #endif #ifdef ENABLE_LZ4 - case COMP_ALG_LZ4: - ALLOC_OBJ_CLEAR (compctx, struct compress_context); - compctx->flags = opt->flags; - compctx->alg = lz4_alg; - break; - case COMP_ALGV2_LZ4: - ALLOC_OBJ_CLEAR (compctx, struct compress_context); - compctx->flags = opt->flags; - compctx->alg = lz4v2_alg; - break; + case COMP_ALG_LZ4: + ALLOC_OBJ_CLEAR(compctx, struct compress_context); + compctx->flags = opt->flags; + compctx->alg = lz4_alg; + break; + + case COMP_ALGV2_LZ4: + ALLOC_OBJ_CLEAR(compctx, struct compress_context); + compctx->flags = opt->flags; + compctx->alg = lz4v2_alg; + break; #endif } - if (compctx) - (*compctx->alg.compress_init)(compctx); + if (compctx) + { + (*compctx->alg.compress_init)(compctx); + } - return compctx; + return compctx; } /* In the v2 compression schemes, an uncompressed packet has * has no opcode in front, unless the first byte is 0x50. In this * case the packet needs to be escaped */ void -compv2_escape_data_ifneeded (struct buffer *buf) +compv2_escape_data_ifneeded(struct buffer *buf) { - uint8_t *head = BPTR (buf); + uint8_t *head = BPTR(buf); if (head[0] != COMP_ALGV2_INDICATOR_BYTE) - return; + { + return; + } /* Header is 0x50 */ ASSERT(buf_prepend(buf, 2)); - head = BPTR (buf); + head = BPTR(buf); head[0] = COMP_ALGV2_INDICATOR_BYTE; head[1] = COMP_ALGV2_UNCOMPRESSED; } @@ -102,37 +110,37 @@ compv2_escape_data_ifneeded (struct buffer *buf) void comp_uninit(struct compress_context *compctx) { - if (compctx) + if (compctx) { - (*compctx->alg.compress_uninit)(compctx); - free(compctx); + (*compctx->alg.compress_uninit)(compctx); + free(compctx); } } void comp_add_to_extra_frame(struct frame *frame) { - /* Leave room for our one-byte compressed/didn't-compress prefix byte. */ - frame_add_to_extra_frame (frame, COMP_PREFIX_LEN); + /* Leave room for our one-byte compressed/didn't-compress prefix byte. */ + frame_add_to_extra_frame(frame, COMP_PREFIX_LEN); } void comp_add_to_extra_buffer(struct frame *frame) { - /* Leave room for compression buffer to expand in worst case scenario - where data is totally uncompressible */ - frame_add_to_extra_buffer (frame, COMP_EXTRA_BUFFER (EXPANDED_SIZE(frame))); + /* Leave room for compression buffer to expand in worst case scenario + * where data is totally uncompressible */ + frame_add_to_extra_buffer(frame, COMP_EXTRA_BUFFER(EXPANDED_SIZE(frame))); } void -comp_print_stats (const struct compress_context *compctx, struct status_output *so) +comp_print_stats(const struct compress_context *compctx, struct status_output *so) { - if (compctx) + if (compctx) { - status_printf (so, "pre-compress bytes," counter_format, compctx->pre_compress); - status_printf (so, "post-compress bytes," counter_format, compctx->post_compress); - status_printf (so, "pre-decompress bytes," counter_format, compctx->pre_decompress); - status_printf (so, "post-decompress bytes," counter_format, compctx->post_decompress); + status_printf(so, "pre-compress bytes," counter_format, compctx->pre_compress); + status_printf(so, "post-compress bytes," counter_format, compctx->post_compress); + status_printf(so, "pre-decompress bytes," counter_format, compctx->pre_decompress); + status_printf(so, "post-decompress bytes," counter_format, compctx->post_decompress); } } @@ -142,25 +150,27 @@ comp_print_stats (const struct compress_context *compctx, struct status_output * void comp_generate_peer_info_string(const struct compress_options *opt, struct buffer *out) { - if (opt) + if (opt) { - bool lzo_avail = false; - if (!(opt->flags & COMP_F_ADVERTISE_STUBS_ONLY)) - { + bool lzo_avail = false; + if (!(opt->flags & COMP_F_ADVERTISE_STUBS_ONLY)) + { #if defined(ENABLE_LZ4) - buf_printf (out, "IV_LZ4=1\n"); - buf_printf (out, "IV_LZ4v2=1\n"); + buf_printf(out, "IV_LZ4=1\n"); + buf_printf(out, "IV_LZ4v2=1\n"); #endif #if defined(ENABLE_LZO) - buf_printf (out, "IV_LZO=1\n"); - lzo_avail = true; + buf_printf(out, "IV_LZO=1\n"); + lzo_avail = true; #endif - } - if (!lzo_avail) - buf_printf (out, "IV_LZO_STUB=1\n"); - buf_printf (out, "IV_COMP_STUB=1\n"); - buf_printf (out, "IV_COMP_STUBv2=1\n"); - buf_printf (out, "IV_TCPNL=1\n"); + } + if (!lzo_avail) + { + buf_printf(out, "IV_LZO_STUB=1\n"); + } + buf_printf(out, "IV_COMP_STUB=1\n"); + buf_printf(out, "IV_COMP_STUBv2=1\n"); + buf_printf(out, "IV_TCPNL=1\n"); } } diff --git a/src/openvpn/comp.h b/src/openvpn/comp.h index 9ed9532939c..7410c92bab4 100644 --- a/src/openvpn/comp.h +++ b/src/openvpn/comp.h @@ -46,11 +46,11 @@ /* algorithm v2 */ #define COMP_ALGV2_UNCOMPRESSED 10 -#define COMP_ALGV2_LZ4 11 +#define COMP_ALGV2_LZ4 11 /* -#define COMP_ALGV2_LZO 12 -#define COMP_ALGV2_SNAPPY 13 -*/ + #define COMP_ALGV2_LZO 12 + #define COMP_ALGV2_SNAPPY 13 + */ /* Compression flags */ #define COMP_F_ADAPTIVE (1<<0) /* COMP_ALG_LZO only */ @@ -76,11 +76,11 @@ #define NO_COMPRESS_BYTE_SWAP 0xFB /* to maintain payload alignment, replace this byte with last byte of packet */ /* V2 on wire code */ -#define COMP_ALGV2_INDICATOR_BYTE 0x50 -#define COMP_ALGV2_UNCOMPRESSED_BYTE 0 -#define COMP_ALGV2_LZ4_BYTE 1 -#define COMP_ALGV2_LZO_BYTE 2 -#define COMP_ALGV2_SNAPPY_BYTE 3 +#define COMP_ALGV2_INDICATOR_BYTE 0x50 +#define COMP_ALGV2_UNCOMPRESSED_BYTE 0 +#define COMP_ALGV2_LZ4_BYTE 1 +#define COMP_ALGV2_LZO_BYTE 2 +#define COMP_ALGV2_SNAPPY_BYTE 3 /* * Compress worst case size expansion (for any algorithm) @@ -104,16 +104,16 @@ struct compress_context; */ struct compress_alg { - const char *name; - void (*compress_init)(struct compress_context *compctx); - void (*compress_uninit)(struct compress_context *compctx); - void (*compress)(struct buffer *buf, struct buffer work, - struct compress_context *compctx, - const struct frame* frame); - - void (*decompress)(struct buffer *buf, struct buffer work, - struct compress_context *compctx, - const struct frame* frame); + const char *name; + void (*compress_init)(struct compress_context *compctx); + void (*compress_uninit)(struct compress_context *compctx); + void (*compress)(struct buffer *buf, struct buffer work, + struct compress_context *compctx, + const struct frame *frame); + + void (*decompress)(struct buffer *buf, struct buffer work, + struct compress_context *compctx, + const struct frame *frame); }; /* @@ -133,8 +133,8 @@ struct compress_alg */ struct compress_options { - int alg; - unsigned int flags; + int alg; + unsigned int flags; }; /* @@ -143,10 +143,10 @@ struct compress_options union compress_workspace_union { #ifdef ENABLE_LZO - struct lzo_compress_workspace lzo; + struct lzo_compress_workspace lzo; #endif #ifdef ENABLE_LZ4 - struct lz4_workspace lz4; + struct lz4_workspace lz4; #endif }; @@ -155,15 +155,15 @@ union compress_workspace_union */ struct compress_context { - unsigned int flags; - struct compress_alg alg; - union compress_workspace_union wu; - - /* statistics */ - counter_type pre_decompress; - counter_type post_decompress; - counter_type pre_compress; - counter_type post_compress; + unsigned int flags; + struct compress_alg alg; + union compress_workspace_union wu; + + /* statistics */ + counter_type pre_decompress; + counter_type post_decompress; + counter_type pre_compress; + counter_type post_compress; }; extern const struct compress_alg comp_stub_alg; @@ -174,25 +174,26 @@ struct compress_context *comp_init(const struct compress_options *opt); void comp_uninit(struct compress_context *compctx); void comp_add_to_extra_frame(struct frame *frame); + void comp_add_to_extra_buffer(struct frame *frame); -void comp_print_stats (const struct compress_context *compctx, struct status_output *so); +void comp_print_stats(const struct compress_context *compctx, struct status_output *so); void comp_generate_peer_info_string(const struct compress_options *opt, struct buffer *out); -void compv2_escape_data_ifneeded (struct buffer *buf); +void compv2_escape_data_ifneeded(struct buffer *buf); static inline bool comp_enabled(const struct compress_options *info) { - return info->alg != COMP_ALG_UNDEF; + return info->alg != COMP_ALG_UNDEF; } static inline bool comp_unswapped_prefix(const struct compress_options *info) { - return !(info->flags & COMP_F_SWAP); + return !(info->flags & COMP_F_SWAP); } #endif /* USE_COMP */ -#endif +#endif /* ifndef OPENVPN_COMP_H */ diff --git a/src/openvpn/compstub.c b/src/openvpn/compstub.c index 9c6aad2de70..7082b99fd19 100644 --- a/src/openvpn/compstub.c +++ b/src/openvpn/compstub.c @@ -39,131 +39,146 @@ #include "memdbg.h" static void -stub_compress_init (struct compress_context *compctx) +stub_compress_init(struct compress_context *compctx) { } static void -stub_compress_uninit (struct compress_context *compctx) +stub_compress_uninit(struct compress_context *compctx) { } static void -stub_compress (struct buffer *buf, struct buffer work, - struct compress_context *compctx, - const struct frame* frame) +stub_compress(struct buffer *buf, struct buffer work, + struct compress_context *compctx, + const struct frame *frame) { - if (buf->len <= 0) - return; - if (compctx->flags & COMP_F_SWAP) + if (buf->len <= 0) + { + return; + } + if (compctx->flags & COMP_F_SWAP) { - uint8_t *head = BPTR (buf); - uint8_t *tail = BEND (buf); - ASSERT (buf_safe (buf, 1)); - ++buf->len; - - /* move head byte of payload to tail */ - *tail = *head; - *head = NO_COMPRESS_BYTE_SWAP; + uint8_t *head = BPTR(buf); + uint8_t *tail = BEND(buf); + ASSERT(buf_safe(buf, 1)); + ++buf->len; + + /* move head byte of payload to tail */ + *tail = *head; + *head = NO_COMPRESS_BYTE_SWAP; } - else + else { - uint8_t *header = buf_prepend (buf, 1); - *header = NO_COMPRESS_BYTE; + uint8_t *header = buf_prepend(buf, 1); + *header = NO_COMPRESS_BYTE; } } static void -stub_decompress (struct buffer *buf, struct buffer work, - struct compress_context *compctx, - const struct frame* frame) +stub_decompress(struct buffer *buf, struct buffer work, + struct compress_context *compctx, + const struct frame *frame) { - uint8_t c; - if (buf->len <= 0) - return; - if (compctx->flags & COMP_F_SWAP) + uint8_t c; + if (buf->len <= 0) + { + return; + } + if (compctx->flags & COMP_F_SWAP) { - uint8_t *head = BPTR (buf); - c = *head; - --buf->len; - *head = *BEND (buf); - if (c != NO_COMPRESS_BYTE_SWAP) - { - dmsg (D_COMP_ERRORS, "Bad compression stub (swap) decompression header byte: %d", c); - buf->len = 0; - } + uint8_t *head = BPTR(buf); + c = *head; + --buf->len; + *head = *BEND(buf); + if (c != NO_COMPRESS_BYTE_SWAP) + { + dmsg(D_COMP_ERRORS, "Bad compression stub (swap) decompression header byte: %d", c); + buf->len = 0; + } } - else + else { - c = *BPTR (buf); - ASSERT (buf_advance (buf, 1)); - if (c != NO_COMPRESS_BYTE) - { - dmsg (D_COMP_ERRORS, "Bad compression stub decompression header byte: %d", c); - buf->len = 0; - } + c = *BPTR(buf); + ASSERT(buf_advance(buf, 1)); + if (c != NO_COMPRESS_BYTE) + { + dmsg(D_COMP_ERRORS, "Bad compression stub decompression header byte: %d", c); + buf->len = 0; + } } } static void -stubv2_compress (struct buffer *buf, struct buffer work, - struct compress_context *compctx, - const struct frame* frame) +stubv2_compress(struct buffer *buf, struct buffer work, + struct compress_context *compctx, + const struct frame *frame) { if (buf->len <= 0) - return; + { + return; + } - compv2_escape_data_ifneeded (buf); + compv2_escape_data_ifneeded(buf); } static void -stubv2_decompress (struct buffer *buf, struct buffer work, - struct compress_context *compctx, - const struct frame* frame) +stubv2_decompress(struct buffer *buf, struct buffer work, + struct compress_context *compctx, + const struct frame *frame) { - if (buf->len <= 0) - return; + if (buf->len <= 0) + { + return; + } - uint8_t *head = BPTR (buf); + uint8_t *head = BPTR(buf); - /* no compression or packet to short*/ - if (head[0] != COMP_ALGV2_INDICATOR_BYTE) - return; + /* no compression or packet to short*/ + if (head[0] != COMP_ALGV2_INDICATOR_BYTE) + { + return; + } - /* compression header (0x50) is present */ - buf_advance(buf, 1); + /* compression header (0x50) is present */ + buf_advance(buf, 1); - /* Packet buffer too short (only 1 byte) */ - if (buf->len <= 0) - return; + /* Packet buffer too short (only 1 byte) */ + if (buf->len <= 0) + { + return; + } - head = BPTR (buf); - buf_advance(buf, 1); + head = BPTR(buf); + buf_advance(buf, 1); - if (head[0] != COMP_ALGV2_UNCOMPRESSED_BYTE) { - dmsg (D_COMP_ERRORS, "Bad compression stubv2 decompression header byte: %d", *head); - buf->len = 0; - return; - } + if (head[0] != COMP_ALGV2_UNCOMPRESSED_BYTE) + { + dmsg(D_COMP_ERRORS, "Bad compression stubv2 decompression header byte: %d", *head); + buf->len = 0; + return; + } } const struct compress_alg compv2_stub_alg = { - "stubv2", - stub_compress_init, - stub_compress_uninit, - stubv2_compress, - stubv2_decompress + "stubv2", + stub_compress_init, + stub_compress_uninit, + stubv2_compress, + stubv2_decompress }; const struct compress_alg comp_stub_alg = { - "stub", - stub_compress_init, - stub_compress_uninit, - stub_compress, - stub_decompress + "stub", + stub_compress_init, + stub_compress_uninit, + stub_compress, + stub_decompress }; -#else -static void dummy(void) {} +#else /* if defined(USE_COMP) */ +static void +dummy(void) { +} #endif /* USE_STUB */ diff --git a/src/openvpn/console.c b/src/openvpn/console.c index c3bb7c3de41..ec64d42fb21 100644 --- a/src/openvpn/console.c +++ b/src/openvpn/console.c @@ -44,19 +44,21 @@ struct _query_user query_user[QUERY_USER_NUMSLOTS]; /* GLOBAL */ -void query_user_clear() +void +query_user_clear() { int i; - for( i = 0; i < QUERY_USER_NUMSLOTS; i++ ) { - CLEAR(query_user[i]); + for (i = 0; i < QUERY_USER_NUMSLOTS; i++) { + CLEAR(query_user[i]); } } -void query_user_add(char *prompt, size_t prompt_len, - char *resp, size_t resp_len, - bool echo) +void +query_user_add(char *prompt, size_t prompt_len, + char *resp, size_t resp_len, + bool echo) { int i; @@ -67,9 +69,10 @@ void query_user_add(char *prompt, size_t prompt_len, /* Seek to the last unused slot */ for (i = 0; i < QUERY_USER_NUMSLOTS; i++) { - if( query_user[i].prompt == NULL ) { - break; - } + if (query_user[i].prompt == NULL) + { + break; + } } ASSERT( i < QUERY_USER_NUMSLOTS ); /* Unlikely, but we want to panic if it happens */ diff --git a/src/openvpn/console.h b/src/openvpn/console.h index ec32cf6491f..495414a11cc 100644 --- a/src/openvpn/console.h +++ b/src/openvpn/console.h @@ -47,7 +47,7 @@ extern struct _query_user query_user[]; /**< Global variable, declared in conso * Wipes all data put into all of the query_user structs * */ -void query_user_clear (); +void query_user_clear(); /** @@ -60,9 +60,9 @@ void query_user_clear (); * @param echo Should the user input be echoed to the user? If False, input will be masked * */ -void query_user_add (char *prompt, size_t prompt_len, - char *resp, size_t resp_len, - bool echo); +void query_user_add(char *prompt, size_t prompt_len, + char *resp, size_t resp_len, + bool echo); /** @@ -73,7 +73,7 @@ void query_user_add (char *prompt, size_t prompt_len, * * @return True if executing all the defined steps completed successfully */ -bool query_user_exec_builtin (); +bool query_user_exec_builtin(); #if defined(ENABLE_SYSTEMD) @@ -84,7 +84,7 @@ bool query_user_exec_builtin (); * * @return True if executing all the defined steps completed successfully */ -bool query_user_exec (); +bool query_user_exec(); #else /* ENABLE_SYSTEMD not defined*/ /** @@ -92,7 +92,8 @@ bool query_user_exec (); * been enabled * */ -static bool query_user_exec () +static bool +query_user_exec() { return query_user_exec_builtin(); } @@ -106,13 +107,14 @@ static bool query_user_exec () * to be called at start-up initialization of OpenVPN. * */ -static inline bool query_user_SINGLE (char *prompt, size_t prompt_len, - char *resp, size_t resp_len, - bool echo) +static inline bool +query_user_SINGLE(char *prompt, size_t prompt_len, + char *resp, size_t resp_len, + bool echo) { query_user_clear(); query_user_add(prompt, prompt_len, resp, resp_len, echo); return query_user_exec(); } -#endif +#endif /* ifndef CONSOLE_H */ diff --git a/src/openvpn/console_builtin.c b/src/openvpn/console_builtin.c index 06994fd5af5..2d0c15fb907 100644 --- a/src/openvpn/console_builtin.c +++ b/src/openvpn/console_builtin.c @@ -56,64 +56,81 @@ * @return Return false on input error, or if service * exit event is signaled. */ -static bool get_console_input_win32 (const char *prompt, const bool echo, char *input, const int capacity) +static bool +get_console_input_win32(const char *prompt, const bool echo, char *input, const int capacity) { HANDLE in = INVALID_HANDLE_VALUE; HANDLE err = INVALID_HANDLE_VALUE; DWORD len = 0; - ASSERT (prompt); - ASSERT (input); - ASSERT (capacity > 0); + ASSERT(prompt); + ASSERT(input); + ASSERT(capacity > 0); input[0] = '\0'; - in = GetStdHandle (STD_INPUT_HANDLE); - err = get_orig_stderr (); + in = GetStdHandle(STD_INPUT_HANDLE); + err = get_orig_stderr(); if (in != INVALID_HANDLE_VALUE && err != INVALID_HANDLE_VALUE - && !win32_service_interrupt (&win32_signal) - && WriteFile (err, prompt, strlen (prompt), &len, NULL)) + && !win32_service_interrupt(&win32_signal) + && WriteFile(err, prompt, strlen(prompt), &len, NULL)) { - bool is_console = (GetFileType (in) == FILE_TYPE_CHAR); + bool is_console = (GetFileType(in) == FILE_TYPE_CHAR); DWORD flags_save = 0; int status = 0; WCHAR *winput; if (is_console) - { - if (GetConsoleMode (in, &flags_save)) - { + { + if (GetConsoleMode(in, &flags_save)) + { DWORD flags = ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT; if (echo) + { flags |= ENABLE_ECHO_INPUT; - SetConsoleMode (in, flags); - } else + } + SetConsoleMode(in, flags); + } + else + { is_console = 0; - } + } + } if (is_console) { - winput = malloc (capacity * sizeof (WCHAR)); + winput = malloc(capacity * sizeof(WCHAR)); if (winput == NULL) + { return false; + } - status = ReadConsoleW (in, winput, capacity, &len, NULL); - WideCharToMultiByte (CP_UTF8, 0, winput, len, input, capacity, NULL, NULL); - free (winput); - } else - status = ReadFile (in, input, capacity, &len, NULL); + status = ReadConsoleW(in, winput, capacity, &len, NULL); + WideCharToMultiByte(CP_UTF8, 0, winput, len, input, capacity, NULL, NULL); + free(winput); + } + else + { + status = ReadFile(in, input, capacity, &len, NULL); + } - string_null_terminate (input, (int)len, capacity); - chomp (input); + string_null_terminate(input, (int)len, capacity); + chomp(input); if (!echo) - WriteFile (err, "\r\n", 2, &len, NULL); + { + WriteFile(err, "\r\n", 2, &len, NULL); + } if (is_console) - SetConsoleMode (in, flags_save); - if (status && !win32_service_interrupt (&win32_signal)) + { + SetConsoleMode(in, flags_save); + } + if (status && !win32_service_interrupt(&win32_signal)) + { return true; + } } return false; @@ -134,12 +151,15 @@ static bool get_console_input_win32 (const char *prompt, const bool echo, char * * or stdin/stderr, depending on the write flag * */ -static FILE * open_tty (const bool write) +static FILE * +open_tty(const bool write) { FILE *ret; - ret = fopen ("/dev/tty", write ? "w" : "r"); + ret = fopen("/dev/tty", write ? "w" : "r"); if (!ret) + { ret = write ? stderr : stdin; + } return ret; } @@ -149,10 +169,13 @@ static FILE * open_tty (const bool write) * @params fp FILE pointer to close * */ -static void close_tty (FILE *fp) +static void +close_tty(FILE *fp) { if (fp != stderr && fp != stdin) - fclose (fp); + { + fclose(fp); + } } #endif /* HAVE_GETPASS */ @@ -168,26 +191,27 @@ static void close_tty (FILE *fp) * * @returns Returns True if user input was gathered */ -static bool get_console_input (const char *prompt, const bool echo, char *input, const int capacity) +static bool +get_console_input(const char *prompt, const bool echo, char *input, const int capacity) { bool ret = false; - ASSERT (prompt); - ASSERT (input); - ASSERT (capacity > 0); + ASSERT(prompt); + ASSERT(input); + ASSERT(capacity > 0); input[0] = '\0'; #if defined(_WIN32) - return get_console_input_win32 (prompt, echo, input, capacity); + return get_console_input_win32(prompt, echo, input, capacity); #elif defined(HAVE_GETPASS) /* did we --daemon'ize before asking for passwords? * (in which case neither stdin or stderr are connected to a tty and * /dev/tty can not be open()ed anymore) */ - if ( !isatty(0) && !isatty(2) ) + if (!isatty(0) && !isatty(2) ) { int fd = open( "/dev/tty", O_RDWR ); - if ( fd < 0 ) + if (fd < 0) { msg(M_FATAL, "neither stdin nor stderr are a tty device and you have neither a " "controlling tty nor systemd - can't ask for '%s'. If you used --daemon, " @@ -201,30 +225,32 @@ static bool get_console_input (const char *prompt, const bool echo, char *input, { FILE *fp; - fp = open_tty (true); - fprintf (fp, "%s", prompt); - fflush (fp); - close_tty (fp); + fp = open_tty(true); + fprintf(fp, "%s", prompt); + fflush(fp); + close_tty(fp); - fp = open_tty (false); - if (fgets (input, capacity, fp) != NULL) + fp = open_tty(false); + if (fgets(input, capacity, fp) != NULL) { - chomp (input); + chomp(input); ret = true; } - close_tty (fp); - } else { - char *gp = getpass (prompt); + close_tty(fp); + } + else + { + char *gp = getpass(prompt); if (gp) { - strncpynt (input, gp, capacity); - secure_memzero (gp, strlen (gp)); + strncpynt(input, gp, capacity); + secure_memzero(gp, strlen(gp)); ret = true; } } -#else - msg (M_FATAL, "Sorry, but I can't get console input on this OS (%s)", prompt); -#endif +#else /* if defined(_WIN32) */ + msg(M_FATAL, "Sorry, but I can't get console input on this OS (%s)", prompt); +#endif /* if defined(_WIN32) */ return ret; } @@ -241,7 +267,8 @@ static bool get_console_input (const char *prompt, const bool echo, char *input, * query_user_exec() will call this function instead. * */ -bool query_user_exec_builtin() +bool +query_user_exec_builtin() { bool ret = true; /* Presume everything goes okay */ int i; @@ -249,12 +276,12 @@ bool query_user_exec_builtin() /* Loop through configured query_user slots */ for (i = 0; i < QUERY_USER_NUMSLOTS && query_user[i].response != NULL; i++) { - if (!get_console_input(query_user[i].prompt, query_user[i].echo, - query_user[i].response, query_user[i].response_len) ) - { - /* Force the final result state to failed on failure */ - ret = false; - } + if (!get_console_input(query_user[i].prompt, query_user[i].echo, + query_user[i].response, query_user[i].response_len) ) + { + /* Force the final result state to failed on failure */ + ret = false; + } } return ret; diff --git a/src/openvpn/console_systemd.c b/src/openvpn/console_systemd.c index 8a953c97efb..1c0aa4c351f 100644 --- a/src/openvpn/console_systemd.c +++ b/src/openvpn/console_systemd.c @@ -42,7 +42,7 @@ */ static bool -check_systemd_running () +check_systemd_running() { struct stat c; @@ -51,40 +51,41 @@ check_systemd_running () * being available */ return (sd_booted() > 0) - && (stat(SYSTEMD_ASK_PASSWORD_PATH, &c) == 0); + && (stat(SYSTEMD_ASK_PASSWORD_PATH, &c) == 0); } static bool -get_console_input_systemd (const char *prompt, const bool echo, char *input, const int capacity) +get_console_input_systemd(const char *prompt, const bool echo, char *input, const int capacity) { int std_out; bool ret = false; - struct argv argv = argv_new (); + struct argv argv = argv_new(); - argv_printf (&argv, SYSTEMD_ASK_PASSWORD_PATH); + argv_printf(&argv, SYSTEMD_ASK_PASSWORD_PATH); #ifdef SYSTEMD_NEWER_THAN_216 /* the --echo support arrived in upstream systemd 217 */ - if( echo ) + if (echo) { - argv_printf_cat(&argv, "--echo"); + argv_printf_cat(&argv, "--echo"); } #endif - argv_printf_cat (&argv, "--icon network-vpn"); - argv_printf_cat (&argv, "%s", prompt); + argv_printf_cat(&argv, "--icon network-vpn"); + argv_printf_cat(&argv, "%s", prompt); - if ((std_out = openvpn_popen (&argv, NULL)) < 0) { - return false; + if ((std_out = openvpn_popen(&argv, NULL)) < 0) + { + return false; } - memset (input, 0, capacity); - if (read (std_out, input, capacity-1) != 0) + memset(input, 0, capacity); + if (read(std_out, input, capacity-1) != 0) { - chomp (input); - ret = true; + chomp(input); + ret = true; } - close (std_out); + close(std_out); - argv_reset (&argv); + argv_reset(&argv); return ret; } @@ -94,7 +95,8 @@ get_console_input_systemd (const char *prompt, const bool echo, char *input, con * it will fall back to use query_user_exec_builtin() instead. * */ -bool query_user_exec() +bool +query_user_exec() { bool ret = true; /* Presume everything goes okay */ int i; @@ -108,12 +110,12 @@ bool query_user_exec() /* Loop through the complete query setup and when needed, collect the information */ for (i = 0; i < QUERY_USER_NUMSLOTS && query_user[i].response != NULL; i++) { - if (!get_console_input_systemd(query_user[i].prompt, query_user[i].echo, - query_user[i].response, query_user[i].response_len) ) - { - /* Force the final result state to failed on failure */ - ret = false; - } + if (!get_console_input_systemd(query_user[i].prompt, query_user[i].echo, + query_user[i].response, query_user[i].response_len) ) + { + /* Force the final result state to failed on failure */ + ret = false; + } } return ret; diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c index 708cc9240e0..b28eb9d757a 100644 --- a/src/openvpn/crypto.c +++ b/src/openvpn/crypto.c @@ -64,284 +64,294 @@ */ static void -openvpn_encrypt_aead (struct buffer *buf, struct buffer work, - struct crypto_options *opt) { +openvpn_encrypt_aead(struct buffer *buf, struct buffer work, + struct crypto_options *opt) { #ifdef HAVE_AEAD_CIPHER_MODES - struct gc_arena gc; - int outlen = 0; - const struct key_ctx *ctx = &opt->key_ctx_bi.encrypt; - uint8_t *mac_out = NULL; - const cipher_kt_t *cipher_kt = cipher_ctx_get_cipher_kt (ctx->cipher); - const int mac_len = cipher_kt_tag_size (cipher_kt); - - /* IV, packet-ID and implicit IV required for this mode. */ - ASSERT (ctx->cipher); - ASSERT (cipher_kt_mode_aead (cipher_kt)); - ASSERT (opt->flags & CO_USE_IV); - ASSERT (packet_id_initialized(&opt->packet_id)); - - gc_init (&gc); - - /* Prepare IV */ - { - struct buffer iv_buffer; - struct packet_id_net pin; - uint8_t iv[OPENVPN_MAX_IV_LENGTH] = {0}; - const int iv_len = cipher_ctx_iv_length (ctx->cipher); + struct gc_arena gc; + int outlen = 0; + const struct key_ctx *ctx = &opt->key_ctx_bi.encrypt; + uint8_t *mac_out = NULL; + const cipher_kt_t *cipher_kt = cipher_ctx_get_cipher_kt(ctx->cipher); + const int mac_len = cipher_kt_tag_size(cipher_kt); + + /* IV, packet-ID and implicit IV required for this mode. */ + ASSERT(ctx->cipher); + ASSERT(cipher_kt_mode_aead(cipher_kt)); + ASSERT(opt->flags & CO_USE_IV); + ASSERT(packet_id_initialized(&opt->packet_id)); + + gc_init(&gc); + + /* Prepare IV */ + { + struct buffer iv_buffer; + struct packet_id_net pin; + uint8_t iv[OPENVPN_MAX_IV_LENGTH] = {0}; + const int iv_len = cipher_ctx_iv_length(ctx->cipher); - ASSERT (iv_len >= OPENVPN_AEAD_MIN_IV_LEN && iv_len <= OPENVPN_MAX_IV_LENGTH); + ASSERT(iv_len >= OPENVPN_AEAD_MIN_IV_LEN && iv_len <= OPENVPN_MAX_IV_LENGTH); - buf_set_write (&iv_buffer, iv, iv_len); + buf_set_write(&iv_buffer, iv, iv_len); - /* IV starts with packet id to make the IV unique for packet */ - packet_id_alloc_outgoing (&opt->packet_id.send, &pin, false); - ASSERT (packet_id_write (&pin, &iv_buffer, false, false)); + /* IV starts with packet id to make the IV unique for packet */ + packet_id_alloc_outgoing(&opt->packet_id.send, &pin, false); + ASSERT(packet_id_write(&pin, &iv_buffer, false, false)); - /* Remainder of IV consists of implicit part (unique per session) */ - ASSERT (buf_write (&iv_buffer, ctx->implicit_iv, ctx->implicit_iv_len)); - ASSERT (iv_buffer.len == iv_len); + /* Remainder of IV consists of implicit part (unique per session) */ + ASSERT(buf_write(&iv_buffer, ctx->implicit_iv, ctx->implicit_iv_len)); + ASSERT(iv_buffer.len == iv_len); - /* Write explicit part of IV to work buffer */ - ASSERT (buf_write(&work, iv, iv_len - ctx->implicit_iv_len)); - dmsg (D_PACKET_CONTENT, "ENCRYPT IV: %s", format_hex (iv, iv_len, 0, &gc)); + /* Write explicit part of IV to work buffer */ + ASSERT(buf_write(&work, iv, iv_len - ctx->implicit_iv_len)); + dmsg(D_PACKET_CONTENT, "ENCRYPT IV: %s", format_hex(iv, iv_len, 0, &gc)); - /* Init cipher_ctx with IV. key & keylen are already initialized */ - ASSERT (cipher_ctx_reset(ctx->cipher, iv)); - } + /* Init cipher_ctx with IV. key & keylen are already initialized */ + ASSERT(cipher_ctx_reset(ctx->cipher, iv)); + } - /* Reserve space for authentication tag */ - mac_out = buf_write_alloc (&work, mac_len); - ASSERT (mac_out); + /* Reserve space for authentication tag */ + mac_out = buf_write_alloc(&work, mac_len); + ASSERT(mac_out); - dmsg (D_PACKET_CONTENT, "ENCRYPT FROM: %s", format_hex (BPTR (buf), BLEN (buf), 80, &gc)); + dmsg(D_PACKET_CONTENT, "ENCRYPT FROM: %s", format_hex(BPTR(buf), BLEN(buf), 80, &gc)); - /* Buffer overflow check */ - if (!buf_safe (&work, buf->len + cipher_ctx_block_size(ctx->cipher))) + /* Buffer overflow check */ + if (!buf_safe(&work, buf->len + cipher_ctx_block_size(ctx->cipher))) { - msg (D_CRYPT_ERRORS, - "ENCRYPT: buffer size error, bc=%d bo=%d bl=%d wc=%d wo=%d wl=%d", - buf->capacity, buf->offset, buf->len, work.capacity, work.offset, - work.len); - goto err; + msg(D_CRYPT_ERRORS, + "ENCRYPT: buffer size error, bc=%d bo=%d bl=%d wc=%d wo=%d wl=%d", + buf->capacity, buf->offset, buf->len, work.capacity, work.offset, + work.len); + goto err; } - /* For AEAD ciphers, authenticate Additional Data, including opcode */ - ASSERT (cipher_ctx_update_ad (ctx->cipher, BPTR (&work), BLEN (&work) - mac_len)); - dmsg (D_PACKET_CONTENT, "ENCRYPT AD: %s", - format_hex (BPTR (&work), BLEN (&work) - mac_len, 0, &gc)); + /* For AEAD ciphers, authenticate Additional Data, including opcode */ + ASSERT(cipher_ctx_update_ad(ctx->cipher, BPTR(&work), BLEN(&work) - mac_len)); + dmsg(D_PACKET_CONTENT, "ENCRYPT AD: %s", + format_hex(BPTR(&work), BLEN(&work) - mac_len, 0, &gc)); - /* Encrypt packet ID, payload */ - ASSERT (cipher_ctx_update (ctx->cipher, BEND (&work), &outlen, BPTR (buf), BLEN (buf))); - ASSERT (buf_inc_len (&work, outlen)); + /* Encrypt packet ID, payload */ + ASSERT(cipher_ctx_update(ctx->cipher, BEND(&work), &outlen, BPTR(buf), BLEN(buf))); + ASSERT(buf_inc_len(&work, outlen)); - /* Flush the encryption buffer */ - ASSERT (cipher_ctx_final (ctx->cipher, BEND (&work), &outlen)); - ASSERT (buf_inc_len (&work, outlen)); + /* Flush the encryption buffer */ + ASSERT(cipher_ctx_final(ctx->cipher, BEND(&work), &outlen)); + ASSERT(buf_inc_len(&work, outlen)); - /* Write authentication tag */ - ASSERT (cipher_ctx_get_tag (ctx->cipher, mac_out, mac_len)); + /* Write authentication tag */ + ASSERT(cipher_ctx_get_tag(ctx->cipher, mac_out, mac_len)); - *buf = work; + *buf = work; - dmsg (D_PACKET_CONTENT, "ENCRYPT TO: %s", format_hex (BPTR (buf), BLEN (buf), 80, &gc)); + dmsg(D_PACKET_CONTENT, "ENCRYPT TO: %s", format_hex(BPTR(buf), BLEN(buf), 80, &gc)); - gc_free (&gc); - return; + gc_free(&gc); + return; err: - crypto_clear_error(); - buf->len = 0; - gc_free (&gc); - return; + crypto_clear_error(); + buf->len = 0; + gc_free(&gc); + return; #else /* HAVE_AEAD_CIPHER_MODES */ - ASSERT (0); -#endif + ASSERT(0); +#endif /* ifdef HAVE_AEAD_CIPHER_MODES */ } static void -openvpn_encrypt_v1 (struct buffer *buf, struct buffer work, - struct crypto_options *opt) +openvpn_encrypt_v1(struct buffer *buf, struct buffer work, + struct crypto_options *opt) { - struct gc_arena gc; - gc_init (&gc); - - if (buf->len > 0 && opt) - { - const struct key_ctx *ctx = &opt->key_ctx_bi.encrypt; - uint8_t *mac_out = NULL; - const uint8_t *hmac_start = NULL; - - /* Do Encrypt from buf -> work */ - if (ctx->cipher) - { - uint8_t iv_buf[OPENVPN_MAX_IV_LENGTH] = {0}; - const int iv_size = cipher_ctx_iv_length (ctx->cipher); - const cipher_kt_t *cipher_kt = cipher_ctx_get_cipher_kt (ctx->cipher); - int outlen; - - /* Reserve space for HMAC */ - if (ctx->hmac) - { - mac_out = buf_write_alloc (&work, hmac_ctx_size(ctx->hmac)); - ASSERT (mac_out); - hmac_start = BEND(&work); - } - - if (cipher_kt_mode_cbc(cipher_kt)) - { - /* generate pseudo-random IV */ - if (opt->flags & CO_USE_IV) - prng_bytes (iv_buf, iv_size); - - /* Put packet ID in plaintext buffer */ - if (packet_id_initialized(&opt->packet_id)) - { - struct packet_id_net pin; - packet_id_alloc_outgoing (&opt->packet_id.send, &pin, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM)); - ASSERT (packet_id_write (&pin, buf, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM), true)); - } - } - else if (cipher_kt_mode_ofb_cfb(cipher_kt)) - { - struct packet_id_net pin; - struct buffer b; - - /* IV and packet-ID required for this mode. */ - ASSERT (opt->flags & CO_USE_IV); - ASSERT (packet_id_initialized(&opt->packet_id)); - - packet_id_alloc_outgoing (&opt->packet_id.send, &pin, true); - buf_set_write (&b, iv_buf, iv_size); - ASSERT (packet_id_write (&pin, &b, true, false)); - } - else /* We only support CBC, CFB, or OFB modes right now */ - { - ASSERT (0); - } - - /* set the IV pseudo-randomly */ - if (opt->flags & CO_USE_IV) + struct gc_arena gc; + gc_init(&gc); + + if (buf->len > 0 && opt) + { + const struct key_ctx *ctx = &opt->key_ctx_bi.encrypt; + uint8_t *mac_out = NULL; + const uint8_t *hmac_start = NULL; + + /* Do Encrypt from buf -> work */ + if (ctx->cipher) + { + uint8_t iv_buf[OPENVPN_MAX_IV_LENGTH] = {0}; + const int iv_size = cipher_ctx_iv_length(ctx->cipher); + const cipher_kt_t *cipher_kt = cipher_ctx_get_cipher_kt(ctx->cipher); + int outlen; + + /* Reserve space for HMAC */ + if (ctx->hmac) { - ASSERT (buf_write(&work, iv_buf, iv_size)); - dmsg (D_PACKET_CONTENT, "ENCRYPT IV: %s", format_hex (iv_buf, iv_size, 0, &gc)); + mac_out = buf_write_alloc(&work, hmac_ctx_size(ctx->hmac)); + ASSERT(mac_out); + hmac_start = BEND(&work); } - dmsg (D_PACKET_CONTENT, "ENCRYPT FROM: %s", - format_hex (BPTR (buf), BLEN (buf), 80, &gc)); - - /* cipher_ctx was already initialized with key & keylen */ - ASSERT (cipher_ctx_reset(ctx->cipher, iv_buf)); - - /* Buffer overflow check */ - if (!buf_safe (&work, buf->len + cipher_ctx_block_size(ctx->cipher))) - { - msg (D_CRYPT_ERRORS, "ENCRYPT: buffer size error, bc=%d bo=%d bl=%d wc=%d wo=%d wl=%d cbs=%d", - buf->capacity, - buf->offset, - buf->len, - work.capacity, - work.offset, - work.len, - cipher_ctx_block_size (ctx->cipher)); - goto err; - } - - /* Encrypt packet ID, payload */ - ASSERT (cipher_ctx_update (ctx->cipher, BEND (&work), &outlen, BPTR (buf), BLEN (buf))); - ASSERT (buf_inc_len(&work, outlen)); - - /* Flush the encryption buffer */ - ASSERT (cipher_ctx_final(ctx->cipher, BEND (&work), &outlen)); - ASSERT (buf_inc_len(&work, outlen)); - - /* For all CBC mode ciphers, check the last block is complete */ - ASSERT (cipher_kt_mode (cipher_kt) != OPENVPN_MODE_CBC || - outlen == iv_size); - } - else /* No Encryption */ - { - if (packet_id_initialized(&opt->packet_id)) - { - struct packet_id_net pin; - packet_id_alloc_outgoing (&opt->packet_id.send, &pin, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM)); - ASSERT (packet_id_write (&pin, buf, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM), true)); - } - if (ctx->hmac) - { - hmac_start = BPTR(buf); - ASSERT (mac_out = buf_prepend (buf, hmac_ctx_size(ctx->hmac))); - } - if (BLEN(&work)) { - buf_write_prepend(buf, BPTR(&work), BLEN(&work)); - } - work = *buf; - } - - /* HMAC the ciphertext (or plaintext if !cipher) */ - if (ctx->hmac) - { - hmac_ctx_reset (ctx->hmac); - hmac_ctx_update (ctx->hmac, hmac_start, BEND(&work) - hmac_start); - hmac_ctx_final (ctx->hmac, mac_out); - dmsg (D_PACKET_CONTENT, "ENCRYPT HMAC: %s", - format_hex (mac_out, hmac_ctx_size(ctx->hmac), 80, &gc)); - } - - *buf = work; - - dmsg (D_PACKET_CONTENT, "ENCRYPT TO: %s", - format_hex (BPTR (&work), BLEN (&work), 80, &gc)); - } - - gc_free (&gc); - return; + if (cipher_kt_mode_cbc(cipher_kt)) + { + /* generate pseudo-random IV */ + if (opt->flags & CO_USE_IV) + { + prng_bytes(iv_buf, iv_size); + } + + /* Put packet ID in plaintext buffer */ + if (packet_id_initialized(&opt->packet_id)) + { + struct packet_id_net pin; + packet_id_alloc_outgoing(&opt->packet_id.send, &pin, BOOL_CAST(opt->flags & CO_PACKET_ID_LONG_FORM)); + ASSERT(packet_id_write(&pin, buf, BOOL_CAST(opt->flags & CO_PACKET_ID_LONG_FORM), true)); + } + } + else if (cipher_kt_mode_ofb_cfb(cipher_kt)) + { + struct packet_id_net pin; + struct buffer b; + + /* IV and packet-ID required for this mode. */ + ASSERT(opt->flags & CO_USE_IV); + ASSERT(packet_id_initialized(&opt->packet_id)); + + packet_id_alloc_outgoing(&opt->packet_id.send, &pin, true); + buf_set_write(&b, iv_buf, iv_size); + ASSERT(packet_id_write(&pin, &b, true, false)); + } + else /* We only support CBC, CFB, or OFB modes right now */ + { + ASSERT(0); + } + + /* set the IV pseudo-randomly */ + if (opt->flags & CO_USE_IV) + { + ASSERT(buf_write(&work, iv_buf, iv_size)); + dmsg(D_PACKET_CONTENT, "ENCRYPT IV: %s", format_hex(iv_buf, iv_size, 0, &gc)); + } + + dmsg(D_PACKET_CONTENT, "ENCRYPT FROM: %s", + format_hex(BPTR(buf), BLEN(buf), 80, &gc)); + + /* cipher_ctx was already initialized with key & keylen */ + ASSERT(cipher_ctx_reset(ctx->cipher, iv_buf)); + + /* Buffer overflow check */ + if (!buf_safe(&work, buf->len + cipher_ctx_block_size(ctx->cipher))) + { + msg(D_CRYPT_ERRORS, "ENCRYPT: buffer size error, bc=%d bo=%d bl=%d wc=%d wo=%d wl=%d cbs=%d", + buf->capacity, + buf->offset, + buf->len, + work.capacity, + work.offset, + work.len, + cipher_ctx_block_size(ctx->cipher)); + goto err; + } + + /* Encrypt packet ID, payload */ + ASSERT(cipher_ctx_update(ctx->cipher, BEND(&work), &outlen, BPTR(buf), BLEN(buf))); + ASSERT(buf_inc_len(&work, outlen)); + + /* Flush the encryption buffer */ + ASSERT(cipher_ctx_final(ctx->cipher, BEND(&work), &outlen)); + ASSERT(buf_inc_len(&work, outlen)); + + /* For all CBC mode ciphers, check the last block is complete */ + ASSERT(cipher_kt_mode(cipher_kt) != OPENVPN_MODE_CBC + || outlen == iv_size); + } + else /* No Encryption */ + { + if (packet_id_initialized(&opt->packet_id)) + { + struct packet_id_net pin; + packet_id_alloc_outgoing(&opt->packet_id.send, &pin, BOOL_CAST(opt->flags & CO_PACKET_ID_LONG_FORM)); + ASSERT(packet_id_write(&pin, buf, BOOL_CAST(opt->flags & CO_PACKET_ID_LONG_FORM), true)); + } + if (ctx->hmac) + { + hmac_start = BPTR(buf); + ASSERT(mac_out = buf_prepend(buf, hmac_ctx_size(ctx->hmac))); + } + if (BLEN(&work)) + { + buf_write_prepend(buf, BPTR(&work), BLEN(&work)); + } + work = *buf; + } + + /* HMAC the ciphertext (or plaintext if !cipher) */ + if (ctx->hmac) + { + hmac_ctx_reset(ctx->hmac); + hmac_ctx_update(ctx->hmac, hmac_start, BEND(&work) - hmac_start); + hmac_ctx_final(ctx->hmac, mac_out); + dmsg(D_PACKET_CONTENT, "ENCRYPT HMAC: %s", + format_hex(mac_out, hmac_ctx_size(ctx->hmac), 80, &gc)); + } + + *buf = work; + + dmsg(D_PACKET_CONTENT, "ENCRYPT TO: %s", + format_hex(BPTR(&work), BLEN(&work), 80, &gc)); + } + + gc_free(&gc); + return; err: - crypto_clear_error(); - buf->len = 0; - gc_free (&gc); - return; + crypto_clear_error(); + buf->len = 0; + gc_free(&gc); + return; } void -openvpn_encrypt (struct buffer *buf, struct buffer work, - struct crypto_options *opt) +openvpn_encrypt(struct buffer *buf, struct buffer work, + struct crypto_options *opt) { - if (buf->len > 0 && opt) + if (buf->len > 0 && opt) { - const cipher_kt_t *cipher_kt = - cipher_ctx_get_cipher_kt(opt->key_ctx_bi.encrypt.cipher); - - if (cipher_kt_mode_aead (cipher_kt)) - openvpn_encrypt_aead(buf, work, opt); - else - openvpn_encrypt_v1(buf, work, opt); + const cipher_kt_t *cipher_kt = + cipher_ctx_get_cipher_kt(opt->key_ctx_bi.encrypt.cipher); + + if (cipher_kt_mode_aead(cipher_kt)) + { + openvpn_encrypt_aead(buf, work, opt); + } + else + { + openvpn_encrypt_v1(buf, work, opt); + } } } -bool crypto_check_replay(struct crypto_options *opt, - const struct packet_id_net *pin, const char *error_prefix, - struct gc_arena *gc) { - bool ret = false; - packet_id_reap_test (&opt->packet_id.rec); - if (packet_id_test (&opt->packet_id.rec, pin)) - { - packet_id_add (&opt->packet_id.rec, pin); - if (opt->pid_persist && (opt->flags & CO_PACKET_ID_LONG_FORM)) - packet_id_persist_save_obj (opt->pid_persist, &opt->packet_id); - ret = true; - } - else - { - if (!(opt->flags & CO_MUTE_REPLAY_WARNINGS)) - { - msg (D_REPLAY_ERRORS, "%s: bad packet ID (may be a replay): %s -- " - "see the man page entry for --no-replay and --replay-window for " - "more info or silence this warning with --mute-replay-warnings", - error_prefix, packet_id_net_print (pin, true, gc)); - } - } - return ret; +bool +crypto_check_replay(struct crypto_options *opt, + const struct packet_id_net *pin, const char *error_prefix, + struct gc_arena *gc) { + bool ret = false; + packet_id_reap_test(&opt->packet_id.rec); + if (packet_id_test(&opt->packet_id.rec, pin)) + { + packet_id_add(&opt->packet_id.rec, pin); + if (opt->pid_persist && (opt->flags & CO_PACKET_ID_LONG_FORM)) + { + packet_id_persist_save_obj(opt->pid_persist, &opt->packet_id); + } + ret = true; + } + else + { + if (!(opt->flags & CO_MUTE_REPLAY_WARNINGS)) + { + msg(D_REPLAY_ERRORS, "%s: bad packet ID (may be a replay): %s -- " + "see the man page entry for --no-replay and --replay-window for " + "more info or silence this warning with --mute-replay-warnings", + error_prefix, packet_id_net_print(pin, true, gc)); + } + } + return ret; } /* @@ -353,141 +363,143 @@ bool crypto_check_replay(struct crypto_options *opt, * is returned. */ static bool -openvpn_decrypt_aead (struct buffer *buf, struct buffer work, - struct crypto_options *opt, const struct frame* frame, - const uint8_t *ad_start) +openvpn_decrypt_aead(struct buffer *buf, struct buffer work, + struct crypto_options *opt, const struct frame *frame, + const uint8_t *ad_start) { #ifdef HAVE_AEAD_CIPHER_MODES - static const char error_prefix[] = "AEAD Decrypt error"; - struct packet_id_net pin = { 0 }; - const struct key_ctx *ctx = &opt->key_ctx_bi.decrypt; - const cipher_kt_t *cipher_kt = cipher_ctx_get_cipher_kt (ctx->cipher); - uint8_t *tag_ptr = NULL; - int tag_size = 0; - int outlen; - struct gc_arena gc; - - gc_init (&gc); - - ASSERT (opt); - ASSERT (frame); - ASSERT (buf->len > 0); - ASSERT (ctx->cipher); - ASSERT (cipher_kt_mode_aead (cipher_kt)); - - dmsg (D_PACKET_CONTENT, "DECRYPT FROM: %s", - format_hex (BPTR (buf), BLEN (buf), 80, &gc)); - - ASSERT (ad_start >= buf->data && ad_start <= BPTR (buf)); + static const char error_prefix[] = "AEAD Decrypt error"; + struct packet_id_net pin = { 0 }; + const struct key_ctx *ctx = &opt->key_ctx_bi.decrypt; + const cipher_kt_t *cipher_kt = cipher_ctx_get_cipher_kt(ctx->cipher); + uint8_t *tag_ptr = NULL; + int tag_size = 0; + int outlen; + struct gc_arena gc; - ASSERT (buf_init (&work, FRAME_HEADROOM_ADJ (frame, FRAME_HEADROOM_MARKER_DECRYPT))); + gc_init(&gc); - /* IV and Packet ID required for this mode */ - ASSERT (packet_id_initialized (&opt->packet_id)); - ASSERT (opt->flags & CO_USE_IV); + ASSERT(opt); + ASSERT(frame); + ASSERT(buf->len > 0); + ASSERT(ctx->cipher); + ASSERT(cipher_kt_mode_aead(cipher_kt)); - /* Combine IV from explicit part from packet and implicit part from context */ - { - uint8_t iv[OPENVPN_MAX_IV_LENGTH] = { 0 }; - const int iv_len = cipher_ctx_iv_length (ctx->cipher); - const size_t packet_iv_len = iv_len - ctx->implicit_iv_len; + dmsg(D_PACKET_CONTENT, "DECRYPT FROM: %s", + format_hex(BPTR(buf), BLEN(buf), 80, &gc)); - ASSERT (ctx->implicit_iv_len <= iv_len); - if (buf->len + ctx->implicit_iv_len < iv_len) - CRYPT_ERROR ("missing IV info"); + ASSERT(ad_start >= buf->data && ad_start <= BPTR(buf)); - memcpy (iv, BPTR(buf), packet_iv_len); - memcpy (iv + packet_iv_len, ctx->implicit_iv, ctx->implicit_iv_len); + ASSERT(buf_init(&work, FRAME_HEADROOM_ADJ(frame, FRAME_HEADROOM_MARKER_DECRYPT))); - dmsg (D_PACKET_CONTENT, "DECRYPT IV: %s", format_hex (iv, iv_len, 0, &gc)); + /* IV and Packet ID required for this mode */ + ASSERT(packet_id_initialized(&opt->packet_id)); + ASSERT(opt->flags & CO_USE_IV); - /* Load IV, ctx->cipher was already initialized with key & keylen */ - if (!cipher_ctx_reset (ctx->cipher, iv)) - { - CRYPT_ERROR ("cipher init failed"); - } - } + /* Combine IV from explicit part from packet and implicit part from context */ + { + uint8_t iv[OPENVPN_MAX_IV_LENGTH] = { 0 }; + const int iv_len = cipher_ctx_iv_length(ctx->cipher); + const size_t packet_iv_len = iv_len - ctx->implicit_iv_len; + + ASSERT(ctx->implicit_iv_len <= iv_len); + if (buf->len + ctx->implicit_iv_len < iv_len) + { + CRYPT_ERROR("missing IV info"); + } + + memcpy(iv, BPTR(buf), packet_iv_len); + memcpy(iv + packet_iv_len, ctx->implicit_iv, ctx->implicit_iv_len); + + dmsg(D_PACKET_CONTENT, "DECRYPT IV: %s", format_hex(iv, iv_len, 0, &gc)); + + /* Load IV, ctx->cipher was already initialized with key & keylen */ + if (!cipher_ctx_reset(ctx->cipher, iv)) + { + CRYPT_ERROR("cipher init failed"); + } + } - /* Read packet ID from packet */ - if (!packet_id_read (&pin, buf, false)) + /* Read packet ID from packet */ + if (!packet_id_read(&pin, buf, false)) { - CRYPT_ERROR ("error reading packet-id"); + CRYPT_ERROR("error reading packet-id"); } - /* keep the tag value to feed in later */ - tag_size = cipher_kt_tag_size(cipher_kt); - if (buf->len < tag_size) + /* keep the tag value to feed in later */ + tag_size = cipher_kt_tag_size(cipher_kt); + if (buf->len < tag_size) { - CRYPT_ERROR ("missing tag"); + CRYPT_ERROR("missing tag"); } - tag_ptr = BPTR(buf); - ASSERT (buf_advance (buf, tag_size)); - dmsg (D_PACKET_CONTENT, "DECRYPT MAC: %s", format_hex (tag_ptr, tag_size, 0, &gc)); + tag_ptr = BPTR(buf); + ASSERT(buf_advance(buf, tag_size)); + dmsg(D_PACKET_CONTENT, "DECRYPT MAC: %s", format_hex(tag_ptr, tag_size, 0, &gc)); #if defined(ENABLE_CRYPTO_OPENSSL) && OPENSSL_VERSION_NUMBER < 0x10001040L - /* OpenSSL <= 1.0.1c bug requires set tag before processing ciphertext */ - if (!EVP_CIPHER_CTX_ctrl (ctx->cipher, EVP_CTRL_GCM_SET_TAG, tag_size, tag_ptr)) + /* OpenSSL <= 1.0.1c bug requires set tag before processing ciphertext */ + if (!EVP_CIPHER_CTX_ctrl(ctx->cipher, EVP_CTRL_GCM_SET_TAG, tag_size, tag_ptr)) { - CRYPT_ERROR ("setting tag failed"); + CRYPT_ERROR("setting tag failed"); } #endif - if (buf->len < 1) + if (buf->len < 1) { - CRYPT_ERROR ("missing payload"); + CRYPT_ERROR("missing payload"); } - dmsg (D_PACKET_CONTENT, "DECRYPT FROM: %s", format_hex (BPTR(buf), BLEN(buf), 0, &gc)); + dmsg(D_PACKET_CONTENT, "DECRYPT FROM: %s", format_hex(BPTR(buf), BLEN(buf), 0, &gc)); - /* Buffer overflow check (should never fail) */ - if (!buf_safe (&work, buf->len + cipher_ctx_block_size(ctx->cipher))) + /* Buffer overflow check (should never fail) */ + if (!buf_safe(&work, buf->len + cipher_ctx_block_size(ctx->cipher))) { - CRYPT_ERROR ("potential buffer overflow"); + CRYPT_ERROR("potential buffer overflow"); } - { - /* feed in tag and the authenticated data */ - const int ad_size = BPTR (buf) - ad_start - tag_size; - ASSERT (cipher_ctx_update_ad (ctx->cipher, ad_start, ad_size)); - dmsg (D_PACKET_CONTENT, "DECRYPT AD: %s", - format_hex (BPTR (buf) - ad_size - tag_size, ad_size, 0, &gc)); - } + { + /* feed in tag and the authenticated data */ + const int ad_size = BPTR(buf) - ad_start - tag_size; + ASSERT(cipher_ctx_update_ad(ctx->cipher, ad_start, ad_size)); + dmsg(D_PACKET_CONTENT, "DECRYPT AD: %s", + format_hex(BPTR(buf) - ad_size - tag_size, ad_size, 0, &gc)); + } - /* Decrypt and authenticate packet */ - if (!cipher_ctx_update (ctx->cipher, BPTR (&work), &outlen, BPTR (buf), - BLEN (buf))) + /* Decrypt and authenticate packet */ + if (!cipher_ctx_update(ctx->cipher, BPTR(&work), &outlen, BPTR(buf), + BLEN(buf))) { - CRYPT_ERROR ("cipher update failed"); + CRYPT_ERROR("cipher update failed"); } - ASSERT (buf_inc_len (&work, outlen)); - if (!cipher_ctx_final_check_tag (ctx->cipher, BPTR (&work) + outlen, - &outlen, tag_ptr, tag_size)) + ASSERT(buf_inc_len(&work, outlen)); + if (!cipher_ctx_final_check_tag(ctx->cipher, BPTR(&work) + outlen, + &outlen, tag_ptr, tag_size)) { - CRYPT_ERROR ("cipher final failed"); + CRYPT_ERROR("cipher final failed"); } - ASSERT (buf_inc_len (&work, outlen)); + ASSERT(buf_inc_len(&work, outlen)); - dmsg (D_PACKET_CONTENT, "DECRYPT TO: %s", - format_hex (BPTR (&work), BLEN (&work), 80, &gc)); + dmsg(D_PACKET_CONTENT, "DECRYPT TO: %s", + format_hex(BPTR(&work), BLEN(&work), 80, &gc)); - if (!crypto_check_replay (opt, &pin, error_prefix, &gc)) + if (!crypto_check_replay(opt, &pin, error_prefix, &gc)) { - goto error_exit; + goto error_exit; } - *buf = work; + *buf = work; - gc_free (&gc); - return true; + gc_free(&gc); + return true; - error_exit: - crypto_clear_error(); - buf->len = 0; - gc_free (&gc); - return false; +error_exit: + crypto_clear_error(); + buf->len = 0; + gc_free(&gc); + return false; #else /* HAVE_AEAD_CIPHER_MODES */ - ASSERT (0); - return false; -#endif + ASSERT(0); + return false; +#endif /* ifdef HAVE_AEAD_CIPHER_MODES */ } /* @@ -499,397 +511,448 @@ openvpn_decrypt_aead (struct buffer *buf, struct buffer work, * is returned. */ static bool -openvpn_decrypt_v1 (struct buffer *buf, struct buffer work, - struct crypto_options *opt, const struct frame* frame) +openvpn_decrypt_v1(struct buffer *buf, struct buffer work, + struct crypto_options *opt, const struct frame *frame) { - static const char error_prefix[] = "Authenticate/Decrypt packet error"; - struct gc_arena gc; - gc_init (&gc); - - if (buf->len > 0 && opt) - { - const struct key_ctx *ctx = &opt->key_ctx_bi.decrypt; - struct packet_id_net pin; - bool have_pin = false; - - dmsg (D_PACKET_CONTENT, "DECRYPT FROM: %s", - format_hex (BPTR (buf), BLEN (buf), 80, &gc)); - - /* Verify the HMAC */ - if (ctx->hmac) - { - int hmac_len; - uint8_t local_hmac[MAX_HMAC_KEY_LENGTH]; /* HMAC of ciphertext computed locally */ - - hmac_ctx_reset(ctx->hmac); - - /* Assume the length of the input HMAC */ - hmac_len = hmac_ctx_size (ctx->hmac); - - /* Authentication fails if insufficient data in packet for HMAC */ - if (buf->len < hmac_len) - CRYPT_ERROR ("missing authentication info"); - - hmac_ctx_update (ctx->hmac, BPTR (buf) + hmac_len, BLEN (buf) - hmac_len); - hmac_ctx_final (ctx->hmac, local_hmac); - - /* Compare locally computed HMAC with packet HMAC */ - if (memcmp_constant_time (local_hmac, BPTR (buf), hmac_len)) - CRYPT_ERROR ("packet HMAC authentication failed"); - - ASSERT (buf_advance (buf, hmac_len)); - } - - /* Decrypt packet ID + payload */ - - if (ctx->cipher) - { - const int iv_size = cipher_ctx_iv_length (ctx->cipher); - const cipher_kt_t *cipher_kt = cipher_ctx_get_cipher_kt (ctx->cipher); - uint8_t iv_buf[OPENVPN_MAX_IV_LENGTH] = { 0 }; - int outlen; - - /* initialize work buffer with FRAME_HEADROOM bytes of prepend capacity */ - ASSERT (buf_init (&work, FRAME_HEADROOM_ADJ (frame, FRAME_HEADROOM_MARKER_DECRYPT))); - - /* use IV if user requested it */ - if (opt->flags & CO_USE_IV) - { - if (buf->len < iv_size) - CRYPT_ERROR ("missing IV info"); - memcpy (iv_buf, BPTR (buf), iv_size); - ASSERT (buf_advance (buf, iv_size)); - } - - /* show the IV's initial state */ - if (opt->flags & CO_USE_IV) - dmsg (D_PACKET_CONTENT, "DECRYPT IV: %s", format_hex (iv_buf, iv_size, 0, &gc)); - - if (buf->len < 1) - CRYPT_ERROR ("missing payload"); - - /* ctx->cipher was already initialized with key & keylen */ - if (!cipher_ctx_reset (ctx->cipher, iv_buf)) - CRYPT_ERROR ("cipher init failed"); - - /* Buffer overflow check (should never happen) */ - if (!buf_safe (&work, buf->len + cipher_ctx_block_size(ctx->cipher))) - CRYPT_ERROR ("potential buffer overflow"); - - /* Decrypt packet ID, payload */ - if (!cipher_ctx_update (ctx->cipher, BPTR (&work), &outlen, BPTR (buf), BLEN (buf))) - CRYPT_ERROR ("cipher update failed"); - ASSERT (buf_inc_len(&work, outlen)); - - /* Flush the decryption buffer */ - if (!cipher_ctx_final (ctx->cipher, BPTR (&work) + outlen, &outlen)) - CRYPT_ERROR ("cipher final failed"); - ASSERT (buf_inc_len(&work, outlen)); - - dmsg (D_PACKET_CONTENT, "DECRYPT TO: %s", - format_hex (BPTR (&work), BLEN (&work), 80, &gc)); - - /* Get packet ID from plaintext buffer or IV, depending on cipher mode */ - { - if (cipher_kt_mode_cbc(cipher_kt)) - { - if (packet_id_initialized(&opt->packet_id)) - { - if (!packet_id_read (&pin, &work, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM))) - CRYPT_ERROR ("error reading CBC packet-id"); - have_pin = true; - } - } - else if (cipher_kt_mode_ofb_cfb(cipher_kt)) - { - struct buffer b; - - /* IV and packet-ID required for this mode. */ - ASSERT (opt->flags & CO_USE_IV); - ASSERT (packet_id_initialized(&opt->packet_id)); - - buf_set_read (&b, iv_buf, iv_size); - if (!packet_id_read (&pin, &b, true)) - CRYPT_ERROR ("error reading CFB/OFB packet-id"); - have_pin = true; - } - else /* We only support CBC, CFB, or OFB modes right now */ - { - ASSERT (0); - } - } - } - else - { - work = *buf; - if (packet_id_initialized(&opt->packet_id)) - { - if (!packet_id_read (&pin, &work, BOOL_CAST (opt->flags & CO_PACKET_ID_LONG_FORM))) - CRYPT_ERROR ("error reading packet-id"); - have_pin = !BOOL_CAST (opt->flags & CO_IGNORE_PACKET_ID); - } - } - - if (have_pin && !crypto_check_replay(opt, &pin, error_prefix, &gc)) - { - goto error_exit; - } - *buf = work; - } - - gc_free (&gc); - return true; - - error_exit: - crypto_clear_error(); - buf->len = 0; - gc_free (&gc); - return false; + static const char error_prefix[] = "Authenticate/Decrypt packet error"; + struct gc_arena gc; + gc_init(&gc); + + if (buf->len > 0 && opt) + { + const struct key_ctx *ctx = &opt->key_ctx_bi.decrypt; + struct packet_id_net pin; + bool have_pin = false; + + dmsg(D_PACKET_CONTENT, "DECRYPT FROM: %s", + format_hex(BPTR(buf), BLEN(buf), 80, &gc)); + + /* Verify the HMAC */ + if (ctx->hmac) + { + int hmac_len; + uint8_t local_hmac[MAX_HMAC_KEY_LENGTH]; /* HMAC of ciphertext computed locally */ + + hmac_ctx_reset(ctx->hmac); + + /* Assume the length of the input HMAC */ + hmac_len = hmac_ctx_size(ctx->hmac); + + /* Authentication fails if insufficient data in packet for HMAC */ + if (buf->len < hmac_len) + { + CRYPT_ERROR("missing authentication info"); + } + + hmac_ctx_update(ctx->hmac, BPTR(buf) + hmac_len, BLEN(buf) - hmac_len); + hmac_ctx_final(ctx->hmac, local_hmac); + + /* Compare locally computed HMAC with packet HMAC */ + if (memcmp_constant_time(local_hmac, BPTR(buf), hmac_len)) + { + CRYPT_ERROR("packet HMAC authentication failed"); + } + + ASSERT(buf_advance(buf, hmac_len)); + } + + /* Decrypt packet ID + payload */ + + if (ctx->cipher) + { + const int iv_size = cipher_ctx_iv_length(ctx->cipher); + const cipher_kt_t *cipher_kt = cipher_ctx_get_cipher_kt(ctx->cipher); + uint8_t iv_buf[OPENVPN_MAX_IV_LENGTH] = { 0 }; + int outlen; + + /* initialize work buffer with FRAME_HEADROOM bytes of prepend capacity */ + ASSERT(buf_init(&work, FRAME_HEADROOM_ADJ(frame, FRAME_HEADROOM_MARKER_DECRYPT))); + + /* use IV if user requested it */ + if (opt->flags & CO_USE_IV) + { + if (buf->len < iv_size) + { + CRYPT_ERROR("missing IV info"); + } + memcpy(iv_buf, BPTR(buf), iv_size); + ASSERT(buf_advance(buf, iv_size)); + } + + /* show the IV's initial state */ + if (opt->flags & CO_USE_IV) + { + dmsg(D_PACKET_CONTENT, "DECRYPT IV: %s", format_hex(iv_buf, iv_size, 0, &gc)); + } + + if (buf->len < 1) + { + CRYPT_ERROR("missing payload"); + } + + /* ctx->cipher was already initialized with key & keylen */ + if (!cipher_ctx_reset(ctx->cipher, iv_buf)) + { + CRYPT_ERROR("cipher init failed"); + } + + /* Buffer overflow check (should never happen) */ + if (!buf_safe(&work, buf->len + cipher_ctx_block_size(ctx->cipher))) + { + CRYPT_ERROR("potential buffer overflow"); + } + + /* Decrypt packet ID, payload */ + if (!cipher_ctx_update(ctx->cipher, BPTR(&work), &outlen, BPTR(buf), BLEN(buf))) + { + CRYPT_ERROR("cipher update failed"); + } + ASSERT(buf_inc_len(&work, outlen)); + + /* Flush the decryption buffer */ + if (!cipher_ctx_final(ctx->cipher, BPTR(&work) + outlen, &outlen)) + { + CRYPT_ERROR("cipher final failed"); + } + ASSERT(buf_inc_len(&work, outlen)); + + dmsg(D_PACKET_CONTENT, "DECRYPT TO: %s", + format_hex(BPTR(&work), BLEN(&work), 80, &gc)); + + /* Get packet ID from plaintext buffer or IV, depending on cipher mode */ + { + if (cipher_kt_mode_cbc(cipher_kt)) + { + if (packet_id_initialized(&opt->packet_id)) + { + if (!packet_id_read(&pin, &work, BOOL_CAST(opt->flags & CO_PACKET_ID_LONG_FORM))) + { + CRYPT_ERROR("error reading CBC packet-id"); + } + have_pin = true; + } + } + else if (cipher_kt_mode_ofb_cfb(cipher_kt)) + { + struct buffer b; + + /* IV and packet-ID required for this mode. */ + ASSERT(opt->flags & CO_USE_IV); + ASSERT(packet_id_initialized(&opt->packet_id)); + + buf_set_read(&b, iv_buf, iv_size); + if (!packet_id_read(&pin, &b, true)) + { + CRYPT_ERROR("error reading CFB/OFB packet-id"); + } + have_pin = true; + } + else /* We only support CBC, CFB, or OFB modes right now */ + { + ASSERT(0); + } + } + } + else + { + work = *buf; + if (packet_id_initialized(&opt->packet_id)) + { + if (!packet_id_read(&pin, &work, BOOL_CAST(opt->flags & CO_PACKET_ID_LONG_FORM))) + { + CRYPT_ERROR("error reading packet-id"); + } + have_pin = !BOOL_CAST(opt->flags & CO_IGNORE_PACKET_ID); + } + } + + if (have_pin && !crypto_check_replay(opt, &pin, error_prefix, &gc)) + { + goto error_exit; + } + *buf = work; + } + + gc_free(&gc); + return true; + +error_exit: + crypto_clear_error(); + buf->len = 0; + gc_free(&gc); + return false; } bool -openvpn_decrypt (struct buffer *buf, struct buffer work, - struct crypto_options *opt, const struct frame* frame, - const uint8_t *ad_start) +openvpn_decrypt(struct buffer *buf, struct buffer work, + struct crypto_options *opt, const struct frame *frame, + const uint8_t *ad_start) { - bool ret = false; + bool ret = false; - if (buf->len > 0 && opt) + if (buf->len > 0 && opt) { - const struct key_ctx *ctx = &opt->key_ctx_bi.decrypt; - if (cipher_kt_mode_aead (cipher_ctx_get_cipher_kt (ctx->cipher))) - { - ret = openvpn_decrypt_aead (buf, work, opt, frame, ad_start); - } - else - { - ret = openvpn_decrypt_v1 (buf, work, opt, frame); - } + const struct key_ctx *ctx = &opt->key_ctx_bi.decrypt; + if (cipher_kt_mode_aead(cipher_ctx_get_cipher_kt(ctx->cipher))) + { + ret = openvpn_decrypt_aead(buf, work, opt, frame, ad_start); + } + else + { + ret = openvpn_decrypt_v1(buf, work, opt, frame); + } } - else + else { - ret = true; + ret = true; } - return ret; + return ret; } void crypto_adjust_frame_parameters(struct frame *frame, - const struct key_type* kt, - bool use_iv, - bool packet_id, - bool packet_id_long_form) + const struct key_type *kt, + bool use_iv, + bool packet_id, + bool packet_id_long_form) { - size_t crypto_overhead = 0; + size_t crypto_overhead = 0; - if (packet_id) - crypto_overhead += packet_id_size (packet_id_long_form); - - if (kt->cipher) + if (packet_id) { - if (use_iv) - crypto_overhead += cipher_kt_iv_size (kt->cipher); - - if (cipher_kt_mode_aead (kt->cipher)) - crypto_overhead += cipher_kt_tag_size (kt->cipher); + crypto_overhead += packet_id_size(packet_id_long_form); + } - /* extra block required by cipher_ctx_update() */ - crypto_overhead += cipher_kt_block_size (kt->cipher); + if (kt->cipher) + { + if (use_iv) + { + crypto_overhead += cipher_kt_iv_size(kt->cipher); + } + + if (cipher_kt_mode_aead(kt->cipher)) + { + crypto_overhead += cipher_kt_tag_size(kt->cipher); + } + + /* extra block required by cipher_ctx_update() */ + crypto_overhead += cipher_kt_block_size(kt->cipher); } - crypto_overhead += kt->hmac_length; + crypto_overhead += kt->hmac_length; - frame_add_to_extra_frame (frame, crypto_overhead); + frame_add_to_extra_frame(frame, crypto_overhead); - msg(D_MTU_DEBUG, "%s: Adjusting frame parameters for crypto by %u bytes", - __func__, (unsigned int) crypto_overhead); + msg(D_MTU_DEBUG, "%s: Adjusting frame parameters for crypto by %u bytes", + __func__, (unsigned int) crypto_overhead); } size_t crypto_max_overhead(void) { - return packet_id_size(true) + OPENVPN_MAX_IV_LENGTH + - OPENVPN_MAX_CIPHER_BLOCK_SIZE + - max_int (OPENVPN_MAX_HMAC_SIZE, OPENVPN_AEAD_TAG_LENGTH); + return packet_id_size(true) + OPENVPN_MAX_IV_LENGTH + +OPENVPN_MAX_CIPHER_BLOCK_SIZE + +max_int(OPENVPN_MAX_HMAC_SIZE, OPENVPN_AEAD_TAG_LENGTH); } /* * Build a struct key_type. */ void -init_key_type (struct key_type *kt, const char *ciphername, - const char *authname, int keysize, bool tls_mode, bool warn) +init_key_type(struct key_type *kt, const char *ciphername, + const char *authname, int keysize, bool tls_mode, bool warn) { - bool aead_cipher = false; + bool aead_cipher = false; - ASSERT(ciphername); - ASSERT(authname); + ASSERT(ciphername); + ASSERT(authname); - CLEAR (*kt); - if (strcmp (ciphername, "none") != 0) + CLEAR(*kt); + if (strcmp(ciphername, "none") != 0) { - kt->cipher = cipher_kt_get (translate_cipher_name_from_openvpn(ciphername)); - if (!kt->cipher) - { - msg (M_FATAL, "Cipher %s not supported", ciphername); - } - - kt->cipher_length = cipher_kt_key_size (kt->cipher); - if (keysize > 0 && keysize <= MAX_CIPHER_KEY_LENGTH) - kt->cipher_length = keysize; - - /* check legal cipher mode */ - aead_cipher = cipher_kt_mode_aead(kt->cipher); - if (!(cipher_kt_mode_cbc(kt->cipher) - || (tls_mode && aead_cipher) + kt->cipher = cipher_kt_get(translate_cipher_name_from_openvpn(ciphername)); + if (!kt->cipher) + { + msg(M_FATAL, "Cipher %s not supported", ciphername); + } + + kt->cipher_length = cipher_kt_key_size(kt->cipher); + if (keysize > 0 && keysize <= MAX_CIPHER_KEY_LENGTH) + { + kt->cipher_length = keysize; + } + + /* check legal cipher mode */ + aead_cipher = cipher_kt_mode_aead(kt->cipher); + if (!(cipher_kt_mode_cbc(kt->cipher) + || (tls_mode && aead_cipher) #ifdef ENABLE_OFB_CFB_MODE - || (tls_mode && cipher_kt_mode_ofb_cfb(kt->cipher)) + || (tls_mode && cipher_kt_mode_ofb_cfb(kt->cipher)) #endif - )) - msg (M_FATAL, "Cipher '%s' mode not supported", ciphername); - - if (OPENVPN_MAX_CIPHER_BLOCK_SIZE < cipher_kt_block_size(kt->cipher)) - msg (M_FATAL, "Cipher '%s' not allowed: block size too big.", ciphername); + )) + { + msg(M_FATAL, "Cipher '%s' mode not supported", ciphername); + } + + if (OPENVPN_MAX_CIPHER_BLOCK_SIZE < cipher_kt_block_size(kt->cipher)) + { + msg(M_FATAL, "Cipher '%s' not allowed: block size too big.", ciphername); + } } - else + else { - if (warn) - msg (M_WARN, "******* WARNING *******: null cipher specified, no encryption will be used"); + if (warn) + { + msg(M_WARN, "******* WARNING *******: null cipher specified, no encryption will be used"); + } } - if (strcmp (authname, "none") != 0) + if (strcmp(authname, "none") != 0) { - if (!aead_cipher) { /* Ignore auth for AEAD ciphers */ - kt->digest = md_kt_get (authname); - kt->hmac_length = md_kt_size (kt->digest); + if (!aead_cipher) /* Ignore auth for AEAD ciphers */ + { + kt->digest = md_kt_get(authname); + kt->hmac_length = md_kt_size(kt->digest); - if (OPENVPN_MAX_HMAC_SIZE < kt->hmac_length) - msg (M_FATAL, "HMAC '%s' not allowed: digest size too big.", authname); - } + if (OPENVPN_MAX_HMAC_SIZE < kt->hmac_length) + { + msg(M_FATAL, "HMAC '%s' not allowed: digest size too big.", authname); + } + } } - else if (!aead_cipher) + else if (!aead_cipher) { - if (warn) - msg (M_WARN, "******* WARNING *******: null MAC specified, no authentication will be used"); + if (warn) + { + msg(M_WARN, "******* WARNING *******: null MAC specified, no authentication will be used"); + } } } /* given a key and key_type, build a key_ctx */ void -init_key_ctx (struct key_ctx *ctx, struct key *key, - const struct key_type *kt, int enc, - const char *prefix) +init_key_ctx(struct key_ctx *ctx, struct key *key, + const struct key_type *kt, int enc, + const char *prefix) { - struct gc_arena gc = gc_new (); - CLEAR (*ctx); - if (kt->cipher && kt->cipher_length > 0) + struct gc_arena gc = gc_new(); + CLEAR(*ctx); + if (kt->cipher && kt->cipher_length > 0) { - ALLOC_OBJ(ctx->cipher, cipher_ctx_t); - cipher_ctx_init (ctx->cipher, key->cipher, kt->cipher_length, - kt->cipher, enc); - - msg (D_HANDSHAKE, "%s: Cipher '%s' initialized with %d bit key", - prefix, - translate_cipher_name_to_openvpn(cipher_kt_name(kt->cipher)), - kt->cipher_length *8); - - dmsg (D_SHOW_KEYS, "%s: CIPHER KEY: %s", prefix, - format_hex (key->cipher, kt->cipher_length, 0, &gc)); - dmsg (D_CRYPTO_DEBUG, "%s: CIPHER block_size=%d iv_size=%d", - prefix, cipher_kt_block_size(kt->cipher), - cipher_kt_iv_size(kt->cipher)); - if (cipher_kt_block_size(kt->cipher) < 128/8) - { - msg (M_WARN, "WARNING: INSECURE cipher with block size less than 128" - " bit (%d bit). This allows attacks like SWEET32. Mitigate by " - "using a --cipher with a larger block size (e.g. AES-256-CBC).", - cipher_kt_block_size(kt->cipher)*8); - } + ALLOC_OBJ(ctx->cipher, cipher_ctx_t); + cipher_ctx_init(ctx->cipher, key->cipher, kt->cipher_length, + kt->cipher, enc); + + msg(D_HANDSHAKE, "%s: Cipher '%s' initialized with %d bit key", + prefix, + translate_cipher_name_to_openvpn(cipher_kt_name(kt->cipher)), + kt->cipher_length *8); + + dmsg(D_SHOW_KEYS, "%s: CIPHER KEY: %s", prefix, + format_hex(key->cipher, kt->cipher_length, 0, &gc)); + dmsg(D_CRYPTO_DEBUG, "%s: CIPHER block_size=%d iv_size=%d", + prefix, cipher_kt_block_size(kt->cipher), + cipher_kt_iv_size(kt->cipher)); + if (cipher_kt_block_size(kt->cipher) < 128/8) + { + msg(M_WARN, "WARNING: INSECURE cipher with block size less than 128" + " bit (%d bit). This allows attacks like SWEET32. Mitigate by " + "using a --cipher with a larger block size (e.g. AES-256-CBC).", + cipher_kt_block_size(kt->cipher)*8); + } } - if (kt->digest && kt->hmac_length > 0) + if (kt->digest && kt->hmac_length > 0) { - ALLOC_OBJ(ctx->hmac, hmac_ctx_t); - hmac_ctx_init (ctx->hmac, key->hmac, kt->hmac_length, kt->digest); + ALLOC_OBJ(ctx->hmac, hmac_ctx_t); + hmac_ctx_init(ctx->hmac, key->hmac, kt->hmac_length, kt->digest); - msg (D_HANDSHAKE, - "%s: Using %d bit message hash '%s' for HMAC authentication", - prefix, md_kt_size(kt->digest) * 8, md_kt_name(kt->digest)); + msg(D_HANDSHAKE, + "%s: Using %d bit message hash '%s' for HMAC authentication", + prefix, md_kt_size(kt->digest) * 8, md_kt_name(kt->digest)); - dmsg (D_SHOW_KEYS, "%s: HMAC KEY: %s", prefix, - format_hex (key->hmac, kt->hmac_length, 0, &gc)); + dmsg(D_SHOW_KEYS, "%s: HMAC KEY: %s", prefix, + format_hex(key->hmac, kt->hmac_length, 0, &gc)); - dmsg (D_CRYPTO_DEBUG, "%s: HMAC size=%d block_size=%d", - prefix, - md_kt_size(kt->digest), - hmac_ctx_size(ctx->hmac)); + dmsg(D_CRYPTO_DEBUG, "%s: HMAC size=%d block_size=%d", + prefix, + md_kt_size(kt->digest), + hmac_ctx_size(ctx->hmac)); } - gc_free (&gc); + gc_free(&gc); } void -free_key_ctx (struct key_ctx *ctx) +free_key_ctx(struct key_ctx *ctx) { - if (ctx->cipher) + if (ctx->cipher) { - cipher_ctx_cleanup(ctx->cipher); - free(ctx->cipher); - ctx->cipher = NULL; + cipher_ctx_cleanup(ctx->cipher); + free(ctx->cipher); + ctx->cipher = NULL; } - if (ctx->hmac) + if (ctx->hmac) { - hmac_ctx_cleanup(ctx->hmac); - free(ctx->hmac); - ctx->hmac = NULL; + hmac_ctx_cleanup(ctx->hmac); + free(ctx->hmac); + ctx->hmac = NULL; } - ctx->implicit_iv_len = 0; + ctx->implicit_iv_len = 0; } void -free_key_ctx_bi (struct key_ctx_bi *ctx) +free_key_ctx_bi(struct key_ctx_bi *ctx) { - free_key_ctx(&ctx->encrypt); - free_key_ctx(&ctx->decrypt); + free_key_ctx(&ctx->encrypt); + free_key_ctx(&ctx->decrypt); } static bool -key_is_zero (struct key *key, const struct key_type *kt) +key_is_zero(struct key *key, const struct key_type *kt) { - int i; - for (i = 0; i < kt->cipher_length; ++i) - if (key->cipher[i]) - return false; - msg (D_CRYPT_ERRORS, "CRYPTO INFO: WARNING: zero key detected"); - return true; + int i; + for (i = 0; i < kt->cipher_length; ++i) + if (key->cipher[i]) + { + return false; + } + msg(D_CRYPT_ERRORS, "CRYPTO INFO: WARNING: zero key detected"); + return true; } /* * Make sure that cipher key is a valid key for current key_type. */ bool -check_key (struct key *key, const struct key_type *kt) +check_key(struct key *key, const struct key_type *kt) { - if (kt->cipher) - { - /* - * Check for zero key - */ - if (key_is_zero(key, kt)) - return false; - - /* - * Check for weak or semi-weak DES keys. - */ - { - const int ndc = key_des_num_cblocks (kt->cipher); - if (ndc) - return key_des_check (key->cipher, kt->cipher_length, ndc); - else - return true; - } - } - return true; + if (kt->cipher) + { + /* + * Check for zero key + */ + if (key_is_zero(key, kt)) + { + return false; + } + + /* + * Check for weak or semi-weak DES keys. + */ + { + const int ndc = key_des_num_cblocks(kt->cipher); + if (ndc) + { + return key_des_check(key->cipher, kt->cipher_length, ndc); + } + else + { + return true; + } + } + } + return true; } /* @@ -899,43 +962,49 @@ check_key (struct key *key, const struct key_type *kt) * This routine cannot guarantee it will generate a good * key. You must always call check_key after this routine * to make sure. - */ + */ void -fixup_key (struct key *key, const struct key_type *kt) +fixup_key(struct key *key, const struct key_type *kt) { - struct gc_arena gc = gc_new (); - if (kt->cipher) + struct gc_arena gc = gc_new(); + if (kt->cipher) { #ifdef ENABLE_DEBUG - const struct key orig = *key; + const struct key orig = *key; #endif - const int ndc = key_des_num_cblocks (kt->cipher); + const int ndc = key_des_num_cblocks(kt->cipher); - if (ndc) - key_des_fixup (key->cipher, kt->cipher_length, ndc); + if (ndc) + { + key_des_fixup(key->cipher, kt->cipher_length, ndc); + } #ifdef ENABLE_DEBUG - if (check_debug_level (D_CRYPTO_DEBUG)) - { - if (memcmp (orig.cipher, key->cipher, kt->cipher_length)) - dmsg (D_CRYPTO_DEBUG, "CRYPTO INFO: fixup_key: before=%s after=%s", - format_hex (orig.cipher, kt->cipher_length, 0, &gc), - format_hex (key->cipher, kt->cipher_length, 0, &gc)); - } + if (check_debug_level(D_CRYPTO_DEBUG)) + { + if (memcmp(orig.cipher, key->cipher, kt->cipher_length)) + { + dmsg(D_CRYPTO_DEBUG, "CRYPTO INFO: fixup_key: before=%s after=%s", + format_hex(orig.cipher, kt->cipher_length, 0, &gc), + format_hex(key->cipher, kt->cipher_length, 0, &gc)); + } + } #endif } - gc_free (&gc); + gc_free(&gc); } void -check_replay_iv_consistency (const struct key_type *kt, bool packet_id, bool use_iv) +check_replay_iv_consistency(const struct key_type *kt, bool packet_id, bool use_iv) { - ASSERT(kt); + ASSERT(kt); - if (!(packet_id && use_iv) && (cipher_kt_mode_ofb_cfb(kt->cipher) || - cipher_kt_mode_aead(kt->cipher))) - msg (M_FATAL, "--no-replay or --no-iv cannot be used with a CFB, OFB or " - "AEAD mode cipher"); + if (!(packet_id && use_iv) && (cipher_kt_mode_ofb_cfb(kt->cipher) + || cipher_kt_mode_aead(kt->cipher))) + { + msg(M_FATAL, "--no-replay or --no-iv cannot be used with a CFB, OFB or " + "AEAD mode cipher"); + } } /* @@ -943,187 +1012,199 @@ check_replay_iv_consistency (const struct key_type *kt, bool packet_id, bool use * sure generated key is valid for key_type. */ void -generate_key_random (struct key *key, const struct key_type *kt) +generate_key_random(struct key *key, const struct key_type *kt) { - int cipher_len = MAX_CIPHER_KEY_LENGTH; - int hmac_len = MAX_HMAC_KEY_LENGTH; - - struct gc_arena gc = gc_new (); - - do { - CLEAR (*key); - if (kt) - { - if (kt->cipher && kt->cipher_length > 0 && kt->cipher_length <= cipher_len) - cipher_len = kt->cipher_length; - - if (kt->digest && kt->hmac_length > 0 && kt->hmac_length <= hmac_len) - hmac_len = kt->hmac_length; - } - if (!rand_bytes (key->cipher, cipher_len) - || !rand_bytes (key->hmac, hmac_len)) - msg (M_FATAL, "ERROR: Random number generator cannot obtain entropy for key generation"); + int cipher_len = MAX_CIPHER_KEY_LENGTH; + int hmac_len = MAX_HMAC_KEY_LENGTH; - dmsg (D_SHOW_KEY_SOURCE, "Cipher source entropy: %s", format_hex (key->cipher, cipher_len, 0, &gc)); - dmsg (D_SHOW_KEY_SOURCE, "HMAC source entropy: %s", format_hex (key->hmac, hmac_len, 0, &gc)); + struct gc_arena gc = gc_new(); - if (kt) - fixup_key (key, kt); - } while (kt && !check_key (key, kt)); + do { + CLEAR(*key); + if (kt) + { + if (kt->cipher && kt->cipher_length > 0 && kt->cipher_length <= cipher_len) + { + cipher_len = kt->cipher_length; + } - gc_free (&gc); + if (kt->digest && kt->hmac_length > 0 && kt->hmac_length <= hmac_len) + { + hmac_len = kt->hmac_length; + } + } + if (!rand_bytes(key->cipher, cipher_len) + || !rand_bytes(key->hmac, hmac_len)) + { + msg(M_FATAL, "ERROR: Random number generator cannot obtain entropy for key generation"); + } + + dmsg(D_SHOW_KEY_SOURCE, "Cipher source entropy: %s", format_hex(key->cipher, cipher_len, 0, &gc)); + dmsg(D_SHOW_KEY_SOURCE, "HMAC source entropy: %s", format_hex(key->hmac, hmac_len, 0, &gc)); + + if (kt) + { + fixup_key(key, kt); + } + } while (kt && !check_key(key, kt)); + + gc_free(&gc); } /* * Print key material */ void -key2_print (const struct key2* k, - const struct key_type *kt, - const char* prefix0, - const char* prefix1) +key2_print(const struct key2 *k, + const struct key_type *kt, + const char *prefix0, + const char *prefix1) { - struct gc_arena gc = gc_new (); - ASSERT (k->n == 2); - dmsg (D_SHOW_KEY_SOURCE, "%s (cipher): %s", - prefix0, - format_hex (k->keys[0].cipher, kt->cipher_length, 0, &gc)); - dmsg (D_SHOW_KEY_SOURCE, "%s (hmac): %s", - prefix0, - format_hex (k->keys[0].hmac, kt->hmac_length, 0, &gc)); - dmsg (D_SHOW_KEY_SOURCE, "%s (cipher): %s", - prefix1, - format_hex (k->keys[1].cipher, kt->cipher_length, 0, &gc)); - dmsg (D_SHOW_KEY_SOURCE, "%s (hmac): %s", - prefix1, - format_hex (k->keys[1].hmac, kt->hmac_length, 0, &gc)); - gc_free (&gc); + struct gc_arena gc = gc_new(); + ASSERT(k->n == 2); + dmsg(D_SHOW_KEY_SOURCE, "%s (cipher): %s", + prefix0, + format_hex(k->keys[0].cipher, kt->cipher_length, 0, &gc)); + dmsg(D_SHOW_KEY_SOURCE, "%s (hmac): %s", + prefix0, + format_hex(k->keys[0].hmac, kt->hmac_length, 0, &gc)); + dmsg(D_SHOW_KEY_SOURCE, "%s (cipher): %s", + prefix1, + format_hex(k->keys[1].cipher, kt->cipher_length, 0, &gc)); + dmsg(D_SHOW_KEY_SOURCE, "%s (hmac): %s", + prefix1, + format_hex(k->keys[1].hmac, kt->hmac_length, 0, &gc)); + gc_free(&gc); } void -test_crypto (struct crypto_options *co, struct frame* frame) +test_crypto(struct crypto_options *co, struct frame *frame) { - int i, j; - struct gc_arena gc = gc_new (); - struct buffer src = alloc_buf_gc (TUN_MTU_SIZE (frame), &gc); - struct buffer work = alloc_buf_gc (BUF_SIZE (frame), &gc); - struct buffer encrypt_workspace = alloc_buf_gc (BUF_SIZE (frame), &gc); - struct buffer decrypt_workspace = alloc_buf_gc (BUF_SIZE (frame), &gc); - struct buffer buf = clear_buf(); - void *buf_p; - - /* init work */ - ASSERT (buf_init (&work, FRAME_HEADROOM (frame))); + int i, j; + struct gc_arena gc = gc_new(); + struct buffer src = alloc_buf_gc(TUN_MTU_SIZE(frame), &gc); + struct buffer work = alloc_buf_gc(BUF_SIZE(frame), &gc); + struct buffer encrypt_workspace = alloc_buf_gc(BUF_SIZE(frame), &gc); + struct buffer decrypt_workspace = alloc_buf_gc(BUF_SIZE(frame), &gc); + struct buffer buf = clear_buf(); + void *buf_p; + + /* init work */ + ASSERT(buf_init(&work, FRAME_HEADROOM(frame))); #ifdef HAVE_AEAD_CIPHER_MODES - /* init implicit IV */ - { - const cipher_kt_t *cipher = - cipher_ctx_get_cipher_kt(co->key_ctx_bi.encrypt.cipher); - - if (cipher_kt_mode_aead(cipher)) - { - size_t impl_iv_len = cipher_kt_iv_size(cipher) - sizeof(packet_id_type); - ASSERT (cipher_kt_iv_size(cipher) <= OPENVPN_MAX_IV_LENGTH); - ASSERT (cipher_kt_iv_size(cipher) >= OPENVPN_AEAD_MIN_IV_LEN); - - /* Generate dummy implicit IV */ - ASSERT (rand_bytes(co->key_ctx_bi.encrypt.implicit_iv, - OPENVPN_MAX_IV_LENGTH)); - co->key_ctx_bi.encrypt.implicit_iv_len = impl_iv_len; - - memcpy(co->key_ctx_bi.decrypt.implicit_iv, - co->key_ctx_bi.encrypt.implicit_iv, OPENVPN_MAX_IV_LENGTH); - co->key_ctx_bi.decrypt.implicit_iv_len = impl_iv_len; - } - } -#endif + /* init implicit IV */ + { + const cipher_kt_t *cipher = + cipher_ctx_get_cipher_kt(co->key_ctx_bi.encrypt.cipher); + + if (cipher_kt_mode_aead(cipher)) + { + size_t impl_iv_len = cipher_kt_iv_size(cipher) - sizeof(packet_id_type); + ASSERT(cipher_kt_iv_size(cipher) <= OPENVPN_MAX_IV_LENGTH); + ASSERT(cipher_kt_iv_size(cipher) >= OPENVPN_AEAD_MIN_IV_LEN); + + /* Generate dummy implicit IV */ + ASSERT(rand_bytes(co->key_ctx_bi.encrypt.implicit_iv, + OPENVPN_MAX_IV_LENGTH)); + co->key_ctx_bi.encrypt.implicit_iv_len = impl_iv_len; + + memcpy(co->key_ctx_bi.decrypt.implicit_iv, + co->key_ctx_bi.encrypt.implicit_iv, OPENVPN_MAX_IV_LENGTH); + co->key_ctx_bi.decrypt.implicit_iv_len = impl_iv_len; + } + } +#endif /* ifdef HAVE_AEAD_CIPHER_MODES */ - msg (M_INFO, "Entering " PACKAGE_NAME " crypto self-test mode."); - for (i = 1; i <= TUN_MTU_SIZE (frame); ++i) - { - update_time (); - - msg (M_INFO, "TESTING ENCRYPT/DECRYPT of packet length=%d", i); - - /* - * Load src with random data. - */ - ASSERT (buf_init (&src, 0)); - ASSERT (i <= src.capacity); - src.len = i; - ASSERT (rand_bytes (BPTR (&src), BLEN (&src))); - - /* copy source to input buf */ - buf = work; - buf_p = buf_write_alloc (&buf, BLEN (&src)); - ASSERT(buf_p); - memcpy (buf_p, BPTR (&src), BLEN (&src)); - - /* initialize work buffer with FRAME_HEADROOM bytes of prepend capacity */ - ASSERT (buf_init (&encrypt_workspace, FRAME_HEADROOM (frame))); - - /* encrypt */ - openvpn_encrypt (&buf, encrypt_workspace, co); - - /* decrypt */ - openvpn_decrypt (&buf, decrypt_workspace, co, frame, BPTR (&buf)); - - /* compare */ - if (buf.len != src.len) - msg (M_FATAL, "SELF TEST FAILED, src.len=%d buf.len=%d", src.len, buf.len); - for (j = 0; j < i; ++j) - { - const uint8_t in = *(BPTR (&src) + j); - const uint8_t out = *(BPTR (&buf) + j); - if (in != out) - msg (M_FATAL, "SELF TEST FAILED, pos=%d in=%d out=%d", j, in, out); - } - } - msg (M_INFO, PACKAGE_NAME " crypto self-test mode SUCCEEDED."); - gc_free (&gc); + msg(M_INFO, "Entering " PACKAGE_NAME " crypto self-test mode."); + for (i = 1; i <= TUN_MTU_SIZE(frame); ++i) + { + update_time(); + + msg(M_INFO, "TESTING ENCRYPT/DECRYPT of packet length=%d", i); + + /* + * Load src with random data. + */ + ASSERT(buf_init(&src, 0)); + ASSERT(i <= src.capacity); + src.len = i; + ASSERT(rand_bytes(BPTR(&src), BLEN(&src))); + + /* copy source to input buf */ + buf = work; + buf_p = buf_write_alloc(&buf, BLEN(&src)); + ASSERT(buf_p); + memcpy(buf_p, BPTR(&src), BLEN(&src)); + + /* initialize work buffer with FRAME_HEADROOM bytes of prepend capacity */ + ASSERT(buf_init(&encrypt_workspace, FRAME_HEADROOM(frame))); + + /* encrypt */ + openvpn_encrypt(&buf, encrypt_workspace, co); + + /* decrypt */ + openvpn_decrypt(&buf, decrypt_workspace, co, frame, BPTR(&buf)); + + /* compare */ + if (buf.len != src.len) + { + msg(M_FATAL, "SELF TEST FAILED, src.len=%d buf.len=%d", src.len, buf.len); + } + for (j = 0; j < i; ++j) + { + const uint8_t in = *(BPTR(&src) + j); + const uint8_t out = *(BPTR(&buf) + j); + if (in != out) + { + msg(M_FATAL, "SELF TEST FAILED, pos=%d in=%d out=%d", j, in, out); + } + } + } + msg(M_INFO, PACKAGE_NAME " crypto self-test mode SUCCEEDED."); + gc_free(&gc); } void -crypto_read_openvpn_key (const struct key_type *key_type, - struct key_ctx_bi *ctx, const char *key_file, const char *key_inline, - const int key_direction, const char *key_name, const char *opt_name) +crypto_read_openvpn_key(const struct key_type *key_type, + struct key_ctx_bi *ctx, const char *key_file, const char *key_inline, + const int key_direction, const char *key_name, const char *opt_name) { - struct key2 key2; - struct key_direction_state kds; - char log_prefix[128] = { 0 }; + struct key2 key2; + struct key_direction_state kds; + char log_prefix[128] = { 0 }; - if (key_inline) + if (key_inline) { - read_key_file (&key2, key_inline, RKF_MUST_SUCCEED|RKF_INLINE); + read_key_file(&key2, key_inline, RKF_MUST_SUCCEED|RKF_INLINE); } - else + else { - read_key_file (&key2, key_file, RKF_MUST_SUCCEED); + read_key_file(&key2, key_file, RKF_MUST_SUCCEED); } - if (key2.n != 2) + if (key2.n != 2) { - msg (M_ERR, "File '%s' does not have OpenVPN Static Key format. Using " - "free-form passphrase file is not supported anymore.", key_file); + msg(M_ERR, "File '%s' does not have OpenVPN Static Key format. Using " + "free-form passphrase file is not supported anymore.", key_file); } - /* check for and fix highly unlikely key problems */ - verify_fix_key2 (&key2, key_type, key_file); + /* check for and fix highly unlikely key problems */ + verify_fix_key2(&key2, key_type, key_file); - /* handle key direction */ - key_direction_state_init (&kds, key_direction); - must_have_n_keys (key_file, opt_name, &key2, kds.need_keys); + /* handle key direction */ + key_direction_state_init(&kds, key_direction); + must_have_n_keys(key_file, opt_name, &key2, kds.need_keys); - /* initialize key in both directions */ - openvpn_snprintf (log_prefix, sizeof (log_prefix), "Outgoing %s", key_name); - init_key_ctx (&ctx->encrypt, &key2.keys[kds.out_key], key_type, - OPENVPN_OP_ENCRYPT, log_prefix); - openvpn_snprintf (log_prefix, sizeof (log_prefix), "Incoming %s", key_name); - init_key_ctx (&ctx->decrypt, &key2.keys[kds.in_key], key_type, - OPENVPN_OP_DECRYPT, log_prefix); + /* initialize key in both directions */ + openvpn_snprintf(log_prefix, sizeof(log_prefix), "Outgoing %s", key_name); + init_key_ctx(&ctx->encrypt, &key2.keys[kds.out_key], key_type, + OPENVPN_OP_ENCRYPT, log_prefix); + openvpn_snprintf(log_prefix, sizeof(log_prefix), "Incoming %s", key_name); + init_key_ctx(&ctx->decrypt, &key2.keys[kds.in_key], key_type, + OPENVPN_OP_DECRYPT, log_prefix); - secure_memzero (&key2, sizeof (key2)); + secure_memzero(&key2, sizeof(key2)); } /* header and footer for static key file */ @@ -1131,198 +1212,221 @@ static const char static_key_head[] = "-----BEGIN OpenVPN Static key V1-----"; static const char static_key_foot[] = "-----END OpenVPN Static key V1-----"; static const char printable_char_fmt[] = - "Non-Hex character ('%c') found at line %d in key file '%s' (%d/%d/%d bytes found/min/max)"; + "Non-Hex character ('%c') found at line %d in key file '%s' (%d/%d/%d bytes found/min/max)"; static const char unprintable_char_fmt[] = - "Non-Hex, unprintable character (0x%02x) found at line %d in key file '%s' (%d/%d/%d bytes found/min/max)"; + "Non-Hex, unprintable character (0x%02x) found at line %d in key file '%s' (%d/%d/%d bytes found/min/max)"; /* read key from file */ void -read_key_file (struct key2 *key2, const char *file, const unsigned int flags) +read_key_file(struct key2 *key2, const char *file, const unsigned int flags) { - struct gc_arena gc = gc_new (); - struct buffer in; - int fd, size; - uint8_t hex_byte[3] = {0, 0, 0}; - const char *error_filename = file; - - /* parse info */ - const unsigned char *cp; - int hb_index = 0; - int line_num = 1; - int line_index = 0; - int match = 0; - - /* output */ - uint8_t* out = (uint8_t*) &key2->keys; - const int keylen = sizeof (key2->keys); - int count = 0; - - /* parse states */ -# define PARSE_INITIAL 0 -# define PARSE_HEAD 1 -# define PARSE_DATA 2 -# define PARSE_DATA_COMPLETE 3 -# define PARSE_FOOT 4 -# define PARSE_FINISHED 5 - int state = PARSE_INITIAL; - - /* constants */ - const int hlen = strlen (static_key_head); - const int flen = strlen (static_key_foot); - const int onekeylen = sizeof (key2->keys[0]); - - CLEAR (*key2); - - /* - * Key can be provided as a filename in 'file' or if RKF_INLINE - * is set, the actual key data itself in ascii form. - */ - if (flags & RKF_INLINE) /* 'file' is a string containing ascii representation of key */ - { - size = strlen (file) + 1; - buf_set_read (&in, (const uint8_t *)file, size); - error_filename = INLINE_FILE_TAG; - } - else /* 'file' is a filename which refers to a file containing the ascii key */ - { - in = alloc_buf_gc (2048, &gc); - fd = platform_open (file, O_RDONLY, 0); - if (fd == -1) - msg (M_ERR, "Cannot open file key file '%s'", file); - size = read (fd, in.data, in.capacity); - if (size < 0) - msg (M_FATAL, "Read error on key file ('%s')", file); - if (size == in.capacity) - msg (M_FATAL, "Key file ('%s') can be a maximum of %d bytes", file, (int)in.capacity); - close (fd); - } - - cp = (unsigned char *)in.data; - while (size > 0) - { - const unsigned char c = *cp; + struct gc_arena gc = gc_new(); + struct buffer in; + int fd, size; + uint8_t hex_byte[3] = {0, 0, 0}; + const char *error_filename = file; + + /* parse info */ + const unsigned char *cp; + int hb_index = 0; + int line_num = 1; + int line_index = 0; + int match = 0; + + /* output */ + uint8_t *out = (uint8_t *) &key2->keys; + const int keylen = sizeof(key2->keys); + int count = 0; + + /* parse states */ +#define PARSE_INITIAL 0 +#define PARSE_HEAD 1 +#define PARSE_DATA 2 +#define PARSE_DATA_COMPLETE 3 +#define PARSE_FOOT 4 +#define PARSE_FINISHED 5 + int state = PARSE_INITIAL; + + /* constants */ + const int hlen = strlen(static_key_head); + const int flen = strlen(static_key_foot); + const int onekeylen = sizeof(key2->keys[0]); + + CLEAR(*key2); + + /* + * Key can be provided as a filename in 'file' or if RKF_INLINE + * is set, the actual key data itself in ascii form. + */ + if (flags & RKF_INLINE) /* 'file' is a string containing ascii representation of key */ + { + size = strlen(file) + 1; + buf_set_read(&in, (const uint8_t *)file, size); + error_filename = INLINE_FILE_TAG; + } + else /* 'file' is a filename which refers to a file containing the ascii key */ + { + in = alloc_buf_gc(2048, &gc); + fd = platform_open(file, O_RDONLY, 0); + if (fd == -1) + { + msg(M_ERR, "Cannot open file key file '%s'", file); + } + size = read(fd, in.data, in.capacity); + if (size < 0) + { + msg(M_FATAL, "Read error on key file ('%s')", file); + } + if (size == in.capacity) + { + msg(M_FATAL, "Key file ('%s') can be a maximum of %d bytes", file, (int)in.capacity); + } + close(fd); + } + + cp = (unsigned char *)in.data; + while (size > 0) + { + const unsigned char c = *cp; #if 0 - msg (M_INFO, "char='%c'[%d] s=%d ln=%d li=%d m=%d c=%d", - c, (int)c, state, line_num, line_index, match, count); + msg(M_INFO, "char='%c'[%d] s=%d ln=%d li=%d m=%d c=%d", + c, (int)c, state, line_num, line_index, match, count); #endif - if (c == '\n') - { - line_index = match = 0; - ++line_num; - } - else - { - /* first char of new line */ - if (!line_index) - { - /* first char of line after header line? */ - if (state == PARSE_HEAD) - state = PARSE_DATA; - - /* first char of footer */ - if ((state == PARSE_DATA || state == PARSE_DATA_COMPLETE) && c == '-') - state = PARSE_FOOT; - } - - /* compare read chars with header line */ - if (state == PARSE_INITIAL) - { - if (line_index < hlen && c == static_key_head[line_index]) - { - if (++match == hlen) - state = PARSE_HEAD; - } - } - - /* compare read chars with footer line */ - if (state == PARSE_FOOT) - { - if (line_index < flen && c == static_key_foot[line_index]) - { - if (++match == flen) - state = PARSE_FINISHED; - } - } - - /* reading key */ - if (state == PARSE_DATA) - { - if (isxdigit(c)) - { - ASSERT (hb_index >= 0 && hb_index < 2); - hex_byte[hb_index++] = c; - if (hb_index == 2) - { - unsigned int u; - ASSERT(sscanf((const char *)hex_byte, "%x", &u) == 1); - *out++ = u; - hb_index = 0; - if (++count == keylen) - state = PARSE_DATA_COMPLETE; - } - } - else if (isspace(c)) - ; - else - { - msg (M_FATAL, - (isprint (c) ? printable_char_fmt : unprintable_char_fmt), - c, line_num, error_filename, count, onekeylen, keylen); - } - } - ++line_index; - } - ++cp; - --size; - } - - /* - * Normally we will read either 1 or 2 keys from file. - */ - key2->n = count / onekeylen; - - ASSERT (key2->n >= 0 && key2->n <= (int) SIZE (key2->keys)); - - if (flags & RKF_MUST_SUCCEED) - { - if (!key2->n) - msg (M_FATAL, "Insufficient key material or header text not found in file '%s' (%d/%d/%d bytes found/min/max)", - error_filename, count, onekeylen, keylen); - - if (state != PARSE_FINISHED) - msg (M_FATAL, "Footer text not found in file '%s' (%d/%d/%d bytes found/min/max)", - error_filename, count, onekeylen, keylen); - } - - /* zero file read buffer if not an inline file */ - if (!(flags & RKF_INLINE)) - buf_clear (&in); + if (c == '\n') + { + line_index = match = 0; + ++line_num; + } + else + { + /* first char of new line */ + if (!line_index) + { + /* first char of line after header line? */ + if (state == PARSE_HEAD) + { + state = PARSE_DATA; + } + + /* first char of footer */ + if ((state == PARSE_DATA || state == PARSE_DATA_COMPLETE) && c == '-') + { + state = PARSE_FOOT; + } + } + + /* compare read chars with header line */ + if (state == PARSE_INITIAL) + { + if (line_index < hlen && c == static_key_head[line_index]) + { + if (++match == hlen) + { + state = PARSE_HEAD; + } + } + } + + /* compare read chars with footer line */ + if (state == PARSE_FOOT) + { + if (line_index < flen && c == static_key_foot[line_index]) + { + if (++match == flen) + { + state = PARSE_FINISHED; + } + } + } + + /* reading key */ + if (state == PARSE_DATA) + { + if (isxdigit(c)) + { + ASSERT(hb_index >= 0 && hb_index < 2); + hex_byte[hb_index++] = c; + if (hb_index == 2) + { + unsigned int u; + ASSERT(sscanf((const char *)hex_byte, "%x", &u) == 1); + *out++ = u; + hb_index = 0; + if (++count == keylen) + { + state = PARSE_DATA_COMPLETE; + } + } + } + else if (isspace(c)) + { + } + else + { + msg(M_FATAL, + (isprint(c) ? printable_char_fmt : unprintable_char_fmt), + c, line_num, error_filename, count, onekeylen, keylen); + } + } + ++line_index; + } + ++cp; + --size; + } + + /* + * Normally we will read either 1 or 2 keys from file. + */ + key2->n = count / onekeylen; + + ASSERT(key2->n >= 0 && key2->n <= (int) SIZE(key2->keys)); + + if (flags & RKF_MUST_SUCCEED) + { + if (!key2->n) + { + msg(M_FATAL, "Insufficient key material or header text not found in file '%s' (%d/%d/%d bytes found/min/max)", + error_filename, count, onekeylen, keylen); + } + + if (state != PARSE_FINISHED) + { + msg(M_FATAL, "Footer text not found in file '%s' (%d/%d/%d bytes found/min/max)", + error_filename, count, onekeylen, keylen); + } + } + + /* zero file read buffer if not an inline file */ + if (!(flags & RKF_INLINE)) + { + buf_clear(&in); + } #if 0 - /* DEBUGGING */ - { - int i; - printf ("KEY READ, n=%d\n", key2->n); - for (i = 0; i < (int) SIZE (key2->keys); ++i) - { - /* format key as ascii */ - const char *fmt = format_hex_ex ((const uint8_t*)&key2->keys[i], - sizeof (key2->keys[i]), - 0, - 16, - "\n", - &gc); - printf ("[%d]\n%s\n\n", i, fmt); - } - } + /* DEBUGGING */ + { + int i; + printf("KEY READ, n=%d\n", key2->n); + for (i = 0; i < (int) SIZE(key2->keys); ++i) + { + /* format key as ascii */ + const char *fmt = format_hex_ex((const uint8_t *)&key2->keys[i], + sizeof(key2->keys[i]), + 0, + 16, + "\n", + &gc); + printf("[%d]\n%s\n\n", i, fmt); + } + } #endif - /* pop our garbage collection level */ - gc_free (&gc); + /* pop our garbage collection level */ + gc_free(&gc); } /* @@ -1330,222 +1434,261 @@ read_key_file (struct key2 *key2, const char *file, const unsigned int flags) * written. */ int -write_key_file (const int nkeys, const char *filename) +write_key_file(const int nkeys, const char *filename) { - struct gc_arena gc = gc_new (); + struct gc_arena gc = gc_new(); - int fd, i; - int nbits = 0; + int fd, i; + int nbits = 0; - /* must be large enough to hold full key file */ - struct buffer out = alloc_buf_gc (2048, &gc); - struct buffer nbits_head_text = alloc_buf_gc (128, &gc); + /* must be large enough to hold full key file */ + struct buffer out = alloc_buf_gc(2048, &gc); + struct buffer nbits_head_text = alloc_buf_gc(128, &gc); - /* how to format the ascii file representation of key */ - const int bytes_per_line = 16; + /* how to format the ascii file representation of key */ + const int bytes_per_line = 16; - /* open key file */ - fd = platform_open (filename, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR); + /* open key file */ + fd = platform_open(filename, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR); - if (fd == -1) - msg (M_ERR, "Cannot open shared secret file '%s' for write", filename); + if (fd == -1) + { + msg(M_ERR, "Cannot open shared secret file '%s' for write", filename); + } - buf_printf (&out, "%s\n", static_key_head); + buf_printf(&out, "%s\n", static_key_head); - for (i = 0; i < nkeys; ++i) + for (i = 0; i < nkeys; ++i) { - struct key key; - char* fmt; + struct key key; + char *fmt; - /* generate random bits */ - generate_key_random (&key, NULL); + /* generate random bits */ + generate_key_random(&key, NULL); - /* format key as ascii */ - fmt = format_hex_ex ((const uint8_t*)&key, - sizeof (key), - 0, - bytes_per_line, - "\n", - &gc); + /* format key as ascii */ + fmt = format_hex_ex((const uint8_t *)&key, + sizeof(key), + 0, + bytes_per_line, + "\n", + &gc); - /* increment random bits counter */ - nbits += sizeof (key) * 8; + /* increment random bits counter */ + nbits += sizeof(key) * 8; - /* write to holding buffer */ - buf_printf (&out, "%s\n", fmt); + /* write to holding buffer */ + buf_printf(&out, "%s\n", fmt); - /* zero memory which held key component (will be freed by GC) */ - secure_memzero (fmt, strlen (fmt)); - secure_memzero (&key, sizeof (key)); + /* zero memory which held key component (will be freed by GC) */ + secure_memzero(fmt, strlen(fmt)); + secure_memzero(&key, sizeof(key)); } - buf_printf (&out, "%s\n", static_key_foot); + buf_printf(&out, "%s\n", static_key_foot); - /* write number of bits */ - buf_printf (&nbits_head_text, "#\n# %d bit OpenVPN static key\n#\n", nbits); - buf_write_string_file (&nbits_head_text, filename, fd); + /* write number of bits */ + buf_printf(&nbits_head_text, "#\n# %d bit OpenVPN static key\n#\n", nbits); + buf_write_string_file(&nbits_head_text, filename, fd); - /* write key file, now formatted in out, to file */ - buf_write_string_file (&out, filename, fd); + /* write key file, now formatted in out, to file */ + buf_write_string_file(&out, filename, fd); - if (close (fd)) - msg (M_ERR, "Close error on shared secret file %s", filename); + if (close(fd)) + { + msg(M_ERR, "Close error on shared secret file %s", filename); + } - /* zero memory which held file content (memory will be freed by GC) */ - buf_clear (&out); + /* zero memory which held file content (memory will be freed by GC) */ + buf_clear(&out); - /* pop our garbage collection level */ - gc_free (&gc); + /* pop our garbage collection level */ + gc_free(&gc); - return nbits; + return nbits; } void -must_have_n_keys (const char *filename, const char *option, const struct key2 *key2, int n) +must_have_n_keys(const char *filename, const char *option, const struct key2 *key2, int n) { - if (key2->n < n) + if (key2->n < n) { #ifdef ENABLE_SMALL - msg (M_FATAL, "Key file '%s' used in --%s contains insufficient key material [keys found=%d required=%d]", filename, option, key2->n, n); + msg(M_FATAL, "Key file '%s' used in --%s contains insufficient key material [keys found=%d required=%d]", filename, option, key2->n, n); #else - msg (M_FATAL, "Key file '%s' used in --%s contains insufficient key material [keys found=%d required=%d] -- try generating a new key file with '" PACKAGE " --genkey --secret [file]', or use the existing key file in bidirectional mode by specifying --%s without a key direction parameter", filename, option, key2->n, n, option); + msg(M_FATAL, "Key file '%s' used in --%s contains insufficient key material [keys found=%d required=%d] -- try generating a new key file with '" PACKAGE " --genkey --secret [file]', or use the existing key file in bidirectional mode by specifying --%s without a key direction parameter", filename, option, key2->n, n, option); #endif } } int -ascii2keydirection (int msglevel, const char *str) +ascii2keydirection(int msglevel, const char *str) { - if (!str) - return KEY_DIRECTION_BIDIRECTIONAL; - else if (!strcmp (str, "0")) - return KEY_DIRECTION_NORMAL; - else if (!strcmp (str, "1")) - return KEY_DIRECTION_INVERSE; - else - { - msg (msglevel, "Unknown key direction '%s' -- must be '0' or '1'", str); - return -1; - } - return KEY_DIRECTION_BIDIRECTIONAL; /* NOTREACHED */ + if (!str) + { + return KEY_DIRECTION_BIDIRECTIONAL; + } + else if (!strcmp(str, "0")) + { + return KEY_DIRECTION_NORMAL; + } + else if (!strcmp(str, "1")) + { + return KEY_DIRECTION_INVERSE; + } + else + { + msg(msglevel, "Unknown key direction '%s' -- must be '0' or '1'", str); + return -1; + } + return KEY_DIRECTION_BIDIRECTIONAL; /* NOTREACHED */ } const char * -keydirection2ascii (int kd, bool remote) +keydirection2ascii(int kd, bool remote) { - if (kd == KEY_DIRECTION_BIDIRECTIONAL) - return NULL; - else if (kd == KEY_DIRECTION_NORMAL) - return remote ? "1" : "0"; - else if (kd == KEY_DIRECTION_INVERSE) - return remote ? "0" : "1"; - else + if (kd == KEY_DIRECTION_BIDIRECTIONAL) + { + return NULL; + } + else if (kd == KEY_DIRECTION_NORMAL) + { + return remote ? "1" : "0"; + } + else if (kd == KEY_DIRECTION_INVERSE) + { + return remote ? "0" : "1"; + } + else { - ASSERT (0); + ASSERT(0); } - return NULL; /* NOTREACHED */ + return NULL; /* NOTREACHED */ } void -key_direction_state_init (struct key_direction_state *kds, int key_direction) +key_direction_state_init(struct key_direction_state *kds, int key_direction) { - CLEAR (*kds); - switch (key_direction) - { - case KEY_DIRECTION_NORMAL: - kds->out_key = 0; - kds->in_key = 1; - kds->need_keys = 2; - break; - case KEY_DIRECTION_INVERSE: - kds->out_key = 1; - kds->in_key = 0; - kds->need_keys = 2; - break; - case KEY_DIRECTION_BIDIRECTIONAL: - kds->out_key = 0; - kds->in_key = 0; - kds->need_keys = 1; - break; - default: - ASSERT (0); + CLEAR(*kds); + switch (key_direction) + { + case KEY_DIRECTION_NORMAL: + kds->out_key = 0; + kds->in_key = 1; + kds->need_keys = 2; + break; + + case KEY_DIRECTION_INVERSE: + kds->out_key = 1; + kds->in_key = 0; + kds->need_keys = 2; + break; + + case KEY_DIRECTION_BIDIRECTIONAL: + kds->out_key = 0; + kds->in_key = 0; + kds->need_keys = 1; + break; + + default: + ASSERT(0); } } void -verify_fix_key2 (struct key2 *key2, const struct key_type *kt, const char *shared_secret_file) +verify_fix_key2(struct key2 *key2, const struct key_type *kt, const char *shared_secret_file) { - int i; + int i; - for (i = 0; i < key2->n; ++i) + for (i = 0; i < key2->n; ++i) { - /* Fix parity for DES keys and make sure not a weak key */ - fixup_key (&key2->keys[i], kt); - - /* This should be a very improbable failure */ - if (!check_key (&key2->keys[i], kt)) - msg (M_FATAL, "Key #%d in '%s' is bad. Try making a new key with --genkey.", - i+1, shared_secret_file); + /* Fix parity for DES keys and make sure not a weak key */ + fixup_key(&key2->keys[i], kt); + + /* This should be a very improbable failure */ + if (!check_key(&key2->keys[i], kt)) + { + msg(M_FATAL, "Key #%d in '%s' is bad. Try making a new key with --genkey.", + i+1, shared_secret_file); + } } } /* given a key and key_type, write key to buffer */ bool -write_key (const struct key *key, const struct key_type *kt, - struct buffer *buf) +write_key(const struct key *key, const struct key_type *kt, + struct buffer *buf) { - ASSERT (kt->cipher_length <= MAX_CIPHER_KEY_LENGTH - && kt->hmac_length <= MAX_HMAC_KEY_LENGTH); + ASSERT(kt->cipher_length <= MAX_CIPHER_KEY_LENGTH + && kt->hmac_length <= MAX_HMAC_KEY_LENGTH); - if (!buf_write (buf, &kt->cipher_length, 1)) - return false; - if (!buf_write (buf, &kt->hmac_length, 1)) - return false; - if (!buf_write (buf, key->cipher, kt->cipher_length)) - return false; - if (!buf_write (buf, key->hmac, kt->hmac_length)) - return false; + if (!buf_write(buf, &kt->cipher_length, 1)) + { + return false; + } + if (!buf_write(buf, &kt->hmac_length, 1)) + { + return false; + } + if (!buf_write(buf, key->cipher, kt->cipher_length)) + { + return false; + } + if (!buf_write(buf, key->hmac, kt->hmac_length)) + { + return false; + } - return true; + return true; } /* * Given a key_type and buffer, read key from buffer. * Return: 1 on success * -1 read failure - * 0 on key length mismatch + * 0 on key length mismatch */ int -read_key (struct key *key, const struct key_type *kt, struct buffer *buf) +read_key(struct key *key, const struct key_type *kt, struct buffer *buf) { - uint8_t cipher_length; - uint8_t hmac_length; + uint8_t cipher_length; + uint8_t hmac_length; - CLEAR (*key); - if (!buf_read (buf, &cipher_length, 1)) - goto read_err; - if (!buf_read (buf, &hmac_length, 1)) - goto read_err; + CLEAR(*key); + if (!buf_read(buf, &cipher_length, 1)) + { + goto read_err; + } + if (!buf_read(buf, &hmac_length, 1)) + { + goto read_err; + } - if (!buf_read (buf, key->cipher, cipher_length)) - goto read_err; - if (!buf_read (buf, key->hmac, hmac_length)) - goto read_err; + if (!buf_read(buf, key->cipher, cipher_length)) + { + goto read_err; + } + if (!buf_read(buf, key->hmac, hmac_length)) + { + goto read_err; + } - if (cipher_length != kt->cipher_length || hmac_length != kt->hmac_length) - goto key_len_err; + if (cipher_length != kt->cipher_length || hmac_length != kt->hmac_length) + { + goto key_len_err; + } - return 1; + return 1; read_err: - msg (D_TLS_ERRORS, "TLS Error: error reading key from remote"); - return -1; + msg(D_TLS_ERRORS, "TLS Error: error reading key from remote"); + return -1; key_len_err: - msg (D_TLS_ERRORS, - "TLS Error: key length mismatch, local cipher/hmac %d/%d, remote cipher/hmac %d/%d", - kt->cipher_length, kt->hmac_length, cipher_length, hmac_length); - return 0; + msg(D_TLS_ERRORS, + "TLS Error: key length mismatch, local cipher/hmac %d/%d, remote cipher/hmac %d/%d", + kt->cipher_length, kt->hmac_length, cipher_length, hmac_length); + return 0; } /* @@ -1561,125 +1704,138 @@ static int nonce_secret_len = 0; /* GLOBAL */ /* Reset the nonce value, also done periodically to refresh entropy */ static void -prng_reset_nonce () +prng_reset_nonce() { - const int size = md_kt_size (nonce_md) + nonce_secret_len; + const int size = md_kt_size(nonce_md) + nonce_secret_len; #if 1 /* Must be 1 for real usage */ - if (!rand_bytes (nonce_data, size)) - msg (M_FATAL, "ERROR: Random number generator cannot obtain entropy for PRNG"); + if (!rand_bytes(nonce_data, size)) + { + msg(M_FATAL, "ERROR: Random number generator cannot obtain entropy for PRNG"); + } #else /* Only for testing -- will cause a predictable PRNG sequence */ { - int i; - for (i = 0; i < size; ++i) - nonce_data[i] = (uint8_t) i; + int i; + for (i = 0; i < size; ++i) + nonce_data[i] = (uint8_t) i; } #endif } void -prng_init (const char *md_name, const int nonce_secret_len_parm) +prng_init(const char *md_name, const int nonce_secret_len_parm) { - prng_uninit (); - nonce_md = md_name ? md_kt_get (md_name) : NULL; - if (nonce_md) - { - ASSERT (nonce_secret_len_parm >= NONCE_SECRET_LEN_MIN && nonce_secret_len_parm <= NONCE_SECRET_LEN_MAX); - nonce_secret_len = nonce_secret_len_parm; - { - const int size = md_kt_size(nonce_md) + nonce_secret_len; - dmsg (D_CRYPTO_DEBUG, "PRNG init md=%s size=%d", md_kt_name(nonce_md), size); - nonce_data = (uint8_t*) malloc (size); - check_malloc_return (nonce_data); - prng_reset_nonce(); - } + prng_uninit(); + nonce_md = md_name ? md_kt_get(md_name) : NULL; + if (nonce_md) + { + ASSERT(nonce_secret_len_parm >= NONCE_SECRET_LEN_MIN && nonce_secret_len_parm <= NONCE_SECRET_LEN_MAX); + nonce_secret_len = nonce_secret_len_parm; + { + const int size = md_kt_size(nonce_md) + nonce_secret_len; + dmsg(D_CRYPTO_DEBUG, "PRNG init md=%s size=%d", md_kt_name(nonce_md), size); + nonce_data = (uint8_t *) malloc(size); + check_malloc_return(nonce_data); + prng_reset_nonce(); + } } } void -prng_uninit (void) +prng_uninit(void) { - free (nonce_data); - nonce_data = NULL; - nonce_md = NULL; - nonce_secret_len = 0; + free(nonce_data); + nonce_data = NULL; + nonce_md = NULL; + nonce_secret_len = 0; } void -prng_bytes (uint8_t *output, int len) +prng_bytes(uint8_t *output, int len) { - static size_t processed = 0; - - if (nonce_md) - { - const int md_size = md_kt_size (nonce_md); - while (len > 0) - { - const int blen = min_int (len, md_size); - md_full(nonce_md, nonce_data, md_size + nonce_secret_len, nonce_data); - memcpy (output, nonce_data, blen); - output += blen; - len -= blen; - - /* Ensure that random data is reset regularly */ - processed += blen; - if(processed > PRNG_NONCE_RESET_BYTES) { - prng_reset_nonce(); - processed = 0; - } - } - } - else - ASSERT (rand_bytes (output, len)); + static size_t processed = 0; + + if (nonce_md) + { + const int md_size = md_kt_size(nonce_md); + while (len > 0) + { + const int blen = min_int(len, md_size); + md_full(nonce_md, nonce_data, md_size + nonce_secret_len, nonce_data); + memcpy(output, nonce_data, blen); + output += blen; + len -= blen; + + /* Ensure that random data is reset regularly */ + processed += blen; + if (processed > PRNG_NONCE_RESET_BYTES) + { + prng_reset_nonce(); + processed = 0; + } + } + } + else + { + ASSERT(rand_bytes(output, len)); + } } /* an analogue to the random() function, but use prng_bytes */ long int get_random() { - long int l; - prng_bytes ((unsigned char *)&l, sizeof(l)); - if (l < 0) - l = -l; - return l; + long int l; + prng_bytes((unsigned char *)&l, sizeof(l)); + if (l < 0) + { + l = -l; + } + return l; } static const cipher_name_pair * get_cipher_name_pair(const char *cipher_name) { - const cipher_name_pair *pair; - size_t i = 0; + const cipher_name_pair *pair; + size_t i = 0; - /* Search for a cipher name translation */ - for (; i < cipher_name_translation_table_count; i++) + /* Search for a cipher name translation */ + for (; i < cipher_name_translation_table_count; i++) { - pair = &cipher_name_translation_table[i]; - if (0 == strcmp (cipher_name, pair->openvpn_name) || - 0 == strcmp (cipher_name, pair->lib_name)) - return pair; + pair = &cipher_name_translation_table[i]; + if (0 == strcmp(cipher_name, pair->openvpn_name) + || 0 == strcmp(cipher_name, pair->lib_name)) + { + return pair; + } } - /* Nothing found, return null */ - return NULL; + /* Nothing found, return null */ + return NULL; } const char * -translate_cipher_name_from_openvpn (const char *cipher_name) { - const cipher_name_pair *pair = get_cipher_name_pair(cipher_name); +translate_cipher_name_from_openvpn(const char *cipher_name) { + const cipher_name_pair *pair = get_cipher_name_pair(cipher_name); - if (NULL == pair) - return cipher_name; + if (NULL == pair) + { + return cipher_name; + } - return pair->lib_name; + return pair->lib_name; } const char * -translate_cipher_name_to_openvpn (const char *cipher_name) { - const cipher_name_pair *pair = get_cipher_name_pair(cipher_name); +translate_cipher_name_to_openvpn(const char *cipher_name) { + const cipher_name_pair *pair = get_cipher_name_pair(cipher_name); - if (NULL == pair) - return cipher_name; + if (NULL == pair) + { + return cipher_name; + } - return pair->openvpn_name; + return pair->openvpn_name; } #endif /* ENABLE_CRYPTO */ diff --git a/src/openvpn/crypto.h b/src/openvpn/crypto.h index ff9074579bd..56761baab8c 100644 --- a/src/openvpn/crypto.h +++ b/src/openvpn/crypto.h @@ -134,7 +134,7 @@ /** Wrapper struct to pass around MD5 digests */ struct md5_digest { - uint8_t digest[MD5_DIGEST_LENGTH]; + uint8_t digest[MD5_DIGEST_LENGTH]; }; /* @@ -142,10 +142,10 @@ struct md5_digest { */ struct key_type { - uint8_t cipher_length; /**< Cipher length, in bytes */ - uint8_t hmac_length; /**< HMAC length, in bytes */ - const cipher_kt_t *cipher; /**< Cipher static parameters */ - const md_kt_t *digest; /**< Message digest static parameters */ + uint8_t cipher_length; /**< Cipher length, in bytes */ + uint8_t hmac_length; /**< HMAC length, in bytes */ + const cipher_kt_t *cipher; /**< Cipher static parameters */ + const md_kt_t *digest; /**< Message digest static parameters */ }; /** @@ -154,10 +154,10 @@ struct key_type */ struct key { - uint8_t cipher[MAX_CIPHER_KEY_LENGTH]; - /**< %Key material for cipher operations. */ - uint8_t hmac[MAX_HMAC_KEY_LENGTH]; - /**< %Key material for HMAC operations. */ + uint8_t cipher[MAX_CIPHER_KEY_LENGTH]; + /**< %Key material for cipher operations. */ + uint8_t hmac[MAX_HMAC_KEY_LENGTH]; + /**< %Key material for HMAC operations. */ }; @@ -167,11 +167,11 @@ struct key */ struct key_ctx { - cipher_ctx_t *cipher; /**< Generic cipher %context. */ - hmac_ctx_t *hmac; /**< Generic HMAC %context. */ - uint8_t implicit_iv[OPENVPN_MAX_IV_LENGTH]; - /**< The implicit part of the IV */ - size_t implicit_iv_len; /**< The length of implicit_iv */ + cipher_ctx_t *cipher; /**< Generic cipher %context. */ + hmac_ctx_t *hmac; /**< Generic HMAC %context. */ + uint8_t implicit_iv[OPENVPN_MAX_IV_LENGTH]; + /**< The implicit part of the IV */ + size_t implicit_iv_len; /**< The length of implicit_iv */ }; #define KEY_DIRECTION_BIDIRECTIONAL 0 /* same keys for both directions */ @@ -184,9 +184,9 @@ struct key_ctx */ struct key2 { - int n; /**< The number of \c key objects stored + int n; /**< The number of \c key objects stored * in the \c key2.keys array. */ - struct key keys[2]; /**< Two unidirectional sets of %key + struct key keys[2]; /**< Two unidirectional sets of %key * material. */ }; @@ -201,11 +201,11 @@ struct key2 */ struct key_direction_state { - int out_key; /**< Index into the \c key2.keys array for + int out_key; /**< Index into the \c key2.keys array for * the sending direction. */ - int in_key; /**< Index into the \c key2.keys array for + int in_key; /**< Index into the \c key2.keys array for * the receiving direction. */ - int need_keys; /**< The number of key objects necessary + int need_keys; /**< The number of key objects necessary * to support both sending and * receiving. * @@ -222,11 +222,11 @@ struct key_direction_state */ struct key_ctx_bi { - struct key_ctx encrypt; /**< Cipher and/or HMAC contexts for sending - * direction. */ - struct key_ctx decrypt; /**< cipher and/or HMAC contexts for + struct key_ctx encrypt; /**< Cipher and/or HMAC contexts for sending + * direction. */ + struct key_ctx decrypt; /**< cipher and/or HMAC contexts for * receiving direction. */ - bool initialized; + bool initialized; }; /** @@ -235,69 +235,69 @@ struct key_ctx_bi */ struct crypto_options { - struct key_ctx_bi key_ctx_bi; - /**< OpenSSL cipher and HMAC contexts for - * both sending and receiving - * directions. */ - struct packet_id packet_id; /**< Current packet ID state for both + struct key_ctx_bi key_ctx_bi; + /**< OpenSSL cipher and HMAC contexts for + * both sending and receiving + * directions. */ + struct packet_id packet_id; /**< Current packet ID state for both * sending and receiving directions. */ - struct packet_id_persist *pid_persist; - /**< Persistent packet ID state for - * keeping state between successive - * OpenVPN process startups. */ - -# define CO_PACKET_ID_LONG_FORM (1<<0) - /**< Bit-flag indicating whether to use - * OpenVPN's long packet ID format. */ -# define CO_USE_IV (1<<1) - /**< Bit-flag indicating whether to - * generate a pseudo-random IV for each - * packet being encrypted. */ -# define CO_IGNORE_PACKET_ID (1<<2) - /**< Bit-flag indicating whether to ignore - * the packet ID of a received packet. - * This flag is used during processing - * of the first packet received from a - * client. */ -# define CO_MUTE_REPLAY_WARNINGS (1<<3) - /**< Bit-flag indicating not to display - * replay warnings. */ - unsigned int flags; /**< Bit-flags determining behavior of + struct packet_id_persist *pid_persist; + /**< Persistent packet ID state for + * keeping state between successive + * OpenVPN process startups. */ + +#define CO_PACKET_ID_LONG_FORM (1<<0) + /**< Bit-flag indicating whether to use + * OpenVPN's long packet ID format. */ +#define CO_USE_IV (1<<1) + /**< Bit-flag indicating whether to + * generate a pseudo-random IV for each + * packet being encrypted. */ +#define CO_IGNORE_PACKET_ID (1<<2) + /**< Bit-flag indicating whether to ignore + * the packet ID of a received packet. + * This flag is used during processing + * of the first packet received from a + * client. */ +#define CO_MUTE_REPLAY_WARNINGS (1<<3) + /**< Bit-flag indicating not to display + * replay warnings. */ + unsigned int flags; /**< Bit-flags determining behavior of * security operation functions. */ }; #define CRYPT_ERROR(format) \ - do { msg (D_CRYPT_ERRORS, "%s: " format, error_prefix); goto error_exit; } while (false) + do { msg(D_CRYPT_ERRORS, "%s: " format, error_prefix); goto error_exit; } while (false) /** * Minimal IV length for AEAD mode ciphers (in bytes): * 4-byte packet id + 8 bytes implicit IV. */ -#define OPENVPN_AEAD_MIN_IV_LEN (sizeof (packet_id_type) + 8) +#define OPENVPN_AEAD_MIN_IV_LEN (sizeof(packet_id_type) + 8) #define RKF_MUST_SUCCEED (1<<0) #define RKF_INLINE (1<<1) -void read_key_file (struct key2 *key2, const char *file, const unsigned int flags); +void read_key_file(struct key2 *key2, const char *file, const unsigned int flags); -int write_key_file (const int nkeys, const char *filename); +int write_key_file(const int nkeys, const char *filename); -int read_passphrase_hash (const char *passphrase_file, - const md_kt_t *digest, - uint8_t *output, - int len); +int read_passphrase_hash(const char *passphrase_file, + const md_kt_t *digest, + uint8_t *output, + int len); -void generate_key_random (struct key *key, const struct key_type *kt); +void generate_key_random(struct key *key, const struct key_type *kt); void check_replay_iv_consistency(const struct key_type *kt, bool packet_id, bool use_iv); -bool check_key (struct key *key, const struct key_type *kt); +bool check_key(struct key *key, const struct key_type *kt); -void fixup_key (struct key *key, const struct key_type *kt); +void fixup_key(struct key *key, const struct key_type *kt); -bool write_key (const struct key *key, const struct key_type *kt, - struct buffer *buf); +bool write_key(const struct key *key, const struct key_type *kt, + struct buffer *buf); -int read_key (struct key *key, const struct key_type *kt, struct buffer *buf); +int read_key(struct key *key, const struct key_type *kt, struct buffer *buf); /** * Initialize a key_type structure with. @@ -311,20 +311,20 @@ int read_key (struct key *key, const struct key_type *kt, struct buffer *buf); * more ciphers than static key mode. * @param warn Print warnings when null cipher / auth is used. */ -void init_key_type (struct key_type *kt, const char *ciphername, - const char *authname, int keysize, bool tls_mode, bool warn); +void init_key_type(struct key_type *kt, const char *ciphername, + const char *authname, int keysize, bool tls_mode, bool warn); /* * Key context functions */ -void init_key_ctx (struct key_ctx *ctx, struct key *key, - const struct key_type *kt, int enc, - const char *prefix); +void init_key_ctx(struct key_ctx *ctx, struct key *key, + const struct key_type *kt, int enc, + const char *prefix); -void free_key_ctx (struct key_ctx *ctx); +void free_key_ctx(struct key_ctx *ctx); -void free_key_ctx_bi (struct key_ctx_bi *ctx); +void free_key_ctx_bi(struct key_ctx_bi *ctx); /**************************************************************************/ @@ -357,8 +357,8 @@ void free_key_ctx_bi (struct key_ctx_bi *ctx); * contain the processed packet ready for sending, or be empty if an * error occurred. */ -void openvpn_encrypt (struct buffer *buf, struct buffer work, - struct crypto_options *opt); +void openvpn_encrypt(struct buffer *buf, struct buffer work, + struct crypto_options *opt); /** @@ -394,33 +394,33 @@ void openvpn_encrypt (struct buffer *buf, struct buffer work, * the plaintext packet ready for further processing, or be empty if * an error occurred. */ -bool openvpn_decrypt (struct buffer *buf, struct buffer work, - struct crypto_options *opt, const struct frame* frame, - const uint8_t *ad_start); +bool openvpn_decrypt(struct buffer *buf, struct buffer work, + struct crypto_options *opt, const struct frame *frame, + const uint8_t *ad_start); /** @} name Functions for performing security operations on data channel packets */ /** * Check packet ID for replay, and perform replay administration. * - * @param opt Crypto options for this packet, contains replay state. - * @param pin Packet ID read from packet. - * @param error_prefix Prefix to use when printing error messages. - * @param gc Garbage collector to use. + * @param opt Crypto options for this packet, contains replay state. + * @param pin Packet ID read from packet. + * @param error_prefix Prefix to use when printing error messages. + * @param gc Garbage collector to use. * * @return true if packet ID is validated to be not a replay, false otherwise. */ bool crypto_check_replay(struct crypto_options *opt, - const struct packet_id_net *pin, const char *error_prefix, - struct gc_arena *gc); + const struct packet_id_net *pin, const char *error_prefix, + struct gc_arena *gc); /** Calculate crypto overhead and adjust frame to account for that */ void crypto_adjust_frame_parameters(struct frame *frame, - const struct key_type* kt, - bool use_iv, - bool packet_id, - bool packet_id_long_form); + const struct key_type *kt, + bool use_iv, + bool packet_id, + bool packet_id_long_form); /** Return the worst-case OpenVPN crypto overhead (in bytes) */ size_t crypto_max_overhead(void); @@ -438,10 +438,10 @@ size_t crypto_max_overhead(void); * Pseudo-random number generator initialisation. * (see \c prng_rand_bytes()) * - * @param md_name Name of the message digest to use - * @param nonce_secret_len_param Length of the nonce to use + * @param md_name Name of the message digest to use + * @param nonce_secret_len_param Length of the nonce to use */ -void prng_init (const char *md_name, const int nonce_secret_len_parm); +void prng_init(const char *md_name, const int nonce_secret_len_parm); /* * Message digest-based pseudo random number generator. @@ -455,37 +455,37 @@ void prng_init (const char *md_name, const int nonce_secret_len_parm); * * Retrieves len bytes of pseudo random data, and places it in output. * - * @param output Output buffer - * @param len Length of the output buffer + * @param output Output buffer + * @param len Length of the output buffer */ -void prng_bytes (uint8_t *output, int len); +void prng_bytes(uint8_t *output, int len); -void prng_uninit (); +void prng_uninit(); -void test_crypto (struct crypto_options *co, struct frame* f); +void test_crypto(struct crypto_options *co, struct frame *f); /* key direction functions */ -void key_direction_state_init (struct key_direction_state *kds, int key_direction); +void key_direction_state_init(struct key_direction_state *kds, int key_direction); -void verify_fix_key2 (struct key2 *key2, const struct key_type *kt, const char *shared_secret_file); +void verify_fix_key2(struct key2 *key2, const struct key_type *kt, const char *shared_secret_file); -void must_have_n_keys (const char *filename, const char *option, const struct key2 *key2, int n); +void must_have_n_keys(const char *filename, const char *option, const struct key2 *key2, int n); -int ascii2keydirection (int msglevel, const char *str); +int ascii2keydirection(int msglevel, const char *str); -const char *keydirection2ascii (int kd, bool remote); +const char *keydirection2ascii(int kd, bool remote); /* print keys */ -void key2_print (const struct key2* k, - const struct key_type *kt, - const char* prefix0, - const char* prefix1); +void key2_print(const struct key2 *k, + const struct key_type *kt, + const char *prefix0, + const char *prefix1); -void crypto_read_openvpn_key (const struct key_type *key_type, - struct key_ctx_bi *ctx, const char *key_file, const char *key_inline, - const int key_direction, const char *key_name, const char *opt_name); +void crypto_read_openvpn_key(const struct key_type *key_type, + struct key_ctx_bi *ctx, const char *key_file, const char *key_inline, + const int key_direction, const char *key_name, const char *opt_name); /* * Inline functions @@ -496,23 +496,23 @@ void crypto_read_openvpn_key (const struct key_type *key_type, * Returns 0 when data is equal, non-zero otherwise. */ static inline int -memcmp_constant_time (const void *a, const void *b, size_t size) { - const uint8_t * a1 = a; - const uint8_t * b1 = b; - int ret = 0; - size_t i; +memcmp_constant_time(const void *a, const void *b, size_t size) { + const uint8_t *a1 = a; + const uint8_t *b1 = b; + int ret = 0; + size_t i; - for (i = 0; i < size; i++) { - ret |= *a1++ ^ *b1++; - } + for (i = 0; i < size; i++) { + ret |= *a1++ ^ *b1++; + } - return ret; + return ret; } static inline bool -key_ctx_bi_defined(const struct key_ctx_bi* key) +key_ctx_bi_defined(const struct key_ctx_bi *key) { - return key->encrypt.cipher || key->encrypt.hmac || key->decrypt.cipher || key->decrypt.hmac; + return key->encrypt.cipher || key->encrypt.hmac || key->decrypt.cipher || key->decrypt.hmac; } diff --git a/src/openvpn/crypto_backend.h b/src/openvpn/crypto_backend.h index bf7d78c4e41..a4b2b43e20b 100644 --- a/src/openvpn/crypto_backend.h +++ b/src/openvpn/crypto_backend.h @@ -45,12 +45,12 @@ #define OPENVPN_MAX_CIPHER_BLOCK_SIZE 32 /* Maximum HMAC digest size (bytes) */ -#define OPENVPN_MAX_HMAC_SIZE 64 +#define OPENVPN_MAX_HMAC_SIZE 64 /** Struct used in cipher name translation table */ typedef struct { - const char *openvpn_name; /**< Cipher name used by OpenVPN */ - const char *lib_name; /**< Cipher name used by crypto library */ + const char *openvpn_name; /**< Cipher name used by OpenVPN */ + const char *lib_name; /**< Cipher name used by crypto library */ } cipher_name_pair; /** Cipher name translation table */ @@ -61,16 +61,16 @@ extern const size_t cipher_name_translation_table_count; * This routine should have additional OpenSSL crypto library initialisations * used by both crypto and ssl components of OpenVPN. */ -void crypto_init_lib (void); +void crypto_init_lib(void); -void crypto_uninit_lib (void); +void crypto_uninit_lib(void); -void crypto_clear_error (void); +void crypto_clear_error(void); /* * Initialise the given named crypto engine. */ -void crypto_init_lib_engine (const char *engine_name); +void crypto_init_lib_engine(const char *engine_name); #ifdef DMALLOC /* @@ -78,26 +78,27 @@ void crypto_init_lib_engine (const char *engine_name); * OpenSSL to use our private malloc/realloc/free functions so that * we can dispatch them to dmalloc. */ -void crypto_init_dmalloc (void); +void crypto_init_dmalloc(void); + #endif /* DMALLOC */ /** * Translate a data channel cipher name from the OpenVPN config file * 'language' to the crypto library specific name. */ -const char * translate_cipher_name_from_openvpn (const char *cipher_name); +const char *translate_cipher_name_from_openvpn(const char *cipher_name); /** * Translate a data channel cipher name from the crypto library specific name * to the OpenVPN config file 'language'. */ -const char * translate_cipher_name_from_openvpn (const char *cipher_name); +const char *translate_cipher_name_from_openvpn(const char *cipher_name); -void show_available_ciphers (void); +void show_available_ciphers(void); -void show_available_digests (void); +void show_available_digests(void); -void show_available_engines (void); +void show_available_engines(void); /* * @@ -112,12 +113,12 @@ void show_available_engines (void); * Wrapper for secure random number generator. Retrieves len bytes of random * data, and places it in output. * - * @param output Output buffer - * @param len Length of the output buffer, in bytes + * @param output Output buffer + * @param len Length of the output buffer, in bytes * - * @return \c 1 on success, \c 0 on failure + * @return \c 1 on success, \c 0 on failure */ -int rand_bytes (uint8_t *output, int len); +int rand_bytes(uint8_t *output, int len); /* * @@ -130,42 +131,42 @@ int rand_bytes (uint8_t *output, int len); * Return number of DES cblocks (1 cblock = length of a single-DES key) for the * current key type or 0 if not a DES cipher. * - * @param kt Type of key + * @param kt Type of key * - * @return Number of DES cblocks that the key consists of, or 0. + * @return Number of DES cblocks that the key consists of, or 0. */ -int key_des_num_cblocks (const cipher_kt_t *kt); +int key_des_num_cblocks(const cipher_kt_t *kt); /* * Check the given DES key. Checks the given key's length, weakness and parity. * - * @param key Key to check - * @param key_len Length of the key, in bytes - * @param ndc Number of DES cblocks that the key is made up of. + * @param key Key to check + * @param key_len Length of the key, in bytes + * @param ndc Number of DES cblocks that the key is made up of. * - * @return \c true if the key is valid, \c false otherwise. + * @return \c true if the key is valid, \c false otherwise. */ -bool key_des_check (uint8_t *key, int key_len, int ndc); +bool key_des_check(uint8_t *key, int key_len, int ndc); /* * Fix the given DES key, setting its parity to odd. * - * @param key Key to check - * @param key_len Length of the key, in bytes - * @param ndc Number of DES cblocks that the key is made up of. + * @param key Key to check + * @param key_len Length of the key, in bytes + * @param ndc Number of DES cblocks that the key is made up of. */ -void key_des_fixup (uint8_t *key, int key_len, int ndc); +void key_des_fixup(uint8_t *key, int key_len, int ndc); /** * Encrypt the given block, using DES ECB mode * - * @param key DES key to use. - * @param src Buffer containing the 8-byte source. - * @param dst Buffer containing the 8-byte destination + * @param key DES key to use. + * @param src Buffer containing the 8-byte source. + * @param dst Buffer containing the 8-byte destination */ -void cipher_des_encrypt_ecb (const unsigned char key[DES_KEY_LENGTH], - unsigned char src[DES_KEY_LENGTH], - unsigned char dst[DES_KEY_LENGTH]); +void cipher_des_encrypt_ecb(const unsigned char key[DES_KEY_LENGTH], + unsigned char src[DES_KEY_LENGTH], + unsigned char dst[DES_KEY_LENGTH]); /* * @@ -191,98 +192,98 @@ void cipher_des_encrypt_ecb (const unsigned char key[DES_KEY_LENGTH], * contents of these parameters are library-specific, and can be used to * initialise encryption/decryption. * - * @param ciphername Name of the cipher to retrieve parameters for (e.g. - * \c AES-128-CBC). + * @param ciphername Name of the cipher to retrieve parameters for (e.g. + * \c AES-128-CBC). * - * @return A statically allocated structure containing parameters - * for the given cipher, or NULL if no matching parameters - * were found. + * @return A statically allocated structure containing parameters + * for the given cipher, or NULL if no matching parameters + * were found. */ -const cipher_kt_t * cipher_kt_get (const char *ciphername); +const cipher_kt_t *cipher_kt_get(const char *ciphername); /** * Retrieve a string describing the cipher (e.g. \c AES-128-CBC). * - * @param cipher_kt Static cipher parameters + * @param cipher_kt Static cipher parameters * * @return a statically allocated string describing the cipher. */ -const char * cipher_kt_name (const cipher_kt_t *cipher_kt); +const char *cipher_kt_name(const cipher_kt_t *cipher_kt); /** * Returns the size of keys used by the cipher, in bytes. If the cipher has a * variable key size, return the default key size. * - * @param cipher_kt Static cipher parameters + * @param cipher_kt Static cipher parameters * - * @return (Default) size of keys used by the cipher, in bytes. + * @return (Default) size of keys used by the cipher, in bytes. */ -int cipher_kt_key_size (const cipher_kt_t *cipher_kt); +int cipher_kt_key_size(const cipher_kt_t *cipher_kt); /** * Returns the size of the IV used by the cipher, in bytes, or 0 if no IV is * used. * - * @param cipher_kt Static cipher parameters + * @param cipher_kt Static cipher parameters * - * @return Size of the IV, in bytes, or 0 if the cipher does not - * use an IV. + * @return Size of the IV, in bytes, or 0 if the cipher does not + * use an IV. */ -int cipher_kt_iv_size (const cipher_kt_t *cipher_kt); +int cipher_kt_iv_size(const cipher_kt_t *cipher_kt); /** * Returns the block size of the cipher, in bytes. * - * @param cipher_kt Static cipher parameters + * @param cipher_kt Static cipher parameters * - * @return Block size, in bytes. + * @return Block size, in bytes. */ -int cipher_kt_block_size (const cipher_kt_t *cipher_kt); +int cipher_kt_block_size(const cipher_kt_t *cipher_kt); /** * Returns the MAC tag size of the cipher, in bytes. * - * @param ctx Static cipher parameters. + * @param ctx Static cipher parameters. * - * @return Tag size in bytes, or 0 if the tag size could not be - * determined. + * @return Tag size in bytes, or 0 if the tag size could not be + * determined. */ -int cipher_kt_tag_size (const cipher_kt_t *cipher_kt); +int cipher_kt_tag_size(const cipher_kt_t *cipher_kt); /** * Returns the mode that the cipher runs in. * - * @param cipher_kt Static cipher parameters. May not be NULL. + * @param cipher_kt Static cipher parameters. May not be NULL. * - * @return Cipher mode, either \c OPENVPN_MODE_CBC, \c - * OPENVPN_MODE_OFB or \c OPENVPN_MODE_CFB + * @return Cipher mode, either \c OPENVPN_MODE_CBC, \c + * OPENVPN_MODE_OFB or \c OPENVPN_MODE_CFB */ -int cipher_kt_mode (const cipher_kt_t *cipher_kt); +int cipher_kt_mode(const cipher_kt_t *cipher_kt); /** * Check if the supplied cipher is a supported CBC mode cipher. * - * @param cipher Static cipher parameters. + * @param cipher Static cipher parameters. * - * @return true iff the cipher is a CBC mode cipher. + * @return true iff the cipher is a CBC mode cipher. */ bool cipher_kt_mode_cbc(const cipher_kt_t *cipher); /** * Check if the supplied cipher is a supported OFB or CFB mode cipher. * - * @param cipher Static cipher parameters. + * @param cipher Static cipher parameters. * - * @return true iff the cipher is a OFB or CFB mode cipher. + * @return true iff the cipher is a OFB or CFB mode cipher. */ bool cipher_kt_mode_ofb_cfb(const cipher_kt_t *cipher); /** * Check if the supplied cipher is a supported AEAD mode cipher. * - * @param cipher Static cipher parameters. + * @param cipher Static cipher parameters. * - * @return true iff the cipher is a AEAD mode cipher. + * @return true iff the cipher is a AEAD mode cipher. */ bool cipher_kt_mode_aead(const cipher_kt_t *cipher); @@ -296,94 +297,94 @@ bool cipher_kt_mode_aead(const cipher_kt_t *cipher); /** * Initialise a cipher context, based on the given key and key type. * - * @param ctx Cipher context. May not be NULL - * @param key Buffer containing the key to use - * @param key_len Length of the key, in bytes - * @param kt Static cipher parameters to use - * @param enc Whether to encrypt or decrypt (either - * \c MBEDTLS_OP_ENCRYPT or \c MBEDTLS_OP_DECRYPT). + * @param ctx Cipher context. May not be NULL + * @param key Buffer containing the key to use + * @param key_len Length of the key, in bytes + * @param kt Static cipher parameters to use + * @param enc Whether to encrypt or decrypt (either + * \c MBEDTLS_OP_ENCRYPT or \c MBEDTLS_OP_DECRYPT). */ -void cipher_ctx_init (cipher_ctx_t *ctx, uint8_t *key, int key_len, - const cipher_kt_t *kt, int enc); +void cipher_ctx_init(cipher_ctx_t *ctx, uint8_t *key, int key_len, + const cipher_kt_t *kt, int enc); /** * Cleanup the specified context. * - * @param ctx Cipher context to cleanup. + * @param ctx Cipher context to cleanup. */ -void cipher_ctx_cleanup (cipher_ctx_t *ctx); +void cipher_ctx_cleanup(cipher_ctx_t *ctx); /** * Returns the size of the IV used by the cipher, in bytes, or 0 if no IV is * used. * - * @param ctx The cipher's context + * @param ctx The cipher's context * - * @return Size of the IV, in bytes, or \c 0 if the cipher does not - * use an IV or ctx was NULL. + * @return Size of the IV, in bytes, or \c 0 if the cipher does not + * use an IV or ctx was NULL. */ -int cipher_ctx_iv_length (const cipher_ctx_t *ctx); +int cipher_ctx_iv_length(const cipher_ctx_t *ctx); /** * Gets the computed message authenticated code (MAC) tag for this cipher. * - * @param ctx The cipher's context - * @param tag The buffer to write computed tag in. - * @param tag_size The tag buffer size, in bytes. + * @param ctx The cipher's context + * @param tag The buffer to write computed tag in. + * @param tag_size The tag buffer size, in bytes. */ -int cipher_ctx_get_tag (cipher_ctx_t *ctx, uint8_t* tag, int tag_len); +int cipher_ctx_get_tag(cipher_ctx_t *ctx, uint8_t *tag, int tag_len); /** * Returns the block size of the cipher, in bytes. * - * @param ctx The cipher's context + * @param ctx The cipher's context * - * @return Block size, in bytes, or 0 if ctx was NULL. + * @return Block size, in bytes, or 0 if ctx was NULL. */ -int cipher_ctx_block_size (const cipher_ctx_t *ctx); +int cipher_ctx_block_size(const cipher_ctx_t *ctx); /** * Returns the mode that the cipher runs in. * - * @param ctx Cipher's context. May not be NULL. + * @param ctx Cipher's context. May not be NULL. * - * @return Cipher mode, either \c OPENVPN_MODE_CBC, \c - * OPENVPN_MODE_OFB or \c OPENVPN_MODE_CFB + * @return Cipher mode, either \c OPENVPN_MODE_CBC, \c + * OPENVPN_MODE_OFB or \c OPENVPN_MODE_CFB */ -int cipher_ctx_mode (const cipher_ctx_t *ctx); +int cipher_ctx_mode(const cipher_ctx_t *ctx); /** * Returns the static cipher parameters for this context. * - * @param ctx Cipher's context. + * @param ctx Cipher's context. * - * @return Static cipher parameters for the supplied context, or - * NULL if unable to determine cipher parameters. + * @return Static cipher parameters for the supplied context, or + * NULL if unable to determine cipher parameters. */ -const cipher_kt_t *cipher_ctx_get_cipher_kt (const cipher_ctx_t *ctx); +const cipher_kt_t *cipher_ctx_get_cipher_kt(const cipher_ctx_t *ctx); /** * Resets the given cipher context, setting the IV to the specified value. * Preserves the associated key information. * - * @param ctx Cipher's context. May not be NULL. - * @param iv_buf The IV to use. + * @param ctx Cipher's context. May not be NULL. + * @param iv_buf The IV to use. * - * @return \c 0 on failure, \c 1 on success. + * @return \c 0 on failure, \c 1 on success. */ -int cipher_ctx_reset (cipher_ctx_t *ctx, uint8_t *iv_buf); +int cipher_ctx_reset(cipher_ctx_t *ctx, uint8_t *iv_buf); /** * Updates the given cipher context, providing additional data (AD) for * authenticated encryption with additional data (AEAD) cipher modes. * - * @param ctx Cipher's context. May not be NULL. - * @param src Source buffer - * @param src_len Length of the source buffer, in bytes + * @param ctx Cipher's context. May not be NULL. + * @param src Source buffer + * @param src_len Length of the source buffer, in bytes * - * @return \c 0 on failure, \c 1 on success. + * @return \c 0 on failure, \c 1 on success. */ -int cipher_ctx_update_ad (cipher_ctx_t *ctx, const uint8_t *src, int src_len); +int cipher_ctx_update_ad(cipher_ctx_t *ctx, const uint8_t *src, int src_len); /** * Updates the given cipher context, encrypting data in the source buffer, and @@ -394,28 +395,28 @@ int cipher_ctx_update_ad (cipher_ctx_t *ctx, const uint8_t *src, int src_len); * to \c cipher_ctx_final(). This implies that dst should have enough room for * src_len + \c cipher_ctx_block_size(). * - * @param ctx Cipher's context. May not be NULL. - * @param dst Destination buffer - * @param dst_len Length of the destination buffer, in bytes - * @param src Source buffer - * @param src_len Length of the source buffer, in bytes + * @param ctx Cipher's context. May not be NULL. + * @param dst Destination buffer + * @param dst_len Length of the destination buffer, in bytes + * @param src Source buffer + * @param src_len Length of the source buffer, in bytes * - * @return \c 0 on failure, \c 1 on success. + * @return \c 0 on failure, \c 1 on success. */ -int cipher_ctx_update (cipher_ctx_t *ctx, uint8_t *dst, int *dst_len, - uint8_t *src, int src_len); +int cipher_ctx_update(cipher_ctx_t *ctx, uint8_t *dst, int *dst_len, + uint8_t *src, int src_len); /** * Pads the final cipher block using PKCS padding, and output to the destination * buffer. * - * @param ctx Cipher's context. May not be NULL. - * @param dst Destination buffer - * @param dst_len Length of the destination buffer, in bytes + * @param ctx Cipher's context. May not be NULL. + * @param dst Destination buffer + * @param dst_len Length of the destination buffer, in bytes * - * @return \c 0 on failure, \c 1 on success. + * @return \c 0 on failure, \c 1 on success. */ -int cipher_ctx_final (cipher_ctx_t *ctx, uint8_t *dst, int *dst_len); +int cipher_ctx_final(cipher_ctx_t *ctx, uint8_t *dst, int *dst_len); /** * Like \c cipher_ctx_final, but check the computed authentication tag against @@ -430,8 +431,8 @@ int cipher_ctx_final (cipher_ctx_t *ctx, uint8_t *dst, int *dst_len); * * @return \c 0 on failure, \c 1 on success. */ -int cipher_ctx_final_check_tag (cipher_ctx_t *ctx, uint8_t *dst, int *dst_len, - uint8_t *tag, size_t tag_len); +int cipher_ctx_final_check_tag(cipher_ctx_t *ctx, uint8_t *dst, int *dst_len, + uint8_t *tag, size_t tag_len); /* @@ -454,32 +455,32 @@ int cipher_ctx_final_check_tag (cipher_ctx_t *ctx, uint8_t *dst, int *dst_len, * contents of these parameters are library-specific, and can be used to * initialise HMAC or message digest operations. * - * @param digest Name of the digest to retrieve parameters for (e.g. - * \c MD5). + * @param digest Name of the digest to retrieve parameters for (e.g. + * \c MD5). * - * @return A statically allocated structure containing parameters - * for the given message digest. + * @return A statically allocated structure containing parameters + * for the given message digest. */ -const md_kt_t * md_kt_get (const char *digest); +const md_kt_t *md_kt_get(const char *digest); /** * Retrieve a string describing the digest digest (e.g. \c SHA1). * - * @param kt Static message digest parameters + * @param kt Static message digest parameters * - * @return Statically allocated string describing the message - * digest. + * @return Statically allocated string describing the message + * digest. */ -const char * md_kt_name (const md_kt_t *kt); +const char *md_kt_name(const md_kt_t *kt); /** * Returns the size of the message digest, in bytes. * - * @param kt Static message digest parameters + * @param kt Static message digest parameters * - * @return Message digest size, in bytes, or 0 if ctx was NULL. + * @return Message digest size, in bytes, or 0 if ctx was NULL. */ -int md_kt_size (const md_kt_t *kt); +int md_kt_size(const md_kt_t *kt); /* @@ -491,55 +492,55 @@ int md_kt_size (const md_kt_t *kt); /* * Calculates the message digest for the given buffer. * - * @param kt Static message digest parameters - * @param src Buffer to digest. May not be NULL. - * @param src_len The length of the incoming buffer. - * @param dst Buffer to write the message digest to. May not be NULL. + * @param kt Static message digest parameters + * @param src Buffer to digest. May not be NULL. + * @param src_len The length of the incoming buffer. + * @param dst Buffer to write the message digest to. May not be NULL. * - * @return \c 1 on success, \c 0 on failure + * @return \c 1 on success, \c 0 on failure */ -int md_full (const md_kt_t *kt, const uint8_t *src, int src_len, uint8_t *dst); +int md_full(const md_kt_t *kt, const uint8_t *src, int src_len, uint8_t *dst); /* * Initialises the given message digest context. * - * @param ctx Message digest context - * @param kt Static message digest parameters + * @param ctx Message digest context + * @param kt Static message digest parameters */ -void md_ctx_init (md_ctx_t *ctx, const md_kt_t *kt); +void md_ctx_init(md_ctx_t *ctx, const md_kt_t *kt); /* * Free the given message digest context. * - * @param ctx Message digest context + * @param ctx Message digest context */ void md_ctx_cleanup(md_ctx_t *ctx); /* * Returns the size of the message digest output by the given context * - * @param ctx Message digest context. + * @param ctx Message digest context. * - * @return Size of the message digest, or \0 if ctx is NULL. + * @return Size of the message digest, or \0 if ctx is NULL. */ -int md_ctx_size (const md_ctx_t *ctx); +int md_ctx_size(const md_ctx_t *ctx); /* * Process the given data for use in the message digest. * - * @param ctx Message digest context. May not be NULL. - * @param src Buffer to digest. May not be NULL. - * @param src_len The length of the incoming buffer. + * @param ctx Message digest context. May not be NULL. + * @param src Buffer to digest. May not be NULL. + * @param src_len The length of the incoming buffer. */ -void md_ctx_update (md_ctx_t *ctx, const uint8_t *src, int src_len); +void md_ctx_update(md_ctx_t *ctx, const uint8_t *src, int src_len); /* * Output the message digest to the given buffer. * - * @param ctx Message digest context. May not be NULL. - * @param dst Buffer to write the message digest to. May not be NULL. + * @param ctx Message digest context. May not be NULL. + * @param dst Buffer to write the message digest to. May not be NULL. */ -void md_ctx_final (md_ctx_t *ctx, uint8_t *dst); +void md_ctx_final(md_ctx_t *ctx, uint8_t *dst); /* @@ -552,73 +553,73 @@ void md_ctx_final (md_ctx_t *ctx, uint8_t *dst); * Initialises the given HMAC context, using the given digest * and key. * - * @param ctx HMAC context to intialise - * @param key The key to use for the HMAC - * @param key_len The key length to use - * @param kt Static message digest parameters + * @param ctx HMAC context to intialise + * @param key The key to use for the HMAC + * @param key_len The key length to use + * @param kt Static message digest parameters * */ -void hmac_ctx_init (hmac_ctx_t *ctx, const uint8_t *key, int key_length, - const md_kt_t *kt); +void hmac_ctx_init(hmac_ctx_t *ctx, const uint8_t *key, int key_length, + const md_kt_t *kt); /* * Free the given HMAC context. * - * @param ctx HMAC context + * @param ctx HMAC context */ void hmac_ctx_cleanup(hmac_ctx_t *ctx); /* * Returns the size of the HMAC output by the given HMAC Context * - * @param ctx HMAC context. + * @param ctx HMAC context. * - * @return Size of the HMAC, or \0 if ctx is NULL. + * @return Size of the HMAC, or \0 if ctx is NULL. */ -int hmac_ctx_size (const hmac_ctx_t *ctx); +int hmac_ctx_size(const hmac_ctx_t *ctx); /* * Resets the given HMAC context, preserving the associated key information * - * @param ctx HMAC context. May not be NULL. + * @param ctx HMAC context. May not be NULL. */ -void hmac_ctx_reset (hmac_ctx_t *ctx); +void hmac_ctx_reset(hmac_ctx_t *ctx); /* * Process the given data for use in the HMAC. * - * @param ctx HMAC context. May not be NULL. - * @param src The buffer to HMAC. May not be NULL. - * @param src_len The length of the incoming buffer. + * @param ctx HMAC context. May not be NULL. + * @param src The buffer to HMAC. May not be NULL. + * @param src_len The length of the incoming buffer. */ -void hmac_ctx_update (hmac_ctx_t *ctx, const uint8_t *src, int src_len); +void hmac_ctx_update(hmac_ctx_t *ctx, const uint8_t *src, int src_len); /* * Output the HMAC to the given buffer. * - * @param ctx HMAC context. May not be NULL. - * @param dst buffer to write the HMAC to. May not be NULL. + * @param ctx HMAC context. May not be NULL. + * @param dst buffer to write the HMAC to. May not be NULL. */ -void hmac_ctx_final (hmac_ctx_t *ctx, uint8_t *dst); +void hmac_ctx_final(hmac_ctx_t *ctx, uint8_t *dst); /** * Translate an OpenVPN cipher name to a crypto library cipher name. * - * @param cipher_name An OpenVPN cipher name + * @param cipher_name An OpenVPN cipher name * - * @return The corresponding crypto library cipher name, or NULL - * if no matching cipher name was found. + * @return The corresponding crypto library cipher name, or NULL + * if no matching cipher name was found. */ -const char * translate_cipher_name_from_openvpn (const char *cipher_name); +const char *translate_cipher_name_from_openvpn(const char *cipher_name); /** * Translate a crypto library cipher name to an OpenVPN cipher name. * - * @param cipher_name A crypto library cipher name + * @param cipher_name A crypto library cipher name * - * @return The corresponding OpenVPN cipher name, or NULL if no - * matching cipher name was found. + * @return The corresponding OpenVPN cipher name, or NULL if no + * matching cipher name was found. */ -const char * translate_cipher_name_to_openvpn (const char *cipher_name); +const char *translate_cipher_name_to_openvpn(const char *cipher_name); #endif /* CRYPTO_BACKEND_H_ */ diff --git a/src/openvpn/crypto_mbedtls.c b/src/openvpn/crypto_mbedtls.c index 6ad5924782a..89915bc04e3 100644 --- a/src/openvpn/crypto_mbedtls.c +++ b/src/openvpn/crypto_mbedtls.c @@ -61,10 +61,10 @@ */ void -crypto_init_lib_engine (const char *engine_name) +crypto_init_lib_engine(const char *engine_name) { - msg (M_WARN, "Note: mbed TLS hardware crypto engine functionality is not " - "available"); + msg(M_WARN, "Note: mbed TLS hardware crypto engine functionality is not " + "available"); } /* @@ -74,51 +74,58 @@ crypto_init_lib_engine (const char *engine_name) */ void -crypto_init_lib (void) +crypto_init_lib(void) { } void -crypto_uninit_lib (void) +crypto_uninit_lib(void) { } void -crypto_clear_error (void) +crypto_clear_error(void) { } -bool mbed_log_err(unsigned int flags, int errval, const char *prefix) +bool +mbed_log_err(unsigned int flags, int errval, const char *prefix) { - if (0 != errval) + if (0 != errval) { - char errstr[256]; - mbedtls_strerror(errval, errstr, sizeof(errstr)); - - if (NULL == prefix) prefix = "mbed TLS error"; - msg (flags, "%s: %s", prefix, errstr); + char errstr[256]; + mbedtls_strerror(errval, errstr, sizeof(errstr)); + + if (NULL == prefix) + { + prefix = "mbed TLS error"; + } + msg(flags, "%s: %s", prefix, errstr); } - return 0 == errval; + return 0 == errval; } -bool mbed_log_func_line(unsigned int flags, int errval, const char *func, - int line) +bool +mbed_log_func_line(unsigned int flags, int errval, const char *func, + int line) { - char prefix[256]; + char prefix[256]; - if (!openvpn_snprintf(prefix, sizeof(prefix), "%s:%d", func, line)) - return mbed_log_err(flags, errval, func); + if (!openvpn_snprintf(prefix, sizeof(prefix), "%s:%d", func, line)) + { + return mbed_log_err(flags, errval, func); + } - return mbed_log_err(flags, errval, prefix); + return mbed_log_err(flags, errval, prefix); } #ifdef DMALLOC void -crypto_init_dmalloc (void) +crypto_init_dmalloc(void) { - msg (M_ERR, "Error: dmalloc support is not available for mbed TLS."); + msg(M_ERR, "Error: dmalloc support is not available for mbed TLS."); } #endif /* DMALLOC */ @@ -130,94 +137,97 @@ const cipher_name_pair cipher_name_translation_table[] = { { "CAMELLIA-256-CFB", "CAMELLIA-256-CFB128" } }; const size_t cipher_name_translation_table_count = - sizeof (cipher_name_translation_table) / sizeof (*cipher_name_translation_table); + sizeof(cipher_name_translation_table) / sizeof(*cipher_name_translation_table); -static void print_cipher(const cipher_kt_t *info) +static void +print_cipher(const cipher_kt_t *info) { - if (info && (cipher_kt_mode_cbc(info) + if (info && (cipher_kt_mode_cbc(info) #ifdef HAVE_AEAD_CIPHER_MODES - || cipher_kt_mode_aead(info) + || cipher_kt_mode_aead(info) #endif - )) + )) { - const char *ssl_only = cipher_kt_mode_cbc(info) ? - "" : ", TLS client/server mode only"; - const char *var_key_size = info->flags & MBEDTLS_CIPHER_VARIABLE_KEY_LEN ? - " by default" : ""; - - printf ("%s (%d bit key%s, %d bit block%s)\n", - cipher_kt_name(info), cipher_kt_key_size(info) * 8, var_key_size, - cipher_kt_block_size(info) * 8, ssl_only); + const char *ssl_only = cipher_kt_mode_cbc(info) ? + "" : ", TLS client/server mode only"; + const char *var_key_size = info->flags & MBEDTLS_CIPHER_VARIABLE_KEY_LEN ? + " by default" : ""; + + printf("%s (%d bit key%s, %d bit block%s)\n", + cipher_kt_name(info), cipher_kt_key_size(info) * 8, var_key_size, + cipher_kt_block_size(info) * 8, ssl_only); } } void -show_available_ciphers () +show_available_ciphers() { - const int *ciphers = mbedtls_cipher_list(); + const int *ciphers = mbedtls_cipher_list(); #ifndef ENABLE_SMALL - printf ("The following ciphers and cipher modes are available for use\n" - "with " PACKAGE_NAME ". Each cipher shown below may be used as a\n" - "parameter to the --cipher option. Using a CBC or GCM mode is\n" - "recommended. In static key mode only CBC mode is allowed.\n\n"); + printf("The following ciphers and cipher modes are available for use\n" + "with " PACKAGE_NAME ". Each cipher shown below may be used as a\n" + "parameter to the --cipher option. Using a CBC or GCM mode is\n" + "recommended. In static key mode only CBC mode is allowed.\n\n"); #endif - while (*ciphers != 0) + while (*ciphers != 0) { - const cipher_kt_t *info = mbedtls_cipher_info_from_type(*ciphers); - if (info && cipher_kt_block_size(info) >= 128/8) - { - print_cipher(info); - } - ciphers++; + const cipher_kt_t *info = mbedtls_cipher_info_from_type(*ciphers); + if (info && cipher_kt_block_size(info) >= 128/8) + { + print_cipher(info); + } + ciphers++; } - printf ("\nThe following ciphers have a block size of less than 128 bits, \n" - "and are therefore deprecated. Do not use unless you have to.\n\n"); - ciphers = mbedtls_cipher_list(); - while (*ciphers != 0) + printf("\nThe following ciphers have a block size of less than 128 bits, \n" + "and are therefore deprecated. Do not use unless you have to.\n\n"); + ciphers = mbedtls_cipher_list(); + while (*ciphers != 0) { - const cipher_kt_t *info = mbedtls_cipher_info_from_type(*ciphers); - if (info && cipher_kt_block_size(info) < 128/8) - { - print_cipher(info); - } - ciphers++; + const cipher_kt_t *info = mbedtls_cipher_info_from_type(*ciphers); + if (info && cipher_kt_block_size(info) < 128/8) + { + print_cipher(info); + } + ciphers++; } - printf ("\n"); + printf("\n"); } void -show_available_digests () +show_available_digests() { - const int *digests = mbedtls_md_list(); + const int *digests = mbedtls_md_list(); #ifndef ENABLE_SMALL - printf ("The following message digests are available for use with\n" - PACKAGE_NAME ". A message digest is used in conjunction with\n" - "the HMAC function, to authenticate received packets.\n" - "You can specify a message digest as parameter to\n" - "the --auth option.\n\n"); + printf("The following message digests are available for use with\n" + PACKAGE_NAME ". A message digest is used in conjunction with\n" + "the HMAC function, to authenticate received packets.\n" + "You can specify a message digest as parameter to\n" + "the --auth option.\n\n"); #endif - while (*digests != 0) + while (*digests != 0) { - const mbedtls_md_info_t *info = mbedtls_md_info_from_type(*digests); - - if (info) - printf ("%s %d bit default key\n", mbedtls_md_get_name(info), - mbedtls_md_get_size(info) * 8); - digests++; + const mbedtls_md_info_t *info = mbedtls_md_info_from_type(*digests); + + if (info) + { + printf("%s %d bit default key\n", mbedtls_md_get_name(info), + mbedtls_md_get_size(info) * 8); + } + digests++; } - printf ("\n"); + printf("\n"); } void -show_available_engines () +show_available_engines() { - printf ("Sorry, mbed TLS hardware crypto engine functionality is not " - "available\n"); + printf("Sorry, mbed TLS hardware crypto engine functionality is not " + "available\n"); } /* @@ -233,64 +243,70 @@ show_available_engines () * Initialise the given ctr_drbg context, using a personalisation string and an * entropy gathering function. */ -mbedtls_ctr_drbg_context * rand_ctx_get() +mbedtls_ctr_drbg_context * +rand_ctx_get() { - static mbedtls_entropy_context ec = {0}; - static mbedtls_ctr_drbg_context cd_ctx = {0}; - static bool rand_initialised = false; + static mbedtls_entropy_context ec = {0}; + static mbedtls_ctr_drbg_context cd_ctx = {0}; + static bool rand_initialised = false; - if (!rand_initialised) + if (!rand_initialised) { - struct gc_arena gc = gc_new(); - struct buffer pers_string = alloc_buf_gc(100, &gc); - - /* - * Personalisation string, should be as unique as possible (see NIST - * 800-90 section 8.7.1). We have very little information at this stage. - * Include Program Name, memory address of the context and PID. - */ - buf_printf(&pers_string, "OpenVPN %0u %p %s", platform_getpid(), &cd_ctx, time_string(0, 0, 0, &gc)); - - /* Initialise mbed TLS RNG, and built-in entropy sources */ - mbedtls_entropy_init(&ec); - - mbedtls_ctr_drbg_init(&cd_ctx); - if (!mbed_ok(mbedtls_ctr_drbg_seed(&cd_ctx, mbedtls_entropy_func, &ec, - BPTR(&pers_string), BLEN(&pers_string)))) - msg (M_FATAL, "Failed to initialize random generator"); - - gc_free(&gc); - rand_initialised = true; - } + struct gc_arena gc = gc_new(); + struct buffer pers_string = alloc_buf_gc(100, &gc); + + /* + * Personalisation string, should be as unique as possible (see NIST + * 800-90 section 8.7.1). We have very little information at this stage. + * Include Program Name, memory address of the context and PID. + */ + buf_printf(&pers_string, "OpenVPN %0u %p %s", platform_getpid(), &cd_ctx, time_string(0, 0, 0, &gc)); + + /* Initialise mbed TLS RNG, and built-in entropy sources */ + mbedtls_entropy_init(&ec); + + mbedtls_ctr_drbg_init(&cd_ctx); + if (!mbed_ok(mbedtls_ctr_drbg_seed(&cd_ctx, mbedtls_entropy_func, &ec, + BPTR(&pers_string), BLEN(&pers_string)))) + { + msg(M_FATAL, "Failed to initialize random generator"); + } + + gc_free(&gc); + rand_initialised = true; + } - return &cd_ctx; + return &cd_ctx; } #ifdef ENABLE_PREDICTION_RESISTANCE -void rand_ctx_enable_prediction_resistance() +void +rand_ctx_enable_prediction_resistance() { - mbedtls_ctr_drbg_context *cd_ctx = rand_ctx_get(); + mbedtls_ctr_drbg_context *cd_ctx = rand_ctx_get(); - mbedtls_ctr_drbg_set_prediction_resistance(cd_ctx, 1); + mbedtls_ctr_drbg_set_prediction_resistance(cd_ctx, 1); } #endif /* ENABLE_PREDICTION_RESISTANCE */ int -rand_bytes (uint8_t *output, int len) +rand_bytes(uint8_t *output, int len) { - mbedtls_ctr_drbg_context *rng_ctx = rand_ctx_get(); + mbedtls_ctr_drbg_context *rng_ctx = rand_ctx_get(); - while (len > 0) + while (len > 0) { - const size_t blen = min_int (len, MBEDTLS_CTR_DRBG_MAX_REQUEST); - if (0 != mbedtls_ctr_drbg_random(rng_ctx, output, blen)) - return 0; - - output += blen; - len -= blen; + const size_t blen = min_int(len, MBEDTLS_CTR_DRBG_MAX_REQUEST); + if (0 != mbedtls_ctr_drbg_random(rng_ctx, output, blen)) + { + return 0; + } + + output += blen; + len -= blen; } - return 1; + return 1; } /* @@ -301,69 +317,75 @@ rand_bytes (uint8_t *output, int len) int -key_des_num_cblocks (const mbedtls_cipher_info_t *kt) +key_des_num_cblocks(const mbedtls_cipher_info_t *kt) { - int ret = 0; - if (kt->type == MBEDTLS_CIPHER_DES_CBC) - ret = 1; - if (kt->type == MBEDTLS_CIPHER_DES_EDE_CBC) - ret = 2; - if (kt->type == MBEDTLS_CIPHER_DES_EDE3_CBC) - ret = 3; + int ret = 0; + if (kt->type == MBEDTLS_CIPHER_DES_CBC) + { + ret = 1; + } + if (kt->type == MBEDTLS_CIPHER_DES_EDE_CBC) + { + ret = 2; + } + if (kt->type == MBEDTLS_CIPHER_DES_EDE3_CBC) + { + ret = 3; + } - dmsg (D_CRYPTO_DEBUG, "CRYPTO INFO: n_DES_cblocks=%d", ret); - return ret; + dmsg(D_CRYPTO_DEBUG, "CRYPTO INFO: n_DES_cblocks=%d", ret); + return ret; } bool -key_des_check (uint8_t *key, int key_len, int ndc) +key_des_check(uint8_t *key, int key_len, int ndc) { - int i; - struct buffer b; + int i; + struct buffer b; - buf_set_read (&b, key, key_len); + buf_set_read(&b, key, key_len); - for (i = 0; i < ndc; ++i) + for (i = 0; i < ndc; ++i) { - unsigned char *key = buf_read_alloc(&b, MBEDTLS_DES_KEY_SIZE); - if (!key) - { - msg (D_CRYPT_ERRORS, "CRYPTO INFO: check_key_DES: insufficient key material"); - goto err; - } - if (0 != mbedtls_des_key_check_weak(key)) - { - msg (D_CRYPT_ERRORS, "CRYPTO INFO: check_key_DES: weak key detected"); - goto err; - } - if (0 != mbedtls_des_key_check_key_parity(key)) - { - msg (D_CRYPT_ERRORS, "CRYPTO INFO: check_key_DES: bad parity detected"); - goto err; - } + unsigned char *key = buf_read_alloc(&b, MBEDTLS_DES_KEY_SIZE); + if (!key) + { + msg(D_CRYPT_ERRORS, "CRYPTO INFO: check_key_DES: insufficient key material"); + goto err; + } + if (0 != mbedtls_des_key_check_weak(key)) + { + msg(D_CRYPT_ERRORS, "CRYPTO INFO: check_key_DES: weak key detected"); + goto err; + } + if (0 != mbedtls_des_key_check_key_parity(key)) + { + msg(D_CRYPT_ERRORS, "CRYPTO INFO: check_key_DES: bad parity detected"); + goto err; + } } - return true; + return true; - err: - return false; +err: + return false; } void -key_des_fixup (uint8_t *key, int key_len, int ndc) +key_des_fixup(uint8_t *key, int key_len, int ndc) { - int i; - struct buffer b; + int i; + struct buffer b; - buf_set_read (&b, key, key_len); - for (i = 0; i < ndc; ++i) + buf_set_read(&b, key, key_len); + for (i = 0; i < ndc; ++i) { - unsigned char *key = buf_read_alloc(&b, MBEDTLS_DES_KEY_SIZE); - if (!key) - { - msg (D_CRYPT_ERRORS, "CRYPTO INFO: fixup_key_DES: insufficient key material"); - return; - } - mbedtls_des_key_set_parity(key); + unsigned char *key = buf_read_alloc(&b, MBEDTLS_DES_KEY_SIZE); + if (!key) + { + msg(D_CRYPT_ERRORS, "CRYPTO INFO: fixup_key_DES: insufficient key material"); + return; + } + mbedtls_des_key_set_parity(key); } } @@ -375,99 +397,109 @@ key_des_fixup (uint8_t *key, int key_len, int ndc) const mbedtls_cipher_info_t * -cipher_kt_get (const char *ciphername) +cipher_kt_get(const char *ciphername) { - const mbedtls_cipher_info_t *cipher = NULL; + const mbedtls_cipher_info_t *cipher = NULL; - ASSERT (ciphername); + ASSERT(ciphername); - cipher = mbedtls_cipher_info_from_string(ciphername); + cipher = mbedtls_cipher_info_from_string(ciphername); - if (NULL == cipher) + if (NULL == cipher) { - msg (D_LOW, "Cipher algorithm '%s' not found", ciphername); - return NULL; + msg(D_LOW, "Cipher algorithm '%s' not found", ciphername); + return NULL; } - if (cipher->key_bitlen/8 > MAX_CIPHER_KEY_LENGTH) + if (cipher->key_bitlen/8 > MAX_CIPHER_KEY_LENGTH) { - msg (D_LOW, "Cipher algorithm '%s' uses a default key size (%d bytes) " - "which is larger than " PACKAGE_NAME "'s current maximum key size " - "(%d bytes)", ciphername, cipher->key_bitlen/8, MAX_CIPHER_KEY_LENGTH); - return NULL; + msg(D_LOW, "Cipher algorithm '%s' uses a default key size (%d bytes) " + "which is larger than " PACKAGE_NAME "'s current maximum key size " + "(%d bytes)", ciphername, cipher->key_bitlen/8, MAX_CIPHER_KEY_LENGTH); + return NULL; } - return cipher; + return cipher; } const char * -cipher_kt_name (const mbedtls_cipher_info_t *cipher_kt) +cipher_kt_name(const mbedtls_cipher_info_t *cipher_kt) { - if (NULL == cipher_kt) - return "[null-cipher]"; + if (NULL == cipher_kt) + { + return "[null-cipher]"; + } - return translate_cipher_name_to_openvpn(cipher_kt->name); + return translate_cipher_name_to_openvpn(cipher_kt->name); } int -cipher_kt_key_size (const mbedtls_cipher_info_t *cipher_kt) +cipher_kt_key_size(const mbedtls_cipher_info_t *cipher_kt) { - if (NULL == cipher_kt) - return 0; + if (NULL == cipher_kt) + { + return 0; + } - return cipher_kt->key_bitlen/8; + return cipher_kt->key_bitlen/8; } int -cipher_kt_iv_size (const mbedtls_cipher_info_t *cipher_kt) +cipher_kt_iv_size(const mbedtls_cipher_info_t *cipher_kt) { - if (NULL == cipher_kt) - return 0; - return cipher_kt->iv_size; + if (NULL == cipher_kt) + { + return 0; + } + return cipher_kt->iv_size; } int -cipher_kt_block_size (const mbedtls_cipher_info_t *cipher_kt) +cipher_kt_block_size(const mbedtls_cipher_info_t *cipher_kt) { - if (NULL == cipher_kt) - return 0; - return cipher_kt->block_size; + if (NULL == cipher_kt) + { + return 0; + } + return cipher_kt->block_size; } int -cipher_kt_tag_size (const mbedtls_cipher_info_t *cipher_kt) +cipher_kt_tag_size(const mbedtls_cipher_info_t *cipher_kt) { #ifdef HAVE_AEAD_CIPHER_MODES - if (cipher_kt && cipher_kt_mode_aead(cipher_kt)) - return OPENVPN_AEAD_TAG_LENGTH; + if (cipher_kt && cipher_kt_mode_aead(cipher_kt)) + { + return OPENVPN_AEAD_TAG_LENGTH; + } #endif - return 0; + return 0; } int -cipher_kt_mode (const mbedtls_cipher_info_t *cipher_kt) +cipher_kt_mode(const mbedtls_cipher_info_t *cipher_kt) { - ASSERT(NULL != cipher_kt); - return cipher_kt->mode; + ASSERT(NULL != cipher_kt); + return cipher_kt->mode; } bool cipher_kt_mode_cbc(const cipher_kt_t *cipher) { - return cipher && cipher_kt_mode(cipher) == OPENVPN_MODE_CBC; + return cipher && cipher_kt_mode(cipher) == OPENVPN_MODE_CBC; } bool cipher_kt_mode_ofb_cfb(const cipher_kt_t *cipher) { - return cipher && (cipher_kt_mode(cipher) == OPENVPN_MODE_OFB || - cipher_kt_mode(cipher) == OPENVPN_MODE_CFB); + return cipher && (cipher_kt_mode(cipher) == OPENVPN_MODE_OFB + || cipher_kt_mode(cipher) == OPENVPN_MODE_CFB); } bool cipher_kt_mode_aead(const cipher_kt_t *cipher) { - return cipher && cipher_kt_mode(cipher) == OPENVPN_MODE_GCM; + return cipher && cipher_kt_mode(cipher) == OPENVPN_MODE_GCM; } @@ -479,159 +511,197 @@ cipher_kt_mode_aead(const cipher_kt_t *cipher) void -cipher_ctx_init (mbedtls_cipher_context_t *ctx, uint8_t *key, int key_len, - const mbedtls_cipher_info_t *kt, const mbedtls_operation_t operation) +cipher_ctx_init(mbedtls_cipher_context_t *ctx, uint8_t *key, int key_len, + const mbedtls_cipher_info_t *kt, const mbedtls_operation_t operation) { - ASSERT(NULL != kt && NULL != ctx); + ASSERT(NULL != kt && NULL != ctx); - CLEAR (*ctx); + CLEAR(*ctx); - if (!mbed_ok(mbedtls_cipher_setup(ctx, kt))) - msg (M_FATAL, "mbed TLS cipher context init #1"); + if (!mbed_ok(mbedtls_cipher_setup(ctx, kt))) + { + msg(M_FATAL, "mbed TLS cipher context init #1"); + } - if (!mbed_ok(mbedtls_cipher_setkey(ctx, key, key_len*8, operation))) - msg (M_FATAL, "mbed TLS cipher set key"); + if (!mbed_ok(mbedtls_cipher_setkey(ctx, key, key_len*8, operation))) + { + msg(M_FATAL, "mbed TLS cipher set key"); + } - /* make sure we used a big enough key */ - ASSERT (ctx->key_bitlen <= key_len*8); + /* make sure we used a big enough key */ + ASSERT(ctx->key_bitlen <= key_len*8); } -void cipher_ctx_cleanup (mbedtls_cipher_context_t *ctx) +void +cipher_ctx_cleanup(mbedtls_cipher_context_t *ctx) { - mbedtls_cipher_free(ctx); + mbedtls_cipher_free(ctx); } -int cipher_ctx_iv_length (const mbedtls_cipher_context_t *ctx) +int +cipher_ctx_iv_length(const mbedtls_cipher_context_t *ctx) { - return mbedtls_cipher_get_iv_size(ctx); + return mbedtls_cipher_get_iv_size(ctx); } -int cipher_ctx_get_tag (cipher_ctx_t *ctx, uint8_t* tag, int tag_len) +int +cipher_ctx_get_tag(cipher_ctx_t *ctx, uint8_t *tag, int tag_len) { #ifdef HAVE_AEAD_CIPHER_MODES - if (tag_len > SIZE_MAX) - return 0; + if (tag_len > SIZE_MAX) + { + return 0; + } - if (!mbed_ok (mbedtls_cipher_write_tag (ctx, (unsigned char *) tag, tag_len))) - return 0; + if (!mbed_ok(mbedtls_cipher_write_tag(ctx, (unsigned char *) tag, tag_len))) + { + return 0; + } - return 1; -#else - ASSERT(0); + return 1; +#else /* ifdef HAVE_AEAD_CIPHER_MODES */ + ASSERT(0); #endif /* HAVE_AEAD_CIPHER_MODES */ } -int cipher_ctx_block_size(const mbedtls_cipher_context_t *ctx) +int +cipher_ctx_block_size(const mbedtls_cipher_context_t *ctx) { - return mbedtls_cipher_get_block_size(ctx); + return mbedtls_cipher_get_block_size(ctx); } -int cipher_ctx_mode (const mbedtls_cipher_context_t *ctx) +int +cipher_ctx_mode(const mbedtls_cipher_context_t *ctx) { - ASSERT(NULL != ctx); + ASSERT(NULL != ctx); - return cipher_kt_mode(ctx->cipher_info); + return cipher_kt_mode(ctx->cipher_info); } const cipher_kt_t * -cipher_ctx_get_cipher_kt (const cipher_ctx_t *ctx) +cipher_ctx_get_cipher_kt(const cipher_ctx_t *ctx) { - return ctx ? ctx->cipher_info : NULL; + return ctx ? ctx->cipher_info : NULL; } -int cipher_ctx_reset (mbedtls_cipher_context_t *ctx, uint8_t *iv_buf) +int +cipher_ctx_reset(mbedtls_cipher_context_t *ctx, uint8_t *iv_buf) { - if (!mbed_ok(mbedtls_cipher_reset(ctx))) - return 0; + if (!mbed_ok(mbedtls_cipher_reset(ctx))) + { + return 0; + } - if (!mbed_ok(mbedtls_cipher_set_iv(ctx, iv_buf, ctx->cipher_info->iv_size))) - return 0; + if (!mbed_ok(mbedtls_cipher_set_iv(ctx, iv_buf, ctx->cipher_info->iv_size))) + { + return 0; + } - return 1; + return 1; } -int cipher_ctx_update_ad (cipher_ctx_t *ctx, const uint8_t *src, int src_len) +int +cipher_ctx_update_ad(cipher_ctx_t *ctx, const uint8_t *src, int src_len) { #ifdef HAVE_AEAD_CIPHER_MODES - if (src_len > SIZE_MAX) - return 0; + if (src_len > SIZE_MAX) + { + return 0; + } - if (!mbed_ok (mbedtls_cipher_update_ad (ctx, src, src_len))) - return 0; + if (!mbed_ok(mbedtls_cipher_update_ad(ctx, src, src_len))) + { + return 0; + } - return 1; -#else - ASSERT(0); + return 1; +#else /* ifdef HAVE_AEAD_CIPHER_MODES */ + ASSERT(0); #endif /* HAVE_AEAD_CIPHER_MODES */ } -int cipher_ctx_update (mbedtls_cipher_context_t *ctx, uint8_t *dst, - int *dst_len, uint8_t *src, int src_len) +int +cipher_ctx_update(mbedtls_cipher_context_t *ctx, uint8_t *dst, + int *dst_len, uint8_t *src, int src_len) { - size_t s_dst_len = *dst_len; + size_t s_dst_len = *dst_len; - if (!mbed_ok(mbedtls_cipher_update(ctx, src, (size_t) src_len, dst, - &s_dst_len))) - return 0; + if (!mbed_ok(mbedtls_cipher_update(ctx, src, (size_t) src_len, dst, + &s_dst_len))) + { + return 0; + } - *dst_len = s_dst_len; + *dst_len = s_dst_len; - return 1; + return 1; } -int cipher_ctx_final (mbedtls_cipher_context_t *ctx, uint8_t *dst, int *dst_len) +int +cipher_ctx_final(mbedtls_cipher_context_t *ctx, uint8_t *dst, int *dst_len) { - size_t s_dst_len = *dst_len; + size_t s_dst_len = *dst_len; - if (!mbed_ok(mbedtls_cipher_finish(ctx, dst, &s_dst_len))) - return 0; + if (!mbed_ok(mbedtls_cipher_finish(ctx, dst, &s_dst_len))) + { + return 0; + } - *dst_len = s_dst_len; + *dst_len = s_dst_len; - return 1; + return 1; } -int cipher_ctx_final_check_tag (mbedtls_cipher_context_t *ctx, uint8_t *dst, - int *dst_len, uint8_t *tag, size_t tag_len) +int +cipher_ctx_final_check_tag(mbedtls_cipher_context_t *ctx, uint8_t *dst, + int *dst_len, uint8_t *tag, size_t tag_len) { #ifdef HAVE_AEAD_CIPHER_MODES - size_t olen = 0; + size_t olen = 0; - if (MBEDTLS_DECRYPT != ctx->operation) - return 0; + if (MBEDTLS_DECRYPT != ctx->operation) + { + return 0; + } - if (tag_len > SIZE_MAX) - return 0; + if (tag_len > SIZE_MAX) + { + return 0; + } - if (!mbed_ok (mbedtls_cipher_finish (ctx, dst, &olen))) + if (!mbed_ok(mbedtls_cipher_finish(ctx, dst, &olen))) { - msg (D_CRYPT_ERRORS, "%s: cipher_ctx_final() failed", __func__); - return 0; + msg(D_CRYPT_ERRORS, "%s: cipher_ctx_final() failed", __func__); + return 0; } - if (olen > INT_MAX) - return 0; - *dst_len = olen; + if (olen > INT_MAX) + { + return 0; + } + *dst_len = olen; - if (!mbed_ok (mbedtls_cipher_check_tag (ctx, (const unsigned char *) tag, - tag_len))) - return 0; + if (!mbed_ok(mbedtls_cipher_check_tag(ctx, (const unsigned char *) tag, + tag_len))) + { + return 0; + } - return 1; -#else - ASSERT(0); + return 1; +#else /* ifdef HAVE_AEAD_CIPHER_MODES */ + ASSERT(0); #endif /* HAVE_AEAD_CIPHER_MODES */ } void -cipher_des_encrypt_ecb (const unsigned char key[DES_KEY_LENGTH], - unsigned char *src, - unsigned char *dst) +cipher_des_encrypt_ecb(const unsigned char key[DES_KEY_LENGTH], + unsigned char *src, + unsigned char *dst) { - mbedtls_des_context ctx; + mbedtls_des_context ctx; - ASSERT (mbed_ok(mbedtls_des_setkey_enc(&ctx, key))); - ASSERT (mbed_ok(mbedtls_des_crypt_ecb(&ctx, src, dst))); + ASSERT(mbed_ok(mbedtls_des_setkey_enc(&ctx, key))); + ASSERT(mbed_ok(mbedtls_des_crypt_ecb(&ctx, src, dst))); } @@ -644,36 +714,44 @@ cipher_des_encrypt_ecb (const unsigned char key[DES_KEY_LENGTH], const mbedtls_md_info_t * -md_kt_get (const char *digest) +md_kt_get(const char *digest) { - const mbedtls_md_info_t *md = NULL; - ASSERT (digest); + const mbedtls_md_info_t *md = NULL; + ASSERT(digest); - md = mbedtls_md_info_from_string(digest); - if (!md) - msg (M_FATAL, "Message hash algorithm '%s' not found", digest); - if (mbedtls_md_get_size(md) > MAX_HMAC_KEY_LENGTH) - msg (M_FATAL, "Message hash algorithm '%s' uses a default hash size (%d bytes) which is larger than " PACKAGE_NAME "'s current maximum hash size (%d bytes)", - digest, - mbedtls_md_get_size(md), - MAX_HMAC_KEY_LENGTH); - return md; + md = mbedtls_md_info_from_string(digest); + if (!md) + { + msg(M_FATAL, "Message hash algorithm '%s' not found", digest); + } + if (mbedtls_md_get_size(md) > MAX_HMAC_KEY_LENGTH) + { + msg(M_FATAL, "Message hash algorithm '%s' uses a default hash size (%d bytes) which is larger than " PACKAGE_NAME "'s current maximum hash size (%d bytes)", + digest, + mbedtls_md_get_size(md), + MAX_HMAC_KEY_LENGTH); + } + return md; } const char * -md_kt_name (const mbedtls_md_info_t *kt) +md_kt_name(const mbedtls_md_info_t *kt) { - if (NULL == kt) - return "[null-digest]"; - return mbedtls_md_get_name (kt); + if (NULL == kt) + { + return "[null-digest]"; + } + return mbedtls_md_get_name(kt); } int -md_kt_size (const mbedtls_md_info_t *kt) +md_kt_size(const mbedtls_md_info_t *kt) { - if (NULL == kt) - return 0; - return mbedtls_md_get_size(kt); + if (NULL == kt) + { + return 0; + } + return mbedtls_md_get_size(kt); } /* @@ -683,20 +761,20 @@ md_kt_size (const mbedtls_md_info_t *kt) */ int -md_full (const md_kt_t *kt, const uint8_t *src, int src_len, uint8_t *dst) +md_full(const md_kt_t *kt, const uint8_t *src, int src_len, uint8_t *dst) { - return 0 == mbedtls_md(kt, src, src_len, dst); + return 0 == mbedtls_md(kt, src, src_len, dst); } void -md_ctx_init (mbedtls_md_context_t *ctx, const mbedtls_md_info_t *kt) +md_ctx_init(mbedtls_md_context_t *ctx, const mbedtls_md_info_t *kt) { - ASSERT(NULL != ctx && NULL != kt); + ASSERT(NULL != ctx && NULL != kt); - mbedtls_md_init(ctx); - ASSERT(0 == mbedtls_md_setup(ctx, kt, 0)); - ASSERT(0 == mbedtls_md_starts(ctx)); + mbedtls_md_init(ctx); + ASSERT(0 == mbedtls_md_setup(ctx, kt, 0)); + ASSERT(0 == mbedtls_md_starts(ctx)); } void @@ -705,24 +783,26 @@ md_ctx_cleanup(mbedtls_md_context_t *ctx) } int -md_ctx_size (const mbedtls_md_context_t *ctx) +md_ctx_size(const mbedtls_md_context_t *ctx) { - if (NULL == ctx) - return 0; - return mbedtls_md_get_size(ctx->md_info); + if (NULL == ctx) + { + return 0; + } + return mbedtls_md_get_size(ctx->md_info); } void -md_ctx_update (mbedtls_md_context_t *ctx, const uint8_t *src, int src_len) +md_ctx_update(mbedtls_md_context_t *ctx, const uint8_t *src, int src_len) { - ASSERT(0 == mbedtls_md_update(ctx, src, src_len)); + ASSERT(0 == mbedtls_md_update(ctx, src, src_len)); } void -md_ctx_final (mbedtls_md_context_t *ctx, uint8_t *dst) +md_ctx_final(mbedtls_md_context_t *ctx, uint8_t *dst) { - ASSERT(0 == mbedtls_md_finish(ctx, dst)); - mbedtls_md_free(ctx); + ASSERT(0 == mbedtls_md_finish(ctx, dst)); + mbedtls_md_free(ctx); } @@ -737,49 +817,51 @@ md_ctx_final (mbedtls_md_context_t *ctx, uint8_t *dst) * TODO: re-enable dmsg for crypto debug */ void -hmac_ctx_init (mbedtls_md_context_t *ctx, const uint8_t *key, int key_len, - const mbedtls_md_info_t *kt) +hmac_ctx_init(mbedtls_md_context_t *ctx, const uint8_t *key, int key_len, + const mbedtls_md_info_t *kt) { - ASSERT(NULL != kt && NULL != ctx); + ASSERT(NULL != kt && NULL != ctx); - mbedtls_md_init(ctx); - ASSERT(0 == mbedtls_md_setup(ctx, kt, 1)); - ASSERT(0 == mbedtls_md_hmac_starts(ctx, key, key_len)); + mbedtls_md_init(ctx); + ASSERT(0 == mbedtls_md_setup(ctx, kt, 1)); + ASSERT(0 == mbedtls_md_hmac_starts(ctx, key, key_len)); - /* make sure we used a big enough key */ - ASSERT (mbedtls_md_get_size(kt) <= key_len); + /* make sure we used a big enough key */ + ASSERT(mbedtls_md_get_size(kt) <= key_len); } void hmac_ctx_cleanup(mbedtls_md_context_t *ctx) { - mbedtls_md_free(ctx); + mbedtls_md_free(ctx); } int -hmac_ctx_size (const mbedtls_md_context_t *ctx) +hmac_ctx_size(const mbedtls_md_context_t *ctx) { - if (NULL == ctx) - return 0; - return mbedtls_md_get_size(ctx->md_info); + if (NULL == ctx) + { + return 0; + } + return mbedtls_md_get_size(ctx->md_info); } void -hmac_ctx_reset (mbedtls_md_context_t *ctx) +hmac_ctx_reset(mbedtls_md_context_t *ctx) { - ASSERT(0 == mbedtls_md_hmac_reset(ctx)); + ASSERT(0 == mbedtls_md_hmac_reset(ctx)); } void -hmac_ctx_update (mbedtls_md_context_t *ctx, const uint8_t *src, int src_len) +hmac_ctx_update(mbedtls_md_context_t *ctx, const uint8_t *src, int src_len) { - ASSERT(0 == mbedtls_md_hmac_update(ctx, src, src_len)); + ASSERT(0 == mbedtls_md_hmac_update(ctx, src, src_len)); } void -hmac_ctx_final (mbedtls_md_context_t *ctx, uint8_t *dst) +hmac_ctx_final(mbedtls_md_context_t *ctx, uint8_t *dst) { - ASSERT(0 == mbedtls_md_hmac_finish(ctx, dst)); + ASSERT(0 == mbedtls_md_hmac_finish(ctx, dst)); } #endif /* ENABLE_CRYPTO && ENABLE_CRYPTO_MBEDTLS */ diff --git a/src/openvpn/crypto_mbedtls.h b/src/openvpn/crypto_mbedtls.h index 574a63f127b..16f9007cc60 100644 --- a/src/openvpn/crypto_mbedtls.h +++ b/src/openvpn/crypto_mbedtls.h @@ -50,29 +50,29 @@ typedef mbedtls_md_context_t md_ctx_t; typedef mbedtls_md_context_t hmac_ctx_t; /** Maximum length of an IV */ -#define OPENVPN_MAX_IV_LENGTH MBEDTLS_MAX_IV_LENGTH +#define OPENVPN_MAX_IV_LENGTH MBEDTLS_MAX_IV_LENGTH /** Cipher is in CBC mode */ -#define OPENVPN_MODE_CBC MBEDTLS_MODE_CBC +#define OPENVPN_MODE_CBC MBEDTLS_MODE_CBC /** Cipher is in OFB mode */ -#define OPENVPN_MODE_OFB MBEDTLS_MODE_OFB +#define OPENVPN_MODE_OFB MBEDTLS_MODE_OFB /** Cipher is in CFB mode */ -#define OPENVPN_MODE_CFB MBEDTLS_MODE_CFB +#define OPENVPN_MODE_CFB MBEDTLS_MODE_CFB /** Cipher is in GCM mode */ -#define OPENVPN_MODE_GCM MBEDTLS_MODE_GCM +#define OPENVPN_MODE_GCM MBEDTLS_MODE_GCM /** Cipher should encrypt */ -#define OPENVPN_OP_ENCRYPT MBEDTLS_ENCRYPT +#define OPENVPN_OP_ENCRYPT MBEDTLS_ENCRYPT /** Cipher should decrypt */ -#define OPENVPN_OP_DECRYPT MBEDTLS_DECRYPT +#define OPENVPN_OP_DECRYPT MBEDTLS_DECRYPT -#define MD4_DIGEST_LENGTH 16 -#define MD5_DIGEST_LENGTH 16 -#define SHA_DIGEST_LENGTH 20 +#define MD4_DIGEST_LENGTH 16 +#define MD5_DIGEST_LENGTH 16 +#define SHA_DIGEST_LENGTH 20 #define DES_KEY_LENGTH 8 /** @@ -92,14 +92,15 @@ mbedtls_ctr_drbg_context *rand_ctx_get(); * Enable prediction resistance on the random number generator. */ void rand_ctx_enable_prediction_resistance(); + #endif /** * Log the supplied mbed TLS error, prefixed by supplied prefix. * - * @param flags Flags to indicate error type and priority. - * @param errval mbed TLS error code to convert to error message. - * @param prefix Prefix to mbed TLS error message. + * @param flags Flags to indicate error type and priority. + * @param errval mbed TLS error code to convert to error message. + * @param prefix Prefix to mbed TLS error message. * * @returns true if no errors are detected, false otherwise. */ @@ -108,23 +109,25 @@ bool mbed_log_err(unsigned int flags, int errval, const char *prefix); /** * Log the supplied mbed TLS error, prefixed by function name and line number. * - * @param flags Flags to indicate error type and priority. - * @param errval mbed TLS error code to convert to error message. - * @param func Function name where error was reported. - * @param line Line number where error was reported. + * @param flags Flags to indicate error type and priority. + * @param errval mbed TLS error code to convert to error message. + * @param func Function name where error was reported. + * @param line Line number where error was reported. * * @returns true if no errors are detected, false otherwise. */ bool mbed_log_func_line(unsigned int flags, int errval, const char *func, - int line); + int line); /** Wraps mbed_log_func_line() to prevent function calls for non-errors */ -static inline bool mbed_log_func_line_lite(unsigned int flags, int errval, - const char *func, int line) { - if (errval) { - return mbed_log_func_line (flags, errval, func, line); - } - return true; +static inline bool +mbed_log_func_line_lite(unsigned int flags, int errval, + const char *func, int line) { + if (errval) + { + return mbed_log_func_line(flags, errval, func, line); + } + return true; } /** @@ -135,12 +138,12 @@ static inline bool mbed_log_func_line_lite(unsigned int flags, int errval, * or * ASSERT (mbed_ok (mbedtls_ssl_func())); * - * @param errval mbed TLS error code to convert to error message. + * @param errval mbed TLS error code to convert to error message. * * @returns true if no errors are detected, false otherwise. */ #define mbed_ok(errval) \ - mbed_log_func_line_lite(D_CRYPT_ERRORS, errval, __func__, __LINE__) + mbed_log_func_line_lite(D_CRYPT_ERRORS, errval, __func__, __LINE__) #endif /* CRYPTO_MBEDTLS_H_ */ diff --git a/src/openvpn/crypto_openssl.c b/src/openvpn/crypto_openssl.c index 306b6c6cf1e..4e783167651 100644 --- a/src/openvpn/crypto_openssl.c +++ b/src/openvpn/crypto_openssl.c @@ -71,71 +71,71 @@ static ENGINE *engine_persist = NULL; /* GLOBAL */ /* Try to load an engine in a shareable library */ static ENGINE * -try_load_engine (const char *engine) +try_load_engine(const char *engine) { - ENGINE *e = ENGINE_by_id ("dynamic"); - if (e) + ENGINE *e = ENGINE_by_id("dynamic"); + if (e) { - if (!ENGINE_ctrl_cmd_string (e, "SO_PATH", engine, 0) - || !ENGINE_ctrl_cmd_string (e, "LOAD", NULL, 0)) - { - ENGINE_free (e); - e = NULL; - } + if (!ENGINE_ctrl_cmd_string(e, "SO_PATH", engine, 0) + || !ENGINE_ctrl_cmd_string(e, "LOAD", NULL, 0)) + { + ENGINE_free(e); + e = NULL; + } } - return e; + return e; } static ENGINE * -setup_engine (const char *engine) +setup_engine(const char *engine) { - ENGINE *e = NULL; + ENGINE *e = NULL; - ENGINE_load_builtin_engines (); + ENGINE_load_builtin_engines(); - if (engine) + if (engine) { - if (strcmp (engine, "auto") == 0) - { - msg (M_INFO, "Initializing OpenSSL auto engine support"); - ENGINE_register_all_complete (); - return NULL; - } - if ((e = ENGINE_by_id (engine)) == NULL - && (e = try_load_engine (engine)) == NULL) - { - crypto_msg (M_FATAL, "OpenSSL error: cannot load engine '%s'", - engine); - } - - if (!ENGINE_set_default (e, ENGINE_METHOD_ALL)) - { - crypto_msg (M_FATAL, - "OpenSSL error: ENGINE_set_default failed on engine '%s'", - engine); - } - - msg (M_INFO, "Initializing OpenSSL support for engine '%s'", - ENGINE_get_id (e)); + if (strcmp(engine, "auto") == 0) + { + msg(M_INFO, "Initializing OpenSSL auto engine support"); + ENGINE_register_all_complete(); + return NULL; + } + if ((e = ENGINE_by_id(engine)) == NULL + && (e = try_load_engine(engine)) == NULL) + { + crypto_msg(M_FATAL, "OpenSSL error: cannot load engine '%s'", + engine); + } + + if (!ENGINE_set_default(e, ENGINE_METHOD_ALL)) + { + crypto_msg(M_FATAL, + "OpenSSL error: ENGINE_set_default failed on engine '%s'", + engine); + } + + msg(M_INFO, "Initializing OpenSSL support for engine '%s'", + ENGINE_get_id(e)); } - return e; + return e; } #endif /* HAVE_OPENSSL_ENGINE */ void -crypto_init_lib_engine (const char *engine_name) +crypto_init_lib_engine(const char *engine_name) { #if HAVE_OPENSSL_ENGINE - if (!engine_initialized) + if (!engine_initialized) { - ASSERT (engine_name); - ASSERT (!engine_persist); - engine_persist = setup_engine (engine_name); - engine_initialized = true; + ASSERT(engine_name); + ASSERT(!engine_persist); + engine_persist = setup_engine(engine_name); + engine_initialized = true; } -#else - msg (M_WARN, "Note: OpenSSL hardware crypto engine functionality is not available"); +#else /* if HAVE_OPENSSL_ENGINE */ + msg(M_WARN, "Note: OpenSSL hardware crypto engine functionality is not available"); #endif } @@ -146,61 +146,61 @@ crypto_init_lib_engine (const char *engine_name) */ void -crypto_init_lib (void) +crypto_init_lib(void) { - /* - * If you build the OpenSSL library and OpenVPN with - * CRYPTO_MDEBUG, you will get a listing of OpenSSL - * memory leaks on program termination. - */ + /* + * If you build the OpenSSL library and OpenVPN with + * CRYPTO_MDEBUG, you will get a listing of OpenSSL + * memory leaks on program termination. + */ #ifdef CRYPTO_MDEBUG - CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON); + CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON); #endif } void -crypto_uninit_lib (void) +crypto_uninit_lib(void) { #ifdef CRYPTO_MDEBUG - FILE* fp = fopen ("sdlog", "w"); - ASSERT (fp); - CRYPTO_mem_leaks_fp (fp); - fclose (fp); + FILE *fp = fopen("sdlog", "w"); + ASSERT(fp); + CRYPTO_mem_leaks_fp(fp); + fclose(fp); #endif #if HAVE_OPENSSL_ENGINE - if (engine_initialized) + if (engine_initialized) { - ENGINE_cleanup (); - engine_persist = NULL; - engine_initialized = false; + ENGINE_cleanup(); + engine_persist = NULL; + engine_initialized = false; } #endif } void -crypto_clear_error (void) +crypto_clear_error(void) { - ERR_clear_error (); + ERR_clear_error(); } void crypto_print_openssl_errors(const unsigned int flags) { - size_t err = 0; + size_t err = 0; - while ((err = ERR_get_error ())) + while ((err = ERR_get_error())) { - /* Be more clear about frequently occurring "no shared cipher" error */ - if (err == ERR_PACK(ERR_LIB_SSL,SSL_F_SSL3_GET_CLIENT_HELLO, - SSL_R_NO_SHARED_CIPHER)) - { - msg (D_CRYPT_ERRORS, "TLS error: The server has no TLS ciphersuites " - "in common with the client. Your --tls-cipher setting might be " - "too restrictive."); - } - - msg (flags, "OpenSSL: %s", ERR_error_string (err, NULL)); + /* Be more clear about frequently occurring "no shared cipher" error */ + if (err == ERR_PACK(ERR_LIB_SSL,SSL_F_SSL3_GET_CLIENT_HELLO, + SSL_R_NO_SHARED_CIPHER)) + { + msg(D_CRYPT_ERRORS, "TLS error: The server has no TLS ciphersuites " + "in common with the client. Your --tls-cipher setting might be " + "too restrictive."); + } + + msg(flags, "OpenSSL: %s", ERR_error_string(err, NULL)); } } @@ -215,29 +215,29 @@ crypto_print_openssl_errors(const unsigned int flags) { #ifdef DMALLOC static void * -crypto_malloc (size_t size, const char *file, int line) +crypto_malloc(size_t size, const char *file, int line) { - return dmalloc_malloc(file, line, size, DMALLOC_FUNC_MALLOC, 0, 0); + return dmalloc_malloc(file, line, size, DMALLOC_FUNC_MALLOC, 0, 0); } static void * -crypto_realloc (void *ptr, size_t size, const char *file, int line) +crypto_realloc(void *ptr, size_t size, const char *file, int line) { - return dmalloc_realloc(file, line, ptr, size, DMALLOC_FUNC_REALLOC, 0); + return dmalloc_realloc(file, line, ptr, size, DMALLOC_FUNC_REALLOC, 0); } static void -crypto_free (void *ptr) +crypto_free(void *ptr) { - dmalloc_free (__FILE__, __LINE__, ptr, DMALLOC_FUNC_FREE); + dmalloc_free(__FILE__, __LINE__, ptr, DMALLOC_FUNC_FREE); } void -crypto_init_dmalloc (void) +crypto_init_dmalloc(void) { - CRYPTO_set_mem_ex_functions (crypto_malloc, - crypto_realloc, - crypto_free); + CRYPTO_set_mem_ex_functions(crypto_malloc, + crypto_realloc, + crypto_free); } #endif /* DMALLOC */ @@ -247,140 +247,144 @@ const cipher_name_pair cipher_name_translation_table[] = { { "AES-256-GCM", "id-aes256-GCM" }, }; const size_t cipher_name_translation_table_count = - sizeof (cipher_name_translation_table) / sizeof (*cipher_name_translation_table); + sizeof(cipher_name_translation_table) / sizeof(*cipher_name_translation_table); static int cipher_name_cmp(const void *a, const void *b) { - const EVP_CIPHER * const *cipher_a = a; - const EVP_CIPHER * const *cipher_b = b; + const EVP_CIPHER *const *cipher_a = a; + const EVP_CIPHER *const *cipher_b = b; - const char *cipher_name_a = - translate_cipher_name_to_openvpn(EVP_CIPHER_name(*cipher_a)); - const char *cipher_name_b = - translate_cipher_name_to_openvpn(EVP_CIPHER_name(*cipher_b)); + const char *cipher_name_a = + translate_cipher_name_to_openvpn(EVP_CIPHER_name(*cipher_a)); + const char *cipher_name_b = + translate_cipher_name_to_openvpn(EVP_CIPHER_name(*cipher_b)); - return strcmp(cipher_name_a, cipher_name_b); + return strcmp(cipher_name_a, cipher_name_b); } static void print_cipher(const EVP_CIPHER *cipher) { - const char *var_key_size = - (EVP_CIPHER_flags (cipher) & EVP_CIPH_VARIABLE_LENGTH) ? - " by default" : ""; - const char *ssl_only = cipher_kt_mode_cbc(cipher) ? - "" : ", TLS client/server mode only"; + const char *var_key_size = + (EVP_CIPHER_flags(cipher) & EVP_CIPH_VARIABLE_LENGTH) ? + " by default" : ""; + const char *ssl_only = cipher_kt_mode_cbc(cipher) ? + "" : ", TLS client/server mode only"; - printf ("%s (%d bit key%s, %d bit block%s)\n", - translate_cipher_name_to_openvpn (EVP_CIPHER_name (cipher)), - EVP_CIPHER_key_length (cipher) * 8, var_key_size, - cipher_kt_block_size (cipher) * 8, ssl_only); + printf("%s (%d bit key%s, %d bit block%s)\n", + translate_cipher_name_to_openvpn(EVP_CIPHER_name(cipher)), + EVP_CIPHER_key_length(cipher) * 8, var_key_size, + cipher_kt_block_size(cipher) * 8, ssl_only); } void -show_available_ciphers () +show_available_ciphers() { - int nid; - size_t i; + int nid; + size_t i; - /* If we ever exceed this, we must be more selective */ - const size_t cipher_list_len = 1000; - const EVP_CIPHER *cipher_list[cipher_list_len]; - size_t num_ciphers = 0; + /* If we ever exceed this, we must be more selective */ + const size_t cipher_list_len = 1000; + const EVP_CIPHER *cipher_list[cipher_list_len]; + size_t num_ciphers = 0; #ifndef ENABLE_SMALL - printf ("The following ciphers and cipher modes are available for use\n" - "with " PACKAGE_NAME ". Each cipher shown below may be use as a\n" - "parameter to the --cipher option. The default key size is\n" - "shown as well as whether or not it can be changed with the\n" - "--keysize directive. Using a CBC or GCM mode is recommended.\n" - "In static key mode only CBC mode is allowed.\n\n"); + printf("The following ciphers and cipher modes are available for use\n" + "with " PACKAGE_NAME ". Each cipher shown below may be use as a\n" + "parameter to the --cipher option. The default key size is\n" + "shown as well as whether or not it can be changed with the\n" + "--keysize directive. Using a CBC or GCM mode is recommended.\n" + "In static key mode only CBC mode is allowed.\n\n"); #endif - for (nid = 0; nid < 10000; ++nid) + for (nid = 0; nid < 10000; ++nid) { - const EVP_CIPHER *cipher = EVP_get_cipherbynid(nid); - if (cipher && (cipher_kt_mode_cbc(cipher) + const EVP_CIPHER *cipher = EVP_get_cipherbynid(nid); + if (cipher && (cipher_kt_mode_cbc(cipher) #ifdef ENABLE_OFB_CFB_MODE - || cipher_kt_mode_ofb_cfb(cipher) + || cipher_kt_mode_ofb_cfb(cipher) #endif #ifdef HAVE_AEAD_CIPHER_MODES - || cipher_kt_mode_aead(cipher) + || cipher_kt_mode_aead(cipher) #endif - )) - { - cipher_list[num_ciphers++] = cipher; - } - if (num_ciphers == cipher_list_len) - { - msg (M_WARN, "WARNING: Too many ciphers, not showing all"); - break; - } + )) + { + cipher_list[num_ciphers++] = cipher; + } + if (num_ciphers == cipher_list_len) + { + msg(M_WARN, "WARNING: Too many ciphers, not showing all"); + break; + } } - qsort (cipher_list, num_ciphers, sizeof(*cipher_list), cipher_name_cmp); + qsort(cipher_list, num_ciphers, sizeof(*cipher_list), cipher_name_cmp); - for (i = 0; i < num_ciphers; i++) { - if (cipher_kt_block_size(cipher_list[i]) >= 128/8) - print_cipher(cipher_list[i]); - } + for (i = 0; i < num_ciphers; i++) { + if (cipher_kt_block_size(cipher_list[i]) >= 128/8) + { + print_cipher(cipher_list[i]); + } + } - printf ("\nThe following ciphers have a block size of less than 128 bits, \n" - "and are therefore deprecated. Do not use unless you have to.\n\n"); - for (i = 0; i < num_ciphers; i++) { - if (cipher_kt_block_size(cipher_list[i]) < 128/8) - print_cipher(cipher_list[i]); - } - printf ("\n"); + printf("\nThe following ciphers have a block size of less than 128 bits, \n" + "and are therefore deprecated. Do not use unless you have to.\n\n"); + for (i = 0; i < num_ciphers; i++) { + if (cipher_kt_block_size(cipher_list[i]) < 128/8) + { + print_cipher(cipher_list[i]); + } + } + printf("\n"); } void -show_available_digests () +show_available_digests() { - int nid; + int nid; #ifndef ENABLE_SMALL - printf ("The following message digests are available for use with\n" - PACKAGE_NAME ". A message digest is used in conjunction with\n" - "the HMAC function, to authenticate received packets.\n" - "You can specify a message digest as parameter to\n" - "the --auth option.\n\n"); + printf("The following message digests are available for use with\n" + PACKAGE_NAME ". A message digest is used in conjunction with\n" + "the HMAC function, to authenticate received packets.\n" + "You can specify a message digest as parameter to\n" + "the --auth option.\n\n"); #endif - for (nid = 0; nid < 10000; ++nid) + for (nid = 0; nid < 10000; ++nid) { - const EVP_MD *digest = EVP_get_digestbynid (nid); - if (digest) - { - printf ("%s %d bit digest size\n", - OBJ_nid2sn (nid), EVP_MD_size (digest) * 8); - } + const EVP_MD *digest = EVP_get_digestbynid(nid); + if (digest) + { + printf("%s %d bit digest size\n", + OBJ_nid2sn(nid), EVP_MD_size(digest) * 8); + } } - printf ("\n"); + printf("\n"); } void -show_available_engines () +show_available_engines() { #if HAVE_OPENSSL_ENGINE /* Only defined for OpenSSL */ - ENGINE *e; + ENGINE *e; - printf ("OpenSSL Crypto Engines\n\n"); + printf("OpenSSL Crypto Engines\n\n"); - ENGINE_load_builtin_engines (); + ENGINE_load_builtin_engines(); - e = ENGINE_get_first (); - while (e) + e = ENGINE_get_first(); + while (e) { - printf ("%s [%s]\n", - ENGINE_get_name (e), - ENGINE_get_id (e)); - e = ENGINE_get_next (e); + printf("%s [%s]\n", + ENGINE_get_name(e), + ENGINE_get_id(e)); + e = ENGINE_get_next(e); } - ENGINE_cleanup (); -#else - printf ("Sorry, OpenSSL hardware crypto engine functionality is not available.\n"); + ENGINE_cleanup(); +#else /* if HAVE_OPENSSL_ENGINE */ + printf("Sorry, OpenSSL hardware crypto engine functionality is not available.\n"); #endif } @@ -393,14 +397,15 @@ show_available_engines () * */ -int rand_bytes(uint8_t *output, int len) +int +rand_bytes(uint8_t *output, int len) { - if (unlikely(1 != RAND_bytes (output, len))) + if (unlikely(1 != RAND_bytes(output, len))) { - crypto_msg(D_CRYPT_ERRORS, "RAND_bytes() failed"); - return 0; + crypto_msg(D_CRYPT_ERRORS, "RAND_bytes() failed"); + return 0; } - return 1; + return 1; } /* @@ -411,79 +416,79 @@ int rand_bytes(uint8_t *output, int len) int -key_des_num_cblocks (const EVP_CIPHER *kt) +key_des_num_cblocks(const EVP_CIPHER *kt) { - int ret = 0; - const char *name = OBJ_nid2sn (EVP_CIPHER_nid (kt)); - if (name) + int ret = 0; + const char *name = OBJ_nid2sn(EVP_CIPHER_nid(kt)); + if (name) { - if (!strncmp (name, "DES-", 4)) - { - ret = EVP_CIPHER_key_length (kt) / sizeof (DES_cblock); - } - else if (!strncmp (name, "DESX-", 5)) - { - ret = 1; - } + if (!strncmp(name, "DES-", 4)) + { + ret = EVP_CIPHER_key_length(kt) / sizeof(DES_cblock); + } + else if (!strncmp(name, "DESX-", 5)) + { + ret = 1; + } } - dmsg (D_CRYPTO_DEBUG, "CRYPTO INFO: n_DES_cblocks=%d", ret); - return ret; + dmsg(D_CRYPTO_DEBUG, "CRYPTO INFO: n_DES_cblocks=%d", ret); + return ret; } bool -key_des_check (uint8_t *key, int key_len, int ndc) +key_des_check(uint8_t *key, int key_len, int ndc) { - int i; - struct buffer b; + int i; + struct buffer b; - buf_set_read (&b, key, key_len); + buf_set_read(&b, key, key_len); - for (i = 0; i < ndc; ++i) + for (i = 0; i < ndc; ++i) { - DES_cblock *dc = (DES_cblock*) buf_read_alloc (&b, sizeof (DES_cblock)); - if (!dc) - { - crypto_msg (D_CRYPT_ERRORS, - "CRYPTO INFO: check_key_DES: insufficient key material"); - goto err; - } - if (DES_is_weak_key(dc)) - { - crypto_msg (D_CRYPT_ERRORS, - "CRYPTO INFO: check_key_DES: weak key detected"); - goto err; - } - if (!DES_check_key_parity (dc)) - { - crypto_msg (D_CRYPT_ERRORS, - "CRYPTO INFO: check_key_DES: bad parity detected"); - goto err; - } + DES_cblock *dc = (DES_cblock *) buf_read_alloc(&b, sizeof(DES_cblock)); + if (!dc) + { + crypto_msg(D_CRYPT_ERRORS, + "CRYPTO INFO: check_key_DES: insufficient key material"); + goto err; + } + if (DES_is_weak_key(dc)) + { + crypto_msg(D_CRYPT_ERRORS, + "CRYPTO INFO: check_key_DES: weak key detected"); + goto err; + } + if (!DES_check_key_parity(dc)) + { + crypto_msg(D_CRYPT_ERRORS, + "CRYPTO INFO: check_key_DES: bad parity detected"); + goto err; + } } - return true; + return true; - err: - ERR_clear_error (); - return false; +err: + ERR_clear_error(); + return false; } void -key_des_fixup (uint8_t *key, int key_len, int ndc) +key_des_fixup(uint8_t *key, int key_len, int ndc) { - int i; - struct buffer b; + int i; + struct buffer b; - buf_set_read (&b, key, key_len); - for (i = 0; i < ndc; ++i) + buf_set_read(&b, key, key_len); + for (i = 0; i < ndc; ++i) { - DES_cblock *dc = (DES_cblock*) buf_read_alloc(&b, sizeof(DES_cblock)); - if (!dc) - { - msg (D_CRYPT_ERRORS, "CRYPTO INFO: fixup_key_DES: insufficient key material"); - ERR_clear_error (); - return; - } - DES_set_odd_parity (dc); + DES_cblock *dc = (DES_cblock *) buf_read_alloc(&b, sizeof(DES_cblock)); + if (!dc) + { + msg(D_CRYPT_ERRORS, "CRYPTO INFO: fixup_key_DES: insufficient key material"); + ERR_clear_error(); + return; + } + DES_set_odd_parity(dc); } } @@ -496,110 +501,122 @@ key_des_fixup (uint8_t *key, int key_len, int ndc) const EVP_CIPHER * -cipher_kt_get (const char *ciphername) +cipher_kt_get(const char *ciphername) { - const EVP_CIPHER *cipher = NULL; + const EVP_CIPHER *cipher = NULL; - ASSERT (ciphername); + ASSERT(ciphername); - cipher = EVP_get_cipherbyname (ciphername); + cipher = EVP_get_cipherbyname(ciphername); - if (NULL == cipher) + if (NULL == cipher) { - crypto_msg (D_LOW, "Cipher algorithm '%s' not found", ciphername); - return NULL; + crypto_msg(D_LOW, "Cipher algorithm '%s' not found", ciphername); + return NULL; } - if (EVP_CIPHER_key_length (cipher) > MAX_CIPHER_KEY_LENGTH) + if (EVP_CIPHER_key_length(cipher) > MAX_CIPHER_KEY_LENGTH) { - msg (D_LOW, "Cipher algorithm '%s' uses a default key size (%d bytes) " - "which is larger than " PACKAGE_NAME "'s current maximum key size " - "(%d bytes)", ciphername, EVP_CIPHER_key_length (cipher), - MAX_CIPHER_KEY_LENGTH); - return NULL; + msg(D_LOW, "Cipher algorithm '%s' uses a default key size (%d bytes) " + "which is larger than " PACKAGE_NAME "'s current maximum key size " + "(%d bytes)", ciphername, EVP_CIPHER_key_length(cipher), + MAX_CIPHER_KEY_LENGTH); + return NULL; } - return cipher; + return cipher; } const char * -cipher_kt_name (const EVP_CIPHER *cipher_kt) +cipher_kt_name(const EVP_CIPHER *cipher_kt) { - if (NULL == cipher_kt) - return "[null-cipher]"; - return EVP_CIPHER_name (cipher_kt); + if (NULL == cipher_kt) + { + return "[null-cipher]"; + } + return EVP_CIPHER_name(cipher_kt); } int -cipher_kt_key_size (const EVP_CIPHER *cipher_kt) +cipher_kt_key_size(const EVP_CIPHER *cipher_kt) { - return EVP_CIPHER_key_length (cipher_kt); + return EVP_CIPHER_key_length(cipher_kt); } int -cipher_kt_iv_size (const EVP_CIPHER *cipher_kt) +cipher_kt_iv_size(const EVP_CIPHER *cipher_kt) { - return EVP_CIPHER_iv_length (cipher_kt); + return EVP_CIPHER_iv_length(cipher_kt); } int -cipher_kt_block_size (const EVP_CIPHER *cipher) { - /* OpenSSL reports OFB/CFB/GCM cipher block sizes as '1 byte'. To work - * around that, try to replace the mode with 'CBC' and return the block size - * reported for that cipher, if possible. If that doesn't work, just return - * the value reported by OpenSSL. - */ - char *name = NULL; - char *mode_str = NULL; - const char *orig_name = NULL; - const EVP_CIPHER *cbc_cipher = NULL; - - int block_size = EVP_CIPHER_block_size(cipher); - - orig_name = cipher_kt_name(cipher); - if (!orig_name) - goto cleanup; - - name = string_alloc(translate_cipher_name_to_openvpn(orig_name), NULL); - mode_str = strrchr (name, '-'); - if (!mode_str || strlen(mode_str) < 4) - goto cleanup; - - strcpy (mode_str, "-CBC"); - - cbc_cipher = EVP_get_cipherbyname(translate_cipher_name_from_openvpn(name)); - if (cbc_cipher) - block_size = EVP_CIPHER_block_size(cbc_cipher); +cipher_kt_block_size(const EVP_CIPHER *cipher) { + /* OpenSSL reports OFB/CFB/GCM cipher block sizes as '1 byte'. To work + * around that, try to replace the mode with 'CBC' and return the block size + * reported for that cipher, if possible. If that doesn't work, just return + * the value reported by OpenSSL. + */ + char *name = NULL; + char *mode_str = NULL; + const char *orig_name = NULL; + const EVP_CIPHER *cbc_cipher = NULL; + + int block_size = EVP_CIPHER_block_size(cipher); + + orig_name = cipher_kt_name(cipher); + if (!orig_name) + { + goto cleanup; + } + + name = string_alloc(translate_cipher_name_to_openvpn(orig_name), NULL); + mode_str = strrchr(name, '-'); + if (!mode_str || strlen(mode_str) < 4) + { + goto cleanup; + } + + strcpy(mode_str, "-CBC"); + + cbc_cipher = EVP_get_cipherbyname(translate_cipher_name_from_openvpn(name)); + if (cbc_cipher) + { + block_size = EVP_CIPHER_block_size(cbc_cipher); + } cleanup: - free (name); - return block_size; + free(name); + return block_size; } int -cipher_kt_tag_size (const EVP_CIPHER *cipher_kt) +cipher_kt_tag_size(const EVP_CIPHER *cipher_kt) { - if (cipher_kt_mode_aead(cipher_kt)) - return OPENVPN_AEAD_TAG_LENGTH; - else - return 0; + if (cipher_kt_mode_aead(cipher_kt)) + { + return OPENVPN_AEAD_TAG_LENGTH; + } + else + { + return 0; + } } int -cipher_kt_mode (const EVP_CIPHER *cipher_kt) +cipher_kt_mode(const EVP_CIPHER *cipher_kt) { - ASSERT(NULL != cipher_kt); - return EVP_CIPHER_mode (cipher_kt); + ASSERT(NULL != cipher_kt); + return EVP_CIPHER_mode(cipher_kt); } bool cipher_kt_mode_cbc(const cipher_kt_t *cipher) { - return cipher && cipher_kt_mode(cipher) == OPENVPN_MODE_CBC + return cipher && cipher_kt_mode(cipher) == OPENVPN_MODE_CBC #ifdef EVP_CIPH_FLAG_AEAD_CIPHER - /* Exclude AEAD cipher modes, they require a different API */ - && !(EVP_CIPHER_flags(cipher) & EVP_CIPH_FLAG_AEAD_CIPHER) + /* Exclude AEAD cipher modes, they require a different API */ + && !(EVP_CIPHER_flags(cipher) & EVP_CIPH_FLAG_AEAD_CIPHER) #endif ; } @@ -607,11 +624,11 @@ cipher_kt_mode_cbc(const cipher_kt_t *cipher) bool cipher_kt_mode_ofb_cfb(const cipher_kt_t *cipher) { - return cipher && (cipher_kt_mode(cipher) == OPENVPN_MODE_OFB || - cipher_kt_mode(cipher) == OPENVPN_MODE_CFB) + return cipher && (cipher_kt_mode(cipher) == OPENVPN_MODE_OFB + || cipher_kt_mode(cipher) == OPENVPN_MODE_CFB) #ifdef EVP_CIPH_FLAG_AEAD_CIPHER - /* Exclude AEAD cipher modes, they require a different API */ - && !(EVP_CIPHER_flags(cipher) & EVP_CIPH_FLAG_AEAD_CIPHER) + /* Exclude AEAD cipher modes, they require a different API */ + && !(EVP_CIPHER_flags(cipher) & EVP_CIPH_FLAG_AEAD_CIPHER) #endif ; } @@ -620,9 +637,9 @@ bool cipher_kt_mode_aead(const cipher_kt_t *cipher) { #ifdef HAVE_AEAD_CIPHER_MODES - return cipher && (cipher_kt_mode(cipher) == OPENVPN_MODE_GCM); + return cipher && (cipher_kt_mode(cipher) == OPENVPN_MODE_GCM); #else - return false; + return false; #endif } @@ -634,124 +651,137 @@ cipher_kt_mode_aead(const cipher_kt_t *cipher) void -cipher_ctx_init (EVP_CIPHER_CTX *ctx, uint8_t *key, int key_len, - const EVP_CIPHER *kt, int enc) +cipher_ctx_init(EVP_CIPHER_CTX *ctx, uint8_t *key, int key_len, + const EVP_CIPHER *kt, int enc) { - ASSERT(NULL != kt && NULL != ctx); + ASSERT(NULL != kt && NULL != ctx); - CLEAR (*ctx); + CLEAR(*ctx); - EVP_CIPHER_CTX_init (ctx); - if (!EVP_CipherInit (ctx, kt, NULL, NULL, enc)) - crypto_msg (M_FATAL, "EVP cipher init #1"); + EVP_CIPHER_CTX_init(ctx); + if (!EVP_CipherInit(ctx, kt, NULL, NULL, enc)) + { + crypto_msg(M_FATAL, "EVP cipher init #1"); + } #ifdef HAVE_EVP_CIPHER_CTX_SET_KEY_LENGTH - if (!EVP_CIPHER_CTX_set_key_length (ctx, key_len)) - crypto_msg (M_FATAL, "EVP set key size"); + if (!EVP_CIPHER_CTX_set_key_length(ctx, key_len)) + { + crypto_msg(M_FATAL, "EVP set key size"); + } #endif - if (!EVP_CipherInit (ctx, NULL, key, NULL, enc)) - crypto_msg (M_FATAL, "EVP cipher init #2"); + if (!EVP_CipherInit(ctx, NULL, key, NULL, enc)) + { + crypto_msg(M_FATAL, "EVP cipher init #2"); + } - /* make sure we used a big enough key */ - ASSERT (EVP_CIPHER_CTX_key_length (ctx) <= key_len); + /* make sure we used a big enough key */ + ASSERT(EVP_CIPHER_CTX_key_length(ctx) <= key_len); } void -cipher_ctx_cleanup (EVP_CIPHER_CTX *ctx) +cipher_ctx_cleanup(EVP_CIPHER_CTX *ctx) { - EVP_CIPHER_CTX_cleanup (ctx); + EVP_CIPHER_CTX_cleanup(ctx); } int -cipher_ctx_iv_length (const EVP_CIPHER_CTX *ctx) +cipher_ctx_iv_length(const EVP_CIPHER_CTX *ctx) { - return EVP_CIPHER_CTX_iv_length (ctx); + return EVP_CIPHER_CTX_iv_length(ctx); } -int cipher_ctx_get_tag (EVP_CIPHER_CTX *ctx, uint8_t *tag_buf, int tag_size) +int +cipher_ctx_get_tag(EVP_CIPHER_CTX *ctx, uint8_t *tag_buf, int tag_size) { #ifdef HAVE_AEAD_CIPHER_MODES - return EVP_CIPHER_CTX_ctrl (ctx, EVP_CTRL_GCM_GET_TAG, tag_size, tag_buf); + return EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, tag_size, tag_buf); #else - ASSERT (0); + ASSERT(0); #endif } int cipher_ctx_block_size(const EVP_CIPHER_CTX *ctx) { - return EVP_CIPHER_CTX_block_size (ctx); + return EVP_CIPHER_CTX_block_size(ctx); } int -cipher_ctx_mode (const EVP_CIPHER_CTX *ctx) +cipher_ctx_mode(const EVP_CIPHER_CTX *ctx) { - return EVP_CIPHER_CTX_mode (ctx); + return EVP_CIPHER_CTX_mode(ctx); } const cipher_kt_t * -cipher_ctx_get_cipher_kt (const cipher_ctx_t *ctx) +cipher_ctx_get_cipher_kt(const cipher_ctx_t *ctx) { - return ctx ? EVP_CIPHER_CTX_cipher(ctx) : NULL; + return ctx ? EVP_CIPHER_CTX_cipher(ctx) : NULL; } int -cipher_ctx_reset (EVP_CIPHER_CTX *ctx, uint8_t *iv_buf) +cipher_ctx_reset(EVP_CIPHER_CTX *ctx, uint8_t *iv_buf) { - return EVP_CipherInit (ctx, NULL, NULL, iv_buf, -1); + return EVP_CipherInit(ctx, NULL, NULL, iv_buf, -1); } int -cipher_ctx_update_ad (EVP_CIPHER_CTX *ctx, const uint8_t *src, int src_len) +cipher_ctx_update_ad(EVP_CIPHER_CTX *ctx, const uint8_t *src, int src_len) { #ifdef HAVE_AEAD_CIPHER_MODES - int len; - if (!EVP_CipherUpdate (ctx, NULL, &len, src, src_len)) - crypto_msg(M_FATAL, "%s: EVP_CipherUpdate() failed", __func__); - return 1; -#else - ASSERT (0); + int len; + if (!EVP_CipherUpdate(ctx, NULL, &len, src, src_len)) + { + crypto_msg(M_FATAL, "%s: EVP_CipherUpdate() failed", __func__); + } + return 1; +#else /* ifdef HAVE_AEAD_CIPHER_MODES */ + ASSERT(0); #endif } int -cipher_ctx_update (EVP_CIPHER_CTX *ctx, uint8_t *dst, int *dst_len, - uint8_t *src, int src_len) +cipher_ctx_update(EVP_CIPHER_CTX *ctx, uint8_t *dst, int *dst_len, + uint8_t *src, int src_len) { - if (!EVP_CipherUpdate (ctx, dst, dst_len, src, src_len)) - crypto_msg(M_FATAL, "%s: EVP_CipherUpdate() failed", __func__); - return 1; + if (!EVP_CipherUpdate(ctx, dst, dst_len, src, src_len)) + { + crypto_msg(M_FATAL, "%s: EVP_CipherUpdate() failed", __func__); + } + return 1; } int -cipher_ctx_final (EVP_CIPHER_CTX *ctx, uint8_t *dst, int *dst_len) +cipher_ctx_final(EVP_CIPHER_CTX *ctx, uint8_t *dst, int *dst_len) { - return EVP_CipherFinal (ctx, dst, dst_len); + return EVP_CipherFinal(ctx, dst, dst_len); } int -cipher_ctx_final_check_tag (EVP_CIPHER_CTX *ctx, uint8_t *dst, int *dst_len, - uint8_t *tag, size_t tag_len) +cipher_ctx_final_check_tag(EVP_CIPHER_CTX *ctx, uint8_t *dst, int *dst_len, + uint8_t *tag, size_t tag_len) { #ifdef HAVE_AEAD_CIPHER_MODES - ASSERT (tag_len < SIZE_MAX); - if (!EVP_CIPHER_CTX_ctrl (ctx, EVP_CTRL_GCM_SET_TAG, tag_len, tag)) - return 0; + ASSERT(tag_len < SIZE_MAX); + if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, tag_len, tag)) + { + return 0; + } - return cipher_ctx_final (ctx, dst, dst_len); -#else - ASSERT (0); + return cipher_ctx_final(ctx, dst, dst_len); +#else /* ifdef HAVE_AEAD_CIPHER_MODES */ + ASSERT(0); #endif } void -cipher_des_encrypt_ecb (const unsigned char key[DES_KEY_LENGTH], - unsigned char *src, - unsigned char *dst) +cipher_des_encrypt_ecb(const unsigned char key[DES_KEY_LENGTH], + unsigned char *src, + unsigned char *dst) { DES_key_schedule sched; - DES_set_key_unchecked((DES_cblock*)key, &sched); + DES_set_key_unchecked((DES_cblock *)key, &sched); DES_ecb_encrypt((DES_cblock *)src, (DES_cblock *)dst, &sched, DES_ENCRYPT); } @@ -763,35 +793,39 @@ cipher_des_encrypt_ecb (const unsigned char key[DES_KEY_LENGTH], const EVP_MD * -md_kt_get (const char *digest) -{ - const EVP_MD *md = NULL; - ASSERT (digest); - md = EVP_get_digestbyname (digest); - if (!md) - crypto_msg (M_FATAL, "Message hash algorithm '%s' not found", digest); - if (EVP_MD_size (md) > MAX_HMAC_KEY_LENGTH) +md_kt_get(const char *digest) +{ + const EVP_MD *md = NULL; + ASSERT(digest); + md = EVP_get_digestbyname(digest); + if (!md) + { + crypto_msg(M_FATAL, "Message hash algorithm '%s' not found", digest); + } + if (EVP_MD_size(md) > MAX_HMAC_KEY_LENGTH) { - crypto_msg (M_FATAL, "Message hash algorithm '%s' uses a default hash " - "size (%d bytes) which is larger than " PACKAGE_NAME "'s current " - "maximum hash size (%d bytes)", - digest, EVP_MD_size (md), MAX_HMAC_KEY_LENGTH); + crypto_msg(M_FATAL, "Message hash algorithm '%s' uses a default hash " + "size (%d bytes) which is larger than " PACKAGE_NAME "'s current " + "maximum hash size (%d bytes)", + digest, EVP_MD_size(md), MAX_HMAC_KEY_LENGTH); } - return md; + return md; } const char * -md_kt_name (const EVP_MD *kt) +md_kt_name(const EVP_MD *kt) { - if (NULL == kt) - return "[null-digest]"; - return EVP_MD_name (kt); + if (NULL == kt) + { + return "[null-digest]"; + } + return EVP_MD_name(kt); } int -md_kt_size (const EVP_MD *kt) +md_kt_size(const EVP_MD *kt) { - return EVP_MD_size(kt); + return EVP_MD_size(kt); } @@ -802,48 +836,48 @@ md_kt_size (const EVP_MD *kt) */ int -md_full (const EVP_MD *kt, const uint8_t *src, int src_len, uint8_t *dst) +md_full(const EVP_MD *kt, const uint8_t *src, int src_len, uint8_t *dst) { - unsigned int in_md_len = 0; + unsigned int in_md_len = 0; - return EVP_Digest(src, src_len, dst, &in_md_len, kt, NULL); + return EVP_Digest(src, src_len, dst, &in_md_len, kt, NULL); } void -md_ctx_init (EVP_MD_CTX *ctx, const EVP_MD *kt) +md_ctx_init(EVP_MD_CTX *ctx, const EVP_MD *kt) { - ASSERT(NULL != ctx && NULL != kt); + ASSERT(NULL != ctx && NULL != kt); - CLEAR (*ctx); + CLEAR(*ctx); - EVP_MD_CTX_init (ctx); - EVP_DigestInit(ctx, kt); + EVP_MD_CTX_init(ctx); + EVP_DigestInit(ctx, kt); } void md_ctx_cleanup(EVP_MD_CTX *ctx) { - EVP_MD_CTX_cleanup(ctx); + EVP_MD_CTX_cleanup(ctx); } int -md_ctx_size (const EVP_MD_CTX *ctx) +md_ctx_size(const EVP_MD_CTX *ctx) { - return EVP_MD_CTX_size(ctx); + return EVP_MD_CTX_size(ctx); } void -md_ctx_update (EVP_MD_CTX *ctx, const uint8_t *src, int src_len) +md_ctx_update(EVP_MD_CTX *ctx, const uint8_t *src, int src_len) { - EVP_DigestUpdate(ctx, src, src_len); + EVP_DigestUpdate(ctx, src, src_len); } void -md_ctx_final (EVP_MD_CTX *ctx, uint8_t *dst) +md_ctx_final(EVP_MD_CTX *ctx, uint8_t *dst) { - unsigned int in_md_len = 0; + unsigned int in_md_len = 0; - EVP_DigestFinal(ctx, dst, &in_md_len); + EVP_DigestFinal(ctx, dst, &in_md_len); } @@ -855,50 +889,50 @@ md_ctx_final (EVP_MD_CTX *ctx, uint8_t *dst) void -hmac_ctx_init (HMAC_CTX *ctx, const uint8_t *key, int key_len, - const EVP_MD *kt) +hmac_ctx_init(HMAC_CTX *ctx, const uint8_t *key, int key_len, + const EVP_MD *kt) { - ASSERT(NULL != kt && NULL != ctx); + ASSERT(NULL != kt && NULL != ctx); - CLEAR(*ctx); + CLEAR(*ctx); - HMAC_CTX_init (ctx); - HMAC_Init_ex (ctx, key, key_len, kt, NULL); + HMAC_CTX_init(ctx); + HMAC_Init_ex(ctx, key, key_len, kt, NULL); - /* make sure we used a big enough key */ - ASSERT (HMAC_size (ctx) <= key_len); + /* make sure we used a big enough key */ + ASSERT(HMAC_size(ctx) <= key_len); } void hmac_ctx_cleanup(HMAC_CTX *ctx) { - HMAC_CTX_cleanup (ctx); + HMAC_CTX_cleanup(ctx); } int -hmac_ctx_size (const HMAC_CTX *ctx) +hmac_ctx_size(const HMAC_CTX *ctx) { - return HMAC_size (ctx); + return HMAC_size(ctx); } void -hmac_ctx_reset (HMAC_CTX *ctx) +hmac_ctx_reset(HMAC_CTX *ctx) { - HMAC_Init_ex (ctx, NULL, 0, NULL, NULL); + HMAC_Init_ex(ctx, NULL, 0, NULL, NULL); } void -hmac_ctx_update (HMAC_CTX *ctx, const uint8_t *src, int src_len) +hmac_ctx_update(HMAC_CTX *ctx, const uint8_t *src, int src_len) { - HMAC_Update (ctx, src, src_len); + HMAC_Update(ctx, src, src_len); } void -hmac_ctx_final (HMAC_CTX *ctx, uint8_t *dst) +hmac_ctx_final(HMAC_CTX *ctx, uint8_t *dst) { - unsigned int in_hmac_len = 0; + unsigned int in_hmac_len = 0; - HMAC_Final (ctx, dst, &in_hmac_len); + HMAC_Final(ctx, dst, &in_hmac_len); } #endif /* ENABLE_CRYPTO && ENABLE_CRYPTO_OPENSSL */ diff --git a/src/openvpn/crypto_openssl.h b/src/openvpn/crypto_openssl.h index f157041713e..6cf009e2253 100644 --- a/src/openvpn/crypto_openssl.h +++ b/src/openvpn/crypto_openssl.h @@ -50,39 +50,39 @@ typedef EVP_MD_CTX md_ctx_t; typedef HMAC_CTX hmac_ctx_t; /** Maximum length of an IV */ -#define OPENVPN_MAX_IV_LENGTH EVP_MAX_IV_LENGTH +#define OPENVPN_MAX_IV_LENGTH EVP_MAX_IV_LENGTH /** Cipher is in CBC mode */ -#define OPENVPN_MODE_CBC EVP_CIPH_CBC_MODE +#define OPENVPN_MODE_CBC EVP_CIPH_CBC_MODE /** Cipher is in OFB mode */ -#define OPENVPN_MODE_OFB EVP_CIPH_OFB_MODE +#define OPENVPN_MODE_OFB EVP_CIPH_OFB_MODE /** Cipher is in CFB mode */ -#define OPENVPN_MODE_CFB EVP_CIPH_CFB_MODE +#define OPENVPN_MODE_CFB EVP_CIPH_CFB_MODE #ifdef HAVE_AEAD_CIPHER_MODES /** Cipher is in GCM mode */ -#define OPENVPN_MODE_GCM EVP_CIPH_GCM_MODE +#define OPENVPN_MODE_GCM EVP_CIPH_GCM_MODE #endif /* HAVE_AEAD_CIPHER_MODES */ /** Cipher should encrypt */ -#define OPENVPN_OP_ENCRYPT 1 +#define OPENVPN_OP_ENCRYPT 1 /** Cipher should decrypt */ -#define OPENVPN_OP_DECRYPT 0 +#define OPENVPN_OP_DECRYPT 0 #define DES_KEY_LENGTH 8 -#define MD4_DIGEST_LENGTH 16 +#define MD4_DIGEST_LENGTH 16 /** * Retrieve any occurred OpenSSL errors and print those errors. * * Note that this function uses the not thread-safe OpenSSL error API. * - * @param flags Flags to indicate error type and priority. + * @param flags Flags to indicate error type and priority. */ void crypto_print_openssl_errors(const unsigned int flags); @@ -91,15 +91,15 @@ void crypto_print_openssl_errors(const unsigned int flags); * * This is just a convenience wrapper for often occurring situations. * - * @param flags Flags to indicate error type and priority. - * @param format Format string to print. - * @param format args (optional) arguments for the format string. + * @param flags Flags to indicate error type and priority. + * @param format Format string to print. + * @param format args (optional) arguments for the format string. */ -# define crypto_msg(flags, ...) \ -do { \ - crypto_print_openssl_errors(nonfatal(flags)); \ - msg((flags), __VA_ARGS__); \ -} while (false) +#define crypto_msg(flags, ...) \ + do { \ + crypto_print_openssl_errors(nonfatal(flags)); \ + msg((flags), __VA_ARGS__); \ + } while (false) #endif /* CRYPTO_OPENSSL_H_ */ diff --git a/src/openvpn/cryptoapi.c b/src/openvpn/cryptoapi.c index e107bd3f761..69a5a32df68 100644 --- a/src/openvpn/cryptoapi.c +++ b/src/openvpn/cryptoapi.c @@ -68,32 +68,32 @@ #endif /* Size of an SSL signature: MD5+SHA1 */ -#define SSL_SIG_LENGTH 36 +#define SSL_SIG_LENGTH 36 /* try to funnel any Windows/CryptoAPI error messages to OpenSSL ERR_... */ -#define ERR_LIB_CRYPTOAPI (ERR_LIB_USER + 69) /* 69 is just a number... */ +#define ERR_LIB_CRYPTOAPI (ERR_LIB_USER + 69) /* 69 is just a number... */ #define CRYPTOAPIerr(f) err_put_ms_error(GetLastError(), (f), __FILE__, __LINE__) -#define CRYPTOAPI_F_CERT_OPEN_SYSTEM_STORE 100 -#define CRYPTOAPI_F_CERT_FIND_CERTIFICATE_IN_STORE 101 +#define CRYPTOAPI_F_CERT_OPEN_SYSTEM_STORE 100 +#define CRYPTOAPI_F_CERT_FIND_CERTIFICATE_IN_STORE 101 #define CRYPTOAPI_F_CRYPT_ACQUIRE_CERTIFICATE_PRIVATE_KEY 102 -#define CRYPTOAPI_F_CRYPT_CREATE_HASH 103 -#define CRYPTOAPI_F_CRYPT_GET_HASH_PARAM 104 -#define CRYPTOAPI_F_CRYPT_SET_HASH_PARAM 105 -#define CRYPTOAPI_F_CRYPT_SIGN_HASH 106 -#define CRYPTOAPI_F_LOAD_LIBRARY 107 -#define CRYPTOAPI_F_GET_PROC_ADDRESS 108 - -static ERR_STRING_DATA CRYPTOAPI_str_functs[] = { - { ERR_PACK(ERR_LIB_CRYPTOAPI, 0, 0), "microsoft cryptoapi"}, - { ERR_PACK(0, CRYPTOAPI_F_CERT_OPEN_SYSTEM_STORE, 0), "CertOpenSystemStore" }, - { ERR_PACK(0, CRYPTOAPI_F_CERT_FIND_CERTIFICATE_IN_STORE, 0), "CertFindCertificateInStore" }, +#define CRYPTOAPI_F_CRYPT_CREATE_HASH 103 +#define CRYPTOAPI_F_CRYPT_GET_HASH_PARAM 104 +#define CRYPTOAPI_F_CRYPT_SET_HASH_PARAM 105 +#define CRYPTOAPI_F_CRYPT_SIGN_HASH 106 +#define CRYPTOAPI_F_LOAD_LIBRARY 107 +#define CRYPTOAPI_F_GET_PROC_ADDRESS 108 + +static ERR_STRING_DATA CRYPTOAPI_str_functs[] = { + { ERR_PACK(ERR_LIB_CRYPTOAPI, 0, 0), "microsoft cryptoapi"}, + { ERR_PACK(0, CRYPTOAPI_F_CERT_OPEN_SYSTEM_STORE, 0), "CertOpenSystemStore" }, + { ERR_PACK(0, CRYPTOAPI_F_CERT_FIND_CERTIFICATE_IN_STORE, 0), "CertFindCertificateInStore" }, { ERR_PACK(0, CRYPTOAPI_F_CRYPT_ACQUIRE_CERTIFICATE_PRIVATE_KEY, 0), "CryptAcquireCertificatePrivateKey" }, - { ERR_PACK(0, CRYPTOAPI_F_CRYPT_CREATE_HASH, 0), "CryptCreateHash" }, - { ERR_PACK(0, CRYPTOAPI_F_CRYPT_GET_HASH_PARAM, 0), "CryptGetHashParam" }, - { ERR_PACK(0, CRYPTOAPI_F_CRYPT_SET_HASH_PARAM, 0), "CryptSetHashParam" }, - { ERR_PACK(0, CRYPTOAPI_F_CRYPT_SIGN_HASH, 0), "CryptSignHash" }, - { ERR_PACK(0, CRYPTOAPI_F_LOAD_LIBRARY, 0), "LoadLibrary" }, - { ERR_PACK(0, CRYPTOAPI_F_GET_PROC_ADDRESS, 0), "GetProcAddress" }, + { ERR_PACK(0, CRYPTOAPI_F_CRYPT_CREATE_HASH, 0), "CryptCreateHash" }, + { ERR_PACK(0, CRYPTOAPI_F_CRYPT_GET_HASH_PARAM, 0), "CryptGetHashParam" }, + { ERR_PACK(0, CRYPTOAPI_F_CRYPT_SET_HASH_PARAM, 0), "CryptSetHashParam" }, + { ERR_PACK(0, CRYPTOAPI_F_CRYPT_SIGN_HASH, 0), "CryptSignHash" }, + { ERR_PACK(0, CRYPTOAPI_F_LOAD_LIBRARY, 0), "LoadLibrary" }, + { ERR_PACK(0, CRYPTOAPI_F_GET_PROC_ADDRESS, 0), "GetProcAddress" }, { 0, NULL } }; @@ -104,76 +104,94 @@ typedef struct _CAPI_DATA { BOOL free_crypt_prov; } CAPI_DATA; -static char *ms_error_text(DWORD ms_err) +static char * +ms_error_text(DWORD ms_err) { LPVOID lpMsgBuf = NULL; char *rv = NULL; FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, ms_err, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */ - (LPTSTR) &lpMsgBuf, 0, NULL); - if (lpMsgBuf) { - char *p; - rv = string_alloc(lpMsgBuf, NULL); - LocalFree(lpMsgBuf); - /* trim to the left */ - if (rv) - for (p = rv + strlen(rv) - 1; p >= rv; p--) { - if (isspace(*p)) - *p = '\0'; - else - break; - } + FORMAT_MESSAGE_ALLOCATE_BUFFER + |FORMAT_MESSAGE_FROM_SYSTEM + |FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, ms_err, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */ + (LPTSTR) &lpMsgBuf, 0, NULL); + if (lpMsgBuf) + { + char *p; + rv = string_alloc(lpMsgBuf, NULL); + LocalFree(lpMsgBuf); + /* trim to the left */ + if (rv) + { + for (p = rv + strlen(rv) - 1; p >= rv; p--) { + if (isspace(*p)) + { + *p = '\0'; + } + else + { + break; + } + } + } } return rv; } -static void err_put_ms_error(DWORD ms_err, int func, const char *file, int line) +static void +err_put_ms_error(DWORD ms_err, int func, const char *file, int line) { static int init = 0; -# define ERR_MAP_SZ 16 +#define ERR_MAP_SZ 16 static struct { - int err; - DWORD ms_err; /* I don't think we get more than 16 *different* errors */ + int err; + DWORD ms_err; /* I don't think we get more than 16 *different* errors */ } err_map[ERR_MAP_SZ]; /* in here, before we give up the whole thing... */ int i; if (ms_err == 0) - /* 0 is not an error */ - return; - if (!init) { - ERR_load_strings(ERR_LIB_CRYPTOAPI, CRYPTOAPI_str_functs); - memset(&err_map, 0, sizeof(err_map)); - init++; + { + /* 0 is not an error */ + return; + } + if (!init) + { + ERR_load_strings(ERR_LIB_CRYPTOAPI, CRYPTOAPI_str_functs); + memset(&err_map, 0, sizeof(err_map)); + init++; } /* since MS error codes are 32 bit, and the ones in the ERR_... system is * only 12, we must have a mapping table between them. */ for (i = 0; i < ERR_MAP_SZ; i++) { - if (err_map[i].ms_err == ms_err) { - ERR_PUT_error(ERR_LIB_CRYPTOAPI, func, err_map[i].err, file, line); - break; - } else if (err_map[i].ms_err == 0 ) { - /* end of table, add new entry */ - ERR_STRING_DATA *esd = calloc(2, sizeof(*esd)); - if (esd == NULL) - break; - err_map[i].ms_err = ms_err; - err_map[i].err = esd->error = i + 100; - esd->string = ms_error_text(ms_err); - check_malloc_return(esd->string); - ERR_load_strings(ERR_LIB_CRYPTOAPI, esd); - ERR_PUT_error(ERR_LIB_CRYPTOAPI, func, err_map[i].err, file, line); - break; - } + if (err_map[i].ms_err == ms_err) + { + ERR_PUT_error(ERR_LIB_CRYPTOAPI, func, err_map[i].err, file, line); + break; + } + else if (err_map[i].ms_err == 0) + { + /* end of table, add new entry */ + ERR_STRING_DATA *esd = calloc(2, sizeof(*esd)); + if (esd == NULL) + { + break; + } + err_map[i].ms_err = ms_err; + err_map[i].err = esd->error = i + 100; + esd->string = ms_error_text(ms_err); + check_malloc_return(esd->string); + ERR_load_strings(ERR_LIB_CRYPTOAPI, esd); + ERR_PUT_error(ERR_LIB_CRYPTOAPI, func, err_map[i].err, file, line); + break; + } } } /* encrypt */ -static int rsa_pub_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) +static int +rsa_pub_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) { /* I haven't been able to trigger this one, but I want to know if it happens... */ assert(0); @@ -182,7 +200,8 @@ static int rsa_pub_enc(int flen, const unsigned char *from, unsigned char *to, R } /* verify arbitrary data */ -static int rsa_pub_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) +static int +rsa_pub_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) { /* I haven't been able to trigger this one, but I want to know if it happens... */ assert(0); @@ -191,68 +210,78 @@ static int rsa_pub_dec(int flen, const unsigned char *from, unsigned char *to, R } /* sign arbitrary data */ -static int rsa_priv_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) +static int +rsa_priv_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) { CAPI_DATA *cd = (CAPI_DATA *) rsa->meth->app_data; HCRYPTHASH hash; DWORD hash_size, len, i; unsigned char *buf; - if (cd == NULL) { - RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, ERR_R_PASSED_NULL_PARAMETER); - return 0; + if (cd == NULL) + { + RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, ERR_R_PASSED_NULL_PARAMETER); + return 0; } - if (padding != RSA_PKCS1_PADDING) { - /* AFAICS, CryptSignHash() *always* uses PKCS1 padding. */ - RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, RSA_R_UNKNOWN_PADDING_TYPE); - return 0; + if (padding != RSA_PKCS1_PADDING) + { + /* AFAICS, CryptSignHash() *always* uses PKCS1 padding. */ + RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, RSA_R_UNKNOWN_PADDING_TYPE); + return 0; } /* Unfortunately, there is no "CryptSign()" function in CryptoAPI, that would * be way to straightforward for M$, I guess... So we have to do it this * tricky way instead, by creating a "Hash", and load the already-made hash * from 'from' into it. */ /* For now, we only support NID_md5_sha1 */ - if (flen != SSL_SIG_LENGTH) { - RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, RSA_R_INVALID_MESSAGE_LENGTH); - return 0; + if (flen != SSL_SIG_LENGTH) + { + RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, RSA_R_INVALID_MESSAGE_LENGTH); + return 0; } - if (!CryptCreateHash(cd->crypt_prov, CALG_SSL3_SHAMD5, 0, 0, &hash)) { - CRYPTOAPIerr(CRYPTOAPI_F_CRYPT_CREATE_HASH); - return 0; + if (!CryptCreateHash(cd->crypt_prov, CALG_SSL3_SHAMD5, 0, 0, &hash)) + { + CRYPTOAPIerr(CRYPTOAPI_F_CRYPT_CREATE_HASH); + return 0; } len = sizeof(hash_size); - if (!CryptGetHashParam(hash, HP_HASHSIZE, (BYTE *) &hash_size, &len, 0)) { - CRYPTOAPIerr(CRYPTOAPI_F_CRYPT_GET_HASH_PARAM); + if (!CryptGetHashParam(hash, HP_HASHSIZE, (BYTE *) &hash_size, &len, 0)) + { + CRYPTOAPIerr(CRYPTOAPI_F_CRYPT_GET_HASH_PARAM); CryptDestroyHash(hash); - return 0; + return 0; } - if ((int) hash_size != flen) { - RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, RSA_R_INVALID_MESSAGE_LENGTH); + if ((int) hash_size != flen) + { + RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, RSA_R_INVALID_MESSAGE_LENGTH); CryptDestroyHash(hash); - return 0; + return 0; } - if (!CryptSetHashParam(hash, HP_HASHVAL, (BYTE * ) from, 0)) { - CRYPTOAPIerr(CRYPTOAPI_F_CRYPT_SET_HASH_PARAM); + if (!CryptSetHashParam(hash, HP_HASHVAL, (BYTE * ) from, 0)) + { + CRYPTOAPIerr(CRYPTOAPI_F_CRYPT_SET_HASH_PARAM); CryptDestroyHash(hash); - return 0; + return 0; } len = RSA_size(rsa); buf = malloc(len); - if (buf == NULL) { - RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, ERR_R_MALLOC_FAILURE); + if (buf == NULL) + { + RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, ERR_R_MALLOC_FAILURE); CryptDestroyHash(hash); - return 0; + return 0; } - if (!CryptSignHash(hash, cd->key_spec, NULL, 0, buf, &len)) { - CRYPTOAPIerr(CRYPTOAPI_F_CRYPT_SIGN_HASH); + if (!CryptSignHash(hash, cd->key_spec, NULL, 0, buf, &len)) + { + CRYPTOAPIerr(CRYPTOAPI_F_CRYPT_SIGN_HASH); CryptDestroyHash(hash); free(buf); - return 0; + return 0; } /* and now, we have to reverse the byte-order in the result from CryptSignHash()... */ for (i = 0; i < len; i++) - to[i] = buf[len - i - 1]; + to[i] = buf[len - i - 1]; free(buf); CryptDestroyHash(hash); @@ -260,7 +289,8 @@ static int rsa_priv_enc(int flen, const unsigned char *from, unsigned char *to, } /* decrypt */ -static int rsa_priv_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) +static int +rsa_priv_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) { /* I haven't been able to trigger this one, but I want to know if it happens... */ assert(0); @@ -269,30 +299,39 @@ static int rsa_priv_dec(int flen, const unsigned char *from, unsigned char *to, } /* called at RSA_new */ -static int init(RSA *rsa) +static int +init(RSA *rsa) { return 0; } /* called at RSA_free */ -static int finish(RSA *rsa) +static int +finish(RSA *rsa) { CAPI_DATA *cd = (CAPI_DATA *) rsa->meth->app_data; if (cd == NULL) - return 0; + { + return 0; + } if (cd->crypt_prov && cd->free_crypt_prov) - CryptReleaseContext(cd->crypt_prov, 0); + { + CryptReleaseContext(cd->crypt_prov, 0); + } if (cd->cert_context) - CertFreeCertificateContext(cd->cert_context); + { + CertFreeCertificateContext(cd->cert_context); + } free(rsa->meth->app_data); free((char *) rsa->meth); rsa->meth = NULL; return 1; } -static const CERT_CONTEXT *find_certificate_in_store(const char *cert_prop, HCERTSTORE cert_store) +static const CERT_CONTEXT * +find_certificate_in_store(const char *cert_prop, HCERTSTORE cert_store) { /* Find, and use, the desired certificate from the store. The * 'cert_prop' certificate search string can look like this: @@ -302,50 +341,68 @@ static const CERT_CONTEXT *find_certificate_in_store(const char *cert_prop, HCER */ const CERT_CONTEXT *rv = NULL; - if (!strncmp(cert_prop, "SUBJ:", 5)) { - /* skip the tag */ - cert_prop += 5; - rv = CertFindCertificateInStore(cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, - 0, CERT_FIND_SUBJECT_STR_A, cert_prop, NULL); - - } else if (!strncmp(cert_prop, "THUMB:", 6)) { - unsigned char hash[255]; - char *p; - int i, x = 0; - CRYPT_HASH_BLOB blob; - - /* skip the tag */ - cert_prop += 6; - for (p = (char *) cert_prop, i = 0; *p && i < sizeof(hash); i++) { - if (*p >= '0' && *p <= '9') - x = (*p - '0') << 4; - else if (*p >= 'A' && *p <= 'F') - x = (*p - 'A' + 10) << 4; - else if (*p >= 'a' && *p <= 'f') - x = (*p - 'a' + 10) << 4; - if (!*++p) /* unexpected end of string */ - break; - if (*p >= '0' && *p <= '9') - x += *p - '0'; - else if (*p >= 'A' && *p <= 'F') - x += *p - 'A' + 10; - else if (*p >= 'a' && *p <= 'f') - x += *p - 'a' + 10; - hash[i] = x; - /* skip any space(s) between hex numbers */ - for (p++; *p && *p == ' '; p++); - } - blob.cbData = i; - blob.pbData = (unsigned char *) &hash; - rv = CertFindCertificateInStore(cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, - 0, CERT_FIND_HASH, &blob, NULL); + if (!strncmp(cert_prop, "SUBJ:", 5)) + { + /* skip the tag */ + cert_prop += 5; + rv = CertFindCertificateInStore(cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, + 0, CERT_FIND_SUBJECT_STR_A, cert_prop, NULL); + + } + else if (!strncmp(cert_prop, "THUMB:", 6)) + { + unsigned char hash[255]; + char *p; + int i, x = 0; + CRYPT_HASH_BLOB blob; + + /* skip the tag */ + cert_prop += 6; + for (p = (char *) cert_prop, i = 0; *p && i < sizeof(hash); i++) { + if (*p >= '0' && *p <= '9') + { + x = (*p - '0') << 4; + } + else if (*p >= 'A' && *p <= 'F') + { + x = (*p - 'A' + 10) << 4; + } + else if (*p >= 'a' && *p <= 'f') + { + x = (*p - 'a' + 10) << 4; + } + if (!*++p) /* unexpected end of string */ + { + break; + } + if (*p >= '0' && *p <= '9') + { + x += *p - '0'; + } + else if (*p >= 'A' && *p <= 'F') + { + x += *p - 'A' + 10; + } + else if (*p >= 'a' && *p <= 'f') + { + x += *p - 'a' + 10; + } + hash[i] = x; + /* skip any space(s) between hex numbers */ + for (p++; *p && *p == ' '; p++) ; + } + blob.cbData = i; + blob.pbData = (unsigned char *) &hash; + rv = CertFindCertificateInStore(cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, + 0, CERT_FIND_HASH, &blob, NULL); } return rv; } -int SSL_CTX_use_CryptoAPI_certificate(SSL_CTX *ssl_ctx, const char *cert_prop) +int +SSL_CTX_use_CryptoAPI_certificate(SSL_CTX *ssl_ctx, const char *cert_prop) { HCERTSTORE cs; X509 *cert = NULL; @@ -353,50 +410,57 @@ int SSL_CTX_use_CryptoAPI_certificate(SSL_CTX *ssl_ctx, const char *cert_prop) CAPI_DATA *cd = calloc(1, sizeof(*cd)); RSA_METHOD *my_rsa_method = calloc(1, sizeof(*my_rsa_method)); - if (cd == NULL || my_rsa_method == NULL) { - SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_MALLOC_FAILURE); - goto err; + if (cd == NULL || my_rsa_method == NULL) + { + SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_MALLOC_FAILURE); + goto err; } /* search CURRENT_USER first, then LOCAL_MACHINE */ - cs = CertOpenStore((LPCSTR) CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_CURRENT_USER | - CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG, L"MY"); - if (cs == NULL) { - CRYPTOAPIerr(CRYPTOAPI_F_CERT_OPEN_SYSTEM_STORE); - goto err; + cs = CertOpenStore((LPCSTR) CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_CURRENT_USER + |CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG, L"MY"); + if (cs == NULL) + { + CRYPTOAPIerr(CRYPTOAPI_F_CERT_OPEN_SYSTEM_STORE); + goto err; } cd->cert_context = find_certificate_in_store(cert_prop, cs); CertCloseStore(cs, 0); - if (!cd->cert_context) { - cs = CertOpenStore((LPCSTR) CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_LOCAL_MACHINE | - CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG, L"MY"); - if (cs == NULL) { - CRYPTOAPIerr(CRYPTOAPI_F_CERT_OPEN_SYSTEM_STORE); - goto err; - } - cd->cert_context = find_certificate_in_store(cert_prop, cs); - CertCloseStore(cs, 0); - if (cd->cert_context == NULL) { - CRYPTOAPIerr(CRYPTOAPI_F_CERT_FIND_CERTIFICATE_IN_STORE); - goto err; - } + if (!cd->cert_context) + { + cs = CertOpenStore((LPCSTR) CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_LOCAL_MACHINE + |CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG, L"MY"); + if (cs == NULL) + { + CRYPTOAPIerr(CRYPTOAPI_F_CERT_OPEN_SYSTEM_STORE); + goto err; + } + cd->cert_context = find_certificate_in_store(cert_prop, cs); + CertCloseStore(cs, 0); + if (cd->cert_context == NULL) + { + CRYPTOAPIerr(CRYPTOAPI_F_CERT_FIND_CERTIFICATE_IN_STORE); + goto err; + } } /* cert_context->pbCertEncoded is the cert X509 DER encoded. */ cert = d2i_X509(NULL, (const unsigned char **) &cd->cert_context->pbCertEncoded, - cd->cert_context->cbCertEncoded); - if (cert == NULL) { - SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_ASN1_LIB); - goto err; + cd->cert_context->cbCertEncoded); + if (cert == NULL) + { + SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_ASN1_LIB); + goto err; } /* set up stuff to use the private key */ if (!CryptAcquireCertificatePrivateKey(cd->cert_context, CRYPT_ACQUIRE_COMPARE_KEY_FLAG, - NULL, &cd->crypt_prov, &cd->key_spec, &cd->free_crypt_prov)) { - /* if we don't have a smart card reader here, and we try to access a - * smart card certificate, we get: - * "Error 1223: The operation was canceled by the user." */ - CRYPTOAPIerr(CRYPTOAPI_F_CRYPT_ACQUIRE_CERTIFICATE_PRIVATE_KEY); - goto err; + NULL, &cd->crypt_prov, &cd->key_spec, &cd->free_crypt_prov)) + { + /* if we don't have a smart card reader here, and we try to access a + * smart card certificate, we get: + * "Error 1223: The operation was canceled by the user." */ + CRYPTOAPIerr(CRYPTOAPI_F_CRYPT_ACQUIRE_CERTIFICATE_PRIVATE_KEY); + goto err; } /* here we don't need to do CryptGetUserKey() or anything; all necessary key * info is in cd->cert_context, and then, in cd->crypt_prov. */ @@ -412,15 +476,18 @@ int SSL_CTX_use_CryptoAPI_certificate(SSL_CTX *ssl_ctx, const char *cert_prop) my_rsa_method->app_data = (char *) cd; rsa = RSA_new(); - if (rsa == NULL) { - SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_MALLOC_FAILURE); - goto err; + if (rsa == NULL) + { + SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_MALLOC_FAILURE); + goto err; } /* cert->cert_info->key->pkey is NULL until we call SSL_CTX_use_certificate(), * so we do it here then... */ if (!SSL_CTX_use_certificate(ssl_ctx, cert)) - goto err; + { + goto err; + } /* the public key */ pub_rsa = cert->cert_info->key->pkey->pkey.rsa; /* SSL_CTX_use_certificate() increased the reference count in 'cert', so @@ -433,36 +500,54 @@ int SSL_CTX_use_CryptoAPI_certificate(SSL_CTX *ssl_ctx, const char *cert_prop) rsa->n = BN_dup(pub_rsa->n); rsa->flags |= RSA_FLAG_EXT_PKEY; if (!RSA_set_method(rsa, my_rsa_method)) - goto err; + { + goto err; + } if (!SSL_CTX_use_RSAPrivateKey(ssl_ctx, rsa)) - goto err; + { + goto err; + } /* SSL_CTX_use_RSAPrivateKey() increased the reference count in 'rsa', so - * we decrease it here with RSA_free(), or it will never be cleaned up. */ + * we decrease it here with RSA_free(), or it will never be cleaned up. */ RSA_free(rsa); return 1; - err: +err: if (cert) - X509_free(cert); + { + X509_free(cert); + } if (rsa) - RSA_free(rsa); - else { - if (my_rsa_method) - free(my_rsa_method); - if (cd) { - if (cd->free_crypt_prov && cd->crypt_prov) - CryptReleaseContext(cd->crypt_prov, 0); - if (cd->cert_context) - CertFreeCertificateContext(cd->cert_context); - free(cd); - } + { + RSA_free(rsa); + } + else + { + if (my_rsa_method) + { + free(my_rsa_method); + } + if (cd) + { + if (cd->free_crypt_prov && cd->crypt_prov) + { + CryptReleaseContext(cd->crypt_prov, 0); + } + if (cd->cert_context) + { + CertFreeCertificateContext(cd->cert_context); + } + free(cd); + } } return 0; } -#else +#else /* ifdef ENABLE_CRYPTOAPI */ #ifdef _MSC_VER /* Dummy function needed to avoid empty file compiler warning in Microsoft VC */ -static void dummy (void) {} +static void +dummy(void) { +} #endif -#endif /* _WIN32 */ +#endif /* _WIN32 */ diff --git a/src/openvpn/dhcp.c b/src/openvpn/dhcp.c index 8d0b18ac6cf..9c706ed9f94 100644 --- a/src/openvpn/dhcp.c +++ b/src/openvpn/dhcp.c @@ -37,176 +37,193 @@ #include "memdbg.h" static int -get_dhcp_message_type (const struct dhcp *dhcp, const int optlen) +get_dhcp_message_type(const struct dhcp *dhcp, const int optlen) { - const uint8_t *p = (uint8_t *) (dhcp + 1); - int i; + const uint8_t *p = (uint8_t *) (dhcp + 1); + int i; - for (i = 0; i < optlen; ++i) + for (i = 0; i < optlen; ++i) { - const uint8_t type = p[i]; - const int room = optlen - i; - if (type == DHCP_END) /* didn't find what we were looking for */ - return -1; - else if (type == DHCP_PAD) /* no-operation */ - ; - else if (type == DHCP_MSG_TYPE) /* what we are looking for */ - { - if (room >= 3) - { - if (p[i+1] == 1) /* option length should be 1 */ - return p[i+2]; /* return message type */ - } - return -1; - } - else /* some other option */ - { - if (room >= 2) - { - const int len = p[i+1]; /* get option length */ - i += (len + 1); /* advance to next option */ - } - } + const uint8_t type = p[i]; + const int room = optlen - i; + if (type == DHCP_END) /* didn't find what we were looking for */ + { + return -1; + } + else if (type == DHCP_PAD) /* no-operation */ + { + } + else if (type == DHCP_MSG_TYPE) /* what we are looking for */ + { + if (room >= 3) + { + if (p[i+1] == 1) /* option length should be 1 */ + { + return p[i+2]; /* return message type */ + } + } + return -1; + } + else /* some other option */ + { + if (room >= 2) + { + const int len = p[i+1]; /* get option length */ + i += (len + 1); /* advance to next option */ + } + } } - return -1; + return -1; } static in_addr_t -do_extract (struct dhcp *dhcp, int optlen) +do_extract(struct dhcp *dhcp, int optlen) { - uint8_t *p = (uint8_t *) (dhcp + 1); - int i; - in_addr_t ret = 0; + uint8_t *p = (uint8_t *) (dhcp + 1); + int i; + in_addr_t ret = 0; - for (i = 0; i < optlen; ) + for (i = 0; i < optlen; ) { - const uint8_t type = p[i]; - const int room = optlen - i; - if (type == DHCP_END) - break; - else if (type == DHCP_PAD) - ++i; - else if (type == DHCP_ROUTER) - { - if (room >= 2) - { - const int len = p[i+1]; /* get option length */ - if (len <= (room-2)) - { - /* get router IP address */ - if (!ret && len >= 4 && (len & 3) == 0) - { - memcpy (&ret, p+i+2, 4); - ret = ntohl (ret); - } - { - /* delete the router option */ - uint8_t *dest = p + i; - const int owlen = len + 2; /* len of data to overwrite */ - uint8_t *src = dest + owlen; - uint8_t *end = p + optlen; - const int movlen = end - src; - if (movlen > 0) - memmove(dest, src, movlen); /* overwrite router option */ - memset(end - owlen, DHCP_PAD, owlen); /* pad tail */ - } - } - else - break; - } - else - break; - } - else /* some other option */ - { - if (room >= 2) - { - const int len = p[i+1]; /* get option length */ - i += (len + 2); /* advance to next option */ - } - else - break; - } + const uint8_t type = p[i]; + const int room = optlen - i; + if (type == DHCP_END) + { + break; + } + else if (type == DHCP_PAD) + { + ++i; + } + else if (type == DHCP_ROUTER) + { + if (room >= 2) + { + const int len = p[i+1]; /* get option length */ + if (len <= (room-2)) + { + /* get router IP address */ + if (!ret && len >= 4 && (len & 3) == 0) + { + memcpy(&ret, p+i+2, 4); + ret = ntohl(ret); + } + { + /* delete the router option */ + uint8_t *dest = p + i; + const int owlen = len + 2; /* len of data to overwrite */ + uint8_t *src = dest + owlen; + uint8_t *end = p + optlen; + const int movlen = end - src; + if (movlen > 0) + { + memmove(dest, src, movlen); /* overwrite router option */ + } + memset(end - owlen, DHCP_PAD, owlen); /* pad tail */ + } + } + else + { + break; + } + } + else + { + break; + } + } + else /* some other option */ + { + if (room >= 2) + { + const int len = p[i+1]; /* get option length */ + i += (len + 2); /* advance to next option */ + } + else + { + break; + } + } } - return ret; + return ret; } static uint16_t -udp_checksum (const uint8_t *buf, - const int len_udp, - const uint8_t *src_addr, - const uint8_t *dest_addr) +udp_checksum(const uint8_t *buf, + const int len_udp, + const uint8_t *src_addr, + const uint8_t *dest_addr) { - uint16_t word16; - uint32_t sum = 0; - int i; - - /* make 16 bit words out of every two adjacent 8 bit words and */ - /* calculate the sum of all 16 bit words */ - for (i = 0; i < len_udp; i += 2){ - word16 = ((buf[i] << 8) & 0xFF00) + ((i + 1 < len_udp) ? (buf[i+1] & 0xFF) : 0); - sum += word16; - } - - /* add the UDP pseudo header which contains the IP source and destination addresses */ - for (i = 0; i < 4; i += 2){ - word16 =((src_addr[i] << 8) & 0xFF00) + (src_addr[i+1] & 0xFF); - sum += word16; - } - for (i = 0; i < 4; i += 2){ - word16 =((dest_addr[i] << 8) & 0xFF00) + (dest_addr[i+1] & 0xFF); - sum += word16; - } - - /* the protocol number and the length of the UDP packet */ - sum += (uint16_t) OPENVPN_IPPROTO_UDP + (uint16_t) len_udp; - - /* keep only the last 16 bits of the 32 bit calculated sum and add the carries */ - while (sum >> 16) - sum = (sum & 0xFFFF) + (sum >> 16); - - /* Take the one's complement of sum */ - return ((uint16_t) ~sum); + uint16_t word16; + uint32_t sum = 0; + int i; + + /* make 16 bit words out of every two adjacent 8 bit words and */ + /* calculate the sum of all 16 bit words */ + for (i = 0; i < len_udp; i += 2) { + word16 = ((buf[i] << 8) & 0xFF00) + ((i + 1 < len_udp) ? (buf[i+1] & 0xFF) : 0); + sum += word16; + } + + /* add the UDP pseudo header which contains the IP source and destination addresses */ + for (i = 0; i < 4; i += 2) { + word16 = ((src_addr[i] << 8) & 0xFF00) + (src_addr[i+1] & 0xFF); + sum += word16; + } + for (i = 0; i < 4; i += 2) { + word16 = ((dest_addr[i] << 8) & 0xFF00) + (dest_addr[i+1] & 0xFF); + sum += word16; + } + + /* the protocol number and the length of the UDP packet */ + sum += (uint16_t) OPENVPN_IPPROTO_UDP + (uint16_t) len_udp; + + /* keep only the last 16 bits of the 32 bit calculated sum and add the carries */ + while (sum >> 16) + sum = (sum & 0xFFFF) + (sum >> 16); + + /* Take the one's complement of sum */ + return ((uint16_t) ~sum); } in_addr_t -dhcp_extract_router_msg (struct buffer *ipbuf) +dhcp_extract_router_msg(struct buffer *ipbuf) { - struct dhcp_full *df = (struct dhcp_full *) BPTR (ipbuf); - const int optlen = BLEN (ipbuf) - (sizeof (struct openvpn_iphdr) + sizeof (struct openvpn_udphdr) + sizeof (struct dhcp)); - - if (optlen >= 0 - && df->ip.protocol == OPENVPN_IPPROTO_UDP - && df->udp.source == htons (BOOTPS_PORT) - && df->udp.dest == htons (BOOTPC_PORT) - && df->dhcp.op == BOOTREPLY) + struct dhcp_full *df = (struct dhcp_full *) BPTR(ipbuf); + const int optlen = BLEN(ipbuf) - (sizeof(struct openvpn_iphdr) + sizeof(struct openvpn_udphdr) + sizeof(struct dhcp)); + + if (optlen >= 0 + && df->ip.protocol == OPENVPN_IPPROTO_UDP + && df->udp.source == htons(BOOTPS_PORT) + && df->udp.dest == htons(BOOTPC_PORT) + && df->dhcp.op == BOOTREPLY) { - const int message_type = get_dhcp_message_type (&df->dhcp, optlen); - if (message_type == DHCPACK || message_type == DHCPOFFER) - { - /* get the router IP address while padding out all DHCP router options */ - const in_addr_t ret = do_extract (&df->dhcp, optlen); - - /* recompute the UDP checksum */ - df->udp.check = 0; - df->udp.check = htons (udp_checksum ((uint8_t *) &df->udp, - sizeof (struct openvpn_udphdr) + sizeof (struct dhcp) + optlen, - (uint8_t *)&df->ip.saddr, - (uint8_t *)&df->ip.daddr)); - - /* only return the extracted Router address if DHCPACK */ - if (message_type == DHCPACK) - { - if (ret) - { - struct gc_arena gc = gc_new (); - msg (D_ROUTE, "Extracted DHCP router address: %s", print_in_addr_t (ret, 0, &gc)); - gc_free (&gc); - } - - return ret; - } - } + const int message_type = get_dhcp_message_type(&df->dhcp, optlen); + if (message_type == DHCPACK || message_type == DHCPOFFER) + { + /* get the router IP address while padding out all DHCP router options */ + const in_addr_t ret = do_extract(&df->dhcp, optlen); + + /* recompute the UDP checksum */ + df->udp.check = 0; + df->udp.check = htons(udp_checksum((uint8_t *) &df->udp, + sizeof(struct openvpn_udphdr) + sizeof(struct dhcp) + optlen, + (uint8_t *)&df->ip.saddr, + (uint8_t *)&df->ip.daddr)); + + /* only return the extracted Router address if DHCPACK */ + if (message_type == DHCPACK) + { + if (ret) + { + struct gc_arena gc = gc_new(); + msg(D_ROUTE, "Extracted DHCP router address: %s", print_in_addr_t(ret, 0, &gc)); + gc_free(&gc); + } + + return ret; + } + } } - return 0; + return 0; } diff --git a/src/openvpn/dhcp.h b/src/openvpn/dhcp.h index e823a4a80f7..ee0f438a48f 100644 --- a/src/openvpn/dhcp.h +++ b/src/openvpn/dhcp.h @@ -52,36 +52,36 @@ #define BOOTPC_PORT 68 struct dhcp { -# define BOOTREQUEST 1 -# define BOOTREPLY 2 - uint8_t op; /* message op */ +#define BOOTREQUEST 1 +#define BOOTREPLY 2 + uint8_t op; /* message op */ - uint8_t htype; /* hardware address type (e.g. '1' = 10Mb Ethernet) */ - uint8_t hlen; /* hardware address length (e.g. '6' for 10Mb Ethernet) */ - uint8_t hops; /* client sets to 0, may be used by relay agents */ - uint32_t xid; /* transaction ID, chosen by client */ - uint16_t secs; /* seconds since request process began, set by client */ - uint16_t flags; - uint32_t ciaddr; /* client IP address, client sets if known */ - uint32_t yiaddr; /* 'your' IP address -- server's response to client */ - uint32_t siaddr; /* server IP address */ - uint32_t giaddr; /* relay agent IP address */ - uint8_t chaddr[16]; /* client hardware address */ - uint8_t sname[64]; /* optional server host name */ - uint8_t file[128]; /* boot file name */ - uint32_t magic; /* must be 0x63825363 (network order) */ + uint8_t htype; /* hardware address type (e.g. '1' = 10Mb Ethernet) */ + uint8_t hlen; /* hardware address length (e.g. '6' for 10Mb Ethernet) */ + uint8_t hops; /* client sets to 0, may be used by relay agents */ + uint32_t xid; /* transaction ID, chosen by client */ + uint16_t secs; /* seconds since request process began, set by client */ + uint16_t flags; + uint32_t ciaddr; /* client IP address, client sets if known */ + uint32_t yiaddr; /* 'your' IP address -- server's response to client */ + uint32_t siaddr; /* server IP address */ + uint32_t giaddr; /* relay agent IP address */ + uint8_t chaddr[16]; /* client hardware address */ + uint8_t sname[64]; /* optional server host name */ + uint8_t file[128]; /* boot file name */ + uint32_t magic; /* must be 0x63825363 (network order) */ }; struct dhcp_full { - struct openvpn_iphdr ip; - struct openvpn_udphdr udp; - struct dhcp dhcp; -# define DHCP_OPTIONS_BUFFER_SIZE 256 - uint8_t options[DHCP_OPTIONS_BUFFER_SIZE]; + struct openvpn_iphdr ip; + struct openvpn_udphdr udp; + struct dhcp dhcp; +#define DHCP_OPTIONS_BUFFER_SIZE 256 + uint8_t options[DHCP_OPTIONS_BUFFER_SIZE]; }; #pragma pack() -in_addr_t dhcp_extract_router_msg (struct buffer *ipbuf); +in_addr_t dhcp_extract_router_msg(struct buffer *ipbuf); -#endif +#endif /* ifndef DHCP_H */ diff --git a/src/openvpn/errlevel.h b/src/openvpn/errlevel.h index 9d56eb4984e..b3a9f8140f1 100644 --- a/src/openvpn/errlevel.h +++ b/src/openvpn/errlevel.h @@ -176,4 +176,4 @@ /*#define D_THREAD_DEBUG LOGLEV(4, 70, M_DEBUG)*/ /* show pthread debug information */ -#endif +#endif /* ifndef ERRLEVEL_H */ diff --git a/src/openvpn/error.c b/src/openvpn/error.c index 425bc30525f..6c07cdec145 100644 --- a/src/openvpn/error.c +++ b/src/openvpn/error.c @@ -69,7 +69,7 @@ static int mute_category; /* GLOBAL */ */ /* If true, indicates that stdin/stdout/stderr - have been redirected due to --log */ + * have been redirected due to --log */ static bool std_redir; /* GLOBAL */ /* Should messages be written to the syslog? */ @@ -98,91 +98,95 @@ static FILE *default_out; /* GLOBAL */ static FILE *default_err; /* GLOBAL */ void -msg_forked (void) +msg_forked(void) { - forked = true; + forked = true; } bool -set_debug_level (const int level, const unsigned int flags) +set_debug_level(const int level, const unsigned int flags) { - const int ceiling = 15; + const int ceiling = 15; - if (level >= 0 && level <= ceiling) + if (level >= 0 && level <= ceiling) { - x_debug_level = level; - return true; + x_debug_level = level; + return true; } - else if (flags & SDL_CONSTRAIN) + else if (flags & SDL_CONSTRAIN) { - x_debug_level = constrain_int (level, 0, ceiling); - return true; + x_debug_level = constrain_int(level, 0, ceiling); + return true; } - return false; + return false; } bool -set_mute_cutoff (const int cutoff) +set_mute_cutoff(const int cutoff) { - if (cutoff >= 0) + if (cutoff >= 0) { - mute_cutoff = cutoff; - return true; + mute_cutoff = cutoff; + return true; + } + else + { + return false; } - else - return false; } int -get_debug_level (void) +get_debug_level(void) { - return x_debug_level; + return x_debug_level; } int -get_mute_cutoff (void) +get_mute_cutoff(void) { - return mute_cutoff; + return mute_cutoff; } void -set_suppress_timestamps (bool suppressed) +set_suppress_timestamps(bool suppressed) { - suppress_timestamps = suppressed; + suppress_timestamps = suppressed; } void -set_machine_readable_output (bool parsable) +set_machine_readable_output(bool parsable) { - machine_readable_output = parsable; + machine_readable_output = parsable; } void -error_reset () +error_reset() { - use_syslog = std_redir = false; - suppress_timestamps = false; - machine_readable_output = false; - x_debug_level = 1; - mute_cutoff = 0; - mute_count = 0; - mute_category = 0; - default_out = OPENVPN_MSG_FP; - default_err = OPENVPN_MSG_FP; + use_syslog = std_redir = false; + suppress_timestamps = false; + machine_readable_output = false; + x_debug_level = 1; + mute_cutoff = 0; + mute_count = 0; + mute_category = 0; + default_out = OPENVPN_MSG_FP; + default_err = OPENVPN_MSG_FP; #ifdef OPENVPN_DEBUG_COMMAND_LINE - msgfp = fopen (OPENVPN_DEBUG_FILE, "w"); - if (!msgfp) - openvpn_exit (OPENVPN_EXIT_STATUS_CANNOT_OPEN_DEBUG_FILE); /* exit point */ -#else - msgfp = NULL; + msgfp = fopen(OPENVPN_DEBUG_FILE, "w"); + if (!msgfp) + { + openvpn_exit(OPENVPN_EXIT_STATUS_CANNOT_OPEN_DEBUG_FILE); /* exit point */ + } +#else /* ifdef OPENVPN_DEBUG_COMMAND_LINE */ + msgfp = NULL; #endif } void -errors_to_stderr (void) +errors_to_stderr(void) { - default_err = OPENVPN_ERROR_FP; + default_err = OPENVPN_ERROR_FP; } /* @@ -191,216 +195,254 @@ errors_to_stderr (void) FILE * msg_fp(const unsigned int flags) { - FILE *fp = msgfp; - if (!fp) - fp = (flags & (M_FATAL|M_USAGE_SMALL)) ? default_err : default_out; - if (!fp) - openvpn_exit (OPENVPN_EXIT_STATUS_CANNOT_OPEN_DEBUG_FILE); /* exit point */ - return fp; + FILE *fp = msgfp; + if (!fp) + { + fp = (flags & (M_FATAL|M_USAGE_SMALL)) ? default_err : default_out; + } + if (!fp) + { + openvpn_exit(OPENVPN_EXIT_STATUS_CANNOT_OPEN_DEBUG_FILE); /* exit point */ + } + return fp; } #define SWAP { tmp = m1; m1 = m2; m2 = tmp; } int x_msg_line_num; /* GLOBAL */ -void x_msg (const unsigned int flags, const char *format, ...) +void +x_msg(const unsigned int flags, const char *format, ...) { - va_list arglist; - va_start (arglist, format); - x_msg_va (flags, format, arglist); - va_end (arglist); + va_list arglist; + va_start(arglist, format); + x_msg_va(flags, format, arglist); + va_end(arglist); } -void x_msg_va (const unsigned int flags, const char *format, va_list arglist) +void +x_msg_va(const unsigned int flags, const char *format, va_list arglist) { - struct gc_arena gc; + struct gc_arena gc; #if SYSLOG_CAPABILITY - int level; + int level; #endif - char *m1; - char *m2; - char *tmp; - int e; - const char *prefix; - const char *prefix_sep; + char *m1; + char *m2; + char *tmp; + int e; + const char *prefix; + const char *prefix_sep; - void usage_small (void); + void usage_small(void); #ifndef HAVE_VARARG_MACROS - /* the macro has checked this otherwise */ - if (!msg_test (flags)) - return; + /* the macro has checked this otherwise */ + if (!msg_test(flags)) + { + return; + } #endif - e = openvpn_errno (); + e = openvpn_errno(); - /* - * Apply muting filter. - */ + /* + * Apply muting filter. + */ #ifndef HAVE_VARARG_MACROS - /* the macro has checked this otherwise */ - if (!dont_mute (flags)) - return; + /* the macro has checked this otherwise */ + if (!dont_mute(flags)) + { + return; + } #endif - gc_init (&gc); + gc_init(&gc); - m1 = (char *) gc_malloc (ERR_BUF_SIZE, false, &gc); - m2 = (char *) gc_malloc (ERR_BUF_SIZE, false, &gc); + m1 = (char *) gc_malloc(ERR_BUF_SIZE, false, &gc); + m2 = (char *) gc_malloc(ERR_BUF_SIZE, false, &gc); - vsnprintf (m1, ERR_BUF_SIZE, format, arglist); - m1[ERR_BUF_SIZE - 1] = 0; /* windows vsnprintf needs this */ + vsnprintf(m1, ERR_BUF_SIZE, format, arglist); + m1[ERR_BUF_SIZE - 1] = 0; /* windows vsnprintf needs this */ - if ((flags & M_ERRNO) && e) + if ((flags & M_ERRNO) && e) { - openvpn_snprintf (m2, ERR_BUF_SIZE, "%s: %s (errno=%d)", - m1, strerror_ts (e, &gc), e); - SWAP; + openvpn_snprintf(m2, ERR_BUF_SIZE, "%s: %s (errno=%d)", + m1, strerror_ts(e, &gc), e); + SWAP; } - if (flags & M_OPTERR) + if (flags & M_OPTERR) { - openvpn_snprintf (m2, ERR_BUF_SIZE, "Options error: %s", m1); - SWAP; + openvpn_snprintf(m2, ERR_BUF_SIZE, "Options error: %s", m1); + SWAP; } #if SYSLOG_CAPABILITY - if (flags & (M_FATAL|M_NONFATAL|M_USAGE_SMALL)) - level = LOG_ERR; - else if (flags & M_WARN) - level = LOG_WARNING; - else - level = LOG_NOTICE; + if (flags & (M_FATAL|M_NONFATAL|M_USAGE_SMALL)) + { + level = LOG_ERR; + } + else if (flags & M_WARN) + { + level = LOG_WARNING; + } + else + { + level = LOG_NOTICE; + } #endif - /* set up client prefix */ - if (flags & M_NOIPREFIX) - prefix = NULL; - else - prefix = msg_get_prefix (); - prefix_sep = " "; - if (!prefix) - prefix_sep = prefix = ""; - - /* virtual output capability used to copy output to management subsystem */ - if (!forked) - { - const struct virtual_output *vo = msg_get_virtual_output (); - if (vo) - { - openvpn_snprintf (m2, ERR_BUF_SIZE, "%s%s%s", - prefix, - prefix_sep, - m1); - virtual_output_print (vo, flags, m2); - } - } - - if (!(flags & M_MSG_VIRT_OUT)) - { - if (use_syslog && !std_redir && !forked) - { + /* set up client prefix */ + if (flags & M_NOIPREFIX) + { + prefix = NULL; + } + else + { + prefix = msg_get_prefix(); + } + prefix_sep = " "; + if (!prefix) + { + prefix_sep = prefix = ""; + } + + /* virtual output capability used to copy output to management subsystem */ + if (!forked) + { + const struct virtual_output *vo = msg_get_virtual_output(); + if (vo) + { + openvpn_snprintf(m2, ERR_BUF_SIZE, "%s%s%s", + prefix, + prefix_sep, + m1); + virtual_output_print(vo, flags, m2); + } + } + + if (!(flags & M_MSG_VIRT_OUT)) + { + if (use_syslog && !std_redir && !forked) + { #if SYSLOG_CAPABILITY - syslog (level, "%s%s%s", - prefix, - prefix_sep, - m1); + syslog(level, "%s%s%s", + prefix, + prefix_sep, + m1); #endif - } - else - { - FILE *fp = msg_fp(flags); - const bool show_usec = check_debug_level (DEBUG_LEVEL_USEC_TIME); - - if (machine_readable_output) - { - struct timeval tv; - gettimeofday (&tv, NULL); - - fprintf (fp, "%lu.%06lu %x %s%s%s%s", - tv.tv_sec, - (unsigned long)tv.tv_usec, - flags, - prefix, - prefix_sep, - m1, - "\n"); - - } - else if ((flags & M_NOPREFIX) || suppress_timestamps) - { - fprintf (fp, "%s%s%s%s", - prefix, - prefix_sep, - m1, - (flags&M_NOLF) ? "" : "\n"); - } - else - { - fprintf (fp, "%s %s%s%s%s", - time_string (0, 0, show_usec, &gc), - prefix, - prefix_sep, - m1, - (flags&M_NOLF) ? "" : "\n"); - } - fflush(fp); - ++x_msg_line_num; - } - } - - if (flags & M_FATAL) - msg (M_INFO, "Exiting due to fatal error"); - - if (flags & M_FATAL) - openvpn_exit (OPENVPN_EXIT_STATUS_ERROR); /* exit point */ - - if (flags & M_USAGE_SMALL) - usage_small (); - - gc_free (&gc); + } + else + { + FILE *fp = msg_fp(flags); + const bool show_usec = check_debug_level(DEBUG_LEVEL_USEC_TIME); + + if (machine_readable_output) + { + struct timeval tv; + gettimeofday(&tv, NULL); + + fprintf(fp, "%lu.%06lu %x %s%s%s%s", + tv.tv_sec, + (unsigned long)tv.tv_usec, + flags, + prefix, + prefix_sep, + m1, + "\n"); + + } + else if ((flags & M_NOPREFIX) || suppress_timestamps) + { + fprintf(fp, "%s%s%s%s", + prefix, + prefix_sep, + m1, + (flags&M_NOLF) ? "" : "\n"); + } + else + { + fprintf(fp, "%s %s%s%s%s", + time_string(0, 0, show_usec, &gc), + prefix, + prefix_sep, + m1, + (flags&M_NOLF) ? "" : "\n"); + } + fflush(fp); + ++x_msg_line_num; + } + } + + if (flags & M_FATAL) + { + msg(M_INFO, "Exiting due to fatal error"); + } + + if (flags & M_FATAL) + { + openvpn_exit(OPENVPN_EXIT_STATUS_ERROR); /* exit point */ + + } + if (flags & M_USAGE_SMALL) + { + usage_small(); + } + + gc_free(&gc); } /* * Apply muting filter. */ bool -dont_mute (unsigned int flags) +dont_mute(unsigned int flags) { - bool ret = true; - if (mute_cutoff > 0 && !(flags & M_NOMUTE)) - { - const int mute_level = DECODE_MUTE_LEVEL (flags); - if (mute_level > 0 && mute_level == mute_category) - { - if (mute_count == mute_cutoff) - msg (M_INFO | M_NOMUTE, "NOTE: --mute triggered..."); - if (++mute_count > mute_cutoff) - ret = false; - } - else - { - const int suppressed = mute_count - mute_cutoff; - if (suppressed > 0) - msg (M_INFO | M_NOMUTE, - "%d variation(s) on previous %d message(s) suppressed by --mute", - suppressed, - mute_cutoff); - mute_count = 1; - mute_category = mute_level; - } - } - return ret; + bool ret = true; + if (mute_cutoff > 0 && !(flags & M_NOMUTE)) + { + const int mute_level = DECODE_MUTE_LEVEL(flags); + if (mute_level > 0 && mute_level == mute_category) + { + if (mute_count == mute_cutoff) + { + msg(M_INFO | M_NOMUTE, "NOTE: --mute triggered..."); + } + if (++mute_count > mute_cutoff) + { + ret = false; + } + } + else + { + const int suppressed = mute_count - mute_cutoff; + if (suppressed > 0) + { + msg(M_INFO | M_NOMUTE, + "%d variation(s) on previous %d message(s) suppressed by --mute", + suppressed, + mute_cutoff); + } + mute_count = 1; + mute_category = mute_level; + } + } + return ret; } void -assert_failed (const char *filename, int line, const char *condition) +assert_failed(const char *filename, int line, const char *condition) { - if (condition) - msg (M_FATAL, "Assertion failed at %s:%d (%s)", filename, line, condition); - else - msg (M_FATAL, "Assertion failed at %s:%d", filename, line); - _exit(1); + if (condition) + { + msg(M_FATAL, "Assertion failed at %s:%d (%s)", filename, line, condition); + } + else + { + msg(M_FATAL, "Assertion failed at %s:%d", filename, line); + } + _exit(1); } /* @@ -408,47 +450,49 @@ assert_failed (const char *filename, int line, const char *condition) * to allocate memory as part of its operation. */ void -out_of_memory (void) +out_of_memory(void) { - fprintf (stderr, PACKAGE_NAME ": Out of Memory\n"); - exit (1); + fprintf(stderr, PACKAGE_NAME ": Out of Memory\n"); + exit(1); } void -open_syslog (const char *pgmname, bool stdio_to_null) +open_syslog(const char *pgmname, bool stdio_to_null) { #if SYSLOG_CAPABILITY - if (!msgfp && !std_redir) + if (!msgfp && !std_redir) { - if (!use_syslog) - { - pgmname_syslog = string_alloc (pgmname ? pgmname : PACKAGE, NULL); - openlog (pgmname_syslog, LOG_PID, LOG_OPENVPN); - use_syslog = true; - - /* Better idea: somehow pipe stdout/stderr output to msg() */ - if (stdio_to_null) - set_std_files_to_null (false); - } + if (!use_syslog) + { + pgmname_syslog = string_alloc(pgmname ? pgmname : PACKAGE, NULL); + openlog(pgmname_syslog, LOG_PID, LOG_OPENVPN); + use_syslog = true; + + /* Better idea: somehow pipe stdout/stderr output to msg() */ + if (stdio_to_null) + { + set_std_files_to_null(false); + } + } } -#else - msg (M_WARN, "Warning on use of --daemon/--inetd: this operating system lacks daemon logging features, therefore when I become a daemon, I won't be able to log status or error messages"); +#else /* if SYSLOG_CAPABILITY */ + msg(M_WARN, "Warning on use of --daemon/--inetd: this operating system lacks daemon logging features, therefore when I become a daemon, I won't be able to log status or error messages"); #endif } void -close_syslog () +close_syslog() { #if SYSLOG_CAPABILITY - if (use_syslog) + if (use_syslog) { - closelog(); - use_syslog = false; - if (pgmname_syslog) - { - free (pgmname_syslog); - pgmname_syslog = NULL; - } + closelog(); + use_syslog = false; + if (pgmname_syslog) + { + free(pgmname_syslog); + pgmname_syslog = NULL; + } } #endif } @@ -458,108 +502,128 @@ close_syslog () static HANDLE orig_stderr; HANDLE -get_orig_stderr (void) +get_orig_stderr(void) { - if (orig_stderr) - return orig_stderr; - else - return GetStdHandle (STD_ERROR_HANDLE); + if (orig_stderr) + { + return orig_stderr; + } + else + { + return GetStdHandle(STD_ERROR_HANDLE); + } } #endif void -redirect_stdout_stderr (const char *file, bool append) +redirect_stdout_stderr(const char *file, bool append) { #if defined(_WIN32) - if (!std_redir) - { - struct gc_arena gc = gc_new (); - HANDLE log_handle; - int log_fd; - - SECURITY_ATTRIBUTES saAttr; - saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); - saAttr.bInheritHandle = TRUE; - saAttr.lpSecurityDescriptor = NULL; - - log_handle = CreateFileW (wide_string (file, &gc), - GENERIC_WRITE, - FILE_SHARE_READ, - &saAttr, - append ? OPEN_ALWAYS : CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL, - NULL); - - gc_free (&gc); - - if (log_handle == INVALID_HANDLE_VALUE) - { - msg (M_WARN|M_ERRNO, "Warning: cannot open --log file: %s", file); - return; - } - - /* append to logfile? */ - if (append) - { - if (SetFilePointer (log_handle, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER) - msg (M_ERR, "Error: cannot seek to end of --log file: %s", file); - } - - /* save original stderr for password prompts */ - orig_stderr = GetStdHandle (STD_ERROR_HANDLE); + if (!std_redir) + { + struct gc_arena gc = gc_new(); + HANDLE log_handle; + int log_fd; + + SECURITY_ATTRIBUTES saAttr; + saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); + saAttr.bInheritHandle = TRUE; + saAttr.lpSecurityDescriptor = NULL; + + log_handle = CreateFileW(wide_string(file, &gc), + GENERIC_WRITE, + FILE_SHARE_READ, + &saAttr, + append ? OPEN_ALWAYS : CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL); + + gc_free(&gc); + + if (log_handle == INVALID_HANDLE_VALUE) + { + msg(M_WARN|M_ERRNO, "Warning: cannot open --log file: %s", file); + return; + } + + /* append to logfile? */ + if (append) + { + if (SetFilePointer(log_handle, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER) + { + msg(M_ERR, "Error: cannot seek to end of --log file: %s", file); + } + } + + /* save original stderr for password prompts */ + orig_stderr = GetStdHandle(STD_ERROR_HANDLE); #if 0 /* seems not be necessary with stdout/stderr redirection below*/ - /* set up for redirection */ - if (!SetStdHandle (STD_OUTPUT_HANDLE, log_handle) - || !SetStdHandle (STD_ERROR_HANDLE, log_handle)) - msg (M_ERR, "Error: cannot redirect stdout/stderr to --log file: %s", file); + /* set up for redirection */ + if (!SetStdHandle(STD_OUTPUT_HANDLE, log_handle) + || !SetStdHandle(STD_ERROR_HANDLE, log_handle)) + { + msg(M_ERR, "Error: cannot redirect stdout/stderr to --log file: %s", file); + } #endif - /* direct stdout/stderr to point to log_handle */ - log_fd = _open_osfhandle ((intptr_t)log_handle, _O_TEXT); - if (log_fd == -1) - msg (M_ERR, "Error: --log redirect failed due to _open_osfhandle failure"); - - /* open log_handle as FILE stream */ - ASSERT (msgfp == NULL); - msgfp = _fdopen (log_fd, "wt"); - if (msgfp == NULL) - msg (M_ERR, "Error: --log redirect failed due to _fdopen"); - - /* redirect C-library stdout/stderr to log file */ - if (_dup2 (log_fd, 1) == -1 || _dup2 (log_fd, 2) == -1) - msg (M_WARN, "Error: --log redirect of stdout/stderr failed"); - - std_redir = true; + /* direct stdout/stderr to point to log_handle */ + log_fd = _open_osfhandle((intptr_t)log_handle, _O_TEXT); + if (log_fd == -1) + { + msg(M_ERR, "Error: --log redirect failed due to _open_osfhandle failure"); + } + + /* open log_handle as FILE stream */ + ASSERT(msgfp == NULL); + msgfp = _fdopen(log_fd, "wt"); + if (msgfp == NULL) + { + msg(M_ERR, "Error: --log redirect failed due to _fdopen"); + } + + /* redirect C-library stdout/stderr to log file */ + if (_dup2(log_fd, 1) == -1 || _dup2(log_fd, 2) == -1) + { + msg(M_WARN, "Error: --log redirect of stdout/stderr failed"); + } + + std_redir = true; } #elif defined(HAVE_DUP2) - if (!std_redir) + if (!std_redir) { - int out = open (file, - O_CREAT | O_WRONLY | (append ? O_APPEND : O_TRUNC), - S_IRUSR | S_IWUSR); - - if (out < 0) - { - msg (M_WARN|M_ERRNO, "Warning: Error redirecting stdout/stderr to --log file: %s", file); - return; - } - - if (dup2 (out, 1) == -1) - msg (M_ERR, "--log file redirection error on stdout"); - if (dup2 (out, 2) == -1) - msg (M_ERR, "--log file redirection error on stderr"); - - if (out > 2) - close (out); - - std_redir = true; + int out = open(file, + O_CREAT | O_WRONLY | (append ? O_APPEND : O_TRUNC), + S_IRUSR | S_IWUSR); + + if (out < 0) + { + msg(M_WARN|M_ERRNO, "Warning: Error redirecting stdout/stderr to --log file: %s", file); + return; + } + + if (dup2(out, 1) == -1) + { + msg(M_ERR, "--log file redirection error on stdout"); + } + if (dup2(out, 2) == -1) + { + msg(M_ERR, "--log file redirection error on stderr"); + } + + if (out > 2) + { + close(out); + } + + std_redir = true; } -#else - msg (M_WARN, "WARNING: The --log option is not supported on this OS because it lacks the dup2 function"); -#endif +#else /* if defined(_WIN32) */ + msg(M_WARN, "WARNING: The --log option is not supported on this OS because it lacks the dup2 function"); +#endif /* if defined(_WIN32) */ } /* @@ -572,17 +636,17 @@ unsigned int x_cs_verbose_level; /* GLOBAL */ unsigned int x_cs_err_delay_ms; /* GLOBAL */ void -reset_check_status () +reset_check_status() { - x_cs_info_level = 0; - x_cs_verbose_level = 0; + x_cs_info_level = 0; + x_cs_verbose_level = 0; } void -set_check_status (unsigned int info_level, unsigned int verbose_level) +set_check_status(unsigned int info_level, unsigned int verbose_level) { - x_cs_info_level = info_level; - x_cs_verbose_level = verbose_level; + x_cs_info_level = info_level; + x_cs_verbose_level = verbose_level; } /* @@ -594,58 +658,64 @@ set_check_status (unsigned int info_level, unsigned int verbose_level) * from the OS. */ void -x_check_status (int status, - const char *description, - struct link_socket *sock, - struct tuntap *tt) +x_check_status(int status, + const char *description, + struct link_socket *sock, + struct tuntap *tt) { - const int my_errno = openvpn_errno (); - const char *extended_msg = NULL; + const int my_errno = openvpn_errno(); + const char *extended_msg = NULL; - msg (x_cs_verbose_level, "%s %s returned %d", - sock ? proto2ascii (sock->info.proto, sock->info.af, true) : "", - description, - status); + msg(x_cs_verbose_level, "%s %s returned %d", + sock ? proto2ascii(sock->info.proto, sock->info.af, true) : "", + description, + status); - if (status < 0) + if (status < 0) { - struct gc_arena gc = gc_new (); + struct gc_arena gc = gc_new(); #if EXTENDED_SOCKET_ERROR_CAPABILITY - /* get extended socket error message and possible PMTU hint from OS */ - if (sock) - { - int mtu; - extended_msg = format_extended_socket_error (sock->sd, &mtu, &gc); - if (mtu > 0 && sock->mtu != mtu) - { - sock->mtu = mtu; - sock->info.mtu_changed = true; - } - } + /* get extended socket error message and possible PMTU hint from OS */ + if (sock) + { + int mtu; + extended_msg = format_extended_socket_error(sock->sd, &mtu, &gc); + if (mtu > 0 && sock->mtu != mtu) + { + sock->mtu = mtu; + sock->info.mtu_changed = true; + } + } #elif defined(_WIN32) - /* get possible driver error from TAP-Windows driver */ - extended_msg = tap_win_getinfo (tt, &gc); + /* get possible driver error from TAP-Windows driver */ + extended_msg = tap_win_getinfo(tt, &gc); #endif - if (!ignore_sys_error (my_errno)) - { - if (extended_msg) - msg (x_cs_info_level, "%s %s [%s]: %s (code=%d)", - description, - sock ? proto2ascii (sock->info.proto, sock->info.af, true) : "", - extended_msg, - strerror_ts (my_errno, &gc), - my_errno); - else - msg (x_cs_info_level, "%s %s: %s (code=%d)", - description, - sock ? proto2ascii (sock->info.proto, sock->info.af, true) : "", - strerror_ts (my_errno, &gc), - my_errno); - - if (x_cs_err_delay_ms) - platform_sleep_milliseconds (x_cs_err_delay_ms); - } - gc_free (&gc); + if (!ignore_sys_error(my_errno)) + { + if (extended_msg) + { + msg(x_cs_info_level, "%s %s [%s]: %s (code=%d)", + description, + sock ? proto2ascii(sock->info.proto, sock->info.af, true) : "", + extended_msg, + strerror_ts(my_errno, &gc), + my_errno); + } + else + { + msg(x_cs_info_level, "%s %s: %s (code=%d)", + description, + sock ? proto2ascii(sock->info.proto, sock->info.af, true) : "", + strerror_ts(my_errno, &gc), + my_errno); + } + + if (x_cs_err_delay_ms) + { + platform_sleep_milliseconds(x_cs_err_delay_ms); + } + } + gc_free(&gc); } } @@ -666,222 +736,288 @@ const struct virtual_output *x_msg_virtual_output; /* GLOBAL */ */ void -openvpn_exit (const int status) +openvpn_exit(const int status) { - if (!forked) + if (!forked) { - void tun_abort(); + void tun_abort(); + #ifdef ENABLE_PLUGIN - void plugin_abort (void); + void plugin_abort(void); + #endif - tun_abort(); + tun_abort(); #ifdef _WIN32 - uninit_win32 (); + uninit_win32(); #endif - close_syslog (); + close_syslog(); #ifdef ENABLE_PLUGIN - plugin_abort (); + plugin_abort(); #endif #if PORT_SHARE - if (port_share) - port_share_abort (port_share); + if (port_share) + { + port_share_abort(port_share); + } #endif #ifdef ENABLE_MEMSTATS - mstats_close(); + mstats_close(); #endif #ifdef ABORT_ON_ERROR - if (status == OPENVPN_EXIT_STATUS_ERROR) - abort (); + if (status == OPENVPN_EXIT_STATUS_ERROR) + { + abort(); + } #endif - if (status == OPENVPN_EXIT_STATUS_GOOD) - perf_output_results (); + if (status == OPENVPN_EXIT_STATUS_GOOD) + { + perf_output_results(); + } } - exit (status); + exit(status); } /* * Translate msg flags into a string */ const char * -msg_flags_string (const unsigned int flags, struct gc_arena *gc) +msg_flags_string(const unsigned int flags, struct gc_arena *gc) { - struct buffer out = alloc_buf_gc (16, gc); - if (flags == M_INFO) - buf_printf (&out, "I"); - if (flags & M_FATAL) - buf_printf (&out, "F"); - if (flags & M_NONFATAL) - buf_printf (&out, "N"); - if (flags & M_WARN) - buf_printf (&out, "W"); - if (flags & M_DEBUG) - buf_printf (&out, "D"); - return BSTR (&out); + struct buffer out = alloc_buf_gc(16, gc); + if (flags == M_INFO) + { + buf_printf(&out, "I"); + } + if (flags & M_FATAL) + { + buf_printf(&out, "F"); + } + if (flags & M_NONFATAL) + { + buf_printf(&out, "N"); + } + if (flags & M_WARN) + { + buf_printf(&out, "W"); + } + if (flags & M_DEBUG) + { + buf_printf(&out, "D"); + } + return BSTR(&out); } #ifdef ENABLE_DEBUG void -crash (void) +crash(void) { - char *null = NULL; - *null = 0; + char *null = NULL; + *null = 0; } #endif #ifdef _WIN32 const char * -strerror_win32 (DWORD errnum, struct gc_arena *gc) +strerror_win32(DWORD errnum, struct gc_arena *gc) { - /* - * This code can be omitted, though often the Windows - * WSA error messages are less informative than the - * Posix equivalents. - */ -#if 1 - switch (errnum) { /* - * When the TAP-Windows driver returns STATUS_UNSUCCESSFUL, this code - * gets returned to user space. + * This code can be omitted, though often the Windows + * WSA error messages are less informative than the + * Posix equivalents. */ - case ERROR_GEN_FAILURE: - return "General failure (ERROR_GEN_FAILURE)"; - case ERROR_IO_PENDING: - return "I/O Operation in progress (ERROR_IO_PENDING)"; - case WSA_IO_INCOMPLETE: - return "I/O Operation in progress (WSA_IO_INCOMPLETE)"; - case WSAEINTR: - return "Interrupted system call (WSAEINTR)"; - case WSAEBADF: - return "Bad file number (WSAEBADF)"; - case WSAEACCES: - return "Permission denied (WSAEACCES)"; - case WSAEFAULT: - return "Bad address (WSAEFAULT)"; - case WSAEINVAL: - return "Invalid argument (WSAEINVAL)"; - case WSAEMFILE: - return "Too many open files (WSAEMFILE)"; - case WSAEWOULDBLOCK: - return "Operation would block (WSAEWOULDBLOCK)"; - case WSAEINPROGRESS: - return "Operation now in progress (WSAEINPROGRESS)"; - case WSAEALREADY: - return "Operation already in progress (WSAEALREADY)"; - case WSAEDESTADDRREQ: - return "Destination address required (WSAEDESTADDRREQ)"; - case WSAEMSGSIZE: - return "Message too long (WSAEMSGSIZE)"; - case WSAEPROTOTYPE: - return "Protocol wrong type for socket (WSAEPROTOTYPE)"; - case WSAENOPROTOOPT: - return "Bad protocol option (WSAENOPROTOOPT)"; - case WSAEPROTONOSUPPORT: - return "Protocol not supported (WSAEPROTONOSUPPORT)"; - case WSAESOCKTNOSUPPORT: - return "Socket type not supported (WSAESOCKTNOSUPPORT)"; - case WSAEOPNOTSUPP: - return "Operation not supported on socket (WSAEOPNOTSUPP)"; - case WSAEPFNOSUPPORT: - return "Protocol family not supported (WSAEPFNOSUPPORT)"; - case WSAEAFNOSUPPORT: - return "Address family not supported by protocol family (WSAEAFNOSUPPORT)"; - case WSAEADDRINUSE: - return "Address already in use (WSAEADDRINUSE)"; - case WSAENETDOWN: - return "Network is down (WSAENETDOWN)"; - case WSAENETUNREACH: - return "Network is unreachable (WSAENETUNREACH)"; - case WSAENETRESET: - return "Net dropped connection or reset (WSAENETRESET)"; - case WSAECONNABORTED: - return "Software caused connection abort (WSAECONNABORTED)"; - case WSAECONNRESET: - return "Connection reset by peer (WSAECONNRESET)"; - case WSAENOBUFS: - return "No buffer space available (WSAENOBUFS)"; - case WSAEISCONN: - return "Socket is already connected (WSAEISCONN)"; - case WSAENOTCONN: - return "Socket is not connected (WSAENOTCONN)"; - case WSAETIMEDOUT: - return "Connection timed out (WSAETIMEDOUT)"; - case WSAECONNREFUSED: - return "Connection refused (WSAECONNREFUSED)"; - case WSAELOOP: - return "Too many levels of symbolic links (WSAELOOP)"; - case WSAENAMETOOLONG: - return "File name too long (WSAENAMETOOLONG)"; - case WSAEHOSTDOWN: - return "Host is down (WSAEHOSTDOWN)"; - case WSAEHOSTUNREACH: - return "No Route to Host (WSAEHOSTUNREACH)"; - case WSAENOTEMPTY: - return "Directory not empty (WSAENOTEMPTY)"; - case WSAEPROCLIM: - return "Too many processes (WSAEPROCLIM)"; - case WSAEUSERS: - return "Too many users (WSAEUSERS)"; - case WSAEDQUOT: - return "Disc Quota Exceeded (WSAEDQUOT)"; - case WSAESTALE: - return "Stale NFS file handle (WSAESTALE)"; - case WSASYSNOTREADY: - return "Network SubSystem is unavailable (WSASYSNOTREADY)"; - case WSAVERNOTSUPPORTED: - return "WINSOCK DLL Version out of range (WSAVERNOTSUPPORTED)"; - case WSANOTINITIALISED: - return "Successful WSASTARTUP not yet performed (WSANOTINITIALISED)"; - case WSAEREMOTE: - return "Too many levels of remote in path (WSAEREMOTE)"; - case WSAHOST_NOT_FOUND: - return "Host not found (WSAHOST_NOT_FOUND)"; - default: - break; - } -#endif +#if 1 + switch (errnum) { + /* + * When the TAP-Windows driver returns STATUS_UNSUCCESSFUL, this code + * gets returned to user space. + */ + case ERROR_GEN_FAILURE: + return "General failure (ERROR_GEN_FAILURE)"; - /* format a windows error message */ - { - char message[256]; - struct buffer out = alloc_buf_gc (256, gc); - const int status = FormatMessage ( - FORMAT_MESSAGE_IGNORE_INSERTS - | FORMAT_MESSAGE_FROM_SYSTEM - | FORMAT_MESSAGE_ARGUMENT_ARRAY, - NULL, - errnum, - 0, - message, - sizeof (message), - NULL); - if (!status) - { - buf_printf (&out, "[Unknown Win32 Error]"); - } - else - { - char *cp; - for (cp = message; *cp != '\0'; ++cp) - { - if (*cp == '\n' || *cp == '\r') - *cp = ' '; - } - - buf_printf(&out, "%s", message); - } - - return BSTR (&out); - } + case ERROR_IO_PENDING: + return "I/O Operation in progress (ERROR_IO_PENDING)"; + + case WSA_IO_INCOMPLETE: + return "I/O Operation in progress (WSA_IO_INCOMPLETE)"; + + case WSAEINTR: + return "Interrupted system call (WSAEINTR)"; + + case WSAEBADF: + return "Bad file number (WSAEBADF)"; + + case WSAEACCES: + return "Permission denied (WSAEACCES)"; + + case WSAEFAULT: + return "Bad address (WSAEFAULT)"; + + case WSAEINVAL: + return "Invalid argument (WSAEINVAL)"; + + case WSAEMFILE: + return "Too many open files (WSAEMFILE)"; + + case WSAEWOULDBLOCK: + return "Operation would block (WSAEWOULDBLOCK)"; + + case WSAEINPROGRESS: + return "Operation now in progress (WSAEINPROGRESS)"; + + case WSAEALREADY: + return "Operation already in progress (WSAEALREADY)"; + + case WSAEDESTADDRREQ: + return "Destination address required (WSAEDESTADDRREQ)"; + + case WSAEMSGSIZE: + return "Message too long (WSAEMSGSIZE)"; + + case WSAEPROTOTYPE: + return "Protocol wrong type for socket (WSAEPROTOTYPE)"; + + case WSAENOPROTOOPT: + return "Bad protocol option (WSAENOPROTOOPT)"; + + case WSAEPROTONOSUPPORT: + return "Protocol not supported (WSAEPROTONOSUPPORT)"; + + case WSAESOCKTNOSUPPORT: + return "Socket type not supported (WSAESOCKTNOSUPPORT)"; + + case WSAEOPNOTSUPP: + return "Operation not supported on socket (WSAEOPNOTSUPP)"; + + case WSAEPFNOSUPPORT: + return "Protocol family not supported (WSAEPFNOSUPPORT)"; + + case WSAEAFNOSUPPORT: + return "Address family not supported by protocol family (WSAEAFNOSUPPORT)"; + + case WSAEADDRINUSE: + return "Address already in use (WSAEADDRINUSE)"; + + case WSAENETDOWN: + return "Network is down (WSAENETDOWN)"; + + case WSAENETUNREACH: + return "Network is unreachable (WSAENETUNREACH)"; + + case WSAENETRESET: + return "Net dropped connection or reset (WSAENETRESET)"; + + case WSAECONNABORTED: + return "Software caused connection abort (WSAECONNABORTED)"; + + case WSAECONNRESET: + return "Connection reset by peer (WSAECONNRESET)"; + + case WSAENOBUFS: + return "No buffer space available (WSAENOBUFS)"; + + case WSAEISCONN: + return "Socket is already connected (WSAEISCONN)"; + + case WSAENOTCONN: + return "Socket is not connected (WSAENOTCONN)"; + + case WSAETIMEDOUT: + return "Connection timed out (WSAETIMEDOUT)"; + + case WSAECONNREFUSED: + return "Connection refused (WSAECONNREFUSED)"; + + case WSAELOOP: + return "Too many levels of symbolic links (WSAELOOP)"; + + case WSAENAMETOOLONG: + return "File name too long (WSAENAMETOOLONG)"; + + case WSAEHOSTDOWN: + return "Host is down (WSAEHOSTDOWN)"; + + case WSAEHOSTUNREACH: + return "No Route to Host (WSAEHOSTUNREACH)"; + + case WSAENOTEMPTY: + return "Directory not empty (WSAENOTEMPTY)"; + + case WSAEPROCLIM: + return "Too many processes (WSAEPROCLIM)"; + + case WSAEUSERS: + return "Too many users (WSAEUSERS)"; + + case WSAEDQUOT: + return "Disc Quota Exceeded (WSAEDQUOT)"; + + case WSAESTALE: + return "Stale NFS file handle (WSAESTALE)"; + + case WSASYSNOTREADY: + return "Network SubSystem is unavailable (WSASYSNOTREADY)"; + + case WSAVERNOTSUPPORTED: + return "WINSOCK DLL Version out of range (WSAVERNOTSUPPORTED)"; + + case WSANOTINITIALISED: + return "Successful WSASTARTUP not yet performed (WSANOTINITIALISED)"; + + case WSAEREMOTE: + return "Too many levels of remote in path (WSAEREMOTE)"; + + case WSAHOST_NOT_FOUND: + return "Host not found (WSAHOST_NOT_FOUND)"; + + default: + break; + } +#endif /* if 1 */ + + /* format a windows error message */ + { + char message[256]; + struct buffer out = alloc_buf_gc(256, gc); + const int status = FormatMessage( + FORMAT_MESSAGE_IGNORE_INSERTS + | FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_ARGUMENT_ARRAY, + NULL, + errnum, + 0, + message, + sizeof(message), + NULL); + if (!status) + { + buf_printf(&out, "[Unknown Win32 Error]"); + } + else + { + char *cp; + for (cp = message; *cp != '\0'; ++cp) + { + if (*cp == '\n' || *cp == '\r') + { + *cp = ' '; + } + } + + buf_printf(&out, "%s", message); + } + + return BSTR(&out); + } } -#endif +#endif /* ifdef _WIN32 */ diff --git a/src/openvpn/error.h b/src/openvpn/error.h index f43bc38d8a7..eb9f8c08fbe 100644 --- a/src/openvpn/error.h +++ b/src/openvpn/error.h @@ -72,12 +72,13 @@ struct gc_arena; /* String and Error functions */ #ifdef _WIN32 -# define openvpn_errno() GetLastError() -# define openvpn_strerror(e, gc) strerror_win32(e, gc) - const char *strerror_win32 (DWORD errnum, struct gc_arena *gc); +#define openvpn_errno() GetLastError() +#define openvpn_strerror(e, gc) strerror_win32(e, gc) +const char *strerror_win32(DWORD errnum, struct gc_arena *gc); + #else -# define openvpn_errno() errno -# define openvpn_strerror(x, gc) strerror(x) +#define openvpn_errno() errno +#define openvpn_strerror(x, gc) strerror(x) #endif /* @@ -89,14 +90,14 @@ extern int x_msg_line_num; /* msg() flags */ -#define M_DEBUG_LEVEL (0x0F) /* debug level mask */ +#define M_DEBUG_LEVEL (0x0F) /* debug level mask */ -#define M_FATAL (1<<4) /* exit program */ -#define M_NONFATAL (1<<5) /* non-fatal error */ -#define M_WARN (1<<6) /* call syslog with LOG_WARNING */ +#define M_FATAL (1<<4) /* exit program */ +#define M_NONFATAL (1<<5) /* non-fatal error */ +#define M_WARN (1<<6) /* call syslog with LOG_WARNING */ #define M_DEBUG (1<<7) -#define M_ERRNO (1<<8) /* show errno description */ +#define M_ERRNO (1<<8) /* show errno description */ #define M_NOMUTE (1<<11) /* don't do mute processing */ #define M_NOPREFIX (1<<12) /* don't show date/time prefix */ @@ -141,73 +142,75 @@ extern int x_msg_line_num; */ /** Check muting filter */ -bool dont_mute (unsigned int flags); +bool dont_mute(unsigned int flags); /* Macro to ensure (and teach static analysis tools) we exit on fatal errors */ -#define EXIT_FATAL(flags) do { if ((flags) & M_FATAL) _exit(1); } while (false) +#define EXIT_FATAL(flags) do { if ((flags) & M_FATAL) {_exit(1);}} while (false) #if defined(HAVE_CPP_VARARG_MACRO_ISO) && !defined(__LCLINT__) -# define HAVE_VARARG_MACROS -# define msg(flags, ...) do { if (msg_test(flags)) x_msg((flags), __VA_ARGS__); EXIT_FATAL(flags); } while (false) -# ifdef ENABLE_DEBUG -# define dmsg(flags, ...) do { if (msg_test(flags)) x_msg((flags), __VA_ARGS__); EXIT_FATAL(flags); } while (false) -# else -# define dmsg(flags, ...) -# endif +#define HAVE_VARARG_MACROS +#define msg(flags, ...) do { if (msg_test(flags)) {x_msg((flags), __VA_ARGS__);} EXIT_FATAL(flags); } while (false) +#ifdef ENABLE_DEBUG +#define dmsg(flags, ...) do { if (msg_test(flags)) {x_msg((flags), __VA_ARGS__);} EXIT_FATAL(flags); } while (false) +#else +#define dmsg(flags, ...) +#endif #elif defined(HAVE_CPP_VARARG_MACRO_GCC) && !defined(__LCLINT__) -# define HAVE_VARARG_MACROS -# define msg(flags, args...) do { if (msg_test(flags)) x_msg((flags), args); EXIT_FATAL(flags); } while (false) -# ifdef ENABLE_DEBUG -# define dmsg(flags, args...) do { if (msg_test(flags)) x_msg((flags), args); EXIT_FATAL(flags); } while (false) -# else -# define dmsg(flags, args...) -# endif +#define HAVE_VARARG_MACROS +#define msg(flags, args ...) do { if (msg_test(flags)) {x_msg((flags), args);} EXIT_FATAL(flags); } while (false) +#ifdef ENABLE_DEBUG +#define dmsg(flags, args ...) do { if (msg_test(flags)) {x_msg((flags), args);} EXIT_FATAL(flags); } while (false) #else -# if !PEDANTIC -# ifdef _MSC_VER -# pragma message("this compiler appears to lack vararg macros which will cause a significant degradation in efficiency") -# else -# warning this compiler appears to lack vararg macros which will cause a significant degradation in efficiency (you can ignore this warning if you are using LCLINT) -# endif -# endif -# define msg x_msg -# define dmsg x_msg +#define dmsg(flags, args ...) #endif +#else /* if defined(HAVE_CPP_VARARG_MACRO_ISO) && !defined(__LCLINT__) */ +#if !PEDANTIC +#ifdef _MSC_VER +#pragma message("this compiler appears to lack vararg macros which will cause a significant degradation in efficiency") +#else +#warning this compiler appears to lack vararg macros which will cause a significant degradation in efficiency (you can ignore this warning if you are using LCLINT) +#endif +#endif +#define msg x_msg +#define dmsg x_msg +#endif /* if defined(HAVE_CPP_VARARG_MACRO_ISO) && !defined(__LCLINT__) */ -void x_msg (const unsigned int flags, const char *format, ...) +void x_msg(const unsigned int flags, const char *format, ...) #ifdef __GNUC__ #if __USE_MINGW_ANSI_STDIO - __attribute__ ((format (gnu_printf, 2, 3))) +__attribute__ ((format(gnu_printf, 2, 3))) #else - __attribute__ ((format (__printf__, 2, 3))) +__attribute__ ((format(__printf__, 2, 3))) #endif #endif - ; /* should be called via msg above */ +; /* should be called via msg above */ -void x_msg_va (const unsigned int flags, const char *format, va_list arglist); +void x_msg_va(const unsigned int flags, const char *format, va_list arglist); /* * Function prototypes */ -void error_reset (void); +void error_reset(void); /* route errors to stderr that would normally go to stdout */ -void errors_to_stderr (void); +void errors_to_stderr(void); + +void set_suppress_timestamps(bool suppressed); -void set_suppress_timestamps (bool suppressed); -void set_machine_readable_output (bool parsable); +void set_machine_readable_output(bool parsable); #define SDL_CONSTRAIN (1<<0) -bool set_debug_level (const int level, const unsigned int flags); +bool set_debug_level(const int level, const unsigned int flags); -bool set_mute_cutoff (const int cutoff); +bool set_mute_cutoff(const int cutoff); -int get_debug_level (void); -int get_mute_cutoff (void); +int get_debug_level(void); -const char *msg_flags_string (const unsigned int flags, struct gc_arena *gc); +int get_mute_cutoff(void); + +const char *msg_flags_string(const unsigned int flags, struct gc_arena *gc); /* * File to print messages to before syslog is opened. @@ -216,61 +219,65 @@ FILE *msg_fp(const unsigned int flags); /* Fatal logic errors */ #ifndef ENABLE_SMALL -#define ASSERT(x) do { if (!(x)) assert_failed(__FILE__, __LINE__, #x); } while (false) +#define ASSERT(x) do { if (!(x)) {assert_failed(__FILE__, __LINE__, #x);}} while (false) #else -#define ASSERT(x) do { if (!(x)) assert_failed(__FILE__, __LINE__, NULL); } while (false) +#define ASSERT(x) do { if (!(x)) {assert_failed(__FILE__, __LINE__, NULL);}} while (false) #endif -void assert_failed (const char *filename, int line, const char *condition) - __attribute__((__noreturn__)); +void assert_failed(const char *filename, int line, const char *condition) +__attribute__((__noreturn__)); /* Poor-man's static_assert() for when not supplied by assert.h, taken from * Linux's sys/cdefs.h under GPLv2 */ #ifndef static_assert #define static_assert(expr, diagnostic) \ - extern int (*__OpenVPN_static_assert_function (void)) \ - [!!sizeof (struct { int __error_if_negative: (expr) ? 2 : -1; })] + extern int (*__OpenVPN_static_assert_function(void)) \ + [!!sizeof(struct { int __error_if_negative : (expr) ? 2 : -1; })] #endif #ifdef ENABLE_DEBUG -void crash (void); /* force a segfault (debugging only) */ +void crash(void); /* force a segfault (debugging only) */ + #endif /* Inline functions */ static inline bool -check_debug_level (unsigned int level) +check_debug_level(unsigned int level) { - return (level & M_DEBUG_LEVEL) <= x_debug_level; + return (level & M_DEBUG_LEVEL) <= x_debug_level; } /** Return true if flags represent an enabled, not muted log level */ -static inline bool msg_test (unsigned int flags) +static inline bool +msg_test(unsigned int flags) { - return check_debug_level (flags) && dont_mute (flags); + return check_debug_level(flags) && dont_mute(flags); } /* Call if we forked */ -void msg_forked (void); +void msg_forked(void); /* syslog output */ -void open_syslog (const char *pgmname, bool stdio_to_null); -void close_syslog (); +void open_syslog(const char *pgmname, bool stdio_to_null); + +void close_syslog(); /* log file output */ -void redirect_stdout_stderr (const char *file, bool append); +void redirect_stdout_stderr(const char *file, bool append); #ifdef _WIN32 /* get original stderr handle, even if redirected by --log/--log-append */ -HANDLE get_orig_stderr (void); +HANDLE get_orig_stderr(void); + #endif /* exit program */ -void openvpn_exit (const int status); +void openvpn_exit(const int status); /* exit program on out of memory error */ -void out_of_memory (void); +void out_of_memory(void); /* * Check the return status of read/write routines. @@ -283,25 +290,28 @@ extern unsigned int x_cs_info_level; extern unsigned int x_cs_verbose_level; extern unsigned int x_cs_err_delay_ms; -void reset_check_status (void); -void set_check_status (unsigned int info_level, unsigned int verbose_level); +void reset_check_status(void); + +void set_check_status(unsigned int info_level, unsigned int verbose_level); -void x_check_status (int status, - const char *description, - struct link_socket *sock, - struct tuntap *tt); +void x_check_status(int status, + const char *description, + struct link_socket *sock, + struct tuntap *tt); static inline void -check_status (int status, const char *description, struct link_socket *sock, struct tuntap *tt) +check_status(int status, const char *description, struct link_socket *sock, struct tuntap *tt) { - if (status < 0 || check_debug_level (x_cs_verbose_level)) - x_check_status (status, description, sock, tt); + if (status < 0 || check_debug_level(x_cs_verbose_level)) + { + x_check_status(status, description, sock, tt); + } } static inline void -set_check_status_error_delay (unsigned int milliseconds) +set_check_status_error_delay(unsigned int milliseconds) { - x_cs_err_delay_ms = milliseconds; + x_cs_err_delay_ms = milliseconds; } /* @@ -313,17 +323,18 @@ set_check_status_error_delay (unsigned int milliseconds) extern const char *x_msg_prefix; -void msg_thread_init (void); -void msg_thread_uninit (void); +void msg_thread_init(void); + +void msg_thread_uninit(void); static inline void -msg_set_prefix (const char *prefix) +msg_set_prefix(const char *prefix) { x_msg_prefix = prefix; } static inline const char * -msg_get_prefix (void) +msg_get_prefix(void) { return x_msg_prefix; } @@ -337,15 +348,15 @@ struct virtual_output; extern const struct virtual_output *x_msg_virtual_output; static inline void -msg_set_virtual_output (const struct virtual_output *vo) +msg_set_virtual_output(const struct virtual_output *vo) { - x_msg_virtual_output = vo; + x_msg_virtual_output = vo; } static inline const struct virtual_output * -msg_get_virtual_output (void) +msg_get_virtual_output(void) { - return x_msg_virtual_output; + return x_msg_virtual_output; } /* @@ -353,34 +364,40 @@ msg_get_virtual_output (void) * which can be safely ignored. */ static inline bool -ignore_sys_error (const int err) +ignore_sys_error(const int err) { - /* I/O operation pending */ + /* I/O operation pending */ #ifdef _WIN32 - if (err == WSAEWOULDBLOCK || err == WSAEINVAL) - return true; + if (err == WSAEWOULDBLOCK || err == WSAEINVAL) + { + return true; + } #else - if (err == EAGAIN) - return true; + if (err == EAGAIN) + { + return true; + } #endif #if 0 /* if enabled, suppress ENOBUFS errors */ #ifdef ENOBUFS - /* No buffer space available */ - if (err == ENOBUFS) - return true; + /* No buffer space available */ + if (err == ENOBUFS) + { + return true; + } #endif #endif - return false; + return false; } /** Convert fatal errors to nonfatal, don't touch other errors */ static inline unsigned int nonfatal(const unsigned int err) { - return err & M_FATAL ? (err ^ M_FATAL) | M_NONFATAL : err; + return err & M_FATAL ? (err ^ M_FATAL) | M_NONFATAL : err; } #include "errlevel.h" -#endif +#endif /* ifndef ERROR_H */ diff --git a/src/openvpn/event.c b/src/openvpn/event.c index 409ad13199d..a13e0dc95aa 100644 --- a/src/openvpn/event.c +++ b/src/openvpn/event.c @@ -66,400 +66,453 @@ #endif static inline int -tv_to_ms_timeout (const struct timeval *tv) +tv_to_ms_timeout(const struct timeval *tv) { - if (tv->tv_sec == 0 && tv->tv_usec == 0) - return 0; - else - return max_int (tv->tv_sec * 1000 + (tv->tv_usec + 500) / 1000, 1); + if (tv->tv_sec == 0 && tv->tv_usec == 0) + { + return 0; + } + else + { + return max_int(tv->tv_sec * 1000 + (tv->tv_usec + 500) / 1000, 1); + } } #ifdef _WIN32 struct we_set { - struct event_set_functions func; - bool fast; - HANDLE *events; - struct event_set_return *esr; - int n_events; - int capacity; + struct event_set_functions func; + bool fast; + HANDLE *events; + struct event_set_return *esr; + int n_events; + int capacity; }; static inline void -we_set_event (struct we_set *wes, int i, event_t event, unsigned int rwflags, void *arg) +we_set_event(struct we_set *wes, int i, event_t event, unsigned int rwflags, void *arg) { - ASSERT (i >= 0 && i < wes->capacity); + ASSERT(i >= 0 && i < wes->capacity); - if (rwflags == EVENT_READ) + if (rwflags == EVENT_READ) { - ASSERT (event->read != NULL); - wes->events[i] = event->read; + ASSERT(event->read != NULL); + wes->events[i] = event->read; } - else if (rwflags == EVENT_WRITE) + else if (rwflags == EVENT_WRITE) { - ASSERT (event->write != NULL); - wes->events[i] = event->write; + ASSERT(event->write != NULL); + wes->events[i] = event->write; } - else - msg (M_FATAL, "fatal error in we_set_events: rwflags=%d", rwflags); - - wes->esr[i].rwflags = rwflags; - wes->esr[i].arg = arg; + else + { + msg(M_FATAL, "fatal error in we_set_events: rwflags=%d", rwflags); + } + + wes->esr[i].rwflags = rwflags; + wes->esr[i].arg = arg; } static inline bool -we_append_event (struct we_set *wes, event_t event, unsigned int rwflags, void *arg) +we_append_event(struct we_set *wes, event_t event, unsigned int rwflags, void *arg) { - if (rwflags & EVENT_WRITE) + if (rwflags & EVENT_WRITE) { - if (wes->n_events < wes->capacity) - { - we_set_event (wes, wes->n_events, event, EVENT_WRITE, arg); - ++wes->n_events; - } - else - return false; + if (wes->n_events < wes->capacity) + { + we_set_event(wes, wes->n_events, event, EVENT_WRITE, arg); + ++wes->n_events; + } + else + { + return false; + } } - if (rwflags & EVENT_READ) + if (rwflags & EVENT_READ) { - if (wes->n_events < wes->capacity) - { - we_set_event (wes, wes->n_events, event, EVENT_READ, arg); - ++wes->n_events; - } - else - return false; + if (wes->n_events < wes->capacity) + { + we_set_event(wes, wes->n_events, event, EVENT_READ, arg); + ++wes->n_events; + } + else + { + return false; + } } - return true; + return true; } static void -we_del_event (struct we_set *wes, event_t event) +we_del_event(struct we_set *wes, event_t event) { - int i, j = 0; - const int len = wes->n_events; + int i, j = 0; + const int len = wes->n_events; - for (i = 0; i < len; ++i) + for (i = 0; i < len; ++i) { - const HANDLE h = wes->events[i]; - if (h == event->read || h == event->write) - --wes->n_events; - else - { - if (i != j) - { - wes->events[j] = wes->events[i]; - wes->esr[j] = wes->esr[i]; - } - ++j; - } + const HANDLE h = wes->events[i]; + if (h == event->read || h == event->write) + { + --wes->n_events; + } + else + { + if (i != j) + { + wes->events[j] = wes->events[i]; + wes->esr[j] = wes->esr[i]; + } + ++j; + } } } static void -we_del_index (struct we_set *wes, int index) +we_del_index(struct we_set *wes, int index) { - int i; - ASSERT (index >= 0 && index < wes->n_events); - for (i = index; i < wes->n_events - 1; ++i) + int i; + ASSERT(index >= 0 && index < wes->n_events); + for (i = index; i < wes->n_events - 1; ++i) { - wes->events[i] = wes->events[i+1]; - wes->esr[i] = wes->esr[i+1]; + wes->events[i] = wes->events[i+1]; + wes->esr[i] = wes->esr[i+1]; } - --wes->n_events; + --wes->n_events; } static void -we_get_rw_indices (struct we_set *wes, event_t event, int *ri, int *wi) +we_get_rw_indices(struct we_set *wes, event_t event, int *ri, int *wi) { - int i; - *ri = *wi = -1; - for (i = 0; i < wes->n_events; ++i) + int i; + *ri = *wi = -1; + for (i = 0; i < wes->n_events; ++i) { - const HANDLE h = wes->events[i]; - if (h == event->read) - { - ASSERT (*ri == -1); - *ri = i; - } - else if (h == event->write) - { - ASSERT (*wi == -1); - *wi = i; - } + const HANDLE h = wes->events[i]; + if (h == event->read) + { + ASSERT(*ri == -1); + *ri = i; + } + else if (h == event->write) + { + ASSERT(*wi == -1); + *wi = i; + } } } static void -we_free (struct event_set *es) +we_free(struct event_set *es) { - struct we_set *wes = (struct we_set *) es; - free (wes->events); - free (wes->esr); - free (wes); + struct we_set *wes = (struct we_set *) es; + free(wes->events); + free(wes->esr); + free(wes); } static void -we_reset (struct event_set *es) +we_reset(struct event_set *es) { - struct we_set *wes = (struct we_set *) es; - ASSERT (wes->fast); - wes->n_events = 0; + struct we_set *wes = (struct we_set *) es; + ASSERT(wes->fast); + wes->n_events = 0; } static void -we_del (struct event_set *es, event_t event) +we_del(struct event_set *es, event_t event) { - struct we_set *wes = (struct we_set *) es; - ASSERT (!wes->fast); - we_del_event (wes, event); + struct we_set *wes = (struct we_set *) es; + ASSERT(!wes->fast); + we_del_event(wes, event); } static void -we_ctl (struct event_set *es, event_t event, unsigned int rwflags, void *arg) +we_ctl(struct event_set *es, event_t event, unsigned int rwflags, void *arg) { - struct we_set *wes = (struct we_set *) es; + struct we_set *wes = (struct we_set *) es; - dmsg (D_EVENT_WAIT, "WE_CTL n=%d ev=%p rwflags=0x%04x arg=" ptr_format, - wes->n_events, - event, - rwflags, - (ptr_type)arg); + dmsg(D_EVENT_WAIT, "WE_CTL n=%d ev=%p rwflags=0x%04x arg=" ptr_format, + wes->n_events, + event, + rwflags, + (ptr_type)arg); - if (wes->fast) + if (wes->fast) { - if (!we_append_event (wes, event, rwflags, arg)) - goto err; + if (!we_append_event(wes, event, rwflags, arg)) + { + goto err; + } } - else + else { - int ri, wi; - int one = -1; - int n = 0; - - we_get_rw_indices (wes, event, &ri, &wi); - if (wi >= 0) - { - one = wi; - ++n; - } - if (ri >= 0) - { - one = ri; - ++n; - } - switch (rwflags) - { - case 0: - switch (n) - { - case 0: - break; - case 1: - we_del_index (wes, one); - break; - case 2: - we_del_event (wes, event); - break; - default: - ASSERT (0); - } - break; - case EVENT_READ: - switch (n) - { - case 0: - if (!we_append_event (wes, event, EVENT_READ, arg)) - goto err; - break; - case 1: - we_set_event (wes, one, event, EVENT_READ, arg); - break; - case 2: - we_del_index (wes, wi); - break; - default: - ASSERT (0); - } - break; - case EVENT_WRITE: - switch (n) - { - case 0: - if (!we_append_event (wes, event, EVENT_WRITE, arg)) - goto err; - break; - case 1: - we_set_event (wes, one, event, EVENT_WRITE, arg); - break; - case 2: - we_del_index (wes, ri); - break; - default: - ASSERT (0); - } - break; - case EVENT_READ|EVENT_WRITE: - switch (n) - { - case 0: - if (!we_append_event (wes, event, EVENT_READ|EVENT_WRITE, arg)) - goto err; - break; - case 1: - if (ri == -1) - { - ASSERT (wi != -1); - if (!we_append_event (wes, event, EVENT_READ, arg)) - goto err; - } - else if (wi == -1) - { - if (!we_append_event (wes, event, EVENT_WRITE, arg)) - goto err; - } - else - ASSERT (0); - break; - case 2: - break; - default: - ASSERT (0); - } - break; - default: - msg (M_FATAL, "fatal error in we_ctl: rwflags=%d", rwflags); - } + int ri, wi; + int one = -1; + int n = 0; + + we_get_rw_indices(wes, event, &ri, &wi); + if (wi >= 0) + { + one = wi; + ++n; + } + if (ri >= 0) + { + one = ri; + ++n; + } + switch (rwflags) + { + case 0: + switch (n) + { + case 0: + break; + + case 1: + we_del_index(wes, one); + break; + + case 2: + we_del_event(wes, event); + break; + + default: + ASSERT(0); + } + break; + + case EVENT_READ: + switch (n) + { + case 0: + if (!we_append_event(wes, event, EVENT_READ, arg)) + { + goto err; + } + break; + + case 1: + we_set_event(wes, one, event, EVENT_READ, arg); + break; + + case 2: + we_del_index(wes, wi); + break; + + default: + ASSERT(0); + } + break; + + case EVENT_WRITE: + switch (n) + { + case 0: + if (!we_append_event(wes, event, EVENT_WRITE, arg)) + { + goto err; + } + break; + + case 1: + we_set_event(wes, one, event, EVENT_WRITE, arg); + break; + + case 2: + we_del_index(wes, ri); + break; + + default: + ASSERT(0); + } + break; + + case EVENT_READ|EVENT_WRITE: + switch (n) + { + case 0: + if (!we_append_event(wes, event, EVENT_READ|EVENT_WRITE, arg)) + { + goto err; + } + break; + + case 1: + if (ri == -1) + { + ASSERT(wi != -1); + if (!we_append_event(wes, event, EVENT_READ, arg)) + { + goto err; + } + } + else if (wi == -1) + { + if (!we_append_event(wes, event, EVENT_WRITE, arg)) + { + goto err; + } + } + else + { + ASSERT(0); + } + break; + + case 2: + break; + + default: + ASSERT(0); + } + break; + + default: + msg(M_FATAL, "fatal error in we_ctl: rwflags=%d", rwflags); + } } - return; + return; - err: - msg (D_EVENT_ERRORS, "Error: Windows resource limit WSA_MAXIMUM_WAIT_EVENTS (%d) has been exceeded", WSA_MAXIMUM_WAIT_EVENTS); +err: + msg(D_EVENT_ERRORS, "Error: Windows resource limit WSA_MAXIMUM_WAIT_EVENTS (%d) has been exceeded", WSA_MAXIMUM_WAIT_EVENTS); } static int -we_wait (struct event_set *es, const struct timeval *tv, struct event_set_return *out, int outlen) +we_wait(struct event_set *es, const struct timeval *tv, struct event_set_return *out, int outlen) { - struct we_set *wes = (struct we_set *) es; - const int timeout = tv_to_ms_timeout (tv); - DWORD status; + struct we_set *wes = (struct we_set *) es; + const int timeout = tv_to_ms_timeout(tv); + DWORD status; - dmsg (D_EVENT_WAIT, "WE_WAIT enter n=%d to=%d", wes->n_events, timeout); + dmsg(D_EVENT_WAIT, "WE_WAIT enter n=%d to=%d", wes->n_events, timeout); #ifdef ENABLE_DEBUG - if (check_debug_level (D_EVENT_WAIT)) { - int i; - for (i = 0; i < wes->n_events; ++i) - dmsg (D_EVENT_WAIT, "[%d] ev=%p rwflags=0x%04x arg=" ptr_format, - i, - wes->events[i], - wes->esr[i].rwflags, - (ptr_type)wes->esr[i].arg); - } + if (check_debug_level(D_EVENT_WAIT)) + { + int i; + for (i = 0; i < wes->n_events; ++i) + dmsg(D_EVENT_WAIT, "[%d] ev=%p rwflags=0x%04x arg=" ptr_format, + i, + wes->events[i], + wes->esr[i].rwflags, + (ptr_type)wes->esr[i].arg); + } #endif - /* - * First poll our event list with 0 timeout - */ - status = WSAWaitForMultipleEvents( - (DWORD) wes->n_events, - wes->events, - FALSE, - (DWORD) 0, - FALSE); - - /* - * If at least one event is already set, we must - * individually poll the whole list. - */ - if (status >= WSA_WAIT_EVENT_0 && status < WSA_WAIT_EVENT_0 + (DWORD) wes->n_events) + /* + * First poll our event list with 0 timeout + */ + status = WSAWaitForMultipleEvents( + (DWORD) wes->n_events, + wes->events, + FALSE, + (DWORD) 0, + FALSE); + + /* + * If at least one event is already set, we must + * individually poll the whole list. + */ + if (status >= WSA_WAIT_EVENT_0 && status < WSA_WAIT_EVENT_0 + (DWORD) wes->n_events) { - int i; - int j = 0; - for (i = 0; i < wes->n_events; ++i) - { - if (j >= outlen) - break; - if (WaitForSingleObject (wes->events[i], 0) == WAIT_OBJECT_0) - { - *out = wes->esr[i]; - dmsg (D_EVENT_WAIT, "WE_WAIT leave [%d,%d] rwflags=0x%04x arg=" ptr_format, - i, j, out->rwflags, (ptr_type)out->arg); - ++j; - ++out; - } - } - return j; + int i; + int j = 0; + for (i = 0; i < wes->n_events; ++i) + { + if (j >= outlen) + { + break; + } + if (WaitForSingleObject(wes->events[i], 0) == WAIT_OBJECT_0) + { + *out = wes->esr[i]; + dmsg(D_EVENT_WAIT, "WE_WAIT leave [%d,%d] rwflags=0x%04x arg=" ptr_format, + i, j, out->rwflags, (ptr_type)out->arg); + ++j; + ++out; + } + } + return j; } - else + else { - /* - * If caller specified timeout > 0, we know at this point - * that no events are set, so wait only for the first event - * (or timeout) and return at most one event_set_return object. - * - * If caller specified timeout == 0, the second call to - * WSAWaitForMultipleEvents would be redundant -- just - * return 0 indicating timeout. - */ - if (timeout > 0) - status = WSAWaitForMultipleEvents( - (DWORD) wes->n_events, - wes->events, - FALSE, - (DWORD) timeout, - FALSE); - - if (outlen >= 1 && status >= WSA_WAIT_EVENT_0 && status < WSA_WAIT_EVENT_0 + (DWORD) wes->n_events) - { - *out = wes->esr[status - WSA_WAIT_EVENT_0]; - dmsg (D_EVENT_WAIT, "WE_WAIT leave rwflags=0x%04x arg=" ptr_format, - out->rwflags, (ptr_type)out->arg); - return 1; - } - else if (status == WSA_WAIT_TIMEOUT) - return 0; - else - return -1; + /* + * If caller specified timeout > 0, we know at this point + * that no events are set, so wait only for the first event + * (or timeout) and return at most one event_set_return object. + * + * If caller specified timeout == 0, the second call to + * WSAWaitForMultipleEvents would be redundant -- just + * return 0 indicating timeout. + */ + if (timeout > 0) + { + status = WSAWaitForMultipleEvents( + (DWORD) wes->n_events, + wes->events, + FALSE, + (DWORD) timeout, + FALSE); + } + + if (outlen >= 1 && status >= WSA_WAIT_EVENT_0 && status < WSA_WAIT_EVENT_0 + (DWORD) wes->n_events) + { + *out = wes->esr[status - WSA_WAIT_EVENT_0]; + dmsg(D_EVENT_WAIT, "WE_WAIT leave rwflags=0x%04x arg=" ptr_format, + out->rwflags, (ptr_type)out->arg); + return 1; + } + else if (status == WSA_WAIT_TIMEOUT) + { + return 0; + } + else + { + return -1; + } } } static struct event_set * -we_init (int *maxevents, unsigned int flags) +we_init(int *maxevents, unsigned int flags) { - struct we_set *wes; + struct we_set *wes; - dmsg (D_EVENT_WAIT, "WE_INIT maxevents=%d flags=0x%08x", *maxevents, flags); + dmsg(D_EVENT_WAIT, "WE_INIT maxevents=%d flags=0x%08x", *maxevents, flags); - ALLOC_OBJ_CLEAR (wes, struct we_set); + ALLOC_OBJ_CLEAR(wes, struct we_set); - /* set dispatch functions */ - wes->func.free = we_free; - wes->func.reset = we_reset; - wes->func.del = we_del; - wes->func.ctl = we_ctl; - wes->func.wait = we_wait; + /* set dispatch functions */ + wes->func.free = we_free; + wes->func.reset = we_reset; + wes->func.del = we_del; + wes->func.ctl = we_ctl; + wes->func.wait = we_wait; - if (flags & EVENT_METHOD_FAST) - wes->fast = true; - wes->n_events = 0; + if (flags & EVENT_METHOD_FAST) + { + wes->fast = true; + } + wes->n_events = 0; - /* Figure our event capacity */ - ASSERT (*maxevents > 0); - wes->capacity = min_int (*maxevents * 2, WSA_MAXIMUM_WAIT_EVENTS); - *maxevents = min_int (*maxevents, WSA_MAXIMUM_WAIT_EVENTS); + /* Figure our event capacity */ + ASSERT(*maxevents > 0); + wes->capacity = min_int(*maxevents * 2, WSA_MAXIMUM_WAIT_EVENTS); + *maxevents = min_int(*maxevents, WSA_MAXIMUM_WAIT_EVENTS); - /* Allocate space for Win32 event handles */ - ALLOC_ARRAY_CLEAR (wes->events, HANDLE, wes->capacity); + /* Allocate space for Win32 event handles */ + ALLOC_ARRAY_CLEAR(wes->events, HANDLE, wes->capacity); - /* Allocate space for event_set_return objects */ - ALLOC_ARRAY_CLEAR (wes->esr, struct event_set_return, wes->capacity); + /* Allocate space for event_set_return objects */ + ALLOC_ARRAY_CLEAR(wes->esr, struct event_set_return, wes->capacity); - dmsg (D_EVENT_WAIT, "WE_INIT maxevents=%d capacity=%d", - *maxevents, wes->capacity); + dmsg(D_EVENT_WAIT, "WE_INIT maxevents=%d capacity=%d", + *maxevents, wes->capacity); - return (struct event_set *) wes; + return (struct event_set *) wes; } #endif /* _WIN32 */ @@ -468,145 +521,163 @@ we_init (int *maxevents, unsigned int flags) struct ep_set { - struct event_set_functions func; - bool fast; - int epfd; - int maxevents; - struct epoll_event *events; + struct event_set_functions func; + bool fast; + int epfd; + int maxevents; + struct epoll_event *events; }; static void -ep_free (struct event_set *es) +ep_free(struct event_set *es) { - struct ep_set *eps = (struct ep_set *) es; - close (eps->epfd); - free (eps->events); - free (eps); + struct ep_set *eps = (struct ep_set *) es; + close(eps->epfd); + free(eps->events); + free(eps); } static void -ep_reset (struct event_set *es) +ep_reset(struct event_set *es) { - const struct ep_set *eps = (struct ep_set *) es; - ASSERT (eps->fast); + const struct ep_set *eps = (struct ep_set *) es; + ASSERT(eps->fast); } static void -ep_del (struct event_set *es, event_t event) +ep_del(struct event_set *es, event_t event) { - struct epoll_event ev; - struct ep_set *eps = (struct ep_set *) es; + struct epoll_event ev; + struct ep_set *eps = (struct ep_set *) es; - dmsg (D_EVENT_WAIT, "EP_DEL ev=%d", (int)event); + dmsg(D_EVENT_WAIT, "EP_DEL ev=%d", (int)event); - ASSERT (!eps->fast); - CLEAR (ev); - epoll_ctl (eps->epfd, EPOLL_CTL_DEL, event, &ev); + ASSERT(!eps->fast); + CLEAR(ev); + epoll_ctl(eps->epfd, EPOLL_CTL_DEL, event, &ev); } static void -ep_ctl (struct event_set *es, event_t event, unsigned int rwflags, void *arg) +ep_ctl(struct event_set *es, event_t event, unsigned int rwflags, void *arg) { - struct ep_set *eps = (struct ep_set *) es; - struct epoll_event ev; + struct ep_set *eps = (struct ep_set *) es; + struct epoll_event ev; - CLEAR (ev); + CLEAR(ev); - ev.data.ptr = arg; - if (rwflags & EVENT_READ) - ev.events |= EPOLLIN; - if (rwflags & EVENT_WRITE) - ev.events |= EPOLLOUT; + ev.data.ptr = arg; + if (rwflags & EVENT_READ) + { + ev.events |= EPOLLIN; + } + if (rwflags & EVENT_WRITE) + { + ev.events |= EPOLLOUT; + } - dmsg (D_EVENT_WAIT, "EP_CTL fd=%d rwflags=0x%04x ev=0x%08x arg=" ptr_format, - (int)event, - rwflags, - (unsigned int)ev.events, - (ptr_type)ev.data.ptr); + dmsg(D_EVENT_WAIT, "EP_CTL fd=%d rwflags=0x%04x ev=0x%08x arg=" ptr_format, + (int)event, + rwflags, + (unsigned int)ev.events, + (ptr_type)ev.data.ptr); - if (epoll_ctl (eps->epfd, EPOLL_CTL_MOD, event, &ev) < 0) + if (epoll_ctl(eps->epfd, EPOLL_CTL_MOD, event, &ev) < 0) { - if (errno == ENOENT) - { - if (epoll_ctl (eps->epfd, EPOLL_CTL_ADD, event, &ev) < 0) - msg (M_ERR, "EVENT: epoll_ctl EPOLL_CTL_ADD failed, sd=%d", (int)event); - } - else - msg (M_ERR, "EVENT: epoll_ctl EPOLL_CTL_MOD failed, sd=%d", (int)event); + if (errno == ENOENT) + { + if (epoll_ctl(eps->epfd, EPOLL_CTL_ADD, event, &ev) < 0) + { + msg(M_ERR, "EVENT: epoll_ctl EPOLL_CTL_ADD failed, sd=%d", (int)event); + } + } + else + { + msg(M_ERR, "EVENT: epoll_ctl EPOLL_CTL_MOD failed, sd=%d", (int)event); + } } } static int -ep_wait (struct event_set *es, const struct timeval *tv, struct event_set_return *out, int outlen) +ep_wait(struct event_set *es, const struct timeval *tv, struct event_set_return *out, int outlen) { - struct ep_set *eps = (struct ep_set *) es; - int stat; + struct ep_set *eps = (struct ep_set *) es; + int stat; - if (outlen > eps->maxevents) - outlen = eps->maxevents; + if (outlen > eps->maxevents) + { + outlen = eps->maxevents; + } - stat = epoll_wait (eps->epfd, eps->events, outlen, tv_to_ms_timeout (tv)); - ASSERT (stat <= outlen); + stat = epoll_wait(eps->epfd, eps->events, outlen, tv_to_ms_timeout(tv)); + ASSERT(stat <= outlen); - if (stat > 0) + if (stat > 0) { - int i; - const struct epoll_event *ev = eps->events; - struct event_set_return *esr = out; - for (i = 0; i < stat; ++i) - { - esr->rwflags = 0; - if (ev->events & (EPOLLIN|EPOLLPRI|EPOLLERR|EPOLLHUP)) - esr->rwflags |= EVENT_READ; - if (ev->events & EPOLLOUT) - esr->rwflags |= EVENT_WRITE; - esr->arg = ev->data.ptr; - dmsg (D_EVENT_WAIT, "EP_WAIT[%d] rwflags=0x%04x ev=0x%08x arg=" ptr_format, - i, esr->rwflags, ev->events, (ptr_type)ev->data.ptr); - ++ev; - ++esr; - } + int i; + const struct epoll_event *ev = eps->events; + struct event_set_return *esr = out; + for (i = 0; i < stat; ++i) + { + esr->rwflags = 0; + if (ev->events & (EPOLLIN|EPOLLPRI|EPOLLERR|EPOLLHUP)) + { + esr->rwflags |= EVENT_READ; + } + if (ev->events & EPOLLOUT) + { + esr->rwflags |= EVENT_WRITE; + } + esr->arg = ev->data.ptr; + dmsg(D_EVENT_WAIT, "EP_WAIT[%d] rwflags=0x%04x ev=0x%08x arg=" ptr_format, + i, esr->rwflags, ev->events, (ptr_type)ev->data.ptr); + ++ev; + ++esr; + } } - return stat; + return stat; } static struct event_set * -ep_init (int *maxevents, unsigned int flags) +ep_init(int *maxevents, unsigned int flags) { - struct ep_set *eps; - int fd; + struct ep_set *eps; + int fd; - dmsg (D_EVENT_WAIT, "EP_INIT maxevents=%d flags=0x%08x", *maxevents, flags); + dmsg(D_EVENT_WAIT, "EP_INIT maxevents=%d flags=0x%08x", *maxevents, flags); - /* open epoll file descriptor */ - fd = epoll_create (*maxevents); - if (fd < 0) - return NULL; + /* open epoll file descriptor */ + fd = epoll_create(*maxevents); + if (fd < 0) + { + return NULL; + } - set_cloexec (fd); + set_cloexec(fd); - ALLOC_OBJ_CLEAR (eps, struct ep_set); + ALLOC_OBJ_CLEAR(eps, struct ep_set); - /* set dispatch functions */ - eps->func.free = ep_free; - eps->func.reset = ep_reset; - eps->func.del = ep_del; - eps->func.ctl = ep_ctl; - eps->func.wait = ep_wait; + /* set dispatch functions */ + eps->func.free = ep_free; + eps->func.reset = ep_reset; + eps->func.del = ep_del; + eps->func.ctl = ep_ctl; + eps->func.wait = ep_wait; - /* fast method ("sort of") corresponds to epoll one-shot */ - if (flags & EVENT_METHOD_FAST) - eps->fast = true; + /* fast method ("sort of") corresponds to epoll one-shot */ + if (flags & EVENT_METHOD_FAST) + { + eps->fast = true; + } - /* allocate space for epoll_wait return */ - ASSERT (*maxevents > 0); - eps->maxevents = *maxevents; - ALLOC_ARRAY_CLEAR (eps->events, struct epoll_event, eps->maxevents); + /* allocate space for epoll_wait return */ + ASSERT(*maxevents > 0); + eps->maxevents = *maxevents; + ALLOC_ARRAY_CLEAR(eps->events, struct epoll_event, eps->maxevents); - /* set epoll control fd */ - eps->epfd = fd; + /* set epoll control fd */ + eps->epfd = fd; - return (struct event_set *) eps; + return (struct event_set *) eps; } #endif /* EPOLL */ @@ -614,191 +685,207 @@ ep_init (int *maxevents, unsigned int flags) struct po_set { - struct event_set_functions func; - bool fast; - struct pollfd *events; - void **args; - int n_events; - int capacity; + struct event_set_functions func; + bool fast; + struct pollfd *events; + void **args; + int n_events; + int capacity; }; static void -po_free (struct event_set *es) +po_free(struct event_set *es) { - struct po_set *pos = (struct po_set *) es; - free (pos->events); - free (pos->args); - free (pos); + struct po_set *pos = (struct po_set *) es; + free(pos->events); + free(pos->args); + free(pos); } static void -po_reset (struct event_set *es) +po_reset(struct event_set *es) { - struct po_set *pos = (struct po_set *) es; - ASSERT (pos->fast); - pos->n_events = 0; + struct po_set *pos = (struct po_set *) es; + ASSERT(pos->fast); + pos->n_events = 0; } static void -po_del (struct event_set *es, event_t event) +po_del(struct event_set *es, event_t event) { - struct po_set *pos = (struct po_set *) es; - int i; + struct po_set *pos = (struct po_set *) es; + int i; - dmsg (D_EVENT_WAIT, "PO_DEL ev=%d", (int)event); + dmsg(D_EVENT_WAIT, "PO_DEL ev=%d", (int)event); - ASSERT (!pos->fast); - for (i = 0; i < pos->n_events; ++i) + ASSERT(!pos->fast); + for (i = 0; i < pos->n_events; ++i) { - if (pos->events[i].fd == event) - { - int j; - for (j = i; j < pos->n_events - 1; ++j) - { - pos->events[j] = pos->events[j+1]; - pos->args[j] = pos->args[j+1]; - } - --pos->n_events; - break; - } + if (pos->events[i].fd == event) + { + int j; + for (j = i; j < pos->n_events - 1; ++j) + { + pos->events[j] = pos->events[j+1]; + pos->args[j] = pos->args[j+1]; + } + --pos->n_events; + break; + } } } static inline void -po_set_pollfd_events (struct pollfd *pfdp, unsigned int rwflags) +po_set_pollfd_events(struct pollfd *pfdp, unsigned int rwflags) { - pfdp->events = 0; - if (rwflags & EVENT_WRITE) - pfdp->events |= POLLOUT; - if (rwflags & EVENT_READ) - pfdp->events |= (POLLIN|POLLPRI); + pfdp->events = 0; + if (rwflags & EVENT_WRITE) + { + pfdp->events |= POLLOUT; + } + if (rwflags & EVENT_READ) + { + pfdp->events |= (POLLIN|POLLPRI); + } } static inline bool -po_append_event (struct po_set *pos, event_t event, unsigned int rwflags, void *arg) +po_append_event(struct po_set *pos, event_t event, unsigned int rwflags, void *arg) { - if (pos->n_events < pos->capacity) + if (pos->n_events < pos->capacity) { - struct pollfd *pfdp = &pos->events[pos->n_events]; - pfdp->fd = event; - pos->args[pos->n_events] = arg; - po_set_pollfd_events (pfdp, rwflags); - ++pos->n_events; - return true; + struct pollfd *pfdp = &pos->events[pos->n_events]; + pfdp->fd = event; + pos->args[pos->n_events] = arg; + po_set_pollfd_events(pfdp, rwflags); + ++pos->n_events; + return true; + } + else + { + return false; } - else - return false; } static void -po_ctl (struct event_set *es, event_t event, unsigned int rwflags, void *arg) +po_ctl(struct event_set *es, event_t event, unsigned int rwflags, void *arg) { - struct po_set *pos = (struct po_set *) es; + struct po_set *pos = (struct po_set *) es; - dmsg (D_EVENT_WAIT, "PO_CTL rwflags=0x%04x ev=%d arg=" ptr_format, - rwflags, (int)event, (ptr_type)arg); + dmsg(D_EVENT_WAIT, "PO_CTL rwflags=0x%04x ev=%d arg=" ptr_format, + rwflags, (int)event, (ptr_type)arg); - if (pos->fast) + if (pos->fast) { - if (!po_append_event (pos, event, rwflags, arg)) - goto err; + if (!po_append_event(pos, event, rwflags, arg)) + { + goto err; + } } - else + else { - int i; - for (i = 0; i < pos->n_events; ++i) - { - struct pollfd *pfdp = &pos->events[i]; - if (pfdp->fd == event) - { - pos->args[i] = arg; - po_set_pollfd_events (pfdp, rwflags); - goto done; - } - } - if (!po_append_event (pos, event, rwflags, arg)) - goto err; + int i; + for (i = 0; i < pos->n_events; ++i) + { + struct pollfd *pfdp = &pos->events[i]; + if (pfdp->fd == event) + { + pos->args[i] = arg; + po_set_pollfd_events(pfdp, rwflags); + goto done; + } + } + if (!po_append_event(pos, event, rwflags, arg)) + { + goto err; + } } - done: - return; +done: + return; - err: - msg (D_EVENT_ERRORS, "Error: poll: too many I/O wait events"); +err: + msg(D_EVENT_ERRORS, "Error: poll: too many I/O wait events"); } static int -po_wait (struct event_set *es, const struct timeval *tv, struct event_set_return *out, int outlen) +po_wait(struct event_set *es, const struct timeval *tv, struct event_set_return *out, int outlen) { - struct po_set *pos = (struct po_set *) es; - int stat; + struct po_set *pos = (struct po_set *) es; + int stat; - stat = poll (pos->events, pos->n_events, tv_to_ms_timeout (tv)); + stat = poll(pos->events, pos->n_events, tv_to_ms_timeout(tv)); - ASSERT (stat <= pos->n_events); + ASSERT(stat <= pos->n_events); - if (stat > 0) + if (stat > 0) { - int i, j=0; - const struct pollfd *pfdp = pos->events; - for (i = 0; i < pos->n_events && j < outlen; ++i) - { - if (pfdp->revents & (POLLIN|POLLPRI|POLLERR|POLLHUP|POLLOUT)) - { - out->rwflags = 0; - if (pfdp->revents & (POLLIN|POLLPRI|POLLERR|POLLHUP)) - out->rwflags |= EVENT_READ; - if (pfdp->revents & POLLOUT) - out->rwflags |= EVENT_WRITE; - out->arg = pos->args[i]; - dmsg (D_EVENT_WAIT, "PO_WAIT[%d,%d] fd=%d rev=0x%08x rwflags=0x%04x arg=" ptr_format " %s", - i, j, pfdp->fd, pfdp->revents, out->rwflags, (ptr_type)out->arg, pos->fast ? "" : "[scalable]"); - ++out; - ++j; - } - else if (pfdp->revents) - { - msg (D_EVENT_ERRORS, "Error: poll: unknown revents=0x%04x", (unsigned int)pfdp->revents); - } - ++pfdp; - } - return j; + int i, j = 0; + const struct pollfd *pfdp = pos->events; + for (i = 0; i < pos->n_events && j < outlen; ++i) + { + if (pfdp->revents & (POLLIN|POLLPRI|POLLERR|POLLHUP|POLLOUT)) + { + out->rwflags = 0; + if (pfdp->revents & (POLLIN|POLLPRI|POLLERR|POLLHUP)) + { + out->rwflags |= EVENT_READ; + } + if (pfdp->revents & POLLOUT) + { + out->rwflags |= EVENT_WRITE; + } + out->arg = pos->args[i]; + dmsg(D_EVENT_WAIT, "PO_WAIT[%d,%d] fd=%d rev=0x%08x rwflags=0x%04x arg=" ptr_format " %s", + i, j, pfdp->fd, pfdp->revents, out->rwflags, (ptr_type)out->arg, pos->fast ? "" : "[scalable]"); + ++out; + ++j; + } + else if (pfdp->revents) + { + msg(D_EVENT_ERRORS, "Error: poll: unknown revents=0x%04x", (unsigned int)pfdp->revents); + } + ++pfdp; + } + return j; } - return stat; + return stat; } static struct event_set * -po_init (int *maxevents, unsigned int flags) +po_init(int *maxevents, unsigned int flags) { - struct po_set *pos; + struct po_set *pos; - dmsg (D_EVENT_WAIT, "PO_INIT maxevents=%d flags=0x%08x", *maxevents, flags); + dmsg(D_EVENT_WAIT, "PO_INIT maxevents=%d flags=0x%08x", *maxevents, flags); - ALLOC_OBJ_CLEAR (pos, struct po_set); + ALLOC_OBJ_CLEAR(pos, struct po_set); - /* set dispatch functions */ - pos->func.free = po_free; - pos->func.reset = po_reset; - pos->func.del = po_del; - pos->func.ctl = po_ctl; - pos->func.wait = po_wait; + /* set dispatch functions */ + pos->func.free = po_free; + pos->func.reset = po_reset; + pos->func.del = po_del; + pos->func.ctl = po_ctl; + pos->func.wait = po_wait; - if (flags & EVENT_METHOD_FAST) - pos->fast = true; + if (flags & EVENT_METHOD_FAST) + { + pos->fast = true; + } - pos->n_events = 0; + pos->n_events = 0; - /* Figure our event capacity */ - ASSERT (*maxevents > 0); - pos->capacity = *maxevents; + /* Figure our event capacity */ + ASSERT(*maxevents > 0); + pos->capacity = *maxevents; - /* Allocate space for pollfd structures to be passed to poll() */ - ALLOC_ARRAY_CLEAR (pos->events, struct pollfd, pos->capacity); + /* Allocate space for pollfd structures to be passed to poll() */ + ALLOC_ARRAY_CLEAR(pos->events, struct pollfd, pos->capacity); - /* Allocate space for event_set_return objects */ - ALLOC_ARRAY_CLEAR (pos->args, void *, pos->capacity); + /* Allocate space for event_set_return objects */ + ALLOC_ARRAY_CLEAR(pos->args, void *, pos->capacity); - return (struct event_set *) pos; + return (struct event_set *) pos; } #endif /* POLL */ @@ -806,259 +893,295 @@ po_init (int *maxevents, unsigned int flags) struct se_set { - struct event_set_functions func; - bool fast; - fd_set readfds; - fd_set writefds; - void **args; /* allocated to capacity size */ - int maxfd; /* largest fd seen so far, always < capacity */ - int capacity; /* fixed largest fd + 1 */ + struct event_set_functions func; + bool fast; + fd_set readfds; + fd_set writefds; + void **args; /* allocated to capacity size */ + int maxfd; /* largest fd seen so far, always < capacity */ + int capacity; /* fixed largest fd + 1 */ }; static void -se_free (struct event_set *es) +se_free(struct event_set *es) { - struct se_set *ses = (struct se_set *) es; - free (ses->args); - free (ses); + struct se_set *ses = (struct se_set *) es; + free(ses->args); + free(ses); } static void -se_reset (struct event_set *es) +se_reset(struct event_set *es) { - struct se_set *ses = (struct se_set *) es; - int i; - ASSERT (ses->fast); - - dmsg (D_EVENT_WAIT, "SE_RESET"); - - FD_ZERO (&ses->readfds); - FD_ZERO (&ses->writefds); - for (i = 0; i <= ses->maxfd; ++i) - ses->args[i] = NULL; - ses->maxfd = -1; + struct se_set *ses = (struct se_set *) es; + int i; + ASSERT(ses->fast); + + dmsg(D_EVENT_WAIT, "SE_RESET"); + + FD_ZERO(&ses->readfds); + FD_ZERO(&ses->writefds); + for (i = 0; i <= ses->maxfd; ++i) + ses->args[i] = NULL; + ses->maxfd = -1; } static void -se_del (struct event_set *es, event_t event) +se_del(struct event_set *es, event_t event) { - struct se_set *ses = (struct se_set *) es; - ASSERT (!ses->fast); + struct se_set *ses = (struct se_set *) es; + ASSERT(!ses->fast); - dmsg (D_EVENT_WAIT, "SE_DEL ev=%d", (int)event); + dmsg(D_EVENT_WAIT, "SE_DEL ev=%d", (int)event); - if (event >= 0 && event < ses->capacity) + if (event >= 0 && event < ses->capacity) + { + FD_CLR(event, &ses->readfds); + FD_CLR(event, &ses->writefds); + ses->args[event] = NULL; + } + else { - FD_CLR (event, &ses->readfds); - FD_CLR (event, &ses->writefds); - ses->args[event] = NULL; + msg(D_EVENT_ERRORS, "Error: select/se_del: too many I/O wait events"); } - else - msg (D_EVENT_ERRORS, "Error: select/se_del: too many I/O wait events"); - return; + return; } static void -se_ctl (struct event_set *es, event_t event, unsigned int rwflags, void *arg) +se_ctl(struct event_set *es, event_t event, unsigned int rwflags, void *arg) { - struct se_set *ses = (struct se_set *) es; + struct se_set *ses = (struct se_set *) es; - dmsg (D_EVENT_WAIT, "SE_CTL rwflags=0x%04x ev=%d fast=%d cap=%d maxfd=%d arg=" ptr_format, - rwflags, (int)event, (int)ses->fast, ses->capacity, ses->maxfd, (ptr_type)arg); + dmsg(D_EVENT_WAIT, "SE_CTL rwflags=0x%04x ev=%d fast=%d cap=%d maxfd=%d arg=" ptr_format, + rwflags, (int)event, (int)ses->fast, ses->capacity, ses->maxfd, (ptr_type)arg); - if (event >= 0 && event < ses->capacity) + if (event >= 0 && event < ses->capacity) { - ses->maxfd = max_int (event, ses->maxfd); - ses->args[event] = arg; - if (ses->fast) - { - if (rwflags & EVENT_READ) - openvpn_fd_set (event, &ses->readfds); - if (rwflags & EVENT_WRITE) - openvpn_fd_set (event, &ses->writefds); - } - else - { - if (rwflags & EVENT_READ) - openvpn_fd_set (event, &ses->readfds); - else - FD_CLR (event, &ses->readfds); - if (rwflags & EVENT_WRITE) - openvpn_fd_set (event, &ses->writefds); - else - FD_CLR (event, &ses->writefds); - } + ses->maxfd = max_int(event, ses->maxfd); + ses->args[event] = arg; + if (ses->fast) + { + if (rwflags & EVENT_READ) + { + openvpn_fd_set(event, &ses->readfds); + } + if (rwflags & EVENT_WRITE) + { + openvpn_fd_set(event, &ses->writefds); + } + } + else + { + if (rwflags & EVENT_READ) + { + openvpn_fd_set(event, &ses->readfds); + } + else + { + FD_CLR(event, &ses->readfds); + } + if (rwflags & EVENT_WRITE) + { + openvpn_fd_set(event, &ses->writefds); + } + else + { + FD_CLR(event, &ses->writefds); + } + } } - else + else { - msg (D_EVENT_ERRORS, "Error: select: too many I/O wait events, fd=%d cap=%d", - (int) event, - ses->capacity); + msg(D_EVENT_ERRORS, "Error: select: too many I/O wait events, fd=%d cap=%d", + (int) event, + ses->capacity); } } static int -se_wait_return (struct se_set *ses, - fd_set *read, - fd_set *write, - struct event_set_return *out, - int outlen) +se_wait_return(struct se_set *ses, + fd_set *read, + fd_set *write, + struct event_set_return *out, + int outlen) { - int i, j = 0; - for (i = 0; i <= ses->maxfd && j < outlen; ++i) + int i, j = 0; + for (i = 0; i <= ses->maxfd && j < outlen; ++i) { - const bool r = FD_ISSET (i, read); - const bool w = FD_ISSET (i, write); - if (r || w) - { - out->rwflags = 0; - if (r) - out->rwflags |= EVENT_READ; - if (w) - out->rwflags |= EVENT_WRITE; - out->arg = ses->args[i]; - dmsg (D_EVENT_WAIT, "SE_WAIT[%d,%d] rwflags=0x%04x arg=" ptr_format, - i, j, out->rwflags, (ptr_type)out->arg); - ++out; - ++j; - } + const bool r = FD_ISSET(i, read); + const bool w = FD_ISSET(i, write); + if (r || w) + { + out->rwflags = 0; + if (r) + { + out->rwflags |= EVENT_READ; + } + if (w) + { + out->rwflags |= EVENT_WRITE; + } + out->arg = ses->args[i]; + dmsg(D_EVENT_WAIT, "SE_WAIT[%d,%d] rwflags=0x%04x arg=" ptr_format, + i, j, out->rwflags, (ptr_type)out->arg); + ++out; + ++j; + } } - return j; + return j; } static int -se_wait_fast (struct event_set *es, const struct timeval *tv, struct event_set_return *out, int outlen) +se_wait_fast(struct event_set *es, const struct timeval *tv, struct event_set_return *out, int outlen) { - struct se_set *ses = (struct se_set *) es; - struct timeval tv_tmp = *tv; - int stat; + struct se_set *ses = (struct se_set *) es; + struct timeval tv_tmp = *tv; + int stat; - dmsg (D_EVENT_WAIT, "SE_WAIT_FAST maxfd=%d tv=%d/%d", - ses->maxfd, - (int)tv_tmp.tv_sec, - (int)tv_tmp.tv_usec); + dmsg(D_EVENT_WAIT, "SE_WAIT_FAST maxfd=%d tv=%d/%d", + ses->maxfd, + (int)tv_tmp.tv_sec, + (int)tv_tmp.tv_usec); - stat = select (ses->maxfd + 1, &ses->readfds, &ses->writefds, NULL, &tv_tmp); + stat = select(ses->maxfd + 1, &ses->readfds, &ses->writefds, NULL, &tv_tmp); - if (stat > 0) - stat = se_wait_return (ses, &ses->readfds, &ses->writefds, out, outlen); + if (stat > 0) + { + stat = se_wait_return(ses, &ses->readfds, &ses->writefds, out, outlen); + } - return stat; + return stat; } static int -se_wait_scalable (struct event_set *es, const struct timeval *tv, struct event_set_return *out, int outlen) +se_wait_scalable(struct event_set *es, const struct timeval *tv, struct event_set_return *out, int outlen) { - struct se_set *ses = (struct se_set *) es; - struct timeval tv_tmp = *tv; - fd_set read = ses->readfds; - fd_set write = ses->writefds; - int stat; + struct se_set *ses = (struct se_set *) es; + struct timeval tv_tmp = *tv; + fd_set read = ses->readfds; + fd_set write = ses->writefds; + int stat; - dmsg (D_EVENT_WAIT, "SE_WAIT_SCALEABLE maxfd=%d tv=%d/%d", - ses->maxfd, (int)tv_tmp.tv_sec, (int)tv_tmp.tv_usec); + dmsg(D_EVENT_WAIT, "SE_WAIT_SCALEABLE maxfd=%d tv=%d/%d", + ses->maxfd, (int)tv_tmp.tv_sec, (int)tv_tmp.tv_usec); - stat = select (ses->maxfd + 1, &read, &write, NULL, &tv_tmp); + stat = select(ses->maxfd + 1, &read, &write, NULL, &tv_tmp); - if (stat > 0) - stat = se_wait_return (ses, &read, &write, out, outlen); + if (stat > 0) + { + stat = se_wait_return(ses, &read, &write, out, outlen); + } - return stat; + return stat; } static struct event_set * -se_init (int *maxevents, unsigned int flags) +se_init(int *maxevents, unsigned int flags) { - struct se_set *ses; + struct se_set *ses; - dmsg (D_EVENT_WAIT, "SE_INIT maxevents=%d flags=0x%08x", *maxevents, flags); + dmsg(D_EVENT_WAIT, "SE_INIT maxevents=%d flags=0x%08x", *maxevents, flags); - ALLOC_OBJ_CLEAR (ses, struct se_set); + ALLOC_OBJ_CLEAR(ses, struct se_set); - /* set dispatch functions */ - ses->func.free = se_free; - ses->func.reset = se_reset; - ses->func.del = se_del; - ses->func.ctl = se_ctl; - ses->func.wait = se_wait_scalable; + /* set dispatch functions */ + ses->func.free = se_free; + ses->func.reset = se_reset; + ses->func.del = se_del; + ses->func.ctl = se_ctl; + ses->func.wait = se_wait_scalable; - if (flags & EVENT_METHOD_FAST) + if (flags & EVENT_METHOD_FAST) { - ses->fast = true; - ses->func.wait = se_wait_fast; + ses->fast = true; + ses->func.wait = se_wait_fast; } - /* Select needs to be passed this value + 1 */ - ses->maxfd = -1; + /* Select needs to be passed this value + 1 */ + ses->maxfd = -1; - /* Set our event capacity */ - ASSERT (*maxevents > 0); - *maxevents = min_int (*maxevents, SELECT_MAX_FDS); - ses->capacity = SELECT_MAX_FDS; + /* Set our event capacity */ + ASSERT(*maxevents > 0); + *maxevents = min_int(*maxevents, SELECT_MAX_FDS); + ses->capacity = SELECT_MAX_FDS; - /* Allocate space for event_set_return void * args */ - ALLOC_ARRAY_CLEAR (ses->args, void *, ses->capacity); + /* Allocate space for event_set_return void * args */ + ALLOC_ARRAY_CLEAR(ses->args, void *, ses->capacity); - return (struct event_set *) ses; + return (struct event_set *) ses; } #endif /* SELECT */ static struct event_set * -event_set_init_simple (int *maxevents, unsigned int flags) +event_set_init_simple(int *maxevents, unsigned int flags) { - struct event_set *ret = NULL; + struct event_set *ret = NULL; #ifdef _WIN32 - ret = we_init (maxevents, flags); + ret = we_init(maxevents, flags); #elif POLL && SELECT #if 0 /* Define to 1 if EVENT_METHOD_US_TIMEOUT should cause select to be favored over poll */ - if (flags & EVENT_METHOD_US_TIMEOUT) - ret = se_init (maxevents, flags); + if (flags & EVENT_METHOD_US_TIMEOUT) + { + ret = se_init(maxevents, flags); + } +#endif +#ifdef SELECT_PREFERRED_OVER_POLL + if (!ret) + { + ret = se_init(maxevents, flags); + } + if (!ret) + { + ret = po_init(maxevents, flags); + } +#else /* ifdef SELECT_PREFERRED_OVER_POLL */ + if (!ret) + { + ret = po_init(maxevents, flags); + } + if (!ret) + { + ret = se_init(maxevents, flags); + } #endif -# ifdef SELECT_PREFERRED_OVER_POLL - if (!ret) - ret = se_init (maxevents, flags); - if (!ret) - ret = po_init (maxevents, flags); -# else - if (!ret) - ret = po_init (maxevents, flags); - if (!ret) - ret = se_init (maxevents, flags); -# endif #elif POLL - ret = po_init (maxevents, flags); + ret = po_init(maxevents, flags); #elif SELECT - ret = se_init (maxevents, flags); -#else + ret = se_init(maxevents, flags); +#else /* ifdef _WIN32 */ #error At least one of poll, select, or WSAWaitForMultipleEvents must be supported by the kernel -#endif - ASSERT (ret); - return ret; +#endif /* ifdef _WIN32 */ + ASSERT(ret); + return ret; } static struct event_set * -event_set_init_scalable (int *maxevents, unsigned int flags) +event_set_init_scalable(int *maxevents, unsigned int flags) { - struct event_set *ret = NULL; + struct event_set *ret = NULL; #if EPOLL - ret = ep_init (maxevents, flags); - if (!ret) + ret = ep_init(maxevents, flags); + if (!ret) { - msg (M_WARN, "Note: sys_epoll API is unavailable, falling back to poll/select API"); - ret = event_set_init_simple (maxevents, flags); + msg(M_WARN, "Note: sys_epoll API is unavailable, falling back to poll/select API"); + ret = event_set_init_simple(maxevents, flags); } -#else - ret = event_set_init_simple (maxevents, flags); +#else /* if EPOLL */ + ret = event_set_init_simple(maxevents, flags); #endif - ASSERT (ret); - return ret; + ASSERT(ret); + return ret; } struct event_set * -event_set_init (int *maxevents, unsigned int flags) +event_set_init(int *maxevents, unsigned int flags) { - if (flags & EVENT_METHOD_FAST) - return event_set_init_simple (maxevents, flags); - else - return event_set_init_scalable (maxevents, flags); + if (flags & EVENT_METHOD_FAST) + { + return event_set_init_simple(maxevents, flags); + } + else + { + return event_set_init_scalable(maxevents, flags); + } } diff --git a/src/openvpn/event.h b/src/openvpn/event.h index 565343d3f30..5e66d482ed1 100644 --- a/src/openvpn/event.h +++ b/src/openvpn/event.h @@ -48,7 +48,7 @@ typedef const struct rw_handle *event_t; #define UNDEFINED_EVENT (NULL) -#else +#else /* ifdef _WIN32 */ typedef int event_t; @@ -61,29 +61,29 @@ struct event_set_return; struct event_set_functions { - void (*free)(struct event_set *es); - void (*reset)(struct event_set *es); - void (*del)(struct event_set *es, event_t event); - void (*ctl)(struct event_set *es, event_t event, unsigned int rwflags, void *arg); - - /* - * Return status for wait: - * -1 on signal or error - * 0 on timeout - * length of event_set_return if at least 1 event is returned - */ - int (*wait)(struct event_set *es, const struct timeval *tv, struct event_set_return *out, int outlen); + void (*free)(struct event_set *es); + void (*reset)(struct event_set *es); + void (*del)(struct event_set *es, event_t event); + void (*ctl)(struct event_set *es, event_t event, unsigned int rwflags, void *arg); + + /* + * Return status for wait: + * -1 on signal or error + * 0 on timeout + * length of event_set_return if at least 1 event is returned + */ + int (*wait)(struct event_set *es, const struct timeval *tv, struct event_set_return *out, int outlen); }; struct event_set_return { - unsigned int rwflags; - void *arg; + unsigned int rwflags; + void *arg; }; struct event_set { - struct event_set_functions func; + struct event_set_functions func; }; /* @@ -93,66 +93,70 @@ struct event_set * of underlying API * flags: EVENT_METHOD_x flags */ -struct event_set *event_set_init (int *maxevents, unsigned int flags); +struct event_set *event_set_init(int *maxevents, unsigned int flags); static inline void -event_free (struct event_set *es) +event_free(struct event_set *es) { - if (es) - (*es->func.free)(es); + if (es) + { + (*es->func.free)(es); + } } static inline void -event_reset (struct event_set *es) +event_reset(struct event_set *es) { - (*es->func.reset)(es); + (*es->func.reset)(es); } static inline void -event_del (struct event_set *es, event_t event) +event_del(struct event_set *es, event_t event) { - (*es->func.del)(es, event); + (*es->func.del)(es, event); } static inline void -event_ctl (struct event_set *es, event_t event, unsigned int rwflags, void *arg) +event_ctl(struct event_set *es, event_t event, unsigned int rwflags, void *arg) { - (*es->func.ctl)(es, event, rwflags, arg); + (*es->func.ctl)(es, event, rwflags, arg); } static inline int -event_wait (struct event_set *es, const struct timeval *tv, struct event_set_return *out, int outlen) +event_wait(struct event_set *es, const struct timeval *tv, struct event_set_return *out, int outlen) { - int ret; - perf_push (PERF_IO_WAIT); - ret = (*es->func.wait)(es, tv, out, outlen); - perf_pop (); - return ret; + int ret; + perf_push(PERF_IO_WAIT); + ret = (*es->func.wait)(es, tv, out, outlen); + perf_pop(); + return ret; } static inline void -event_set_return_init (struct event_set_return *esr) +event_set_return_init(struct event_set_return *esr) { - esr->rwflags = 0; - esr->arg = NULL; + esr->rwflags = 0; + esr->arg = NULL; } #ifdef _WIN32 static inline void -wait_signal (struct event_set *es, void *arg) +wait_signal(struct event_set *es, void *arg) { - if (HANDLE_DEFINED (win32_signal.in.read)) - event_ctl (es, &win32_signal.in, EVENT_READ, arg); + if (HANDLE_DEFINED(win32_signal.in.read)) + { + event_ctl(es, &win32_signal.in, EVENT_READ, arg); + } } -#else +#else /* ifdef _WIN32 */ static inline void -wait_signal (struct event_set *es, void *arg) +wait_signal(struct event_set *es, void *arg) { } #endif -#endif +#endif /* ifndef EVENT_H */ diff --git a/src/openvpn/fdmisc.c b/src/openvpn/fdmisc.c index ce01319713a..3851c43d143 100644 --- a/src/openvpn/fdmisc.c +++ b/src/openvpn/fdmisc.c @@ -37,42 +37,52 @@ /* Set a file descriptor to non-blocking */ bool -set_nonblock_action (int fd) +set_nonblock_action(int fd) { #ifdef _WIN32 - u_long arg = 1; - if (ioctlsocket (fd, FIONBIO, &arg)) - return false; -#else - if (fcntl (fd, F_SETFL, O_NONBLOCK) < 0) - return false; + u_long arg = 1; + if (ioctlsocket(fd, FIONBIO, &arg)) + { + return false; + } +#else /* ifdef _WIN32 */ + if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) + { + return false; + } #endif - return true; + return true; } /* Set a file descriptor to not be passed across execs */ bool -set_cloexec_action (int fd) +set_cloexec_action(int fd) { #ifndef _WIN32 - if (fcntl (fd, F_SETFD, FD_CLOEXEC) < 0) - return false; + if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) + { + return false; + } #endif - return true; + return true; } /* Set a file descriptor to non-blocking */ void -set_nonblock (int fd) +set_nonblock(int fd) { - if (!set_nonblock_action (fd)) - msg (M_ERR, "Set socket to non-blocking mode failed"); + if (!set_nonblock_action(fd)) + { + msg(M_ERR, "Set socket to non-blocking mode failed"); + } } /* Set a file descriptor to not be passed across execs */ void -set_cloexec (int fd) +set_cloexec(int fd) { - if (!set_cloexec_action (fd)) - msg (M_ERR, "Set FD_CLOEXEC flag on file descriptor failed"); + if (!set_cloexec_action(fd)) + { + msg(M_ERR, "Set FD_CLOEXEC flag on file descriptor failed"); + } } diff --git a/src/openvpn/fdmisc.h b/src/openvpn/fdmisc.h index d34db9bd194..bd9b47ca220 100644 --- a/src/openvpn/fdmisc.h +++ b/src/openvpn/fdmisc.h @@ -29,18 +29,21 @@ #include "error.h" #include "syshead.h" -bool set_nonblock_action (int fd); -bool set_cloexec_action (int fd); +bool set_nonblock_action(int fd); -void set_nonblock (int fd); -void set_cloexec (int fd); +bool set_cloexec_action(int fd); -static inline void openvpn_fd_set(int fd, fd_set *setp) +void set_nonblock(int fd); + +void set_cloexec(int fd); + +static inline void +openvpn_fd_set(int fd, fd_set *setp) { #ifndef _WIN32 /* The Windows FD_SET() implementation does not overflow */ - ASSERT (fd >= 0 && fd < FD_SETSIZE); + ASSERT(fd >= 0 && fd < FD_SETSIZE); #endif - FD_SET (fd, setp); + FD_SET(fd, setp); } #undef FD_SET /* prevent direct use of FD_SET() */ diff --git a/src/openvpn/forward-inline.h b/src/openvpn/forward-inline.h index 5d4e3089977..6bce755f66c 100644 --- a/src/openvpn/forward-inline.h +++ b/src/openvpn/forward-inline.h @@ -33,12 +33,15 @@ * Does TLS session need service? */ static inline void -check_tls (struct context *c) +check_tls(struct context *c) { #if defined(ENABLE_CRYPTO) - void check_tls_dowork (struct context *c); - if (c->c2.tls_multi) - check_tls_dowork (c); + void check_tls_dowork(struct context *c); + + if (c->c2.tls_multi) + { + check_tls_dowork(c); + } #endif } @@ -47,25 +50,31 @@ check_tls (struct context *c) * Also check for --tls-exit trigger. */ static inline void -check_tls_errors (struct context *c) +check_tls_errors(struct context *c) { #if defined(ENABLE_CRYPTO) - void check_tls_errors_co (struct context *c); - void check_tls_errors_nco (struct context *c); - if (c->c2.tls_multi && c->c2.tls_exit_signal) + void check_tls_errors_co(struct context *c); + + void check_tls_errors_nco(struct context *c); + + if (c->c2.tls_multi && c->c2.tls_exit_signal) { - if (link_socket_connection_oriented (c->c2.link_socket)) - { - if (c->c2.tls_multi->n_soft_errors) - check_tls_errors_co (c); - } - else - { - if (c->c2.tls_multi->n_hard_errors) - check_tls_errors_nco (c); - } + if (link_socket_connection_oriented(c->c2.link_socket)) + { + if (c->c2.tls_multi->n_soft_errors) + { + check_tls_errors_co(c); + } + } + else + { + if (c->c2.tls_multi->n_hard_errors) + { + check_tls_errors_nco(c); + } + } } -#endif +#endif /* if defined(ENABLE_CRYPTO) */ } /* @@ -73,12 +82,15 @@ check_tls_errors (struct context *c) * messages on the control channel. */ static inline void -check_incoming_control_channel (struct context *c) +check_incoming_control_channel(struct context *c) { #if P2MP - void check_incoming_control_channel_dowork (struct context *c); - if (tls_test_payload_len (c->c2.tls_multi) > 0) - check_incoming_control_channel_dowork (c); + void check_incoming_control_channel_dowork(struct context *c); + + if (tls_test_payload_len(c->c2.tls_multi) > 0) + { + check_incoming_control_channel_dowork(c); + } #endif } @@ -87,77 +99,91 @@ check_incoming_control_channel (struct context *c) * checks for connection establishment. */ static inline void -check_connection_established (struct context *c) +check_connection_established(struct context *c) { - void check_connection_established_dowork (struct context *c); - if (event_timeout_defined (&c->c2.wait_for_connect)) - check_connection_established_dowork (c); + void check_connection_established_dowork(struct context *c); + + if (event_timeout_defined(&c->c2.wait_for_connect)) + { + check_connection_established_dowork(c); + } } /* * Should we add routes? */ static inline void -check_add_routes (struct context *c) +check_add_routes(struct context *c) { - void check_add_routes_dowork (struct context *c); - if (event_timeout_trigger (&c->c2.route_wakeup, &c->c2.timeval, ETT_DEFAULT)) - check_add_routes_dowork (c); + void check_add_routes_dowork(struct context *c); + + if (event_timeout_trigger(&c->c2.route_wakeup, &c->c2.timeval, ETT_DEFAULT)) + { + check_add_routes_dowork(c); + } } /* * Should we exit due to inactivity timeout? */ static inline void -check_inactivity_timeout (struct context *c) +check_inactivity_timeout(struct context *c) { - void check_inactivity_timeout_dowork (struct context *c); + void check_inactivity_timeout_dowork(struct context *c); - if (c->options.inactivity_timeout - && event_timeout_trigger (&c->c2.inactivity_interval, &c->c2.timeval, ETT_DEFAULT)) - check_inactivity_timeout_dowork (c); + if (c->options.inactivity_timeout + && event_timeout_trigger(&c->c2.inactivity_interval, &c->c2.timeval, ETT_DEFAULT)) + { + check_inactivity_timeout_dowork(c); + } } #if P2MP static inline void -check_server_poll_timeout (struct context *c) +check_server_poll_timeout(struct context *c) { - void check_server_poll_timeout_dowork (struct context *c); + void check_server_poll_timeout_dowork(struct context *c); - if (c->options.ce.connect_timeout - && event_timeout_trigger (&c->c2.server_poll_interval, &c->c2.timeval, ETT_DEFAULT)) - check_server_poll_timeout_dowork (c); + if (c->options.ce.connect_timeout + && event_timeout_trigger(&c->c2.server_poll_interval, &c->c2.timeval, ETT_DEFAULT)) + { + check_server_poll_timeout_dowork(c); + } } /* * Scheduled exit? */ static inline void -check_scheduled_exit (struct context *c) +check_scheduled_exit(struct context *c) { - void check_scheduled_exit_dowork (struct context *c); + void check_scheduled_exit_dowork(struct context *c); - if (event_timeout_defined (&c->c2.scheduled_exit)) + if (event_timeout_defined(&c->c2.scheduled_exit)) { - if (event_timeout_trigger (&c->c2.scheduled_exit, &c->c2.timeval, ETT_DEFAULT)) - check_scheduled_exit_dowork (c); + if (event_timeout_trigger(&c->c2.scheduled_exit, &c->c2.timeval, ETT_DEFAULT)) + { + check_scheduled_exit_dowork(c); + } } } -#endif +#endif /* if P2MP */ /* * Should we write timer-triggered status file. */ static inline void -check_status_file (struct context *c) +check_status_file(struct context *c) { - void check_status_file_dowork (struct context *c); + void check_status_file_dowork(struct context *c); - if (c->c1.status_output) + if (c->c1.status_output) { - if (status_trigger_tv (c->c1.status_output, &c->c2.timeval)) - check_status_file_dowork (c); + if (status_trigger_tv(c->c1.status_output, &c->c2.timeval)) + { + check_status_file_dowork(c); + } } } @@ -166,11 +192,14 @@ check_status_file (struct context *c) * Should we deliver a datagram fragment to remote? */ static inline void -check_fragment (struct context *c) +check_fragment(struct context *c) { - void check_fragment_dowork (struct context *c); - if (c->c2.fragment) - check_fragment_dowork (c); + void check_fragment_dowork(struct context *c); + + if (c->c2.fragment) + { + check_fragment_dowork(c); + } } #endif @@ -180,11 +209,14 @@ check_fragment (struct context *c) * see if we should send a push_request in response to --pull */ static inline void -check_push_request (struct context *c) +check_push_request(struct context *c) { - void check_push_request_dowork (struct context *c); - if (event_timeout_trigger (&c->c2.push_request_interval, &c->c2.timeval, ETT_DEFAULT)) - check_push_request_dowork (c); + void check_push_request_dowork(struct context *c); + + if (event_timeout_trigger(&c->c2.push_request_interval, &c->c2.timeval, ETT_DEFAULT)) + { + check_push_request_dowork(c); + } } #endif @@ -194,11 +226,13 @@ check_push_request (struct context *c) * Should we persist our anti-replay packet ID state to disk? */ static inline void -check_packet_id_persist_flush (struct context *c) +check_packet_id_persist_flush(struct context *c) { - if (packet_id_persist_enabled (&c->c1.pid_persist) - && event_timeout_trigger (&c->c2.packet_id_persist_interval, &c->c2.timeval, ETT_DEFAULT)) - packet_id_persist_save (&c->c1.pid_persist); + if (packet_id_persist_enabled(&c->c1.pid_persist) + && event_timeout_trigger(&c->c2.packet_id_persist_interval, &c->c2.timeval, ETT_DEFAULT)) + { + packet_id_persist_save(&c->c1.pid_persist); + } } #endif @@ -207,44 +241,50 @@ check_packet_id_persist_flush (struct context *c) * immediately. */ static inline void -context_immediate_reschedule (struct context *c) +context_immediate_reschedule(struct context *c) { - c->c2.timeval.tv_sec = 0; /* ZERO-TIMEOUT */ - c->c2.timeval.tv_usec = 0; + c->c2.timeval.tv_sec = 0; /* ZERO-TIMEOUT */ + c->c2.timeval.tv_usec = 0; } static inline void -context_reschedule_sec (struct context *c, int sec) +context_reschedule_sec(struct context *c, int sec) { - if (sec < 0) - sec = 0; - if (sec < c->c2.timeval.tv_sec) + if (sec < 0) { - c->c2.timeval.tv_sec = sec; - c->c2.timeval.tv_usec = 0; + sec = 0; + } + if (sec < c->c2.timeval.tv_sec) + { + c->c2.timeval.tv_sec = sec; + c->c2.timeval.tv_usec = 0; } } static inline struct link_socket_info * -get_link_socket_info (struct context *c) +get_link_socket_info(struct context *c) { - if (c->c2.link_socket_info) - return c->c2.link_socket_info; - else - return &c->c2.link_socket->info; + if (c->c2.link_socket_info) + { + return c->c2.link_socket_info; + } + else + { + return &c->c2.link_socket->info; + } } static inline void -register_activity (struct context *c, const int size) +register_activity(struct context *c, const int size) { - if (c->options.inactivity_timeout) + if (c->options.inactivity_timeout) { - c->c2.inactivity_bytes += size; - if (c->c2.inactivity_bytes >= c->options.inactivity_minimum_bytes) - { - c->c2.inactivity_bytes = 0; - event_timeout_reset (&c->c2.inactivity_interval); - } + c->c2.inactivity_bytes += size; + if (c->c2.inactivity_bytes >= c->options.inactivity_minimum_bytes) + { + c->c2.inactivity_bytes = 0; + event_timeout_reset(&c->c2.inactivity_interval); + } } } @@ -253,14 +293,18 @@ register_activity (struct context *c, const int size) * a point-to-point tunnel. */ static inline unsigned int -p2p_iow_flags (const struct context *c) +p2p_iow_flags(const struct context *c) { - unsigned int flags = (IOW_SHAPER|IOW_CHECK_RESIDUAL|IOW_FRAG|IOW_READ|IOW_WAIT_SIGNAL); - if (c->c2.to_link.len > 0) - flags |= IOW_TO_LINK; - if (c->c2.to_tun.len > 0) - flags |= IOW_TO_TUN; - return flags; + unsigned int flags = (IOW_SHAPER|IOW_CHECK_RESIDUAL|IOW_FRAG|IOW_READ|IOW_WAIT_SIGNAL); + if (c->c2.to_link.len > 0) + { + flags |= IOW_TO_LINK; + } + if (c->c2.to_tun.len > 0) + { + flags |= IOW_TO_TUN; + } + return flags; } /* @@ -268,24 +312,28 @@ p2p_iow_flags (const struct context *c) * for TCP in server mode. */ static inline void -io_wait (struct context *c, const unsigned int flags) +io_wait(struct context *c, const unsigned int flags) { - void io_wait_dowork (struct context *c, const unsigned int flags); + void io_wait_dowork(struct context *c, const unsigned int flags); - if (c->c2.fast_io && (flags & (IOW_TO_TUN|IOW_TO_LINK|IOW_MBUF))) + if (c->c2.fast_io && (flags & (IOW_TO_TUN|IOW_TO_LINK|IOW_MBUF))) { - /* fast path -- only for TUN/TAP/UDP writes */ - unsigned int ret = 0; - if (flags & IOW_TO_TUN) - ret |= TUN_WRITE; - if (flags & (IOW_TO_LINK|IOW_MBUF)) - ret |= SOCKET_WRITE; - c->c2.event_set_status = ret; + /* fast path -- only for TUN/TAP/UDP writes */ + unsigned int ret = 0; + if (flags & IOW_TO_TUN) + { + ret |= TUN_WRITE; + } + if (flags & (IOW_TO_LINK|IOW_MBUF)) + { + ret |= SOCKET_WRITE; + } + c->c2.event_set_status = ret; } - else + else { - /* slow path */ - io_wait_dowork (c, flags); + /* slow path */ + io_wait_dowork(c, flags); } } diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c index 4502e10127c..ab560562492 100644 --- a/src/openvpn/forward.c +++ b/src/openvpn/forward.c @@ -56,27 +56,27 @@ counter_type link_write_bytes_global; /* GLOBAL */ #ifdef ENABLE_DEBUG const char * -wait_status_string (struct context *c, struct gc_arena *gc) +wait_status_string(struct context *c, struct gc_arena *gc) { - struct buffer out = alloc_buf_gc (64, gc); - buf_printf (&out, "I/O WAIT %s|%s|%s|%s %s", - tun_stat (c->c1.tuntap, EVENT_READ, gc), - tun_stat (c->c1.tuntap, EVENT_WRITE, gc), - socket_stat (c->c2.link_socket, EVENT_READ, gc), - socket_stat (c->c2.link_socket, EVENT_WRITE, gc), - tv_string (&c->c2.timeval, gc)); - return BSTR (&out); + struct buffer out = alloc_buf_gc(64, gc); + buf_printf(&out, "I/O WAIT %s|%s|%s|%s %s", + tun_stat(c->c1.tuntap, EVENT_READ, gc), + tun_stat(c->c1.tuntap, EVENT_WRITE, gc), + socket_stat(c->c2.link_socket, EVENT_READ, gc), + socket_stat(c->c2.link_socket, EVENT_WRITE, gc), + tv_string(&c->c2.timeval, gc)); + return BSTR(&out); } void -show_wait_status (struct context *c) +show_wait_status(struct context *c) { - struct gc_arena gc = gc_new (); - dmsg (D_EVENT_WAIT, "%s", wait_status_string (c, &gc)); - gc_free (&gc); + struct gc_arena gc = gc_new(); + dmsg(D_EVENT_WAIT, "%s", wait_status_string(c, &gc)); + gc_free(&gc); } -#endif +#endif /* ifdef ENABLE_DEBUG */ /* * In TLS mode, let TLS level respond to any control-channel @@ -90,45 +90,47 @@ show_wait_status (struct context *c) */ #ifdef ENABLE_CRYPTO void -check_tls_dowork (struct context *c) +check_tls_dowork(struct context *c) { - interval_t wakeup = BIG_TIMEOUT; + interval_t wakeup = BIG_TIMEOUT; - if (interval_test (&c->c2.tmp_int)) + if (interval_test(&c->c2.tmp_int)) { - const int tmp_status = tls_multi_process - (c->c2.tls_multi, &c->c2.to_link, &c->c2.to_link_addr, - get_link_socket_info (c), &wakeup); - if (tmp_status == TLSMP_ACTIVE) - { - update_time (); - interval_action (&c->c2.tmp_int); - } - else if (tmp_status == TLSMP_KILL) - { - register_signal (c, SIGTERM, "auth-control-exit"); - } - - interval_future_trigger (&c->c2.tmp_int, wakeup); + const int tmp_status = tls_multi_process + (c->c2.tls_multi, &c->c2.to_link, &c->c2.to_link_addr, + get_link_socket_info(c), &wakeup); + if (tmp_status == TLSMP_ACTIVE) + { + update_time(); + interval_action(&c->c2.tmp_int); + } + else if (tmp_status == TLSMP_KILL) + { + register_signal(c, SIGTERM, "auth-control-exit"); + } + + interval_future_trigger(&c->c2.tmp_int, wakeup); } - interval_schedule_wakeup (&c->c2.tmp_int, &wakeup); + interval_schedule_wakeup(&c->c2.tmp_int, &wakeup); - if (wakeup) - context_reschedule_sec (c, wakeup); + if (wakeup) + { + context_reschedule_sec(c, wakeup); + } } void -check_tls_errors_co (struct context *c) +check_tls_errors_co(struct context *c) { - msg (D_STREAM_ERRORS, "Fatal TLS error (check_tls_errors_co), restarting"); - register_signal (c, c->c2.tls_exit_signal, "tls-error"); /* SOFT-SIGUSR1 -- TLS error */ + msg(D_STREAM_ERRORS, "Fatal TLS error (check_tls_errors_co), restarting"); + register_signal(c, c->c2.tls_exit_signal, "tls-error"); /* SOFT-SIGUSR1 -- TLS error */ } void -check_tls_errors_nco (struct context *c) +check_tls_errors_nco(struct context *c) { - register_signal (c, c->c2.tls_exit_signal, "tls-error"); /* SOFT-SIGUSR1 -- TLS error */ + register_signal(c, c->c2.tls_exit_signal, "tls-error"); /* SOFT-SIGUSR1 -- TLS error */ } #endif /* ENABLE_CRYPTO */ @@ -139,38 +141,48 @@ check_tls_errors_nco (struct context *c) * messages on the control channel. */ void -check_incoming_control_channel_dowork (struct context *c) +check_incoming_control_channel_dowork(struct context *c) { - const int len = tls_test_payload_len (c->c2.tls_multi); - if (len) - { - struct gc_arena gc = gc_new (); - struct buffer buf = alloc_buf_gc (len, &gc); - if (tls_rec_payload (c->c2.tls_multi, &buf)) - { - /* force null termination of message */ - buf_null_terminate (&buf); - - /* enforce character class restrictions */ - string_mod (BSTR (&buf), CC_PRINT, CC_CRLF, 0); - - if (buf_string_match_head_str (&buf, "AUTH_FAILED")) - receive_auth_failed (c, &buf); - else if (buf_string_match_head_str (&buf, "PUSH_")) - incoming_push_message (c, &buf); - else if (buf_string_match_head_str (&buf, "RESTART")) - server_pushed_signal (c, &buf, true, 7); - else if (buf_string_match_head_str (&buf, "HALT")) - server_pushed_signal (c, &buf, false, 4); - else - msg (D_PUSH_ERRORS, "WARNING: Received unknown control message: %s", BSTR (&buf)); - } - else - { - msg (D_PUSH_ERRORS, "WARNING: Receive control message failed"); - } - - gc_free (&gc); + const int len = tls_test_payload_len(c->c2.tls_multi); + if (len) + { + struct gc_arena gc = gc_new(); + struct buffer buf = alloc_buf_gc(len, &gc); + if (tls_rec_payload(c->c2.tls_multi, &buf)) + { + /* force null termination of message */ + buf_null_terminate(&buf); + + /* enforce character class restrictions */ + string_mod(BSTR(&buf), CC_PRINT, CC_CRLF, 0); + + if (buf_string_match_head_str(&buf, "AUTH_FAILED")) + { + receive_auth_failed(c, &buf); + } + else if (buf_string_match_head_str(&buf, "PUSH_")) + { + incoming_push_message(c, &buf); + } + else if (buf_string_match_head_str(&buf, "RESTART")) + { + server_pushed_signal(c, &buf, true, 7); + } + else if (buf_string_match_head_str(&buf, "HALT")) + { + server_pushed_signal(c, &buf, false, 4); + } + else + { + msg(D_PUSH_ERRORS, "WARNING: Received unknown control message: %s", BSTR(&buf)); + } + } + else + { + msg(D_PUSH_ERRORS, "WARNING: Receive control message failed"); + } + + gc_free(&gc); } } @@ -178,12 +190,12 @@ check_incoming_control_channel_dowork (struct context *c) * Periodically resend PUSH_REQUEST until PUSH message received */ void -check_push_request_dowork (struct context *c) +check_push_request_dowork(struct context *c) { - send_push_request (c); + send_push_request(c); - /* if no response to first push_request, retry at PUSH_REQUEST_INTERVAL second intervals */ - event_timeout_modify_wakeup (&c->c2.push_request_interval, PUSH_REQUEST_INTERVAL); + /* if no response to first push_request, retry at PUSH_REQUEST_INTERVAL second intervals */ + event_timeout_modify_wakeup(&c->c2.push_request_interval, PUSH_REQUEST_INTERVAL); } #endif /* P2MP */ @@ -192,40 +204,40 @@ check_push_request_dowork (struct context *c) * Things that need to happen immediately after connection initiation should go here. */ void -check_connection_established_dowork (struct context *c) +check_connection_established_dowork(struct context *c) { - if (event_timeout_trigger (&c->c2.wait_for_connect, &c->c2.timeval, ETT_DEFAULT)) + if (event_timeout_trigger(&c->c2.wait_for_connect, &c->c2.timeval, ETT_DEFAULT)) { - if (CONNECTION_ESTABLISHED (c)) - { + if (CONNECTION_ESTABLISHED(c)) + { #if P2MP - /* if --pull was specified, send a push request to server */ - if (c->c2.tls_multi && c->options.pull) - { + /* if --pull was specified, send a push request to server */ + if (c->c2.tls_multi && c->options.pull) + { #ifdef ENABLE_MANAGEMENT - if (management) - { - management_set_state (management, - OPENVPN_STATE_GET_CONFIG, - NULL, - NULL, - NULL, - NULL, - NULL); - } + if (management) + { + management_set_state(management, + OPENVPN_STATE_GET_CONFIG, + NULL, + NULL, + NULL, + NULL, + NULL); + } #endif - /* fire up push request right away (already 1s delayed) */ - event_timeout_init (&c->c2.push_request_interval, 0, now); - reset_coarse_timers (c); - } - else -#endif - { - do_up (c, false, 0); - } - - event_timeout_clear (&c->c2.wait_for_connect); - } + /* fire up push request right away (already 1s delayed) */ + event_timeout_init(&c->c2.push_request_interval, 0, now); + reset_coarse_timers(c); + } + else +#endif /* if P2MP */ + { + do_up(c, false, 0); + } + + event_timeout_clear(&c->c2.wait_for_connect); + } } } @@ -235,35 +247,36 @@ check_connection_established_dowork (struct context *c) * etc. */ bool -send_control_channel_string (struct context *c, const char *str, int msglevel) +send_control_channel_string(struct context *c, const char *str, int msglevel) { #ifdef ENABLE_CRYPTO - if (c->c2.tls_multi) { - struct gc_arena gc = gc_new (); - bool stat; - - /* buffered cleartext write onto TLS control channel */ - stat = tls_send_payload (c->c2.tls_multi, (uint8_t*) str, strlen (str) + 1); - - /* - * Reschedule tls_multi_process. - * NOTE: in multi-client mode, usually the below two statements are - * insufficient to reschedule the client instance object unless - * multi_schedule_context_wakeup(m, mi) is also called. - */ - interval_action (&c->c2.tmp_int); - context_immediate_reschedule (c); /* ZERO-TIMEOUT */ - - msg (msglevel, "SENT CONTROL [%s]: '%s' (status=%d)", - tls_common_name (c->c2.tls_multi, false), - sanitize_control_message (str, &gc), - (int) stat); - - gc_free (&gc); - return stat; - } + if (c->c2.tls_multi) + { + struct gc_arena gc = gc_new(); + bool stat; + + /* buffered cleartext write onto TLS control channel */ + stat = tls_send_payload(c->c2.tls_multi, (uint8_t *) str, strlen(str) + 1); + + /* + * Reschedule tls_multi_process. + * NOTE: in multi-client mode, usually the below two statements are + * insufficient to reschedule the client instance object unless + * multi_schedule_context_wakeup(m, mi) is also called. + */ + interval_action(&c->c2.tmp_int); + context_immediate_reschedule(c); /* ZERO-TIMEOUT */ + + msg(msglevel, "SENT CONTROL [%s]: '%s' (status=%d)", + tls_common_name(c->c2.tls_multi, false), + sanitize_control_message(str, &gc), + (int) stat); + + gc_free(&gc); + return stat; + } #endif /* ENABLE_CRYPTO */ - return true; + return true; } /* @@ -271,46 +284,48 @@ send_control_channel_string (struct context *c, const char *str, int msglevel) */ static void -check_add_routes_action (struct context *c, const bool errors) +check_add_routes_action(struct context *c, const bool errors) { - do_route (&c->options, c->c1.route_list, c->c1.route_ipv6_list, - c->c1.tuntap, c->plugins, c->c2.es); - update_time (); - event_timeout_clear (&c->c2.route_wakeup); - event_timeout_clear (&c->c2.route_wakeup_expire); - initialization_sequence_completed (c, errors ? ISC_ERRORS : 0); /* client/p2p --route-delay was defined */ + do_route(&c->options, c->c1.route_list, c->c1.route_ipv6_list, + c->c1.tuntap, c->plugins, c->c2.es); + update_time(); + event_timeout_clear(&c->c2.route_wakeup); + event_timeout_clear(&c->c2.route_wakeup_expire); + initialization_sequence_completed(c, errors ? ISC_ERRORS : 0); /* client/p2p --route-delay was defined */ } void -check_add_routes_dowork (struct context *c) +check_add_routes_dowork(struct context *c) { - if (test_routes (c->c1.route_list, c->c1.tuntap)) + if (test_routes(c->c1.route_list, c->c1.tuntap)) { - check_add_routes_action (c, false); + check_add_routes_action(c, false); } - else if (event_timeout_trigger (&c->c2.route_wakeup_expire, &c->c2.timeval, ETT_DEFAULT)) + else if (event_timeout_trigger(&c->c2.route_wakeup_expire, &c->c2.timeval, ETT_DEFAULT)) { - check_add_routes_action (c, true); + check_add_routes_action(c, true); } - else + else { - msg (D_ROUTE, "Route: Waiting for TUN/TAP interface to come up..."); - if (c->c1.tuntap) - { - if (!tun_standby (c->c1.tuntap)) - { - register_signal (c, SIGHUP, "ip-fail"); - c->persist.restart_sleep_seconds = 10; + msg(D_ROUTE, "Route: Waiting for TUN/TAP interface to come up..."); + if (c->c1.tuntap) + { + if (!tun_standby(c->c1.tuntap)) + { + register_signal(c, SIGHUP, "ip-fail"); + c->persist.restart_sleep_seconds = 10; #ifdef _WIN32 - show_routes (M_INFO|M_NOPREFIX); - show_adapters (M_INFO|M_NOPREFIX); + show_routes(M_INFO|M_NOPREFIX); + show_adapters(M_INFO|M_NOPREFIX); #endif - } - } - update_time (); - if (c->c2.route_wakeup.n != 1) - event_timeout_init (&c->c2.route_wakeup, 1, now); - event_timeout_reset (&c->c2.ping_rec_interval); + } + } + update_time(); + if (c->c2.route_wakeup.n != 1) + { + event_timeout_init(&c->c2.route_wakeup, 1, now); + } + event_timeout_reset(&c->c2.ping_rec_interval); } } @@ -318,31 +333,31 @@ check_add_routes_dowork (struct context *c) * Should we exit due to inactivity timeout? */ void -check_inactivity_timeout_dowork (struct context *c) +check_inactivity_timeout_dowork(struct context *c) { - msg (M_INFO, "Inactivity timeout (--inactive), exiting"); - register_signal (c, SIGTERM, "inactive"); + msg(M_INFO, "Inactivity timeout (--inactive), exiting"); + register_signal(c, SIGTERM, "inactive"); } int -get_server_poll_remaining_time (struct event_timeout* server_poll_timeout) +get_server_poll_remaining_time(struct event_timeout *server_poll_timeout) { update_time(); int remaining = event_timeout_remaining(server_poll_timeout); - return max_int (0, remaining); + return max_int(0, remaining); } #if P2MP void -check_server_poll_timeout_dowork (struct context *c) +check_server_poll_timeout_dowork(struct context *c) { - event_timeout_reset (&c->c2.server_poll_interval); - ASSERT(c->c2.tls_multi); - if (!tls_initial_packet_received (c->c2.tls_multi)) + event_timeout_reset(&c->c2.server_poll_interval); + ASSERT(c->c2.tls_multi); + if (!tls_initial_packet_received(c->c2.tls_multi)) { - msg (M_INFO, "Server poll timeout, restarting"); - register_signal (c, SIGUSR1, "server_poll"); - c->persist.restart_sleep_seconds = -1; + msg(M_INFO, "Server poll timeout, restarting"); + register_signal(c, SIGUSR1, "server_poll"); + c->persist.restart_sleep_seconds = -1; } } @@ -350,35 +365,37 @@ check_server_poll_timeout_dowork (struct context *c) * Schedule a signal n_seconds from now. */ void -schedule_exit (struct context *c, const int n_seconds, const int signal) +schedule_exit(struct context *c, const int n_seconds, const int signal) { - tls_set_single_session (c->c2.tls_multi); - update_time (); - reset_coarse_timers (c); - event_timeout_init (&c->c2.scheduled_exit, n_seconds, now); - c->c2.scheduled_exit_signal = signal; - msg (D_SCHED_EXIT, "Delayed exit in %d seconds", n_seconds); + tls_set_single_session(c->c2.tls_multi); + update_time(); + reset_coarse_timers(c); + event_timeout_init(&c->c2.scheduled_exit, n_seconds, now); + c->c2.scheduled_exit_signal = signal; + msg(D_SCHED_EXIT, "Delayed exit in %d seconds", n_seconds); } /* * Scheduled exit? */ void -check_scheduled_exit_dowork (struct context *c) +check_scheduled_exit_dowork(struct context *c) { - register_signal (c, c->c2.scheduled_exit_signal, "delayed-exit"); + register_signal(c, c->c2.scheduled_exit_signal, "delayed-exit"); } -#endif +#endif /* if P2MP */ /* * Should we write timer-triggered status file. */ void -check_status_file_dowork (struct context *c) +check_status_file_dowork(struct context *c) { - if (c->c1.status_output) - print_status (c, c->c1.status_output); + if (c->c1.status_output) + { + print_status(c, c->c1.status_output); + } } #ifdef ENABLE_FRAGMENT @@ -386,46 +403,46 @@ check_status_file_dowork (struct context *c) * Should we deliver a datagram fragment to remote? */ void -check_fragment_dowork (struct context *c) +check_fragment_dowork(struct context *c) { - struct link_socket_info *lsi = get_link_socket_info (c); + struct link_socket_info *lsi = get_link_socket_info(c); - /* OS MTU Hint? */ - if (lsi->mtu_changed) + /* OS MTU Hint? */ + if (lsi->mtu_changed) { - frame_adjust_path_mtu (&c->c2.frame_fragment, c->c2.link_socket->mtu, - c->options.ce.proto); - lsi->mtu_changed = false; + frame_adjust_path_mtu(&c->c2.frame_fragment, c->c2.link_socket->mtu, + c->options.ce.proto); + lsi->mtu_changed = false; } - if (fragment_outgoing_defined (c->c2.fragment)) + if (fragment_outgoing_defined(c->c2.fragment)) { - if (!c->c2.to_link.len) - { - /* encrypt a fragment for output to TCP/UDP port */ - ASSERT (fragment_ready_to_send (c->c2.fragment, &c->c2.buf, &c->c2.frame_fragment)); - encrypt_sign (c, false); - } + if (!c->c2.to_link.len) + { + /* encrypt a fragment for output to TCP/UDP port */ + ASSERT(fragment_ready_to_send(c->c2.fragment, &c->c2.buf, &c->c2.frame_fragment)); + encrypt_sign(c, false); + } } - fragment_housekeeping (c->c2.fragment, &c->c2.frame_fragment, &c->c2.timeval); + fragment_housekeeping(c->c2.fragment, &c->c2.frame_fragment, &c->c2.timeval); } -#endif +#endif /* ifdef ENABLE_FRAGMENT */ /* * Buffer reallocation, for use with null encryption. */ static inline void -buffer_turnover (const uint8_t *orig_buf, struct buffer *dest_stub, struct buffer *src_stub, struct buffer *storage) +buffer_turnover(const uint8_t *orig_buf, struct buffer *dest_stub, struct buffer *src_stub, struct buffer *storage) { - if (orig_buf == src_stub->data && src_stub->data != storage->data) + if (orig_buf == src_stub->data && src_stub->data != storage->data) { - buf_assign (storage, src_stub); - *dest_stub = *storage; + buf_assign(storage, src_stub); + *dest_stub = *storage; } - else + else { - *dest_stub = *src_stub; + *dest_stub = *src_stub; } } @@ -435,188 +452,218 @@ buffer_turnover (const uint8_t *orig_buf, struct buffer *dest_stub, struct buffe * Output: c->c2.to_link */ void -encrypt_sign (struct context *c, bool comp_frag) +encrypt_sign(struct context *c, bool comp_frag) { - struct context_buffers *b = c->c2.buffers; - const uint8_t *orig_buf = c->c2.buf.data; - struct crypto_options *co = NULL; + struct context_buffers *b = c->c2.buffers; + const uint8_t *orig_buf = c->c2.buf.data; + struct crypto_options *co = NULL; #if P2MP_SERVER - /* - * Drop non-TLS outgoing packet if client-connect script/plugin - * has not yet succeeded. - */ - if (c->c2.context_auth != CAS_SUCCEEDED) - c->c2.buf.len = 0; + /* + * Drop non-TLS outgoing packet if client-connect script/plugin + * has not yet succeeded. + */ + if (c->c2.context_auth != CAS_SUCCEEDED) + { + c->c2.buf.len = 0; + } #endif - if (comp_frag) + if (comp_frag) { #ifdef USE_COMP - /* Compress the packet. */ - if (c->c2.comp_context) - (*c->c2.comp_context->alg.compress)(&c->c2.buf, b->compress_buf, c->c2.comp_context, &c->c2.frame); + /* Compress the packet. */ + if (c->c2.comp_context) + { + (*c->c2.comp_context->alg.compress)(&c->c2.buf, b->compress_buf, c->c2.comp_context, &c->c2.frame); + } #endif #ifdef ENABLE_FRAGMENT - if (c->c2.fragment) - fragment_outgoing (c->c2.fragment, &c->c2.buf, &c->c2.frame_fragment); + if (c->c2.fragment) + { + fragment_outgoing(c->c2.fragment, &c->c2.buf, &c->c2.frame_fragment); + } #endif } #ifdef ENABLE_CRYPTO - /* initialize work buffer with FRAME_HEADROOM bytes of prepend capacity */ - ASSERT (buf_init (&b->encrypt_buf, FRAME_HEADROOM (&c->c2.frame))); + /* initialize work buffer with FRAME_HEADROOM bytes of prepend capacity */ + ASSERT(buf_init(&b->encrypt_buf, FRAME_HEADROOM(&c->c2.frame))); - if (c->c2.tls_multi) + if (c->c2.tls_multi) { - /* Get the key we will use to encrypt the packet. */ - tls_pre_encrypt (c->c2.tls_multi, &c->c2.buf, &co); - /* If using P_DATA_V2, prepend the 1-byte opcode and 3-byte peer-id to the - * packet before openvpn_encrypt(), so we can authenticate the opcode too. - */ - if (c->c2.buf.len > 0 && !c->c2.tls_multi->opt.server && c->c2.tls_multi->use_peer_id) - tls_prepend_opcode_v2 (c->c2.tls_multi, &b->encrypt_buf); + /* Get the key we will use to encrypt the packet. */ + tls_pre_encrypt(c->c2.tls_multi, &c->c2.buf, &co); + /* If using P_DATA_V2, prepend the 1-byte opcode and 3-byte peer-id to the + * packet before openvpn_encrypt(), so we can authenticate the opcode too. + */ + if (c->c2.buf.len > 0 && !c->c2.tls_multi->opt.server && c->c2.tls_multi->use_peer_id) + { + tls_prepend_opcode_v2(c->c2.tls_multi, &b->encrypt_buf); + } } - else + else { - co = &c->c2.crypto_options; + co = &c->c2.crypto_options; } - /* Encrypt and authenticate the packet */ - openvpn_encrypt (&c->c2.buf, b->encrypt_buf, co); + /* Encrypt and authenticate the packet */ + openvpn_encrypt(&c->c2.buf, b->encrypt_buf, co); - /* Do packet administration */ - if (c->c2.tls_multi) + /* Do packet administration */ + if (c->c2.tls_multi) { - if (c->c2.buf.len > 0 && (c->c2.tls_multi->opt.server || !c->c2.tls_multi->use_peer_id)) - tls_prepend_opcode_v1(c->c2.tls_multi, &c->c2.buf); - tls_post_encrypt (c->c2.tls_multi, &c->c2.buf); + if (c->c2.buf.len > 0 && (c->c2.tls_multi->opt.server || !c->c2.tls_multi->use_peer_id)) + { + tls_prepend_opcode_v1(c->c2.tls_multi, &c->c2.buf); + } + tls_post_encrypt(c->c2.tls_multi, &c->c2.buf); } -#endif +#endif /* ifdef ENABLE_CRYPTO */ - /* - * Get the address we will be sending the packet to. - */ - link_socket_get_outgoing_addr (&c->c2.buf, get_link_socket_info (c), - &c->c2.to_link_addr); + /* + * Get the address we will be sending the packet to. + */ + link_socket_get_outgoing_addr(&c->c2.buf, get_link_socket_info(c), + &c->c2.to_link_addr); - /* if null encryption, copy result to read_tun_buf */ - buffer_turnover (orig_buf, &c->c2.to_link, &c->c2.buf, &b->read_tun_buf); + /* if null encryption, copy result to read_tun_buf */ + buffer_turnover(orig_buf, &c->c2.to_link, &c->c2.buf, &b->read_tun_buf); } /* * Coarse timers work to 1 second resolution. */ static void -process_coarse_timers (struct context *c) +process_coarse_timers(struct context *c) { #ifdef ENABLE_CRYPTO - /* flush current packet-id to file once per 60 - seconds if --replay-persist was specified */ - check_packet_id_persist_flush (c); + /* flush current packet-id to file once per 60 + * seconds if --replay-persist was specified */ + check_packet_id_persist_flush(c); #endif - /* should we update status file? */ - check_status_file (c); + /* should we update status file? */ + check_status_file(c); - /* process connection establishment items */ - check_connection_established (c); + /* process connection establishment items */ + check_connection_established(c); #if P2MP - /* see if we should send a push_request in response to --pull */ - check_push_request (c); + /* see if we should send a push_request in response to --pull */ + check_push_request(c); #endif #ifdef PLUGIN_PF - pf_check_reload (c); + pf_check_reload(c); #endif - /* process --route options */ - check_add_routes (c); + /* process --route options */ + check_add_routes(c); - /* possibly exit due to --inactive */ - check_inactivity_timeout (c); - if (c->sig->signal_received) - return; + /* possibly exit due to --inactive */ + check_inactivity_timeout(c); + if (c->sig->signal_received) + { + return; + } - /* restart if ping not received */ - check_ping_restart (c); - if (c->sig->signal_received) - return; + /* restart if ping not received */ + check_ping_restart(c); + if (c->sig->signal_received) + { + return; + } #if P2MP - if (c->c2.tls_multi) + if (c->c2.tls_multi) { - check_server_poll_timeout (c); - if (c->sig->signal_received) - return; - - check_scheduled_exit (c); - if (c->sig->signal_received) - return; + check_server_poll_timeout(c); + if (c->sig->signal_received) + { + return; + } + + check_scheduled_exit(c); + if (c->sig->signal_received) + { + return; + } } #endif #ifdef ENABLE_OCC - /* Should we send an OCC_REQUEST message? */ - check_send_occ_req (c); + /* Should we send an OCC_REQUEST message? */ + check_send_occ_req(c); - /* Should we send an MTU load test? */ - check_send_occ_load_test (c); + /* Should we send an MTU load test? */ + check_send_occ_load_test(c); - /* Should we send an OCC_EXIT message to remote? */ - if (c->c2.explicit_exit_notification_time_wait) - process_explicit_exit_notification_timer_wakeup (c); + /* Should we send an OCC_EXIT message to remote? */ + if (c->c2.explicit_exit_notification_time_wait) + { + process_explicit_exit_notification_timer_wakeup(c); + } #endif - /* Should we ping the remote? */ - check_ping_send (c); + /* Should we ping the remote? */ + check_ping_send(c); } static void -check_coarse_timers_dowork (struct context *c) +check_coarse_timers_dowork(struct context *c) { - const struct timeval save = c->c2.timeval; - c->c2.timeval.tv_sec = BIG_TIMEOUT; - c->c2.timeval.tv_usec = 0; - process_coarse_timers (c); - c->c2.coarse_timer_wakeup = now + c->c2.timeval.tv_sec; + const struct timeval save = c->c2.timeval; + c->c2.timeval.tv_sec = BIG_TIMEOUT; + c->c2.timeval.tv_usec = 0; + process_coarse_timers(c); + c->c2.coarse_timer_wakeup = now + c->c2.timeval.tv_sec; - dmsg (D_INTERVAL, "TIMER: coarse timer wakeup %d seconds", (int) c->c2.timeval.tv_sec); + dmsg(D_INTERVAL, "TIMER: coarse timer wakeup %d seconds", (int) c->c2.timeval.tv_sec); - /* Is the coarse timeout NOT the earliest one? */ - if (c->c2.timeval.tv_sec > save.tv_sec) - c->c2.timeval = save; + /* Is the coarse timeout NOT the earliest one? */ + if (c->c2.timeval.tv_sec > save.tv_sec) + { + c->c2.timeval = save; + } } static inline void -check_coarse_timers (struct context *c) +check_coarse_timers(struct context *c) { - const time_t local_now = now; - if (local_now >= c->c2.coarse_timer_wakeup) - check_coarse_timers_dowork (c); - else - context_reschedule_sec (c, c->c2.coarse_timer_wakeup - local_now); + const time_t local_now = now; + if (local_now >= c->c2.coarse_timer_wakeup) + { + check_coarse_timers_dowork(c); + } + else + { + context_reschedule_sec(c, c->c2.coarse_timer_wakeup - local_now); + } } static void -check_timeout_random_component_dowork (struct context *c) +check_timeout_random_component_dowork(struct context *c) { - const int update_interval = 10; /* seconds */ - c->c2.update_timeout_random_component = now + update_interval; - c->c2.timeout_random_component.tv_usec = (time_t) get_random () & 0x0003FFFF; - c->c2.timeout_random_component.tv_sec = 0; + const int update_interval = 10; /* seconds */ + c->c2.update_timeout_random_component = now + update_interval; + c->c2.timeout_random_component.tv_usec = (time_t) get_random() & 0x0003FFFF; + c->c2.timeout_random_component.tv_sec = 0; - dmsg (D_INTERVAL, "RANDOM USEC=%d", (int) c->c2.timeout_random_component.tv_usec); + dmsg(D_INTERVAL, "RANDOM USEC=%d", (int) c->c2.timeout_random_component.tv_usec); } static inline void -check_timeout_random_component (struct context *c) +check_timeout_random_component(struct context *c) { - if (now >= c->c2.update_timeout_random_component) - check_timeout_random_component_dowork (c); - if (c->c2.timeval.tv_sec >= 1) - tv_add (&c->c2.timeval, &c->c2.timeout_random_component); + if (now >= c->c2.update_timeout_random_component) + { + check_timeout_random_component_dowork(c); + } + if (c->c2.timeval.tv_sec >= 1) + { + tv_add(&c->c2.timeval, &c->c2.timeout_random_component); + } } /* @@ -625,35 +672,39 @@ check_timeout_random_component (struct context *c) */ static inline void -socks_postprocess_incoming_link (struct context *c) +socks_postprocess_incoming_link(struct context *c) { - if (c->c2.link_socket->socks_proxy && c->c2.link_socket->info.proto == PROTO_UDP) - socks_process_incoming_udp (&c->c2.buf, &c->c2.from); + if (c->c2.link_socket->socks_proxy && c->c2.link_socket->info.proto == PROTO_UDP) + { + socks_process_incoming_udp(&c->c2.buf, &c->c2.from); + } } static inline void -socks_preprocess_outgoing_link (struct context *c, - struct link_socket_actual **to_addr, - int *size_delta) +socks_preprocess_outgoing_link(struct context *c, + struct link_socket_actual **to_addr, + int *size_delta) { - if (c->c2.link_socket->socks_proxy && c->c2.link_socket->info.proto == PROTO_UDP) + if (c->c2.link_socket->socks_proxy && c->c2.link_socket->info.proto == PROTO_UDP) { - *size_delta += socks_process_outgoing_udp (&c->c2.to_link, c->c2.to_link_addr); - *to_addr = &c->c2.link_socket->socks_relay; + *size_delta += socks_process_outgoing_udp(&c->c2.to_link, c->c2.to_link_addr); + *to_addr = &c->c2.link_socket->socks_relay; } } /* undo effect of socks_preprocess_outgoing_link */ static inline void -link_socket_write_post_size_adjust (int *size, - int size_delta, - struct buffer *buf) +link_socket_write_post_size_adjust(int *size, + int size_delta, + struct buffer *buf) { - if (size_delta > 0 && *size > size_delta) + if (size_delta > 0 && *size > size_delta) { - *size -= size_delta; - if (!buf_advance (buf, size_delta)) - *size = 0; + *size -= size_delta; + if (!buf_advance(buf, size_delta)) + { + *size = 0; + } } } @@ -662,279 +713,306 @@ link_socket_write_post_size_adjust (int *size, */ void -read_incoming_link (struct context *c) +read_incoming_link(struct context *c) { - /* - * Set up for recvfrom call to read datagram - * sent to our TCP/UDP port. - */ - int status; + /* + * Set up for recvfrom call to read datagram + * sent to our TCP/UDP port. + */ + int status; - /*ASSERT (!c->c2.to_tun.len);*/ + /*ASSERT (!c->c2.to_tun.len);*/ - perf_push (PERF_READ_IN_LINK); + perf_push(PERF_READ_IN_LINK); - c->c2.buf = c->c2.buffers->read_link_buf; - ASSERT (buf_init (&c->c2.buf, FRAME_HEADROOM_ADJ (&c->c2.frame, FRAME_HEADROOM_MARKER_READ_LINK))); + c->c2.buf = c->c2.buffers->read_link_buf; + ASSERT(buf_init(&c->c2.buf, FRAME_HEADROOM_ADJ(&c->c2.frame, FRAME_HEADROOM_MARKER_READ_LINK))); - status = link_socket_read (c->c2.link_socket, - &c->c2.buf, - &c->c2.from); + status = link_socket_read(c->c2.link_socket, + &c->c2.buf, + &c->c2.from); - if (socket_connection_reset (c->c2.link_socket, status)) + if (socket_connection_reset(c->c2.link_socket, status)) { #if PORT_SHARE - if (port_share && socket_foreign_protocol_detected (c->c2.link_socket)) - { - const struct buffer *fbuf = socket_foreign_protocol_head (c->c2.link_socket); - const int sd = socket_foreign_protocol_sd (c->c2.link_socket); - port_share_redirect (port_share, fbuf, sd); - register_signal (c, SIGTERM, "port-share-redirect"); - } - else + if (port_share && socket_foreign_protocol_detected(c->c2.link_socket)) + { + const struct buffer *fbuf = socket_foreign_protocol_head(c->c2.link_socket); + const int sd = socket_foreign_protocol_sd(c->c2.link_socket); + port_share_redirect(port_share, fbuf, sd); + register_signal(c, SIGTERM, "port-share-redirect"); + } + else #endif - { - /* received a disconnect from a connection-oriented protocol */ - if (c->options.inetd) - { - register_signal (c, SIGTERM, "connection-reset-inetd"); - msg (D_STREAM_ERRORS, "Connection reset, inetd/xinetd exit [%d]", status); - } - else - { + { + /* received a disconnect from a connection-oriented protocol */ + if (c->options.inetd) + { + register_signal(c, SIGTERM, "connection-reset-inetd"); + msg(D_STREAM_ERRORS, "Connection reset, inetd/xinetd exit [%d]", status); + } + else + { #ifdef ENABLE_OCC - if (event_timeout_defined(&c->c2.explicit_exit_notification_interval)) - { - msg (D_STREAM_ERRORS, "Connection reset during exit notification period, ignoring [%d]", status); - openvpn_sleep(1); - } - else + if (event_timeout_defined(&c->c2.explicit_exit_notification_interval)) + { + msg(D_STREAM_ERRORS, "Connection reset during exit notification period, ignoring [%d]", status); + openvpn_sleep(1); + } + else #endif - { - register_signal (c, SIGUSR1, "connection-reset"); /* SOFT-SIGUSR1 -- TCP connection reset */ - msg (D_STREAM_ERRORS, "Connection reset, restarting [%d]", status); - } - } - } - perf_pop (); - return; + { + register_signal(c, SIGUSR1, "connection-reset"); /* SOFT-SIGUSR1 -- TCP connection reset */ + msg(D_STREAM_ERRORS, "Connection reset, restarting [%d]", status); + } + } + } + perf_pop(); + return; } - /* check recvfrom status */ - check_status (status, "read", c->c2.link_socket, NULL); + /* check recvfrom status */ + check_status(status, "read", c->c2.link_socket, NULL); - /* Remove socks header if applicable */ - socks_postprocess_incoming_link (c); + /* Remove socks header if applicable */ + socks_postprocess_incoming_link(c); - perf_pop (); + perf_pop(); } bool -process_incoming_link_part1 (struct context *c, struct link_socket_info *lsi, bool floated) +process_incoming_link_part1(struct context *c, struct link_socket_info *lsi, bool floated) { - struct gc_arena gc = gc_new (); - bool decrypt_status = false; + struct gc_arena gc = gc_new(); + bool decrypt_status = false; - if (c->c2.buf.len > 0) + if (c->c2.buf.len > 0) { - c->c2.link_read_bytes += c->c2.buf.len; - link_read_bytes_global += c->c2.buf.len; + c->c2.link_read_bytes += c->c2.buf.len; + link_read_bytes_global += c->c2.buf.len; #ifdef ENABLE_MEMSTATS - if (mmap_stats) - mmap_stats->link_read_bytes = link_read_bytes_global; + if (mmap_stats) + { + mmap_stats->link_read_bytes = link_read_bytes_global; + } #endif - c->c2.original_recv_size = c->c2.buf.len; + c->c2.original_recv_size = c->c2.buf.len; #ifdef ENABLE_MANAGEMENT - if (management) - { - management_bytes_in (management, c->c2.buf.len); + if (management) + { + management_bytes_in(management, c->c2.buf.len); #ifdef MANAGEMENT_DEF_AUTH - management_bytes_server (management, &c->c2.link_read_bytes, &c->c2.link_write_bytes, &c->c2.mda_context); + management_bytes_server(management, &c->c2.link_read_bytes, &c->c2.link_write_bytes, &c->c2.mda_context); #endif - } + } #endif } - else - c->c2.original_recv_size = 0; - + else + { + c->c2.original_recv_size = 0; + } + #ifdef ENABLE_DEBUG - /* take action to corrupt packet if we are in gremlin test mode */ - if (c->options.gremlin) { - if (!ask_gremlin (c->options.gremlin)) - c->c2.buf.len = 0; - corrupt_gremlin (&c->c2.buf, c->options.gremlin); - } + /* take action to corrupt packet if we are in gremlin test mode */ + if (c->options.gremlin) + { + if (!ask_gremlin(c->options.gremlin)) + { + c->c2.buf.len = 0; + } + corrupt_gremlin(&c->c2.buf, c->options.gremlin); + } #endif - /* log incoming packet */ + /* log incoming packet */ #ifdef LOG_RW - if (c->c2.log_rw && c->c2.buf.len > 0) - fprintf (stderr, "R"); + if (c->c2.log_rw && c->c2.buf.len > 0) + { + fprintf(stderr, "R"); + } #endif - msg (D_LINK_RW, "%s READ [%d] from %s: %s", - proto2ascii (lsi->proto, lsi->af, true), - BLEN (&c->c2.buf), - print_link_socket_actual (&c->c2.from, &gc), - PROTO_DUMP (&c->c2.buf, &gc)); - - /* - * Good, non-zero length packet received. - * Commence multi-stage processing of packet, - * such as authenticate, decrypt, decompress. - * If any stage fails, it sets buf.len to 0 or -1, - * telling downstream stages to ignore the packet. - */ - if (c->c2.buf.len > 0) - { - struct crypto_options *co = NULL; - const uint8_t *ad_start = NULL; - if (!link_socket_verify_incoming_addr (&c->c2.buf, lsi, &c->c2.from)) - link_socket_bad_incoming_addr (&c->c2.buf, lsi, &c->c2.from); + msg(D_LINK_RW, "%s READ [%d] from %s: %s", + proto2ascii(lsi->proto, lsi->af, true), + BLEN(&c->c2.buf), + print_link_socket_actual(&c->c2.from, &gc), + PROTO_DUMP(&c->c2.buf, &gc)); + + /* + * Good, non-zero length packet received. + * Commence multi-stage processing of packet, + * such as authenticate, decrypt, decompress. + * If any stage fails, it sets buf.len to 0 or -1, + * telling downstream stages to ignore the packet. + */ + if (c->c2.buf.len > 0) + { + struct crypto_options *co = NULL; + const uint8_t *ad_start = NULL; + if (!link_socket_verify_incoming_addr(&c->c2.buf, lsi, &c->c2.from)) + { + link_socket_bad_incoming_addr(&c->c2.buf, lsi, &c->c2.from); + } #ifdef ENABLE_CRYPTO - if (c->c2.tls_multi) - { - /* - * If tls_pre_decrypt returns true, it means the incoming - * packet was a good TLS control channel packet. If so, TLS code - * will deal with the packet and set buf.len to 0 so downstream - * stages ignore it. - * - * If the packet is a data channel packet, tls_pre_decrypt - * will load crypto_options with the correct encryption key - * and return false. - */ - if (tls_pre_decrypt (c->c2.tls_multi, &c->c2.from, &c->c2.buf, &co, - floated, &ad_start)) - { - interval_action (&c->c2.tmp_int); - - /* reset packet received timer if TLS packet */ - if (c->options.ping_rec_timeout) - event_timeout_reset (&c->c2.ping_rec_interval); - } - } - else - { - co = &c->c2.crypto_options; - } + if (c->c2.tls_multi) + { + /* + * If tls_pre_decrypt returns true, it means the incoming + * packet was a good TLS control channel packet. If so, TLS code + * will deal with the packet and set buf.len to 0 so downstream + * stages ignore it. + * + * If the packet is a data channel packet, tls_pre_decrypt + * will load crypto_options with the correct encryption key + * and return false. + */ + if (tls_pre_decrypt(c->c2.tls_multi, &c->c2.from, &c->c2.buf, &co, + floated, &ad_start)) + { + interval_action(&c->c2.tmp_int); + + /* reset packet received timer if TLS packet */ + if (c->options.ping_rec_timeout) + { + event_timeout_reset(&c->c2.ping_rec_interval); + } + } + } + else + { + co = &c->c2.crypto_options; + } #if P2MP_SERVER - /* - * Drop non-TLS packet if client-connect script/plugin has not - * yet succeeded. - */ - if (c->c2.context_auth != CAS_SUCCEEDED) - c->c2.buf.len = 0; + /* + * Drop non-TLS packet if client-connect script/plugin has not + * yet succeeded. + */ + if (c->c2.context_auth != CAS_SUCCEEDED) + { + c->c2.buf.len = 0; + } #endif - /* authenticate and decrypt the incoming packet */ - decrypt_status = openvpn_decrypt (&c->c2.buf, c->c2.buffers->decrypt_buf, - co, &c->c2.frame, ad_start); + /* authenticate and decrypt the incoming packet */ + decrypt_status = openvpn_decrypt(&c->c2.buf, c->c2.buffers->decrypt_buf, + co, &c->c2.frame, ad_start); - if (!decrypt_status && link_socket_connection_oriented (c->c2.link_socket)) - { - /* decryption errors are fatal in TCP mode */ - register_signal (c, SIGUSR1, "decryption-error"); /* SOFT-SIGUSR1 -- decryption error in TCP mode */ - msg (D_STREAM_ERRORS, "Fatal decryption error (process_incoming_link), restarting"); - } + if (!decrypt_status && link_socket_connection_oriented(c->c2.link_socket)) + { + /* decryption errors are fatal in TCP mode */ + register_signal(c, SIGUSR1, "decryption-error"); /* SOFT-SIGUSR1 -- decryption error in TCP mode */ + msg(D_STREAM_ERRORS, "Fatal decryption error (process_incoming_link), restarting"); + } #else /* ENABLE_CRYPTO */ - decrypt_status = true; + decrypt_status = true; #endif /* ENABLE_CRYPTO */ } - else + else { - buf_reset (&c->c2.to_tun); + buf_reset(&c->c2.to_tun); } - gc_free (&gc); + gc_free(&gc); - return decrypt_status; + return decrypt_status; } void -process_incoming_link_part2 (struct context *c, struct link_socket_info *lsi, const uint8_t *orig_buf) +process_incoming_link_part2(struct context *c, struct link_socket_info *lsi, const uint8_t *orig_buf) { - if (c->c2.buf.len > 0) + if (c->c2.buf.len > 0) { #ifdef ENABLE_FRAGMENT - if (c->c2.fragment) - fragment_incoming (c->c2.fragment, &c->c2.buf, &c->c2.frame_fragment); + if (c->c2.fragment) + { + fragment_incoming(c->c2.fragment, &c->c2.buf, &c->c2.frame_fragment); + } #endif #ifdef USE_COMP - /* decompress the incoming packet */ - if (c->c2.comp_context) - (*c->c2.comp_context->alg.decompress)(&c->c2.buf, c->c2.buffers->decompress_buf, c->c2.comp_context, &c->c2.frame); + /* decompress the incoming packet */ + if (c->c2.comp_context) + { + (*c->c2.comp_context->alg.decompress)(&c->c2.buf, c->c2.buffers->decompress_buf, c->c2.comp_context, &c->c2.frame); + } #endif #ifdef PACKET_TRUNCATION_CHECK - /* if (c->c2.buf.len > 1) --c->c2.buf.len; */ - ipv4_packet_size_verify (BPTR (&c->c2.buf), - BLEN (&c->c2.buf), - TUNNEL_TYPE (c->c1.tuntap), - "POST_DECRYPT", - &c->c2.n_trunc_post_decrypt); + /* if (c->c2.buf.len > 1) --c->c2.buf.len; */ + ipv4_packet_size_verify(BPTR(&c->c2.buf), + BLEN(&c->c2.buf), + TUNNEL_TYPE(c->c1.tuntap), + "POST_DECRYPT", + &c->c2.n_trunc_post_decrypt); #endif - /* - * Set our "official" outgoing address, since - * if buf.len is non-zero, we know the packet - * authenticated. In TLS mode we do nothing - * because TLS mode takes care of source address - * authentication. - * - * Also, update the persisted version of our packet-id. - */ - if (!TLS_MODE (c)) - link_socket_set_outgoing_addr (&c->c2.buf, lsi, &c->c2.from, NULL, c->c2.es); - - /* reset packet received timer */ - if (c->options.ping_rec_timeout && c->c2.buf.len > 0) - event_timeout_reset (&c->c2.ping_rec_interval); - - /* increment authenticated receive byte count */ - if (c->c2.buf.len > 0) - { - c->c2.link_read_bytes_auth += c->c2.buf.len; - c->c2.max_recv_size_local = max_int (c->c2.original_recv_size, c->c2.max_recv_size_local); - } - - /* Did we just receive an openvpn ping packet? */ - if (is_ping_msg (&c->c2.buf)) - { - dmsg (D_PING, "RECEIVED PING PACKET"); - c->c2.buf.len = 0; /* drop packet */ - } + /* + * Set our "official" outgoing address, since + * if buf.len is non-zero, we know the packet + * authenticated. In TLS mode we do nothing + * because TLS mode takes care of source address + * authentication. + * + * Also, update the persisted version of our packet-id. + */ + if (!TLS_MODE(c)) + { + link_socket_set_outgoing_addr(&c->c2.buf, lsi, &c->c2.from, NULL, c->c2.es); + } + + /* reset packet received timer */ + if (c->options.ping_rec_timeout && c->c2.buf.len > 0) + { + event_timeout_reset(&c->c2.ping_rec_interval); + } + + /* increment authenticated receive byte count */ + if (c->c2.buf.len > 0) + { + c->c2.link_read_bytes_auth += c->c2.buf.len; + c->c2.max_recv_size_local = max_int(c->c2.original_recv_size, c->c2.max_recv_size_local); + } + + /* Did we just receive an openvpn ping packet? */ + if (is_ping_msg(&c->c2.buf)) + { + dmsg(D_PING, "RECEIVED PING PACKET"); + c->c2.buf.len = 0; /* drop packet */ + } #ifdef ENABLE_OCC - /* Did we just receive an OCC packet? */ - if (is_occ_msg (&c->c2.buf)) - process_received_occ_msg (c); + /* Did we just receive an OCC packet? */ + if (is_occ_msg(&c->c2.buf)) + { + process_received_occ_msg(c); + } #endif - buffer_turnover (orig_buf, &c->c2.to_tun, &c->c2.buf, &c->c2.buffers->read_link_buf); + buffer_turnover(orig_buf, &c->c2.to_tun, &c->c2.buf, &c->c2.buffers->read_link_buf); - /* to_tun defined + unopened tuntap can cause deadlock */ - if (!tuntap_defined (c->c1.tuntap)) - c->c2.to_tun.len = 0; + /* to_tun defined + unopened tuntap can cause deadlock */ + if (!tuntap_defined(c->c1.tuntap)) + { + c->c2.to_tun.len = 0; + } } - else + else { - buf_reset (&c->c2.to_tun); + buf_reset(&c->c2.to_tun); } } void -process_incoming_link (struct context *c) +process_incoming_link(struct context *c) { - perf_push (PERF_PROC_IN_LINK); + perf_push(PERF_PROC_IN_LINK); - struct link_socket_info *lsi = get_link_socket_info (c); - const uint8_t *orig_buf = c->c2.buf.data; + struct link_socket_info *lsi = get_link_socket_info(c); + const uint8_t *orig_buf = c->c2.buf.data; - process_incoming_link_part1(c, lsi, false); - process_incoming_link_part2(c, lsi, orig_buf); + process_incoming_link_part1(c, lsi, false); + process_incoming_link_part2(c, lsi, orig_buf); - perf_pop (); + perf_pop(); } /* @@ -942,55 +1020,55 @@ process_incoming_link (struct context *c) */ void -read_incoming_tun (struct context *c) +read_incoming_tun(struct context *c) { - /* - * Setup for read() call on TUN/TAP device. - */ - /*ASSERT (!c->c2.to_link.len);*/ + /* + * Setup for read() call on TUN/TAP device. + */ + /*ASSERT (!c->c2.to_link.len);*/ - perf_push (PERF_READ_IN_TUN); + perf_push(PERF_READ_IN_TUN); - c->c2.buf = c->c2.buffers->read_tun_buf; + c->c2.buf = c->c2.buffers->read_tun_buf; #ifdef TUN_PASS_BUFFER - read_tun_buffered (c->c1.tuntap, &c->c2.buf, MAX_RW_SIZE_TUN (&c->c2.frame)); + read_tun_buffered(c->c1.tuntap, &c->c2.buf, MAX_RW_SIZE_TUN(&c->c2.frame)); #else - ASSERT (buf_init (&c->c2.buf, FRAME_HEADROOM (&c->c2.frame))); - ASSERT (buf_safe (&c->c2.buf, MAX_RW_SIZE_TUN (&c->c2.frame))); - c->c2.buf.len = read_tun (c->c1.tuntap, BPTR (&c->c2.buf), MAX_RW_SIZE_TUN (&c->c2.frame)); + ASSERT(buf_init(&c->c2.buf, FRAME_HEADROOM(&c->c2.frame))); + ASSERT(buf_safe(&c->c2.buf, MAX_RW_SIZE_TUN(&c->c2.frame))); + c->c2.buf.len = read_tun(c->c1.tuntap, BPTR(&c->c2.buf), MAX_RW_SIZE_TUN(&c->c2.frame)); #endif #ifdef PACKET_TRUNCATION_CHECK - ipv4_packet_size_verify (BPTR (&c->c2.buf), - BLEN (&c->c2.buf), - TUNNEL_TYPE (c->c1.tuntap), - "READ_TUN", - &c->c2.n_trunc_tun_read); + ipv4_packet_size_verify(BPTR(&c->c2.buf), + BLEN(&c->c2.buf), + TUNNEL_TYPE(c->c1.tuntap), + "READ_TUN", + &c->c2.n_trunc_tun_read); #endif - /* Was TUN/TAP interface stopped? */ - if (tuntap_stop (c->c2.buf.len)) + /* Was TUN/TAP interface stopped? */ + if (tuntap_stop(c->c2.buf.len)) { - register_signal (c, SIGTERM, "tun-stop"); - msg (M_INFO, "TUN/TAP interface has been stopped, exiting"); - perf_pop (); - return; + register_signal(c, SIGTERM, "tun-stop"); + msg(M_INFO, "TUN/TAP interface has been stopped, exiting"); + perf_pop(); + return; } - /* Was TUN/TAP I/O operation aborted? */ - if (tuntap_abort(c->c2.buf.len)) - { - register_signal(c, SIGHUP, "tun-abort"); - c->persist.restart_sleep_seconds = 10; - msg(M_INFO, "TUN/TAP I/O operation aborted, restarting"); - perf_pop(); - return; - } + /* Was TUN/TAP I/O operation aborted? */ + if (tuntap_abort(c->c2.buf.len)) + { + register_signal(c, SIGHUP, "tun-abort"); + c->persist.restart_sleep_seconds = 10; + msg(M_INFO, "TUN/TAP I/O operation aborted, restarting"); + perf_pop(); + return; + } - /* Check the status return from read() */ - check_status (c->c2.buf.len, "read from TUN/TAP", NULL, c->c1.tuntap); + /* Check the status return from read() */ + check_status(c->c2.buf.len, "read from TUN/TAP", NULL, c->c1.tuntap); - perf_pop (); + perf_pop(); } /** @@ -1002,64 +1080,78 @@ read_incoming_tun (struct context *c) * and sent to routing table, which sends it again to tun. */ static void -drop_if_recursive_routing (struct context *c, struct buffer *buf) +drop_if_recursive_routing(struct context *c, struct buffer *buf) { - bool drop = false; - struct openvpn_sockaddr tun_sa; - int ip_hdr_offset = 0; - - if (c->c2.to_link_addr == NULL) /* no remote addr known */ - return; - - tun_sa = c->c2.to_link_addr->dest; + bool drop = false; + struct openvpn_sockaddr tun_sa; + int ip_hdr_offset = 0; - int proto_ver = get_tun_ip_ver (TUNNEL_TYPE (c->c1.tuntap), &c->c2.buf, &ip_hdr_offset); - - if (proto_ver == 4) + if (c->c2.to_link_addr == NULL) /* no remote addr known */ { - const struct openvpn_iphdr *pip; - - /* make sure we got whole IP header */ - if (BLEN (buf) < ((int) sizeof (struct openvpn_iphdr) + ip_hdr_offset)) - return; + return; + } - /* skip ipv4 packets for ipv6 tun */ - if (tun_sa.addr.sa.sa_family != AF_INET) - return; + tun_sa = c->c2.to_link_addr->dest; - pip = (struct openvpn_iphdr *) (BPTR (buf) + ip_hdr_offset); + int proto_ver = get_tun_ip_ver(TUNNEL_TYPE(c->c1.tuntap), &c->c2.buf, &ip_hdr_offset); - /* drop packets with same dest addr as gateway */ - if (tun_sa.addr.in4.sin_addr.s_addr == pip->daddr) - drop = true; + if (proto_ver == 4) + { + const struct openvpn_iphdr *pip; + + /* make sure we got whole IP header */ + if (BLEN(buf) < ((int) sizeof(struct openvpn_iphdr) + ip_hdr_offset)) + { + return; + } + + /* skip ipv4 packets for ipv6 tun */ + if (tun_sa.addr.sa.sa_family != AF_INET) + { + return; + } + + pip = (struct openvpn_iphdr *) (BPTR(buf) + ip_hdr_offset); + + /* drop packets with same dest addr as gateway */ + if (tun_sa.addr.in4.sin_addr.s_addr == pip->daddr) + { + drop = true; + } } - else if (proto_ver == 6) + else if (proto_ver == 6) { - const struct openvpn_ipv6hdr *pip6; - - /* make sure we got whole IPv6 header */ - if (BLEN (buf) < ((int) sizeof (struct openvpn_ipv6hdr) + ip_hdr_offset)) - return; - - /* skip ipv6 packets for ipv4 tun */ - if (tun_sa.addr.sa.sa_family != AF_INET6) - return; - - /* drop packets with same dest addr as gateway */ - pip6 = (struct openvpn_ipv6hdr *) (BPTR (buf) + ip_hdr_offset); - if (IN6_ARE_ADDR_EQUAL(&tun_sa.addr.in6.sin6_addr, &pip6->daddr)) - drop = true; + const struct openvpn_ipv6hdr *pip6; + + /* make sure we got whole IPv6 header */ + if (BLEN(buf) < ((int) sizeof(struct openvpn_ipv6hdr) + ip_hdr_offset)) + { + return; + } + + /* skip ipv6 packets for ipv4 tun */ + if (tun_sa.addr.sa.sa_family != AF_INET6) + { + return; + } + + /* drop packets with same dest addr as gateway */ + pip6 = (struct openvpn_ipv6hdr *) (BPTR(buf) + ip_hdr_offset); + if (IN6_ARE_ADDR_EQUAL(&tun_sa.addr.in6.sin6_addr, &pip6->daddr)) + { + drop = true; + } } - if (drop) + if (drop) { - struct gc_arena gc = gc_new (); + struct gc_arena gc = gc_new(); - c->c2.buf.len = 0; + c->c2.buf.len = 0; - msg(D_LOW, "Recursive routing detected, drop tun packet to %s", - print_link_socket_actual(c->c2.to_link_addr, &gc)); - gc_free (&gc); + msg(D_LOW, "Recursive routing detected, drop tun packet to %s", + print_link_socket_actual(c->c2.to_link_addr, &gc)); + gc_free(&gc); } } @@ -1069,114 +1161,136 @@ drop_if_recursive_routing (struct context *c, struct buffer *buf) */ void -process_incoming_tun (struct context *c) +process_incoming_tun(struct context *c) { - struct gc_arena gc = gc_new (); + struct gc_arena gc = gc_new(); - perf_push (PERF_PROC_IN_TUN); + perf_push(PERF_PROC_IN_TUN); - if (c->c2.buf.len > 0) - c->c2.tun_read_bytes += c->c2.buf.len; + if (c->c2.buf.len > 0) + { + c->c2.tun_read_bytes += c->c2.buf.len; + } #ifdef LOG_RW - if (c->c2.log_rw && c->c2.buf.len > 0) - fprintf (stderr, "r"); + if (c->c2.log_rw && c->c2.buf.len > 0) + { + fprintf(stderr, "r"); + } #endif - /* Show packet content */ - dmsg (D_TUN_RW, "TUN READ [%d]", BLEN (&c->c2.buf)); + /* Show packet content */ + dmsg(D_TUN_RW, "TUN READ [%d]", BLEN(&c->c2.buf)); - if (c->c2.buf.len > 0) + if (c->c2.buf.len > 0) { - if ((c->options.mode == MODE_POINT_TO_POINT) && (!c->options.allow_recursive_routing)) - drop_if_recursive_routing (c, &c->c2.buf); - /* - * The --passtos and --mssfix options require - * us to examine the IP header (IPv4 or IPv6). - */ - process_ip_header (c, PIPV4_PASSTOS|PIP_MSSFIX|PIPV4_CLIENT_NAT, &c->c2.buf); + if ((c->options.mode == MODE_POINT_TO_POINT) && (!c->options.allow_recursive_routing)) + { + drop_if_recursive_routing(c, &c->c2.buf); + } + /* + * The --passtos and --mssfix options require + * us to examine the IP header (IPv4 or IPv6). + */ + process_ip_header(c, PIPV4_PASSTOS|PIP_MSSFIX|PIPV4_CLIENT_NAT, &c->c2.buf); #ifdef PACKET_TRUNCATION_CHECK - /* if (c->c2.buf.len > 1) --c->c2.buf.len; */ - ipv4_packet_size_verify (BPTR (&c->c2.buf), - BLEN (&c->c2.buf), - TUNNEL_TYPE (c->c1.tuntap), - "PRE_ENCRYPT", - &c->c2.n_trunc_pre_encrypt); + /* if (c->c2.buf.len > 1) --c->c2.buf.len; */ + ipv4_packet_size_verify(BPTR(&c->c2.buf), + BLEN(&c->c2.buf), + TUNNEL_TYPE(c->c1.tuntap), + "PRE_ENCRYPT", + &c->c2.n_trunc_pre_encrypt); #endif - encrypt_sign (c, true); + encrypt_sign(c, true); } - else + else { - buf_reset (&c->c2.to_link); + buf_reset(&c->c2.to_link); } - perf_pop (); - gc_free (&gc); + perf_pop(); + gc_free(&gc); } void -process_ip_header (struct context *c, unsigned int flags, struct buffer *buf) +process_ip_header(struct context *c, unsigned int flags, struct buffer *buf) { - if (!c->options.ce.mssfix) - flags &= ~PIP_MSSFIX; + if (!c->options.ce.mssfix) + { + flags &= ~PIP_MSSFIX; + } #if PASSTOS_CAPABILITY - if (!c->options.passtos) - flags &= ~PIPV4_PASSTOS; + if (!c->options.passtos) + { + flags &= ~PIPV4_PASSTOS; + } #endif - if (!c->options.client_nat) - flags &= ~PIPV4_CLIENT_NAT; - if (!c->options.route_gateway_via_dhcp) - flags &= ~PIPV4_EXTRACT_DHCP_ROUTER; + if (!c->options.client_nat) + { + flags &= ~PIPV4_CLIENT_NAT; + } + if (!c->options.route_gateway_via_dhcp) + { + flags &= ~PIPV4_EXTRACT_DHCP_ROUTER; + } - if (buf->len > 0) + if (buf->len > 0) { - /* - * The --passtos and --mssfix options require - * us to examine the IPv4 header. - */ + /* + * The --passtos and --mssfix options require + * us to examine the IPv4 header. + */ - if (flags & (PIP_MSSFIX + if (flags & (PIP_MSSFIX #if PASSTOS_CAPABILITY - | PIPV4_PASSTOS + | PIPV4_PASSTOS #endif - | PIPV4_CLIENT_NAT - )) - { - struct buffer ipbuf = *buf; - if (is_ipv4 (TUNNEL_TYPE (c->c1.tuntap), &ipbuf)) - { + | PIPV4_CLIENT_NAT + )) + { + struct buffer ipbuf = *buf; + if (is_ipv4(TUNNEL_TYPE(c->c1.tuntap), &ipbuf)) + { #if PASSTOS_CAPABILITY - /* extract TOS from IP header */ - if (flags & PIPV4_PASSTOS) - link_socket_extract_tos (c->c2.link_socket, &ipbuf); + /* extract TOS from IP header */ + if (flags & PIPV4_PASSTOS) + { + link_socket_extract_tos(c->c2.link_socket, &ipbuf); + } #endif - - /* possibly alter the TCP MSS */ - if (flags & PIP_MSSFIX) - mss_fixup_ipv4 (&ipbuf, MTU_TO_MSS (TUN_MTU_SIZE_DYNAMIC (&c->c2.frame))); - - /* possibly do NAT on packet */ - if ((flags & PIPV4_CLIENT_NAT) && c->options.client_nat) - { - const int direction = (flags & PIPV4_OUTGOING) ? CN_INCOMING : CN_OUTGOING; - client_nat_transform (c->options.client_nat, &ipbuf, direction); - } - /* possibly extract a DHCP router message */ - if (flags & PIPV4_EXTRACT_DHCP_ROUTER) - { - const in_addr_t dhcp_router = dhcp_extract_router_msg (&ipbuf); - if (dhcp_router) - route_list_add_vpn_gateway (c->c1.route_list, c->c2.es, dhcp_router); - } - } - else if (is_ipv6 (TUNNEL_TYPE (c->c1.tuntap), &ipbuf)) - { - /* possibly alter the TCP MSS */ - if (flags & PIP_MSSFIX) - mss_fixup_ipv6 (&ipbuf, MTU_TO_MSS (TUN_MTU_SIZE_DYNAMIC (&c->c2.frame))); - } - } + + /* possibly alter the TCP MSS */ + if (flags & PIP_MSSFIX) + { + mss_fixup_ipv4(&ipbuf, MTU_TO_MSS(TUN_MTU_SIZE_DYNAMIC(&c->c2.frame))); + } + + /* possibly do NAT on packet */ + if ((flags & PIPV4_CLIENT_NAT) && c->options.client_nat) + { + const int direction = (flags & PIPV4_OUTGOING) ? CN_INCOMING : CN_OUTGOING; + client_nat_transform(c->options.client_nat, &ipbuf, direction); + } + /* possibly extract a DHCP router message */ + if (flags & PIPV4_EXTRACT_DHCP_ROUTER) + { + const in_addr_t dhcp_router = dhcp_extract_router_msg(&ipbuf); + if (dhcp_router) + { + route_list_add_vpn_gateway(c->c1.route_list, c->c2.es, dhcp_router); + } + } + } + else if (is_ipv6(TUNNEL_TYPE(c->c1.tuntap), &ipbuf)) + { + /* possibly alter the TCP MSS */ + if (flags & PIP_MSSFIX) + { + mss_fixup_ipv6(&ipbuf, MTU_TO_MSS(TUN_MTU_SIZE_DYNAMIC(&c->c2.frame))); + } + } + } } } @@ -1185,139 +1299,153 @@ process_ip_header (struct context *c, unsigned int flags, struct buffer *buf) */ void -process_outgoing_link (struct context *c) +process_outgoing_link(struct context *c) { - struct gc_arena gc = gc_new (); - int error_code = 0; + struct gc_arena gc = gc_new(); + int error_code = 0; - perf_push (PERF_PROC_OUT_LINK); + perf_push(PERF_PROC_OUT_LINK); - if (c->c2.to_link.len > 0 && c->c2.to_link.len <= EXPANDED_SIZE (&c->c2.frame)) + if (c->c2.to_link.len > 0 && c->c2.to_link.len <= EXPANDED_SIZE(&c->c2.frame)) { - /* - * Setup for call to send/sendto which will send - * packet to remote over the TCP/UDP port. - */ - int size = 0; - ASSERT (link_socket_actual_defined (c->c2.to_link_addr)); + /* + * Setup for call to send/sendto which will send + * packet to remote over the TCP/UDP port. + */ + int size = 0; + ASSERT(link_socket_actual_defined(c->c2.to_link_addr)); #ifdef ENABLE_DEBUG - /* In gremlin-test mode, we may choose to drop this packet */ - if (!c->options.gremlin || ask_gremlin (c->options.gremlin)) + /* In gremlin-test mode, we may choose to drop this packet */ + if (!c->options.gremlin || ask_gremlin(c->options.gremlin)) #endif - { - /* - * Let the traffic shaper know how many bytes - * we wrote. - */ + { + /* + * Let the traffic shaper know how many bytes + * we wrote. + */ #ifdef ENABLE_FEATURE_SHAPER - if (c->options.shaper) - shaper_wrote_bytes (&c->c2.shaper, BLEN (&c->c2.to_link) - + datagram_overhead (c->options.ce.proto)); + if (c->options.shaper) + { + shaper_wrote_bytes(&c->c2.shaper, BLEN(&c->c2.to_link) + + datagram_overhead(c->options.ce.proto)); + } #endif - /* - * Let the pinger know that we sent a packet. - */ - if (c->options.ping_send_timeout) - event_timeout_reset (&c->c2.ping_send_interval); + /* + * Let the pinger know that we sent a packet. + */ + if (c->options.ping_send_timeout) + { + event_timeout_reset(&c->c2.ping_send_interval); + } #if PASSTOS_CAPABILITY - /* Set TOS */ - link_socket_set_tos (c->c2.link_socket); + /* Set TOS */ + link_socket_set_tos(c->c2.link_socket); #endif - /* Log packet send */ + /* Log packet send */ #ifdef LOG_RW - if (c->c2.log_rw) - fprintf (stderr, "W"); + if (c->c2.log_rw) + { + fprintf(stderr, "W"); + } #endif - msg (D_LINK_RW, "%s WRITE [%d] to %s: %s", - proto2ascii (c->c2.link_socket->info.proto, c->c2.link_socket->info.af, true), - BLEN (&c->c2.to_link), - print_link_socket_actual (c->c2.to_link_addr, &gc), - PROTO_DUMP (&c->c2.to_link, &gc)); - - /* Packet send complexified by possible Socks5 usage */ - { - struct link_socket_actual *to_addr = c->c2.to_link_addr; - int size_delta = 0; - - /* If Socks5 over UDP, prepend header */ - socks_preprocess_outgoing_link (c, &to_addr, &size_delta); - - /* Send packet */ - size = link_socket_write (c->c2.link_socket, - &c->c2.to_link, - to_addr); - - /* Undo effect of prepend */ - link_socket_write_post_size_adjust (&size, size_delta, &c->c2.to_link); - } - - if (size > 0) - { - c->c2.max_send_size_local = max_int (size, c->c2.max_send_size_local); - c->c2.link_write_bytes += size; - link_write_bytes_global += size; + msg(D_LINK_RW, "%s WRITE [%d] to %s: %s", + proto2ascii(c->c2.link_socket->info.proto, c->c2.link_socket->info.af, true), + BLEN(&c->c2.to_link), + print_link_socket_actual(c->c2.to_link_addr, &gc), + PROTO_DUMP(&c->c2.to_link, &gc)); + + /* Packet send complexified by possible Socks5 usage */ + { + struct link_socket_actual *to_addr = c->c2.to_link_addr; + int size_delta = 0; + + /* If Socks5 over UDP, prepend header */ + socks_preprocess_outgoing_link(c, &to_addr, &size_delta); + + /* Send packet */ + size = link_socket_write(c->c2.link_socket, + &c->c2.to_link, + to_addr); + + /* Undo effect of prepend */ + link_socket_write_post_size_adjust(&size, size_delta, &c->c2.to_link); + } + + if (size > 0) + { + c->c2.max_send_size_local = max_int(size, c->c2.max_send_size_local); + c->c2.link_write_bytes += size; + link_write_bytes_global += size; #ifdef ENABLE_MEMSTATS - if (mmap_stats) - mmap_stats->link_write_bytes = link_write_bytes_global; + if (mmap_stats) + { + mmap_stats->link_write_bytes = link_write_bytes_global; + } #endif #ifdef ENABLE_MANAGEMENT - if (management) - { - management_bytes_out (management, size); + if (management) + { + management_bytes_out(management, size); #ifdef MANAGEMENT_DEF_AUTH - management_bytes_server (management, &c->c2.link_read_bytes, &c->c2.link_write_bytes, &c->c2.mda_context); + management_bytes_server(management, &c->c2.link_read_bytes, &c->c2.link_write_bytes, &c->c2.mda_context); #endif - } + } #endif - } - } - - /* Check return status */ - error_code = openvpn_errno(); - check_status (size, "write", c->c2.link_socket, NULL); - - if (size > 0) - { - /* Did we write a different size packet than we intended? */ - if (size != BLEN (&c->c2.to_link)) - msg (D_LINK_ERRORS, - "TCP/UDP packet was truncated/expanded on write to %s (tried=%d,actual=%d)", - print_link_socket_actual (c->c2.to_link_addr, &gc), - BLEN (&c->c2.to_link), - size); - } - - /* if not a ping/control message, indicate activity regarding --inactive parameter */ - if (c->c2.buf.len > 0 ) - register_activity (c, size); + } + } + + /* Check return status */ + error_code = openvpn_errno(); + check_status(size, "write", c->c2.link_socket, NULL); + + if (size > 0) + { + /* Did we write a different size packet than we intended? */ + if (size != BLEN(&c->c2.to_link)) + { + msg(D_LINK_ERRORS, + "TCP/UDP packet was truncated/expanded on write to %s (tried=%d,actual=%d)", + print_link_socket_actual(c->c2.to_link_addr, &gc), + BLEN(&c->c2.to_link), + size); + } + } + + /* if not a ping/control message, indicate activity regarding --inactive parameter */ + if (c->c2.buf.len > 0) + { + register_activity(c, size); + } #ifdef ENABLE_CRYPTO - /* for unreachable network and "connecting" state switch to the next host */ - if (size < 0 && ENETUNREACH == error_code && c->c2.tls_multi && - !tls_initial_packet_received (c->c2.tls_multi) && c->options.mode == MODE_POINT_TO_POINT) - { - msg (M_INFO, "Network unreachable, restarting"); - register_signal (c, SIGUSR1, "network-unreachable"); - } + /* for unreachable network and "connecting" state switch to the next host */ + if (size < 0 && ENETUNREACH == error_code && c->c2.tls_multi + && !tls_initial_packet_received(c->c2.tls_multi) && c->options.mode == MODE_POINT_TO_POINT) + { + msg(M_INFO, "Network unreachable, restarting"); + register_signal(c, SIGUSR1, "network-unreachable"); + } #endif } - else + else { - if (c->c2.to_link.len > 0) - msg (D_LINK_ERRORS, "TCP/UDP packet too large on write to %s (tried=%d,max=%d)", - print_link_socket_actual (c->c2.to_link_addr, &gc), - c->c2.to_link.len, - EXPANDED_SIZE (&c->c2.frame)); + if (c->c2.to_link.len > 0) + { + msg(D_LINK_ERRORS, "TCP/UDP packet too large on write to %s (tried=%d,max=%d)", + print_link_socket_actual(c->c2.to_link_addr, &gc), + c->c2.to_link.len, + EXPANDED_SIZE(&c->c2.frame)); + } } - buf_reset (&c->c2.to_link); + buf_reset(&c->c2.to_link); - perf_pop (); - gc_free (&gc); + perf_pop(); + gc_free(&gc); } /* @@ -1325,138 +1453,152 @@ process_outgoing_link (struct context *c) */ void -process_outgoing_tun (struct context *c) +process_outgoing_tun(struct context *c) { - struct gc_arena gc = gc_new (); + struct gc_arena gc = gc_new(); - /* - * Set up for write() call to TUN/TAP - * device. - */ - if (c->c2.to_tun.len <= 0) - return; + /* + * Set up for write() call to TUN/TAP + * device. + */ + if (c->c2.to_tun.len <= 0) + { + return; + } - perf_push (PERF_PROC_OUT_TUN); + perf_push(PERF_PROC_OUT_TUN); - /* - * The --mssfix option requires - * us to examine the IP header (IPv4 or IPv6). - */ - process_ip_header (c, PIP_MSSFIX|PIPV4_EXTRACT_DHCP_ROUTER|PIPV4_CLIENT_NAT|PIPV4_OUTGOING, &c->c2.to_tun); + /* + * The --mssfix option requires + * us to examine the IP header (IPv4 or IPv6). + */ + process_ip_header(c, PIP_MSSFIX|PIPV4_EXTRACT_DHCP_ROUTER|PIPV4_CLIENT_NAT|PIPV4_OUTGOING, &c->c2.to_tun); - if (c->c2.to_tun.len <= MAX_RW_SIZE_TUN (&c->c2.frame)) + if (c->c2.to_tun.len <= MAX_RW_SIZE_TUN(&c->c2.frame)) { - /* - * Write to TUN/TAP device. - */ - int size; + /* + * Write to TUN/TAP device. + */ + int size; #ifdef LOG_RW - if (c->c2.log_rw) - fprintf (stderr, "w"); + if (c->c2.log_rw) + { + fprintf(stderr, "w"); + } #endif - dmsg (D_TUN_RW, "TUN WRITE [%d]", BLEN (&c->c2.to_tun)); + dmsg(D_TUN_RW, "TUN WRITE [%d]", BLEN(&c->c2.to_tun)); #ifdef PACKET_TRUNCATION_CHECK - ipv4_packet_size_verify (BPTR (&c->c2.to_tun), - BLEN (&c->c2.to_tun), - TUNNEL_TYPE (c->c1.tuntap), - "WRITE_TUN", - &c->c2.n_trunc_tun_write); + ipv4_packet_size_verify(BPTR(&c->c2.to_tun), + BLEN(&c->c2.to_tun), + TUNNEL_TYPE(c->c1.tuntap), + "WRITE_TUN", + &c->c2.n_trunc_tun_write); #endif #ifdef TUN_PASS_BUFFER - size = write_tun_buffered (c->c1.tuntap, &c->c2.to_tun); + size = write_tun_buffered(c->c1.tuntap, &c->c2.to_tun); #else - size = write_tun (c->c1.tuntap, BPTR (&c->c2.to_tun), BLEN (&c->c2.to_tun)); + size = write_tun(c->c1.tuntap, BPTR(&c->c2.to_tun), BLEN(&c->c2.to_tun)); #endif - if (size > 0) - c->c2.tun_write_bytes += size; - check_status (size, "write to TUN/TAP", NULL, c->c1.tuntap); - - /* check written packet size */ - if (size > 0) - { - /* Did we write a different size packet than we intended? */ - if (size != BLEN (&c->c2.to_tun)) - msg (D_LINK_ERRORS, - "TUN/TAP packet was destructively fragmented on write to %s (tried=%d,actual=%d)", - c->c1.tuntap->actual_name, - BLEN (&c->c2.to_tun), - size); - - /* indicate activity regarding --inactive parameter */ - register_activity (c, size); - } + if (size > 0) + { + c->c2.tun_write_bytes += size; + } + check_status(size, "write to TUN/TAP", NULL, c->c1.tuntap); + + /* check written packet size */ + if (size > 0) + { + /* Did we write a different size packet than we intended? */ + if (size != BLEN(&c->c2.to_tun)) + { + msg(D_LINK_ERRORS, + "TUN/TAP packet was destructively fragmented on write to %s (tried=%d,actual=%d)", + c->c1.tuntap->actual_name, + BLEN(&c->c2.to_tun), + size); + } + + /* indicate activity regarding --inactive parameter */ + register_activity(c, size); + } } - else + else { - /* - * This should never happen, probably indicates some kind - * of MTU mismatch. - */ - msg (D_LINK_ERRORS, "tun packet too large on write (tried=%d,max=%d)", - c->c2.to_tun.len, - MAX_RW_SIZE_TUN (&c->c2.frame)); + /* + * This should never happen, probably indicates some kind + * of MTU mismatch. + */ + msg(D_LINK_ERRORS, "tun packet too large on write (tried=%d,max=%d)", + c->c2.to_tun.len, + MAX_RW_SIZE_TUN(&c->c2.frame)); } - buf_reset (&c->c2.to_tun); + buf_reset(&c->c2.to_tun); - perf_pop (); - gc_free (&gc); + perf_pop(); + gc_free(&gc); } void -pre_select (struct context *c) +pre_select(struct context *c) { - /* make sure current time (now) is updated on function entry */ + /* make sure current time (now) is updated on function entry */ - /* - * Start with an effectively infinite timeout, then let it - * reduce to a timeout that reflects the component which - * needs the earliest service. - */ - c->c2.timeval.tv_sec = BIG_TIMEOUT; - c->c2.timeval.tv_usec = 0; + /* + * Start with an effectively infinite timeout, then let it + * reduce to a timeout that reflects the component which + * needs the earliest service. + */ + c->c2.timeval.tv_sec = BIG_TIMEOUT; + c->c2.timeval.tv_usec = 0; #if defined(_WIN32) - if (check_debug_level (D_TAP_WIN_DEBUG)) + if (check_debug_level(D_TAP_WIN_DEBUG)) { - c->c2.timeval.tv_sec = 1; - if (tuntap_defined (c->c1.tuntap)) - tun_show_debug (c->c1.tuntap); + c->c2.timeval.tv_sec = 1; + if (tuntap_defined(c->c1.tuntap)) + { + tun_show_debug(c->c1.tuntap); + } } #endif - /* check coarse timers? */ - check_coarse_timers (c); - if (c->sig->signal_received) - return; + /* check coarse timers? */ + check_coarse_timers(c); + if (c->sig->signal_received) + { + return; + } - /* Does TLS need service? */ - check_tls (c); + /* Does TLS need service? */ + check_tls(c); - /* In certain cases, TLS errors will require a restart */ - check_tls_errors (c); - if (c->sig->signal_received) - return; + /* In certain cases, TLS errors will require a restart */ + check_tls_errors(c); + if (c->sig->signal_received) + { + return; + } - /* check for incoming configuration info on the control channel */ - check_incoming_control_channel (c); + /* check for incoming configuration info on the control channel */ + check_incoming_control_channel(c); #ifdef ENABLE_OCC - /* Should we send an OCC message? */ - check_send_occ_msg (c); + /* Should we send an OCC message? */ + check_send_occ_msg(c); #endif #ifdef ENABLE_FRAGMENT - /* Should we deliver a datagram fragment to remote? */ - check_fragment (c); + /* Should we deliver a datagram fragment to remote? */ + check_fragment(c); #endif - /* Update random component of timeout */ - check_timeout_random_component (c); + /* Update random component of timeout */ + check_timeout_random_component(c); } /* @@ -1466,218 +1608,242 @@ pre_select (struct context *c) */ void -io_wait_dowork (struct context *c, const unsigned int flags) +io_wait_dowork(struct context *c, const unsigned int flags) { - unsigned int socket = 0; - unsigned int tuntap = 0; - struct event_set_return esr[4]; - - /* These shifts all depend on EVENT_READ and EVENT_WRITE */ - static int socket_shift = 0; /* depends on SOCKET_READ and SOCKET_WRITE */ - static int tun_shift = 2; /* depends on TUN_READ and TUN_WRITE */ - static int err_shift = 4; /* depends on ES_ERROR */ + unsigned int socket = 0; + unsigned int tuntap = 0; + struct event_set_return esr[4]; + + /* These shifts all depend on EVENT_READ and EVENT_WRITE */ + static int socket_shift = 0; /* depends on SOCKET_READ and SOCKET_WRITE */ + static int tun_shift = 2; /* depends on TUN_READ and TUN_WRITE */ + static int err_shift = 4; /* depends on ES_ERROR */ #ifdef ENABLE_MANAGEMENT - static int management_shift = 6; /* depends on MANAGEMENT_READ and MANAGEMENT_WRITE */ + static int management_shift = 6; /* depends on MANAGEMENT_READ and MANAGEMENT_WRITE */ #endif #ifdef ENABLE_ASYNC_PUSH - static int file_shift = 8; /* listening inotify events */ + static int file_shift = 8; /* listening inotify events */ #endif - /* - * Decide what kind of events we want to wait for. - */ - event_reset (c->c2.event_set); - - /* - * On win32 we use the keyboard or an event object as a source - * of asynchronous signals. - */ - if (flags & IOW_WAIT_SIGNAL) - wait_signal (c->c2.event_set, (void*)&err_shift); - - /* - * If outgoing data (for TCP/UDP port) pending, wait for ready-to-send - * status from TCP/UDP port. Otherwise, wait for incoming data on - * TUN/TAP device. - */ - if (flags & IOW_TO_LINK) - { - if (flags & IOW_SHAPER) - { - /* - * If sending this packet would put us over our traffic shaping - * quota, don't send -- instead compute the delay we must wait - * until it will be OK to send the packet. - */ + /* + * Decide what kind of events we want to wait for. + */ + event_reset(c->c2.event_set); + + /* + * On win32 we use the keyboard or an event object as a source + * of asynchronous signals. + */ + if (flags & IOW_WAIT_SIGNAL) + { + wait_signal(c->c2.event_set, (void *)&err_shift); + } + + /* + * If outgoing data (for TCP/UDP port) pending, wait for ready-to-send + * status from TCP/UDP port. Otherwise, wait for incoming data on + * TUN/TAP device. + */ + if (flags & IOW_TO_LINK) + { + if (flags & IOW_SHAPER) + { + /* + * If sending this packet would put us over our traffic shaping + * quota, don't send -- instead compute the delay we must wait + * until it will be OK to send the packet. + */ #ifdef ENABLE_FEATURE_SHAPER - int delay = 0; - - /* set traffic shaping delay in microseconds */ - if (c->options.shaper) - delay = max_int (delay, shaper_delay (&c->c2.shaper)); - - if (delay < 1000) - { - socket |= EVENT_WRITE; - } - else - { - shaper_soonest_event (&c->c2.timeval, delay); - } + int delay = 0; + + /* set traffic shaping delay in microseconds */ + if (c->options.shaper) + { + delay = max_int(delay, shaper_delay(&c->c2.shaper)); + } + + if (delay < 1000) + { + socket |= EVENT_WRITE; + } + else + { + shaper_soonest_event(&c->c2.timeval, delay); + } #else /* ENABLE_FEATURE_SHAPER */ - socket |= EVENT_WRITE; + socket |= EVENT_WRITE; #endif /* ENABLE_FEATURE_SHAPER */ - } - else - { - socket |= EVENT_WRITE; - } + } + else + { + socket |= EVENT_WRITE; + } } - else if (!((flags & IOW_FRAG) && TO_LINK_FRAG (c))) + else if (!((flags & IOW_FRAG) && TO_LINK_FRAG(c))) { - if (flags & IOW_READ_TUN) - tuntap |= EVENT_READ; + if (flags & IOW_READ_TUN) + { + tuntap |= EVENT_READ; + } } - /* - * If outgoing data (for TUN/TAP device) pending, wait for ready-to-send status - * from device. Otherwise, wait for incoming data on TCP/UDP port. - */ - if (flags & IOW_TO_TUN) + /* + * If outgoing data (for TUN/TAP device) pending, wait for ready-to-send status + * from device. Otherwise, wait for incoming data on TCP/UDP port. + */ + if (flags & IOW_TO_TUN) { - tuntap |= EVENT_WRITE; + tuntap |= EVENT_WRITE; } - else + else { - if (flags & IOW_READ_LINK) - socket |= EVENT_READ; + if (flags & IOW_READ_LINK) + { + socket |= EVENT_READ; + } } - /* - * outgoing bcast buffer waiting to be sent? - */ - if (flags & IOW_MBUF) - socket |= EVENT_WRITE; + /* + * outgoing bcast buffer waiting to be sent? + */ + if (flags & IOW_MBUF) + { + socket |= EVENT_WRITE; + } - /* - * Force wait on TUN input, even if also waiting on TCP/UDP output - */ - if (flags & IOW_READ_TUN_FORCE) - tuntap |= EVENT_READ; + /* + * Force wait on TUN input, even if also waiting on TCP/UDP output + */ + if (flags & IOW_READ_TUN_FORCE) + { + tuntap |= EVENT_READ; + } - /* - * Configure event wait based on socket, tuntap flags. - */ - socket_set (c->c2.link_socket, c->c2.event_set, socket, (void*)&socket_shift, NULL); - tun_set (c->c1.tuntap, c->c2.event_set, tuntap, (void*)&tun_shift, NULL); + /* + * Configure event wait based on socket, tuntap flags. + */ + socket_set(c->c2.link_socket, c->c2.event_set, socket, (void *)&socket_shift, NULL); + tun_set(c->c1.tuntap, c->c2.event_set, tuntap, (void *)&tun_shift, NULL); #ifdef ENABLE_MANAGEMENT - if (management) - management_socket_set (management, c->c2.event_set, (void*)&management_shift, NULL); + if (management) + { + management_socket_set(management, c->c2.event_set, (void *)&management_shift, NULL); + } #endif #ifdef ENABLE_ASYNC_PUSH - /* arm inotify watcher */ - if (c->options.mode == MODE_SERVER) - event_ctl (c->c2.event_set, c->c2.inotify_fd, EVENT_READ, (void*)&file_shift); + /* arm inotify watcher */ + if (c->options.mode == MODE_SERVER) + { + event_ctl(c->c2.event_set, c->c2.inotify_fd, EVENT_READ, (void *)&file_shift); + } #endif - /* - * Possible scenarios: - * (1) tcp/udp port has data available to read - * (2) tcp/udp port is ready to accept more data to write - * (3) tun dev has data available to read - * (4) tun dev is ready to accept more data to write - * (5) we received a signal (handler sets signal_received) - * (6) timeout (tv) expired - */ + /* + * Possible scenarios: + * (1) tcp/udp port has data available to read + * (2) tcp/udp port is ready to accept more data to write + * (3) tun dev has data available to read + * (4) tun dev is ready to accept more data to write + * (5) we received a signal (handler sets signal_received) + * (6) timeout (tv) expired + */ - c->c2.event_set_status = ES_ERROR; + c->c2.event_set_status = ES_ERROR; - if (!c->sig->signal_received) + if (!c->sig->signal_received) { - if (!(flags & IOW_CHECK_RESIDUAL) || !socket_read_residual (c->c2.link_socket)) - { - int status; + if (!(flags & IOW_CHECK_RESIDUAL) || !socket_read_residual(c->c2.link_socket)) + { + int status; #ifdef ENABLE_DEBUG - if (check_debug_level (D_EVENT_WAIT)) - show_wait_status (c); + if (check_debug_level(D_EVENT_WAIT)) + { + show_wait_status(c); + } #endif - /* - * Wait for something to happen. - */ - status = event_wait (c->c2.event_set, &c->c2.timeval, esr, SIZE(esr)); - - check_status (status, "event_wait", NULL, NULL); - - if (status > 0) - { - int i; - c->c2.event_set_status = 0; - for (i = 0; i < status; ++i) - { - const struct event_set_return *e = &esr[i]; - c->c2.event_set_status |= ((e->rwflags & 3) << *((int*)e->arg)); - } - } - else if (status == 0) - { - c->c2.event_set_status = ES_TIMEOUT; - } - } - else - { - c->c2.event_set_status = SOCKET_READ; - } - } - - /* 'now' should always be a reasonably up-to-date timestamp */ - update_time (); - - /* set signal_received if a signal was received */ - if (c->c2.event_set_status & ES_ERROR) - get_signal (&c->sig->signal_received); - - dmsg (D_EVENT_WAIT, "I/O WAIT status=0x%04x", c->c2.event_set_status); + /* + * Wait for something to happen. + */ + status = event_wait(c->c2.event_set, &c->c2.timeval, esr, SIZE(esr)); + + check_status(status, "event_wait", NULL, NULL); + + if (status > 0) + { + int i; + c->c2.event_set_status = 0; + for (i = 0; i < status; ++i) + { + const struct event_set_return *e = &esr[i]; + c->c2.event_set_status |= ((e->rwflags & 3) << *((int *)e->arg)); + } + } + else if (status == 0) + { + c->c2.event_set_status = ES_TIMEOUT; + } + } + else + { + c->c2.event_set_status = SOCKET_READ; + } + } + + /* 'now' should always be a reasonably up-to-date timestamp */ + update_time(); + + /* set signal_received if a signal was received */ + if (c->c2.event_set_status & ES_ERROR) + { + get_signal(&c->sig->signal_received); + } + + dmsg(D_EVENT_WAIT, "I/O WAIT status=0x%04x", c->c2.event_set_status); } void -process_io (struct context *c) +process_io(struct context *c) { - const unsigned int status = c->c2.event_set_status; + const unsigned int status = c->c2.event_set_status; #ifdef ENABLE_MANAGEMENT - if (status & (MANAGEMENT_READ|MANAGEMENT_WRITE)) + if (status & (MANAGEMENT_READ|MANAGEMENT_WRITE)) { - ASSERT (management); - management_io (management); + ASSERT(management); + management_io(management); } #endif - /* TCP/UDP port ready to accept write */ - if (status & SOCKET_WRITE) + /* TCP/UDP port ready to accept write */ + if (status & SOCKET_WRITE) { - process_outgoing_link (c); + process_outgoing_link(c); } - /* TUN device ready to accept write */ - else if (status & TUN_WRITE) + /* TUN device ready to accept write */ + else if (status & TUN_WRITE) { - process_outgoing_tun (c); + process_outgoing_tun(c); } - /* Incoming data on TCP/UDP port */ - else if (status & SOCKET_READ) + /* Incoming data on TCP/UDP port */ + else if (status & SOCKET_READ) { - read_incoming_link (c); - if (!IS_SIG (c)) - process_incoming_link (c); + read_incoming_link(c); + if (!IS_SIG(c)) + { + process_incoming_link(c); + } } - /* Incoming data on TUN device */ - else if (status & TUN_READ) + /* Incoming data on TUN device */ + else if (status & TUN_READ) { - read_incoming_tun (c); - if (!IS_SIG (c)) - process_incoming_tun (c); + read_incoming_tun(c); + if (!IS_SIG(c)) + { + process_incoming_tun(c); + } } } diff --git a/src/openvpn/forward.h b/src/openvpn/forward.h index 0856aa73081..82f7bbf09ba 100644 --- a/src/openvpn/forward.h +++ b/src/openvpn/forward.h @@ -41,7 +41,7 @@ #define ANY_OUT(c) (TUN_OUT(c) || LINK_OUT(c)) #ifdef ENABLE_FRAGMENT -#define TO_LINK_FRAG(c) ((c)->c2.fragment && fragment_outgoing_defined ((c)->c2.fragment)) +#define TO_LINK_FRAG(c) ((c)->c2.fragment && fragment_outgoing_defined((c)->c2.fragment)) #else #define TO_LINK_FRAG(c) (false) #endif @@ -62,11 +62,13 @@ #define IOW_READ (IOW_READ_TUN|IOW_READ_LINK) -void pre_select (struct context *c); -void process_io (struct context *c); +void pre_select(struct context *c); -const char *wait_status_string (struct context *c, struct gc_arena *gc); -void show_wait_status (struct context *c); +void process_io(struct context *c); + +const char *wait_status_string(struct context *c, struct gc_arena *gc); + +void show_wait_status(struct context *c); /**********************************************************************/ @@ -102,8 +104,9 @@ void show_wait_status (struct context *c); * the packet then gets fragmented, this function will be called again * once for each remaining fragment with this parameter set to false. */ -void encrypt_sign (struct context *c, bool comp_frag); -int get_server_poll_remaining_time (struct event_timeout* server_poll_timeout); +void encrypt_sign(struct context *c, bool comp_frag); + +int get_server_poll_remaining_time(struct event_timeout *server_poll_timeout); /**********************************************************************/ /** @@ -125,7 +128,7 @@ int get_server_poll_remaining_time (struct event_timeout* server_poll_timeout); * @param c - The context structure which contains the external * network socket from which to read incoming packets. */ -void read_incoming_link (struct context *c); +void read_incoming_link(struct context *c); /** * Starts processing a packet read from the external network interface. @@ -153,7 +156,7 @@ void read_incoming_link (struct context *c); * * @return true if packet is authenticated, false otherwise. */ -bool process_incoming_link_part1 (struct context *c, struct link_socket_info *lsi, bool floated); +bool process_incoming_link_part1(struct context *c, struct link_socket_info *lsi, bool floated); /** * Continues processing a packet read from the external network interface. @@ -180,7 +183,7 @@ bool process_incoming_link_part1 (struct context *c, struct link_socket_info *ls * @param orig_buf - Pointer to a buffer data. * */ -void process_incoming_link_part2 (struct context *c, struct link_socket_info *lsi, const uint8_t *orig_buf); +void process_incoming_link_part2(struct context *c, struct link_socket_info *lsi, const uint8_t *orig_buf); /** * Write a packet to the external network interface. @@ -194,7 +197,7 @@ void process_incoming_link_part2 (struct context *c, struct link_socket_info *ls * @param c - The context structure of the VPN tunnel associated with the * packet. */ -void process_outgoing_link (struct context *c); +void process_outgoing_link(struct context *c); /**************************************************************************/ @@ -210,7 +213,7 @@ void process_outgoing_link (struct context *c); * @param c - The context structure in which to store the received * packet. */ -void read_incoming_tun (struct context *c); +void read_incoming_tun(struct context *c); /** @@ -225,7 +228,7 @@ void read_incoming_tun (struct context *c); * @param c - The context structure of the VPN tunnel associated with the * packet. */ -void process_incoming_tun (struct context *c); +void process_incoming_tun(struct context *c); /** @@ -240,12 +243,12 @@ void process_incoming_tun (struct context *c); * @param c - The context structure of the VPN tunnel associated with * the packet. */ -void process_outgoing_tun (struct context *c); +void process_outgoing_tun(struct context *c); /**************************************************************************/ -bool send_control_channel_string (struct context *c, const char *str, int msglevel); +bool send_control_channel_string(struct context *c, const char *str, int msglevel); #define PIPV4_PASSTOS (1<<0) #define PIP_MSSFIX (1<<1) /* v4 and v6 */ @@ -253,10 +256,11 @@ bool send_control_channel_string (struct context *c, const char *str, int msglev #define PIPV4_EXTRACT_DHCP_ROUTER (1<<3) #define PIPV4_CLIENT_NAT (1<<4) -void process_ip_header (struct context *c, unsigned int flags, struct buffer *buf); +void process_ip_header(struct context *c, unsigned int flags, struct buffer *buf); #if P2MP -void schedule_exit (struct context *c, const int n_seconds, const int signal); +void schedule_exit(struct context *c, const int n_seconds, const int signal); + #endif #endif /* FORWARD_H */ diff --git a/src/openvpn/fragment.c b/src/openvpn/fragment.c index 7ad1d616fbc..87b93805747 100644 --- a/src/openvpn/fragment.c +++ b/src/openvpn/fragment.c @@ -40,19 +40,19 @@ #define FRAG_ERR(s) { errmsg = s; goto error; } static void -fragment_list_buf_init (struct fragment_list *list, const struct frame *frame) +fragment_list_buf_init(struct fragment_list *list, const struct frame *frame) { - int i; - for (i = 0; i < N_FRAG_BUF; ++i) - list->fragments[i].buf = alloc_buf (BUF_SIZE (frame)); + int i; + for (i = 0; i < N_FRAG_BUF; ++i) + list->fragments[i].buf = alloc_buf(BUF_SIZE(frame)); } static void -fragment_list_buf_free (struct fragment_list *list) +fragment_list_buf_free(struct fragment_list *list) { - int i; - for (i = 0; i < N_FRAG_BUF; ++i) - free_buf (&list->fragments[i].buf); + int i; + for (i = 0; i < N_FRAG_BUF; ++i) + free_buf(&list->fragments[i].buf); } /* @@ -60,69 +60,69 @@ fragment_list_buf_free (struct fragment_list *list) * similar to packet_id code. */ static struct fragment * -fragment_list_get_buf (struct fragment_list *list, int seq_id) +fragment_list_get_buf(struct fragment_list *list, int seq_id) { - int diff; - if (abs (diff = modulo_subtract (seq_id, list->seq_id, N_SEQ_ID)) >= N_FRAG_BUF) + int diff; + if (abs(diff = modulo_subtract(seq_id, list->seq_id, N_SEQ_ID)) >= N_FRAG_BUF) { - int i; - for (i = 0; i < N_FRAG_BUF; ++i) - list->fragments[i].defined = false; - list->index = 0; - list->seq_id = seq_id; - diff = 0; + int i; + for (i = 0; i < N_FRAG_BUF; ++i) + list->fragments[i].defined = false; + list->index = 0; + list->seq_id = seq_id; + diff = 0; } - while (diff > 0) + while (diff > 0) { - list->fragments[list->index = modulo_add (list->index, 1, N_FRAG_BUF)].defined = false; - list->seq_id = modulo_add (list->seq_id, 1, N_SEQ_ID); - --diff; + list->fragments[list->index = modulo_add(list->index, 1, N_FRAG_BUF)].defined = false; + list->seq_id = modulo_add(list->seq_id, 1, N_SEQ_ID); + --diff; } - return &list->fragments[modulo_add (list->index, diff, N_FRAG_BUF)]; + return &list->fragments[modulo_add(list->index, diff, N_FRAG_BUF)]; } struct fragment_master * -fragment_init (struct frame *frame) +fragment_init(struct frame *frame) { - struct fragment_master *ret; + struct fragment_master *ret; - /* code that initializes other parts of - fragment_master assume an initial CLEAR */ - ALLOC_OBJ_CLEAR (ret, struct fragment_master); + /* code that initializes other parts of + * fragment_master assume an initial CLEAR */ + ALLOC_OBJ_CLEAR(ret, struct fragment_master); - /* add in the size of our contribution to the expanded frame size */ - frame_add_to_extra_frame (frame, sizeof(fragment_header_type)); + /* add in the size of our contribution to the expanded frame size */ + frame_add_to_extra_frame(frame, sizeof(fragment_header_type)); - /* - * Outgoing sequence ID is randomized to reduce - * the probability of sequence number collisions - * when openvpn sessions are restarted. This is - * not done out of any need for security, as all - * fragmentation control information resides - * inside of the encrypted/authenticated envelope. - */ - ret->outgoing_seq_id = (int)get_random() & (N_SEQ_ID - 1); + /* + * Outgoing sequence ID is randomized to reduce + * the probability of sequence number collisions + * when openvpn sessions are restarted. This is + * not done out of any need for security, as all + * fragmentation control information resides + * inside of the encrypted/authenticated envelope. + */ + ret->outgoing_seq_id = (int)get_random() & (N_SEQ_ID - 1); - event_timeout_init (&ret->wakeup, FRAG_WAKEUP_INTERVAL, now); + event_timeout_init(&ret->wakeup, FRAG_WAKEUP_INTERVAL, now); - return ret; + return ret; } void -fragment_free (struct fragment_master *f) +fragment_free(struct fragment_master *f) { - fragment_list_buf_free (&f->incoming); - free_buf (&f->outgoing); - free_buf (&f->outgoing_return); - free (f); + fragment_list_buf_free(&f->incoming); + free_buf(&f->outgoing); + free_buf(&f->outgoing_return); + free(f); } void -fragment_frame_init (struct fragment_master *f, const struct frame *frame) +fragment_frame_init(struct fragment_master *f, const struct frame *frame) { - fragment_list_buf_init (&f->incoming, frame); - f->outgoing = alloc_buf (BUF_SIZE (frame)); - f->outgoing_return = alloc_buf (BUF_SIZE (frame)); + fragment_list_buf_init(&f->incoming, frame); + f->outgoing = alloc_buf(BUF_SIZE(frame)); + f->outgoing_return = alloc_buf(BUF_SIZE(frame)); } /* @@ -132,154 +132,164 @@ fragment_frame_init (struct fragment_master *f, const struct frame *frame) * If a fragment fully completes the datagram, return the datagram. */ void -fragment_incoming (struct fragment_master *f, struct buffer *buf, - const struct frame* frame) +fragment_incoming(struct fragment_master *f, struct buffer *buf, + const struct frame *frame) { - const char *errmsg = NULL; - fragment_header_type flags = 0; - int frag_type = 0; + const char *errmsg = NULL; + fragment_header_type flags = 0; + int frag_type = 0; - if (buf->len > 0) + if (buf->len > 0) { - /* get flags from packet head */ - if (!buf_read (buf, &flags, sizeof (flags))) - FRAG_ERR ("flags not found in packet"); - flags = ntoh_fragment_header_type (flags); + /* get flags from packet head */ + if (!buf_read(buf, &flags, sizeof(flags))) + { + FRAG_ERR("flags not found in packet"); + } + flags = ntoh_fragment_header_type(flags); - /* get fragment type from flags */ - frag_type = ((flags >> FRAG_TYPE_SHIFT) & FRAG_TYPE_MASK); + /* get fragment type from flags */ + frag_type = ((flags >> FRAG_TYPE_SHIFT) & FRAG_TYPE_MASK); #if 0 - /* - * If you want to extract FRAG_EXTRA_MASK/FRAG_EXTRA_SHIFT bits, - * do it here. - */ - if (frag_type == FRAG_WHOLE || frag_type == FRAG_YES_NOTLAST) - { - } + /* + * If you want to extract FRAG_EXTRA_MASK/FRAG_EXTRA_SHIFT bits, + * do it here. + */ + if (frag_type == FRAG_WHOLE || frag_type == FRAG_YES_NOTLAST) + { + } #endif - /* handle the fragment type */ - if (frag_type == FRAG_WHOLE) - { - dmsg (D_FRAG_DEBUG, - "FRAG_IN buf->len=%d type=FRAG_WHOLE flags=" - fragment_header_format, - buf->len, - flags); - - if (flags & (FRAG_SEQ_ID_MASK | FRAG_ID_MASK)) - FRAG_ERR ("spurrious FRAG_WHOLE flags"); - } - else if (frag_type == FRAG_YES_NOTLAST || frag_type == FRAG_YES_LAST) - { - const int seq_id = ((flags >> FRAG_SEQ_ID_SHIFT) & FRAG_SEQ_ID_MASK); - const int n = ((flags >> FRAG_ID_SHIFT) & FRAG_ID_MASK); - const int size = ((frag_type == FRAG_YES_LAST) - ? (int)(((flags >> FRAG_SIZE_SHIFT) & FRAG_SIZE_MASK) << FRAG_SIZE_ROUND_SHIFT) - : buf->len); - - /* get the appropriate fragment buffer based on received seq_id */ - struct fragment *frag = fragment_list_get_buf (&f->incoming, seq_id); - - dmsg (D_FRAG_DEBUG, - "FRAG_IN len=%d type=%d seq_id=%d frag_id=%d size=%d flags=" - fragment_header_format, - buf->len, - frag_type, - seq_id, - n, - size, - flags); - - /* make sure that size is an even multiple of 1<defined || (frag->defined && frag->max_frag_size != size)) - { - frag->defined = true; - frag->max_frag_size = size; - frag->map = 0; - ASSERT (buf_init (&frag->buf, FRAME_HEADROOM_ADJ (frame, FRAME_HEADROOM_MARKER_FRAGMENT))); - } - - /* copy the data to fragment buffer */ - if (!buf_copy_range (&frag->buf, n * size, buf, 0, buf->len)) - FRAG_ERR ("fragment buffer overflow"); - - /* set elements in bit array to reflect which fragments have been received */ - frag->map |= (((frag_type == FRAG_YES_LAST) ? FRAG_MAP_MASK : 1) << n); - - /* update timestamp on partially built datagram */ - frag->timestamp = now; - - /* received full datagram? */ - if ((frag->map & FRAG_MAP_MASK) == FRAG_MAP_MASK) - { - frag->defined = false; - *buf = frag->buf; - } - else - { - buf->len = 0; - } - } - else if (frag_type == FRAG_TEST) - { - FRAG_ERR ("FRAG_TEST not implemented"); - } - else - { - FRAG_ERR ("unknown fragment type"); - } + /* handle the fragment type */ + if (frag_type == FRAG_WHOLE) + { + dmsg(D_FRAG_DEBUG, + "FRAG_IN buf->len=%d type=FRAG_WHOLE flags=" + fragment_header_format, + buf->len, + flags); + + if (flags & (FRAG_SEQ_ID_MASK | FRAG_ID_MASK)) + { + FRAG_ERR("spurrious FRAG_WHOLE flags"); + } + } + else if (frag_type == FRAG_YES_NOTLAST || frag_type == FRAG_YES_LAST) + { + const int seq_id = ((flags >> FRAG_SEQ_ID_SHIFT) & FRAG_SEQ_ID_MASK); + const int n = ((flags >> FRAG_ID_SHIFT) & FRAG_ID_MASK); + const int size = ((frag_type == FRAG_YES_LAST) + ? (int)(((flags >> FRAG_SIZE_SHIFT) & FRAG_SIZE_MASK) << FRAG_SIZE_ROUND_SHIFT) + : buf->len); + + /* get the appropriate fragment buffer based on received seq_id */ + struct fragment *frag = fragment_list_get_buf(&f->incoming, seq_id); + + dmsg(D_FRAG_DEBUG, + "FRAG_IN len=%d type=%d seq_id=%d frag_id=%d size=%d flags=" + fragment_header_format, + buf->len, + frag_type, + seq_id, + n, + size, + flags); + + /* make sure that size is an even multiple of 1<defined || (frag->defined && frag->max_frag_size != size)) + { + frag->defined = true; + frag->max_frag_size = size; + frag->map = 0; + ASSERT(buf_init(&frag->buf, FRAME_HEADROOM_ADJ(frame, FRAME_HEADROOM_MARKER_FRAGMENT))); + } + + /* copy the data to fragment buffer */ + if (!buf_copy_range(&frag->buf, n * size, buf, 0, buf->len)) + { + FRAG_ERR("fragment buffer overflow"); + } + + /* set elements in bit array to reflect which fragments have been received */ + frag->map |= (((frag_type == FRAG_YES_LAST) ? FRAG_MAP_MASK : 1) << n); + + /* update timestamp on partially built datagram */ + frag->timestamp = now; + + /* received full datagram? */ + if ((frag->map & FRAG_MAP_MASK) == FRAG_MAP_MASK) + { + frag->defined = false; + *buf = frag->buf; + } + else + { + buf->len = 0; + } + } + else if (frag_type == FRAG_TEST) + { + FRAG_ERR("FRAG_TEST not implemented"); + } + else + { + FRAG_ERR("unknown fragment type"); + } } - return; + return; - error: - if (errmsg) - msg (D_FRAG_ERRORS, "FRAG_IN error flags=" fragment_header_format ": %s", flags, errmsg); - buf->len = 0; - return; +error: + if (errmsg) + { + msg(D_FRAG_ERRORS, "FRAG_IN error flags=" fragment_header_format ": %s", flags, errmsg); + } + buf->len = 0; + return; } /* pack fragment parms into a uint32_t and prepend to buffer */ static void -fragment_prepend_flags (struct buffer *buf, - int type, - int seq_id, - int frag_id, - int frag_size) +fragment_prepend_flags(struct buffer *buf, + int type, + int seq_id, + int frag_id, + int frag_size) { - fragment_header_type flags = ((type & FRAG_TYPE_MASK) << FRAG_TYPE_SHIFT) - | ((seq_id & FRAG_SEQ_ID_MASK) << FRAG_SEQ_ID_SHIFT) - | ((frag_id & FRAG_ID_MASK) << FRAG_ID_SHIFT); + fragment_header_type flags = ((type & FRAG_TYPE_MASK) << FRAG_TYPE_SHIFT) + | ((seq_id & FRAG_SEQ_ID_MASK) << FRAG_SEQ_ID_SHIFT) + | ((frag_id & FRAG_ID_MASK) << FRAG_ID_SHIFT); - if (type == FRAG_WHOLE || type == FRAG_YES_NOTLAST) + if (type == FRAG_WHOLE || type == FRAG_YES_NOTLAST) { - /* - * If you want to set FRAG_EXTRA_MASK/FRAG_EXTRA_SHIFT bits, - * do it here. - */ - dmsg (D_FRAG_DEBUG, - "FRAG_OUT len=%d type=%d seq_id=%d frag_id=%d frag_size=%d flags=" - fragment_header_format, - buf->len, type, seq_id, frag_id, frag_size, flags); + /* + * If you want to set FRAG_EXTRA_MASK/FRAG_EXTRA_SHIFT bits, + * do it here. + */ + dmsg(D_FRAG_DEBUG, + "FRAG_OUT len=%d type=%d seq_id=%d frag_id=%d frag_size=%d flags=" + fragment_header_format, + buf->len, type, seq_id, frag_id, frag_size, flags); } - else + else { - flags |= (((frag_size >> FRAG_SIZE_ROUND_SHIFT) & FRAG_SIZE_MASK) << FRAG_SIZE_SHIFT); + flags |= (((frag_size >> FRAG_SIZE_ROUND_SHIFT) & FRAG_SIZE_MASK) << FRAG_SIZE_SHIFT); - dmsg (D_FRAG_DEBUG, - "FRAG_OUT len=%d type=%d seq_id=%d frag_id=%d frag_size=%d flags=" - fragment_header_format, - buf->len, type, seq_id, frag_id, frag_size, flags); + dmsg(D_FRAG_DEBUG, + "FRAG_OUT len=%d type=%d seq_id=%d frag_id=%d frag_size=%d flags=" + fragment_header_format, + buf->len, type, seq_id, frag_id, frag_size, flags); } - flags = hton_fragment_header_type (flags); - ASSERT (buf_write_prepend (buf, &flags, sizeof (flags))); + flags = hton_fragment_header_type(flags); + ASSERT(buf_write_prepend(buf, &flags, sizeof(flags))); } /* @@ -288,127 +298,141 @@ fragment_prepend_flags (struct buffer *buf, * similar size as previous fragments. */ static inline int -optimal_fragment_size (int len, int max_frag_size) +optimal_fragment_size(int len, int max_frag_size) { - const int mfs_aligned = (max_frag_size & ~FRAG_SIZE_ROUND_MASK); - const int div = len / mfs_aligned; - const int mod = len % mfs_aligned; - - if (div > 0 && mod > 0 && mod < mfs_aligned * 3 / 4) - return min_int (mfs_aligned, (max_frag_size - ((max_frag_size - mod) / (div + 1)) - + FRAG_SIZE_ROUND_MASK) & ~FRAG_SIZE_ROUND_MASK); - else - return mfs_aligned; + const int mfs_aligned = (max_frag_size & ~FRAG_SIZE_ROUND_MASK); + const int div = len / mfs_aligned; + const int mod = len % mfs_aligned; + + if (div > 0 && mod > 0 && mod < mfs_aligned * 3 / 4) + { + return min_int(mfs_aligned, (max_frag_size - ((max_frag_size - mod) / (div + 1)) + + FRAG_SIZE_ROUND_MASK) & ~FRAG_SIZE_ROUND_MASK); + } + else + { + return mfs_aligned; + } } /* process an outgoing datagram, possibly breaking it up into fragments */ void -fragment_outgoing (struct fragment_master *f, struct buffer *buf, - const struct frame* frame) +fragment_outgoing(struct fragment_master *f, struct buffer *buf, + const struct frame *frame) { - const char *errmsg = NULL; - if (buf->len > 0) + const char *errmsg = NULL; + if (buf->len > 0) { - /* The outgoing buffer should be empty so we can put new data in it */ - if (f->outgoing.len) - msg (D_FRAG_ERRORS, "FRAG: outgoing buffer is not empty, len=[%d,%d]", - buf->len, f->outgoing.len); - if (buf->len > PAYLOAD_SIZE_DYNAMIC(frame)) /* should we fragment? */ - { - /* - * Send the datagram as a series of 2 or more fragments. - */ - f->outgoing_frag_size = optimal_fragment_size (buf->len, PAYLOAD_SIZE_DYNAMIC(frame)); - if (buf->len > f->outgoing_frag_size * MAX_FRAGS) - FRAG_ERR ("too many fragments would be required to send datagram"); - ASSERT (buf_init (&f->outgoing, FRAME_HEADROOM (frame))); - ASSERT (buf_copy (&f->outgoing, buf)); - f->outgoing_seq_id = modulo_add (f->outgoing_seq_id, 1, N_SEQ_ID); - f->outgoing_frag_id = 0; - buf->len = 0; - ASSERT (fragment_ready_to_send (f, buf, frame)); - } - else - { - /* - * Send the datagram whole. - */ - fragment_prepend_flags (buf, - FRAG_WHOLE, - 0, - 0, - 0); - } + /* The outgoing buffer should be empty so we can put new data in it */ + if (f->outgoing.len) + { + msg(D_FRAG_ERRORS, "FRAG: outgoing buffer is not empty, len=[%d,%d]", + buf->len, f->outgoing.len); + } + if (buf->len > PAYLOAD_SIZE_DYNAMIC(frame)) /* should we fragment? */ + { + /* + * Send the datagram as a series of 2 or more fragments. + */ + f->outgoing_frag_size = optimal_fragment_size(buf->len, PAYLOAD_SIZE_DYNAMIC(frame)); + if (buf->len > f->outgoing_frag_size * MAX_FRAGS) + { + FRAG_ERR("too many fragments would be required to send datagram"); + } + ASSERT(buf_init(&f->outgoing, FRAME_HEADROOM(frame))); + ASSERT(buf_copy(&f->outgoing, buf)); + f->outgoing_seq_id = modulo_add(f->outgoing_seq_id, 1, N_SEQ_ID); + f->outgoing_frag_id = 0; + buf->len = 0; + ASSERT(fragment_ready_to_send(f, buf, frame)); + } + else + { + /* + * Send the datagram whole. + */ + fragment_prepend_flags(buf, + FRAG_WHOLE, + 0, + 0, + 0); + } } - return; - - error: - if (errmsg) - msg (D_FRAG_ERRORS, "FRAG_OUT error, len=%d frag_size=%d MAX_FRAGS=%d: %s", - buf->len, f->outgoing_frag_size, MAX_FRAGS, errmsg); - buf->len = 0; - return; + return; + +error: + if (errmsg) + { + msg(D_FRAG_ERRORS, "FRAG_OUT error, len=%d frag_size=%d MAX_FRAGS=%d: %s", + buf->len, f->outgoing_frag_size, MAX_FRAGS, errmsg); + } + buf->len = 0; + return; } /* return true (and set buf) if we have an outgoing fragment which is ready to send */ bool -fragment_ready_to_send (struct fragment_master *f, struct buffer *buf, - const struct frame* frame) +fragment_ready_to_send(struct fragment_master *f, struct buffer *buf, + const struct frame *frame) { - if (fragment_outgoing_defined (f)) + if (fragment_outgoing_defined(f)) + { + /* get fragment size, and determine if it is the last fragment */ + int size = f->outgoing_frag_size; + int last = false; + if (f->outgoing.len <= size) + { + size = f->outgoing.len; + last = true; + } + + /* initialize return buffer */ + *buf = f->outgoing_return; + ASSERT(buf_init(buf, FRAME_HEADROOM(frame))); + ASSERT(buf_copy_n(buf, &f->outgoing, size)); + + /* fragment flags differ based on whether or not we are sending the last fragment */ + fragment_prepend_flags(buf, + last ? FRAG_YES_LAST : FRAG_YES_NOTLAST, + f->outgoing_seq_id, + f->outgoing_frag_id++, + f->outgoing_frag_size); + + ASSERT(!last || !f->outgoing.len); /* outgoing buffer length should be zero after last fragment sent */ + + return true; + } + else { - /* get fragment size, and determine if it is the last fragment */ - int size = f->outgoing_frag_size; - int last = false; - if (f->outgoing.len <= size) - { - size = f->outgoing.len; - last = true; - } - - /* initialize return buffer */ - *buf = f->outgoing_return; - ASSERT (buf_init (buf, FRAME_HEADROOM (frame))); - ASSERT (buf_copy_n (buf, &f->outgoing, size)); - - /* fragment flags differ based on whether or not we are sending the last fragment */ - fragment_prepend_flags (buf, - last ? FRAG_YES_LAST : FRAG_YES_NOTLAST, - f->outgoing_seq_id, - f->outgoing_frag_id++, - f->outgoing_frag_size); - - ASSERT (!last || !f->outgoing.len); /* outgoing buffer length should be zero after last fragment sent */ - - return true; + return false; } - else - return false; } static void -fragment_ttl_reap (struct fragment_master *f) +fragment_ttl_reap(struct fragment_master *f) { - int i; - for (i = 0; i < N_FRAG_BUF; ++i) + int i; + for (i = 0; i < N_FRAG_BUF; ++i) { - struct fragment *frag = &f->incoming.fragments[i]; - if (frag->defined && frag->timestamp + FRAG_TTL_SEC <= now) - { - msg (D_FRAG_ERRORS, "FRAG TTL expired i=%d", i); - frag->defined = false; - } + struct fragment *frag = &f->incoming.fragments[i]; + if (frag->defined && frag->timestamp + FRAG_TTL_SEC <= now) + { + msg(D_FRAG_ERRORS, "FRAG TTL expired i=%d", i); + frag->defined = false; + } } } /* called every FRAG_WAKEUP_INTERVAL seconds */ void -fragment_wakeup (struct fragment_master *f, struct frame *frame) +fragment_wakeup(struct fragment_master *f, struct frame *frame) { - /* delete fragments with expired TTLs */ - fragment_ttl_reap (f); + /* delete fragments with expired TTLs */ + fragment_ttl_reap(f); } -#else -static void dummy(void) {} -#endif +#else /* ifdef ENABLE_FRAGMENT */ +static void +dummy(void) { +} +#endif /* ifdef ENABLE_FRAGMENT */ diff --git a/src/openvpn/fragment.h b/src/openvpn/fragment.h index 866573b28f9..407321259e6 100644 --- a/src/openvpn/fragment.h +++ b/src/openvpn/fragment.h @@ -48,43 +48,43 @@ #define N_FRAG_BUF 25 - /**< Number of packet buffers for - * reassembling incoming fragmented - * packets. */ +/**< Number of packet buffers for + * reassembling incoming fragmented + * packets. */ #define FRAG_TTL_SEC 10 - /**< Time-to-live in seconds for a %fragment. */ +/**< Time-to-live in seconds for a %fragment. */ #define FRAG_WAKEUP_INTERVAL 5 - /**< Interval in seconds between calls to - * wakeup code. */ +/**< Interval in seconds between calls to + * wakeup code. */ /**************************************************************************/ /** * Structure for reassembling one incoming fragmented packet. */ struct fragment { - bool defined; /**< Whether reassembly is currently + bool defined; /**< Whether reassembly is currently * taking place in this structure. */ - int max_frag_size; /**< Maximum size of each %fragment. */ + int max_frag_size; /**< Maximum size of each %fragment. */ -# define FRAG_MAP_MASK 0xFFFFFFFF - /**< Mask for reassembly map. */ -# define MAX_FRAGS 32 /**< Maximum number of fragments per packet. */ - unsigned int map; - /**< Reassembly map for recording which - * fragments have been received. - * - * A bit array where each bit - * corresponds to a %fragment. A 1 bit - * in element n means that the %fragment - * n has been received. Needs to have - * at least \c MAX_FRAGS bits. */ +#define FRAG_MAP_MASK 0xFFFFFFFF + /**< Mask for reassembly map. */ +#define MAX_FRAGS 32 /**< Maximum number of fragments per packet. */ + unsigned int map; + /**< Reassembly map for recording which + * fragments have been received. + * + * A bit array where each bit + * corresponds to a %fragment. A 1 bit + * in element n means that the %fragment + * n has been received. Needs to have + * at least \c MAX_FRAGS bits. */ - time_t timestamp; /**< Timestamp for time-to-live purposes. */ + time_t timestamp; /**< Timestamp for time-to-live purposes. */ - struct buffer buf; /**< Buffer in which received datagrams + struct buffer buf; /**< Buffer in which received datagrams * are reassembled. */ }; @@ -94,10 +94,10 @@ struct fragment { * concurrently. */ struct fragment_list { - int seq_id; /**< Highest fragmentation sequence ID of + int seq_id; /**< Highest fragmentation sequence ID of * the packets currently being * reassembled. */ - int index; /**< Index of the packet being reassembled + int index; /**< Index of the packet being reassembled * with the highest fragmentation * sequence ID into the \c * fragment_list.fragments array. */ @@ -112,7 +112,7 @@ struct fragment_list { * fragmentation sequence IDs in the range \c fragment_list.seq_id \c - * \c N_FRAG_BUF \c + \c 1 to \c fragment_list.seq_id, inclusive. */ - struct fragment fragments[N_FRAG_BUF]; + struct fragment fragments[N_FRAG_BUF]; }; @@ -135,16 +135,16 @@ struct fragment_list { * and returns the whole packets once reassembly is complete. */ struct fragment_master { - struct event_timeout wakeup; /**< Timeout structure used by the main - * event loop to know when to do - * fragmentation housekeeping. */ - bool received_os_mtu_hint; /**< Whether the operating system has + struct event_timeout wakeup; /**< Timeout structure used by the main + * event loop to know when to do + * fragmentation housekeeping. */ + bool received_os_mtu_hint; /**< Whether the operating system has * explicitly recommended an MTU value. */ -# define N_SEQ_ID 256 - /**< One more than the maximum fragment - * sequence ID, above which the IDs wrap - * to zero. Should be a power of 2. */ - int outgoing_seq_id; /**< Fragment sequence ID of the current +#define N_SEQ_ID 256 + /**< One more than the maximum fragment + * sequence ID, above which the IDs wrap + * to zero. Should be a power of 2. */ + int outgoing_seq_id; /**< Fragment sequence ID of the current * fragmented packet waiting to be sent. * * All parts of a fragmented packet @@ -152,10 +152,10 @@ struct fragment_master { * the remote OpenVPN peer can determine * which parts belong to which original * packet. */ -# define MAX_FRAG_PKT_SIZE 65536 - /**< (Not used) Maximum packet size before - * fragmenting. */ - int outgoing_frag_size; /**< Size in bytes of each part to be +#define MAX_FRAG_PKT_SIZE 65536 + /**< (Not used) Maximum packet size before + * fragmenting. */ + int outgoing_frag_size; /**< Size in bytes of each part to be * sent, except for the last part which * may be smaller. * @@ -167,19 +167,19 @@ struct fragment_master { * FRAG_YES_LAST) using the \c * FRAG_SIZE_MASK and \c FRAG_SIZE_SHIFT * bits. */ - int outgoing_frag_id; /**< The fragment ID of the next part to + int outgoing_frag_id; /**< The fragment ID of the next part to * be sent. Must have a value between 0 * and \c MAX_FRAGS-1. */ - struct buffer outgoing; /**< Buffer containing the remaining parts + struct buffer outgoing; /**< Buffer containing the remaining parts * of the fragmented packet being sent. */ - struct buffer outgoing_return; - /**< Buffer used by \c - * fragment_ready_to_send() to return a - * part to send. */ - - struct fragment_list incoming; - /**< List of structures for reassembling - * incoming packets. */ + struct buffer outgoing_return; + /**< Buffer used by \c + * fragment_ready_to_send() to return a + * part to send. */ + + struct fragment_list incoming; + /**< List of structures for reassembling + * incoming packets. */ }; @@ -189,19 +189,19 @@ struct fragment_master { *//** @{ *//*************************************/ typedef uint32_t fragment_header_type; - /**< Fragmentation information is stored in - * a 32-bit packet header. */ +/**< Fragmentation information is stored in + * a 32-bit packet header. */ #define hton_fragment_header_type(x) htonl(x) - /**< Convert a fragment_header_type from - * host to network order. */ +/**< Convert a fragment_header_type from + * host to network order. */ #define ntoh_fragment_header_type(x) ntohl(x) - /**< Convert a \c fragment_header_type - * from network to host order. */ +/**< Convert a \c fragment_header_type + * from network to host order. */ #define FRAG_TYPE_MASK 0x00000003 - /**< Bit mask for %fragment type info. */ +/**< Bit mask for %fragment type info. */ #define FRAG_TYPE_SHIFT 0 /**< Bit shift for %fragment type info. */ #define FRAG_WHOLE 0 /**< Fragment type indicating packet is @@ -218,13 +218,13 @@ typedef uint32_t fragment_header_type; * size. */ #define FRAG_SEQ_ID_MASK 0x000000ff - /**< Bit mask for %fragment sequence ID. */ +/**< Bit mask for %fragment sequence ID. */ #define FRAG_SEQ_ID_SHIFT 2 /**< Bit shift for %fragment sequence ID. */ #define FRAG_ID_MASK 0x0000001f - /**< Bit mask for %fragment ID. */ +/**< Bit mask for %fragment ID. */ #define FRAG_ID_SHIFT 10 - /**< Bit shift for %fragment ID. */ +/**< Bit shift for %fragment ID. */ /* * FRAG_SIZE 14 bits @@ -236,12 +236,12 @@ typedef uint32_t fragment_header_type; * to be the actual %fragment size received. */ #define FRAG_SIZE_MASK 0x00003fff - /**< Bit mask for %fragment size. */ +/**< Bit mask for %fragment size. */ #define FRAG_SIZE_SHIFT 15 - /**< Bit shift for %fragment size. */ +/**< Bit shift for %fragment size. */ #define FRAG_SIZE_ROUND_SHIFT 2 /**< Bit shift for %fragment size rounding. */ #define FRAG_SIZE_ROUND_MASK ((1 << FRAG_SIZE_ROUND_SHIFT) - 1) - /**< Bit mask for %fragment size rounding. */ +/**< Bit mask for %fragment size rounding. */ /* * FRAG_EXTRA 16 bits @@ -249,9 +249,9 @@ typedef uint32_t fragment_header_type; * IF FRAG_WHOLE or FRAG_YES_NOTLAST, these 16 bits are available (not currently used) */ #define FRAG_EXTRA_MASK 0x0000ffff - /**< Bit mask for extra bits. */ +/**< Bit mask for extra bits. */ #define FRAG_EXTRA_SHIFT 15 - /**< Bit shift for extra bits. */ +/**< Bit shift for extra bits. */ /** @} name Fragment header *//********************************************/ @@ -271,7 +271,7 @@ typedef uint32_t fragment_header_type; * * @return A pointer to the new \c fragment_master structure. */ -struct fragment_master *fragment_init (struct frame *frame); +struct fragment_master *fragment_init(struct frame *frame); /** @@ -283,7 +283,7 @@ struct fragment_master *fragment_init (struct frame *frame); * tunnel, used to determine how much memory to * allocate for each packet buffer. */ -void fragment_frame_init (struct fragment_master *f, const struct frame *frame); +void fragment_frame_init(struct fragment_master *f, const struct frame *frame); /** @@ -291,7 +291,7 @@ void fragment_frame_init (struct fragment_master *f, const struct frame *frame); * * @param f - The \c fragment_master structure to free. */ -void fragment_free (struct fragment_master *f); +void fragment_free(struct fragment_master *f); /** @} name Functions for initialization and cleanup *//*******************/ @@ -340,8 +340,8 @@ void fragment_free (struct fragment_master *f); * complete. If an error occurs during processing, the buffer length * is also set to zero. */ -void fragment_incoming (struct fragment_master *f, struct buffer *buf, - const struct frame* frame); +void fragment_incoming(struct fragment_master *f, struct buffer *buf, + const struct frame *frame); /** @} name Functions for processing packets received from a VPN tunnel */ @@ -391,8 +391,8 @@ void fragment_incoming (struct fragment_master *f, struct buffer *buf, * cases a fragmentation header will have been prepended to inform the * remote peer how to handle the packet. */ -void fragment_outgoing (struct fragment_master *f, struct buffer *buf, - const struct frame* frame); +void fragment_outgoing(struct fragment_master *f, struct buffer *buf, + const struct frame *frame); /** * Check whether outgoing fragments are ready to be send, and if so make @@ -421,8 +421,8 @@ void fragment_outgoing (struct fragment_master *f, struct buffer *buf, * @li False, if there are no outgoing fragmented parts waiting to be * sent. */ -bool fragment_ready_to_send (struct fragment_master *f, struct buffer *buf, - const struct frame* frame); +bool fragment_ready_to_send(struct fragment_master *f, struct buffer *buf, + const struct frame *frame); /** * Check whether a \c fragment_master structure contains fragments ready @@ -436,15 +436,15 @@ bool fragment_ready_to_send (struct fragment_master *f, struct buffer *buf, * @li False, otherwise. */ static inline bool -fragment_outgoing_defined (struct fragment_master *f) +fragment_outgoing_defined(struct fragment_master *f) { - return f->outgoing.len > 0; + return f->outgoing.len > 0; } /** @} name Functions for processing packets going out through a VPN tunnel */ -void fragment_wakeup (struct fragment_master *f, struct frame *frame); +void fragment_wakeup(struct fragment_master *f, struct frame *frame); /**************************************************************************/ @@ -463,10 +463,12 @@ void fragment_wakeup (struct fragment_master *f, struct frame *frame); * tunnel. */ static inline void -fragment_housekeeping (struct fragment_master *f, struct frame *frame, struct timeval *tv) +fragment_housekeeping(struct fragment_master *f, struct frame *frame, struct timeval *tv) { - if (event_timeout_trigger (&f->wakeup, tv, ETT_DEFAULT)) - fragment_wakeup (f, frame); + if (event_timeout_trigger(&f->wakeup, tv, ETT_DEFAULT)) + { + fragment_wakeup(f, frame); + } } /** @} name Functions for regular housekeeping *//*************************/ @@ -475,5 +477,5 @@ fragment_housekeeping (struct fragment_master *f, struct frame *frame, struct ti /** @} addtogroup fragmentation *//****************************************/ -#endif -#endif +#endif /* ifdef ENABLE_FRAGMENT */ +#endif /* ifndef FRAGMENT_H */ diff --git a/src/openvpn/gremlin.c b/src/openvpn/gremlin.c index f0aa7f619c2..e8b10a7e141 100644 --- a/src/openvpn/gremlin.c +++ b/src/openvpn/gremlin.c @@ -82,32 +82,34 @@ static const int down_high[] = { 10, 60, 120 }; * { number of packets, packet size } */ static const struct packet_flood_parms packet_flood_data[] = - {{10, 100}, {10, 1500}, {100, 1500}}; +{{10, 100}, {10, 1500}, {100, 1500}}; struct packet_flood_parms -get_packet_flood_parms (int level) +get_packet_flood_parms(int level) { - ASSERT (level > 0 && level < 4); - return packet_flood_data [level - 1]; + ASSERT(level > 0 && level < 4); + return packet_flood_data [level - 1]; } /* * Return true with probability 1/n */ -static bool flip(int n) { - return (get_random() % n) == 0; +static bool +flip(int n) { + return (get_random() % n) == 0; } /* * Return uniformly distributed random number between * low and high. */ -static int roll(int low, int high) { - int ret; - ASSERT (low <= high); - ret = low + (get_random() % (high - low + 1)); - ASSERT (ret >= low && ret <= high); - return ret; +static int +roll(int low, int high) { + int ret; + ASSERT(low <= high); + ret = low + (get_random() % (high - low + 1)); + ASSERT(ret >= low && ret <= high); + return ret; } static bool initialized; /* GLOBAL */ @@ -118,104 +120,118 @@ static time_t next; /* GLOBAL */ * Return false if we should drop a packet. */ bool -ask_gremlin (int flags) +ask_gremlin(int flags) { - const int up_down_level = GREMLIN_UP_DOWN_LEVEL (flags); - const int drop_level = GREMLIN_DROP_LEVEL (flags); + const int up_down_level = GREMLIN_UP_DOWN_LEVEL(flags); + const int drop_level = GREMLIN_DROP_LEVEL(flags); - if (!initialized) + if (!initialized) { - initialized = true; - - if (up_down_level) - up = false; - else - up = true; - - next = now; + initialized = true; + + if (up_down_level) + { + up = false; + } + else + { + up = true; + } + + next = now; } - if (up_down_level) /* change up/down state? */ + if (up_down_level) /* change up/down state? */ { - if (now >= next) - { - int delta; - if (up) - { - delta = roll (down_low[up_down_level-1], down_high[up_down_level-1]); - up = false; - } - else - { - delta = roll (up_low[up_down_level-1], up_high[up_down_level-1]); - up = true; - } - - msg (D_GREMLIN, - "GREMLIN: CONNECTION GOING %s FOR %d SECONDS", - (up ? "UP" : "DOWN"), - delta); - next = now + delta; - } + if (now >= next) + { + int delta; + if (up) + { + delta = roll(down_low[up_down_level-1], down_high[up_down_level-1]); + up = false; + } + else + { + delta = roll(up_low[up_down_level-1], up_high[up_down_level-1]); + up = true; + } + + msg(D_GREMLIN, + "GREMLIN: CONNECTION GOING %s FOR %d SECONDS", + (up ? "UP" : "DOWN"), + delta); + next = now + delta; + } } - if (drop_level) + if (drop_level) { - if (up && flip (drop_freq[drop_level-1])) - { - dmsg (D_GREMLIN_VERBOSE, "GREMLIN: Random packet drop"); - return false; - } + if (up && flip(drop_freq[drop_level-1])) + { + dmsg(D_GREMLIN_VERBOSE, "GREMLIN: Random packet drop"); + return false; + } } - return up; + return up; } /* * Possibly corrupt a packet. */ -void corrupt_gremlin (struct buffer *buf, int flags) { - const int corrupt_level = GREMLIN_CORRUPT_LEVEL (flags); - if (corrupt_level) +void +corrupt_gremlin(struct buffer *buf, int flags) { + const int corrupt_level = GREMLIN_CORRUPT_LEVEL(flags); + if (corrupt_level) { - if (flip (corrupt_freq[corrupt_level-1])) - { - do - { - if (buf->len > 0) - { - uint8_t r = roll (0, 255); - int method = roll (0, 5); - - switch (method) { - case 0: /* corrupt the first byte */ - *BPTR (buf) = r; - break; - case 1: /* corrupt the last byte */ - *(BPTR (buf) + buf->len - 1) = r; - break; - case 2: /* corrupt a random byte */ - *(BPTR(buf) + roll (0, buf->len - 1)) = r; - break; - case 3: /* append a random byte */ - buf_write (buf, &r, 1); - break; - case 4: /* reduce length by 1 */ - --buf->len; - break; - case 5: /* reduce length by a random amount */ - buf->len -= roll (0, buf->len - 1); - break; - } - dmsg (D_GREMLIN_VERBOSE, "GREMLIN: Packet Corruption, method=%d", method); - } - else - break; - } while (flip (2)); /* a 50% chance we will corrupt again */ - } + if (flip(corrupt_freq[corrupt_level-1])) + { + do + { + if (buf->len > 0) + { + uint8_t r = roll(0, 255); + int method = roll(0, 5); + + switch (method) { + case 0: /* corrupt the first byte */ + *BPTR(buf) = r; + break; + + case 1: /* corrupt the last byte */ + *(BPTR(buf) + buf->len - 1) = r; + break; + + case 2: /* corrupt a random byte */ + *(BPTR(buf) + roll(0, buf->len - 1)) = r; + break; + + case 3: /* append a random byte */ + buf_write(buf, &r, 1); + break; + + case 4: /* reduce length by 1 */ + --buf->len; + break; + + case 5: /* reduce length by a random amount */ + buf->len -= roll(0, buf->len - 1); + break; + } + dmsg(D_GREMLIN_VERBOSE, "GREMLIN: Packet Corruption, method=%d", method); + } + else + { + break; + } + } while (flip(2)); /* a 50% chance we will corrupt again */ + } } } -#else -static void dummy(void) {} -#endif +#else /* ifdef ENABLE_DEBUG */ +static void +dummy(void) { +} +#endif /* ifdef ENABLE_DEBUG */ diff --git a/src/openvpn/gremlin.h b/src/openvpn/gremlin.h index c0aeab18394..c60048cfdee 100644 --- a/src/openvpn/gremlin.h +++ b/src/openvpn/gremlin.h @@ -60,13 +60,15 @@ struct packet_flood_parms { - int n_packets; - int packet_size; + int n_packets; + int packet_size; }; -bool ask_gremlin (int flags); -void corrupt_gremlin (struct buffer* buf, int flags); -struct packet_flood_parms get_packet_flood_parms (int level); +bool ask_gremlin(int flags); -#endif -#endif +void corrupt_gremlin(struct buffer *buf, int flags); + +struct packet_flood_parms get_packet_flood_parms(int level); + +#endif /* ifdef ENABLE_DEBUG */ +#endif /* ifndef GREMLIN_H */ diff --git a/src/openvpn/helper.c b/src/openvpn/helper.c index 319c71634f4..1fc4c861863 100644 --- a/src/openvpn/helper.c +++ b/src/openvpn/helper.c @@ -40,101 +40,107 @@ #if P2MP_SERVER static const char * -print_netmask (int netbits, struct gc_arena *gc) +print_netmask(int netbits, struct gc_arena *gc) { - struct buffer out = alloc_buf_gc (128, gc); - const in_addr_t netmask = netbits_to_netmask (netbits); + struct buffer out = alloc_buf_gc(128, gc); + const in_addr_t netmask = netbits_to_netmask(netbits); - buf_printf (&out, "%s (/%d)", print_in_addr_t (netmask, 0, gc), netbits); + buf_printf(&out, "%s (/%d)", print_in_addr_t(netmask, 0, gc), netbits); - return BSTR (&out); + return BSTR(&out); } static const char * -print_opt_route_gateway (const in_addr_t route_gateway, struct gc_arena *gc) +print_opt_route_gateway(const in_addr_t route_gateway, struct gc_arena *gc) { - struct buffer out = alloc_buf_gc (128, gc); - ASSERT (route_gateway); - buf_printf (&out, "route-gateway %s", print_in_addr_t (route_gateway, 0, gc)); - return BSTR (&out); + struct buffer out = alloc_buf_gc(128, gc); + ASSERT(route_gateway); + buf_printf(&out, "route-gateway %s", print_in_addr_t(route_gateway, 0, gc)); + return BSTR(&out); } static const char * -print_opt_route_gateway_dhcp (struct gc_arena *gc) +print_opt_route_gateway_dhcp(struct gc_arena *gc) { - struct buffer out = alloc_buf_gc (32, gc); - buf_printf (&out, "route-gateway dhcp"); - return BSTR (&out); + struct buffer out = alloc_buf_gc(32, gc); + buf_printf(&out, "route-gateway dhcp"); + return BSTR(&out); } static const char * -print_opt_route (const in_addr_t network, const in_addr_t netmask, struct gc_arena *gc) +print_opt_route(const in_addr_t network, const in_addr_t netmask, struct gc_arena *gc) { - struct buffer out = alloc_buf_gc (128, gc); - ASSERT (network); - - if (netmask) - buf_printf (&out, "route %s %s", - print_in_addr_t (network, 0, gc), - print_in_addr_t (netmask, 0, gc)); - else - buf_printf (&out, "route %s", - print_in_addr_t (network, 0, gc)); - - return BSTR (&out); + struct buffer out = alloc_buf_gc(128, gc); + ASSERT(network); + + if (netmask) + { + buf_printf(&out, "route %s %s", + print_in_addr_t(network, 0, gc), + print_in_addr_t(netmask, 0, gc)); + } + else + { + buf_printf(&out, "route %s", + print_in_addr_t(network, 0, gc)); + } + + return BSTR(&out); } static const char * -print_opt_topology (const int topology, struct gc_arena *gc) +print_opt_topology(const int topology, struct gc_arena *gc) { - struct buffer out = alloc_buf_gc (128, gc); + struct buffer out = alloc_buf_gc(128, gc); - buf_printf (&out, "topology %s", print_topology (topology)); + buf_printf(&out, "topology %s", print_topology(topology)); - return BSTR (&out); + return BSTR(&out); } static const char * -print_str_int (const char *str, const int i, struct gc_arena *gc) +print_str_int(const char *str, const int i, struct gc_arena *gc) { - struct buffer out = alloc_buf_gc (128, gc); - buf_printf (&out, "%s %d", str, i); - return BSTR (&out); + struct buffer out = alloc_buf_gc(128, gc); + buf_printf(&out, "%s %d", str, i); + return BSTR(&out); } static const char * -print_str (const char *str, struct gc_arena *gc) +print_str(const char *str, struct gc_arena *gc) { - struct buffer out = alloc_buf_gc (128, gc); - buf_printf (&out, "%s", str); - return BSTR (&out); + struct buffer out = alloc_buf_gc(128, gc); + buf_printf(&out, "%s", str); + return BSTR(&out); } static void -helper_add_route (const in_addr_t network, const in_addr_t netmask, struct options *o) +helper_add_route(const in_addr_t network, const in_addr_t netmask, struct options *o) { - rol_check_alloc (o); - add_route_to_option_list (o->routes, - print_in_addr_t (network, 0, &o->gc), - print_in_addr_t (netmask, 0, &o->gc), - NULL, - NULL); + rol_check_alloc(o); + add_route_to_option_list(o->routes, + print_in_addr_t(network, 0, &o->gc), + print_in_addr_t(netmask, 0, &o->gc), + NULL, + NULL); } static void -verify_common_subnet (const char *opt, const in_addr_t a, const in_addr_t b, const in_addr_t subnet) +verify_common_subnet(const char *opt, const in_addr_t a, const in_addr_t b, const in_addr_t subnet) { - struct gc_arena gc = gc_new (); - if ((a & subnet) != (b & subnet)) - msg (M_USAGE, "%s IP addresses %s and %s are not in the same %s subnet", - opt, - print_in_addr_t (a, 0, &gc), - print_in_addr_t (b, 0, &gc), - print_in_addr_t (subnet, 0, &gc)); - gc_free (&gc); + struct gc_arena gc = gc_new(); + if ((a & subnet) != (b & subnet)) + { + msg(M_USAGE, "%s IP addresses %s and %s are not in the same %s subnet", + opt, + print_in_addr_t(a, 0, &gc), + print_in_addr_t(b, 0, &gc), + print_in_addr_t(subnet, 0, &gc)); + } + gc_free(&gc); } -#endif +#endif /* if P2MP_SERVER */ /* * Process server, server-bridge, and client helper @@ -142,309 +148,349 @@ verify_common_subnet (const char *opt, const in_addr_t a, const in_addr_t b, con * parsed and placed in struct options. */ void -helper_client_server (struct options *o) +helper_client_server(struct options *o) { - struct gc_arena gc = gc_new (); + struct gc_arena gc = gc_new(); #if P2MP #if P2MP_SERVER /* - * Get tun/tap/null device type - */ - const int dev = dev_type_enum (o->dev, o->dev_type); - const int topology = o->topology; - - /* - * - * HELPER DIRECTIVE for IPv6 - * - * server-ipv6 2001:db8::/64 - * - * EXPANDS TO: - * - * tun-ipv6 - * push "tun-ipv6" - * ifconfig-ipv6 2001:db8::1 2001:db8::2 - * if !nopool: - * ifconfig-ipv6-pool 2001:db8::1000/64 - * - */ - if ( o->server_ipv6_defined ) - { - if ( ! o->server_defined ) - { - msg (M_USAGE, "--server-ipv6 must be used together with --server"); - } - if ( o->server_flags & SF_NOPOOL ) - { - msg( M_USAGE, "--server-ipv6 is incompatible with 'nopool' option" ); - } - if ( o->ifconfig_ipv6_pool_defined ) - { - msg( M_USAGE, "--server-ipv6 already defines an ifconfig-ipv6-pool, so you can't also specify --ifconfig-pool explicitly"); - } + * Get tun/tap/null device type + */ + const int dev = dev_type_enum(o->dev, o->dev_type); + const int topology = o->topology; + + /* + * + * HELPER DIRECTIVE for IPv6 + * + * server-ipv6 2001:db8::/64 + * + * EXPANDS TO: + * + * tun-ipv6 + * push "tun-ipv6" + * ifconfig-ipv6 2001:db8::1 2001:db8::2 + * if !nopool: + * ifconfig-ipv6-pool 2001:db8::1000/64 + * + */ + if (o->server_ipv6_defined) + { + if (!o->server_defined) + { + msg(M_USAGE, "--server-ipv6 must be used together with --server"); + } + if (o->server_flags & SF_NOPOOL) + { + msg( M_USAGE, "--server-ipv6 is incompatible with 'nopool' option" ); + } + if (o->ifconfig_ipv6_pool_defined) + { + msg( M_USAGE, "--server-ipv6 already defines an ifconfig-ipv6-pool, so you can't also specify --ifconfig-pool explicitly"); + } /* local ifconfig is "base address + 1" and "+2" */ - o->ifconfig_ipv6_local = - print_in6_addr( add_in6_addr( o->server_network_ipv6, 1), 0, &o->gc ); - o->ifconfig_ipv6_remote = - print_in6_addr( add_in6_addr( o->server_network_ipv6, 2), 0, &o->gc ); - o->ifconfig_ipv6_netbits = o->server_netbits_ipv6; - - /* pool starts at "base address + 0x1000" - leave enough room */ - ASSERT( o->server_netbits_ipv6 <= 112 ); /* want 16 bits */ - - o->ifconfig_ipv6_pool_defined = true; - o->ifconfig_ipv6_pool_base = - add_in6_addr( o->server_network_ipv6, 0x1000 ); - o->ifconfig_ipv6_pool_netbits = o->server_netbits_ipv6; - - push_option( o, "tun-ipv6", M_USAGE ); - } - - /* - * - * HELPER DIRECTIVE: - * - * server 10.8.0.0 255.255.255.0 - * - * EXPANDS TO: - * - * mode server - * tls-server - * push "topology [topology]" - * - * if tun AND (topology == net30 OR topology == p2p): - * ifconfig 10.8.0.1 10.8.0.2 - * if !nopool: - * ifconfig-pool 10.8.0.4 10.8.0.251 - * route 10.8.0.0 255.255.255.0 - * if client-to-client: - * push "route 10.8.0.0 255.255.255.0" - * else if topology == net30: - * push "route 10.8.0.1" - * - * if tap OR (tun AND topology == subnet): - * ifconfig 10.8.0.1 255.255.255.0 - * if !nopool: - * ifconfig-pool 10.8.0.2 10.8.0.253 255.255.255.0 - * push "route-gateway 10.8.0.1" - * if route-gateway unset: - * route-gateway 10.8.0.2 - */ - - if (o->server_defined) + o->ifconfig_ipv6_local = + print_in6_addr( add_in6_addr( o->server_network_ipv6, 1), 0, &o->gc ); + o->ifconfig_ipv6_remote = + print_in6_addr( add_in6_addr( o->server_network_ipv6, 2), 0, &o->gc ); + o->ifconfig_ipv6_netbits = o->server_netbits_ipv6; + + /* pool starts at "base address + 0x1000" - leave enough room */ + ASSERT( o->server_netbits_ipv6 <= 112 ); /* want 16 bits */ + + o->ifconfig_ipv6_pool_defined = true; + o->ifconfig_ipv6_pool_base = + add_in6_addr( o->server_network_ipv6, 0x1000 ); + o->ifconfig_ipv6_pool_netbits = o->server_netbits_ipv6; + + push_option( o, "tun-ipv6", M_USAGE ); + } + + /* + * + * HELPER DIRECTIVE: + * + * server 10.8.0.0 255.255.255.0 + * + * EXPANDS TO: + * + * mode server + * tls-server + * push "topology [topology]" + * + * if tun AND (topology == net30 OR topology == p2p): + * ifconfig 10.8.0.1 10.8.0.2 + * if !nopool: + * ifconfig-pool 10.8.0.4 10.8.0.251 + * route 10.8.0.0 255.255.255.0 + * if client-to-client: + * push "route 10.8.0.0 255.255.255.0" + * else if topology == net30: + * push "route 10.8.0.1" + * + * if tap OR (tun AND topology == subnet): + * ifconfig 10.8.0.1 255.255.255.0 + * if !nopool: + * ifconfig-pool 10.8.0.2 10.8.0.253 255.255.255.0 + * push "route-gateway 10.8.0.1" + * if route-gateway unset: + * route-gateway 10.8.0.2 + */ + + if (o->server_defined) { - int netbits = -2; - bool status = false; - - if (o->client) - msg (M_USAGE, "--server and --client cannot be used together"); - - if (o->server_bridge_defined || o->server_bridge_proxy_dhcp) - msg (M_USAGE, "--server and --server-bridge cannot be used together"); - - if (o->shared_secret_file) - msg (M_USAGE, "--server and --secret cannot be used together (you must use SSL/TLS keys)"); - - if (!(o->server_flags & SF_NOPOOL) && o->ifconfig_pool_defined) - msg (M_USAGE, "--server already defines an ifconfig-pool, so you can't also specify --ifconfig-pool explicitly"); - - if (!(dev == DEV_TYPE_TAP || dev == DEV_TYPE_TUN)) - msg (M_USAGE, "--server directive only makes sense with --dev tun or --dev tap"); - - status = netmask_to_netbits (o->server_network, o->server_netmask, &netbits); - if (!status) - msg (M_USAGE, "--server directive network/netmask combination is invalid"); - - if (netbits < 0) - msg (M_USAGE, "--server directive netmask is invalid"); - - if (netbits < IFCONFIG_POOL_MIN_NETBITS) - msg (M_USAGE, "--server directive netmask allows for too many host addresses (subnet must be %s or higher)", - print_netmask (IFCONFIG_POOL_MIN_NETBITS, &gc)); - - if (dev == DEV_TYPE_TUN) - { - int pool_end_reserve = 4; - - if (netbits > 29) - msg (M_USAGE, "--server directive when used with --dev tun must define a subnet of %s or lower", - print_netmask (29, &gc)); - - if (netbits == 29) - pool_end_reserve = 0; - - o->mode = MODE_SERVER; - o->tls_server = true; - - if (topology == TOP_NET30 || topology == TOP_P2P) - { - o->ifconfig_local = print_in_addr_t (o->server_network + 1, 0, &o->gc); - o->ifconfig_remote_netmask = print_in_addr_t (o->server_network + 2, 0, &o->gc); - - if (!(o->server_flags & SF_NOPOOL)) - { - o->ifconfig_pool_defined = true; - o->ifconfig_pool_start = o->server_network + 4; - o->ifconfig_pool_end = (o->server_network | ~o->server_netmask) - pool_end_reserve; - ifconfig_pool_verify_range (M_USAGE, o->ifconfig_pool_start, o->ifconfig_pool_end); - } - - helper_add_route (o->server_network, o->server_netmask, o); - if (o->enable_c2c) - push_option (o, print_opt_route (o->server_network, o->server_netmask, &o->gc), M_USAGE); - else if (topology == TOP_NET30) - push_option (o, print_opt_route (o->server_network + 1, 0, &o->gc), M_USAGE); - } - else if (topology == TOP_SUBNET) - { - o->ifconfig_local = print_in_addr_t (o->server_network + 1, 0, &o->gc); - o->ifconfig_remote_netmask = print_in_addr_t (o->server_netmask, 0, &o->gc); - - if (!(o->server_flags & SF_NOPOOL)) - { - o->ifconfig_pool_defined = true; - o->ifconfig_pool_start = o->server_network + 2; - o->ifconfig_pool_end = (o->server_network | ~o->server_netmask) - 2; - ifconfig_pool_verify_range (M_USAGE, o->ifconfig_pool_start, o->ifconfig_pool_end); - } - o->ifconfig_pool_netmask = o->server_netmask; - - push_option (o, print_opt_route_gateway (o->server_network + 1, &o->gc), M_USAGE); - if (!o->route_default_gateway) - o->route_default_gateway = print_in_addr_t (o->server_network + 2, 0, &o->gc); - } - else - ASSERT (0); - - push_option (o, print_opt_topology (topology, &o->gc), M_USAGE); - } - else if (dev == DEV_TYPE_TAP) - { - if (netbits > 30) - msg (M_USAGE, "--server directive when used with --dev tap must define a subnet of %s or lower", - print_netmask (30, &gc)); - - o->mode = MODE_SERVER; - o->tls_server = true; - o->ifconfig_local = print_in_addr_t (o->server_network + 1, 0, &o->gc); - o->ifconfig_remote_netmask = print_in_addr_t (o->server_netmask, 0, &o->gc); - - if (!(o->server_flags & SF_NOPOOL)) - { - o->ifconfig_pool_defined = true; - o->ifconfig_pool_start = o->server_network + 2; - o->ifconfig_pool_end = (o->server_network | ~o->server_netmask) - 1; - ifconfig_pool_verify_range (M_USAGE, o->ifconfig_pool_start, o->ifconfig_pool_end); - } - o->ifconfig_pool_netmask = o->server_netmask; - - push_option (o, print_opt_route_gateway (o->server_network + 1, &o->gc), M_USAGE); - } - else - { - ASSERT (0); - } - - /* set push-ifconfig-constraint directive */ - if ((dev == DEV_TYPE_TAP || topology == TOP_SUBNET)) - { - o->push_ifconfig_constraint_defined = true; - o->push_ifconfig_constraint_network = o->server_network; - o->push_ifconfig_constraint_netmask = o->server_netmask; - } + int netbits = -2; + bool status = false; + + if (o->client) + { + msg(M_USAGE, "--server and --client cannot be used together"); + } + + if (o->server_bridge_defined || o->server_bridge_proxy_dhcp) + { + msg(M_USAGE, "--server and --server-bridge cannot be used together"); + } + + if (o->shared_secret_file) + { + msg(M_USAGE, "--server and --secret cannot be used together (you must use SSL/TLS keys)"); + } + + if (!(o->server_flags & SF_NOPOOL) && o->ifconfig_pool_defined) + { + msg(M_USAGE, "--server already defines an ifconfig-pool, so you can't also specify --ifconfig-pool explicitly"); + } + + if (!(dev == DEV_TYPE_TAP || dev == DEV_TYPE_TUN)) + { + msg(M_USAGE, "--server directive only makes sense with --dev tun or --dev tap"); + } + + status = netmask_to_netbits(o->server_network, o->server_netmask, &netbits); + if (!status) + { + msg(M_USAGE, "--server directive network/netmask combination is invalid"); + } + + if (netbits < 0) + { + msg(M_USAGE, "--server directive netmask is invalid"); + } + + if (netbits < IFCONFIG_POOL_MIN_NETBITS) + { + msg(M_USAGE, "--server directive netmask allows for too many host addresses (subnet must be %s or higher)", + print_netmask(IFCONFIG_POOL_MIN_NETBITS, &gc)); + } + + if (dev == DEV_TYPE_TUN) + { + int pool_end_reserve = 4; + + if (netbits > 29) + { + msg(M_USAGE, "--server directive when used with --dev tun must define a subnet of %s or lower", + print_netmask(29, &gc)); + } + + if (netbits == 29) + { + pool_end_reserve = 0; + } + + o->mode = MODE_SERVER; + o->tls_server = true; + + if (topology == TOP_NET30 || topology == TOP_P2P) + { + o->ifconfig_local = print_in_addr_t(o->server_network + 1, 0, &o->gc); + o->ifconfig_remote_netmask = print_in_addr_t(o->server_network + 2, 0, &o->gc); + + if (!(o->server_flags & SF_NOPOOL)) + { + o->ifconfig_pool_defined = true; + o->ifconfig_pool_start = o->server_network + 4; + o->ifconfig_pool_end = (o->server_network | ~o->server_netmask) - pool_end_reserve; + ifconfig_pool_verify_range(M_USAGE, o->ifconfig_pool_start, o->ifconfig_pool_end); + } + + helper_add_route(o->server_network, o->server_netmask, o); + if (o->enable_c2c) + { + push_option(o, print_opt_route(o->server_network, o->server_netmask, &o->gc), M_USAGE); + } + else if (topology == TOP_NET30) + { + push_option(o, print_opt_route(o->server_network + 1, 0, &o->gc), M_USAGE); + } + } + else if (topology == TOP_SUBNET) + { + o->ifconfig_local = print_in_addr_t(o->server_network + 1, 0, &o->gc); + o->ifconfig_remote_netmask = print_in_addr_t(o->server_netmask, 0, &o->gc); + + if (!(o->server_flags & SF_NOPOOL)) + { + o->ifconfig_pool_defined = true; + o->ifconfig_pool_start = o->server_network + 2; + o->ifconfig_pool_end = (o->server_network | ~o->server_netmask) - 2; + ifconfig_pool_verify_range(M_USAGE, o->ifconfig_pool_start, o->ifconfig_pool_end); + } + o->ifconfig_pool_netmask = o->server_netmask; + + push_option(o, print_opt_route_gateway(o->server_network + 1, &o->gc), M_USAGE); + if (!o->route_default_gateway) + { + o->route_default_gateway = print_in_addr_t(o->server_network + 2, 0, &o->gc); + } + } + else + { + ASSERT(0); + } + + push_option(o, print_opt_topology(topology, &o->gc), M_USAGE); + } + else if (dev == DEV_TYPE_TAP) + { + if (netbits > 30) + { + msg(M_USAGE, "--server directive when used with --dev tap must define a subnet of %s or lower", + print_netmask(30, &gc)); + } + + o->mode = MODE_SERVER; + o->tls_server = true; + o->ifconfig_local = print_in_addr_t(o->server_network + 1, 0, &o->gc); + o->ifconfig_remote_netmask = print_in_addr_t(o->server_netmask, 0, &o->gc); + + if (!(o->server_flags & SF_NOPOOL)) + { + o->ifconfig_pool_defined = true; + o->ifconfig_pool_start = o->server_network + 2; + o->ifconfig_pool_end = (o->server_network | ~o->server_netmask) - 1; + ifconfig_pool_verify_range(M_USAGE, o->ifconfig_pool_start, o->ifconfig_pool_end); + } + o->ifconfig_pool_netmask = o->server_netmask; + + push_option(o, print_opt_route_gateway(o->server_network + 1, &o->gc), M_USAGE); + } + else + { + ASSERT(0); + } + + /* set push-ifconfig-constraint directive */ + if ((dev == DEV_TYPE_TAP || topology == TOP_SUBNET)) + { + o->push_ifconfig_constraint_defined = true; + o->push_ifconfig_constraint_network = o->server_network; + o->push_ifconfig_constraint_netmask = o->server_netmask; + } } - /* - * HELPER DIRECTIVE: - * - * server-bridge 10.8.0.4 255.255.255.0 10.8.0.128 10.8.0.254 - * - * EXPANDS TO: - * - * mode server - * tls-server - * - * ifconfig-pool 10.8.0.128 10.8.0.254 255.255.255.0 - * push "route-gateway 10.8.0.4" - * - * OR - * - * server-bridge - * - * EXPANDS TO: - * - * mode server - * tls-server - * - * if !nogw: - * push "route-gateway dhcp" - */ - else if (o->server_bridge_defined | o->server_bridge_proxy_dhcp) + /* + * HELPER DIRECTIVE: + * + * server-bridge 10.8.0.4 255.255.255.0 10.8.0.128 10.8.0.254 + * + * EXPANDS TO: + * + * mode server + * tls-server + * + * ifconfig-pool 10.8.0.128 10.8.0.254 255.255.255.0 + * push "route-gateway 10.8.0.4" + * + * OR + * + * server-bridge + * + * EXPANDS TO: + * + * mode server + * tls-server + * + * if !nogw: + * push "route-gateway dhcp" + */ + else if (o->server_bridge_defined | o->server_bridge_proxy_dhcp) { - if (o->client) - msg (M_USAGE, "--server-bridge and --client cannot be used together"); - - if (!(o->server_flags & SF_NOPOOL) && o->ifconfig_pool_defined) - msg (M_USAGE, "--server-bridge already defines an ifconfig-pool, so you can't also specify --ifconfig-pool explicitly"); - - if (o->shared_secret_file) - msg (M_USAGE, "--server-bridge and --secret cannot be used together (you must use SSL/TLS keys)"); - - if (dev != DEV_TYPE_TAP) - msg (M_USAGE, "--server-bridge directive only makes sense with --dev tap"); - - if (o->server_bridge_defined) - { - verify_common_subnet ("--server-bridge", o->server_bridge_ip, o->server_bridge_pool_start, o->server_bridge_netmask); - verify_common_subnet ("--server-bridge", o->server_bridge_pool_start, o->server_bridge_pool_end, o->server_bridge_netmask); - verify_common_subnet ("--server-bridge", o->server_bridge_ip, o->server_bridge_pool_end, o->server_bridge_netmask); - } - - o->mode = MODE_SERVER; - o->tls_server = true; - - if (o->server_bridge_defined) - { - o->ifconfig_pool_defined = true; - o->ifconfig_pool_start = o->server_bridge_pool_start; - o->ifconfig_pool_end = o->server_bridge_pool_end; - ifconfig_pool_verify_range (M_USAGE, o->ifconfig_pool_start, o->ifconfig_pool_end); - o->ifconfig_pool_netmask = o->server_bridge_netmask; - push_option (o, print_opt_route_gateway (o->server_bridge_ip, &o->gc), M_USAGE); - } - else if (o->server_bridge_proxy_dhcp && !(o->server_flags & SF_NO_PUSH_ROUTE_GATEWAY)) - { - push_option (o, print_opt_route_gateway_dhcp (&o->gc), M_USAGE); - } + if (o->client) + { + msg(M_USAGE, "--server-bridge and --client cannot be used together"); + } + + if (!(o->server_flags & SF_NOPOOL) && o->ifconfig_pool_defined) + { + msg(M_USAGE, "--server-bridge already defines an ifconfig-pool, so you can't also specify --ifconfig-pool explicitly"); + } + + if (o->shared_secret_file) + { + msg(M_USAGE, "--server-bridge and --secret cannot be used together (you must use SSL/TLS keys)"); + } + + if (dev != DEV_TYPE_TAP) + { + msg(M_USAGE, "--server-bridge directive only makes sense with --dev tap"); + } + + if (o->server_bridge_defined) + { + verify_common_subnet("--server-bridge", o->server_bridge_ip, o->server_bridge_pool_start, o->server_bridge_netmask); + verify_common_subnet("--server-bridge", o->server_bridge_pool_start, o->server_bridge_pool_end, o->server_bridge_netmask); + verify_common_subnet("--server-bridge", o->server_bridge_ip, o->server_bridge_pool_end, o->server_bridge_netmask); + } + + o->mode = MODE_SERVER; + o->tls_server = true; + + if (o->server_bridge_defined) + { + o->ifconfig_pool_defined = true; + o->ifconfig_pool_start = o->server_bridge_pool_start; + o->ifconfig_pool_end = o->server_bridge_pool_end; + ifconfig_pool_verify_range(M_USAGE, o->ifconfig_pool_start, o->ifconfig_pool_end); + o->ifconfig_pool_netmask = o->server_bridge_netmask; + push_option(o, print_opt_route_gateway(o->server_bridge_ip, &o->gc), M_USAGE); + } + else if (o->server_bridge_proxy_dhcp && !(o->server_flags & SF_NO_PUSH_ROUTE_GATEWAY)) + { + push_option(o, print_opt_route_gateway_dhcp(&o->gc), M_USAGE); + } } - else + else #endif /* P2MP_SERVER */ - /* - * HELPER DIRECTIVE: - * - * client - * - * EXPANDS TO: - * - * pull - * tls-client - */ - if (o->client) + /* + * HELPER DIRECTIVE: + * + * client + * + * EXPANDS TO: + * + * pull + * tls-client + */ + if (o->client) { - if (o->key_method != 2) - msg (M_USAGE, "--client requires --key-method 2"); + if (o->key_method != 2) + { + msg(M_USAGE, "--client requires --key-method 2"); + } - o->pull = true; - o->tls_client = true; + o->pull = true; + o->tls_client = true; } #endif /* P2MP */ - gc_free (&gc); + gc_free(&gc); } /* @@ -465,45 +511,51 @@ helper_client_server (struct options *o) * ping-restart 60 */ void -helper_keepalive (struct options *o) +helper_keepalive(struct options *o) { - if (o->keepalive_ping || o->keepalive_timeout) + if (o->keepalive_ping || o->keepalive_timeout) { - /* - * Sanity checks. - */ - if (o->keepalive_ping <= 0 || o->keepalive_timeout <= 0) - msg (M_USAGE, "--keepalive parameters must be > 0"); - if (o->keepalive_ping * 2 > o->keepalive_timeout) - msg (M_USAGE, "the second parameter to --keepalive (restart timeout=%d) must be at least twice the value of the first parameter (ping interval=%d). A ratio of 1:5 or 1:6 would be even better. Recommended setting is --keepalive 10 60.", - o->keepalive_timeout, - o->keepalive_ping); - if (o->ping_send_timeout || o->ping_rec_timeout) - msg (M_USAGE, "--keepalive conflicts with --ping, --ping-exit, or --ping-restart. If you use --keepalive, you don't need any of the other --ping directives."); - - /* - * Expand. - */ - if (o->mode == MODE_POINT_TO_POINT) - { - o->ping_rec_timeout_action = PING_RESTART; - o->ping_send_timeout = o->keepalive_ping; - o->ping_rec_timeout = o->keepalive_timeout; - } + /* + * Sanity checks. + */ + if (o->keepalive_ping <= 0 || o->keepalive_timeout <= 0) + { + msg(M_USAGE, "--keepalive parameters must be > 0"); + } + if (o->keepalive_ping * 2 > o->keepalive_timeout) + { + msg(M_USAGE, "the second parameter to --keepalive (restart timeout=%d) must be at least twice the value of the first parameter (ping interval=%d). A ratio of 1:5 or 1:6 would be even better. Recommended setting is --keepalive 10 60.", + o->keepalive_timeout, + o->keepalive_ping); + } + if (o->ping_send_timeout || o->ping_rec_timeout) + { + msg(M_USAGE, "--keepalive conflicts with --ping, --ping-exit, or --ping-restart. If you use --keepalive, you don't need any of the other --ping directives."); + } + + /* + * Expand. + */ + if (o->mode == MODE_POINT_TO_POINT) + { + o->ping_rec_timeout_action = PING_RESTART; + o->ping_send_timeout = o->keepalive_ping; + o->ping_rec_timeout = o->keepalive_timeout; + } #if P2MP_SERVER - else if (o->mode == MODE_SERVER) - { - o->ping_rec_timeout_action = PING_RESTART; - o->ping_send_timeout = o->keepalive_ping; - o->ping_rec_timeout = o->keepalive_timeout * 2; - push_option (o, print_str_int ("ping", o->keepalive_ping, &o->gc), M_USAGE); - push_option (o, print_str_int ("ping-restart", o->keepalive_timeout, &o->gc), M_USAGE); - } + else if (o->mode == MODE_SERVER) + { + o->ping_rec_timeout_action = PING_RESTART; + o->ping_send_timeout = o->keepalive_ping; + o->ping_rec_timeout = o->keepalive_timeout * 2; + push_option(o, print_str_int("ping", o->keepalive_ping, &o->gc), M_USAGE); + push_option(o, print_str_int("ping-restart", o->keepalive_timeout, &o->gc), M_USAGE); + } #endif - else - { - ASSERT (0); - } + else + { + ASSERT(0); + } } } @@ -520,20 +572,20 @@ helper_keepalive (struct options *o) * push "socket-flags TCP_NODELAY" */ void -helper_tcp_nodelay (struct options *o) +helper_tcp_nodelay(struct options *o) { #if P2MP_SERVER - if (o->server_flags & SF_TCP_NODELAY_HELPER) + if (o->server_flags & SF_TCP_NODELAY_HELPER) { - if (o->mode == MODE_SERVER) - { - o->sockflags |= SF_TCP_NODELAY; - push_option (o, print_str ("socket-flags TCP_NODELAY", &o->gc), M_USAGE); - } - else - { - o->sockflags |= SF_TCP_NODELAY; - } + if (o->mode == MODE_SERVER) + { + o->sockflags |= SF_TCP_NODELAY; + push_option(o, print_str("socket-flags TCP_NODELAY", &o->gc), M_USAGE); + } + else + { + o->sockflags |= SF_TCP_NODELAY; + } } #endif } diff --git a/src/openvpn/helper.h b/src/openvpn/helper.h index 444969c9081..d78c02f7200 100644 --- a/src/openvpn/helper.h +++ b/src/openvpn/helper.h @@ -31,8 +31,10 @@ #include "options.h" -void helper_keepalive (struct options *o); -void helper_client_server (struct options *o); -void helper_tcp_nodelay (struct options *o); +void helper_keepalive(struct options *o); + +void helper_client_server(struct options *o); + +void helper_tcp_nodelay(struct options *o); #endif diff --git a/src/openvpn/httpdigest.c b/src/openvpn/httpdigest.c index 99bbda4675c..c5f0d927474 100644 --- a/src/openvpn/httpdigest.c +++ b/src/openvpn/httpdigest.c @@ -37,118 +37,126 @@ static void CvtHex( - IN HASH Bin, - OUT HASHHEX Hex - ) + IN HASH Bin, + OUT HASHHEX Hex + ) { - unsigned short i; - unsigned char j; + unsigned short i; + unsigned char j; - for (i = 0; i < HASHLEN; i++) { - j = (Bin[i] >> 4) & 0xf; - if (j <= 9) - Hex[i*2] = (j + '0'); - else - Hex[i*2] = (j + 'a' - 10); - j = Bin[i] & 0xf; - if (j <= 9) - Hex[i*2+1] = (j + '0'); - else - Hex[i*2+1] = (j + 'a' - 10); - }; - Hex[HASHHEXLEN] = '\0'; -}; + for (i = 0; i < HASHLEN; i++) { + j = (Bin[i] >> 4) & 0xf; + if (j <= 9) + { + Hex[i*2] = (j + '0'); + } + else + { + Hex[i*2] = (j + 'a' - 10); + } + j = Bin[i] & 0xf; + if (j <= 9) + { + Hex[i*2+1] = (j + '0'); + } + else + { + Hex[i*2+1] = (j + 'a' - 10); + } + } + Hex[HASHHEXLEN] = '\0'; +} /* calculate H(A1) as per spec */ void DigestCalcHA1( - IN char * pszAlg, - IN char * pszUserName, - IN char * pszRealm, - IN char * pszPassword, - IN char * pszNonce, - IN char * pszCNonce, - OUT HASHHEX SessionKey - ) + IN char *pszAlg, + IN char *pszUserName, + IN char *pszRealm, + IN char *pszPassword, + IN char *pszNonce, + IN char *pszCNonce, + OUT HASHHEX SessionKey + ) { - HASH HA1; - md_ctx_t md5_ctx; - const md_kt_t *md5_kt = md_kt_get("MD5"); + HASH HA1; + md_ctx_t md5_ctx; + const md_kt_t *md5_kt = md_kt_get("MD5"); - md_ctx_init(&md5_ctx, md5_kt); - md_ctx_update(&md5_ctx, (const uint8_t *) pszUserName, strlen(pszUserName)); - md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1); - md_ctx_update(&md5_ctx, (const uint8_t *) pszRealm, strlen(pszRealm)); - md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1); - md_ctx_update(&md5_ctx, (const uint8_t *) pszPassword, strlen(pszPassword)); - md_ctx_final(&md5_ctx, HA1); - if (pszAlg && strcasecmp(pszAlg, "md5-sess") == 0) + md_ctx_init(&md5_ctx, md5_kt); + md_ctx_update(&md5_ctx, (const uint8_t *) pszUserName, strlen(pszUserName)); + md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1); + md_ctx_update(&md5_ctx, (const uint8_t *) pszRealm, strlen(pszRealm)); + md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1); + md_ctx_update(&md5_ctx, (const uint8_t *) pszPassword, strlen(pszPassword)); + md_ctx_final(&md5_ctx, HA1); + if (pszAlg && strcasecmp(pszAlg, "md5-sess") == 0) { - md_ctx_init(&md5_ctx, md5_kt); - md_ctx_update(&md5_ctx, HA1, HASHLEN); - md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1); - md_ctx_update(&md5_ctx, (const uint8_t *) pszNonce, strlen(pszNonce)); - md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1); - md_ctx_update(&md5_ctx, (const uint8_t *) pszCNonce, strlen(pszCNonce)); - md_ctx_final(&md5_ctx, HA1); - }; - md_ctx_cleanup(&md5_ctx); - CvtHex(HA1, SessionKey); + md_ctx_init(&md5_ctx, md5_kt); + md_ctx_update(&md5_ctx, HA1, HASHLEN); + md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1); + md_ctx_update(&md5_ctx, (const uint8_t *) pszNonce, strlen(pszNonce)); + md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1); + md_ctx_update(&md5_ctx, (const uint8_t *) pszCNonce, strlen(pszCNonce)); + md_ctx_final(&md5_ctx, HA1); + } + md_ctx_cleanup(&md5_ctx); + CvtHex(HA1, SessionKey); } /* calculate request-digest/response-digest as per HTTP Digest spec */ void DigestCalcResponse( - IN HASHHEX HA1, /* H(A1) */ - IN char * pszNonce, /* nonce from server */ - IN char * pszNonceCount, /* 8 hex digits */ - IN char * pszCNonce, /* client nonce */ - IN char * pszQop, /* qop-value: "", "auth", "auth-int" */ - IN char * pszMethod, /* method from the request */ - IN char * pszDigestUri, /* requested URL */ - IN HASHHEX HEntity, /* H(entity body) if qop="auth-int" */ - OUT HASHHEX Response /* request-digest or response-digest */ - ) + IN HASHHEX HA1, /* H(A1) */ + IN char *pszNonce, /* nonce from server */ + IN char *pszNonceCount, /* 8 hex digits */ + IN char *pszCNonce, /* client nonce */ + IN char *pszQop, /* qop-value: "", "auth", "auth-int" */ + IN char *pszMethod, /* method from the request */ + IN char *pszDigestUri, /* requested URL */ + IN HASHHEX HEntity, /* H(entity body) if qop="auth-int" */ + OUT HASHHEX Response /* request-digest or response-digest */ + ) { - HASH HA2; - HASH RespHash; - HASHHEX HA2Hex; + HASH HA2; + HASH RespHash; + HASHHEX HA2Hex; - md_ctx_t md5_ctx; - const md_kt_t *md5_kt = md_kt_get("MD5"); + md_ctx_t md5_ctx; + const md_kt_t *md5_kt = md_kt_get("MD5"); - /* calculate H(A2) */ - md_ctx_init(&md5_ctx, md5_kt); - md_ctx_update(&md5_ctx, (const uint8_t *) pszMethod, strlen(pszMethod)); - md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1); - md_ctx_update(&md5_ctx, (const uint8_t *) pszDigestUri, strlen(pszDigestUri)); - if (strcasecmp(pszQop, "auth-int") == 0) + /* calculate H(A2) */ + md_ctx_init(&md5_ctx, md5_kt); + md_ctx_update(&md5_ctx, (const uint8_t *) pszMethod, strlen(pszMethod)); + md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1); + md_ctx_update(&md5_ctx, (const uint8_t *) pszDigestUri, strlen(pszDigestUri)); + if (strcasecmp(pszQop, "auth-int") == 0) { - md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1); - md_ctx_update(&md5_ctx, HEntity, HASHHEXLEN); - }; - md_ctx_final(&md5_ctx, HA2); - CvtHex(HA2, HA2Hex); + md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1); + md_ctx_update(&md5_ctx, HEntity, HASHHEXLEN); + } + md_ctx_final(&md5_ctx, HA2); + CvtHex(HA2, HA2Hex); - /* calculate response */ - md_ctx_init(&md5_ctx, md5_kt); - md_ctx_update(&md5_ctx, HA1, HASHHEXLEN); - md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1); - md_ctx_update(&md5_ctx, (const uint8_t *) pszNonce, strlen(pszNonce)); - md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1); - if (*pszQop) + /* calculate response */ + md_ctx_init(&md5_ctx, md5_kt); + md_ctx_update(&md5_ctx, HA1, HASHHEXLEN); + md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1); + md_ctx_update(&md5_ctx, (const uint8_t *) pszNonce, strlen(pszNonce)); + md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1); + if (*pszQop) { - md_ctx_update(&md5_ctx, (const uint8_t *) pszNonceCount, strlen(pszNonceCount)); - md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1); - md_ctx_update(&md5_ctx, (const uint8_t *) pszCNonce, strlen(pszCNonce)); - md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1); - md_ctx_update(&md5_ctx, (const uint8_t *) pszQop, strlen(pszQop)); - md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1); - }; - md_ctx_update(&md5_ctx, HA2Hex, HASHHEXLEN); - md_ctx_final(&md5_ctx, RespHash); - md_ctx_cleanup(&md5_ctx); - CvtHex(RespHash, Response); + md_ctx_update(&md5_ctx, (const uint8_t *) pszNonceCount, strlen(pszNonceCount)); + md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1); + md_ctx_update(&md5_ctx, (const uint8_t *) pszCNonce, strlen(pszCNonce)); + md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1); + md_ctx_update(&md5_ctx, (const uint8_t *) pszQop, strlen(pszQop)); + md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1); + } + md_ctx_update(&md5_ctx, HA2Hex, HASHHEXLEN); + md_ctx_final(&md5_ctx, RespHash); + md_ctx_cleanup(&md5_ctx); + CvtHex(RespHash, Response); } -#endif +#endif /* if PROXY_DIGEST_AUTH */ diff --git a/src/openvpn/httpdigest.h b/src/openvpn/httpdigest.h index 84238413c1d..fff7d4655da 100644 --- a/src/openvpn/httpdigest.h +++ b/src/openvpn/httpdigest.h @@ -35,26 +35,26 @@ typedef unsigned char HASHHEX[HASHHEXLEN+1]; /* calculate H(A1) as per HTTP Digest spec */ void DigestCalcHA1( - IN char * pszAlg, - IN char * pszUserName, - IN char * pszRealm, - IN char * pszPassword, - IN char * pszNonce, - IN char * pszCNonce, + IN char *pszAlg, + IN char *pszUserName, + IN char *pszRealm, + IN char *pszPassword, + IN char *pszNonce, + IN char *pszCNonce, OUT HASHHEX SessionKey ); /* calculate request-digest/response-digest as per HTTP Digest spec */ void DigestCalcResponse( IN HASHHEX HA1, /* H(A1) */ - IN char * pszNonce, /* nonce from server */ - IN char * pszNonceCount, /* 8 hex digits */ - IN char * pszCNonce, /* client nonce */ - IN char * pszQop, /* qop-value: "", "auth", "auth-int" */ - IN char * pszMethod, /* method from the request */ - IN char * pszDigestUri, /* requested URL */ + IN char *pszNonce, /* nonce from server */ + IN char *pszNonceCount, /* 8 hex digits */ + IN char *pszCNonce, /* client nonce */ + IN char *pszQop, /* qop-value: "", "auth", "auth-int" */ + IN char *pszMethod, /* method from the request */ + IN char *pszDigestUri, /* requested URL */ IN HASHHEX HEntity, /* H(entity body) if qop="auth-int" */ OUT HASHHEX Response /* request-digest or response-digest */ ); -#endif +#endif /* if PROXY_DIGEST_AUTH */ diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 26b236de055..f6a5ac7d969 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -64,34 +64,34 @@ static struct context *static_context; /* GLOBAL */ #define CF_INIT_TLS_MULTI (1<<1) #define CF_INIT_TLS_AUTH_STANDALONE (1<<2) -static void do_init_first_time (struct context *c); +static void do_init_first_time(struct context *c); void -context_clear (struct context *c) +context_clear(struct context *c) { - CLEAR (*c); + CLEAR(*c); } void -context_clear_1 (struct context *c) +context_clear_1(struct context *c) { - CLEAR (c->c1); + CLEAR(c->c1); } void -context_clear_2 (struct context *c) +context_clear_2(struct context *c) { - CLEAR (c->c2); + CLEAR(c->c2); } void -context_clear_all_except_first_time (struct context *c) +context_clear_all_except_first_time(struct context *c) { - const bool first_time_save = c->first_time; - const struct context_persist cpsave = c->persist; - context_clear (c); - c->first_time = first_time_save; - c->persist = cpsave; + const bool first_time_save = c->first_time; + const struct context_persist cpsave = c->persist; + context_clear(c); + c->first_time = first_time_save; + c->persist = cpsave; } /* @@ -99,180 +99,184 @@ context_clear_all_except_first_time (struct context *c) * of a SIGUSR1 restart. */ static void -update_options_ce_post (struct options *options) +update_options_ce_post(struct options *options) { #if P2MP - /* - * In pull mode, we usually import --ping/--ping-restart parameters from - * the server. However we should also set an initial default --ping-restart - * for the period of time before we pull the --ping-restart parameter - * from the server. - */ - if (options->pull - && options->ping_rec_timeout_action == PING_UNDEF - && proto_is_dgram(options->ce.proto)) + /* + * In pull mode, we usually import --ping/--ping-restart parameters from + * the server. However we should also set an initial default --ping-restart + * for the period of time before we pull the --ping-restart parameter + * from the server. + */ + if (options->pull + && options->ping_rec_timeout_action == PING_UNDEF + && proto_is_dgram(options->ce.proto)) { - options->ping_rec_timeout = PRE_PULL_INITIAL_PING_RESTART; - options->ping_rec_timeout_action = PING_RESTART; + options->ping_rec_timeout = PRE_PULL_INITIAL_PING_RESTART; + options->ping_rec_timeout_action = PING_RESTART; } #endif } #ifdef ENABLE_MANAGEMENT static bool -management_callback_proxy_cmd (void *arg, const char **p) +management_callback_proxy_cmd(void *arg, const char **p) { - struct context *c = arg; - struct connection_entry *ce = &c->options.ce; - struct gc_arena *gc = &c->c2.gc; - bool ret = false; + struct context *c = arg; + struct connection_entry *ce = &c->options.ce; + struct gc_arena *gc = &c->c2.gc; + bool ret = false; - update_time(); - if (streq (p[1], "NONE")) - ret = true; - else if (p[2] && p[3]) + update_time(); + if (streq(p[1], "NONE")) + { + ret = true; + } + else if (p[2] && p[3]) { - if (streq (p[1], "HTTP")) + if (streq(p[1], "HTTP")) { - struct http_proxy_options *ho; - if (ce->proto != PROTO_TCP && ce->proto != PROTO_TCP_CLIENT ) + struct http_proxy_options *ho; + if (ce->proto != PROTO_TCP && ce->proto != PROTO_TCP_CLIENT) { - msg (M_WARN, "HTTP proxy support only works for TCP based connections"); - return false; + msg(M_WARN, "HTTP proxy support only works for TCP based connections"); + return false; } - ho = init_http_proxy_options_once (&ce->http_proxy_options, gc); - ho->server = string_alloc (p[2], gc); - ho->port = string_alloc (p[3], gc); - ho->auth_retry = (p[4] && streq (p[4], "nct") ? PAR_NCT : PAR_ALL); - ret = true; + ho = init_http_proxy_options_once(&ce->http_proxy_options, gc); + ho->server = string_alloc(p[2], gc); + ho->port = string_alloc(p[3], gc); + ho->auth_retry = (p[4] && streq(p[4], "nct") ? PAR_NCT : PAR_ALL); + ret = true; } - else if (streq (p[1], "SOCKS")) + else if (streq(p[1], "SOCKS")) { - ce->socks_proxy_server = string_alloc (p[2], gc); - ce->socks_proxy_port = p[3]; - ret = true; + ce->socks_proxy_server = string_alloc(p[2], gc); + ce->socks_proxy_port = p[3]; + ret = true; } } - else - msg (M_WARN, "Bad proxy command"); + else + { + msg(M_WARN, "Bad proxy command"); + } - ce->flags &= ~CE_MAN_QUERY_PROXY; + ce->flags &= ~CE_MAN_QUERY_PROXY; - return ret; + return ret; } static bool -ce_management_query_proxy (struct context *c) -{ - const struct connection_list *l = c->options.connection_list; - struct connection_entry *ce = &c->options.ce; - struct gc_arena gc; - bool ret = true; - - update_time(); - if (management) - { - gc = gc_new (); - { - struct buffer out = alloc_buf_gc (256, &gc); - buf_printf (&out, ">PROXY:%u,%s,%s", (l ? l->current : 0) + 1, - (proto_is_udp (ce->proto) ? "UDP" : "TCP"), np (ce->remote)); - management_notify_generic (management, BSTR (&out)); - } - ce->flags |= CE_MAN_QUERY_PROXY; - while (ce->flags & CE_MAN_QUERY_PROXY) - { - management_event_loop_n_seconds (management, 1); - if (IS_SIG (c)) +ce_management_query_proxy(struct context *c) +{ + const struct connection_list *l = c->options.connection_list; + struct connection_entry *ce = &c->options.ce; + struct gc_arena gc; + bool ret = true; + + update_time(); + if (management) + { + gc = gc_new(); + { + struct buffer out = alloc_buf_gc(256, &gc); + buf_printf(&out, ">PROXY:%u,%s,%s", (l ? l->current : 0) + 1, + (proto_is_udp(ce->proto) ? "UDP" : "TCP"), np(ce->remote)); + management_notify_generic(management, BSTR(&out)); + } + ce->flags |= CE_MAN_QUERY_PROXY; + while (ce->flags & CE_MAN_QUERY_PROXY) + { + management_event_loop_n_seconds(management, 1); + if (IS_SIG(c)) { - ret = false; - break; + ret = false; + break; } } - gc_free (&gc); + gc_free(&gc); } - return ret; + return ret; } static bool -management_callback_remote_cmd (void *arg, const char **p) -{ - struct context *c = (struct context *) arg; - struct connection_entry *ce = &c->options.ce; - int ret = false; - if (p[1] && ((ce->flags>>CE_MAN_QUERY_REMOTE_SHIFT)&CE_MAN_QUERY_REMOTE_MASK) == CE_MAN_QUERY_REMOTE_QUERY) - { - int flags = 0; - if (!strcmp(p[1], "ACCEPT")) - { - flags = CE_MAN_QUERY_REMOTE_ACCEPT; - ret = true; - } - else if (!strcmp(p[1], "SKIP")) - { - flags = CE_MAN_QUERY_REMOTE_SKIP; - ret = true; - } - else if (!strcmp(p[1], "MOD") && p[2] && p[3]) - { - if (strlen(p[2]) < RH_HOST_LEN && strlen(p[3]) < RH_PORT_LEN) - { - struct remote_host_store *rhs = c->options.rh_store; - if (!rhs) - { - ALLOC_OBJ_CLEAR_GC (rhs, struct remote_host_store, &c->options.gc); - c->options.rh_store = rhs; - } - strncpynt(rhs->host, p[2], RH_HOST_LEN); - strncpynt(rhs->port, p[3], RH_PORT_LEN); - - ce->remote = rhs->host; - ce->remote_port = rhs->port; - flags = CE_MAN_QUERY_REMOTE_MOD; - ret = true; - } - } - if (ret) - { - ce->flags &= ~(CE_MAN_QUERY_REMOTE_MASK<flags |= ((flags&CE_MAN_QUERY_REMOTE_MASK)<options.ce; + int ret = false; + if (p[1] && ((ce->flags>>CE_MAN_QUERY_REMOTE_SHIFT)&CE_MAN_QUERY_REMOTE_MASK) == CE_MAN_QUERY_REMOTE_QUERY) + { + int flags = 0; + if (!strcmp(p[1], "ACCEPT")) + { + flags = CE_MAN_QUERY_REMOTE_ACCEPT; + ret = true; + } + else if (!strcmp(p[1], "SKIP")) + { + flags = CE_MAN_QUERY_REMOTE_SKIP; + ret = true; + } + else if (!strcmp(p[1], "MOD") && p[2] && p[3]) + { + if (strlen(p[2]) < RH_HOST_LEN && strlen(p[3]) < RH_PORT_LEN) + { + struct remote_host_store *rhs = c->options.rh_store; + if (!rhs) + { + ALLOC_OBJ_CLEAR_GC(rhs, struct remote_host_store, &c->options.gc); + c->options.rh_store = rhs; + } + strncpynt(rhs->host, p[2], RH_HOST_LEN); + strncpynt(rhs->port, p[3], RH_PORT_LEN); + + ce->remote = rhs->host; + ce->remote_port = rhs->port; + flags = CE_MAN_QUERY_REMOTE_MOD; + ret = true; + } + } + if (ret) + { + ce->flags &= ~(CE_MAN_QUERY_REMOTE_MASK<flags |= ((flags&CE_MAN_QUERY_REMOTE_MASK)<options.ce; - int ret = true; - update_time(); - if (management) - { - struct buffer out = alloc_buf_gc (256, &gc); - buf_printf (&out, ">REMOTE:%s,%s,%s", np(ce->remote), ce->remote_port, proto2ascii(ce->proto, ce->af, false)); - management_notify_generic(management, BSTR (&out)); - ce->flags &= ~(CE_MAN_QUERY_REMOTE_MASK<flags |= (CE_MAN_QUERY_REMOTE_QUERY<flags>>CE_MAN_QUERY_REMOTE_SHIFT) & CE_MAN_QUERY_REMOTE_MASK) == CE_MAN_QUERY_REMOTE_QUERY) - { - management_event_loop_n_seconds (management, 1); - if (IS_SIG (c)) - { - ret = false; - break; - } - } - } - { - const int flags = ((ce->flags>>CE_MAN_QUERY_REMOTE_SHIFT) & CE_MAN_QUERY_REMOTE_MASK); - ret = (flags != CE_MAN_QUERY_REMOTE_SKIP); - } - gc_free (&gc); - return ret; +ce_management_query_remote(struct context *c) +{ + struct gc_arena gc = gc_new(); + volatile struct connection_entry *ce = &c->options.ce; + int ret = true; + update_time(); + if (management) + { + struct buffer out = alloc_buf_gc(256, &gc); + buf_printf(&out, ">REMOTE:%s,%s,%s", np(ce->remote), ce->remote_port, proto2ascii(ce->proto, ce->af, false)); + management_notify_generic(management, BSTR(&out)); + ce->flags &= ~(CE_MAN_QUERY_REMOTE_MASK<flags |= (CE_MAN_QUERY_REMOTE_QUERY<flags>>CE_MAN_QUERY_REMOTE_SHIFT) & CE_MAN_QUERY_REMOTE_MASK) == CE_MAN_QUERY_REMOTE_QUERY) + { + management_event_loop_n_seconds(management, 1); + if (IS_SIG(c)) + { + ret = false; + break; + } + } + } + { + const int flags = ((ce->flags>>CE_MAN_QUERY_REMOTE_SHIFT) & CE_MAN_QUERY_REMOTE_MASK); + ret = (flags != CE_MAN_QUERY_REMOTE_SKIP); + } + gc_free(&gc); + return ret; } #endif /* ENABLE_MANAGEMENT */ @@ -280,23 +284,23 @@ ce_management_query_remote (struct context *c) * Initialize and possibly randomize connection list. */ static void -init_connection_list (struct context *c) +init_connection_list(struct context *c) { - struct connection_list *l = c->options.connection_list; + struct connection_list *l = c->options.connection_list; - l->current = -1; - if (c->options.remote_random) + l->current = -1; + if (c->options.remote_random) { - int i; - for (i = 0; i < l->len; ++i) + int i; + for (i = 0; i < l->len; ++i) { - const int j = get_random () % l->len; - if (i != j) + const int j = get_random() % l->len; + if (i != j) { - struct connection_entry *tmp; - tmp = l->array[i]; - l->array[i] = l->array[j]; - l->array[j] = tmp; + struct connection_entry *tmp; + tmp = l->array[i]; + l->array[i] = l->array[j]; + l->array[j] = tmp; } } } @@ -305,10 +309,13 @@ init_connection_list (struct context *c) /* * Clear the remote address list */ -static void clear_remote_addrlist (struct link_socket_addr *lsa, bool free) +static void +clear_remote_addrlist(struct link_socket_addr *lsa, bool free) { if (lsa->remote_list && free) - freeaddrinfo(lsa->remote_list); + { + freeaddrinfo(lsa->remote_list); + } lsa->remote_list = NULL; lsa->current_remote = NULL; } @@ -317,118 +324,132 @@ static void clear_remote_addrlist (struct link_socket_addr *lsa, bool free) * Increment to next connection entry */ static void -next_connection_entry (struct context *c) -{ - struct connection_list *l = c->options.connection_list; - bool ce_defined; - struct connection_entry *ce; - int n_cycles = 0; - - do { - ce_defined = true; - if (c->options.no_advance && l->current >= 0) - { - c->options.no_advance = false; - } - else - { - /* Check if there is another resolved address to try for - * the current connection */ - if (c->c1.link_socket_addr.current_remote && - c->c1.link_socket_addr.current_remote->ai_next) - { - c->c1.link_socket_addr.current_remote = - c->c1.link_socket_addr.current_remote->ai_next; - } +next_connection_entry(struct context *c) +{ + struct connection_list *l = c->options.connection_list; + bool ce_defined; + struct connection_entry *ce; + int n_cycles = 0; + + do { + ce_defined = true; + if (c->options.no_advance && l->current >= 0) + { + c->options.no_advance = false; + } else - { - /* FIXME (schwabe) fix the persist-remote-ip option for real, - * this is broken probably ever since connection lists and multiple - * remote existed - */ - if (!c->options.persist_remote_ip) - { - /* close_instance should have cleared the addrinfo objects */ - ASSERT (c->c1.link_socket_addr.current_remote == NULL); - ASSERT (c->c1.link_socket_addr.remote_list == NULL); - } - else + { + /* Check if there is another resolved address to try for + * the current connection */ + if (c->c1.link_socket_addr.current_remote + && c->c1.link_socket_addr.current_remote->ai_next) + { c->c1.link_socket_addr.current_remote = - c->c1.link_socket_addr.remote_list; - - /* - * Increase the number of connection attempts - * If this is connect-retry-max * size(l) - * OpenVPN will quit - */ - - c->options.unsuccessful_attempts++; - - if (++l->current >= l->len) - { - - l->current = 0; - if (++n_cycles >= 2) - msg (M_FATAL, "No usable connection profiles are present"); - } - } - } + c->c1.link_socket_addr.current_remote->ai_next; + } + else + { + /* FIXME (schwabe) fix the persist-remote-ip option for real, + * this is broken probably ever since connection lists and multiple + * remote existed + */ + if (!c->options.persist_remote_ip) + { + /* close_instance should have cleared the addrinfo objects */ + ASSERT(c->c1.link_socket_addr.current_remote == NULL); + ASSERT(c->c1.link_socket_addr.remote_list == NULL); + } + else + { + c->c1.link_socket_addr.current_remote = + c->c1.link_socket_addr.remote_list; + } + + /* + * Increase the number of connection attempts + * If this is connect-retry-max * size(l) + * OpenVPN will quit + */ + + c->options.unsuccessful_attempts++; + + if (++l->current >= l->len) + { + + l->current = 0; + if (++n_cycles >= 2) + { + msg(M_FATAL, "No usable connection profiles are present"); + } + } + } + } - ce = l->array[l->current]; + ce = l->array[l->current]; - if (ce->flags & CE_DISABLED) - ce_defined = false; + if (ce->flags & CE_DISABLED) + { + ce_defined = false; + } - c->options.ce = *ce; + c->options.ce = *ce; #ifdef ENABLE_MANAGEMENT - if (ce_defined && management && management_query_remote_enabled(management)) - { - /* allow management interface to override connection entry details */ - ce_defined = ce_management_query_remote(c); - if (IS_SIG (c)) - break; - } - else + if (ce_defined && management && management_query_remote_enabled(management)) + { + /* allow management interface to override connection entry details */ + ce_defined = ce_management_query_remote(c); + if (IS_SIG(c)) + { + break; + } + } + else #endif #ifdef ENABLE_MANAGEMENT - if (ce_defined && management && management_query_proxy_enabled (management)) + if (ce_defined && management && management_query_proxy_enabled(management)) { - ce_defined = ce_management_query_proxy (c); - if (IS_SIG (c)) - break; + ce_defined = ce_management_query_proxy(c); + if (IS_SIG(c)) + { + break; + } } #endif - } while (!ce_defined); + } while (!ce_defined); - /* Check if this connection attempt would bring us over the limit */ - if (c->options.connect_retry_max > 0 && - c->options.unsuccessful_attempts > (l->len * c->options.connect_retry_max)) - msg(M_FATAL, "All connections have been connect-retry-max (%d) times unsuccessful, exiting", - c->options.connect_retry_max); - update_options_ce_post (&c->options); + /* Check if this connection attempt would bring us over the limit */ + if (c->options.connect_retry_max > 0 + && c->options.unsuccessful_attempts > (l->len * c->options.connect_retry_max)) + { + msg(M_FATAL, "All connections have been connect-retry-max (%d) times unsuccessful, exiting", + c->options.connect_retry_max); + } + update_options_ce_post(&c->options); } /* * Query for private key and auth-user-pass username/passwords */ void -init_query_passwords (const struct context *c) +init_query_passwords(const struct context *c) { #ifdef ENABLE_CRYPTO - /* Certificate password input */ - if (c->options.key_pass_file) - pem_password_setup (c->options.key_pass_file); + /* Certificate password input */ + if (c->options.key_pass_file) + { + pem_password_setup(c->options.key_pass_file); + } #endif - + #if P2MP - /* Auth user/pass input */ - if (c->options.auth_user_pass_file) + /* Auth user/pass input */ + if (c->options.auth_user_pass_file) { #ifdef ENABLE_CLIENT_CR - auth_user_pass_setup (c->options.auth_user_pass_file, &c->options.sc_info); + auth_user_pass_setup(c->options.auth_user_pass_file, &c->options.sc_info); #else - auth_user_pass_setup (c->options.auth_user_pass_file, NULL); + auth_user_pass_setup(c->options.auth_user_pass_file, NULL); #endif } #endif @@ -439,382 +460,396 @@ init_query_passwords (const struct context *c) */ static void -uninit_proxy_dowork (struct context *c) +uninit_proxy_dowork(struct context *c) { - if (c->c1.http_proxy_owned && c->c1.http_proxy) + if (c->c1.http_proxy_owned && c->c1.http_proxy) { - http_proxy_close (c->c1.http_proxy); - c->c1.http_proxy = NULL; - c->c1.http_proxy_owned = false; + http_proxy_close(c->c1.http_proxy); + c->c1.http_proxy = NULL; + c->c1.http_proxy_owned = false; } - if (c->c1.socks_proxy_owned && c->c1.socks_proxy) + if (c->c1.socks_proxy_owned && c->c1.socks_proxy) { - socks_proxy_close (c->c1.socks_proxy); - c->c1.socks_proxy = NULL; - c->c1.socks_proxy_owned = false; + socks_proxy_close(c->c1.socks_proxy); + c->c1.socks_proxy = NULL; + c->c1.socks_proxy_owned = false; } } static void -init_proxy_dowork (struct context *c) +init_proxy_dowork(struct context *c) { - bool did_http = false; + bool did_http = false; - uninit_proxy_dowork (c); + uninit_proxy_dowork(c); - if (c->options.ce.http_proxy_options) + if (c->options.ce.http_proxy_options) { - /* Possible HTTP proxy user/pass input */ - c->c1.http_proxy = http_proxy_new (c->options.ce.http_proxy_options); - if (c->c1.http_proxy) - { - did_http = true; - c->c1.http_proxy_owned = true; - } + /* Possible HTTP proxy user/pass input */ + c->c1.http_proxy = http_proxy_new(c->options.ce.http_proxy_options); + if (c->c1.http_proxy) + { + did_http = true; + c->c1.http_proxy_owned = true; + } } if (!did_http && c->options.ce.socks_proxy_server) { - c->c1.socks_proxy = socks_proxy_new (c->options.ce.socks_proxy_server, - c->options.ce.socks_proxy_port, - c->options.ce.socks_proxy_authfile); - if (c->c1.socks_proxy) - { - c->c1.socks_proxy_owned = true; - } + c->c1.socks_proxy = socks_proxy_new(c->options.ce.socks_proxy_server, + c->options.ce.socks_proxy_port, + c->options.ce.socks_proxy_authfile); + if (c->c1.socks_proxy) + { + c->c1.socks_proxy_owned = true; + } } } static void -init_proxy (struct context *c) +init_proxy(struct context *c) { - init_proxy_dowork (c); + init_proxy_dowork(c); } static void -uninit_proxy (struct context *c) +uninit_proxy(struct context *c) { - uninit_proxy_dowork (c); + uninit_proxy_dowork(c); } void -context_init_1 (struct context *c) +context_init_1(struct context *c) { - context_clear_1 (c); + context_clear_1(c); - packet_id_persist_init (&c->c1.pid_persist); + packet_id_persist_init(&c->c1.pid_persist); - init_connection_list (c); + init_connection_list(c); #if defined(ENABLE_PKCS11) - if (c->first_time) { - int i; - pkcs11_initialize (true, c->options.pkcs11_pin_cache_period); - for (i=0;ioptions.pkcs11_providers[i] != NULL;i++) - pkcs11_addProvider (c->options.pkcs11_providers[i], c->options.pkcs11_protected_authentication[i], - c->options.pkcs11_private_mode[i], c->options.pkcs11_cert_private[i]); - } + if (c->first_time) + { + int i; + pkcs11_initialize(true, c->options.pkcs11_pin_cache_period); + for (i = 0; ioptions.pkcs11_providers[i] != NULL; i++) + pkcs11_addProvider(c->options.pkcs11_providers[i], c->options.pkcs11_protected_authentication[i], + c->options.pkcs11_private_mode[i], c->options.pkcs11_cert_private[i]); + } #endif #if 0 /* test get_user_pass with GET_USER_PASS_NEED_OK flag */ - { - /* - * In the management interface, you can okay the request by entering "needok token-insertion-request ok" - */ - struct user_pass up; - CLEAR (up); - strcpy (up.username, "Please insert your cryptographic token"); /* put the high-level message in up.username */ - get_user_pass (&up, NULL, "token-insertion-request", GET_USER_PASS_MANAGEMENT|GET_USER_PASS_NEED_OK); - msg (M_INFO, "RET:%s", up.password); /* will return the third argument to management interface - 'needok' command, usually 'ok' or 'cancel'. */ - } + { + /* + * In the management interface, you can okay the request by entering "needok token-insertion-request ok" + */ + struct user_pass up; + CLEAR(up); + strcpy(up.username, "Please insert your cryptographic token"); /* put the high-level message in up.username */ + get_user_pass(&up, NULL, "token-insertion-request", GET_USER_PASS_MANAGEMENT|GET_USER_PASS_NEED_OK); + msg(M_INFO, "RET:%s", up.password); /* will return the third argument to management interface + * 'needok' command, usually 'ok' or 'cancel'. */ + } #endif } void -context_gc_free (struct context *c) +context_gc_free(struct context *c) { - gc_free (&c->c2.gc); - gc_free (&c->options.gc); - gc_free (&c->gc); + gc_free(&c->c2.gc); + gc_free(&c->options.gc); + gc_free(&c->gc); } #if PORT_SHARE static void -close_port_share (void) +close_port_share(void) { - if (port_share) + if (port_share) { - port_share_close (port_share); - port_share = NULL; + port_share_close(port_share); + port_share = NULL; } } static void -init_port_share (struct context *c) +init_port_share(struct context *c) { - if (!port_share && (c->options.port_share_host && c->options.port_share_port)) + if (!port_share && (c->options.port_share_host && c->options.port_share_port)) { - port_share = port_share_open (c->options.port_share_host, - c->options.port_share_port, - MAX_RW_SIZE_LINK (&c->c2.frame), - c->options.port_share_journal_dir); - if (port_share == NULL) - msg (M_FATAL, "Fatal error: Port sharing failed"); + port_share = port_share_open(c->options.port_share_host, + c->options.port_share_port, + MAX_RW_SIZE_LINK(&c->c2.frame), + c->options.port_share_journal_dir); + if (port_share == NULL) + { + msg(M_FATAL, "Fatal error: Port sharing failed"); + } } } -#endif +#endif /* if PORT_SHARE */ bool -init_static (void) +init_static(void) { - /* configure_path (); */ + /* configure_path (); */ #if defined(ENABLE_CRYPTO) && defined(DMALLOC) - crypto_init_dmalloc(); + crypto_init_dmalloc(); #endif - init_random_seed (); /* init random() function, only used as - source for weak random numbers */ - error_reset (); /* initialize error.c */ - reset_check_status (); /* initialize status check code in socket.c */ + init_random_seed(); /* init random() function, only used as + * source for weak random numbers */ + error_reset(); /* initialize error.c */ + reset_check_status(); /* initialize status check code in socket.c */ #ifdef _WIN32 - init_win32 (); + init_win32(); #endif #ifdef OPENVPN_DEBUG_COMMAND_LINE - { - int i; - for (i = 0; i < argc; ++i) - msg (M_INFO, "argv[%d] = '%s'", i, argv[i]); - } + { + int i; + for (i = 0; i < argc; ++i) + msg(M_INFO, "argv[%d] = '%s'", i, argv[i]); + } #endif - update_time (); + update_time(); #ifdef ENABLE_CRYPTO - init_ssl_lib (); + init_ssl_lib(); - /* init PRNG used for IV generation */ - /* When forking, copy this to more places in the code to avoid fork - random-state predictability */ - prng_init (NULL, 0); + /* init PRNG used for IV generation */ + /* When forking, copy this to more places in the code to avoid fork + * random-state predictability */ + prng_init(NULL, 0); #endif #ifdef PID_TEST - packet_id_interactive_test (); /* test the sequence number code */ - return false; + packet_id_interactive_test(); /* test the sequence number code */ + return false; #endif #ifdef SCHEDULE_TEST - schedule_test (); - return false; + schedule_test(); + return false; #endif #ifdef LIST_TEST - list_test (); - return false; + list_test(); + return false; #endif #ifdef IFCONFIG_POOL_TEST - ifconfig_pool_test (0x0A010004, 0x0A0100FF); - return false; + ifconfig_pool_test(0x0A010004, 0x0A0100FF); + return false; #endif #ifdef CHARACTER_CLASS_DEBUG - character_class_debug (); - return false; + character_class_debug(); + return false; #endif #ifdef EXTRACT_X509_FIELD_TEST - extract_x509_field_test (); - return false; + extract_x509_field_test(); + return false; #endif #ifdef TIME_TEST - time_test (); - return false; + time_test(); + return false; #endif #ifdef TEST_GET_DEFAULT_GATEWAY - { - struct route_gateway_info rgi; - struct route_ipv6_gateway_info rgi6; - get_default_gateway(&rgi); - get_default_gateway_ipv6(&rgi6, NULL); - print_default_gateway(M_INFO, &rgi, &rgi6); - return false; - } + { + struct route_gateway_info rgi; + struct route_ipv6_gateway_info rgi6; + get_default_gateway(&rgi); + get_default_gateway_ipv6(&rgi6, NULL); + print_default_gateway(M_INFO, &rgi, &rgi6); + return false; + } #endif #ifdef GEN_PATH_TEST - { - struct gc_arena gc = gc_new (); - const char *fn = gen_path ("foo", - "bar", - &gc); - printf ("%s\n", fn); - gc_free (&gc); - } - return false; + { + struct gc_arena gc = gc_new(); + const char *fn = gen_path("foo", + "bar", + &gc); + printf("%s\n", fn); + gc_free(&gc); + } + return false; #endif #ifdef STATUS_PRINTF_TEST - { - struct gc_arena gc = gc_new (); - const char *tmp_file = create_temp_file ("/tmp", "foo", &gc); - struct status_output *so = status_open (tmp_file, 0, -1, NULL, STATUS_OUTPUT_WRITE); - status_printf (so, "%s", "foo"); - status_printf (so, "%s", "bar"); - if (!status_close (so)) - msg (M_WARN, "STATUS_PRINTF_TEST: %s: write error", tmp_file); - gc_free (&gc); - } - return false; + { + struct gc_arena gc = gc_new(); + const char *tmp_file = create_temp_file("/tmp", "foo", &gc); + struct status_output *so = status_open(tmp_file, 0, -1, NULL, STATUS_OUTPUT_WRITE); + status_printf(so, "%s", "foo"); + status_printf(so, "%s", "bar"); + if (!status_close(so)) + { + msg(M_WARN, "STATUS_PRINTF_TEST: %s: write error", tmp_file); + } + gc_free(&gc); + } + return false; #endif #ifdef ARGV_TEST - { - void argv_test (void); - argv_test (); - return false; - } + { + void argv_test(void); + + argv_test(); + return false; + } #endif #ifdef PRNG_TEST - { - struct gc_arena gc = gc_new (); - uint8_t rndbuf[8]; - int i; - prng_init ("sha1", 16); - /*prng_init (NULL, 0);*/ - const int factor = 1; - for (i = 0; i < factor * 8; ++i) - { + { + struct gc_arena gc = gc_new(); + uint8_t rndbuf[8]; + int i; + prng_init("sha1", 16); + /*prng_init (NULL, 0);*/ + const int factor = 1; + for (i = 0; i < factor * 8; ++i) + { #if 1 - prng_bytes (rndbuf, sizeof (rndbuf)); + prng_bytes(rndbuf, sizeof(rndbuf)); #else - ASSERT(rand_bytes (rndbuf, sizeof (rndbuf))); -#endif - printf ("[%d] %s\n", i, format_hex (rndbuf, sizeof (rndbuf), 0, &gc)); - } - gc_free (&gc); - prng_uninit (); - return false; - } + ASSERT(rand_bytes(rndbuf, sizeof(rndbuf))); #endif + printf("[%d] %s\n", i, format_hex(rndbuf, sizeof(rndbuf), 0, &gc)); + } + gc_free(&gc); + prng_uninit(); + return false; + } +#endif /* ifdef PRNG_TEST */ #ifdef BUFFER_LIST_AGGREGATE_TEST - /* test buffer_list_aggregate function */ - { - static const char *text[] = { - "It was a bright cold day in April, ", - "and the clocks were striking ", - "thirteen. ", - "Winston Smith, ", - "his chin nuzzled into his breast in an ", - "effort to escape the vile wind, ", - "slipped quickly through the glass doors ", - "of Victory Mansions, though not quickly ", - "enough to prevent a swirl of gritty dust from ", - "entering along with him." - }; - - int iter, listcap; - for (listcap = 0; listcap < 12; ++listcap) - { - for (iter = 0; iter < 512; ++iter) - { - struct buffer_list *bl = buffer_list_new(listcap); - { - int i; - for (i = 0; i < SIZE(text); ++i) - buffer_list_push(bl, (unsigned char *)text[i]); - } - printf("[cap=%d i=%d] *************************\n", listcap, iter); - if (!(iter & 8)) - buffer_list_aggregate(bl, iter/2); - if (!(iter & 16)) - buffer_list_push(bl, (unsigned char *)"Even more text..."); - buffer_list_aggregate(bl, iter); - if (!(iter & 1)) - buffer_list_push(bl, (unsigned char *)"More text..."); - { - struct buffer *buf; - while ((buf = buffer_list_peek(bl))) - { - int c; - printf ("'"); - while ((c = buf_read_u8(buf)) >= 0) - putchar(c); - printf ("'\n"); - buffer_list_advance(bl, 0); - } - } - buffer_list_free(bl); - } - } - return false; - } -#endif + /* test buffer_list_aggregate function */ + { + static const char *text[] = { + "It was a bright cold day in April, ", + "and the clocks were striking ", + "thirteen. ", + "Winston Smith, ", + "his chin nuzzled into his breast in an ", + "effort to escape the vile wind, ", + "slipped quickly through the glass doors ", + "of Victory Mansions, though not quickly ", + "enough to prevent a swirl of gritty dust from ", + "entering along with him." + }; + + int iter, listcap; + for (listcap = 0; listcap < 12; ++listcap) + { + for (iter = 0; iter < 512; ++iter) + { + struct buffer_list *bl = buffer_list_new(listcap); + { + int i; + for (i = 0; i < SIZE(text); ++i) + buffer_list_push(bl, (unsigned char *)text[i]); + } + printf("[cap=%d i=%d] *************************\n", listcap, iter); + if (!(iter & 8)) + { + buffer_list_aggregate(bl, iter/2); + } + if (!(iter & 16)) + { + buffer_list_push(bl, (unsigned char *)"Even more text..."); + } + buffer_list_aggregate(bl, iter); + if (!(iter & 1)) + { + buffer_list_push(bl, (unsigned char *)"More text..."); + } + { + struct buffer *buf; + while ((buf = buffer_list_peek(bl))) + { + int c; + printf("'"); + while ((c = buf_read_u8(buf)) >= 0) + putchar(c); + printf("'\n"); + buffer_list_advance(bl, 0); + } + } + buffer_list_free(bl); + } + } + return false; + } +#endif /* ifdef BUFFER_LIST_AGGREGATE_TEST */ #ifdef MSTATS_TEST - { - int i; - mstats_open("/dev/shm/mstats.dat"); - for (i = 0; i < 30; ++i) - { - mmap_stats->n_clients += 1; - mmap_stats->link_write_bytes += 8; - mmap_stats->link_read_bytes += 16; - sleep(1); - } - mstats_close(); - return false; - } + { + int i; + mstats_open("/dev/shm/mstats.dat"); + for (i = 0; i < 30; ++i) + { + mmap_stats->n_clients += 1; + mmap_stats->link_write_bytes += 8; + mmap_stats->link_read_bytes += 16; + sleep(1); + } + mstats_close(); + return false; + } #endif - return true; + return true; } void -uninit_static (void) +uninit_static(void) { #ifdef ENABLE_CRYPTO - free_ssl_lib (); + free_ssl_lib(); #endif #ifdef ENABLE_PKCS11 - pkcs11_terminate (); + pkcs11_terminate(); #endif #if PORT_SHARE - close_port_share (); + close_port_share(); #endif #if defined(MEASURE_TLS_HANDSHAKE_STATS) && defined(ENABLE_CRYPTO) - show_tls_performance_stats (); + show_tls_performance_stats(); #endif } void -init_verb_mute (struct context *c, unsigned int flags) +init_verb_mute(struct context *c, unsigned int flags) { - if (flags & IVM_LEVEL_1) + if (flags & IVM_LEVEL_1) { - /* set verbosity and mute levels */ - set_check_status (D_LINK_ERRORS, D_READ_WRITE); - set_debug_level (c->options.verbosity, SDL_CONSTRAIN); - set_mute_cutoff (c->options.mute); + /* set verbosity and mute levels */ + set_check_status(D_LINK_ERRORS, D_READ_WRITE); + set_debug_level(c->options.verbosity, SDL_CONSTRAIN); + set_mute_cutoff(c->options.mute); } - /* special D_LOG_RW mode */ - if (flags & IVM_LEVEL_2) - c->c2.log_rw = (check_debug_level (D_LOG_RW) && !check_debug_level (D_LOG_RW + 1)); + /* special D_LOG_RW mode */ + if (flags & IVM_LEVEL_2) + { + c->c2.log_rw = (check_debug_level(D_LOG_RW) && !check_debug_level(D_LOG_RW + 1)); + } } /* @@ -823,103 +858,120 @@ init_verb_mute (struct context *c, unsigned int flags) * set --dev to tun. */ void -init_options_dev (struct options *options) +init_options_dev(struct options *options) { - if (!options->dev && options->dev_node) { - char *dev_node = string_alloc(options->dev_node, NULL); /* POSIX basename() implementaions may modify its arguments */ - options->dev = basename (dev_node); - } + if (!options->dev && options->dev_node) + { + char *dev_node = string_alloc(options->dev_node, NULL); /* POSIX basename() implementaions may modify its arguments */ + options->dev = basename(dev_node); + } } bool -print_openssl_info (const struct options *options) +print_openssl_info(const struct options *options) { - /* - * OpenSSL info print mode? - */ + /* + * OpenSSL info print mode? + */ #ifdef ENABLE_CRYPTO - if (options->show_ciphers || options->show_digests || options->show_engines - || options->show_tls_ciphers || options->show_curves) + if (options->show_ciphers || options->show_digests || options->show_engines + || options->show_tls_ciphers || options->show_curves) { - if (options->show_ciphers) - show_available_ciphers (); - if (options->show_digests) - show_available_digests (); - if (options->show_engines) - show_available_engines (); - if (options->show_tls_ciphers) - show_available_tls_ciphers (options->cipher_list); - if (options->show_curves) - show_available_curves(); - return true; + if (options->show_ciphers) + { + show_available_ciphers(); + } + if (options->show_digests) + { + show_available_digests(); + } + if (options->show_engines) + { + show_available_engines(); + } + if (options->show_tls_ciphers) + { + show_available_tls_ciphers(options->cipher_list); + } + if (options->show_curves) + { + show_available_curves(); + } + return true; } -#endif - return false; +#endif /* ifdef ENABLE_CRYPTO */ + return false; } /* * Static pre-shared key generation mode? */ bool -do_genkey (const struct options * options) +do_genkey(const struct options *options) { #ifdef ENABLE_CRYPTO - if (options->genkey) + if (options->genkey) { - int nbits_written; + int nbits_written; - notnull (options->shared_secret_file, - "shared secret output file (--secret)"); + notnull(options->shared_secret_file, + "shared secret output file (--secret)"); - if (options->mlock) /* should we disable paging? */ - platform_mlockall (true); + if (options->mlock) /* should we disable paging? */ + { + platform_mlockall(true); + } - nbits_written = write_key_file (2, options->shared_secret_file); + nbits_written = write_key_file(2, options->shared_secret_file); - msg (D_GENKEY | M_NOPREFIX, - "Randomly generated %d bit key written to %s", nbits_written, - options->shared_secret_file); - return true; + msg(D_GENKEY | M_NOPREFIX, + "Randomly generated %d bit key written to %s", nbits_written, + options->shared_secret_file); + return true; } #endif - return false; + return false; } /* * Persistent TUN/TAP device management mode? */ bool -do_persist_tuntap (const struct options *options) +do_persist_tuntap(const struct options *options) { - if (options->persist_config) + if (options->persist_config) { - /* sanity check on options for --mktun or --rmtun */ - notnull (options->dev, "TUN/TAP device (--dev)"); - if (options->ce.remote || options->ifconfig_local - || options->ifconfig_remote_netmask + /* sanity check on options for --mktun or --rmtun */ + notnull(options->dev, "TUN/TAP device (--dev)"); + if (options->ce.remote || options->ifconfig_local + || options->ifconfig_remote_netmask #ifdef ENABLE_CRYPTO - || options->shared_secret_file - || options->tls_server || options->tls_client + || options->shared_secret_file + || options->tls_server || options->tls_client #endif - ) - msg (M_FATAL|M_OPTERR, - "options --mktun or --rmtun should only be used together with --dev"); + ) + { + msg(M_FATAL|M_OPTERR, + "options --mktun or --rmtun should only be used together with --dev"); + } #ifdef ENABLE_FEATURE_TUN_PERSIST - tuncfg (options->dev, options->dev_type, options->dev_node, - options->persist_mode, - options->username, options->groupname, &options->tuntap_options); - if (options->persist_mode && options->lladdr) - set_lladdr(options->dev, options->lladdr, NULL); - return true; -#else - msg( M_FATAL|M_OPTERR, - "options --mktun and --rmtun are not available on your operating " - "system. Please check 'man tun' (or 'tap'), whether your system " - "supports using 'ifconfig %s create' / 'destroy' to create/remove " - "persistant tunnel interfaces.", options->dev ); + tuncfg(options->dev, options->dev_type, options->dev_node, + options->persist_mode, + options->username, options->groupname, &options->tuntap_options); + if (options->persist_mode && options->lladdr) + { + set_lladdr(options->dev, options->lladdr, NULL); + } + return true; +#else /* ifdef ENABLE_FEATURE_TUN_PERSIST */ + msg( M_FATAL|M_OPTERR, + "options --mktun and --rmtun are not available on your operating " + "system. Please check 'man tun' (or 'tap'), whether your system " + "supports using 'ifconfig %s create' / 'destroy' to create/remove " + "persistant tunnel interfaces.", options->dev ); #endif } - return false; + return false; } /* @@ -927,112 +979,134 @@ do_persist_tuntap (const struct options *options) * Return true if we did it. */ bool -possibly_become_daemon (const struct options *options) +possibly_become_daemon(const struct options *options) { - bool ret = false; + bool ret = false; #ifdef ENABLE_SYSTEMD - /* return without forking if we are running from systemd */ - if (sd_notify(0, "READY=0") > 0) - return ret; + /* return without forking if we are running from systemd */ + if (sd_notify(0, "READY=0") > 0) + { + return ret; + } #endif - if (options->daemon) + if (options->daemon) { - ASSERT (!options->inetd); - /* Don't chdir immediately, but the end of the init sequence, if needed */ - if (daemon (1, options->log) < 0) - msg (M_ERR, "daemon() failed or unsupported"); - restore_signal_state (); - if (options->log) - set_std_files_to_null (true); + ASSERT(!options->inetd); + /* Don't chdir immediately, but the end of the init sequence, if needed */ + if (daemon(1, options->log) < 0) + { + msg(M_ERR, "daemon() failed or unsupported"); + } + restore_signal_state(); + if (options->log) + { + set_std_files_to_null(true); + } - ret = true; + ret = true; } - return ret; + return ret; } /* * Actually do UID/GID downgrade, chroot and SELinux context switching, if requested. */ static void -do_uid_gid_chroot (struct context *c, bool no_delay) +do_uid_gid_chroot(struct context *c, bool no_delay) { - static const char why_not[] = "will be delayed because of --client, --pull, or --up-delay"; - struct context_0 *c0 = c->c0; + static const char why_not[] = "will be delayed because of --client, --pull, or --up-delay"; + struct context_0 *c0 = c->c0; - if (c0 && !c0->uid_gid_chroot_set) + if (c0 && !c0->uid_gid_chroot_set) { - /* chroot if requested */ - if (c->options.chroot_dir) - { - if (no_delay) + /* chroot if requested */ + if (c->options.chroot_dir) + { + if (no_delay) { #ifdef ENABLE_SYSTEMD - /* If OpenVPN is started by systemd, the OpenVPN process needs - * to provide a preliminary status report to systemd. This is - * needed as $NOTIFY_SOCKET will not be available inside the - * chroot, which sd_notify()/sd_notifyf() depends on. - * - * This approach is the simplest and the most non-intrusive - * solution right before the 2.4_rc2 release. - * - * TODO: Consider altnernative solutions - bind mount? - * systemd does not grok OpenVPN configuration files, thus cannot - * have a sane way to know if OpenVPN will chroot or not and to - * which subdirectory it will chroot into. - */ - sd_notifyf(0, "READY=1\n" - "STATUS=Entering chroot, most of the init completed successfully\n" - "MAINPID=%lu", (unsigned long) getpid()); -#endif - platform_chroot (c->options.chroot_dir); + /* If OpenVPN is started by systemd, the OpenVPN process needs + * to provide a preliminary status report to systemd. This is + * needed as $NOTIFY_SOCKET will not be available inside the + * chroot, which sd_notify()/sd_notifyf() depends on. + * + * This approach is the simplest and the most non-intrusive + * solution right before the 2.4_rc2 release. + * + * TODO: Consider altnernative solutions - bind mount? + * systemd does not grok OpenVPN configuration files, thus cannot + * have a sane way to know if OpenVPN will chroot or not and to + * which subdirectory it will chroot into. + */ + sd_notifyf(0, "READY=1\n" + "STATUS=Entering chroot, most of the init completed successfully\n" + "MAINPID=%lu", (unsigned long) getpid()); +#endif + platform_chroot(c->options.chroot_dir); + } + else if (c->first_time) + { + msg(M_INFO, "NOTE: chroot %s", why_not); + } + } + + /* set user and/or group if we want to setuid/setgid */ + if (c0->uid_gid_specified) + { + if (no_delay) + { + platform_group_set(&c0->platform_state_group); + platform_user_set(&c0->platform_state_user); + } + else if (c->first_time) + { + msg(M_INFO, "NOTE: UID/GID downgrade %s", why_not); } - else if (c->first_time) - msg (M_INFO, "NOTE: chroot %s", why_not); - } - - /* set user and/or group if we want to setuid/setgid */ - if (c0->uid_gid_specified) - { - if (no_delay) { - platform_group_set (&c0->platform_state_group); - platform_user_set (&c0->platform_state_user); - } - else if (c->first_time) - msg (M_INFO, "NOTE: UID/GID downgrade %s", why_not); - } + } #ifdef ENABLE_MEMSTATS - if (c->first_time && c->options.memstats_fn) - mstats_open(c->options.memstats_fn); + if (c->first_time && c->options.memstats_fn) + { + mstats_open(c->options.memstats_fn); + } #endif #ifdef ENABLE_SELINUX - /* Apply a SELinux context in order to restrict what OpenVPN can do - * to _only_ what it is supposed to do after initialization is complete - * (basically just network I/O operations). Doing it after chroot - * requires /proc to be mounted in the chroot (which is annoying indeed - * but doing it before requires more complex SELinux policies. - */ - if (c->options.selinux_context) - { - if (no_delay) { - if (-1 == setcon (c->options.selinux_context)) - msg (M_ERR, "setcon to '%s' failed; is /proc accessible?", c->options.selinux_context); - else - msg (M_INFO, "setcon to '%s' succeeded", c->options.selinux_context); - } - else if (c->first_time) - msg (M_INFO, "NOTE: setcon %s", why_not); - } -#endif - - /* Privileges are going to be dropped by now (if requested), be sure - * to prevent any future privilege dropping attempts from now on. - */ - if (no_delay) - c0->uid_gid_chroot_set = true; + /* Apply a SELinux context in order to restrict what OpenVPN can do + * to _only_ what it is supposed to do after initialization is complete + * (basically just network I/O operations). Doing it after chroot + * requires /proc to be mounted in the chroot (which is annoying indeed + * but doing it before requires more complex SELinux policies. + */ + if (c->options.selinux_context) + { + if (no_delay) + { + if (-1 == setcon(c->options.selinux_context)) + { + msg(M_ERR, "setcon to '%s' failed; is /proc accessible?", c->options.selinux_context); + } + else + { + msg(M_INFO, "setcon to '%s' succeeded", c->options.selinux_context); + } + } + else if (c->first_time) + { + msg(M_INFO, "NOTE: setcon %s", why_not); + } + } +#endif + + /* Privileges are going to be dropped by now (if requested), be sure + * to prevent any future privilege dropping attempts from now on. + */ + if (no_delay) + { + c0->uid_gid_chroot_set = true; + } } } @@ -1041,50 +1115,50 @@ do_uid_gid_chroot (struct context *c, bool no_delay) * prepending to msg() output. */ const char * -format_common_name (struct context *c, struct gc_arena *gc) +format_common_name(struct context *c, struct gc_arena *gc) { - struct buffer out = alloc_buf_gc (256, gc); + struct buffer out = alloc_buf_gc(256, gc); #ifdef ENABLE_CRYPTO - if (c->c2.tls_multi) + if (c->c2.tls_multi) { - buf_printf (&out, "[%s] ", tls_common_name (c->c2.tls_multi, false)); + buf_printf(&out, "[%s] ", tls_common_name(c->c2.tls_multi, false)); } #endif - return BSTR (&out); + return BSTR(&out); } void -pre_setup (const struct options *options) +pre_setup(const struct options *options) { #ifdef _WIN32 - if (options->exit_event_name) + if (options->exit_event_name) { - win32_signal_open (&win32_signal, - WSO_FORCE_SERVICE, - options->exit_event_name, - options->exit_event_initial_state); + win32_signal_open(&win32_signal, + WSO_FORCE_SERVICE, + options->exit_event_name, + options->exit_event_initial_state); } - else + else { - win32_signal_open (&win32_signal, - WSO_FORCE_CONSOLE, - NULL, - false); + win32_signal_open(&win32_signal, + WSO_FORCE_CONSOLE, + NULL, + false); - /* put a title on the top window bar */ - if (win32_signal.mode == WSO_MODE_CONSOLE) - { - window_title_save (&window_title); - window_title_generate (options->config); - } + /* put a title on the top window bar */ + if (win32_signal.mode == WSO_MODE_CONSOLE) + { + window_title_save(&window_title); + window_title_generate(options->config); + } } -#endif +#endif /* ifdef _WIN32 */ } void -reset_coarse_timers (struct context *c) +reset_coarse_timers(struct context *c) { - c->c2.coarse_timer_wakeup = 0; + c->c2.coarse_timer_wakeup = 0; } /* @@ -1093,59 +1167,73 @@ reset_coarse_timers (struct context *c) * before */ static void -do_init_server_poll_timeout (struct context *c) +do_init_server_poll_timeout(struct context *c) { - update_time (); + update_time(); if (c->options.ce.connect_timeout) - event_timeout_init (&c->c2.server_poll_interval, c->options.ce.connect_timeout, now); + { + event_timeout_init(&c->c2.server_poll_interval, c->options.ce.connect_timeout, now); + } } /* * Initialize timers */ static void -do_init_timers (struct context *c, bool deferred) +do_init_timers(struct context *c, bool deferred) { - update_time (); - reset_coarse_timers (c); + update_time(); + reset_coarse_timers(c); - /* initialize inactivity timeout */ - if (c->options.inactivity_timeout) - event_timeout_init (&c->c2.inactivity_interval, c->options.inactivity_timeout, now); + /* initialize inactivity timeout */ + if (c->options.inactivity_timeout) + { + event_timeout_init(&c->c2.inactivity_interval, c->options.inactivity_timeout, now); + } - /* initialize pings */ + /* initialize pings */ - if (c->options.ping_send_timeout) - event_timeout_init (&c->c2.ping_send_interval, c->options.ping_send_timeout, 0); + if (c->options.ping_send_timeout) + { + event_timeout_init(&c->c2.ping_send_interval, c->options.ping_send_timeout, 0); + } - if (c->options.ping_rec_timeout) - event_timeout_init (&c->c2.ping_rec_interval, c->options.ping_rec_timeout, now); + if (c->options.ping_rec_timeout) + { + event_timeout_init(&c->c2.ping_rec_interval, c->options.ping_rec_timeout, now); + } - if (!deferred) + if (!deferred) { - /* initialize connection establishment timer */ - event_timeout_init (&c->c2.wait_for_connect, 1, now); + /* initialize connection establishment timer */ + event_timeout_init(&c->c2.wait_for_connect, 1, now); #ifdef ENABLE_OCC - /* initialize occ timers */ + /* initialize occ timers */ - if (c->options.occ - && !TLS_MODE (c) - && c->c2.options_string_local && c->c2.options_string_remote) - event_timeout_init (&c->c2.occ_interval, OCC_INTERVAL_SECONDS, now); + if (c->options.occ + && !TLS_MODE(c) + && c->c2.options_string_local && c->c2.options_string_remote) + { + event_timeout_init(&c->c2.occ_interval, OCC_INTERVAL_SECONDS, now); + } - if (c->options.mtu_test) - event_timeout_init (&c->c2.occ_mtu_load_test_interval, OCC_MTU_LOAD_INTERVAL_SECONDS, now); + if (c->options.mtu_test) + { + event_timeout_init(&c->c2.occ_mtu_load_test_interval, OCC_MTU_LOAD_INTERVAL_SECONDS, now); + } #endif - /* initialize packet_id persistence timer */ + /* initialize packet_id persistence timer */ #ifdef ENABLE_CRYPTO - if (c->options.packet_id_file) - event_timeout_init (&c->c2.packet_id_persist_interval, 60, now); + if (c->options.packet_id_file) + { + event_timeout_init(&c->c2.packet_id_persist_interval, 60, now); + } - /* initialize tmp_int optimization that limits the number of times we call - tls_multi_process in the main event loop */ - interval_init (&c->c2.tmp_int, TLS_MULTI_HORIZON, TLS_MULTI_REFRESH); + /* initialize tmp_int optimization that limits the number of times we call + * tls_multi_process in the main event loop */ + interval_init(&c->c2.tmp_int, TLS_MULTI_HORIZON, TLS_MULTI_REFRESH); #endif } } @@ -1154,14 +1242,14 @@ do_init_timers (struct context *c, bool deferred) * Initialize traffic shaper. */ static void -do_init_traffic_shaper (struct context *c) +do_init_traffic_shaper(struct context *c) { #ifdef ENABLE_FEATURE_SHAPER - /* initialize traffic shaper (i.e. transmit bandwidth limiter) */ - if (c->options.shaper) + /* initialize traffic shaper (i.e. transmit bandwidth limiter) */ + if (c->options.shaper) { - shaper_init (&c->c2.shaper, c->options.shaper); - shaper_msg (&c->c2.shaper); + shaper_init(&c->c2.shaper, c->options.shaper); + shaper_msg(&c->c2.shaper); } #endif } @@ -1172,12 +1260,16 @@ do_init_traffic_shaper (struct context *c) * parts of OpenVPN might want to fill the route-list with info, e.g. DHCP) */ static void -do_alloc_route_list (struct context *c) +do_alloc_route_list(struct context *c) { - if (!c->c1.route_list) - ALLOC_OBJ_CLEAR_GC (c->c1.route_list, struct route_list, &c->gc); - if (c->options.routes_ipv6 && !c->c1.route_ipv6_list) - ALLOC_OBJ_CLEAR_GC (c->c1.route_ipv6_list, struct route_ipv6_list, &c->gc); + if (!c->c1.route_list) + { + ALLOC_OBJ_CLEAR_GC(c->c1.route_list, struct route_list, &c->gc); + } + if (c->options.routes_ipv6 && !c->c1.route_ipv6_list) + { + ALLOC_OBJ_CLEAR_GC(c->c1.route_ipv6_list, struct route_ipv6_list, &c->gc); + } } @@ -1186,76 +1278,86 @@ do_alloc_route_list (struct context *c) * options and saving routes in the environment. */ static void -do_init_route_list (const struct options *options, - struct route_list *route_list, - const struct link_socket_info *link_socket_info, - struct env_set *es) +do_init_route_list(const struct options *options, + struct route_list *route_list, + const struct link_socket_info *link_socket_info, + struct env_set *es) { - const char *gw = NULL; - int dev = dev_type_enum (options->dev, options->dev_type); - int metric = 0; + const char *gw = NULL; + int dev = dev_type_enum(options->dev, options->dev_type); + int metric = 0; - if (dev == DEV_TYPE_TUN && (options->topology == TOP_NET30 || options->topology == TOP_P2P)) - gw = options->ifconfig_remote_netmask; - if (options->route_default_gateway) - gw = options->route_default_gateway; - if (options->route_default_metric) - metric = options->route_default_metric; + if (dev == DEV_TYPE_TUN && (options->topology == TOP_NET30 || options->topology == TOP_P2P)) + { + gw = options->ifconfig_remote_netmask; + } + if (options->route_default_gateway) + { + gw = options->route_default_gateway; + } + if (options->route_default_metric) + { + metric = options->route_default_metric; + } - if (init_route_list (route_list, - options->routes, - gw, - metric, - link_socket_current_remote (link_socket_info), - es)) + if (init_route_list(route_list, + options->routes, + gw, + metric, + link_socket_current_remote(link_socket_info), + es)) { - /* copy routes to environment */ - setenv_routes (es, route_list); + /* copy routes to environment */ + setenv_routes(es, route_list); } } static void -do_init_route_ipv6_list (const struct options *options, - struct route_ipv6_list *route_ipv6_list, - const struct link_socket_info *link_socket_info, - struct env_set *es) +do_init_route_ipv6_list(const struct options *options, + struct route_ipv6_list *route_ipv6_list, + const struct link_socket_info *link_socket_info, + struct env_set *es) { - const char *gw = NULL; - int metric = -1; /* no metric set */ + const char *gw = NULL; + int metric = -1; /* no metric set */ - gw = options->ifconfig_ipv6_remote; /* default GW = remote end */ -#if 0 /* not yet done for IPv6 - TODO!*/ - if ( options->route_ipv6_default_gateway ) /* override? */ - gw = options->route_ipv6_default_gateway; + gw = options->ifconfig_ipv6_remote; /* default GW = remote end */ +#if 0 /* not yet done for IPv6 - TODO!*/ + if (options->route_ipv6_default_gateway) /* override? */ + { + gw = options->route_ipv6_default_gateway; + } #endif - if (options->route_default_metric) - metric = options->route_default_metric; + if (options->route_default_metric) + { + metric = options->route_default_metric; + } - /* redirect (IPv6) gateway to VPN? if yes, add a few more specifics - */ - if ( options->routes_ipv6->flags & RG_REROUTE_GW ) + /* redirect (IPv6) gateway to VPN? if yes, add a few more specifics + */ + if (options->routes_ipv6->flags & RG_REROUTE_GW) { - char *opt_list[] = { "::/3", "2000::/4", "3000::/4", "fc00::/7", NULL }; - int i; + char *opt_list[] = { "::/3", "2000::/4", "3000::/4", "fc00::/7", NULL }; + int i; - for (i=0; opt_list[i]; i++) - { - add_route_ipv6_to_option_list( options->routes_ipv6, - string_alloc (opt_list[i], options->routes_ipv6->gc), - NULL, NULL ); - } + for (i = 0; opt_list[i]; i++) + { + add_route_ipv6_to_option_list( options->routes_ipv6, + string_alloc(opt_list[i], options->routes_ipv6->gc), + NULL, NULL ); + } } - if (init_route_ipv6_list (route_ipv6_list, - options->routes_ipv6, - gw, - metric, - link_socket_current_remote_ipv6 (link_socket_info), - es)) + if (init_route_ipv6_list(route_ipv6_list, + options->routes_ipv6, + gw, + metric, + link_socket_current_remote_ipv6(link_socket_info), + es)) { - /* copy routes to environment */ - setenv_routes_ipv6 (es, route_ipv6_list); + /* copy routes to environment */ + setenv_routes_ipv6(es, route_ipv6_list); } } @@ -1264,98 +1366,105 @@ do_init_route_ipv6_list (const struct options *options, * Called after all initialization has been completed. */ void -initialization_sequence_completed (struct context *c, const unsigned int flags) +initialization_sequence_completed(struct context *c, const unsigned int flags) { - static const char message[] = "Initialization Sequence Completed"; + static const char message[] = "Initialization Sequence Completed"; - /* Reset the unsuccessful connection counter on complete initialisation */ - c->options.unsuccessful_attempts=0; + /* Reset the unsuccessful connection counter on complete initialisation */ + c->options.unsuccessful_attempts = 0; - /* If we delayed UID/GID downgrade or chroot, do it now */ - do_uid_gid_chroot (c, true); + /* If we delayed UID/GID downgrade or chroot, do it now */ + do_uid_gid_chroot(c, true); - /* Test if errors */ - if (flags & ISC_ERRORS) + /* Test if errors */ + if (flags & ISC_ERRORS) { #ifdef _WIN32 - show_routes (M_INFO|M_NOPREFIX); - show_adapters (M_INFO|M_NOPREFIX); - msg (M_INFO, "%s With Errors ( see http://openvpn.net/faq.html#dhcpclientserv )", message); + show_routes(M_INFO|M_NOPREFIX); + show_adapters(M_INFO|M_NOPREFIX); + msg(M_INFO, "%s With Errors ( see http://openvpn.net/faq.html#dhcpclientserv )", message); #else #ifdef ENABLE_SYSTEMD - sd_notifyf(0, "STATUS=Failed to start up: %s With Errors\nERRNO=1", message); + sd_notifyf(0, "STATUS=Failed to start up: %s With Errors\nERRNO=1", message); #endif /* HAVE_SYSTEMD_SD_DAEMON_H */ - msg (M_INFO, "%s With Errors", message); + msg(M_INFO, "%s With Errors", message); #endif } - else + else { #ifdef ENABLE_SYSTEMD - sd_notifyf(0, "READY=1\nSTATUS=%s\nMAINPID=%lu", message, (unsigned long) getpid()); + sd_notifyf(0, "READY=1\nSTATUS=%s\nMAINPID=%lu", message, (unsigned long) getpid()); #endif - msg (M_INFO, "%s", message); + msg(M_INFO, "%s", message); } - /* Flag that we initialized */ - if ((flags & (ISC_ERRORS|ISC_SERVER)) == 0) - c->options.no_advance=true; + /* Flag that we initialized */ + if ((flags & (ISC_ERRORS|ISC_SERVER)) == 0) + { + c->options.no_advance = true; + } #ifdef _WIN32 - fork_register_dns_action (c->c1.tuntap); + fork_register_dns_action(c->c1.tuntap); #endif #ifdef ENABLE_MANAGEMENT - /* Tell management interface that we initialized */ - if (management) - { - in_addr_t *tun_local = NULL; - struct in6_addr *tun_local6 = NULL; - struct openvpn_sockaddr local, remote; - struct link_socket_actual *actual; - socklen_t sa_len = sizeof(local); - const char *detail = "SUCCESS"; - if (flags & ISC_ERRORS) - detail = "ERROR"; - - CLEAR (local); - actual = &get_link_socket_info(c)->lsa->actual; - remote = actual->dest; - getsockname(c->c2.link_socket->sd, &local.addr.sa, &sa_len); + /* Tell management interface that we initialized */ + if (management) + { + in_addr_t *tun_local = NULL; + struct in6_addr *tun_local6 = NULL; + struct openvpn_sockaddr local, remote; + struct link_socket_actual *actual; + socklen_t sa_len = sizeof(local); + const char *detail = "SUCCESS"; + if (flags & ISC_ERRORS) + { + detail = "ERROR"; + } + + CLEAR(local); + actual = &get_link_socket_info(c)->lsa->actual; + remote = actual->dest; + getsockname(c->c2.link_socket->sd, &local.addr.sa, &sa_len); #if ENABLE_IP_PKTINFO - if (!addr_defined(&local)) + if (!addr_defined(&local)) { - switch (local.addr.sa.sa_family) + switch (local.addr.sa.sa_family) { - case AF_INET: + case AF_INET: #if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) - local.addr.in4.sin_addr = actual->pi.in4.ipi_spec_dst; + local.addr.in4.sin_addr = actual->pi.in4.ipi_spec_dst; #else - local.addr.in4.sin_addr = actual->pi.in4; + local.addr.in4.sin_addr = actual->pi.in4; #endif - break; - case AF_INET6: - local.addr.in6.sin6_addr = actual->pi.in6.ipi6_addr; - break; + break; + + case AF_INET6: + local.addr.in6.sin6_addr = actual->pi.in6.ipi6_addr; + break; } } #endif - if (c->c1.tuntap) + if (c->c1.tuntap) { - tun_local = &c->c1.tuntap->local; - tun_local6 = &c->c1.tuntap->local_ipv6; + tun_local = &c->c1.tuntap->local; + tun_local6 = &c->c1.tuntap->local_ipv6; + } + management_set_state(management, + OPENVPN_STATE_CONNECTED, + detail, + tun_local, + tun_local6, + &local, + &remote); + if (tun_local) + { + management_post_tunnel_open(management, *tun_local); } - management_set_state (management, - OPENVPN_STATE_CONNECTED, - detail, - tun_local, - tun_local6, - &local, - &remote); - if (tun_local) - management_post_tunnel_open (management, *tun_local); } -#endif +#endif /* ifdef ENABLE_MANAGEMENT */ } /* @@ -1363,48 +1472,52 @@ initialization_sequence_completed (struct context *c, const unsigned int flags) * based on options. */ void -do_route (const struct options *options, - struct route_list *route_list, - struct route_ipv6_list *route_ipv6_list, - const struct tuntap *tt, - const struct plugin_list *plugins, - struct env_set *es) +do_route(const struct options *options, + struct route_list *route_list, + struct route_ipv6_list *route_ipv6_list, + const struct tuntap *tt, + const struct plugin_list *plugins, + struct env_set *es) { - if (!options->route_noexec && ( route_list || route_ipv6_list ) ) + if (!options->route_noexec && ( route_list || route_ipv6_list ) ) { - add_routes (route_list, route_ipv6_list, tt, ROUTE_OPTION_FLAGS (options), es); - setenv_int (es, "redirect_gateway", route_did_redirect_default_gateway(route_list)); + add_routes(route_list, route_ipv6_list, tt, ROUTE_OPTION_FLAGS(options), es); + setenv_int(es, "redirect_gateway", route_did_redirect_default_gateway(route_list)); } #ifdef ENABLE_MANAGEMENT - if (management) - management_up_down (management, "UP", es); + if (management) + { + management_up_down(management, "UP", es); + } #endif - if (plugin_defined (plugins, OPENVPN_PLUGIN_ROUTE_UP)) + if (plugin_defined(plugins, OPENVPN_PLUGIN_ROUTE_UP)) { - if (plugin_call (plugins, OPENVPN_PLUGIN_ROUTE_UP, NULL, NULL, es) != OPENVPN_PLUGIN_FUNC_SUCCESS) - msg (M_WARN, "WARNING: route-up plugin call failed"); + if (plugin_call(plugins, OPENVPN_PLUGIN_ROUTE_UP, NULL, NULL, es) != OPENVPN_PLUGIN_FUNC_SUCCESS) + { + msg(M_WARN, "WARNING: route-up plugin call failed"); + } } - if (options->route_script) + if (options->route_script) { - struct argv argv = argv_new (); - setenv_str (es, "script_type", "route-up"); - argv_parse_cmd (&argv, options->route_script); - openvpn_run_script (&argv, es, 0, "--route-up"); - argv_reset (&argv); + struct argv argv = argv_new(); + setenv_str(es, "script_type", "route-up"); + argv_parse_cmd(&argv, options->route_script); + openvpn_run_script(&argv, es, 0, "--route-up"); + argv_reset(&argv); } #ifdef _WIN32 - if (options->show_net_up) + if (options->show_net_up) { - show_routes (M_INFO|M_NOPREFIX); - show_adapters (M_INFO|M_NOPREFIX); + show_routes(M_INFO|M_NOPREFIX); + show_adapters(M_INFO|M_NOPREFIX); } - else if (check_debug_level (D_SHOW_NET)) + else if (check_debug_level(D_SHOW_NET)) { - show_routes (D_SHOW_NET|M_NOPREFIX); - show_adapters (D_SHOW_NET|M_NOPREFIX); + show_routes(D_SHOW_NET|M_NOPREFIX); + show_adapters(D_SHOW_NET|M_NOPREFIX); } #endif } @@ -1413,26 +1526,26 @@ do_route (const struct options *options, * initialize tun/tap device object */ static void -do_init_tun (struct context *c) +do_init_tun(struct context *c) { - c->c1.tuntap = init_tun (c->options.dev, - c->options.dev_type, - c->options.topology, - c->options.ifconfig_local, - c->options.ifconfig_remote_netmask, - c->options.ifconfig_ipv6_local, - c->options.ifconfig_ipv6_netbits, - c->options.ifconfig_ipv6_remote, - c->c1.link_socket_addr.bind_local, - c->c1.link_socket_addr.remote_list, - !c->options.ifconfig_nowarn, - c->c2.es); - - init_tun_post (c->c1.tuntap, - &c->c2.frame, - &c->options.tuntap_options); - - c->c1.tuntap_owned = true; + c->c1.tuntap = init_tun(c->options.dev, + c->options.dev_type, + c->options.topology, + c->options.ifconfig_local, + c->options.ifconfig_remote_netmask, + c->options.ifconfig_ipv6_local, + c->options.ifconfig_ipv6_netbits, + c->options.ifconfig_ipv6_remote, + c->c1.link_socket_addr.bind_local, + c->c1.link_socket_addr.remote_list, + !c->options.ifconfig_nowarn, + c->c2.es); + + init_tun_post(c->c1.tuntap, + &c->c2.frame, + &c->options.tuntap_options); + + c->c1.tuntap_owned = true; } /* @@ -1440,166 +1553,185 @@ do_init_tun (struct context *c) */ static bool -do_open_tun (struct context *c) +do_open_tun(struct context *c) { - struct gc_arena gc = gc_new (); - bool ret = false; + struct gc_arena gc = gc_new(); + bool ret = false; #ifndef TARGET_ANDROID - if (!c->c1.tuntap) + if (!c->c1.tuntap) { #endif #ifdef TARGET_ANDROID - /* If we emulate persist-tun on android we still have to open a new tun and - * then close the old */ - int oldtunfd=-1; - if (c->c1.tuntap) - oldtunfd = c->c1.tuntap->fd; + /* If we emulate persist-tun on android we still have to open a new tun and + * then close the old */ + int oldtunfd = -1; + if (c->c1.tuntap) + { + oldtunfd = c->c1.tuntap->fd; + } #endif - /* initialize (but do not open) tun/tap object */ - do_init_tun (c); + /* initialize (but do not open) tun/tap object */ + do_init_tun(c); #ifdef _WIN32 - /* store (hide) interactive service handle in tuntap_options */ - c->c1.tuntap->options.msg_channel = c->options.msg_channel; - msg (D_ROUTE, "interactive service msg_channel=%u", (unsigned int) c->options.msg_channel); -#endif - - /* allocate route list structure */ - do_alloc_route_list (c); - - /* parse and resolve the route option list */ - ASSERT(c->c2.link_socket); - if (c->options.routes && c->c1.route_list) - do_init_route_list (&c->options, c->c1.route_list, - &c->c2.link_socket->info, c->c2.es); - if (c->options.routes_ipv6 && c->c1.route_ipv6_list) - do_init_route_ipv6_list (&c->options, c->c1.route_ipv6_list, - &c->c2.link_socket->info, c->c2.es); - - /* do ifconfig */ - if (!c->options.ifconfig_noexec - && ifconfig_order () == IFCONFIG_BEFORE_TUN_OPEN) - { - /* guess actual tun/tap unit number that will be returned - by open_tun */ - const char *guess = guess_tuntap_dev (c->options.dev, - c->options.dev_type, - c->options.dev_node, - &gc); - do_ifconfig (c->c1.tuntap, guess, TUN_MTU_SIZE (&c->c2.frame), c->c2.es); - } - - /* possibly add routes */ - if (route_order() == ROUTE_BEFORE_TUN) { + /* store (hide) interactive service handle in tuntap_options */ + c->c1.tuntap->options.msg_channel = c->options.msg_channel; + msg(D_ROUTE, "interactive service msg_channel=%u", (unsigned int) c->options.msg_channel); +#endif + + /* allocate route list structure */ + do_alloc_route_list(c); + + /* parse and resolve the route option list */ + ASSERT(c->c2.link_socket); + if (c->options.routes && c->c1.route_list) + { + do_init_route_list(&c->options, c->c1.route_list, + &c->c2.link_socket->info, c->c2.es); + } + if (c->options.routes_ipv6 && c->c1.route_ipv6_list) + { + do_init_route_ipv6_list(&c->options, c->c1.route_ipv6_list, + &c->c2.link_socket->info, c->c2.es); + } + + /* do ifconfig */ + if (!c->options.ifconfig_noexec + && ifconfig_order() == IFCONFIG_BEFORE_TUN_OPEN) + { + /* guess actual tun/tap unit number that will be returned + * by open_tun */ + const char *guess = guess_tuntap_dev(c->options.dev, + c->options.dev_type, + c->options.dev_node, + &gc); + do_ifconfig(c->c1.tuntap, guess, TUN_MTU_SIZE(&c->c2.frame), c->c2.es); + } + + /* possibly add routes */ + if (route_order() == ROUTE_BEFORE_TUN) + { /* Ignore route_delay, would cause ROUTE_BEFORE_TUN to be ignored */ - do_route (&c->options, c->c1.route_list, c->c1.route_ipv6_list, - c->c1.tuntap, c->plugins, c->c2.es); - } + do_route(&c->options, c->c1.route_list, c->c1.route_ipv6_list, + c->c1.tuntap, c->plugins, c->c2.es); + } #ifdef TARGET_ANDROID - /* Store the old fd inside the fd so open_tun can use it */ - c->c1.tuntap->fd = oldtunfd; -#endif - /* open the tun device */ - open_tun (c->options.dev, c->options.dev_type, c->options.dev_node, - c->c1.tuntap); - - /* set the hardware address */ - if (c->options.lladdr) - set_lladdr(c->c1.tuntap->actual_name, c->options.lladdr, c->c2.es); - - /* do ifconfig */ - if (!c->options.ifconfig_noexec - && ifconfig_order () == IFCONFIG_AFTER_TUN_OPEN) - { - do_ifconfig (c->c1.tuntap, c->c1.tuntap->actual_name, TUN_MTU_SIZE (&c->c2.frame), c->c2.es); - } - - /* run the up script */ - run_up_down (c->options.up_script, - c->plugins, - OPENVPN_PLUGIN_UP, - c->c1.tuntap->actual_name, + /* Store the old fd inside the fd so open_tun can use it */ + c->c1.tuntap->fd = oldtunfd; +#endif + /* open the tun device */ + open_tun(c->options.dev, c->options.dev_type, c->options.dev_node, + c->c1.tuntap); + + /* set the hardware address */ + if (c->options.lladdr) + { + set_lladdr(c->c1.tuntap->actual_name, c->options.lladdr, c->c2.es); + } + + /* do ifconfig */ + if (!c->options.ifconfig_noexec + && ifconfig_order() == IFCONFIG_AFTER_TUN_OPEN) + { + do_ifconfig(c->c1.tuntap, c->c1.tuntap->actual_name, TUN_MTU_SIZE(&c->c2.frame), c->c2.es); + } + + /* run the up script */ + run_up_down(c->options.up_script, + c->plugins, + OPENVPN_PLUGIN_UP, + c->c1.tuntap->actual_name, #ifdef _WIN32 - c->c1.tuntap->adapter_index, -#endif - dev_type_string (c->options.dev, c->options.dev_type), - TUN_MTU_SIZE (&c->c2.frame), - EXPANDED_SIZE (&c->c2.frame), - print_in_addr_t (c->c1.tuntap->local, IA_EMPTY_IF_UNDEF, &gc), - print_in_addr_t (c->c1.tuntap->remote_netmask, IA_EMPTY_IF_UNDEF, &gc), - "init", - NULL, - "up", - c->c2.es); + c->c1.tuntap->adapter_index, +#endif + dev_type_string(c->options.dev, c->options.dev_type), + TUN_MTU_SIZE(&c->c2.frame), + EXPANDED_SIZE(&c->c2.frame), + print_in_addr_t(c->c1.tuntap->local, IA_EMPTY_IF_UNDEF, &gc), + print_in_addr_t(c->c1.tuntap->remote_netmask, IA_EMPTY_IF_UNDEF, &gc), + "init", + NULL, + "up", + c->c2.es); #if defined(_WIN32) - if (c->options.block_outside_dns) - { - dmsg (D_LOW, "Blocking outside DNS"); + if (c->options.block_outside_dns) + { + dmsg(D_LOW, "Blocking outside DNS"); if (!win_wfp_block_dns(c->c1.tuntap->adapter_index, c->options.msg_channel)) - msg (M_FATAL, "Blocking DNS failed!"); - } + { + msg(M_FATAL, "Blocking DNS failed!"); + } + } #endif - /* possibly add routes */ - if ((route_order() == ROUTE_AFTER_TUN) && (!c->options.route_delay_defined)) - do_route (&c->options, c->c1.route_list, c->c1.route_ipv6_list, - c->c1.tuntap, c->plugins, c->c2.es); + /* possibly add routes */ + if ((route_order() == ROUTE_AFTER_TUN) && (!c->options.route_delay_defined)) + { + do_route(&c->options, c->c1.route_list, c->c1.route_ipv6_list, + c->c1.tuntap, c->plugins, c->c2.es); + } - /* - * Did tun/tap driver give us an MTU? - */ - if (c->c1.tuntap->post_open_mtu) - frame_set_mtu_dynamic (&c->c2.frame, - c->c1.tuntap->post_open_mtu, - SET_MTU_TUN | SET_MTU_UPPER_BOUND); + /* + * Did tun/tap driver give us an MTU? + */ + if (c->c1.tuntap->post_open_mtu) + { + frame_set_mtu_dynamic(&c->c2.frame, + c->c1.tuntap->post_open_mtu, + SET_MTU_TUN | SET_MTU_UPPER_BOUND); + } - ret = true; - static_context = c; + ret = true; + static_context = c; #ifndef TARGET_ANDROID - } - else - { - msg (M_INFO, "Preserving previous TUN/TAP instance: %s", - c->c1.tuntap->actual_name); +} +else +{ + msg(M_INFO, "Preserving previous TUN/TAP instance: %s", + c->c1.tuntap->actual_name); - /* explicitly set the ifconfig_* env vars */ - do_ifconfig_setenv(c->c1.tuntap, c->c2.es); + /* explicitly set the ifconfig_* env vars */ + do_ifconfig_setenv(c->c1.tuntap, c->c2.es); - /* run the up script if user specified --up-restart */ - if (c->options.up_restart) - run_up_down (c->options.up_script, - c->plugins, - OPENVPN_PLUGIN_UP, - c->c1.tuntap->actual_name, + /* run the up script if user specified --up-restart */ + if (c->options.up_restart) + { + run_up_down(c->options.up_script, + c->plugins, + OPENVPN_PLUGIN_UP, + c->c1.tuntap->actual_name, #ifdef _WIN32 - c->c1.tuntap->adapter_index, -#endif - dev_type_string (c->options.dev, c->options.dev_type), - TUN_MTU_SIZE (&c->c2.frame), - EXPANDED_SIZE (&c->c2.frame), - print_in_addr_t (c->c1.tuntap->local, IA_EMPTY_IF_UNDEF, &gc), - print_in_addr_t (c->c1.tuntap->remote_netmask, IA_EMPTY_IF_UNDEF, &gc), - "restart", - NULL, - "up", - c->c2.es); + c->c1.tuntap->adapter_index, +#endif + dev_type_string(c->options.dev, c->options.dev_type), + TUN_MTU_SIZE(&c->c2.frame), + EXPANDED_SIZE(&c->c2.frame), + print_in_addr_t(c->c1.tuntap->local, IA_EMPTY_IF_UNDEF, &gc), + print_in_addr_t(c->c1.tuntap->remote_netmask, IA_EMPTY_IF_UNDEF, &gc), + "restart", + NULL, + "up", + c->c2.es); + } #if defined(_WIN32) - if (c->options.block_outside_dns) + if (c->options.block_outside_dns) + { + dmsg(D_LOW, "Blocking outside DNS"); + if (!win_wfp_block_dns(c->c1.tuntap->adapter_index, c->options.msg_channel)) { - dmsg (D_LOW, "Blocking outside DNS"); - if (!win_wfp_block_dns(c->c1.tuntap->adapter_index, c->options.msg_channel)) - msg (M_FATAL, "Blocking DNS failed!"); + msg(M_FATAL, "Blocking DNS failed!"); } -#endif - } #endif - gc_free (&gc); - return ret; + +} +#endif /* ifndef TARGET_ANDROID */ + gc_free(&gc); + return ret; } /* @@ -1607,147 +1739,157 @@ do_open_tun (struct context *c) */ static void -do_close_tun_simple (struct context *c) +do_close_tun_simple(struct context *c) { - msg (D_CLOSE, "Closing TUN/TAP interface"); - close_tun (c->c1.tuntap); - c->c1.tuntap = NULL; - c->c1.tuntap_owned = false; + msg(D_CLOSE, "Closing TUN/TAP interface"); + close_tun(c->c1.tuntap); + c->c1.tuntap = NULL; + c->c1.tuntap_owned = false; #if P2MP - CLEAR (c->c1.pulled_options_digest_save); + CLEAR(c->c1.pulled_options_digest_save); #endif } static void -do_close_tun (struct context *c, bool force) +do_close_tun(struct context *c, bool force) { - struct gc_arena gc = gc_new (); - if (c->c1.tuntap && c->c1.tuntap_owned) + struct gc_arena gc = gc_new(); + if (c->c1.tuntap && c->c1.tuntap_owned) { - const char *tuntap_actual = string_alloc (c->c1.tuntap->actual_name, &gc); + const char *tuntap_actual = string_alloc(c->c1.tuntap->actual_name, &gc); #ifdef _WIN32 - DWORD adapter_index = c->c1.tuntap->adapter_index; + DWORD adapter_index = c->c1.tuntap->adapter_index; #endif - const in_addr_t local = c->c1.tuntap->local; - const in_addr_t remote_netmask = c->c1.tuntap->remote_netmask; + const in_addr_t local = c->c1.tuntap->local; + const in_addr_t remote_netmask = c->c1.tuntap->remote_netmask; - if (force || !(c->sig->signal_received == SIGUSR1 && c->options.persist_tun)) - { - static_context = NULL; + if (force || !(c->sig->signal_received == SIGUSR1 && c->options.persist_tun)) + { + static_context = NULL; #ifdef ENABLE_MANAGEMENT - /* tell management layer we are about to close the TUN/TAP device */ - if (management) - { - management_pre_tunnel_close (management); - management_up_down (management, "DOWN", c->c2.es); - } -#endif - - /* delete any routes we added */ - if (c->c1.route_list || c->c1.route_ipv6_list ) - { - run_up_down (c->options.route_predown_script, - c->plugins, - OPENVPN_PLUGIN_ROUTE_PREDOWN, - tuntap_actual, + /* tell management layer we are about to close the TUN/TAP device */ + if (management) + { + management_pre_tunnel_close(management); + management_up_down(management, "DOWN", c->c2.es); + } +#endif + + /* delete any routes we added */ + if (c->c1.route_list || c->c1.route_ipv6_list) + { + run_up_down(c->options.route_predown_script, + c->plugins, + OPENVPN_PLUGIN_ROUTE_PREDOWN, + tuntap_actual, #ifdef _WIN32 - adapter_index, -#endif - NULL, - TUN_MTU_SIZE (&c->c2.frame), - EXPANDED_SIZE (&c->c2.frame), - print_in_addr_t (local, IA_EMPTY_IF_UNDEF, &gc), - print_in_addr_t (remote_netmask, IA_EMPTY_IF_UNDEF, &gc), - "init", - signal_description (c->sig->signal_received, + adapter_index, +#endif + NULL, + TUN_MTU_SIZE(&c->c2.frame), + EXPANDED_SIZE(&c->c2.frame), + print_in_addr_t(local, IA_EMPTY_IF_UNDEF, &gc), + print_in_addr_t(remote_netmask, IA_EMPTY_IF_UNDEF, &gc), + "init", + signal_description(c->sig->signal_received, c->sig->signal_text), - "route-pre-down", - c->c2.es); + "route-pre-down", + c->c2.es); - delete_routes (c->c1.route_list, c->c1.route_ipv6_list, - c->c1.tuntap, ROUTE_OPTION_FLAGS (&c->options), c->c2.es); + delete_routes(c->c1.route_list, c->c1.route_ipv6_list, + c->c1.tuntap, ROUTE_OPTION_FLAGS(&c->options), c->c2.es); } - /* actually close tun/tap device based on --down-pre flag */ - if (!c->options.down_pre) - do_close_tun_simple (c); + /* actually close tun/tap device based on --down-pre flag */ + if (!c->options.down_pre) + { + do_close_tun_simple(c); + } - /* Run the down script -- note that it will run at reduced - privilege if, for example, "--user nobody" was used. */ - run_up_down (c->options.down_script, - c->plugins, - OPENVPN_PLUGIN_DOWN, - tuntap_actual, + /* Run the down script -- note that it will run at reduced + * privilege if, for example, "--user nobody" was used. */ + run_up_down(c->options.down_script, + c->plugins, + OPENVPN_PLUGIN_DOWN, + tuntap_actual, #ifdef _WIN32 - adapter_index, -#endif - NULL, - TUN_MTU_SIZE (&c->c2.frame), - EXPANDED_SIZE (&c->c2.frame), - print_in_addr_t (local, IA_EMPTY_IF_UNDEF, &gc), - print_in_addr_t (remote_netmask, IA_EMPTY_IF_UNDEF, &gc), - "init", - signal_description (c->sig->signal_received, - c->sig->signal_text), - "down", - c->c2.es); + adapter_index, +#endif + NULL, + TUN_MTU_SIZE(&c->c2.frame), + EXPANDED_SIZE(&c->c2.frame), + print_in_addr_t(local, IA_EMPTY_IF_UNDEF, &gc), + print_in_addr_t(remote_netmask, IA_EMPTY_IF_UNDEF, &gc), + "init", + signal_description(c->sig->signal_received, + c->sig->signal_text), + "down", + c->c2.es); #if defined(_WIN32) if (c->options.block_outside_dns) { if (!win_wfp_uninit(c->options.msg_channel)) - msg (M_FATAL, "Uninitialising WFP failed!"); + { + msg(M_FATAL, "Uninitialising WFP failed!"); + } } #endif - /* actually close tun/tap device based on --down-pre flag */ - if (c->options.down_pre) - do_close_tun_simple (c); - } - else - { - /* run the down script on this restart if --up-restart was specified */ - if (c->options.up_restart) - run_up_down (c->options.down_script, - c->plugins, - OPENVPN_PLUGIN_DOWN, - tuntap_actual, + /* actually close tun/tap device based on --down-pre flag */ + if (c->options.down_pre) + { + do_close_tun_simple(c); + } + } + else + { + /* run the down script on this restart if --up-restart was specified */ + if (c->options.up_restart) + { + run_up_down(c->options.down_script, + c->plugins, + OPENVPN_PLUGIN_DOWN, + tuntap_actual, #ifdef _WIN32 - adapter_index, -#endif - NULL, - TUN_MTU_SIZE (&c->c2.frame), - EXPANDED_SIZE (&c->c2.frame), - print_in_addr_t (local, IA_EMPTY_IF_UNDEF, &gc), - print_in_addr_t (remote_netmask, IA_EMPTY_IF_UNDEF, &gc), - "restart", - signal_description (c->sig->signal_received, - c->sig->signal_text), - "down", - c->c2.es); + adapter_index, +#endif + NULL, + TUN_MTU_SIZE(&c->c2.frame), + EXPANDED_SIZE(&c->c2.frame), + print_in_addr_t(local, IA_EMPTY_IF_UNDEF, &gc), + print_in_addr_t(remote_netmask, IA_EMPTY_IF_UNDEF, &gc), + "restart", + signal_description(c->sig->signal_received, + c->sig->signal_text), + "down", + c->c2.es); + } #if defined(_WIN32) - if (c->options.block_outside_dns) + if (c->options.block_outside_dns) { - if (!win_wfp_uninit(c->options.msg_channel)) - msg (M_FATAL, "Uninitialising WFP failed!"); + if (!win_wfp_uninit(c->options.msg_channel)) + { + msg(M_FATAL, "Uninitialising WFP failed!"); + } } #endif - } + } } - gc_free (&gc); + gc_free(&gc); } void tun_abort() { - struct context *c = static_context; - if (c) + struct context *c = static_context; + if (c) { - static_context = NULL; - do_close_tun (c, true); + static_context = NULL; + do_close_tun(c, true); } } @@ -1762,232 +1904,252 @@ tun_abort() */ static bool options_hash_changed_or_zero(const struct md5_digest *a, - const struct md5_digest *b) + const struct md5_digest *b) { - const struct md5_digest zero = {{0}}; - return memcmp (a, b, sizeof(struct md5_digest)) || - !memcmp (a, &zero, sizeof(struct md5_digest)); + const struct md5_digest zero = {{0}}; + return memcmp(a, b, sizeof(struct md5_digest)) + || !memcmp(a, &zero, sizeof(struct md5_digest)); } #endif /* P2MP */ bool -do_up (struct context *c, bool pulled_options, unsigned int option_types_found) +do_up(struct context *c, bool pulled_options, unsigned int option_types_found) { - if (!c->c2.do_up_ran) + if (!c->c2.do_up_ran) { - reset_coarse_timers (c); + reset_coarse_timers(c); - if (pulled_options && option_types_found) - { - if (!do_deferred_options (c, option_types_found)) - { - msg (D_PUSH_ERRORS, "ERROR: Failed to apply push options"); - return false; - } - } + if (pulled_options && option_types_found) + { + if (!do_deferred_options(c, option_types_found)) + { + msg(D_PUSH_ERRORS, "ERROR: Failed to apply push options"); + return false; + } + } - /* if --up-delay specified, open tun, do ifconfig, and run up script now */ - if (c->options.up_delay || PULL_DEFINED (&c->options)) - { - c->c2.did_open_tun = do_open_tun (c); - update_time (); + /* if --up-delay specified, open tun, do ifconfig, and run up script now */ + if (c->options.up_delay || PULL_DEFINED(&c->options)) + { + c->c2.did_open_tun = do_open_tun(c); + update_time(); #if P2MP - /* - * Was tun interface object persisted from previous restart iteration, - * and if so did pulled options string change from previous iteration? - */ - if (!c->c2.did_open_tun - && PULL_DEFINED (&c->options) - && c->c1.tuntap - && options_hash_changed_or_zero (&c->c1.pulled_options_digest_save, - &c->c2.pulled_options_digest)) - { - /* if so, close tun, delete routes, then reinitialize tun and add routes */ - msg (M_INFO, "NOTE: Pulled options changed on restart, will need to close and reopen TUN/TAP device."); - do_close_tun (c, true); - openvpn_sleep (1); - c->c2.did_open_tun = do_open_tun (c); - update_time (); - } -#endif - } - - if (c->c2.did_open_tun) - { + /* + * Was tun interface object persisted from previous restart iteration, + * and if so did pulled options string change from previous iteration? + */ + if (!c->c2.did_open_tun + && PULL_DEFINED(&c->options) + && c->c1.tuntap + && options_hash_changed_or_zero(&c->c1.pulled_options_digest_save, + &c->c2.pulled_options_digest)) + { + /* if so, close tun, delete routes, then reinitialize tun and add routes */ + msg(M_INFO, "NOTE: Pulled options changed on restart, will need to close and reopen TUN/TAP device."); + do_close_tun(c, true); + openvpn_sleep(1); + c->c2.did_open_tun = do_open_tun(c); + update_time(); + } +#endif + } + + if (c->c2.did_open_tun) + { #if P2MP - c->c1.pulled_options_digest_save = c->c2.pulled_options_digest; -#endif - - /* if --route-delay was specified, start timer */ - if ((route_order() == ROUTE_AFTER_TUN) && c->options.route_delay_defined) - { - event_timeout_init (&c->c2.route_wakeup, c->options.route_delay, now); - event_timeout_init (&c->c2.route_wakeup_expire, c->options.route_delay + c->options.route_delay_window, now); - if (c->c1.tuntap) - tun_standby_init (c->c1.tuntap); - } - else - { - initialization_sequence_completed (c, 0); /* client/p2p --route-delay undefined */ - } - } - else if (c->options.mode == MODE_POINT_TO_POINT) - { - initialization_sequence_completed (c, 0); /* client/p2p restart with --persist-tun */ - } - - c->c2.do_up_ran = true; - } - return true; + c->c1.pulled_options_digest_save = c->c2.pulled_options_digest; +#endif + + /* if --route-delay was specified, start timer */ + if ((route_order() == ROUTE_AFTER_TUN) && c->options.route_delay_defined) + { + event_timeout_init(&c->c2.route_wakeup, c->options.route_delay, now); + event_timeout_init(&c->c2.route_wakeup_expire, c->options.route_delay + c->options.route_delay_window, now); + if (c->c1.tuntap) + { + tun_standby_init(c->c1.tuntap); + } + } + else + { + initialization_sequence_completed(c, 0); /* client/p2p --route-delay undefined */ + } + } + else if (c->options.mode == MODE_POINT_TO_POINT) + { + initialization_sequence_completed(c, 0); /* client/p2p restart with --persist-tun */ + } + + c->c2.do_up_ran = true; + } + return true; } /* * These are the option categories which will be accepted by pull. */ unsigned int -pull_permission_mask (const struct context *c) -{ - unsigned int flags = - OPT_P_UP - | OPT_P_ROUTE_EXTRAS - | OPT_P_SOCKBUF - | OPT_P_SOCKFLAGS - | OPT_P_SETENV - | OPT_P_SHAPER - | OPT_P_TIMER - | OPT_P_COMP - | OPT_P_PERSIST - | OPT_P_MESSAGES - | OPT_P_EXPLICIT_NOTIFY - | OPT_P_ECHO - | OPT_P_PULL_MODE - | OPT_P_PEER_ID; - - if (!c->options.route_nopull) - flags |= (OPT_P_ROUTE | OPT_P_IPWIN32); +pull_permission_mask(const struct context *c) +{ + unsigned int flags = + OPT_P_UP + | OPT_P_ROUTE_EXTRAS + | OPT_P_SOCKBUF + | OPT_P_SOCKFLAGS + | OPT_P_SETENV + | OPT_P_SHAPER + | OPT_P_TIMER + | OPT_P_COMP + | OPT_P_PERSIST + | OPT_P_MESSAGES + | OPT_P_EXPLICIT_NOTIFY + | OPT_P_ECHO + | OPT_P_PULL_MODE + | OPT_P_PEER_ID; + + if (!c->options.route_nopull) + { + flags |= (OPT_P_ROUTE | OPT_P_IPWIN32); + } #ifdef ENABLE_CRYPTO - if (c->options.ncp_enabled) - flags |= OPT_P_NCP; + if (c->options.ncp_enabled) + { + flags |= OPT_P_NCP; + } #endif - return flags; + return flags; } /* * Handle non-tun-related pulled options. */ bool -do_deferred_options (struct context *c, const unsigned int found) +do_deferred_options(struct context *c, const unsigned int found) { - if (found & OPT_P_MESSAGES) + if (found & OPT_P_MESSAGES) { - init_verb_mute (c, IVM_LEVEL_1|IVM_LEVEL_2); - msg (D_PUSH, "OPTIONS IMPORT: --verb and/or --mute level changed"); + init_verb_mute(c, IVM_LEVEL_1|IVM_LEVEL_2); + msg(D_PUSH, "OPTIONS IMPORT: --verb and/or --mute level changed"); } - if (found & OPT_P_TIMER) + if (found & OPT_P_TIMER) { - do_init_timers (c, true); - msg (D_PUSH, "OPTIONS IMPORT: timers and/or timeouts modified"); + do_init_timers(c, true); + msg(D_PUSH, "OPTIONS IMPORT: timers and/or timeouts modified"); } #ifdef ENABLE_OCC - if (found & OPT_P_EXPLICIT_NOTIFY) + if (found & OPT_P_EXPLICIT_NOTIFY) { - if (!proto_is_udp(c->options.ce.proto) && c->options.ce.explicit_exit_notification) - { - msg (D_PUSH, "OPTIONS IMPORT: --explicit-exit-notify can only be used with --proto udp"); - c->options.ce.explicit_exit_notification = 0; - } - else - msg (D_PUSH, "OPTIONS IMPORT: explicit notify parm(s) modified"); + if (!proto_is_udp(c->options.ce.proto) && c->options.ce.explicit_exit_notification) + { + msg(D_PUSH, "OPTIONS IMPORT: --explicit-exit-notify can only be used with --proto udp"); + c->options.ce.explicit_exit_notification = 0; + } + else + { + msg(D_PUSH, "OPTIONS IMPORT: explicit notify parm(s) modified"); + } } #endif #ifdef USE_COMP - if (found & OPT_P_COMP) + if (found & OPT_P_COMP) { - msg (D_PUSH, "OPTIONS IMPORT: compression parms modified"); - comp_uninit (c->c2.comp_context); - c->c2.comp_context = comp_init (&c->options.comp); + msg(D_PUSH, "OPTIONS IMPORT: compression parms modified"); + comp_uninit(c->c2.comp_context); + c->c2.comp_context = comp_init(&c->options.comp); } #endif - if (found & OPT_P_SHAPER) + if (found & OPT_P_SHAPER) { - msg (D_PUSH, "OPTIONS IMPORT: traffic shaper enabled"); - do_init_traffic_shaper (c); + msg(D_PUSH, "OPTIONS IMPORT: traffic shaper enabled"); + do_init_traffic_shaper(c); } - if (found & OPT_P_SOCKBUF) + if (found & OPT_P_SOCKBUF) { - msg (D_PUSH, "OPTIONS IMPORT: --sndbuf/--rcvbuf options modified"); - link_socket_update_buffer_sizes (c->c2.link_socket, c->options.rcvbuf, c->options.sndbuf); + msg(D_PUSH, "OPTIONS IMPORT: --sndbuf/--rcvbuf options modified"); + link_socket_update_buffer_sizes(c->c2.link_socket, c->options.rcvbuf, c->options.sndbuf); } - if (found & OPT_P_SOCKFLAGS) + if (found & OPT_P_SOCKFLAGS) { - msg (D_PUSH, "OPTIONS IMPORT: --socket-flags option modified"); - link_socket_update_flags (c->c2.link_socket, c->options.sockflags); + msg(D_PUSH, "OPTIONS IMPORT: --socket-flags option modified"); + link_socket_update_flags(c->c2.link_socket, c->options.sockflags); } - if (found & OPT_P_PERSIST) - msg (D_PUSH, "OPTIONS IMPORT: --persist options modified"); - if (found & OPT_P_UP) - msg (D_PUSH, "OPTIONS IMPORT: --ifconfig/up options modified"); - if (found & OPT_P_ROUTE) - msg (D_PUSH, "OPTIONS IMPORT: route options modified"); - if (found & OPT_P_ROUTE_EXTRAS) - msg (D_PUSH, "OPTIONS IMPORT: route-related options modified"); - if (found & OPT_P_IPWIN32) - msg (D_PUSH, "OPTIONS IMPORT: --ip-win32 and/or --dhcp-option options modified"); - if (found & OPT_P_SETENV) - msg (D_PUSH, "OPTIONS IMPORT: environment modified"); + if (found & OPT_P_PERSIST) + { + msg(D_PUSH, "OPTIONS IMPORT: --persist options modified"); + } + if (found & OPT_P_UP) + { + msg(D_PUSH, "OPTIONS IMPORT: --ifconfig/up options modified"); + } + if (found & OPT_P_ROUTE) + { + msg(D_PUSH, "OPTIONS IMPORT: route options modified"); + } + if (found & OPT_P_ROUTE_EXTRAS) + { + msg(D_PUSH, "OPTIONS IMPORT: route-related options modified"); + } + if (found & OPT_P_IPWIN32) + { + msg(D_PUSH, "OPTIONS IMPORT: --ip-win32 and/or --dhcp-option options modified"); + } + if (found & OPT_P_SETENV) + { + msg(D_PUSH, "OPTIONS IMPORT: environment modified"); + } #ifdef ENABLE_CRYPTO - if (found & OPT_P_PEER_ID) - { - msg (D_PUSH, "OPTIONS IMPORT: peer-id set"); - c->c2.tls_multi->use_peer_id = true; - c->c2.tls_multi->peer_id = c->options.peer_id; - frame_add_to_extra_frame(&c->c2.frame, +3); /* peer-id overhead */ - if ( !c->options.ce.link_mtu_defined ) - { - frame_add_to_link_mtu(&c->c2.frame, +3); - msg (D_PUSH, "OPTIONS IMPORT: adjusting link_mtu to %d", - EXPANDED_SIZE(&c->c2.frame)); - } - else - { - msg (M_WARN, "OPTIONS IMPORT: WARNING: peer-id set, but link-mtu" - " fixed by config - reducing tun-mtu to %d, expect" - " MTU problems", TUN_MTU_SIZE(&c->c2.frame) ); - } - } - - /* process (potentially pushed) crypto options */ - if (c->options.pull) - { - struct tls_session *session = &c->c2.tls_multi->session[TM_ACTIVE]; - if (found & OPT_P_NCP) - { - msg (D_PUSH, "OPTIONS IMPORT: data channel crypto options modified"); - } - else if (c->options.ncp_enabled) - { - tls_poor_mans_ncp(&c->options, c->c2.tls_multi->remote_ciphername); - } - /* Do not regenerate keys if server sends an extra push reply */ - if (!session->key[KS_PRIMARY].crypto_options.key_ctx_bi.initialized && - !tls_session_update_crypto_params(session, &c->options, &c->c2.frame)) - { - msg (D_TLS_ERRORS, "OPTIONS ERROR: failed to import crypto options"); - return false; - } - } -#endif - return true; + if (found & OPT_P_PEER_ID) + { + msg(D_PUSH, "OPTIONS IMPORT: peer-id set"); + c->c2.tls_multi->use_peer_id = true; + c->c2.tls_multi->peer_id = c->options.peer_id; + frame_add_to_extra_frame(&c->c2.frame, +3); /* peer-id overhead */ + if (!c->options.ce.link_mtu_defined) + { + frame_add_to_link_mtu(&c->c2.frame, +3); + msg(D_PUSH, "OPTIONS IMPORT: adjusting link_mtu to %d", + EXPANDED_SIZE(&c->c2.frame)); + } + else + { + msg(M_WARN, "OPTIONS IMPORT: WARNING: peer-id set, but link-mtu" + " fixed by config - reducing tun-mtu to %d, expect" + " MTU problems", TUN_MTU_SIZE(&c->c2.frame) ); + } + } + + /* process (potentially pushed) crypto options */ + if (c->options.pull) + { + struct tls_session *session = &c->c2.tls_multi->session[TM_ACTIVE]; + if (found & OPT_P_NCP) + { + msg(D_PUSH, "OPTIONS IMPORT: data channel crypto options modified"); + } + else if (c->options.ncp_enabled) + { + tls_poor_mans_ncp(&c->options, c->c2.tls_multi->remote_ciphername); + } + /* Do not regenerate keys if server sends an extra push reply */ + if (!session->key[KS_PRIMARY].crypto_options.key_ctx_bi.initialized + && !tls_session_update_crypto_params(session, &c->options, &c->c2.frame)) + { + msg(D_TLS_ERRORS, "OPTIONS ERROR: failed to import crypto options"); + return false; + } + } +#endif /* ifdef ENABLE_CRYPTO */ + return true; } /* @@ -1995,79 +2157,92 @@ do_deferred_options (struct context *c, const unsigned int found) * time OpenVPN would wait without management */ static bool -do_hold (int holdtime) +do_hold(int holdtime) { #ifdef ENABLE_MANAGEMENT - if (management) + if (management) { - /* block until management hold is released */ - if (management_hold (management, holdtime)) - return true; + /* block until management hold is released */ + if (management_hold(management, holdtime)) + { + return true; + } } #endif - return false; + return false; } /* * Sleep before restart. */ static void -socket_restart_pause (struct context *c) +socket_restart_pause(struct context *c) { - int sec = 2; - int backoff = 0; + int sec = 2; + int backoff = 0; - switch (c->options.ce.proto) + switch (c->options.ce.proto) { - case PROTO_TCP_SERVER: - sec = 1; - break; - case PROTO_UDP: - case PROTO_TCP_CLIENT: - sec = c->options.ce.connect_retry_seconds; - break; + case PROTO_TCP_SERVER: + sec = 1; + break; + + case PROTO_UDP: + case PROTO_TCP_CLIENT: + sec = c->options.ce.connect_retry_seconds; + break; } #ifdef ENABLE_DEBUG - if (GREMLIN_CONNECTION_FLOOD_LEVEL (c->options.gremlin)) - sec = 0; + if (GREMLIN_CONNECTION_FLOOD_LEVEL(c->options.gremlin)) + { + sec = 0; + } #endif #if P2MP - if (auth_retry_get () == AR_NOINTERACT) - sec = 10; + if (auth_retry_get() == AR_NOINTERACT) + { + sec = 10; + } #endif - /* Slow down reconnection after 5 retries per remote -- for tcp only in client mode */ - if (c->options.ce.proto != PROTO_TCP_SERVER) + /* Slow down reconnection after 5 retries per remote -- for tcp only in client mode */ + if (c->options.ce.proto != PROTO_TCP_SERVER) { - backoff = (c->options.unsuccessful_attempts / c->options.connection_list->len) - 4; - if (backoff > 0) + backoff = (c->options.unsuccessful_attempts / c->options.connection_list->len) - 4; + if (backoff > 0) { - /* sec is less than 2^16; we can left shift it by up to 15 bits without overflow */ - sec = max_int (sec, 1) << min_int (backoff, 15); + /* sec is less than 2^16; we can left shift it by up to 15 bits without overflow */ + sec = max_int(sec, 1) << min_int(backoff, 15); } - if (sec > c->options.ce.connect_retry_seconds_max) - sec = c->options.ce.connect_retry_seconds_max; + if (sec > c->options.ce.connect_retry_seconds_max) + { + sec = c->options.ce.connect_retry_seconds_max; + } } - if (c->persist.restart_sleep_seconds > 0 && c->persist.restart_sleep_seconds > sec) - sec = c->persist.restart_sleep_seconds; - else if (c->persist.restart_sleep_seconds == -1) - sec = 0; - c->persist.restart_sleep_seconds = 0; + if (c->persist.restart_sleep_seconds > 0 && c->persist.restart_sleep_seconds > sec) + { + sec = c->persist.restart_sleep_seconds; + } + else if (c->persist.restart_sleep_seconds == -1) + { + sec = 0; + } + c->persist.restart_sleep_seconds = 0; - /* do managment hold on context restart, i.e. second, third, fourth, etc. initialization */ - if (do_hold (sec)) - { - sec = 0; - } + /* do managment hold on context restart, i.e. second, third, fourth, etc. initialization */ + if (do_hold(sec)) + { + sec = 0; + } - if (sec) + if (sec) { - msg (D_RESTART, "Restart pause, %d second(s)", sec); - openvpn_sleep (sec); + msg(D_RESTART, "Restart pause, %d second(s)", sec); + openvpn_sleep(sec); } } @@ -2075,79 +2250,91 @@ socket_restart_pause (struct context *c) * Do a possible pause on context_2 initialization. */ static void -do_startup_pause (struct context *c) +do_startup_pause(struct context *c) { - if (!c->first_time) - socket_restart_pause (c); - else - do_hold (0); /* do management hold on first context initialization */ + if (!c->first_time) + { + socket_restart_pause(c); + } + else + { + do_hold(0); /* do management hold on first context initialization */ + } } /* * Finalize MTU parameters based on command line or config file options. */ static void -frame_finalize_options (struct context *c, const struct options *o) +frame_finalize_options(struct context *c, const struct options *o) { - if (!o) - o = &c->options; + if (!o) + { + o = &c->options; + } - /* - * Set adjustment factor for buffer alignment when no - * cipher is used. - */ - if (!CIPHER_ENABLED (c)) + /* + * Set adjustment factor for buffer alignment when no + * cipher is used. + */ + if (!CIPHER_ENABLED(c)) { - frame_align_to_extra_frame (&c->c2.frame); - frame_or_align_flags (&c->c2.frame, - FRAME_HEADROOM_MARKER_FRAGMENT - |FRAME_HEADROOM_MARKER_READ_LINK - |FRAME_HEADROOM_MARKER_READ_STREAM); + frame_align_to_extra_frame(&c->c2.frame); + frame_or_align_flags(&c->c2.frame, + FRAME_HEADROOM_MARKER_FRAGMENT + |FRAME_HEADROOM_MARKER_READ_LINK + |FRAME_HEADROOM_MARKER_READ_STREAM); } - - frame_add_to_extra_buffer (&c->c2.frame, PAYLOAD_ALIGN); - frame_finalize (&c->c2.frame, - o->ce.link_mtu_defined, - o->ce.link_mtu, - o->ce.tun_mtu_defined, - o->ce.tun_mtu); + + frame_add_to_extra_buffer(&c->c2.frame, PAYLOAD_ALIGN); + frame_finalize(&c->c2.frame, + o->ce.link_mtu_defined, + o->ce.link_mtu, + o->ce.tun_mtu_defined, + o->ce.tun_mtu); } /* * Free a key schedule, including OpenSSL components. */ static void -key_schedule_free (struct key_schedule *ks, bool free_ssl_ctx) +key_schedule_free(struct key_schedule *ks, bool free_ssl_ctx) { #ifdef ENABLE_CRYPTO - free_key_ctx_bi (&ks->static_key); - if (tls_ctx_initialised(&ks->ssl_ctx) && free_ssl_ctx) + free_key_ctx_bi(&ks->static_key); + if (tls_ctx_initialised(&ks->ssl_ctx) && free_ssl_ctx) { - tls_ctx_free (&ks->ssl_ctx); - free_key_ctx_bi (&ks->tls_wrap_key); + tls_ctx_free(&ks->ssl_ctx); + free_key_ctx_bi(&ks->tls_wrap_key); } #endif /* ENABLE_CRYPTO */ - CLEAR (*ks); + CLEAR(*ks); } #ifdef ENABLE_CRYPTO static void -init_crypto_pre (struct context *c, const unsigned int flags) +init_crypto_pre(struct context *c, const unsigned int flags) { - if (c->options.engine) - crypto_init_lib_engine (c->options.engine); + if (c->options.engine) + { + crypto_init_lib_engine(c->options.engine); + } - if (flags & CF_LOAD_PERSISTED_PACKET_ID) + if (flags & CF_LOAD_PERSISTED_PACKET_ID) { - /* load a persisted packet-id for cross-session replay-protection */ - if (c->options.packet_id_file) - packet_id_persist_load (&c->c1.pid_persist, c->options.packet_id_file); + /* load a persisted packet-id for cross-session replay-protection */ + if (c->options.packet_id_file) + { + packet_id_persist_load(&c->c1.pid_persist, c->options.packet_id_file); + } } #ifdef ENABLE_PREDICTION_RESISTANCE - if (c->options.use_prediction_resistance) - rand_ctx_enable_prediction_resistance(); + if (c->options.use_prediction_resistance) + { + rand_ctx_enable_prediction_resistance(); + } #endif } @@ -2156,62 +2343,66 @@ init_crypto_pre (struct context *c, const unsigned int flags) * Static Key Mode (using a pre-shared key) */ static void -do_init_crypto_static (struct context *c, const unsigned int flags) +do_init_crypto_static(struct context *c, const unsigned int flags) { - const struct options *options = &c->options; - ASSERT (options->shared_secret_file); - - init_crypto_pre (c, flags); + const struct options *options = &c->options; + ASSERT(options->shared_secret_file); - /* Initialize flags */ - if (c->options.use_iv) - c->c2.crypto_options.flags |= CO_USE_IV; + init_crypto_pre(c, flags); - if (c->options.mute_replay_warnings) - c->c2.crypto_options.flags |= CO_MUTE_REPLAY_WARNINGS; + /* Initialize flags */ + if (c->options.use_iv) + { + c->c2.crypto_options.flags |= CO_USE_IV; + } - /* Initialize packet ID tracking */ - if (options->replay) + if (c->options.mute_replay_warnings) { - packet_id_init (&c->c2.crypto_options.packet_id, - options->replay_window, - options->replay_time, - "STATIC", 0); - c->c2.crypto_options.pid_persist = &c->c1.pid_persist; - c->c2.crypto_options.flags |= CO_PACKET_ID_LONG_FORM; - packet_id_persist_load_obj (&c->c1.pid_persist, - &c->c2.crypto_options.packet_id); + c->c2.crypto_options.flags |= CO_MUTE_REPLAY_WARNINGS; } - if (!key_ctx_bi_defined (&c->c1.ks.static_key)) + /* Initialize packet ID tracking */ + if (options->replay) { - /* Get cipher & hash algorithms */ - init_key_type (&c->c1.ks.key_type, options->ciphername, options->authname, - options->keysize, options->test_crypto, true); + packet_id_init(&c->c2.crypto_options.packet_id, + options->replay_window, + options->replay_time, + "STATIC", 0); + c->c2.crypto_options.pid_persist = &c->c1.pid_persist; + c->c2.crypto_options.flags |= CO_PACKET_ID_LONG_FORM; + packet_id_persist_load_obj(&c->c1.pid_persist, + &c->c2.crypto_options.packet_id); + } - /* Read cipher and hmac keys from shared secret file */ - crypto_read_openvpn_key (&c->c1.ks.key_type, &c->c1.ks.static_key, - options->shared_secret_file, - options->shared_secret_file_inline, - options->key_direction, "Static Key Encryption", - "secret"); + if (!key_ctx_bi_defined(&c->c1.ks.static_key)) + { + /* Get cipher & hash algorithms */ + init_key_type(&c->c1.ks.key_type, options->ciphername, options->authname, + options->keysize, options->test_crypto, true); + + /* Read cipher and hmac keys from shared secret file */ + crypto_read_openvpn_key(&c->c1.ks.key_type, &c->c1.ks.static_key, + options->shared_secret_file, + options->shared_secret_file_inline, + options->key_direction, "Static Key Encryption", + "secret"); } - else + else { - msg (M_INFO, "Re-using pre-shared static key"); + msg(M_INFO, "Re-using pre-shared static key"); } - /* Get key schedule */ - c->c2.crypto_options.key_ctx_bi = c->c1.ks.static_key; + /* Get key schedule */ + c->c2.crypto_options.key_ctx_bi = c->c1.ks.static_key; - /* Compute MTU parameters */ - crypto_adjust_frame_parameters (&c->c2.frame, - &c->c1.ks.key_type, - options->use_iv, options->replay, true); + /* Compute MTU parameters */ + crypto_adjust_frame_parameters(&c->c2.frame, + &c->c1.ks.key_type, + options->use_iv, options->replay, true); - /* Sanity check on IV, sequence number, and cipher mode options */ - check_replay_iv_consistency (&c->c1.ks.key_type, options->replay, - options->use_iv); + /* Sanity check on IV, sequence number, and cipher mode options */ + check_replay_iv_consistency(&c->c1.ks.key_type, options->replay, + options->use_iv); } /* @@ -2219,309 +2410,337 @@ do_init_crypto_static (struct context *c, const unsigned int flags) * which is preserved across SIGUSR1 resets. */ static void -do_init_crypto_tls_c1 (struct context *c) +do_init_crypto_tls_c1(struct context *c) { - const struct options *options = &c->options; + const struct options *options = &c->options; - if (!tls_ctx_initialised(&c->c1.ks.ssl_ctx)) + if (!tls_ctx_initialised(&c->c1.ks.ssl_ctx)) { - /* - * Initialize the OpenSSL library's global - * SSL context. - */ - init_ssl (options, &(c->c1.ks.ssl_ctx)); - if (!tls_ctx_initialised(&c->c1.ks.ssl_ctx)) - { + /* + * Initialize the OpenSSL library's global + * SSL context. + */ + init_ssl(options, &(c->c1.ks.ssl_ctx)); + if (!tls_ctx_initialised(&c->c1.ks.ssl_ctx)) + { #if P2MP - switch (auth_retry_get ()) - { - case AR_NONE: - msg (M_FATAL, "Error: private key password verification failed"); - break; - case AR_INTERACT: - ssl_purge_auth (false); - case AR_NOINTERACT: - c->sig->signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- Password failure error */ - break; - default: - ASSERT (0); - } - c->sig->signal_text = "private-key-password-failure"; - return; -#else - msg (M_FATAL, "Error: private key password verification failed"); -#endif - } - - /* Get cipher & hash algorithms */ - init_key_type (&c->c1.ks.key_type, options->ciphername, options->authname, - options->keysize, true, true); - - /* Initialize PRNG with config-specified digest */ - prng_init (options->prng_hash, options->prng_nonce_secret_len); - - /* TLS handshake authentication (--tls-auth) */ - if (options->tls_auth_file) - { - /* Initialize key_type for tls-auth with auth only */ - CLEAR (c->c1.ks.tls_auth_key_type); - if (!streq (options->authname, "none")) - { - c->c1.ks.tls_auth_key_type.digest = md_kt_get (options->authname); - c->c1.ks.tls_auth_key_type.hmac_length = - md_kt_size (c->c1.ks.tls_auth_key_type.digest); - } - else - { - msg (M_FATAL, "ERROR: tls-auth enabled, but no valid --auth " - "algorithm specified ('%s')", options->authname); - } - - crypto_read_openvpn_key (&c->c1.ks.tls_auth_key_type, - &c->c1.ks.tls_wrap_key, options->tls_auth_file, - options->tls_auth_file_inline, options->key_direction, - "Control Channel Authentication", "tls-auth"); - } - - /* TLS handshake encryption+authentication (--tls-crypt) */ - if (options->tls_crypt_file) { - tls_crypt_init_key (&c->c1.ks.tls_wrap_key, options->tls_crypt_file, - options->tls_crypt_inline, options->tls_server); - } - - c->c1.ciphername = options->ciphername; - c->c1.authname = options->authname; - c->c1.keysize = options->keysize; + switch (auth_retry_get()) + { + case AR_NONE: + msg(M_FATAL, "Error: private key password verification failed"); + break; + + case AR_INTERACT: + ssl_purge_auth(false); + + case AR_NOINTERACT: + c->sig->signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- Password failure error */ + break; + + default: + ASSERT(0); + } + c->sig->signal_text = "private-key-password-failure"; + return; +#else /* if P2MP */ + msg(M_FATAL, "Error: private key password verification failed"); +#endif + } + + /* Get cipher & hash algorithms */ + init_key_type(&c->c1.ks.key_type, options->ciphername, options->authname, + options->keysize, true, true); + + /* Initialize PRNG with config-specified digest */ + prng_init(options->prng_hash, options->prng_nonce_secret_len); + + /* TLS handshake authentication (--tls-auth) */ + if (options->tls_auth_file) + { + /* Initialize key_type for tls-auth with auth only */ + CLEAR(c->c1.ks.tls_auth_key_type); + if (!streq(options->authname, "none")) + { + c->c1.ks.tls_auth_key_type.digest = md_kt_get(options->authname); + c->c1.ks.tls_auth_key_type.hmac_length = + md_kt_size(c->c1.ks.tls_auth_key_type.digest); + } + else + { + msg(M_FATAL, "ERROR: tls-auth enabled, but no valid --auth " + "algorithm specified ('%s')", options->authname); + } + + crypto_read_openvpn_key(&c->c1.ks.tls_auth_key_type, + &c->c1.ks.tls_wrap_key, options->tls_auth_file, + options->tls_auth_file_inline, options->key_direction, + "Control Channel Authentication", "tls-auth"); + } + + /* TLS handshake encryption+authentication (--tls-crypt) */ + if (options->tls_crypt_file) + { + tls_crypt_init_key(&c->c1.ks.tls_wrap_key, options->tls_crypt_file, + options->tls_crypt_inline, options->tls_server); + } + + c->c1.ciphername = options->ciphername; + c->c1.authname = options->authname; + c->c1.keysize = options->keysize; #if 0 /* was: #if ENABLE_INLINE_FILES -- Note that enabling this code will break restarts */ - if (options->priv_key_file_inline) - { - string_clear (c->options.priv_key_file_inline); - c->options.priv_key_file_inline = NULL; - } + if (options->priv_key_file_inline) + { + string_clear(c->options.priv_key_file_inline); + c->options.priv_key_file_inline = NULL; + } #endif } - else + else { - msg (D_INIT_MEDIUM, "Re-using SSL/TLS context"); + msg(D_INIT_MEDIUM, "Re-using SSL/TLS context"); - /* Restore pre-NCP cipher options */ - c->options.ciphername = c->c1.ciphername; - c->options.authname = c->c1.authname; - c->options.keysize = c->c1.keysize; + /* Restore pre-NCP cipher options */ + c->options.ciphername = c->c1.ciphername; + c->options.authname = c->c1.authname; + c->options.keysize = c->c1.keysize; } } static void -do_init_crypto_tls (struct context *c, const unsigned int flags) +do_init_crypto_tls(struct context *c, const unsigned int flags) { - const struct options *options = &c->options; - struct tls_options to; - bool packet_id_long_form; + const struct options *options = &c->options; + struct tls_options to; + bool packet_id_long_form; - ASSERT (options->tls_server || options->tls_client); - ASSERT (!options->test_crypto); + ASSERT(options->tls_server || options->tls_client); + ASSERT(!options->test_crypto); - init_crypto_pre (c, flags); + init_crypto_pre(c, flags); - /* Make sure we are either a TLS client or server but not both */ - ASSERT (options->tls_server == !options->tls_client); + /* Make sure we are either a TLS client or server but not both */ + ASSERT(options->tls_server == !options->tls_client); - /* initialize persistent component */ - do_init_crypto_tls_c1 (c); - if (IS_SIG (c)) - return; + /* initialize persistent component */ + do_init_crypto_tls_c1(c); + if (IS_SIG(c)) + { + return; + } + + /* Sanity check on IV, sequence number, and cipher mode options */ + check_replay_iv_consistency(&c->c1.ks.key_type, options->replay, + options->use_iv); + + /* In short form, unique datagram identifier is 32 bits, in long form 64 bits */ + packet_id_long_form = cipher_kt_mode_ofb_cfb(c->c1.ks.key_type.cipher); + + /* Compute MTU parameters (postpone if we push/pull options) */ + if (c->options.pull || c->options.mode == MODE_SERVER) + { + /* Account for worst-case crypto overhead before allocating buffers */ + frame_add_to_extra_frame(&c->c2.frame, crypto_max_overhead()); + } + else + { + crypto_adjust_frame_parameters(&c->c2.frame, &c->c1.ks.key_type, + options->use_iv, options->replay, packet_id_long_form); + } + tls_adjust_frame_parameters(&c->c2.frame); - /* Sanity check on IV, sequence number, and cipher mode options */ - check_replay_iv_consistency (&c->c1.ks.key_type, options->replay, - options->use_iv); - - /* In short form, unique datagram identifier is 32 bits, in long form 64 bits */ - packet_id_long_form = cipher_kt_mode_ofb_cfb (c->c1.ks.key_type.cipher); - - /* Compute MTU parameters (postpone if we push/pull options) */ - if (c->options.pull || c->options.mode == MODE_SERVER) - { - /* Account for worst-case crypto overhead before allocating buffers */ - frame_add_to_extra_frame (&c->c2.frame, crypto_max_overhead()); - } - else - { - crypto_adjust_frame_parameters(&c->c2.frame, &c->c1.ks.key_type, - options->use_iv, options->replay, packet_id_long_form); - } - tls_adjust_frame_parameters (&c->c2.frame); - - /* Set all command-line TLS-related options */ - CLEAR (to); - - if (options->use_iv) - to.crypto_flags |= CO_USE_IV; - - if (options->mute_replay_warnings) - to.crypto_flags |= CO_MUTE_REPLAY_WARNINGS; - - to.crypto_flags &= ~(CO_PACKET_ID_LONG_FORM); - if (packet_id_long_form) - to.crypto_flags |= CO_PACKET_ID_LONG_FORM; - - to.ssl_ctx = c->c1.ks.ssl_ctx; - to.key_type = c->c1.ks.key_type; - to.server = options->tls_server; - to.key_method = options->key_method; - to.replay = options->replay; - to.replay_window = options->replay_window; - to.replay_time = options->replay_time; - to.tcp_mode = link_socket_proto_connection_oriented (options->ce.proto); - to.config_ciphername = c->c1.ciphername; - to.config_authname = c->c1.authname; - to.ncp_enabled = options->ncp_enabled; - to.transition_window = options->transition_window; - to.handshake_window = options->handshake_window; - to.packet_timeout = options->tls_timeout; - to.renegotiate_bytes = options->renegotiate_bytes; - to.renegotiate_packets = options->renegotiate_packets; - to.renegotiate_seconds = options->renegotiate_seconds; - to.single_session = options->single_session; - to.mode = options->mode; - to.pull = options->pull; + /* Set all command-line TLS-related options */ + CLEAR(to); + + if (options->use_iv) + { + to.crypto_flags |= CO_USE_IV; + } + + if (options->mute_replay_warnings) + { + to.crypto_flags |= CO_MUTE_REPLAY_WARNINGS; + } + + to.crypto_flags &= ~(CO_PACKET_ID_LONG_FORM); + if (packet_id_long_form) + { + to.crypto_flags |= CO_PACKET_ID_LONG_FORM; + } + + to.ssl_ctx = c->c1.ks.ssl_ctx; + to.key_type = c->c1.ks.key_type; + to.server = options->tls_server; + to.key_method = options->key_method; + to.replay = options->replay; + to.replay_window = options->replay_window; + to.replay_time = options->replay_time; + to.tcp_mode = link_socket_proto_connection_oriented(options->ce.proto); + to.config_ciphername = c->c1.ciphername; + to.config_authname = c->c1.authname; + to.ncp_enabled = options->ncp_enabled; + to.transition_window = options->transition_window; + to.handshake_window = options->handshake_window; + to.packet_timeout = options->tls_timeout; + to.renegotiate_bytes = options->renegotiate_bytes; + to.renegotiate_packets = options->renegotiate_packets; + to.renegotiate_seconds = options->renegotiate_seconds; + to.single_session = options->single_session; + to.mode = options->mode; + to.pull = options->pull; #ifdef ENABLE_PUSH_PEER_INFO - if (options->push_peer_info) /* all there is */ - to.push_peer_info_detail = 2; - else if (options->pull) /* pull clients send some details */ - to.push_peer_info_detail = 1; - else /* default: no peer-info at all */ - to.push_peer_info_detail = 0; + if (options->push_peer_info) /* all there is */ + { + to.push_peer_info_detail = 2; + } + else if (options->pull) /* pull clients send some details */ + { + to.push_peer_info_detail = 1; + } + else /* default: no peer-info at all */ + { + to.push_peer_info_detail = 0; + } #endif - /* should we not xmit any packets until we get an initial - response from client? */ - if (to.server && options->ce.proto == PROTO_TCP_SERVER) - to.xmit_hold = true; + /* should we not xmit any packets until we get an initial + * response from client? */ + if (to.server && options->ce.proto == PROTO_TCP_SERVER) + { + to.xmit_hold = true; + } #ifdef ENABLE_OCC - to.disable_occ = !options->occ; -#endif - - to.verify_command = options->tls_verify; - to.verify_export_cert = options->tls_export_cert; - to.verify_x509_type = (options->verify_x509_type & 0xff); - to.verify_x509_name = options->verify_x509_name; - to.crl_file = options->crl_file; - to.crl_file_inline = options->crl_file_inline; - to.ssl_flags = options->ssl_flags; - to.ns_cert_type = options->ns_cert_type; - memmove (to.remote_cert_ku, options->remote_cert_ku, sizeof (to.remote_cert_ku)); - to.remote_cert_eku = options->remote_cert_eku; - to.verify_hash = options->verify_hash; + to.disable_occ = !options->occ; +#endif + + to.verify_command = options->tls_verify; + to.verify_export_cert = options->tls_export_cert; + to.verify_x509_type = (options->verify_x509_type & 0xff); + to.verify_x509_name = options->verify_x509_name; + to.crl_file = options->crl_file; + to.crl_file_inline = options->crl_file_inline; + to.ssl_flags = options->ssl_flags; + to.ns_cert_type = options->ns_cert_type; + memmove(to.remote_cert_ku, options->remote_cert_ku, sizeof(to.remote_cert_ku)); + to.remote_cert_eku = options->remote_cert_eku; + to.verify_hash = options->verify_hash; #ifdef ENABLE_X509ALTUSERNAME - to.x509_username_field = (char *) options->x509_username_field; + to.x509_username_field = (char *) options->x509_username_field; #else - to.x509_username_field = X509_USERNAME_FIELD_DEFAULT; + to.x509_username_field = X509_USERNAME_FIELD_DEFAULT; #endif - to.es = c->c2.es; + to.es = c->c2.es; #ifdef ENABLE_DEBUG - to.gremlin = c->options.gremlin; + to.gremlin = c->options.gremlin; #endif - to.plugins = c->plugins; + to.plugins = c->plugins; #ifdef MANAGEMENT_DEF_AUTH - to.mda_context = &c->c2.mda_context; + to.mda_context = &c->c2.mda_context; #endif #if P2MP_SERVER - to.auth_user_pass_verify_script = options->auth_user_pass_verify_script; - to.auth_user_pass_verify_script_via_file = options->auth_user_pass_verify_script_via_file; - to.tmp_dir = options->tmp_dir; - if (options->ccd_exclusive) - to.client_config_dir_exclusive = options->client_config_dir; - to.auth_user_pass_file = options->auth_user_pass_file; - to.auth_token_generate = options->auth_token_generate; - to.auth_token_lifetime = options->auth_token_lifetime; + to.auth_user_pass_verify_script = options->auth_user_pass_verify_script; + to.auth_user_pass_verify_script_via_file = options->auth_user_pass_verify_script_via_file; + to.tmp_dir = options->tmp_dir; + if (options->ccd_exclusive) + { + to.client_config_dir_exclusive = options->client_config_dir; + } + to.auth_user_pass_file = options->auth_user_pass_file; + to.auth_token_generate = options->auth_token_generate; + to.auth_token_lifetime = options->auth_token_lifetime; #endif - to.x509_track = options->x509_track; + to.x509_track = options->x509_track; #if P2MP #ifdef ENABLE_CLIENT_CR - to.sci = &options->sc_info; + to.sci = &options->sc_info; #endif #endif #ifdef USE_COMP - to.comp_options = options->comp; + to.comp_options = options->comp; #endif #if defined(ENABLE_CRYPTO_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10001000 - if (options->keying_material_exporter_label) + if (options->keying_material_exporter_label) { - to.ekm_size = options->keying_material_exporter_length; - if (to.ekm_size < 16 || to.ekm_size > 4095) - to.ekm_size = 0; + to.ekm_size = options->keying_material_exporter_length; + if (to.ekm_size < 16 || to.ekm_size > 4095) + { + to.ekm_size = 0; + } - to.ekm_label = options->keying_material_exporter_label; - to.ekm_label_size = strlen(to.ekm_label); + to.ekm_label = options->keying_material_exporter_label; + to.ekm_label_size = strlen(to.ekm_label); } - else + else { - to.ekm_size = 0; + to.ekm_size = 0; } #endif - /* TLS handshake authentication (--tls-auth) */ - if (options->tls_auth_file) + /* TLS handshake authentication (--tls-auth) */ + if (options->tls_auth_file) { - to.tls_wrap.mode = TLS_WRAP_AUTH; - to.tls_wrap.opt.key_ctx_bi = c->c1.ks.tls_wrap_key; - to.tls_wrap.opt.pid_persist = &c->c1.pid_persist; - to.tls_wrap.opt.flags |= CO_PACKET_ID_LONG_FORM; - crypto_adjust_frame_parameters (&to.frame, - &c->c1.ks.tls_auth_key_type, - false, true, true); + to.tls_wrap.mode = TLS_WRAP_AUTH; + to.tls_wrap.opt.key_ctx_bi = c->c1.ks.tls_wrap_key; + to.tls_wrap.opt.pid_persist = &c->c1.pid_persist; + to.tls_wrap.opt.flags |= CO_PACKET_ID_LONG_FORM; + crypto_adjust_frame_parameters(&to.frame, + &c->c1.ks.tls_auth_key_type, + false, true, true); } - /* TLS handshake encryption (--tls-crypt) */ - if (options->tls_crypt_file) + /* TLS handshake encryption (--tls-crypt) */ + if (options->tls_crypt_file) { - to.tls_wrap.mode = TLS_WRAP_CRYPT; - to.tls_wrap.opt.key_ctx_bi = c->c1.ks.tls_wrap_key; - to.tls_wrap.opt.pid_persist = &c->c1.pid_persist; - to.tls_wrap.opt.flags |= CO_PACKET_ID_LONG_FORM; - tls_crypt_adjust_frame_parameters (&to.frame); + to.tls_wrap.mode = TLS_WRAP_CRYPT; + to.tls_wrap.opt.key_ctx_bi = c->c1.ks.tls_wrap_key; + to.tls_wrap.opt.pid_persist = &c->c1.pid_persist; + to.tls_wrap.opt.flags |= CO_PACKET_ID_LONG_FORM; + tls_crypt_adjust_frame_parameters(&to.frame); } - /* If we are running over TCP, allow for - length prefix */ - socket_adjust_frame_parameters (&to.frame, options->ce.proto); + /* If we are running over TCP, allow for + * length prefix */ + socket_adjust_frame_parameters(&to.frame, options->ce.proto); - /* - * Initialize OpenVPN's master TLS-mode object. - */ - if (flags & CF_INIT_TLS_MULTI) - c->c2.tls_multi = tls_multi_init (&to); + /* + * Initialize OpenVPN's master TLS-mode object. + */ + if (flags & CF_INIT_TLS_MULTI) + { + c->c2.tls_multi = tls_multi_init(&to); + } - if (flags & CF_INIT_TLS_AUTH_STANDALONE) - c->c2.tls_auth_standalone = tls_auth_standalone_init (&to, &c->c2.gc); + if (flags & CF_INIT_TLS_AUTH_STANDALONE) + { + c->c2.tls_auth_standalone = tls_auth_standalone_init(&to, &c->c2.gc); + } } static void -do_init_finalize_tls_frame (struct context *c) +do_init_finalize_tls_frame(struct context *c) { - if (c->c2.tls_multi) + if (c->c2.tls_multi) { - tls_multi_init_finalize (c->c2.tls_multi, &c->c2.frame); - ASSERT (EXPANDED_SIZE (&c->c2.tls_multi->opt.frame) <= - EXPANDED_SIZE (&c->c2.frame)); - frame_print (&c->c2.tls_multi->opt.frame, D_MTU_INFO, - "Control Channel MTU parms"); + tls_multi_init_finalize(c->c2.tls_multi, &c->c2.frame); + ASSERT(EXPANDED_SIZE(&c->c2.tls_multi->opt.frame) <= + EXPANDED_SIZE(&c->c2.frame)); + frame_print(&c->c2.tls_multi->opt.frame, D_MTU_INFO, + "Control Channel MTU parms"); } - if (c->c2.tls_auth_standalone) + if (c->c2.tls_auth_standalone) { - tls_auth_standalone_finalize (c->c2.tls_auth_standalone, &c->c2.frame); - frame_print (&c->c2.tls_auth_standalone->frame, D_MTU_INFO, - "TLS-Auth MTU parms"); + tls_auth_standalone_finalize(c->c2.tls_auth_standalone, &c->c2.frame); + frame_print(&c->c2.tls_auth_standalone->frame, D_MTU_INFO, + "TLS-Auth MTU parms"); } } @@ -2529,282 +2748,328 @@ do_init_finalize_tls_frame (struct context *c) * No encryption or authentication. */ static void -do_init_crypto_none (const struct context *c) +do_init_crypto_none(const struct context *c) { - ASSERT (!c->options.test_crypto); - msg (M_WARN, - "******* WARNING *******: all encryption and authentication features disabled -- all data will be tunnelled as cleartext"); + ASSERT(!c->options.test_crypto); + msg(M_WARN, + "******* WARNING *******: all encryption and authentication features disabled -- all data will be tunnelled as cleartext"); } -#endif +#endif /* ifdef ENABLE_CRYPTO */ static void -do_init_crypto (struct context *c, const unsigned int flags) +do_init_crypto(struct context *c, const unsigned int flags) { #ifdef ENABLE_CRYPTO - if (c->options.shared_secret_file) - do_init_crypto_static (c, flags); - else if (c->options.tls_server || c->options.tls_client) - do_init_crypto_tls (c, flags); - else /* no encryption or authentication. */ - do_init_crypto_none (c); + if (c->options.shared_secret_file) + { + do_init_crypto_static(c, flags); + } + else if (c->options.tls_server || c->options.tls_client) + { + do_init_crypto_tls(c, flags); + } + else /* no encryption or authentication. */ + { + do_init_crypto_none(c); + } #else /* ENABLE_CRYPTO */ - msg (M_WARN, - "******* WARNING *******: " PACKAGE_NAME - " built without crypto library -- encryption and authentication features disabled -- all data will be tunnelled as cleartext"); + msg(M_WARN, + "******* WARNING *******: " PACKAGE_NAME + " built without crypto library -- encryption and authentication features disabled -- all data will be tunnelled as cleartext"); #endif /* ENABLE_CRYPTO */ } static void -do_init_frame (struct context *c) +do_init_frame(struct context *c) { #ifdef USE_COMP - /* - * modify frame parameters if compression is enabled - */ - if (comp_enabled(&c->options.comp)) + /* + * modify frame parameters if compression is enabled + */ + if (comp_enabled(&c->options.comp)) { - comp_add_to_extra_frame (&c->c2.frame); + comp_add_to_extra_frame(&c->c2.frame); #if !defined(ENABLE_LZ4) - /* - * Compression usage affects buffer alignment when non-swapped algs - * such as LZO is used. - * Newer algs like LZ4 and comp-stub with COMP_F_SWAP don't need - * any special alignment because of the control-byte swap approach. - * LZO alignment (on the other hand) is problematic because - * the presence of the control byte means that either the output of - * decryption must be written to an unaligned buffer, or the input - * to compression (or packet dispatch if packet is uncompressed) - * must be read from an unaligned buffer. - * This code tries to align the input to compression (or packet - * dispatch if packet is uncompressed) at the cost of requiring - * decryption output to be written to an unaligned buffer, so - * it's more of a tradeoff than an optimal solution and we don't - * include it when we are doing a modern build with LZ4. - * Strictly speaking, on the server it would be better to execute - * this code for every connection after we decide the compression - * method, but currently the frame code doesn't appear to be - * flexible enough for this, since the frame is already established - * before it is known which compression options will be pushed. - */ - if (comp_unswapped_prefix (&c->options.comp) && CIPHER_ENABLED (c)) - { - frame_add_to_align_adjust (&c->c2.frame, COMP_PREFIX_LEN); - frame_or_align_flags (&c->c2.frame, - FRAME_HEADROOM_MARKER_FRAGMENT - |FRAME_HEADROOM_MARKER_DECRYPT); - } + /* + * Compression usage affects buffer alignment when non-swapped algs + * such as LZO is used. + * Newer algs like LZ4 and comp-stub with COMP_F_SWAP don't need + * any special alignment because of the control-byte swap approach. + * LZO alignment (on the other hand) is problematic because + * the presence of the control byte means that either the output of + * decryption must be written to an unaligned buffer, or the input + * to compression (or packet dispatch if packet is uncompressed) + * must be read from an unaligned buffer. + * This code tries to align the input to compression (or packet + * dispatch if packet is uncompressed) at the cost of requiring + * decryption output to be written to an unaligned buffer, so + * it's more of a tradeoff than an optimal solution and we don't + * include it when we are doing a modern build with LZ4. + * Strictly speaking, on the server it would be better to execute + * this code for every connection after we decide the compression + * method, but currently the frame code doesn't appear to be + * flexible enough for this, since the frame is already established + * before it is known which compression options will be pushed. + */ + if (comp_unswapped_prefix(&c->options.comp) && CIPHER_ENABLED(c)) + { + frame_add_to_align_adjust(&c->c2.frame, COMP_PREFIX_LEN); + frame_or_align_flags(&c->c2.frame, + FRAME_HEADROOM_MARKER_FRAGMENT + |FRAME_HEADROOM_MARKER_DECRYPT); + } #endif #ifdef ENABLE_FRAGMENT - comp_add_to_extra_frame (&c->c2.frame_fragment_omit); /* omit compression frame delta from final frame_fragment */ + comp_add_to_extra_frame(&c->c2.frame_fragment_omit); /* omit compression frame delta from final frame_fragment */ #endif } #endif /* USE_COMP */ - /* - * Adjust frame size for UDP Socks support. - */ - if (c->options.ce.socks_proxy_server) - socks_adjust_frame_parameters (&c->c2.frame, c->options.ce.proto); - - /* - * Adjust frame size based on the --tun-mtu-extra parameter. - */ - if (c->options.ce.tun_mtu_extra_defined) - tun_adjust_frame_parameters (&c->c2.frame, c->options.ce.tun_mtu_extra); - - /* - * Adjust frame size based on link socket parameters. - * (Since TCP is a stream protocol, we need to insert - * a packet length uint16_t in the buffer.) - */ - socket_adjust_frame_parameters (&c->c2.frame, c->options.ce.proto); - - /* - * Fill in the blanks in the frame parameters structure, - * make sure values are rational, etc. - */ - frame_finalize_options (c, NULL); + /* + * Adjust frame size for UDP Socks support. + */ + if (c->options.ce.socks_proxy_server) + { + socks_adjust_frame_parameters(&c->c2.frame, c->options.ce.proto); + } + + /* + * Adjust frame size based on the --tun-mtu-extra parameter. + */ + if (c->options.ce.tun_mtu_extra_defined) + { + tun_adjust_frame_parameters(&c->c2.frame, c->options.ce.tun_mtu_extra); + } + + /* + * Adjust frame size based on link socket parameters. + * (Since TCP is a stream protocol, we need to insert + * a packet length uint16_t in the buffer.) + */ + socket_adjust_frame_parameters(&c->c2.frame, c->options.ce.proto); + + /* + * Fill in the blanks in the frame parameters structure, + * make sure values are rational, etc. + */ + frame_finalize_options(c, NULL); #ifdef USE_COMP - /* - * Modify frame parameters if compression is compiled in. - * Should be called after frame_finalize_options. - */ - comp_add_to_extra_buffer (&c->c2.frame); + /* + * Modify frame parameters if compression is compiled in. + * Should be called after frame_finalize_options. + */ + comp_add_to_extra_buffer(&c->c2.frame); #ifdef ENABLE_FRAGMENT - comp_add_to_extra_buffer (&c->c2.frame_fragment_omit); /* omit compression frame delta from final frame_fragment */ + comp_add_to_extra_buffer(&c->c2.frame_fragment_omit); /* omit compression frame delta from final frame_fragment */ #endif #endif /* USE_COMP */ - /* packets with peer-id (P_DATA_V2) need 3 extra bytes in frame (on client) - * and need link_mtu+3 bytes on socket reception (on server). - * - * accomodate receive path in f->extra_link, which has the side effect of - * also increasing send buffers (BUF_SIZE() macro), which need to be - * allocated big enough before receiving peer-id option from server. - * - * f->extra_frame is adjusted when peer-id option is push-received - */ - frame_add_to_extra_link(&c->c2.frame, 3); + /* packets with peer-id (P_DATA_V2) need 3 extra bytes in frame (on client) + * and need link_mtu+3 bytes on socket reception (on server). + * + * accomodate receive path in f->extra_link, which has the side effect of + * also increasing send buffers (BUF_SIZE() macro), which need to be + * allocated big enough before receiving peer-id option from server. + * + * f->extra_frame is adjusted when peer-id option is push-received + */ + frame_add_to_extra_link(&c->c2.frame, 3); #ifdef ENABLE_FRAGMENT - /* - * Set frame parameter for fragment code. This is necessary because - * the fragmentation code deals with payloads which have already been - * passed through the compression code. - */ - c->c2.frame_fragment = c->c2.frame; - frame_subtract_extra (&c->c2.frame_fragment, &c->c2.frame_fragment_omit); + /* + * Set frame parameter for fragment code. This is necessary because + * the fragmentation code deals with payloads which have already been + * passed through the compression code. + */ + c->c2.frame_fragment = c->c2.frame; + frame_subtract_extra(&c->c2.frame_fragment, &c->c2.frame_fragment_omit); #endif #if defined(ENABLE_FRAGMENT) && defined(ENABLE_OCC) - /* - * MTU advisories - */ - if (c->options.ce.fragment && c->options.mtu_test) - msg (M_WARN, - "WARNING: using --fragment and --mtu-test together may produce an inaccurate MTU test result"); + /* + * MTU advisories + */ + if (c->options.ce.fragment && c->options.mtu_test) + { + msg(M_WARN, + "WARNING: using --fragment and --mtu-test together may produce an inaccurate MTU test result"); + } #endif #ifdef ENABLE_FRAGMENT - if ((c->options.ce.mssfix || c->options.ce.fragment) - && TUN_MTU_SIZE (&c->c2.frame_fragment) != ETHERNET_MTU) - msg (M_WARN, - "WARNING: normally if you use --mssfix and/or --fragment, you should also set --tun-mtu %d (currently it is %d)", - ETHERNET_MTU, TUN_MTU_SIZE (&c->c2.frame_fragment)); + if ((c->options.ce.mssfix || c->options.ce.fragment) + && TUN_MTU_SIZE(&c->c2.frame_fragment) != ETHERNET_MTU) + { + msg(M_WARN, + "WARNING: normally if you use --mssfix and/or --fragment, you should also set --tun-mtu %d (currently it is %d)", + ETHERNET_MTU, TUN_MTU_SIZE(&c->c2.frame_fragment)); + } #endif } static void -do_option_warnings (struct context *c) +do_option_warnings(struct context *c) { - const struct options *o = &c->options; + const struct options *o = &c->options; - if (o->ping_send_timeout && !o->ping_rec_timeout) - msg (M_WARN, "WARNING: --ping should normally be used with --ping-restart or --ping-exit"); + if (o->ping_send_timeout && !o->ping_rec_timeout) + { + msg(M_WARN, "WARNING: --ping should normally be used with --ping-restart or --ping-exit"); + } - if (o->username || o->groupname || o->chroot_dir + if (o->username || o->groupname || o->chroot_dir #ifdef ENABLE_SELINUX - || o->selinux_context + || o->selinux_context #endif - ) - { - if (!o->persist_tun) - msg (M_WARN, "WARNING: you are using user/group/chroot/setcon without persist-tun -- this may cause restarts to fail"); - if (!o->persist_key + ) + { + if (!o->persist_tun) + { + msg(M_WARN, "WARNING: you are using user/group/chroot/setcon without persist-tun -- this may cause restarts to fail"); + } + if (!o->persist_key #ifdef ENABLE_PKCS11 - && !o->pkcs11_id + && !o->pkcs11_id #endif - ) - msg (M_WARN, "WARNING: you are using user/group/chroot/setcon without persist-key -- this may cause restarts to fail"); - } + ) + { + msg(M_WARN, "WARNING: you are using user/group/chroot/setcon without persist-key -- this may cause restarts to fail"); + } + } - if (o->chroot_dir && !(o->username && o->groupname)) - msg (M_WARN, "WARNING: you are using chroot without specifying user and group -- this may cause the chroot jail to be insecure"); + if (o->chroot_dir && !(o->username && o->groupname)) + { + msg(M_WARN, "WARNING: you are using chroot without specifying user and group -- this may cause the chroot jail to be insecure"); + } #if P2MP - if (o->pull && o->ifconfig_local && c->first_time) - msg (M_WARN, "WARNING: using --pull/--client and --ifconfig together is probably not what you want"); + if (o->pull && o->ifconfig_local && c->first_time) + { + msg(M_WARN, "WARNING: using --pull/--client and --ifconfig together is probably not what you want"); + } #if P2MP_SERVER - if (o->server_bridge_defined | o->server_bridge_proxy_dhcp) - msg (M_WARN, "NOTE: when bridging your LAN adapter with the TAP adapter, note that the new bridge adapter will often take on its own IP address that is different from what the LAN adapter was previously set to"); + if (o->server_bridge_defined | o->server_bridge_proxy_dhcp) + { + msg(M_WARN, "NOTE: when bridging your LAN adapter with the TAP adapter, note that the new bridge adapter will often take on its own IP address that is different from what the LAN adapter was previously set to"); + } - if (o->mode == MODE_SERVER) + if (o->mode == MODE_SERVER) { - if (o->duplicate_cn && o->client_config_dir) - msg (M_WARN, "WARNING: using --duplicate-cn and --client-config-dir together is probably not what you want"); - if (o->duplicate_cn && o->ifconfig_pool_persist_filename) - msg (M_WARN, "WARNING: --ifconfig-pool-persist will not work with --duplicate-cn"); - if (!o->keepalive_ping || !o->keepalive_timeout) - msg (M_WARN, "WARNING: --keepalive option is missing from server config"); + if (o->duplicate_cn && o->client_config_dir) + { + msg(M_WARN, "WARNING: using --duplicate-cn and --client-config-dir together is probably not what you want"); + } + if (o->duplicate_cn && o->ifconfig_pool_persist_filename) + { + msg(M_WARN, "WARNING: --ifconfig-pool-persist will not work with --duplicate-cn"); + } + if (!o->keepalive_ping || !o->keepalive_timeout) + { + msg(M_WARN, "WARNING: --keepalive option is missing from server config"); + } } -#endif -#endif +#endif /* if P2MP_SERVER */ +#endif /* if P2MP */ #ifdef ENABLE_CRYPTO - if (!o->replay) - msg (M_WARN, "WARNING: You have disabled Replay Protection (--no-replay) which may make " PACKAGE_NAME " less secure"); - if (!o->use_iv) - msg (M_WARN, "WARNING: You have disabled Crypto IVs (--no-iv) which may make " PACKAGE_NAME " less secure"); - - if (o->tls_server) - warn_on_use_of_common_subnets (); - if (o->tls_client - && !o->tls_verify - && o->verify_x509_type == VERIFY_X509_NONE - && !(o->ns_cert_type & NS_CERT_CHECK_SERVER) - && !o->remote_cert_eku) - msg (M_WARN, "WARNING: No server certificate verification method has been enabled. See http://openvpn.net/howto.html#mitm for more info."); -#endif - - /* If a script is used, print appropiate warnings */ - if (o->user_script_used) - { - if (script_security >= SSEC_SCRIPTS) - msg (M_WARN, "NOTE: the current --script-security setting may allow this configuration to call user-defined scripts"); - else if (script_security >= SSEC_PW_ENV) - msg (M_WARN, "WARNING: the current --script-security setting may allow passwords to be passed to scripts via environmental variables"); - else - msg (M_WARN, "NOTE: starting with " PACKAGE_NAME " 2.1, '--script-security 2' or higher is required to call user-defined scripts or executables"); - } + if (!o->replay) + { + msg(M_WARN, "WARNING: You have disabled Replay Protection (--no-replay) which may make " PACKAGE_NAME " less secure"); + } + if (!o->use_iv) + { + msg(M_WARN, "WARNING: You have disabled Crypto IVs (--no-iv) which may make " PACKAGE_NAME " less secure"); + } + + if (o->tls_server) + { + warn_on_use_of_common_subnets(); + } + if (o->tls_client + && !o->tls_verify + && o->verify_x509_type == VERIFY_X509_NONE + && !(o->ns_cert_type & NS_CERT_CHECK_SERVER) + && !o->remote_cert_eku) + { + msg(M_WARN, "WARNING: No server certificate verification method has been enabled. See http://openvpn.net/howto.html#mitm for more info."); + } +#endif /* ifdef ENABLE_CRYPTO */ + + /* If a script is used, print appropiate warnings */ + if (o->user_script_used) + { + if (script_security >= SSEC_SCRIPTS) + { + msg(M_WARN, "NOTE: the current --script-security setting may allow this configuration to call user-defined scripts"); + } + else if (script_security >= SSEC_PW_ENV) + { + msg(M_WARN, "WARNING: the current --script-security setting may allow passwords to be passed to scripts via environmental variables"); + } + else + { + msg(M_WARN, "NOTE: starting with " PACKAGE_NAME " 2.1, '--script-security 2' or higher is required to call user-defined scripts or executables"); + } + } } static void -do_init_frame_tls (struct context *c) +do_init_frame_tls(struct context *c) { #ifdef ENABLE_CRYPTO - do_init_finalize_tls_frame (c); + do_init_finalize_tls_frame(c); #endif } struct context_buffers * -init_context_buffers (const struct frame *frame) +init_context_buffers(const struct frame *frame) { - struct context_buffers *b; + struct context_buffers *b; - ALLOC_OBJ_CLEAR (b, struct context_buffers); + ALLOC_OBJ_CLEAR(b, struct context_buffers); - b->read_link_buf = alloc_buf (BUF_SIZE (frame)); - b->read_tun_buf = alloc_buf (BUF_SIZE (frame)); + b->read_link_buf = alloc_buf(BUF_SIZE(frame)); + b->read_tun_buf = alloc_buf(BUF_SIZE(frame)); - b->aux_buf = alloc_buf (BUF_SIZE (frame)); + b->aux_buf = alloc_buf(BUF_SIZE(frame)); #ifdef ENABLE_CRYPTO - b->encrypt_buf = alloc_buf (BUF_SIZE (frame)); - b->decrypt_buf = alloc_buf (BUF_SIZE (frame)); + b->encrypt_buf = alloc_buf(BUF_SIZE(frame)); + b->decrypt_buf = alloc_buf(BUF_SIZE(frame)); #endif #ifdef USE_COMP - b->compress_buf = alloc_buf (BUF_SIZE (frame)); - b->decompress_buf = alloc_buf (BUF_SIZE (frame)); + b->compress_buf = alloc_buf(BUF_SIZE(frame)); + b->decompress_buf = alloc_buf(BUF_SIZE(frame)); #endif - return b; + return b; } void -free_context_buffers (struct context_buffers *b) +free_context_buffers(struct context_buffers *b) { - if (b) + if (b) { - free_buf (&b->read_link_buf); - free_buf (&b->read_tun_buf); - free_buf (&b->aux_buf); + free_buf(&b->read_link_buf); + free_buf(&b->read_tun_buf); + free_buf(&b->aux_buf); #ifdef USE_COMP - free_buf (&b->compress_buf); - free_buf (&b->decompress_buf); + free_buf(&b->compress_buf); + free_buf(&b->decompress_buf); #endif #ifdef ENABLE_CRYPTO - free_buf (&b->encrypt_buf); - free_buf (&b->decrypt_buf); + free_buf(&b->encrypt_buf); + free_buf(&b->decrypt_buf); #endif - free (b); + free(b); } } @@ -2813,10 +3078,10 @@ free_context_buffers (struct context_buffers *b) * our buffers. */ static void -do_init_buffers (struct context *c) +do_init_buffers(struct context *c) { - c->c2.buffers = init_context_buffers (&c->c2.frame); - c->c2.buffers_owned = true; + c->c2.buffers = init_context_buffers(&c->c2.frame); + c->c2.buffers_owned = true; } #ifdef ENABLE_FRAGMENT @@ -2825,12 +3090,12 @@ do_init_buffers (struct context *c) * once frame parameters are known. */ static void -do_init_fragment (struct context *c) +do_init_fragment(struct context *c) { - ASSERT (c->options.ce.fragment); - frame_set_mtu_dynamic (&c->c2.frame_fragment, - c->options.ce.fragment, SET_MTU_UPPER_BOUND); - fragment_frame_init (c->c2.fragment, &c->c2.frame_fragment); + ASSERT(c->options.ce.fragment); + frame_set_mtu_dynamic(&c->c2.frame_fragment, + c->options.ce.fragment, SET_MTU_UPPER_BOUND); + fragment_frame_init(c->c2.fragment, &c->c2.frame_fragment); } #endif @@ -2838,78 +3103,82 @@ do_init_fragment (struct context *c) * Allocate our socket object. */ static void -do_link_socket_new (struct context *c) +do_link_socket_new(struct context *c) { - ASSERT (!c->c2.link_socket); - c->c2.link_socket = link_socket_new (); - c->c2.link_socket_owned = true; + ASSERT(!c->c2.link_socket); + c->c2.link_socket = link_socket_new(); + c->c2.link_socket_owned = true; } /* * bind the TCP/UDP socket */ static void -do_init_socket_1 (struct context *c, const int mode) +do_init_socket_1(struct context *c, const int mode) { - unsigned int sockflags = c->options.sockflags; + unsigned int sockflags = c->options.sockflags; #if PORT_SHARE - if (c->options.port_share_host && c->options.port_share_port) - sockflags |= SF_PORT_SHARE; -#endif - - link_socket_init_phase1 (c->c2.link_socket, - c->options.ce.local, - c->options.ce.local_port, - c->options.ce.remote, - c->options.ce.remote_port, - c->c1.dns_cache, - c->options.ce.proto, - c->options.ce.af, - c->options.ce.bind_ipv6_only, - mode, - c->c2.accept_from, - c->c1.http_proxy, - c->c1.socks_proxy, + if (c->options.port_share_host && c->options.port_share_port) + { + sockflags |= SF_PORT_SHARE; + } +#endif + + link_socket_init_phase1(c->c2.link_socket, + c->options.ce.local, + c->options.ce.local_port, + c->options.ce.remote, + c->options.ce.remote_port, + c->c1.dns_cache, + c->options.ce.proto, + c->options.ce.af, + c->options.ce.bind_ipv6_only, + mode, + c->c2.accept_from, + c->c1.http_proxy, + c->c1.socks_proxy, #ifdef ENABLE_DEBUG - c->options.gremlin, -#endif - c->options.ce.bind_local, - c->options.ce.remote_float, - c->options.inetd, - &c->c1.link_socket_addr, - c->options.ipchange, - c->plugins, - c->options.resolve_retry_seconds, - c->options.ce.mtu_discover_type, - c->options.rcvbuf, - c->options.sndbuf, - c->options.mark, - &c->c2.server_poll_interval, - sockflags); + c->options.gremlin, +#endif + c->options.ce.bind_local, + c->options.ce.remote_float, + c->options.inetd, + &c->c1.link_socket_addr, + c->options.ipchange, + c->plugins, + c->options.resolve_retry_seconds, + c->options.ce.mtu_discover_type, + c->options.rcvbuf, + c->options.sndbuf, + c->options.mark, + &c->c2.server_poll_interval, + sockflags); } /* * finalize the TCP/UDP socket */ static void -do_init_socket_2 (struct context *c) +do_init_socket_2(struct context *c) { - link_socket_init_phase2 (c->c2.link_socket, &c->c2.frame, - c->sig); + link_socket_init_phase2(c->c2.link_socket, &c->c2.frame, + c->sig); } /* * Print MTU INFO */ static void -do_print_data_channel_mtu_parms (struct context *c) +do_print_data_channel_mtu_parms(struct context *c) { - frame_print (&c->c2.frame, D_MTU_INFO, "Data Channel MTU parms"); + frame_print(&c->c2.frame, D_MTU_INFO, "Data Channel MTU parms"); #ifdef ENABLE_FRAGMENT - if (c->c2.fragment) - frame_print (&c->c2.frame_fragment, D_MTU_INFO, - "Fragmentation MTU parms"); + if (c->c2.fragment) + { + frame_print(&c->c2.frame_fragment, D_MTU_INFO, + "Fragmentation MTU parms"); + } #endif } @@ -2918,32 +3187,34 @@ do_print_data_channel_mtu_parms (struct context *c) * Get local and remote options compatibility strings. */ static void -do_compute_occ_strings (struct context *c) +do_compute_occ_strings(struct context *c) { - struct gc_arena gc = gc_new (); + struct gc_arena gc = gc_new(); - c->c2.options_string_local = - options_string (&c->options, &c->c2.frame, c->c1.tuntap, false, &gc); - c->c2.options_string_remote = - options_string (&c->options, &c->c2.frame, c->c1.tuntap, true, &gc); + c->c2.options_string_local = + options_string(&c->options, &c->c2.frame, c->c1.tuntap, false, &gc); + c->c2.options_string_remote = + options_string(&c->options, &c->c2.frame, c->c1.tuntap, true, &gc); - msg (D_SHOW_OCC, "Local Options String (VER=%s): '%s'", - options_string_version (c->c2.options_string_local, &gc), - c->c2.options_string_local); - msg (D_SHOW_OCC, "Expected Remote Options String (VER=%s): '%s'", - options_string_version (c->c2.options_string_remote, &gc), - c->c2.options_string_remote); + msg(D_SHOW_OCC, "Local Options String (VER=%s): '%s'", + options_string_version(c->c2.options_string_local, &gc), + c->c2.options_string_local); + msg(D_SHOW_OCC, "Expected Remote Options String (VER=%s): '%s'", + options_string_version(c->c2.options_string_remote, &gc), + c->c2.options_string_remote); #ifdef ENABLE_CRYPTO - if (c->c2.tls_multi) - tls_multi_init_set_options (c->c2.tls_multi, - c->c2.options_string_local, - c->c2.options_string_remote); + if (c->c2.tls_multi) + { + tls_multi_init_set_options(c->c2.tls_multi, + c->c2.options_string_local, + c->c2.options_string_remote); + } #endif - gc_free (&gc); + gc_free(&gc); } -#endif +#endif /* ifdef ENABLE_OCC */ /* * These things can only be executed once per program instantiation. @@ -2951,26 +3222,28 @@ do_compute_occ_strings (struct context *c) * Daemonize if requested. */ static void -do_init_first_time (struct context *c) +do_init_first_time(struct context *c) { - if (c->first_time && !c->c0) + if (c->first_time && !c->c0) { - struct context_0 *c0; + struct context_0 *c0; - ALLOC_OBJ_CLEAR_GC (c->c0, struct context_0, &c->gc); - c0 = c->c0; - - /* get user and/or group that we want to setuid/setgid to */ - c0->uid_gid_specified = - platform_group_get (c->options.groupname, &c0->platform_state_group) | - platform_user_get (c->options.username, &c0->platform_state_user); + ALLOC_OBJ_CLEAR_GC(c->c0, struct context_0, &c->gc); + c0 = c->c0; - /* perform postponed chdir if --daemon */ - if (c->did_we_daemonize && c->options.cd_dir == NULL) - platform_chdir("/"); + /* get user and/or group that we want to setuid/setgid to */ + c0->uid_gid_specified = + platform_group_get(c->options.groupname, &c0->platform_state_group) + |platform_user_get(c->options.username, &c0->platform_state_user); - /* should we change scheduling priority? */ - platform_nice (c->options.nice); + /* perform postponed chdir if --daemon */ + if (c->did_we_daemonize && c->options.cd_dir == NULL) + { + platform_chdir("/"); + } + + /* should we change scheduling priority? */ + platform_nice(c->options.nice); } } @@ -2978,16 +3251,16 @@ do_init_first_time (struct context *c) * If xinetd/inetd mode, don't allow restart. */ static void -do_close_check_if_restart_permitted (struct context *c) +do_close_check_if_restart_permitted(struct context *c) { - if (c->options.inetd - && (c->sig->signal_received == SIGHUP - || c->sig->signal_received == SIGUSR1)) + if (c->options.inetd + && (c->sig->signal_received == SIGHUP + || c->sig->signal_received == SIGUSR1)) { - c->sig->signal_received = SIGTERM; - msg (M_INFO, - PACKAGE_NAME - " started by inetd/xinetd cannot restart... Exiting."); + c->sig->signal_received = SIGTERM; + msg(M_INFO, + PACKAGE_NAME + " started by inetd/xinetd cannot restart... Exiting."); } } @@ -2995,13 +3268,13 @@ do_close_check_if_restart_permitted (struct context *c) * free buffers */ static void -do_close_free_buf (struct context *c) +do_close_free_buf(struct context *c) { - if (c->c2.buffers_owned) + if (c->c2.buffers_owned) { - free_context_buffers (c->c2.buffers); - c->c2.buffers = NULL; - c->c2.buffers_owned = false; + free_context_buffers(c->c2.buffers); + c->c2.buffers = NULL; + c->c2.buffers_owned = false; } } @@ -3009,22 +3282,26 @@ do_close_free_buf (struct context *c) * close TLS */ static void -do_close_tls (struct context *c) +do_close_tls(struct context *c) { #ifdef ENABLE_CRYPTO - if (c->c2.tls_multi) + if (c->c2.tls_multi) { - tls_multi_free (c->c2.tls_multi, true); - c->c2.tls_multi = NULL; + tls_multi_free(c->c2.tls_multi, true); + c->c2.tls_multi = NULL; } #ifdef ENABLE_OCC - /* free options compatibility strings */ - if (c->c2.options_string_local) - free (c->c2.options_string_local); - if (c->c2.options_string_remote) - free (c->c2.options_string_remote); - c->c2.options_string_local = c->c2.options_string_remote = NULL; + /* free options compatibility strings */ + if (c->c2.options_string_local) + { + free(c->c2.options_string_local); + } + if (c->c2.options_string_remote) + { + free(c->c2.options_string_remote); + } + c->c2.options_string_local = c->c2.options_string_remote = NULL; #endif #endif } @@ -3033,62 +3310,71 @@ do_close_tls (struct context *c) * Free key schedules */ static void -do_close_free_key_schedule (struct context *c, bool free_ssl_ctx) +do_close_free_key_schedule(struct context *c, bool free_ssl_ctx) { - if (!(c->sig->signal_received == SIGUSR1 && c->options.persist_key)) - key_schedule_free (&c->c1.ks, free_ssl_ctx); + if (!(c->sig->signal_received == SIGUSR1 && c->options.persist_key)) + { + key_schedule_free(&c->c1.ks, free_ssl_ctx); + } } /* * Close TCP/UDP connection */ static void -do_close_link_socket (struct context *c) +do_close_link_socket(struct context *c) { - if (c->c2.link_socket && c->c2.link_socket_owned) + if (c->c2.link_socket && c->c2.link_socket_owned) { - link_socket_close (c->c2.link_socket); - c->c2.link_socket = NULL; + link_socket_close(c->c2.link_socket); + c->c2.link_socket = NULL; } - - /* Preserve the resolved list of remote if the user request to or if we want - * reconnect to the same host again or there are still addresses that need - * to be tried */ - if (!(c->sig->signal_received == SIGUSR1 && - ( (c->options.persist_remote_ip) - || - ( c->sig->source != SIG_SOURCE_HARD && - ((c->c1.link_socket_addr.current_remote && c->c1.link_socket_addr.current_remote->ai_next) - || c->options.no_advance)) - ))) + + /* Preserve the resolved list of remote if the user request to or if we want + * reconnect to the same host again or there are still addresses that need + * to be tried */ + if (!(c->sig->signal_received == SIGUSR1 + && ( (c->options.persist_remote_ip) + || + ( c->sig->source != SIG_SOURCE_HARD + && ((c->c1.link_socket_addr.current_remote && c->c1.link_socket_addr.current_remote->ai_next) + || c->options.no_advance)) + ))) { - clear_remote_addrlist(&c->c1.link_socket_addr, !c->options.resolve_in_advance); + clear_remote_addrlist(&c->c1.link_socket_addr, !c->options.resolve_in_advance); } /* Clear the remote actual address when persist_remote_ip is not in use */ if (!(c->sig->signal_received == SIGUSR1 && c->options.persist_remote_ip)) - CLEAR (c->c1.link_socket_addr.actual); + { + CLEAR(c->c1.link_socket_addr.actual); + } - if (!(c->sig->signal_received == SIGUSR1 && c->options.persist_local_ip)) { - if (c->c1.link_socket_addr.bind_local && !c->options.resolve_in_advance) - freeaddrinfo(c->c1.link_socket_addr.bind_local); + if (!(c->sig->signal_received == SIGUSR1 && c->options.persist_local_ip)) + { + if (c->c1.link_socket_addr.bind_local && !c->options.resolve_in_advance) + { + freeaddrinfo(c->c1.link_socket_addr.bind_local); + } - c->c1.link_socket_addr.bind_local=NULL; - } + c->c1.link_socket_addr.bind_local = NULL; + } } /* * Close packet-id persistance file */ static void -do_close_packet_id (struct context *c) +do_close_packet_id(struct context *c) { #ifdef ENABLE_CRYPTO - packet_id_free (&c->c2.crypto_options.packet_id); - packet_id_persist_save (&c->c1.pid_persist); - if (!(c->sig->signal_received == SIGUSR1)) - packet_id_persist_close (&c->c1.pid_persist); + packet_id_free(&c->c2.crypto_options.packet_id); + packet_id_persist_save(&c->c1.pid_persist); + if (!(c->sig->signal_received == SIGUSR1)) + { + packet_id_persist_close(&c->c1.pid_persist); + } #endif } @@ -3097,12 +3383,12 @@ do_close_packet_id (struct context *c) * Close fragmentation handler. */ static void -do_close_fragment (struct context *c) +do_close_fragment(struct context *c) { - if (c->c2.fragment) + if (c->c2.fragment) { - fragment_free (c->c2.fragment); - c->c2.fragment = NULL; + fragment_free(c->c2.fragment); + c->c2.fragment = NULL; } } #endif @@ -3112,30 +3398,32 @@ do_close_fragment (struct context *c) */ static void -do_event_set_init (struct context *c, - bool need_us_timeout) +do_event_set_init(struct context *c, + bool need_us_timeout) { - unsigned int flags = 0; + unsigned int flags = 0; - c->c2.event_set_max = BASE_N_EVENTS; + c->c2.event_set_max = BASE_N_EVENTS; - flags |= EVENT_METHOD_FAST; + flags |= EVENT_METHOD_FAST; - if (need_us_timeout) - flags |= EVENT_METHOD_US_TIMEOUT; + if (need_us_timeout) + { + flags |= EVENT_METHOD_US_TIMEOUT; + } - c->c2.event_set = event_set_init (&c->c2.event_set_max, flags); - c->c2.event_set_owned = true; + c->c2.event_set = event_set_init(&c->c2.event_set_max, flags); + c->c2.event_set_owned = true; } static void -do_close_event_set (struct context *c) +do_close_event_set(struct context *c) { - if (c->c2.event_set && c->c2.event_set_owned) + if (c->c2.event_set && c->c2.event_set_owned) { - event_free (c->c2.event_set); - c->c2.event_set = NULL; - c->c2.event_set_owned = false; + event_free(c->c2.event_set); + c->c2.event_set = NULL; + c->c2.event_set_owned = false; } } @@ -3144,30 +3432,30 @@ do_close_event_set (struct context *c) */ static void -do_open_status_output (struct context *c) +do_open_status_output(struct context *c) { - if (!c->c1.status_output) + if (!c->c1.status_output) { - c->c1.status_output = status_open (c->options.status_file, - c->options.status_file_update_freq, - -1, - NULL, - STATUS_OUTPUT_WRITE); - c->c1.status_output_owned = true; + c->c1.status_output = status_open(c->options.status_file, + c->options.status_file_update_freq, + -1, + NULL, + STATUS_OUTPUT_WRITE); + c->c1.status_output_owned = true; } } static void -do_close_status_output (struct context *c) +do_close_status_output(struct context *c) { - if (!(c->sig->signal_received == SIGUSR1)) + if (!(c->sig->signal_received == SIGUSR1)) { - if (c->c1.status_output_owned && c->c1.status_output) - { - status_close (c->c1.status_output); - c->c1.status_output = NULL; - c->c1.status_output_owned = false; - } + if (c->c1.status_output_owned && c->c1.status_output) + { + status_close(c->c1.status_output); + c->c1.status_output = NULL; + c->c1.status_output_owned = false; + } } } @@ -3175,30 +3463,30 @@ do_close_status_output (struct context *c) * Handle ifconfig-pool persistance object. */ static void -do_open_ifconfig_pool_persist (struct context *c) +do_open_ifconfig_pool_persist(struct context *c) { #if P2MP_SERVER - if (!c->c1.ifconfig_pool_persist && c->options.ifconfig_pool_persist_filename) + if (!c->c1.ifconfig_pool_persist && c->options.ifconfig_pool_persist_filename) { - c->c1.ifconfig_pool_persist = ifconfig_pool_persist_init (c->options.ifconfig_pool_persist_filename, - c->options.ifconfig_pool_persist_refresh_freq); - c->c1.ifconfig_pool_persist_owned = true; + c->c1.ifconfig_pool_persist = ifconfig_pool_persist_init(c->options.ifconfig_pool_persist_filename, + c->options.ifconfig_pool_persist_refresh_freq); + c->c1.ifconfig_pool_persist_owned = true; } #endif } static void -do_close_ifconfig_pool_persist (struct context *c) +do_close_ifconfig_pool_persist(struct context *c) { #if P2MP_SERVER - if (!(c->sig->signal_received == SIGUSR1)) + if (!(c->sig->signal_received == SIGUSR1)) { - if (c->c1.ifconfig_pool_persist && c->c1.ifconfig_pool_persist_owned) - { - ifconfig_pool_persist_close (c->c1.ifconfig_pool_persist); - c->c1.ifconfig_pool_persist = NULL; - c->c1.ifconfig_pool_persist_owned = false; - } + if (c->c1.ifconfig_pool_persist && c->c1.ifconfig_pool_persist_owned) + { + ifconfig_pool_persist_close(c->c1.ifconfig_pool_persist); + c->c1.ifconfig_pool_persist = NULL; + c->c1.ifconfig_pool_persist_owned = false; + } } #endif } @@ -3208,21 +3496,21 @@ do_close_ifconfig_pool_persist (struct context *c) */ static void -do_inherit_env (struct context *c, const struct env_set *src) +do_inherit_env(struct context *c, const struct env_set *src) { - c->c2.es = env_set_create (NULL); - c->c2.es_owned = true; - env_set_inherit (c->c2.es, src); + c->c2.es = env_set_create(NULL); + c->c2.es_owned = true; + env_set_inherit(c->c2.es, src); } static void -do_env_set_destroy (struct context *c) +do_env_set_destroy(struct context *c) { - if (c->c2.es && c->c2.es_owned) + if (c->c2.es && c->c2.es_owned) { - env_set_destroy (c->c2.es); - c->c2.es = NULL; - c->c2.es_owned = false; + env_set_destroy(c->c2.es); + c->c2.es = NULL; + c->c2.es_owned = false; } } @@ -3235,182 +3523,200 @@ do_env_set_destroy (struct context *c) * (3) --shaper is disabled */ static void -do_setup_fast_io (struct context *c) +do_setup_fast_io(struct context *c) { - if (c->options.fast_io) + if (c->options.fast_io) { #ifdef _WIN32 - msg (M_INFO, "NOTE: --fast-io is disabled since we are running on Windows"); + msg(M_INFO, "NOTE: --fast-io is disabled since we are running on Windows"); #else - if (!proto_is_udp(c->options.ce.proto)) - msg (M_INFO, "NOTE: --fast-io is disabled since we are not using UDP"); - else - { + if (!proto_is_udp(c->options.ce.proto)) + { + msg(M_INFO, "NOTE: --fast-io is disabled since we are not using UDP"); + } + else + { #ifdef ENABLE_FEATURE_SHAPER - if (c->options.shaper) - msg (M_INFO, "NOTE: --fast-io is disabled since we are using --shaper"); - else + if (c->options.shaper) + { + msg(M_INFO, "NOTE: --fast-io is disabled since we are using --shaper"); + } + else #endif - { - c->c2.fast_io = true; - } - } + { + c->c2.fast_io = true; + } + } #endif } } static void -do_signal_on_tls_errors (struct context *c) +do_signal_on_tls_errors(struct context *c) { #ifdef ENABLE_CRYPTO - if (c->options.tls_exit) - c->c2.tls_exit_signal = SIGTERM; - else - c->c2.tls_exit_signal = SIGUSR1; + if (c->options.tls_exit) + { + c->c2.tls_exit_signal = SIGTERM; + } + else + { + c->c2.tls_exit_signal = SIGUSR1; + } #endif } #ifdef ENABLE_PLUGIN void -init_plugins (struct context *c) +init_plugins(struct context *c) { - if (c->options.plugin_list && !c->plugins) + if (c->options.plugin_list && !c->plugins) { - c->plugins = plugin_list_init (c->options.plugin_list); - c->plugins_owned = true; + c->plugins = plugin_list_init(c->options.plugin_list); + c->plugins_owned = true; } } void -open_plugins (struct context *c, const bool import_options, int init_point) -{ - if (c->plugins && c->plugins_owned) - { - if (import_options) - { - struct plugin_return pr, config; - plugin_return_init (&pr); - plugin_list_open (c->plugins, c->options.plugin_list, &pr, c->c2.es, init_point); - plugin_return_get_column (&pr, &config, "config"); - if (plugin_return_defined (&config)) - { - int i; - for (i = 0; i < config.n; ++i) - { - unsigned int option_types_found = 0; - if (config.list[i] && config.list[i]->value) - options_string_import (&c->options, - config.list[i]->value, - D_IMPORT_ERRORS|M_OPTERR, - OPT_P_DEFAULT & ~OPT_P_PLUGIN, - &option_types_found, - c->es); - } - } - plugin_return_free (&pr); - } - else - { - plugin_list_open (c->plugins, c->options.plugin_list, NULL, c->c2.es, init_point); - } +open_plugins(struct context *c, const bool import_options, int init_point) +{ + if (c->plugins && c->plugins_owned) + { + if (import_options) + { + struct plugin_return pr, config; + plugin_return_init(&pr); + plugin_list_open(c->plugins, c->options.plugin_list, &pr, c->c2.es, init_point); + plugin_return_get_column(&pr, &config, "config"); + if (plugin_return_defined(&config)) + { + int i; + for (i = 0; i < config.n; ++i) + { + unsigned int option_types_found = 0; + if (config.list[i] && config.list[i]->value) + { + options_string_import(&c->options, + config.list[i]->value, + D_IMPORT_ERRORS|M_OPTERR, + OPT_P_DEFAULT & ~OPT_P_PLUGIN, + &option_types_found, + c->es); + } + } + } + plugin_return_free(&pr); + } + else + { + plugin_list_open(c->plugins, c->options.plugin_list, NULL, c->c2.es, init_point); + } } } static void -do_close_plugins (struct context *c) +do_close_plugins(struct context *c) { - if (c->plugins && c->plugins_owned && !(c->sig->signal_received == SIGUSR1)) + if (c->plugins && c->plugins_owned && !(c->sig->signal_received == SIGUSR1)) { - plugin_list_close (c->plugins); - c->plugins = NULL; - c->plugins_owned = false; + plugin_list_close(c->plugins); + c->plugins = NULL; + c->plugins_owned = false; } } static void -do_inherit_plugins (struct context *c, const struct context *src) +do_inherit_plugins(struct context *c, const struct context *src) { - if (!c->plugins && src->plugins) + if (!c->plugins && src->plugins) { - c->plugins = plugin_list_inherit (src->plugins); - c->plugins_owned = true; + c->plugins = plugin_list_inherit(src->plugins); + c->plugins_owned = true; } } -#endif +#endif /* ifdef ENABLE_PLUGIN */ #ifdef ENABLE_MANAGEMENT static void -management_callback_status_p2p (void *arg, const int version, struct status_output *so) +management_callback_status_p2p(void *arg, const int version, struct status_output *so) { - struct context *c = (struct context *) arg; - print_status (c, so); + struct context *c = (struct context *) arg; + print_status(c, so); } void -management_show_net_callback (void *arg, const int msglevel) +management_show_net_callback(void *arg, const int msglevel) { #ifdef _WIN32 - show_routes (msglevel); - show_adapters (msglevel); - msg (msglevel, "END"); + show_routes(msglevel); + show_adapters(msglevel); + msg(msglevel, "END"); #else - msg (msglevel, "ERROR: Sorry, this command is currently only implemented on Windows"); + msg(msglevel, "ERROR: Sorry, this command is currently only implemented on Windows"); #endif } #ifdef TARGET_ANDROID int -management_callback_network_change (void *arg, bool samenetwork) +management_callback_network_change(void *arg, bool samenetwork) { /* Check if the client should translate the network change to a SIGUSR1 to - reestablish the connection or just reprotect the socket - - At the moment just assume that, for all settings that use pull (not - --static) and are not using peer-id reestablishing the connection is - required (unless the network is the same) - - The function returns -1 on invalid fd and -2 if the socket cannot be - reused. On the -2 return value the man_network_change function triggers - a SIGUSR1 to force a reconnect. - */ - - int socketfd=-1; - struct context *c = (struct context *) arg; - if (!c->c2.link_socket) - return -1; - if (c->c2.link_socket->sd == SOCKET_UNDEFINED) - return -1; + * reestablish the connection or just reprotect the socket + * + * At the moment just assume that, for all settings that use pull (not + * --static) and are not using peer-id reestablishing the connection is + * required (unless the network is the same) + * + * The function returns -1 on invalid fd and -2 if the socket cannot be + * reused. On the -2 return value the man_network_change function triggers + * a SIGUSR1 to force a reconnect. + */ + + int socketfd = -1; + struct context *c = (struct context *) arg; + if (!c->c2.link_socket) + { + return -1; + } + if (c->c2.link_socket->sd == SOCKET_UNDEFINED) + { + return -1; + } - socketfd = c->c2.link_socket->sd; - if (!c->options.pull || c->c2.tls_multi->use_peer_id || samenetwork) - return socketfd; - else - return -2; + socketfd = c->c2.link_socket->sd; + if (!c->options.pull || c->c2.tls_multi->use_peer_id || samenetwork) + { + return socketfd; + } + else + { + return -2; + } } -#endif +#endif /* ifdef TARGET_ANDROID */ -#endif +#endif /* ifdef ENABLE_MANAGEMENT */ void -init_management_callback_p2p (struct context *c) +init_management_callback_p2p(struct context *c) { #ifdef ENABLE_MANAGEMENT - if (management) - { - struct management_callback cb; - CLEAR (cb); - cb.arg = c; - cb.status = management_callback_status_p2p; - cb.show_net = management_show_net_callback; - cb.proxy_cmd = management_callback_proxy_cmd; - cb.remote_cmd = management_callback_remote_cmd; + if (management) + { + struct management_callback cb; + CLEAR(cb); + cb.arg = c; + cb.status = management_callback_status_p2p; + cb.show_net = management_show_net_callback; + cb.proxy_cmd = management_callback_proxy_cmd; + cb.remote_cmd = management_callback_remote_cmd; #ifdef TARGET_ANDROID - cb.network_change = management_callback_network_change; + cb.network_change = management_callback_network_change; #endif - management_set_callback (management, &cb); + management_set_callback(management, &cb); } #endif } @@ -3418,79 +3724,85 @@ init_management_callback_p2p (struct context *c) #ifdef ENABLE_MANAGEMENT void -init_management (struct context *c) +init_management(struct context *c) { - if (!management) - management = management_init (); + if (!management) + { + management = management_init(); + } } bool -open_management (struct context *c) -{ - /* initialize management layer */ - if (management) - { - if (c->options.management_addr) - { - unsigned int flags = c->options.management_flags; - if (c->options.mode == MODE_SERVER) - flags |= MF_SERVER; - if (management_open (management, - c->options.management_addr, - c->options.management_port, - c->options.management_user_pass, - c->options.management_client_user, - c->options.management_client_group, - c->options.management_log_history_cache, - c->options.management_echo_buffer_size, - c->options.management_state_buffer_size, - c->options.management_write_peer_info_file, - c->options.remap_sigusr1, - flags)) - { - management_set_state (management, - OPENVPN_STATE_CONNECTING, - NULL, - NULL, - NULL, - NULL, - NULL); - } - - /* initial management hold, called early, before first context initialization */ - do_hold (0); - if (IS_SIG (c)) - { - msg (M_WARN, "Signal received from management interface, exiting"); - return false; - } - } - else - close_management (); - } - return true; +open_management(struct context *c) +{ + /* initialize management layer */ + if (management) + { + if (c->options.management_addr) + { + unsigned int flags = c->options.management_flags; + if (c->options.mode == MODE_SERVER) + { + flags |= MF_SERVER; + } + if (management_open(management, + c->options.management_addr, + c->options.management_port, + c->options.management_user_pass, + c->options.management_client_user, + c->options.management_client_group, + c->options.management_log_history_cache, + c->options.management_echo_buffer_size, + c->options.management_state_buffer_size, + c->options.management_write_peer_info_file, + c->options.remap_sigusr1, + flags)) + { + management_set_state(management, + OPENVPN_STATE_CONNECTING, + NULL, + NULL, + NULL, + NULL, + NULL); + } + + /* initial management hold, called early, before first context initialization */ + do_hold(0); + if (IS_SIG(c)) + { + msg(M_WARN, "Signal received from management interface, exiting"); + return false; + } + } + else + { + close_management(); + } + } + return true; } void -close_management (void) +close_management(void) { - if (management) + if (management) { - management_close (management); - management = NULL; + management_close(management); + management = NULL; } } -#endif +#endif /* ifdef ENABLE_MANAGEMENT */ void -uninit_management_callback (void) +uninit_management_callback(void) { #ifdef ENABLE_MANAGEMENT - if (management) + if (management) { - management_clear_callback (management); + management_clear_callback(management); } #endif } @@ -3500,21 +3812,21 @@ uninit_management_callback (void) * signal settings. */ void -init_instance_handle_signals (struct context *c, const struct env_set *env, const unsigned int flags) +init_instance_handle_signals(struct context *c, const struct env_set *env, const unsigned int flags) { - pre_init_signal_catch (); - init_instance (c, env, flags); - post_init_signal_catch (); - - /* - * This is done so that signals thrown during - * initialization can bring us back to - * a management hold. - */ - if (IS_SIG (c)) + pre_init_signal_catch(); + init_instance(c, env, flags); + post_init_signal_catch(); + + /* + * This is done so that signals thrown during + * initialization can bring us back to + * a management hold. + */ + if (IS_SIG(c)) { - remap_signal (c); - uninit_management_callback (); + remap_signal(c); + uninit_management_callback(); } } @@ -3522,467 +3834,555 @@ init_instance_handle_signals (struct context *c, const struct env_set *env, cons * Initialize a tunnel instance. */ void -init_instance (struct context *c, const struct env_set *env, const unsigned int flags) +init_instance(struct context *c, const struct env_set *env, const unsigned int flags) { - const struct options *options = &c->options; - const bool child = (c->mode == CM_CHILD_TCP || c->mode == CM_CHILD_UDP); - int link_socket_mode = LS_MODE_DEFAULT; + const struct options *options = &c->options; + const bool child = (c->mode == CM_CHILD_TCP || c->mode == CM_CHILD_UDP); + int link_socket_mode = LS_MODE_DEFAULT; - /* init garbage collection level */ - gc_init (&c->c2.gc); + /* init garbage collection level */ + gc_init(&c->c2.gc); - /* inherit environmental variables */ - if (env) - do_inherit_env (c, env); + /* inherit environmental variables */ + if (env) + { + do_inherit_env(c, env); + } - /* signals caught here will abort */ - c->sig->signal_received = 0; - c->sig->signal_text = NULL; - c->sig->source = SIG_SOURCE_SOFT; + /* signals caught here will abort */ + c->sig->signal_received = 0; + c->sig->signal_text = NULL; + c->sig->source = SIG_SOURCE_SOFT; - if (c->mode == CM_P2P) - init_management_callback_p2p (c); + if (c->mode == CM_P2P) + { + init_management_callback_p2p(c); + } - /* possible sleep or management hold if restart */ - if (c->mode == CM_P2P || c->mode == CM_TOP) + /* possible sleep or management hold if restart */ + if (c->mode == CM_P2P || c->mode == CM_TOP) { - do_startup_pause (c); - if (IS_SIG (c)) - goto sig; + do_startup_pause(c); + if (IS_SIG(c)) + { + goto sig; + } } - if (c->options.resolve_in_advance) + if (c->options.resolve_in_advance) { - do_preresolve (c); - if (IS_SIG (c)) - goto sig; + do_preresolve(c); + if (IS_SIG(c)) + { + goto sig; + } } - /* map in current connection entry */ - next_connection_entry (c); + /* map in current connection entry */ + next_connection_entry(c); - /* link_socket_mode allows CM_CHILD_TCP - instances to inherit acceptable fds - from a top-level parent */ - if (c->options.ce.proto == PROTO_TCP_SERVER) + /* link_socket_mode allows CM_CHILD_TCP + * instances to inherit acceptable fds + * from a top-level parent */ + if (c->options.ce.proto == PROTO_TCP_SERVER) { - if (c->mode == CM_TOP) - link_socket_mode = LS_MODE_TCP_LISTEN; - else if (c->mode == CM_CHILD_TCP) - link_socket_mode = LS_MODE_TCP_ACCEPT_FROM; + if (c->mode == CM_TOP) + { + link_socket_mode = LS_MODE_TCP_LISTEN; + } + else if (c->mode == CM_CHILD_TCP) + { + link_socket_mode = LS_MODE_TCP_ACCEPT_FROM; + } } - /* should we disable paging? */ - if (c->first_time && options->mlock) - platform_mlockall (true); + /* should we disable paging? */ + if (c->first_time && options->mlock) + { + platform_mlockall(true); + } #if P2MP - /* get passwords if undefined */ - if (auth_retry_get () == AR_INTERACT) - init_query_passwords (c); + /* get passwords if undefined */ + if (auth_retry_get() == AR_INTERACT) + { + init_query_passwords(c); + } #endif - /* initialize context level 2 --verb/--mute parms */ - init_verb_mute (c, IVM_LEVEL_2); + /* initialize context level 2 --verb/--mute parms */ + init_verb_mute(c, IVM_LEVEL_2); + + /* set error message delay for non-server modes */ + if (c->mode == CM_P2P) + { + set_check_status_error_delay(P2P_ERROR_DELAY_MS); + } - /* set error message delay for non-server modes */ - if (c->mode == CM_P2P) - set_check_status_error_delay (P2P_ERROR_DELAY_MS); - - /* warn about inconsistent options */ - if (c->mode == CM_P2P || c->mode == CM_TOP) - do_option_warnings (c); + /* warn about inconsistent options */ + if (c->mode == CM_P2P || c->mode == CM_TOP) + { + do_option_warnings(c); + } #ifdef ENABLE_PLUGIN - /* initialize plugins */ - if (c->mode == CM_P2P || c->mode == CM_TOP) - open_plugins (c, false, OPENVPN_PLUGIN_INIT_PRE_DAEMON); + /* initialize plugins */ + if (c->mode == CM_P2P || c->mode == CM_TOP) + { + open_plugins(c, false, OPENVPN_PLUGIN_INIT_PRE_DAEMON); + } #endif - /* should we enable fast I/O? */ - if (c->mode == CM_P2P || c->mode == CM_TOP) - do_setup_fast_io (c); + /* should we enable fast I/O? */ + if (c->mode == CM_P2P || c->mode == CM_TOP) + { + do_setup_fast_io(c); + } - /* should we throw a signal on TLS errors? */ - do_signal_on_tls_errors (c); + /* should we throw a signal on TLS errors? */ + do_signal_on_tls_errors(c); - /* open --status file */ - if (c->mode == CM_P2P || c->mode == CM_TOP) - do_open_status_output (c); + /* open --status file */ + if (c->mode == CM_P2P || c->mode == CM_TOP) + { + do_open_status_output(c); + } - /* open --ifconfig-pool-persist file */ - if (c->mode == CM_TOP) - do_open_ifconfig_pool_persist (c); + /* open --ifconfig-pool-persist file */ + if (c->mode == CM_TOP) + { + do_open_ifconfig_pool_persist(c); + } #ifdef ENABLE_OCC - /* reset OCC state */ - if (c->mode == CM_P2P || child) - c->c2.occ_op = occ_reset_op (); + /* reset OCC state */ + if (c->mode == CM_P2P || child) + { + c->c2.occ_op = occ_reset_op(); + } #endif - /* our wait-for-i/o objects, different for posix vs. win32 */ - if (c->mode == CM_P2P) - do_event_set_init (c, SHAPER_DEFINED (&c->options)); - else if (c->mode == CM_CHILD_TCP) - do_event_set_init (c, false); + /* our wait-for-i/o objects, different for posix vs. win32 */ + if (c->mode == CM_P2P) + { + do_event_set_init(c, SHAPER_DEFINED(&c->options)); + } + else if (c->mode == CM_CHILD_TCP) + { + do_event_set_init(c, false); + } - /* initialize HTTP or SOCKS proxy object at scope level 2 */ - init_proxy (c); + /* initialize HTTP or SOCKS proxy object at scope level 2 */ + init_proxy(c); - /* allocate our socket object */ - if (c->mode == CM_P2P || c->mode == CM_TOP || c->mode == CM_CHILD_TCP) - do_link_socket_new (c); + /* allocate our socket object */ + if (c->mode == CM_P2P || c->mode == CM_TOP || c->mode == CM_CHILD_TCP) + { + do_link_socket_new(c); + } #ifdef ENABLE_FRAGMENT - /* initialize internal fragmentation object */ - if (options->ce.fragment && (c->mode == CM_P2P || child)) - c->c2.fragment = fragment_init (&c->c2.frame); + /* initialize internal fragmentation object */ + if (options->ce.fragment && (c->mode == CM_P2P || child)) + { + c->c2.fragment = fragment_init(&c->c2.frame); + } #endif - /* init crypto layer */ - { - unsigned int crypto_flags = 0; - if (c->mode == CM_TOP) - crypto_flags = CF_INIT_TLS_AUTH_STANDALONE; - else if (c->mode == CM_P2P) - crypto_flags = CF_LOAD_PERSISTED_PACKET_ID | CF_INIT_TLS_MULTI; - else if (child) - crypto_flags = CF_INIT_TLS_MULTI; - do_init_crypto (c, crypto_flags); - if (IS_SIG (c) && !child) - goto sig; - } + /* init crypto layer */ + { + unsigned int crypto_flags = 0; + if (c->mode == CM_TOP) + { + crypto_flags = CF_INIT_TLS_AUTH_STANDALONE; + } + else if (c->mode == CM_P2P) + { + crypto_flags = CF_LOAD_PERSISTED_PACKET_ID | CF_INIT_TLS_MULTI; + } + else if (child) + { + crypto_flags = CF_INIT_TLS_MULTI; + } + do_init_crypto(c, crypto_flags); + if (IS_SIG(c) && !child) + { + goto sig; + } + } #ifdef USE_COMP - /* initialize compression library. */ - if (comp_enabled(&options->comp) && (c->mode == CM_P2P || child)) - c->c2.comp_context = comp_init (&options->comp); + /* initialize compression library. */ + if (comp_enabled(&options->comp) && (c->mode == CM_P2P || child)) + { + c->c2.comp_context = comp_init(&options->comp); + } #endif - /* initialize MTU variables */ - do_init_frame (c); + /* initialize MTU variables */ + do_init_frame(c); - /* initialize TLS MTU variables */ - do_init_frame_tls (c); + /* initialize TLS MTU variables */ + do_init_frame_tls(c); - /* init workspace buffers whose size is derived from frame size */ - if (c->mode == CM_P2P || c->mode == CM_CHILD_TCP) - do_init_buffers (c); + /* init workspace buffers whose size is derived from frame size */ + if (c->mode == CM_P2P || c->mode == CM_CHILD_TCP) + { + do_init_buffers(c); + } #ifdef ENABLE_FRAGMENT - /* initialize internal fragmentation capability with known frame size */ - if (options->ce.fragment && (c->mode == CM_P2P || child)) - do_init_fragment (c); + /* initialize internal fragmentation capability with known frame size */ + if (options->ce.fragment && (c->mode == CM_P2P || child)) + { + do_init_fragment(c); + } #endif - /* initialize dynamic MTU variable */ - frame_init_mssfix (&c->c2.frame, &c->options); + /* initialize dynamic MTU variable */ + frame_init_mssfix(&c->c2.frame, &c->options); - /* bind the TCP/UDP socket */ - if (c->mode == CM_P2P || c->mode == CM_TOP || c->mode == CM_CHILD_TCP) - do_init_socket_1 (c, link_socket_mode); + /* bind the TCP/UDP socket */ + if (c->mode == CM_P2P || c->mode == CM_TOP || c->mode == CM_CHILD_TCP) + { + do_init_socket_1(c, link_socket_mode); + } - /* initialize tun/tap device object, - open tun/tap device, ifconfig, run up script, etc. */ - if (!(options->up_delay || PULL_DEFINED (options)) && (c->mode == CM_P2P || c->mode == CM_TOP)) - c->c2.did_open_tun = do_open_tun (c); + /* initialize tun/tap device object, + * open tun/tap device, ifconfig, run up script, etc. */ + if (!(options->up_delay || PULL_DEFINED(options)) && (c->mode == CM_P2P || c->mode == CM_TOP)) + { + c->c2.did_open_tun = do_open_tun(c); + } - /* print MTU info */ - do_print_data_channel_mtu_parms (c); + /* print MTU info */ + do_print_data_channel_mtu_parms(c); #ifdef ENABLE_OCC - /* get local and remote options compatibility strings */ - if (c->mode == CM_P2P || child) - do_compute_occ_strings (c); + /* get local and remote options compatibility strings */ + if (c->mode == CM_P2P || child) + { + do_compute_occ_strings(c); + } #endif - /* initialize output speed limiter */ - if (c->mode == CM_P2P) - do_init_traffic_shaper (c); + /* initialize output speed limiter */ + if (c->mode == CM_P2P) + { + do_init_traffic_shaper(c); + } - /* do one-time inits, and possibily become a daemon here */ - do_init_first_time (c); + /* do one-time inits, and possibily become a daemon here */ + do_init_first_time(c); #ifdef ENABLE_PLUGIN - /* initialize plugins */ - if (c->mode == CM_P2P || c->mode == CM_TOP) - open_plugins (c, false, OPENVPN_PLUGIN_INIT_POST_DAEMON); + /* initialize plugins */ + if (c->mode == CM_P2P || c->mode == CM_TOP) + { + open_plugins(c, false, OPENVPN_PLUGIN_INIT_POST_DAEMON); + } #endif - /* initialise connect timeout timer */ - do_init_server_poll_timeout(c); + /* initialise connect timeout timer */ + do_init_server_poll_timeout(c); - /* finalize the TCP/UDP socket */ - if (c->mode == CM_P2P || c->mode == CM_TOP || c->mode == CM_CHILD_TCP) - do_init_socket_2 (c); + /* finalize the TCP/UDP socket */ + if (c->mode == CM_P2P || c->mode == CM_TOP || c->mode == CM_CHILD_TCP) + { + do_init_socket_2(c); + } - /* - * Actually do UID/GID downgrade, and chroot, if requested. - * May be delayed by --client, --pull, or --up-delay. - */ - do_uid_gid_chroot (c, c->c2.did_open_tun); + /* + * Actually do UID/GID downgrade, and chroot, if requested. + * May be delayed by --client, --pull, or --up-delay. + */ + do_uid_gid_chroot(c, c->c2.did_open_tun); - /* initialize timers */ - if (c->mode == CM_P2P || child) - do_init_timers (c, false); + /* initialize timers */ + if (c->mode == CM_P2P || child) + { + do_init_timers(c, false); + } #ifdef ENABLE_PLUGIN - /* initialize plugins */ - if (c->mode == CM_P2P || c->mode == CM_TOP) - open_plugins (c, false, OPENVPN_PLUGIN_INIT_POST_UID_CHANGE); + /* initialize plugins */ + if (c->mode == CM_P2P || c->mode == CM_TOP) + { + open_plugins(c, false, OPENVPN_PLUGIN_INIT_POST_UID_CHANGE); + } #endif #if PORT_SHARE - /* share OpenVPN port with foreign (such as HTTPS) server */ - if (c->first_time && (c->mode == CM_P2P || c->mode == CM_TOP)) - init_port_share (c); + /* share OpenVPN port with foreign (such as HTTPS) server */ + if (c->first_time && (c->mode == CM_P2P || c->mode == CM_TOP)) + { + init_port_share(c); + } #endif - + #ifdef ENABLE_PF - if (child) - pf_init_context (c); + if (child) + { + pf_init_context(c); + } #endif - /* Check for signals */ - if (IS_SIG (c)) - goto sig; + /* Check for signals */ + if (IS_SIG(c)) + { + goto sig; + } - return; + return; - sig: - if (!c->sig->signal_text) - c->sig->signal_text = "init_instance"; - close_context (c, -1, flags); - return; +sig: + if (!c->sig->signal_text) + { + c->sig->signal_text = "init_instance"; + } + close_context(c, -1, flags); + return; } /* * Close a tunnel instance. */ void -close_instance (struct context *c) +close_instance(struct context *c) { - /* close event objects */ - do_close_event_set (c); + /* close event objects */ + do_close_event_set(c); if (c->mode == CM_P2P - || c->mode == CM_CHILD_TCP - || c->mode == CM_CHILD_UDP - || c->mode == CM_TOP) - { - /* if xinetd/inetd mode, don't allow restart */ - do_close_check_if_restart_permitted (c); + || c->mode == CM_CHILD_TCP + || c->mode == CM_CHILD_UDP + || c->mode == CM_TOP) + { + /* if xinetd/inetd mode, don't allow restart */ + do_close_check_if_restart_permitted(c); #ifdef USE_COMP - if (c->c2.comp_context) - { - comp_uninit (c->c2.comp_context); - c->c2.comp_context = NULL; - } + if (c->c2.comp_context) + { + comp_uninit(c->c2.comp_context); + c->c2.comp_context = NULL; + } #endif - /* free buffers */ - do_close_free_buf (c); + /* free buffers */ + do_close_free_buf(c); - /* close TLS */ - do_close_tls (c); + /* close TLS */ + do_close_tls(c); - /* free key schedules */ - do_close_free_key_schedule (c, (c->mode == CM_P2P || c->mode == CM_TOP)); + /* free key schedules */ + do_close_free_key_schedule(c, (c->mode == CM_P2P || c->mode == CM_TOP)); - /* close TCP/UDP connection */ - do_close_link_socket (c); + /* close TCP/UDP connection */ + do_close_link_socket(c); - /* close TUN/TAP device */ - do_close_tun (c, false); + /* close TUN/TAP device */ + do_close_tun(c, false); #ifdef MANAGEMENT_DEF_AUTH - if (management) - management_notify_client_close (management, &c->c2.mda_context, NULL); + if (management) + { + management_notify_client_close(management, &c->c2.mda_context, NULL); + } #endif #ifdef ENABLE_PF - pf_destroy_context (&c->c2.pf); + pf_destroy_context(&c->c2.pf); #endif #ifdef ENABLE_PLUGIN - /* call plugin close functions and unload */ - do_close_plugins (c); + /* call plugin close functions and unload */ + do_close_plugins(c); #endif - /* close packet-id persistance file */ - do_close_packet_id (c); + /* close packet-id persistance file */ + do_close_packet_id(c); - /* close --status file */ - do_close_status_output (c); + /* close --status file */ + do_close_status_output(c); #ifdef ENABLE_FRAGMENT - /* close fragmentation handler */ - do_close_fragment (c); + /* close fragmentation handler */ + do_close_fragment(c); #endif - /* close --ifconfig-pool-persist obj */ - do_close_ifconfig_pool_persist (c); + /* close --ifconfig-pool-persist obj */ + do_close_ifconfig_pool_persist(c); - /* free up environmental variable store */ - do_env_set_destroy (c); + /* free up environmental variable store */ + do_env_set_destroy(c); - /* close HTTP or SOCKS proxy */ - uninit_proxy (c); + /* close HTTP or SOCKS proxy */ + uninit_proxy(c); - /* garbage collect */ - gc_free (&c->c2.gc); - } + /* garbage collect */ + gc_free(&c->c2.gc); + } } void -inherit_context_child (struct context *dest, - const struct context *src) +inherit_context_child(struct context *dest, + const struct context *src) { - CLEAR (*dest); + CLEAR(*dest); - /* proto_is_dgram will ASSERT(0) if proto is invalid */ - dest->mode = proto_is_dgram(src->options.ce.proto)? CM_CHILD_UDP : CM_CHILD_TCP; + /* proto_is_dgram will ASSERT(0) if proto is invalid */ + dest->mode = proto_is_dgram(src->options.ce.proto) ? CM_CHILD_UDP : CM_CHILD_TCP; - dest->gc = gc_new (); + dest->gc = gc_new(); - ALLOC_OBJ_CLEAR_GC (dest->sig, struct signal_info, &dest->gc); + ALLOC_OBJ_CLEAR_GC(dest->sig, struct signal_info, &dest->gc); - /* c1 init */ - packet_id_persist_init (&dest->c1.pid_persist); + /* c1 init */ + packet_id_persist_init(&dest->c1.pid_persist); #ifdef ENABLE_CRYPTO - dest->c1.ks.key_type = src->c1.ks.key_type; - /* inherit SSL context */ - dest->c1.ks.ssl_ctx = src->c1.ks.ssl_ctx; - dest->c1.ks.tls_wrap_key = src->c1.ks.tls_wrap_key; - dest->c1.ks.tls_auth_key_type = src->c1.ks.tls_auth_key_type; - /* inherit pre-NCP ciphers */ - dest->c1.ciphername = src->c1.ciphername; - dest->c1.authname = src->c1.authname; - dest->c1.keysize = src->c1.keysize; -#endif - - /* options */ - dest->options = src->options; - options_detach (&dest->options); - - if (dest->mode == CM_CHILD_TCP) + dest->c1.ks.key_type = src->c1.ks.key_type; + /* inherit SSL context */ + dest->c1.ks.ssl_ctx = src->c1.ks.ssl_ctx; + dest->c1.ks.tls_wrap_key = src->c1.ks.tls_wrap_key; + dest->c1.ks.tls_auth_key_type = src->c1.ks.tls_auth_key_type; + /* inherit pre-NCP ciphers */ + dest->c1.ciphername = src->c1.ciphername; + dest->c1.authname = src->c1.authname; + dest->c1.keysize = src->c1.keysize; +#endif + + /* options */ + dest->options = src->options; + options_detach(&dest->options); + + if (dest->mode == CM_CHILD_TCP) { - /* - * The CM_TOP context does the socket listen(), - * and the CM_CHILD_TCP context does the accept(). - */ - dest->c2.accept_from = src->c2.link_socket; + /* + * The CM_TOP context does the socket listen(), + * and the CM_CHILD_TCP context does the accept(). + */ + dest->c2.accept_from = src->c2.link_socket; } #ifdef ENABLE_PLUGIN - /* inherit plugins */ - do_inherit_plugins (dest, src); + /* inherit plugins */ + do_inherit_plugins(dest, src); #endif - /* context init */ - init_instance (dest, src->c2.es, CC_NO_CLOSE | CC_USR1_TO_HUP); - if (IS_SIG (dest)) - return; + /* context init */ + init_instance(dest, src->c2.es, CC_NO_CLOSE | CC_USR1_TO_HUP); + if (IS_SIG(dest)) + { + return; + } - /* inherit tun/tap interface object */ - dest->c1.tuntap = src->c1.tuntap; + /* inherit tun/tap interface object */ + dest->c1.tuntap = src->c1.tuntap; - /* UDP inherits some extra things which TCP does not */ - if (dest->mode == CM_CHILD_UDP) + /* UDP inherits some extra things which TCP does not */ + if (dest->mode == CM_CHILD_UDP) { - /* inherit buffers */ - dest->c2.buffers = src->c2.buffers; + /* inherit buffers */ + dest->c2.buffers = src->c2.buffers; - /* inherit parent link_socket and tuntap */ - dest->c2.link_socket = src->c2.link_socket; + /* inherit parent link_socket and tuntap */ + dest->c2.link_socket = src->c2.link_socket; - ALLOC_OBJ_GC (dest->c2.link_socket_info, struct link_socket_info, &dest->gc); - *dest->c2.link_socket_info = src->c2.link_socket->info; + ALLOC_OBJ_GC(dest->c2.link_socket_info, struct link_socket_info, &dest->gc); + *dest->c2.link_socket_info = src->c2.link_socket->info; - /* locally override some link_socket_info fields */ - dest->c2.link_socket_info->lsa = &dest->c1.link_socket_addr; - dest->c2.link_socket_info->connection_established = false; + /* locally override some link_socket_info fields */ + dest->c2.link_socket_info->lsa = &dest->c1.link_socket_addr; + dest->c2.link_socket_info->connection_established = false; } } void -inherit_context_top (struct context *dest, - const struct context *src) +inherit_context_top(struct context *dest, + const struct context *src) { - /* copy parent */ - *dest = *src; + /* copy parent */ + *dest = *src; - /* - * CM_TOP_CLONE will prevent close_instance from freeing or closing - * resources owned by the parent. - * - * Also note that CM_TOP_CLONE context objects are - * closed by multi_top_free in multi.c. - */ - dest->mode = CM_TOP_CLONE; + /* + * CM_TOP_CLONE will prevent close_instance from freeing or closing + * resources owned by the parent. + * + * Also note that CM_TOP_CLONE context objects are + * closed by multi_top_free in multi.c. + */ + dest->mode = CM_TOP_CLONE; - dest->first_time = false; - dest->c0 = NULL; + dest->first_time = false; + dest->c0 = NULL; - options_detach (&dest->options); - gc_detach (&dest->gc); - gc_detach (&dest->c2.gc); + options_detach(&dest->options); + gc_detach(&dest->gc); + gc_detach(&dest->c2.gc); - /* detach plugins */ - dest->plugins_owned = false; + /* detach plugins */ + dest->plugins_owned = false; #ifdef ENABLE_CRYPTO - dest->c2.tls_multi = NULL; + dest->c2.tls_multi = NULL; #endif - /* detach c1 ownership */ - dest->c1.tuntap_owned = false; - dest->c1.status_output_owned = false; + /* detach c1 ownership */ + dest->c1.tuntap_owned = false; + dest->c1.status_output_owned = false; #if P2MP_SERVER - dest->c1.ifconfig_pool_persist_owned = false; + dest->c1.ifconfig_pool_persist_owned = false; #endif - /* detach c2 ownership */ - dest->c2.event_set_owned = false; - dest->c2.link_socket_owned = false; - dest->c2.buffers_owned = false; - dest->c2.es_owned = false; + /* detach c2 ownership */ + dest->c2.event_set_owned = false; + dest->c2.link_socket_owned = false; + dest->c2.buffers_owned = false; + dest->c2.es_owned = false; - dest->c2.event_set = NULL; - if (proto_is_dgram(src->options.ce.proto)) - do_event_set_init (dest, false); + dest->c2.event_set = NULL; + if (proto_is_dgram(src->options.ce.proto)) + { + do_event_set_init(dest, false); + } #ifdef USE_COMP - dest->c2.comp_context = NULL; + dest->c2.comp_context = NULL; #endif } void -close_context (struct context *c, int sig, unsigned int flags) +close_context(struct context *c, int sig, unsigned int flags) { - ASSERT (c); - ASSERT (c->sig); + ASSERT(c); + ASSERT(c->sig); - if (sig >= 0) - c->sig->signal_received = sig; + if (sig >= 0) + { + c->sig->signal_received = sig; + } - if (c->sig->signal_received == SIGUSR1) + if (c->sig->signal_received == SIGUSR1) { - if ((flags & CC_USR1_TO_HUP) - || (c->sig->source == SIG_SOURCE_HARD && (flags & CC_HARD_USR1_TO_HUP))) + if ((flags & CC_USR1_TO_HUP) + || (c->sig->source == SIG_SOURCE_HARD && (flags & CC_HARD_USR1_TO_HUP))) { - c->sig->signal_received = SIGHUP; - c->sig->signal_text = "close_context usr1 to hup"; + c->sig->signal_received = SIGHUP; + c->sig->signal_text = "close_context usr1 to hup"; } } - if (!(flags & CC_NO_CLOSE)) - close_instance (c); + if (!(flags & CC_NO_CLOSE)) + { + close_instance(c); + } - if (flags & CC_GC_FREE) - context_gc_free (c); + if (flags & CC_GC_FREE) + { + context_gc_free(c); + } } #ifdef ENABLE_CRYPTO @@ -3992,48 +4392,48 @@ close_context (struct context *c, int sig, unsigned int flags) * on the crypto subsystem. */ static void * -test_crypto_thread (void *arg) +test_crypto_thread(void *arg) { - struct context *c = (struct context *) arg; - const struct options *options = &c->options; + struct context *c = (struct context *) arg; + const struct options *options = &c->options; - ASSERT (options->test_crypto); - init_verb_mute (c, IVM_LEVEL_1); - context_init_1 (c); - next_connection_entry(c); - do_init_crypto_static (c, 0); + ASSERT(options->test_crypto); + init_verb_mute(c, IVM_LEVEL_1); + context_init_1(c); + next_connection_entry(c); + do_init_crypto_static(c, 0); - frame_finalize_options (c, options); + frame_finalize_options(c, options); - test_crypto (&c->c2.crypto_options, &c->c2.frame); + test_crypto(&c->c2.crypto_options, &c->c2.frame); - key_schedule_free (&c->c1.ks, true); - packet_id_free (&c->c2.crypto_options.packet_id); + key_schedule_free(&c->c1.ks, true); + packet_id_free(&c->c2.crypto_options.packet_id); - context_gc_free (c); - return NULL; + context_gc_free(c); + return NULL; } #endif /* ENABLE_CRYPTO */ bool -do_test_crypto (const struct options *o) +do_test_crypto(const struct options *o) { #ifdef ENABLE_CRYPTO - if (o->test_crypto) + if (o->test_crypto) { - struct context c; + struct context c; - /* print version number */ - msg (M_INFO, "%s", title_string); + /* print version number */ + msg(M_INFO, "%s", title_string); - context_clear (&c); - c.options = *o; - options_detach (&c.options); - c.first_time = true; - test_crypto_thread ((void *) &c); - return true; + context_clear(&c); + c.options = *o; + options_detach(&c.options); + c.first_time = true; + test_crypto_thread((void *) &c); + return true; } #endif - return false; + return false; } diff --git a/src/openvpn/init.h b/src/openvpn/init.h index 524bc64b147..d742bc7c7e0 100644 --- a/src/openvpn/init.h +++ b/src/openvpn/init.h @@ -33,103 +33,112 @@ */ #define BASE_N_EVENTS 4 -void context_clear (struct context *c); -void context_clear_1 (struct context *c); -void context_clear_2 (struct context *c); -void context_init_1 (struct context *c); -void context_clear_all_except_first_time (struct context *c); +void context_clear(struct context *c); -bool init_static (void); +void context_clear_1(struct context *c); -void uninit_static (void); +void context_clear_2(struct context *c); -#define IVM_LEVEL_1 (1<<0) +void context_init_1(struct context *c); + +void context_clear_all_except_first_time(struct context *c); + +bool init_static(void); + +void uninit_static(void); + +#define IVM_LEVEL_1 (1<<0) #define IVM_LEVEL_2 (1<<1) -void init_verb_mute (struct context *c, unsigned int flags); +void init_verb_mute(struct context *c, unsigned int flags); -void init_options_dev (struct options *options); +void init_options_dev(struct options *options); -bool print_openssl_info (const struct options *options); +bool print_openssl_info(const struct options *options); -bool do_genkey (const struct options *options); +bool do_genkey(const struct options *options); -bool do_persist_tuntap (const struct options *options); +bool do_persist_tuntap(const struct options *options); -bool possibly_become_daemon (const struct options *options); +bool possibly_become_daemon(const struct options *options); -void pre_setup (const struct options *options); +void pre_setup(const struct options *options); -void init_instance_handle_signals (struct context *c, const struct env_set *env, const unsigned int flags); +void init_instance_handle_signals(struct context *c, const struct env_set *env, const unsigned int flags); -void init_instance (struct context *c, const struct env_set *env, const unsigned int flags); +void init_instance(struct context *c, const struct env_set *env, const unsigned int flags); /** * Query for private key and auth-user-pass username/passwords. */ -void init_query_passwords (const struct context *c); +void init_query_passwords(const struct context *c); -void do_route (const struct options *options, - struct route_list *route_list, - struct route_ipv6_list *route_ipv6_list, - const struct tuntap *tt, - const struct plugin_list *plugins, - struct env_set *es); +void do_route(const struct options *options, + struct route_list *route_list, + struct route_ipv6_list *route_ipv6_list, + const struct tuntap *tt, + const struct plugin_list *plugins, + struct env_set *es); -void close_instance (struct context *c); +void close_instance(struct context *c); -bool do_test_crypto (const struct options *o); +bool do_test_crypto(const struct options *o); -void context_gc_free (struct context *c); +void context_gc_free(struct context *c); -bool do_up (struct context *c, - bool pulled_options, - unsigned int option_types_found); +bool do_up(struct context *c, + bool pulled_options, + unsigned int option_types_found); -unsigned int pull_permission_mask (const struct context *c); +unsigned int pull_permission_mask(const struct context *c); -const char *format_common_name (struct context *c, struct gc_arena *gc); +const char *format_common_name(struct context *c, struct gc_arena *gc); -void reset_coarse_timers (struct context *c); +void reset_coarse_timers(struct context *c); -bool do_deferred_options (struct context *c, const unsigned int found); +bool do_deferred_options(struct context *c, const unsigned int found); -void inherit_context_child (struct context *dest, - const struct context *src); +void inherit_context_child(struct context *dest, + const struct context *src); -void inherit_context_top (struct context *dest, - const struct context *src); +void inherit_context_top(struct context *dest, + const struct context *src); #define CC_GC_FREE (1<<0) #define CC_USR1_TO_HUP (1<<1) #define CC_HARD_USR1_TO_HUP (1<<2) #define CC_NO_CLOSE (1<<3) -void close_context (struct context *c, int sig, unsigned int flags); +void close_context(struct context *c, int sig, unsigned int flags); -struct context_buffers *init_context_buffers (const struct frame *frame); +struct context_buffers *init_context_buffers(const struct frame *frame); -void free_context_buffers (struct context_buffers *b); +void free_context_buffers(struct context_buffers *b); #define ISC_ERRORS (1<<0) #define ISC_SERVER (1<<1) -void initialization_sequence_completed (struct context *c, const unsigned int flags); +void initialization_sequence_completed(struct context *c, const unsigned int flags); #ifdef ENABLE_MANAGEMENT -void init_management (struct context *c); -bool open_management (struct context *c); -void close_management (void); +void init_management(struct context *c); + +bool open_management(struct context *c); -void management_show_net_callback (void *arg, const int msglevel); +void close_management(void); + +void management_show_net_callback(void *arg, const int msglevel); #endif -void init_management_callback_p2p (struct context *c); -void uninit_management_callback (void); +void init_management_callback_p2p(struct context *c); + +void uninit_management_callback(void); #ifdef ENABLE_PLUGIN -void init_plugins (struct context *c); -void open_plugins (struct context *c, const bool import_options, int init_point); -#endif +void init_plugins(struct context *c); + +void open_plugins(struct context *c, const bool import_options, int init_point); #endif + +#endif /* ifndef INIT_H */ diff --git a/src/openvpn/integer.h b/src/openvpn/integer.h index f0fc196e67c..ee9a43eab97 100644 --- a/src/openvpn/integer.h +++ b/src/openvpn/integer.h @@ -32,34 +32,50 @@ */ static inline int -max_int (int x, int y) +max_int(int x, int y) { - if (x > y) - return x; - else - return y; + if (x > y) + { + return x; + } + else + { + return y; + } } static inline int -min_int (int x, int y) +min_int(int x, int y) { - if (x < y) - return x; - else - return y; + if (x < y) + { + return x; + } + else + { + return y; + } } static inline int -constrain_int (int x, int min, int max) +constrain_int(int x, int min, int max) { - if (min > max) - return min; - if (x < min) - return min; - else if (x > max) - return max; - else - return x; + if (min > max) + { + return min; + } + if (x < min) + { + return min; + } + else if (x > max) + { + return max; + } + else + { + return x; + } } /* @@ -75,10 +91,10 @@ constrain_int (int x, int min, int max) static inline int modulo_subtract(int x, int y, int mod) { - const int d1 = x - y; - const int d2 = (x > y ? -mod : mod) + d1; - ASSERT (0 <= x && x < mod && 0 <= y && y < mod); - return abs(d1) > abs(d2) ? d2 : d1; + const int d1 = x - y; + const int d2 = (x > y ? -mod : mod) + d1; + ASSERT(0 <= x && x < mod && 0 <= y && y < mod); + return abs(d1) > abs(d2) ? d2 : d1; } /* @@ -90,25 +106,31 @@ modulo_subtract(int x, int y, int mod) static inline int modulo_add(int x, int y, int mod) { - int sum = x + y; - ASSERT (0 <= x && x < mod && -mod <= y && y <= mod); - if (sum >= mod) - sum -= mod; - if (sum < 0) - sum += mod; - return sum; + int sum = x + y; + ASSERT(0 <= x && x < mod && -mod <= y && y <= mod); + if (sum >= mod) + { + sum -= mod; + } + if (sum < 0) + { + sum += mod; + } + return sum; } static inline int -index_verify (int index, int size, const char *file, int line) +index_verify(int index, int size, const char *file, int line) { - if (index < 0 || index >= size) - msg (M_FATAL, "Assertion Failed: Array index=%d out of bounds for array size=%d in %s:%d", - index, - size, - file, - line); - return index; + if (index < 0 || index >= size) + { + msg(M_FATAL, "Assertion Failed: Array index=%d out of bounds for array size=%d in %s:%d", + index, + size, + file, + line); + } + return index; } -#endif +#endif /* ifndef INTEGER_H */ diff --git a/src/openvpn/interval.c b/src/openvpn/interval.c index 64494f1b4ce..108b778835c 100644 --- a/src/openvpn/interval.c +++ b/src/openvpn/interval.c @@ -35,49 +35,49 @@ #include "memdbg.h" void -interval_init (struct interval *top, int horizon, int refresh) +interval_init(struct interval *top, int horizon, int refresh) { - CLEAR (*top); - top->refresh = refresh; - top->horizon = horizon; + CLEAR(*top); + top->refresh = refresh; + top->horizon = horizon; } bool -event_timeout_trigger (struct event_timeout *et, - struct timeval *tv, - const int et_const_retry) +event_timeout_trigger(struct event_timeout *et, + struct timeval *tv, + const int et_const_retry) { - bool ret = false; - const time_t local_now = now; + bool ret = false; + const time_t local_now = now; - if (et->defined) + if (et->defined) { - int wakeup = (int) et->last + et->n - local_now; - if (wakeup <= 0) - { + int wakeup = (int) et->last + et->n - local_now; + if (wakeup <= 0) + { #if INTERVAL_DEBUG - dmsg (D_INTERVAL, "EVENT event_timeout_trigger (%d) etcr=%d", et->n, et_const_retry); + dmsg(D_INTERVAL, "EVENT event_timeout_trigger (%d) etcr=%d", et->n, et_const_retry); #endif - if (et_const_retry < 0) - { - et->last = local_now; - wakeup = et->n; - ret = true; - } - else - { - wakeup = et_const_retry; - } - } + if (et_const_retry < 0) + { + et->last = local_now; + wakeup = et->n; + ret = true; + } + else + { + wakeup = et_const_retry; + } + } - if (tv && wakeup < tv->tv_sec) - { + if (tv && wakeup < tv->tv_sec) + { #if INTERVAL_DEBUG - dmsg (D_INTERVAL, "EVENT event_timeout_wakeup (%d/%d) etcr=%d", wakeup, et->n, et_const_retry); + dmsg(D_INTERVAL, "EVENT event_timeout_wakeup (%d/%d) etcr=%d", wakeup, et->n, et_const_retry); #endif - tv->tv_sec = wakeup; - tv->tv_usec = 0; - } + tv->tv_sec = wakeup; + tv->tv_usec = 0; + } } - return ret; + return ret; } diff --git a/src/openvpn/interval.h b/src/openvpn/interval.h index 59eb1f64d57..0507ed2187e 100644 --- a/src/openvpn/interval.h +++ b/src/openvpn/interval.h @@ -42,14 +42,14 @@ struct interval { - interval_t refresh; - interval_t horizon; - time_t future_trigger; - time_t last_action; - time_t last_test_true; + interval_t refresh; + interval_t horizon; + time_t future_trigger; + time_t last_action; + time_t last_test_true; }; -void interval_init (struct interval *top, int horizon, int refresh); +void interval_init(struct interval *top, int horizon, int refresh); /* * IF @@ -64,41 +64,41 @@ void interval_init (struct interval *top, int horizon, int refresh); */ static inline bool -interval_test (struct interval* top) +interval_test(struct interval *top) { - bool trigger = false; - const time_t local_now = now; + bool trigger = false; + const time_t local_now = now; - if (top->future_trigger && local_now >= top->future_trigger) + if (top->future_trigger && local_now >= top->future_trigger) { - trigger = true; - top->future_trigger = 0; + trigger = true; + top->future_trigger = 0; } - if (top->last_action + top->horizon > local_now || - top->last_test_true + top->refresh <= local_now || - trigger) + if (top->last_action + top->horizon > local_now + || top->last_test_true + top->refresh <= local_now + || trigger) { - top->last_test_true = local_now; + top->last_test_true = local_now; #if INTERVAL_DEBUG - dmsg (D_INTERVAL, "INTERVAL interval_test true"); + dmsg(D_INTERVAL, "INTERVAL interval_test true"); #endif - return true; + return true; } - else + else { - return false; + return false; } } static inline void -interval_schedule_wakeup (struct interval* top, interval_t *wakeup) +interval_schedule_wakeup(struct interval *top, interval_t *wakeup) { - const time_t local_now = now; - interval_earliest_wakeup (wakeup, top->last_test_true + top->refresh, local_now); - interval_earliest_wakeup (wakeup, top->future_trigger, local_now); + const time_t local_now = now; + interval_earliest_wakeup(wakeup, top->last_test_true + top->refresh, local_now); + interval_earliest_wakeup(wakeup, top->future_trigger, local_now); #if INTERVAL_DEBUG - dmsg (D_INTERVAL, "INTERVAL interval_schedule wakeup=%d", (int)*wakeup); + dmsg(D_INTERVAL, "INTERVAL interval_schedule wakeup=%d", (int)*wakeup); #endif } @@ -106,13 +106,13 @@ interval_schedule_wakeup (struct interval* top, interval_t *wakeup) * In wakeup seconds, interval_test will return true once. */ static inline void -interval_future_trigger (struct interval* top, interval_t wakeup) { - if (wakeup) +interval_future_trigger(struct interval *top, interval_t wakeup) { + if (wakeup) { #if INTERVAL_DEBUG - dmsg (D_INTERVAL, "INTERVAL interval_future_trigger %d", (int)wakeup); + dmsg(D_INTERVAL, "INTERVAL interval_future_trigger %d", (int)wakeup); #endif - top->future_trigger = now + wakeup; + top->future_trigger = now + wakeup; } } @@ -121,12 +121,12 @@ interval_future_trigger (struct interval* top, interval_t wakeup) { * horizon seconds. */ static inline void -interval_action (struct interval* top) +interval_action(struct interval *top) { #if INTERVAL_DEBUG - dmsg (D_INTERVAL, "INTERVAL action"); + dmsg(D_INTERVAL, "INTERVAL action"); #endif - top->last_action = now; + top->last_action = now; } /* @@ -135,63 +135,68 @@ interval_action (struct interval* top) struct event_timeout { - bool defined; - interval_t n; - time_t last; /* time of last event */ + bool defined; + interval_t n; + time_t last; /* time of last event */ }; static inline bool -event_timeout_defined (const struct event_timeout* et) +event_timeout_defined(const struct event_timeout *et) { - return et->defined; + return et->defined; } static inline void -event_timeout_clear (struct event_timeout* et) +event_timeout_clear(struct event_timeout *et) { - et->defined = false; - et->n = 0; - et->last = 0; + et->defined = false; + et->n = 0; + et->last = 0; } static inline struct event_timeout -event_timeout_clear_ret () +event_timeout_clear_ret() { - struct event_timeout ret; - event_timeout_clear (&ret); - return ret; + struct event_timeout ret; + event_timeout_clear(&ret); + return ret; } static inline void -event_timeout_init (struct event_timeout* et, interval_t n, const time_t local_now) +event_timeout_init(struct event_timeout *et, interval_t n, const time_t local_now) { - et->defined = true; - et->n = (n >= 0) ? n : 0; - et->last = local_now; + et->defined = true; + et->n = (n >= 0) ? n : 0; + et->last = local_now; } static inline void -event_timeout_reset (struct event_timeout* et) +event_timeout_reset(struct event_timeout *et) { - if (et->defined) - et->last = now; + if (et->defined) + { + et->last = now; + } } static inline void -event_timeout_modify_wakeup (struct event_timeout* et, interval_t n) +event_timeout_modify_wakeup(struct event_timeout *et, interval_t n) { - /* note that you might need to call reset_coarse_timers after this */ - if (et->defined) - et->n = (n >= 0) ? n : 0; + /* note that you might need to call reset_coarse_timers after this */ + if (et->defined) + { + et->n = (n >= 0) ? n : 0; + } } /* * Will return the time left for a timeout, this function does not check * if the timeout is actually valid */ -static inline interval_t event_timeout_remaining (struct event_timeout* et) +static inline interval_t +event_timeout_remaining(struct event_timeout *et) { - return (int) et->last + et->n - now; + return (int) et->last + et->n - now; } /* @@ -207,9 +212,9 @@ static inline interval_t event_timeout_remaining (struct event_timeout* et) #define ETT_DEFAULT (-1) -bool event_timeout_trigger (struct event_timeout *et, - struct timeval *tv, - const int et_const_retry); +bool event_timeout_trigger(struct event_timeout *et, + struct timeval *tv, + const int et_const_retry); /* * Measure time intervals in microseconds @@ -220,37 +225,37 @@ bool event_timeout_trigger (struct event_timeout *et, #define USEC_TIMER_MAX_USEC (USEC_TIMER_MAX * 1000000) struct usec_timer { - struct timeval start; - struct timeval end; + struct timeval start; + struct timeval end; }; #ifdef HAVE_GETTIMEOFDAY static inline void -usec_timer_start (struct usec_timer *obj) +usec_timer_start(struct usec_timer *obj) { - CLEAR (*obj); - openvpn_gettimeofday (&obj->start, NULL); + CLEAR(*obj); + openvpn_gettimeofday(&obj->start, NULL); } static inline void -usec_timer_end (struct usec_timer *obj) +usec_timer_end(struct usec_timer *obj) { - openvpn_gettimeofday (&obj->end, NULL); + openvpn_gettimeofday(&obj->end, NULL); } #endif /* HAVE_GETTIMEOFDAY */ static inline bool -usec_timer_interval_defined (struct usec_timer *obj) +usec_timer_interval_defined(struct usec_timer *obj) { - return obj->start.tv_sec && obj->end.tv_sec; + return obj->start.tv_sec && obj->end.tv_sec; } static inline int -usec_timer_interval (struct usec_timer *obj) +usec_timer_interval(struct usec_timer *obj) { - return tv_subtract (&obj->end, &obj->start, USEC_TIMER_MAX); + return tv_subtract(&obj->end, &obj->start, USEC_TIMER_MAX); } #endif /* INTERVAL_H */ diff --git a/src/openvpn/list.c b/src/openvpn/list.c index ea6bd74bd86..4d64b4cdfa7 100644 --- a/src/openvpn/list.c +++ b/src/openvpn/list.c @@ -38,294 +38,306 @@ #include "memdbg.h" struct hash * -hash_init (const int n_buckets, - const uint32_t iv, - uint32_t (*hash_function)(const void *key, uint32_t iv), - bool (*compare_function)(const void *key1, const void *key2)) +hash_init(const int n_buckets, + const uint32_t iv, + uint32_t (*hash_function)(const void *key, uint32_t iv), + bool (*compare_function)(const void *key1, const void *key2)) { - struct hash *h; - int i; - - ASSERT (n_buckets > 0); - ALLOC_OBJ_CLEAR (h, struct hash); - h->n_buckets = (int) adjust_power_of_2 (n_buckets); - h->mask = h->n_buckets - 1; - h->hash_function = hash_function; - h->compare_function = compare_function; - h->iv = iv; - ALLOC_ARRAY (h->buckets, struct hash_bucket, h->n_buckets); - for (i = 0; i < h->n_buckets; ++i) + struct hash *h; + int i; + + ASSERT(n_buckets > 0); + ALLOC_OBJ_CLEAR(h, struct hash); + h->n_buckets = (int) adjust_power_of_2(n_buckets); + h->mask = h->n_buckets - 1; + h->hash_function = hash_function; + h->compare_function = compare_function; + h->iv = iv; + ALLOC_ARRAY(h->buckets, struct hash_bucket, h->n_buckets); + for (i = 0; i < h->n_buckets; ++i) { - struct hash_bucket *b = &h->buckets[i]; - b->list = NULL; + struct hash_bucket *b = &h->buckets[i]; + b->list = NULL; } - return h; + return h; } void -hash_free (struct hash *hash) +hash_free(struct hash *hash) { - int i; - for (i = 0; i < hash->n_buckets; ++i) + int i; + for (i = 0; i < hash->n_buckets; ++i) { - struct hash_bucket *b = &hash->buckets[i]; - struct hash_element *he = b->list; - - while (he) - { - struct hash_element *next = he->next; - free (he); - he = next; - } + struct hash_bucket *b = &hash->buckets[i]; + struct hash_element *he = b->list; + + while (he) + { + struct hash_element *next = he->next; + free(he); + he = next; + } } - free (hash->buckets); - free (hash); + free(hash->buckets); + free(hash); } struct hash_element * -hash_lookup_fast (struct hash *hash, - struct hash_bucket *bucket, - const void *key, - uint32_t hv) +hash_lookup_fast(struct hash *hash, + struct hash_bucket *bucket, + const void *key, + uint32_t hv) { - struct hash_element *he; - struct hash_element *prev = NULL; + struct hash_element *he; + struct hash_element *prev = NULL; - he = bucket->list; + he = bucket->list; - while (he) + while (he) { - if (hv == he->hash_value && (*hash->compare_function)(key, he->key)) - { - /* move to head of list */ - if (prev) - { - prev->next = he->next; - he->next = bucket->list; - bucket->list = he; - } - return he; - } - prev = he; - he = he->next; + if (hv == he->hash_value && (*hash->compare_function)(key, he->key)) + { + /* move to head of list */ + if (prev) + { + prev->next = he->next; + he->next = bucket->list; + bucket->list = he; + } + return he; + } + prev = he; + he = he->next; } - return NULL; + return NULL; } bool -hash_remove_fast (struct hash *hash, - struct hash_bucket *bucket, - const void *key, - uint32_t hv) +hash_remove_fast(struct hash *hash, + struct hash_bucket *bucket, + const void *key, + uint32_t hv) { - struct hash_element *he; - struct hash_element *prev = NULL; + struct hash_element *he; + struct hash_element *prev = NULL; - he = bucket->list; + he = bucket->list; - while (he) + while (he) { - if (hv == he->hash_value && (*hash->compare_function)(key, he->key)) - { - if (prev) - prev->next = he->next; - else - bucket->list = he->next; - free (he); - --hash->n_elements; - return true; - } - prev = he; - he = he->next; + if (hv == he->hash_value && (*hash->compare_function)(key, he->key)) + { + if (prev) + { + prev->next = he->next; + } + else + { + bucket->list = he->next; + } + free(he); + --hash->n_elements; + return true; + } + prev = he; + he = he->next; } - return false; + return false; } bool -hash_add (struct hash *hash, const void *key, void *value, bool replace) +hash_add(struct hash *hash, const void *key, void *value, bool replace) { - uint32_t hv; - struct hash_bucket *bucket; - struct hash_element *he; - bool ret = false; + uint32_t hv; + struct hash_bucket *bucket; + struct hash_element *he; + bool ret = false; - hv = hash_value (hash, key); - bucket = &hash->buckets[hv & hash->mask]; + hv = hash_value(hash, key); + bucket = &hash->buckets[hv & hash->mask]; - if ((he = hash_lookup_fast (hash, bucket, key, hv))) /* already exists? */ + if ((he = hash_lookup_fast(hash, bucket, key, hv))) /* already exists? */ { - if (replace) - { - he->value = value; - ret = true; - } + if (replace) + { + he->value = value; + ret = true; + } } - else + else { - hash_add_fast (hash, bucket, key, hv, value); - ret = true; + hash_add_fast(hash, bucket, key, hv, value); + ret = true; } - return ret; + return ret; } void -hash_remove_by_value (struct hash *hash, void *value) +hash_remove_by_value(struct hash *hash, void *value) { - struct hash_iterator hi; - struct hash_element *he; + struct hash_iterator hi; + struct hash_element *he; - hash_iterator_init (hash, &hi); - while ((he = hash_iterator_next (&hi))) + hash_iterator_init(hash, &hi); + while ((he = hash_iterator_next(&hi))) { - if (he->value == value) - hash_iterator_delete_element (&hi); + if (he->value == value) + { + hash_iterator_delete_element(&hi); + } } - hash_iterator_free (&hi); + hash_iterator_free(&hi); } static void -hash_remove_marked (struct hash *hash, struct hash_bucket *bucket) +hash_remove_marked(struct hash *hash, struct hash_bucket *bucket) { - struct hash_element *prev = NULL; - struct hash_element *he = bucket->list; + struct hash_element *prev = NULL; + struct hash_element *he = bucket->list; - while (he) + while (he) { - if (!he->key) /* marked? */ - { - struct hash_element *newhe; - if (prev) - newhe = prev->next = he->next; - else - newhe = bucket->list = he->next; - free (he); - --hash->n_elements; - he = newhe; - } - else - { - prev = he; - he = he->next; - } + if (!he->key) /* marked? */ + { + struct hash_element *newhe; + if (prev) + { + newhe = prev->next = he->next; + } + else + { + newhe = bucket->list = he->next; + } + free(he); + --hash->n_elements; + he = newhe; + } + else + { + prev = he; + he = he->next; + } } } uint32_t -void_ptr_hash_function (const void *key, uint32_t iv) +void_ptr_hash_function(const void *key, uint32_t iv) { - return hash_func ((const void *)&key, sizeof (key), iv); + return hash_func((const void *)&key, sizeof(key), iv); } bool -void_ptr_compare_function (const void *key1, const void *key2) +void_ptr_compare_function(const void *key1, const void *key2) { - return key1 == key2; + return key1 == key2; } void -hash_iterator_init_range (struct hash *hash, - struct hash_iterator *hi, - int start_bucket, - int end_bucket) +hash_iterator_init_range(struct hash *hash, + struct hash_iterator *hi, + int start_bucket, + int end_bucket) { - if (end_bucket > hash->n_buckets) - end_bucket = hash->n_buckets; - - ASSERT (start_bucket >= 0 && start_bucket <= end_bucket); - - hi->hash = hash; - hi->elem = NULL; - hi->bucket = NULL; - hi->last = NULL; - hi->bucket_marked = false; - hi->bucket_index_start = start_bucket; - hi->bucket_index_end = end_bucket; - hi->bucket_index = hi->bucket_index_start - 1; + if (end_bucket > hash->n_buckets) + { + end_bucket = hash->n_buckets; + } + + ASSERT(start_bucket >= 0 && start_bucket <= end_bucket); + + hi->hash = hash; + hi->elem = NULL; + hi->bucket = NULL; + hi->last = NULL; + hi->bucket_marked = false; + hi->bucket_index_start = start_bucket; + hi->bucket_index_end = end_bucket; + hi->bucket_index = hi->bucket_index_start - 1; } void -hash_iterator_init (struct hash *hash, - struct hash_iterator *hi) +hash_iterator_init(struct hash *hash, + struct hash_iterator *hi) { - hash_iterator_init_range (hash, hi, 0, hash->n_buckets); + hash_iterator_init_range(hash, hi, 0, hash->n_buckets); } static inline void -hash_iterator_lock (struct hash_iterator *hi, struct hash_bucket *b) +hash_iterator_lock(struct hash_iterator *hi, struct hash_bucket *b) { - hi->bucket = b; - hi->last = NULL; - hi->bucket_marked = false; + hi->bucket = b; + hi->last = NULL; + hi->bucket_marked = false; } static inline void -hash_iterator_unlock (struct hash_iterator *hi) +hash_iterator_unlock(struct hash_iterator *hi) { - if (hi->bucket) + if (hi->bucket) { - if (hi->bucket_marked) - { - hash_remove_marked (hi->hash, hi->bucket); - hi->bucket_marked = false; - } - hi->bucket = NULL; - hi->last = NULL; + if (hi->bucket_marked) + { + hash_remove_marked(hi->hash, hi->bucket); + hi->bucket_marked = false; + } + hi->bucket = NULL; + hi->last = NULL; } } static inline void -hash_iterator_advance (struct hash_iterator *hi) +hash_iterator_advance(struct hash_iterator *hi) { - hi->last = hi->elem; - hi->elem = hi->elem->next; + hi->last = hi->elem; + hi->elem = hi->elem->next; } void -hash_iterator_free (struct hash_iterator *hi) +hash_iterator_free(struct hash_iterator *hi) { - hash_iterator_unlock (hi); + hash_iterator_unlock(hi); } struct hash_element * -hash_iterator_next (struct hash_iterator *hi) +hash_iterator_next(struct hash_iterator *hi) { - struct hash_element *ret = NULL; - if (hi->elem) + struct hash_element *ret = NULL; + if (hi->elem) { - ret = hi->elem; - hash_iterator_advance (hi); + ret = hi->elem; + hash_iterator_advance(hi); } - else + else { - while (++hi->bucket_index < hi->bucket_index_end) - { - struct hash_bucket *b; - hash_iterator_unlock (hi); - b = &hi->hash->buckets[hi->bucket_index]; - if (b->list) - { - hash_iterator_lock (hi, b); - hi->elem = b->list; - if (hi->elem) - { - ret = hi->elem; - hash_iterator_advance (hi); - break; - } - } - } + while (++hi->bucket_index < hi->bucket_index_end) + { + struct hash_bucket *b; + hash_iterator_unlock(hi); + b = &hi->hash->buckets[hi->bucket_index]; + if (b->list) + { + hash_iterator_lock(hi, b); + hi->elem = b->list; + if (hi->elem) + { + ret = hi->elem; + hash_iterator_advance(hi); + break; + } + } + } } - return ret; + return ret; } void -hash_iterator_delete_element (struct hash_iterator *hi) +hash_iterator_delete_element(struct hash_iterator *hi) { - ASSERT (hi->last); - hi->last->key = NULL; - hi->bucket_marked = true; + ASSERT(hi->last); + hi->last->key = NULL; + hi->bucket_marked = true; } @@ -338,312 +350,326 @@ hash_iterator_delete_element (struct hash_iterator *hi) struct word { - const char *word; - int n; + const char *word; + int n; }; static uint32_t -word_hash_function (const void *key, uint32_t iv) +word_hash_function(const void *key, uint32_t iv) { - const char *str = (const char *) key; - const int len = strlen (str); - return hash_func ((const uint8_t *)str, len, iv); + const char *str = (const char *) key; + const int len = strlen(str); + return hash_func((const uint8_t *)str, len, iv); } static bool -word_compare_function (const void *key1, const void *key2) +word_compare_function(const void *key1, const void *key2) { - return strcmp ((const char *)key1, (const char *)key2) == 0; + return strcmp((const char *)key1, (const char *)key2) == 0; } static void -print_nhash (struct hash *hash) +print_nhash(struct hash *hash) { - struct hash_iterator hi; - struct hash_element *he; - int count = 0; + struct hash_iterator hi; + struct hash_element *he; + int count = 0; - hash_iterator_init (hash, &hi, true); + hash_iterator_init(hash, &hi, true); - while ((he = hash_iterator_next (&hi))) + while ((he = hash_iterator_next(&hi))) { - printf ("%d ", (int) he->value); - ++count; + printf("%d ", (int) he->value); + ++count; } - printf ("\n"); + printf("\n"); - hash_iterator_free (&hi); - ASSERT (count == hash_n_elements (hash)); + hash_iterator_free(&hi); + ASSERT(count == hash_n_elements(hash)); } static void -rmhash (struct hash *hash, const char *word) +rmhash(struct hash *hash, const char *word) { - hash_remove (hash, word); + hash_remove(hash, word); } void -list_test (void) +list_test(void) { - openvpn_thread_init (); - - { - struct gc_arena gc = gc_new (); - struct hash *hash = hash_init (10000, get_random (), word_hash_function, word_compare_function); - struct hash *nhash = hash_init (256, get_random (), word_hash_function, word_compare_function); - - printf ("hash_init n_buckets=%d mask=0x%08x\n", hash->n_buckets, hash->mask); - - /* parse words from stdin */ - while (true) - { - char buf[256]; - char wordbuf[256]; - int wbi; - int bi; - char c; - - if (!fgets(buf, sizeof(buf), stdin)) - break; - - bi = wbi = 0; - do - { - c = buf[bi++]; - if (isalnum (c) || c == '_') - { - ASSERT (wbi < (int) sizeof (wordbuf)); - wordbuf[wbi++] = c; - } - else - { - if (wbi) - { - struct word *w; - ASSERT (wbi < (int) sizeof (wordbuf)); - wordbuf[wbi++] = '\0'; - - /* word is parsed from stdin */ - - /* does it already exist in table? */ - w = (struct word *) hash_lookup (hash, wordbuf); - - if (w) - { - /* yes, increment count */ - ++w->n; - } - else - { - /* no, make a new object */ - ALLOC_OBJ_GC (w, struct word, &gc); - w->word = string_alloc (wordbuf, &gc); - w->n = 1; - ASSERT (hash_add (hash, w->word, w, false)); - ASSERT (hash_add (nhash, w->word, (void*) ((random() & 0x0F) + 1), false)); - } - } - wbi = 0; - } - } while (c); - } + openvpn_thread_init(); -#if 1 - /* remove some words from the table */ { - rmhash (hash, "true"); - rmhash (hash, "false"); - } + struct gc_arena gc = gc_new(); + struct hash *hash = hash_init(10000, get_random(), word_hash_function, word_compare_function); + struct hash *nhash = hash_init(256, get_random(), word_hash_function, word_compare_function); + + printf("hash_init n_buckets=%d mask=0x%08x\n", hash->n_buckets, hash->mask); + + /* parse words from stdin */ + while (true) + { + char buf[256]; + char wordbuf[256]; + int wbi; + int bi; + char c; + + if (!fgets(buf, sizeof(buf), stdin)) + { + break; + } + + bi = wbi = 0; + do + { + c = buf[bi++]; + if (isalnum(c) || c == '_') + { + ASSERT(wbi < (int) sizeof(wordbuf)); + wordbuf[wbi++] = c; + } + else + { + if (wbi) + { + struct word *w; + ASSERT(wbi < (int) sizeof(wordbuf)); + wordbuf[wbi++] = '\0'; + + /* word is parsed from stdin */ + + /* does it already exist in table? */ + w = (struct word *) hash_lookup(hash, wordbuf); + + if (w) + { + /* yes, increment count */ + ++w->n; + } + else + { + /* no, make a new object */ + ALLOC_OBJ_GC(w, struct word, &gc); + w->word = string_alloc(wordbuf, &gc); + w->n = 1; + ASSERT(hash_add(hash, w->word, w, false)); + ASSERT(hash_add(nhash, w->word, (void *) ((random() & 0x0F) + 1), false)); + } + } + wbi = 0; + } + } while (c); + } + +#if 1 + /* remove some words from the table */ + { + rmhash(hash, "true"); + rmhash(hash, "false"); + } #endif - /* output contents of hash table */ - { - int base; - int inc = 0; - int count = 0; - - for (base = 0; base < hash_n_buckets (hash); base += inc) { - struct hash_iterator hi; - struct hash_element *he; - inc = (get_random () % 3) + 1; - hash_iterator_init_range (hash, &hi, true, base, base + inc); - - while ((he = hash_iterator_next (&hi))) - { - struct word *w = (struct word *) he->value; - printf ("%6d '%s'\n", w->n, w->word); - ++count; - } - - hash_iterator_free (&hi); - } - ASSERT (count == hash_n_elements (hash)); - } - + /* output contents of hash table */ + { + int base; + int inc = 0; + int count = 0; + + for (base = 0; base < hash_n_buckets(hash); base += inc) { + struct hash_iterator hi; + struct hash_element *he; + inc = (get_random() % 3) + 1; + hash_iterator_init_range(hash, &hi, true, base, base + inc); + + while ((he = hash_iterator_next(&hi))) + { + struct word *w = (struct word *) he->value; + printf("%6d '%s'\n", w->n, w->word); + ++count; + } + + hash_iterator_free(&hi); + } + ASSERT(count == hash_n_elements(hash)); + } + #if 1 - /* test hash_remove_by_value function */ - { - int i; - for (i = 1; i <= 16; ++i) - { - printf ("[%d] ***********************************\n", i); - print_nhash (nhash); - hash_remove_by_value (nhash, (void *) i, true); - } - printf ("FINAL **************************\n"); - print_nhash (nhash); - } + /* test hash_remove_by_value function */ + { + int i; + for (i = 1; i <= 16; ++i) + { + printf("[%d] ***********************************\n", i); + print_nhash(nhash); + hash_remove_by_value(nhash, (void *) i, true); + } + printf("FINAL **************************\n"); + print_nhash(nhash); + } #endif - hash_free (hash); - hash_free (nhash); - gc_free (&gc); - } + hash_free(hash); + hash_free(nhash); + gc_free(&gc); + } - openvpn_thread_cleanup (); + openvpn_thread_cleanup(); } -#endif +#endif /* ifdef LIST_TEST */ /* --------------------------------------------------------------------- -hash() -- hash a variable-length key into a 32-bit value - k : the key (the unaligned variable-length array of bytes) - len : the length of the key, counting by bytes - level : can be any 4-byte value -Returns a 32-bit value. Every bit of the key affects every bit of -the return value. Every 1-bit and 2-bit delta achieves avalanche. -About 36+6len instructions. - -The best hash table sizes are powers of 2. There is no need to do -mod a prime (mod is sooo slow!). If you need less than 32 bits, -use a bitmask. For example, if you need only 10 bits, do - h = (h & hashmask(10)); -In which case, the hash table should have hashsize(10) elements. - -If you are hashing n strings (uint8_t **)k, do it like this: - for (i=0, h=0; i>13); - b -= c; a ^= x; - b -= a; x = (a<<8); - c -= a; b ^= x; - c -= b; x = (b>>13); - ... - Unfortunately, superscalar Pentiums and Sparcs can't take advantage - of that parallelism. They've also turned some of those single-cycle - latency instructions into multi-cycle latency instructions. Still, - this is the fastest good hash I could find. There were about 2^^68 - to choose from. I only looked at a billion or so. - -James Yonan Notes: - -* This function is faster than it looks, and appears to be - appropriate for our usage in OpenVPN which is primarily - for hash-table based address lookup (IPv4, IPv6, and Ethernet MAC). - NOTE: This function is never used for cryptographic purposes, only - to produce evenly-distributed indexes into hash tables. - -* Benchmark results: 11.39 machine cycles per byte on a P2 266Mhz, - and 12.1 machine cycles per byte on a - 2.2 Ghz P4 when hashing a 6 byte string. --------------------------------------------------------------------- -*/ + * -------------------------------------------------------------------- + * hash() -- hash a variable-length key into a 32-bit value + * k : the key (the unaligned variable-length array of bytes) + * len : the length of the key, counting by bytes + * level : can be any 4-byte value + * Returns a 32-bit value. Every bit of the key affects every bit of + * the return value. Every 1-bit and 2-bit delta achieves avalanche. + * About 36+6len instructions. + * + * The best hash table sizes are powers of 2. There is no need to do + * mod a prime (mod is sooo slow!). If you need less than 32 bits, + * use a bitmask. For example, if you need only 10 bits, do + * h = (h & hashmask(10)); + * In which case, the hash table should have hashsize(10) elements. + * + * If you are hashing n strings (uint8_t **)k, do it like this: + * for (i=0, h=0; i>13); + * b -= c; a ^= x; + * b -= a; x = (a<<8); + * c -= a; b ^= x; + * c -= b; x = (b>>13); + * ... + * Unfortunately, superscalar Pentiums and Sparcs can't take advantage + * of that parallelism. They've also turned some of those single-cycle + * latency instructions into multi-cycle latency instructions. Still, + * this is the fastest good hash I could find. There were about 2^^68 + * to choose from. I only looked at a billion or so. + * + * James Yonan Notes: + * + * This function is faster than it looks, and appears to be + * appropriate for our usage in OpenVPN which is primarily + * for hash-table based address lookup (IPv4, IPv6, and Ethernet MAC). + * NOTE: This function is never used for cryptographic purposes, only + * to produce evenly-distributed indexes into hash tables. + * + * Benchmark results: 11.39 machine cycles per byte on a P2 266Mhz, + * and 12.1 machine cycles per byte on a + * 2.2 Ghz P4 when hashing a 6 byte string. + * -------------------------------------------------------------------- + */ #define mix(a,b,c) \ -{ \ - a -= b; a -= c; a ^= (c>>13); \ - b -= c; b -= a; b ^= (a<<8); \ - c -= a; c -= b; c ^= (b>>13); \ - a -= b; a -= c; a ^= (c>>12); \ - b -= c; b -= a; b ^= (a<<16); \ - c -= a; c -= b; c ^= (b>>5); \ - a -= b; a -= c; a ^= (c>>3); \ - b -= c; b -= a; b ^= (a<<10); \ - c -= a; c -= b; c ^= (b>>15); \ -} + { \ + a -= b; a -= c; a ^= (c>>13); \ + b -= c; b -= a; b ^= (a<<8); \ + c -= a; c -= b; c ^= (b>>13); \ + a -= b; a -= c; a ^= (c>>12); \ + b -= c; b -= a; b ^= (a<<16); \ + c -= a; c -= b; c ^= (b>>5); \ + a -= b; a -= c; a ^= (c>>3); \ + b -= c; b -= a; b ^= (a<<10); \ + c -= a; c -= b; c ^= (b>>15); \ + } uint32_t -hash_func (const uint8_t *k, uint32_t length, uint32_t initval) +hash_func(const uint8_t *k, uint32_t length, uint32_t initval) { - uint32_t a, b, c, len; + uint32_t a, b, c, len; - /* Set up the internal state */ - len = length; - a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */ - c = initval; /* the previous hash value */ + /* Set up the internal state */ + len = length; + a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */ + c = initval; /* the previous hash value */ - /*---------------------------------------- handle most of the key */ - while (len >= 12) + /*---------------------------------------- handle most of the key */ + while (len >= 12) { - a += (k[0] + ((uint32_t) k[1] << 8) - + ((uint32_t) k[2] << 16) - + ((uint32_t) k[3] << 24)); - b += (k[4] + ((uint32_t) k[5] << 8) - + ((uint32_t) k[6] << 16) - + ((uint32_t) k[7] << 24)); - c += (k[8] + ((uint32_t) k[9] << 8) - + ((uint32_t) k[10] << 16) - + ((uint32_t) k[11] << 24)); - mix (a, b, c); - k += 12; - len -= 12; + a += (k[0] + ((uint32_t) k[1] << 8) + + ((uint32_t) k[2] << 16) + + ((uint32_t) k[3] << 24)); + b += (k[4] + ((uint32_t) k[5] << 8) + + ((uint32_t) k[6] << 16) + + ((uint32_t) k[7] << 24)); + c += (k[8] + ((uint32_t) k[9] << 8) + + ((uint32_t) k[10] << 16) + + ((uint32_t) k[11] << 24)); + mix(a, b, c); + k += 12; + len -= 12; } - /*------------------------------------- handle the last 11 bytes */ - c += length; - switch (len) /* all the case statements fall through */ + /*------------------------------------- handle the last 11 bytes */ + c += length; + switch (len) /* all the case statements fall through */ { - case 11: - c += ((uint32_t) k[10] << 24); - case 10: - c += ((uint32_t) k[9] << 16); - case 9: - c += ((uint32_t) k[8] << 8); - /* the first byte of c is reserved for the length */ - case 8: - b += ((uint32_t) k[7] << 24); - case 7: - b += ((uint32_t) k[6] << 16); - case 6: - b += ((uint32_t) k[5] << 8); - case 5: - b += k[4]; - case 4: - a += ((uint32_t) k[3] << 24); - case 3: - a += ((uint32_t) k[2] << 16); - case 2: - a += ((uint32_t) k[1] << 8); - case 1: - a += k[0]; - /* case 0: nothing left to add */ + case 11: + c += ((uint32_t) k[10] << 24); + + case 10: + c += ((uint32_t) k[9] << 16); + + case 9: + c += ((uint32_t) k[8] << 8); + + /* the first byte of c is reserved for the length */ + case 8: + b += ((uint32_t) k[7] << 24); + + case 7: + b += ((uint32_t) k[6] << 16); + + case 6: + b += ((uint32_t) k[5] << 8); + + case 5: + b += k[4]; + + case 4: + a += ((uint32_t) k[3] << 24); + + case 3: + a += ((uint32_t) k[2] << 16); + + case 2: + a += ((uint32_t) k[1] << 8); + + case 1: + a += k[0]; + /* case 0: nothing left to add */ } - mix (a, b, c); - /*-------------------------------------- report the result */ - return c; + mix(a, b, c); + /*-------------------------------------- report the result */ + return c; } -#else -static void dummy(void) {} +#else /* if P2MP_SERVER */ +static void +dummy(void) { +} #endif /* P2MP_SERVER */ diff --git a/src/openvpn/list.h b/src/openvpn/list.h index adde36b3e93..72fb2c9e0a8 100644 --- a/src/openvpn/list.h +++ b/src/openvpn/list.h @@ -47,149 +47,156 @@ struct hash_element { - void *value; - const void *key; - unsigned int hash_value; - struct hash_element *next; + void *value; + const void *key; + unsigned int hash_value; + struct hash_element *next; }; struct hash_bucket { - struct hash_element *list; + struct hash_element *list; }; struct hash { - int n_buckets; - int n_elements; - int mask; - uint32_t iv; - uint32_t (*hash_function)(const void *key, uint32_t iv); - bool (*compare_function)(const void *key1, const void *key2); /* return true if equal */ - struct hash_bucket *buckets; + int n_buckets; + int n_elements; + int mask; + uint32_t iv; + uint32_t (*hash_function)(const void *key, uint32_t iv); + bool (*compare_function)(const void *key1, const void *key2); /* return true if equal */ + struct hash_bucket *buckets; }; -struct hash *hash_init (const int n_buckets, - const uint32_t iv, - uint32_t (*hash_function)(const void *key, uint32_t iv), - bool (*compare_function)(const void *key1, const void *key2)); +struct hash *hash_init(const int n_buckets, + const uint32_t iv, + uint32_t (*hash_function)(const void *key, uint32_t iv), + bool (*compare_function)(const void *key1, const void *key2)); -void hash_free (struct hash *hash); +void hash_free(struct hash *hash); -bool hash_add (struct hash *hash, const void *key, void *value, bool replace); +bool hash_add(struct hash *hash, const void *key, void *value, bool replace); -struct hash_element *hash_lookup_fast (struct hash *hash, - struct hash_bucket *bucket, - const void *key, - uint32_t hv); +struct hash_element *hash_lookup_fast(struct hash *hash, + struct hash_bucket *bucket, + const void *key, + uint32_t hv); -bool hash_remove_fast (struct hash *hash, - struct hash_bucket *bucket, - const void *key, - uint32_t hv); +bool hash_remove_fast(struct hash *hash, + struct hash_bucket *bucket, + const void *key, + uint32_t hv); -void hash_remove_by_value (struct hash *hash, void *value); +void hash_remove_by_value(struct hash *hash, void *value); struct hash_iterator { - struct hash *hash; - int bucket_index; - struct hash_bucket *bucket; - struct hash_element *elem; - struct hash_element *last; - bool bucket_marked; - int bucket_index_start; - int bucket_index_end; + struct hash *hash; + int bucket_index; + struct hash_bucket *bucket; + struct hash_element *elem; + struct hash_element *last; + bool bucket_marked; + int bucket_index_start; + int bucket_index_end; }; -void hash_iterator_init_range (struct hash *hash, - struct hash_iterator *hi, - int start_bucket, - int end_bucket); +void hash_iterator_init_range(struct hash *hash, + struct hash_iterator *hi, + int start_bucket, + int end_bucket); -void hash_iterator_init (struct hash *hash, struct hash_iterator *iter); -struct hash_element *hash_iterator_next (struct hash_iterator *hi); -void hash_iterator_delete_element (struct hash_iterator *hi); -void hash_iterator_free (struct hash_iterator *hi); +void hash_iterator_init(struct hash *hash, struct hash_iterator *iter); -uint32_t hash_func (const uint8_t *k, uint32_t length, uint32_t initval); +struct hash_element *hash_iterator_next(struct hash_iterator *hi); -uint32_t void_ptr_hash_function (const void *key, uint32_t iv); -bool void_ptr_compare_function (const void *key1, const void *key2); +void hash_iterator_delete_element(struct hash_iterator *hi); + +void hash_iterator_free(struct hash_iterator *hi); + +uint32_t hash_func(const uint8_t *k, uint32_t length, uint32_t initval); + +uint32_t void_ptr_hash_function(const void *key, uint32_t iv); + +bool void_ptr_compare_function(const void *key1, const void *key2); #ifdef LIST_TEST -void list_test (void); +void list_test(void); + #endif static inline uint32_t -hash_value (const struct hash *hash, const void *key) +hash_value(const struct hash *hash, const void *key) { - return (*hash->hash_function)(key, hash->iv); + return (*hash->hash_function)(key, hash->iv); } static inline int -hash_n_elements (const struct hash *hash) +hash_n_elements(const struct hash *hash) { - return hash->n_elements; + return hash->n_elements; } static inline int -hash_n_buckets (const struct hash *hash) +hash_n_buckets(const struct hash *hash) { - return hash->n_buckets; + return hash->n_buckets; } static inline struct hash_bucket * -hash_bucket (struct hash *hash, uint32_t hv) +hash_bucket(struct hash *hash, uint32_t hv) { - return &hash->buckets[hv & hash->mask]; + return &hash->buckets[hv & hash->mask]; } static inline void * -hash_lookup (struct hash *hash, const void *key) +hash_lookup(struct hash *hash, const void *key) { - void *ret = NULL; - struct hash_element *he; - uint32_t hv = hash_value (hash, key); - struct hash_bucket *bucket = &hash->buckets[hv & hash->mask]; - - he = hash_lookup_fast (hash, bucket, key, hv); - if (he) - ret = he->value; - - return ret; + void *ret = NULL; + struct hash_element *he; + uint32_t hv = hash_value(hash, key); + struct hash_bucket *bucket = &hash->buckets[hv & hash->mask]; + + he = hash_lookup_fast(hash, bucket, key, hv); + if (he) + { + ret = he->value; + } + + return ret; } /* NOTE: assumes that key is not a duplicate */ static inline void -hash_add_fast (struct hash *hash, - struct hash_bucket *bucket, - const void *key, - uint32_t hv, - void *value) +hash_add_fast(struct hash *hash, + struct hash_bucket *bucket, + const void *key, + uint32_t hv, + void *value) { - struct hash_element *he; - - ALLOC_OBJ (he, struct hash_element); - he->value = value; - he->key = key; - he->hash_value = hv; - he->next = bucket->list; - bucket->list = he; - ++hash->n_elements; + struct hash_element *he; + + ALLOC_OBJ(he, struct hash_element); + he->value = value; + he->key = key; + he->hash_value = hv; + he->next = bucket->list; + bucket->list = he; + ++hash->n_elements; } static inline bool -hash_remove (struct hash *hash, const void *key) +hash_remove(struct hash *hash, const void *key) { - uint32_t hv; - struct hash_bucket *bucket; - bool ret; - - hv = hash_value (hash, key); - bucket = &hash->buckets[hv & hash->mask]; - ret = hash_remove_fast (hash, bucket, key, hv); - return ret; + uint32_t hv; + struct hash_bucket *bucket; + bool ret; + + hv = hash_value(hash, key); + bucket = &hash->buckets[hv & hash->mask]; + ret = hash_remove_fast(hash, bucket, key, hv); + return ret; } #endif /* P2MP_SERVER */ diff --git a/src/openvpn/lladdr.c b/src/openvpn/lladdr.c index 57f447b32e7..ff71e48c6f5 100644 --- a/src/openvpn/lladdr.c +++ b/src/openvpn/lladdr.c @@ -1,5 +1,5 @@ /* - * Support routine for configuring link layer address + * Support routine for configuring link layer address */ #ifdef HAVE_CONFIG_H @@ -12,56 +12,61 @@ #include "error.h" #include "misc.h" -int set_lladdr(const char *ifname, const char *lladdr, - const struct env_set *es) +int +set_lladdr(const char *ifname, const char *lladdr, + const struct env_set *es) { - struct argv argv = argv_new (); - int r; + struct argv argv = argv_new(); + int r; + + if (!ifname || !lladdr) + { + return -1; + } - if (!ifname || !lladdr) - return -1; - #if defined(TARGET_LINUX) #ifdef ENABLE_IPROUTE - argv_printf (&argv, - "%s link set addr %s dev %s", - iproute_path, lladdr, ifname); + argv_printf(&argv, + "%s link set addr %s dev %s", + iproute_path, lladdr, ifname); #else - argv_printf (&argv, - "%s %s hw ether %s", - IFCONFIG_PATH, - ifname, lladdr); + argv_printf(&argv, + "%s %s hw ether %s", + IFCONFIG_PATH, + ifname, lladdr); #endif #elif defined(TARGET_SOLARIS) - argv_printf (&argv, - "%s %s ether %s", - IFCONFIG_PATH, - ifname, lladdr); + argv_printf(&argv, + "%s %s ether %s", + IFCONFIG_PATH, + ifname, lladdr); #elif defined(TARGET_OPENBSD) - argv_printf (&argv, - "%s %s lladdr %s", - IFCONFIG_PATH, - ifname, lladdr); + argv_printf(&argv, + "%s %s lladdr %s", + IFCONFIG_PATH, + ifname, lladdr); #elif defined(TARGET_DARWIN) - argv_printf (&argv, - "%s %s lladdr %s", - IFCONFIG_PATH, - ifname, lladdr); + argv_printf(&argv, + "%s %s lladdr %s", + IFCONFIG_PATH, + ifname, lladdr); #elif defined(TARGET_FREEBSD) - argv_printf (&argv, - "%s %s ether %s", - IFCONFIG_PATH, - ifname, lladdr); -#else - msg (M_WARN, "Sorry, but I don't know how to configure link layer addresses on this operating system."); - return -1; -#endif + argv_printf(&argv, + "%s %s ether %s", + IFCONFIG_PATH, + ifname, lladdr); +#else /* if defined(TARGET_LINUX) */ + msg(M_WARN, "Sorry, but I don't know how to configure link layer addresses on this operating system."); + return -1; +#endif /* if defined(TARGET_LINUX) */ - argv_msg (M_INFO, &argv); - r = openvpn_execve_check (&argv, es, M_WARN, "ERROR: Unable to set link layer address."); - if (r) - msg (M_INFO, "TUN/TAP link layer address set to %s", lladdr); + argv_msg(M_INFO, &argv); + r = openvpn_execve_check(&argv, es, M_WARN, "ERROR: Unable to set link layer address."); + if (r) + { + msg(M_INFO, "TUN/TAP link layer address set to %s", lladdr); + } - argv_reset (&argv); - return r; + argv_reset(&argv); + return r; } diff --git a/src/openvpn/lladdr.h b/src/openvpn/lladdr.h index d6c4256296a..f6ea2b1227c 100644 --- a/src/openvpn/lladdr.h +++ b/src/openvpn/lladdr.h @@ -1,8 +1,8 @@ /* - * Support routine for configuring link layer address + * Support routine for configuring link layer address */ #include "misc.h" int set_lladdr(const char *ifname, const char *lladdr, - const struct env_set *es); + const struct env_set *es); diff --git a/src/openvpn/lzo.c b/src/openvpn/lzo.c index 25a839bad0f..e587268aa57 100644 --- a/src/openvpn/lzo.c +++ b/src/openvpn/lzo.c @@ -50,206 +50,223 @@ * @return */ static bool -lzo_adaptive_compress_test (struct lzo_adaptive_compress *ac) +lzo_adaptive_compress_test(struct lzo_adaptive_compress *ac) { - const bool save = ac->compress_state; - const time_t local_now = now; + const bool save = ac->compress_state; + const time_t local_now = now; - if (!ac->compress_state) + if (!ac->compress_state) { - if (local_now >= ac->next) - { - if (ac->n_total > AC_MIN_BYTES - && (ac->n_total - ac->n_comp) < (ac->n_total / (100 / AC_SAVE_PCT))) - { - ac->compress_state = true; - ac->next = local_now + AC_OFF_SEC; - } - else - { - ac->next = local_now + AC_SAMP_SEC; - } - dmsg (D_COMP, "lzo_adaptive_compress_test: comp=%d total=%d", ac->n_comp, ac->n_total); - ac->n_total = ac->n_comp = 0; - } + if (local_now >= ac->next) + { + if (ac->n_total > AC_MIN_BYTES + && (ac->n_total - ac->n_comp) < (ac->n_total / (100 / AC_SAVE_PCT))) + { + ac->compress_state = true; + ac->next = local_now + AC_OFF_SEC; + } + else + { + ac->next = local_now + AC_SAMP_SEC; + } + dmsg(D_COMP, "lzo_adaptive_compress_test: comp=%d total=%d", ac->n_comp, ac->n_total); + ac->n_total = ac->n_comp = 0; + } } - else + else { - if (local_now >= ac->next) - { - ac->next = local_now + AC_SAMP_SEC; - ac->n_total = ac->n_comp = 0; - ac->compress_state = false; - } + if (local_now >= ac->next) + { + ac->next = local_now + AC_SAMP_SEC; + ac->n_total = ac->n_comp = 0; + ac->compress_state = false; + } } - if (ac->compress_state != save) - dmsg (D_COMP_LOW, "Adaptive compression state %s", (ac->compress_state ? "OFF" : "ON")); + if (ac->compress_state != save) + { + dmsg(D_COMP_LOW, "Adaptive compression state %s", (ac->compress_state ? "OFF" : "ON")); + } - return !ac->compress_state; + return !ac->compress_state; } static inline void -lzo_adaptive_compress_data (struct lzo_adaptive_compress *ac, int n_total, int n_comp) +lzo_adaptive_compress_data(struct lzo_adaptive_compress *ac, int n_total, int n_comp) { - ac->n_total += n_total; - ac->n_comp += n_comp; + ac->n_total += n_total; + ac->n_comp += n_comp; } static void -lzo_compress_init (struct compress_context *compctx) +lzo_compress_init(struct compress_context *compctx) { - msg (D_INIT_MEDIUM, "LZO compression initializing"); - ASSERT(!(compctx->flags & COMP_F_SWAP)); - compctx->wu.lzo.wmem_size = LZO_WORKSPACE; - if (lzo_init () != LZO_E_OK) - msg (M_FATAL, "Cannot initialize LZO compression library"); - compctx->wu.lzo.wmem = (lzo_voidp) lzo_malloc (compctx->wu.lzo.wmem_size); - check_malloc_return (compctx->wu.lzo.wmem); + msg(D_INIT_MEDIUM, "LZO compression initializing"); + ASSERT(!(compctx->flags & COMP_F_SWAP)); + compctx->wu.lzo.wmem_size = LZO_WORKSPACE; + if (lzo_init() != LZO_E_OK) + { + msg(M_FATAL, "Cannot initialize LZO compression library"); + } + compctx->wu.lzo.wmem = (lzo_voidp) lzo_malloc(compctx->wu.lzo.wmem_size); + check_malloc_return(compctx->wu.lzo.wmem); } static void -lzo_compress_uninit (struct compress_context *compctx) +lzo_compress_uninit(struct compress_context *compctx) { - lzo_free (compctx->wu.lzo.wmem); - compctx->wu.lzo.wmem = NULL; + lzo_free(compctx->wu.lzo.wmem); + compctx->wu.lzo.wmem = NULL; } static inline bool -lzo_compression_enabled (struct compress_context *compctx) +lzo_compression_enabled(struct compress_context *compctx) { - if (compctx->flags & COMP_F_ASYM) - return false; - else + if (compctx->flags & COMP_F_ASYM) { - if (compctx->flags & COMP_F_ADAPTIVE) - return lzo_adaptive_compress_test (&compctx->wu.lzo.ac); - else - return true; + return false; + } + else + { + if (compctx->flags & COMP_F_ADAPTIVE) + { + return lzo_adaptive_compress_test(&compctx->wu.lzo.ac); + } + else + { + return true; + } } } static void -lzo_compress (struct buffer *buf, struct buffer work, - struct compress_context *compctx, - const struct frame* frame) +lzo_compress(struct buffer *buf, struct buffer work, + struct compress_context *compctx, + const struct frame *frame) { - lzo_uint zlen = 0; - int err; - bool compressed = false; - - if (buf->len <= 0) - return; - - /* - * In order to attempt compression, length must be at least COMPRESS_THRESHOLD, - * and our adaptive level must give the OK. - */ - if (buf->len >= COMPRESS_THRESHOLD && lzo_compression_enabled (compctx)) + lzo_uint zlen = 0; + int err; + bool compressed = false; + + if (buf->len <= 0) { - const size_t ps = PAYLOAD_SIZE (frame); - ASSERT (buf_init (&work, FRAME_HEADROOM (frame))); - ASSERT (buf_safe (&work, ps + COMP_EXTRA_BUFFER (ps))); - - if (buf->len > ps) - { - dmsg (D_COMP_ERRORS, "LZO compression buffer overflow"); - buf->len = 0; - return; - } - - err = LZO_COMPRESS (BPTR (buf), BLEN (buf), BPTR (&work), &zlen, compctx->wu.lzo.wmem); - if (err != LZO_E_OK) - { - dmsg (D_COMP_ERRORS, "LZO compression error: %d", err); - buf->len = 0; - return; - } - - ASSERT (buf_safe (&work, zlen)); - work.len = zlen; - compressed = true; - - dmsg (D_COMP, "LZO compress %d -> %d", buf->len, work.len); - compctx->pre_compress += buf->len; - compctx->post_compress += work.len; - - /* tell adaptive level about our success or lack thereof in getting any size reduction */ - if (compctx->flags & COMP_F_ADAPTIVE) - lzo_adaptive_compress_data (&compctx->wu.lzo.ac, buf->len, work.len); + return; } - /* did compression save us anything ? */ - if (compressed && work.len < buf->len) + /* + * In order to attempt compression, length must be at least COMPRESS_THRESHOLD, + * and our adaptive level must give the OK. + */ + if (buf->len >= COMPRESS_THRESHOLD && lzo_compression_enabled(compctx)) { - uint8_t *header = buf_prepend (&work, 1); - *header = LZO_COMPRESS_BYTE; - *buf = work; + const size_t ps = PAYLOAD_SIZE(frame); + ASSERT(buf_init(&work, FRAME_HEADROOM(frame))); + ASSERT(buf_safe(&work, ps + COMP_EXTRA_BUFFER(ps))); + + if (buf->len > ps) + { + dmsg(D_COMP_ERRORS, "LZO compression buffer overflow"); + buf->len = 0; + return; + } + + err = LZO_COMPRESS(BPTR(buf), BLEN(buf), BPTR(&work), &zlen, compctx->wu.lzo.wmem); + if (err != LZO_E_OK) + { + dmsg(D_COMP_ERRORS, "LZO compression error: %d", err); + buf->len = 0; + return; + } + + ASSERT(buf_safe(&work, zlen)); + work.len = zlen; + compressed = true; + + dmsg(D_COMP, "LZO compress %d -> %d", buf->len, work.len); + compctx->pre_compress += buf->len; + compctx->post_compress += work.len; + + /* tell adaptive level about our success or lack thereof in getting any size reduction */ + if (compctx->flags & COMP_F_ADAPTIVE) + { + lzo_adaptive_compress_data(&compctx->wu.lzo.ac, buf->len, work.len); + } } - else + + /* did compression save us anything ? */ + if (compressed && work.len < buf->len) + { + uint8_t *header = buf_prepend(&work, 1); + *header = LZO_COMPRESS_BYTE; + *buf = work; + } + else { - uint8_t *header = buf_prepend (buf, 1); - *header = NO_COMPRESS_BYTE; + uint8_t *header = buf_prepend(buf, 1); + *header = NO_COMPRESS_BYTE; } } static void -lzo_decompress (struct buffer *buf, struct buffer work, - struct compress_context *compctx, - const struct frame* frame) +lzo_decompress(struct buffer *buf, struct buffer work, + struct compress_context *compctx, + const struct frame *frame) { - lzo_uint zlen = EXPANDED_SIZE (frame); - int err; - uint8_t c; /* flag indicating whether or not our peer compressed */ + lzo_uint zlen = EXPANDED_SIZE(frame); + int err; + uint8_t c; /* flag indicating whether or not our peer compressed */ - if (buf->len <= 0) - return; + if (buf->len <= 0) + { + return; + } - ASSERT (buf_init (&work, FRAME_HEADROOM (frame))); + ASSERT(buf_init(&work, FRAME_HEADROOM(frame))); - c = *BPTR (buf); - ASSERT (buf_advance (buf, 1)); + c = *BPTR(buf); + ASSERT(buf_advance(buf, 1)); - if (c == LZO_COMPRESS_BYTE) /* packet was compressed */ + if (c == LZO_COMPRESS_BYTE) /* packet was compressed */ { - ASSERT (buf_safe (&work, zlen)); - err = LZO_DECOMPRESS (BPTR (buf), BLEN (buf), BPTR (&work), &zlen, - compctx->wu.lzo.wmem); - if (err != LZO_E_OK) - { - dmsg (D_COMP_ERRORS, "LZO decompression error: %d", err); - buf->len = 0; - return; - } - - ASSERT (buf_safe (&work, zlen)); - work.len = zlen; - - dmsg (D_COMP, "LZO decompress %d -> %d", buf->len, work.len); - compctx->pre_decompress += buf->len; - compctx->post_decompress += work.len; - - *buf = work; + ASSERT(buf_safe(&work, zlen)); + err = LZO_DECOMPRESS(BPTR(buf), BLEN(buf), BPTR(&work), &zlen, + compctx->wu.lzo.wmem); + if (err != LZO_E_OK) + { + dmsg(D_COMP_ERRORS, "LZO decompression error: %d", err); + buf->len = 0; + return; + } + + ASSERT(buf_safe(&work, zlen)); + work.len = zlen; + + dmsg(D_COMP, "LZO decompress %d -> %d", buf->len, work.len); + compctx->pre_decompress += buf->len; + compctx->post_decompress += work.len; + + *buf = work; } - else if (c == NO_COMPRESS_BYTE) /* packet was not compressed */ + else if (c == NO_COMPRESS_BYTE) /* packet was not compressed */ { - ; } - else + else { - dmsg (D_COMP_ERRORS, "Bad LZO decompression header byte: %d", c); - buf->len = 0; + dmsg(D_COMP_ERRORS, "Bad LZO decompression header byte: %d", c); + buf->len = 0; } } const struct compress_alg lzo_alg = { - "lzo", - lzo_compress_init, - lzo_compress_uninit, - lzo_compress, - lzo_decompress + "lzo", + lzo_compress_init, + lzo_compress_uninit, + lzo_compress, + lzo_decompress }; -#else -static void dummy(void) {} +#else /* if defined(ENABLE_LZO) */ +static void +dummy(void) { +} #endif /* ENABLE_LZO */ diff --git a/src/openvpn/lzo.h b/src/openvpn/lzo.h index f33e587ad21..f9eddcc0401 100644 --- a/src/openvpn/lzo.h +++ b/src/openvpn/lzo.h @@ -60,26 +60,26 @@ extern const struct compress_alg lzo_alg; /**************************************************************************/ /** @name LZO library interface defines *//** @{ *//***********************/ #define LZO_COMPRESS lzo1x_1_15_compress - /**< LZO library compression function. - * - * Use \c lzo1x_1_15_compress because it - * is described as faster than the - * standard routine, although it does - * need a bit more memory. */ -#define LZO_WORKSPACE LZO1X_1_15_MEM_COMPRESS - /**< The size in bytes of the memory - * %buffer required by the LZO library - * compression algorithm. */ +/**< LZO library compression function. + * + * Use \c lzo1x_1_15_compress because it + * is described as faster than the + * standard routine, although it does + * need a bit more memory. */ +#define LZO_WORKSPACE LZO1X_1_15_MEM_COMPRESS +/**< The size in bytes of the memory + * %buffer required by the LZO library + * compression algorithm. */ #define LZO_DECOMPRESS lzo1x_decompress_safe - /**< LZO library decompression function. - * - * Use safe decompress because it - * includes checks for possible %buffer - * overflows. If speed is essential and - * you will always be using a MAC to - * verify the integrity of incoming - * packets, you might want to consider - * using the non-safe version. */ +/**< LZO library decompression function. + * + * Use safe decompress because it + * includes checks for possible %buffer + * overflows. If speed is essential and + * you will always be using a MAC to + * verify the integrity of incoming + * packets, you might want to consider + * using the non-safe version. */ /** @} name LZO library interface *//**************************************/ @@ -100,10 +100,10 @@ extern const struct compress_alg lzo_alg; * Adaptive compression state. */ struct lzo_adaptive_compress { - bool compress_state; - time_t next; - int n_total; - int n_comp; + bool compress_state; + time_t next; + int n_total; + int n_comp; }; @@ -119,13 +119,13 @@ struct lzo_adaptive_compress { */ struct lzo_compress_workspace { - lzo_voidp wmem; - int wmem_size; - struct lzo_adaptive_compress ac; + lzo_voidp wmem; + int wmem_size; + struct lzo_adaptive_compress ac; }; /** @} addtogroup compression */ #endif /* ENABLE_LZO && USE_COMP */ -#endif +#endif /* ifndef OPENVPN_LZO_H */ diff --git a/src/openvpn/manage.c b/src/openvpn/manage.c index aab42249656..b6520c0d4cd 100644 --- a/src/openvpn/manage.c +++ b/src/openvpn/manage.c @@ -64,286 +64,321 @@ static const char blank_up[] = "[[BLANK]]"; struct management *management; /* GLOBAL */ /* static forward declarations */ -static void man_output_standalone (struct management *man, volatile int *signal_received); -static void man_reset_client_socket (struct management *man, const bool exiting); - -static void -man_help () -{ - msg (M_CLIENT, "Management Interface for %s", title_string); - msg (M_CLIENT, "Commands:"); - msg (M_CLIENT, "auth-retry t : Auth failure retry mode (none,interact,nointeract)."); - msg (M_CLIENT, "bytecount n : Show bytes in/out, update every n secs (0=off)."); - msg (M_CLIENT, "echo [on|off] [N|all] : Like log, but only show messages in echo buffer."); - msg (M_CLIENT, "exit|quit : Close management session."); - msg (M_CLIENT, "forget-passwords : Forget passwords entered so far."); - msg (M_CLIENT, "help : Print this message."); - msg (M_CLIENT, "hold [on|off|release] : Set/show hold flag to on/off state, or"); - msg (M_CLIENT, " release current hold and start tunnel."); - msg (M_CLIENT, "kill cn : Kill the client instance(s) having common name cn."); - msg (M_CLIENT, "kill IP:port : Kill the client instance connecting from IP:port."); - msg (M_CLIENT, "load-stats : Show global server load stats."); - msg (M_CLIENT, "log [on|off] [N|all] : Turn on/off realtime log display"); - msg (M_CLIENT, " + show last N lines or 'all' for entire history."); - msg (M_CLIENT, "mute [n] : Set log mute level to n, or show level if n is absent."); - msg (M_CLIENT, "needok type action : Enter confirmation for NEED-OK request of 'type',"); - msg (M_CLIENT, " where action = 'ok' or 'cancel'."); - msg (M_CLIENT, "needstr type action : Enter confirmation for NEED-STR request of 'type',"); - msg (M_CLIENT, " where action is reply string."); - msg (M_CLIENT, "net : (Windows only) Show network info and routing table."); - msg (M_CLIENT, "password type p : Enter password p for a queried OpenVPN password."); - msg (M_CLIENT, "remote type [host port] : Override remote directive, type=ACCEPT|MOD|SKIP."); - msg (M_CLIENT, "proxy type [host port flags] : Enter dynamic proxy server info."); - msg (M_CLIENT, "pid : Show process ID of the current OpenVPN process."); +static void man_output_standalone(struct management *man, volatile int *signal_received); + +static void man_reset_client_socket(struct management *man, const bool exiting); + +static void +man_help() +{ + msg(M_CLIENT, "Management Interface for %s", title_string); + msg(M_CLIENT, "Commands:"); + msg(M_CLIENT, "auth-retry t : Auth failure retry mode (none,interact,nointeract)."); + msg(M_CLIENT, "bytecount n : Show bytes in/out, update every n secs (0=off)."); + msg(M_CLIENT, "echo [on|off] [N|all] : Like log, but only show messages in echo buffer."); + msg(M_CLIENT, "exit|quit : Close management session."); + msg(M_CLIENT, "forget-passwords : Forget passwords entered so far."); + msg(M_CLIENT, "help : Print this message."); + msg(M_CLIENT, "hold [on|off|release] : Set/show hold flag to on/off state, or"); + msg(M_CLIENT, " release current hold and start tunnel."); + msg(M_CLIENT, "kill cn : Kill the client instance(s) having common name cn."); + msg(M_CLIENT, "kill IP:port : Kill the client instance connecting from IP:port."); + msg(M_CLIENT, "load-stats : Show global server load stats."); + msg(M_CLIENT, "log [on|off] [N|all] : Turn on/off realtime log display"); + msg(M_CLIENT, " + show last N lines or 'all' for entire history."); + msg(M_CLIENT, "mute [n] : Set log mute level to n, or show level if n is absent."); + msg(M_CLIENT, "needok type action : Enter confirmation for NEED-OK request of 'type',"); + msg(M_CLIENT, " where action = 'ok' or 'cancel'."); + msg(M_CLIENT, "needstr type action : Enter confirmation for NEED-STR request of 'type',"); + msg(M_CLIENT, " where action is reply string."); + msg(M_CLIENT, "net : (Windows only) Show network info and routing table."); + msg(M_CLIENT, "password type p : Enter password p for a queried OpenVPN password."); + msg(M_CLIENT, "remote type [host port] : Override remote directive, type=ACCEPT|MOD|SKIP."); + msg(M_CLIENT, "proxy type [host port flags] : Enter dynamic proxy server info."); + msg(M_CLIENT, "pid : Show process ID of the current OpenVPN process."); #ifdef ENABLE_PKCS11 - msg (M_CLIENT, "pkcs11-id-count : Get number of available PKCS#11 identities."); - msg (M_CLIENT, "pkcs11-id-get index : Get PKCS#11 identity at index."); + msg(M_CLIENT, "pkcs11-id-count : Get number of available PKCS#11 identities."); + msg(M_CLIENT, "pkcs11-id-get index : Get PKCS#11 identity at index."); #endif #ifdef MANAGEMENT_DEF_AUTH - msg (M_CLIENT, "client-auth CID KID : Authenticate client-id/key-id CID/KID (MULTILINE)"); - msg (M_CLIENT, "client-auth-nt CID KID : Authenticate client-id/key-id CID/KID"); - msg (M_CLIENT, "client-deny CID KID R [CR] : Deny auth client-id/key-id CID/KID with log reason"); - msg (M_CLIENT, " text R and optional client reason text CR"); - msg (M_CLIENT, "client-kill CID [M] : Kill client instance CID with message M (def=RESTART)"); - msg (M_CLIENT, "env-filter [level] : Set env-var filter level"); + msg(M_CLIENT, "client-auth CID KID : Authenticate client-id/key-id CID/KID (MULTILINE)"); + msg(M_CLIENT, "client-auth-nt CID KID : Authenticate client-id/key-id CID/KID"); + msg(M_CLIENT, "client-deny CID KID R [CR] : Deny auth client-id/key-id CID/KID with log reason"); + msg(M_CLIENT, " text R and optional client reason text CR"); + msg(M_CLIENT, "client-kill CID [M] : Kill client instance CID with message M (def=RESTART)"); + msg(M_CLIENT, "env-filter [level] : Set env-var filter level"); #ifdef MANAGEMENT_PF - msg (M_CLIENT, "client-pf CID : Define packet filter for client CID (MULTILINE)"); + msg(M_CLIENT, "client-pf CID : Define packet filter for client CID (MULTILINE)"); #endif #endif #ifdef MANAGMENT_EXTERNAL_KEY - msg (M_CLIENT, "rsa-sig : Enter an RSA signature in response to >RSA_SIGN challenge"); - msg (M_CLIENT, " Enter signature base64 on subsequent lines followed by END"); - msg (M_CLIENT, "certificate : Enter a client certificate in response to >NEED-CERT challenge"); - msg (M_CLIENT, " Enter certificate base64 on subsequent lines followed by END"); + msg(M_CLIENT, "rsa-sig : Enter an RSA signature in response to >RSA_SIGN challenge"); + msg(M_CLIENT, " Enter signature base64 on subsequent lines followed by END"); + msg(M_CLIENT, "certificate : Enter a client certificate in response to >NEED-CERT challenge"); + msg(M_CLIENT, " Enter certificate base64 on subsequent lines followed by END"); #endif - msg (M_CLIENT, "signal s : Send signal s to daemon,"); - msg (M_CLIENT, " s = SIGHUP|SIGTERM|SIGUSR1|SIGUSR2."); - msg (M_CLIENT, "state [on|off] [N|all] : Like log, but show state history."); - msg (M_CLIENT, "status [n] : Show current daemon status info using format #n."); - msg (M_CLIENT, "test n : Produce n lines of output for testing/debugging."); - msg (M_CLIENT, "username type u : Enter username u for a queried OpenVPN username."); - msg (M_CLIENT, "verb [n] : Set log verbosity level to n, or show if n is absent."); - msg (M_CLIENT, "version : Show current version number."); - msg (M_CLIENT, "END"); + msg(M_CLIENT, "signal s : Send signal s to daemon,"); + msg(M_CLIENT, " s = SIGHUP|SIGTERM|SIGUSR1|SIGUSR2."); + msg(M_CLIENT, "state [on|off] [N|all] : Like log, but show state history."); + msg(M_CLIENT, "status [n] : Show current daemon status info using format #n."); + msg(M_CLIENT, "test n : Produce n lines of output for testing/debugging."); + msg(M_CLIENT, "username type u : Enter username u for a queried OpenVPN username."); + msg(M_CLIENT, "verb [n] : Set log verbosity level to n, or show if n is absent."); + msg(M_CLIENT, "version : Show current version number."); + msg(M_CLIENT, "END"); } static const char * -man_state_name (const int state) -{ - switch (state) - { - case OPENVPN_STATE_INITIAL: - return "INITIAL"; - case OPENVPN_STATE_CONNECTING: - return "CONNECTING"; - case OPENVPN_STATE_WAIT: - return "WAIT"; - case OPENVPN_STATE_AUTH: - return "AUTH"; - case OPENVPN_STATE_GET_CONFIG: - return "GET_CONFIG"; - case OPENVPN_STATE_ASSIGN_IP: - return "ASSIGN_IP"; - case OPENVPN_STATE_ADD_ROUTES: - return "ADD_ROUTES"; - case OPENVPN_STATE_CONNECTED: - return "CONNECTED"; - case OPENVPN_STATE_RECONNECTING: - return "RECONNECTING"; - case OPENVPN_STATE_EXITING: - return "EXITING"; - case OPENVPN_STATE_RESOLVE: - return "RESOLVE"; - case OPENVPN_STATE_TCP_CONNECT: - return "TCP_CONNECT"; - default: - return "?"; - } -} - -static void -man_welcome (struct management *man) -{ - msg (M_CLIENT, ">INFO:OpenVPN Management Interface Version %d -- type 'help' for more info", - MANAGEMENT_VERSION); - if (man->persist.special_state_msg) - msg (M_CLIENT, "%s", man->persist.special_state_msg); +man_state_name(const int state) +{ + switch (state) + { + case OPENVPN_STATE_INITIAL: + return "INITIAL"; + + case OPENVPN_STATE_CONNECTING: + return "CONNECTING"; + + case OPENVPN_STATE_WAIT: + return "WAIT"; + + case OPENVPN_STATE_AUTH: + return "AUTH"; + + case OPENVPN_STATE_GET_CONFIG: + return "GET_CONFIG"; + + case OPENVPN_STATE_ASSIGN_IP: + return "ASSIGN_IP"; + + case OPENVPN_STATE_ADD_ROUTES: + return "ADD_ROUTES"; + + case OPENVPN_STATE_CONNECTED: + return "CONNECTED"; + + case OPENVPN_STATE_RECONNECTING: + return "RECONNECTING"; + + case OPENVPN_STATE_EXITING: + return "EXITING"; + + case OPENVPN_STATE_RESOLVE: + return "RESOLVE"; + + case OPENVPN_STATE_TCP_CONNECT: + return "TCP_CONNECT"; + + default: + return "?"; + } +} + +static void +man_welcome(struct management *man) +{ + msg(M_CLIENT, ">INFO:OpenVPN Management Interface Version %d -- type 'help' for more info", + MANAGEMENT_VERSION); + if (man->persist.special_state_msg) + { + msg(M_CLIENT, "%s", man->persist.special_state_msg); + } } static inline bool -man_password_needed (struct management *man) +man_password_needed(struct management *man) { - return man->settings.up.defined && !man->connection.password_verified; + return man->settings.up.defined && !man->connection.password_verified; } static void -man_check_password (struct management *man, const char *line) +man_check_password(struct management *man, const char *line) { - if (man_password_needed (man)) + if (man_password_needed(man)) { - if (streq (line, man->settings.up.password)) - { - man->connection.password_verified = true; - msg (M_CLIENT, "SUCCESS: password is correct"); - man_welcome (man); - } - else - { - man->connection.password_verified = false; - msg (M_CLIENT, "ERROR: bad password"); - if (++man->connection.password_tries >= MANAGEMENT_N_PASSWORD_RETRIES) - { - msg (M_WARN, "MAN: client connection rejected after %d failed password attempts", - MANAGEMENT_N_PASSWORD_RETRIES); - man->connection.halt = true; - } - } + if (streq(line, man->settings.up.password)) + { + man->connection.password_verified = true; + msg(M_CLIENT, "SUCCESS: password is correct"); + man_welcome(man); + } + else + { + man->connection.password_verified = false; + msg(M_CLIENT, "ERROR: bad password"); + if (++man->connection.password_tries >= MANAGEMENT_N_PASSWORD_RETRIES) + { + msg(M_WARN, "MAN: client connection rejected after %d failed password attempts", + MANAGEMENT_N_PASSWORD_RETRIES); + man->connection.halt = true; + } + } } } static void -man_update_io_state (struct management *man) +man_update_io_state(struct management *man) { - if (socket_defined (man->connection.sd_cli)) + if (socket_defined(man->connection.sd_cli)) { - if (buffer_list_defined (man->connection.out)) - { - man->connection.state = MS_CC_WAIT_WRITE; - } - else - { - man->connection.state = MS_CC_WAIT_READ; - } + if (buffer_list_defined(man->connection.out)) + { + man->connection.state = MS_CC_WAIT_WRITE; + } + else + { + man->connection.state = MS_CC_WAIT_READ; + } } } static void -man_output_list_push_finalize (struct management *man) +man_output_list_push_finalize(struct management *man) { - if (management_connected (man)) + if (management_connected(man)) { - man_update_io_state (man); - if (!man->persist.standalone_disabled) - { - volatile int signal_received = 0; - man_output_standalone (man, &signal_received); - } + man_update_io_state(man); + if (!man->persist.standalone_disabled) + { + volatile int signal_received = 0; + man_output_standalone(man, &signal_received); + } } } static void -man_output_list_push_str (struct management *man, const char *str) +man_output_list_push_str(struct management *man, const char *str) { - if (management_connected (man) && str) + if (management_connected(man) && str) { - buffer_list_push (man->connection.out, (const unsigned char *) str); + buffer_list_push(man->connection.out, (const unsigned char *) str); } } static void -man_output_list_push (struct management *man, const char *str) +man_output_list_push(struct management *man, const char *str) { - man_output_list_push_str (man, str); - man_output_list_push_finalize (man); + man_output_list_push_str(man, str); + man_output_list_push_finalize(man); } static void -man_prompt (struct management *man) +man_prompt(struct management *man) { - if (man_password_needed (man)) - man_output_list_push (man, "ENTER PASSWORD:"); + if (man_password_needed(man)) + { + man_output_list_push(man, "ENTER PASSWORD:"); + } #if 0 /* should we use prompt? */ - else - man_output_list_push (man, ">"); + else + { + man_output_list_push(man, ">"); + } #endif } static void -man_delete_unix_socket (struct management *man) +man_delete_unix_socket(struct management *man) { #if UNIX_SOCK_SUPPORT - if ((man->settings.flags & (MF_UNIX_SOCK|MF_CONNECT_AS_CLIENT)) == MF_UNIX_SOCK) - socket_delete_unix (&man->settings.local_unix); + if ((man->settings.flags & (MF_UNIX_SOCK|MF_CONNECT_AS_CLIENT)) == MF_UNIX_SOCK) + { + socket_delete_unix(&man->settings.local_unix); + } #endif } static void -man_close_socket (struct management *man, const socket_descriptor_t sd) +man_close_socket(struct management *man, const socket_descriptor_t sd) { #ifndef _WIN32 - /* - * Windows doesn't need this because the ne32 event is permanently - * enabled at struct management scope. - */ - if (man->persist.callback.delete_event) - (*man->persist.callback.delete_event) (man->persist.callback.arg, sd); + /* + * Windows doesn't need this because the ne32 event is permanently + * enabled at struct management scope. + */ + if (man->persist.callback.delete_event) + { + (*man->persist.callback.delete_event)(man->persist.callback.arg, sd); + } #endif - openvpn_close_socket (sd); + openvpn_close_socket(sd); } static void -virtual_output_callback_func (void *arg, const unsigned int flags, const char *str) +virtual_output_callback_func(void *arg, const unsigned int flags, const char *str) { - struct management *man = (struct management *) arg; - static int recursive_level = 0; /* GLOBAL */ + struct management *man = (struct management *) arg; + static int recursive_level = 0; /* GLOBAL */ -# define AF_DID_PUSH (1<<0) -# define AF_DID_RESET (1<<1) +#define AF_DID_PUSH (1<<0) +#define AF_DID_RESET (1<<1) - if (!recursive_level) /* don't allow recursion */ + if (!recursive_level) /* don't allow recursion */ { - struct gc_arena gc = gc_new (); - struct log_entry e; - const char *out = NULL; - unsigned int action_flags = 0; - - ++recursive_level; - - CLEAR (e); - update_time (); - e.timestamp = now; - e.u.msg_flags = flags; - e.string = str; + struct gc_arena gc = gc_new(); + struct log_entry e; + const char *out = NULL; + unsigned int action_flags = 0; - if (flags & M_FATAL) - man->persist.standalone_disabled = false; + ++recursive_level; - if (flags != M_CLIENT) - log_history_add (man->persist.log, &e); + CLEAR(e); + update_time(); + e.timestamp = now; + e.u.msg_flags = flags; + e.string = str; - if (!man_password_needed (man)) - { - if (flags == M_CLIENT) - out = log_entry_print (&e, LOG_PRINT_CRLF, &gc); - else if (man->connection.log_realtime) - out = log_entry_print (&e, LOG_PRINT_INT_DATE - | LOG_PRINT_MSG_FLAGS - | LOG_PRINT_LOG_PREFIX - | LOG_PRINT_CRLF, &gc); - if (out) - { - man_output_list_push_str (man, out); - action_flags |= AF_DID_PUSH; - } - if (flags & M_FATAL) - { - out = log_entry_print (&e, LOG_FATAL_NOTIFY|LOG_PRINT_CRLF, &gc); - if (out) - { - man_output_list_push_str (man, out); - action_flags |= (AF_DID_PUSH|AF_DID_RESET); - } - } - } + if (flags & M_FATAL) + { + man->persist.standalone_disabled = false; + } - gc_free (&gc); + if (flags != M_CLIENT) + { + log_history_add(man->persist.log, &e); + } - if (action_flags & AF_DID_PUSH) - man_output_list_push_finalize (man); - if (action_flags & AF_DID_RESET) - man_reset_client_socket (man, true); + if (!man_password_needed(man)) + { + if (flags == M_CLIENT) + { + out = log_entry_print(&e, LOG_PRINT_CRLF, &gc); + } + else if (man->connection.log_realtime) + { + out = log_entry_print(&e, LOG_PRINT_INT_DATE + | LOG_PRINT_MSG_FLAGS + | LOG_PRINT_LOG_PREFIX + | LOG_PRINT_CRLF, &gc); + } + if (out) + { + man_output_list_push_str(man, out); + action_flags |= AF_DID_PUSH; + } + if (flags & M_FATAL) + { + out = log_entry_print(&e, LOG_FATAL_NOTIFY|LOG_PRINT_CRLF, &gc); + if (out) + { + man_output_list_push_str(man, out); + action_flags |= (AF_DID_PUSH|AF_DID_RESET); + } + } + } + + gc_free(&gc); + + if (action_flags & AF_DID_PUSH) + { + man_output_list_push_finalize(man); + } + if (action_flags & AF_DID_RESET) + { + man_reset_client_socket(man, true); + } - --recursive_level; + --recursive_level; } } @@ -352,180 +387,194 @@ virtual_output_callback_func (void *arg, const unsigned int flags, const char *s * or -1 if the signal should be ignored. */ static int -man_mod_signal (const struct management *man, const int signum) +man_mod_signal(const struct management *man, const int signum) { - const unsigned int flags = man->settings.mansig; - int s = signum; - if (s == SIGUSR1) + const unsigned int flags = man->settings.mansig; + int s = signum; + if (s == SIGUSR1) { - if (flags & MANSIG_MAP_USR1_TO_HUP) - s = SIGHUP; - if (flags & MANSIG_MAP_USR1_TO_TERM) - s = SIGTERM; + if (flags & MANSIG_MAP_USR1_TO_HUP) + { + s = SIGHUP; + } + if (flags & MANSIG_MAP_USR1_TO_TERM) + { + s = SIGTERM; + } } - if (flags & MANSIG_IGNORE_USR1_HUP) + if (flags & MANSIG_IGNORE_USR1_HUP) { - if (s == SIGHUP || s == SIGUSR1) - s = -1; + if (s == SIGHUP || s == SIGUSR1) + { + s = -1; + } } - return s; + return s; } static void -man_signal (struct management *man, const char *name) +man_signal(struct management *man, const char *name) { - const int sig = parse_signal (name); - if (sig >= 0) + const int sig = parse_signal(name); + if (sig >= 0) { - const int sig_mod = man_mod_signal (man, sig); - if (sig_mod >= 0) - { - throw_signal (sig_mod); - msg (M_CLIENT, "SUCCESS: signal %s thrown", signal_name (sig_mod, true)); - } - else - { - if (man->persist.special_state_msg) - msg (M_CLIENT, "%s", man->persist.special_state_msg); - else - msg (M_CLIENT, "ERROR: signal '%s' is currently ignored", name); - } + const int sig_mod = man_mod_signal(man, sig); + if (sig_mod >= 0) + { + throw_signal(sig_mod); + msg(M_CLIENT, "SUCCESS: signal %s thrown", signal_name(sig_mod, true)); + } + else + { + if (man->persist.special_state_msg) + { + msg(M_CLIENT, "%s", man->persist.special_state_msg); + } + else + { + msg(M_CLIENT, "ERROR: signal '%s' is currently ignored", name); + } + } } - else + else { - msg (M_CLIENT, "ERROR: signal '%s' is not a known signal type", name); + msg(M_CLIENT, "ERROR: signal '%s' is not a known signal type", name); } } static void -man_status (struct management *man, const int version, struct status_output *so) +man_status(struct management *man, const int version, struct status_output *so) { - if (man->persist.callback.status) + if (man->persist.callback.status) { - (*man->persist.callback.status) (man->persist.callback.arg, version, so); + (*man->persist.callback.status)(man->persist.callback.arg, version, so); } - else + else { - msg (M_CLIENT, "ERROR: The 'status' command is not supported by the current daemon mode"); + msg(M_CLIENT, "ERROR: The 'status' command is not supported by the current daemon mode"); } } static void -man_bytecount (struct management *man, const int update_seconds) +man_bytecount(struct management *man, const int update_seconds) { - if (update_seconds >= 0) - man->connection.bytecount_update_seconds = update_seconds; - else - man->connection.bytecount_update_seconds = 0; - msg (M_CLIENT, "SUCCESS: bytecount interval changed"); + if (update_seconds >= 0) + { + man->connection.bytecount_update_seconds = update_seconds; + } + else + { + man->connection.bytecount_update_seconds = 0; + } + msg(M_CLIENT, "SUCCESS: bytecount interval changed"); } void -man_bytecount_output_client (struct management *man) +man_bytecount_output_client(struct management *man) { - char in[32]; - char out[32]; - /* do in a roundabout way to work around possible mingw or mingw-glibc bug */ - openvpn_snprintf (in, sizeof (in), counter_format, man->persist.bytes_in); - openvpn_snprintf (out, sizeof (out), counter_format, man->persist.bytes_out); - msg (M_CLIENT, ">BYTECOUNT:%s,%s", in, out); - man->connection.bytecount_last_update = now; + char in[32]; + char out[32]; + /* do in a roundabout way to work around possible mingw or mingw-glibc bug */ + openvpn_snprintf(in, sizeof(in), counter_format, man->persist.bytes_in); + openvpn_snprintf(out, sizeof(out), counter_format, man->persist.bytes_out); + msg(M_CLIENT, ">BYTECOUNT:%s,%s", in, out); + man->connection.bytecount_last_update = now; } #ifdef MANAGEMENT_DEF_AUTH void -man_bytecount_output_server (struct management *man, - const counter_type *bytes_in_total, - const counter_type *bytes_out_total, - struct man_def_auth_context *mdac) +man_bytecount_output_server(struct management *man, + const counter_type *bytes_in_total, + const counter_type *bytes_out_total, + struct man_def_auth_context *mdac) { - char in[32]; - char out[32]; - /* do in a roundabout way to work around possible mingw or mingw-glibc bug */ - openvpn_snprintf (in, sizeof (in), counter_format, *bytes_in_total); - openvpn_snprintf (out, sizeof (out), counter_format, *bytes_out_total); - msg (M_CLIENT, ">BYTECOUNT_CLI:%lu,%s,%s", mdac->cid, in, out); - mdac->bytecount_last_update = now; + char in[32]; + char out[32]; + /* do in a roundabout way to work around possible mingw or mingw-glibc bug */ + openvpn_snprintf(in, sizeof(in), counter_format, *bytes_in_total); + openvpn_snprintf(out, sizeof(out), counter_format, *bytes_out_total); + msg(M_CLIENT, ">BYTECOUNT_CLI:%lu,%s,%s", mdac->cid, in, out); + mdac->bytecount_last_update = now; } #endif static void -man_kill (struct management *man, const char *victim) -{ - struct gc_arena gc = gc_new (); - - if (man->persist.callback.kill_by_cn && man->persist.callback.kill_by_addr) - { - struct buffer buf; - char p1[128]; - char p2[128]; - int n_killed; - - buf_set_read (&buf, (uint8_t*) victim, strlen (victim) + 1); - buf_parse (&buf, ':', p1, sizeof (p1)); - buf_parse (&buf, ':', p2, sizeof (p2)); - - if (strlen (p1) && strlen (p2)) - { - /* IP:port specified */ - bool status; - const in_addr_t addr = getaddr (GETADDR_HOST_ORDER|GETADDR_MSG_VIRT_OUT, p1, 0, &status, NULL); - if (status) - { - const int port = atoi (p2); - if (port > 0 && port < 65536) - { - n_killed = (*man->persist.callback.kill_by_addr) (man->persist.callback.arg, addr, port); - if (n_killed > 0) - { - msg (M_CLIENT, "SUCCESS: %d client(s) at address %s:%d killed", - n_killed, - print_in_addr_t (addr, 0, &gc), - port); - } - else - { - msg (M_CLIENT, "ERROR: client at address %s:%d not found", - print_in_addr_t (addr, 0, &gc), - port); - } - } - else - { - msg (M_CLIENT, "ERROR: port number is out of range: %s", p2); - } - } - else - { - msg (M_CLIENT, "ERROR: error parsing IP address: %s", p1); - } - } - else if (strlen (p1)) - { - /* common name specified */ - n_killed = (*man->persist.callback.kill_by_cn) (man->persist.callback.arg, p1); - if (n_killed > 0) - { - msg (M_CLIENT, "SUCCESS: common name '%s' found, %d client(s) killed", p1, n_killed); - } - else - { - msg (M_CLIENT, "ERROR: common name '%s' not found", p1); - } - } - else - { - msg (M_CLIENT, "ERROR: kill parse"); - } - } - else - { - msg (M_CLIENT, "ERROR: The 'kill' command is not supported by the current daemon mode"); - } - - gc_free (&gc); +man_kill(struct management *man, const char *victim) +{ + struct gc_arena gc = gc_new(); + + if (man->persist.callback.kill_by_cn && man->persist.callback.kill_by_addr) + { + struct buffer buf; + char p1[128]; + char p2[128]; + int n_killed; + + buf_set_read(&buf, (uint8_t *) victim, strlen(victim) + 1); + buf_parse(&buf, ':', p1, sizeof(p1)); + buf_parse(&buf, ':', p2, sizeof(p2)); + + if (strlen(p1) && strlen(p2)) + { + /* IP:port specified */ + bool status; + const in_addr_t addr = getaddr(GETADDR_HOST_ORDER|GETADDR_MSG_VIRT_OUT, p1, 0, &status, NULL); + if (status) + { + const int port = atoi(p2); + if (port > 0 && port < 65536) + { + n_killed = (*man->persist.callback.kill_by_addr)(man->persist.callback.arg, addr, port); + if (n_killed > 0) + { + msg(M_CLIENT, "SUCCESS: %d client(s) at address %s:%d killed", + n_killed, + print_in_addr_t(addr, 0, &gc), + port); + } + else + { + msg(M_CLIENT, "ERROR: client at address %s:%d not found", + print_in_addr_t(addr, 0, &gc), + port); + } + } + else + { + msg(M_CLIENT, "ERROR: port number is out of range: %s", p2); + } + } + else + { + msg(M_CLIENT, "ERROR: error parsing IP address: %s", p1); + } + } + else if (strlen(p1)) + { + /* common name specified */ + n_killed = (*man->persist.callback.kill_by_cn)(man->persist.callback.arg, p1); + if (n_killed > 0) + { + msg(M_CLIENT, "SUCCESS: common name '%s' found, %d client(s) killed", p1, n_killed); + } + else + { + msg(M_CLIENT, "ERROR: common name '%s' not found", p1); + } + } + else + { + msg(M_CLIENT, "ERROR: kill parse"); + } + } + else + { + msg(M_CLIENT, "ERROR: The 'kill' command is not supported by the current daemon mode"); + } + + gc_free(&gc); } /* @@ -533,249 +582,270 @@ man_kill (struct management *man, const char *victim) * for the log and echo commands. */ static void -man_history (struct management *man, - const char *parm, - const char *type, - struct log_history *log, - bool *realtime, - const unsigned int lep_flags) +man_history(struct management *man, + const char *parm, + const char *type, + struct log_history *log, + bool *realtime, + const unsigned int lep_flags) { - struct gc_arena gc = gc_new (); - int n = 0; + struct gc_arena gc = gc_new(); + int n = 0; - if (streq (parm, "on")) + if (streq(parm, "on")) { - *realtime = true; - msg (M_CLIENT, "SUCCESS: real-time %s notification set to ON", type); + *realtime = true; + msg(M_CLIENT, "SUCCESS: real-time %s notification set to ON", type); } - else if (streq (parm, "off")) + else if (streq(parm, "off")) { - *realtime = false; - msg (M_CLIENT, "SUCCESS: real-time %s notification set to OFF", type); + *realtime = false; + msg(M_CLIENT, "SUCCESS: real-time %s notification set to OFF", type); } - else if (streq (parm, "all") || (n = atoi (parm)) > 0) + else if (streq(parm, "all") || (n = atoi(parm)) > 0) { - const int size = log_history_size (log); - const int start = (n ? n : size) - 1; - int i; + const int size = log_history_size(log); + const int start = (n ? n : size) - 1; + int i; - for (i = start; i >= 0; --i) - { - const struct log_entry *e = log_history_ref (log, i); - if (e) - { - const char *out = log_entry_print (e, lep_flags, &gc); - virtual_output_callback_func (man, M_CLIENT, out); - } - } - msg (M_CLIENT, "END"); + for (i = start; i >= 0; --i) + { + const struct log_entry *e = log_history_ref(log, i); + if (e) + { + const char *out = log_entry_print(e, lep_flags, &gc); + virtual_output_callback_func(man, M_CLIENT, out); + } + } + msg(M_CLIENT, "END"); } - else + else { - msg (M_CLIENT, "ERROR: %s parameter must be 'on' or 'off' or some number n or 'all'", type); + msg(M_CLIENT, "ERROR: %s parameter must be 'on' or 'off' or some number n or 'all'", type); } - gc_free (&gc); + gc_free(&gc); } static void -man_log (struct management *man, const char *parm) +man_log(struct management *man, const char *parm) { - man_history (man, - parm, - "log", - man->persist.log, - &man->connection.log_realtime, - LOG_PRINT_INT_DATE|LOG_PRINT_MSG_FLAGS); + man_history(man, + parm, + "log", + man->persist.log, + &man->connection.log_realtime, + LOG_PRINT_INT_DATE|LOG_PRINT_MSG_FLAGS); } static void -man_echo (struct management *man, const char *parm) +man_echo(struct management *man, const char *parm) { - man_history (man, - parm, - "echo", - man->persist.echo, - &man->connection.echo_realtime, - LOG_PRINT_INT_DATE|MANAGEMENT_ECHO_FLAGS); + man_history(man, + parm, + "echo", + man->persist.echo, + &man->connection.echo_realtime, + LOG_PRINT_INT_DATE|MANAGEMENT_ECHO_FLAGS); } static void -man_state (struct management *man, const char *parm) +man_state(struct management *man, const char *parm) { - man_history (man, - parm, - "state", - man->persist.state, - &man->connection.state_realtime, - LOG_PRINT_INT_DATE|LOG_PRINT_STATE| - LOG_PRINT_LOCAL_IP|LOG_PRINT_REMOTE_IP); + man_history(man, + parm, + "state", + man->persist.state, + &man->connection.state_realtime, + LOG_PRINT_INT_DATE|LOG_PRINT_STATE + |LOG_PRINT_LOCAL_IP|LOG_PRINT_REMOTE_IP); } static void -man_up_finalize (struct management *man) +man_up_finalize(struct management *man) { - switch (man->connection.up_query_mode) + switch (man->connection.up_query_mode) { - case UP_QUERY_USER_PASS: - if (!strlen (man->connection.up_query.username)) - break; - /* fall through */ - case UP_QUERY_PASS: - case UP_QUERY_NEED_OK: - case UP_QUERY_NEED_STR: - if (strlen (man->connection.up_query.password)) - man->connection.up_query.defined = true; - break; - case UP_QUERY_DISABLED: - man->connection.up_query.defined = false; - break; - default: - ASSERT (0); + case UP_QUERY_USER_PASS: + if (!strlen(man->connection.up_query.username)) + { + break; + } + + /* fall through */ + case UP_QUERY_PASS: + case UP_QUERY_NEED_OK: + case UP_QUERY_NEED_STR: + if (strlen(man->connection.up_query.password)) + { + man->connection.up_query.defined = true; + } + break; + + case UP_QUERY_DISABLED: + man->connection.up_query.defined = false; + break; + + default: + ASSERT(0); } } static void -man_query_user_pass (struct management *man, - const char *type, - const char *string, - const bool needed, - const char *prompt, - char *dest, - int len) +man_query_user_pass(struct management *man, + const char *type, + const char *string, + const bool needed, + const char *prompt, + char *dest, + int len) { - if (needed) + if (needed) { - ASSERT (man->connection.up_query_type); - if (streq (man->connection.up_query_type, type)) - { - strncpynt (dest, string, len); - man_up_finalize (man); - msg (M_CLIENT, "SUCCESS: '%s' %s entered, but not yet verified", - type, - prompt); - } - else - msg (M_CLIENT, "ERROR: %s of type '%s' entered, but we need one of type '%s'", - prompt, - type, - man->connection.up_query_type); + ASSERT(man->connection.up_query_type); + if (streq(man->connection.up_query_type, type)) + { + strncpynt(dest, string, len); + man_up_finalize(man); + msg(M_CLIENT, "SUCCESS: '%s' %s entered, but not yet verified", + type, + prompt); + } + else + { + msg(M_CLIENT, "ERROR: %s of type '%s' entered, but we need one of type '%s'", + prompt, + type, + man->connection.up_query_type); + } } - else + else { - msg (M_CLIENT, "ERROR: no %s is currently needed at this time", prompt); + msg(M_CLIENT, "ERROR: no %s is currently needed at this time", prompt); } } static void -man_query_username (struct management *man, const char *type, const char *string) +man_query_username(struct management *man, const char *type, const char *string) { - const bool needed = ((man->connection.up_query_mode == UP_QUERY_USER_PASS - ) && man->connection.up_query_type); - man_query_user_pass (man, type, string, needed, "username", man->connection.up_query.username, USER_PASS_LEN); + const bool needed = ((man->connection.up_query_mode == UP_QUERY_USER_PASS + ) && man->connection.up_query_type); + man_query_user_pass(man, type, string, needed, "username", man->connection.up_query.username, USER_PASS_LEN); } static void -man_query_password (struct management *man, const char *type, const char *string) +man_query_password(struct management *man, const char *type, const char *string) { - const bool needed = ((man->connection.up_query_mode == UP_QUERY_PASS - || man->connection.up_query_mode == UP_QUERY_USER_PASS - ) && man->connection.up_query_type); - if (!string[0]) /* allow blank passwords to be passed through using the blank_up tag */ - string = blank_up; - man_query_user_pass (man, type, string, needed, "password", man->connection.up_query.password, USER_PASS_LEN); + const bool needed = ((man->connection.up_query_mode == UP_QUERY_PASS + || man->connection.up_query_mode == UP_QUERY_USER_PASS + ) && man->connection.up_query_type); + if (!string[0]) /* allow blank passwords to be passed through using the blank_up tag */ + { + string = blank_up; + } + man_query_user_pass(man, type, string, needed, "password", man->connection.up_query.password, USER_PASS_LEN); } static void -man_query_need_ok (struct management *man, const char *type, const char *action) +man_query_need_ok(struct management *man, const char *type, const char *action) { - const bool needed = ((man->connection.up_query_mode == UP_QUERY_NEED_OK) && man->connection.up_query_type); - man_query_user_pass (man, type, action, needed, "needok-confirmation", man->connection.up_query.password, USER_PASS_LEN); + const bool needed = ((man->connection.up_query_mode == UP_QUERY_NEED_OK) && man->connection.up_query_type); + man_query_user_pass(man, type, action, needed, "needok-confirmation", man->connection.up_query.password, USER_PASS_LEN); } static void -man_query_need_str (struct management *man, const char *type, const char *action) +man_query_need_str(struct management *man, const char *type, const char *action) { - const bool needed = ((man->connection.up_query_mode == UP_QUERY_NEED_STR) && man->connection.up_query_type); - man_query_user_pass (man, type, action, needed, "needstr-string", man->connection.up_query.password, USER_PASS_LEN); + const bool needed = ((man->connection.up_query_mode == UP_QUERY_NEED_STR) && man->connection.up_query_type); + man_query_user_pass(man, type, action, needed, "needstr-string", man->connection.up_query.password, USER_PASS_LEN); } static void -man_forget_passwords (struct management *man) +man_forget_passwords(struct management *man) { #ifdef ENABLE_CRYPTO - ssl_purge_auth (false); - msg (M_CLIENT, "SUCCESS: Passwords were forgotten"); + ssl_purge_auth(false); + msg(M_CLIENT, "SUCCESS: Passwords were forgotten"); #endif } static void -man_net (struct management *man) +man_net(struct management *man) { - if (man->persist.callback.show_net) + if (man->persist.callback.show_net) { - (*man->persist.callback.show_net) (man->persist.callback.arg, M_CLIENT); + (*man->persist.callback.show_net)(man->persist.callback.arg, M_CLIENT); } - else + else { - msg (M_CLIENT, "ERROR: The 'net' command is not supported by the current daemon mode"); + msg(M_CLIENT, "ERROR: The 'net' command is not supported by the current daemon mode"); } } #ifdef ENABLE_PKCS11 static void -man_pkcs11_id_count (struct management *man) +man_pkcs11_id_count(struct management *man) { - msg (M_CLIENT, ">PKCS11ID-COUNT:%d", pkcs11_management_id_count ()); + msg(M_CLIENT, ">PKCS11ID-COUNT:%d", pkcs11_management_id_count()); } static void -man_pkcs11_id_get (struct management *man, const int index) +man_pkcs11_id_get(struct management *man, const int index) { - char *id = NULL; - char *base64 = NULL; + char *id = NULL; + char *base64 = NULL; - if (pkcs11_management_id_get (index, &id, &base64)) - msg (M_CLIENT, ">PKCS11ID-ENTRY:'%d', ID:'%s', BLOB:'%s'", index, id, base64); - else - msg (M_CLIENT, ">PKCS11ID-ENTRY:'%d'", index); + if (pkcs11_management_id_get(index, &id, &base64)) + { + msg(M_CLIENT, ">PKCS11ID-ENTRY:'%d', ID:'%s', BLOB:'%s'", index, id, base64); + } + else + { + msg(M_CLIENT, ">PKCS11ID-ENTRY:'%d'", index); + } - if (id != NULL) - free (id); - if (base64 != NULL) - free (base64); + if (id != NULL) + { + free(id); + } + if (base64 != NULL) + { + free(base64); + } } -#endif +#endif /* ifdef ENABLE_PKCS11 */ static void -man_hold (struct management *man, const char *cmd) +man_hold(struct management *man, const char *cmd) { - if (cmd) + if (cmd) { - if (streq (cmd, "on")) - { - man->settings.flags |= MF_HOLD; - msg (M_CLIENT, "SUCCESS: hold flag set to ON"); - } - else if (streq (cmd, "off")) - { - man->settings.flags &= ~MF_HOLD; - msg (M_CLIENT, "SUCCESS: hold flag set to OFF"); - } - else if (streq (cmd, "release")) - { - man->persist.hold_release = true; - msg (M_CLIENT, "SUCCESS: hold release succeeded"); - } - else - { - msg (M_CLIENT, "ERROR: bad hold command parameter"); - } + if (streq(cmd, "on")) + { + man->settings.flags |= MF_HOLD; + msg(M_CLIENT, "SUCCESS: hold flag set to ON"); + } + else if (streq(cmd, "off")) + { + man->settings.flags &= ~MF_HOLD; + msg(M_CLIENT, "SUCCESS: hold flag set to OFF"); + } + else if (streq(cmd, "release")) + { + man->persist.hold_release = true; + msg(M_CLIENT, "SUCCESS: hold release succeeded"); + } + else + { + msg(M_CLIENT, "ERROR: bad hold command parameter"); + } + } + else + { + msg(M_CLIENT, "SUCCESS: hold=%d", BOOL_CAST(man->settings.flags & MF_HOLD)); } - else - msg (M_CLIENT, "SUCCESS: hold=%d", BOOL_CAST(man->settings.flags & MF_HOLD)); } #ifdef MANAGEMENT_IN_EXTRA @@ -784,101 +854,106 @@ man_hold (struct management *man, const char *cmd) #define IER_NEW 1 static void -in_extra_reset (struct man_connection *mc, const int mode) +in_extra_reset(struct man_connection *mc, const int mode) { - if (mc) + if (mc) { - if (mode != IER_NEW) - { - mc->in_extra_cmd = IEC_UNDEF; + if (mode != IER_NEW) + { + mc->in_extra_cmd = IEC_UNDEF; #ifdef MANAGEMENT_DEF_AUTH - mc->in_extra_cid = 0; - mc->in_extra_kid = 0; + mc->in_extra_cid = 0; + mc->in_extra_kid = 0; #endif - } - if (mc->in_extra) - { - buffer_list_free (mc->in_extra); - mc->in_extra = NULL; - } - if (mode == IER_NEW) - mc->in_extra = buffer_list_new (0); + } + if (mc->in_extra) + { + buffer_list_free(mc->in_extra); + mc->in_extra = NULL; + } + if (mode == IER_NEW) + { + mc->in_extra = buffer_list_new(0); + } } } static void -in_extra_dispatch (struct management *man) +in_extra_dispatch(struct management *man) { - switch (man->connection.in_extra_cmd) + switch (man->connection.in_extra_cmd) { #ifdef MANAGEMENT_DEF_AUTH - case IEC_CLIENT_AUTH: - if (man->persist.callback.client_auth) - { - const bool status = (*man->persist.callback.client_auth) - (man->persist.callback.arg, - man->connection.in_extra_cid, - man->connection.in_extra_kid, - true, - NULL, - NULL, - man->connection.in_extra); - man->connection.in_extra = NULL; - if (status) - { - msg (M_CLIENT, "SUCCESS: client-auth command succeeded"); - } - else - { - msg (M_CLIENT, "ERROR: client-auth command failed"); - } - } - else - { - msg (M_CLIENT, "ERROR: The client-auth command is not supported by the current daemon mode"); - } - break; -#endif + case IEC_CLIENT_AUTH: + if (man->persist.callback.client_auth) + { + const bool status = (*man->persist.callback.client_auth) + (man->persist.callback.arg, + man->connection.in_extra_cid, + man->connection.in_extra_kid, + true, + NULL, + NULL, + man->connection.in_extra); + man->connection.in_extra = NULL; + if (status) + { + msg(M_CLIENT, "SUCCESS: client-auth command succeeded"); + } + else + { + msg(M_CLIENT, "ERROR: client-auth command failed"); + } + } + else + { + msg(M_CLIENT, "ERROR: The client-auth command is not supported by the current daemon mode"); + } + break; + +#endif /* ifdef MANAGEMENT_DEF_AUTH */ #ifdef MANAGEMENT_PF - case IEC_CLIENT_PF: - if (man->persist.callback.client_pf) - { - const bool status = (*man->persist.callback.client_pf) - (man->persist.callback.arg, - man->connection.in_extra_cid, - man->connection.in_extra); - man->connection.in_extra = NULL; - if (status) - { - msg (M_CLIENT, "SUCCESS: client-pf command succeeded"); - } - else - { - msg (M_CLIENT, "ERROR: client-pf command failed"); - } - } - else - { - msg (M_CLIENT, "ERROR: The client-pf command is not supported by the current daemon mode"); - } - break; -#endif + case IEC_CLIENT_PF: + if (man->persist.callback.client_pf) + { + const bool status = (*man->persist.callback.client_pf) + (man->persist.callback.arg, + man->connection.in_extra_cid, + man->connection.in_extra); + man->connection.in_extra = NULL; + if (status) + { + msg(M_CLIENT, "SUCCESS: client-pf command succeeded"); + } + else + { + msg(M_CLIENT, "ERROR: client-pf command failed"); + } + } + else + { + msg(M_CLIENT, "ERROR: The client-pf command is not supported by the current daemon mode"); + } + break; + +#endif /* ifdef MANAGEMENT_PF */ #ifdef MANAGMENT_EXTERNAL_KEY - case IEC_RSA_SIGN: - man->connection.ext_key_state = EKS_READY; - buffer_list_free (man->connection.ext_key_input); - man->connection.ext_key_input = man->connection.in_extra; - man->connection.in_extra = NULL; - return; - case IEC_CERTIFICATE: - man->connection.ext_cert_state = EKS_READY; - buffer_list_free (man->connection.ext_cert_input); - man->connection.ext_cert_input = man->connection.in_extra; - man->connection.in_extra = NULL; - return; + case IEC_RSA_SIGN: + man->connection.ext_key_state = EKS_READY; + buffer_list_free(man->connection.ext_key_input); + man->connection.ext_key_input = man->connection.in_extra; + man->connection.in_extra = NULL; + return; + + case IEC_CERTIFICATE: + man->connection.ext_cert_state = EKS_READY; + buffer_list_free(man->connection.ext_cert_input); + man->connection.ext_cert_input = man->connection.in_extra; + man->connection.in_extra = NULL; + return; #endif } - in_extra_reset (&man->connection, IER_RESET); + in_extra_reset(&man->connection, IER_RESET); } #endif /* MANAGEMENT_IN_EXTRA */ @@ -886,136 +961,142 @@ in_extra_dispatch (struct management *man) #ifdef MANAGEMENT_DEF_AUTH static bool -parse_cid (const char *str, unsigned long *cid) +parse_cid(const char *str, unsigned long *cid) { - if (sscanf (str, "%lu", cid) == 1) - return true; - else + if (sscanf(str, "%lu", cid) == 1) + { + return true; + } + else { - msg (M_CLIENT, "ERROR: cannot parse CID"); - return false; + msg(M_CLIENT, "ERROR: cannot parse CID"); + return false; } } static bool -parse_kid (const char *str, unsigned int *kid) +parse_kid(const char *str, unsigned int *kid) { - if (sscanf (str, "%u", kid) == 1) - return true; - else + if (sscanf(str, "%u", kid) == 1) + { + return true; + } + else { - msg (M_CLIENT, "ERROR: cannot parse KID"); - return false; + msg(M_CLIENT, "ERROR: cannot parse KID"); + return false; } } static void -man_client_auth (struct management *man, const char *cid_str, const char *kid_str, const bool extra) +man_client_auth(struct management *man, const char *cid_str, const char *kid_str, const bool extra) { - struct man_connection *mc = &man->connection; - mc->in_extra_cid = 0; - mc->in_extra_kid = 0; - if (parse_cid (cid_str, &mc->in_extra_cid) - && parse_kid (kid_str, &mc->in_extra_kid)) + struct man_connection *mc = &man->connection; + mc->in_extra_cid = 0; + mc->in_extra_kid = 0; + if (parse_cid(cid_str, &mc->in_extra_cid) + && parse_kid(kid_str, &mc->in_extra_kid)) { - mc->in_extra_cmd = IEC_CLIENT_AUTH; - in_extra_reset (mc, IER_NEW); - if (!extra) - in_extra_dispatch (man); + mc->in_extra_cmd = IEC_CLIENT_AUTH; + in_extra_reset(mc, IER_NEW); + if (!extra) + { + in_extra_dispatch(man); + } } } static void -man_client_deny (struct management *man, const char *cid_str, const char *kid_str, const char *reason, const char *client_reason) +man_client_deny(struct management *man, const char *cid_str, const char *kid_str, const char *reason, const char *client_reason) { - unsigned long cid = 0; - unsigned int kid = 0; - if (parse_cid (cid_str, &cid) && parse_kid (kid_str, &kid)) + unsigned long cid = 0; + unsigned int kid = 0; + if (parse_cid(cid_str, &cid) && parse_kid(kid_str, &kid)) { - if (man->persist.callback.client_auth) - { - const bool status = (*man->persist.callback.client_auth) - (man->persist.callback.arg, - cid, - kid, - false, - reason, - client_reason, - NULL); - if (status) - { - msg (M_CLIENT, "SUCCESS: client-deny command succeeded"); - } - else - { - msg (M_CLIENT, "ERROR: client-deny command failed"); - } - } - else - { - msg (M_CLIENT, "ERROR: The client-deny command is not supported by the current daemon mode"); - } + if (man->persist.callback.client_auth) + { + const bool status = (*man->persist.callback.client_auth) + (man->persist.callback.arg, + cid, + kid, + false, + reason, + client_reason, + NULL); + if (status) + { + msg(M_CLIENT, "SUCCESS: client-deny command succeeded"); + } + else + { + msg(M_CLIENT, "ERROR: client-deny command failed"); + } + } + else + { + msg(M_CLIENT, "ERROR: The client-deny command is not supported by the current daemon mode"); + } } } static void -man_client_kill (struct management *man, const char *cid_str, const char *kill_msg) +man_client_kill(struct management *man, const char *cid_str, const char *kill_msg) { - unsigned long cid = 0; - if (parse_cid (cid_str, &cid)) + unsigned long cid = 0; + if (parse_cid(cid_str, &cid)) { - if (man->persist.callback.kill_by_cid) - { - const bool status = (*man->persist.callback.kill_by_cid) (man->persist.callback.arg, cid, kill_msg); - if (status) - { - msg (M_CLIENT, "SUCCESS: client-kill command succeeded"); - } - else - { - msg (M_CLIENT, "ERROR: client-kill command failed"); - } - } - else - { - msg (M_CLIENT, "ERROR: The client-kill command is not supported by the current daemon mode"); - } + if (man->persist.callback.kill_by_cid) + { + const bool status = (*man->persist.callback.kill_by_cid)(man->persist.callback.arg, cid, kill_msg); + if (status) + { + msg(M_CLIENT, "SUCCESS: client-kill command succeeded"); + } + else + { + msg(M_CLIENT, "ERROR: client-kill command failed"); + } + } + else + { + msg(M_CLIENT, "ERROR: The client-kill command is not supported by the current daemon mode"); + } } } static void -man_client_n_clients (struct management *man) +man_client_n_clients(struct management *man) { - if (man->persist.callback.n_clients) + if (man->persist.callback.n_clients) { - const int nclients = (*man->persist.callback.n_clients) (man->persist.callback.arg); - msg (M_CLIENT, "SUCCESS: nclients=%d", nclients); + const int nclients = (*man->persist.callback.n_clients)(man->persist.callback.arg); + msg(M_CLIENT, "SUCCESS: nclients=%d", nclients); } - else + else { - msg (M_CLIENT, "ERROR: The nclients command is not supported by the current daemon mode"); + msg(M_CLIENT, "ERROR: The nclients command is not supported by the current daemon mode"); } } static void -man_env_filter (struct management *man, const int level) +man_env_filter(struct management *man, const int level) { - man->connection.env_filter_level = level; - msg (M_CLIENT, "SUCCESS: env_filter_level=%d", level); + man->connection.env_filter_level = level; + msg(M_CLIENT, "SUCCESS: env_filter_level=%d", level); } #ifdef MANAGEMENT_PF static void -man_client_pf (struct management *man, const char *cid_str) +man_client_pf(struct management *man, const char *cid_str) { - struct man_connection *mc = &man->connection; - mc->in_extra_cid = 0; - mc->in_extra_kid = 0; - if (parse_cid (cid_str, &mc->in_extra_cid)) + struct man_connection *mc = &man->connection; + mc->in_extra_cid = 0; + mc->in_extra_kid = 0; + if (parse_cid(cid_str, &mc->in_extra_cid)) { - mc->in_extra_cmd = IEC_CLIENT_PF; - in_extra_reset (mc, IER_NEW); + mc->in_extra_cmd = IEC_CLIENT_PF; + in_extra_reset(mc, IER_NEW); } } @@ -1025,899 +1106,1015 @@ man_client_pf (struct management *man, const char *cid_str) #ifdef MANAGMENT_EXTERNAL_KEY static void -man_rsa_sig (struct management *man) +man_rsa_sig(struct management *man) { - struct man_connection *mc = &man->connection; - if (mc->ext_key_state == EKS_SOLICIT) + struct man_connection *mc = &man->connection; + if (mc->ext_key_state == EKS_SOLICIT) { - mc->ext_key_state = EKS_INPUT; - mc->in_extra_cmd = IEC_RSA_SIGN; - in_extra_reset (mc, IER_NEW); + mc->ext_key_state = EKS_INPUT; + mc->in_extra_cmd = IEC_RSA_SIGN; + in_extra_reset(mc, IER_NEW); + } + else + { + msg(M_CLIENT, "ERROR: The rsa-sig command is not currently available"); } - else - msg (M_CLIENT, "ERROR: The rsa-sig command is not currently available"); } static void -man_certificate (struct management *man) +man_certificate(struct management *man) { - struct man_connection *mc = &man->connection; - if (mc->ext_cert_state == EKS_SOLICIT) + struct man_connection *mc = &man->connection; + if (mc->ext_cert_state == EKS_SOLICIT) + { + mc->ext_cert_state = EKS_INPUT; + mc->in_extra_cmd = IEC_CERTIFICATE; + in_extra_reset(mc, IER_NEW); + } + else { - mc->ext_cert_state = EKS_INPUT; - mc->in_extra_cmd = IEC_CERTIFICATE; - in_extra_reset (mc, IER_NEW); + msg(M_CLIENT, "ERROR: The certificate command is not currently available"); } - else - msg (M_CLIENT, "ERROR: The certificate command is not currently available"); } -#endif +#endif /* ifdef MANAGMENT_EXTERNAL_KEY */ static void -man_load_stats (struct management *man) +man_load_stats(struct management *man) { - extern counter_type link_read_bytes_global; - extern counter_type link_write_bytes_global; - int nclients = 0; + extern counter_type link_read_bytes_global; + extern counter_type link_write_bytes_global; + int nclients = 0; - if (man->persist.callback.n_clients) - nclients = (*man->persist.callback.n_clients) (man->persist.callback.arg); - msg (M_CLIENT, "SUCCESS: nclients=%d,bytesin=" counter_format ",bytesout=" counter_format, - nclients, - link_read_bytes_global, - link_write_bytes_global); + if (man->persist.callback.n_clients) + { + nclients = (*man->persist.callback.n_clients)(man->persist.callback.arg); + } + msg(M_CLIENT, "SUCCESS: nclients=%d,bytesin=" counter_format ",bytesout=" counter_format, + nclients, + link_read_bytes_global, + link_write_bytes_global); } #define MN_AT_LEAST (1<<0) static bool -man_need (struct management *man, const char **p, const int n, unsigned int flags) +man_need(struct management *man, const char **p, const int n, unsigned int flags) { - int i; - ASSERT (p[0]); - for (i = 1; i <= n; ++i) + int i; + ASSERT(p[0]); + for (i = 1; i <= n; ++i) { - if (!p[i]) - { - msg (M_CLIENT, "ERROR: the '%s' command requires %s%d parameter%s", - p[0], - (flags & MN_AT_LEAST) ? "at least " : "", - n, - n > 1 ? "s" : ""); - return false; - } + if (!p[i]) + { + msg(M_CLIENT, "ERROR: the '%s' command requires %s%d parameter%s", + p[0], + (flags & MN_AT_LEAST) ? "at least " : "", + n, + n > 1 ? "s" : ""); + return false; + } } - return true; + return true; } static void -man_proxy (struct management *man, const char **p) +man_proxy(struct management *man, const char **p) { - if (man->persist.callback.proxy_cmd) + if (man->persist.callback.proxy_cmd) + { + const bool status = (*man->persist.callback.proxy_cmd)(man->persist.callback.arg, p); + if (status) + { + msg(M_CLIENT, "SUCCESS: proxy command succeeded"); + } + else + { + msg(M_CLIENT, "ERROR: proxy command failed"); + } + } + else { - const bool status = (*man->persist.callback.proxy_cmd)(man->persist.callback.arg, p); - if (status) - msg (M_CLIENT, "SUCCESS: proxy command succeeded"); - else - msg (M_CLIENT, "ERROR: proxy command failed"); + msg(M_CLIENT, "ERROR: The proxy command is not supported by the current daemon mode"); } - else - msg (M_CLIENT, "ERROR: The proxy command is not supported by the current daemon mode"); } static void -man_remote (struct management *man, const char **p) +man_remote(struct management *man, const char **p) { - if (man->persist.callback.remote_cmd) + if (man->persist.callback.remote_cmd) { - const bool status = (*man->persist.callback.remote_cmd)(man->persist.callback.arg, p); - if (status) - { - msg (M_CLIENT, "SUCCESS: remote command succeeded"); - } - else - { - msg (M_CLIENT, "ERROR: remote command failed"); - } + const bool status = (*man->persist.callback.remote_cmd)(man->persist.callback.arg, p); + if (status) + { + msg(M_CLIENT, "SUCCESS: remote command succeeded"); + } + else + { + msg(M_CLIENT, "ERROR: remote command failed"); + } } - else + else { - msg (M_CLIENT, "ERROR: The remote command is not supported by the current daemon mode"); + msg(M_CLIENT, "ERROR: The remote command is not supported by the current daemon mode"); } } #ifdef TARGET_ANDROID static void -man_network_change (struct management *man, bool samenetwork) +man_network_change(struct management *man, bool samenetwork) { - /* Called to signal the OpenVPN that the network configuration has changed and - the client should either float or reconnect. - - The code is currently only used by ics-openvpn - */ - if (man->persist.callback.network_change) + /* Called to signal the OpenVPN that the network configuration has changed and + * the client should either float or reconnect. + * + * The code is currently only used by ics-openvpn + */ + if (man->persist.callback.network_change) { - int fd = (*man->persist.callback.network_change) - (man->persist.callback.arg, samenetwork); - man->connection.fdtosend = fd; - msg (M_CLIENT, "PROTECTFD: fd '%d' sent to be protected", fd); - if (fd == -2) - man_signal (man, "SIGUSR1"); + int fd = (*man->persist.callback.network_change) + (man->persist.callback.arg, samenetwork); + man->connection.fdtosend = fd; + msg(M_CLIENT, "PROTECTFD: fd '%d' sent to be protected", fd); + if (fd == -2) + { + man_signal(man, "SIGUSR1"); + } } } #endif static void -man_dispatch_command (struct management *man, struct status_output *so, const char **p, const int nparms) +man_dispatch_command(struct management *man, struct status_output *so, const char **p, const int nparms) { - struct gc_arena gc = gc_new (); + struct gc_arena gc = gc_new(); - ASSERT (p[0]); - if (streq (p[0], "exit") || streq (p[0], "quit")) + ASSERT(p[0]); + if (streq(p[0], "exit") || streq(p[0], "quit")) { - man->connection.halt = true; - goto done; + man->connection.halt = true; + goto done; } - else if (streq (p[0], "help")) + else if (streq(p[0], "help")) { - man_help (); + man_help(); } - else if (streq (p[0], "version")) + else if (streq(p[0], "version")) { - msg (M_CLIENT, "OpenVPN Version: %s", title_string); - msg (M_CLIENT, "Management Version: %d", MANAGEMENT_VERSION); - msg (M_CLIENT, "END"); + msg(M_CLIENT, "OpenVPN Version: %s", title_string); + msg(M_CLIENT, "Management Version: %d", MANAGEMENT_VERSION); + msg(M_CLIENT, "END"); } - else if (streq (p[0], "pid")) + else if (streq(p[0], "pid")) { - msg (M_CLIENT, "SUCCESS: pid=%d", platform_getpid ()); + msg(M_CLIENT, "SUCCESS: pid=%d", platform_getpid()); } #ifdef MANAGEMENT_DEF_AUTH - else if (streq (p[0], "nclients")) + else if (streq(p[0], "nclients")) { - man_client_n_clients (man); + man_client_n_clients(man); } - else if (streq (p[0], "env-filter")) + else if (streq(p[0], "env-filter")) { - int level = 0; - if (p[1]) - level = atoi (p[1]); - man_env_filter (man, level); + int level = 0; + if (p[1]) + { + level = atoi(p[1]); + } + man_env_filter(man, level); } #endif - else if (streq (p[0], "signal")) + else if (streq(p[0], "signal")) { - if (man_need (man, p, 1, 0)) - man_signal (man, p[1]); + if (man_need(man, p, 1, 0)) + { + man_signal(man, p[1]); + } } #ifdef TARGET_ANDROID - else if (streq (p[0], "network-change")) + else if (streq(p[0], "network-change")) { - bool samenetwork = false; - if (p[1] && streq(p[1], "samenetwork")) - samenetwork = true; + bool samenetwork = false; + if (p[1] && streq(p[1], "samenetwork")) + { + samenetwork = true; + } - man_network_change(man, samenetwork); + man_network_change(man, samenetwork); } #endif - else if (streq (p[0], "load-stats")) + else if (streq(p[0], "load-stats")) { - man_load_stats (man); + man_load_stats(man); } - else if (streq (p[0], "status")) + else if (streq(p[0], "status")) { - int version = 0; - if (p[1]) - version = atoi (p[1]); - man_status (man, version, so); + int version = 0; + if (p[1]) + { + version = atoi(p[1]); + } + man_status(man, version, so); } - else if (streq (p[0], "kill")) + else if (streq(p[0], "kill")) { - if (man_need (man, p, 1, 0)) - man_kill (man, p[1]); + if (man_need(man, p, 1, 0)) + { + man_kill(man, p[1]); + } } - else if (streq (p[0], "verb")) + else if (streq(p[0], "verb")) { - if (p[1]) - { - const int level = atoi(p[1]); - if (set_debug_level (level, 0)) - msg (M_CLIENT, "SUCCESS: verb level changed"); - else - msg (M_CLIENT, "ERROR: verb level is out of range"); - } - else - msg (M_CLIENT, "SUCCESS: verb=%d", get_debug_level ()); + if (p[1]) + { + const int level = atoi(p[1]); + if (set_debug_level(level, 0)) + { + msg(M_CLIENT, "SUCCESS: verb level changed"); + } + else + { + msg(M_CLIENT, "ERROR: verb level is out of range"); + } + } + else + { + msg(M_CLIENT, "SUCCESS: verb=%d", get_debug_level()); + } } - else if (streq (p[0], "mute")) + else if (streq(p[0], "mute")) { - if (p[1]) - { - const int level = atoi(p[1]); - if (set_mute_cutoff (level)) - msg (M_CLIENT, "SUCCESS: mute level changed"); - else - msg (M_CLIENT, "ERROR: mute level is out of range"); - } - else - msg (M_CLIENT, "SUCCESS: mute=%d", get_mute_cutoff ()); + if (p[1]) + { + const int level = atoi(p[1]); + if (set_mute_cutoff(level)) + { + msg(M_CLIENT, "SUCCESS: mute level changed"); + } + else + { + msg(M_CLIENT, "ERROR: mute level is out of range"); + } + } + else + { + msg(M_CLIENT, "SUCCESS: mute=%d", get_mute_cutoff()); + } } - else if (streq (p[0], "auth-retry")) + else if (streq(p[0], "auth-retry")) { #if P2MP - if (p[1]) - { - if (auth_retry_set (M_CLIENT, p[1])) - msg (M_CLIENT, "SUCCESS: auth-retry parameter changed"); - else - msg (M_CLIENT, "ERROR: bad auth-retry parameter"); - } - else - msg (M_CLIENT, "SUCCESS: auth-retry=%s", auth_retry_print ()); -#else - msg (M_CLIENT, "ERROR: auth-retry feature is unavailable"); + if (p[1]) + { + if (auth_retry_set(M_CLIENT, p[1])) + { + msg(M_CLIENT, "SUCCESS: auth-retry parameter changed"); + } + else + { + msg(M_CLIENT, "ERROR: bad auth-retry parameter"); + } + } + else + { + msg(M_CLIENT, "SUCCESS: auth-retry=%s", auth_retry_print()); + } +#else /* if P2MP */ + msg(M_CLIENT, "ERROR: auth-retry feature is unavailable"); #endif } - else if (streq (p[0], "state")) - { - if (!p[1]) - { - man_state (man, "1"); - } - else - { - if (p[1]) - man_state (man, p[1]); - if (p[2]) - man_state (man, p[2]); - } - } - else if (streq (p[0], "log")) + else if (streq(p[0], "state")) { - if (man_need (man, p, 1, MN_AT_LEAST)) - { - if (p[1]) - man_log (man, p[1]); - if (p[2]) - man_log (man, p[2]); - } - } - else if (streq (p[0], "echo")) - { - if (man_need (man, p, 1, MN_AT_LEAST)) - { - if (p[1]) - man_echo (man, p[1]); - if (p[2]) - man_echo (man, p[2]); - } - } - else if (streq (p[0], "username")) - { - if (man_need (man, p, 2, 0)) - man_query_username (man, p[1], p[2]); + if (!p[1]) + { + man_state(man, "1"); + } + else + { + if (p[1]) + { + man_state(man, p[1]); + } + if (p[2]) + { + man_state(man, p[2]); + } + } + } + else if (streq(p[0], "log")) + { + if (man_need(man, p, 1, MN_AT_LEAST)) + { + if (p[1]) + { + man_log(man, p[1]); + } + if (p[2]) + { + man_log(man, p[2]); + } + } + } + else if (streq(p[0], "echo")) + { + if (man_need(man, p, 1, MN_AT_LEAST)) + { + if (p[1]) + { + man_echo(man, p[1]); + } + if (p[2]) + { + man_echo(man, p[2]); + } + } + } + else if (streq(p[0], "username")) + { + if (man_need(man, p, 2, 0)) + { + man_query_username(man, p[1], p[2]); + } } - else if (streq (p[0], "password")) + else if (streq(p[0], "password")) { - if (man_need (man, p, 2, 0)) - man_query_password (man, p[1], p[2]); + if (man_need(man, p, 2, 0)) + { + man_query_password(man, p[1], p[2]); + } } - else if (streq (p[0], "forget-passwords")) + else if (streq(p[0], "forget-passwords")) { - man_forget_passwords (man); + man_forget_passwords(man); } - else if (streq (p[0], "needok")) + else if (streq(p[0], "needok")) { - if (man_need (man, p, 2, 0)) - man_query_need_ok (man, p[1], p[2]); + if (man_need(man, p, 2, 0)) + { + man_query_need_ok(man, p[1], p[2]); + } } - else if (streq (p[0], "needstr")) + else if (streq(p[0], "needstr")) { - if (man_need (man, p, 2, 0)) - man_query_need_str (man, p[1], p[2]); + if (man_need(man, p, 2, 0)) + { + man_query_need_str(man, p[1], p[2]); + } } - else if (streq (p[0], "net")) + else if (streq(p[0], "net")) { - man_net (man); + man_net(man); } - else if (streq (p[0], "hold")) + else if (streq(p[0], "hold")) { - man_hold (man, p[1]); + man_hold(man, p[1]); } - else if (streq (p[0], "bytecount")) + else if (streq(p[0], "bytecount")) { - if (man_need (man, p, 1, 0)) - man_bytecount (man, atoi(p[1])); + if (man_need(man, p, 1, 0)) + { + man_bytecount(man, atoi(p[1])); + } } #ifdef MANAGEMENT_DEF_AUTH - else if (streq (p[0], "client-kill")) + else if (streq(p[0], "client-kill")) { - if (man_need (man, p, 1, MN_AT_LEAST)) - man_client_kill (man, p[1], p[2]); + if (man_need(man, p, 1, MN_AT_LEAST)) + { + man_client_kill(man, p[1], p[2]); + } } - else if (streq (p[0], "client-deny")) + else if (streq(p[0], "client-deny")) { - if (man_need (man, p, 3, MN_AT_LEAST)) - man_client_deny (man, p[1], p[2], p[3], p[4]); + if (man_need(man, p, 3, MN_AT_LEAST)) + { + man_client_deny(man, p[1], p[2], p[3], p[4]); + } } - else if (streq (p[0], "client-auth-nt")) + else if (streq(p[0], "client-auth-nt")) { - if (man_need (man, p, 2, 0)) - man_client_auth (man, p[1], p[2], false); + if (man_need(man, p, 2, 0)) + { + man_client_auth(man, p[1], p[2], false); + } } - else if (streq (p[0], "client-auth")) + else if (streq(p[0], "client-auth")) { - if (man_need (man, p, 2, 0)) - man_client_auth (man, p[1], p[2], true); + if (man_need(man, p, 2, 0)) + { + man_client_auth(man, p[1], p[2], true); + } } #ifdef MANAGEMENT_PF - else if (streq (p[0], "client-pf")) + else if (streq(p[0], "client-pf")) { - if (man_need (man, p, 1, 0)) - man_client_pf (man, p[1]); + if (man_need(man, p, 1, 0)) + { + man_client_pf(man, p[1]); + } } #endif -#endif +#endif /* ifdef MANAGEMENT_DEF_AUTH */ #ifdef MANAGMENT_EXTERNAL_KEY - else if (streq (p[0], "rsa-sig")) + else if (streq(p[0], "rsa-sig")) { - man_rsa_sig (man); + man_rsa_sig(man); } - else if (streq (p[0], "certificate")) + else if (streq(p[0], "certificate")) { - man_certificate (man); + man_certificate(man); } #endif #ifdef ENABLE_PKCS11 - else if (streq (p[0], "pkcs11-id-count")) + else if (streq(p[0], "pkcs11-id-count")) { - man_pkcs11_id_count (man); + man_pkcs11_id_count(man); } - else if (streq (p[0], "pkcs11-id-get")) + else if (streq(p[0], "pkcs11-id-get")) { - if (man_need (man, p, 1, 0)) - man_pkcs11_id_get (man, atoi(p[1])); + if (man_need(man, p, 1, 0)) + { + man_pkcs11_id_get(man, atoi(p[1])); + } } #endif - else if (streq (p[0], "proxy")) + else if (streq(p[0], "proxy")) { - if (man_need (man, p, 1, MN_AT_LEAST)) - man_proxy (man, p); + if (man_need(man, p, 1, MN_AT_LEAST)) + { + man_proxy(man, p); + } } - else if (streq (p[0], "remote")) + else if (streq(p[0], "remote")) { - if (man_need (man, p, 1, MN_AT_LEAST)) - man_remote (man, p); + if (man_need(man, p, 1, MN_AT_LEAST)) + { + man_remote(man, p); + } } #if 1 - else if (streq (p[0], "test")) - { - if (man_need (man, p, 1, 0)) - { - int i; - const int n = atoi (p[1]); - for (i = 0; i < n; ++i) - { - msg (M_CLIENT, "[%d] The purpose of this command is to generate large amounts of output.", i); - } - } + else if (streq(p[0], "test")) + { + if (man_need(man, p, 1, 0)) + { + int i; + const int n = atoi(p[1]); + for (i = 0; i < n; ++i) + { + msg(M_CLIENT, "[%d] The purpose of this command is to generate large amounts of output.", i); + } + } } #endif - else + else { - msg (M_CLIENT, "ERROR: unknown command, enter 'help' for more options"); + msg(M_CLIENT, "ERROR: unknown command, enter 'help' for more options"); } - done: - gc_free (&gc); +done: + gc_free(&gc); } #ifdef _WIN32 static void -man_start_ne32 (struct management *man) +man_start_ne32(struct management *man) { - switch (man->connection.state) + switch (man->connection.state) { - case MS_LISTEN: - net_event_win32_start (&man->connection.ne32, FD_ACCEPT, man->connection.sd_top); - break; - case MS_CC_WAIT_READ: - case MS_CC_WAIT_WRITE: - net_event_win32_start (&man->connection.ne32, FD_READ|FD_WRITE|FD_CLOSE, man->connection.sd_cli); - break; - default: - ASSERT (0); - } + case MS_LISTEN: + net_event_win32_start(&man->connection.ne32, FD_ACCEPT, man->connection.sd_top); + break; + + case MS_CC_WAIT_READ: + case MS_CC_WAIT_WRITE: + net_event_win32_start(&man->connection.ne32, FD_READ|FD_WRITE|FD_CLOSE, man->connection.sd_cli); + break; + + default: + ASSERT(0); + } } static void -man_stop_ne32 (struct management *man) +man_stop_ne32(struct management *man) { - net_event_win32_stop (&man->connection.ne32); + net_event_win32_stop(&man->connection.ne32); } -#endif +#endif /* ifdef _WIN32 */ static void -man_record_peer_info (struct management *man) +man_record_peer_info(struct management *man) { - struct gc_arena gc = gc_new (); - if (man->settings.write_peer_info_file) + struct gc_arena gc = gc_new(); + if (man->settings.write_peer_info_file) { - bool success = false; + bool success = false; #ifdef HAVE_GETSOCKNAME - if (socket_defined (man->connection.sd_cli)) - { - struct sockaddr_in addr; - socklen_t addrlen = sizeof (addr); - int status; - - CLEAR (addr); - status = getsockname (man->connection.sd_cli, (struct sockaddr *)&addr, &addrlen); - if (!status && addrlen == sizeof (addr)) - { - const in_addr_t a = ntohl (addr.sin_addr.s_addr); - const int p = ntohs (addr.sin_port); - FILE *fp = platform_fopen (man->settings.write_peer_info_file, "w"); - if (fp) - { - fprintf (fp, "%s\n%d\n", print_in_addr_t (a, 0, &gc), p); - if (!fclose (fp)) - success = true; - } - } - } -#endif - if (!success) - { - msg (D_MANAGEMENT, "MANAGEMENT: failed to write peer info to file %s", - man->settings.write_peer_info_file); - throw_signal_soft (SIGTERM, "management-connect-failed"); - } + if (socket_defined(man->connection.sd_cli)) + { + struct sockaddr_in addr; + socklen_t addrlen = sizeof(addr); + int status; + + CLEAR(addr); + status = getsockname(man->connection.sd_cli, (struct sockaddr *)&addr, &addrlen); + if (!status && addrlen == sizeof(addr)) + { + const in_addr_t a = ntohl(addr.sin_addr.s_addr); + const int p = ntohs(addr.sin_port); + FILE *fp = platform_fopen(man->settings.write_peer_info_file, "w"); + if (fp) + { + fprintf(fp, "%s\n%d\n", print_in_addr_t(a, 0, &gc), p); + if (!fclose(fp)) + { + success = true; + } + } + } + } +#endif /* ifdef HAVE_GETSOCKNAME */ + if (!success) + { + msg(D_MANAGEMENT, "MANAGEMENT: failed to write peer info to file %s", + man->settings.write_peer_info_file); + throw_signal_soft(SIGTERM, "management-connect-failed"); + } } - gc_free (&gc); + gc_free(&gc); } static void -man_connection_settings_reset (struct management *man) +man_connection_settings_reset(struct management *man) { - man->connection.state_realtime = false; - man->connection.log_realtime = false; - man->connection.echo_realtime = false; - man->connection.bytecount_update_seconds = 0; - man->connection.password_verified = false; - man->connection.password_tries = 0; - man->connection.halt = false; - man->connection.state = MS_CC_WAIT_WRITE; + man->connection.state_realtime = false; + man->connection.log_realtime = false; + man->connection.echo_realtime = false; + man->connection.bytecount_update_seconds = 0; + man->connection.password_verified = false; + man->connection.password_tries = 0; + man->connection.halt = false; + man->connection.state = MS_CC_WAIT_WRITE; } static void -man_new_connection_post (struct management *man, const char *description) +man_new_connection_post(struct management *man, const char *description) { - struct gc_arena gc = gc_new (); + struct gc_arena gc = gc_new(); - set_nonblock (man->connection.sd_cli); + set_nonblock(man->connection.sd_cli); - man_connection_settings_reset (man); + man_connection_settings_reset(man); #ifdef _WIN32 - man_start_ne32 (man); + man_start_ne32(man); #endif #if UNIX_SOCK_SUPPORT - if (man->settings.flags & MF_UNIX_SOCK) + if (man->settings.flags & MF_UNIX_SOCK) { - msg (D_MANAGEMENT, "MANAGEMENT: %s %s", - description, - sockaddr_unix_name (&man->settings.local_unix, "NULL")); + msg(D_MANAGEMENT, "MANAGEMENT: %s %s", + description, + sockaddr_unix_name(&man->settings.local_unix, "NULL")); } - else + else #endif - msg (D_MANAGEMENT, "MANAGEMENT: %s %s", - description, - print_sockaddr (man->settings.local->ai_addr, &gc)); + msg(D_MANAGEMENT, "MANAGEMENT: %s %s", + description, + print_sockaddr(man->settings.local->ai_addr, &gc)); - buffer_list_reset (man->connection.out); + buffer_list_reset(man->connection.out); - if (!man_password_needed (man)) - man_welcome (man); - man_prompt (man); - man_update_io_state (man); + if (!man_password_needed(man)) + { + man_welcome(man); + } + man_prompt(man); + man_update_io_state(man); - gc_free (&gc); + gc_free(&gc); } #if UNIX_SOCK_SUPPORT static bool -man_verify_unix_peer_uid_gid (struct management *man, const socket_descriptor_t sd) -{ - if (socket_defined (sd) && (man->settings.client_uid != -1 || man->settings.client_gid != -1)) - { - static const char err_prefix[] = "MANAGEMENT: unix domain socket client connection rejected --"; - int uid, gid; - if (unix_socket_get_peer_uid_gid (man->connection.sd_cli, &uid, &gid)) - { - if (man->settings.client_uid != -1 && man->settings.client_uid != uid) - { - msg (D_MANAGEMENT, "%s UID of socket peer (%d) doesn't match required value (%d) as given by --management-client-user", - err_prefix, uid, man->settings.client_uid); - return false; - } - if (man->settings.client_gid != -1 && man->settings.client_gid != gid) - { - msg (D_MANAGEMENT, "%s GID of socket peer (%d) doesn't match required value (%d) as given by --management-client-group", - err_prefix, gid, man->settings.client_gid); - return false; - } - } - else - { - msg (D_MANAGEMENT, "%s cannot get UID/GID of socket peer", err_prefix); - return false; - } - } - return true; +man_verify_unix_peer_uid_gid(struct management *man, const socket_descriptor_t sd) +{ + if (socket_defined(sd) && (man->settings.client_uid != -1 || man->settings.client_gid != -1)) + { + static const char err_prefix[] = "MANAGEMENT: unix domain socket client connection rejected --"; + int uid, gid; + if (unix_socket_get_peer_uid_gid(man->connection.sd_cli, &uid, &gid)) + { + if (man->settings.client_uid != -1 && man->settings.client_uid != uid) + { + msg(D_MANAGEMENT, "%s UID of socket peer (%d) doesn't match required value (%d) as given by --management-client-user", + err_prefix, uid, man->settings.client_uid); + return false; + } + if (man->settings.client_gid != -1 && man->settings.client_gid != gid) + { + msg(D_MANAGEMENT, "%s GID of socket peer (%d) doesn't match required value (%d) as given by --management-client-group", + err_prefix, gid, man->settings.client_gid); + return false; + } + } + else + { + msg(D_MANAGEMENT, "%s cannot get UID/GID of socket peer", err_prefix); + return false; + } + } + return true; } -#endif +#endif /* if UNIX_SOCK_SUPPORT */ static void -man_accept (struct management *man) +man_accept(struct management *man) { - struct link_socket_actual act; - CLEAR (act); + struct link_socket_actual act; + CLEAR(act); - /* - * Accept the TCP or Unix domain socket client. - */ + /* + * Accept the TCP or Unix domain socket client. + */ #if UNIX_SOCK_SUPPORT - if (man->settings.flags & MF_UNIX_SOCK) + if (man->settings.flags & MF_UNIX_SOCK) { - struct sockaddr_un remote; - man->connection.sd_cli = socket_accept_unix (man->connection.sd_top, &remote); - if (!man_verify_unix_peer_uid_gid (man, man->connection.sd_cli)) - sd_close (&man->connection.sd_cli); + struct sockaddr_un remote; + man->connection.sd_cli = socket_accept_unix(man->connection.sd_top, &remote); + if (!man_verify_unix_peer_uid_gid(man, man->connection.sd_cli)) + { + sd_close(&man->connection.sd_cli); + } } - else + else #endif - man->connection.sd_cli = socket_do_accept (man->connection.sd_top, &act, false); + man->connection.sd_cli = socket_do_accept(man->connection.sd_top, &act, false); - if (socket_defined (man->connection.sd_cli)) + if (socket_defined(man->connection.sd_cli)) { - man->connection.remote = act.dest; + man->connection.remote = act.dest; - if (socket_defined (man->connection.sd_top)) - { + if (socket_defined(man->connection.sd_top)) + { #ifdef _WIN32 - man_stop_ne32 (man); + man_stop_ne32(man); #endif - } + } - man_new_connection_post (man, "Client connected from"); + man_new_connection_post(man, "Client connected from"); } } static void -man_listen (struct management *man) +man_listen(struct management *man) { - struct gc_arena gc = gc_new (); + struct gc_arena gc = gc_new(); - /* - * Initialize state - */ - man->connection.state = MS_LISTEN; - man->connection.sd_cli = SOCKET_UNDEFINED; + /* + * Initialize state + */ + man->connection.state = MS_LISTEN; + man->connection.sd_cli = SOCKET_UNDEFINED; - /* - * Initialize listening socket - */ - if (man->connection.sd_top == SOCKET_UNDEFINED) + /* + * Initialize listening socket + */ + if (man->connection.sd_top == SOCKET_UNDEFINED) { #if UNIX_SOCK_SUPPORT - if (man->settings.flags & MF_UNIX_SOCK) - { - man_delete_unix_socket (man); - man->connection.sd_top = create_socket_unix (); - socket_bind_unix (man->connection.sd_top, &man->settings.local_unix, "MANAGEMENT"); - } - else + if (man->settings.flags & MF_UNIX_SOCK) + { + man_delete_unix_socket(man); + man->connection.sd_top = create_socket_unix(); + socket_bind_unix(man->connection.sd_top, &man->settings.local_unix, "MANAGEMENT"); + } + else #endif - { - man->connection.sd_top = create_socket_tcp (man->settings.local); - socket_bind (man->connection.sd_top, man->settings.local, - man->settings.local->ai_family, "MANAGEMENT", false); - } - - /* - * Listen for connection - */ - if (listen (man->connection.sd_top, 1)) - msg (M_ERR, "MANAGEMENT: listen() failed"); - - /* - * Set misc socket properties - */ - set_nonblock (man->connection.sd_top); + { + man->connection.sd_top = create_socket_tcp(man->settings.local); + socket_bind(man->connection.sd_top, man->settings.local, + man->settings.local->ai_family, "MANAGEMENT", false); + } + + /* + * Listen for connection + */ + if (listen(man->connection.sd_top, 1)) + { + msg(M_ERR, "MANAGEMENT: listen() failed"); + } + + /* + * Set misc socket properties + */ + set_nonblock(man->connection.sd_top); #if UNIX_SOCK_SUPPORT - if (man->settings.flags & MF_UNIX_SOCK) - { - msg (D_MANAGEMENT, "MANAGEMENT: unix domain socket listening on %s", - sockaddr_unix_name (&man->settings.local_unix, "NULL")); - } - else + if (man->settings.flags & MF_UNIX_SOCK) + { + msg(D_MANAGEMENT, "MANAGEMENT: unix domain socket listening on %s", + sockaddr_unix_name(&man->settings.local_unix, "NULL")); + } + else #endif - msg (D_MANAGEMENT, "MANAGEMENT: TCP Socket listening on %s", - print_sockaddr (man->settings.local->ai_addr, &gc)); + msg(D_MANAGEMENT, "MANAGEMENT: TCP Socket listening on %s", + print_sockaddr(man->settings.local->ai_addr, &gc)); } #ifdef _WIN32 - man_start_ne32 (man); + man_start_ne32(man); #endif - - gc_free (&gc); + + gc_free(&gc); } static void -man_connect (struct management *man) +man_connect(struct management *man) { - struct gc_arena gc = gc_new (); - int status; - int signal_received = 0; + struct gc_arena gc = gc_new(); + int status; + int signal_received = 0; - /* - * Initialize state - */ - man->connection.state = MS_INITIAL; - man->connection.sd_top = SOCKET_UNDEFINED; + /* + * Initialize state + */ + man->connection.state = MS_INITIAL; + man->connection.sd_top = SOCKET_UNDEFINED; #if UNIX_SOCK_SUPPORT - if (man->settings.flags & MF_UNIX_SOCK) + if (man->settings.flags & MF_UNIX_SOCK) { - man->connection.sd_cli = create_socket_unix (); - status = socket_connect_unix (man->connection.sd_cli, &man->settings.local_unix); - if (!status && !man_verify_unix_peer_uid_gid (man, man->connection.sd_cli)) - { + man->connection.sd_cli = create_socket_unix(); + status = socket_connect_unix(man->connection.sd_cli, &man->settings.local_unix); + if (!status && !man_verify_unix_peer_uid_gid(man, man->connection.sd_cli)) + { #ifdef EPERM - status = EPERM; + status = EPERM; #else - status = 1; + status = 1; #endif - sd_close (&man->connection.sd_cli); - } + sd_close(&man->connection.sd_cli); + } } - else + else #endif { - man->connection.sd_cli = create_socket_tcp (man->settings.local); - status = openvpn_connect (man->connection.sd_cli, - man->settings.local->ai_addr, - 5, - &signal_received); + man->connection.sd_cli = create_socket_tcp(man->settings.local); + status = openvpn_connect(man->connection.sd_cli, + man->settings.local->ai_addr, + 5, + &signal_received); } - if (signal_received) + if (signal_received) { - throw_signal (signal_received); - goto done; + throw_signal(signal_received); + goto done; } - if (status) + if (status) { #if UNIX_SOCK_SUPPORT - if (man->settings.flags & MF_UNIX_SOCK) - { - msg (D_LINK_ERRORS, - "MANAGEMENT: connect to unix socket %s failed: %s", - sockaddr_unix_name (&man->settings.local_unix, "NULL"), - strerror_ts (status, &gc)); - } - else + if (man->settings.flags & MF_UNIX_SOCK) + { + msg(D_LINK_ERRORS, + "MANAGEMENT: connect to unix socket %s failed: %s", + sockaddr_unix_name(&man->settings.local_unix, "NULL"), + strerror_ts(status, &gc)); + } + else #endif - msg (D_LINK_ERRORS, - "MANAGEMENT: connect to %s failed: %s", - print_sockaddr (man->settings.local->ai_addr, &gc), - strerror_ts (status, &gc)); - throw_signal_soft (SIGTERM, "management-connect-failed"); - goto done; + msg(D_LINK_ERRORS, + "MANAGEMENT: connect to %s failed: %s", + print_sockaddr(man->settings.local->ai_addr, &gc), + strerror_ts(status, &gc)); + throw_signal_soft(SIGTERM, "management-connect-failed"); + goto done; } - man_record_peer_info (man); - man_new_connection_post (man, "Connected to management server at"); + man_record_peer_info(man); + man_new_connection_post(man, "Connected to management server at"); - done: - gc_free (&gc); +done: + gc_free(&gc); } static void -man_reset_client_socket (struct management *man, const bool exiting) +man_reset_client_socket(struct management *man, const bool exiting) { - if (socket_defined (man->connection.sd_cli)) + if (socket_defined(man->connection.sd_cli)) { #ifdef _WIN32 - man_stop_ne32 (man); + man_stop_ne32(man); #endif - man_close_socket (man, man->connection.sd_cli); - man->connection.sd_cli = SOCKET_UNDEFINED; - man->connection.state = MS_INITIAL; - command_line_reset (man->connection.in); - buffer_list_reset (man->connection.out); + man_close_socket(man, man->connection.sd_cli); + man->connection.sd_cli = SOCKET_UNDEFINED; + man->connection.state = MS_INITIAL; + command_line_reset(man->connection.in); + buffer_list_reset(man->connection.out); #ifdef MANAGEMENT_IN_EXTRA - in_extra_reset (&man->connection, IER_RESET); + in_extra_reset(&man->connection, IER_RESET); #endif - msg (D_MANAGEMENT, "MANAGEMENT: Client disconnected"); + msg(D_MANAGEMENT, "MANAGEMENT: Client disconnected"); } - if (!exiting) + if (!exiting) { #ifdef ENABLE_CRYPTO - if (man->settings.flags & MF_FORGET_DISCONNECT) - ssl_purge_auth (false); + if (man->settings.flags & MF_FORGET_DISCONNECT) + { + ssl_purge_auth(false); + } #endif - if (man->settings.flags & MF_SIGNAL) { - int mysig = man_mod_signal (man, SIGUSR1); - if (mysig >= 0) - { - msg (D_MANAGEMENT, "MANAGEMENT: Triggering management signal"); - throw_signal_soft (mysig, "management-disconnect"); - } - } - - if (man->settings.flags & MF_CONNECT_AS_CLIENT) - { - msg (D_MANAGEMENT, "MANAGEMENT: Triggering management exit"); - throw_signal_soft (SIGTERM, "management-exit"); - } - else - man_listen (man); + if (man->settings.flags & MF_SIGNAL) + { + int mysig = man_mod_signal(man, SIGUSR1); + if (mysig >= 0) + { + msg(D_MANAGEMENT, "MANAGEMENT: Triggering management signal"); + throw_signal_soft(mysig, "management-disconnect"); + } + } + + if (man->settings.flags & MF_CONNECT_AS_CLIENT) + { + msg(D_MANAGEMENT, "MANAGEMENT: Triggering management exit"); + throw_signal_soft(SIGTERM, "management-exit"); + } + else + { + man_listen(man); + } } } static void -man_process_command (struct management *man, const char *line) +man_process_command(struct management *man, const char *line) { - struct gc_arena gc = gc_new (); - struct status_output *so; - int nparms; - char *parms[MAX_PARMS+1]; + struct gc_arena gc = gc_new(); + struct status_output *so; + int nparms; + char *parms[MAX_PARMS+1]; - CLEAR (parms); - so = status_open (NULL, 0, -1, &man->persist.vout, 0); + CLEAR(parms); + so = status_open(NULL, 0, -1, &man->persist.vout, 0); #ifdef MANAGEMENT_IN_EXTRA - in_extra_reset (&man->connection, IER_RESET); + in_extra_reset(&man->connection, IER_RESET); #endif - if (man_password_needed (man)) + if (man_password_needed(man)) { - man_check_password (man, line); + man_check_password(man, line); } - else + else { - nparms = parse_line (line, parms, MAX_PARMS, "TCP", 0, M_CLIENT, &gc); - if (parms[0] && streq (parms[0], "password")) - msg (D_MANAGEMENT_DEBUG, "MANAGEMENT: CMD 'password [...]'"); - else if (!streq (line, "load-stats")) - msg (D_MANAGEMENT_DEBUG, "MANAGEMENT: CMD '%s'", line); + nparms = parse_line(line, parms, MAX_PARMS, "TCP", 0, M_CLIENT, &gc); + if (parms[0] && streq(parms[0], "password")) + { + msg(D_MANAGEMENT_DEBUG, "MANAGEMENT: CMD 'password [...]'"); + } + else if (!streq(line, "load-stats")) + { + msg(D_MANAGEMENT_DEBUG, "MANAGEMENT: CMD '%s'", line); + } #if 0 - /* DEBUGGING -- print args */ - { - int i; - for (i = 0; i < nparms; ++i) - msg (M_INFO, "[%d] '%s'", i, parms[i]); - } + /* DEBUGGING -- print args */ + { + int i; + for (i = 0; i < nparms; ++i) + msg(M_INFO, "[%d] '%s'", i, parms[i]); + } #endif - if (nparms > 0) - man_dispatch_command (man, so, (const char **)parms, nparms); + if (nparms > 0) + { + man_dispatch_command(man, so, (const char **)parms, nparms); + } } - CLEAR (parms); - status_close (so); - gc_free (&gc); + CLEAR(parms); + status_close(so); + gc_free(&gc); } static bool -man_io_error (struct management *man, const char *prefix) +man_io_error(struct management *man, const char *prefix) { - const int err = openvpn_errno (); + const int err = openvpn_errno(); - if (!ignore_sys_error (err)) + if (!ignore_sys_error(err)) { - struct gc_arena gc = gc_new (); - msg (D_MANAGEMENT, "MANAGEMENT: TCP %s error: %s", - prefix, - strerror_ts (err, &gc)); - gc_free (&gc); - return true; + struct gc_arena gc = gc_new(); + msg(D_MANAGEMENT, "MANAGEMENT: TCP %s error: %s", + prefix, + strerror_ts(err, &gc)); + gc_free(&gc); + return true; + } + else + { + return false; } - else - return false; } #ifdef TARGET_ANDROID -static ssize_t man_send_with_fd (int fd, void *ptr, size_t nbytes, int flags, int sendfd) +static ssize_t +man_send_with_fd(int fd, void *ptr, size_t nbytes, int flags, int sendfd) { - struct msghdr msg; - struct iovec iov[1]; + struct msghdr msg; + struct iovec iov[1]; - union { - struct cmsghdr cm; - char control[CMSG_SPACE(sizeof(int))]; - } control_un; - struct cmsghdr *cmptr; + union { + struct cmsghdr cm; + char control[CMSG_SPACE(sizeof(int))]; + } control_un; + struct cmsghdr *cmptr; - msg.msg_control = control_un.control; - msg.msg_controllen = sizeof(control_un.control); + msg.msg_control = control_un.control; + msg.msg_controllen = sizeof(control_un.control); - cmptr = CMSG_FIRSTHDR(&msg); - cmptr->cmsg_len = CMSG_LEN(sizeof(int)); - cmptr->cmsg_level = SOL_SOCKET; - cmptr->cmsg_type = SCM_RIGHTS; - *((int *) CMSG_DATA(cmptr)) = sendfd; + cmptr = CMSG_FIRSTHDR(&msg); + cmptr->cmsg_len = CMSG_LEN(sizeof(int)); + cmptr->cmsg_level = SOL_SOCKET; + cmptr->cmsg_type = SCM_RIGHTS; + *((int *) CMSG_DATA(cmptr)) = sendfd; - msg.msg_name = NULL; - msg.msg_namelen = 0; + msg.msg_name = NULL; + msg.msg_namelen = 0; - iov[0].iov_base = ptr; - iov[0].iov_len = nbytes; - msg.msg_iov = iov; - msg.msg_iovlen = 1; + iov[0].iov_base = ptr; + iov[0].iov_len = nbytes; + msg.msg_iov = iov; + msg.msg_iovlen = 1; - return (sendmsg(fd, &msg, flags)); + return (sendmsg(fd, &msg, flags)); } -static ssize_t man_recv_with_fd (int fd, void *ptr, size_t nbytes, int flags, int *recvfd) +static ssize_t +man_recv_with_fd(int fd, void *ptr, size_t nbytes, int flags, int *recvfd) { - struct msghdr msghdr; - struct iovec iov[1]; - ssize_t n; + struct msghdr msghdr; + struct iovec iov[1]; + ssize_t n; - union { - struct cmsghdr cm; - char control[CMSG_SPACE(sizeof (int))]; - } control_un; - struct cmsghdr *cmptr; + union { + struct cmsghdr cm; + char control[CMSG_SPACE(sizeof(int))]; + } control_un; + struct cmsghdr *cmptr; - msghdr.msg_control = control_un.control; - msghdr.msg_controllen = sizeof(control_un.control); + msghdr.msg_control = control_un.control; + msghdr.msg_controllen = sizeof(control_un.control); - msghdr.msg_name = NULL; - msghdr.msg_namelen = 0; + msghdr.msg_name = NULL; + msghdr.msg_namelen = 0; - iov[0].iov_base = ptr; - iov[0].iov_len = nbytes; - msghdr.msg_iov = iov; - msghdr.msg_iovlen = 1; + iov[0].iov_base = ptr; + iov[0].iov_len = nbytes; + msghdr.msg_iov = iov; + msghdr.msg_iovlen = 1; - if ( (n = recvmsg(fd, &msghdr, flags)) <= 0) - return (n); + if ( (n = recvmsg(fd, &msghdr, flags)) <= 0) + { + return (n); + } - if ( (cmptr = CMSG_FIRSTHDR(&msghdr)) != NULL && - cmptr->cmsg_len == CMSG_LEN(sizeof(int))) { - if (cmptr->cmsg_level != SOL_SOCKET) - msg (M_ERR, "control level != SOL_SOCKET"); - if (cmptr->cmsg_type != SCM_RIGHTS) - msg (M_ERR, "control type != SCM_RIGHTS"); - *recvfd = *((int *) CMSG_DATA(cmptr)); - } else - *recvfd = -1; /* descriptor was not passed */ + if ( (cmptr = CMSG_FIRSTHDR(&msghdr)) != NULL + && cmptr->cmsg_len == CMSG_LEN(sizeof(int))) + { + if (cmptr->cmsg_level != SOL_SOCKET) + { + msg(M_ERR, "control level != SOL_SOCKET"); + } + if (cmptr->cmsg_type != SCM_RIGHTS) + { + msg(M_ERR, "control type != SCM_RIGHTS"); + } + *recvfd = *((int *) CMSG_DATA(cmptr)); + } + else + { + *recvfd = -1; /* descriptor was not passed */ - return (n); + } + return (n); } /* * The android control method will instruct the GUI part of openvpn to do * the route/ifconfig/open tun command. See doc/android.txt for details. */ -bool management_android_control (struct management *man, const char *command, const char *msg) +bool +management_android_control(struct management *man, const char *command, const char *msg) { - struct user_pass up; - CLEAR(up); - strncpy (up.username, msg, sizeof(up.username)-1); + struct user_pass up; + CLEAR(up); + strncpy(up.username, msg, sizeof(up.username)-1); - management_query_user_pass(management, &up , command, GET_USER_PASS_NEED_OK,(void*) 0); - return strcmp ("ok", up.password)==0; + management_query_user_pass(management, &up, command, GET_USER_PASS_NEED_OK,(void *) 0); + return strcmp("ok", up.password)==0; } /* @@ -1926,1020 +2123,1145 @@ bool management_android_control (struct management *man, const char *command, co * is rebooted. This management method ask the UI what method should be taken to * ensure the optimal solution for the situation */ -int managment_android_persisttun_action (struct management *man) -{ - struct user_pass up; - CLEAR(up); - strcpy(up.username,"tunmethod"); - management_query_user_pass(management, &up , "PERSIST_TUN_ACTION", - GET_USER_PASS_NEED_OK,(void*) 0); - if (!strcmp("NOACTION", up.password)) - return ANDROID_KEEP_OLD_TUN; - else if (!strcmp ("OPEN_AFTER_CLOSE", up.password)) - return ANDROID_OPEN_AFTER_CLOSE; - else if (!strcmp ("OPEN_BEFORE_CLOSE", up.password)) - return ANDROID_OPEN_BEFORE_CLOSE; - else - msg (M_ERR, "Got unrecognised '%s' from management for PERSIST_TUN_ACTION query", up.password); +int +managment_android_persisttun_action(struct management *man) +{ + struct user_pass up; + CLEAR(up); + strcpy(up.username,"tunmethod"); + management_query_user_pass(management, &up, "PERSIST_TUN_ACTION", + GET_USER_PASS_NEED_OK,(void *) 0); + if (!strcmp("NOACTION", up.password)) + { + return ANDROID_KEEP_OLD_TUN; + } + else if (!strcmp("OPEN_AFTER_CLOSE", up.password)) + { + return ANDROID_OPEN_AFTER_CLOSE; + } + else if (!strcmp("OPEN_BEFORE_CLOSE", up.password)) + { + return ANDROID_OPEN_BEFORE_CLOSE; + } + else + { + msg(M_ERR, "Got unrecognised '%s' from management for PERSIST_TUN_ACTION query", up.password); + } - ASSERT(0); - return ANDROID_OPEN_AFTER_CLOSE; + ASSERT(0); + return ANDROID_OPEN_AFTER_CLOSE; } -#endif +#endif /* ifdef TARGET_ANDROID */ static int -man_read (struct management *man) +man_read(struct management *man) { - /* - * read command line from socket - */ - unsigned char buf[256]; - int len = 0; + /* + * read command line from socket + */ + unsigned char buf[256]; + int len = 0; #ifdef TARGET_ANDROID - int fd; - len = man_recv_with_fd (man->connection.sd_cli, buf, sizeof (buf), MSG_NOSIGNAL, &fd); - if(fd >= 0) - man->connection.lastfdreceived = fd; -#else - len = recv (man->connection.sd_cli, buf, sizeof (buf), MSG_NOSIGNAL); + int fd; + len = man_recv_with_fd(man->connection.sd_cli, buf, sizeof(buf), MSG_NOSIGNAL, &fd); + if (fd >= 0) + { + man->connection.lastfdreceived = fd; + } +#else /* ifdef TARGET_ANDROID */ + len = recv(man->connection.sd_cli, buf, sizeof(buf), MSG_NOSIGNAL); #endif - if (len == 0) + if (len == 0) { - man_reset_client_socket (man, false); + man_reset_client_socket(man, false); } - else if (len > 0) + else if (len > 0) { - bool processed_command = false; + bool processed_command = false; - ASSERT (len <= (int) sizeof (buf)); - command_line_add (man->connection.in, buf, len); + ASSERT(len <= (int) sizeof(buf)); + command_line_add(man->connection.in, buf, len); - /* - * Reset output object - */ - buffer_list_reset (man->connection.out); + /* + * Reset output object + */ + buffer_list_reset(man->connection.out); - /* - * process command line if complete - */ - { - const unsigned char *line; - while ((line = command_line_get (man->connection.in))) - { + /* + * process command line if complete + */ + { + const unsigned char *line; + while ((line = command_line_get(man->connection.in))) + { #ifdef MANAGEMENT_IN_EXTRA - if (man->connection.in_extra) - { - if (!strcmp ((char *)line, "END")) - in_extra_dispatch (man); - else - buffer_list_push (man->connection.in_extra, line); - } - else + if (man->connection.in_extra) + { + if (!strcmp((char *)line, "END")) + { + in_extra_dispatch(man); + } + else + { + buffer_list_push(man->connection.in_extra, line); + } + } + else #endif - man_process_command (man, (char *) line); - if (man->connection.halt) - break; - command_line_next (man->connection.in); - processed_command = true; - } - } - - /* - * Reset output state to MS_CC_WAIT_(READ|WRITE) - */ - if (man->connection.halt) - { - man_reset_client_socket (man, false); - len = 0; - } - else - { - if (processed_command) - man_prompt (man); - man_update_io_state (man); - } - } - else /* len < 0 */ - { - if (man_io_error (man, "recv")) - man_reset_client_socket (man, false); - } - return len; + man_process_command(man, (char *) line); + if (man->connection.halt) + { + break; + } + command_line_next(man->connection.in); + processed_command = true; + } + } + + /* + * Reset output state to MS_CC_WAIT_(READ|WRITE) + */ + if (man->connection.halt) + { + man_reset_client_socket(man, false); + len = 0; + } + else + { + if (processed_command) + { + man_prompt(man); + } + man_update_io_state(man); + } + } + else /* len < 0 */ + { + if (man_io_error(man, "recv")) + { + man_reset_client_socket(man, false); + } + } + return len; } static int -man_write (struct management *man) +man_write(struct management *man) { - const int size_hint = 1024; - int sent = 0; - const struct buffer *buf; + const int size_hint = 1024; + int sent = 0; + const struct buffer *buf; - buffer_list_aggregate(man->connection.out, size_hint); - buf = buffer_list_peek (man->connection.out); - if (buf && BLEN (buf)) + buffer_list_aggregate(man->connection.out, size_hint); + buf = buffer_list_peek(man->connection.out); + if (buf && BLEN(buf)) { - const int len = min_int (size_hint, BLEN (buf)); + const int len = min_int(size_hint, BLEN(buf)); #ifdef TARGET_ANDROID - if (man->connection.fdtosend > 0) + if (man->connection.fdtosend > 0) { - sent = man_send_with_fd (man->connection.sd_cli, BPTR (buf), len, MSG_NOSIGNAL,man->connection.fdtosend); + sent = man_send_with_fd(man->connection.sd_cli, BPTR(buf), len, MSG_NOSIGNAL,man->connection.fdtosend); man->connection.fdtosend = -1; - } else + } + else #endif - sent = send (man->connection.sd_cli, BPTR (buf), len, MSG_NOSIGNAL); - if (sent >= 0) - { - buffer_list_advance (man->connection.out, sent); - } - else if (sent < 0) - { - if (man_io_error (man, "send")) - man_reset_client_socket (man, false); - } + sent = send(man->connection.sd_cli, BPTR(buf), len, MSG_NOSIGNAL); + if (sent >= 0) + { + buffer_list_advance(man->connection.out, sent); + } + else if (sent < 0) + { + if (man_io_error(man, "send")) + { + man_reset_client_socket(man, false); + } + } } - /* - * Reset output state to MS_CC_WAIT_(READ|WRITE) - */ - man_update_io_state (man); + /* + * Reset output state to MS_CC_WAIT_(READ|WRITE) + */ + man_update_io_state(man); - return sent; + return sent; } static void -man_connection_clear (struct man_connection *mc) +man_connection_clear(struct man_connection *mc) { - CLEAR (*mc); + CLEAR(*mc); - /* set initial state */ - mc->state = MS_INITIAL; + /* set initial state */ + mc->state = MS_INITIAL; - /* clear socket descriptors */ - mc->sd_top = SOCKET_UNDEFINED; - mc->sd_cli = SOCKET_UNDEFINED; + /* clear socket descriptors */ + mc->sd_top = SOCKET_UNDEFINED; + mc->sd_cli = SOCKET_UNDEFINED; } static void -man_persist_init (struct management *man, - const int log_history_cache, - const int echo_buffer_size, - const int state_buffer_size) +man_persist_init(struct management *man, + const int log_history_cache, + const int echo_buffer_size, + const int state_buffer_size) { - struct man_persist *mp = &man->persist; - if (!mp->defined) + struct man_persist *mp = &man->persist; + if (!mp->defined) { - CLEAR (*mp); + CLEAR(*mp); - /* initialize log history store */ - mp->log = log_history_init (log_history_cache); + /* initialize log history store */ + mp->log = log_history_init(log_history_cache); - /* - * Initialize virtual output object, so that functions - * which write to a virtual_output object can be redirected - * here to the management object. - */ - mp->vout.func = virtual_output_callback_func; - mp->vout.arg = man; - mp->vout.flags_default = M_CLIENT; - msg_set_virtual_output (&mp->vout); + /* + * Initialize virtual output object, so that functions + * which write to a virtual_output object can be redirected + * here to the management object. + */ + mp->vout.func = virtual_output_callback_func; + mp->vout.arg = man; + mp->vout.flags_default = M_CLIENT; + msg_set_virtual_output(&mp->vout); - /* - * Initialize --echo list - */ - man->persist.echo = log_history_init (echo_buffer_size); + /* + * Initialize --echo list + */ + man->persist.echo = log_history_init(echo_buffer_size); - /* - * Initialize --state list - */ - man->persist.state = log_history_init (state_buffer_size); + /* + * Initialize --state list + */ + man->persist.state = log_history_init(state_buffer_size); - mp->defined = true; + mp->defined = true; } } static void -man_persist_close (struct man_persist *mp) +man_persist_close(struct man_persist *mp) { - if (mp->log) + if (mp->log) { - msg_set_virtual_output (NULL); - log_history_close (mp->log); + msg_set_virtual_output(NULL); + log_history_close(mp->log); } - if (mp->echo) - log_history_close (mp->echo); + if (mp->echo) + { + log_history_close(mp->echo); + } - if (mp->state) - log_history_close (mp->state); + if (mp->state) + { + log_history_close(mp->state); + } - CLEAR (*mp); + CLEAR(*mp); } - + static void -man_settings_init (struct man_settings *ms, - const char *addr, - const char *port, - const char *pass_file, - const char *client_user, - const char *client_group, - const int log_history_cache, - const int echo_buffer_size, - const int state_buffer_size, - const char *write_peer_info_file, - const int remap_sigusr1, - const unsigned int flags) +man_settings_init(struct man_settings *ms, + const char *addr, + const char *port, + const char *pass_file, + const char *client_user, + const char *client_group, + const int log_history_cache, + const int echo_buffer_size, + const int state_buffer_size, + const char *write_peer_info_file, + const int remap_sigusr1, + const unsigned int flags) { - if (!ms->defined) + if (!ms->defined) { - CLEAR (*ms); + CLEAR(*ms); - ms->flags = flags; - ms->client_uid = -1; - ms->client_gid = -1; + ms->flags = flags; + ms->client_uid = -1; + ms->client_gid = -1; - /* - * Get username/password - */ - if (pass_file) - get_user_pass (&ms->up, pass_file, "Management", GET_USER_PASS_PASSWORD_ONLY); + /* + * Get username/password + */ + if (pass_file) + { + get_user_pass(&ms->up, pass_file, "Management", GET_USER_PASS_PASSWORD_ONLY); + } - /* - * lookup client UID/GID if specified - */ - if (client_user) - { - struct platform_state_user s; - platform_user_get (client_user, &s); - ms->client_uid = platform_state_user_uid (&s); - msg (D_MANAGEMENT, "MANAGEMENT: client_uid=%d", ms->client_uid); - ASSERT (ms->client_uid >= 0); - } - if (client_group) - { - struct platform_state_group s; - platform_group_get (client_group, &s); - ms->client_gid = platform_state_group_gid (&s); - msg (D_MANAGEMENT, "MANAGEMENT: client_gid=%d", ms->client_gid); - ASSERT (ms->client_gid >= 0); - } + /* + * lookup client UID/GID if specified + */ + if (client_user) + { + struct platform_state_user s; + platform_user_get(client_user, &s); + ms->client_uid = platform_state_user_uid(&s); + msg(D_MANAGEMENT, "MANAGEMENT: client_uid=%d", ms->client_uid); + ASSERT(ms->client_uid >= 0); + } + if (client_group) + { + struct platform_state_group s; + platform_group_get(client_group, &s); + ms->client_gid = platform_state_group_gid(&s); + msg(D_MANAGEMENT, "MANAGEMENT: client_gid=%d", ms->client_gid); + ASSERT(ms->client_gid >= 0); + } - ms->write_peer_info_file = string_alloc (write_peer_info_file, NULL); + ms->write_peer_info_file = string_alloc(write_peer_info_file, NULL); #if UNIX_SOCK_SUPPORT - if (ms->flags & MF_UNIX_SOCK) - sockaddr_unix_init (&ms->local_unix, addr); - else + if (ms->flags & MF_UNIX_SOCK) + { + sockaddr_unix_init(&ms->local_unix, addr); + } + else #endif - { - - /* - * Run management over tunnel, or - * separate channel? - */ - if (streq (addr, "tunnel") && !(flags & MF_CONNECT_AS_CLIENT)) - { - ms->management_over_tunnel = true; - } - else - { - int status; - int resolve_flags = GETADDR_RESOLVE|GETADDR_WARN_ON_SIGNAL|GETADDR_FATAL; - - if (! (flags & MF_CONNECT_AS_CLIENT)) - resolve_flags |= GETADDR_PASSIVE; - - status = openvpn_getaddrinfo (resolve_flags, addr, port, 0, - NULL, AF_UNSPEC, &ms->local); - ASSERT(status==0); - } - } - - /* - * Log history and echo buffer may need to be resized - */ - ms->log_history_cache = log_history_cache; - ms->echo_buffer_size = echo_buffer_size; - ms->state_buffer_size = state_buffer_size; + { - /* - * Set remap sigusr1 flags - */ - if (remap_sigusr1 == SIGHUP) - ms->mansig |= MANSIG_MAP_USR1_TO_HUP; - else if (remap_sigusr1 == SIGTERM) - ms->mansig |= MANSIG_MAP_USR1_TO_TERM; + /* + * Run management over tunnel, or + * separate channel? + */ + if (streq(addr, "tunnel") && !(flags & MF_CONNECT_AS_CLIENT)) + { + ms->management_over_tunnel = true; + } + else + { + int status; + int resolve_flags = GETADDR_RESOLVE|GETADDR_WARN_ON_SIGNAL|GETADDR_FATAL; + + if (!(flags & MF_CONNECT_AS_CLIENT)) + { + resolve_flags |= GETADDR_PASSIVE; + } + + status = openvpn_getaddrinfo(resolve_flags, addr, port, 0, + NULL, AF_UNSPEC, &ms->local); + ASSERT(status==0); + } + } + + /* + * Log history and echo buffer may need to be resized + */ + ms->log_history_cache = log_history_cache; + ms->echo_buffer_size = echo_buffer_size; + ms->state_buffer_size = state_buffer_size; + + /* + * Set remap sigusr1 flags + */ + if (remap_sigusr1 == SIGHUP) + { + ms->mansig |= MANSIG_MAP_USR1_TO_HUP; + } + else if (remap_sigusr1 == SIGTERM) + { + ms->mansig |= MANSIG_MAP_USR1_TO_TERM; + } - ms->defined = true; + ms->defined = true; } } static void -man_settings_close (struct man_settings *ms) +man_settings_close(struct man_settings *ms) { - if (ms->local) - freeaddrinfo(ms->local); - free (ms->write_peer_info_file); - CLEAR (*ms); + if (ms->local) + { + freeaddrinfo(ms->local); + } + free(ms->write_peer_info_file); + CLEAR(*ms); } static void -man_connection_init (struct management *man) +man_connection_init(struct management *man) { - if (man->connection.state == MS_INITIAL) + if (man->connection.state == MS_INITIAL) { #ifdef _WIN32 - /* - * This object is a sort of TCP/IP helper - * for Windows. - */ - net_event_win32_init (&man->connection.ne32); + /* + * This object is a sort of TCP/IP helper + * for Windows. + */ + net_event_win32_init(&man->connection.ne32); #endif - /* - * Allocate helper objects for command line input and - * command output from/to the socket. - */ - man->connection.in = command_line_new (1024); - man->connection.out = buffer_list_new (0); - - /* - * Initialize event set for standalone usage, when we are - * running outside of the primary event loop. - */ - { - int maxevents = 1; - man->connection.es = event_set_init (&maxevents, EVENT_METHOD_FAST); - } - - /* - * Listen/connect socket - */ - if (man->settings.flags & MF_CONNECT_AS_CLIENT) - man_connect (man); - else - man_listen (man); + /* + * Allocate helper objects for command line input and + * command output from/to the socket. + */ + man->connection.in = command_line_new(1024); + man->connection.out = buffer_list_new(0); + + /* + * Initialize event set for standalone usage, when we are + * running outside of the primary event loop. + */ + { + int maxevents = 1; + man->connection.es = event_set_init(&maxevents, EVENT_METHOD_FAST); + } + + /* + * Listen/connect socket + */ + if (man->settings.flags & MF_CONNECT_AS_CLIENT) + { + man_connect(man); + } + else + { + man_listen(man); + } } } static void -man_connection_close (struct management *man) +man_connection_close(struct management *man) { - struct man_connection *mc = &man->connection; + struct man_connection *mc = &man->connection; - if (mc->es) - event_free (mc->es); + if (mc->es) + { + event_free(mc->es); + } #ifdef _WIN32 - net_event_win32_close (&mc->ne32); + net_event_win32_close(&mc->ne32); #endif - if (socket_defined (mc->sd_top)) + if (socket_defined(mc->sd_top)) { - man_close_socket (man, mc->sd_top); - man_delete_unix_socket (man); + man_close_socket(man, mc->sd_top); + man_delete_unix_socket(man); + } + if (socket_defined(mc->sd_cli)) + { + man_close_socket(man, mc->sd_cli); + } + if (mc->in) + { + command_line_free(mc->in); + } + if (mc->out) + { + buffer_list_free(mc->out); } - if (socket_defined (mc->sd_cli)) - man_close_socket (man, mc->sd_cli); - if (mc->in) - command_line_free (mc->in); - if (mc->out) - buffer_list_free (mc->out); #ifdef MANAGEMENT_IN_EXTRA - in_extra_reset (&man->connection, IER_RESET); + in_extra_reset(&man->connection, IER_RESET); #endif #ifdef MANAGMENT_EXTERNAL_KEY - buffer_list_free (mc->ext_key_input); + buffer_list_free(mc->ext_key_input); #endif - man_connection_clear (mc); + man_connection_clear(mc); } struct management * -management_init (void) +management_init(void) { - struct management *man; - ALLOC_OBJ_CLEAR (man, struct management); + struct management *man; + ALLOC_OBJ_CLEAR(man, struct management); - man_persist_init (man, - MANAGEMENT_LOG_HISTORY_INITIAL_SIZE, - MANAGEMENT_ECHO_BUFFER_SIZE, - MANAGEMENT_STATE_BUFFER_SIZE); + man_persist_init(man, + MANAGEMENT_LOG_HISTORY_INITIAL_SIZE, + MANAGEMENT_ECHO_BUFFER_SIZE, + MANAGEMENT_STATE_BUFFER_SIZE); - man_connection_clear (&man->connection); + man_connection_clear(&man->connection); - return man; + return man; } bool -management_open (struct management *man, - const char *addr, - const char *port, - const char *pass_file, - const char *client_user, - const char *client_group, - const int log_history_cache, - const int echo_buffer_size, - const int state_buffer_size, - const char *write_peer_info_file, - const int remap_sigusr1, - const unsigned int flags) -{ - bool ret = false; - - /* - * Save the settings only if they have not - * been saved before. - */ - man_settings_init (&man->settings, - addr, - port, - pass_file, - client_user, - client_group, - log_history_cache, - echo_buffer_size, - state_buffer_size, - write_peer_info_file, - remap_sigusr1, - flags); - - /* - * The log is initially sized to MANAGEMENT_LOG_HISTORY_INITIAL_SIZE, - * but may be changed here. Ditto for echo and state buffers. - */ - log_history_resize (man->persist.log, man->settings.log_history_cache); - log_history_resize (man->persist.echo, man->settings.echo_buffer_size); - log_history_resize (man->persist.state, man->settings.state_buffer_size); - - /* - * If connection object is uninitialized and we are not doing - * over-the-tunnel management, then open (listening) connection. - */ - if (man->connection.state == MS_INITIAL) - { - if (!man->settings.management_over_tunnel) - { - man_connection_init (man); - ret = true; - } - } - - return ret; +management_open(struct management *man, + const char *addr, + const char *port, + const char *pass_file, + const char *client_user, + const char *client_group, + const int log_history_cache, + const int echo_buffer_size, + const int state_buffer_size, + const char *write_peer_info_file, + const int remap_sigusr1, + const unsigned int flags) +{ + bool ret = false; + + /* + * Save the settings only if they have not + * been saved before. + */ + man_settings_init(&man->settings, + addr, + port, + pass_file, + client_user, + client_group, + log_history_cache, + echo_buffer_size, + state_buffer_size, + write_peer_info_file, + remap_sigusr1, + flags); + + /* + * The log is initially sized to MANAGEMENT_LOG_HISTORY_INITIAL_SIZE, + * but may be changed here. Ditto for echo and state buffers. + */ + log_history_resize(man->persist.log, man->settings.log_history_cache); + log_history_resize(man->persist.echo, man->settings.echo_buffer_size); + log_history_resize(man->persist.state, man->settings.state_buffer_size); + + /* + * If connection object is uninitialized and we are not doing + * over-the-tunnel management, then open (listening) connection. + */ + if (man->connection.state == MS_INITIAL) + { + if (!man->settings.management_over_tunnel) + { + man_connection_init(man); + ret = true; + } + } + + return ret; } void -management_close (struct management *man) +management_close(struct management *man) { - man_output_list_push_finalize (man); /* flush output queue */ - man_connection_close (man); - man_settings_close (&man->settings); - man_persist_close (&man->persist); - free (man); + man_output_list_push_finalize(man); /* flush output queue */ + man_connection_close(man); + man_settings_close(&man->settings); + man_persist_close(&man->persist); + free(man); } void -management_set_callback (struct management *man, - const struct management_callback *cb) +management_set_callback(struct management *man, + const struct management_callback *cb) { - man->persist.standalone_disabled = true; - man->persist.callback = *cb; + man->persist.standalone_disabled = true; + man->persist.callback = *cb; } void -management_clear_callback (struct management *man) +management_clear_callback(struct management *man) { - man->persist.standalone_disabled = false; - man->persist.hold_release = false; - CLEAR (man->persist.callback); - man_output_list_push_finalize (man); /* flush output queue */ + man->persist.standalone_disabled = false; + man->persist.hold_release = false; + CLEAR(man->persist.callback); + man_output_list_push_finalize(man); /* flush output queue */ } void -management_set_state (struct management *man, - const int state, - const char *detail, - const in_addr_t *tun_local_ip, - const struct in6_addr *tun_local_ip6, - const struct openvpn_sockaddr *local, - const struct openvpn_sockaddr *remote) -{ - if (man->persist.state && (!(man->settings.flags & MF_SERVER) || state < OPENVPN_STATE_CLIENT_BASE)) - { - struct gc_arena gc = gc_new (); - struct log_entry e; - const char *out = NULL; - - update_time (); - CLEAR (e); - e.timestamp = now; - e.u.state = state; - e.string = detail; - if (tun_local_ip) - e.local_ip = *tun_local_ip; - if (tun_local_ip6) - e.local_ip6 = *tun_local_ip6; - if (local) - e.local_sock = *local; - if (remote) - e.remote_sock = *remote; - - log_history_add (man->persist.state, &e); - - if (man->connection.state_realtime) - out = log_entry_print (&e, LOG_PRINT_STATE_PREFIX - | LOG_PRINT_INT_DATE - | LOG_PRINT_STATE - | LOG_PRINT_LOCAL_IP - | LOG_PRINT_REMOTE_IP - | LOG_PRINT_CRLF - | LOG_ECHO_TO_LOG, &gc); - - if (out) - man_output_list_push (man, out); - - gc_free (&gc); +management_set_state(struct management *man, + const int state, + const char *detail, + const in_addr_t *tun_local_ip, + const struct in6_addr *tun_local_ip6, + const struct openvpn_sockaddr *local, + const struct openvpn_sockaddr *remote) +{ + if (man->persist.state && (!(man->settings.flags & MF_SERVER) || state < OPENVPN_STATE_CLIENT_BASE)) + { + struct gc_arena gc = gc_new(); + struct log_entry e; + const char *out = NULL; + + update_time(); + CLEAR(e); + e.timestamp = now; + e.u.state = state; + e.string = detail; + if (tun_local_ip) + { + e.local_ip = *tun_local_ip; + } + if (tun_local_ip6) + { + e.local_ip6 = *tun_local_ip6; + } + if (local) + { + e.local_sock = *local; + } + if (remote) + { + e.remote_sock = *remote; + } + + log_history_add(man->persist.state, &e); + + if (man->connection.state_realtime) + { + out = log_entry_print(&e, LOG_PRINT_STATE_PREFIX + | LOG_PRINT_INT_DATE + | LOG_PRINT_STATE + | LOG_PRINT_LOCAL_IP + | LOG_PRINT_REMOTE_IP + | LOG_PRINT_CRLF + | LOG_ECHO_TO_LOG, &gc); + } + + if (out) + { + man_output_list_push(man, out); + } + + gc_free(&gc); } } static bool -env_filter_match (const char *env_str, const int env_filter_level) -{ - static const char *env_names[] = { - "username=", - "password=", - "X509_0_CN=", - "tls_serial_", - "untrusted_ip=", - "ifconfig_local=", - "ifconfig_netmask=", - "daemon_start_time=", - "daemon_pid=", - "dev=", - "ifconfig_pool_remote_ip=", - "ifconfig_pool_netmask=", - "time_duration=", - "bytes_sent=", - "bytes_received=" - }; - - if (env_filter_level == 0) - return true; - else if (env_filter_level <= 1 && !strncmp(env_str, "X509_", 5)) - return true; - else if (env_filter_level <= 2) - { - size_t i; - for (i = 0; i < SIZE(env_names); ++i) - { - const char *en = env_names[i]; - const size_t len = strlen(en); - if (!strncmp(env_str, en, len)) - return true; - } - return false; +env_filter_match(const char *env_str, const int env_filter_level) +{ + static const char *env_names[] = { + "username=", + "password=", + "X509_0_CN=", + "tls_serial_", + "untrusted_ip=", + "ifconfig_local=", + "ifconfig_netmask=", + "daemon_start_time=", + "daemon_pid=", + "dev=", + "ifconfig_pool_remote_ip=", + "ifconfig_pool_netmask=", + "time_duration=", + "bytes_sent=", + "bytes_received=" + }; + + if (env_filter_level == 0) + { + return true; + } + else if (env_filter_level <= 1 && !strncmp(env_str, "X509_", 5)) + { + return true; + } + else if (env_filter_level <= 2) + { + size_t i; + for (i = 0; i < SIZE(env_names); ++i) + { + const char *en = env_names[i]; + const size_t len = strlen(en); + if (!strncmp(env_str, en, len)) + { + return true; + } + } + return false; } - return false; + return false; } static void -man_output_env (const struct env_set *es, const bool tail, const int env_filter_level, const char *prefix) +man_output_env(const struct env_set *es, const bool tail, const int env_filter_level, const char *prefix) { - if (es) + if (es) + { + struct env_item *e; + for (e = es->list; e != NULL; e = e->next) + { + if (e->string && (!env_filter_level || env_filter_match(e->string, env_filter_level))) + { + msg(M_CLIENT, ">%s:ENV,%s", prefix, e->string); + } + } + } + if (tail) { - struct env_item *e; - for (e = es->list; e != NULL; e = e->next) - { - if (e->string && (!env_filter_level || env_filter_match(e->string, env_filter_level))) - msg (M_CLIENT, ">%s:ENV,%s", prefix, e->string); - } + msg(M_CLIENT, ">%s:ENV,END", prefix); } - if (tail) - msg (M_CLIENT, ">%s:ENV,END", prefix); } static void -man_output_extra_env (struct management *man, const char *prefix) +man_output_extra_env(struct management *man, const char *prefix) { - struct gc_arena gc = gc_new (); - struct env_set *es = env_set_create (&gc); - if (man->persist.callback.n_clients) + struct gc_arena gc = gc_new(); + struct env_set *es = env_set_create(&gc); + if (man->persist.callback.n_clients) { - const int nclients = (*man->persist.callback.n_clients) (man->persist.callback.arg); - setenv_int (es, "n_clients", nclients); + const int nclients = (*man->persist.callback.n_clients)(man->persist.callback.arg); + setenv_int(es, "n_clients", nclients); } - man_output_env (es, false, man->connection.env_filter_level, prefix); - gc_free (&gc); + man_output_env(es, false, man->connection.env_filter_level, prefix); + gc_free(&gc); } void management_up_down(struct management *man, const char *updown, const struct env_set *es) { - if (man->settings.flags & MF_UP_DOWN) + if (man->settings.flags & MF_UP_DOWN) { - msg (M_CLIENT, ">UPDOWN:%s", updown); - man_output_env (es, true, 0, "UPDOWN"); + msg(M_CLIENT, ">UPDOWN:%s", updown); + man_output_env(es, true, 0, "UPDOWN"); } } void management_notify(struct management *man, const char *severity, const char *type, const char *text) { - msg (M_CLIENT, ">NOTIFY:%s,%s,%s", severity, type, text); + msg(M_CLIENT, ">NOTIFY:%s,%s,%s", severity, type, text); } void -management_notify_generic (struct management *man, const char *str) +management_notify_generic(struct management *man, const char *str) { - msg (M_CLIENT, "%s", str); + msg(M_CLIENT, "%s", str); } #ifdef MANAGEMENT_DEF_AUTH static void -man_output_peer_info_env (struct management *man, struct man_def_auth_context *mdac) +man_output_peer_info_env(struct management *man, struct man_def_auth_context *mdac) { - char line[256]; - if (man->persist.callback.get_peer_info) + char line[256]; + if (man->persist.callback.get_peer_info) { - const char *peer_info = (*man->persist.callback.get_peer_info) (man->persist.callback.arg, mdac->cid); - if (peer_info) - { - struct buffer buf; - buf_set_read (&buf, (const uint8_t *) peer_info, strlen(peer_info)); - while (buf_parse (&buf, '\n', line, sizeof (line))) - { - chomp (line); - if (validate_peer_info_line(line)) - { - msg (M_CLIENT, ">CLIENT:ENV,%s", line); - } - else - msg (D_MANAGEMENT, "validation failed on peer_info line received from client"); - } - } + const char *peer_info = (*man->persist.callback.get_peer_info)(man->persist.callback.arg, mdac->cid); + if (peer_info) + { + struct buffer buf; + buf_set_read(&buf, (const uint8_t *) peer_info, strlen(peer_info)); + while (buf_parse(&buf, '\n', line, sizeof(line))) + { + chomp(line); + if (validate_peer_info_line(line)) + { + msg(M_CLIENT, ">CLIENT:ENV,%s", line); + } + else + { + msg(D_MANAGEMENT, "validation failed on peer_info line received from client"); + } + } + } } } void -management_notify_client_needing_auth (struct management *management, - const unsigned int mda_key_id, - struct man_def_auth_context *mdac, - const struct env_set *es) +management_notify_client_needing_auth(struct management *management, + const unsigned int mda_key_id, + struct man_def_auth_context *mdac, + const struct env_set *es) { - if (!(mdac->flags & DAF_CONNECTION_CLOSED)) + if (!(mdac->flags & DAF_CONNECTION_CLOSED)) { - const char *mode = "CONNECT"; - if (mdac->flags & DAF_CONNECTION_ESTABLISHED) - mode = "REAUTH"; - msg (M_CLIENT, ">CLIENT:%s,%lu,%u", mode, mdac->cid, mda_key_id); - man_output_extra_env (management, "CLIENT"); - if (management->connection.env_filter_level>0) - man_output_peer_info_env(management, mdac); - man_output_env (es, true, management->connection.env_filter_level, "CLIENT"); - mdac->flags |= DAF_INITIAL_AUTH; + const char *mode = "CONNECT"; + if (mdac->flags & DAF_CONNECTION_ESTABLISHED) + { + mode = "REAUTH"; + } + msg(M_CLIENT, ">CLIENT:%s,%lu,%u", mode, mdac->cid, mda_key_id); + man_output_extra_env(management, "CLIENT"); + if (management->connection.env_filter_level>0) + { + man_output_peer_info_env(management, mdac); + } + man_output_env(es, true, management->connection.env_filter_level, "CLIENT"); + mdac->flags |= DAF_INITIAL_AUTH; } } void -management_connection_established (struct management *management, - struct man_def_auth_context *mdac, - const struct env_set *es) +management_connection_established(struct management *management, + struct man_def_auth_context *mdac, + const struct env_set *es) { - mdac->flags |= DAF_CONNECTION_ESTABLISHED; - msg (M_CLIENT, ">CLIENT:ESTABLISHED,%lu", mdac->cid); - man_output_extra_env (management, "CLIENT"); - man_output_env (es, true, management->connection.env_filter_level, "CLIENT"); + mdac->flags |= DAF_CONNECTION_ESTABLISHED; + msg(M_CLIENT, ">CLIENT:ESTABLISHED,%lu", mdac->cid); + man_output_extra_env(management, "CLIENT"); + man_output_env(es, true, management->connection.env_filter_level, "CLIENT"); } void -management_notify_client_close (struct management *management, - struct man_def_auth_context *mdac, - const struct env_set *es) +management_notify_client_close(struct management *management, + struct man_def_auth_context *mdac, + const struct env_set *es) { - if ((mdac->flags & DAF_INITIAL_AUTH) && !(mdac->flags & DAF_CONNECTION_CLOSED)) + if ((mdac->flags & DAF_INITIAL_AUTH) && !(mdac->flags & DAF_CONNECTION_CLOSED)) { - msg (M_CLIENT, ">CLIENT:DISCONNECT,%lu", mdac->cid); - man_output_env (es, true, management->connection.env_filter_level, "CLIENT"); - mdac->flags |= DAF_CONNECTION_CLOSED; + msg(M_CLIENT, ">CLIENT:DISCONNECT,%lu", mdac->cid); + man_output_env(es, true, management->connection.env_filter_level, "CLIENT"); + mdac->flags |= DAF_CONNECTION_CLOSED; } } void -management_learn_addr (struct management *management, - struct man_def_auth_context *mdac, - const struct mroute_addr *addr, - const bool primary) +management_learn_addr(struct management *management, + struct man_def_auth_context *mdac, + const struct mroute_addr *addr, + const bool primary) { - struct gc_arena gc = gc_new (); - if ((mdac->flags & DAF_INITIAL_AUTH) && !(mdac->flags & DAF_CONNECTION_CLOSED)) + struct gc_arena gc = gc_new(); + if ((mdac->flags & DAF_INITIAL_AUTH) && !(mdac->flags & DAF_CONNECTION_CLOSED)) { - msg (M_CLIENT, ">CLIENT:ADDRESS,%lu,%s,%d", - mdac->cid, - mroute_addr_print_ex (addr, MAPF_SUBNET, &gc), - BOOL_CAST (primary)); + msg(M_CLIENT, ">CLIENT:ADDRESS,%lu,%s,%d", + mdac->cid, + mroute_addr_print_ex(addr, MAPF_SUBNET, &gc), + BOOL_CAST(primary)); } - gc_free (&gc); + gc_free(&gc); } #endif /* MANAGEMENT_DEF_AUTH */ void -management_echo (struct management *man, const char *string, const bool pull) +management_echo(struct management *man, const char *string, const bool pull) { - if (man->persist.echo) + if (man->persist.echo) { - struct gc_arena gc = gc_new (); - struct log_entry e; - const char *out = NULL; + struct gc_arena gc = gc_new(); + struct log_entry e; + const char *out = NULL; - update_time (); - CLEAR (e); - e.timestamp = now; - e.string = string; - e.u.intval = BOOL_CAST (pull); + update_time(); + CLEAR(e); + e.timestamp = now; + e.string = string; + e.u.intval = BOOL_CAST(pull); - log_history_add (man->persist.echo, &e); + log_history_add(man->persist.echo, &e); - if (man->connection.echo_realtime) - out = log_entry_print (&e, LOG_PRINT_INT_DATE|LOG_PRINT_ECHO_PREFIX|LOG_PRINT_CRLF|MANAGEMENT_ECHO_FLAGS, &gc); + if (man->connection.echo_realtime) + { + out = log_entry_print(&e, LOG_PRINT_INT_DATE|LOG_PRINT_ECHO_PREFIX|LOG_PRINT_CRLF|MANAGEMENT_ECHO_FLAGS, &gc); + } - if (out) - man_output_list_push (man, out); + if (out) + { + man_output_list_push(man, out); + } - gc_free (&gc); + gc_free(&gc); } } void -management_post_tunnel_open (struct management *man, const in_addr_t tun_local_ip) +management_post_tunnel_open(struct management *man, const in_addr_t tun_local_ip) { - /* - * If we are running management over the tunnel, - * this is the place to initialize the connection. - */ - if (man->settings.management_over_tunnel - && man->connection.state == MS_INITIAL) + /* + * If we are running management over the tunnel, + * this is the place to initialize the connection. + */ + if (man->settings.management_over_tunnel + && man->connection.state == MS_INITIAL) { - /* listen on our local TUN/TAP IP address */ - struct in_addr ia; - int ret; + /* listen on our local TUN/TAP IP address */ + struct in_addr ia; + int ret; - ia.s_addr = htonl(tun_local_ip); - ret = openvpn_getaddrinfo(GETADDR_PASSIVE, inet_ntoa(ia), NULL, 0, NULL, - AF_INET, &man->settings.local); - ASSERT (ret==0); - man_connection_init (man); + ia.s_addr = htonl(tun_local_ip); + ret = openvpn_getaddrinfo(GETADDR_PASSIVE, inet_ntoa(ia), NULL, 0, NULL, + AF_INET, &man->settings.local); + ASSERT(ret==0); + man_connection_init(man); } } void -management_pre_tunnel_close (struct management *man) +management_pre_tunnel_close(struct management *man) { - if (man->settings.management_over_tunnel) - man_connection_close (man); + if (man->settings.management_over_tunnel) + { + man_connection_close(man); + } } void -management_auth_failure (struct management *man, const char *type, const char *reason) +management_auth_failure(struct management *man, const char *type, const char *reason) { - if (reason) - msg (M_CLIENT, ">PASSWORD:Verification Failed: '%s' ['%s']", type, reason); - else - msg (M_CLIENT, ">PASSWORD:Verification Failed: '%s'", type); + if (reason) + { + msg(M_CLIENT, ">PASSWORD:Verification Failed: '%s' ['%s']", type, reason); + } + else + { + msg(M_CLIENT, ">PASSWORD:Verification Failed: '%s'", type); + } } void -management_auth_token (struct management *man, const char *token) +management_auth_token(struct management *man, const char *token) { - msg (M_CLIENT, ">PASSWORD:Auth-Token:%s", token); + msg(M_CLIENT, ">PASSWORD:Auth-Token:%s", token); } static inline bool -man_persist_state (unsigned int *persistent, const int n) +man_persist_state(unsigned int *persistent, const int n) { - if (persistent) + if (persistent) { - if (*persistent == (unsigned int)n) - return false; - *persistent = n; + if (*persistent == (unsigned int)n) + { + return false; + } + *persistent = n; } - return true; + return true; } #ifdef _WIN32 void -management_socket_set (struct management *man, - struct event_set *es, - void *arg, - unsigned int *persistent) -{ - if (man->connection.state != MS_INITIAL) - { - event_t ev = net_event_win32_get_event (&man->connection.ne32); - net_event_win32_reset_write (&man->connection.ne32); - - switch (man->connection.state) - { - case MS_LISTEN: - if (man_persist_state (persistent, 1)) - event_ctl (es, ev, EVENT_READ, arg); - break; - case MS_CC_WAIT_READ: - if (man_persist_state (persistent, 2)) - event_ctl (es, ev, EVENT_READ, arg); - break; - case MS_CC_WAIT_WRITE: - if (man_persist_state (persistent, 3)) - event_ctl (es, ev, EVENT_READ|EVENT_WRITE, arg); - break; - default: - ASSERT (0); - } +management_socket_set(struct management *man, + struct event_set *es, + void *arg, + unsigned int *persistent) +{ + if (man->connection.state != MS_INITIAL) + { + event_t ev = net_event_win32_get_event(&man->connection.ne32); + net_event_win32_reset_write(&man->connection.ne32); + + switch (man->connection.state) + { + case MS_LISTEN: + if (man_persist_state(persistent, 1)) + { + event_ctl(es, ev, EVENT_READ, arg); + } + break; + + case MS_CC_WAIT_READ: + if (man_persist_state(persistent, 2)) + { + event_ctl(es, ev, EVENT_READ, arg); + } + break; + + case MS_CC_WAIT_WRITE: + if (man_persist_state(persistent, 3)) + { + event_ctl(es, ev, EVENT_READ|EVENT_WRITE, arg); + } + break; + + default: + ASSERT(0); + } } } void -management_io (struct management *man) -{ - if (man->connection.state != MS_INITIAL) - { - long net_events; - net_event_win32_reset (&man->connection.ne32); - net_events = net_event_win32_get_event_mask (&man->connection.ne32); - - if (net_events & FD_CLOSE) - { - man_reset_client_socket (man, false); - } - else - { - if (man->connection.state == MS_LISTEN) - { - if (net_events & FD_ACCEPT) - { - man_accept (man); - net_event_win32_clear_selected_events (&man->connection.ne32, FD_ACCEPT); - } - } - else if (man->connection.state == MS_CC_WAIT_READ || man->connection.state == MS_CC_WAIT_WRITE) - { - if (net_events & FD_READ) - { - while (man_read (man) > 0) - ; - net_event_win32_clear_selected_events (&man->connection.ne32, FD_READ); - } - - if (net_events & FD_WRITE) - { - int status; - status = man_write (man); - if (status < 0 && WSAGetLastError() == WSAEWOULDBLOCK) - { - net_event_win32_clear_selected_events (&man->connection.ne32, FD_WRITE); - } - } - } - } - } -} +management_io(struct management *man) +{ + if (man->connection.state != MS_INITIAL) + { + long net_events; + net_event_win32_reset(&man->connection.ne32); + net_events = net_event_win32_get_event_mask(&man->connection.ne32); -#else + if (net_events & FD_CLOSE) + { + man_reset_client_socket(man, false); + } + else + { + if (man->connection.state == MS_LISTEN) + { + if (net_events & FD_ACCEPT) + { + man_accept(man); + net_event_win32_clear_selected_events(&man->connection.ne32, FD_ACCEPT); + } + } + else if (man->connection.state == MS_CC_WAIT_READ || man->connection.state == MS_CC_WAIT_WRITE) + { + if (net_events & FD_READ) + { + while (man_read(man) > 0) + ; + net_event_win32_clear_selected_events(&man->connection.ne32, FD_READ); + } + + if (net_events & FD_WRITE) + { + int status; + status = man_write(man); + if (status < 0 && WSAGetLastError() == WSAEWOULDBLOCK) + { + net_event_win32_clear_selected_events(&man->connection.ne32, FD_WRITE); + } + } + } + } + } +} + +#else /* ifdef _WIN32 */ void -management_socket_set (struct management *man, - struct event_set *es, - void *arg, - unsigned int *persistent) -{ - switch (man->connection.state) - { - case MS_LISTEN: - if (man_persist_state (persistent, 1)) - event_ctl (es, man->connection.sd_top, EVENT_READ, arg); - break; - case MS_CC_WAIT_READ: - if (man_persist_state (persistent, 2)) - event_ctl (es, man->connection.sd_cli, EVENT_READ, arg); - break; - case MS_CC_WAIT_WRITE: - if (man_persist_state (persistent, 3)) - event_ctl (es, man->connection.sd_cli, EVENT_WRITE, arg); - break; - case MS_INITIAL: - break; - default: - ASSERT (0); +management_socket_set(struct management *man, + struct event_set *es, + void *arg, + unsigned int *persistent) +{ + switch (man->connection.state) + { + case MS_LISTEN: + if (man_persist_state(persistent, 1)) + { + event_ctl(es, man->connection.sd_top, EVENT_READ, arg); + } + break; + + case MS_CC_WAIT_READ: + if (man_persist_state(persistent, 2)) + { + event_ctl(es, man->connection.sd_cli, EVENT_READ, arg); + } + break; + + case MS_CC_WAIT_WRITE: + if (man_persist_state(persistent, 3)) + { + event_ctl(es, man->connection.sd_cli, EVENT_WRITE, arg); + } + break; + + case MS_INITIAL: + break; + + default: + ASSERT(0); } } void -management_io (struct management *man) +management_io(struct management *man) { - switch (man->connection.state) + switch (man->connection.state) { - case MS_LISTEN: - man_accept (man); - break; - case MS_CC_WAIT_READ: - man_read (man); - break; - case MS_CC_WAIT_WRITE: - man_write (man); - break; - case MS_INITIAL: - break; - default: - ASSERT (0); + case MS_LISTEN: + man_accept(man); + break; + + case MS_CC_WAIT_READ: + man_read(man); + break; + + case MS_CC_WAIT_WRITE: + man_write(man); + break; + + case MS_INITIAL: + break; + + default: + ASSERT(0); } } -#endif +#endif /* ifdef _WIN32 */ static inline bool -man_standalone_ok (const struct management *man) +man_standalone_ok(const struct management *man) { - return !man->settings.management_over_tunnel && man->connection.state != MS_INITIAL; + return !man->settings.management_over_tunnel && man->connection.state != MS_INITIAL; } static bool -man_check_for_signals (volatile int *signal_received) +man_check_for_signals(volatile int *signal_received) { - if (signal_received) + if (signal_received) { - get_signal (signal_received); - if (*signal_received) - return true; + get_signal(signal_received); + if (*signal_received) + { + return true; + } } - return false; + return false; } /* * Wait for socket I/O when outside primary event loop */ static int -man_block (struct management *man, volatile int *signal_received, const time_t expire) -{ - struct timeval tv; - struct event_set_return esr; - int status = -1; - - if (man_standalone_ok (man)) - { - while (true) - { - event_reset (man->connection.es); - management_socket_set (man, man->connection.es, NULL, NULL); - tv.tv_usec = 0; - tv.tv_sec = 1; - if (man_check_for_signals (signal_received)) - { - status = -1; - break; - } - status = event_wait (man->connection.es, &tv, &esr, 1); - update_time (); - if (man_check_for_signals (signal_received)) - { - status = -1; - break; - } - - if (status > 0) - break; - else if (expire && now >= expire) - { - /* set SIGINT signal if expiration time exceeded */ - status = 0; - if (signal_received) - *signal_received = SIGINT; - break; - } - } - } - return status; +man_block(struct management *man, volatile int *signal_received, const time_t expire) +{ + struct timeval tv; + struct event_set_return esr; + int status = -1; + + if (man_standalone_ok(man)) + { + while (true) + { + event_reset(man->connection.es); + management_socket_set(man, man->connection.es, NULL, NULL); + tv.tv_usec = 0; + tv.tv_sec = 1; + if (man_check_for_signals(signal_received)) + { + status = -1; + break; + } + status = event_wait(man->connection.es, &tv, &esr, 1); + update_time(); + if (man_check_for_signals(signal_received)) + { + status = -1; + break; + } + + if (status > 0) + { + break; + } + else if (expire && now >= expire) + { + /* set SIGINT signal if expiration time exceeded */ + status = 0; + if (signal_received) + { + *signal_received = SIGINT; + } + break; + } + } + } + return status; } /* * Perform management socket output outside primary event loop */ static void -man_output_standalone (struct management *man, volatile int *signal_received) +man_output_standalone(struct management *man, volatile int *signal_received) { - if (man_standalone_ok (man)) + if (man_standalone_ok(man)) { - while (man->connection.state == MS_CC_WAIT_WRITE) - { - management_io (man); - if (man->connection.state == MS_CC_WAIT_WRITE) - man_block (man, signal_received, 0); - if (signal_received && *signal_received) - break; - } + while (man->connection.state == MS_CC_WAIT_WRITE) + { + management_io(man); + if (man->connection.state == MS_CC_WAIT_WRITE) + { + man_block(man, signal_received, 0); + } + if (signal_received && *signal_received) + { + break; + } + } } } @@ -2947,16 +3269,18 @@ man_output_standalone (struct management *man, volatile int *signal_received) * Process management event loop outside primary event loop */ static int -man_standalone_event_loop (struct management *man, volatile int *signal_received, const time_t expire) +man_standalone_event_loop(struct management *man, volatile int *signal_received, const time_t expire) { - int status = -1; - if (man_standalone_ok (man)) + int status = -1; + if (man_standalone_ok(man)) { - status = man_block (man, signal_received, expire); - if (status > 0) - management_io (man); + status = man_block(man, signal_received, expire); + if (status > 0) + { + management_io(man); + } } - return status; + return status; } #define MWCC_PASSWORD_WAIT (1<<0) @@ -2967,25 +3291,33 @@ man_standalone_event_loop (struct management *man, volatile int *signal_received * Block until client connects */ static void -man_wait_for_client_connection (struct management *man, - volatile int *signal_received, - const time_t expire, - unsigned int flags) +man_wait_for_client_connection(struct management *man, + volatile int *signal_received, + const time_t expire, + unsigned int flags) { - ASSERT (man_standalone_ok (man)); - if (man->connection.state == MS_LISTEN) + ASSERT(man_standalone_ok(man)); + if (man->connection.state == MS_LISTEN) { - if (flags & MWCC_PASSWORD_WAIT) - msg (D_MANAGEMENT, "Need password(s) from management interface, waiting..."); - if (flags & MWCC_HOLD_WAIT) - msg (D_MANAGEMENT, "Need hold release from management interface, waiting..."); - if (flags & MWCC_OTHER_WAIT) - msg (D_MANAGEMENT, "Need information from management interface, waiting..."); - do { - man_standalone_event_loop (man, signal_received, expire); - if (signal_received && *signal_received) - break; - } while (man->connection.state == MS_LISTEN || man_password_needed (man)); + if (flags & MWCC_PASSWORD_WAIT) + { + msg(D_MANAGEMENT, "Need password(s) from management interface, waiting..."); + } + if (flags & MWCC_HOLD_WAIT) + { + msg(D_MANAGEMENT, "Need hold release from management interface, waiting..."); + } + if (flags & MWCC_OTHER_WAIT) + { + msg(D_MANAGEMENT, "Need information from management interface, waiting..."); + } + do { + man_standalone_event_loop(man, signal_received, expire); + if (signal_received && *signal_received) + { + break; + } + } while (man->connection.state == MS_LISTEN || man_password_needed(man)); } } @@ -2993,43 +3325,51 @@ man_wait_for_client_connection (struct management *man, * Process the management event loop for sec seconds */ void -management_event_loop_n_seconds (struct management *man, int sec) +management_event_loop_n_seconds(struct management *man, int sec) { - if (man_standalone_ok (man)) + if (man_standalone_ok(man)) { - volatile int signal_received = 0; - const bool standalone_disabled_save = man->persist.standalone_disabled; - time_t expire = 0; + volatile int signal_received = 0; + const bool standalone_disabled_save = man->persist.standalone_disabled; + time_t expire = 0; - man->persist.standalone_disabled = false; /* This is so M_CLIENT messages will be correctly passed through msg() */ + man->persist.standalone_disabled = false; /* This is so M_CLIENT messages will be correctly passed through msg() */ - /* set expire time */ - update_time (); - if (sec) - expire = now + sec; + /* set expire time */ + update_time(); + if (sec) + { + expire = now + sec; + } - /* if no client connection, wait for one */ - man_wait_for_client_connection (man, &signal_received, expire, 0); - if (signal_received) - return; + /* if no client connection, wait for one */ + man_wait_for_client_connection(man, &signal_received, expire, 0); + if (signal_received) + { + return; + } - /* run command processing event loop */ - do - { - man_standalone_event_loop (man, &signal_received, expire); - if (!signal_received) - man_check_for_signals (&signal_received); - if (signal_received) - return; - update_time(); - } while (expire && expire > now); + /* run command processing event loop */ + do + { + man_standalone_event_loop(man, &signal_received, expire); + if (!signal_received) + { + man_check_for_signals(&signal_received); + } + if (signal_received) + { + return; + } + update_time(); + } while (expire && expire > now); - /* revert state */ - man->persist.standalone_disabled = standalone_disabled_save; + /* revert state */ + man->persist.standalone_disabled = standalone_disabled_save; } - else + else { - sleep (sec); + sleep(sec); } } @@ -3037,282 +3377,311 @@ management_event_loop_n_seconds (struct management *man, int sec) * Get a username/password from management channel in standalone mode. */ bool -management_query_user_pass (struct management *man, - struct user_pass *up, - const char *type, - const unsigned int flags, - const char *static_challenge) -{ - struct gc_arena gc = gc_new (); - bool ret = false; - - if (man_standalone_ok (man)) - { - volatile int signal_received = 0; - const bool standalone_disabled_save = man->persist.standalone_disabled; - struct buffer alert_msg = alloc_buf_gc (128, &gc); - const char *alert_type = NULL; - const char *prefix = NULL; - unsigned int up_query_mode = 0; +management_query_user_pass(struct management *man, + struct user_pass *up, + const char *type, + const unsigned int flags, + const char *static_challenge) +{ + struct gc_arena gc = gc_new(); + bool ret = false; + + if (man_standalone_ok(man)) + { + volatile int signal_received = 0; + const bool standalone_disabled_save = man->persist.standalone_disabled; + struct buffer alert_msg = alloc_buf_gc(128, &gc); + const char *alert_type = NULL; + const char *prefix = NULL; + unsigned int up_query_mode = 0; #ifdef ENABLE_CLIENT_CR - const char *sc = NULL; + const char *sc = NULL; #endif - ret = true; - man->persist.standalone_disabled = false; /* This is so M_CLIENT messages will be correctly passed through msg() */ - man->persist.special_state_msg = NULL; - - CLEAR (man->connection.up_query); - - if (flags & GET_USER_PASS_NEED_OK) - { - up_query_mode = UP_QUERY_NEED_OK; - prefix= "NEED-OK"; - alert_type = "confirmation"; - } - else if (flags & GET_USER_PASS_NEED_STR) - { - up_query_mode = UP_QUERY_NEED_STR; - prefix= "NEED-STR"; - alert_type = "string"; - } - else if (flags & GET_USER_PASS_PASSWORD_ONLY) - { - up_query_mode = UP_QUERY_PASS; - prefix = "PASSWORD"; - alert_type = "password"; - } - else - { - up_query_mode = UP_QUERY_USER_PASS; - prefix = "PASSWORD"; - alert_type = "username/password"; + ret = true; + man->persist.standalone_disabled = false; /* This is so M_CLIENT messages will be correctly passed through msg() */ + man->persist.special_state_msg = NULL; + + CLEAR(man->connection.up_query); + + if (flags & GET_USER_PASS_NEED_OK) + { + up_query_mode = UP_QUERY_NEED_OK; + prefix = "NEED-OK"; + alert_type = "confirmation"; + } + else if (flags & GET_USER_PASS_NEED_STR) + { + up_query_mode = UP_QUERY_NEED_STR; + prefix = "NEED-STR"; + alert_type = "string"; + } + else if (flags & GET_USER_PASS_PASSWORD_ONLY) + { + up_query_mode = UP_QUERY_PASS; + prefix = "PASSWORD"; + alert_type = "password"; + } + else + { + up_query_mode = UP_QUERY_USER_PASS; + prefix = "PASSWORD"; + alert_type = "username/password"; #ifdef ENABLE_CLIENT_CR - if (static_challenge) - sc = static_challenge; + if (static_challenge) + { + sc = static_challenge; + } #endif - } - buf_printf (&alert_msg, ">%s:Need '%s' %s", - prefix, - type, - alert_type); + } + buf_printf(&alert_msg, ">%s:Need '%s' %s", + prefix, + type, + alert_type); - if (flags & (GET_USER_PASS_NEED_OK | GET_USER_PASS_NEED_STR)) - buf_printf (&alert_msg, " MSG:%s", up->username); + if (flags & (GET_USER_PASS_NEED_OK | GET_USER_PASS_NEED_STR)) + { + buf_printf(&alert_msg, " MSG:%s", up->username); + } #ifdef ENABLE_CLIENT_CR - if (sc) - buf_printf (&alert_msg, " SC:%d,%s", - BOOL_CAST(flags & GET_USER_PASS_STATIC_CHALLENGE_ECHO), - sc); + if (sc) + { + buf_printf(&alert_msg, " SC:%d,%s", + BOOL_CAST(flags & GET_USER_PASS_STATIC_CHALLENGE_ECHO), + sc); + } #endif - man_wait_for_client_connection (man, &signal_received, 0, MWCC_PASSWORD_WAIT); - if (signal_received) - ret = false; - - if (ret) - { - man->persist.special_state_msg = BSTR (&alert_msg); - msg (M_CLIENT, "%s", man->persist.special_state_msg); - - /* tell command line parser which info we need */ - man->connection.up_query_mode = up_query_mode; - man->connection.up_query_type = type; - - /* run command processing event loop until we get our username/password/response */ - do - { - man_standalone_event_loop (man, &signal_received, 0); - if (!signal_received) - man_check_for_signals (&signal_received); - if (signal_received) - { - ret = false; - break; - } - } while (!man->connection.up_query.defined); - } - - /* revert state */ - man->connection.up_query_mode = UP_QUERY_DISABLED; - man->connection.up_query_type = NULL; - man->persist.standalone_disabled = standalone_disabled_save; - man->persist.special_state_msg = NULL; - - /* pass through blank passwords */ - if (!strcmp (man->connection.up_query.password, blank_up)) - CLEAR (man->connection.up_query.password); - - /* - * Transfer u/p to return object, zero any record - * we hold in the management object. - */ - if (ret) - { - man->connection.up_query.nocache = up->nocache; /* preserve caller's nocache setting */ - *up = man->connection.up_query; - } - secure_memzero (&man->connection.up_query, sizeof (man->connection.up_query)); - } - - gc_free (&gc); - return ret; + man_wait_for_client_connection(man, &signal_received, 0, MWCC_PASSWORD_WAIT); + if (signal_received) + { + ret = false; + } + + if (ret) + { + man->persist.special_state_msg = BSTR(&alert_msg); + msg(M_CLIENT, "%s", man->persist.special_state_msg); + + /* tell command line parser which info we need */ + man->connection.up_query_mode = up_query_mode; + man->connection.up_query_type = type; + + /* run command processing event loop until we get our username/password/response */ + do + { + man_standalone_event_loop(man, &signal_received, 0); + if (!signal_received) + { + man_check_for_signals(&signal_received); + } + if (signal_received) + { + ret = false; + break; + } + } while (!man->connection.up_query.defined); + } + + /* revert state */ + man->connection.up_query_mode = UP_QUERY_DISABLED; + man->connection.up_query_type = NULL; + man->persist.standalone_disabled = standalone_disabled_save; + man->persist.special_state_msg = NULL; + + /* pass through blank passwords */ + if (!strcmp(man->connection.up_query.password, blank_up)) + { + CLEAR(man->connection.up_query.password); + } + + /* + * Transfer u/p to return object, zero any record + * we hold in the management object. + */ + if (ret) + { + man->connection.up_query.nocache = up->nocache; /* preserve caller's nocache setting */ + *up = man->connection.up_query; + } + secure_memzero(&man->connection.up_query, sizeof(man->connection.up_query)); + } + + gc_free(&gc); + return ret; } #ifdef MANAGMENT_EXTERNAL_KEY int -management_query_multiline (struct management *man, - const char *b64_data, const char *prompt, const char *cmd, int *state, struct buffer_list **input) +management_query_multiline(struct management *man, + const char *b64_data, const char *prompt, const char *cmd, int *state, struct buffer_list **input) { - struct gc_arena gc = gc_new (); - int ret = 0; - volatile int signal_received = 0; - struct buffer alert_msg = clear_buf(); - const bool standalone_disabled_save = man->persist.standalone_disabled; - struct man_connection *mc = &man->connection; + struct gc_arena gc = gc_new(); + int ret = 0; + volatile int signal_received = 0; + struct buffer alert_msg = clear_buf(); + const bool standalone_disabled_save = man->persist.standalone_disabled; + struct man_connection *mc = &man->connection; - if (man_standalone_ok (man)) + if (man_standalone_ok(man)) { - man->persist.standalone_disabled = false; /* This is so M_CLIENT messages will be correctly passed through msg() */ - man->persist.special_state_msg = NULL; + man->persist.standalone_disabled = false; /* This is so M_CLIENT messages will be correctly passed through msg() */ + man->persist.special_state_msg = NULL; - *state = EKS_SOLICIT; + *state = EKS_SOLICIT; - if (b64_data) { - alert_msg = alloc_buf_gc (strlen(b64_data)+strlen(prompt)+3, &gc); - buf_printf (&alert_msg, ">%s:%s", prompt, b64_data); - } else { - alert_msg = alloc_buf_gc (strlen(prompt)+3, &gc); - buf_printf (&alert_msg, ">%s", prompt); - } + if (b64_data) + { + alert_msg = alloc_buf_gc(strlen(b64_data)+strlen(prompt)+3, &gc); + buf_printf(&alert_msg, ">%s:%s", prompt, b64_data); + } + else + { + alert_msg = alloc_buf_gc(strlen(prompt)+3, &gc); + buf_printf(&alert_msg, ">%s", prompt); + } - man_wait_for_client_connection (man, &signal_received, 0, MWCC_OTHER_WAIT); + man_wait_for_client_connection(man, &signal_received, 0, MWCC_OTHER_WAIT); - if (signal_received) - goto done; + if (signal_received) + { + goto done; + } - man->persist.special_state_msg = BSTR (&alert_msg); - msg (M_CLIENT, "%s", man->persist.special_state_msg); + man->persist.special_state_msg = BSTR(&alert_msg); + msg(M_CLIENT, "%s", man->persist.special_state_msg); - /* run command processing event loop until we get our signature */ - do - { - man_standalone_event_loop (man, &signal_received, 0); - if (!signal_received) - man_check_for_signals (&signal_received); - if (signal_received) - goto done; - } while (*state != EKS_READY); + /* run command processing event loop until we get our signature */ + do + { + man_standalone_event_loop(man, &signal_received, 0); + if (!signal_received) + { + man_check_for_signals(&signal_received); + } + if (signal_received) + { + goto done; + } + } while (*state != EKS_READY); - ret = 1; + ret = 1; } - done: - if (*state == EKS_READY && ret) - msg (M_CLIENT, "SUCCESS: %s command succeeded", cmd); - else if (*state == EKS_INPUT || *state == EKS_READY) - msg (M_CLIENT, "ERROR: %s command failed", cmd); +done: + if (*state == EKS_READY && ret) + { + msg(M_CLIENT, "SUCCESS: %s command succeeded", cmd); + } + else if (*state == EKS_INPUT || *state == EKS_READY) + { + msg(M_CLIENT, "ERROR: %s command failed", cmd); + } - /* revert state */ - man->persist.standalone_disabled = standalone_disabled_save; - man->persist.special_state_msg = NULL; - in_extra_reset (mc, IER_RESET); - *state = EKS_UNDEF; + /* revert state */ + man->persist.standalone_disabled = standalone_disabled_save; + man->persist.special_state_msg = NULL; + in_extra_reset(mc, IER_RESET); + *state = EKS_UNDEF; - gc_free (&gc); - return ret; + gc_free(&gc); + return ret; } -char * /* returns allocated base64 signature */ -management_query_multiline_flatten_newline (struct management *man, - const char *b64_data, const char *prompt, const char *cmd, int *state, struct buffer_list **input) +char * +/* returns allocated base64 signature */ +management_query_multiline_flatten_newline(struct management *man, + const char *b64_data, const char *prompt, const char *cmd, int *state, struct buffer_list **input) { - int ok; - char *result = NULL; - struct buffer *buf; + int ok; + char *result = NULL; + struct buffer *buf; - ok = management_query_multiline(man, b64_data, prompt, cmd, state, input); - if (ok && buffer_list_defined(*input)) - { - buffer_list_aggregate_separator (*input, 10000, "\n"); - buf = buffer_list_peek (*input); - if (buf && BLEN(buf) > 0) + ok = management_query_multiline(man, b64_data, prompt, cmd, state, input); + if (ok && buffer_list_defined(*input)) { - result = (char *) malloc(BLEN(buf)+1); - check_malloc_return(result); - memcpy(result, buf->data, BLEN(buf)); - result[BLEN(buf)] = '\0'; + buffer_list_aggregate_separator(*input, 10000, "\n"); + buf = buffer_list_peek(*input); + if (buf && BLEN(buf) > 0) + { + result = (char *) malloc(BLEN(buf)+1); + check_malloc_return(result); + memcpy(result, buf->data, BLEN(buf)); + result[BLEN(buf)] = '\0'; + } } - } - buffer_list_free (*input); - *input = NULL; + buffer_list_free(*input); + *input = NULL; - return result; + return result; } -char * /* returns allocated base64 signature */ -management_query_multiline_flatten (struct management *man, - const char *b64_data, const char *prompt, const char *cmd, int *state, struct buffer_list **input) +char * +/* returns allocated base64 signature */ +management_query_multiline_flatten(struct management *man, + const char *b64_data, const char *prompt, const char *cmd, int *state, struct buffer_list **input) { - int ok; - char *result = NULL; - struct buffer *buf; + int ok; + char *result = NULL; + struct buffer *buf; - ok = management_query_multiline(man, b64_data, prompt, cmd, state, input); - if (ok && buffer_list_defined(*input)) - { - buffer_list_aggregate (*input, 2048); - buf = buffer_list_peek (*input); - if (buf && BLEN(buf) > 0) + ok = management_query_multiline(man, b64_data, prompt, cmd, state, input); + if (ok && buffer_list_defined(*input)) { - result = (char *) malloc(BLEN(buf)+1); - check_malloc_return(result); - memcpy(result, buf->data, BLEN(buf)); - result[BLEN(buf)] = '\0'; + buffer_list_aggregate(*input, 2048); + buf = buffer_list_peek(*input); + if (buf && BLEN(buf) > 0) + { + result = (char *) malloc(BLEN(buf)+1); + check_malloc_return(result); + memcpy(result, buf->data, BLEN(buf)); + result[BLEN(buf)] = '\0'; + } } - } - buffer_list_free (*input); - *input = NULL; + buffer_list_free(*input); + *input = NULL; - return result; + return result; } -char * /* returns allocated base64 signature */ -management_query_rsa_sig (struct management *man, - const char *b64_data) +char * +/* returns allocated base64 signature */ +management_query_rsa_sig(struct management *man, + const char *b64_data) { - return management_query_multiline_flatten(man, b64_data, "RSA_SIGN", "rsa-sign", - &man->connection.ext_key_state, &man->connection.ext_key_input); + return management_query_multiline_flatten(man, b64_data, "RSA_SIGN", "rsa-sign", + &man->connection.ext_key_state, &man->connection.ext_key_input); } -char* management_query_cert (struct management *man, const char *cert_name) +char * +management_query_cert(struct management *man, const char *cert_name) { - const char prompt_1[] = "NEED-CERTIFICATE:"; - struct buffer buf_prompt = alloc_buf(strlen(cert_name) + 20); - buf_write(&buf_prompt, prompt_1, strlen(prompt_1)); - buf_write(&buf_prompt, cert_name, strlen(cert_name)+1); // +1 for \0 + const char prompt_1[] = "NEED-CERTIFICATE:"; + struct buffer buf_prompt = alloc_buf(strlen(cert_name) + 20); + buf_write(&buf_prompt, prompt_1, strlen(prompt_1)); + buf_write(&buf_prompt, cert_name, strlen(cert_name)+1); /* +1 for \0 */ - char *result; - result = management_query_multiline_flatten_newline(management, - NULL, (char*)buf_bptr(&buf_prompt), "certificate", - &man->connection.ext_cert_state, &man->connection.ext_cert_input); - free_buf(&buf_prompt); - return result; + char *result; + result = management_query_multiline_flatten_newline(management, + NULL, (char *)buf_bptr(&buf_prompt), "certificate", + &man->connection.ext_cert_state, &man->connection.ext_cert_input); + free_buf(&buf_prompt); + return result; } -#endif +#endif /* ifdef MANAGMENT_EXTERNAL_KEY */ /* * Return true if management_hold() would block */ bool -management_would_hold (struct management *man) +management_would_hold(struct management *man) { - return (man->settings.flags & MF_HOLD) && !man->persist.hold_release && man_standalone_ok (man); + return (man->settings.flags & MF_HOLD) && !man->persist.hold_release && man_standalone_ok(man); } /* @@ -3320,9 +3689,9 @@ management_would_hold (struct management *man) * daemonize. */ bool -management_should_daemonize (struct management *man) +management_should_daemonize(struct management *man) { - return management_would_hold (man) || (man->settings.flags & MF_QUERY_PASSWORDS); + return management_would_hold(man) || (man->settings.flags & MF_QUERY_PASSWORDS); } /* @@ -3330,47 +3699,51 @@ management_should_daemonize (struct management *man) * Return true if the caller should not sleep for an additional time interval. */ bool -management_hold (struct management *man, int holdtime) +management_hold(struct management *man, int holdtime) { - if (management_would_hold (man)) + if (management_would_hold(man)) { - volatile int signal_received = 0; - const bool standalone_disabled_save = man->persist.standalone_disabled; - struct gc_arena gc = gc_new (); - - man->persist.standalone_disabled = false; /* This is so M_CLIENT messages will be correctly passed through msg() */ - man->persist.special_state_msg = NULL; - man->settings.mansig |= MANSIG_IGNORE_USR1_HUP; - - man_wait_for_client_connection (man, &signal_received, 0, MWCC_HOLD_WAIT); + volatile int signal_received = 0; + const bool standalone_disabled_save = man->persist.standalone_disabled; + struct gc_arena gc = gc_new(); - if (!signal_received) - { - struct buffer out = alloc_buf_gc (128, &gc); - buf_printf (&out, ">HOLD:Waiting for hold release:%d", holdtime); - man->persist.special_state_msg = BSTR (&out); - msg (M_CLIENT, "%s", man->persist.special_state_msg); + man->persist.standalone_disabled = false; /* This is so M_CLIENT messages will be correctly passed through msg() */ + man->persist.special_state_msg = NULL; + man->settings.mansig |= MANSIG_IGNORE_USR1_HUP; - /* run command processing event loop until we get our username/password */ - do - { - man_standalone_event_loop (man, &signal_received, 0); - if (!signal_received) - man_check_for_signals (&signal_received); - if (signal_received) - break; - } while (!man->persist.hold_release); - } + man_wait_for_client_connection(man, &signal_received, 0, MWCC_HOLD_WAIT); - /* revert state */ - man->persist.standalone_disabled = standalone_disabled_save; - man->persist.special_state_msg = NULL; - man->settings.mansig &= ~MANSIG_IGNORE_USR1_HUP; - - gc_free (&gc); - return true; + if (!signal_received) + { + struct buffer out = alloc_buf_gc(128, &gc); + buf_printf(&out, ">HOLD:Waiting for hold release:%d", holdtime); + man->persist.special_state_msg = BSTR(&out); + msg(M_CLIENT, "%s", man->persist.special_state_msg); + + /* run command processing event loop until we get our username/password */ + do + { + man_standalone_event_loop(man, &signal_received, 0); + if (!signal_received) + { + man_check_for_signals(&signal_received); + } + if (signal_received) + { + break; + } + } while (!man->persist.hold_release); + } + + /* revert state */ + man->persist.standalone_disabled = standalone_disabled_save; + man->persist.special_state_msg = NULL; + man->settings.mansig &= ~MANSIG_IGNORE_USR1_HUP; + + gc_free(&gc); + return true; } - return false; + return false; } /* @@ -3378,67 +3751,69 @@ management_hold (struct management *man, int holdtime) */ struct command_line * -command_line_new (const int buf_len) +command_line_new(const int buf_len) { - struct command_line *cl; - ALLOC_OBJ_CLEAR (cl, struct command_line); - cl->buf = alloc_buf (buf_len); - cl->residual = alloc_buf (buf_len); - return cl; + struct command_line *cl; + ALLOC_OBJ_CLEAR(cl, struct command_line); + cl->buf = alloc_buf(buf_len); + cl->residual = alloc_buf(buf_len); + return cl; } void -command_line_reset (struct command_line *cl) +command_line_reset(struct command_line *cl) { - buf_clear (&cl->buf); - buf_clear (&cl->residual); + buf_clear(&cl->buf); + buf_clear(&cl->residual); } void -command_line_free (struct command_line *cl) +command_line_free(struct command_line *cl) { - command_line_reset (cl); - free_buf (&cl->buf); - free_buf (&cl->residual); - free (cl); + command_line_reset(cl); + free_buf(&cl->buf); + free_buf(&cl->residual); + free(cl); } void -command_line_add (struct command_line *cl, const unsigned char *buf, const int len) +command_line_add(struct command_line *cl, const unsigned char *buf, const int len) { - int i; - for (i = 0; i < len; ++i) + int i; + for (i = 0; i < len; ++i) { - if (buf[i] && char_class(buf[i], (CC_PRINT|CC_NEWLINE))) - { - if (!buf_write_u8 (&cl->buf, buf[i])) - buf_clear (&cl->buf); - } + if (buf[i] && char_class(buf[i], (CC_PRINT|CC_NEWLINE))) + { + if (!buf_write_u8(&cl->buf, buf[i])) + { + buf_clear(&cl->buf); + } + } } } const unsigned char * -command_line_get (struct command_line *cl) +command_line_get(struct command_line *cl) { - int i; - const unsigned char *ret = NULL; + int i; + const unsigned char *ret = NULL; - i = buf_substring_len (&cl->buf, '\n'); - if (i >= 0) + i = buf_substring_len(&cl->buf, '\n'); + if (i >= 0) { - buf_copy_excess (&cl->residual, &cl->buf, i); - buf_chomp (&cl->buf); - ret = (const unsigned char *) BSTR (&cl->buf); + buf_copy_excess(&cl->residual, &cl->buf, i); + buf_chomp(&cl->buf); + ret = (const unsigned char *) BSTR(&cl->buf); } - return ret; + return ret; } void -command_line_next (struct command_line *cl) +command_line_next(struct command_line *cl) { - buf_clear (&cl->buf); - buf_copy (&cl->buf, &cl->residual); - buf_clear (&cl->residual); + buf_clear(&cl->buf); + buf_copy(&cl->buf, &cl->residual); + buf_clear(&cl->residual); } /* @@ -3446,51 +3821,79 @@ command_line_next (struct command_line *cl) */ const char * -log_entry_print (const struct log_entry *e, unsigned int flags, struct gc_arena *gc) -{ - struct buffer out = alloc_buf_gc (ERR_BUF_SIZE, gc); - if (flags & LOG_FATAL_NOTIFY) - buf_printf (&out, ">FATAL:"); - if (flags & LOG_PRINT_LOG_PREFIX) - buf_printf (&out, ">LOG:"); - if (flags & LOG_PRINT_ECHO_PREFIX) - buf_printf (&out, ">ECHO:"); - if (flags & LOG_PRINT_STATE_PREFIX) - buf_printf (&out, ">STATE:"); - if (flags & LOG_PRINT_INT_DATE) - buf_printf (&out, "%u,", (unsigned int)e->timestamp); - if (flags & LOG_PRINT_MSG_FLAGS) - buf_printf (&out, "%s,", msg_flags_string (e->u.msg_flags, gc)); - if (flags & LOG_PRINT_STATE) - buf_printf (&out, "%s,", man_state_name (e->u.state)); - if (flags & LOG_PRINT_INTVAL) - buf_printf (&out, "%d,", e->u.intval); - if (e->string) - buf_printf (&out, "%s", e->string); - if (flags & LOG_PRINT_LOCAL_IP) - 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", (!addr_defined (&e->remote_sock) ? "," : - print_sockaddr_ex (&e->remote_sock.addr.sa, ",", PS_DONT_SHOW_FAMILY|PS_SHOW_PORT, gc))); - buf_printf (&out, ",%s", (!addr_defined (&e->local_sock) ? "," : - print_sockaddr_ex (&e->local_sock.addr.sa, ",", PS_DONT_SHOW_FAMILY|PS_SHOW_PORT, gc))); - } - if (flags & LOG_PRINT_LOCAL_IP && !IN6_IS_ADDR_UNSPECIFIED(&e->local_ip6)) - buf_printf (&out, ",%s", print_in6_addr (e->local_ip6, IA_EMPTY_IF_UNDEF, gc)); - if (flags & LOG_ECHO_TO_LOG) - msg (D_MANAGEMENT, "MANAGEMENT: %s", BSTR (&out)); - if (flags & LOG_PRINT_CRLF) - buf_printf (&out, "\r\n"); - return BSTR (&out); -} - -static void -log_entry_free_contents (struct log_entry *e) -{ - if (e->string) - free ((char *)e->string); - CLEAR (*e); +log_entry_print(const struct log_entry *e, unsigned int flags, struct gc_arena *gc) +{ + struct buffer out = alloc_buf_gc(ERR_BUF_SIZE, gc); + if (flags & LOG_FATAL_NOTIFY) + { + buf_printf(&out, ">FATAL:"); + } + if (flags & LOG_PRINT_LOG_PREFIX) + { + buf_printf(&out, ">LOG:"); + } + if (flags & LOG_PRINT_ECHO_PREFIX) + { + buf_printf(&out, ">ECHO:"); + } + if (flags & LOG_PRINT_STATE_PREFIX) + { + buf_printf(&out, ">STATE:"); + } + if (flags & LOG_PRINT_INT_DATE) + { + buf_printf(&out, "%u,", (unsigned int)e->timestamp); + } + if (flags & LOG_PRINT_MSG_FLAGS) + { + buf_printf(&out, "%s,", msg_flags_string(e->u.msg_flags, gc)); + } + if (flags & LOG_PRINT_STATE) + { + buf_printf(&out, "%s,", man_state_name(e->u.state)); + } + if (flags & LOG_PRINT_INTVAL) + { + buf_printf(&out, "%d,", e->u.intval); + } + if (e->string) + { + buf_printf(&out, "%s", e->string); + } + if (flags & LOG_PRINT_LOCAL_IP) + { + 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", (!addr_defined(&e->remote_sock) ? "," : + print_sockaddr_ex(&e->remote_sock.addr.sa, ",", PS_DONT_SHOW_FAMILY|PS_SHOW_PORT, gc))); + buf_printf(&out, ",%s", (!addr_defined(&e->local_sock) ? "," : + print_sockaddr_ex(&e->local_sock.addr.sa, ",", PS_DONT_SHOW_FAMILY|PS_SHOW_PORT, gc))); + } + if (flags & LOG_PRINT_LOCAL_IP && !IN6_IS_ADDR_UNSPECIFIED(&e->local_ip6)) + { + buf_printf(&out, ",%s", print_in6_addr(e->local_ip6, IA_EMPTY_IF_UNDEF, gc)); + } + if (flags & LOG_ECHO_TO_LOG) + { + msg(D_MANAGEMENT, "MANAGEMENT: %s", BSTR(&out)); + } + if (flags & LOG_PRINT_CRLF) + { + buf_printf(&out, "\r\n"); + } + return BSTR(&out); +} + +static void +log_entry_free_contents(struct log_entry *e) +{ + if (e->string) + { + free((char *)e->string); + } + CLEAR(*e); } /* @@ -3498,94 +3901,100 @@ log_entry_free_contents (struct log_entry *e) */ static inline int -log_index (const struct log_history *h, int i) +log_index(const struct log_history *h, int i) { - return modulo_add (h->base, i, h->capacity); + return modulo_add(h->base, i, h->capacity); } static void -log_history_obj_init (struct log_history *h, int capacity) +log_history_obj_init(struct log_history *h, int capacity) { - CLEAR (*h); - h->capacity = capacity; - ALLOC_ARRAY_CLEAR (h->array, struct log_entry, capacity); + CLEAR(*h); + h->capacity = capacity; + ALLOC_ARRAY_CLEAR(h->array, struct log_entry, capacity); } struct log_history * -log_history_init (const int capacity) +log_history_init(const int capacity) { - struct log_history *h; - ASSERT (capacity > 0); - ALLOC_OBJ (h, struct log_history); - log_history_obj_init (h, capacity); - return h; + struct log_history *h; + ASSERT(capacity > 0); + ALLOC_OBJ(h, struct log_history); + log_history_obj_init(h, capacity); + return h; } static void -log_history_free_contents (struct log_history *h) +log_history_free_contents(struct log_history *h) { - int i; - for (i = 0; i < h->size; ++i) - log_entry_free_contents (&h->array[log_index(h, i)]); - free (h->array); + int i; + for (i = 0; i < h->size; ++i) + log_entry_free_contents(&h->array[log_index(h, i)]); + free(h->array); } void -log_history_close (struct log_history *h) +log_history_close(struct log_history *h) { - log_history_free_contents (h); - free (h); + log_history_free_contents(h); + free(h); } void -log_history_add (struct log_history *h, const struct log_entry *le) +log_history_add(struct log_history *h, const struct log_entry *le) { - struct log_entry *e; - ASSERT (h->size >= 0 && h->size <= h->capacity); - if (h->size == h->capacity) + struct log_entry *e; + ASSERT(h->size >= 0 && h->size <= h->capacity); + if (h->size == h->capacity) { - e = &h->array[h->base]; - log_entry_free_contents (e); - h->base = log_index (h, 1); + e = &h->array[h->base]; + log_entry_free_contents(e); + h->base = log_index(h, 1); } - else + else { - e = &h->array[log_index(h, h->size)]; - ++h->size; + e = &h->array[log_index(h, h->size)]; + ++h->size; } - *e = *le; - e->string = string_alloc (le->string, NULL); + *e = *le; + e->string = string_alloc(le->string, NULL); } void -log_history_resize (struct log_history *h, const int capacity) +log_history_resize(struct log_history *h, const int capacity) { - if (capacity != h->capacity) + if (capacity != h->capacity) { - struct log_history newlog; - int i; + struct log_history newlog; + int i; + + ASSERT(capacity > 0); + log_history_obj_init(&newlog, capacity); - ASSERT (capacity > 0); - log_history_obj_init (&newlog, capacity); + for (i = 0; i < h->size; ++i) + log_history_add(&newlog, &h->array[log_index(h, i)]); - for (i = 0; i < h->size; ++i) - log_history_add (&newlog, &h->array[log_index(h, i)]); - - log_history_free_contents (h); - *h = newlog; + log_history_free_contents(h); + *h = newlog; } } const struct log_entry * -log_history_ref (const struct log_history *h, const int index) +log_history_ref(const struct log_history *h, const int index) { - if (index >= 0 && index < h->size) - return &h->array[log_index(h, (h->size - 1) - index)]; - else - return NULL; + if (index >= 0 && index < h->size) + { + return &h->array[log_index(h, (h->size - 1) - index)]; + } + else + { + return NULL; + } } -#else -static void dummy(void) {} +#else /* ifdef ENABLE_MANAGEMENT */ +static void +dummy(void) { +} #endif /* ENABLE_MANAGEMENT */ diff --git a/src/openvpn/manage.h b/src/openvpn/manage.h index 3ffced07a52..7e022f01231 100644 --- a/src/openvpn/manage.h +++ b/src/openvpn/manage.h @@ -43,16 +43,16 @@ */ #ifdef MANAGEMENT_DEF_AUTH struct man_def_auth_context { - unsigned long cid; + unsigned long cid; #define DAF_CONNECTION_ESTABLISHED (1<<0) #define DAF_CONNECTION_CLOSED (1<<1) #define DAF_INITIAL_AUTH (1<<2) - unsigned int flags; + unsigned int flags; - unsigned int mda_key_id_counter; + unsigned int mda_key_id_counter; - time_t bytecount_last_update; + time_t bytecount_last_update; }; #endif @@ -61,37 +61,41 @@ struct man_def_auth_context { */ struct command_line { - struct buffer buf; - struct buffer residual; + struct buffer buf; + struct buffer residual; }; -struct command_line *command_line_new (const int buf_len); -void command_line_free (struct command_line *cl); +struct command_line *command_line_new(const int buf_len); -void command_line_add (struct command_line *cl, const unsigned char *buf, const int len); -const unsigned char *command_line_get (struct command_line *cl); -void command_line_reset (struct command_line *cl); -void command_line_next (struct command_line *cl); +void command_line_free(struct command_line *cl); + +void command_line_add(struct command_line *cl, const unsigned char *buf, const int len); + +const unsigned char *command_line_get(struct command_line *cl); + +void command_line_reset(struct command_line *cl); + +void command_line_next(struct command_line *cl); /* * Manage log file history */ union log_entry_union { - unsigned int msg_flags; - int state; - int intval; + unsigned int msg_flags; + int state; + int intval; }; struct log_entry { - time_t timestamp; - const char *string; - in_addr_t local_ip; - struct in6_addr local_ip6; - struct openvpn_sockaddr local_sock; - struct openvpn_sockaddr remote_sock; - union log_entry_union u; + time_t timestamp; + const char *string; + in_addr_t local_ip; + struct in6_addr local_ip6; + struct openvpn_sockaddr local_sock; + struct openvpn_sockaddr remote_sock; + union log_entry_union u; }; #define LOG_PRINT_LOG_PREFIX (1<<0) @@ -112,32 +116,36 @@ struct log_entry #define LOG_ECHO_TO_LOG (1<<11) -const char *log_entry_print (const struct log_entry *e, unsigned int flags, struct gc_arena *gc); +const char *log_entry_print(const struct log_entry *e, unsigned int flags, struct gc_arena *gc); struct log_history { - int base; - int size; - int capacity; - struct log_entry *array; + int base; + int size; + int capacity; + struct log_entry *array; }; -struct log_history *log_history_init (const int capacity); -void log_history_close (struct log_history *h); -void log_history_add (struct log_history *h, const struct log_entry *le); -void log_history_resize (struct log_history *h, const int capacity); -const struct log_entry *log_history_ref (const struct log_history *h, const int index); +struct log_history *log_history_init(const int capacity); + +void log_history_close(struct log_history *h); + +void log_history_add(struct log_history *h, const struct log_entry *le); + +void log_history_resize(struct log_history *h, const int capacity); + +const struct log_entry *log_history_ref(const struct log_history *h, const int index); static inline int -log_history_size (const struct log_history *h) +log_history_size(const struct log_history *h) { - return h->size; + return h->size; } static inline int -log_history_capacity (const struct log_history *h) +log_history_capacity(const struct log_history *h) { - return h->capacity; + return h->capacity; } /* @@ -146,37 +154,37 @@ log_history_capacity (const struct log_history *h) */ struct management_callback { - void *arg; + void *arg; -# define MCF_SERVER (1<<0) /* is OpenVPN being run as a server? */ - unsigned int flags; +#define MCF_SERVER (1<<0) /* is OpenVPN being run as a server? */ + unsigned int flags; - void (*status) (void *arg, const int version, struct status_output *so); - void (*show_net) (void *arg, const int msglevel); - int (*kill_by_cn) (void *arg, const char *common_name); - int (*kill_by_addr) (void *arg, const in_addr_t addr, const int port); - void (*delete_event) (void *arg, event_t event); - int (*n_clients) (void *arg); + void (*status) (void *arg, const int version, struct status_output *so); + void (*show_net) (void *arg, const int msglevel); + int (*kill_by_cn) (void *arg, const char *common_name); + int (*kill_by_addr) (void *arg, const in_addr_t addr, const int port); + void (*delete_event) (void *arg, event_t event); + int (*n_clients) (void *arg); #ifdef MANAGEMENT_DEF_AUTH - bool (*kill_by_cid) (void *arg, const unsigned long cid, const char *kill_msg); - bool (*client_auth) (void *arg, - const unsigned long cid, - const unsigned int mda_key_id, - const bool auth, - const char *reason, - const char *client_reason, - struct buffer_list *cc_config); /* ownership transferred */ - char *(*get_peer_info) (void *arg, const unsigned long cid); + bool (*kill_by_cid)(void *arg, const unsigned long cid, const char *kill_msg); + bool (*client_auth) (void *arg, + const unsigned long cid, + const unsigned int mda_key_id, + const bool auth, + const char *reason, + const char *client_reason, + struct buffer_list *cc_config); /* ownership transferred */ + char *(*get_peer_info) (void *arg, const unsigned long cid); #endif #ifdef MANAGEMENT_PF - bool (*client_pf) (void *arg, - const unsigned long cid, - struct buffer_list *pf_config); /* ownership transferred */ + bool (*client_pf)(void *arg, + const unsigned long cid, + struct buffer_list *pf_config); /* ownership transferred */ #endif - bool (*proxy_cmd) (void *arg, const char **p); - bool (*remote_cmd) (void *arg, const char **p); + bool (*proxy_cmd)(void *arg, const char **p); + bool (*remote_cmd) (void *arg, const char **p); #ifdef TARGET_ANDROID - int (*network_change) (void *arg, bool samenetwork); + int (*network_change)(void *arg, bool samenetwork); #endif }; @@ -195,46 +203,46 @@ struct management_callback */ struct man_persist { - bool defined; + bool defined; - struct log_history *log; - struct virtual_output vout; + struct log_history *log; + struct virtual_output vout; - bool standalone_disabled; - struct management_callback callback; + bool standalone_disabled; + struct management_callback callback; - struct log_history *echo; /* saved --echo strings */ - struct log_history *state; + struct log_history *echo; /* saved --echo strings */ + struct log_history *state; - bool hold_release; + bool hold_release; - const char *special_state_msg; + const char *special_state_msg; - counter_type bytes_in; - counter_type bytes_out; + counter_type bytes_in; + counter_type bytes_out; }; struct man_settings { - bool defined; - unsigned int flags; /* MF_x flags */ - struct addrinfo* local; + bool defined; + unsigned int flags; /* MF_x flags */ + struct addrinfo *local; #if UNIX_SOCK_SUPPORT - struct sockaddr_un local_unix; + struct sockaddr_un local_unix; #endif - bool management_over_tunnel; - struct user_pass up; - int log_history_cache; - int echo_buffer_size; - int state_buffer_size; - char *write_peer_info_file; - int client_uid; - int client_gid; + bool management_over_tunnel; + struct user_pass up; + int log_history_cache; + int echo_buffer_size; + int state_buffer_size; + char *write_peer_info_file; + int client_uid; + int client_gid; /* flags for handling the management interface "signal" command */ -# define MANSIG_IGNORE_USR1_HUP (1<<0) -# define MANSIG_MAP_USR1_TO_HUP (1<<1) -# define MANSIG_MAP_USR1_TO_TERM (1<<2) - unsigned int mansig; +#define MANSIG_IGNORE_USR1_HUP (1<<0) +#define MANSIG_MAP_USR1_TO_HUP (1<<1) +#define MANSIG_MAP_USR1_TO_TERM (1<<2) + unsigned int mansig; }; /* up_query modes */ @@ -251,225 +259,230 @@ struct man_settings { #define MS_CC_WAIT_WRITE 3 /* client is connected, waiting for ability to write to socket */ struct man_connection { - int state; + int state; - socket_descriptor_t sd_top; - socket_descriptor_t sd_cli; - struct openvpn_sockaddr remote; + socket_descriptor_t sd_top; + socket_descriptor_t sd_cli; + struct openvpn_sockaddr remote; #ifdef _WIN32 - struct net_event_win32 ne32; + struct net_event_win32 ne32; #endif - bool halt; - bool password_verified; - int password_tries; + bool halt; + bool password_verified; + int password_tries; - struct command_line *in; - struct buffer_list *out; + struct command_line *in; + struct buffer_list *out; #ifdef MANAGEMENT_IN_EXTRA -# define IEC_UNDEF 0 -# define IEC_CLIENT_AUTH 1 -# define IEC_CLIENT_PF 2 -# define IEC_RSA_SIGN 3 -# define IEC_CERTIFICATE 4 - int in_extra_cmd; - struct buffer_list *in_extra; +#define IEC_UNDEF 0 +#define IEC_CLIENT_AUTH 1 +#define IEC_CLIENT_PF 2 +#define IEC_RSA_SIGN 3 +#define IEC_CERTIFICATE 4 + int in_extra_cmd; + struct buffer_list *in_extra; #ifdef MANAGEMENT_DEF_AUTH - unsigned long in_extra_cid; - unsigned int in_extra_kid; + unsigned long in_extra_cid; + unsigned int in_extra_kid; #endif #ifdef MANAGMENT_EXTERNAL_KEY -# define EKS_UNDEF 0 -# define EKS_SOLICIT 1 -# define EKS_INPUT 2 -# define EKS_READY 3 - int ext_key_state; - struct buffer_list *ext_key_input; - int ext_cert_state; - struct buffer_list *ext_cert_input; +#define EKS_UNDEF 0 +#define EKS_SOLICIT 1 +#define EKS_INPUT 2 +#define EKS_READY 3 + int ext_key_state; + struct buffer_list *ext_key_input; + int ext_cert_state; + struct buffer_list *ext_cert_input; #endif -#endif - struct event_set *es; - int env_filter_level; +#endif /* ifdef MANAGEMENT_IN_EXTRA */ + struct event_set *es; + int env_filter_level; - bool state_realtime; - bool log_realtime; - bool echo_realtime; - int bytecount_update_seconds; - time_t bytecount_last_update; + bool state_realtime; + bool log_realtime; + bool echo_realtime; + int bytecount_update_seconds; + time_t bytecount_last_update; - const char *up_query_type; - int up_query_mode; - struct user_pass up_query; + const char *up_query_type; + int up_query_mode; + struct user_pass up_query; #ifdef MANAGMENT_EXTERNAL_KEY - struct buffer_list *rsa_sig; + struct buffer_list *rsa_sig; #endif #ifdef TARGET_ANDROID - int fdtosend; - int lastfdreceived; + int fdtosend; + int lastfdreceived; #endif }; struct management { - struct man_persist persist; - struct man_settings settings; - struct man_connection connection; + struct man_persist persist; + struct man_settings settings; + struct man_connection connection; }; extern struct management *management; struct user_pass; -struct management *management_init (void); +struct management *management_init(void); /* management_open flags */ -# define MF_SERVER (1<<0) -# define MF_QUERY_PASSWORDS (1<<1) -# define MF_HOLD (1<<2) -# define MF_SIGNAL (1<<3) -# define MF_FORGET_DISCONNECT (1<<4) -# define MF_CONNECT_AS_CLIENT (1<<5) +#define MF_SERVER (1<<0) +#define MF_QUERY_PASSWORDS (1<<1) +#define MF_HOLD (1<<2) +#define MF_SIGNAL (1<<3) +#define MF_FORGET_DISCONNECT (1<<4) +#define MF_CONNECT_AS_CLIENT (1<<5) #ifdef MANAGEMENT_DEF_AUTH -# define MF_CLIENT_AUTH (1<<6) +#define MF_CLIENT_AUTH (1<<6) #endif #ifdef MANAGEMENT_PF -# define MF_CLIENT_PF (1<<7) +#define MF_CLIENT_PF (1<<7) #endif -# define MF_UNIX_SOCK (1<<8) +#define MF_UNIX_SOCK (1<<8) #ifdef MANAGMENT_EXTERNAL_KEY -# define MF_EXTERNAL_KEY (1<<9) +#define MF_EXTERNAL_KEY (1<<9) #endif #define MF_UP_DOWN (1<<10) #define MF_QUERY_REMOTE (1<<11) #define MF_QUERY_PROXY (1<<12) #define MF_EXTERNAL_CERT (1<<13) -bool management_open (struct management *man, - const char *addr, - const char *port, - const char *pass_file, - const char *client_user, - const char *client_group, - const int log_history_cache, - const int echo_buffer_size, - const int state_buffer_size, - const char *write_peer_info_file, - const int remap_sigusr1, - const unsigned int flags); +bool management_open(struct management *man, + const char *addr, + const char *port, + const char *pass_file, + const char *client_user, + const char *client_group, + const int log_history_cache, + const int echo_buffer_size, + const int state_buffer_size, + const char *write_peer_info_file, + const int remap_sigusr1, + const unsigned int flags); -void management_close (struct management *man); +void management_close(struct management *man); -void management_post_tunnel_open (struct management *man, const in_addr_t tun_local_ip); +void management_post_tunnel_open(struct management *man, const in_addr_t tun_local_ip); -void management_pre_tunnel_close (struct management *man); +void management_pre_tunnel_close(struct management *man); -void management_socket_set (struct management *man, - struct event_set *es, - void *arg, - unsigned int *persistent); +void management_socket_set(struct management *man, + struct event_set *es, + void *arg, + unsigned int *persistent); -void management_io (struct management *man); +void management_io(struct management *man); -void management_set_callback (struct management *man, - const struct management_callback *cb); +void management_set_callback(struct management *man, + const struct management_callback *cb); -void management_clear_callback (struct management *man); +void management_clear_callback(struct management *man); -bool management_query_user_pass (struct management *man, - struct user_pass *up, - const char *type, - const unsigned int flags, - const char *static_challenge); +bool management_query_user_pass(struct management *man, + struct user_pass *up, + const char *type, + const unsigned int flags, + const char *static_challenge); #ifdef TARGET_ANDROID -bool management_android_control (struct management *man, const char *command, const char *msg); +bool management_android_control(struct management *man, const char *command, const char *msg); #define ANDROID_KEEP_OLD_TUN 1 #define ANDROID_OPEN_AFTER_CLOSE 2 #define ANDROID_OPEN_BEFORE_CLOSE 3 -int managment_android_persisttun_action (struct management *man); +int managment_android_persisttun_action(struct management *man); + #endif -bool management_should_daemonize (struct management *man); -bool management_would_hold (struct management *man); -bool management_hold (struct management *man, int holdtime); +bool management_should_daemonize(struct management *man); -void management_event_loop_n_seconds (struct management *man, int sec); +bool management_would_hold(struct management *man); + +bool management_hold(struct management *man, int holdtime); + +void management_event_loop_n_seconds(struct management *man, int sec); void management_up_down(struct management *man, const char *updown, const struct env_set *es); void management_notify(struct management *man, const char *severity, const char *type, const char *text); -void management_notify_generic (struct management *man, const char *str); +void management_notify_generic(struct management *man, const char *str); #ifdef MANAGEMENT_DEF_AUTH -void management_notify_client_needing_auth (struct management *management, - const unsigned int auth_id, - struct man_def_auth_context *mdac, - const struct env_set *es); - -void management_connection_established (struct management *management, - struct man_def_auth_context *mdac, - const struct env_set *es); - -void management_notify_client_close (struct management *management, - struct man_def_auth_context *mdac, - const struct env_set *es); - -void management_learn_addr (struct management *management, - struct man_def_auth_context *mdac, - const struct mroute_addr *addr, - const bool primary); +void management_notify_client_needing_auth(struct management *management, + const unsigned int auth_id, + struct man_def_auth_context *mdac, + const struct env_set *es); + +void management_connection_established(struct management *management, + struct man_def_auth_context *mdac, + const struct env_set *es); + +void management_notify_client_close(struct management *management, + struct man_def_auth_context *mdac, + const struct env_set *es); + +void management_learn_addr(struct management *management, + struct man_def_auth_context *mdac, + const struct mroute_addr *addr, + const bool primary); + #endif #ifdef MANAGMENT_EXTERNAL_KEY -char *management_query_rsa_sig (struct management *man, const char *b64_data); -char* management_query_cert (struct management *man, const char *cert_name); +char *management_query_rsa_sig(struct management *man, const char *b64_data); + +char *management_query_cert(struct management *man, const char *cert_name); #endif static inline bool -management_connected (const struct management *man) +management_connected(const struct management *man) { - return man->connection.state == MS_CC_WAIT_READ || man->connection.state == MS_CC_WAIT_WRITE; + return man->connection.state == MS_CC_WAIT_READ || man->connection.state == MS_CC_WAIT_WRITE; } static inline bool -management_query_user_pass_enabled (const struct management *man) +management_query_user_pass_enabled(const struct management *man) { - return BOOL_CAST(man->settings.flags & MF_QUERY_PASSWORDS); + return BOOL_CAST(man->settings.flags & MF_QUERY_PASSWORDS); } static inline bool -management_query_remote_enabled (const struct management *man) +management_query_remote_enabled(const struct management *man) { - return BOOL_CAST(man->settings.flags & MF_QUERY_REMOTE); + return BOOL_CAST(man->settings.flags & MF_QUERY_REMOTE); } static inline bool -management_query_proxy_enabled (const struct management *man) +management_query_proxy_enabled(const struct management *man) { - return BOOL_CAST(man->settings.flags & MF_QUERY_PROXY); + return BOOL_CAST(man->settings.flags & MF_QUERY_PROXY); } #ifdef MANAGEMENT_PF static inline bool -management_enable_pf (const struct management *man) +management_enable_pf(const struct management *man) { - return man && BOOL_CAST(man->settings.flags & MF_CLIENT_PF); + return man && BOOL_CAST(man->settings.flags & MF_CLIENT_PF); } #endif #ifdef MANAGEMENT_DEF_AUTH static inline bool -management_enable_def_auth (const struct management *man) +management_enable_def_auth(const struct management *man) { - return man && BOOL_CAST(man->settings.flags & MF_CLIENT_AUTH); + return man && BOOL_CAST(man->settings.flags & MF_CLIENT_AUTH); } #endif @@ -495,94 +508,102 @@ management_enable_def_auth (const struct management *man) #define OPENVPN_STATE_CLIENT_BASE 7 /* Base index of client-only states */ -void management_set_state (struct management *man, - const int state, - const char *detail, - const in_addr_t *tun_local_ip, - const struct in6_addr *tun_local_ip6, - const struct openvpn_sockaddr *local_addr, - const struct openvpn_sockaddr *remote_addr); +void management_set_state(struct management *man, + const int state, + const char *detail, + const in_addr_t *tun_local_ip, + const struct in6_addr *tun_local_ip6, + const struct openvpn_sockaddr *local_addr, + const struct openvpn_sockaddr *remote_addr); /* * The management object keeps track of OpenVPN --echo * parameters. */ -void management_echo (struct management *man, const char *string, const bool pull); +void management_echo(struct management *man, const char *string, const bool pull); /* * OpenVPN calls here to indicate a password failure */ -void management_auth_failure (struct management *man, const char *type, const char *reason); +void management_auth_failure(struct management *man, const char *type, const char *reason); /* * Echo an authentication token to management interface */ -void management_auth_token (struct management *man, const char *token); +void management_auth_token(struct management *man, const char *token); /* * These functions drive the bytecount in/out counters. */ -void man_bytecount_output_client (struct management *man); +void man_bytecount_output_client(struct management *man); static inline void -man_bytecount_possible_output_client (struct management *man) +man_bytecount_possible_output_client(struct management *man) { - if (man->connection.bytecount_update_seconds > 0 - && now >= man->connection.bytecount_last_update - + man->connection.bytecount_update_seconds) - man_bytecount_output_client (man); + if (man->connection.bytecount_update_seconds > 0 + && now >= man->connection.bytecount_last_update + + man->connection.bytecount_update_seconds) + { + man_bytecount_output_client(man); + } } static inline void -management_bytes_out_client (struct management *man, const int size) +management_bytes_out_client(struct management *man, const int size) { - man->persist.bytes_out += size; - man_bytecount_possible_output_client (man); + man->persist.bytes_out += size; + man_bytecount_possible_output_client(man); } static inline void -management_bytes_in_client (struct management *man, const int size) +management_bytes_in_client(struct management *man, const int size) { - man->persist.bytes_in += size; - man_bytecount_possible_output_client (man); + man->persist.bytes_in += size; + man_bytecount_possible_output_client(man); } static inline void -management_bytes_out (struct management *man, const int size) +management_bytes_out(struct management *man, const int size) { - if (!(man->persist.callback.flags & MCF_SERVER)) - management_bytes_out_client (man, size); + if (!(man->persist.callback.flags & MCF_SERVER)) + { + management_bytes_out_client(man, size); + } } static inline void -management_bytes_in (struct management *man, const int size) +management_bytes_in(struct management *man, const int size) { - if (!(man->persist.callback.flags & MCF_SERVER)) - management_bytes_in_client (man, size); + if (!(man->persist.callback.flags & MCF_SERVER)) + { + management_bytes_in_client(man, size); + } } #ifdef MANAGEMENT_DEF_AUTH static inline void -management_bytes_server (struct management *man, - const counter_type *bytes_in_total, - const counter_type *bytes_out_total, - struct man_def_auth_context *mdac) +management_bytes_server(struct management *man, + const counter_type *bytes_in_total, + const counter_type *bytes_out_total, + struct man_def_auth_context *mdac) { - void man_bytecount_output_server (struct management *man, - const counter_type *bytes_in_total, - const counter_type *bytes_out_total, - struct man_def_auth_context *mdac); - - if (man->connection.bytecount_update_seconds > 0 - && now >= mdac->bytecount_last_update + man->connection.bytecount_update_seconds - && (mdac->flags & (DAF_CONNECTION_ESTABLISHED|DAF_CONNECTION_CLOSED)) == DAF_CONNECTION_ESTABLISHED) - man_bytecount_output_server (man, bytes_in_total, bytes_out_total, mdac); + void man_bytecount_output_server(struct management *man, + const counter_type *bytes_in_total, + const counter_type *bytes_out_total, + struct man_def_auth_context *mdac); + + if (man->connection.bytecount_update_seconds > 0 + && now >= mdac->bytecount_last_update + man->connection.bytecount_update_seconds + && (mdac->flags & (DAF_CONNECTION_ESTABLISHED|DAF_CONNECTION_CLOSED)) == DAF_CONNECTION_ESTABLISHED) + { + man_bytecount_output_server(man, bytes_in_total, bytes_out_total, mdac); + } } #endif /* MANAGEMENT_DEF_AUTH */ -#endif -#endif +#endif /* ifdef ENABLE_MANAGEMENT */ +#endif /* ifndef MANAGE_H */ diff --git a/src/openvpn/mbuf.c b/src/openvpn/mbuf.c index 82f2388800d..a8388c49ec5 100644 --- a/src/openvpn/mbuf.c +++ b/src/openvpn/mbuf.c @@ -40,136 +40,140 @@ #include "memdbg.h" struct mbuf_set * -mbuf_init (unsigned int size) +mbuf_init(unsigned int size) { - struct mbuf_set *ret; - ALLOC_OBJ_CLEAR (ret, struct mbuf_set); - ret->capacity = adjust_power_of_2 (size); - ALLOC_ARRAY (ret->array, struct mbuf_item, ret->capacity); - return ret; + struct mbuf_set *ret; + ALLOC_OBJ_CLEAR(ret, struct mbuf_set); + ret->capacity = adjust_power_of_2(size); + ALLOC_ARRAY(ret->array, struct mbuf_item, ret->capacity); + return ret; } void -mbuf_free (struct mbuf_set *ms) +mbuf_free(struct mbuf_set *ms) { - if (ms) + if (ms) { - int i; - for (i = 0; i < (int) ms->len; ++i) - { - struct mbuf_item *item = &ms->array[MBUF_INDEX(ms->head, i, ms->capacity)]; - mbuf_free_buf (item->buffer); - } - free (ms->array); - free (ms); + int i; + for (i = 0; i < (int) ms->len; ++i) + { + struct mbuf_item *item = &ms->array[MBUF_INDEX(ms->head, i, ms->capacity)]; + mbuf_free_buf(item->buffer); + } + free(ms->array); + free(ms); } } struct mbuf_buffer * -mbuf_alloc_buf (const struct buffer *buf) +mbuf_alloc_buf(const struct buffer *buf) { - struct mbuf_buffer *ret; - ALLOC_OBJ (ret, struct mbuf_buffer); - ret->buf = clone_buf (buf); - ret->refcount = 1; - ret->flags = 0; - return ret; + struct mbuf_buffer *ret; + ALLOC_OBJ(ret, struct mbuf_buffer); + ret->buf = clone_buf(buf); + ret->refcount = 1; + ret->flags = 0; + return ret; } void -mbuf_free_buf (struct mbuf_buffer *mb) +mbuf_free_buf(struct mbuf_buffer *mb) { - if (mb) + if (mb) { - if (--mb->refcount <= 0) - { - free_buf (&mb->buf); - free (mb); - } + if (--mb->refcount <= 0) + { + free_buf(&mb->buf); + free(mb); + } } } void -mbuf_add_item (struct mbuf_set *ms, const struct mbuf_item *item) +mbuf_add_item(struct mbuf_set *ms, const struct mbuf_item *item) { - ASSERT (ms); - if (ms->len == ms->capacity) + ASSERT(ms); + if (ms->len == ms->capacity) { - struct mbuf_item rm; - ASSERT (mbuf_extract_item (ms, &rm)); - mbuf_free_buf (rm.buffer); - msg (D_MULTI_DROPPED, "MBUF: mbuf packet dropped"); + struct mbuf_item rm; + ASSERT(mbuf_extract_item(ms, &rm)); + mbuf_free_buf(rm.buffer); + msg(D_MULTI_DROPPED, "MBUF: mbuf packet dropped"); } - ASSERT (ms->len < ms->capacity); + ASSERT(ms->len < ms->capacity); - ms->array[MBUF_INDEX(ms->head, ms->len, ms->capacity)] = *item; - if (++ms->len > ms->max_queued) - ms->max_queued = ms->len; - ++item->buffer->refcount; + ms->array[MBUF_INDEX(ms->head, ms->len, ms->capacity)] = *item; + if (++ms->len > ms->max_queued) + { + ms->max_queued = ms->len; + } + ++item->buffer->refcount; } bool -mbuf_extract_item (struct mbuf_set *ms, struct mbuf_item *item) +mbuf_extract_item(struct mbuf_set *ms, struct mbuf_item *item) { - bool ret = false; - if (ms) + bool ret = false; + if (ms) { - while (ms->len) - { - *item = ms->array[ms->head]; - ms->head = MBUF_INDEX(ms->head, 1, ms->capacity); - --ms->len; - if (item->instance) /* ignore dereferenced instances */ - { - ret = true; - break; - } - } + while (ms->len) + { + *item = ms->array[ms->head]; + ms->head = MBUF_INDEX(ms->head, 1, ms->capacity); + --ms->len; + if (item->instance) /* ignore dereferenced instances */ + { + ret = true; + break; + } + } } - return ret; + return ret; } struct multi_instance * -mbuf_peek_dowork (struct mbuf_set *ms) +mbuf_peek_dowork(struct mbuf_set *ms) { - struct multi_instance *ret = NULL; - if (ms) + struct multi_instance *ret = NULL; + if (ms) { - int i; - for (i = 0; i < (int) ms->len; ++i) - { - struct mbuf_item *item = &ms->array[MBUF_INDEX(ms->head, i, ms->capacity)]; - if (item->instance) - { - ret = item->instance; - break; - } - } + int i; + for (i = 0; i < (int) ms->len; ++i) + { + struct mbuf_item *item = &ms->array[MBUF_INDEX(ms->head, i, ms->capacity)]; + if (item->instance) + { + ret = item->instance; + break; + } + } } - return ret; + return ret; } void -mbuf_dereference_instance (struct mbuf_set *ms, struct multi_instance *mi) +mbuf_dereference_instance(struct mbuf_set *ms, struct multi_instance *mi) { - if (ms) + if (ms) { - int i; - for (i = 0; i < (int) ms->len; ++i) - { - struct mbuf_item *item = &ms->array[MBUF_INDEX(ms->head, i, ms->capacity)]; - if (item->instance == mi) - { - mbuf_free_buf (item->buffer); - item->buffer = NULL; - item->instance = NULL; - msg (D_MBUF, "MBUF: dereferenced queued packet"); - } - } + int i; + for (i = 0; i < (int) ms->len; ++i) + { + struct mbuf_item *item = &ms->array[MBUF_INDEX(ms->head, i, ms->capacity)]; + if (item->instance == mi) + { + mbuf_free_buf(item->buffer); + item->buffer = NULL; + item->instance = NULL; + msg(D_MBUF, "MBUF: dereferenced queued packet"); + } + } } } -#else -static void dummy(void) {} +#else /* if P2MP */ +static void +dummy(void) { +} #endif /* P2MP */ diff --git a/src/openvpn/mbuf.h b/src/openvpn/mbuf.h index 1085adc7c01..c6375e37a83 100644 --- a/src/openvpn/mbuf.h +++ b/src/openvpn/mbuf.h @@ -43,67 +43,74 @@ struct multi_instance; struct mbuf_buffer { - struct buffer buf; - int refcount; + struct buffer buf; + int refcount; -# define MF_UNICAST (1<<0) - unsigned int flags; +#define MF_UNICAST (1<<0) + unsigned int flags; }; struct mbuf_item { - struct mbuf_buffer *buffer; - struct multi_instance *instance; + struct mbuf_buffer *buffer; + struct multi_instance *instance; }; struct mbuf_set { - unsigned int head; - unsigned int len; - unsigned int capacity; - unsigned int max_queued; - struct mbuf_item *array; + unsigned int head; + unsigned int len; + unsigned int capacity; + unsigned int max_queued; + struct mbuf_item *array; }; -struct mbuf_set *mbuf_init (unsigned int size); -void mbuf_free (struct mbuf_set *ms); +struct mbuf_set *mbuf_init(unsigned int size); -struct mbuf_buffer *mbuf_alloc_buf (const struct buffer *buf); -void mbuf_free_buf (struct mbuf_buffer *mb); +void mbuf_free(struct mbuf_set *ms); -void mbuf_add_item (struct mbuf_set *ms, const struct mbuf_item *item); +struct mbuf_buffer *mbuf_alloc_buf(const struct buffer *buf); -bool mbuf_extract_item (struct mbuf_set *ms, struct mbuf_item *item); +void mbuf_free_buf(struct mbuf_buffer *mb); -void mbuf_dereference_instance (struct mbuf_set *ms, struct multi_instance *mi); +void mbuf_add_item(struct mbuf_set *ms, const struct mbuf_item *item); + +bool mbuf_extract_item(struct mbuf_set *ms, struct mbuf_item *item); + +void mbuf_dereference_instance(struct mbuf_set *ms, struct multi_instance *mi); static inline bool -mbuf_defined (const struct mbuf_set *ms) +mbuf_defined(const struct mbuf_set *ms) { - return ms && ms->len; + return ms && ms->len; } static inline unsigned int -mbuf_len (const struct mbuf_set *ms) +mbuf_len(const struct mbuf_set *ms) { - return ms->len; + return ms->len; } static inline int -mbuf_maximum_queued (const struct mbuf_set *ms) +mbuf_maximum_queued(const struct mbuf_set *ms) { - return (int) ms->max_queued; + return (int) ms->max_queued; } static inline struct multi_instance * -mbuf_peek (struct mbuf_set *ms) +mbuf_peek(struct mbuf_set *ms) { - struct multi_instance *mbuf_peek_dowork (struct mbuf_set *ms); - if (mbuf_defined (ms)) - return mbuf_peek_dowork (ms); - else - return NULL; + struct multi_instance *mbuf_peek_dowork(struct mbuf_set *ms); + + if (mbuf_defined(ms)) + { + return mbuf_peek_dowork(ms); + } + else + { + return NULL; + } } -#endif -#endif +#endif /* if P2MP */ +#endif /* ifndef MBUF_H */ diff --git a/src/openvpn/memdbg.h b/src/openvpn/memdbg.h index 1f6bb676f20..4906f882170 100644 --- a/src/openvpn/memdbg.h +++ b/src/openvpn/memdbg.h @@ -49,7 +49,7 @@ #define VALGRIND_MAKE_READABLE(addr, len) -#else +#else /* ifdef USE_VALGRIND */ #define VALGRIND_MAKE_READABLE(addr, len) diff --git a/src/openvpn/misc.c b/src/openvpn/misc.c index 4e06c91d531..7c769a83cea 100644 --- a/src/openvpn/misc.c +++ b/src/openvpn/misc.c @@ -60,92 +60,108 @@ int script_security = SSEC_BUILT_IN; /* GLOBAL */ * Used to execute the up/down script/plugins. */ void -run_up_down (const char *command, - const struct plugin_list *plugins, - int plugin_type, - const char *arg, +run_up_down(const char *command, + const struct plugin_list *plugins, + int plugin_type, + const char *arg, #ifdef _WIN32 - DWORD adapter_index, + DWORD adapter_index, #endif - const char *dev_type, - int tun_mtu, - int link_mtu, - const char *ifconfig_local, - const char* ifconfig_remote, - const char *context, - const char *signal_text, - const char *script_type, - struct env_set *es) -{ - struct gc_arena gc = gc_new (); - - if (signal_text) - setenv_str (es, "signal", signal_text); - setenv_str (es, "script_context", context); - setenv_int (es, "tun_mtu", tun_mtu); - setenv_int (es, "link_mtu", link_mtu); - setenv_str (es, "dev", arg); - if (dev_type) - setenv_str (es, "dev_type", dev_type); + const char *dev_type, + int tun_mtu, + int link_mtu, + const char *ifconfig_local, + const char *ifconfig_remote, + const char *context, + const char *signal_text, + const char *script_type, + struct env_set *es) +{ + struct gc_arena gc = gc_new(); + + if (signal_text) + { + setenv_str(es, "signal", signal_text); + } + setenv_str(es, "script_context", context); + setenv_int(es, "tun_mtu", tun_mtu); + setenv_int(es, "link_mtu", link_mtu); + setenv_str(es, "dev", arg); + if (dev_type) + { + setenv_str(es, "dev_type", dev_type); + } #ifdef _WIN32 - setenv_int (es, "dev_idx", adapter_index); + setenv_int(es, "dev_idx", adapter_index); #endif - if (!ifconfig_local) - ifconfig_local = ""; - if (!ifconfig_remote) - ifconfig_remote = ""; - if (!context) - context = ""; - - if (plugin_defined (plugins, plugin_type)) + if (!ifconfig_local) { - struct argv argv = argv_new (); - ASSERT (arg); - argv_printf (&argv, - "%s %d %d %s %s %s", - arg, - tun_mtu, link_mtu, - ifconfig_local, ifconfig_remote, - context); + ifconfig_local = ""; + } + if (!ifconfig_remote) + { + ifconfig_remote = ""; + } + if (!context) + { + context = ""; + } - if (plugin_call (plugins, plugin_type, &argv, NULL, es) != OPENVPN_PLUGIN_FUNC_SUCCESS) - msg (M_FATAL, "ERROR: up/down plugin call failed"); + if (plugin_defined(plugins, plugin_type)) + { + struct argv argv = argv_new(); + ASSERT(arg); + argv_printf(&argv, + "%s %d %d %s %s %s", + arg, + tun_mtu, link_mtu, + ifconfig_local, ifconfig_remote, + context); + + if (plugin_call(plugins, plugin_type, &argv, NULL, es) != OPENVPN_PLUGIN_FUNC_SUCCESS) + { + msg(M_FATAL, "ERROR: up/down plugin call failed"); + } - argv_reset (&argv); + argv_reset(&argv); } - if (command) + if (command) { - struct argv argv = argv_new (); - ASSERT (arg); - setenv_str (es, "script_type", script_type); - argv_parse_cmd (&argv, command); - argv_printf_cat (&argv, "%s %d %d %s %s %s", arg, tun_mtu, link_mtu, - ifconfig_local, ifconfig_remote, context); - argv_msg (M_INFO, &argv); - openvpn_run_script (&argv, es, S_FATAL, "--up/--down"); - argv_reset (&argv); + struct argv argv = argv_new(); + ASSERT(arg); + setenv_str(es, "script_type", script_type); + argv_parse_cmd(&argv, command); + argv_printf_cat(&argv, "%s %d %d %s %s %s", arg, tun_mtu, link_mtu, + ifconfig_local, ifconfig_remote, context); + argv_msg(M_INFO, &argv); + openvpn_run_script(&argv, es, S_FATAL, "--up/--down"); + argv_reset(&argv); } - gc_free (&gc); + gc_free(&gc); } /* Write our PID to a file */ void -write_pid (const char *filename) +write_pid(const char *filename) { - if (filename) + if (filename) { - unsigned int pid = 0; - FILE *fp = platform_fopen (filename, "w"); - if (!fp) - msg (M_ERR, "Open error on pid file %s", filename); + unsigned int pid = 0; + FILE *fp = platform_fopen(filename, "w"); + if (!fp) + { + msg(M_ERR, "Open error on pid file %s", filename); + } - pid = platform_getpid (); - fprintf(fp, "%u\n", pid); - if (fclose (fp)) - msg (M_ERR, "Close error on pid file %s", filename); + pid = platform_getpid(); + fprintf(fp, "%u\n", pid); + if (fclose(fp)) + { + msg(M_ERR, "Close error on pid file %s", filename); + } } } @@ -153,20 +169,22 @@ write_pid (const char *filename) * Set standard file descriptors to /dev/null */ void -set_std_files_to_null (bool stdin_only) +set_std_files_to_null(bool stdin_only) { #if defined(HAVE_DUP) && defined(HAVE_DUP2) - int fd; - if ((fd = open ("/dev/null", O_RDWR, 0)) != -1) - { - dup2 (fd, 0); - if (!stdin_only) - { - dup2 (fd, 1); - dup2 (fd, 2); - } - if (fd > 2) - close (fd); + int fd; + if ((fd = open("/dev/null", O_RDWR, 0)) != -1) + { + dup2(fd, 0); + if (!stdin_only) + { + dup2(fd, 1); + dup2(fd, 2); + } + if (fd > 2) + { + close(fd); + } } #endif } @@ -178,14 +196,16 @@ set_std_files_to_null (bool stdin_only) int inetd_socket_descriptor = SOCKET_UNDEFINED; /* GLOBAL */ void -save_inetd_socket_descriptor (void) +save_inetd_socket_descriptor(void) { - inetd_socket_descriptor = INETD_SOCKET_DESCRIPTOR; + inetd_socket_descriptor = INETD_SOCKET_DESCRIPTOR; #if defined(HAVE_DUP) && defined(HAVE_DUP2) - /* use handle passed by inetd/xinetd */ - if ((inetd_socket_descriptor = dup (INETD_SOCKET_DESCRIPTOR)) < 0) - msg (M_ERR, "INETD_SOCKET_DESCRIPTOR dup(%d) failed", INETD_SOCKET_DESCRIPTOR); - set_std_files_to_null (true); + /* use handle passed by inetd/xinetd */ + if ((inetd_socket_descriptor = dup(INETD_SOCKET_DESCRIPTOR)) < 0) + { + msg(M_ERR, "INETD_SOCKET_DESCRIPTOR dup(%d) failed", INETD_SOCKET_DESCRIPTOR); + } + set_std_files_to_null(true); #endif } @@ -193,62 +213,82 @@ save_inetd_socket_descriptor (void) * Print an error message based on the status code returned by system(). */ const char * -system_error_message (int stat, struct gc_arena *gc) +system_error_message(int stat, struct gc_arena *gc) { - struct buffer out = alloc_buf_gc (256, gc); + struct buffer out = alloc_buf_gc(256, gc); #ifdef _WIN32 - if (stat == -1) - buf_printf (&out, "external program did not execute -- "); - buf_printf (&out, "returned error code %d", stat); -#else - if (stat == -1) - buf_printf (&out, "external program fork failed"); - else if (!WIFEXITED (stat)) - buf_printf (&out, "external program did not exit normally"); - else - { - const int cmd_ret = WEXITSTATUS (stat); - if (!cmd_ret) - buf_printf (&out, "external program exited normally"); - else if (cmd_ret == 127) - buf_printf (&out, "could not execute external program"); - else - buf_printf (&out, "external program exited with error status: %d", cmd_ret); + if (stat == -1) + { + buf_printf(&out, "external program did not execute -- "); } -#endif - return (const char *)out.data; + buf_printf(&out, "returned error code %d", stat); +#else /* ifdef _WIN32 */ + if (stat == -1) + { + buf_printf(&out, "external program fork failed"); + } + else if (!WIFEXITED(stat)) + { + buf_printf(&out, "external program did not exit normally"); + } + else + { + const int cmd_ret = WEXITSTATUS(stat); + if (!cmd_ret) + { + buf_printf(&out, "external program exited normally"); + } + else if (cmd_ret == 127) + { + buf_printf(&out, "could not execute external program"); + } + else + { + buf_printf(&out, "external program exited with error status: %d", cmd_ret); + } + } +#endif /* ifdef _WIN32 */ + return (const char *)out.data; } /* * Wrapper around openvpn_execve */ bool -openvpn_execve_check (const struct argv *a, const struct env_set *es, const unsigned int flags, const char *error_message) +openvpn_execve_check(const struct argv *a, const struct env_set *es, const unsigned int flags, const char *error_message) { - struct gc_arena gc = gc_new (); - const int stat = openvpn_execve (a, es, flags); - int ret = false; + struct gc_arena gc = gc_new(); + const int stat = openvpn_execve(a, es, flags); + int ret = false; - if (platform_system_ok (stat)) - ret = true; - else + if (platform_system_ok(stat)) + { + ret = true; + } + else { - if (error_message) - msg (((flags & S_FATAL) ? M_FATAL : M_WARN), "%s: %s", - error_message, - system_error_message (stat, &gc)); + if (error_message) + { + msg(((flags & S_FATAL) ? M_FATAL : M_WARN), "%s: %s", + error_message, + system_error_message(stat, &gc)); + } } - gc_free (&gc); - return ret; + gc_free(&gc); + return ret; } bool -openvpn_execve_allowed (const unsigned int flags) +openvpn_execve_allowed(const unsigned int flags) { - if (flags & S_SCRIPT) - return script_security >= SSEC_SCRIPTS; - else - return script_security >= SSEC_BUILT_IN; + if (flags & S_SCRIPT) + { + return script_security >= SSEC_SCRIPTS; + } + else + { + return script_security >= SSEC_BUILT_IN; + } } @@ -259,54 +299,58 @@ openvpn_execve_allowed (const unsigned int flags) * assocated with formatting and parsing a command line. */ int -openvpn_execve (const struct argv *a, const struct env_set *es, const unsigned int flags) +openvpn_execve(const struct argv *a, const struct env_set *es, const unsigned int flags) { - struct gc_arena gc = gc_new (); - int ret = -1; - static bool warn_shown = false; + struct gc_arena gc = gc_new(); + int ret = -1; + static bool warn_shown = false; - if (a && a->argv[0]) + if (a && a->argv[0]) { #if defined(ENABLE_FEATURE_EXECVE) - if (openvpn_execve_allowed (flags)) - { - const char *cmd = a->argv[0]; - char *const *argv = a->argv; - char *const *envp = (char *const *)make_env_array (es, true, &gc); - pid_t pid; - - pid = fork (); - if (pid == (pid_t)0) /* child side */ + if (openvpn_execve_allowed(flags)) + { + const char *cmd = a->argv[0]; + char *const *argv = a->argv; + char *const *envp = (char *const *)make_env_array(es, true, &gc); + pid_t pid; + + pid = fork(); + if (pid == (pid_t)0) /* child side */ { - execve (cmd, argv, envp); - exit (127); + execve(cmd, argv, envp); + exit(127); } - else if (pid < (pid_t)0) /* fork failed */ - msg (M_ERR, "openvpn_execve: unable to fork"); - else /* parent side */ + else if (pid < (pid_t)0) /* fork failed */ { - if (waitpid (pid, &ret, 0) != pid) - ret = -1; + msg(M_ERR, "openvpn_execve: unable to fork"); + } + else /* parent side */ + { + if (waitpid(pid, &ret, 0) != pid) + { + ret = -1; + } } } - else if (!warn_shown && (script_security < SSEC_SCRIPTS)) - { - msg (M_WARN, SCRIPT_SECURITY_WARNING); - warn_shown = true; - } -#else - msg (M_WARN, "openvpn_execve: execve function not available"); -#endif + else if (!warn_shown && (script_security < SSEC_SCRIPTS)) + { + msg(M_WARN, SCRIPT_SECURITY_WARNING); + warn_shown = true; + } +#else /* if defined(ENABLE_FEATURE_EXECVE) */ + msg(M_WARN, "openvpn_execve: execve function not available"); +#endif /* if defined(ENABLE_FEATURE_EXECVE) */ } - else + else { - msg (M_FATAL, "openvpn_execve: called with empty argv"); + msg(M_FATAL, "openvpn_execve: called with empty argv"); } - gc_free (&gc); - return ret; + gc_free(&gc); + return ret; } -#endif +#endif /* ifndef _WIN32 */ /* * Run execve() inside a fork(), duping stdout. Designed to replicate the semantics of popen() but @@ -314,68 +358,70 @@ openvpn_execve (const struct argv *a, const struct env_set *es, const unsigned i * assocated with formatting and parsing a command line. */ int -openvpn_popen (const struct argv *a, const struct env_set *es) +openvpn_popen(const struct argv *a, const struct env_set *es) { - struct gc_arena gc = gc_new (); - int ret = -1; - static bool warn_shown = false; + struct gc_arena gc = gc_new(); + int ret = -1; + static bool warn_shown = false; - if (a && a->argv[0]) + if (a && a->argv[0]) { #if defined(ENABLE_FEATURE_EXECVE) - if (script_security >= SSEC_BUILT_IN) - { - const char *cmd = a->argv[0]; - char *const *argv = a->argv; - char *const *envp = (char *const *)make_env_array (es, true, &gc); - pid_t pid; - int pipe_stdout[2]; - - if (pipe (pipe_stdout) == 0) { - pid = fork (); - if (pid == (pid_t)0) /* child side */ - { - close (pipe_stdout[0]); /* Close read end */ - dup2 (pipe_stdout[1],1); - execve (cmd, argv, envp); - exit (127); - } - else if (pid > (pid_t)0) /* parent side */ - { - int status = 0; - - close (pipe_stdout[1]); /* Close write end */ - waitpid(pid, &status, 0); - ret = pipe_stdout[0]; - } - else /* fork failed */ - { - close (pipe_stdout[0]); - close (pipe_stdout[1]); - msg (M_ERR, "openvpn_popen: unable to fork %s", cmd); - } - } - else { - msg (M_WARN, "openvpn_popen: unable to create stdout pipe for %s", cmd); + if (script_security >= SSEC_BUILT_IN) + { + const char *cmd = a->argv[0]; + char *const *argv = a->argv; + char *const *envp = (char *const *)make_env_array(es, true, &gc); + pid_t pid; + int pipe_stdout[2]; + + if (pipe(pipe_stdout) == 0) + { + pid = fork(); + if (pid == (pid_t)0) /* child side */ + { + close(pipe_stdout[0]); /* Close read end */ + dup2(pipe_stdout[1],1); + execve(cmd, argv, envp); + exit(127); + } + else if (pid > (pid_t)0) /* parent side */ + { + int status = 0; + + close(pipe_stdout[1]); /* Close write end */ + waitpid(pid, &status, 0); + ret = pipe_stdout[0]; + } + else /* fork failed */ + { + close(pipe_stdout[0]); + close(pipe_stdout[1]); + msg(M_ERR, "openvpn_popen: unable to fork %s", cmd); + } + } + else + { + msg(M_WARN, "openvpn_popen: unable to create stdout pipe for %s", cmd); ret = -1; - } - } - else if (!warn_shown && (script_security < SSEC_SCRIPTS)) - { - msg (M_WARN, SCRIPT_SECURITY_WARNING); - warn_shown = true; - } -#else - msg (M_WARN, "openvpn_popen: execve function not available"); -#endif + } + } + else if (!warn_shown && (script_security < SSEC_SCRIPTS)) + { + msg(M_WARN, SCRIPT_SECURITY_WARNING); + warn_shown = true; + } +#else /* if defined(ENABLE_FEATURE_EXECVE) */ + msg(M_WARN, "openvpn_popen: execve function not available"); +#endif /* if defined(ENABLE_FEATURE_EXECVE) */ } - else + else { - msg (M_FATAL, "openvpn_popen: called with empty argv"); + msg(M_FATAL, "openvpn_popen: called with empty argv"); } - gc_free (&gc); - return ret; + gc_free(&gc); + return ret; } @@ -390,27 +436,27 @@ openvpn_popen (const struct argv *a, const struct env_set *es) void init_random_seed(void) { - struct timeval tv; + struct timeval tv; - if (!gettimeofday (&tv, NULL)) + if (!gettimeofday(&tv, NULL)) { - const unsigned int seed = (unsigned int) tv.tv_sec ^ tv.tv_usec; - srandom (seed); + const unsigned int seed = (unsigned int) tv.tv_sec ^ tv.tv_usec; + srandom(seed); } } /* thread-safe strerror */ const char * -strerror_ts (int errnum, struct gc_arena *gc) +strerror_ts(int errnum, struct gc_arena *gc) { #ifdef HAVE_STRERROR - struct buffer out = alloc_buf_gc (256, gc); + struct buffer out = alloc_buf_gc(256, gc); - buf_printf (&out, "%s", openvpn_strerror (errnum, gc)); - return BSTR (&out); + buf_printf(&out, "%s", openvpn_strerror(errnum, gc)); + return BSTR(&out); #else - return "[error string unavailable]"; + return "[error string unavailable]"; #endif } @@ -425,491 +471,525 @@ strerror_ts (int errnum, struct gc_arena *gc) /* General-purpose environmental variable set functions */ static char * -construct_name_value (const char *name, const char *value, struct gc_arena *gc) +construct_name_value(const char *name, const char *value, struct gc_arena *gc) { - struct buffer out; + struct buffer out; - ASSERT (name); - if (!value) - value = ""; - out = alloc_buf_gc (strlen (name) + strlen (value) + 2, gc); - buf_printf (&out, "%s=%s", name, value); - return BSTR (&out); + ASSERT(name); + if (!value) + { + value = ""; + } + out = alloc_buf_gc(strlen(name) + strlen(value) + 2, gc); + buf_printf(&out, "%s=%s", name, value); + return BSTR(&out); } bool -deconstruct_name_value (const char *str, const char **name, const char **value, struct gc_arena *gc) +deconstruct_name_value(const char *str, const char **name, const char **value, struct gc_arena *gc) { - char *cp; + char *cp; - ASSERT (str); - ASSERT (name && value); + ASSERT(str); + ASSERT(name && value); - *name = cp = string_alloc (str, gc); - *value = NULL; + *name = cp = string_alloc(str, gc); + *value = NULL; - while ((*cp)) + while ((*cp)) { - if (*cp == '=' && !*value) - { - *cp = 0; - *value = cp + 1; - } - ++cp; + if (*cp == '=' && !*value) + { + *cp = 0; + *value = cp + 1; + } + ++cp; } - return *name && *value; + return *name && *value; } static bool -env_string_equal (const char *s1, const char *s2) +env_string_equal(const char *s1, const char *s2) { - int c1, c2; - ASSERT (s1); - ASSERT (s2); + int c1, c2; + ASSERT(s1); + ASSERT(s2); - while (true) + while (true) { - c1 = *s1++; - c2 = *s2++; - if (c1 == '=') - c1 = 0; - if (c2 == '=') - c2 = 0; - if (!c1 && !c2) - return true; - if (c1 != c2) - break; + c1 = *s1++; + c2 = *s2++; + if (c1 == '=') + { + c1 = 0; + } + if (c2 == '=') + { + c2 = 0; + } + if (!c1 && !c2) + { + return true; + } + if (c1 != c2) + { + break; + } } - return false; + return false; } static bool -remove_env_item (const char *str, const bool do_free, struct env_item **list) +remove_env_item(const char *str, const bool do_free, struct env_item **list) { - struct env_item *current, *prev; + struct env_item *current, *prev; - ASSERT (str); - ASSERT (list); + ASSERT(str); + ASSERT(list); - for (current = *list, prev = NULL; current != NULL; current = current->next) + for (current = *list, prev = NULL; current != NULL; current = current->next) { - if (env_string_equal (current->string, str)) - { - if (prev) - prev->next = current->next; - else - *list = current->next; - if (do_free) - { - secure_memzero (current->string, strlen (current->string)); - free (current->string); - free (current); - } - return true; - } - prev = current; + if (env_string_equal(current->string, str)) + { + if (prev) + { + prev->next = current->next; + } + else + { + *list = current->next; + } + if (do_free) + { + secure_memzero(current->string, strlen(current->string)); + free(current->string); + free(current); + } + return true; + } + prev = current; } - return false; + return false; } static void -add_env_item (char *str, const bool do_alloc, struct env_item **list, struct gc_arena *gc) +add_env_item(char *str, const bool do_alloc, struct env_item **list, struct gc_arena *gc) { - struct env_item *item; + struct env_item *item; - ASSERT (str); - ASSERT (list); + ASSERT(str); + ASSERT(list); - ALLOC_OBJ_GC (item, struct env_item, gc); - item->string = do_alloc ? string_alloc (str, gc): str; - item->next = *list; - *list = item; + ALLOC_OBJ_GC(item, struct env_item, gc); + item->string = do_alloc ? string_alloc(str, gc) : str; + item->next = *list; + *list = item; } /* struct env_set functions */ static bool -env_set_del_nolock (struct env_set *es, const char *str) +env_set_del_nolock(struct env_set *es, const char *str) { - return remove_env_item (str, es->gc == NULL, &es->list); + return remove_env_item(str, es->gc == NULL, &es->list); } static void -env_set_add_nolock (struct env_set *es, const char *str) +env_set_add_nolock(struct env_set *es, const char *str) { - remove_env_item (str, es->gc == NULL, &es->list); - add_env_item ((char *)str, true, &es->list, es->gc); + remove_env_item(str, es->gc == NULL, &es->list); + add_env_item((char *)str, true, &es->list, es->gc); } struct env_set * -env_set_create (struct gc_arena *gc) +env_set_create(struct gc_arena *gc) { - struct env_set *es; - ALLOC_OBJ_CLEAR_GC (es, struct env_set, gc); - es->list = NULL; - es->gc = gc; - return es; + struct env_set *es; + ALLOC_OBJ_CLEAR_GC(es, struct env_set, gc); + es->list = NULL; + es->gc = gc; + return es; } void -env_set_destroy (struct env_set *es) +env_set_destroy(struct env_set *es) { - if (es && es->gc == NULL) + if (es && es->gc == NULL) { - struct env_item *e = es->list; - while (e) - { - struct env_item *next = e->next; - free (e->string); - free (e); - e = next; - } - free (es); + struct env_item *e = es->list; + while (e) + { + struct env_item *next = e->next; + free(e->string); + free(e); + e = next; + } + free(es); } } bool -env_set_del (struct env_set *es, const char *str) +env_set_del(struct env_set *es, const char *str) { - bool ret; - ASSERT (es); - ASSERT (str); - ret = env_set_del_nolock (es, str); - return ret; + bool ret; + ASSERT(es); + ASSERT(str); + ret = env_set_del_nolock(es, str); + return ret; } void -env_set_add (struct env_set *es, const char *str) +env_set_add(struct env_set *es, const char *str) { - ASSERT (es); - ASSERT (str); - env_set_add_nolock (es, str); + ASSERT(es); + ASSERT(str); + env_set_add_nolock(es, str); } -const char* -env_set_get (const struct env_set *es, const char *name) +const char * +env_set_get(const struct env_set *es, const char *name) { - const struct env_item *item = es->list; - while (item && !env_string_equal(item->string, name)) { - item = item->next; - } - return item ? item->string : NULL; + const struct env_item *item = es->list; + while (item && !env_string_equal(item->string, name)) { + item = item->next; + } + return item ? item->string : NULL; } void -env_set_print (int msglevel, const struct env_set *es) +env_set_print(int msglevel, const struct env_set *es) { - if (check_debug_level (msglevel)) + if (check_debug_level(msglevel)) { - const struct env_item *e; - int i; + const struct env_item *e; + int i; - if (es) - { - e = es->list; - i = 0; + if (es) + { + e = es->list; + i = 0; - while (e) - { - if (env_safe_to_print (e->string)) - msg (msglevel, "ENV [%d] '%s'", i, e->string); - ++i; - e = e->next; - } - } + while (e) + { + if (env_safe_to_print(e->string)) + { + msg(msglevel, "ENV [%d] '%s'", i, e->string); + } + ++i; + e = e->next; + } + } } } void -env_set_inherit (struct env_set *es, const struct env_set *src) +env_set_inherit(struct env_set *es, const struct env_set *src) { - const struct env_item *e; + const struct env_item *e; - ASSERT (es); + ASSERT(es); - if (src) + if (src) { - e = src->list; - while (e) - { - env_set_add_nolock (es, e->string); - e = e->next; - } + e = src->list; + while (e) + { + env_set_add_nolock(es, e->string); + e = e->next; + } } } void -env_set_add_to_environment (const struct env_set *es) +env_set_add_to_environment(const struct env_set *es) { - if (es) + if (es) { - struct gc_arena gc = gc_new (); - const struct env_item *e; + struct gc_arena gc = gc_new(); + const struct env_item *e; - e = es->list; + e = es->list; - while (e) - { - const char *name; - const char *value; + while (e) + { + const char *name; + const char *value; - if (deconstruct_name_value (e->string, &name, &value, &gc)) - setenv_str (NULL, name, value); + if (deconstruct_name_value(e->string, &name, &value, &gc)) + { + setenv_str(NULL, name, value); + } - e = e->next; - } - gc_free (&gc); + e = e->next; + } + gc_free(&gc); } } void -env_set_remove_from_environment (const struct env_set *es) +env_set_remove_from_environment(const struct env_set *es) { - if (es) + if (es) { - struct gc_arena gc = gc_new (); - const struct env_item *e; + struct gc_arena gc = gc_new(); + const struct env_item *e; - e = es->list; + e = es->list; - while (e) - { - const char *name; - const char *value; + while (e) + { + const char *name; + const char *value; - if (deconstruct_name_value (e->string, &name, &value, &gc)) - setenv_del (NULL, name); + if (deconstruct_name_value(e->string, &name, &value, &gc)) + { + setenv_del(NULL, name); + } - e = e->next; - } - gc_free (&gc); + e = e->next; + } + gc_free(&gc); } } /* add/modify/delete environmental strings */ void -setenv_counter (struct env_set *es, const char *name, counter_type value) +setenv_counter(struct env_set *es, const char *name, counter_type value) { - char buf[64]; - openvpn_snprintf (buf, sizeof(buf), counter_format, value); - setenv_str (es, name, buf); + char buf[64]; + openvpn_snprintf(buf, sizeof(buf), counter_format, value); + setenv_str(es, name, buf); } void -setenv_int (struct env_set *es, const char *name, int value) +setenv_int(struct env_set *es, const char *name, int value) { - char buf[64]; - openvpn_snprintf (buf, sizeof(buf), "%d", value); - setenv_str (es, name, buf); + char buf[64]; + openvpn_snprintf(buf, sizeof(buf), "%d", value); + setenv_str(es, name, buf); } void -setenv_unsigned (struct env_set *es, const char *name, unsigned int value) +setenv_unsigned(struct env_set *es, const char *name, unsigned int value) { - char buf[64]; - openvpn_snprintf (buf, sizeof(buf), "%u", value); - setenv_str (es, name, buf); + char buf[64]; + openvpn_snprintf(buf, sizeof(buf), "%u", value); + setenv_str(es, name, buf); } void -setenv_str (struct env_set *es, const char *name, const char *value) +setenv_str(struct env_set *es, const char *name, const char *value) { - setenv_str_ex (es, name, value, CC_NAME, 0, 0, CC_PRINT, 0, 0); + setenv_str_ex(es, name, value, CC_NAME, 0, 0, CC_PRINT, 0, 0); } void -setenv_str_safe (struct env_set *es, const char *name, const char *value) +setenv_str_safe(struct env_set *es, const char *name, const char *value) { - uint8_t b[64]; - struct buffer buf; - buf_set_write (&buf, b, sizeof (b)); - if (buf_printf (&buf, "OPENVPN_%s", name)) - setenv_str (es, BSTR(&buf), value); - else - msg (M_WARN, "setenv_str_safe: name overflow"); + uint8_t b[64]; + struct buffer buf; + buf_set_write(&buf, b, sizeof(b)); + if (buf_printf(&buf, "OPENVPN_%s", name)) + { + setenv_str(es, BSTR(&buf), value); + } + else + { + msg(M_WARN, "setenv_str_safe: name overflow"); + } } -void setenv_str_incr(struct env_set *es, const char *name, const char *value) +void +setenv_str_incr(struct env_set *es, const char *name, const char *value) { - unsigned int counter = 1; - const size_t tmpname_len = strlen(name) + 5; /* 3 digits counter max */ - char *tmpname = gc_malloc(tmpname_len, true, NULL); - strcpy(tmpname, name); - while (NULL != env_set_get(es, tmpname) && counter < 1000) + unsigned int counter = 1; + const size_t tmpname_len = strlen(name) + 5; /* 3 digits counter max */ + char *tmpname = gc_malloc(tmpname_len, true, NULL); + strcpy(tmpname, name); + while (NULL != env_set_get(es, tmpname) && counter < 1000) { - ASSERT (openvpn_snprintf (tmpname, tmpname_len, "%s_%u", name, counter)); - counter++; + ASSERT(openvpn_snprintf(tmpname, tmpname_len, "%s_%u", name, counter)); + counter++; } - if (counter < 1000) + if (counter < 1000) { - setenv_str (es, tmpname, value); + setenv_str(es, tmpname, value); } - else + else { - msg (D_TLS_DEBUG_MED, "Too many same-name env variables, ignoring: %s", name); + msg(D_TLS_DEBUG_MED, "Too many same-name env variables, ignoring: %s", name); } - free (tmpname); + free(tmpname); } void -setenv_del (struct env_set *es, const char *name) +setenv_del(struct env_set *es, const char *name) { - ASSERT (name); - setenv_str (es, name, NULL); + ASSERT(name); + setenv_str(es, name, NULL); } void -setenv_str_ex (struct env_set *es, - const char *name, - const char *value, - const unsigned int name_include, - const unsigned int name_exclude, - const char name_replace, - const unsigned int value_include, - const unsigned int value_exclude, - const char value_replace) +setenv_str_ex(struct env_set *es, + const char *name, + const char *value, + const unsigned int name_include, + const unsigned int name_exclude, + const char name_replace, + const unsigned int value_include, + const unsigned int value_exclude, + const char value_replace) { - struct gc_arena gc = gc_new (); - const char *name_tmp; - const char *val_tmp = NULL; + struct gc_arena gc = gc_new(); + const char *name_tmp; + const char *val_tmp = NULL; - ASSERT (name && strlen (name) > 1); + ASSERT(name && strlen(name) > 1); - name_tmp = string_mod_const (name, name_include, name_exclude, name_replace, &gc); + name_tmp = string_mod_const(name, name_include, name_exclude, name_replace, &gc); - if (value) - val_tmp = string_mod_const (value, value_include, value_exclude, value_replace, &gc); + if (value) + { + val_tmp = string_mod_const(value, value_include, value_exclude, value_replace, &gc); + } - ASSERT (es); + ASSERT(es); - if (val_tmp) + if (val_tmp) { - const char *str = construct_name_value (name_tmp, val_tmp, &gc); - env_set_add (es, str); + const char *str = construct_name_value(name_tmp, val_tmp, &gc); + env_set_add(es, str); #if DEBUG_VERBOSE_SETENV - msg (M_INFO, "SETENV_ES '%s'", str); + msg(M_INFO, "SETENV_ES '%s'", str); #endif } - else - env_set_del (es, name_tmp); + else + { + env_set_del(es, name_tmp); + } - gc_free (&gc); + gc_free(&gc); } /* * Setenv functions that append an integer index to the name */ static const char * -setenv_format_indexed_name (const char *name, const int i, struct gc_arena *gc) +setenv_format_indexed_name(const char *name, const int i, struct gc_arena *gc) { - struct buffer out = alloc_buf_gc (strlen (name) + 16, gc); - if (i >= 0) - buf_printf (&out, "%s_%d", name, i); - else - buf_printf (&out, "%s", name); - return BSTR (&out); + struct buffer out = alloc_buf_gc(strlen(name) + 16, gc); + if (i >= 0) + { + buf_printf(&out, "%s_%d", name, i); + } + else + { + buf_printf(&out, "%s", name); + } + return BSTR(&out); } void -setenv_int_i (struct env_set *es, const char *name, const int value, const int i) +setenv_int_i(struct env_set *es, const char *name, const int value, const int i) { - struct gc_arena gc = gc_new (); - const char *name_str = setenv_format_indexed_name (name, i, &gc); - setenv_int (es, name_str, value); - gc_free (&gc); + struct gc_arena gc = gc_new(); + const char *name_str = setenv_format_indexed_name(name, i, &gc); + setenv_int(es, name_str, value); + gc_free(&gc); } void -setenv_str_i (struct env_set *es, const char *name, const char *value, const int i) +setenv_str_i(struct env_set *es, const char *name, const char *value, const int i) { - struct gc_arena gc = gc_new (); - const char *name_str = setenv_format_indexed_name (name, i, &gc); - setenv_str (es, name_str, value); - gc_free (&gc); + struct gc_arena gc = gc_new(); + const char *name_str = setenv_format_indexed_name(name, i, &gc); + setenv_str(es, name_str, value); + gc_free(&gc); } /* return true if filename can be opened for read */ bool -test_file (const char *filename) +test_file(const char *filename) { - bool ret = false; - if (filename) + bool ret = false; + if (filename) { - FILE *fp = platform_fopen (filename, "r"); - if (fp) - { - fclose (fp); - ret = true; - } - else - { - if( openvpn_errno () == EACCES ) { - msg( M_WARN | M_ERRNO, "Could not access file '%s'", filename); - } - } + FILE *fp = platform_fopen(filename, "r"); + if (fp) + { + fclose(fp); + ret = true; + } + else + { + if (openvpn_errno() == EACCES) + { + msg( M_WARN | M_ERRNO, "Could not access file '%s'", filename); + } + } } - dmsg (D_TEST_FILE, "TEST FILE '%s' [%d]", - filename ? filename : "UNDEF", - ret); + dmsg(D_TEST_FILE, "TEST FILE '%s' [%d]", + filename ? filename : "UNDEF", + ret); - return ret; + return ret; } #ifdef ENABLE_CRYPTO /* create a temporary filename in directory */ const char * -create_temp_file (const char *directory, const char *prefix, struct gc_arena *gc) +create_temp_file(const char *directory, const char *prefix, struct gc_arena *gc) { - static unsigned int counter; - struct buffer fname = alloc_buf_gc (256, gc); - int fd; - const char *retfname = NULL; - unsigned int attempts = 0; + static unsigned int counter; + struct buffer fname = alloc_buf_gc(256, gc); + int fd; + const char *retfname = NULL; + unsigned int attempts = 0; - do + do { - uint8_t rndbytes[16]; - const char *rndstr; + uint8_t rndbytes[16]; + const char *rndstr; - ++attempts; - ++counter; + ++attempts; + ++counter; - prng_bytes (rndbytes, sizeof rndbytes); - rndstr = format_hex_ex (rndbytes, sizeof rndbytes, 40, 0, NULL, gc); - buf_printf (&fname, PACKAGE "_%s_%s.tmp", prefix, rndstr); + prng_bytes(rndbytes, sizeof rndbytes); + rndstr = format_hex_ex(rndbytes, sizeof rndbytes, 40, 0, NULL, gc); + buf_printf(&fname, PACKAGE "_%s_%s.tmp", prefix, rndstr); - retfname = gen_path (directory, BSTR (&fname), gc); - if (!retfname) + retfname = gen_path(directory, BSTR(&fname), gc); + if (!retfname) { - msg (M_FATAL, "Failed to create temporary filename and path"); - return NULL; + msg(M_FATAL, "Failed to create temporary filename and path"); + return NULL; } - /* Atomically create the file. Errors out if the file already - exists. */ - fd = platform_open (retfname, O_CREAT | O_EXCL | O_WRONLY, S_IRUSR | S_IWUSR); - if (fd != -1) + /* Atomically create the file. Errors out if the file already + * exists. */ + fd = platform_open(retfname, O_CREAT | O_EXCL | O_WRONLY, S_IRUSR | S_IWUSR); + if (fd != -1) { - close (fd); - return retfname; + close(fd); + return retfname; } - else if (fd == -1 && errno != EEXIST) + else if (fd == -1 && errno != EEXIST) { - /* Something else went wrong, no need to retry. */ - struct gc_arena gcerr = gc_new (); - msg (M_FATAL, "Could not create temporary file '%s': %s", - retfname, strerror_ts (errno, &gcerr)); - gc_free (&gcerr); - return NULL; + /* Something else went wrong, no need to retry. */ + struct gc_arena gcerr = gc_new(); + msg(M_FATAL, "Could not create temporary file '%s': %s", + retfname, strerror_ts(errno, &gcerr)); + gc_free(&gcerr); + return NULL; } } - while (attempts < 6); + while (attempts < 6); - msg (M_FATAL, "Failed to create temporary file after %i attempts", attempts); - return NULL; + msg(M_FATAL, "Failed to create temporary file after %i attempts", attempts); + return NULL; } /* @@ -920,83 +1000,89 @@ create_temp_file (const char *directory, const char *prefix, struct gc_arena *gc const char * hostname_randomize(const char *hostname, struct gc_arena *gc) { -# define n_rnd_bytes 6 +#define n_rnd_bytes 6 - uint8_t rnd_bytes[n_rnd_bytes]; - const char *rnd_str; - struct buffer hname = alloc_buf_gc (strlen(hostname)+sizeof(rnd_bytes)*2+4, gc); + uint8_t rnd_bytes[n_rnd_bytes]; + const char *rnd_str; + struct buffer hname = alloc_buf_gc(strlen(hostname)+sizeof(rnd_bytes)*2+4, gc); - prng_bytes (rnd_bytes, sizeof (rnd_bytes)); - rnd_str = format_hex_ex (rnd_bytes, sizeof (rnd_bytes), 40, 0, NULL, gc); - buf_printf(&hname, "%s.%s", rnd_str, hostname); - return BSTR(&hname); -# undef n_rnd_bytes + prng_bytes(rnd_bytes, sizeof(rnd_bytes)); + rnd_str = format_hex_ex(rnd_bytes, sizeof(rnd_bytes), 40, 0, NULL, gc); + buf_printf(&hname, "%s.%s", rnd_str, hostname); + return BSTR(&hname); +#undef n_rnd_bytes } -#else +#else /* ifdef ENABLE_CRYPTO */ const char * hostname_randomize(const char *hostname, struct gc_arena *gc) { - msg (M_WARN, "WARNING: hostname randomization disabled when crypto support is not compiled"); - return hostname; + msg(M_WARN, "WARNING: hostname randomization disabled when crypto support is not compiled"); + return hostname; } -#endif +#endif /* ifdef ENABLE_CRYPTO */ /* * Put a directory and filename together. */ const char * -gen_path (const char *directory, const char *filename, struct gc_arena *gc) +gen_path(const char *directory, const char *filename, struct gc_arena *gc) { #ifdef _WIN32 - const int CC_PATH_RESERVED = CC_LESS_THAN|CC_GREATER_THAN|CC_COLON| - CC_DOUBLE_QUOTE|CC_SLASH|CC_BACKSLASH|CC_PIPE|CC_QUESTION_MARK|CC_ASTERISK; + const int CC_PATH_RESERVED = CC_LESS_THAN|CC_GREATER_THAN|CC_COLON + |CC_DOUBLE_QUOTE|CC_SLASH|CC_BACKSLASH|CC_PIPE|CC_QUESTION_MARK|CC_ASTERISK; #else - const int CC_PATH_RESERVED = CC_SLASH; + const int CC_PATH_RESERVED = CC_SLASH; #endif - const char *safe_filename = string_mod_const (filename, CC_PRINT, CC_PATH_RESERVED, '_', gc); + const char *safe_filename = string_mod_const(filename, CC_PRINT, CC_PATH_RESERVED, '_', gc); - if (safe_filename - && strcmp (safe_filename, ".") - && strcmp (safe_filename, "..") + if (safe_filename + && strcmp(safe_filename, ".") + && strcmp(safe_filename, "..") #ifdef _WIN32 - && win_safe_filename (safe_filename) + && win_safe_filename(safe_filename) #endif - ) + ) { - const size_t outsize = strlen(safe_filename) + (directory ? strlen (directory) : 0) + 16; - struct buffer out = alloc_buf_gc (outsize, gc); - char dirsep[2]; + const size_t outsize = strlen(safe_filename) + (directory ? strlen(directory) : 0) + 16; + struct buffer out = alloc_buf_gc(outsize, gc); + char dirsep[2]; - dirsep[0] = OS_SPECIFIC_DIRSEP; - dirsep[1] = '\0'; + dirsep[0] = OS_SPECIFIC_DIRSEP; + dirsep[1] = '\0'; - if (directory) - buf_printf (&out, "%s%s", directory, dirsep); - buf_printf (&out, "%s", safe_filename); + if (directory) + { + buf_printf(&out, "%s%s", directory, dirsep); + } + buf_printf(&out, "%s", safe_filename); - return BSTR (&out); + return BSTR(&out); + } + else + { + return NULL; } - else - return NULL; } bool -absolute_pathname (const char *pathname) +absolute_pathname(const char *pathname) { - if (pathname) + if (pathname) { - const int c = pathname[0]; + const int c = pathname[0]; #ifdef _WIN32 - return c == '\\' || (isalpha(c) && pathname[1] == ':' && pathname[2] == '\\'); + return c == '\\' || (isalpha(c) && pathname[1] == ':' && pathname[2] == '\\'); #else - return c == '/'; + return c == '/'; #endif } - else - return false; + else + { + return false; + } } /* @@ -1004,233 +1090,263 @@ absolute_pathname (const char *pathname) */ bool -get_user_pass_cr (struct user_pass *up, - const char *auth_file, - const char *prefix, - const unsigned int flags, - const char *auth_challenge) +get_user_pass_cr(struct user_pass *up, + const char *auth_file, + const char *prefix, + const unsigned int flags, + const char *auth_challenge) { - struct gc_arena gc = gc_new (); + struct gc_arena gc = gc_new(); - if (!up->defined) + if (!up->defined) { - bool from_authfile = (auth_file && !streq (auth_file, "stdin")); - bool username_from_stdin = false; - bool password_from_stdin = false; - bool response_from_stdin = true; + bool from_authfile = (auth_file && !streq(auth_file, "stdin")); + bool username_from_stdin = false; + bool password_from_stdin = false; + bool response_from_stdin = true; - if (flags & GET_USER_PASS_PREVIOUS_CREDS_FAILED) - msg (M_WARN, "Note: previous '%s' credentials failed", prefix); + if (flags & GET_USER_PASS_PREVIOUS_CREDS_FAILED) + { + msg(M_WARN, "Note: previous '%s' credentials failed", prefix); + } #ifdef ENABLE_MANAGEMENT - /* - * Get username/password from management interface? - */ - if (management - && (!from_authfile && (flags & GET_USER_PASS_MANAGEMENT)) - && management_query_user_pass_enabled (management)) - { - const char *sc = NULL; - response_from_stdin = false; - - if (flags & GET_USER_PASS_PREVIOUS_CREDS_FAILED) - management_auth_failure (management, prefix, "previous auth credentials failed"); + /* + * Get username/password from management interface? + */ + if (management + && (!from_authfile && (flags & GET_USER_PASS_MANAGEMENT)) + && management_query_user_pass_enabled(management)) + { + const char *sc = NULL; + response_from_stdin = false; + + if (flags & GET_USER_PASS_PREVIOUS_CREDS_FAILED) + { + management_auth_failure(management, prefix, "previous auth credentials failed"); + } #ifdef ENABLE_CLIENT_CR - if (auth_challenge && (flags & GET_USER_PASS_STATIC_CHALLENGE)) - sc = auth_challenge; -#endif - if (!management_query_user_pass (management, up, prefix, flags, sc)) - { - if ((flags & GET_USER_PASS_NOFATAL) != 0) - return false; - else - msg (M_FATAL, "ERROR: could not read %s username/password/ok/string from management interface", prefix); - } - } - else + if (auth_challenge && (flags & GET_USER_PASS_STATIC_CHALLENGE)) + { + sc = auth_challenge; + } #endif - /* - * Get NEED_OK confirmation from the console - */ - if (flags & GET_USER_PASS_NEED_OK) - { - struct buffer user_prompt = alloc_buf_gc (128, &gc); - - buf_printf (&user_prompt, "NEED-OK|%s|%s:", prefix, up->username); - if (!query_user_SINGLE (BSTR(&user_prompt), BLEN(&user_prompt), - up->password, USER_PASS_LEN, false)) + if (!management_query_user_pass(management, up, prefix, flags, sc)) { - msg (M_FATAL, "ERROR: could not read %s ok-confirmation from stdin", prefix); + if ((flags & GET_USER_PASS_NOFATAL) != 0) + { + return false; + } + else + { + msg(M_FATAL, "ERROR: could not read %s username/password/ok/string from management interface", prefix); + } } - - if (!strlen (up->password)) - strcpy (up->password, "ok"); - } - else if (flags & GET_USER_PASS_INLINE_CREDS) - { - struct buffer buf; - buf_set_read (&buf, (uint8_t*) auth_file, strlen (auth_file) + 1); - if (!(flags & GET_USER_PASS_PASSWORD_ONLY)) - buf_parse (&buf, '\n', up->username, USER_PASS_LEN); - buf_parse (&buf, '\n', up->password, USER_PASS_LEN); - } - /* - * Read from auth file unless this is a dynamic challenge request. - */ - else if (from_authfile && !(flags & GET_USER_PASS_DYNAMIC_CHALLENGE)) + } + else +#endif /* ifdef ENABLE_MANAGEMENT */ + /* + * Get NEED_OK confirmation from the console + */ + if (flags & GET_USER_PASS_NEED_OK) { - /* - * Try to get username/password from a file. - */ - FILE *fp; - char password_buf[USER_PASS_LEN] = { '\0' }; + struct buffer user_prompt = alloc_buf_gc(128, &gc); - fp = platform_fopen (auth_file, "r"); - if (!fp) - msg (M_ERR, "Error opening '%s' auth file: %s", prefix, auth_file); + buf_printf(&user_prompt, "NEED-OK|%s|%s:", prefix, up->username); + if (!query_user_SINGLE(BSTR(&user_prompt), BLEN(&user_prompt), + up->password, USER_PASS_LEN, false)) + { + msg(M_FATAL, "ERROR: could not read %s ok-confirmation from stdin", prefix); + } + + if (!strlen(up->password)) + { + strcpy(up->password, "ok"); + } + } + else if (flags & GET_USER_PASS_INLINE_CREDS) + { + struct buffer buf; + buf_set_read(&buf, (uint8_t *) auth_file, strlen(auth_file) + 1); + if (!(flags & GET_USER_PASS_PASSWORD_ONLY)) + { + buf_parse(&buf, '\n', up->username, USER_PASS_LEN); + } + buf_parse(&buf, '\n', up->password, USER_PASS_LEN); + } + /* + * Read from auth file unless this is a dynamic challenge request. + */ + else if (from_authfile && !(flags & GET_USER_PASS_DYNAMIC_CHALLENGE)) + { + /* + * Try to get username/password from a file. + */ + FILE *fp; + char password_buf[USER_PASS_LEN] = { '\0' }; + + fp = platform_fopen(auth_file, "r"); + if (!fp) + { + msg(M_ERR, "Error opening '%s' auth file: %s", prefix, auth_file); + } - if ((flags & GET_USER_PASS_PASSWORD_ONLY) == 0) + if ((flags & GET_USER_PASS_PASSWORD_ONLY) == 0) { - /* Read username first */ - if (fgets (up->username, USER_PASS_LEN, fp) == NULL) - msg (M_FATAL, "Error reading username from %s authfile: %s", - prefix, - auth_file); - } - chomp (up->username); - - if (fgets (password_buf, USER_PASS_LEN, fp) != NULL) + /* Read username first */ + if (fgets(up->username, USER_PASS_LEN, fp) == NULL) + { + msg(M_FATAL, "Error reading username from %s authfile: %s", + prefix, + auth_file); + } + } + chomp(up->username); + + if (fgets(password_buf, USER_PASS_LEN, fp) != NULL) { - chomp (password_buf); + chomp(password_buf); } - if (flags & GET_USER_PASS_PASSWORD_ONLY && !password_buf[0]) - msg (M_FATAL, "Error reading password from %s authfile: %s", prefix, auth_file); + if (flags & GET_USER_PASS_PASSWORD_ONLY && !password_buf[0]) + { + msg(M_FATAL, "Error reading password from %s authfile: %s", prefix, auth_file); + } - if (password_buf[0]) - strncpy(up->password, password_buf, USER_PASS_LEN); - else - password_from_stdin = 1; + if (password_buf[0]) + { + strncpy(up->password, password_buf, USER_PASS_LEN); + } + else + { + password_from_stdin = 1; + } - fclose (fp); + fclose(fp); - if (!(flags & GET_USER_PASS_PASSWORD_ONLY) && strlen (up->username) == 0) - msg (M_FATAL, "ERROR: username from %s authfile '%s' is empty", prefix, auth_file); + if (!(flags & GET_USER_PASS_PASSWORD_ONLY) && strlen(up->username) == 0) + { + msg(M_FATAL, "ERROR: username from %s authfile '%s' is empty", prefix, auth_file); + } } - else + else { - username_from_stdin = true; - password_from_stdin = true; + username_from_stdin = true; + password_from_stdin = true; } - /* - * Get username/password from standard input? - */ - if (username_from_stdin || password_from_stdin || response_from_stdin) - { + /* + * Get username/password from standard input? + */ + if (username_from_stdin || password_from_stdin || response_from_stdin) + { #ifdef ENABLE_CLIENT_CR - if (auth_challenge && (flags & GET_USER_PASS_DYNAMIC_CHALLENGE) && response_from_stdin) - { - struct auth_challenge_info *ac = get_auth_challenge (auth_challenge, &gc); - if (ac) - { - char *response = (char *) gc_malloc (USER_PASS_LEN, false, &gc); - struct buffer packed_resp, challenge; - - challenge = alloc_buf_gc (14+strlen(ac->challenge_text), &gc); - buf_printf (&challenge, "CHALLENGE: %s", ac->challenge_text); - buf_set_write (&packed_resp, (uint8_t*)up->password, USER_PASS_LEN); - - if (!query_user_SINGLE (BSTR(&challenge), BLEN(&challenge), - response, USER_PASS_LEN, BOOL_CAST(ac->flags&CR_ECHO))) - { - msg (M_FATAL, "ERROR: could not read challenge response from stdin"); - } - strncpynt (up->username, ac->user, USER_PASS_LEN); - buf_printf (&packed_resp, "CRV1::%s::%s", ac->state_id, response); - } - else - { - msg (M_FATAL, "ERROR: received malformed challenge request from server"); - } - } - else -#endif - { - struct buffer user_prompt = alloc_buf_gc (128, &gc); - struct buffer pass_prompt = alloc_buf_gc (128, &gc); + if (auth_challenge && (flags & GET_USER_PASS_DYNAMIC_CHALLENGE) && response_from_stdin) + { + struct auth_challenge_info *ac = get_auth_challenge(auth_challenge, &gc); + if (ac) + { + char *response = (char *) gc_malloc(USER_PASS_LEN, false, &gc); + struct buffer packed_resp, challenge; + + challenge = alloc_buf_gc(14+strlen(ac->challenge_text), &gc); + buf_printf(&challenge, "CHALLENGE: %s", ac->challenge_text); + buf_set_write(&packed_resp, (uint8_t *)up->password, USER_PASS_LEN); + + if (!query_user_SINGLE(BSTR(&challenge), BLEN(&challenge), + response, USER_PASS_LEN, BOOL_CAST(ac->flags&CR_ECHO))) + { + msg(M_FATAL, "ERROR: could not read challenge response from stdin"); + } + strncpynt(up->username, ac->user, USER_PASS_LEN); + buf_printf(&packed_resp, "CRV1::%s::%s", ac->state_id, response); + } + else + { + msg(M_FATAL, "ERROR: received malformed challenge request from server"); + } + } + else +#endif /* ifdef ENABLE_CLIENT_CR */ + { + struct buffer user_prompt = alloc_buf_gc(128, &gc); + struct buffer pass_prompt = alloc_buf_gc(128, &gc); - query_user_clear (); - buf_printf (&user_prompt, "Enter %s Username:", prefix); - buf_printf (&pass_prompt, "Enter %s Password:", prefix); + query_user_clear(); + buf_printf(&user_prompt, "Enter %s Username:", prefix); + buf_printf(&pass_prompt, "Enter %s Password:", prefix); - if (username_from_stdin && !(flags & GET_USER_PASS_PASSWORD_ONLY)) - { - query_user_add (BSTR(&user_prompt), BLEN(&user_prompt), - up->username, USER_PASS_LEN, true); - } + if (username_from_stdin && !(flags & GET_USER_PASS_PASSWORD_ONLY)) + { + query_user_add(BSTR(&user_prompt), BLEN(&user_prompt), + up->username, USER_PASS_LEN, true); + } - if (password_from_stdin) + if (password_from_stdin) { - query_user_add (BSTR(&pass_prompt), BLEN(&pass_prompt), - up->password, USER_PASS_LEN, false); + query_user_add(BSTR(&pass_prompt), BLEN(&pass_prompt), + up->password, USER_PASS_LEN, false); } - if( !query_user_exec () ) - { - msg(M_FATAL, "ERROR: Failed retrieving username or password"); - } + if (!query_user_exec() ) + { + msg(M_FATAL, "ERROR: Failed retrieving username or password"); + } - if (!(flags & GET_USER_PASS_PASSWORD_ONLY)) - { - if (strlen (up->username) == 0) - msg (M_FATAL, "ERROR: %s username is empty", prefix); - } + if (!(flags & GET_USER_PASS_PASSWORD_ONLY)) + { + if (strlen(up->username) == 0) + { + msg(M_FATAL, "ERROR: %s username is empty", prefix); + } + } #ifdef ENABLE_CLIENT_CR - if (auth_challenge && (flags & GET_USER_PASS_STATIC_CHALLENGE) && response_from_stdin) - { - char *response = (char *) gc_malloc (USER_PASS_LEN, false, &gc); - struct buffer packed_resp, challenge; - char *pw64=NULL, *resp64=NULL; - - challenge = alloc_buf_gc (14+strlen(auth_challenge), &gc); - buf_printf (&challenge, "CHALLENGE: %s", auth_challenge); - - if (!query_user_SINGLE (BSTR(&challenge), BLEN(&challenge), - response, USER_PASS_LEN, - BOOL_CAST(flags & GET_USER_PASS_STATIC_CHALLENGE_ECHO))) - { - msg (M_FATAL, "ERROR: could not retrieve static challenge response"); - } - if (openvpn_base64_encode(up->password, strlen(up->password), &pw64) == -1 - || openvpn_base64_encode(response, strlen(response), &resp64) == -1) - msg (M_FATAL, "ERROR: could not base64-encode password/static_response"); - buf_set_write (&packed_resp, (uint8_t*)up->password, USER_PASS_LEN); - buf_printf (&packed_resp, "SCRV1:%s:%s", pw64, resp64); - string_clear(pw64); - free(pw64); - string_clear(resp64); - free(resp64); - } -#endif - } - } + if (auth_challenge && (flags & GET_USER_PASS_STATIC_CHALLENGE) && response_from_stdin) + { + char *response = (char *) gc_malloc(USER_PASS_LEN, false, &gc); + struct buffer packed_resp, challenge; + char *pw64 = NULL, *resp64 = NULL; + + challenge = alloc_buf_gc(14+strlen(auth_challenge), &gc); + buf_printf(&challenge, "CHALLENGE: %s", auth_challenge); + + if (!query_user_SINGLE(BSTR(&challenge), BLEN(&challenge), + response, USER_PASS_LEN, + BOOL_CAST(flags & GET_USER_PASS_STATIC_CHALLENGE_ECHO))) + { + msg(M_FATAL, "ERROR: could not retrieve static challenge response"); + } + if (openvpn_base64_encode(up->password, strlen(up->password), &pw64) == -1 + || openvpn_base64_encode(response, strlen(response), &resp64) == -1) + { + msg(M_FATAL, "ERROR: could not base64-encode password/static_response"); + } + buf_set_write(&packed_resp, (uint8_t *)up->password, USER_PASS_LEN); + buf_printf(&packed_resp, "SCRV1:%s:%s", pw64, resp64); + string_clear(pw64); + free(pw64); + string_clear(resp64); + free(resp64); + } +#endif /* ifdef ENABLE_CLIENT_CR */ + } + } - string_mod (up->username, CC_PRINT, CC_CRLF, 0); - string_mod (up->password, CC_PRINT, CC_CRLF, 0); + string_mod(up->username, CC_PRINT, CC_CRLF, 0); + string_mod(up->password, CC_PRINT, CC_CRLF, 0); - up->defined = true; + up->defined = true; } #if 0 - msg (M_INFO, "GET_USER_PASS %s u='%s' p='%s'", prefix, up->username, up->password); + msg(M_INFO, "GET_USER_PASS %s u='%s' p='%s'", prefix, up->username, up->password); #endif - gc_free (&gc); + gc_free(&gc); - return true; + return true; } #ifdef ENABLE_CLIENT_CR @@ -1240,125 +1356,143 @@ get_user_pass_cr (struct user_pass *up, * the dynamic challenge/response protocol implemented here. */ struct auth_challenge_info * -get_auth_challenge (const char *auth_challenge, struct gc_arena *gc) -{ - if (auth_challenge) - { - struct auth_challenge_info *ac; - const int len = strlen (auth_challenge); - char *work = (char *) gc_malloc (len+1, false, gc); - char *cp; - - struct buffer b; - buf_set_read (&b, (const uint8_t *)auth_challenge, len); - - ALLOC_OBJ_CLEAR_GC (ac, struct auth_challenge_info, gc); - - /* parse prefix */ - if (!buf_parse(&b, ':', work, len)) - return NULL; - if (strcmp(work, "CRV1")) - return NULL; - - /* parse flags */ - if (!buf_parse(&b, ':', work, len)) - return NULL; - for (cp = work; *cp != '\0'; ++cp) - { - const char c = *cp; - if (c == 'E') - ac->flags |= CR_ECHO; - else if (c == 'R') - ac->flags |= CR_RESPONSE; - } - - /* parse state ID */ - if (!buf_parse(&b, ':', work, len)) - return NULL; - ac->state_id = string_alloc(work, gc); - - /* parse user name */ - if (!buf_parse(&b, ':', work, len)) - return NULL; - ac->user = (char *) gc_malloc (strlen(work)+1, true, gc); - openvpn_base64_decode(work, (void*)ac->user, -1); - - /* parse challenge text */ - ac->challenge_text = string_alloc(BSTR(&b), gc); - - return ac; - } - else - return NULL; +get_auth_challenge(const char *auth_challenge, struct gc_arena *gc) +{ + if (auth_challenge) + { + struct auth_challenge_info *ac; + const int len = strlen(auth_challenge); + char *work = (char *) gc_malloc(len+1, false, gc); + char *cp; + + struct buffer b; + buf_set_read(&b, (const uint8_t *)auth_challenge, len); + + ALLOC_OBJ_CLEAR_GC(ac, struct auth_challenge_info, gc); + + /* parse prefix */ + if (!buf_parse(&b, ':', work, len)) + { + return NULL; + } + if (strcmp(work, "CRV1")) + { + return NULL; + } + + /* parse flags */ + if (!buf_parse(&b, ':', work, len)) + { + return NULL; + } + for (cp = work; *cp != '\0'; ++cp) + { + const char c = *cp; + if (c == 'E') + { + ac->flags |= CR_ECHO; + } + else if (c == 'R') + { + ac->flags |= CR_RESPONSE; + } + } + + /* parse state ID */ + if (!buf_parse(&b, ':', work, len)) + { + return NULL; + } + ac->state_id = string_alloc(work, gc); + + /* parse user name */ + if (!buf_parse(&b, ':', work, len)) + { + return NULL; + } + ac->user = (char *) gc_malloc(strlen(work)+1, true, gc); + openvpn_base64_decode(work, (void *)ac->user, -1); + + /* parse challenge text */ + ac->challenge_text = string_alloc(BSTR(&b), gc); + + return ac; + } + else + { + return NULL; + } } -#endif +#endif /* ifdef ENABLE_CLIENT_CR */ #if AUTO_USERID void -get_user_pass_auto_userid (struct user_pass *up, const char *tag) +get_user_pass_auto_userid(struct user_pass *up, const char *tag) { - struct gc_arena gc = gc_new (); - struct buffer buf; - uint8_t macaddr[6]; - static uint8_t digest [MD5_DIGEST_LENGTH]; - static const uint8_t hashprefix[] = "AUTO_USERID_DIGEST"; + struct gc_arena gc = gc_new(); + struct buffer buf; + uint8_t macaddr[6]; + static uint8_t digest [MD5_DIGEST_LENGTH]; + static const uint8_t hashprefix[] = "AUTO_USERID_DIGEST"; - const md_kt_t *md5_kt = md_kt_get("MD5"); - md_ctx_t ctx; + const md_kt_t *md5_kt = md_kt_get("MD5"); + md_ctx_t ctx; - CLEAR (*up); - buf_set_write (&buf, (uint8_t*)up->username, USER_PASS_LEN); - buf_printf (&buf, "%s", TARGET_PREFIX); - if (get_default_gateway_mac_addr (macaddr)) + CLEAR(*up); + buf_set_write(&buf, (uint8_t *)up->username, USER_PASS_LEN); + buf_printf(&buf, "%s", TARGET_PREFIX); + if (get_default_gateway_mac_addr(macaddr)) + { + dmsg(D_AUTO_USERID, "GUPAU: macaddr=%s", format_hex_ex(macaddr, sizeof(macaddr), 0, 1, ":", &gc)); + md_ctx_init(&ctx, md5_kt); + md_ctx_update(&ctx, hashprefix, sizeof(hashprefix) - 1); + md_ctx_update(&ctx, macaddr, sizeof(macaddr)); + md_ctx_final(&ctx, digest); + md_ctx_cleanup(&ctx) + buf_printf(&buf, "%s", format_hex_ex(digest, sizeof(digest), 0, 256, " ", &gc)); + } + else { - dmsg (D_AUTO_USERID, "GUPAU: macaddr=%s", format_hex_ex (macaddr, sizeof (macaddr), 0, 1, ":", &gc)); - md_ctx_init(&ctx, md5_kt); - md_ctx_update(&ctx, hashprefix, sizeof (hashprefix) - 1); - md_ctx_update(&ctx, macaddr, sizeof (macaddr)); - md_ctx_final(&ctx, digest); - md_ctx_cleanup(&ctx) - buf_printf(&buf, "%s", format_hex_ex (digest, sizeof (digest), 0, 256, " ", &gc)); + buf_printf(&buf, "UNKNOWN"); } - else + if (tag && strcmp(tag, "stdin")) { - buf_printf (&buf, "UNKNOWN"); + buf_printf(&buf, "-%s", tag); } - if (tag && strcmp (tag, "stdin")) - buf_printf (&buf, "-%s", tag); - up->defined = true; - gc_free (&gc); + up->defined = true; + gc_free(&gc); - dmsg (D_AUTO_USERID, "GUPAU: AUTO_USERID: '%s'", up->username); + dmsg(D_AUTO_USERID, "GUPAU: AUTO_USERID: '%s'", up->username); } -#endif +#endif /* if AUTO_USERID */ void -purge_user_pass (struct user_pass *up, const bool force) +purge_user_pass(struct user_pass *up, const bool force) { - const bool nocache = up->nocache; - static bool warn_shown = false; - if (nocache || force) + const bool nocache = up->nocache; + static bool warn_shown = false; + if (nocache || force) { - secure_memzero (up, sizeof(*up)); - up->nocache = nocache; + secure_memzero(up, sizeof(*up)); + up->nocache = nocache; } - else if (!warn_shown) + else if (!warn_shown) { - msg (M_WARN, "WARNING: this configuration may cache passwords in memory -- use the auth-nocache option to prevent this"); - warn_shown = true; + msg(M_WARN, "WARNING: this configuration may cache passwords in memory -- use the auth-nocache option to prevent this"); + warn_shown = true; } } void -set_auth_token (struct user_pass *up, const char *token) +set_auth_token(struct user_pass *up, const char *token) { - if (token && strlen(token) && up && up->defined && !up->nocache) + if (token && strlen(token) && up && up->defined && !up->nocache) { - CLEAR (up->password); - strncpynt (up->password, token, USER_PASS_LEN); + CLEAR(up->password); + strncpynt(up->password, token, USER_PASS_LEN); } } @@ -1369,173 +1503,184 @@ set_auth_token (struct user_pass *up, const char *token) * Assumes that string has been null terminated. */ const char * -safe_print (const char *str, struct gc_arena *gc) +safe_print(const char *str, struct gc_arena *gc) { - return string_mod_const (str, CC_PRINT, CC_CRLF, '.', gc); + return string_mod_const(str, CC_PRINT, CC_CRLF, '.', gc); } static bool -is_password_env_var (const char *str) +is_password_env_var(const char *str) { - return (strncmp (str, "password", 8) == 0); + return (strncmp(str, "password", 8) == 0); } bool -env_allowed (const char *str) +env_allowed(const char *str) { - return (script_security >= SSEC_PW_ENV || !is_password_env_var (str)); + return (script_security >= SSEC_PW_ENV || !is_password_env_var(str)); } bool -env_safe_to_print (const char *str) +env_safe_to_print(const char *str) { #ifndef UNSAFE_DEBUG - if (is_password_env_var (str)) - return false; + if (is_password_env_var(str)) + { + return false; + } #endif - return true; + return true; } /* Make arrays of strings */ const char ** -make_env_array (const struct env_set *es, - const bool check_allowed, - struct gc_arena *gc) +make_env_array(const struct env_set *es, + const bool check_allowed, + struct gc_arena *gc) { - char **ret = NULL; - struct env_item *e = NULL; - int i = 0, n = 0; + char **ret = NULL; + struct env_item *e = NULL; + int i = 0, n = 0; - /* figure length of es */ - if (es) + /* figure length of es */ + if (es) { - for (e = es->list; e != NULL; e = e->next) - ++n; + for (e = es->list; e != NULL; e = e->next) + ++n; } - /* alloc return array */ - ALLOC_ARRAY_CLEAR_GC (ret, char *, n+1, gc); + /* alloc return array */ + ALLOC_ARRAY_CLEAR_GC(ret, char *, n+1, gc); - /* fill return array */ - if (es) + /* fill return array */ + if (es) { - i = 0; - for (e = es->list; e != NULL; e = e->next) - { - if (!check_allowed || env_allowed (e->string)) - { - ASSERT (i < n); - ret[i++] = e->string; - } - } + i = 0; + for (e = es->list; e != NULL; e = e->next) + { + if (!check_allowed || env_allowed(e->string)) + { + ASSERT(i < n); + ret[i++] = e->string; + } + } } - ret[i] = NULL; - return (const char **)ret; + ret[i] = NULL; + return (const char **)ret; } const char ** -make_arg_array (const char *first, const char *parms, struct gc_arena *gc) +make_arg_array(const char *first, const char *parms, struct gc_arena *gc) { - char **ret = NULL; - int base = 0; - const int max_parms = MAX_PARMS + 2; - int n = 0; + char **ret = NULL; + int base = 0; + const int max_parms = MAX_PARMS + 2; + int n = 0; - /* alloc return array */ - ALLOC_ARRAY_CLEAR_GC (ret, char *, max_parms, gc); + /* alloc return array */ + ALLOC_ARRAY_CLEAR_GC(ret, char *, max_parms, gc); - /* process first parameter, if provided */ - if (first) + /* process first parameter, if provided */ + if (first) { - ret[base++] = string_alloc (first, gc); + ret[base++] = string_alloc(first, gc); } - if (parms) + if (parms) { - n = parse_line (parms, &ret[base], max_parms - base - 1, "make_arg_array", 0, M_WARN, gc); - ASSERT (n >= 0 && n + base + 1 <= max_parms); + n = parse_line(parms, &ret[base], max_parms - base - 1, "make_arg_array", 0, M_WARN, gc); + ASSERT(n >= 0 && n + base + 1 <= max_parms); } - ret[base + n] = NULL; + ret[base + n] = NULL; - return (const char **)ret; + return (const char **)ret; } static const char ** -make_inline_array (const char *str, struct gc_arena *gc) +make_inline_array(const char *str, struct gc_arena *gc) { - char line[OPTION_LINE_SIZE]; - struct buffer buf; - int len = 0; - char **ret = NULL; - int i = 0; + char line[OPTION_LINE_SIZE]; + struct buffer buf; + int len = 0; + char **ret = NULL; + int i = 0; - buf_set_read (&buf, (const uint8_t *) str, strlen (str)); - while (buf_parse (&buf, '\n', line, sizeof (line))) - ++len; + buf_set_read(&buf, (const uint8_t *) str, strlen(str)); + while (buf_parse(&buf, '\n', line, sizeof(line))) + ++len; - /* alloc return array */ - ALLOC_ARRAY_CLEAR_GC (ret, char *, len + 1, gc); + /* alloc return array */ + ALLOC_ARRAY_CLEAR_GC(ret, char *, len + 1, gc); - buf_set_read (&buf, (const uint8_t *) str, strlen(str)); - while (buf_parse (&buf, '\n', line, sizeof (line))) + buf_set_read(&buf, (const uint8_t *) str, strlen(str)); + while (buf_parse(&buf, '\n', line, sizeof(line))) { - chomp (line); - ASSERT (i < len); - ret[i] = string_alloc (skip_leading_whitespace (line), gc); - ++i; - } - ASSERT (i <= len); - ret[i] = NULL; - return (const char **)ret; + chomp(line); + ASSERT(i < len); + ret[i] = string_alloc(skip_leading_whitespace(line), gc); + ++i; + } + ASSERT(i <= len); + ret[i] = NULL; + return (const char **)ret; } static const char ** -make_arg_copy (char **p, struct gc_arena *gc) +make_arg_copy(char **p, struct gc_arena *gc) { - char **ret = NULL; - const int len = string_array_len ((const char **)p); - const int max_parms = len + 1; - int i; + char **ret = NULL; + const int len = string_array_len((const char **)p); + const int max_parms = len + 1; + int i; - /* alloc return array */ - ALLOC_ARRAY_CLEAR_GC (ret, char *, max_parms, gc); + /* alloc return array */ + ALLOC_ARRAY_CLEAR_GC(ret, char *, max_parms, gc); - for (i = 0; i < len; ++i) - ret[i] = p[i]; + for (i = 0; i < len; ++i) + ret[i] = p[i]; - return (const char **)ret; + return (const char **)ret; } const char ** -make_extended_arg_array (char **p, struct gc_arena *gc) -{ - const int argc = string_array_len ((const char **)p); - if (!strcmp (p[0], INLINE_FILE_TAG) && argc == 2) - return make_inline_array (p[1], gc); - else - if (argc == 0) - return make_arg_array (NULL, NULL, gc); - else if (argc == 1) - return make_arg_array (p[0], NULL, gc); - else if (argc == 2) - return make_arg_array (p[0], p[1], gc); - else - return make_arg_copy (p, gc); +make_extended_arg_array(char **p, struct gc_arena *gc) +{ + const int argc = string_array_len((const char **)p); + if (!strcmp(p[0], INLINE_FILE_TAG) && argc == 2) + { + return make_inline_array(p[1], gc); + } + else if (argc == 0) + { + return make_arg_array(NULL, NULL, gc); + } + else if (argc == 1) + { + return make_arg_array(p[0], NULL, gc); + } + else if (argc == 2) + { + return make_arg_array(p[0], p[1], gc); + } + else + { + return make_arg_copy(p, gc); + } } void -openvpn_sleep (const int n) +openvpn_sleep(const int n) { #ifdef ENABLE_MANAGEMENT - if (management) + if (management) { - management_event_loop_n_seconds (management, n); - return; + management_event_loop_n_seconds(management, n); + return; } #endif - sleep (n); + sleep(n); } /* @@ -1543,17 +1688,17 @@ openvpn_sleep (const int n) * or u if u is a power of 2. */ size_t -adjust_power_of_2 (size_t u) +adjust_power_of_2(size_t u) { - size_t ret = 1; + size_t ret = 1; - while (ret < u) + while (ret < u) { - ret <<= 1; - ASSERT (ret > 0); + ret <<= 1; + ASSERT(ret > 0); } - return ret; + return ret; } /* @@ -1563,57 +1708,61 @@ adjust_power_of_2 (size_t u) const char * sanitize_control_message(const char *src, struct gc_arena *gc) { - char *ret = gc_malloc (strlen(src)+1, false, gc); - char *dest = ret; - bool redact = false; - int skip = 0; - - for (;;) - { - const char c = *src; - if (c == '\0') - break; - if (c == 'S' && !strncmp(src, "SESS_ID_", 8)) - { - skip = 7; - redact = true; - } - else if (c == 'e' && !strncmp(src, "echo ", 5)) - { - skip = 4; - redact = true; - } - else if (!check_debug_level(D_SHOW_KEYS) - && (c == 'a' && !strncmp(src, "auth-token ", 11))) - { - /* Unless --verb is 7 or higher (D_SHOW_KEYS), hide - * the auth-token value coming in the src string - */ - skip = 10; - redact = true; - } - - if (c == ',') /* end of redacted item? */ - { - skip = 0; - redact = false; - } - - if (redact) - { - if (skip > 0) - { - --skip; - *dest++ = c; - } - } - else - *dest++ = c; - - ++src; - } - *dest = '\0'; - return ret; + char *ret = gc_malloc(strlen(src)+1, false, gc); + char *dest = ret; + bool redact = false; + int skip = 0; + + for (;; ) + { + const char c = *src; + if (c == '\0') + { + break; + } + if (c == 'S' && !strncmp(src, "SESS_ID_", 8)) + { + skip = 7; + redact = true; + } + else if (c == 'e' && !strncmp(src, "echo ", 5)) + { + skip = 4; + redact = true; + } + else if (!check_debug_level(D_SHOW_KEYS) + && (c == 'a' && !strncmp(src, "auth-token ", 11))) + { + /* Unless --verb is 7 or higher (D_SHOW_KEYS), hide + * the auth-token value coming in the src string + */ + skip = 10; + redact = true; + } + + if (c == ',') /* end of redacted item? */ + { + skip = 0; + redact = false; + } + + if (redact) + { + if (skip > 0) + { + --skip; + *dest++ = c; + } + } + else + { + *dest++ = c; + } + + ++src; + } + *dest = '\0'; + return ret; } /** @@ -1626,14 +1775,16 @@ sanitize_control_message(const char *src, struct gc_arena *gc) * @return Returns 0 if the flag is not set, otherwise the 'flag' value is returned */ bool -compat_flag (unsigned int flag) +compat_flag(unsigned int flag) { - static unsigned int compat_flags = 0; + static unsigned int compat_flags = 0; - if (flag & COMPAT_FLAG_SET) - compat_flags |= (flag >> 1); + if (flag & COMPAT_FLAG_SET) + { + compat_flags |= (flag >> 1); + } - return (compat_flags & (flag >> 1)); + return (compat_flags & (flag >> 1)); } @@ -1645,49 +1796,60 @@ compat_flag (unsigned int flag) bool validate_peer_info_line(char *line) { - uint8_t c; - int state = 0; - while (*line) - { - c = *line; - switch (state) - { - case 0: - case 1: - if (c == '=' && state == 1) - state = 2; - else if (isalnum(c) || c == '_') - state = 1; - else - return false; - case 2: - /* after the '=', replace non-printable or shell meta with '_' */ - if (!isprint(c) || isspace(c) || - c == '$' || c == '(' || c == '`' ) - *line = '_'; - } - line++; - } - return (state == 2); + uint8_t c; + int state = 0; + while (*line) + { + c = *line; + switch (state) + { + case 0: + case 1: + if (c == '=' && state == 1) + { + state = 2; + } + else if (isalnum(c) || c == '_') + { + state = 1; + } + else + { + return false; + } + + case 2: + /* after the '=', replace non-printable or shell meta with '_' */ + if (!isprint(c) || isspace(c) + || c == '$' || c == '(' || c == '`') + { + *line = '_'; + } + } + line++; + } + return (state == 2); } void -output_peer_info_env (struct env_set *es, const char * peer_info) -{ - char line[256]; - struct buffer buf; - buf_set_read (&buf, (const uint8_t *) peer_info, strlen(peer_info)); - while (buf_parse (&buf, '\n', line, sizeof (line))) - { - chomp (line); - if (validate_peer_info_line(line) && - (strncmp(line, "IV_", 3) == 0 || strncmp(line, "UV_", 3) == 0) ) - { - msg (M_INFO, "peer info: %s", line); - env_set_add(es, line); - } - else - msg (M_WARN, "validation failed on peer_info line received from client"); +output_peer_info_env(struct env_set *es, const char *peer_info) +{ + char line[256]; + struct buffer buf; + buf_set_read(&buf, (const uint8_t *) peer_info, strlen(peer_info)); + while (buf_parse(&buf, '\n', line, sizeof(line))) + { + chomp(line); + if (validate_peer_info_line(line) + && (strncmp(line, "IV_", 3) == 0 || strncmp(line, "UV_", 3) == 0) ) + { + msg(M_INFO, "peer info: %s", line); + env_set_add(es, line); + } + else + { + msg(M_WARN, "validation failed on peer_info line received from client"); + } } } diff --git a/src/openvpn/misc.h b/src/openvpn/misc.h index b8bbaa7fe09..606c46552c0 100644 --- a/src/openvpn/misc.h +++ b/src/openvpn/misc.h @@ -43,88 +43,97 @@ struct plugin_list; */ struct env_item { - char *string; - struct env_item *next; + char *string; + struct env_item *next; }; struct env_set { - struct gc_arena *gc; - struct env_item *list; + struct gc_arena *gc; + struct env_item *list; }; -void run_up_down (const char *command, - const struct plugin_list *plugins, - int plugin_type, - const char *arg, +void run_up_down(const char *command, + const struct plugin_list *plugins, + int plugin_type, + const char *arg, #ifdef _WIN32 - DWORD adapter_index, + DWORD adapter_index, #endif - const char *dev_type, - int tun_mtu, - int link_mtu, - const char *ifconfig_local, - const char* ifconfig_remote, - const char *context, - const char *signal_text, - const char *script_type, - struct env_set *es); - -void write_pid (const char *filename); + const char *dev_type, + int tun_mtu, + int link_mtu, + const char *ifconfig_local, + const char *ifconfig_remote, + const char *context, + const char *signal_text, + const char *script_type, + struct env_set *es); + +void write_pid(const char *filename); /* system flags */ #define S_SCRIPT (1<<0) #define S_FATAL (1<<1) -const char *system_error_message (int, struct gc_arena *gc); +const char *system_error_message(int, struct gc_arena *gc); /* wrapper around the execve() call */ -int openvpn_popen (const struct argv *a, const struct env_set *es); -int openvpn_execve (const struct argv *a, const struct env_set *es, const unsigned int flags); -bool openvpn_execve_check (const struct argv *a, const struct env_set *es, const unsigned int flags, const char *error_message); -bool openvpn_execve_allowed (const unsigned int flags); +int openvpn_popen(const struct argv *a, const struct env_set *es); + +int openvpn_execve(const struct argv *a, const struct env_set *es, const unsigned int flags); + +bool openvpn_execve_check(const struct argv *a, const struct env_set *es, const unsigned int flags, const char *error_message); + +bool openvpn_execve_allowed(const unsigned int flags); static inline bool -openvpn_run_script (const struct argv *a, const struct env_set *es, const unsigned int flags, const char *hook) +openvpn_run_script(const struct argv *a, const struct env_set *es, const unsigned int flags, const char *hook) { - char msg[256]; + char msg[256]; - openvpn_snprintf(msg, sizeof(msg), "WARNING: Failed running command (%s)", hook); - return openvpn_execve_check(a, es, flags | S_SCRIPT, msg); + openvpn_snprintf(msg, sizeof(msg), "WARNING: Failed running command (%s)", hook); + return openvpn_execve_check(a, es, flags | S_SCRIPT, msg); } #ifdef HAVE_STRERROR /* a thread-safe version of strerror */ -const char* strerror_ts (int errnum, struct gc_arena *gc); +const char *strerror_ts(int errnum, struct gc_arena *gc); + #endif /* Set standard file descriptors to /dev/null */ -void set_std_files_to_null (bool stdin_only); +void set_std_files_to_null(bool stdin_only); /* dup inetd/xinetd socket descriptor and save */ extern int inetd_socket_descriptor; -void save_inetd_socket_descriptor (void); +void save_inetd_socket_descriptor(void); /* init random() function, only used as source for weak random numbers, when !ENABLE_CRYPTO */ void init_random_seed(void); /* set/delete environmental variable */ -void setenv_str_ex (struct env_set *es, - const char *name, - const char *value, - const unsigned int name_include, - const unsigned int name_exclude, - const char name_replace, - const unsigned int value_include, - const unsigned int value_exclude, - const char value_replace); - -void setenv_counter (struct env_set *es, const char *name, counter_type value); -void setenv_int (struct env_set *es, const char *name, int value); -void setenv_unsigned (struct env_set *es, const char *name, unsigned int value); -void setenv_str (struct env_set *es, const char *name, const char *value); -void setenv_str_safe (struct env_set *es, const char *name, const char *value); -void setenv_del (struct env_set *es, const char *name); +void setenv_str_ex(struct env_set *es, + const char *name, + const char *value, + const unsigned int name_include, + const unsigned int name_exclude, + const char name_replace, + const unsigned int value_include, + const unsigned int value_exclude, + const char value_replace); + +void setenv_counter(struct env_set *es, const char *name, counter_type value); + +void setenv_int(struct env_set *es, const char *name, int value); + +void setenv_unsigned(struct env_set *es, const char *name, unsigned int value); + +void setenv_str(struct env_set *es, const char *name, const char *value); + +void setenv_str_safe(struct env_set *es, const char *name, const char *value); + +void setenv_del(struct env_set *es, const char *name); /** * Store the supplied name value pair in the env_set. If the variable with the @@ -132,51 +141,59 @@ void setenv_del (struct env_set *es, const char *name); */ void setenv_str_incr(struct env_set *es, const char *name, const char *value); -void setenv_int_i (struct env_set *es, const char *name, const int value, const int i); -void setenv_str_i (struct env_set *es, const char *name, const char *value, const int i); +void setenv_int_i(struct env_set *es, const char *name, const int value, const int i); + +void setenv_str_i(struct env_set *es, const char *name, const char *value, const int i); /* struct env_set functions */ -struct env_set *env_set_create (struct gc_arena *gc); -void env_set_destroy (struct env_set *es); -bool env_set_del (struct env_set *es, const char *str); -void env_set_add (struct env_set *es, const char *str); -const char* env_set_get (const struct env_set *es, const char *name); +struct env_set *env_set_create(struct gc_arena *gc); + +void env_set_destroy(struct env_set *es); + +bool env_set_del(struct env_set *es, const char *str); -void env_set_print (int msglevel, const struct env_set *es); +void env_set_add(struct env_set *es, const char *str); -void env_set_inherit (struct env_set *es, const struct env_set *src); +const char *env_set_get(const struct env_set *es, const char *name); -void env_set_add_to_environment (const struct env_set *es); -void env_set_remove_from_environment (const struct env_set *es); +void env_set_print(int msglevel, const struct env_set *es); + +void env_set_inherit(struct env_set *es, const struct env_set *src); + +void env_set_add_to_environment(const struct env_set *es); + +void env_set_remove_from_environment(const struct env_set *es); /* Make arrays of strings */ -const char **make_env_array (const struct env_set *es, - const bool check_allowed, - struct gc_arena *gc); +const char **make_env_array(const struct env_set *es, + const bool check_allowed, + struct gc_arena *gc); + +const char **make_arg_array(const char *first, const char *parms, struct gc_arena *gc); -const char **make_arg_array (const char *first, const char *parms, struct gc_arena *gc); -const char **make_extended_arg_array (char **p, struct gc_arena *gc); +const char **make_extended_arg_array(char **p, struct gc_arena *gc); /* an analogue to the random() function, but use OpenSSL functions if available */ #ifdef ENABLE_CRYPTO long int get_random(void); + #else #define get_random random #endif /* return true if filename can be opened for read */ -bool test_file (const char *filename); +bool test_file(const char *filename); /* create a temporary file in directory, returns the filename of the created file */ -const char *create_temp_file (const char *directory, const char *prefix, struct gc_arena *gc); +const char *create_temp_file(const char *directory, const char *prefix, struct gc_arena *gc); /* put a directory and filename together */ -const char *gen_path (const char *directory, const char *filename, struct gc_arena *gc); +const char *gen_path(const char *directory, const char *filename, struct gc_arena *gc); /* return true if pathname is absolute */ -bool absolute_pathname (const char *pathname); +bool absolute_pathname(const char *pathname); /* prepend a random prefix to hostname (need ENABLE_CRYPTO) */ const char *hostname_randomize(const char *hostname, struct gc_arena *gc); @@ -187,17 +204,17 @@ const char *hostname_randomize(const char *hostname, struct gc_arena *gc); struct user_pass { - bool defined; - bool nocache; + bool defined; + bool nocache; /* max length of username/password */ -# ifdef ENABLE_PKCS11 -# define USER_PASS_LEN 4096 -# else -# define USER_PASS_LEN 128 -# endif - char username[USER_PASS_LEN]; - char password[USER_PASS_LEN]; +#ifdef ENABLE_PKCS11 +#define USER_PASS_LEN 4096 +#else +#define USER_PASS_LEN 128 +#endif + char username[USER_PASS_LEN]; + char password[USER_PASS_LEN]; }; #ifdef ENABLE_CLIENT_CR @@ -205,31 +222,31 @@ struct user_pass * Challenge response info on client as pushed by server. */ struct auth_challenge_info { -# define CR_ECHO (1<<0) /* echo response when typed by user */ -# define CR_RESPONSE (1<<1) /* response needed */ - unsigned int flags; +#define CR_ECHO (1<<0) /* echo response when typed by user */ +#define CR_RESPONSE (1<<1) /* response needed */ + unsigned int flags; - const char *user; - const char *state_id; - const char *challenge_text; + const char *user; + const char *state_id; + const char *challenge_text; }; -struct auth_challenge_info *get_auth_challenge (const char *auth_challenge, struct gc_arena *gc); +struct auth_challenge_info *get_auth_challenge(const char *auth_challenge, struct gc_arena *gc); /* * Challenge response info on client as pushed by server. */ struct static_challenge_info { -# define SC_ECHO (1<<0) /* echo response when typed by user */ - unsigned int flags; +#define SC_ECHO (1<<0) /* echo response when typed by user */ + unsigned int flags; - const char *challenge_text; + const char *challenge_text; }; -#else +#else /* ifdef ENABLE_CLIENT_CR */ struct auth_challenge_info {}; struct static_challenge_info {}; -#endif +#endif /* ifdef ENABLE_CLIENT_CR */ /* * Flags for get_user_pass and management_query_user_pass @@ -248,54 +265,55 @@ struct static_challenge_info {}; #define GET_USER_PASS_INLINE_CREDS (1<<10) /* indicates that auth_file is actually inline creds */ -bool get_user_pass_cr (struct user_pass *up, - const char *auth_file, - const char *prefix, - const unsigned int flags, - const char *auth_challenge); +bool get_user_pass_cr(struct user_pass *up, + const char *auth_file, + const char *prefix, + const unsigned int flags, + const char *auth_challenge); static inline bool -get_user_pass (struct user_pass *up, - const char *auth_file, - const char *prefix, - const unsigned int flags) +get_user_pass(struct user_pass *up, + const char *auth_file, + const char *prefix, + const unsigned int flags) { - return get_user_pass_cr (up, auth_file, prefix, flags, NULL); + return get_user_pass_cr(up, auth_file, prefix, flags, NULL); } -void fail_user_pass (const char *prefix, - const unsigned int flags, - const char *reason); +void fail_user_pass(const char *prefix, + const unsigned int flags, + const char *reason); -void purge_user_pass (struct user_pass *up, const bool force); +void purge_user_pass(struct user_pass *up, const bool force); -void set_auth_token (struct user_pass *up, const char *token); +void set_auth_token(struct user_pass *up, const char *token); /* * Process string received by untrusted peer before * printing to console or log file. * Assumes that string has been null terminated. */ -const char *safe_print (const char *str, struct gc_arena *gc); +const char *safe_print(const char *str, struct gc_arena *gc); /* returns true if environmental variable safe to print to log */ -bool env_safe_to_print (const char *str); +bool env_safe_to_print(const char *str); /* returns true if environmental variable may be passed to an external program */ -bool env_allowed (const char *str); +bool env_allowed(const char *str); /* * A sleep function that services the management layer for n * seconds rather than doing nothing. */ -void openvpn_sleep (const int n); +void openvpn_sleep(const int n); -void configure_path (void); +void configure_path(void); const char *sanitize_control_message(const char *str, struct gc_arena *gc); #if AUTO_USERID -void get_user_pass_auto_userid (struct user_pass *up, const char *tag); +void get_user_pass_auto_userid(struct user_pass *up, const char *tag); + #endif /* @@ -313,19 +331,21 @@ extern const char *iproute_path; extern int script_security; /* GLOBAL */ /* return the next largest power of 2 */ -size_t adjust_power_of_2 (size_t u); +size_t adjust_power_of_2(size_t u); #define COMPAT_FLAG_QUERY 0 /** compat_flags operator: Query for a flag */ #define COMPAT_FLAG_SET (1<<0) /** compat_flags operator: Set a compat flag */ #define COMPAT_NAMES (1<<1) /** compat flag: --compat-names set */ #define COMPAT_NO_NAME_REMAPPING (1<<2) /** compat flag: --compat-names without char remapping */ -bool compat_flag (unsigned int flag); +bool compat_flag(unsigned int flag); #if P2MP_SERVER /* helper to parse peer_info received from multi client, validate * (this is untrusted data) and put into environment */ bool validate_peer_info_line(char *line); -void output_peer_info_env (struct env_set *es, const char * peer_info); + +void output_peer_info_env(struct env_set *es, const char *peer_info); + #endif /* P2MP_SERVER */ -#endif +#endif /* ifndef MISC_H */ diff --git a/src/openvpn/mroute.c b/src/openvpn/mroute.c index c905af78626..cdcd061fa82 100644 --- a/src/openvpn/mroute.c +++ b/src/openvpn/mroute.c @@ -40,9 +40,9 @@ #include "memdbg.h" void -mroute_addr_init (struct mroute_addr *addr) +mroute_addr_init(struct mroute_addr *addr) { - CLEAR (*addr); + CLEAR(*addr); } /* @@ -50,269 +50,288 @@ mroute_addr_init (struct mroute_addr *addr) */ static inline bool -is_mac_mcast_addr (const uint8_t *mac) +is_mac_mcast_addr(const uint8_t *mac) { - return (bool) (mac[0] & 1); + return (bool) (mac[0] & 1); } static inline bool -is_mac_mcast_maddr (const struct mroute_addr *addr) +is_mac_mcast_maddr(const struct mroute_addr *addr) { - return (addr->type & MR_ADDR_MASK) == MR_ADDR_ETHER && - is_mac_mcast_addr (addr->eth_addr); + return (addr->type & MR_ADDR_MASK) == MR_ADDR_ETHER + && is_mac_mcast_addr(addr->eth_addr); } /* * Don't learn certain addresses. */ bool -mroute_learnable_address (const struct mroute_addr *addr) +mroute_learnable_address(const struct mroute_addr *addr) { - int i; - bool not_all_zeros = false; - bool not_all_ones = false; + int i; + bool not_all_zeros = false; + bool not_all_ones = false; - for (i = 0; i < addr->len; ++i) + for (i = 0; i < addr->len; ++i) { - int b = addr->raw_addr[i]; - if (b != 0x00) - not_all_zeros = true; - if (b != 0xFF) - not_all_ones = true; + int b = addr->raw_addr[i]; + if (b != 0x00) + { + not_all_zeros = true; + } + if (b != 0xFF) + { + not_all_ones = true; + } } - return not_all_zeros && not_all_ones && !is_mac_mcast_maddr (addr); + return not_all_zeros && not_all_ones && !is_mac_mcast_maddr(addr); } static inline void -mroute_get_in_addr_t (struct mroute_addr *ma, const in_addr_t src, unsigned int mask) +mroute_get_in_addr_t(struct mroute_addr *ma, const in_addr_t src, unsigned int mask) { - if (ma) + if (ma) { - ma->type = MR_ADDR_IPV4 | mask; - ma->netbits = 0; - ma->len = 4; - ma->v4.addr = src; + ma->type = MR_ADDR_IPV4 | mask; + ma->netbits = 0; + ma->len = 4; + ma->v4.addr = src; } } static inline void -mroute_get_in6_addr (struct mroute_addr *ma, const struct in6_addr src, unsigned int mask) +mroute_get_in6_addr(struct mroute_addr *ma, const struct in6_addr src, unsigned int mask) { - if (ma) + if (ma) { - ma->type = MR_ADDR_IPV6 | mask; - ma->netbits = 0; - ma->len = 16; - ma->v6.addr = src; + ma->type = MR_ADDR_IPV6 | mask; + ma->netbits = 0; + ma->len = 16; + ma->v6.addr = src; } } static inline bool -mroute_is_mcast (const in_addr_t addr) +mroute_is_mcast(const in_addr_t addr) { - return ((addr & htonl(IP_MCAST_SUBNET_MASK)) == htonl(IP_MCAST_NETWORK)); + return ((addr & htonl(IP_MCAST_SUBNET_MASK)) == htonl(IP_MCAST_NETWORK)); } -/* RFC 4291, 2.7, "binary 11111111 at the start of an address identifies +/* RFC 4291, 2.7, "binary 11111111 at the start of an address identifies * the address as being a multicast address" */ static inline bool -mroute_is_mcast_ipv6 (const struct in6_addr addr) +mroute_is_mcast_ipv6(const struct in6_addr addr) { - return (addr.s6_addr[0] == 0xff); + return (addr.s6_addr[0] == 0xff); } #ifdef ENABLE_PF static unsigned int -mroute_extract_addr_arp (struct mroute_addr *src, - struct mroute_addr *dest, - const struct buffer *buf) +mroute_extract_addr_arp(struct mroute_addr *src, + struct mroute_addr *dest, + const struct buffer *buf) { - unsigned int ret = 0; - if (BLEN (buf) >= (int) sizeof (struct openvpn_arp)) + unsigned int ret = 0; + if (BLEN(buf) >= (int) sizeof(struct openvpn_arp)) { - const struct openvpn_arp *arp = (const struct openvpn_arp *) BPTR (buf); - if (arp->mac_addr_type == htons(0x0001) - && arp->proto_addr_type == htons(0x0800) - && arp->mac_addr_size == 0x06 - && arp->proto_addr_size == 0x04) - { - mroute_get_in_addr_t (src, arp->ip_src, MR_ARP); - mroute_get_in_addr_t (dest, arp->ip_dest, MR_ARP); - - /* multicast packet? */ - if (mroute_is_mcast (arp->ip_dest)) - ret |= MROUTE_EXTRACT_MCAST; - - ret |= MROUTE_EXTRACT_SUCCEEDED; - } + const struct openvpn_arp *arp = (const struct openvpn_arp *) BPTR(buf); + if (arp->mac_addr_type == htons(0x0001) + && arp->proto_addr_type == htons(0x0800) + && arp->mac_addr_size == 0x06 + && arp->proto_addr_size == 0x04) + { + mroute_get_in_addr_t(src, arp->ip_src, MR_ARP); + mroute_get_in_addr_t(dest, arp->ip_dest, MR_ARP); + + /* multicast packet? */ + if (mroute_is_mcast(arp->ip_dest)) + { + ret |= MROUTE_EXTRACT_MCAST; + } + + ret |= MROUTE_EXTRACT_SUCCEEDED; + } } - return ret; + return ret; } -#endif +#endif /* ifdef ENABLE_PF */ unsigned int -mroute_extract_addr_ipv4 (struct mroute_addr *src, - struct mroute_addr *dest, - const struct buffer *buf) +mroute_extract_addr_ipv4(struct mroute_addr *src, + struct mroute_addr *dest, + const struct buffer *buf) { - unsigned int ret = 0; - if (BLEN (buf) >= 1) + unsigned int ret = 0; + if (BLEN(buf) >= 1) { - switch (OPENVPN_IPH_GET_VER (*BPTR(buf))) - { - case 4: - if (BLEN (buf) >= (int) sizeof (struct openvpn_iphdr)) - { - const struct openvpn_iphdr *ip = (const struct openvpn_iphdr *) BPTR (buf); - - mroute_get_in_addr_t (src, ip->saddr, 0); - mroute_get_in_addr_t (dest, ip->daddr, 0); - - /* multicast packet? */ - if (mroute_is_mcast (ip->daddr)) - ret |= MROUTE_EXTRACT_MCAST; - - /* IGMP message? */ - if (ip->protocol == OPENVPN_IPPROTO_IGMP) - ret |= MROUTE_EXTRACT_IGMP; - - ret |= MROUTE_EXTRACT_SUCCEEDED; - } - break; - case 6: - if (BLEN (buf) >= (int) sizeof (struct openvpn_ipv6hdr)) - { - const struct openvpn_ipv6hdr *ipv6 = (const struct openvpn_ipv6hdr *) BPTR (buf); -#if 0 /* very basic debug */ - struct gc_arena gc = gc_new (); - msg( M_INFO, "IPv6 packet! src=%s, dst=%s", - print_in6_addr( ipv6->saddr, 0, &gc ), - print_in6_addr( ipv6->daddr, 0, &gc )); - gc_free (&gc); + switch (OPENVPN_IPH_GET_VER(*BPTR(buf))) + { + case 4: + if (BLEN(buf) >= (int) sizeof(struct openvpn_iphdr)) + { + const struct openvpn_iphdr *ip = (const struct openvpn_iphdr *) BPTR(buf); + + mroute_get_in_addr_t(src, ip->saddr, 0); + mroute_get_in_addr_t(dest, ip->daddr, 0); + + /* multicast packet? */ + if (mroute_is_mcast(ip->daddr)) + { + ret |= MROUTE_EXTRACT_MCAST; + } + + /* IGMP message? */ + if (ip->protocol == OPENVPN_IPPROTO_IGMP) + { + ret |= MROUTE_EXTRACT_IGMP; + } + + ret |= MROUTE_EXTRACT_SUCCEEDED; + } + break; + + case 6: + if (BLEN(buf) >= (int) sizeof(struct openvpn_ipv6hdr)) + { + const struct openvpn_ipv6hdr *ipv6 = (const struct openvpn_ipv6hdr *) BPTR(buf); +#if 0 /* very basic debug */ + struct gc_arena gc = gc_new(); + msg( M_INFO, "IPv6 packet! src=%s, dst=%s", + print_in6_addr( ipv6->saddr, 0, &gc ), + print_in6_addr( ipv6->daddr, 0, &gc )); + gc_free(&gc); #endif - mroute_get_in6_addr (src, ipv6->saddr, 0); - mroute_get_in6_addr (dest, ipv6->daddr, 0); + mroute_get_in6_addr(src, ipv6->saddr, 0); + mroute_get_in6_addr(dest, ipv6->daddr, 0); + + if (mroute_is_mcast_ipv6(ipv6->daddr)) + { + ret |= MROUTE_EXTRACT_MCAST; + } - if (mroute_is_mcast_ipv6 (ipv6->daddr)) - ret |= MROUTE_EXTRACT_MCAST; + ret |= MROUTE_EXTRACT_SUCCEEDED; + } + break; - ret |= MROUTE_EXTRACT_SUCCEEDED; - } - break; - default: - msg (M_WARN, "IP packet with unknown IP version=%d seen", - OPENVPN_IPH_GET_VER (*BPTR(buf))); - } + default: + msg(M_WARN, "IP packet with unknown IP version=%d seen", + OPENVPN_IPH_GET_VER(*BPTR(buf))); + } } - return ret; + return ret; } unsigned int -mroute_extract_addr_ether (struct mroute_addr *src, - struct mroute_addr *dest, - struct mroute_addr *esrc, - struct mroute_addr *edest, - const struct buffer *buf) +mroute_extract_addr_ether(struct mroute_addr *src, + struct mroute_addr *dest, + struct mroute_addr *esrc, + struct mroute_addr *edest, + const struct buffer *buf) { - unsigned int ret = 0; - if (BLEN (buf) >= (int) sizeof (struct openvpn_ethhdr)) + unsigned int ret = 0; + if (BLEN(buf) >= (int) sizeof(struct openvpn_ethhdr)) { - const struct openvpn_ethhdr *eth = (const struct openvpn_ethhdr *) BPTR (buf); - if (src) - { - src->type = MR_ADDR_ETHER; - src->netbits = 0; - src->len = 6; - memcpy (src->eth_addr, eth->source, sizeof(dest->eth_addr)); - } - if (dest) - { - dest->type = MR_ADDR_ETHER; - dest->netbits = 0; - dest->len = 6; - memcpy (dest->eth_addr, eth->dest, sizeof(dest->eth_addr)); - - /* ethernet broadcast/multicast packet? */ - if (is_mac_mcast_addr (eth->dest)) - ret |= MROUTE_EXTRACT_BCAST; - } - - ret |= MROUTE_EXTRACT_SUCCEEDED; + const struct openvpn_ethhdr *eth = (const struct openvpn_ethhdr *) BPTR(buf); + if (src) + { + src->type = MR_ADDR_ETHER; + src->netbits = 0; + src->len = 6; + memcpy(src->eth_addr, eth->source, sizeof(dest->eth_addr)); + } + if (dest) + { + dest->type = MR_ADDR_ETHER; + dest->netbits = 0; + dest->len = 6; + memcpy(dest->eth_addr, eth->dest, sizeof(dest->eth_addr)); + + /* ethernet broadcast/multicast packet? */ + if (is_mac_mcast_addr(eth->dest)) + { + ret |= MROUTE_EXTRACT_BCAST; + } + } + + ret |= MROUTE_EXTRACT_SUCCEEDED; #ifdef ENABLE_PF - if (esrc || edest) - { - struct buffer b = *buf; - if (buf_advance (&b, sizeof (struct openvpn_ethhdr))) - { - switch (ntohs (eth->proto)) - { - case OPENVPN_ETH_P_IPV4: - ret |= (mroute_extract_addr_ipv4 (esrc, edest, &b) << MROUTE_SEC_SHIFT); - break; - case OPENVPN_ETH_P_ARP: - ret |= (mroute_extract_addr_arp (esrc, edest, &b) << MROUTE_SEC_SHIFT); - break; - } - } - } + if (esrc || edest) + { + struct buffer b = *buf; + if (buf_advance(&b, sizeof(struct openvpn_ethhdr))) + { + switch (ntohs(eth->proto)) + { + case OPENVPN_ETH_P_IPV4: + ret |= (mroute_extract_addr_ipv4(esrc, edest, &b) << MROUTE_SEC_SHIFT); + break; + + case OPENVPN_ETH_P_ARP: + ret |= (mroute_extract_addr_arp(esrc, edest, &b) << MROUTE_SEC_SHIFT); + break; + } + } + } #endif } - return ret; + return ret; } /* * Translate a struct openvpn_sockaddr (osaddr) * to a struct mroute_addr (addr). */ -bool mroute_extract_openvpn_sockaddr (struct mroute_addr *addr, - const struct openvpn_sockaddr *osaddr, - bool use_port) +bool +mroute_extract_openvpn_sockaddr(struct mroute_addr *addr, + const struct openvpn_sockaddr *osaddr, + bool use_port) { - switch (osaddr->addr.sa.sa_family) - { - case AF_INET: + switch (osaddr->addr.sa.sa_family) { - if (use_port) - { - addr->type = MR_ADDR_IPV4 | MR_WITH_PORT; - addr->netbits = 0; - addr->len = 6; - addr->v4.addr = osaddr->addr.in4.sin_addr.s_addr; - addr->v4.port = osaddr->addr.in4.sin_port; - } - else - { - addr->type = MR_ADDR_IPV4; - addr->netbits = 0; - addr->len = 4; - addr->v4.addr = osaddr->addr.in4.sin_addr.s_addr; - } - return true; + case AF_INET: + { + if (use_port) + { + addr->type = MR_ADDR_IPV4 | MR_WITH_PORT; + addr->netbits = 0; + addr->len = 6; + addr->v4.addr = osaddr->addr.in4.sin_addr.s_addr; + addr->v4.port = osaddr->addr.in4.sin_port; + } + else + { + addr->type = MR_ADDR_IPV4; + addr->netbits = 0; + addr->len = 4; + addr->v4.addr = osaddr->addr.in4.sin_addr.s_addr; + } + return true; + } + + case AF_INET6: + if (use_port) + { + addr->type = MR_ADDR_IPV6 | MR_WITH_PORT; + addr->netbits = 0; + addr->len = 18; + addr->v6.addr = osaddr->addr.in6.sin6_addr; + addr->v6.port = osaddr->addr.in6.sin6_port; + } + else + { + addr->type = MR_ADDR_IPV6; + addr->netbits = 0; + addr->len = 16; + addr->v6.addr = osaddr->addr.in6.sin6_addr; + } + return true; } - case AF_INET6: - if (use_port) - { - addr->type = MR_ADDR_IPV6 | MR_WITH_PORT; - addr->netbits = 0; - addr->len = 18; - addr->v6.addr = osaddr->addr.in6.sin6_addr; - addr->v6.port = osaddr->addr.in6.sin6_port; - } - else - { - addr->type = MR_ADDR_IPV6; - addr->netbits = 0; - addr->len = 16; - addr->v6.addr = osaddr->addr.in6.sin6_addr; - } - return true; - } - return false; + return false; } /* @@ -325,36 +344,38 @@ bool mroute_extract_openvpn_sockaddr (struct mroute_addr *addr, * might benefit from some "zeroize 32 bit at a time" improvements */ void -mroute_addr_mask_host_bits (struct mroute_addr *ma) +mroute_addr_mask_host_bits(struct mroute_addr *ma) { - if ((ma->type & MR_ADDR_MASK) == MR_ADDR_IPV4) + if ((ma->type & MR_ADDR_MASK) == MR_ADDR_IPV4) { - in_addr_t addr = ntohl (ma->v4.addr); - addr &= netbits_to_netmask (ma->netbits); - ma->v4.addr = htonl (addr); + in_addr_t addr = ntohl(ma->v4.addr); + addr &= netbits_to_netmask(ma->netbits); + ma->v4.addr = htonl(addr); } - else if ((ma->type & MR_ADDR_MASK) == MR_ADDR_IPV6) + else if ((ma->type & MR_ADDR_MASK) == MR_ADDR_IPV6) { - int byte = sizeof (ma->v6.addr) - 1; /* rightmost byte in address */ - int bits_to_clear = 128 - ma->netbits; + int byte = sizeof(ma->v6.addr) - 1; /* rightmost byte in address */ + int bits_to_clear = 128 - ma->netbits; - while( byte >= 0 && bits_to_clear > 0 ) + while (byte >= 0 && bits_to_clear > 0) { - if ( bits_to_clear >= 8 ) - { - ma->v6.addr.s6_addr[byte--] = 0; - bits_to_clear -= 8; - } - else - { - ma->v6.addr.s6_addr[byte--] &= (IPV4_NETMASK_HOST << bits_to_clear); - bits_to_clear = 0; - } + if (bits_to_clear >= 8) + { + ma->v6.addr.s6_addr[byte--] = 0; + bits_to_clear -= 8; + } + else + { + ma->v6.addr.s6_addr[byte--] &= (IPV4_NETMASK_HOST << bits_to_clear); + bits_to_clear = 0; + } } - ASSERT( bits_to_clear == 0 ); + ASSERT( bits_to_clear == 0 ); + } + else + { + ASSERT(0); } - else - ASSERT(0); } /* @@ -363,91 +384,100 @@ mroute_addr_mask_host_bits (struct mroute_addr *ma) * and the actual address. */ uint32_t -mroute_addr_hash_function (const void *key, uint32_t iv) +mroute_addr_hash_function(const void *key, uint32_t iv) { - return hash_func (mroute_addr_hash_ptr ((const struct mroute_addr *) key), - mroute_addr_hash_len ((const struct mroute_addr *) key), - iv); + return hash_func(mroute_addr_hash_ptr((const struct mroute_addr *) key), + mroute_addr_hash_len((const struct mroute_addr *) key), + iv); } bool -mroute_addr_compare_function (const void *key1, const void *key2) +mroute_addr_compare_function(const void *key1, const void *key2) { - return mroute_addr_equal ((const struct mroute_addr *) key1, - (const struct mroute_addr *) key2); + return mroute_addr_equal((const struct mroute_addr *) key1, + (const struct mroute_addr *) key2); } const char * -mroute_addr_print (const struct mroute_addr *ma, - struct gc_arena *gc) +mroute_addr_print(const struct mroute_addr *ma, + struct gc_arena *gc) { - return mroute_addr_print_ex (ma, MAPF_IA_EMPTY_IF_UNDEF, gc); + return mroute_addr_print_ex(ma, MAPF_IA_EMPTY_IF_UNDEF, gc); } const char * -mroute_addr_print_ex (const struct mroute_addr *ma, - const unsigned int flags, - struct gc_arena *gc) +mroute_addr_print_ex(const struct mroute_addr *ma, + const unsigned int flags, + struct gc_arena *gc) { - struct buffer out = alloc_buf_gc (64, gc); - if (ma) + struct buffer out = alloc_buf_gc(64, gc); + if (ma) { - struct mroute_addr maddr = *ma; - - switch (maddr.type & MR_ADDR_MASK) - { - case MR_ADDR_ETHER: - buf_printf (&out, "%s", format_hex_ex (ma->eth_addr, - sizeof(ma->eth_addr), 0, 1, ":", gc)); - break; - case MR_ADDR_IPV4: - { - if ((flags & MAPF_SHOW_ARP) && (maddr.type & MR_ARP)) - buf_printf (&out, "ARP/"); - buf_printf (&out, "%s", print_in_addr_t (ntohl (maddr.v4.addr), - (flags & MAPF_IA_EMPTY_IF_UNDEF) ? IA_EMPTY_IF_UNDEF : 0, gc)); - if (maddr.type & MR_WITH_NETBITS) - { - if (flags & MAPF_SUBNET) - { - const in_addr_t netmask = netbits_to_netmask (maddr.netbits); - buf_printf (&out, "/%s", print_in_addr_t (netmask, 0, gc)); - } - else - buf_printf (&out, "/%d", maddr.netbits); - } - if (maddr.type & MR_WITH_PORT) - { - buf_printf (&out, ":%d", ntohs (maddr.v4.port)); - } - } - break; - case MR_ADDR_IPV6: - { - if ( IN6_IS_ADDR_V4MAPPED( &maddr.v6.addr ) ) - { - buf_printf (&out, "%s", print_in_addr_t (maddr.v4mappedv6.addr, - IA_NET_ORDER, gc)); - } - else - { - buf_printf (&out, "%s", print_in6_addr (maddr.v6.addr, 0, gc)); - } - if (maddr.type & MR_WITH_NETBITS) - { - buf_printf (&out, "/%d", maddr.netbits); - } - } - break; - default: - buf_printf (&out, "UNKNOWN"); - break; - } - return BSTR (&out); - } + struct mroute_addr maddr = *ma; + + switch (maddr.type & MR_ADDR_MASK) + { + case MR_ADDR_ETHER: + buf_printf(&out, "%s", format_hex_ex(ma->eth_addr, + sizeof(ma->eth_addr), 0, 1, ":", gc)); + break; + + case MR_ADDR_IPV4: + { + if ((flags & MAPF_SHOW_ARP) && (maddr.type & MR_ARP)) + { + buf_printf(&out, "ARP/"); + } + buf_printf(&out, "%s", print_in_addr_t(ntohl(maddr.v4.addr), + (flags & MAPF_IA_EMPTY_IF_UNDEF) ? IA_EMPTY_IF_UNDEF : 0, gc)); + if (maddr.type & MR_WITH_NETBITS) + { + if (flags & MAPF_SUBNET) + { + const in_addr_t netmask = netbits_to_netmask(maddr.netbits); + buf_printf(&out, "/%s", print_in_addr_t(netmask, 0, gc)); + } + else + { + buf_printf(&out, "/%d", maddr.netbits); + } + } + if (maddr.type & MR_WITH_PORT) + { + buf_printf(&out, ":%d", ntohs(maddr.v4.port)); + } + } + break; + + case MR_ADDR_IPV6: + { + if (IN6_IS_ADDR_V4MAPPED( &maddr.v6.addr ) ) + { + buf_printf(&out, "%s", print_in_addr_t(maddr.v4mappedv6.addr, + IA_NET_ORDER, gc)); + } + else + { + buf_printf(&out, "%s", print_in6_addr(maddr.v6.addr, 0, gc)); + } + if (maddr.type & MR_WITH_NETBITS) + { + buf_printf(&out, "/%d", maddr.netbits); + } + } + break; + + default: + buf_printf(&out, "UNKNOWN"); + break; + } + return BSTR(&out); + } else - return "[NULL]"; - } + { + return "[NULL]"; + } +} /* * mroute_helper's main job is keeping track of @@ -456,74 +486,82 @@ mroute_addr_print_ex (const struct mroute_addr *ma, */ struct mroute_helper * -mroute_helper_init (int ageable_ttl_secs) +mroute_helper_init(int ageable_ttl_secs) { - struct mroute_helper *mh; - ALLOC_OBJ_CLEAR (mh, struct mroute_helper); - mh->ageable_ttl_secs = ageable_ttl_secs; - return mh; + struct mroute_helper *mh; + ALLOC_OBJ_CLEAR(mh, struct mroute_helper); + mh->ageable_ttl_secs = ageable_ttl_secs; + return mh; } static void -mroute_helper_regenerate (struct mroute_helper *mh) +mroute_helper_regenerate(struct mroute_helper *mh) { - int i, j = 0; - for (i = MR_HELPER_NET_LEN - 1; i >= 0; --i) + int i, j = 0; + for (i = MR_HELPER_NET_LEN - 1; i >= 0; --i) { - if (mh->net_len_refcount[i] > 0) - mh->net_len[j++] = (uint8_t) i; + if (mh->net_len_refcount[i] > 0) + { + mh->net_len[j++] = (uint8_t) i; + } } - mh->n_net_len = j; + mh->n_net_len = j; #ifdef ENABLE_DEBUG - if (check_debug_level (D_MULTI_DEBUG)) + if (check_debug_level(D_MULTI_DEBUG)) { - struct gc_arena gc = gc_new (); - struct buffer out = alloc_buf_gc (256, &gc); - buf_printf (&out, "MROUTE CIDR netlen:"); - for (i = 0; i < mh->n_net_len; ++i) - { - buf_printf (&out, " /%d", mh->net_len[i]); - } - dmsg (D_MULTI_DEBUG, "%s", BSTR (&out)); - gc_free (&gc); + struct gc_arena gc = gc_new(); + struct buffer out = alloc_buf_gc(256, &gc); + buf_printf(&out, "MROUTE CIDR netlen:"); + for (i = 0; i < mh->n_net_len; ++i) + { + buf_printf(&out, " /%d", mh->net_len[i]); + } + dmsg(D_MULTI_DEBUG, "%s", BSTR(&out)); + gc_free(&gc); } #endif } void -mroute_helper_add_iroute46 (struct mroute_helper *mh, int netbits) +mroute_helper_add_iroute46(struct mroute_helper *mh, int netbits) { - if (netbits >= 0) + if (netbits >= 0) { - ASSERT (netbits < MR_HELPER_NET_LEN); - ++mh->cache_generation; - ++mh->net_len_refcount[netbits]; - if (mh->net_len_refcount[netbits] == 1) - mroute_helper_regenerate (mh); + ASSERT(netbits < MR_HELPER_NET_LEN); + ++mh->cache_generation; + ++mh->net_len_refcount[netbits]; + if (mh->net_len_refcount[netbits] == 1) + { + mroute_helper_regenerate(mh); + } } } void -mroute_helper_del_iroute46 (struct mroute_helper *mh, int netbits) +mroute_helper_del_iroute46(struct mroute_helper *mh, int netbits) { - if (netbits >= 0) + if (netbits >= 0) { - ASSERT (netbits < MR_HELPER_NET_LEN); - ++mh->cache_generation; - --mh->net_len_refcount[netbits]; - ASSERT (mh->net_len_refcount[netbits] >= 0); - if (!mh->net_len_refcount[netbits]) - mroute_helper_regenerate (mh); + ASSERT(netbits < MR_HELPER_NET_LEN); + ++mh->cache_generation; + --mh->net_len_refcount[netbits]; + ASSERT(mh->net_len_refcount[netbits] >= 0); + if (!mh->net_len_refcount[netbits]) + { + mroute_helper_regenerate(mh); + } } } void -mroute_helper_free (struct mroute_helper *mh) +mroute_helper_free(struct mroute_helper *mh) { - free (mh); + free(mh); } -#else -static void dummy(void) {} +#else /* if P2MP_SERVER */ +static void +dummy(void) { +} #endif /* P2MP_SERVER */ diff --git a/src/openvpn/mroute.h b/src/openvpn/mroute.h index 8f7a064231f..9da41ee1ed5 100644 --- a/src/openvpn/mroute.h +++ b/src/openvpn/mroute.h @@ -76,49 +76,49 @@ #define MR_ARP 16 struct mroute_addr { - uint8_t len; /* length of address */ - uint8_t unused; - uint8_t type; /* MR_ADDR/MR_WITH flags */ - uint8_t netbits; /* number of bits in network part of address, - valid if MR_WITH_NETBITS is set */ - union { - uint8_t raw_addr[MR_MAX_ADDR_LEN]; /* actual address */ - uint8_t eth_addr[OPENVPN_ETH_ALEN]; - struct { - in_addr_t addr; /* _network order_ IPv4 address */ - in_port_t port; /* _network order_ TCP/UDP port */ - } v4; - struct { - struct in6_addr addr; - in_port_t port; /* _network order_ TCP/UDP port */ - } v6; - struct { - uint8_t prefix[12]; - in_addr_t addr; /* _network order_ IPv4 address */ - } v4mappedv6; - } + uint8_t len; /* length of address */ + uint8_t unused; + uint8_t type; /* MR_ADDR/MR_WITH flags */ + uint8_t netbits; /* number of bits in network part of address, + * valid if MR_WITH_NETBITS is set */ + union { + uint8_t raw_addr[MR_MAX_ADDR_LEN]; /* actual address */ + uint8_t eth_addr[OPENVPN_ETH_ALEN]; + struct { + in_addr_t addr; /* _network order_ IPv4 address */ + in_port_t port; /* _network order_ TCP/UDP port */ + } v4; + struct { + struct in6_addr addr; + in_port_t port; /* _network order_ TCP/UDP port */ + } v6; + struct { + uint8_t prefix[12]; + in_addr_t addr; /* _network order_ IPv4 address */ + } v4mappedv6; + } #ifndef HAVE_ANONYMOUS_UNION_SUPPORT /* Wrappers to support compilers that do not grok anonymous unions */ - mroute_union + mroute_union #define raw_addr mroute_union.raw_addr #define eth_addr mroute_union.eth_addr #define v4 mroute_union.v4 #define v6 mroute_union.v6 #define v4mappedv6 mroute_union.v4mappedv6 #endif - ; + ; }; /* Double-check that struct packing works as expected */ -static_assert (offsetof(struct mroute_addr, v4.port) == - offsetof(struct mroute_addr, v4) + 4, - "Unexpected struct packing of v4"); -static_assert (offsetof(struct mroute_addr, v6.port) == - offsetof(struct mroute_addr, v6) + 16, - "Unexpected struct packing of v6"); -static_assert (offsetof(struct mroute_addr, v4mappedv6.addr) == - offsetof(struct mroute_addr, v4mappedv6) + 12, - "Unexpected struct packing of v4mappedv6"); +static_assert(offsetof(struct mroute_addr, v4.port) == + offsetof(struct mroute_addr, v4) + 4, + "Unexpected struct packing of v4"); +static_assert(offsetof(struct mroute_addr, v6.port) == + offsetof(struct mroute_addr, v6) + 16, + "Unexpected struct packing of v6"); +static_assert(offsetof(struct mroute_addr, v4mappedv6.addr) == + offsetof(struct mroute_addr, v4mappedv6) + 12, + "Unexpected struct packing of v4mappedv6"); /* * Number of bits in an address. Should be raised for IPv6. @@ -129,122 +129,140 @@ static_assert (offsetof(struct mroute_addr, v4mappedv6.addr) == * Used to help maintain CIDR routing table. */ struct mroute_helper { - unsigned int cache_generation; /* incremented when route added */ - int ageable_ttl_secs; /* host route cache entry time-to-live*/ - int n_net_len; /* length of net_len array */ - uint8_t net_len[MR_HELPER_NET_LEN]; /* CIDR netlengths in descending order */ - int net_len_refcount[MR_HELPER_NET_LEN]; /* refcount of each netlength */ + unsigned int cache_generation; /* incremented when route added */ + int ageable_ttl_secs; /* host route cache entry time-to-live*/ + int n_net_len; /* length of net_len array */ + uint8_t net_len[MR_HELPER_NET_LEN]; /* CIDR netlengths in descending order */ + int net_len_refcount[MR_HELPER_NET_LEN]; /* refcount of each netlength */ }; struct openvpn_sockaddr; -bool mroute_extract_openvpn_sockaddr (struct mroute_addr *addr, - const struct openvpn_sockaddr *osaddr, - bool use_port); +bool mroute_extract_openvpn_sockaddr(struct mroute_addr *addr, + const struct openvpn_sockaddr *osaddr, + bool use_port); -bool mroute_learnable_address (const struct mroute_addr *addr); +bool mroute_learnable_address(const struct mroute_addr *addr); -uint32_t mroute_addr_hash_function (const void *key, uint32_t iv); -bool mroute_addr_compare_function (const void *key1, const void *key2); +uint32_t mroute_addr_hash_function(const void *key, uint32_t iv); -void mroute_addr_init (struct mroute_addr *addr); +bool mroute_addr_compare_function(const void *key1, const void *key2); -const char *mroute_addr_print (const struct mroute_addr *ma, - struct gc_arena *gc); +void mroute_addr_init(struct mroute_addr *addr); + +const char *mroute_addr_print(const struct mroute_addr *ma, + struct gc_arena *gc); #define MAPF_SUBNET (1<<0) #define MAPF_IA_EMPTY_IF_UNDEF (1<<1) #define MAPF_SHOW_ARP (1<<2) -const char *mroute_addr_print_ex (const struct mroute_addr *ma, - const unsigned int flags, - struct gc_arena *gc); +const char *mroute_addr_print_ex(const struct mroute_addr *ma, + const unsigned int flags, + struct gc_arena *gc); + +void mroute_addr_mask_host_bits(struct mroute_addr *ma); + +struct mroute_helper *mroute_helper_init(int ageable_ttl_secs); + +void mroute_helper_free(struct mroute_helper *mh); -void mroute_addr_mask_host_bits (struct mroute_addr *ma); +void mroute_helper_add_iroute46(struct mroute_helper *mh, int netbits); -struct mroute_helper *mroute_helper_init (int ageable_ttl_secs); -void mroute_helper_free (struct mroute_helper *mh); -void mroute_helper_add_iroute46 (struct mroute_helper *mh, int netbits); -void mroute_helper_del_iroute46 (struct mroute_helper *mh, int netbits); +void mroute_helper_del_iroute46(struct mroute_helper *mh, int netbits); /* * Given a raw packet in buf, return the src and dest * addresses of the packet. */ static inline unsigned int -mroute_extract_addr_from_packet (struct mroute_addr *src, - struct mroute_addr *dest, - struct mroute_addr *esrc, - struct mroute_addr *edest, - const struct buffer *buf, - int tunnel_type) +mroute_extract_addr_from_packet(struct mroute_addr *src, + struct mroute_addr *dest, + struct mroute_addr *esrc, + struct mroute_addr *edest, + const struct buffer *buf, + int tunnel_type) { - unsigned int mroute_extract_addr_ipv4 (struct mroute_addr *src, - struct mroute_addr *dest, - const struct buffer *buf); - - unsigned int mroute_extract_addr_ether (struct mroute_addr *src, - struct mroute_addr *dest, - struct mroute_addr *esrc, - struct mroute_addr *edest, - const struct buffer *buf); - unsigned int ret = 0; - verify_align_4 (buf); - if (tunnel_type == DEV_TYPE_TUN) - ret = mroute_extract_addr_ipv4 (src, dest, buf); - else if (tunnel_type == DEV_TYPE_TAP) - ret = mroute_extract_addr_ether (src, dest, esrc, edest, buf); - return ret; + unsigned int mroute_extract_addr_ipv4(struct mroute_addr *src, + struct mroute_addr *dest, + const struct buffer *buf); + + unsigned int mroute_extract_addr_ether(struct mroute_addr *src, + struct mroute_addr *dest, + struct mroute_addr *esrc, + struct mroute_addr *edest, + const struct buffer *buf); + + unsigned int ret = 0; + verify_align_4(buf); + if (tunnel_type == DEV_TYPE_TUN) + { + ret = mroute_extract_addr_ipv4(src, dest, buf); + } + else if (tunnel_type == DEV_TYPE_TAP) + { + ret = mroute_extract_addr_ether(src, dest, esrc, edest, buf); + } + return ret; } static inline bool -mroute_addr_equal (const struct mroute_addr *a1, const struct mroute_addr *a2) +mroute_addr_equal(const struct mroute_addr *a1, const struct mroute_addr *a2) { - if (a1->type != a2->type) - return false; - if (a1->netbits != a2->netbits) - return false; - if (a1->len != a2->len) - return false; - return memcmp (a1->raw_addr, a2->raw_addr, a1->len) == 0; + if (a1->type != a2->type) + { + return false; + } + if (a1->netbits != a2->netbits) + { + return false; + } + if (a1->len != a2->len) + { + return false; + } + return memcmp(a1->raw_addr, a2->raw_addr, a1->len) == 0; } static inline const uint8_t * -mroute_addr_hash_ptr (const struct mroute_addr *a) +mroute_addr_hash_ptr(const struct mroute_addr *a) { - /* NOTE: depends on ordering of struct mroute_addr */ - return (uint8_t *) &a->type; + /* NOTE: depends on ordering of struct mroute_addr */ + return (uint8_t *) &a->type; } static inline uint32_t -mroute_addr_hash_len (const struct mroute_addr *a) +mroute_addr_hash_len(const struct mroute_addr *a) { - return (uint32_t) a->len + 2; + return (uint32_t) a->len + 2; } static inline void -mroute_extract_in_addr_t (struct mroute_addr *dest, const in_addr_t src) +mroute_extract_in_addr_t(struct mroute_addr *dest, const in_addr_t src) { - dest->type = MR_ADDR_IPV4; - dest->netbits = 0; - dest->len = 4; - dest->v4.addr = htonl (src); + dest->type = MR_ADDR_IPV4; + dest->netbits = 0; + dest->len = 4; + dest->v4.addr = htonl(src); } static inline in_addr_t -in_addr_t_from_mroute_addr (const struct mroute_addr *addr) +in_addr_t_from_mroute_addr(const struct mroute_addr *addr) { - if ((addr->type & MR_ADDR_MASK) == MR_ADDR_IPV4 && addr->netbits == 0 && addr->len == 4) { - return ntohl(addr->v4.addr); - } else { - return 0; - } + if ((addr->type & MR_ADDR_MASK) == MR_ADDR_IPV4 && addr->netbits == 0 && addr->len == 4) + { + return ntohl(addr->v4.addr); + } + else + { + return 0; + } } static inline void -mroute_addr_reset (struct mroute_addr *ma) +mroute_addr_reset(struct mroute_addr *ma) { - ma->len = 0; - ma->type = MR_ADDR_NONE; + ma->len = 0; + ma->type = MR_ADDR_NONE; } #endif /* P2MP_SERVER */ diff --git a/src/openvpn/mss.c b/src/openvpn/mss.c index 7298c7bb5db..af3457b4403 100644 --- a/src/openvpn/mss.c +++ b/src/openvpn/mss.c @@ -44,33 +44,37 @@ * if yes, hand to mss_fixup_dowork() */ void -mss_fixup_ipv4 (struct buffer *buf, int maxmss) +mss_fixup_ipv4(struct buffer *buf, int maxmss) { - const struct openvpn_iphdr *pip; - int hlen; - - if (BLEN (buf) < (int) sizeof (struct openvpn_iphdr)) - return; - - verify_align_4 (buf); - pip = (struct openvpn_iphdr *) BPTR (buf); - - hlen = OPENVPN_IPH_GET_LEN (pip->version_len); - - if (pip->protocol == OPENVPN_IPPROTO_TCP - && ntohs (pip->tot_len) == BLEN (buf) - && (ntohs (pip->frag_off) & OPENVPN_IP_OFFMASK) == 0 - && hlen <= BLEN (buf) - && BLEN (buf) - hlen - >= (int) sizeof (struct openvpn_tcphdr)) + const struct openvpn_iphdr *pip; + int hlen; + + if (BLEN(buf) < (int) sizeof(struct openvpn_iphdr)) { - struct buffer newbuf = *buf; - if (buf_advance (&newbuf, hlen)) - { - struct openvpn_tcphdr *tc = (struct openvpn_tcphdr *) BPTR (&newbuf); - if (tc->flags & OPENVPN_TCPH_SYN_MASK) - mss_fixup_dowork (&newbuf, (uint16_t) maxmss); - } + return; + } + + verify_align_4(buf); + pip = (struct openvpn_iphdr *) BPTR(buf); + + hlen = OPENVPN_IPH_GET_LEN(pip->version_len); + + if (pip->protocol == OPENVPN_IPPROTO_TCP + && ntohs(pip->tot_len) == BLEN(buf) + && (ntohs(pip->frag_off) & OPENVPN_IP_OFFMASK) == 0 + && hlen <= BLEN(buf) + && BLEN(buf) - hlen + >= (int) sizeof(struct openvpn_tcphdr)) + { + struct buffer newbuf = *buf; + if (buf_advance(&newbuf, hlen)) + { + struct openvpn_tcphdr *tc = (struct openvpn_tcphdr *) BPTR(&newbuf); + if (tc->flags & OPENVPN_TCPH_SYN_MASK) + { + mss_fixup_dowork(&newbuf, (uint16_t) maxmss); + } + } } } @@ -80,42 +84,50 @@ mss_fixup_ipv4 (struct buffer *buf, int maxmss) * (IPv6 header structure is sufficiently different from IPv4...) */ void -mss_fixup_ipv6 (struct buffer *buf, int maxmss) +mss_fixup_ipv6(struct buffer *buf, int maxmss) { - const struct openvpn_ipv6hdr *pip6; - struct buffer newbuf; - - if (BLEN (buf) < (int) sizeof (struct openvpn_ipv6hdr)) - return; - - verify_align_4 (buf); - pip6 = (struct openvpn_ipv6hdr *) BPTR (buf); - - /* do we have the full IPv6 packet? - * "payload_len" does not include IPv6 header (+40 bytes) - */ - if (BLEN (buf) != (int) ntohs(pip6->payload_len)+40 ) - return; - - /* follow header chain until we reach final header, then check for TCP - * - * An IPv6 packet could, theoretically, have a chain of multiple headers - * before the final header (TCP, UDP, ...), so we'd need to walk that - * chain (see RFC 2460 and RFC 6564 for details). - * - * In practice, "most typically used" extention headers (AH, routing, - * fragment, mobility) are very unlikely to be seen inside an OpenVPN - * tun, so for now, we only handle the case of "single next header = TCP" - */ - if ( pip6->nexthdr != OPENVPN_IPPROTO_TCP ) - return; - - newbuf = *buf; - if ( buf_advance( &newbuf, 40 ) ) + const struct openvpn_ipv6hdr *pip6; + struct buffer newbuf; + + if (BLEN(buf) < (int) sizeof(struct openvpn_ipv6hdr)) { - struct openvpn_tcphdr *tc = (struct openvpn_tcphdr *) BPTR (&newbuf); - if (tc->flags & OPENVPN_TCPH_SYN_MASK) - mss_fixup_dowork (&newbuf, (uint16_t) maxmss-20); + return; + } + + verify_align_4(buf); + pip6 = (struct openvpn_ipv6hdr *) BPTR(buf); + + /* do we have the full IPv6 packet? + * "payload_len" does not include IPv6 header (+40 bytes) + */ + if (BLEN(buf) != (int) ntohs(pip6->payload_len)+40) + { + return; + } + + /* follow header chain until we reach final header, then check for TCP + * + * An IPv6 packet could, theoretically, have a chain of multiple headers + * before the final header (TCP, UDP, ...), so we'd need to walk that + * chain (see RFC 2460 and RFC 6564 for details). + * + * In practice, "most typically used" extention headers (AH, routing, + * fragment, mobility) are very unlikely to be seen inside an OpenVPN + * tun, so for now, we only handle the case of "single next header = TCP" + */ + if (pip6->nexthdr != OPENVPN_IPPROTO_TCP) + { + return; + } + + newbuf = *buf; + if (buf_advance( &newbuf, 40 ) ) + { + struct openvpn_tcphdr *tc = (struct openvpn_tcphdr *) BPTR(&newbuf); + if (tc->flags & OPENVPN_TCPH_SYN_MASK) + { + mss_fixup_dowork(&newbuf, (uint16_t) maxmss-20); + } } } @@ -125,50 +137,63 @@ mss_fixup_ipv6 (struct buffer *buf, int maxmss) */ void -mss_fixup_dowork (struct buffer *buf, uint16_t maxmss) +mss_fixup_dowork(struct buffer *buf, uint16_t maxmss) { - int hlen, olen, optlen; - uint8_t *opt; - uint16_t mssval; - int accumulate; - struct openvpn_tcphdr *tc; - - ASSERT (BLEN (buf) >= (int) sizeof (struct openvpn_tcphdr)); - - verify_align_4 (buf); - tc = (struct openvpn_tcphdr *) BPTR (buf); - hlen = OPENVPN_TCPH_GET_DOFF (tc->doff_res); - - /* Invalid header length or header without options. */ - if (hlen <= (int) sizeof (struct openvpn_tcphdr) - || hlen > BLEN (buf)) - return; - - for (olen = hlen - sizeof (struct openvpn_tcphdr), - opt = (uint8_t *)(tc + 1); - olen > 0; - olen -= optlen, opt += optlen) { - if (*opt == OPENVPN_TCPOPT_EOL) - break; - else if (*opt == OPENVPN_TCPOPT_NOP) - optlen = 1; - else { - optlen = *(opt + 1); - if (optlen <= 0 || optlen > olen) - break; - if (*opt == OPENVPN_TCPOPT_MAXSEG) { - if (optlen != OPENVPN_TCPOLEN_MAXSEG) - continue; - mssval = (opt[2]<<8)+opt[3]; - if (mssval > maxmss) { - dmsg (D_MSS, "MSS: %d -> %d", (int) mssval, (int) maxmss); - accumulate = htons(mssval); - opt[2] = (maxmss>>8)&0xff; - opt[3] = maxmss&0xff; - accumulate -= htons(maxmss); - ADJUST_CHECKSUM (accumulate, tc->check); + int hlen, olen, optlen; + uint8_t *opt; + uint16_t mssval; + int accumulate; + struct openvpn_tcphdr *tc; + + ASSERT(BLEN(buf) >= (int) sizeof(struct openvpn_tcphdr)); + + verify_align_4(buf); + tc = (struct openvpn_tcphdr *) BPTR(buf); + hlen = OPENVPN_TCPH_GET_DOFF(tc->doff_res); + + /* Invalid header length or header without options. */ + if (hlen <= (int) sizeof(struct openvpn_tcphdr) + || hlen > BLEN(buf)) + { + return; + } + + for (olen = hlen - sizeof(struct openvpn_tcphdr), + opt = (uint8_t *)(tc + 1); + olen > 0; + olen -= optlen, opt += optlen) { + if (*opt == OPENVPN_TCPOPT_EOL) + { + break; + } + else if (*opt == OPENVPN_TCPOPT_NOP) + { + optlen = 1; + } + else + { + optlen = *(opt + 1); + if (optlen <= 0 || optlen > olen) + { + break; + } + if (*opt == OPENVPN_TCPOPT_MAXSEG) + { + if (optlen != OPENVPN_TCPOLEN_MAXSEG) + { + continue; + } + mssval = (opt[2]<<8)+opt[3]; + if (mssval > maxmss) + { + dmsg(D_MSS, "MSS: %d -> %d", (int) mssval, (int) maxmss); + accumulate = htons(mssval); + opt[2] = (maxmss>>8)&0xff; + opt[3] = maxmss&0xff; + accumulate -= htons(maxmss); + ADJUST_CHECKSUM(accumulate, tc->check); + } + } } - } } - } } diff --git a/src/openvpn/mss.h b/src/openvpn/mss.h index 0d329432549..6d18fb975f1 100644 --- a/src/openvpn/mss.h +++ b/src/openvpn/mss.h @@ -28,8 +28,10 @@ #include "proto.h" #include "error.h" -void mss_fixup_ipv4 (struct buffer *buf, int maxmss); -void mss_fixup_ipv6 (struct buffer *buf, int maxmss); -void mss_fixup_dowork (struct buffer *buf, uint16_t maxmss); +void mss_fixup_ipv4(struct buffer *buf, int maxmss); + +void mss_fixup_ipv6(struct buffer *buf, int maxmss); + +void mss_fixup_dowork(struct buffer *buf, uint16_t maxmss); #endif diff --git a/src/openvpn/mstats.c b/src/openvpn/mstats.c index 3be493cd429..3dad866a8ae 100644 --- a/src/openvpn/mstats.c +++ b/src/openvpn/mstats.c @@ -50,73 +50,79 @@ static char mmap_fn[128]; void mstats_open(const char *fn) { - void *data; - ssize_t stat; - int fd; - struct mmap_stats ms; + void *data; + ssize_t stat; + int fd; + struct mmap_stats ms; - if (mmap_stats) /* already called? */ - return; + if (mmap_stats) /* already called? */ + { + return; + } - /* verify that filename is not too long */ - if (strlen(fn) >= sizeof(mmap_fn)) - msg (M_FATAL, "mstats_open: filename too long"); + /* verify that filename is not too long */ + if (strlen(fn) >= sizeof(mmap_fn)) + { + msg(M_FATAL, "mstats_open: filename too long"); + } - /* create file that will be memory mapped */ - fd = open (fn, O_CREAT | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR); - if (fd < 0) + /* create file that will be memory mapped */ + fd = open(fn, O_CREAT | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR); + if (fd < 0) { - msg (M_ERR, "mstats_open: cannot open: %s", fn); - return; + msg(M_ERR, "mstats_open: cannot open: %s", fn); + return; } - /* set the file to the correct size to contain a - struct mmap_stats, and zero it */ - CLEAR(ms); - ms.state = MSTATS_ACTIVE; - stat = write(fd, &ms, sizeof(ms)); - if (stat != sizeof(ms)) + /* set the file to the correct size to contain a + * struct mmap_stats, and zero it */ + CLEAR(ms); + ms.state = MSTATS_ACTIVE; + stat = write(fd, &ms, sizeof(ms)); + if (stat != sizeof(ms)) { - msg (M_ERR, "mstats_open: write error: %s", fn); - close(fd); - return; + msg(M_ERR, "mstats_open: write error: %s", fn); + close(fd); + return; } - /* mmap the file */ - data = mmap(NULL, sizeof(struct mmap_stats), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); - if (data == MAP_FAILED) + /* mmap the file */ + data = mmap(NULL, sizeof(struct mmap_stats), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + if (data == MAP_FAILED) { - msg (M_ERR, "mstats_open: write error: %s", fn); - close(fd); - return; + msg(M_ERR, "mstats_open: write error: %s", fn); + close(fd); + return; } - /* close the fd (mmap now controls the file) */ - if (close(fd)) + /* close the fd (mmap now controls the file) */ + if (close(fd)) { - msg (M_ERR, "mstats_open: close error: %s", fn); + msg(M_ERR, "mstats_open: close error: %s", fn); } - /* save filename so we can delete it later */ - strcpy(mmap_fn, fn); + /* save filename so we can delete it later */ + strcpy(mmap_fn, fn); - /* save a global pointer to memory-mapped region */ - mmap_stats = (struct mmap_stats *)data; + /* save a global pointer to memory-mapped region */ + mmap_stats = (struct mmap_stats *)data; - msg (M_INFO, "memstats data will be written to %s", fn); + msg(M_INFO, "memstats data will be written to %s", fn); } void mstats_close(void) { - if (mmap_stats) + if (mmap_stats) { - mmap_stats->state = MSTATS_EXPIRED; - if (munmap((void *)mmap_stats, sizeof(struct mmap_stats))) - msg (M_WARN | M_ERRNO, "mstats_close: munmap error"); - platform_unlink(mmap_fn); - mmap_stats = NULL; + mmap_stats->state = MSTATS_EXPIRED; + if (munmap((void *)mmap_stats, sizeof(struct mmap_stats))) + { + msg(M_WARN | M_ERRNO, "mstats_close: munmap error"); + } + platform_unlink(mmap_fn); + mmap_stats = NULL; } } -#endif +#endif /* if defined(ENABLE_MEMSTATS) */ diff --git a/src/openvpn/mstats.h b/src/openvpn/mstats.h index dab05fe9256..7a5cc68029a 100644 --- a/src/openvpn/mstats.h +++ b/src/openvpn/mstats.h @@ -33,19 +33,20 @@ /* this struct is mapped to the file */ struct mmap_stats { - counter_type link_read_bytes; /* counter_type can be assumed to be a uint64_t */ - counter_type link_write_bytes; - int n_clients; - -# define MSTATS_UNDEF 0 -# define MSTATS_ACTIVE 1 -# define MSTATS_EXPIRED 2 - int state; + counter_type link_read_bytes; /* counter_type can be assumed to be a uint64_t */ + counter_type link_write_bytes; + int n_clients; + +#define MSTATS_UNDEF 0 +#define MSTATS_ACTIVE 1 +#define MSTATS_EXPIRED 2 + int state; }; extern volatile struct mmap_stats *mmap_stats; /* GLOBAL */ void mstats_open(const char *fn); + void mstats_close(void); -#endif +#endif /* if !defined(OPENVPN_MEMSTATS_H) && defined(ENABLE_MEMSTATS) */ diff --git a/src/openvpn/mtcp.c b/src/openvpn/mtcp.c index 78e5ccd0a0e..4fab23fb454 100644 --- a/src/openvpn/mtcp.c +++ b/src/openvpn/mtcp.c @@ -59,619 +59,706 @@ /* * Special tags passed to event.[ch] functions */ -#define MTCP_SOCKET ((void*)1) -#define MTCP_TUN ((void*)2) -#define MTCP_SIG ((void*)3) /* Only on Windows */ +#define MTCP_SOCKET ((void *)1) +#define MTCP_TUN ((void *)2) +#define MTCP_SIG ((void *)3) /* Only on Windows */ #ifdef ENABLE_MANAGEMENT -# define MTCP_MANAGEMENT ((void*)4) +#define MTCP_MANAGEMENT ((void *)4) #endif #ifdef ENABLE_ASYNC_PUSH -#define MTCP_FILE_CLOSE_WRITE ((void*)5) +#define MTCP_FILE_CLOSE_WRITE ((void *)5) #endif -#define MTCP_N ((void*)16) /* upper bound on MTCP_x */ +#define MTCP_N ((void *)16) /* upper bound on MTCP_x */ struct ta_iow_flags { - unsigned int flags; - unsigned int ret; - unsigned int tun; - unsigned int sock; + unsigned int flags; + unsigned int ret; + unsigned int tun; + unsigned int sock; }; static const char * -pract (int action) +pract(int action) { - switch (action) + switch (action) { - case TA_UNDEF: - return "TA_UNDEF"; - case TA_SOCKET_READ: - return "TA_SOCKET_READ"; - case TA_SOCKET_READ_RESIDUAL: - return "TA_SOCKET_READ_RESIDUAL"; - case TA_SOCKET_WRITE: - return "TA_SOCKET_WRITE"; - case TA_SOCKET_WRITE_READY: - return "TA_SOCKET_WRITE_READY"; - case TA_SOCKET_WRITE_DEFERRED: - return "TA_SOCKET_WRITE_DEFERRED"; - case TA_TUN_READ: - return "TA_TUN_READ"; - case TA_TUN_WRITE: - return "TA_TUN_WRITE"; - case TA_INITIAL: - return "TA_INITIAL"; - case TA_TIMEOUT: - return "TA_TIMEOUT"; - case TA_TUN_WRITE_TIMEOUT: - return "TA_TUN_WRITE_TIMEOUT"; - default: - return "?"; + case TA_UNDEF: + return "TA_UNDEF"; + + case TA_SOCKET_READ: + return "TA_SOCKET_READ"; + + case TA_SOCKET_READ_RESIDUAL: + return "TA_SOCKET_READ_RESIDUAL"; + + case TA_SOCKET_WRITE: + return "TA_SOCKET_WRITE"; + + case TA_SOCKET_WRITE_READY: + return "TA_SOCKET_WRITE_READY"; + + case TA_SOCKET_WRITE_DEFERRED: + return "TA_SOCKET_WRITE_DEFERRED"; + + case TA_TUN_READ: + return "TA_TUN_READ"; + + case TA_TUN_WRITE: + return "TA_TUN_WRITE"; + + case TA_INITIAL: + return "TA_INITIAL"; + + case TA_TIMEOUT: + return "TA_TIMEOUT"; + + case TA_TUN_WRITE_TIMEOUT: + return "TA_TUN_WRITE_TIMEOUT"; + + default: + return "?"; } } static struct multi_instance * -multi_create_instance_tcp (struct multi_context *m) +multi_create_instance_tcp(struct multi_context *m) { - struct gc_arena gc = gc_new (); - struct multi_instance *mi = NULL; - struct hash *hash = m->hash; + struct gc_arena gc = gc_new(); + struct multi_instance *mi = NULL; + struct hash *hash = m->hash; - mi = multi_create_instance (m, NULL); - if (mi) + mi = multi_create_instance(m, NULL); + if (mi) { - struct hash_element *he; - const uint32_t hv = hash_value (hash, &mi->real); - struct hash_bucket *bucket = hash_bucket (hash, hv); - - he = hash_lookup_fast (hash, bucket, &mi->real, hv); - - if (he) - { - struct multi_instance *oldmi = (struct multi_instance *) he->value; - msg (D_MULTI_LOW, "MULTI TCP: new incoming client address matches existing client address -- new client takes precedence"); - oldmi->did_real_hash = false; - multi_close_instance (m, oldmi, false); - he->key = &mi->real; - he->value = mi; - } - else - hash_add_fast (hash, bucket, &mi->real, hv, mi); - - mi->did_real_hash = true; + struct hash_element *he; + const uint32_t hv = hash_value(hash, &mi->real); + struct hash_bucket *bucket = hash_bucket(hash, hv); + + he = hash_lookup_fast(hash, bucket, &mi->real, hv); + + if (he) + { + struct multi_instance *oldmi = (struct multi_instance *) he->value; + msg(D_MULTI_LOW, "MULTI TCP: new incoming client address matches existing client address -- new client takes precedence"); + oldmi->did_real_hash = false; + multi_close_instance(m, oldmi, false); + he->key = &mi->real; + he->value = mi; + } + else + { + hash_add_fast(hash, bucket, &mi->real, hv, mi); + } + + mi->did_real_hash = true; } #ifdef ENABLE_DEBUG - if (mi) - dmsg (D_MULTI_DEBUG, "MULTI TCP: instance added: %s", mroute_addr_print (&mi->real, &gc)); - else - dmsg (D_MULTI_DEBUG, "MULTI TCP: new client instance failed"); + if (mi) + { + dmsg(D_MULTI_DEBUG, "MULTI TCP: instance added: %s", mroute_addr_print(&mi->real, &gc)); + } + else + { + dmsg(D_MULTI_DEBUG, "MULTI TCP: new client instance failed"); + } #endif - gc_free (&gc); - ASSERT (!(mi && mi->halt)); - return mi; + gc_free(&gc); + ASSERT(!(mi && mi->halt)); + return mi; } bool -multi_tcp_instance_specific_init (struct multi_context *m, struct multi_instance *mi) +multi_tcp_instance_specific_init(struct multi_context *m, struct multi_instance *mi) { - /* buffer for queued TCP socket output packets */ - mi->tcp_link_out_deferred = mbuf_init (m->top.options.n_bcast_buf); - - ASSERT (mi->context.c2.link_socket); - ASSERT (mi->context.c2.link_socket->info.lsa); - ASSERT (mi->context.c2.link_socket->mode == LS_MODE_TCP_ACCEPT_FROM); - ASSERT (mi->context.c2.link_socket->info.lsa->actual.dest.addr.sa.sa_family == AF_INET - || mi->context.c2.link_socket->info.lsa->actual.dest.addr.sa.sa_family == AF_INET6 - ); - if (!mroute_extract_openvpn_sockaddr (&mi->real, &mi->context.c2.link_socket->info.lsa->actual.dest, true)) + /* buffer for queued TCP socket output packets */ + mi->tcp_link_out_deferred = mbuf_init(m->top.options.n_bcast_buf); + + ASSERT(mi->context.c2.link_socket); + ASSERT(mi->context.c2.link_socket->info.lsa); + ASSERT(mi->context.c2.link_socket->mode == LS_MODE_TCP_ACCEPT_FROM); + ASSERT(mi->context.c2.link_socket->info.lsa->actual.dest.addr.sa.sa_family == AF_INET + || mi->context.c2.link_socket->info.lsa->actual.dest.addr.sa.sa_family == AF_INET6 + ); + if (!mroute_extract_openvpn_sockaddr(&mi->real, &mi->context.c2.link_socket->info.lsa->actual.dest, true)) { - msg (D_MULTI_ERRORS, "MULTI TCP: TCP client address is undefined"); - return false; + msg(D_MULTI_ERRORS, "MULTI TCP: TCP client address is undefined"); + return false; } - return true; + return true; } void -multi_tcp_instance_specific_free (struct multi_instance *mi) +multi_tcp_instance_specific_free(struct multi_instance *mi) { - mbuf_free (mi->tcp_link_out_deferred); + mbuf_free(mi->tcp_link_out_deferred); } struct multi_tcp * -multi_tcp_init (int maxevents, int *maxclients) +multi_tcp_init(int maxevents, int *maxclients) { - struct multi_tcp *mtcp; - const int extra_events = BASE_N_EVENTS; - - ASSERT (maxevents >= 1); - ASSERT (maxclients); - - ALLOC_OBJ_CLEAR (mtcp, struct multi_tcp); - mtcp->maxevents = maxevents + extra_events; - mtcp->es = event_set_init (&mtcp->maxevents, 0); - wait_signal (mtcp->es, MTCP_SIG); - ALLOC_ARRAY (mtcp->esr, struct event_set_return, mtcp->maxevents); - *maxclients = max_int (min_int (mtcp->maxevents - extra_events, *maxclients), 1); - msg (D_MULTI_LOW, "MULTI: TCP INIT maxclients=%d maxevents=%d", *maxclients, mtcp->maxevents); - return mtcp; + struct multi_tcp *mtcp; + const int extra_events = BASE_N_EVENTS; + + ASSERT(maxevents >= 1); + ASSERT(maxclients); + + ALLOC_OBJ_CLEAR(mtcp, struct multi_tcp); + mtcp->maxevents = maxevents + extra_events; + mtcp->es = event_set_init(&mtcp->maxevents, 0); + wait_signal(mtcp->es, MTCP_SIG); + ALLOC_ARRAY(mtcp->esr, struct event_set_return, mtcp->maxevents); + *maxclients = max_int(min_int(mtcp->maxevents - extra_events, *maxclients), 1); + msg(D_MULTI_LOW, "MULTI: TCP INIT maxclients=%d maxevents=%d", *maxclients, mtcp->maxevents); + return mtcp; } void -multi_tcp_delete_event (struct multi_tcp *mtcp, event_t event) +multi_tcp_delete_event(struct multi_tcp *mtcp, event_t event) { - if (mtcp && mtcp->es) - event_del (mtcp->es, event); + if (mtcp && mtcp->es) + { + event_del(mtcp->es, event); + } } void -multi_tcp_free (struct multi_tcp *mtcp) +multi_tcp_free(struct multi_tcp *mtcp) { - if (mtcp) + if (mtcp) { - event_free (mtcp->es); - if (mtcp->esr) - free (mtcp->esr); - free (mtcp); + event_free(mtcp->es); + if (mtcp->esr) + { + free(mtcp->esr); + } + free(mtcp); } } void -multi_tcp_dereference_instance (struct multi_tcp *mtcp, struct multi_instance *mi) +multi_tcp_dereference_instance(struct multi_tcp *mtcp, struct multi_instance *mi) { - struct link_socket *ls = mi->context.c2.link_socket; - if (ls && mi->socket_set_called) - event_del (mtcp->es, socket_event_handle (ls)); - mtcp->n_esr = 0; + struct link_socket *ls = mi->context.c2.link_socket; + if (ls && mi->socket_set_called) + { + event_del(mtcp->es, socket_event_handle(ls)); + } + mtcp->n_esr = 0; } static inline void -multi_tcp_set_global_rw_flags (struct multi_context *m, struct multi_instance *mi) +multi_tcp_set_global_rw_flags(struct multi_context *m, struct multi_instance *mi) { - if (mi) + if (mi) { - mi->socket_set_called = true; - socket_set (mi->context.c2.link_socket, - m->mtcp->es, - mbuf_defined (mi->tcp_link_out_deferred) ? EVENT_WRITE : EVENT_READ, - mi, - &mi->tcp_rwflags); + mi->socket_set_called = true; + socket_set(mi->context.c2.link_socket, + m->mtcp->es, + mbuf_defined(mi->tcp_link_out_deferred) ? EVENT_WRITE : EVENT_READ, + mi, + &mi->tcp_rwflags); } } static inline int -multi_tcp_wait (const struct context *c, - struct multi_tcp *mtcp) +multi_tcp_wait(const struct context *c, + struct multi_tcp *mtcp) { - int status; - socket_set_listen_persistent (c->c2.link_socket, mtcp->es, MTCP_SOCKET); - tun_set (c->c1.tuntap, mtcp->es, EVENT_READ, MTCP_TUN, &mtcp->tun_rwflags); + int status; + socket_set_listen_persistent(c->c2.link_socket, mtcp->es, MTCP_SOCKET); + tun_set(c->c1.tuntap, mtcp->es, EVENT_READ, MTCP_TUN, &mtcp->tun_rwflags); #ifdef ENABLE_MANAGEMENT - if (management) - management_socket_set (management, mtcp->es, MTCP_MANAGEMENT, &mtcp->management_persist_flags); + if (management) + { + management_socket_set(management, mtcp->es, MTCP_MANAGEMENT, &mtcp->management_persist_flags); + } #endif #ifdef ENABLE_ASYNC_PUSH - /* arm inotify watcher */ - event_ctl (mtcp->es, c->c2.inotify_fd, EVENT_READ, MTCP_FILE_CLOSE_WRITE); + /* arm inotify watcher */ + event_ctl(mtcp->es, c->c2.inotify_fd, EVENT_READ, MTCP_FILE_CLOSE_WRITE); #endif - status = event_wait (mtcp->es, &c->c2.timeval, mtcp->esr, mtcp->maxevents); - update_time (); - mtcp->n_esr = 0; - if (status > 0) - mtcp->n_esr = status; - return status; + status = event_wait(mtcp->es, &c->c2.timeval, mtcp->esr, mtcp->maxevents); + update_time(); + mtcp->n_esr = 0; + if (status > 0) + { + mtcp->n_esr = status; + } + return status; } static inline struct context * -multi_tcp_context (struct multi_context *m, struct multi_instance *mi) +multi_tcp_context(struct multi_context *m, struct multi_instance *mi) { - if (mi) - return &mi->context; - else - return &m->top; + if (mi) + { + return &mi->context; + } + else + { + return &m->top; + } } static bool -multi_tcp_process_outgoing_link_ready (struct multi_context *m, struct multi_instance *mi, const unsigned int mpp_flags) +multi_tcp_process_outgoing_link_ready(struct multi_context *m, struct multi_instance *mi, const unsigned int mpp_flags) { - struct mbuf_item item; - bool ret = true; - ASSERT (mi); + struct mbuf_item item; + bool ret = true; + ASSERT(mi); - /* extract from queue */ - if (mbuf_extract_item (mi->tcp_link_out_deferred, &item)) /* ciphertext IP packet */ + /* extract from queue */ + if (mbuf_extract_item(mi->tcp_link_out_deferred, &item)) /* ciphertext IP packet */ { - dmsg (D_MULTI_TCP, "MULTI TCP: transmitting previously deferred packet"); - - ASSERT (mi == item.instance); - mi->context.c2.to_link = item.buffer->buf; - ret = multi_process_outgoing_link_dowork (m, mi, mpp_flags); - if (!ret) - mi = NULL; - mbuf_free_buf (item.buffer); + dmsg(D_MULTI_TCP, "MULTI TCP: transmitting previously deferred packet"); + + ASSERT(mi == item.instance); + mi->context.c2.to_link = item.buffer->buf; + ret = multi_process_outgoing_link_dowork(m, mi, mpp_flags); + if (!ret) + { + mi = NULL; + } + mbuf_free_buf(item.buffer); } - return ret; + return ret; } static bool -multi_tcp_process_outgoing_link (struct multi_context *m, bool defer, const unsigned int mpp_flags) +multi_tcp_process_outgoing_link(struct multi_context *m, bool defer, const unsigned int mpp_flags) { - struct multi_instance *mi = multi_process_outgoing_link_pre (m); - bool ret = true; + struct multi_instance *mi = multi_process_outgoing_link_pre(m); + bool ret = true; - if (mi) + if (mi) { - if (defer || mbuf_defined (mi->tcp_link_out_deferred)) - { - /* save to queue */ - struct buffer *buf = &mi->context.c2.to_link; - if (BLEN (buf) > 0) - { - struct mbuf_buffer *mb = mbuf_alloc_buf (buf); - struct mbuf_item item; - - set_prefix (mi); - dmsg (D_MULTI_TCP, "MULTI TCP: queuing deferred packet"); - item.buffer = mb; - item.instance = mi; - mbuf_add_item (mi->tcp_link_out_deferred, &item); - mbuf_free_buf (mb); - buf_reset (buf); - ret = multi_process_post (m, mi, mpp_flags); - if (!ret) - mi = NULL; - clear_prefix (); - } - } - else - { - ret = multi_process_outgoing_link_dowork (m, mi, mpp_flags); - if (!ret) - mi = NULL; - } + if (defer || mbuf_defined(mi->tcp_link_out_deferred)) + { + /* save to queue */ + struct buffer *buf = &mi->context.c2.to_link; + if (BLEN(buf) > 0) + { + struct mbuf_buffer *mb = mbuf_alloc_buf(buf); + struct mbuf_item item; + + set_prefix(mi); + dmsg(D_MULTI_TCP, "MULTI TCP: queuing deferred packet"); + item.buffer = mb; + item.instance = mi; + mbuf_add_item(mi->tcp_link_out_deferred, &item); + mbuf_free_buf(mb); + buf_reset(buf); + ret = multi_process_post(m, mi, mpp_flags); + if (!ret) + { + mi = NULL; + } + clear_prefix(); + } + } + else + { + ret = multi_process_outgoing_link_dowork(m, mi, mpp_flags); + if (!ret) + { + mi = NULL; + } + } } - return ret; + return ret; } static int -multi_tcp_wait_lite (struct multi_context *m, struct multi_instance *mi, const int action, bool *tun_input_pending) +multi_tcp_wait_lite(struct multi_context *m, struct multi_instance *mi, const int action, bool *tun_input_pending) { - struct context *c = multi_tcp_context (m, mi); - unsigned int looking_for = 0; + struct context *c = multi_tcp_context(m, mi); + unsigned int looking_for = 0; - dmsg (D_MULTI_DEBUG, "MULTI TCP: multi_tcp_wait_lite a=%s mi=" ptr_format, - pract(action), - (ptr_type)mi); + dmsg(D_MULTI_DEBUG, "MULTI TCP: multi_tcp_wait_lite a=%s mi=" ptr_format, + pract(action), + (ptr_type)mi); - tv_clear (&c->c2.timeval); /* ZERO-TIMEOUT */ + tv_clear(&c->c2.timeval); /* ZERO-TIMEOUT */ - switch (action) + switch (action) { - case TA_TUN_READ: - looking_for = TUN_READ; - tun_input_pending = NULL; - io_wait (c, IOW_READ_TUN); - break; - case TA_SOCKET_READ: - looking_for = SOCKET_READ; - tun_input_pending = NULL; - io_wait (c, IOW_READ_LINK); - break; - case TA_TUN_WRITE: - looking_for = TUN_WRITE; - tun_input_pending = NULL; - c->c2.timeval.tv_sec = 1; /* For some reason, the Linux 2.2 TUN/TAP driver hits this timeout */ - perf_push (PERF_PROC_OUT_TUN_MTCP); - io_wait (c, IOW_TO_TUN); - perf_pop (); - break; - case TA_SOCKET_WRITE: - looking_for = SOCKET_WRITE; - io_wait (c, IOW_TO_LINK|IOW_READ_TUN_FORCE); - break; - default: - msg (M_FATAL, "MULTI TCP: multi_tcp_wait_lite, unhandled action=%d", action); + case TA_TUN_READ: + looking_for = TUN_READ; + tun_input_pending = NULL; + io_wait(c, IOW_READ_TUN); + break; + + case TA_SOCKET_READ: + looking_for = SOCKET_READ; + tun_input_pending = NULL; + io_wait(c, IOW_READ_LINK); + break; + + case TA_TUN_WRITE: + looking_for = TUN_WRITE; + tun_input_pending = NULL; + c->c2.timeval.tv_sec = 1; /* For some reason, the Linux 2.2 TUN/TAP driver hits this timeout */ + perf_push(PERF_PROC_OUT_TUN_MTCP); + io_wait(c, IOW_TO_TUN); + perf_pop(); + break; + + case TA_SOCKET_WRITE: + looking_for = SOCKET_WRITE; + io_wait(c, IOW_TO_LINK|IOW_READ_TUN_FORCE); + break; + + default: + msg(M_FATAL, "MULTI TCP: multi_tcp_wait_lite, unhandled action=%d", action); } - if (tun_input_pending && (c->c2.event_set_status & TUN_READ)) - *tun_input_pending = true; + if (tun_input_pending && (c->c2.event_set_status & TUN_READ)) + { + *tun_input_pending = true; + } - if (c->c2.event_set_status & looking_for) + if (c->c2.event_set_status & looking_for) { - return action; + return action; } - else + else { - switch (action) - { - /* TCP socket output buffer is full */ - case TA_SOCKET_WRITE: - return TA_SOCKET_WRITE_DEFERRED; - - /* TUN device timed out on accepting write */ - case TA_TUN_WRITE: - return TA_TUN_WRITE_TIMEOUT; - } - - return TA_UNDEF; + switch (action) + { + /* TCP socket output buffer is full */ + case TA_SOCKET_WRITE: + return TA_SOCKET_WRITE_DEFERRED; + + /* TUN device timed out on accepting write */ + case TA_TUN_WRITE: + return TA_TUN_WRITE_TIMEOUT; + } + + return TA_UNDEF; } } static struct multi_instance * -multi_tcp_dispatch (struct multi_context *m, struct multi_instance *mi, const int action) +multi_tcp_dispatch(struct multi_context *m, struct multi_instance *mi, const int action) { - const unsigned int mpp_flags = MPP_PRE_SELECT|MPP_RECORD_TOUCH; - struct multi_instance *touched = mi; - m->mpp_touched = &touched; + const unsigned int mpp_flags = MPP_PRE_SELECT|MPP_RECORD_TOUCH; + struct multi_instance *touched = mi; + m->mpp_touched = &touched; - dmsg (D_MULTI_DEBUG, "MULTI TCP: multi_tcp_dispatch a=%s mi=" ptr_format, - pract(action), - (ptr_type)mi); + dmsg(D_MULTI_DEBUG, "MULTI TCP: multi_tcp_dispatch a=%s mi=" ptr_format, + pract(action), + (ptr_type)mi); - switch (action) + switch (action) { - case TA_TUN_READ: - read_incoming_tun (&m->top); - if (!IS_SIG (&m->top)) - multi_process_incoming_tun (m, mpp_flags); - break; - case TA_SOCKET_READ: - case TA_SOCKET_READ_RESIDUAL: - ASSERT (mi); - ASSERT (mi->context.c2.link_socket); - set_prefix (mi); - read_incoming_link (&mi->context); - clear_prefix (); - if (!IS_SIG (&mi->context)) - { - multi_process_incoming_link (m, mi, mpp_flags); - if (!IS_SIG (&mi->context)) - stream_buf_read_setup (mi->context.c2.link_socket); - } - break; - case TA_TIMEOUT: - multi_process_timeout (m, mpp_flags); - break; - case TA_TUN_WRITE: - multi_process_outgoing_tun (m, mpp_flags); - break; - case TA_TUN_WRITE_TIMEOUT: - multi_process_drop_outgoing_tun (m, mpp_flags); - break; - case TA_SOCKET_WRITE_READY: - ASSERT (mi); - multi_tcp_process_outgoing_link_ready (m, mi, mpp_flags); - break; - case TA_SOCKET_WRITE: - multi_tcp_process_outgoing_link (m, false, mpp_flags); - break; - case TA_SOCKET_WRITE_DEFERRED: - multi_tcp_process_outgoing_link (m, true, mpp_flags); - break; - case TA_INITIAL: - ASSERT (mi); - multi_tcp_set_global_rw_flags (m, mi); - multi_process_post (m, mi, mpp_flags); - break; - default: - msg (M_FATAL, "MULTI TCP: multi_tcp_dispatch, unhandled action=%d", action); + case TA_TUN_READ: + read_incoming_tun(&m->top); + if (!IS_SIG(&m->top)) + { + multi_process_incoming_tun(m, mpp_flags); + } + break; + + case TA_SOCKET_READ: + case TA_SOCKET_READ_RESIDUAL: + ASSERT(mi); + ASSERT(mi->context.c2.link_socket); + set_prefix(mi); + read_incoming_link(&mi->context); + clear_prefix(); + if (!IS_SIG(&mi->context)) + { + multi_process_incoming_link(m, mi, mpp_flags); + if (!IS_SIG(&mi->context)) + { + stream_buf_read_setup(mi->context.c2.link_socket); + } + } + break; + + case TA_TIMEOUT: + multi_process_timeout(m, mpp_flags); + break; + + case TA_TUN_WRITE: + multi_process_outgoing_tun(m, mpp_flags); + break; + + case TA_TUN_WRITE_TIMEOUT: + multi_process_drop_outgoing_tun(m, mpp_flags); + break; + + case TA_SOCKET_WRITE_READY: + ASSERT(mi); + multi_tcp_process_outgoing_link_ready(m, mi, mpp_flags); + break; + + case TA_SOCKET_WRITE: + multi_tcp_process_outgoing_link(m, false, mpp_flags); + break; + + case TA_SOCKET_WRITE_DEFERRED: + multi_tcp_process_outgoing_link(m, true, mpp_flags); + break; + + case TA_INITIAL: + ASSERT(mi); + multi_tcp_set_global_rw_flags(m, mi); + multi_process_post(m, mi, mpp_flags); + break; + + default: + msg(M_FATAL, "MULTI TCP: multi_tcp_dispatch, unhandled action=%d", action); } - m->mpp_touched = NULL; - return touched; + m->mpp_touched = NULL; + return touched; } int -multi_tcp_post (struct multi_context *m, struct multi_instance *mi, const int action) +multi_tcp_post(struct multi_context *m, struct multi_instance *mi, const int action) { - struct context *c = multi_tcp_context (m, mi); - int newaction = TA_UNDEF; + struct context *c = multi_tcp_context(m, mi); + int newaction = TA_UNDEF; -# define MTP_NONE 0 -# define MTP_TUN_OUT (1<<0) -# define MTP_LINK_OUT (1<<1) - unsigned int flags = MTP_NONE; +#define MTP_NONE 0 +#define MTP_TUN_OUT (1<<0) +#define MTP_LINK_OUT (1<<1) + unsigned int flags = MTP_NONE; - if (TUN_OUT(c)) - flags |= MTP_TUN_OUT; - if (LINK_OUT(c)) - flags |= MTP_LINK_OUT; + if (TUN_OUT(c)) + { + flags |= MTP_TUN_OUT; + } + if (LINK_OUT(c)) + { + flags |= MTP_LINK_OUT; + } - switch (flags) + switch (flags) { - case MTP_TUN_OUT|MTP_LINK_OUT: - case MTP_TUN_OUT: - newaction = TA_TUN_WRITE; - break; - case MTP_LINK_OUT: - newaction = TA_SOCKET_WRITE; - break; - case MTP_NONE: - if (mi && socket_read_residual (c->c2.link_socket)) - newaction = TA_SOCKET_READ_RESIDUAL; - else - multi_tcp_set_global_rw_flags (m, mi); - break; - default: - { - struct gc_arena gc = gc_new (); - msg (M_FATAL, "MULTI TCP: multi_tcp_post bad state, mi=%s flags=%d", - multi_instance_string (mi, false, &gc), - flags); - gc_free (&gc); - break; - } + case MTP_TUN_OUT|MTP_LINK_OUT: + case MTP_TUN_OUT: + newaction = TA_TUN_WRITE; + break; + + case MTP_LINK_OUT: + newaction = TA_SOCKET_WRITE; + break; + + case MTP_NONE: + if (mi && socket_read_residual(c->c2.link_socket)) + { + newaction = TA_SOCKET_READ_RESIDUAL; + } + else + { + multi_tcp_set_global_rw_flags(m, mi); + } + break; + + default: + { + struct gc_arena gc = gc_new(); + msg(M_FATAL, "MULTI TCP: multi_tcp_post bad state, mi=%s flags=%d", + multi_instance_string(mi, false, &gc), + flags); + gc_free(&gc); + break; + } } - dmsg (D_MULTI_DEBUG, "MULTI TCP: multi_tcp_post %s -> %s", - pract(action), - pract(newaction)); + dmsg(D_MULTI_DEBUG, "MULTI TCP: multi_tcp_post %s -> %s", + pract(action), + pract(newaction)); - return newaction; + return newaction; } static void -multi_tcp_action (struct multi_context *m, struct multi_instance *mi, int action, bool poll) +multi_tcp_action(struct multi_context *m, struct multi_instance *mi, int action, bool poll) { - bool tun_input_pending = false; - - do { - dmsg (D_MULTI_DEBUG, "MULTI TCP: multi_tcp_action a=%s p=%d", - pract(action), - poll); - - /* - * If TA_SOCKET_READ_RESIDUAL, it means we still have pending - * input packets which were read by a prior TCP recv. - * - * Otherwise do a "lite" wait, which means we wait with 0 timeout - * on I/O events only related to the current instance, not - * the big list of events. - * - * On our first pass, poll will be false because we already know - * that input is available, and to call io_wait would be redundant. - */ - if (poll && action != TA_SOCKET_READ_RESIDUAL) - { - const int orig_action = action; - action = multi_tcp_wait_lite (m, mi, action, &tun_input_pending); - if (action == TA_UNDEF) - msg (M_FATAL, "MULTI TCP: I/O wait required blocking in multi_tcp_action, action=%d", orig_action); - } - - /* - * Dispatch the action - */ - { - struct multi_instance *touched = multi_tcp_dispatch (m, mi, action); - - /* - * Signal received or TCP connection - * reset by peer? - */ - if (touched && IS_SIG (&touched->context)) - { - if (mi == touched) - mi = NULL; - multi_close_instance_on_signal (m, touched); - } - } - - /* - * If dispatch produced any pending output - * for a particular instance, point to - * that instance. - */ - if (m->pending) - mi = m->pending; - - /* - * Based on the effects of the action, - * such as generating pending output, - * possibly transition to a new action state. - */ - action = multi_tcp_post (m, mi, action); - - /* - * If we are finished processing the original action, - * check if we have any TUN input. If so, transition - * our action state to processing this input. - */ - if (tun_input_pending && action == TA_UNDEF) - { - action = TA_TUN_READ; - mi = NULL; - tun_input_pending = false; - poll = false; - } - else - poll = true; - - } while (action != TA_UNDEF); + bool tun_input_pending = false; + + do { + dmsg(D_MULTI_DEBUG, "MULTI TCP: multi_tcp_action a=%s p=%d", + pract(action), + poll); + + /* + * If TA_SOCKET_READ_RESIDUAL, it means we still have pending + * input packets which were read by a prior TCP recv. + * + * Otherwise do a "lite" wait, which means we wait with 0 timeout + * on I/O events only related to the current instance, not + * the big list of events. + * + * On our first pass, poll will be false because we already know + * that input is available, and to call io_wait would be redundant. + */ + if (poll && action != TA_SOCKET_READ_RESIDUAL) + { + const int orig_action = action; + action = multi_tcp_wait_lite(m, mi, action, &tun_input_pending); + if (action == TA_UNDEF) + { + msg(M_FATAL, "MULTI TCP: I/O wait required blocking in multi_tcp_action, action=%d", orig_action); + } + } + + /* + * Dispatch the action + */ + { + struct multi_instance *touched = multi_tcp_dispatch(m, mi, action); + + /* + * Signal received or TCP connection + * reset by peer? + */ + if (touched && IS_SIG(&touched->context)) + { + if (mi == touched) + { + mi = NULL; + } + multi_close_instance_on_signal(m, touched); + } + } + + /* + * If dispatch produced any pending output + * for a particular instance, point to + * that instance. + */ + if (m->pending) + { + mi = m->pending; + } + + /* + * Based on the effects of the action, + * such as generating pending output, + * possibly transition to a new action state. + */ + action = multi_tcp_post(m, mi, action); + + /* + * If we are finished processing the original action, + * check if we have any TUN input. If so, transition + * our action state to processing this input. + */ + if (tun_input_pending && action == TA_UNDEF) + { + action = TA_TUN_READ; + mi = NULL; + tun_input_pending = false; + poll = false; + } + else + { + poll = true; + } + + } while (action != TA_UNDEF); } static void -multi_tcp_process_io (struct multi_context *m) +multi_tcp_process_io(struct multi_context *m) { - struct multi_tcp *mtcp = m->mtcp; - int i; + struct multi_tcp *mtcp = m->mtcp; + int i; - for (i = 0; i < mtcp->n_esr; ++i) + for (i = 0; i < mtcp->n_esr; ++i) { - struct event_set_return *e = &mtcp->esr[i]; - - /* incoming data for instance? */ - if (e->arg >= MTCP_N) - { - struct multi_instance *mi = (struct multi_instance *) e->arg; - if (mi) - { - if (e->rwflags & EVENT_WRITE) - multi_tcp_action (m, mi, TA_SOCKET_WRITE_READY, false); - else if (e->rwflags & EVENT_READ) - multi_tcp_action (m, mi, TA_SOCKET_READ, false); - } - } - else - { + struct event_set_return *e = &mtcp->esr[i]; + + /* incoming data for instance? */ + if (e->arg >= MTCP_N) + { + struct multi_instance *mi = (struct multi_instance *) e->arg; + if (mi) + { + if (e->rwflags & EVENT_WRITE) + { + multi_tcp_action(m, mi, TA_SOCKET_WRITE_READY, false); + } + else if (e->rwflags & EVENT_READ) + { + multi_tcp_action(m, mi, TA_SOCKET_READ, false); + } + } + } + else + { #ifdef ENABLE_MANAGEMENT - if (e->arg == MTCP_MANAGEMENT) - { - ASSERT (management); - management_io (management); - } - else + if (e->arg == MTCP_MANAGEMENT) + { + ASSERT(management); + management_io(management); + } + else #endif - /* incoming data on TUN? */ - if (e->arg == MTCP_TUN) - { - if (e->rwflags & EVENT_WRITE) - multi_tcp_action (m, NULL, TA_TUN_WRITE, false); - else if (e->rwflags & EVENT_READ) - multi_tcp_action (m, NULL, TA_TUN_READ, false); - } - /* new incoming TCP client attempting to connect? */ - else if (e->arg == MTCP_SOCKET) - { - struct multi_instance *mi; - ASSERT (m->top.c2.link_socket); - socket_reset_listen_persistent (m->top.c2.link_socket); - mi = multi_create_instance_tcp (m); - if (mi) - multi_tcp_action (m, mi, TA_INITIAL, false); - } - /* signal received? */ - else if (e->arg == MTCP_SIG) - { - get_signal (&m->top.sig->signal_received); - } + /* incoming data on TUN? */ + if (e->arg == MTCP_TUN) + { + if (e->rwflags & EVENT_WRITE) + { + multi_tcp_action(m, NULL, TA_TUN_WRITE, false); + } + else if (e->rwflags & EVENT_READ) + { + multi_tcp_action(m, NULL, TA_TUN_READ, false); + } + } + /* new incoming TCP client attempting to connect? */ + else if (e->arg == MTCP_SOCKET) + { + struct multi_instance *mi; + ASSERT(m->top.c2.link_socket); + socket_reset_listen_persistent(m->top.c2.link_socket); + mi = multi_create_instance_tcp(m); + if (mi) + { + multi_tcp_action(m, mi, TA_INITIAL, false); + } + } + /* signal received? */ + else if (e->arg == MTCP_SIG) + { + get_signal(&m->top.sig->signal_received); + } #ifdef ENABLE_ASYNC_PUSH - else if (e->arg == MTCP_FILE_CLOSE_WRITE) - { - multi_process_file_closed (m, MPP_PRE_SELECT | MPP_RECORD_TOUCH); - } + else if (e->arg == MTCP_FILE_CLOSE_WRITE) + { + multi_process_file_closed(m, MPP_PRE_SELECT | MPP_RECORD_TOUCH); + } #endif - } - if (IS_SIG (&m->top)) - break; + } + if (IS_SIG(&m->top)) + { + break; + } + } + mtcp->n_esr = 0; + + /* + * Process queued mbuf packets destined for TCP socket + */ + { + struct multi_instance *mi; + while (!IS_SIG(&m->top) && (mi = mbuf_peek(m->mbuf)) != NULL) + { + multi_tcp_action(m, mi, TA_SOCKET_WRITE, true); + } } - mtcp->n_esr = 0; - - /* - * Process queued mbuf packets destined for TCP socket - */ - { - struct multi_instance *mi; - while (!IS_SIG (&m->top) && (mi = mbuf_peek (m->mbuf)) != NULL) - { - multi_tcp_action (m, mi, TA_SOCKET_WRITE, true); - } - } } /* @@ -679,81 +766,83 @@ multi_tcp_process_io (struct multi_context *m) * TCP mode. */ void -tunnel_server_tcp (struct context *top) +tunnel_server_tcp(struct context *top) { - struct multi_context multi; - int status; + struct multi_context multi; + int status; - top->mode = CM_TOP; - context_clear_2 (top); + top->mode = CM_TOP; + context_clear_2(top); - /* initialize top-tunnel instance */ - init_instance_handle_signals (top, top->es, CC_HARD_USR1_TO_HUP); - if (IS_SIG (top)) - return; - - /* initialize global multi_context object */ - multi_init (&multi, top, true, MC_SINGLE_THREADED); + /* initialize top-tunnel instance */ + init_instance_handle_signals(top, top->es, CC_HARD_USR1_TO_HUP); + if (IS_SIG(top)) + { + return; + } - /* initialize our cloned top object */ - multi_top_init (&multi, top); + /* initialize global multi_context object */ + multi_init(&multi, top, true, MC_SINGLE_THREADED); - /* initialize management interface */ - init_management_callback_multi (&multi); + /* initialize our cloned top object */ + multi_top_init(&multi, top); - /* finished with initialization */ - initialization_sequence_completed (top, ISC_SERVER); /* --mode server --proto tcp-server */ + /* initialize management interface */ + init_management_callback_multi(&multi); + + /* finished with initialization */ + initialization_sequence_completed(top, ISC_SERVER); /* --mode server --proto tcp-server */ #ifdef ENABLE_ASYNC_PUSH - multi.top.c2.inotify_fd = inotify_init(); - if (multi.top.c2.inotify_fd < 0) + multi.top.c2.inotify_fd = inotify_init(); + if (multi.top.c2.inotify_fd < 0) { - msg (D_MULTI_ERRORS, "MULTI: inotify_init error: %s", strerror(errno)); + msg(D_MULTI_ERRORS, "MULTI: inotify_init error: %s", strerror(errno)); } #endif - /* per-packet event loop */ - while (true) + /* per-packet event loop */ + while (true) { - perf_push (PERF_EVENT_LOOP); - - /* wait on tun/socket list */ - multi_get_timeout (&multi, &multi.top.c2.timeval); - status = multi_tcp_wait (&multi.top, multi.mtcp); - MULTI_CHECK_SIG (&multi); - - /* check on status of coarse timers */ - multi_process_per_second_timers (&multi); - - /* timeout? */ - if (status > 0) - { - /* process the I/O which triggered select */ - multi_tcp_process_io (&multi); - MULTI_CHECK_SIG (&multi); - } - else if (status == 0) - { - multi_tcp_action (&multi, NULL, TA_TIMEOUT, false); - } - - perf_pop (); + perf_push(PERF_EVENT_LOOP); + + /* wait on tun/socket list */ + multi_get_timeout(&multi, &multi.top.c2.timeval); + status = multi_tcp_wait(&multi.top, multi.mtcp); + MULTI_CHECK_SIG(&multi); + + /* check on status of coarse timers */ + multi_process_per_second_timers(&multi); + + /* timeout? */ + if (status > 0) + { + /* process the I/O which triggered select */ + multi_tcp_process_io(&multi); + MULTI_CHECK_SIG(&multi); + } + else if (status == 0) + { + multi_tcp_action(&multi, NULL, TA_TIMEOUT, false); + } + + perf_pop(); } #ifdef ENABLE_ASYNC_PUSH - close(top->c2.inotify_fd); + close(top->c2.inotify_fd); #endif - /* shut down management interface */ - uninit_management_callback_multi (&multi); + /* shut down management interface */ + uninit_management_callback_multi(&multi); - /* save ifconfig-pool */ - multi_ifconfig_pool_persist (&multi, true); + /* save ifconfig-pool */ + multi_ifconfig_pool_persist(&multi, true); - /* tear down tunnel instance (unless --persist-tun) */ - multi_uninit (&multi); - multi_top_free (&multi); - close_instance (top); + /* tear down tunnel instance (unless --persist-tun) */ + multi_uninit(&multi); + multi_top_free(&multi); + close_instance(top); } -#endif +#endif /* if P2MP_SERVER */ diff --git a/src/openvpn/mtcp.h b/src/openvpn/mtcp.h index b677b48a7a5..a11e56e60f0 100644 --- a/src/openvpn/mtcp.h +++ b/src/openvpn/mtcp.h @@ -38,27 +38,30 @@ */ struct multi_tcp { - struct event_set *es; - struct event_set_return *esr; - int n_esr; - int maxevents; - unsigned int tun_rwflags; + struct event_set *es; + struct event_set_return *esr; + int n_esr; + int maxevents; + unsigned int tun_rwflags; #ifdef ENABLE_MANAGEMENT - unsigned int management_persist_flags; + unsigned int management_persist_flags; #endif }; struct multi_instance; struct context; -struct multi_tcp *multi_tcp_init (int maxevents, int *maxclients); -void multi_tcp_free (struct multi_tcp *mtcp); -void multi_tcp_dereference_instance (struct multi_tcp *mtcp, struct multi_instance *mi); +struct multi_tcp *multi_tcp_init(int maxevents, int *maxclients); -bool multi_tcp_instance_specific_init (struct multi_context *m, struct multi_instance *mi); -void multi_tcp_instance_specific_free (struct multi_instance *mi); +void multi_tcp_free(struct multi_tcp *mtcp); -void multi_tcp_link_out_deferred (struct multi_context *m, struct multi_instance *mi); +void multi_tcp_dereference_instance(struct multi_tcp *mtcp, struct multi_instance *mi); + +bool multi_tcp_instance_specific_init(struct multi_context *m, struct multi_instance *mi); + +void multi_tcp_instance_specific_free(struct multi_instance *mi); + +void multi_tcp_link_out_deferred(struct multi_context *m, struct multi_instance *mi); /**************************************************************************/ @@ -68,10 +71,10 @@ void multi_tcp_link_out_deferred (struct multi_context *m, struct multi_instance * * @param top - Top-level context structure. */ -void tunnel_server_tcp (struct context *top); +void tunnel_server_tcp(struct context *top); -void multi_tcp_delete_event (struct multi_tcp *mtcp, event_t event); +void multi_tcp_delete_event(struct multi_tcp *mtcp, event_t event); -#endif -#endif +#endif /* if P2MP_SERVER */ +#endif /* ifndef MTCP_H */ diff --git a/src/openvpn/mtu.c b/src/openvpn/mtu.c index 8cbaa863b65..416a11e9604 100644 --- a/src/openvpn/mtu.c +++ b/src/openvpn/mtu.c @@ -41,76 +41,78 @@ /* allocate a buffer for socket or tun layer */ void -alloc_buf_sock_tun (struct buffer *buf, - const struct frame *frame, - const bool tuntap_buffer, - const unsigned int align_mask) +alloc_buf_sock_tun(struct buffer *buf, + const struct frame *frame, + const bool tuntap_buffer, + const unsigned int align_mask) { - /* allocate buffer for overlapped I/O */ - *buf = alloc_buf (BUF_SIZE (frame)); - ASSERT (buf_init (buf, FRAME_HEADROOM_ADJ (frame, align_mask))); - buf->len = tuntap_buffer ? MAX_RW_SIZE_TUN (frame) : MAX_RW_SIZE_LINK (frame); - ASSERT (buf_safe (buf, 0)); + /* allocate buffer for overlapped I/O */ + *buf = alloc_buf(BUF_SIZE(frame)); + ASSERT(buf_init(buf, FRAME_HEADROOM_ADJ(frame, align_mask))); + buf->len = tuntap_buffer ? MAX_RW_SIZE_TUN(frame) : MAX_RW_SIZE_LINK(frame); + ASSERT(buf_safe(buf, 0)); } void -frame_finalize (struct frame *frame, - bool link_mtu_defined, - int link_mtu, - bool tun_mtu_defined, - int tun_mtu) +frame_finalize(struct frame *frame, + bool link_mtu_defined, + int link_mtu, + bool tun_mtu_defined, + int tun_mtu) { - /* Set link_mtu based on command line options */ - if (tun_mtu_defined) + /* Set link_mtu based on command line options */ + if (tun_mtu_defined) { - ASSERT (!link_mtu_defined); - frame->link_mtu = tun_mtu + TUN_LINK_DELTA (frame); + ASSERT(!link_mtu_defined); + frame->link_mtu = tun_mtu + TUN_LINK_DELTA(frame); } - else + else { - ASSERT (link_mtu_defined); - frame->link_mtu = link_mtu; + ASSERT(link_mtu_defined); + frame->link_mtu = link_mtu; } - if (TUN_MTU_SIZE (frame) < TUN_MTU_MIN) + if (TUN_MTU_SIZE(frame) < TUN_MTU_MIN) { - msg (M_WARN, "TUN MTU value (%d) must be at least %d", TUN_MTU_SIZE (frame), TUN_MTU_MIN); - frame_print (frame, M_FATAL, "MTU is too small"); + msg(M_WARN, "TUN MTU value (%d) must be at least %d", TUN_MTU_SIZE(frame), TUN_MTU_MIN); + frame_print(frame, M_FATAL, "MTU is too small"); } - frame->link_mtu_dynamic = frame->link_mtu; + frame->link_mtu_dynamic = frame->link_mtu; } /* * Set the tun MTU dynamically. */ void -frame_set_mtu_dynamic (struct frame *frame, int mtu, unsigned int flags) +frame_set_mtu_dynamic(struct frame *frame, int mtu, unsigned int flags) { #ifdef ENABLE_DEBUG - const int orig_mtu = mtu; - const int orig_link_mtu_dynamic = frame->link_mtu_dynamic; + const int orig_mtu = mtu; + const int orig_link_mtu_dynamic = frame->link_mtu_dynamic; #endif - ASSERT (mtu >= 0); + ASSERT(mtu >= 0); - if (flags & SET_MTU_TUN) - mtu += TUN_LINK_DELTA (frame); + if (flags & SET_MTU_TUN) + { + mtu += TUN_LINK_DELTA(frame); + } - if (!(flags & SET_MTU_UPPER_BOUND) || mtu < frame->link_mtu_dynamic) + if (!(flags & SET_MTU_UPPER_BOUND) || mtu < frame->link_mtu_dynamic) { - frame->link_mtu_dynamic = constrain_int ( - mtu, - EXPANDED_SIZE_MIN (frame), - EXPANDED_SIZE (frame)); + frame->link_mtu_dynamic = constrain_int( + mtu, + EXPANDED_SIZE_MIN(frame), + EXPANDED_SIZE(frame)); } - dmsg (D_MTU_DEBUG, "MTU DYNAMIC mtu=%d, flags=%u, %d -> %d", - orig_mtu, - flags, - orig_link_mtu_dynamic, - frame->link_mtu_dynamic); + dmsg(D_MTU_DEBUG, "MTU DYNAMIC mtu=%d, flags=%u, %d -> %d", + orig_mtu, + flags, + orig_link_mtu_dynamic, + frame->link_mtu_dynamic); } /* @@ -119,200 +121,227 @@ frame_set_mtu_dynamic (struct frame *frame, int mtu, unsigned int flags) * queue. */ void -frame_subtract_extra (struct frame *frame, const struct frame *src) +frame_subtract_extra(struct frame *frame, const struct frame *src) { - frame->extra_frame -= src->extra_frame; - frame->extra_tun += src->extra_frame; + frame->extra_frame -= src->extra_frame; + frame->extra_tun += src->extra_frame; } void -frame_init_mssfix (struct frame *frame, const struct options *options) +frame_init_mssfix(struct frame *frame, const struct options *options) { - if (options->ce.mssfix) + if (options->ce.mssfix) { - frame_set_mtu_dynamic (frame, options->ce.mssfix, SET_MTU_UPPER_BOUND); + frame_set_mtu_dynamic(frame, options->ce.mssfix, SET_MTU_UPPER_BOUND); } } void -frame_print (const struct frame *frame, - int level, - const char *prefix) +frame_print(const struct frame *frame, + int level, + const char *prefix) { - struct gc_arena gc = gc_new (); - struct buffer out = alloc_buf_gc (256, &gc); - if (prefix) - buf_printf (&out, "%s ", prefix); - buf_printf (&out, "["); - buf_printf (&out, " L:%d", frame->link_mtu); - buf_printf (&out, " D:%d", frame->link_mtu_dynamic); - buf_printf (&out, " EF:%d", frame->extra_frame); - buf_printf (&out, " EB:%d", frame->extra_buffer); - buf_printf (&out, " ET:%d", frame->extra_tun); - buf_printf (&out, " EL:%d", frame->extra_link); - if (frame->align_flags && frame->align_adjust) - buf_printf (&out, " AF:%u/%d", frame->align_flags, frame->align_adjust); - buf_printf (&out, " ]"); - - msg (level, "%s", out.data); - gc_free (&gc); + struct gc_arena gc = gc_new(); + struct buffer out = alloc_buf_gc(256, &gc); + if (prefix) + { + buf_printf(&out, "%s ", prefix); + } + buf_printf(&out, "["); + buf_printf(&out, " L:%d", frame->link_mtu); + buf_printf(&out, " D:%d", frame->link_mtu_dynamic); + buf_printf(&out, " EF:%d", frame->extra_frame); + buf_printf(&out, " EB:%d", frame->extra_buffer); + buf_printf(&out, " ET:%d", frame->extra_tun); + buf_printf(&out, " EL:%d", frame->extra_link); + if (frame->align_flags && frame->align_adjust) + { + buf_printf(&out, " AF:%u/%d", frame->align_flags, frame->align_adjust); + } + buf_printf(&out, " ]"); + + msg(level, "%s", out.data); + gc_free(&gc); } #define MTUDISC_NOT_SUPPORTED_MSG "--mtu-disc is not supported on this OS" void -set_mtu_discover_type (int sd, int mtu_type, sa_family_t proto_af) +set_mtu_discover_type(int sd, int mtu_type, sa_family_t proto_af) { - if (mtu_type >= 0) + if (mtu_type >= 0) { - switch (proto_af) - { + switch (proto_af) + { #if defined(HAVE_SETSOCKOPT) && defined(IP_MTU_DISCOVER) - case AF_INET: - if (setsockopt - (sd, IPPROTO_IP, IP_MTU_DISCOVER, &mtu_type, sizeof (mtu_type))) - msg (M_ERR, "Error setting IP_MTU_DISCOVER type=%d on TCP/UDP socket", - mtu_type); - break; + case AF_INET: + if (setsockopt + (sd, IPPROTO_IP, IP_MTU_DISCOVER, &mtu_type, sizeof(mtu_type))) + { + msg(M_ERR, "Error setting IP_MTU_DISCOVER type=%d on TCP/UDP socket", + mtu_type); + } + break; + #endif #if defined(HAVE_SETSOCKOPT) && defined(IPV6_MTU_DISCOVER) - case AF_INET6: - if (setsockopt - (sd, IPPROTO_IPV6, IPV6_MTU_DISCOVER, &mtu_type, sizeof (mtu_type))) - msg (M_ERR, "Error setting IPV6_MTU_DISCOVER type=%d on TCP6/UDP6 socket", - mtu_type); - break; + case AF_INET6: + if (setsockopt + (sd, IPPROTO_IPV6, IPV6_MTU_DISCOVER, &mtu_type, sizeof(mtu_type))) + { + msg(M_ERR, "Error setting IPV6_MTU_DISCOVER type=%d on TCP6/UDP6 socket", + mtu_type); + } + break; + #endif - default: - msg (M_FATAL, MTUDISC_NOT_SUPPORTED_MSG); - break; - } + default: + msg(M_FATAL, MTUDISC_NOT_SUPPORTED_MSG); + break; + } } } int -translate_mtu_discover_type_name (const char *name) +translate_mtu_discover_type_name(const char *name) { #if defined(IP_PMTUDISC_DONT) && defined(IP_PMTUDISC_WANT) && defined(IP_PMTUDISC_DO) - if (!strcmp (name, "yes")) - return IP_PMTUDISC_DO; - if (!strcmp (name, "maybe")) - return IP_PMTUDISC_WANT; - if (!strcmp (name, "no")) - return IP_PMTUDISC_DONT; - msg (M_FATAL, - "invalid --mtu-disc type: '%s' -- valid types are 'yes', 'maybe', or 'no'", - name); -#else - msg (M_FATAL, MTUDISC_NOT_SUPPORTED_MSG); + if (!strcmp(name, "yes")) + { + return IP_PMTUDISC_DO; + } + if (!strcmp(name, "maybe")) + { + return IP_PMTUDISC_WANT; + } + if (!strcmp(name, "no")) + { + return IP_PMTUDISC_DONT; + } + msg(M_FATAL, + "invalid --mtu-disc type: '%s' -- valid types are 'yes', 'maybe', or 'no'", + name); +#else /* if defined(IP_PMTUDISC_DONT) && defined(IP_PMTUDISC_WANT) && defined(IP_PMTUDISC_DO) */ + msg(M_FATAL, MTUDISC_NOT_SUPPORTED_MSG); #endif - return -1; /* NOTREACHED */ + return -1; /* NOTREACHED */ } #if EXTENDED_SOCKET_ERROR_CAPABILITY struct probehdr { - uint32_t ttl; - struct timeval tv; + uint32_t ttl; + struct timeval tv; }; const char * -format_extended_socket_error (int fd, int *mtu, struct gc_arena *gc) +format_extended_socket_error(int fd, int *mtu, struct gc_arena *gc) { - int res; - struct probehdr rcvbuf; - struct iovec iov; - struct msghdr msg; - struct cmsghdr *cmsg; - struct sock_extended_err *e; - struct sockaddr_in addr; - struct buffer out = alloc_buf_gc (256, gc); - char *cbuf = (char *) gc_malloc (256, false, gc); - - *mtu = 0; - - while (true) + int res; + struct probehdr rcvbuf; + struct iovec iov; + struct msghdr msg; + struct cmsghdr *cmsg; + struct sock_extended_err *e; + struct sockaddr_in addr; + struct buffer out = alloc_buf_gc(256, gc); + char *cbuf = (char *) gc_malloc(256, false, gc); + + *mtu = 0; + + while (true) { - memset (&rcvbuf, -1, sizeof (rcvbuf)); - iov.iov_base = &rcvbuf; - iov.iov_len = sizeof (rcvbuf); - msg.msg_name = (uint8_t *) &addr; - msg.msg_namelen = sizeof (addr); - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - msg.msg_flags = 0; - msg.msg_control = cbuf; - msg.msg_controllen = 256; /* size of cbuf */ - - res = recvmsg (fd, &msg, MSG_ERRQUEUE); - if (res < 0) - goto exit; - - e = NULL; - - for (cmsg = CMSG_FIRSTHDR (&msg); cmsg; cmsg = CMSG_NXTHDR (&msg, cmsg)) - { - if (cmsg->cmsg_level == SOL_IP) - { - if (cmsg->cmsg_type == IP_RECVERR) - { - e = (struct sock_extended_err *) CMSG_DATA (cmsg); - } - else - { - buf_printf (&out ,"CMSG=%d|", cmsg->cmsg_type); - } - } - } - if (e == NULL) - { - buf_printf (&out, "NO-INFO|"); - goto exit; - } - - switch (e->ee_errno) - { - case ETIMEDOUT: - buf_printf (&out, "ETIMEDOUT|"); - break; - case EMSGSIZE: - buf_printf (&out, "EMSGSIZE Path-MTU=%d|", e->ee_info); - *mtu = e->ee_info; - break; - case ECONNREFUSED: - buf_printf (&out, "ECONNREFUSED|"); - break; - case EPROTO: - buf_printf (&out, "EPROTO|"); - break; - case EHOSTUNREACH: - buf_printf (&out, "EHOSTUNREACH|"); - break; - case ENETUNREACH: - buf_printf (&out, "ENETUNREACH|"); - break; - case EACCES: - buf_printf (&out, "EACCES|"); - break; - default: - buf_printf (&out, "UNKNOWN|"); - break; - } + memset(&rcvbuf, -1, sizeof(rcvbuf)); + iov.iov_base = &rcvbuf; + iov.iov_len = sizeof(rcvbuf); + msg.msg_name = (uint8_t *) &addr; + msg.msg_namelen = sizeof(addr); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_flags = 0; + msg.msg_control = cbuf; + msg.msg_controllen = 256; /* size of cbuf */ + + res = recvmsg(fd, &msg, MSG_ERRQUEUE); + if (res < 0) + { + goto exit; + } + + e = NULL; + + for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) + { + if (cmsg->cmsg_level == SOL_IP) + { + if (cmsg->cmsg_type == IP_RECVERR) + { + e = (struct sock_extended_err *) CMSG_DATA(cmsg); + } + else + { + buf_printf(&out,"CMSG=%d|", cmsg->cmsg_type); + } + } + } + if (e == NULL) + { + buf_printf(&out, "NO-INFO|"); + goto exit; + } + + switch (e->ee_errno) + { + case ETIMEDOUT: + buf_printf(&out, "ETIMEDOUT|"); + break; + + case EMSGSIZE: + buf_printf(&out, "EMSGSIZE Path-MTU=%d|", e->ee_info); + *mtu = e->ee_info; + break; + + case ECONNREFUSED: + buf_printf(&out, "ECONNREFUSED|"); + break; + + case EPROTO: + buf_printf(&out, "EPROTO|"); + break; + + case EHOSTUNREACH: + buf_printf(&out, "EHOSTUNREACH|"); + break; + + case ENETUNREACH: + buf_printf(&out, "ENETUNREACH|"); + break; + + case EACCES: + buf_printf(&out, "EACCES|"); + break; + + default: + buf_printf(&out, "UNKNOWN|"); + break; + } } - exit: - buf_rmtail (&out, '|'); - return BSTR (&out); +exit: + buf_rmtail(&out, '|'); + return BSTR(&out); } void -set_sock_extended_error_passing (int sd) +set_sock_extended_error_passing(int sd) { - int on = 1; - if (setsockopt (sd, SOL_IP, IP_RECVERR, (void *) &on, sizeof (on))) - msg (M_WARN | M_ERRNO, - "Note: enable extended error passing on TCP/UDP socket failed (IP_RECVERR)"); + int on = 1; + if (setsockopt(sd, SOL_IP, IP_RECVERR, (void *) &on, sizeof(on))) + { + msg(M_WARN | M_ERRNO, + "Note: enable extended error passing on TCP/UDP socket failed (IP_RECVERR)"); + } } -#endif +#endif /* if EXTENDED_SOCKET_ERROR_CAPABILITY */ diff --git a/src/openvpn/mtu.h b/src/openvpn/mtu.h index 0320545b15c..0d5402d0034 100644 --- a/src/openvpn/mtu.h +++ b/src/openvpn/mtu.h @@ -28,7 +28,7 @@ #include "buffer.h" /* - * + * * Packet maninipulation routes such as encrypt, decrypt, compress, decompress * are passed a frame buffer that looks like this: * @@ -92,20 +92,20 @@ * Packet geometry parameters. */ struct frame { - int link_mtu; /**< Maximum packet size to be sent over + int link_mtu; /**< Maximum packet size to be sent over * the external network interface. */ - int link_mtu_dynamic; /**< Dynamic MTU value for the external + int link_mtu_dynamic; /**< Dynamic MTU value for the external * network interface. */ - int extra_frame; /**< Maximum number of bytes that all + int extra_frame; /**< Maximum number of bytes that all * processing steps together could add. * @code * frame.link_mtu = "socket MTU" - extra_frame; * @endcode */ - int extra_buffer; /**< Maximum number of bytes that + int extra_buffer; /**< Maximum number of bytes that * processing steps could expand the * internal work buffer. * @@ -115,24 +115,24 @@ struct frame { * space for worst-case expansion of * incompressible content. */ - int extra_tun; /**< Maximum number of bytes in excess of + int extra_tun; /**< Maximum number of bytes in excess of * the tun/tap MTU that might be read * from or written to the virtual * tun/tap network interface. */ - int extra_link; /**< Maximum number of bytes in excess of + int extra_link; /**< Maximum number of bytes in excess of * external network interface's MTU that * might be read from or written to it. */ - /* - * Alignment control - */ -# define FRAME_HEADROOM_MARKER_DECRYPT (1<<0) -# define FRAME_HEADROOM_MARKER_FRAGMENT (1<<1) -# define FRAME_HEADROOM_MARKER_READ_LINK (1<<2) -# define FRAME_HEADROOM_MARKER_READ_STREAM (1<<3) - unsigned int align_flags; - int align_adjust; + /* + * Alignment control + */ +#define FRAME_HEADROOM_MARKER_DECRYPT (1<<0) +#define FRAME_HEADROOM_MARKER_FRAGMENT (1<<1) +#define FRAME_HEADROOM_MARKER_READ_LINK (1<<2) +#define FRAME_HEADROOM_MARKER_READ_STREAM (1<<3) + unsigned int align_flags; + int align_adjust; }; /* Forward declarations, to prevent includes */ @@ -198,20 +198,21 @@ struct options; * Function prototypes. */ -void frame_finalize (struct frame *frame, - bool link_mtu_defined, - int link_mtu, - bool tun_mtu_defined, - int tun_mtu); +void frame_finalize(struct frame *frame, + bool link_mtu_defined, + int link_mtu, + bool tun_mtu_defined, + int tun_mtu); + +void frame_subtract_extra(struct frame *frame, const struct frame *src); -void frame_subtract_extra (struct frame *frame, const struct frame *src); +void frame_print(const struct frame *frame, + int level, + const char *prefix); -void frame_print (const struct frame *frame, - int level, - const char *prefix); +void set_mtu_discover_type(int sd, int mtu_type, sa_family_t proto_af); -void set_mtu_discover_type (int sd, int mtu_type, sa_family_t proto_af); -int translate_mtu_discover_type_name (const char *name); +int translate_mtu_discover_type_name(const char *name); /* * frame_set_mtu_dynamic and flags @@ -220,18 +221,18 @@ int translate_mtu_discover_type_name (const char *name); #define SET_MTU_TUN (1<<0) /* use tun/tap rather than link sizing */ #define SET_MTU_UPPER_BOUND (1<<1) /* only decrease dynamic MTU */ -void frame_set_mtu_dynamic (struct frame *frame, int mtu, unsigned int flags); +void frame_set_mtu_dynamic(struct frame *frame, int mtu, unsigned int flags); /* * allocate a buffer for socket or tun layer */ -void alloc_buf_sock_tun (struct buffer *buf, - const struct frame *frame, - const bool tuntap_buffer, - const unsigned int align_mask); +void alloc_buf_sock_tun(struct buffer *buf, + const struct frame *frame, + const bool tuntap_buffer, + const unsigned int align_mask); /** Set the --mssfix option. */ -void frame_init_mssfix (struct frame *frame, const struct options *options); +void frame_init_mssfix(struct frame *frame, const struct options *options); /* * EXTENDED_SOCKET_ERROR_CAPABILITY functions -- print extra error info @@ -241,8 +242,9 @@ void frame_init_mssfix (struct frame *frame, const struct options *options); #if EXTENDED_SOCKET_ERROR_CAPABILITY -void set_sock_extended_error_passing (int sd); -const char *format_extended_socket_error (int fd, int *mtu, struct gc_arena *gc); +void set_sock_extended_error_passing(int sd); + +const char *format_extended_socket_error(int fd, int *mtu, struct gc_arena *gc); #endif @@ -251,12 +253,12 @@ const char *format_extended_socket_error (int fd, int *mtu, struct gc_arena *gc) * headroom and alignment issues. */ static inline int -frame_headroom (const struct frame *f, const unsigned int flag_mask) +frame_headroom(const struct frame *f, const unsigned int flag_mask) { - const int offset = FRAME_HEADROOM_BASE (f); - const int adjust = (flag_mask & f->align_flags) ? f->align_adjust : 0; - const int delta = ((PAYLOAD_ALIGN << 24) - (offset + adjust)) & (PAYLOAD_ALIGN - 1); - return offset + delta; + const int offset = FRAME_HEADROOM_BASE(f); + const int adjust = (flag_mask & f->align_flags) ? f->align_adjust : 0; + const int delta = ((PAYLOAD_ALIGN << 24) - (offset + adjust)) & (PAYLOAD_ALIGN - 1); + return offset + delta; } /* @@ -264,57 +266,57 @@ frame_headroom (const struct frame *f, const unsigned int flag_mask) */ static inline void -frame_add_to_link_mtu (struct frame *frame, const int increment) +frame_add_to_link_mtu(struct frame *frame, const int increment) { - frame->link_mtu += increment; + frame->link_mtu += increment; } static inline void -frame_add_to_extra_frame (struct frame *frame, const int increment) +frame_add_to_extra_frame(struct frame *frame, const int increment) { - frame->extra_frame += increment; + frame->extra_frame += increment; } static inline void -frame_add_to_extra_tun (struct frame *frame, const int increment) +frame_add_to_extra_tun(struct frame *frame, const int increment) { - frame->extra_tun += increment; + frame->extra_tun += increment; } static inline void -frame_add_to_extra_link (struct frame *frame, const int increment) +frame_add_to_extra_link(struct frame *frame, const int increment) { - frame->extra_link += increment; + frame->extra_link += increment; } static inline void -frame_add_to_extra_buffer (struct frame *frame, const int increment) +frame_add_to_extra_buffer(struct frame *frame, const int increment) { - frame->extra_buffer += increment; + frame->extra_buffer += increment; } static inline void -frame_add_to_align_adjust (struct frame *frame, const int increment) +frame_add_to_align_adjust(struct frame *frame, const int increment) { - frame->align_adjust += increment; + frame->align_adjust += increment; } static inline void -frame_align_to_extra_frame (struct frame *frame) +frame_align_to_extra_frame(struct frame *frame) { - frame->align_adjust = frame->extra_frame + frame->extra_link; + frame->align_adjust = frame->extra_frame + frame->extra_link; } static inline void -frame_or_align_flags (struct frame *frame, const unsigned int flag_mask) +frame_or_align_flags(struct frame *frame, const unsigned int flag_mask) { - frame->align_flags |= flag_mask; + frame->align_flags |= flag_mask; } static inline bool -frame_defined (const struct frame *frame) +frame_defined(const struct frame *frame) { - return frame->link_mtu > 0; + return frame->link_mtu > 0; } -#endif +#endif /* ifndef MTU_H */ diff --git a/src/openvpn/mudp.c b/src/openvpn/mudp.c index fec5e8d9244..35a8d3c73cb 100644 --- a/src/openvpn/mudp.c +++ b/src/openvpn/mudp.c @@ -49,189 +49,205 @@ */ struct multi_instance * -multi_get_create_instance_udp (struct multi_context *m, bool *floated) +multi_get_create_instance_udp(struct multi_context *m, bool *floated) { - struct gc_arena gc = gc_new (); - struct mroute_addr real; - struct multi_instance *mi = NULL; - struct hash *hash = m->hash; + struct gc_arena gc = gc_new(); + struct mroute_addr real; + struct multi_instance *mi = NULL; + struct hash *hash = m->hash; - if (mroute_extract_openvpn_sockaddr (&real, &m->top.c2.from.dest, true) && - m->top.c2.buf.len > 0) + if (mroute_extract_openvpn_sockaddr(&real, &m->top.c2.from.dest, true) + && m->top.c2.buf.len > 0) { - struct hash_element *he; - const uint32_t hv = hash_value (hash, &real); - struct hash_bucket *bucket = hash_bucket (hash, hv); - uint8_t* ptr = BPTR(&m->top.c2.buf); - uint8_t op = ptr[0] >> P_OPCODE_SHIFT; - bool v2 = (op == P_DATA_V2) && (m->top.c2.buf.len >= (1 + 3)); - bool peer_id_disabled = false; - - /* make sure buffer has enough length to read opcode (1 byte) and peer-id (3 bytes) */ - if (v2) - { - uint32_t peer_id = ntohl(*(uint32_t*)ptr) & 0xFFFFFF; - peer_id_disabled = (peer_id == MAX_PEER_ID); - - if (!peer_id_disabled && (peer_id < m->max_clients) && (m->instances[peer_id])) - { - mi = m->instances[peer_id]; - - *floated = !link_socket_actual_match(&mi->context.c2.from, &m->top.c2.from); - - if (*floated) - { - /* reset prefix, since here we are not sure peer is the one it claims to be */ - ungenerate_prefix(mi); - msg (D_MULTI_MEDIUM, "Float requested for peer %" PRIu32 " to %s", peer_id, - mroute_addr_print (&real, &gc)); - } - } - } - if (!v2 || peer_id_disabled) - { - he = hash_lookup_fast (hash, bucket, &real, hv); - if (he) - { - mi = (struct multi_instance *) he->value; - } - } - if (!mi) - { - if (!m->top.c2.tls_auth_standalone - || tls_pre_decrypt_lite (m->top.c2.tls_auth_standalone, &m->top.c2.from, &m->top.c2.buf)) - { - if (frequency_limit_event_allowed (m->new_connection_limiter)) - { - mi = multi_create_instance (m, &real); - if (mi) - { - int i; - - hash_add_fast (hash, bucket, &mi->real, hv, mi); - mi->did_real_hash = true; - - /* max_clients must be less then max peer-id value */ - ASSERT(m->max_clients < MAX_PEER_ID); - - for (i = 0; i < m->max_clients; ++i) - { - if (!m->instances[i]) - { - mi->context.c2.tls_multi->peer_id = i; - m->instances[i] = mi; - break; - } - } - - /* should not really end up here, since multi_create_instance returns null - * if amount of clients exceeds max_clients */ - ASSERT(i < m->max_clients); - } - } - else - { - msg (D_MULTI_ERRORS, - "MULTI: Connection from %s would exceed new connection frequency limit as controlled by --connect-freq", - mroute_addr_print (&real, &gc)); - } - } - } + struct hash_element *he; + const uint32_t hv = hash_value(hash, &real); + struct hash_bucket *bucket = hash_bucket(hash, hv); + uint8_t *ptr = BPTR(&m->top.c2.buf); + uint8_t op = ptr[0] >> P_OPCODE_SHIFT; + bool v2 = (op == P_DATA_V2) && (m->top.c2.buf.len >= (1 + 3)); + bool peer_id_disabled = false; + + /* make sure buffer has enough length to read opcode (1 byte) and peer-id (3 bytes) */ + if (v2) + { + uint32_t peer_id = ntohl(*(uint32_t *)ptr) & 0xFFFFFF; + peer_id_disabled = (peer_id == MAX_PEER_ID); + + if (!peer_id_disabled && (peer_id < m->max_clients) && (m->instances[peer_id])) + { + mi = m->instances[peer_id]; + + *floated = !link_socket_actual_match(&mi->context.c2.from, &m->top.c2.from); + + if (*floated) + { + /* reset prefix, since here we are not sure peer is the one it claims to be */ + ungenerate_prefix(mi); + msg(D_MULTI_MEDIUM, "Float requested for peer %" PRIu32 " to %s", peer_id, + mroute_addr_print(&real, &gc)); + } + } + } + if (!v2 || peer_id_disabled) + { + he = hash_lookup_fast(hash, bucket, &real, hv); + if (he) + { + mi = (struct multi_instance *) he->value; + } + } + if (!mi) + { + if (!m->top.c2.tls_auth_standalone + || tls_pre_decrypt_lite(m->top.c2.tls_auth_standalone, &m->top.c2.from, &m->top.c2.buf)) + { + if (frequency_limit_event_allowed(m->new_connection_limiter)) + { + mi = multi_create_instance(m, &real); + if (mi) + { + int i; + + hash_add_fast(hash, bucket, &mi->real, hv, mi); + mi->did_real_hash = true; + + /* max_clients must be less then max peer-id value */ + ASSERT(m->max_clients < MAX_PEER_ID); + + for (i = 0; i < m->max_clients; ++i) + { + if (!m->instances[i]) + { + mi->context.c2.tls_multi->peer_id = i; + m->instances[i] = mi; + break; + } + } + + /* should not really end up here, since multi_create_instance returns null + * if amount of clients exceeds max_clients */ + ASSERT(i < m->max_clients); + } + } + else + { + msg(D_MULTI_ERRORS, + "MULTI: Connection from %s would exceed new connection frequency limit as controlled by --connect-freq", + mroute_addr_print(&real, &gc)); + } + } + } #ifdef ENABLE_DEBUG - if (check_debug_level (D_MULTI_DEBUG)) - { - const char *status = mi ? "[ok]" : "[failed]"; - - dmsg (D_MULTI_DEBUG, "GET INST BY REAL: %s %s", - mroute_addr_print (&real, &gc), - status); - } + if (check_debug_level(D_MULTI_DEBUG)) + { + const char *status = mi ? "[ok]" : "[failed]"; + + dmsg(D_MULTI_DEBUG, "GET INST BY REAL: %s %s", + mroute_addr_print(&real, &gc), + status); + } #endif } - gc_free (&gc); - ASSERT (!(mi && mi->halt)); - return mi; + gc_free(&gc); + ASSERT(!(mi && mi->halt)); + return mi; } /* * Send a packet to TCP/UDP socket. */ static inline void -multi_process_outgoing_link (struct multi_context *m, const unsigned int mpp_flags) +multi_process_outgoing_link(struct multi_context *m, const unsigned int mpp_flags) { - struct multi_instance *mi = multi_process_outgoing_link_pre (m); - if (mi) - multi_process_outgoing_link_dowork (m, mi, mpp_flags); + struct multi_instance *mi = multi_process_outgoing_link_pre(m); + if (mi) + { + multi_process_outgoing_link_dowork(m, mi, mpp_flags); + } } /* * Process an I/O event. */ static void -multi_process_io_udp (struct multi_context *m) +multi_process_io_udp(struct multi_context *m) { - const unsigned int status = m->top.c2.event_set_status; - const unsigned int mpp_flags = m->top.c2.fast_io - ? (MPP_CONDITIONAL_PRE_SELECT | MPP_CLOSE_ON_SIGNAL) - : (MPP_PRE_SELECT | MPP_CLOSE_ON_SIGNAL); + const unsigned int status = m->top.c2.event_set_status; + const unsigned int mpp_flags = m->top.c2.fast_io + ? (MPP_CONDITIONAL_PRE_SELECT | MPP_CLOSE_ON_SIGNAL) + : (MPP_PRE_SELECT | MPP_CLOSE_ON_SIGNAL); #ifdef MULTI_DEBUG_EVENT_LOOP - char buf[16]; - buf[0] = 0; - if (status & SOCKET_READ) - strcat (buf, "SR/"); - else if (status & SOCKET_WRITE) - strcat (buf, "SW/"); - else if (status & TUN_READ) - strcat (buf, "TR/"); - else if (status & TUN_WRITE) - strcat (buf, "TW/"); + char buf[16]; + buf[0] = 0; + if (status & SOCKET_READ) + { + strcat(buf, "SR/"); + } + else if (status & SOCKET_WRITE) + { + strcat(buf, "SW/"); + } + else if (status & TUN_READ) + { + strcat(buf, "TR/"); + } + else if (status & TUN_WRITE) + { + strcat(buf, "TW/"); + } #ifdef ENABLE_ASYNC_PUSH - else if (status & FILE_CLOSED) - strcat (buf, "FC/"); -#endif - printf ("IO %s\n", buf); + else if (status & FILE_CLOSED) + { + strcat(buf, "FC/"); + } #endif + printf("IO %s\n", buf); +#endif /* ifdef MULTI_DEBUG_EVENT_LOOP */ #ifdef ENABLE_MANAGEMENT - if (status & (MANAGEMENT_READ|MANAGEMENT_WRITE)) + if (status & (MANAGEMENT_READ|MANAGEMENT_WRITE)) { - ASSERT (management); - management_io (management); + ASSERT(management); + management_io(management); } #endif - /* UDP port ready to accept write */ - if (status & SOCKET_WRITE) + /* UDP port ready to accept write */ + if (status & SOCKET_WRITE) { - multi_process_outgoing_link (m, mpp_flags); + multi_process_outgoing_link(m, mpp_flags); } - /* TUN device ready to accept write */ - else if (status & TUN_WRITE) + /* TUN device ready to accept write */ + else if (status & TUN_WRITE) { - multi_process_outgoing_tun (m, mpp_flags); + multi_process_outgoing_tun(m, mpp_flags); } - /* Incoming data on UDP port */ - else if (status & SOCKET_READ) + /* Incoming data on UDP port */ + else if (status & SOCKET_READ) { - read_incoming_link (&m->top); - if (!IS_SIG (&m->top)) - multi_process_incoming_link (m, NULL, mpp_flags); + read_incoming_link(&m->top); + if (!IS_SIG(&m->top)) + { + multi_process_incoming_link(m, NULL, mpp_flags); + } } - /* Incoming data on TUN device */ - else if (status & TUN_READ) + /* Incoming data on TUN device */ + else if (status & TUN_READ) { - read_incoming_tun (&m->top); - if (!IS_SIG (&m->top)) - multi_process_incoming_tun (m, mpp_flags); + read_incoming_tun(&m->top); + if (!IS_SIG(&m->top)) + { + multi_process_incoming_tun(m, mpp_flags); + } } #ifdef ENABLE_ASYNC_PUSH - /* INOTIFY callback */ - else if (status & FILE_CLOSED) + /* INOTIFY callback */ + else if (status & FILE_CLOSED) { - multi_process_file_closed(m, mpp_flags); + multi_process_file_closed(m, mpp_flags); } #endif } @@ -241,22 +257,30 @@ multi_process_io_udp (struct multi_context *m) * a point-to-multipoint tunnel. */ static inline unsigned int -p2mp_iow_flags (const struct multi_context *m) +p2mp_iow_flags(const struct multi_context *m) { - unsigned int flags = IOW_WAIT_SIGNAL; - if (m->pending) + unsigned int flags = IOW_WAIT_SIGNAL; + if (m->pending) + { + if (TUN_OUT(&m->pending->context)) + { + flags |= IOW_TO_TUN; + } + if (LINK_OUT(&m->pending->context)) + { + flags |= IOW_TO_LINK; + } + } + else if (mbuf_defined(m->mbuf)) + { + flags |= IOW_MBUF; + } + else { - if (TUN_OUT (&m->pending->context)) - flags |= IOW_TO_TUN; - if (LINK_OUT (&m->pending->context)) - flags |= IOW_TO_LINK; + flags |= IOW_READ; } - else if (mbuf_defined (m->mbuf)) - flags |= IOW_MBUF; - else - flags |= IOW_READ; - return flags; + return flags; } @@ -272,86 +296,88 @@ p2mp_iow_flags (const struct multi_context *m) * @param top - Top-level context structure. */ static void -tunnel_server_udp_single_threaded (struct context *top) +tunnel_server_udp_single_threaded(struct context *top) { - struct multi_context multi; + struct multi_context multi; - top->mode = CM_TOP; - context_clear_2 (top); + top->mode = CM_TOP; + context_clear_2(top); - /* initialize top-tunnel instance */ - init_instance_handle_signals (top, top->es, CC_HARD_USR1_TO_HUP); - if (IS_SIG (top)) - return; - - /* initialize global multi_context object */ - multi_init (&multi, top, false, MC_SINGLE_THREADED); + /* initialize top-tunnel instance */ + init_instance_handle_signals(top, top->es, CC_HARD_USR1_TO_HUP); + if (IS_SIG(top)) + { + return; + } - /* initialize our cloned top object */ - multi_top_init (&multi, top); + /* initialize global multi_context object */ + multi_init(&multi, top, false, MC_SINGLE_THREADED); - /* initialize management interface */ - init_management_callback_multi (&multi); + /* initialize our cloned top object */ + multi_top_init(&multi, top); - /* finished with initialization */ - initialization_sequence_completed (top, ISC_SERVER); /* --mode server --proto udp */ + /* initialize management interface */ + init_management_callback_multi(&multi); + + /* finished with initialization */ + initialization_sequence_completed(top, ISC_SERVER); /* --mode server --proto udp */ #ifdef ENABLE_ASYNC_PUSH - multi.top.c2.inotify_fd = inotify_init(); - if (multi.top.c2.inotify_fd < 0) + multi.top.c2.inotify_fd = inotify_init(); + if (multi.top.c2.inotify_fd < 0) { - msg (D_MULTI_ERRORS, "MULTI: inotify_init error: %s", strerror(errno)); + msg(D_MULTI_ERRORS, "MULTI: inotify_init error: %s", strerror(errno)); } #endif - /* per-packet event loop */ - while (true) + /* per-packet event loop */ + while (true) { - perf_push (PERF_EVENT_LOOP); - - /* set up and do the io_wait() */ - multi_get_timeout (&multi, &multi.top.c2.timeval); - io_wait (&multi.top, p2mp_iow_flags (&multi)); - MULTI_CHECK_SIG (&multi); - - /* check on status of coarse timers */ - multi_process_per_second_timers (&multi); - - /* timeout? */ - if (multi.top.c2.event_set_status == ES_TIMEOUT) - { - multi_process_timeout (&multi, MPP_PRE_SELECT|MPP_CLOSE_ON_SIGNAL); - } - else - { - /* process I/O */ - multi_process_io_udp (&multi); - MULTI_CHECK_SIG (&multi); - } - - perf_pop (); + perf_push(PERF_EVENT_LOOP); + + /* set up and do the io_wait() */ + multi_get_timeout(&multi, &multi.top.c2.timeval); + io_wait(&multi.top, p2mp_iow_flags(&multi)); + MULTI_CHECK_SIG(&multi); + + /* check on status of coarse timers */ + multi_process_per_second_timers(&multi); + + /* timeout? */ + if (multi.top.c2.event_set_status == ES_TIMEOUT) + { + multi_process_timeout(&multi, MPP_PRE_SELECT|MPP_CLOSE_ON_SIGNAL); + } + else + { + /* process I/O */ + multi_process_io_udp(&multi); + MULTI_CHECK_SIG(&multi); + } + + perf_pop(); } #ifdef ENABLE_ASYNC_PUSH - close(top->c2.inotify_fd); + close(top->c2.inotify_fd); #endif - /* shut down management interface */ - uninit_management_callback_multi (&multi); + /* shut down management interface */ + uninit_management_callback_multi(&multi); - /* save ifconfig-pool */ - multi_ifconfig_pool_persist (&multi, true); + /* save ifconfig-pool */ + multi_ifconfig_pool_persist(&multi, true); - /* tear down tunnel instance (unless --persist-tun) */ - multi_uninit (&multi); - multi_top_free (&multi); - close_instance (top); + /* tear down tunnel instance (unless --persist-tun) */ + multi_uninit(&multi); + multi_top_free(&multi); + close_instance(top); } void -tunnel_server_udp (struct context *top) +tunnel_server_udp(struct context *top) { - tunnel_server_udp_single_threaded (top); + tunnel_server_udp_single_threaded(top); } -#endif +#endif /* if P2MP_SERVER */ diff --git a/src/openvpn/mudp.h b/src/openvpn/mudp.h index 1f15d9d22c4..89ec78c507f 100644 --- a/src/openvpn/mudp.h +++ b/src/openvpn/mudp.h @@ -44,7 +44,7 @@ struct multi_context; * * @param top - Top-level context structure. */ -void tunnel_server_udp (struct context *top); +void tunnel_server_udp(struct context *top); /**************************************************************************/ @@ -65,7 +65,7 @@ void tunnel_server_udp (struct context *top); * packet's source address or if one was a newly created successfully. * NULL if one did not yet exist and a new one was not created. */ -struct multi_instance *multi_get_create_instance_udp (struct multi_context *m, bool *floated); +struct multi_instance *multi_get_create_instance_udp(struct multi_context *m, bool *floated); #endif #endif diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index 4fc8b026480..3480579bf7d 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -55,22 +55,28 @@ #ifdef MULTI_DEBUG_EVENT_LOOP static const char * -id (struct multi_instance *mi) +id(struct multi_instance *mi) { - if (mi) - return tls_common_name (mi->context.c2.tls_multi, false); - else - return "NULL"; + if (mi) + { + return tls_common_name(mi->context.c2.tls_multi, false); + } + else + { + return "NULL"; + } } #endif #ifdef MANAGEMENT_DEF_AUTH static void -set_cc_config (struct multi_instance *mi, struct buffer_list *cc_config) +set_cc_config(struct multi_instance *mi, struct buffer_list *cc_config) { - if (mi->cc_config) - buffer_list_free (mi->cc_config); - mi->cc_config = cc_config; + if (mi->cc_config) + { + buffer_list_free(mi->cc_config); + } + mi->cc_config = cc_config; } #endif @@ -78,170 +84,188 @@ static inline void update_mstat_n_clients(const int n_clients) { #ifdef ENABLE_MEMSTATS - if (mmap_stats) - mmap_stats->n_clients = n_clients; + if (mmap_stats) + { + mmap_stats->n_clients = n_clients; + } #endif } static bool -learn_address_script (const struct multi_context *m, - const struct multi_instance *mi, - const char *op, - const struct mroute_addr *addr) -{ - struct gc_arena gc = gc_new (); - struct env_set *es; - bool ret = true; - struct plugin_list *plugins; - - /* get environmental variable source */ - if (mi && mi->context.c2.es) - es = mi->context.c2.es; - else - es = env_set_create (&gc); - - /* get plugin source */ - if (mi) - plugins = mi->context.plugins; - else - plugins = m->top.plugins; - - if (plugin_defined (plugins, OPENVPN_PLUGIN_LEARN_ADDRESS)) - { - struct argv argv = argv_new (); - argv_printf (&argv, "%s %s", - op, - mroute_addr_print (addr, &gc)); - if (mi) - argv_printf_cat (&argv, "%s", tls_common_name (mi->context.c2.tls_multi, false)); - if (plugin_call (plugins, OPENVPN_PLUGIN_LEARN_ADDRESS, &argv, NULL, es) != OPENVPN_PLUGIN_FUNC_SUCCESS) - { - msg (M_WARN, "WARNING: learn-address plugin call failed"); - ret = false; - } - argv_reset (&argv); - } - - if (m->top.options.learn_address_script) - { - struct argv argv = argv_new (); - setenv_str (es, "script_type", "learn-address"); - argv_parse_cmd (&argv, m->top.options.learn_address_script); - argv_printf_cat (&argv, "%s %s", op, mroute_addr_print (addr, &gc)); - if (mi) - argv_printf_cat (&argv, "%s", tls_common_name (mi->context.c2.tls_multi, false)); - if (!openvpn_run_script (&argv, es, 0, "--learn-address")) - ret = false; - argv_reset (&argv); - } - - gc_free (&gc); - return ret; +learn_address_script(const struct multi_context *m, + const struct multi_instance *mi, + const char *op, + const struct mroute_addr *addr) +{ + struct gc_arena gc = gc_new(); + struct env_set *es; + bool ret = true; + struct plugin_list *plugins; + + /* get environmental variable source */ + if (mi && mi->context.c2.es) + { + es = mi->context.c2.es; + } + else + { + es = env_set_create(&gc); + } + + /* get plugin source */ + if (mi) + { + plugins = mi->context.plugins; + } + else + { + plugins = m->top.plugins; + } + + if (plugin_defined(plugins, OPENVPN_PLUGIN_LEARN_ADDRESS)) + { + struct argv argv = argv_new(); + argv_printf(&argv, "%s %s", + op, + mroute_addr_print(addr, &gc)); + if (mi) + { + argv_printf_cat(&argv, "%s", tls_common_name(mi->context.c2.tls_multi, false)); + } + if (plugin_call(plugins, OPENVPN_PLUGIN_LEARN_ADDRESS, &argv, NULL, es) != OPENVPN_PLUGIN_FUNC_SUCCESS) + { + msg(M_WARN, "WARNING: learn-address plugin call failed"); + ret = false; + } + argv_reset(&argv); + } + + if (m->top.options.learn_address_script) + { + struct argv argv = argv_new(); + setenv_str(es, "script_type", "learn-address"); + argv_parse_cmd(&argv, m->top.options.learn_address_script); + argv_printf_cat(&argv, "%s %s", op, mroute_addr_print(addr, &gc)); + if (mi) + { + argv_printf_cat(&argv, "%s", tls_common_name(mi->context.c2.tls_multi, false)); + } + if (!openvpn_run_script(&argv, es, 0, "--learn-address")) + { + ret = false; + } + argv_reset(&argv); + } + + gc_free(&gc); + return ret; } void -multi_ifconfig_pool_persist (struct multi_context *m, bool force) +multi_ifconfig_pool_persist(struct multi_context *m, bool force) { - /* write pool data to file */ - if (m->ifconfig_pool - && m->top.c1.ifconfig_pool_persist - && (force || ifconfig_pool_write_trigger (m->top.c1.ifconfig_pool_persist))) + /* write pool data to file */ + if (m->ifconfig_pool + && m->top.c1.ifconfig_pool_persist + && (force || ifconfig_pool_write_trigger(m->top.c1.ifconfig_pool_persist))) { - ifconfig_pool_write (m->top.c1.ifconfig_pool_persist, m->ifconfig_pool); + ifconfig_pool_write(m->top.c1.ifconfig_pool_persist, m->ifconfig_pool); } } static void -multi_reap_range (const struct multi_context *m, - int start_bucket, - int end_bucket) +multi_reap_range(const struct multi_context *m, + int start_bucket, + int end_bucket) { - struct gc_arena gc = gc_new (); - struct hash_iterator hi; - struct hash_element *he; + struct gc_arena gc = gc_new(); + struct hash_iterator hi; + struct hash_element *he; - if (start_bucket < 0) + if (start_bucket < 0) { - start_bucket = 0; - end_bucket = hash_n_buckets (m->vhash); + start_bucket = 0; + end_bucket = hash_n_buckets(m->vhash); } - dmsg (D_MULTI_DEBUG, "MULTI: REAP range %d -> %d", start_bucket, end_bucket); - hash_iterator_init_range (m->vhash, &hi, start_bucket, end_bucket); - while ((he = hash_iterator_next (&hi)) != NULL) + dmsg(D_MULTI_DEBUG, "MULTI: REAP range %d -> %d", start_bucket, end_bucket); + hash_iterator_init_range(m->vhash, &hi, start_bucket, end_bucket); + while ((he = hash_iterator_next(&hi)) != NULL) { - struct multi_route *r = (struct multi_route *) he->value; - if (!multi_route_defined (m, r)) - { - dmsg (D_MULTI_DEBUG, "MULTI: REAP DEL %s", - mroute_addr_print (&r->addr, &gc)); - learn_address_script (m, NULL, "delete", &r->addr); - multi_route_del (r); - hash_iterator_delete_element (&hi); - } + struct multi_route *r = (struct multi_route *) he->value; + if (!multi_route_defined(m, r)) + { + dmsg(D_MULTI_DEBUG, "MULTI: REAP DEL %s", + mroute_addr_print(&r->addr, &gc)); + learn_address_script(m, NULL, "delete", &r->addr); + multi_route_del(r); + hash_iterator_delete_element(&hi); + } } - hash_iterator_free (&hi); - gc_free (&gc); + hash_iterator_free(&hi); + gc_free(&gc); } static void -multi_reap_all (const struct multi_context *m) +multi_reap_all(const struct multi_context *m) { - multi_reap_range (m, -1, 0); + multi_reap_range(m, -1, 0); } static struct multi_reap * -multi_reap_new (int buckets_per_pass) +multi_reap_new(int buckets_per_pass) { - struct multi_reap *mr; - ALLOC_OBJ (mr, struct multi_reap); - mr->bucket_base = 0; - mr->buckets_per_pass = buckets_per_pass; - mr->last_call = now; - return mr; + struct multi_reap *mr; + ALLOC_OBJ(mr, struct multi_reap); + mr->bucket_base = 0; + mr->buckets_per_pass = buckets_per_pass; + mr->last_call = now; + return mr; } void -multi_reap_process_dowork (const struct multi_context *m) +multi_reap_process_dowork(const struct multi_context *m) { - struct multi_reap *mr = m->reaper; - if (mr->bucket_base >= hash_n_buckets (m->vhash)) - mr->bucket_base = 0; - multi_reap_range (m, mr->bucket_base, mr->bucket_base + mr->buckets_per_pass); - mr->bucket_base += mr->buckets_per_pass; - mr->last_call = now; + struct multi_reap *mr = m->reaper; + if (mr->bucket_base >= hash_n_buckets(m->vhash)) + { + mr->bucket_base = 0; + } + multi_reap_range(m, mr->bucket_base, mr->bucket_base + mr->buckets_per_pass); + mr->bucket_base += mr->buckets_per_pass; + mr->last_call = now; } static void -multi_reap_free (struct multi_reap *mr) +multi_reap_free(struct multi_reap *mr) { - free (mr); + free(mr); } /* * How many buckets in vhash to reap per pass. */ static int -reap_buckets_per_pass (int n_buckets) +reap_buckets_per_pass(int n_buckets) { - return constrain_int (n_buckets / REAP_DIVISOR, REAP_MIN, REAP_MAX); + return constrain_int(n_buckets / REAP_DIVISOR, REAP_MIN, REAP_MAX); } #ifdef MANAGEMENT_DEF_AUTH static uint32_t -cid_hash_function (const void *key, uint32_t iv) +cid_hash_function(const void *key, uint32_t iv) { - const unsigned long *k = (const unsigned long *)key; - return (uint32_t) *k; + const unsigned long *k = (const unsigned long *)key; + return (uint32_t) *k; } static bool -cid_compare_function (const void *key1, const void *key2) +cid_compare_function(const void *key1, const void *key2) { - const unsigned long *k1 = (const unsigned long *)key1; - const unsigned long *k2 = (const unsigned long *)key2; - return *k1 == *k2; + const unsigned long *k1 = (const unsigned long *)key1; + const unsigned long *k2 = (const unsigned long *)key2; + return *k1 == *k2; } #endif @@ -251,15 +275,15 @@ static uint32_t /* * inotify watcher descriptors are used as hash value */ -int_hash_function (const void *key, uint32_t iv) +int_hash_function(const void *key, uint32_t iv) { - return (unsigned long)key; + return (unsigned long)key; } static bool -int_compare_function (const void *key1, const void *key2) +int_compare_function(const void *key1, const void *key2) { - return (unsigned long)key1 == (unsigned long)key2; + return (unsigned long)key1 == (unsigned long)key2; } #endif @@ -267,216 +291,236 @@ int_compare_function (const void *key1, const void *key2) * Main initialization function, init multi_context object. */ void -multi_init (struct multi_context *m, struct context *t, bool tcp_mode, int thread_mode) -{ - int dev = DEV_TYPE_UNDEF; - - msg (D_MULTI_LOW, "MULTI: multi_init called, r=%d v=%d", - t->options.real_hash_size, - t->options.virtual_hash_size); - - /* - * Get tun/tap/null device type - */ - dev = dev_type_enum (t->options.dev, t->options.dev_type); - - /* - * Init our multi_context object. - */ - CLEAR (*m); - - m->thread_mode = thread_mode; - - /* - * Real address hash table (source port number is - * considered to be part of the address). Used - * to determine which client sent an incoming packet - * which is seen on the TCP/UDP socket. - */ - m->hash = hash_init (t->options.real_hash_size, - get_random (), - mroute_addr_hash_function, - mroute_addr_compare_function); - - /* - * Virtual address hash table. Used to determine - * which client to route a packet to. - */ - m->vhash = hash_init (t->options.virtual_hash_size, - get_random (), - mroute_addr_hash_function, - mroute_addr_compare_function); - - /* - * This hash table is a clone of m->hash but with a - * bucket size of one so that it can be used - * for fast iteration through the list. - */ - m->iter = hash_init (1, - get_random (), - mroute_addr_hash_function, - mroute_addr_compare_function); +multi_init(struct multi_context *m, struct context *t, bool tcp_mode, int thread_mode) +{ + int dev = DEV_TYPE_UNDEF; + + msg(D_MULTI_LOW, "MULTI: multi_init called, r=%d v=%d", + t->options.real_hash_size, + t->options.virtual_hash_size); + + /* + * Get tun/tap/null device type + */ + dev = dev_type_enum(t->options.dev, t->options.dev_type); + + /* + * Init our multi_context object. + */ + CLEAR(*m); + + m->thread_mode = thread_mode; + + /* + * Real address hash table (source port number is + * considered to be part of the address). Used + * to determine which client sent an incoming packet + * which is seen on the TCP/UDP socket. + */ + m->hash = hash_init(t->options.real_hash_size, + get_random(), + mroute_addr_hash_function, + mroute_addr_compare_function); + + /* + * Virtual address hash table. Used to determine + * which client to route a packet to. + */ + m->vhash = hash_init(t->options.virtual_hash_size, + get_random(), + mroute_addr_hash_function, + mroute_addr_compare_function); + + /* + * This hash table is a clone of m->hash but with a + * bucket size of one so that it can be used + * for fast iteration through the list. + */ + m->iter = hash_init(1, + get_random(), + mroute_addr_hash_function, + mroute_addr_compare_function); #ifdef MANAGEMENT_DEF_AUTH - m->cid_hash = hash_init (t->options.real_hash_size, - 0, - cid_hash_function, - cid_compare_function); + m->cid_hash = hash_init(t->options.real_hash_size, + 0, + cid_hash_function, + cid_compare_function); #endif #ifdef ENABLE_ASYNC_PUSH - /* - * Mapping between inotify watch descriptors and - * multi_instances. - */ - m->inotify_watchers = hash_init (t->options.real_hash_size, - get_random(), - int_hash_function, - int_compare_function); + /* + * Mapping between inotify watch descriptors and + * multi_instances. + */ + m->inotify_watchers = hash_init(t->options.real_hash_size, + get_random(), + int_hash_function, + int_compare_function); #endif - /* - * This is our scheduler, for time-based wakeup - * events. - */ - m->schedule = schedule_init (); - - /* - * Limit frequency of incoming connections to control - * DoS. - */ - m->new_connection_limiter = frequency_limit_init (t->options.cf_max, - t->options.cf_per); - - /* - * Allocate broadcast/multicast buffer list - */ - m->mbuf = mbuf_init (t->options.n_bcast_buf); - - /* - * Different status file format options are available - */ - m->status_file_version = t->options.status_file_version; - - /* - * Possibly allocate an ifconfig pool, do it - * differently based on whether a tun or tap style - * tunnel. - */ - if (t->options.ifconfig_pool_defined) - { - int pool_type = IFCONFIG_POOL_INDIV; - - if ( dev == DEV_TYPE_TUN && t->options.topology == TOP_NET30 ) - pool_type = IFCONFIG_POOL_30NET; - - m->ifconfig_pool = ifconfig_pool_init (pool_type, - t->options.ifconfig_pool_start, - t->options.ifconfig_pool_end, - t->options.duplicate_cn, - t->options.ifconfig_ipv6_pool_defined, - t->options.ifconfig_ipv6_pool_base, - t->options.ifconfig_ipv6_pool_netbits ); - - /* reload pool data from file */ - if (t->c1.ifconfig_pool_persist) - ifconfig_pool_read (t->c1.ifconfig_pool_persist, m->ifconfig_pool); - } - - /* - * Help us keep track of routing table. - */ - m->route_helper = mroute_helper_init (MULTI_CACHE_ROUTE_TTL); - - /* - * Initialize route and instance reaper. - */ - m->reaper = multi_reap_new (reap_buckets_per_pass (t->options.virtual_hash_size)); - - /* - * Get local ifconfig address - */ - CLEAR (m->local); - ASSERT (t->c1.tuntap); - mroute_extract_in_addr_t (&m->local, t->c1.tuntap->local); - - /* - * Per-client limits - */ - m->max_clients = t->options.max_clients; - - m->instances = calloc(m->max_clients, sizeof(struct multi_instance*)); - - /* - * Initialize multi-socket TCP I/O wait object - */ - if (tcp_mode) - m->mtcp = multi_tcp_init (t->options.max_clients, &m->max_clients); - m->tcp_queue_limit = t->options.tcp_queue_limit; - - /* - * Allow client <-> client communication, without going through - * tun/tap interface and network stack? - */ - m->enable_c2c = t->options.enable_c2c; - - /* initialize stale routes check timer */ - if (t->options.stale_routes_check_interval > 0) - { - msg (M_INFO, "Initializing stale route check timer to run every %i seconds and to removing routes with activity timeout older than %i seconds", - t->options.stale_routes_check_interval, t->options.stale_routes_ageing_time); - event_timeout_init (&m->stale_routes_check_et, t->options.stale_routes_check_interval, 0); - } - - m->deferred_shutdown_signal.signal_received = 0; + /* + * This is our scheduler, for time-based wakeup + * events. + */ + m->schedule = schedule_init(); + + /* + * Limit frequency of incoming connections to control + * DoS. + */ + m->new_connection_limiter = frequency_limit_init(t->options.cf_max, + t->options.cf_per); + + /* + * Allocate broadcast/multicast buffer list + */ + m->mbuf = mbuf_init(t->options.n_bcast_buf); + + /* + * Different status file format options are available + */ + m->status_file_version = t->options.status_file_version; + + /* + * Possibly allocate an ifconfig pool, do it + * differently based on whether a tun or tap style + * tunnel. + */ + if (t->options.ifconfig_pool_defined) + { + int pool_type = IFCONFIG_POOL_INDIV; + + if (dev == DEV_TYPE_TUN && t->options.topology == TOP_NET30) + { + pool_type = IFCONFIG_POOL_30NET; + } + + m->ifconfig_pool = ifconfig_pool_init(pool_type, + t->options.ifconfig_pool_start, + t->options.ifconfig_pool_end, + t->options.duplicate_cn, + t->options.ifconfig_ipv6_pool_defined, + t->options.ifconfig_ipv6_pool_base, + t->options.ifconfig_ipv6_pool_netbits ); + + /* reload pool data from file */ + if (t->c1.ifconfig_pool_persist) + { + ifconfig_pool_read(t->c1.ifconfig_pool_persist, m->ifconfig_pool); + } + } + + /* + * Help us keep track of routing table. + */ + m->route_helper = mroute_helper_init(MULTI_CACHE_ROUTE_TTL); + + /* + * Initialize route and instance reaper. + */ + m->reaper = multi_reap_new(reap_buckets_per_pass(t->options.virtual_hash_size)); + + /* + * Get local ifconfig address + */ + CLEAR(m->local); + ASSERT(t->c1.tuntap); + mroute_extract_in_addr_t(&m->local, t->c1.tuntap->local); + + /* + * Per-client limits + */ + m->max_clients = t->options.max_clients; + + m->instances = calloc(m->max_clients, sizeof(struct multi_instance *)); + + /* + * Initialize multi-socket TCP I/O wait object + */ + if (tcp_mode) + { + m->mtcp = multi_tcp_init(t->options.max_clients, &m->max_clients); + } + m->tcp_queue_limit = t->options.tcp_queue_limit; + + /* + * Allow client <-> client communication, without going through + * tun/tap interface and network stack? + */ + m->enable_c2c = t->options.enable_c2c; + + /* initialize stale routes check timer */ + if (t->options.stale_routes_check_interval > 0) + { + msg(M_INFO, "Initializing stale route check timer to run every %i seconds and to removing routes with activity timeout older than %i seconds", + t->options.stale_routes_check_interval, t->options.stale_routes_ageing_time); + event_timeout_init(&m->stale_routes_check_et, t->options.stale_routes_check_interval, 0); + } + + m->deferred_shutdown_signal.signal_received = 0; } const char * -multi_instance_string (const struct multi_instance *mi, bool null, struct gc_arena *gc) +multi_instance_string(const struct multi_instance *mi, bool null, struct gc_arena *gc) { - if (mi) + if (mi) { - struct buffer out = alloc_buf_gc (MULTI_PREFIX_MAX_LENGTH, gc); - const char *cn = tls_common_name (mi->context.c2.tls_multi, true); + struct buffer out = alloc_buf_gc(MULTI_PREFIX_MAX_LENGTH, gc); + const char *cn = tls_common_name(mi->context.c2.tls_multi, true); - if (cn) - buf_printf (&out, "%s/", cn); - buf_printf (&out, "%s", mroute_addr_print (&mi->real, gc)); - return BSTR (&out); + if (cn) + { + buf_printf(&out, "%s/", cn); + } + buf_printf(&out, "%s", mroute_addr_print(&mi->real, gc)); + return BSTR(&out); + } + else if (null) + { + return NULL; + } + else + { + return "UNDEF"; } - else if (null) - return NULL; - else - return "UNDEF"; } void -generate_prefix (struct multi_instance *mi) +generate_prefix(struct multi_instance *mi) { - struct gc_arena gc = gc_new(); - const char *prefix = multi_instance_string (mi, true, &gc); - if (prefix) - strncpynt(mi->msg_prefix, prefix, sizeof(mi->msg_prefix)); - else - mi->msg_prefix[0] = '\0'; - set_prefix (mi); - gc_free(&gc); + struct gc_arena gc = gc_new(); + const char *prefix = multi_instance_string(mi, true, &gc); + if (prefix) + { + strncpynt(mi->msg_prefix, prefix, sizeof(mi->msg_prefix)); + } + else + { + mi->msg_prefix[0] = '\0'; + } + set_prefix(mi); + gc_free(&gc); } void -ungenerate_prefix (struct multi_instance *mi) +ungenerate_prefix(struct multi_instance *mi) { - mi->msg_prefix[0] = '\0'; - set_prefix (mi); + mi->msg_prefix[0] = '\0'; + set_prefix(mi); } static const char * -mi_prefix (const struct multi_instance *mi) +mi_prefix(const struct multi_instance *mi) { - if (mi && mi->msg_prefix[0]) - return mi->msg_prefix; - else - return "UNDEF_I"; + if (mi && mi->msg_prefix[0]) + { + return mi->msg_prefix; + } + else + { + return "UNDEF_I"; + } } /* @@ -485,219 +529,233 @@ mi_prefix (const struct multi_instance *mi) * CIDR netlengths. */ static void -multi_del_iroutes (struct multi_context *m, - struct multi_instance *mi) +multi_del_iroutes(struct multi_context *m, + struct multi_instance *mi) { - const struct iroute *ir; - const struct iroute_ipv6 *ir6; - if (TUNNEL_TYPE (mi->context.c1.tuntap) == DEV_TYPE_TUN) + const struct iroute *ir; + const struct iroute_ipv6 *ir6; + if (TUNNEL_TYPE(mi->context.c1.tuntap) == DEV_TYPE_TUN) { - for (ir = mi->context.options.iroutes; ir != NULL; ir = ir->next) - mroute_helper_del_iroute46 (m->route_helper, ir->netbits); + for (ir = mi->context.options.iroutes; ir != NULL; ir = ir->next) + mroute_helper_del_iroute46(m->route_helper, ir->netbits); - for ( ir6 = mi->context.options.iroutes_ipv6; ir6 != NULL; ir6 = ir6->next ) - mroute_helper_del_iroute46 (m->route_helper, ir6->netbits); + for (ir6 = mi->context.options.iroutes_ipv6; ir6 != NULL; ir6 = ir6->next) + mroute_helper_del_iroute46(m->route_helper, ir6->netbits); } } static void -setenv_stats (struct context *c) +setenv_stats(struct context *c) { - setenv_counter (c->c2.es, "bytes_received", c->c2.link_read_bytes); - setenv_counter (c->c2.es, "bytes_sent", c->c2.link_write_bytes); + setenv_counter(c->c2.es, "bytes_received", c->c2.link_read_bytes); + setenv_counter(c->c2.es, "bytes_sent", c->c2.link_write_bytes); } static void -multi_client_disconnect_setenv (struct multi_context *m, - struct multi_instance *mi) +multi_client_disconnect_setenv(struct multi_context *m, + struct multi_instance *mi) { - /* setenv client real IP address */ - setenv_trusted (mi->context.c2.es, get_link_socket_info (&mi->context)); + /* setenv client real IP address */ + setenv_trusted(mi->context.c2.es, get_link_socket_info(&mi->context)); - /* setenv stats */ - setenv_stats (&mi->context); + /* setenv stats */ + setenv_stats(&mi->context); - /* setenv connection duration */ - { - const unsigned int duration = (unsigned int) now - mi->created; - setenv_unsigned (mi->context.c2.es, "time_duration", duration); - } + /* setenv connection duration */ + { + const unsigned int duration = (unsigned int) now - mi->created; + setenv_unsigned(mi->context.c2.es, "time_duration", duration); + } } static void -multi_client_disconnect_script (struct multi_context *m, - struct multi_instance *mi) -{ - if ((mi->context.c2.context_auth == CAS_SUCCEEDED && mi->connection_established_flag) - || mi->context.c2.context_auth == CAS_PARTIAL) - { - multi_client_disconnect_setenv (m, mi); - - if (plugin_defined (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_DISCONNECT)) - { - if (plugin_call (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_DISCONNECT, NULL, NULL, mi->context.c2.es) != OPENVPN_PLUGIN_FUNC_SUCCESS) - msg (M_WARN, "WARNING: client-disconnect plugin call failed"); - } - - if (mi->context.options.client_disconnect_script) - { - struct argv argv = argv_new (); - setenv_str (mi->context.c2.es, "script_type", "client-disconnect"); - argv_parse_cmd (&argv, mi->context.options.client_disconnect_script); - openvpn_run_script (&argv, mi->context.c2.es, 0, "--client-disconnect"); - argv_reset (&argv); - } +multi_client_disconnect_script(struct multi_context *m, + struct multi_instance *mi) +{ + if ((mi->context.c2.context_auth == CAS_SUCCEEDED && mi->connection_established_flag) + || mi->context.c2.context_auth == CAS_PARTIAL) + { + multi_client_disconnect_setenv(m, mi); + + if (plugin_defined(mi->context.plugins, OPENVPN_PLUGIN_CLIENT_DISCONNECT)) + { + if (plugin_call(mi->context.plugins, OPENVPN_PLUGIN_CLIENT_DISCONNECT, NULL, NULL, mi->context.c2.es) != OPENVPN_PLUGIN_FUNC_SUCCESS) + { + msg(M_WARN, "WARNING: client-disconnect plugin call failed"); + } + } + + if (mi->context.options.client_disconnect_script) + { + struct argv argv = argv_new(); + setenv_str(mi->context.c2.es, "script_type", "client-disconnect"); + argv_parse_cmd(&argv, mi->context.options.client_disconnect_script); + openvpn_run_script(&argv, mi->context.c2.es, 0, "--client-disconnect"); + argv_reset(&argv); + } #ifdef MANAGEMENT_DEF_AUTH - if (management) - management_notify_client_close (management, &mi->context.c2.mda_context, mi->context.c2.es); + if (management) + { + management_notify_client_close(management, &mi->context.c2.mda_context, mi->context.c2.es); + } #endif } } void -multi_close_instance (struct multi_context *m, - struct multi_instance *mi, - bool shutdown) -{ - perf_push (PERF_MULTI_CLOSE_INSTANCE); - - ASSERT (!mi->halt); - mi->halt = true; - - dmsg (D_MULTI_DEBUG, "MULTI: multi_close_instance called"); - - /* adjust current client connection count */ - m->n_clients += mi->n_clients_delta; - update_mstat_n_clients(m->n_clients); - mi->n_clients_delta = 0; - - /* prevent dangling pointers */ - if (m->pending == mi) - multi_set_pending (m, NULL); - if (m->earliest_wakeup == mi) - m->earliest_wakeup = NULL; - - if (!shutdown) - { - if (mi->did_real_hash) - { - ASSERT (hash_remove (m->hash, &mi->real)); - } - if (mi->did_iter) - { - ASSERT (hash_remove (m->iter, &mi->real)); - } +multi_close_instance(struct multi_context *m, + struct multi_instance *mi, + bool shutdown) +{ + perf_push(PERF_MULTI_CLOSE_INSTANCE); + + ASSERT(!mi->halt); + mi->halt = true; + + dmsg(D_MULTI_DEBUG, "MULTI: multi_close_instance called"); + + /* adjust current client connection count */ + m->n_clients += mi->n_clients_delta; + update_mstat_n_clients(m->n_clients); + mi->n_clients_delta = 0; + + /* prevent dangling pointers */ + if (m->pending == mi) + { + multi_set_pending(m, NULL); + } + if (m->earliest_wakeup == mi) + { + m->earliest_wakeup = NULL; + } + + if (!shutdown) + { + if (mi->did_real_hash) + { + ASSERT(hash_remove(m->hash, &mi->real)); + } + if (mi->did_iter) + { + ASSERT(hash_remove(m->iter, &mi->real)); + } #ifdef MANAGEMENT_DEF_AUTH - if (mi->did_cid_hash) - { - ASSERT (hash_remove (m->cid_hash, &mi->context.c2.mda_context.cid)); - } + if (mi->did_cid_hash) + { + ASSERT(hash_remove(m->cid_hash, &mi->context.c2.mda_context.cid)); + } #endif #ifdef ENABLE_ASYNC_PUSH - if (mi->inotify_watch != -1) - { - hash_remove(m->inotify_watchers, (void*) (unsigned long)mi->inotify_watch); - mi->inotify_watch = -1; - } + if (mi->inotify_watch != -1) + { + hash_remove(m->inotify_watchers, (void *) (unsigned long)mi->inotify_watch); + mi->inotify_watch = -1; + } #endif - if (mi->context.c2.tls_multi->peer_id != MAX_PEER_ID) - m->instances[mi->context.c2.tls_multi->peer_id] = NULL; + if (mi->context.c2.tls_multi->peer_id != MAX_PEER_ID) + { + m->instances[mi->context.c2.tls_multi->peer_id] = NULL; + } - schedule_remove_entry (m->schedule, (struct schedule_entry *) mi); + schedule_remove_entry(m->schedule, (struct schedule_entry *) mi); - ifconfig_pool_release (m->ifconfig_pool, mi->vaddr_handle, false); - - if (mi->did_iroutes) + ifconfig_pool_release(m->ifconfig_pool, mi->vaddr_handle, false); + + if (mi->did_iroutes) { - multi_del_iroutes (m, mi); - mi->did_iroutes = false; + multi_del_iroutes(m, mi); + mi->did_iroutes = false; } - if (m->mtcp) - multi_tcp_dereference_instance (m->mtcp, mi); + if (m->mtcp) + { + multi_tcp_dereference_instance(m->mtcp, mi); + } - mbuf_dereference_instance (m->mbuf, mi); + mbuf_dereference_instance(m->mbuf, mi); } #ifdef MANAGEMENT_DEF_AUTH - set_cc_config (mi, NULL); + set_cc_config(mi, NULL); #endif - multi_client_disconnect_script (m, mi); + multi_client_disconnect_script(m, mi); - if (mi->did_open_context) - close_context (&mi->context, SIGTERM, CC_GC_FREE); + if (mi->did_open_context) + { + close_context(&mi->context, SIGTERM, CC_GC_FREE); + } - multi_tcp_instance_specific_free (mi); + multi_tcp_instance_specific_free(mi); - ungenerate_prefix (mi); + ungenerate_prefix(mi); - /* - * Don't actually delete the instance memory allocation yet, - * because virtual routes may still point to it. Let the - * vhash reaper deal with it. - */ - multi_instance_dec_refcount (mi); + /* + * Don't actually delete the instance memory allocation yet, + * because virtual routes may still point to it. Let the + * vhash reaper deal with it. + */ + multi_instance_dec_refcount(mi); - perf_pop (); + perf_pop(); } /* * Called on shutdown or restart. */ void -multi_uninit (struct multi_context *m) +multi_uninit(struct multi_context *m) { - if (m->thread_mode & MC_WORK_THREAD) + if (m->thread_mode & MC_WORK_THREAD) { - multi_top_free (m); - m->thread_mode = MC_UNDEF; + multi_top_free(m); + m->thread_mode = MC_UNDEF; } - else if (m->thread_mode) + else if (m->thread_mode) { - if (m->hash) - { - struct hash_iterator hi; - struct hash_element *he; - - hash_iterator_init (m->iter, &hi); - while ((he = hash_iterator_next (&hi))) - { - struct multi_instance *mi = (struct multi_instance *) he->value; - mi->did_iter = false; - multi_close_instance (m, mi, true); - } - hash_iterator_free (&hi); - - multi_reap_all (m); - - hash_free (m->hash); - hash_free (m->vhash); - hash_free (m->iter); + if (m->hash) + { + struct hash_iterator hi; + struct hash_element *he; + + hash_iterator_init(m->iter, &hi); + while ((he = hash_iterator_next(&hi))) + { + struct multi_instance *mi = (struct multi_instance *) he->value; + mi->did_iter = false; + multi_close_instance(m, mi, true); + } + hash_iterator_free(&hi); + + multi_reap_all(m); + + hash_free(m->hash); + hash_free(m->vhash); + hash_free(m->iter); #ifdef MANAGEMENT_DEF_AUTH - hash_free (m->cid_hash); + hash_free(m->cid_hash); #endif - m->hash = NULL; + m->hash = NULL; - free(m->instances); + free(m->instances); #ifdef ENABLE_ASYNC_PUSH - hash_free (m->inotify_watchers); - m->inotify_watchers = NULL; + hash_free(m->inotify_watchers); + m->inotify_watchers = NULL; #endif - schedule_free (m->schedule); - mbuf_free (m->mbuf); - ifconfig_pool_free (m->ifconfig_pool); - frequency_limit_free (m->new_connection_limiter); - multi_reap_free (m->reaper); - mroute_helper_free (m->route_helper); - multi_tcp_free (m->mtcp); - m->thread_mode = MC_UNDEF; - } + schedule_free(m->schedule); + mbuf_free(m->mbuf); + ifconfig_pool_free(m->ifconfig_pool); + frequency_limit_free(m->new_connection_limiter); + multi_reap_free(m->reaper); + mroute_helper_free(m->route_helper); + multi_tcp_free(m->mtcp); + m->thread_mode = MC_UNDEF; + } } } @@ -705,86 +763,90 @@ multi_uninit (struct multi_context *m) * Create a client instance object for a newly connected client. */ struct multi_instance * -multi_create_instance (struct multi_context *m, const struct mroute_addr *real) +multi_create_instance(struct multi_context *m, const struct mroute_addr *real) { - struct gc_arena gc = gc_new (); - struct multi_instance *mi; + struct gc_arena gc = gc_new(); + struct multi_instance *mi; - perf_push (PERF_MULTI_CREATE_INSTANCE); + perf_push(PERF_MULTI_CREATE_INSTANCE); - msg (D_MULTI_MEDIUM, "MULTI: multi_create_instance called"); + msg(D_MULTI_MEDIUM, "MULTI: multi_create_instance called"); - ALLOC_OBJ_CLEAR (mi, struct multi_instance); + ALLOC_OBJ_CLEAR(mi, struct multi_instance); - mi->gc = gc_new (); - multi_instance_inc_refcount (mi); - mi->vaddr_handle = -1; - mi->created = now; - mroute_addr_init (&mi->real); + mi->gc = gc_new(); + multi_instance_inc_refcount(mi); + mi->vaddr_handle = -1; + mi->created = now; + mroute_addr_init(&mi->real); - if (real) + if (real) { - mi->real = *real; - generate_prefix (mi); + mi->real = *real; + generate_prefix(mi); } - mi->did_open_context = true; - inherit_context_child (&mi->context, &m->top); - if (IS_SIG (&mi->context)) - goto err; + mi->did_open_context = true; + inherit_context_child(&mi->context, &m->top); + if (IS_SIG(&mi->context)) + { + goto err; + } - mi->context.c2.context_auth = CAS_PENDING; + mi->context.c2.context_auth = CAS_PENDING; - if (hash_n_elements (m->hash) >= m->max_clients) + if (hash_n_elements(m->hash) >= m->max_clients) { - msg (D_MULTI_ERRORS, "MULTI: new incoming connection would exceed maximum number of clients (%d)", m->max_clients); - goto err; + msg(D_MULTI_ERRORS, "MULTI: new incoming connection would exceed maximum number of clients (%d)", m->max_clients); + goto err; } - if (!real) /* TCP mode? */ + if (!real) /* TCP mode? */ { - if (!multi_tcp_instance_specific_init (m, mi)) - goto err; - generate_prefix (mi); + if (!multi_tcp_instance_specific_init(m, mi)) + { + goto err; + } + generate_prefix(mi); } - if (!hash_add (m->iter, &mi->real, mi, false)) + if (!hash_add(m->iter, &mi->real, mi, false)) { - msg (D_MULTI_LOW, "MULTI: unable to add real address [%s] to iterator hash table", - mroute_addr_print (&mi->real, &gc)); - goto err; + msg(D_MULTI_LOW, "MULTI: unable to add real address [%s] to iterator hash table", + mroute_addr_print(&mi->real, &gc)); + goto err; } - mi->did_iter = true; + mi->did_iter = true; #ifdef MANAGEMENT_DEF_AUTH - do { - mi->context.c2.mda_context.cid = m->cid_counter++; - } while (!hash_add (m->cid_hash, &mi->context.c2.mda_context.cid, mi, false)); - mi->did_cid_hash = true; + do { + mi->context.c2.mda_context.cid = m->cid_counter++; + } while (!hash_add(m->cid_hash, &mi->context.c2.mda_context.cid, mi, false)); + mi->did_cid_hash = true; #endif - mi->context.c2.push_reply_deferred = true; + mi->context.c2.push_reply_deferred = true; #ifdef ENABLE_ASYNC_PUSH - mi->context.c2.push_request_received = false; - mi->inotify_watch = -1; + mi->context.c2.push_request_received = false; + mi->inotify_watch = -1; #endif - if (!multi_process_post (m, mi, MPP_PRE_SELECT)) + if (!multi_process_post(m, mi, MPP_PRE_SELECT)) { - msg (D_MULTI_ERRORS, "MULTI: signal occurred during client instance initialization"); - goto err; + msg(D_MULTI_ERRORS, "MULTI: signal occurred during client instance initialization"); + goto err; } - perf_pop (); - gc_free (&gc); - return mi; + perf_pop(); + gc_free(&gc); + return mi; - err: - multi_close_instance (m, mi, false); - perf_pop (); - gc_free (&gc); - return NULL; +err: + multi_close_instance(m, mi, false); + perf_pop(); + gc_free(&gc); + return NULL; } /* @@ -793,194 +855,202 @@ multi_create_instance (struct multi_context *m, const struct mroute_addr *real) * If status file is NULL, write to syslog. */ void -multi_print_status (struct multi_context *m, struct status_output *so, const int version) -{ - if (m->hash) - { - struct gc_arena gc_top = gc_new (); - struct hash_iterator hi; - const struct hash_element *he; - - status_reset (so); - - if (version == 1) /* WAS: m->status_file_version */ - { - /* - * Status file version 1 - */ - status_printf (so, "OpenVPN CLIENT LIST"); - status_printf (so, "Updated,%s", time_string (0, 0, false, &gc_top)); - status_printf (so, "Common Name,Real Address,Bytes Received,Bytes Sent,Connected Since"); - hash_iterator_init (m->hash, &hi); - while ((he = hash_iterator_next (&hi))) - { - struct gc_arena gc = gc_new (); - const struct multi_instance *mi = (struct multi_instance *) he->value; - - if (!mi->halt) - { - status_printf (so, "%s,%s," counter_format "," counter_format ",%s", - tls_common_name (mi->context.c2.tls_multi, false), - mroute_addr_print (&mi->real, &gc), - mi->context.c2.link_read_bytes, - mi->context.c2.link_write_bytes, - time_string (mi->created, 0, false, &gc)); - } - gc_free (&gc); - } - hash_iterator_free (&hi); - - status_printf (so, "ROUTING TABLE"); - status_printf (so, "Virtual Address,Common Name,Real Address,Last Ref"); - hash_iterator_init (m->vhash, &hi); - while ((he = hash_iterator_next (&hi))) - { - struct gc_arena gc = gc_new (); - const struct multi_route *route = (struct multi_route *) he->value; - - if (multi_route_defined (m, route)) - { - const struct multi_instance *mi = route->instance; - const struct mroute_addr *ma = &route->addr; - char flags[2] = {0, 0}; - - if (route->flags & MULTI_ROUTE_CACHE) - flags[0] = 'C'; - status_printf (so, "%s%s,%s,%s,%s", - mroute_addr_print (ma, &gc), - flags, - tls_common_name (mi->context.c2.tls_multi, false), - mroute_addr_print (&mi->real, &gc), - time_string (route->last_reference, 0, false, &gc)); - } - gc_free (&gc); - } - hash_iterator_free (&hi); - - status_printf (so, "GLOBAL STATS"); - if (m->mbuf) - status_printf (so, "Max bcast/mcast queue length,%d", - mbuf_maximum_queued (m->mbuf)); - - status_printf (so, "END"); - } - else if (version == 2 || version == 3) - { - const char sep = (version == 3) ? '\t' : ','; - - /* - * Status file version 2 and 3 - */ - status_printf (so, "TITLE%c%s", sep, title_string); - status_printf (so, "TIME%c%s%c%u", sep, time_string (now, 0, false, &gc_top), sep, (unsigned int)now); - status_printf (so, "HEADER%cCLIENT_LIST%cCommon Name%cReal Address%cVirtual Address%cVirtual IPv6 Address%cBytes Received%cBytes Sent%cConnected Since%cConnected Since (time_t)%cUsername%cClient ID%cPeer ID", - sep, sep, sep, sep, sep, sep, sep, sep, sep, sep, sep, sep); - hash_iterator_init (m->hash, &hi); - while ((he = hash_iterator_next (&hi))) - { - struct gc_arena gc = gc_new (); - const struct multi_instance *mi = (struct multi_instance *) he->value; - - if (!mi->halt) - { - status_printf (so, "CLIENT_LIST%c%s%c%s%c%s%c%s%c" counter_format "%c" counter_format "%c%s%c%u%c%s%c" +multi_print_status(struct multi_context *m, struct status_output *so, const int version) +{ + if (m->hash) + { + struct gc_arena gc_top = gc_new(); + struct hash_iterator hi; + const struct hash_element *he; + + status_reset(so); + + if (version == 1) /* WAS: m->status_file_version */ + { + /* + * Status file version 1 + */ + status_printf(so, "OpenVPN CLIENT LIST"); + status_printf(so, "Updated,%s", time_string(0, 0, false, &gc_top)); + status_printf(so, "Common Name,Real Address,Bytes Received,Bytes Sent,Connected Since"); + hash_iterator_init(m->hash, &hi); + while ((he = hash_iterator_next(&hi))) + { + struct gc_arena gc = gc_new(); + const struct multi_instance *mi = (struct multi_instance *) he->value; + + if (!mi->halt) + { + status_printf(so, "%s,%s," counter_format "," counter_format ",%s", + tls_common_name(mi->context.c2.tls_multi, false), + mroute_addr_print(&mi->real, &gc), + mi->context.c2.link_read_bytes, + mi->context.c2.link_write_bytes, + time_string(mi->created, 0, false, &gc)); + } + gc_free(&gc); + } + hash_iterator_free(&hi); + + status_printf(so, "ROUTING TABLE"); + status_printf(so, "Virtual Address,Common Name,Real Address,Last Ref"); + hash_iterator_init(m->vhash, &hi); + while ((he = hash_iterator_next(&hi))) + { + struct gc_arena gc = gc_new(); + const struct multi_route *route = (struct multi_route *) he->value; + + if (multi_route_defined(m, route)) + { + const struct multi_instance *mi = route->instance; + const struct mroute_addr *ma = &route->addr; + char flags[2] = {0, 0}; + + if (route->flags & MULTI_ROUTE_CACHE) + { + flags[0] = 'C'; + } + status_printf(so, "%s%s,%s,%s,%s", + mroute_addr_print(ma, &gc), + flags, + tls_common_name(mi->context.c2.tls_multi, false), + mroute_addr_print(&mi->real, &gc), + time_string(route->last_reference, 0, false, &gc)); + } + gc_free(&gc); + } + hash_iterator_free(&hi); + + status_printf(so, "GLOBAL STATS"); + if (m->mbuf) + { + status_printf(so, "Max bcast/mcast queue length,%d", + mbuf_maximum_queued(m->mbuf)); + } + + status_printf(so, "END"); + } + else if (version == 2 || version == 3) + { + const char sep = (version == 3) ? '\t' : ','; + + /* + * Status file version 2 and 3 + */ + status_printf(so, "TITLE%c%s", sep, title_string); + status_printf(so, "TIME%c%s%c%u", sep, time_string(now, 0, false, &gc_top), sep, (unsigned int)now); + status_printf(so, "HEADER%cCLIENT_LIST%cCommon Name%cReal Address%cVirtual Address%cVirtual IPv6 Address%cBytes Received%cBytes Sent%cConnected Since%cConnected Since (time_t)%cUsername%cClient ID%cPeer ID", + sep, sep, sep, sep, sep, sep, sep, sep, sep, sep, sep, sep); + hash_iterator_init(m->hash, &hi); + while ((he = hash_iterator_next(&hi))) + { + struct gc_arena gc = gc_new(); + const struct multi_instance *mi = (struct multi_instance *) he->value; + + if (!mi->halt) + { + status_printf(so, "CLIENT_LIST%c%s%c%s%c%s%c%s%c" counter_format "%c" counter_format "%c%s%c%u%c%s%c" #ifdef MANAGEMENT_DEF_AUTH - "%lu" + "%lu" #else - "" + "" #endif - "%c%"PRIu32, - sep, tls_common_name (mi->context.c2.tls_multi, false), - sep, mroute_addr_print (&mi->real, &gc), - sep, print_in_addr_t (mi->reporting_addr, IA_EMPTY_IF_UNDEF, &gc), - sep, print_in6_addr (mi->reporting_addr_ipv6, IA_EMPTY_IF_UNDEF, &gc), - sep, mi->context.c2.link_read_bytes, - sep, mi->context.c2.link_write_bytes, - sep, time_string (mi->created, 0, false, &gc), - sep, (unsigned int)mi->created, - sep, tls_username (mi->context.c2.tls_multi, false), + "%c%" PRIu32, + sep, tls_common_name(mi->context.c2.tls_multi, false), + sep, mroute_addr_print(&mi->real, &gc), + sep, print_in_addr_t(mi->reporting_addr, IA_EMPTY_IF_UNDEF, &gc), + sep, print_in6_addr(mi->reporting_addr_ipv6, IA_EMPTY_IF_UNDEF, &gc), + sep, mi->context.c2.link_read_bytes, + sep, mi->context.c2.link_write_bytes, + sep, time_string(mi->created, 0, false, &gc), + sep, (unsigned int)mi->created, + sep, tls_username(mi->context.c2.tls_multi, false), #ifdef MANAGEMENT_DEF_AUTH - sep, mi->context.c2.mda_context.cid, + sep, mi->context.c2.mda_context.cid, #else - sep, + sep, #endif - sep, mi->context.c2.tls_multi ? mi->context.c2.tls_multi->peer_id : UINT32_MAX); - } - gc_free (&gc); - } - hash_iterator_free (&hi); - - status_printf (so, "HEADER%cROUTING_TABLE%cVirtual Address%cCommon Name%cReal Address%cLast Ref%cLast Ref (time_t)", - sep, sep, sep, sep, sep, sep); - hash_iterator_init (m->vhash, &hi); - while ((he = hash_iterator_next (&hi))) - { - struct gc_arena gc = gc_new (); - const struct multi_route *route = (struct multi_route *) he->value; - - if (multi_route_defined (m, route)) - { - const struct multi_instance *mi = route->instance; - const struct mroute_addr *ma = &route->addr; - char flags[2] = {0, 0}; - - if (route->flags & MULTI_ROUTE_CACHE) - flags[0] = 'C'; - status_printf (so, "ROUTING_TABLE%c%s%s%c%s%c%s%c%s%c%u", - sep, mroute_addr_print (ma, &gc), flags, - sep, tls_common_name (mi->context.c2.tls_multi, false), - sep, mroute_addr_print (&mi->real, &gc), - sep, time_string (route->last_reference, 0, false, &gc), - sep, (unsigned int)route->last_reference); - } - gc_free (&gc); - } - hash_iterator_free (&hi); - - if (m->mbuf) - status_printf (so, "GLOBAL_STATS%cMax bcast/mcast queue length%c%d", - sep, sep, mbuf_maximum_queued (m->mbuf)); - - status_printf (so, "END"); - } - else - { - status_printf (so, "ERROR: bad status format version number"); - } + sep, mi->context.c2.tls_multi ? mi->context.c2.tls_multi->peer_id : UINT32_MAX); + } + gc_free(&gc); + } + hash_iterator_free(&hi); + + status_printf(so, "HEADER%cROUTING_TABLE%cVirtual Address%cCommon Name%cReal Address%cLast Ref%cLast Ref (time_t)", + sep, sep, sep, sep, sep, sep); + hash_iterator_init(m->vhash, &hi); + while ((he = hash_iterator_next(&hi))) + { + struct gc_arena gc = gc_new(); + const struct multi_route *route = (struct multi_route *) he->value; + + if (multi_route_defined(m, route)) + { + const struct multi_instance *mi = route->instance; + const struct mroute_addr *ma = &route->addr; + char flags[2] = {0, 0}; + + if (route->flags & MULTI_ROUTE_CACHE) + { + flags[0] = 'C'; + } + status_printf(so, "ROUTING_TABLE%c%s%s%c%s%c%s%c%s%c%u", + sep, mroute_addr_print(ma, &gc), flags, + sep, tls_common_name(mi->context.c2.tls_multi, false), + sep, mroute_addr_print(&mi->real, &gc), + sep, time_string(route->last_reference, 0, false, &gc), + sep, (unsigned int)route->last_reference); + } + gc_free(&gc); + } + hash_iterator_free(&hi); + + if (m->mbuf) + { + status_printf(so, "GLOBAL_STATS%cMax bcast/mcast queue length%c%d", + sep, sep, mbuf_maximum_queued(m->mbuf)); + } + + status_printf(so, "END"); + } + else + { + status_printf(so, "ERROR: bad status format version number"); + } #ifdef PACKET_TRUNCATION_CHECK - { - status_printf (so, "HEADER,ERRORS,Common Name,TUN Read Trunc,TUN Write Trunc,Pre-encrypt Trunc,Post-decrypt Trunc"); - hash_iterator_init (m->hash, &hi); - while ((he = hash_iterator_next (&hi))) - { - struct gc_arena gc = gc_new (); - const struct multi_instance *mi = (struct multi_instance *) he->value; - - if (!mi->halt) - { - status_printf (so, "ERRORS,%s," counter_format "," counter_format "," counter_format "," counter_format, - tls_common_name (mi->context.c2.tls_multi, false), - m->top.c2.n_trunc_tun_read, - mi->context.c2.n_trunc_tun_write, - mi->context.c2.n_trunc_pre_encrypt, - mi->context.c2.n_trunc_post_decrypt); - } - gc_free (&gc); - } - hash_iterator_free (&hi); - } -#endif + { + status_printf(so, "HEADER,ERRORS,Common Name,TUN Read Trunc,TUN Write Trunc,Pre-encrypt Trunc,Post-decrypt Trunc"); + hash_iterator_init(m->hash, &hi); + while ((he = hash_iterator_next(&hi))) + { + struct gc_arena gc = gc_new(); + const struct multi_instance *mi = (struct multi_instance *) he->value; + + if (!mi->halt) + { + status_printf(so, "ERRORS,%s," counter_format "," counter_format "," counter_format "," counter_format, + tls_common_name(mi->context.c2.tls_multi, false), + m->top.c2.n_trunc_tun_read, + mi->context.c2.n_trunc_tun_write, + mi->context.c2.n_trunc_pre_encrypt, + mi->context.c2.n_trunc_post_decrypt); + } + gc_free(&gc); + } + hash_iterator_free(&hi); + } +#endif /* ifdef PACKET_TRUNCATION_CHECK */ - status_flush (so); - gc_free (&gc_top); + status_flush(so); + gc_free(&gc_top); } #ifdef ENABLE_ASYNC_PUSH - if (m->inotify_watchers) - { - msg (D_MULTI_DEBUG, "inotify watchers count: %d\n", hash_n_elements(m->inotify_watchers)); - } + if (m->inotify_watchers) + { + msg(D_MULTI_DEBUG, "inotify watchers count: %d\n", hash_n_elements(m->inotify_watchers)); + } #endif } @@ -993,229 +1063,243 @@ multi_print_status (struct multi_context *m, struct status_output *so, const int * or NULL if none. */ static struct multi_instance * -multi_learn_addr (struct multi_context *m, - struct multi_instance *mi, - const struct mroute_addr *addr, - const unsigned int flags) -{ - struct hash_element *he; - const uint32_t hv = hash_value (m->vhash, addr); - struct hash_bucket *bucket = hash_bucket (m->vhash, hv); - struct multi_route *oldroute = NULL; - struct multi_instance *owner = NULL; - - /* if route currently exists, get the instance which owns it */ - he = hash_lookup_fast (m->vhash, bucket, addr, hv); - if (he) - oldroute = (struct multi_route *) he->value; - if (oldroute && multi_route_defined (m, oldroute)) - owner = oldroute->instance; - - /* do we need to add address to hash table? */ - if ((!owner || owner != mi) - && mroute_learnable_address (addr) - && !mroute_addr_equal (addr, &m->local)) - { - struct gc_arena gc = gc_new (); - struct multi_route *newroute; - bool learn_succeeded = false; - - ALLOC_OBJ (newroute, struct multi_route); - newroute->addr = *addr; - newroute->instance = mi; - newroute->flags = flags; - newroute->last_reference = now; - newroute->cache_generation = 0; - - /* The cache is invalidated when cache_generation is incremented */ - if (flags & MULTI_ROUTE_CACHE) - newroute->cache_generation = m->route_helper->cache_generation; - - if (oldroute) /* route already exists? */ - { - if (route_quota_test (m, mi) && learn_address_script (m, mi, "update", &newroute->addr)) - { - learn_succeeded = true; - owner = mi; - multi_instance_inc_refcount (mi); - route_quota_inc (mi); - - /* delete old route */ - multi_route_del (oldroute); - - /* modify hash table entry, replacing old route */ - he->key = &newroute->addr; - he->value = newroute; - } - } - else - { - if (route_quota_test (m, mi) && learn_address_script (m, mi, "add", &newroute->addr)) - { - learn_succeeded = true; - owner = mi; - multi_instance_inc_refcount (mi); - route_quota_inc (mi); - - /* add new route */ - hash_add_fast (m->vhash, bucket, &newroute->addr, hv, newroute); - } - } - - msg (D_MULTI_LOW, "MULTI: Learn%s: %s -> %s", - learn_succeeded ? "" : " FAILED", - mroute_addr_print (&newroute->addr, &gc), - multi_instance_string (mi, false, &gc)); - - if (!learn_succeeded) - free (newroute); - - gc_free (&gc); - } - - return owner; +multi_learn_addr(struct multi_context *m, + struct multi_instance *mi, + const struct mroute_addr *addr, + const unsigned int flags) +{ + struct hash_element *he; + const uint32_t hv = hash_value(m->vhash, addr); + struct hash_bucket *bucket = hash_bucket(m->vhash, hv); + struct multi_route *oldroute = NULL; + struct multi_instance *owner = NULL; + + /* if route currently exists, get the instance which owns it */ + he = hash_lookup_fast(m->vhash, bucket, addr, hv); + if (he) + { + oldroute = (struct multi_route *) he->value; + } + if (oldroute && multi_route_defined(m, oldroute)) + { + owner = oldroute->instance; + } + + /* do we need to add address to hash table? */ + if ((!owner || owner != mi) + && mroute_learnable_address(addr) + && !mroute_addr_equal(addr, &m->local)) + { + struct gc_arena gc = gc_new(); + struct multi_route *newroute; + bool learn_succeeded = false; + + ALLOC_OBJ(newroute, struct multi_route); + newroute->addr = *addr; + newroute->instance = mi; + newroute->flags = flags; + newroute->last_reference = now; + newroute->cache_generation = 0; + + /* The cache is invalidated when cache_generation is incremented */ + if (flags & MULTI_ROUTE_CACHE) + { + newroute->cache_generation = m->route_helper->cache_generation; + } + + if (oldroute) /* route already exists? */ + { + if (route_quota_test(m, mi) && learn_address_script(m, mi, "update", &newroute->addr)) + { + learn_succeeded = true; + owner = mi; + multi_instance_inc_refcount(mi); + route_quota_inc(mi); + + /* delete old route */ + multi_route_del(oldroute); + + /* modify hash table entry, replacing old route */ + he->key = &newroute->addr; + he->value = newroute; + } + } + else + { + if (route_quota_test(m, mi) && learn_address_script(m, mi, "add", &newroute->addr)) + { + learn_succeeded = true; + owner = mi; + multi_instance_inc_refcount(mi); + route_quota_inc(mi); + + /* add new route */ + hash_add_fast(m->vhash, bucket, &newroute->addr, hv, newroute); + } + } + + msg(D_MULTI_LOW, "MULTI: Learn%s: %s -> %s", + learn_succeeded ? "" : " FAILED", + mroute_addr_print(&newroute->addr, &gc), + multi_instance_string(mi, false, &gc)); + + if (!learn_succeeded) + { + free(newroute); + } + + gc_free(&gc); + } + + return owner; } /* * Get client instance based on virtual address. */ static struct multi_instance * -multi_get_instance_by_virtual_addr (struct multi_context *m, - const struct mroute_addr *addr, - bool cidr_routing) +multi_get_instance_by_virtual_addr(struct multi_context *m, + const struct mroute_addr *addr, + bool cidr_routing) { - struct multi_route *route; - struct multi_instance *ret = NULL; + struct multi_route *route; + struct multi_instance *ret = NULL; - /* check for local address */ - if (mroute_addr_equal (addr, &m->local)) - return NULL; + /* check for local address */ + if (mroute_addr_equal(addr, &m->local)) + { + return NULL; + } - route = (struct multi_route *) hash_lookup (m->vhash, addr); + route = (struct multi_route *) hash_lookup(m->vhash, addr); - /* does host route (possible cached) exist? */ - if (route && multi_route_defined (m, route)) + /* does host route (possible cached) exist? */ + if (route && multi_route_defined(m, route)) { - struct multi_instance *mi = route->instance; - route->last_reference = now; - ret = mi; + struct multi_instance *mi = route->instance; + route->last_reference = now; + ret = mi; } - else if (cidr_routing) /* do we need to regenerate a host route cache entry? */ + else if (cidr_routing) /* do we need to regenerate a host route cache entry? */ { - struct mroute_helper *rh = m->route_helper; - struct mroute_addr tryaddr; - int i; - - /* cycle through each CIDR length */ - for (i = 0; i < rh->n_net_len; ++i) - { - tryaddr = *addr; - tryaddr.type |= MR_WITH_NETBITS; - tryaddr.netbits = rh->net_len[i]; - mroute_addr_mask_host_bits (&tryaddr); + struct mroute_helper *rh = m->route_helper; + struct mroute_addr tryaddr; + int i; - /* look up a possible route with netbits netmask */ - route = (struct multi_route *) hash_lookup (m->vhash, &tryaddr); - - if (route && multi_route_defined (m, route)) - { - /* found an applicable route, cache host route */ - struct multi_instance *mi = route->instance; - multi_learn_addr (m, mi, addr, MULTI_ROUTE_CACHE|MULTI_ROUTE_AGEABLE); - ret = mi; - break; - } - } + /* cycle through each CIDR length */ + for (i = 0; i < rh->n_net_len; ++i) + { + tryaddr = *addr; + tryaddr.type |= MR_WITH_NETBITS; + tryaddr.netbits = rh->net_len[i]; + mroute_addr_mask_host_bits(&tryaddr); + + /* look up a possible route with netbits netmask */ + route = (struct multi_route *) hash_lookup(m->vhash, &tryaddr); + + if (route && multi_route_defined(m, route)) + { + /* found an applicable route, cache host route */ + struct multi_instance *mi = route->instance; + multi_learn_addr(m, mi, addr, MULTI_ROUTE_CACHE|MULTI_ROUTE_AGEABLE); + ret = mi; + break; + } + } } - + #ifdef ENABLE_DEBUG - if (check_debug_level (D_MULTI_DEBUG)) - { - struct gc_arena gc = gc_new (); - const char *addr_text = mroute_addr_print (addr, &gc); - if (ret) - { - dmsg (D_MULTI_DEBUG, "GET INST BY VIRT: %s -> %s via %s", - addr_text, - multi_instance_string (ret, false, &gc), - mroute_addr_print (&route->addr, &gc)); - } - else - { - dmsg (D_MULTI_DEBUG, "GET INST BY VIRT: %s [failed]", - addr_text); - } - gc_free (&gc); + if (check_debug_level(D_MULTI_DEBUG)) + { + struct gc_arena gc = gc_new(); + const char *addr_text = mroute_addr_print(addr, &gc); + if (ret) + { + dmsg(D_MULTI_DEBUG, "GET INST BY VIRT: %s -> %s via %s", + addr_text, + multi_instance_string(ret, false, &gc), + mroute_addr_print(&route->addr, &gc)); + } + else + { + dmsg(D_MULTI_DEBUG, "GET INST BY VIRT: %s [failed]", + addr_text); + } + gc_free(&gc); } #endif - ASSERT (!(ret && ret->halt)); - return ret; + ASSERT(!(ret && ret->halt)); + return ret; } /* * Helper function to multi_learn_addr(). */ static struct multi_instance * -multi_learn_in_addr_t (struct multi_context *m, - struct multi_instance *mi, - in_addr_t a, - int netbits, /* -1 if host route, otherwise # of network bits in address */ - bool primary) +multi_learn_in_addr_t(struct multi_context *m, + struct multi_instance *mi, + in_addr_t a, + int netbits, /* -1 if host route, otherwise # of network bits in address */ + bool primary) { - struct openvpn_sockaddr remote_si; - struct mroute_addr addr; + struct openvpn_sockaddr remote_si; + struct mroute_addr addr; - CLEAR (remote_si); - remote_si.addr.in4.sin_family = AF_INET; - remote_si.addr.in4.sin_addr.s_addr = htonl (a); - ASSERT (mroute_extract_openvpn_sockaddr (&addr, &remote_si, false)); + CLEAR(remote_si); + remote_si.addr.in4.sin_family = AF_INET; + remote_si.addr.in4.sin_addr.s_addr = htonl(a); + ASSERT(mroute_extract_openvpn_sockaddr(&addr, &remote_si, false)); - if (netbits >= 0) + if (netbits >= 0) { - addr.type |= MR_WITH_NETBITS; - addr.netbits = (uint8_t) netbits; + addr.type |= MR_WITH_NETBITS; + addr.netbits = (uint8_t) netbits; } - { - struct multi_instance *owner = multi_learn_addr (m, mi, &addr, 0); + { + struct multi_instance *owner = multi_learn_addr(m, mi, &addr, 0); #ifdef MANAGEMENT_DEF_AUTH - if (management && owner) - management_learn_addr (management, &mi->context.c2.mda_context, &addr, primary); + if (management && owner) + { + management_learn_addr(management, &mi->context.c2.mda_context, &addr, primary); + } #endif - return owner; - } + return owner; + } } static struct multi_instance * -multi_learn_in6_addr (struct multi_context *m, - struct multi_instance *mi, - struct in6_addr a6, - int netbits, /* -1 if host route, otherwise # of network bits in address */ - bool primary) +multi_learn_in6_addr(struct multi_context *m, + struct multi_instance *mi, + struct in6_addr a6, + int netbits, /* -1 if host route, otherwise # of network bits in address */ + bool primary) { - struct mroute_addr addr; + struct mroute_addr addr; - addr.len = 16; - addr.type = MR_ADDR_IPV6; - addr.netbits = 0; - addr.v6.addr = a6; + addr.len = 16; + addr.type = MR_ADDR_IPV6; + addr.netbits = 0; + addr.v6.addr = a6; - if (netbits >= 0) + if (netbits >= 0) { - addr.type |= MR_WITH_NETBITS; - addr.netbits = (uint8_t) netbits; - mroute_addr_mask_host_bits( &addr ); + addr.type |= MR_WITH_NETBITS; + addr.netbits = (uint8_t) netbits; + mroute_addr_mask_host_bits( &addr ); } - { - struct multi_instance *owner = multi_learn_addr (m, mi, &addr, 0); + { + struct multi_instance *owner = multi_learn_addr(m, mi, &addr, 0); #ifdef MANAGEMENT_DEF_AUTH - if (management && owner) - management_learn_addr (management, &mi->context.c2.mda_context, &addr, primary); + if (management && owner) + { + management_learn_addr(management, &mi->context.c2.mda_context, &addr, primary); + } #endif - return owner; - } + return owner; + } } /* @@ -1223,44 +1307,48 @@ multi_learn_in6_addr (struct multi_context *m, * to internal routing table. */ static void -multi_add_iroutes (struct multi_context *m, - struct multi_instance *mi) -{ - struct gc_arena gc = gc_new (); - const struct iroute *ir; - const struct iroute_ipv6 *ir6; - if (TUNNEL_TYPE (mi->context.c1.tuntap) == DEV_TYPE_TUN) - { - mi->did_iroutes = true; - for (ir = mi->context.options.iroutes; ir != NULL; ir = ir->next) - { - if (ir->netbits >= 0) - msg (D_MULTI_LOW, "MULTI: internal route %s/%d -> %s", - print_in_addr_t (ir->network, 0, &gc), - ir->netbits, - multi_instance_string (mi, false, &gc)); - else - msg (D_MULTI_LOW, "MULTI: internal route %s -> %s", - print_in_addr_t (ir->network, 0, &gc), - multi_instance_string (mi, false, &gc)); - - mroute_helper_add_iroute46 (m->route_helper, ir->netbits); - - multi_learn_in_addr_t (m, mi, ir->network, ir->netbits, false); - } - for ( ir6 = mi->context.options.iroutes_ipv6; ir6 != NULL; ir6 = ir6->next ) - { - msg (D_MULTI_LOW, "MULTI: internal route %s/%d -> %s", - print_in6_addr (ir6->network, 0, &gc), - ir6->netbits, - multi_instance_string (mi, false, &gc)); - - mroute_helper_add_iroute46 (m->route_helper, ir6->netbits); - - multi_learn_in6_addr (m, mi, ir6->network, ir6->netbits, false); - } - } - gc_free (&gc); +multi_add_iroutes(struct multi_context *m, + struct multi_instance *mi) +{ + struct gc_arena gc = gc_new(); + const struct iroute *ir; + const struct iroute_ipv6 *ir6; + if (TUNNEL_TYPE(mi->context.c1.tuntap) == DEV_TYPE_TUN) + { + mi->did_iroutes = true; + for (ir = mi->context.options.iroutes; ir != NULL; ir = ir->next) + { + if (ir->netbits >= 0) + { + msg(D_MULTI_LOW, "MULTI: internal route %s/%d -> %s", + print_in_addr_t(ir->network, 0, &gc), + ir->netbits, + multi_instance_string(mi, false, &gc)); + } + else + { + msg(D_MULTI_LOW, "MULTI: internal route %s -> %s", + print_in_addr_t(ir->network, 0, &gc), + multi_instance_string(mi, false, &gc)); + } + + mroute_helper_add_iroute46(m->route_helper, ir->netbits); + + multi_learn_in_addr_t(m, mi, ir->network, ir->netbits, false); + } + for (ir6 = mi->context.options.iroutes_ipv6; ir6 != NULL; ir6 = ir6->next) + { + msg(D_MULTI_LOW, "MULTI: internal route %s/%d -> %s", + print_in6_addr(ir6->network, 0, &gc), + ir6->netbits, + multi_instance_string(mi, false, &gc)); + + mroute_helper_add_iroute46(m->route_helper, ir6->netbits); + + multi_learn_in6_addr(m, mi, ir6->network, ir6->netbits, false); + } + } + gc_free(&gc); } /* @@ -1268,65 +1356,67 @@ multi_add_iroutes (struct multi_context *m, * same common name. */ static void -multi_delete_dup (struct multi_context *m, struct multi_instance *new_mi) -{ - if (new_mi) - { - const char *new_cn = tls_common_name (new_mi->context.c2.tls_multi, true); - if (new_cn) - { - struct hash_iterator hi; - struct hash_element *he; - int count = 0; - - hash_iterator_init (m->iter, &hi); - while ((he = hash_iterator_next (&hi))) - { - struct multi_instance *mi = (struct multi_instance *) he->value; - if (mi != new_mi && !mi->halt) - { - const char *cn = tls_common_name (mi->context.c2.tls_multi, true); - if (cn && !strcmp (cn, new_cn)) - { - mi->did_iter = false; - multi_close_instance (m, mi, false); - hash_iterator_delete_element (&hi); - ++count; - } - } - } - hash_iterator_free (&hi); - - if (count) - msg (D_MULTI_LOW, "MULTI: new connection by client '%s' will cause previous active sessions by this client to be dropped. Remember to use the --duplicate-cn option if you want multiple clients using the same certificate or username to concurrently connect.", new_cn); - } +multi_delete_dup(struct multi_context *m, struct multi_instance *new_mi) +{ + if (new_mi) + { + const char *new_cn = tls_common_name(new_mi->context.c2.tls_multi, true); + if (new_cn) + { + struct hash_iterator hi; + struct hash_element *he; + int count = 0; + + hash_iterator_init(m->iter, &hi); + while ((he = hash_iterator_next(&hi))) + { + struct multi_instance *mi = (struct multi_instance *) he->value; + if (mi != new_mi && !mi->halt) + { + const char *cn = tls_common_name(mi->context.c2.tls_multi, true); + if (cn && !strcmp(cn, new_cn)) + { + mi->did_iter = false; + multi_close_instance(m, mi, false); + hash_iterator_delete_element(&hi); + ++count; + } + } + } + hash_iterator_free(&hi); + + if (count) + { + msg(D_MULTI_LOW, "MULTI: new connection by client '%s' will cause previous active sessions by this client to be dropped. Remember to use the --duplicate-cn option if you want multiple clients using the same certificate or username to concurrently connect.", new_cn); + } + } } } static void -check_stale_routes (struct multi_context *m) +check_stale_routes(struct multi_context *m) { - struct gc_arena gc = gc_new (); - struct hash_iterator hi; - struct hash_element *he; + struct gc_arena gc = gc_new(); + struct hash_iterator hi; + struct hash_element *he; - dmsg (D_MULTI_DEBUG, "MULTI: Checking stale routes"); - hash_iterator_init_range (m->vhash, &hi, 0, hash_n_buckets (m->vhash)); - while ((he = hash_iterator_next (&hi)) != NULL) + dmsg(D_MULTI_DEBUG, "MULTI: Checking stale routes"); + hash_iterator_init_range(m->vhash, &hi, 0, hash_n_buckets(m->vhash)); + while ((he = hash_iterator_next(&hi)) != NULL) { - struct multi_route *r = (struct multi_route *) he->value; - if (multi_route_defined (m, r) && difftime(now, r->last_reference) >= m->top.options.stale_routes_ageing_time) + struct multi_route *r = (struct multi_route *) he->value; + if (multi_route_defined(m, r) && difftime(now, r->last_reference) >= m->top.options.stale_routes_ageing_time) { - dmsg (D_MULTI_DEBUG, "MULTI: Deleting stale route for address '%s'", - mroute_addr_print (&r->addr, &gc)); - learn_address_script (m, NULL, "delete", &r->addr); - multi_route_del (r); - hash_iterator_delete_element (&hi); + dmsg(D_MULTI_DEBUG, "MULTI: Deleting stale route for address '%s'", + mroute_addr_print(&r->addr, &gc)); + learn_address_script(m, NULL, "delete", &r->addr); + multi_route_del(r); + hash_iterator_delete_element(&hi); } } - hash_iterator_free (&hi); - gc_free (&gc); + hash_iterator_free(&hi); + gc_free(&gc); } /* @@ -1334,192 +1424,208 @@ check_stale_routes (struct multi_context *m) * complies with --ifconfig-push-constraint directive. */ static bool -ifconfig_push_constraint_satisfied (const struct context *c) +ifconfig_push_constraint_satisfied(const struct context *c) { - const struct options *o = &c->options; - if (o->push_ifconfig_constraint_defined && c->c2.push_ifconfig_defined) - return (o->push_ifconfig_constraint_netmask & c->c2.push_ifconfig_local) == o->push_ifconfig_constraint_network; - else - return true; + const struct options *o = &c->options; + if (o->push_ifconfig_constraint_defined && c->c2.push_ifconfig_defined) + { + return (o->push_ifconfig_constraint_netmask & c->c2.push_ifconfig_local) == o->push_ifconfig_constraint_network; + } + else + { + return true; + } } /* * Select a virtual address for a new client instance. * Use an --ifconfig-push directive, if given (static IP). - * Otherwise use an --ifconfig-pool address (dynamic IP). + * Otherwise use an --ifconfig-pool address (dynamic IP). */ static void -multi_select_virtual_addr (struct multi_context *m, struct multi_instance *mi) -{ - struct gc_arena gc = gc_new (); - - /* - * If ifconfig addresses were set by dynamic config file, - * release pool addresses, otherwise keep them. - */ - if (mi->context.options.push_ifconfig_defined) - { - /* ifconfig addresses were set statically, - release dynamic allocation */ - if (mi->vaddr_handle >= 0) - { - ifconfig_pool_release (m->ifconfig_pool, mi->vaddr_handle, true); - mi->vaddr_handle = -1; - } - - mi->context.c2.push_ifconfig_defined = true; - mi->context.c2.push_ifconfig_local = mi->context.options.push_ifconfig_local; - mi->context.c2.push_ifconfig_remote_netmask = mi->context.options.push_ifconfig_remote_netmask; - mi->context.c2.push_ifconfig_local_alias = mi->context.options.push_ifconfig_local_alias; - - /* the current implementation does not allow "static IPv4, pool IPv6", - * (see below) so issue a warning if that happens - don't break the - * session, though, as we don't even know if this client WANTS IPv6 - */ - if ( mi->context.options.ifconfig_ipv6_pool_defined && - ! mi->context.options.push_ifconfig_ipv6_defined ) - { - msg( M_INFO, "MULTI_sva: WARNING: if --ifconfig-push is used for IPv4, automatic IPv6 assignment from --ifconfig-ipv6-pool does not work. Use --ifconfig-ipv6-push for IPv6 then." ); - } - } - else if (m->ifconfig_pool && mi->vaddr_handle < 0) /* otherwise, choose a pool address */ - { - in_addr_t local=0, remote=0; - struct in6_addr remote_ipv6; - const char *cn = NULL; - - if (!mi->context.options.duplicate_cn) - cn = tls_common_name (mi->context.c2.tls_multi, true); - - CLEAR(remote_ipv6); - mi->vaddr_handle = ifconfig_pool_acquire (m->ifconfig_pool, &local, &remote, &remote_ipv6, cn); - if (mi->vaddr_handle >= 0) - { - const int tunnel_type = TUNNEL_TYPE (mi->context.c1.tuntap); - const int tunnel_topology = TUNNEL_TOPOLOGY (mi->context.c1.tuntap); - - msg( M_INFO, "MULTI_sva: pool returned IPv4=%s, IPv6=%s", - print_in_addr_t( remote, 0, &gc ), - (mi->context.options.ifconfig_ipv6_pool_defined - ? print_in6_addr( remote_ipv6, 0, &gc ) - : "(Not enabled)") ); - - /* set push_ifconfig_remote_netmask from pool ifconfig address(es) */ - mi->context.c2.push_ifconfig_local = remote; - if (tunnel_type == DEV_TYPE_TAP || (tunnel_type == DEV_TYPE_TUN && tunnel_topology == TOP_SUBNET)) - { - mi->context.c2.push_ifconfig_remote_netmask = mi->context.options.ifconfig_pool_netmask; - if (!mi->context.c2.push_ifconfig_remote_netmask) - mi->context.c2.push_ifconfig_remote_netmask = mi->context.c1.tuntap->remote_netmask; - } - else if (tunnel_type == DEV_TYPE_TUN) - { - if (tunnel_topology == TOP_P2P) - mi->context.c2.push_ifconfig_remote_netmask = mi->context.c1.tuntap->local; - else if (tunnel_topology == TOP_NET30) - mi->context.c2.push_ifconfig_remote_netmask = local; - } - - if (mi->context.c2.push_ifconfig_remote_netmask) - mi->context.c2.push_ifconfig_defined = true; - else - msg (D_MULTI_ERRORS, "MULTI: no --ifconfig-pool netmask parameter is available to push to %s", - multi_instance_string (mi, false, &gc)); - - if ( mi->context.options.ifconfig_ipv6_pool_defined ) - { - mi->context.c2.push_ifconfig_ipv6_local = remote_ipv6; - mi->context.c2.push_ifconfig_ipv6_remote = - mi->context.c1.tuntap->local_ipv6; - mi->context.c2.push_ifconfig_ipv6_netbits = - mi->context.options.ifconfig_ipv6_netbits; - mi->context.c2.push_ifconfig_ipv6_defined = true; - } - } - else - { - msg (D_MULTI_ERRORS, "MULTI: no free --ifconfig-pool addresses are available"); - } - } - - /* IPv6 push_ifconfig is a bit problematic - since IPv6 shares the - * pool handling with IPv4, the combination "static IPv4, dynamic IPv6" - * will fail (because no pool will be allocated in this case). - * OTOH, this doesn't make too much sense in reality - and the other - * way round ("dynamic IPv4, static IPv6") or "both static" makes sense - * -> and so it's implemented right now - */ - if ( mi->context.options.push_ifconfig_ipv6_defined ) - { - mi->context.c2.push_ifconfig_ipv6_local = - mi->context.options.push_ifconfig_ipv6_local; - mi->context.c2.push_ifconfig_ipv6_remote = - mi->context.options.push_ifconfig_ipv6_remote; - mi->context.c2.push_ifconfig_ipv6_netbits = - mi->context.options.push_ifconfig_ipv6_netbits; - mi->context.c2.push_ifconfig_ipv6_defined = true; - - msg( M_INFO, "MULTI_sva: push_ifconfig_ipv6 %s/%d", - print_in6_addr( mi->context.c2.push_ifconfig_ipv6_local, 0, &gc ), - mi->context.c2.push_ifconfig_ipv6_netbits ); - } - - gc_free (&gc); +multi_select_virtual_addr(struct multi_context *m, struct multi_instance *mi) +{ + struct gc_arena gc = gc_new(); + + /* + * If ifconfig addresses were set by dynamic config file, + * release pool addresses, otherwise keep them. + */ + if (mi->context.options.push_ifconfig_defined) + { + /* ifconfig addresses were set statically, + * release dynamic allocation */ + if (mi->vaddr_handle >= 0) + { + ifconfig_pool_release(m->ifconfig_pool, mi->vaddr_handle, true); + mi->vaddr_handle = -1; + } + + mi->context.c2.push_ifconfig_defined = true; + mi->context.c2.push_ifconfig_local = mi->context.options.push_ifconfig_local; + mi->context.c2.push_ifconfig_remote_netmask = mi->context.options.push_ifconfig_remote_netmask; + mi->context.c2.push_ifconfig_local_alias = mi->context.options.push_ifconfig_local_alias; + + /* the current implementation does not allow "static IPv4, pool IPv6", + * (see below) so issue a warning if that happens - don't break the + * session, though, as we don't even know if this client WANTS IPv6 + */ + if (mi->context.options.ifconfig_ipv6_pool_defined + && !mi->context.options.push_ifconfig_ipv6_defined) + { + msg( M_INFO, "MULTI_sva: WARNING: if --ifconfig-push is used for IPv4, automatic IPv6 assignment from --ifconfig-ipv6-pool does not work. Use --ifconfig-ipv6-push for IPv6 then." ); + } + } + else if (m->ifconfig_pool && mi->vaddr_handle < 0) /* otherwise, choose a pool address */ + { + in_addr_t local = 0, remote = 0; + struct in6_addr remote_ipv6; + const char *cn = NULL; + + if (!mi->context.options.duplicate_cn) + { + cn = tls_common_name(mi->context.c2.tls_multi, true); + } + + CLEAR(remote_ipv6); + mi->vaddr_handle = ifconfig_pool_acquire(m->ifconfig_pool, &local, &remote, &remote_ipv6, cn); + if (mi->vaddr_handle >= 0) + { + const int tunnel_type = TUNNEL_TYPE(mi->context.c1.tuntap); + const int tunnel_topology = TUNNEL_TOPOLOGY(mi->context.c1.tuntap); + + msg( M_INFO, "MULTI_sva: pool returned IPv4=%s, IPv6=%s", + print_in_addr_t( remote, 0, &gc ), + (mi->context.options.ifconfig_ipv6_pool_defined + ? print_in6_addr( remote_ipv6, 0, &gc ) + : "(Not enabled)") ); + + /* set push_ifconfig_remote_netmask from pool ifconfig address(es) */ + mi->context.c2.push_ifconfig_local = remote; + if (tunnel_type == DEV_TYPE_TAP || (tunnel_type == DEV_TYPE_TUN && tunnel_topology == TOP_SUBNET)) + { + mi->context.c2.push_ifconfig_remote_netmask = mi->context.options.ifconfig_pool_netmask; + if (!mi->context.c2.push_ifconfig_remote_netmask) + { + mi->context.c2.push_ifconfig_remote_netmask = mi->context.c1.tuntap->remote_netmask; + } + } + else if (tunnel_type == DEV_TYPE_TUN) + { + if (tunnel_topology == TOP_P2P) + { + mi->context.c2.push_ifconfig_remote_netmask = mi->context.c1.tuntap->local; + } + else if (tunnel_topology == TOP_NET30) + { + mi->context.c2.push_ifconfig_remote_netmask = local; + } + } + + if (mi->context.c2.push_ifconfig_remote_netmask) + { + mi->context.c2.push_ifconfig_defined = true; + } + else + { + msg(D_MULTI_ERRORS, "MULTI: no --ifconfig-pool netmask parameter is available to push to %s", + multi_instance_string(mi, false, &gc)); + } + + if (mi->context.options.ifconfig_ipv6_pool_defined) + { + mi->context.c2.push_ifconfig_ipv6_local = remote_ipv6; + mi->context.c2.push_ifconfig_ipv6_remote = + mi->context.c1.tuntap->local_ipv6; + mi->context.c2.push_ifconfig_ipv6_netbits = + mi->context.options.ifconfig_ipv6_netbits; + mi->context.c2.push_ifconfig_ipv6_defined = true; + } + } + else + { + msg(D_MULTI_ERRORS, "MULTI: no free --ifconfig-pool addresses are available"); + } + } + + /* IPv6 push_ifconfig is a bit problematic - since IPv6 shares the + * pool handling with IPv4, the combination "static IPv4, dynamic IPv6" + * will fail (because no pool will be allocated in this case). + * OTOH, this doesn't make too much sense in reality - and the other + * way round ("dynamic IPv4, static IPv6") or "both static" makes sense + * -> and so it's implemented right now + */ + if (mi->context.options.push_ifconfig_ipv6_defined) + { + mi->context.c2.push_ifconfig_ipv6_local = + mi->context.options.push_ifconfig_ipv6_local; + mi->context.c2.push_ifconfig_ipv6_remote = + mi->context.options.push_ifconfig_ipv6_remote; + mi->context.c2.push_ifconfig_ipv6_netbits = + mi->context.options.push_ifconfig_ipv6_netbits; + mi->context.c2.push_ifconfig_ipv6_defined = true; + + msg( M_INFO, "MULTI_sva: push_ifconfig_ipv6 %s/%d", + print_in6_addr( mi->context.c2.push_ifconfig_ipv6_local, 0, &gc ), + mi->context.c2.push_ifconfig_ipv6_netbits ); + } + + gc_free(&gc); } /* * Set virtual address environmental variables. */ static void -multi_set_virtual_addr_env (struct multi_context *m, struct multi_instance *mi) -{ - setenv_del (mi->context.c2.es, "ifconfig_pool_local_ip"); - setenv_del (mi->context.c2.es, "ifconfig_pool_remote_ip"); - setenv_del (mi->context.c2.es, "ifconfig_pool_netmask"); - - if (mi->context.c2.push_ifconfig_defined) - { - const int tunnel_type = TUNNEL_TYPE (mi->context.c1.tuntap); - const int tunnel_topology = TUNNEL_TOPOLOGY (mi->context.c1.tuntap); - - setenv_in_addr_t (mi->context.c2.es, - "ifconfig_pool_remote_ip", - mi->context.c2.push_ifconfig_local, - SA_SET_IF_NONZERO); - - if (tunnel_type == DEV_TYPE_TAP || (tunnel_type == DEV_TYPE_TUN && tunnel_topology == TOP_SUBNET)) - { - setenv_in_addr_t (mi->context.c2.es, - "ifconfig_pool_netmask", - mi->context.c2.push_ifconfig_remote_netmask, - SA_SET_IF_NONZERO); - } - else if (tunnel_type == DEV_TYPE_TUN) - { - setenv_in_addr_t (mi->context.c2.es, - "ifconfig_pool_local_ip", - mi->context.c2.push_ifconfig_remote_netmask, - SA_SET_IF_NONZERO); - } - } - - setenv_del (mi->context.c2.es, "ifconfig_pool_local_ip6"); - setenv_del (mi->context.c2.es, "ifconfig_pool_remote_ip6"); - setenv_del (mi->context.c2.es, "ifconfig_pool_ip6_netbits"); - - if (mi->context.c2.push_ifconfig_ipv6_defined) - { - setenv_in6_addr (mi->context.c2.es, - "ifconfig_pool_remote", - &mi->context.c2.push_ifconfig_ipv6_local, - SA_SET_IF_NONZERO); - setenv_in6_addr (mi->context.c2.es, - "ifconfig_pool_local", - &mi->context.c2.push_ifconfig_ipv6_remote, - SA_SET_IF_NONZERO); - setenv_int (mi->context.c2.es, - "ifconfig_pool_ip6_netbits", - mi->context.c2.push_ifconfig_ipv6_netbits); +multi_set_virtual_addr_env(struct multi_context *m, struct multi_instance *mi) +{ + setenv_del(mi->context.c2.es, "ifconfig_pool_local_ip"); + setenv_del(mi->context.c2.es, "ifconfig_pool_remote_ip"); + setenv_del(mi->context.c2.es, "ifconfig_pool_netmask"); + + if (mi->context.c2.push_ifconfig_defined) + { + const int tunnel_type = TUNNEL_TYPE(mi->context.c1.tuntap); + const int tunnel_topology = TUNNEL_TOPOLOGY(mi->context.c1.tuntap); + + setenv_in_addr_t(mi->context.c2.es, + "ifconfig_pool_remote_ip", + mi->context.c2.push_ifconfig_local, + SA_SET_IF_NONZERO); + + if (tunnel_type == DEV_TYPE_TAP || (tunnel_type == DEV_TYPE_TUN && tunnel_topology == TOP_SUBNET)) + { + setenv_in_addr_t(mi->context.c2.es, + "ifconfig_pool_netmask", + mi->context.c2.push_ifconfig_remote_netmask, + SA_SET_IF_NONZERO); + } + else if (tunnel_type == DEV_TYPE_TUN) + { + setenv_in_addr_t(mi->context.c2.es, + "ifconfig_pool_local_ip", + mi->context.c2.push_ifconfig_remote_netmask, + SA_SET_IF_NONZERO); + } + } + + setenv_del(mi->context.c2.es, "ifconfig_pool_local_ip6"); + setenv_del(mi->context.c2.es, "ifconfig_pool_remote_ip6"); + setenv_del(mi->context.c2.es, "ifconfig_pool_ip6_netbits"); + + if (mi->context.c2.push_ifconfig_ipv6_defined) + { + setenv_in6_addr(mi->context.c2.es, + "ifconfig_pool_remote", + &mi->context.c2.push_ifconfig_ipv6_local, + SA_SET_IF_NONZERO); + setenv_in6_addr(mi->context.c2.es, + "ifconfig_pool_local", + &mi->context.c2.push_ifconfig_ipv6_remote, + SA_SET_IF_NONZERO); + setenv_int(mi->context.c2.es, + "ifconfig_pool_ip6_netbits", + mi->context.c2.push_ifconfig_ipv6_netbits); } } @@ -1527,30 +1633,30 @@ multi_set_virtual_addr_env (struct multi_context *m, struct multi_instance *mi) * Called after client-connect script is called */ static void -multi_client_connect_post (struct multi_context *m, - struct multi_instance *mi, - const char *dc_file, - unsigned int option_permissions_mask, - unsigned int *option_types_found) +multi_client_connect_post(struct multi_context *m, + struct multi_instance *mi, + const char *dc_file, + unsigned int option_permissions_mask, + unsigned int *option_types_found) { - /* Did script generate a dynamic config file? */ - if (test_file (dc_file)) + /* Did script generate a dynamic config file? */ + if (test_file(dc_file)) { - options_server_import (&mi->context.options, - dc_file, - D_IMPORT_ERRORS|M_OPTERR, - option_permissions_mask, - option_types_found, - mi->context.c2.es); + options_server_import(&mi->context.options, + dc_file, + D_IMPORT_ERRORS|M_OPTERR, + option_permissions_mask, + option_types_found, + mi->context.c2.es); - /* - * If the --client-connect script generates a config file - * with an --ifconfig-push directive, it will override any - * --ifconfig-push directive from the --client-config-dir - * directory or any --ifconfig-pool dynamic address. - */ - multi_select_virtual_addr (m, mi); - multi_set_virtual_addr_env (m, mi); + /* + * If the --client-connect script generates a config file + * with an --ifconfig-push directive, it will override any + * --ifconfig-push directive from the --client-config-dir + * directory or any --ifconfig-pool dynamic address. + */ + multi_select_virtual_addr(m, mi); + multi_set_virtual_addr_env(m, mi); } } @@ -1560,43 +1666,45 @@ multi_client_connect_post (struct multi_context *m, * Called after client-connect plug-in is called */ static void -multi_client_connect_post_plugin (struct multi_context *m, - struct multi_instance *mi, - const struct plugin_return *pr, - unsigned int option_permissions_mask, - unsigned int *option_types_found) -{ - struct plugin_return config; - - plugin_return_get_column (pr, &config, "config"); - - /* Did script generate a dynamic config file? */ - if (plugin_return_defined (&config)) - { - int i; - for (i = 0; i < config.n; ++i) - { - if (config.list[i] && config.list[i]->value) - options_string_import (&mi->context.options, - config.list[i]->value, - D_IMPORT_ERRORS|M_OPTERR, - option_permissions_mask, - option_types_found, - mi->context.c2.es); - } - - /* - * If the --client-connect script generates a config file - * with an --ifconfig-push directive, it will override any - * --ifconfig-push directive from the --client-config-dir - * directory or any --ifconfig-pool dynamic address. - */ - multi_select_virtual_addr (m, mi); - multi_set_virtual_addr_env (m, mi); +multi_client_connect_post_plugin(struct multi_context *m, + struct multi_instance *mi, + const struct plugin_return *pr, + unsigned int option_permissions_mask, + unsigned int *option_types_found) +{ + struct plugin_return config; + + plugin_return_get_column(pr, &config, "config"); + + /* Did script generate a dynamic config file? */ + if (plugin_return_defined(&config)) + { + int i; + for (i = 0; i < config.n; ++i) + { + if (config.list[i] && config.list[i]->value) + { + options_string_import(&mi->context.options, + config.list[i]->value, + D_IMPORT_ERRORS|M_OPTERR, + option_permissions_mask, + option_types_found, + mi->context.c2.es); + } + } + + /* + * If the --client-connect script generates a config file + * with an --ifconfig-push directive, it will override any + * --ifconfig-push directive from the --client-config-dir + * directory or any --ifconfig-pool dynamic address. + */ + multi_select_virtual_addr(m, mi); + multi_set_virtual_addr_env(m, mi); } } -#endif +#endif /* ifdef ENABLE_PLUGIN */ #ifdef MANAGEMENT_DEF_AUTH @@ -1604,63 +1712,63 @@ multi_client_connect_post_plugin (struct multi_context *m, * Called to load management-derived client-connect config */ static void -multi_client_connect_mda (struct multi_context *m, - struct multi_instance *mi, - const struct buffer_list *config, - unsigned int option_permissions_mask, - unsigned int *option_types_found) -{ - if (config) - { - struct buffer_entry *be; - - for (be = config->head; be != NULL; be = be->next) - { - const char *opt = BSTR(&be->buf); - options_string_import (&mi->context.options, - opt, - D_IMPORT_ERRORS|M_OPTERR, - option_permissions_mask, - option_types_found, - mi->context.c2.es); - } - - /* - * If the --client-connect script generates a config file - * with an --ifconfig-push directive, it will override any - * --ifconfig-push directive from the --client-config-dir - * directory or any --ifconfig-pool dynamic address. - */ - multi_select_virtual_addr (m, mi); - multi_set_virtual_addr_env (m, mi); +multi_client_connect_mda(struct multi_context *m, + struct multi_instance *mi, + const struct buffer_list *config, + unsigned int option_permissions_mask, + unsigned int *option_types_found) +{ + if (config) + { + struct buffer_entry *be; + + for (be = config->head; be != NULL; be = be->next) + { + const char *opt = BSTR(&be->buf); + options_string_import(&mi->context.options, + opt, + D_IMPORT_ERRORS|M_OPTERR, + option_permissions_mask, + option_types_found, + mi->context.c2.es); + } + + /* + * If the --client-connect script generates a config file + * with an --ifconfig-push directive, it will override any + * --ifconfig-push directive from the --client-config-dir + * directory or any --ifconfig-pool dynamic address. + */ + multi_select_virtual_addr(m, mi); + multi_set_virtual_addr_env(m, mi); } } -#endif +#endif /* ifdef MANAGEMENT_DEF_AUTH */ static void -multi_client_connect_setenv (struct multi_context *m, - struct multi_instance *mi) +multi_client_connect_setenv(struct multi_context *m, + struct multi_instance *mi) { - struct gc_arena gc = gc_new (); + struct gc_arena gc = gc_new(); - /* setenv incoming cert common name for script */ - setenv_str (mi->context.c2.es, "common_name", tls_common_name (mi->context.c2.tls_multi, true)); + /* setenv incoming cert common name for script */ + setenv_str(mi->context.c2.es, "common_name", tls_common_name(mi->context.c2.tls_multi, true)); - /* setenv client real IP address */ - setenv_trusted (mi->context.c2.es, get_link_socket_info (&mi->context)); + /* setenv client real IP address */ + setenv_trusted(mi->context.c2.es, get_link_socket_info(&mi->context)); - /* setenv client virtual IP address */ - multi_set_virtual_addr_env (m, mi); + /* setenv client virtual IP address */ + multi_set_virtual_addr_env(m, mi); - /* setenv connection time */ - { - const char *created_ascii = time_string (mi->created, 0, false, &gc); - setenv_str (mi->context.c2.es, "time_ascii", created_ascii); - setenv_unsigned (mi->context.c2.es, "time_unix", (unsigned int)mi->created); - } + /* setenv connection time */ + { + const char *created_ascii = time_string(mi->created, 0, false, &gc); + setenv_str(mi->context.c2.es, "time_ascii", created_ascii); + setenv_unsigned(mi->context.c2.es, "time_unix", (unsigned int)mi->created); + } - gc_free (&gc); + gc_free(&gc); } /* @@ -1673,316 +1781,328 @@ multi_client_connect_setenv (struct multi_context *m, * push */ static void -multi_connection_established (struct multi_context *m, struct multi_instance *mi) -{ - if (tls_authentication_status (mi->context.c2.tls_multi, 0) == TLS_AUTHENTICATION_SUCCEEDED) - { - struct gc_arena gc = gc_new (); - unsigned int option_types_found = 0; - - const unsigned int option_permissions_mask = - OPT_P_INSTANCE - | OPT_P_INHERIT - | OPT_P_PUSH - | OPT_P_TIMER - | OPT_P_CONFIG - | OPT_P_ECHO - | OPT_P_COMP - | OPT_P_SOCKFLAGS; - - int cc_succeeded = true; /* client connect script status */ - int cc_succeeded_count = 0; - - ASSERT (mi->context.c1.tuntap); - - /* lock down the common name and cert hashes so they can't change during future TLS renegotiations */ - tls_lock_common_name (mi->context.c2.tls_multi); - tls_lock_cert_hash_set (mi->context.c2.tls_multi); - - /* generate a msg() prefix for this client instance */ - generate_prefix (mi); - - /* delete instances of previous clients with same common-name */ - if (!mi->context.options.duplicate_cn) - multi_delete_dup (m, mi); - - /* reset pool handle to null */ - mi->vaddr_handle = -1; - - /* - * Try to source a dynamic config file from the - * --client-config-dir directory. - */ - if (mi->context.options.client_config_dir) - { - const char *ccd_file; - - ccd_file = gen_path (mi->context.options.client_config_dir, - tls_common_name (mi->context.c2.tls_multi, false), - &gc); - - /* try common-name file */ - if (test_file (ccd_file)) - { - options_server_import (&mi->context.options, - ccd_file, - D_IMPORT_ERRORS|M_OPTERR, - option_permissions_mask, - &option_types_found, - mi->context.c2.es); - } - else /* try default file */ - { - ccd_file = gen_path (mi->context.options.client_config_dir, - CCD_DEFAULT, - &gc); - - if (test_file (ccd_file)) - { - options_server_import (&mi->context.options, - ccd_file, - D_IMPORT_ERRORS|M_OPTERR, - option_permissions_mask, - &option_types_found, - mi->context.c2.es); - } - } - } - - /* - * Select a virtual address from either --ifconfig-push in --client-config-dir file - * or --ifconfig-pool. - */ - multi_select_virtual_addr (m, mi); - - /* do --client-connect setenvs */ - multi_client_connect_setenv (m, mi); +multi_connection_established(struct multi_context *m, struct multi_instance *mi) +{ + if (tls_authentication_status(mi->context.c2.tls_multi, 0) == TLS_AUTHENTICATION_SUCCEEDED) + { + struct gc_arena gc = gc_new(); + unsigned int option_types_found = 0; -#ifdef ENABLE_PLUGIN - /* - * Call client-connect plug-in. - */ + const unsigned int option_permissions_mask = + OPT_P_INSTANCE + | OPT_P_INHERIT + | OPT_P_PUSH + | OPT_P_TIMER + | OPT_P_CONFIG + | OPT_P_ECHO + | OPT_P_COMP + | OPT_P_SOCKFLAGS; - /* deprecated callback, use a file for passing back return info */ - if (plugin_defined (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT)) - { - struct argv argv = argv_new (); - const char *dc_file = create_temp_file (mi->context.options.tmp_dir, "cc", &gc); + int cc_succeeded = true; /* client connect script status */ + int cc_succeeded_count = 0; - if( !dc_file ) { - cc_succeeded = false; - goto script_depr_failed; - } - - argv_printf (&argv, "%s", dc_file); - if (plugin_call (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT, &argv, NULL, mi->context.c2.es) != OPENVPN_PLUGIN_FUNC_SUCCESS) - { - msg (M_WARN, "WARNING: client-connect plugin call failed"); - cc_succeeded = false; - } - else - { - multi_client_connect_post (m, mi, dc_file, option_permissions_mask, &option_types_found); - ++cc_succeeded_count; - } - - if (!platform_unlink (dc_file)) - msg (D_MULTI_ERRORS, "MULTI: problem deleting temporary file: %s", - dc_file); - - script_depr_failed: - argv_reset (&argv); - } - - /* V2 callback, use a plugin_return struct for passing back return info */ - if (plugin_defined (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT_V2)) - { - struct plugin_return pr; - - plugin_return_init (&pr); - - if (plugin_call (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT_V2, NULL, &pr, mi->context.c2.es) != OPENVPN_PLUGIN_FUNC_SUCCESS) - { - msg (M_WARN, "WARNING: client-connect-v2 plugin call failed"); - cc_succeeded = false; - } - else - { - multi_client_connect_post_plugin (m, mi, &pr, option_permissions_mask, &option_types_found); - ++cc_succeeded_count; - } - - plugin_return_free (&pr); - } -#endif + ASSERT(mi->context.c1.tuntap); - /* - * Run --client-connect script. - */ - if (mi->context.options.client_connect_script && cc_succeeded) - { - struct argv argv = argv_new (); - const char *dc_file = NULL; + /* lock down the common name and cert hashes so they can't change during future TLS renegotiations */ + tls_lock_common_name(mi->context.c2.tls_multi); + tls_lock_cert_hash_set(mi->context.c2.tls_multi); - setenv_str (mi->context.c2.es, "script_type", "client-connect"); + /* generate a msg() prefix for this client instance */ + generate_prefix(mi); - dc_file = create_temp_file (mi->context.options.tmp_dir, "cc", &gc); - if( !dc_file ) { - cc_succeeded = false; - goto script_failed; - } - - argv_parse_cmd (&argv, mi->context.options.client_connect_script); - argv_printf_cat (&argv, "%s", dc_file); - - if (openvpn_run_script (&argv, mi->context.c2.es, 0, "--client-connect")) - { - multi_client_connect_post (m, mi, dc_file, option_permissions_mask, &option_types_found); - ++cc_succeeded_count; - } - else - cc_succeeded = false; - - if (!platform_unlink (dc_file)) - msg (D_MULTI_ERRORS, "MULTI: problem deleting temporary file: %s", - dc_file); - - script_failed: - argv_reset (&argv); - } - - /* - * Check for client-connect script left by management interface client - */ + /* delete instances of previous clients with same common-name */ + if (!mi->context.options.duplicate_cn) + { + multi_delete_dup(m, mi); + } + + /* reset pool handle to null */ + mi->vaddr_handle = -1; + + /* + * Try to source a dynamic config file from the + * --client-config-dir directory. + */ + if (mi->context.options.client_config_dir) + { + const char *ccd_file; + + ccd_file = gen_path(mi->context.options.client_config_dir, + tls_common_name(mi->context.c2.tls_multi, false), + &gc); + + /* try common-name file */ + if (test_file(ccd_file)) + { + options_server_import(&mi->context.options, + ccd_file, + D_IMPORT_ERRORS|M_OPTERR, + option_permissions_mask, + &option_types_found, + mi->context.c2.es); + } + else /* try default file */ + { + ccd_file = gen_path(mi->context.options.client_config_dir, + CCD_DEFAULT, + &gc); + + if (test_file(ccd_file)) + { + options_server_import(&mi->context.options, + ccd_file, + D_IMPORT_ERRORS|M_OPTERR, + option_permissions_mask, + &option_types_found, + mi->context.c2.es); + } + } + } + + /* + * Select a virtual address from either --ifconfig-push in --client-config-dir file + * or --ifconfig-pool. + */ + multi_select_virtual_addr(m, mi); + + /* do --client-connect setenvs */ + multi_client_connect_setenv(m, mi); + +#ifdef ENABLE_PLUGIN + /* + * Call client-connect plug-in. + */ + + /* deprecated callback, use a file for passing back return info */ + if (plugin_defined(mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT)) + { + struct argv argv = argv_new(); + const char *dc_file = create_temp_file(mi->context.options.tmp_dir, "cc", &gc); + + if (!dc_file) + { + cc_succeeded = false; + goto script_depr_failed; + } + + argv_printf(&argv, "%s", dc_file); + if (plugin_call(mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT, &argv, NULL, mi->context.c2.es) != OPENVPN_PLUGIN_FUNC_SUCCESS) + { + msg(M_WARN, "WARNING: client-connect plugin call failed"); + cc_succeeded = false; + } + else + { + multi_client_connect_post(m, mi, dc_file, option_permissions_mask, &option_types_found); + ++cc_succeeded_count; + } + + if (!platform_unlink(dc_file)) + { + msg(D_MULTI_ERRORS, "MULTI: problem deleting temporary file: %s", + dc_file); + } + +script_depr_failed: + argv_reset(&argv); + } + + /* V2 callback, use a plugin_return struct for passing back return info */ + if (plugin_defined(mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT_V2)) + { + struct plugin_return pr; + + plugin_return_init(&pr); + + if (plugin_call(mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT_V2, NULL, &pr, mi->context.c2.es) != OPENVPN_PLUGIN_FUNC_SUCCESS) + { + msg(M_WARN, "WARNING: client-connect-v2 plugin call failed"); + cc_succeeded = false; + } + else + { + multi_client_connect_post_plugin(m, mi, &pr, option_permissions_mask, &option_types_found); + ++cc_succeeded_count; + } + + plugin_return_free(&pr); + } +#endif /* ifdef ENABLE_PLUGIN */ + + /* + * Run --client-connect script. + */ + if (mi->context.options.client_connect_script && cc_succeeded) + { + struct argv argv = argv_new(); + const char *dc_file = NULL; + + setenv_str(mi->context.c2.es, "script_type", "client-connect"); + + dc_file = create_temp_file(mi->context.options.tmp_dir, "cc", &gc); + if (!dc_file) + { + cc_succeeded = false; + goto script_failed; + } + + argv_parse_cmd(&argv, mi->context.options.client_connect_script); + argv_printf_cat(&argv, "%s", dc_file); + + if (openvpn_run_script(&argv, mi->context.c2.es, 0, "--client-connect")) + { + multi_client_connect_post(m, mi, dc_file, option_permissions_mask, &option_types_found); + ++cc_succeeded_count; + } + else + { + cc_succeeded = false; + } + + if (!platform_unlink(dc_file)) + { + msg(D_MULTI_ERRORS, "MULTI: problem deleting temporary file: %s", + dc_file); + } + +script_failed: + argv_reset(&argv); + } + + /* + * Check for client-connect script left by management interface client + */ #ifdef MANAGEMENT_DEF_AUTH - if (cc_succeeded && mi->cc_config) - { - multi_client_connect_mda (m, mi, mi->cc_config, option_permissions_mask, &option_types_found); - ++cc_succeeded_count; - } + if (cc_succeeded && mi->cc_config) + { + multi_client_connect_mda(m, mi, mi->cc_config, option_permissions_mask, &option_types_found); + ++cc_succeeded_count; + } #endif - /* - * Check for "disable" directive in client-config-dir file - * or config file generated by --client-connect script. - */ - if (mi->context.options.disable) - { - msg (D_MULTI_ERRORS, "MULTI: client has been rejected due to 'disable' directive"); - cc_succeeded = false; - cc_succeeded_count = 0; - } - - if (cc_succeeded) - { - /* - * Process sourced options. - */ - do_deferred_options (&mi->context, option_types_found); - - /* - * make sure we got ifconfig settings from somewhere - */ - if (!mi->context.c2.push_ifconfig_defined) - { - msg (D_MULTI_ERRORS, "MULTI: no dynamic or static remote --ifconfig address is available for %s", - multi_instance_string (mi, false, &gc)); - } - - /* - * make sure that ifconfig settings comply with constraints - */ - if (!ifconfig_push_constraint_satisfied (&mi->context)) - { - /* JYFIXME -- this should cause the connection to fail */ - msg (D_MULTI_ERRORS, "MULTI ERROR: primary virtual IP for %s (%s) violates tunnel network/netmask constraint (%s/%s)", - multi_instance_string (mi, false, &gc), - print_in_addr_t (mi->context.c2.push_ifconfig_local, 0, &gc), - print_in_addr_t (mi->context.options.push_ifconfig_constraint_network, 0, &gc), - print_in_addr_t (mi->context.options.push_ifconfig_constraint_netmask, 0, &gc)); - } - - /* - * For routed tunnels, set up internal route to endpoint - * plus add all iroute routes. - */ - if (TUNNEL_TYPE (mi->context.c1.tuntap) == DEV_TYPE_TUN) - { - if (mi->context.c2.push_ifconfig_defined) - { - multi_learn_in_addr_t (m, mi, mi->context.c2.push_ifconfig_local, -1, true); - msg (D_MULTI_LOW, "MULTI: primary virtual IP for %s: %s", - multi_instance_string (mi, false, &gc), - print_in_addr_t (mi->context.c2.push_ifconfig_local, 0, &gc)); - } - - if (mi->context.c2.push_ifconfig_ipv6_defined) - { - multi_learn_in6_addr (m, mi, mi->context.c2.push_ifconfig_ipv6_local, -1, true); - /* TODO: find out where addresses are "unlearned"!! */ - msg (D_MULTI_LOW, "MULTI: primary virtual IPv6 for %s: %s", - multi_instance_string (mi, false, &gc), - print_in6_addr (mi->context.c2.push_ifconfig_ipv6_local, 0, &gc)); - } - - /* add routes locally, pointing to new client, if - --iroute options have been specified */ - multi_add_iroutes (m, mi); - - /* - * iroutes represent subnets which are "owned" by a particular - * client. Therefore, do not actually push a route to a client - * if it matches one of the client's iroutes. - */ - remove_iroutes_from_push_route_list (&mi->context.options); - } - else if (mi->context.options.iroutes) - { - msg (D_MULTI_ERRORS, "MULTI: --iroute options rejected for %s -- iroute only works with tun-style tunnels", - multi_instance_string (mi, false, &gc)); - } - - /* set our client's VPN endpoint for status reporting purposes */ - mi->reporting_addr = mi->context.c2.push_ifconfig_local; - mi->reporting_addr_ipv6 = mi->context.c2.push_ifconfig_ipv6_local; - - /* set context-level authentication flag */ - mi->context.c2.context_auth = CAS_SUCCEEDED; + /* + * Check for "disable" directive in client-config-dir file + * or config file generated by --client-connect script. + */ + if (mi->context.options.disable) + { + msg(D_MULTI_ERRORS, "MULTI: client has been rejected due to 'disable' directive"); + cc_succeeded = false; + cc_succeeded_count = 0; + } + + if (cc_succeeded) + { + /* + * Process sourced options. + */ + do_deferred_options(&mi->context, option_types_found); + + /* + * make sure we got ifconfig settings from somewhere + */ + if (!mi->context.c2.push_ifconfig_defined) + { + msg(D_MULTI_ERRORS, "MULTI: no dynamic or static remote --ifconfig address is available for %s", + multi_instance_string(mi, false, &gc)); + } + + /* + * make sure that ifconfig settings comply with constraints + */ + if (!ifconfig_push_constraint_satisfied(&mi->context)) + { + /* JYFIXME -- this should cause the connection to fail */ + msg(D_MULTI_ERRORS, "MULTI ERROR: primary virtual IP for %s (%s) violates tunnel network/netmask constraint (%s/%s)", + multi_instance_string(mi, false, &gc), + print_in_addr_t(mi->context.c2.push_ifconfig_local, 0, &gc), + print_in_addr_t(mi->context.options.push_ifconfig_constraint_network, 0, &gc), + print_in_addr_t(mi->context.options.push_ifconfig_constraint_netmask, 0, &gc)); + } + + /* + * For routed tunnels, set up internal route to endpoint + * plus add all iroute routes. + */ + if (TUNNEL_TYPE(mi->context.c1.tuntap) == DEV_TYPE_TUN) + { + if (mi->context.c2.push_ifconfig_defined) + { + multi_learn_in_addr_t(m, mi, mi->context.c2.push_ifconfig_local, -1, true); + msg(D_MULTI_LOW, "MULTI: primary virtual IP for %s: %s", + multi_instance_string(mi, false, &gc), + print_in_addr_t(mi->context.c2.push_ifconfig_local, 0, &gc)); + } + + if (mi->context.c2.push_ifconfig_ipv6_defined) + { + multi_learn_in6_addr(m, mi, mi->context.c2.push_ifconfig_ipv6_local, -1, true); + /* TODO: find out where addresses are "unlearned"!! */ + msg(D_MULTI_LOW, "MULTI: primary virtual IPv6 for %s: %s", + multi_instance_string(mi, false, &gc), + print_in6_addr(mi->context.c2.push_ifconfig_ipv6_local, 0, &gc)); + } + + /* add routes locally, pointing to new client, if + * --iroute options have been specified */ + multi_add_iroutes(m, mi); + + /* + * iroutes represent subnets which are "owned" by a particular + * client. Therefore, do not actually push a route to a client + * if it matches one of the client's iroutes. + */ + remove_iroutes_from_push_route_list(&mi->context.options); + } + else if (mi->context.options.iroutes) + { + msg(D_MULTI_ERRORS, "MULTI: --iroute options rejected for %s -- iroute only works with tun-style tunnels", + multi_instance_string(mi, false, &gc)); + } + + /* set our client's VPN endpoint for status reporting purposes */ + mi->reporting_addr = mi->context.c2.push_ifconfig_local; + mi->reporting_addr_ipv6 = mi->context.c2.push_ifconfig_ipv6_local; + + /* set context-level authentication flag */ + mi->context.c2.context_auth = CAS_SUCCEEDED; #ifdef ENABLE_ASYNC_PUSH - /* authentication complete, send push reply */ - if (mi->context.c2.push_request_received) - { - process_incoming_push_request(&mi->context); - } + /* authentication complete, send push reply */ + if (mi->context.c2.push_request_received) + { + process_incoming_push_request(&mi->context); + } #endif - } - else - { - /* set context-level authentication flag */ - mi->context.c2.context_auth = cc_succeeded_count ? CAS_PARTIAL : CAS_FAILED; - } + } + else + { + /* set context-level authentication flag */ + mi->context.c2.context_auth = cc_succeeded_count ? CAS_PARTIAL : CAS_FAILED; + } - /* set flag so we don't get called again */ - mi->connection_established_flag = true; + /* set flag so we don't get called again */ + mi->connection_established_flag = true; - /* increment number of current authenticated clients */ - ++m->n_clients; - update_mstat_n_clients(m->n_clients); - --mi->n_clients_delta; + /* increment number of current authenticated clients */ + ++m->n_clients; + update_mstat_n_clients(m->n_clients); + --mi->n_clients_delta; #ifdef MANAGEMENT_DEF_AUTH - if (management) - management_connection_established (management, &mi->context.c2.mda_context, mi->context.c2.es); + if (management) + { + management_connection_established(management, &mi->context.c2.mda_context, mi->context.c2.es); + } #endif - gc_free (&gc); + gc_free(&gc); } - /* - * Reply now to client's PUSH_REQUEST query - */ - mi->context.c2.push_reply_deferred = false; + /* + * Reply now to client's PUSH_REQUEST query + */ + mi->context.c2.push_reply_deferred = false; } #ifdef ENABLE_ASYNC_PUSH @@ -1991,71 +2111,71 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi * Continues authentication and sends push_reply. */ void -multi_process_file_closed (struct multi_context *m, const unsigned int mpp_flags) -{ - char buffer[INOTIFY_EVENT_BUFFER_SIZE]; - size_t buffer_i = 0; - int r = read (m->top.c2.inotify_fd, buffer, INOTIFY_EVENT_BUFFER_SIZE); - - while (buffer_i < r) - { - /* parse inotify events */ - struct inotify_event *pevent = (struct inotify_event *) &buffer[buffer_i]; - size_t event_size = sizeof (struct inotify_event) + pevent->len; - buffer_i += event_size; - - msg(D_MULTI_DEBUG, "MULTI: modified fd %d, mask %d", pevent->wd, pevent->mask); - - struct multi_instance* mi = hash_lookup(m->inotify_watchers, (void*) (unsigned long) pevent->wd); - - if (pevent->mask & IN_CLOSE_WRITE) - { - if (mi) - { - /* continue authentication and send push_reply */ - multi_process_post (m, mi, mpp_flags); - } - else - { - msg(D_MULTI_ERRORS, "MULTI: multi_instance not found!"); - } - } - else if (pevent->mask & IN_IGNORED) - { - /* this event is _always_ fired when watch is removed or file is deleted */ - if (mi) - { - hash_remove(m->inotify_watchers, (void*) (unsigned long) pevent->wd); - mi->inotify_watch = -1; - } - } - else - { - msg(D_MULTI_ERRORS, "MULTI: unknown mask %d", pevent->mask); - } +multi_process_file_closed(struct multi_context *m, const unsigned int mpp_flags) +{ + char buffer[INOTIFY_EVENT_BUFFER_SIZE]; + size_t buffer_i = 0; + int r = read(m->top.c2.inotify_fd, buffer, INOTIFY_EVENT_BUFFER_SIZE); + + while (buffer_i < r) + { + /* parse inotify events */ + struct inotify_event *pevent = (struct inotify_event *) &buffer[buffer_i]; + size_t event_size = sizeof(struct inotify_event) + pevent->len; + buffer_i += event_size; + + msg(D_MULTI_DEBUG, "MULTI: modified fd %d, mask %d", pevent->wd, pevent->mask); + + struct multi_instance *mi = hash_lookup(m->inotify_watchers, (void *) (unsigned long) pevent->wd); + + if (pevent->mask & IN_CLOSE_WRITE) + { + if (mi) + { + /* continue authentication and send push_reply */ + multi_process_post(m, mi, mpp_flags); + } + else + { + msg(D_MULTI_ERRORS, "MULTI: multi_instance not found!"); + } + } + else if (pevent->mask & IN_IGNORED) + { + /* this event is _always_ fired when watch is removed or file is deleted */ + if (mi) + { + hash_remove(m->inotify_watchers, (void *) (unsigned long) pevent->wd); + mi->inotify_watch = -1; + } + } + else + { + msg(D_MULTI_ERRORS, "MULTI: unknown mask %d", pevent->mask); + } } } -#endif +#endif /* ifdef ENABLE_ASYNC_PUSH */ /* * Add a mbuf buffer to a particular * instance. */ void -multi_add_mbuf (struct multi_context *m, - struct multi_instance *mi, - struct mbuf_buffer *mb) +multi_add_mbuf(struct multi_context *m, + struct multi_instance *mi, + struct mbuf_buffer *mb) { - if (multi_output_queue_ready (m, mi)) + if (multi_output_queue_ready(m, mi)) { - struct mbuf_item item; - item.buffer = mb; - item.instance = mi; - mbuf_add_item (m->mbuf, &item); + struct mbuf_item item; + item.buffer = mb; + item.instance = mi; + mbuf_add_item(m->mbuf, &item); } - else + else { - msg (D_MULTI_DROPPED, "MULTI: packet dropped due to output saturation (multi_add_mbuf)"); + msg(D_MULTI_DROPPED, "MULTI: packet dropped due to output saturation (multi_add_mbuf)"); } } @@ -2063,18 +2183,18 @@ multi_add_mbuf (struct multi_context *m, * Add a packet to a client instance output queue. */ static inline void -multi_unicast (struct multi_context *m, - const struct buffer *buf, - struct multi_instance *mi) +multi_unicast(struct multi_context *m, + const struct buffer *buf, + struct multi_instance *mi) { - struct mbuf_buffer *mb; + struct mbuf_buffer *mb; - if (BLEN (buf) > 0) + if (BLEN(buf) > 0) { - mb = mbuf_alloc_buf (buf); - mb->flags = MF_UNICAST; - multi_add_mbuf (m, mi, mb); - mbuf_free_buf (mb); + mb = mbuf_alloc_buf(buf); + mb->flags = MF_UNICAST; + multi_add_mbuf(m, mi, mb); + mbuf_free_buf(mb); } } @@ -2082,61 +2202,61 @@ multi_unicast (struct multi_context *m, * Broadcast a packet to all clients. */ static void -multi_bcast (struct multi_context *m, - const struct buffer *buf, - const struct multi_instance *sender_instance, - const struct mroute_addr *sender_addr) +multi_bcast(struct multi_context *m, + const struct buffer *buf, + const struct multi_instance *sender_instance, + const struct mroute_addr *sender_addr) { - struct hash_iterator hi; - struct hash_element *he; - struct multi_instance *mi; - struct mbuf_buffer *mb; + struct hash_iterator hi; + struct hash_element *he; + struct multi_instance *mi; + struct mbuf_buffer *mb; - if (BLEN (buf) > 0) + if (BLEN(buf) > 0) { - perf_push (PERF_MULTI_BCAST); + perf_push(PERF_MULTI_BCAST); #ifdef MULTI_DEBUG_EVENT_LOOP - printf ("BCAST len=%d\n", BLEN (buf)); + printf("BCAST len=%d\n", BLEN(buf)); #endif - mb = mbuf_alloc_buf (buf); - hash_iterator_init (m->iter, &hi); - - while ((he = hash_iterator_next (&hi))) - { - mi = (struct multi_instance *) he->value; - if (mi != sender_instance && !mi->halt) - { + mb = mbuf_alloc_buf(buf); + hash_iterator_init(m->iter, &hi); + + while ((he = hash_iterator_next(&hi))) + { + mi = (struct multi_instance *) he->value; + if (mi != sender_instance && !mi->halt) + { #ifdef ENABLE_PF - if (sender_instance) - { - if (!pf_c2c_test (&sender_instance->context, &mi->context, "bcast_c2c")) - { - msg (D_PF_DROPPED_BCAST, "PF: client[%s] -> client[%s] packet dropped by BCAST packet filter", - mi_prefix (sender_instance), - mi_prefix (mi)); - continue; - } - } - if (sender_addr) - { - if (!pf_addr_test (&mi->context, sender_addr, "bcast_src_addr")) - { - struct gc_arena gc = gc_new (); - msg (D_PF_DROPPED_BCAST, "PF: addr[%s] -> client[%s] packet dropped by BCAST packet filter", - mroute_addr_print_ex (sender_addr, MAPF_SHOW_ARP, &gc), - mi_prefix (mi)); - gc_free (&gc); - continue; - } - } -#endif - multi_add_mbuf (m, mi, mb); - } - } + if (sender_instance) + { + if (!pf_c2c_test(&sender_instance->context, &mi->context, "bcast_c2c")) + { + msg(D_PF_DROPPED_BCAST, "PF: client[%s] -> client[%s] packet dropped by BCAST packet filter", + mi_prefix(sender_instance), + mi_prefix(mi)); + continue; + } + } + if (sender_addr) + { + if (!pf_addr_test(&mi->context, sender_addr, "bcast_src_addr")) + { + struct gc_arena gc = gc_new(); + msg(D_PF_DROPPED_BCAST, "PF: addr[%s] -> client[%s] packet dropped by BCAST packet filter", + mroute_addr_print_ex(sender_addr, MAPF_SHOW_ARP, &gc), + mi_prefix(mi)); + gc_free(&gc); + continue; + } + } +#endif /* ifdef ENABLE_PF */ + multi_add_mbuf(m, mi, mb); + } + } - hash_iterator_free (&hi); - mbuf_free_buf (mb); - perf_pop (); + hash_iterator_free(&hi); + mbuf_free_buf(mb); + perf_pop(); } } @@ -2152,35 +2272,39 @@ multi_bcast (struct multi_context *m, * Sigma should be no larger than TV_WITHIN_SIGMA_MAX_USEC */ static inline unsigned int -compute_wakeup_sigma (const struct timeval *delta) +compute_wakeup_sigma(const struct timeval *delta) { - if (delta->tv_sec < 1) + if (delta->tv_sec < 1) { - /* if < 1 sec, fuzz = # of microseconds / 8 */ - return delta->tv_usec >> 3; + /* if < 1 sec, fuzz = # of microseconds / 8 */ + return delta->tv_usec >> 3; } - else + else { - /* if < 10 minutes, fuzz = 13.1% of timeout */ - if (delta->tv_sec < 600) - return delta->tv_sec << 17; - else - return 120000000; /* if >= 10 minutes, fuzz = 2 minutes */ + /* if < 10 minutes, fuzz = 13.1% of timeout */ + if (delta->tv_sec < 600) + { + return delta->tv_sec << 17; + } + else + { + return 120000000; /* if >= 10 minutes, fuzz = 2 minutes */ + } } } static void -multi_schedule_context_wakeup (struct multi_context *m, struct multi_instance *mi) +multi_schedule_context_wakeup(struct multi_context *m, struct multi_instance *mi) { - /* calculate an absolute wakeup time */ - ASSERT (!openvpn_gettimeofday (&mi->wakeup, NULL)); - tv_add (&mi->wakeup, &mi->context.c2.timeval); + /* calculate an absolute wakeup time */ + ASSERT(!openvpn_gettimeofday(&mi->wakeup, NULL)); + tv_add(&mi->wakeup, &mi->context.c2.timeval); - /* tell scheduler to wake us up at some point in the future */ - schedule_add_entry (m->schedule, - (struct schedule_entry *) mi, - &mi->wakeup, - compute_wakeup_sigma (&mi->context.c2.timeval)); + /* tell scheduler to wake us up at some point in the future */ + schedule_add_entry(m->schedule, + (struct schedule_entry *) mi, + &mi->wakeup, + compute_wakeup_sigma(&mi->context.c2.timeval)); } /* @@ -2191,139 +2315,146 @@ multi_schedule_context_wakeup (struct multi_context *m, struct multi_instance *m * Also close context on signal. */ bool -multi_process_post (struct multi_context *m, struct multi_instance *mi, const unsigned int flags) +multi_process_post(struct multi_context *m, struct multi_instance *mi, const unsigned int flags) { - bool ret = true; + bool ret = true; - if (!IS_SIG (&mi->context) && ((flags & MPP_PRE_SELECT) || ((flags & MPP_CONDITIONAL_PRE_SELECT) && !ANY_OUT (&mi->context)))) + if (!IS_SIG(&mi->context) && ((flags & MPP_PRE_SELECT) || ((flags & MPP_CONDITIONAL_PRE_SELECT) && !ANY_OUT(&mi->context)))) { #if defined(ENABLE_ASYNC_PUSH) && defined(ENABLE_DEF_AUTH) - bool was_authenticated = false; - struct key_state *ks = NULL; - if (mi->context.c2.tls_multi) + bool was_authenticated = false; + struct key_state *ks = NULL; + if (mi->context.c2.tls_multi) { - ks = &mi->context.c2.tls_multi->session[TM_ACTIVE].key[KS_PRIMARY]; - was_authenticated = ks->authenticated; + ks = &mi->context.c2.tls_multi->session[TM_ACTIVE].key[KS_PRIMARY]; + was_authenticated = ks->authenticated; } #endif - /* figure timeouts and fetch possible outgoing - to_link packets (such as ping or TLS control) */ - pre_select (&mi->context); + /* figure timeouts and fetch possible outgoing + * to_link packets (such as ping or TLS control) */ + pre_select(&mi->context); #if defined(ENABLE_ASYNC_PUSH) && defined(ENABLE_DEF_AUTH) - if (ks && ks->auth_control_file && ks->auth_deferred && !was_authenticated) - { - /* watch acf file */ - long watch_descriptor = inotify_add_watch(m->top.c2.inotify_fd, ks->auth_control_file, IN_CLOSE_WRITE | IN_ONESHOT); - if (watch_descriptor >= 0) - { - if (mi->inotify_watch != -1) - { - hash_remove(m->inotify_watchers, (void*) (unsigned long)mi->inotify_watch); - } - hash_add (m->inotify_watchers, (const uintptr_t*)watch_descriptor, mi, true); - mi->inotify_watch = watch_descriptor; - } - else - { - msg(M_NONFATAL, "MULTI: inotify_add_watch error: %s", strerror(errno)); - } - } + if (ks && ks->auth_control_file && ks->auth_deferred && !was_authenticated) + { + /* watch acf file */ + long watch_descriptor = inotify_add_watch(m->top.c2.inotify_fd, ks->auth_control_file, IN_CLOSE_WRITE | IN_ONESHOT); + if (watch_descriptor >= 0) + { + if (mi->inotify_watch != -1) + { + hash_remove(m->inotify_watchers, (void *) (unsigned long)mi->inotify_watch); + } + hash_add(m->inotify_watchers, (const uintptr_t *)watch_descriptor, mi, true); + mi->inotify_watch = watch_descriptor; + } + else + { + msg(M_NONFATAL, "MULTI: inotify_add_watch error: %s", strerror(errno)); + } + } #endif - if (!IS_SIG (&mi->context)) - { - /* connection is "established" when SSL/TLS key negotiation succeeds - and (if specified) auth user/pass succeeds */ - if (!mi->connection_established_flag && CONNECTION_ESTABLISHED (&mi->context)) - multi_connection_established (m, mi); - - /* tell scheduler to wake us up at some point in the future */ - multi_schedule_context_wakeup(m, mi); - } + if (!IS_SIG(&mi->context)) + { + /* connection is "established" when SSL/TLS key negotiation succeeds + * and (if specified) auth user/pass succeeds */ + if (!mi->connection_established_flag && CONNECTION_ESTABLISHED(&mi->context)) + { + multi_connection_established(m, mi); + } + + /* tell scheduler to wake us up at some point in the future */ + multi_schedule_context_wakeup(m, mi); + } } - if (IS_SIG (&mi->context)) + if (IS_SIG(&mi->context)) { - if (flags & MPP_CLOSE_ON_SIGNAL) - { - multi_close_instance_on_signal (m, mi); - ret = false; - } + if (flags & MPP_CLOSE_ON_SIGNAL) + { + multi_close_instance_on_signal(m, mi); + ret = false; + } } - else + else { - /* continue to pend on output? */ - multi_set_pending (m, ANY_OUT (&mi->context) ? mi : NULL); + /* continue to pend on output? */ + multi_set_pending(m, ANY_OUT(&mi->context) ? mi : NULL); #ifdef MULTI_DEBUG_EVENT_LOOP - printf ("POST %s[%d] to=%d lo=%d/%d w=%d/%d\n", - id(mi), - (int) (mi == m->pending), - mi ? mi->context.c2.to_tun.len : -1, - mi ? mi->context.c2.to_link.len : -1, - (mi && mi->context.c2.fragment) ? mi->context.c2.fragment->outgoing.len : -1, - (int)mi->context.c2.timeval.tv_sec, - (int)mi->context.c2.timeval.tv_usec); + printf("POST %s[%d] to=%d lo=%d/%d w=%d/%d\n", + id(mi), + (int) (mi == m->pending), + mi ? mi->context.c2.to_tun.len : -1, + mi ? mi->context.c2.to_link.len : -1, + (mi && mi->context.c2.fragment) ? mi->context.c2.fragment->outgoing.len : -1, + (int)mi->context.c2.timeval.tv_sec, + (int)mi->context.c2.timeval.tv_usec); #endif } - if ((flags & MPP_RECORD_TOUCH) && m->mpp_touched) - *m->mpp_touched = mi; + if ((flags & MPP_RECORD_TOUCH) && m->mpp_touched) + { + *m->mpp_touched = mi; + } - return ret; + return ret; } -void multi_process_float (struct multi_context* m, struct multi_instance* mi) +void +multi_process_float(struct multi_context *m, struct multi_instance *mi) { - struct mroute_addr real; - struct hash *hash = m->hash; - struct gc_arena gc = gc_new (); + struct mroute_addr real; + struct hash *hash = m->hash; + struct gc_arena gc = gc_new(); - if (!mroute_extract_openvpn_sockaddr (&real, &m->top.c2.from.dest, true)) - goto done; + if (!mroute_extract_openvpn_sockaddr(&real, &m->top.c2.from.dest, true)) + { + goto done; + } - const uint32_t hv = hash_value (hash, &real); - struct hash_bucket *bucket = hash_bucket (hash, hv); + const uint32_t hv = hash_value(hash, &real); + struct hash_bucket *bucket = hash_bucket(hash, hv); - /* make sure that we don't float to an address taken by another client */ - struct hash_element *he = hash_lookup_fast (hash, bucket, &real, hv); - if (he) + /* make sure that we don't float to an address taken by another client */ + struct hash_element *he = hash_lookup_fast(hash, bucket, &real, hv); + if (he) { - struct multi_instance *ex_mi = (struct multi_instance *) he->value; + struct multi_instance *ex_mi = (struct multi_instance *) he->value; - struct tls_multi *m1 = mi->context.c2.tls_multi; - struct tls_multi *m2 = ex_mi->context.c2.tls_multi; + struct tls_multi *m1 = mi->context.c2.tls_multi; + struct tls_multi *m2 = ex_mi->context.c2.tls_multi; - /* do not float if target address is taken by client with another cert */ - if (!cert_hash_compare(m1->locked_cert_hash_set, m2->locked_cert_hash_set)) - { - msg (D_MULTI_LOW, "Disallow float to an address taken by another client %s", - multi_instance_string (ex_mi, false, &gc)); + /* do not float if target address is taken by client with another cert */ + if (!cert_hash_compare(m1->locked_cert_hash_set, m2->locked_cert_hash_set)) + { + msg(D_MULTI_LOW, "Disallow float to an address taken by another client %s", + multi_instance_string(ex_mi, false, &gc)); - mi->context.c2.buf.len = 0; + mi->context.c2.buf.len = 0; - goto done; - } + goto done; + } - msg (D_MULTI_MEDIUM, "closing instance %s", multi_instance_string (ex_mi, false, &gc)); - multi_close_instance(m, ex_mi, false); + msg(D_MULTI_MEDIUM, "closing instance %s", multi_instance_string(ex_mi, false, &gc)); + multi_close_instance(m, ex_mi, false); } - msg (D_MULTI_MEDIUM, "peer %" PRIu32 " (%s) floated from %s to %s", - mi->context.c2.tls_multi->peer_id, - tls_common_name (mi->context.c2.tls_multi, false), - mroute_addr_print (&mi->real, &gc), - print_link_socket_actual (&m->top.c2.from, &gc)); + msg(D_MULTI_MEDIUM, "peer %" PRIu32 " (%s) floated from %s to %s", + mi->context.c2.tls_multi->peer_id, + tls_common_name(mi->context.c2.tls_multi, false), + mroute_addr_print(&mi->real, &gc), + print_link_socket_actual(&m->top.c2.from, &gc)); /* remove old address from hash table before changing address */ - ASSERT (hash_remove (m->hash, &mi->real)); - ASSERT (hash_remove (m->iter, &mi->real)); + ASSERT(hash_remove(m->hash, &mi->real)); + ASSERT(hash_remove(m->iter, &mi->real)); /* change external network address of the remote peer */ mi->real = real; - generate_prefix (mi); + generate_prefix(mi); mi->context.c2.from = m->top.c2.from; mi->context.c2.to_link_addr = &mi->context.c2.from; @@ -2332,17 +2463,17 @@ void multi_process_float (struct multi_context* m, struct multi_instance* mi) mi->context.c2.link_socket = m->top.c2.link_socket; mi->context.c2.link_socket_info->lsa->actual = m->top.c2.from; - tls_update_remote_addr (mi->context.c2.tls_multi, &mi->context.c2.from); + tls_update_remote_addr(mi->context.c2.tls_multi, &mi->context.c2.from); - ASSERT (hash_add (m->hash, &mi->real, mi, false)); - ASSERT (hash_add (m->iter, &mi->real, mi, false)); + ASSERT(hash_add(m->hash, &mi->real, mi, false)); + ASSERT(hash_add(m->iter, &mi->real, mi, false)); #ifdef MANAGEMENT_DEF_AUTH - ASSERT (hash_add (m->cid_hash, &mi->context.c2.mda_context.cid, mi, true)); + ASSERT(hash_add(m->cid_hash, &mi->context.c2.mda_context.cid, mi, true)); #endif done: - gc_free (&gc); + gc_free(&gc); } /* @@ -2350,224 +2481,230 @@ void multi_process_float (struct multi_context* m, struct multi_instance* mi) * i.e. client -> server direction. */ bool -multi_process_incoming_link (struct multi_context *m, struct multi_instance *instance, const unsigned int mpp_flags) +multi_process_incoming_link(struct multi_context *m, struct multi_instance *instance, const unsigned int mpp_flags) { - struct gc_arena gc = gc_new (); + struct gc_arena gc = gc_new(); - struct context *c; - struct mroute_addr src, dest; - unsigned int mroute_flags; - struct multi_instance *mi; - bool ret = true; - bool floated = false; + struct context *c; + struct mroute_addr src, dest; + unsigned int mroute_flags; + struct multi_instance *mi; + bool ret = true; + bool floated = false; - if (m->pending) - return true; + if (m->pending) + { + return true; + } - if (!instance) + if (!instance) { #ifdef MULTI_DEBUG_EVENT_LOOP - printf ("TCP/UDP -> TUN [%d]\n", BLEN (&m->top.c2.buf)); + printf("TCP/UDP -> TUN [%d]\n", BLEN(&m->top.c2.buf)); #endif - multi_set_pending (m, multi_get_create_instance_udp (m, &floated)); - } - else - multi_set_pending (m, instance); - - if (m->pending) - { - set_prefix (m->pending); - - /* get instance context */ - c = &m->pending->context; - - if (!instance) - { - /* transfer packet pointer from top-level context buffer to instance */ - c->c2.buf = m->top.c2.buf; - - /* transfer from-addr from top-level context buffer to instance */ - if (!floated) - c->c2.from = m->top.c2.from; - } - - if (BLEN (&c->c2.buf) > 0) - { - struct link_socket_info *lsi; - const uint8_t *orig_buf; - - /* decrypt in instance context */ - - perf_push (PERF_PROC_IN_LINK); - lsi = get_link_socket_info (c); - orig_buf = c->c2.buf.data; - if (process_incoming_link_part1(c, lsi, floated)) - { - if (floated) - { - multi_process_float (m, m->pending); - } - - process_incoming_link_part2(c, lsi, orig_buf); - } - perf_pop (); - - if (TUNNEL_TYPE (m->top.c1.tuntap) == DEV_TYPE_TUN) - { - /* extract packet source and dest addresses */ - mroute_flags = mroute_extract_addr_from_packet (&src, - &dest, - NULL, - NULL, - &c->c2.to_tun, - DEV_TYPE_TUN); - - /* drop packet if extract failed */ - if (!(mroute_flags & MROUTE_EXTRACT_SUCCEEDED)) - { - c->c2.to_tun.len = 0; - } - /* make sure that source address is associated with this client */ - else if (multi_get_instance_by_virtual_addr (m, &src, true) != m->pending) - { - /* IPv6 link-local address (fe80::xxx)? */ - if ( (src.type & MR_ADDR_MASK) == MR_ADDR_IPV6 && - IN6_IS_ADDR_LINKLOCAL (&src.v6.addr) ) - { - /* do nothing, for now. TODO: add address learning */ - } - else - { - msg (D_MULTI_DROPPED, "MULTI: bad source address from client [%s], packet dropped", - mroute_addr_print (&src, &gc)); - } - c->c2.to_tun.len = 0; - } - /* client-to-client communication enabled? */ - else if (m->enable_c2c) - { - /* multicast? */ - if (mroute_flags & MROUTE_EXTRACT_MCAST) - { - /* for now, treat multicast as broadcast */ - multi_bcast (m, &c->c2.to_tun, m->pending, NULL); - } - else /* possible client to client routing */ - { - ASSERT (!(mroute_flags & MROUTE_EXTRACT_BCAST)); - mi = multi_get_instance_by_virtual_addr (m, &dest, true); - - /* if dest addr is a known client, route to it */ - if (mi) - { + multi_set_pending(m, multi_get_create_instance_udp(m, &floated)); + } + else + { + multi_set_pending(m, instance); + } + + if (m->pending) + { + set_prefix(m->pending); + + /* get instance context */ + c = &m->pending->context; + + if (!instance) + { + /* transfer packet pointer from top-level context buffer to instance */ + c->c2.buf = m->top.c2.buf; + + /* transfer from-addr from top-level context buffer to instance */ + if (!floated) + { + c->c2.from = m->top.c2.from; + } + } + + if (BLEN(&c->c2.buf) > 0) + { + struct link_socket_info *lsi; + const uint8_t *orig_buf; + + /* decrypt in instance context */ + + perf_push(PERF_PROC_IN_LINK); + lsi = get_link_socket_info(c); + orig_buf = c->c2.buf.data; + if (process_incoming_link_part1(c, lsi, floated)) + { + if (floated) + { + multi_process_float(m, m->pending); + } + + process_incoming_link_part2(c, lsi, orig_buf); + } + perf_pop(); + + if (TUNNEL_TYPE(m->top.c1.tuntap) == DEV_TYPE_TUN) + { + /* extract packet source and dest addresses */ + mroute_flags = mroute_extract_addr_from_packet(&src, + &dest, + NULL, + NULL, + &c->c2.to_tun, + DEV_TYPE_TUN); + + /* drop packet if extract failed */ + if (!(mroute_flags & MROUTE_EXTRACT_SUCCEEDED)) + { + c->c2.to_tun.len = 0; + } + /* make sure that source address is associated with this client */ + else if (multi_get_instance_by_virtual_addr(m, &src, true) != m->pending) + { + /* IPv6 link-local address (fe80::xxx)? */ + if ( (src.type & MR_ADDR_MASK) == MR_ADDR_IPV6 + && IN6_IS_ADDR_LINKLOCAL(&src.v6.addr) ) + { + /* do nothing, for now. TODO: add address learning */ + } + else + { + msg(D_MULTI_DROPPED, "MULTI: bad source address from client [%s], packet dropped", + mroute_addr_print(&src, &gc)); + } + c->c2.to_tun.len = 0; + } + /* client-to-client communication enabled? */ + else if (m->enable_c2c) + { + /* multicast? */ + if (mroute_flags & MROUTE_EXTRACT_MCAST) + { + /* for now, treat multicast as broadcast */ + multi_bcast(m, &c->c2.to_tun, m->pending, NULL); + } + else /* possible client to client routing */ + { + ASSERT(!(mroute_flags & MROUTE_EXTRACT_BCAST)); + mi = multi_get_instance_by_virtual_addr(m, &dest, true); + + /* if dest addr is a known client, route to it */ + if (mi) + { #ifdef ENABLE_PF - if (!pf_c2c_test (c, &mi->context, "tun_c2c")) - { - msg (D_PF_DROPPED, "PF: client -> client[%s] packet dropped by TUN packet filter", - mi_prefix (mi)); - } - else + if (!pf_c2c_test(c, &mi->context, "tun_c2c")) + { + msg(D_PF_DROPPED, "PF: client -> client[%s] packet dropped by TUN packet filter", + mi_prefix(mi)); + } + else #endif - { - multi_unicast (m, &c->c2.to_tun, mi); - register_activity (c, BLEN(&c->c2.to_tun)); - } - c->c2.to_tun.len = 0; - } - } - } + { + multi_unicast(m, &c->c2.to_tun, mi); + register_activity(c, BLEN(&c->c2.to_tun)); + } + c->c2.to_tun.len = 0; + } + } + } #ifdef ENABLE_PF - if (c->c2.to_tun.len && !pf_addr_test (c, &dest, "tun_dest_addr")) - { - msg (D_PF_DROPPED, "PF: client -> addr[%s] packet dropped by TUN packet filter", - mroute_addr_print_ex (&dest, MAPF_SHOW_ARP, &gc)); - c->c2.to_tun.len = 0; - } + if (c->c2.to_tun.len && !pf_addr_test(c, &dest, "tun_dest_addr")) + { + msg(D_PF_DROPPED, "PF: client -> addr[%s] packet dropped by TUN packet filter", + mroute_addr_print_ex(&dest, MAPF_SHOW_ARP, &gc)); + c->c2.to_tun.len = 0; + } #endif - } - else if (TUNNEL_TYPE (m->top.c1.tuntap) == DEV_TYPE_TAP) - { + } + else if (TUNNEL_TYPE(m->top.c1.tuntap) == DEV_TYPE_TAP) + { #ifdef ENABLE_PF - struct mroute_addr edest; - mroute_addr_reset (&edest); + struct mroute_addr edest; + mroute_addr_reset(&edest); #endif - /* extract packet source and dest addresses */ - mroute_flags = mroute_extract_addr_from_packet (&src, - &dest, - NULL, + /* extract packet source and dest addresses */ + mroute_flags = mroute_extract_addr_from_packet(&src, + &dest, + NULL, #ifdef ENABLE_PF - &edest, + &edest, #else - NULL, + NULL, #endif - &c->c2.to_tun, - DEV_TYPE_TAP); - - if (mroute_flags & MROUTE_EXTRACT_SUCCEEDED) - { - if (multi_learn_addr (m, m->pending, &src, 0) == m->pending) - { - /* check for broadcast */ - if (m->enable_c2c) - { - if (mroute_flags & (MROUTE_EXTRACT_BCAST|MROUTE_EXTRACT_MCAST)) - { - multi_bcast (m, &c->c2.to_tun, m->pending, NULL); - } - else /* try client-to-client routing */ - { - mi = multi_get_instance_by_virtual_addr (m, &dest, false); - - /* if dest addr is a known client, route to it */ - if (mi) - { + &c->c2.to_tun, + DEV_TYPE_TAP); + + if (mroute_flags & MROUTE_EXTRACT_SUCCEEDED) + { + if (multi_learn_addr(m, m->pending, &src, 0) == m->pending) + { + /* check for broadcast */ + if (m->enable_c2c) + { + if (mroute_flags & (MROUTE_EXTRACT_BCAST|MROUTE_EXTRACT_MCAST)) + { + multi_bcast(m, &c->c2.to_tun, m->pending, NULL); + } + else /* try client-to-client routing */ + { + mi = multi_get_instance_by_virtual_addr(m, &dest, false); + + /* if dest addr is a known client, route to it */ + if (mi) + { #ifdef ENABLE_PF - if (!pf_c2c_test (c, &mi->context, "tap_c2c")) - { - msg (D_PF_DROPPED, "PF: client -> client[%s] packet dropped by TAP packet filter", - mi_prefix (mi)); - } - else + if (!pf_c2c_test(c, &mi->context, "tap_c2c")) + { + msg(D_PF_DROPPED, "PF: client -> client[%s] packet dropped by TAP packet filter", + mi_prefix(mi)); + } + else #endif - { - multi_unicast (m, &c->c2.to_tun, mi); - register_activity (c, BLEN(&c->c2.to_tun)); - } - c->c2.to_tun.len = 0; - } - } - } + { + multi_unicast(m, &c->c2.to_tun, mi); + register_activity(c, BLEN(&c->c2.to_tun)); + } + c->c2.to_tun.len = 0; + } + } + } #ifdef ENABLE_PF - if (c->c2.to_tun.len && !pf_addr_test (c, &edest, "tap_dest_addr")) - { - msg (D_PF_DROPPED, "PF: client -> addr[%s] packet dropped by TAP packet filter", - mroute_addr_print_ex (&edest, MAPF_SHOW_ARP, &gc)); - c->c2.to_tun.len = 0; - } + if (c->c2.to_tun.len && !pf_addr_test(c, &edest, "tap_dest_addr")) + { + msg(D_PF_DROPPED, "PF: client -> addr[%s] packet dropped by TAP packet filter", + mroute_addr_print_ex(&edest, MAPF_SHOW_ARP, &gc)); + c->c2.to_tun.len = 0; + } #endif - } - else - { - msg (D_MULTI_DROPPED, "MULTI: bad source address from client [%s], packet dropped", - mroute_addr_print (&src, &gc)); - c->c2.to_tun.len = 0; - } - } - else - { - c->c2.to_tun.len = 0; - } - } - } + } + else + { + msg(D_MULTI_DROPPED, "MULTI: bad source address from client [%s], packet dropped", + mroute_addr_print(&src, &gc)); + c->c2.to_tun.len = 0; + } + } + else + { + c->c2.to_tun.len = 0; + } + } + } - /* postprocess and set wakeup */ - ret = multi_process_post (m, m->pending, mpp_flags); + /* postprocess and set wakeup */ + ret = multi_process_post(m, m->pending, mpp_flags); - clear_prefix (); + clear_prefix(); } - gc_free (&gc); - return ret; + gc_free(&gc); + return ret; } /* @@ -2575,115 +2712,117 @@ multi_process_incoming_link (struct multi_context *m, struct multi_instance *ins * i.e. server -> client direction. */ bool -multi_process_incoming_tun (struct multi_context *m, const unsigned int mpp_flags) +multi_process_incoming_tun(struct multi_context *m, const unsigned int mpp_flags) { - struct gc_arena gc = gc_new (); - bool ret = true; + struct gc_arena gc = gc_new(); + bool ret = true; - if (BLEN (&m->top.c2.buf) > 0) + if (BLEN(&m->top.c2.buf) > 0) { - unsigned int mroute_flags; - struct mroute_addr src, dest; - const int dev_type = TUNNEL_TYPE (m->top.c1.tuntap); + unsigned int mroute_flags; + struct mroute_addr src, dest; + const int dev_type = TUNNEL_TYPE(m->top.c1.tuntap); #ifdef ENABLE_PF - struct mroute_addr esrc, *e1, *e2; - if (dev_type == DEV_TYPE_TUN) - { - e1 = NULL; - e2 = &src; - } - else - { - e1 = e2 = &esrc; - mroute_addr_reset (&esrc); - } + struct mroute_addr esrc, *e1, *e2; + if (dev_type == DEV_TYPE_TUN) + { + e1 = NULL; + e2 = &src; + } + else + { + e1 = e2 = &esrc; + mroute_addr_reset(&esrc); + } #endif #ifdef MULTI_DEBUG_EVENT_LOOP - printf ("TUN -> TCP/UDP [%d]\n", BLEN (&m->top.c2.buf)); + printf("TUN -> TCP/UDP [%d]\n", BLEN(&m->top.c2.buf)); #endif - if (m->pending) - return true; + if (m->pending) + { + return true; + } - /* - * Route an incoming tun/tap packet to - * the appropriate multi_instance object. - */ + /* + * Route an incoming tun/tap packet to + * the appropriate multi_instance object. + */ - mroute_flags = mroute_extract_addr_from_packet (&src, - &dest, + mroute_flags = mroute_extract_addr_from_packet(&src, + &dest, #ifdef ENABLE_PF - e1, + e1, #else - NULL, + NULL, #endif - NULL, - &m->top.c2.buf, - dev_type); - - if (mroute_flags & MROUTE_EXTRACT_SUCCEEDED) - { - struct context *c; - - /* broadcast or multicast dest addr? */ - if (mroute_flags & (MROUTE_EXTRACT_BCAST|MROUTE_EXTRACT_MCAST)) - { - /* for now, treat multicast as broadcast */ + NULL, + &m->top.c2.buf, + dev_type); + + if (mroute_flags & MROUTE_EXTRACT_SUCCEEDED) + { + struct context *c; + + /* broadcast or multicast dest addr? */ + if (mroute_flags & (MROUTE_EXTRACT_BCAST|MROUTE_EXTRACT_MCAST)) + { + /* for now, treat multicast as broadcast */ #ifdef ENABLE_PF - multi_bcast (m, &m->top.c2.buf, NULL, e2); + multi_bcast(m, &m->top.c2.buf, NULL, e2); #else - multi_bcast (m, &m->top.c2.buf, NULL, NULL); + multi_bcast(m, &m->top.c2.buf, NULL, NULL); #endif - } - else - { - multi_set_pending (m, multi_get_instance_by_virtual_addr (m, &dest, dev_type == DEV_TYPE_TUN)); - - if (m->pending) - { - /* get instance context */ - c = &m->pending->context; - - set_prefix (m->pending); + } + else + { + multi_set_pending(m, multi_get_instance_by_virtual_addr(m, &dest, dev_type == DEV_TYPE_TUN)); + + if (m->pending) + { + /* get instance context */ + c = &m->pending->context; + + set_prefix(m->pending); #ifdef ENABLE_PF - if (!pf_addr_test (c, e2, "tun_tap_src_addr")) - { - msg (D_PF_DROPPED, "PF: addr[%s] -> client packet dropped by packet filter", - mroute_addr_print_ex (&src, MAPF_SHOW_ARP, &gc)); - buf_reset_len (&c->c2.buf); - } - else + if (!pf_addr_test(c, e2, "tun_tap_src_addr")) + { + msg(D_PF_DROPPED, "PF: addr[%s] -> client packet dropped by packet filter", + mroute_addr_print_ex(&src, MAPF_SHOW_ARP, &gc)); + buf_reset_len(&c->c2.buf); + } + else #endif - { - if (multi_output_queue_ready (m, m->pending)) - { - /* transfer packet pointer from top-level context buffer to instance */ - c->c2.buf = m->top.c2.buf; - } - else - { - /* drop packet */ - msg (D_MULTI_DROPPED, "MULTI: packet dropped due to output saturation (multi_process_incoming_tun)"); - buf_reset_len (&c->c2.buf); - } - } - - /* encrypt in instance context */ - process_incoming_tun (c); - - /* postprocess and set wakeup */ - ret = multi_process_post (m, m->pending, mpp_flags); - - clear_prefix (); - } - } - } - } - gc_free (&gc); - return ret; + { + if (multi_output_queue_ready(m, m->pending)) + { + /* transfer packet pointer from top-level context buffer to instance */ + c->c2.buf = m->top.c2.buf; + } + else + { + /* drop packet */ + msg(D_MULTI_DROPPED, "MULTI: packet dropped due to output saturation (multi_process_incoming_tun)"); + buf_reset_len(&c->c2.buf); + } + } + + /* encrypt in instance context */ + process_incoming_tun(c); + + /* postprocess and set wakeup */ + ret = multi_process_post(m, m->pending, mpp_flags); + + clear_prefix(); + } + } + } + } + gc_free(&gc); + return ret; } /* @@ -2691,30 +2830,32 @@ multi_process_incoming_tun (struct multi_context *m, const unsigned int mpp_flag * queue. */ struct multi_instance * -multi_get_queue (struct mbuf_set *ms) +multi_get_queue(struct mbuf_set *ms) { - struct mbuf_item item; + struct mbuf_item item; - if (mbuf_extract_item (ms, &item)) /* cleartext IP packet */ + if (mbuf_extract_item(ms, &item)) /* cleartext IP packet */ { - unsigned int pip_flags = PIPV4_PASSTOS; + unsigned int pip_flags = PIPV4_PASSTOS; - set_prefix (item.instance); - item.instance->context.c2.buf = item.buffer->buf; - if (item.buffer->flags & MF_UNICAST) /* --mssfix doesn't make sense for broadcast or multicast */ - pip_flags |= PIP_MSSFIX; - process_ip_header (&item.instance->context, pip_flags, &item.instance->context.c2.buf); - encrypt_sign (&item.instance->context, true); - mbuf_free_buf (item.buffer); + set_prefix(item.instance); + item.instance->context.c2.buf = item.buffer->buf; + if (item.buffer->flags & MF_UNICAST) /* --mssfix doesn't make sense for broadcast or multicast */ + { + pip_flags |= PIP_MSSFIX; + } + process_ip_header(&item.instance->context, pip_flags, &item.instance->context.c2.buf); + encrypt_sign(&item.instance->context, true); + mbuf_free_buf(item.buffer); - dmsg (D_MULTI_DEBUG, "MULTI: C2C/MCAST/BCAST"); + dmsg(D_MULTI_DEBUG, "MULTI: C2C/MCAST/BCAST"); - clear_prefix (); - return item.instance; + clear_prefix(); + return item.instance; } - else + else { - return NULL; + return NULL; } } @@ -2723,52 +2864,52 @@ multi_get_queue (struct mbuf_set *ms) * client instance object needs timer-based service. */ bool -multi_process_timeout (struct multi_context *m, const unsigned int mpp_flags) +multi_process_timeout(struct multi_context *m, const unsigned int mpp_flags) { - bool ret = true; + bool ret = true; #ifdef MULTI_DEBUG_EVENT_LOOP - printf ("%s -> TIMEOUT\n", id(m->earliest_wakeup)); + printf("%s -> TIMEOUT\n", id(m->earliest_wakeup)); #endif - /* instance marked for wakeup? */ - if (m->earliest_wakeup) + /* instance marked for wakeup? */ + if (m->earliest_wakeup) { - if (m->earliest_wakeup == (struct multi_instance*)&m->deferred_shutdown_signal) - { - schedule_remove_entry(m->schedule, (struct schedule_entry*) &m->deferred_shutdown_signal); - throw_signal(m->deferred_shutdown_signal.signal_received); - } - else - { - set_prefix (m->earliest_wakeup); - ret = multi_process_post (m, m->earliest_wakeup, mpp_flags); - clear_prefix (); - } - m->earliest_wakeup = NULL; + if (m->earliest_wakeup == (struct multi_instance *)&m->deferred_shutdown_signal) + { + schedule_remove_entry(m->schedule, (struct schedule_entry *) &m->deferred_shutdown_signal); + throw_signal(m->deferred_shutdown_signal.signal_received); + } + else + { + set_prefix(m->earliest_wakeup); + ret = multi_process_post(m, m->earliest_wakeup, mpp_flags); + clear_prefix(); + } + m->earliest_wakeup = NULL; } - return ret; + return ret; } /* * Drop a TUN/TAP outgoing packet.. */ void -multi_process_drop_outgoing_tun (struct multi_context *m, const unsigned int mpp_flags) +multi_process_drop_outgoing_tun(struct multi_context *m, const unsigned int mpp_flags) { - struct multi_instance *mi = m->pending; + struct multi_instance *mi = m->pending; - ASSERT (mi); + ASSERT(mi); - set_prefix (mi); + set_prefix(mi); - msg (D_MULTI_ERRORS, "MULTI: Outgoing TUN queue full, dropped packet len=%d", - mi->context.c2.to_tun.len); + msg(D_MULTI_ERRORS, "MULTI: Outgoing TUN queue full, dropped packet len=%d", + mi->context.c2.to_tun.len); - buf_reset (&mi->context.c2.to_tun); + buf_reset(&mi->context.c2.to_tun); - multi_process_post (m, mi, mpp_flags); - clear_prefix (); + multi_process_post(m, mi, mpp_flags); + clear_prefix(); } /* @@ -2776,13 +2917,13 @@ multi_process_drop_outgoing_tun (struct multi_context *m, const unsigned int mpp */ void -route_quota_exceeded (const struct multi_context *m, const struct multi_instance *mi) +route_quota_exceeded(const struct multi_context *m, const struct multi_instance *mi) { - struct gc_arena gc = gc_new (); - msg (D_ROUTE_QUOTA, "MULTI ROUTE: route quota (%d) exceeded for %s (see --max-routes-per-client option)", - mi->context.options.max_routes_per_client, - multi_instance_string (mi, false, &gc)); - gc_free (&gc); + struct gc_arena gc = gc_new(); + msg(D_ROUTE_QUOTA, "MULTI ROUTE: route quota (%d) exceeded for %s (see --max-routes-per-client option)", + mi->context.options.max_routes_per_client, + multi_instance_string(mi, false, &gc)); + gc_free(&gc); } #ifdef ENABLE_DEBUG @@ -2790,124 +2931,128 @@ route_quota_exceeded (const struct multi_context *m, const struct multi_instance * Flood clients with random packets */ static void -gremlin_flood_clients (struct multi_context *m) +gremlin_flood_clients(struct multi_context *m) { - const int level = GREMLIN_PACKET_FLOOD_LEVEL (m->top.options.gremlin); - if (level) + const int level = GREMLIN_PACKET_FLOOD_LEVEL(m->top.options.gremlin); + if (level) { - struct gc_arena gc = gc_new (); - struct buffer buf = alloc_buf_gc (BUF_SIZE (&m->top.c2.frame), &gc); - struct packet_flood_parms parm = get_packet_flood_parms (level); - int i; + struct gc_arena gc = gc_new(); + struct buffer buf = alloc_buf_gc(BUF_SIZE(&m->top.c2.frame), &gc); + struct packet_flood_parms parm = get_packet_flood_parms(level); + int i; - ASSERT (buf_init (&buf, FRAME_HEADROOM (&m->top.c2.frame))); - parm.packet_size = min_int (parm.packet_size, MAX_RW_SIZE_TUN (&m->top.c2.frame)); + ASSERT(buf_init(&buf, FRAME_HEADROOM(&m->top.c2.frame))); + parm.packet_size = min_int(parm.packet_size, MAX_RW_SIZE_TUN(&m->top.c2.frame)); - msg (D_GREMLIN, "GREMLIN_FLOOD_CLIENTS: flooding clients with %d packets of size %d", - parm.n_packets, - parm.packet_size); + msg(D_GREMLIN, "GREMLIN_FLOOD_CLIENTS: flooding clients with %d packets of size %d", + parm.n_packets, + parm.packet_size); - for (i = 0; i < parm.packet_size; ++i) - ASSERT (buf_write_u8 (&buf, get_random () & 0xFF)); + for (i = 0; i < parm.packet_size; ++i) + ASSERT(buf_write_u8(&buf, get_random() & 0xFF)); - for (i = 0; i < parm.n_packets; ++i) - multi_bcast (m, &buf, NULL, NULL); + for (i = 0; i < parm.n_packets; ++i) + multi_bcast(m, &buf, NULL, NULL); - gc_free (&gc); + gc_free(&gc); } } -#endif +#endif /* ifdef ENABLE_DEBUG */ bool -stale_route_check_trigger (struct multi_context *m) +stale_route_check_trigger(struct multi_context *m) { - struct timeval null; - CLEAR (null); - return event_timeout_trigger (&m->stale_routes_check_et, &null, ETT_DEFAULT); + struct timeval null; + CLEAR(null); + return event_timeout_trigger(&m->stale_routes_check_et, &null, ETT_DEFAULT); } /* * Process timers in the top-level context */ void -multi_process_per_second_timers_dowork (struct multi_context *m) +multi_process_per_second_timers_dowork(struct multi_context *m) { - /* possibly reap instances/routes in vhash */ - multi_reap_process (m); + /* possibly reap instances/routes in vhash */ + multi_reap_process(m); - /* possibly print to status log */ - if (m->top.c1.status_output) + /* possibly print to status log */ + if (m->top.c1.status_output) { - if (status_trigger (m->top.c1.status_output)) - multi_print_status (m, m->top.c1.status_output, m->status_file_version); + if (status_trigger(m->top.c1.status_output)) + { + multi_print_status(m, m->top.c1.status_output, m->status_file_version); + } } - /* possibly flush ifconfig-pool file */ - multi_ifconfig_pool_persist (m, false); + /* possibly flush ifconfig-pool file */ + multi_ifconfig_pool_persist(m, false); #ifdef ENABLE_DEBUG - gremlin_flood_clients (m); + gremlin_flood_clients(m); #endif - /* Should we check for stale routes? */ - if (m->top.options.stale_routes_check_interval && stale_route_check_trigger (m)) - check_stale_routes (m); + /* Should we check for stale routes? */ + if (m->top.options.stale_routes_check_interval && stale_route_check_trigger(m)) + { + check_stale_routes(m); + } } void -multi_top_init (struct multi_context *m, const struct context *top) +multi_top_init(struct multi_context *m, const struct context *top) { - inherit_context_top (&m->top, top); - m->top.c2.buffers = init_context_buffers (&top->c2.frame); + inherit_context_top(&m->top, top); + m->top.c2.buffers = init_context_buffers(&top->c2.frame); } void -multi_top_free (struct multi_context *m) +multi_top_free(struct multi_context *m) { - close_context (&m->top, -1, CC_GC_FREE); - free_context_buffers (m->top.c2.buffers); + close_context(&m->top, -1, CC_GC_FREE); + free_context_buffers(m->top.c2.buffers); } static bool is_exit_restart(int sig) { - return (sig == SIGUSR1 || sig == SIGTERM || sig == SIGHUP || sig == SIGINT); + return (sig == SIGUSR1 || sig == SIGTERM || sig == SIGHUP || sig == SIGINT); } static void multi_push_restart_schedule_exit(struct multi_context *m, bool next_server) { - struct hash_iterator hi; - struct hash_element *he; - struct timeval tv; + struct hash_iterator hi; + struct hash_element *he; + struct timeval tv; - /* tell all clients to restart */ - hash_iterator_init (m->iter, &hi); - while ((he = hash_iterator_next (&hi))) + /* tell all clients to restart */ + hash_iterator_init(m->iter, &hi); + while ((he = hash_iterator_next(&hi))) { - struct multi_instance *mi = (struct multi_instance *) he->value; - if (!mi->halt) + struct multi_instance *mi = (struct multi_instance *) he->value; + if (!mi->halt) { - send_control_channel_string (&mi->context, next_server ? "RESTART,[N]" : "RESTART", D_PUSH); - multi_schedule_context_wakeup(m, mi); + send_control_channel_string(&mi->context, next_server ? "RESTART,[N]" : "RESTART", D_PUSH); + multi_schedule_context_wakeup(m, mi); } } - hash_iterator_free (&hi); + hash_iterator_free(&hi); - /* reschedule signal */ - ASSERT (!openvpn_gettimeofday (&m->deferred_shutdown_signal.wakeup, NULL)); - tv.tv_sec = 2; - tv.tv_usec = 0; - tv_add (&m->deferred_shutdown_signal.wakeup, &tv); + /* reschedule signal */ + ASSERT(!openvpn_gettimeofday(&m->deferred_shutdown_signal.wakeup, NULL)); + tv.tv_sec = 2; + tv.tv_usec = 0; + tv_add(&m->deferred_shutdown_signal.wakeup, &tv); - m->deferred_shutdown_signal.signal_received = m->top.sig->signal_received; + m->deferred_shutdown_signal.signal_received = m->top.sig->signal_received; - schedule_add_entry (m->schedule, - (struct schedule_entry *) &m->deferred_shutdown_signal, - &m->deferred_shutdown_signal.wakeup, - compute_wakeup_sigma (&m->deferred_shutdown_signal.wakeup)); + schedule_add_entry(m->schedule, + (struct schedule_entry *) &m->deferred_shutdown_signal, + &m->deferred_shutdown_signal.wakeup, + compute_wakeup_sigma(&m->deferred_shutdown_signal.wakeup)); - m->top.sig->signal_received = 0; + m->top.sig->signal_received = 0; } /* @@ -2915,25 +3060,25 @@ multi_push_restart_schedule_exit(struct multi_context *m, bool next_server) * false if it should continue. */ bool -multi_process_signal (struct multi_context *m) +multi_process_signal(struct multi_context *m) { - if (m->top.sig->signal_received == SIGUSR2) + if (m->top.sig->signal_received == SIGUSR2) { - struct status_output *so = status_open (NULL, 0, M_INFO, NULL, 0); - multi_print_status (m, so, m->status_file_version); - status_close (so); - m->top.sig->signal_received = 0; - return false; + struct status_output *so = status_open(NULL, 0, M_INFO, NULL, 0); + multi_print_status(m, so, m->status_file_version); + status_close(so); + m->top.sig->signal_received = 0; + return false; } - else if (proto_is_dgram(m->top.options.ce.proto) && - is_exit_restart(m->top.sig->signal_received) && - (m->deferred_shutdown_signal.signal_received == 0) && - m->top.options.ce.explicit_exit_notification != 0) + else if (proto_is_dgram(m->top.options.ce.proto) + && is_exit_restart(m->top.sig->signal_received) + && (m->deferred_shutdown_signal.signal_received == 0) + && m->top.options.ce.explicit_exit_notification != 0) { - multi_push_restart_schedule_exit(m, m->top.options.ce.explicit_exit_notification == 2); - return false; + multi_push_restart_schedule_exit(m, m->top.options.ce.explicit_exit_notification == 2); + return false; } - return true; + return true; } /* @@ -2941,20 +3086,20 @@ multi_process_signal (struct multi_context *m) * reception of a soft signal. */ void -multi_close_instance_on_signal (struct multi_context *m, struct multi_instance *mi) +multi_close_instance_on_signal(struct multi_context *m, struct multi_instance *mi) { - remap_signal (&mi->context); - set_prefix (mi); - print_signal (mi->context.sig, "client-instance", D_MULTI_LOW); - clear_prefix (); - multi_close_instance (m, mi, false); + remap_signal(&mi->context); + set_prefix(mi); + print_signal(mi->context.sig, "client-instance", D_MULTI_LOW); + clear_prefix(); + multi_close_instance(m, mi, false); } static void -multi_signal_instance (struct multi_context *m, struct multi_instance *mi, const int sig) +multi_signal_instance(struct multi_context *m, struct multi_instance *mi, const int sig) { - mi->context.sig->signal_received = sig; - multi_close_instance_on_signal (m, mi); + mi->context.sig->signal_received = sig; + multi_close_instance_on_signal(m, mi); } /* @@ -2964,246 +3109,272 @@ multi_signal_instance (struct multi_context *m, struct multi_instance *mi, const #ifdef ENABLE_MANAGEMENT static void -management_callback_status (void *arg, const int version, struct status_output *so) +management_callback_status(void *arg, const int version, struct status_output *so) { - struct multi_context *m = (struct multi_context *) arg; + struct multi_context *m = (struct multi_context *) arg; - if (!version) - multi_print_status (m, so, m->status_file_version); - else - multi_print_status (m, so, version); + if (!version) + { + multi_print_status(m, so, m->status_file_version); + } + else + { + multi_print_status(m, so, version); + } } static int -management_callback_n_clients (void *arg) +management_callback_n_clients(void *arg) { - struct multi_context *m = (struct multi_context *) arg; - return m->n_clients; + struct multi_context *m = (struct multi_context *) arg; + return m->n_clients; } static int -management_callback_kill_by_cn (void *arg, const char *del_cn) +management_callback_kill_by_cn(void *arg, const char *del_cn) { - struct multi_context *m = (struct multi_context *) arg; - struct hash_iterator hi; - struct hash_element *he; - int count = 0; + struct multi_context *m = (struct multi_context *) arg; + struct hash_iterator hi; + struct hash_element *he; + int count = 0; - hash_iterator_init (m->iter, &hi); - while ((he = hash_iterator_next (&hi))) + hash_iterator_init(m->iter, &hi); + while ((he = hash_iterator_next(&hi))) { - struct multi_instance *mi = (struct multi_instance *) he->value; - if (!mi->halt) - { - const char *cn = tls_common_name (mi->context.c2.tls_multi, false); - if (cn && !strcmp (cn, del_cn)) - { - multi_signal_instance (m, mi, SIGTERM); - ++count; - } - } + struct multi_instance *mi = (struct multi_instance *) he->value; + if (!mi->halt) + { + const char *cn = tls_common_name(mi->context.c2.tls_multi, false); + if (cn && !strcmp(cn, del_cn)) + { + multi_signal_instance(m, mi, SIGTERM); + ++count; + } + } } - hash_iterator_free (&hi); - return count; + hash_iterator_free(&hi); + return count; } static int -management_callback_kill_by_addr (void *arg, const in_addr_t addr, const int port) -{ - struct multi_context *m = (struct multi_context *) arg; - struct hash_iterator hi; - struct hash_element *he; - struct openvpn_sockaddr saddr; - struct mroute_addr maddr; - int count = 0; - - CLEAR (saddr); - saddr.addr.in4.sin_family = AF_INET; - saddr.addr.in4.sin_addr.s_addr = htonl (addr); - saddr.addr.in4.sin_port = htons (port); - if (mroute_extract_openvpn_sockaddr (&maddr, &saddr, true)) - { - hash_iterator_init (m->iter, &hi); - while ((he = hash_iterator_next (&hi))) - { - struct multi_instance *mi = (struct multi_instance *) he->value; - if (!mi->halt && mroute_addr_equal (&maddr, &mi->real)) - { - multi_signal_instance (m, mi, SIGTERM); - ++count; - } - } - hash_iterator_free (&hi); - } - return count; +management_callback_kill_by_addr(void *arg, const in_addr_t addr, const int port) +{ + struct multi_context *m = (struct multi_context *) arg; + struct hash_iterator hi; + struct hash_element *he; + struct openvpn_sockaddr saddr; + struct mroute_addr maddr; + int count = 0; + + CLEAR(saddr); + saddr.addr.in4.sin_family = AF_INET; + saddr.addr.in4.sin_addr.s_addr = htonl(addr); + saddr.addr.in4.sin_port = htons(port); + if (mroute_extract_openvpn_sockaddr(&maddr, &saddr, true)) + { + hash_iterator_init(m->iter, &hi); + while ((he = hash_iterator_next(&hi))) + { + struct multi_instance *mi = (struct multi_instance *) he->value; + if (!mi->halt && mroute_addr_equal(&maddr, &mi->real)) + { + multi_signal_instance(m, mi, SIGTERM); + ++count; + } + } + hash_iterator_free(&hi); + } + return count; } static void -management_delete_event (void *arg, event_t event) +management_delete_event(void *arg, event_t event) { - struct multi_context *m = (struct multi_context *) arg; - if (m->mtcp) - multi_tcp_delete_event (m->mtcp, event); + struct multi_context *m = (struct multi_context *) arg; + if (m->mtcp) + { + multi_tcp_delete_event(m->mtcp, event); + } } -#endif +#endif /* ifdef ENABLE_MANAGEMENT */ #ifdef MANAGEMENT_DEF_AUTH static struct multi_instance * -lookup_by_cid (struct multi_context *m, const unsigned long cid) +lookup_by_cid(struct multi_context *m, const unsigned long cid) { - if (m) + if (m) { - struct multi_instance *mi = (struct multi_instance *) hash_lookup (m->cid_hash, &cid); - if (mi && !mi->halt) - return mi; + struct multi_instance *mi = (struct multi_instance *) hash_lookup(m->cid_hash, &cid); + if (mi && !mi->halt) + { + return mi; + } } - return NULL; + return NULL; } static bool -management_kill_by_cid (void *arg, const unsigned long cid, const char *kill_msg) +management_kill_by_cid(void *arg, const unsigned long cid, const char *kill_msg) { - struct multi_context *m = (struct multi_context *) arg; - struct multi_instance *mi = lookup_by_cid (m, cid); - if (mi) + struct multi_context *m = (struct multi_context *) arg; + struct multi_instance *mi = lookup_by_cid(m, cid); + if (mi) { - send_restart (&mi->context, kill_msg); /* was: multi_signal_instance (m, mi, SIGTERM); */ - multi_schedule_context_wakeup(m, mi); - return true; + send_restart(&mi->context, kill_msg); /* was: multi_signal_instance (m, mi, SIGTERM); */ + multi_schedule_context_wakeup(m, mi); + return true; + } + else + { + return false; } - else - return false; } static bool -management_client_auth (void *arg, - const unsigned long cid, - const unsigned int mda_key_id, - const bool auth, - const char *reason, - const char *client_reason, - struct buffer_list *cc_config) /* ownership transferred */ -{ - struct multi_context *m = (struct multi_context *) arg; - struct multi_instance *mi = lookup_by_cid (m, cid); - bool cc_config_owned = true; - bool ret = false; - - if (mi) - { - ret = tls_authenticate_key (mi->context.c2.tls_multi, mda_key_id, auth, client_reason); - if (ret) - { - if (auth) - { - if (!mi->connection_established_flag) - { - set_cc_config (mi, cc_config); - cc_config_owned = false; - } - } - else - { - if (reason) - msg (D_MULTI_LOW, "MULTI: connection rejected: %s, CLI:%s", reason, np(client_reason)); - if (mi->connection_established_flag) - { - send_auth_failed (&mi->context, client_reason); /* mid-session reauth failed */ - multi_schedule_context_wakeup(m, mi); - } - } - } - } - if (cc_config_owned && cc_config) - buffer_list_free (cc_config); - return ret; +management_client_auth(void *arg, + const unsigned long cid, + const unsigned int mda_key_id, + const bool auth, + const char *reason, + const char *client_reason, + struct buffer_list *cc_config) /* ownership transferred */ +{ + struct multi_context *m = (struct multi_context *) arg; + struct multi_instance *mi = lookup_by_cid(m, cid); + bool cc_config_owned = true; + bool ret = false; + + if (mi) + { + ret = tls_authenticate_key(mi->context.c2.tls_multi, mda_key_id, auth, client_reason); + if (ret) + { + if (auth) + { + if (!mi->connection_established_flag) + { + set_cc_config(mi, cc_config); + cc_config_owned = false; + } + } + else + { + if (reason) + { + msg(D_MULTI_LOW, "MULTI: connection rejected: %s, CLI:%s", reason, np(client_reason)); + } + if (mi->connection_established_flag) + { + send_auth_failed(&mi->context, client_reason); /* mid-session reauth failed */ + multi_schedule_context_wakeup(m, mi); + } + } + } + } + if (cc_config_owned && cc_config) + { + buffer_list_free(cc_config); + } + return ret; } static char * -management_get_peer_info (void *arg, const unsigned long cid) +management_get_peer_info(void *arg, const unsigned long cid) { - struct multi_context *m = (struct multi_context *) arg; - struct multi_instance *mi = lookup_by_cid (m, cid); - char *ret = NULL; + struct multi_context *m = (struct multi_context *) arg; + struct multi_instance *mi = lookup_by_cid(m, cid); + char *ret = NULL; - if (mi) - ret = tls_get_peer_info (mi->context.c2.tls_multi); + if (mi) + { + ret = tls_get_peer_info(mi->context.c2.tls_multi); + } - return ret; + return ret; } -#endif +#endif /* ifdef MANAGEMENT_DEF_AUTH */ #ifdef MANAGEMENT_PF static bool -management_client_pf (void *arg, - const unsigned long cid, - struct buffer_list *pf_config) /* ownership transferred */ +management_client_pf(void *arg, + const unsigned long cid, + struct buffer_list *pf_config) /* ownership transferred */ { - struct multi_context *m = (struct multi_context *) arg; - struct multi_instance *mi = lookup_by_cid (m, cid); - bool ret = false; + struct multi_context *m = (struct multi_context *) arg; + struct multi_instance *mi = lookup_by_cid(m, cid); + bool ret = false; - if (mi && pf_config) - ret = pf_load_from_buffer_list (&mi->context, pf_config); + if (mi && pf_config) + { + ret = pf_load_from_buffer_list(&mi->context, pf_config); + } - if (pf_config) - buffer_list_free (pf_config); - return ret; + if (pf_config) + { + buffer_list_free(pf_config); + } + return ret; } -#endif +#endif /* ifdef MANAGEMENT_PF */ void -init_management_callback_multi (struct multi_context *m) +init_management_callback_multi(struct multi_context *m) { #ifdef ENABLE_MANAGEMENT - if (management) - { - struct management_callback cb; - CLEAR (cb); - cb.arg = m; - cb.flags = MCF_SERVER; - cb.status = management_callback_status; - cb.show_net = management_show_net_callback; - cb.kill_by_cn = management_callback_kill_by_cn; - cb.kill_by_addr = management_callback_kill_by_addr; - cb.delete_event = management_delete_event; - cb.n_clients = management_callback_n_clients; + if (management) + { + struct management_callback cb; + CLEAR(cb); + cb.arg = m; + cb.flags = MCF_SERVER; + cb.status = management_callback_status; + cb.show_net = management_show_net_callback; + cb.kill_by_cn = management_callback_kill_by_cn; + cb.kill_by_addr = management_callback_kill_by_addr; + cb.delete_event = management_delete_event; + cb.n_clients = management_callback_n_clients; #ifdef MANAGEMENT_DEF_AUTH - cb.kill_by_cid = management_kill_by_cid; - cb.client_auth = management_client_auth; - cb.get_peer_info = management_get_peer_info; + cb.kill_by_cid = management_kill_by_cid; + cb.client_auth = management_client_auth; + cb.get_peer_info = management_get_peer_info; #endif #ifdef MANAGEMENT_PF - cb.client_pf = management_client_pf; + cb.client_pf = management_client_pf; #endif - management_set_callback (management, &cb); + management_set_callback(management, &cb); } -#endif +#endif /* ifdef ENABLE_MANAGEMENT */ } void -uninit_management_callback_multi (struct multi_context *m) +uninit_management_callback_multi(struct multi_context *m) { - uninit_management_callback (); + uninit_management_callback(); } /* * Top level event loop. */ void -tunnel_server (struct context *top) +tunnel_server(struct context *top) { - ASSERT (top->options.mode == MODE_SERVER); + ASSERT(top->options.mode == MODE_SERVER); - if (proto_is_dgram(top->options.ce.proto)) - tunnel_server_udp(top); - else - tunnel_server_tcp(top); + if (proto_is_dgram(top->options.ce.proto)) + { + tunnel_server_udp(top); + } + else + { + tunnel_server_tcp(top); + } } -#else -static void dummy(void) {} +#else /* if P2MP_SERVER */ +static void +dummy(void) { +} #endif /* P2MP_SERVER */ diff --git a/src/openvpn/multi.h b/src/openvpn/multi.h index 0d369f34856..7508fe27f28 100644 --- a/src/openvpn/multi.h +++ b/src/openvpn/multi.h @@ -51,17 +51,17 @@ */ struct multi_reap { - int bucket_base; - int buckets_per_pass; - time_t last_call; + int bucket_base; + int buckets_per_pass; + time_t last_call; }; struct deferred_signal_schedule_entry { - struct schedule_entry se; - int signal_received; - struct timeval wakeup; + struct schedule_entry se; + int signal_received; + struct timeval wakeup; }; /** @@ -75,46 +75,46 @@ struct deferred_signal_schedule_entry * server-mode. */ struct multi_instance { - struct schedule_entry se; /* this must be the first element of the structure */ - struct gc_arena gc; - bool defined; - bool halt; - int refcount; - int route_count; /* number of routes (including cached routes) owned by this instance */ - time_t created; /**< Time at which a VPN tunnel instance + struct schedule_entry se; /* this must be the first element of the structure */ + struct gc_arena gc; + bool defined; + bool halt; + int refcount; + int route_count; /* number of routes (including cached routes) owned by this instance */ + time_t created; /**< Time at which a VPN tunnel instance * was created. This parameter is set * by the \c multi_create_instance() * function. */ - struct timeval wakeup; /* absolute time */ - struct mroute_addr real; /**< External network address of the + struct timeval wakeup; /* absolute time */ + struct mroute_addr real; /**< External network address of the * remote peer. */ - ifconfig_pool_handle vaddr_handle; - char msg_prefix[MULTI_PREFIX_MAX_LENGTH]; + ifconfig_pool_handle vaddr_handle; + char msg_prefix[MULTI_PREFIX_MAX_LENGTH]; - /* queued outgoing data in Server/TCP mode */ - unsigned int tcp_rwflags; - struct mbuf_set *tcp_link_out_deferred; - bool socket_set_called; + /* queued outgoing data in Server/TCP mode */ + unsigned int tcp_rwflags; + struct mbuf_set *tcp_link_out_deferred; + bool socket_set_called; - in_addr_t reporting_addr; /* IP address shown in status listing */ - struct in6_addr reporting_addr_ipv6; /* IPv6 address in status listing */ + in_addr_t reporting_addr; /* IP address shown in status listing */ + struct in6_addr reporting_addr_ipv6; /* IPv6 address in status listing */ - bool did_open_context; - bool did_real_hash; - bool did_iter; + bool did_open_context; + bool did_real_hash; + bool did_iter; #ifdef MANAGEMENT_DEF_AUTH - bool did_cid_hash; - struct buffer_list *cc_config; + bool did_cid_hash; + struct buffer_list *cc_config; #endif - bool connection_established_flag; - bool did_iroutes; - int n_clients_delta; /* added to multi_context.n_clients when instance is closed */ + bool connection_established_flag; + bool did_iroutes; + int n_clients_delta; /* added to multi_context.n_clients when instance is closed */ - struct context context; /**< The context structure storing state + struct context context; /**< The context structure storing state * for this VPN tunnel. */ #ifdef ENABLE_ASYNC_PUSH - int inotify_watch; /* watch descriptor for acf */ + int inotify_watch; /* watch descriptor for acf */ #endif }; @@ -130,66 +130,66 @@ struct multi_instance { * server-mode. */ struct multi_context { -# define MC_UNDEF 0 -# define MC_SINGLE_THREADED (1<<0) -# define MC_MULTI_THREADED_MASTER (1<<1) -# define MC_MULTI_THREADED_WORKER (1<<2) -# define MC_MULTI_THREADED_SCHEDULER (1<<3) -# define MC_WORK_THREAD (MC_MULTI_THREADED_WORKER|MC_MULTI_THREADED_SCHEDULER) - int thread_mode; - - struct multi_instance** instances; /**< Array of multi_instances. An instance can be +#define MC_UNDEF 0 +#define MC_SINGLE_THREADED (1<<0) +#define MC_MULTI_THREADED_MASTER (1<<1) +#define MC_MULTI_THREADED_WORKER (1<<2) +#define MC_MULTI_THREADED_SCHEDULER (1<<3) +#define MC_WORK_THREAD (MC_MULTI_THREADED_WORKER|MC_MULTI_THREADED_SCHEDULER) + int thread_mode; + + struct multi_instance **instances; /**< Array of multi_instances. An instance can be * accessed using peer-id as an index. */ - struct hash *hash; /**< VPN tunnel instances indexed by real + struct hash *hash; /**< VPN tunnel instances indexed by real * address of the remote peer. */ - struct hash *vhash; /**< VPN tunnel instances indexed by + struct hash *vhash; /**< VPN tunnel instances indexed by * virtual address of remote hosts. */ - struct hash *iter; /**< VPN tunnel instances indexed by real + struct hash *iter; /**< VPN tunnel instances indexed by real * address of the remote peer, optimized * for iteration. */ - struct schedule *schedule; - struct mbuf_set *mbuf; /**< Set of buffers for passing data + struct schedule *schedule; + struct mbuf_set *mbuf; /**< Set of buffers for passing data * channel packets between VPN tunnel * instances. */ - struct multi_tcp *mtcp; /**< State specific to OpenVPN using TCP + struct multi_tcp *mtcp; /**< State specific to OpenVPN using TCP * as external transport. */ - struct ifconfig_pool *ifconfig_pool; - struct frequency_limit *new_connection_limiter; - struct mroute_helper *route_helper; - struct multi_reap *reaper; - struct mroute_addr local; - bool enable_c2c; - int max_clients; - int tcp_queue_limit; - int status_file_version; - int n_clients; /* current number of authenticated clients */ + struct ifconfig_pool *ifconfig_pool; + struct frequency_limit *new_connection_limiter; + struct mroute_helper *route_helper; + struct multi_reap *reaper; + struct mroute_addr local; + bool enable_c2c; + int max_clients; + int tcp_queue_limit; + int status_file_version; + int n_clients; /* current number of authenticated clients */ #ifdef MANAGEMENT_DEF_AUTH - struct hash *cid_hash; - unsigned long cid_counter; + struct hash *cid_hash; + unsigned long cid_counter; #endif - struct multi_instance *pending; - struct multi_instance *earliest_wakeup; - struct multi_instance **mpp_touched; - struct context_buffers *context_buffers; - time_t per_second_trigger; + struct multi_instance *pending; + struct multi_instance *earliest_wakeup; + struct multi_instance **mpp_touched; + struct context_buffers *context_buffers; + time_t per_second_trigger; - struct context top; /**< Storage structure for process-wide + struct context top; /**< Storage structure for process-wide * configuration. */ - /* - * Timer object for stale route check - */ - struct event_timeout stale_routes_check_et; + /* + * Timer object for stale route check + */ + struct event_timeout stale_routes_check_et; #ifdef ENABLE_ASYNC_PUSH - /* mapping between inotify watch descriptors and multi_instances */ - struct hash *inotify_watchers; + /* mapping between inotify watch descriptors and multi_instances */ + struct hash *inotify_watchers; #endif - struct deferred_signal_schedule_entry deferred_shutdown_signal; + struct deferred_signal_schedule_entry deferred_shutdown_signal; }; /* @@ -197,15 +197,15 @@ struct multi_context { */ struct multi_route { - struct mroute_addr addr; - struct multi_instance *instance; + struct mroute_addr addr; + struct multi_instance *instance; -# define MULTI_ROUTE_CACHE (1<<0) -# define MULTI_ROUTE_AGEABLE (1<<1) - unsigned int flags; +#define MULTI_ROUTE_CACHE (1<<0) +#define MULTI_ROUTE_AGEABLE (1<<1) + unsigned int flags; - unsigned int cache_generation; - time_t last_reference; + unsigned int cache_generation; + time_t last_reference; }; @@ -221,25 +221,28 @@ struct multi_route * * @param top - Top-level context structure. */ -void tunnel_server (struct context *top); +void tunnel_server(struct context *top); -const char *multi_instance_string (const struct multi_instance *mi, bool null, struct gc_arena *gc); +const char *multi_instance_string(const struct multi_instance *mi, bool null, struct gc_arena *gc); /* * Called by mtcp.c, mudp.c, or other (to be written) protocol drivers */ -void multi_init (struct multi_context *m, struct context *t, bool tcp_mode, int thread_mode); -void multi_uninit (struct multi_context *m); +void multi_init(struct multi_context *m, struct context *t, bool tcp_mode, int thread_mode); -void multi_top_init (struct multi_context *m, const struct context *top); -void multi_top_free (struct multi_context *m); +void multi_uninit(struct multi_context *m); -struct multi_instance *multi_create_instance (struct multi_context *m, const struct mroute_addr *real); -void multi_close_instance (struct multi_context *m, struct multi_instance *mi, bool shutdown); +void multi_top_init(struct multi_context *m, const struct context *top); -bool multi_process_timeout (struct multi_context *m, const unsigned int mpp_flags); +void multi_top_free(struct multi_context *m); + +struct multi_instance *multi_create_instance(struct multi_context *m, const struct mroute_addr *real); + +void multi_close_instance(struct multi_context *m, struct multi_instance *mi, bool shutdown); + +bool multi_process_timeout(struct multi_context *m, const unsigned int mpp_flags); /** * Handles peer floating. @@ -249,7 +252,7 @@ bool multi_process_timeout (struct multi_context *m, const unsigned int mpp_flag * existing peer. Updates multi_instance with new address, * updates hashtables in multi_context. */ -void multi_process_float (struct multi_context* m, struct multi_instance* mi); +void multi_process_float(struct multi_context *m, struct multi_instance *mi); #define MPP_PRE_SELECT (1<<0) #define MPP_CONDITIONAL_PRE_SELECT (1<<1) @@ -279,7 +282,7 @@ void multi_process_float (struct multi_context* m, struct multi_instance* mi); * signal during processing. * - False, if the VPN tunnel instance \a mi was closed. */ -bool multi_process_post (struct multi_context *m, struct multi_instance *mi, const unsigned int flags); +bool multi_process_post(struct multi_context *m, struct multi_instance *mi, const unsigned int flags); /**************************************************************************/ @@ -305,7 +308,7 @@ bool multi_process_post (struct multi_context *m, struct multi_instance *mi, con * the case when using UDP transport. * @param mpp_flags - Fast I/O optimization flags. */ -bool multi_process_incoming_link (struct multi_context *m, struct multi_instance *instance, const unsigned int mpp_flags); +bool multi_process_incoming_link(struct multi_context *m, struct multi_instance *instance, const unsigned int mpp_flags); /** @@ -323,27 +326,28 @@ bool multi_process_incoming_link (struct multi_context *m, struct multi_instance * @param m - The single \c multi_context structure. * @param mpp_flags - Fast I/O optimization flags. */ -bool multi_process_incoming_tun (struct multi_context *m, const unsigned int mpp_flags); +bool multi_process_incoming_tun(struct multi_context *m, const unsigned int mpp_flags); + +void multi_process_drop_outgoing_tun(struct multi_context *m, const unsigned int mpp_flags); -void multi_process_drop_outgoing_tun (struct multi_context *m, const unsigned int mpp_flags); +void multi_print_status(struct multi_context *m, struct status_output *so, const int version); -void multi_print_status (struct multi_context *m, struct status_output *so, const int version); +struct multi_instance *multi_get_queue(struct mbuf_set *ms); -struct multi_instance *multi_get_queue (struct mbuf_set *ms); +void multi_add_mbuf(struct multi_context *m, + struct multi_instance *mi, + struct mbuf_buffer *mb); -void multi_add_mbuf (struct multi_context *m, - struct multi_instance *mi, - struct mbuf_buffer *mb); +void multi_ifconfig_pool_persist(struct multi_context *m, bool force); -void multi_ifconfig_pool_persist (struct multi_context *m, bool force); +bool multi_process_signal(struct multi_context *m); -bool multi_process_signal (struct multi_context *m); +void multi_close_instance_on_signal(struct multi_context *m, struct multi_instance *mi); -void multi_close_instance_on_signal (struct multi_context *m, struct multi_instance *mi); +void init_management_callback_multi(struct multi_context *m); -void init_management_callback_multi (struct multi_context *m); -void uninit_management_callback_multi (struct multi_context *m); +void uninit_management_callback_multi(struct multi_context *m); #ifdef ENABLE_ASYNC_PUSH @@ -354,20 +358,25 @@ void uninit_management_callback_multi (struct multi_context *m); * @param m multi_context * @param mpp_flags */ -void multi_process_file_closed (struct multi_context *m, const unsigned int mpp_flags); +void multi_process_file_closed(struct multi_context *m, const unsigned int mpp_flags); + #endif /* * Return true if our output queue is not full */ static inline bool -multi_output_queue_ready (const struct multi_context *m, - const struct multi_instance *mi) +multi_output_queue_ready(const struct multi_context *m, + const struct multi_instance *mi) { - if (mi->tcp_link_out_deferred) - return mbuf_len (mi->tcp_link_out_deferred) <= m->tcp_queue_limit; - else - return true; + if (mi->tcp_link_out_deferred) + { + return mbuf_len(mi->tcp_link_out_deferred) <= m->tcp_queue_limit; + } + else + { + return true; + } } /* @@ -376,46 +385,52 @@ multi_output_queue_ready (const struct multi_context *m, * the to_link buffer. */ static inline struct multi_instance * -multi_process_outgoing_link_pre (struct multi_context *m) +multi_process_outgoing_link_pre(struct multi_context *m) { - struct multi_instance *mi = NULL; + struct multi_instance *mi = NULL; - if (m->pending) - mi = m->pending; - else if (mbuf_defined (m->mbuf)) - mi = multi_get_queue (m->mbuf); - return mi; + if (m->pending) + { + mi = m->pending; + } + else if (mbuf_defined(m->mbuf)) + { + mi = multi_get_queue(m->mbuf); + } + return mi; } /* * Per-client route quota management */ -void route_quota_exceeded (const struct multi_context *m, const struct multi_instance *mi); +void route_quota_exceeded(const struct multi_context *m, const struct multi_instance *mi); static inline void -route_quota_inc (struct multi_instance *mi) +route_quota_inc(struct multi_instance *mi) { - ++mi->route_count; + ++mi->route_count; } static inline void -route_quota_dec (struct multi_instance *mi) +route_quota_dec(struct multi_instance *mi) { - --mi->route_count; + --mi->route_count; } /* can we add a new route? */ static inline bool -route_quota_test (const struct multi_context *m, const struct multi_instance *mi) +route_quota_test(const struct multi_context *m, const struct multi_instance *mi) { - if (mi->route_count >= mi->context.options.max_routes_per_client) + if (mi->route_count >= mi->context.options.max_routes_per_client) + { + route_quota_exceeded(m, mi); + return false; + } + else { - route_quota_exceeded (m, mi); - return false; + return true; } - else - return true; } /* @@ -423,73 +438,83 @@ route_quota_test (const struct multi_context *m, const struct multi_instance *mi */ static inline void -multi_instance_inc_refcount (struct multi_instance *mi) +multi_instance_inc_refcount(struct multi_instance *mi) { - ++mi->refcount; + ++mi->refcount; } static inline void -multi_instance_dec_refcount (struct multi_instance *mi) +multi_instance_dec_refcount(struct multi_instance *mi) { - if (--mi->refcount <= 0) + if (--mi->refcount <= 0) { - gc_free (&mi->gc); - free (mi); + gc_free(&mi->gc); + free(mi); } } static inline void -multi_route_del (struct multi_route *route) +multi_route_del(struct multi_route *route) { - struct multi_instance *mi = route->instance; - route_quota_dec (mi); - multi_instance_dec_refcount (mi); - free (route); + struct multi_instance *mi = route->instance; + route_quota_dec(mi); + multi_instance_dec_refcount(mi); + free(route); } static inline bool -multi_route_defined (const struct multi_context *m, - const struct multi_route *r) +multi_route_defined(const struct multi_context *m, + const struct multi_route *r) { - if (r->instance->halt) - return false; - else if ((r->flags & MULTI_ROUTE_CACHE) - && r->cache_generation != m->route_helper->cache_generation) - return false; - else if ((r->flags & MULTI_ROUTE_AGEABLE) - && r->last_reference + m->route_helper->ageable_ttl_secs < now) - return false; - else - return true; + if (r->instance->halt) + { + return false; + } + else if ((r->flags & MULTI_ROUTE_CACHE) + && r->cache_generation != m->route_helper->cache_generation) + { + return false; + } + else if ((r->flags & MULTI_ROUTE_AGEABLE) + && r->last_reference + m->route_helper->ageable_ttl_secs < now) + { + return false; + } + else + { + return true; + } } /* * Takes prefix away from multi_instance. */ void -ungenerate_prefix (struct multi_instance *mi); +ungenerate_prefix(struct multi_instance *mi); /* * Set a msg() function prefix with our current client instance ID. */ static inline void -set_prefix (struct multi_instance *mi) +set_prefix(struct multi_instance *mi) { #ifdef MULTI_DEBUG_EVENT_LOOP - if (mi->msg_prefix[0]) - printf ("[%s]\n", mi->msg_prefix); + if (mi->msg_prefix[0]) + { + printf("[%s]\n", mi->msg_prefix); + } #endif - msg_set_prefix (mi->msg_prefix[0] ? mi->msg_prefix : NULL); + msg_set_prefix(mi->msg_prefix[0] ? mi->msg_prefix : NULL); } static inline void -clear_prefix (void) +clear_prefix(void) { #ifdef MULTI_DEBUG_EVENT_LOOP - printf ("[NULL]\n"); + printf("[NULL]\n"); #endif - msg_set_prefix (NULL); + msg_set_prefix(NULL); } /* @@ -513,21 +538,25 @@ clear_prefix (void) #define MULTI_CACHE_ROUTE_TTL 60 static inline void -multi_reap_process (const struct multi_context *m) +multi_reap_process(const struct multi_context *m) { - void multi_reap_process_dowork (const struct multi_context *m); - if (m->reaper->last_call != now) - multi_reap_process_dowork (m); + void multi_reap_process_dowork(const struct multi_context *m); + + if (m->reaper->last_call != now) + { + multi_reap_process_dowork(m); + } } static inline void -multi_process_per_second_timers (struct multi_context *m) +multi_process_per_second_timers(struct multi_context *m) { - if (m->per_second_trigger != now) + if (m->per_second_trigger != now) { - void multi_process_per_second_timers_dowork (struct multi_context *m); - multi_process_per_second_timers_dowork (m); - m->per_second_trigger = now; + void multi_process_per_second_timers_dowork(struct multi_context *m); + + multi_process_per_second_timers_dowork(m); + m->per_second_trigger = now; } } @@ -540,27 +569,27 @@ multi_process_per_second_timers (struct multi_context *m) * to current time. */ static inline void -multi_get_timeout (struct multi_context *m, struct timeval *dest) +multi_get_timeout(struct multi_context *m, struct timeval *dest) { - struct timeval tv, current; + struct timeval tv, current; - CLEAR (tv); - m->earliest_wakeup = (struct multi_instance *) schedule_get_earliest_wakeup (m->schedule, &tv); - if (m->earliest_wakeup) + CLEAR(tv); + m->earliest_wakeup = (struct multi_instance *) schedule_get_earliest_wakeup(m->schedule, &tv); + if (m->earliest_wakeup) { - ASSERT (!openvpn_gettimeofday (¤t, NULL)); - tv_delta (dest, ¤t, &tv); - if (dest->tv_sec >= REAP_MAX_WAKEUP) - { - m->earliest_wakeup = NULL; - dest->tv_sec = REAP_MAX_WAKEUP; - dest->tv_usec = 0; - } + ASSERT(!openvpn_gettimeofday(¤t, NULL)); + tv_delta(dest, ¤t, &tv); + if (dest->tv_sec >= REAP_MAX_WAKEUP) + { + m->earliest_wakeup = NULL; + dest->tv_sec = REAP_MAX_WAKEUP; + dest->tv_usec = 0; + } } - else + else { - dest->tv_sec = REAP_MAX_WAKEUP; - dest->tv_usec = 0; + dest->tv_sec = REAP_MAX_WAKEUP; + dest->tv_usec = 0; } } @@ -583,46 +612,46 @@ multi_get_timeout (struct multi_context *m, struct timeval *dest) * - Falls, if the \c multi_instance was closed. */ static inline bool -multi_process_outgoing_tun (struct multi_context *m, const unsigned int mpp_flags) +multi_process_outgoing_tun(struct multi_context *m, const unsigned int mpp_flags) { - struct multi_instance *mi = m->pending; - bool ret = true; + struct multi_instance *mi = m->pending; + bool ret = true; - ASSERT (mi); + ASSERT(mi); #ifdef MULTI_DEBUG_EVENT_LOOP - printf ("%s -> TUN len=%d\n", - id(mi), - mi->context.c2.to_tun.len); + printf("%s -> TUN len=%d\n", + id(mi), + mi->context.c2.to_tun.len); #endif - set_prefix (mi); - process_outgoing_tun (&mi->context); - ret = multi_process_post (m, mi, mpp_flags); - clear_prefix (); - return ret; + set_prefix(mi); + process_outgoing_tun(&mi->context); + ret = multi_process_post(m, mi, mpp_flags); + clear_prefix(); + return ret; } static inline bool -multi_process_outgoing_link_dowork (struct multi_context *m, struct multi_instance *mi, const unsigned int mpp_flags) +multi_process_outgoing_link_dowork(struct multi_context *m, struct multi_instance *mi, const unsigned int mpp_flags) { - bool ret = true; - set_prefix (mi); - process_outgoing_link (&mi->context); - ret = multi_process_post (m, mi, mpp_flags); - clear_prefix (); - return ret; + bool ret = true; + set_prefix(mi); + process_outgoing_link(&mi->context); + ret = multi_process_post(m, mi, mpp_flags); + clear_prefix(); + return ret; } /* * Check for signals. */ -#define MULTI_CHECK_SIG(m) EVENT_LOOP_CHECK_SIGNAL (&(m)->top, multi_process_signal, (m)) +#define MULTI_CHECK_SIG(m) EVENT_LOOP_CHECK_SIGNAL(&(m)->top, multi_process_signal, (m)) static inline void -multi_set_pending (struct multi_context *m, struct multi_instance *mi) +multi_set_pending(struct multi_context *m, struct multi_instance *mi) { - m->pending = mi; + m->pending = mi; } #endif /* P2MP_SERVER */ diff --git a/src/openvpn/ntlm.c b/src/openvpn/ntlm.c index 3390bdddfe0..e78af9e6f42 100644 --- a/src/openvpn/ntlm.c +++ b/src/openvpn/ntlm.c @@ -45,308 +45,334 @@ /* 64bit datatype macros */ -#ifdef _MSC_VER - /* MS compilers */ -# define UINTEGER64 __int64 -# define UINT64(c) c ## Ui64 -#else - /* Non MS compilers */ -# define UINTEGER64 unsigned long long -# define UINT64(c) c ## LL +#ifdef _MSC_VER +/* MS compilers */ +#define UINTEGER64 __int64 +#define UINT64(c) c ## Ui64 +#else +/* Non MS compilers */ +#define UINTEGER64 unsigned long long +#define UINT64(c) c ## LL #endif - static void create_des_keys(const unsigned char *hash, unsigned char *key) { - key[0] = hash[0]; - key[1] = ((hash[0]&1)<<7)|(hash[1]>>1); - key[2] = ((hash[1]&3)<<6)|(hash[2]>>2); - key[3] = ((hash[2]&7)<<5)|(hash[3]>>3); - key[4] = ((hash[3]&15)<<4)|(hash[4]>>4); - key[5] = ((hash[4]&31)<<3)|(hash[5]>>5); - key[6] = ((hash[5]&63)<<2)|(hash[6]>>6); - key[7] = ((hash[6]&127)<<1); - key_des_fixup(key, 8, 1); + key[0] = hash[0]; + key[1] = ((hash[0]&1)<<7)|(hash[1]>>1); + key[2] = ((hash[1]&3)<<6)|(hash[2]>>2); + key[3] = ((hash[2]&7)<<5)|(hash[3]>>3); + key[4] = ((hash[3]&15)<<4)|(hash[4]>>4); + key[5] = ((hash[4]&31)<<3)|(hash[5]>>5); + key[6] = ((hash[5]&63)<<2)|(hash[6]>>6); + key[7] = ((hash[6]&127)<<1); + key_des_fixup(key, 8, 1); } static void -gen_md4_hash (const char* data, int data_len, char *result) +gen_md4_hash(const char *data, int data_len, char *result) { - /* result is 16 byte md4 hash */ - const md_kt_t *md4_kt = md_kt_get("MD4"); - char md[MD4_DIGEST_LENGTH]; + /* result is 16 byte md4 hash */ + const md_kt_t *md4_kt = md_kt_get("MD4"); + char md[MD4_DIGEST_LENGTH]; - md_full(md4_kt, data, data_len, md); - memcpy (result, md, MD4_DIGEST_LENGTH); + md_full(md4_kt, data, data_len, md); + memcpy(result, md, MD4_DIGEST_LENGTH); } static void -gen_hmac_md5 (const char* data, int data_len, const char* key, int key_len,char *result) +gen_hmac_md5(const char *data, int data_len, const char *key, int key_len,char *result) { - const md_kt_t *md5_kt = md_kt_get("MD5"); - hmac_ctx_t hmac_ctx; - CLEAR(hmac_ctx); - - hmac_ctx_init(&hmac_ctx, key, key_len, md5_kt); - hmac_ctx_update(&hmac_ctx, (const unsigned char *)data, data_len); - hmac_ctx_final(&hmac_ctx, (unsigned char *)result); - hmac_ctx_cleanup(&hmac_ctx); + const md_kt_t *md5_kt = md_kt_get("MD5"); + hmac_ctx_t hmac_ctx; + CLEAR(hmac_ctx); + + hmac_ctx_init(&hmac_ctx, key, key_len, md5_kt); + hmac_ctx_update(&hmac_ctx, (const unsigned char *)data, data_len); + hmac_ctx_final(&hmac_ctx, (unsigned char *)result); + hmac_ctx_cleanup(&hmac_ctx); } static void -gen_timestamp (unsigned char *timestamp) -{ - /* Copies 8 bytes long timestamp into "timestamp" buffer. - * Timestamp is Little-endian, 64-bit signed value representing the number of tenths of a microsecond since January 1, 1601. - */ - - UINTEGER64 timestamp_ull; - - timestamp_ull = openvpn_time(NULL); - timestamp_ull = (timestamp_ull + UINT64(11644473600)) * UINT64(10000000); - - /* store little endian value */ - timestamp[0]= timestamp_ull & UINT64(0xFF); - timestamp[1]= (timestamp_ull >> 8) & UINT64(0xFF); - timestamp[2]= (timestamp_ull >> 16) & UINT64(0xFF); - timestamp[3]= (timestamp_ull >> 24) & UINT64(0xFF); - timestamp[4]= (timestamp_ull >> 32) & UINT64(0xFF); - timestamp[5]= (timestamp_ull >> 40) & UINT64(0xFF); - timestamp[6]= (timestamp_ull >> 48) & UINT64(0xFF); - timestamp[7]= (timestamp_ull >> 56) & UINT64(0xFF); +gen_timestamp(unsigned char *timestamp) +{ + /* Copies 8 bytes long timestamp into "timestamp" buffer. + * Timestamp is Little-endian, 64-bit signed value representing the number of tenths of a microsecond since January 1, 1601. + */ + + UINTEGER64 timestamp_ull; + + timestamp_ull = openvpn_time(NULL); + timestamp_ull = (timestamp_ull + UINT64(11644473600)) * UINT64(10000000); + + /* store little endian value */ + timestamp[0] = timestamp_ull & UINT64(0xFF); + timestamp[1] = (timestamp_ull >> 8) & UINT64(0xFF); + timestamp[2] = (timestamp_ull >> 16) & UINT64(0xFF); + timestamp[3] = (timestamp_ull >> 24) & UINT64(0xFF); + timestamp[4] = (timestamp_ull >> 32) & UINT64(0xFF); + timestamp[5] = (timestamp_ull >> 40) & UINT64(0xFF); + timestamp[6] = (timestamp_ull >> 48) & UINT64(0xFF); + timestamp[7] = (timestamp_ull >> 56) & UINT64(0xFF); } static void -gen_nonce (unsigned char *nonce) -{ - /* Generates 8 random bytes to be used as client nonce */ - int i; - - for(i=0;i<8;i++){ - nonce[i] = (unsigned char)get_random(); - } +gen_nonce(unsigned char *nonce) +{ + /* Generates 8 random bytes to be used as client nonce */ + int i; + + for (i = 0; i<8; i++) { + nonce[i] = (unsigned char)get_random(); + } } -unsigned char *my_strupr(unsigned char *str) -{ - /* converts string to uppercase in place */ - unsigned char *tmp = str;; +unsigned char * +my_strupr(unsigned char *str) +{ + /* converts string to uppercase in place */ + unsigned char *tmp = str; - do *str = toupper(*str); while (*(++str)); - return tmp; + do *str = toupper(*str); while (*(++str)); + return tmp; } static int -unicodize (char *dst, const char *src) +unicodize(char *dst, const char *src) { - /* not really unicode... */ - int i = 0; - do + /* not really unicode... */ + int i = 0; + do { - dst[i++] = *src; - dst[i++] = 0; + dst[i++] = *src; + dst[i++] = 0; } - while (*src++); + while (*src++); - return i; + return i; } static void add_security_buffer(int sb_offset, void *data, int length, unsigned char *msg_buf, int *msg_bufpos) { - /* Adds security buffer data to a message and sets security buffer's offset and length */ - msg_buf[sb_offset] = (unsigned char)length; - msg_buf[sb_offset + 2] = msg_buf[sb_offset]; - msg_buf[sb_offset + 4] = (unsigned char)(*msg_bufpos & 0xff); - msg_buf[sb_offset + 5] = (unsigned char)((*msg_bufpos >> 8) & 0xff); - memcpy(&msg_buf[*msg_bufpos], data, msg_buf[sb_offset]); - *msg_bufpos += length; + /* Adds security buffer data to a message and sets security buffer's offset and length */ + msg_buf[sb_offset] = (unsigned char)length; + msg_buf[sb_offset + 2] = msg_buf[sb_offset]; + msg_buf[sb_offset + 4] = (unsigned char)(*msg_bufpos & 0xff); + msg_buf[sb_offset + 5] = (unsigned char)((*msg_bufpos >> 8) & 0xff); + memcpy(&msg_buf[*msg_bufpos], data, msg_buf[sb_offset]); + *msg_bufpos += length; } const char * -ntlm_phase_1 (const struct http_proxy_info *p, struct gc_arena *gc) +ntlm_phase_1(const struct http_proxy_info *p, struct gc_arena *gc) { - struct buffer out = alloc_buf_gc (96, gc); - /* try a minimal NTLM handshake - * - * http://davenport.sourceforge.net/ntlm.html - * - * This message contains only the NTLMSSP signature, - * the NTLM message type, - * and the minimal set of flags (Negotiate NTLM and Negotiate OEM). - * - */ - buf_printf (&out, "%s", "TlRMTVNTUAABAAAAAgIAAA=="); - return (BSTR (&out)); + struct buffer out = alloc_buf_gc(96, gc); + /* try a minimal NTLM handshake + * + * http://davenport.sourceforge.net/ntlm.html + * + * This message contains only the NTLMSSP signature, + * the NTLM message type, + * and the minimal set of flags (Negotiate NTLM and Negotiate OEM). + * + */ + buf_printf(&out, "%s", "TlRMTVNTUAABAAAAAgIAAA=="); + return (BSTR(&out)); } const char * -ntlm_phase_3 (const struct http_proxy_info *p, const char *phase_2, struct gc_arena *gc) +ntlm_phase_3(const struct http_proxy_info *p, const char *phase_2, struct gc_arena *gc) { - /* NTLM handshake - * - * http://davenport.sourceforge.net/ntlm.html - * - */ - - char pwbuf[sizeof (p->up.password) * 2]; /* for unicode password */ - char buf2[128]; /* decoded reply from proxy */ - unsigned char phase3[464]; - - char md4_hash[MD4_DIGEST_LENGTH+5]; - char challenge[8], ntlm_response[24]; - int i, ret_val; - - char ntlmv2_response[144]; - char userdomain_u[256]; /* for uppercase unicode username and domain */ - char userdomain[128]; /* the same as previous but ascii */ - char ntlmv2_hash[MD5_DIGEST_LENGTH]; - char ntlmv2_hmacmd5[16]; - char *ntlmv2_blob = ntlmv2_response + 16; /* inside ntlmv2_response, length: 128 */ - int ntlmv2_blob_size=0; - int phase3_bufpos = 0x40; /* offset to next security buffer data to be added */ - size_t len; - - char domain[128]; - char username[128]; - char *separator; - - bool ntlmv2_enabled = (p->auth_method == HTTP_AUTH_NTLM2); - - CLEAR (buf2); - - ASSERT (strlen (p->up.username) > 0); - ASSERT (strlen (p->up.password) > 0); - - /* username parsing */ - separator = strchr(p->up.username, '\\'); - if (separator == NULL) { - strncpy(username, p->up.username, sizeof(username)-1); - username[sizeof(username)-1]=0; - domain[0]=0; - } else { - strncpy(username, separator+1, sizeof(username)-1); - username[sizeof(username)-1]=0; - len = separator - p->up.username; - if (len > sizeof(domain) - 1) len = sizeof(domain) - 1; - strncpy(domain, p->up.username, len); - domain[len]=0; - } - - - /* fill 1st 16 bytes with md4 hash, disregard terminating null */ - gen_md4_hash (pwbuf, unicodize (pwbuf, p->up.password) - 2, md4_hash); - - /* pad to 21 bytes */ - memset(md4_hash + MD4_DIGEST_LENGTH, 0, 5); - - ret_val = openvpn_base64_decode( phase_2, (void *)buf2, -1); - if (ret_val < 0) - return NULL; - - /* we can be sure that phase_2 is less than 128 - * therefore buf2 needs to be (3/4 * 128) */ - - /* extract the challenge from bytes 24-31 */ - for (i=0; i<8; i++) - { - challenge[i] = buf2[i+24]; - } - - if (ntlmv2_enabled){ /* Generate NTLMv2 response */ - int tib_len; - - /* NTLMv2 hash */ - my_strupr((unsigned char *)strcpy(userdomain, username)); - if (strlen(username) + strlen(domain) < sizeof(userdomain)) - strcat(userdomain, domain); - else - msg (M_INFO, "Warning: Username or domain too long"); - unicodize (userdomain_u, userdomain); - gen_hmac_md5(userdomain_u, 2 * strlen(userdomain), md4_hash, MD5_DIGEST_LENGTH, ntlmv2_hash); - - /* NTLMv2 Blob */ - memset(ntlmv2_blob, 0, 128); /* Clear blob buffer */ - ntlmv2_blob[0x00]=1; /* Signature */ - ntlmv2_blob[0x01]=1; /* Signature */ - ntlmv2_blob[0x04]=0; /* Reserved */ - gen_timestamp((unsigned char *)&ntlmv2_blob[0x08]); /* 64-bit Timestamp */ - gen_nonce((unsigned char *)&ntlmv2_blob[0x10]); /* 64-bit Client Nonce */ - ntlmv2_blob[0x18]=0; /* Unknown, zero should work */ - - /* Add target information block to the blob */ - if (( *((long *)&buf2[0x14]) & 0x00800000) == 0x00800000){ /* Check for Target Information block */ - tib_len = buf2[0x28];/* Get Target Information block size */ - if (tib_len > 96) tib_len = 96; - { - char *tib_ptr = buf2 + buf2[0x2c]; /* Get Target Information block pointer */ - memcpy(&ntlmv2_blob[0x1c], tib_ptr, tib_len); /* Copy Target Information block into the blob */ - } - } else { - tib_len = 0; - } - - ntlmv2_blob[0x1c + tib_len] = 0; /* Unknown, zero works */ - - /* Get blob length */ - ntlmv2_blob_size = 0x20 + tib_len; - - /* Add challenge from message 2 */ - memcpy(&ntlmv2_response[8], challenge, 8); - - /* hmac-md5 */ - gen_hmac_md5(&ntlmv2_response[8], ntlmv2_blob_size + 8, ntlmv2_hash, MD5_DIGEST_LENGTH, ntlmv2_hmacmd5); - - /* Add hmac-md5 result to the blob */ - memcpy(ntlmv2_response, ntlmv2_hmacmd5, MD5_DIGEST_LENGTH); /* Note: This overwrites challenge previously written at ntlmv2_response[8..15] */ - - } else { /* Generate NTLM response */ - unsigned char key1[DES_KEY_LENGTH], key2[DES_KEY_LENGTH], key3[DES_KEY_LENGTH]; - - create_des_keys ((unsigned char *)md4_hash, key1); - cipher_des_encrypt_ecb (key1, challenge, ntlm_response); - - create_des_keys ((unsigned char *)&(md4_hash[DES_KEY_LENGTH-1]), key2); - cipher_des_encrypt_ecb (key2, challenge, &ntlm_response[DES_KEY_LENGTH]); - - create_des_keys ((unsigned char *)&(md4_hash[2*(DES_KEY_LENGTH-1)]), key3); - cipher_des_encrypt_ecb (key3, challenge, &ntlm_response[DES_KEY_LENGTH*2]); - } - - - memset (phase3, 0, sizeof (phase3)); /* clear reply */ - - strcpy ((char *)phase3, "NTLMSSP\0"); /* signature */ - phase3[8] = 3; /* type 3 */ - - if (ntlmv2_enabled){ /* NTLMv2 response */ - add_security_buffer(0x14, ntlmv2_response, ntlmv2_blob_size + 16, phase3, &phase3_bufpos); - }else{ /* NTLM response */ - add_security_buffer(0x14, ntlm_response, 24, phase3, &phase3_bufpos); - } - - /* username in ascii */ - add_security_buffer(0x24, username, strlen (username), phase3, &phase3_bufpos); - - /* Set domain. If is empty, default domain will be used (i.e. proxy's domain) */ - add_security_buffer(0x1c, domain, strlen (domain), phase3, &phase3_bufpos); - - - /* other security buffers will be empty */ - phase3[0x10] = phase3_bufpos; /* lm not used */ - phase3[0x30] = phase3_bufpos; /* no workstation name supplied */ - phase3[0x38] = phase3_bufpos; /* no session key */ - - /* flags */ - phase3[0x3c] = 0x02; /* negotiate oem */ - phase3[0x3d] = 0x02; /* negotiate ntlm */ - - return ((const char *)make_base64_string2 ((unsigned char *)phase3, phase3_bufpos, gc)); + /* NTLM handshake + * + * http://davenport.sourceforge.net/ntlm.html + * + */ + + char pwbuf[sizeof(p->up.password) * 2]; /* for unicode password */ + char buf2[128]; /* decoded reply from proxy */ + unsigned char phase3[464]; + + char md4_hash[MD4_DIGEST_LENGTH+5]; + char challenge[8], ntlm_response[24]; + int i, ret_val; + + char ntlmv2_response[144]; + char userdomain_u[256]; /* for uppercase unicode username and domain */ + char userdomain[128]; /* the same as previous but ascii */ + char ntlmv2_hash[MD5_DIGEST_LENGTH]; + char ntlmv2_hmacmd5[16]; + char *ntlmv2_blob = ntlmv2_response + 16; /* inside ntlmv2_response, length: 128 */ + int ntlmv2_blob_size = 0; + int phase3_bufpos = 0x40; /* offset to next security buffer data to be added */ + size_t len; + + char domain[128]; + char username[128]; + char *separator; + + bool ntlmv2_enabled = (p->auth_method == HTTP_AUTH_NTLM2); + + CLEAR(buf2); + + ASSERT(strlen(p->up.username) > 0); + ASSERT(strlen(p->up.password) > 0); + + /* username parsing */ + separator = strchr(p->up.username, '\\'); + if (separator == NULL) + { + strncpy(username, p->up.username, sizeof(username)-1); + username[sizeof(username)-1] = 0; + domain[0] = 0; + } + else + { + strncpy(username, separator+1, sizeof(username)-1); + username[sizeof(username)-1] = 0; + len = separator - p->up.username; + if (len > sizeof(domain) - 1) + { + len = sizeof(domain) - 1; + } + strncpy(domain, p->up.username, len); + domain[len] = 0; + } + + + /* fill 1st 16 bytes with md4 hash, disregard terminating null */ + gen_md4_hash(pwbuf, unicodize(pwbuf, p->up.password) - 2, md4_hash); + + /* pad to 21 bytes */ + memset(md4_hash + MD4_DIGEST_LENGTH, 0, 5); + + ret_val = openvpn_base64_decode( phase_2, (void *)buf2, -1); + if (ret_val < 0) + { + return NULL; + } + + /* we can be sure that phase_2 is less than 128 + * therefore buf2 needs to be (3/4 * 128) */ + + /* extract the challenge from bytes 24-31 */ + for (i = 0; i<8; i++) + { + challenge[i] = buf2[i+24]; + } + + if (ntlmv2_enabled) /* Generate NTLMv2 response */ + { + int tib_len; + + /* NTLMv2 hash */ + my_strupr((unsigned char *)strcpy(userdomain, username)); + if (strlen(username) + strlen(domain) < sizeof(userdomain)) + { + strcat(userdomain, domain); + } + else + { + msg(M_INFO, "Warning: Username or domain too long"); + } + unicodize(userdomain_u, userdomain); + gen_hmac_md5(userdomain_u, 2 * strlen(userdomain), md4_hash, MD5_DIGEST_LENGTH, ntlmv2_hash); + + /* NTLMv2 Blob */ + memset(ntlmv2_blob, 0, 128); /* Clear blob buffer */ + ntlmv2_blob[0x00] = 1; /* Signature */ + ntlmv2_blob[0x01] = 1; /* Signature */ + ntlmv2_blob[0x04] = 0; /* Reserved */ + gen_timestamp((unsigned char *)&ntlmv2_blob[0x08]); /* 64-bit Timestamp */ + gen_nonce((unsigned char *)&ntlmv2_blob[0x10]); /* 64-bit Client Nonce */ + ntlmv2_blob[0x18] = 0; /* Unknown, zero should work */ + + /* Add target information block to the blob */ + if (( *((long *)&buf2[0x14]) & 0x00800000) == 0x00800000) /* Check for Target Information block */ + { + tib_len = buf2[0x28]; /* Get Target Information block size */ + if (tib_len > 96) + { + tib_len = 96; + } + { + char *tib_ptr = buf2 + buf2[0x2c]; /* Get Target Information block pointer */ + memcpy(&ntlmv2_blob[0x1c], tib_ptr, tib_len); /* Copy Target Information block into the blob */ + } + } + else + { + tib_len = 0; + } + + ntlmv2_blob[0x1c + tib_len] = 0; /* Unknown, zero works */ + + /* Get blob length */ + ntlmv2_blob_size = 0x20 + tib_len; + + /* Add challenge from message 2 */ + memcpy(&ntlmv2_response[8], challenge, 8); + + /* hmac-md5 */ + gen_hmac_md5(&ntlmv2_response[8], ntlmv2_blob_size + 8, ntlmv2_hash, MD5_DIGEST_LENGTH, ntlmv2_hmacmd5); + + /* Add hmac-md5 result to the blob */ + memcpy(ntlmv2_response, ntlmv2_hmacmd5, MD5_DIGEST_LENGTH); /* Note: This overwrites challenge previously written at ntlmv2_response[8..15] */ + + } + else /* Generate NTLM response */ + { + unsigned char key1[DES_KEY_LENGTH], key2[DES_KEY_LENGTH], key3[DES_KEY_LENGTH]; + + create_des_keys((unsigned char *)md4_hash, key1); + cipher_des_encrypt_ecb(key1, challenge, ntlm_response); + + create_des_keys((unsigned char *)&(md4_hash[DES_KEY_LENGTH-1]), key2); + cipher_des_encrypt_ecb(key2, challenge, &ntlm_response[DES_KEY_LENGTH]); + + create_des_keys((unsigned char *)&(md4_hash[2*(DES_KEY_LENGTH-1)]), key3); + cipher_des_encrypt_ecb(key3, challenge, &ntlm_response[DES_KEY_LENGTH*2]); + } + + + memset(phase3, 0, sizeof(phase3)); /* clear reply */ + + strcpy((char *)phase3, "NTLMSSP\0"); /* signature */ + phase3[8] = 3; /* type 3 */ + + if (ntlmv2_enabled) /* NTLMv2 response */ + { + add_security_buffer(0x14, ntlmv2_response, ntlmv2_blob_size + 16, phase3, &phase3_bufpos); + } + else /* NTLM response */ + { + add_security_buffer(0x14, ntlm_response, 24, phase3, &phase3_bufpos); + } + + /* username in ascii */ + add_security_buffer(0x24, username, strlen(username), phase3, &phase3_bufpos); + + /* Set domain. If is empty, default domain will be used (i.e. proxy's domain) */ + add_security_buffer(0x1c, domain, strlen(domain), phase3, &phase3_bufpos); + + + /* other security buffers will be empty */ + phase3[0x10] = phase3_bufpos; /* lm not used */ + phase3[0x30] = phase3_bufpos; /* no workstation name supplied */ + phase3[0x38] = phase3_bufpos; /* no session key */ + + /* flags */ + phase3[0x3c] = 0x02; /* negotiate oem */ + phase3[0x3d] = 0x02; /* negotiate ntlm */ + + return ((const char *)make_base64_string2((unsigned char *)phase3, phase3_bufpos, gc)); } -#else -static void dummy(void) {} -#endif +#else /* if NTLM */ +static void +dummy(void) { +} +#endif /* if NTLM */ diff --git a/src/openvpn/ntlm.h b/src/openvpn/ntlm.h index 77903b08c5c..b0a6821449d 100644 --- a/src/openvpn/ntlm.h +++ b/src/openvpn/ntlm.h @@ -3,8 +3,9 @@ #if NTLM -const char *ntlm_phase_1 (const struct http_proxy_info *p, struct gc_arena *gc); -const char *ntlm_phase_3 (const struct http_proxy_info *p, const char *phase_2, struct gc_arena *gc); +const char *ntlm_phase_1(const struct http_proxy_info *p, struct gc_arena *gc); + +const char *ntlm_phase_3(const struct http_proxy_info *p, const char *phase_2, struct gc_arena *gc); #endif diff --git a/src/openvpn/occ-inline.h b/src/openvpn/occ-inline.h index 516eb4d96b3..5b656d4c65c 100644 --- a/src/openvpn/occ-inline.h +++ b/src/openvpn/occ-inline.h @@ -32,54 +32,65 @@ */ static inline int -occ_reset_op () +occ_reset_op() { - return -1; + return -1; } /* * Should we send an OCC_REQUEST message? */ static inline void -check_send_occ_req (struct context *c) +check_send_occ_req(struct context *c) { - void check_send_occ_req_dowork (struct context *c); - if (event_timeout_defined (&c->c2.occ_interval) - && event_timeout_trigger (&c->c2.occ_interval, - &c->c2.timeval, - (!TO_LINK_DEF(c) && c->c2.occ_op < 0) ? ETT_DEFAULT : 0)) - check_send_occ_req_dowork (c); + void check_send_occ_req_dowork(struct context *c); + + if (event_timeout_defined(&c->c2.occ_interval) + && event_timeout_trigger(&c->c2.occ_interval, + &c->c2.timeval, + (!TO_LINK_DEF(c) && c->c2.occ_op < 0) ? ETT_DEFAULT : 0)) + { + check_send_occ_req_dowork(c); + } } /* * Should we send an MTU load test? */ static inline void -check_send_occ_load_test (struct context *c) +check_send_occ_load_test(struct context *c) { - void check_send_occ_load_test_dowork (struct context *c); - if (event_timeout_defined (&c->c2.occ_mtu_load_test_interval) - && event_timeout_trigger (&c->c2.occ_mtu_load_test_interval, - &c->c2.timeval, - (!TO_LINK_DEF(c) && c->c2.occ_op < 0) ? ETT_DEFAULT : 0)) - check_send_occ_load_test_dowork (c); + void check_send_occ_load_test_dowork(struct context *c); + + if (event_timeout_defined(&c->c2.occ_mtu_load_test_interval) + && event_timeout_trigger(&c->c2.occ_mtu_load_test_interval, + &c->c2.timeval, + (!TO_LINK_DEF(c) && c->c2.occ_op < 0) ? ETT_DEFAULT : 0)) + { + check_send_occ_load_test_dowork(c); + } } /* * Should we send an OCC message? */ static inline void -check_send_occ_msg (struct context *c) +check_send_occ_msg(struct context *c) { - void check_send_occ_msg_dowork (struct context *c); - if (c->c2.occ_op >= 0) + void check_send_occ_msg_dowork(struct context *c); + + if (c->c2.occ_op >= 0) { - if (!TO_LINK_DEF(c)) - check_send_occ_msg_dowork (c); - else - tv_clear (&c->c2.timeval); /* ZERO-TIMEOUT */ + if (!TO_LINK_DEF(c)) + { + check_send_occ_msg_dowork(c); + } + else + { + tv_clear(&c->c2.timeval); /* ZERO-TIMEOUT */ + } } } -#endif -#endif +#endif /* ifdef ENABLE_OCC */ +#endif /* ifndef OCC_INLINE_H */ diff --git a/src/openvpn/occ.c b/src/openvpn/occ.c index d71381df699..046d03b1a6d 100644 --- a/src/openvpn/occ.c +++ b/src/openvpn/occ.c @@ -60,340 +60,376 @@ */ const uint8_t occ_magic[] = { - 0x28, 0x7f, 0x34, 0x6b, 0xd4, 0xef, 0x7a, 0x81, - 0x2d, 0x56, 0xb8, 0xd3, 0xaf, 0xc5, 0x45, 0x9c + 0x28, 0x7f, 0x34, 0x6b, 0xd4, 0xef, 0x7a, 0x81, + 0x2d, 0x56, 0xb8, 0xd3, 0xaf, 0xc5, 0x45, 0x9c }; static const struct mtu_load_test mtu_load_test_sequence[] = { - {OCC_MTU_LOAD_REQUEST, -1000}, - {OCC_MTU_LOAD, -1000}, - {OCC_MTU_LOAD_REQUEST, -1000}, - {OCC_MTU_LOAD, -1000}, - {OCC_MTU_LOAD_REQUEST, -1000}, - {OCC_MTU_LOAD, -1000}, - - {OCC_MTU_LOAD_REQUEST, -750}, - {OCC_MTU_LOAD, -750}, - {OCC_MTU_LOAD_REQUEST, -750}, - {OCC_MTU_LOAD, -750}, - {OCC_MTU_LOAD_REQUEST, -750}, - {OCC_MTU_LOAD, -750}, - - {OCC_MTU_LOAD_REQUEST, -500}, - {OCC_MTU_LOAD, -500}, - {OCC_MTU_LOAD_REQUEST, -500}, - {OCC_MTU_LOAD, -500}, - {OCC_MTU_LOAD_REQUEST, -500}, - {OCC_MTU_LOAD, -500}, - - {OCC_MTU_LOAD_REQUEST, -400}, - {OCC_MTU_LOAD, -400}, - {OCC_MTU_LOAD_REQUEST, -400}, - {OCC_MTU_LOAD, -400}, - {OCC_MTU_LOAD_REQUEST, -400}, - {OCC_MTU_LOAD, -400}, - - {OCC_MTU_LOAD_REQUEST, -300}, - {OCC_MTU_LOAD, -300}, - {OCC_MTU_LOAD_REQUEST, -300}, - {OCC_MTU_LOAD, -300}, - {OCC_MTU_LOAD_REQUEST, -300}, - {OCC_MTU_LOAD, -300}, - - {OCC_MTU_LOAD_REQUEST, -200}, - {OCC_MTU_LOAD, -200}, - {OCC_MTU_LOAD_REQUEST, -200}, - {OCC_MTU_LOAD, -200}, - {OCC_MTU_LOAD_REQUEST, -200}, - {OCC_MTU_LOAD, -200}, - - {OCC_MTU_LOAD_REQUEST, -150}, - {OCC_MTU_LOAD, -150}, - {OCC_MTU_LOAD_REQUEST, -150}, - {OCC_MTU_LOAD, -150}, - {OCC_MTU_LOAD_REQUEST, -150}, - {OCC_MTU_LOAD, -150}, - - {OCC_MTU_LOAD_REQUEST, -100}, - {OCC_MTU_LOAD, -100}, - {OCC_MTU_LOAD_REQUEST, -100}, - {OCC_MTU_LOAD, -100}, - {OCC_MTU_LOAD_REQUEST, -100}, - {OCC_MTU_LOAD, -100}, - - {OCC_MTU_LOAD_REQUEST, -50}, - {OCC_MTU_LOAD, -50}, - {OCC_MTU_LOAD_REQUEST, -50}, - {OCC_MTU_LOAD, -50}, - {OCC_MTU_LOAD_REQUEST, -50}, - {OCC_MTU_LOAD, -50}, - - {OCC_MTU_LOAD_REQUEST, 0}, - {OCC_MTU_LOAD, 0}, - {OCC_MTU_LOAD_REQUEST, 0}, - {OCC_MTU_LOAD, 0}, - {OCC_MTU_LOAD_REQUEST, 0}, - {OCC_MTU_LOAD, 0}, - - {OCC_MTU_REQUEST, 0}, - {OCC_MTU_REQUEST, 0}, - {OCC_MTU_REQUEST, 0}, - {OCC_MTU_REQUEST, 0}, - {OCC_MTU_REQUEST, 0}, - {OCC_MTU_REQUEST, 0}, - {OCC_MTU_REQUEST, 0}, - {OCC_MTU_REQUEST, 0}, - {OCC_MTU_REQUEST, 0}, - {OCC_MTU_REQUEST, 0}, - - {-1, 0} + {OCC_MTU_LOAD_REQUEST, -1000}, + {OCC_MTU_LOAD, -1000}, + {OCC_MTU_LOAD_REQUEST, -1000}, + {OCC_MTU_LOAD, -1000}, + {OCC_MTU_LOAD_REQUEST, -1000}, + {OCC_MTU_LOAD, -1000}, + + {OCC_MTU_LOAD_REQUEST, -750}, + {OCC_MTU_LOAD, -750}, + {OCC_MTU_LOAD_REQUEST, -750}, + {OCC_MTU_LOAD, -750}, + {OCC_MTU_LOAD_REQUEST, -750}, + {OCC_MTU_LOAD, -750}, + + {OCC_MTU_LOAD_REQUEST, -500}, + {OCC_MTU_LOAD, -500}, + {OCC_MTU_LOAD_REQUEST, -500}, + {OCC_MTU_LOAD, -500}, + {OCC_MTU_LOAD_REQUEST, -500}, + {OCC_MTU_LOAD, -500}, + + {OCC_MTU_LOAD_REQUEST, -400}, + {OCC_MTU_LOAD, -400}, + {OCC_MTU_LOAD_REQUEST, -400}, + {OCC_MTU_LOAD, -400}, + {OCC_MTU_LOAD_REQUEST, -400}, + {OCC_MTU_LOAD, -400}, + + {OCC_MTU_LOAD_REQUEST, -300}, + {OCC_MTU_LOAD, -300}, + {OCC_MTU_LOAD_REQUEST, -300}, + {OCC_MTU_LOAD, -300}, + {OCC_MTU_LOAD_REQUEST, -300}, + {OCC_MTU_LOAD, -300}, + + {OCC_MTU_LOAD_REQUEST, -200}, + {OCC_MTU_LOAD, -200}, + {OCC_MTU_LOAD_REQUEST, -200}, + {OCC_MTU_LOAD, -200}, + {OCC_MTU_LOAD_REQUEST, -200}, + {OCC_MTU_LOAD, -200}, + + {OCC_MTU_LOAD_REQUEST, -150}, + {OCC_MTU_LOAD, -150}, + {OCC_MTU_LOAD_REQUEST, -150}, + {OCC_MTU_LOAD, -150}, + {OCC_MTU_LOAD_REQUEST, -150}, + {OCC_MTU_LOAD, -150}, + + {OCC_MTU_LOAD_REQUEST, -100}, + {OCC_MTU_LOAD, -100}, + {OCC_MTU_LOAD_REQUEST, -100}, + {OCC_MTU_LOAD, -100}, + {OCC_MTU_LOAD_REQUEST, -100}, + {OCC_MTU_LOAD, -100}, + + {OCC_MTU_LOAD_REQUEST, -50}, + {OCC_MTU_LOAD, -50}, + {OCC_MTU_LOAD_REQUEST, -50}, + {OCC_MTU_LOAD, -50}, + {OCC_MTU_LOAD_REQUEST, -50}, + {OCC_MTU_LOAD, -50}, + + {OCC_MTU_LOAD_REQUEST, 0}, + {OCC_MTU_LOAD, 0}, + {OCC_MTU_LOAD_REQUEST, 0}, + {OCC_MTU_LOAD, 0}, + {OCC_MTU_LOAD_REQUEST, 0}, + {OCC_MTU_LOAD, 0}, + + {OCC_MTU_REQUEST, 0}, + {OCC_MTU_REQUEST, 0}, + {OCC_MTU_REQUEST, 0}, + {OCC_MTU_REQUEST, 0}, + {OCC_MTU_REQUEST, 0}, + {OCC_MTU_REQUEST, 0}, + {OCC_MTU_REQUEST, 0}, + {OCC_MTU_REQUEST, 0}, + {OCC_MTU_REQUEST, 0}, + {OCC_MTU_REQUEST, 0}, + + {-1, 0} }; void -check_send_occ_req_dowork (struct context *c) +check_send_occ_req_dowork(struct context *c) { - if (++c->c2.occ_n_tries >= OCC_N_TRIES) + if (++c->c2.occ_n_tries >= OCC_N_TRIES) { - if (c->options.ce.remote) - /* - * No OCC_REPLY from peer after repeated attempts. - * Give up. - */ - msg (D_SHOW_OCC, - "NOTE: failed to obtain options consistency info from peer -- " - "this could occur if the remote peer is running a version of " - PACKAGE_NAME - " before 1.5-beta8 or if there is a network connectivity problem, and will not necessarily prevent " - PACKAGE_NAME - " from running (" counter_format " bytes received from peer, " counter_format - " bytes authenticated data channel traffic) -- you can disable the options consistency " - "check with --disable-occ.", - c->c2.link_read_bytes, - c->c2.link_read_bytes_auth); - event_timeout_clear (&c->c2.occ_interval); + if (c->options.ce.remote) + { + /* + * No OCC_REPLY from peer after repeated attempts. + * Give up. + */ + msg(D_SHOW_OCC, + "NOTE: failed to obtain options consistency info from peer -- " + "this could occur if the remote peer is running a version of " + PACKAGE_NAME + " before 1.5-beta8 or if there is a network connectivity problem, and will not necessarily prevent " + PACKAGE_NAME + " from running (" counter_format " bytes received from peer, " counter_format + " bytes authenticated data channel traffic) -- you can disable the options consistency " + "check with --disable-occ.", + c->c2.link_read_bytes, + c->c2.link_read_bytes_auth); + } + event_timeout_clear(&c->c2.occ_interval); } - else + else { - c->c2.occ_op = OCC_REQUEST; + c->c2.occ_op = OCC_REQUEST; - /* - * If we don't hear back from peer, send another - * OCC_REQUEST in OCC_INTERVAL_SECONDS. - */ - event_timeout_reset (&c->c2.occ_interval); + /* + * If we don't hear back from peer, send another + * OCC_REQUEST in OCC_INTERVAL_SECONDS. + */ + event_timeout_reset(&c->c2.occ_interval); } } void -check_send_occ_load_test_dowork (struct context *c) +check_send_occ_load_test_dowork(struct context *c) { - if (CONNECTION_ESTABLISHED (c)) + if (CONNECTION_ESTABLISHED(c)) { - const struct mtu_load_test *entry; - - if (!c->c2.occ_mtu_load_n_tries) - msg (M_INFO, - "NOTE: Beginning empirical MTU test -- results should be available in 3 to 4 minutes."); - - entry = &mtu_load_test_sequence[c->c2.occ_mtu_load_n_tries++]; - if (entry->op >= 0) - { - c->c2.occ_op = entry->op; - c->c2.occ_mtu_load_size = - EXPANDED_SIZE (&c->c2.frame) + entry->delta; - } - else - { - msg (M_INFO, - "NOTE: failed to empirically measure MTU (requires " PACKAGE_NAME " 1.5 or higher at other end of connection)."); - event_timeout_clear (&c->c2.occ_mtu_load_test_interval); - c->c2.occ_mtu_load_n_tries = 0; - } + const struct mtu_load_test *entry; + + if (!c->c2.occ_mtu_load_n_tries) + { + msg(M_INFO, + "NOTE: Beginning empirical MTU test -- results should be available in 3 to 4 minutes."); + } + + entry = &mtu_load_test_sequence[c->c2.occ_mtu_load_n_tries++]; + if (entry->op >= 0) + { + c->c2.occ_op = entry->op; + c->c2.occ_mtu_load_size = + EXPANDED_SIZE(&c->c2.frame) + entry->delta; + } + else + { + msg(M_INFO, + "NOTE: failed to empirically measure MTU (requires " PACKAGE_NAME " 1.5 or higher at other end of connection)."); + event_timeout_clear(&c->c2.occ_mtu_load_test_interval); + c->c2.occ_mtu_load_n_tries = 0; + } } } void -check_send_occ_msg_dowork (struct context *c) +check_send_occ_msg_dowork(struct context *c) { - bool doit = false; + bool doit = false; - c->c2.buf = c->c2.buffers->aux_buf; - ASSERT (buf_init (&c->c2.buf, FRAME_HEADROOM (&c->c2.frame))); - ASSERT (buf_safe (&c->c2.buf, MAX_RW_SIZE_TUN (&c->c2.frame))); - ASSERT (buf_write (&c->c2.buf, occ_magic, OCC_STRING_SIZE)); + c->c2.buf = c->c2.buffers->aux_buf; + ASSERT(buf_init(&c->c2.buf, FRAME_HEADROOM(&c->c2.frame))); + ASSERT(buf_safe(&c->c2.buf, MAX_RW_SIZE_TUN(&c->c2.frame))); + ASSERT(buf_write(&c->c2.buf, occ_magic, OCC_STRING_SIZE)); - switch (c->c2.occ_op) + switch (c->c2.occ_op) { - case OCC_REQUEST: - if (!buf_write_u8 (&c->c2.buf, OCC_REQUEST)) - break; - dmsg (D_PACKET_CONTENT, "SENT OCC_REQUEST"); - doit = true; - break; - - case OCC_REPLY: - if (!c->c2.options_string_local) - break; - if (!buf_write_u8 (&c->c2.buf, OCC_REPLY)) - break; - if (!buf_write (&c->c2.buf, c->c2.options_string_local, - strlen (c->c2.options_string_local) + 1)) - break; - dmsg (D_PACKET_CONTENT, "SENT OCC_REPLY"); - doit = true; - break; - - case OCC_MTU_REQUEST: - if (!buf_write_u8 (&c->c2.buf, OCC_MTU_REQUEST)) - break; - dmsg (D_PACKET_CONTENT, "SENT OCC_MTU_REQUEST"); - doit = true; - break; - - case OCC_MTU_REPLY: - if (!buf_write_u8 (&c->c2.buf, OCC_MTU_REPLY)) - break; - if (!buf_write_u16 (&c->c2.buf, c->c2.max_recv_size_local)) - break; - if (!buf_write_u16 (&c->c2.buf, c->c2.max_send_size_local)) - break; - dmsg (D_PACKET_CONTENT, "SENT OCC_MTU_REPLY"); - doit = true; - break; - - case OCC_MTU_LOAD_REQUEST: - if (!buf_write_u8 (&c->c2.buf, OCC_MTU_LOAD_REQUEST)) - break; - if (!buf_write_u16 (&c->c2.buf, c->c2.occ_mtu_load_size)) - break; - dmsg (D_PACKET_CONTENT, "SENT OCC_MTU_LOAD_REQUEST"); - doit = true; - break; - - case OCC_MTU_LOAD: - { - int need_to_add; - - if (!buf_write_u8 (&c->c2.buf, OCC_MTU_LOAD)) - break; - need_to_add = min_int (c->c2.occ_mtu_load_size, EXPANDED_SIZE (&c->c2.frame)) - - OCC_STRING_SIZE - - sizeof (uint8_t) - - EXTRA_FRAME (&c->c2.frame); - - while (need_to_add > 0) - { - /* - * Fill the load test packet with pseudo-random bytes. - */ - if (!buf_write_u8 (&c->c2.buf, get_random () & 0xFF)) - break; - --need_to_add; - } - dmsg (D_PACKET_CONTENT, "SENT OCC_MTU_LOAD min_int(%d-%d-%d-%d,%d) size=%d", - c->c2.occ_mtu_load_size, - OCC_STRING_SIZE, - (int) sizeof (uint8_t), - EXTRA_FRAME (&c->c2.frame), - MAX_RW_SIZE_TUN (&c->c2.frame), - BLEN (&c->c2.buf)); - doit = true; - } - break; - - case OCC_EXIT: - if (!buf_write_u8 (&c->c2.buf, OCC_EXIT)) - break; - dmsg (D_PACKET_CONTENT, "SENT OCC_EXIT"); - doit = true; - break; + case OCC_REQUEST: + if (!buf_write_u8(&c->c2.buf, OCC_REQUEST)) + { + break; + } + dmsg(D_PACKET_CONTENT, "SENT OCC_REQUEST"); + doit = true; + break; + + case OCC_REPLY: + if (!c->c2.options_string_local) + { + break; + } + if (!buf_write_u8(&c->c2.buf, OCC_REPLY)) + { + break; + } + if (!buf_write(&c->c2.buf, c->c2.options_string_local, + strlen(c->c2.options_string_local) + 1)) + { + break; + } + dmsg(D_PACKET_CONTENT, "SENT OCC_REPLY"); + doit = true; + break; + + case OCC_MTU_REQUEST: + if (!buf_write_u8(&c->c2.buf, OCC_MTU_REQUEST)) + { + break; + } + dmsg(D_PACKET_CONTENT, "SENT OCC_MTU_REQUEST"); + doit = true; + break; + + case OCC_MTU_REPLY: + if (!buf_write_u8(&c->c2.buf, OCC_MTU_REPLY)) + { + break; + } + if (!buf_write_u16(&c->c2.buf, c->c2.max_recv_size_local)) + { + break; + } + if (!buf_write_u16(&c->c2.buf, c->c2.max_send_size_local)) + { + break; + } + dmsg(D_PACKET_CONTENT, "SENT OCC_MTU_REPLY"); + doit = true; + break; + + case OCC_MTU_LOAD_REQUEST: + if (!buf_write_u8(&c->c2.buf, OCC_MTU_LOAD_REQUEST)) + { + break; + } + if (!buf_write_u16(&c->c2.buf, c->c2.occ_mtu_load_size)) + { + break; + } + dmsg(D_PACKET_CONTENT, "SENT OCC_MTU_LOAD_REQUEST"); + doit = true; + break; + + case OCC_MTU_LOAD: + { + int need_to_add; + + if (!buf_write_u8(&c->c2.buf, OCC_MTU_LOAD)) + { + break; + } + need_to_add = min_int(c->c2.occ_mtu_load_size, EXPANDED_SIZE(&c->c2.frame)) + - OCC_STRING_SIZE + - sizeof(uint8_t) + - EXTRA_FRAME(&c->c2.frame); + + while (need_to_add > 0) + { + /* + * Fill the load test packet with pseudo-random bytes. + */ + if (!buf_write_u8(&c->c2.buf, get_random() & 0xFF)) + { + break; + } + --need_to_add; + } + dmsg(D_PACKET_CONTENT, "SENT OCC_MTU_LOAD min_int(%d-%d-%d-%d,%d) size=%d", + c->c2.occ_mtu_load_size, + OCC_STRING_SIZE, + (int) sizeof(uint8_t), + EXTRA_FRAME(&c->c2.frame), + MAX_RW_SIZE_TUN(&c->c2.frame), + BLEN(&c->c2.buf)); + doit = true; + } + break; + + case OCC_EXIT: + if (!buf_write_u8(&c->c2.buf, OCC_EXIT)) + { + break; + } + dmsg(D_PACKET_CONTENT, "SENT OCC_EXIT"); + doit = true; + break; } - if (doit) + if (doit) { - /* - * We will treat the packet like any other outgoing packet, - * compress, encrypt, sign, etc. - */ - encrypt_sign (c, true); + /* + * We will treat the packet like any other outgoing packet, + * compress, encrypt, sign, etc. + */ + encrypt_sign(c, true); } - c->c2.occ_op = -1; + c->c2.occ_op = -1; } void -process_received_occ_msg (struct context *c) +process_received_occ_msg(struct context *c) { - ASSERT (buf_advance (&c->c2.buf, OCC_STRING_SIZE)); - switch (buf_read_u8 (&c->c2.buf)) + ASSERT(buf_advance(&c->c2.buf, OCC_STRING_SIZE)); + switch (buf_read_u8(&c->c2.buf)) { - case OCC_REQUEST: - dmsg (D_PACKET_CONTENT, "RECEIVED OCC_REQUEST"); - c->c2.occ_op = OCC_REPLY; - break; - - case OCC_MTU_REQUEST: - dmsg (D_PACKET_CONTENT, "RECEIVED OCC_MTU_REQUEST"); - c->c2.occ_op = OCC_MTU_REPLY; - break; - - case OCC_MTU_LOAD_REQUEST: - dmsg (D_PACKET_CONTENT, "RECEIVED OCC_MTU_LOAD_REQUEST"); - c->c2.occ_mtu_load_size = buf_read_u16 (&c->c2.buf); - if (c->c2.occ_mtu_load_size >= 0) - c->c2.occ_op = OCC_MTU_LOAD; - break; - - case OCC_REPLY: - dmsg (D_PACKET_CONTENT, "RECEIVED OCC_REPLY"); - if (c->options.occ && !TLS_MODE (c) && c->c2.options_string_remote) - { - if (!options_cmp_equal_safe ((char *) BPTR (&c->c2.buf), - c->c2.options_string_remote, - c->c2.buf.len)) - { - options_warning_safe ((char *) BPTR (&c->c2.buf), - c->c2.options_string_remote, - c->c2.buf.len); - } - } - event_timeout_clear (&c->c2.occ_interval); - break; - - case OCC_MTU_REPLY: - dmsg (D_PACKET_CONTENT, "RECEIVED OCC_MTU_REPLY"); - c->c2.max_recv_size_remote = buf_read_u16 (&c->c2.buf); - c->c2.max_send_size_remote = buf_read_u16 (&c->c2.buf); - if (c->options.mtu_test - && c->c2.max_recv_size_remote > 0 - && c->c2.max_send_size_remote > 0) - { - msg (M_INFO, "NOTE: Empirical MTU test completed [Tried,Actual] local->remote=[%d,%d] remote->local=[%d,%d]", - c->c2.max_send_size_local, - c->c2.max_recv_size_remote, - c->c2.max_send_size_remote, - c->c2.max_recv_size_local); - if (!c->options.ce.fragment - && (proto_is_dgram(c->options.ce.proto)) - && c->c2.max_send_size_local > TUN_MTU_MIN - && (c->c2.max_recv_size_remote < c->c2.max_send_size_local - || c->c2.max_recv_size_local < c->c2.max_send_size_remote)) - msg (M_INFO, "NOTE: This connection is unable to accommodate a UDP packet size of %d. Consider using --fragment or --mssfix options as a workaround.", - c->c2.max_send_size_local); - } - event_timeout_clear (&c->c2.occ_mtu_load_test_interval); - break; - - case OCC_EXIT: - dmsg (D_PACKET_CONTENT, "RECEIVED OCC_EXIT"); - c->sig->signal_received = SIGTERM; - c->sig->signal_text = "remote-exit"; - break; + case OCC_REQUEST: + dmsg(D_PACKET_CONTENT, "RECEIVED OCC_REQUEST"); + c->c2.occ_op = OCC_REPLY; + break; + + case OCC_MTU_REQUEST: + dmsg(D_PACKET_CONTENT, "RECEIVED OCC_MTU_REQUEST"); + c->c2.occ_op = OCC_MTU_REPLY; + break; + + case OCC_MTU_LOAD_REQUEST: + dmsg(D_PACKET_CONTENT, "RECEIVED OCC_MTU_LOAD_REQUEST"); + c->c2.occ_mtu_load_size = buf_read_u16(&c->c2.buf); + if (c->c2.occ_mtu_load_size >= 0) + { + c->c2.occ_op = OCC_MTU_LOAD; + } + break; + + case OCC_REPLY: + dmsg(D_PACKET_CONTENT, "RECEIVED OCC_REPLY"); + if (c->options.occ && !TLS_MODE(c) && c->c2.options_string_remote) + { + if (!options_cmp_equal_safe((char *) BPTR(&c->c2.buf), + c->c2.options_string_remote, + c->c2.buf.len)) + { + options_warning_safe((char *) BPTR(&c->c2.buf), + c->c2.options_string_remote, + c->c2.buf.len); + } + } + event_timeout_clear(&c->c2.occ_interval); + break; + + case OCC_MTU_REPLY: + dmsg(D_PACKET_CONTENT, "RECEIVED OCC_MTU_REPLY"); + c->c2.max_recv_size_remote = buf_read_u16(&c->c2.buf); + c->c2.max_send_size_remote = buf_read_u16(&c->c2.buf); + if (c->options.mtu_test + && c->c2.max_recv_size_remote > 0 + && c->c2.max_send_size_remote > 0) + { + msg(M_INFO, "NOTE: Empirical MTU test completed [Tried,Actual] local->remote=[%d,%d] remote->local=[%d,%d]", + c->c2.max_send_size_local, + c->c2.max_recv_size_remote, + c->c2.max_send_size_remote, + c->c2.max_recv_size_local); + if (!c->options.ce.fragment + && (proto_is_dgram(c->options.ce.proto)) + && c->c2.max_send_size_local > TUN_MTU_MIN + && (c->c2.max_recv_size_remote < c->c2.max_send_size_local + || c->c2.max_recv_size_local < c->c2.max_send_size_remote)) + { + msg(M_INFO, "NOTE: This connection is unable to accommodate a UDP packet size of %d. Consider using --fragment or --mssfix options as a workaround.", + c->c2.max_send_size_local); + } + } + event_timeout_clear(&c->c2.occ_mtu_load_test_interval); + break; + + case OCC_EXIT: + dmsg(D_PACKET_CONTENT, "RECEIVED OCC_EXIT"); + c->sig->signal_received = SIGTERM; + c->sig->signal_text = "remote-exit"; + break; } - c->c2.buf.len = 0; /* don't pass packet on */ + c->c2.buf.len = 0; /* don't pass packet on */ } -#else -static void dummy(void) {} -#endif +#else /* ifdef ENABLE_OCC */ +static void +dummy(void) { +} +#endif /* ifdef ENABLE_OCC */ diff --git a/src/openvpn/occ.h b/src/openvpn/occ.h index 5d88cc9ec35..cb5d957fb84 100644 --- a/src/openvpn/occ.h +++ b/src/openvpn/occ.h @@ -36,8 +36,8 @@ * OCC (OpenVPN Configuration Control) protocol opcodes. */ -#define OCC_REQUEST 0 /* request options string from peer */ -#define OCC_REPLY 1 /* deliver options string to peer */ +#define OCC_REQUEST 0 /* request options string from peer */ +#define OCC_REPLY 1 /* deliver options string to peer */ /* * Send an OCC_REQUEST once every OCC_INTERVAL @@ -52,11 +52,11 @@ /* * Other OCC protocol opcodes used to estimate the MTU empirically. */ -#define OCC_MTU_LOAD_REQUEST 2 /* Ask peer to send a big packet to us */ -#define OCC_MTU_LOAD 3 /* Send a big packet to peer */ -#define OCC_MTU_REQUEST 4 /* Ask peer to tell us the largest - packet it has received from us so far */ -#define OCC_MTU_REPLY 5 /* Send largest packet size to peer */ +#define OCC_MTU_LOAD_REQUEST 2 /* Ask peer to send a big packet to us */ +#define OCC_MTU_LOAD 3 /* Send a big packet to peer */ +#define OCC_MTU_REQUEST 4 /* Ask peer to tell us the largest + * packet it has received from us so far */ +#define OCC_MTU_REPLY 5 /* Send largest packet size to peer */ /* * Process one command from mtu_load_test_sequence @@ -75,21 +75,21 @@ */ struct mtu_load_test { - int op; /* OCC opcode to send to peer */ - int delta; /* determine packet size to send by using - this delta against currently - configured MTU */ + int op; /* OCC opcode to send to peer */ + int delta; /* determine packet size to send by using + * this delta against currently + * configured MTU */ }; extern const uint8_t occ_magic[]; static inline bool -is_occ_msg (const struct buffer* buf) +is_occ_msg(const struct buffer *buf) { - return buf_string_match_head (buf, occ_magic, OCC_STRING_SIZE); + return buf_string_match_head(buf, occ_magic, OCC_STRING_SIZE); } -void process_received_occ_msg (struct context *c); +void process_received_occ_msg(struct context *c); -#endif -#endif +#endif /* ifdef ENABLE_OCC */ +#endif /* ifndef OCC_H */ diff --git a/src/openvpn/openvpn.c b/src/openvpn/openvpn.c index 5fb2fd9cfaf..9a1ff9ce446 100644 --- a/src/openvpn/openvpn.c +++ b/src/openvpn/openvpn.c @@ -39,13 +39,13 @@ #include "forward-inline.h" -#define P2P_CHECK_SIG() EVENT_LOOP_CHECK_SIGNAL (c, process_signal_p2p, c); +#define P2P_CHECK_SIG() EVENT_LOOP_CHECK_SIGNAL(c, process_signal_p2p, c); static bool -process_signal_p2p (struct context *c) +process_signal_p2p(struct context *c) { - remap_signal (c); - return process_signal (c); + remap_signal(c); + return process_signal(c); } @@ -59,49 +59,51 @@ process_signal_p2p (struct context *c) * @param c - The context structure of the single active VPN tunnel. */ static void -tunnel_point_to_point (struct context *c) +tunnel_point_to_point(struct context *c) { - context_clear_2 (c); + context_clear_2(c); - /* set point-to-point mode */ - c->mode = CM_P2P; + /* set point-to-point mode */ + c->mode = CM_P2P; - /* initialize tunnel instance */ - init_instance_handle_signals (c, c->es, CC_HARD_USR1_TO_HUP); - if (IS_SIG (c)) - return; + /* initialize tunnel instance */ + init_instance_handle_signals(c, c->es, CC_HARD_USR1_TO_HUP); + if (IS_SIG(c)) + { + return; + } - /* main event loop */ - while (true) + /* main event loop */ + while (true) { - perf_push (PERF_EVENT_LOOP); + perf_push(PERF_EVENT_LOOP); - /* process timers, TLS, etc. */ - pre_select (c); - P2P_CHECK_SIG(); + /* process timers, TLS, etc. */ + pre_select(c); + P2P_CHECK_SIG(); - /* set up and do the I/O wait */ - io_wait (c, p2p_iow_flags (c)); - P2P_CHECK_SIG(); + /* set up and do the I/O wait */ + io_wait(c, p2p_iow_flags(c)); + P2P_CHECK_SIG(); - /* timeout? */ - if (c->c2.event_set_status == ES_TIMEOUT) - { - perf_pop (); - continue; - } + /* timeout? */ + if (c->c2.event_set_status == ES_TIMEOUT) + { + perf_pop(); + continue; + } - /* process the I/O which triggered select */ - process_io (c); - P2P_CHECK_SIG(); + /* process the I/O which triggered select */ + process_io(c); + P2P_CHECK_SIG(); - perf_pop (); + perf_pop(); } - uninit_management_callback (); + uninit_management_callback(); - /* tear down tunnel instance (unless --persist-tun) */ - close_instance (c); + /* tear down tunnel instance (unless --persist-tun) */ + close_instance(c); } #undef PROCESS_SIGNAL_P2P @@ -129,219 +131,237 @@ tunnel_point_to_point (struct context *c) */ static int -openvpn_main (int argc, char *argv[]) +openvpn_main(int argc, char *argv[]) { - struct context c; + struct context c; #if PEDANTIC - fprintf (stderr, "Sorry, I was built with --enable-pedantic and I am incapable of doing any real work!\n"); - return 1; + fprintf(stderr, "Sorry, I was built with --enable-pedantic and I am incapable of doing any real work!\n"); + return 1; #endif #ifdef _WIN32 - SetConsoleOutputCP (CP_UTF8); + SetConsoleOutputCP(CP_UTF8); #endif - CLEAR (c); + CLEAR(c); - /* signify first time for components which can - only be initialized once per program instantiation. */ - c.first_time = true; + /* signify first time for components which can + * only be initialized once per program instantiation. */ + c.first_time = true; - /* initialize program-wide statics */ - if (init_static ()) + /* initialize program-wide statics */ + if (init_static()) { - /* - * This loop is initially executed on startup and then - * once per SIGHUP. - */ - do - { - /* enter pre-initialization mode with regard to signal handling */ - pre_init_signal_catch (); - - /* zero context struct but leave first_time member alone */ - context_clear_all_except_first_time (&c); - - /* static signal info object */ - CLEAR (siginfo_static); - c.sig = &siginfo_static; - - /* initialize garbage collector scoped to context object */ - gc_init (&c.gc); - - /* initialize environmental variable store */ - c.es = env_set_create (NULL); + /* + * This loop is initially executed on startup and then + * once per SIGHUP. + */ + do + { + /* enter pre-initialization mode with regard to signal handling */ + pre_init_signal_catch(); + + /* zero context struct but leave first_time member alone */ + context_clear_all_except_first_time(&c); + + /* static signal info object */ + CLEAR(siginfo_static); + c.sig = &siginfo_static; + + /* initialize garbage collector scoped to context object */ + gc_init(&c.gc); + + /* initialize environmental variable store */ + c.es = env_set_create(NULL); #ifdef _WIN32 - set_win_sys_path_via_env (c.es); + set_win_sys_path_via_env(c.es); #endif #ifdef ENABLE_MANAGEMENT - /* initialize management subsystem */ - init_management (&c); + /* initialize management subsystem */ + init_management(&c); #endif - /* initialize options to default state */ - init_options (&c.options, true); + /* initialize options to default state */ + init_options(&c.options, true); - /* parse command line options, and read configuration file */ - parse_argv (&c.options, argc, argv, M_USAGE, OPT_P_DEFAULT, NULL, c.es); + /* parse command line options, and read configuration file */ + parse_argv(&c.options, argc, argv, M_USAGE, OPT_P_DEFAULT, NULL, c.es); #ifdef ENABLE_PLUGIN - /* plugins may contribute options configuration */ - init_verb_mute (&c, IVM_LEVEL_1); - init_plugins (&c); - open_plugins (&c, true, OPENVPN_PLUGIN_INIT_PRE_CONFIG_PARSE); + /* plugins may contribute options configuration */ + init_verb_mute(&c, IVM_LEVEL_1); + init_plugins(&c); + open_plugins(&c, true, OPENVPN_PLUGIN_INIT_PRE_CONFIG_PARSE); #endif - /* init verbosity and mute levels */ - init_verb_mute (&c, IVM_LEVEL_1); + /* init verbosity and mute levels */ + init_verb_mute(&c, IVM_LEVEL_1); - /* set dev options */ - init_options_dev (&c.options); + /* set dev options */ + init_options_dev(&c.options); - /* openssl print info? */ - if (print_openssl_info (&c.options)) - break; + /* openssl print info? */ + if (print_openssl_info(&c.options)) + { + break; + } - /* --genkey mode? */ - if (do_genkey (&c.options)) - break; + /* --genkey mode? */ + if (do_genkey(&c.options)) + { + break; + } - /* tun/tap persist command? */ - if (do_persist_tuntap (&c.options)) - break; + /* tun/tap persist command? */ + if (do_persist_tuntap(&c.options)) + { + break; + } - /* sanity check on options */ - options_postprocess (&c.options); + /* sanity check on options */ + options_postprocess(&c.options); - /* show all option settings */ - show_settings (&c.options); + /* show all option settings */ + show_settings(&c.options); - /* print version number */ - msg (M_INFO, "%s", title_string); + /* print version number */ + msg(M_INFO, "%s", title_string); #ifdef _WIN32 - show_windows_version(M_INFO); + show_windows_version(M_INFO); #endif - show_library_versions(M_INFO); + show_library_versions(M_INFO); - /* misc stuff */ - pre_setup (&c.options); + /* misc stuff */ + pre_setup(&c.options); - /* test crypto? */ - if (do_test_crypto (&c.options)) - break; + /* test crypto? */ + if (do_test_crypto(&c.options)) + { + break; + } - /* Query passwords before becoming a daemon if we don't use the - * management interface to get them. */ + /* Query passwords before becoming a daemon if we don't use the + * management interface to get them. */ #ifdef ENABLE_MANAGEMENT - if (!(c.options.management_flags & MF_QUERY_PASSWORDS)) + if (!(c.options.management_flags & MF_QUERY_PASSWORDS)) #endif - init_query_passwords (&c); + init_query_passwords(&c); - /* become a daemon if --daemon */ - if (c.first_time) - { - c.did_we_daemonize = possibly_become_daemon (&c.options); - write_pid (c.options.writepid); - } + /* become a daemon if --daemon */ + if (c.first_time) + { + c.did_we_daemonize = possibly_become_daemon(&c.options); + write_pid(c.options.writepid); + } #ifdef ENABLE_MANAGEMENT - /* open management subsystem */ - if (!open_management (&c)) - break; - /* query for passwords through management interface, if needed */ - if (c.options.management_flags & MF_QUERY_PASSWORDS) - init_query_passwords (&c); + /* open management subsystem */ + if (!open_management(&c)) + { + break; + } + /* query for passwords through management interface, if needed */ + if (c.options.management_flags & MF_QUERY_PASSWORDS) + { + init_query_passwords(&c); + } #endif - /* set certain options as environmental variables */ - setenv_settings (c.es, &c.options); + /* set certain options as environmental variables */ + setenv_settings(c.es, &c.options); - /* finish context init */ - context_init_1 (&c); + /* finish context init */ + context_init_1(&c); + + do + { + /* run tunnel depending on mode */ + switch (c.options.mode) + { + case MODE_POINT_TO_POINT: + tunnel_point_to_point(&c); + break; - do - { - /* run tunnel depending on mode */ - switch (c.options.mode) - { - case MODE_POINT_TO_POINT: - tunnel_point_to_point (&c); - break; #if P2MP_SERVER - case MODE_SERVER: - tunnel_server (&c); - break; + case MODE_SERVER: + tunnel_server(&c); + break; + #endif - default: - ASSERT (0); - } - - /* indicates first iteration -- has program-wide scope */ - c.first_time = false; - - /* any signals received? */ - if (IS_SIG (&c)) - print_signal (c.sig, NULL, M_INFO); - - /* pass restart status to management subsystem */ - signal_restart_status (c.sig); - } - while (c.sig->signal_received == SIGUSR1); - - uninit_options (&c.options); - gc_reset (&c.gc); - } - while (c.sig->signal_received == SIGHUP); + default: + ASSERT(0); + } + + /* indicates first iteration -- has program-wide scope */ + c.first_time = false; + + /* any signals received? */ + if (IS_SIG(&c)) + { + print_signal(c.sig, NULL, M_INFO); + } + + /* pass restart status to management subsystem */ + signal_restart_status(c.sig); + } + while (c.sig->signal_received == SIGUSR1); + + uninit_options(&c.options); + gc_reset(&c.gc); + } + while (c.sig->signal_received == SIGHUP); } - context_gc_free (&c); + context_gc_free(&c); - env_set_destroy (c.es); + env_set_destroy(c.es); #ifdef ENABLE_MANAGEMENT - /* close management interface */ - close_management (); + /* close management interface */ + close_management(); #endif - /* uninitialize program-wide statics */ - uninit_static (); + /* uninitialize program-wide statics */ + uninit_static(); - openvpn_exit (OPENVPN_EXIT_STATUS_GOOD); /* exit point */ - return 0; /* NOTREACHED */ + openvpn_exit(OPENVPN_EXIT_STATUS_GOOD); /* exit point */ + return 0; /* NOTREACHED */ } #ifdef _WIN32 int -wmain (int argc, wchar_t *wargv[]) { - char **argv; - int ret; - int i; +wmain(int argc, wchar_t *wargv[]) { + char **argv; + int ret; + int i; - if ((argv = calloc(argc+1, sizeof(char*))) == NULL) - return 1; + if ((argv = calloc(argc+1, sizeof(char *))) == NULL) + { + return 1; + } - for (i = 0; i < argc; i++) + for (i = 0; i < argc; i++) { - int n = WideCharToMultiByte (CP_UTF8, 0, wargv[i], -1, NULL, 0, NULL, NULL); - argv[i] = malloc (n); - WideCharToMultiByte (CP_UTF8, 0, wargv[i], -1, argv[i], n, NULL, NULL); + int n = WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1, NULL, 0, NULL, NULL); + argv[i] = malloc(n); + WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1, argv[i], n, NULL, NULL); } - ret = openvpn_main(argc, argv); + ret = openvpn_main(argc, argv); - for (i=0; i < argc; i++ ) + for (i = 0; i < argc; i++) { - free (argv[i]); + free(argv[i]); } - free(argv); + free(argv); - return ret; + return ret; } -#else +#else /* ifdef _WIN32 */ int -main (int argc, char *argv[]) { - return openvpn_main(argc, argv); +main(int argc, char *argv[]) { + return openvpn_main(argc, argv); } -#endif +#endif /* ifdef _WIN32 */ diff --git a/src/openvpn/openvpn.h b/src/openvpn/openvpn.h index fa5cc1d58a8..36c53e8f47b 100644 --- a/src/openvpn/openvpn.h +++ b/src/openvpn/openvpn.h @@ -56,21 +56,21 @@ struct key_schedule { #ifdef ENABLE_CRYPTO - /* which cipher, HMAC digest, and key sizes are we using? */ - struct key_type key_type; + /* which cipher, HMAC digest, and key sizes are we using? */ + struct key_type key_type; - /* pre-shared static key, read from a file */ - struct key_ctx_bi static_key; + /* pre-shared static key, read from a file */ + struct key_ctx_bi static_key; - /* our global SSL context */ - struct tls_root_ctx ssl_ctx; + /* our global SSL context */ + struct tls_root_ctx ssl_ctx; - /* optional TLS control channel wrapping */ - struct key_type tls_auth_key_type; - struct key_ctx_bi tls_wrap_key; -#else /* ENABLE_CRYPTO */ - int dummy; -#endif /* ENABLE_CRYPTO */ + /* optional TLS control channel wrapping */ + struct key_type tls_auth_key_type; + struct key_ctx_bi tls_wrap_key; +#else /* ENABLE_CRYPTO */ + int dummy; +#endif /* ENABLE_CRYPTO */ }; /* @@ -80,10 +80,10 @@ struct key_schedule #ifndef PACKET_ID_H struct packet_id_persist { - int dummy; + int dummy; }; static inline void -packet_id_persist_init (struct packet_id_persist *p) +packet_id_persist_init(struct packet_id_persist *p) { } #endif @@ -93,27 +93,27 @@ packet_id_persist_init (struct packet_id_persist *p) */ struct context_buffers { - /* miscellaneous buffer, used by ping, occ, etc. */ - struct buffer aux_buf; + /* miscellaneous buffer, used by ping, occ, etc. */ + struct buffer aux_buf; - /* workspace buffers used by crypto routines */ + /* workspace buffers used by crypto routines */ #ifdef ENABLE_CRYPTO - struct buffer encrypt_buf; - struct buffer decrypt_buf; + struct buffer encrypt_buf; + struct buffer decrypt_buf; #endif - /* workspace buffers for compression */ + /* workspace buffers for compression */ #ifdef USE_COMP - struct buffer compress_buf; - struct buffer decompress_buf; + struct buffer compress_buf; + struct buffer decompress_buf; #endif - /* - * Buffers used to read from TUN device - * and TCP/UDP port. - */ - struct buffer read_link_buf; - struct buffer read_tun_buf; + /* + * Buffers used to read from TUN device + * and TCP/UDP port. + */ + struct buffer read_link_buf; + struct buffer read_tun_buf; }; /* @@ -121,7 +121,7 @@ struct context_buffers */ struct context_persist { - int restart_sleep_seconds; + int restart_sleep_seconds; }; @@ -136,12 +136,12 @@ struct context_persist */ struct context_0 { - /* workspace for --user/--group */ - bool uid_gid_specified; - /* helper which tells us whether we should keep trying to drop privileges */ - bool uid_gid_chroot_set; - struct platform_state_user platform_state_user; - struct platform_state_group platform_state_group; + /* workspace for --user/--group */ + bool uid_gid_specified; + /* helper which tells us whether we should keep trying to drop privileges */ + bool uid_gid_chroot_set; + struct platform_state_user platform_state_user; + struct platform_state_group platform_state_group; }; @@ -156,64 +156,64 @@ struct context_0 */ struct context_1 { - struct link_socket_addr link_socket_addr; - /**< Local and remote addresses on the - * external network. */ + struct link_socket_addr link_socket_addr; + /**< Local and remote addresses on the + * external network. */ - /* tunnel session keys */ - struct key_schedule ks; + /* tunnel session keys */ + struct key_schedule ks; - /* preresolved and cached host names */ - struct cached_dns_entry *dns_cache; + /* preresolved and cached host names */ + struct cached_dns_entry *dns_cache; - /* persist crypto sequence number to/from file */ - struct packet_id_persist pid_persist; + /* persist crypto sequence number to/from file */ + struct packet_id_persist pid_persist; - struct tuntap *tuntap; /**< Tun/tap virtual network interface. */ - bool tuntap_owned; /**< Whether the tun/tap interface should + struct tuntap *tuntap; /**< Tun/tap virtual network interface. */ + bool tuntap_owned; /**< Whether the tun/tap interface should * be cleaned up when this %context is * cleaned up. */ - struct route_list *route_list; - /**< List of routing information. See the - * \c --route command line option. */ + struct route_list *route_list; + /**< List of routing information. See the + * \c --route command line option. */ - /* list of --route-ipv6 directives */ - struct route_ipv6_list *route_ipv6_list; + /* list of --route-ipv6 directives */ + struct route_ipv6_list *route_ipv6_list; - /* --status file */ - struct status_output *status_output; - bool status_output_owned; + /* --status file */ + struct status_output *status_output; + bool status_output_owned; - /* HTTP proxy object */ - struct http_proxy_info *http_proxy; - bool http_proxy_owned; + /* HTTP proxy object */ + struct http_proxy_info *http_proxy; + bool http_proxy_owned; - /* SOCKS proxy object */ - struct socks_proxy_info *socks_proxy; - bool socks_proxy_owned; + /* SOCKS proxy object */ + struct socks_proxy_info *socks_proxy; + bool socks_proxy_owned; #if P2MP #if P2MP_SERVER - /* persist --ifconfig-pool db to file */ - struct ifconfig_pool_persist *ifconfig_pool_persist; - bool ifconfig_pool_persist_owned; + /* persist --ifconfig-pool db to file */ + struct ifconfig_pool_persist *ifconfig_pool_persist; + bool ifconfig_pool_persist_owned; #endif - /* if client mode, hash of option strings we pulled from server */ - struct md5_digest pulled_options_digest_save; - /**< Hash of option strings received from the - * remote OpenVPN server. Only used in - * client-mode. */ + /* if client mode, hash of option strings we pulled from server */ + struct md5_digest pulled_options_digest_save; + /**< Hash of option strings received from the + * remote OpenVPN server. Only used in + * client-mode. */ - struct user_pass *auth_user_pass; - /**< Username and password for - * authentication. */ + struct user_pass *auth_user_pass; + /**< Username and password for + * authentication. */ - const char *ciphername; /**< Data channel cipher from config file */ - const char *authname; /**< Data channel auth from config file */ - int keysize; /**< Data channel keysize from config file */ + const char *ciphername; /**< Data channel cipher from config file */ + const char *authname; /**< Data channel auth from config file */ + int keysize; /**< Data channel keysize from config file */ #endif }; @@ -228,268 +228,268 @@ struct context_1 */ struct context_2 { - struct gc_arena gc; /**< Garbage collection arena for + struct gc_arena gc; /**< Garbage collection arena for * allocations done in the level 2 scope * of this context_2 structure. */ - /* our global wait events */ - struct event_set *event_set; - int event_set_max; - bool event_set_owned; - - /* event flags returned by io_wait */ -# define SOCKET_READ (1<<0) -# define SOCKET_WRITE (1<<1) -# define TUN_READ (1<<2) -# define TUN_WRITE (1<<3) -# define ES_ERROR (1<<4) -# define ES_TIMEOUT (1<<5) -# ifdef ENABLE_MANAGEMENT -# define MANAGEMENT_READ (1<<6) -# define MANAGEMENT_WRITE (1<<7) -# endif + /* our global wait events */ + struct event_set *event_set; + int event_set_max; + bool event_set_owned; + + /* event flags returned by io_wait */ +#define SOCKET_READ (1<<0) +#define SOCKET_WRITE (1<<1) +#define TUN_READ (1<<2) +#define TUN_WRITE (1<<3) +#define ES_ERROR (1<<4) +#define ES_TIMEOUT (1<<5) +#ifdef ENABLE_MANAGEMENT +#define MANAGEMENT_READ (1<<6) +#define MANAGEMENT_WRITE (1<<7) +#endif #ifdef ENABLE_ASYNC_PUSH -# define FILE_CLOSED (1<<8) +#define FILE_CLOSED (1<<8) #endif - unsigned int event_set_status; + unsigned int event_set_status; - struct link_socket *link_socket; /* socket used for TCP/UDP connection to remote */ - bool link_socket_owned; - struct link_socket_info *link_socket_info; - const struct link_socket *accept_from; /* possibly do accept() on a parent link_socket */ + struct link_socket *link_socket; /* socket used for TCP/UDP connection to remote */ + bool link_socket_owned; + struct link_socket_info *link_socket_info; + const struct link_socket *accept_from; /* possibly do accept() on a parent link_socket */ - struct link_socket_actual *to_link_addr; /* IP address of remote */ - struct link_socket_actual from; /* address of incoming datagram */ + struct link_socket_actual *to_link_addr; /* IP address of remote */ + struct link_socket_actual from; /* address of incoming datagram */ - /* MTU frame parameters */ - struct frame frame; + /* MTU frame parameters */ + struct frame frame; #ifdef ENABLE_FRAGMENT - /* Object to handle advanced MTU negotiation and datagram fragmentation */ - struct fragment_master *fragment; - struct frame frame_fragment; - struct frame frame_fragment_omit; + /* Object to handle advanced MTU negotiation and datagram fragmentation */ + struct fragment_master *fragment; + struct frame frame_fragment; + struct frame frame_fragment_omit; #endif #ifdef ENABLE_FEATURE_SHAPER - /* - * Traffic shaper object. - */ - struct shaper shaper; + /* + * Traffic shaper object. + */ + struct shaper shaper; #endif - /* - * Statistics - */ - counter_type tun_read_bytes; - counter_type tun_write_bytes; - counter_type link_read_bytes; - counter_type link_read_bytes_auth; - counter_type link_write_bytes; + /* + * Statistics + */ + counter_type tun_read_bytes; + counter_type tun_write_bytes; + counter_type link_read_bytes; + counter_type link_read_bytes_auth; + counter_type link_write_bytes; #ifdef PACKET_TRUNCATION_CHECK - counter_type n_trunc_tun_read; - counter_type n_trunc_tun_write; - counter_type n_trunc_pre_encrypt; - counter_type n_trunc_post_decrypt; + counter_type n_trunc_tun_read; + counter_type n_trunc_tun_write; + counter_type n_trunc_pre_encrypt; + counter_type n_trunc_post_decrypt; #endif - /* - * Timer objects for ping and inactivity - * timeout features. - */ - struct event_timeout wait_for_connect; - struct event_timeout ping_send_interval; - struct event_timeout ping_rec_interval; + /* + * Timer objects for ping and inactivity + * timeout features. + */ + struct event_timeout wait_for_connect; + struct event_timeout ping_send_interval; + struct event_timeout ping_rec_interval; - /* --inactive */ - struct event_timeout inactivity_interval; - int inactivity_bytes; + /* --inactive */ + struct event_timeout inactivity_interval; + int inactivity_bytes; #ifdef ENABLE_OCC - /* the option strings must match across peers */ - char *options_string_local; - char *options_string_remote; + /* the option strings must match across peers */ + char *options_string_local; + char *options_string_remote; - int occ_op; /* INIT to -1 */ - int occ_n_tries; - struct event_timeout occ_interval; + int occ_op; /* INIT to -1 */ + int occ_n_tries; + struct event_timeout occ_interval; #endif - /* - * Keep track of maximum packet size received so far - * (of authenticated packets). - */ - int original_recv_size; /* temporary */ - int max_recv_size_local; /* max packet size received */ - int max_recv_size_remote; /* max packet size received by remote */ - int max_send_size_local; /* max packet size sent */ - int max_send_size_remote; /* max packet size sent by remote */ + /* + * Keep track of maximum packet size received so far + * (of authenticated packets). + */ + int original_recv_size; /* temporary */ + int max_recv_size_local; /* max packet size received */ + int max_recv_size_remote; /* max packet size received by remote */ + int max_send_size_local; /* max packet size sent */ + int max_send_size_remote; /* max packet size sent by remote */ #ifdef ENABLE_OCC - /* remote wants us to send back a load test packet of this size */ - int occ_mtu_load_size; + /* remote wants us to send back a load test packet of this size */ + int occ_mtu_load_size; - struct event_timeout occ_mtu_load_test_interval; - int occ_mtu_load_n_tries; + struct event_timeout occ_mtu_load_test_interval; + int occ_mtu_load_n_tries; #endif #ifdef ENABLE_CRYPTO - /* - * TLS-mode crypto objects. - */ - struct tls_multi *tls_multi; /**< TLS state structure for this VPN - * tunnel. */ - - struct tls_auth_standalone *tls_auth_standalone; - /**< TLS state structure required for the - * initial authentication of a client's - * connection attempt. This structure - * is used by the \c - * tls_pre_decrypt_lite() function when - * it performs the HMAC firewall check - * on the first connection packet - * received from a new client. See the - * \c --tls-auth commandline option. */ - - /* used to optimize calls to tls_multi_process */ - struct interval tmp_int; - - /* throw this signal on TLS errors */ - int tls_exit_signal; - - struct crypto_options crypto_options; - /**< Security parameters and crypto state - * used by the \link data_crypto Data - * Channel Crypto module\endlink to - * process data channel packet. */ - - struct event_timeout packet_id_persist_interval; + /* + * TLS-mode crypto objects. + */ + struct tls_multi *tls_multi; /**< TLS state structure for this VPN + * tunnel. */ + + struct tls_auth_standalone *tls_auth_standalone; + /**< TLS state structure required for the + * initial authentication of a client's + * connection attempt. This structure + * is used by the \c + * tls_pre_decrypt_lite() function when + * it performs the HMAC firewall check + * on the first connection packet + * received from a new client. See the + * \c --tls-auth commandline option. */ + + /* used to optimize calls to tls_multi_process */ + struct interval tmp_int; + + /* throw this signal on TLS errors */ + int tls_exit_signal; + + struct crypto_options crypto_options; + /**< Security parameters and crypto state + * used by the \link data_crypto Data + * Channel Crypto module\endlink to + * process data channel packet. */ + + struct event_timeout packet_id_persist_interval; #endif /* ENABLE_CRYPTO */ #ifdef USE_COMP - struct compress_context *comp_context; - /**< Compression context used by the - * \link compression Data Channel - * Compression module\endlink. */ + struct compress_context *comp_context; + /**< Compression context used by the + * \link compression Data Channel + * Compression module\endlink. */ #endif - /* - * Buffers used for packet processing. - */ - struct context_buffers *buffers; - bool buffers_owned; /* if true, we should free all buffers on close */ + /* + * Buffers used for packet processing. + */ + struct context_buffers *buffers; + bool buffers_owned; /* if true, we should free all buffers on close */ - /* - * These buffers don't actually allocate storage, they are used - * as pointers to the allocated buffers in - * struct context_buffers. - */ - struct buffer buf; - struct buffer to_tun; - struct buffer to_link; + /* + * These buffers don't actually allocate storage, they are used + * as pointers to the allocated buffers in + * struct context_buffers. + */ + struct buffer buf; + struct buffer to_tun; + struct buffer to_link; - /* should we print R|W|r|w to console on packet transfers? */ - bool log_rw; + /* should we print R|W|r|w to console on packet transfers? */ + bool log_rw; - /* route stuff */ - struct event_timeout route_wakeup; - struct event_timeout route_wakeup_expire; + /* route stuff */ + struct event_timeout route_wakeup; + struct event_timeout route_wakeup_expire; - /* did we open tun/tap dev during this cycle? */ - bool did_open_tun; + /* did we open tun/tap dev during this cycle? */ + bool did_open_tun; - /* - * Event loop info - */ + /* + * Event loop info + */ - /* how long to wait on link/tun read before we will need to be serviced */ - struct timeval timeval; + /* how long to wait on link/tun read before we will need to be serviced */ + struct timeval timeval; - /* next wakeup for processing coarse timers (>1 sec resolution) */ - time_t coarse_timer_wakeup; + /* next wakeup for processing coarse timers (>1 sec resolution) */ + time_t coarse_timer_wakeup; - /* maintain a random delta to add to timeouts to avoid contexts - waking up simultaneously */ - time_t update_timeout_random_component; - struct timeval timeout_random_component; + /* maintain a random delta to add to timeouts to avoid contexts + * waking up simultaneously */ + time_t update_timeout_random_component; + struct timeval timeout_random_component; - /* Timer for everything up to the first packet from the *OpenVPN* server - * socks, http proxy, and tcp packets do not count */ - struct event_timeout server_poll_interval; + /* Timer for everything up to the first packet from the *OpenVPN* server + * socks, http proxy, and tcp packets do not count */ + struct event_timeout server_poll_interval; - /* indicates that the do_up_delay function has run */ - bool do_up_ran; + /* indicates that the do_up_delay function has run */ + bool do_up_ran; #ifdef ENABLE_OCC - /* indicates that we have received a SIGTERM when - options->explicit_exit_notification is enabled, - but we have not exited yet */ - time_t explicit_exit_notification_time_wait; - struct event_timeout explicit_exit_notification_interval; + /* indicates that we have received a SIGTERM when + * options->explicit_exit_notification is enabled, + * but we have not exited yet */ + time_t explicit_exit_notification_time_wait; + struct event_timeout explicit_exit_notification_interval; #endif - /* environmental variables to pass to scripts */ - struct env_set *es; - bool es_owned; + /* environmental variables to pass to scripts */ + struct env_set *es; + bool es_owned; - /* don't wait for TUN/TAP/UDP to be ready to accept write */ - bool fast_io; + /* don't wait for TUN/TAP/UDP to be ready to accept write */ + bool fast_io; #if P2MP #if P2MP_SERVER - /* --ifconfig endpoints to be pushed to client */ - bool push_reply_deferred; + /* --ifconfig endpoints to be pushed to client */ + bool push_reply_deferred; #ifdef ENABLE_ASYNC_PUSH - bool push_request_received; -#endif - bool push_ifconfig_defined; - time_t sent_push_reply_expiry; - in_addr_t push_ifconfig_local; - in_addr_t push_ifconfig_remote_netmask; - in_addr_t push_ifconfig_local_alias; - - bool push_ifconfig_ipv6_defined; - struct in6_addr push_ifconfig_ipv6_local; - int push_ifconfig_ipv6_netbits; - struct in6_addr push_ifconfig_ipv6_remote; - - /* client authentication state, CAS_SUCCEEDED must be 0 */ -# define CAS_SUCCEEDED 0 -# define CAS_PENDING 1 -# define CAS_FAILED 2 -# define CAS_PARTIAL 3 /* at least one client-connect script/plugin - succeeded while a later one in the chain failed */ - int context_auth; -#endif - - struct event_timeout push_request_interval; - int n_sent_push_requests; - bool did_pre_pull_restore; - - /* hash of pulled options, so we can compare when options change */ - bool pulled_options_md5_init_done; - md_ctx_t pulled_options_state; - struct md5_digest pulled_options_digest; - - struct event_timeout scheduled_exit; - int scheduled_exit_signal; + bool push_request_received; #endif - - /* packet filter */ + bool push_ifconfig_defined; + time_t sent_push_reply_expiry; + in_addr_t push_ifconfig_local; + in_addr_t push_ifconfig_remote_netmask; + in_addr_t push_ifconfig_local_alias; + + bool push_ifconfig_ipv6_defined; + struct in6_addr push_ifconfig_ipv6_local; + int push_ifconfig_ipv6_netbits; + struct in6_addr push_ifconfig_ipv6_remote; + + /* client authentication state, CAS_SUCCEEDED must be 0 */ +#define CAS_SUCCEEDED 0 +#define CAS_PENDING 1 +#define CAS_FAILED 2 +#define CAS_PARTIAL 3 /* at least one client-connect script/plugin + * succeeded while a later one in the chain failed */ + int context_auth; +#endif /* if P2MP_SERVER */ + + struct event_timeout push_request_interval; + int n_sent_push_requests; + bool did_pre_pull_restore; + + /* hash of pulled options, so we can compare when options change */ + bool pulled_options_md5_init_done; + md_ctx_t pulled_options_state; + struct md5_digest pulled_options_digest; + + struct event_timeout scheduled_exit; + int scheduled_exit_signal; +#endif /* if P2MP */ + + /* packet filter */ #ifdef ENABLE_PF - struct pf_context pf; + struct pf_context pf; #endif #ifdef MANAGEMENT_DEF_AUTH - struct man_def_auth_context mda_context; + struct man_def_auth_context mda_context; #endif #ifdef ENABLE_ASYNC_PUSH - int inotify_fd; /* descriptor for monitoring file changes */ + int inotify_fd; /* descriptor for monitoring file changes */ #endif }; @@ -507,59 +507,59 @@ struct context_2 */ struct context { - struct options options; /**< Options loaded from command line or + struct options options; /**< Options loaded from command line or * configuration file. */ - bool first_time; /**< True on the first iteration of + bool first_time; /**< True on the first iteration of * OpenVPN's main loop. */ - /* context modes */ -# define CM_P2P 0 /* standalone point-to-point session or client */ -# define CM_TOP 1 /* top level of a multi-client or point-to-multipoint server */ -# define CM_TOP_CLONE 2 /* clone of a CM_TOP context for one thread */ -# define CM_CHILD_UDP 3 /* child context of a CM_TOP or CM_THREAD */ -# define CM_CHILD_TCP 4 /* child context of a CM_TOP or CM_THREAD */ - int mode; /**< Role of this context within the + /* context modes */ +#define CM_P2P 0 /* standalone point-to-point session or client */ +#define CM_TOP 1 /* top level of a multi-client or point-to-multipoint server */ +#define CM_TOP_CLONE 2 /* clone of a CM_TOP context for one thread */ +#define CM_CHILD_UDP 3 /* child context of a CM_TOP or CM_THREAD */ +#define CM_CHILD_TCP 4 /* child context of a CM_TOP or CM_THREAD */ + int mode; /**< Role of this context within the * OpenVPN process. Valid values are \c * CM_P2P, \c CM_TOP, \c CM_TOP_CLONE, * \c CM_CHILD_UDP, and \c CM_CHILD_TCP. */ - struct gc_arena gc; /**< Garbage collection arena for + struct gc_arena gc; /**< Garbage collection arena for * allocations done in the scope of this * context structure. */ - struct env_set *es; /**< Set of environment variables. */ + struct env_set *es; /**< Set of environment variables. */ - struct signal_info *sig; /**< Internal error signaling object. */ + struct signal_info *sig; /**< Internal error signaling object. */ - struct plugin_list *plugins; /**< List of plug-ins. */ - bool plugins_owned; /**< Whether the plug-ins should be + struct plugin_list *plugins; /**< List of plug-ins. */ + bool plugins_owned; /**< Whether the plug-ins should be * cleaned up when this %context is * cleaned up. */ - - bool did_we_daemonize; /**< Whether demonization has already + + bool did_we_daemonize; /**< Whether demonization has already * taken place. */ - struct context_persist persist; - /**< Persistent %context. */ - struct context_0 *c0; /**< Level 0 %context. */ - struct context_1 c1; /**< Level 1 %context. */ - struct context_2 c2; /**< Level 2 %context. */ + struct context_persist persist; + /**< Persistent %context. */ + struct context_0 *c0; /**< Level 0 %context. */ + struct context_1 c1; /**< Level 1 %context. */ + struct context_2 c2; /**< Level 2 %context. */ }; /* * Check for a signal when inside an event loop */ #define EVENT_LOOP_CHECK_SIGNAL(c, func, arg) \ - if (IS_SIG (c)) \ - { \ - const int brk = func (arg); \ - perf_pop (); \ - if (brk) \ - break; \ - else \ - continue; \ - } + if (IS_SIG(c)) \ + { \ + const int brk = func(arg); \ + perf_pop(); \ + if (brk) { \ + break;} \ + else { \ + continue;} \ + } /* * Macros for referencing objects which may not @@ -568,15 +568,15 @@ struct context #ifdef ENABLE_CRYPTO #define TLS_MODE(c) ((c)->c2.tls_multi != NULL) -#define PROTO_DUMP_FLAGS (check_debug_level (D_LINK_RW_VERBOSE) ? (PD_SHOW_DATA|PD_VERBOSE) : 0) +#define PROTO_DUMP_FLAGS (check_debug_level(D_LINK_RW_VERBOSE) ? (PD_SHOW_DATA|PD_VERBOSE) : 0) #define PROTO_DUMP(buf, gc) protocol_dump((buf), \ - PROTO_DUMP_FLAGS | \ - (c->c2.tls_multi ? PD_TLS : 0) | \ - (c->options.tls_auth_file ? c->c1.ks.key_type.hmac_length : 0), \ - gc) -#else + PROTO_DUMP_FLAGS \ + |(c->c2.tls_multi ? PD_TLS : 0) \ + |(c->options.tls_auth_file ? c->c1.ks.key_type.hmac_length : 0), \ + gc) +#else /* ifdef ENABLE_CRYPTO */ #define TLS_MODE(c) (false) -#define PROTO_DUMP(buf, gc) format_hex (BPTR (buf), BLEN (buf), 80, gc) +#define PROTO_DUMP(buf, gc) format_hex(BPTR(buf), BLEN(buf), 80, gc) #endif #ifdef ENABLE_CRYPTO @@ -594,4 +594,4 @@ struct context /* this represents "disabled peer-id" */ #define MAX_PEER_ID 0xFFFFFF -#endif +#endif /* ifndef OPENVPN_H */ diff --git a/src/openvpn/options.c b/src/openvpn/options.c index f6e0f138a53..b34350222b7 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -63,715 +63,715 @@ #include "memdbg.h" const char title_string[] = - PACKAGE_STRING + PACKAGE_STRING #ifdef CONFIGURE_GIT_REVISION - " [git:" CONFIGURE_GIT_REVISION CONFIGURE_GIT_FLAGS "]" + " [git:" CONFIGURE_GIT_REVISION CONFIGURE_GIT_FLAGS "]" #endif - " " TARGET_ALIAS + " " TARGET_ALIAS #ifdef ENABLE_CRYPTO #if defined(ENABLE_CRYPTO_MBEDTLS) - " [SSL (mbed TLS)]" + " [SSL (mbed TLS)]" #elif defined(ENABLE_CRYPTO_OPENSSL) - " [SSL (OpenSSL)]" + " [SSL (OpenSSL)]" #else - " [SSL]" + " [SSL]" #endif /* defined(ENABLE_CRYPTO_MBEDTLS) */ #endif /* ENABLE_CRYPTO */ #ifdef USE_COMP #ifdef ENABLE_LZO - " [LZO]" + " [LZO]" #endif #ifdef ENABLE_LZ4 - " [LZ4]" + " [LZ4]" #endif #ifdef ENABLE_COMP_STUB - " [COMP_STUB]" + " [COMP_STUB]" #endif #endif /* USE_COMP */ #if EPOLL - " [EPOLL]" + " [EPOLL]" #endif #ifdef PRODUCT_TAP_DEBUG - " [TAPDBG]" + " [TAPDBG]" #endif #ifdef ENABLE_PKCS11 - " [PKCS11]" + " [PKCS11]" #endif #if ENABLE_IP_PKTINFO -# if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) - " [MH/PKTINFO]" -# elif defined(IP_RECVDSTADDR) - " [MH/RECVDA]" -# endif +#if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) + " [MH/PKTINFO]" +#elif defined(IP_RECVDSTADDR) + " [MH/RECVDA]" +#endif #endif #ifdef HAVE_AEAD_CIPHER_MODES - " [AEAD]" + " [AEAD]" #endif - " built on " __DATE__ + " built on " __DATE__ ; #ifndef ENABLE_SMALL static const char usage_message[] = - "%s\n" - "\n" - "General Options:\n" - "--config file : Read configuration options from file.\n" - "--help : Show options.\n" - "--version : Show copyright and version information.\n" - "\n" - "Tunnel Options:\n" - "--local host : Local host name or ip address. Implies --bind.\n" - "--remote host [port] : Remote host name or ip address.\n" - "--remote-random : If multiple --remote options specified, choose one randomly.\n" - "--remote-random-hostname : Add a random string to remote DNS name.\n" - "--mode m : Major mode, m = 'p2p' (default, point-to-point) or 'server'.\n" - "--proto p : Use protocol p for communicating with peer.\n" - " p = udp (default), tcp-server, or tcp-client\n" - "--proto-force p : only consider protocol p in list of connection profiles.\n" - " p = udp6, tcp6-server, or tcp6-client (ipv6)\n" - "--connect-retry n [m] : For client, number of seconds to wait between\n" - " connection retries (default=%d). On repeated retries\n" - " the wait time is exponentially increased to a maximum of m\n" - " (default=%d).\n" - "--connect-retry-max n : Maximum connection attempt retries, default infinite.\n" - "--http-proxy s p [up] [auth] : Connect to remote host\n" - " through an HTTP proxy at address s and port p.\n" - " If proxy authentication is required,\n" - " up is a file containing username/password on 2 lines, or\n" - " 'stdin' to prompt from console. Add auth='ntlm' if\n" - " the proxy requires NTLM authentication.\n" - "--http-proxy s p 'auto[-nct]' : Like the above directive, but automatically\n" - " determine auth method and query for username/password\n" - " if needed. auto-nct disables weak proxy auth methods.\n" - "--http-proxy-option type [parm] : Set extended HTTP proxy options.\n" - " Repeat to set multiple options.\n" - " VERSION version (default=1.0)\n" - " AGENT user-agent\n" - "--socks-proxy s [p] [up] : Connect to remote host through a Socks5 proxy at\n" - " address s and port p (default port = 1080).\n" - " If proxy authentication is required,\n" - " up is a file containing username/password on 2 lines, or\n" - " 'stdin' to prompt for console.\n" - "--socks-proxy-retry : Retry indefinitely on Socks proxy errors.\n" - "--resolv-retry n: If hostname resolve fails for --remote, retry\n" - " resolve for n seconds before failing (disabled by default).\n" - " Set n=\"infinite\" to retry indefinitely.\n" - "--float : Allow remote to change its IP address/port, such as through\n" - " DHCP (this is the default if --remote is not used).\n" - "--ipchange cmd : Run command cmd on remote ip address initial\n" - " setting or change -- execute as: cmd ip-address port#\n" - "--port port : TCP/UDP port # for both local and remote.\n" - "--lport port : TCP/UDP port # for local (default=%s). Implies --bind.\n" - "--rport port : TCP/UDP port # for remote (default=%s).\n" - "--bind : Bind to local address and port. (This is the default unless\n" - " --proto tcp-client" - " or --http-proxy" - " or --socks-proxy" - " is used).\n" - "--nobind : Do not bind to local address and port.\n" - "--dev tunX|tapX : tun/tap device (X can be omitted for dynamic device.\n" - "--dev-type dt : Which device type are we using? (dt = tun or tap) Use\n" - " this option only if the tun/tap device used with --dev\n" - " does not begin with \"tun\" or \"tap\".\n" - "--dev-node node : Explicitly set the device node rather than using\n" - " /dev/net/tun, /dev/tun, /dev/tap, etc.\n" - "--lladdr hw : Set the link layer address of the tap device.\n" - "--topology t : Set --dev tun topology: 'net30', 'p2p', or 'subnet'.\n" + "%s\n" + "\n" + "General Options:\n" + "--config file : Read configuration options from file.\n" + "--help : Show options.\n" + "--version : Show copyright and version information.\n" + "\n" + "Tunnel Options:\n" + "--local host : Local host name or ip address. Implies --bind.\n" + "--remote host [port] : Remote host name or ip address.\n" + "--remote-random : If multiple --remote options specified, choose one randomly.\n" + "--remote-random-hostname : Add a random string to remote DNS name.\n" + "--mode m : Major mode, m = 'p2p' (default, point-to-point) or 'server'.\n" + "--proto p : Use protocol p for communicating with peer.\n" + " p = udp (default), tcp-server, or tcp-client\n" + "--proto-force p : only consider protocol p in list of connection profiles.\n" + " p = udp6, tcp6-server, or tcp6-client (ipv6)\n" + "--connect-retry n [m] : For client, number of seconds to wait between\n" + " connection retries (default=%d). On repeated retries\n" + " the wait time is exponentially increased to a maximum of m\n" + " (default=%d).\n" + "--connect-retry-max n : Maximum connection attempt retries, default infinite.\n" + "--http-proxy s p [up] [auth] : Connect to remote host\n" + " through an HTTP proxy at address s and port p.\n" + " If proxy authentication is required,\n" + " up is a file containing username/password on 2 lines, or\n" + " 'stdin' to prompt from console. Add auth='ntlm' if\n" + " the proxy requires NTLM authentication.\n" + "--http-proxy s p 'auto[-nct]' : Like the above directive, but automatically\n" + " determine auth method and query for username/password\n" + " if needed. auto-nct disables weak proxy auth methods.\n" + "--http-proxy-option type [parm] : Set extended HTTP proxy options.\n" + " Repeat to set multiple options.\n" + " VERSION version (default=1.0)\n" + " AGENT user-agent\n" + "--socks-proxy s [p] [up] : Connect to remote host through a Socks5 proxy at\n" + " address s and port p (default port = 1080).\n" + " If proxy authentication is required,\n" + " up is a file containing username/password on 2 lines, or\n" + " 'stdin' to prompt for console.\n" + "--socks-proxy-retry : Retry indefinitely on Socks proxy errors.\n" + "--resolv-retry n: If hostname resolve fails for --remote, retry\n" + " resolve for n seconds before failing (disabled by default).\n" + " Set n=\"infinite\" to retry indefinitely.\n" + "--float : Allow remote to change its IP address/port, such as through\n" + " DHCP (this is the default if --remote is not used).\n" + "--ipchange cmd : Run command cmd on remote ip address initial\n" + " setting or change -- execute as: cmd ip-address port#\n" + "--port port : TCP/UDP port # for both local and remote.\n" + "--lport port : TCP/UDP port # for local (default=%s). Implies --bind.\n" + "--rport port : TCP/UDP port # for remote (default=%s).\n" + "--bind : Bind to local address and port. (This is the default unless\n" + " --proto tcp-client" + " or --http-proxy" + " or --socks-proxy" + " is used).\n" + "--nobind : Do not bind to local address and port.\n" + "--dev tunX|tapX : tun/tap device (X can be omitted for dynamic device.\n" + "--dev-type dt : Which device type are we using? (dt = tun or tap) Use\n" + " this option only if the tun/tap device used with --dev\n" + " does not begin with \"tun\" or \"tap\".\n" + "--dev-node node : Explicitly set the device node rather than using\n" + " /dev/net/tun, /dev/tun, /dev/tap, etc.\n" + "--lladdr hw : Set the link layer address of the tap device.\n" + "--topology t : Set --dev tun topology: 'net30', 'p2p', or 'subnet'.\n" #ifdef ENABLE_IPROUTE - "--iproute cmd : Use this command instead of default " IPROUTE_PATH ".\n" -#endif - "--ifconfig l rn : TUN: configure device to use IP address l as a local\n" - " endpoint and rn as a remote endpoint. l & rn should be\n" - " swapped on the other peer. l & rn must be private\n" - " addresses outside of the subnets used by either peer.\n" - " TAP: configure device to use IP address l as a local\n" - " endpoint and rn as a subnet mask.\n" - "--ifconfig-ipv6 l r : configure device to use IPv6 address l as local\n" - " endpoint (as a /64) and r as remote endpoint\n" - "--ifconfig-noexec : Don't actually execute ifconfig/netsh command, instead\n" - " pass --ifconfig parms by environment to scripts.\n" - "--ifconfig-nowarn : Don't warn if the --ifconfig option on this side of the\n" - " connection doesn't match the remote side.\n" - "--route network [netmask] [gateway] [metric] :\n" - " Add route to routing table after connection\n" - " is established. Multiple routes can be specified.\n" - " netmask default: 255.255.255.255\n" - " gateway default: taken from --route-gateway or --ifconfig\n" - " Specify default by leaving blank or setting to \"nil\".\n" - "--route-ipv6 network/bits [gateway] [metric] :\n" - " Add IPv6 route to routing table after connection\n" - " is established. Multiple routes can be specified.\n" - " gateway default: taken from 'remote' in --ifconfig-ipv6\n" - "--route-gateway gw|'dhcp' : Specify a default gateway for use with --route.\n" - "--route-metric m : Specify a default metric for use with --route.\n" - "--route-delay n [w] : Delay n seconds after connection initiation before\n" - " adding routes (may be 0). If not specified, routes will\n" - " be added immediately after tun/tap open. On Windows, wait\n" - " up to w seconds for TUN/TAP adapter to come up.\n" - "--route-up cmd : Run command cmd after routes are added.\n" - "--route-pre-down cmd : Run command cmd before routes are removed.\n" - "--route-noexec : Don't add routes automatically. Instead pass routes to\n" - " --route-up script using environmental variables.\n" - "--route-nopull : When used with --client or --pull, accept options pushed\n" - " by server EXCEPT for routes and dhcp options.\n" - "--allow-pull-fqdn : Allow client to pull DNS names from server for\n" - " --ifconfig, --route, and --route-gateway.\n" - "--redirect-gateway [flags]: Automatically execute routing\n" - " commands to redirect all outgoing IP traffic through the\n" - " VPN. Add 'local' flag if both " PACKAGE_NAME " servers are directly\n" - " connected via a common subnet, such as with WiFi.\n" - " Add 'def1' flag to set default route using using 0.0.0.0/1\n" - " and 128.0.0.0/1 rather than 0.0.0.0/0. Add 'bypass-dhcp'\n" - " flag to add a direct route to DHCP server, bypassing tunnel.\n" - " Add 'bypass-dns' flag to similarly bypass tunnel for DNS.\n" - "--redirect-private [flags]: Like --redirect-gateway, but omit actually changing\n" - " the default gateway. Useful when pushing private subnets.\n" - "--client-nat snat|dnat network netmask alias : on client add 1-to-1 NAT rule.\n" + "--iproute cmd : Use this command instead of default " IPROUTE_PATH ".\n" +#endif + "--ifconfig l rn : TUN: configure device to use IP address l as a local\n" + " endpoint and rn as a remote endpoint. l & rn should be\n" + " swapped on the other peer. l & rn must be private\n" + " addresses outside of the subnets used by either peer.\n" + " TAP: configure device to use IP address l as a local\n" + " endpoint and rn as a subnet mask.\n" + "--ifconfig-ipv6 l r : configure device to use IPv6 address l as local\n" + " endpoint (as a /64) and r as remote endpoint\n" + "--ifconfig-noexec : Don't actually execute ifconfig/netsh command, instead\n" + " pass --ifconfig parms by environment to scripts.\n" + "--ifconfig-nowarn : Don't warn if the --ifconfig option on this side of the\n" + " connection doesn't match the remote side.\n" + "--route network [netmask] [gateway] [metric] :\n" + " Add route to routing table after connection\n" + " is established. Multiple routes can be specified.\n" + " netmask default: 255.255.255.255\n" + " gateway default: taken from --route-gateway or --ifconfig\n" + " Specify default by leaving blank or setting to \"nil\".\n" + "--route-ipv6 network/bits [gateway] [metric] :\n" + " Add IPv6 route to routing table after connection\n" + " is established. Multiple routes can be specified.\n" + " gateway default: taken from 'remote' in --ifconfig-ipv6\n" + "--route-gateway gw|'dhcp' : Specify a default gateway for use with --route.\n" + "--route-metric m : Specify a default metric for use with --route.\n" + "--route-delay n [w] : Delay n seconds after connection initiation before\n" + " adding routes (may be 0). If not specified, routes will\n" + " be added immediately after tun/tap open. On Windows, wait\n" + " up to w seconds for TUN/TAP adapter to come up.\n" + "--route-up cmd : Run command cmd after routes are added.\n" + "--route-pre-down cmd : Run command cmd before routes are removed.\n" + "--route-noexec : Don't add routes automatically. Instead pass routes to\n" + " --route-up script using environmental variables.\n" + "--route-nopull : When used with --client or --pull, accept options pushed\n" + " by server EXCEPT for routes and dhcp options.\n" + "--allow-pull-fqdn : Allow client to pull DNS names from server for\n" + " --ifconfig, --route, and --route-gateway.\n" + "--redirect-gateway [flags]: Automatically execute routing\n" + " commands to redirect all outgoing IP traffic through the\n" + " VPN. Add 'local' flag if both " PACKAGE_NAME " servers are directly\n" + " connected via a common subnet, such as with WiFi.\n" + " Add 'def1' flag to set default route using using 0.0.0.0/1\n" + " and 128.0.0.0/1 rather than 0.0.0.0/0. Add 'bypass-dhcp'\n" + " flag to add a direct route to DHCP server, bypassing tunnel.\n" + " Add 'bypass-dns' flag to similarly bypass tunnel for DNS.\n" + "--redirect-private [flags]: Like --redirect-gateway, but omit actually changing\n" + " the default gateway. Useful when pushing private subnets.\n" + "--client-nat snat|dnat network netmask alias : on client add 1-to-1 NAT rule.\n" #ifdef ENABLE_PUSH_PEER_INFO - "--push-peer-info : (client only) push client info to server.\n" -#endif - "--setenv name value : Set a custom environmental variable to pass to script.\n" - "--setenv FORWARD_COMPATIBLE 1 : Relax config file syntax checking to allow\n" - " directives for future OpenVPN versions to be ignored.\n" - "--ignore-unkown-option opt1 opt2 ...: Relax config file syntax. Allow\n" - " these options to be ignored when unknown\n" - "--script-security level: Where level can be:\n" - " 0 -- strictly no calling of external programs\n" - " 1 -- (default) only call built-ins such as ifconfig\n" - " 2 -- allow calling of built-ins and scripts\n" - " 3 -- allow password to be passed to scripts via env\n" - "--shaper n : Restrict output to peer to n bytes per second.\n" - "--keepalive n m : Helper option for setting timeouts in server mode. Send\n" - " ping once every n seconds, restart if ping not received\n" - " for m seconds.\n" - "--inactive n [bytes] : Exit after n seconds of activity on tun/tap device\n" - " produces a combined in/out byte count < bytes.\n" - "--ping-exit n : Exit if n seconds pass without reception of remote ping.\n" - "--ping-restart n: Restart if n seconds pass without reception of remote ping.\n" - "--ping-timer-rem: Run the --ping-exit/--ping-restart timer only if we have a\n" - " remote address.\n" - "--ping n : Ping remote once every n seconds over TCP/UDP port.\n" + "--push-peer-info : (client only) push client info to server.\n" +#endif + "--setenv name value : Set a custom environmental variable to pass to script.\n" + "--setenv FORWARD_COMPATIBLE 1 : Relax config file syntax checking to allow\n" + " directives for future OpenVPN versions to be ignored.\n" + "--ignore-unkown-option opt1 opt2 ...: Relax config file syntax. Allow\n" + " these options to be ignored when unknown\n" + "--script-security level: Where level can be:\n" + " 0 -- strictly no calling of external programs\n" + " 1 -- (default) only call built-ins such as ifconfig\n" + " 2 -- allow calling of built-ins and scripts\n" + " 3 -- allow password to be passed to scripts via env\n" + "--shaper n : Restrict output to peer to n bytes per second.\n" + "--keepalive n m : Helper option for setting timeouts in server mode. Send\n" + " ping once every n seconds, restart if ping not received\n" + " for m seconds.\n" + "--inactive n [bytes] : Exit after n seconds of activity on tun/tap device\n" + " produces a combined in/out byte count < bytes.\n" + "--ping-exit n : Exit if n seconds pass without reception of remote ping.\n" + "--ping-restart n: Restart if n seconds pass without reception of remote ping.\n" + "--ping-timer-rem: Run the --ping-exit/--ping-restart timer only if we have a\n" + " remote address.\n" + "--ping n : Ping remote once every n seconds over TCP/UDP port.\n" #if ENABLE_IP_PKTINFO - "--multihome : Configure a multi-homed UDP server.\n" -#endif - "--fast-io : (experimental) Optimize TUN/TAP/UDP writes.\n" - "--remap-usr1 s : On SIGUSR1 signals, remap signal (s='SIGHUP' or 'SIGTERM').\n" - "--persist-tun : Keep tun/tap device open across SIGUSR1 or --ping-restart.\n" - "--persist-remote-ip : Keep remote IP address across SIGUSR1 or --ping-restart.\n" - "--persist-local-ip : Keep local IP address across SIGUSR1 or --ping-restart.\n" - "--persist-key : Don't re-read key files across SIGUSR1 or --ping-restart.\n" + "--multihome : Configure a multi-homed UDP server.\n" +#endif + "--fast-io : (experimental) Optimize TUN/TAP/UDP writes.\n" + "--remap-usr1 s : On SIGUSR1 signals, remap signal (s='SIGHUP' or 'SIGTERM').\n" + "--persist-tun : Keep tun/tap device open across SIGUSR1 or --ping-restart.\n" + "--persist-remote-ip : Keep remote IP address across SIGUSR1 or --ping-restart.\n" + "--persist-local-ip : Keep local IP address across SIGUSR1 or --ping-restart.\n" + "--persist-key : Don't re-read key files across SIGUSR1 or --ping-restart.\n" #if PASSTOS_CAPABILITY - "--passtos : TOS passthrough (applies to IPv4 only).\n" -#endif - "--tun-mtu n : Take the tun/tap device MTU to be n and derive the\n" - " TCP/UDP MTU from it (default=%d).\n" - "--tun-mtu-extra n : Assume that tun/tap device might return as many\n" - " as n bytes more than the tun-mtu size on read\n" - " (default TUN=0 TAP=%d).\n" - "--link-mtu n : Take the TCP/UDP device MTU to be n and derive the tun MTU\n" - " from it.\n" - "--mtu-disc type : Should we do Path MTU discovery on TCP/UDP channel?\n" - " 'no' -- Never send DF (Don't Fragment) frames\n" - " 'maybe' -- Use per-route hints\n" - " 'yes' -- Always DF (Don't Fragment)\n" + "--passtos : TOS passthrough (applies to IPv4 only).\n" +#endif + "--tun-mtu n : Take the tun/tap device MTU to be n and derive the\n" + " TCP/UDP MTU from it (default=%d).\n" + "--tun-mtu-extra n : Assume that tun/tap device might return as many\n" + " as n bytes more than the tun-mtu size on read\n" + " (default TUN=0 TAP=%d).\n" + "--link-mtu n : Take the TCP/UDP device MTU to be n and derive the tun MTU\n" + " from it.\n" + "--mtu-disc type : Should we do Path MTU discovery on TCP/UDP channel?\n" + " 'no' -- Never send DF (Don't Fragment) frames\n" + " 'maybe' -- Use per-route hints\n" + " 'yes' -- Always DF (Don't Fragment)\n" #ifdef ENABLE_OCC - "--mtu-test : Empirically measure and report MTU.\n" + "--mtu-test : Empirically measure and report MTU.\n" #endif #ifdef ENABLE_FRAGMENT - "--fragment max : Enable internal datagram fragmentation so that no UDP\n" - " datagrams are sent which are larger than max bytes.\n" - " Adds 4 bytes of overhead per datagram.\n" -#endif - "--mssfix [n] : Set upper bound on TCP MSS, default = tun-mtu size\n" - " or --fragment max value, whichever is lower.\n" - "--sndbuf size : Set the TCP/UDP send buffer size.\n" - "--rcvbuf size : Set the TCP/UDP receive buffer size.\n" + "--fragment max : Enable internal datagram fragmentation so that no UDP\n" + " datagrams are sent which are larger than max bytes.\n" + " Adds 4 bytes of overhead per datagram.\n" +#endif + "--mssfix [n] : Set upper bound on TCP MSS, default = tun-mtu size\n" + " or --fragment max value, whichever is lower.\n" + "--sndbuf size : Set the TCP/UDP send buffer size.\n" + "--rcvbuf size : Set the TCP/UDP receive buffer size.\n" #if defined(TARGET_LINUX) && HAVE_DECL_SO_MARK - "--mark value : Mark encrypted packets being sent with value. The mark value\n" - " can be matched in policy routing and packetfilter rules.\n" + "--mark value : Mark encrypted packets being sent with value. The mark value\n" + " can be matched in policy routing and packetfilter rules.\n" #endif - "--txqueuelen n : Set the tun/tap TX queue length to n (Linux only).\n" + "--txqueuelen n : Set the tun/tap TX queue length to n (Linux only).\n" #ifdef ENABLE_MEMSTATS - "--memstats file : Write live usage stats to memory mapped binary file.\n" -#endif - "--mlock : Disable Paging -- ensures key material and tunnel\n" - " data will never be written to disk.\n" - "--up cmd : Run command cmd after successful tun device open.\n" - " Execute as: cmd tun/tap-dev tun-mtu link-mtu \\\n" - " ifconfig-local-ip ifconfig-remote-ip\n" - " (pre --user or --group UID/GID change)\n" - "--up-delay : Delay tun/tap open and possible --up script execution\n" - " until after TCP/UDP connection establishment with peer.\n" - "--down cmd : Run command cmd after tun device close.\n" - " (post --user/--group UID/GID change and/or --chroot)\n" - " (command parameters are same as --up option)\n" - "--down-pre : Run --down command before TUN/TAP close.\n" - "--up-restart : Run up/down commands for all restarts including those\n" - " caused by --ping-restart or SIGUSR1\n" - "--user user : Set UID to user after initialization.\n" - "--group group : Set GID to group after initialization.\n" - "--chroot dir : Chroot to this directory after initialization.\n" + "--memstats file : Write live usage stats to memory mapped binary file.\n" +#endif + "--mlock : Disable Paging -- ensures key material and tunnel\n" + " data will never be written to disk.\n" + "--up cmd : Run command cmd after successful tun device open.\n" + " Execute as: cmd tun/tap-dev tun-mtu link-mtu \\\n" + " ifconfig-local-ip ifconfig-remote-ip\n" + " (pre --user or --group UID/GID change)\n" + "--up-delay : Delay tun/tap open and possible --up script execution\n" + " until after TCP/UDP connection establishment with peer.\n" + "--down cmd : Run command cmd after tun device close.\n" + " (post --user/--group UID/GID change and/or --chroot)\n" + " (command parameters are same as --up option)\n" + "--down-pre : Run --down command before TUN/TAP close.\n" + "--up-restart : Run up/down commands for all restarts including those\n" + " caused by --ping-restart or SIGUSR1\n" + "--user user : Set UID to user after initialization.\n" + "--group group : Set GID to group after initialization.\n" + "--chroot dir : Chroot to this directory after initialization.\n" #ifdef ENABLE_SELINUX - "--setcon context: Apply this SELinux context after initialization.\n" -#endif - "--cd dir : Change to this directory before initialization.\n" - "--daemon [name] : Become a daemon after initialization.\n" - " The optional 'name' parameter will be passed\n" - " as the program name to the system logger.\n" - "--syslog [name] : Output to syslog, but do not become a daemon.\n" - " See --daemon above for a description of the 'name' parm.\n" - "--inetd [name] ['wait'|'nowait'] : Run as an inetd or xinetd server.\n" - " See --daemon above for a description of the 'name' parm.\n" - "--log file : Output log to file which is created/truncated on open.\n" - "--log-append file : Append log to file, or create file if nonexistent.\n" - "--suppress-timestamps : Don't log timestamps to stdout/stderr.\n" - "--machine-readable-output : Always log timestamp, message flags to stdout/stderr.\n" - "--writepid file : Write main process ID to file.\n" - "--nice n : Change process priority (>0 = lower, <0 = higher).\n" - "--echo [parms ...] : Echo parameters to log output.\n" - "--verb n : Set output verbosity to n (default=%d):\n" - " (Level 3 is recommended if you want a good summary\n" - " of what's happening without being swamped by output).\n" - " : 0 -- no output except fatal errors\n" - " : 1 -- startup info + connection initiated messages +\n" - " non-fatal encryption & net errors\n" - " : 2,3 -- show TLS negotiations & route info\n" - " : 4 -- show parameters\n" - " : 5 -- show 'RrWw' chars on console for each packet sent\n" - " and received from TCP/UDP (caps) or tun/tap (lc)\n" - " : 6 to 11 -- debug messages of increasing verbosity\n" - "--mute n : Log at most n consecutive messages in the same category.\n" - "--status file n : Write operational status to file every n seconds.\n" - "--status-version [n] : Choose the status file format version number.\n" - " Currently, n can be 1, 2, or 3 (default=1).\n" + "--setcon context: Apply this SELinux context after initialization.\n" +#endif + "--cd dir : Change to this directory before initialization.\n" + "--daemon [name] : Become a daemon after initialization.\n" + " The optional 'name' parameter will be passed\n" + " as the program name to the system logger.\n" + "--syslog [name] : Output to syslog, but do not become a daemon.\n" + " See --daemon above for a description of the 'name' parm.\n" + "--inetd [name] ['wait'|'nowait'] : Run as an inetd or xinetd server.\n" + " See --daemon above for a description of the 'name' parm.\n" + "--log file : Output log to file which is created/truncated on open.\n" + "--log-append file : Append log to file, or create file if nonexistent.\n" + "--suppress-timestamps : Don't log timestamps to stdout/stderr.\n" + "--machine-readable-output : Always log timestamp, message flags to stdout/stderr.\n" + "--writepid file : Write main process ID to file.\n" + "--nice n : Change process priority (>0 = lower, <0 = higher).\n" + "--echo [parms ...] : Echo parameters to log output.\n" + "--verb n : Set output verbosity to n (default=%d):\n" + " (Level 3 is recommended if you want a good summary\n" + " of what's happening without being swamped by output).\n" + " : 0 -- no output except fatal errors\n" + " : 1 -- startup info + connection initiated messages +\n" + " non-fatal encryption & net errors\n" + " : 2,3 -- show TLS negotiations & route info\n" + " : 4 -- show parameters\n" + " : 5 -- show 'RrWw' chars on console for each packet sent\n" + " and received from TCP/UDP (caps) or tun/tap (lc)\n" + " : 6 to 11 -- debug messages of increasing verbosity\n" + "--mute n : Log at most n consecutive messages in the same category.\n" + "--status file n : Write operational status to file every n seconds.\n" + "--status-version [n] : Choose the status file format version number.\n" + " Currently, n can be 1, 2, or 3 (default=1).\n" #ifdef ENABLE_OCC - "--disable-occ : Disable options consistency check between peers.\n" + "--disable-occ : Disable options consistency check between peers.\n" #endif #ifdef ENABLE_DEBUG - "--gremlin mask : Special stress testing mode (for debugging only).\n" + "--gremlin mask : Special stress testing mode (for debugging only).\n" #endif #if defined(USE_COMP) - "--compress alg : Use compression algorithm alg\n" + "--compress alg : Use compression algorithm alg\n" #if defined(ENABLE_LZO) - "--comp-lzo : Use LZO compression -- may add up to 1 byte per\n" - " packet for uncompressible data.\n" - "--comp-noadapt : Don't use adaptive compression when --comp-lzo\n" - " is specified.\n" + "--comp-lzo : Use LZO compression -- may add up to 1 byte per\n" + " packet for uncompressible data.\n" + "--comp-noadapt : Don't use adaptive compression when --comp-lzo\n" + " is specified.\n" #endif #endif #ifdef ENABLE_MANAGEMENT - "--management ip port [pass] : Enable a TCP server on ip:port to handle\n" - " management functions. pass is a password file\n" - " or 'stdin' to prompt from console.\n" + "--management ip port [pass] : Enable a TCP server on ip:port to handle\n" + " management functions. pass is a password file\n" + " or 'stdin' to prompt from console.\n" #if UNIX_SOCK_SUPPORT - " To listen on a unix domain socket, specific the pathname\n" - " in place of ip and use 'unix' as the port number.\n" -#endif - "--management-client : Management interface will connect as a TCP client to\n" - " ip/port rather than listen as a TCP server.\n" - "--management-query-passwords : Query management channel for private key\n" - " and auth-user-pass passwords.\n" - "--management-query-proxy : Query management channel for proxy information.\n" - "--management-query-remote : Query management channel for --remote directive.\n" - "--management-hold : Start " PACKAGE_NAME " in a hibernating state, until a client\n" - " of the management interface explicitly starts it.\n" - "--management-signal : Issue SIGUSR1 when management disconnect event occurs.\n" - "--management-forget-disconnect : Forget passwords when management disconnect\n" - " event occurs.\n" - "--management-up-down : Report tunnel up/down events to management interface.\n" - "--management-log-cache n : Cache n lines of log file history for usage\n" - " by the management channel.\n" + " To listen on a unix domain socket, specific the pathname\n" + " in place of ip and use 'unix' as the port number.\n" +#endif + "--management-client : Management interface will connect as a TCP client to\n" + " ip/port rather than listen as a TCP server.\n" + "--management-query-passwords : Query management channel for private key\n" + " and auth-user-pass passwords.\n" + "--management-query-proxy : Query management channel for proxy information.\n" + "--management-query-remote : Query management channel for --remote directive.\n" + "--management-hold : Start " PACKAGE_NAME " in a hibernating state, until a client\n" + " of the management interface explicitly starts it.\n" + "--management-signal : Issue SIGUSR1 when management disconnect event occurs.\n" + "--management-forget-disconnect : Forget passwords when management disconnect\n" + " event occurs.\n" + "--management-up-down : Report tunnel up/down events to management interface.\n" + "--management-log-cache n : Cache n lines of log file history for usage\n" + " by the management channel.\n" #if UNIX_SOCK_SUPPORT - "--management-client-user u : When management interface is a unix socket, only\n" - " allow connections from user u.\n" - "--management-client-group g : When management interface is a unix socket, only\n" - " allow connections from group g.\n" + "--management-client-user u : When management interface is a unix socket, only\n" + " allow connections from user u.\n" + "--management-client-group g : When management interface is a unix socket, only\n" + " allow connections from group g.\n" #endif #ifdef MANAGEMENT_DEF_AUTH - "--management-client-auth : gives management interface client the responsibility\n" - " to authenticate clients after their client certificate\n" - " has been verified.\n" + "--management-client-auth : gives management interface client the responsibility\n" + " to authenticate clients after their client certificate\n" + " has been verified.\n" #endif #ifdef MANAGEMENT_PF - "--management-client-pf : management interface clients must specify a packet\n" - " filter file for each connecting client.\n" -#endif + "--management-client-pf : management interface clients must specify a packet\n" + " filter file for each connecting client.\n" #endif +#endif /* ifdef ENABLE_MANAGEMENT */ #ifdef ENABLE_PLUGIN - "--plugin m [str]: Load plug-in module m passing str as an argument\n" - " to its initialization function.\n" + "--plugin m [str]: Load plug-in module m passing str as an argument\n" + " to its initialization function.\n" #endif #if P2MP #if P2MP_SERVER - "\n" - "Multi-Client Server options (when --mode server is used):\n" - "--server network netmask : Helper option to easily configure server mode.\n" - "--server-ipv6 network/bits : Configure IPv6 server mode.\n" - "--server-bridge [IP netmask pool-start-IP pool-end-IP] : Helper option to\n" - " easily configure ethernet bridging server mode.\n" - "--push \"option\" : Push a config file option back to the peer for remote\n" - " execution. Peer must specify --pull in its config file.\n" - "--push-reset : Don't inherit global push list for specific\n" - " client instance.\n" - "--ifconfig-pool start-IP end-IP [netmask] : Set aside a pool of subnets\n" - " to be dynamically allocated to connecting clients.\n" - "--ifconfig-pool-linear : Use individual addresses rather than /30 subnets\n" - " in tun mode. Not compatible with Windows clients.\n" - "--ifconfig-pool-persist file [seconds] : Persist/unpersist ifconfig-pool\n" - " data to file, at seconds intervals (default=600).\n" - " If seconds=0, file will be treated as read-only.\n" - "--ifconfig-ipv6-pool base-IP/bits : set aside an IPv6 network block\n" - " to be dynamically allocated to connecting clients.\n" - "--ifconfig-push local remote-netmask : Push an ifconfig option to remote,\n" - " overrides --ifconfig-pool dynamic allocation.\n" - " Only valid in a client-specific config file.\n" - "--ifconfig-ipv6-push local/bits remote : Push an ifconfig-ipv6 option to\n" - " remote, overrides --ifconfig-ipv6-pool allocation.\n" - " Only valid in a client-specific config file.\n" - "--iroute network [netmask] : Route subnet to client.\n" - "--iroute-ipv6 network/bits : Route IPv6 subnet to client.\n" - " Sets up internal routes only.\n" - " Only valid in a client-specific config file.\n" - "--disable : Client is disabled.\n" - " Only valid in a client-specific config file.\n" - "--client-cert-not-required : Don't require client certificate, client\n" - " will authenticate using username/password.\n" - "--verify-client-cert [none|optional|require] : perform no, optional or\n" - " mandatory client certificate verification.\n" - " Default is to require the client to supply a certificate.\n" - "--username-as-common-name : For auth-user-pass authentication, use\n" - " the authenticated username as the common name,\n" - " rather than the common name from the client cert.\n" - "--auth-user-pass-verify cmd method: Query client for username/password and\n" - " run command cmd to verify. If method='via-env', pass\n" - " user/pass via environment, if method='via-file', pass\n" - " user/pass via temporary file.\n" - "--auth-gen-token [lifetime] Generate a random authentication token which is pushed\n" - " to each client, replacing the password. Usefull when\n" - " OTP based two-factor auth mechanisms are in use and\n" - " --reneg-* options are enabled. Optionally a lifetime in seconds\n" - " for generated tokens can be set.\n" - "--opt-verify : Clients that connect with options that are incompatible\n" - " with those of the server will be disconnected.\n" - "--auth-user-pass-optional : Allow connections by clients that don't\n" - " specify a username/password.\n" - "--no-name-remapping : Allow Common Name and X509 Subject to include\n" - " any printable character.\n" - "--client-to-client : Internally route client-to-client traffic.\n" - "--duplicate-cn : Allow multiple clients with the same common name to\n" - " concurrently connect.\n" - "--client-connect cmd : Run command cmd on client connection.\n" - "--client-disconnect cmd : Run command cmd on client disconnection.\n" - "--client-config-dir dir : Directory for custom client config files.\n" - "--ccd-exclusive : Refuse connection unless custom client config is found.\n" - "--tmp-dir dir : Temporary directory, used for --client-connect return file and plugin communication.\n" - "--hash-size r v : Set the size of the real address hash table to r and the\n" - " virtual address table to v.\n" - "--bcast-buffers n : Allocate n broadcast buffers.\n" - "--tcp-queue-limit n : Maximum number of queued TCP output packets.\n" - "--tcp-nodelay : Macro that sets TCP_NODELAY socket flag on the server\n" - " as well as pushes it to connecting clients.\n" - "--learn-address cmd : Run command cmd to validate client virtual addresses.\n" - "--connect-freq n s : Allow a maximum of n new connections per s seconds.\n" - "--max-clients n : Allow a maximum of n simultaneously connected clients.\n" - "--max-routes-per-client n : Allow a maximum of n internal routes per client.\n" - "--stale-routes-check n [t] : Remove routes with a last activity timestamp\n" - " older than n seconds. Run this check every t\n" - " seconds (defaults to n).\n" - "--explicit-exit-notify [n] : In UDP server mode send [RESTART] command on exit/restart to connected\n" - " clients. n = 1 - reconnect to same server,\n" - " 2 - advance to next server, default=1.\n" + "\n" + "Multi-Client Server options (when --mode server is used):\n" + "--server network netmask : Helper option to easily configure server mode.\n" + "--server-ipv6 network/bits : Configure IPv6 server mode.\n" + "--server-bridge [IP netmask pool-start-IP pool-end-IP] : Helper option to\n" + " easily configure ethernet bridging server mode.\n" + "--push \"option\" : Push a config file option back to the peer for remote\n" + " execution. Peer must specify --pull in its config file.\n" + "--push-reset : Don't inherit global push list for specific\n" + " client instance.\n" + "--ifconfig-pool start-IP end-IP [netmask] : Set aside a pool of subnets\n" + " to be dynamically allocated to connecting clients.\n" + "--ifconfig-pool-linear : Use individual addresses rather than /30 subnets\n" + " in tun mode. Not compatible with Windows clients.\n" + "--ifconfig-pool-persist file [seconds] : Persist/unpersist ifconfig-pool\n" + " data to file, at seconds intervals (default=600).\n" + " If seconds=0, file will be treated as read-only.\n" + "--ifconfig-ipv6-pool base-IP/bits : set aside an IPv6 network block\n" + " to be dynamically allocated to connecting clients.\n" + "--ifconfig-push local remote-netmask : Push an ifconfig option to remote,\n" + " overrides --ifconfig-pool dynamic allocation.\n" + " Only valid in a client-specific config file.\n" + "--ifconfig-ipv6-push local/bits remote : Push an ifconfig-ipv6 option to\n" + " remote, overrides --ifconfig-ipv6-pool allocation.\n" + " Only valid in a client-specific config file.\n" + "--iroute network [netmask] : Route subnet to client.\n" + "--iroute-ipv6 network/bits : Route IPv6 subnet to client.\n" + " Sets up internal routes only.\n" + " Only valid in a client-specific config file.\n" + "--disable : Client is disabled.\n" + " Only valid in a client-specific config file.\n" + "--client-cert-not-required : Don't require client certificate, client\n" + " will authenticate using username/password.\n" + "--verify-client-cert [none|optional|require] : perform no, optional or\n" + " mandatory client certificate verification.\n" + " Default is to require the client to supply a certificate.\n" + "--username-as-common-name : For auth-user-pass authentication, use\n" + " the authenticated username as the common name,\n" + " rather than the common name from the client cert.\n" + "--auth-user-pass-verify cmd method: Query client for username/password and\n" + " run command cmd to verify. If method='via-env', pass\n" + " user/pass via environment, if method='via-file', pass\n" + " user/pass via temporary file.\n" + "--auth-gen-token [lifetime] Generate a random authentication token which is pushed\n" + " to each client, replacing the password. Usefull when\n" + " OTP based two-factor auth mechanisms are in use and\n" + " --reneg-* options are enabled. Optionally a lifetime in seconds\n" + " for generated tokens can be set.\n" + "--opt-verify : Clients that connect with options that are incompatible\n" + " with those of the server will be disconnected.\n" + "--auth-user-pass-optional : Allow connections by clients that don't\n" + " specify a username/password.\n" + "--no-name-remapping : Allow Common Name and X509 Subject to include\n" + " any printable character.\n" + "--client-to-client : Internally route client-to-client traffic.\n" + "--duplicate-cn : Allow multiple clients with the same common name to\n" + " concurrently connect.\n" + "--client-connect cmd : Run command cmd on client connection.\n" + "--client-disconnect cmd : Run command cmd on client disconnection.\n" + "--client-config-dir dir : Directory for custom client config files.\n" + "--ccd-exclusive : Refuse connection unless custom client config is found.\n" + "--tmp-dir dir : Temporary directory, used for --client-connect return file and plugin communication.\n" + "--hash-size r v : Set the size of the real address hash table to r and the\n" + " virtual address table to v.\n" + "--bcast-buffers n : Allocate n broadcast buffers.\n" + "--tcp-queue-limit n : Maximum number of queued TCP output packets.\n" + "--tcp-nodelay : Macro that sets TCP_NODELAY socket flag on the server\n" + " as well as pushes it to connecting clients.\n" + "--learn-address cmd : Run command cmd to validate client virtual addresses.\n" + "--connect-freq n s : Allow a maximum of n new connections per s seconds.\n" + "--max-clients n : Allow a maximum of n simultaneously connected clients.\n" + "--max-routes-per-client n : Allow a maximum of n internal routes per client.\n" + "--stale-routes-check n [t] : Remove routes with a last activity timestamp\n" + " older than n seconds. Run this check every t\n" + " seconds (defaults to n).\n" + "--explicit-exit-notify [n] : In UDP server mode send [RESTART] command on exit/restart to connected\n" + " clients. n = 1 - reconnect to same server,\n" + " 2 - advance to next server, default=1.\n" #if PORT_SHARE - "--port-share host port [dir] : When run in TCP mode, proxy incoming HTTPS\n" - " sessions to a web server at host:port. dir specifies an\n" - " optional directory to write origin IP:port data.\n" -#endif -#endif - "\n" - "Client options (when connecting to a multi-client server):\n" - "--client : Helper option to easily configure client mode.\n" - "--auth-user-pass [up] : Authenticate with server using username/password.\n" - " up is a file containing the username on the first line,\n" - " and a password on the second. If either the password or both\n" - " the username and the password are omitted OpenVPN will prompt\n" - " for them from console.\n" - "--pull : Accept certain config file options from the peer as if they\n" - " were part of the local config file. Must be specified\n" - " when connecting to a '--mode server' remote host.\n" - "--pull-filter accept|ignore|reject t : Filter each option received from the\n" - " server if it starts with the text t. The action flag accept,\n" - " ignore or reject causes the option to be allowed, removed or\n" - " rejected with error. May be specified multiple times, and\n" - " each filter is applied in the order of appearance.\n" - "--auth-retry t : How to handle auth failures. Set t to\n" - " none (default), interact, or nointeract.\n" - "--static-challenge t e : Enable static challenge/response protocol using\n" - " challenge text t, with e indicating echo flag (0|1)\n" - "--connect-timeout n : when polling possible remote servers to connect to\n" - " in a round-robin fashion, spend no more than n seconds\n" - " waiting for a response before trying the next server.\n" - "--allow-recursive-routing : When this option is set, OpenVPN will not drop\n" - " incoming tun packets with same destination as host.\n" -#endif + "--port-share host port [dir] : When run in TCP mode, proxy incoming HTTPS\n" + " sessions to a web server at host:port. dir specifies an\n" + " optional directory to write origin IP:port data.\n" +#endif +#endif /* if P2MP_SERVER */ + "\n" + "Client options (when connecting to a multi-client server):\n" + "--client : Helper option to easily configure client mode.\n" + "--auth-user-pass [up] : Authenticate with server using username/password.\n" + " up is a file containing the username on the first line,\n" + " and a password on the second. If either the password or both\n" + " the username and the password are omitted OpenVPN will prompt\n" + " for them from console.\n" + "--pull : Accept certain config file options from the peer as if they\n" + " were part of the local config file. Must be specified\n" + " when connecting to a '--mode server' remote host.\n" + "--pull-filter accept|ignore|reject t : Filter each option received from the\n" + " server if it starts with the text t. The action flag accept,\n" + " ignore or reject causes the option to be allowed, removed or\n" + " rejected with error. May be specified multiple times, and\n" + " each filter is applied in the order of appearance.\n" + "--auth-retry t : How to handle auth failures. Set t to\n" + " none (default), interact, or nointeract.\n" + "--static-challenge t e : Enable static challenge/response protocol using\n" + " challenge text t, with e indicating echo flag (0|1)\n" + "--connect-timeout n : when polling possible remote servers to connect to\n" + " in a round-robin fashion, spend no more than n seconds\n" + " waiting for a response before trying the next server.\n" + "--allow-recursive-routing : When this option is set, OpenVPN will not drop\n" + " incoming tun packets with same destination as host.\n" +#endif /* if P2MP */ #ifdef ENABLE_OCC - "--explicit-exit-notify [n] : On exit/restart, send exit signal to\n" - " server/remote. n = # of retries, default=1.\n" + "--explicit-exit-notify [n] : On exit/restart, send exit signal to\n" + " server/remote. n = # of retries, default=1.\n" #endif #ifdef ENABLE_CRYPTO - "\n" - "Data Channel Encryption Options (must be compatible between peers):\n" - "(These options are meaningful for both Static Key & TLS-mode)\n" - "--secret f [d] : Enable Static Key encryption mode (non-TLS).\n" - " Use shared secret file f, generate with --genkey.\n" - " The optional d parameter controls key directionality.\n" - " If d is specified, use separate keys for each\n" - " direction, set d=0 on one side of the connection,\n" - " and d=1 on the other side.\n" - "--auth alg : Authenticate packets with HMAC using message\n" - " digest algorithm alg (default=%s).\n" - " (usually adds 16 or 20 bytes per packet)\n" - " Set alg=none to disable authentication.\n" - "--cipher alg : Encrypt packets with cipher algorithm alg\n" - " (default=%s).\n" - " Set alg=none to disable encryption.\n" - "--ncp-ciphers list : List of ciphers that are allowed to be negotiated.\n" - "--ncp-disable : Disable cipher negotiation.\n" - "--prng alg [nsl] : For PRNG, use digest algorithm alg, and\n" - " nonce_secret_len=nsl. Set alg=none to disable PRNG.\n" + "\n" + "Data Channel Encryption Options (must be compatible between peers):\n" + "(These options are meaningful for both Static Key & TLS-mode)\n" + "--secret f [d] : Enable Static Key encryption mode (non-TLS).\n" + " Use shared secret file f, generate with --genkey.\n" + " The optional d parameter controls key directionality.\n" + " If d is specified, use separate keys for each\n" + " direction, set d=0 on one side of the connection,\n" + " and d=1 on the other side.\n" + "--auth alg : Authenticate packets with HMAC using message\n" + " digest algorithm alg (default=%s).\n" + " (usually adds 16 or 20 bytes per packet)\n" + " Set alg=none to disable authentication.\n" + "--cipher alg : Encrypt packets with cipher algorithm alg\n" + " (default=%s).\n" + " Set alg=none to disable encryption.\n" + "--ncp-ciphers list : List of ciphers that are allowed to be negotiated.\n" + "--ncp-disable : Disable cipher negotiation.\n" + "--prng alg [nsl] : For PRNG, use digest algorithm alg, and\n" + " nonce_secret_len=nsl. Set alg=none to disable PRNG.\n" #ifdef HAVE_EVP_CIPHER_CTX_SET_KEY_LENGTH - "--keysize n : Size of cipher key in bits (optional).\n" - " If unspecified, defaults to cipher-specific default.\n" + "--keysize n : Size of cipher key in bits (optional).\n" + " If unspecified, defaults to cipher-specific default.\n" #endif #ifndef ENABLE_CRYPTO_MBEDTLS - "--engine [name] : Enable OpenSSL hardware crypto engine functionality.\n" -#endif - "--no-replay : Disable replay protection.\n" - "--mute-replay-warnings : Silence the output of replay warnings to log file.\n" - "--replay-window n [t] : Use a replay protection sliding window of size n\n" - " and a time window of t seconds.\n" - " Default n=%d t=%d\n" - "--no-iv : Disable cipher IV -- only allowed with CBC mode ciphers.\n" - "--replay-persist file : Persist replay-protection state across sessions\n" - " using file.\n" - "--test-crypto : Run a self-test of crypto features enabled.\n" - " For debugging only.\n" + "--engine [name] : Enable OpenSSL hardware crypto engine functionality.\n" +#endif + "--no-replay : Disable replay protection.\n" + "--mute-replay-warnings : Silence the output of replay warnings to log file.\n" + "--replay-window n [t] : Use a replay protection sliding window of size n\n" + " and a time window of t seconds.\n" + " Default n=%d t=%d\n" + "--no-iv : Disable cipher IV -- only allowed with CBC mode ciphers.\n" + "--replay-persist file : Persist replay-protection state across sessions\n" + " using file.\n" + "--test-crypto : Run a self-test of crypto features enabled.\n" + " For debugging only.\n" #ifdef ENABLE_PREDICTION_RESISTANCE - "--use-prediction-resistance: Enable prediction resistance on the random\n" - " number generator.\n" -#endif - "\n" - "TLS Key Negotiation Options:\n" - "(These options are meaningful only for TLS-mode)\n" - "--tls-server : Enable TLS and assume server role during TLS handshake.\n" - "--tls-client : Enable TLS and assume client role during TLS handshake.\n" - "--key-method m : Data channel key exchange method. m should be a method\n" - " number, such as 1 (default), 2, etc.\n" - "--ca file : Certificate authority file in .pem format containing\n" - " root certificate.\n" + "--use-prediction-resistance: Enable prediction resistance on the random\n" + " number generator.\n" +#endif + "\n" + "TLS Key Negotiation Options:\n" + "(These options are meaningful only for TLS-mode)\n" + "--tls-server : Enable TLS and assume server role during TLS handshake.\n" + "--tls-client : Enable TLS and assume client role during TLS handshake.\n" + "--key-method m : Data channel key exchange method. m should be a method\n" + " number, such as 1 (default), 2, etc.\n" + "--ca file : Certificate authority file in .pem format containing\n" + " root certificate.\n" #ifndef ENABLE_CRYPTO_MBEDTLS - "--capath dir : A directory of trusted certificates (CAs" - " and CRLs).\n" + "--capath dir : A directory of trusted certificates (CAs" + " and CRLs).\n" #endif /* ENABLE_CRYPTO_MBEDTLS */ - "--dh file : File containing Diffie Hellman parameters\n" - " in .pem format (for --tls-server only).\n" - " Use \"openssl dhparam -out dh1024.pem 1024\" to generate.\n" - "--cert file : Local certificate in .pem format -- must be signed\n" - " by a Certificate Authority in --ca file.\n" - "--extra-certs file : one or more PEM certs that complete the cert chain.\n" - "--key file : Local private key in .pem format.\n" - "--tls-version-min ['or-highest'] : sets the minimum TLS version we\n" - " will accept from the peer. If version is unrecognized and 'or-highest'\n" - " is specified, require max TLS version supported by SSL implementation.\n" - "--tls-version-max : sets the maximum TLS version we will use.\n" + "--dh file : File containing Diffie Hellman parameters\n" + " in .pem format (for --tls-server only).\n" + " Use \"openssl dhparam -out dh1024.pem 1024\" to generate.\n" + "--cert file : Local certificate in .pem format -- must be signed\n" + " by a Certificate Authority in --ca file.\n" + "--extra-certs file : one or more PEM certs that complete the cert chain.\n" + "--key file : Local private key in .pem format.\n" + "--tls-version-min ['or-highest'] : sets the minimum TLS version we\n" + " will accept from the peer. If version is unrecognized and 'or-highest'\n" + " is specified, require max TLS version supported by SSL implementation.\n" + "--tls-version-max : sets the maximum TLS version we will use.\n" #ifndef ENABLE_CRYPTO_MBEDTLS - "--pkcs12 file : PKCS#12 file containing local private key, local certificate\n" - " and optionally the root CA certificate.\n" + "--pkcs12 file : PKCS#12 file containing local private key, local certificate\n" + " and optionally the root CA certificate.\n" #endif #ifdef ENABLE_X509ALTUSERNAME - "--x509-username-field : Field in x509 certificate containing the username.\n" - " Default is CN in the Subject field.\n" + "--x509-username-field : Field in x509 certificate containing the username.\n" + " Default is CN in the Subject field.\n" #endif - "--verify-hash : Specify SHA1 fingerprint for level-1 cert.\n" + "--verify-hash : Specify SHA1 fingerprint for level-1 cert.\n" #ifdef _WIN32 - "--cryptoapicert select-string : Load the certificate and private key from the\n" - " Windows Certificate System Store.\n" -#endif - "--tls-cipher l : A list l of allowable TLS ciphers separated by : (optional).\n" - " : Use --show-tls to see a list of supported TLS ciphers.\n" - "--tls-timeout n : Packet retransmit timeout on TLS control channel\n" - " if no ACK from remote within n seconds (default=%d).\n" - "--reneg-bytes n : Renegotiate data chan. key after n bytes sent and recvd.\n" - "--reneg-pkts n : Renegotiate data chan. key after n packets sent and recvd.\n" - "--reneg-sec n : Renegotiate data chan. key after n seconds (default=%d).\n" - "--hand-window n : Data channel key exchange must finalize within n seconds\n" - " of handshake initiation by any peer (default=%d).\n" - "--tran-window n : Transition window -- old key can live this many seconds\n" - " after new key renegotiation begins (default=%d).\n" - "--single-session: Allow only one session (reset state on restart).\n" - "--tls-exit : Exit on TLS negotiation failure.\n" - "--tls-auth f [d]: Add an additional layer of authentication on top of the TLS\n" - " control channel to protect against attacks on the TLS stack\n" - " and DoS attacks.\n" - " f (required) is a shared-secret key file.\n" - " The optional d parameter controls key directionality,\n" - " see --secret option for more info.\n" - "--tls-crypt key : Add an additional layer of authenticated encryption on top\n" - " of the TLS control channel to hide the TLS certificate,\n" - " provide basic post-quantum security and protect against\n" - " attacks on the TLS stack and DoS attacks.\n" - " key (required) provides the pre-shared key file.\n" - " see --secret option for more info.\n" - "--askpass [file]: Get PEM password from controlling tty before we daemonize.\n" - "--auth-nocache : Don't cache --askpass or --auth-user-pass passwords.\n" - "--crl-verify crl ['dir']: Check peer certificate against a CRL.\n" - "--tls-verify cmd: Run command cmd to verify the X509 name of a\n" - " pending TLS connection that has otherwise passed all other\n" - " tests of certification. cmd should return 0 to allow\n" - " TLS handshake to proceed, or 1 to fail. (cmd is\n" - " executed as 'cmd certificate_depth subject')\n" - "--tls-export-cert [directory] : Get peer cert in PEM format and store it \n" - " in an openvpn temporary file in [directory]. Peer cert is \n" - " stored before tls-verify script execution and deleted after.\n" - "--verify-x509-name name: Accept connections only from a host with X509 subject\n" - " DN name. The remote host must also pass all other tests\n" - " of verification.\n" - "--ns-cert-type t: Require that peer certificate was signed with an explicit\n" - " nsCertType designation t = 'client' | 'server'.\n" - "--x509-track x : Save peer X509 attribute x in environment for use by\n" - " plugins and management interface.\n" + "--cryptoapicert select-string : Load the certificate and private key from the\n" + " Windows Certificate System Store.\n" +#endif + "--tls-cipher l : A list l of allowable TLS ciphers separated by : (optional).\n" + " : Use --show-tls to see a list of supported TLS ciphers.\n" + "--tls-timeout n : Packet retransmit timeout on TLS control channel\n" + " if no ACK from remote within n seconds (default=%d).\n" + "--reneg-bytes n : Renegotiate data chan. key after n bytes sent and recvd.\n" + "--reneg-pkts n : Renegotiate data chan. key after n packets sent and recvd.\n" + "--reneg-sec n : Renegotiate data chan. key after n seconds (default=%d).\n" + "--hand-window n : Data channel key exchange must finalize within n seconds\n" + " of handshake initiation by any peer (default=%d).\n" + "--tran-window n : Transition window -- old key can live this many seconds\n" + " after new key renegotiation begins (default=%d).\n" + "--single-session: Allow only one session (reset state on restart).\n" + "--tls-exit : Exit on TLS negotiation failure.\n" + "--tls-auth f [d]: Add an additional layer of authentication on top of the TLS\n" + " control channel to protect against attacks on the TLS stack\n" + " and DoS attacks.\n" + " f (required) is a shared-secret key file.\n" + " The optional d parameter controls key directionality,\n" + " see --secret option for more info.\n" + "--tls-crypt key : Add an additional layer of authenticated encryption on top\n" + " of the TLS control channel to hide the TLS certificate,\n" + " provide basic post-quantum security and protect against\n" + " attacks on the TLS stack and DoS attacks.\n" + " key (required) provides the pre-shared key file.\n" + " see --secret option for more info.\n" + "--askpass [file]: Get PEM password from controlling tty before we daemonize.\n" + "--auth-nocache : Don't cache --askpass or --auth-user-pass passwords.\n" + "--crl-verify crl ['dir']: Check peer certificate against a CRL.\n" + "--tls-verify cmd: Run command cmd to verify the X509 name of a\n" + " pending TLS connection that has otherwise passed all other\n" + " tests of certification. cmd should return 0 to allow\n" + " TLS handshake to proceed, or 1 to fail. (cmd is\n" + " executed as 'cmd certificate_depth subject')\n" + "--tls-export-cert [directory] : Get peer cert in PEM format and store it \n" + " in an openvpn temporary file in [directory]. Peer cert is \n" + " stored before tls-verify script execution and deleted after.\n" + "--verify-x509-name name: Accept connections only from a host with X509 subject\n" + " DN name. The remote host must also pass all other tests\n" + " of verification.\n" + "--ns-cert-type t: Require that peer certificate was signed with an explicit\n" + " nsCertType designation t = 'client' | 'server'.\n" + "--x509-track x : Save peer X509 attribute x in environment for use by\n" + " plugins and management interface.\n" #if defined(ENABLE_CRYPTO_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10001000 - "--keying-material-exporter label len : Save Exported Keying Material (RFC5705)\n" - " of len bytes (min. 16 bytes) using label in environment for use by plugins.\n" -#endif - "--remote-cert-ku v ... : Require that the peer certificate was signed with\n" - " explicit key usage, you can specify more than one value.\n" - " value should be given in hex format.\n" - "--remote-cert-eku oid : Require that the peer certificate was signed with\n" - " explicit extended key usage. Extended key usage can be encoded\n" - " as an object identifier or OpenSSL string representation.\n" - "--remote-cert-tls t: Require that peer certificate was signed with explicit\n" - " key usage and extended key usage based on RFC3280 TLS rules.\n" - " t = 'client' | 'server'.\n" + "--keying-material-exporter label len : Save Exported Keying Material (RFC5705)\n" + " of len bytes (min. 16 bytes) using label in environment for use by plugins.\n" +#endif + "--remote-cert-ku v ... : Require that the peer certificate was signed with\n" + " explicit key usage, you can specify more than one value.\n" + " value should be given in hex format.\n" + "--remote-cert-eku oid : Require that the peer certificate was signed with\n" + " explicit extended key usage. Extended key usage can be encoded\n" + " as an object identifier or OpenSSL string representation.\n" + "--remote-cert-tls t: Require that peer certificate was signed with explicit\n" + " key usage and extended key usage based on RFC3280 TLS rules.\n" + " t = 'client' | 'server'.\n" #ifdef ENABLE_PKCS11 - "\n" - "PKCS#11 Options:\n" - "--pkcs11-providers provider ... : PKCS#11 provider to load.\n" - "--pkcs11-protected-authentication [0|1] ... : Use PKCS#11 protected authentication\n" - " path. Set for each provider.\n" - "--pkcs11-private-mode hex ... : PKCS#11 private key mode mask.\n" - " 0 : Try to determind automatically (default).\n" - " 1 : Use Sign.\n" - " 2 : Use SignRecover.\n" - " 4 : Use Decrypt.\n" - " 8 : Use Unwrap.\n" - "--pkcs11-cert-private [0|1] ... : Set if login should be performed before\n" - " certificate can be accessed. Set for each provider.\n" - "--pkcs11-pin-cache seconds : Number of seconds to cache PIN. The default is -1\n" - " cache until token is removed.\n" - "--pkcs11-id-management : Acquire identity from management interface.\n" - "--pkcs11-id serialized-id 'id' : Identity to use, get using standalone --show-pkcs11-ids\n" -#endif /* ENABLE_PKCS11 */ - "\n" - "SSL Library information:\n" - "--show-ciphers : Show cipher algorithms to use with --cipher option.\n" - "--show-digests : Show message digest algorithms to use with --auth option.\n" - "--show-engines : Show hardware crypto accelerator engines (if available).\n" - "--show-tls : Show all TLS ciphers (TLS used only as a control channel).\n" + "\n" + "PKCS#11 Options:\n" + "--pkcs11-providers provider ... : PKCS#11 provider to load.\n" + "--pkcs11-protected-authentication [0|1] ... : Use PKCS#11 protected authentication\n" + " path. Set for each provider.\n" + "--pkcs11-private-mode hex ... : PKCS#11 private key mode mask.\n" + " 0 : Try to determind automatically (default).\n" + " 1 : Use Sign.\n" + " 2 : Use SignRecover.\n" + " 4 : Use Decrypt.\n" + " 8 : Use Unwrap.\n" + "--pkcs11-cert-private [0|1] ... : Set if login should be performed before\n" + " certificate can be accessed. Set for each provider.\n" + "--pkcs11-pin-cache seconds : Number of seconds to cache PIN. The default is -1\n" + " cache until token is removed.\n" + "--pkcs11-id-management : Acquire identity from management interface.\n" + "--pkcs11-id serialized-id 'id' : Identity to use, get using standalone --show-pkcs11-ids\n" +#endif /* ENABLE_PKCS11 */ + "\n" + "SSL Library information:\n" + "--show-ciphers : Show cipher algorithms to use with --cipher option.\n" + "--show-digests : Show message digest algorithms to use with --auth option.\n" + "--show-engines : Show hardware crypto accelerator engines (if available).\n" + "--show-tls : Show all TLS ciphers (TLS used only as a control channel).\n" #ifdef _WIN32 - "\n" - "Windows Specific:\n" - "--win-sys path : Pathname of Windows system directory. Default is the pathname\n" - " from SystemRoot environment variable.\n" - "--ip-win32 method : When using --ifconfig on Windows, set TAP-Windows adapter\n" - " IP address using method = manual, netsh, ipapi,\n" - " dynamic, or adaptive (default = adaptive).\n" - " Dynamic method allows two optional parameters:\n" - " offset: DHCP server address offset (> -256 and < 256).\n" - " If 0, use network address, if >0, take nth\n" - " address forward from network address, if <0,\n" - " take nth address backward from broadcast\n" - " address.\n" - " Default is 0.\n" - " lease-time: Lease time in seconds.\n" - " Default is one year.\n" - "--route-method : Which method to use for adding routes on Windows?\n" - " adaptive (default) -- Try ipapi then fall back to exe.\n" - " ipapi -- Use IP helper API.\n" - " exe -- Call the route.exe shell command.\n" - "--dhcp-option type [parm] : Set extended TAP-Windows properties, must\n" - " be used with --ip-win32 dynamic. For options\n" - " which allow multiple addresses,\n" - " --dhcp-option must be repeated.\n" - " DOMAIN name : Set DNS suffix\n" - " DNS addr : Set domain name server address(es) (IPv4)\n" - " DNS6 addr : Set domain name server address(es) (IPv6)\n" - " NTP : Set NTP server address(es)\n" - " NBDD : Set NBDD server address(es)\n" - " WINS addr : Set WINS server address(es)\n" - " NBT type : Set NetBIOS over TCP/IP Node type\n" - " 1: B, 2: P, 4: M, 8: H\n" - " NBS id : Set NetBIOS scope ID\n" - " DISABLE-NBT : Disable Netbios-over-TCP/IP.\n" - "--dhcp-renew : Ask Windows to renew the TAP adapter lease on startup.\n" - "--dhcp-pre-release : Ask Windows to release the previous TAP adapter lease on\n" -" startup.\n" - "--dhcp-release : Ask Windows to release the TAP adapter lease on shutdown.\n" - "--register-dns : Run ipconfig /flushdns and ipconfig /registerdns\n" - " on connection initiation.\n" - "--tap-sleep n : Sleep for n seconds after TAP adapter open before\n" - " attempting to set adapter properties.\n" - "--pause-exit : When run from a console window, pause before exiting.\n" - "--service ex [0|1] : For use when " PACKAGE_NAME " is being instantiated by a\n" - " service, and should not be used directly by end-users.\n" - " ex is the name of an event object which, when\n" - " signaled, will cause " PACKAGE_NAME " to exit. A second\n" - " optional parameter controls the initial state of ex.\n" - "--show-net-up : Show " PACKAGE_NAME "'s view of routing table and net adapter list\n" - " after TAP adapter is up and routes have been added.\n" + "\n" + "Windows Specific:\n" + "--win-sys path : Pathname of Windows system directory. Default is the pathname\n" + " from SystemRoot environment variable.\n" + "--ip-win32 method : When using --ifconfig on Windows, set TAP-Windows adapter\n" + " IP address using method = manual, netsh, ipapi,\n" + " dynamic, or adaptive (default = adaptive).\n" + " Dynamic method allows two optional parameters:\n" + " offset: DHCP server address offset (> -256 and < 256).\n" + " If 0, use network address, if >0, take nth\n" + " address forward from network address, if <0,\n" + " take nth address backward from broadcast\n" + " address.\n" + " Default is 0.\n" + " lease-time: Lease time in seconds.\n" + " Default is one year.\n" + "--route-method : Which method to use for adding routes on Windows?\n" + " adaptive (default) -- Try ipapi then fall back to exe.\n" + " ipapi -- Use IP helper API.\n" + " exe -- Call the route.exe shell command.\n" + "--dhcp-option type [parm] : Set extended TAP-Windows properties, must\n" + " be used with --ip-win32 dynamic. For options\n" + " which allow multiple addresses,\n" + " --dhcp-option must be repeated.\n" + " DOMAIN name : Set DNS suffix\n" + " DNS addr : Set domain name server address(es) (IPv4)\n" + " DNS6 addr : Set domain name server address(es) (IPv6)\n" + " NTP : Set NTP server address(es)\n" + " NBDD : Set NBDD server address(es)\n" + " WINS addr : Set WINS server address(es)\n" + " NBT type : Set NetBIOS over TCP/IP Node type\n" + " 1: B, 2: P, 4: M, 8: H\n" + " NBS id : Set NetBIOS scope ID\n" + " DISABLE-NBT : Disable Netbios-over-TCP/IP.\n" + "--dhcp-renew : Ask Windows to renew the TAP adapter lease on startup.\n" + "--dhcp-pre-release : Ask Windows to release the previous TAP adapter lease on\n" + " startup.\n" + "--dhcp-release : Ask Windows to release the TAP adapter lease on shutdown.\n" + "--register-dns : Run ipconfig /flushdns and ipconfig /registerdns\n" + " on connection initiation.\n" + "--tap-sleep n : Sleep for n seconds after TAP adapter open before\n" + " attempting to set adapter properties.\n" + "--pause-exit : When run from a console window, pause before exiting.\n" + "--service ex [0|1] : For use when " PACKAGE_NAME " is being instantiated by a\n" + " service, and should not be used directly by end-users.\n" + " ex is the name of an event object which, when\n" + " signaled, will cause " PACKAGE_NAME " to exit. A second\n" + " optional parameter controls the initial state of ex.\n" + "--show-net-up : Show " PACKAGE_NAME "'s view of routing table and net adapter list\n" + " after TAP adapter is up and routes have been added.\n" #ifdef _WIN32 - "--block-outside-dns : Block DNS on other network adapters to prevent DNS leaks\n" -#endif - "Windows Standalone Options:\n" - "\n" - "--show-adapters : Show all TAP-Windows adapters.\n" - "--show-net : Show " PACKAGE_NAME "'s view of routing table and net adapter list.\n" - "--show-valid-subnets : Show valid subnets for --dev tun emulation.\n" - "--allow-nonadmin [TAP-adapter] : Allow " PACKAGE_NAME " running without admin privileges\n" - " to access TAP adapter.\n" -#endif - "\n" - "Generate a random key (only for non-TLS static key encryption mode):\n" - "--genkey : Generate a random key to be used as a shared secret,\n" - " for use with the --secret option.\n" - "--secret file : Write key to file.\n" -#endif /* ENABLE_CRYPTO */ + "--block-outside-dns : Block DNS on other network adapters to prevent DNS leaks\n" +#endif + "Windows Standalone Options:\n" + "\n" + "--show-adapters : Show all TAP-Windows adapters.\n" + "--show-net : Show " PACKAGE_NAME "'s view of routing table and net adapter list.\n" + "--show-valid-subnets : Show valid subnets for --dev tun emulation.\n" + "--allow-nonadmin [TAP-adapter] : Allow " PACKAGE_NAME " running without admin privileges\n" + " to access TAP adapter.\n" +#endif /* ifdef _WIN32 */ + "\n" + "Generate a random key (only for non-TLS static key encryption mode):\n" + "--genkey : Generate a random key to be used as a shared secret,\n" + " for use with the --secret option.\n" + "--secret file : Write key to file.\n" +#endif /* ENABLE_CRYPTO */ #ifdef ENABLE_FEATURE_TUN_PERSIST - "\n" - "Tun/tap config mode (available with linux 2.4+):\n" - "--mktun : Create a persistent tunnel.\n" - "--rmtun : Remove a persistent tunnel.\n" - "--dev tunX|tapX : tun/tap device\n" - "--dev-type dt : Device type. See tunnel options above for details.\n" - "--user user : User to set privilege to.\n" - "--group group : Group to set privilege to.\n" + "\n" + "Tun/tap config mode (available with linux 2.4+):\n" + "--mktun : Create a persistent tunnel.\n" + "--rmtun : Remove a persistent tunnel.\n" + "--dev tunX|tapX : tun/tap device\n" + "--dev-type dt : Device type. See tunnel options above for details.\n" + "--user user : User to set privilege to.\n" + "--group group : Group to set privilege to.\n" #endif #ifdef ENABLE_PKCS11 - "\n" - "PKCS#11 standalone options:\n" + "\n" + "PKCS#11 standalone options:\n" #ifdef DEFAULT_PKCS11_MODULE - "--show-pkcs11-ids [provider] [cert_private] : Show PKCS#11 available ids.\n" + "--show-pkcs11-ids [provider] [cert_private] : Show PKCS#11 available ids.\n" #else - "--show-pkcs11-ids provider [cert_private] : Show PKCS#11 available ids.\n" + "--show-pkcs11-ids provider [cert_private] : Show PKCS#11 available ids.\n" #endif - " --verb option can be added *BEFORE* this.\n" -#endif /* ENABLE_PKCS11 */ - "\n" - "General Standalone Options:\n" + " --verb option can be added *BEFORE* this.\n" +#endif /* ENABLE_PKCS11 */ + "\n" + "General Standalone Options:\n" #ifdef ENABLE_DEBUG - "--show-gateway : Show info about default gateway.\n" + "--show-gateway : Show info about default gateway.\n" #endif - ; +; #endif /* !ENABLE_SMALL */ @@ -781,165 +781,174 @@ static const char usage_message[] = * will be set to 0. */ void -init_options (struct options *o, const bool init_gc) +init_options(struct options *o, const bool init_gc) { - CLEAR (*o); - if (init_gc) - { - gc_init (&o->gc); - o->gc_owned = true; - } - o->mode = MODE_POINT_TO_POINT; - o->topology = TOP_NET30; - o->ce.proto = PROTO_UDP; - o->ce.af = AF_UNSPEC; - o->ce.bind_ipv6_only = false; - o->ce.connect_retry_seconds = 5; - o->ce.connect_retry_seconds_max = 300; - o->ce.connect_timeout = 120; - o->connect_retry_max = 0; - o->ce.local_port = o->ce.remote_port = OPENVPN_PORT; - o->verbosity = 1; - o->status_file_update_freq = 60; - o->status_file_version = 1; - o->ce.bind_local = true; - o->ce.tun_mtu = TUN_MTU_DEFAULT; - o->ce.link_mtu = LINK_MTU_DEFAULT; - o->ce.mtu_discover_type = -1; - o->ce.mssfix = MSSFIX_DEFAULT; - o->route_delay_window = 30; - o->resolve_retry_seconds = RESOLV_RETRY_INFINITE; - o->resolve_in_advance = false; - o->proto_force = -1; + CLEAR(*o); + if (init_gc) + { + gc_init(&o->gc); + o->gc_owned = true; + } + o->mode = MODE_POINT_TO_POINT; + o->topology = TOP_NET30; + o->ce.proto = PROTO_UDP; + o->ce.af = AF_UNSPEC; + o->ce.bind_ipv6_only = false; + o->ce.connect_retry_seconds = 5; + o->ce.connect_retry_seconds_max = 300; + o->ce.connect_timeout = 120; + o->connect_retry_max = 0; + o->ce.local_port = o->ce.remote_port = OPENVPN_PORT; + o->verbosity = 1; + o->status_file_update_freq = 60; + o->status_file_version = 1; + o->ce.bind_local = true; + o->ce.tun_mtu = TUN_MTU_DEFAULT; + o->ce.link_mtu = LINK_MTU_DEFAULT; + o->ce.mtu_discover_type = -1; + o->ce.mssfix = MSSFIX_DEFAULT; + o->route_delay_window = 30; + o->resolve_retry_seconds = RESOLV_RETRY_INFINITE; + o->resolve_in_advance = false; + o->proto_force = -1; #ifdef ENABLE_OCC - o->occ = true; + o->occ = true; #endif #ifdef ENABLE_MANAGEMENT - o->management_log_history_cache = 250; - o->management_echo_buffer_size = 100; - o->management_state_buffer_size = 100; + o->management_log_history_cache = 250; + o->management_echo_buffer_size = 100; + o->management_state_buffer_size = 100; #endif #ifdef ENABLE_FEATURE_TUN_PERSIST - o->persist_mode = 1; + o->persist_mode = 1; #endif #ifdef TARGET_LINUX - o->tuntap_options.txqueuelen = 100; + o->tuntap_options.txqueuelen = 100; #endif #ifdef _WIN32 #if 0 - o->tuntap_options.ip_win32_type = IPW32_SET_ADAPTIVE; + o->tuntap_options.ip_win32_type = IPW32_SET_ADAPTIVE; #else - o->tuntap_options.ip_win32_type = IPW32_SET_DHCP_MASQ; + o->tuntap_options.ip_win32_type = IPW32_SET_DHCP_MASQ; #endif - o->tuntap_options.dhcp_lease_time = 31536000; /* one year */ - o->tuntap_options.dhcp_masq_offset = 0; /* use network address as internal DHCP server address */ - o->route_method = ROUTE_METHOD_ADAPTIVE; - o->block_outside_dns = false; + o->tuntap_options.dhcp_lease_time = 31536000; /* one year */ + o->tuntap_options.dhcp_masq_offset = 0; /* use network address as internal DHCP server address */ + o->route_method = ROUTE_METHOD_ADAPTIVE; + o->block_outside_dns = false; #endif #if P2MP_SERVER - o->real_hash_size = 256; - o->virtual_hash_size = 256; - o->n_bcast_buf = 256; - o->tcp_queue_limit = 64; - o->max_clients = 1024; - o->max_routes_per_client = 256; - o->stale_routes_check_interval = 0; - o->ifconfig_pool_persist_refresh_freq = 600; + o->real_hash_size = 256; + o->virtual_hash_size = 256; + o->n_bcast_buf = 256; + o->tcp_queue_limit = 64; + o->max_clients = 1024; + o->max_routes_per_client = 256; + o->stale_routes_check_interval = 0; + o->ifconfig_pool_persist_refresh_freq = 600; #endif #if P2MP - o->scheduled_exit_interval = 5; + o->scheduled_exit_interval = 5; #endif #ifdef ENABLE_CRYPTO - o->ciphername = "BF-CBC"; + o->ciphername = "BF-CBC"; #ifdef HAVE_AEAD_CIPHER_MODES /* IV_NCP=2 requires GCM support */ - o->ncp_enabled = true; + o->ncp_enabled = true; #else - o->ncp_enabled = false; -#endif - o->ncp_ciphers = "AES-256-GCM:AES-128-GCM"; - o->authname = "SHA1"; - o->prng_hash = "SHA1"; - o->prng_nonce_secret_len = 16; - o->replay = true; - o->replay_window = DEFAULT_SEQ_BACKTRACK; - o->replay_time = DEFAULT_TIME_BACKTRACK; - o->use_iv = true; - o->key_direction = KEY_DIRECTION_BIDIRECTIONAL; + o->ncp_enabled = false; +#endif + o->ncp_ciphers = "AES-256-GCM:AES-128-GCM"; + o->authname = "SHA1"; + o->prng_hash = "SHA1"; + o->prng_nonce_secret_len = 16; + o->replay = true; + o->replay_window = DEFAULT_SEQ_BACKTRACK; + o->replay_time = DEFAULT_TIME_BACKTRACK; + o->use_iv = true; + o->key_direction = KEY_DIRECTION_BIDIRECTIONAL; #ifdef ENABLE_PREDICTION_RESISTANCE - o->use_prediction_resistance = false; -#endif - o->key_method = 2; - o->tls_timeout = 2; - o->renegotiate_bytes = -1; - o->renegotiate_seconds = 3600; - o->handshake_window = 60; - o->transition_window = 3600; - o->ecdh_curve = NULL; + o->use_prediction_resistance = false; +#endif + o->key_method = 2; + o->tls_timeout = 2; + o->renegotiate_bytes = -1; + o->renegotiate_seconds = 3600; + o->handshake_window = 60; + o->transition_window = 3600; + o->ecdh_curve = NULL; #ifdef ENABLE_X509ALTUSERNAME - o->x509_username_field = X509_USERNAME_FIELD_DEFAULT; + o->x509_username_field = X509_USERNAME_FIELD_DEFAULT; #endif #endif /* ENABLE_CRYPTO */ #ifdef ENABLE_PKCS11 - o->pkcs11_pin_cache_period = -1; -#endif /* ENABLE_PKCS11 */ + o->pkcs11_pin_cache_period = -1; +#endif /* ENABLE_PKCS11 */ /* P2MP server context features */ #if P2MP_SERVER - o->auth_token_generate = false; + o->auth_token_generate = false; - /* Set default --tmp-dir */ + /* Set default --tmp-dir */ #ifdef _WIN32 - /* On Windows, find temp dir via enviroment variables */ - o->tmp_dir = win_get_tempdir(); + /* On Windows, find temp dir via enviroment variables */ + o->tmp_dir = win_get_tempdir(); #else - /* Non-windows platforms use $TMPDIR, and if not set, default to '/tmp' */ - o->tmp_dir = getenv("TMPDIR"); - if( !o->tmp_dir ) { - o->tmp_dir = "/tmp"; - } + /* Non-windows platforms use $TMPDIR, and if not set, default to '/tmp' */ + o->tmp_dir = getenv("TMPDIR"); + if (!o->tmp_dir) + { + o->tmp_dir = "/tmp"; + } #endif /* _WIN32 */ #endif /* P2MP_SERVER */ - o->allow_recursive_routing = false; + o->allow_recursive_routing = false; } void -uninit_options (struct options *o) +uninit_options(struct options *o) { - if (o->gc_owned) + if (o->gc_owned) { - gc_free (&o->gc); + gc_free(&o->gc); } } struct pull_filter { -# define PUF_TYPE_UNDEF 0 /** undefined filter type */ -# define PUF_TYPE_ACCEPT 1 /** filter type to accept a matching option */ -# define PUF_TYPE_IGNORE 2 /** filter type to ignore a matching option */ -# define PUF_TYPE_REJECT 3 /** filter type to reject and trigger SIGUSR1 */ - int type; - int size; - char *pattern; - struct pull_filter *next; +#define PUF_TYPE_UNDEF 0 /** undefined filter type */ +#define PUF_TYPE_ACCEPT 1 /** filter type to accept a matching option */ +#define PUF_TYPE_IGNORE 2 /** filter type to ignore a matching option */ +#define PUF_TYPE_REJECT 3 /** filter type to reject and trigger SIGUSR1 */ + int type; + int size; + char *pattern; + struct pull_filter *next; }; struct pull_filter_list { - struct pull_filter *head; - struct pull_filter *tail; + struct pull_filter *head; + struct pull_filter *tail; }; static const char * -pull_filter_type_name (int type) +pull_filter_type_name(int type) { - if (type == PUF_TYPE_ACCEPT) - return "accept"; - if (type == PUF_TYPE_IGNORE) - return "ignore"; - if (type == PUF_TYPE_REJECT) - return "reject"; - else - return "???"; + if (type == PUF_TYPE_ACCEPT) + { + return "accept"; + } + if (type == PUF_TYPE_IGNORE) + { + return "ignore"; + } + if (type == PUF_TYPE_REJECT) + { + return "reject"; + } + else + { + return "???"; + } } #ifndef ENABLE_SMALL @@ -954,62 +963,68 @@ pull_filter_type_name (int type) #endif void -setenv_connection_entry (struct env_set *es, - const struct connection_entry *e, - const int i) +setenv_connection_entry(struct env_set *es, + const struct connection_entry *e, + const int i) { - setenv_str_i (es, "proto", proto2ascii (e->proto, e->af, false), i); - setenv_str_i (es, "local", e->local, i); - setenv_str_i (es, "local_port", e->local_port, i); - setenv_str_i (es, "remote", e->remote, i); - setenv_str_i (es, "remote_port", e->remote_port, i); + setenv_str_i(es, "proto", proto2ascii(e->proto, e->af, false), i); + setenv_str_i(es, "local", e->local, i); + setenv_str_i(es, "local_port", e->local_port, i); + setenv_str_i(es, "remote", e->remote, i); + setenv_str_i(es, "remote_port", e->remote_port, i); - if (e->http_proxy_options) + if (e->http_proxy_options) { - setenv_str_i (es, "http_proxy_server", e->http_proxy_options->server, i); - setenv_str_i (es, "http_proxy_port", e->http_proxy_options->port, i); + setenv_str_i(es, "http_proxy_server", e->http_proxy_options->server, i); + setenv_str_i(es, "http_proxy_port", e->http_proxy_options->port, i); } - if (e->socks_proxy_server) + if (e->socks_proxy_server) { - setenv_str_i (es, "socks_proxy_server", e->socks_proxy_server, i); - setenv_str_i (es, "socks_proxy_port", e->socks_proxy_port, i); + setenv_str_i(es, "socks_proxy_server", e->socks_proxy_server, i); + setenv_str_i(es, "socks_proxy_port", e->socks_proxy_port, i); } } void -setenv_settings (struct env_set *es, const struct options *o) +setenv_settings(struct env_set *es, const struct options *o) { - setenv_str (es, "config", o->config); - setenv_int (es, "verb", o->verbosity); - setenv_int (es, "daemon", o->daemon); - setenv_int (es, "daemon_log_redirect", o->log); - setenv_unsigned (es, "daemon_start_time", time(NULL)); - setenv_int (es, "daemon_pid", platform_getpid()); + setenv_str(es, "config", o->config); + setenv_int(es, "verb", o->verbosity); + setenv_int(es, "daemon", o->daemon); + setenv_int(es, "daemon_log_redirect", o->log); + setenv_unsigned(es, "daemon_start_time", time(NULL)); + setenv_int(es, "daemon_pid", platform_getpid()); - if (o->connection_list) + if (o->connection_list) + { + int i; + for (i = 0; i < o->connection_list->len; ++i) + setenv_connection_entry(es, o->connection_list->array[i], i+1); + } + else { - int i; - for (i = 0; i < o->connection_list->len; ++i) - setenv_connection_entry (es, o->connection_list->array[i], i+1); + setenv_connection_entry(es, &o->ce, 1); } - else - setenv_connection_entry (es, &o->ce, 1); } static in_addr_t -get_ip_addr (const char *ip_string, int msglevel, bool *error) +get_ip_addr(const char *ip_string, int msglevel, bool *error) { - unsigned int flags = GETADDR_HOST_ORDER; - bool succeeded = false; - in_addr_t ret; + unsigned int flags = GETADDR_HOST_ORDER; + bool succeeded = false; + in_addr_t ret; - if (msglevel & M_FATAL) - flags |= GETADDR_FATAL; + if (msglevel & M_FATAL) + { + flags |= GETADDR_FATAL; + } - ret = getaddr (flags, ip_string, 0, &succeeded, NULL); - if (!succeeded && error) - *error = true; - return ret; + ret = getaddr(flags, ip_string, 0, &succeeded, NULL); + if (!succeeded && error) + { + *error = true; + } + return ret; } /* helper: parse a text string containing an IPv6 address + netbits @@ -1019,52 +1034,58 @@ get_ip_addr (const char *ip_string, int msglevel, bool *error) * return true if parsing succeeded, modify *network and *netbits */ bool -get_ipv6_addr( const char * prefix_str, struct in6_addr *network, - unsigned int * netbits, int msglevel) +get_ipv6_addr( const char *prefix_str, struct in6_addr *network, + unsigned int *netbits, int msglevel) { - char * sep, * endp; + char *sep, *endp; int bits; struct in6_addr t_network; sep = strchr( prefix_str, '/' ); - if ( sep == NULL ) - { - bits = 64; - } + if (sep == NULL) + { + bits = 64; + } else - { - bits = strtol( sep+1, &endp, 10 ); - if ( *endp != '\0' || bits < 0 || bits > 128 ) - { - msg (msglevel, "IPv6 prefix '%s': invalid '/bits' spec", prefix_str); - return false; - } - } + { + bits = strtol( sep+1, &endp, 10 ); + if (*endp != '\0' || bits < 0 || bits > 128) + { + msg(msglevel, "IPv6 prefix '%s': invalid '/bits' spec", prefix_str); + return false; + } + } /* temporary replace '/' in caller-provided string with '\0', otherwise * inet_pton() will refuse prefix string * (alternative would be to strncpy() the prefix to temporary buffer) */ - if ( sep != NULL ) *sep = '\0'; - - if ( inet_pton( AF_INET6, prefix_str, &t_network ) != 1 ) - { - msg (msglevel, "IPv6 prefix '%s': invalid IPv6 address", prefix_str); - return false; - } - - if ( sep != NULL ) *sep = '/'; - - if ( netbits != NULL ) - { - *netbits = bits; - } - if ( network != NULL ) - { - *network = t_network; - } - return true; /* parsing OK, values set */ + if (sep != NULL) + { + *sep = '\0'; + } + + if (inet_pton( AF_INET6, prefix_str, &t_network ) != 1) + { + msg(msglevel, "IPv6 prefix '%s': invalid IPv6 address", prefix_str); + return false; + } + + if (sep != NULL) + { + *sep = '/'; + } + + if (netbits != NULL) + { + *netbits = bits; + } + if (network != NULL) + { + *network = t_network; + } + return true; /* parsing OK, values set */ } /** @@ -1073,24 +1094,25 @@ get_ipv6_addr( const char * prefix_str, struct in6_addr *network, * If gc != NULL, the allocated memory is registered in the supplied gc. */ static char * -get_ipv6_addr_no_netbits (const char *addr, struct gc_arena *gc) +get_ipv6_addr_no_netbits(const char *addr, struct gc_arena *gc) { - const char *end = strchr (addr, '/'); - char *ret = NULL; - if (NULL == end) + const char *end = strchr(addr, '/'); + char *ret = NULL; + if (NULL == end) { - ret = string_alloc (addr, gc); + ret = string_alloc(addr, gc); } - else + else { - size_t len = end - addr; - ret = gc_malloc (len + 1, true, gc); - memcpy (ret, addr, len); + size_t len = end - addr; + ret = gc_malloc(len + 1, true, gc); + memcpy(ret, addr, len); } - return ret; + return ret; } -static bool ipv6_addr_safe_hexplusbits( const char * ipv6_prefix_spec ) +static bool +ipv6_addr_safe_hexplusbits( const char *ipv6_prefix_spec ) { struct in6_addr t_addr; unsigned int t_bits; @@ -1099,205 +1121,221 @@ static bool ipv6_addr_safe_hexplusbits( const char * ipv6_prefix_spec ) } static char * -string_substitute (const char *src, int from, int to, struct gc_arena *gc) +string_substitute(const char *src, int from, int to, struct gc_arena *gc) { - char *ret = (char *) gc_malloc (strlen (src) + 1, true, gc); - char *dest = ret; - char c; + char *ret = (char *) gc_malloc(strlen(src) + 1, true, gc); + char *dest = ret; + char c; - do + do { - c = *src++; - if (c == from) - c = to; - *dest++ = c; + c = *src++; + if (c == from) + { + c = to; + } + *dest++ = c; } - while (c); - return ret; + while (c); + return ret; } #ifdef ENABLE_CRYPTO static uint8_t * parse_hash_fingerprint(const char *str, int nbytes, int msglevel, struct gc_arena *gc) { - int i; - const char *cp = str; - uint8_t *ret = (uint8_t *) gc_malloc (nbytes, true, gc); - char term = 1; - int byte; - char bs[3]; - - for (i = 0; i < nbytes; ++i) - { - if (strlen(cp) < 2) - msg (msglevel, "format error in hash fingerprint: %s", str); - bs[0] = *cp++; - bs[1] = *cp++; - bs[2] = 0; - byte = 0; - if (sscanf(bs, "%x", &byte) != 1) - msg (msglevel, "format error in hash fingerprint hex byte: %s", str); - ret[i] = (uint8_t)byte; - term = *cp++; - if (term != ':' && term != 0) - msg (msglevel, "format error in hash fingerprint delimiter: %s", str); - if (term == 0) - break; - } - if (term != 0 || i != nbytes-1) - msg (msglevel, "hash fingerprint is different length than expected (%d bytes): %s", nbytes, str); - return ret; + int i; + const char *cp = str; + uint8_t *ret = (uint8_t *) gc_malloc(nbytes, true, gc); + char term = 1; + int byte; + char bs[3]; + + for (i = 0; i < nbytes; ++i) + { + if (strlen(cp) < 2) + { + msg(msglevel, "format error in hash fingerprint: %s", str); + } + bs[0] = *cp++; + bs[1] = *cp++; + bs[2] = 0; + byte = 0; + if (sscanf(bs, "%x", &byte) != 1) + { + msg(msglevel, "format error in hash fingerprint hex byte: %s", str); + } + ret[i] = (uint8_t)byte; + term = *cp++; + if (term != ':' && term != 0) + { + msg(msglevel, "format error in hash fingerprint delimiter: %s", str); + } + if (term == 0) + { + break; + } + } + if (term != 0 || i != nbytes-1) + { + msg(msglevel, "hash fingerprint is different length than expected (%d bytes): %s", nbytes, str); + } + return ret; } -#endif +#endif /* ifdef ENABLE_CRYPTO */ #ifdef _WIN32 #ifndef ENABLE_SMALL static void -show_dhcp_option_addrs (const char *name, const in_addr_t *array, int len) +show_dhcp_option_addrs(const char *name, const in_addr_t *array, int len) { - struct gc_arena gc = gc_new (); - int i; - for (i = 0; i < len; ++i) + struct gc_arena gc = gc_new(); + int i; + for (i = 0; i < len; ++i) { - msg (D_SHOW_PARMS, " %s[%d] = %s", - name, - i, - print_in_addr_t (array[i], 0, &gc)); + msg(D_SHOW_PARMS, " %s[%d] = %s", + name, + i, + print_in_addr_t(array[i], 0, &gc)); } - gc_free (&gc); + gc_free(&gc); } static void -show_tuntap_options (const struct tuntap_options *o) +show_tuntap_options(const struct tuntap_options *o) { - SHOW_BOOL (ip_win32_defined); - SHOW_INT (ip_win32_type); - SHOW_INT (dhcp_masq_offset); - SHOW_INT (dhcp_lease_time); - SHOW_INT (tap_sleep); - SHOW_BOOL (dhcp_options); - SHOW_BOOL (dhcp_renew); - SHOW_BOOL (dhcp_pre_release); - SHOW_BOOL (dhcp_release); - SHOW_STR (domain); - SHOW_STR (netbios_scope); - SHOW_INT (netbios_node_type); - SHOW_BOOL (disable_nbt); - - show_dhcp_option_addrs ("DNS", o->dns, o->dns_len); - show_dhcp_option_addrs ("WINS", o->wins, o->wins_len); - show_dhcp_option_addrs ("NTP", o->ntp, o->ntp_len); - show_dhcp_option_addrs ("NBDD", o->nbdd, o->nbdd_len); + SHOW_BOOL(ip_win32_defined); + SHOW_INT(ip_win32_type); + SHOW_INT(dhcp_masq_offset); + SHOW_INT(dhcp_lease_time); + SHOW_INT(tap_sleep); + SHOW_BOOL(dhcp_options); + SHOW_BOOL(dhcp_renew); + SHOW_BOOL(dhcp_pre_release); + SHOW_BOOL(dhcp_release); + SHOW_STR(domain); + SHOW_STR(netbios_scope); + SHOW_INT(netbios_node_type); + SHOW_BOOL(disable_nbt); + + show_dhcp_option_addrs("DNS", o->dns, o->dns_len); + show_dhcp_option_addrs("WINS", o->wins, o->wins_len); + show_dhcp_option_addrs("NTP", o->ntp, o->ntp_len); + show_dhcp_option_addrs("NBDD", o->nbdd, o->nbdd_len); } -#endif -#endif +#endif /* ifndef ENABLE_SMALL */ +#endif /* ifdef _WIN32 */ #if defined(_WIN32) || defined(TARGET_ANDROID) static void -dhcp_option_address_parse (const char *name, const char *parm, in_addr_t *array, int *len, int msglevel) +dhcp_option_address_parse(const char *name, const char *parm, in_addr_t *array, int *len, int msglevel) { - if (*len >= N_DHCP_ADDR) - { - msg (msglevel, "--dhcp-option %s: maximum of %d %s servers can be specified", - name, - N_DHCP_ADDR, - name); - } - else - { - if (ip_addr_dotted_quad_safe (parm)) /* FQDN -- IP address only */ - { - bool error = false; - const in_addr_t addr = get_ip_addr (parm, msglevel, &error); - if (!error) - array[(*len)++] = addr; - } - else - { - msg (msglevel, "dhcp-option parameter %s '%s' must be an IP address", name, parm); - } + if (*len >= N_DHCP_ADDR) + { + msg(msglevel, "--dhcp-option %s: maximum of %d %s servers can be specified", + name, + N_DHCP_ADDR, + name); + } + else + { + if (ip_addr_dotted_quad_safe(parm)) /* FQDN -- IP address only */ + { + bool error = false; + const in_addr_t addr = get_ip_addr(parm, msglevel, &error); + if (!error) + { + array[(*len)++] = addr; + } + } + else + { + msg(msglevel, "dhcp-option parameter %s '%s' must be an IP address", name, parm); + } } } -#endif +#endif /* if defined(_WIN32) || defined(TARGET_ANDROID) */ #if P2MP #ifndef ENABLE_SMALL static void -show_p2mp_parms (const struct options *o) +show_p2mp_parms(const struct options *o) { - struct gc_arena gc = gc_new (); + struct gc_arena gc = gc_new(); #if P2MP_SERVER - msg (D_SHOW_PARMS, " server_network = %s", print_in_addr_t (o->server_network, 0, &gc)); - msg (D_SHOW_PARMS, " server_netmask = %s", print_in_addr_t (o->server_netmask, 0, &gc)); - msg (D_SHOW_PARMS, " server_network_ipv6 = %s", print_in6_addr (o->server_network_ipv6, 0, &gc) ); - SHOW_INT (server_netbits_ipv6); - msg (D_SHOW_PARMS, " server_bridge_ip = %s", print_in_addr_t (o->server_bridge_ip, 0, &gc)); - msg (D_SHOW_PARMS, " server_bridge_netmask = %s", print_in_addr_t (o->server_bridge_netmask, 0, &gc)); - msg (D_SHOW_PARMS, " server_bridge_pool_start = %s", print_in_addr_t (o->server_bridge_pool_start, 0, &gc)); - msg (D_SHOW_PARMS, " server_bridge_pool_end = %s", print_in_addr_t (o->server_bridge_pool_end, 0, &gc)); - if (o->push_list.head) - { - const struct push_entry *e = o->push_list.head; - while (e) - { - if (e->enable) - msg (D_SHOW_PARMS, " push_entry = '%s'", e->option); - e = e->next; - } - } - SHOW_BOOL (ifconfig_pool_defined); - msg (D_SHOW_PARMS, " ifconfig_pool_start = %s", print_in_addr_t (o->ifconfig_pool_start, 0, &gc)); - msg (D_SHOW_PARMS, " ifconfig_pool_end = %s", print_in_addr_t (o->ifconfig_pool_end, 0, &gc)); - msg (D_SHOW_PARMS, " ifconfig_pool_netmask = %s", print_in_addr_t (o->ifconfig_pool_netmask, 0, &gc)); - SHOW_STR (ifconfig_pool_persist_filename); - SHOW_INT (ifconfig_pool_persist_refresh_freq); - SHOW_BOOL (ifconfig_ipv6_pool_defined); - msg (D_SHOW_PARMS, " ifconfig_ipv6_pool_base = %s", print_in6_addr (o->ifconfig_ipv6_pool_base, 0, &gc)); - SHOW_INT (ifconfig_ipv6_pool_netbits); - SHOW_INT (n_bcast_buf); - SHOW_INT (tcp_queue_limit); - SHOW_INT (real_hash_size); - SHOW_INT (virtual_hash_size); - SHOW_STR (client_connect_script); - SHOW_STR (learn_address_script); - SHOW_STR (client_disconnect_script); - SHOW_STR (client_config_dir); - SHOW_BOOL (ccd_exclusive); - SHOW_STR (tmp_dir); - SHOW_BOOL (push_ifconfig_defined); - msg (D_SHOW_PARMS, " push_ifconfig_local = %s", print_in_addr_t (o->push_ifconfig_local, 0, &gc)); - msg (D_SHOW_PARMS, " push_ifconfig_remote_netmask = %s", print_in_addr_t (o->push_ifconfig_remote_netmask, 0, &gc)); - SHOW_BOOL (push_ifconfig_ipv6_defined); - msg (D_SHOW_PARMS, " push_ifconfig_ipv6_local = %s/%d", print_in6_addr (o->push_ifconfig_ipv6_local, 0, &gc), o->push_ifconfig_ipv6_netbits ); - msg (D_SHOW_PARMS, " push_ifconfig_ipv6_remote = %s", print_in6_addr (o->push_ifconfig_ipv6_remote, 0, &gc)); - SHOW_BOOL (enable_c2c); - SHOW_BOOL (duplicate_cn); - SHOW_INT (cf_max); - SHOW_INT (cf_per); - SHOW_INT (max_clients); - SHOW_INT (max_routes_per_client); - SHOW_STR (auth_user_pass_verify_script); - SHOW_BOOL (auth_user_pass_verify_script_via_file); - SHOW_BOOL (auth_token_generate); - SHOW_INT (auth_token_lifetime); + msg(D_SHOW_PARMS, " server_network = %s", print_in_addr_t(o->server_network, 0, &gc)); + msg(D_SHOW_PARMS, " server_netmask = %s", print_in_addr_t(o->server_netmask, 0, &gc)); + msg(D_SHOW_PARMS, " server_network_ipv6 = %s", print_in6_addr(o->server_network_ipv6, 0, &gc) ); + SHOW_INT(server_netbits_ipv6); + msg(D_SHOW_PARMS, " server_bridge_ip = %s", print_in_addr_t(o->server_bridge_ip, 0, &gc)); + msg(D_SHOW_PARMS, " server_bridge_netmask = %s", print_in_addr_t(o->server_bridge_netmask, 0, &gc)); + msg(D_SHOW_PARMS, " server_bridge_pool_start = %s", print_in_addr_t(o->server_bridge_pool_start, 0, &gc)); + msg(D_SHOW_PARMS, " server_bridge_pool_end = %s", print_in_addr_t(o->server_bridge_pool_end, 0, &gc)); + if (o->push_list.head) + { + const struct push_entry *e = o->push_list.head; + while (e) + { + if (e->enable) + { + msg(D_SHOW_PARMS, " push_entry = '%s'", e->option); + } + e = e->next; + } + } + SHOW_BOOL(ifconfig_pool_defined); + msg(D_SHOW_PARMS, " ifconfig_pool_start = %s", print_in_addr_t(o->ifconfig_pool_start, 0, &gc)); + msg(D_SHOW_PARMS, " ifconfig_pool_end = %s", print_in_addr_t(o->ifconfig_pool_end, 0, &gc)); + msg(D_SHOW_PARMS, " ifconfig_pool_netmask = %s", print_in_addr_t(o->ifconfig_pool_netmask, 0, &gc)); + SHOW_STR(ifconfig_pool_persist_filename); + SHOW_INT(ifconfig_pool_persist_refresh_freq); + SHOW_BOOL(ifconfig_ipv6_pool_defined); + msg(D_SHOW_PARMS, " ifconfig_ipv6_pool_base = %s", print_in6_addr(o->ifconfig_ipv6_pool_base, 0, &gc)); + SHOW_INT(ifconfig_ipv6_pool_netbits); + SHOW_INT(n_bcast_buf); + SHOW_INT(tcp_queue_limit); + SHOW_INT(real_hash_size); + SHOW_INT(virtual_hash_size); + SHOW_STR(client_connect_script); + SHOW_STR(learn_address_script); + SHOW_STR(client_disconnect_script); + SHOW_STR(client_config_dir); + SHOW_BOOL(ccd_exclusive); + SHOW_STR(tmp_dir); + SHOW_BOOL(push_ifconfig_defined); + msg(D_SHOW_PARMS, " push_ifconfig_local = %s", print_in_addr_t(o->push_ifconfig_local, 0, &gc)); + msg(D_SHOW_PARMS, " push_ifconfig_remote_netmask = %s", print_in_addr_t(o->push_ifconfig_remote_netmask, 0, &gc)); + SHOW_BOOL(push_ifconfig_ipv6_defined); + msg(D_SHOW_PARMS, " push_ifconfig_ipv6_local = %s/%d", print_in6_addr(o->push_ifconfig_ipv6_local, 0, &gc), o->push_ifconfig_ipv6_netbits ); + msg(D_SHOW_PARMS, " push_ifconfig_ipv6_remote = %s", print_in6_addr(o->push_ifconfig_ipv6_remote, 0, &gc)); + SHOW_BOOL(enable_c2c); + SHOW_BOOL(duplicate_cn); + SHOW_INT(cf_max); + SHOW_INT(cf_per); + SHOW_INT(max_clients); + SHOW_INT(max_routes_per_client); + SHOW_STR(auth_user_pass_verify_script); + SHOW_BOOL(auth_user_pass_verify_script_via_file); + SHOW_BOOL(auth_token_generate); + SHOW_INT(auth_token_lifetime); #if PORT_SHARE - SHOW_STR (port_share_host); - SHOW_STR (port_share_port); + SHOW_STR(port_share_host); + SHOW_STR(port_share_port); #endif #endif /* P2MP_SERVER */ - SHOW_BOOL (client); - SHOW_BOOL (pull); - SHOW_STR (auth_user_pass_file); + SHOW_BOOL(client); + SHOW_BOOL(pull); + SHOW_STR(auth_user_pass_file); - gc_free (&gc); + gc_free(&gc); } #endif /* ! ENABLE_SMALL */ @@ -1305,461 +1343,485 @@ show_p2mp_parms (const struct options *o) #if P2MP_SERVER static void -option_iroute (struct options *o, - const char *network_str, - const char *netmask_str, - int msglevel) +option_iroute(struct options *o, + const char *network_str, + const char *netmask_str, + int msglevel) { - struct iroute *ir; + struct iroute *ir; - ALLOC_OBJ_GC (ir, struct iroute, &o->gc); - ir->network = getaddr (GETADDR_HOST_ORDER, network_str, 0, NULL, NULL); - ir->netbits = -1; + ALLOC_OBJ_GC(ir, struct iroute, &o->gc); + ir->network = getaddr(GETADDR_HOST_ORDER, network_str, 0, NULL, NULL); + ir->netbits = -1; - if (netmask_str) + if (netmask_str) { - const in_addr_t netmask = getaddr (GETADDR_HOST_ORDER, netmask_str, 0, NULL, NULL); - if (!netmask_to_netbits (ir->network, netmask, &ir->netbits)) - { - msg (msglevel, "in --iroute %s %s : Bad network/subnet specification", - network_str, - netmask_str); - return; - } + const in_addr_t netmask = getaddr(GETADDR_HOST_ORDER, netmask_str, 0, NULL, NULL); + if (!netmask_to_netbits(ir->network, netmask, &ir->netbits)) + { + msg(msglevel, "in --iroute %s %s : Bad network/subnet specification", + network_str, + netmask_str); + return; + } } - ir->next = o->iroutes; - o->iroutes = ir; + ir->next = o->iroutes; + o->iroutes = ir; } static void -option_iroute_ipv6 (struct options *o, - const char *prefix_str, - int msglevel) +option_iroute_ipv6(struct options *o, + const char *prefix_str, + int msglevel) { - struct iroute_ipv6 *ir; + struct iroute_ipv6 *ir; - ALLOC_OBJ_GC (ir, struct iroute_ipv6, &o->gc); + ALLOC_OBJ_GC(ir, struct iroute_ipv6, &o->gc); - if ( !get_ipv6_addr (prefix_str, &ir->network, &ir->netbits, msglevel )) + if (!get_ipv6_addr(prefix_str, &ir->network, &ir->netbits, msglevel )) { - msg (msglevel, "in --iroute-ipv6 %s: Bad IPv6 prefix specification", - prefix_str); - return; + msg(msglevel, "in --iroute-ipv6 %s: Bad IPv6 prefix specification", + prefix_str); + return; } - ir->next = o->iroutes_ipv6; - o->iroutes_ipv6 = ir; + ir->next = o->iroutes_ipv6; + o->iroutes_ipv6 = ir; } #endif /* P2MP_SERVER */ #endif /* P2MP */ #ifndef ENABLE_SMALL static void -show_http_proxy_options (const struct http_proxy_options *o) +show_http_proxy_options(const struct http_proxy_options *o) { - int i; - msg (D_SHOW_PARMS, "BEGIN http_proxy"); - SHOW_STR (server); - SHOW_STR (port); - SHOW_STR (auth_method_string); - SHOW_STR (auth_file); - SHOW_STR (http_version); - SHOW_STR (user_agent); - for (i=0; i < MAX_CUSTOM_HTTP_HEADER && o->custom_headers[i].name;i++) - { - if (o->custom_headers[i].content) - msg (D_SHOW_PARMS, " custom_header[%d] = %s: %s", i, - o->custom_headers[i].name, o->custom_headers[i].content); - else - msg (D_SHOW_PARMS, " custom_header[%d] = %s", i, - o->custom_headers[i].name); - } - msg (D_SHOW_PARMS, "END http_proxy"); + int i; + msg(D_SHOW_PARMS, "BEGIN http_proxy"); + SHOW_STR(server); + SHOW_STR(port); + SHOW_STR(auth_method_string); + SHOW_STR(auth_file); + SHOW_STR(http_version); + SHOW_STR(user_agent); + for (i = 0; i < MAX_CUSTOM_HTTP_HEADER && o->custom_headers[i].name; i++) + { + if (o->custom_headers[i].content) + { + msg(D_SHOW_PARMS, " custom_header[%d] = %s: %s", i, + o->custom_headers[i].name, o->custom_headers[i].content); + } + else + { + msg(D_SHOW_PARMS, " custom_header[%d] = %s", i, + o->custom_headers[i].name); + } + } + msg(D_SHOW_PARMS, "END http_proxy"); } -#endif +#endif /* ifndef ENABLE_SMALL */ void -options_detach (struct options *o) +options_detach(struct options *o) { - gc_detach (&o->gc); - o->routes = NULL; - o->client_nat = NULL; + gc_detach(&o->gc); + o->routes = NULL; + o->client_nat = NULL; #if P2MP_SERVER - clone_push_list(o); + clone_push_list(o); #endif } void -rol_check_alloc (struct options *options) +rol_check_alloc(struct options *options) { - if (!options->routes) - options->routes = new_route_option_list (&options->gc); + if (!options->routes) + { + options->routes = new_route_option_list(&options->gc); + } } void -rol6_check_alloc (struct options *options) +rol6_check_alloc(struct options *options) { - if (!options->routes_ipv6) - options->routes_ipv6 = new_route_ipv6_option_list (&options->gc); + if (!options->routes_ipv6) + { + options->routes_ipv6 = new_route_ipv6_option_list(&options->gc); + } } static void -cnol_check_alloc (struct options *options) +cnol_check_alloc(struct options *options) { - if (!options->client_nat) - options->client_nat = new_client_nat_list (&options->gc); + if (!options->client_nat) + { + options->client_nat = new_client_nat_list(&options->gc); + } } #ifndef ENABLE_SMALL static void -show_connection_entry (const struct connection_entry *o) +show_connection_entry(const struct connection_entry *o) { - msg (D_SHOW_PARMS, " proto = %s", proto2ascii (o->proto, o->af, false)); - SHOW_STR (local); - SHOW_STR (local_port); - SHOW_STR (remote); - SHOW_STR (remote_port); - SHOW_BOOL (remote_float); - SHOW_BOOL (bind_defined); - SHOW_BOOL (bind_local); - SHOW_BOOL (bind_ipv6_only); - SHOW_INT (connect_retry_seconds); - SHOW_INT (connect_timeout); - - if (o->http_proxy_options) - show_http_proxy_options (o->http_proxy_options); - SHOW_STR (socks_proxy_server); - SHOW_STR (socks_proxy_port); - SHOW_INT (tun_mtu); - SHOW_BOOL (tun_mtu_defined); - SHOW_INT (link_mtu); - SHOW_BOOL (link_mtu_defined); - SHOW_INT (tun_mtu_extra); - SHOW_BOOL (tun_mtu_extra_defined); - - SHOW_INT (mtu_discover_type); + msg(D_SHOW_PARMS, " proto = %s", proto2ascii(o->proto, o->af, false)); + SHOW_STR(local); + SHOW_STR(local_port); + SHOW_STR(remote); + SHOW_STR(remote_port); + SHOW_BOOL(remote_float); + SHOW_BOOL(bind_defined); + SHOW_BOOL(bind_local); + SHOW_BOOL(bind_ipv6_only); + SHOW_INT(connect_retry_seconds); + SHOW_INT(connect_timeout); + + if (o->http_proxy_options) + { + show_http_proxy_options(o->http_proxy_options); + } + SHOW_STR(socks_proxy_server); + SHOW_STR(socks_proxy_port); + SHOW_INT(tun_mtu); + SHOW_BOOL(tun_mtu_defined); + SHOW_INT(link_mtu); + SHOW_BOOL(link_mtu_defined); + SHOW_INT(tun_mtu_extra); + SHOW_BOOL(tun_mtu_extra_defined); + + SHOW_INT(mtu_discover_type); #ifdef ENABLE_FRAGMENT - SHOW_INT (fragment); + SHOW_INT(fragment); #endif - SHOW_INT (mssfix); + SHOW_INT(mssfix); #ifdef ENABLE_OCC - SHOW_INT (explicit_exit_notification); + SHOW_INT(explicit_exit_notification); #endif } static void -show_connection_entries (const struct options *o) +show_connection_entries(const struct options *o) { - if (o->connection_list) - { - const struct connection_list *l = o->connection_list; - int i; - for (i = 0; i < l->len; ++i) - { - msg (D_SHOW_PARMS, "Connection profiles [%d]:", i); - show_connection_entry (l->array[i]); - } - } - else - { - msg (D_SHOW_PARMS, "Connection profiles [default]:"); - show_connection_entry (&o->ce); - } - msg (D_SHOW_PARMS, "Connection profiles END"); + if (o->connection_list) + { + const struct connection_list *l = o->connection_list; + int i; + for (i = 0; i < l->len; ++i) + { + msg(D_SHOW_PARMS, "Connection profiles [%d]:", i); + show_connection_entry(l->array[i]); + } + } + else + { + msg(D_SHOW_PARMS, "Connection profiles [default]:"); + show_connection_entry(&o->ce); + } + msg(D_SHOW_PARMS, "Connection profiles END"); } static void -show_pull_filter_list (const struct pull_filter_list *l) +show_pull_filter_list(const struct pull_filter_list *l) { - struct pull_filter *f; - if (!l) - return; + struct pull_filter *f; + if (!l) + { + return; + } - msg (D_SHOW_PARMS, " Pull filters:"); - for (f = l->head; f; f = f->next) + msg(D_SHOW_PARMS, " Pull filters:"); + for (f = l->head; f; f = f->next) { - msg (D_SHOW_PARMS, " %s \"%s\"", pull_filter_type_name(f->type), f->pattern); + msg(D_SHOW_PARMS, " %s \"%s\"", pull_filter_type_name(f->type), f->pattern); } } -#endif +#endif /* ifndef ENABLE_SMALL */ void -show_settings (const struct options *o) +show_settings(const struct options *o) { #ifndef ENABLE_SMALL - msg (D_SHOW_PARMS, "Current Parameter Settings:"); + msg(D_SHOW_PARMS, "Current Parameter Settings:"); - SHOW_STR (config); - - SHOW_INT (mode); + SHOW_STR(config); + + SHOW_INT(mode); #ifdef ENABLE_FEATURE_TUN_PERSIST - SHOW_BOOL (persist_config); - SHOW_INT (persist_mode); + SHOW_BOOL(persist_config); + SHOW_INT(persist_mode); #endif #ifdef ENABLE_CRYPTO - SHOW_BOOL (show_ciphers); - SHOW_BOOL (show_digests); - SHOW_BOOL (show_engines); - SHOW_BOOL (genkey); - SHOW_STR (key_pass_file); - SHOW_BOOL (show_tls_ciphers); -#endif - - SHOW_INT (connect_retry_max); - show_connection_entries (o); - - SHOW_BOOL (remote_random); - - SHOW_STR (ipchange); - SHOW_STR (dev); - SHOW_STR (dev_type); - SHOW_STR (dev_node); - SHOW_STR (lladdr); - SHOW_INT (topology); - SHOW_STR (ifconfig_local); - SHOW_STR (ifconfig_remote_netmask); - SHOW_BOOL (ifconfig_noexec); - SHOW_BOOL (ifconfig_nowarn); - SHOW_STR (ifconfig_ipv6_local); - SHOW_INT (ifconfig_ipv6_netbits); - SHOW_STR (ifconfig_ipv6_remote); + SHOW_BOOL(show_ciphers); + SHOW_BOOL(show_digests); + SHOW_BOOL(show_engines); + SHOW_BOOL(genkey); + SHOW_STR(key_pass_file); + SHOW_BOOL(show_tls_ciphers); +#endif + + SHOW_INT(connect_retry_max); + show_connection_entries(o); + + SHOW_BOOL(remote_random); + + SHOW_STR(ipchange); + SHOW_STR(dev); + SHOW_STR(dev_type); + SHOW_STR(dev_node); + SHOW_STR(lladdr); + SHOW_INT(topology); + SHOW_STR(ifconfig_local); + SHOW_STR(ifconfig_remote_netmask); + SHOW_BOOL(ifconfig_noexec); + SHOW_BOOL(ifconfig_nowarn); + SHOW_STR(ifconfig_ipv6_local); + SHOW_INT(ifconfig_ipv6_netbits); + SHOW_STR(ifconfig_ipv6_remote); #ifdef ENABLE_FEATURE_SHAPER - SHOW_INT (shaper); + SHOW_INT(shaper); #endif #ifdef ENABLE_OCC - SHOW_INT (mtu_test); + SHOW_INT(mtu_test); #endif - SHOW_BOOL (mlock); + SHOW_BOOL(mlock); - SHOW_INT (keepalive_ping); - SHOW_INT (keepalive_timeout); - SHOW_INT (inactivity_timeout); - SHOW_INT (ping_send_timeout); - SHOW_INT (ping_rec_timeout); - SHOW_INT (ping_rec_timeout_action); - SHOW_BOOL (ping_timer_remote); - SHOW_INT (remap_sigusr1); - SHOW_BOOL (persist_tun); - SHOW_BOOL (persist_local_ip); - SHOW_BOOL (persist_remote_ip); - SHOW_BOOL (persist_key); + SHOW_INT(keepalive_ping); + SHOW_INT(keepalive_timeout); + SHOW_INT(inactivity_timeout); + SHOW_INT(ping_send_timeout); + SHOW_INT(ping_rec_timeout); + SHOW_INT(ping_rec_timeout_action); + SHOW_BOOL(ping_timer_remote); + SHOW_INT(remap_sigusr1); + SHOW_BOOL(persist_tun); + SHOW_BOOL(persist_local_ip); + SHOW_BOOL(persist_remote_ip); + SHOW_BOOL(persist_key); #if PASSTOS_CAPABILITY - SHOW_BOOL (passtos); + SHOW_BOOL(passtos); #endif - SHOW_INT (resolve_retry_seconds); - SHOW_BOOL (resolve_in_advance); + SHOW_INT(resolve_retry_seconds); + SHOW_BOOL(resolve_in_advance); - SHOW_STR (username); - SHOW_STR (groupname); - SHOW_STR (chroot_dir); - SHOW_STR (cd_dir); + SHOW_STR(username); + SHOW_STR(groupname); + SHOW_STR(chroot_dir); + SHOW_STR(cd_dir); #ifdef ENABLE_SELINUX - SHOW_STR (selinux_context); -#endif - SHOW_STR (writepid); - SHOW_STR (up_script); - SHOW_STR (down_script); - SHOW_BOOL (down_pre); - SHOW_BOOL (up_restart); - SHOW_BOOL (up_delay); - SHOW_BOOL (daemon); - SHOW_INT (inetd); - SHOW_BOOL (log); - SHOW_BOOL (suppress_timestamps); - SHOW_BOOL (machine_readable_output); - SHOW_INT (nice); - SHOW_INT (verbosity); - SHOW_INT (mute); + SHOW_STR(selinux_context); +#endif + SHOW_STR(writepid); + SHOW_STR(up_script); + SHOW_STR(down_script); + SHOW_BOOL(down_pre); + SHOW_BOOL(up_restart); + SHOW_BOOL(up_delay); + SHOW_BOOL(daemon); + SHOW_INT(inetd); + SHOW_BOOL(log); + SHOW_BOOL(suppress_timestamps); + SHOW_BOOL(machine_readable_output); + SHOW_INT(nice); + SHOW_INT(verbosity); + SHOW_INT(mute); #ifdef ENABLE_DEBUG - SHOW_INT (gremlin); + SHOW_INT(gremlin); #endif - SHOW_STR (status_file); - SHOW_INT (status_file_version); - SHOW_INT (status_file_update_freq); + SHOW_STR(status_file); + SHOW_INT(status_file_version); + SHOW_INT(status_file_update_freq); #ifdef ENABLE_OCC - SHOW_BOOL (occ); + SHOW_BOOL(occ); #endif - SHOW_INT (rcvbuf); - SHOW_INT (sndbuf); + SHOW_INT(rcvbuf); + SHOW_INT(sndbuf); #if defined(TARGET_LINUX) && HAVE_DECL_SO_MARK - SHOW_INT (mark); + SHOW_INT(mark); #endif - SHOW_INT (sockflags); + SHOW_INT(sockflags); - SHOW_BOOL (fast_io); + SHOW_BOOL(fast_io); #ifdef USE_COMP - SHOW_INT (comp.alg); - SHOW_INT (comp.flags); + SHOW_INT(comp.alg); + SHOW_INT(comp.flags); #endif - SHOW_STR (route_script); - SHOW_STR (route_default_gateway); - SHOW_INT (route_default_metric); - SHOW_BOOL (route_noexec); - SHOW_INT (route_delay); - SHOW_INT (route_delay_window); - SHOW_BOOL (route_delay_defined); - SHOW_BOOL (route_nopull); - SHOW_BOOL (route_gateway_via_dhcp); - SHOW_BOOL (allow_pull_fqdn); - show_pull_filter_list (o->pull_filter_list); + SHOW_STR(route_script); + SHOW_STR(route_default_gateway); + SHOW_INT(route_default_metric); + SHOW_BOOL(route_noexec); + SHOW_INT(route_delay); + SHOW_INT(route_delay_window); + SHOW_BOOL(route_delay_defined); + SHOW_BOOL(route_nopull); + SHOW_BOOL(route_gateway_via_dhcp); + SHOW_BOOL(allow_pull_fqdn); + show_pull_filter_list(o->pull_filter_list); - if (o->routes) - print_route_options (o->routes, D_SHOW_PARMS); + if (o->routes) + { + print_route_options(o->routes, D_SHOW_PARMS); + } - if (o->client_nat) - print_client_nat_list(o->client_nat, D_SHOW_PARMS); + if (o->client_nat) + { + print_client_nat_list(o->client_nat, D_SHOW_PARMS); + } #ifdef ENABLE_MANAGEMENT - SHOW_STR (management_addr); - SHOW_STR (management_port); - SHOW_STR (management_user_pass); - SHOW_INT (management_log_history_cache); - SHOW_INT (management_echo_buffer_size); - SHOW_STR (management_write_peer_info_file); - SHOW_STR (management_client_user); - SHOW_STR (management_client_group); - SHOW_INT (management_flags); + SHOW_STR(management_addr); + SHOW_STR(management_port); + SHOW_STR(management_user_pass); + SHOW_INT(management_log_history_cache); + SHOW_INT(management_echo_buffer_size); + SHOW_STR(management_write_peer_info_file); + SHOW_STR(management_client_user); + SHOW_STR(management_client_group); + SHOW_INT(management_flags); #endif #ifdef ENABLE_PLUGIN - if (o->plugin_list) - plugin_option_list_print (o->plugin_list, D_SHOW_PARMS); + if (o->plugin_list) + { + plugin_option_list_print(o->plugin_list, D_SHOW_PARMS); + } #endif #ifdef ENABLE_CRYPTO - SHOW_STR (shared_secret_file); - SHOW_INT (key_direction); - SHOW_STR (ciphername); - SHOW_BOOL (ncp_enabled); - SHOW_STR (ncp_ciphers); - SHOW_STR (authname); - SHOW_STR (prng_hash); - SHOW_INT (prng_nonce_secret_len); - SHOW_INT (keysize); + SHOW_STR(shared_secret_file); + SHOW_INT(key_direction); + SHOW_STR(ciphername); + SHOW_BOOL(ncp_enabled); + SHOW_STR(ncp_ciphers); + SHOW_STR(authname); + SHOW_STR(prng_hash); + SHOW_INT(prng_nonce_secret_len); + SHOW_INT(keysize); #ifndef ENABLE_CRYPTO_MBEDTLS - SHOW_BOOL (engine); + SHOW_BOOL(engine); #endif /* ENABLE_CRYPTO_MBEDTLS */ - SHOW_BOOL (replay); - SHOW_BOOL (mute_replay_warnings); - SHOW_INT (replay_window); - SHOW_INT (replay_time); - SHOW_STR (packet_id_file); - SHOW_BOOL (use_iv); - SHOW_BOOL (test_crypto); + SHOW_BOOL(replay); + SHOW_BOOL(mute_replay_warnings); + SHOW_INT(replay_window); + SHOW_INT(replay_time); + SHOW_STR(packet_id_file); + SHOW_BOOL(use_iv); + SHOW_BOOL(test_crypto); #ifdef ENABLE_PREDICTION_RESISTANCE - SHOW_BOOL (use_prediction_resistance); + SHOW_BOOL(use_prediction_resistance); #endif - SHOW_BOOL (tls_server); - SHOW_BOOL (tls_client); - SHOW_INT (key_method); - SHOW_STR (ca_file); - SHOW_STR (ca_path); - SHOW_STR (dh_file); + SHOW_BOOL(tls_server); + SHOW_BOOL(tls_client); + SHOW_INT(key_method); + SHOW_STR(ca_file); + SHOW_STR(ca_path); + SHOW_STR(dh_file); #ifdef MANAGMENT_EXTERNAL_KEY - if((o->management_flags & MF_EXTERNAL_CERT)) - SHOW_PARM ("cert_file","EXTERNAL_CERT","%s"); - else + if ((o->management_flags & MF_EXTERNAL_CERT)) + { + SHOW_PARM("cert_file","EXTERNAL_CERT","%s"); + } + else #endif - SHOW_STR (cert_file); - SHOW_STR (extra_certs_file); + SHOW_STR(cert_file); + SHOW_STR(extra_certs_file); #ifdef MANAGMENT_EXTERNAL_KEY - if((o->management_flags & MF_EXTERNAL_KEY)) - SHOW_PARM ("priv_key_file","EXTERNAL_PRIVATE_KEY","%s"); - else + if ((o->management_flags & MF_EXTERNAL_KEY)) + { + SHOW_PARM("priv_key_file","EXTERNAL_PRIVATE_KEY","%s"); + } + else #endif - SHOW_STR (priv_key_file); + SHOW_STR(priv_key_file); #ifndef ENABLE_CRYPTO_MBEDTLS - SHOW_STR (pkcs12_file); + SHOW_STR(pkcs12_file); #endif #ifdef ENABLE_CRYPTOAPI - SHOW_STR (cryptoapi_cert); -#endif - SHOW_STR (cipher_list); - SHOW_STR (tls_verify); - SHOW_STR (tls_export_cert); - SHOW_INT (verify_x509_type); - SHOW_STR (verify_x509_name); - SHOW_STR (crl_file); - SHOW_INT (ns_cert_type); - { - int i; - for (i=0;ipkcs11_providers[i] != NULL;i++) - SHOW_PARM (pkcs11_providers, o->pkcs11_providers[i], "%s"); - } - { - int i; - for (i=0;ipkcs11_protected_authentication[i] ? "ENABLED" : "DISABLED", "%s"); - } - { - int i; - for (i=0;ipkcs11_private_mode[i], "%08x"); - } - { - int i; - for (i=0;ipkcs11_cert_private[i] ? "ENABLED" : "DISABLED", "%s"); - } - SHOW_INT (pkcs11_pin_cache_period); - SHOW_STR (pkcs11_id); - SHOW_BOOL (pkcs11_id_management); -#endif /* ENABLE_PKCS11 */ + { + int i; + for (i = 0; ipkcs11_providers[i] != NULL; i++) + SHOW_PARM(pkcs11_providers, o->pkcs11_providers[i], "%s"); + } + { + int i; + for (i = 0; ipkcs11_protected_authentication[i] ? "ENABLED" : "DISABLED", "%s"); + } + { + int i; + for (i = 0; ipkcs11_private_mode[i], "%08x"); + } + { + int i; + for (i = 0; ipkcs11_cert_private[i] ? "ENABLED" : "DISABLED", "%s"); + } + SHOW_INT(pkcs11_pin_cache_period); + SHOW_STR(pkcs11_id); + SHOW_BOOL(pkcs11_id_management); +#endif /* ENABLE_PKCS11 */ #if P2MP - show_p2mp_parms (o); + show_p2mp_parms(o); #endif #ifdef _WIN32 - SHOW_BOOL (show_net_up); - SHOW_INT (route_method); - SHOW_BOOL (block_outside_dns); - show_tuntap_options (&o->tuntap_options); -#endif + SHOW_BOOL(show_net_up); + SHOW_INT(route_method); + SHOW_BOOL(block_outside_dns); + show_tuntap_options(&o->tuntap_options); #endif +#endif /* ifndef ENABLE_SMALL */ } #undef SHOW_PARM @@ -1770,953 +1832,1217 @@ show_settings (const struct options *o) #ifdef ENABLE_MANAGEMENT static struct http_proxy_options * -parse_http_proxy_override (const char *server, - const char *port, - const char *flags, - const int msglevel, - struct gc_arena *gc) +parse_http_proxy_override(const char *server, + const char *port, + const char *flags, + const int msglevel, + struct gc_arena *gc) { - if (server && port) - { - struct http_proxy_options *ho; - ALLOC_OBJ_CLEAR_GC (ho, struct http_proxy_options, gc); - ho->server = string_alloc(server, gc); - ho->port = port; - if (flags && !strcmp(flags, "nct")) - ho->auth_retry = PAR_NCT; - else - ho->auth_retry = PAR_ALL; - ho->http_version = "1.0"; - ho->user_agent = "OpenVPN-Autoproxy/1.0"; - return ho; - } - else - return NULL; + if (server && port) + { + struct http_proxy_options *ho; + ALLOC_OBJ_CLEAR_GC(ho, struct http_proxy_options, gc); + ho->server = string_alloc(server, gc); + ho->port = port; + if (flags && !strcmp(flags, "nct")) + { + ho->auth_retry = PAR_NCT; + } + else + { + ho->auth_retry = PAR_ALL; + } + ho->http_version = "1.0"; + ho->user_agent = "OpenVPN-Autoproxy/1.0"; + return ho; + } + else + { + return NULL; + } } void -options_postprocess_http_proxy_override (struct options *o) +options_postprocess_http_proxy_override(struct options *o) { - const struct connection_list *l = o->connection_list; - int i; - bool succeed = false; - for (i = 0; i < l->len; ++i) + const struct connection_list *l = o->connection_list; + int i; + bool succeed = false; + for (i = 0; i < l->len; ++i) { - struct connection_entry *ce = l->array[i]; - if (ce->proto == PROTO_TCP_CLIENT || ce->proto == PROTO_TCP) + struct connection_entry *ce = l->array[i]; + if (ce->proto == PROTO_TCP_CLIENT || ce->proto == PROTO_TCP) { - ce->http_proxy_options = o->http_proxy_override; - succeed = true; + ce->http_proxy_options = o->http_proxy_override; + succeed = true; } } - if (succeed) + if (succeed) { - for (i = 0; i < l->len; ++i) + for (i = 0; i < l->len; ++i) { - struct connection_entry *ce = l->array[i]; - if (ce->proto == PROTO_UDP) + struct connection_entry *ce = l->array[i]; + if (ce->proto == PROTO_UDP) { - ce->flags |= CE_DISABLED; + ce->flags |= CE_DISABLED; } } } - else + else { - msg (M_WARN, "Note: option http-proxy-override ignored because no TCP-based connection profiles are defined"); + msg(M_WARN, "Note: option http-proxy-override ignored because no TCP-based connection profiles are defined"); } } -#endif +#endif /* ifdef ENABLE_MANAGEMENT */ static struct connection_list * -alloc_connection_list_if_undef (struct options *options) +alloc_connection_list_if_undef(struct options *options) { - if (!options->connection_list) - ALLOC_OBJ_CLEAR_GC (options->connection_list, struct connection_list, &options->gc); - return options->connection_list; + if (!options->connection_list) + { + ALLOC_OBJ_CLEAR_GC(options->connection_list, struct connection_list, &options->gc); + } + return options->connection_list; } static struct connection_entry * -alloc_connection_entry (struct options *options, const int msglevel) +alloc_connection_entry(struct options *options, const int msglevel) { - struct connection_list *l = alloc_connection_list_if_undef (options); - struct connection_entry *e; + struct connection_list *l = alloc_connection_list_if_undef(options); + struct connection_entry *e; - if (l->len >= CONNECTION_LIST_SIZE) + if (l->len >= CONNECTION_LIST_SIZE) { - msg (msglevel, "Maximum number of 'connection' options (%d) exceeded", CONNECTION_LIST_SIZE); - return NULL; + msg(msglevel, "Maximum number of 'connection' options (%d) exceeded", CONNECTION_LIST_SIZE); + return NULL; } - ALLOC_OBJ_GC (e, struct connection_entry, &options->gc); - l->array[l->len++] = e; - return e; + ALLOC_OBJ_GC(e, struct connection_entry, &options->gc); + l->array[l->len++] = e; + return e; } static struct remote_list * -alloc_remote_list_if_undef (struct options *options) +alloc_remote_list_if_undef(struct options *options) { - if (!options->remote_list) - ALLOC_OBJ_CLEAR_GC (options->remote_list, struct remote_list, &options->gc); - return options->remote_list; + if (!options->remote_list) + { + ALLOC_OBJ_CLEAR_GC(options->remote_list, struct remote_list, &options->gc); + } + return options->remote_list; } static struct remote_entry * -alloc_remote_entry (struct options *options, const int msglevel) +alloc_remote_entry(struct options *options, const int msglevel) { - struct remote_list *l = alloc_remote_list_if_undef (options); - struct remote_entry *e; + struct remote_list *l = alloc_remote_list_if_undef(options); + struct remote_entry *e; - if (l->len >= CONNECTION_LIST_SIZE) + if (l->len >= CONNECTION_LIST_SIZE) { - msg (msglevel, "Maximum number of 'remote' options (%d) exceeded", CONNECTION_LIST_SIZE); - return NULL; + msg(msglevel, "Maximum number of 'remote' options (%d) exceeded", CONNECTION_LIST_SIZE); + return NULL; } - ALLOC_OBJ_GC (e, struct remote_entry, &options->gc); - l->array[l->len++] = e; - return e; + ALLOC_OBJ_GC(e, struct remote_entry, &options->gc); + l->array[l->len++] = e; + return e; } static struct pull_filter_list * -alloc_pull_filter_list (struct options *o) +alloc_pull_filter_list(struct options *o) { - if (!o->pull_filter_list) - ALLOC_OBJ_CLEAR_GC (o->pull_filter_list, struct pull_filter_list, &o->gc); - return o->pull_filter_list; + if (!o->pull_filter_list) + { + ALLOC_OBJ_CLEAR_GC(o->pull_filter_list, struct pull_filter_list, &o->gc); + } + return o->pull_filter_list; } static struct pull_filter * -alloc_pull_filter (struct options *o, const int msglevel) +alloc_pull_filter(struct options *o, const int msglevel) { - struct pull_filter_list *l = alloc_pull_filter_list (o); - struct pull_filter *f; + struct pull_filter_list *l = alloc_pull_filter_list(o); + struct pull_filter *f; - ALLOC_OBJ_CLEAR_GC (f, struct pull_filter, &o->gc); - if (l->head) + ALLOC_OBJ_CLEAR_GC(f, struct pull_filter, &o->gc); + if (l->head) { - ASSERT (l->tail); - l->tail->next = f; + ASSERT(l->tail); + l->tail->next = f; } - else + else { - ASSERT (!l->tail); - l->head = f; + ASSERT(!l->tail); + l->head = f; } - l->tail = f; - return f; + l->tail = f; + return f; } void -connection_entry_load_re (struct connection_entry *ce, const struct remote_entry *re) +connection_entry_load_re(struct connection_entry *ce, const struct remote_entry *re) { - if (re->remote) - ce->remote = re->remote; - if (re->remote_port) - ce->remote_port = re->remote_port; - if (re->proto >= 0) - ce->proto = re->proto; - if (re->af > 0) - ce->af = re->af; + if (re->remote) + { + ce->remote = re->remote; + } + if (re->remote_port) + { + ce->remote_port = re->remote_port; + } + if (re->proto >= 0) + { + ce->proto = re->proto; + } + if (re->af > 0) + { + ce->af = re->af; + } } static void -options_postprocess_verify_ce (const struct options *options, const struct connection_entry *ce) +options_postprocess_verify_ce(const struct options *options, const struct connection_entry *ce) { - struct options defaults; - int dev = DEV_TYPE_UNDEF; - bool pull = false; + struct options defaults; + int dev = DEV_TYPE_UNDEF; + bool pull = false; - init_options (&defaults, true); + init_options(&defaults, true); #ifdef ENABLE_CRYPTO - if (options->test_crypto) + if (options->test_crypto) { - notnull (options->shared_secret_file, "key file (--secret)"); + notnull(options->shared_secret_file, "key file (--secret)"); } - else + else #endif - notnull (options->dev, "TUN/TAP device (--dev)"); + notnull(options->dev, "TUN/TAP device (--dev)"); - /* - * Get tun/tap/null device type - */ - dev = dev_type_enum (options->dev, options->dev_type); + /* + * Get tun/tap/null device type + */ + dev = dev_type_enum(options->dev, options->dev_type); - /* - * If "proto tcp" is specified, make sure we know whether it is - * tcp-client or tcp-server. - */ - if (ce->proto == PROTO_TCP) - msg (M_USAGE, "--proto tcp is ambiguous in this context. Please specify --proto tcp-server or --proto tcp-client"); + /* + * If "proto tcp" is specified, make sure we know whether it is + * tcp-client or tcp-server. + */ + if (ce->proto == PROTO_TCP) + { + msg(M_USAGE, "--proto tcp is ambiguous in this context. Please specify --proto tcp-server or --proto tcp-client"); + } - /* - * Sanity check on daemon/inetd modes - */ + /* + * Sanity check on daemon/inetd modes + */ - if (options->daemon && options->inetd) - msg (M_USAGE, "only one of --daemon or --inetd may be specified"); + if (options->daemon && options->inetd) + { + msg(M_USAGE, "only one of --daemon or --inetd may be specified"); + } - if (options->inetd && (ce->local || ce->remote)) - msg (M_USAGE, "--local or --remote cannot be used with --inetd"); + if (options->inetd && (ce->local || ce->remote)) + { + msg(M_USAGE, "--local or --remote cannot be used with --inetd"); + } - if (options->inetd && ce->proto == PROTO_TCP_CLIENT) - msg (M_USAGE, "--proto tcp-client cannot be used with --inetd"); + if (options->inetd && ce->proto == PROTO_TCP_CLIENT) + { + msg(M_USAGE, "--proto tcp-client cannot be used with --inetd"); + } - if (options->inetd == INETD_NOWAIT && ce->proto != PROTO_TCP_SERVER) - msg (M_USAGE, "--inetd nowait can only be used with --proto tcp-server"); + if (options->inetd == INETD_NOWAIT && ce->proto != PROTO_TCP_SERVER) + { + msg(M_USAGE, "--inetd nowait can only be used with --proto tcp-server"); + } - if (options->inetd == INETD_NOWAIT + if (options->inetd == INETD_NOWAIT #ifdef ENABLE_CRYPTO - && !(options->tls_server || options->tls_client) + && !(options->tls_server || options->tls_client) #endif - ) - msg (M_USAGE, "--inetd nowait can only be used in TLS mode"); + ) + { + msg(M_USAGE, "--inetd nowait can only be used in TLS mode"); + } + + if (options->inetd == INETD_NOWAIT && dev != DEV_TYPE_TAP) + { + msg(M_USAGE, "--inetd nowait only makes sense in --dev tap mode"); + } - if (options->inetd == INETD_NOWAIT && dev != DEV_TYPE_TAP) - msg (M_USAGE, "--inetd nowait only makes sense in --dev tap mode"); + if (options->lladdr && dev != DEV_TYPE_TAP) + { + msg(M_USAGE, "--lladdr can only be used in --dev tap mode"); + } - if (options->lladdr && dev != DEV_TYPE_TAP) - msg (M_USAGE, "--lladdr can only be used in --dev tap mode"); - - /* - * Sanity check on MTU parameters - */ - if (options->ce.tun_mtu_defined && options->ce.link_mtu_defined) - msg (M_USAGE, "only one of --tun-mtu or --link-mtu may be defined (note that --ifconfig implies --link-mtu %d)", LINK_MTU_DEFAULT); + /* + * Sanity check on MTU parameters + */ + if (options->ce.tun_mtu_defined && options->ce.link_mtu_defined) + { + msg(M_USAGE, "only one of --tun-mtu or --link-mtu may be defined (note that --ifconfig implies --link-mtu %d)", LINK_MTU_DEFAULT); + } #ifdef ENABLE_OCC - if (!proto_is_udp(ce->proto) && options->mtu_test) - msg (M_USAGE, "--mtu-test only makes sense with --proto udp"); + if (!proto_is_udp(ce->proto) && options->mtu_test) + { + msg(M_USAGE, "--mtu-test only makes sense with --proto udp"); + } #endif - /* will we be pulling options from server? */ + /* will we be pulling options from server? */ #if P2MP - pull = options->pull; + pull = options->pull; #endif - /* - * Sanity check on --local, --remote, and --ifconfig - */ + /* + * Sanity check on --local, --remote, and --ifconfig + */ + + if (proto_is_net(ce->proto) + && string_defined_equal(ce->local, ce->remote) + && string_defined_equal(ce->local_port, ce->remote_port)) + { + msg(M_USAGE, "--remote and --local addresses are the same"); + } - if (proto_is_net(ce->proto) - && string_defined_equal (ce->local, ce->remote) - && string_defined_equal (ce->local_port, ce->remote_port)) - msg (M_USAGE, "--remote and --local addresses are the same"); - - if (string_defined_equal (ce->remote, options->ifconfig_local) - || string_defined_equal (ce->remote, options->ifconfig_remote_netmask)) - msg (M_USAGE, "--local and --remote addresses must be distinct from --ifconfig addresses"); + if (string_defined_equal(ce->remote, options->ifconfig_local) + || string_defined_equal(ce->remote, options->ifconfig_remote_netmask)) + { + msg(M_USAGE, "--local and --remote addresses must be distinct from --ifconfig addresses"); + } - if (string_defined_equal (ce->local, options->ifconfig_local) - || string_defined_equal (ce->local, options->ifconfig_remote_netmask)) - msg (M_USAGE, "--local addresses must be distinct from --ifconfig addresses"); + if (string_defined_equal(ce->local, options->ifconfig_local) + || string_defined_equal(ce->local, options->ifconfig_remote_netmask)) + { + msg(M_USAGE, "--local addresses must be distinct from --ifconfig addresses"); + } - if (string_defined_equal (options->ifconfig_local, options->ifconfig_remote_netmask)) - msg (M_USAGE, "local and remote/netmask --ifconfig addresses must be different"); + if (string_defined_equal(options->ifconfig_local, options->ifconfig_remote_netmask)) + { + msg(M_USAGE, "local and remote/netmask --ifconfig addresses must be different"); + } - if (ce->bind_defined && !ce->bind_local) - msg (M_USAGE, "--bind and --nobind can't be used together"); + if (ce->bind_defined && !ce->bind_local) + { + msg(M_USAGE, "--bind and --nobind can't be used together"); + } - if (ce->local && !ce->bind_local) - msg (M_USAGE, "--local and --nobind don't make sense when used together"); + if (ce->local && !ce->bind_local) + { + msg(M_USAGE, "--local and --nobind don't make sense when used together"); + } - if (ce->local_port_defined && !ce->bind_local) - msg (M_USAGE, "--lport and --nobind don't make sense when used together"); + if (ce->local_port_defined && !ce->bind_local) + { + msg(M_USAGE, "--lport and --nobind don't make sense when used together"); + } - if (!ce->remote && !ce->bind_local) - msg (M_USAGE, "--nobind doesn't make sense unless used with --remote"); + if (!ce->remote && !ce->bind_local) + { + msg(M_USAGE, "--nobind doesn't make sense unless used with --remote"); + } - /* - * Check for consistency of management options - */ + /* + * Check for consistency of management options + */ #ifdef ENABLE_MANAGEMENT - if (!options->management_addr && - (options->management_flags - || options->management_write_peer_info_file - || options->management_log_history_cache != defaults.management_log_history_cache)) - msg (M_USAGE, "--management is not specified, however one or more options which modify the behavior of --management were specified"); + if (!options->management_addr + && (options->management_flags + || options->management_write_peer_info_file + || options->management_log_history_cache != defaults.management_log_history_cache)) + { + msg(M_USAGE, "--management is not specified, however one or more options which modify the behavior of --management were specified"); + } - if ((options->management_client_user || options->management_client_group) - && !(options->management_flags & MF_UNIX_SOCK)) - msg (M_USAGE, "--management-client-(user|group) can only be used on unix domain sockets"); + if ((options->management_client_user || options->management_client_group) + && !(options->management_flags & MF_UNIX_SOCK)) + { + msg(M_USAGE, "--management-client-(user|group) can only be used on unix domain sockets"); + } #endif - /* - * Windows-specific options. - */ + /* + * Windows-specific options. + */ #ifdef _WIN32 - if (dev == DEV_TYPE_TUN && !(pull || (options->ifconfig_local && options->ifconfig_remote_netmask))) - msg (M_USAGE, "On Windows, --ifconfig is required when --dev tun is used"); + if (dev == DEV_TYPE_TUN && !(pull || (options->ifconfig_local && options->ifconfig_remote_netmask))) + { + msg(M_USAGE, "On Windows, --ifconfig is required when --dev tun is used"); + } - if ((options->tuntap_options.ip_win32_defined) - && !(pull || (options->ifconfig_local && options->ifconfig_remote_netmask))) - msg (M_USAGE, "On Windows, --ip-win32 doesn't make sense unless --ifconfig is also used"); + if ((options->tuntap_options.ip_win32_defined) + && !(pull || (options->ifconfig_local && options->ifconfig_remote_netmask))) + { + msg(M_USAGE, "On Windows, --ip-win32 doesn't make sense unless --ifconfig is also used"); + } - if (options->tuntap_options.dhcp_options - && options->tuntap_options.ip_win32_type != IPW32_SET_DHCP_MASQ - && options->tuntap_options.ip_win32_type != IPW32_SET_ADAPTIVE) - msg (M_USAGE, "--dhcp-options requires --ip-win32 dynamic or adaptive"); + if (options->tuntap_options.dhcp_options + && options->tuntap_options.ip_win32_type != IPW32_SET_DHCP_MASQ + && options->tuntap_options.ip_win32_type != IPW32_SET_ADAPTIVE) + { + msg(M_USAGE, "--dhcp-options requires --ip-win32 dynamic or adaptive"); + } #endif - /* - * Check that protocol options make sense. - */ + /* + * Check that protocol options make sense. + */ #ifdef ENABLE_FRAGMENT - if (!proto_is_udp(ce->proto) && ce->fragment) - msg (M_USAGE, "--fragment can only be used with --proto udp"); + if (!proto_is_udp(ce->proto) && ce->fragment) + { + msg(M_USAGE, "--fragment can only be used with --proto udp"); + } #endif #ifdef ENABLE_OCC - if (!proto_is_udp(ce->proto) && ce->explicit_exit_notification) - msg (M_USAGE, "--explicit-exit-notify can only be used with --proto udp"); -#endif - - if (!ce->remote && ce->proto == PROTO_TCP_CLIENT) - msg (M_USAGE, "--remote MUST be used in TCP Client mode"); - - if ((ce->http_proxy_options) && ce->proto != PROTO_TCP_CLIENT) - msg (M_USAGE, "--http-proxy MUST be used in TCP Client mode (i.e. --proto tcp-client)"); - if ((ce->http_proxy_options) && !ce->http_proxy_options->server) - msg (M_USAGE, "--http-proxy not specified but other http proxy options present"); - - if (ce->http_proxy_options && ce->socks_proxy_server) - msg (M_USAGE, "--http-proxy can not be used together with --socks-proxy"); - - if (ce->socks_proxy_server && ce->proto == PROTO_TCP_SERVER) - msg (M_USAGE, "--socks-proxy can not be used in TCP Server mode"); - - if (ce->proto == PROTO_TCP_SERVER && (options->connection_list->len > 1)) - msg (M_USAGE, "TCP server mode allows at most one --remote address"); - -#if P2MP_SERVER - - /* - * Check consistency of --mode server options. - */ - if (options->mode == MODE_SERVER) - { - if (!(dev == DEV_TYPE_TUN || dev == DEV_TYPE_TAP)) - msg (M_USAGE, "--mode server only works with --dev tun or --dev tap"); - if (options->pull) - msg (M_USAGE, "--pull cannot be used with --mode server"); - if (options->pull_filter_list) - msg (M_USAGE, "--pull-filter cannot be used with --mode server"); - if (!(proto_is_udp(ce->proto) || ce->proto == PROTO_TCP_SERVER)) - msg (M_USAGE, "--mode server currently only supports " - "--proto udp or --proto tcp-server or proto tcp6-server"); -#if PORT_SHARE - if ((options->port_share_host || options->port_share_port) && - (ce->proto != PROTO_TCP_SERVER)) - msg (M_USAGE, "--port-share only works in TCP server mode " - "(--proto tcp-server or tcp6-server)"); -#endif - if (!options->tls_server) - msg (M_USAGE, "--mode server requires --tls-server"); - if (ce->remote) - msg (M_USAGE, "--remote cannot be used with --mode server"); - if (!ce->bind_local) - msg (M_USAGE, "--nobind cannot be used with --mode server"); - if (ce->http_proxy_options) - msg (M_USAGE, "--http-proxy cannot be used with --mode server"); - if (ce->socks_proxy_server) - msg (M_USAGE, "--socks-proxy cannot be used with --mode server"); - /* blocks force to have a remote embedded, so we check for the - * --remote and bail out if it is present */ - if (options->connection_list->len >1 || - options->connection_list->array[0]->remote) - msg (M_USAGE, " cannot be used with --mode server"); - - if (options->shaper) - msg (M_USAGE, "--shaper cannot be used with --mode server"); - if (options->inetd) - msg (M_USAGE, "--inetd cannot be used with --mode server"); - if (options->ipchange) - msg (M_USAGE, "--ipchange cannot be used with --mode server (use --client-connect instead)"); - if (!(proto_is_dgram(ce->proto) || ce->proto == PROTO_TCP_SERVER)) - msg (M_USAGE, "--mode server currently only supports " - "--proto udp or --proto tcp-server or --proto tcp6-server"); - if (!proto_is_udp(ce->proto) && (options->cf_max || options->cf_per)) - msg (M_USAGE, "--connect-freq only works with --mode server --proto udp. Try --max-clients instead."); - if (!(dev == DEV_TYPE_TAP || (dev == DEV_TYPE_TUN && options->topology == TOP_SUBNET)) && options->ifconfig_pool_netmask) - msg (M_USAGE, "The third parameter to --ifconfig-pool (netmask) is only valid in --dev tap mode"); - if (options->routes && (options->routes->flags & RG_ENABLE)) - msg (M_USAGE, "--redirect-gateway cannot be used with --mode server (however --push \"redirect-gateway\" is fine)"); - if (options->route_delay_defined) - msg (M_USAGE, "--route-delay cannot be used with --mode server"); - if (options->up_delay) - msg (M_USAGE, "--up-delay cannot be used with --mode server"); - if (!options->ifconfig_pool_defined && options->ifconfig_pool_persist_filename) - msg (M_USAGE, "--ifconfig-pool-persist must be used with --ifconfig-pool"); - if (options->ifconfig_ipv6_pool_defined && !options->ifconfig_ipv6_local ) - msg (M_USAGE, "--ifconfig-ipv6-pool needs --ifconfig-ipv6"); - if (options->allow_recursive_routing) - msg (M_USAGE, "--allow-recursive-routing cannot be used with --mode server"); - if (options->auth_user_pass_file) - msg (M_USAGE, "--auth-user-pass cannot be used with --mode server (it should be used on the client side only)"); - if (options->ccd_exclusive && !options->client_config_dir) - msg (M_USAGE, "--ccd-exclusive must be used with --client-config-dir"); - if (options->key_method != 2) - msg (M_USAGE, "--mode server requires --key-method 2"); - - { - const bool ccnr = (options->auth_user_pass_verify_script - || PLUGIN_OPTION_LIST (options) - || MAN_CLIENT_AUTH_ENABLED (options)); - const char *postfix = "must be used with --management-client-auth, an --auth-user-pass-verify script, or plugin"; - if ((options->ssl_flags & (SSLF_CLIENT_CERT_NOT_REQUIRED|SSLF_CLIENT_CERT_OPTIONAL)) && !ccnr) - msg (M_USAGE, "--verify-client-cert none|optional %s", postfix); - if ((options->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) && !ccnr) - msg (M_USAGE, "--username-as-common-name %s", postfix); - if ((options->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL) && !ccnr) - msg (M_USAGE, "--auth-user-pass-optional %s", postfix); - } - } - else - { - /* - * When not in server mode, err if parameters are - * specified which require --mode server. - */ - if (options->ifconfig_pool_defined || options->ifconfig_pool_persist_filename) - msg (M_USAGE, "--ifconfig-pool/--ifconfig-pool-persist requires --mode server"); - if (options->ifconfig_ipv6_pool_defined) - msg (M_USAGE, "--ifconfig-ipv6-pool requires --mode server"); - if (options->real_hash_size != defaults.real_hash_size - || options->virtual_hash_size != defaults.virtual_hash_size) - msg (M_USAGE, "--hash-size requires --mode server"); - if (options->learn_address_script) - msg (M_USAGE, "--learn-address requires --mode server"); - if (options->client_connect_script) - msg (M_USAGE, "--client-connect requires --mode server"); - if (options->client_disconnect_script) - msg (M_USAGE, "--client-disconnect requires --mode server"); - if (options->client_config_dir || options->ccd_exclusive) - msg (M_USAGE, "--client-config-dir/--ccd-exclusive requires --mode server"); - if (options->enable_c2c) - msg (M_USAGE, "--client-to-client requires --mode server"); - if (options->duplicate_cn) - msg (M_USAGE, "--duplicate-cn requires --mode server"); - if (options->cf_max || options->cf_per) - msg (M_USAGE, "--connect-freq requires --mode server"); - if (options->ssl_flags & (SSLF_CLIENT_CERT_NOT_REQUIRED|SSLF_CLIENT_CERT_OPTIONAL)) - msg (M_USAGE, "--client-cert-not-required and --verify-client-cert require --mode server"); - if (options->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) - msg (M_USAGE, "--username-as-common-name requires --mode server"); - if (options->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL) - msg (M_USAGE, "--auth-user-pass-optional requires --mode server"); - if (options->ssl_flags & SSLF_OPT_VERIFY) - msg (M_USAGE, "--opt-verify requires --mode server"); - if (options->server_flags & SF_TCP_NODELAY_HELPER) - msg (M_WARN, "WARNING: setting tcp-nodelay on the client side will not " - "affect the server. To have TCP_NODELAY in both direction use " - "tcp-nodelay in the server configuration instead."); - if (options->auth_user_pass_verify_script) - msg (M_USAGE, "--auth-user-pass-verify requires --mode server"); - if (options->auth_token_generate) - msg (M_USAGE, "--auth-gen-token requires --mode server"); -#if PORT_SHARE - if (options->port_share_host || options->port_share_port) - msg (M_USAGE, "--port-share requires TCP server mode (--mode server --proto tcp-server)"); + if (!proto_is_udp(ce->proto) && ce->explicit_exit_notification) + { + msg(M_USAGE, "--explicit-exit-notify can only be used with --proto udp"); + } #endif - if (options->stale_routes_check_interval) - msg (M_USAGE, "--stale-routes-check requires --mode server"); - if (compat_flag (COMPAT_FLAG_QUERY | COMPAT_NO_NAME_REMAPPING)) - msg (M_USAGE, "--compat-x509-names no-remapping requires --mode server"); + if (!ce->remote && ce->proto == PROTO_TCP_CLIENT) + { + msg(M_USAGE, "--remote MUST be used in TCP Client mode"); } -#endif /* P2MP_SERVER */ - -#ifdef ENABLE_CRYPTO - if (options->ncp_enabled && !tls_check_ncp_cipher_list(options->ncp_ciphers)) + if ((ce->http_proxy_options) && ce->proto != PROTO_TCP_CLIENT) { - msg (M_USAGE, "NCP cipher list contains unsupported ciphers."); + msg(M_USAGE, "--http-proxy MUST be used in TCP Client mode (i.e. --proto tcp-client)"); } - if (options->ncp_enabled && !options->use_iv) + if ((ce->http_proxy_options) && !ce->http_proxy_options->server) { - msg (M_USAGE, "--no-iv not allowed when NCP is enabled."); + msg(M_USAGE, "--http-proxy not specified but other http proxy options present"); } - if (!options->use_iv) + + if (ce->http_proxy_options && ce->socks_proxy_server) { - msg (M_WARN, "WARNING: --no-iv is deprecated and will be removed in 2.5"); + msg(M_USAGE, "--http-proxy can not be used together with --socks-proxy"); } - /* - * Check consistency of replay options - */ - if (!options->replay - && (options->replay_window != defaults.replay_window - || options->replay_time != defaults.replay_time)) - msg (M_USAGE, "--replay-window doesn't make sense when replay protection is disabled with --no-replay"); - - /* - * SSL/TLS mode sanity checks. - */ - if (options->tls_server + options->tls_client + - (options->shared_secret_file != NULL) > 1) - msg (M_USAGE, "specify only one of --tls-server, --tls-client, or --secret"); - - if (options->ssl_flags & (SSLF_CLIENT_CERT_NOT_REQUIRED|SSLF_CLIENT_CERT_OPTIONAL)) + if (ce->socks_proxy_server && ce->proto == PROTO_TCP_SERVER) { - msg (M_WARN, "WARNING: POTENTIALLY DANGEROUS OPTION " - "--verify-client-cert none|optional (or --client-cert-not-required) " - "may accept clients which do not present a certificate"); + msg(M_USAGE, "--socks-proxy can not be used in TCP Server mode"); } - if (options->key_method == 1) + if (ce->proto == PROTO_TCP_SERVER && (options->connection_list->len > 1)) { - msg (M_WARN, "WARNING: --key-method 1 is deprecated and will be removed " - "in OpenVPN 2.5. By default --key-method 2 will be used if not set " - "in the configuration file, which is the recommended approach."); + msg(M_USAGE, "TCP server mode allows at most one --remote address"); } - if (options->tls_server || options->tls_client) +#if P2MP_SERVER + + /* + * Check consistency of --mode server options. + */ + if (options->mode == MODE_SERVER) { -#ifdef ENABLE_PKCS11 - if (options->pkcs11_providers[0]) - { - notnull (options->ca_file, "CA file (--ca)"); - - if (options->pkcs11_id_management && options->pkcs11_id != NULL) - msg(M_USAGE, "Parameter --pkcs11-id cannot be used when --pkcs11-id-management is also specified."); - if (!options->pkcs11_id_management && options->pkcs11_id == NULL) - msg(M_USAGE, "Parameter --pkcs11-id or --pkcs11-id-management should be specified."); - if (options->cert_file) - msg(M_USAGE, "Parameter --cert cannot be used when --pkcs11-provider is also specified."); - if (options->priv_key_file) - msg(M_USAGE, "Parameter --key cannot be used when --pkcs11-provider is also specified."); -#ifdef MANAGMENT_EXTERNAL_KEY - if (options->management_flags & MF_EXTERNAL_KEY) - msg(M_USAGE, "Parameter --management-external-key cannot be used when --pkcs11-provider is also specified."); - if (options->management_flags & MF_EXTERNAL_CERT) - msg(M_USAGE, "Parameter --management-external-cert cannot be used when --pkcs11-provider is also specified."); -#endif - if (options->pkcs12_file) - msg(M_USAGE, "Parameter --pkcs12 cannot be used when --pkcs11-provider is also specified."); -#ifdef ENABLE_CRYPTOAPI - if (options->cryptoapi_cert) - msg(M_USAGE, "Parameter --cryptoapicert cannot be used when --pkcs11-provider is also specified."); -#endif - } - else -#endif -#ifdef MANAGMENT_EXTERNAL_KEY - if((options->management_flags & MF_EXTERNAL_KEY) && options->priv_key_file) - { - msg (M_USAGE, "--key and --management-external-key are mutually exclusive"); - } - else if((options->management_flags & MF_EXTERNAL_CERT)) - { - if (options->cert_file) - msg (M_USAGE, "--cert and --management-external-cert are mutually exclusive"); - else if(!(options->management_flags & MF_EXTERNAL_KEY)) - msg (M_USAGE, "--management-external-cert must be used with --management-external-key"); - } - else -#endif -#ifdef ENABLE_CRYPTOAPI - if (options->cryptoapi_cert) - { - if ((!(options->ca_file)) && (!(options->ca_path))) - msg(M_USAGE, "You must define CA file (--ca) or CA path (--capath)"); - if (options->cert_file) - msg(M_USAGE, "Parameter --cert cannot be used when --cryptoapicert is also specified."); - if (options->priv_key_file) - msg(M_USAGE, "Parameter --key cannot be used when --cryptoapicert is also specified."); - if (options->pkcs12_file) - msg(M_USAGE, "Parameter --pkcs12 cannot be used when --cryptoapicert is also specified."); + if (!(dev == DEV_TYPE_TUN || dev == DEV_TYPE_TAP)) + { + msg(M_USAGE, "--mode server only works with --dev tun or --dev tap"); + } + if (options->pull) + { + msg(M_USAGE, "--pull cannot be used with --mode server"); + } + if (options->pull_filter_list) + { + msg(M_USAGE, "--pull-filter cannot be used with --mode server"); + } + if (!(proto_is_udp(ce->proto) || ce->proto == PROTO_TCP_SERVER)) + { + msg(M_USAGE, "--mode server currently only supports " + "--proto udp or --proto tcp-server or proto tcp6-server"); + } +#if PORT_SHARE + if ((options->port_share_host || options->port_share_port) + && (ce->proto != PROTO_TCP_SERVER)) + { + msg(M_USAGE, "--port-share only works in TCP server mode " + "(--proto tcp-server or tcp6-server)"); + } +#endif + if (!options->tls_server) + { + msg(M_USAGE, "--mode server requires --tls-server"); + } + if (ce->remote) + { + msg(M_USAGE, "--remote cannot be used with --mode server"); + } + if (!ce->bind_local) + { + msg(M_USAGE, "--nobind cannot be used with --mode server"); + } + if (ce->http_proxy_options) + { + msg(M_USAGE, "--http-proxy cannot be used with --mode server"); + } + if (ce->socks_proxy_server) + { + msg(M_USAGE, "--socks-proxy cannot be used with --mode server"); + } + /* blocks force to have a remote embedded, so we check for the + * --remote and bail out if it is present */ + if (options->connection_list->len >1 + || options->connection_list->array[0]->remote) + { + msg(M_USAGE, " cannot be used with --mode server"); + } + + if (options->shaper) + { + msg(M_USAGE, "--shaper cannot be used with --mode server"); + } + if (options->inetd) + { + msg(M_USAGE, "--inetd cannot be used with --mode server"); + } + if (options->ipchange) + { + msg(M_USAGE, "--ipchange cannot be used with --mode server (use --client-connect instead)"); + } + if (!(proto_is_dgram(ce->proto) || ce->proto == PROTO_TCP_SERVER)) + { + msg(M_USAGE, "--mode server currently only supports " + "--proto udp or --proto tcp-server or --proto tcp6-server"); + } + if (!proto_is_udp(ce->proto) && (options->cf_max || options->cf_per)) + { + msg(M_USAGE, "--connect-freq only works with --mode server --proto udp. Try --max-clients instead."); + } + if (!(dev == DEV_TYPE_TAP || (dev == DEV_TYPE_TUN && options->topology == TOP_SUBNET)) && options->ifconfig_pool_netmask) + { + msg(M_USAGE, "The third parameter to --ifconfig-pool (netmask) is only valid in --dev tap mode"); + } + if (options->routes && (options->routes->flags & RG_ENABLE)) + { + msg(M_USAGE, "--redirect-gateway cannot be used with --mode server (however --push \"redirect-gateway\" is fine)"); + } + if (options->route_delay_defined) + { + msg(M_USAGE, "--route-delay cannot be used with --mode server"); + } + if (options->up_delay) + { + msg(M_USAGE, "--up-delay cannot be used with --mode server"); + } + if (!options->ifconfig_pool_defined && options->ifconfig_pool_persist_filename) + { + msg(M_USAGE, "--ifconfig-pool-persist must be used with --ifconfig-pool"); + } + if (options->ifconfig_ipv6_pool_defined && !options->ifconfig_ipv6_local) + { + msg(M_USAGE, "--ifconfig-ipv6-pool needs --ifconfig-ipv6"); + } + if (options->allow_recursive_routing) + { + msg(M_USAGE, "--allow-recursive-routing cannot be used with --mode server"); + } + if (options->auth_user_pass_file) + { + msg(M_USAGE, "--auth-user-pass cannot be used with --mode server (it should be used on the client side only)"); + } + if (options->ccd_exclusive && !options->client_config_dir) + { + msg(M_USAGE, "--ccd-exclusive must be used with --client-config-dir"); + } + if (options->key_method != 2) + { + msg(M_USAGE, "--mode server requires --key-method 2"); + } + + { + const bool ccnr = (options->auth_user_pass_verify_script + || PLUGIN_OPTION_LIST(options) + || MAN_CLIENT_AUTH_ENABLED(options)); + const char *postfix = "must be used with --management-client-auth, an --auth-user-pass-verify script, or plugin"; + if ((options->ssl_flags & (SSLF_CLIENT_CERT_NOT_REQUIRED|SSLF_CLIENT_CERT_OPTIONAL)) && !ccnr) + { + msg(M_USAGE, "--verify-client-cert none|optional %s", postfix); + } + if ((options->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) && !ccnr) + { + msg(M_USAGE, "--username-as-common-name %s", postfix); + } + if ((options->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL) && !ccnr) + { + msg(M_USAGE, "--auth-user-pass-optional %s", postfix); + } + } + } + else + { + /* + * When not in server mode, err if parameters are + * specified which require --mode server. + */ + if (options->ifconfig_pool_defined || options->ifconfig_pool_persist_filename) + { + msg(M_USAGE, "--ifconfig-pool/--ifconfig-pool-persist requires --mode server"); + } + if (options->ifconfig_ipv6_pool_defined) + { + msg(M_USAGE, "--ifconfig-ipv6-pool requires --mode server"); + } + if (options->real_hash_size != defaults.real_hash_size + || options->virtual_hash_size != defaults.virtual_hash_size) + { + msg(M_USAGE, "--hash-size requires --mode server"); + } + if (options->learn_address_script) + { + msg(M_USAGE, "--learn-address requires --mode server"); + } + if (options->client_connect_script) + { + msg(M_USAGE, "--client-connect requires --mode server"); + } + if (options->client_disconnect_script) + { + msg(M_USAGE, "--client-disconnect requires --mode server"); + } + if (options->client_config_dir || options->ccd_exclusive) + { + msg(M_USAGE, "--client-config-dir/--ccd-exclusive requires --mode server"); + } + if (options->enable_c2c) + { + msg(M_USAGE, "--client-to-client requires --mode server"); + } + if (options->duplicate_cn) + { + msg(M_USAGE, "--duplicate-cn requires --mode server"); + } + if (options->cf_max || options->cf_per) + { + msg(M_USAGE, "--connect-freq requires --mode server"); + } + if (options->ssl_flags & (SSLF_CLIENT_CERT_NOT_REQUIRED|SSLF_CLIENT_CERT_OPTIONAL)) + { + msg(M_USAGE, "--client-cert-not-required and --verify-client-cert require --mode server"); + } + if (options->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) + { + msg(M_USAGE, "--username-as-common-name requires --mode server"); + } + if (options->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL) + { + msg(M_USAGE, "--auth-user-pass-optional requires --mode server"); + } + if (options->ssl_flags & SSLF_OPT_VERIFY) + { + msg(M_USAGE, "--opt-verify requires --mode server"); + } + if (options->server_flags & SF_TCP_NODELAY_HELPER) + { + msg(M_WARN, "WARNING: setting tcp-nodelay on the client side will not " + "affect the server. To have TCP_NODELAY in both direction use " + "tcp-nodelay in the server configuration instead."); + } + if (options->auth_user_pass_verify_script) + { + msg(M_USAGE, "--auth-user-pass-verify requires --mode server"); + } + if (options->auth_token_generate) + { + msg(M_USAGE, "--auth-gen-token requires --mode server"); + } +#if PORT_SHARE + if (options->port_share_host || options->port_share_port) + { + msg(M_USAGE, "--port-share requires TCP server mode (--mode server --proto tcp-server)"); + } +#endif + + if (options->stale_routes_check_interval) + { + msg(M_USAGE, "--stale-routes-check requires --mode server"); + } + if (compat_flag(COMPAT_FLAG_QUERY | COMPAT_NO_NAME_REMAPPING)) + { + msg(M_USAGE, "--compat-x509-names no-remapping requires --mode server"); + } + } +#endif /* P2MP_SERVER */ + +#ifdef ENABLE_CRYPTO + + if (options->ncp_enabled && !tls_check_ncp_cipher_list(options->ncp_ciphers)) + { + msg(M_USAGE, "NCP cipher list contains unsupported ciphers."); + } + if (options->ncp_enabled && !options->use_iv) + { + msg(M_USAGE, "--no-iv not allowed when NCP is enabled."); + } + if (!options->use_iv) + { + msg(M_WARN, "WARNING: --no-iv is deprecated and will be removed in 2.5"); + } + + /* + * Check consistency of replay options + */ + if (!options->replay + && (options->replay_window != defaults.replay_window + || options->replay_time != defaults.replay_time)) + { + msg(M_USAGE, "--replay-window doesn't make sense when replay protection is disabled with --no-replay"); + } + + /* + * SSL/TLS mode sanity checks. + */ + if (options->tls_server + options->tls_client + +(options->shared_secret_file != NULL) > 1) + { + msg(M_USAGE, "specify only one of --tls-server, --tls-client, or --secret"); + } + + if (options->ssl_flags & (SSLF_CLIENT_CERT_NOT_REQUIRED|SSLF_CLIENT_CERT_OPTIONAL)) + { + msg(M_WARN, "WARNING: POTENTIALLY DANGEROUS OPTION " + "--verify-client-cert none|optional (or --client-cert-not-required) " + "may accept clients which do not present a certificate"); + } + + if (options->key_method == 1) + { + msg(M_WARN, "WARNING: --key-method 1 is deprecated and will be removed " + "in OpenVPN 2.5. By default --key-method 2 will be used if not set " + "in the configuration file, which is the recommended approach."); + } + + if (options->tls_server || options->tls_client) + { +#ifdef ENABLE_PKCS11 + if (options->pkcs11_providers[0]) + { + notnull(options->ca_file, "CA file (--ca)"); + + if (options->pkcs11_id_management && options->pkcs11_id != NULL) + { + msg(M_USAGE, "Parameter --pkcs11-id cannot be used when --pkcs11-id-management is also specified."); + } + if (!options->pkcs11_id_management && options->pkcs11_id == NULL) + { + msg(M_USAGE, "Parameter --pkcs11-id or --pkcs11-id-management should be specified."); + } + if (options->cert_file) + { + msg(M_USAGE, "Parameter --cert cannot be used when --pkcs11-provider is also specified."); + } + if (options->priv_key_file) + { + msg(M_USAGE, "Parameter --key cannot be used when --pkcs11-provider is also specified."); + } +#ifdef MANAGMENT_EXTERNAL_KEY + if (options->management_flags & MF_EXTERNAL_KEY) + { + msg(M_USAGE, "Parameter --management-external-key cannot be used when --pkcs11-provider is also specified."); + } + if (options->management_flags & MF_EXTERNAL_CERT) + { + msg(M_USAGE, "Parameter --management-external-cert cannot be used when --pkcs11-provider is also specified."); + } +#endif + if (options->pkcs12_file) + { + msg(M_USAGE, "Parameter --pkcs12 cannot be used when --pkcs11-provider is also specified."); + } +#ifdef ENABLE_CRYPTOAPI + if (options->cryptoapi_cert) + { + msg(M_USAGE, "Parameter --cryptoapicert cannot be used when --pkcs11-provider is also specified."); + } +#endif + } + else +#endif /* ifdef ENABLE_PKCS11 */ #ifdef MANAGMENT_EXTERNAL_KEY - if (options->management_flags & MF_EXTERNAL_KEY) - msg(M_USAGE, "Parameter --management-external-key cannot be used when --cryptoapicert is also specified."); - if (options->management_flags & MF_EXTERNAL_CERT) - msg(M_USAGE, "Parameter --management-external-cert cannot be used when --cryptoapicert is also specified."); + if ((options->management_flags & MF_EXTERNAL_KEY) && options->priv_key_file) + { + msg(M_USAGE, "--key and --management-external-key are mutually exclusive"); + } + else if ((options->management_flags & MF_EXTERNAL_CERT)) + { + if (options->cert_file) + { + msg(M_USAGE, "--cert and --management-external-cert are mutually exclusive"); + } + else if (!(options->management_flags & MF_EXTERNAL_KEY)) + { + msg(M_USAGE, "--management-external-cert must be used with --management-external-key"); + } + } + else #endif - } - else +#ifdef ENABLE_CRYPTOAPI + if (options->cryptoapi_cert) + { + if ((!(options->ca_file)) && (!(options->ca_path))) + { + msg(M_USAGE, "You must define CA file (--ca) or CA path (--capath)"); + } + if (options->cert_file) + { + msg(M_USAGE, "Parameter --cert cannot be used when --cryptoapicert is also specified."); + } + if (options->priv_key_file) + { + msg(M_USAGE, "Parameter --key cannot be used when --cryptoapicert is also specified."); + } + if (options->pkcs12_file) + { + msg(M_USAGE, "Parameter --pkcs12 cannot be used when --cryptoapicert is also specified."); + } +#ifdef MANAGMENT_EXTERNAL_KEY + if (options->management_flags & MF_EXTERNAL_KEY) + { + msg(M_USAGE, "Parameter --management-external-key cannot be used when --cryptoapicert is also specified."); + } + if (options->management_flags & MF_EXTERNAL_CERT) + { + msg(M_USAGE, "Parameter --management-external-cert cannot be used when --cryptoapicert is also specified."); + } #endif - if (options->pkcs12_file) + } + else +#endif /* ifdef ENABLE_CRYPTOAPI */ + if (options->pkcs12_file) { #ifdef ENABLE_CRYPTO_MBEDTLS - msg(M_USAGE, "Parameter --pkcs12 cannot be used with the mbed TLS version version of OpenVPN."); + msg(M_USAGE, "Parameter --pkcs12 cannot be used with the mbed TLS version version of OpenVPN."); #else - if (options->ca_path) - msg(M_USAGE, "Parameter --capath cannot be used when --pkcs12 is also specified."); - if (options->cert_file) - msg(M_USAGE, "Parameter --cert cannot be used when --pkcs12 is also specified."); - if (options->priv_key_file) - msg(M_USAGE, "Parameter --key cannot be used when --pkcs12 is also specified."); + if (options->ca_path) + { + msg(M_USAGE, "Parameter --capath cannot be used when --pkcs12 is also specified."); + } + if (options->cert_file) + { + msg(M_USAGE, "Parameter --cert cannot be used when --pkcs12 is also specified."); + } + if (options->priv_key_file) + { + msg(M_USAGE, "Parameter --key cannot be used when --pkcs12 is also specified."); + } #ifdef MANAGMENT_EXTERNAL_KEY - if (options->management_flags & MF_EXTERNAL_KEY) - msg(M_USAGE, "Parameter --management-external-key cannot be used when --pkcs12 is also specified."); - if (options->management_flags & MF_EXTERNAL_CERT) - msg(M_USAGE, "Parameter --management-external-cert cannot be used when --pkcs12 is also specified."); -#endif + if (options->management_flags & MF_EXTERNAL_KEY) + { + msg(M_USAGE, "Parameter --management-external-key cannot be used when --pkcs12 is also specified."); + } + if (options->management_flags & MF_EXTERNAL_CERT) + { + msg(M_USAGE, "Parameter --management-external-cert cannot be used when --pkcs12 is also specified."); + } #endif +#endif /* ifdef ENABLE_CRYPTO_MBEDTLS */ } - else + else { #ifdef ENABLE_CRYPTO_MBEDTLS - if (!(options->ca_file)) - msg(M_USAGE, "You must define CA file (--ca)"); - if (options->ca_path) - msg(M_USAGE, "Parameter --capath cannot be used with the mbed TLS version version of OpenVPN."); -#else - if ((!(options->ca_file)) && (!(options->ca_path))) - msg(M_USAGE, "You must define CA file (--ca) or CA path (--capath)"); + if (!(options->ca_file)) + { + msg(M_USAGE, "You must define CA file (--ca)"); + } + if (options->ca_path) + { + msg(M_USAGE, "Parameter --capath cannot be used with the mbed TLS version version of OpenVPN."); + } +#else /* ifdef ENABLE_CRYPTO_MBEDTLS */ + if ((!(options->ca_file)) && (!(options->ca_path))) + { + msg(M_USAGE, "You must define CA file (--ca) or CA path (--capath)"); + } #endif - if (pull) - { + if (pull) + { - const int sum = + const int sum = #ifdef MANAGMENT_EXTERNAL_KEY - ((options->cert_file != NULL) || (options->management_flags & MF_EXTERNAL_CERT)) + - ((options->priv_key_file != NULL) || (options->management_flags & MF_EXTERNAL_KEY)); + ((options->cert_file != NULL) || (options->management_flags & MF_EXTERNAL_CERT)) + +((options->priv_key_file != NULL) || (options->management_flags & MF_EXTERNAL_KEY)); #else - (options->cert_file != NULL) + (options->priv_key_file != NULL); + (options->cert_file != NULL) + (options->priv_key_file != NULL); #endif - if (sum == 0) - { + if (sum == 0) + { #if P2MP - if (!options->auth_user_pass_file) -#endif - msg (M_USAGE, "No client-side authentication method is specified. You must use either --cert/--key, --pkcs12, or --auth-user-pass"); - } - else if (sum == 2) - ; - else - { - msg (M_USAGE, "If you use one of --cert or --key, you must use them both"); - } - } - else - { + if (!options->auth_user_pass_file) +#endif + msg(M_USAGE, "No client-side authentication method is specified. You must use either --cert/--key, --pkcs12, or --auth-user-pass"); + } + else if (sum == 2) + { + } + else + { + msg(M_USAGE, "If you use one of --cert or --key, you must use them both"); + } + } + else + { #ifdef MANAGMENT_EXTERNAL_KEY - if (!(options->management_flags & MF_EXTERNAL_CERT)) + if (!(options->management_flags & MF_EXTERNAL_CERT)) #endif - notnull (options->cert_file, "certificate file (--cert) or PKCS#12 file (--pkcs12)"); + notnull(options->cert_file, "certificate file (--cert) or PKCS#12 file (--pkcs12)"); #ifdef MANAGMENT_EXTERNAL_KEY - if (!(options->management_flags & MF_EXTERNAL_KEY)) + if (!(options->management_flags & MF_EXTERNAL_KEY)) #endif - notnull (options->priv_key_file, "private key file (--key) or PKCS#12 file (--pkcs12)"); - } - } - if (options->tls_auth_file && options->tls_crypt_file) - { - msg (M_USAGE, "--tls-auth and --tls-crypt are mutually exclusive"); - } + notnull(options->priv_key_file, "private key file (--key) or PKCS#12 file (--pkcs12)"); + } + } + if (options->tls_auth_file && options->tls_crypt_file) + { + msg(M_USAGE, "--tls-auth and --tls-crypt are mutually exclusive"); + } } - else + else { - /* - * Make sure user doesn't specify any TLS options - * when in non-TLS mode. - */ + /* + * Make sure user doesn't specify any TLS options + * when in non-TLS mode. + */ -#define MUST_BE_UNDEF(parm) if (options->parm != defaults.parm) msg (M_USAGE, err, #parm); +#define MUST_BE_UNDEF(parm) if (options->parm != defaults.parm) {msg(M_USAGE, err, #parm); \ +} - const char err[] = "Parameter %s can only be specified in TLS-mode, i.e. where --tls-server or --tls-client is also specified."; + const char err[] = "Parameter %s can only be specified in TLS-mode, i.e. where --tls-server or --tls-client is also specified."; - MUST_BE_UNDEF (ca_file); - MUST_BE_UNDEF (ca_path); - MUST_BE_UNDEF (dh_file); - MUST_BE_UNDEF (cert_file); - MUST_BE_UNDEF (priv_key_file); + MUST_BE_UNDEF(ca_file); + MUST_BE_UNDEF(ca_path); + MUST_BE_UNDEF(dh_file); + MUST_BE_UNDEF(cert_file); + MUST_BE_UNDEF(priv_key_file); #ifndef ENABLE_CRYPTO_MBEDTLS - MUST_BE_UNDEF (pkcs12_file); -#endif - MUST_BE_UNDEF (cipher_list); - MUST_BE_UNDEF (tls_verify); - MUST_BE_UNDEF (tls_export_cert); - MUST_BE_UNDEF (verify_x509_name); - MUST_BE_UNDEF (tls_timeout); - MUST_BE_UNDEF (renegotiate_bytes); - MUST_BE_UNDEF (renegotiate_packets); - MUST_BE_UNDEF (renegotiate_seconds); - MUST_BE_UNDEF (handshake_window); - MUST_BE_UNDEF (transition_window); - MUST_BE_UNDEF (tls_auth_file); - MUST_BE_UNDEF (tls_crypt_file); - MUST_BE_UNDEF (single_session); + MUST_BE_UNDEF(pkcs12_file); +#endif + MUST_BE_UNDEF(cipher_list); + MUST_BE_UNDEF(tls_verify); + MUST_BE_UNDEF(tls_export_cert); + MUST_BE_UNDEF(verify_x509_name); + MUST_BE_UNDEF(tls_timeout); + MUST_BE_UNDEF(renegotiate_bytes); + MUST_BE_UNDEF(renegotiate_packets); + MUST_BE_UNDEF(renegotiate_seconds); + MUST_BE_UNDEF(handshake_window); + MUST_BE_UNDEF(transition_window); + MUST_BE_UNDEF(tls_auth_file); + MUST_BE_UNDEF(tls_crypt_file); + MUST_BE_UNDEF(single_session); #ifdef ENABLE_PUSH_PEER_INFO - MUST_BE_UNDEF (push_peer_info); -#endif - MUST_BE_UNDEF (tls_exit); - MUST_BE_UNDEF (crl_file); - MUST_BE_UNDEF (key_method); - MUST_BE_UNDEF (ns_cert_type); - MUST_BE_UNDEF (remote_cert_ku[0]); - MUST_BE_UNDEF (remote_cert_eku); + MUST_BE_UNDEF(push_peer_info); +#endif + MUST_BE_UNDEF(tls_exit); + MUST_BE_UNDEF(crl_file); + MUST_BE_UNDEF(key_method); + MUST_BE_UNDEF(ns_cert_type); + MUST_BE_UNDEF(remote_cert_ku[0]); + MUST_BE_UNDEF(remote_cert_eku); #ifdef ENABLE_PKCS11 - MUST_BE_UNDEF (pkcs11_providers[0]); - MUST_BE_UNDEF (pkcs11_private_mode[0]); - MUST_BE_UNDEF (pkcs11_id); - MUST_BE_UNDEF (pkcs11_id_management); + MUST_BE_UNDEF(pkcs11_providers[0]); + MUST_BE_UNDEF(pkcs11_private_mode[0]); + MUST_BE_UNDEF(pkcs11_id); + MUST_BE_UNDEF(pkcs11_id_management); #endif - if (pull) - msg (M_USAGE, err, "--pull"); + if (pull) + { + msg(M_USAGE, err, "--pull"); + } } #undef MUST_BE_UNDEF #endif /* ENABLE_CRYPTO */ #if P2MP - if (options->auth_user_pass_file && !options->pull) - msg (M_USAGE, "--auth-user-pass requires --pull"); + if (options->auth_user_pass_file && !options->pull) + { + msg(M_USAGE, "--auth-user-pass requires --pull"); + } #endif - uninit_options (&defaults); + uninit_options(&defaults); } static void -options_postprocess_mutate_ce (struct options *o, struct connection_entry *ce) +options_postprocess_mutate_ce(struct options *o, struct connection_entry *ce) { - const int dev = dev_type_enum (o->dev, o->dev_type); + const int dev = dev_type_enum(o->dev, o->dev_type); #if P2MP_SERVER - if (o->server_defined || o->server_bridge_defined || o->server_bridge_proxy_dhcp) + if (o->server_defined || o->server_bridge_defined || o->server_bridge_proxy_dhcp) { - if (ce->proto == PROTO_TCP) - ce->proto = PROTO_TCP_SERVER; + if (ce->proto == PROTO_TCP) + { + ce->proto = PROTO_TCP_SERVER; + } } #endif #if P2MP - if (o->client) + if (o->client) { - if (ce->proto == PROTO_TCP) - ce->proto = PROTO_TCP_CLIENT; + if (ce->proto == PROTO_TCP) + { + ce->proto = PROTO_TCP_CLIENT; + } } #endif - if (ce->proto == PROTO_TCP_CLIENT && !ce->local && !ce->local_port_defined && !ce->bind_defined) - ce->bind_local = false; + if (ce->proto == PROTO_TCP_CLIENT && !ce->local && !ce->local_port_defined && !ce->bind_defined) + { + ce->bind_local = false; + } - if (ce->proto == PROTO_UDP && ce->socks_proxy_server && !ce->local && !ce->local_port_defined && !ce->bind_defined) - ce->bind_local = false; + if (ce->proto == PROTO_UDP && ce->socks_proxy_server && !ce->local && !ce->local_port_defined && !ce->bind_defined) + { + ce->bind_local = false; + } - if (!ce->bind_local) - ce->local_port = NULL; + if (!ce->bind_local) + { + ce->local_port = NULL; + } - /* if protocol forcing is enabled, disable all protocols except for the forced one */ - if (o->proto_force >= 0 && o->proto_force != ce->proto) - ce->flags |= CE_DISABLED; + /* if protocol forcing is enabled, disable all protocols except for the forced one */ + if (o->proto_force >= 0 && o->proto_force != ce->proto) + { + ce->flags |= CE_DISABLED; + } - /* - * If --mssfix is supplied without a parameter, default - * it to --fragment value, if --fragment is specified. - */ - if (o->ce.mssfix_default) + /* + * If --mssfix is supplied without a parameter, default + * it to --fragment value, if --fragment is specified. + */ + if (o->ce.mssfix_default) { #ifdef ENABLE_FRAGMENT - if (ce->fragment) - ce->mssfix = ce->fragment; + if (ce->fragment) + { + ce->mssfix = ce->fragment; + } #else - msg (M_USAGE, "--mssfix must specify a parameter"); -#endif - } - - /* - * Set MTU defaults - */ - { - if (!ce->tun_mtu_defined && !ce->link_mtu_defined) - { - ce->tun_mtu_defined = true; - } - if ((dev == DEV_TYPE_TAP) && !ce->tun_mtu_extra_defined) - { - ce->tun_mtu_extra_defined = true; - ce->tun_mtu_extra = TAP_MTU_EXTRA_DEFAULT; - } - } + msg(M_USAGE, "--mssfix must specify a parameter"); +#endif + } + + /* + * Set MTU defaults + */ + { + if (!ce->tun_mtu_defined && !ce->link_mtu_defined) + { + ce->tun_mtu_defined = true; + } + if ((dev == DEV_TYPE_TAP) && !ce->tun_mtu_extra_defined) + { + ce->tun_mtu_extra_defined = true; + ce->tun_mtu_extra = TAP_MTU_EXTRA_DEFAULT; + } + } } #ifdef _WIN32 /* If iservice is in use, we need def1 method for redirect-gateway */ static void -remap_redirect_gateway_flags (struct options *opt) +remap_redirect_gateway_flags(struct options *opt) { - if (opt->routes - && opt->route_method == ROUTE_METHOD_SERVICE - && opt->routes->flags & RG_REROUTE_GW - && !(opt->routes->flags & RG_DEF1)) + if (opt->routes + && opt->route_method == ROUTE_METHOD_SERVICE + && opt->routes->flags & RG_REROUTE_GW + && !(opt->routes->flags & RG_DEF1)) { - msg (M_INFO, "Flag 'def1' added to --redirect-gateway (iservice is in use)"); - opt->routes->flags |= RG_DEF1; + msg(M_INFO, "Flag 'def1' added to --redirect-gateway (iservice is in use)"); + opt->routes->flags |= RG_DEF1; } } #endif static void -options_postprocess_mutate_invariant (struct options *options) +options_postprocess_mutate_invariant(struct options *options) { #ifdef _WIN32 - const int dev = dev_type_enum (options->dev, options->dev_type); + const int dev = dev_type_enum(options->dev, options->dev_type); #endif - /* - * In forking TCP server mode, you don't need to ifconfig - * the tap device (the assumption is that it will be bridged). - */ - if (options->inetd == INETD_NOWAIT) - options->ifconfig_noexec = true; + /* + * In forking TCP server mode, you don't need to ifconfig + * the tap device (the assumption is that it will be bridged). + */ + if (options->inetd == INETD_NOWAIT) + { + options->ifconfig_noexec = true; + } #ifdef _WIN32 - if ((dev == DEV_TYPE_TUN || dev == DEV_TYPE_TAP) && !options->route_delay_defined) + if ((dev == DEV_TYPE_TUN || dev == DEV_TYPE_TAP) && !options->route_delay_defined) { - if (options->mode == MODE_POINT_TO_POINT) - { - options->route_delay_defined = true; - options->route_delay = 5; /* Vista sometimes has a race without this */ - } + if (options->mode == MODE_POINT_TO_POINT) + { + options->route_delay_defined = true; + options->route_delay = 5; /* Vista sometimes has a race without this */ + } } - if (options->ifconfig_noexec) + if (options->ifconfig_noexec) { - options->tuntap_options.ip_win32_type = IPW32_SET_MANUAL; - options->ifconfig_noexec = false; + options->tuntap_options.ip_win32_type = IPW32_SET_MANUAL; + options->ifconfig_noexec = false; } - remap_redirect_gateway_flags (options); + remap_redirect_gateway_flags(options); #endif #if P2MP_SERVER - /* - * Check consistency of --mode server options. - */ - if (options->mode == MODE_SERVER) + /* + * Check consistency of --mode server options. + */ + if (options->mode == MODE_SERVER) { #ifdef _WIN32 - /* - * We need to explicitly set --tap-sleep because - * we do not schedule event timers in the top-level context. - */ - options->tuntap_options.tap_sleep = 10; - if (options->route_delay_defined && options->route_delay) - options->tuntap_options.tap_sleep = options->route_delay; - options->route_delay_defined = false; + /* + * We need to explicitly set --tap-sleep because + * we do not schedule event timers in the top-level context. + */ + options->tuntap_options.tap_sleep = 10; + if (options->route_delay_defined && options->route_delay) + { + options->tuntap_options.tap_sleep = options->route_delay; + } + options->route_delay_defined = false; #endif } #endif #ifdef DEFAULT_PKCS11_MODULE - /* If p11-kit is present on the system then load its p11-kit-proxy.so - by default if the user asks for PKCS#11 without otherwise specifying - the module to use. */ - if (!options->pkcs11_providers[0] && - (options->pkcs11_id || options->pkcs11_id_management)) - options->pkcs11_providers[0] = DEFAULT_PKCS11_MODULE; + /* If p11-kit is present on the system then load its p11-kit-proxy.so + * by default if the user asks for PKCS#11 without otherwise specifying + * the module to use. */ + if (!options->pkcs11_providers[0] + && (options->pkcs11_id || options->pkcs11_id_management)) + { + options->pkcs11_providers[0] = DEFAULT_PKCS11_MODULE; + } #endif } static void -options_postprocess_verify (const struct options *o) +options_postprocess_verify(const struct options *o) { - if (o->connection_list) + if (o->connection_list) + { + int i; + for (i = 0; i < o->connection_list->len; ++i) + options_postprocess_verify_ce(o, o->connection_list->array[i]); + } + else { - int i; - for (i = 0; i < o->connection_list->len; ++i) - options_postprocess_verify_ce (o, o->connection_list->array[i]); + options_postprocess_verify_ce(o, &o->ce); } - else - options_postprocess_verify_ce (o, &o->ce); } static void -options_postprocess_mutate (struct options *o) +options_postprocess_mutate(struct options *o) { - int i; - /* - * Process helper-type options which map to other, more complex - * sequences of options. - */ - helper_client_server (o); - helper_keepalive (o); - helper_tcp_nodelay (o); + int i; + /* + * Process helper-type options which map to other, more complex + * sequences of options. + */ + helper_client_server(o); + helper_keepalive(o); + helper_tcp_nodelay(o); - options_postprocess_mutate_invariant (o); + options_postprocess_mutate_invariant(o); - if (o->remote_list && !o->connection_list) + if (o->remote_list && !o->connection_list) { - /* - * Convert remotes into connection list - */ - const struct remote_list *rl = o->remote_list; - for (i = 0; i < rl->len; ++i) + /* + * Convert remotes into connection list + */ + const struct remote_list *rl = o->remote_list; + for (i = 0; i < rl->len; ++i) { - const struct remote_entry *re = rl->array[i]; - struct connection_entry ce = o->ce; - struct connection_entry *ace; - - ASSERT (re->remote); - connection_entry_load_re (&ce, re); - ace = alloc_connection_entry (o, M_USAGE); - ASSERT (ace); - *ace = ce; + const struct remote_entry *re = rl->array[i]; + struct connection_entry ce = o->ce; + struct connection_entry *ace; + + ASSERT(re->remote); + connection_entry_load_re(&ce, re); + ace = alloc_connection_entry(o, M_USAGE); + ASSERT(ace); + *ace = ce; } } - else if(!o->remote_list && !o->connection_list) + else if (!o->remote_list && !o->connection_list) { - struct connection_entry *ace; - ace = alloc_connection_entry (o, M_USAGE); - ASSERT (ace); - *ace = o->ce; + struct connection_entry *ace; + ace = alloc_connection_entry(o, M_USAGE); + ASSERT(ace); + *ace = o->ce; } - ASSERT (o->connection_list); - for (i = 0; i < o->connection_list->len; ++i) - options_postprocess_mutate_ce (o, o->connection_list->array[i]); + ASSERT(o->connection_list); + for (i = 0; i < o->connection_list->len; ++i) + options_postprocess_mutate_ce(o, o->connection_list->array[i]); #ifdef ENABLE_CRYPTO - if (o->tls_server) + if (o->tls_server) { - /* Check that DH file is specified, or explicitly disabled */ - notnull (o->dh_file, "DH file (--dh)"); - if (streq (o->dh_file, "none")) - o->dh_file = NULL; + /* Check that DH file is specified, or explicitly disabled */ + notnull(o->dh_file, "DH file (--dh)"); + if (streq(o->dh_file, "none")) + { + o->dh_file = NULL; + } } - /* cipher negotiation (NCP) currently assumes --pull or --mode server */ - if ( o->ncp_enabled && - ! (o->pull || o->mode == MODE_SERVER) ) + /* cipher negotiation (NCP) currently assumes --pull or --mode server */ + if (o->ncp_enabled + && !(o->pull || o->mode == MODE_SERVER) ) { - msg( M_WARN, "disabling NCP mode (--ncp-disable) because not " - "in P2MP client or server mode" ); - o->ncp_enabled = false; + msg( M_WARN, "disabling NCP mode (--ncp-disable) because not " + "in P2MP client or server mode" ); + o->ncp_enabled = false; } #endif #if ENABLE_MANAGEMENT - if (o->http_proxy_override) - options_postprocess_http_proxy_override(o); + if (o->http_proxy_override) + { + options_postprocess_http_proxy_override(o); + } #endif #ifdef ENABLE_CRYPTOAPI - if (o->cryptoapi_cert) + if (o->cryptoapi_cert) { - const int tls_version_max = - (o->ssl_flags >> SSLF_TLS_VERSION_MAX_SHIFT) & - SSLF_TLS_VERSION_MAX_MASK; + const int tls_version_max = + (o->ssl_flags >> SSLF_TLS_VERSION_MAX_SHIFT) + &SSLF_TLS_VERSION_MAX_MASK; - if (tls_version_max == TLS_VER_UNSPEC || tls_version_max > TLS_VER_1_1) - { - msg(M_WARN, "Warning: cryptapicert used, setting maximum TLS " - "version to 1.1."); - o->ssl_flags &= ~(SSLF_TLS_VERSION_MAX_MASK << - SSLF_TLS_VERSION_MAX_SHIFT); - o->ssl_flags |= (TLS_VER_1_1 << SSLF_TLS_VERSION_MAX_SHIFT); - } + if (tls_version_max == TLS_VER_UNSPEC || tls_version_max > TLS_VER_1_1) + { + msg(M_WARN, "Warning: cryptapicert used, setting maximum TLS " + "version to 1.1."); + o->ssl_flags &= ~(SSLF_TLS_VERSION_MAX_MASK + <ssl_flags |= (TLS_VER_1_1 << SSLF_TLS_VERSION_MAX_SHIFT); + } } #endif /* ENABLE_CRYPTOAPI */ #if P2MP - /* - * Save certain parms before modifying options via --pull - */ - pre_pull_save (o); + /* + * Save certain parms before modifying options via --pull + */ + pre_pull_save(o); #endif } @@ -2731,71 +3057,89 @@ options_postprocess_mutate (struct options *o) #define CHKACC_FILEXSTWR (1<<2) /** If file exists, is it writable? */ #define CHKACC_INLINE (1<<3) /** File is present if it's an inline file */ #define CHKACC_ACPTSTDIN (1<<4) /** If filename is stdin, it's allowed and "exists" */ -#define CHKACC_PRIVATE (1<<5) /** Warn if this (private) file is group/others accessible */ +#define CHKACC_PRIVATE (1<<5) /** Warn if this (private) file is group/others accessible */ static bool check_file_access(const int type, const char *file, const int mode, const char *opt) { - int errcode = 0; + int errcode = 0; - /* If no file configured, no errors to look for */ - if (!file) - return false; + /* If no file configured, no errors to look for */ + if (!file) + { + return false; + } - /* If this may be an inline file, and the proper inline "filename" is set - no issues */ - if ((type & CHKACC_INLINE) && streq(file, INLINE_FILE_TAG) ) - return false; + /* If this may be an inline file, and the proper inline "filename" is set - no issues */ + if ((type & CHKACC_INLINE) && streq(file, INLINE_FILE_TAG) ) + { + return false; + } - /* If stdin is allowed and the file name is 'stdin', then do no - * further checks as stdin is always available - */ - if( (type & CHKACC_ACPTSTDIN) && streq(file, "stdin") ) - return false; + /* If stdin is allowed and the file name is 'stdin', then do no + * further checks as stdin is always available + */ + if ( (type & CHKACC_ACPTSTDIN) && streq(file, "stdin") ) + { + return false; + } - /* Is the directory path leading to the given file accessible? */ - if (type & CHKACC_DIRPATH) + /* Is the directory path leading to the given file accessible? */ + if (type & CHKACC_DIRPATH) { - char *fullpath = string_alloc (file, NULL); /* POSIX dirname() implementaion may modify its arguments */ - char *dirpath = dirname(fullpath); + char *fullpath = string_alloc(file, NULL); /* POSIX dirname() implementaion may modify its arguments */ + char *dirpath = dirname(fullpath); - if (platform_access (dirpath, mode|X_OK) != 0) - errcode = errno; - free(fullpath); + if (platform_access(dirpath, mode|X_OK) != 0) + { + errcode = errno; + } + free(fullpath); } - /* Is the file itself accessible? */ - if (!errcode && (type & CHKACC_FILE) && (platform_access (file, mode) != 0) ) - errcode = errno; + /* Is the file itself accessible? */ + if (!errcode && (type & CHKACC_FILE) && (platform_access(file, mode) != 0) ) + { + errcode = errno; + } - /* If the file exists and is accessible, is it writable? */ - if (!errcode && (type & CHKACC_FILEXSTWR) && (platform_access (file, F_OK) == 0) ) - if (platform_access (file, W_OK) != 0) - errcode = errno; + /* If the file exists and is accessible, is it writable? */ + if (!errcode && (type & CHKACC_FILEXSTWR) && (platform_access(file, F_OK) == 0) ) + { + if (platform_access(file, W_OK) != 0) + { + errcode = errno; + } + } - /* Warn if a given private file is group/others accessible. */ - if (type & CHKACC_PRIVATE) + /* Warn if a given private file is group/others accessible. */ + if (type & CHKACC_PRIVATE) { - platform_stat_t st; - if (platform_stat (file, &st)) - { - msg (M_WARN | M_ERRNO, "WARNING: cannot stat file '%s'", file); - } + platform_stat_t st; + if (platform_stat(file, &st)) + { + msg(M_WARN | M_ERRNO, "WARNING: cannot stat file '%s'", file); + } #ifndef _WIN32 - else - { - if (st.st_mode & (S_IRWXG|S_IRWXO)) - msg (M_WARN, "WARNING: file '%s' is group or others accessible", file); - } + else + { + if (st.st_mode & (S_IRWXG|S_IRWXO)) + { + msg(M_WARN, "WARNING: file '%s' is group or others accessible", file); + } + } #endif } - /* Scream if an error is found */ - if( errcode > 0 ) - msg (M_NOPREFIX|M_OPTERR, "%s fails with '%s': %s", - opt, file, strerror(errno)); + /* Scream if an error is found */ + if (errcode > 0) + { + msg(M_NOPREFIX|M_OPTERR, "%s fails with '%s': %s", + opt, file, strerror(errno)); + } - /* Return true if an error occured */ - return (errcode != 0 ? true : false); + /* Return true if an error occured */ + return (errcode != 0 ? true : false); } /* A wrapper for check_file_access() which also takes a chroot directory. @@ -2805,34 +3149,36 @@ check_file_access(const int type, const char *file, const int mode, const char * static bool check_file_access_chroot(const char *chroot, const int type, const char *file, const int mode, const char *opt) { - bool ret = false; + bool ret = false; - /* If no file configured, no errors to look for */ - if (!file) - return false; + /* If no file configured, no errors to look for */ + if (!file) + { + return false; + } - /* If chroot is set, look for the file/directory inside the chroot */ - if( chroot ) + /* If chroot is set, look for the file/directory inside the chroot */ + if (chroot) { - struct gc_arena gc = gc_new(); - struct buffer chroot_file; - int len = 0; + struct gc_arena gc = gc_new(); + struct buffer chroot_file; + int len = 0; - /* Build up a new full path including chroot directory */ - len = strlen(chroot) + strlen(PATH_SEPARATOR_STR) + strlen(file) + 1; - chroot_file = alloc_buf_gc(len, &gc); - buf_printf(&chroot_file, "%s%s%s", chroot, PATH_SEPARATOR_STR, file); - ASSERT (chroot_file.len > 0); + /* Build up a new full path including chroot directory */ + len = strlen(chroot) + strlen(PATH_SEPARATOR_STR) + strlen(file) + 1; + chroot_file = alloc_buf_gc(len, &gc); + buf_printf(&chroot_file, "%s%s%s", chroot, PATH_SEPARATOR_STR, file); + ASSERT(chroot_file.len > 0); - ret = check_file_access(type, BSTR(&chroot_file), mode, opt); - gc_free(&gc); + ret = check_file_access(type, BSTR(&chroot_file), mode, opt); + gc_free(&gc); } - else + else { - /* No chroot in play, just call core file check function */ - ret = check_file_access(type, file, mode, opt); + /* No chroot in play, just call core file check function */ + ret = check_file_access(type, file, mode, opt); } - return ret; + return ret; } @@ -2855,34 +3201,38 @@ check_file_access_chroot(const char *chroot, const int type, const char *file, c static bool check_cmd_access(const char *command, const char *opt, const char *chroot) { - struct argv argv; - bool return_code; - - /* If no command was set, there are no errors to look for */ - if (! command) - return false; - - /* Extract executable path and arguments */ - argv = argv_new (); - argv_parse_cmd (&argv, command); - - /* if an executable is specified then check it; otherwise, complain */ - if (argv.argv[0]) - /* Scripts requires R_OK as well, but that might fail on binaries which - * only requires X_OK to function on Unix - a scenario not unlikely to - * be seen on suid binaries. - */ - return_code = check_file_access_chroot(chroot, CHKACC_FILE, argv.argv[0], X_OK, opt); - else + struct argv argv; + bool return_code; + + /* If no command was set, there are no errors to look for */ + if (!command) + { + return false; + } + + /* Extract executable path and arguments */ + argv = argv_new(); + argv_parse_cmd(&argv, command); + + /* if an executable is specified then check it; otherwise, complain */ + if (argv.argv[0]) + { + /* Scripts requires R_OK as well, but that might fail on binaries which + * only requires X_OK to function on Unix - a scenario not unlikely to + * be seen on suid binaries. + */ + return_code = check_file_access_chroot(chroot, CHKACC_FILE, argv.argv[0], X_OK, opt); + } + else { - msg (M_NOPREFIX|M_OPTERR, "%s fails with '%s': No path to executable.", - opt, command); - return_code = true; + msg(M_NOPREFIX|M_OPTERR, "%s fails with '%s': No path to executable.", + opt, command); + return_code = true; } - argv_reset (&argv); + argv_reset(&argv); - return return_code; + return return_code; } /* @@ -2890,84 +3240,90 @@ check_cmd_access(const char *command, const char *opt, const char *chroot) * is accessible by OpenVPN */ static void -options_postprocess_filechecks (struct options *options) +options_postprocess_filechecks(struct options *options) { - bool errs = false; + bool errs = false; #ifdef ENABLE_CRYPTO - /* ** SSL/TLS/crypto related files ** */ - errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE, options->dh_file, R_OK, "--dh"); - errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE, options->ca_file, R_OK, "--ca"); - errs |= check_file_access_chroot (options->chroot_dir, CHKACC_FILE, options->ca_path, R_OK, "--capath"); - errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE, options->cert_file, R_OK, "--cert"); - errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE, options->extra_certs_file, R_OK, - "--extra-certs"); + /* ** SSL/TLS/crypto related files ** */ + errs |= check_file_access(CHKACC_FILE|CHKACC_INLINE, options->dh_file, R_OK, "--dh"); + errs |= check_file_access(CHKACC_FILE|CHKACC_INLINE, options->ca_file, R_OK, "--ca"); + errs |= check_file_access_chroot(options->chroot_dir, CHKACC_FILE, options->ca_path, R_OK, "--capath"); + errs |= check_file_access(CHKACC_FILE|CHKACC_INLINE, options->cert_file, R_OK, "--cert"); + errs |= check_file_access(CHKACC_FILE|CHKACC_INLINE, options->extra_certs_file, R_OK, + "--extra-certs"); #ifdef MANAGMENT_EXTERNAL_KEY - if(!(options->management_flags & MF_EXTERNAL_KEY)) -#endif - { - errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE|CHKACC_PRIVATE, - options->priv_key_file, R_OK, "--key"); - } - errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE|CHKACC_PRIVATE, - options->pkcs12_file, R_OK, "--pkcs12"); - - if (options->ssl_flags & SSLF_CRL_VERIFY_DIR) - errs |= check_file_access_chroot (options->chroot_dir, CHKACC_FILE, options->crl_file, R_OK|X_OK, - "--crl-verify directory"); - else - errs |= check_file_access_chroot (options->chroot_dir, CHKACC_FILE|CHKACC_INLINE, - options->crl_file, R_OK, "--crl-verify"); - - errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE|CHKACC_PRIVATE, - options->tls_auth_file, R_OK, "--tls-auth"); - errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE|CHKACC_PRIVATE, - options->tls_crypt_file, R_OK, "--tls-crypt"); - errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE|CHKACC_PRIVATE, - options->shared_secret_file, R_OK, "--secret"); - errs |= check_file_access (CHKACC_DIRPATH|CHKACC_FILEXSTWR, - options->packet_id_file, R_OK|W_OK, "--replay-persist"); - - /* ** Password files ** */ - errs |= check_file_access (CHKACC_FILE|CHKACC_ACPTSTDIN|CHKACC_PRIVATE, - options->key_pass_file, R_OK, "--askpass"); + if (!(options->management_flags & MF_EXTERNAL_KEY)) +#endif + { + errs |= check_file_access(CHKACC_FILE|CHKACC_INLINE|CHKACC_PRIVATE, + options->priv_key_file, R_OK, "--key"); + } + errs |= check_file_access(CHKACC_FILE|CHKACC_INLINE|CHKACC_PRIVATE, + options->pkcs12_file, R_OK, "--pkcs12"); + + if (options->ssl_flags & SSLF_CRL_VERIFY_DIR) + { + errs |= check_file_access_chroot(options->chroot_dir, CHKACC_FILE, options->crl_file, R_OK|X_OK, + "--crl-verify directory"); + } + else + { + errs |= check_file_access_chroot(options->chroot_dir, CHKACC_FILE|CHKACC_INLINE, + options->crl_file, R_OK, "--crl-verify"); + } + + errs |= check_file_access(CHKACC_FILE|CHKACC_INLINE|CHKACC_PRIVATE, + options->tls_auth_file, R_OK, "--tls-auth"); + errs |= check_file_access(CHKACC_FILE|CHKACC_INLINE|CHKACC_PRIVATE, + options->tls_crypt_file, R_OK, "--tls-crypt"); + errs |= check_file_access(CHKACC_FILE|CHKACC_INLINE|CHKACC_PRIVATE, + options->shared_secret_file, R_OK, "--secret"); + errs |= check_file_access(CHKACC_DIRPATH|CHKACC_FILEXSTWR, + options->packet_id_file, R_OK|W_OK, "--replay-persist"); + + /* ** Password files ** */ + errs |= check_file_access(CHKACC_FILE|CHKACC_ACPTSTDIN|CHKACC_PRIVATE, + options->key_pass_file, R_OK, "--askpass"); #endif /* ENABLE_CRYPTO */ #ifdef ENABLE_MANAGEMENT - errs |= check_file_access (CHKACC_FILE|CHKACC_ACPTSTDIN|CHKACC_PRIVATE, - options->management_user_pass, R_OK, - "--management user/password file"); + errs |= check_file_access(CHKACC_FILE|CHKACC_ACPTSTDIN|CHKACC_PRIVATE, + options->management_user_pass, R_OK, + "--management user/password file"); #endif /* ENABLE_MANAGEMENT */ #if P2MP - errs |= check_file_access (CHKACC_FILE|CHKACC_ACPTSTDIN|CHKACC_PRIVATE, - options->auth_user_pass_file, R_OK, - "--auth-user-pass"); + errs |= check_file_access(CHKACC_FILE|CHKACC_ACPTSTDIN|CHKACC_PRIVATE, + options->auth_user_pass_file, R_OK, + "--auth-user-pass"); #endif /* P2MP */ - /* ** System related ** */ - errs |= check_file_access (CHKACC_FILE, options->chroot_dir, - R_OK|X_OK, "--chroot directory"); - errs |= check_file_access (CHKACC_DIRPATH|CHKACC_FILEXSTWR, options->writepid, - R_OK|W_OK, "--writepid"); + /* ** System related ** */ + errs |= check_file_access(CHKACC_FILE, options->chroot_dir, + R_OK|X_OK, "--chroot directory"); + errs |= check_file_access(CHKACC_DIRPATH|CHKACC_FILEXSTWR, options->writepid, + R_OK|W_OK, "--writepid"); - /* ** Log related ** */ - errs |= check_file_access (CHKACC_DIRPATH|CHKACC_FILEXSTWR, options->status_file, - R_OK|W_OK, "--status"); + /* ** Log related ** */ + errs |= check_file_access(CHKACC_DIRPATH|CHKACC_FILEXSTWR, options->status_file, + R_OK|W_OK, "--status"); - /* ** Config related ** */ + /* ** Config related ** */ #ifdef ENABLE_CRYPTO - errs |= check_file_access_chroot (options->chroot_dir, CHKACC_FILE, options->tls_export_cert, - R_OK|W_OK|X_OK, "--tls-export-cert"); + errs |= check_file_access_chroot(options->chroot_dir, CHKACC_FILE, options->tls_export_cert, + R_OK|W_OK|X_OK, "--tls-export-cert"); #endif /* ENABLE_CRYPTO */ #if P2MP_SERVER - errs |= check_file_access_chroot (options->chroot_dir, CHKACC_FILE, options->client_config_dir, - R_OK|X_OK, "--client-config-dir"); - errs |= check_file_access_chroot (options->chroot_dir, CHKACC_FILE, options->tmp_dir, - R_OK|W_OK|X_OK, "Temporary directory (--tmp-dir)"); + errs |= check_file_access_chroot(options->chroot_dir, CHKACC_FILE, options->client_config_dir, + R_OK|X_OK, "--client-config-dir"); + errs |= check_file_access_chroot(options->chroot_dir, CHKACC_FILE, options->tmp_dir, + R_OK|W_OK|X_OK, "Temporary directory (--tmp-dir)"); #endif /* P2MP_SERVER */ - if (errs) - msg (M_USAGE, "Please correct these errors."); + if (errs) + { + msg(M_USAGE, "Please correct these errors."); + } } #endif /* !ENABLE_SMALL */ @@ -2977,12 +3333,12 @@ options_postprocess_filechecks (struct options *options) * options. */ void -options_postprocess (struct options *options) +options_postprocess(struct options *options) { - options_postprocess_mutate (options); - options_postprocess_verify (options); + options_postprocess_mutate(options); + options_postprocess_verify(options); #ifndef ENABLE_SMALL - options_postprocess_filechecks (options); + options_postprocess_filechecks(options); #endif /* !ENABLE_SMALL */ } @@ -2993,74 +3349,82 @@ options_postprocess (struct options *options) */ void -pre_pull_save (struct options *o) +pre_pull_save(struct options *o) { - if (o->pull) - { - ALLOC_OBJ_CLEAR_GC (o->pre_pull, struct options_pre_pull, &o->gc); - o->pre_pull->tuntap_options = o->tuntap_options; - o->pre_pull->tuntap_options_defined = true; - o->pre_pull->foreign_option_index = o->foreign_option_index; - if (o->routes) - { - o->pre_pull->routes = clone_route_option_list(o->routes, &o->gc); - o->pre_pull->routes_defined = true; - } - if (o->routes_ipv6) - { - o->pre_pull->routes_ipv6 = clone_route_ipv6_option_list(o->routes_ipv6, &o->gc); - o->pre_pull->routes_ipv6_defined = true; - } - if (o->client_nat) - { - o->pre_pull->client_nat = clone_client_nat_option_list(o->client_nat, &o->gc); - o->pre_pull->client_nat_defined = true; - } + if (o->pull) + { + ALLOC_OBJ_CLEAR_GC(o->pre_pull, struct options_pre_pull, &o->gc); + o->pre_pull->tuntap_options = o->tuntap_options; + o->pre_pull->tuntap_options_defined = true; + o->pre_pull->foreign_option_index = o->foreign_option_index; + if (o->routes) + { + o->pre_pull->routes = clone_route_option_list(o->routes, &o->gc); + o->pre_pull->routes_defined = true; + } + if (o->routes_ipv6) + { + o->pre_pull->routes_ipv6 = clone_route_ipv6_option_list(o->routes_ipv6, &o->gc); + o->pre_pull->routes_ipv6_defined = true; + } + if (o->client_nat) + { + o->pre_pull->client_nat = clone_client_nat_option_list(o->client_nat, &o->gc); + o->pre_pull->client_nat_defined = true; + } } } void -pre_pull_restore (struct options *o, struct gc_arena *gc) +pre_pull_restore(struct options *o, struct gc_arena *gc) { - const struct options_pre_pull *pp = o->pre_pull; - if (pp) - { - CLEAR (o->tuntap_options); - if (pp->tuntap_options_defined) - o->tuntap_options = pp->tuntap_options; - - if (pp->routes_defined) - { - rol_check_alloc (o); - copy_route_option_list (o->routes, pp->routes, gc); - } - else - o->routes = NULL; - - if (pp->routes_ipv6_defined) - { - rol6_check_alloc (o); - copy_route_ipv6_option_list (o->routes_ipv6, pp->routes_ipv6, gc); - } - else - o->routes_ipv6 = NULL; - - if (pp->client_nat_defined) - { - cnol_check_alloc (o); - copy_client_nat_option_list (o->client_nat, pp->client_nat); - } - else - o->client_nat = NULL; - - o->foreign_option_index = pp->foreign_option_index; - } - - o->push_continuation = 0; - o->push_option_types_found = 0; + const struct options_pre_pull *pp = o->pre_pull; + if (pp) + { + CLEAR(o->tuntap_options); + if (pp->tuntap_options_defined) + { + o->tuntap_options = pp->tuntap_options; + } + + if (pp->routes_defined) + { + rol_check_alloc(o); + copy_route_option_list(o->routes, pp->routes, gc); + } + else + { + o->routes = NULL; + } + + if (pp->routes_ipv6_defined) + { + rol6_check_alloc(o); + copy_route_ipv6_option_list(o->routes_ipv6, pp->routes_ipv6, gc); + } + else + { + o->routes_ipv6 = NULL; + } + + if (pp->client_nat_defined) + { + cnol_check_alloc(o); + copy_client_nat_option_list(o->client_nat, pp->client_nat); + } + else + { + o->client_nat = NULL; + } + + o->foreign_option_index = pp->foreign_option_index; + } + + o->push_continuation = 0; + o->push_option_types_found = 0; } -#endif +#endif /* if P2MP */ #ifdef ENABLE_OCC @@ -3074,25 +3438,25 @@ pre_pull_restore (struct options *o, struct gc_arena *gc) static size_t calc_options_string_link_mtu(const struct options *o, const struct frame *frame) { - size_t link_mtu = EXPANDED_SIZE (frame); + size_t link_mtu = EXPANDED_SIZE(frame); #ifdef ENABLE_CRYPTO - if (o->pull || o->mode == MODE_SERVER) - { - struct frame fake_frame = *frame; - struct key_type fake_kt; - init_key_type (&fake_kt, o->ciphername, o->authname, o->keysize, true, - false); - frame_add_to_extra_frame (&fake_frame, -(crypto_max_overhead())); - crypto_adjust_frame_parameters (&fake_frame, &fake_kt, o->use_iv, - o->replay, cipher_kt_mode_ofb_cfb (fake_kt.cipher)); - frame_finalize(&fake_frame, o->ce.link_mtu_defined, o->ce.link_mtu, - o->ce.tun_mtu_defined, o->ce.tun_mtu); - msg (D_MTU_DEBUG, "%s: link-mtu %u -> %d", __func__, (unsigned int) link_mtu, - EXPANDED_SIZE (&fake_frame)); - link_mtu = EXPANDED_SIZE (&fake_frame); - } -#endif - return link_mtu; + if (o->pull || o->mode == MODE_SERVER) + { + struct frame fake_frame = *frame; + struct key_type fake_kt; + init_key_type(&fake_kt, o->ciphername, o->authname, o->keysize, true, + false); + frame_add_to_extra_frame(&fake_frame, -(crypto_max_overhead())); + crypto_adjust_frame_parameters(&fake_frame, &fake_kt, o->use_iv, + o->replay, cipher_kt_mode_ofb_cfb(fake_kt.cipher)); + frame_finalize(&fake_frame, o->ce.link_mtu_defined, o->ce.link_mtu, + o->ce.tun_mtu_defined, o->ce.tun_mtu); + msg(D_MTU_DEBUG, "%s: link-mtu %u -> %d", __func__, (unsigned int) link_mtu, + EXPANDED_SIZE(&fake_frame)); + link_mtu = EXPANDED_SIZE(&fake_frame); + } +#endif + return link_mtu; } /* @@ -3140,74 +3504,84 @@ calc_options_string_link_mtu(const struct options *o, const struct frame *frame) * the other end of the connection] */ char * -options_string (const struct options *o, - const struct frame *frame, - struct tuntap *tt, - bool remote, - struct gc_arena *gc) +options_string(const struct options *o, + const struct frame *frame, + struct tuntap *tt, + bool remote, + struct gc_arena *gc) { - struct buffer out = alloc_buf (OPTION_LINE_SIZE); - bool tt_local = false; + struct buffer out = alloc_buf(OPTION_LINE_SIZE); + bool tt_local = false; - buf_printf (&out, "V4"); + buf_printf(&out, "V4"); - /* - * Tunnel Options - */ - - buf_printf (&out, ",dev-type %s", dev_type_string (o->dev, o->dev_type)); - buf_printf (&out, ",link-mtu %u", (unsigned int) calc_options_string_link_mtu(o, frame)); - buf_printf (&out, ",tun-mtu %d", PAYLOAD_SIZE (frame)); - buf_printf (&out, ",proto %s", proto_remote (o->ce.proto, remote)); + /* + * Tunnel Options + */ - /* send tun_ipv6 only in peer2peer mode - in client/server mode, it - * is usually pushed by the server, triggering a non-helpful warning - */ - if (o->ifconfig_ipv6_local && o->mode == MODE_POINT_TO_POINT && !PULL_DEFINED(o)) - buf_printf (&out, ",tun-ipv6"); + buf_printf(&out, ",dev-type %s", dev_type_string(o->dev, o->dev_type)); + buf_printf(&out, ",link-mtu %u", (unsigned int) calc_options_string_link_mtu(o, frame)); + buf_printf(&out, ",tun-mtu %d", PAYLOAD_SIZE(frame)); + buf_printf(&out, ",proto %s", proto_remote(o->ce.proto, remote)); - /* - * Try to get ifconfig parameters into the options string. - * If tt is undefined, make a temporary instantiation. - */ - if (!tt) + /* send tun_ipv6 only in peer2peer mode - in client/server mode, it + * is usually pushed by the server, triggering a non-helpful warning + */ + if (o->ifconfig_ipv6_local && o->mode == MODE_POINT_TO_POINT && !PULL_DEFINED(o)) { - tt = init_tun (o->dev, - o->dev_type, - o->topology, - o->ifconfig_local, - o->ifconfig_remote_netmask, - o->ifconfig_ipv6_local, - o->ifconfig_ipv6_netbits, - o->ifconfig_ipv6_remote, - NULL, - NULL, - false, - NULL); - if (tt) - tt_local = true; + buf_printf(&out, ",tun-ipv6"); + } + + /* + * Try to get ifconfig parameters into the options string. + * If tt is undefined, make a temporary instantiation. + */ + if (!tt) + { + tt = init_tun(o->dev, + o->dev_type, + o->topology, + o->ifconfig_local, + o->ifconfig_remote_netmask, + o->ifconfig_ipv6_local, + o->ifconfig_ipv6_netbits, + o->ifconfig_ipv6_remote, + NULL, + NULL, + false, + NULL); + if (tt) + { + tt_local = true; + } } - if (tt && o->mode == MODE_POINT_TO_POINT && !PULL_DEFINED(o)) + if (tt && o->mode == MODE_POINT_TO_POINT && !PULL_DEFINED(o)) { - const char *ios = ifconfig_options_string (tt, remote, o->ifconfig_nowarn, gc); - if (ios && strlen (ios)) - buf_printf (&out, ",ifconfig %s", ios); + const char *ios = ifconfig_options_string(tt, remote, o->ifconfig_nowarn, gc); + if (ios && strlen(ios)) + { + buf_printf(&out, ",ifconfig %s", ios); + } } - if (tt_local) + if (tt_local) { - free (tt); - tt = NULL; + free(tt); + tt = NULL; } #ifdef USE_COMP - if (o->comp.alg != COMP_ALG_UNDEF) - buf_printf (&out, ",comp-lzo"); /* for compatibility, this simply indicates that compression context is active, not necessarily LZO per-se */ + if (o->comp.alg != COMP_ALG_UNDEF) + { + buf_printf(&out, ",comp-lzo"); /* for compatibility, this simply indicates that compression context is active, not necessarily LZO per-se */ + } #endif #ifdef ENABLE_FRAGMENT - if (o->ce.fragment) - buf_printf (&out, ",mtu-dynamic"); + if (o->ce.fragment) + { + buf_printf(&out, ",mtu-dynamic"); + } #endif #ifdef ENABLE_CRYPTO @@ -3215,85 +3589,107 @@ options_string (const struct options *o, #define TLS_CLIENT (o->tls_client) #define TLS_SERVER (o->tls_server) - /* - * Key direction - */ - { - const char *kd = keydirection2ascii (o->key_direction, remote); - if (kd) - buf_printf (&out, ",keydir %s", kd); - } - - /* - * Crypto Options - */ + /* + * Key direction + */ + { + const char *kd = keydirection2ascii(o->key_direction, remote); + if (kd) + { + buf_printf(&out, ",keydir %s", kd); + } + } + + /* + * Crypto Options + */ if (o->shared_secret_file || TLS_CLIENT || TLS_SERVER) - { - struct key_type kt; - - ASSERT ((o->shared_secret_file != NULL) - + (TLS_CLIENT == true) - + (TLS_SERVER == true) - <= 1); - - init_key_type (&kt, o->ciphername, o->authname, o->keysize, true, - false); - - buf_printf (&out, ",cipher %s", - translate_cipher_name_to_openvpn(cipher_kt_name (kt.cipher))); - buf_printf (&out, ",auth %s", md_kt_name (kt.digest)); - buf_printf (&out, ",keysize %d", kt.cipher_length * 8); - if (o->shared_secret_file) - buf_printf (&out, ",secret"); - if (!o->replay) - buf_printf (&out, ",no-replay"); - if (!o->use_iv) - buf_printf (&out, ",no-iv"); + { + struct key_type kt; + + ASSERT((o->shared_secret_file != NULL) + + (TLS_CLIENT == true) + + (TLS_SERVER == true) + <= 1); + + init_key_type(&kt, o->ciphername, o->authname, o->keysize, true, + false); + + buf_printf(&out, ",cipher %s", + translate_cipher_name_to_openvpn(cipher_kt_name(kt.cipher))); + buf_printf(&out, ",auth %s", md_kt_name(kt.digest)); + buf_printf(&out, ",keysize %d", kt.cipher_length * 8); + if (o->shared_secret_file) + { + buf_printf(&out, ",secret"); + } + if (!o->replay) + { + buf_printf(&out, ",no-replay"); + } + if (!o->use_iv) + { + buf_printf(&out, ",no-iv"); + } #ifdef ENABLE_PREDICTION_RESISTANCE if (o->use_prediction_resistance) - buf_printf (&out, ",use-prediction-resistance"); -#endif - } - - /* - * SSL Options - */ - { - if (TLS_CLIENT || TLS_SERVER) - { - if (o->tls_auth_file) - buf_printf (&out, ",tls-auth"); - /* Not adding tls-crypt here, because we won't reach this code if - * tls-auth/tls-crypt does not match. Removing tls-auth here would - * break stuff, so leaving that in place. */ - - if (o->key_method > 1) - buf_printf (&out, ",key-method %d", o->key_method); - } - - if (remote) - { - if (TLS_CLIENT) - buf_printf (&out, ",tls-server"); - else if (TLS_SERVER) - buf_printf (&out, ",tls-client"); - } - else - { - if (TLS_CLIENT) - buf_printf (&out, ",tls-client"); - else if (TLS_SERVER) - buf_printf (&out, ",tls-server"); - } - } + { + buf_printf(&out, ",use-prediction-resistance"); + } +#endif + } + + /* + * SSL Options + */ + { + if (TLS_CLIENT || TLS_SERVER) + { + if (o->tls_auth_file) + { + buf_printf(&out, ",tls-auth"); + } + /* Not adding tls-crypt here, because we won't reach this code if + * tls-auth/tls-crypt does not match. Removing tls-auth here would + * break stuff, so leaving that in place. */ + + if (o->key_method > 1) + { + buf_printf(&out, ",key-method %d", o->key_method); + } + } + + if (remote) + { + if (TLS_CLIENT) + { + buf_printf(&out, ",tls-server"); + } + else if (TLS_SERVER) + { + buf_printf(&out, ",tls-client"); + } + } + else + { + if (TLS_CLIENT) + { + buf_printf(&out, ",tls-client"); + } + else if (TLS_SERVER) + { + buf_printf(&out, ",tls-server"); + } + } + } #undef TLS_CLIENT #undef TLS_SERVER #endif /* ENABLE_CRYPTO */ - return BSTR (&out); + return BSTR(&out); } /* @@ -3304,234 +3700,244 @@ options_string (const struct options *o, */ bool -options_cmp_equal (char *actual, const char *expected) +options_cmp_equal(char *actual, const char *expected) { - return options_cmp_equal_safe (actual, expected, strlen (actual) + 1); + return options_cmp_equal_safe(actual, expected, strlen(actual) + 1); } void -options_warning (char *actual, const char *expected) +options_warning(char *actual, const char *expected) { - options_warning_safe (actual, expected, strlen (actual) + 1); + options_warning_safe(actual, expected, strlen(actual) + 1); } static const char * -options_warning_extract_parm1 (const char *option_string, - struct gc_arena *gc_ret) +options_warning_extract_parm1(const char *option_string, + struct gc_arena *gc_ret) { - struct gc_arena gc = gc_new (); - struct buffer b = string_alloc_buf (option_string, &gc); - char *p = gc_malloc (OPTION_PARM_SIZE, false, &gc); - const char *ret; - - buf_parse (&b, ' ', p, OPTION_PARM_SIZE); - ret = string_alloc (p, gc_ret); - gc_free (&gc); - return ret; + struct gc_arena gc = gc_new(); + struct buffer b = string_alloc_buf(option_string, &gc); + char *p = gc_malloc(OPTION_PARM_SIZE, false, &gc); + const char *ret; + + buf_parse(&b, ' ', p, OPTION_PARM_SIZE); + ret = string_alloc(p, gc_ret); + gc_free(&gc); + return ret; } static void -options_warning_safe_scan2 (const int msglevel, - const int delim, - const bool report_inconsistent, - const char *p1, - const struct buffer *b2_src, - const char *b1_name, - const char *b2_name) +options_warning_safe_scan2(const int msglevel, + const int delim, + const bool report_inconsistent, + const char *p1, + const struct buffer *b2_src, + const char *b1_name, + const char *b2_name) { - /* we will stop sending 'proto xxx' in OCC in a future version - * (because it's not useful), and to reduce questions when - * interoperating, we start not-printing a warning about it today - */ - if (strncmp(p1, "proto ", 6) == 0 ) - { - return; - } - - if (strlen (p1) > 0) - { - struct gc_arena gc = gc_new (); - struct buffer b2 = *b2_src; - const char *p1_prefix = options_warning_extract_parm1 (p1, &gc); - char *p2 = gc_malloc (OPTION_PARM_SIZE, false, &gc); - - while (buf_parse (&b2, delim, p2, OPTION_PARM_SIZE)) - { - if (strlen (p2)) - { - const char *p2_prefix = options_warning_extract_parm1 (p2, &gc); - - if (!strcmp (p1, p2)) - goto done; - if (!strcmp (p1_prefix, p2_prefix)) - { - if (report_inconsistent) - msg (msglevel, "WARNING: '%s' is used inconsistently, %s='%s', %s='%s'", - safe_print (p1_prefix, &gc), - b1_name, - safe_print (p1, &gc), - b2_name, - safe_print (p2, &gc)); - goto done; - } - } - } - - msg (msglevel, "WARNING: '%s' is present in %s config but missing in %s config, %s='%s'", - safe_print (p1_prefix, &gc), - b1_name, - b2_name, - b1_name, - safe_print (p1, &gc)); - - done: - gc_free (&gc); + /* we will stop sending 'proto xxx' in OCC in a future version + * (because it's not useful), and to reduce questions when + * interoperating, we start not-printing a warning about it today + */ + if (strncmp(p1, "proto ", 6) == 0) + { + return; + } + + if (strlen(p1) > 0) + { + struct gc_arena gc = gc_new(); + struct buffer b2 = *b2_src; + const char *p1_prefix = options_warning_extract_parm1(p1, &gc); + char *p2 = gc_malloc(OPTION_PARM_SIZE, false, &gc); + + while (buf_parse(&b2, delim, p2, OPTION_PARM_SIZE)) + { + if (strlen(p2)) + { + const char *p2_prefix = options_warning_extract_parm1(p2, &gc); + + if (!strcmp(p1, p2)) + { + goto done; + } + if (!strcmp(p1_prefix, p2_prefix)) + { + if (report_inconsistent) + { + msg(msglevel, "WARNING: '%s' is used inconsistently, %s='%s', %s='%s'", + safe_print(p1_prefix, &gc), + b1_name, + safe_print(p1, &gc), + b2_name, + safe_print(p2, &gc)); + } + goto done; + } + } + } + + msg(msglevel, "WARNING: '%s' is present in %s config but missing in %s config, %s='%s'", + safe_print(p1_prefix, &gc), + b1_name, + b2_name, + b1_name, + safe_print(p1, &gc)); + +done: + gc_free(&gc); } } static void -options_warning_safe_scan1 (const int msglevel, - const int delim, - const bool report_inconsistent, - const struct buffer *b1_src, - const struct buffer *b2_src, - const char *b1_name, - const char *b2_name) +options_warning_safe_scan1(const int msglevel, + const int delim, + const bool report_inconsistent, + const struct buffer *b1_src, + const struct buffer *b2_src, + const char *b1_name, + const char *b2_name) { - struct gc_arena gc = gc_new (); - struct buffer b = *b1_src; - char *p = gc_malloc (OPTION_PARM_SIZE, true, &gc); + struct gc_arena gc = gc_new(); + struct buffer b = *b1_src; + char *p = gc_malloc(OPTION_PARM_SIZE, true, &gc); - while (buf_parse (&b, delim, p, OPTION_PARM_SIZE)) - options_warning_safe_scan2 (msglevel, delim, report_inconsistent, p, b2_src, b1_name, b2_name); + while (buf_parse(&b, delim, p, OPTION_PARM_SIZE)) + options_warning_safe_scan2(msglevel, delim, report_inconsistent, p, b2_src, b1_name, b2_name); - gc_free (&gc); + gc_free(&gc); } static void -options_warning_safe_ml (const int msglevel, char *actual, const char *expected, size_t actual_n) +options_warning_safe_ml(const int msglevel, char *actual, const char *expected, size_t actual_n) { - struct gc_arena gc = gc_new (); + struct gc_arena gc = gc_new(); - if (actual_n > 0) + if (actual_n > 0) { - struct buffer local = alloc_buf_gc (OPTION_PARM_SIZE + 16, &gc); - struct buffer remote = alloc_buf_gc (OPTION_PARM_SIZE + 16, &gc); - actual[actual_n - 1] = 0; + struct buffer local = alloc_buf_gc(OPTION_PARM_SIZE + 16, &gc); + struct buffer remote = alloc_buf_gc(OPTION_PARM_SIZE + 16, &gc); + actual[actual_n - 1] = 0; - buf_printf (&local, "version %s", expected); - buf_printf (&remote, "version %s", actual); + buf_printf(&local, "version %s", expected); + buf_printf(&remote, "version %s", actual); - options_warning_safe_scan1 (msglevel, ',', true, - &local, &remote, - "local", "remote"); + options_warning_safe_scan1(msglevel, ',', true, + &local, &remote, + "local", "remote"); - options_warning_safe_scan1 (msglevel, ',', false, - &remote, &local, - "remote", "local"); + options_warning_safe_scan1(msglevel, ',', false, + &remote, &local, + "remote", "local"); } - gc_free (&gc); + gc_free(&gc); } bool -options_cmp_equal_safe (char *actual, const char *expected, size_t actual_n) +options_cmp_equal_safe(char *actual, const char *expected, size_t actual_n) { - struct gc_arena gc = gc_new (); - bool ret = true; + struct gc_arena gc = gc_new(); + bool ret = true; - if (actual_n > 0) + if (actual_n > 0) { - actual[actual_n - 1] = 0; + actual[actual_n - 1] = 0; #ifndef ENABLE_STRICT_OPTIONS_CHECK - if (strncmp (actual, expected, 2)) - { - msg (D_SHOW_OCC, "NOTE: Options consistency check may be skewed by version differences"); - options_warning_safe_ml (D_SHOW_OCC, actual, expected, actual_n); - } - else + if (strncmp(actual, expected, 2)) + { + msg(D_SHOW_OCC, "NOTE: Options consistency check may be skewed by version differences"); + options_warning_safe_ml(D_SHOW_OCC, actual, expected, actual_n); + } + else #endif - ret = !strcmp (actual, expected); + ret = !strcmp(actual, expected); } - gc_free (&gc); - return ret; + gc_free(&gc); + return ret; } void -options_warning_safe (char *actual, const char *expected, size_t actual_n) +options_warning_safe(char *actual, const char *expected, size_t actual_n) { - options_warning_safe_ml (M_WARN, actual, expected, actual_n); + options_warning_safe_ml(M_WARN, actual, expected, actual_n); } const char * -options_string_version (const char* s, struct gc_arena *gc) +options_string_version(const char *s, struct gc_arena *gc) { - struct buffer out = alloc_buf_gc (4, gc); - strncpynt ((char *) BPTR (&out), s, 3); - return BSTR (&out); + struct buffer out = alloc_buf_gc(4, gc); + strncpynt((char *) BPTR(&out), s, 3); + return BSTR(&out); } #endif /* ENABLE_OCC */ char * -options_string_extract_option (const char *options_string,const char *opt_name, - struct gc_arena *gc) +options_string_extract_option(const char *options_string,const char *opt_name, + struct gc_arena *gc) { - char *ret = NULL; - const size_t opt_name_len = strlen(opt_name); - - const char *p = options_string; - while (p) - { - if (0 == strncmp(p, opt_name, opt_name_len) && - strlen(p) > (opt_name_len+1) && p[opt_name_len] == ' ') - { - /* option found, extract value */ - const char *start = &p[opt_name_len+1]; - const char *end = strchr (p, ','); - size_t val_len = end ? end - start : strlen (start); - ret = gc_malloc (val_len+1, true, gc); - memcpy (ret, start, val_len); - break; - } - p = strchr (p, ','); - if (p) - { - p++; /* skip delimiter */ - } - } - return ret; + char *ret = NULL; + const size_t opt_name_len = strlen(opt_name); + + const char *p = options_string; + while (p) + { + if (0 == strncmp(p, opt_name, opt_name_len) + && strlen(p) > (opt_name_len+1) && p[opt_name_len] == ' ') + { + /* option found, extract value */ + const char *start = &p[opt_name_len+1]; + const char *end = strchr(p, ','); + size_t val_len = end ? end - start : strlen(start); + ret = gc_malloc(val_len+1, true, gc); + memcpy(ret, start, val_len); + break; + } + p = strchr(p, ','); + if (p) + { + p++; /* skip delimiter */ + } + } + return ret; } static void -foreign_option (struct options *o, char *argv[], int len, struct env_set *es) +foreign_option(struct options *o, char *argv[], int len, struct env_set *es) { - if (len > 0) - { - struct gc_arena gc = gc_new(); - struct buffer name = alloc_buf_gc (OPTION_PARM_SIZE, &gc); - struct buffer value = alloc_buf_gc (OPTION_PARM_SIZE, &gc); - int i; - bool first = true; - bool good = true; - - good &= buf_printf (&name, "foreign_option_%d", o->foreign_option_index + 1); - ++o->foreign_option_index; - for (i = 0; i < len; ++i) - { - if (argv[i]) - { - if (!first) - good &= buf_printf (&value, " "); - good &= buf_printf (&value, "%s", argv[i]); - first = false; - } - } - if (good) - setenv_str (es, BSTR(&name), BSTR(&value)); - else - msg (M_WARN, "foreign_option: name/value overflow"); - gc_free (&gc); + if (len > 0) + { + struct gc_arena gc = gc_new(); + struct buffer name = alloc_buf_gc(OPTION_PARM_SIZE, &gc); + struct buffer value = alloc_buf_gc(OPTION_PARM_SIZE, &gc); + int i; + bool first = true; + bool good = true; + + good &= buf_printf(&name, "foreign_option_%d", o->foreign_option_index + 1); + ++o->foreign_option_index; + for (i = 0; i < len; ++i) + { + if (argv[i]) + { + if (!first) + { + good &= buf_printf(&value, " "); + } + good &= buf_printf(&value, "%s", argv[i]); + first = false; + } + } + if (good) + { + setenv_str(es, BSTR(&name), BSTR(&value)); + } + else + { + msg(M_WARN, "foreign_option: name/value overflow"); + } + gc_free(&gc); } } @@ -3540,36 +3946,46 @@ foreign_option (struct options *o, char *argv[], int len, struct env_set *es) */ int -parse_topology (const char *str, const int msglevel) +parse_topology(const char *str, const int msglevel) { - if (streq (str, "net30")) - return TOP_NET30; - else if (streq (str, "p2p")) - return TOP_P2P; - else if (streq (str, "subnet")) - return TOP_SUBNET; - else + if (streq(str, "net30")) + { + return TOP_NET30; + } + else if (streq(str, "p2p")) + { + return TOP_P2P; + } + else if (streq(str, "subnet")) + { + return TOP_SUBNET; + } + else { - msg (msglevel, "--topology must be net30, p2p, or subnet"); - return TOP_UNDEF; + msg(msglevel, "--topology must be net30, p2p, or subnet"); + return TOP_UNDEF; } } const char * -print_topology (const int topology) +print_topology(const int topology) { - switch (topology) - { - case TOP_UNDEF: - return "undef"; - case TOP_NET30: - return "net30"; - case TOP_P2P: - return "p2p"; - case TOP_SUBNET: - return "subnet"; - default: - return "unknown"; + switch (topology) + { + case TOP_UNDEF: + return "undef"; + + case TOP_NET30: + return "net30"; + + case TOP_P2P: + return "p2p"; + + case TOP_SUBNET: + return "subnet"; + + default: + return "unknown"; } } @@ -3582,103 +3998,113 @@ print_topology (const int topology) static int global_auth_retry; /* GLOBAL */ int -auth_retry_get (void) +auth_retry_get(void) { - return global_auth_retry; + return global_auth_retry; } bool -auth_retry_set (const int msglevel, const char *option) +auth_retry_set(const int msglevel, const char *option) { - if (streq (option, "interact")) - global_auth_retry = AR_INTERACT; - else if (streq (option, "nointeract")) - global_auth_retry = AR_NOINTERACT; - else if (streq (option, "none")) - global_auth_retry = AR_NONE; - else - { - msg (msglevel, "--auth-retry method must be 'interact', 'nointeract', or 'none'"); - return false; - } - return true; + if (streq(option, "interact")) + { + global_auth_retry = AR_INTERACT; + } + else if (streq(option, "nointeract")) + { + global_auth_retry = AR_NOINTERACT; + } + else if (streq(option, "none")) + { + global_auth_retry = AR_NONE; + } + else + { + msg(msglevel, "--auth-retry method must be 'interact', 'nointeract', or 'none'"); + return false; + } + return true; } const char * -auth_retry_print (void) +auth_retry_print(void) { - switch (global_auth_retry) + switch (global_auth_retry) { - case AR_NONE: - return "none"; - case AR_NOINTERACT: - return "nointeract"; - case AR_INTERACT: - return "interact"; - default: - return "???"; + case AR_NONE: + return "none"; + + case AR_NOINTERACT: + return "nointeract"; + + case AR_INTERACT: + return "interact"; + + default: + return "???"; } } -#endif +#endif /* if P2MP */ /* * Print the help message. */ static void -usage (void) +usage(void) { - FILE *fp = msg_fp(0); + FILE *fp = msg_fp(0); #ifdef ENABLE_SMALL - fprintf (fp, "Usage message not available\n"); + fprintf(fp, "Usage message not available\n"); #else - struct options o; - init_options (&o, true); + struct options o; + init_options(&o, true); #ifdef ENABLE_CRYPTO - fprintf (fp, usage_message, - title_string, - o.ce.connect_retry_seconds, - o.ce.connect_retry_seconds_max, - o.ce.local_port, o.ce.remote_port, - TUN_MTU_DEFAULT, TAP_MTU_EXTRA_DEFAULT, - o.verbosity, - o.authname, o.ciphername, - o.replay_window, o.replay_time, - o.tls_timeout, o.renegotiate_seconds, - o.handshake_window, o.transition_window); -#else - fprintf (fp, usage_message, - title_string, - o.ce.connect_retry_seconds, - o.ce.local_port, o.ce.remote_port, - TUN_MTU_DEFAULT, TAP_MTU_EXTRA_DEFAULT, - o.verbosity); -#endif - fflush(fp); + fprintf(fp, usage_message, + title_string, + o.ce.connect_retry_seconds, + o.ce.connect_retry_seconds_max, + o.ce.local_port, o.ce.remote_port, + TUN_MTU_DEFAULT, TAP_MTU_EXTRA_DEFAULT, + o.verbosity, + o.authname, o.ciphername, + o.replay_window, o.replay_time, + o.tls_timeout, o.renegotiate_seconds, + o.handshake_window, o.transition_window); +#else /* ifdef ENABLE_CRYPTO */ + fprintf(fp, usage_message, + title_string, + o.ce.connect_retry_seconds, + o.ce.local_port, o.ce.remote_port, + TUN_MTU_DEFAULT, TAP_MTU_EXTRA_DEFAULT, + o.verbosity); +#endif + fflush(fp); #endif /* ENABLE_SMALL */ - - openvpn_exit (OPENVPN_EXIT_STATUS_USAGE); /* exit point */ + + openvpn_exit(OPENVPN_EXIT_STATUS_USAGE); /* exit point */ } void -usage_small (void) +usage_small(void) { - msg (M_WARN|M_NOPREFIX, "Use --help for more information."); - openvpn_exit (OPENVPN_EXIT_STATUS_USAGE); /* exit point */ + msg(M_WARN|M_NOPREFIX, "Use --help for more information."); + openvpn_exit(OPENVPN_EXIT_STATUS_USAGE); /* exit point */ } #ifdef _WIN32 -void show_windows_version(const unsigned int flags) +void +show_windows_version(const unsigned int flags) { - struct gc_arena gc = gc_new (); - msg (flags, "Windows version %s", win32_version_string (&gc, true)); - gc_free (&gc); + struct gc_arena gc = gc_new(); + msg(flags, "Windows version %s", win32_version_string(&gc, true)); + gc_free(&gc); } #endif @@ -3696,507 +4122,559 @@ show_library_versions(const unsigned int flags) #define LZO_LIB_VER_STR "", "" #endif - msg (flags, "library versions: %s%s%s", SSL_LIB_VER_STR, LZO_LIB_VER_STR); + msg(flags, "library versions: %s%s%s", SSL_LIB_VER_STR, LZO_LIB_VER_STR); #undef SSL_LIB_VER_STR #undef LZO_LIB_VER_STR } static void -usage_version (void) +usage_version(void) { - msg (M_INFO|M_NOPREFIX, "%s", title_string); - show_library_versions( M_INFO|M_NOPREFIX ); + msg(M_INFO|M_NOPREFIX, "%s", title_string); + show_library_versions( M_INFO|M_NOPREFIX ); #ifdef _WIN32 - show_windows_version( M_INFO|M_NOPREFIX ); + show_windows_version( M_INFO|M_NOPREFIX ); #endif - msg (M_INFO|M_NOPREFIX, "Originally developed by James Yonan"); - msg (M_INFO|M_NOPREFIX, "Copyright (C) 2002-2016 OpenVPN Technologies, Inc. "); + msg(M_INFO|M_NOPREFIX, "Originally developed by James Yonan"); + msg(M_INFO|M_NOPREFIX, "Copyright (C) 2002-2016 OpenVPN Technologies, Inc. "); #ifndef ENABLE_SMALL #ifdef CONFIGURE_DEFINES - msg (M_INFO|M_NOPREFIX, "Compile time defines: %s", CONFIGURE_DEFINES); + msg(M_INFO|M_NOPREFIX, "Compile time defines: %s", CONFIGURE_DEFINES); #endif #ifdef CONFIGURE_SPECIAL_BUILD - msg (M_INFO|M_NOPREFIX, "special build: %s", CONFIGURE_SPECIAL_BUILD); + msg(M_INFO|M_NOPREFIX, "special build: %s", CONFIGURE_SPECIAL_BUILD); #endif #endif - openvpn_exit (OPENVPN_EXIT_STATUS_USAGE); /* exit point */ + openvpn_exit(OPENVPN_EXIT_STATUS_USAGE); /* exit point */ } void -notnull (const char *arg, const char *description) +notnull(const char *arg, const char *description) { - if (!arg) - msg (M_USAGE, "You must define %s", description); + if (!arg) + { + msg(M_USAGE, "You must define %s", description); + } } bool -string_defined_equal (const char *s1, const char *s2) +string_defined_equal(const char *s1, const char *s2) { - if (s1 && s2) - return !strcmp (s1, s2); - else - return false; + if (s1 && s2) + { + return !strcmp(s1, s2); + } + else + { + return false; + } } #if 0 static void -ping_rec_err (int msglevel) +ping_rec_err(int msglevel) { - msg (msglevel, "only one of --ping-exit or --ping-restart options may be specified"); + msg(msglevel, "only one of --ping-exit or --ping-restart options may be specified"); } #endif static int -positive_atoi (const char *str) +positive_atoi(const char *str) { - const int i = atoi (str); - return i < 0 ? 0 : i; + const int i = atoi(str); + return i < 0 ? 0 : i; } #ifdef _WIN32 /* This function is only used when compiling on Windows */ static unsigned int -atou (const char *str) +atou(const char *str) { - unsigned int val = 0; - sscanf (str, "%u", &val); - return val; + unsigned int val = 0; + sscanf(str, "%u", &val); + return val; } #endif static inline bool -space (unsigned char c) +space(unsigned char c) { - return c == '\0' || isspace (c); + return c == '\0' || isspace(c); } int -parse_line (const char *line, - char *p[], - const int n, - const char *file, - const int line_num, - int msglevel, - struct gc_arena *gc) +parse_line(const char *line, + char *p[], + const int n, + const char *file, + const int line_num, + int msglevel, + struct gc_arena *gc) { - const int STATE_INITIAL = 0; - const int STATE_READING_QUOTED_PARM = 1; - const int STATE_READING_UNQUOTED_PARM = 2; - const int STATE_DONE = 3; - const int STATE_READING_SQUOTED_PARM = 4; - - const char *error_prefix = ""; - - int ret = 0; - const char *c = line; - int state = STATE_INITIAL; - bool backslash = false; - char in, out; - - char parm[OPTION_PARM_SIZE]; - unsigned int parm_len = 0; - - msglevel &= ~M_OPTERR; - - if (msglevel & M_MSG_VIRT_OUT) - error_prefix = "ERROR: "; - - do - { - in = *c; - out = 0; - - if (!backslash && in == '\\' && state != STATE_READING_SQUOTED_PARM) - { - backslash = true; - } - else - { - if (state == STATE_INITIAL) - { - if (!space (in)) - { - if (in == ';' || in == '#') /* comment */ - break; - if (!backslash && in == '\"') - state = STATE_READING_QUOTED_PARM; - else if (!backslash && in == '\'') - state = STATE_READING_SQUOTED_PARM; - else - { - out = in; - state = STATE_READING_UNQUOTED_PARM; - } - } - } - else if (state == STATE_READING_UNQUOTED_PARM) - { - if (!backslash && space (in)) - state = STATE_DONE; - else - out = in; - } - else if (state == STATE_READING_QUOTED_PARM) - { - if (!backslash && in == '\"') - state = STATE_DONE; - else - out = in; - } - else if (state == STATE_READING_SQUOTED_PARM) - { - if (in == '\'') - state = STATE_DONE; - else - out = in; - } - if (state == STATE_DONE) - { - /* ASSERT (parm_len > 0); */ - p[ret] = gc_malloc (parm_len + 1, true, gc); - memcpy (p[ret], parm, parm_len); - p[ret][parm_len] = '\0'; - state = STATE_INITIAL; - parm_len = 0; - ++ret; - } - - if (backslash && out) - { - if (!(out == '\\' || out == '\"' || space (out))) - { + const int STATE_INITIAL = 0; + const int STATE_READING_QUOTED_PARM = 1; + const int STATE_READING_UNQUOTED_PARM = 2; + const int STATE_DONE = 3; + const int STATE_READING_SQUOTED_PARM = 4; + + const char *error_prefix = ""; + + int ret = 0; + const char *c = line; + int state = STATE_INITIAL; + bool backslash = false; + char in, out; + + char parm[OPTION_PARM_SIZE]; + unsigned int parm_len = 0; + + msglevel &= ~M_OPTERR; + + if (msglevel & M_MSG_VIRT_OUT) + { + error_prefix = "ERROR: "; + } + + do + { + in = *c; + out = 0; + + if (!backslash && in == '\\' && state != STATE_READING_SQUOTED_PARM) + { + backslash = true; + } + else + { + if (state == STATE_INITIAL) + { + if (!space(in)) + { + if (in == ';' || in == '#') /* comment */ + { + break; + } + if (!backslash && in == '\"') + { + state = STATE_READING_QUOTED_PARM; + } + else if (!backslash && in == '\'') + { + state = STATE_READING_SQUOTED_PARM; + } + else + { + out = in; + state = STATE_READING_UNQUOTED_PARM; + } + } + } + else if (state == STATE_READING_UNQUOTED_PARM) + { + if (!backslash && space(in)) + { + state = STATE_DONE; + } + else + { + out = in; + } + } + else if (state == STATE_READING_QUOTED_PARM) + { + if (!backslash && in == '\"') + { + state = STATE_DONE; + } + else + { + out = in; + } + } + else if (state == STATE_READING_SQUOTED_PARM) + { + if (in == '\'') + { + state = STATE_DONE; + } + else + { + out = in; + } + } + if (state == STATE_DONE) + { + /* ASSERT (parm_len > 0); */ + p[ret] = gc_malloc(parm_len + 1, true, gc); + memcpy(p[ret], parm, parm_len); + p[ret][parm_len] = '\0'; + state = STATE_INITIAL; + parm_len = 0; + ++ret; + } + + if (backslash && out) + { + if (!(out == '\\' || out == '\"' || space(out))) + { #ifdef ENABLE_SMALL - msg (msglevel, "%sOptions warning: Bad backslash ('\\') usage in %s:%d", error_prefix, file, line_num); + msg(msglevel, "%sOptions warning: Bad backslash ('\\') usage in %s:%d", error_prefix, file, line_num); #else - msg (msglevel, "%sOptions warning: Bad backslash ('\\') usage in %s:%d: remember that backslashes are treated as shell-escapes and if you need to pass backslash characters as part of a Windows filename, you should use double backslashes such as \"c:\\\\" PACKAGE "\\\\static.key\"", error_prefix, file, line_num); -#endif - return 0; - } - } - backslash = false; - } - - /* store parameter character */ - if (out) - { - if (parm_len >= SIZE (parm)) - { - parm[SIZE (parm) - 1] = 0; - msg (msglevel, "%sOptions error: Parameter at %s:%d is too long (%d chars max): %s", - error_prefix, file, line_num, (int) SIZE (parm), parm); - return 0; - } - parm[parm_len++] = out; - } - - /* avoid overflow if too many parms in one config file line */ - if (ret >= n) - break; + msg(msglevel, "%sOptions warning: Bad backslash ('\\') usage in %s:%d: remember that backslashes are treated as shell-escapes and if you need to pass backslash characters as part of a Windows filename, you should use double backslashes such as \"c:\\\\" PACKAGE "\\\\static.key\"", error_prefix, file, line_num); +#endif + return 0; + } + } + backslash = false; + } + + /* store parameter character */ + if (out) + { + if (parm_len >= SIZE(parm)) + { + parm[SIZE(parm) - 1] = 0; + msg(msglevel, "%sOptions error: Parameter at %s:%d is too long (%d chars max): %s", + error_prefix, file, line_num, (int) SIZE(parm), parm); + return 0; + } + parm[parm_len++] = out; + } + + /* avoid overflow if too many parms in one config file line */ + if (ret >= n) + { + break; + } } while (*c++ != '\0'); - if (state == STATE_READING_QUOTED_PARM) + if (state == STATE_READING_QUOTED_PARM) { - msg (msglevel, "%sOptions error: No closing quotation (\") in %s:%d", error_prefix, file, line_num); - return 0; + msg(msglevel, "%sOptions error: No closing quotation (\") in %s:%d", error_prefix, file, line_num); + return 0; } - if (state == STATE_READING_SQUOTED_PARM) + if (state == STATE_READING_SQUOTED_PARM) { - msg (msglevel, "%sOptions error: No closing single quotation (\') in %s:%d", error_prefix, file, line_num); - return 0; + msg(msglevel, "%sOptions error: No closing single quotation (\') in %s:%d", error_prefix, file, line_num); + return 0; } - if (state != STATE_INITIAL) + if (state != STATE_INITIAL) { - msg (msglevel, "%sOptions error: Residual parse state (%d) in %s:%d", error_prefix, state, file, line_num); - return 0; + msg(msglevel, "%sOptions error: Residual parse state (%d) in %s:%d", error_prefix, state, file, line_num); + return 0; } #if 0 - { - int i; - for (i = 0; i < ret; ++i) - { - msg (M_INFO|M_NOPREFIX, "%s:%d ARG[%d] '%s'", file, line_num, i, p[i]); - } - } + { + int i; + for (i = 0; i < ret; ++i) + { + msg(M_INFO|M_NOPREFIX, "%s:%d ARG[%d] '%s'", file, line_num, i, p[i]); + } + } #endif return ret; } static void -bypass_doubledash (char **p) +bypass_doubledash(char **p) { - if (strlen (*p) >= 3 && !strncmp (*p, "--", 2)) - *p += 2; + if (strlen(*p) >= 3 && !strncmp(*p, "--", 2)) + { + *p += 2; + } } struct in_src { -# define IS_TYPE_FP 1 -# define IS_TYPE_BUF 2 - int type; - union { - FILE *fp; - struct buffer *multiline; - } u; +#define IS_TYPE_FP 1 +#define IS_TYPE_BUF 2 + int type; + union { + FILE *fp; + struct buffer *multiline; + } u; }; static bool -in_src_get (const struct in_src *is, char *line, const int size) +in_src_get(const struct in_src *is, char *line, const int size) { - if (is->type == IS_TYPE_FP) + if (is->type == IS_TYPE_FP) { - return BOOL_CAST (fgets (line, size, is->u.fp)); + return BOOL_CAST(fgets(line, size, is->u.fp)); } - else if (is->type == IS_TYPE_BUF) + else if (is->type == IS_TYPE_BUF) { - bool status = buf_parse (is->u.multiline, '\n', line, size); - if ((int) strlen (line) + 1 < size) - strcat (line, "\n"); - return status; + bool status = buf_parse(is->u.multiline, '\n', line, size); + if ((int) strlen(line) + 1 < size) + { + strcat(line, "\n"); + } + return status; } - else + else { - ASSERT (0); - return false; + ASSERT(0); + return false; } } static char * -read_inline_file (struct in_src *is, const char *close_tag, struct gc_arena *gc) +read_inline_file(struct in_src *is, const char *close_tag, struct gc_arena *gc) { - char line[OPTION_LINE_SIZE]; - struct buffer buf = alloc_buf (8*OPTION_LINE_SIZE); - char *ret; - bool endtagfound = false; - - while (in_src_get (is, line, sizeof (line))) - { - char *line_ptr = line; - /* Remove leading spaces */ - while (isspace(*line_ptr)) line_ptr++; - if (!strncmp (line_ptr, close_tag, strlen (close_tag))) - { - endtagfound = true; - break; - } - if (!buf_safe (&buf, strlen(line)+1)) - { - /* Increase buffer size */ - struct buffer buf2 = alloc_buf (buf.capacity * 2); - ASSERT (buf_copy (&buf2, &buf)); - buf_clear (&buf); - free_buf (&buf); - buf = buf2; - } - buf_printf (&buf, "%s", line); - } - if (!endtagfound) - msg (M_FATAL, "ERROR: Endtag %s missing", close_tag); - ret = string_alloc (BSTR (&buf), gc); - buf_clear (&buf); - free_buf (&buf); - secure_memzero (line, sizeof (line)); - return ret; + char line[OPTION_LINE_SIZE]; + struct buffer buf = alloc_buf(8*OPTION_LINE_SIZE); + char *ret; + bool endtagfound = false; + + while (in_src_get(is, line, sizeof(line))) + { + char *line_ptr = line; + /* Remove leading spaces */ + while (isspace(*line_ptr)) line_ptr++; + if (!strncmp(line_ptr, close_tag, strlen(close_tag))) + { + endtagfound = true; + break; + } + if (!buf_safe(&buf, strlen(line)+1)) + { + /* Increase buffer size */ + struct buffer buf2 = alloc_buf(buf.capacity * 2); + ASSERT(buf_copy(&buf2, &buf)); + buf_clear(&buf); + free_buf(&buf); + buf = buf2; + } + buf_printf(&buf, "%s", line); + } + if (!endtagfound) + { + msg(M_FATAL, "ERROR: Endtag %s missing", close_tag); + } + ret = string_alloc(BSTR(&buf), gc); + buf_clear(&buf); + free_buf(&buf); + secure_memzero(line, sizeof(line)); + return ret; } static bool -check_inline_file (struct in_src *is, char *p[], struct gc_arena *gc) +check_inline_file(struct in_src *is, char *p[], struct gc_arena *gc) { - bool ret = false; - if (p[0] && !p[1]) - { - char *arg = p[0]; - if (arg[0] == '<' && arg[strlen(arg)-1] == '>') - { - struct buffer close_tag; - arg[strlen(arg)-1] = '\0'; - p[0] = string_alloc (arg+1, gc); - p[1] = string_alloc (INLINE_FILE_TAG, gc); - close_tag = alloc_buf (strlen(p[0]) + 4); - buf_printf (&close_tag, "", p[0]); - p[2] = read_inline_file (is, BSTR (&close_tag), gc); - p[3] = NULL; - free_buf (&close_tag); - ret = true; - } - } - return ret; + bool ret = false; + if (p[0] && !p[1]) + { + char *arg = p[0]; + if (arg[0] == '<' && arg[strlen(arg)-1] == '>') + { + struct buffer close_tag; + arg[strlen(arg)-1] = '\0'; + p[0] = string_alloc(arg+1, gc); + p[1] = string_alloc(INLINE_FILE_TAG, gc); + close_tag = alloc_buf(strlen(p[0]) + 4); + buf_printf(&close_tag, "", p[0]); + p[2] = read_inline_file(is, BSTR(&close_tag), gc); + p[3] = NULL; + free_buf(&close_tag); + ret = true; + } + } + return ret; } static bool -check_inline_file_via_fp (FILE *fp, char *p[], struct gc_arena *gc) +check_inline_file_via_fp(FILE *fp, char *p[], struct gc_arena *gc) { - struct in_src is; - is.type = IS_TYPE_FP; - is.u.fp = fp; - return check_inline_file (&is, p, gc); + struct in_src is; + is.type = IS_TYPE_FP; + is.u.fp = fp; + return check_inline_file(&is, p, gc); } static bool -check_inline_file_via_buf (struct buffer *multiline, char *p[], struct gc_arena *gc) +check_inline_file_via_buf(struct buffer *multiline, char *p[], struct gc_arena *gc) { - struct in_src is; - is.type = IS_TYPE_BUF; - is.u.multiline = multiline; - return check_inline_file (&is, p, gc); + struct in_src is; + is.type = IS_TYPE_BUF; + is.u.multiline = multiline; + return check_inline_file(&is, p, gc); } static void -add_option (struct options *options, - char *p[], - const char *file, - int line, - const int level, - const int msglevel, - const unsigned int permission_mask, - unsigned int *option_types_found, - struct env_set *es); +add_option(struct options *options, + char *p[], + const char *file, + int line, + const int level, + const int msglevel, + const unsigned int permission_mask, + unsigned int *option_types_found, + struct env_set *es); static void -read_config_file (struct options *options, - const char *file, - int level, - const char *top_file, - const int top_line, - const int msglevel, - const unsigned int permission_mask, - unsigned int *option_types_found, - struct env_set *es) +read_config_file(struct options *options, + const char *file, + int level, + const char *top_file, + const int top_line, + const int msglevel, + const unsigned int permission_mask, + unsigned int *option_types_found, + struct env_set *es) { - const int max_recursive_levels = 10; - FILE *fp; - int line_num; - char line[OPTION_LINE_SIZE+1]; - char *p[MAX_PARMS]; - - ++level; - if (level <= max_recursive_levels) - { - if (streq (file, "stdin")) - fp = stdin; - else - fp = platform_fopen (file, "r"); - if (fp) - { - line_num = 0; - while (fgets(line, sizeof (line), fp)) - { - int offset = 0; - CLEAR (p); - ++line_num; - if (strlen(line) == OPTION_LINE_SIZE) - msg (msglevel, "In %s:%d: Maximum optione line length (%d) exceeded, line starts with %s", - file, line_num, OPTION_LINE_SIZE, line); - - /* Ignore UTF-8 BOM at start of stream */ - if (line_num == 1 && strncmp (line, "\xEF\xBB\xBF", 3) == 0) - offset = 3; - if (parse_line (line + offset, p, SIZE (p), file, line_num, msglevel, &options->gc)) - { - bypass_doubledash (&p[0]); - check_inline_file_via_fp (fp, p, &options->gc); - add_option (options, p, file, line_num, level, msglevel, permission_mask, option_types_found, es); - } - } - if (fp != stdin) - fclose (fp); - } - else - { - msg (msglevel, "In %s:%d: Error opening configuration file: %s", top_file, top_line, file); - } - } - else - { - msg (msglevel, "In %s:%d: Maximum recursive include levels exceeded in include attempt of file %s -- probably you have a configuration file that tries to include itself.", top_file, top_line, file); - } - secure_memzero (line, sizeof (line)); - CLEAR (p); + const int max_recursive_levels = 10; + FILE *fp; + int line_num; + char line[OPTION_LINE_SIZE+1]; + char *p[MAX_PARMS]; + + ++level; + if (level <= max_recursive_levels) + { + if (streq(file, "stdin")) + { + fp = stdin; + } + else + { + fp = platform_fopen(file, "r"); + } + if (fp) + { + line_num = 0; + while (fgets(line, sizeof(line), fp)) + { + int offset = 0; + CLEAR(p); + ++line_num; + if (strlen(line) == OPTION_LINE_SIZE) + { + msg(msglevel, "In %s:%d: Maximum optione line length (%d) exceeded, line starts with %s", + file, line_num, OPTION_LINE_SIZE, line); + } + + /* Ignore UTF-8 BOM at start of stream */ + if (line_num == 1 && strncmp(line, "\xEF\xBB\xBF", 3) == 0) + { + offset = 3; + } + if (parse_line(line + offset, p, SIZE(p), file, line_num, msglevel, &options->gc)) + { + bypass_doubledash(&p[0]); + check_inline_file_via_fp(fp, p, &options->gc); + add_option(options, p, file, line_num, level, msglevel, permission_mask, option_types_found, es); + } + } + if (fp != stdin) + { + fclose(fp); + } + } + else + { + msg(msglevel, "In %s:%d: Error opening configuration file: %s", top_file, top_line, file); + } + } + else + { + msg(msglevel, "In %s:%d: Maximum recursive include levels exceeded in include attempt of file %s -- probably you have a configuration file that tries to include itself.", top_file, top_line, file); + } + secure_memzero(line, sizeof(line)); + CLEAR(p); } static void -read_config_string (const char *prefix, - struct options *options, - const char *config, - const int msglevel, - const unsigned int permission_mask, - unsigned int *option_types_found, - struct env_set *es) +read_config_string(const char *prefix, + struct options *options, + const char *config, + const int msglevel, + const unsigned int permission_mask, + unsigned int *option_types_found, + struct env_set *es) { - char line[OPTION_LINE_SIZE]; - struct buffer multiline; - int line_num = 0; - - buf_set_read (&multiline, (uint8_t*)config, strlen (config)); - - while (buf_parse (&multiline, '\n', line, sizeof (line))) - { - char *p[MAX_PARMS]; - CLEAR (p); - ++line_num; - if (parse_line (line, p, SIZE (p), prefix, line_num, msglevel, &options->gc)) - { - bypass_doubledash (&p[0]); - check_inline_file_via_buf (&multiline, p, &options->gc); - add_option (options, p, prefix, line_num, 0, msglevel, permission_mask, option_types_found, es); - } - CLEAR (p); - } - secure_memzero (line, sizeof (line)); + char line[OPTION_LINE_SIZE]; + struct buffer multiline; + int line_num = 0; + + buf_set_read(&multiline, (uint8_t *)config, strlen(config)); + + while (buf_parse(&multiline, '\n', line, sizeof(line))) + { + char *p[MAX_PARMS]; + CLEAR(p); + ++line_num; + if (parse_line(line, p, SIZE(p), prefix, line_num, msglevel, &options->gc)) + { + bypass_doubledash(&p[0]); + check_inline_file_via_buf(&multiline, p, &options->gc); + add_option(options, p, prefix, line_num, 0, msglevel, permission_mask, option_types_found, es); + } + CLEAR(p); + } + secure_memzero(line, sizeof(line)); } void -parse_argv (struct options *options, - const int argc, - char *argv[], - const int msglevel, - const unsigned int permission_mask, - unsigned int *option_types_found, - struct env_set *es) +parse_argv(struct options *options, + const int argc, + char *argv[], + const int msglevel, + const unsigned int permission_mask, + unsigned int *option_types_found, + struct env_set *es) { - int i, j; - - /* usage message */ - if (argc <= 1) - usage (); - - /* config filename specified only? */ - if (argc == 2 && strncmp (argv[1], "--", 2)) - { - char *p[MAX_PARMS]; - CLEAR (p); - p[0] = "config"; - p[1] = argv[1]; - add_option (options, p, NULL, 0, 0, msglevel, permission_mask, option_types_found, es); - } - else - { - /* parse command line */ - for (i = 1; i < argc; ++i) - { - char *p[MAX_PARMS]; - CLEAR (p); - p[0] = argv[i]; - if (strncmp(p[0], "--", 2)) - { - msg (msglevel, "I'm trying to parse \"%s\" as an --option parameter but I don't see a leading '--'", p[0]); - } - else - p[0] += 2; - - for (j = 1; j < MAX_PARMS; ++j) - { - if (i + j < argc) - { - char *arg = argv[i + j]; - if (strncmp (arg, "--", 2)) - p[j] = arg; - else - break; - } - } - add_option (options, p, NULL, 0, 0, msglevel, permission_mask, option_types_found, es); - i += j - 1; - } + int i, j; + + /* usage message */ + if (argc <= 1) + { + usage(); + } + + /* config filename specified only? */ + if (argc == 2 && strncmp(argv[1], "--", 2)) + { + char *p[MAX_PARMS]; + CLEAR(p); + p[0] = "config"; + p[1] = argv[1]; + add_option(options, p, NULL, 0, 0, msglevel, permission_mask, option_types_found, es); + } + else + { + /* parse command line */ + for (i = 1; i < argc; ++i) + { + char *p[MAX_PARMS]; + CLEAR(p); + p[0] = argv[i]; + if (strncmp(p[0], "--", 2)) + { + msg(msglevel, "I'm trying to parse \"%s\" as an --option parameter but I don't see a leading '--'", p[0]); + } + else + { + p[0] += 2; + } + + for (j = 1; j < MAX_PARMS; ++j) + { + if (i + j < argc) + { + char *arg = argv[i + j]; + if (strncmp(arg, "--", 2)) + { + p[j] = arg; + } + else + { + break; + } + } + } + add_option(options, p, NULL, 0, 0, msglevel, permission_mask, option_types_found, es); + i += j - 1; + } } } @@ -4209,141 +4687,151 @@ parse_argv (struct options *options, * In that case the caller must end the push processing. */ static bool -apply_pull_filter (const struct options *o, char *line) +apply_pull_filter(const struct options *o, char *line) { - struct pull_filter *f; + struct pull_filter *f; - if (!o->pull_filter_list) return true; + if (!o->pull_filter_list) + { + return true; + } - for (f = o->pull_filter_list->head; f; f = f->next) + for (f = o->pull_filter_list->head; f; f = f->next) { - if (f->type == PUF_TYPE_ACCEPT && strncmp (line, f->pattern, f->size) == 0) + if (f->type == PUF_TYPE_ACCEPT && strncmp(line, f->pattern, f->size) == 0) { - msg (D_LOW, "Pushed option accepted by filter: '%s'", line); - return true; + msg(D_LOW, "Pushed option accepted by filter: '%s'", line); + return true; } - else if (f->type == PUF_TYPE_IGNORE && strncmp (line, f->pattern, f->size) == 0) + else if (f->type == PUF_TYPE_IGNORE && strncmp(line, f->pattern, f->size) == 0) { - msg (D_PUSH, "Pushed option removed by filter: '%s'", line); - *line = '\0'; - return true; + msg(D_PUSH, "Pushed option removed by filter: '%s'", line); + *line = '\0'; + return true; } - else if (f->type == PUF_TYPE_REJECT && strncmp (line, f->pattern, f->size) == 0) + else if (f->type == PUF_TYPE_REJECT && strncmp(line, f->pattern, f->size) == 0) { - msg (M_WARN, "Pushed option rejected by filter: '%s'. Restarting.", line); - *line = '\0'; - throw_signal_soft (SIGUSR1, "Offending option received from server"); - return false; + msg(M_WARN, "Pushed option rejected by filter: '%s'. Restarting.", line); + *line = '\0'; + throw_signal_soft(SIGUSR1, "Offending option received from server"); + return false; } } - return true; + return true; } bool -apply_push_options (struct options *options, - struct buffer *buf, - unsigned int permission_mask, - unsigned int *option_types_found, - struct env_set *es) +apply_push_options(struct options *options, + struct buffer *buf, + unsigned int permission_mask, + unsigned int *option_types_found, + struct env_set *es) { - char line[OPTION_PARM_SIZE]; - int line_num = 0; - const char *file = "[PUSH-OPTIONS]"; - const int msglevel = D_PUSH_ERRORS|M_OPTERR; + char line[OPTION_PARM_SIZE]; + int line_num = 0; + const char *file = "[PUSH-OPTIONS]"; + const int msglevel = D_PUSH_ERRORS|M_OPTERR; - while (buf_parse (buf, ',', line, sizeof (line))) + while (buf_parse(buf, ',', line, sizeof(line))) { - char *p[MAX_PARMS]; - CLEAR (p); - ++line_num; - if (!apply_pull_filter(options, line)) + char *p[MAX_PARMS]; + CLEAR(p); + ++line_num; + if (!apply_pull_filter(options, line)) + { + return false; /* Cause push/pull error and stop push processing */ + } + if (parse_line(line, p, SIZE(p), file, line_num, msglevel, &options->gc)) { - return false; /* Cause push/pull error and stop push processing */ + add_option(options, p, file, line_num, 0, msglevel, permission_mask, option_types_found, es); } - if (parse_line (line, p, SIZE (p), file, line_num, msglevel, &options->gc)) - { - add_option (options, p, file, line_num, 0, msglevel, permission_mask, option_types_found, es); - } } - return true; + return true; } void -options_server_import (struct options *o, - const char *filename, - int msglevel, - unsigned int permission_mask, - unsigned int *option_types_found, - struct env_set *es) +options_server_import(struct options *o, + const char *filename, + int msglevel, + unsigned int permission_mask, + unsigned int *option_types_found, + struct env_set *es) { - msg (D_PUSH, "OPTIONS IMPORT: reading client specific options from: %s", filename); - read_config_file (o, - filename, - 0, - filename, - 0, - msglevel, - permission_mask, - option_types_found, - es); + msg(D_PUSH, "OPTIONS IMPORT: reading client specific options from: %s", filename); + read_config_file(o, + filename, + 0, + filename, + 0, + msglevel, + permission_mask, + option_types_found, + es); } -void options_string_import (struct options *options, - const char *config, - const int msglevel, - const unsigned int permission_mask, - unsigned int *option_types_found, - struct env_set *es) +void +options_string_import(struct options *options, + const char *config, + const int msglevel, + const unsigned int permission_mask, + unsigned int *option_types_found, + struct env_set *es) { - read_config_string ("[CONFIG-STRING]", options, config, msglevel, permission_mask, option_types_found, es); + read_config_string("[CONFIG-STRING]", options, config, msglevel, permission_mask, option_types_found, es); } #if P2MP -#define VERIFY_PERMISSION(mask) { if (!verify_permission(p[0], file, line, (mask), permission_mask, option_types_found, msglevel, options)) goto err; } +#define VERIFY_PERMISSION(mask) { if (!verify_permission(p[0], file, line, (mask), permission_mask, option_types_found, msglevel, options)) {goto err;}} static bool -verify_permission (const char *name, - const char* file, - int line, - const unsigned int type, - const unsigned int allowed, - unsigned int *found, - const int msglevel, - struct options* options) +verify_permission(const char *name, + const char *file, + int line, + const unsigned int type, + const unsigned int allowed, + unsigned int *found, + const int msglevel, + struct options *options) { - if (!(type & allowed)) + if (!(type & allowed)) { - msg (msglevel, "option '%s' cannot be used in this context (%s)", name, file); - return false; + msg(msglevel, "option '%s' cannot be used in this context (%s)", name, file); + return false; } - if (found) - *found |= type; + if (found) + { + *found |= type; + } #ifndef ENABLE_SMALL - /* Check if this options is allowed in connection block, - * but we are currently not in a connection block - * Parsing a connection block uses a temporary options struct without - * connection_list - */ + /* Check if this options is allowed in connection block, + * but we are currently not in a connection block + * Parsing a connection block uses a temporary options struct without + * connection_list + */ - if ((type & OPT_P_CONNECTION) && options->connection_list) + if ((type & OPT_P_CONNECTION) && options->connection_list) { - if (file) - msg (M_WARN, "Option '%s' in %s:%d is ignored by previous blocks ", name, file, line); - else - msg (M_WARN, "Option '%s' is ignored by previous blocks", name); + if (file) + { + msg(M_WARN, "Option '%s' in %s:%d is ignored by previous blocks ", name, file, line); + } + else + { + msg(M_WARN, "Option '%s' is ignored by previous blocks", name); + } } #endif - return true; + return true; } -#else +#else /* if P2MP */ #define VERIFY_PERMISSION(mask) -#endif +#endif /* if P2MP */ /* * Check that an option doesn't have too @@ -4353,3169 +4841,3373 @@ verify_permission (const char *name, #define NM_QUOTE_HINT (1<<0) static bool -no_more_than_n_args (const int msglevel, - char *p[], - const int max, - const unsigned int flags) +no_more_than_n_args(const int msglevel, + char *p[], + const int max, + const unsigned int flags) { - const int len = string_array_len ((const char **)p); + const int len = string_array_len((const char **)p); - if (!len) - return false; + if (!len) + { + return false; + } - if (len > max) + if (len > max) { - msg (msglevel, "the --%s directive should have at most %d parameter%s.%s", - p[0], - max - 1, - max >= 3 ? "s" : "", - (flags & NM_QUOTE_HINT) ? " To pass a list of arguments as one of the parameters, try enclosing them in double quotes (\"\")." : ""); - return false; + msg(msglevel, "the --%s directive should have at most %d parameter%s.%s", + p[0], + max - 1, + max >= 3 ? "s" : "", + (flags & NM_QUOTE_HINT) ? " To pass a list of arguments as one of the parameters, try enclosing them in double quotes (\"\")." : ""); + return false; + } + else + { + return true; } - else - return true; } static inline int -msglevel_forward_compatible (struct options *options, const int msglevel) +msglevel_forward_compatible(struct options *options, const int msglevel) { - return options->forward_compatible ? M_WARN : msglevel; + return options->forward_compatible ? M_WARN : msglevel; } static void -set_user_script (struct options *options, - const char **script, - const char *new_script, - const char *type, - bool in_chroot) +set_user_script(struct options *options, + const char **script, + const char *new_script, + const char *type, + bool in_chroot) { - if (*script) { - msg (M_WARN, "Multiple --%s scripts defined. " - "The previously configured script is overridden.", type); - } - *script = new_script; - options->user_script_used = true; + if (*script) + { + msg(M_WARN, "Multiple --%s scripts defined. " + "The previously configured script is overridden.", type); + } + *script = new_script; + options->user_script_used = true; #ifndef ENABLE_SMALL - { - char script_name[100]; - openvpn_snprintf (script_name, sizeof(script_name), - "--%s script", type); + { + char script_name[100]; + openvpn_snprintf(script_name, sizeof(script_name), + "--%s script", type); - if (check_cmd_access (*script, script_name, (in_chroot ? options->chroot_dir : NULL))) - msg (M_USAGE, "Please correct this error."); + if (check_cmd_access(*script, script_name, (in_chroot ? options->chroot_dir : NULL))) + { + msg(M_USAGE, "Please correct this error."); + } - } + } #endif } static void -add_option (struct options *options, - char *p[], - const char *file, - int line, - const int level, - const int msglevel, - const unsigned int permission_mask, - unsigned int *option_types_found, - struct env_set *es) +add_option(struct options *options, + char *p[], + const char *file, + int line, + const int level, + const int msglevel, + const unsigned int permission_mask, + unsigned int *option_types_found, + struct env_set *es) { - struct gc_arena gc = gc_new (); - const bool pull_mode = BOOL_CAST (permission_mask & OPT_P_PULL_MODE); - int msglevel_fc = msglevel_forward_compatible (options, msglevel); + struct gc_arena gc = gc_new(); + const bool pull_mode = BOOL_CAST(permission_mask & OPT_P_PULL_MODE); + int msglevel_fc = msglevel_forward_compatible(options, msglevel); - ASSERT (MAX_PARMS >= 7); + ASSERT(MAX_PARMS >= 7); - /* - * If directive begins with "setenv opt" prefix, don't raise an error if - * directive is unrecognized. - */ - if (streq (p[0], "setenv") && p[1] && streq (p[1], "opt") && !(permission_mask & OPT_P_PULL_MODE)) + /* + * If directive begins with "setenv opt" prefix, don't raise an error if + * directive is unrecognized. + */ + if (streq(p[0], "setenv") && p[1] && streq(p[1], "opt") && !(permission_mask & OPT_P_PULL_MODE)) { - if (!p[2]) - p[2] = "setenv opt"; /* will trigger an error that includes setenv opt */ - p += 2; - msglevel_fc = M_WARN; + if (!p[2]) + { + p[2] = "setenv opt"; /* will trigger an error that includes setenv opt */ + } + p += 2; + msglevel_fc = M_WARN; } - if (!file) + if (!file) { - file = "[CMD-LINE]"; - line = 1; + file = "[CMD-LINE]"; + line = 1; } - if (streq (p[0], "help")) + if (streq(p[0], "help")) { - VERIFY_PERMISSION (OPT_P_GENERAL); - usage (); - if (p[1]) + VERIFY_PERMISSION(OPT_P_GENERAL); + usage(); + if (p[1]) { - msg (msglevel, "--help does not accept any parameters"); - goto err; + msg(msglevel, "--help does not accept any parameters"); + goto err; } } - if (streq (p[0], "version") && !p[1]) + if (streq(p[0], "version") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - usage_version (); + VERIFY_PERMISSION(OPT_P_GENERAL); + usage_version(); } - else if (streq (p[0], "config") && p[1] && !p[2]) + else if (streq(p[0], "config") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_CONFIG); + VERIFY_PERMISSION(OPT_P_CONFIG); - /* save first config file only in options */ - if (!options->config) - options->config = p[1]; + /* save first config file only in options */ + if (!options->config) + { + options->config = p[1]; + } - read_config_file (options, p[1], level, file, line, msglevel, permission_mask, option_types_found, es); + read_config_file(options, p[1], level, file, line, msglevel, permission_mask, option_types_found, es); } #if defined(ENABLE_DEBUG) && !defined(ENABLE_SMALL) - else if (streq (p[0], "show-gateway") && !p[2]) + else if (streq(p[0], "show-gateway") && !p[2]) { - struct route_gateway_info rgi; - struct route_ipv6_gateway_info rgi6; - struct in6_addr remote = IN6ADDR_ANY_INIT; - VERIFY_PERMISSION (OPT_P_GENERAL); - if (p[1]) - get_ipv6_addr (p[1], &remote, NULL, M_WARN); - get_default_gateway(&rgi); - get_default_gateway_ipv6(&rgi6, &remote); - print_default_gateway(M_INFO, &rgi, &rgi6); - openvpn_exit (OPENVPN_EXIT_STATUS_GOOD); /* exit point */ + struct route_gateway_info rgi; + struct route_ipv6_gateway_info rgi6; + struct in6_addr remote = IN6ADDR_ANY_INIT; + VERIFY_PERMISSION(OPT_P_GENERAL); + if (p[1]) + { + get_ipv6_addr(p[1], &remote, NULL, M_WARN); + } + get_default_gateway(&rgi); + get_default_gateway_ipv6(&rgi6, &remote); + print_default_gateway(M_INFO, &rgi, &rgi6); + openvpn_exit(OPENVPN_EXIT_STATUS_GOOD); /* exit point */ } #endif #if 0 - else if (streq (p[0], "foreign-option") && p[1]) + else if (streq(p[0], "foreign-option") && p[1]) { - VERIFY_PERMISSION (OPT_P_IPWIN32); - foreign_option (options, p, 3, es); + VERIFY_PERMISSION(OPT_P_IPWIN32); + foreign_option(options, p, 3, es); } #endif - else if (streq (p[0], "echo") || streq (p[0], "parameter")) + else if (streq(p[0], "echo") || streq(p[0], "parameter")) { - struct buffer string = alloc_buf_gc (OPTION_PARM_SIZE, &gc); - int j; - bool good = true; + struct buffer string = alloc_buf_gc(OPTION_PARM_SIZE, &gc); + int j; + bool good = true; - VERIFY_PERMISSION (OPT_P_ECHO); + VERIFY_PERMISSION(OPT_P_ECHO); - for (j = 1; j < MAX_PARMS; ++j) - { - if (!p[j]) - break; - if (j > 1) - good &= buf_printf (&string, " "); - good &= buf_printf (&string, "%s", p[j]); - } - if (good) - { + for (j = 1; j < MAX_PARMS; ++j) + { + if (!p[j]) + { + break; + } + if (j > 1) + { + good &= buf_printf(&string, " "); + } + good &= buf_printf(&string, "%s", p[j]); + } + if (good) + { #if 0 - /* removed for now since ECHO can potentially include - security-sensitive strings */ - msg (M_INFO, "%s:%s", - pull_mode ? "ECHO-PULL" : "ECHO", - BSTR (&string)); + /* removed for now since ECHO can potentially include + * security-sensitive strings */ + msg(M_INFO, "%s:%s", + pull_mode ? "ECHO-PULL" : "ECHO", + BSTR(&string)); #endif #ifdef ENABLE_MANAGEMENT - if (management) - management_echo (management, BSTR (&string), pull_mode); + if (management) + { + management_echo(management, BSTR(&string), pull_mode); + } #endif - } - else - msg (M_WARN, "echo/parameter option overflow"); + } + else + { + msg(M_WARN, "echo/parameter option overflow"); + } } #ifdef ENABLE_MANAGEMENT - else if (streq (p[0], "management") && p[1] && p[2] && !p[4]) + else if (streq(p[0], "management") && p[1] && p[2] && !p[4]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - if (streq (p[2], "unix")) - { + VERIFY_PERMISSION(OPT_P_GENERAL); + if (streq(p[2], "unix")) + { #if UNIX_SOCK_SUPPORT - options->management_flags |= MF_UNIX_SOCK; + options->management_flags |= MF_UNIX_SOCK; #else - msg (msglevel, "MANAGEMENT: this platform does not support unix domain sockets"); - goto err; + msg(msglevel, "MANAGEMENT: this platform does not support unix domain sockets"); + goto err; +#endif + } + + options->management_addr = p[1]; + options->management_port = p[2]; + if (p[3]) + { + options->management_user_pass = p[3]; + } + } + else if (streq(p[0], "management-client-user") && p[1] && !p[2]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + options->management_client_user = p[1]; + } + else if (streq(p[0], "management-client-group") && p[1] && !p[2]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + options->management_client_group = p[1]; + } + else if (streq(p[0], "management-query-passwords") && !p[1]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + options->management_flags |= MF_QUERY_PASSWORDS; + } + else if (streq(p[0], "management-query-remote") && !p[1]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + options->management_flags |= MF_QUERY_REMOTE; + } + else if (streq(p[0], "management-query-proxy") && !p[1]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + options->management_flags |= MF_QUERY_PROXY; + } + else if (streq(p[0], "management-hold") && !p[1]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + options->management_flags |= MF_HOLD; + } + else if (streq(p[0], "management-signal") && !p[1]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + options->management_flags |= MF_SIGNAL; + } + else if (streq(p[0], "management-forget-disconnect") && !p[1]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + options->management_flags |= MF_FORGET_DISCONNECT; + } + else if (streq(p[0], "management-up-down") && !p[1]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + options->management_flags |= MF_UP_DOWN; + } + else if (streq(p[0], "management-client") && !p[2]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + options->management_flags |= MF_CONNECT_AS_CLIENT; + options->management_write_peer_info_file = p[1]; + } +#ifdef MANAGMENT_EXTERNAL_KEY + else if (streq(p[0], "management-external-key") && !p[1]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + options->management_flags |= MF_EXTERNAL_KEY; + } + else if (streq(p[0], "management-external-cert") && p[1] && !p[2]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + options->management_flags |= MF_EXTERNAL_CERT; + options->management_certificate = p[1]; + } +#endif +#ifdef MANAGEMENT_DEF_AUTH + else if (streq(p[0], "management-client-auth") && !p[1]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + options->management_flags |= MF_CLIENT_AUTH; + } +#endif +#ifdef MANAGEMENT_PF + else if (streq(p[0], "management-client-pf") && !p[1]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + options->management_flags |= (MF_CLIENT_PF | MF_CLIENT_AUTH); + } +#endif + else if (streq(p[0], "management-log-cache") && p[1] && !p[2]) + { + int cache; + + VERIFY_PERMISSION(OPT_P_GENERAL); + cache = atoi(p[1]); + if (cache < 1) + { + msg(msglevel, "--management-log-cache parameter is out of range"); + goto err; + } + options->management_log_history_cache = cache; + } +#endif /* ifdef ENABLE_MANAGEMENT */ +#ifdef ENABLE_PLUGIN + else if (streq(p[0], "plugin") && p[1] && !p[3]) + { + VERIFY_PERMISSION(OPT_P_PLUGIN); + if (!options->plugin_list) + { + options->plugin_list = plugin_option_list_new(&options->gc); + } + if (!plugin_option_list_add(options->plugin_list, &p[1], &options->gc)) + { + msg(msglevel, "plugin add failed: %s", p[1]); + goto err; + } + } +#endif + else if (streq(p[0], "mode") && p[1] && !p[2]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + if (streq(p[1], "p2p")) + { + options->mode = MODE_POINT_TO_POINT; + } +#if P2MP_SERVER + else if (streq(p[1], "server")) + { + options->mode = MODE_SERVER; + } +#endif + else + { + msg(msglevel, "Bad --mode parameter: %s", p[1]); + goto err; + } + } + else if (streq(p[0], "dev") && p[1] && !p[2]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + options->dev = p[1]; + } + else if (streq(p[0], "dev-type") && p[1] && !p[2]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + options->dev_type = p[1]; + } + else if (streq(p[0], "dev-node") && p[1] && !p[2]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + options->dev_node = p[1]; + } + else if (streq(p[0], "lladdr") && p[1] && !p[2]) + { + VERIFY_PERMISSION(OPT_P_UP); + if (mac_addr_safe(p[1])) /* MAC address only */ + { + options->lladdr = p[1]; + } + else + { + msg(msglevel, "lladdr parm '%s' must be a MAC address", p[1]); + goto err; + } + } + else if (streq(p[0], "topology") && p[1] && !p[2]) + { + VERIFY_PERMISSION(OPT_P_UP); + options->topology = parse_topology(p[1], msglevel); + } + else if (streq(p[0], "tun-ipv6") && !p[1]) + { + VERIFY_PERMISSION(OPT_P_UP); + msg(M_WARN, "Note: option tun-ipv6 is ignored because modern operating systems do not need special IPv6 tun handling anymore."); + } +#ifdef ENABLE_IPROUTE + else if (streq(p[0], "iproute") && p[1] && !p[2]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + iproute_path = p[1]; + } #endif - } + else if (streq(p[0], "ifconfig") && p[1] && p[2] && !p[3]) + { + VERIFY_PERMISSION(OPT_P_UP); + if (ip_or_dns_addr_safe(p[1], options->allow_pull_fqdn) && ip_or_dns_addr_safe(p[2], options->allow_pull_fqdn)) /* FQDN -- may be DNS name */ + { + options->ifconfig_local = p[1]; + options->ifconfig_remote_netmask = p[2]; + } + else + { + msg(msglevel, "ifconfig parms '%s' and '%s' must be valid addresses", p[1], p[2]); + goto err; + } + } + else if (streq(p[0], "ifconfig-ipv6") && p[1] && p[2] && !p[3]) + { + unsigned int netbits; + + VERIFY_PERMISSION(OPT_P_UP); + if (get_ipv6_addr( p[1], NULL, &netbits, msglevel ) + && ipv6_addr_safe( p[2] ) ) + { + if (netbits < 64 || netbits > 124) + { + msg( msglevel, "ifconfig-ipv6: /netbits must be between 64 and 124, not '/%d'", netbits ); + goto err; + } + + options->ifconfig_ipv6_local = get_ipv6_addr_no_netbits(p[1], &options->gc); + options->ifconfig_ipv6_netbits = netbits; + options->ifconfig_ipv6_remote = p[2]; + } + else + { + msg(msglevel, "ifconfig-ipv6 parms '%s' and '%s' must be valid addresses", p[1], p[2]); + goto err; + } + } + else if (streq(p[0], "ifconfig-noexec") && !p[1]) + { + VERIFY_PERMISSION(OPT_P_UP); + options->ifconfig_noexec = true; + } + else if (streq(p[0], "ifconfig-nowarn") && !p[1]) + { + VERIFY_PERMISSION(OPT_P_UP); + options->ifconfig_nowarn = true; + } + else if (streq(p[0], "local") && p[1] && !p[2]) + { + VERIFY_PERMISSION(OPT_P_GENERAL|OPT_P_CONNECTION); + options->ce.local = p[1]; + } + else if (streq(p[0], "remote-random") && !p[1]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + options->remote_random = true; + } + else if (streq(p[0], "connection") && p[1] && !p[3]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + if (streq(p[1], INLINE_FILE_TAG) && p[2]) + { + struct options sub; + struct connection_entry *e; + + init_options(&sub, true); + sub.ce = options->ce; + read_config_string("[CONNECTION-OPTIONS]", &sub, p[2], msglevel, OPT_P_CONNECTION, option_types_found, es); + if (!sub.ce.remote) + { + msg(msglevel, "Each 'connection' block must contain exactly one 'remote' directive"); + goto err; + } + + e = alloc_connection_entry(options, msglevel); + if (!e) + { + goto err; + } + *e = sub.ce; + gc_transfer(&options->gc, &sub.gc); + uninit_options(&sub); + } + } + else if (streq(p[0], "ignore-unknown-option") && p[1]) + { + int i; + int j; + int numignored = 0; + const char **ignore; + + VERIFY_PERMISSION(OPT_P_GENERAL); + /* Find out how many options to be ignored */ + for (i = 1; p[i]; i++) + numignored++; + + /* add number of options already ignored */ + for (i = 0; options->ignore_unknown_option + && options->ignore_unknown_option[i]; i++) + numignored++; + + /* Allocate array */ + ALLOC_ARRAY_GC(ignore, const char *, numignored+1, &options->gc); + for (i = 0; options->ignore_unknown_option + && options->ignore_unknown_option[i]; i++) + ignore[i] = options->ignore_unknown_option[i]; - options->management_addr = p[1]; - options->management_port = p[2]; - if (p[3]) - { - options->management_user_pass = p[3]; - } + options->ignore_unknown_option = ignore; + + for (j = 1; p[j]; j++) + { + /* Allow the user to specify ignore-unknown-option --opt too */ + if (p[j][0]=='-' && p[j][1]=='-') + { + options->ignore_unknown_option[i] = (p[j]+2); + } + else + { + options->ignore_unknown_option[i] = p[j]; + } + i++; + } + + options->ignore_unknown_option[i] = NULL; } - else if (streq (p[0], "management-client-user") && p[1] && !p[2]) +#if ENABLE_MANAGEMENT + else if (streq(p[0], "http-proxy-override") && p[1] && p[2] && !p[4]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->management_client_user = p[1]; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->http_proxy_override = parse_http_proxy_override(p[1], p[2], p[3], msglevel, &options->gc); + if (!options->http_proxy_override) + { + goto err; + } } - else if (streq (p[0], "management-client-group") && p[1] && !p[2]) +#endif + else if (streq(p[0], "remote") && p[1] && !p[4]) + { + struct remote_entry re; + re.remote = re.remote_port = NULL; + re.proto = -1; + re.af = 0; + + VERIFY_PERMISSION(OPT_P_GENERAL|OPT_P_CONNECTION); + re.remote = p[1]; + if (p[2]) + { + re.remote_port = p[2]; + if (p[3]) + { + const int proto = ascii2proto(p[3]); + const sa_family_t af = ascii2af(p[3]); + if (proto < 0) + { + msg(msglevel, "remote: bad protocol associated with host %s: '%s'", p[1], p[3]); + goto err; + } + re.proto = proto; + re.af = af; + } + } + if (permission_mask & OPT_P_GENERAL) + { + struct remote_entry *e = alloc_remote_entry(options, msglevel); + if (!e) + { + goto err; + } + *e = re; + } + else if (permission_mask & OPT_P_CONNECTION) + { + connection_entry_load_re(&options->ce, &re); + } + } + else if (streq(p[0], "resolv-retry") && p[1] && !p[2]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + if (streq(p[1], "infinite")) + { + options->resolve_retry_seconds = RESOLV_RETRY_INFINITE; + } + else + { + options->resolve_retry_seconds = positive_atoi(p[1]); + } + } + else if ((streq(p[0], "preresolve") || streq(p[0], "ip-remote-hint")) && !p[2]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + options->resolve_in_advance = true; + /* Note the ip-remote-hint and the argument p[1] are for + * backward compatibility */ + if (p[1]) + { + options->ip_remote_hint = p[1]; + } + } + else if (streq(p[0], "connect-retry") && p[1] && !p[3]) + { + VERIFY_PERMISSION(OPT_P_GENERAL|OPT_P_CONNECTION); + options->ce.connect_retry_seconds = positive_atoi(p[1]); + /* + * Limit the base value of retry wait interval to 16 bits to avoid + * overflow when scaled up for exponential backoff + */ + if (options->ce.connect_retry_seconds > 0xFFFF) + { + options->ce.connect_retry_seconds = 0xFFFF; + msg(M_WARN, "connect retry wait interval truncated to %d", + options->ce.connect_retry_seconds); + } + + if (p[2]) + { + options->ce.connect_retry_seconds_max = + max_int(positive_atoi(p[2]), options->ce.connect_retry_seconds); + } + } + else if ((streq(p[0], "connect-timeout") || streq(p[0], "server-poll-timeout")) + && p[1] && !p[2]) + { + VERIFY_PERMISSION(OPT_P_GENERAL|OPT_P_CONNECTION); + options->ce.connect_timeout = positive_atoi(p[1]); + } + else if (streq(p[0], "connect-retry-max") && p[1] && !p[2]) + { + VERIFY_PERMISSION(OPT_P_GENERAL|OPT_P_CONNECTION); + options->connect_retry_max = positive_atoi(p[1]); + } + else if (streq(p[0], "ipchange") && p[1]) + { + VERIFY_PERMISSION(OPT_P_SCRIPT); + if (!no_more_than_n_args(msglevel, p, 2, NM_QUOTE_HINT)) + { + goto err; + } + set_user_script(options, + &options->ipchange, + string_substitute(p[1], ',', ' ', &options->gc), + "ipchange", true); + } + else if (streq(p[0], "float") && !p[1]) + { + VERIFY_PERMISSION(OPT_P_GENERAL|OPT_P_CONNECTION); + options->ce.remote_float = true; + } +#ifdef ENABLE_DEBUG + else if (streq(p[0], "gremlin") && p[1] && !p[2]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + options->gremlin = positive_atoi(p[1]); + } +#endif + else if (streq(p[0], "chroot") && p[1] && !p[2]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + options->chroot_dir = p[1]; + } + else if (streq(p[0], "cd") && p[1] && !p[2]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + if (platform_chdir(p[1])) + { + msg(M_ERR, "cd to '%s' failed", p[1]); + goto err; + } + options->cd_dir = p[1]; + } +#ifdef ENABLE_SELINUX + else if (streq(p[0], "setcon") && p[1] && !p[2]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + options->selinux_context = p[1]; + } +#endif + else if (streq(p[0], "writepid") && p[1] && !p[2]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + options->writepid = p[1]; + } + else if (streq(p[0], "up") && p[1]) + { + VERIFY_PERMISSION(OPT_P_SCRIPT); + if (!no_more_than_n_args(msglevel, p, 2, NM_QUOTE_HINT)) + { + goto err; + } + set_user_script(options, &options->up_script, p[1], "up", false); + } + else if (streq(p[0], "down") && p[1]) + { + VERIFY_PERMISSION(OPT_P_SCRIPT); + if (!no_more_than_n_args(msglevel, p, 2, NM_QUOTE_HINT)) + { + goto err; + } + set_user_script(options, &options->down_script, p[1], "down", true); + } + else if (streq(p[0], "down-pre") && !p[1]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + options->down_pre = true; + } + else if (streq(p[0], "up-delay") && !p[1]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + options->up_delay = true; + } + else if (streq(p[0], "up-restart") && !p[1]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + options->up_restart = true; + } + else if (streq(p[0], "syslog") && !p[2]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + open_syslog(p[1], false); + } + else if (streq(p[0], "daemon") && !p[2]) + { + bool didit = false; + VERIFY_PERMISSION(OPT_P_GENERAL); + if (!options->daemon) + { + options->daemon = didit = true; + open_syslog(p[1], false); + } + if (p[1]) + { + if (!didit) + { + msg(M_WARN, "WARNING: Multiple --daemon directives specified, ignoring --daemon %s. (Note that initscripts sometimes add their own --daemon directive.)", p[1]); + goto err; + } + } + } + else if (streq(p[0], "inetd") && !p[3]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + if (!options->inetd) + { + int z; + const char *name = NULL; + const char *opterr = "when --inetd is used with two parameters, one of them must be 'wait' or 'nowait' and the other must be a daemon name to use for system logging"; + + options->inetd = -1; + + for (z = 1; z <= 2; ++z) + { + if (p[z]) + { + if (streq(p[z], "wait")) + { + if (options->inetd != -1) + { + msg(msglevel, "%s", opterr); + goto err; + } + else + { + options->inetd = INETD_WAIT; + } + } + else if (streq(p[z], "nowait")) + { + if (options->inetd != -1) + { + msg(msglevel, "%s", opterr); + goto err; + } + else + { + options->inetd = INETD_NOWAIT; + } + } + else + { + if (name != NULL) + { + msg(msglevel, "%s", opterr); + goto err; + } + name = p[z]; + } + } + } + + /* default */ + if (options->inetd == -1) + { + options->inetd = INETD_WAIT; + } + + save_inetd_socket_descriptor(); + open_syslog(name, true); + } + } + else if (streq(p[0], "log") && p[1] && !p[2]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + options->log = true; + redirect_stdout_stderr(p[1], false); + } + else if (streq(p[0], "suppress-timestamps") && !p[1]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + options->suppress_timestamps = true; + set_suppress_timestamps(true); + } + else if (streq(p[0], "machine-readable-output") && !p[1]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + options->machine_readable_output = true; + set_machine_readable_output(true); + } + else if (streq(p[0], "log-append") && p[1] && !p[2]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + options->log = true; + redirect_stdout_stderr(p[1], true); + } +#ifdef ENABLE_MEMSTATS + else if (streq(p[0], "memstats") && p[1] && !p[2]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + options->memstats_fn = p[1]; + } +#endif + else if (streq(p[0], "mlock") && !p[1]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + options->mlock = true; + } +#if ENABLE_IP_PKTINFO + else if (streq(p[0], "multihome") && !p[1]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + options->sockflags |= SF_USE_IP_PKTINFO; + } +#endif + else if (streq(p[0], "verb") && p[1] && !p[2]) + { + VERIFY_PERMISSION(OPT_P_MESSAGES); + options->verbosity = positive_atoi(p[1]); +#if !defined(ENABLE_DEBUG) && !defined(ENABLE_SMALL) + /* Warn when a debug verbosity is supplied when built without debug support */ + if (options->verbosity >= 7) + { + msg(M_WARN, "NOTE: debug verbosity (--verb %d) is enabled but this build lacks debug support.", + options->verbosity); + } +#endif + } + else if (streq(p[0], "mute") && p[1] && !p[2]) + { + VERIFY_PERMISSION(OPT_P_MESSAGES); + options->mute = positive_atoi(p[1]); + } + else if (streq(p[0], "errors-to-stderr") && !p[1]) + { + VERIFY_PERMISSION(OPT_P_MESSAGES); + errors_to_stderr(); + } + else if (streq(p[0], "status") && p[1] && !p[3]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + options->status_file = p[1]; + if (p[2]) + { + options->status_file_update_freq = positive_atoi(p[2]); + } + } + else if (streq(p[0], "status-version") && p[1] && !p[2]) + { + int version; + + VERIFY_PERMISSION(OPT_P_GENERAL); + version = atoi(p[1]); + if (version < 1 || version > 3) + { + msg(msglevel, "--status-version must be 1 to 3"); + goto err; + } + options->status_file_version = version; + } + else if (streq(p[0], "remap-usr1") && p[1] && !p[2]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + if (streq(p[1], "SIGHUP")) + { + options->remap_sigusr1 = SIGHUP; + } + else if (streq(p[1], "SIGTERM")) + { + options->remap_sigusr1 = SIGTERM; + } + else + { + msg(msglevel, "--remap-usr1 parm must be 'SIGHUP' or 'SIGTERM'"); + goto err; + } + } + else if ((streq(p[0], "link-mtu") || streq(p[0], "udp-mtu")) && p[1] && !p[2]) + { + VERIFY_PERMISSION(OPT_P_MTU|OPT_P_CONNECTION); + options->ce.link_mtu = positive_atoi(p[1]); + options->ce.link_mtu_defined = true; + } + else if (streq(p[0], "tun-mtu") && p[1] && !p[2]) + { + VERIFY_PERMISSION(OPT_P_MTU|OPT_P_CONNECTION); + options->ce.tun_mtu = positive_atoi(p[1]); + options->ce.tun_mtu_defined = true; + } + else if (streq(p[0], "tun-mtu-extra") && p[1] && !p[2]) + { + VERIFY_PERMISSION(OPT_P_MTU|OPT_P_CONNECTION); + options->ce.tun_mtu_extra = positive_atoi(p[1]); + options->ce.tun_mtu_extra_defined = true; + } +#ifdef ENABLE_FRAGMENT + else if (streq(p[0], "mtu-dynamic")) + { + VERIFY_PERMISSION(OPT_P_MTU|OPT_P_CONNECTION); + msg(msglevel, "--mtu-dynamic has been replaced by --fragment"); + goto err; + } + else if (streq(p[0], "fragment") && p[1] && !p[2]) + { +/* VERIFY_PERMISSION (OPT_P_MTU); */ + VERIFY_PERMISSION(OPT_P_MTU|OPT_P_CONNECTION); + options->ce.fragment = positive_atoi(p[1]); + } +#endif + else if (streq(p[0], "mtu-disc") && p[1] && !p[2]) + { + VERIFY_PERMISSION(OPT_P_MTU|OPT_P_CONNECTION); + options->ce.mtu_discover_type = translate_mtu_discover_type_name(p[1]); + } +#ifdef ENABLE_OCC + else if (streq(p[0], "mtu-test") && !p[1]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + options->mtu_test = true; + } +#endif + else if (streq(p[0], "nice") && p[1] && !p[2]) + { + VERIFY_PERMISSION(OPT_P_NICE); + options->nice = atoi(p[1]); + } + else if (streq(p[0], "rcvbuf") && p[1] && !p[2]) + { + VERIFY_PERMISSION(OPT_P_SOCKBUF); + options->rcvbuf = positive_atoi(p[1]); + } + else if (streq(p[0], "sndbuf") && p[1] && !p[2]) + { + VERIFY_PERMISSION(OPT_P_SOCKBUF); + options->sndbuf = positive_atoi(p[1]); + } + else if (streq(p[0], "mark") && p[1] && !p[2]) + { +#if defined(TARGET_LINUX) && HAVE_DECL_SO_MARK + VERIFY_PERMISSION(OPT_P_GENERAL); + options->mark = atoi(p[1]); +#endif + } + else if (streq(p[0], "socket-flags")) + { + int j; + VERIFY_PERMISSION(OPT_P_SOCKFLAGS); + for (j = 1; j < MAX_PARMS && p[j]; ++j) + { + if (streq(p[j], "TCP_NODELAY")) + { + options->sockflags |= SF_TCP_NODELAY; + } + else + { + msg(msglevel, "unknown socket flag: %s", p[j]); + } + } + } + else if (streq(p[0], "txqueuelen") && p[1] && !p[2]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); +#ifdef TARGET_LINUX + options->tuntap_options.txqueuelen = positive_atoi(p[1]); +#else + msg(msglevel, "--txqueuelen not supported on this OS"); + goto err; +#endif + } + else if (streq(p[0], "shaper") && p[1] && !p[2]) + { +#ifdef ENABLE_FEATURE_SHAPER + int shaper; + + VERIFY_PERMISSION(OPT_P_SHAPER); + shaper = atoi(p[1]); + if (shaper < SHAPER_MIN || shaper > SHAPER_MAX) + { + msg(msglevel, "Bad shaper value, must be between %d and %d", + SHAPER_MIN, SHAPER_MAX); + goto err; + } + options->shaper = shaper; +#else /* ENABLE_FEATURE_SHAPER */ + VERIFY_PERMISSION(OPT_P_GENERAL); + msg(msglevel, "--shaper requires the gettimeofday() function which is missing"); + goto err; +#endif /* ENABLE_FEATURE_SHAPER */ + } + else if (streq(p[0], "port") && p[1] && !p[2]) + { + VERIFY_PERMISSION(OPT_P_GENERAL|OPT_P_CONNECTION); + options->ce.local_port = options->ce.remote_port = p[1]; + } + else if (streq(p[0], "lport") && p[1] && !p[2]) + { + VERIFY_PERMISSION(OPT_P_GENERAL|OPT_P_CONNECTION); + options->ce.local_port_defined = true; + options->ce.local_port = p[1]; + } + else if (streq(p[0], "rport") && p[1] && !p[2]) + { + VERIFY_PERMISSION(OPT_P_GENERAL|OPT_P_CONNECTION); + options->ce.remote_port = p[1]; + } + else if (streq(p[0], "bind") && !p[1]) + { + VERIFY_PERMISSION(OPT_P_GENERAL|OPT_P_CONNECTION); + options->ce.bind_defined = true; + if (p[1] && streq(p[1], "ipv6only")) + { + options->ce.bind_ipv6_only = true; + } + + } + else if (streq(p[0], "nobind") && !p[1]) + { + VERIFY_PERMISSION(OPT_P_GENERAL|OPT_P_CONNECTION); + options->ce.bind_local = false; + } + else if (streq(p[0], "fast-io") && !p[1]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + options->fast_io = true; + } + else if (streq(p[0], "inactive") && p[1] && !p[3]) + { + VERIFY_PERMISSION(OPT_P_TIMER); + options->inactivity_timeout = positive_atoi(p[1]); + if (p[2]) + { + options->inactivity_minimum_bytes = positive_atoi(p[2]); + } + } + else if (streq(p[0], "proto") && p[1] && !p[2]) + { + int proto; + sa_family_t af; + VERIFY_PERMISSION(OPT_P_GENERAL|OPT_P_CONNECTION); + proto = ascii2proto(p[1]); + af = ascii2af(p[1]); + if (proto < 0) + { + msg(msglevel, "Bad protocol: '%s'. Allowed protocols with --proto option: %s", + p[1], + proto2ascii_all(&gc)); + goto err; + } + options->ce.proto = proto; + options->ce.af = af; + } + else if (streq(p[0], "proto-force") && p[1] && !p[2]) + { + int proto_force; + VERIFY_PERMISSION(OPT_P_GENERAL); + proto_force = ascii2proto(p[1]); + if (proto_force < 0) + { + msg(msglevel, "Bad --proto-force protocol: '%s'", p[1]); + goto err; + } + options->proto_force = proto_force; + } + else if (streq(p[0], "http-proxy") && p[1] && !p[5]) + { + struct http_proxy_options *ho; + + VERIFY_PERMISSION(OPT_P_GENERAL|OPT_P_CONNECTION); + + { + if (!p[2]) + { + msg(msglevel, "http-proxy port number not defined"); + goto err; + } + + ho = init_http_proxy_options_once(&options->ce.http_proxy_options, &options->gc); + + ho->server = p[1]; + ho->port = p[2]; + } + + if (p[3]) + { + /* auto -- try to figure out proxy addr, port, and type automatically */ + /* semiauto -- given proxy addr:port, try to figure out type automatically */ + /* (auto|semiauto)-nct -- disable proxy auth cleartext protocols (i.e. basic auth) */ + if (streq(p[3], "auto")) + { + ho->auth_retry = PAR_ALL; + } + else if (streq(p[3], "auto-nct")) + { + ho->auth_retry = PAR_NCT; + } + else + { + ho->auth_method_string = "basic"; + ho->auth_file = p[3]; + + if (p[4]) + { + ho->auth_method_string = p[4]; + } + } + } + else + { + ho->auth_method_string = "none"; + } + } + else if (streq(p[0], "http-proxy-user-pass") && p[1]) + { + struct http_proxy_options *ho; + VERIFY_PERMISSION(OPT_P_GENERAL); + ho = init_http_proxy_options_once(&options->ce.http_proxy_options, &options->gc); + if (streq(p[1], INLINE_FILE_TAG) && p[2]) + { + ho->auth_file = p[2]; + ho->inline_creds = true; + } + else + { + ho->auth_file = p[1]; + } + } + else if (streq(p[0], "http-proxy-retry") || streq(p[0], "socks-proxy-retry")) + { + VERIFY_PERMISSION(OPT_P_GENERAL|OPT_P_CONNECTION); + msg(M_WARN, "DEPRECATED OPTION: http-proxy-retry and socks-proxy-retry: " + "In OpenVPN 2.4 proxy connection retries are handled like regular connections. " + "Use connect-retry-max 1 to get a similar behavior as before."); + } + else if (streq(p[0], "http-proxy-timeout") && p[1] && !p[2]) + { + VERIFY_PERMISSION(OPT_P_GENERAL|OPT_P_CONNECTION); + msg(M_WARN, "DEPRECATED OPTION: http-proxy-timeout: In OpenVPN 2.4 the timeout until a connection to a " + "server is established is managed with a single timeout set by connect-timeout"); + } + else if (streq(p[0], "http-proxy-option") && p[1] && !p[4]) + { + struct http_proxy_options *ho; + + VERIFY_PERMISSION(OPT_P_GENERAL|OPT_P_CONNECTION); + ho = init_http_proxy_options_once(&options->ce.http_proxy_options, &options->gc); + + if (streq(p[1], "VERSION") && p[2] && !p[3]) + { + ho->http_version = p[2]; + } + else if (streq(p[1], "AGENT") && p[2] && !p[3]) + { + ho->user_agent = p[2]; + } + else if ((streq(p[1], "EXT1") || streq(p[1], "EXT2") || streq(p[1], "CUSTOM-HEADER")) + && p[2]) + { + /* In the wild patched versions use both EXT1/2 and CUSTOM-HEADER + * with either two argument or one */ + + struct http_custom_header *custom_header = NULL; + int i; + /* Find the first free header */ + for (i = 0; i < MAX_CUSTOM_HTTP_HEADER; i++) { + if (!ho->custom_headers[i].name) + { + custom_header = &ho->custom_headers[i]; + break; + } + } + if (!custom_header) + { + msg(msglevel, "Cannot use more than %d http-proxy-option CUSTOM-HEADER : '%s'", MAX_CUSTOM_HTTP_HEADER, p[1]); + } + else + { + /* We will save p[2] and p[3], the proxy code will detect if + * p[3] is NULL */ + custom_header->name = p[2]; + custom_header->content = p[3]; + } + } + else + { + msg(msglevel, "Bad http-proxy-option or missing or extra parameter: '%s'", p[1]); + } + } + else if (streq(p[0], "socks-proxy") && p[1] && !p[4]) + { + VERIFY_PERMISSION(OPT_P_GENERAL|OPT_P_CONNECTION); + + if (p[2]) + { + options->ce.socks_proxy_port = p[2]; + } + else + { + options->ce.socks_proxy_port = "1080"; + } + options->ce.socks_proxy_server = p[1]; + options->ce.socks_proxy_authfile = p[3]; /* might be NULL */ + } + else if (streq(p[0], "keepalive") && p[1] && p[2] && !p[3]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + options->keepalive_ping = atoi(p[1]); + options->keepalive_timeout = atoi(p[2]); + } + else if (streq(p[0], "ping") && p[1] && !p[2]) + { + VERIFY_PERMISSION(OPT_P_TIMER); + options->ping_send_timeout = positive_atoi(p[1]); + } + else if (streq(p[0], "ping-exit") && p[1] && !p[2]) + { + VERIFY_PERMISSION(OPT_P_TIMER); + options->ping_rec_timeout = positive_atoi(p[1]); + options->ping_rec_timeout_action = PING_EXIT; + } + else if (streq(p[0], "ping-restart") && p[1] && !p[2]) + { + VERIFY_PERMISSION(OPT_P_TIMER); + options->ping_rec_timeout = positive_atoi(p[1]); + options->ping_rec_timeout_action = PING_RESTART; + } + else if (streq(p[0], "ping-timer-rem") && !p[1]) + { + VERIFY_PERMISSION(OPT_P_TIMER); + options->ping_timer_remote = true; + } +#ifdef ENABLE_OCC + else if (streq(p[0], "explicit-exit-notify") && !p[2]) + { + VERIFY_PERMISSION(OPT_P_GENERAL|OPT_P_CONNECTION|OPT_P_EXPLICIT_NOTIFY); + if (p[1]) + { + options->ce.explicit_exit_notification = positive_atoi(p[1]); + } + else + { + options->ce.explicit_exit_notification = 1; + } + } +#endif + else if (streq(p[0], "persist-tun") && !p[1]) + { + VERIFY_PERMISSION(OPT_P_PERSIST); + options->persist_tun = true; + } + else if (streq(p[0], "persist-key") && !p[1]) + { + VERIFY_PERMISSION(OPT_P_PERSIST); + options->persist_key = true; + } + else if (streq(p[0], "persist-local-ip") && !p[1]) + { + VERIFY_PERMISSION(OPT_P_PERSIST_IP); + options->persist_local_ip = true; + } + else if (streq(p[0], "persist-remote-ip") && !p[1]) + { + VERIFY_PERMISSION(OPT_P_PERSIST_IP); + options->persist_remote_ip = true; + } + else if (streq(p[0], "client-nat") && p[1] && p[2] && p[3] && p[4] && !p[5]) + { + VERIFY_PERMISSION(OPT_P_ROUTE); + cnol_check_alloc(options); + add_client_nat_to_option_list(options->client_nat, p[1], p[2], p[3], p[4], msglevel); + } + else if (streq(p[0], "route") && p[1] && !p[5]) + { + VERIFY_PERMISSION(OPT_P_ROUTE); + rol_check_alloc(options); + if (pull_mode) + { + if (!ip_or_dns_addr_safe(p[1], options->allow_pull_fqdn) && !is_special_addr(p[1])) /* FQDN -- may be DNS name */ + { + msg(msglevel, "route parameter network/IP '%s' must be a valid address", p[1]); + goto err; + } + if (p[2] && !ip_addr_dotted_quad_safe(p[2])) /* FQDN -- must be IP address */ + { + msg(msglevel, "route parameter netmask '%s' must be an IP address", p[2]); + goto err; + } + if (p[3] && !ip_or_dns_addr_safe(p[3], options->allow_pull_fqdn) && !is_special_addr(p[3])) /* FQDN -- may be DNS name */ + { + msg(msglevel, "route parameter gateway '%s' must be a valid address", p[3]); + goto err; + } + } + add_route_to_option_list(options->routes, p[1], p[2], p[3], p[4]); + } + else if (streq(p[0], "route-ipv6") && p[1] && !p[4]) + { + VERIFY_PERMISSION(OPT_P_ROUTE); + rol6_check_alloc(options); + if (pull_mode) + { + if (!ipv6_addr_safe_hexplusbits(p[1])) + { + msg(msglevel, "route-ipv6 parameter network/IP '%s' must be a valid address", p[1]); + goto err; + } + if (p[2] && !ipv6_addr_safe(p[2])) + { + msg(msglevel, "route-ipv6 parameter gateway '%s' must be a valid address", p[2]); + goto err; + } + /* p[3] is metric, if present */ + } + add_route_ipv6_to_option_list(options->routes_ipv6, p[1], p[2], p[3]); + } + else if (streq(p[0], "max-routes") && !p[2]) + { + msg(M_WARN, "DEPRECATED OPTION: --max-routes option ignored." + "The number of routes is unlimited as of version 2.4. " + "This option will be removed in a future version, " + "please remove it from your configuration."); + } + else if (streq(p[0], "route-gateway") && p[1] && !p[2]) + { + VERIFY_PERMISSION(OPT_P_ROUTE_EXTRAS); + if (streq(p[1], "dhcp")) + { + options->route_gateway_via_dhcp = true; + } + else + { + if (ip_or_dns_addr_safe(p[1], options->allow_pull_fqdn) || is_special_addr(p[1])) /* FQDN -- may be DNS name */ + { + options->route_default_gateway = p[1]; + } + else + { + msg(msglevel, "route-gateway parm '%s' must be a valid address", p[1]); + goto err; + } + } + } + else if (streq(p[0], "route-metric") && p[1] && !p[2]) + { + VERIFY_PERMISSION(OPT_P_ROUTE); + options->route_default_metric = positive_atoi(p[1]); + } + else if (streq(p[0], "route-delay") && !p[3]) + { + VERIFY_PERMISSION(OPT_P_ROUTE_EXTRAS); + options->route_delay_defined = true; + if (p[1]) + { + options->route_delay = positive_atoi(p[1]); + if (p[2]) + { + options->route_delay_window = positive_atoi(p[2]); + } + } + else + { + options->route_delay = 0; + } + } + else if (streq(p[0], "route-up") && p[1]) + { + VERIFY_PERMISSION(OPT_P_SCRIPT); + if (!no_more_than_n_args(msglevel, p, 2, NM_QUOTE_HINT)) + { + goto err; + } + set_user_script(options, &options->route_script, p[1], "route-up", false); + } + else if (streq(p[0], "route-pre-down") && p[1]) + { + VERIFY_PERMISSION(OPT_P_SCRIPT); + if (!no_more_than_n_args(msglevel, p, 2, NM_QUOTE_HINT)) + { + goto err; + } + set_user_script(options, + &options->route_predown_script, + p[1], + "route-pre-down", true); + } + else if (streq(p[0], "route-noexec") && !p[1]) + { + VERIFY_PERMISSION(OPT_P_SCRIPT); + options->route_noexec = true; + } + else if (streq(p[0], "route-nopull") && !p[1]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + options->route_nopull = true; + } + else if (streq(p[0], "pull-filter") && p[1] && p[2] && !p[3]) + { + struct pull_filter *f; + VERIFY_PERMISSION(OPT_P_GENERAL) + f = alloc_pull_filter(options, msglevel); + + if (strcmp("accept", p[1]) == 0) + { + f->type = PUF_TYPE_ACCEPT; + } + else if (strcmp("ignore", p[1]) == 0) + { + f->type = PUF_TYPE_IGNORE; + } + else if (strcmp("reject", p[1]) == 0) + { + f->type = PUF_TYPE_REJECT; + } + else + { + msg(msglevel, "Unknown --pull-filter type: %s", p[1]); + goto err; + } + f->pattern = p[2]; + f->size = strlen(p[2]); + } + else if (streq(p[0], "allow-pull-fqdn") && !p[1]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + options->allow_pull_fqdn = true; + } + else if (streq(p[0], "redirect-gateway") || streq(p[0], "redirect-private")) + { + int j; + VERIFY_PERMISSION(OPT_P_ROUTE); + rol_check_alloc(options); + if (streq(p[0], "redirect-gateway")) + { + options->routes->flags |= RG_REROUTE_GW; + } + for (j = 1; j < MAX_PARMS && p[j] != NULL; ++j) + { + if (streq(p[j], "local")) + { + options->routes->flags |= RG_LOCAL; + } + else if (streq(p[j], "autolocal")) + { + options->routes->flags |= RG_AUTO_LOCAL; + } + else if (streq(p[j], "def1")) + { + options->routes->flags |= RG_DEF1; + } + else if (streq(p[j], "bypass-dhcp")) + { + options->routes->flags |= RG_BYPASS_DHCP; + } + else if (streq(p[j], "bypass-dns")) + { + options->routes->flags |= RG_BYPASS_DNS; + } + else if (streq(p[j], "block-local")) + { + options->routes->flags |= RG_BLOCK_LOCAL; + } + else if (streq(p[j], "ipv6")) + { + rol6_check_alloc(options); + options->routes_ipv6->flags |= RG_REROUTE_GW; + } + else if (streq(p[j], "!ipv4")) + { + options->routes->flags &= ~RG_REROUTE_GW; + } + else + { + msg(msglevel, "unknown --%s flag: %s", p[0], p[j]); + goto err; + } + } +#ifdef _WIN32 + /* we need this here to handle pushed --redirect-gateway */ + remap_redirect_gateway_flags(options); +#endif + options->routes->flags |= RG_ENABLE; + } + else if (streq(p[0], "remote-random-hostname") && !p[1]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + options->sockflags |= SF_HOST_RANDOMIZE; + } + else if (streq(p[0], "setenv") && p[1] && !p[3]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + if (streq(p[1], "REMOTE_RANDOM_HOSTNAME") && !p[2]) + { + options->sockflags |= SF_HOST_RANDOMIZE; + } + else if (streq(p[1], "GENERIC_CONFIG")) + { + msg(msglevel, "this is a generic configuration and cannot directly be used"); + goto err; + } +#ifdef ENABLE_PUSH_PEER_INFO + else if (streq(p[1], "PUSH_PEER_INFO") && !p[2]) + { + options->push_peer_info = true; + } +#endif + else if (streq(p[1], "SERVER_POLL_TIMEOUT") && p[2]) + { + options->ce.connect_timeout = positive_atoi(p[2]); + } + else + { + if (streq(p[1], "FORWARD_COMPATIBLE") && p[2] && streq(p[2], "1")) + { + options->forward_compatible = true; + msglevel_fc = msglevel_forward_compatible(options, msglevel); + } + setenv_str(es, p[1], p[2] ? p[2] : ""); + } + } + else if (streq(p[0], "setenv-safe") && p[1] && !p[3]) + { + VERIFY_PERMISSION(OPT_P_SETENV); + setenv_str_safe(es, p[1], p[2] ? p[2] : ""); + } + else if (streq(p[0], "script-security") && p[1] && !p[2]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + script_security = atoi(p[1]); + } + else if (streq(p[0], "mssfix") && !p[2]) + { + VERIFY_PERMISSION(OPT_P_GENERAL|OPT_P_CONNECTION); + if (p[1]) + { + options->ce.mssfix = positive_atoi(p[1]); + } + else + { + options->ce.mssfix_default = true; + } + + } +#ifdef ENABLE_OCC + else if (streq(p[0], "disable-occ") && !p[1]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + options->occ = false; + } +#endif +#if P2MP +#if P2MP_SERVER + else if (streq(p[0], "server") && p[1] && p[2] && !p[4]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->management_client_group = p[1]; + const int lev = M_WARN; + bool error = false; + in_addr_t network, netmask; + + VERIFY_PERMISSION(OPT_P_GENERAL); + network = get_ip_addr(p[1], lev, &error); + netmask = get_ip_addr(p[2], lev, &error); + if (error || !network || !netmask) + { + msg(msglevel, "error parsing --server parameters"); + goto err; + } + options->server_defined = true; + options->server_network = network; + options->server_netmask = netmask; + + if (p[3]) + { + if (streq(p[3], "nopool")) + { + options->server_flags |= SF_NOPOOL; + } + else + { + msg(msglevel, "error parsing --server: %s is not a recognized flag", p[3]); + goto err; + } + } } - else if (streq (p[0], "management-query-passwords") && !p[1]) + else if (streq(p[0], "server-ipv6") && p[1] && !p[3]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->management_flags |= MF_QUERY_PASSWORDS; + const int lev = M_WARN; + struct in6_addr network; + unsigned int netbits = 0; + + VERIFY_PERMISSION(OPT_P_GENERAL); + if (!get_ipv6_addr(p[1], &network, &netbits, lev) ) + { + msg(msglevel, "error parsing --server-ipv6 parameter"); + goto err; + } + if (netbits < 64 || netbits > 112) + { + msg( msglevel, "--server-ipv6 settings: only /64../112 supported right now (not /%d)", netbits ); + goto err; + } + options->server_ipv6_defined = true; + options->server_network_ipv6 = network; + options->server_netbits_ipv6 = netbits; + + if (p[2]) /* no "nopool" options or similar for IPv6 */ + { + msg(msglevel, "error parsing --server-ipv6: %s is not a recognized flag", p[3]); + goto err; + } } - else if (streq (p[0], "management-query-remote") && !p[1]) + else if (streq(p[0], "server-bridge") && p[1] && p[2] && p[3] && p[4] && !p[5]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->management_flags |= MF_QUERY_REMOTE; + const int lev = M_WARN; + bool error = false; + in_addr_t ip, netmask, pool_start, pool_end; + + VERIFY_PERMISSION(OPT_P_GENERAL); + ip = get_ip_addr(p[1], lev, &error); + netmask = get_ip_addr(p[2], lev, &error); + pool_start = get_ip_addr(p[3], lev, &error); + pool_end = get_ip_addr(p[4], lev, &error); + if (error || !ip || !netmask || !pool_start || !pool_end) + { + msg(msglevel, "error parsing --server-bridge parameters"); + goto err; + } + options->server_bridge_defined = true; + options->server_bridge_ip = ip; + options->server_bridge_netmask = netmask; + options->server_bridge_pool_start = pool_start; + options->server_bridge_pool_end = pool_end; } - else if (streq (p[0], "management-query-proxy") && !p[1]) + else if (streq(p[0], "server-bridge") && p[1] && streq(p[1], "nogw") && !p[2]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->management_flags |= MF_QUERY_PROXY; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->server_bridge_proxy_dhcp = true; + options->server_flags |= SF_NO_PUSH_ROUTE_GATEWAY; } - else if (streq (p[0], "management-hold") && !p[1]) + else if (streq(p[0], "server-bridge") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->management_flags |= MF_HOLD; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->server_bridge_proxy_dhcp = true; } - else if (streq (p[0], "management-signal") && !p[1]) + else if (streq(p[0], "push") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->management_flags |= MF_SIGNAL; + VERIFY_PERMISSION(OPT_P_PUSH); + push_options(options, &p[1], msglevel, &options->gc); } - else if (streq (p[0], "management-forget-disconnect") && !p[1]) + else if (streq(p[0], "push-reset") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->management_flags |= MF_FORGET_DISCONNECT; + VERIFY_PERMISSION(OPT_P_INSTANCE); + push_reset(options); } - else if (streq (p[0], "management-up-down") && !p[1]) + else if (streq(p[0], "push-remove") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->management_flags |= MF_UP_DOWN; + VERIFY_PERMISSION(OPT_P_INSTANCE); + msg(D_PUSH, "PUSH_REMOVE '%s'", p[1]); + push_remove_option(options,p[1]); } - else if (streq (p[0], "management-client") && !p[2]) + else if (streq(p[0], "ifconfig-pool") && p[1] && p[2] && !p[4]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->management_flags |= MF_CONNECT_AS_CLIENT; - options->management_write_peer_info_file = p[1]; + const int lev = M_WARN; + bool error = false; + in_addr_t start, end, netmask = 0; + + VERIFY_PERMISSION(OPT_P_GENERAL); + start = get_ip_addr(p[1], lev, &error); + end = get_ip_addr(p[2], lev, &error); + if (p[3]) + { + netmask = get_ip_addr(p[3], lev, &error); + } + if (error) + { + msg(msglevel, "error parsing --ifconfig-pool parameters"); + goto err; + } + if (!ifconfig_pool_verify_range(msglevel, start, end)) + { + goto err; + } + + options->ifconfig_pool_defined = true; + options->ifconfig_pool_start = start; + options->ifconfig_pool_end = end; + if (netmask) + { + options->ifconfig_pool_netmask = netmask; + } } -#ifdef MANAGMENT_EXTERNAL_KEY - else if (streq (p[0], "management-external-key") && !p[1]) + else if (streq(p[0], "ifconfig-pool-persist") && p[1] && !p[3]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->management_flags |= MF_EXTERNAL_KEY; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->ifconfig_pool_persist_filename = p[1]; + if (p[2]) + { + options->ifconfig_pool_persist_refresh_freq = positive_atoi(p[2]); + } } - else if (streq (p[0], "management-external-cert") && p[1] && !p[2]) + else if (streq(p[0], "ifconfig-pool-linear") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->management_flags |= MF_EXTERNAL_CERT; - options->management_certificate = p[1]; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->topology = TOP_P2P; } -#endif -#ifdef MANAGEMENT_DEF_AUTH - else if (streq (p[0], "management-client-auth") && !p[1]) + else if (streq(p[0], "ifconfig-ipv6-pool") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->management_flags |= MF_CLIENT_AUTH; + const int lev = M_WARN; + struct in6_addr network; + unsigned int netbits = 0; + + VERIFY_PERMISSION(OPT_P_GENERAL); + if (!get_ipv6_addr(p[1], &network, &netbits, lev ) ) + { + msg(msglevel, "error parsing --ifconfig-ipv6-pool parameters"); + goto err; + } + if (netbits < 64 || netbits > 112) + { + msg( msglevel, "--ifconfig-ipv6-pool settings: only /64../112 supported right now (not /%d)", netbits ); + goto err; + } + + options->ifconfig_ipv6_pool_defined = true; + options->ifconfig_ipv6_pool_base = network; + options->ifconfig_ipv6_pool_netbits = netbits; } -#endif -#ifdef MANAGEMENT_PF - else if (streq (p[0], "management-client-pf") && !p[1]) + else if (streq(p[0], "hash-size") && p[1] && p[2] && !p[3]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->management_flags |= (MF_CLIENT_PF | MF_CLIENT_AUTH); + int real, virtual; + + VERIFY_PERMISSION(OPT_P_GENERAL); + real = atoi(p[1]); + virtual = atoi(p[2]); + if (real < 1 || virtual < 1) + { + msg(msglevel, "--hash-size sizes must be >= 1 (preferably a power of 2)"); + goto err; + } + options->real_hash_size = real; + options->virtual_hash_size = real; } -#endif - else if (streq (p[0], "management-log-cache") && p[1] && !p[2]) + else if (streq(p[0], "connect-freq") && p[1] && p[2] && !p[3]) { - int cache; + int cf_max, cf_per; - VERIFY_PERMISSION (OPT_P_GENERAL); - cache = atoi (p[1]); - if (cache < 1) - { - msg (msglevel, "--management-log-cache parameter is out of range"); - goto err; - } - options->management_log_history_cache = cache; + VERIFY_PERMISSION(OPT_P_GENERAL); + cf_max = atoi(p[1]); + cf_per = atoi(p[2]); + if (cf_max < 0 || cf_per < 0) + { + msg(msglevel, "--connect-freq parms must be > 0"); + goto err; + } + options->cf_max = cf_max; + options->cf_per = cf_per; } -#endif -#ifdef ENABLE_PLUGIN - else if (streq (p[0], "plugin") && p[1] && !p[3]) + else if (streq(p[0], "max-clients") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_PLUGIN); - if (!options->plugin_list) - options->plugin_list = plugin_option_list_new (&options->gc); - if (!plugin_option_list_add (options->plugin_list, &p[1], &options->gc)) - { - msg (msglevel, "plugin add failed: %s", p[1]); - goto err; - } + int max_clients; + + VERIFY_PERMISSION(OPT_P_GENERAL); + max_clients = atoi(p[1]); + if (max_clients < 0) + { + msg(msglevel, "--max-clients must be at least 1"); + goto err; + } + if (max_clients >= MAX_PEER_ID) /* max peer-id value */ + { + msg(msglevel, "--max-clients must be less than %d", MAX_PEER_ID); + goto err; + } + options->max_clients = max_clients; } -#endif - else if (streq (p[0], "mode") && p[1] && !p[2]) + else if (streq(p[0], "max-routes-per-client") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - if (streq (p[1], "p2p")) - options->mode = MODE_POINT_TO_POINT; -#if P2MP_SERVER - else if (streq (p[1], "server")) - options->mode = MODE_SERVER; -#endif - else - { - msg (msglevel, "Bad --mode parameter: %s", p[1]); - goto err; - } + VERIFY_PERMISSION(OPT_P_INHERIT); + options->max_routes_per_client = max_int(atoi(p[1]), 1); } - else if (streq (p[0], "dev") && p[1] && !p[2]) + else if (streq(p[0], "client-cert-not-required") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->dev = p[1]; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->ssl_flags |= SSLF_CLIENT_CERT_NOT_REQUIRED; + msg(M_WARN, "DEPRECATED OPTION: --client-cert-not-required, use --verify-client-cert instead"); } - else if (streq (p[0], "dev-type") && p[1] && !p[2]) + else if (streq(p[0], "verify-client-cert") && !p[2]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->dev_type = p[1]; + VERIFY_PERMISSION(OPT_P_GENERAL); + + /* Reset any existing flags */ + options->ssl_flags &= ~SSLF_CLIENT_CERT_OPTIONAL; + options->ssl_flags &= ~SSLF_CLIENT_CERT_NOT_REQUIRED; + if (p[1]) + { + if (streq(p[1], "none")) + { + options->ssl_flags |= SSLF_CLIENT_CERT_NOT_REQUIRED; + } + else if (streq(p[1], "optional")) + { + options->ssl_flags |= SSLF_CLIENT_CERT_OPTIONAL; + } + else if (!streq(p[1], "require")) + { + msg(msglevel, "parameter to --verify-client-cert must be 'none', 'optional' or 'require'"); + goto err; + } + } } - else if (streq (p[0], "dev-node") && p[1] && !p[2]) + else if (streq(p[0], "username-as-common-name") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->dev_node = p[1]; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->ssl_flags |= SSLF_USERNAME_AS_COMMON_NAME; } - else if (streq (p[0], "lladdr") && p[1] && !p[2]) + else if (streq(p[0], "auth-user-pass-optional") && !p[1]) { - VERIFY_PERMISSION (OPT_P_UP); - if (mac_addr_safe (p[1])) /* MAC address only */ - options->lladdr = p[1]; - else - { - msg (msglevel, "lladdr parm '%s' must be a MAC address", p[1]); - goto err; - } + VERIFY_PERMISSION(OPT_P_GENERAL); + options->ssl_flags |= SSLF_AUTH_USER_PASS_OPTIONAL; } - else if (streq (p[0], "topology") && p[1] && !p[2]) + else if (streq(p[0], "opt-verify") && !p[1]) { - VERIFY_PERMISSION (OPT_P_UP); - options->topology = parse_topology (p[1], msglevel); + VERIFY_PERMISSION(OPT_P_GENERAL); + options->ssl_flags |= SSLF_OPT_VERIFY; } - else if (streq (p[0], "tun-ipv6") && !p[1]) + else if (streq(p[0], "auth-user-pass-verify") && p[1]) { - VERIFY_PERMISSION (OPT_P_UP); - msg (M_WARN, "Note: option tun-ipv6 is ignored because modern operating systems do not need special IPv6 tun handling anymore."); + VERIFY_PERMISSION(OPT_P_SCRIPT); + if (!no_more_than_n_args(msglevel, p, 3, NM_QUOTE_HINT)) + { + goto err; + } + if (p[2]) + { + if (streq(p[2], "via-env")) + { + options->auth_user_pass_verify_script_via_file = false; + } + else if (streq(p[2], "via-file")) + { + options->auth_user_pass_verify_script_via_file = true; + } + else + { + msg(msglevel, "second parm to --auth-user-pass-verify must be 'via-env' or 'via-file'"); + goto err; + } + } + else + { + msg(msglevel, "--auth-user-pass-verify requires a second parameter ('via-env' or 'via-file')"); + goto err; + } + set_user_script(options, + &options->auth_user_pass_verify_script, + p[1], "auth-user-pass-verify", true); } -#ifdef ENABLE_IPROUTE - else if (streq (p[0], "iproute") && p[1] && !p[2]) + else if (streq(p[0], "auth-gen-token")) { - VERIFY_PERMISSION (OPT_P_GENERAL); - iproute_path = p[1]; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->auth_token_generate = true; + options->auth_token_lifetime = p[1] ? positive_atoi(p[1]) : 0; } -#endif - else if (streq (p[0], "ifconfig") && p[1] && p[2] && !p[3]) + else if (streq(p[0], "client-connect") && p[1]) { - VERIFY_PERMISSION (OPT_P_UP); - if (ip_or_dns_addr_safe (p[1], options->allow_pull_fqdn) && ip_or_dns_addr_safe (p[2], options->allow_pull_fqdn)) /* FQDN -- may be DNS name */ - { - options->ifconfig_local = p[1]; - options->ifconfig_remote_netmask = p[2]; - } - else - { - msg (msglevel, "ifconfig parms '%s' and '%s' must be valid addresses", p[1], p[2]); - goto err; - } + VERIFY_PERMISSION(OPT_P_SCRIPT); + if (!no_more_than_n_args(msglevel, p, 2, NM_QUOTE_HINT)) + { + goto err; + } + set_user_script(options, &options->client_connect_script, + p[1], "client-connect", true); } - else if (streq (p[0], "ifconfig-ipv6") && p[1] && p[2] && !p[3]) + else if (streq(p[0], "client-disconnect") && p[1]) { - unsigned int netbits; - - VERIFY_PERMISSION (OPT_P_UP); - if ( get_ipv6_addr( p[1], NULL, &netbits, msglevel ) && - ipv6_addr_safe( p[2] ) ) + VERIFY_PERMISSION(OPT_P_SCRIPT); + if (!no_more_than_n_args(msglevel, p, 2, NM_QUOTE_HINT)) { - if ( netbits < 64 || netbits > 124 ) - { - msg( msglevel, "ifconfig-ipv6: /netbits must be between 64 and 124, not '/%d'", netbits ); - goto err; - } - - options->ifconfig_ipv6_local = get_ipv6_addr_no_netbits (p[1], &options->gc); - options->ifconfig_ipv6_netbits = netbits; - options->ifconfig_ipv6_remote = p[2]; + goto err; } - else - { - msg (msglevel, "ifconfig-ipv6 parms '%s' and '%s' must be valid addresses", p[1], p[2]); - goto err; - } + set_user_script(options, &options->client_disconnect_script, + p[1], "client-disconnect", true); } - else if (streq (p[0], "ifconfig-noexec") && !p[1]) + else if (streq(p[0], "learn-address") && p[1]) { - VERIFY_PERMISSION (OPT_P_UP); - options->ifconfig_noexec = true; + VERIFY_PERMISSION(OPT_P_SCRIPT); + if (!no_more_than_n_args(msglevel, p, 2, NM_QUOTE_HINT)) + { + goto err; + } + set_user_script(options, &options->learn_address_script, + p[1], "learn-address", true); } - else if (streq (p[0], "ifconfig-nowarn") && !p[1]) + else if (streq(p[0], "tmp-dir") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_UP); - options->ifconfig_nowarn = true; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->tmp_dir = p[1]; } - else if (streq (p[0], "local") && p[1] && !p[2]) + else if (streq(p[0], "client-config-dir") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); - options->ce.local = p[1]; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->client_config_dir = p[1]; } - else if (streq (p[0], "remote-random") && !p[1]) + else if (streq(p[0], "ccd-exclusive") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->remote_random = true; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->ccd_exclusive = true; } - else if (streq (p[0], "connection") && p[1] && !p[3]) + else if (streq(p[0], "bcast-buffers") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - if (streq (p[1], INLINE_FILE_TAG) && p[2]) - { - struct options sub; - struct connection_entry *e; - - init_options (&sub, true); - sub.ce = options->ce; - read_config_string ("[CONNECTION-OPTIONS]", &sub, p[2], msglevel, OPT_P_CONNECTION, option_types_found, es); - if (!sub.ce.remote) - { - msg (msglevel, "Each 'connection' block must contain exactly one 'remote' directive"); - goto err; - } + int n_bcast_buf; - e = alloc_connection_entry (options, msglevel); - if (!e) - goto err; - *e = sub.ce; - gc_transfer (&options->gc, &sub.gc); - uninit_options (&sub); - } + VERIFY_PERMISSION(OPT_P_GENERAL); + n_bcast_buf = atoi(p[1]); + if (n_bcast_buf < 1) + { + msg(msglevel, "--bcast-buffers parameter must be > 0"); + } + options->n_bcast_buf = n_bcast_buf; } - else if (streq (p[0], "ignore-unknown-option") && p[1]) + else if (streq(p[0], "tcp-queue-limit") && p[1] && !p[2]) { - int i; - int j; - int numignored=0; - const char **ignore; - - VERIFY_PERMISSION (OPT_P_GENERAL); - /* Find out how many options to be ignored */ - for (i=1;p[i];i++) - numignored++; - - /* add number of options already ignored */ - for (i=0;options->ignore_unknown_option && - options->ignore_unknown_option[i]; i++) - numignored++; + int tcp_queue_limit; - /* Allocate array */ - ALLOC_ARRAY_GC (ignore, const char*, numignored+1, &options->gc); - for (i=0;options->ignore_unknown_option && - options->ignore_unknown_option[i]; i++) - ignore[i]=options->ignore_unknown_option[i]; - - options->ignore_unknown_option=ignore; - - for (j=1;p[j];j++) + VERIFY_PERMISSION(OPT_P_GENERAL); + tcp_queue_limit = atoi(p[1]); + if (tcp_queue_limit < 1) { - /* Allow the user to specify ignore-unknown-option --opt too */ - if (p[j][0]=='-' && p[j][1]=='-') - options->ignore_unknown_option[i] = (p[j]+2); - else - options->ignore_unknown_option[i] = p[j]; - i++; + msg(msglevel, "--tcp-queue-limit parameter must be > 0"); } - - options->ignore_unknown_option[i] = NULL; - } -#if ENABLE_MANAGEMENT - else if (streq (p[0], "http-proxy-override") && p[1] && p[2] && !p[4]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->http_proxy_override = parse_http_proxy_override(p[1], p[2], p[3], msglevel, &options->gc); - if (!options->http_proxy_override) - goto err; - } -#endif - else if (streq (p[0], "remote") && p[1] && !p[4]) - { - struct remote_entry re; - re.remote = re.remote_port= NULL; - re.proto = -1; - re.af=0; - - VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); - re.remote = p[1]; - if (p[2]) - { - re.remote_port = p[2]; - if (p[3]) - { - const int proto = ascii2proto (p[3]); - const sa_family_t af = ascii2af (p[3]); - if (proto < 0) - { - msg (msglevel, "remote: bad protocol associated with host %s: '%s'", p[1], p[3]); - goto err; - } - re.proto = proto; - re.af = af; - } - } - if (permission_mask & OPT_P_GENERAL) - { - struct remote_entry *e = alloc_remote_entry (options, msglevel); - if (!e) - goto err; - *e = re; - } - else if (permission_mask & OPT_P_CONNECTION) - { - connection_entry_load_re (&options->ce, &re); - } - } - else if (streq (p[0], "resolv-retry") && p[1] && !p[2]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - if (streq (p[1], "infinite")) - options->resolve_retry_seconds = RESOLV_RETRY_INFINITE; - else - options->resolve_retry_seconds = positive_atoi (p[1]); - } - else if ((streq (p[0], "preresolve") || streq (p[0], "ip-remote-hint")) && !p[2]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->resolve_in_advance = true; - /* Note the ip-remote-hint and the argument p[1] are for - backward compatibility */ - if (p[1]) - options->ip_remote_hint=p[1]; - } - else if (streq (p[0], "connect-retry") && p[1] && !p[3]) - { - VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); - options->ce.connect_retry_seconds = positive_atoi (p[1]); - /* - * Limit the base value of retry wait interval to 16 bits to avoid - * overflow when scaled up for exponential backoff - */ - if (options->ce.connect_retry_seconds > 0xFFFF) - { - options->ce.connect_retry_seconds = 0xFFFF; - msg (M_WARN, "connect retry wait interval truncated to %d", - options->ce.connect_retry_seconds); - } - - if (p[2]) - options->ce.connect_retry_seconds_max = - max_int (positive_atoi (p[2]), options->ce.connect_retry_seconds); - } - else if ((streq (p[0], "connect-timeout") || streq (p[0], "server-poll-timeout")) - && p[1] && !p[2]) - { - VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); - options->ce.connect_timeout = positive_atoi (p[1]); - } - else if (streq (p[0], "connect-retry-max") && p[1] && !p[2]) - { - VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); - options->connect_retry_max = positive_atoi (p[1]); - } - else if (streq (p[0], "ipchange") && p[1]) - { - VERIFY_PERMISSION (OPT_P_SCRIPT); - if (!no_more_than_n_args (msglevel, p, 2, NM_QUOTE_HINT)) - goto err; - set_user_script (options, - &options->ipchange, - string_substitute (p[1], ',', ' ', &options->gc), - "ipchange", true); - } - else if (streq (p[0], "float") && !p[1]) - { - VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); - options->ce.remote_float = true; + options->tcp_queue_limit = tcp_queue_limit; } -#ifdef ENABLE_DEBUG - else if (streq (p[0], "gremlin") && p[1] && !p[2]) +#if PORT_SHARE + else if (streq(p[0], "port-share") && p[1] && p[2] && !p[4]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->gremlin = positive_atoi (p[1]); + VERIFY_PERMISSION(OPT_P_GENERAL); + options->port_share_host = p[1]; + options->port_share_port = p[2]; + options->port_share_journal_dir = p[3]; } #endif - else if (streq (p[0], "chroot") && p[1] && !p[2]) + else if (streq(p[0], "client-to-client") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->chroot_dir = p[1]; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->enable_c2c = true; } - else if (streq (p[0], "cd") && p[1] && !p[2]) + else if (streq(p[0], "duplicate-cn") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - if (platform_chdir (p[1])) - { - msg (M_ERR, "cd to '%s' failed", p[1]); - goto err; - } - options->cd_dir = p[1]; - } -#ifdef ENABLE_SELINUX - else if (streq (p[0], "setcon") && p[1] && !p[2]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->selinux_context = p[1]; - } -#endif - else if (streq (p[0], "writepid") && p[1] && !p[2]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->writepid = p[1]; - } - else if (streq (p[0], "up") && p[1]) - { - VERIFY_PERMISSION (OPT_P_SCRIPT); - if (!no_more_than_n_args (msglevel, p, 2, NM_QUOTE_HINT)) - goto err; - set_user_script (options, &options->up_script, p[1], "up", false); - } - else if (streq (p[0], "down") && p[1]) - { - VERIFY_PERMISSION (OPT_P_SCRIPT); - if (!no_more_than_n_args (msglevel, p, 2, NM_QUOTE_HINT)) - goto err; - set_user_script (options, &options->down_script, p[1], "down", true); - } - else if (streq (p[0], "down-pre") && !p[1]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->down_pre = true; - } - else if (streq (p[0], "up-delay") && !p[1]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->up_delay = true; - } - else if (streq (p[0], "up-restart") && !p[1]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->up_restart = true; - } - else if (streq (p[0], "syslog") && !p[2]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - open_syslog (p[1], false); - } - else if (streq (p[0], "daemon") && !p[2]) - { - bool didit = false; - VERIFY_PERMISSION (OPT_P_GENERAL); - if (!options->daemon) - { - options->daemon = didit = true; - open_syslog (p[1], false); - } - if (p[1]) - { - if (!didit) - { - msg (M_WARN, "WARNING: Multiple --daemon directives specified, ignoring --daemon %s. (Note that initscripts sometimes add their own --daemon directive.)", p[1]); - goto err; - } - } - } - else if (streq (p[0], "inetd") && !p[3]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - if (!options->inetd) - { - int z; - const char *name = NULL; - const char *opterr = "when --inetd is used with two parameters, one of them must be 'wait' or 'nowait' and the other must be a daemon name to use for system logging"; - - options->inetd = -1; - - for (z = 1; z <= 2; ++z) - { - if (p[z]) - { - if (streq (p[z], "wait")) - { - if (options->inetd != -1) - { - msg (msglevel, "%s", opterr); - goto err; - } - else - options->inetd = INETD_WAIT; - } - else if (streq (p[z], "nowait")) - { - if (options->inetd != -1) - { - msg (msglevel, "%s", opterr); - goto err; - } - else - options->inetd = INETD_NOWAIT; - } - else - { - if (name != NULL) - { - msg (msglevel, "%s", opterr); - goto err; - } - name = p[z]; - } - } - } - - /* default */ - if (options->inetd == -1) - options->inetd = INETD_WAIT; - - save_inetd_socket_descriptor (); - open_syslog (name, true); - } - } - else if (streq (p[0], "log") && p[1] && !p[2]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->log = true; - redirect_stdout_stderr (p[1], false); - } - else if (streq (p[0], "suppress-timestamps") && !p[1]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->suppress_timestamps = true; - set_suppress_timestamps(true); - } - else if (streq (p[0], "machine-readable-output") && !p[1]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->machine_readable_output = true; - set_machine_readable_output(true); - } - else if (streq (p[0], "log-append") && p[1] && !p[2]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->log = true; - redirect_stdout_stderr (p[1], true); + VERIFY_PERMISSION(OPT_P_GENERAL); + options->duplicate_cn = true; } -#ifdef ENABLE_MEMSTATS - else if (streq (p[0], "memstats") && p[1] && !p[2]) + else if (streq(p[0], "iroute") && p[1] && !p[3]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->memstats_fn = p[1]; + const char *netmask = NULL; + + VERIFY_PERMISSION(OPT_P_INSTANCE); + if (p[2]) + { + netmask = p[2]; + } + option_iroute(options, p[1], netmask, msglevel); } -#endif - else if (streq (p[0], "mlock") && !p[1]) + else if (streq(p[0], "iroute-ipv6") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->mlock = true; + VERIFY_PERMISSION(OPT_P_INSTANCE); + option_iroute_ipv6(options, p[1], msglevel); } -#if ENABLE_IP_PKTINFO - else if (streq (p[0], "multihome") && !p[1]) + else if (streq(p[0], "ifconfig-push") && p[1] && p[2] && !p[4]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->sockflags |= SF_USE_IP_PKTINFO; + in_addr_t local, remote_netmask; + + VERIFY_PERMISSION(OPT_P_INSTANCE); + local = getaddr(GETADDR_HOST_ORDER|GETADDR_RESOLVE, p[1], 0, NULL, NULL); + remote_netmask = getaddr(GETADDR_HOST_ORDER|GETADDR_RESOLVE, p[2], 0, NULL, NULL); + if (local && remote_netmask) + { + options->push_ifconfig_defined = true; + options->push_ifconfig_local = local; + options->push_ifconfig_remote_netmask = remote_netmask; + if (p[3]) + { + options->push_ifconfig_local_alias = getaddr(GETADDR_HOST_ORDER|GETADDR_RESOLVE, p[3], 0, NULL, NULL); + } + } + else + { + msg(msglevel, "cannot parse --ifconfig-push addresses"); + goto err; + } } -#endif - else if (streq (p[0], "verb") && p[1] && !p[2]) + else if (streq(p[0], "ifconfig-push-constraint") && p[1] && p[2] && !p[3]) { - VERIFY_PERMISSION (OPT_P_MESSAGES); - options->verbosity = positive_atoi (p[1]); -#if !defined(ENABLE_DEBUG) && !defined(ENABLE_SMALL) - /* Warn when a debug verbosity is supplied when built without debug support */ - if (options->verbosity >= 7) - msg (M_WARN, "NOTE: debug verbosity (--verb %d) is enabled but this build lacks debug support.", - options->verbosity); -#endif + in_addr_t network, netmask; + + VERIFY_PERMISSION(OPT_P_GENERAL); + network = getaddr(GETADDR_HOST_ORDER|GETADDR_RESOLVE, p[1], 0, NULL, NULL); + netmask = getaddr(GETADDR_HOST_ORDER, p[2], 0, NULL, NULL); + if (network && netmask) + { + options->push_ifconfig_constraint_defined = true; + options->push_ifconfig_constraint_network = network; + options->push_ifconfig_constraint_netmask = netmask; + } + else + { + msg(msglevel, "cannot parse --ifconfig-push-constraint addresses"); + goto err; + } } - else if (streq (p[0], "mute") && p[1] && !p[2]) + else if (streq(p[0], "ifconfig-ipv6-push") && p[1] && !p[3]) { - VERIFY_PERMISSION (OPT_P_MESSAGES); - options->mute = positive_atoi (p[1]); + struct in6_addr local, remote; + unsigned int netbits; + + VERIFY_PERMISSION(OPT_P_INSTANCE); + + if (!get_ipv6_addr( p[1], &local, &netbits, msglevel ) ) + { + msg(msglevel, "cannot parse --ifconfig-ipv6-push addresses"); + goto err; + } + + if (p[2]) + { + if (!get_ipv6_addr( p[2], &remote, NULL, msglevel ) ) + { + msg( msglevel, "cannot parse --ifconfig-ipv6-push addresses"); + goto err; + } + } + else + { + if (!options->ifconfig_ipv6_local + || !get_ipv6_addr( options->ifconfig_ipv6_local, &remote, + NULL, msglevel ) ) + { + msg( msglevel, "second argument to --ifconfig-ipv6-push missing and no global --ifconfig-ipv6 address set"); + goto err; + } + } + + options->push_ifconfig_ipv6_defined = true; + options->push_ifconfig_ipv6_local = local; + options->push_ifconfig_ipv6_netbits = netbits; + options->push_ifconfig_ipv6_remote = remote; + options->push_ifconfig_ipv6_blocked = false; } - else if (streq (p[0], "errors-to-stderr") && !p[1]) + else if (streq(p[0], "disable") && !p[1]) { - VERIFY_PERMISSION (OPT_P_MESSAGES); - errors_to_stderr(); + VERIFY_PERMISSION(OPT_P_INSTANCE); + options->disable = true; } - else if (streq (p[0], "status") && p[1] && !p[3]) + else if (streq(p[0], "tcp-nodelay") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->status_file = p[1]; - if (p[2]) - { - options->status_file_update_freq = positive_atoi (p[2]); - } + VERIFY_PERMISSION(OPT_P_GENERAL); + options->server_flags |= SF_TCP_NODELAY_HELPER; } - else if (streq (p[0], "status-version") && p[1] && !p[2]) + else if (streq(p[0], "stale-routes-check") && p[1] && !p[3]) { - int version; + int ageing_time, check_interval; - VERIFY_PERMISSION (OPT_P_GENERAL); - version = atoi (p[1]); - if (version < 1 || version > 3) - { - msg (msglevel, "--status-version must be 1 to 3"); - goto err; - } - options->status_file_version = version; - } - else if (streq (p[0], "remap-usr1") && p[1] && !p[2]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - if (streq (p[1], "SIGHUP")) - options->remap_sigusr1 = SIGHUP; - else if (streq (p[1], "SIGTERM")) - options->remap_sigusr1 = SIGTERM; - else - { - msg (msglevel, "--remap-usr1 parm must be 'SIGHUP' or 'SIGTERM'"); - goto err; - } - } - else if ((streq (p[0], "link-mtu") || streq (p[0], "udp-mtu")) && p[1] && !p[2]) - { - VERIFY_PERMISSION (OPT_P_MTU|OPT_P_CONNECTION); - options->ce.link_mtu = positive_atoi (p[1]); - options->ce.link_mtu_defined = true; + VERIFY_PERMISSION(OPT_P_GENERAL); + ageing_time = atoi(p[1]); + if (p[2]) + { + check_interval = atoi(p[2]); + } + else + { + check_interval = ageing_time; + } + + if (ageing_time < 1 || check_interval < 1) + { + msg(msglevel, "--stale-routes-check aging time and check interval must be >= 1"); + goto err; + } + options->stale_routes_ageing_time = ageing_time; + options->stale_routes_check_interval = check_interval; } - else if (streq (p[0], "tun-mtu") && p[1] && !p[2]) +#endif /* P2MP_SERVER */ + + else if (streq(p[0], "client") && !p[1]) { - VERIFY_PERMISSION (OPT_P_MTU|OPT_P_CONNECTION); - options->ce.tun_mtu = positive_atoi (p[1]); - options->ce.tun_mtu_defined = true; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->client = true; } - else if (streq (p[0], "tun-mtu-extra") && p[1] && !p[2]) + else if (streq(p[0], "pull") && !p[1]) { - VERIFY_PERMISSION (OPT_P_MTU|OPT_P_CONNECTION); - options->ce.tun_mtu_extra = positive_atoi (p[1]); - options->ce.tun_mtu_extra_defined = true; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->pull = true; } -#ifdef ENABLE_FRAGMENT - else if (streq (p[0], "mtu-dynamic")) + else if (streq(p[0], "push-continuation") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_MTU|OPT_P_CONNECTION); - msg (msglevel, "--mtu-dynamic has been replaced by --fragment"); - goto err; + VERIFY_PERMISSION(OPT_P_PULL_MODE); + options->push_continuation = atoi(p[1]); } - else if (streq (p[0], "fragment") && p[1] && !p[2]) + else if (streq(p[0], "auth-user-pass") && !p[2]) { -/* VERIFY_PERMISSION (OPT_P_MTU); */ - VERIFY_PERMISSION (OPT_P_MTU|OPT_P_CONNECTION); - options->ce.fragment = positive_atoi (p[1]); + VERIFY_PERMISSION(OPT_P_GENERAL); + if (p[1]) + { + options->auth_user_pass_file = p[1]; + } + else + { + options->auth_user_pass_file = "stdin"; + } } -#endif - else if (streq (p[0], "mtu-disc") && p[1] && !p[2]) + else if (streq(p[0], "auth-retry") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_MTU|OPT_P_CONNECTION); - options->ce.mtu_discover_type = translate_mtu_discover_type_name (p[1]); + VERIFY_PERMISSION(OPT_P_GENERAL); + auth_retry_set(msglevel, p[1]); } -#ifdef ENABLE_OCC - else if (streq (p[0], "mtu-test") && !p[1]) +#ifdef ENABLE_CLIENT_CR + else if (streq(p[0], "static-challenge") && p[1] && p[2] && !p[3]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->mtu_test = true; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->sc_info.challenge_text = p[1]; + if (atoi(p[2])) + { + options->sc_info.flags |= SC_ECHO; + } } #endif - else if (streq (p[0], "nice") && p[1] && !p[2]) +#endif /* if P2MP */ + else if (streq(p[0], "msg-channel") && p[1]) { - VERIFY_PERMISSION (OPT_P_NICE); - options->nice = atoi (p[1]); - } - else if (streq (p[0], "rcvbuf") && p[1] && !p[2]) - { - VERIFY_PERMISSION (OPT_P_SOCKBUF); - options->rcvbuf = positive_atoi (p[1]); - } - else if (streq (p[0], "sndbuf") && p[1] && !p[2]) - { - VERIFY_PERMISSION (OPT_P_SOCKBUF); - options->sndbuf = positive_atoi (p[1]); - } - else if (streq (p[0], "mark") && p[1] && !p[2]) - { -#if defined(TARGET_LINUX) && HAVE_DECL_SO_MARK - VERIFY_PERMISSION (OPT_P_GENERAL); - options->mark = atoi(p[1]); +#ifdef _WIN32 + VERIFY_PERMISSION(OPT_P_GENERAL); + HANDLE process = GetCurrentProcess(); + HANDLE handle = (HANDLE) atoi(p[1]); + if (!DuplicateHandle(process, handle, process, &options->msg_channel, 0, + FALSE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) + { + msg(msglevel, "could not duplicate service pipe handle"); + goto err; + } + options->route_method = ROUTE_METHOD_SERVICE; +#else /* ifdef _WIN32 */ + msg(msglevel, "--msg-channel is only supported on Windows"); + goto err; #endif } - else if (streq (p[0], "socket-flags")) - { - int j; - VERIFY_PERMISSION (OPT_P_SOCKFLAGS); - for (j = 1; j < MAX_PARMS && p[j]; ++j) - { - if (streq (p[j], "TCP_NODELAY")) - options->sockflags |= SF_TCP_NODELAY; - else - msg (msglevel, "unknown socket flag: %s", p[j]); - } - } - else if (streq (p[0], "txqueuelen") && p[1] && !p[2]) +#ifdef _WIN32 + else if (streq(p[0], "win-sys") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_GENERAL); -#ifdef TARGET_LINUX - options->tuntap_options.txqueuelen = positive_atoi (p[1]); -#else - msg (msglevel, "--txqueuelen not supported on this OS"); - goto err; -#endif + VERIFY_PERMISSION(OPT_P_GENERAL); + if (streq(p[1], "env")) + { + msg(M_INFO, "NOTE: --win-sys env is default from OpenVPN v2.3. " + "This entry will now be ignored. " + "Please remove this entry from your configuration file."); + } + else + { + set_win_sys_path(p[1], es); + } } - else if (streq (p[0], "shaper") && p[1] && !p[2]) + else if (streq(p[0], "route-method") && p[1] && !p[2]) { -#ifdef ENABLE_FEATURE_SHAPER - int shaper; - - VERIFY_PERMISSION (OPT_P_SHAPER); - shaper = atoi (p[1]); - if (shaper < SHAPER_MIN || shaper > SHAPER_MAX) - { - msg (msglevel, "Bad shaper value, must be between %d and %d", - SHAPER_MIN, SHAPER_MAX); - goto err; - } - options->shaper = shaper; -#else /* ENABLE_FEATURE_SHAPER */ - VERIFY_PERMISSION (OPT_P_GENERAL); - msg (msglevel, "--shaper requires the gettimeofday() function which is missing"); - goto err; -#endif /* ENABLE_FEATURE_SHAPER */ - } - else if (streq (p[0], "port") && p[1] && !p[2]) - { - VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); - options->ce.local_port = options->ce.remote_port = p[1]; - } - else if (streq (p[0], "lport") && p[1] && !p[2]) - { - VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); - options->ce.local_port_defined = true; - options->ce.local_port = p[1]; - } - else if (streq (p[0], "rport") && p[1] && !p[2]) - { - VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); - options->ce.remote_port = p[1]; - } - else if (streq (p[0], "bind") && !p[1]) - { - VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); - options->ce.bind_defined = true; - if (p[1] && streq (p[1], "ipv6only")) - options->ce.bind_ipv6_only=true; - - } - else if (streq (p[0], "nobind") && !p[1]) - { - VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); - options->ce.bind_local = false; - } - else if (streq (p[0], "fast-io") && !p[1]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->fast_io = true; - } - else if (streq (p[0], "inactive") && p[1] && !p[3]) - { - VERIFY_PERMISSION (OPT_P_TIMER); - options->inactivity_timeout = positive_atoi (p[1]); - if (p[2]) - options->inactivity_minimum_bytes = positive_atoi (p[2]); - } - else if (streq (p[0], "proto") && p[1] && !p[2]) - { - int proto; - sa_family_t af; - VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); - proto = ascii2proto (p[1]); - af = ascii2af(p[1]); - if (proto < 0) - { - msg (msglevel, "Bad protocol: '%s'. Allowed protocols with --proto option: %s", - p[1], - proto2ascii_all (&gc)); - goto err; - } - options->ce.proto = proto; - options->ce.af = af; - } - else if (streq (p[0], "proto-force") && p[1] && !p[2]) - { - int proto_force; - VERIFY_PERMISSION (OPT_P_GENERAL); - proto_force = ascii2proto (p[1]); - if (proto_force < 0) - { - msg (msglevel, "Bad --proto-force protocol: '%s'", p[1]); - goto err; - } - options->proto_force = proto_force; - } - else if (streq (p[0], "http-proxy") && p[1] && !p[5]) - { - struct http_proxy_options *ho; - - VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); - - { - if (!p[2]) - { - msg (msglevel, "http-proxy port number not defined"); - goto err; - } - - ho = init_http_proxy_options_once (&options->ce.http_proxy_options, &options->gc); - - ho->server = p[1]; - ho->port = p[2]; - } - - if (p[3]) - { - /* auto -- try to figure out proxy addr, port, and type automatically */ - /* semiauto -- given proxy addr:port, try to figure out type automatically */ - /* (auto|semiauto)-nct -- disable proxy auth cleartext protocols (i.e. basic auth) */ - if (streq (p[3], "auto")) - ho->auth_retry = PAR_ALL; - else if (streq (p[3], "auto-nct")) - ho->auth_retry = PAR_NCT; - else - { - ho->auth_method_string = "basic"; - ho->auth_file = p[3]; - - if (p[4]) - { - ho->auth_method_string = p[4]; - } - } - } - else - { - ho->auth_method_string = "none"; - } - } - else if (streq (p[0], "http-proxy-user-pass") && p[1]) - { - struct http_proxy_options *ho; - VERIFY_PERMISSION (OPT_P_GENERAL); - ho = init_http_proxy_options_once (&options->ce.http_proxy_options, &options->gc); - if (streq (p[1], INLINE_FILE_TAG) && p[2]) - { - ho->auth_file = p[2]; - ho->inline_creds = true; - } - else - ho->auth_file = p[1]; - } - else if (streq (p[0], "http-proxy-retry") || streq (p[0], "socks-proxy-retry")) - { - VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); - msg (M_WARN, "DEPRECATED OPTION: http-proxy-retry and socks-proxy-retry: " - "In OpenVPN 2.4 proxy connection retries are handled like regular connections. " - "Use connect-retry-max 1 to get a similar behavior as before."); - } - else if (streq (p[0], "http-proxy-timeout") && p[1] && !p[2]) - { - VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); - msg (M_WARN, "DEPRECATED OPTION: http-proxy-timeout: In OpenVPN 2.4 the timeout until a connection to a " - "server is established is managed with a single timeout set by connect-timeout"); - } - else if (streq (p[0], "http-proxy-option") && p[1] && !p[4]) - { - struct http_proxy_options *ho; - - VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); - ho = init_http_proxy_options_once (&options->ce.http_proxy_options, &options->gc); - - if (streq (p[1], "VERSION") && p[2] && !p[3]) - { - ho->http_version = p[2]; - } - else if (streq (p[1], "AGENT") && p[2] && !p[3]) - { - ho->user_agent = p[2]; - } - else if ((streq (p[1], "EXT1") || streq(p[1], "EXT2") || streq(p[1], "CUSTOM-HEADER")) - && p[2]) - { - /* In the wild patched versions use both EXT1/2 and CUSTOM-HEADER - * with either two argument or one */ - - struct http_custom_header *custom_header = NULL; - int i; - /* Find the first free header */ - for (i=0; i < MAX_CUSTOM_HTTP_HEADER; i++) { - if (!ho->custom_headers[i].name) { - custom_header = &ho->custom_headers[i]; - break; - } - } - if (!custom_header) - { - msg (msglevel, "Cannot use more than %d http-proxy-option CUSTOM-HEADER : '%s'", MAX_CUSTOM_HTTP_HEADER, p[1]); - } - else - { - /* We will save p[2] and p[3], the proxy code will detect if - * p[3] is NULL */ - custom_header->name = p[2]; - custom_header->content = p[3]; - } - } - else - { - msg (msglevel, "Bad http-proxy-option or missing or extra parameter: '%s'", p[1]); - } - } - else if (streq (p[0], "socks-proxy") && p[1] && !p[4]) - { - VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); - - if (p[2]) - { - options->ce.socks_proxy_port = p[2]; - } - else - { - options->ce.socks_proxy_port = "1080"; - } - options->ce.socks_proxy_server = p[1]; - options->ce.socks_proxy_authfile = p[3]; /* might be NULL */ - } - else if (streq (p[0], "keepalive") && p[1] && p[2] && !p[3]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->keepalive_ping = atoi (p[1]); - options->keepalive_timeout = atoi (p[2]); - } - else if (streq (p[0], "ping") && p[1] && !p[2]) - { - VERIFY_PERMISSION (OPT_P_TIMER); - options->ping_send_timeout = positive_atoi (p[1]); - } - else if (streq (p[0], "ping-exit") && p[1] && !p[2]) - { - VERIFY_PERMISSION (OPT_P_TIMER); - options->ping_rec_timeout = positive_atoi (p[1]); - options->ping_rec_timeout_action = PING_EXIT; - } - else if (streq (p[0], "ping-restart") && p[1] && !p[2]) - { - VERIFY_PERMISSION (OPT_P_TIMER); - options->ping_rec_timeout = positive_atoi (p[1]); - options->ping_rec_timeout_action = PING_RESTART; - } - else if (streq (p[0], "ping-timer-rem") && !p[1]) - { - VERIFY_PERMISSION (OPT_P_TIMER); - options->ping_timer_remote = true; - } -#ifdef ENABLE_OCC - else if (streq (p[0], "explicit-exit-notify") && !p[2]) - { - VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION|OPT_P_EXPLICIT_NOTIFY); - if (p[1]) - { - options->ce.explicit_exit_notification = positive_atoi (p[1]); - } - else - { - options->ce.explicit_exit_notification = 1; - } - } -#endif - else if (streq (p[0], "persist-tun") && !p[1]) - { - VERIFY_PERMISSION (OPT_P_PERSIST); - options->persist_tun = true; - } - else if (streq (p[0], "persist-key") && !p[1]) - { - VERIFY_PERMISSION (OPT_P_PERSIST); - options->persist_key = true; - } - else if (streq (p[0], "persist-local-ip") && !p[1]) - { - VERIFY_PERMISSION (OPT_P_PERSIST_IP); - options->persist_local_ip = true; - } - else if (streq (p[0], "persist-remote-ip") && !p[1]) - { - VERIFY_PERMISSION (OPT_P_PERSIST_IP); - options->persist_remote_ip = true; - } - else if (streq (p[0], "client-nat") && p[1] && p[2] && p[3] && p[4] && !p[5]) - { - VERIFY_PERMISSION (OPT_P_ROUTE); - cnol_check_alloc (options); - add_client_nat_to_option_list(options->client_nat, p[1], p[2], p[3], p[4], msglevel); - } - else if (streq (p[0], "route") && p[1] && !p[5]) - { - VERIFY_PERMISSION (OPT_P_ROUTE); - rol_check_alloc (options); - if (pull_mode) - { - if (!ip_or_dns_addr_safe (p[1], options->allow_pull_fqdn) && !is_special_addr (p[1])) /* FQDN -- may be DNS name */ - { - msg (msglevel, "route parameter network/IP '%s' must be a valid address", p[1]); - goto err; - } - if (p[2] && !ip_addr_dotted_quad_safe (p[2])) /* FQDN -- must be IP address */ - { - msg (msglevel, "route parameter netmask '%s' must be an IP address", p[2]); - goto err; - } - if (p[3] && !ip_or_dns_addr_safe (p[3], options->allow_pull_fqdn) && !is_special_addr (p[3])) /* FQDN -- may be DNS name */ - { - msg (msglevel, "route parameter gateway '%s' must be a valid address", p[3]); - goto err; - } - } - add_route_to_option_list (options->routes, p[1], p[2], p[3], p[4]); - } - else if (streq (p[0], "route-ipv6") && p[1] && !p[4]) - { - VERIFY_PERMISSION (OPT_P_ROUTE); - rol6_check_alloc (options); - if (pull_mode) - { - if (!ipv6_addr_safe_hexplusbits (p[1])) - { - msg (msglevel, "route-ipv6 parameter network/IP '%s' must be a valid address", p[1]); - goto err; - } - if (p[2] && !ipv6_addr_safe (p[2])) - { - msg (msglevel, "route-ipv6 parameter gateway '%s' must be a valid address", p[2]); - goto err; - } - /* p[3] is metric, if present */ - } - add_route_ipv6_to_option_list (options->routes_ipv6, p[1], p[2], p[3]); - } - else if (streq (p[0], "max-routes") && !p[2]) - { - msg (M_WARN, "DEPRECATED OPTION: --max-routes option ignored." - "The number of routes is unlimited as of version 2.4. " - "This option will be removed in a future version, " - "please remove it from your configuration."); - } - else if (streq (p[0], "route-gateway") && p[1] && !p[2]) - { - VERIFY_PERMISSION (OPT_P_ROUTE_EXTRAS); - if (streq (p[1], "dhcp")) - { - options->route_gateway_via_dhcp = true; - } - else - { - if (ip_or_dns_addr_safe (p[1], options->allow_pull_fqdn) || is_special_addr (p[1])) /* FQDN -- may be DNS name */ - { - options->route_default_gateway = p[1]; - } - else - { - msg (msglevel, "route-gateway parm '%s' must be a valid address", p[1]); - goto err; - } - } - } - else if (streq (p[0], "route-metric") && p[1] && !p[2]) - { - VERIFY_PERMISSION (OPT_P_ROUTE); - options->route_default_metric = positive_atoi (p[1]); - } - else if (streq (p[0], "route-delay") && !p[3]) - { - VERIFY_PERMISSION (OPT_P_ROUTE_EXTRAS); - options->route_delay_defined = true; - if (p[1]) - { - options->route_delay = positive_atoi (p[1]); - if (p[2]) - { - options->route_delay_window = positive_atoi (p[2]); - } - } - else - { - options->route_delay = 0; - } - } - else if (streq (p[0], "route-up") && p[1]) - { - VERIFY_PERMISSION (OPT_P_SCRIPT); - if (!no_more_than_n_args (msglevel, p, 2, NM_QUOTE_HINT)) - goto err; - set_user_script (options, &options->route_script, p[1], "route-up", false); - } - else if (streq (p[0], "route-pre-down") && p[1]) - { - VERIFY_PERMISSION (OPT_P_SCRIPT); - if (!no_more_than_n_args (msglevel, p, 2, NM_QUOTE_HINT)) - goto err; - set_user_script (options, - &options->route_predown_script, - p[1], - "route-pre-down", true); - } - else if (streq (p[0], "route-noexec") && !p[1]) - { - VERIFY_PERMISSION (OPT_P_SCRIPT); - options->route_noexec = true; - } - else if (streq (p[0], "route-nopull") && !p[1]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->route_nopull = true; - } - else if (streq (p[0], "pull-filter") && p[1] && p[2] && !p[3]) - { - struct pull_filter *f; - VERIFY_PERMISSION (OPT_P_GENERAL) - f = alloc_pull_filter (options, msglevel); - - if (strcmp ("accept", p[1]) == 0) - f->type = PUF_TYPE_ACCEPT; - else if (strcmp ("ignore", p[1]) == 0) - f->type = PUF_TYPE_IGNORE; - else if (strcmp ("reject", p[1]) == 0) - f->type = PUF_TYPE_REJECT; - else - { - msg (msglevel, "Unknown --pull-filter type: %s", p[1]); - goto err; - } - f->pattern = p[2]; - f->size = strlen(p[2]); - } - else if (streq (p[0], "allow-pull-fqdn") && !p[1]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->allow_pull_fqdn = true; - } - else if (streq (p[0], "redirect-gateway") || streq (p[0], "redirect-private")) - { - int j; - VERIFY_PERMISSION (OPT_P_ROUTE); - rol_check_alloc (options); - if (streq (p[0], "redirect-gateway")) - options->routes->flags |= RG_REROUTE_GW; - for (j = 1; j < MAX_PARMS && p[j] != NULL; ++j) - { - if (streq (p[j], "local")) - options->routes->flags |= RG_LOCAL; - else if (streq (p[j], "autolocal")) - options->routes->flags |= RG_AUTO_LOCAL; - else if (streq (p[j], "def1")) - options->routes->flags |= RG_DEF1; - else if (streq (p[j], "bypass-dhcp")) - options->routes->flags |= RG_BYPASS_DHCP; - else if (streq (p[j], "bypass-dns")) - options->routes->flags |= RG_BYPASS_DNS; - else if (streq (p[j], "block-local")) - options->routes->flags |= RG_BLOCK_LOCAL; - else if (streq (p[j], "ipv6")) - { - rol6_check_alloc (options); - options->routes_ipv6->flags |= RG_REROUTE_GW; - } - else if (streq (p[j], "!ipv4")) - options->routes->flags &= ~RG_REROUTE_GW; - else - { - msg (msglevel, "unknown --%s flag: %s", p[0], p[j]); - goto err; - } - } -#ifdef _WIN32 - /* we need this here to handle pushed --redirect-gateway */ - remap_redirect_gateway_flags (options); -#endif - options->routes->flags |= RG_ENABLE; + VERIFY_PERMISSION(OPT_P_ROUTE_EXTRAS); + if (streq(p[1], "adaptive")) + { + options->route_method = ROUTE_METHOD_ADAPTIVE; + } + else if (streq(p[1], "ipapi")) + { + options->route_method = ROUTE_METHOD_IPAPI; + } + else if (streq(p[1], "exe")) + { + options->route_method = ROUTE_METHOD_EXE; + } + else + { + msg(msglevel, "--route method must be 'adaptive', 'ipapi', or 'exe'"); + goto err; + } } - else if (streq (p[0], "remote-random-hostname") && !p[1]) + else if (streq(p[0], "ip-win32") && p[1] && !p[4]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->sockflags |= SF_HOST_RANDOMIZE; + const int index = ascii2ipset(p[1]); + struct tuntap_options *to = &options->tuntap_options; + + VERIFY_PERMISSION(OPT_P_IPWIN32); + + if (index < 0) + { + msg(msglevel, + "Bad --ip-win32 method: '%s'. Allowed methods: %s", + p[1], + ipset2ascii_all(&gc)); + goto err; + } + + if (index == IPW32_SET_ADAPTIVE) + { + options->route_delay_window = IPW32_SET_ADAPTIVE_DELAY_WINDOW; + } + + if (index == IPW32_SET_DHCP_MASQ) + { + if (p[2]) + { + if (!streq(p[2], "default")) + { + int offset = atoi(p[2]); + + if (!(offset > -256 && offset < 256)) + { + msg(msglevel, "--ip-win32 dynamic [offset] [lease-time]: offset (%d) must be > -256 and < 256", offset); + goto err; + } + + to->dhcp_masq_custom_offset = true; + to->dhcp_masq_offset = offset; + } + + if (p[3]) + { + const int min_lease = 30; + int lease_time; + lease_time = atoi(p[3]); + if (lease_time < min_lease) + { + msg(msglevel, "--ip-win32 dynamic [offset] [lease-time]: lease time parameter (%d) must be at least %d seconds", lease_time, min_lease); + goto err; + } + to->dhcp_lease_time = lease_time; + } + } + } + to->ip_win32_type = index; + to->ip_win32_defined = true; } - else if (streq (p[0], "setenv") && p[1] && !p[3]) +#endif /* ifdef _WIN32 */ +#if defined(_WIN32) || defined(TARGET_ANDROID) + else if (streq(p[0], "dhcp-option") && p[1] && !p[3]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - if (streq (p[1], "REMOTE_RANDOM_HOSTNAME") && !p[2]) - { - options->sockflags |= SF_HOST_RANDOMIZE; - } - else if (streq (p[1], "GENERIC_CONFIG")) - { - msg (msglevel, "this is a generic configuration and cannot directly be used"); - goto err; - } -#ifdef ENABLE_PUSH_PEER_INFO - else if (streq (p[1], "PUSH_PEER_INFO") && !p[2]) - { - options->push_peer_info = true; - } -#endif - else if (streq (p[1], "SERVER_POLL_TIMEOUT") && p[2]) - { - options->ce.connect_timeout = positive_atoi(p[2]); - } - else - { - if (streq (p[1], "FORWARD_COMPATIBLE") && p[2] && streq (p[2], "1")) - { - options->forward_compatible = true; - msglevel_fc = msglevel_forward_compatible (options, msglevel); - } - setenv_str (es, p[1], p[2] ? p[2] : ""); - } - } - else if (streq (p[0], "setenv-safe") && p[1] && !p[3]) - { - VERIFY_PERMISSION (OPT_P_SETENV); - setenv_str_safe (es, p[1], p[2] ? p[2] : ""); - } - else if (streq (p[0], "script-security") && p[1] && !p[2]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - script_security = atoi (p[1]); - } - else if (streq (p[0], "mssfix") && !p[2]) - { - VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); - if (p[1]) - { - options->ce.mssfix = positive_atoi (p[1]); - } - else - options->ce.mssfix_default = true; + struct tuntap_options *o = &options->tuntap_options; + VERIFY_PERMISSION(OPT_P_IPWIN32); + + if (streq(p[1], "DOMAIN") && p[2]) + { + o->domain = p[2]; + } + else if (streq(p[1], "NBS") && p[2]) + { + o->netbios_scope = p[2]; + } + else if (streq(p[1], "NBT") && p[2]) + { + int t; + t = atoi(p[2]); + if (!(t == 1 || t == 2 || t == 4 || t == 8)) + { + msg(msglevel, "--dhcp-option NBT: parameter (%d) must be 1, 2, 4, or 8", t); + goto err; + } + o->netbios_node_type = t; + } + else if (streq(p[1], "DNS") && p[2]) + { + dhcp_option_address_parse("DNS", p[2], o->dns, &o->dns_len, msglevel); + } + else if (streq(p[1], "DNS6") && p[2] && ipv6_addr_safe(p[2])) + { + struct in6_addr addr; + foreign_option(options, p, 3, es); + if (o->dns6_len >= N_DHCP_ADDR) + { + msg(msglevel, "--dhcp-option DNS6: maximum of %d dns servers can be specified", + N_DHCP_ADDR); + } + else if (get_ipv6_addr(p[2], &addr, NULL, msglevel)) + { + o->dns6[o->dns6_len++] = addr; + } + } + else if (streq(p[1], "WINS") && p[2]) + { + dhcp_option_address_parse("WINS", p[2], o->wins, &o->wins_len, msglevel); + } + else if (streq(p[1], "NTP") && p[2]) + { + dhcp_option_address_parse("NTP", p[2], o->ntp, &o->ntp_len, msglevel); + } + else if (streq(p[1], "NBDD") && p[2]) + { + dhcp_option_address_parse("NBDD", p[2], o->nbdd, &o->nbdd_len, msglevel); + } + else if (streq(p[1], "DISABLE-NBT") && !p[2]) + { + o->disable_nbt = 1; + } + else + { + msg(msglevel, "--dhcp-option: unknown option type '%s' or missing or unknown parameter", p[1]); + goto err; + } + /* flag that we have options to give to the TAP driver's DHCPv4 server + * - skipped for "DNS6", as that's not a DHCPv4 option + */ + if (!streq(p[1], "DNS6")) + { + o->dhcp_options = true; + } } -#ifdef ENABLE_OCC - else if (streq (p[0], "disable-occ") && !p[1]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->occ = false; - } -#endif -#if P2MP -#if P2MP_SERVER - else if (streq (p[0], "server") && p[1] && p[2] && !p[4]) - { - const int lev = M_WARN; - bool error = false; - in_addr_t network, netmask; - - VERIFY_PERMISSION (OPT_P_GENERAL); - network = get_ip_addr (p[1], lev, &error); - netmask = get_ip_addr (p[2], lev, &error); - if (error || !network || !netmask) - { - msg (msglevel, "error parsing --server parameters"); - goto err; - } - options->server_defined = true; - options->server_network = network; - options->server_netmask = netmask; - - if (p[3]) - { - if (streq (p[3], "nopool")) - options->server_flags |= SF_NOPOOL; - else - { - msg (msglevel, "error parsing --server: %s is not a recognized flag", p[3]); - goto err; - } - } - } - else if (streq (p[0], "server-ipv6") && p[1] && !p[3]) - { - const int lev = M_WARN; - struct in6_addr network; - unsigned int netbits = 0; - - VERIFY_PERMISSION (OPT_P_GENERAL); - if ( ! get_ipv6_addr (p[1], &network, &netbits, lev) ) - { - msg (msglevel, "error parsing --server-ipv6 parameter"); - goto err; - } - if ( netbits < 64 || netbits > 112 ) - { - msg( msglevel, "--server-ipv6 settings: only /64../112 supported right now (not /%d)", netbits ); - goto err; - } - options->server_ipv6_defined = true; - options->server_network_ipv6 = network; - options->server_netbits_ipv6 = netbits; - - if (p[2]) /* no "nopool" options or similar for IPv6 */ - { - msg (msglevel, "error parsing --server-ipv6: %s is not a recognized flag", p[3]); - goto err; - } - } - else if (streq (p[0], "server-bridge") && p[1] && p[2] && p[3] && p[4] && !p[5]) - { - const int lev = M_WARN; - bool error = false; - in_addr_t ip, netmask, pool_start, pool_end; - - VERIFY_PERMISSION (OPT_P_GENERAL); - ip = get_ip_addr (p[1], lev, &error); - netmask = get_ip_addr (p[2], lev, &error); - pool_start = get_ip_addr (p[3], lev, &error); - pool_end = get_ip_addr (p[4], lev, &error); - if (error || !ip || !netmask || !pool_start || !pool_end) - { - msg (msglevel, "error parsing --server-bridge parameters"); - goto err; - } - options->server_bridge_defined = true; - options->server_bridge_ip = ip; - options->server_bridge_netmask = netmask; - options->server_bridge_pool_start = pool_start; - options->server_bridge_pool_end = pool_end; - } - else if (streq (p[0], "server-bridge") && p[1] && streq (p[1], "nogw") && !p[2]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->server_bridge_proxy_dhcp = true; - options->server_flags |= SF_NO_PUSH_ROUTE_GATEWAY; - } - else if (streq (p[0], "server-bridge") && !p[1]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->server_bridge_proxy_dhcp = true; - } - else if (streq (p[0], "push") && p[1] && !p[2]) - { - VERIFY_PERMISSION (OPT_P_PUSH); - push_options (options, &p[1], msglevel, &options->gc); - } - else if (streq (p[0], "push-reset") && !p[1]) - { - VERIFY_PERMISSION (OPT_P_INSTANCE); - push_reset (options); - } - else if (streq (p[0], "push-remove") && p[1] && !p[2]) - { - VERIFY_PERMISSION (OPT_P_INSTANCE); - msg (D_PUSH, "PUSH_REMOVE '%s'", p[1]); - push_remove_option (options,p[1]); - } - else if (streq (p[0], "ifconfig-pool") && p[1] && p[2] && !p[4]) - { - const int lev = M_WARN; - bool error = false; - in_addr_t start, end, netmask=0; - - VERIFY_PERMISSION (OPT_P_GENERAL); - start = get_ip_addr (p[1], lev, &error); - end = get_ip_addr (p[2], lev, &error); - if (p[3]) - { - netmask = get_ip_addr (p[3], lev, &error); - } - if (error) - { - msg (msglevel, "error parsing --ifconfig-pool parameters"); - goto err; - } - if (!ifconfig_pool_verify_range (msglevel, start, end)) - goto err; - - options->ifconfig_pool_defined = true; - options->ifconfig_pool_start = start; - options->ifconfig_pool_end = end; - if (netmask) - options->ifconfig_pool_netmask = netmask; - } - else if (streq (p[0], "ifconfig-pool-persist") && p[1] && !p[3]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->ifconfig_pool_persist_filename = p[1]; - if (p[2]) - { - options->ifconfig_pool_persist_refresh_freq = positive_atoi (p[2]); - } - } - else if (streq (p[0], "ifconfig-pool-linear") && !p[1]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->topology = TOP_P2P; - } - else if (streq (p[0], "ifconfig-ipv6-pool") && p[1] && !p[2]) - { - const int lev = M_WARN; - struct in6_addr network; - unsigned int netbits = 0; - - VERIFY_PERMISSION (OPT_P_GENERAL); - if ( ! get_ipv6_addr (p[1], &network, &netbits, lev ) ) - { - msg (msglevel, "error parsing --ifconfig-ipv6-pool parameters"); - goto err; - } - if ( netbits < 64 || netbits > 112 ) - { - msg( msglevel, "--ifconfig-ipv6-pool settings: only /64../112 supported right now (not /%d)", netbits ); - goto err; - } - - options->ifconfig_ipv6_pool_defined = true; - options->ifconfig_ipv6_pool_base = network; - options->ifconfig_ipv6_pool_netbits = netbits; - } - else if (streq (p[0], "hash-size") && p[1] && p[2] && !p[3]) - { - int real, virtual; - - VERIFY_PERMISSION (OPT_P_GENERAL); - real = atoi (p[1]); - virtual = atoi (p[2]); - if (real < 1 || virtual < 1) - { - msg (msglevel, "--hash-size sizes must be >= 1 (preferably a power of 2)"); - goto err; - } - options->real_hash_size = real; - options->virtual_hash_size = real; - } - else if (streq (p[0], "connect-freq") && p[1] && p[2] && !p[3]) - { - int cf_max, cf_per; - - VERIFY_PERMISSION (OPT_P_GENERAL); - cf_max = atoi (p[1]); - cf_per = atoi (p[2]); - if (cf_max < 0 || cf_per < 0) - { - msg (msglevel, "--connect-freq parms must be > 0"); - goto err; - } - options->cf_max = cf_max; - options->cf_per = cf_per; - } - else if (streq (p[0], "max-clients") && p[1] && !p[2]) - { - int max_clients; - - VERIFY_PERMISSION (OPT_P_GENERAL); - max_clients = atoi (p[1]); - if (max_clients < 0) - { - msg (msglevel, "--max-clients must be at least 1"); - goto err; - } - if (max_clients >= MAX_PEER_ID) /* max peer-id value */ - { - msg (msglevel, "--max-clients must be less than %d", MAX_PEER_ID); - goto err; - } - options->max_clients = max_clients; - } - else if (streq (p[0], "max-routes-per-client") && p[1] && !p[2]) - { - VERIFY_PERMISSION (OPT_P_INHERIT); - options->max_routes_per_client = max_int (atoi (p[1]), 1); - } - else if (streq (p[0], "client-cert-not-required") && !p[1]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->ssl_flags |= SSLF_CLIENT_CERT_NOT_REQUIRED; - msg (M_WARN, "DEPRECATED OPTION: --client-cert-not-required, use --verify-client-cert instead"); - } - else if (streq (p[0], "verify-client-cert") && !p[2]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - - /* Reset any existing flags */ - options->ssl_flags &= ~SSLF_CLIENT_CERT_OPTIONAL; - options->ssl_flags &= ~SSLF_CLIENT_CERT_NOT_REQUIRED; - if (p[1]) - { - if (streq (p[1], "none")) - options->ssl_flags |= SSLF_CLIENT_CERT_NOT_REQUIRED; - else if (streq (p[1], "optional")) - options->ssl_flags |= SSLF_CLIENT_CERT_OPTIONAL; - else if (!streq (p[1], "require")) - { - msg (msglevel, "parameter to --verify-client-cert must be 'none', 'optional' or 'require'"); - goto err; - } - } - } - else if (streq (p[0], "username-as-common-name") && !p[1]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->ssl_flags |= SSLF_USERNAME_AS_COMMON_NAME; - } - else if (streq (p[0], "auth-user-pass-optional") && !p[1]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->ssl_flags |= SSLF_AUTH_USER_PASS_OPTIONAL; - } - else if (streq (p[0], "opt-verify") && !p[1]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->ssl_flags |= SSLF_OPT_VERIFY; - } - else if (streq (p[0], "auth-user-pass-verify") && p[1]) - { - VERIFY_PERMISSION (OPT_P_SCRIPT); - if (!no_more_than_n_args (msglevel, p, 3, NM_QUOTE_HINT)) - goto err; - if (p[2]) - { - if (streq (p[2], "via-env")) - options->auth_user_pass_verify_script_via_file = false; - else if (streq (p[2], "via-file")) - options->auth_user_pass_verify_script_via_file = true; - else - { - msg (msglevel, "second parm to --auth-user-pass-verify must be 'via-env' or 'via-file'"); - goto err; - } - } - else - { - msg (msglevel, "--auth-user-pass-verify requires a second parameter ('via-env' or 'via-file')"); - goto err; - } - set_user_script (options, - &options->auth_user_pass_verify_script, - p[1], "auth-user-pass-verify", true); - } - else if (streq (p[0], "auth-gen-token")) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->auth_token_generate = true; - options->auth_token_lifetime = p[1] ? positive_atoi (p[1]) : 0; - } - else if (streq (p[0], "client-connect") && p[1]) - { - VERIFY_PERMISSION (OPT_P_SCRIPT); - if (!no_more_than_n_args (msglevel, p, 2, NM_QUOTE_HINT)) - goto err; - set_user_script (options, &options->client_connect_script, - p[1], "client-connect", true); - } - else if (streq (p[0], "client-disconnect") && p[1]) - { - VERIFY_PERMISSION (OPT_P_SCRIPT); - if (!no_more_than_n_args (msglevel, p, 2, NM_QUOTE_HINT)) - goto err; - set_user_script (options, &options->client_disconnect_script, - p[1], "client-disconnect", true); - } - else if (streq (p[0], "learn-address") && p[1]) - { - VERIFY_PERMISSION (OPT_P_SCRIPT); - if (!no_more_than_n_args (msglevel, p, 2, NM_QUOTE_HINT)) - goto err; - set_user_script (options, &options->learn_address_script, - p[1], "learn-address", true); - } - else if (streq (p[0], "tmp-dir") && p[1] && !p[2]) +#endif /* if defined(_WIN32) || defined(TARGET_ANDROID) */ +#ifdef _WIN32 + else if (streq(p[0], "show-adapters") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->tmp_dir = p[1]; + VERIFY_PERMISSION(OPT_P_GENERAL); + show_tap_win_adapters(M_INFO|M_NOPREFIX, M_WARN|M_NOPREFIX); + openvpn_exit(OPENVPN_EXIT_STATUS_GOOD); /* exit point */ } - else if (streq (p[0], "client-config-dir") && p[1] && !p[2]) + else if (streq(p[0], "show-net") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->client_config_dir = p[1]; + VERIFY_PERMISSION(OPT_P_GENERAL); + show_routes(M_INFO|M_NOPREFIX); + show_adapters(M_INFO|M_NOPREFIX); + openvpn_exit(OPENVPN_EXIT_STATUS_GOOD); /* exit point */ } - else if (streq (p[0], "ccd-exclusive") && !p[1]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->ccd_exclusive = true; - } - else if (streq (p[0], "bcast-buffers") && p[1] && !p[2]) + else if (streq(p[0], "show-net-up") && !p[1]) { - int n_bcast_buf; - - VERIFY_PERMISSION (OPT_P_GENERAL); - n_bcast_buf = atoi (p[1]); - if (n_bcast_buf < 1) - msg (msglevel, "--bcast-buffers parameter must be > 0"); - options->n_bcast_buf = n_bcast_buf; + VERIFY_PERMISSION(OPT_P_UP); + options->show_net_up = true; } - else if (streq (p[0], "tcp-queue-limit") && p[1] && !p[2]) + else if (streq(p[0], "tap-sleep") && p[1] && !p[2]) { - int tcp_queue_limit; - - VERIFY_PERMISSION (OPT_P_GENERAL); - tcp_queue_limit = atoi (p[1]); - if (tcp_queue_limit < 1) - msg (msglevel, "--tcp-queue-limit parameter must be > 0"); - options->tcp_queue_limit = tcp_queue_limit; - } -#if PORT_SHARE - else if (streq (p[0], "port-share") && p[1] && p[2] && !p[4]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->port_share_host = p[1]; - options->port_share_port = p[2]; - options->port_share_journal_dir = p[3]; - } -#endif - else if (streq (p[0], "client-to-client") && !p[1]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->enable_c2c = true; - } - else if (streq (p[0], "duplicate-cn") && !p[1]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->duplicate_cn = true; - } - else if (streq (p[0], "iroute") && p[1] && !p[3]) - { - const char *netmask = NULL; - - VERIFY_PERMISSION (OPT_P_INSTANCE); - if (p[2]) - { - netmask = p[2]; - } - option_iroute (options, p[1], netmask, msglevel); - } - else if (streq (p[0], "iroute-ipv6") && p[1] && !p[2]) - { - VERIFY_PERMISSION (OPT_P_INSTANCE); - option_iroute_ipv6 (options, p[1], msglevel); - } - else if (streq (p[0], "ifconfig-push") && p[1] && p[2] && !p[4]) - { - in_addr_t local, remote_netmask; - - VERIFY_PERMISSION (OPT_P_INSTANCE); - local = getaddr (GETADDR_HOST_ORDER|GETADDR_RESOLVE, p[1], 0, NULL, NULL); - remote_netmask = getaddr (GETADDR_HOST_ORDER|GETADDR_RESOLVE, p[2], 0, NULL, NULL); - if (local && remote_netmask) - { - options->push_ifconfig_defined = true; - options->push_ifconfig_local = local; - options->push_ifconfig_remote_netmask = remote_netmask; - if (p[3]) - options->push_ifconfig_local_alias = getaddr (GETADDR_HOST_ORDER|GETADDR_RESOLVE, p[3], 0, NULL, NULL); - } - else - { - msg (msglevel, "cannot parse --ifconfig-push addresses"); - goto err; - } - } - else if (streq (p[0], "ifconfig-push-constraint") && p[1] && p[2] && !p[3]) - { - in_addr_t network, netmask; - - VERIFY_PERMISSION (OPT_P_GENERAL); - network = getaddr (GETADDR_HOST_ORDER|GETADDR_RESOLVE, p[1], 0, NULL, NULL); - netmask = getaddr (GETADDR_HOST_ORDER, p[2], 0, NULL, NULL); - if (network && netmask) - { - options->push_ifconfig_constraint_defined = true; - options->push_ifconfig_constraint_network = network; - options->push_ifconfig_constraint_netmask = netmask; - } - else - { - msg (msglevel, "cannot parse --ifconfig-push-constraint addresses"); - goto err; - } - } - else if (streq (p[0], "ifconfig-ipv6-push") && p[1] && !p[3]) - { - struct in6_addr local, remote; - unsigned int netbits; - - VERIFY_PERMISSION (OPT_P_INSTANCE); - - if ( ! get_ipv6_addr( p[1], &local, &netbits, msglevel ) ) - { - msg (msglevel, "cannot parse --ifconfig-ipv6-push addresses"); - goto err; - } - - if ( p[2] ) - { - if ( !get_ipv6_addr( p[2], &remote, NULL, msglevel ) ) - { - msg( msglevel, "cannot parse --ifconfig-ipv6-push addresses"); - goto err; - } - } - else - { - if ( ! options->ifconfig_ipv6_local || - ! get_ipv6_addr( options->ifconfig_ipv6_local, &remote, - NULL, msglevel ) ) - { - msg( msglevel, "second argument to --ifconfig-ipv6-push missing and no global --ifconfig-ipv6 address set"); - goto err; - } - } - - options->push_ifconfig_ipv6_defined = true; - options->push_ifconfig_ipv6_local = local; - options->push_ifconfig_ipv6_netbits = netbits; - options->push_ifconfig_ipv6_remote = remote; - options->push_ifconfig_ipv6_blocked = false; - } - else if (streq (p[0], "disable") && !p[1]) - { - VERIFY_PERMISSION (OPT_P_INSTANCE); - options->disable = true; - } - else if (streq (p[0], "tcp-nodelay") && !p[1]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->server_flags |= SF_TCP_NODELAY_HELPER; - } - else if (streq (p[0], "stale-routes-check") && p[1] && !p[3]) - { - int ageing_time, check_interval; - - VERIFY_PERMISSION (OPT_P_GENERAL); - ageing_time = atoi (p[1]); - if (p[2]) - check_interval = atoi (p[2]); - else - check_interval = ageing_time; - - if (ageing_time < 1 || check_interval < 1) - { - msg (msglevel, "--stale-routes-check aging time and check interval must be >= 1"); - goto err; + int s; + VERIFY_PERMISSION(OPT_P_IPWIN32); + s = atoi(p[1]); + if (s < 0 || s >= 256) + { + msg(msglevel, "--tap-sleep parameter must be between 0 and 255"); + goto err; } - options->stale_routes_ageing_time = ageing_time; - options->stale_routes_check_interval = check_interval; + options->tuntap_options.tap_sleep = s; } -#endif /* P2MP_SERVER */ - - else if (streq (p[0], "client") && !p[1]) + else if (streq(p[0], "dhcp-renew") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->client = true; + VERIFY_PERMISSION(OPT_P_IPWIN32); + options->tuntap_options.dhcp_renew = true; } - else if (streq (p[0], "pull") && !p[1]) + else if (streq(p[0], "dhcp-pre-release") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->pull = true; + VERIFY_PERMISSION(OPT_P_IPWIN32); + options->tuntap_options.dhcp_pre_release = true; } - else if (streq (p[0], "push-continuation") && p[1] && !p[2]) + else if (streq(p[0], "dhcp-release") && !p[1]) { - VERIFY_PERMISSION (OPT_P_PULL_MODE); - options->push_continuation = atoi(p[1]); + VERIFY_PERMISSION(OPT_P_IPWIN32); + options->tuntap_options.dhcp_release = true; } - else if (streq (p[0], "auth-user-pass") && !p[2]) + else if (streq(p[0], "dhcp-internal") && p[1] && !p[2]) /* standalone method for internal use */ { - VERIFY_PERMISSION (OPT_P_GENERAL); - if (p[1]) - { - options->auth_user_pass_file = p[1]; - } - else - options->auth_user_pass_file = "stdin"; + unsigned int adapter_index; + VERIFY_PERMISSION(OPT_P_GENERAL); + set_debug_level(options->verbosity, SDL_CONSTRAIN); + adapter_index = atou(p[1]); + sleep(options->tuntap_options.tap_sleep); + if (options->tuntap_options.dhcp_pre_release) + { + dhcp_release_by_adapter_index(adapter_index); + } + if (options->tuntap_options.dhcp_renew) + { + dhcp_renew_by_adapter_index(adapter_index); + } + openvpn_exit(OPENVPN_EXIT_STATUS_GOOD); /* exit point */ } - else if (streq (p[0], "auth-retry") && p[1] && !p[2]) + else if (streq(p[0], "register-dns") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - auth_retry_set (msglevel, p[1]); + VERIFY_PERMISSION(OPT_P_IPWIN32); + options->tuntap_options.register_dns = true; } -#ifdef ENABLE_CLIENT_CR - else if (streq (p[0], "static-challenge") && p[1] && p[2] && !p[3]) + else if (streq(p[0], "block-outside-dns") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->sc_info.challenge_text = p[1]; - if (atoi(p[2])) - options->sc_info.flags |= SC_ECHO; + VERIFY_PERMISSION(OPT_P_IPWIN32); + options->block_outside_dns = true; } -#endif -#endif - else if (streq (p[0], "msg-channel") && p[1]) + else if (streq(p[0], "rdns-internal") && !p[1]) + /* standalone method for internal use + * + * (if --register-dns is set, openvpn needs to call itself in a + * sub-process to execute the required functions in a non-blocking + * way, and uses --rdns-internal to signal that to itself) + */ { -#ifdef _WIN32 - VERIFY_PERMISSION (OPT_P_GENERAL); - HANDLE process = GetCurrentProcess (); - HANDLE handle = (HANDLE) atoi (p[1]); - if (!DuplicateHandle (process, handle, process, &options->msg_channel, 0, - FALSE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) + VERIFY_PERMISSION(OPT_P_GENERAL); + set_debug_level(options->verbosity, SDL_CONSTRAIN); + if (options->tuntap_options.register_dns) { - msg (msglevel, "could not duplicate service pipe handle"); - goto err; + ipconfig_register_dns(NULL); } - options->route_method = ROUTE_METHOD_SERVICE; -#else - msg (msglevel, "--msg-channel is only supported on Windows"); - goto err; -#endif - } -#ifdef _WIN32 - else if (streq (p[0], "win-sys") && p[1] && !p[2]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - if (streq (p[1], "env")) - msg (M_INFO, "NOTE: --win-sys env is default from OpenVPN v2.3. " - "This entry will now be ignored. " - "Please remove this entry from your configuration file."); - else - set_win_sys_path (p[1], es); - } - else if (streq (p[0], "route-method") && p[1] && !p[2]) - { - VERIFY_PERMISSION (OPT_P_ROUTE_EXTRAS); - if (streq (p[1], "adaptive")) - options->route_method = ROUTE_METHOD_ADAPTIVE; - else if (streq (p[1], "ipapi")) - options->route_method = ROUTE_METHOD_IPAPI; - else if (streq (p[1], "exe")) - options->route_method = ROUTE_METHOD_EXE; - else - { - msg (msglevel, "--route method must be 'adaptive', 'ipapi', or 'exe'"); - goto err; - } - } - else if (streq (p[0], "ip-win32") && p[1] && !p[4]) - { - const int index = ascii2ipset (p[1]); - struct tuntap_options *to = &options->tuntap_options; - - VERIFY_PERMISSION (OPT_P_IPWIN32); - - if (index < 0) - { - msg (msglevel, - "Bad --ip-win32 method: '%s'. Allowed methods: %s", - p[1], - ipset2ascii_all (&gc)); - goto err; - } - - if (index == IPW32_SET_ADAPTIVE) - options->route_delay_window = IPW32_SET_ADAPTIVE_DELAY_WINDOW; - - if (index == IPW32_SET_DHCP_MASQ) - { - if (p[2]) - { - if (!streq (p[2], "default")) - { - int offset = atoi (p[2]); - - if (!(offset > -256 && offset < 256)) - { - msg (msglevel, "--ip-win32 dynamic [offset] [lease-time]: offset (%d) must be > -256 and < 256", offset); - goto err; - } - - to->dhcp_masq_custom_offset = true; - to->dhcp_masq_offset = offset; - } - - if (p[3]) - { - const int min_lease = 30; - int lease_time; - lease_time = atoi (p[3]); - if (lease_time < min_lease) - { - msg (msglevel, "--ip-win32 dynamic [offset] [lease-time]: lease time parameter (%d) must be at least %d seconds", lease_time, min_lease); - goto err; - } - to->dhcp_lease_time = lease_time; - } - } - } - to->ip_win32_type = index; - to->ip_win32_defined = true; - } -#endif -#if defined(_WIN32) || defined(TARGET_ANDROID) - else if (streq (p[0], "dhcp-option") && p[1] && !p[3]) - { - struct tuntap_options *o = &options->tuntap_options; - VERIFY_PERMISSION (OPT_P_IPWIN32); - - if (streq (p[1], "DOMAIN") && p[2]) - { - o->domain = p[2]; - } - else if (streq (p[1], "NBS") && p[2]) - { - o->netbios_scope = p[2]; - } - else if (streq (p[1], "NBT") && p[2]) - { - int t; - t = atoi (p[2]); - if (!(t == 1 || t == 2 || t == 4 || t == 8)) - { - msg (msglevel, "--dhcp-option NBT: parameter (%d) must be 1, 2, 4, or 8", t); - goto err; - } - o->netbios_node_type = t; - } - else if (streq (p[1], "DNS") && p[2]) - { - dhcp_option_address_parse ("DNS", p[2], o->dns, &o->dns_len, msglevel); - } - else if (streq (p[1], "DNS6") && p[2] && ipv6_addr_safe(p[2])) - { - struct in6_addr addr; - foreign_option (options, p, 3, es); - if (o->dns6_len >= N_DHCP_ADDR) - { - msg (msglevel, "--dhcp-option DNS6: maximum of %d dns servers can be specified", - N_DHCP_ADDR); - } - else if (get_ipv6_addr (p[2], &addr, NULL, msglevel)) - { - o->dns6[o->dns6_len++] = addr; - } - } - else if (streq (p[1], "WINS") && p[2]) - { - dhcp_option_address_parse ("WINS", p[2], o->wins, &o->wins_len, msglevel); - } - else if (streq (p[1], "NTP") && p[2]) - { - dhcp_option_address_parse ("NTP", p[2], o->ntp, &o->ntp_len, msglevel); - } - else if (streq (p[1], "NBDD") && p[2]) - { - dhcp_option_address_parse ("NBDD", p[2], o->nbdd, &o->nbdd_len, msglevel); - } - else if (streq (p[1], "DISABLE-NBT") && !p[2]) - { - o->disable_nbt = 1; - } - else - { - msg (msglevel, "--dhcp-option: unknown option type '%s' or missing or unknown parameter", p[1]); - goto err; - } - - /* flag that we have options to give to the TAP driver's DHCPv4 server - * - skipped for "DNS6", as that's not a DHCPv4 option - */ - if (!streq (p[1], "DNS6")) - { - o->dhcp_options = true; - } + openvpn_exit(OPENVPN_EXIT_STATUS_GOOD); /* exit point */ } -#endif -#ifdef _WIN32 - else if (streq (p[0], "show-adapters") && !p[1]) + else if (streq(p[0], "show-valid-subnets") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - show_tap_win_adapters (M_INFO|M_NOPREFIX, M_WARN|M_NOPREFIX); - openvpn_exit (OPENVPN_EXIT_STATUS_GOOD); /* exit point */ + VERIFY_PERMISSION(OPT_P_GENERAL); + show_valid_win32_tun_subnets(); + openvpn_exit(OPENVPN_EXIT_STATUS_GOOD); /* exit point */ } - else if (streq (p[0], "show-net") && !p[1]) + else if (streq(p[0], "pause-exit") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - show_routes (M_INFO|M_NOPREFIX); - show_adapters (M_INFO|M_NOPREFIX); - openvpn_exit (OPENVPN_EXIT_STATUS_GOOD); /* exit point */ + VERIFY_PERMISSION(OPT_P_GENERAL); + set_pause_exit_win32(); } - else if (streq (p[0], "show-net-up") && !p[1]) + else if (streq(p[0], "service") && p[1] && !p[3]) { - VERIFY_PERMISSION (OPT_P_UP); - options->show_net_up = true; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->exit_event_name = p[1]; + if (p[2]) + { + options->exit_event_initial_state = (atoi(p[2]) != 0); + } } - else if (streq (p[0], "tap-sleep") && p[1] && !p[2]) + else if (streq(p[0], "allow-nonadmin") && !p[2]) { - int s; - VERIFY_PERMISSION (OPT_P_IPWIN32); - s = atoi (p[1]); - if (s < 0 || s >= 256) - { - msg (msglevel, "--tap-sleep parameter must be between 0 and 255"); - goto err; - } - options->tuntap_options.tap_sleep = s; + VERIFY_PERMISSION(OPT_P_GENERAL); + tap_allow_nonadmin_access(p[1]); + openvpn_exit(OPENVPN_EXIT_STATUS_GOOD); /* exit point */ } - else if (streq (p[0], "dhcp-renew") && !p[1]) + else if (streq(p[0], "user") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_IPWIN32); - options->tuntap_options.dhcp_renew = true; + VERIFY_PERMISSION(OPT_P_GENERAL); + msg(M_WARN, "NOTE: --user option is not implemented on Windows"); } - else if (streq (p[0], "dhcp-pre-release") && !p[1]) + else if (streq(p[0], "group") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_IPWIN32); - options->tuntap_options.dhcp_pre_release = true; + VERIFY_PERMISSION(OPT_P_GENERAL); + msg(M_WARN, "NOTE: --group option is not implemented on Windows"); } - else if (streq (p[0], "dhcp-release") && !p[1]) +#else /* ifdef _WIN32 */ + else if (streq(p[0], "user") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_IPWIN32); - options->tuntap_options.dhcp_release = true; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->username = p[1]; } - else if (streq (p[0], "dhcp-internal") && p[1] && !p[2]) /* standalone method for internal use */ + else if (streq(p[0], "group") && p[1] && !p[2]) { - unsigned int adapter_index; - VERIFY_PERMISSION (OPT_P_GENERAL); - set_debug_level (options->verbosity, SDL_CONSTRAIN); - adapter_index = atou (p[1]); - sleep (options->tuntap_options.tap_sleep); - if (options->tuntap_options.dhcp_pre_release) - dhcp_release_by_adapter_index (adapter_index); - if (options->tuntap_options.dhcp_renew) - dhcp_renew_by_adapter_index (adapter_index); - openvpn_exit (OPENVPN_EXIT_STATUS_GOOD); /* exit point */ + VERIFY_PERMISSION(OPT_P_GENERAL); + options->groupname = p[1]; } - else if (streq (p[0], "register-dns") && !p[1]) + else if (streq(p[0], "dhcp-option") && p[1] && !p[3]) { - VERIFY_PERMISSION (OPT_P_IPWIN32); - options->tuntap_options.register_dns = true; + VERIFY_PERMISSION(OPT_P_IPWIN32); + foreign_option(options, p, 3, es); } - else if (streq (p[0], "block-outside-dns") && !p[1]) + else if (streq(p[0], "route-method") && p[1] && !p[2]) /* ignore when pushed to non-Windows OS */ { - VERIFY_PERMISSION (OPT_P_IPWIN32); - options->block_outside_dns = true; + VERIFY_PERMISSION(OPT_P_ROUTE_EXTRAS); } - else if (streq (p[0], "rdns-internal") && !p[1]) - /* standalone method for internal use - * - * (if --register-dns is set, openvpn needs to call itself in a - * sub-process to execute the required functions in a non-blocking - * way, and uses --rdns-internal to signal that to itself) - */ +#endif /* ifdef _WIN32 */ +#if PASSTOS_CAPABILITY + else if (streq(p[0], "passtos") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - set_debug_level (options->verbosity, SDL_CONSTRAIN); - if (options->tuntap_options.register_dns) - ipconfig_register_dns (NULL); - openvpn_exit (OPENVPN_EXIT_STATUS_GOOD); /* exit point */ + VERIFY_PERMISSION(OPT_P_GENERAL); + options->passtos = true; } - else if (streq (p[0], "show-valid-subnets") && !p[1]) +#endif +#if defined(USE_COMP) + else if (streq(p[0], "comp-lzo") && !p[2]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - show_valid_win32_tun_subnets (); - openvpn_exit (OPENVPN_EXIT_STATUS_GOOD); /* exit point */ + VERIFY_PERMISSION(OPT_P_COMP); + +#if defined(ENABLE_LZO) + if (p[1] && streq(p[1], "no")) +#endif + { + options->comp.alg = COMP_ALG_STUB; + options->comp.flags = 0; + } +#if defined(ENABLE_LZO) + else if (p[1]) + { + if (streq(p[1], "yes")) + { + options->comp.alg = COMP_ALG_LZO; + options->comp.flags = 0; + } + else if (streq(p[1], "adaptive")) + { + options->comp.alg = COMP_ALG_LZO; + options->comp.flags = COMP_F_ADAPTIVE; + } + else + { + msg(msglevel, "bad comp-lzo option: %s -- must be 'yes', 'no', or 'adaptive'", p[1]); + goto err; + } + } + else + { + options->comp.alg = COMP_ALG_LZO; + options->comp.flags = COMP_F_ADAPTIVE; + } +#endif /* if defined(ENABLE_LZO) */ } - else if (streq (p[0], "pause-exit") && !p[1]) + else if (streq(p[0], "comp-noadapt") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - set_pause_exit_win32 (); + VERIFY_PERMISSION(OPT_P_COMP); + options->comp.flags &= ~COMP_F_ADAPTIVE; } - else if (streq (p[0], "service") && p[1] && !p[3]) + else if (streq(p[0], "compress") && !p[2]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->exit_event_name = p[1]; - if (p[2]) - { - options->exit_event_initial_state = (atoi(p[2]) != 0); - } + VERIFY_PERMISSION(OPT_P_COMP); + if (p[1]) + { + if (streq(p[1], "stub")) + { + options->comp.alg = COMP_ALG_STUB; + options->comp.flags = (COMP_F_SWAP|COMP_F_ADVERTISE_STUBS_ONLY); + } + else if (streq(p[1], "stub-v2")) + { + options->comp.alg = COMP_ALGV2_UNCOMPRESSED; + options->comp.flags = COMP_F_ADVERTISE_STUBS_ONLY; + } +#if defined(ENABLE_LZO) + else if (streq(p[1], "lzo")) + { + options->comp.alg = COMP_ALG_LZO; + options->comp.flags = 0; + } +#endif +#if defined(ENABLE_LZ4) + else if (streq(p[1], "lz4")) + { + options->comp.alg = COMP_ALG_LZ4; + options->comp.flags = COMP_F_SWAP; + } + else if (streq(p[1], "lz4-v2")) + { + options->comp.alg = COMP_ALGV2_LZ4; + options->comp.flags = 0; + } +#endif + else + { + msg(msglevel, "bad comp option: %s", p[1]); + goto err; + } + } + else + { + options->comp.alg = COMP_ALG_STUB; + options->comp.flags = COMP_F_SWAP; + } } - else if (streq (p[0], "allow-nonadmin") && !p[2]) +#endif /* USE_COMP */ +#ifdef ENABLE_CRYPTO + else if (streq(p[0], "show-ciphers") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - tap_allow_nonadmin_access (p[1]); - openvpn_exit (OPENVPN_EXIT_STATUS_GOOD); /* exit point */ + VERIFY_PERMISSION(OPT_P_GENERAL); + options->show_ciphers = true; } - else if (streq (p[0], "user") && p[1] && !p[2]) + else if (streq(p[0], "show-digests") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - msg (M_WARN, "NOTE: --user option is not implemented on Windows"); + VERIFY_PERMISSION(OPT_P_GENERAL); + options->show_digests = true; } - else if (streq (p[0], "group") && p[1] && !p[2]) + else if (streq(p[0], "show-engines") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - msg (M_WARN, "NOTE: --group option is not implemented on Windows"); + VERIFY_PERMISSION(OPT_P_GENERAL); + options->show_engines = true; } -#else - else if (streq (p[0], "user") && p[1] && !p[2]) + else if (streq(p[0], "key-direction") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->username = p[1]; + int key_direction; + + key_direction = ascii2keydirection(msglevel, p[1]); + if (key_direction >= 0) + { + options->key_direction = key_direction; + } + else + { + goto err; + } } - else if (streq (p[0], "group") && p[1] && !p[2]) + else if (streq(p[0], "secret") && p[1] && !p[3]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->groupname = p[1]; + VERIFY_PERMISSION(OPT_P_GENERAL); + if (streq(p[1], INLINE_FILE_TAG) && p[2]) + { + options->shared_secret_file_inline = p[2]; + } + else if (p[2]) + { + int key_direction; + + key_direction = ascii2keydirection(msglevel, p[2]); + if (key_direction >= 0) + { + options->key_direction = key_direction; + } + else + { + goto err; + } + } + options->shared_secret_file = p[1]; } - else if (streq (p[0], "dhcp-option") && p[1] && !p[3]) + else if (streq(p[0], "genkey") && !p[1]) { - VERIFY_PERMISSION (OPT_P_IPWIN32); - foreign_option (options, p, 3, es); + VERIFY_PERMISSION(OPT_P_GENERAL); + options->genkey = true; } - else if (streq (p[0], "route-method") && p[1] && !p[2]) /* ignore when pushed to non-Windows OS */ + else if (streq(p[0], "auth") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_ROUTE_EXTRAS); + VERIFY_PERMISSION(OPT_P_GENERAL); + options->authname = p[1]; } -#endif -#if PASSTOS_CAPABILITY - else if (streq (p[0], "passtos") && !p[1]) + else if (streq(p[0], "cipher") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->passtos = true; + VERIFY_PERMISSION(OPT_P_NCP); + options->ciphername = p[1]; } -#endif -#if defined(USE_COMP) - else if (streq (p[0], "comp-lzo") && !p[2]) + else if (streq(p[0], "ncp-ciphers") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_COMP); - -#if defined(ENABLE_LZO) - if (p[1] && streq (p[1], "no")) -#endif - { - options->comp.alg = COMP_ALG_STUB; - options->comp.flags = 0; - } -#if defined(ENABLE_LZO) - else if (p[1]) - { - if (streq (p[1], "yes")) - { - options->comp.alg = COMP_ALG_LZO; - options->comp.flags = 0; - } - else if (streq (p[1], "adaptive")) - { - options->comp.alg = COMP_ALG_LZO; - options->comp.flags = COMP_F_ADAPTIVE; - } - else - { - msg (msglevel, "bad comp-lzo option: %s -- must be 'yes', 'no', or 'adaptive'", p[1]); - goto err; - } - } - else - { - options->comp.alg = COMP_ALG_LZO; - options->comp.flags = COMP_F_ADAPTIVE; - } -#endif - } - else if (streq (p[0], "comp-noadapt") && !p[1]) - { - VERIFY_PERMISSION (OPT_P_COMP); - options->comp.flags &= ~COMP_F_ADAPTIVE; - } - else if (streq (p[0], "compress") && !p[2]) - { - VERIFY_PERMISSION (OPT_P_COMP); - if (p[1]) - { - if (streq (p[1], "stub")) - { - options->comp.alg = COMP_ALG_STUB; - options->comp.flags = (COMP_F_SWAP|COMP_F_ADVERTISE_STUBS_ONLY); - } - else if (streq(p[1], "stub-v2")) - { - options->comp.alg = COMP_ALGV2_UNCOMPRESSED; - options->comp.flags = COMP_F_ADVERTISE_STUBS_ONLY; - } -#if defined(ENABLE_LZO) - else if (streq (p[1], "lzo")) - { - options->comp.alg = COMP_ALG_LZO; - options->comp.flags = 0; - } -#endif -#if defined(ENABLE_LZ4) - else if (streq (p[1], "lz4")) - { - options->comp.alg = COMP_ALG_LZ4; - options->comp.flags = COMP_F_SWAP; - } - else if (streq (p[1], "lz4-v2")) - { - options->comp.alg = COMP_ALGV2_LZ4; - options->comp.flags = 0; - } -#endif - else - { - msg (msglevel, "bad comp option: %s", p[1]); - goto err; - } - } - else - { - options->comp.alg = COMP_ALG_STUB; - options->comp.flags = COMP_F_SWAP; - } + VERIFY_PERMISSION(OPT_P_GENERAL|OPT_P_INSTANCE); + options->ncp_ciphers = p[1]; } -#endif /* USE_COMP */ -#ifdef ENABLE_CRYPTO - else if (streq (p[0], "show-ciphers") && !p[1]) + else if (streq(p[0], "ncp-disable") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->show_ciphers = true; + VERIFY_PERMISSION(OPT_P_GENERAL|OPT_P_INSTANCE); + options->ncp_enabled = false; } - else if (streq (p[0], "show-digests") && !p[1]) + else if (streq(p[0], "prng") && p[1] && !p[3]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->show_digests = true; + VERIFY_PERMISSION(OPT_P_GENERAL); + if (streq(p[1], "none")) + { + options->prng_hash = NULL; + } + else + { + options->prng_hash = p[1]; + } + if (p[2]) + { + const int sl = atoi(p[2]); + if (sl >= NONCE_SECRET_LEN_MIN && sl <= NONCE_SECRET_LEN_MAX) + { + options->prng_nonce_secret_len = sl; + } + else + { + msg(msglevel, "prng parameter nonce_secret_len must be between %d and %d", + NONCE_SECRET_LEN_MIN, NONCE_SECRET_LEN_MAX); + goto err; + } + } } - else if (streq (p[0], "show-engines") && !p[1]) + else if (streq(p[0], "no-replay") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->show_engines = true; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->replay = false; } - else if (streq (p[0], "key-direction") && p[1] && !p[2]) + else if (streq(p[0], "replay-window") && !p[3]) { - int key_direction; + VERIFY_PERMISSION(OPT_P_GENERAL); + if (p[1]) + { + int replay_window; - key_direction = ascii2keydirection (msglevel, p[1]); - if (key_direction >= 0) - options->key_direction = key_direction; - else - goto err; - } - else if (streq (p[0], "secret") && p[1] && !p[3]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - if (streq (p[1], INLINE_FILE_TAG) && p[2]) - { - options->shared_secret_file_inline = p[2]; - } - else - if (p[2]) - { - int key_direction; - - key_direction = ascii2keydirection (msglevel, p[2]); - if (key_direction >= 0) - options->key_direction = key_direction; - else - goto err; - } - options->shared_secret_file = p[1]; - } - else if (streq (p[0], "genkey") && !p[1]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->genkey = true; - } - else if (streq (p[0], "auth") && p[1] && !p[2]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->authname = p[1]; - } - else if (streq (p[0], "cipher") && p[1] && !p[2]) - { - VERIFY_PERMISSION (OPT_P_NCP); - options->ciphername = p[1]; + replay_window = atoi(p[1]); + if (!(MIN_SEQ_BACKTRACK <= replay_window && replay_window <= MAX_SEQ_BACKTRACK)) + { + msg(msglevel, "replay-window window size parameter (%d) must be between %d and %d", + replay_window, + MIN_SEQ_BACKTRACK, + MAX_SEQ_BACKTRACK); + goto err; + } + options->replay_window = replay_window; + + if (p[2]) + { + int replay_time; + + replay_time = atoi(p[2]); + if (!(MIN_TIME_BACKTRACK <= replay_time && replay_time <= MAX_TIME_BACKTRACK)) + { + msg(msglevel, "replay-window time window parameter (%d) must be between %d and %d", + replay_time, + MIN_TIME_BACKTRACK, + MAX_TIME_BACKTRACK); + goto err; + } + options->replay_time = replay_time; + } + } + else + { + msg(msglevel, "replay-window option is missing window size parameter"); + goto err; + } } - else if (streq (p[0], "ncp-ciphers") && p[1] && !p[2]) + else if (streq(p[0], "mute-replay-warnings") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_INSTANCE); - options->ncp_ciphers = p[1]; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->mute_replay_warnings = true; } - else if (streq (p[0], "ncp-disable") && !p[1]) + else if (streq(p[0], "no-iv") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_INSTANCE); - options->ncp_enabled = false; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->use_iv = false; } - else if (streq (p[0], "prng") && p[1] && !p[3]) + else if (streq(p[0], "replay-persist") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - if (streq (p[1], "none")) - options->prng_hash = NULL; - else - options->prng_hash = p[1]; - if (p[2]) - { - const int sl = atoi (p[2]); - if (sl >= NONCE_SECRET_LEN_MIN && sl <= NONCE_SECRET_LEN_MAX) - { - options->prng_nonce_secret_len = sl; - } - else - { - msg (msglevel, "prng parameter nonce_secret_len must be between %d and %d", - NONCE_SECRET_LEN_MIN, NONCE_SECRET_LEN_MAX); - goto err; - } - } + VERIFY_PERMISSION(OPT_P_GENERAL); + options->packet_id_file = p[1]; } - else if (streq (p[0], "no-replay") && !p[1]) + else if (streq(p[0], "test-crypto") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->replay = false; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->test_crypto = true; } - else if (streq (p[0], "replay-window") && !p[3]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - if (p[1]) - { - int replay_window; - - replay_window = atoi (p[1]); - if (!(MIN_SEQ_BACKTRACK <= replay_window && replay_window <= MAX_SEQ_BACKTRACK)) - { - msg (msglevel, "replay-window window size parameter (%d) must be between %d and %d", - replay_window, - MIN_SEQ_BACKTRACK, - MAX_SEQ_BACKTRACK); - goto err; - } - options->replay_window = replay_window; - - if (p[2]) - { - int replay_time; - - replay_time = atoi (p[2]); - if (!(MIN_TIME_BACKTRACK <= replay_time && replay_time <= MAX_TIME_BACKTRACK)) - { - msg (msglevel, "replay-window time window parameter (%d) must be between %d and %d", - replay_time, - MIN_TIME_BACKTRACK, - MAX_TIME_BACKTRACK); - goto err; - } - options->replay_time = replay_time; - } - } - else - { - msg (msglevel, "replay-window option is missing window size parameter"); - goto err; - } - } - else if (streq (p[0], "mute-replay-warnings") && !p[1]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->mute_replay_warnings = true; - } - else if (streq (p[0], "no-iv") && !p[1]) +#ifndef ENABLE_CRYPTO_MBEDTLS + else if (streq(p[0], "engine") && !p[2]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->use_iv = false; - } - else if (streq (p[0], "replay-persist") && p[1] && !p[2]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->packet_id_file = p[1]; - } - else if (streq (p[0], "test-crypto") && !p[1]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->test_crypto = true; + VERIFY_PERMISSION(OPT_P_GENERAL); + if (p[1]) + { + options->engine = p[1]; + } + else + { + options->engine = "auto"; + } } -#ifndef ENABLE_CRYPTO_MBEDTLS - else if (streq (p[0], "engine") && !p[2]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - if (p[1]) - { - options->engine = p[1]; - } - else - options->engine = "auto"; - } #endif /* ENABLE_CRYPTO_MBEDTLS */ #ifdef HAVE_EVP_CIPHER_CTX_SET_KEY_LENGTH - else if (streq (p[0], "keysize") && p[1] && !p[2]) + else if (streq(p[0], "keysize") && p[1] && !p[2]) { - int keysize; + int keysize; - VERIFY_PERMISSION (OPT_P_NCP); - keysize = atoi (p[1]) / 8; - if (keysize < 0 || keysize > MAX_CIPHER_KEY_LENGTH) - { - msg (msglevel, "Bad keysize: %s", p[1]); - goto err; - } - options->keysize = keysize; + VERIFY_PERMISSION(OPT_P_NCP); + keysize = atoi(p[1]) / 8; + if (keysize < 0 || keysize > MAX_CIPHER_KEY_LENGTH) + { + msg(msglevel, "Bad keysize: %s", p[1]); + goto err; + } + options->keysize = keysize; } #endif #ifdef ENABLE_PREDICTION_RESISTANCE - else if (streq (p[0], "use-prediction-resistance") && !p[1]) + else if (streq(p[0], "use-prediction-resistance") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->use_prediction_resistance = true; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->use_prediction_resistance = true; } #endif - else if (streq (p[0], "show-tls") && !p[1]) + else if (streq(p[0], "show-tls") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->show_tls_ciphers = true; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->show_tls_ciphers = true; } - else if (streq (p[0], "show-curves") && !p[1]) + else if (streq(p[0], "show-curves") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->show_curves = true; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->show_curves = true; } - else if (streq (p[0], "ecdh-curve") && p[1] && !p[2]) + else if (streq(p[0], "ecdh-curve") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->ecdh_curve= p[1]; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->ecdh_curve = p[1]; } - else if (streq (p[0], "tls-server") && !p[1]) + else if (streq(p[0], "tls-server") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->tls_server = true; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->tls_server = true; } - else if (streq (p[0], "tls-client") && !p[1]) + else if (streq(p[0], "tls-client") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->tls_client = true; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->tls_client = true; } - else if (streq (p[0], "ca") && p[1] && ((streq (p[1], INLINE_FILE_TAG) && p[2]) || !p[2]) && !p[3]) + else if (streq(p[0], "ca") && p[1] && ((streq(p[1], INLINE_FILE_TAG) && p[2]) || !p[2]) && !p[3]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->ca_file = p[1]; - if (streq (p[1], INLINE_FILE_TAG) && p[2]) - { - options->ca_file_inline = p[2]; - } + VERIFY_PERMISSION(OPT_P_GENERAL); + options->ca_file = p[1]; + if (streq(p[1], INLINE_FILE_TAG) && p[2]) + { + options->ca_file_inline = p[2]; + } } #ifndef ENABLE_CRYPTO_MBEDTLS - else if (streq (p[0], "capath") && p[1] && !p[2]) + else if (streq(p[0], "capath") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->ca_path = p[1]; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->ca_path = p[1]; } #endif /* ENABLE_CRYPTO_MBEDTLS */ - else if (streq (p[0], "dh") && p[1] && ((streq (p[1], INLINE_FILE_TAG) && p[2]) || !p[2]) && !p[3]) + else if (streq(p[0], "dh") && p[1] && ((streq(p[1], INLINE_FILE_TAG) && p[2]) || !p[2]) && !p[3]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->dh_file = p[1]; - if (streq (p[1], INLINE_FILE_TAG) && p[2]) - { - options->dh_file_inline = p[2]; - } + VERIFY_PERMISSION(OPT_P_GENERAL); + options->dh_file = p[1]; + if (streq(p[1], INLINE_FILE_TAG) && p[2]) + { + options->dh_file_inline = p[2]; + } } - else if (streq (p[0], "cert") && p[1] && ((streq (p[1], INLINE_FILE_TAG) && p[2]) || !p[2]) && !p[3]) + else if (streq(p[0], "cert") && p[1] && ((streq(p[1], INLINE_FILE_TAG) && p[2]) || !p[2]) && !p[3]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->cert_file = p[1]; - if (streq (p[1], INLINE_FILE_TAG) && p[2]) - { - options->cert_file_inline = p[2]; - } + VERIFY_PERMISSION(OPT_P_GENERAL); + options->cert_file = p[1]; + if (streq(p[1], INLINE_FILE_TAG) && p[2]) + { + options->cert_file_inline = p[2]; + } } - else if (streq (p[0], "extra-certs") && p[1] && ((streq (p[1], INLINE_FILE_TAG) && p[2]) || !p[2]) && !p[3]) + else if (streq(p[0], "extra-certs") && p[1] && ((streq(p[1], INLINE_FILE_TAG) && p[2]) || !p[2]) && !p[3]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->extra_certs_file = p[1]; - if (streq (p[1], INLINE_FILE_TAG) && p[2]) - { - options->extra_certs_file_inline = p[2]; - } + VERIFY_PERMISSION(OPT_P_GENERAL); + options->extra_certs_file = p[1]; + if (streq(p[1], INLINE_FILE_TAG) && p[2]) + { + options->extra_certs_file_inline = p[2]; + } } - else if (streq (p[0], "verify-hash") && p[1] && !p[2]) + else if (streq(p[0], "verify-hash") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->verify_hash = parse_hash_fingerprint(p[1], SHA_DIGEST_LENGTH, msglevel, &options->gc); + VERIFY_PERMISSION(OPT_P_GENERAL); + options->verify_hash = parse_hash_fingerprint(p[1], SHA_DIGEST_LENGTH, msglevel, &options->gc); } #ifdef ENABLE_CRYPTOAPI - else if (streq (p[0], "cryptoapicert") && p[1] && !p[2]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->cryptoapi_cert = p[1]; - } -#endif - else if (streq (p[0], "key") && p[1] && ((streq (p[1], INLINE_FILE_TAG) && p[2]) || !p[2]) && !p[3]) - { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->priv_key_file = p[1]; - if (streq (p[1], INLINE_FILE_TAG) && p[2]) - { - options->priv_key_file_inline = p[2]; - } - } - else if (streq (p[0], "tls-version-min") && p[1] && !p[3]) - { - int ver; - VERIFY_PERMISSION (OPT_P_GENERAL); - ver = tls_version_parse(p[1], p[2]); - if (ver == TLS_VER_BAD) - { - msg (msglevel, "unknown tls-version-min parameter: %s", p[1]); - goto err; - } - options->ssl_flags &= - ~(SSLF_TLS_VERSION_MIN_MASK << SSLF_TLS_VERSION_MIN_SHIFT); - options->ssl_flags |= (ver << SSLF_TLS_VERSION_MIN_SHIFT); - } - else if (streq (p[0], "tls-version-max") && p[1] && !p[2]) - { - int ver; - VERIFY_PERMISSION (OPT_P_GENERAL); - ver = tls_version_parse(p[1], NULL); - if (ver == TLS_VER_BAD) - { - msg (msglevel, "unknown tls-version-max parameter: %s", p[1]); - goto err; - } - options->ssl_flags &= - ~(SSLF_TLS_VERSION_MAX_MASK << SSLF_TLS_VERSION_MAX_SHIFT); - options->ssl_flags |= (ver << SSLF_TLS_VERSION_MAX_SHIFT); + else if (streq(p[0], "cryptoapicert") && p[1] && !p[2]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + options->cryptoapi_cert = p[1]; + } +#endif + else if (streq(p[0], "key") && p[1] && ((streq(p[1], INLINE_FILE_TAG) && p[2]) || !p[2]) && !p[3]) + { + VERIFY_PERMISSION(OPT_P_GENERAL); + options->priv_key_file = p[1]; + if (streq(p[1], INLINE_FILE_TAG) && p[2]) + { + options->priv_key_file_inline = p[2]; + } + } + else if (streq(p[0], "tls-version-min") && p[1] && !p[3]) + { + int ver; + VERIFY_PERMISSION(OPT_P_GENERAL); + ver = tls_version_parse(p[1], p[2]); + if (ver == TLS_VER_BAD) + { + msg(msglevel, "unknown tls-version-min parameter: %s", p[1]); + goto err; + } + options->ssl_flags &= + ~(SSLF_TLS_VERSION_MIN_MASK << SSLF_TLS_VERSION_MIN_SHIFT); + options->ssl_flags |= (ver << SSLF_TLS_VERSION_MIN_SHIFT); + } + else if (streq(p[0], "tls-version-max") && p[1] && !p[2]) + { + int ver; + VERIFY_PERMISSION(OPT_P_GENERAL); + ver = tls_version_parse(p[1], NULL); + if (ver == TLS_VER_BAD) + { + msg(msglevel, "unknown tls-version-max parameter: %s", p[1]); + goto err; + } + options->ssl_flags &= + ~(SSLF_TLS_VERSION_MAX_MASK << SSLF_TLS_VERSION_MAX_SHIFT); + options->ssl_flags |= (ver << SSLF_TLS_VERSION_MAX_SHIFT); } #ifndef ENABLE_CRYPTO_MBEDTLS - else if (streq (p[0], "pkcs12") && p[1] && ((streq (p[1], INLINE_FILE_TAG) && p[2]) || !p[2]) && !p[3]) + else if (streq(p[0], "pkcs12") && p[1] && ((streq(p[1], INLINE_FILE_TAG) && p[2]) || !p[2]) && !p[3]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->pkcs12_file = p[1]; - if (streq (p[1], INLINE_FILE_TAG) && p[2]) - { - options->pkcs12_file_inline = p[2]; - } + VERIFY_PERMISSION(OPT_P_GENERAL); + options->pkcs12_file = p[1]; + if (streq(p[1], INLINE_FILE_TAG) && p[2]) + { + options->pkcs12_file_inline = p[2]; + } } #endif /* ENABLE_CRYPTO_MBEDTLS */ - else if (streq (p[0], "askpass") && !p[2]) + else if (streq(p[0], "askpass") && !p[2]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - if (p[1]) - { - options->key_pass_file = p[1]; - } - else - options->key_pass_file = "stdin"; + VERIFY_PERMISSION(OPT_P_GENERAL); + if (p[1]) + { + options->key_pass_file = p[1]; + } + else + { + options->key_pass_file = "stdin"; + } } - else if (streq (p[0], "auth-nocache") && !p[1]) + else if (streq(p[0], "auth-nocache") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - ssl_set_auth_nocache (); + VERIFY_PERMISSION(OPT_P_GENERAL); + ssl_set_auth_nocache(); } - else if (streq (p[0], "auth-token") && p[1] && !p[2]) + else if (streq(p[0], "auth-token") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_ECHO); - ssl_set_auth_token(p[1]); + VERIFY_PERMISSION(OPT_P_ECHO); + ssl_set_auth_token(p[1]); #ifdef ENABLE_MANAGEMENT - if (management) - management_auth_token (management, p[1]); + if (management) + { + management_auth_token(management, p[1]); + } #endif } - else if (streq (p[0], "single-session") && !p[1]) + else if (streq(p[0], "single-session") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->single_session = true; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->single_session = true; } #ifdef ENABLE_PUSH_PEER_INFO - else if (streq (p[0], "push-peer-info") && !p[1]) + else if (streq(p[0], "push-peer-info") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->push_peer_info = true; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->push_peer_info = true; } #endif - else if (streq (p[0], "tls-exit") && !p[1]) + else if (streq(p[0], "tls-exit") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->tls_exit = true; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->tls_exit = true; } - else if (streq (p[0], "tls-cipher") && p[1] && !p[2]) + else if (streq(p[0], "tls-cipher") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->cipher_list = p[1]; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->cipher_list = p[1]; } - else if (streq (p[0], "crl-verify") && p[1] && ((p[2] && streq(p[2], "dir")) - || (p[2] && streq (p[1], INLINE_FILE_TAG) ) || !p[2]) && !p[3]) + else if (streq(p[0], "crl-verify") && p[1] && ((p[2] && streq(p[2], "dir")) + || (p[2] && streq(p[1], INLINE_FILE_TAG) ) || !p[2]) && !p[3]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - if (p[2] && streq(p[2], "dir")) - options->ssl_flags |= SSLF_CRL_VERIFY_DIR; - options->crl_file = p[1]; - if (streq (p[1], INLINE_FILE_TAG) && p[2]) - { - options->crl_file_inline = p[2]; - } + VERIFY_PERMISSION(OPT_P_GENERAL); + if (p[2] && streq(p[2], "dir")) + { + options->ssl_flags |= SSLF_CRL_VERIFY_DIR; + } + options->crl_file = p[1]; + if (streq(p[1], INLINE_FILE_TAG) && p[2]) + { + options->crl_file_inline = p[2]; + } } - else if (streq (p[0], "tls-verify") && p[1]) + else if (streq(p[0], "tls-verify") && p[1]) { - VERIFY_PERMISSION (OPT_P_SCRIPT); - if (!no_more_than_n_args (msglevel, p, 2, NM_QUOTE_HINT)) - goto err; - set_user_script (options, &options->tls_verify, - string_substitute (p[1], ',', ' ', &options->gc), - "tls-verify", true); + VERIFY_PERMISSION(OPT_P_SCRIPT); + if (!no_more_than_n_args(msglevel, p, 2, NM_QUOTE_HINT)) + { + goto err; + } + set_user_script(options, &options->tls_verify, + string_substitute(p[1], ',', ' ', &options->gc), + "tls-verify", true); } #ifndef ENABLE_CRYPTO_MBEDTLS - else if (streq (p[0], "tls-export-cert") && p[1] && !p[2]) + else if (streq(p[0], "tls-export-cert") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->tls_export_cert = p[1]; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->tls_export_cert = p[1]; } #endif #if P2MP_SERVER - else if (streq (p[0], "compat-names") && ((p[1] && streq (p[1], "no-remapping")) || !p[1]) && !p[2]) + else if (streq(p[0], "compat-names") && ((p[1] && streq(p[1], "no-remapping")) || !p[1]) && !p[2]) #else - else if (streq (p[0], "compat-names") && !p[1]) + else if (streq(p[0], "compat-names") && !p[1]) #endif { - VERIFY_PERMISSION (OPT_P_GENERAL); - if (options->verify_x509_type != VERIFY_X509_NONE) + VERIFY_PERMISSION(OPT_P_GENERAL); + if (options->verify_x509_type != VERIFY_X509_NONE) { - msg (msglevel, "you cannot use --compat-names with --verify-x509-name"); - goto err; + msg(msglevel, "you cannot use --compat-names with --verify-x509-name"); + goto err; } - msg (M_WARN, "DEPRECATED OPTION: --compat-names, please update your configuration. This will be removed in OpenVPN v2.5."); - compat_flag (COMPAT_FLAG_SET | COMPAT_NAMES); + msg(M_WARN, "DEPRECATED OPTION: --compat-names, please update your configuration. This will be removed in OpenVPN v2.5."); + compat_flag(COMPAT_FLAG_SET | COMPAT_NAMES); #if P2MP_SERVER - if (p[1] && streq (p[1], "no-remapping")) - compat_flag (COMPAT_FLAG_SET | COMPAT_NO_NAME_REMAPPING); + if (p[1] && streq(p[1], "no-remapping")) + { + compat_flag(COMPAT_FLAG_SET | COMPAT_NO_NAME_REMAPPING); + } } - else if (streq (p[0], "no-name-remapping") && !p[1]) + else if (streq(p[0], "no-name-remapping") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - if (options->verify_x509_type != VERIFY_X509_NONE) + VERIFY_PERMISSION(OPT_P_GENERAL); + if (options->verify_x509_type != VERIFY_X509_NONE) { - msg (msglevel, "you cannot use --no-name-remapping with --verify-x509-name"); - goto err; + msg(msglevel, "you cannot use --no-name-remapping with --verify-x509-name"); + goto err; } - msg (M_WARN, "DEPRECATED OPTION: --no-name-remapping, please update your configuration. This will be removed in OpenVPN v2.5."); - compat_flag (COMPAT_FLAG_SET | COMPAT_NAMES); - compat_flag (COMPAT_FLAG_SET | COMPAT_NO_NAME_REMAPPING); + msg(M_WARN, "DEPRECATED OPTION: --no-name-remapping, please update your configuration. This will be removed in OpenVPN v2.5."); + compat_flag(COMPAT_FLAG_SET | COMPAT_NAMES); + compat_flag(COMPAT_FLAG_SET | COMPAT_NO_NAME_REMAPPING); #endif } - else if (streq (p[0], "verify-x509-name") && p[1] && strlen (p[1]) && !p[3]) + else if (streq(p[0], "verify-x509-name") && p[1] && strlen(p[1]) && !p[3]) { - int type = VERIFY_X509_SUBJECT_DN; - VERIFY_PERMISSION (OPT_P_GENERAL); - if (compat_flag (COMPAT_FLAG_QUERY | COMPAT_NAMES)) + int type = VERIFY_X509_SUBJECT_DN; + VERIFY_PERMISSION(OPT_P_GENERAL); + if (compat_flag(COMPAT_FLAG_QUERY | COMPAT_NAMES)) { - msg (msglevel, "you cannot use --verify-x509-name with " - "--compat-names or --no-name-remapping"); - goto err; + msg(msglevel, "you cannot use --verify-x509-name with " + "--compat-names or --no-name-remapping"); + goto err; } - if (p[2]) + if (p[2]) { - if (streq (p[2], "subject")) - type = VERIFY_X509_SUBJECT_DN; - else if (streq (p[2], "name")) - type = VERIFY_X509_SUBJECT_RDN; - else if (streq (p[2], "name-prefix")) - type = VERIFY_X509_SUBJECT_RDN_PREFIX; - else + if (streq(p[2], "subject")) { - msg (msglevel, "unknown X.509 name type: %s", p[2]); - goto err; + type = VERIFY_X509_SUBJECT_DN; + } + else if (streq(p[2], "name")) + { + type = VERIFY_X509_SUBJECT_RDN; + } + else if (streq(p[2], "name-prefix")) + { + type = VERIFY_X509_SUBJECT_RDN_PREFIX; + } + else + { + msg(msglevel, "unknown X.509 name type: %s", p[2]); + goto err; } } - options->verify_x509_type = type; - options->verify_x509_name = p[1]; + options->verify_x509_type = type; + options->verify_x509_name = p[1]; } - else if (streq (p[0], "ns-cert-type") && p[1] && !p[2]) + else if (streq(p[0], "ns-cert-type") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - if (streq (p[1], "server")) - options->ns_cert_type = NS_CERT_CHECK_SERVER; - else if (streq (p[1], "client")) - options->ns_cert_type = NS_CERT_CHECK_CLIENT; - else - { - msg (msglevel, "--ns-cert-type must be 'client' or 'server'"); - goto err; - } + VERIFY_PERMISSION(OPT_P_GENERAL); + if (streq(p[1], "server")) + { + options->ns_cert_type = NS_CERT_CHECK_SERVER; + } + else if (streq(p[1], "client")) + { + options->ns_cert_type = NS_CERT_CHECK_CLIENT; + } + else + { + msg(msglevel, "--ns-cert-type must be 'client' or 'server'"); + goto err; + } } - else if (streq (p[0], "remote-cert-ku")) + else if (streq(p[0], "remote-cert-ku")) { - int j; + int j; - VERIFY_PERMISSION (OPT_P_GENERAL); + VERIFY_PERMISSION(OPT_P_GENERAL); - for (j = 1; j < MAX_PARMS && p[j] != NULL; ++j) - sscanf (p[j], "%x", &(options->remote_cert_ku[j-1])); + for (j = 1; j < MAX_PARMS && p[j] != NULL; ++j) + sscanf(p[j], "%x", &(options->remote_cert_ku[j-1])); } - else if (streq (p[0], "remote-cert-eku") && p[1] && !p[2]) + else if (streq(p[0], "remote-cert-eku") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->remote_cert_eku = p[1]; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->remote_cert_eku = p[1]; } - else if (streq (p[0], "remote-cert-tls") && p[1] && !p[2]) + else if (streq(p[0], "remote-cert-tls") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_GENERAL); + VERIFY_PERMISSION(OPT_P_GENERAL); - if (streq (p[1], "server")) - { - options->remote_cert_ku[0] = 0xa0; - options->remote_cert_ku[1] = 0x88; - options->remote_cert_eku = "TLS Web Server Authentication"; - } - else if (streq (p[1], "client")) - { - options->remote_cert_ku[0] = 0x80; - options->remote_cert_ku[1] = 0x08; - options->remote_cert_ku[2] = 0x88; - options->remote_cert_eku = "TLS Web Client Authentication"; - } - else - { - msg (msglevel, "--remote-cert-tls must be 'client' or 'server'"); - goto err; - } + if (streq(p[1], "server")) + { + options->remote_cert_ku[0] = 0xa0; + options->remote_cert_ku[1] = 0x88; + options->remote_cert_eku = "TLS Web Server Authentication"; + } + else if (streq(p[1], "client")) + { + options->remote_cert_ku[0] = 0x80; + options->remote_cert_ku[1] = 0x08; + options->remote_cert_ku[2] = 0x88; + options->remote_cert_eku = "TLS Web Client Authentication"; + } + else + { + msg(msglevel, "--remote-cert-tls must be 'client' or 'server'"); + goto err; + } } - else if (streq (p[0], "tls-timeout") && p[1] && !p[2]) + else if (streq(p[0], "tls-timeout") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_TLS_PARMS); - options->tls_timeout = positive_atoi (p[1]); + VERIFY_PERMISSION(OPT_P_TLS_PARMS); + options->tls_timeout = positive_atoi(p[1]); } - else if (streq (p[0], "reneg-bytes") && p[1] && !p[2]) + else if (streq(p[0], "reneg-bytes") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_TLS_PARMS); - options->renegotiate_bytes = positive_atoi (p[1]); + VERIFY_PERMISSION(OPT_P_TLS_PARMS); + options->renegotiate_bytes = positive_atoi(p[1]); } - else if (streq (p[0], "reneg-pkts") && p[1] && !p[2]) + else if (streq(p[0], "reneg-pkts") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_TLS_PARMS); - options->renegotiate_packets = positive_atoi (p[1]); + VERIFY_PERMISSION(OPT_P_TLS_PARMS); + options->renegotiate_packets = positive_atoi(p[1]); } - else if (streq (p[0], "reneg-sec") && p[1] && !p[2]) + else if (streq(p[0], "reneg-sec") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_TLS_PARMS); - options->renegotiate_seconds = positive_atoi (p[1]); + VERIFY_PERMISSION(OPT_P_TLS_PARMS); + options->renegotiate_seconds = positive_atoi(p[1]); } - else if (streq (p[0], "hand-window") && p[1] && !p[2]) + else if (streq(p[0], "hand-window") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_TLS_PARMS); - options->handshake_window = positive_atoi (p[1]); + VERIFY_PERMISSION(OPT_P_TLS_PARMS); + options->handshake_window = positive_atoi(p[1]); } - else if (streq (p[0], "tran-window") && p[1] && !p[2]) + else if (streq(p[0], "tran-window") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_TLS_PARMS); - options->transition_window = positive_atoi (p[1]); + VERIFY_PERMISSION(OPT_P_TLS_PARMS); + options->transition_window = positive_atoi(p[1]); } - else if (streq (p[0], "tls-auth") && p[1] && !p[3]) + else if (streq(p[0], "tls-auth") && p[1] && !p[3]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - if (streq (p[1], INLINE_FILE_TAG) && p[2]) - { - options->tls_auth_file_inline = p[2]; - } - else - if (p[2]) - { - int key_direction; + VERIFY_PERMISSION(OPT_P_GENERAL); + if (streq(p[1], INLINE_FILE_TAG) && p[2]) + { + options->tls_auth_file_inline = p[2]; + } + else if (p[2]) + { + int key_direction; - key_direction = ascii2keydirection (msglevel, p[2]); - if (key_direction >= 0) - options->key_direction = key_direction; - else - goto err; - } - options->tls_auth_file = p[1]; + key_direction = ascii2keydirection(msglevel, p[2]); + if (key_direction >= 0) + { + options->key_direction = key_direction; + } + else + { + goto err; + } + } + options->tls_auth_file = p[1]; } - else if (streq (p[0], "tls-crypt") && p[1] && !p[3]) + else if (streq(p[0], "tls-crypt") && p[1] && !p[3]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - if (streq (p[1], INLINE_FILE_TAG) && p[2]) - { - options->tls_crypt_inline = p[2]; - } - options->tls_crypt_file = p[1]; + VERIFY_PERMISSION(OPT_P_GENERAL); + if (streq(p[1], INLINE_FILE_TAG) && p[2]) + { + options->tls_crypt_inline = p[2]; + } + options->tls_crypt_file = p[1]; } - else if (streq (p[0], "key-method") && p[1] && !p[2]) + else if (streq(p[0], "key-method") && p[1] && !p[2]) { - int key_method; + int key_method; - VERIFY_PERMISSION (OPT_P_GENERAL); - key_method = atoi (p[1]); - if (key_method < KEY_METHOD_MIN || key_method > KEY_METHOD_MAX) - { - msg (msglevel, "key_method parameter (%d) must be >= %d and <= %d", - key_method, - KEY_METHOD_MIN, - KEY_METHOD_MAX); - goto err; - } - options->key_method = key_method; + VERIFY_PERMISSION(OPT_P_GENERAL); + key_method = atoi(p[1]); + if (key_method < KEY_METHOD_MIN || key_method > KEY_METHOD_MAX) + { + msg(msglevel, "key_method parameter (%d) must be >= %d and <= %d", + key_method, + KEY_METHOD_MIN, + KEY_METHOD_MAX); + goto err; + } + options->key_method = key_method; } - else if (streq (p[0], "x509-track") && p[1] && !p[2]) + else if (streq(p[0], "x509-track") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - x509_track_add (&options->x509_track, p[1], msglevel, &options->gc); + VERIFY_PERMISSION(OPT_P_GENERAL); + x509_track_add(&options->x509_track, p[1], msglevel, &options->gc); } #ifdef ENABLE_X509ALTUSERNAME - else if (streq (p[0], "x509-username-field") && p[1] && !p[2]) - { - /* This option used to automatically upcase the fieldname passed as the - * option argument, e.g., "ou" became "OU". Now, this "helpfulness" is - * fine-tuned by only upcasing Subject field attribute names which consist - * of all lower-case characters. Mixed-case attributes such as - * "emailAddress" are left as-is. An option parameter having the "ext:" - * prefix for matching X.509v3 extended fields will also remain unchanged. - */ - char *s = p[1]; - - VERIFY_PERMISSION (OPT_P_GENERAL); - if (strncmp("ext:", s, 4) != 0) - { - size_t i = 0; - while (s[i] && !isupper(s[i])) i++; - if (strlen(s) == i) - { - while ((*s = toupper(*s)) != '\0') s++; - msg(M_WARN, "DEPRECATED FEATURE: automatically upcased the " - "--x509-username-field parameter to '%s'; please update your" - "configuration", p[1]); - } - } - options->x509_username_field = p[1]; + else if (streq(p[0], "x509-username-field") && p[1] && !p[2]) + { + /* This option used to automatically upcase the fieldname passed as the + * option argument, e.g., "ou" became "OU". Now, this "helpfulness" is + * fine-tuned by only upcasing Subject field attribute names which consist + * of all lower-case characters. Mixed-case attributes such as + * "emailAddress" are left as-is. An option parameter having the "ext:" + * prefix for matching X.509v3 extended fields will also remain unchanged. + */ + char *s = p[1]; + + VERIFY_PERMISSION(OPT_P_GENERAL); + if (strncmp("ext:", s, 4) != 0) + { + size_t i = 0; + while (s[i] && !isupper(s[i])) i++; + if (strlen(s) == i) + { + while ((*s = toupper(*s)) != '\0') s++; + msg(M_WARN, "DEPRECATED FEATURE: automatically upcased the " + "--x509-username-field parameter to '%s'; please update your" + "configuration", p[1]); + } + } + options->x509_username_field = p[1]; } #endif /* ENABLE_X509ALTUSERNAME */ #endif /* ENABLE_CRYPTO */ #ifdef ENABLE_PKCS11 - else if (streq (p[0], "show-pkcs11-ids") && !p[3]) + else if (streq(p[0], "show-pkcs11-ids") && !p[3]) { - char *provider = p[1]; - bool cert_private = (p[2] == NULL ? false : ( atoi (p[2]) != 0 )); + char *provider = p[1]; + bool cert_private = (p[2] == NULL ? false : ( atoi(p[2]) != 0 )); #ifdef DEFAULT_PKCS11_MODULE - if (!provider) - provider = DEFAULT_PKCS11_MODULE; - else if (!p[2]) + if (!provider) + { + provider = DEFAULT_PKCS11_MODULE; + } + else if (!p[2]) { - char *endp = NULL; - int i = strtol(provider, &endp, 10); + char *endp = NULL; + int i = strtol(provider, &endp, 10); - if (*endp == 0) - { - /* There was one argument, and it was purely numeric. - Interpret it as the cert_private argument */ - provider = DEFAULT_PKCS11_MODULE; - cert_private = i; - } + if (*endp == 0) + { + /* There was one argument, and it was purely numeric. + * Interpret it as the cert_private argument */ + provider = DEFAULT_PKCS11_MODULE; + cert_private = i; + } } -#else - if (!provider) - { - msg (msglevel, "--show-pkcs11-ids requires a provider parameter"); +#else /* ifdef DEFAULT_PKCS11_MODULE */ + if (!provider) + { + msg(msglevel, "--show-pkcs11-ids requires a provider parameter"); goto err; - } -#endif - VERIFY_PERMISSION (OPT_P_GENERAL); + } +#endif /* ifdef DEFAULT_PKCS11_MODULE */ + VERIFY_PERMISSION(OPT_P_GENERAL); - set_debug_level (options->verbosity, SDL_CONSTRAIN); - show_pkcs11_ids (provider, cert_private); - openvpn_exit (OPENVPN_EXIT_STATUS_GOOD); /* exit point */ + set_debug_level(options->verbosity, SDL_CONSTRAIN); + show_pkcs11_ids(provider, cert_private); + openvpn_exit(OPENVPN_EXIT_STATUS_GOOD); /* exit point */ } - else if (streq (p[0], "pkcs11-providers") && p[1]) + else if (streq(p[0], "pkcs11-providers") && p[1]) { - int j; - - VERIFY_PERMISSION (OPT_P_GENERAL); + int j; + + VERIFY_PERMISSION(OPT_P_GENERAL); - for (j = 1; j < MAX_PARMS && p[j] != NULL; ++j) - options->pkcs11_providers[j-1] = p[j]; + for (j = 1; j < MAX_PARMS && p[j] != NULL; ++j) + options->pkcs11_providers[j-1] = p[j]; } - else if (streq (p[0], "pkcs11-protected-authentication")) + else if (streq(p[0], "pkcs11-protected-authentication")) { - int j; + int j; - VERIFY_PERMISSION (OPT_P_GENERAL); + VERIFY_PERMISSION(OPT_P_GENERAL); - for (j = 1; j < MAX_PARMS && p[j] != NULL; ++j) - options->pkcs11_protected_authentication[j-1] = atoi (p[j]) != 0 ? 1 : 0; + for (j = 1; j < MAX_PARMS && p[j] != NULL; ++j) + options->pkcs11_protected_authentication[j-1] = atoi(p[j]) != 0 ? 1 : 0; } - else if (streq (p[0], "pkcs11-private-mode") && p[1]) + else if (streq(p[0], "pkcs11-private-mode") && p[1]) { - int j; - - VERIFY_PERMISSION (OPT_P_GENERAL); + int j; - for (j = 1; j < MAX_PARMS && p[j] != NULL; ++j) - sscanf (p[j], "%x", &(options->pkcs11_private_mode[j-1])); + VERIFY_PERMISSION(OPT_P_GENERAL); + + for (j = 1; j < MAX_PARMS && p[j] != NULL; ++j) + sscanf(p[j], "%x", &(options->pkcs11_private_mode[j-1])); } - else if (streq (p[0], "pkcs11-cert-private")) + else if (streq(p[0], "pkcs11-cert-private")) { - int j; + int j; - VERIFY_PERMISSION (OPT_P_GENERAL); + VERIFY_PERMISSION(OPT_P_GENERAL); - for (j = 1; j < MAX_PARMS && p[j] != NULL; ++j) - options->pkcs11_cert_private[j-1] = atoi (p[j]) != 0 ? 1 : 0; + for (j = 1; j < MAX_PARMS && p[j] != NULL; ++j) + options->pkcs11_cert_private[j-1] = atoi(p[j]) != 0 ? 1 : 0; } - else if (streq (p[0], "pkcs11-pin-cache") && p[1] && !p[2]) + else if (streq(p[0], "pkcs11-pin-cache") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->pkcs11_pin_cache_period = atoi (p[1]); + VERIFY_PERMISSION(OPT_P_GENERAL); + options->pkcs11_pin_cache_period = atoi(p[1]); } - else if (streq (p[0], "pkcs11-id") && p[1] && !p[2]) + else if (streq(p[0], "pkcs11-id") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->pkcs11_id = p[1]; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->pkcs11_id = p[1]; } - else if (streq (p[0], "pkcs11-id-management") && !p[1]) + else if (streq(p[0], "pkcs11-id-management") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->pkcs11_id_management = true; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->pkcs11_id_management = true; } -#endif - else if (streq (p[0], "rmtun") && !p[1]) +#endif /* ifdef ENABLE_PKCS11 */ + else if (streq(p[0], "rmtun") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->persist_config = true; - options->persist_mode = 0; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->persist_config = true; + options->persist_mode = 0; } - else if (streq (p[0], "mktun") && !p[1]) + else if (streq(p[0], "mktun") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->persist_config = true; - options->persist_mode = 1; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->persist_config = true; + options->persist_mode = 1; } - else if (streq (p[0], "peer-id") && p[1] && !p[2]) + else if (streq(p[0], "peer-id") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_PEER_ID); - options->use_peer_id = true; - options->peer_id = atoi(p[1]); + VERIFY_PERMISSION(OPT_P_PEER_ID); + options->use_peer_id = true; + options->peer_id = atoi(p[1]); } #if defined(ENABLE_CRYPTO_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10001000 - else if (streq (p[0], "keying-material-exporter") && p[1] && p[2]) + else if (streq(p[0], "keying-material-exporter") && p[1] && p[2]) { - int ekm_length = positive_atoi (p[2]); + int ekm_length = positive_atoi(p[2]); - VERIFY_PERMISSION (OPT_P_GENERAL); + VERIFY_PERMISSION(OPT_P_GENERAL); - if (strncmp(p[1], "EXPORTER", 8)) + if (strncmp(p[1], "EXPORTER", 8)) { - msg (msglevel, "Keying material exporter label must begin with " - "\"EXPORTER\""); - goto err; + msg(msglevel, "Keying material exporter label must begin with " + "\"EXPORTER\""); + goto err; } - if (ekm_length < 16 || ekm_length > 4095) + if (ekm_length < 16 || ekm_length > 4095) { - msg (msglevel, "Invalid keying material exporter length"); - goto err; + msg(msglevel, "Invalid keying material exporter length"); + goto err; } - options->keying_material_exporter_label = p[1]; - options->keying_material_exporter_length = ekm_length; + options->keying_material_exporter_label = p[1]; + options->keying_material_exporter_length = ekm_length; } -#endif - else if (streq (p[0], "allow-recursive-routing") && !p[1]) +#endif /* if defined(ENABLE_CRYPTO_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10001000 */ + else if (streq(p[0], "allow-recursive-routing") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->allow_recursive_routing = true; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->allow_recursive_routing = true; } - else + else { - int i; - int msglevel= msglevel_fc; - /* Check if an option is in --ignore-unknown-option and - set warning level to non fatal */ - for(i=0; options->ignore_unknown_option && options->ignore_unknown_option[i]; i++) + int i; + int msglevel = msglevel_fc; + /* Check if an option is in --ignore-unknown-option and + * set warning level to non fatal */ + for (i = 0; options->ignore_unknown_option && options->ignore_unknown_option[i]; i++) { - if (streq(p[0], options->ignore_unknown_option[i])) + if (streq(p[0], options->ignore_unknown_option[i])) { - msglevel = M_WARN; - break; + msglevel = M_WARN; + break; } } - if (file) - msg (msglevel, "Unrecognized option or missing or extra parameter(s) in %s:%d: %s (%s)", file, line, p[0], PACKAGE_VERSION); - else - msg (msglevel, "Unrecognized option or missing or extra parameter(s): --%s (%s)", p[0], PACKAGE_VERSION); + if (file) + { + msg(msglevel, "Unrecognized option or missing or extra parameter(s) in %s:%d: %s (%s)", file, line, p[0], PACKAGE_VERSION); + } + else + { + msg(msglevel, "Unrecognized option or missing or extra parameter(s): --%s (%s)", p[0], PACKAGE_VERSION); + } } - err: - gc_free (&gc); +err: + gc_free(&gc); } diff --git a/src/openvpn/options.h b/src/openvpn/options.h index 067728a070f..3fd0f23083e 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -62,310 +62,310 @@ extern const char title_string[]; /* certain options are saved before --pull modifications are applied */ struct options_pre_pull { - bool tuntap_options_defined; - struct tuntap_options tuntap_options; + bool tuntap_options_defined; + struct tuntap_options tuntap_options; - bool routes_defined; - struct route_option_list *routes; + bool routes_defined; + struct route_option_list *routes; - bool routes_ipv6_defined; - struct route_ipv6_option_list *routes_ipv6; + bool routes_ipv6_defined; + struct route_ipv6_option_list *routes_ipv6; - bool client_nat_defined; - struct client_nat_option_list *client_nat; + bool client_nat_defined; + struct client_nat_option_list *client_nat; - int foreign_option_index; + int foreign_option_index; }; #endif #if defined(ENABLE_CRYPTO) && !defined(ENABLE_CRYPTO_OPENSSL) && !defined(ENABLE_CRYPTO_MBEDTLS) -# error "At least one of OpenSSL or mbed TLS needs to be defined." +#error "At least one of OpenSSL or mbed TLS needs to be defined." #endif struct connection_entry { - int proto; - sa_family_t af; - const char* local_port; - bool local_port_defined; - const char *remote_port; - const char *local; - const char *remote; - bool remote_float; - bool bind_defined; - bool bind_ipv6_only; - bool bind_local; - int connect_retry_seconds; - int connect_retry_seconds_max; - int connect_timeout; - struct http_proxy_options *http_proxy_options; - const char *socks_proxy_server; - const char *socks_proxy_port; - const char *socks_proxy_authfile; - - int tun_mtu; /* MTU of tun device */ - bool tun_mtu_defined; /* true if user overriding parm with command line option */ - int tun_mtu_extra; - bool tun_mtu_extra_defined; - int link_mtu; /* MTU of device over which tunnel packets pass via TCP/UDP */ - bool link_mtu_defined; /* true if user overriding parm with command line option */ - - /* Advanced MTU negotiation and datagram fragmentation options */ - int mtu_discover_type; /* used if OS supports setting Path MTU discovery options on socket */ - - int fragment; /* internal fragmentation size */ - int mssfix; /* Upper bound on TCP MSS */ - bool mssfix_default; /* true if --mssfix was supplied without a parameter */ - - int explicit_exit_notification; /* Explicitly tell peer when we are exiting via OCC_EXIT or [RESTART] message */ - -# define CE_DISABLED (1<<0) -# define CE_MAN_QUERY_PROXY (1<<1) -# define CE_MAN_QUERY_REMOTE_UNDEF 0 -# define CE_MAN_QUERY_REMOTE_QUERY 1 -# define CE_MAN_QUERY_REMOTE_ACCEPT 2 -# define CE_MAN_QUERY_REMOTE_MOD 3 -# define CE_MAN_QUERY_REMOTE_SKIP 4 -# define CE_MAN_QUERY_REMOTE_MASK (0x07) -# define CE_MAN_QUERY_REMOTE_SHIFT (2) - unsigned int flags; + int proto; + sa_family_t af; + const char *local_port; + bool local_port_defined; + const char *remote_port; + const char *local; + const char *remote; + bool remote_float; + bool bind_defined; + bool bind_ipv6_only; + bool bind_local; + int connect_retry_seconds; + int connect_retry_seconds_max; + int connect_timeout; + struct http_proxy_options *http_proxy_options; + const char *socks_proxy_server; + const char *socks_proxy_port; + const char *socks_proxy_authfile; + + int tun_mtu; /* MTU of tun device */ + bool tun_mtu_defined; /* true if user overriding parm with command line option */ + int tun_mtu_extra; + bool tun_mtu_extra_defined; + int link_mtu; /* MTU of device over which tunnel packets pass via TCP/UDP */ + bool link_mtu_defined; /* true if user overriding parm with command line option */ + + /* Advanced MTU negotiation and datagram fragmentation options */ + int mtu_discover_type; /* used if OS supports setting Path MTU discovery options on socket */ + + int fragment; /* internal fragmentation size */ + int mssfix; /* Upper bound on TCP MSS */ + bool mssfix_default; /* true if --mssfix was supplied without a parameter */ + + int explicit_exit_notification; /* Explicitly tell peer when we are exiting via OCC_EXIT or [RESTART] message */ + +#define CE_DISABLED (1<<0) +#define CE_MAN_QUERY_PROXY (1<<1) +#define CE_MAN_QUERY_REMOTE_UNDEF 0 +#define CE_MAN_QUERY_REMOTE_QUERY 1 +#define CE_MAN_QUERY_REMOTE_ACCEPT 2 +#define CE_MAN_QUERY_REMOTE_MOD 3 +#define CE_MAN_QUERY_REMOTE_SKIP 4 +#define CE_MAN_QUERY_REMOTE_MASK (0x07) +#define CE_MAN_QUERY_REMOTE_SHIFT (2) + unsigned int flags; }; struct remote_entry { - const char *remote; - const char *remote_port; - int proto; - sa_family_t af; + const char *remote; + const char *remote_port; + int proto; + sa_family_t af; }; #define CONNECTION_LIST_SIZE 64 struct connection_list { - int len; - int current; - struct connection_entry *array[CONNECTION_LIST_SIZE]; + int len; + int current; + struct connection_entry *array[CONNECTION_LIST_SIZE]; }; struct remote_list { - int len; - struct remote_entry *array[CONNECTION_LIST_SIZE]; + int len; + struct remote_entry *array[CONNECTION_LIST_SIZE]; }; struct remote_host_store { -# define RH_HOST_LEN 80 - char host[RH_HOST_LEN]; +#define RH_HOST_LEN 80 + char host[RH_HOST_LEN]; #define RH_PORT_LEN 20 - char port[RH_PORT_LEN]; + char port[RH_PORT_LEN]; }; /* Command line options */ struct options { - struct gc_arena gc; - bool gc_owned; + struct gc_arena gc; + bool gc_owned; - /* first config file */ - const char *config; + /* first config file */ + const char *config; - /* major mode */ -# define MODE_POINT_TO_POINT 0 -# define MODE_SERVER 1 - int mode; + /* major mode */ +#define MODE_POINT_TO_POINT 0 +#define MODE_SERVER 1 + int mode; - /* enable forward compatibility for post-2.1 features */ - bool forward_compatible; - /* list of options that should be ignored even if unkown */ - const char ** ignore_unknown_option; + /* enable forward compatibility for post-2.1 features */ + bool forward_compatible; + /* list of options that should be ignored even if unkown */ + const char **ignore_unknown_option; - /* persist parms */ - bool persist_config; - int persist_mode; + /* persist parms */ + bool persist_config; + int persist_mode; #ifdef ENABLE_CRYPTO - const char *key_pass_file; - bool show_ciphers; - bool show_digests; - bool show_engines; - bool show_tls_ciphers; - bool show_curves; - bool genkey; -#endif - - /* Networking parms */ - int connect_retry_max; - struct connection_entry ce; - struct connection_list *connection_list; - - struct remote_list *remote_list; - /* Do not advanced the connection or remote addr list*/ - bool no_advance; - /* Counts the number of unsuccessful connection attempts */ - unsigned int unsuccessful_attempts; + const char *key_pass_file; + bool show_ciphers; + bool show_digests; + bool show_engines; + bool show_tls_ciphers; + bool show_curves; + bool genkey; +#endif + + /* Networking parms */ + int connect_retry_max; + struct connection_entry ce; + struct connection_list *connection_list; + + struct remote_list *remote_list; + /* Do not advanced the connection or remote addr list*/ + bool no_advance; + /* Counts the number of unsuccessful connection attempts */ + unsigned int unsuccessful_attempts; #if ENABLE_MANAGEMENT - struct http_proxy_options *http_proxy_override; -#endif - - struct remote_host_store *rh_store; - - bool remote_random; - const char *ipchange; - const char *dev; - const char *dev_type; - const char *dev_node; - const char *lladdr; - int topology; /* one of the TOP_x values from proto.h */ - const char *ifconfig_local; - const char *ifconfig_remote_netmask; - const char *ifconfig_ipv6_local; - int ifconfig_ipv6_netbits; - const char *ifconfig_ipv6_remote; - bool ifconfig_noexec; - bool ifconfig_nowarn; + struct http_proxy_options *http_proxy_override; +#endif + + struct remote_host_store *rh_store; + + bool remote_random; + const char *ipchange; + const char *dev; + const char *dev_type; + const char *dev_node; + const char *lladdr; + int topology; /* one of the TOP_x values from proto.h */ + const char *ifconfig_local; + const char *ifconfig_remote_netmask; + const char *ifconfig_ipv6_local; + int ifconfig_ipv6_netbits; + const char *ifconfig_ipv6_remote; + bool ifconfig_noexec; + bool ifconfig_nowarn; #ifdef ENABLE_FEATURE_SHAPER - int shaper; + int shaper; #endif - int proto_force; + int proto_force; #ifdef ENABLE_OCC - bool mtu_test; + bool mtu_test; #endif #ifdef ENABLE_MEMSTATS - char *memstats_fn; + char *memstats_fn; #endif - bool mlock; + bool mlock; - int keepalive_ping; /* a proxy for ping/ping-restart */ - int keepalive_timeout; + int keepalive_ping; /* a proxy for ping/ping-restart */ + int keepalive_timeout; - int inactivity_timeout; /* --inactive */ - int inactivity_minimum_bytes; + int inactivity_timeout; /* --inactive */ + int inactivity_minimum_bytes; - int ping_send_timeout; /* Send a TCP/UDP ping to remote every n seconds */ - int ping_rec_timeout; /* Expect a TCP/UDP ping from remote at least once every n seconds */ - bool ping_timer_remote; /* Run ping timer only if we have a remote address */ + int ping_send_timeout; /* Send a TCP/UDP ping to remote every n seconds */ + int ping_rec_timeout; /* Expect a TCP/UDP ping from remote at least once every n seconds */ + bool ping_timer_remote; /* Run ping timer only if we have a remote address */ -# define PING_UNDEF 0 -# define PING_EXIT 1 -# define PING_RESTART 2 - int ping_rec_timeout_action; /* What action to take on ping_rec_timeout (exit or restart)? */ +#define PING_UNDEF 0 +#define PING_EXIT 1 +#define PING_RESTART 2 + int ping_rec_timeout_action; /* What action to take on ping_rec_timeout (exit or restart)? */ - bool persist_tun; /* Don't close/reopen TUN/TAP dev on SIGUSR1 or PING_RESTART */ - bool persist_local_ip; /* Don't re-resolve local address on SIGUSR1 or PING_RESTART */ - bool persist_remote_ip; /* Don't re-resolve remote address on SIGUSR1 or PING_RESTART */ - bool persist_key; /* Don't re-read key files on SIGUSR1 or PING_RESTART */ + bool persist_tun; /* Don't close/reopen TUN/TAP dev on SIGUSR1 or PING_RESTART */ + bool persist_local_ip; /* Don't re-resolve local address on SIGUSR1 or PING_RESTART */ + bool persist_remote_ip; /* Don't re-resolve remote address on SIGUSR1 or PING_RESTART */ + bool persist_key; /* Don't re-read key files on SIGUSR1 or PING_RESTART */ #if PASSTOS_CAPABILITY - bool passtos; + bool passtos; #endif - int resolve_retry_seconds; /* If hostname resolve fails, retry for n seconds */ - bool resolve_in_advance; - const char *ip_remote_hint; + int resolve_retry_seconds; /* If hostname resolve fails, retry for n seconds */ + bool resolve_in_advance; + const char *ip_remote_hint; - struct tuntap_options tuntap_options; + struct tuntap_options tuntap_options; - /* Misc parms */ - const char *username; - const char *groupname; - const char *chroot_dir; - const char *cd_dir; + /* Misc parms */ + const char *username; + const char *groupname; + const char *chroot_dir; + const char *cd_dir; #ifdef ENABLE_SELINUX - char *selinux_context; + char *selinux_context; #endif - const char *writepid; - const char *up_script; - const char *down_script; - bool user_script_used; - bool down_pre; - bool up_delay; - bool up_restart; - bool daemon; + const char *writepid; + const char *up_script; + const char *down_script; + bool user_script_used; + bool down_pre; + bool up_delay; + bool up_restart; + bool daemon; - int remap_sigusr1; + int remap_sigusr1; - /* inetd modes defined in socket.h */ - int inetd; + /* inetd modes defined in socket.h */ + int inetd; - bool log; - bool suppress_timestamps; - bool machine_readable_output; - int nice; - int verbosity; - int mute; + bool log; + bool suppress_timestamps; + bool machine_readable_output; + int nice; + int verbosity; + int mute; #ifdef ENABLE_DEBUG - int gremlin; + int gremlin; #endif - const char *status_file; - int status_file_version; - int status_file_update_freq; + const char *status_file; + int status_file_version; + int status_file_update_freq; - /* optimize TUN/TAP/UDP writes */ - bool fast_io; + /* optimize TUN/TAP/UDP writes */ + bool fast_io; #ifdef USE_COMP - struct compress_options comp; -#endif - - /* buffer sizes */ - int rcvbuf; - int sndbuf; - - /* mark value */ - int mark; - - /* socket flags */ - unsigned int sockflags; - - /* route management */ - const char *route_script; - const char *route_predown_script; - const char *route_default_gateway; - int route_default_metric; - bool route_noexec; - int route_delay; - int route_delay_window; - bool route_delay_defined; - struct route_option_list *routes; - struct route_ipv6_option_list *routes_ipv6; /* IPv6 */ - bool route_nopull; - bool route_gateway_via_dhcp; - bool allow_pull_fqdn; /* as a client, allow server to push a FQDN for certain parameters */ - struct client_nat_option_list *client_nat; + struct compress_options comp; +#endif + + /* buffer sizes */ + int rcvbuf; + int sndbuf; + + /* mark value */ + int mark; + + /* socket flags */ + unsigned int sockflags; + + /* route management */ + const char *route_script; + const char *route_predown_script; + const char *route_default_gateway; + int route_default_metric; + bool route_noexec; + int route_delay; + int route_delay_window; + bool route_delay_defined; + struct route_option_list *routes; + struct route_ipv6_option_list *routes_ipv6; /* IPv6 */ + bool route_nopull; + bool route_gateway_via_dhcp; + bool allow_pull_fqdn; /* as a client, allow server to push a FQDN for certain parameters */ + struct client_nat_option_list *client_nat; #ifdef ENABLE_OCC - /* Enable options consistency check between peers */ - bool occ; + /* Enable options consistency check between peers */ + bool occ; #endif #ifdef ENABLE_MANAGEMENT - const char *management_addr; - const char *management_port; - const char *management_user_pass; - int management_log_history_cache; - int management_echo_buffer_size; - int management_state_buffer_size; - const char *management_write_peer_info_file; + const char *management_addr; + const char *management_port; + const char *management_user_pass; + int management_log_history_cache; + int management_echo_buffer_size; + int management_state_buffer_size; + const char *management_write_peer_info_file; - const char *management_client_user; - const char *management_client_group; + const char *management_client_user; + const char *management_client_group; - /* Mask of MF_ values of manage.h */ - unsigned int management_flags; - const char *management_certificate; + /* Mask of MF_ values of manage.h */ + unsigned int management_flags; + const char *management_certificate; #endif #ifdef ENABLE_PLUGIN - struct plugin_option_list *plugin_list; + struct plugin_option_list *plugin_list; #endif @@ -373,238 +373,238 @@ struct options #if P2MP #if P2MP_SERVER - /* the tmp dir is for now only used in the P2P server context */ - const char *tmp_dir; - bool server_defined; - in_addr_t server_network; - in_addr_t server_netmask; - bool server_ipv6_defined; /* IPv6 */ - struct in6_addr server_network_ipv6; /* IPv6 */ - unsigned int server_netbits_ipv6; /* IPv6 */ - -# define SF_NOPOOL (1<<0) -# define SF_TCP_NODELAY_HELPER (1<<1) -# define SF_NO_PUSH_ROUTE_GATEWAY (1<<2) - unsigned int server_flags; - - bool server_bridge_proxy_dhcp; - - bool server_bridge_defined; - in_addr_t server_bridge_ip; - in_addr_t server_bridge_netmask; - in_addr_t server_bridge_pool_start; - in_addr_t server_bridge_pool_end; - - struct push_list push_list; - bool ifconfig_pool_defined; - in_addr_t ifconfig_pool_start; - in_addr_t ifconfig_pool_end; - in_addr_t ifconfig_pool_netmask; - const char *ifconfig_pool_persist_filename; - int ifconfig_pool_persist_refresh_freq; - - bool ifconfig_ipv6_pool_defined; /* IPv6 */ - struct in6_addr ifconfig_ipv6_pool_base; /* IPv6 */ - int ifconfig_ipv6_pool_netbits; /* IPv6 */ - - int real_hash_size; - int virtual_hash_size; - const char *client_connect_script; - const char *client_disconnect_script; - const char *learn_address_script; - const char *client_config_dir; - bool ccd_exclusive; - bool disable; - int n_bcast_buf; - int tcp_queue_limit; - struct iroute *iroutes; - struct iroute_ipv6 *iroutes_ipv6; /* IPv6 */ - bool push_ifconfig_defined; - in_addr_t push_ifconfig_local; - in_addr_t push_ifconfig_remote_netmask; - in_addr_t push_ifconfig_local_alias; - bool push_ifconfig_constraint_defined; - in_addr_t push_ifconfig_constraint_network; - in_addr_t push_ifconfig_constraint_netmask; - bool push_ifconfig_ipv6_defined; /* IPv6 */ - struct in6_addr push_ifconfig_ipv6_local; /* IPv6 */ - int push_ifconfig_ipv6_netbits; /* IPv6 */ - struct in6_addr push_ifconfig_ipv6_remote; /* IPv6 */ - bool push_ifconfig_ipv6_blocked; /* IPv6 */ - bool enable_c2c; - bool duplicate_cn; - int cf_max; - int cf_per; - int max_clients; - int max_routes_per_client; - int stale_routes_check_interval; - int stale_routes_ageing_time; - - const char *auth_user_pass_verify_script; - bool auth_user_pass_verify_script_via_file; - bool auth_token_generate; - unsigned int auth_token_lifetime; + /* the tmp dir is for now only used in the P2P server context */ + const char *tmp_dir; + bool server_defined; + in_addr_t server_network; + in_addr_t server_netmask; + bool server_ipv6_defined; /* IPv6 */ + struct in6_addr server_network_ipv6; /* IPv6 */ + unsigned int server_netbits_ipv6; /* IPv6 */ + +#define SF_NOPOOL (1<<0) +#define SF_TCP_NODELAY_HELPER (1<<1) +#define SF_NO_PUSH_ROUTE_GATEWAY (1<<2) + unsigned int server_flags; + + bool server_bridge_proxy_dhcp; + + bool server_bridge_defined; + in_addr_t server_bridge_ip; + in_addr_t server_bridge_netmask; + in_addr_t server_bridge_pool_start; + in_addr_t server_bridge_pool_end; + + struct push_list push_list; + bool ifconfig_pool_defined; + in_addr_t ifconfig_pool_start; + in_addr_t ifconfig_pool_end; + in_addr_t ifconfig_pool_netmask; + const char *ifconfig_pool_persist_filename; + int ifconfig_pool_persist_refresh_freq; + + bool ifconfig_ipv6_pool_defined; /* IPv6 */ + struct in6_addr ifconfig_ipv6_pool_base; /* IPv6 */ + int ifconfig_ipv6_pool_netbits; /* IPv6 */ + + int real_hash_size; + int virtual_hash_size; + const char *client_connect_script; + const char *client_disconnect_script; + const char *learn_address_script; + const char *client_config_dir; + bool ccd_exclusive; + bool disable; + int n_bcast_buf; + int tcp_queue_limit; + struct iroute *iroutes; + struct iroute_ipv6 *iroutes_ipv6; /* IPv6 */ + bool push_ifconfig_defined; + in_addr_t push_ifconfig_local; + in_addr_t push_ifconfig_remote_netmask; + in_addr_t push_ifconfig_local_alias; + bool push_ifconfig_constraint_defined; + in_addr_t push_ifconfig_constraint_network; + in_addr_t push_ifconfig_constraint_netmask; + bool push_ifconfig_ipv6_defined; /* IPv6 */ + struct in6_addr push_ifconfig_ipv6_local; /* IPv6 */ + int push_ifconfig_ipv6_netbits; /* IPv6 */ + struct in6_addr push_ifconfig_ipv6_remote; /* IPv6 */ + bool push_ifconfig_ipv6_blocked; /* IPv6 */ + bool enable_c2c; + bool duplicate_cn; + int cf_max; + int cf_per; + int max_clients; + int max_routes_per_client; + int stale_routes_check_interval; + int stale_routes_ageing_time; + + const char *auth_user_pass_verify_script; + bool auth_user_pass_verify_script_via_file; + bool auth_token_generate; + unsigned int auth_token_lifetime; #if PORT_SHARE - char *port_share_host; - char *port_share_port; - const char *port_share_journal_dir; -#endif + char *port_share_host; + char *port_share_port; + const char *port_share_journal_dir; #endif +#endif /* if P2MP_SERVER */ - bool client; - bool pull; /* client pull of config options from server */ - int push_continuation; - unsigned int push_option_types_found; - const char *auth_user_pass_file; - struct options_pre_pull *pre_pull; + bool client; + bool pull; /* client pull of config options from server */ + int push_continuation; + unsigned int push_option_types_found; + const char *auth_user_pass_file; + struct options_pre_pull *pre_pull; - int scheduled_exit_interval; + int scheduled_exit_interval; #ifdef ENABLE_CLIENT_CR - struct static_challenge_info sc_info; -#endif + struct static_challenge_info sc_info; #endif +#endif /* if P2MP */ #ifdef ENABLE_CRYPTO - /* Cipher parms */ - const char *shared_secret_file; - const char *shared_secret_file_inline; - int key_direction; - const char *ciphername; - bool ncp_enabled; - const char *ncp_ciphers; - const char *authname; - int keysize; - const char *prng_hash; - int prng_nonce_secret_len; - const char *engine; - bool replay; - bool mute_replay_warnings; - int replay_window; - int replay_time; - const char *packet_id_file; - bool use_iv; - bool test_crypto; + /* Cipher parms */ + const char *shared_secret_file; + const char *shared_secret_file_inline; + int key_direction; + const char *ciphername; + bool ncp_enabled; + const char *ncp_ciphers; + const char *authname; + int keysize; + const char *prng_hash; + int prng_nonce_secret_len; + const char *engine; + bool replay; + bool mute_replay_warnings; + int replay_window; + int replay_time; + const char *packet_id_file; + bool use_iv; + bool test_crypto; #ifdef ENABLE_PREDICTION_RESISTANCE - bool use_prediction_resistance; -#endif - - /* TLS (control channel) parms */ - bool tls_server; - bool tls_client; - const char *ca_file; - const char *ca_path; - const char *dh_file; - const char *cert_file; - const char *extra_certs_file; - const char *priv_key_file; - const char *pkcs12_file; - const char *cipher_list; - const char *ecdh_curve; - const char *tls_verify; - int verify_x509_type; - const char *verify_x509_name; - const char *tls_export_cert; - const char *crl_file; - - const char *ca_file_inline; - const char *cert_file_inline; - const char *extra_certs_file_inline; - const char *crl_file_inline; - char *priv_key_file_inline; - const char *dh_file_inline; - const char *pkcs12_file_inline; /* contains the base64 encoding of pkcs12 file */ - - int ns_cert_type; /* set to 0, NS_CERT_CHECK_SERVER, or NS_CERT_CHECK_CLIENT */ - unsigned remote_cert_ku[MAX_PARMS]; - const char *remote_cert_eku; - uint8_t *verify_hash; - unsigned int ssl_flags; /* set to SSLF_x flags from ssl.h */ + bool use_prediction_resistance; +#endif + + /* TLS (control channel) parms */ + bool tls_server; + bool tls_client; + const char *ca_file; + const char *ca_path; + const char *dh_file; + const char *cert_file; + const char *extra_certs_file; + const char *priv_key_file; + const char *pkcs12_file; + const char *cipher_list; + const char *ecdh_curve; + const char *tls_verify; + int verify_x509_type; + const char *verify_x509_name; + const char *tls_export_cert; + const char *crl_file; + + const char *ca_file_inline; + const char *cert_file_inline; + const char *extra_certs_file_inline; + const char *crl_file_inline; + char *priv_key_file_inline; + const char *dh_file_inline; + const char *pkcs12_file_inline; /* contains the base64 encoding of pkcs12 file */ + + int ns_cert_type; /* set to 0, NS_CERT_CHECK_SERVER, or NS_CERT_CHECK_CLIENT */ + unsigned remote_cert_ku[MAX_PARMS]; + const char *remote_cert_eku; + uint8_t *verify_hash; + unsigned int ssl_flags; /* set to SSLF_x flags from ssl.h */ #ifdef ENABLE_PKCS11 - const char *pkcs11_providers[MAX_PARMS]; - unsigned pkcs11_private_mode[MAX_PARMS]; - bool pkcs11_protected_authentication[MAX_PARMS]; - bool pkcs11_cert_private[MAX_PARMS]; - int pkcs11_pin_cache_period; - const char *pkcs11_id; - bool pkcs11_id_management; + const char *pkcs11_providers[MAX_PARMS]; + unsigned pkcs11_private_mode[MAX_PARMS]; + bool pkcs11_protected_authentication[MAX_PARMS]; + bool pkcs11_cert_private[MAX_PARMS]; + int pkcs11_pin_cache_period; + const char *pkcs11_id; + bool pkcs11_id_management; #endif #ifdef ENABLE_CRYPTOAPI - const char *cryptoapi_cert; + const char *cryptoapi_cert; #endif - /* data channel key exchange method */ - int key_method; + /* data channel key exchange method */ + int key_method; - /* Per-packet timeout on control channel */ - int tls_timeout; + /* Per-packet timeout on control channel */ + int tls_timeout; - /* Data channel key renegotiation parameters */ - int renegotiate_bytes; - int renegotiate_packets; - int renegotiate_seconds; + /* Data channel key renegotiation parameters */ + int renegotiate_bytes; + int renegotiate_packets; + int renegotiate_seconds; - /* Data channel key handshake must finalize - within n seconds of handshake initiation. */ - int handshake_window; + /* Data channel key handshake must finalize + * within n seconds of handshake initiation. */ + int handshake_window; #ifdef ENABLE_X509ALTUSERNAME - /* Field used to be the username in X509 cert. */ - char *x509_username_field; + /* Field used to be the username in X509 cert. */ + char *x509_username_field; #endif - /* Old key allowed to live n seconds after new key goes active */ - int transition_window; + /* Old key allowed to live n seconds after new key goes active */ + int transition_window; - /* Shared secret used for TLS control channel authentication */ - const char *tls_auth_file; - const char *tls_auth_file_inline; + /* Shared secret used for TLS control channel authentication */ + const char *tls_auth_file; + const char *tls_auth_file_inline; - /* Shared secret used for TLS control channel authenticated encryption */ - const char *tls_crypt_file; - const char *tls_crypt_inline; + /* Shared secret used for TLS control channel authenticated encryption */ + const char *tls_crypt_file; + const char *tls_crypt_inline; - /* Allow only one session */ - bool single_session; + /* Allow only one session */ + bool single_session; #ifdef ENABLE_PUSH_PEER_INFO - bool push_peer_info; + bool push_peer_info; #endif - bool tls_exit; + bool tls_exit; #endif /* ENABLE_CRYPTO */ - const struct x509_track *x509_track; + const struct x509_track *x509_track; - /* special state parms */ - int foreign_option_index; + /* special state parms */ + int foreign_option_index; #ifdef _WIN32 - HANDLE msg_channel; - const char *exit_event_name; - bool exit_event_initial_state; - bool show_net_up; - int route_method; - bool block_outside_dns; + HANDLE msg_channel; + const char *exit_event_name; + bool exit_event_initial_state; + bool show_net_up; + int route_method; + bool block_outside_dns; #endif - bool use_peer_id; - uint32_t peer_id; + bool use_peer_id; + uint32_t peer_id; #if defined(ENABLE_CRYPTO_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10001000 - /* Keying Material Exporters [RFC 5705] */ - const char *keying_material_exporter_label; - int keying_material_exporter_length; + /* Keying Material Exporters [RFC 5705] */ + const char *keying_material_exporter_label; + int keying_material_exporter_length; #endif - struct pull_filter_list *pull_filter_list; + struct pull_filter_list *pull_filter_list; - /* Useful when packets sent by openvpn itself are not subject - to the routing tables that would move packets into the tunnel. */ - bool allow_recursive_routing; + /* Useful when packets sent by openvpn itself are not subject + * to the routing tables that would move packets into the tunnel. */ + bool allow_recursive_routing; }; #define streq(x, y) (!strcmp((x), (y))) @@ -683,101 +683,109 @@ struct options #define MAN_CLIENT_AUTH_ENABLED(opt) (false) #endif -void parse_argv (struct options *options, - const int argc, - char *argv[], - const int msglevel, - const unsigned int permission_mask, - unsigned int *option_types_found, - struct env_set *es); +void parse_argv(struct options *options, + const int argc, + char *argv[], + const int msglevel, + const unsigned int permission_mask, + unsigned int *option_types_found, + struct env_set *es); -void notnull (const char *arg, const char *description); +void notnull(const char *arg, const char *description); -void usage_small (void); +void usage_small(void); void show_library_versions(const unsigned int flags); #ifdef _WIN32 void show_windows_version(const unsigned int flags); + #endif -void init_options (struct options *o, const bool init_gc); -void uninit_options (struct options *o); +void init_options(struct options *o, const bool init_gc); + +void uninit_options(struct options *o); -void setenv_settings (struct env_set *es, const struct options *o); -void show_settings (const struct options *o); +void setenv_settings(struct env_set *es, const struct options *o); -bool string_defined_equal (const char *s1, const char *s2); +void show_settings(const struct options *o); + +bool string_defined_equal(const char *s1, const char *s2); #ifdef ENABLE_OCC -const char *options_string_version (const char* s, struct gc_arena *gc); +const char *options_string_version(const char *s, struct gc_arena *gc); + +char *options_string(const struct options *o, + const struct frame *frame, + struct tuntap *tt, + bool remote, + struct gc_arena *gc); + +bool options_cmp_equal_safe(char *actual, const char *expected, size_t actual_n); -char *options_string (const struct options *o, - const struct frame *frame, - struct tuntap *tt, - bool remote, - struct gc_arena *gc); +void options_warning_safe(char *actual, const char *expected, size_t actual_n); -bool options_cmp_equal_safe (char *actual, const char *expected, size_t actual_n); -void options_warning_safe (char *actual, const char *expected, size_t actual_n); -bool options_cmp_equal (char *actual, const char *expected); -void options_warning (char *actual, const char *expected); +bool options_cmp_equal(char *actual, const char *expected); + +void options_warning(char *actual, const char *expected); #endif /** * Given an OpenVPN options string, extract the value of an option. * - * @param options_string Zero-terminated, comma-separated options string - * @param opt_name The name of the option to extract - * @param gc The gc to allocate the return value + * @param options_string Zero-terminated, comma-separated options string + * @param opt_name The name of the option to extract + * @param gc The gc to allocate the return value * * @return gc-allocated value of option with name opt_name if option was found, * or NULL otherwise. */ -char *options_string_extract_option (const char *options_string, - const char *opt_name, struct gc_arena *gc); +char *options_string_extract_option(const char *options_string, + const char *opt_name, struct gc_arena *gc); + +void options_postprocess(struct options *options); -void options_postprocess (struct options *options); +void pre_pull_save(struct options *o); -void pre_pull_save (struct options *o); -void pre_pull_restore (struct options *o, struct gc_arena *gc); +void pre_pull_restore(struct options *o, struct gc_arena *gc); -bool apply_push_options (struct options *options, - struct buffer *buf, - unsigned int permission_mask, - unsigned int *option_types_found, - struct env_set *es); +bool apply_push_options(struct options *options, + struct buffer *buf, + unsigned int permission_mask, + unsigned int *option_types_found, + struct env_set *es); -void options_detach (struct options *o); +void options_detach(struct options *o); -void options_server_import (struct options *o, - const char *filename, - int msglevel, - unsigned int permission_mask, - unsigned int *option_types_found, - struct env_set *es); +void options_server_import(struct options *o, + const char *filename, + int msglevel, + unsigned int permission_mask, + unsigned int *option_types_found, + struct env_set *es); -void pre_pull_default (struct options *o); +void pre_pull_default(struct options *o); -void rol_check_alloc (struct options *options); +void rol_check_alloc(struct options *options); -int parse_line (const char *line, - char *p[], - const int n, - const char *file, - const int line_num, - int msglevel, - struct gc_arena *gc); +int parse_line(const char *line, + char *p[], + const int n, + const char *file, + const int line_num, + int msglevel, + struct gc_arena *gc); /* * parse/print topology coding */ -int parse_topology (const char *str, const int msglevel); -const char *print_topology (const int topology); +int parse_topology(const char *str, const int msglevel); + +const char *print_topology(const int topology); /* * Manage auth-retry variable @@ -789,21 +797,23 @@ const char *print_topology (const int topology); #define AR_INTERACT 1 #define AR_NOINTERACT 2 -int auth_retry_get (void); -bool auth_retry_set (const int msglevel, const char *option); -const char *auth_retry_print (void); +int auth_retry_get(void); + +bool auth_retry_set(const int msglevel, const char *option); + +const char *auth_retry_print(void); #endif -void options_string_import (struct options *options, - const char *config, - const int msglevel, - const unsigned int permission_mask, - unsigned int *option_types_found, - struct env_set *es); +void options_string_import(struct options *options, + const char *config, + const int msglevel, + const unsigned int permission_mask, + unsigned int *option_types_found, + struct env_set *es); -bool get_ipv6_addr( const char * prefix_str, struct in6_addr *network, - unsigned int * netbits, int msglevel ); +bool get_ipv6_addr( const char *prefix_str, struct in6_addr *network, + unsigned int *netbits, int msglevel ); -#endif +#endif /* ifndef OPTIONS_H */ diff --git a/src/openvpn/otime.c b/src/openvpn/otime.c index 2c1e5b1347e..cc487e50862 100644 --- a/src/openvpn/otime.c +++ b/src/openvpn/otime.c @@ -47,90 +47,96 @@ time_t now_usec = 0; /* GLOBAL */ */ void -update_now (const time_t system_time) +update_now(const time_t system_time) { - const int forward_threshold = 86400; /* threshold at which to dampen forward jumps */ - const int backward_trigger = 10; /* backward jump must be >= this many seconds before we adjust */ - time_t real_time = system_time + now_adj; + const int forward_threshold = 86400; /* threshold at which to dampen forward jumps */ + const int backward_trigger = 10; /* backward jump must be >= this many seconds before we adjust */ + time_t real_time = system_time + now_adj; - if (real_time > now) + if (real_time > now) { - const time_t overshoot = real_time - now - 1; - if (overshoot > forward_threshold && now_adj >= overshoot) + const time_t overshoot = real_time - now - 1; + if (overshoot > forward_threshold && now_adj >= overshoot) { - now_adj -= overshoot; - real_time -= overshoot; + now_adj -= overshoot; + real_time -= overshoot; } - now = real_time; + now = real_time; + } + else if (real_time < now - backward_trigger) + { + now_adj += (now - real_time); } - else if (real_time < now - backward_trigger) - now_adj += (now - real_time); } void -update_now_usec (struct timeval *tv) +update_now_usec(struct timeval *tv) { - const time_t last = now; - update_now (tv->tv_sec); - if (now > last || (now == last && tv->tv_usec > now_usec)) - now_usec = tv->tv_usec; + const time_t last = now; + update_now(tv->tv_sec); + if (now > last || (now == last && tv->tv_usec > now_usec)) + { + now_usec = tv->tv_usec; + } } #endif /* TIME_BACKTRACK_PROTECTION */ -/* +/* * Return a numerical string describing a struct timeval. */ const char * -tv_string (const struct timeval *tv, struct gc_arena *gc) +tv_string(const struct timeval *tv, struct gc_arena *gc) { - struct buffer out = alloc_buf_gc (64, gc); - buf_printf (&out, "[%d/%d]", - (int) tv->tv_sec, - (int )tv->tv_usec); - return BSTR (&out); + struct buffer out = alloc_buf_gc(64, gc); + buf_printf(&out, "[%d/%d]", + (int) tv->tv_sec, + (int )tv->tv_usec); + return BSTR(&out); } -/* +/* * Return an ascii string describing an absolute * date/time in a struct timeval. - * + * */ const char * -tv_string_abs (const struct timeval *tv, struct gc_arena *gc) +tv_string_abs(const struct timeval *tv, struct gc_arena *gc) { - return time_string ((time_t) tv->tv_sec, - (int) tv->tv_usec, - true, - gc); + return time_string((time_t) tv->tv_sec, + (int) tv->tv_usec, + true, + gc); } /* format a time_t as ascii, or use current time if 0 */ const char * -time_string (time_t t, int usec, bool show_usec, struct gc_arena *gc) +time_string(time_t t, int usec, bool show_usec, struct gc_arena *gc) { - struct buffer out = alloc_buf_gc (64, gc); - struct timeval tv; + struct buffer out = alloc_buf_gc(64, gc); + struct timeval tv; - if (t) + if (t) { - tv.tv_sec = t; - tv.tv_usec = usec; + tv.tv_sec = t; + tv.tv_usec = usec; } - else + else { - gettimeofday (&tv, NULL); + gettimeofday(&tv, NULL); } - t = tv.tv_sec; - buf_printf (&out, "%s", ctime(&t)); - buf_rmtail (&out, '\n'); + t = tv.tv_sec; + buf_printf(&out, "%s", ctime(&t)); + buf_rmtail(&out, '\n'); - if (show_usec && tv.tv_usec) - buf_printf (&out, " us=%d", (int)tv.tv_usec); + if (show_usec && tv.tv_usec) + { + buf_printf(&out, " us=%d", (int)tv.tv_usec); + } - return BSTR (&out); + return BSTR(&out); } /* @@ -141,60 +147,62 @@ time_string (time_t t, int usec, bool show_usec, struct gc_arena *gc) */ struct frequency_limit * -frequency_limit_init (int max, int per) +frequency_limit_init(int max, int per) { - struct frequency_limit *f; + struct frequency_limit *f; - ASSERT (max >= 0 && per >= 0); + ASSERT(max >= 0 && per >= 0); - ALLOC_OBJ (f, struct frequency_limit); - f->max = max; - f->per = per; - f->n = 0; - f->reset = 0; - return f; + ALLOC_OBJ(f, struct frequency_limit); + f->max = max; + f->per = per; + f->n = 0; + f->reset = 0; + return f; } void -frequency_limit_free (struct frequency_limit *f) +frequency_limit_free(struct frequency_limit *f) { - free (f); + free(f); } bool -frequency_limit_event_allowed (struct frequency_limit *f) +frequency_limit_event_allowed(struct frequency_limit *f) { - if (f->per) + if (f->per) + { + bool ret; + if (now >= f->reset + f->per) + { + f->reset = now; + f->n = 0; + } + ret = (++f->n <= f->max); + return ret; + } + else { - bool ret; - if (now >= f->reset + f->per) - { - f->reset = now; - f->n = 0; - } - ret = (++f->n <= f->max); - return ret; + return true; } - else - return true; } #ifdef TIME_TEST void -time_test (void) +time_test(void) { - struct timeval tv; - time_t t; - int i; - for (i = 0; i < 10000; ++i) + struct timeval tv; + time_t t; + int i; + for (i = 0; i < 10000; ++i) { - t = time(NULL); - gettimeofday (&tv, NULL); + t = time(NULL); + gettimeofday(&tv, NULL); #if 1 - msg (M_INFO, "t=%u s=%u us=%u", - (unsigned int)t, - (unsigned int)tv.tv_sec, - (unsigned int)tv.tv_usec); + msg(M_INFO, "t=%u s=%u us=%u", + (unsigned int)t, + (unsigned int)tv.tv_sec, + (unsigned int)tv.tv_usec); #endif } } diff --git a/src/openvpn/otime.h b/src/openvpn/otime.h index c0b0f38c949..2b596ff2f72 100644 --- a/src/openvpn/otime.h +++ b/src/openvpn/otime.h @@ -31,205 +31,244 @@ struct frequency_limit { - int max; - int per; - int n; - time_t reset; + int max; + int per; + int n; + time_t reset; }; -struct frequency_limit *frequency_limit_init (int max, int per); -void frequency_limit_free (struct frequency_limit *f); -bool frequency_limit_event_allowed (struct frequency_limit *f); +struct frequency_limit *frequency_limit_init(int max, int per); + +void frequency_limit_free(struct frequency_limit *f); + +bool frequency_limit_event_allowed(struct frequency_limit *f); /* format a time_t as ascii, or use current time if 0 */ -const char* time_string (time_t t, int usec, bool show_usec, struct gc_arena *gc); +const char *time_string(time_t t, int usec, bool show_usec, struct gc_arena *gc); /* struct timeval functions */ -const char *tv_string (const struct timeval *tv, struct gc_arena *gc); -const char *tv_string_abs (const struct timeval *tv, struct gc_arena *gc); +const char *tv_string(const struct timeval *tv, struct gc_arena *gc); + +const char *tv_string_abs(const struct timeval *tv, struct gc_arena *gc); extern time_t now; /* updated frequently to time(NULL) */ -void time_test (void); +void time_test(void); #if TIME_BACKTRACK_PROTECTION -void update_now (const time_t system_time); +void update_now(const time_t system_time); extern time_t now_usec; -void update_now_usec (struct timeval *tv); +void update_now_usec(struct timeval *tv); static inline int -openvpn_gettimeofday (struct timeval *tv, void *tz) +openvpn_gettimeofday(struct timeval *tv, void *tz) { - const int status = gettimeofday (tv, tz); - if (!status) + const int status = gettimeofday(tv, tz); + if (!status) { - update_now_usec (tv); - tv->tv_sec = now; - tv->tv_usec = now_usec; + update_now_usec(tv); + tv->tv_sec = now; + tv->tv_usec = now_usec; } - return status; + return status; } static inline void -update_time (void) +update_time(void) { #ifdef _WIN32 - /* on _WIN32, gettimeofday is faster than time(NULL) */ - struct timeval tv; - openvpn_gettimeofday (&tv, NULL); + /* on _WIN32, gettimeofday is faster than time(NULL) */ + struct timeval tv; + openvpn_gettimeofday(&tv, NULL); #else - update_now (time (NULL)); + update_now(time(NULL)); #endif } #else /* !TIME_BACKTRACK_PROTECTION */ static inline void -update_time (void) +update_time(void) { #if defined(_WIN32) - /* on _WIN32, gettimeofday is faster than time(NULL) */ - struct timeval tv; - if (!gettimeofday (&tv, NULL)) + /* on _WIN32, gettimeofday is faster than time(NULL) */ + struct timeval tv; + if (!gettimeofday(&tv, NULL)) { - if (tv.tv_sec != now) - now = tv.tv_sec; + if (tv.tv_sec != now) + { + now = tv.tv_sec; + } + } +#else /* if defined(_WIN32) */ + const time_t real_time = time(NULL); + if (real_time != now) + { + now = real_time; } -#else - const time_t real_time = time (NULL); - if (real_time != now) - now = real_time; #endif } static inline int -openvpn_gettimeofday (struct timeval *tv, void *tz) +openvpn_gettimeofday(struct timeval *tv, void *tz) { - return gettimeofday (tv, tz); + return gettimeofday(tv, tz); } #endif /* TIME_BACKTRACK_PROTECTION */ static inline time_t -openvpn_time (time_t *t) +openvpn_time(time_t *t) { - update_time (); - if (t) - *t = now; - return now; + update_time(); + if (t) + { + *t = now; + } + return now; } static inline void -tv_clear (struct timeval *tv) +tv_clear(struct timeval *tv) { - tv->tv_sec = 0; - tv->tv_usec = 0; + tv->tv_sec = 0; + tv->tv_usec = 0; } static inline bool -tv_defined (const struct timeval *tv) +tv_defined(const struct timeval *tv) { - return tv->tv_sec > 0 && tv->tv_usec > 0; + return tv->tv_sec > 0 && tv->tv_usec > 0; } /* return tv1 - tv2 in usec, constrained by max_seconds */ static inline int -tv_subtract (const struct timeval *tv1, const struct timeval *tv2, const unsigned int max_seconds) +tv_subtract(const struct timeval *tv1, const struct timeval *tv2, const unsigned int max_seconds) { - const int max_usec = max_seconds * 1000000; - const int sec_diff = tv1->tv_sec - tv2->tv_sec; - - if (sec_diff > ((int)max_seconds + 10)) - return max_usec; - else if (sec_diff < -((int)max_seconds + 10)) - return -max_usec; - return constrain_int (sec_diff * 1000000 + (tv1->tv_usec - tv2->tv_usec), -max_usec, max_usec); + const int max_usec = max_seconds * 1000000; + const int sec_diff = tv1->tv_sec - tv2->tv_sec; + + if (sec_diff > ((int)max_seconds + 10)) + { + return max_usec; + } + else if (sec_diff < -((int)max_seconds + 10)) + { + return -max_usec; + } + return constrain_int(sec_diff * 1000000 + (tv1->tv_usec - tv2->tv_usec), -max_usec, max_usec); } static inline void -tv_add (struct timeval *dest, const struct timeval *src) +tv_add(struct timeval *dest, const struct timeval *src) { - dest->tv_sec += src->tv_sec; - dest->tv_usec += src->tv_usec; - dest->tv_sec += (dest->tv_usec >> 20); - dest->tv_usec &= 0x000FFFFF; - if (dest->tv_usec >= 1000000) + dest->tv_sec += src->tv_sec; + dest->tv_usec += src->tv_usec; + dest->tv_sec += (dest->tv_usec >> 20); + dest->tv_usec &= 0x000FFFFF; + if (dest->tv_usec >= 1000000) { - dest->tv_usec -= 1000000; - dest->tv_sec += 1; - } + dest->tv_usec -= 1000000; + dest->tv_sec += 1; + } } static inline bool -tv_lt (const struct timeval *t1, const struct timeval *t2) +tv_lt(const struct timeval *t1, const struct timeval *t2) { - if (t1->tv_sec < t2->tv_sec) - return true; - else if (t1->tv_sec > t2->tv_sec) - return false; - else - return t1->tv_usec < t2->tv_usec; + if (t1->tv_sec < t2->tv_sec) + { + return true; + } + else if (t1->tv_sec > t2->tv_sec) + { + return false; + } + else + { + return t1->tv_usec < t2->tv_usec; + } } static inline bool -tv_le (const struct timeval *t1, const struct timeval *t2) +tv_le(const struct timeval *t1, const struct timeval *t2) { - if (t1->tv_sec < t2->tv_sec) - return true; - else if (t1->tv_sec > t2->tv_sec) - return false; - else - return t1->tv_usec <= t2->tv_usec; + if (t1->tv_sec < t2->tv_sec) + { + return true; + } + else if (t1->tv_sec > t2->tv_sec) + { + return false; + } + else + { + return t1->tv_usec <= t2->tv_usec; + } } static inline bool -tv_ge (const struct timeval *t1, const struct timeval *t2) +tv_ge(const struct timeval *t1, const struct timeval *t2) { - if (t1->tv_sec > t2->tv_sec) - return true; - else if (t1->tv_sec < t2->tv_sec) - return false; - else - return t1->tv_usec >= t2->tv_usec; + if (t1->tv_sec > t2->tv_sec) + { + return true; + } + else if (t1->tv_sec < t2->tv_sec) + { + return false; + } + else + { + return t1->tv_usec >= t2->tv_usec; + } } static inline bool -tv_gt (const struct timeval *t1, const struct timeval *t2) +tv_gt(const struct timeval *t1, const struct timeval *t2) { - if (t1->tv_sec > t2->tv_sec) - return true; - else if (t1->tv_sec < t2->tv_sec) - return false; - else - return t1->tv_usec > t2->tv_usec; + if (t1->tv_sec > t2->tv_sec) + { + return true; + } + else if (t1->tv_sec < t2->tv_sec) + { + return false; + } + else + { + return t1->tv_usec > t2->tv_usec; + } } static inline bool -tv_eq (const struct timeval *t1, const struct timeval *t2) +tv_eq(const struct timeval *t1, const struct timeval *t2) { - return t1->tv_sec == t2->tv_sec && t1->tv_usec == t2->tv_usec; + return t1->tv_sec == t2->tv_sec && t1->tv_usec == t2->tv_usec; } static inline void -tv_delta (struct timeval *dest, const struct timeval *t1, const struct timeval *t2) +tv_delta(struct timeval *dest, const struct timeval *t1, const struct timeval *t2) { - int sec = t2->tv_sec - t1->tv_sec; - int usec = t2->tv_usec - t1->tv_usec; + int sec = t2->tv_sec - t1->tv_sec; + int usec = t2->tv_usec - t1->tv_usec; - while (usec < 0) + while (usec < 0) { - usec += 1000000; - sec -= 1; + usec += 1000000; + sec -= 1; } - if (sec < 0) - usec = sec = 0; + if (sec < 0) + { + usec = sec = 0; + } - dest->tv_sec = sec; - dest->tv_usec = usec; + dest->tv_sec = sec; + dest->tv_usec = usec; } #define TV_WITHIN_SIGMA_MAX_SEC 600 @@ -239,10 +278,10 @@ tv_delta (struct timeval *dest, const struct timeval *t1, const struct timeval * * Is t1 and t2 within sigma microseconds of each other? */ static inline bool -tv_within_sigma (const struct timeval *t1, const struct timeval *t2, unsigned int sigma) +tv_within_sigma(const struct timeval *t1, const struct timeval *t2, unsigned int sigma) { - const int delta = tv_subtract (t1, t2, TV_WITHIN_SIGMA_MAX_SEC); /* sigma should be less than 10 minutes */ - return -(int)sigma <= delta && delta <= (int)sigma; + const int delta = tv_subtract(t1, t2, TV_WITHIN_SIGMA_MAX_SEC); /* sigma should be less than 10 minutes */ + return -(int)sigma <= delta && delta <= (int)sigma; } /* @@ -250,15 +289,19 @@ tv_within_sigma (const struct timeval *t1, const struct timeval *t2, unsigned in * called again. */ static inline void -interval_earliest_wakeup (interval_t *wakeup, time_t at, time_t current) { - if (at > current) +interval_earliest_wakeup(interval_t *wakeup, time_t at, time_t current) { + if (at > current) { - const interval_t delta = (interval_t) (at - current); - if (delta < *wakeup) - *wakeup = delta; - if (*wakeup < 0) - *wakeup = 0; + const interval_t delta = (interval_t) (at - current); + if (delta < *wakeup) + { + *wakeup = delta; + } + if (*wakeup < 0) + { + *wakeup = 0; + } } } -#endif +#endif /* ifndef OTIME_H */ diff --git a/src/openvpn/packet_id.c b/src/openvpn/packet_id.c index 987451929c7..64d19c59d97 100644 --- a/src/openvpn/packet_id.c +++ b/src/openvpn/packet_id.c @@ -56,103 +56,111 @@ #define SEQ_UNSEEN ((time_t)0) #define SEQ_EXPIRED ((time_t)1) -static void packet_id_debug_print (int msglevel, - const struct packet_id_rec *p, - const struct packet_id_net *pin, - const char *message, - int value); +static void packet_id_debug_print(int msglevel, + const struct packet_id_rec *p, + const struct packet_id_net *pin, + const char *message, + int value); static inline void -packet_id_debug (int msglevel, - const struct packet_id_rec *p, - const struct packet_id_net *pin, - const char *message, - int value) +packet_id_debug(int msglevel, + const struct packet_id_rec *p, + const struct packet_id_net *pin, + const char *message, + int value) { #ifdef ENABLE_DEBUG - if (unlikely(check_debug_level(msglevel))) - packet_id_debug_print (msglevel, p, pin, message, value); + if (unlikely(check_debug_level(msglevel))) + { + packet_id_debug_print(msglevel, p, pin, message, value); + } #endif } void -packet_id_init (struct packet_id *p, int seq_backtrack, int time_backtrack, const char *name, int unit) +packet_id_init(struct packet_id *p, int seq_backtrack, int time_backtrack, const char *name, int unit) { - dmsg (D_PID_DEBUG, "PID packet_id_init seq_backtrack=%d time_backtrack=%d", - seq_backtrack, - time_backtrack); + dmsg(D_PID_DEBUG, "PID packet_id_init seq_backtrack=%d time_backtrack=%d", + seq_backtrack, + time_backtrack); - ASSERT (p); - CLEAR (*p); + ASSERT(p); + CLEAR(*p); - p->rec.name = name; - p->rec.unit = unit; - if (seq_backtrack) + p->rec.name = name; + p->rec.unit = unit; + if (seq_backtrack) { - ASSERT (MIN_SEQ_BACKTRACK <= seq_backtrack && seq_backtrack <= MAX_SEQ_BACKTRACK); - ASSERT (MIN_TIME_BACKTRACK <= time_backtrack && time_backtrack <= MAX_TIME_BACKTRACK); - CIRC_LIST_ALLOC (p->rec.seq_list, struct seq_list, seq_backtrack); - p->rec.seq_backtrack = seq_backtrack; - p->rec.time_backtrack = time_backtrack; + ASSERT(MIN_SEQ_BACKTRACK <= seq_backtrack && seq_backtrack <= MAX_SEQ_BACKTRACK); + ASSERT(MIN_TIME_BACKTRACK <= time_backtrack && time_backtrack <= MAX_TIME_BACKTRACK); + CIRC_LIST_ALLOC(p->rec.seq_list, struct seq_list, seq_backtrack); + p->rec.seq_backtrack = seq_backtrack; + p->rec.time_backtrack = time_backtrack; } - p->rec.initialized = true; + p->rec.initialized = true; } void -packet_id_free (struct packet_id *p) +packet_id_free(struct packet_id *p) { - if (p) + if (p) { - dmsg (D_PID_DEBUG, "PID packet_id_free"); - if (p->rec.seq_list) - free (p->rec.seq_list); - CLEAR (*p); + dmsg(D_PID_DEBUG, "PID packet_id_free"); + if (p->rec.seq_list) + { + free(p->rec.seq_list); + } + CLEAR(*p); } } void -packet_id_add (struct packet_id_rec *p, const struct packet_id_net *pin) +packet_id_add(struct packet_id_rec *p, const struct packet_id_net *pin) { - const time_t local_now = now; - if (p->seq_list) + const time_t local_now = now; + if (p->seq_list) { - packet_id_type diff; - - /* - * If time value increases, start a new - * sequence number sequence. - */ - if (!CIRC_LIST_SIZE (p->seq_list) - || pin->time > p->time - || (pin->id >= (packet_id_type)p->seq_backtrack - && pin->id - (packet_id_type)p->seq_backtrack > p->id)) - { - p->time = pin->time; - p->id = 0; - if (pin->id > (packet_id_type)p->seq_backtrack) - p->id = pin->id - (packet_id_type)p->seq_backtrack; - CIRC_LIST_RESET (p->seq_list); - } - - while (p->id < pin->id + packet_id_type diff; + + /* + * If time value increases, start a new + * sequence number sequence. + */ + if (!CIRC_LIST_SIZE(p->seq_list) + || pin->time > p->time + || (pin->id >= (packet_id_type)p->seq_backtrack + && pin->id - (packet_id_type)p->seq_backtrack > p->id)) + { + p->time = pin->time; + p->id = 0; + if (pin->id > (packet_id_type)p->seq_backtrack) + { + p->id = pin->id - (packet_id_type)p->seq_backtrack; + } + CIRC_LIST_RESET(p->seq_list); + } + + while (p->id < pin->id #ifdef PID_SIMULATE_BACKTRACK - || (get_random() % 64) < 31 + || (get_random() % 64) < 31 #endif - ) - { - CIRC_LIST_PUSH (p->seq_list, SEQ_UNSEEN); - ++p->id; - } - - diff = p->id - pin->id; - if (diff < (packet_id_type) CIRC_LIST_SIZE (p->seq_list) - && local_now > SEQ_EXPIRED) - CIRC_LIST_ITEM (p->seq_list, diff) = local_now; + ) + { + CIRC_LIST_PUSH(p->seq_list, SEQ_UNSEEN); + ++p->id; + } + + diff = p->id - pin->id; + if (diff < (packet_id_type) CIRC_LIST_SIZE(p->seq_list) + && local_now > SEQ_EXPIRED) + { + CIRC_LIST_ITEM(p->seq_list, diff) = local_now; + } } - else + else { - p->time = pin->time; - p->id = pin->id; + p->time = pin->time; + p->id = pin->id; } } @@ -162,25 +170,31 @@ packet_id_add (struct packet_id_rec *p, const struct packet_id_net *pin) * time_backtrack. */ void -packet_id_reap (struct packet_id_rec *p) +packet_id_reap(struct packet_id_rec *p) { - const time_t local_now = now; - if (p->time_backtrack) + const time_t local_now = now; + if (p->time_backtrack) { - int i; - bool expire = false; - for (i = 0; i < CIRC_LIST_SIZE (p->seq_list); ++i) - { - const time_t t = CIRC_LIST_ITEM (p->seq_list, i); - if (t == SEQ_EXPIRED) - break; - if (!expire && t && t + p->time_backtrack < local_now) - expire = true; - if (expire) - CIRC_LIST_ITEM (p->seq_list, i) = SEQ_EXPIRED; - } + int i; + bool expire = false; + for (i = 0; i < CIRC_LIST_SIZE(p->seq_list); ++i) + { + const time_t t = CIRC_LIST_ITEM(p->seq_list, i); + if (t == SEQ_EXPIRED) + { + break; + } + if (!expire && t && t + p->time_backtrack < local_now) + { + expire = true; + } + if (expire) + { + CIRC_LIST_ITEM(p->seq_list, i) = SEQ_EXPIRED; + } + } } - p->last_reap = local_now; + p->last_reap = local_now; } /* @@ -188,82 +202,96 @@ packet_id_reap (struct packet_id_rec *p) * it is a replay. */ bool -packet_id_test (struct packet_id_rec *p, - const struct packet_id_net *pin) +packet_id_test(struct packet_id_rec *p, + const struct packet_id_net *pin) { - packet_id_type diff; + packet_id_type diff; - packet_id_debug (D_PID_DEBUG, p, pin, "PID_TEST", 0); - - ASSERT (p->initialized); + packet_id_debug(D_PID_DEBUG, p, pin, "PID_TEST", 0); - if (!pin->id) - return false; + ASSERT(p->initialized); + + if (!pin->id) + { + return false; + } - if (p->seq_backtrack) + if (p->seq_backtrack) { - /* - * In backtrack mode, we allow packet reordering subject - * to the seq_backtrack and time_backtrack constraints. - * - * This mode is used with UDP. - */ - if (pin->time == p->time) - { - /* is packet-id greater than any one we've seen yet? */ - if (pin->id > p->id) - return true; - - /* check packet-id sliding window for original/replay status */ - diff = p->id - pin->id; - - /* keep track of maximum backtrack seen for debugging purposes */ - if ((int)diff > p->max_backtrack_stat) - { - p->max_backtrack_stat = (int)diff; - packet_id_debug (D_PID_DEBUG_LOW, p, pin, "PID_ERR replay-window backtrack occurred", p->max_backtrack_stat); - } - - if (diff >= (packet_id_type) CIRC_LIST_SIZE (p->seq_list)) - { - packet_id_debug (D_PID_DEBUG_LOW, p, pin, "PID_ERR large diff", diff); - return false; - } - - { - const time_t v = CIRC_LIST_ITEM (p->seq_list, diff); - if (v == 0) - return true; - else - { - /* raised from D_PID_DEBUG_LOW to reduce verbosity */ - packet_id_debug (D_PID_DEBUG_MEDIUM, p, pin, "PID_ERR replay", diff); - return false; - } - } - } - else if (pin->time < p->time) /* if time goes back, reject */ - { - packet_id_debug (D_PID_DEBUG_LOW, p, pin, "PID_ERR time backtrack", 0); - return false; - } - else /* time moved forward */ - return true; + /* + * In backtrack mode, we allow packet reordering subject + * to the seq_backtrack and time_backtrack constraints. + * + * This mode is used with UDP. + */ + if (pin->time == p->time) + { + /* is packet-id greater than any one we've seen yet? */ + if (pin->id > p->id) + { + return true; + } + + /* check packet-id sliding window for original/replay status */ + diff = p->id - pin->id; + + /* keep track of maximum backtrack seen for debugging purposes */ + if ((int)diff > p->max_backtrack_stat) + { + p->max_backtrack_stat = (int)diff; + packet_id_debug(D_PID_DEBUG_LOW, p, pin, "PID_ERR replay-window backtrack occurred", p->max_backtrack_stat); + } + + if (diff >= (packet_id_type) CIRC_LIST_SIZE(p->seq_list)) + { + packet_id_debug(D_PID_DEBUG_LOW, p, pin, "PID_ERR large diff", diff); + return false; + } + + { + const time_t v = CIRC_LIST_ITEM(p->seq_list, diff); + if (v == 0) + { + return true; + } + else + { + /* raised from D_PID_DEBUG_LOW to reduce verbosity */ + packet_id_debug(D_PID_DEBUG_MEDIUM, p, pin, "PID_ERR replay", diff); + return false; + } + } + } + else if (pin->time < p->time) /* if time goes back, reject */ + { + packet_id_debug(D_PID_DEBUG_LOW, p, pin, "PID_ERR time backtrack", 0); + return false; + } + else /* time moved forward */ + { + return true; + } } - else + else { - /* - * In non-backtrack mode, all sequence number series must - * begin at some number n > 0 and must increment linearly without gaps. - * - * This mode is used with TCP. - */ - if (pin->time == p->time) - return !p->id || pin->id == p->id + 1; - else if (pin->time < p->time) /* if time goes back, reject */ - return false; - else /* time moved forward */ - return pin->id == 1; + /* + * In non-backtrack mode, all sequence number series must + * begin at some number n > 0 and must increment linearly without gaps. + * + * This mode is used with TCP. + */ + if (pin->time == p->time) + { + return !p->id || pin->id == p->id + 1; + } + else if (pin->time < p->time) /* if time goes back, reject */ + { + return false; + } + else /* time moved forward */ + { + return pin->id == 1; + } } } @@ -273,333 +301,371 @@ packet_id_test (struct packet_id_rec *p, */ bool -packet_id_read (struct packet_id_net *pin, struct buffer *buf, bool long_form) +packet_id_read(struct packet_id_net *pin, struct buffer *buf, bool long_form) { - packet_id_type net_id; - net_time_t net_time; + packet_id_type net_id; + net_time_t net_time; - pin->id = 0; - pin->time = 0; + pin->id = 0; + pin->time = 0; - if (!buf_read (buf, &net_id, sizeof (net_id))) - return false; - pin->id = ntohpid (net_id); - if (long_form) + if (!buf_read(buf, &net_id, sizeof(net_id))) { - if (!buf_read (buf, &net_time, sizeof (net_time))) - return false; - pin->time = ntohtime (net_time); + return false; } - return true; + pin->id = ntohpid(net_id); + if (long_form) + { + if (!buf_read(buf, &net_time, sizeof(net_time))) + { + return false; + } + pin->time = ntohtime(net_time); + } + return true; } bool -packet_id_write (const struct packet_id_net *pin, struct buffer *buf, bool long_form, bool prepend) +packet_id_write(const struct packet_id_net *pin, struct buffer *buf, bool long_form, bool prepend) { - packet_id_type net_id = htonpid (pin->id); - net_time_t net_time = htontime (pin->time); + packet_id_type net_id = htonpid(pin->id); + net_time_t net_time = htontime(pin->time); - if (prepend) + if (prepend) { - if (long_form) - { - if (!buf_write_prepend (buf, &net_time, sizeof (net_time))) - return false; - } - if (!buf_write_prepend (buf, &net_id, sizeof (net_id))) - return false; + if (long_form) + { + if (!buf_write_prepend(buf, &net_time, sizeof(net_time))) + { + return false; + } + } + if (!buf_write_prepend(buf, &net_id, sizeof(net_id))) + { + return false; + } } - else + else { - if (!buf_write (buf, &net_id, sizeof (net_id))) - return false; - if (long_form) - { - if (!buf_write (buf, &net_time, sizeof (net_time))) - return false; - } + if (!buf_write(buf, &net_id, sizeof(net_id))) + { + return false; + } + if (long_form) + { + if (!buf_write(buf, &net_time, sizeof(net_time))) + { + return false; + } + } } - return true; + return true; } const char * -packet_id_net_print (const struct packet_id_net *pin, bool print_timestamp, struct gc_arena *gc) +packet_id_net_print(const struct packet_id_net *pin, bool print_timestamp, struct gc_arena *gc) { - struct buffer out = alloc_buf_gc (256, gc); + struct buffer out = alloc_buf_gc(256, gc); - buf_printf (&out, "[ #" packet_id_format, (packet_id_print_type)pin->id); - if (print_timestamp && pin->time) - buf_printf (&out, " / time = (" packet_id_format ") %s", - (packet_id_print_type)pin->time, - time_string (pin->time, 0, false, gc)); + buf_printf(&out, "[ #" packet_id_format, (packet_id_print_type)pin->id); + if (print_timestamp && pin->time) + { + buf_printf(&out, " / time = (" packet_id_format ") %s", + (packet_id_print_type)pin->time, + time_string(pin->time, 0, false, gc)); + } - buf_printf (&out, " ]"); - return BSTR (&out); + buf_printf(&out, " ]"); + return BSTR(&out); } /* initialize the packet_id_persist structure in a disabled state */ void -packet_id_persist_init (struct packet_id_persist *p) +packet_id_persist_init(struct packet_id_persist *p) { - p->filename = NULL; - p->fd = -1; - p->time = p->time_last_written = 0; - p->id = p->id_last_written = 0; + p->filename = NULL; + p->fd = -1; + p->time = p->time_last_written = 0; + p->id = p->id_last_written = 0; } /* close the file descriptor if it is open, and switch to disabled state */ void -packet_id_persist_close (struct packet_id_persist *p) +packet_id_persist_close(struct packet_id_persist *p) { - if (packet_id_persist_enabled (p)) + if (packet_id_persist_enabled(p)) { - if (close (p->fd)) - msg (D_PID_PERSIST | M_ERRNO, "Close error on --replay-persist file %s", p->filename); - packet_id_persist_init (p); + if (close(p->fd)) + { + msg(D_PID_PERSIST | M_ERRNO, "Close error on --replay-persist file %s", p->filename); + } + packet_id_persist_init(p); } } /* load persisted rec packet_id (time and id) only once from file, and set state to enabled */ void -packet_id_persist_load (struct packet_id_persist *p, const char *filename) +packet_id_persist_load(struct packet_id_persist *p, const char *filename) { - struct gc_arena gc = gc_new (); - if (!packet_id_persist_enabled (p)) + struct gc_arena gc = gc_new(); + if (!packet_id_persist_enabled(p)) { - /* open packet-id persist file for both read and write */ - p->fd = platform_open (filename, - O_CREAT | O_RDWR | O_BINARY, - S_IRUSR | S_IWUSR); - if (p->fd == -1) - { - msg (D_PID_PERSIST | M_ERRNO, - "Cannot open --replay-persist file %s for read/write", - filename); - } - else - { - struct packet_id_persist_file_image image; - ssize_t n; + /* open packet-id persist file for both read and write */ + p->fd = platform_open(filename, + O_CREAT | O_RDWR | O_BINARY, + S_IRUSR | S_IWUSR); + if (p->fd == -1) + { + msg(D_PID_PERSIST | M_ERRNO, + "Cannot open --replay-persist file %s for read/write", + filename); + } + else + { + struct packet_id_persist_file_image image; + ssize_t n; #if defined(HAVE_FLOCK) && defined(LOCK_EX) && defined(LOCK_NB) - if (flock (p->fd, LOCK_EX | LOCK_NB)) - msg (M_ERR, "Cannot obtain exclusive lock on --replay-persist file %s", filename); + if (flock(p->fd, LOCK_EX | LOCK_NB)) + { + msg(M_ERR, "Cannot obtain exclusive lock on --replay-persist file %s", filename); + } #endif - p->filename = filename; - n = read (p->fd, &image, sizeof(image)); - if (n == sizeof(image)) - { - p->time = p->time_last_written = image.time; - p->id = p->id_last_written = image.id; - dmsg (D_PID_PERSIST_DEBUG, "PID Persist Read from %s: %s", - p->filename, packet_id_persist_print (p, &gc)); - } - else if (n == -1) - { - msg (D_PID_PERSIST | M_ERRNO, - "Read error on --replay-persist file %s", - p->filename); - } - } + p->filename = filename; + n = read(p->fd, &image, sizeof(image)); + if (n == sizeof(image)) + { + p->time = p->time_last_written = image.time; + p->id = p->id_last_written = image.id; + dmsg(D_PID_PERSIST_DEBUG, "PID Persist Read from %s: %s", + p->filename, packet_id_persist_print(p, &gc)); + } + else if (n == -1) + { + msg(D_PID_PERSIST | M_ERRNO, + "Read error on --replay-persist file %s", + p->filename); + } + } } - gc_free (&gc); + gc_free(&gc); } /* save persisted rec packet_id (time and id) to file (only if enabled state) */ void -packet_id_persist_save (struct packet_id_persist *p) +packet_id_persist_save(struct packet_id_persist *p) { - if (packet_id_persist_enabled (p) && p->time && (p->time != p->time_last_written || - p->id != p->id_last_written)) + if (packet_id_persist_enabled(p) && p->time && (p->time != p->time_last_written + || p->id != p->id_last_written)) { - struct packet_id_persist_file_image image; - ssize_t n; - off_t seek_ret; - struct gc_arena gc = gc_new (); - - image.time = p->time; - image.id = p->id; - seek_ret = lseek(p->fd, (off_t)0, SEEK_SET); - if (seek_ret == (off_t)0) - { - n = write(p->fd, &image, sizeof(image)); - if (n == sizeof(image)) - { - p->time_last_written = p->time; - p->id_last_written = p->id; - dmsg (D_PID_PERSIST_DEBUG, "PID Persist Write to %s: %s", - p->filename, packet_id_persist_print (p, &gc)); - } - else - { - msg (D_PID_PERSIST | M_ERRNO, - "Cannot write to --replay-persist file %s", - p->filename); - } - } - else - { - msg (D_PID_PERSIST | M_ERRNO, - "Cannot seek to beginning of --replay-persist file %s", - p->filename); - } - gc_free (&gc); + struct packet_id_persist_file_image image; + ssize_t n; + off_t seek_ret; + struct gc_arena gc = gc_new(); + + image.time = p->time; + image.id = p->id; + seek_ret = lseek(p->fd, (off_t)0, SEEK_SET); + if (seek_ret == (off_t)0) + { + n = write(p->fd, &image, sizeof(image)); + if (n == sizeof(image)) + { + p->time_last_written = p->time; + p->id_last_written = p->id; + dmsg(D_PID_PERSIST_DEBUG, "PID Persist Write to %s: %s", + p->filename, packet_id_persist_print(p, &gc)); + } + else + { + msg(D_PID_PERSIST | M_ERRNO, + "Cannot write to --replay-persist file %s", + p->filename); + } + } + else + { + msg(D_PID_PERSIST | M_ERRNO, + "Cannot seek to beginning of --replay-persist file %s", + p->filename); + } + gc_free(&gc); } } /* transfer packet_id_persist -> packet_id */ void -packet_id_persist_load_obj (const struct packet_id_persist *p, struct packet_id *pid) +packet_id_persist_load_obj(const struct packet_id_persist *p, struct packet_id *pid) { - if (p && pid && packet_id_persist_enabled (p) && p->time) + if (p && pid && packet_id_persist_enabled(p) && p->time) { - pid->rec.time = p->time; - pid->rec.id = p->id; + pid->rec.time = p->time; + pid->rec.id = p->id; } } const char * -packet_id_persist_print (const struct packet_id_persist *p, struct gc_arena *gc) +packet_id_persist_print(const struct packet_id_persist *p, struct gc_arena *gc) { - struct buffer out = alloc_buf_gc (256, gc); + struct buffer out = alloc_buf_gc(256, gc); - buf_printf (&out, "["); + buf_printf(&out, "["); - if (packet_id_persist_enabled (p)) + if (packet_id_persist_enabled(p)) { - buf_printf (&out, " #" packet_id_format, (packet_id_print_type)p->id); - if (p->time) - buf_printf (&out, " / time = (" packet_id_format ") %s", - (packet_id_print_type)p->time, - time_string (p->time, 0, false, gc)); + buf_printf(&out, " #" packet_id_format, (packet_id_print_type)p->id); + if (p->time) + { + buf_printf(&out, " / time = (" packet_id_format ") %s", + (packet_id_print_type)p->time, + time_string(p->time, 0, false, gc)); + } } - buf_printf (&out, " ]"); - return (char *)out.data; + buf_printf(&out, " ]"); + return (char *)out.data; } #ifdef ENABLE_DEBUG static void -packet_id_debug_print (int msglevel, - const struct packet_id_rec *p, - const struct packet_id_net *pin, - const char *message, - int value) +packet_id_debug_print(int msglevel, + const struct packet_id_rec *p, + const struct packet_id_net *pin, + const char *message, + int value) { - struct gc_arena gc = gc_new (); - struct buffer out = alloc_buf_gc (256, &gc); - struct timeval tv; - const time_t prev_now = now; - const struct seq_list *sl = p->seq_list; - int i; - - CLEAR (tv); - gettimeofday (&tv, NULL); - - buf_printf (&out, "%s [%d]", message, value); - buf_printf (&out, " [%s-%d] [", p->name, p->unit); - for (i = 0; sl != NULL && i < sl->x_size; ++i) + struct gc_arena gc = gc_new(); + struct buffer out = alloc_buf_gc(256, &gc); + struct timeval tv; + const time_t prev_now = now; + const struct seq_list *sl = p->seq_list; + int i; + + CLEAR(tv); + gettimeofday(&tv, NULL); + + buf_printf(&out, "%s [%d]", message, value); + buf_printf(&out, " [%s-%d] [", p->name, p->unit); + for (i = 0; sl != NULL && i < sl->x_size; ++i) { - char c; - time_t v; - int diff; - - v = CIRC_LIST_ITEM(sl, i); - if (v == SEQ_UNSEEN) - c = '_'; - else if (v == SEQ_EXPIRED) - c = 'E'; - else - { - diff = (int) prev_now - v; - if (diff < 0) - c = 'N'; - else if (diff < 10) - c = '0' + diff; - else - c = '>'; - } - buf_printf(&out, "%c", c); + char c; + time_t v; + int diff; + + v = CIRC_LIST_ITEM(sl, i); + if (v == SEQ_UNSEEN) + { + c = '_'; + } + else if (v == SEQ_EXPIRED) + { + c = 'E'; + } + else + { + diff = (int) prev_now - v; + if (diff < 0) + { + c = 'N'; + } + else if (diff < 10) + { + c = '0' + diff; + } + else + { + c = '>'; + } + } + buf_printf(&out, "%c", c); } - buf_printf (&out, "] " time_format ":" packet_id_format, (time_type)p->time, (packet_id_print_type)p->id); - if (pin) - buf_printf (&out, " " time_format ":" packet_id_format, (time_type)pin->time, (packet_id_print_type)pin->id); - - buf_printf (&out, " t=" time_format "[%d]", - (time_type)prev_now, - (int)(prev_now - tv.tv_sec)); - - buf_printf (&out, " r=[%d,%d,%d,%d,%d]", - (int)(p->last_reap - tv.tv_sec), - p->seq_backtrack, - p->time_backtrack, - p->max_backtrack_stat, - (int)p->initialized); - if (sl != NULL) + buf_printf(&out, "] " time_format ":" packet_id_format, (time_type)p->time, (packet_id_print_type)p->id); + if (pin) + { + buf_printf(&out, " " time_format ":" packet_id_format, (time_type)pin->time, (packet_id_print_type)pin->id); + } + + buf_printf(&out, " t=" time_format "[%d]", + (time_type)prev_now, + (int)(prev_now - tv.tv_sec)); + + buf_printf(&out, " r=[%d,%d,%d,%d,%d]", + (int)(p->last_reap - tv.tv_sec), + p->seq_backtrack, + p->time_backtrack, + p->max_backtrack_stat, + (int)p->initialized); + if (sl != NULL) { - buf_printf (&out, " sl=[%d,%d,%d,%d]", - sl->x_head, - sl->x_size, - sl->x_cap, - sl->x_sizeof); + buf_printf(&out, " sl=[%d,%d,%d,%d]", + sl->x_head, + sl->x_size, + sl->x_cap, + sl->x_sizeof); } - msg (msglevel, "%s", BSTR(&out)); - gc_free (&gc); + msg(msglevel, "%s", BSTR(&out)); + gc_free(&gc); } -#endif +#endif /* ifdef ENABLE_DEBUG */ #ifdef PID_TEST void -packet_id_interactive_test () +packet_id_interactive_test() { - struct packet_id pid; - struct packet_id_net pin; - bool long_form; - bool count = 0; - bool test; - - const int seq_backtrack = 10; - const int time_backtrack = 10; - - packet_id_init (&pid, seq_backtrack, time_backtrack); - - while (true) { - char buf[80]; - if (!fgets(buf, sizeof(buf), stdin)) - break; - update_time (); - if (sscanf (buf, "%lu,%u", &pin.time, &pin.id) == 2) - { - packet_id_reap_test (&pid.rec); - test = packet_id_test (&pid.rec, &pin); - printf ("packet_id_test (" time_format ", " packet_id_format ") returned %d\n", - (time_type)pin.time, - (packet_id_print_type)pin.id, - test); - if (test) - packet_id_add (&pid.rec, &pin); - } - else - { - long_form = (count < 20); - packet_id_alloc_outgoing (&pid.send, &pin, long_form); - printf ("(" time_format "(" packet_id_format "), %d)\n", - (time_type)pin.time, - (packet_id_print_type)pin.id, - long_form); - if (pid.send.id == 10) - pid.send.id = 0xFFFFFFF8; - ++count; - } - } - packet_id_free (&pid); + struct packet_id pid; + struct packet_id_net pin; + bool long_form; + bool count = 0; + bool test; + + const int seq_backtrack = 10; + const int time_backtrack = 10; + + packet_id_init(&pid, seq_backtrack, time_backtrack); + + while (true) { + char buf[80]; + if (!fgets(buf, sizeof(buf), stdin)) + { + break; + } + update_time(); + if (sscanf(buf, "%lu,%u", &pin.time, &pin.id) == 2) + { + packet_id_reap_test(&pid.rec); + test = packet_id_test(&pid.rec, &pin); + printf("packet_id_test (" time_format ", " packet_id_format ") returned %d\n", + (time_type)pin.time, + (packet_id_print_type)pin.id, + test); + if (test) + { + packet_id_add(&pid.rec, &pin); + } + } + else + { + long_form = (count < 20); + packet_id_alloc_outgoing(&pid.send, &pin, long_form); + printf("(" time_format "(" packet_id_format "), %d)\n", + (time_type)pin.time, + (packet_id_print_type)pin.id, + long_form); + if (pid.send.id == 10) + { + pid.send.id = 0xFFFFFFF8; + } + ++count; + } + } + packet_id_free(&pid); } -#endif +#endif /* ifdef PID_TEST */ #endif /* ENABLE_CRYPTO */ diff --git a/src/openvpn/packet_id.h b/src/openvpn/packet_id.h index fb059b7d16f..d4019ff7c1d 100644 --- a/src/openvpn/packet_id.h +++ b/src/openvpn/packet_id.h @@ -71,7 +71,7 @@ typedef uint32_t net_time_t; /* convert a net_time_t in network order to a time_t in host order */ #define ntohtime(x) ((time_t)ntohl(x)) -#else +#else /* if 1 */ /* * DEBUGGING ONLY. @@ -89,7 +89,7 @@ typedef uint16_t net_time_t; #define htontime(x) htons((net_time_t)x) #define ntohtime(x) ((time_t)ntohs(x)) -#endif +#endif /* if 1 */ /* * Printf formats for special types @@ -124,7 +124,7 @@ typedef unsigned int packet_id_print_type; */ #define SEQ_REAP_INTERVAL 5 -CIRC_LIST (seq_list, time_t); +CIRC_LIST(seq_list, time_t); /* * This is the data structure we keep on the receiving side, @@ -133,16 +133,16 @@ CIRC_LIST (seq_list, time_t); */ struct packet_id_rec { - time_t last_reap; /* last call of packet_id_reap */ - time_t time; /* highest time stamp received */ - packet_id_type id; /* highest sequence number received */ - int seq_backtrack; /* set from --replay-window */ - int time_backtrack; /* set from --replay-window */ - int max_backtrack_stat; /* maximum backtrack seen so far */ - bool initialized; /* true if packet_id_init was called */ - struct seq_list *seq_list; /* packet-id "memory" */ - const char *name; - int unit; + time_t last_reap; /* last call of packet_id_reap */ + time_t time; /* highest time stamp received */ + packet_id_type id; /* highest sequence number received */ + int seq_backtrack; /* set from --replay-window */ + int time_backtrack; /* set from --replay-window */ + int max_backtrack_stat; /* maximum backtrack seen so far */ + bool initialized; /* true if packet_id_init was called */ + struct seq_list *seq_list; /* packet-id "memory" */ + const char *name; + int unit; }; /* @@ -151,18 +151,18 @@ struct packet_id_rec */ struct packet_id_persist { - const char *filename; - int fd; - time_t time; /* time stamp */ - packet_id_type id; /* sequence number */ - time_t time_last_written; - packet_id_type id_last_written; + const char *filename; + int fd; + time_t time; /* time stamp */ + packet_id_type id; /* sequence number */ + time_t time_last_written; + packet_id_type id_last_written; }; struct packet_id_persist_file_image { - time_t time; /* time stamp */ - packet_id_type id; /* sequence number */ + time_t time; /* time stamp */ + packet_id_type id; /* sequence number */ }; /* @@ -171,8 +171,8 @@ struct packet_id_persist_file_image */ struct packet_id_send { - packet_id_type id; - time_t time; + packet_id_type id; + time_t time; }; /* @@ -200,104 +200,108 @@ struct packet_id_send */ struct packet_id_net { - packet_id_type id; - time_t time; /* converted to net_time_t before transmission */ + packet_id_type id; + time_t time; /* converted to net_time_t before transmission */ }; struct packet_id { - struct packet_id_send send; - struct packet_id_rec rec; + struct packet_id_send send; + struct packet_id_rec rec; }; -void packet_id_init (struct packet_id *p, int seq_backtrack, int time_backtrack, const char *name, int unit); -void packet_id_free (struct packet_id *p); +void packet_id_init(struct packet_id *p, int seq_backtrack, int time_backtrack, const char *name, int unit); + +void packet_id_free(struct packet_id *p); /* should we accept an incoming packet id ? */ -bool packet_id_test (struct packet_id_rec *p, - const struct packet_id_net *pin); +bool packet_id_test(struct packet_id_rec *p, + const struct packet_id_net *pin); /* change our current state to reflect an accepted packet id */ -void packet_id_add (struct packet_id_rec *p, - const struct packet_id_net *pin); +void packet_id_add(struct packet_id_rec *p, + const struct packet_id_net *pin); -/* expire TIME_BACKTRACK sequence numbers */ -void packet_id_reap (struct packet_id_rec *p); +/* expire TIME_BACKTRACK sequence numbers */ +void packet_id_reap(struct packet_id_rec *p); /* * packet ID persistence */ /* initialize the packet_id_persist structure in a disabled state */ -void packet_id_persist_init (struct packet_id_persist *p); +void packet_id_persist_init(struct packet_id_persist *p); /* close the file descriptor if it is open, and switch to disabled state */ -void packet_id_persist_close (struct packet_id_persist *p); +void packet_id_persist_close(struct packet_id_persist *p); /* load persisted rec packet_id (time and id) only once from file, and set state to enabled */ -void packet_id_persist_load (struct packet_id_persist *p, const char *filename); +void packet_id_persist_load(struct packet_id_persist *p, const char *filename); /* save persisted rec packet_id (time and id) to file (only if enabled state) */ -void packet_id_persist_save (struct packet_id_persist *p); +void packet_id_persist_save(struct packet_id_persist *p); /* transfer packet_id_persist -> packet_id */ -void packet_id_persist_load_obj (const struct packet_id_persist *p, struct packet_id* pid); +void packet_id_persist_load_obj(const struct packet_id_persist *p, struct packet_id *pid); /* return an ascii string representing a packet_id_persist object */ -const char *packet_id_persist_print (const struct packet_id_persist *p, struct gc_arena *gc); +const char *packet_id_persist_print(const struct packet_id_persist *p, struct gc_arena *gc); /* * Read/write a packet ID to/from the buffer. Short form is sequence number * only. Long form is sequence number and timestamp. */ -bool packet_id_read (struct packet_id_net *pin, struct buffer *buf, bool long_form); -bool packet_id_write (const struct packet_id_net *pin, struct buffer *buf, bool long_form, bool prepend); +bool packet_id_read(struct packet_id_net *pin, struct buffer *buf, bool long_form); + +bool packet_id_write(const struct packet_id_net *pin, struct buffer *buf, bool long_form, bool prepend); /* * Inline functions. */ /** Is this struct packet_id initialized? */ -static inline bool packet_id_initialized (const struct packet_id *pid) +static inline bool +packet_id_initialized(const struct packet_id *pid) { - return pid->rec.initialized; + return pid->rec.initialized; } /* are we in enabled state? */ static inline bool -packet_id_persist_enabled (const struct packet_id_persist *p) +packet_id_persist_enabled(const struct packet_id_persist *p) { - return p->fd >= 0; + return p->fd >= 0; } /* transfer packet_id -> packet_id_persist */ static inline void -packet_id_persist_save_obj (struct packet_id_persist *p, const struct packet_id* pid) +packet_id_persist_save_obj(struct packet_id_persist *p, const struct packet_id *pid) { - if (packet_id_persist_enabled (p) && pid->rec.time) + if (packet_id_persist_enabled(p) && pid->rec.time) { - p->time = pid->rec.time; - p->id = pid->rec.id; + p->time = pid->rec.time; + p->id = pid->rec.id; } } -const char* packet_id_net_print(const struct packet_id_net *pin, bool print_timestamp, struct gc_arena *gc); +const char *packet_id_net_print(const struct packet_id_net *pin, bool print_timestamp, struct gc_arena *gc); #ifdef PID_TEST void packet_id_interactive_test(); + #endif static inline int -packet_id_size (bool long_form) +packet_id_size(bool long_form) { - return sizeof (packet_id_type) + (long_form ? sizeof (net_time_t) : 0); -} + return sizeof(packet_id_type) + (long_form ? sizeof(net_time_t) : 0); +} static inline bool -packet_id_close_to_wrapping (const struct packet_id_send *p) +packet_id_close_to_wrapping(const struct packet_id_send *p) { - return p->id >= PACKET_ID_WRAP_TRIGGER; + return p->id >= PACKET_ID_WRAP_TRIGGER; } /* @@ -306,38 +310,46 @@ packet_id_close_to_wrapping (const struct packet_id_send *p) * In long_form, a time_t is added as well. */ static inline void -packet_id_alloc_outgoing (struct packet_id_send *p, struct packet_id_net *pin, bool long_form) +packet_id_alloc_outgoing(struct packet_id_send *p, struct packet_id_net *pin, bool long_form) { - if (!p->time) - p->time = now; - pin->id = ++p->id; - if (!pin->id) + if (!p->time) + { + p->time = now; + } + pin->id = ++p->id; + if (!pin->id) { - ASSERT (long_form); - p->time = now; - pin->id = p->id = 1; + ASSERT(long_form); + p->time = now; + pin->id = p->id = 1; } - pin->time = p->time; + pin->time = p->time; } static inline bool -check_timestamp_delta (time_t remote, unsigned int max_delta) +check_timestamp_delta(time_t remote, unsigned int max_delta) { - unsigned int abs; - const time_t local_now = now; - - if (local_now >= remote) - abs = local_now - remote; - else - abs = remote - local_now; - return abs <= max_delta; + unsigned int abs; + const time_t local_now = now; + + if (local_now >= remote) + { + abs = local_now - remote; + } + else + { + abs = remote - local_now; + } + return abs <= max_delta; } static inline void -packet_id_reap_test (struct packet_id_rec *p) +packet_id_reap_test(struct packet_id_rec *p) { - if (p->last_reap + SEQ_REAP_INTERVAL <= now) - packet_id_reap (p); + if (p->last_reap + SEQ_REAP_INTERVAL <= now) + { + packet_id_reap(p); + } } #endif /* PACKET_ID_H */ diff --git a/src/openvpn/perf.c b/src/openvpn/perf.c index 910d171d896..e012eb4166f 100644 --- a/src/openvpn/perf.c +++ b/src/openvpn/perf.c @@ -40,260 +40,288 @@ #include "memdbg.h" static const char *metric_names[] = { - "PERF_BIO_READ_PLAINTEXT", - "PERF_BIO_WRITE_PLAINTEXT", - "PERF_BIO_READ_CIPHERTEXT", - "PERF_BIO_WRITE_CIPHERTEXT", - "PERF_TLS_MULTI_PROCESS", - "PERF_IO_WAIT", - "PERF_EVENT_LOOP", - "PERF_MULTI_CREATE_INSTANCE", - "PERF_MULTI_CLOSE_INSTANCE", - "PERF_MULTI_SHOW_STATS", - "PERF_MULTI_BCAST", - "PERF_MULTI_MCAST", - "PERF_SCRIPT", - "PERF_READ_IN_LINK", - "PERF_PROC_IN_LINK", - "PERF_READ_IN_TUN", - "PERF_PROC_IN_TUN", - "PERF_PROC_OUT_LINK", - "PERF_PROC_OUT_TUN", - "PERF_PROC_OUT_TUN_MTCP" + "PERF_BIO_READ_PLAINTEXT", + "PERF_BIO_WRITE_PLAINTEXT", + "PERF_BIO_READ_CIPHERTEXT", + "PERF_BIO_WRITE_CIPHERTEXT", + "PERF_TLS_MULTI_PROCESS", + "PERF_IO_WAIT", + "PERF_EVENT_LOOP", + "PERF_MULTI_CREATE_INSTANCE", + "PERF_MULTI_CLOSE_INSTANCE", + "PERF_MULTI_SHOW_STATS", + "PERF_MULTI_BCAST", + "PERF_MULTI_MCAST", + "PERF_SCRIPT", + "PERF_READ_IN_LINK", + "PERF_PROC_IN_LINK", + "PERF_READ_IN_TUN", + "PERF_PROC_IN_TUN", + "PERF_PROC_OUT_LINK", + "PERF_PROC_OUT_TUN", + "PERF_PROC_OUT_TUN_MTCP" }; struct perf { -# define PS_INITIAL 0 -# define PS_METER_RUNNING 1 -# define PS_METER_INTERRUPTED 2 - int state; - - struct timeval start; - double sofar; - double sum; - double max; - double count; +#define PS_INITIAL 0 +#define PS_METER_RUNNING 1 +#define PS_METER_INTERRUPTED 2 + int state; + + struct timeval start; + double sofar; + double sum; + double max; + double count; }; struct perf_set { - int stack_len; - int stack[STACK_N]; - struct perf perf[PERF_N]; + int stack_len; + int stack[STACK_N]; + struct perf perf[PERF_N]; }; static struct perf_set perf_set; -static void perf_print_state (int lev); +static void perf_print_state(int lev); static inline int -get_stack_index (int sdelta) +get_stack_index(int sdelta) { - const int sindex = perf_set.stack_len + sdelta; - if (sindex >= 0 && sindex < STACK_N) - return sindex; - else - return -1; + const int sindex = perf_set.stack_len + sdelta; + if (sindex >= 0 && sindex < STACK_N) + { + return sindex; + } + else + { + return -1; + } } static int -get_perf_index (int sdelta) +get_perf_index(int sdelta) { - const int sindex = get_stack_index (sdelta); - if (sindex >= 0) + const int sindex = get_stack_index(sdelta); + if (sindex >= 0) { - const int pindex = perf_set.stack[sindex]; - if (pindex >= 0 && pindex < PERF_N) - return pindex; - else - return -1; + const int pindex = perf_set.stack[sindex]; + if (pindex >= 0 && pindex < PERF_N) + { + return pindex; + } + else + { + return -1; + } + } + else + { + return -1; } - else - return -1; } static struct perf * -get_perf (int sdelta) +get_perf(int sdelta) { - const int pindex = get_perf_index (sdelta); - if (pindex >= 0) - return &perf_set.perf[pindex]; - else - return NULL; + const int pindex = get_perf_index(sdelta); + if (pindex >= 0) + { + return &perf_set.perf[pindex]; + } + else + { + return NULL; + } } static void -push_perf_index (int pindex) +push_perf_index(int pindex) { - const int sindex = get_stack_index (0); - const int newlen = get_stack_index (1); - if (sindex >= 0 && newlen >= 0 - && pindex >= 0 && pindex < PERF_N) + const int sindex = get_stack_index(0); + const int newlen = get_stack_index(1); + if (sindex >= 0 && newlen >= 0 + && pindex >= 0 && pindex < PERF_N) { - int i; - for (i = 0; i < sindex; ++i) - if (perf_set.stack[i] == pindex) - { - perf_print_state (M_INFO); - msg (M_FATAL, "PERF: push_perf_index %s failed", - metric_names [pindex]); - } - - perf_set.stack[sindex] = pindex; - perf_set.stack_len = newlen; + int i; + for (i = 0; i < sindex; ++i) + if (perf_set.stack[i] == pindex) + { + perf_print_state(M_INFO); + msg(M_FATAL, "PERF: push_perf_index %s failed", + metric_names [pindex]); + } + + perf_set.stack[sindex] = pindex; + perf_set.stack_len = newlen; + } + else + { + msg(M_FATAL, "PERF: push_perf_index: stack push error"); } - else - msg (M_FATAL, "PERF: push_perf_index: stack push error"); } static void -pop_perf_index (void) +pop_perf_index(void) { - const int newlen = get_stack_index (-1); - if (newlen >= 0) + const int newlen = get_stack_index(-1); + if (newlen >= 0) { - perf_set.stack_len = newlen; + perf_set.stack_len = newlen; + } + else + { + msg(M_FATAL, "PERF: pop_perf_index: stack pop error"); } - else - msg (M_FATAL, "PERF: pop_perf_index: stack pop error"); } static void -state_must_be (const struct perf *p, const int wanted) +state_must_be(const struct perf *p, const int wanted) { - if (p->state != wanted) - msg (M_FATAL, "PERF: bad state actual=%d wanted=%d", - p->state, - wanted); + if (p->state != wanted) + { + msg(M_FATAL, "PERF: bad state actual=%d wanted=%d", + p->state, + wanted); + } } static void -update_sofar (struct perf *p) +update_sofar(struct perf *p) { - struct timeval current; - ASSERT (!gettimeofday (¤t, NULL)); - p->sofar += (double) tv_subtract (¤t, &p->start, 600) / 1000000.0; - tv_clear (&p->start); + struct timeval current; + ASSERT(!gettimeofday(¤t, NULL)); + p->sofar += (double) tv_subtract(¤t, &p->start, 600) / 1000000.0; + tv_clear(&p->start); } static void -perf_start (struct perf *p) +perf_start(struct perf *p) { - state_must_be (p, PS_INITIAL); - ASSERT (!gettimeofday (&p->start, NULL)); - p->sofar = 0.0; - p->state = PS_METER_RUNNING; + state_must_be(p, PS_INITIAL); + ASSERT(!gettimeofday(&p->start, NULL)); + p->sofar = 0.0; + p->state = PS_METER_RUNNING; } static void -perf_stop (struct perf *p) +perf_stop(struct perf *p) { - state_must_be (p, PS_METER_RUNNING); - update_sofar (p); - p->sum += p->sofar; - if (p->sofar > p->max) - p->max = p->sofar; - p->count += 1.0; - p->sofar = 0.0; - p->state = PS_INITIAL; + state_must_be(p, PS_METER_RUNNING); + update_sofar(p); + p->sum += p->sofar; + if (p->sofar > p->max) + { + p->max = p->sofar; + } + p->count += 1.0; + p->sofar = 0.0; + p->state = PS_INITIAL; } static void -perf_interrupt (struct perf *p) +perf_interrupt(struct perf *p) { - state_must_be (p, PS_METER_RUNNING); - update_sofar (p); - p->state = PS_METER_INTERRUPTED; + state_must_be(p, PS_METER_RUNNING); + update_sofar(p); + p->state = PS_METER_INTERRUPTED; } static void -perf_resume (struct perf *p) +perf_resume(struct perf *p) { - state_must_be (p, PS_METER_INTERRUPTED); - ASSERT (!gettimeofday (&p->start, NULL)); - p->state = PS_METER_RUNNING; + state_must_be(p, PS_METER_INTERRUPTED); + ASSERT(!gettimeofday(&p->start, NULL)); + p->state = PS_METER_RUNNING; } void -perf_push (int type) +perf_push(int type) { - struct perf *prev; - struct perf *cur; + struct perf *prev; + struct perf *cur; - ASSERT (SIZE(metric_names) == PERF_N); - push_perf_index (type); + ASSERT(SIZE(metric_names) == PERF_N); + push_perf_index(type); - prev = get_perf (-2); - cur = get_perf (-1); + prev = get_perf(-2); + cur = get_perf(-1); - ASSERT (cur); + ASSERT(cur); - if (prev) - perf_interrupt (prev); - perf_start (cur); + if (prev) + { + perf_interrupt(prev); + } + perf_start(cur); } void -perf_pop (void) +perf_pop(void) { - struct perf *prev; - struct perf *cur; + struct perf *prev; + struct perf *cur; - prev = get_perf (-2); - cur = get_perf (-1); + prev = get_perf(-2); + cur = get_perf(-1); - ASSERT (cur); - perf_stop (cur); + ASSERT(cur); + perf_stop(cur); - if (prev) - perf_resume (prev); + if (prev) + { + perf_resume(prev); + } - pop_perf_index (); + pop_perf_index(); } void -perf_output_results (void) +perf_output_results(void) { - int i; - msg (M_INFO, "LATENCY PROFILE (mean and max are in milliseconds)"); - for (i = 0; i < PERF_N; ++i) + int i; + msg(M_INFO, "LATENCY PROFILE (mean and max are in milliseconds)"); + for (i = 0; i < PERF_N; ++i) { - struct perf *p = &perf_set.perf[i]; - if (p->count > 0.0) - { - const double mean = p->sum / p->count; - msg (M_INFO, "%s n=%.0f mean=%.3f max=%.3f", metric_names[i], p->count, mean*1000.0, p->max*1000.0); - } + struct perf *p = &perf_set.perf[i]; + if (p->count > 0.0) + { + const double mean = p->sum / p->count; + msg(M_INFO, "%s n=%.0f mean=%.3f max=%.3f", metric_names[i], p->count, mean*1000.0, p->max*1000.0); + } } } static void -perf_print_state (int lev) +perf_print_state(int lev) { - struct gc_arena gc = gc_new (); - int i; - msg (lev, "PERF STATE"); - msg (lev, "Stack:"); - for (i = 0; i < perf_set.stack_len; ++i) + struct gc_arena gc = gc_new(); + int i; + msg(lev, "PERF STATE"); + msg(lev, "Stack:"); + for (i = 0; i < perf_set.stack_len; ++i) { - const int j = perf_set.stack[i]; - const struct perf *p = &perf_set.perf[j]; - msg (lev, "[%d] %s state=%d start=%s sofar=%f sum=%f max=%f count=%f", - i, - metric_names[j], - p->state, - tv_string (&p->start, &gc), - p->sofar, - p->sum, - p->max, - p->count); + const int j = perf_set.stack[i]; + const struct perf *p = &perf_set.perf[j]; + msg(lev, "[%d] %s state=%d start=%s sofar=%f sum=%f max=%f count=%f", + i, + metric_names[j], + p->state, + tv_string(&p->start, &gc), + p->sofar, + p->sum, + p->max, + p->count); } - gc_free (&gc); + gc_free(&gc); } -#else +#else /* ifdef ENABLE_PERFORMANCE_METRICS */ #ifdef _MSC_VER /* Dummy function needed to avoid empty file compiler warning in Microsoft VC */ -static void dummy(void) {} -#endif +static void +dummy(void) { +} #endif +#endif /* ifdef ENABLE_PERFORMANCE_METRICS */ diff --git a/src/openvpn/perf.h b/src/openvpn/perf.h index c531d9c142f..f277b1e96df 100644 --- a/src/openvpn/perf.h +++ b/src/openvpn/perf.h @@ -67,16 +67,24 @@ */ #define STACK_N 64 -void perf_push (int type); -void perf_pop (void); -void perf_output_results (void); +void perf_push(int type); -#else +void perf_pop(void); -static inline void perf_push (int type) {} -static inline void perf_pop (void) {} -static inline void perf_output_results (void) {} +void perf_output_results(void); -#endif +#else /* ifdef ENABLE_PERFORMANCE_METRICS */ -#endif +static inline void +perf_push(int type) { +} +static inline void +perf_pop(void) { +} +static inline void +perf_output_results(void) { +} + +#endif /* ifdef ENABLE_PERFORMANCE_METRICS */ + +#endif /* ifndef PERF_H */ diff --git a/src/openvpn/pf-inline.h b/src/openvpn/pf-inline.h index 6b5dcb25575..beaae5c7e48 100644 --- a/src/openvpn/pf-inline.h +++ b/src/openvpn/pf-inline.h @@ -32,28 +32,33 @@ #define PCT_SRC 1 #define PCT_DEST 2 static inline bool -pf_c2c_test (const struct context *src, const struct context *dest, const char *prefix) +pf_c2c_test(const struct context *src, const struct context *dest, const char *prefix) { - bool pf_cn_test (struct pf_set *pfs, const struct tls_multi *tm, const int type, const char *prefix); - return (!src->c2.pf.enabled || pf_cn_test (src->c2.pf.pfs, dest->c2.tls_multi, PCT_DEST, prefix)) - && (!dest->c2.pf.enabled || pf_cn_test (dest->c2.pf.pfs, src->c2.tls_multi, PCT_SRC, prefix)); + bool pf_cn_test(struct pf_set *pfs, const struct tls_multi *tm, const int type, const char *prefix); + + return (!src->c2.pf.enabled || pf_cn_test(src->c2.pf.pfs, dest->c2.tls_multi, PCT_DEST, prefix)) + && (!dest->c2.pf.enabled || pf_cn_test(dest->c2.pf.pfs, src->c2.tls_multi, PCT_SRC, prefix)); } static inline bool -pf_addr_test (const struct context *src, const struct mroute_addr *dest, const char *prefix) +pf_addr_test(const struct context *src, const struct mroute_addr *dest, const char *prefix) { - bool pf_addr_test_dowork (const struct context *src, const struct mroute_addr *dest, const char *prefix); + bool pf_addr_test_dowork(const struct context *src, const struct mroute_addr *dest, const char *prefix); - if (src->c2.pf.enabled) - return pf_addr_test_dowork (src, dest, prefix); - else - return true; + if (src->c2.pf.enabled) + { + return pf_addr_test_dowork(src, dest, prefix); + } + else + { + return true; + } } static inline bool -pf_kill_test (const struct pf_set *pfs) +pf_kill_test(const struct pf_set *pfs) { - return pfs->kill; + return pfs->kill; } -#endif +#endif /* if defined(ENABLE_PF) && !defined(PF_INLINE_H) */ diff --git a/src/openvpn/pf.c b/src/openvpn/pf.c index a3208db1225..7db4ba97a80 100644 --- a/src/openvpn/pf.c +++ b/src/openvpn/pf.c @@ -41,285 +41,307 @@ #include "pf-inline.h" static void -pf_destroy (struct pf_set *pfs) +pf_destroy(struct pf_set *pfs) { - if (pfs) - { - if (pfs->cns.hash_table) - hash_free (pfs->cns.hash_table); - - { - struct pf_cn_elem *l = pfs->cns.list; - while (l) - { - struct pf_cn_elem *next = l->next; - free (l->rule.cn); - free (l); - l = next; - } - } - { - struct pf_subnet *l = pfs->sns.list; - while (l) - { - struct pf_subnet *next = l->next; - free (l); - l = next; - } - } - free (pfs); + if (pfs) + { + if (pfs->cns.hash_table) + { + hash_free(pfs->cns.hash_table); + } + + { + struct pf_cn_elem *l = pfs->cns.list; + while (l) + { + struct pf_cn_elem *next = l->next; + free(l->rule.cn); + free(l); + l = next; + } + } + { + struct pf_subnet *l = pfs->sns.list; + while (l) + { + struct pf_subnet *next = l->next; + free(l); + l = next; + } + } + free(pfs); } } static bool -add_client (const char *line, const char *prefix, const int line_num, struct pf_cn_elem ***next, const bool exclude) +add_client(const char *line, const char *prefix, const int line_num, struct pf_cn_elem ***next, const bool exclude) { - struct pf_cn_elem *e; - ALLOC_OBJ_CLEAR (e, struct pf_cn_elem); - e->rule.exclude = exclude; - e->rule.cn = string_alloc (line, NULL); - **next = e; - *next = &e->next; - return true; + struct pf_cn_elem *e; + ALLOC_OBJ_CLEAR(e, struct pf_cn_elem); + e->rule.exclude = exclude; + e->rule.cn = string_alloc(line, NULL); + **next = e; + *next = &e->next; + return true; } static bool -add_subnet (const char *line, const char *prefix, const int line_num, struct pf_subnet ***next, const bool exclude) +add_subnet(const char *line, const char *prefix, const int line_num, struct pf_subnet ***next, const bool exclude) { - struct in_addr network; - in_addr_t netmask = 0; - - if (strcmp (line, "unknown")) - { - int netbits = 32; - char *div = strchr (line, '/'); - - if (div) - { - *div++ = '\0'; - if (sscanf (div, "%d", &netbits) != 1) - { - msg (D_PF_INFO, "PF: %s/%d: bad '/n' subnet specifier: '%s'", prefix, line_num, div); - return false; - } - if (netbits < 0 || netbits > 32) - { - msg (D_PF_INFO, "PF: %s/%d: bad '/n' subnet specifier: must be between 0 and 32: '%s'", prefix, line_num, div); - return false; - } - } - - if (openvpn_inet_aton (line, &network) != OIA_IP) - { - msg (D_PF_INFO, "PF: %s/%d: bad network address: '%s'", prefix, line_num, line); - return false; - } - netmask = netbits_to_netmask (netbits); - if ((network.s_addr & htonl (netmask)) != network.s_addr) + struct in_addr network; + in_addr_t netmask = 0; + + if (strcmp(line, "unknown")) + { + int netbits = 32; + char *div = strchr(line, '/'); + + if (div) + { + *div++ = '\0'; + if (sscanf(div, "%d", &netbits) != 1) + { + msg(D_PF_INFO, "PF: %s/%d: bad '/n' subnet specifier: '%s'", prefix, line_num, div); + return false; + } + if (netbits < 0 || netbits > 32) + { + msg(D_PF_INFO, "PF: %s/%d: bad '/n' subnet specifier: must be between 0 and 32: '%s'", prefix, line_num, div); + return false; + } + } + + if (openvpn_inet_aton(line, &network) != OIA_IP) + { + msg(D_PF_INFO, "PF: %s/%d: bad network address: '%s'", prefix, line_num, line); + return false; + } + netmask = netbits_to_netmask(netbits); + if ((network.s_addr & htonl(netmask)) != network.s_addr) { - network.s_addr &= htonl (netmask); - msg (M_WARN, "WARNING: PF: %s/%d: incorrect subnet %s/%d changed to %s/%d", prefix, line_num, line, netbits, inet_ntoa (network), netbits); + network.s_addr &= htonl(netmask); + msg(M_WARN, "WARNING: PF: %s/%d: incorrect subnet %s/%d changed to %s/%d", prefix, line_num, line, netbits, inet_ntoa(network), netbits); } } - else + else { - /* match special "unknown" tag for addresses unrecognized by mroute */ - network.s_addr = htonl(0); - netmask = IPV4_NETMASK_HOST; + /* match special "unknown" tag for addresses unrecognized by mroute */ + network.s_addr = htonl(0); + netmask = IPV4_NETMASK_HOST; } - { - struct pf_subnet *e; - ALLOC_OBJ_CLEAR (e, struct pf_subnet); - e->rule.exclude = exclude; - e->rule.network = ntohl (network.s_addr); - e->rule.netmask = netmask; - **next = e; - *next = &e->next; - return true; - } + { + struct pf_subnet *e; + ALLOC_OBJ_CLEAR(e, struct pf_subnet); + e->rule.exclude = exclude; + e->rule.network = ntohl(network.s_addr); + e->rule.netmask = netmask; + **next = e; + *next = &e->next; + return true; + } } static uint32_t -cn_hash_function (const void *key, uint32_t iv) +cn_hash_function(const void *key, uint32_t iv) { - return hash_func ((uint8_t *)key, strlen ((char *)key) + 1, iv); + return hash_func((uint8_t *)key, strlen((char *)key) + 1, iv); } static bool -cn_compare_function (const void *key1, const void *key2) +cn_compare_function(const void *key1, const void *key2) { - return !strcmp((const char *)key1, (const char *)key2); + return !strcmp((const char *)key1, (const char *)key2); } static bool -genhash (struct pf_cn_set *cns, const char *prefix, const int n_clients) +genhash(struct pf_cn_set *cns, const char *prefix, const int n_clients) { - struct pf_cn_elem *e; - bool status = true; - int n_buckets = n_clients; - - if (n_buckets < 16) - n_buckets = 16; - cns->hash_table = hash_init (n_buckets, 0, cn_hash_function, cn_compare_function); - for (e = cns->list; e != NULL; e = e->next) - { - if (!hash_add (cns->hash_table, e->rule.cn, &e->rule, false)) - { - msg (D_PF_INFO, "PF: %s: duplicate common name in [clients] section: '%s'", prefix, e->rule.cn); - status = false; - } - } - - return status; + struct pf_cn_elem *e; + bool status = true; + int n_buckets = n_clients; + + if (n_buckets < 16) + { + n_buckets = 16; + } + cns->hash_table = hash_init(n_buckets, 0, cn_hash_function, cn_compare_function); + for (e = cns->list; e != NULL; e = e->next) + { + if (!hash_add(cns->hash_table, e->rule.cn, &e->rule, false)) + { + msg(D_PF_INFO, "PF: %s: duplicate common name in [clients] section: '%s'", prefix, e->rule.cn); + status = false; + } + } + + return status; } static struct pf_set * -pf_init (const struct buffer_list *bl, const char *prefix, const bool allow_kill) +pf_init(const struct buffer_list *bl, const char *prefix, const bool allow_kill) { -# define MODE_UNDEF 0 -# define MODE_CLIENTS 1 -# define MODE_SUBNETS 2 - int mode = MODE_UNDEF; - int line_num = 0; - int n_clients = 0; - int n_subnets = 0; - int n_errors = 0; - struct pf_set *pfs = NULL; - char line[PF_MAX_LINE_LEN]; - - ALLOC_OBJ_CLEAR (pfs, struct pf_set); - if (bl) - { - struct pf_cn_elem **cl = &pfs->cns.list; - struct pf_subnet **sl = &pfs->sns.list; - struct buffer_entry *be; - - for (be = bl->head; be != NULL; be = be->next) - { - ++line_num; - strncpynt (line, BSTR(&be->buf), sizeof(line)); - rm_trailing_chars (line, "\r\n\t "); - if (line[0] == '\0' || line[0] == '#') - ; - else if (line[0] == '+' || line[0] == '-') - { - bool exclude = (line[0] == '-'); - - if (line[1] =='\0') - { - msg (D_PF_INFO, "PF: %s/%d: no data after +/-: '%s'", prefix, line_num, line); - ++n_errors; - } - else if (mode == MODE_CLIENTS) - { - if (add_client (&line[1], prefix, line_num, &cl, exclude)) - ++n_clients; - else - ++n_errors; - } - else if (mode == MODE_SUBNETS) - { - if (add_subnet (&line[1], prefix, line_num, &sl, exclude)) - ++n_subnets; - else - ++n_errors; - } - else if (mode == MODE_UNDEF) - ; - else - { - ASSERT (0); - } - } - else if (line[0] == '[') - { - if (!strcasecmp (line, "[clients accept]")) - { - mode = MODE_CLIENTS; - pfs->cns.default_allow = true; - } - else if (!strcasecmp (line, "[clients drop]")) - { - mode = MODE_CLIENTS; - pfs->cns.default_allow = false; - } - else if (!strcasecmp (line, "[subnets accept]")) - { - mode = MODE_SUBNETS; - pfs->sns.default_allow = true; - } - else if (!strcasecmp (line, "[subnets drop]")) - { - mode = MODE_SUBNETS; - pfs->sns.default_allow = false; - } - else if (!strcasecmp (line, "[end]")) - goto done; - else if (allow_kill && !strcasecmp (line, "[kill]")) - goto kill; - else - { - mode = MODE_UNDEF; - msg (D_PF_INFO, "PF: %s/%d unknown tag: '%s'", prefix, line_num, line); - ++n_errors; - } - } - else - { - msg (D_PF_INFO, "PF: %s/%d line must begin with '+', '-', or '[' : '%s'", prefix, line_num, line); - ++n_errors; - } - } - ++n_errors; - msg (D_PF_INFO, "PF: %s: missing [end]", prefix); - } - else - { - msg (D_PF_INFO, "PF: %s: cannot open", prefix); - ++n_errors; - } - - done: - if (bl) - { - if (!n_errors) - { - if (!genhash (&pfs->cns, prefix, n_clients)) - ++n_errors; - } - if (n_errors) - msg (D_PF_INFO, "PF: %s rejected due to %d error(s)", prefix, n_errors); - } - if (n_errors) - { - pf_destroy (pfs); - pfs = NULL; - } - return pfs; - - kill: - pf_destroy (pfs); - ALLOC_OBJ_CLEAR (pfs, struct pf_set); - pfs->kill = true; - return pfs; +#define MODE_UNDEF 0 +#define MODE_CLIENTS 1 +#define MODE_SUBNETS 2 + int mode = MODE_UNDEF; + int line_num = 0; + int n_clients = 0; + int n_subnets = 0; + int n_errors = 0; + struct pf_set *pfs = NULL; + char line[PF_MAX_LINE_LEN]; + + ALLOC_OBJ_CLEAR(pfs, struct pf_set); + if (bl) + { + struct pf_cn_elem **cl = &pfs->cns.list; + struct pf_subnet **sl = &pfs->sns.list; + struct buffer_entry *be; + + for (be = bl->head; be != NULL; be = be->next) + { + ++line_num; + strncpynt(line, BSTR(&be->buf), sizeof(line)); + rm_trailing_chars(line, "\r\n\t "); + if (line[0] == '\0' || line[0] == '#') + { + } + else if (line[0] == '+' || line[0] == '-') + { + bool exclude = (line[0] == '-'); + + if (line[1] =='\0') + { + msg(D_PF_INFO, "PF: %s/%d: no data after +/-: '%s'", prefix, line_num, line); + ++n_errors; + } + else if (mode == MODE_CLIENTS) + { + if (add_client(&line[1], prefix, line_num, &cl, exclude)) + { + ++n_clients; + } + else + { + ++n_errors; + } + } + else if (mode == MODE_SUBNETS) + { + if (add_subnet(&line[1], prefix, line_num, &sl, exclude)) + { + ++n_subnets; + } + else + { + ++n_errors; + } + } + else if (mode == MODE_UNDEF) + { + } + else + { + ASSERT(0); + } + } + else if (line[0] == '[') + { + if (!strcasecmp(line, "[clients accept]")) + { + mode = MODE_CLIENTS; + pfs->cns.default_allow = true; + } + else if (!strcasecmp(line, "[clients drop]")) + { + mode = MODE_CLIENTS; + pfs->cns.default_allow = false; + } + else if (!strcasecmp(line, "[subnets accept]")) + { + mode = MODE_SUBNETS; + pfs->sns.default_allow = true; + } + else if (!strcasecmp(line, "[subnets drop]")) + { + mode = MODE_SUBNETS; + pfs->sns.default_allow = false; + } + else if (!strcasecmp(line, "[end]")) + { + goto done; + } + else if (allow_kill && !strcasecmp(line, "[kill]")) + { + goto kill; + } + else + { + mode = MODE_UNDEF; + msg(D_PF_INFO, "PF: %s/%d unknown tag: '%s'", prefix, line_num, line); + ++n_errors; + } + } + else + { + msg(D_PF_INFO, "PF: %s/%d line must begin with '+', '-', or '[' : '%s'", prefix, line_num, line); + ++n_errors; + } + } + ++n_errors; + msg(D_PF_INFO, "PF: %s: missing [end]", prefix); + } + else + { + msg(D_PF_INFO, "PF: %s: cannot open", prefix); + ++n_errors; + } + +done: + if (bl) + { + if (!n_errors) + { + if (!genhash(&pfs->cns, prefix, n_clients)) + { + ++n_errors; + } + } + if (n_errors) + { + msg(D_PF_INFO, "PF: %s rejected due to %d error(s)", prefix, n_errors); + } + } + if (n_errors) + { + pf_destroy(pfs); + pfs = NULL; + } + return pfs; + +kill: + pf_destroy(pfs); + ALLOC_OBJ_CLEAR(pfs, struct pf_set); + pfs->kill = true; + return pfs; } #ifdef PLUGIN_PF static struct pf_set * -pf_init_from_file (const char *fn) +pf_init_from_file(const char *fn) { - struct buffer_list *bl = buffer_list_file (fn, PF_MAX_LINE_LEN); - if (bl) + struct buffer_list *bl = buffer_list_file(fn, PF_MAX_LINE_LEN); + if (bl) { - struct pf_set *pfs = pf_init (bl, fn, true); - buffer_list_free (bl); - return pfs; + struct pf_set *pfs = pf_init(bl, fn, true); + buffer_list_free(bl); + return pfs; } - else + else { - msg (D_PF_INFO|M_ERRNO, "PF: %s: cannot open", fn); - return NULL; + msg(D_PF_INFO|M_ERRNO, "PF: %s: cannot open", fn); + return NULL; } } #endif @@ -327,390 +349,433 @@ pf_init_from_file (const char *fn) #ifdef ENABLE_DEBUG static const char * -drop_accept (const bool accept) +drop_accept(const bool accept) { - return accept ? "ACCEPT" : "DROP"; + return accept ? "ACCEPT" : "DROP"; } static const char * -pct_name (const int type) +pct_name(const int type) { - switch (type) + switch (type) { - case PCT_SRC: - return "SRC"; - case PCT_DEST: - return "DEST"; - default: - return "???"; + case PCT_SRC: + return "SRC"; + + case PCT_DEST: + return "DEST"; + + default: + return "???"; } } static void -pf_cn_test_print (const char *prefix, - const int type, - const char *prefix2, - const char *cn, - const bool allow, - const struct pf_cn *rule) +pf_cn_test_print(const char *prefix, + const int type, + const char *prefix2, + const char *cn, + const bool allow, + const struct pf_cn *rule) { - if (rule) + if (rule) { - dmsg (D_PF_DEBUG, "PF: %s/%s/%s %s %s rule=[%s %s]", - prefix, prefix2, pct_name (type), - cn, drop_accept (allow), - rule->cn, drop_accept (!rule->exclude)); + dmsg(D_PF_DEBUG, "PF: %s/%s/%s %s %s rule=[%s %s]", + prefix, prefix2, pct_name(type), + cn, drop_accept(allow), + rule->cn, drop_accept(!rule->exclude)); } - else + else { - dmsg (D_PF_DEBUG, "PF: %s/%s/%s %s %s", - prefix, prefix2, pct_name (type), - cn, drop_accept (allow)); + dmsg(D_PF_DEBUG, "PF: %s/%s/%s %s %s", + prefix, prefix2, pct_name(type), + cn, drop_accept(allow)); } } static void -pf_addr_test_print (const char *prefix, - const char *prefix2, - const struct context *src, - const struct mroute_addr *dest, - const bool allow, - const struct ipv4_subnet *rule) +pf_addr_test_print(const char *prefix, + const char *prefix2, + const struct context *src, + const struct mroute_addr *dest, + const bool allow, + const struct ipv4_subnet *rule) { - struct gc_arena gc = gc_new (); - if (rule) - { - dmsg (D_PF_DEBUG, "PF: %s/%s %s %s %s rule=[%s/%s %s]", - prefix, - prefix2, - tls_common_name (src->c2.tls_multi, false), - mroute_addr_print_ex (dest, MAPF_SHOW_ARP, &gc), - drop_accept (allow), - print_in_addr_t (rule->network, 0, &gc), - print_in_addr_t (rule->netmask, 0, &gc), - drop_accept (!rule->exclude)); - } - else - { - dmsg (D_PF_DEBUG, "PF: %s/%s %s %s %s", - prefix, - prefix2, - tls_common_name (src->c2.tls_multi, false), - mroute_addr_print_ex (dest, MAPF_SHOW_ARP, &gc), - drop_accept (allow)); - } - gc_free (&gc); + struct gc_arena gc = gc_new(); + if (rule) + { + dmsg(D_PF_DEBUG, "PF: %s/%s %s %s %s rule=[%s/%s %s]", + prefix, + prefix2, + tls_common_name(src->c2.tls_multi, false), + mroute_addr_print_ex(dest, MAPF_SHOW_ARP, &gc), + drop_accept(allow), + print_in_addr_t(rule->network, 0, &gc), + print_in_addr_t(rule->netmask, 0, &gc), + drop_accept(!rule->exclude)); + } + else + { + dmsg(D_PF_DEBUG, "PF: %s/%s %s %s %s", + prefix, + prefix2, + tls_common_name(src->c2.tls_multi, false), + mroute_addr_print_ex(dest, MAPF_SHOW_ARP, &gc), + drop_accept(allow)); + } + gc_free(&gc); } -#endif +#endif /* ifdef ENABLE_DEBUG */ static inline struct pf_cn * -lookup_cn_rule (struct hash *h, const char *cn, const uint32_t cn_hash) +lookup_cn_rule(struct hash *h, const char *cn, const uint32_t cn_hash) { - struct hash_element *he = hash_lookup_fast (h, hash_bucket (h, cn_hash), cn, cn_hash); - if (he) - return (struct pf_cn *) he->value; - else - return NULL; + struct hash_element *he = hash_lookup_fast(h, hash_bucket(h, cn_hash), cn, cn_hash); + if (he) + { + return (struct pf_cn *) he->value; + } + else + { + return NULL; + } } bool -pf_cn_test (struct pf_set *pfs, const struct tls_multi *tm, const int type, const char *prefix) +pf_cn_test(struct pf_set *pfs, const struct tls_multi *tm, const int type, const char *prefix) { - if (pfs && !pfs->kill) - { - const char *cn; - uint32_t cn_hash; - if (tls_common_name_hash (tm, &cn, &cn_hash)) - { - const struct pf_cn *rule = lookup_cn_rule (pfs->cns.hash_table, cn, cn_hash); - if (rule) - { + if (pfs && !pfs->kill) + { + const char *cn; + uint32_t cn_hash; + if (tls_common_name_hash(tm, &cn, &cn_hash)) + { + const struct pf_cn *rule = lookup_cn_rule(pfs->cns.hash_table, cn, cn_hash); + if (rule) + { #ifdef ENABLE_DEBUG - if (check_debug_level (D_PF_DEBUG)) - pf_cn_test_print ("PF_CN_MATCH", type, prefix, cn, !rule->exclude, rule); + if (check_debug_level(D_PF_DEBUG)) + { + pf_cn_test_print("PF_CN_MATCH", type, prefix, cn, !rule->exclude, rule); + } #endif - if (!rule->exclude) - return true; - else - return false; - } - else - { + if (!rule->exclude) + { + return true; + } + else + { + return false; + } + } + else + { #ifdef ENABLE_DEBUG - if (check_debug_level (D_PF_DEBUG)) - pf_cn_test_print ("PF_CN_DEFAULT", type, prefix, cn, pfs->cns.default_allow, NULL); + if (check_debug_level(D_PF_DEBUG)) + { + pf_cn_test_print("PF_CN_DEFAULT", type, prefix, cn, pfs->cns.default_allow, NULL); + } #endif - if (pfs->cns.default_allow) - return true; - else - return false; - } - } + if (pfs->cns.default_allow) + { + return true; + } + else + { + return false; + } + } + } } #ifdef ENABLE_DEBUG - if (check_debug_level (D_PF_DEBUG)) - pf_cn_test_print ("PF_CN_FAULT", type, prefix, tls_common_name (tm, false), false, NULL); + if (check_debug_level(D_PF_DEBUG)) + { + pf_cn_test_print("PF_CN_FAULT", type, prefix, tls_common_name(tm, false), false, NULL); + } #endif - return false; + return false; } bool -pf_addr_test_dowork (const struct context *src, const struct mroute_addr *dest, const char *prefix) +pf_addr_test_dowork(const struct context *src, const struct mroute_addr *dest, const char *prefix) { - struct pf_set *pfs = src->c2.pf.pfs; - if (pfs && !pfs->kill) - { - const in_addr_t addr = in_addr_t_from_mroute_addr (dest); - const struct pf_subnet *se = pfs->sns.list; - while (se) - { - if ((addr & se->rule.netmask) == se->rule.network) - { + struct pf_set *pfs = src->c2.pf.pfs; + if (pfs && !pfs->kill) + { + const in_addr_t addr = in_addr_t_from_mroute_addr(dest); + const struct pf_subnet *se = pfs->sns.list; + while (se) + { + if ((addr & se->rule.netmask) == se->rule.network) + { #ifdef ENABLE_DEBUG - if (check_debug_level (D_PF_DEBUG)) - pf_addr_test_print ("PF_ADDR_MATCH", prefix, src, dest, !se->rule.exclude, &se->rule); + if (check_debug_level(D_PF_DEBUG)) + { + pf_addr_test_print("PF_ADDR_MATCH", prefix, src, dest, !se->rule.exclude, &se->rule); + } #endif - return !se->rule.exclude; - } - se = se->next; - } + return !se->rule.exclude; + } + se = se->next; + } #ifdef ENABLE_DEBUG - if (check_debug_level (D_PF_DEBUG)) - pf_addr_test_print ("PF_ADDR_DEFAULT", prefix, src, dest, pfs->sns.default_allow, NULL); + if (check_debug_level(D_PF_DEBUG)) + { + pf_addr_test_print("PF_ADDR_DEFAULT", prefix, src, dest, pfs->sns.default_allow, NULL); + } #endif - return pfs->sns.default_allow; + return pfs->sns.default_allow; } - else + else { #ifdef ENABLE_DEBUG - if (check_debug_level (D_PF_DEBUG)) - pf_addr_test_print ("PF_ADDR_FAULT", prefix, src, dest, false, NULL); + if (check_debug_level(D_PF_DEBUG)) + { + pf_addr_test_print("PF_ADDR_FAULT", prefix, src, dest, false, NULL); + } #endif - return false; + return false; } } #ifdef PLUGIN_PF void -pf_check_reload (struct context *c) +pf_check_reload(struct context *c) { - const int slow_wakeup = 15; - const int fast_wakeup = 1; - const int wakeup_transition = 60; - bool reloaded = false; - - if (c->c2.pf.enabled - && c->c2.pf.filename - && event_timeout_trigger (&c->c2.pf.reload, &c->c2.timeval, ETT_DEFAULT)) - { - platform_stat_t s; - if (!platform_stat (c->c2.pf.filename, &s)) - { - if (s.st_mtime > c->c2.pf.file_last_mod) - { - struct pf_set *pfs = pf_init_from_file (c->c2.pf.filename); - if (pfs) - { - if (c->c2.pf.pfs) - pf_destroy (c->c2.pf.pfs); - c->c2.pf.pfs = pfs; - reloaded = true; - if (pf_kill_test (pfs)) - { - c->sig->signal_received = SIGTERM; - c->sig->signal_text = "pf-kill"; - } - } - c->c2.pf.file_last_mod = s.st_mtime; - } - } - { - int wakeup = slow_wakeup; - if (!c->c2.pf.pfs && c->c2.pf.n_check_reload < wakeup_transition) - wakeup = fast_wakeup; - event_timeout_init (&c->c2.pf.reload, wakeup, now); - reset_coarse_timers (c); - c->c2.pf.n_check_reload++; - } + const int slow_wakeup = 15; + const int fast_wakeup = 1; + const int wakeup_transition = 60; + bool reloaded = false; + + if (c->c2.pf.enabled + && c->c2.pf.filename + && event_timeout_trigger(&c->c2.pf.reload, &c->c2.timeval, ETT_DEFAULT)) + { + platform_stat_t s; + if (!platform_stat(c->c2.pf.filename, &s)) + { + if (s.st_mtime > c->c2.pf.file_last_mod) + { + struct pf_set *pfs = pf_init_from_file(c->c2.pf.filename); + if (pfs) + { + if (c->c2.pf.pfs) + { + pf_destroy(c->c2.pf.pfs); + } + c->c2.pf.pfs = pfs; + reloaded = true; + if (pf_kill_test(pfs)) + { + c->sig->signal_received = SIGTERM; + c->sig->signal_text = "pf-kill"; + } + } + c->c2.pf.file_last_mod = s.st_mtime; + } + } + { + int wakeup = slow_wakeup; + if (!c->c2.pf.pfs && c->c2.pf.n_check_reload < wakeup_transition) + { + wakeup = fast_wakeup; + } + event_timeout_init(&c->c2.pf.reload, wakeup, now); + reset_coarse_timers(c); + c->c2.pf.n_check_reload++; + } } #ifdef ENABLE_DEBUG - if (reloaded && check_debug_level (D_PF_DEBUG)) - pf_context_print (&c->c2.pf, "pf_check_reload", D_PF_DEBUG); + if (reloaded && check_debug_level(D_PF_DEBUG)) + { + pf_context_print(&c->c2.pf, "pf_check_reload", D_PF_DEBUG); + } #endif } -#endif +#endif /* ifdef PLUGIN_PF */ #ifdef MANAGEMENT_PF bool -pf_load_from_buffer_list (struct context *c, const struct buffer_list *config) +pf_load_from_buffer_list(struct context *c, const struct buffer_list *config) { - struct pf_set *pfs = pf_init (config, "[SERVER-PF]", false); - if (pfs) + struct pf_set *pfs = pf_init(config, "[SERVER-PF]", false); + if (pfs) { - if (c->c2.pf.pfs) - pf_destroy (c->c2.pf.pfs); - c->c2.pf.pfs = pfs; - return true; + if (c->c2.pf.pfs) + { + pf_destroy(c->c2.pf.pfs); + } + c->c2.pf.pfs = pfs; + return true; + } + else + { + return false; } - else - return false; } #endif void -pf_init_context (struct context *c) +pf_init_context(struct context *c) { - struct gc_arena gc = gc_new (); + struct gc_arena gc = gc_new(); #ifdef PLUGIN_PF - if (plugin_defined (c->plugins, OPENVPN_PLUGIN_ENABLE_PF)) + if (plugin_defined(c->plugins, OPENVPN_PLUGIN_ENABLE_PF)) { - const char *pf_file = create_temp_file (c->options.tmp_dir, "pf", &gc); - if( pf_file ) { - setenv_str (c->c2.es, "pf_file", pf_file); + const char *pf_file = create_temp_file(c->options.tmp_dir, "pf", &gc); + if (pf_file) + { + setenv_str(c->c2.es, "pf_file", pf_file); - if (plugin_call (c->plugins, OPENVPN_PLUGIN_ENABLE_PF, NULL, NULL, c->c2.es) == OPENVPN_PLUGIN_FUNC_SUCCESS) - { - event_timeout_init (&c->c2.pf.reload, 1, now); - c->c2.pf.filename = string_alloc (pf_file, &c->c2.gc); - c->c2.pf.enabled = true; + if (plugin_call(c->plugins, OPENVPN_PLUGIN_ENABLE_PF, NULL, NULL, c->c2.es) == OPENVPN_PLUGIN_FUNC_SUCCESS) + { + event_timeout_init(&c->c2.pf.reload, 1, now); + c->c2.pf.filename = string_alloc(pf_file, &c->c2.gc); + c->c2.pf.enabled = true; #ifdef ENABLE_DEBUG - if (check_debug_level (D_PF_DEBUG)) - pf_context_print (&c->c2.pf, "pf_init_context#1", D_PF_DEBUG); + if (check_debug_level(D_PF_DEBUG)) + { + pf_context_print(&c->c2.pf, "pf_init_context#1", D_PF_DEBUG); + } #endif - } - else - { - msg (M_WARN, "WARNING: OPENVPN_PLUGIN_ENABLE_PF disabled"); - } - } + } + else + { + msg(M_WARN, "WARNING: OPENVPN_PLUGIN_ENABLE_PF disabled"); + } + } } -#endif +#endif /* ifdef PLUGIN_PF */ #ifdef MANAGEMENT_PF - if (!c->c2.pf.enabled && management_enable_pf (management)) + if (!c->c2.pf.enabled && management_enable_pf(management)) { - c->c2.pf.enabled = true; + c->c2.pf.enabled = true; #ifdef ENABLE_DEBUG - if (check_debug_level (D_PF_DEBUG)) - pf_context_print (&c->c2.pf, "pf_init_context#2", D_PF_DEBUG); + if (check_debug_level(D_PF_DEBUG)) + { + pf_context_print(&c->c2.pf, "pf_init_context#2", D_PF_DEBUG); + } #endif } #endif - gc_free (&gc); + gc_free(&gc); } void -pf_destroy_context (struct pf_context *pfc) +pf_destroy_context(struct pf_context *pfc) { #ifdef PLUGIN_PF - if (pfc->filename) + if (pfc->filename) { - platform_unlink (pfc->filename); + platform_unlink(pfc->filename); } #endif - if (pfc->pfs) - pf_destroy (pfc->pfs); + if (pfc->pfs) + { + pf_destroy(pfc->pfs); + } } #ifdef ENABLE_DEBUG static void -pf_subnet_set_print (const struct pf_subnet_set *s, const int lev) +pf_subnet_set_print(const struct pf_subnet_set *s, const int lev) { - struct gc_arena gc = gc_new (); - if (s) + struct gc_arena gc = gc_new(); + if (s) { - struct pf_subnet *e; + struct pf_subnet *e; - msg (lev, " ----- struct pf_subnet_set -----"); - msg (lev, " default_allow=%s", drop_accept (s->default_allow)); + msg(lev, " ----- struct pf_subnet_set -----"); + msg(lev, " default_allow=%s", drop_accept(s->default_allow)); - for (e = s->list; e != NULL; e = e->next) - { - msg (lev, " %s/%s %s", - print_in_addr_t (e->rule.network, 0, &gc), - print_in_addr_t (e->rule.netmask, 0, &gc), - drop_accept (!e->rule.exclude)); - } + for (e = s->list; e != NULL; e = e->next) + { + msg(lev, " %s/%s %s", + print_in_addr_t(e->rule.network, 0, &gc), + print_in_addr_t(e->rule.netmask, 0, &gc), + drop_accept(!e->rule.exclude)); + } } - gc_free (&gc); + gc_free(&gc); } static void -pf_cn_set_print (const struct pf_cn_set *s, const int lev) +pf_cn_set_print(const struct pf_cn_set *s, const int lev) { - if (s) - { - struct hash_iterator hi; - struct hash_element *he; - - msg (lev, " ----- struct pf_cn_set -----"); - msg (lev, " default_allow=%s", drop_accept (s->default_allow)); - - if (s->hash_table) - { - hash_iterator_init (s->hash_table, &hi); - while ((he = hash_iterator_next (&hi))) - { - struct pf_cn *e = (struct pf_cn *)he->value; - msg (lev, " %s %s", - e->cn, - drop_accept (!e->exclude)); - } - - msg (lev, " ----------"); - - { - struct pf_cn_elem *ce; - for (ce = s->list; ce != NULL; ce = ce->next) - { - struct pf_cn *e = lookup_cn_rule (s->hash_table, ce->rule.cn, cn_hash_function (ce->rule.cn, 0)); - if (e) - { - msg (lev, " %s %s", - e->cn, - drop_accept (!e->exclude)); - } - else - { - msg (lev, " %s LOOKUP FAILED", ce->rule.cn); - } - } - } - } + if (s) + { + struct hash_iterator hi; + struct hash_element *he; + + msg(lev, " ----- struct pf_cn_set -----"); + msg(lev, " default_allow=%s", drop_accept(s->default_allow)); + + if (s->hash_table) + { + hash_iterator_init(s->hash_table, &hi); + while ((he = hash_iterator_next(&hi))) + { + struct pf_cn *e = (struct pf_cn *)he->value; + msg(lev, " %s %s", + e->cn, + drop_accept(!e->exclude)); + } + + msg(lev, " ----------"); + + { + struct pf_cn_elem *ce; + for (ce = s->list; ce != NULL; ce = ce->next) + { + struct pf_cn *e = lookup_cn_rule(s->hash_table, ce->rule.cn, cn_hash_function(ce->rule.cn, 0)); + if (e) + { + msg(lev, " %s %s", + e->cn, + drop_accept(!e->exclude)); + } + else + { + msg(lev, " %s LOOKUP FAILED", ce->rule.cn); + } + } + } + } } } static void -pf_set_print (const struct pf_set *pfs, const int lev) +pf_set_print(const struct pf_set *pfs, const int lev) { - if (pfs) + if (pfs) { - msg (lev, " ----- struct pf_set -----"); - msg (lev, " kill=%d", pfs->kill); - pf_subnet_set_print (&pfs->sns, lev); - pf_cn_set_print (&pfs->cns, lev); + msg(lev, " ----- struct pf_set -----"); + msg(lev, " kill=%d", pfs->kill); + pf_subnet_set_print(&pfs->sns, lev); + pf_cn_set_print(&pfs->cns, lev); } } void -pf_context_print (const struct pf_context *pfc, const char *prefix, const int lev) +pf_context_print(const struct pf_context *pfc, const char *prefix, const int lev) { - msg (lev, "----- %s : struct pf_context -----", prefix); - if (pfc) + msg(lev, "----- %s : struct pf_context -----", prefix); + if (pfc) { - msg (lev, "enabled=%d", pfc->enabled); + msg(lev, "enabled=%d", pfc->enabled); #ifdef PLUGIN_PF - msg (lev, "filename='%s'", np(pfc->filename)); - msg (lev, "file_last_mod=%u", (unsigned int)pfc->file_last_mod); - msg (lev, "n_check_reload=%u", pfc->n_check_reload); - msg (lev, "reload=[%d,%u,%u]", pfc->reload.defined, pfc->reload.n, (unsigned int)pfc->reload.last); + msg(lev, "filename='%s'", np(pfc->filename)); + msg(lev, "file_last_mod=%u", (unsigned int)pfc->file_last_mod); + msg(lev, "n_check_reload=%u", pfc->n_check_reload); + msg(lev, "reload=[%d,%u,%u]", pfc->reload.defined, pfc->reload.n, (unsigned int)pfc->reload.last); #endif - pf_set_print (pfc->pfs, lev); + pf_set_print(pfc->pfs, lev); } - msg (lev, "--------------------"); + msg(lev, "--------------------"); } -#endif +#endif /* ifdef ENABLE_DEBUG */ -#endif +#endif /* if defined(ENABLE_PF) */ diff --git a/src/openvpn/pf.h b/src/openvpn/pf.h index 04adf0eaa92..e5c951f2ece 100644 --- a/src/openvpn/pf.h +++ b/src/openvpn/pf.h @@ -35,68 +35,71 @@ struct context; struct ipv4_subnet { - bool exclude; - in_addr_t network; - in_addr_t netmask; + bool exclude; + in_addr_t network; + in_addr_t netmask; }; struct pf_subnet { - struct pf_subnet *next; - struct ipv4_subnet rule; + struct pf_subnet *next; + struct ipv4_subnet rule; }; struct pf_subnet_set { - bool default_allow; - struct pf_subnet *list; + bool default_allow; + struct pf_subnet *list; }; struct pf_cn { - bool exclude; - char *cn; + bool exclude; + char *cn; }; struct pf_cn_elem { - struct pf_cn_elem *next; - struct pf_cn rule; + struct pf_cn_elem *next; + struct pf_cn rule; }; struct pf_cn_set { - bool default_allow; - struct pf_cn_elem *list; - struct hash *hash_table; + bool default_allow; + struct pf_cn_elem *list; + struct hash *hash_table; }; struct pf_set { - bool kill; - struct pf_subnet_set sns; - struct pf_cn_set cns; + bool kill; + struct pf_subnet_set sns; + struct pf_cn_set cns; }; struct pf_context { - bool enabled; - struct pf_set *pfs; + bool enabled; + struct pf_set *pfs; #ifdef PLUGIN_PF - char *filename; - time_t file_last_mod; - unsigned int n_check_reload; - struct event_timeout reload; + char *filename; + time_t file_last_mod; + unsigned int n_check_reload; + struct event_timeout reload; #endif }; -void pf_init_context (struct context *c); +void pf_init_context(struct context *c); -void pf_destroy_context (struct pf_context *pfc); +void pf_destroy_context(struct pf_context *pfc); #ifdef PLUGIN_PF -void pf_check_reload (struct context *c); +void pf_check_reload(struct context *c); + #endif #ifdef MANAGEMENT_PF -bool pf_load_from_buffer_list (struct context *c, const struct buffer_list *config); +bool pf_load_from_buffer_list(struct context *c, const struct buffer_list *config); + #endif #ifdef ENABLE_DEBUG -void pf_context_print (const struct pf_context *pfc, const char *prefix, const int lev); -#endif +void pf_context_print(const struct pf_context *pfc, const char *prefix, const int lev); #endif + +#endif /* if defined(ENABLE_PF) && !defined(OPENVPN_PF_H) */ diff --git a/src/openvpn/ping-inline.h b/src/openvpn/ping-inline.h index c7249705f9e..10291003197 100644 --- a/src/openvpn/ping-inline.h +++ b/src/openvpn/ping-inline.h @@ -30,30 +30,36 @@ * not received in n seconds? */ static inline void -check_ping_restart (struct context *c) +check_ping_restart(struct context *c) { - void check_ping_restart_dowork (struct context *c); - if (c->options.ping_rec_timeout - && event_timeout_trigger (&c->c2.ping_rec_interval, - &c->c2.timeval, - (!c->options.ping_timer_remote - || link_socket_actual_defined (&c->c1.link_socket_addr.actual)) - ? ETT_DEFAULT : 15)) - check_ping_restart_dowork (c); + void check_ping_restart_dowork(struct context *c); + + if (c->options.ping_rec_timeout + && event_timeout_trigger(&c->c2.ping_rec_interval, + &c->c2.timeval, + (!c->options.ping_timer_remote + || link_socket_actual_defined(&c->c1.link_socket_addr.actual)) + ? ETT_DEFAULT : 15)) + { + check_ping_restart_dowork(c); + } } /* * Should we ping the remote? */ static inline void -check_ping_send (struct context *c) +check_ping_send(struct context *c) { - void check_ping_send_dowork (struct context *c); - if (c->options.ping_send_timeout - && event_timeout_trigger (&c->c2.ping_send_interval, - &c->c2.timeval, - !TO_LINK_DEF(c) ? ETT_DEFAULT : 1)) - check_ping_send_dowork (c); + void check_ping_send_dowork(struct context *c); + + if (c->options.ping_send_timeout + && event_timeout_trigger(&c->c2.ping_send_interval, + &c->c2.timeval, + !TO_LINK_DEF(c) ? ETT_DEFAULT : 1)) + { + check_ping_send_dowork(c); + } } -#endif +#endif /* ifndef PING_INLINE_H */ diff --git a/src/openvpn/ping.c b/src/openvpn/ping.c index 6dc0b4e55c4..1af31ccb6c2 100644 --- a/src/openvpn/ping.c +++ b/src/openvpn/ping.c @@ -44,8 +44,8 @@ * PING_STRING_SIZE must be sizeof (ping_string) */ const uint8_t ping_string[] = { - 0x2a, 0x18, 0x7b, 0xf3, 0x64, 0x1e, 0xb4, 0xcb, - 0x07, 0xed, 0x2d, 0x0a, 0x98, 0x1f, 0xc7, 0x48 + 0x2a, 0x18, 0x7b, 0xf3, 0x64, 0x1e, 0xb4, 0xcb, + 0x07, 0xed, 0x2d, 0x0a, 0x98, 0x1f, 0xc7, 0x48 }; /* @@ -53,46 +53,48 @@ const uint8_t ping_string[] = { * not received in n seconds? */ void -check_ping_restart_dowork (struct context *c) +check_ping_restart_dowork(struct context *c) { - struct gc_arena gc = gc_new (); - switch (c->options.ping_rec_timeout_action) + struct gc_arena gc = gc_new(); + switch (c->options.ping_rec_timeout_action) { - case PING_EXIT: - msg (M_INFO, "%sInactivity timeout (--ping-exit), exiting", - format_common_name (c, &gc)); - c->sig->signal_received = SIGTERM; - c->sig->signal_text = "ping-exit"; - break; - case PING_RESTART: - msg (M_INFO, "%sInactivity timeout (--ping-restart), restarting", - format_common_name (c, &gc)); - c->sig->signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- Ping Restart */ - c->sig->signal_text = "ping-restart"; - break; - default: - ASSERT (0); + case PING_EXIT: + msg(M_INFO, "%sInactivity timeout (--ping-exit), exiting", + format_common_name(c, &gc)); + c->sig->signal_received = SIGTERM; + c->sig->signal_text = "ping-exit"; + break; + + case PING_RESTART: + msg(M_INFO, "%sInactivity timeout (--ping-restart), restarting", + format_common_name(c, &gc)); + c->sig->signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- Ping Restart */ + c->sig->signal_text = "ping-restart"; + break; + + default: + ASSERT(0); } - gc_free (&gc); + gc_free(&gc); } /* * Should we ping the remote? */ void -check_ping_send_dowork (struct context *c) +check_ping_send_dowork(struct context *c) { - c->c2.buf = c->c2.buffers->aux_buf; - ASSERT (buf_init (&c->c2.buf, FRAME_HEADROOM (&c->c2.frame))); - ASSERT (buf_safe (&c->c2.buf, MAX_RW_SIZE_TUN (&c->c2.frame))); - ASSERT (buf_write (&c->c2.buf, ping_string, sizeof (ping_string))); + c->c2.buf = c->c2.buffers->aux_buf; + ASSERT(buf_init(&c->c2.buf, FRAME_HEADROOM(&c->c2.frame))); + ASSERT(buf_safe(&c->c2.buf, MAX_RW_SIZE_TUN(&c->c2.frame))); + ASSERT(buf_write(&c->c2.buf, ping_string, sizeof(ping_string))); - /* - * We will treat the ping like any other outgoing packet, - * encrypt, sign, etc. - */ - encrypt_sign (c, true); - /* Set length to 0, so it won't be counted as activity */ - c->c2.buf.len = 0; - dmsg (D_PING, "SENT PING"); -} + /* + * We will treat the ping like any other outgoing packet, + * encrypt, sign, etc. + */ + encrypt_sign(c, true); + /* Set length to 0, so it won't be counted as activity */ + c->c2.buf.len = 0; + dmsg(D_PING, "SENT PING"); +} diff --git a/src/openvpn/ping.h b/src/openvpn/ping.h index 88f5f3a9527..6f060c6d654 100644 --- a/src/openvpn/ping.h +++ b/src/openvpn/ping.h @@ -39,9 +39,9 @@ extern const uint8_t ping_string[]; #define PING_STRING_SIZE 16 static inline bool -is_ping_msg (const struct buffer* buf) +is_ping_msg(const struct buffer *buf) { - return buf_string_match (buf, ping_string, PING_STRING_SIZE); + return buf_string_match(buf, ping_string, PING_STRING_SIZE); } #endif diff --git a/src/openvpn/pkcs11.c b/src/openvpn/pkcs11.c index 26210589792..f77d4cd36ad 100644 --- a/src/openvpn/pkcs11.c +++ b/src/openvpn/pkcs11.c @@ -45,898 +45,968 @@ static time_t -__mytime (void) { - return openvpn_time (NULL); +__mytime(void) { + return openvpn_time(NULL); } #if !defined(_WIN32) static int -__mygettimeofday (struct timeval *tv) { - return gettimeofday (tv, NULL); +__mygettimeofday(struct timeval *tv) { + return gettimeofday(tv, NULL); } #endif static void -__mysleep (const unsigned long usec) { +__mysleep(const unsigned long usec) { #if defined(_WIN32) - Sleep (usec/1000); + Sleep(usec/1000); #else - usleep (usec); + usleep(usec); #endif } static pkcs11h_engine_system_t s_pkcs11h_sys_engine = { - malloc, - free, - __mytime, - __mysleep, + malloc, + free, + __mytime, + __mysleep, #if defined(_WIN32) - NULL + NULL #else - __mygettimeofday + __mygettimeofday #endif }; static unsigned -_pkcs11_msg_pkcs112openvpn ( - const unsigned flags -) { - unsigned openvpn_flags; - - switch (flags) { - case PKCS11H_LOG_DEBUG2: - openvpn_flags = D_PKCS11_DEBUG; - break; - case PKCS11H_LOG_DEBUG1: - openvpn_flags = D_SHOW_PKCS11; - break; - case PKCS11H_LOG_INFO: - openvpn_flags = M_INFO; - break; - case PKCS11H_LOG_WARN: - openvpn_flags = M_WARN; - break; - case PKCS11H_LOG_ERROR: - openvpn_flags = M_FATAL; - break; - default: - openvpn_flags = M_FATAL; - break; - } +_pkcs11_msg_pkcs112openvpn( + const unsigned flags + ) { + unsigned openvpn_flags; + + switch (flags) { + case PKCS11H_LOG_DEBUG2: + openvpn_flags = D_PKCS11_DEBUG; + break; + + case PKCS11H_LOG_DEBUG1: + openvpn_flags = D_SHOW_PKCS11; + break; + + case PKCS11H_LOG_INFO: + openvpn_flags = M_INFO; + break; + + case PKCS11H_LOG_WARN: + openvpn_flags = M_WARN; + break; + + case PKCS11H_LOG_ERROR: + openvpn_flags = M_FATAL; + break; + + default: + openvpn_flags = M_FATAL; + break; + } #if defined(ENABLE_PKCS11_FORCE_DEBUG) - openvpn_flags=M_INFO; + openvpn_flags = M_INFO; #endif - return openvpn_flags; + return openvpn_flags; } static unsigned -_pkcs11_msg_openvpn2pkcs11 ( - const unsigned flags -) { - unsigned pkcs11_flags; - - if ((flags & D_PKCS11_DEBUG) != 0) { - pkcs11_flags = PKCS11H_LOG_DEBUG2; - } - else if ((flags & D_SHOW_PKCS11) != 0) { - pkcs11_flags = PKCS11H_LOG_DEBUG1; - } - else if ((flags & M_INFO) != 0) { - pkcs11_flags = PKCS11H_LOG_INFO; - } - else if ((flags & M_WARN) != 0) { - pkcs11_flags = PKCS11H_LOG_WARN; - } - else if ((flags & M_FATAL) != 0) { - pkcs11_flags = PKCS11H_LOG_ERROR; - } - else { - pkcs11_flags = PKCS11H_LOG_ERROR; - } +_pkcs11_msg_openvpn2pkcs11( + const unsigned flags + ) { + unsigned pkcs11_flags; + + if ((flags & D_PKCS11_DEBUG) != 0) + { + pkcs11_flags = PKCS11H_LOG_DEBUG2; + } + else if ((flags & D_SHOW_PKCS11) != 0) + { + pkcs11_flags = PKCS11H_LOG_DEBUG1; + } + else if ((flags & M_INFO) != 0) + { + pkcs11_flags = PKCS11H_LOG_INFO; + } + else if ((flags & M_WARN) != 0) + { + pkcs11_flags = PKCS11H_LOG_WARN; + } + else if ((flags & M_FATAL) != 0) + { + pkcs11_flags = PKCS11H_LOG_ERROR; + } + else + { + pkcs11_flags = PKCS11H_LOG_ERROR; + } #if defined(ENABLE_PKCS11_FORCE_DEBUG) - pkcs11_flags = PKCS11H_LOG_DEBUG2; + pkcs11_flags = PKCS11H_LOG_DEBUG2; #endif - return pkcs11_flags; + return pkcs11_flags; } static void -_pkcs11_openvpn_log ( - void * const global_data, - unsigned flags, - const char * const szFormat, - va_list args -) { - char Buffer[10*1024]; - - (void)global_data; - - vsnprintf (Buffer, sizeof (Buffer), szFormat, args); - Buffer[sizeof (Buffer)-1] = 0; - - msg (_pkcs11_msg_pkcs112openvpn (flags), "%s", Buffer); +_pkcs11_openvpn_log( + void *const global_data, + unsigned flags, + const char *const szFormat, + va_list args + ) { + char Buffer[10*1024]; + + (void)global_data; + + vsnprintf(Buffer, sizeof(Buffer), szFormat, args); + Buffer[sizeof(Buffer)-1] = 0; + + msg(_pkcs11_msg_pkcs112openvpn(flags), "%s", Buffer); } static PKCS11H_BOOL -_pkcs11_openvpn_token_prompt ( - void * const global_data, - void * const user_data, - const pkcs11h_token_id_t token, - const unsigned retry -) { - struct user_pass token_resp; - - (void)global_data; - (void)user_data; - (void)retry; - - ASSERT (token!=NULL); - - CLEAR (token_resp); - token_resp.defined = false; - token_resp.nocache = true; - openvpn_snprintf ( - token_resp.username, - sizeof (token_resp.username), - "Please insert %s token", - token->label - ); - - if ( - !get_user_pass ( - &token_resp, - NULL, - "token-insertion-request", - GET_USER_PASS_MANAGEMENT|GET_USER_PASS_NEED_OK|GET_USER_PASS_NOFATAL - ) - ) { - return false; - } - else { - return strcmp (token_resp.password, "ok") == 0; - } +_pkcs11_openvpn_token_prompt( + void *const global_data, + void *const user_data, + const pkcs11h_token_id_t token, + const unsigned retry + ) { + struct user_pass token_resp; + + (void)global_data; + (void)user_data; + (void)retry; + + ASSERT(token!=NULL); + + CLEAR(token_resp); + token_resp.defined = false; + token_resp.nocache = true; + openvpn_snprintf( + token_resp.username, + sizeof(token_resp.username), + "Please insert %s token", + token->label + ); + + if ( + !get_user_pass( + &token_resp, + NULL, + "token-insertion-request", + GET_USER_PASS_MANAGEMENT|GET_USER_PASS_NEED_OK|GET_USER_PASS_NOFATAL + ) + ) + { + return false; + } + else + { + return strcmp(token_resp.password, "ok") == 0; + } } static PKCS11H_BOOL -_pkcs11_openvpn_pin_prompt ( - void * const global_data, - void * const user_data, - const pkcs11h_token_id_t token, - const unsigned retry, - char * const pin, - const size_t pin_max -) { - struct user_pass token_pass; - char prompt[1024]; - - (void)global_data; - (void)user_data; - (void)retry; - - ASSERT (token!=NULL); - - openvpn_snprintf (prompt, sizeof (prompt), "%s token", token->label); - - token_pass.defined = false; - token_pass.nocache = true; - - if ( - !get_user_pass ( - &token_pass, - NULL, - prompt, - GET_USER_PASS_MANAGEMENT|GET_USER_PASS_PASSWORD_ONLY|GET_USER_PASS_NOFATAL - ) - ) { - return false; - } - else { - strncpynt (pin, token_pass.password, pin_max); - purge_user_pass (&token_pass, true); - - if (strlen (pin) == 0) { - return false; - } - else { - return true; - } - } +_pkcs11_openvpn_pin_prompt( + void *const global_data, + void *const user_data, + const pkcs11h_token_id_t token, + const unsigned retry, + char *const pin, + const size_t pin_max + ) { + struct user_pass token_pass; + char prompt[1024]; + + (void)global_data; + (void)user_data; + (void)retry; + + ASSERT(token!=NULL); + + openvpn_snprintf(prompt, sizeof(prompt), "%s token", token->label); + + token_pass.defined = false; + token_pass.nocache = true; + + if ( + !get_user_pass( + &token_pass, + NULL, + prompt, + GET_USER_PASS_MANAGEMENT|GET_USER_PASS_PASSWORD_ONLY|GET_USER_PASS_NOFATAL + ) + ) + { + return false; + } + else + { + strncpynt(pin, token_pass.password, pin_max); + purge_user_pass(&token_pass, true); + + if (strlen(pin) == 0) + { + return false; + } + else + { + return true; + } + } } bool -pkcs11_initialize ( - const bool protected_auth, - const int nPINCachePeriod -) { - CK_RV rv = CKR_FUNCTION_FAILED; - - dmsg ( - D_PKCS11_DEBUG, - "PKCS#11: pkcs11_initialize - entered" - ); - - if ((rv = pkcs11h_engine_setSystem (&s_pkcs11h_sys_engine)) != CKR_OK) { - msg (M_FATAL, "PKCS#11: Cannot initialize system engine %ld-'%s'", rv, pkcs11h_getMessage (rv)); - goto cleanup; - } - - if ((rv = pkcs11h_initialize ()) != CKR_OK) { - msg (M_FATAL, "PKCS#11: Cannot initialize %ld-'%s'", rv, pkcs11h_getMessage (rv)); - goto cleanup; - } - - if ((rv = pkcs11h_setLogHook (_pkcs11_openvpn_log, NULL)) != CKR_OK) { - msg (M_FATAL, "PKCS#11: Cannot set hooks %ld-'%s'", rv, pkcs11h_getMessage (rv)); - goto cleanup; - } - - pkcs11h_setLogLevel (_pkcs11_msg_openvpn2pkcs11 (get_debug_level ())); - - if ((rv = pkcs11h_setForkMode (TRUE)) != CKR_OK) { - msg (M_FATAL, "PKCS#11: Cannot set fork mode %ld-'%s'", rv, pkcs11h_getMessage (rv)); - goto cleanup; - } - - if ((rv = pkcs11h_setTokenPromptHook (_pkcs11_openvpn_token_prompt, NULL)) != CKR_OK) { - msg (M_FATAL, "PKCS#11: Cannot set hooks %ld-'%s'", rv, pkcs11h_getMessage (rv)); - goto cleanup; - } - - if ((rv = pkcs11h_setPINPromptHook (_pkcs11_openvpn_pin_prompt, NULL)) != CKR_OK) { - msg (M_FATAL, "PKCS#11: Cannot set hooks %ld-'%s'", rv, pkcs11h_getMessage (rv)); - goto cleanup; - } - - if ((rv = pkcs11h_setProtectedAuthentication (protected_auth)) != CKR_OK) { - msg (M_FATAL, "PKCS#11: Cannot set protected authentication mode %ld-'%s'", rv, pkcs11h_getMessage (rv)); - goto cleanup; - } - - if ((rv = pkcs11h_setPINCachePeriod (nPINCachePeriod)) != CKR_OK) { - msg (M_FATAL, "PKCS#11: Cannot set Pcache period %ld-'%s'", rv, pkcs11h_getMessage (rv)); - goto cleanup; - } - - rv = CKR_OK; +pkcs11_initialize( + const bool protected_auth, + const int nPINCachePeriod + ) { + CK_RV rv = CKR_FUNCTION_FAILED; + + dmsg( + D_PKCS11_DEBUG, + "PKCS#11: pkcs11_initialize - entered" + ); + + if ((rv = pkcs11h_engine_setSystem(&s_pkcs11h_sys_engine)) != CKR_OK) + { + msg(M_FATAL, "PKCS#11: Cannot initialize system engine %ld-'%s'", rv, pkcs11h_getMessage(rv)); + goto cleanup; + } + + if ((rv = pkcs11h_initialize()) != CKR_OK) + { + msg(M_FATAL, "PKCS#11: Cannot initialize %ld-'%s'", rv, pkcs11h_getMessage(rv)); + goto cleanup; + } + + if ((rv = pkcs11h_setLogHook(_pkcs11_openvpn_log, NULL)) != CKR_OK) + { + msg(M_FATAL, "PKCS#11: Cannot set hooks %ld-'%s'", rv, pkcs11h_getMessage(rv)); + goto cleanup; + } + + pkcs11h_setLogLevel(_pkcs11_msg_openvpn2pkcs11(get_debug_level())); + + if ((rv = pkcs11h_setForkMode(TRUE)) != CKR_OK) + { + msg(M_FATAL, "PKCS#11: Cannot set fork mode %ld-'%s'", rv, pkcs11h_getMessage(rv)); + goto cleanup; + } + + if ((rv = pkcs11h_setTokenPromptHook(_pkcs11_openvpn_token_prompt, NULL)) != CKR_OK) + { + msg(M_FATAL, "PKCS#11: Cannot set hooks %ld-'%s'", rv, pkcs11h_getMessage(rv)); + goto cleanup; + } + + if ((rv = pkcs11h_setPINPromptHook(_pkcs11_openvpn_pin_prompt, NULL)) != CKR_OK) + { + msg(M_FATAL, "PKCS#11: Cannot set hooks %ld-'%s'", rv, pkcs11h_getMessage(rv)); + goto cleanup; + } + + if ((rv = pkcs11h_setProtectedAuthentication(protected_auth)) != CKR_OK) + { + msg(M_FATAL, "PKCS#11: Cannot set protected authentication mode %ld-'%s'", rv, pkcs11h_getMessage(rv)); + goto cleanup; + } + + if ((rv = pkcs11h_setPINCachePeriod(nPINCachePeriod)) != CKR_OK) + { + msg(M_FATAL, "PKCS#11: Cannot set Pcache period %ld-'%s'", rv, pkcs11h_getMessage(rv)); + goto cleanup; + } + + rv = CKR_OK; cleanup: - dmsg ( - D_PKCS11_DEBUG, - "PKCS#11: pkcs11_initialize - return %ld-'%s'", - rv, - pkcs11h_getMessage (rv) - ); - - return rv == CKR_OK; + dmsg( + D_PKCS11_DEBUG, + "PKCS#11: pkcs11_initialize - return %ld-'%s'", + rv, + pkcs11h_getMessage(rv) + ); + + return rv == CKR_OK; } void -pkcs11_terminate () { - dmsg ( - D_PKCS11_DEBUG, - "PKCS#11: pkcs11_terminate - entered" - ); - - pkcs11h_terminate (); - - dmsg ( - D_PKCS11_DEBUG, - "PKCS#11: pkcs11_terminate - return" - ); +pkcs11_terminate() { + dmsg( + D_PKCS11_DEBUG, + "PKCS#11: pkcs11_terminate - entered" + ); + + pkcs11h_terminate(); + + dmsg( + D_PKCS11_DEBUG, + "PKCS#11: pkcs11_terminate - return" + ); } bool -pkcs11_addProvider ( - const char * const provider, - const bool protected_auth, - const unsigned private_mode, - const bool cert_private -) { - CK_RV rv = CKR_OK; - - ASSERT (provider!=NULL); - - dmsg ( - D_PKCS11_DEBUG, - "PKCS#11: pkcs11_addProvider - entered - provider='%s', private_mode=%08x", - provider, - private_mode - ); - - msg ( - M_INFO, - "PKCS#11: Adding PKCS#11 provider '%s'", - provider - ); - - if ( - (rv = pkcs11h_addProvider ( - provider, - provider, - protected_auth, - private_mode, - PKCS11H_SLOTEVENT_METHOD_AUTO, - 0, - cert_private - )) != CKR_OK - ) { - msg (M_WARN, "PKCS#11: Cannot initialize provider '%s' %ld-'%s'", provider, rv, pkcs11h_getMessage (rv)); - } - - dmsg ( - D_PKCS11_DEBUG, - "PKCS#11: pkcs11_addProvider - return rv=%ld-'%s'", - rv, - pkcs11h_getMessage (rv) - ); - - return rv == CKR_OK; +pkcs11_addProvider( + const char *const provider, + const bool protected_auth, + const unsigned private_mode, + const bool cert_private + ) { + CK_RV rv = CKR_OK; + + ASSERT(provider!=NULL); + + dmsg( + D_PKCS11_DEBUG, + "PKCS#11: pkcs11_addProvider - entered - provider='%s', private_mode=%08x", + provider, + private_mode + ); + + msg( + M_INFO, + "PKCS#11: Adding PKCS#11 provider '%s'", + provider + ); + + if ( + (rv = pkcs11h_addProvider( + provider, + provider, + protected_auth, + private_mode, + PKCS11H_SLOTEVENT_METHOD_AUTO, + 0, + cert_private + )) != CKR_OK + ) + { + msg(M_WARN, "PKCS#11: Cannot initialize provider '%s' %ld-'%s'", provider, rv, pkcs11h_getMessage(rv)); + } + + dmsg( + D_PKCS11_DEBUG, + "PKCS#11: pkcs11_addProvider - return rv=%ld-'%s'", + rv, + pkcs11h_getMessage(rv) + ); + + return rv == CKR_OK; } int pkcs11_logout() { - return pkcs11h_logout () == CKR_OK; + return pkcs11h_logout() == CKR_OK; } int -pkcs11_management_id_count () { - pkcs11h_certificate_id_list_t id_list = NULL; - pkcs11h_certificate_id_list_t t = NULL; - CK_RV rv = CKR_OK; - int count = 0; - - dmsg ( - D_PKCS11_DEBUG, - "PKCS#11: pkcs11_management_id_count - entered" - ); - - if ( - (rv = pkcs11h_certificate_enumCertificateIds ( - PKCS11H_ENUM_METHOD_CACHE_EXIST, - NULL, - PKCS11H_PROMPT_MASK_ALLOW_ALL, - NULL, - &id_list - )) != CKR_OK - ) { - msg (M_WARN, "PKCS#11: Cannot get certificate list %ld-'%s'", rv, pkcs11h_getMessage (rv)); - goto cleanup; - } - - for (count = 0, t = id_list; t != NULL; t = t->next) { - count++; - } +pkcs11_management_id_count() { + pkcs11h_certificate_id_list_t id_list = NULL; + pkcs11h_certificate_id_list_t t = NULL; + CK_RV rv = CKR_OK; + int count = 0; + + dmsg( + D_PKCS11_DEBUG, + "PKCS#11: pkcs11_management_id_count - entered" + ); + + if ( + (rv = pkcs11h_certificate_enumCertificateIds( + PKCS11H_ENUM_METHOD_CACHE_EXIST, + NULL, + PKCS11H_PROMPT_MASK_ALLOW_ALL, + NULL, + &id_list + )) != CKR_OK + ) + { + msg(M_WARN, "PKCS#11: Cannot get certificate list %ld-'%s'", rv, pkcs11h_getMessage(rv)); + goto cleanup; + } + + for (count = 0, t = id_list; t != NULL; t = t->next) { + count++; + } cleanup: - if (id_list != NULL) { - pkcs11h_certificate_freeCertificateIdList (id_list); - id_list = NULL; - } + if (id_list != NULL) + { + pkcs11h_certificate_freeCertificateIdList(id_list); + id_list = NULL; + } - dmsg ( - D_PKCS11_DEBUG, - "PKCS#11: pkcs11_management_id_count - return count=%d", - count - ); + dmsg( + D_PKCS11_DEBUG, + "PKCS#11: pkcs11_management_id_count - return count=%d", + count + ); - return count; + return count; } bool -pkcs11_management_id_get ( - const int index, - char ** id, - char **base64 -) { - pkcs11h_certificate_id_list_t id_list = NULL; - pkcs11h_certificate_id_list_t entry = NULL; +pkcs11_management_id_get( + const int index, + char **id, + char **base64 + ) { + pkcs11h_certificate_id_list_t id_list = NULL; + pkcs11h_certificate_id_list_t entry = NULL; #if 0 /* certificate_id seems to be unused -- JY */ - pkcs11h_certificate_id_t certificate_id = NULL; + pkcs11h_certificate_id_t certificate_id = NULL; #endif - pkcs11h_certificate_t certificate = NULL; - CK_RV rv = CKR_OK; - unsigned char *certificate_blob = NULL; - size_t certificate_blob_size = 0; - size_t max; - char *internal_id = NULL; - char *internal_base64 = NULL; - int count = 0; - bool success = false; - - ASSERT (id!=NULL); - ASSERT (base64!=NULL); - - dmsg ( - D_PKCS11_DEBUG, - "PKCS#11: pkcs11_management_id_get - entered index=%d", - index - ); - - *id = NULL; - *base64 = NULL; - - if ( - (rv = pkcs11h_certificate_enumCertificateIds ( - PKCS11H_ENUM_METHOD_CACHE_EXIST, - NULL, - PKCS11H_PROMPT_MASK_ALLOW_ALL, - NULL, - &id_list - )) != CKR_OK - ) { - msg (M_WARN, "PKCS#11: Cannot get certificate list %ld-'%s'", rv, pkcs11h_getMessage (rv)); - goto cleanup; - } - - entry = id_list; - count = 0; - while (entry != NULL && count != index) { - count++; - entry = entry->next; - } - - if (entry == NULL) { - dmsg ( - D_PKCS11_DEBUG, - "PKCS#11: pkcs11_management_id_get - no certificate at index=%d", - index - ); - goto cleanup; - } - - if ( - (rv = pkcs11h_certificate_serializeCertificateId ( - NULL, - &max, - entry->certificate_id - )) != CKR_OK - ) { - msg (M_WARN, "PKCS#11: Cannot serialize certificate id %ld-'%s'", rv, pkcs11h_getMessage (rv)); - goto cleanup; - } - - if ((internal_id = (char *)malloc (max)) == NULL) { - msg (M_FATAL, "PKCS#11: Cannot allocate memory"); - goto cleanup; - } - - if ( - (rv = pkcs11h_certificate_serializeCertificateId ( - internal_id, - &max, - entry->certificate_id - )) != CKR_OK - ) { - msg (M_WARN, "PKCS#11: Cannot serialize certificate id %ld-'%s'", rv, pkcs11h_getMessage (rv)); - goto cleanup; - } - - if ( - (rv = pkcs11h_certificate_create ( - entry->certificate_id, - NULL, - PKCS11H_PROMPT_MASK_ALLOW_ALL, - PKCS11H_PIN_CACHE_INFINITE, - &certificate - )) != CKR_OK - ) { - msg (M_WARN, "PKCS#11: Cannot get certificate %ld-'%s'", rv, pkcs11h_getMessage (rv)); - goto cleanup; - } - - if ( - (rv = pkcs11h_certificate_getCertificateBlob ( - certificate, - NULL, - &certificate_blob_size - )) != CKR_OK - ) { - msg (M_WARN, "PKCS#11: Cannot get certificate blob %ld-'%s'", rv, pkcs11h_getMessage (rv)); - goto cleanup; - } - - if ((certificate_blob = (unsigned char *)malloc (certificate_blob_size)) == NULL) { - msg (M_FATAL, "PKCS#11: Cannot allocate memory"); - goto cleanup; - } - - if ( - (rv = pkcs11h_certificate_getCertificateBlob ( - certificate, - certificate_blob, - &certificate_blob_size - )) != CKR_OK - ) { - msg (M_WARN, "PKCS#11: Cannot get certificate blob %ld-'%s'", rv, pkcs11h_getMessage (rv)); - goto cleanup; - } - - if (openvpn_base64_encode (certificate_blob, certificate_blob_size, &internal_base64) == -1) { - msg (M_WARN, "PKCS#11: Cannot encode certificate"); - goto cleanup; - } - - *id = internal_id; - internal_id = NULL; - *base64 = internal_base64; - internal_base64 = NULL; - success = true; - + pkcs11h_certificate_t certificate = NULL; + CK_RV rv = CKR_OK; + unsigned char *certificate_blob = NULL; + size_t certificate_blob_size = 0; + size_t max; + char *internal_id = NULL; + char *internal_base64 = NULL; + int count = 0; + bool success = false; + + ASSERT(id!=NULL); + ASSERT(base64!=NULL); + + dmsg( + D_PKCS11_DEBUG, + "PKCS#11: pkcs11_management_id_get - entered index=%d", + index + ); + + *id = NULL; + *base64 = NULL; + + if ( + (rv = pkcs11h_certificate_enumCertificateIds( + PKCS11H_ENUM_METHOD_CACHE_EXIST, + NULL, + PKCS11H_PROMPT_MASK_ALLOW_ALL, + NULL, + &id_list + )) != CKR_OK + ) + { + msg(M_WARN, "PKCS#11: Cannot get certificate list %ld-'%s'", rv, pkcs11h_getMessage(rv)); + goto cleanup; + } + + entry = id_list; + count = 0; + while (entry != NULL && count != index) { + count++; + entry = entry->next; + } + + if (entry == NULL) + { + dmsg( + D_PKCS11_DEBUG, + "PKCS#11: pkcs11_management_id_get - no certificate at index=%d", + index + ); + goto cleanup; + } + + if ( + (rv = pkcs11h_certificate_serializeCertificateId( + NULL, + &max, + entry->certificate_id + )) != CKR_OK + ) + { + msg(M_WARN, "PKCS#11: Cannot serialize certificate id %ld-'%s'", rv, pkcs11h_getMessage(rv)); + goto cleanup; + } + + if ((internal_id = (char *)malloc(max)) == NULL) + { + msg(M_FATAL, "PKCS#11: Cannot allocate memory"); + goto cleanup; + } + + if ( + (rv = pkcs11h_certificate_serializeCertificateId( + internal_id, + &max, + entry->certificate_id + )) != CKR_OK + ) + { + msg(M_WARN, "PKCS#11: Cannot serialize certificate id %ld-'%s'", rv, pkcs11h_getMessage(rv)); + goto cleanup; + } + + if ( + (rv = pkcs11h_certificate_create( + entry->certificate_id, + NULL, + PKCS11H_PROMPT_MASK_ALLOW_ALL, + PKCS11H_PIN_CACHE_INFINITE, + &certificate + )) != CKR_OK + ) + { + msg(M_WARN, "PKCS#11: Cannot get certificate %ld-'%s'", rv, pkcs11h_getMessage(rv)); + goto cleanup; + } + + if ( + (rv = pkcs11h_certificate_getCertificateBlob( + certificate, + NULL, + &certificate_blob_size + )) != CKR_OK + ) + { + msg(M_WARN, "PKCS#11: Cannot get certificate blob %ld-'%s'", rv, pkcs11h_getMessage(rv)); + goto cleanup; + } + + if ((certificate_blob = (unsigned char *)malloc(certificate_blob_size)) == NULL) + { + msg(M_FATAL, "PKCS#11: Cannot allocate memory"); + goto cleanup; + } + + if ( + (rv = pkcs11h_certificate_getCertificateBlob( + certificate, + certificate_blob, + &certificate_blob_size + )) != CKR_OK + ) + { + msg(M_WARN, "PKCS#11: Cannot get certificate blob %ld-'%s'", rv, pkcs11h_getMessage(rv)); + goto cleanup; + } + + if (openvpn_base64_encode(certificate_blob, certificate_blob_size, &internal_base64) == -1) + { + msg(M_WARN, "PKCS#11: Cannot encode certificate"); + goto cleanup; + } + + *id = internal_id; + internal_id = NULL; + *base64 = internal_base64; + internal_base64 = NULL; + success = true; + cleanup: - if (id_list != NULL) { - pkcs11h_certificate_freeCertificateIdList (id_list); - id_list = NULL; - } - - if (internal_id != NULL) { - free (internal_id); - internal_id = NULL; - } - - if (internal_base64 != NULL) { - free (internal_base64); - internal_base64 = NULL; - } - - if (certificate_blob != NULL) { - free (certificate_blob); - certificate_blob = NULL; - } - - dmsg ( - D_PKCS11_DEBUG, - "PKCS#11: pkcs11_management_id_get - return success=%d, id='%s'", - success ? 1 : 0, - *id - ); - - return success; + if (id_list != NULL) + { + pkcs11h_certificate_freeCertificateIdList(id_list); + id_list = NULL; + } + + if (internal_id != NULL) + { + free(internal_id); + internal_id = NULL; + } + + if (internal_base64 != NULL) + { + free(internal_base64); + internal_base64 = NULL; + } + + if (certificate_blob != NULL) + { + free(certificate_blob); + certificate_blob = NULL; + } + + dmsg( + D_PKCS11_DEBUG, + "PKCS#11: pkcs11_management_id_get - return success=%d, id='%s'", + success ? 1 : 0, + *id + ); + + return success; } int -tls_ctx_use_pkcs11 ( - struct tls_root_ctx * const ssl_ctx, - bool pkcs11_id_management, - const char * const pkcs11_id -) { - pkcs11h_certificate_id_t certificate_id = NULL; - pkcs11h_certificate_t certificate = NULL; - CK_RV rv = CKR_OK; - - bool ok = false; - - ASSERT (ssl_ctx!=NULL); - ASSERT (pkcs11_id_management || pkcs11_id!=NULL); - - dmsg ( - D_PKCS11_DEBUG, - "PKCS#11: tls_ctx_use_pkcs11 - entered - ssl_ctx=%p, pkcs11_id_management=%d, pkcs11_id='%s'", - (void *)ssl_ctx, - pkcs11_id_management ? 1 : 0, - pkcs11_id - ); - - if (pkcs11_id_management) { - struct user_pass id_resp; - - CLEAR (id_resp); - - id_resp.defined = false; - id_resp.nocache = true; - openvpn_snprintf ( - id_resp.username, - sizeof (id_resp.username), - "Please specify PKCS#11 id to use" - ); - - if ( - !get_user_pass ( - &id_resp, - NULL, - "pkcs11-id-request", - GET_USER_PASS_MANAGEMENT|GET_USER_PASS_NEED_STR|GET_USER_PASS_NOFATAL - ) - ) { - goto cleanup; - } - - if ( - (rv = pkcs11h_certificate_deserializeCertificateId ( - &certificate_id, - id_resp.password - )) != CKR_OK - ) { - msg (M_WARN, "PKCS#11: Cannot deserialize id %ld-'%s'", rv, pkcs11h_getMessage (rv)); - goto cleanup; - } - } - else { - if ( - (rv = pkcs11h_certificate_deserializeCertificateId ( - &certificate_id, - pkcs11_id - )) != CKR_OK - ) { - msg (M_WARN, "PKCS#11: Cannot deserialize id %ld-'%s'", rv, pkcs11h_getMessage (rv)); - goto cleanup; - } - } - - if ( - (rv = pkcs11h_certificate_create ( - certificate_id, - NULL, - PKCS11H_PROMPT_MASK_ALLOW_ALL, - PKCS11H_PIN_CACHE_INFINITE, - &certificate - )) != CKR_OK - ) { - msg (M_WARN, "PKCS#11: Cannot get certificate %ld-'%s'", rv, pkcs11h_getMessage (rv)); - goto cleanup; - } - - if ( - (pkcs11_init_tls_session ( - certificate, - ssl_ctx - )) - ) { - /* Handled by SSL context free */ - certificate = NULL; - goto cleanup; - } - - /* Handled by SSL context free */ - certificate = NULL; - ok = true; +tls_ctx_use_pkcs11( + struct tls_root_ctx *const ssl_ctx, + bool pkcs11_id_management, + const char *const pkcs11_id + ) { + pkcs11h_certificate_id_t certificate_id = NULL; + pkcs11h_certificate_t certificate = NULL; + CK_RV rv = CKR_OK; + + bool ok = false; + + ASSERT(ssl_ctx!=NULL); + ASSERT(pkcs11_id_management || pkcs11_id!=NULL); + + dmsg( + D_PKCS11_DEBUG, + "PKCS#11: tls_ctx_use_pkcs11 - entered - ssl_ctx=%p, pkcs11_id_management=%d, pkcs11_id='%s'", + (void *)ssl_ctx, + pkcs11_id_management ? 1 : 0, + pkcs11_id + ); + + if (pkcs11_id_management) + { + struct user_pass id_resp; + + CLEAR(id_resp); + + id_resp.defined = false; + id_resp.nocache = true; + openvpn_snprintf( + id_resp.username, + sizeof(id_resp.username), + "Please specify PKCS#11 id to use" + ); + + if ( + !get_user_pass( + &id_resp, + NULL, + "pkcs11-id-request", + GET_USER_PASS_MANAGEMENT|GET_USER_PASS_NEED_STR|GET_USER_PASS_NOFATAL + ) + ) + { + goto cleanup; + } + + if ( + (rv = pkcs11h_certificate_deserializeCertificateId( + &certificate_id, + id_resp.password + )) != CKR_OK + ) + { + msg(M_WARN, "PKCS#11: Cannot deserialize id %ld-'%s'", rv, pkcs11h_getMessage(rv)); + goto cleanup; + } + } + else + { + if ( + (rv = pkcs11h_certificate_deserializeCertificateId( + &certificate_id, + pkcs11_id + )) != CKR_OK + ) + { + msg(M_WARN, "PKCS#11: Cannot deserialize id %ld-'%s'", rv, pkcs11h_getMessage(rv)); + goto cleanup; + } + } + + if ( + (rv = pkcs11h_certificate_create( + certificate_id, + NULL, + PKCS11H_PROMPT_MASK_ALLOW_ALL, + PKCS11H_PIN_CACHE_INFINITE, + &certificate + )) != CKR_OK + ) + { + msg(M_WARN, "PKCS#11: Cannot get certificate %ld-'%s'", rv, pkcs11h_getMessage(rv)); + goto cleanup; + } + + if ( + (pkcs11_init_tls_session( + certificate, + ssl_ctx + )) + ) + { + /* Handled by SSL context free */ + certificate = NULL; + goto cleanup; + } + + /* Handled by SSL context free */ + certificate = NULL; + ok = true; cleanup: - if (certificate != NULL) { - pkcs11h_certificate_freeCertificate (certificate); - certificate = NULL; - } - - if (certificate_id != NULL) { - pkcs11h_certificate_freeCertificateId (certificate_id); - certificate_id = NULL; - } - - dmsg ( - D_PKCS11_DEBUG, - "PKCS#11: tls_ctx_use_pkcs11 - return ok=%d, rv=%ld", - ok ? 1 : 0, - rv - ); - - return ok ? 1 : 0; + if (certificate != NULL) + { + pkcs11h_certificate_freeCertificate(certificate); + certificate = NULL; + } + + if (certificate_id != NULL) + { + pkcs11h_certificate_freeCertificateId(certificate_id); + certificate_id = NULL; + } + + dmsg( + D_PKCS11_DEBUG, + "PKCS#11: tls_ctx_use_pkcs11 - return ok=%d, rv=%ld", + ok ? 1 : 0, + rv + ); + + return ok ? 1 : 0; } static PKCS11H_BOOL -_pkcs11_openvpn_show_pkcs11_ids_pin_prompt ( - void * const global_data, - void * const user_data, - const pkcs11h_token_id_t token, - const unsigned retry, - char * const pin, - const size_t pin_max -) { - struct gc_arena gc = gc_new (); - struct buffer pass_prompt = alloc_buf_gc (128, &gc); - - (void)global_data; - (void)user_data; - (void)retry; - - ASSERT (token!=NULL); - - buf_printf (&pass_prompt, "Please enter '%s' token PIN or 'cancel': ", token->display); - if (!query_user_SINGLE(BSTR(&pass_prompt), BLEN(&pass_prompt), - pin, pin_max, false)) - { - msg (M_FATAL, "Could not retrieve the PIN"); - } - - gc_free (&gc); - - if (!strcmp (pin, "cancel")) { - return FALSE; - } - else { - return TRUE; - } +_pkcs11_openvpn_show_pkcs11_ids_pin_prompt( + void *const global_data, + void *const user_data, + const pkcs11h_token_id_t token, + const unsigned retry, + char *const pin, + const size_t pin_max + ) { + struct gc_arena gc = gc_new(); + struct buffer pass_prompt = alloc_buf_gc(128, &gc); + + (void)global_data; + (void)user_data; + (void)retry; + + ASSERT(token!=NULL); + + buf_printf(&pass_prompt, "Please enter '%s' token PIN or 'cancel': ", token->display); + if (!query_user_SINGLE(BSTR(&pass_prompt), BLEN(&pass_prompt), + pin, pin_max, false)) + { + msg(M_FATAL, "Could not retrieve the PIN"); + } + + gc_free(&gc); + + if (!strcmp(pin, "cancel")) + { + return FALSE; + } + else + { + return TRUE; + } } void -show_pkcs11_ids ( - const char * const provider, - bool cert_private -) { - struct gc_arena gc = gc_new(); - pkcs11h_certificate_id_list_t user_certificates = NULL; - pkcs11h_certificate_id_list_t current = NULL; - CK_RV rv = CKR_FUNCTION_FAILED; - - if ((rv = pkcs11h_initialize ()) != CKR_OK) { - msg (M_FATAL, "PKCS#11: Cannot initialize %ld-'%s'", rv, pkcs11h_getMessage (rv)); - goto cleanup; - } - - if ((rv = pkcs11h_setLogHook (_pkcs11_openvpn_log, NULL)) != CKR_OK) { - msg (M_FATAL, "PKCS#11: Cannot set hooks %ld-'%s'", rv, pkcs11h_getMessage (rv)); - goto cleanup; - } - - pkcs11h_setLogLevel (_pkcs11_msg_openvpn2pkcs11 (get_debug_level ())); - - if ((rv = pkcs11h_setProtectedAuthentication (TRUE)) != CKR_OK) { - msg (M_FATAL, "PKCS#11: Cannot set protected authentication %ld-'%s'", rv, pkcs11h_getMessage (rv)); - goto cleanup; - } - - if ((rv = pkcs11h_setPINPromptHook (_pkcs11_openvpn_show_pkcs11_ids_pin_prompt, NULL)) != CKR_OK) { - msg (M_FATAL, "PKCS#11: Cannot set PIN hook %ld-'%s'", rv, pkcs11h_getMessage (rv)); - goto cleanup; - } - - if ( - (rv = pkcs11h_addProvider ( - provider, - provider, - TRUE, - 0, - FALSE, - 0, - cert_private ? TRUE : FALSE - )) != CKR_OK - ) { - msg (M_FATAL, "PKCS#11: Cannot add provider '%s' %ld-'%s'", provider, rv, pkcs11h_getMessage (rv)); - goto cleanup; - } - - if ( - (rv = pkcs11h_certificate_enumCertificateIds ( - PKCS11H_ENUM_METHOD_CACHE_EXIST, - NULL, - PKCS11H_PROMPT_MASK_ALLOW_ALL, - NULL, - &user_certificates - )) != CKR_OK - ) { - msg (M_FATAL, "PKCS#11: Cannot enumerate certificates %ld-'%s'", rv, pkcs11h_getMessage (rv)); - goto cleanup; - } - - msg ( - M_INFO|M_NOPREFIX|M_NOLF, - ( - "\n" - "The following objects are available for use.\n" - "Each object shown below may be used as parameter to\n" - "--pkcs11-id option please remember to use single quote mark.\n" - ) - ); - for (current = user_certificates;current != NULL; current = current->next) { - pkcs11h_certificate_t certificate = NULL; - char *dn = NULL; - char serial[1024] = {0}; - char *ser = NULL; - size_t ser_len = 0; - - if ( - (rv = pkcs11h_certificate_serializeCertificateId ( - NULL, - &ser_len, - current->certificate_id - )) != CKR_OK - ) { - msg (M_FATAL, "PKCS#11: Cannot serialize certificate %ld-'%s'", rv, pkcs11h_getMessage (rv)); - goto cleanup1; - } - - if ( - rv == CKR_OK && - (ser = (char *)malloc (ser_len)) == NULL - ) { - msg (M_FATAL, "PKCS#11: Cannot allocate memory"); - goto cleanup1; - } - - if ( - (rv = pkcs11h_certificate_serializeCertificateId ( - ser, - &ser_len, - current->certificate_id - )) != CKR_OK - ) { - msg (M_FATAL, "PKCS#11: Cannot serialize certificate %ld-'%s'", rv, pkcs11h_getMessage (rv)); - goto cleanup1; - } - - if ( - (rv = pkcs11h_certificate_create ( - current->certificate_id, - NULL, - PKCS11H_PROMPT_MASK_ALLOW_ALL, - PKCS11H_PIN_CACHE_INFINITE, - &certificate - )) - ) { - msg (M_FATAL, "PKCS#11: Cannot create certificate %ld-'%s'", rv, pkcs11h_getMessage (rv)); - goto cleanup1; - } - - if ( - (dn = pkcs11_certificate_dn ( - certificate, - &gc - )) == NULL - ) { - goto cleanup1; - } - - if ( - (pkcs11_certificate_serial ( - certificate, - serial, - sizeof(serial) - )) - ) { - goto cleanup1; - } - - msg ( - M_INFO|M_NOPREFIX|M_NOLF, - ( - "\n" - "Certificate\n" - " DN: %s\n" - " Serial: %s\n" - " Serialized id: %s\n" - ), - dn, - serial, - ser - ); - - cleanup1: - - if (certificate != NULL) { - pkcs11h_certificate_freeCertificate (certificate); - certificate = NULL; - } - - if (ser != NULL) { - free (ser); - ser = NULL; - } - } +show_pkcs11_ids( + const char *const provider, + bool cert_private + ) { + struct gc_arena gc = gc_new(); + pkcs11h_certificate_id_list_t user_certificates = NULL; + pkcs11h_certificate_id_list_t current = NULL; + CK_RV rv = CKR_FUNCTION_FAILED; + + if ((rv = pkcs11h_initialize()) != CKR_OK) + { + msg(M_FATAL, "PKCS#11: Cannot initialize %ld-'%s'", rv, pkcs11h_getMessage(rv)); + goto cleanup; + } + + if ((rv = pkcs11h_setLogHook(_pkcs11_openvpn_log, NULL)) != CKR_OK) + { + msg(M_FATAL, "PKCS#11: Cannot set hooks %ld-'%s'", rv, pkcs11h_getMessage(rv)); + goto cleanup; + } + + pkcs11h_setLogLevel(_pkcs11_msg_openvpn2pkcs11(get_debug_level())); + + if ((rv = pkcs11h_setProtectedAuthentication(TRUE)) != CKR_OK) + { + msg(M_FATAL, "PKCS#11: Cannot set protected authentication %ld-'%s'", rv, pkcs11h_getMessage(rv)); + goto cleanup; + } + + if ((rv = pkcs11h_setPINPromptHook(_pkcs11_openvpn_show_pkcs11_ids_pin_prompt, NULL)) != CKR_OK) + { + msg(M_FATAL, "PKCS#11: Cannot set PIN hook %ld-'%s'", rv, pkcs11h_getMessage(rv)); + goto cleanup; + } + + if ( + (rv = pkcs11h_addProvider( + provider, + provider, + TRUE, + 0, + FALSE, + 0, + cert_private ? TRUE : FALSE + )) != CKR_OK + ) + { + msg(M_FATAL, "PKCS#11: Cannot add provider '%s' %ld-'%s'", provider, rv, pkcs11h_getMessage(rv)); + goto cleanup; + } + + if ( + (rv = pkcs11h_certificate_enumCertificateIds( + PKCS11H_ENUM_METHOD_CACHE_EXIST, + NULL, + PKCS11H_PROMPT_MASK_ALLOW_ALL, + NULL, + &user_certificates + )) != CKR_OK + ) + { + msg(M_FATAL, "PKCS#11: Cannot enumerate certificates %ld-'%s'", rv, pkcs11h_getMessage(rv)); + goto cleanup; + } + + msg( + M_INFO|M_NOPREFIX|M_NOLF, + ( + "\n" + "The following objects are available for use.\n" + "Each object shown below may be used as parameter to\n" + "--pkcs11-id option please remember to use single quote mark.\n" + ) + ); + for (current = user_certificates; current != NULL; current = current->next) { + pkcs11h_certificate_t certificate = NULL; + char *dn = NULL; + char serial[1024] = {0}; + char *ser = NULL; + size_t ser_len = 0; + + if ( + (rv = pkcs11h_certificate_serializeCertificateId( + NULL, + &ser_len, + current->certificate_id + )) != CKR_OK + ) + { + msg(M_FATAL, "PKCS#11: Cannot serialize certificate %ld-'%s'", rv, pkcs11h_getMessage(rv)); + goto cleanup1; + } + + if ( + rv == CKR_OK + && (ser = (char *)malloc(ser_len)) == NULL + ) + { + msg(M_FATAL, "PKCS#11: Cannot allocate memory"); + goto cleanup1; + } + + if ( + (rv = pkcs11h_certificate_serializeCertificateId( + ser, + &ser_len, + current->certificate_id + )) != CKR_OK + ) + { + msg(M_FATAL, "PKCS#11: Cannot serialize certificate %ld-'%s'", rv, pkcs11h_getMessage(rv)); + goto cleanup1; + } + + if ( + (rv = pkcs11h_certificate_create( + current->certificate_id, + NULL, + PKCS11H_PROMPT_MASK_ALLOW_ALL, + PKCS11H_PIN_CACHE_INFINITE, + &certificate + )) + ) + { + msg(M_FATAL, "PKCS#11: Cannot create certificate %ld-'%s'", rv, pkcs11h_getMessage(rv)); + goto cleanup1; + } + + if ( + (dn = pkcs11_certificate_dn( + certificate, + &gc + )) == NULL + ) + { + goto cleanup1; + } + + if ( + (pkcs11_certificate_serial( + certificate, + serial, + sizeof(serial) + )) + ) + { + goto cleanup1; + } + + msg( + M_INFO|M_NOPREFIX|M_NOLF, + ( + "\n" + "Certificate\n" + " DN: %s\n" + " Serial: %s\n" + " Serialized id: %s\n" + ), + dn, + serial, + ser + ); + +cleanup1: + + if (certificate != NULL) + { + pkcs11h_certificate_freeCertificate(certificate); + certificate = NULL; + } + + if (ser != NULL) + { + free(ser); + ser = NULL; + } + } cleanup: - if (user_certificates != NULL) { - pkcs11h_certificate_freeCertificateIdList (user_certificates); - user_certificates = NULL; - } - - pkcs11h_terminate (); - gc_free (&gc); + if (user_certificates != NULL) + { + pkcs11h_certificate_freeCertificateIdList(user_certificates); + user_certificates = NULL; + } + + pkcs11h_terminate(); + gc_free(&gc); } -#else +#else /* if defined(ENABLE_PKCS11) */ #ifdef _MSC_VER /* Dummy function needed to avoid empty file compiler warning in Microsoft VC */ -static void dummy (void) {} +static void +dummy(void) { +} #endif #endif /* ENABLE_PKCS11 */ diff --git a/src/openvpn/pkcs11.h b/src/openvpn/pkcs11.h index b49401ca096..621796dbf6f 100644 --- a/src/openvpn/pkcs11.h +++ b/src/openvpn/pkcs11.h @@ -30,48 +30,48 @@ #include "ssl_common.h" bool -pkcs11_initialize ( - const bool fProtectedAuthentication, - const int nPINCachePeriod -); +pkcs11_initialize( + const bool fProtectedAuthentication, + const int nPINCachePeriod + ); void -pkcs11_terminate (); +pkcs11_terminate(); bool -pkcs11_addProvider ( - const char * const provider, - const bool fProtectedAuthentication, - const unsigned private_mode, - const bool fCertIsPrivate -); +pkcs11_addProvider( + const char *const provider, + const bool fProtectedAuthentication, + const unsigned private_mode, + const bool fCertIsPrivate + ); int pkcs11_logout(); int -pkcs11_management_id_count (); +pkcs11_management_id_count(); bool -pkcs11_management_id_get ( - const int index, - char ** id, - char **base64 -); +pkcs11_management_id_get( + const int index, + char **id, + char **base64 + ); int -tls_ctx_use_pkcs11 ( - struct tls_root_ctx * const ssl_ctx, - bool pkcs11_id_management, - const char * const pkcs11_id -); +tls_ctx_use_pkcs11( + struct tls_root_ctx *const ssl_ctx, + bool pkcs11_id_management, + const char *const pkcs11_id + ); void -show_pkcs11_ids ( - const char * const provider, - bool cert_private -); +show_pkcs11_ids( + const char *const provider, + bool cert_private + ); -#endif /* ENABLE_PKCS11 */ +#endif /* ENABLE_PKCS11 */ -#endif /* OPENVPN_PKCS11H_H */ +#endif /* OPENVPN_PKCS11H_H */ diff --git a/src/openvpn/pkcs11_backend.h b/src/openvpn/pkcs11_backend.h index 7b7ec45baf3..e883d0c458e 100644 --- a/src/openvpn/pkcs11_backend.h +++ b/src/openvpn/pkcs11_backend.h @@ -41,35 +41,35 @@ /** * Retrieve PKCS #11 Certificate's DN in a printable format. * - * @param certificate The PKCS #11 helper certificate object - * @param gc Garbage collection pool to allocate memory in + * @param certificate The PKCS #11 helper certificate object + * @param gc Garbage collection pool to allocate memory in * - * @return Certificate's DN on success, NULL on failure + * @return Certificate's DN on success, NULL on failure */ -char * pkcs11_certificate_dn (pkcs11h_certificate_t certificate, struct gc_arena *gc); +char *pkcs11_certificate_dn(pkcs11h_certificate_t certificate, struct gc_arena *gc); /** * Retrieve PKCS #11 Certificate's serial number in a printable format. * - * @param certificate The PKCS #11 helper certificate object - * @param serial Buffer that the certificate's serial will be placed in. - * @param serial_len Size of said buffer. + * @param certificate The PKCS #11 helper certificate object + * @param serial Buffer that the certificate's serial will be placed in. + * @param serial_len Size of said buffer. * - * @return 1 on failure, 0 on success + * @return 1 on failure, 0 on success */ -int pkcs11_certificate_serial (pkcs11h_certificate_t certificate, char *serial, - size_t serial_len); +int pkcs11_certificate_serial(pkcs11h_certificate_t certificate, char *serial, + size_t serial_len); /** * Load PKCS #11 Certificate's information into the given TLS context * - * @param certificate The PKCS #11 helper certificate object - * @param ssl_ctx TLS context to use. + * @param certificate The PKCS #11 helper certificate object + * @param ssl_ctx TLS context to use. * - * @return 1 on failure, 0 on success + * @return 1 on failure, 0 on success */ int pkcs11_init_tls_session(pkcs11h_certificate_t certificate, - struct tls_root_ctx * const ssl_ctx); + struct tls_root_ctx *const ssl_ctx); #endif /* defined(ENABLE_PKCS11) */ #endif /* PKCS11_BACKEND_H_ */ diff --git a/src/openvpn/pkcs11_mbedtls.c b/src/openvpn/pkcs11_mbedtls.c index e208b61f1ab..874618cfebf 100644 --- a/src/openvpn/pkcs11_mbedtls.c +++ b/src/openvpn/pkcs11_mbedtls.c @@ -44,86 +44,93 @@ int pkcs11_init_tls_session(pkcs11h_certificate_t certificate, - struct tls_root_ctx * const ssl_ctx) + struct tls_root_ctx *const ssl_ctx) { - int ret = 1; - - ASSERT (NULL != ssl_ctx); - - ALLOC_OBJ_CLEAR (ssl_ctx->crt_chain, mbedtls_x509_crt); - if (mbedtls_pkcs11_x509_cert_bind(ssl_ctx->crt_chain, certificate)) { - msg (M_FATAL, "PKCS#11: Cannot retrieve mbed TLS certificate object"); - goto cleanup; - } - - ALLOC_OBJ_CLEAR (ssl_ctx->priv_key_pkcs11, mbedtls_pkcs11_context); - if (mbedtls_pkcs11_priv_key_bind(ssl_ctx->priv_key_pkcs11, certificate)) { - msg (M_FATAL, "PKCS#11: Cannot initialize mbed TLS private key object"); - goto cleanup; - } - - ALLOC_OBJ_CLEAR (ssl_ctx->priv_key, mbedtls_pk_context); - if (!mbed_ok(mbedtls_pk_setup_rsa_alt(ssl_ctx->priv_key, - ssl_ctx->priv_key_pkcs11, mbedtls_ssl_pkcs11_decrypt, - mbedtls_ssl_pkcs11_sign, mbedtls_ssl_pkcs11_key_len))) { - goto cleanup; - } - - ret = 0; + int ret = 1; + + ASSERT(NULL != ssl_ctx); + + ALLOC_OBJ_CLEAR(ssl_ctx->crt_chain, mbedtls_x509_crt); + if (mbedtls_pkcs11_x509_cert_bind(ssl_ctx->crt_chain, certificate)) + { + msg(M_FATAL, "PKCS#11: Cannot retrieve mbed TLS certificate object"); + goto cleanup; + } + + ALLOC_OBJ_CLEAR(ssl_ctx->priv_key_pkcs11, mbedtls_pkcs11_context); + if (mbedtls_pkcs11_priv_key_bind(ssl_ctx->priv_key_pkcs11, certificate)) + { + msg(M_FATAL, "PKCS#11: Cannot initialize mbed TLS private key object"); + goto cleanup; + } + + ALLOC_OBJ_CLEAR(ssl_ctx->priv_key, mbedtls_pk_context); + if (!mbed_ok(mbedtls_pk_setup_rsa_alt(ssl_ctx->priv_key, + ssl_ctx->priv_key_pkcs11, mbedtls_ssl_pkcs11_decrypt, + mbedtls_ssl_pkcs11_sign, mbedtls_ssl_pkcs11_key_len))) + { + goto cleanup; + } + + ret = 0; cleanup: - return ret; + return ret; } char * -pkcs11_certificate_dn (pkcs11h_certificate_t cert, struct gc_arena *gc) +pkcs11_certificate_dn(pkcs11h_certificate_t cert, struct gc_arena *gc) { - char *ret = NULL; - char dn[1024] = {0}; + char *ret = NULL; + char dn[1024] = {0}; - mbedtls_x509_crt mbed_crt = {0}; + mbedtls_x509_crt mbed_crt = {0}; - if (mbedtls_pkcs11_x509_cert_bind(&mbed_crt, cert)) { - msg (M_FATAL, "PKCS#11: Cannot retrieve mbed TLS certificate object"); - goto cleanup; - } + if (mbedtls_pkcs11_x509_cert_bind(&mbed_crt, cert)) + { + msg(M_FATAL, "PKCS#11: Cannot retrieve mbed TLS certificate object"); + goto cleanup; + } - if (-1 == mbedtls_x509_dn_gets (dn, sizeof(dn), &mbed_crt.subject)) { - msg (M_FATAL, "PKCS#11: mbed TLS cannot parse subject"); - goto cleanup; - } + if (-1 == mbedtls_x509_dn_gets(dn, sizeof(dn), &mbed_crt.subject)) + { + msg(M_FATAL, "PKCS#11: mbed TLS cannot parse subject"); + goto cleanup; + } - ret = string_alloc(dn, gc); + ret = string_alloc(dn, gc); cleanup: - mbedtls_x509_crt_free(&mbed_crt); + mbedtls_x509_crt_free(&mbed_crt); - return ret; + return ret; } int -pkcs11_certificate_serial (pkcs11h_certificate_t cert, char *serial, - size_t serial_len) +pkcs11_certificate_serial(pkcs11h_certificate_t cert, char *serial, + size_t serial_len) { - int ret = 1; + int ret = 1; - mbedtls_x509_crt mbed_crt = {0}; + mbedtls_x509_crt mbed_crt = {0}; - if (mbedtls_pkcs11_x509_cert_bind(&mbed_crt, cert)) { - msg (M_FATAL, "PKCS#11: Cannot retrieve mbed TLS certificate object"); - goto cleanup; - } + if (mbedtls_pkcs11_x509_cert_bind(&mbed_crt, cert)) + { + msg(M_FATAL, "PKCS#11: Cannot retrieve mbed TLS certificate object"); + goto cleanup; + } - if (-1 == mbedtls_x509_serial_gets (serial, serial_len, &mbed_crt.serial)) { - msg (M_FATAL, "PKCS#11: mbed TLS cannot parse serial"); - goto cleanup; - } + if (-1 == mbedtls_x509_serial_gets(serial, serial_len, &mbed_crt.serial)) + { + msg(M_FATAL, "PKCS#11: mbed TLS cannot parse serial"); + goto cleanup; + } - ret = 0; + ret = 0; cleanup: - mbedtls_x509_crt_free(&mbed_crt); + mbedtls_x509_crt_free(&mbed_crt); - return ret; + return ret; } #endif /* defined(ENABLE_PKCS11) && defined(ENABLE_CRYPTO_MBEDTLS) */ diff --git a/src/openvpn/pkcs11_openssl.c b/src/openvpn/pkcs11_openssl.c index 87eb166e865..bab4c900b68 100644 --- a/src/openvpn/pkcs11_openssl.c +++ b/src/openvpn/pkcs11_openssl.c @@ -44,149 +44,152 @@ int pkcs11_init_tls_session(pkcs11h_certificate_t certificate, - struct tls_root_ctx * const ssl_ctx) + struct tls_root_ctx *const ssl_ctx) { - int ret = 1; + int ret = 1; - X509 *x509 = NULL; - EVP_PKEY *evp = NULL; - pkcs11h_openssl_session_t openssl_session = NULL; + X509 *x509 = NULL; + EVP_PKEY *evp = NULL; + pkcs11h_openssl_session_t openssl_session = NULL; - if ((openssl_session = pkcs11h_openssl_createSession (certificate)) == NULL) + if ((openssl_session = pkcs11h_openssl_createSession(certificate)) == NULL) { - msg (M_WARN, "PKCS#11: Cannot initialize openssl session"); - goto cleanup; + msg(M_WARN, "PKCS#11: Cannot initialize openssl session"); + goto cleanup; } - /* - * Will be released by openssl_session - */ - certificate = NULL; + /* + * Will be released by openssl_session + */ + certificate = NULL; - if ((evp = pkcs11h_openssl_session_getEVP (openssl_session)) == NULL) + if ((evp = pkcs11h_openssl_session_getEVP(openssl_session)) == NULL) { - msg (M_WARN, "PKCS#11: Unable get evp object"); - goto cleanup; + msg(M_WARN, "PKCS#11: Unable get evp object"); + goto cleanup; } - if ((x509 = pkcs11h_openssl_session_getX509 (openssl_session)) == NULL) + if ((x509 = pkcs11h_openssl_session_getX509(openssl_session)) == NULL) { - msg (M_WARN, "PKCS#11: Unable get certificate object"); - goto cleanup; + msg(M_WARN, "PKCS#11: Unable get certificate object"); + goto cleanup; } - if (!SSL_CTX_use_PrivateKey (ssl_ctx->ctx, evp)) + if (!SSL_CTX_use_PrivateKey(ssl_ctx->ctx, evp)) { - msg (M_WARN, "PKCS#11: Cannot set private key for openssl"); - goto cleanup; + msg(M_WARN, "PKCS#11: Cannot set private key for openssl"); + goto cleanup; } - if (!SSL_CTX_use_certificate (ssl_ctx->ctx, x509)) + if (!SSL_CTX_use_certificate(ssl_ctx->ctx, x509)) { - msg (M_WARN, "PKCS#11: Cannot set certificate for openssl"); - goto cleanup; + msg(M_WARN, "PKCS#11: Cannot set certificate for openssl"); + goto cleanup; } - ret = 0; + ret = 0; cleanup: - /* - * Certificate freeing is usually handled by openssl_session. - * If something went wrong, creating the session we have to do it manually. - */ - if (certificate != NULL) { - pkcs11h_certificate_freeCertificate (certificate); - certificate = NULL; - } + /* + * Certificate freeing is usually handled by openssl_session. + * If something went wrong, creating the session we have to do it manually. + */ + if (certificate != NULL) + { + pkcs11h_certificate_freeCertificate(certificate); + certificate = NULL; + } - /* - * openssl objects have reference - * count, so release them - */ - if (x509 != NULL) + /* + * openssl objects have reference + * count, so release them + */ + if (x509 != NULL) { - X509_free (x509); - x509 = NULL; + X509_free(x509); + x509 = NULL; } - if (evp != NULL) + if (evp != NULL) { - EVP_PKEY_free (evp); - evp = NULL; + EVP_PKEY_free(evp); + evp = NULL; } - if (openssl_session != NULL) + if (openssl_session != NULL) { - pkcs11h_openssl_freeSession (openssl_session); - openssl_session = NULL; + pkcs11h_openssl_freeSession(openssl_session); + openssl_session = NULL; } - return ret; + return ret; } char * -pkcs11_certificate_dn (pkcs11h_certificate_t certificate, struct gc_arena *gc) +pkcs11_certificate_dn(pkcs11h_certificate_t certificate, struct gc_arena *gc) { - X509 *x509 = NULL; + X509 *x509 = NULL; - char *dn = NULL; + char *dn = NULL; - if ((x509 = pkcs11h_openssl_getX509 (certificate)) == NULL) + if ((x509 = pkcs11h_openssl_getX509(certificate)) == NULL) { - msg (M_FATAL, "PKCS#11: Cannot get X509"); - goto cleanup; + msg(M_FATAL, "PKCS#11: Cannot get X509"); + goto cleanup; } - dn = x509_get_subject (x509, gc); + dn = x509_get_subject(x509, gc); cleanup: - if (x509 != NULL) + if (x509 != NULL) { - X509_free (x509); - x509 = NULL; + X509_free(x509); + x509 = NULL; } - return dn; + return dn; } int -pkcs11_certificate_serial (pkcs11h_certificate_t certificate, char *serial, - size_t serial_len) +pkcs11_certificate_serial(pkcs11h_certificate_t certificate, char *serial, + size_t serial_len) { - X509 *x509 = NULL; - BIO *bio = NULL; - int ret = 1; - int n; + X509 *x509 = NULL; + BIO *bio = NULL; + int ret = 1; + int n; - if ((x509 = pkcs11h_openssl_getX509 (certificate)) == NULL) + if ((x509 = pkcs11h_openssl_getX509(certificate)) == NULL) { - msg (M_FATAL, "PKCS#11: Cannot get X509"); - goto cleanup; + msg(M_FATAL, "PKCS#11: Cannot get X509"); + goto cleanup; } - if ((bio = BIO_new (BIO_s_mem ())) == NULL) + if ((bio = BIO_new(BIO_s_mem())) == NULL) { - msg (M_FATAL, "PKCS#11: Cannot create BIO"); - goto cleanup; + msg(M_FATAL, "PKCS#11: Cannot create BIO"); + goto cleanup; } - i2a_ASN1_INTEGER(bio, X509_get_serialNumber (x509)); - n = BIO_read (bio, serial, serial_len-1); + i2a_ASN1_INTEGER(bio, X509_get_serialNumber(x509)); + n = BIO_read(bio, serial, serial_len-1); - if (n<0) { - serial[0] = '\x0'; - } - else { - serial[n] = 0; - } + if (n<0) + { + serial[0] = '\x0'; + } + else + { + serial[n] = 0; + } - ret = 0; + ret = 0; cleanup: - if (x509 != NULL) + if (x509 != NULL) { - X509_free (x509); - x509 = NULL; + X509_free(x509); + x509 = NULL; } - return ret; + return ret; } #endif /* defined(ENABLE_PKCS11) && defined(ENABLE_OPENSSL) */ diff --git a/src/openvpn/platform.c b/src/openvpn/platform.c index 634364726c9..3deed32665e 100644 --- a/src/openvpn/platform.c +++ b/src/openvpn/platform.c @@ -39,21 +39,25 @@ #include "platform.h" /* Redefine the top level directory of the filesystem - to restrict access to files for security */ + * to restrict access to files for security */ void -platform_chroot (const char *path) +platform_chroot(const char *path) { - if (path) + if (path) { #ifdef HAVE_CHROOT - const char *top = "/"; - if (chroot (path)) - msg (M_ERR, "chroot to '%s' failed", path); - if (platform_chdir (top)) - msg (M_ERR, "cd to '%s' failed", top); - msg (M_INFO, "chroot to '%s' and cd to '%s' succeeded", path, top); -#else - msg (M_FATAL, "Sorry but I can't chroot to '%s' because this operating system doesn't appear to support the chroot() system call", path); + const char *top = "/"; + if (chroot(path)) + { + msg(M_ERR, "chroot to '%s' failed", path); + } + if (platform_chdir(top)) + { + msg(M_ERR, "cd to '%s' failed", top); + } + msg(M_INFO, "chroot to '%s' and cd to '%s' succeeded", path, top); +#else /* ifdef HAVE_CHROOT */ + msg(M_FATAL, "Sorry but I can't chroot to '%s' because this operating system doesn't appear to support the chroot() system call", path); #endif } } @@ -61,34 +65,38 @@ platform_chroot (const char *path) /* Get/Set UID of process */ bool -platform_user_get (const char *username, struct platform_state_user *state) +platform_user_get(const char *username, struct platform_state_user *state) { - bool ret = false; - CLEAR (*state); - if (username) + bool ret = false; + CLEAR(*state); + if (username) { #if defined(HAVE_GETPWNAM) && defined(HAVE_SETUID) - state->pw = getpwnam (username); - if (!state->pw) - msg (M_ERR, "failed to find UID for user %s", username); - state->username = username; - ret = true; -#else - msg (M_FATAL, "cannot get UID for user %s -- platform lacks getpwname() or setuid() system calls", username); + state->pw = getpwnam(username); + if (!state->pw) + { + msg(M_ERR, "failed to find UID for user %s", username); + } + state->username = username; + ret = true; +#else /* if defined(HAVE_GETPWNAM) && defined(HAVE_SETUID) */ + msg(M_FATAL, "cannot get UID for user %s -- platform lacks getpwname() or setuid() system calls", username); #endif } - return ret; + return ret; } void -platform_user_set (const struct platform_state_user *state) +platform_user_set(const struct platform_state_user *state) { #if defined(HAVE_GETPWNAM) && defined(HAVE_SETUID) - if (state->username && state->pw) + if (state->username && state->pw) { - if (setuid (state->pw->pw_uid)) - msg (M_ERR, "setuid('%s') failed", state->username); - msg (M_INFO, "UID set to %s", state->username); + if (setuid(state->pw->pw_uid)) + { + msg(M_ERR, "setuid('%s') failed", state->username); + } + msg(M_INFO, "UID set to %s", state->username); } #endif } @@ -96,41 +104,47 @@ platform_user_set (const struct platform_state_user *state) /* Get/Set GID of process */ bool -platform_group_get (const char *groupname, struct platform_state_group *state) +platform_group_get(const char *groupname, struct platform_state_group *state) { - bool ret = false; - CLEAR (*state); - if (groupname) + bool ret = false; + CLEAR(*state); + if (groupname) { #if defined(HAVE_GETGRNAM) && defined(HAVE_SETGID) - state->gr = getgrnam (groupname); - if (!state->gr) - msg (M_ERR, "failed to find GID for group %s", groupname); - state->groupname = groupname; - ret = true; -#else - msg (M_FATAL, "cannot get GID for group %s -- platform lacks getgrnam() or setgid() system calls", groupname); + state->gr = getgrnam(groupname); + if (!state->gr) + { + msg(M_ERR, "failed to find GID for group %s", groupname); + } + state->groupname = groupname; + ret = true; +#else /* if defined(HAVE_GETGRNAM) && defined(HAVE_SETGID) */ + msg(M_FATAL, "cannot get GID for group %s -- platform lacks getgrnam() or setgid() system calls", groupname); #endif } - return ret; + return ret; } void -platform_group_set (const struct platform_state_group *state) +platform_group_set(const struct platform_state_group *state) { #if defined(HAVE_GETGRNAM) && defined(HAVE_SETGID) - if (state->groupname && state->gr) + if (state->groupname && state->gr) { - if (setgid (state->gr->gr_gid)) - msg (M_ERR, "setgid('%s') failed", state->groupname); - msg (M_INFO, "GID set to %s", state->groupname); + if (setgid(state->gr->gr_gid)) + { + msg(M_ERR, "setgid('%s') failed", state->groupname); + } + msg(M_INFO, "GID set to %s", state->groupname); #ifdef HAVE_SETGROUPS - { - gid_t gr_list[1]; - gr_list[0] = state->gr->gr_gid; - if (setgroups (1, gr_list)) - msg (M_ERR, "setgroups('%s') failed", state->groupname); - } + { + gid_t gr_list[1]; + gr_list[0] = state->gr->gr_gid; + if (setgroups(1, gr_list)) + { + msg(M_ERR, "setgroups('%s') failed", state->groupname); + } + } #endif } #endif @@ -138,33 +152,37 @@ platform_group_set (const struct platform_state_group *state) /* Change process priority */ void -platform_nice (int niceval) +platform_nice(int niceval) { - if (niceval) + if (niceval) { #ifdef HAVE_NICE - errno = 0; - if (nice (niceval) < 0 && errno != 0) - msg (M_WARN | M_ERRNO, "WARNING: nice %d failed: %s", niceval, strerror(errno)); - else - msg (M_INFO, "nice %d succeeded", niceval); -#else - msg (M_WARN, "WARNING: nice %d failed (function not implemented)", niceval); + errno = 0; + if (nice(niceval) < 0 && errno != 0) + { + msg(M_WARN | M_ERRNO, "WARNING: nice %d failed: %s", niceval, strerror(errno)); + } + else + { + msg(M_INFO, "nice %d succeeded", niceval); + } +#else /* ifdef HAVE_NICE */ + msg(M_WARN, "WARNING: nice %d failed (function not implemented)", niceval); #endif } } /* Get current PID */ unsigned int -platform_getpid () +platform_getpid() { #ifdef _WIN32 - return (unsigned int) GetCurrentProcessId (); + return (unsigned int) GetCurrentProcessId(); #else #ifdef HAVE_GETPID - return (unsigned int) getpid (); + return (unsigned int) getpid(); #else - return 0; + return 0; #endif #endif } @@ -174,12 +192,16 @@ void platform_mlockall(bool print_msg) { #ifdef HAVE_MLOCKALL - if (mlockall (MCL_CURRENT | MCL_FUTURE)) - msg (M_WARN | M_ERRNO, "WARNING: mlockall call failed"); - else if (print_msg) - msg (M_INFO, "mlockall call succeeded"); -#else - msg (M_WARN, "WARNING: mlockall call failed (function not implemented)"); + if (mlockall(MCL_CURRENT | MCL_FUTURE)) + { + msg(M_WARN | M_ERRNO, "WARNING: mlockall call failed"); + } + else if (print_msg) + { + msg(M_INFO, "mlockall call succeeded"); + } +#else /* ifdef HAVE_MLOCKALL */ + msg(M_WARN, "WARNING: mlockall call failed (function not implemented)"); #endif } @@ -187,20 +209,20 @@ platform_mlockall(bool print_msg) * Wrapper for chdir library function */ int -platform_chdir (const char* dir) +platform_chdir(const char *dir) { #ifdef HAVE_CHDIR #ifdef _WIN32 - int res; - struct gc_arena gc = gc_new (); - res = _wchdir (wide_string (dir, &gc)); - gc_free (&gc); - return res; -#else - return chdir (dir); + int res; + struct gc_arena gc = gc_new(); + res = _wchdir(wide_string(dir, &gc)); + gc_free(&gc); + return res; +#else /* ifdef _WIN32 */ + return chdir(dir); #endif -#else - return -1; +#else /* ifdef HAVE_CHDIR */ + return -1; #endif } @@ -208,25 +230,25 @@ platform_chdir (const char* dir) * convert execve() return into a success/failure value */ bool -platform_system_ok (int stat) +platform_system_ok(int stat) { #ifdef _WIN32 - return stat == 0; + return stat == 0; #else - return stat != -1 && WIFEXITED (stat) && WEXITSTATUS (stat) == 0; + return stat != -1 && WIFEXITED(stat) && WEXITSTATUS(stat) == 0; #endif } int -platform_access (const char *path, int mode) +platform_access(const char *path, int mode) { #ifdef _WIN32 - struct gc_arena gc = gc_new (); - int ret = _waccess (wide_string (path, &gc), mode & ~X_OK); - gc_free (&gc); - return ret; + struct gc_arena gc = gc_new(); + int ret = _waccess(wide_string(path, &gc), mode & ~X_OK); + gc_free(&gc); + return ret; #else - return access (path, mode); + return access(path, mode); #endif } @@ -234,15 +256,15 @@ platform_access (const char *path, int mode) * Go to sleep for n milliseconds. */ void -platform_sleep_milliseconds (unsigned int n) +platform_sleep_milliseconds(unsigned int n) { #ifdef _WIN32 - Sleep (n); + Sleep(n); #else - struct timeval tv; - tv.tv_sec = n / 1000; - tv.tv_usec = (n % 1000) * 1000; - select (0, NULL, NULL, NULL, &tv); + struct timeval tv; + tv.tv_sec = n / 1000; + tv.tv_usec = (n % 1000) * 1000; + select(0, NULL, NULL, NULL, &tv); #endif } @@ -250,67 +272,67 @@ platform_sleep_milliseconds (unsigned int n) * Go to sleep indefinitely. */ void -platform_sleep_until_signal (void) +platform_sleep_until_signal(void) { #ifdef _WIN32 - ASSERT (0); + ASSERT(0); #else - select (0, NULL, NULL, NULL, NULL); + select(0, NULL, NULL, NULL, NULL); #endif } /* delete a file, return true if succeeded */ bool -platform_unlink (const char *filename) +platform_unlink(const char *filename) { #if defined(_WIN32) - struct gc_arena gc = gc_new (); - BOOL ret = DeleteFileW (wide_string (filename, &gc)); - gc_free (&gc); - return (ret != 0); + struct gc_arena gc = gc_new(); + BOOL ret = DeleteFileW(wide_string(filename, &gc)); + gc_free(&gc); + return (ret != 0); #elif defined(HAVE_UNLINK) - return (unlink (filename) == 0); -#else - return false; + return (unlink(filename) == 0); +#else /* if defined(_WIN32) */ + return false; #endif } FILE * -platform_fopen (const char *path, const char *mode) +platform_fopen(const char *path, const char *mode) { #ifdef _WIN32 - struct gc_arena gc = gc_new (); - FILE *f = _wfopen (wide_string (path, &gc), wide_string (mode, &gc)); - gc_free (&gc); - return f; + struct gc_arena gc = gc_new(); + FILE *f = _wfopen(wide_string(path, &gc), wide_string(mode, &gc)); + gc_free(&gc); + return f; #else - return fopen(path, mode); + return fopen(path, mode); #endif } int -platform_open (const char *path, int flags, int mode) +platform_open(const char *path, int flags, int mode) { #ifdef _WIN32 - struct gc_arena gc = gc_new (); - int fd = _wopen (wide_string (path, &gc), flags, mode); - gc_free (&gc); - return fd; + struct gc_arena gc = gc_new(); + int fd = _wopen(wide_string(path, &gc), flags, mode); + gc_free(&gc); + return fd; #else - return open(path, flags, mode); + return open(path, flags, mode); #endif } int -platform_stat (const char *path, platform_stat_t *buf) +platform_stat(const char *path, platform_stat_t *buf) { #ifdef _WIN32 - struct gc_arena gc = gc_new (); - int res = _wstat (wide_string (path, &gc), buf); - gc_free (&gc); - return res; + struct gc_arena gc = gc_new(); + int res = _wstat(wide_string(path, &gc), buf); + gc_free(&gc); + return res; #else - return stat(path, buf); + return stat(path, buf); #endif } diff --git a/src/openvpn/platform.h b/src/openvpn/platform.h index fe2685aeef1..a43ee13b678 100644 --- a/src/openvpn/platform.h +++ b/src/openvpn/platform.h @@ -55,10 +55,10 @@ struct platform_state_user { #if defined(HAVE_GETPWNAM) && defined(HAVE_SETUID) - const char *username; - struct passwd *pw; + const char *username; + struct passwd *pw; #else - int dummy; + int dummy; #endif }; @@ -66,75 +66,82 @@ struct platform_state_user { struct platform_state_group { #if defined(HAVE_GETGRNAM) && defined(HAVE_SETGID) - const char *groupname; - struct group *gr; + const char *groupname; + struct group *gr; #else - int dummy; + int dummy; #endif }; -bool platform_user_get (const char *username, struct platform_state_user *state); -void platform_user_set (const struct platform_state_user *state); +bool platform_user_get(const char *username, struct platform_state_user *state); -bool platform_group_get (const char *groupname, struct platform_state_group *state); -void platform_group_set (const struct platform_state_group *state); +void platform_user_set(const struct platform_state_user *state); + +bool platform_group_get(const char *groupname, struct platform_state_group *state); + +void platform_group_set(const struct platform_state_group *state); /* * Extract UID or GID */ static inline int -platform_state_user_uid (const struct platform_state_user *s) +platform_state_user_uid(const struct platform_state_user *s) { #if defined(HAVE_GETPWNAM) && defined(HAVE_SETUID) - if (s->pw) - return s->pw->pw_uid; + if (s->pw) + { + return s->pw->pw_uid; + } #endif - return -1; + return -1; } static inline int -platform_state_group_gid (const struct platform_state_group *s) +platform_state_group_gid(const struct platform_state_group *s) { #if defined(HAVE_GETGRNAM) && defined(HAVE_SETGID) - if (s->gr) - return s->gr->gr_gid; + if (s->gr) + { + return s->gr->gr_gid; + } #endif - return -1; + return -1; } -void platform_chroot (const char *path); +void platform_chroot(const char *path); -void platform_nice (int niceval); +void platform_nice(int niceval); -unsigned int platform_getpid (void); +unsigned int platform_getpid(void); -void platform_mlockall (bool print_msg); /* Disable paging */ +void platform_mlockall(bool print_msg); /* Disable paging */ -int platform_chdir (const char* dir); +int platform_chdir(const char *dir); /* interpret the status code returned by execve() */ -bool platform_system_ok (int stat); +bool platform_system_ok(int stat); -int platform_access (const char *path, int mode); +int platform_access(const char *path, int mode); -void platform_sleep_milliseconds (unsigned int n); +void platform_sleep_milliseconds(unsigned int n); -void platform_sleep_until_signal (void); +void platform_sleep_until_signal(void); /* delete a file, return true if succeeded */ -bool platform_unlink (const char *filename); +bool platform_unlink(const char *filename); -int platform_putenv (char *string); +int platform_putenv(char *string); -FILE *platform_fopen (const char *path, const char *mode); -int platform_open (const char *path, int flags, int mode); +FILE *platform_fopen(const char *path, const char *mode); + +int platform_open(const char *path, int flags, int mode); #ifdef _WIN32 typedef struct _stat platform_stat_t; #else typedef struct stat platform_stat_t; #endif -int platform_stat (const char *path, platform_stat_t *buf); +int platform_stat(const char *path, platform_stat_t *buf); -#endif +#endif /* ifndef PLATFORM_H */ diff --git a/src/openvpn/plugin.c b/src/openvpn/plugin.c index 24434383d32..dab9c93fcd4 100644 --- a/src/openvpn/plugin.c +++ b/src/openvpn/plugin.c @@ -53,301 +53,356 @@ static struct plugin_common *static_plugin_common = NULL; /* GLOBAL */ static void -plugin_show_string_array (int msglevel, const char *name, const char *array[]) +plugin_show_string_array(int msglevel, const char *name, const char *array[]) { - int i; - for (i = 0; array[i]; ++i) + int i; + for (i = 0; array[i]; ++i) { - if (env_safe_to_print (array[i])) - msg (msglevel, "%s[%d] = '%s'", name, i, array[i]); + if (env_safe_to_print(array[i])) + { + msg(msglevel, "%s[%d] = '%s'", name, i, array[i]); + } } } static void -plugin_show_args_env (int msglevel, const char *argv[], const char *envp[]) +plugin_show_args_env(int msglevel, const char *argv[], const char *envp[]) { - if (check_debug_level (msglevel)) + if (check_debug_level(msglevel)) { - plugin_show_string_array (msglevel, "ARGV", argv); - plugin_show_string_array (msglevel, "ENVP", envp); + plugin_show_string_array(msglevel, "ARGV", argv); + plugin_show_string_array(msglevel, "ENVP", envp); } } static const char * -plugin_type_name (const int type) -{ - switch (type) - { - case OPENVPN_PLUGIN_UP: - return "PLUGIN_UP"; - case OPENVPN_PLUGIN_DOWN: - return "PLUGIN_DOWN"; - case OPENVPN_PLUGIN_ROUTE_UP: - return "PLUGIN_ROUTE_UP"; - case OPENVPN_PLUGIN_IPCHANGE: - return "PLUGIN_IPCHANGE"; - case OPENVPN_PLUGIN_TLS_VERIFY: - return "PLUGIN_TLS_VERIFY"; - case OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY: - return "PLUGIN_AUTH_USER_PASS_VERIFY"; - case OPENVPN_PLUGIN_CLIENT_CONNECT: - return "PLUGIN_CLIENT_CONNECT"; - case OPENVPN_PLUGIN_CLIENT_CONNECT_V2: - return "PLUGIN_CLIENT_CONNECT"; - case OPENVPN_PLUGIN_CLIENT_DISCONNECT: - return "PLUGIN_CLIENT_DISCONNECT"; - case OPENVPN_PLUGIN_LEARN_ADDRESS: - return "PLUGIN_LEARN_ADDRESS"; - case OPENVPN_PLUGIN_TLS_FINAL: - return "PLUGIN_TLS_FINAL"; - case OPENVPN_PLUGIN_ENABLE_PF: - return "PLUGIN_ENABLE_PF"; - case OPENVPN_PLUGIN_ROUTE_PREDOWN: - return "PLUGIN_ROUTE_PREDOWN"; - default: - return "PLUGIN_???"; +plugin_type_name(const int type) +{ + switch (type) + { + case OPENVPN_PLUGIN_UP: + return "PLUGIN_UP"; + + case OPENVPN_PLUGIN_DOWN: + return "PLUGIN_DOWN"; + + case OPENVPN_PLUGIN_ROUTE_UP: + return "PLUGIN_ROUTE_UP"; + + case OPENVPN_PLUGIN_IPCHANGE: + return "PLUGIN_IPCHANGE"; + + case OPENVPN_PLUGIN_TLS_VERIFY: + return "PLUGIN_TLS_VERIFY"; + + case OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY: + return "PLUGIN_AUTH_USER_PASS_VERIFY"; + + case OPENVPN_PLUGIN_CLIENT_CONNECT: + return "PLUGIN_CLIENT_CONNECT"; + + case OPENVPN_PLUGIN_CLIENT_CONNECT_V2: + return "PLUGIN_CLIENT_CONNECT"; + + case OPENVPN_PLUGIN_CLIENT_DISCONNECT: + return "PLUGIN_CLIENT_DISCONNECT"; + + case OPENVPN_PLUGIN_LEARN_ADDRESS: + return "PLUGIN_LEARN_ADDRESS"; + + case OPENVPN_PLUGIN_TLS_FINAL: + return "PLUGIN_TLS_FINAL"; + + case OPENVPN_PLUGIN_ENABLE_PF: + return "PLUGIN_ENABLE_PF"; + + case OPENVPN_PLUGIN_ROUTE_PREDOWN: + return "PLUGIN_ROUTE_PREDOWN"; + + default: + return "PLUGIN_???"; } } static const char * -plugin_mask_string (const unsigned int type_mask, struct gc_arena *gc) +plugin_mask_string(const unsigned int type_mask, struct gc_arena *gc) { - struct buffer out = alloc_buf_gc (256, gc); - bool first = true; - int i; + struct buffer out = alloc_buf_gc(256, gc); + bool first = true; + int i; - for (i = 0; i < OPENVPN_PLUGIN_N; ++i) + for (i = 0; i < OPENVPN_PLUGIN_N; ++i) { - if (OPENVPN_PLUGIN_MASK (i) & type_mask) - { - if (!first) - buf_printf (&out, "|"); - buf_printf (&out, "%s", plugin_type_name (i)); - first = false; - } + if (OPENVPN_PLUGIN_MASK(i) & type_mask) + { + if (!first) + { + buf_printf(&out, "|"); + } + buf_printf(&out, "%s", plugin_type_name(i)); + first = false; + } } - return BSTR (&out); + return BSTR(&out); } static inline unsigned int -plugin_supported_types (void) +plugin_supported_types(void) { - return ((1<n < MAX_PLUGINS) + if (list->n < MAX_PLUGINS) { - struct plugin_option *o = &list->plugins[list->n++]; - o->argv = make_extended_arg_array (p, gc); - if (o->argv[0]) - o->so_pathname = o->argv[0]; - return true; + struct plugin_option *o = &list->plugins[list->n++]; + o->argv = make_extended_arg_array(p, gc); + if (o->argv[0]) + { + o->so_pathname = o->argv[0]; + } + return true; + } + else + { + return false; } - else - return false; } #ifndef ENABLE_SMALL void -plugin_option_list_print (const struct plugin_option_list *list, int msglevel) +plugin_option_list_print(const struct plugin_option_list *list, int msglevel) { - int i; - struct gc_arena gc = gc_new (); + int i; + struct gc_arena gc = gc_new(); - for (i = 0; i < list->n; ++i) + for (i = 0; i < list->n; ++i) { - const struct plugin_option *o = &list->plugins[i]; - msg (msglevel, " plugin[%d] %s '%s'", i, o->so_pathname, print_argv (o->argv, &gc, PA_BRACKET)); + const struct plugin_option *o = &list->plugins[i]; + msg(msglevel, " plugin[%d] %s '%s'", i, o->so_pathname, print_argv(o->argv, &gc, PA_BRACKET)); } - gc_free (&gc); + gc_free(&gc); } #endif #ifndef _WIN32 static void -libdl_resolve_symbol (void *handle, void **dest, const char *symbol, const char *plugin_name, const unsigned int flags) +libdl_resolve_symbol(void *handle, void **dest, const char *symbol, const char *plugin_name, const unsigned int flags) { - *dest = dlsym (handle, symbol); - if ((flags & PLUGIN_SYMBOL_REQUIRED) && !*dest) - msg (M_FATAL, "PLUGIN: could not find required symbol '%s' in plugin shared object %s: %s", symbol, plugin_name, dlerror()); + *dest = dlsym(handle, symbol); + if ((flags & PLUGIN_SYMBOL_REQUIRED) && !*dest) + { + msg(M_FATAL, "PLUGIN: could not find required symbol '%s' in plugin shared object %s: %s", symbol, plugin_name, dlerror()); + } } -#else +#else /* ifndef _WIN32 */ static void -dll_resolve_symbol (HMODULE module, void **dest, const char *symbol, const char *plugin_name, const unsigned int flags) +dll_resolve_symbol(HMODULE module, void **dest, const char *symbol, const char *plugin_name, const unsigned int flags) { - *dest = GetProcAddress (module, symbol); - if ((flags & PLUGIN_SYMBOL_REQUIRED) && !*dest) - msg (M_FATAL, "PLUGIN: could not find required symbol '%s' in plugin DLL %s", symbol, plugin_name); + *dest = GetProcAddress(module, symbol); + if ((flags & PLUGIN_SYMBOL_REQUIRED) && !*dest) + { + msg(M_FATAL, "PLUGIN: could not find required symbol '%s' in plugin DLL %s", symbol, plugin_name); + } } -#endif +#endif /* ifndef _WIN32 */ static void -plugin_init_item (struct plugin *p, const struct plugin_option *o) +plugin_init_item(struct plugin *p, const struct plugin_option *o) { - struct gc_arena gc = gc_new (); - bool rel = false; + struct gc_arena gc = gc_new(); + bool rel = false; - p->so_pathname = o->so_pathname; - p->plugin_type_mask = plugin_supported_types (); + p->so_pathname = o->so_pathname; + p->plugin_type_mask = plugin_supported_types(); #ifndef _WIN32 - p->handle = NULL; + p->handle = NULL; #if defined(PLUGIN_LIBDIR) - if (!absolute_pathname (p->so_pathname)) + if (!absolute_pathname(p->so_pathname)) { - char full[PATH_MAX]; + char full[PATH_MAX]; - openvpn_snprintf (full, sizeof(full), "%s/%s", PLUGIN_LIBDIR, p->so_pathname); - p->handle = dlopen (full, RTLD_NOW); + openvpn_snprintf(full, sizeof(full), "%s/%s", PLUGIN_LIBDIR, p->so_pathname); + p->handle = dlopen(full, RTLD_NOW); #if defined(ENABLE_PLUGIN_SEARCH) - if (!p->handle) - { - rel = true; - p->handle = dlopen (p->so_pathname, RTLD_NOW); - } + if (!p->handle) + { + rel = true; + p->handle = dlopen(p->so_pathname, RTLD_NOW); + } #endif } - else + else #endif { - rel = !absolute_pathname (p->so_pathname); - p->handle = dlopen (p->so_pathname, RTLD_NOW); + rel = !absolute_pathname(p->so_pathname); + p->handle = dlopen(p->so_pathname, RTLD_NOW); + } + if (!p->handle) + { + msg(M_ERR, "PLUGIN_INIT: could not load plugin shared object %s: %s", p->so_pathname, dlerror()); } - if (!p->handle) - msg (M_ERR, "PLUGIN_INIT: could not load plugin shared object %s: %s", p->so_pathname, dlerror()); -# define PLUGIN_SYM(var, name, flags) libdl_resolve_symbol (p->handle, (void*)&p->var, name, p->so_pathname, flags) +#define PLUGIN_SYM(var, name, flags) libdl_resolve_symbol(p->handle, (void *)&p->var, name, p->so_pathname, flags) -#else +#else /* ifndef _WIN32 */ - rel = !absolute_pathname (p->so_pathname); - p->module = LoadLibraryW (wide_string (p->so_pathname, &gc)); - if (!p->module) - msg (M_ERR, "PLUGIN_INIT: could not load plugin DLL: %s", p->so_pathname); + rel = !absolute_pathname(p->so_pathname); + p->module = LoadLibraryW(wide_string(p->so_pathname, &gc)); + if (!p->module) + { + msg(M_ERR, "PLUGIN_INIT: could not load plugin DLL: %s", p->so_pathname); + } -# define PLUGIN_SYM(var, name, flags) dll_resolve_symbol (p->module, (void*)&p->var, name, p->so_pathname, flags) +#define PLUGIN_SYM(var, name, flags) dll_resolve_symbol(p->module, (void *)&p->var, name, p->so_pathname, flags) -#endif +#endif /* ifndef _WIN32 */ - PLUGIN_SYM (open1, "openvpn_plugin_open_v1", 0); - PLUGIN_SYM (open2, "openvpn_plugin_open_v2", 0); - PLUGIN_SYM (open3, "openvpn_plugin_open_v3", 0); - PLUGIN_SYM (func1, "openvpn_plugin_func_v1", 0); - PLUGIN_SYM (func2, "openvpn_plugin_func_v2", 0); - PLUGIN_SYM (func3, "openvpn_plugin_func_v3", 0); - PLUGIN_SYM (close, "openvpn_plugin_close_v1", PLUGIN_SYMBOL_REQUIRED); - PLUGIN_SYM (abort, "openvpn_plugin_abort_v1", 0); - PLUGIN_SYM (client_constructor, "openvpn_plugin_client_constructor_v1", 0); - PLUGIN_SYM (client_destructor, "openvpn_plugin_client_destructor_v1", 0); - PLUGIN_SYM (min_version_required, "openvpn_plugin_min_version_required_v1", 0); - PLUGIN_SYM (initialization_point, "openvpn_plugin_select_initialization_point_v1", 0); + PLUGIN_SYM(open1, "openvpn_plugin_open_v1", 0); + PLUGIN_SYM(open2, "openvpn_plugin_open_v2", 0); + PLUGIN_SYM(open3, "openvpn_plugin_open_v3", 0); + PLUGIN_SYM(func1, "openvpn_plugin_func_v1", 0); + PLUGIN_SYM(func2, "openvpn_plugin_func_v2", 0); + PLUGIN_SYM(func3, "openvpn_plugin_func_v3", 0); + PLUGIN_SYM(close, "openvpn_plugin_close_v1", PLUGIN_SYMBOL_REQUIRED); + PLUGIN_SYM(abort, "openvpn_plugin_abort_v1", 0); + PLUGIN_SYM(client_constructor, "openvpn_plugin_client_constructor_v1", 0); + PLUGIN_SYM(client_destructor, "openvpn_plugin_client_destructor_v1", 0); + PLUGIN_SYM(min_version_required, "openvpn_plugin_min_version_required_v1", 0); + PLUGIN_SYM(initialization_point, "openvpn_plugin_select_initialization_point_v1", 0); - if (!p->open1 && !p->open2 && !p->open3) - msg (M_FATAL, "PLUGIN: symbol openvpn_plugin_open_vX is undefined in plugin: %s", p->so_pathname); + if (!p->open1 && !p->open2 && !p->open3) + { + msg(M_FATAL, "PLUGIN: symbol openvpn_plugin_open_vX is undefined in plugin: %s", p->so_pathname); + } - if (!p->func1 && !p->func2 && !p->func3) - msg (M_FATAL, "PLUGIN: symbol openvpn_plugin_func_vX is undefined in plugin: %s", p->so_pathname); + if (!p->func1 && !p->func2 && !p->func3) + { + msg(M_FATAL, "PLUGIN: symbol openvpn_plugin_func_vX is undefined in plugin: %s", p->so_pathname); + } - /* - * Verify that we are sufficiently up-to-date to handle the plugin - */ - if (p->min_version_required) + /* + * Verify that we are sufficiently up-to-date to handle the plugin + */ + if (p->min_version_required) { - const int plugin_needs_version = (*p->min_version_required)(); - if (plugin_needs_version > OPENVPN_PLUGIN_VERSION) - msg (M_FATAL, "PLUGIN_INIT: plugin needs interface version %d, but this version of OpenVPN only supports version %d: %s", - plugin_needs_version, - OPENVPN_PLUGIN_VERSION, - p->so_pathname); + const int plugin_needs_version = (*p->min_version_required)(); + if (plugin_needs_version > OPENVPN_PLUGIN_VERSION) + { + msg(M_FATAL, "PLUGIN_INIT: plugin needs interface version %d, but this version of OpenVPN only supports version %d: %s", + plugin_needs_version, + OPENVPN_PLUGIN_VERSION, + p->so_pathname); + } } - if (p->initialization_point) - p->requested_initialization_point = (*p->initialization_point)(); - else - p->requested_initialization_point = OPENVPN_PLUGIN_INIT_PRE_DAEMON; + if (p->initialization_point) + { + p->requested_initialization_point = (*p->initialization_point)(); + } + else + { + p->requested_initialization_point = OPENVPN_PLUGIN_INIT_PRE_DAEMON; + } - if (rel) - msg (M_WARN, "WARNING: plugin '%s' specified by a relative pathname -- using an absolute pathname would be more secure", p->so_pathname); + if (rel) + { + msg(M_WARN, "WARNING: plugin '%s' specified by a relative pathname -- using an absolute pathname would be more secure", p->so_pathname); + } - p->initialized = true; + p->initialized = true; - gc_free (&gc); + gc_free(&gc); } static void -plugin_vlog (openvpn_plugin_log_flags_t flags, const char *name, const char *format, va_list arglist) +plugin_vlog(openvpn_plugin_log_flags_t flags, const char *name, const char *format, va_list arglist) { - unsigned int msg_flags = 0; + unsigned int msg_flags = 0; - if (!format) - return; + if (!format) + { + return; + } - if (!name || name[0] == '\0') + if (!name || name[0] == '\0') { - msg (D_PLUGIN_DEBUG, "PLUGIN: suppressed log message from plugin with unknown name"); - return; + msg(D_PLUGIN_DEBUG, "PLUGIN: suppressed log message from plugin with unknown name"); + return; } - if (flags & PLOG_ERR) - msg_flags = M_INFO | M_NONFATAL; - else if (flags & PLOG_WARN) - msg_flags = M_INFO | M_WARN; - else if (flags & PLOG_NOTE) - msg_flags = M_INFO; - else if (flags & PLOG_DEBUG) - msg_flags = D_PLUGIN_DEBUG; + if (flags & PLOG_ERR) + { + msg_flags = M_INFO | M_NONFATAL; + } + else if (flags & PLOG_WARN) + { + msg_flags = M_INFO | M_WARN; + } + else if (flags & PLOG_NOTE) + { + msg_flags = M_INFO; + } + else if (flags & PLOG_DEBUG) + { + msg_flags = D_PLUGIN_DEBUG; + } - if (flags & PLOG_ERRNO) - msg_flags |= M_ERRNO; - if (flags & PLOG_NOMUTE) - msg_flags |= M_NOMUTE; + if (flags & PLOG_ERRNO) + { + msg_flags |= M_ERRNO; + } + if (flags & PLOG_NOMUTE) + { + msg_flags |= M_NOMUTE; + } - if (msg_test (msg_flags)) + if (msg_test(msg_flags)) { - struct gc_arena gc; - char* msg_fmt; + struct gc_arena gc; + char *msg_fmt; - /* Never add instance prefix; not thread safe */ - msg_flags |= M_NOIPREFIX; + /* Never add instance prefix; not thread safe */ + msg_flags |= M_NOIPREFIX; - gc_init (&gc); - msg_fmt = gc_malloc (ERR_BUF_SIZE, false, &gc); - openvpn_snprintf (msg_fmt, ERR_BUF_SIZE, "PLUGIN %s: %s", name, format); - x_msg_va (msg_flags, msg_fmt, arglist); + gc_init(&gc); + msg_fmt = gc_malloc(ERR_BUF_SIZE, false, &gc); + openvpn_snprintf(msg_fmt, ERR_BUF_SIZE, "PLUGIN %s: %s", name, format); + x_msg_va(msg_flags, msg_fmt, arglist); - gc_free (&gc); + gc_free(&gc); } } static void -plugin_log (openvpn_plugin_log_flags_t flags, const char *name, const char *format, ...) +plugin_log(openvpn_plugin_log_flags_t flags, const char *name, const char *format, ...) { - va_list arglist; - va_start (arglist, format); - plugin_vlog (flags, name, format, arglist); - va_end (arglist); + va_list arglist; + va_start(arglist, format); + plugin_vlog(flags, name, format, arglist); + va_end(arglist); } static struct openvpn_plugin_callbacks callbacks = { - plugin_log, - plugin_vlog + plugin_log, + plugin_vlog }; @@ -356,448 +411,506 @@ static struct openvpn_plugin_callbacks callbacks = { * inside a struct declaration */ #ifndef CONFIGURE_GIT_REVISION -# define _OPENVPN_PATCH_LEVEL OPENVPN_VERSION_PATCH +#define _OPENVPN_PATCH_LEVEL OPENVPN_VERSION_PATCH #else -# define _OPENVPN_PATCH_LEVEL "git:" CONFIGURE_GIT_REVISION CONFIGURE_GIT_FLAGS +#define _OPENVPN_PATCH_LEVEL "git:" CONFIGURE_GIT_REVISION CONFIGURE_GIT_FLAGS #endif static void -plugin_open_item (struct plugin *p, - const struct plugin_option *o, - struct openvpn_plugin_string_list **retlist, - const char **envp, - const int init_point) -{ - ASSERT (p->initialized); - - /* clear return list */ - if (retlist) - *retlist = NULL; - - if (!p->plugin_handle && init_point == p->requested_initialization_point) - { - struct gc_arena gc = gc_new (); - - dmsg (D_PLUGIN_DEBUG, "PLUGIN_INIT: PRE"); - plugin_show_args_env (D_PLUGIN_DEBUG, o->argv, envp); - - /* - * Call the plugin initialization - */ - if (p->open3) { - struct openvpn_plugin_args_open_in args = { p->plugin_type_mask, - (const char ** const) o->argv, - (const char ** const) envp, - &callbacks, - SSLAPI, - PACKAGE_VERSION, - OPENVPN_VERSION_MAJOR, - OPENVPN_VERSION_MINOR, - _OPENVPN_PATCH_LEVEL - }; - struct openvpn_plugin_args_open_return retargs; - - CLEAR(retargs); - retargs.return_list = retlist; - if ((*p->open3)(OPENVPN_PLUGINv3_STRUCTVER, &args, &retargs) == OPENVPN_PLUGIN_FUNC_SUCCESS) { - p->plugin_type_mask = retargs.type_mask; - p->plugin_handle = retargs.handle; - } else { - p->plugin_handle = NULL; +plugin_open_item(struct plugin *p, + const struct plugin_option *o, + struct openvpn_plugin_string_list **retlist, + const char **envp, + const int init_point) +{ + ASSERT(p->initialized); + + /* clear return list */ + if (retlist) + { + *retlist = NULL; + } + + if (!p->plugin_handle && init_point == p->requested_initialization_point) + { + struct gc_arena gc = gc_new(); + + dmsg(D_PLUGIN_DEBUG, "PLUGIN_INIT: PRE"); + plugin_show_args_env(D_PLUGIN_DEBUG, o->argv, envp); + + /* + * Call the plugin initialization + */ + if (p->open3) + { + struct openvpn_plugin_args_open_in args = { p->plugin_type_mask, + (const char **const) o->argv, + (const char **const) envp, + &callbacks, + SSLAPI, + PACKAGE_VERSION, + OPENVPN_VERSION_MAJOR, + OPENVPN_VERSION_MINOR, + _OPENVPN_PATCH_LEVEL}; + struct openvpn_plugin_args_open_return retargs; + + CLEAR(retargs); + retargs.return_list = retlist; + if ((*p->open3)(OPENVPN_PLUGINv3_STRUCTVER, &args, &retargs) == OPENVPN_PLUGIN_FUNC_SUCCESS) + { + p->plugin_type_mask = retargs.type_mask; + p->plugin_handle = retargs.handle; + } + else + { + p->plugin_handle = NULL; + } + } + else if (p->open2) + { + p->plugin_handle = (*p->open2)(&p->plugin_type_mask, o->argv, envp, retlist); + } + else if (p->open1) + { + p->plugin_handle = (*p->open1)(&p->plugin_type_mask, o->argv, envp); + } + else + { + ASSERT(0); } - } else if (p->open2) - p->plugin_handle = (*p->open2)(&p->plugin_type_mask, o->argv, envp, retlist); - else if (p->open1) - p->plugin_handle = (*p->open1)(&p->plugin_type_mask, o->argv, envp); - else - ASSERT (0); - msg (D_PLUGIN, "PLUGIN_INIT: POST %s '%s' intercepted=%s %s", - p->so_pathname, - print_argv (o->argv, &gc, PA_BRACKET), - plugin_mask_string (p->plugin_type_mask, &gc), - (retlist && *retlist) ? "[RETLIST]" : ""); - - if ((p->plugin_type_mask | plugin_supported_types()) != plugin_supported_types()) - msg (M_FATAL, "PLUGIN_INIT: plugin %s expressed interest in unsupported plugin types: [want=0x%08x, have=0x%08x]", - p->so_pathname, - p->plugin_type_mask, - plugin_supported_types()); + msg(D_PLUGIN, "PLUGIN_INIT: POST %s '%s' intercepted=%s %s", + p->so_pathname, + print_argv(o->argv, &gc, PA_BRACKET), + plugin_mask_string(p->plugin_type_mask, &gc), + (retlist && *retlist) ? "[RETLIST]" : ""); + + if ((p->plugin_type_mask | plugin_supported_types()) != plugin_supported_types()) + { + msg(M_FATAL, "PLUGIN_INIT: plugin %s expressed interest in unsupported plugin types: [want=0x%08x, have=0x%08x]", + p->so_pathname, + p->plugin_type_mask, + plugin_supported_types()); + } - if (p->plugin_handle == NULL) - msg (M_FATAL, "PLUGIN_INIT: plugin initialization function failed: %s", - p->so_pathname); + if (p->plugin_handle == NULL) + { + msg(M_FATAL, "PLUGIN_INIT: plugin initialization function failed: %s", + p->so_pathname); + } - gc_free (&gc); + gc_free(&gc); } } static int -plugin_call_item (const struct plugin *p, - void *per_client_context, - const int type, - const struct argv *av, - struct openvpn_plugin_string_list **retlist, - const char **envp +plugin_call_item(const struct plugin *p, + void *per_client_context, + const int type, + const struct argv *av, + struct openvpn_plugin_string_list **retlist, + const char **envp #ifdef ENABLE_CRYPTO - , int certdepth, - openvpn_x509_cert_t *current_cert + , int certdepth, + openvpn_x509_cert_t *current_cert #endif - ) + ) { - int status = OPENVPN_PLUGIN_FUNC_SUCCESS; - - /* clear return list */ - if (retlist) - *retlist = NULL; + int status = OPENVPN_PLUGIN_FUNC_SUCCESS; - if (p->plugin_handle && (p->plugin_type_mask & OPENVPN_PLUGIN_MASK (type))) + /* clear return list */ + if (retlist) { - struct gc_arena gc = gc_new (); - struct argv a = argv_insert_head (av, p->so_pathname); - - dmsg (D_PLUGIN_DEBUG, "PLUGIN_CALL: PRE type=%s", plugin_type_name (type)); - plugin_show_args_env (D_PLUGIN_DEBUG, (const char **)a.argv, envp); + *retlist = NULL; + } - /* - * Call the plugin work function - */ - if (p->func3) { - struct openvpn_plugin_args_func_in args = { type, - (const char ** const) a.argv, - (const char ** const) envp, - p->plugin_handle, - per_client_context, + if (p->plugin_handle && (p->plugin_type_mask & OPENVPN_PLUGIN_MASK(type))) + { + struct gc_arena gc = gc_new(); + struct argv a = argv_insert_head(av, p->so_pathname); + + dmsg(D_PLUGIN_DEBUG, "PLUGIN_CALL: PRE type=%s", plugin_type_name(type)); + plugin_show_args_env(D_PLUGIN_DEBUG, (const char **)a.argv, envp); + + /* + * Call the plugin work function + */ + if (p->func3) + { + struct openvpn_plugin_args_func_in args = { type, + (const char **const) a.argv, + (const char **const) envp, + p->plugin_handle, + per_client_context, #ifdef ENABLE_CRYPTO - (current_cert ? certdepth : -1), - current_cert + (current_cert ? certdepth : -1), + current_cert #else - -1, - NULL + -1, + NULL #endif - }; - - struct openvpn_plugin_args_func_return retargs; + }; - CLEAR(retargs); - retargs.return_list = retlist; - status = (*p->func3)(OPENVPN_PLUGINv3_STRUCTVER, &args, &retargs); - } else if (p->func2) - status = (*p->func2)(p->plugin_handle, type, (const char **)a.argv, envp, per_client_context, retlist); - else if (p->func1) - status = (*p->func1)(p->plugin_handle, type, (const char **)a.argv, envp); - else - ASSERT (0); + struct openvpn_plugin_args_func_return retargs; - msg (D_PLUGIN, "PLUGIN_CALL: POST %s/%s status=%d", - p->so_pathname, - plugin_type_name (type), - status); + CLEAR(retargs); + retargs.return_list = retlist; + status = (*p->func3)(OPENVPN_PLUGINv3_STRUCTVER, &args, &retargs); + } + else if (p->func2) + { + status = (*p->func2)(p->plugin_handle, type, (const char **)a.argv, envp, per_client_context, retlist); + } + else if (p->func1) + { + status = (*p->func1)(p->plugin_handle, type, (const char **)a.argv, envp); + } + else + { + ASSERT(0); + } - if (status == OPENVPN_PLUGIN_FUNC_ERROR) - msg (M_WARN, "PLUGIN_CALL: plugin function %s failed with status %d: %s", - plugin_type_name (type), - status, - p->so_pathname); + msg(D_PLUGIN, "PLUGIN_CALL: POST %s/%s status=%d", + p->so_pathname, + plugin_type_name(type), + status); + + if (status == OPENVPN_PLUGIN_FUNC_ERROR) + { + msg(M_WARN, "PLUGIN_CALL: plugin function %s failed with status %d: %s", + plugin_type_name(type), + status, + p->so_pathname); + } - argv_reset (&a); - gc_free (&gc); + argv_reset(&a); + gc_free(&gc); } - return status; + return status; } static void -plugin_close_item (struct plugin *p) +plugin_close_item(struct plugin *p) { - if (p->initialized) + if (p->initialized) { - msg (D_PLUGIN, "PLUGIN_CLOSE: %s", p->so_pathname); - - /* - * Call the plugin close function - */ - if (p->plugin_handle) - (*p->close)(p->plugin_handle); + msg(D_PLUGIN, "PLUGIN_CLOSE: %s", p->so_pathname); + + /* + * Call the plugin close function + */ + if (p->plugin_handle) + { + (*p->close)(p->plugin_handle); + } #ifndef _WIN32 - if (dlclose (p->handle)) - msg (M_WARN, "PLUGIN_CLOSE: dlclose() failed on plugin: %s", p->so_pathname); + if (dlclose(p->handle)) + { + msg(M_WARN, "PLUGIN_CLOSE: dlclose() failed on plugin: %s", p->so_pathname); + } #elif defined(_WIN32) - if (!FreeLibrary (p->module)) - msg (M_WARN, "PLUGIN_CLOSE: FreeLibrary() failed on plugin: %s", p->so_pathname); + if (!FreeLibrary(p->module)) + { + msg(M_WARN, "PLUGIN_CLOSE: FreeLibrary() failed on plugin: %s", p->so_pathname); + } #endif - p->initialized = false; + p->initialized = false; } } static void -plugin_abort_item (const struct plugin *p) +plugin_abort_item(const struct plugin *p) { - /* - * Call the plugin abort function - */ - if (p->abort) - (*p->abort)(p->plugin_handle); + /* + * Call the plugin abort function + */ + if (p->abort) + { + (*p->abort)(p->plugin_handle); + } } static void -plugin_per_client_init (const struct plugin_common *pc, - struct plugin_per_client *cli, - const int init_point) +plugin_per_client_init(const struct plugin_common *pc, + struct plugin_per_client *cli, + const int init_point) { - const int n = pc->n; - int i; + const int n = pc->n; + int i; - for (i = 0; i < n; ++i) + for (i = 0; i < n; ++i) { - const struct plugin *p = &pc->plugins[i]; - if (p->plugin_handle - && (init_point < 0 || init_point == p->requested_initialization_point) - && p->client_constructor) - cli->per_client_context[i] = (*p->client_constructor)(p->plugin_handle); + const struct plugin *p = &pc->plugins[i]; + if (p->plugin_handle + && (init_point < 0 || init_point == p->requested_initialization_point) + && p->client_constructor) + { + cli->per_client_context[i] = (*p->client_constructor)(p->plugin_handle); + } } } static void -plugin_per_client_destroy (const struct plugin_common *pc, struct plugin_per_client *cli) +plugin_per_client_destroy(const struct plugin_common *pc, struct plugin_per_client *cli) { - const int n = pc->n; - int i; + const int n = pc->n; + int i; - for (i = 0; i < n; ++i) + for (i = 0; i < n; ++i) { - const struct plugin *p = &pc->plugins[i]; - void *cc = cli->per_client_context[i]; + const struct plugin *p = &pc->plugins[i]; + void *cc = cli->per_client_context[i]; - if (p->client_destructor && cc) - (*p->client_destructor)(p->plugin_handle, cc); + if (p->client_destructor && cc) + { + (*p->client_destructor)(p->plugin_handle, cc); + } } - CLEAR (*cli); + CLEAR(*cli); } struct plugin_list * -plugin_list_inherit (const struct plugin_list *src) +plugin_list_inherit(const struct plugin_list *src) { - struct plugin_list *pl; - ALLOC_OBJ_CLEAR (pl, struct plugin_list); - pl->common = src->common; - ASSERT (pl->common); - plugin_per_client_init (pl->common, &pl->per_client, -1); - return pl; + struct plugin_list *pl; + ALLOC_OBJ_CLEAR(pl, struct plugin_list); + pl->common = src->common; + ASSERT(pl->common); + plugin_per_client_init(pl->common, &pl->per_client, -1); + return pl; } static struct plugin_common * -plugin_common_init (const struct plugin_option_list *list) +plugin_common_init(const struct plugin_option_list *list) { - int i; - struct plugin_common *pc; + int i; + struct plugin_common *pc; - ALLOC_OBJ_CLEAR (pc, struct plugin_common); + ALLOC_OBJ_CLEAR(pc, struct plugin_common); - for (i = 0; i < list->n; ++i) + for (i = 0; i < list->n; ++i) { - plugin_init_item (&pc->plugins[i], - &list->plugins[i]); - pc->n = i + 1; + plugin_init_item(&pc->plugins[i], + &list->plugins[i]); + pc->n = i + 1; } - static_plugin_common = pc; - return pc; + static_plugin_common = pc; + return pc; } static void -plugin_common_open (struct plugin_common *pc, - const struct plugin_option_list *list, - struct plugin_return *pr, - const struct env_set *es, - const int init_point) +plugin_common_open(struct plugin_common *pc, + const struct plugin_option_list *list, + struct plugin_return *pr, + const struct env_set *es, + const int init_point) { - struct gc_arena gc = gc_new (); - int i; - const char **envp; + struct gc_arena gc = gc_new(); + int i; + const char **envp; - envp = make_env_array (es, false, &gc); + envp = make_env_array(es, false, &gc); - if (pr) - plugin_return_init (pr); + if (pr) + { + plugin_return_init(pr); + } - for (i = 0; i < pc->n; ++i) + for (i = 0; i < pc->n; ++i) { - plugin_open_item (&pc->plugins[i], - &list->plugins[i], - pr ? &pr->list[i] : NULL, - envp, - init_point); + plugin_open_item(&pc->plugins[i], + &list->plugins[i], + pr ? &pr->list[i] : NULL, + envp, + init_point); } - if (pr) - pr->n = i; + if (pr) + { + pr->n = i; + } - gc_free (&gc); + gc_free(&gc); } static void -plugin_common_close (struct plugin_common *pc) +plugin_common_close(struct plugin_common *pc) { - static_plugin_common = NULL; - if (pc) + static_plugin_common = NULL; + if (pc) { - int i; + int i; - for (i = 0; i < pc->n; ++i) - plugin_close_item (&pc->plugins[i]); - free (pc); + for (i = 0; i < pc->n; ++i) + plugin_close_item(&pc->plugins[i]); + free(pc); } } struct plugin_list * -plugin_list_init (const struct plugin_option_list *list) +plugin_list_init(const struct plugin_option_list *list) { - struct plugin_list *pl; - ALLOC_OBJ_CLEAR (pl, struct plugin_list); - pl->common = plugin_common_init (list); - pl->common_owned = true; - return pl; + struct plugin_list *pl; + ALLOC_OBJ_CLEAR(pl, struct plugin_list); + pl->common = plugin_common_init(list); + pl->common_owned = true; + return pl; } void -plugin_list_open (struct plugin_list *pl, - const struct plugin_option_list *list, - struct plugin_return *pr, - const struct env_set *es, - const int init_point) +plugin_list_open(struct plugin_list *pl, + const struct plugin_option_list *list, + struct plugin_return *pr, + const struct env_set *es, + const int init_point) { - plugin_common_open (pl->common, list, pr, es, init_point); - plugin_per_client_init (pl->common, &pl->per_client, init_point); + plugin_common_open(pl->common, list, pr, es, init_point); + plugin_per_client_init(pl->common, &pl->per_client, init_point); } int -plugin_call_ssl (const struct plugin_list *pl, - const int type, - const struct argv *av, - struct plugin_return *pr, - struct env_set *es +plugin_call_ssl(const struct plugin_list *pl, + const int type, + const struct argv *av, + struct plugin_return *pr, + struct env_set *es #ifdef ENABLE_CRYPTO - , int certdepth, - openvpn_x509_cert_t *current_cert + , int certdepth, + openvpn_x509_cert_t *current_cert #endif - ) -{ - if (pr) - plugin_return_init (pr); - - if (plugin_defined (pl, type)) - { - struct gc_arena gc = gc_new (); - int i; - const char **envp; - const int n = plugin_n (pl); - bool success = false; - bool error = false; - bool deferred = false; - - setenv_del (es, "script_type"); - envp = make_env_array (es, false, &gc); - - for (i = 0; i < n; ++i) - { - const int status = plugin_call_item (&pl->common->plugins[i], - pl->per_client.per_client_context[i], - type, - av, - pr ? &pr->list[i] : NULL, - envp + ) +{ + if (pr) + { + plugin_return_init(pr); + } + + if (plugin_defined(pl, type)) + { + struct gc_arena gc = gc_new(); + int i; + const char **envp; + const int n = plugin_n(pl); + bool success = false; + bool error = false; + bool deferred = false; + + setenv_del(es, "script_type"); + envp = make_env_array(es, false, &gc); + + for (i = 0; i < n; ++i) + { + const int status = plugin_call_item(&pl->common->plugins[i], + pl->per_client.per_client_context[i], + type, + av, + pr ? &pr->list[i] : NULL, + envp #ifdef ENABLE_CRYPTO - ,certdepth, - current_cert + ,certdepth, + current_cert #endif - ); - switch (status) - { - case OPENVPN_PLUGIN_FUNC_SUCCESS: - success = true; - break; - case OPENVPN_PLUGIN_FUNC_DEFERRED: - deferred = true; - break; - default: - error = true; - break; - } - } + ); + switch (status) + { + case OPENVPN_PLUGIN_FUNC_SUCCESS: + success = true; + break; + + case OPENVPN_PLUGIN_FUNC_DEFERRED: + deferred = true; + break; + + default: + error = true; + break; + } + } - if (pr) - pr->n = i; + if (pr) + { + pr->n = i; + } - gc_free (&gc); + gc_free(&gc); - if (type == OPENVPN_PLUGIN_ENABLE_PF && success) - return OPENVPN_PLUGIN_FUNC_SUCCESS; - else if (error) - return OPENVPN_PLUGIN_FUNC_ERROR; - else if (deferred) - return OPENVPN_PLUGIN_FUNC_DEFERRED; + if (type == OPENVPN_PLUGIN_ENABLE_PF && success) + { + return OPENVPN_PLUGIN_FUNC_SUCCESS; + } + else if (error) + { + return OPENVPN_PLUGIN_FUNC_ERROR; + } + else if (deferred) + { + return OPENVPN_PLUGIN_FUNC_DEFERRED; + } } - return OPENVPN_PLUGIN_FUNC_SUCCESS; + return OPENVPN_PLUGIN_FUNC_SUCCESS; } void -plugin_list_close (struct plugin_list *pl) +plugin_list_close(struct plugin_list *pl) { - if (pl) + if (pl) { - if (pl->common) - { - plugin_per_client_destroy (pl->common, &pl->per_client); - - if (pl->common_owned) - plugin_common_close (pl->common); - } + if (pl->common) + { + plugin_per_client_destroy(pl->common, &pl->per_client); + + if (pl->common_owned) + { + plugin_common_close(pl->common); + } + } - free (pl); + free(pl); } } void -plugin_abort (void) +plugin_abort(void) { - struct plugin_common *pc = static_plugin_common; - static_plugin_common = NULL; - if (pc) + struct plugin_common *pc = static_plugin_common; + static_plugin_common = NULL; + if (pc) { - int i; + int i; - for (i = 0; i < pc->n; ++i) - plugin_abort_item (&pc->plugins[i]); + for (i = 0; i < pc->n; ++i) + plugin_abort_item(&pc->plugins[i]); } } bool -plugin_defined (const struct plugin_list *pl, const int type) +plugin_defined(const struct plugin_list *pl, const int type) { - bool ret = false; + bool ret = false; - if (pl) + if (pl) { - const struct plugin_common *pc = pl->common; - - if (pc) - { - int i; - const unsigned int mask = OPENVPN_PLUGIN_MASK (type); - for (i = 0; i < pc->n; ++i) - { - if (pc->plugins[i].plugin_type_mask & mask) - { - ret = true; - break; - } - } - } + const struct plugin_common *pc = pl->common; + + if (pc) + { + int i; + const unsigned int mask = OPENVPN_PLUGIN_MASK(type); + for (i = 0; i < pc->n; ++i) + { + if (pc->plugins[i].plugin_type_mask & mask) + { + ret = true; + break; + } + } + } } - return ret; + return ret; } /* @@ -805,87 +918,91 @@ plugin_defined (const struct plugin_list *pl, const int type) */ static void -openvpn_plugin_string_list_item_free (struct openvpn_plugin_string_list *l) +openvpn_plugin_string_list_item_free(struct openvpn_plugin_string_list *l) { - if (l) + if (l) { - free (l->name); - string_clear (l->value); - free (l->value); - free (l); + free(l->name); + string_clear(l->value); + free(l->value); + free(l); } } static void -openvpn_plugin_string_list_free (struct openvpn_plugin_string_list *l) +openvpn_plugin_string_list_free(struct openvpn_plugin_string_list *l) { - struct openvpn_plugin_string_list *next; - while (l) + struct openvpn_plugin_string_list *next; + while (l) { - next = l->next; - openvpn_plugin_string_list_item_free (l); - l = next; + next = l->next; + openvpn_plugin_string_list_item_free(l); + l = next; } } static struct openvpn_plugin_string_list * -openvpn_plugin_string_list_find (struct openvpn_plugin_string_list *l, const char *name) +openvpn_plugin_string_list_find(struct openvpn_plugin_string_list *l, const char *name) { - while (l) + while (l) { - if (!strcmp (l->name, name)) - return l; - l = l->next; + if (!strcmp(l->name, name)) + { + return l; + } + l = l->next; } - return NULL; + return NULL; } void -plugin_return_get_column (const struct plugin_return *src, - struct plugin_return *dest, - const char *colname) +plugin_return_get_column(const struct plugin_return *src, + struct plugin_return *dest, + const char *colname) { - int i; + int i; - dest->n = 0; - for (i = 0; i < src->n; ++i) - dest->list[i] = openvpn_plugin_string_list_find (src->list[i], colname); - dest->n = i; + dest->n = 0; + for (i = 0; i < src->n; ++i) + dest->list[i] = openvpn_plugin_string_list_find(src->list[i], colname); + dest->n = i; } void -plugin_return_free (struct plugin_return *pr) +plugin_return_free(struct plugin_return *pr) { - int i; - for (i = 0; i < pr->n; ++i) - openvpn_plugin_string_list_free (pr->list[i]); - pr->n = 0; + int i; + for (i = 0; i < pr->n; ++i) + openvpn_plugin_string_list_free(pr->list[i]); + pr->n = 0; } #ifdef ENABLE_DEBUG void -plugin_return_print (const int msglevel, const char *prefix, const struct plugin_return *pr) +plugin_return_print(const int msglevel, const char *prefix, const struct plugin_return *pr) { - int i; - msg (msglevel, "PLUGIN_RETURN_PRINT %s", prefix); - for (i = 0; i < pr->n; ++i) + int i; + msg(msglevel, "PLUGIN_RETURN_PRINT %s", prefix); + for (i = 0; i < pr->n; ++i) { - struct openvpn_plugin_string_list *l = pr->list[i]; - int count = 0; - - msg (msglevel, "PLUGIN #%d (%s)", i, prefix); - while (l) - { - msg (msglevel, "[%d] '%s' -> '%s'\n", - ++count, - l->name, - l->value); - l = l->next; - } + struct openvpn_plugin_string_list *l = pr->list[i]; + int count = 0; + + msg(msglevel, "PLUGIN #%d (%s)", i, prefix); + while (l) + { + msg(msglevel, "[%d] '%s' -> '%s'\n", + ++count, + l->name, + l->value); + l = l->next; + } } } -#endif +#endif /* ifdef ENABLE_DEBUG */ -#else -static void dummy(void) {} +#else /* ifdef ENABLE_PLUGIN */ +static void +dummy(void) { +} #endif /* ENABLE_PLUGIN */ diff --git a/src/openvpn/plugin.h b/src/openvpn/plugin.h index b1e045889d0..7f0cbd430c5 100644 --- a/src/openvpn/plugin.h +++ b/src/openvpn/plugin.h @@ -44,168 +44,176 @@ #define MAX_PLUGINS 16 struct plugin_option { - const char *so_pathname; - const char **argv; + const char *so_pathname; + const char **argv; }; struct plugin_option_list { - int n; - struct plugin_option plugins[MAX_PLUGINS]; + int n; + struct plugin_option plugins[MAX_PLUGINS]; }; struct plugin { - bool initialized; - const char *so_pathname; - unsigned int plugin_type_mask; - int requested_initialization_point; + bool initialized; + const char *so_pathname; + unsigned int plugin_type_mask; + int requested_initialization_point; #ifndef _WIN32 - void *handle; + void *handle; #else - HMODULE module; + HMODULE module; #endif - openvpn_plugin_open_v1 open1; - openvpn_plugin_open_v2 open2; - openvpn_plugin_open_v3 open3; - openvpn_plugin_func_v1 func1; - openvpn_plugin_func_v2 func2; - openvpn_plugin_func_v3 func3; - openvpn_plugin_close_v1 close; - openvpn_plugin_abort_v1 abort; - openvpn_plugin_client_constructor_v1 client_constructor; - openvpn_plugin_client_destructor_v1 client_destructor; - openvpn_plugin_min_version_required_v1 min_version_required; - openvpn_plugin_select_initialization_point_v1 initialization_point; - - openvpn_plugin_handle_t plugin_handle; + openvpn_plugin_open_v1 open1; + openvpn_plugin_open_v2 open2; + openvpn_plugin_open_v3 open3; + openvpn_plugin_func_v1 func1; + openvpn_plugin_func_v2 func2; + openvpn_plugin_func_v3 func3; + openvpn_plugin_close_v1 close; + openvpn_plugin_abort_v1 abort; + openvpn_plugin_client_constructor_v1 client_constructor; + openvpn_plugin_client_destructor_v1 client_destructor; + openvpn_plugin_min_version_required_v1 min_version_required; + openvpn_plugin_select_initialization_point_v1 initialization_point; + + openvpn_plugin_handle_t plugin_handle; }; struct plugin_per_client { - void *per_client_context[MAX_PLUGINS]; + void *per_client_context[MAX_PLUGINS]; }; struct plugin_common { - int n; - struct plugin plugins[MAX_PLUGINS]; + int n; + struct plugin plugins[MAX_PLUGINS]; }; struct plugin_list { - struct plugin_per_client per_client; - struct plugin_common *common; - bool common_owned; + struct plugin_per_client per_client; + struct plugin_common *common; + bool common_owned; }; struct plugin_return { - int n; - struct openvpn_plugin_string_list *list[MAX_PLUGINS]; + int n; + struct openvpn_plugin_string_list *list[MAX_PLUGINS]; }; -struct plugin_option_list *plugin_option_list_new (struct gc_arena *gc); -bool plugin_option_list_add (struct plugin_option_list *list, char **p, struct gc_arena *gc); +struct plugin_option_list *plugin_option_list_new(struct gc_arena *gc); + +bool plugin_option_list_add(struct plugin_option_list *list, char **p, struct gc_arena *gc); #ifndef ENABLE_SMALL -void plugin_option_list_print (const struct plugin_option_list *list, int msglevel); +void plugin_option_list_print(const struct plugin_option_list *list, int msglevel); + #endif -struct plugin_list *plugin_list_init (const struct plugin_option_list *list); +struct plugin_list *plugin_list_init(const struct plugin_option_list *list); -void plugin_list_open (struct plugin_list *pl, - const struct plugin_option_list *list, - struct plugin_return *pr, - const struct env_set *es, - const int init_point); +void plugin_list_open(struct plugin_list *pl, + const struct plugin_option_list *list, + struct plugin_return *pr, + const struct env_set *es, + const int init_point); -struct plugin_list *plugin_list_inherit (const struct plugin_list *src); +struct plugin_list *plugin_list_inherit(const struct plugin_list *src); -int plugin_call_ssl (const struct plugin_list *pl, - const int type, - const struct argv *av, - struct plugin_return *pr, - struct env_set *es +int plugin_call_ssl(const struct plugin_list *pl, + const int type, + const struct argv *av, + struct plugin_return *pr, + struct env_set *es #ifdef ENABLE_CRYPTO - , int current_cert_depth, - openvpn_x509_cert_t *current_cert + , int current_cert_depth, + openvpn_x509_cert_t *current_cert #endif - ); + ); -void plugin_list_close (struct plugin_list *pl); -bool plugin_defined (const struct plugin_list *pl, const int type); +void plugin_list_close(struct plugin_list *pl); -void plugin_return_get_column (const struct plugin_return *src, - struct plugin_return *dest, - const char *colname); +bool plugin_defined(const struct plugin_list *pl, const int type); -void plugin_return_free (struct plugin_return *pr); +void plugin_return_get_column(const struct plugin_return *src, + struct plugin_return *dest, + const char *colname); + +void plugin_return_free(struct plugin_return *pr); #ifdef ENABLE_DEBUG -void plugin_return_print (const int msglevel, const char *prefix, const struct plugin_return *pr); +void plugin_return_print(const int msglevel, const char *prefix, const struct plugin_return *pr); + #endif static inline int -plugin_n (const struct plugin_list *pl) +plugin_n(const struct plugin_list *pl) { - if (pl && pl->common) - return pl->common->n; - else - return 0; + if (pl && pl->common) + { + return pl->common->n; + } + else + { + return 0; + } } static inline bool -plugin_return_defined (const struct plugin_return *pr) +plugin_return_defined(const struct plugin_return *pr) { - return pr->n >= 0; + return pr->n >= 0; } static inline void -plugin_return_init (struct plugin_return *pr) +plugin_return_init(struct plugin_return *pr) { - pr->n = 0; + pr->n = 0; } -#else +#else /* ifdef ENABLE_PLUGIN */ struct plugin_list { int dummy; }; struct plugin_return { int dummy; }; static inline bool -plugin_defined (const struct plugin_list *pl, const int type) +plugin_defined(const struct plugin_list *pl, const int type) { - return false; + return false; } static inline int -plugin_call_ssl (const struct plugin_list *pl, - const int type, - const struct argv *av, - struct plugin_return *pr, - struct env_set *es +plugin_call_ssl(const struct plugin_list *pl, + const int type, + const struct argv *av, + struct plugin_return *pr, + struct env_set *es #ifdef ENABLE_CRYPTO - , int current_cert_depth, - openvpn_x509_cert_t *current_cert + , int current_cert_depth, + openvpn_x509_cert_t *current_cert #endif - ) + ) { - return 0; + return 0; } #endif /* ENABLE_PLUGIN */ static inline int plugin_call(const struct plugin_list *pl, - const int type, - const struct argv *av, - struct plugin_return *pr, - struct env_set *es) + const int type, + const struct argv *av, + struct plugin_return *pr, + struct env_set *es) { - return plugin_call_ssl(pl, type, av, pr, es + return plugin_call_ssl(pl, type, av, pr, es #ifdef ENABLE_CRYPTO - , -1, NULL + , -1, NULL #endif - ); + ); } #endif /* OPENVPN_PLUGIN_H */ diff --git a/src/openvpn/pool.c b/src/openvpn/pool.c index 28c26b4da2b..8d5dc1bea1f 100644 --- a/src/openvpn/pool.c +++ b/src/openvpn/pool.c @@ -41,228 +41,244 @@ #if P2MP static void -ifconfig_pool_entry_free (struct ifconfig_pool_entry *ipe, bool hard) +ifconfig_pool_entry_free(struct ifconfig_pool_entry *ipe, bool hard) { - ipe->in_use = false; - if (hard && ipe->common_name) + ipe->in_use = false; + if (hard && ipe->common_name) { - free (ipe->common_name); - ipe->common_name = NULL; + free(ipe->common_name); + ipe->common_name = NULL; + } + if (hard) + { + ipe->last_release = 0; + } + else + { + ipe->last_release = now; } - if (hard) - ipe->last_release = 0; - else - ipe->last_release = now; } static int -ifconfig_pool_find (struct ifconfig_pool *pool, const char *common_name) +ifconfig_pool_find(struct ifconfig_pool *pool, const char *common_name) { - int i; - time_t earliest_release = 0; - int previous_usage = -1; - int new_usage = -1; + int i; + time_t earliest_release = 0; + int previous_usage = -1; + int new_usage = -1; - for (i = 0; i < pool->size; ++i) + for (i = 0; i < pool->size; ++i) { - struct ifconfig_pool_entry *ipe = &pool->list[i]; - if (!ipe->in_use) - { - /* - * If duplicate_cn mode, take first available IP address - */ - if (pool->duplicate_cn) - { - new_usage = i; - break; - } - - /* - * Keep track of the unused IP address entry which - * was released earliest. - */ - if ((new_usage == -1 || ipe->last_release < earliest_release) && !ipe->fixed) - { - earliest_release = ipe->last_release; - new_usage = i; - } - - /* - * Keep track of a possible allocation to us - * from an earlier session. - */ - if (previous_usage < 0 - && common_name - && ipe->common_name - && !strcmp (common_name, ipe->common_name)) - previous_usage = i; - - } + struct ifconfig_pool_entry *ipe = &pool->list[i]; + if (!ipe->in_use) + { + /* + * If duplicate_cn mode, take first available IP address + */ + if (pool->duplicate_cn) + { + new_usage = i; + break; + } + + /* + * Keep track of the unused IP address entry which + * was released earliest. + */ + if ((new_usage == -1 || ipe->last_release < earliest_release) && !ipe->fixed) + { + earliest_release = ipe->last_release; + new_usage = i; + } + + /* + * Keep track of a possible allocation to us + * from an earlier session. + */ + if (previous_usage < 0 + && common_name + && ipe->common_name + && !strcmp(common_name, ipe->common_name)) + { + previous_usage = i; + } + + } } - if (previous_usage >= 0) - return previous_usage; + if (previous_usage >= 0) + { + return previous_usage; + } - if (new_usage >= 0) - return new_usage; + if (new_usage >= 0) + { + return new_usage; + } - return -1; + return -1; } /* * Verify start/end range */ bool -ifconfig_pool_verify_range (const int msglevel, const in_addr_t start, const in_addr_t end) +ifconfig_pool_verify_range(const int msglevel, const in_addr_t start, const in_addr_t end) { - struct gc_arena gc = gc_new (); - bool ret = true; + struct gc_arena gc = gc_new(); + bool ret = true; - if (start > end) + if (start > end) { - msg (msglevel, "--ifconfig-pool start IP [%s] is greater than end IP [%s]", - print_in_addr_t (start, 0, &gc), - print_in_addr_t (end, 0, &gc)); - ret = false; + msg(msglevel, "--ifconfig-pool start IP [%s] is greater than end IP [%s]", + print_in_addr_t(start, 0, &gc), + print_in_addr_t(end, 0, &gc)); + ret = false; } - if (end - start >= IFCONFIG_POOL_MAX) + if (end - start >= IFCONFIG_POOL_MAX) { - msg (msglevel, "--ifconfig-pool address range is too large [%s -> %s]. Current maximum is %d addresses, as defined by IFCONFIG_POOL_MAX variable.", - print_in_addr_t (start, 0, &gc), - print_in_addr_t (end, 0, &gc), - IFCONFIG_POOL_MAX); - ret = false; + msg(msglevel, "--ifconfig-pool address range is too large [%s -> %s]. Current maximum is %d addresses, as defined by IFCONFIG_POOL_MAX variable.", + print_in_addr_t(start, 0, &gc), + print_in_addr_t(end, 0, &gc), + IFCONFIG_POOL_MAX); + ret = false; } - gc_free (&gc); - return ret; + gc_free(&gc); + return ret; } struct ifconfig_pool * -ifconfig_pool_init (int type, in_addr_t start, in_addr_t end, - const bool duplicate_cn, - const bool ipv6_pool, const struct in6_addr ipv6_base, - const int ipv6_netbits ) +ifconfig_pool_init(int type, in_addr_t start, in_addr_t end, + const bool duplicate_cn, + const bool ipv6_pool, const struct in6_addr ipv6_base, + const int ipv6_netbits ) { - struct gc_arena gc = gc_new (); - struct ifconfig_pool *pool = NULL; + struct gc_arena gc = gc_new(); + struct ifconfig_pool *pool = NULL; - ASSERT (start <= end && end - start < IFCONFIG_POOL_MAX); - ALLOC_OBJ_CLEAR (pool, struct ifconfig_pool); + ASSERT(start <= end && end - start < IFCONFIG_POOL_MAX); + ALLOC_OBJ_CLEAR(pool, struct ifconfig_pool); - pool->type = type; - pool->duplicate_cn = duplicate_cn; + pool->type = type; + pool->duplicate_cn = duplicate_cn; - switch (type) + switch (type) { - case IFCONFIG_POOL_30NET: - pool->base = start & ~3; - pool->size = (((end | 3) + 1) - pool->base) >> 2; - break; - case IFCONFIG_POOL_INDIV: - pool->base = start; - pool->size = end - start + 1; - break; - default: - ASSERT (0); + case IFCONFIG_POOL_30NET: + pool->base = start & ~3; + pool->size = (((end | 3) + 1) - pool->base) >> 2; + break; + + case IFCONFIG_POOL_INDIV: + pool->base = start; + pool->size = end - start + 1; + break; + + default: + ASSERT(0); } - /* IPv6 pools are always "INDIV" type */ - pool->ipv6 = ipv6_pool; + /* IPv6 pools are always "INDIV" type */ + pool->ipv6 = ipv6_pool; - if ( pool->ipv6 ) + if (pool->ipv6) { - pool->base_ipv6 = ipv6_base; - pool->size_ipv6 = ipv6_netbits>96? ( 1<<(128-ipv6_netbits) ) - : IFCONFIG_POOL_MAX; - - msg( D_IFCONFIG_POOL, "IFCONFIG POOL IPv6: (IPv4) size=%d, size_ipv6=%d, netbits=%d, base_ipv6=%s", - pool->size, pool->size_ipv6, ipv6_netbits, - print_in6_addr( pool->base_ipv6, 0, &gc )); - - /* the current code is very simple and assumes that the IPv6 - * pool is at least as big as the IPv4 pool, and we don't need - * to do separate math etc. for IPv6 - */ - ASSERT( pool->size < pool->size_ipv6 ); + pool->base_ipv6 = ipv6_base; + pool->size_ipv6 = ipv6_netbits>96 ? ( 1<<(128-ipv6_netbits) ) + : IFCONFIG_POOL_MAX; + + msg( D_IFCONFIG_POOL, "IFCONFIG POOL IPv6: (IPv4) size=%d, size_ipv6=%d, netbits=%d, base_ipv6=%s", + pool->size, pool->size_ipv6, ipv6_netbits, + print_in6_addr( pool->base_ipv6, 0, &gc )); + + /* the current code is very simple and assumes that the IPv6 + * pool is at least as big as the IPv4 pool, and we don't need + * to do separate math etc. for IPv6 + */ + ASSERT( pool->size < pool->size_ipv6 ); } - ALLOC_ARRAY_CLEAR (pool->list, struct ifconfig_pool_entry, pool->size); + ALLOC_ARRAY_CLEAR(pool->list, struct ifconfig_pool_entry, pool->size); - msg (D_IFCONFIG_POOL, "IFCONFIG POOL: base=%s size=%d, ipv6=%d", - print_in_addr_t (pool->base, 0, &gc), - pool->size, pool->ipv6 ); + msg(D_IFCONFIG_POOL, "IFCONFIG POOL: base=%s size=%d, ipv6=%d", + print_in_addr_t(pool->base, 0, &gc), + pool->size, pool->ipv6 ); - gc_free (&gc); - return pool; + gc_free(&gc); + return pool; } void -ifconfig_pool_free (struct ifconfig_pool *pool) +ifconfig_pool_free(struct ifconfig_pool *pool) { - if (pool) + if (pool) { - int i; - for (i = 0; i < pool->size; ++i) - ifconfig_pool_entry_free (&pool->list[i], true); - free (pool->list); - free (pool); + int i; + for (i = 0; i < pool->size; ++i) + ifconfig_pool_entry_free(&pool->list[i], true); + free(pool->list); + free(pool); } } ifconfig_pool_handle -ifconfig_pool_acquire (struct ifconfig_pool *pool, in_addr_t *local, in_addr_t *remote, struct in6_addr *remote_ipv6, const char *common_name) +ifconfig_pool_acquire(struct ifconfig_pool *pool, in_addr_t *local, in_addr_t *remote, struct in6_addr *remote_ipv6, const char *common_name) { - int i; + int i; - i = ifconfig_pool_find (pool, common_name); - if (i >= 0) + i = ifconfig_pool_find(pool, common_name); + if (i >= 0) { - struct ifconfig_pool_entry *ipe = &pool->list[i]; - ASSERT (!ipe->in_use); - ifconfig_pool_entry_free (ipe, true); - ipe->in_use = true; - if (common_name) - ipe->common_name = string_alloc (common_name, NULL); - - switch (pool->type) - { - case IFCONFIG_POOL_30NET: - { - in_addr_t b = pool->base + (i << 2); - *local = b + 1; - *remote = b + 2; - break; - } - case IFCONFIG_POOL_INDIV: - { - in_addr_t b = pool->base + i; - *local = 0; - *remote = b; - break; - } - default: - ASSERT (0); - } - - /* IPv6 pools are always INDIV (--linear) */ - if ( pool->ipv6 && remote_ipv6 ) - { - *remote_ipv6 = add_in6_addr( pool->base_ipv6, i ); - } + struct ifconfig_pool_entry *ipe = &pool->list[i]; + ASSERT(!ipe->in_use); + ifconfig_pool_entry_free(ipe, true); + ipe->in_use = true; + if (common_name) + { + ipe->common_name = string_alloc(common_name, NULL); + } + + switch (pool->type) + { + case IFCONFIG_POOL_30NET: + { + in_addr_t b = pool->base + (i << 2); + *local = b + 1; + *remote = b + 2; + break; + } + + case IFCONFIG_POOL_INDIV: + { + in_addr_t b = pool->base + i; + *local = 0; + *remote = b; + break; + } + + default: + ASSERT(0); + } + + /* IPv6 pools are always INDIV (--linear) */ + if (pool->ipv6 && remote_ipv6) + { + *remote_ipv6 = add_in6_addr( pool->base_ipv6, i ); + } } - return i; + return i; } bool -ifconfig_pool_release (struct ifconfig_pool* pool, ifconfig_pool_handle hand, const bool hard) +ifconfig_pool_release(struct ifconfig_pool *pool, ifconfig_pool_handle hand, const bool hard) { - bool ret = false; - if (pool && hand >= 0 && hand < pool->size) + bool ret = false; + if (pool && hand >= 0 && hand < pool->size) { - ifconfig_pool_entry_free (&pool->list[hand], hard); - ret = true; + ifconfig_pool_entry_free(&pool->list[hand], hard); + ret = true; } - return ret; + return ret; } /* @@ -270,129 +286,135 @@ ifconfig_pool_release (struct ifconfig_pool* pool, ifconfig_pool_handle hand, co */ static ifconfig_pool_handle -ifconfig_pool_ip_base_to_handle (const struct ifconfig_pool* pool, const in_addr_t addr) +ifconfig_pool_ip_base_to_handle(const struct ifconfig_pool *pool, const in_addr_t addr) { - ifconfig_pool_handle ret = -1; + ifconfig_pool_handle ret = -1; - switch (pool->type) + switch (pool->type) { - case IFCONFIG_POOL_30NET: - { - ret = (addr - pool->base) >> 2; - break; - } - case IFCONFIG_POOL_INDIV: - { - ret = (addr - pool->base); - break; - } - default: - ASSERT (0); + case IFCONFIG_POOL_30NET: + { + ret = (addr - pool->base) >> 2; + break; + } + + case IFCONFIG_POOL_INDIV: + { + ret = (addr - pool->base); + break; + } + + default: + ASSERT(0); } - if (ret < 0 || ret >= pool->size) - ret = -1; + if (ret < 0 || ret >= pool->size) + { + ret = -1; + } - return ret; + return ret; } static in_addr_t -ifconfig_pool_handle_to_ip_base (const struct ifconfig_pool* pool, ifconfig_pool_handle hand) +ifconfig_pool_handle_to_ip_base(const struct ifconfig_pool *pool, ifconfig_pool_handle hand) { - in_addr_t ret = 0; + in_addr_t ret = 0; - if (hand >= 0 && hand < pool->size) + if (hand >= 0 && hand < pool->size) { - switch (pool->type) - { - case IFCONFIG_POOL_30NET: - { - ret = pool->base + (hand << 2);; - break; - } - case IFCONFIG_POOL_INDIV: - { - ret = pool->base + hand; - break; - } - default: - ASSERT (0); - } + switch (pool->type) + { + case IFCONFIG_POOL_30NET: + { + ret = pool->base + (hand << 2); + break; + } + + case IFCONFIG_POOL_INDIV: + { + ret = pool->base + hand; + break; + } + + default: + ASSERT(0); + } } - return ret; + return ret; } static struct in6_addr -ifconfig_pool_handle_to_ipv6_base (const struct ifconfig_pool* pool, ifconfig_pool_handle hand) +ifconfig_pool_handle_to_ipv6_base(const struct ifconfig_pool *pool, ifconfig_pool_handle hand) { - struct in6_addr ret = in6addr_any; + struct in6_addr ret = in6addr_any; - /* IPv6 pools are always INDIV (--linear) */ - if (hand >= 0 && hand < pool->size_ipv6 ) + /* IPv6 pools are always INDIV (--linear) */ + if (hand >= 0 && hand < pool->size_ipv6) { - ret = add_in6_addr( pool->base_ipv6, hand ); + ret = add_in6_addr( pool->base_ipv6, hand ); } - return ret; + return ret; } static void -ifconfig_pool_set (struct ifconfig_pool* pool, const char *cn, const in_addr_t addr, const bool fixed) +ifconfig_pool_set(struct ifconfig_pool *pool, const char *cn, const in_addr_t addr, const bool fixed) { - ifconfig_pool_handle h = ifconfig_pool_ip_base_to_handle (pool, addr); - if (h >= 0) + ifconfig_pool_handle h = ifconfig_pool_ip_base_to_handle(pool, addr); + if (h >= 0) { - struct ifconfig_pool_entry *e = &pool->list[h]; - ifconfig_pool_entry_free (e, true); - e->in_use = false; - e->common_name = string_alloc (cn, NULL); - e->last_release = now; - e->fixed = fixed; + struct ifconfig_pool_entry *e = &pool->list[h]; + ifconfig_pool_entry_free(e, true); + e->in_use = false; + e->common_name = string_alloc(cn, NULL); + e->last_release = now; + e->fixed = fixed; } } static void -ifconfig_pool_list (const struct ifconfig_pool* pool, struct status_output *out) +ifconfig_pool_list(const struct ifconfig_pool *pool, struct status_output *out) { - if (pool && out) + if (pool && out) { - struct gc_arena gc = gc_new (); - int i; - - for (i = 0; i < pool->size; ++i) - { - const struct ifconfig_pool_entry *e = &pool->list[i]; - if (e->common_name) - { - const in_addr_t ip = ifconfig_pool_handle_to_ip_base (pool, i); - if ( pool->ipv6 ) - { - struct in6_addr ip6 = ifconfig_pool_handle_to_ipv6_base (pool, i); - status_printf (out, "%s,%s,%s", - e->common_name, - print_in_addr_t (ip, 0, &gc), - print_in6_addr (ip6, 0, &gc)); - } - else - { - status_printf (out, "%s,%s", - e->common_name, - print_in_addr_t (ip, 0, &gc)); - } - } - } - gc_free (&gc); + struct gc_arena gc = gc_new(); + int i; + + for (i = 0; i < pool->size; ++i) + { + const struct ifconfig_pool_entry *e = &pool->list[i]; + if (e->common_name) + { + const in_addr_t ip = ifconfig_pool_handle_to_ip_base(pool, i); + if (pool->ipv6) + { + struct in6_addr ip6 = ifconfig_pool_handle_to_ipv6_base(pool, i); + status_printf(out, "%s,%s,%s", + e->common_name, + print_in_addr_t(ip, 0, &gc), + print_in6_addr(ip6, 0, &gc)); + } + else + { + status_printf(out, "%s,%s", + e->common_name, + print_in_addr_t(ip, 0, &gc)); + } + } + } + gc_free(&gc); } } static void -ifconfig_pool_msg (const struct ifconfig_pool* pool, int msglevel) +ifconfig_pool_msg(const struct ifconfig_pool *pool, int msglevel) { - struct status_output *so = status_open (NULL, 0, msglevel, NULL, 0); - ASSERT (so); - status_printf (so, "IFCONFIG POOL LIST"); - ifconfig_pool_list (pool, so); - status_close (so); + struct status_output *so = status_open(NULL, 0, msglevel, NULL, 0); + ASSERT(so); + status_printf(so, "IFCONFIG POOL LIST"); + ifconfig_pool_list(pool, so); + status_close(so); } /* @@ -400,105 +422,115 @@ ifconfig_pool_msg (const struct ifconfig_pool* pool, int msglevel) */ struct ifconfig_pool_persist * -ifconfig_pool_persist_init (const char *filename, int refresh_freq) +ifconfig_pool_persist_init(const char *filename, int refresh_freq) { - struct ifconfig_pool_persist *ret; + struct ifconfig_pool_persist *ret; - ASSERT (filename); + ASSERT(filename); - ALLOC_OBJ_CLEAR (ret, struct ifconfig_pool_persist); - if (refresh_freq > 0) + ALLOC_OBJ_CLEAR(ret, struct ifconfig_pool_persist); + if (refresh_freq > 0) { - ret->fixed = false; - ret->file = status_open (filename, refresh_freq, -1, NULL, STATUS_OUTPUT_READ|STATUS_OUTPUT_WRITE); + ret->fixed = false; + ret->file = status_open(filename, refresh_freq, -1, NULL, STATUS_OUTPUT_READ|STATUS_OUTPUT_WRITE); } - else + else { - ret->fixed = true; - ret->file = status_open (filename, 0, -1, NULL, STATUS_OUTPUT_READ); + ret->fixed = true; + ret->file = status_open(filename, 0, -1, NULL, STATUS_OUTPUT_READ); } - return ret; + return ret; } void -ifconfig_pool_persist_close (struct ifconfig_pool_persist *persist) +ifconfig_pool_persist_close(struct ifconfig_pool_persist *persist) { - if (persist) + if (persist) { - if (persist->file) - status_close (persist->file); - free (persist); + if (persist->file) + { + status_close(persist->file); + } + free(persist); } } bool -ifconfig_pool_write_trigger (struct ifconfig_pool_persist *persist) +ifconfig_pool_write_trigger(struct ifconfig_pool_persist *persist) { - if (persist->file) - return status_trigger (persist->file); - else - return false; + if (persist->file) + { + return status_trigger(persist->file); + } + else + { + return false; + } } void -ifconfig_pool_read (struct ifconfig_pool_persist *persist, struct ifconfig_pool *pool) +ifconfig_pool_read(struct ifconfig_pool_persist *persist, struct ifconfig_pool *pool) { - const int buf_size = 128; + const int buf_size = 128; - update_time (); - if (persist && persist->file && pool) + update_time(); + if (persist && persist->file && pool) { - struct gc_arena gc = gc_new (); - struct buffer in = alloc_buf_gc (256, &gc); - char *cn_buf; - char *ip_buf; - int line = 0; - - ALLOC_ARRAY_CLEAR_GC (cn_buf, char, buf_size, &gc); - ALLOC_ARRAY_CLEAR_GC (ip_buf, char, buf_size, &gc); - - while (true) - { - ASSERT (buf_init (&in, 0)); - if (!status_read (persist->file, &in)) - break; - ++line; - if (BLEN (&in)) - { - int c = *BSTR(&in); - if (c == '#' || c == ';') - continue; - msg( M_INFO, "ifconfig_pool_read(), in='%s', TODO: IPv6", - BSTR(&in) ); - - if (buf_parse (&in, ',', cn_buf, buf_size) - && buf_parse (&in, ',', ip_buf, buf_size)) - { - bool succeeded; - const in_addr_t addr = getaddr (GETADDR_HOST_ORDER, ip_buf, 0, &succeeded, NULL); - if (succeeded) - { - msg( M_INFO, "succeeded -> ifconfig_pool_set()"); - ifconfig_pool_set (pool, cn_buf, addr, persist->fixed); - } - } - } - } - - ifconfig_pool_msg (pool, D_IFCONFIG_POOL); - - gc_free (&gc); + struct gc_arena gc = gc_new(); + struct buffer in = alloc_buf_gc(256, &gc); + char *cn_buf; + char *ip_buf; + int line = 0; + + ALLOC_ARRAY_CLEAR_GC(cn_buf, char, buf_size, &gc); + ALLOC_ARRAY_CLEAR_GC(ip_buf, char, buf_size, &gc); + + while (true) + { + ASSERT(buf_init(&in, 0)); + if (!status_read(persist->file, &in)) + { + break; + } + ++line; + if (BLEN(&in)) + { + int c = *BSTR(&in); + if (c == '#' || c == ';') + { + continue; + } + msg( M_INFO, "ifconfig_pool_read(), in='%s', TODO: IPv6", + BSTR(&in) ); + + if (buf_parse(&in, ',', cn_buf, buf_size) + && buf_parse(&in, ',', ip_buf, buf_size)) + { + bool succeeded; + const in_addr_t addr = getaddr(GETADDR_HOST_ORDER, ip_buf, 0, &succeeded, NULL); + if (succeeded) + { + msg( M_INFO, "succeeded -> ifconfig_pool_set()"); + ifconfig_pool_set(pool, cn_buf, addr, persist->fixed); + } + } + } + } + + ifconfig_pool_msg(pool, D_IFCONFIG_POOL); + + gc_free(&gc); } } void -ifconfig_pool_write (struct ifconfig_pool_persist *persist, const struct ifconfig_pool *pool) +ifconfig_pool_write(struct ifconfig_pool_persist *persist, const struct ifconfig_pool *pool) { - if (persist && persist->file && (status_rw_flags (persist->file) & STATUS_OUTPUT_WRITE) && pool) + if (persist && persist->file && (status_rw_flags(persist->file) & STATUS_OUTPUT_WRITE) && pool) { - status_reset (persist->file); - ifconfig_pool_list (pool, persist->file); - status_flush (persist->file); + status_reset(persist->file); + ifconfig_pool_list(pool, persist->file); + status_flush(persist->file); } } @@ -511,79 +543,85 @@ ifconfig_pool_write (struct ifconfig_pool_persist *persist, const struct ifconfi #define DUP_CN void -ifconfig_pool_test (in_addr_t start, in_addr_t end) +ifconfig_pool_test(in_addr_t start, in_addr_t end) { - struct gc_arena gc = gc_new (); - struct ifconfig_pool *p = ifconfig_pool_init (IFCONFIG_POOL_30NET, start, end); - /*struct ifconfig_pool *p = ifconfig_pool_init (IFCONFIG_POOL_INDIV, start, end);*/ - ifconfig_pool_handle array[256]; - int i; + struct gc_arena gc = gc_new(); + struct ifconfig_pool *p = ifconfig_pool_init(IFCONFIG_POOL_30NET, start, end); + /*struct ifconfig_pool *p = ifconfig_pool_init (IFCONFIG_POOL_INDIV, start, end);*/ + ifconfig_pool_handle array[256]; + int i; - CLEAR (array); + CLEAR(array); - msg (M_INFO | M_NOPREFIX, "************ 1"); - for (i = 0; i < (int) SIZE (array); ++i) + msg(M_INFO | M_NOPREFIX, "************ 1"); + for (i = 0; i < (int) SIZE(array); ++i) { - char *cn; - ifconfig_pool_handle h; - in_addr_t local, remote; - char buf[256]; - openvpn_snprintf (buf, sizeof(buf), "common-name-%d", i); + char *cn; + ifconfig_pool_handle h; + in_addr_t local, remote; + char buf[256]; + openvpn_snprintf(buf, sizeof(buf), "common-name-%d", i); #ifdef DUP_CN - cn = NULL; + cn = NULL; #else - cn = buf; + cn = buf; #endif - h = ifconfig_pool_acquire (p, &local, &remote, NULL, cn); - if (h < 0) - break; - msg (M_INFO | M_NOPREFIX, "IFCONFIG_POOL TEST pass 1: l=%s r=%s cn=%s", - print_in_addr_t (local, 0, &gc), - print_in_addr_t (remote, 0, &gc), - cn); - array[i] = h; - + h = ifconfig_pool_acquire(p, &local, &remote, NULL, cn); + if (h < 0) + { + break; + } + msg(M_INFO | M_NOPREFIX, "IFCONFIG_POOL TEST pass 1: l=%s r=%s cn=%s", + print_in_addr_t(local, 0, &gc), + print_in_addr_t(remote, 0, &gc), + cn); + array[i] = h; + } - msg (M_INFO | M_NOPREFIX, "************* 2"); - for (i = (int) SIZE (array) / 16; i < (int) SIZE (array) / 8; ++i) + msg(M_INFO | M_NOPREFIX, "************* 2"); + for (i = (int) SIZE(array) / 16; i < (int) SIZE(array) / 8; ++i) { - msg (M_INFO, "Attempt to release %d cn=%s", array[i], p->list[i].common_name); - if (!ifconfig_pool_release (p, array[i])) - break; - msg (M_INFO, "Succeeded"); + msg(M_INFO, "Attempt to release %d cn=%s", array[i], p->list[i].common_name); + if (!ifconfig_pool_release(p, array[i])) + { + break; + } + msg(M_INFO, "Succeeded"); } - CLEAR (array); + CLEAR(array); - msg (M_INFO | M_NOPREFIX, "**************** 3"); - for (i = 0; i < (int) SIZE (array); ++i) + msg(M_INFO | M_NOPREFIX, "**************** 3"); + for (i = 0; i < (int) SIZE(array); ++i) { - char *cn; - ifconfig_pool_handle h; - in_addr_t local, remote; - char buf[256]; - snprintf (buf, sizeof(buf), "common-name-%d", i+24); + char *cn; + ifconfig_pool_handle h; + in_addr_t local, remote; + char buf[256]; + snprintf(buf, sizeof(buf), "common-name-%d", i+24); #ifdef DUP_CN - cn = NULL; + cn = NULL; #else - cn = buf; + cn = buf; #endif - h = ifconfig_pool_acquire (p, &local, &remote, NULL, cn); - if (h < 0) - break; - msg (M_INFO | M_NOPREFIX, "IFCONFIG_POOL TEST pass 3: l=%s r=%s cn=%s", - print_in_addr_t (local, 0, &gc), - print_in_addr_t (remote, 0, &gc), - cn); - array[i] = h; - + h = ifconfig_pool_acquire(p, &local, &remote, NULL, cn); + if (h < 0) + { + break; + } + msg(M_INFO | M_NOPREFIX, "IFCONFIG_POOL TEST pass 3: l=%s r=%s cn=%s", + print_in_addr_t(local, 0, &gc), + print_in_addr_t(remote, 0, &gc), + cn); + array[i] = h; + } - ifconfig_pool_free (p); - gc_free (&gc); + ifconfig_pool_free(p); + gc_free(&gc); } -#endif +#endif /* ifdef IFCONFIG_POOL_TEST */ -#endif +#endif /* if P2MP */ diff --git a/src/openvpn/pool.h b/src/openvpn/pool.h index fc9d6ab2288..5638b9f3269 100644 --- a/src/openvpn/pool.h +++ b/src/openvpn/pool.h @@ -40,52 +40,56 @@ struct ifconfig_pool_entry { - bool in_use; - char *common_name; - time_t last_release; - bool fixed; + bool in_use; + char *common_name; + time_t last_release; + bool fixed; }; struct ifconfig_pool { - in_addr_t base; - int size; - int type; - bool duplicate_cn; - bool ipv6; - struct in6_addr base_ipv6; - unsigned int size_ipv6; - struct ifconfig_pool_entry *list; + in_addr_t base; + int size; + int type; + bool duplicate_cn; + bool ipv6; + struct in6_addr base_ipv6; + unsigned int size_ipv6; + struct ifconfig_pool_entry *list; }; struct ifconfig_pool_persist { - struct status_output *file; - bool fixed; + struct status_output *file; + bool fixed; }; typedef int ifconfig_pool_handle; -struct ifconfig_pool *ifconfig_pool_init (int type, in_addr_t start, in_addr_t end, const bool duplicate_cn, const bool ipv6_pool, const struct in6_addr ipv6_base, const int ipv6_netbits ); +struct ifconfig_pool *ifconfig_pool_init(int type, in_addr_t start, in_addr_t end, const bool duplicate_cn, const bool ipv6_pool, const struct in6_addr ipv6_base, const int ipv6_netbits ); -void ifconfig_pool_free (struct ifconfig_pool *pool); +void ifconfig_pool_free(struct ifconfig_pool *pool); -bool ifconfig_pool_verify_range (const int msglevel, const in_addr_t start, const in_addr_t end); +bool ifconfig_pool_verify_range(const int msglevel, const in_addr_t start, const in_addr_t end); -ifconfig_pool_handle ifconfig_pool_acquire (struct ifconfig_pool *pool, in_addr_t *local, in_addr_t *remote, struct in6_addr *remote_ipv6, const char *common_name); +ifconfig_pool_handle ifconfig_pool_acquire(struct ifconfig_pool *pool, in_addr_t *local, in_addr_t *remote, struct in6_addr *remote_ipv6, const char *common_name); -bool ifconfig_pool_release (struct ifconfig_pool* pool, ifconfig_pool_handle hand, const bool hard); +bool ifconfig_pool_release(struct ifconfig_pool *pool, ifconfig_pool_handle hand, const bool hard); -struct ifconfig_pool_persist *ifconfig_pool_persist_init (const char *filename, int refresh_freq); -void ifconfig_pool_persist_close (struct ifconfig_pool_persist *persist); -bool ifconfig_pool_write_trigger (struct ifconfig_pool_persist *persist); +struct ifconfig_pool_persist *ifconfig_pool_persist_init(const char *filename, int refresh_freq); -void ifconfig_pool_read (struct ifconfig_pool_persist *persist, struct ifconfig_pool *pool); -void ifconfig_pool_write (struct ifconfig_pool_persist *persist, const struct ifconfig_pool *pool); +void ifconfig_pool_persist_close(struct ifconfig_pool_persist *persist); + +bool ifconfig_pool_write_trigger(struct ifconfig_pool_persist *persist); + +void ifconfig_pool_read(struct ifconfig_pool_persist *persist, struct ifconfig_pool *pool); + +void ifconfig_pool_write(struct ifconfig_pool_persist *persist, const struct ifconfig_pool *pool); #ifdef IFCONFIG_POOL_TEST -void ifconfig_pool_test (in_addr_t start, in_addr_t end); -#endif +void ifconfig_pool_test(in_addr_t start, in_addr_t end); #endif -#endif + +#endif /* if P2MP */ +#endif /* ifndef POOL_H */ diff --git a/src/openvpn/proto.c b/src/openvpn/proto.c index 7b58e6ab170..acf35f5cb68 100644 --- a/src/openvpn/proto.c +++ b/src/openvpn/proto.c @@ -41,48 +41,60 @@ */ static bool -is_ipv_X ( int tunnel_type, struct buffer *buf, int ip_ver ) +is_ipv_X( int tunnel_type, struct buffer *buf, int ip_ver ) { - int offset; - const struct openvpn_iphdr *ih; + int offset; + const struct openvpn_iphdr *ih; - verify_align_4 (buf); - if (tunnel_type == DEV_TYPE_TUN) + verify_align_4(buf); + if (tunnel_type == DEV_TYPE_TUN) { - if (BLEN (buf) < (int) sizeof (struct openvpn_iphdr)) - return false; - offset = 0; + if (BLEN(buf) < (int) sizeof(struct openvpn_iphdr)) + { + return false; + } + offset = 0; } - else if (tunnel_type == DEV_TYPE_TAP) + else if (tunnel_type == DEV_TYPE_TAP) { - const struct openvpn_ethhdr *eh; - if (BLEN (buf) < (int)(sizeof (struct openvpn_ethhdr) - + sizeof (struct openvpn_iphdr))) - return false; - eh = (const struct openvpn_ethhdr *) BPTR (buf); - if (ntohs (eh->proto) != (ip_ver == 6 ? OPENVPN_ETH_P_IPV6 : OPENVPN_ETH_P_IPV4)) - return false; - offset = sizeof (struct openvpn_ethhdr); + const struct openvpn_ethhdr *eh; + if (BLEN(buf) < (int)(sizeof(struct openvpn_ethhdr) + + sizeof(struct openvpn_iphdr))) + { + return false; + } + eh = (const struct openvpn_ethhdr *) BPTR(buf); + if (ntohs(eh->proto) != (ip_ver == 6 ? OPENVPN_ETH_P_IPV6 : OPENVPN_ETH_P_IPV4)) + { + return false; + } + offset = sizeof(struct openvpn_ethhdr); + } + else + { + return false; } - else - return false; - ih = (const struct openvpn_iphdr *) (BPTR (buf) + offset); + ih = (const struct openvpn_iphdr *) (BPTR(buf) + offset); - /* IP version is stored in the same bits for IPv4 or IPv6 header */ - if (OPENVPN_IPH_GET_VER (ih->version_len) == ip_ver) - return buf_advance (buf, offset); - else - return false; + /* IP version is stored in the same bits for IPv4 or IPv6 header */ + if (OPENVPN_IPH_GET_VER(ih->version_len) == ip_ver) + { + return buf_advance(buf, offset); + } + else + { + return false; + } } bool -is_ipv4 (int tunnel_type, struct buffer *buf) +is_ipv4(int tunnel_type, struct buffer *buf) { return is_ipv_X( tunnel_type, buf, 4 ); } bool -is_ipv6 (int tunnel_type, struct buffer *buf) +is_ipv6(int tunnel_type, struct buffer *buf) { return is_ipv_X( tunnel_type, buf, 6 ); } @@ -90,52 +102,56 @@ is_ipv6 (int tunnel_type, struct buffer *buf) #ifdef PACKET_TRUNCATION_CHECK void -ipv4_packet_size_verify (const uint8_t *data, - const int size, - const int tunnel_type, - const char *prefix, - counter_type *errors) +ipv4_packet_size_verify(const uint8_t *data, + const int size, + const int tunnel_type, + const char *prefix, + counter_type *errors) { - if (size > 0) + if (size > 0) { - struct buffer buf; - - buf_set_read (&buf, data, size); - - if (is_ipv4 (tunnel_type, &buf)) - { - const struct openvpn_iphdr *pip; - int hlen; - int totlen; - const char *msgstr = "PACKET SIZE INFO"; - unsigned int msglevel = D_PACKET_TRUNC_DEBUG; - - if (BLEN (&buf) < (int) sizeof (struct openvpn_iphdr)) - return; - - verify_align_4 (&buf); - pip = (struct openvpn_iphdr *) BPTR (&buf); - - hlen = OPENVPN_IPH_GET_LEN (pip->version_len); - totlen = ntohs (pip->tot_len); - - if (BLEN (&buf) != totlen) - { - msgstr = "PACKET TRUNCATION ERROR"; - msglevel = D_PACKET_TRUNC_ERR; - if (errors) - ++(*errors); - } - - msg (msglevel, "%s %s: size=%d totlen=%d hlen=%d errcount=" counter_format, - msgstr, - prefix, - BLEN (&buf), - totlen, - hlen, - errors ? *errors : (counter_type)0); - } + struct buffer buf; + + buf_set_read(&buf, data, size); + + if (is_ipv4(tunnel_type, &buf)) + { + const struct openvpn_iphdr *pip; + int hlen; + int totlen; + const char *msgstr = "PACKET SIZE INFO"; + unsigned int msglevel = D_PACKET_TRUNC_DEBUG; + + if (BLEN(&buf) < (int) sizeof(struct openvpn_iphdr)) + { + return; + } + + verify_align_4(&buf); + pip = (struct openvpn_iphdr *) BPTR(&buf); + + hlen = OPENVPN_IPH_GET_LEN(pip->version_len); + totlen = ntohs(pip->tot_len); + + if (BLEN(&buf) != totlen) + { + msgstr = "PACKET TRUNCATION ERROR"; + msglevel = D_PACKET_TRUNC_ERR; + if (errors) + { + ++(*errors); + } + } + + msg(msglevel, "%s %s: size=%d totlen=%d hlen=%d errcount=" counter_format, + msgstr, + prefix, + BLEN(&buf), + totlen, + hlen, + errors ? *errors : (counter_type)0); + } } } -#endif +#endif /* ifdef PACKET_TRUNCATION_CHECK */ diff --git a/src/openvpn/proto.h b/src/openvpn/proto.h index 07612c8732a..1b560a3aa67 100644 --- a/src/openvpn/proto.h +++ b/src/openvpn/proto.h @@ -53,72 +53,72 @@ */ #define OPENVPN_ETH_ALEN 6 /* ethernet address length */ -struct openvpn_ethhdr +struct openvpn_ethhdr { - uint8_t dest[OPENVPN_ETH_ALEN]; /* destination ethernet addr */ - uint8_t source[OPENVPN_ETH_ALEN]; /* source ethernet addr */ + uint8_t dest[OPENVPN_ETH_ALEN]; /* destination ethernet addr */ + uint8_t source[OPENVPN_ETH_ALEN]; /* source ethernet addr */ -# define OPENVPN_ETH_P_IPV4 0x0800 /* IPv4 protocol */ -# define OPENVPN_ETH_P_IPV6 0x86DD /* IPv6 protocol */ -# define OPENVPN_ETH_P_ARP 0x0806 /* ARP protocol */ - uint16_t proto; /* packet type ID field */ +#define OPENVPN_ETH_P_IPV4 0x0800 /* IPv4 protocol */ +#define OPENVPN_ETH_P_IPV6 0x86DD /* IPv6 protocol */ +#define OPENVPN_ETH_P_ARP 0x0806 /* ARP protocol */ + uint16_t proto; /* packet type ID field */ }; struct openvpn_arp { -# define ARP_MAC_ADDR_TYPE 0x0001 - uint16_t mac_addr_type; /* 0x0001 */ +#define ARP_MAC_ADDR_TYPE 0x0001 + uint16_t mac_addr_type; /* 0x0001 */ - uint16_t proto_addr_type; /* 0x0800 */ - uint8_t mac_addr_size; /* 0x06 */ - uint8_t proto_addr_size; /* 0x04 */ + uint16_t proto_addr_type; /* 0x0800 */ + uint8_t mac_addr_size; /* 0x06 */ + uint8_t proto_addr_size; /* 0x04 */ -# define ARP_REQUEST 0x0001 -# define ARP_REPLY 0x0002 - uint16_t arp_command; /* 0x0001 for ARP request, 0x0002 for ARP reply */ +#define ARP_REQUEST 0x0001 +#define ARP_REPLY 0x0002 + uint16_t arp_command; /* 0x0001 for ARP request, 0x0002 for ARP reply */ - uint8_t mac_src[OPENVPN_ETH_ALEN]; - in_addr_t ip_src; - uint8_t mac_dest[OPENVPN_ETH_ALEN]; - in_addr_t ip_dest; + uint8_t mac_src[OPENVPN_ETH_ALEN]; + in_addr_t ip_src; + uint8_t mac_dest[OPENVPN_ETH_ALEN]; + in_addr_t ip_dest; }; struct openvpn_iphdr { -# define OPENVPN_IPH_GET_VER(v) (((v) >> 4) & 0x0F) -# define OPENVPN_IPH_GET_LEN(v) (((v) & 0x0F) << 2) - uint8_t version_len; +#define OPENVPN_IPH_GET_VER(v) (((v) >> 4) & 0x0F) +#define OPENVPN_IPH_GET_LEN(v) (((v) & 0x0F) << 2) + uint8_t version_len; - uint8_t tos; - uint16_t tot_len; - uint16_t id; + uint8_t tos; + uint16_t tot_len; + uint16_t id; -# define OPENVPN_IP_OFFMASK 0x1fff - uint16_t frag_off; +#define OPENVPN_IP_OFFMASK 0x1fff + uint16_t frag_off; - uint8_t ttl; + uint8_t ttl; -# define OPENVPN_IPPROTO_IGMP 2 /* IGMP protocol */ -# define OPENVPN_IPPROTO_TCP 6 /* TCP protocol */ -# define OPENVPN_IPPROTO_UDP 17 /* UDP protocol */ - uint8_t protocol; +#define OPENVPN_IPPROTO_IGMP 2 /* IGMP protocol */ +#define OPENVPN_IPPROTO_TCP 6 /* TCP protocol */ +#define OPENVPN_IPPROTO_UDP 17 /* UDP protocol */ + uint8_t protocol; - uint16_t check; - uint32_t saddr; - uint32_t daddr; - /*The options start here. */ + uint16_t check; + uint32_t saddr; + uint32_t daddr; + /*The options start here. */ }; /* * IPv6 header */ struct openvpn_ipv6hdr { - uint8_t version_prio; - uint8_t flow_lbl[3]; - uint16_t payload_len; - uint8_t nexthdr; - uint8_t hop_limit; - - struct in6_addr saddr; - struct in6_addr daddr; + uint8_t version_prio; + uint8_t flow_lbl[3]; + uint16_t payload_len; + uint8_t nexthdr; + uint8_t hop_limit; + + struct in6_addr saddr; + struct in6_addr daddr; }; @@ -126,50 +126,50 @@ struct openvpn_ipv6hdr { * UDP header */ struct openvpn_udphdr { - uint16_t source; - uint16_t dest; - uint16_t len; - uint16_t check; + uint16_t source; + uint16_t dest; + uint16_t len; + uint16_t check; }; /* * TCP header, per RFC 793. */ struct openvpn_tcphdr { - uint16_t source; /* source port */ - uint16_t dest; /* destination port */ - uint32_t seq; /* sequence number */ - uint32_t ack_seq; /* acknowledgement number */ - -# define OPENVPN_TCPH_GET_DOFF(d) (((d) & 0xF0) >> 2) - uint8_t doff_res; - -# define OPENVPN_TCPH_FIN_MASK (1<<0) -# define OPENVPN_TCPH_SYN_MASK (1<<1) -# define OPENVPN_TCPH_RST_MASK (1<<2) -# define OPENVPN_TCPH_PSH_MASK (1<<3) -# define OPENVPN_TCPH_ACK_MASK (1<<4) -# define OPENVPN_TCPH_URG_MASK (1<<5) -# define OPENVPN_TCPH_ECE_MASK (1<<6) -# define OPENVPN_TCPH_CWR_MASK (1<<7) - uint8_t flags; - - uint16_t window; - uint16_t check; - uint16_t urg_ptr; + uint16_t source; /* source port */ + uint16_t dest; /* destination port */ + uint32_t seq; /* sequence number */ + uint32_t ack_seq; /* acknowledgement number */ + +#define OPENVPN_TCPH_GET_DOFF(d) (((d) & 0xF0) >> 2) + uint8_t doff_res; + +#define OPENVPN_TCPH_FIN_MASK (1<<0) +#define OPENVPN_TCPH_SYN_MASK (1<<1) +#define OPENVPN_TCPH_RST_MASK (1<<2) +#define OPENVPN_TCPH_PSH_MASK (1<<3) +#define OPENVPN_TCPH_ACK_MASK (1<<4) +#define OPENVPN_TCPH_URG_MASK (1<<5) +#define OPENVPN_TCPH_ECE_MASK (1<<6) +#define OPENVPN_TCPH_CWR_MASK (1<<7) + uint8_t flags; + + uint16_t window; + uint16_t check; + uint16_t urg_ptr; }; -#define OPENVPN_TCPOPT_EOL 0 -#define OPENVPN_TCPOPT_NOP 1 -#define OPENVPN_TCPOPT_MAXSEG 2 +#define OPENVPN_TCPOPT_EOL 0 +#define OPENVPN_TCPOPT_NOP 1 +#define OPENVPN_TCPOPT_MAXSEG 2 #define OPENVPN_TCPOLEN_MAXSEG 4 struct ip_tcp_udp_hdr { - struct openvpn_iphdr ip; - union { - struct openvpn_tcphdr tcp; - struct openvpn_udphdr udp; - } u; + struct openvpn_iphdr ip; + union { + struct openvpn_tcphdr tcp; + struct openvpn_udphdr udp; + } u; }; #pragma pack() @@ -183,28 +183,28 @@ struct ip_tcp_udp_hdr { * is the checksum value to be updated. */ #define ADJUST_CHECKSUM(acc, cksum) { \ - int _acc = acc; \ - _acc += (cksum); \ - if (_acc < 0) { \ - _acc = -_acc; \ - _acc = (_acc >> 16) + (_acc & 0xffff); \ - _acc += _acc >> 16; \ - (cksum) = (uint16_t) ~_acc; \ - } else { \ - _acc = (_acc >> 16) + (_acc & 0xffff); \ - _acc += _acc >> 16; \ - (cksum) = (uint16_t) _acc; \ - } \ + int _acc = acc; \ + _acc += (cksum); \ + if (_acc < 0) { \ + _acc = -_acc; \ + _acc = (_acc >> 16) + (_acc & 0xffff); \ + _acc += _acc >> 16; \ + (cksum) = (uint16_t) ~_acc; \ + } else { \ + _acc = (_acc >> 16) + (_acc & 0xffff); \ + _acc += _acc >> 16; \ + (cksum) = (uint16_t) _acc; \ + } \ } #define ADD_CHECKSUM_32(acc, u32) { \ - acc += (u32) & 0xffff; \ - acc += (u32) >> 16; \ + acc += (u32) & 0xffff; \ + acc += (u32) >> 16; \ } #define SUB_CHECKSUM_32(acc, u32) { \ - acc -= (u32) & 0xffff; \ - acc -= (u32) >> 16; \ + acc -= (u32) & 0xffff; \ + acc -= (u32) >> 16; \ } /* @@ -216,61 +216,64 @@ struct ip_tcp_udp_hdr { * (RFC 879, section 7). */ #define MTU_TO_MSS(mtu) (mtu - sizeof(struct openvpn_iphdr) \ - - sizeof(struct openvpn_tcphdr)) + - sizeof(struct openvpn_tcphdr)) /* * This returns an ip protocol version of packet inside tun * and offset of IP header (via parameter). */ -inline static int get_tun_ip_ver(int tunnel_type, struct buffer *buf, int *ip_hdr_offset) +inline static int +get_tun_ip_ver(int tunnel_type, struct buffer *buf, int *ip_hdr_offset) { - int ip_ver = -1; + int ip_ver = -1; - /* for tun get ip version from ip header */ - if (tunnel_type == DEV_TYPE_TUN) + /* for tun get ip version from ip header */ + if (tunnel_type == DEV_TYPE_TUN) { - *ip_hdr_offset = 0; - if (likely(BLEN (buf) >= (int) sizeof (struct openvpn_iphdr))) - { - ip_ver = OPENVPN_IPH_GET_VER (*BPTR(buf)); - } + *ip_hdr_offset = 0; + if (likely(BLEN(buf) >= (int) sizeof(struct openvpn_iphdr))) + { + ip_ver = OPENVPN_IPH_GET_VER(*BPTR(buf)); + } } - else if (tunnel_type == DEV_TYPE_TAP) + else if (tunnel_type == DEV_TYPE_TAP) { - *ip_hdr_offset = (int)(sizeof (struct openvpn_ethhdr)); - /* for tap get ip version from eth header */ - if (likely(BLEN (buf) >= *ip_hdr_offset)) - { - const struct openvpn_ethhdr *eh = (const struct openvpn_ethhdr *) BPTR (buf); - uint16_t proto = ntohs (eh->proto); - if (proto == OPENVPN_ETH_P_IPV6) - { - ip_ver = 6; - } - else if (proto == OPENVPN_ETH_P_IPV4) - { - ip_ver = 4; - } - } + *ip_hdr_offset = (int)(sizeof(struct openvpn_ethhdr)); + /* for tap get ip version from eth header */ + if (likely(BLEN(buf) >= *ip_hdr_offset)) + { + const struct openvpn_ethhdr *eh = (const struct openvpn_ethhdr *) BPTR(buf); + uint16_t proto = ntohs(eh->proto); + if (proto == OPENVPN_ETH_P_IPV6) + { + ip_ver = 6; + } + else if (proto == OPENVPN_ETH_P_IPV4) + { + ip_ver = 4; + } + } } - return ip_ver; + return ip_ver; } /* * If raw tunnel packet is IPv4 or IPv6, return true and increment * buffer offset to start of IP header. */ -bool is_ipv4 (int tunnel_type, struct buffer *buf); -bool is_ipv6 (int tunnel_type, struct buffer *buf); +bool is_ipv4(int tunnel_type, struct buffer *buf); + +bool is_ipv6(int tunnel_type, struct buffer *buf); #ifdef PACKET_TRUNCATION_CHECK -void ipv4_packet_size_verify (const uint8_t *data, - const int size, - const int tunnel_type, - const char - *prefix, - counter_type *errors); -#endif +void ipv4_packet_size_verify(const uint8_t *data, + const int size, + const int tunnel_type, + const char + *prefix, + counter_type *errors); #endif + +#endif /* ifndef PROTO_H */ diff --git a/src/openvpn/proxy.c b/src/openvpn/proxy.c index 0f780202a0b..7a06038c2c7 100644 --- a/src/openvpn/proxy.c +++ b/src/openvpn/proxy.c @@ -46,16 +46,16 @@ #define UP_TYPE_PROXY "HTTP Proxy" struct http_proxy_options * -init_http_proxy_options_once (struct http_proxy_options **hpo, - struct gc_arena *gc) +init_http_proxy_options_once(struct http_proxy_options **hpo, + struct gc_arena *gc) { - if (!*hpo) + if (!*hpo) { - ALLOC_OBJ_CLEAR_GC (*hpo, struct http_proxy_options, gc); - /* http proxy defaults */ - (*hpo)->http_version = "1.0"; + ALLOC_OBJ_CLEAR_GC(*hpo, struct http_proxy_options, gc); + /* http proxy defaults */ + (*hpo)->http_version = "1.0"; } - return *hpo; + return *hpo; } @@ -63,214 +63,240 @@ init_http_proxy_options_once (struct http_proxy_options **hpo, static struct user_pass static_proxy_user_pass; static bool -recv_line (socket_descriptor_t sd, - char *buf, - int len, - const int timeout_sec, - const bool verbose, - struct buffer *lookahead, - volatile int *signal_received) +recv_line(socket_descriptor_t sd, + char *buf, + int len, + const int timeout_sec, + const bool verbose, + struct buffer *lookahead, + volatile int *signal_received) { - struct buffer la; - int lastc = 0; + struct buffer la; + int lastc = 0; - CLEAR (la); - if (lookahead) - la = *lookahead; + CLEAR(la); + if (lookahead) + { + la = *lookahead; + } - while (true) + while (true) { - int status; - ssize_t size; - fd_set reads; - struct timeval tv; - uint8_t c; - - if (buf_defined (&la)) - { - ASSERT (buf_init (&la, 0)); - } - - FD_ZERO (&reads); - openvpn_fd_set (sd, &reads); - tv.tv_sec = timeout_sec; - tv.tv_usec = 0; - - status = select (sd + 1, &reads, NULL, NULL, &tv); - - get_signal (signal_received); - if (*signal_received) - goto error; - - /* timeout? */ - if (status == 0) - { - if (verbose) - msg (D_LINK_ERRORS | M_ERRNO, "recv_line: TCP port read timeout expired"); - goto error; - } - - /* error */ - if (status < 0) - { - if (verbose) - msg (D_LINK_ERRORS | M_ERRNO, "recv_line: TCP port read failed on select()"); - goto error; - } - - /* read single char */ - size = recv (sd, &c, 1, MSG_NOSIGNAL); - - /* error? */ - if (size != 1) - { - if (verbose) - msg (D_LINK_ERRORS | M_ERRNO, "recv_line: TCP port read failed on recv()"); - goto error; - } + int status; + ssize_t size; + fd_set reads; + struct timeval tv; + uint8_t c; + + if (buf_defined(&la)) + { + ASSERT(buf_init(&la, 0)); + } + + FD_ZERO(&reads); + openvpn_fd_set(sd, &reads); + tv.tv_sec = timeout_sec; + tv.tv_usec = 0; + + status = select(sd + 1, &reads, NULL, NULL, &tv); + + get_signal(signal_received); + if (*signal_received) + { + goto error; + } + + /* timeout? */ + if (status == 0) + { + if (verbose) + { + msg(D_LINK_ERRORS | M_ERRNO, "recv_line: TCP port read timeout expired"); + } + goto error; + } + + /* error */ + if (status < 0) + { + if (verbose) + { + msg(D_LINK_ERRORS | M_ERRNO, "recv_line: TCP port read failed on select()"); + } + goto error; + } + + /* read single char */ + size = recv(sd, &c, 1, MSG_NOSIGNAL); + + /* error? */ + if (size != 1) + { + if (verbose) + { + msg(D_LINK_ERRORS | M_ERRNO, "recv_line: TCP port read failed on recv()"); + } + goto error; + } #if 0 - if (isprint(c)) - msg (M_INFO, "PROXY: read '%c' (%d)", c, (int)c); - else - msg (M_INFO, "PROXY: read (%d)", (int)c); + if (isprint(c)) + { + msg(M_INFO, "PROXY: read '%c' (%d)", c, (int)c); + } + else + { + msg(M_INFO, "PROXY: read (%d)", (int)c); + } #endif - /* store char in buffer */ - if (len > 1) - { - *buf++ = c; - --len; - } - - /* also store char in lookahead buffer */ - if (buf_defined (&la)) - { - buf_write_u8 (&la, c); - if (!isprint(c) && !isspace(c)) /* not ascii? */ - { - if (verbose) - msg (D_LINK_ERRORS | M_ERRNO, "recv_line: Non-ASCII character (%d) read on recv()", (int)c); - *lookahead = la; - return false; - } - } - - /* end of line? */ - if (lastc == '\r' && c == '\n') - break; - - lastc = c; + /* store char in buffer */ + if (len > 1) + { + *buf++ = c; + --len; + } + + /* also store char in lookahead buffer */ + if (buf_defined(&la)) + { + buf_write_u8(&la, c); + if (!isprint(c) && !isspace(c)) /* not ascii? */ + { + if (verbose) + { + msg(D_LINK_ERRORS | M_ERRNO, "recv_line: Non-ASCII character (%d) read on recv()", (int)c); + } + *lookahead = la; + return false; + } + } + + /* end of line? */ + if (lastc == '\r' && c == '\n') + { + break; + } + + lastc = c; } - /* append trailing null */ - if (len > 0) - *buf++ = '\0'; + /* append trailing null */ + if (len > 0) + { + *buf++ = '\0'; + } - return true; + return true; - error: - return false; +error: + return false; } static bool -send_line (socket_descriptor_t sd, - const char *buf) +send_line(socket_descriptor_t sd, + const char *buf) { - const ssize_t size = send (sd, buf, strlen (buf), MSG_NOSIGNAL); - if (size != (ssize_t) strlen (buf)) + const ssize_t size = send(sd, buf, strlen(buf), MSG_NOSIGNAL); + if (size != (ssize_t) strlen(buf)) { - msg (D_LINK_ERRORS | M_ERRNO, "send_line: TCP port write failed on send()"); - return false; + msg(D_LINK_ERRORS | M_ERRNO, "send_line: TCP port write failed on send()"); + return false; } - return true; + return true; } static bool -send_line_crlf (socket_descriptor_t sd, - const char *src) +send_line_crlf(socket_descriptor_t sd, + const char *src) { - bool ret; - - struct buffer buf = alloc_buf (strlen (src) + 3); - ASSERT (buf_write (&buf, src, strlen (src))); - ASSERT (buf_write (&buf, "\r\n", 3)); - ret = send_line (sd, BSTR (&buf)); - free_buf (&buf); - return ret; + bool ret; + + struct buffer buf = alloc_buf(strlen(src) + 3); + ASSERT(buf_write(&buf, src, strlen(src))); + ASSERT(buf_write(&buf, "\r\n", 3)); + ret = send_line(sd, BSTR(&buf)); + free_buf(&buf); + return ret; } static bool -send_crlf (socket_descriptor_t sd) +send_crlf(socket_descriptor_t sd) { - return send_line_crlf (sd, ""); + return send_line_crlf(sd, ""); } uint8_t * -make_base64_string2 (const uint8_t *str, int src_len, struct gc_arena *gc) +make_base64_string2(const uint8_t *str, int src_len, struct gc_arena *gc) { - uint8_t *ret = NULL; - char *b64out = NULL; - ASSERT (openvpn_base64_encode ((const void *)str, src_len, &b64out) >= 0); - ret = (uint8_t *) string_alloc (b64out, gc); - free (b64out); - return ret; + uint8_t *ret = NULL; + char *b64out = NULL; + ASSERT(openvpn_base64_encode((const void *)str, src_len, &b64out) >= 0); + ret = (uint8_t *) string_alloc(b64out, gc); + free(b64out); + return ret; } uint8_t * -make_base64_string (const uint8_t *str, struct gc_arena *gc) +make_base64_string(const uint8_t *str, struct gc_arena *gc) { - return make_base64_string2 (str, strlen ((const char *)str), gc); + return make_base64_string2(str, strlen((const char *)str), gc); } static const char * -username_password_as_base64 (const struct http_proxy_info *p, - struct gc_arena *gc) +username_password_as_base64(const struct http_proxy_info *p, + struct gc_arena *gc) { - struct buffer out = alloc_buf_gc (strlen (p->up.username) + strlen (p->up.password) + 2, gc); - ASSERT (strlen (p->up.username) > 0); - buf_printf (&out, "%s:%s", p->up.username, p->up.password); - return (const char *)make_base64_string ((const uint8_t*)BSTR (&out), gc); + struct buffer out = alloc_buf_gc(strlen(p->up.username) + strlen(p->up.password) + 2, gc); + ASSERT(strlen(p->up.username) > 0); + buf_printf(&out, "%s:%s", p->up.username, p->up.password); + return (const char *)make_base64_string((const uint8_t *)BSTR(&out), gc); } static void -get_user_pass_http (struct http_proxy_info *p, const bool force) +get_user_pass_http(struct http_proxy_info *p, const bool force) { - if (!static_proxy_user_pass.defined || force) + if (!static_proxy_user_pass.defined || force) { - unsigned int flags = GET_USER_PASS_MANAGEMENT; - if (p->queried_creds) - flags |= GET_USER_PASS_PREVIOUS_CREDS_FAILED; - if (p->options.inline_creds) - flags |= GET_USER_PASS_INLINE_CREDS; - get_user_pass (&static_proxy_user_pass, - p->options.auth_file, - UP_TYPE_PROXY, - flags); - p->queried_creds = true; - p->up = static_proxy_user_pass; + unsigned int flags = GET_USER_PASS_MANAGEMENT; + if (p->queried_creds) + { + flags |= GET_USER_PASS_PREVIOUS_CREDS_FAILED; + } + if (p->options.inline_creds) + { + flags |= GET_USER_PASS_INLINE_CREDS; + } + get_user_pass(&static_proxy_user_pass, + p->options.auth_file, + UP_TYPE_PROXY, + flags); + p->queried_creds = true; + p->up = static_proxy_user_pass; } } static void -clear_user_pass_http (void) +clear_user_pass_http(void) { - purge_user_pass (&static_proxy_user_pass, true); + purge_user_pass(&static_proxy_user_pass, true); } #if 0 /* function only used in #if 0 debug statement */ static void -dump_residual (socket_descriptor_t sd, - int timeout, - volatile int *signal_received) +dump_residual(socket_descriptor_t sd, + int timeout, + volatile int *signal_received) { - char buf[256]; - while (true) + char buf[256]; + while (true) { - if (!recv_line (sd, buf, sizeof (buf), timeout, true, NULL, signal_received)) - return; - chomp (buf); - msg (D_PROXY, "PROXY HEADER: '%s'", buf); + if (!recv_line(sd, buf, sizeof(buf), timeout, true, NULL, signal_received)) + { + return; + } + chomp(buf); + msg(D_PROXY, "PROXY HEADER: '%s'", buf); } } #endif @@ -280,58 +306,62 @@ dump_residual (socket_descriptor_t sd, * Consumes all headers. */ static int -get_proxy_authenticate (socket_descriptor_t sd, - int timeout, - char **data, - struct gc_arena *gc, - volatile int *signal_received) +get_proxy_authenticate(socket_descriptor_t sd, + int timeout, + char **data, + struct gc_arena *gc, + volatile int *signal_received) { - char buf[256]; - int ret = HTTP_AUTH_NONE; - while (true) + char buf[256]; + int ret = HTTP_AUTH_NONE; + while (true) { - if (!recv_line (sd, buf, sizeof (buf), timeout, true, NULL, signal_received)) - { - *data = NULL; - return HTTP_AUTH_NONE; - } - chomp (buf); - if (!strlen(buf)) - return ret; - if (ret == HTTP_AUTH_NONE && !strncmp(buf, "Proxy-Authenticate: ", 20)) - { - if (!strncmp(buf+20, "Basic ", 6)) - { - msg (D_PROXY, "PROXY AUTH BASIC: '%s'", buf); - *data = string_alloc(buf+26, gc); - ret = HTTP_AUTH_BASIC; - } + if (!recv_line(sd, buf, sizeof(buf), timeout, true, NULL, signal_received)) + { + *data = NULL; + return HTTP_AUTH_NONE; + } + chomp(buf); + if (!strlen(buf)) + { + return ret; + } + if (ret == HTTP_AUTH_NONE && !strncmp(buf, "Proxy-Authenticate: ", 20)) + { + if (!strncmp(buf+20, "Basic ", 6)) + { + msg(D_PROXY, "PROXY AUTH BASIC: '%s'", buf); + *data = string_alloc(buf+26, gc); + ret = HTTP_AUTH_BASIC; + } #if PROXY_DIGEST_AUTH - else if (!strncmp(buf+20, "Digest ", 7)) - { - msg (D_PROXY, "PROXY AUTH DIGEST: '%s'", buf); - *data = string_alloc(buf+27, gc); - ret = HTTP_AUTH_DIGEST; - } + else if (!strncmp(buf+20, "Digest ", 7)) + { + msg(D_PROXY, "PROXY AUTH DIGEST: '%s'", buf); + *data = string_alloc(buf+27, gc); + ret = HTTP_AUTH_DIGEST; + } #endif #if NTLM - else if (!strncmp(buf+20, "NTLM", 4)) - { - msg (D_PROXY, "PROXY AUTH HTLM: '%s'", buf); - *data = NULL; - ret = HTTP_AUTH_NTLM; - } + else if (!strncmp(buf+20, "NTLM", 4)) + { + msg(D_PROXY, "PROXY AUTH HTLM: '%s'", buf); + *data = NULL; + ret = HTTP_AUTH_NTLM; + } #endif - } + } } } static void -store_proxy_authenticate (struct http_proxy_info *p, char *data) +store_proxy_authenticate(struct http_proxy_info *p, char *data) { - if (p->proxy_authenticate) - free (p->proxy_authenticate); - p->proxy_authenticate = data; + if (p->proxy_authenticate) + { + free(p->proxy_authenticate); + } + p->proxy_authenticate = data; } /* @@ -340,611 +370,698 @@ store_proxy_authenticate (struct http_proxy_info *p, char *data) */ static bool get_key_value(const char *str, /* source string */ - char *key, /* key stored here */ - char *value, /* value stored here */ - int max_key_len, - int max_value_len, - const char **endptr) /* next search position */ + char *key, /* key stored here */ + char *value, /* value stored here */ + int max_key_len, + int max_value_len, + const char **endptr) /* next search position */ { - int c; - bool starts_with_quote = false; - bool escape = false; + int c; + bool starts_with_quote = false; + bool escape = false; - for (c = max_key_len-1; (*str && (*str != '=') && c--); ) - *key++ = *str++; - *key = '\0'; + for (c = max_key_len-1; (*str && (*str != '=') && c--); ) + *key++ = *str++; + *key = '\0'; - if('=' != *str++) - /* no key/value found */ - return false; + if ('=' != *str++) + { + /* no key/value found */ + return false; + } - if('\"' == *str) + if ('\"' == *str) { - /* quoted string */ - str++; - starts_with_quote = true; + /* quoted string */ + str++; + starts_with_quote = true; } - for (c = max_value_len-1; *str && c--; str++) + for (c = max_value_len-1; *str && c--; str++) { - switch (*str) - { - case '\\': - if (!escape) - { - /* possibly the start of an escaped quote */ - escape = true; - *value++ = '\\'; /* even though this is an escape character, we still - store it as-is in the target buffer */ - continue; - } - break; - case ',': - if (!starts_with_quote) - { - /* this signals the end of the value if we didn't get a starting quote - and then we do "sloppy" parsing */ - c=0; /* the end */ - continue; - } - break; - case '\r': - case '\n': - /* end of string */ - c=0; - continue; - case '\"': - if (!escape && starts_with_quote) - { - /* end of string */ - c=0; - continue; - } - break; - } - escape = false; - *value++ = *str; + switch (*str) + { + case '\\': + if (!escape) + { + /* possibly the start of an escaped quote */ + escape = true; + *value++ = '\\'; /* even though this is an escape character, we still + * store it as-is in the target buffer */ + continue; + } + break; + + case ',': + if (!starts_with_quote) + { + /* this signals the end of the value if we didn't get a starting quote + * and then we do "sloppy" parsing */ + c = 0; /* the end */ + continue; + } + break; + + case '\r': + case '\n': + /* end of string */ + c = 0; + continue; + + case '\"': + if (!escape && starts_with_quote) + { + /* end of string */ + c = 0; + continue; + } + break; + } + escape = false; + *value++ = *str; } - *value = '\0'; + *value = '\0'; - *endptr = str; + *endptr = str; - return true; /* success */ + return true; /* success */ } static char * -get_pa_var (const char *key, const char *pa, struct gc_arena *gc) +get_pa_var(const char *key, const char *pa, struct gc_arena *gc) { - char k[64]; - char v[256]; - const char *content = pa; + char k[64]; + char v[256]; + const char *content = pa; - while (true) + while (true) { - const int status = get_key_value(content, k, v, sizeof(k), sizeof(v), &content); - if (status) - { - if (!strcmp(key, k)) - return string_alloc(v, gc); - } - else - return NULL; - - /* advance to start of next key */ - if (*content == ',') - ++content; - while (*content && isspace(*content)) - ++content; + const int status = get_key_value(content, k, v, sizeof(k), sizeof(v), &content); + if (status) + { + if (!strcmp(key, k)) + { + return string_alloc(v, gc); + } + } + else + { + return NULL; + } + + /* advance to start of next key */ + if (*content == ',') + { + ++content; + } + while (*content && isspace(*content)) + ++content; } } struct http_proxy_info * -http_proxy_new (const struct http_proxy_options *o) +http_proxy_new(const struct http_proxy_options *o) { - struct http_proxy_info *p; + struct http_proxy_info *p; - if (!o || !o->server) - msg (M_FATAL, "HTTP_PROXY: server not specified"); + if (!o || !o->server) + { + msg(M_FATAL, "HTTP_PROXY: server not specified"); + } - ASSERT ( o->port); + ASSERT( o->port); - ALLOC_OBJ_CLEAR (p, struct http_proxy_info); - p->options = *o; + ALLOC_OBJ_CLEAR(p, struct http_proxy_info); + p->options = *o; - /* parse authentication method */ - p->auth_method = HTTP_AUTH_NONE; - if (o->auth_method_string) + /* parse authentication method */ + p->auth_method = HTTP_AUTH_NONE; + if (o->auth_method_string) { - if (!strcmp (o->auth_method_string, "none")) - p->auth_method = HTTP_AUTH_NONE; - else if (!strcmp (o->auth_method_string, "basic")) - p->auth_method = HTTP_AUTH_BASIC; + if (!strcmp(o->auth_method_string, "none")) + { + p->auth_method = HTTP_AUTH_NONE; + } + else if (!strcmp(o->auth_method_string, "basic")) + { + p->auth_method = HTTP_AUTH_BASIC; + } #if NTLM - else if (!strcmp (o->auth_method_string, "ntlm")) - p->auth_method = HTTP_AUTH_NTLM; - else if (!strcmp (o->auth_method_string, "ntlm2")) - p->auth_method = HTTP_AUTH_NTLM2; + else if (!strcmp(o->auth_method_string, "ntlm")) + { + p->auth_method = HTTP_AUTH_NTLM; + } + else if (!strcmp(o->auth_method_string, "ntlm2")) + { + p->auth_method = HTTP_AUTH_NTLM2; + } #endif - else - msg (M_FATAL, "ERROR: unknown HTTP authentication method: '%s'", - o->auth_method_string); + else + { + msg(M_FATAL, "ERROR: unknown HTTP authentication method: '%s'", + o->auth_method_string); + } } - /* only basic and NTLM/NTLMv2 authentication supported so far */ - if (p->auth_method == HTTP_AUTH_BASIC || p->auth_method == HTTP_AUTH_NTLM || p->auth_method == HTTP_AUTH_NTLM2) + /* only basic and NTLM/NTLMv2 authentication supported so far */ + if (p->auth_method == HTTP_AUTH_BASIC || p->auth_method == HTTP_AUTH_NTLM || p->auth_method == HTTP_AUTH_NTLM2) { - get_user_pass_http (p, true); + get_user_pass_http(p, true); } #if !NTLM - if (p->auth_method == HTTP_AUTH_NTLM || p->auth_method == HTTP_AUTH_NTLM2) - msg (M_FATAL, "Sorry, this version of " PACKAGE_NAME " was built without NTLM Proxy support."); + if (p->auth_method == HTTP_AUTH_NTLM || p->auth_method == HTTP_AUTH_NTLM2) + { + msg(M_FATAL, "Sorry, this version of " PACKAGE_NAME " was built without NTLM Proxy support."); + } #endif - p->defined = true; - return p; + p->defined = true; + return p; } void -http_proxy_close (struct http_proxy_info *hp) +http_proxy_close(struct http_proxy_info *hp) { - free (hp); + free(hp); } bool -add_proxy_headers (struct http_proxy_info *p, - socket_descriptor_t sd, /* already open to proxy */ - const char *host, /* openvpn server remote */ - const char* port /* openvpn server port */ - ) +add_proxy_headers(struct http_proxy_info *p, + socket_descriptor_t sd, /* already open to proxy */ + const char *host, /* openvpn server remote */ + const char *port /* openvpn server port */ + ) { - char buf[512]; - int i; - bool host_header_sent=false; - - /* - * Send custom headers if provided - * If content is NULL the whole header is in name - * Also remember if we already sent a Host: header - */ - for (i=0; i < MAX_CUSTOM_HTTP_HEADER && p->options.custom_headers[i].name;i++) + char buf[512]; + int i; + bool host_header_sent = false; + + /* + * Send custom headers if provided + * If content is NULL the whole header is in name + * Also remember if we already sent a Host: header + */ + for (i = 0; i < MAX_CUSTOM_HTTP_HEADER && p->options.custom_headers[i].name; i++) { - if (p->options.custom_headers[i].content) - { - openvpn_snprintf (buf, sizeof(buf), "%s: %s", - p->options.custom_headers[i].name, - p->options.custom_headers[i].content); - if (!strcasecmp(p->options.custom_headers[i].name, "Host")) - host_header_sent=true; - } - else - { - openvpn_snprintf (buf, sizeof(buf), "%s", - p->options.custom_headers[i].name); - if (!strncasecmp(p->options.custom_headers[i].name, "Host:", 5)) - host_header_sent=true; - } - - msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); - if (!send_line_crlf (sd, buf)) - return false; + if (p->options.custom_headers[i].content) + { + openvpn_snprintf(buf, sizeof(buf), "%s: %s", + p->options.custom_headers[i].name, + p->options.custom_headers[i].content); + if (!strcasecmp(p->options.custom_headers[i].name, "Host")) + { + host_header_sent = true; + } + } + else + { + openvpn_snprintf(buf, sizeof(buf), "%s", + p->options.custom_headers[i].name); + if (!strncasecmp(p->options.custom_headers[i].name, "Host:", 5)) + { + host_header_sent = true; + } + } + + msg(D_PROXY, "Send to HTTP proxy: '%s'", buf); + if (!send_line_crlf(sd, buf)) + { + return false; + } } - if (!host_header_sent) + if (!host_header_sent) { - openvpn_snprintf (buf, sizeof(buf), "Host: %s", host); - msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); - if (!send_line_crlf(sd, buf)) - return false; + openvpn_snprintf(buf, sizeof(buf), "Host: %s", host); + msg(D_PROXY, "Send to HTTP proxy: '%s'", buf); + if (!send_line_crlf(sd, buf)) + { + return false; + } } - /* send User-Agent string if provided */ - if (p->options.user_agent) + /* send User-Agent string if provided */ + if (p->options.user_agent) { - openvpn_snprintf (buf, sizeof(buf), "User-Agent: %s", - p->options.user_agent); - msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); - if (!send_line_crlf (sd, buf)) - return false; + openvpn_snprintf(buf, sizeof(buf), "User-Agent: %s", + p->options.user_agent); + msg(D_PROXY, "Send to HTTP proxy: '%s'", buf); + if (!send_line_crlf(sd, buf)) + { + return false; + } } - return true; + return true; } bool -establish_http_proxy_passthru (struct http_proxy_info *p, - socket_descriptor_t sd, /* already open to proxy */ - const char *host, /* openvpn server remote */ - const char *port, /* openvpn server port */ - struct event_timeout* server_poll_timeout, - struct buffer *lookahead, - volatile int *signal_received) +establish_http_proxy_passthru(struct http_proxy_info *p, + socket_descriptor_t sd, /* already open to proxy */ + const char *host, /* openvpn server remote */ + const char *port, /* openvpn server port */ + struct event_timeout *server_poll_timeout, + struct buffer *lookahead, + volatile int *signal_received) { - struct gc_arena gc = gc_new (); - char buf[512]; - char buf2[129]; - char get[80]; - int status; - int nparms; - bool ret = false; - bool processed = false; - - /* get user/pass if not previously given */ - if (p->auth_method == HTTP_AUTH_BASIC - || p->auth_method == HTTP_AUTH_DIGEST - || p->auth_method == HTTP_AUTH_NTLM) - get_user_pass_http (p, false); - - /* are we being called again after getting the digest server nonce in the previous transaction? */ - if (p->auth_method == HTTP_AUTH_DIGEST && p->proxy_authenticate) + struct gc_arena gc = gc_new(); + char buf[512]; + char buf2[129]; + char get[80]; + int status; + int nparms; + bool ret = false; + bool processed = false; + + /* get user/pass if not previously given */ + if (p->auth_method == HTTP_AUTH_BASIC + || p->auth_method == HTTP_AUTH_DIGEST + || p->auth_method == HTTP_AUTH_NTLM) + { + get_user_pass_http(p, false); + } + + /* are we being called again after getting the digest server nonce in the previous transaction? */ + if (p->auth_method == HTTP_AUTH_DIGEST && p->proxy_authenticate) { - nparms = 1; - status = 407; + nparms = 1; + status = 407; } - else + else { - /* format HTTP CONNECT message */ - openvpn_snprintf (buf, sizeof(buf), "CONNECT %s:%s HTTP/%s", - host, - port, - p->options.http_version); - - msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); - - /* send HTTP CONNECT message to proxy */ - if (!send_line_crlf (sd, buf)) - goto error; - - if (!add_proxy_headers (p, sd, host, port)) - goto error; - - /* auth specified? */ - switch (p->auth_method) - { - case HTTP_AUTH_NONE: - break; - - case HTTP_AUTH_BASIC: - openvpn_snprintf (buf, sizeof(buf), "Proxy-Authorization: Basic %s", - username_password_as_base64 (p, &gc)); - msg (D_PROXY, "Attempting Basic Proxy-Authorization"); - dmsg (D_SHOW_KEYS, "Send to HTTP proxy: '%s'", buf); - if (!send_line_crlf (sd, buf)) - goto error; - break; + /* format HTTP CONNECT message */ + openvpn_snprintf(buf, sizeof(buf), "CONNECT %s:%s HTTP/%s", + host, + port, + p->options.http_version); + + msg(D_PROXY, "Send to HTTP proxy: '%s'", buf); + + /* send HTTP CONNECT message to proxy */ + if (!send_line_crlf(sd, buf)) + { + goto error; + } + + if (!add_proxy_headers(p, sd, host, port)) + { + goto error; + } + + /* auth specified? */ + switch (p->auth_method) + { + case HTTP_AUTH_NONE: + break; + + case HTTP_AUTH_BASIC: + openvpn_snprintf(buf, sizeof(buf), "Proxy-Authorization: Basic %s", + username_password_as_base64(p, &gc)); + msg(D_PROXY, "Attempting Basic Proxy-Authorization"); + dmsg(D_SHOW_KEYS, "Send to HTTP proxy: '%s'", buf); + if (!send_line_crlf(sd, buf)) + { + goto error; + } + break; #if NTLM - case HTTP_AUTH_NTLM: - case HTTP_AUTH_NTLM2: - /* keep-alive connection */ - openvpn_snprintf (buf, sizeof(buf), "Proxy-Connection: Keep-Alive"); - if (!send_line_crlf (sd, buf)) - goto error; - - openvpn_snprintf (buf, sizeof(buf), "Proxy-Authorization: NTLM %s", - ntlm_phase_1 (p, &gc)); - msg (D_PROXY, "Attempting NTLM Proxy-Authorization phase 1"); - dmsg (D_SHOW_KEYS, "Send to HTTP proxy: '%s'", buf); - if (!send_line_crlf (sd, buf)) - goto error; - break; + case HTTP_AUTH_NTLM: + case HTTP_AUTH_NTLM2: + /* keep-alive connection */ + openvpn_snprintf(buf, sizeof(buf), "Proxy-Connection: Keep-Alive"); + if (!send_line_crlf(sd, buf)) + { + goto error; + } + + openvpn_snprintf(buf, sizeof(buf), "Proxy-Authorization: NTLM %s", + ntlm_phase_1(p, &gc)); + msg(D_PROXY, "Attempting NTLM Proxy-Authorization phase 1"); + dmsg(D_SHOW_KEYS, "Send to HTTP proxy: '%s'", buf); + if (!send_line_crlf(sd, buf)) + { + goto error; + } + break; #endif - default: - ASSERT (0); - } + default: + ASSERT(0); + } - /* send empty CR, LF */ - if (!send_crlf (sd)) - goto error; + /* send empty CR, LF */ + if (!send_crlf(sd)) + { + goto error; + } - /* receive reply from proxy */ - if (!recv_line (sd, buf, sizeof(buf), get_server_poll_remaining_time (server_poll_timeout), true, NULL, signal_received)) - goto error; + /* receive reply from proxy */ + if (!recv_line(sd, buf, sizeof(buf), get_server_poll_remaining_time(server_poll_timeout), true, NULL, signal_received)) + { + goto error; + } - /* remove trailing CR, LF */ - chomp (buf); + /* remove trailing CR, LF */ + chomp(buf); - msg (D_PROXY, "HTTP proxy returned: '%s'", buf); + msg(D_PROXY, "HTTP proxy returned: '%s'", buf); - /* parse return string */ - nparms = sscanf (buf, "%*s %d", &status); + /* parse return string */ + nparms = sscanf(buf, "%*s %d", &status); } - /* check for a "407 Proxy Authentication Required" response */ - while (nparms >= 1 && status == 407) + /* check for a "407 Proxy Authentication Required" response */ + while (nparms >= 1 && status == 407) { - msg (D_PROXY, "Proxy requires authentication"); + msg(D_PROXY, "Proxy requires authentication"); - if (p->auth_method == HTTP_AUTH_BASIC && !processed) - { - processed = true; - } - else if ((p->auth_method == HTTP_AUTH_NTLM || p->auth_method == HTTP_AUTH_NTLM2) && !processed) /* check for NTLM */ + if (p->auth_method == HTTP_AUTH_BASIC && !processed) + { + processed = true; + } + else if ((p->auth_method == HTTP_AUTH_NTLM || p->auth_method == HTTP_AUTH_NTLM2) && !processed) /* check for NTLM */ { #if NTLM - /* look for the phase 2 response */ + /* look for the phase 2 response */ - while (true) + while (true) { - if (!recv_line (sd, buf, sizeof(buf), get_server_poll_remaining_time (server_poll_timeout), true, NULL, signal_received)) - goto error; - chomp (buf); - msg (D_PROXY, "HTTP proxy returned: '%s'", buf); + if (!recv_line(sd, buf, sizeof(buf), get_server_poll_remaining_time(server_poll_timeout), true, NULL, signal_received)) + { + goto error; + } + chomp(buf); + msg(D_PROXY, "HTTP proxy returned: '%s'", buf); - openvpn_snprintf (get, sizeof get, "%%*s NTLM %%%ds", (int) sizeof (buf2) - 1); - nparms = sscanf (buf, get, buf2); - buf2[128] = 0; /* we only need the beginning - ensure it's null terminated. */ + openvpn_snprintf(get, sizeof get, "%%*s NTLM %%%ds", (int) sizeof(buf2) - 1); + nparms = sscanf(buf, get, buf2); + buf2[128] = 0; /* we only need the beginning - ensure it's null terminated. */ - /* check for "Proxy-Authenticate: NTLM TlRM..." */ - if (nparms == 1) + /* check for "Proxy-Authenticate: NTLM TlRM..." */ + if (nparms == 1) { - /* parse buf2 */ - msg (D_PROXY, "auth string: '%s'", buf2); - break; + /* parse buf2 */ + msg(D_PROXY, "auth string: '%s'", buf2); + break; } } - /* if we are here then auth string was got */ - msg (D_PROXY, "Received NTLM Proxy-Authorization phase 2 response"); + /* if we are here then auth string was got */ + msg(D_PROXY, "Received NTLM Proxy-Authorization phase 2 response"); - /* receive and discard everything else */ - while (recv_line (sd, NULL, 0, 2, true, NULL, signal_received)) - ; + /* receive and discard everything else */ + while (recv_line(sd, NULL, 0, 2, true, NULL, signal_received)) + ; - /* now send the phase 3 reply */ + /* now send the phase 3 reply */ - /* format HTTP CONNECT message */ - openvpn_snprintf (buf, sizeof(buf), "CONNECT %s:%s HTTP/%s", - host, - port, - p->options.http_version); + /* format HTTP CONNECT message */ + openvpn_snprintf(buf, sizeof(buf), "CONNECT %s:%s HTTP/%s", + host, + port, + p->options.http_version); - msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); + msg(D_PROXY, "Send to HTTP proxy: '%s'", buf); - /* send HTTP CONNECT message to proxy */ - if (!send_line_crlf (sd, buf)) - goto error; + /* send HTTP CONNECT message to proxy */ + if (!send_line_crlf(sd, buf)) + { + goto error; + } - /* keep-alive connection */ - openvpn_snprintf (buf, sizeof(buf), "Proxy-Connection: Keep-Alive"); - if (!send_line_crlf (sd, buf)) - goto error; + /* keep-alive connection */ + openvpn_snprintf(buf, sizeof(buf), "Proxy-Connection: Keep-Alive"); + if (!send_line_crlf(sd, buf)) + { + goto error; + } - /* send HOST etc, */ - if (!add_proxy_headers (p, sd, host, port)) - goto error; - - msg (D_PROXY, "Attempting NTLM Proxy-Authorization phase 3"); - { - const char *np3 = ntlm_phase_3 (p, buf2, &gc); - if (!np3) - { - msg (D_PROXY, "NTLM Proxy-Authorization phase 3 failed: received corrupted data from proxy server"); - goto error; - } - openvpn_snprintf (buf, sizeof(buf), "Proxy-Authorization: NTLM %s", np3); - } - - msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); - if (!send_line_crlf (sd, buf)) - goto error; - /* ok so far... */ - /* send empty CR, LF */ - if (!send_crlf (sd)) - goto error; + /* send HOST etc, */ + if (!add_proxy_headers(p, sd, host, port)) + { + goto error; + } - /* receive reply from proxy */ - if (!recv_line (sd, buf, sizeof(buf), get_server_poll_remaining_time (server_poll_timeout), true, NULL, signal_received)) - goto error; + msg(D_PROXY, "Attempting NTLM Proxy-Authorization phase 3"); + { + const char *np3 = ntlm_phase_3(p, buf2, &gc); + if (!np3) + { + msg(D_PROXY, "NTLM Proxy-Authorization phase 3 failed: received corrupted data from proxy server"); + goto error; + } + openvpn_snprintf(buf, sizeof(buf), "Proxy-Authorization: NTLM %s", np3); + } + + msg(D_PROXY, "Send to HTTP proxy: '%s'", buf); + if (!send_line_crlf(sd, buf)) + { + goto error; + } + /* ok so far... */ + /* send empty CR, LF */ + if (!send_crlf(sd)) + { + goto error; + } - /* remove trailing CR, LF */ - chomp (buf); + /* receive reply from proxy */ + if (!recv_line(sd, buf, sizeof(buf), get_server_poll_remaining_time(server_poll_timeout), true, NULL, signal_received)) + { + goto error; + } - msg (D_PROXY, "HTTP proxy returned: '%s'", buf); + /* remove trailing CR, LF */ + chomp(buf); - /* parse return string */ - nparms = sscanf (buf, "%*s %d", &status); - processed = true; -#endif - } + msg(D_PROXY, "HTTP proxy returned: '%s'", buf); + + /* parse return string */ + nparms = sscanf(buf, "%*s %d", &status); + processed = true; +#endif /* if NTLM */ + } #if PROXY_DIGEST_AUTH - else if (p->auth_method == HTTP_AUTH_DIGEST && !processed) - { - char *pa = p->proxy_authenticate; - const int method = p->auth_method; - ASSERT(pa); - - if (method == HTTP_AUTH_DIGEST) - { - const char *http_method = "CONNECT"; - const char *nonce_count = "00000001"; - const char *qop = "auth"; - const char *username = p->up.username; - const char *password = p->up.password; - char *opaque_kv = ""; - char uri[128]; - uint8_t cnonce_raw[8]; - uint8_t *cnonce; - HASHHEX session_key; - HASHHEX response; - - const char *realm = get_pa_var("realm", pa, &gc); - const char *nonce = get_pa_var("nonce", pa, &gc); - const char *algor = get_pa_var("algorithm", pa, &gc); - const char *opaque = get_pa_var("opaque", pa, &gc); - - /* generate a client nonce */ - ASSERT(rand_bytes(cnonce_raw, sizeof(cnonce_raw))); - cnonce = make_base64_string2(cnonce_raw, sizeof(cnonce_raw), &gc); - - - /* build the digest response */ - openvpn_snprintf (uri, sizeof(uri), "%s:%s", - host, - port); - - if (opaque) - { - const int len = strlen(opaque)+16; - opaque_kv = gc_malloc(len, false, &gc); - openvpn_snprintf (opaque_kv, len, ", opaque=\"%s\"", opaque); - } - - DigestCalcHA1(algor, - username, - realm, - password, - nonce, - (char *)cnonce, - session_key); - DigestCalcResponse(session_key, - nonce, - nonce_count, - (char *)cnonce, - qop, - http_method, - uri, - NULL, - response); - - /* format HTTP CONNECT message */ - openvpn_snprintf (buf, sizeof(buf), "%s %s HTTP/%s", - http_method, - uri, - p->options.http_version); - - msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); - - /* send HTTP CONNECT message to proxy */ - if (!send_line_crlf (sd, buf)) - goto error; - - /* send HOST etc, */ - if (!add_proxy_headers (p, sd, host, port)) - goto error; - - /* send digest response */ - openvpn_snprintf (buf, sizeof(buf), "Proxy-Authorization: Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", qop=%s, nc=%s, cnonce=\"%s\", response=\"%s\"%s", - username, - realm, - nonce, - uri, - qop, - nonce_count, - cnonce, - response, - opaque_kv - ); - msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); - if (!send_line_crlf (sd, buf)) - goto error; - if (!send_crlf (sd)) - goto error; - - /* receive reply from proxy */ - if (!recv_line (sd, buf, sizeof(buf), get_server_poll_remaining_time (server_poll_timeout), true, NULL, signal_received)) - goto error; - - /* remove trailing CR, LF */ - chomp (buf); - - msg (D_PROXY, "HTTP proxy returned: '%s'", buf); - - /* parse return string */ - nparms = sscanf (buf, "%*s %d", &status); - processed = true; - } - else - { - msg (D_PROXY, "HTTP proxy: digest method not supported"); - goto error; - } - } -#endif - else if (p->options.auth_retry) - { - /* figure out what kind of authentication the proxy needs */ - char *pa = NULL; - const int method = get_proxy_authenticate(sd, - get_server_poll_remaining_time (server_poll_timeout), - &pa, - NULL, - signal_received); - if (method != HTTP_AUTH_NONE) - { - if (pa) - msg (D_PROXY, "HTTP proxy authenticate '%s'", pa); - if (p->options.auth_retry == PAR_NCT && method == HTTP_AUTH_BASIC) - { - msg (D_PROXY, "HTTP proxy: support for basic auth and other cleartext proxy auth methods is disabled"); - goto error; - } - p->auth_method = method; - store_proxy_authenticate(p, pa); - ret = true; - goto done; - } - else - { - msg (D_PROXY, "HTTP proxy: do not recognize the authentication method required by proxy"); - free (pa); - goto error; - } - } - else - { - if (!processed) - msg (D_PROXY, "HTTP proxy: no support for proxy authentication method"); - goto error; - } - - /* clear state */ - if (p->options.auth_retry) - clear_user_pass_http(); - store_proxy_authenticate(p, NULL); + else if (p->auth_method == HTTP_AUTH_DIGEST && !processed) + { + char *pa = p->proxy_authenticate; + const int method = p->auth_method; + ASSERT(pa); + + if (method == HTTP_AUTH_DIGEST) + { + const char *http_method = "CONNECT"; + const char *nonce_count = "00000001"; + const char *qop = "auth"; + const char *username = p->up.username; + const char *password = p->up.password; + char *opaque_kv = ""; + char uri[128]; + uint8_t cnonce_raw[8]; + uint8_t *cnonce; + HASHHEX session_key; + HASHHEX response; + + const char *realm = get_pa_var("realm", pa, &gc); + const char *nonce = get_pa_var("nonce", pa, &gc); + const char *algor = get_pa_var("algorithm", pa, &gc); + const char *opaque = get_pa_var("opaque", pa, &gc); + + /* generate a client nonce */ + ASSERT(rand_bytes(cnonce_raw, sizeof(cnonce_raw))); + cnonce = make_base64_string2(cnonce_raw, sizeof(cnonce_raw), &gc); + + + /* build the digest response */ + openvpn_snprintf(uri, sizeof(uri), "%s:%s", + host, + port); + + if (opaque) + { + const int len = strlen(opaque)+16; + opaque_kv = gc_malloc(len, false, &gc); + openvpn_snprintf(opaque_kv, len, ", opaque=\"%s\"", opaque); + } + + DigestCalcHA1(algor, + username, + realm, + password, + nonce, + (char *)cnonce, + session_key); + DigestCalcResponse(session_key, + nonce, + nonce_count, + (char *)cnonce, + qop, + http_method, + uri, + NULL, + response); + + /* format HTTP CONNECT message */ + openvpn_snprintf(buf, sizeof(buf), "%s %s HTTP/%s", + http_method, + uri, + p->options.http_version); + + msg(D_PROXY, "Send to HTTP proxy: '%s'", buf); + + /* send HTTP CONNECT message to proxy */ + if (!send_line_crlf(sd, buf)) + { + goto error; + } + + /* send HOST etc, */ + if (!add_proxy_headers(p, sd, host, port)) + { + goto error; + } + + /* send digest response */ + openvpn_snprintf(buf, sizeof(buf), "Proxy-Authorization: Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", qop=%s, nc=%s, cnonce=\"%s\", response=\"%s\"%s", + username, + realm, + nonce, + uri, + qop, + nonce_count, + cnonce, + response, + opaque_kv + ); + msg(D_PROXY, "Send to HTTP proxy: '%s'", buf); + if (!send_line_crlf(sd, buf)) + { + goto error; + } + if (!send_crlf(sd)) + { + goto error; + } + + /* receive reply from proxy */ + if (!recv_line(sd, buf, sizeof(buf), get_server_poll_remaining_time(server_poll_timeout), true, NULL, signal_received)) + { + goto error; + } + + /* remove trailing CR, LF */ + chomp(buf); + + msg(D_PROXY, "HTTP proxy returned: '%s'", buf); + + /* parse return string */ + nparms = sscanf(buf, "%*s %d", &status); + processed = true; + } + else + { + msg(D_PROXY, "HTTP proxy: digest method not supported"); + goto error; + } + } +#endif /* if PROXY_DIGEST_AUTH */ + else if (p->options.auth_retry) + { + /* figure out what kind of authentication the proxy needs */ + char *pa = NULL; + const int method = get_proxy_authenticate(sd, + get_server_poll_remaining_time(server_poll_timeout), + &pa, + NULL, + signal_received); + if (method != HTTP_AUTH_NONE) + { + if (pa) + { + msg(D_PROXY, "HTTP proxy authenticate '%s'", pa); + } + if (p->options.auth_retry == PAR_NCT && method == HTTP_AUTH_BASIC) + { + msg(D_PROXY, "HTTP proxy: support for basic auth and other cleartext proxy auth methods is disabled"); + goto error; + } + p->auth_method = method; + store_proxy_authenticate(p, pa); + ret = true; + goto done; + } + else + { + msg(D_PROXY, "HTTP proxy: do not recognize the authentication method required by proxy"); + free(pa); + goto error; + } + } + else + { + if (!processed) + { + msg(D_PROXY, "HTTP proxy: no support for proxy authentication method"); + } + goto error; + } + + /* clear state */ + if (p->options.auth_retry) + { + clear_user_pass_http(); + } + store_proxy_authenticate(p, NULL); } - /* check return code, success = 200 */ - if (nparms < 1 || status != 200) + /* check return code, success = 200 */ + if (nparms < 1 || status != 200) { - msg (D_LINK_ERRORS, "HTTP proxy returned bad status"); + msg(D_LINK_ERRORS, "HTTP proxy returned bad status"); #if 0 - /* DEBUGGING -- show a multi-line HTTP error response */ - dump_residual(sd, get_server_poll_remaining_time (server_poll_timeout), signal_received); + /* DEBUGGING -- show a multi-line HTTP error response */ + dump_residual(sd, get_server_poll_remaining_time(server_poll_timeout), signal_received); #endif - goto error; + goto error; } - /* SUCCESS */ + /* SUCCESS */ - /* receive line from proxy and discard */ - if (!recv_line (sd, NULL, 0, get_server_poll_remaining_time (server_poll_timeout), true, NULL, signal_received)) - goto error; + /* receive line from proxy and discard */ + if (!recv_line(sd, NULL, 0, get_server_poll_remaining_time(server_poll_timeout), true, NULL, signal_received)) + { + goto error; + } - /* - * Toss out any extraneous chars, but don't throw away the - * start of the OpenVPN data stream (put it in lookahead). - */ - while (recv_line (sd, NULL, 0, 2, false, lookahead, signal_received)) - ; + /* + * Toss out any extraneous chars, but don't throw away the + * start of the OpenVPN data stream (put it in lookahead). + */ + while (recv_line(sd, NULL, 0, 2, false, lookahead, signal_received)) + ; - /* reset queried_creds so that we don't think that the next creds request is due to an auth error */ - p->queried_creds = false; + /* reset queried_creds so that we don't think that the next creds request is due to an auth error */ + p->queried_creds = false; #if 0 - if (lookahead && BLEN (lookahead)) - msg (M_INFO, "HTTP PROXY: lookahead: %s", format_hex (BPTR (lookahead), BLEN (lookahead), 0)); + if (lookahead && BLEN(lookahead)) + { + msg(M_INFO, "HTTP PROXY: lookahead: %s", format_hex(BPTR(lookahead), BLEN(lookahead), 0)); + } #endif - done: - gc_free (&gc); - return ret; +done: + gc_free(&gc); + return ret; - error: - if (!*signal_received) - *signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- HTTP proxy error */ - gc_free (&gc); - return ret; +error: + if (!*signal_received) + { + *signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- HTTP proxy error */ + } + gc_free(&gc); + return ret; } diff --git a/src/openvpn/proxy.h b/src/openvpn/proxy.h index 7d2581ce327..892277bca2b 100644 --- a/src/openvpn/proxy.h +++ b/src/openvpn/proxy.h @@ -37,59 +37,60 @@ #define HTTP_AUTH_N 5 /* number of HTTP_AUTH methods */ struct http_custom_header { - const char *name; - const char *content; + const char *name; + const char *content; }; #define MAX_CUSTOM_HTTP_HEADER 10 struct http_proxy_options { - const char *server; - const char *port; - -# define PAR_NO 0 /* don't support any auth retries */ -# define PAR_ALL 1 /* allow all proxy auth protocols */ -# define PAR_NCT 2 /* disable cleartext proxy auth protocols */ - int auth_retry; - - const char *auth_method_string; - const char *auth_file; - const char *http_version; - const char *user_agent; - struct http_custom_header custom_headers[MAX_CUSTOM_HTTP_HEADER]; - bool inline_creds; + const char *server; + const char *port; + +#define PAR_NO 0 /* don't support any auth retries */ +#define PAR_ALL 1 /* allow all proxy auth protocols */ +#define PAR_NCT 2 /* disable cleartext proxy auth protocols */ + int auth_retry; + + const char *auth_method_string; + const char *auth_file; + const char *http_version; + const char *user_agent; + struct http_custom_header custom_headers[MAX_CUSTOM_HTTP_HEADER]; + bool inline_creds; }; struct http_proxy_options_simple { - const char *server; - const char *port; - int auth_retry; + const char *server; + const char *port; + int auth_retry; }; struct http_proxy_info { - bool defined; - int auth_method; - struct http_proxy_options options; - struct user_pass up; - char *proxy_authenticate; - bool queried_creds; + bool defined; + int auth_method; + struct http_proxy_options options; + struct user_pass up; + char *proxy_authenticate; + bool queried_creds; }; -struct http_proxy_options *init_http_proxy_options_once (struct http_proxy_options **hpo, - struct gc_arena *gc); +struct http_proxy_options *init_http_proxy_options_once(struct http_proxy_options **hpo, + struct gc_arena *gc); + +struct http_proxy_info *http_proxy_new(const struct http_proxy_options *o); -struct http_proxy_info *http_proxy_new (const struct http_proxy_options *o); +void http_proxy_close(struct http_proxy_info *hp); -void http_proxy_close (struct http_proxy_info *hp); +bool establish_http_proxy_passthru(struct http_proxy_info *p, + socket_descriptor_t sd, /* already open to proxy */ + const char *host, /* openvpn server remote */ + const char *port, /* openvpn server port */ + struct event_timeout *server_poll_timeout, + struct buffer *lookahead, + volatile int *signal_received); -bool establish_http_proxy_passthru (struct http_proxy_info *p, - socket_descriptor_t sd, /* already open to proxy */ - const char *host, /* openvpn server remote */ - const char *port, /* openvpn server port */ - struct event_timeout* server_poll_timeout, - struct buffer *lookahead, - volatile int *signal_received); +uint8_t *make_base64_string2(const uint8_t *str, int str_len, struct gc_arena *gc); -uint8_t *make_base64_string2 (const uint8_t *str, int str_len, struct gc_arena *gc); -uint8_t *make_base64_string (const uint8_t *str, struct gc_arena *gc); +uint8_t *make_base64_string(const uint8_t *str, struct gc_arena *gc); #endif /* PROXY_H */ diff --git a/src/openvpn/ps.c b/src/openvpn/ps.c index 2cb68f170a5..bca670c74e1 100644 --- a/src/openvpn/ps.c +++ b/src/openvpn/ps.c @@ -68,32 +68,34 @@ struct port_share *port_share = NULL; /* GLOBAL */ * usually HTTPS */ struct proxy_connection { - bool defined; - struct proxy_connection *next; - struct proxy_connection *counterpart; - struct buffer buf; - bool buffer_initial; - int rwflags; - int sd; - char *jfn; + bool defined; + struct proxy_connection *next; + struct proxy_connection *counterpart; + struct buffer buf; + bool buffer_initial; + int rwflags; + int sd; + char *jfn; }; #if 0 static const char * -headc (const struct buffer *buf) +headc(const struct buffer *buf) { - static char foo[16]; - strncpy (foo, BSTR(buf), 15); - foo[15] = 0; - return foo; + static char foo[16]; + strncpy(foo, BSTR(buf), 15); + foo[15] = 0; + return foo; } #endif static inline void -close_socket_if_defined (const socket_descriptor_t sd) +close_socket_if_defined(const socket_descriptor_t sd) { - if (socket_defined (sd)) - openvpn_close_socket (sd); + if (socket_defined(sd)) + { + openvpn_close_socket(sd); + } } /* @@ -107,14 +109,16 @@ close_socket_if_defined (const socket_descriptor_t sd) * fds from crossing a fork(). */ static void -close_fds_except (int keep) +close_fds_except(int keep) { - socket_descriptor_t i; - closelog (); - for (i = 3; i <= 100; ++i) + socket_descriptor_t i; + closelog(); + for (i = 3; i <= 100; ++i) { - if (i != keep) - openvpn_close_socket (i); + if (i != keep) + { + openvpn_close_socket(i); + } } } @@ -123,15 +127,15 @@ close_fds_except (int keep) * deal with them. */ static void -set_signals (void) +set_signals(void) { - signal (SIGTERM, SIG_DFL); + signal(SIGTERM, SIG_DFL); - signal (SIGINT, SIG_IGN); - signal (SIGHUP, SIG_IGN); - signal (SIGUSR1, SIG_IGN); - signal (SIGUSR2, SIG_IGN); - signal (SIGPIPE, SIG_IGN); + signal(SIGINT, SIG_IGN); + signal(SIGHUP, SIG_IGN); + signal(SIGUSR1, SIG_IGN); + signal(SIGUSR2, SIG_IGN); + signal(SIGPIPE, SIG_IGN); } /* @@ -139,33 +143,39 @@ set_signals (void) */ static int -recv_control (const socket_descriptor_t fd) +recv_control(const socket_descriptor_t fd) { - unsigned char c; - const ssize_t size = read (fd, &c, sizeof (c)); - if (size == sizeof (c)) - return c; - else + unsigned char c; + const ssize_t size = read(fd, &c, sizeof(c)); + if (size == sizeof(c)) + { + return c; + } + else { - return -1; + return -1; } } static int -send_control (const socket_descriptor_t fd, int code) +send_control(const socket_descriptor_t fd, int code) { - unsigned char c = (unsigned char) code; - const ssize_t size = write (fd, &c, sizeof (c)); - if (size == sizeof (c)) - return (int) size; - else - return -1; + unsigned char c = (unsigned char) code; + const ssize_t size = write(fd, &c, sizeof(c)); + if (size == sizeof(c)) + { + return (int) size; + } + else + { + return -1; + } } static int -cmsg_size () +cmsg_size() { - return CMSG_SPACE(sizeof(socket_descriptor_t)); + return CMSG_SPACE(sizeof(socket_descriptor_t)); } /* @@ -176,83 +186,87 @@ cmsg_size () * send commands, data, and file descriptors to the background process. */ static void -port_share_sendmsg (const socket_descriptor_t sd, - const char command, - const struct buffer *head, - const socket_descriptor_t sd_send) +port_share_sendmsg(const socket_descriptor_t sd, + const char command, + const struct buffer *head, + const socket_descriptor_t sd_send) { - if (socket_defined (sd)) - { - struct msghdr mesg; - struct cmsghdr* h; - struct iovec iov[2]; - socket_descriptor_t sd_null[2] = { SOCKET_UNDEFINED, SOCKET_UNDEFINED }; - char cmd; - ssize_t status; - - dmsg (D_PS_PROXY_DEBUG, "PORT SHARE: sendmsg sd=%d len=%d", - (int)sd_send, - head ? BLEN(head) : -1); - - CLEAR (mesg); - - cmd = command; - - iov[0].iov_base = &cmd; - iov[0].iov_len = sizeof (cmd); - mesg.msg_iovlen = 1; - - if (head) - { - iov[1].iov_base = BPTR (head); - iov[1].iov_len = BLEN (head); - mesg.msg_iovlen = 2; - } - - mesg.msg_iov = iov; - - mesg.msg_controllen = cmsg_size (); - mesg.msg_control = (char *) malloc (mesg.msg_controllen); - check_malloc_return (mesg.msg_control); - mesg.msg_flags = 0; - - h = CMSG_FIRSTHDR(&mesg); - h->cmsg_level = SOL_SOCKET; - h->cmsg_type = SCM_RIGHTS; - h->cmsg_len = CMSG_LEN(sizeof(socket_descriptor_t)); - - if (socket_defined (sd_send)) - { - memcpy (CMSG_DATA(h), &sd_send, sizeof (sd_send)); - } - else - { - socketpair (PF_UNIX, SOCK_DGRAM, 0, sd_null); - memcpy (CMSG_DATA(h), &sd_null[0], sizeof (sd_null[0])); - } - - status = sendmsg (sd, &mesg, MSG_NOSIGNAL); - if (status == -1) - msg (M_WARN|M_ERRNO, "PORT SHARE: sendmsg failed -- unable to communicate with background process (%d,%d,%d,%d)", - sd, sd_send, sd_null[0], sd_null[1] - ); - - close_socket_if_defined (sd_null[0]); - close_socket_if_defined (sd_null[1]); - free (mesg.msg_control); + if (socket_defined(sd)) + { + struct msghdr mesg; + struct cmsghdr *h; + struct iovec iov[2]; + socket_descriptor_t sd_null[2] = { SOCKET_UNDEFINED, SOCKET_UNDEFINED }; + char cmd; + ssize_t status; + + dmsg(D_PS_PROXY_DEBUG, "PORT SHARE: sendmsg sd=%d len=%d", + (int)sd_send, + head ? BLEN(head) : -1); + + CLEAR(mesg); + + cmd = command; + + iov[0].iov_base = &cmd; + iov[0].iov_len = sizeof(cmd); + mesg.msg_iovlen = 1; + + if (head) + { + iov[1].iov_base = BPTR(head); + iov[1].iov_len = BLEN(head); + mesg.msg_iovlen = 2; + } + + mesg.msg_iov = iov; + + mesg.msg_controllen = cmsg_size(); + mesg.msg_control = (char *) malloc(mesg.msg_controllen); + check_malloc_return(mesg.msg_control); + mesg.msg_flags = 0; + + h = CMSG_FIRSTHDR(&mesg); + h->cmsg_level = SOL_SOCKET; + h->cmsg_type = SCM_RIGHTS; + h->cmsg_len = CMSG_LEN(sizeof(socket_descriptor_t)); + + if (socket_defined(sd_send)) + { + memcpy(CMSG_DATA(h), &sd_send, sizeof(sd_send)); + } + else + { + socketpair(PF_UNIX, SOCK_DGRAM, 0, sd_null); + memcpy(CMSG_DATA(h), &sd_null[0], sizeof(sd_null[0])); + } + + status = sendmsg(sd, &mesg, MSG_NOSIGNAL); + if (status == -1) + { + msg(M_WARN|M_ERRNO, "PORT SHARE: sendmsg failed -- unable to communicate with background process (%d,%d,%d,%d)", + sd, sd_send, sd_null[0], sd_null[1] + ); + } + + close_socket_if_defined(sd_null[0]); + close_socket_if_defined(sd_null[1]); + free(mesg.msg_control); } } static void -proxy_entry_close_sd (struct proxy_connection *pc, struct event_set *es) +proxy_entry_close_sd(struct proxy_connection *pc, struct event_set *es) { - if (pc->defined && socket_defined (pc->sd)) + if (pc->defined && socket_defined(pc->sd)) { - dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: delete sd=%d", (int)pc->sd); - if (es) - event_del (es, pc->sd); - openvpn_close_socket (pc->sd); - pc->sd = SOCKET_UNDEFINED; + dmsg(D_PS_PROXY_DEBUG, "PORT SHARE PROXY: delete sd=%d", (int)pc->sd); + if (es) + { + event_del(es, pc->sd); + } + openvpn_close_socket(pc->sd); + pc->sd = SOCKET_UNDEFINED; } } @@ -260,24 +274,26 @@ proxy_entry_close_sd (struct proxy_connection *pc, struct event_set *es) * Mark a proxy entry and its counterpart for close. */ static void -proxy_entry_mark_for_close (struct proxy_connection *pc, struct event_set *es) +proxy_entry_mark_for_close(struct proxy_connection *pc, struct event_set *es) { - if (pc->defined) - { - struct proxy_connection *cp = pc->counterpart; - proxy_entry_close_sd (pc, es); - free_buf (&pc->buf); - pc->buffer_initial = false; - pc->rwflags = 0; - pc->defined = false; - if (pc->jfn) - { - unlink (pc->jfn); - free (pc->jfn); - pc->jfn = NULL; - } - if (cp && cp->defined && cp->counterpart == pc) - proxy_entry_mark_for_close (cp, es); + if (pc->defined) + { + struct proxy_connection *cp = pc->counterpart; + proxy_entry_close_sd(pc, es); + free_buf(&pc->buf); + pc->buffer_initial = false; + pc->rwflags = 0; + pc->defined = false; + if (pc->jfn) + { + unlink(pc->jfn); + free(pc->jfn); + pc->jfn = NULL; + } + if (cp && cp->defined && cp->counterpart == pc) + { + proxy_entry_mark_for_close(cp, es); + } } } @@ -286,28 +302,34 @@ proxy_entry_mark_for_close (struct proxy_connection *pc, struct event_set *es) * for close. */ static void -proxy_list_housekeeping (struct proxy_connection **list) +proxy_list_housekeeping(struct proxy_connection **list) { - if (list) - { - struct proxy_connection *prev = NULL; - struct proxy_connection *pc = *list; - - while (pc) - { - struct proxy_connection *next = pc->next; - if (!pc->defined) - { - free (pc); - if (prev) - prev->next = next; - else - *list = next; - } - else - prev = pc; - pc = next; - } + if (list) + { + struct proxy_connection *prev = NULL; + struct proxy_connection *pc = *list; + + while (pc) + { + struct proxy_connection *next = pc->next; + if (!pc->defined) + { + free(pc); + if (prev) + { + prev->next = next; + } + else + { + *list = next; + } + } + else + { + prev = pc; + } + pc = next; + } } } @@ -316,70 +338,72 @@ proxy_list_housekeeping (struct proxy_connection **list) * the proxy can determine true client origin. */ static void -journal_add (const char *journal_dir, struct proxy_connection *pc, struct proxy_connection *cp) +journal_add(const char *journal_dir, struct proxy_connection *pc, struct proxy_connection *cp) { - struct gc_arena gc = gc_new (); - struct openvpn_sockaddr from, to; - socklen_t slen, dlen; - int fnlen; - char *jfn; - int fd; - - slen = sizeof(from.addr.sa); - dlen = sizeof(to.addr.sa); - if (!getpeername (pc->sd, (struct sockaddr *) &from.addr.sa, &slen) - && !getsockname (cp->sd, (struct sockaddr *) &to.addr.sa, &dlen)) - { - const char *f = print_openvpn_sockaddr (&from, &gc); - const char *t = print_openvpn_sockaddr (&to, &gc); - fnlen = strlen(journal_dir) + strlen(t) + 2; - jfn = (char *) malloc(fnlen); - check_malloc_return (jfn); - openvpn_snprintf (jfn, fnlen, "%s/%s", journal_dir, t); - dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: client origin %s -> %s", jfn, f); - fd = platform_open (jfn, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP); - if (fd != -1) - { - if (write(fd, f, strlen(f)) != strlen(f)) - msg(M_WARN, "PORT SHARE: writing to journal file (%s) failed", jfn); - close (fd); - cp->jfn = jfn; - } - else - { - msg (M_WARN|M_ERRNO, "PORT SHARE: unable to write journal file in %s", jfn); - free (jfn); - } - } - gc_free (&gc); + struct gc_arena gc = gc_new(); + struct openvpn_sockaddr from, to; + socklen_t slen, dlen; + int fnlen; + char *jfn; + int fd; + + slen = sizeof(from.addr.sa); + dlen = sizeof(to.addr.sa); + if (!getpeername(pc->sd, (struct sockaddr *) &from.addr.sa, &slen) + && !getsockname(cp->sd, (struct sockaddr *) &to.addr.sa, &dlen)) + { + const char *f = print_openvpn_sockaddr(&from, &gc); + const char *t = print_openvpn_sockaddr(&to, &gc); + fnlen = strlen(journal_dir) + strlen(t) + 2; + jfn = (char *) malloc(fnlen); + check_malloc_return(jfn); + openvpn_snprintf(jfn, fnlen, "%s/%s", journal_dir, t); + dmsg(D_PS_PROXY_DEBUG, "PORT SHARE PROXY: client origin %s -> %s", jfn, f); + fd = platform_open(jfn, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP); + if (fd != -1) + { + if (write(fd, f, strlen(f)) != strlen(f)) + { + msg(M_WARN, "PORT SHARE: writing to journal file (%s) failed", jfn); + } + close(fd); + cp->jfn = jfn; + } + else + { + msg(M_WARN|M_ERRNO, "PORT SHARE: unable to write journal file in %s", jfn); + free(jfn); + } + } + gc_free(&gc); } /* * Cleanup function, on proxy process exit. */ static void -proxy_list_close (struct proxy_connection **list) +proxy_list_close(struct proxy_connection **list) { - if (list) + if (list) { - struct proxy_connection *pc = *list; - while (pc) - { - proxy_entry_mark_for_close (pc, NULL); - pc = pc->next; - } - proxy_list_housekeeping (list); + struct proxy_connection *pc = *list; + while (pc) + { + proxy_entry_mark_for_close(pc, NULL); + pc = pc->next; + } + proxy_list_housekeeping(list); } } static inline void -proxy_connection_io_requeue (struct proxy_connection *pc, const int rwflags_new, struct event_set *es) +proxy_connection_io_requeue(struct proxy_connection *pc, const int rwflags_new, struct event_set *es) { - if (socket_defined (pc->sd) && pc->rwflags != rwflags_new) + if (socket_defined(pc->sd) && pc->rwflags != rwflags_new) { - /*dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: requeue[%d] rwflags=%d", (int)pc->sd, rwflags_new);*/ - event_ctl (es, pc->sd, rwflags_new, (void*)pc); - pc->rwflags = rwflags_new; + /*dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: requeue[%d] rwflags=%d", (int)pc->sd, rwflags_new);*/ + event_ctl(es, pc->sd, rwflags_new, (void *)pc); + pc->rwflags = rwflags_new; } } @@ -391,72 +415,74 @@ proxy_connection_io_requeue (struct proxy_connection *pc, const int rwflags_new, * on success and false on failure to connect to server. */ static bool -proxy_entry_new (struct proxy_connection **list, - struct event_set *es, - const struct sockaddr_in server_addr, - const socket_descriptor_t sd_client, - struct buffer *initial_data, - const char *journal_dir) +proxy_entry_new(struct proxy_connection **list, + struct event_set *es, + const struct sockaddr_in server_addr, + const socket_descriptor_t sd_client, + struct buffer *initial_data, + const char *journal_dir) { - socket_descriptor_t sd_server; - int status; - struct proxy_connection *pc; - struct proxy_connection *cp; - - /* connect to port share server */ - if ((sd_server = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) - { - msg (M_WARN|M_ERRNO, "PORT SHARE PROXY: cannot create socket"); - return false; - } - status = openvpn_connect (sd_server,(const struct sockaddr*) &server_addr, 5, NULL); - if (status) - { - msg (M_WARN, "PORT SHARE PROXY: connect to port-share server failed"); - openvpn_close_socket (sd_server); - return false; - } - dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: connect to port-share server succeeded"); - - set_nonblock (sd_client); - set_nonblock (sd_server); - - /* allocate 2 new proxy_connection objects */ - ALLOC_OBJ_CLEAR (pc, struct proxy_connection); - ALLOC_OBJ_CLEAR (cp, struct proxy_connection); - - /* client object */ - pc->defined = true; - pc->next = cp; - pc->counterpart = cp; - pc->buf = *initial_data; - pc->buffer_initial = true; - pc->rwflags = EVENT_UNDEF; - pc->sd = sd_client; - - /* server object */ - cp->defined = true; - cp->next = *list; - cp->counterpart = pc; - cp->buf = alloc_buf (PROXY_CONNECTION_BUFFER_SIZE); - cp->buffer_initial = false; - cp->rwflags = EVENT_UNDEF; - cp->sd = sd_server; - - /* add to list */ - *list = pc; - - /* add journal entry */ - if (journal_dir) - journal_add (journal_dir, pc, cp); - - dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: NEW CONNECTION [c=%d s=%d]", (int)sd_client, (int)sd_server); - - /* set initial i/o states */ - proxy_connection_io_requeue (pc, EVENT_READ, es); - proxy_connection_io_requeue (cp, EVENT_READ|EVENT_WRITE, es); - - return true; + socket_descriptor_t sd_server; + int status; + struct proxy_connection *pc; + struct proxy_connection *cp; + + /* connect to port share server */ + if ((sd_server = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) + { + msg(M_WARN|M_ERRNO, "PORT SHARE PROXY: cannot create socket"); + return false; + } + status = openvpn_connect(sd_server,(const struct sockaddr *) &server_addr, 5, NULL); + if (status) + { + msg(M_WARN, "PORT SHARE PROXY: connect to port-share server failed"); + openvpn_close_socket(sd_server); + return false; + } + dmsg(D_PS_PROXY_DEBUG, "PORT SHARE PROXY: connect to port-share server succeeded"); + + set_nonblock(sd_client); + set_nonblock(sd_server); + + /* allocate 2 new proxy_connection objects */ + ALLOC_OBJ_CLEAR(pc, struct proxy_connection); + ALLOC_OBJ_CLEAR(cp, struct proxy_connection); + + /* client object */ + pc->defined = true; + pc->next = cp; + pc->counterpart = cp; + pc->buf = *initial_data; + pc->buffer_initial = true; + pc->rwflags = EVENT_UNDEF; + pc->sd = sd_client; + + /* server object */ + cp->defined = true; + cp->next = *list; + cp->counterpart = pc; + cp->buf = alloc_buf(PROXY_CONNECTION_BUFFER_SIZE); + cp->buffer_initial = false; + cp->rwflags = EVENT_UNDEF; + cp->sd = sd_server; + + /* add to list */ + *list = pc; + + /* add journal entry */ + if (journal_dir) + { + journal_add(journal_dir, pc, cp); + } + + dmsg(D_PS_PROXY_DEBUG, "PORT SHARE PROXY: NEW CONNECTION [c=%d s=%d]", (int)sd_client, (int)sd_server); + + /* set initial i/o states */ + proxy_connection_io_requeue(pc, EVENT_READ, es); + proxy_connection_io_requeue(cp, EVENT_READ|EVENT_WRITE, es); + + return true; } /* @@ -466,146 +492,148 @@ proxy_entry_new (struct proxy_connection **list, * exit, true otherwise. */ static bool -control_message_from_parent (const socket_descriptor_t sd_control, - struct proxy_connection **list, - struct event_set *es, - const struct sockaddr_in server_addr, - const int max_initial_buf, - const char *journal_dir) +control_message_from_parent(const socket_descriptor_t sd_control, + struct proxy_connection **list, + struct event_set *es, + const struct sockaddr_in server_addr, + const int max_initial_buf, + const char *journal_dir) { - /* this buffer needs to be large enough to handle the largest buffer - that might be returned by the link_socket_read call in read_incoming_link. */ - struct buffer buf = alloc_buf (max_initial_buf); - - struct msghdr mesg; - struct cmsghdr* h; - struct iovec iov[2]; - char command = 0; - ssize_t status; - int ret = true; - - CLEAR (mesg); - - iov[0].iov_base = &command; - iov[0].iov_len = sizeof (command); - iov[1].iov_base = BPTR (&buf); - iov[1].iov_len = BCAP (&buf); - mesg.msg_iov = iov; - mesg.msg_iovlen = 2; - - mesg.msg_controllen = cmsg_size (); - mesg.msg_control = (char *) malloc (mesg.msg_controllen); - check_malloc_return (mesg.msg_control); - mesg.msg_flags = 0; - - h = CMSG_FIRSTHDR(&mesg); - h->cmsg_len = CMSG_LEN(sizeof(socket_descriptor_t)); - h->cmsg_level = SOL_SOCKET; - h->cmsg_type = SCM_RIGHTS; - static const socket_descriptor_t socket_undefined = SOCKET_UNDEFINED; - memcpy (CMSG_DATA(h), &socket_undefined, sizeof(socket_undefined)); - - status = recvmsg (sd_control, &mesg, MSG_NOSIGNAL); - if (status != -1) - { - if ( h == NULL - || h->cmsg_len != CMSG_LEN(sizeof(socket_descriptor_t)) - || h->cmsg_level != SOL_SOCKET - || h->cmsg_type != SCM_RIGHTS ) - { - msg (M_WARN, "PORT SHARE PROXY: received unknown message"); - } - else - { - socket_descriptor_t received_fd; - memcpy (&received_fd, CMSG_DATA(h), sizeof(received_fd)); - dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: RECEIVED sd=%d", (int)received_fd); - - if (status >= 2 && command == COMMAND_REDIRECT) - { - buf.len = status - 1; - if (proxy_entry_new (list, - es, - server_addr, - received_fd, - &buf, - journal_dir)) - { - CLEAR (buf); /* we gave the buffer to proxy_entry_new */ - } - else - { - openvpn_close_socket (received_fd); - } - } - else if (status >= 1 && command == COMMAND_EXIT) - { - dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: RECEIVED COMMAND_EXIT"); - openvpn_close_socket (received_fd); /* null socket */ - ret = false; - } - } - } - free (mesg.msg_control); - free_buf (&buf); - return ret; + /* this buffer needs to be large enough to handle the largest buffer + * that might be returned by the link_socket_read call in read_incoming_link. */ + struct buffer buf = alloc_buf(max_initial_buf); + + struct msghdr mesg; + struct cmsghdr *h; + struct iovec iov[2]; + char command = 0; + ssize_t status; + int ret = true; + + CLEAR(mesg); + + iov[0].iov_base = &command; + iov[0].iov_len = sizeof(command); + iov[1].iov_base = BPTR(&buf); + iov[1].iov_len = BCAP(&buf); + mesg.msg_iov = iov; + mesg.msg_iovlen = 2; + + mesg.msg_controllen = cmsg_size(); + mesg.msg_control = (char *) malloc(mesg.msg_controllen); + check_malloc_return(mesg.msg_control); + mesg.msg_flags = 0; + + h = CMSG_FIRSTHDR(&mesg); + h->cmsg_len = CMSG_LEN(sizeof(socket_descriptor_t)); + h->cmsg_level = SOL_SOCKET; + h->cmsg_type = SCM_RIGHTS; + static const socket_descriptor_t socket_undefined = SOCKET_UNDEFINED; + memcpy(CMSG_DATA(h), &socket_undefined, sizeof(socket_undefined)); + + status = recvmsg(sd_control, &mesg, MSG_NOSIGNAL); + if (status != -1) + { + if (h == NULL + || h->cmsg_len != CMSG_LEN(sizeof(socket_descriptor_t)) + || h->cmsg_level != SOL_SOCKET + || h->cmsg_type != SCM_RIGHTS) + { + msg(M_WARN, "PORT SHARE PROXY: received unknown message"); + } + else + { + socket_descriptor_t received_fd; + memcpy(&received_fd, CMSG_DATA(h), sizeof(received_fd)); + dmsg(D_PS_PROXY_DEBUG, "PORT SHARE PROXY: RECEIVED sd=%d", (int)received_fd); + + if (status >= 2 && command == COMMAND_REDIRECT) + { + buf.len = status - 1; + if (proxy_entry_new(list, + es, + server_addr, + received_fd, + &buf, + journal_dir)) + { + CLEAR(buf); /* we gave the buffer to proxy_entry_new */ + } + else + { + openvpn_close_socket(received_fd); + } + } + else if (status >= 1 && command == COMMAND_EXIT) + { + dmsg(D_PS_PROXY_DEBUG, "PORT SHARE PROXY: RECEIVED COMMAND_EXIT"); + openvpn_close_socket(received_fd); /* null socket */ + ret = false; + } + } + } + free(mesg.msg_control); + free_buf(&buf); + return ret; } static int -proxy_connection_io_recv (struct proxy_connection *pc) +proxy_connection_io_recv(struct proxy_connection *pc) { - /* recv data from socket */ - const int status = recv (pc->sd, BPTR(&pc->buf), BCAP(&pc->buf), MSG_NOSIGNAL); - if (status < 0) + /* recv data from socket */ + const int status = recv(pc->sd, BPTR(&pc->buf), BCAP(&pc->buf), MSG_NOSIGNAL); + if (status < 0) { - return (errno == EAGAIN) ? IOSTAT_EAGAIN_ON_READ : IOSTAT_READ_ERROR; + return (errno == EAGAIN) ? IOSTAT_EAGAIN_ON_READ : IOSTAT_READ_ERROR; } - else + else { - if (!status) - return IOSTAT_READ_ERROR; - dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: read[%d] %d", (int)pc->sd, status); - pc->buf.len = status; + if (!status) + { + return IOSTAT_READ_ERROR; + } + dmsg(D_PS_PROXY_DEBUG, "PORT SHARE PROXY: read[%d] %d", (int)pc->sd, status); + pc->buf.len = status; } - return IOSTAT_GOOD; + return IOSTAT_GOOD; } static int -proxy_connection_io_send (struct proxy_connection *pc, int *bytes_sent) +proxy_connection_io_send(struct proxy_connection *pc, int *bytes_sent) { - const socket_descriptor_t sd = pc->counterpart->sd; - const int status = send (sd, BPTR(&pc->buf), BLEN(&pc->buf), MSG_NOSIGNAL); + const socket_descriptor_t sd = pc->counterpart->sd; + const int status = send(sd, BPTR(&pc->buf), BLEN(&pc->buf), MSG_NOSIGNAL); - if (status < 0) + if (status < 0) { - const int e = errno; - return (e == EAGAIN) ? IOSTAT_EAGAIN_ON_WRITE : IOSTAT_WRITE_ERROR; + const int e = errno; + return (e == EAGAIN) ? IOSTAT_EAGAIN_ON_WRITE : IOSTAT_WRITE_ERROR; } - else + else { - *bytes_sent += status; - if (status != pc->buf.len) - { - dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: partial write[%d], tried=%d got=%d", (int)sd, pc->buf.len, status); - buf_advance (&pc->buf, status); - return IOSTAT_EAGAIN_ON_WRITE; - } - else - { - dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: wrote[%d] %d", (int)sd, status); - pc->buf.len = 0; - pc->buf.offset = 0; - } + *bytes_sent += status; + if (status != pc->buf.len) + { + dmsg(D_PS_PROXY_DEBUG, "PORT SHARE PROXY: partial write[%d], tried=%d got=%d", (int)sd, pc->buf.len, status); + buf_advance(&pc->buf, status); + return IOSTAT_EAGAIN_ON_WRITE; + } + else + { + dmsg(D_PS_PROXY_DEBUG, "PORT SHARE PROXY: wrote[%d] %d", (int)sd, status); + pc->buf.len = 0; + pc->buf.offset = 0; + } } - /* realloc send buffer after initial send */ - if (pc->buffer_initial) + /* realloc send buffer after initial send */ + if (pc->buffer_initial) { - free_buf (&pc->buf); - pc->buf = alloc_buf (PROXY_CONNECTION_BUFFER_SIZE); - pc->buffer_initial = false; + free_buf(&pc->buf); + pc->buf = alloc_buf(PROXY_CONNECTION_BUFFER_SIZE); + pc->buffer_initial = false; } - return IOSTAT_GOOD; + return IOSTAT_GOOD; } /* @@ -613,52 +641,60 @@ proxy_connection_io_send (struct proxy_connection *pc, int *bytes_sent) */ static int -proxy_connection_io_xfer (struct proxy_connection *pc, const int max_transfer) +proxy_connection_io_xfer(struct proxy_connection *pc, const int max_transfer) { - int transferred = 0; - while (transferred < max_transfer) - { - if (!BLEN (&pc->buf)) - { - const int status = proxy_connection_io_recv (pc); - if (status != IOSTAT_GOOD) - return status; - } - - if (BLEN (&pc->buf)) - { - const int status = proxy_connection_io_send (pc, &transferred); - if (status != IOSTAT_GOOD) - return status; - } - } - return IOSTAT_EAGAIN_ON_READ; + int transferred = 0; + while (transferred < max_transfer) + { + if (!BLEN(&pc->buf)) + { + const int status = proxy_connection_io_recv(pc); + if (status != IOSTAT_GOOD) + { + return status; + } + } + + if (BLEN(&pc->buf)) + { + const int status = proxy_connection_io_send(pc, &transferred); + if (status != IOSTAT_GOOD) + { + return status; + } + } + } + return IOSTAT_EAGAIN_ON_READ; } /* * Decide how the receipt of an EAGAIN status should affect our next IO queueing. */ static bool -proxy_connection_io_status (const int status, int *rwflags_pc, int *rwflags_cp) +proxy_connection_io_status(const int status, int *rwflags_pc, int *rwflags_cp) { - switch (status) - { - case IOSTAT_EAGAIN_ON_READ: - *rwflags_pc |= EVENT_READ; - *rwflags_cp &= ~EVENT_WRITE; - return true; - case IOSTAT_EAGAIN_ON_WRITE: - *rwflags_pc &= ~EVENT_READ; - *rwflags_cp |= EVENT_WRITE; - return true; - case IOSTAT_READ_ERROR: - return false; - case IOSTAT_WRITE_ERROR: - return false; - default: - msg (M_FATAL, "PORT SHARE PROXY: unexpected status=%d", status); - } - return false; /* NOTREACHED */ + switch (status) + { + case IOSTAT_EAGAIN_ON_READ: + *rwflags_pc |= EVENT_READ; + *rwflags_cp &= ~EVENT_WRITE; + return true; + + case IOSTAT_EAGAIN_ON_WRITE: + *rwflags_pc &= ~EVENT_READ; + *rwflags_cp |= EVENT_WRITE; + return true; + + case IOSTAT_READ_ERROR: + return false; + + case IOSTAT_WRITE_ERROR: + return false; + + default: + msg(M_FATAL, "PORT SHARE PROXY: unexpected status=%d", status); + } + return false; /* NOTREACHED */ } /* @@ -666,107 +702,115 @@ proxy_connection_io_status (const int status, int *rwflags_pc, int *rwflags_cp) * in the proxied connection. */ static int -proxy_connection_io_dispatch (struct proxy_connection *pc, - const int rwflags, - struct event_set *es) +proxy_connection_io_dispatch(struct proxy_connection *pc, + const int rwflags, + struct event_set *es) { - const int max_transfer_per_iteration = 10000; - struct proxy_connection *cp = pc->counterpart; - int rwflags_pc = pc->rwflags; - int rwflags_cp = cp->rwflags; + const int max_transfer_per_iteration = 10000; + struct proxy_connection *cp = pc->counterpart; + int rwflags_pc = pc->rwflags; + int rwflags_cp = cp->rwflags; - ASSERT(pc->defined && cp->defined && cp->counterpart == pc); + ASSERT(pc->defined && cp->defined && cp->counterpart == pc); - if (rwflags & EVENT_READ) + if (rwflags & EVENT_READ) { - const int status = proxy_connection_io_xfer (pc, max_transfer_per_iteration); - if (!proxy_connection_io_status (status, &rwflags_pc, &rwflags_cp)) - goto bad; + const int status = proxy_connection_io_xfer(pc, max_transfer_per_iteration); + if (!proxy_connection_io_status(status, &rwflags_pc, &rwflags_cp)) + { + goto bad; + } } - if (rwflags & EVENT_WRITE) + if (rwflags & EVENT_WRITE) { - const int status = proxy_connection_io_xfer (cp, max_transfer_per_iteration); - if (!proxy_connection_io_status (status, &rwflags_cp, &rwflags_pc)) - goto bad; + const int status = proxy_connection_io_xfer(cp, max_transfer_per_iteration); + if (!proxy_connection_io_status(status, &rwflags_cp, &rwflags_pc)) + { + goto bad; + } } - proxy_connection_io_requeue (pc, rwflags_pc, es); - proxy_connection_io_requeue (cp, rwflags_cp, es); + proxy_connection_io_requeue(pc, rwflags_pc, es); + proxy_connection_io_requeue(cp, rwflags_cp, es); - return true; + return true; - bad: - proxy_entry_mark_for_close (pc, es); - return false; +bad: + proxy_entry_mark_for_close(pc, es); + return false; } /* * This is the main function for the port share proxy background process. */ static void -port_share_proxy (const struct sockaddr_in hostaddr, - const socket_descriptor_t sd_control, - const int max_initial_buf, - const char *journal_dir) +port_share_proxy(const struct sockaddr_in hostaddr, + const socket_descriptor_t sd_control, + const int max_initial_buf, + const char *journal_dir) { - if (send_control (sd_control, RESPONSE_INIT_SUCCEEDED) >= 0) - { - void *sd_control_marker = (void *)1; - int maxevents = 256; - struct event_set *es; - struct event_set_return esr[64]; - struct proxy_connection *list = NULL; - time_t last_housekeeping = 0; - - msg (D_PS_PROXY, "PORT SHARE PROXY: proxy starting"); - - es = event_set_init (&maxevents, 0); - event_ctl (es, sd_control, EVENT_READ, sd_control_marker); - while (true) - { - int n_events; - struct timeval tv; - time_t current; - - tv.tv_sec = 10; - tv.tv_usec = 0; - n_events = event_wait (es, &tv, esr, SIZE(esr)); - /*dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: event_wait returned %d", n_events);*/ - current = time(NULL); - if (n_events > 0) - { - int i; - for (i = 0; i < n_events; ++i) - { - const struct event_set_return *e = &esr[i]; - if (e->arg == sd_control_marker) - { - if (!control_message_from_parent (sd_control, &list, es, hostaddr, max_initial_buf, journal_dir)) - goto done; - } - else - { - struct proxy_connection *pc = (struct proxy_connection *)e->arg; - if (pc->defined) - proxy_connection_io_dispatch (pc, e->rwflags, es); - } - } - } - else if (n_events < 0) - { - dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: event_wait failed"); - } - if (current > last_housekeeping) - { - proxy_list_housekeeping (&list); - last_housekeeping = current; - } - } - - done: - proxy_list_close (&list); - event_free (es); - } - msg (M_INFO, "PORT SHARE PROXY: proxy exiting"); + if (send_control(sd_control, RESPONSE_INIT_SUCCEEDED) >= 0) + { + void *sd_control_marker = (void *)1; + int maxevents = 256; + struct event_set *es; + struct event_set_return esr[64]; + struct proxy_connection *list = NULL; + time_t last_housekeeping = 0; + + msg(D_PS_PROXY, "PORT SHARE PROXY: proxy starting"); + + es = event_set_init(&maxevents, 0); + event_ctl(es, sd_control, EVENT_READ, sd_control_marker); + while (true) + { + int n_events; + struct timeval tv; + time_t current; + + tv.tv_sec = 10; + tv.tv_usec = 0; + n_events = event_wait(es, &tv, esr, SIZE(esr)); + /*dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: event_wait returned %d", n_events);*/ + current = time(NULL); + if (n_events > 0) + { + int i; + for (i = 0; i < n_events; ++i) + { + const struct event_set_return *e = &esr[i]; + if (e->arg == sd_control_marker) + { + if (!control_message_from_parent(sd_control, &list, es, hostaddr, max_initial_buf, journal_dir)) + { + goto done; + } + } + else + { + struct proxy_connection *pc = (struct proxy_connection *)e->arg; + if (pc->defined) + { + proxy_connection_io_dispatch(pc, e->rwflags, es); + } + } + } + } + else if (n_events < 0) + { + dmsg(D_PS_PROXY_DEBUG, "PORT SHARE PROXY: event_wait failed"); + } + if (current > last_housekeeping) + { + proxy_list_housekeeping(&list); + last_housekeeping = current; + } + } + +done: + proxy_list_close(&list); + event_free(es); + } + msg(M_INFO, "PORT SHARE PROXY: proxy exiting"); } /* @@ -774,155 +818,157 @@ port_share_proxy (const struct sockaddr_in hostaddr, * share proxy. */ struct port_share * -port_share_open (const char *host, - const char *port, - const int max_initial_buf, - const char *journal_dir) +port_share_open(const char *host, + const char *port, + const int max_initial_buf, + const char *journal_dir) { - pid_t pid; - socket_descriptor_t fd[2]; - struct sockaddr_in hostaddr; - struct port_share *ps; - int status; - struct addrinfo* ai; - - ALLOC_OBJ_CLEAR (ps, struct port_share); - ps->foreground_fd = -1; - ps->background_pid = -1; - - /* - * Get host's IP address - */ - - status = openvpn_getaddrinfo (GETADDR_RESOLVE|GETADDR_FATAL, + pid_t pid; + socket_descriptor_t fd[2]; + struct sockaddr_in hostaddr; + struct port_share *ps; + int status; + struct addrinfo *ai; + + ALLOC_OBJ_CLEAR(ps, struct port_share); + ps->foreground_fd = -1; + ps->background_pid = -1; + + /* + * Get host's IP address + */ + + status = openvpn_getaddrinfo(GETADDR_RESOLVE|GETADDR_FATAL, host, port, 0, NULL, AF_INET, &ai); - ASSERT (status==0); - hostaddr = *((struct sockaddr_in*) ai->ai_addr); - freeaddrinfo(ai); - - /* - * Make a socket for foreground and background processes - * to communicate. - */ - if (socketpair (PF_UNIX, SOCK_DGRAM, 0, fd) == -1) + ASSERT(status==0); + hostaddr = *((struct sockaddr_in *) ai->ai_addr); + freeaddrinfo(ai); + + /* + * Make a socket for foreground and background processes + * to communicate. + */ + if (socketpair(PF_UNIX, SOCK_DGRAM, 0, fd) == -1) { - msg (M_WARN, "PORT SHARE: socketpair call failed"); - goto error; + msg(M_WARN, "PORT SHARE: socketpair call failed"); + goto error; } - /* - * Fork off background proxy process. - */ - pid = fork (); + /* + * Fork off background proxy process. + */ + pid = fork(); - if (pid) + if (pid) { - int status; - - /* - * Foreground Process - */ - - ps->background_pid = pid; - - /* close our copy of child's socket */ - openvpn_close_socket (fd[1]); - - /* don't let future subprocesses inherit child socket */ - set_cloexec (fd[0]); - - /* wait for background child process to initialize */ - status = recv_control (fd[0]); - if (status == RESPONSE_INIT_SUCCEEDED) - { - /* note that this will cause possible EAGAIN when writing to - control socket if proxy process is backlogged */ - set_nonblock (fd[0]); - - ps->foreground_fd = fd[0]; - return ps; - } - else - { - msg (M_ERR, "PORT SHARE: unexpected init recv_control status=%d", status); - } + int status; + + /* + * Foreground Process + */ + + ps->background_pid = pid; + + /* close our copy of child's socket */ + openvpn_close_socket(fd[1]); + + /* don't let future subprocesses inherit child socket */ + set_cloexec(fd[0]); + + /* wait for background child process to initialize */ + status = recv_control(fd[0]); + if (status == RESPONSE_INIT_SUCCEEDED) + { + /* note that this will cause possible EAGAIN when writing to + * control socket if proxy process is backlogged */ + set_nonblock(fd[0]); + + ps->foreground_fd = fd[0]; + return ps; + } + else + { + msg(M_ERR, "PORT SHARE: unexpected init recv_control status=%d", status); + } } - else + else { - /* - * Background Process - */ + /* + * Background Process + */ - /* Ignore most signals (the parent will receive them) */ - set_signals (); + /* Ignore most signals (the parent will receive them) */ + set_signals(); - /* Let msg know that we forked */ - msg_forked (); + /* Let msg know that we forked */ + msg_forked(); #ifdef ENABLE_MANAGEMENT - /* Don't interact with management interface */ - management = NULL; + /* Don't interact with management interface */ + management = NULL; #endif - /* close all parent fds except our socket back to parent */ - close_fds_except (fd[1]); + /* close all parent fds except our socket back to parent */ + close_fds_except(fd[1]); - /* no blocking on control channel back to parent */ - set_nonblock (fd[1]); + /* no blocking on control channel back to parent */ + set_nonblock(fd[1]); - /* initialize prng */ - prng_init (NULL, 0); + /* initialize prng */ + prng_init(NULL, 0); - /* execute the event loop */ - port_share_proxy (hostaddr, fd[1], max_initial_buf, journal_dir); + /* execute the event loop */ + port_share_proxy(hostaddr, fd[1], max_initial_buf, journal_dir); - openvpn_close_socket (fd[1]); + openvpn_close_socket(fd[1]); - exit (0); - return 0; /* NOTREACHED */ + exit(0); + return 0; /* NOTREACHED */ } - error: - port_share_close (ps); - return NULL; +error: + port_share_close(ps); + return NULL; } void -port_share_close (struct port_share *ps) +port_share_close(struct port_share *ps) { - if (ps) + if (ps) { - if (ps->foreground_fd >= 0) - { - /* tell background process to exit */ - port_share_sendmsg (ps->foreground_fd, COMMAND_EXIT, NULL, SOCKET_UNDEFINED); - - /* wait for background process to exit */ - dmsg (D_PS_PROXY_DEBUG, "PORT SHARE: waiting for background process to exit"); - if (ps->background_pid > 0) - waitpid (ps->background_pid, NULL, 0); - dmsg (D_PS_PROXY_DEBUG, "PORT SHARE: background process exited"); - - openvpn_close_socket (ps->foreground_fd); - ps->foreground_fd = -1; - } - - free (ps); + if (ps->foreground_fd >= 0) + { + /* tell background process to exit */ + port_share_sendmsg(ps->foreground_fd, COMMAND_EXIT, NULL, SOCKET_UNDEFINED); + + /* wait for background process to exit */ + dmsg(D_PS_PROXY_DEBUG, "PORT SHARE: waiting for background process to exit"); + if (ps->background_pid > 0) + { + waitpid(ps->background_pid, NULL, 0); + } + dmsg(D_PS_PROXY_DEBUG, "PORT SHARE: background process exited"); + + openvpn_close_socket(ps->foreground_fd); + ps->foreground_fd = -1; + } + + free(ps); } } void -port_share_abort (struct port_share *ps) +port_share_abort(struct port_share *ps) { - if (ps) + if (ps) { - /* tell background process to exit */ - if (ps->foreground_fd >= 0) - { - send_control (ps->foreground_fd, COMMAND_EXIT); - openvpn_close_socket (ps->foreground_fd); - ps->foreground_fd = -1; - } + /* tell background process to exit */ + if (ps->foreground_fd >= 0) + { + send_control(ps->foreground_fd, COMMAND_EXIT); + openvpn_close_socket(ps->foreground_fd); + ps->foreground_fd = -1; + } } } @@ -932,22 +978,24 @@ port_share_abort (struct port_share *ps) * client attempting to connect with an OpenVPN server. */ bool -is_openvpn_protocol (const struct buffer *buf) +is_openvpn_protocol(const struct buffer *buf) { - const unsigned char *p = (const unsigned char *) BSTR (buf); - const int len = BLEN (buf); - if (len >= 3) + const unsigned char *p = (const unsigned char *) BSTR(buf); + const int len = BLEN(buf); + if (len >= 3) { - return p[0] == 0 - && p[1] >= 14 - && p[2] == (P_CONTROL_HARD_RESET_CLIENT_V2<= 14 + && p[2] == (P_CONTROL_HARD_RESET_CLIENT_V2<= 2) + else if (len >= 2) { - return p[0] == 0 && p[1] >= 14; + return p[0] == 0 && p[1] >= 14; + } + else + { + return true; } - else - return true; } /* @@ -956,12 +1004,12 @@ is_openvpn_protocol (const struct buffer *buf) * call. */ void -port_share_redirect (struct port_share *ps, const struct buffer *head, socket_descriptor_t sd) +port_share_redirect(struct port_share *ps, const struct buffer *head, socket_descriptor_t sd) { - if (ps) + if (ps) { - port_share_sendmsg (ps->foreground_fd, COMMAND_REDIRECT, head, sd); + port_share_sendmsg(ps->foreground_fd, COMMAND_REDIRECT, head, sd); } } -#endif +#endif /* if PORT_SHARE */ diff --git a/src/openvpn/ps.h b/src/openvpn/ps.h index e8919d4810e..cbfe9b8765c 100644 --- a/src/openvpn/ps.h +++ b/src/openvpn/ps.h @@ -34,26 +34,27 @@ typedef void (*post_fork_cleanup_func_t)(void *arg); struct port_share { - /* Foreground's socket to background process */ - socket_descriptor_t foreground_fd; + /* Foreground's socket to background process */ + socket_descriptor_t foreground_fd; - /* Process ID of background process */ - pid_t background_pid; + /* Process ID of background process */ + pid_t background_pid; }; extern struct port_share *port_share; -struct port_share *port_share_open (const char *host, - const char *port, - const int max_initial_buf, - const char *journal_dir); +struct port_share *port_share_open(const char *host, + const char *port, + const int max_initial_buf, + const char *journal_dir); -void port_share_close (struct port_share *ps); -void port_share_abort (struct port_share *ps); +void port_share_close(struct port_share *ps); -bool is_openvpn_protocol (const struct buffer *buf); +void port_share_abort(struct port_share *ps); -void port_share_redirect (struct port_share *ps, const struct buffer *head, socket_descriptor_t sd); +bool is_openvpn_protocol(const struct buffer *buf); -#endif -#endif +void port_share_redirect(struct port_share *ps, const struct buffer *head, socket_descriptor_t sd); + +#endif /* if PORT_SHARE */ +#endif /* ifndef PS_H */ diff --git a/src/openvpn/push.c b/src/openvpn/push.c index 9953079c603..34c65c49413 100644 --- a/src/openvpn/push.c +++ b/src/openvpn/push.c @@ -49,50 +49,55 @@ static char push_reply_cmd[] = "PUSH_REPLY"; * Runs on client. */ void -receive_auth_failed (struct context *c, const struct buffer *buffer) +receive_auth_failed(struct context *c, const struct buffer *buffer) { - msg (M_VERB0, "AUTH: Received control message: %s", BSTR(buffer)); - c->options.no_advance=true; - - if (c->options.pull) - { - switch (auth_retry_get ()) - { - case AR_NONE: - c->sig->signal_received = SIGTERM; /* SOFT-SIGTERM -- Auth failure error */ - break; - case AR_INTERACT: - ssl_purge_auth (false); - case AR_NOINTERACT: - c->sig->signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- Auth failure error */ - break; - default: - ASSERT (0); - } - c->sig->signal_text = "auth-failure"; + msg(M_VERB0, "AUTH: Received control message: %s", BSTR(buffer)); + c->options.no_advance = true; + + if (c->options.pull) + { + switch (auth_retry_get()) + { + case AR_NONE: + c->sig->signal_received = SIGTERM; /* SOFT-SIGTERM -- Auth failure error */ + break; + + case AR_INTERACT: + ssl_purge_auth(false); + + case AR_NOINTERACT: + c->sig->signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- Auth failure error */ + break; + + default: + ASSERT(0); + } + c->sig->signal_text = "auth-failure"; #ifdef ENABLE_MANAGEMENT - if (management) - { - const char *reason = NULL; - struct buffer buf = *buffer; - if (buf_string_compare_advance (&buf, "AUTH_FAILED,") && BLEN (&buf)) - reason = BSTR (&buf); - management_auth_failure (management, UP_TYPE_AUTH, reason); - } + if (management) + { + const char *reason = NULL; + struct buffer buf = *buffer; + if (buf_string_compare_advance(&buf, "AUTH_FAILED,") && BLEN(&buf)) + { + reason = BSTR(&buf); + } + management_auth_failure(management, UP_TYPE_AUTH, reason); + } #endif - /* - * Save the dynamic-challenge text even when management is defined - */ - { + /* + * Save the dynamic-challenge text even when management is defined + */ + { #ifdef ENABLE_CLIENT_CR - struct buffer buf = *buffer; - if (buf_string_match_head_str (&buf, "AUTH_FAILED,CRV1:") && BLEN (&buf)) - { - buf_advance (&buf, 12); /* Length of "AUTH_FAILED," substring */ - ssl_put_auth_challenge (BSTR (&buf)); - } + struct buffer buf = *buffer; + if (buf_string_match_head_str(&buf, "AUTH_FAILED,CRV1:") && BLEN(&buf)) + { + buf_advance(&buf, 12); /* Length of "AUTH_FAILED," substring */ + ssl_put_auth_challenge(BSTR(&buf)); + } #endif - } + } } } @@ -100,53 +105,61 @@ receive_auth_failed (struct context *c, const struct buffer *buffer) * Act on received restart message from server */ void -server_pushed_signal (struct context *c, const struct buffer *buffer, const bool restart, const int adv) +server_pushed_signal(struct context *c, const struct buffer *buffer, const bool restart, const int adv) { - if (c->options.pull) - { - struct buffer buf = *buffer; - const char *m = ""; - if (buf_advance (&buf, adv) && buf_read_u8 (&buf) == ',' && BLEN (&buf)) - m = BSTR (&buf); - - /* preserve cached passwords? */ - /* advance to next server? */ - { - bool purge = true; - - if (m[0] == '[') - { - int i; - for (i = 1; m[i] != '\0' && m[i] != ']'; ++i) - { - if (m[i] == 'P') - purge = false; - else if (m[i] == 'N') - { - /* next server? */ - c->options.no_advance = false; - } - } - } - if (purge) - ssl_purge_auth (true); - } - - if (restart) - { - msg (D_STREAM_ERRORS, "Connection reset command was pushed by server ('%s')", m); - c->sig->signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- server-pushed connection reset */ - c->sig->signal_text = "server-pushed-connection-reset"; - } - else - { - msg (D_STREAM_ERRORS, "Halt command was pushed by server ('%s')", m); - c->sig->signal_received = SIGTERM; /* SOFT-SIGTERM -- server-pushed halt */ - c->sig->signal_text = "server-pushed-halt"; - } + if (c->options.pull) + { + struct buffer buf = *buffer; + const char *m = ""; + if (buf_advance(&buf, adv) && buf_read_u8(&buf) == ',' && BLEN(&buf)) + { + m = BSTR(&buf); + } + + /* preserve cached passwords? */ + /* advance to next server? */ + { + bool purge = true; + + if (m[0] == '[') + { + int i; + for (i = 1; m[i] != '\0' && m[i] != ']'; ++i) + { + if (m[i] == 'P') + { + purge = false; + } + else if (m[i] == 'N') + { + /* next server? */ + c->options.no_advance = false; + } + } + } + if (purge) + { + ssl_purge_auth(true); + } + } + + if (restart) + { + msg(D_STREAM_ERRORS, "Connection reset command was pushed by server ('%s')", m); + c->sig->signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- server-pushed connection reset */ + c->sig->signal_text = "server-pushed-connection-reset"; + } + else + { + msg(D_STREAM_ERRORS, "Halt command was pushed by server ('%s')", m); + c->sig->signal_received = SIGTERM; /* SOFT-SIGTERM -- server-pushed halt */ + c->sig->signal_text = "server-pushed-halt"; + } #ifdef ENABLE_MANAGEMENT - if (management) - management_notify (management, "info", c->sig->signal_text, m); + if (management) + { + management_notify(management, "info", c->sig->signal_text, m); + } #endif } } @@ -167,128 +180,134 @@ server_pushed_signal (struct context *c, const struct buffer *buffer, const bool * @return true on success, false on failure. */ static bool push_option_fmt(struct gc_arena *gc, struct push_list *push_list, - int msglevel, const char *fmt, ...) + int msglevel, const char *fmt, ...) #ifdef __GNUC__ #if __USE_MINGW_ANSI_STDIO - __attribute__ ((format (gnu_printf, 4, 5))) +__attribute__ ((format(gnu_printf, 4, 5))) #else - __attribute__ ((format (__printf__, 4, 5))) +__attribute__ ((format(__printf__, 4, 5))) #endif #endif - ; +; /* * Send auth failed message from server to client. */ void -send_auth_failed (struct context *c, const char *client_reason) +send_auth_failed(struct context *c, const char *client_reason) { - struct gc_arena gc = gc_new (); - static const char auth_failed[] = "AUTH_FAILED"; - size_t len; + struct gc_arena gc = gc_new(); + static const char auth_failed[] = "AUTH_FAILED"; + size_t len; - schedule_exit (c, c->options.scheduled_exit_interval, SIGTERM); + schedule_exit(c, c->options.scheduled_exit_interval, SIGTERM); - len = (client_reason ? strlen(client_reason)+1 : 0) + sizeof(auth_failed); - if (len > PUSH_BUNDLE_SIZE) - len = PUSH_BUNDLE_SIZE; + len = (client_reason ? strlen(client_reason)+1 : 0) + sizeof(auth_failed); + if (len > PUSH_BUNDLE_SIZE) + { + len = PUSH_BUNDLE_SIZE; + } - { - struct buffer buf = alloc_buf_gc (len, &gc); - buf_printf (&buf, auth_failed); - if (client_reason) - buf_printf (&buf, ",%s", client_reason); - send_control_channel_string (c, BSTR (&buf), D_PUSH); - } + { + struct buffer buf = alloc_buf_gc(len, &gc); + buf_printf(&buf, auth_failed); + if (client_reason) + { + buf_printf(&buf, ",%s", client_reason); + } + send_control_channel_string(c, BSTR(&buf), D_PUSH); + } - gc_free (&gc); + gc_free(&gc); } /* * Send restart message from server to client. */ void -send_restart (struct context *c, const char *kill_msg) +send_restart(struct context *c, const char *kill_msg) { - schedule_exit (c, c->options.scheduled_exit_interval, SIGTERM); - send_control_channel_string (c, kill_msg ? kill_msg : "RESTART", D_PUSH); + schedule_exit(c, c->options.scheduled_exit_interval, SIGTERM); + send_control_channel_string(c, kill_msg ? kill_msg : "RESTART", D_PUSH); } -#endif +#endif /* if P2MP_SERVER */ /* * Push/Pull */ void -incoming_push_message (struct context *c, const struct buffer *buffer) +incoming_push_message(struct context *c, const struct buffer *buffer) { - struct gc_arena gc = gc_new (); - unsigned int option_types_found = 0; - int status; - - msg (D_PUSH, "PUSH: Received control message: '%s'", sanitize_control_message(BSTR(buffer), &gc)); - - status = process_incoming_push_msg (c, - buffer, - c->options.pull, - pull_permission_mask (c), - &option_types_found); - - if (status == PUSH_MSG_ERROR) - msg (D_PUSH_ERRORS, "WARNING: Received bad push/pull message: %s", sanitize_control_message(BSTR(buffer), &gc)); - else if (status == PUSH_MSG_REPLY || status == PUSH_MSG_CONTINUATION) - { - c->options.push_option_types_found |= option_types_found; - - /* delay bringing tun/tap up until --push parms received from remote */ - if (status == PUSH_MSG_REPLY) - { - if (!do_up (c, true, c->options.push_option_types_found)) - { - msg (D_PUSH_ERRORS, "Failed to open tun/tap interface"); - goto error; - } - } - event_timeout_clear (&c->c2.push_request_interval); - } - else if (status == PUSH_MSG_REQUEST) - { - if (c->options.mode == MODE_SERVER) - { - struct tls_session *session = &c->c2.tls_multi->session[TM_ACTIVE]; - /* Do not regenerate keys if client send a second push request */ - if (!session->key[KS_PRIMARY].crypto_options.key_ctx_bi.initialized && - !tls_session_update_crypto_params (session, &c->options, - &c->c2.frame)) - { - msg (D_TLS_ERRORS, "TLS Error: initializing data channel failed"); - goto error; - } - } - } - - goto cleanup; + struct gc_arena gc = gc_new(); + unsigned int option_types_found = 0; + int status; + + msg(D_PUSH, "PUSH: Received control message: '%s'", sanitize_control_message(BSTR(buffer), &gc)); + + status = process_incoming_push_msg(c, + buffer, + c->options.pull, + pull_permission_mask(c), + &option_types_found); + + if (status == PUSH_MSG_ERROR) + { + msg(D_PUSH_ERRORS, "WARNING: Received bad push/pull message: %s", sanitize_control_message(BSTR(buffer), &gc)); + } + else if (status == PUSH_MSG_REPLY || status == PUSH_MSG_CONTINUATION) + { + c->options.push_option_types_found |= option_types_found; + + /* delay bringing tun/tap up until --push parms received from remote */ + if (status == PUSH_MSG_REPLY) + { + if (!do_up(c, true, c->options.push_option_types_found)) + { + msg(D_PUSH_ERRORS, "Failed to open tun/tap interface"); + goto error; + } + } + event_timeout_clear(&c->c2.push_request_interval); + } + else if (status == PUSH_MSG_REQUEST) + { + if (c->options.mode == MODE_SERVER) + { + struct tls_session *session = &c->c2.tls_multi->session[TM_ACTIVE]; + /* Do not regenerate keys if client send a second push request */ + if (!session->key[KS_PRIMARY].crypto_options.key_ctx_bi.initialized + && !tls_session_update_crypto_params(session, &c->options, + &c->c2.frame)) + { + msg(D_TLS_ERRORS, "TLS Error: initializing data channel failed"); + goto error; + } + } + } + + goto cleanup; error: - register_signal (c, SIGUSR1, "process-push-msg-failed"); + register_signal(c, SIGUSR1, "process-push-msg-failed"); cleanup: - gc_free (&gc); + gc_free(&gc); } bool -send_push_request (struct context *c) +send_push_request(struct context *c) { - const int max_push_requests = c->options.handshake_window / PUSH_REQUEST_INTERVAL; - if (++c->c2.n_sent_push_requests <= max_push_requests) + const int max_push_requests = c->options.handshake_window / PUSH_REQUEST_INTERVAL; + if (++c->c2.n_sent_push_requests <= max_push_requests) { - return send_control_channel_string (c, "PUSH_REQUEST", D_PUSH); + return send_control_channel_string(c, "PUSH_REQUEST", D_PUSH); } - else + else { - msg (D_STREAM_ERRORS, "No reply from server after sending %d push requests", max_push_requests); - c->sig->signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- server-pushed connection reset */ - c->sig->signal_text = "no-push-reply"; - return false; + msg(D_STREAM_ERRORS, "No reply from server after sending %d push requests", max_push_requests); + c->sig->signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- server-pushed connection reset */ + c->sig->signal_text = "no-push-reply"; + return false; } } @@ -297,426 +316,444 @@ send_push_request (struct context *c) /** * Prepare push options, based on local options and available peer info. * - * @param context context structure storing data for VPN tunnel - * @param gc gc arena for allocating push options - * @param push_list push list to where options are added + * @param context context structure storing data for VPN tunnel + * @param gc gc arena for allocating push options + * @param push_list push list to where options are added * * @return true on success, false on failure. */ static bool -prepare_push_reply (struct context *c, struct gc_arena *gc, - struct push_list *push_list) +prepare_push_reply(struct context *c, struct gc_arena *gc, + struct push_list *push_list) { - const char *optstr = NULL; - struct tls_multi *tls_multi = c->c2.tls_multi; - const char * const peer_info = tls_multi->peer_info; - struct options *o = &c->options; - - /* ipv6 */ - if (c->c2.push_ifconfig_ipv6_defined && !o->push_ifconfig_ipv6_blocked) - { - push_option_fmt (gc, push_list, M_USAGE, "ifconfig-ipv6 %s/%d %s", - print_in6_addr (c->c2.push_ifconfig_ipv6_local, 0, gc), - c->c2.push_ifconfig_ipv6_netbits, - print_in6_addr (c->c2.push_ifconfig_ipv6_remote, - 0, gc)); - } - - /* ipv4 */ - if (c->c2.push_ifconfig_defined && c->c2.push_ifconfig_local && - c->c2.push_ifconfig_remote_netmask) - { - in_addr_t ifconfig_local = c->c2.push_ifconfig_local; - if (c->c2.push_ifconfig_local_alias) - ifconfig_local = c->c2.push_ifconfig_local_alias; - push_option_fmt (gc, push_list, M_USAGE, "ifconfig %s %s", - print_in_addr_t (ifconfig_local, 0, gc), - print_in_addr_t (c->c2.push_ifconfig_remote_netmask, - 0, gc)); - } - - /* Send peer-id if client supports it */ - optstr = peer_info ? strstr(peer_info, "IV_PROTO=") : NULL; - if (optstr) - { - int proto = 0; - int r = sscanf(optstr, "IV_PROTO=%d", &proto); - if ((r == 1) && (proto >= 2)) - { - push_option_fmt(gc, push_list, M_USAGE, "peer-id %d", - tls_multi->peer_id); - } - } - - /* Push cipher if client supports Negotiable Crypto Parameters */ - if (tls_peer_info_ncp_ver (peer_info) >= 2 && o->ncp_enabled) - { - /* if we have already created our key, we cannot change our own - * cipher, so disable NCP and warn = explain why - */ - const struct tls_session *session = &tls_multi->session[TM_ACTIVE]; - if ( session->key[KS_PRIMARY].crypto_options.key_ctx_bi.initialized ) - { - msg( M_INFO, "PUSH: client wants to negotiate cipher (NCP), but " - "server has already generated data channel keys, " - "ignoring client request" ); - } - else - { - /* Push the first cipher from --ncp-ciphers to the client. - * TODO: actual negotiation, instead of server dictatorship. */ - char *push_cipher = string_alloc(o->ncp_ciphers, &o->gc); - o->ciphername = strtok (push_cipher, ":"); - push_option_fmt(gc, push_list, M_USAGE, "cipher %s", o->ciphername); - } - } - else if (o->ncp_enabled) - { - tls_poor_mans_ncp (o, tls_multi->remote_ciphername); - } - - /* If server uses --auth-gen-token and we have an auth token - * to send to the client - */ - if (false == tls_multi->auth_token_sent && NULL != tls_multi->auth_token) - { - push_option_fmt(gc, push_list, M_USAGE, - "auth-token %s", tls_multi->auth_token); - tls_multi->auth_token_sent = true; - } - return true; + const char *optstr = NULL; + struct tls_multi *tls_multi = c->c2.tls_multi; + const char *const peer_info = tls_multi->peer_info; + struct options *o = &c->options; + + /* ipv6 */ + if (c->c2.push_ifconfig_ipv6_defined && !o->push_ifconfig_ipv6_blocked) + { + push_option_fmt(gc, push_list, M_USAGE, "ifconfig-ipv6 %s/%d %s", + print_in6_addr(c->c2.push_ifconfig_ipv6_local, 0, gc), + c->c2.push_ifconfig_ipv6_netbits, + print_in6_addr(c->c2.push_ifconfig_ipv6_remote, + 0, gc)); + } + + /* ipv4 */ + if (c->c2.push_ifconfig_defined && c->c2.push_ifconfig_local + && c->c2.push_ifconfig_remote_netmask) + { + in_addr_t ifconfig_local = c->c2.push_ifconfig_local; + if (c->c2.push_ifconfig_local_alias) + { + ifconfig_local = c->c2.push_ifconfig_local_alias; + } + push_option_fmt(gc, push_list, M_USAGE, "ifconfig %s %s", + print_in_addr_t(ifconfig_local, 0, gc), + print_in_addr_t(c->c2.push_ifconfig_remote_netmask, + 0, gc)); + } + + /* Send peer-id if client supports it */ + optstr = peer_info ? strstr(peer_info, "IV_PROTO=") : NULL; + if (optstr) + { + int proto = 0; + int r = sscanf(optstr, "IV_PROTO=%d", &proto); + if ((r == 1) && (proto >= 2)) + { + push_option_fmt(gc, push_list, M_USAGE, "peer-id %d", + tls_multi->peer_id); + } + } + + /* Push cipher if client supports Negotiable Crypto Parameters */ + if (tls_peer_info_ncp_ver(peer_info) >= 2 && o->ncp_enabled) + { + /* if we have already created our key, we cannot change our own + * cipher, so disable NCP and warn = explain why + */ + const struct tls_session *session = &tls_multi->session[TM_ACTIVE]; + if (session->key[KS_PRIMARY].crypto_options.key_ctx_bi.initialized) + { + msg( M_INFO, "PUSH: client wants to negotiate cipher (NCP), but " + "server has already generated data channel keys, " + "ignoring client request" ); + } + else + { + /* Push the first cipher from --ncp-ciphers to the client. + * TODO: actual negotiation, instead of server dictatorship. */ + char *push_cipher = string_alloc(o->ncp_ciphers, &o->gc); + o->ciphername = strtok(push_cipher, ":"); + push_option_fmt(gc, push_list, M_USAGE, "cipher %s", o->ciphername); + } + } + else if (o->ncp_enabled) + { + tls_poor_mans_ncp(o, tls_multi->remote_ciphername); + } + + /* If server uses --auth-gen-token and we have an auth token + * to send to the client + */ + if (false == tls_multi->auth_token_sent && NULL != tls_multi->auth_token) + { + push_option_fmt(gc, push_list, M_USAGE, + "auth-token %s", tls_multi->auth_token); + tls_multi->auth_token_sent = true; + } + return true; } static bool -send_push_options (struct context *c, struct buffer *buf, - struct push_list *push_list, int safe_cap, - bool *push_sent, bool *multi_push) +send_push_options(struct context *c, struct buffer *buf, + struct push_list *push_list, int safe_cap, + bool *push_sent, bool *multi_push) { - struct push_entry *e = push_list->head; - - while (e) - { - if (e->enable) - { - const int l = strlen (e->option); - if (BLEN (buf) + l >= safe_cap) - { - buf_printf (buf, ",push-continuation 2"); - { - const bool status = send_control_channel_string (c, BSTR (buf), D_PUSH); - if (!status) - return false; - *push_sent = true; - *multi_push = true; - buf_reset_len (buf); - buf_printf (buf, "%s", push_reply_cmd); - } - } - if (BLEN (buf) + l >= safe_cap) - { - msg (M_WARN, "--push option is too long"); - return false; - } - buf_printf (buf, ",%s", e->option); - } - e = e->next; - } - return true; + struct push_entry *e = push_list->head; + + while (e) + { + if (e->enable) + { + const int l = strlen(e->option); + if (BLEN(buf) + l >= safe_cap) + { + buf_printf(buf, ",push-continuation 2"); + { + const bool status = send_control_channel_string(c, BSTR(buf), D_PUSH); + if (!status) + { + return false; + } + *push_sent = true; + *multi_push = true; + buf_reset_len(buf); + buf_printf(buf, "%s", push_reply_cmd); + } + } + if (BLEN(buf) + l >= safe_cap) + { + msg(M_WARN, "--push option is too long"); + return false; + } + buf_printf(buf, ",%s", e->option); + } + e = e->next; + } + return true; } static bool -send_push_reply (struct context *c, struct push_list *per_client_push_list) +send_push_reply(struct context *c, struct push_list *per_client_push_list) { - struct gc_arena gc = gc_new (); - struct buffer buf = alloc_buf_gc (PUSH_BUNDLE_SIZE, &gc); - bool multi_push = false; - const int extra = 84; /* extra space for possible trailing ifconfig and push-continuation */ - const int safe_cap = BCAP (&buf) - extra; - bool push_sent = false; - - buf_printf (&buf, "%s", push_reply_cmd); - - /* send options which are common to all clients */ - if (!send_push_options (c, &buf, &c->options.push_list, safe_cap, - &push_sent, &multi_push)) - goto fail; - - /* send client-specific options */ - if (!send_push_options (c, &buf, per_client_push_list, safe_cap, - &push_sent, &multi_push)) - goto fail; - - if (multi_push) - buf_printf (&buf, ",push-continuation 1"); + struct gc_arena gc = gc_new(); + struct buffer buf = alloc_buf_gc(PUSH_BUNDLE_SIZE, &gc); + bool multi_push = false; + const int extra = 84; /* extra space for possible trailing ifconfig and push-continuation */ + const int safe_cap = BCAP(&buf) - extra; + bool push_sent = false; + + buf_printf(&buf, "%s", push_reply_cmd); + + /* send options which are common to all clients */ + if (!send_push_options(c, &buf, &c->options.push_list, safe_cap, + &push_sent, &multi_push)) + { + goto fail; + } - if (BLEN (&buf) > sizeof(push_reply_cmd)-1) + /* send client-specific options */ + if (!send_push_options(c, &buf, per_client_push_list, safe_cap, + &push_sent, &multi_push)) { - const bool status = send_control_channel_string (c, BSTR (&buf), D_PUSH); - if (!status) goto fail; - push_sent = true; } - /* If nothing have been pushed, send an empty push, - * as the client is expecting a response - */ - if (!push_sent) + if (multi_push) { - bool status = false; + buf_printf(&buf, ",push-continuation 1"); + } - buf_reset_len (&buf); - buf_printf (&buf, "%s", push_reply_cmd); - status = send_control_channel_string (c, BSTR(&buf), D_PUSH); - if (!status) - goto fail; + if (BLEN(&buf) > sizeof(push_reply_cmd)-1) + { + const bool status = send_control_channel_string(c, BSTR(&buf), D_PUSH); + if (!status) + { + goto fail; + } + push_sent = true; } - gc_free (&gc); - return true; + /* If nothing have been pushed, send an empty push, + * as the client is expecting a response + */ + if (!push_sent) + { + bool status = false; + + buf_reset_len(&buf); + buf_printf(&buf, "%s", push_reply_cmd); + status = send_control_channel_string(c, BSTR(&buf), D_PUSH); + if (!status) + { + goto fail; + } + } - fail: - gc_free (&gc); - return false; + gc_free(&gc); + return true; + +fail: + gc_free(&gc); + return false; } static void -push_option_ex (struct gc_arena *gc, struct push_list *push_list, - const char *opt, bool enable, int msglevel) +push_option_ex(struct gc_arena *gc, struct push_list *push_list, + const char *opt, bool enable, int msglevel) { - if (!string_class (opt, CC_ANY, CC_COMMA)) - { - msg (msglevel, "PUSH OPTION FAILED (illegal comma (',') in string): '%s'", opt); - } - else - { - struct push_entry *e; - ALLOC_OBJ_CLEAR_GC (e, struct push_entry, gc); - e->enable = true; - e->option = opt; - if (push_list->head) - { - ASSERT(push_list->tail); - push_list->tail->next = e; - push_list->tail = e; - } - else - { - ASSERT(!push_list->tail); - push_list->head = e; - push_list->tail = e; - } + if (!string_class(opt, CC_ANY, CC_COMMA)) + { + msg(msglevel, "PUSH OPTION FAILED (illegal comma (',') in string): '%s'", opt); + } + else + { + struct push_entry *e; + ALLOC_OBJ_CLEAR_GC(e, struct push_entry, gc); + e->enable = true; + e->option = opt; + if (push_list->head) + { + ASSERT(push_list->tail); + push_list->tail->next = e; + push_list->tail = e; + } + else + { + ASSERT(!push_list->tail); + push_list->head = e; + push_list->tail = e; + } } } void -push_option (struct options *o, const char *opt, int msglevel) +push_option(struct options *o, const char *opt, int msglevel) { - push_option_ex (&o->gc, &o->push_list, opt, true, msglevel); + push_option_ex(&o->gc, &o->push_list, opt, true, msglevel); } void -clone_push_list (struct options *o) +clone_push_list(struct options *o) { - if (o->push_list.head) + if (o->push_list.head) { - const struct push_entry *e = o->push_list.head; - push_reset (o); - while (e) - { - push_option_ex (&o->gc, &o->push_list, - string_alloc (e->option, &o->gc), true, M_FATAL); - e = e->next; - } + const struct push_entry *e = o->push_list.head; + push_reset(o); + while (e) + { + push_option_ex(&o->gc, &o->push_list, + string_alloc(e->option, &o->gc), true, M_FATAL); + e = e->next; + } } } void -push_options (struct options *o, char **p, int msglevel, struct gc_arena *gc) +push_options(struct options *o, char **p, int msglevel, struct gc_arena *gc) { - const char **argv = make_extended_arg_array (p, gc); - char *opt = print_argv (argv, gc, 0); - push_option (o, opt, msglevel); + const char **argv = make_extended_arg_array(p, gc); + char *opt = print_argv(argv, gc, 0); + push_option(o, opt, msglevel); } -static bool push_option_fmt(struct gc_arena *gc, struct push_list *push_list, - int msglevel, const char *format, ...) +static bool +push_option_fmt(struct gc_arena *gc, struct push_list *push_list, + int msglevel, const char *format, ...) { - va_list arglist; - char tmp[256] = {0}; - int len; - va_start (arglist, format); - len = vsnprintf (tmp, sizeof(tmp), format, arglist); - va_end (arglist); - if (len > sizeof(tmp)-1) - return false; - push_option_ex (gc, push_list, string_alloc (tmp, gc), true, msglevel); - return true; + va_list arglist; + char tmp[256] = {0}; + int len; + va_start(arglist, format); + len = vsnprintf(tmp, sizeof(tmp), format, arglist); + va_end(arglist); + if (len > sizeof(tmp)-1) + { + return false; + } + push_option_ex(gc, push_list, string_alloc(tmp, gc), true, msglevel); + return true; } void -push_reset (struct options *o) +push_reset(struct options *o) { - CLEAR (o->push_list); + CLEAR(o->push_list); } void -push_remove_option (struct options *o, const char *p) +push_remove_option(struct options *o, const char *p) { - msg (D_PUSH_DEBUG, "PUSH_REMOVE searching for: '%s'", p); + msg(D_PUSH_DEBUG, "PUSH_REMOVE searching for: '%s'", p); - /* ifconfig-ipv6 is special, as not part of the push list */ - if ( streq( p, "ifconfig-ipv6" )) + /* ifconfig-ipv6 is special, as not part of the push list */ + if (streq( p, "ifconfig-ipv6" )) { - o->push_ifconfig_ipv6_blocked = true; - return; + o->push_ifconfig_ipv6_blocked = true; + return; } - if (o && o->push_list.head ) + if (o && o->push_list.head) { - struct push_entry *e = o->push_list.head; - - /* cycle through the push list */ - while (e) - { - if ( e->enable && - strncmp( e->option, p, strlen(p) ) == 0 ) - { - msg (D_PUSH_DEBUG, "PUSH_REMOVE removing: '%s'", e->option); - e->enable = false; - } - - e = e->next; - } + struct push_entry *e = o->push_list.head; + + /* cycle through the push list */ + while (e) + { + if (e->enable + && strncmp( e->option, p, strlen(p) ) == 0) + { + msg(D_PUSH_DEBUG, "PUSH_REMOVE removing: '%s'", e->option); + e->enable = false; + } + + e = e->next; + } } } -#endif +#endif /* if P2MP_SERVER */ #if P2MP_SERVER int -process_incoming_push_request (struct context *c) +process_incoming_push_request(struct context *c) { - int ret = PUSH_MSG_ERROR; + int ret = PUSH_MSG_ERROR; #ifdef ENABLE_ASYNC_PUSH - c->c2.push_request_received = true; + c->c2.push_request_received = true; #endif - if (tls_authentication_status (c->c2.tls_multi, 0) == TLS_AUTHENTICATION_FAILED || c->c2.context_auth == CAS_FAILED) + if (tls_authentication_status(c->c2.tls_multi, 0) == TLS_AUTHENTICATION_FAILED || c->c2.context_auth == CAS_FAILED) { - const char *client_reason = tls_client_reason (c->c2.tls_multi); - send_auth_failed (c, client_reason); - ret = PUSH_MSG_AUTH_FAILURE; + const char *client_reason = tls_client_reason(c->c2.tls_multi); + send_auth_failed(c, client_reason); + ret = PUSH_MSG_AUTH_FAILURE; } - else if (!c->c2.push_reply_deferred && c->c2.context_auth == CAS_SUCCEEDED) + else if (!c->c2.push_reply_deferred && c->c2.context_auth == CAS_SUCCEEDED) { - time_t now; - - openvpn_time (&now); - if (c->c2.sent_push_reply_expiry > now) - { - ret = PUSH_MSG_ALREADY_REPLIED; - } - else - { - /* per-client push options - peer-id, cipher, ifconfig, ipv6-ifconfig */ - struct push_list push_list; - struct gc_arena gc = gc_new (); - - CLEAR (push_list); - if (prepare_push_reply (c, &gc, &push_list) && - send_push_reply (c, &push_list)) - { - ret = PUSH_MSG_REQUEST; - c->c2.sent_push_reply_expiry = now + 30; - } - gc_free(&gc); - } + time_t now; + + openvpn_time(&now); + if (c->c2.sent_push_reply_expiry > now) + { + ret = PUSH_MSG_ALREADY_REPLIED; + } + else + { + /* per-client push options - peer-id, cipher, ifconfig, ipv6-ifconfig */ + struct push_list push_list; + struct gc_arena gc = gc_new(); + + CLEAR(push_list); + if (prepare_push_reply(c, &gc, &push_list) + && send_push_reply(c, &push_list)) + { + ret = PUSH_MSG_REQUEST; + c->c2.sent_push_reply_expiry = now + 30; + } + gc_free(&gc); + } } - else + else { - ret = PUSH_MSG_REQUEST_DEFERRED; + ret = PUSH_MSG_REQUEST_DEFERRED; } - return ret; + return ret; } -#endif +#endif /* if P2MP_SERVER */ static void push_update_digest(md_ctx_t *ctx, struct buffer *buf) { - char line[OPTION_PARM_SIZE]; - while (buf_parse (buf, ',', line, sizeof (line))) + char line[OPTION_PARM_SIZE]; + while (buf_parse(buf, ',', line, sizeof(line))) { - /* peer-id might change on restart and this should not trigger reopening tun */ - if (strstr (line, "peer-id ") != line) - { - md_ctx_update (ctx, (const uint8_t *) line, strlen(line)); - } + /* peer-id might change on restart and this should not trigger reopening tun */ + if (strstr(line, "peer-id ") != line) + { + md_ctx_update(ctx, (const uint8_t *) line, strlen(line)); + } } } int -process_incoming_push_msg (struct context *c, - const struct buffer *buffer, - bool honor_received_options, - unsigned int permission_mask, - unsigned int *option_types_found) +process_incoming_push_msg(struct context *c, + const struct buffer *buffer, + bool honor_received_options, + unsigned int permission_mask, + unsigned int *option_types_found) { - int ret = PUSH_MSG_ERROR; - struct buffer buf = *buffer; + int ret = PUSH_MSG_ERROR; + struct buffer buf = *buffer; #if P2MP_SERVER - if (buf_string_compare_advance (&buf, "PUSH_REQUEST")) + if (buf_string_compare_advance(&buf, "PUSH_REQUEST")) { - ret = process_incoming_push_request(c); + ret = process_incoming_push_request(c); } - else + else #endif - if (honor_received_options && buf_string_compare_advance (&buf, "PUSH_REPLY")) - { - const uint8_t ch = buf_read_u8 (&buf); - if (ch == ',') - { - struct buffer buf_orig = buf; - if (!c->c2.pulled_options_md5_init_done) - { - md_ctx_init(&c->c2.pulled_options_state, md_kt_get("MD5")); - c->c2.pulled_options_md5_init_done = true; - } - if (!c->c2.did_pre_pull_restore) - { - pre_pull_restore (&c->options, &c->c2.gc); - c->c2.did_pre_pull_restore = true; - } - if (apply_push_options (&c->options, - &buf, - permission_mask, - option_types_found, - c->c2.es)) - { - push_update_digest (&c->c2.pulled_options_state, &buf_orig); - switch (c->options.push_continuation) - { - case 0: - case 1: - md_ctx_final (&c->c2.pulled_options_state, c->c2.pulled_options_digest.digest); - md_ctx_cleanup (&c->c2.pulled_options_state); - c->c2.pulled_options_md5_init_done = false; - ret = PUSH_MSG_REPLY; - break; - case 2: - ret = PUSH_MSG_CONTINUATION; - break; - } - } - } - else if (ch == '\0') - { - ret = PUSH_MSG_REPLY; - } - /* show_settings (&c->options); */ - } - return ret; + if (honor_received_options && buf_string_compare_advance(&buf, "PUSH_REPLY")) + { + const uint8_t ch = buf_read_u8(&buf); + if (ch == ',') + { + struct buffer buf_orig = buf; + if (!c->c2.pulled_options_md5_init_done) + { + md_ctx_init(&c->c2.pulled_options_state, md_kt_get("MD5")); + c->c2.pulled_options_md5_init_done = true; + } + if (!c->c2.did_pre_pull_restore) + { + pre_pull_restore(&c->options, &c->c2.gc); + c->c2.did_pre_pull_restore = true; + } + if (apply_push_options(&c->options, + &buf, + permission_mask, + option_types_found, + c->c2.es)) + { + push_update_digest(&c->c2.pulled_options_state, &buf_orig); + switch (c->options.push_continuation) + { + case 0: + case 1: + md_ctx_final(&c->c2.pulled_options_state, c->c2.pulled_options_digest.digest); + md_ctx_cleanup(&c->c2.pulled_options_state); + c->c2.pulled_options_md5_init_done = false; + ret = PUSH_MSG_REPLY; + break; + + case 2: + ret = PUSH_MSG_CONTINUATION; + break; + } + } + } + else if (ch == '\0') + { + ret = PUSH_MSG_REPLY; + } + /* show_settings (&c->options); */ + } + return ret; } #if P2MP_SERVER @@ -725,62 +762,64 @@ process_incoming_push_msg (struct context *c, * Remove iroutes from the push_list. */ void -remove_iroutes_from_push_route_list (struct options *o) +remove_iroutes_from_push_route_list(struct options *o) { - if (o && o->push_list.head && o->iroutes) - { - struct gc_arena gc = gc_new (); - struct push_entry *e = o->push_list.head; - - /* cycle through the push list */ - while (e) - { - char *p[MAX_PARMS]; - bool enable = true; - - /* parse the push item */ - CLEAR (p); - if ( e->enable && - parse_line (e->option, p, SIZE (p), "[PUSH_ROUTE_REMOVE]", 1, D_ROUTE_DEBUG, &gc)) - { - /* is the push item a route directive? */ - if (p[0] && !strcmp (p[0], "route") && !p[3]) - { - /* get route parameters */ - bool status1, status2; - const in_addr_t network = getaddr (GETADDR_HOST_ORDER, p[1], 0, &status1, NULL); - const in_addr_t netmask = getaddr (GETADDR_HOST_ORDER, p[2] ? p[2] : "255.255.255.255", 0, &status2, NULL); - - /* did route parameters parse correctly? */ - if (status1 && status2) - { - const struct iroute *ir; - - /* does route match an iroute? */ - for (ir = o->iroutes; ir != NULL; ir = ir->next) - { - if (network == ir->network && netmask == netbits_to_netmask (ir->netbits >= 0 ? ir->netbits : 32)) - { - enable = false; - break; - } - } - } - } - - /* should we copy the push item? */ - e->enable = enable; - if (!enable) - msg (D_PUSH, "REMOVE PUSH ROUTE: '%s'", e->option); - } - - e = e->next; - } - - gc_free (&gc); + if (o && o->push_list.head && o->iroutes) + { + struct gc_arena gc = gc_new(); + struct push_entry *e = o->push_list.head; + + /* cycle through the push list */ + while (e) + { + char *p[MAX_PARMS]; + bool enable = true; + + /* parse the push item */ + CLEAR(p); + if (e->enable + && parse_line(e->option, p, SIZE(p), "[PUSH_ROUTE_REMOVE]", 1, D_ROUTE_DEBUG, &gc)) + { + /* is the push item a route directive? */ + if (p[0] && !strcmp(p[0], "route") && !p[3]) + { + /* get route parameters */ + bool status1, status2; + const in_addr_t network = getaddr(GETADDR_HOST_ORDER, p[1], 0, &status1, NULL); + const in_addr_t netmask = getaddr(GETADDR_HOST_ORDER, p[2] ? p[2] : "255.255.255.255", 0, &status2, NULL); + + /* did route parameters parse correctly? */ + if (status1 && status2) + { + const struct iroute *ir; + + /* does route match an iroute? */ + for (ir = o->iroutes; ir != NULL; ir = ir->next) + { + if (network == ir->network && netmask == netbits_to_netmask(ir->netbits >= 0 ? ir->netbits : 32)) + { + enable = false; + break; + } + } + } + } + + /* should we copy the push item? */ + e->enable = enable; + if (!enable) + { + msg(D_PUSH, "REMOVE PUSH ROUTE: '%s'", e->option); + } + } + + e = e->next; + } + + gc_free(&gc); } } -#endif +#endif /* if P2MP_SERVER */ -#endif +#endif /* if P2MP */ diff --git a/src/openvpn/push.h b/src/openvpn/push.h index 1dfd80e5b2b..38cf5c1042c 100644 --- a/src/openvpn/push.h +++ b/src/openvpn/push.h @@ -37,37 +37,39 @@ #define PUSH_MSG_CONTINUATION 5 #define PUSH_MSG_ALREADY_REPLIED 6 -int process_incoming_push_request (struct context *c); +int process_incoming_push_request(struct context *c); -int process_incoming_push_msg (struct context *c, - const struct buffer *buffer, - bool honor_received_options, - unsigned int permission_mask, - unsigned int *option_types_found); +int process_incoming_push_msg(struct context *c, + const struct buffer *buffer, + bool honor_received_options, + unsigned int permission_mask, + unsigned int *option_types_found); -bool send_push_request (struct context *c); +bool send_push_request(struct context *c); -void receive_auth_failed (struct context *c, const struct buffer *buffer); +void receive_auth_failed(struct context *c, const struct buffer *buffer); -void server_pushed_signal (struct context *c, const struct buffer *buffer, const bool restart, const int adv); +void server_pushed_signal(struct context *c, const struct buffer *buffer, const bool restart, const int adv); -void incoming_push_message (struct context *c, const struct buffer *buffer); +void incoming_push_message(struct context *c, const struct buffer *buffer); #if P2MP_SERVER -void clone_push_list (struct options *o); +void clone_push_list(struct options *o); -void push_option (struct options *o, const char *opt, int msglevel); -void push_options (struct options *o, char **p, int msglevel, struct gc_arena *gc); +void push_option(struct options *o, const char *opt, int msglevel); -void push_reset (struct options *o); -void push_remove_option (struct options *o, const char *p); +void push_options(struct options *o, char **p, int msglevel, struct gc_arena *gc); -void remove_iroutes_from_push_route_list (struct options *o); +void push_reset(struct options *o); -void send_auth_failed (struct context *c, const char *client_reason); +void push_remove_option(struct options *o, const char *p); -void send_restart (struct context *c, const char *kill_msg); +void remove_iroutes_from_push_route_list(struct options *o); + +void send_auth_failed(struct context *c, const char *client_reason); + +void send_restart(struct context *c, const char *kill_msg); #endif -#endif -#endif +#endif /* if P2MP */ +#endif /* ifndef PUSH_H */ diff --git a/src/openvpn/pushlist.h b/src/openvpn/pushlist.h index b2526761ec5..5471b1b2305 100644 --- a/src/openvpn/pushlist.h +++ b/src/openvpn/pushlist.h @@ -28,14 +28,14 @@ /* parameters to be pushed to peer */ struct push_entry { - struct push_entry *next; - bool enable; - const char *option; + struct push_entry *next; + bool enable; + const char *option; }; struct push_list { - struct push_entry *head; - struct push_entry *tail; + struct push_entry *head; + struct push_entry *tail; }; diff --git a/src/openvpn/reliable.c b/src/openvpn/reliable.c index 22883a725aa..36719166d8b 100644 --- a/src/openvpn/reliable.c +++ b/src/openvpn/reliable.c @@ -48,226 +48,256 @@ * verify that test - base < extent while allowing for base or test wraparound */ static inline bool -reliable_pid_in_range1 (const packet_id_type test, - const packet_id_type base, - const unsigned int extent) +reliable_pid_in_range1(const packet_id_type test, + const packet_id_type base, + const unsigned int extent) { - if (test >= base) + if (test >= base) { - if (test - base < extent) - return true; + if (test - base < extent) + { + return true; + } } - else + else { - if ((test+0x80000000u) - (base+0x80000000u) < extent) - return true; + if ((test+0x80000000u) - (base+0x80000000u) < extent) + { + return true; + } } - return false; + return false; } /* * verify that test < base + extent while allowing for base or test wraparound */ static inline bool -reliable_pid_in_range2 (const packet_id_type test, - const packet_id_type base, - const unsigned int extent) +reliable_pid_in_range2(const packet_id_type test, + const packet_id_type base, + const unsigned int extent) { - if (base + extent >= base) + if (base + extent >= base) { - if (test < base + extent) - return true; + if (test < base + extent) + { + return true; + } } - else + else { - if ((test+0x80000000u) < (base+0x80000000u) + extent) - return true; + if ((test+0x80000000u) < (base+0x80000000u) + extent) + { + return true; + } } - return false; + return false; } /* * verify that p1 < p2 while allowing for p1 or p2 wraparound */ static inline bool -reliable_pid_min (const packet_id_type p1, - const packet_id_type p2) +reliable_pid_min(const packet_id_type p1, + const packet_id_type p2) { - return !reliable_pid_in_range1 (p1, p2, 0x80000000u); + return !reliable_pid_in_range1(p1, p2, 0x80000000u); } /* check if a particular packet_id is present in ack */ static inline bool -reliable_ack_packet_id_present (struct reliable_ack *ack, packet_id_type pid) +reliable_ack_packet_id_present(struct reliable_ack *ack, packet_id_type pid) { - int i; - for (i = 0; i < ack->len; ++i) - if (ack->packet_id[i] == pid) - return true; - return false; + int i; + for (i = 0; i < ack->len; ++i) + if (ack->packet_id[i] == pid) + { + return true; + } + return false; } /* get a packet_id from buf */ bool -reliable_ack_read_packet_id (struct buffer *buf, packet_id_type *pid) +reliable_ack_read_packet_id(struct buffer *buf, packet_id_type *pid) { - packet_id_type net_pid; + packet_id_type net_pid; - if (buf_read (buf, &net_pid, sizeof (net_pid))) + if (buf_read(buf, &net_pid, sizeof(net_pid))) { - *pid = ntohpid (net_pid); - dmsg (D_REL_DEBUG, "ACK read ID " packet_id_format " (buf->len=%d)", - (packet_id_print_type)*pid, buf->len); - return true; + *pid = ntohpid(net_pid); + dmsg(D_REL_DEBUG, "ACK read ID " packet_id_format " (buf->len=%d)", + (packet_id_print_type)*pid, buf->len); + return true; } - dmsg (D_REL_LOW, "ACK read ID FAILED (buf->len=%d)", buf->len); - return false; + dmsg(D_REL_LOW, "ACK read ID FAILED (buf->len=%d)", buf->len); + return false; } /* acknowledge a packet_id by adding it to a struct reliable_ack */ bool -reliable_ack_acknowledge_packet_id (struct reliable_ack *ack, packet_id_type pid) +reliable_ack_acknowledge_packet_id(struct reliable_ack *ack, packet_id_type pid) { - if (!reliable_ack_packet_id_present (ack, pid) && ack->len < RELIABLE_ACK_SIZE) + if (!reliable_ack_packet_id_present(ack, pid) && ack->len < RELIABLE_ACK_SIZE) { - ack->packet_id[ack->len++] = pid; - dmsg (D_REL_DEBUG, "ACK acknowledge ID " packet_id_format " (ack->len=%d)", - (packet_id_print_type)pid, ack->len); - return true; + ack->packet_id[ack->len++] = pid; + dmsg(D_REL_DEBUG, "ACK acknowledge ID " packet_id_format " (ack->len=%d)", + (packet_id_print_type)pid, ack->len); + return true; } - dmsg (D_REL_LOW, "ACK acknowledge ID " packet_id_format " FAILED (ack->len=%d)", - (packet_id_print_type)pid, ack->len); - return false; + dmsg(D_REL_LOW, "ACK acknowledge ID " packet_id_format " FAILED (ack->len=%d)", + (packet_id_print_type)pid, ack->len); + return false; } /* read a packet ID acknowledgement record from buf into ack */ bool -reliable_ack_read (struct reliable_ack * ack, - struct buffer * buf, const struct session_id * sid) +reliable_ack_read(struct reliable_ack *ack, + struct buffer *buf, const struct session_id *sid) { - struct gc_arena gc = gc_new (); - int i; - uint8_t count; - packet_id_type net_pid; - packet_id_type pid; - struct session_id session_id_remote; - - if (!buf_read (buf, &count, sizeof (count))) - goto error; - for (i = 0; i < count; ++i) - { - if (!buf_read (buf, &net_pid, sizeof (net_pid))) - goto error; - if (ack->len >= RELIABLE_ACK_SIZE) - goto error; - pid = ntohpid (net_pid); - ack->packet_id[ack->len++] = pid; - } - if (count) - { - if (!session_id_read (&session_id_remote, buf)) - goto error; - if (!session_id_defined (&session_id_remote) || - !session_id_equal (&session_id_remote, sid)) - { - dmsg (D_REL_LOW, - "ACK read BAD SESSION-ID FROM REMOTE, local=%s, remote=%s", - session_id_print (sid, &gc), session_id_print (&session_id_remote, &gc)); - goto error; - } - } - gc_free (&gc); - return true; + struct gc_arena gc = gc_new(); + int i; + uint8_t count; + packet_id_type net_pid; + packet_id_type pid; + struct session_id session_id_remote; + + if (!buf_read(buf, &count, sizeof(count))) + { + goto error; + } + for (i = 0; i < count; ++i) + { + if (!buf_read(buf, &net_pid, sizeof(net_pid))) + { + goto error; + } + if (ack->len >= RELIABLE_ACK_SIZE) + { + goto error; + } + pid = ntohpid(net_pid); + ack->packet_id[ack->len++] = pid; + } + if (count) + { + if (!session_id_read(&session_id_remote, buf)) + { + goto error; + } + if (!session_id_defined(&session_id_remote) + || !session_id_equal(&session_id_remote, sid)) + { + dmsg(D_REL_LOW, + "ACK read BAD SESSION-ID FROM REMOTE, local=%s, remote=%s", + session_id_print(sid, &gc), session_id_print(&session_id_remote, &gc)); + goto error; + } + } + gc_free(&gc); + return true; error: - gc_free (&gc); - return false; + gc_free(&gc); + return false; } -#define ACK_SIZE(n) (sizeof (uint8_t) + ((n) ? SID_SIZE : 0) + sizeof (packet_id_type) * (n)) +#define ACK_SIZE(n) (sizeof(uint8_t) + ((n) ? SID_SIZE : 0) + sizeof(packet_id_type) * (n)) /* write a packet ID acknowledgement record to buf, */ /* removing all acknowledged entries from ack */ bool -reliable_ack_write (struct reliable_ack * ack, - struct buffer * buf, - const struct session_id * sid, int max, bool prepend) +reliable_ack_write(struct reliable_ack *ack, + struct buffer *buf, + const struct session_id *sid, int max, bool prepend) { - int i, j; - uint8_t n; - struct buffer sub; + int i, j; + uint8_t n; + struct buffer sub; - n = ack->len; - if (n > max) - n = max; - sub = buf_sub (buf, ACK_SIZE(n), prepend); - if (!BDEF (&sub)) - goto error; - ASSERT (buf_write (&sub, &n, sizeof (n))); - for (i = 0; i < n; ++i) + n = ack->len; + if (n > max) { - packet_id_type pid = ack->packet_id[i]; - packet_id_type net_pid = htonpid (pid); - ASSERT (buf_write (&sub, &net_pid, sizeof (net_pid))); - dmsg (D_REL_DEBUG, "ACK write ID " packet_id_format " (ack->len=%d, n=%d)", (packet_id_print_type)pid, ack->len, n); + n = max; } - if (n) + sub = buf_sub(buf, ACK_SIZE(n), prepend); + if (!BDEF(&sub)) { - ASSERT (session_id_defined (sid)); - ASSERT (session_id_write (sid, &sub)); - for (i = 0, j = n; j < ack->len;) - ack->packet_id[i++] = ack->packet_id[j++]; - ack->len = i; + goto error; + } + ASSERT(buf_write(&sub, &n, sizeof(n))); + for (i = 0; i < n; ++i) + { + packet_id_type pid = ack->packet_id[i]; + packet_id_type net_pid = htonpid(pid); + ASSERT(buf_write(&sub, &net_pid, sizeof(net_pid))); + dmsg(D_REL_DEBUG, "ACK write ID " packet_id_format " (ack->len=%d, n=%d)", (packet_id_print_type)pid, ack->len, n); + } + if (n) + { + ASSERT(session_id_defined(sid)); + ASSERT(session_id_write(sid, &sub)); + for (i = 0, j = n; j < ack->len; ) + ack->packet_id[i++] = ack->packet_id[j++]; + ack->len = i; } - return true; + return true; error: - return false; + return false; } /* add to extra_frame the maximum number of bytes we will need for reliable_ack_write */ void -reliable_ack_adjust_frame_parameters (struct frame* frame, int max) +reliable_ack_adjust_frame_parameters(struct frame *frame, int max) { - frame_add_to_extra_frame (frame, ACK_SIZE (max)); + frame_add_to_extra_frame(frame, ACK_SIZE(max)); } /* print a reliable ACK record coming off the wire */ const char * -reliable_ack_print (struct buffer *buf, bool verbose, struct gc_arena *gc) +reliable_ack_print(struct buffer *buf, bool verbose, struct gc_arena *gc) { - int i; - uint8_t n_ack; - struct session_id sid_ack; - packet_id_type pid; - struct buffer out = alloc_buf_gc (256, gc); + int i; + uint8_t n_ack; + struct session_id sid_ack; + packet_id_type pid; + struct buffer out = alloc_buf_gc(256, gc); - buf_printf (&out, "["); - if (!buf_read (buf, &n_ack, sizeof (n_ack))) - goto done; - for (i = 0; i < n_ack; ++i) + buf_printf(&out, "["); + if (!buf_read(buf, &n_ack, sizeof(n_ack))) { - if (!buf_read (buf, &pid, sizeof (pid))) - goto done; - pid = ntohpid (pid); - buf_printf (&out, " " packet_id_format, (packet_id_print_type)pid); + goto done; } - if (n_ack) + for (i = 0; i < n_ack; ++i) { - if (!session_id_read (&sid_ack, buf)) - goto done; - if (verbose) - buf_printf (&out, " sid=%s", session_id_print (&sid_ack, gc)); + if (!buf_read(buf, &pid, sizeof(pid))) + { + goto done; + } + pid = ntohpid(pid); + buf_printf(&out, " " packet_id_format, (packet_id_print_type)pid); + } + if (n_ack) + { + if (!session_id_read(&sid_ack, buf)) + { + goto done; + } + if (verbose) + { + buf_printf(&out, " sid=%s", session_id_print(&sid_ack, gc)); + } } - done: - buf_printf (&out, " ]"); - return BSTR (&out); +done: + buf_printf(&out, " ]"); + return BSTR(&out); } /* @@ -275,362 +305,378 @@ reliable_ack_print (struct buffer *buf, bool verbose, struct gc_arena *gc) */ void -reliable_init (struct reliable *rel, int buf_size, int offset, int array_size, bool hold) +reliable_init(struct reliable *rel, int buf_size, int offset, int array_size, bool hold) { - int i; + int i; - CLEAR (*rel); - ASSERT (array_size > 0 && array_size <= RELIABLE_CAPACITY); - rel->hold = hold; - rel->size = array_size; - rel->offset = offset; - for (i = 0; i < rel->size; ++i) + CLEAR(*rel); + ASSERT(array_size > 0 && array_size <= RELIABLE_CAPACITY); + rel->hold = hold; + rel->size = array_size; + rel->offset = offset; + for (i = 0; i < rel->size; ++i) { - struct reliable_entry *e = &rel->array[i]; - e->buf = alloc_buf (buf_size); - ASSERT (buf_init (&e->buf, offset)); + struct reliable_entry *e = &rel->array[i]; + e->buf = alloc_buf(buf_size); + ASSERT(buf_init(&e->buf, offset)); } } void -reliable_free (struct reliable *rel) +reliable_free(struct reliable *rel) { - int i; - for (i = 0; i < rel->size; ++i) + int i; + for (i = 0; i < rel->size; ++i) { - struct reliable_entry *e = &rel->array[i]; - free_buf (&e->buf); + struct reliable_entry *e = &rel->array[i]; + free_buf(&e->buf); } } /* no active buffers? */ bool -reliable_empty (const struct reliable *rel) +reliable_empty(const struct reliable *rel) { - int i; - for (i = 0; i < rel->size; ++i) + int i; + for (i = 0; i < rel->size; ++i) { - const struct reliable_entry *e = &rel->array[i]; - if (e->active) - return false; + const struct reliable_entry *e = &rel->array[i]; + if (e->active) + { + return false; + } } - return true; + return true; } /* del acknowledged items from send buf */ void -reliable_send_purge (struct reliable *rel, struct reliable_ack *ack) +reliable_send_purge(struct reliable *rel, struct reliable_ack *ack) { - int i, j; - for (i = 0; i < ack->len; ++i) - { - packet_id_type pid = ack->packet_id[i]; - for (j = 0; j < rel->size; ++j) - { - struct reliable_entry *e = &rel->array[j]; - if (e->active && e->packet_id == pid) - { - dmsg (D_REL_DEBUG, - "ACK received for pid " packet_id_format ", deleting from send buffer", - (packet_id_print_type)pid); + int i, j; + for (i = 0; i < ack->len; ++i) + { + packet_id_type pid = ack->packet_id[i]; + for (j = 0; j < rel->size; ++j) + { + struct reliable_entry *e = &rel->array[j]; + if (e->active && e->packet_id == pid) + { + dmsg(D_REL_DEBUG, + "ACK received for pid " packet_id_format ", deleting from send buffer", + (packet_id_print_type)pid); #if 0 - /* DEBUGGING -- how close were we timing out on ACK failure and resending? */ - { - if (e->next_try) - { - const interval_t wake = e->next_try - now; - msg (M_INFO, "ACK " packet_id_format ", wake=%d", pid, wake); - } - } + /* DEBUGGING -- how close were we timing out on ACK failure and resending? */ + { + if (e->next_try) + { + const interval_t wake = e->next_try - now; + msg(M_INFO, "ACK " packet_id_format ", wake=%d", pid, wake); + } + } #endif - e->active = false; - break; - } - } + e->active = false; + break; + } + } } } /* print the current sequence of active packet IDs */ static const char * -reliable_print_ids (const struct reliable *rel, struct gc_arena *gc) +reliable_print_ids(const struct reliable *rel, struct gc_arena *gc) { - struct buffer out = alloc_buf_gc (256, gc); - int i; + struct buffer out = alloc_buf_gc(256, gc); + int i; - buf_printf (&out, "[" packet_id_format "]", (packet_id_print_type)rel->packet_id); - for (i = 0; i < rel->size; ++i) + buf_printf(&out, "[" packet_id_format "]", (packet_id_print_type)rel->packet_id); + for (i = 0; i < rel->size; ++i) { - const struct reliable_entry *e = &rel->array[i]; - if (e->active) - buf_printf (&out, " " packet_id_format, (packet_id_print_type)e->packet_id); + const struct reliable_entry *e = &rel->array[i]; + if (e->active) + { + buf_printf(&out, " " packet_id_format, (packet_id_print_type)e->packet_id); + } } - return BSTR (&out); + return BSTR(&out); } /* true if at least one free buffer available */ bool -reliable_can_get (const struct reliable *rel) +reliable_can_get(const struct reliable *rel) { - struct gc_arena gc = gc_new (); - int i; - for (i = 0; i < rel->size; ++i) - { - const struct reliable_entry *e = &rel->array[i]; - if (!e->active) - return true; - } - dmsg (D_REL_LOW, "ACK no free receive buffer available: %s", reliable_print_ids (rel, &gc)); - gc_free (&gc); - return false; + struct gc_arena gc = gc_new(); + int i; + for (i = 0; i < rel->size; ++i) + { + const struct reliable_entry *e = &rel->array[i]; + if (!e->active) + { + return true; + } + } + dmsg(D_REL_LOW, "ACK no free receive buffer available: %s", reliable_print_ids(rel, &gc)); + gc_free(&gc); + return false; } /* make sure that incoming packet ID isn't a replay */ bool -reliable_not_replay (const struct reliable *rel, packet_id_type id) +reliable_not_replay(const struct reliable *rel, packet_id_type id) { - struct gc_arena gc = gc_new (); - int i; - if (reliable_pid_min (id, rel->packet_id)) - goto bad; - for (i = 0; i < rel->size; ++i) + struct gc_arena gc = gc_new(); + int i; + if (reliable_pid_min(id, rel->packet_id)) { - const struct reliable_entry *e = &rel->array[i]; - if (e->active && e->packet_id == id) - goto bad; + goto bad; } - gc_free (&gc); - return true; + for (i = 0; i < rel->size; ++i) + { + const struct reliable_entry *e = &rel->array[i]; + if (e->active && e->packet_id == id) + { + goto bad; + } + } + gc_free(&gc); + return true; - bad: - dmsg (D_REL_DEBUG, "ACK " packet_id_format " is a replay: %s", (packet_id_print_type)id, reliable_print_ids (rel, &gc)); - gc_free (&gc); - return false; +bad: + dmsg(D_REL_DEBUG, "ACK " packet_id_format " is a replay: %s", (packet_id_print_type)id, reliable_print_ids(rel, &gc)); + gc_free(&gc); + return false; } /* make sure that incoming packet ID won't deadlock the receive buffer */ bool -reliable_wont_break_sequentiality (const struct reliable *rel, packet_id_type id) +reliable_wont_break_sequentiality(const struct reliable *rel, packet_id_type id) { - struct gc_arena gc = gc_new (); + struct gc_arena gc = gc_new(); - const int ret = reliable_pid_in_range2 (id, rel->packet_id, rel->size); + const int ret = reliable_pid_in_range2(id, rel->packet_id, rel->size); - if (!ret) + if (!ret) { - dmsg (D_REL_LOW, "ACK " packet_id_format " breaks sequentiality: %s", - (packet_id_print_type)id, reliable_print_ids (rel, &gc)); + dmsg(D_REL_LOW, "ACK " packet_id_format " breaks sequentiality: %s", + (packet_id_print_type)id, reliable_print_ids(rel, &gc)); } - dmsg (D_REL_DEBUG, "ACK RWBS rel->size=%d rel->packet_id=%08x id=%08x ret=%d\n", rel->size, rel->packet_id, id, ret); + dmsg(D_REL_DEBUG, "ACK RWBS rel->size=%d rel->packet_id=%08x id=%08x ret=%d\n", rel->size, rel->packet_id, id, ret); - gc_free (&gc); - return ret; + gc_free(&gc); + return ret; } /* grab a free buffer */ struct buffer * -reliable_get_buf (struct reliable *rel) +reliable_get_buf(struct reliable *rel) { - int i; - for (i = 0; i < rel->size; ++i) + int i; + for (i = 0; i < rel->size; ++i) { - struct reliable_entry *e = &rel->array[i]; - if (!e->active) - { - ASSERT (buf_init (&e->buf, rel->offset)); - return &e->buf; - } + struct reliable_entry *e = &rel->array[i]; + if (!e->active) + { + ASSERT(buf_init(&e->buf, rel->offset)); + return &e->buf; + } } - return NULL; + return NULL; } /* grab a free buffer, fail if buffer clogged by unacknowledged low packet IDs */ struct buffer * -reliable_get_buf_output_sequenced (struct reliable *rel) +reliable_get_buf_output_sequenced(struct reliable *rel) { - struct gc_arena gc = gc_new (); - int i; - packet_id_type min_id = 0; - bool min_id_defined = false; - struct buffer *ret = NULL; + struct gc_arena gc = gc_new(); + int i; + packet_id_type min_id = 0; + bool min_id_defined = false; + struct buffer *ret = NULL; - /* find minimum active packet_id */ - for (i = 0; i < rel->size; ++i) + /* find minimum active packet_id */ + for (i = 0; i < rel->size; ++i) { - const struct reliable_entry *e = &rel->array[i]; - if (e->active) - { - if (!min_id_defined || reliable_pid_min (e->packet_id, min_id)) - { - min_id_defined = true; - min_id = e->packet_id; - } - } + const struct reliable_entry *e = &rel->array[i]; + if (e->active) + { + if (!min_id_defined || reliable_pid_min(e->packet_id, min_id)) + { + min_id_defined = true; + min_id = e->packet_id; + } + } } - if (!min_id_defined || reliable_pid_in_range1 (rel->packet_id, min_id, rel->size)) + if (!min_id_defined || reliable_pid_in_range1(rel->packet_id, min_id, rel->size)) { - ret = reliable_get_buf (rel); + ret = reliable_get_buf(rel); } - else + else { - dmsg (D_REL_LOW, "ACK output sequence broken: %s", reliable_print_ids (rel, &gc)); + dmsg(D_REL_LOW, "ACK output sequence broken: %s", reliable_print_ids(rel, &gc)); } - gc_free (&gc); - return ret; + gc_free(&gc); + return ret; } /* get active buffer for next sequentially increasing key ID */ struct buffer * -reliable_get_buf_sequenced (struct reliable *rel) +reliable_get_buf_sequenced(struct reliable *rel) { - int i; - for (i = 0; i < rel->size; ++i) + int i; + for (i = 0; i < rel->size; ++i) { - struct reliable_entry *e = &rel->array[i]; - if (e->active && e->packet_id == rel->packet_id) - { - return &e->buf; - } + struct reliable_entry *e = &rel->array[i]; + if (e->active && e->packet_id == rel->packet_id) + { + return &e->buf; + } } - return NULL; + return NULL; } /* return true if reliable_send would return a non-NULL result */ bool -reliable_can_send (const struct reliable *rel) +reliable_can_send(const struct reliable *rel) { - struct gc_arena gc = gc_new (); - int i; - int n_active = 0, n_current = 0; - for (i = 0; i < rel->size; ++i) - { - const struct reliable_entry *e = &rel->array[i]; - if (e->active) - { - ++n_active; - if (now >= e->next_try) - ++n_current; - } - } - dmsg (D_REL_DEBUG, "ACK reliable_can_send active=%d current=%d : %s", - n_active, - n_current, - reliable_print_ids (rel, &gc)); - - gc_free (&gc); - return n_current > 0 && !rel->hold; + struct gc_arena gc = gc_new(); + int i; + int n_active = 0, n_current = 0; + for (i = 0; i < rel->size; ++i) + { + const struct reliable_entry *e = &rel->array[i]; + if (e->active) + { + ++n_active; + if (now >= e->next_try) + { + ++n_current; + } + } + } + dmsg(D_REL_DEBUG, "ACK reliable_can_send active=%d current=%d : %s", + n_active, + n_current, + reliable_print_ids(rel, &gc)); + + gc_free(&gc); + return n_current > 0 && !rel->hold; } #ifdef EXPONENTIAL_BACKOFF /* return a unique point-in-time to trigger retry */ static time_t -reliable_unique_retry (struct reliable *rel, time_t retry) +reliable_unique_retry(struct reliable *rel, time_t retry) { - int i; - while (true) - { - for (i = 0; i < rel->size; ++i) - { - struct reliable_entry *e = &rel->array[i]; - if (e->active && e->next_try == retry) - goto again; - } - break; - again: - ++retry; - } - return retry; + int i; + while (true) + { + for (i = 0; i < rel->size; ++i) + { + struct reliable_entry *e = &rel->array[i]; + if (e->active && e->next_try == retry) + { + goto again; + } + } + break; +again: + ++retry; + } + return retry; } -#endif +#endif /* ifdef EXPONENTIAL_BACKOFF */ /* return next buffer to send to remote */ struct buffer * -reliable_send (struct reliable *rel, int *opcode) +reliable_send(struct reliable *rel, int *opcode) { - int i; - struct reliable_entry *best = NULL; - const time_t local_now = now; + int i; + struct reliable_entry *best = NULL; + const time_t local_now = now; - for (i = 0; i < rel->size; ++i) + for (i = 0; i < rel->size; ++i) { - struct reliable_entry *e = &rel->array[i]; - if (e->active && local_now >= e->next_try) - { - if (!best || reliable_pid_min (e->packet_id, best->packet_id)) - best = e; - } + struct reliable_entry *e = &rel->array[i]; + if (e->active && local_now >= e->next_try) + { + if (!best || reliable_pid_min(e->packet_id, best->packet_id)) + { + best = e; + } + } } - if (best) + if (best) { #ifdef EXPONENTIAL_BACKOFF - /* exponential backoff */ - best->next_try = reliable_unique_retry (rel, local_now + best->timeout); - best->timeout *= 2; + /* exponential backoff */ + best->next_try = reliable_unique_retry(rel, local_now + best->timeout); + best->timeout *= 2; #else - /* constant timeout, no backoff */ - best->next_try = local_now + best->timeout; + /* constant timeout, no backoff */ + best->next_try = local_now + best->timeout; #endif - *opcode = best->opcode; - dmsg (D_REL_DEBUG, "ACK reliable_send ID " packet_id_format " (size=%d to=%d)", - (packet_id_print_type)best->packet_id, best->buf.len, - (int)(best->next_try - local_now)); - return &best->buf; + *opcode = best->opcode; + dmsg(D_REL_DEBUG, "ACK reliable_send ID " packet_id_format " (size=%d to=%d)", + (packet_id_print_type)best->packet_id, best->buf.len, + (int)(best->next_try - local_now)); + return &best->buf; } - return NULL; + return NULL; } /* schedule all pending packets for immediate retransmit */ void -reliable_schedule_now (struct reliable *rel) +reliable_schedule_now(struct reliable *rel) { - int i; - dmsg (D_REL_DEBUG, "ACK reliable_schedule_now"); - rel->hold = false; - for (i = 0; i < rel->size; ++i) - { - struct reliable_entry *e = &rel->array[i]; - if (e->active) - { - e->next_try = now; - e->timeout = rel->initial_timeout; - } + int i; + dmsg(D_REL_DEBUG, "ACK reliable_schedule_now"); + rel->hold = false; + for (i = 0; i < rel->size; ++i) + { + struct reliable_entry *e = &rel->array[i]; + if (e->active) + { + e->next_try = now; + e->timeout = rel->initial_timeout; + } } } /* in how many seconds should we wake up to check for timeout */ /* if we return BIG_TIMEOUT, nothing to wait for */ interval_t -reliable_send_timeout (const struct reliable *rel) +reliable_send_timeout(const struct reliable *rel) { - struct gc_arena gc = gc_new (); - interval_t ret = BIG_TIMEOUT; - int i; - const time_t local_now = now; - - for (i = 0; i < rel->size; ++i) - { - const struct reliable_entry *e = &rel->array[i]; - if (e->active) - { - if (e->next_try <= local_now) - { - ret = 0; - break; - } - else - { - ret = min_int (ret, e->next_try - local_now); - } - } - } - - dmsg (D_REL_DEBUG, "ACK reliable_send_timeout %d %s", - (int) ret, - reliable_print_ids (rel, &gc)); - - gc_free (&gc); - return ret; + struct gc_arena gc = gc_new(); + interval_t ret = BIG_TIMEOUT; + int i; + const time_t local_now = now; + + for (i = 0; i < rel->size; ++i) + { + const struct reliable_entry *e = &rel->array[i]; + if (e->active) + { + if (e->next_try <= local_now) + { + ret = 0; + break; + } + else + { + ret = min_int(ret, e->next_try - local_now); + } + } + } + + dmsg(D_REL_DEBUG, "ACK reliable_send_timeout %d %s", + (int) ret, + reliable_print_ids(rel, &gc)); + + gc_free(&gc); + return ret; } /* @@ -638,31 +684,31 @@ reliable_send_timeout (const struct reliable *rel) */ void -reliable_mark_active_incoming (struct reliable *rel, struct buffer *buf, - packet_id_type pid, int opcode) +reliable_mark_active_incoming(struct reliable *rel, struct buffer *buf, + packet_id_type pid, int opcode) { - int i; - for (i = 0; i < rel->size; ++i) + int i; + for (i = 0; i < rel->size; ++i) { - struct reliable_entry *e = &rel->array[i]; - if (buf == &e->buf) - { - e->active = true; + struct reliable_entry *e = &rel->array[i]; + if (buf == &e->buf) + { + e->active = true; - /* packets may not arrive in sequential order */ - e->packet_id = pid; + /* packets may not arrive in sequential order */ + e->packet_id = pid; - /* check for replay */ - ASSERT (!reliable_pid_min (pid, rel->packet_id)); + /* check for replay */ + ASSERT(!reliable_pid_min(pid, rel->packet_id)); - e->opcode = opcode; - e->next_try = 0; - e->timeout = 0; - dmsg (D_REL_DEBUG, "ACK mark active incoming ID " packet_id_format, (packet_id_print_type)e->packet_id); - return; - } + e->opcode = opcode; + e->next_try = 0; + e->timeout = 0; + dmsg(D_REL_DEBUG, "ACK mark active incoming ID " packet_id_format, (packet_id_print_type)e->packet_id); + return; + } } - ASSERT (0); /* buf not found in rel */ + ASSERT(0); /* buf not found in rel */ } /* @@ -670,88 +716,92 @@ reliable_mark_active_incoming (struct reliable *rel, struct buffer *buf, */ void -reliable_mark_active_outgoing (struct reliable *rel, struct buffer *buf, int opcode) +reliable_mark_active_outgoing(struct reliable *rel, struct buffer *buf, int opcode) { - int i; - for (i = 0; i < rel->size; ++i) - { - struct reliable_entry *e = &rel->array[i]; - if (buf == &e->buf) - { - /* Write mode, increment packet_id (i.e. sequence number) - linearly and prepend id to packet */ - packet_id_type net_pid; - e->packet_id = rel->packet_id++; - net_pid = htonpid (e->packet_id); - ASSERT (buf_write_prepend (buf, &net_pid, sizeof (net_pid))); - e->active = true; - e->opcode = opcode; - e->next_try = 0; - e->timeout = rel->initial_timeout; - dmsg (D_REL_DEBUG, "ACK mark active outgoing ID " packet_id_format, (packet_id_print_type)e->packet_id); - return; - } - } - ASSERT (0); /* buf not found in rel */ + int i; + for (i = 0; i < rel->size; ++i) + { + struct reliable_entry *e = &rel->array[i]; + if (buf == &e->buf) + { + /* Write mode, increment packet_id (i.e. sequence number) + * linearly and prepend id to packet */ + packet_id_type net_pid; + e->packet_id = rel->packet_id++; + net_pid = htonpid(e->packet_id); + ASSERT(buf_write_prepend(buf, &net_pid, sizeof(net_pid))); + e->active = true; + e->opcode = opcode; + e->next_try = 0; + e->timeout = rel->initial_timeout; + dmsg(D_REL_DEBUG, "ACK mark active outgoing ID " packet_id_format, (packet_id_print_type)e->packet_id); + return; + } + } + ASSERT(0); /* buf not found in rel */ } /* delete a buffer previously activated by reliable_mark_active() */ void -reliable_mark_deleted (struct reliable *rel, struct buffer *buf, bool inc_pid) +reliable_mark_deleted(struct reliable *rel, struct buffer *buf, bool inc_pid) { - int i; - for (i = 0; i < rel->size; ++i) - { - struct reliable_entry *e = &rel->array[i]; - if (buf == &e->buf) - { - e->active = false; - if (inc_pid) - rel->packet_id = e->packet_id + 1; - return; - } - } - ASSERT (0); + int i; + for (i = 0; i < rel->size; ++i) + { + struct reliable_entry *e = &rel->array[i]; + if (buf == &e->buf) + { + e->active = false; + if (inc_pid) + { + rel->packet_id = e->packet_id + 1; + } + return; + } + } + ASSERT(0); } #if 0 void -reliable_ack_debug_print (const struct reliable_ack *ack, char *desc) +reliable_ack_debug_print(const struct reliable_ack *ack, char *desc) { - int i; + int i; - printf ("********* struct reliable_ack %s\n", desc); - for (i = 0; i < ack->len; ++i) + printf("********* struct reliable_ack %s\n", desc); + for (i = 0; i < ack->len; ++i) { - printf (" %d: " packet_id_format "\n", i, (packet_id_print_type) ack->packet_id[i]); + printf(" %d: " packet_id_format "\n", i, (packet_id_print_type) ack->packet_id[i]); } } void -reliable_debug_print (const struct reliable *rel, char *desc) +reliable_debug_print(const struct reliable *rel, char *desc) { - int i; - update_time (); - - printf ("********* struct reliable %s\n", desc); - printf (" initial_timeout=%d\n", (int)rel->initial_timeout); - printf (" packet_id=" packet_id_format "\n", rel->packet_id); - printf (" now=" time_format "\n", now); - for (i = 0; i < rel->size; ++i) - { - const struct reliable_entry *e = &rel->array[i]; - if (e->active) - { - printf (" %d: packet_id=" packet_id_format " len=%d", i, e->packet_id, e->buf.len); - printf (" next_try=" time_format, e->next_try); - printf ("\n"); - } + int i; + update_time(); + + printf("********* struct reliable %s\n", desc); + printf(" initial_timeout=%d\n", (int)rel->initial_timeout); + printf(" packet_id=" packet_id_format "\n", rel->packet_id); + printf(" now=" time_format "\n", now); + for (i = 0; i < rel->size; ++i) + { + const struct reliable_entry *e = &rel->array[i]; + if (e->active) + { + printf(" %d: packet_id=" packet_id_format " len=%d", i, e->packet_id, e->buf.len); + printf(" next_try=" time_format, e->next_try); + printf("\n"); + } } } -#endif +#endif /* if 0 */ -#else -static void dummy(void) {} +#else /* ifdef ENABLE_CRYPTO */ +static void +dummy(void) { +} #endif /* ENABLE_CRYPTO */ diff --git a/src/openvpn/reliable.h b/src/openvpn/reliable.h index 828dcd3cccb..84cd1e27a9a 100644 --- a/src/openvpn/reliable.h +++ b/src/openvpn/reliable.h @@ -51,7 +51,7 @@ * be stored in one \c reliable_ack * structure. */ -#define RELIABLE_CAPACITY 8 /**< The maximum number of packets that +#define RELIABLE_CAPACITY 8 /**< The maximum number of packets that * the reliability layer for one VPN * tunnel in one direction can store. */ @@ -61,8 +61,8 @@ */ struct reliable_ack { - int len; - packet_id_type packet_id[RELIABLE_ACK_SIZE]; + int len; + packet_id_type packet_id[RELIABLE_ACK_SIZE]; }; /** @@ -71,12 +71,12 @@ struct reliable_ack */ struct reliable_entry { - bool active; - interval_t timeout; - time_t next_try; - packet_id_type packet_id; - int opcode; - struct buffer buf; + bool active; + interval_t timeout; + time_t next_try; + packet_id_type packet_id; + int opcode; + struct buffer buf; }; /** @@ -85,12 +85,12 @@ struct reliable_entry */ struct reliable { - int size; - interval_t initial_timeout; - packet_id_type packet_id; - int offset; - bool hold; /* don't xmit until reliable_schedule_now is called */ - struct reliable_entry array[RELIABLE_CAPACITY]; + int size; + interval_t initial_timeout; + packet_id_type packet_id; + int offset; + bool hold; /* don't xmit until reliable_schedule_now is called */ + struct reliable_entry array[RELIABLE_CAPACITY]; }; @@ -116,8 +116,8 @@ struct reliable * @li True, if processing was successful. * @li False, if an error occurs during processing. */ -bool reliable_ack_read (struct reliable_ack *ack, - struct buffer *buf, const struct session_id *sid); +bool reliable_ack_read(struct reliable_ack *ack, + struct buffer *buf, const struct session_id *sid); /** * Remove acknowledged packets from a reliable structure. @@ -126,7 +126,7 @@ bool reliable_ack_read (struct reliable_ack *ack, * @param ack The acknowledgment structure containing received * acknowledgments. */ -void reliable_send_purge (struct reliable *rel, struct reliable_ack *ack); +void reliable_send_purge(struct reliable *rel, struct reliable_ack *ack); /** @} name Functions for processing incoming acknowledgments */ @@ -146,9 +146,9 @@ void reliable_send_purge (struct reliable *rel, struct reliable_ack *ack); * @li False, if there are packet IDs to be acknowledged. */ static inline bool -reliable_ack_empty (struct reliable_ack *ack) +reliable_ack_empty(struct reliable_ack *ack) { - return !ack->len; + return !ack->len; } /** @@ -169,9 +169,9 @@ reliable_ack_empty (struct reliable_ack *ack) * @li True, if processing was successful. * @li False, if an error occurs during processing. */ -bool reliable_ack_write (struct reliable_ack *ack, - struct buffer *buf, - const struct session_id *sid, int max, bool prepend); +bool reliable_ack_write(struct reliable_ack *ack, + struct buffer *buf, + const struct session_id *sid, int max, bool prepend); /** @} name Functions for processing outgoing acknowledgments */ @@ -192,17 +192,17 @@ bool reliable_ack_write (struct reliable_ack *ack, * structure can store simultaneously. * @param hold description */ -void reliable_init (struct reliable *rel, int buf_size, int offset, int array_size, bool hold); +void reliable_init(struct reliable *rel, int buf_size, int offset, int array_size, bool hold); /** * Free allocated memory associated with a reliable structure. * * @param rel The reliable structured to clean up. */ -void reliable_free (struct reliable *rel); +void reliable_free(struct reliable *rel); /* add to extra_frame the maximum number of bytes we will need for reliable_ack_write */ -void reliable_ack_adjust_frame_parameters (struct frame* frame, int max); +void reliable_ack_adjust_frame_parameters(struct frame *frame, int max); /** @} name Functions for initialization and cleanup */ @@ -221,7 +221,7 @@ void reliable_ack_adjust_frame_parameters (struct frame* frame, int max); * @li True, if at least one buffer is available for use. * @li False, if all the buffers are active. */ -bool reliable_can_get (const struct reliable *rel); +bool reliable_can_get(const struct reliable *rel); /** * Check that a received packet's ID is not a replay. @@ -234,7 +234,7 @@ bool reliable_can_get (const struct reliable *rel); * @li True, if the packet ID is not a replay. * @li False, if the packet ID is a replay. */ -bool reliable_not_replay (const struct reliable *rel, packet_id_type id); +bool reliable_not_replay(const struct reliable *rel, packet_id_type id); /** * Check that a received packet's ID can safely be stored in @@ -258,7 +258,7 @@ bool reliable_not_replay (const struct reliable *rel, packet_id_type id); * @li False, if the packet does not fit safely in the reliable * structure's processing window. */ -bool reliable_wont_break_sequentiality (const struct reliable *rel, packet_id_type id); +bool reliable_wont_break_sequentiality(const struct reliable *rel, packet_id_type id); /** * Read the packet ID of a received packet. @@ -270,7 +270,7 @@ bool reliable_wont_break_sequentiality (const struct reliable *rel, packet_id_ty * @li True, if processing was successful. * @li False, if an error occurs during processing. */ -bool reliable_ack_read_packet_id (struct buffer *buf, packet_id_type *pid); +bool reliable_ack_read_packet_id(struct buffer *buf, packet_id_type *pid); /** * Get the buffer of a free %reliable entry in which to store a @@ -283,7 +283,7 @@ bool reliable_ack_read_packet_id (struct buffer *buf, packet_id_type *pid); * reliable structure. If there are no free entries available, this * function returns NULL. */ -struct buffer *reliable_get_buf (struct reliable *rel); +struct buffer *reliable_get_buf(struct reliable *rel); /** * Mark the %reliable entry associated with the given buffer as active @@ -294,8 +294,8 @@ struct buffer *reliable_get_buf (struct reliable *rel); * @param pid The packet's packet ID. * @param opcode The packet's opcode. */ -void reliable_mark_active_incoming (struct reliable *rel, struct buffer *buf, - packet_id_type pid, int opcode); +void reliable_mark_active_incoming(struct reliable *rel, struct buffer *buf, + packet_id_type pid, int opcode); /** * Record a packet ID for later acknowledgment. @@ -310,7 +310,7 @@ void reliable_mark_active_incoming (struct reliable *rel, struct buffer *buf, * @li False, if the packet ID was already present in \a ack or \a ack * has no free space to store any more packet IDs. */ -bool reliable_ack_acknowledge_packet_id (struct reliable_ack *ack, packet_id_type pid); +bool reliable_ack_acknowledge_packet_id(struct reliable_ack *ack, packet_id_type pid); /** @} name Functions for inserting incoming packets */ @@ -329,7 +329,7 @@ bool reliable_ack_acknowledge_packet_id (struct reliable_ack *ack, packet_id_typ * sequential key ID. If no such entry is present, this function * returns NULL. */ -struct buffer *reliable_get_buf_sequenced (struct reliable *rel); +struct buffer *reliable_get_buf_sequenced(struct reliable *rel); /** * Remove an entry from a reliable structure. @@ -339,7 +339,7 @@ struct buffer *reliable_get_buf_sequenced (struct reliable *rel); * @param inc_pid If true, the reliable structure's packet ID counter * will be incremented. */ -void reliable_mark_deleted (struct reliable *rel, struct buffer *buf, bool inc_pid); +void reliable_mark_deleted(struct reliable *rel, struct buffer *buf, bool inc_pid); /** @} name Functions for extracting incoming packets */ @@ -360,7 +360,7 @@ void reliable_mark_deleted (struct reliable *rel, struct buffer *buf, bool inc_p * function returns NULL. If the outgoing acknowledgment sequence is * broken, this function also returns NULL. */ -struct buffer *reliable_get_buf_output_sequenced (struct reliable *rel); +struct buffer *reliable_get_buf_output_sequenced(struct reliable *rel); /** * Mark the reliable entry associated with the given buffer as @@ -373,7 +373,7 @@ struct buffer *reliable_get_buf_output_sequenced (struct reliable *rel); * copied. * @param opcode The packet's opcode. */ -void reliable_mark_active_outgoing (struct reliable *rel, struct buffer *buf, int opcode); +void reliable_mark_active_outgoing(struct reliable *rel, struct buffer *buf, int opcode); /** @} name Functions for inserting outgoing packets */ @@ -394,7 +394,7 @@ void reliable_mark_active_outgoing (struct reliable *rel, struct buffer *buf, in * @li False, if there are no active entries, or the active entries * are not yet ready for resending. */ -bool reliable_can_send (const struct reliable *rel); +bool reliable_can_send(const struct reliable *rel); /** * Get the next packet to send to the remote peer. @@ -413,7 +413,7 @@ bool reliable_can_send (const struct reliable *rel); * reliable structure. If a valid pointer is returned, then \a opcode * will point to the opcode of that packet. */ -struct buffer *reliable_send (struct reliable *rel, int *opcode); +struct buffer *reliable_send(struct reliable *rel, int *opcode); /** @} name Functions for extracting outgoing packets */ @@ -432,7 +432,7 @@ struct buffer *reliable_send (struct reliable *rel, int *opcode); * structure. * @li False, if there is at least one active entry present. */ -bool reliable_empty (const struct reliable *rel); +bool reliable_empty(const struct reliable *rel); /** * Determined how many seconds until the earliest resend should @@ -445,7 +445,7 @@ bool reliable_empty (const struct reliable *rel); * the next time for attempting resending of one or more packets has * already passed, this function will return 0. */ -interval_t reliable_send_timeout (const struct reliable *rel); +interval_t reliable_send_timeout(const struct reliable *rel); /** * Reschedule all entries of a reliable structure to be ready @@ -454,21 +454,21 @@ interval_t reliable_send_timeout (const struct reliable *rel); * @param rel The reliable structure of which the entries should be * modified. */ -void reliable_schedule_now (struct reliable *rel); +void reliable_schedule_now(struct reliable *rel); -void reliable_debug_print (const struct reliable *rel, char *desc); +void reliable_debug_print(const struct reliable *rel, char *desc); /* set sending timeout (after this time we send again until ACK) */ static inline void -reliable_set_timeout (struct reliable *rel, interval_t timeout) +reliable_set_timeout(struct reliable *rel, interval_t timeout) { - rel->initial_timeout = timeout; + rel->initial_timeout = timeout; } /* print a reliable ACK record coming off the wire */ -const char *reliable_ack_print (struct buffer *buf, bool verbose, struct gc_arena *gc); +const char *reliable_ack_print(struct buffer *buf, bool verbose, struct gc_arena *gc); -void reliable_ack_debug_print (const struct reliable_ack *ack, char *desc); +void reliable_ack_debug_print(const struct reliable_ack *ack, char *desc); /** @} name Miscellaneous functions */ diff --git a/src/openvpn/route.c b/src/openvpn/route.c index fec12c11bee..01c37874be7 100644 --- a/src/openvpn/route.c +++ b/src/openvpn/route.c @@ -46,77 +46,83 @@ #include "memdbg.h" #if defined(TARGET_LINUX) || defined(TARGET_ANDROID) -#include /* RTM_GETROUTE etc. */ +#include /* RTM_GETROUTE etc. */ #endif #ifdef _WIN32 #include "openvpn-msg.h" #define METRIC_NOT_USED ((DWORD)-1) -static bool add_route_service (const struct route_ipv4 *, const struct tuntap *); -static bool del_route_service (const struct route_ipv4 *, const struct tuntap *); -static bool add_route_ipv6_service (const struct route_ipv6 *, const struct tuntap *); -static bool del_route_ipv6_service (const struct route_ipv6 *, const struct tuntap *); +static bool add_route_service(const struct route_ipv4 *, const struct tuntap *); + +static bool del_route_service(const struct route_ipv4 *, const struct tuntap *); + +static bool add_route_ipv6_service(const struct route_ipv6 *, const struct tuntap *); + +static bool del_route_ipv6_service(const struct route_ipv6 *, const struct tuntap *); + #endif -static void delete_route (struct route_ipv4 *r, const struct tuntap *tt, unsigned int flags, const struct route_gateway_info *rgi, const struct env_set *es); +static void delete_route(struct route_ipv4 *r, const struct tuntap *tt, unsigned int flags, const struct route_gateway_info *rgi, const struct env_set *es); -static void get_bypass_addresses (struct route_bypass *rb, const unsigned int flags); +static void get_bypass_addresses(struct route_bypass *rb, const unsigned int flags); #ifdef ENABLE_DEBUG static void -print_bypass_addresses (const struct route_bypass *rb) +print_bypass_addresses(const struct route_bypass *rb) { - struct gc_arena gc = gc_new (); - int i; - for (i = 0; i < rb->n_bypass; ++i) + struct gc_arena gc = gc_new(); + int i; + for (i = 0; i < rb->n_bypass; ++i) { - msg (D_ROUTE, "ROUTE: bypass_host_route[%d]=%s", - i, - print_in_addr_t (rb->bypass[i], 0, &gc)); + msg(D_ROUTE, "ROUTE: bypass_host_route[%d]=%s", + i, + print_in_addr_t(rb->bypass[i], 0, &gc)); } - gc_free (&gc); + gc_free(&gc); } #endif static bool -add_bypass_address (struct route_bypass *rb, const in_addr_t a) +add_bypass_address(struct route_bypass *rb, const in_addr_t a) { - int i; - for (i = 0; i < rb->n_bypass; ++i) + int i; + for (i = 0; i < rb->n_bypass; ++i) { - if (a == rb->bypass[i]) /* avoid duplicates */ - return true; + if (a == rb->bypass[i]) /* avoid duplicates */ + { + return true; + } } - if (rb->n_bypass < N_ROUTE_BYPASS) + if (rb->n_bypass < N_ROUTE_BYPASS) { - rb->bypass[rb->n_bypass++] = a; - return true; + rb->bypass[rb->n_bypass++] = a; + return true; } - else + else { - return false; + return false; } } struct route_option_list * -new_route_option_list (struct gc_arena *a) +new_route_option_list(struct gc_arena *a) { - struct route_option_list *ret; - ALLOC_OBJ_CLEAR_GC (ret, struct route_option_list, a); - ret->gc = a; - return ret; + struct route_option_list *ret; + ALLOC_OBJ_CLEAR_GC(ret, struct route_option_list, a); + ret->gc = a; + return ret; } struct route_ipv6_option_list * -new_route_ipv6_option_list (struct gc_arena *a) +new_route_ipv6_option_list(struct gc_arena *a) { - struct route_ipv6_option_list *ret; - ALLOC_OBJ_CLEAR_GC (ret, struct route_ipv6_option_list, a); - ret->gc = a; - return ret; + struct route_ipv6_option_list *ret; + ALLOC_OBJ_CLEAR_GC(ret, struct route_ipv6_option_list, a); + ret->gc = a; + return ret; } /* @@ -127,544 +133,594 @@ new_route_ipv6_option_list (struct gc_arena *a) * the c2->gc so they get freed immediately after a reconnect. */ struct route_option_list * -clone_route_option_list (const struct route_option_list *src, struct gc_arena *a) +clone_route_option_list(const struct route_option_list *src, struct gc_arena *a) { - struct route_option_list *ret; - ALLOC_OBJ_GC (ret, struct route_option_list, a); - *ret = *src; - return ret; + struct route_option_list *ret; + ALLOC_OBJ_GC(ret, struct route_option_list, a); + *ret = *src; + return ret; } struct route_ipv6_option_list * -clone_route_ipv6_option_list (const struct route_ipv6_option_list *src, struct gc_arena *a) +clone_route_ipv6_option_list(const struct route_ipv6_option_list *src, struct gc_arena *a) { - struct route_ipv6_option_list *ret; - ALLOC_OBJ_GC (ret, struct route_ipv6_option_list, a); - *ret = *src; - return ret; + struct route_ipv6_option_list *ret; + ALLOC_OBJ_GC(ret, struct route_ipv6_option_list, a); + *ret = *src; + return ret; } void -copy_route_option_list (struct route_option_list *dest, const struct route_option_list *src, struct gc_arena *a) +copy_route_option_list(struct route_option_list *dest, const struct route_option_list *src, struct gc_arena *a) { - *dest = *src; - dest->gc = a; + *dest = *src; + dest->gc = a; } void -copy_route_ipv6_option_list (struct route_ipv6_option_list *dest, - const struct route_ipv6_option_list *src, - struct gc_arena *a) +copy_route_ipv6_option_list(struct route_ipv6_option_list *dest, + const struct route_ipv6_option_list *src, + struct gc_arena *a) { - *dest = *src; - dest->gc = a; + *dest = *src; + dest->gc = a; } static const char * -route_string (const struct route_ipv4 *r, struct gc_arena *gc) +route_string(const struct route_ipv4 *r, struct gc_arena *gc) { - struct buffer out = alloc_buf_gc (256, gc); - buf_printf (&out, "ROUTE network %s netmask %s gateway %s", - print_in_addr_t (r->network, 0, gc), - print_in_addr_t (r->netmask, 0, gc), - print_in_addr_t (r->gateway, 0, gc) - ); - if (r->flags & RT_METRIC_DEFINED) - buf_printf (&out, " metric %d", r->metric); - return BSTR (&out); + struct buffer out = alloc_buf_gc(256, gc); + buf_printf(&out, "ROUTE network %s netmask %s gateway %s", + print_in_addr_t(r->network, 0, gc), + print_in_addr_t(r->netmask, 0, gc), + print_in_addr_t(r->gateway, 0, gc) + ); + if (r->flags & RT_METRIC_DEFINED) + { + buf_printf(&out, " metric %d", r->metric); + } + return BSTR(&out); } static bool -is_route_parm_defined (const char *parm) +is_route_parm_defined(const char *parm) { - if (!parm) - return false; - if (!strcmp (parm, "default")) - return false; - return true; + if (!parm) + { + return false; + } + if (!strcmp(parm, "default")) + { + return false; + } + return true; } static void -setenv_route_addr (struct env_set *es, const char *key, const in_addr_t addr, int i) +setenv_route_addr(struct env_set *es, const char *key, const in_addr_t addr, int i) { - struct gc_arena gc = gc_new (); - struct buffer name = alloc_buf_gc (256, &gc); - if (i >= 0) - buf_printf (&name, "route_%s_%d", key, i); - else - buf_printf (&name, "route_%s", key); - setenv_str (es, BSTR (&name), print_in_addr_t (addr, 0, &gc)); - gc_free (&gc); + struct gc_arena gc = gc_new(); + struct buffer name = alloc_buf_gc(256, &gc); + if (i >= 0) + { + buf_printf(&name, "route_%s_%d", key, i); + } + else + { + buf_printf(&name, "route_%s", key); + } + setenv_str(es, BSTR(&name), print_in_addr_t(addr, 0, &gc)); + gc_free(&gc); } static bool -get_special_addr (const struct route_list *rl, - const char *string, - in_addr_t *out, - bool *status) -{ - if (status) - *status = true; - if (!strcmp (string, "vpn_gateway")) - { - if (rl) - { - if (rl->spec.flags & RTSA_REMOTE_ENDPOINT) - *out = rl->spec.remote_endpoint; - else - { - msg (M_INFO, PACKAGE_NAME " ROUTE: vpn_gateway undefined"); - if (status) - *status = false; - } - } - return true; - } - else if (!strcmp (string, "net_gateway")) - { - if (rl) - { - if (rl->rgi.flags & RGI_ADDR_DEFINED) - *out = rl->rgi.gateway.addr; - else - { - msg (M_INFO, PACKAGE_NAME " ROUTE: net_gateway undefined -- unable to get default gateway from system"); - if (status) - *status = false; - } - } - return true; - } - else if (!strcmp (string, "remote_host")) - { - if (rl) - { - if (rl->spec.flags & RTSA_REMOTE_HOST) - *out = rl->spec.remote_host; - else - { - msg (M_INFO, PACKAGE_NAME " ROUTE: remote_host undefined"); - if (status) - *status = false; - } - } - return true; - } - return false; +get_special_addr(const struct route_list *rl, + const char *string, + in_addr_t *out, + bool *status) +{ + if (status) + { + *status = true; + } + if (!strcmp(string, "vpn_gateway")) + { + if (rl) + { + if (rl->spec.flags & RTSA_REMOTE_ENDPOINT) + { + *out = rl->spec.remote_endpoint; + } + else + { + msg(M_INFO, PACKAGE_NAME " ROUTE: vpn_gateway undefined"); + if (status) + { + *status = false; + } + } + } + return true; + } + else if (!strcmp(string, "net_gateway")) + { + if (rl) + { + if (rl->rgi.flags & RGI_ADDR_DEFINED) + { + *out = rl->rgi.gateway.addr; + } + else + { + msg(M_INFO, PACKAGE_NAME " ROUTE: net_gateway undefined -- unable to get default gateway from system"); + if (status) + { + *status = false; + } + } + } + return true; + } + else if (!strcmp(string, "remote_host")) + { + if (rl) + { + if (rl->spec.flags & RTSA_REMOTE_HOST) + { + *out = rl->spec.remote_host; + } + else + { + msg(M_INFO, PACKAGE_NAME " ROUTE: remote_host undefined"); + if (status) + { + *status = false; + } + } + } + return true; + } + return false; } bool -is_special_addr (const char *addr_str) +is_special_addr(const char *addr_str) { - if (addr_str) - return get_special_addr (NULL, addr_str, NULL, NULL); - else - return false; + if (addr_str) + { + return get_special_addr(NULL, addr_str, NULL, NULL); + } + else + { + return false; + } } static bool -init_route (struct route_ipv4 *r, - struct addrinfo **network_list, - const struct route_option *ro, - const struct route_list *rl) +init_route(struct route_ipv4 *r, + struct addrinfo **network_list, + const struct route_option *ro, + const struct route_list *rl) { - const in_addr_t default_netmask = IPV4_NETMASK_HOST; - bool status; - int ret; - struct in_addr special; + const in_addr_t default_netmask = IPV4_NETMASK_HOST; + bool status; + int ret; + struct in_addr special; - CLEAR (*r); - r->option = ro; + CLEAR(*r); + r->option = ro; - /* network */ + /* network */ - if (!is_route_parm_defined (ro->network)) + if (!is_route_parm_defined(ro->network)) { - goto fail; + goto fail; } - /* get_special_addr replaces specialaddr with a special ip addr - like gw. getaddrinfo is called to convert a a addrinfo struct */ + /* get_special_addr replaces specialaddr with a special ip addr + * like gw. getaddrinfo is called to convert a a addrinfo struct */ - if(get_special_addr (rl, ro->network, (in_addr_t *) &special.s_addr, &status)) + if (get_special_addr(rl, ro->network, (in_addr_t *) &special.s_addr, &status)) + { + special.s_addr = htonl(special.s_addr); + ret = openvpn_getaddrinfo(0, inet_ntoa(special), NULL, 0, NULL, + AF_INET, network_list); + } + else { - special.s_addr = htonl(special.s_addr); - ret = openvpn_getaddrinfo(0, inet_ntoa(special), NULL, 0, NULL, - AF_INET, network_list); + ret = openvpn_getaddrinfo(GETADDR_RESOLVE | GETADDR_WARN_ON_SIGNAL, + ro->network, NULL, 0, NULL, AF_INET, network_list); } - else - ret = openvpn_getaddrinfo(GETADDR_RESOLVE | GETADDR_WARN_ON_SIGNAL, - ro->network, NULL, 0, NULL, AF_INET, network_list); - status = (ret == 0); + status = (ret == 0); - if (!status) - goto fail; + if (!status) + { + goto fail; + } - /* netmask */ + /* netmask */ - if (is_route_parm_defined (ro->netmask)) + if (is_route_parm_defined(ro->netmask)) + { + r->netmask = getaddr( + GETADDR_HOST_ORDER + | GETADDR_WARN_ON_SIGNAL, + ro->netmask, + 0, + &status, + NULL); + if (!status) + { + goto fail; + } + } + else { - r->netmask = getaddr ( - GETADDR_HOST_ORDER - | GETADDR_WARN_ON_SIGNAL, - ro->netmask, - 0, - &status, - NULL); - if (!status) - goto fail; + r->netmask = default_netmask; } - else - r->netmask = default_netmask; - /* gateway */ + /* gateway */ - if (is_route_parm_defined (ro->gateway)) + if (is_route_parm_defined(ro->gateway)) { - if (!get_special_addr (rl, ro->gateway, &r->gateway, &status)) - { - r->gateway = getaddr ( - GETADDR_RESOLVE - | GETADDR_HOST_ORDER - | GETADDR_WARN_ON_SIGNAL, - ro->gateway, - 0, - &status, - NULL); - } - if (!status) - goto fail; + if (!get_special_addr(rl, ro->gateway, &r->gateway, &status)) + { + r->gateway = getaddr( + GETADDR_RESOLVE + | GETADDR_HOST_ORDER + | GETADDR_WARN_ON_SIGNAL, + ro->gateway, + 0, + &status, + NULL); + } + if (!status) + { + goto fail; + } } - else + else { - if (rl->spec.flags & RTSA_REMOTE_ENDPOINT) - r->gateway = rl->spec.remote_endpoint; - else - { - msg (M_WARN, PACKAGE_NAME " ROUTE: " PACKAGE_NAME " needs a gateway parameter for a --route option and no default was specified by either --route-gateway or --ifconfig options"); - goto fail; - } + if (rl->spec.flags & RTSA_REMOTE_ENDPOINT) + { + r->gateway = rl->spec.remote_endpoint; + } + else + { + msg(M_WARN, PACKAGE_NAME " ROUTE: " PACKAGE_NAME " needs a gateway parameter for a --route option and no default was specified by either --route-gateway or --ifconfig options"); + goto fail; + } } - /* metric */ + /* metric */ - r->metric = 0; - if (is_route_parm_defined (ro->metric)) + r->metric = 0; + if (is_route_parm_defined(ro->metric)) { - r->metric = atoi (ro->metric); - if (r->metric < 0) - { - msg (M_WARN, PACKAGE_NAME " ROUTE: route metric for network %s (%s) must be >= 0", - ro->network, - ro->metric); - goto fail; - } - r->flags |= RT_METRIC_DEFINED; + r->metric = atoi(ro->metric); + if (r->metric < 0) + { + msg(M_WARN, PACKAGE_NAME " ROUTE: route metric for network %s (%s) must be >= 0", + ro->network, + ro->metric); + goto fail; + } + r->flags |= RT_METRIC_DEFINED; } - else if (rl->spec.flags & RTSA_DEFAULT_METRIC) + else if (rl->spec.flags & RTSA_DEFAULT_METRIC) { - r->metric = rl->spec.default_metric; - r->flags |= RT_METRIC_DEFINED; + r->metric = rl->spec.default_metric; + r->flags |= RT_METRIC_DEFINED; } - r->flags |= RT_DEFINED; + r->flags |= RT_DEFINED; - return true; + return true; - fail: - msg (M_WARN, PACKAGE_NAME " ROUTE: failed to parse/resolve route for host/network: %s", - ro->network); - return false; +fail: + msg(M_WARN, PACKAGE_NAME " ROUTE: failed to parse/resolve route for host/network: %s", + ro->network); + return false; } static bool -init_route_ipv6 (struct route_ipv6 *r6, - const struct route_ipv6_option *r6o, - const struct route_ipv6_list *rl6 ) +init_route_ipv6(struct route_ipv6 *r6, + const struct route_ipv6_option *r6o, + const struct route_ipv6_list *rl6 ) { - CLEAR (*r6); + CLEAR(*r6); - if ( !get_ipv6_addr( r6o->prefix, &r6->network, &r6->netbits, M_WARN )) - goto fail; + if (!get_ipv6_addr( r6o->prefix, &r6->network, &r6->netbits, M_WARN )) + { + goto fail; + } - /* gateway */ - if (is_route_parm_defined (r6o->gateway)) + /* gateway */ + if (is_route_parm_defined(r6o->gateway)) { - if ( inet_pton( AF_INET6, r6o->gateway, &r6->gateway ) != 1 ) + if (inet_pton( AF_INET6, r6o->gateway, &r6->gateway ) != 1) { - msg( M_WARN, PACKAGE_NAME "ROUTE6: cannot parse gateway spec '%s'", r6o->gateway ); + msg( M_WARN, PACKAGE_NAME "ROUTE6: cannot parse gateway spec '%s'", r6o->gateway ); } } - else if (rl6->spec_flags & RTSA_REMOTE_ENDPOINT) + else if (rl6->spec_flags & RTSA_REMOTE_ENDPOINT) { - r6->gateway = rl6->remote_endpoint_ipv6; + r6->gateway = rl6->remote_endpoint_ipv6; } - else + else { - msg (M_WARN, PACKAGE_NAME " ROUTE6: " PACKAGE_NAME " needs a gateway parameter for a --route-ipv6 option and no default was specified by either --route-ipv6-gateway or --ifconfig-ipv6 options"); - goto fail; + msg(M_WARN, PACKAGE_NAME " ROUTE6: " PACKAGE_NAME " needs a gateway parameter for a --route-ipv6 option and no default was specified by either --route-ipv6-gateway or --ifconfig-ipv6 options"); + goto fail; } - /* metric */ + /* metric */ - r6->metric = -1; - if (is_route_parm_defined (r6o->metric)) + r6->metric = -1; + if (is_route_parm_defined(r6o->metric)) { - r6->metric = atoi (r6o->metric); - if (r6->metric < 0) - { - msg (M_WARN, PACKAGE_NAME " ROUTE: route metric for network %s (%s) must be >= 0", - r6o->prefix, - r6o->metric); - goto fail; - } - r6->flags |= RT_METRIC_DEFINED; + r6->metric = atoi(r6o->metric); + if (r6->metric < 0) + { + msg(M_WARN, PACKAGE_NAME " ROUTE: route metric for network %s (%s) must be >= 0", + r6o->prefix, + r6o->metric); + goto fail; + } + r6->flags |= RT_METRIC_DEFINED; } - else if (rl6->spec_flags & RTSA_DEFAULT_METRIC) + else if (rl6->spec_flags & RTSA_DEFAULT_METRIC) { - r6->metric = rl6->default_metric; - r6->flags |= RT_METRIC_DEFINED; + r6->metric = rl6->default_metric; + r6->flags |= RT_METRIC_DEFINED; } - r6->flags |= RT_DEFINED; + r6->flags |= RT_DEFINED; - return true; + return true; - fail: - msg (M_WARN, PACKAGE_NAME " ROUTE: failed to parse/resolve route for host/network: %s", - r6o->prefix); - return false; +fail: + msg(M_WARN, PACKAGE_NAME " ROUTE: failed to parse/resolve route for host/network: %s", + r6o->prefix); + return false; } void -add_route_to_option_list (struct route_option_list *l, - const char *network, - const char *netmask, - const char *gateway, - const char *metric) +add_route_to_option_list(struct route_option_list *l, + const char *network, + const char *netmask, + const char *gateway, + const char *metric) { - struct route_option *ro; - ALLOC_OBJ_GC (ro, struct route_option, l->gc); - ro->network = network; - ro->netmask = netmask; - ro->gateway = gateway; - ro->metric = metric; - ro->next = l->routes; - l->routes = ro; + struct route_option *ro; + ALLOC_OBJ_GC(ro, struct route_option, l->gc); + ro->network = network; + ro->netmask = netmask; + ro->gateway = gateway; + ro->metric = metric; + ro->next = l->routes; + l->routes = ro; } void -add_route_ipv6_to_option_list (struct route_ipv6_option_list *l, - const char *prefix, - const char *gateway, - const char *metric) +add_route_ipv6_to_option_list(struct route_ipv6_option_list *l, + const char *prefix, + const char *gateway, + const char *metric) { - struct route_ipv6_option *ro; - ALLOC_OBJ_GC (ro, struct route_ipv6_option, l->gc); - ro->prefix = prefix; - ro->gateway = gateway; - ro->metric = metric; - ro->next = l->routes_ipv6; - l->routes_ipv6 = ro; + struct route_ipv6_option *ro; + ALLOC_OBJ_GC(ro, struct route_ipv6_option, l->gc); + ro->prefix = prefix; + ro->gateway = gateway; + ro->metric = metric; + ro->next = l->routes_ipv6; + l->routes_ipv6 = ro; } void -clear_route_list (struct route_list *rl) +clear_route_list(struct route_list *rl) { - gc_free (&rl->gc); - CLEAR (*rl); + gc_free(&rl->gc); + CLEAR(*rl); } void -clear_route_ipv6_list (struct route_ipv6_list *rl6) +clear_route_ipv6_list(struct route_ipv6_list *rl6) { - gc_free (&rl6->gc); - CLEAR (*rl6); + gc_free(&rl6->gc); + CLEAR(*rl6); } void -route_list_add_vpn_gateway (struct route_list *rl, - struct env_set *es, - const in_addr_t addr) +route_list_add_vpn_gateway(struct route_list *rl, + struct env_set *es, + const in_addr_t addr) { - ASSERT(rl); - rl->spec.remote_endpoint = addr; - rl->spec.flags |= RTSA_REMOTE_ENDPOINT; - setenv_route_addr (es, "vpn_gateway", rl->spec.remote_endpoint, -1); + ASSERT(rl); + rl->spec.remote_endpoint = addr; + rl->spec.flags |= RTSA_REMOTE_ENDPOINT; + setenv_route_addr(es, "vpn_gateway", rl->spec.remote_endpoint, -1); } static void -add_block_local_item (struct route_list *rl, - const struct route_gateway_address *gateway, - in_addr_t target) +add_block_local_item(struct route_list *rl, + const struct route_gateway_address *gateway, + in_addr_t target) { - const int rgi_needed = (RGI_ADDR_DEFINED|RGI_NETMASK_DEFINED); - if ((rl->rgi.flags & rgi_needed) == rgi_needed - && rl->rgi.gateway.netmask < 0xFFFFFFFF) + const int rgi_needed = (RGI_ADDR_DEFINED|RGI_NETMASK_DEFINED); + if ((rl->rgi.flags & rgi_needed) == rgi_needed + && rl->rgi.gateway.netmask < 0xFFFFFFFF) { - struct route_ipv4 *r1, *r2; - unsigned int l2; - - ALLOC_OBJ_GC (r1, struct route_ipv4, &rl->gc); - ALLOC_OBJ_GC (r2, struct route_ipv4, &rl->gc); - - /* split a route into two smaller blocking routes, and direct them to target */ - l2 = ((~gateway->netmask)+1)>>1; - r1->flags = RT_DEFINED; - r1->gateway = target; - r1->network = gateway->addr & gateway->netmask; - r1->netmask = ~(l2-1); - r1->next = rl->routes; - rl->routes = r1; - - *r2 = *r1; - r2->network += l2; - r2->next = rl->routes; - rl->routes = r2; + struct route_ipv4 *r1, *r2; + unsigned int l2; + + ALLOC_OBJ_GC(r1, struct route_ipv4, &rl->gc); + ALLOC_OBJ_GC(r2, struct route_ipv4, &rl->gc); + + /* split a route into two smaller blocking routes, and direct them to target */ + l2 = ((~gateway->netmask)+1)>>1; + r1->flags = RT_DEFINED; + r1->gateway = target; + r1->network = gateway->addr & gateway->netmask; + r1->netmask = ~(l2-1); + r1->next = rl->routes; + rl->routes = r1; + + *r2 = *r1; + r2->network += l2; + r2->next = rl->routes; + rl->routes = r2; } } static void -add_block_local (struct route_list *rl) +add_block_local(struct route_list *rl) { - const int rgi_needed = (RGI_ADDR_DEFINED|RGI_NETMASK_DEFINED); - if ((rl->flags & RG_BLOCK_LOCAL) - && (rl->rgi.flags & rgi_needed) == rgi_needed - && (rl->spec.flags & RTSA_REMOTE_ENDPOINT) - && rl->spec.remote_host_local != TLA_LOCAL) + const int rgi_needed = (RGI_ADDR_DEFINED|RGI_NETMASK_DEFINED); + if ((rl->flags & RG_BLOCK_LOCAL) + && (rl->rgi.flags & rgi_needed) == rgi_needed + && (rl->spec.flags & RTSA_REMOTE_ENDPOINT) + && rl->spec.remote_host_local != TLA_LOCAL) { - size_t i; + size_t i; #ifndef TARGET_ANDROID - /* add bypass for gateway addr */ - add_bypass_address (&rl->spec.bypass, rl->rgi.gateway.addr); + /* add bypass for gateway addr */ + add_bypass_address(&rl->spec.bypass, rl->rgi.gateway.addr); #endif - /* block access to local subnet */ - add_block_local_item (rl, &rl->rgi.gateway, rl->spec.remote_endpoint); + /* block access to local subnet */ + add_block_local_item(rl, &rl->rgi.gateway, rl->spec.remote_endpoint); - /* process additional subnets on gateway interface */ - for (i = 0; i < rl->rgi.n_addrs; ++i) - { - const struct route_gateway_address *gwa = &rl->rgi.addrs[i]; - /* omit the add/subnet in &rl->rgi which we processed above */ - if (!((rl->rgi.gateway.addr & rl->rgi.gateway.netmask) == (gwa->addr & gwa->netmask) - && rl->rgi.gateway.netmask == gwa->netmask)) - add_block_local_item (rl, gwa, rl->spec.remote_endpoint); - } + /* process additional subnets on gateway interface */ + for (i = 0; i < rl->rgi.n_addrs; ++i) + { + const struct route_gateway_address *gwa = &rl->rgi.addrs[i]; + /* omit the add/subnet in &rl->rgi which we processed above */ + if (!((rl->rgi.gateway.addr & rl->rgi.gateway.netmask) == (gwa->addr & gwa->netmask) + && rl->rgi.gateway.netmask == gwa->netmask)) + { + add_block_local_item(rl, gwa, rl->spec.remote_endpoint); + } + } } } bool -init_route_list (struct route_list *rl, - const struct route_option_list *opt, - const char *remote_endpoint, - int default_metric, - in_addr_t remote_host, - struct env_set *es) +init_route_list(struct route_list *rl, + const struct route_option_list *opt, + const char *remote_endpoint, + int default_metric, + in_addr_t remote_host, + struct env_set *es) { - struct gc_arena gc = gc_new (); - bool ret = true; + struct gc_arena gc = gc_new(); + bool ret = true; - clear_route_list (rl); + clear_route_list(rl); - rl->flags = opt->flags; + rl->flags = opt->flags; - if (remote_host) + if (remote_host) { - rl->spec.remote_host = remote_host; - rl->spec.flags |= RTSA_REMOTE_HOST; + rl->spec.remote_host = remote_host; + rl->spec.flags |= RTSA_REMOTE_HOST; } - if (default_metric) + if (default_metric) { - rl->spec.default_metric = default_metric; - rl->spec.flags |= RTSA_DEFAULT_METRIC; + rl->spec.default_metric = default_metric; + rl->spec.flags |= RTSA_DEFAULT_METRIC; } - get_default_gateway (&rl->rgi); - if (rl->rgi.flags & RGI_ADDR_DEFINED) + get_default_gateway(&rl->rgi); + if (rl->rgi.flags & RGI_ADDR_DEFINED) { - setenv_route_addr (es, "net_gateway", rl->rgi.gateway.addr, -1); + setenv_route_addr(es, "net_gateway", rl->rgi.gateway.addr, -1); #if defined(ENABLE_DEBUG) && !defined(ENABLE_SMALL) - print_default_gateway (D_ROUTE, &rl->rgi, NULL); + print_default_gateway(D_ROUTE, &rl->rgi, NULL); #endif } - else + else { - dmsg (D_ROUTE, "ROUTE: default_gateway=UNDEF"); + dmsg(D_ROUTE, "ROUTE: default_gateway=UNDEF"); } - if (rl->spec.flags & RTSA_REMOTE_HOST) - rl->spec.remote_host_local = test_local_addr (remote_host, &rl->rgi); - - if (is_route_parm_defined (remote_endpoint)) + if (rl->spec.flags & RTSA_REMOTE_HOST) { - bool defined = false; - rl->spec.remote_endpoint = getaddr ( - GETADDR_RESOLVE - | GETADDR_HOST_ORDER - | GETADDR_WARN_ON_SIGNAL, - remote_endpoint, - 0, - &defined, - NULL); + rl->spec.remote_host_local = test_local_addr(remote_host, &rl->rgi); + } - if (defined) - { - setenv_route_addr (es, "vpn_gateway", rl->spec.remote_endpoint, -1); - rl->spec.flags |= RTSA_REMOTE_ENDPOINT; - } - else - { - msg (M_WARN, PACKAGE_NAME " ROUTE: failed to parse/resolve default gateway: %s", - remote_endpoint); - ret = false; - } + if (is_route_parm_defined(remote_endpoint)) + { + bool defined = false; + rl->spec.remote_endpoint = getaddr( + GETADDR_RESOLVE + | GETADDR_HOST_ORDER + | GETADDR_WARN_ON_SIGNAL, + remote_endpoint, + 0, + &defined, + NULL); + + if (defined) + { + setenv_route_addr(es, "vpn_gateway", rl->spec.remote_endpoint, -1); + rl->spec.flags |= RTSA_REMOTE_ENDPOINT; + } + else + { + msg(M_WARN, PACKAGE_NAME " ROUTE: failed to parse/resolve default gateway: %s", + remote_endpoint); + ret = false; + } } - if (rl->flags & RG_ENABLE) + if (rl->flags & RG_ENABLE) { - add_block_local (rl); - get_bypass_addresses (&rl->spec.bypass, rl->flags); + add_block_local(rl); + get_bypass_addresses(&rl->spec.bypass, rl->flags); #ifdef ENABLE_DEBUG - print_bypass_addresses (&rl->spec.bypass); + print_bypass_addresses(&rl->spec.bypass); #endif } - /* parse the routes from opt to rl */ - { - struct route_option *ro; - for (ro = opt->routes; ro; ro = ro->next) - { - struct addrinfo* netlist = NULL; - struct route_ipv4 r; - - if (!init_route (&r, &netlist, ro, rl)) - ret = false; - else - { - struct addrinfo* curele; - for (curele = netlist; curele; curele = curele->ai_next) - { - struct route_ipv4 *new; - ALLOC_OBJ_GC (new, struct route_ipv4, &rl->gc); - *new = r; - new->network = ntohl (((struct sockaddr_in*)curele->ai_addr)->sin_addr.s_addr); - new->next = rl->routes; - rl->routes = new; - } - } - if (netlist) - gc_addspecial(netlist, &gc_freeaddrinfo_callback, &gc); - } - } - - gc_free (&gc); - return ret; + /* parse the routes from opt to rl */ + { + struct route_option *ro; + for (ro = opt->routes; ro; ro = ro->next) + { + struct addrinfo *netlist = NULL; + struct route_ipv4 r; + + if (!init_route(&r, &netlist, ro, rl)) + { + ret = false; + } + else + { + struct addrinfo *curele; + for (curele = netlist; curele; curele = curele->ai_next) + { + struct route_ipv4 *new; + ALLOC_OBJ_GC(new, struct route_ipv4, &rl->gc); + *new = r; + new->network = ntohl(((struct sockaddr_in *)curele->ai_addr)->sin_addr.s_addr); + new->next = rl->routes; + rl->routes = new; + } + } + if (netlist) + { + gc_addspecial(netlist, &gc_freeaddrinfo_callback, &gc); + } + } + } + + gc_free(&gc); + return ret; } /* check whether an IPv6 host address is covered by a given route_ipv6 @@ -673,657 +729,711 @@ init_route_list (struct route_list *rl, */ static bool route_ipv6_match_host( const struct route_ipv6 *r6, - const struct in6_addr *host ) + const struct in6_addr *host ) { unsigned int bits = r6->netbits; int i; unsigned int mask; - if ( bits>128 ) - return false; + if (bits>128) + { + return false; + } - for( i=0; bits >= 8; i++, bits -= 8 ) + for (i = 0; bits >= 8; i++, bits -= 8) { - if ( r6->network.s6_addr[i] != host->s6_addr[i] ) - return false; + if (r6->network.s6_addr[i] != host->s6_addr[i]) + { + return false; + } } - if ( bits == 0 ) - return true; + if (bits == 0) + { + return true; + } mask = 0xff << (8-bits); if ( (r6->network.s6_addr[i] & mask) == (host->s6_addr[i] & mask )) - return true; + { + return true; + } return false; } bool -init_route_ipv6_list (struct route_ipv6_list *rl6, - const struct route_ipv6_option_list *opt6, - const char *remote_endpoint, - int default_metric, - const struct in6_addr *remote_host_ipv6, - struct env_set *es) +init_route_ipv6_list(struct route_ipv6_list *rl6, + const struct route_ipv6_option_list *opt6, + const char *remote_endpoint, + int default_metric, + const struct in6_addr *remote_host_ipv6, + struct env_set *es) { - struct gc_arena gc = gc_new (); - bool ret = true; - bool need_remote_ipv6_route; + struct gc_arena gc = gc_new(); + bool ret = true; + bool need_remote_ipv6_route; - clear_route_ipv6_list (rl6); + clear_route_ipv6_list(rl6); - rl6->flags = opt6->flags; + rl6->flags = opt6->flags; - if (remote_host_ipv6) + if (remote_host_ipv6) { - rl6->remote_host_ipv6 = *remote_host_ipv6; - rl6->spec_flags |= RTSA_REMOTE_HOST; + rl6->remote_host_ipv6 = *remote_host_ipv6; + rl6->spec_flags |= RTSA_REMOTE_HOST; } - if (default_metric >= 0 ) + if (default_metric >= 0) { - rl6->default_metric = default_metric; - rl6->spec_flags |= RTSA_DEFAULT_METRIC; + rl6->default_metric = default_metric; + rl6->spec_flags |= RTSA_DEFAULT_METRIC; } - msg (D_ROUTE, "GDG6: remote_host_ipv6=%s", - remote_host_ipv6? print_in6_addr (*remote_host_ipv6, 0, &gc): "n/a" ); + msg(D_ROUTE, "GDG6: remote_host_ipv6=%s", + remote_host_ipv6 ? print_in6_addr(*remote_host_ipv6, 0, &gc) : "n/a" ); - get_default_gateway_ipv6 (&rl6->rgi6, remote_host_ipv6); - if (rl6->rgi6.flags & RGI_ADDR_DEFINED) + get_default_gateway_ipv6(&rl6->rgi6, remote_host_ipv6); + if (rl6->rgi6.flags & RGI_ADDR_DEFINED) { - setenv_str (es, "net_gateway_ipv6", print_in6_addr (rl6->rgi6.gateway.addr_ipv6, 0, &gc)); + setenv_str(es, "net_gateway_ipv6", print_in6_addr(rl6->rgi6.gateway.addr_ipv6, 0, &gc)); #if defined(ENABLE_DEBUG) && !defined(ENABLE_SMALL) - print_default_gateway (D_ROUTE, NULL, &rl6->rgi6); + print_default_gateway(D_ROUTE, NULL, &rl6->rgi6); #endif } - else + else { - dmsg (D_ROUTE, "ROUTE6: default_gateway=UNDEF"); + dmsg(D_ROUTE, "ROUTE6: default_gateway=UNDEF"); } - if ( is_route_parm_defined( remote_endpoint )) + if (is_route_parm_defined( remote_endpoint )) { - if ( inet_pton( AF_INET6, remote_endpoint, - &rl6->remote_endpoint_ipv6) == 1 ) + if (inet_pton( AF_INET6, remote_endpoint, + &rl6->remote_endpoint_ipv6) == 1) + { + rl6->spec_flags |= RTSA_REMOTE_ENDPOINT; + } + else { - rl6->spec_flags |= RTSA_REMOTE_ENDPOINT; + msg(M_WARN, PACKAGE_NAME " ROUTE: failed to parse/resolve VPN endpoint: %s", remote_endpoint); + ret = false; } - else - { - msg (M_WARN, PACKAGE_NAME " ROUTE: failed to parse/resolve VPN endpoint: %s", remote_endpoint); - ret = false; - } } - /* parse the routes from opt6 to rl6 - * discovering potential overlaps with remote_host_ipv6 in the process - */ - need_remote_ipv6_route = false; + /* parse the routes from opt6 to rl6 + * discovering potential overlaps with remote_host_ipv6 in the process + */ + need_remote_ipv6_route = false; - { - struct route_ipv6_option *ro6; - for (ro6 = opt6->routes_ipv6; ro6; ro6 = ro6->next) - { - struct route_ipv6 *r6; - ALLOC_OBJ_GC (r6, struct route_ipv6, &rl6->gc); - if (!init_route_ipv6 (r6, ro6, rl6)) - ret = false; - else - { - r6->next = rl6->routes_ipv6; - rl6->routes_ipv6 = r6; + { + struct route_ipv6_option *ro6; + for (ro6 = opt6->routes_ipv6; ro6; ro6 = ro6->next) + { + struct route_ipv6 *r6; + ALLOC_OBJ_GC(r6, struct route_ipv6, &rl6->gc); + if (!init_route_ipv6(r6, ro6, rl6)) + { + ret = false; + } + else + { + r6->next = rl6->routes_ipv6; + rl6->routes_ipv6 = r6; #ifndef TARGET_ANDROID - /* On Android the VPNService protect function call will take of - * avoiding routing loops, so ignore this part and let - * need_remote_ipv6_route always evaluate to false - */ - if ( remote_host_ipv6 && - route_ipv6_match_host( r6, remote_host_ipv6 ) ) - { - need_remote_ipv6_route = true; - msg (D_ROUTE, "ROUTE6: %s/%d overlaps IPv6 remote %s, adding host route to VPN endpoint", - print_in6_addr (r6->network, 0, &gc), r6->netbits, - print_in6_addr (*remote_host_ipv6, 0, &gc)); - } + /* On Android the VPNService protect function call will take of + * avoiding routing loops, so ignore this part and let + * need_remote_ipv6_route always evaluate to false + */ + if (remote_host_ipv6 + && route_ipv6_match_host( r6, remote_host_ipv6 ) ) + { + need_remote_ipv6_route = true; + msg(D_ROUTE, "ROUTE6: %s/%d overlaps IPv6 remote %s, adding host route to VPN endpoint", + print_in6_addr(r6->network, 0, &gc), r6->netbits, + print_in6_addr(*remote_host_ipv6, 0, &gc)); + } #endif - } - } - } + } + } + } - /* add VPN server host route if needed */ - if ( need_remote_ipv6_route ) + /* add VPN server host route if needed */ + if (need_remote_ipv6_route) { - if ( (rl6->rgi6.flags & (RGI_ADDR_DEFINED|RGI_IFACE_DEFINED) ) == - (RGI_ADDR_DEFINED|RGI_IFACE_DEFINED) ) + if ( (rl6->rgi6.flags & (RGI_ADDR_DEFINED|RGI_IFACE_DEFINED) ) == + (RGI_ADDR_DEFINED|RGI_IFACE_DEFINED) ) { - struct route_ipv6 *r6; - ALLOC_OBJ_CLEAR_GC (r6, struct route_ipv6, &rl6->gc); - - r6->network = *remote_host_ipv6; - r6->netbits = 128; - if ( !(rl6->rgi6.flags & RGI_ON_LINK) ) - { r6->gateway = rl6->rgi6.gateway.addr_ipv6; } - r6->metric = 1; + struct route_ipv6 *r6; + ALLOC_OBJ_CLEAR_GC(r6, struct route_ipv6, &rl6->gc); + + r6->network = *remote_host_ipv6; + r6->netbits = 128; + if (!(rl6->rgi6.flags & RGI_ON_LINK) ) + { + r6->gateway = rl6->rgi6.gateway.addr_ipv6; + } + r6->metric = 1; #ifdef _WIN32 - r6->adapter_index = rl6->rgi6.adapter_index; + r6->adapter_index = rl6->rgi6.adapter_index; #else - r6->iface = rl6->rgi6.iface; + r6->iface = rl6->rgi6.iface; #endif - r6->flags = RT_DEFINED | RT_METRIC_DEFINED; + r6->flags = RT_DEFINED | RT_METRIC_DEFINED; - r6->next = rl6->routes_ipv6; - rl6->routes_ipv6 = r6; - } - else + r6->next = rl6->routes_ipv6; + rl6->routes_ipv6 = r6; + } + else { - msg (M_WARN, "ROUTE6: IPv6 route overlaps with IPv6 remote address, but could not determine IPv6 gateway address + interface, expect failure\n" ); - } + msg(M_WARN, "ROUTE6: IPv6 route overlaps with IPv6 remote address, but could not determine IPv6 gateway address + interface, expect failure\n" ); + } } - gc_free (&gc); - return ret; + gc_free(&gc); + return ret; } static void -add_route3 (in_addr_t network, - in_addr_t netmask, - in_addr_t gateway, - const struct tuntap *tt, - unsigned int flags, - const struct route_gateway_info *rgi, - const struct env_set *es) -{ - struct route_ipv4 r; - CLEAR (r); - r.flags = RT_DEFINED; - r.network = network; - r.netmask = netmask; - r.gateway = gateway; - add_route (&r, tt, flags, rgi, es); +add_route3(in_addr_t network, + in_addr_t netmask, + in_addr_t gateway, + const struct tuntap *tt, + unsigned int flags, + const struct route_gateway_info *rgi, + const struct env_set *es) +{ + struct route_ipv4 r; + CLEAR(r); + r.flags = RT_DEFINED; + r.network = network; + r.netmask = netmask; + r.gateway = gateway; + add_route(&r, tt, flags, rgi, es); } static void -del_route3 (in_addr_t network, - in_addr_t netmask, - in_addr_t gateway, - const struct tuntap *tt, - unsigned int flags, - const struct route_gateway_info *rgi, - const struct env_set *es) -{ - struct route_ipv4 r; - CLEAR (r); - r.flags = RT_DEFINED|RT_ADDED; - r.network = network; - r.netmask = netmask; - r.gateway = gateway; - delete_route (&r, tt, flags, rgi, es); +del_route3(in_addr_t network, + in_addr_t netmask, + in_addr_t gateway, + const struct tuntap *tt, + unsigned int flags, + const struct route_gateway_info *rgi, + const struct env_set *es) +{ + struct route_ipv4 r; + CLEAR(r); + r.flags = RT_DEFINED|RT_ADDED; + r.network = network; + r.netmask = netmask; + r.gateway = gateway; + delete_route(&r, tt, flags, rgi, es); } static void -add_bypass_routes (struct route_bypass *rb, - in_addr_t gateway, - const struct tuntap *tt, - unsigned int flags, - const struct route_gateway_info *rgi, - const struct env_set *es) +add_bypass_routes(struct route_bypass *rb, + in_addr_t gateway, + const struct tuntap *tt, + unsigned int flags, + const struct route_gateway_info *rgi, + const struct env_set *es) { - int i; - for (i = 0; i < rb->n_bypass; ++i) + int i; + for (i = 0; i < rb->n_bypass; ++i) { - if (rb->bypass[i]) - add_route3 (rb->bypass[i], - IPV4_NETMASK_HOST, - gateway, - tt, - flags | ROUTE_REF_GW, - rgi, - es); + if (rb->bypass[i]) + { + add_route3(rb->bypass[i], + IPV4_NETMASK_HOST, + gateway, + tt, + flags | ROUTE_REF_GW, + rgi, + es); + } } } static void -del_bypass_routes (struct route_bypass *rb, - in_addr_t gateway, - const struct tuntap *tt, - unsigned int flags, - const struct route_gateway_info *rgi, - const struct env_set *es) +del_bypass_routes(struct route_bypass *rb, + in_addr_t gateway, + const struct tuntap *tt, + unsigned int flags, + const struct route_gateway_info *rgi, + const struct env_set *es) { - int i; - for (i = 0; i < rb->n_bypass; ++i) + int i; + for (i = 0; i < rb->n_bypass; ++i) { - if (rb->bypass[i]) - del_route3 (rb->bypass[i], - IPV4_NETMASK_HOST, - gateway, - tt, - flags | ROUTE_REF_GW, - rgi, - es); + if (rb->bypass[i]) + { + del_route3(rb->bypass[i], + IPV4_NETMASK_HOST, + gateway, + tt, + flags | ROUTE_REF_GW, + rgi, + es); + } } } static void -redirect_default_route_to_vpn (struct route_list *rl, const struct tuntap *tt, unsigned int flags, const struct env_set *es) -{ - const char err[] = "NOTE: unable to redirect default gateway --"; - - if ( rl && rl->flags & RG_ENABLE ) - { - if (!(rl->spec.flags & RTSA_REMOTE_ENDPOINT) && (rl->flags & RG_REROUTE_GW)) - { - msg (M_WARN, "%s VPN gateway parameter (--route-gateway or --ifconfig) is missing", err); - } - else if (!(rl->rgi.flags & RGI_ADDR_DEFINED)) - { - msg (M_WARN, "%s Cannot read current default gateway from system", err); - } - else if (!(rl->spec.flags & RTSA_REMOTE_HOST)) - { - msg (M_WARN, "%s Cannot obtain current remote host address", err); - } - else - { -#ifndef TARGET_ANDROID - bool local = BOOL_CAST(rl->flags & RG_LOCAL); - if (rl->flags & RG_AUTO_LOCAL) { - const int tla = rl->spec.remote_host_local; - if (tla == TLA_NONLOCAL) - { - dmsg (D_ROUTE, "ROUTE remote_host is NOT LOCAL"); - local = false; - } - else if (tla == TLA_LOCAL) - { - dmsg (D_ROUTE, "ROUTE remote_host is LOCAL"); - local = true; - } - } - if (!local) - { - /* route remote host to original default gateway */ - /* if remote_host is not ipv4 (ie: ipv6), just skip - * adding this special /32 route */ - if (rl->spec.remote_host != IPV4_INVALID_ADDR) { - add_route3 (rl->spec.remote_host, - IPV4_NETMASK_HOST, - rl->rgi.gateway.addr, - tt, - flags | ROUTE_REF_GW, - &rl->rgi, - es); - rl->iflags |= RL_DID_LOCAL; - } else { - dmsg (D_ROUTE, "ROUTE remote_host protocol differs from tunneled"); - } - } -#endif +redirect_default_route_to_vpn(struct route_list *rl, const struct tuntap *tt, unsigned int flags, const struct env_set *es) +{ + const char err[] = "NOTE: unable to redirect default gateway --"; - /* route DHCP/DNS server traffic through original default gateway */ - add_bypass_routes (&rl->spec.bypass, rl->rgi.gateway.addr, tt, flags, &rl->rgi, es); - - if (rl->flags & RG_REROUTE_GW) - { - if (rl->flags & RG_DEF1) - { - /* add new default route (1st component) */ - add_route3 (0x00000000, - 0x80000000, - rl->spec.remote_endpoint, - tt, - flags, - &rl->rgi, - es); - - /* add new default route (2nd component) */ - add_route3 (0x80000000, - 0x80000000, - rl->spec.remote_endpoint, - tt, - flags, - &rl->rgi, - es); - } - else - { - /* delete default route */ - del_route3 (0, - 0, - rl->rgi.gateway.addr, - tt, - flags | ROUTE_REF_GW, - &rl->rgi, - es); - - /* add new default route */ - add_route3 (0, - 0, - rl->spec.remote_endpoint, - tt, - flags, - &rl->rgi, - es); - } - } - - /* set a flag so we can undo later */ - rl->iflags |= RL_DID_REDIRECT_DEFAULT_GATEWAY; - } + if (rl && rl->flags & RG_ENABLE) + { + if (!(rl->spec.flags & RTSA_REMOTE_ENDPOINT) && (rl->flags & RG_REROUTE_GW)) + { + msg(M_WARN, "%s VPN gateway parameter (--route-gateway or --ifconfig) is missing", err); + } + else if (!(rl->rgi.flags & RGI_ADDR_DEFINED)) + { + msg(M_WARN, "%s Cannot read current default gateway from system", err); + } + else if (!(rl->spec.flags & RTSA_REMOTE_HOST)) + { + msg(M_WARN, "%s Cannot obtain current remote host address", err); + } + else + { +#ifndef TARGET_ANDROID + bool local = BOOL_CAST(rl->flags & RG_LOCAL); + if (rl->flags & RG_AUTO_LOCAL) + { + const int tla = rl->spec.remote_host_local; + if (tla == TLA_NONLOCAL) + { + dmsg(D_ROUTE, "ROUTE remote_host is NOT LOCAL"); + local = false; + } + else if (tla == TLA_LOCAL) + { + dmsg(D_ROUTE, "ROUTE remote_host is LOCAL"); + local = true; + } + } + if (!local) + { + /* route remote host to original default gateway */ + /* if remote_host is not ipv4 (ie: ipv6), just skip + * adding this special /32 route */ + if (rl->spec.remote_host != IPV4_INVALID_ADDR) + { + add_route3(rl->spec.remote_host, + IPV4_NETMASK_HOST, + rl->rgi.gateway.addr, + tt, + flags | ROUTE_REF_GW, + &rl->rgi, + es); + rl->iflags |= RL_DID_LOCAL; + } + else + { + dmsg(D_ROUTE, "ROUTE remote_host protocol differs from tunneled"); + } + } +#endif /* ifndef TARGET_ANDROID */ + + /* route DHCP/DNS server traffic through original default gateway */ + add_bypass_routes(&rl->spec.bypass, rl->rgi.gateway.addr, tt, flags, &rl->rgi, es); + + if (rl->flags & RG_REROUTE_GW) + { + if (rl->flags & RG_DEF1) + { + /* add new default route (1st component) */ + add_route3(0x00000000, + 0x80000000, + rl->spec.remote_endpoint, + tt, + flags, + &rl->rgi, + es); + + /* add new default route (2nd component) */ + add_route3(0x80000000, + 0x80000000, + rl->spec.remote_endpoint, + tt, + flags, + &rl->rgi, + es); + } + else + { + /* delete default route */ + del_route3(0, + 0, + rl->rgi.gateway.addr, + tt, + flags | ROUTE_REF_GW, + &rl->rgi, + es); + + /* add new default route */ + add_route3(0, + 0, + rl->spec.remote_endpoint, + tt, + flags, + &rl->rgi, + es); + } + } + + /* set a flag so we can undo later */ + rl->iflags |= RL_DID_REDIRECT_DEFAULT_GATEWAY; + } } } static void -undo_redirect_default_route_to_vpn (struct route_list *rl, const struct tuntap *tt, unsigned int flags, const struct env_set *es) -{ - if ( rl && rl->iflags & RL_DID_REDIRECT_DEFAULT_GATEWAY ) - { - /* delete remote host route */ - if (rl->iflags & RL_DID_LOCAL) - { - del_route3 (rl->spec.remote_host, - IPV4_NETMASK_HOST, - rl->rgi.gateway.addr, - tt, - flags | ROUTE_REF_GW, - &rl->rgi, - es); - rl->iflags &= ~RL_DID_LOCAL; - } - - /* delete special DHCP/DNS bypass route */ - del_bypass_routes (&rl->spec.bypass, rl->rgi.gateway.addr, tt, flags, &rl->rgi, es); - - if (rl->flags & RG_REROUTE_GW) - { - if (rl->flags & RG_DEF1) - { - /* delete default route (1st component) */ - del_route3 (0x00000000, - 0x80000000, - rl->spec.remote_endpoint, - tt, - flags, - &rl->rgi, - es); - - /* delete default route (2nd component) */ - del_route3 (0x80000000, - 0x80000000, - rl->spec.remote_endpoint, - tt, - flags, - &rl->rgi, - es); - } - else - { - /* delete default route */ - del_route3 (0, - 0, - rl->spec.remote_endpoint, - tt, - flags, - &rl->rgi, - es); - - /* restore original default route */ - add_route3 (0, - 0, - rl->rgi.gateway.addr, - tt, - flags | ROUTE_REF_GW, - &rl->rgi, - es); - } - } - - rl->iflags &= ~RL_DID_REDIRECT_DEFAULT_GATEWAY; +undo_redirect_default_route_to_vpn(struct route_list *rl, const struct tuntap *tt, unsigned int flags, const struct env_set *es) +{ + if (rl && rl->iflags & RL_DID_REDIRECT_DEFAULT_GATEWAY) + { + /* delete remote host route */ + if (rl->iflags & RL_DID_LOCAL) + { + del_route3(rl->spec.remote_host, + IPV4_NETMASK_HOST, + rl->rgi.gateway.addr, + tt, + flags | ROUTE_REF_GW, + &rl->rgi, + es); + rl->iflags &= ~RL_DID_LOCAL; + } + + /* delete special DHCP/DNS bypass route */ + del_bypass_routes(&rl->spec.bypass, rl->rgi.gateway.addr, tt, flags, &rl->rgi, es); + + if (rl->flags & RG_REROUTE_GW) + { + if (rl->flags & RG_DEF1) + { + /* delete default route (1st component) */ + del_route3(0x00000000, + 0x80000000, + rl->spec.remote_endpoint, + tt, + flags, + &rl->rgi, + es); + + /* delete default route (2nd component) */ + del_route3(0x80000000, + 0x80000000, + rl->spec.remote_endpoint, + tt, + flags, + &rl->rgi, + es); + } + else + { + /* delete default route */ + del_route3(0, + 0, + rl->spec.remote_endpoint, + tt, + flags, + &rl->rgi, + es); + + /* restore original default route */ + add_route3(0, + 0, + rl->rgi.gateway.addr, + tt, + flags | ROUTE_REF_GW, + &rl->rgi, + es); + } + } + + rl->iflags &= ~RL_DID_REDIRECT_DEFAULT_GATEWAY; } } void -add_routes (struct route_list *rl, struct route_ipv6_list *rl6, const struct tuntap *tt, unsigned int flags, const struct env_set *es) +add_routes(struct route_list *rl, struct route_ipv6_list *rl6, const struct tuntap *tt, unsigned int flags, const struct env_set *es) { - redirect_default_route_to_vpn (rl, tt, flags, es); - if ( rl && !(rl->iflags & RL_ROUTES_ADDED) ) + redirect_default_route_to_vpn(rl, tt, flags, es); + if (rl && !(rl->iflags & RL_ROUTES_ADDED) ) { - struct route_ipv4 *r; + struct route_ipv4 *r; #ifdef ENABLE_MANAGEMENT - if (management && rl->routes) - { - management_set_state (management, - OPENVPN_STATE_ADD_ROUTES, - NULL, - NULL, - NULL, - NULL, - NULL); - } + if (management && rl->routes) + { + management_set_state(management, + OPENVPN_STATE_ADD_ROUTES, + NULL, + NULL, + NULL, + NULL, + NULL); + } #endif - for (r = rl->routes; r; r = r->next) - { - check_subnet_conflict (r->network, r->netmask, "route"); - if (flags & ROUTE_DELETE_FIRST) - delete_route (r, tt, flags, &rl->rgi, es); - add_route (r, tt, flags, &rl->rgi, es); - } - rl->iflags |= RL_ROUTES_ADDED; + for (r = rl->routes; r; r = r->next) + { + check_subnet_conflict(r->network, r->netmask, "route"); + if (flags & ROUTE_DELETE_FIRST) + { + delete_route(r, tt, flags, &rl->rgi, es); + } + add_route(r, tt, flags, &rl->rgi, es); + } + rl->iflags |= RL_ROUTES_ADDED; } - if (rl6 && !(rl6->iflags & RL_ROUTES_ADDED) ) + if (rl6 && !(rl6->iflags & RL_ROUTES_ADDED) ) { - struct route_ipv6 *r; - for (r = rl6->routes_ipv6; r; r = r->next) - { - if (flags & ROUTE_DELETE_FIRST) - delete_route_ipv6 (r, tt, flags, es); - add_route_ipv6 (r, tt, flags, es); - } - rl6->iflags |= RL_ROUTES_ADDED; + struct route_ipv6 *r; + for (r = rl6->routes_ipv6; r; r = r->next) + { + if (flags & ROUTE_DELETE_FIRST) + { + delete_route_ipv6(r, tt, flags, es); + } + add_route_ipv6(r, tt, flags, es); + } + rl6->iflags |= RL_ROUTES_ADDED; } } void -delete_routes (struct route_list *rl, struct route_ipv6_list *rl6, - const struct tuntap *tt, unsigned int flags, const struct env_set *es) +delete_routes(struct route_list *rl, struct route_ipv6_list *rl6, + const struct tuntap *tt, unsigned int flags, const struct env_set *es) { - if ( rl && rl->iflags & RL_ROUTES_ADDED ) + if (rl && rl->iflags & RL_ROUTES_ADDED) { - struct route_ipv4 *r; - for (r = rl->routes; r; r = r->next) - { - delete_route (r, tt, flags, &rl->rgi, es); - } - rl->iflags &= ~RL_ROUTES_ADDED; + struct route_ipv4 *r; + for (r = rl->routes; r; r = r->next) + { + delete_route(r, tt, flags, &rl->rgi, es); + } + rl->iflags &= ~RL_ROUTES_ADDED; } - undo_redirect_default_route_to_vpn (rl, tt, flags, es); + undo_redirect_default_route_to_vpn(rl, tt, flags, es); - if ( rl ) + if (rl) { - clear_route_list (rl); + clear_route_list(rl); } - if ( rl6 && (rl6->iflags & RL_ROUTES_ADDED) ) + if (rl6 && (rl6->iflags & RL_ROUTES_ADDED) ) { - struct route_ipv6 *r6; - for (r6 = rl6->routes_ipv6; r6; r6 = r6->next) - { - delete_route_ipv6 (r6, tt, flags, es); - } - rl6->iflags &= ~RL_ROUTES_ADDED; + struct route_ipv6 *r6; + for (r6 = rl6->routes_ipv6; r6; r6 = r6->next) + { + delete_route_ipv6(r6, tt, flags, es); + } + rl6->iflags &= ~RL_ROUTES_ADDED; } - if ( rl6 ) + if (rl6) { - clear_route_ipv6_list (rl6); + clear_route_ipv6_list(rl6); } } #ifndef ENABLE_SMALL static const char * -show_opt (const char *option) +show_opt(const char *option) { - if (!option) - return "default (not set)"; - else - return option; + if (!option) + { + return "default (not set)"; + } + else + { + return option; + } } static void -print_route_option (const struct route_option *ro, int level) +print_route_option(const struct route_option *ro, int level) { - msg (level, " route %s/%s/%s/%s", - show_opt (ro->network), - show_opt (ro->netmask), - show_opt (ro->gateway), - show_opt (ro->metric)); + msg(level, " route %s/%s/%s/%s", + show_opt(ro->network), + show_opt(ro->netmask), + show_opt(ro->gateway), + show_opt(ro->metric)); } void -print_route_options (const struct route_option_list *rol, - int level) +print_route_options(const struct route_option_list *rol, + int level) { - struct route_option *ro; - if (rol->flags & RG_ENABLE) - msg (level, " [redirect_default_gateway local=%d]", - (rol->flags & RG_LOCAL) != 0); - for (ro = rol->routes; ro; ro = ro->next) - print_route_option (ro, level); + struct route_option *ro; + if (rol->flags & RG_ENABLE) + { + msg(level, " [redirect_default_gateway local=%d]", + (rol->flags & RG_LOCAL) != 0); + } + for (ro = rol->routes; ro; ro = ro->next) + print_route_option(ro, level); } void print_default_gateway(const int msglevel, - const struct route_gateway_info *rgi, - const struct route_ipv6_gateway_info *rgi6) -{ - struct gc_arena gc = gc_new (); - if (rgi && (rgi->flags & RGI_ADDR_DEFINED)) - { - struct buffer out = alloc_buf_gc (256, &gc); - buf_printf (&out, "ROUTE_GATEWAY"); - if (rgi->flags & RGI_ON_LINK) - buf_printf (&out, " ON_LINK"); - else - buf_printf (&out, " %s", print_in_addr_t (rgi->gateway.addr, 0, &gc)); - if (rgi->flags & RGI_NETMASK_DEFINED) - buf_printf (&out, "/%s", print_in_addr_t (rgi->gateway.netmask, 0, &gc)); + const struct route_gateway_info *rgi, + const struct route_ipv6_gateway_info *rgi6) +{ + struct gc_arena gc = gc_new(); + if (rgi && (rgi->flags & RGI_ADDR_DEFINED)) + { + struct buffer out = alloc_buf_gc(256, &gc); + buf_printf(&out, "ROUTE_GATEWAY"); + if (rgi->flags & RGI_ON_LINK) + { + buf_printf(&out, " ON_LINK"); + } + else + { + buf_printf(&out, " %s", print_in_addr_t(rgi->gateway.addr, 0, &gc)); + } + if (rgi->flags & RGI_NETMASK_DEFINED) + { + buf_printf(&out, "/%s", print_in_addr_t(rgi->gateway.netmask, 0, &gc)); + } #ifdef _WIN32 - if (rgi->flags & RGI_IFACE_DEFINED) - buf_printf (&out, " I=%u", (unsigned int)rgi->adapter_index); + if (rgi->flags & RGI_IFACE_DEFINED) + { + buf_printf(&out, " I=%u", (unsigned int)rgi->adapter_index); + } #else - if (rgi->flags & RGI_IFACE_DEFINED) - buf_printf (&out, " IFACE=%s", rgi->iface); + if (rgi->flags & RGI_IFACE_DEFINED) + { + buf_printf(&out, " IFACE=%s", rgi->iface); + } #endif - if (rgi->flags & RGI_HWADDR_DEFINED) - buf_printf (&out, " HWADDR=%s", format_hex_ex (rgi->hwaddr, 6, 0, 1, ":", &gc)); - msg (msglevel, "%s", BSTR (&out)); + if (rgi->flags & RGI_HWADDR_DEFINED) + { + buf_printf(&out, " HWADDR=%s", format_hex_ex(rgi->hwaddr, 6, 0, 1, ":", &gc)); + } + msg(msglevel, "%s", BSTR(&out)); } - if (rgi6 && (rgi6->flags & RGI_ADDR_DEFINED)) + if (rgi6 && (rgi6->flags & RGI_ADDR_DEFINED)) { - struct buffer out = alloc_buf_gc (256, &gc); - buf_printf (&out, "ROUTE6_GATEWAY"); - buf_printf (&out, " %s", print_in6_addr (rgi6->gateway.addr_ipv6, 0, &gc)); - if (rgi6->flags & RGI_ON_LINK) - buf_printf (&out, " ON_LINK"); - if (rgi6->flags & RGI_NETMASK_DEFINED) - buf_printf (&out, "/%d", rgi6->gateway.netbits_ipv6); + struct buffer out = alloc_buf_gc(256, &gc); + buf_printf(&out, "ROUTE6_GATEWAY"); + buf_printf(&out, " %s", print_in6_addr(rgi6->gateway.addr_ipv6, 0, &gc)); + if (rgi6->flags & RGI_ON_LINK) + { + buf_printf(&out, " ON_LINK"); + } + if (rgi6->flags & RGI_NETMASK_DEFINED) + { + buf_printf(&out, "/%d", rgi6->gateway.netbits_ipv6); + } #ifdef _WIN32 - if (rgi6->flags & RGI_IFACE_DEFINED) - buf_printf (&out, " I=%u", (unsigned int)rgi6->adapter_index); + if (rgi6->flags & RGI_IFACE_DEFINED) + { + buf_printf(&out, " I=%u", (unsigned int)rgi6->adapter_index); + } #else - if (rgi6->flags & RGI_IFACE_DEFINED) - buf_printf (&out, " IFACE=%s", rgi6->iface); + if (rgi6->flags & RGI_IFACE_DEFINED) + { + buf_printf(&out, " IFACE=%s", rgi6->iface); + } #endif - if (rgi6->flags & RGI_HWADDR_DEFINED) - buf_printf (&out, " HWADDR=%s", format_hex_ex (rgi6->hwaddr, 6, 0, 1, ":", &gc)); - msg (msglevel, "%s", BSTR (&out)); + if (rgi6->flags & RGI_HWADDR_DEFINED) + { + buf_printf(&out, " HWADDR=%s", format_hex_ex(rgi6->hwaddr, 6, 0, 1, ":", &gc)); + } + msg(msglevel, "%s", BSTR(&out)); } - gc_free (&gc); + gc_free(&gc); } -#endif +#endif /* ifndef ENABLE_SMALL */ static void -print_route (const struct route_ipv4 *r, int level) +print_route(const struct route_ipv4 *r, int level) { - struct gc_arena gc = gc_new (); - if (r->flags & RT_DEFINED) - msg (level, "%s", route_string (r, &gc)); - gc_free (&gc); + struct gc_arena gc = gc_new(); + if (r->flags & RT_DEFINED) + { + msg(level, "%s", route_string(r, &gc)); + } + gc_free(&gc); } void -print_routes (const struct route_list *rl, int level) +print_routes(const struct route_list *rl, int level) { - struct route_ipv4 *r; - for (r = rl->routes; r; r = r->next) - print_route (r, level); + struct route_ipv4 *r; + for (r = rl->routes; r; r = r->next) + print_route(r, level); } static void -setenv_route (struct env_set *es, const struct route_ipv4 *r, int i) +setenv_route(struct env_set *es, const struct route_ipv4 *r, int i) { - struct gc_arena gc = gc_new (); - if (r->flags & RT_DEFINED) + struct gc_arena gc = gc_new(); + if (r->flags & RT_DEFINED) { - setenv_route_addr (es, "network", r->network, i); - setenv_route_addr (es, "netmask", r->netmask, i); - setenv_route_addr (es, "gateway", r->gateway, i); + setenv_route_addr(es, "network", r->network, i); + setenv_route_addr(es, "netmask", r->netmask, i); + setenv_route_addr(es, "gateway", r->gateway, i); - if (r->flags & RT_METRIC_DEFINED) - { - struct buffer name = alloc_buf_gc (256, &gc); - buf_printf (&name, "route_metric_%d", i); - setenv_int (es, BSTR (&name), r->metric); - } + if (r->flags & RT_METRIC_DEFINED) + { + struct buffer name = alloc_buf_gc(256, &gc); + buf_printf(&name, "route_metric_%d", i); + setenv_int(es, BSTR(&name), r->metric); + } } - gc_free (&gc); + gc_free(&gc); } void -setenv_routes (struct env_set *es, const struct route_list *rl) +setenv_routes(struct env_set *es, const struct route_list *rl) { - int i = 1; - struct route_ipv4 *r; - for (r = rl->routes; r; r = r->next) - setenv_route (es, r, i++); + int i = 1; + struct route_ipv4 *r; + for (r = rl->routes; r; r = r->next) + setenv_route(es, r, i++); } static void -setenv_route_ipv6 (struct env_set *es, const struct route_ipv6 *r6, int i) +setenv_route_ipv6(struct env_set *es, const struct route_ipv6 *r6, int i) { - struct gc_arena gc = gc_new (); - if (r6->flags & RT_DEFINED) + struct gc_arena gc = gc_new(); + if (r6->flags & RT_DEFINED) { - struct buffer name1 = alloc_buf_gc( 256, &gc ); - struct buffer val = alloc_buf_gc( 256, &gc ); - struct buffer name2 = alloc_buf_gc( 256, &gc ); + struct buffer name1 = alloc_buf_gc( 256, &gc ); + struct buffer val = alloc_buf_gc( 256, &gc ); + struct buffer name2 = alloc_buf_gc( 256, &gc ); - buf_printf( &name1, "route_ipv6_network_%d", i ); - buf_printf( &val, "%s/%d", print_in6_addr( r6->network, 0, &gc ), - r6->netbits ); - setenv_str( es, BSTR(&name1), BSTR(&val) ); + buf_printf( &name1, "route_ipv6_network_%d", i ); + buf_printf( &val, "%s/%d", print_in6_addr( r6->network, 0, &gc ), + r6->netbits ); + setenv_str( es, BSTR(&name1), BSTR(&val) ); - buf_printf( &name2, "route_ipv6_gateway_%d", i ); - setenv_str( es, BSTR(&name2), print_in6_addr( r6->gateway, 0, &gc )); + buf_printf( &name2, "route_ipv6_gateway_%d", i ); + setenv_str( es, BSTR(&name2), print_in6_addr( r6->gateway, 0, &gc )); } - gc_free (&gc); + gc_free(&gc); } void -setenv_routes_ipv6 (struct env_set *es, const struct route_ipv6_list *rl6) +setenv_routes_ipv6(struct env_set *es, const struct route_ipv6_list *rl6) { - int i = 1; - struct route_ipv6 *r6; - for (r6 = rl6->routes_ipv6; r6; r6 = r6->next) - setenv_route_ipv6 (es, r6, i++); + int i = 1; + struct route_ipv6 *r6; + for (r6 = rl6->routes_ipv6; r6; r6 = r6->next) + setenv_route_ipv6(es, r6, i++); } /* @@ -1350,965 +1460,1073 @@ setenv_routes_ipv6 (struct env_set *es, const struct route_ipv6_list *rl6) #define LR_ERROR 2 /* caller should abort adding route */ static int -local_route (in_addr_t network, - in_addr_t netmask, - in_addr_t gateway, - const struct route_gateway_info *rgi) -{ - /* set LR_MATCH on local host routes */ - const int rgi_needed = (RGI_ADDR_DEFINED|RGI_NETMASK_DEFINED|RGI_IFACE_DEFINED); - if (rgi - && (rgi->flags & rgi_needed) == rgi_needed - && gateway == rgi->gateway.addr - && netmask == 0xFFFFFFFF) - { - if (((network ^ rgi->gateway.addr) & rgi->gateway.netmask) == 0) - return LR_MATCH; - else - { - /* examine additional subnets on gateway interface */ - size_t i; - for (i = 0; i < rgi->n_addrs; ++i) - { - const struct route_gateway_address *gwa = &rgi->addrs[i]; - if (((network ^ gwa->addr) & gwa->netmask) == 0) - return LR_MATCH; - } - } +local_route(in_addr_t network, + in_addr_t netmask, + in_addr_t gateway, + const struct route_gateway_info *rgi) +{ + /* set LR_MATCH on local host routes */ + const int rgi_needed = (RGI_ADDR_DEFINED|RGI_NETMASK_DEFINED|RGI_IFACE_DEFINED); + if (rgi + && (rgi->flags & rgi_needed) == rgi_needed + && gateway == rgi->gateway.addr + && netmask == 0xFFFFFFFF) + { + if (((network ^ rgi->gateway.addr) & rgi->gateway.netmask) == 0) + { + return LR_MATCH; + } + else + { + /* examine additional subnets on gateway interface */ + size_t i; + for (i = 0; i < rgi->n_addrs; ++i) + { + const struct route_gateway_address *gwa = &rgi->addrs[i]; + if (((network ^ gwa->addr) & gwa->netmask) == 0) + { + return LR_MATCH; + } + } + } } return LR_NOMATCH; } /* Return true if the "on-link" form of the route should be used. This is when the gateway for a - a route is specified as an interface rather than an address. */ + * a route is specified as an interface rather than an address. */ static inline bool -is_on_link (const int is_local_route, const unsigned int flags, const struct route_gateway_info *rgi) +is_on_link(const int is_local_route, const unsigned int flags, const struct route_gateway_info *rgi) { - return rgi && (is_local_route == LR_MATCH || ((flags & ROUTE_REF_GW) && (rgi->flags & RGI_ON_LINK))); + return rgi && (is_local_route == LR_MATCH || ((flags & ROUTE_REF_GW) && (rgi->flags & RGI_ON_LINK))); } void -add_route (struct route_ipv4 *r, - const struct tuntap *tt, - unsigned int flags, - const struct route_gateway_info *rgi, /* may be NULL */ - const struct env_set *es) +add_route(struct route_ipv4 *r, + const struct tuntap *tt, + unsigned int flags, + const struct route_gateway_info *rgi, /* may be NULL */ + const struct env_set *es) { - struct gc_arena gc; - struct argv argv = argv_new (); - const char *network; - const char *netmask; - const char *gateway; - bool status = false; - int is_local_route; - - if (!(r->flags & RT_DEFINED)) - return; + struct gc_arena gc; + struct argv argv = argv_new(); + const char *network; + const char *netmask; + const char *gateway; + bool status = false; + int is_local_route; + + if (!(r->flags & RT_DEFINED)) + { + return; + } - gc_init (&gc); + gc_init(&gc); - network = print_in_addr_t (r->network, 0, &gc); - netmask = print_in_addr_t (r->netmask, 0, &gc); - gateway = print_in_addr_t (r->gateway, 0, &gc); + network = print_in_addr_t(r->network, 0, &gc); + netmask = print_in_addr_t(r->netmask, 0, &gc); + gateway = print_in_addr_t(r->gateway, 0, &gc); - is_local_route = local_route(r->network, r->netmask, r->gateway, rgi); - if (is_local_route == LR_ERROR) - goto done; + is_local_route = local_route(r->network, r->netmask, r->gateway, rgi); + if (is_local_route == LR_ERROR) + { + goto done; + } #if defined(TARGET_LINUX) #ifdef ENABLE_IPROUTE - argv_printf (&argv, "%s route add %s/%d", - iproute_path, - network, - netmask_to_netbits2(r->netmask)); - - if (r->flags & RT_METRIC_DEFINED) - argv_printf_cat (&argv, "metric %d", r->metric); - - if (is_on_link (is_local_route, flags, rgi)) - argv_printf_cat (&argv, "dev %s", rgi->iface); - else - argv_printf_cat (&argv, "via %s", gateway); -#else - argv_printf (&argv, "%s add -net %s netmask %s", - ROUTE_PATH, - network, - netmask); - if (r->flags & RT_METRIC_DEFINED) - argv_printf_cat (&argv, "metric %d", r->metric); - if (is_on_link (is_local_route, flags, rgi)) - argv_printf_cat (&argv, "dev %s", rgi->iface); - else - argv_printf_cat (&argv, "gw %s", gateway); + argv_printf(&argv, "%s route add %s/%d", + iproute_path, + network, + netmask_to_netbits2(r->netmask)); + + if (r->flags & RT_METRIC_DEFINED) + { + argv_printf_cat(&argv, "metric %d", r->metric); + } + + if (is_on_link(is_local_route, flags, rgi)) + { + argv_printf_cat(&argv, "dev %s", rgi->iface); + } + else + { + argv_printf_cat(&argv, "via %s", gateway); + } +#else /* ifdef ENABLE_IPROUTE */ + argv_printf(&argv, "%s add -net %s netmask %s", + ROUTE_PATH, + network, + netmask); + if (r->flags & RT_METRIC_DEFINED) + { + argv_printf_cat(&argv, "metric %d", r->metric); + } + if (is_on_link(is_local_route, flags, rgi)) + { + argv_printf_cat(&argv, "dev %s", rgi->iface); + } + else + { + argv_printf_cat(&argv, "gw %s", gateway); + } #endif /*ENABLE_IPROUTE*/ - argv_msg (D_ROUTE, &argv); - status = openvpn_execve_check (&argv, es, 0, "ERROR: Linux route add command failed"); + argv_msg(D_ROUTE, &argv); + status = openvpn_execve_check(&argv, es, 0, "ERROR: Linux route add command failed"); #elif defined (TARGET_ANDROID) - struct buffer out = alloc_buf_gc (128, &gc); + struct buffer out = alloc_buf_gc(128, &gc); - if (rgi) - buf_printf (&out, "%s %s %s dev %s", network, netmask, gateway, rgi->iface); - else - buf_printf (&out, "%s %s %s", network, netmask, gateway); - management_android_control (management, "ROUTE", buf_bptr(&out)); + if (rgi) + { + buf_printf(&out, "%s %s %s dev %s", network, netmask, gateway, rgi->iface); + } + else + { + buf_printf(&out, "%s %s %s", network, netmask, gateway); + } + management_android_control(management, "ROUTE", buf_bptr(&out)); #elif defined (_WIN32) - { - DWORD ai = TUN_ADAPTER_INDEX_INVALID; - argv_printf (&argv, "%s%sc ADD %s MASK %s %s", - get_win_sys_path(), - WIN_ROUTE_PATH_SUFFIX, - network, - netmask, - gateway); - if (r->flags & RT_METRIC_DEFINED) - argv_printf_cat (&argv, "METRIC %d", r->metric); - if (is_on_link (is_local_route, flags, rgi)) - { - ai = rgi->adapter_index; - argv_printf_cat (&argv, "IF %u", (unsigned int)ai); - } + { + DWORD ai = TUN_ADAPTER_INDEX_INVALID; + argv_printf(&argv, "%s%sc ADD %s MASK %s %s", + get_win_sys_path(), + WIN_ROUTE_PATH_SUFFIX, + network, + netmask, + gateway); + if (r->flags & RT_METRIC_DEFINED) + { + argv_printf_cat(&argv, "METRIC %d", r->metric); + } + if (is_on_link(is_local_route, flags, rgi)) + { + ai = rgi->adapter_index; + argv_printf_cat(&argv, "IF %u", (unsigned int)ai); + } - argv_msg (D_ROUTE, &argv); + argv_msg(D_ROUTE, &argv); - if ((flags & ROUTE_METHOD_MASK) == ROUTE_METHOD_SERVICE) - { - status = add_route_service (r, tt); - msg (D_ROUTE, "Route addition via service %s", status ? "succeeded" : "failed"); - } - else if ((flags & ROUTE_METHOD_MASK) == ROUTE_METHOD_IPAPI) - { - status = add_route_ipapi (r, tt, ai); - msg (D_ROUTE, "Route addition via IPAPI %s", status ? "succeeded" : "failed"); - } - else if ((flags & ROUTE_METHOD_MASK) == ROUTE_METHOD_EXE) - { - netcmd_semaphore_lock (); - status = openvpn_execve_check (&argv, es, 0, "ERROR: Windows route add command failed"); - netcmd_semaphore_release (); - } - else if ((flags & ROUTE_METHOD_MASK) == ROUTE_METHOD_ADAPTIVE) - { - status = add_route_ipapi (r, tt, ai); - msg (D_ROUTE, "Route addition via IPAPI %s [adaptive]", status ? "succeeded" : "failed"); - if (!status) - { - msg (D_ROUTE, "Route addition fallback to route.exe"); - netcmd_semaphore_lock (); - status = openvpn_execve_check (&argv, es, 0, "ERROR: Windows route add command failed [adaptive]"); - netcmd_semaphore_release (); - } - } - else - { - ASSERT (0); - } - } + if ((flags & ROUTE_METHOD_MASK) == ROUTE_METHOD_SERVICE) + { + status = add_route_service(r, tt); + msg(D_ROUTE, "Route addition via service %s", status ? "succeeded" : "failed"); + } + else if ((flags & ROUTE_METHOD_MASK) == ROUTE_METHOD_IPAPI) + { + status = add_route_ipapi(r, tt, ai); + msg(D_ROUTE, "Route addition via IPAPI %s", status ? "succeeded" : "failed"); + } + else if ((flags & ROUTE_METHOD_MASK) == ROUTE_METHOD_EXE) + { + netcmd_semaphore_lock(); + status = openvpn_execve_check(&argv, es, 0, "ERROR: Windows route add command failed"); + netcmd_semaphore_release(); + } + else if ((flags & ROUTE_METHOD_MASK) == ROUTE_METHOD_ADAPTIVE) + { + status = add_route_ipapi(r, tt, ai); + msg(D_ROUTE, "Route addition via IPAPI %s [adaptive]", status ? "succeeded" : "failed"); + if (!status) + { + msg(D_ROUTE, "Route addition fallback to route.exe"); + netcmd_semaphore_lock(); + status = openvpn_execve_check(&argv, es, 0, "ERROR: Windows route add command failed [adaptive]"); + netcmd_semaphore_release(); + } + } + else + { + ASSERT(0); + } + } #elif defined (TARGET_SOLARIS) - /* example: route add 192.0.2.32 -netmask 255.255.255.224 somegateway */ + /* example: route add 192.0.2.32 -netmask 255.255.255.224 somegateway */ - argv_printf (&argv, "%s add", - ROUTE_PATH); + argv_printf(&argv, "%s add", + ROUTE_PATH); - argv_printf_cat (&argv, "%s -netmask %s %s", - network, - netmask, - gateway); + argv_printf_cat(&argv, "%s -netmask %s %s", + network, + netmask, + gateway); - /* Solaris can only distinguish between "metric 0" == "on-link on the - * interface where the IP address given is configured" and "metric > 0" - * == "use gateway specified" (no finer-grained route metrics available) - * - * More recent versions of Solaris can also do "-interface", but that - * would break backwards compatibility with older versions for no gain. - */ - if (r->flags & RT_METRIC_DEFINED ) - argv_printf_cat (&argv, "%d", r->metric); + /* Solaris can only distinguish between "metric 0" == "on-link on the + * interface where the IP address given is configured" and "metric > 0" + * == "use gateway specified" (no finer-grained route metrics available) + * + * More recent versions of Solaris can also do "-interface", but that + * would break backwards compatibility with older versions for no gain. + */ + if (r->flags & RT_METRIC_DEFINED) + { + argv_printf_cat(&argv, "%d", r->metric); + } - argv_msg (D_ROUTE, &argv); - status = openvpn_execve_check (&argv, es, 0, "ERROR: Solaris route add command failed"); + argv_msg(D_ROUTE, &argv); + status = openvpn_execve_check(&argv, es, 0, "ERROR: Solaris route add command failed"); #elif defined(TARGET_FREEBSD) - argv_printf (&argv, "%s add", - ROUTE_PATH); + argv_printf(&argv, "%s add", + ROUTE_PATH); #if 0 - if (r->flags & RT_METRIC_DEFINED) - argv_printf_cat (&argv, "-rtt %d", r->metric); + if (r->flags & RT_METRIC_DEFINED) + { + argv_printf_cat(&argv, "-rtt %d", r->metric); + } #endif - argv_printf_cat (&argv, "-net %s %s %s", - network, - gateway, - netmask); + argv_printf_cat(&argv, "-net %s %s %s", + network, + gateway, + netmask); - /* FIXME -- add on-link support for FreeBSD */ + /* FIXME -- add on-link support for FreeBSD */ - argv_msg (D_ROUTE, &argv); - status = openvpn_execve_check (&argv, es, 0, "ERROR: FreeBSD route add command failed"); + argv_msg(D_ROUTE, &argv); + status = openvpn_execve_check(&argv, es, 0, "ERROR: FreeBSD route add command failed"); #elif defined(TARGET_DRAGONFLY) - argv_printf (&argv, "%s add", - ROUTE_PATH); + argv_printf(&argv, "%s add", + ROUTE_PATH); #if 0 - if (r->flags & RT_METRIC_DEFINED) - argv_printf_cat (&argv, "-rtt %d", r->metric); + if (r->flags & RT_METRIC_DEFINED) + { + argv_printf_cat(&argv, "-rtt %d", r->metric); + } #endif - argv_printf_cat (&argv, "-net %s %s %s", - network, - gateway, - netmask); + argv_printf_cat(&argv, "-net %s %s %s", + network, + gateway, + netmask); - /* FIXME -- add on-link support for Dragonfly */ + /* FIXME -- add on-link support for Dragonfly */ - argv_msg (D_ROUTE, &argv); - status = openvpn_execve_check (&argv, es, 0, "ERROR: DragonFly route add command failed"); + argv_msg(D_ROUTE, &argv); + status = openvpn_execve_check(&argv, es, 0, "ERROR: DragonFly route add command failed"); #elif defined(TARGET_DARWIN) - argv_printf (&argv, "%s add", - ROUTE_PATH); + argv_printf(&argv, "%s add", + ROUTE_PATH); #if 0 - if (r->flags & RT_METRIC_DEFINED) - argv_printf_cat (&argv, "-rtt %d", r->metric); + if (r->flags & RT_METRIC_DEFINED) + { + argv_printf_cat(&argv, "-rtt %d", r->metric); + } #endif - if (is_on_link (is_local_route, flags, rgi)) + if (is_on_link(is_local_route, flags, rgi)) { - /* Mac OS X route syntax for ON_LINK: - route add -cloning -net 10.10.0.1 -netmask 255.255.255.255 -interface en0 */ - argv_printf_cat (&argv, "-cloning -net %s -netmask %s -interface %s", - network, - netmask, - rgi->iface); + /* Mac OS X route syntax for ON_LINK: + * route add -cloning -net 10.10.0.1 -netmask 255.255.255.255 -interface en0 */ + argv_printf_cat(&argv, "-cloning -net %s -netmask %s -interface %s", + network, + netmask, + rgi->iface); } - else + else { - argv_printf_cat (&argv, "-net %s %s %s", - network, - gateway, - netmask); + argv_printf_cat(&argv, "-net %s %s %s", + network, + gateway, + netmask); } - argv_msg (D_ROUTE, &argv); - status = openvpn_execve_check (&argv, es, 0, "ERROR: OS X route add command failed"); + argv_msg(D_ROUTE, &argv); + status = openvpn_execve_check(&argv, es, 0, "ERROR: OS X route add command failed"); #elif defined(TARGET_OPENBSD) || defined(TARGET_NETBSD) - argv_printf (&argv, "%s add", - ROUTE_PATH); + argv_printf(&argv, "%s add", + ROUTE_PATH); #if 0 - if (r->flags & RT_METRIC_DEFINED) - argv_printf_cat (&argv, "-rtt %d", r->metric); + if (r->flags & RT_METRIC_DEFINED) + { + argv_printf_cat(&argv, "-rtt %d", r->metric); + } #endif - argv_printf_cat (&argv, "-net %s %s -netmask %s", - network, - gateway, - netmask); + argv_printf_cat(&argv, "-net %s %s -netmask %s", + network, + gateway, + netmask); - /* FIXME -- add on-link support for OpenBSD/NetBSD */ + /* FIXME -- add on-link support for OpenBSD/NetBSD */ - argv_msg (D_ROUTE, &argv); - status = openvpn_execve_check (&argv, es, 0, "ERROR: OpenBSD/NetBSD route add command failed"); + argv_msg(D_ROUTE, &argv); + status = openvpn_execve_check(&argv, es, 0, "ERROR: OpenBSD/NetBSD route add command failed"); #elif defined(TARGET_AIX) - { - int netbits = netmask_to_netbits2(r->netmask); - argv_printf (&argv, "%s add -net %s/%d %s", - ROUTE_PATH, - network, netbits, gateway); - argv_msg (D_ROUTE, &argv); - status = openvpn_execve_check (&argv, es, 0, "ERROR: AIX route add command failed"); - } + { + int netbits = netmask_to_netbits2(r->netmask); + argv_printf(&argv, "%s add -net %s/%d %s", + ROUTE_PATH, + network, netbits, gateway); + argv_msg(D_ROUTE, &argv); + status = openvpn_execve_check(&argv, es, 0, "ERROR: AIX route add command failed"); + } -#else - msg (M_FATAL, "Sorry, but I don't know how to do 'route' commands on this operating system. Try putting your routes in a --route-up script"); -#endif +#else /* if defined(TARGET_LINUX) */ + msg(M_FATAL, "Sorry, but I don't know how to do 'route' commands on this operating system. Try putting your routes in a --route-up script"); +#endif /* if defined(TARGET_LINUX) */ - done: - if (status) - r->flags |= RT_ADDED; - else - r->flags &= ~RT_ADDED; - argv_reset (&argv); - gc_free (&gc); +done: + if (status) + { + r->flags |= RT_ADDED; + } + else + { + r->flags &= ~RT_ADDED; + } + argv_reset(&argv); + gc_free(&gc); } static void route_ipv6_clear_host_bits( struct route_ipv6 *r6 ) { - /* clear host bit parts of route - * (needed if routes are specified improperly, or if we need to - * explicitely setup/clear the "connected" network routes on some OSes) - */ - int byte = 15; - int bits_to_clear = 128 - r6->netbits; + /* clear host bit parts of route + * (needed if routes are specified improperly, or if we need to + * explicitely setup/clear the "connected" network routes on some OSes) + */ + int byte = 15; + int bits_to_clear = 128 - r6->netbits; - while( byte >= 0 && bits_to_clear > 0 ) + while (byte >= 0 && bits_to_clear > 0) { - if ( bits_to_clear >= 8 ) - { r6->network.s6_addr[byte--] = 0; bits_to_clear -= 8; } - else - { r6->network.s6_addr[byte--] &= (0xff << bits_to_clear); bits_to_clear = 0; } + if (bits_to_clear >= 8) + { + r6->network.s6_addr[byte--] = 0; bits_to_clear -= 8; + } + else + { + r6->network.s6_addr[byte--] &= (0xff << bits_to_clear); bits_to_clear = 0; + } } } void -add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int flags, const struct env_set *es) +add_route_ipv6(struct route_ipv6 *r6, const struct tuntap *tt, unsigned int flags, const struct env_set *es) { - struct gc_arena gc; - struct argv argv = argv_new (); + struct gc_arena gc; + struct argv argv = argv_new(); - const char *network; - const char *gateway; - bool status = false; - const char *device = tt->actual_name; + const char *network; + const char *gateway; + bool status = false; + const char *device = tt->actual_name; - bool gateway_needed = false; + bool gateway_needed = false; - if (! (r6->flags & RT_DEFINED) ) - return; + if (!(r6->flags & RT_DEFINED) ) + { + return; + } #ifndef _WIN32 - if ( r6->iface != NULL ) /* vpn server special route */ + if (r6->iface != NULL) /* vpn server special route */ { - device = r6->iface; - if ( !IN6_IS_ADDR_UNSPECIFIED(&r6->gateway) ) - gateway_needed = true; + device = r6->iface; + if (!IN6_IS_ADDR_UNSPECIFIED(&r6->gateway) ) + { + gateway_needed = true; + } } #endif - gc_init (&gc); + gc_init(&gc); - route_ipv6_clear_host_bits (r6); + route_ipv6_clear_host_bits(r6); - network = print_in6_addr( r6->network, 0, &gc); - gateway = print_in6_addr( r6->gateway, 0, &gc); + network = print_in6_addr( r6->network, 0, &gc); + gateway = print_in6_addr( r6->gateway, 0, &gc); -#if defined(TARGET_DARWIN) || \ - defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY) || \ - defined(TARGET_OPENBSD) || defined(TARGET_NETBSD) +#if defined(TARGET_DARWIN) \ + || defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY) \ + || defined(TARGET_OPENBSD) || defined(TARGET_NETBSD) - /* the BSD platforms cannot specify gateway and interface independently, - * but for link-local destinations, we MUST specify the interface, so - * we build a combined "$gateway%$interface" gateway string - */ - if ( r6->iface != NULL && gateway_needed && - IN6_IS_ADDR_LINKLOCAL(&r6->gateway) ) /* fe80::...%intf */ + /* the BSD platforms cannot specify gateway and interface independently, + * but for link-local destinations, we MUST specify the interface, so + * we build a combined "$gateway%$interface" gateway string + */ + if (r6->iface != NULL && gateway_needed + && IN6_IS_ADDR_LINKLOCAL(&r6->gateway) ) /* fe80::...%intf */ { - int len = strlen(gateway) + 1 + strlen(r6->iface)+1; - char * tmp = gc_malloc( len, true, &gc ); - snprintf( tmp, len, "%s%%%s", gateway, r6->iface ); - gateway = tmp; + int len = strlen(gateway) + 1 + strlen(r6->iface)+1; + char *tmp = gc_malloc( len, true, &gc ); + snprintf( tmp, len, "%s%%%s", gateway, r6->iface ); + gateway = tmp; } #endif - if (!tt->did_ifconfig_ipv6_setup) + if (!tt->did_ifconfig_ipv6_setup) { - msg( M_INFO, "add_route_ipv6(): not adding %s/%d: " - "no IPv6 address been configured on interface %s", - network, r6->netbits, device); - return; + msg( M_INFO, "add_route_ipv6(): not adding %s/%d: " + "no IPv6 address been configured on interface %s", + network, r6->netbits, device); + return; } - msg( M_INFO, "add_route_ipv6(%s/%d -> %s metric %d) dev %s", - network, r6->netbits, gateway, r6->metric, device ); + msg( M_INFO, "add_route_ipv6(%s/%d -> %s metric %d) dev %s", + network, r6->netbits, gateway, r6->metric, device ); - /* - * Filter out routes which are essentially no-ops - * (not currently done for IPv6) - */ + /* + * Filter out routes which are essentially no-ops + * (not currently done for IPv6) + */ - /* On "tun" interface, we never set a gateway if the operating system - * can do "route to interface" - it does not add value, as the target - * dev already fully qualifies the route destination on point-to-point - * interfaces. OTOH, on "tap" interface, we must always set the - * gateway unless the route is to be an on-link network - */ - if ( tt->type == DEV_TYPE_TAP && - !( (r6->flags & RT_METRIC_DEFINED) && r6->metric == 0 ) ) + /* On "tun" interface, we never set a gateway if the operating system + * can do "route to interface" - it does not add value, as the target + * dev already fully qualifies the route destination on point-to-point + * interfaces. OTOH, on "tap" interface, we must always set the + * gateway unless the route is to be an on-link network + */ + if (tt->type == DEV_TYPE_TAP + && !( (r6->flags & RT_METRIC_DEFINED) && r6->metric == 0 ) ) { - gateway_needed = true; + gateway_needed = true; } #if defined(TARGET_LINUX) #ifdef ENABLE_IPROUTE - argv_printf (&argv, "%s -6 route add %s/%d dev %s", - iproute_path, - network, - r6->netbits, - device); - if (gateway_needed) - argv_printf_cat (&argv, "via %s", gateway); - if ( (r6->flags & RT_METRIC_DEFINED) && r6->metric > 0 ) - argv_printf_cat (&argv, " metric %d", r6->metric); + argv_printf(&argv, "%s -6 route add %s/%d dev %s", + iproute_path, + network, + r6->netbits, + device); + if (gateway_needed) + { + argv_printf_cat(&argv, "via %s", gateway); + } + if ( (r6->flags & RT_METRIC_DEFINED) && r6->metric > 0) + { + argv_printf_cat(&argv, " metric %d", r6->metric); + } -#else - argv_printf (&argv, "%s -A inet6 add %s/%d dev %s", - ROUTE_PATH, - network, - r6->netbits, - device); - if (gateway_needed) - argv_printf_cat (&argv, "gw %s", gateway); - if ( (r6->flags & RT_METRIC_DEFINED) && r6->metric > 0 ) - argv_printf_cat (&argv, " metric %d", r6->metric); +#else /* ifdef ENABLE_IPROUTE */ + argv_printf(&argv, "%s -A inet6 add %s/%d dev %s", + ROUTE_PATH, + network, + r6->netbits, + device); + if (gateway_needed) + { + argv_printf_cat(&argv, "gw %s", gateway); + } + if ( (r6->flags & RT_METRIC_DEFINED) && r6->metric > 0) + { + argv_printf_cat(&argv, " metric %d", r6->metric); + } #endif /*ENABLE_IPROUTE*/ - argv_msg (D_ROUTE, &argv); - status = openvpn_execve_check (&argv, es, 0, "ERROR: Linux route -6/-A inet6 add command failed"); + argv_msg(D_ROUTE, &argv); + status = openvpn_execve_check(&argv, es, 0, "ERROR: Linux route -6/-A inet6 add command failed"); #elif defined (TARGET_ANDROID) - struct buffer out = alloc_buf_gc (64, &gc); + struct buffer out = alloc_buf_gc(64, &gc); - buf_printf (&out, "%s/%d %s", network, r6->netbits, device); + buf_printf(&out, "%s/%d %s", network, r6->netbits, device); - management_android_control (management, "ROUTE6", buf_bptr(&out)); + management_android_control(management, "ROUTE6", buf_bptr(&out)); #elif defined (_WIN32) - if (tt->options.msg_channel) - status = add_route_ipv6_service (r6, tt); - else - { - struct buffer out = alloc_buf_gc (64, &gc); - if ( r6->adapter_index ) /* vpn server special route */ - { - buf_printf (&out, "interface=%d", r6->adapter_index ); - gateway_needed = true; - } - else - { - buf_printf (&out, "interface=%d", tt->adapter_index ); - } - device = buf_bptr(&out); - - /* netsh interface ipv6 add route 2001:db8::/32 MyTunDevice */ - argv_printf (&argv, "%s%sc interface ipv6 add route %s/%d %s", - get_win_sys_path(), - NETSH_PATH_SUFFIX, - network, - r6->netbits, - device); - - /* next-hop depends on TUN or TAP mode: - * - in TAP mode, we use the "real" next-hop - * - in TUN mode we use a special-case link-local address that the tapdrvr - * knows about and will answer ND (neighbor discovery) packets for - */ - if ( tt->type == DEV_TYPE_TUN && !gateway_needed ) - argv_printf_cat( &argv, " %s", "fe80::8" ); - else if ( !IN6_IS_ADDR_UNSPECIFIED(&r6->gateway) ) - argv_printf_cat( &argv, " %s", gateway ); + if (tt->options.msg_channel) + { + status = add_route_ipv6_service(r6, tt); + } + else + { + struct buffer out = alloc_buf_gc(64, &gc); + if (r6->adapter_index) /* vpn server special route */ + { + buf_printf(&out, "interface=%d", r6->adapter_index ); + gateway_needed = true; + } + else + { + buf_printf(&out, "interface=%d", tt->adapter_index ); + } + device = buf_bptr(&out); + + /* netsh interface ipv6 add route 2001:db8::/32 MyTunDevice */ + argv_printf(&argv, "%s%sc interface ipv6 add route %s/%d %s", + get_win_sys_path(), + NETSH_PATH_SUFFIX, + network, + r6->netbits, + device); + + /* next-hop depends on TUN or TAP mode: + * - in TAP mode, we use the "real" next-hop + * - in TUN mode we use a special-case link-local address that the tapdrvr + * knows about and will answer ND (neighbor discovery) packets for + */ + if (tt->type == DEV_TYPE_TUN && !gateway_needed) + { + argv_printf_cat( &argv, " %s", "fe80::8" ); + } + else if (!IN6_IS_ADDR_UNSPECIFIED(&r6->gateway) ) + { + argv_printf_cat( &argv, " %s", gateway ); + } #if 0 - if (r6->flags & RT_METRIC_DEFINED) - argv_printf_cat (&argv, " METRIC %d", r->metric); + if (r6->flags & RT_METRIC_DEFINED) + { + argv_printf_cat(&argv, " METRIC %d", r->metric); + } #endif - /* in some versions of Windows, routes are persistent across reboots by - * default, unless "store=active" is set (pointed out by Tony Lim, thanks) - */ - argv_printf_cat( &argv, " store=active" ); + /* in some versions of Windows, routes are persistent across reboots by + * default, unless "store=active" is set (pointed out by Tony Lim, thanks) + */ + argv_printf_cat( &argv, " store=active" ); - argv_msg (D_ROUTE, &argv); + argv_msg(D_ROUTE, &argv); - netcmd_semaphore_lock (); - status = openvpn_execve_check (&argv, es, 0, "ERROR: Windows route add ipv6 command failed"); - netcmd_semaphore_release (); + netcmd_semaphore_lock(); + status = openvpn_execve_check(&argv, es, 0, "ERROR: Windows route add ipv6 command failed"); + netcmd_semaphore_release(); } #elif defined (TARGET_SOLARIS) - /* example: route add -inet6 2001:db8::/32 somegateway 0 */ - - /* for some reason, routes to tun/tap do not work for me unless I set - * "metric 0" - otherwise, the routes will be nicely installed, but - * packets will just disappear somewhere. So we always use "0" now, - * unless the route points to "gateway on other interface"... - * - * (Note: OpenSolaris can not specify host%interface gateways, so we just - * use the GW addresses - it seems to still work for fe80:: addresses, - * however this is done internally. NUD maybe?) - */ - argv_printf (&argv, "%s add -inet6 %s/%d %s", - ROUTE_PATH, - network, - r6->netbits, - gateway ); - - /* on tun/tap, not "elsewhere"? -> metric 0 */ - if ( !r6->iface ) - argv_printf_cat (&argv, "0"); - - argv_msg (D_ROUTE, &argv); - status = openvpn_execve_check (&argv, es, 0, "ERROR: Solaris route add -inet6 command failed"); + /* example: route add -inet6 2001:db8::/32 somegateway 0 */ + + /* for some reason, routes to tun/tap do not work for me unless I set + * "metric 0" - otherwise, the routes will be nicely installed, but + * packets will just disappear somewhere. So we always use "0" now, + * unless the route points to "gateway on other interface"... + * + * (Note: OpenSolaris can not specify host%interface gateways, so we just + * use the GW addresses - it seems to still work for fe80:: addresses, + * however this is done internally. NUD maybe?) + */ + argv_printf(&argv, "%s add -inet6 %s/%d %s", + ROUTE_PATH, + network, + r6->netbits, + gateway ); + + /* on tun/tap, not "elsewhere"? -> metric 0 */ + if (!r6->iface) + { + argv_printf_cat(&argv, "0"); + } + + argv_msg(D_ROUTE, &argv); + status = openvpn_execve_check(&argv, es, 0, "ERROR: Solaris route add -inet6 command failed"); #elif defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY) - argv_printf (&argv, "%s add -inet6 %s/%d", - ROUTE_PATH, - network, - r6->netbits); + argv_printf(&argv, "%s add -inet6 %s/%d", + ROUTE_PATH, + network, + r6->netbits); - if (gateway_needed) - argv_printf_cat (&argv, "%s", gateway); - else - argv_printf_cat (&argv, "-iface %s", device); + if (gateway_needed) + { + argv_printf_cat(&argv, "%s", gateway); + } + else + { + argv_printf_cat(&argv, "-iface %s", device); + } - argv_msg (D_ROUTE, &argv); - status = openvpn_execve_check (&argv, es, 0, "ERROR: *BSD route add -inet6 command failed"); + argv_msg(D_ROUTE, &argv); + status = openvpn_execve_check(&argv, es, 0, "ERROR: *BSD route add -inet6 command failed"); -#elif defined(TARGET_DARWIN) +#elif defined(TARGET_DARWIN) - argv_printf (&argv, "%s add -inet6 %s -prefixlen %d", - ROUTE_PATH, - network, r6->netbits ); + argv_printf(&argv, "%s add -inet6 %s -prefixlen %d", + ROUTE_PATH, + network, r6->netbits ); - if (gateway_needed) - argv_printf_cat (&argv, "%s", gateway); - else - argv_printf_cat (&argv, "-iface %s", device); + if (gateway_needed) + { + argv_printf_cat(&argv, "%s", gateway); + } + else + { + argv_printf_cat(&argv, "-iface %s", device); + } - argv_msg (D_ROUTE, &argv); - status = openvpn_execve_check (&argv, es, 0, "ERROR: MacOS X route add -inet6 command failed"); + argv_msg(D_ROUTE, &argv); + status = openvpn_execve_check(&argv, es, 0, "ERROR: MacOS X route add -inet6 command failed"); #elif defined(TARGET_OPENBSD) - argv_printf (&argv, "%s add -inet6 %s -prefixlen %d %s", - ROUTE_PATH, - network, r6->netbits, gateway ); + argv_printf(&argv, "%s add -inet6 %s -prefixlen %d %s", + ROUTE_PATH, + network, r6->netbits, gateway ); - argv_msg (D_ROUTE, &argv); - status = openvpn_execve_check (&argv, es, 0, "ERROR: OpenBSD route add -inet6 command failed"); + argv_msg(D_ROUTE, &argv); + status = openvpn_execve_check(&argv, es, 0, "ERROR: OpenBSD route add -inet6 command failed"); #elif defined(TARGET_NETBSD) - argv_printf (&argv, "%s add -inet6 %s/%d %s", - ROUTE_PATH, - network, r6->netbits, gateway ); + argv_printf(&argv, "%s add -inet6 %s/%d %s", + ROUTE_PATH, + network, r6->netbits, gateway ); - argv_msg (D_ROUTE, &argv); - status = openvpn_execve_check (&argv, es, 0, "ERROR: NetBSD route add -inet6 command failed"); + argv_msg(D_ROUTE, &argv); + status = openvpn_execve_check(&argv, es, 0, "ERROR: NetBSD route add -inet6 command failed"); #elif defined(TARGET_AIX) - argv_printf (&argv, "%s add -inet6 %s/%d %s", - ROUTE_PATH, - network, r6->netbits, gateway); - argv_msg (D_ROUTE, &argv); - status = openvpn_execve_check (&argv, es, 0, "ERROR: AIX route add command failed"); + argv_printf(&argv, "%s add -inet6 %s/%d %s", + ROUTE_PATH, + network, r6->netbits, gateway); + argv_msg(D_ROUTE, &argv); + status = openvpn_execve_check(&argv, es, 0, "ERROR: AIX route add command failed"); -#else - msg (M_FATAL, "Sorry, but I don't know how to do 'route ipv6' commands on this operating system. Try putting your routes in a --route-up script"); -#endif +#else /* if defined(TARGET_LINUX) */ + msg(M_FATAL, "Sorry, but I don't know how to do 'route ipv6' commands on this operating system. Try putting your routes in a --route-up script"); +#endif /* if defined(TARGET_LINUX) */ - if (status) - r6->flags |= RT_ADDED; - else - r6->flags &= ~RT_ADDED; - argv_reset (&argv); - gc_free (&gc); + if (status) + { + r6->flags |= RT_ADDED; + } + else + { + r6->flags &= ~RT_ADDED; + } + argv_reset(&argv); + gc_free(&gc); } static void -delete_route (struct route_ipv4 *r, - const struct tuntap *tt, - unsigned int flags, - const struct route_gateway_info *rgi, - const struct env_set *es) +delete_route(struct route_ipv4 *r, + const struct tuntap *tt, + unsigned int flags, + const struct route_gateway_info *rgi, + const struct env_set *es) { - struct gc_arena gc; - struct argv argv = argv_new (); - const char *network; - const char *netmask; - const char *gateway; - int is_local_route; - - if ((r->flags & (RT_DEFINED|RT_ADDED)) != (RT_DEFINED|RT_ADDED)) - return; + struct gc_arena gc; + struct argv argv = argv_new(); + const char *network; + const char *netmask; + const char *gateway; + int is_local_route; + + if ((r->flags & (RT_DEFINED|RT_ADDED)) != (RT_DEFINED|RT_ADDED)) + { + return; + } - gc_init (&gc); + gc_init(&gc); - network = print_in_addr_t (r->network, 0, &gc); - netmask = print_in_addr_t (r->netmask, 0, &gc); - gateway = print_in_addr_t (r->gateway, 0, &gc); + network = print_in_addr_t(r->network, 0, &gc); + netmask = print_in_addr_t(r->netmask, 0, &gc); + gateway = print_in_addr_t(r->gateway, 0, &gc); - is_local_route = local_route(r->network, r->netmask, r->gateway, rgi); - if (is_local_route == LR_ERROR) - goto done; + is_local_route = local_route(r->network, r->netmask, r->gateway, rgi); + if (is_local_route == LR_ERROR) + { + goto done; + } #if defined(TARGET_LINUX) #ifdef ENABLE_IPROUTE - argv_printf (&argv, "%s route del %s/%d", - iproute_path, - network, - netmask_to_netbits2(r->netmask)); + argv_printf(&argv, "%s route del %s/%d", + iproute_path, + network, + netmask_to_netbits2(r->netmask)); #else - argv_printf (&argv, "%s del -net %s netmask %s", - ROUTE_PATH, - network, - netmask); + argv_printf(&argv, "%s del -net %s netmask %s", + ROUTE_PATH, + network, + netmask); #endif /*ENABLE_IPROUTE*/ - if (r->flags & RT_METRIC_DEFINED) - argv_printf_cat (&argv, "metric %d", r->metric); - argv_msg (D_ROUTE, &argv); - openvpn_execve_check (&argv, es, 0, "ERROR: Linux route delete command failed"); + if (r->flags & RT_METRIC_DEFINED) + { + argv_printf_cat(&argv, "metric %d", r->metric); + } + argv_msg(D_ROUTE, &argv); + openvpn_execve_check(&argv, es, 0, "ERROR: Linux route delete command failed"); #elif defined (_WIN32) - - argv_printf (&argv, "%s%sc DELETE %s MASK %s %s", - get_win_sys_path(), - WIN_ROUTE_PATH_SUFFIX, - network, - netmask, - gateway); - argv_msg (D_ROUTE, &argv); + argv_printf(&argv, "%s%sc DELETE %s MASK %s %s", + get_win_sys_path(), + WIN_ROUTE_PATH_SUFFIX, + network, + netmask, + gateway); + + argv_msg(D_ROUTE, &argv); - if ((flags & ROUTE_METHOD_MASK) == ROUTE_METHOD_SERVICE) + if ((flags & ROUTE_METHOD_MASK) == ROUTE_METHOD_SERVICE) { - const bool status = del_route_service (r, tt); - msg (D_ROUTE, "Route deletion via service %s", status ? "succeeded" : "failed"); + const bool status = del_route_service(r, tt); + msg(D_ROUTE, "Route deletion via service %s", status ? "succeeded" : "failed"); } - else if ((flags & ROUTE_METHOD_MASK) == ROUTE_METHOD_IPAPI) + else if ((flags & ROUTE_METHOD_MASK) == ROUTE_METHOD_IPAPI) { - const bool status = del_route_ipapi (r, tt); - msg (D_ROUTE, "Route deletion via IPAPI %s", status ? "succeeded" : "failed"); + const bool status = del_route_ipapi(r, tt); + msg(D_ROUTE, "Route deletion via IPAPI %s", status ? "succeeded" : "failed"); } - else if ((flags & ROUTE_METHOD_MASK) == ROUTE_METHOD_EXE) + else if ((flags & ROUTE_METHOD_MASK) == ROUTE_METHOD_EXE) { - netcmd_semaphore_lock (); - openvpn_execve_check (&argv, es, 0, "ERROR: Windows route delete command failed"); - netcmd_semaphore_release (); + netcmd_semaphore_lock(); + openvpn_execve_check(&argv, es, 0, "ERROR: Windows route delete command failed"); + netcmd_semaphore_release(); } - else if ((flags & ROUTE_METHOD_MASK) == ROUTE_METHOD_ADAPTIVE) + else if ((flags & ROUTE_METHOD_MASK) == ROUTE_METHOD_ADAPTIVE) { - const bool status = del_route_ipapi (r, tt); - msg (D_ROUTE, "Route deletion via IPAPI %s [adaptive]", status ? "succeeded" : "failed"); - if (!status) - { - msg (D_ROUTE, "Route deletion fallback to route.exe"); - netcmd_semaphore_lock (); - openvpn_execve_check (&argv, es, 0, "ERROR: Windows route delete command failed [adaptive]"); - netcmd_semaphore_release (); - } + const bool status = del_route_ipapi(r, tt); + msg(D_ROUTE, "Route deletion via IPAPI %s [adaptive]", status ? "succeeded" : "failed"); + if (!status) + { + msg(D_ROUTE, "Route deletion fallback to route.exe"); + netcmd_semaphore_lock(); + openvpn_execve_check(&argv, es, 0, "ERROR: Windows route delete command failed [adaptive]"); + netcmd_semaphore_release(); + } } - else + else { - ASSERT (0); + ASSERT(0); } #elif defined (TARGET_SOLARIS) - argv_printf (&argv, "%s delete %s -netmask %s %s", - ROUTE_PATH, - network, - netmask, - gateway); + argv_printf(&argv, "%s delete %s -netmask %s %s", + ROUTE_PATH, + network, + netmask, + gateway); - argv_msg (D_ROUTE, &argv); - openvpn_execve_check (&argv, es, 0, "ERROR: Solaris route delete command failed"); + argv_msg(D_ROUTE, &argv); + openvpn_execve_check(&argv, es, 0, "ERROR: Solaris route delete command failed"); #elif defined(TARGET_FREEBSD) - argv_printf (&argv, "%s delete -net %s %s %s", - ROUTE_PATH, - network, - gateway, - netmask); + argv_printf(&argv, "%s delete -net %s %s %s", + ROUTE_PATH, + network, + gateway, + netmask); - argv_msg (D_ROUTE, &argv); - openvpn_execve_check (&argv, es, 0, "ERROR: FreeBSD route delete command failed"); + argv_msg(D_ROUTE, &argv); + openvpn_execve_check(&argv, es, 0, "ERROR: FreeBSD route delete command failed"); #elif defined(TARGET_DRAGONFLY) - argv_printf (&argv, "%s delete -net %s %s %s", - ROUTE_PATH, - network, - gateway, - netmask); + argv_printf(&argv, "%s delete -net %s %s %s", + ROUTE_PATH, + network, + gateway, + netmask); - argv_msg (D_ROUTE, &argv); - openvpn_execve_check (&argv, es, 0, "ERROR: DragonFly route delete command failed"); + argv_msg(D_ROUTE, &argv); + openvpn_execve_check(&argv, es, 0, "ERROR: DragonFly route delete command failed"); #elif defined(TARGET_DARWIN) - if (is_on_link (is_local_route, flags, rgi)) + if (is_on_link(is_local_route, flags, rgi)) { - argv_printf (&argv, "%s delete -cloning -net %s -netmask %s -interface %s", - ROUTE_PATH, - network, - netmask, - rgi->iface); + argv_printf(&argv, "%s delete -cloning -net %s -netmask %s -interface %s", + ROUTE_PATH, + network, + netmask, + rgi->iface); } - else + else { - argv_printf (&argv, "%s delete -net %s %s %s", - ROUTE_PATH, - network, - gateway, - netmask); + argv_printf(&argv, "%s delete -net %s %s %s", + ROUTE_PATH, + network, + gateway, + netmask); } - argv_msg (D_ROUTE, &argv); - openvpn_execve_check (&argv, es, 0, "ERROR: OS X route delete command failed"); + argv_msg(D_ROUTE, &argv); + openvpn_execve_check(&argv, es, 0, "ERROR: OS X route delete command failed"); #elif defined(TARGET_OPENBSD) || defined(TARGET_NETBSD) - argv_printf (&argv, "%s delete -net %s %s -netmask %s", - ROUTE_PATH, - network, - gateway, - netmask); + argv_printf(&argv, "%s delete -net %s %s -netmask %s", + ROUTE_PATH, + network, + gateway, + netmask); - argv_msg (D_ROUTE, &argv); - openvpn_execve_check (&argv, es, 0, "ERROR: OpenBSD/NetBSD route delete command failed"); + argv_msg(D_ROUTE, &argv); + openvpn_execve_check(&argv, es, 0, "ERROR: OpenBSD/NetBSD route delete command failed"); #elif defined(TARGET_ANDROID) - msg (M_NONFATAL, "Sorry, deleting routes on Android is not possible. The VpnService API allows routes to be set on connect only."); + msg(M_NONFATAL, "Sorry, deleting routes on Android is not possible. The VpnService API allows routes to be set on connect only."); #elif defined(TARGET_AIX) - { - int netbits = netmask_to_netbits2(r->netmask); - argv_printf (&argv, "%s delete -net %s/%d %s", - ROUTE_PATH, - network, netbits, gateway); - argv_msg (D_ROUTE, &argv); - openvpn_execve_check (&argv, es, 0, "ERROR: AIX route delete command failed"); - } + { + int netbits = netmask_to_netbits2(r->netmask); + argv_printf(&argv, "%s delete -net %s/%d %s", + ROUTE_PATH, + network, netbits, gateway); + argv_msg(D_ROUTE, &argv); + openvpn_execve_check(&argv, es, 0, "ERROR: AIX route delete command failed"); + } -#else - msg (M_FATAL, "Sorry, but I don't know how to do 'route' commands on this operating system. Try putting your routes in a --route-up script"); -#endif +#else /* if defined(TARGET_LINUX) */ + msg(M_FATAL, "Sorry, but I don't know how to do 'route' commands on this operating system. Try putting your routes in a --route-up script"); +#endif /* if defined(TARGET_LINUX) */ - done: - r->flags &= ~RT_ADDED; - argv_reset (&argv); - gc_free (&gc); +done: + r->flags &= ~RT_ADDED; + argv_reset(&argv); + gc_free(&gc); } void -delete_route_ipv6 (const struct route_ipv6 *r6, const struct tuntap *tt, unsigned int flags, const struct env_set *es) +delete_route_ipv6(const struct route_ipv6 *r6, const struct tuntap *tt, unsigned int flags, const struct env_set *es) { - struct gc_arena gc; - struct argv argv = argv_new (); - const char *network; - const char *gateway; - const char *device = tt->actual_name; - bool gateway_needed = false; - - if ((r6->flags & (RT_DEFINED|RT_ADDED)) != (RT_DEFINED|RT_ADDED)) - return; + struct gc_arena gc; + struct argv argv = argv_new(); + const char *network; + const char *gateway; + const char *device = tt->actual_name; + bool gateway_needed = false; + + if ((r6->flags & (RT_DEFINED|RT_ADDED)) != (RT_DEFINED|RT_ADDED)) + { + return; + } #ifndef _WIN32 - if ( r6->iface != NULL ) /* vpn server special route */ + if (r6->iface != NULL) /* vpn server special route */ { - device = r6->iface; - gateway_needed = true; + device = r6->iface; + gateway_needed = true; } #endif - gc_init (&gc); + gc_init(&gc); - network = print_in6_addr( r6->network, 0, &gc); - gateway = print_in6_addr( r6->gateway, 0, &gc); + network = print_in6_addr( r6->network, 0, &gc); + gateway = print_in6_addr( r6->gateway, 0, &gc); -#if defined(TARGET_DARWIN) || \ - defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY) || \ - defined(TARGET_OPENBSD) || defined(TARGET_NETBSD) +#if defined(TARGET_DARWIN) \ + || defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY) \ + || defined(TARGET_OPENBSD) || defined(TARGET_NETBSD) - /* the BSD platforms cannot specify gateway and interface independently, - * but for link-local destinations, we MUST specify the interface, so - * we build a combined "$gateway%$interface" gateway string - */ - if ( r6->iface != NULL && gateway_needed && - IN6_IS_ADDR_LINKLOCAL(&r6->gateway) ) /* fe80::...%intf */ + /* the BSD platforms cannot specify gateway and interface independently, + * but for link-local destinations, we MUST specify the interface, so + * we build a combined "$gateway%$interface" gateway string + */ + if (r6->iface != NULL && gateway_needed + && IN6_IS_ADDR_LINKLOCAL(&r6->gateway) ) /* fe80::...%intf */ { - int len = strlen(gateway) + 1 + strlen(r6->iface)+1; - char * tmp = gc_malloc( len, true, &gc ); - snprintf( tmp, len, "%s%%%s", gateway, r6->iface ); - gateway = tmp; + int len = strlen(gateway) + 1 + strlen(r6->iface)+1; + char *tmp = gc_malloc( len, true, &gc ); + snprintf( tmp, len, "%s%%%s", gateway, r6->iface ); + gateway = tmp; } #endif - msg( M_INFO, "delete_route_ipv6(%s/%d)", network, r6->netbits ); + msg( M_INFO, "delete_route_ipv6(%s/%d)", network, r6->netbits ); - /* if we used a gateway on "add route", we also need to specify it on - * delete, otherwise some OSes will refuse to delete the route - */ - if ( tt->type == DEV_TYPE_TAP && - !( (r6->flags & RT_METRIC_DEFINED) && r6->metric == 0 ) ) + /* if we used a gateway on "add route", we also need to specify it on + * delete, otherwise some OSes will refuse to delete the route + */ + if (tt->type == DEV_TYPE_TAP + && !( (r6->flags & RT_METRIC_DEFINED) && r6->metric == 0 ) ) { - gateway_needed = true; + gateway_needed = true; } #if defined(TARGET_LINUX) #ifdef ENABLE_IPROUTE - argv_printf (&argv, "%s -6 route del %s/%d dev %s", - iproute_path, - network, - r6->netbits, - device); - if (gateway_needed) - argv_printf_cat (&argv, "via %s", gateway); -#else - argv_printf (&argv, "%s -A inet6 del %s/%d dev %s", - ROUTE_PATH, - network, - r6->netbits, - device); - if (gateway_needed) - argv_printf_cat (&argv, "gw %s", gateway); - if ( (r6->flags & RT_METRIC_DEFINED) && r6->metric > 0 ) - argv_printf_cat (&argv, " metric %d", r6->metric); + argv_printf(&argv, "%s -6 route del %s/%d dev %s", + iproute_path, + network, + r6->netbits, + device); + if (gateway_needed) + { + argv_printf_cat(&argv, "via %s", gateway); + } +#else /* ifdef ENABLE_IPROUTE */ + argv_printf(&argv, "%s -A inet6 del %s/%d dev %s", + ROUTE_PATH, + network, + r6->netbits, + device); + if (gateway_needed) + { + argv_printf_cat(&argv, "gw %s", gateway); + } + if ( (r6->flags & RT_METRIC_DEFINED) && r6->metric > 0) + { + argv_printf_cat(&argv, " metric %d", r6->metric); + } #endif /*ENABLE_IPROUTE*/ - argv_msg (D_ROUTE, &argv); - openvpn_execve_check (&argv, es, 0, "ERROR: Linux route -6/-A inet6 del command failed"); + argv_msg(D_ROUTE, &argv); + openvpn_execve_check(&argv, es, 0, "ERROR: Linux route -6/-A inet6 del command failed"); #elif defined (_WIN32) - if (tt->options.msg_channel) - del_route_ipv6_service (r6, tt); - else - { - struct buffer out = alloc_buf_gc (64, &gc); - if ( r6->adapter_index ) /* vpn server special route */ - { - buf_printf (&out, "interface=%d", r6->adapter_index ); - gateway_needed = true; - } - else - { - buf_printf (&out, "interface=%d", tt->adapter_index ); - } - device = buf_bptr(&out); - - /* netsh interface ipv6 delete route 2001:db8::/32 MyTunDevice */ - argv_printf (&argv, "%s%sc interface ipv6 delete route %s/%d %s", - get_win_sys_path(), - NETSH_PATH_SUFFIX, - network, - r6->netbits, - device); - - /* next-hop depends on TUN or TAP mode: - * - in TAP mode, we use the "real" next-hop - * - in TUN mode we use a special-case link-local address that the tapdrvr - * knows about and will answer ND (neighbor discovery) packets for - * (and "route deletion without specifying next-hop" does not work...) - */ - if ( tt->type == DEV_TYPE_TUN && !gateway_needed ) - argv_printf_cat( &argv, " %s", "fe80::8" ); - else if ( !IN6_IS_ADDR_UNSPECIFIED(&r6->gateway) ) - argv_printf_cat( &argv, " %s", gateway ); + if (tt->options.msg_channel) + { + del_route_ipv6_service(r6, tt); + } + else + { + struct buffer out = alloc_buf_gc(64, &gc); + if (r6->adapter_index) /* vpn server special route */ + { + buf_printf(&out, "interface=%d", r6->adapter_index ); + gateway_needed = true; + } + else + { + buf_printf(&out, "interface=%d", tt->adapter_index ); + } + device = buf_bptr(&out); + + /* netsh interface ipv6 delete route 2001:db8::/32 MyTunDevice */ + argv_printf(&argv, "%s%sc interface ipv6 delete route %s/%d %s", + get_win_sys_path(), + NETSH_PATH_SUFFIX, + network, + r6->netbits, + device); + + /* next-hop depends on TUN or TAP mode: + * - in TAP mode, we use the "real" next-hop + * - in TUN mode we use a special-case link-local address that the tapdrvr + * knows about and will answer ND (neighbor discovery) packets for + * (and "route deletion without specifying next-hop" does not work...) + */ + if (tt->type == DEV_TYPE_TUN && !gateway_needed) + { + argv_printf_cat( &argv, " %s", "fe80::8" ); + } + else if (!IN6_IS_ADDR_UNSPECIFIED(&r6->gateway) ) + { + argv_printf_cat( &argv, " %s", gateway ); + } #if 0 - if (r6->flags & RT_METRIC_DEFINED) - argv_printf_cat (&argv, "METRIC %d", r->metric); + if (r6->flags & RT_METRIC_DEFINED) + { + argv_printf_cat(&argv, "METRIC %d", r->metric); + } #endif - /* Windows XP to 7 "just delete" routes, wherever they came from, but - * in Windows 8(.1?), if you create them with "store=active", this is - * how you should delete them as well (pointed out by Cedric Tabary) - */ - argv_printf_cat( &argv, " store=active" ); + /* Windows XP to 7 "just delete" routes, wherever they came from, but + * in Windows 8(.1?), if you create them with "store=active", this is + * how you should delete them as well (pointed out by Cedric Tabary) + */ + argv_printf_cat( &argv, " store=active" ); - argv_msg (D_ROUTE, &argv); + argv_msg(D_ROUTE, &argv); - netcmd_semaphore_lock (); - openvpn_execve_check (&argv, es, 0, "ERROR: Windows route delete ipv6 command failed"); - netcmd_semaphore_release (); + netcmd_semaphore_lock(); + openvpn_execve_check(&argv, es, 0, "ERROR: Windows route delete ipv6 command failed"); + netcmd_semaphore_release(); } #elif defined (TARGET_SOLARIS) - /* example: route delete -inet6 2001:db8::/32 somegateway */ + /* example: route delete -inet6 2001:db8::/32 somegateway */ - argv_printf (&argv, "%s delete -inet6 %s/%d %s", - ROUTE_PATH, - network, - r6->netbits, - gateway ); + argv_printf(&argv, "%s delete -inet6 %s/%d %s", + ROUTE_PATH, + network, + r6->netbits, + gateway ); - argv_msg (D_ROUTE, &argv); - openvpn_execve_check (&argv, es, 0, "ERROR: Solaris route delete -inet6 command failed"); + argv_msg(D_ROUTE, &argv); + openvpn_execve_check(&argv, es, 0, "ERROR: Solaris route delete -inet6 command failed"); #elif defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY) - argv_printf (&argv, "%s delete -inet6 %s/%d", - ROUTE_PATH, - network, - r6->netbits ); + argv_printf(&argv, "%s delete -inet6 %s/%d", + ROUTE_PATH, + network, + r6->netbits ); - if (gateway_needed) - argv_printf_cat (&argv, "%s", gateway); - else - argv_printf_cat (&argv, "-iface %s", device); + if (gateway_needed) + { + argv_printf_cat(&argv, "%s", gateway); + } + else + { + argv_printf_cat(&argv, "-iface %s", device); + } - argv_msg (D_ROUTE, &argv); - openvpn_execve_check (&argv, es, 0, "ERROR: *BSD route delete -inet6 command failed"); + argv_msg(D_ROUTE, &argv); + openvpn_execve_check(&argv, es, 0, "ERROR: *BSD route delete -inet6 command failed"); -#elif defined(TARGET_DARWIN) +#elif defined(TARGET_DARWIN) - argv_printf (&argv, "%s delete -inet6 %s -prefixlen %d", - ROUTE_PATH, - network, r6->netbits ); + argv_printf(&argv, "%s delete -inet6 %s -prefixlen %d", + ROUTE_PATH, + network, r6->netbits ); - if (gateway_needed) - argv_printf_cat (&argv, "%s", gateway); - else - argv_printf_cat (&argv, "-iface %s", device); + if (gateway_needed) + { + argv_printf_cat(&argv, "%s", gateway); + } + else + { + argv_printf_cat(&argv, "-iface %s", device); + } - argv_msg (D_ROUTE, &argv); - openvpn_execve_check (&argv, es, 0, "ERROR: MacOS X route delete -inet6 command failed"); + argv_msg(D_ROUTE, &argv); + openvpn_execve_check(&argv, es, 0, "ERROR: MacOS X route delete -inet6 command failed"); #elif defined(TARGET_OPENBSD) - argv_printf (&argv, "%s delete -inet6 %s -prefixlen %d %s", - ROUTE_PATH, - network, r6->netbits, gateway ); + argv_printf(&argv, "%s delete -inet6 %s -prefixlen %d %s", + ROUTE_PATH, + network, r6->netbits, gateway ); - argv_msg (D_ROUTE, &argv); - openvpn_execve_check (&argv, es, 0, "ERROR: OpenBSD route delete -inet6 command failed"); + argv_msg(D_ROUTE, &argv); + openvpn_execve_check(&argv, es, 0, "ERROR: OpenBSD route delete -inet6 command failed"); #elif defined(TARGET_NETBSD) - argv_printf (&argv, "%s delete -inet6 %s/%d %s", - ROUTE_PATH, - network, r6->netbits, gateway ); + argv_printf(&argv, "%s delete -inet6 %s/%d %s", + ROUTE_PATH, + network, r6->netbits, gateway ); - argv_msg (D_ROUTE, &argv); - openvpn_execve_check (&argv, es, 0, "ERROR: NetBSD route delete -inet6 command failed"); + argv_msg(D_ROUTE, &argv); + openvpn_execve_check(&argv, es, 0, "ERROR: NetBSD route delete -inet6 command failed"); #elif defined(TARGET_AIX) - argv_printf (&argv, "%s delete -inet6 %s/%d %s", - ROUTE_PATH, - network, r6->netbits, gateway); - argv_msg (D_ROUTE, &argv); - openvpn_execve_check (&argv, es, 0, "ERROR: AIX route add command failed"); + argv_printf(&argv, "%s delete -inet6 %s/%d %s", + ROUTE_PATH, + network, r6->netbits, gateway); + argv_msg(D_ROUTE, &argv); + openvpn_execve_check(&argv, es, 0, "ERROR: AIX route add command failed"); -#else - msg (M_FATAL, "Sorry, but I don't know how to do 'route ipv6' commands on this operating system. Try putting your routes in a --route-down script"); -#endif +#else /* if defined(TARGET_LINUX) */ + msg(M_FATAL, "Sorry, but I don't know how to do 'route ipv6' commands on this operating system. Try putting your routes in a --route-down script"); +#endif /* if defined(TARGET_LINUX) */ - argv_reset (&argv); - gc_free (&gc); + argv_reset(&argv); + gc_free(&gc); } /* @@ -2319,224 +2537,234 @@ delete_route_ipv6 (const struct route_ipv6 *r6, const struct tuntap *tt, unsigne #if defined(_WIN32) static const MIB_IPFORWARDTABLE * -get_windows_routing_table (struct gc_arena *gc) +get_windows_routing_table(struct gc_arena *gc) { - ULONG size = 0; - PMIB_IPFORWARDTABLE rt = NULL; - DWORD status; + ULONG size = 0; + PMIB_IPFORWARDTABLE rt = NULL; + DWORD status; - status = GetIpForwardTable (NULL, &size, TRUE); - if (status == ERROR_INSUFFICIENT_BUFFER) + status = GetIpForwardTable(NULL, &size, TRUE); + if (status == ERROR_INSUFFICIENT_BUFFER) { - rt = (PMIB_IPFORWARDTABLE) gc_malloc (size, false, gc); - status = GetIpForwardTable (rt, &size, TRUE); - if (status != NO_ERROR) - { - msg (D_ROUTE, "NOTE: GetIpForwardTable returned error: %s (code=%u)", - strerror_win32 (status, gc), - (unsigned int)status); - rt = NULL; - } + rt = (PMIB_IPFORWARDTABLE) gc_malloc(size, false, gc); + status = GetIpForwardTable(rt, &size, TRUE); + if (status != NO_ERROR) + { + msg(D_ROUTE, "NOTE: GetIpForwardTable returned error: %s (code=%u)", + strerror_win32(status, gc), + (unsigned int)status); + rt = NULL; + } } - return rt; + return rt; } static int -test_route (const IP_ADAPTER_INFO *adapters, - const in_addr_t gateway, - DWORD *index) +test_route(const IP_ADAPTER_INFO *adapters, + const in_addr_t gateway, + DWORD *index) { - int count = 0; - DWORD i = adapter_index_of_ip (adapters, gateway, &count, NULL); - if (index) - *index = i; - return count; + int count = 0; + DWORD i = adapter_index_of_ip(adapters, gateway, &count, NULL); + if (index) + { + *index = i; + } + return count; } static void -test_route_helper (bool *ret, - int *count, - int *good, - int *ambig, - const IP_ADAPTER_INFO *adapters, - const in_addr_t gateway) +test_route_helper(bool *ret, + int *count, + int *good, + int *ambig, + const IP_ADAPTER_INFO *adapters, + const in_addr_t gateway) { - int c; + int c; - ++*count; - c = test_route (adapters, gateway, NULL); - if (c == 0) - *ret = false; - else - ++*good; - if (c > 1) - ++*ambig; + ++*count; + c = test_route(adapters, gateway, NULL); + if (c == 0) + { + *ret = false; + } + else + { + ++*good; + } + if (c > 1) + { + ++*ambig; + } } /* * If we tried to add routes now, would we succeed? */ bool -test_routes (const struct route_list *rl, const struct tuntap *tt) +test_routes(const struct route_list *rl, const struct tuntap *tt) { - struct gc_arena gc = gc_new (); - const IP_ADAPTER_INFO *adapters = get_adapter_info_list (&gc); - bool ret = false; - int count = 0; - int good = 0; - int ambig = 0; - int len = -1; - bool adapter_up = false; - - if (is_adapter_up (tt, adapters)) + struct gc_arena gc = gc_new(); + const IP_ADAPTER_INFO *adapters = get_adapter_info_list(&gc); + bool ret = false; + int count = 0; + int good = 0; + int ambig = 0; + int len = -1; + bool adapter_up = false; + + if (is_adapter_up(tt, adapters)) { - ret = true; - adapter_up = true; - - if (rl) - { - struct route_ipv4 *r; - for (r = rl->routes, len = 0; r; r = r->next, ++len) - test_route_helper (&ret, &count, &good, &ambig, adapters, r->gateway); + ret = true; + adapter_up = true; - if ((rl->flags & RG_ENABLE) && (rl->spec.flags & RTSA_REMOTE_ENDPOINT)) - test_route_helper (&ret, &count, &good, &ambig, adapters, rl->spec.remote_endpoint); - } + if (rl) + { + struct route_ipv4 *r; + for (r = rl->routes, len = 0; r; r = r->next, ++len) + test_route_helper(&ret, &count, &good, &ambig, adapters, r->gateway); + + if ((rl->flags & RG_ENABLE) && (rl->spec.flags & RTSA_REMOTE_ENDPOINT)) + { + test_route_helper(&ret, &count, &good, &ambig, adapters, rl->spec.remote_endpoint); + } + } } - msg (D_ROUTE, "TEST ROUTES: %d/%d succeeded len=%d ret=%d a=%d u/d=%s", - good, - count, - len, - (int)ret, - ambig, - adapter_up ? "up" : "down"); + msg(D_ROUTE, "TEST ROUTES: %d/%d succeeded len=%d ret=%d a=%d u/d=%s", + good, + count, + len, + (int)ret, + ambig, + adapter_up ? "up" : "down"); - gc_free (&gc); - return ret; + gc_free(&gc); + return ret; } static const MIB_IPFORWARDROW * -get_default_gateway_row (const MIB_IPFORWARDTABLE *routes) +get_default_gateway_row(const MIB_IPFORWARDTABLE *routes) { - struct gc_arena gc = gc_new (); - DWORD lowest_metric = MAXDWORD; - const MIB_IPFORWARDROW *ret = NULL; - int i; - int best = -1; + struct gc_arena gc = gc_new(); + DWORD lowest_metric = MAXDWORD; + const MIB_IPFORWARDROW *ret = NULL; + int i; + int best = -1; - if (routes) + if (routes) { - for (i = 0; i < routes->dwNumEntries; ++i) - { - const MIB_IPFORWARDROW *row = &routes->table[i]; - const in_addr_t net = ntohl (row->dwForwardDest); - const in_addr_t mask = ntohl (row->dwForwardMask); - const DWORD index = row->dwForwardIfIndex; - const DWORD metric = row->dwForwardMetric1; - - dmsg (D_ROUTE_DEBUG, "GDGR: route[%d] %s/%s i=%d m=%d", - i, - print_in_addr_t ((in_addr_t) net, 0, &gc), - print_in_addr_t ((in_addr_t) mask, 0, &gc), - (int)index, - (int)metric); - - if (!net && !mask && metric < lowest_metric) - { - ret = row; - lowest_metric = metric; - best = i; - } - } + for (i = 0; i < routes->dwNumEntries; ++i) + { + const MIB_IPFORWARDROW *row = &routes->table[i]; + const in_addr_t net = ntohl(row->dwForwardDest); + const in_addr_t mask = ntohl(row->dwForwardMask); + const DWORD index = row->dwForwardIfIndex; + const DWORD metric = row->dwForwardMetric1; + + dmsg(D_ROUTE_DEBUG, "GDGR: route[%d] %s/%s i=%d m=%d", + i, + print_in_addr_t((in_addr_t) net, 0, &gc), + print_in_addr_t((in_addr_t) mask, 0, &gc), + (int)index, + (int)metric); + + if (!net && !mask && metric < lowest_metric) + { + ret = row; + lowest_metric = metric; + best = i; + } + } } - dmsg (D_ROUTE_DEBUG, "GDGR: best=%d lm=%u", best, (unsigned int)lowest_metric); + dmsg(D_ROUTE_DEBUG, "GDGR: best=%d lm=%u", best, (unsigned int)lowest_metric); - gc_free (&gc); - return ret; + gc_free(&gc); + return ret; } void -get_default_gateway (struct route_gateway_info *rgi) +get_default_gateway(struct route_gateway_info *rgi) { - struct gc_arena gc = gc_new (); + struct gc_arena gc = gc_new(); - const IP_ADAPTER_INFO *adapters = get_adapter_info_list (&gc); - const MIB_IPFORWARDTABLE *routes = get_windows_routing_table (&gc); - const MIB_IPFORWARDROW *row = get_default_gateway_row (routes); - DWORD a_index; - const IP_ADAPTER_INFO *ai; + const IP_ADAPTER_INFO *adapters = get_adapter_info_list(&gc); + const MIB_IPFORWARDTABLE *routes = get_windows_routing_table(&gc); + const MIB_IPFORWARDROW *row = get_default_gateway_row(routes); + DWORD a_index; + const IP_ADAPTER_INFO *ai; - CLEAR(*rgi); + CLEAR(*rgi); - if (row) + if (row) { - rgi->gateway.addr = ntohl (row->dwForwardNextHop); - if (rgi->gateway.addr) - { - rgi->flags |= RGI_ADDR_DEFINED; - a_index = adapter_index_of_ip (adapters, rgi->gateway.addr, NULL, &rgi->gateway.netmask); - if (a_index != TUN_ADAPTER_INDEX_INVALID) - { - rgi->adapter_index = a_index; - rgi->flags |= (RGI_IFACE_DEFINED|RGI_NETMASK_DEFINED); - ai = get_adapter (adapters, a_index); - if (ai) - { - memcpy (rgi->hwaddr, ai->Address, 6); - rgi->flags |= RGI_HWADDR_DEFINED; - } - } - } + rgi->gateway.addr = ntohl(row->dwForwardNextHop); + if (rgi->gateway.addr) + { + rgi->flags |= RGI_ADDR_DEFINED; + a_index = adapter_index_of_ip(adapters, rgi->gateway.addr, NULL, &rgi->gateway.netmask); + if (a_index != TUN_ADAPTER_INDEX_INVALID) + { + rgi->adapter_index = a_index; + rgi->flags |= (RGI_IFACE_DEFINED|RGI_NETMASK_DEFINED); + ai = get_adapter(adapters, a_index); + if (ai) + { + memcpy(rgi->hwaddr, ai->Address, 6); + rgi->flags |= RGI_HWADDR_DEFINED; + } + } + } } - gc_free (&gc); + gc_free(&gc); } static DWORD -windows_route_find_if_index (const struct route_ipv4 *r, const struct tuntap *tt) +windows_route_find_if_index(const struct route_ipv4 *r, const struct tuntap *tt) { - struct gc_arena gc = gc_new (); - DWORD ret = TUN_ADAPTER_INDEX_INVALID; - int count = 0; - const IP_ADAPTER_INFO *adapters = get_adapter_info_list (&gc); - const IP_ADAPTER_INFO *tun_adapter = get_tun_adapter (tt, adapters); - bool on_tun = false; - - /* first test on tun interface */ - if (is_ip_in_adapter_subnet (tun_adapter, r->gateway, NULL)) + struct gc_arena gc = gc_new(); + DWORD ret = TUN_ADAPTER_INDEX_INVALID; + int count = 0; + const IP_ADAPTER_INFO *adapters = get_adapter_info_list(&gc); + const IP_ADAPTER_INFO *tun_adapter = get_tun_adapter(tt, adapters); + bool on_tun = false; + + /* first test on tun interface */ + if (is_ip_in_adapter_subnet(tun_adapter, r->gateway, NULL)) { - ret = tun_adapter->Index; - count = 1; - on_tun = true; + ret = tun_adapter->Index; + count = 1; + on_tun = true; } - else /* test on other interfaces */ + else /* test on other interfaces */ { - count = test_route (adapters, r->gateway, &ret); + count = test_route(adapters, r->gateway, &ret); } - if (count == 0) + if (count == 0) { - msg (M_WARN, "Warning: route gateway is not reachable on any active network adapters: %s", - print_in_addr_t (r->gateway, 0, &gc)); - ret = TUN_ADAPTER_INDEX_INVALID; + msg(M_WARN, "Warning: route gateway is not reachable on any active network adapters: %s", + print_in_addr_t(r->gateway, 0, &gc)); + ret = TUN_ADAPTER_INDEX_INVALID; } - else if (count > 1) + else if (count > 1) { - msg (M_WARN, "Warning: route gateway is ambiguous: %s (%d matches)", - print_in_addr_t (r->gateway, 0, &gc), - count); - ret = TUN_ADAPTER_INDEX_INVALID; + msg(M_WARN, "Warning: route gateway is ambiguous: %s (%d matches)", + print_in_addr_t(r->gateway, 0, &gc), + count); + ret = TUN_ADAPTER_INDEX_INVALID; } - dmsg (D_ROUTE_DEBUG, "DEBUG: route find if: on_tun=%d count=%d index=%d", - on_tun, - count, - (int)ret); + dmsg(D_ROUTE_DEBUG, "DEBUG: route find if: on_tun=%d count=%d index=%d", + on_tun, + count, + (int)ret); - gc_free (&gc); - return ret; + gc_free(&gc); + return ret; } /* IPv6 implementation using GetBestRoute2() @@ -2546,9 +2774,9 @@ windows_route_find_if_index (const struct route_ipv4 *r, const struct tuntap *tt */ void get_default_gateway_ipv6(struct route_ipv6_gateway_info *rgi6, - const struct in6_addr *dest) + const struct in6_addr *dest) { - struct gc_arena gc = gc_new (); + struct gc_arena gc = gc_new(); MIB_IPFORWARD_ROW2 BestRoute; SOCKADDR_INET DestinationAddress, BestSourceAddress; DWORD BestIfIndex; @@ -2556,11 +2784,11 @@ get_default_gateway_ipv6(struct route_ipv6_gateway_info *rgi6, NET_LUID InterfaceLuid; CLEAR(*rgi6); - CLEAR(InterfaceLuid); // cleared = not used for lookup + CLEAR(InterfaceLuid); /* cleared = not used for lookup */ CLEAR(DestinationAddress); DestinationAddress.si_family = AF_INET6; - if ( dest ) + if (dest) { DestinationAddress.Ipv6.sin6_addr = *dest; } @@ -2569,10 +2797,10 @@ get_default_gateway_ipv6(struct route_ipv6_gateway_info *rgi6, if (status != NO_ERROR) { - msg (D_ROUTE, "NOTE: GetBestInterfaceEx returned error: %s (code=%u)", - strerror_win32 (status, &gc), - (unsigned int)status); - goto done; + msg(D_ROUTE, "NOTE: GetBestInterfaceEx returned error: %s (code=%u)", + strerror_win32(status, &gc), + (unsigned int)status); + goto done; } msg( D_ROUTE, "GetBestInterfaceEx() returned if=%d", (int) BestIfIndex ); @@ -2583,485 +2811,523 @@ get_default_gateway_ipv6(struct route_ipv6_gateway_info *rgi6, if (status != NO_ERROR) { - msg (D_ROUTE, "NOTE: GetIpForwardEntry2 returned error: %s (code=%u)", - strerror_win32 (status, &gc), - (unsigned int)status); - goto done; + msg(D_ROUTE, "NOTE: GetIpForwardEntry2 returned error: %s (code=%u)", + strerror_win32(status, &gc), + (unsigned int)status); + goto done; } msg( D_ROUTE, "GDG6: II=%d DP=%s/%d NH=%s", - BestRoute.InterfaceIndex, - print_in6_addr( BestRoute.DestinationPrefix.Prefix.Ipv6.sin6_addr, 0, &gc), - BestRoute.DestinationPrefix.PrefixLength, - print_in6_addr( BestRoute.NextHop.Ipv6.sin6_addr, 0, &gc) ); + BestRoute.InterfaceIndex, + print_in6_addr( BestRoute.DestinationPrefix.Prefix.Ipv6.sin6_addr, 0, &gc), + BestRoute.DestinationPrefix.PrefixLength, + print_in6_addr( BestRoute.NextHop.Ipv6.sin6_addr, 0, &gc) ); msg( D_ROUTE, "GDG6: Metric=%d, Loopback=%d, AA=%d, I=%d", - (int) BestRoute.Metric, - (int) BestRoute.Loopback, - (int) BestRoute.AutoconfigureAddress, - (int) BestRoute.Immortal ); + (int) BestRoute.Metric, + (int) BestRoute.Loopback, + (int) BestRoute.AutoconfigureAddress, + (int) BestRoute.Immortal ); rgi6->gateway.addr_ipv6 = BestRoute.NextHop.Ipv6.sin6_addr; rgi6->adapter_index = BestRoute.InterfaceIndex; rgi6->flags |= RGI_ADDR_DEFINED | RGI_IFACE_DEFINED; /* on-link is signalled by receiving an empty (::) NextHop */ - if ( IN6_IS_ADDR_UNSPECIFIED(&BestRoute.NextHop.Ipv6.sin6_addr) ) - { - rgi6->flags |= RGI_ON_LINK; - } + if (IN6_IS_ADDR_UNSPECIFIED(&BestRoute.NextHop.Ipv6.sin6_addr) ) + { + rgi6->flags |= RGI_ON_LINK; + } - done: - gc_free (&gc); +done: + gc_free(&gc); } bool -add_route_ipapi (const struct route_ipv4 *r, const struct tuntap *tt, DWORD adapter_index) -{ - struct gc_arena gc = gc_new (); - bool ret = false; - DWORD status; - const DWORD if_index = (adapter_index == TUN_ADAPTER_INDEX_INVALID) ? windows_route_find_if_index (r, tt) : adapter_index; - - if (if_index != TUN_ADAPTER_INDEX_INVALID) - { - MIB_IPFORWARDROW fr; - CLEAR (fr); - fr.dwForwardDest = htonl (r->network); - fr.dwForwardMask = htonl (r->netmask); - fr.dwForwardPolicy = 0; - fr.dwForwardNextHop = htonl (r->gateway); - fr.dwForwardIfIndex = if_index; - fr.dwForwardType = 4; /* the next hop is not the final dest */ - fr.dwForwardProto = 3; /* PROTO_IP_NETMGMT */ - fr.dwForwardAge = 0; - fr.dwForwardNextHopAS = 0; - fr.dwForwardMetric1 = (r->flags & RT_METRIC_DEFINED) ? r->metric : 1; - fr.dwForwardMetric2 = METRIC_NOT_USED; - fr.dwForwardMetric3 = METRIC_NOT_USED; - fr.dwForwardMetric4 = METRIC_NOT_USED; - fr.dwForwardMetric5 = METRIC_NOT_USED; - - if ((r->network & r->netmask) != r->network) - msg (M_WARN, "Warning: address %s is not a network address in relation to netmask %s", - print_in_addr_t (r->network, 0, &gc), - print_in_addr_t (r->netmask, 0, &gc)); - - status = CreateIpForwardEntry (&fr); - - if (status == NO_ERROR) - ret = true; - else - { - /* failed, try increasing the metric to work around Vista issue */ - const unsigned int forward_metric_limit = 2048; /* iteratively retry higher metrics up to this limit */ - - for ( ; fr.dwForwardMetric1 <= forward_metric_limit; ++fr.dwForwardMetric1) - { - /* try a different forward type=3 ("the next hop is the final dest") in addition to 4. - --redirect-gateway over RRAS seems to need this. */ - for (fr.dwForwardType = 4; fr.dwForwardType >= 3; --fr.dwForwardType) - { - status = CreateIpForwardEntry (&fr); - if (status == NO_ERROR) - { - msg (D_ROUTE, "ROUTE: CreateIpForwardEntry succeeded with dwForwardMetric1=%u and dwForwardType=%u", - (unsigned int)fr.dwForwardMetric1, - (unsigned int)fr.dwForwardType); - ret = true; - goto doublebreak; - } - else if (status != ERROR_BAD_ARGUMENTS) - goto doublebreak; - } - } - - doublebreak: - if (status != NO_ERROR) - msg (M_WARN, "ROUTE: route addition failed using CreateIpForwardEntry: %s [status=%u if_index=%u]", - strerror_win32 (status, &gc), - (unsigned int)status, - (unsigned int)if_index); - } - } - - gc_free (&gc); - return ret; +add_route_ipapi(const struct route_ipv4 *r, const struct tuntap *tt, DWORD adapter_index) +{ + struct gc_arena gc = gc_new(); + bool ret = false; + DWORD status; + const DWORD if_index = (adapter_index == TUN_ADAPTER_INDEX_INVALID) ? windows_route_find_if_index(r, tt) : adapter_index; + + if (if_index != TUN_ADAPTER_INDEX_INVALID) + { + MIB_IPFORWARDROW fr; + CLEAR(fr); + fr.dwForwardDest = htonl(r->network); + fr.dwForwardMask = htonl(r->netmask); + fr.dwForwardPolicy = 0; + fr.dwForwardNextHop = htonl(r->gateway); + fr.dwForwardIfIndex = if_index; + fr.dwForwardType = 4; /* the next hop is not the final dest */ + fr.dwForwardProto = 3; /* PROTO_IP_NETMGMT */ + fr.dwForwardAge = 0; + fr.dwForwardNextHopAS = 0; + fr.dwForwardMetric1 = (r->flags & RT_METRIC_DEFINED) ? r->metric : 1; + fr.dwForwardMetric2 = METRIC_NOT_USED; + fr.dwForwardMetric3 = METRIC_NOT_USED; + fr.dwForwardMetric4 = METRIC_NOT_USED; + fr.dwForwardMetric5 = METRIC_NOT_USED; + + if ((r->network & r->netmask) != r->network) + { + msg(M_WARN, "Warning: address %s is not a network address in relation to netmask %s", + print_in_addr_t(r->network, 0, &gc), + print_in_addr_t(r->netmask, 0, &gc)); + } + + status = CreateIpForwardEntry(&fr); + + if (status == NO_ERROR) + { + ret = true; + } + else + { + /* failed, try increasing the metric to work around Vista issue */ + const unsigned int forward_metric_limit = 2048; /* iteratively retry higher metrics up to this limit */ + + for (; fr.dwForwardMetric1 <= forward_metric_limit; ++fr.dwForwardMetric1) + { + /* try a different forward type=3 ("the next hop is the final dest") in addition to 4. + * --redirect-gateway over RRAS seems to need this. */ + for (fr.dwForwardType = 4; fr.dwForwardType >= 3; --fr.dwForwardType) + { + status = CreateIpForwardEntry(&fr); + if (status == NO_ERROR) + { + msg(D_ROUTE, "ROUTE: CreateIpForwardEntry succeeded with dwForwardMetric1=%u and dwForwardType=%u", + (unsigned int)fr.dwForwardMetric1, + (unsigned int)fr.dwForwardType); + ret = true; + goto doublebreak; + } + else if (status != ERROR_BAD_ARGUMENTS) + { + goto doublebreak; + } + } + } + +doublebreak: + if (status != NO_ERROR) + { + msg(M_WARN, "ROUTE: route addition failed using CreateIpForwardEntry: %s [status=%u if_index=%u]", + strerror_win32(status, &gc), + (unsigned int)status, + (unsigned int)if_index); + } + } + } + + gc_free(&gc); + return ret; } bool -del_route_ipapi (const struct route_ipv4 *r, const struct tuntap *tt) +del_route_ipapi(const struct route_ipv4 *r, const struct tuntap *tt) { - struct gc_arena gc = gc_new (); - bool ret = false; - DWORD status; - const DWORD if_index = windows_route_find_if_index (r, tt); + struct gc_arena gc = gc_new(); + bool ret = false; + DWORD status; + const DWORD if_index = windows_route_find_if_index(r, tt); - if (if_index != TUN_ADAPTER_INDEX_INVALID) + if (if_index != TUN_ADAPTER_INDEX_INVALID) { - MIB_IPFORWARDROW fr; - CLEAR (fr); + MIB_IPFORWARDROW fr; + CLEAR(fr); - fr.dwForwardDest = htonl (r->network); - fr.dwForwardMask = htonl (r->netmask); - fr.dwForwardPolicy = 0; - fr.dwForwardNextHop = htonl (r->gateway); - fr.dwForwardIfIndex = if_index; + fr.dwForwardDest = htonl(r->network); + fr.dwForwardMask = htonl(r->netmask); + fr.dwForwardPolicy = 0; + fr.dwForwardNextHop = htonl(r->gateway); + fr.dwForwardIfIndex = if_index; - status = DeleteIpForwardEntry (&fr); + status = DeleteIpForwardEntry(&fr); - if (status == NO_ERROR) - ret = true; - else - msg (M_WARN, "ROUTE: route deletion failed using DeleteIpForwardEntry: %s", - strerror_win32 (status, &gc)); + if (status == NO_ERROR) + { + ret = true; + } + else + { + msg(M_WARN, "ROUTE: route deletion failed using DeleteIpForwardEntry: %s", + strerror_win32(status, &gc)); + } } - gc_free (&gc); - return ret; + gc_free(&gc); + return ret; } static bool -do_route_service (const bool add, const route_message_t *rt, const size_t size, HANDLE pipe) +do_route_service(const bool add, const route_message_t *rt, const size_t size, HANDLE pipe) { - DWORD len; - bool ret = false; - ack_message_t ack; - struct gc_arena gc = gc_new (); + DWORD len; + bool ret = false; + ack_message_t ack; + struct gc_arena gc = gc_new(); - if (!WriteFile (pipe, rt, size, &len, NULL) || - !ReadFile (pipe, &ack, sizeof (ack), &len, NULL)) + if (!WriteFile(pipe, rt, size, &len, NULL) + || !ReadFile(pipe, &ack, sizeof(ack), &len, NULL)) { - msg (M_WARN, "ROUTE: could not talk to service: %s [%lu]", - strerror_win32 (GetLastError (), &gc), GetLastError ()); - goto out; + msg(M_WARN, "ROUTE: could not talk to service: %s [%lu]", + strerror_win32(GetLastError(), &gc), GetLastError()); + goto out; } - if (ack.error_number != NO_ERROR) + if (ack.error_number != NO_ERROR) { - msg (M_WARN, "ROUTE: route %s failed using service: %s [status=%u if_index=%lu]", - (add ? "addition" : "deletion"), strerror_win32 (ack.error_number, &gc), - ack.error_number, rt->iface.index); - goto out; + msg(M_WARN, "ROUTE: route %s failed using service: %s [status=%u if_index=%lu]", + (add ? "addition" : "deletion"), strerror_win32(ack.error_number, &gc), + ack.error_number, rt->iface.index); + goto out; } - ret = true; + ret = true; out: - gc_free (&gc); - return ret; + gc_free(&gc); + return ret; } static bool -do_route_ipv4_service (const bool add, const struct route_ipv4 *r, const struct tuntap *tt) +do_route_ipv4_service(const bool add, const struct route_ipv4 *r, const struct tuntap *tt) { - DWORD if_index = windows_route_find_if_index (r, tt); - if (if_index == ~0) - return false; - - route_message_t msg = { - .header = { - (add ? msg_add_route : msg_del_route), - sizeof (route_message_t), - 0 }, - .family = AF_INET, - .prefix.ipv4.s_addr = htonl(r->network), - .gateway.ipv4.s_addr = htonl(r->gateway), - .iface = { .index = if_index, .name = "" }, - .metric = (r->flags & RT_METRIC_DEFINED ? r->metric : -1) - }; + DWORD if_index = windows_route_find_if_index(r, tt); + if (if_index == ~0) + { + return false; + } - netmask_to_netbits (r->network, r->netmask, &msg.prefix_len); - if (msg.prefix_len == -1) - msg.prefix_len = 32; + route_message_t msg = { + .header = { + (add ? msg_add_route : msg_del_route), + sizeof(route_message_t), + 0 + }, + .family = AF_INET, + .prefix.ipv4.s_addr = htonl(r->network), + .gateway.ipv4.s_addr = htonl(r->gateway), + .iface = { .index = if_index, .name = "" }, + .metric = (r->flags & RT_METRIC_DEFINED ? r->metric : -1) + }; + + netmask_to_netbits(r->network, r->netmask, &msg.prefix_len); + if (msg.prefix_len == -1) + { + msg.prefix_len = 32; + } - return do_route_service (add, &msg, sizeof (msg), tt->options.msg_channel); + return do_route_service(add, &msg, sizeof(msg), tt->options.msg_channel); } static bool -do_route_ipv6_service (const bool add, const struct route_ipv6 *r, const struct tuntap *tt) +do_route_ipv6_service(const bool add, const struct route_ipv6 *r, const struct tuntap *tt) { - bool status; - route_message_t msg = { - .header = { - (add ? msg_add_route : msg_del_route), - sizeof (route_message_t), - 0 }, - .family = AF_INET6, - .prefix.ipv6 = r->network, - .prefix_len = r->netbits, - .gateway.ipv6 = r->gateway, - .iface = { .index = tt->adapter_index, .name = "" }, - .metric = ( (r->flags & RT_METRIC_DEFINED) ? r->metric : -1) - }; - - if ( r->adapter_index ) /* vpn server special route */ - msg.iface.index = r->adapter_index; + bool status; + route_message_t msg = { + .header = { + (add ? msg_add_route : msg_del_route), + sizeof(route_message_t), + 0 + }, + .family = AF_INET6, + .prefix.ipv6 = r->network, + .prefix_len = r->netbits, + .gateway.ipv6 = r->gateway, + .iface = { .index = tt->adapter_index, .name = "" }, + .metric = ( (r->flags & RT_METRIC_DEFINED) ? r->metric : -1) + }; + + if (r->adapter_index) /* vpn server special route */ + { + msg.iface.index = r->adapter_index; + } - /* In TUN mode we use a special link-local address as the next hop. - * The tapdrvr knows about it and will answer neighbor discovery packets. - */ - if (tt->type == DEV_TYPE_TUN) - inet_pton (AF_INET6, "fe80::8", &msg.gateway.ipv6); + /* In TUN mode we use a special link-local address as the next hop. + * The tapdrvr knows about it and will answer neighbor discovery packets. + */ + if (tt->type == DEV_TYPE_TUN) + { + inet_pton(AF_INET6, "fe80::8", &msg.gateway.ipv6); + } - if (msg.iface.index == TUN_ADAPTER_INDEX_INVALID) + if (msg.iface.index == TUN_ADAPTER_INDEX_INVALID) { - strncpy (msg.iface.name, tt->actual_name, sizeof (msg.iface.name)); - msg.iface.name[sizeof (msg.iface.name) - 1] = '\0'; + strncpy(msg.iface.name, tt->actual_name, sizeof(msg.iface.name)); + msg.iface.name[sizeof(msg.iface.name) - 1] = '\0'; } - status = do_route_service (add, &msg, sizeof (msg), tt->options.msg_channel); - msg (D_ROUTE, "IPv6 route %s via service %s", - add ? "addition" : "deletion", - status ? "succeeded" : "failed"); - return status; + status = do_route_service(add, &msg, sizeof(msg), tt->options.msg_channel); + msg(D_ROUTE, "IPv6 route %s via service %s", + add ? "addition" : "deletion", + status ? "succeeded" : "failed"); + return status; } static bool -add_route_service (const struct route_ipv4 *r, const struct tuntap *tt) +add_route_service(const struct route_ipv4 *r, const struct tuntap *tt) { - return do_route_ipv4_service (true, r, tt); + return do_route_ipv4_service(true, r, tt); } static bool -del_route_service (const struct route_ipv4 *r, const struct tuntap *tt) +del_route_service(const struct route_ipv4 *r, const struct tuntap *tt) { - return do_route_ipv4_service (false, r, tt); + return do_route_ipv4_service(false, r, tt); } static bool -add_route_ipv6_service (const struct route_ipv6 *r, const struct tuntap *tt) +add_route_ipv6_service(const struct route_ipv6 *r, const struct tuntap *tt) { - return do_route_ipv6_service (true, r, tt); + return do_route_ipv6_service(true, r, tt); } static bool -del_route_ipv6_service (const struct route_ipv6 *r, const struct tuntap *tt) +del_route_ipv6_service(const struct route_ipv6 *r, const struct tuntap *tt) { - return do_route_ipv6_service (false, r, tt); + return do_route_ipv6_service(false, r, tt); } static const char * -format_route_entry (const MIB_IPFORWARDROW *r, struct gc_arena *gc) -{ - struct buffer out = alloc_buf_gc (256, gc); - buf_printf (&out, "%s %s %s p=%d i=%d t=%d pr=%d a=%d h=%d m=%d/%d/%d/%d/%d", - print_in_addr_t (r->dwForwardDest, IA_NET_ORDER, gc), - print_in_addr_t (r->dwForwardMask, IA_NET_ORDER, gc), - print_in_addr_t (r->dwForwardNextHop, IA_NET_ORDER, gc), - (int)r->dwForwardPolicy, - (int)r->dwForwardIfIndex, - (int)r->dwForwardType, - (int)r->dwForwardProto, - (int)r->dwForwardAge, - (int)r->dwForwardNextHopAS, - (int)r->dwForwardMetric1, - (int)r->dwForwardMetric2, - (int)r->dwForwardMetric3, - (int)r->dwForwardMetric4, - (int)r->dwForwardMetric5); - return BSTR (&out); +format_route_entry(const MIB_IPFORWARDROW *r, struct gc_arena *gc) +{ + struct buffer out = alloc_buf_gc(256, gc); + buf_printf(&out, "%s %s %s p=%d i=%d t=%d pr=%d a=%d h=%d m=%d/%d/%d/%d/%d", + print_in_addr_t(r->dwForwardDest, IA_NET_ORDER, gc), + print_in_addr_t(r->dwForwardMask, IA_NET_ORDER, gc), + print_in_addr_t(r->dwForwardNextHop, IA_NET_ORDER, gc), + (int)r->dwForwardPolicy, + (int)r->dwForwardIfIndex, + (int)r->dwForwardType, + (int)r->dwForwardProto, + (int)r->dwForwardAge, + (int)r->dwForwardNextHopAS, + (int)r->dwForwardMetric1, + (int)r->dwForwardMetric2, + (int)r->dwForwardMetric3, + (int)r->dwForwardMetric4, + (int)r->dwForwardMetric5); + return BSTR(&out); } /* * Show current routing table */ void -show_routes (int msglev) +show_routes(int msglev) { - struct gc_arena gc = gc_new (); - int i; + struct gc_arena gc = gc_new(); + int i; - const MIB_IPFORWARDTABLE *rt = get_windows_routing_table (&gc); + const MIB_IPFORWARDTABLE *rt = get_windows_routing_table(&gc); - msg (msglev, "SYSTEM ROUTING TABLE"); - if (rt) + msg(msglev, "SYSTEM ROUTING TABLE"); + if (rt) { - for (i = 0; i < rt->dwNumEntries; ++i) - { - msg (msglev, "%s", format_route_entry (&rt->table[i], &gc)); - } + for (i = 0; i < rt->dwNumEntries; ++i) + { + msg(msglev, "%s", format_route_entry(&rt->table[i], &gc)); + } } - gc_free (&gc); + gc_free(&gc); } #elif defined(TARGET_LINUX) || defined(TARGET_ANDROID) void -get_default_gateway (struct route_gateway_info *rgi) +get_default_gateway(struct route_gateway_info *rgi) { - struct gc_arena gc = gc_new (); - int sd = -1; - char best_name[16]; - best_name[0] = 0; + struct gc_arena gc = gc_new(); + int sd = -1; + char best_name[16]; + best_name[0] = 0; - CLEAR(*rgi); + CLEAR(*rgi); #ifndef TARGET_ANDROID - /* get default gateway IP addr */ - { - FILE *fp = fopen ("/proc/net/route", "r"); - if (fp) - { - char line[256]; - int count = 0; - unsigned int lowest_metric = UINT_MAX; - in_addr_t best_gw = 0; - bool found = false; - while (fgets (line, sizeof (line), fp) != NULL) - { - if (count) - { - unsigned int net_x = 0; - unsigned int mask_x = 0; - unsigned int gw_x = 0; - unsigned int metric = 0; - unsigned int flags = 0; - char name[16]; - name[0] = 0; - const int np = sscanf (line, "%15s\t%x\t%x\t%x\t%*s\t%*s\t%d\t%x", - name, - &net_x, - &gw_x, - &flags, - &metric, - &mask_x); - if (np == 6 && (flags & IFF_UP)) - { - const in_addr_t net = ntohl (net_x); - const in_addr_t mask = ntohl (mask_x); - const in_addr_t gw = ntohl (gw_x); - - if (!net && !mask && metric < lowest_metric) - { - found = true; - best_gw = gw; - strcpy (best_name, name); - lowest_metric = metric; - } - } - } - ++count; - } - fclose (fp); - - if (found) - { - rgi->gateway.addr = best_gw; - rgi->flags |= RGI_ADDR_DEFINED; - if (!rgi->gateway.addr && best_name[0]) - rgi->flags |= RGI_ON_LINK; - } - } - } -#else - /* Android, set some pseudo GW, addr is in host byte order, - * Determining the default GW on Android 5.0+ is non trivial - * and serves almost no purpose since OpenVPN only uses the - * default GW address to add routes for networks that should - * NOT be routed over the VPN. Using a well known address - * (127.'d'.'g'.'w') for the default GW make detecting - * these routes easier from the controlling app. - */ - rgi->gateway.addr = 127 << 24 | 'd' << 16 | 'g' << 8 | 'w'; - rgi->flags |= RGI_ADDR_DEFINED; - strcpy(best_name, "android-gw"); -#endif + /* get default gateway IP addr */ + { + FILE *fp = fopen("/proc/net/route", "r"); + if (fp) + { + char line[256]; + int count = 0; + unsigned int lowest_metric = UINT_MAX; + in_addr_t best_gw = 0; + bool found = false; + while (fgets(line, sizeof(line), fp) != NULL) + { + if (count) + { + unsigned int net_x = 0; + unsigned int mask_x = 0; + unsigned int gw_x = 0; + unsigned int metric = 0; + unsigned int flags = 0; + char name[16]; + name[0] = 0; + const int np = sscanf(line, "%15s\t%x\t%x\t%x\t%*s\t%*s\t%d\t%x", + name, + &net_x, + &gw_x, + &flags, + &metric, + &mask_x); + if (np == 6 && (flags & IFF_UP)) + { + const in_addr_t net = ntohl(net_x); + const in_addr_t mask = ntohl(mask_x); + const in_addr_t gw = ntohl(gw_x); + + if (!net && !mask && metric < lowest_metric) + { + found = true; + best_gw = gw; + strcpy(best_name, name); + lowest_metric = metric; + } + } + } + ++count; + } + fclose(fp); + + if (found) + { + rgi->gateway.addr = best_gw; + rgi->flags |= RGI_ADDR_DEFINED; + if (!rgi->gateway.addr && best_name[0]) + { + rgi->flags |= RGI_ON_LINK; + } + } + } + } +#else /* ifndef TARGET_ANDROID */ + /* Android, set some pseudo GW, addr is in host byte order, + * Determining the default GW on Android 5.0+ is non trivial + * and serves almost no purpose since OpenVPN only uses the + * default GW address to add routes for networks that should + * NOT be routed over the VPN. Using a well known address + * (127.'d'.'g'.'w') for the default GW make detecting + * these routes easier from the controlling app. + */ + rgi->gateway.addr = 127 << 24 | 'd' << 16 | 'g' << 8 | 'w'; + rgi->flags |= RGI_ADDR_DEFINED; + strcpy(best_name, "android-gw"); +#endif /* ifndef TARGET_ANDROID */ + + /* scan adapter list */ + if (rgi->flags & RGI_ADDR_DEFINED) + { + struct ifreq *ifr, *ifend; + in_addr_t addr, netmask; + struct ifreq ifreq; + struct ifconf ifc; + struct ifreq ifs[20]; /* Maximum number of interfaces to scan */ + + if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + { + msg(M_WARN, "GDG: socket() failed"); + goto done; + } + ifc.ifc_len = sizeof(ifs); + ifc.ifc_req = ifs; + if (ioctl(sd, SIOCGIFCONF, &ifc) < 0) + { + msg(M_WARN, "GDG: ioctl(SIOCGIFCONF) failed"); + goto done; + } - /* scan adapter list */ - if (rgi->flags & RGI_ADDR_DEFINED) - { - struct ifreq *ifr, *ifend; - in_addr_t addr, netmask; - struct ifreq ifreq; - struct ifconf ifc; - struct ifreq ifs[20]; /* Maximum number of interfaces to scan */ - - if ((sd = socket (AF_INET, SOCK_DGRAM, 0)) < 0) - { - msg (M_WARN, "GDG: socket() failed"); - goto done; - } - ifc.ifc_len = sizeof (ifs); - ifc.ifc_req = ifs; - if (ioctl (sd, SIOCGIFCONF, &ifc) < 0) - { - msg (M_WARN, "GDG: ioctl(SIOCGIFCONF) failed"); - goto done; - } - - /* scan through interface list */ - ifend = ifs + (ifc.ifc_len / sizeof (struct ifreq)); - for (ifr = ifc.ifc_req; ifr < ifend; ifr++) - { - if (ifr->ifr_addr.sa_family == AF_INET) - { - /* get interface addr */ - addr = ntohl(((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr); - - /* get interface name */ - strncpynt (ifreq.ifr_name, ifr->ifr_name, sizeof (ifreq.ifr_name)); - - /* check that the interface is up */ - if (ioctl (sd, SIOCGIFFLAGS, &ifreq) < 0) - continue; - if (!(ifreq.ifr_flags & IFF_UP)) - continue; - - if (rgi->flags & RGI_ON_LINK) - { - /* check that interface name of current interface - matches interface name of best default route */ - if (strcmp(ifreq.ifr_name, best_name)) - continue; + /* scan through interface list */ + ifend = ifs + (ifc.ifc_len / sizeof(struct ifreq)); + for (ifr = ifc.ifc_req; ifr < ifend; ifr++) + { + if (ifr->ifr_addr.sa_family == AF_INET) + { + /* get interface addr */ + addr = ntohl(((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr); + + /* get interface name */ + strncpynt(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name)); + + /* check that the interface is up */ + if (ioctl(sd, SIOCGIFFLAGS, &ifreq) < 0) + { + continue; + } + if (!(ifreq.ifr_flags & IFF_UP)) + { + continue; + } + + if (rgi->flags & RGI_ON_LINK) + { + /* check that interface name of current interface + * matches interface name of best default route */ + if (strcmp(ifreq.ifr_name, best_name)) + { + continue; + } #if 0 - /* if point-to-point link, use remote addr as route gateway */ - if ((ifreq.ifr_flags & IFF_POINTOPOINT) && ioctl (sd, SIOCGIFDSTADDR, &ifreq) >= 0) - { - rgi->gateway.addr = ntohl(((struct sockaddr_in *) &ifreq.ifr_addr)->sin_addr.s_addr); - if (rgi->gateway.addr) - rgi->flags &= ~RGI_ON_LINK; - } + /* if point-to-point link, use remote addr as route gateway */ + if ((ifreq.ifr_flags & IFF_POINTOPOINT) && ioctl(sd, SIOCGIFDSTADDR, &ifreq) >= 0) + { + rgi->gateway.addr = ntohl(((struct sockaddr_in *) &ifreq.ifr_addr)->sin_addr.s_addr); + if (rgi->gateway.addr) + { + rgi->flags &= ~RGI_ON_LINK; + } + } #endif - } - else - { - /* get interface netmask */ - if (ioctl (sd, SIOCGIFNETMASK, &ifreq) < 0) - continue; - netmask = ntohl(((struct sockaddr_in *) &ifreq.ifr_addr)->sin_addr.s_addr); - - /* check that interface matches default route */ - if (((rgi->gateway.addr ^ addr) & netmask) != 0) - continue; - - /* save netmask */ - rgi->gateway.netmask = netmask; - rgi->flags |= RGI_NETMASK_DEFINED; - } - - /* save iface name */ - strncpynt (rgi->iface, ifreq.ifr_name, sizeof(rgi->iface)); - rgi->flags |= RGI_IFACE_DEFINED; - - /* now get the hardware address. */ - memset (&ifreq.ifr_hwaddr, 0, sizeof (struct sockaddr)); - if (ioctl (sd, SIOCGIFHWADDR, &ifreq) < 0) - { - msg (M_WARN, "GDG: SIOCGIFHWADDR(%s) failed", ifreq.ifr_name); - goto done; - } - memcpy (rgi->hwaddr, &ifreq.ifr_hwaddr.sa_data, 6); - rgi->flags |= RGI_HWADDR_DEFINED; - - break; - } - } - } - - done: - if (sd >= 0) - close (sd); - gc_free (&gc); + } + else + { + /* get interface netmask */ + if (ioctl(sd, SIOCGIFNETMASK, &ifreq) < 0) + { + continue; + } + netmask = ntohl(((struct sockaddr_in *) &ifreq.ifr_addr)->sin_addr.s_addr); + + /* check that interface matches default route */ + if (((rgi->gateway.addr ^ addr) & netmask) != 0) + { + continue; + } + + /* save netmask */ + rgi->gateway.netmask = netmask; + rgi->flags |= RGI_NETMASK_DEFINED; + } + + /* save iface name */ + strncpynt(rgi->iface, ifreq.ifr_name, sizeof(rgi->iface)); + rgi->flags |= RGI_IFACE_DEFINED; + + /* now get the hardware address. */ + memset(&ifreq.ifr_hwaddr, 0, sizeof(struct sockaddr)); + if (ioctl(sd, SIOCGIFHWADDR, &ifreq) < 0) + { + msg(M_WARN, "GDG: SIOCGIFHWADDR(%s) failed", ifreq.ifr_name); + goto done; + } + memcpy(rgi->hwaddr, &ifreq.ifr_hwaddr.sa_data, 6); + rgi->flags |= RGI_HWADDR_DEFINED; + + break; + } + } + } + +done: + if (sd >= 0) + { + close(sd); + } + gc_free(&gc); } /* IPv6 implementation using netlink @@ -3070,14 +3336,14 @@ get_default_gateway (struct route_gateway_info *rgi) * http://www.virtualbox.org/svn/vbox/trunk/src/VBox/NetworkServices/NAT/rtmon_linux.c */ struct rtreq { - struct nlmsghdr nh; - struct rtmsg rtm; - char attrbuf[512]; + struct nlmsghdr nh; + struct rtmsg rtm; + char attrbuf[512]; }; void get_default_gateway_ipv6(struct route_ipv6_gateway_info *rgi6, - const struct in6_addr *dest) + const struct in6_addr *dest) { int nls = -1; struct rtreq rtreq; @@ -3089,8 +3355,10 @@ get_default_gateway_ipv6(struct route_ipv6_gateway_info *rgi6, CLEAR(*rgi6); nls = socket( PF_NETLINK, SOCK_RAW, NETLINK_ROUTE ); - if ( nls < 0 ) - { msg(M_WARN|M_ERRNO, "GDG6: socket() failed" ); goto done; } + if (nls < 0) + { + msg(M_WARN|M_ERRNO, "GDG6: socket() failed" ); goto done; + } /* bind() is not needed, no unsolicited msgs coming in */ @@ -3098,10 +3366,10 @@ get_default_gateway_ipv6(struct route_ipv6_gateway_info *rgi6, */ CLEAR(rtreq); rtreq.nh.nlmsg_type = RTM_GETROUTE; - rtreq.nh.nlmsg_flags = NLM_F_REQUEST; /* best match only */ + rtreq.nh.nlmsg_flags = NLM_F_REQUEST; /* best match only */ rtreq.rtm.rtm_family = AF_INET6; - rtreq.rtm.rtm_src_len = 0; /* not source dependent */ - rtreq.rtm.rtm_dst_len = 128; /* exact dst */ + rtreq.rtm.rtm_src_len = 0; /* not source dependent */ + rtreq.rtm.rtm_dst_len = 128; /* exact dst */ rtreq.rtm.rtm_table = RT_TABLE_MAIN; rtreq.rtm.rtm_protocol = RTPROT_UNSPEC; rtreq.nh.nlmsg_len = NLMSG_SPACE(sizeof(rtreq.rtm)); @@ -3110,27 +3378,35 @@ get_default_gateway_ipv6(struct route_ipv6_gateway_info *rgi6, rta = (struct rtattr *)(((char *) &rtreq)+NLMSG_ALIGN(rtreq.nh.nlmsg_len)); rta->rta_type = RTA_DST; rta->rta_len = RTA_LENGTH(16); - rtreq.nh.nlmsg_len = NLMSG_ALIGN(rtreq.nh.nlmsg_len) + - RTA_LENGTH(16); + rtreq.nh.nlmsg_len = NLMSG_ALIGN(rtreq.nh.nlmsg_len) + +RTA_LENGTH(16); - if ( dest == NULL ) /* ::, unspecified */ - memset( RTA_DATA(rta), 0, 16 ); /* :: = all-zero */ + if (dest == NULL) /* ::, unspecified */ + { + memset( RTA_DATA(rta), 0, 16 ); /* :: = all-zero */ + } else - memcpy( RTA_DATA(rta), (void *)dest, 16 ); + { + memcpy( RTA_DATA(rta), (void *)dest, 16 ); + } /* send and receive reply */ - if ( send( nls, &rtreq, rtreq.nh.nlmsg_len, 0 ) < 0 ) - { msg(M_WARN|M_ERRNO, "GDG6: send() failed" ); goto done; } + if (send( nls, &rtreq, rtreq.nh.nlmsg_len, 0 ) < 0) + { + msg(M_WARN|M_ERRNO, "GDG6: send() failed" ); goto done; + } ssize = recv(nls, rtbuf, sizeof(rtbuf), MSG_TRUNC); if (ssize < 0) - { msg(M_WARN|M_ERRNO, "GDG6: recv() failed" ); goto done; } + { + msg(M_WARN|M_ERRNO, "GDG6: recv() failed" ); goto done; + } if (ssize > sizeof(rtbuf)) { - msg(M_WARN, "get_default_gateway_ipv6: returned message too big for buffer (%d>%d)", (int)ssize, (int)sizeof(rtbuf) ); - goto done; + msg(M_WARN, "get_default_gateway_ipv6: returned message too big for buffer (%d>%d)", (int)ssize, (int)sizeof(rtbuf) ); + goto done; } struct nlmsghdr *nh; @@ -3139,74 +3415,91 @@ get_default_gateway_ipv6(struct route_ipv6_gateway_info *rgi6, NLMSG_OK(nh, ssize); nh = NLMSG_NEXT(nh, ssize)) { - struct rtmsg *rtm; - int attrlen; - - if (nh->nlmsg_type == NLMSG_DONE) { break; } - - if (nh->nlmsg_type == NLMSG_ERROR) { - struct nlmsgerr *ne = (struct nlmsgerr *)NLMSG_DATA(nh); - msg(M_WARN, "GDG6: NLSMG_ERROR: error %d\n", ne->error); - break; - } - - if (nh->nlmsg_type != RTM_NEWROUTE) { - /* shouldn't happen */ - msg(M_WARN, "GDG6: unexpected msg_type %d", nh->nlmsg_type ); - continue; - } - - rtm = (struct rtmsg *)NLMSG_DATA(nh); - attrlen = RTM_PAYLOAD(nh); - - /* we're only looking for routes in the main table, as "we have - * no IPv6" will lead to a lookup result in "Local" (::/0 reject) - */ - if (rtm->rtm_family != AF_INET6 || - rtm->rtm_table != RT_TABLE_MAIN) - { continue; } /* we're not interested */ - - for (rta = RTM_RTA(rtm); - RTA_OK(rta, attrlen); - rta = RTA_NEXT(rta, attrlen)) - { - if (rta->rta_type == RTA_GATEWAY) { - if ( RTA_PAYLOAD(rta) != sizeof(struct in6_addr) ) - { msg(M_WARN, "GDG6: RTA_GW size mismatch"); continue; } - rgi6->gateway.addr_ipv6 = *(struct in6_addr*) RTA_DATA(rta); - rgi6->flags |= RGI_ADDR_DEFINED; - } - else if (rta->rta_type == RTA_OIF) { - char ifname[IF_NAMESIZE+1]; - int oif; - if ( RTA_PAYLOAD(rta) != sizeof(oif) ) - { msg(M_WARN, "GDG6: oif size mismatch"); continue; } - - memcpy(&oif, RTA_DATA(rta), sizeof(oif)); - if_indextoname(oif,ifname); - strncpy( rgi6->iface, ifname, sizeof(rgi6->iface)-1 ); - rgi6->flags |= RGI_IFACE_DEFINED; - } - } + struct rtmsg *rtm; + int attrlen; + + if (nh->nlmsg_type == NLMSG_DONE) + { + break; + } + + if (nh->nlmsg_type == NLMSG_ERROR) + { + struct nlmsgerr *ne = (struct nlmsgerr *)NLMSG_DATA(nh); + msg(M_WARN, "GDG6: NLSMG_ERROR: error %d\n", ne->error); + break; + } + + if (nh->nlmsg_type != RTM_NEWROUTE) + { + /* shouldn't happen */ + msg(M_WARN, "GDG6: unexpected msg_type %d", nh->nlmsg_type ); + continue; + } + + rtm = (struct rtmsg *)NLMSG_DATA(nh); + attrlen = RTM_PAYLOAD(nh); + + /* we're only looking for routes in the main table, as "we have + * no IPv6" will lead to a lookup result in "Local" (::/0 reject) + */ + if (rtm->rtm_family != AF_INET6 + || rtm->rtm_table != RT_TABLE_MAIN) + { + continue; + } /* we're not interested */ + + for (rta = RTM_RTA(rtm); + RTA_OK(rta, attrlen); + rta = RTA_NEXT(rta, attrlen)) + { + if (rta->rta_type == RTA_GATEWAY) + { + if (RTA_PAYLOAD(rta) != sizeof(struct in6_addr) ) + { + msg(M_WARN, "GDG6: RTA_GW size mismatch"); continue; + } + rgi6->gateway.addr_ipv6 = *(struct in6_addr *) RTA_DATA(rta); + rgi6->flags |= RGI_ADDR_DEFINED; + } + else if (rta->rta_type == RTA_OIF) + { + char ifname[IF_NAMESIZE+1]; + int oif; + if (RTA_PAYLOAD(rta) != sizeof(oif) ) + { + msg(M_WARN, "GDG6: oif size mismatch"); continue; + } + + memcpy(&oif, RTA_DATA(rta), sizeof(oif)); + if_indextoname(oif,ifname); + strncpy( rgi6->iface, ifname, sizeof(rgi6->iface)-1 ); + rgi6->flags |= RGI_IFACE_DEFINED; + } + } } /* if we have an interface but no gateway, the destination is on-link */ if ( ( rgi6->flags & (RGI_IFACE_DEFINED|RGI_ADDR_DEFINED) ) == - RGI_IFACE_DEFINED ) + RGI_IFACE_DEFINED) { - rgi6->flags |= (RGI_ADDR_DEFINED | RGI_ON_LINK); - if ( dest ) - rgi6->gateway.addr_ipv6 = *dest; + rgi6->flags |= (RGI_ADDR_DEFINED | RGI_ON_LINK); + if (dest) + { + rgi6->gateway.addr_ipv6 = *dest; + } } - done: +done: if (nls >= 0) - close (nls); + { + close(nls); + } } -#elif defined(TARGET_DARWIN) || defined(TARGET_SOLARIS) || \ - defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY) || \ - defined(TARGET_OPENBSD) || defined(TARGET_NETBSD) +#elif defined(TARGET_DARWIN) || defined(TARGET_SOLARIS) \ + || defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY) \ + || defined(TARGET_OPENBSD) || defined(TARGET_NETBSD) #include #include @@ -3215,8 +3508,8 @@ get_default_gateway_ipv6(struct route_ipv6_gateway_info *rgi6, #include struct rtmsg { - struct rt_msghdr m_rtm; - char m_space[512]; + struct rt_msghdr m_rtm; + char m_space[512]; }; /* the route socket code is identical for all 4 supported BSDs and for @@ -3232,25 +3525,25 @@ struct rtmsg { */ #if defined(TARGET_DARWIN) -# define ROUNDUP(a) \ - ((a) > 0 ? (1 + (((a) - 1) | (sizeof(uint32_t) - 1))) : sizeof(uint32_t)) +#define ROUNDUP(a) \ + ((a) > 0 ? (1 + (((a) - 1) | (sizeof(uint32_t) - 1))) : sizeof(uint32_t)) #else -# define ROUNDUP(a) \ - ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) +#define ROUNDUP(a) \ + ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) #endif #if defined(TARGET_SOLARIS) #define NEXTADDR(w, u) \ - if (rtm_addrs & (w)) {\ - l = ROUNDUP(sizeof(u)); memmove(cp, &(u), l); cp += l;\ - } + if (rtm_addrs & (w)) { \ + l = ROUNDUP(sizeof(u)); memmove(cp, &(u), l); cp += l; \ + } #define ADVANCE(x, n) (x += ROUNDUP(sizeof(struct sockaddr_in))) -#else +#else /* if defined(TARGET_SOLARIS) */ #define NEXTADDR(w, u) \ - if (rtm_addrs & (w)) {\ - l = ROUNDUP( ((struct sockaddr *)&(u))->sa_len); memmove(cp, &(u), l); cp += l;\ - } + if (rtm_addrs & (w)) { \ + l = ROUNDUP( ((struct sockaddr *)&(u))->sa_len); memmove(cp, &(u), l); cp += l; \ + } #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) #endif @@ -3258,193 +3551,206 @@ struct rtmsg { #define max(a,b) ((a) > (b) ? (a) : (b)) void -get_default_gateway (struct route_gateway_info *rgi) +get_default_gateway(struct route_gateway_info *rgi) { - struct gc_arena gc = gc_new (); - struct rtmsg m_rtmsg; - int sockfd = -1; - int seq, l, pid, rtm_addrs; - unsigned int i; - struct sockaddr so_dst, so_mask; - char *cp = m_rtmsg.m_space; - struct sockaddr *gate = NULL, *ifp = NULL, *sa; - struct rt_msghdr *rtm_aux; + struct gc_arena gc = gc_new(); + struct rtmsg m_rtmsg; + int sockfd = -1; + int seq, l, pid, rtm_addrs; + unsigned int i; + struct sockaddr so_dst, so_mask; + char *cp = m_rtmsg.m_space; + struct sockaddr *gate = NULL, *ifp = NULL, *sa; + struct rt_msghdr *rtm_aux; -# define rtm m_rtmsg.m_rtm +#define rtm m_rtmsg.m_rtm - CLEAR(*rgi); + CLEAR(*rgi); - /* setup data to send to routing socket */ - pid = getpid(); - seq = 0; - rtm_addrs = RTA_DST | RTA_NETMASK | RTA_IFP; + /* setup data to send to routing socket */ + pid = getpid(); + seq = 0; + rtm_addrs = RTA_DST | RTA_NETMASK | RTA_IFP; - bzero(&m_rtmsg, sizeof(m_rtmsg)); - bzero(&so_dst, sizeof(so_dst)); - bzero(&so_mask, sizeof(so_mask)); - bzero(&rtm, sizeof(struct rt_msghdr)); + bzero(&m_rtmsg, sizeof(m_rtmsg)); + bzero(&so_dst, sizeof(so_dst)); + bzero(&so_mask, sizeof(so_mask)); + bzero(&rtm, sizeof(struct rt_msghdr)); - rtm.rtm_type = RTM_GET; - rtm.rtm_flags = RTF_UP | RTF_GATEWAY; - rtm.rtm_version = RTM_VERSION; - rtm.rtm_seq = ++seq; - rtm.rtm_addrs = rtm_addrs; + rtm.rtm_type = RTM_GET; + rtm.rtm_flags = RTF_UP | RTF_GATEWAY; + rtm.rtm_version = RTM_VERSION; + rtm.rtm_seq = ++seq; + rtm.rtm_addrs = rtm_addrs; - so_dst.sa_family = AF_INET; - so_mask.sa_family = AF_INET; + so_dst.sa_family = AF_INET; + so_mask.sa_family = AF_INET; #ifndef TARGET_SOLARIS - so_dst.sa_len = sizeof(struct sockaddr_in); - so_mask.sa_len = sizeof(struct sockaddr_in); + so_dst.sa_len = sizeof(struct sockaddr_in); + so_mask.sa_len = sizeof(struct sockaddr_in); #endif - NEXTADDR(RTA_DST, so_dst); - NEXTADDR(RTA_NETMASK, so_mask); - - rtm.rtm_msglen = l = cp - (char *)&m_rtmsg; - - /* transact with routing socket */ - sockfd = socket(PF_ROUTE, SOCK_RAW, 0); - if (sockfd < 0) - { - msg (M_WARN, "GDG: socket #1 failed"); - goto done; - } - if (write(sockfd, (char *)&m_rtmsg, l) < 0) - { - msg (M_WARN, "GDG: problem writing to routing socket"); - goto done; - } - do { - l = read(sockfd, (char *)&m_rtmsg, sizeof(m_rtmsg)); - } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid)); - close(sockfd); - sockfd = -1; - - /* extract return data from routing socket */ - rtm_aux = &rtm; - cp = ((char *)(rtm_aux + 1)); - if (rtm_aux->rtm_addrs) - { - for (i = 1; i; i <<= 1) - { - if (i & rtm_aux->rtm_addrs) - { - sa = (struct sockaddr *)cp; - if (i == RTA_GATEWAY ) - gate = sa; - else if (i == RTA_IFP) - ifp = sa; - ADVANCE(cp, sa); - } - } - } - else - goto done; - - /* get gateway addr and interface name */ - if (gate != NULL ) - { - /* get default gateway addr */ - rgi->gateway.addr = ntohl(((struct sockaddr_in *)gate)->sin_addr.s_addr); - if (rgi->gateway.addr) - rgi->flags |= RGI_ADDR_DEFINED; - - if (ifp) - { - /* get interface name */ - const struct sockaddr_dl *adl = (struct sockaddr_dl *) ifp; - if (adl->sdl_nlen && adl->sdl_nlen < sizeof(rgi->iface)) - { - memcpy (rgi->iface, adl->sdl_data, adl->sdl_nlen); - rgi->iface[adl->sdl_nlen] = '\0'; - rgi->flags |= RGI_IFACE_DEFINED; - } - } - } - - /* get netmask of interface that owns default gateway */ - if (rgi->flags & RGI_IFACE_DEFINED) { - struct ifreq ifr; - - sockfd = socket(AF_INET, SOCK_DGRAM, 0); + NEXTADDR(RTA_DST, so_dst); + NEXTADDR(RTA_NETMASK, so_mask); + + rtm.rtm_msglen = l = cp - (char *)&m_rtmsg; + + /* transact with routing socket */ + sockfd = socket(PF_ROUTE, SOCK_RAW, 0); if (sockfd < 0) - { - msg (M_WARN, "GDG: socket #2 failed"); - goto done; - } - - CLEAR(ifr); - ifr.ifr_addr.sa_family = AF_INET; - strncpynt(ifr.ifr_name, rgi->iface, IFNAMSIZ); - - if (ioctl(sockfd, SIOCGIFNETMASK, (char *)&ifr) < 0) - { - msg (M_WARN, "GDG: ioctl #1 failed"); - goto done; - } + { + msg(M_WARN, "GDG: socket #1 failed"); + goto done; + } + if (write(sockfd, (char *)&m_rtmsg, l) < 0) + { + msg(M_WARN, "GDG: problem writing to routing socket"); + goto done; + } + do { + l = read(sockfd, (char *)&m_rtmsg, sizeof(m_rtmsg)); + } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid)); close(sockfd); sockfd = -1; - rgi->gateway.netmask = ntohl(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr); - rgi->flags |= RGI_NETMASK_DEFINED; - } - - /* try to read MAC addr associated with interface that owns default gateway */ - if (rgi->flags & RGI_IFACE_DEFINED) - { - struct ifconf ifc; - struct ifreq *ifr; - const int bufsize = 4096; - char *buffer; - - buffer = (char *) gc_malloc (bufsize, true, &gc); - sockfd = socket(AF_INET, SOCK_DGRAM, 0); - if (sockfd < 0) - { - msg (M_WARN, "GDG: socket #3 failed"); - goto done; - } - - ifc.ifc_len = bufsize; - ifc.ifc_buf = buffer; - - if (ioctl(sockfd, SIOCGIFCONF, (char *)&ifc) < 0) - { - msg (M_WARN, "GDG: ioctl #2 failed"); - goto done; - } - close(sockfd); - sockfd = -1; - - for (cp = buffer; cp <= buffer + ifc.ifc_len - sizeof(struct ifreq); ) - { - ifr = (struct ifreq *)cp; + /* extract return data from routing socket */ + rtm_aux = &rtm; + cp = ((char *)(rtm_aux + 1)); + if (rtm_aux->rtm_addrs) + { + for (i = 1; i; i <<= 1) + { + if (i & rtm_aux->rtm_addrs) + { + sa = (struct sockaddr *)cp; + if (i == RTA_GATEWAY) + { + gate = sa; + } + else if (i == RTA_IFP) + { + ifp = sa; + } + ADVANCE(cp, sa); + } + } + } + else + { + goto done; + } + + /* get gateway addr and interface name */ + if (gate != NULL) + { + /* get default gateway addr */ + rgi->gateway.addr = ntohl(((struct sockaddr_in *)gate)->sin_addr.s_addr); + if (rgi->gateway.addr) + { + rgi->flags |= RGI_ADDR_DEFINED; + } + + if (ifp) + { + /* get interface name */ + const struct sockaddr_dl *adl = (struct sockaddr_dl *) ifp; + if (adl->sdl_nlen && adl->sdl_nlen < sizeof(rgi->iface)) + { + memcpy(rgi->iface, adl->sdl_data, adl->sdl_nlen); + rgi->iface[adl->sdl_nlen] = '\0'; + rgi->flags |= RGI_IFACE_DEFINED; + } + } + } + + /* get netmask of interface that owns default gateway */ + if (rgi->flags & RGI_IFACE_DEFINED) + { + struct ifreq ifr; + + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd < 0) + { + msg(M_WARN, "GDG: socket #2 failed"); + goto done; + } + + CLEAR(ifr); + ifr.ifr_addr.sa_family = AF_INET; + strncpynt(ifr.ifr_name, rgi->iface, IFNAMSIZ); + + if (ioctl(sockfd, SIOCGIFNETMASK, (char *)&ifr) < 0) + { + msg(M_WARN, "GDG: ioctl #1 failed"); + goto done; + } + close(sockfd); + sockfd = -1; + + rgi->gateway.netmask = ntohl(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr); + rgi->flags |= RGI_NETMASK_DEFINED; + } + + /* try to read MAC addr associated with interface that owns default gateway */ + if (rgi->flags & RGI_IFACE_DEFINED) + { + struct ifconf ifc; + struct ifreq *ifr; + const int bufsize = 4096; + char *buffer; + + buffer = (char *) gc_malloc(bufsize, true, &gc); + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd < 0) + { + msg(M_WARN, "GDG: socket #3 failed"); + goto done; + } + + ifc.ifc_len = bufsize; + ifc.ifc_buf = buffer; + + if (ioctl(sockfd, SIOCGIFCONF, (char *)&ifc) < 0) + { + msg(M_WARN, "GDG: ioctl #2 failed"); + goto done; + } + close(sockfd); + sockfd = -1; + + for (cp = buffer; cp <= buffer + ifc.ifc_len - sizeof(struct ifreq); ) + { + ifr = (struct ifreq *)cp; #if defined(TARGET_SOLARIS) - const size_t len = sizeof(ifr->ifr_name) + sizeof(ifr->ifr_addr); + const size_t len = sizeof(ifr->ifr_name) + sizeof(ifr->ifr_addr); #else - const size_t len = sizeof(ifr->ifr_name) + max(sizeof(ifr->ifr_addr), ifr->ifr_addr.sa_len); + const size_t len = sizeof(ifr->ifr_name) + max(sizeof(ifr->ifr_addr), ifr->ifr_addr.sa_len); #endif - if (!ifr->ifr_addr.sa_family) - break; - if (!strncmp(ifr->ifr_name, rgi->iface, IFNAMSIZ)) - { - if (ifr->ifr_addr.sa_family == AF_LINK) - { - struct sockaddr_dl *sdl = (struct sockaddr_dl *)&ifr->ifr_addr; - memcpy(rgi->hwaddr, LLADDR(sdl), 6); - rgi->flags |= RGI_HWADDR_DEFINED; - } - } - cp += len; - } - } - - done: - if (sockfd >= 0) - close(sockfd); - gc_free (&gc); + if (!ifr->ifr_addr.sa_family) + { + break; + } + if (!strncmp(ifr->ifr_name, rgi->iface, IFNAMSIZ)) + { + if (ifr->ifr_addr.sa_family == AF_LINK) + { + struct sockaddr_dl *sdl = (struct sockaddr_dl *)&ifr->ifr_addr; + memcpy(rgi->hwaddr, LLADDR(sdl), 6); + rgi->flags |= RGI_HWADDR_DEFINED; + } + } + cp += len; + } + } + +done: + if (sockfd >= 0) + { + close(sockfd); + } + gc_free(&gc); } /* BSD implementation using routing socket (as does IPv4) @@ -3455,13 +3761,13 @@ get_default_gateway (struct route_gateway_info *rgi) /* Solaris has no length field - this is ugly, but less #ifdef in total */ #if defined(TARGET_SOLARIS) -# undef ADVANCE -# define ADVANCE(x, n) (x += ROUNDUP(sizeof(struct sockaddr_in6))) +#undef ADVANCE +#define ADVANCE(x, n) (x += ROUNDUP(sizeof(struct sockaddr_in6))) #endif void get_default_gateway_ipv6(struct route_ipv6_gateway_info *rgi6, - const struct in6_addr *dest) + const struct in6_addr *dest) { struct rtmsg m_rtmsg; @@ -3493,12 +3799,12 @@ get_default_gateway_ipv6(struct route_ipv6_gateway_info *rgi6, so_dst.sin6_family = AF_INET6; so_mask.sin6_family = AF_INET6; - if ( dest != NULL && /* specific host? */ - !IN6_IS_ADDR_UNSPECIFIED(dest) ) + if (dest != NULL /* specific host? */ + && !IN6_IS_ADDR_UNSPECIFIED(dest) ) { - so_dst.sin6_addr = *dest; - /* :: needs /0 "netmask", host route wants "no netmask */ - rtm_addrs &= ~RTA_NETMASK; + so_dst.sin6_addr = *dest; + /* :: needs /0 "netmask", host route wants "no netmask */ + rtm_addrs &= ~RTA_NETMASK; } rtm.rtm_addrs = rtm_addrs; @@ -3517,18 +3823,18 @@ get_default_gateway_ipv6(struct route_ipv6_gateway_info *rgi6, sockfd = socket(PF_ROUTE, SOCK_RAW, 0); if (sockfd < 0) { - msg (M_WARN, "GDG6: socket #1 failed"); - goto done; + msg(M_WARN, "GDG6: socket #1 failed"); + goto done; } if (write(sockfd, (char *)&m_rtmsg, l) < 0) { - msg (M_WARN, "GDG6: problem writing to routing socket"); - goto done; + msg(M_WARN, "GDG6: problem writing to routing socket"); + goto done; } do { - l = read(sockfd, (char *)&m_rtmsg, sizeof(m_rtmsg)); + l = read(sockfd, (char *)&m_rtmsg, sizeof(m_rtmsg)); } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid)); @@ -3540,70 +3846,78 @@ get_default_gateway_ipv6(struct route_ipv6_gateway_info *rgi6, cp = ((char *)(rtm_aux + 1)); if (rtm_aux->rtm_addrs) { - for (i = 1; i; i <<= 1) - { - if (i & rtm_aux->rtm_addrs) - { - sa = (struct sockaddr *)cp; - if (i == RTA_GATEWAY ) - gate = sa; - else if (i == RTA_IFP) - ifp = sa; - ADVANCE(cp, sa); - } - } + for (i = 1; i; i <<= 1) + { + if (i & rtm_aux->rtm_addrs) + { + sa = (struct sockaddr *)cp; + if (i == RTA_GATEWAY) + { + gate = sa; + } + else if (i == RTA_IFP) + { + ifp = sa; + } + ADVANCE(cp, sa); + } + } } else - goto done; + { + goto done; + } /* get gateway addr and interface name */ - if (gate != NULL ) + if (gate != NULL) { - struct sockaddr_in6 * s6 = (struct sockaddr_in6 *)gate; - struct in6_addr gw = s6->sin6_addr; + struct sockaddr_in6 *s6 = (struct sockaddr_in6 *)gate; + struct in6_addr gw = s6->sin6_addr; #ifndef TARGET_SOLARIS - /* You do not really want to know... from FreeBSD's route.c - * (KAME encodes the 16 bit scope_id in s6_addr[2] + [3], - * but for a correct link-local address these must be :0000: ) - */ - if ( gate->sa_len == sizeof(struct sockaddr_in6) && - IN6_IS_ADDR_LINKLOCAL(&gw) ) - { - gw.s6_addr[2] = gw.s6_addr[3] = 0; - } - - if ( gate->sa_len != sizeof(struct sockaddr_in6) || - IN6_IS_ADDR_UNSPECIFIED(&gw) ) - { - rgi6->flags |= RGI_ON_LINK; - } - else + /* You do not really want to know... from FreeBSD's route.c + * (KAME encodes the 16 bit scope_id in s6_addr[2] + [3], + * but for a correct link-local address these must be :0000: ) + */ + if (gate->sa_len == sizeof(struct sockaddr_in6) + && IN6_IS_ADDR_LINKLOCAL(&gw) ) + { + gw.s6_addr[2] = gw.s6_addr[3] = 0; + } + + if (gate->sa_len != sizeof(struct sockaddr_in6) + || IN6_IS_ADDR_UNSPECIFIED(&gw) ) + { + rgi6->flags |= RGI_ON_LINK; + } + else #endif - rgi6->gateway.addr_ipv6 = gw; - rgi6->flags |= RGI_ADDR_DEFINED; + rgi6->gateway.addr_ipv6 = gw; + rgi6->flags |= RGI_ADDR_DEFINED; - if (ifp) - { - /* get interface name */ - const struct sockaddr_dl *adl = (struct sockaddr_dl *) ifp; - if (adl->sdl_nlen && adl->sdl_nlen < sizeof(rgi6->iface)) - { - memcpy (rgi6->iface, adl->sdl_data, adl->sdl_nlen); - rgi6->flags |= RGI_IFACE_DEFINED; - } - } + if (ifp) + { + /* get interface name */ + const struct sockaddr_dl *adl = (struct sockaddr_dl *) ifp; + if (adl->sdl_nlen && adl->sdl_nlen < sizeof(rgi6->iface)) + { + memcpy(rgi6->iface, adl->sdl_data, adl->sdl_nlen); + rgi6->flags |= RGI_IFACE_DEFINED; + } + } } - done: +done: if (sockfd >= 0) - close(sockfd); + { + close(sockfd); + } } #undef max -#else +#else /* if defined(_WIN32) */ /* * This is a platform-specific method that returns data about @@ -3630,61 +3944,66 @@ get_default_gateway_ipv6(struct route_ipv6_gateway_info *rgi6, * may be disabled by missing items. */ void -get_default_gateway (struct route_gateway_info *rgi) +get_default_gateway(struct route_gateway_info *rgi) { - CLEAR(*rgi); + CLEAR(*rgi); } void get_default_gateway_ipv6(struct route_ipv6_gateway_info *rgi6, - const struct in6_addr *dest) + const struct in6_addr *dest) { msg(D_ROUTE, "no support for get_default_gateway_ipv6() on this system"); CLEAR(*rgi6); } -#endif +#endif /* if defined(_WIN32) */ bool -netmask_to_netbits (const in_addr_t network, const in_addr_t netmask, int *netbits) +netmask_to_netbits(const in_addr_t network, const in_addr_t netmask, int *netbits) { - int i; - const int addrlen = sizeof (in_addr_t) * 8; + int i; + const int addrlen = sizeof(in_addr_t) * 8; - if ((network & netmask) == network) + if ((network & netmask) == network) { - for (i = 0; i <= addrlen; ++i) - { - in_addr_t mask = netbits_to_netmask (i); - if (mask == netmask) - { - if (i == addrlen) - *netbits = -1; - else - *netbits = i; - return true; - } - } + for (i = 0; i <= addrlen; ++i) + { + in_addr_t mask = netbits_to_netmask(i); + if (mask == netmask) + { + if (i == addrlen) + { + *netbits = -1; + } + else + { + *netbits = i; + } + return true; + } + } } - return false; + return false; } /* similar to netmask_to_netbits(), but don't mess with base address * etc., just convert to netbits - non-mappable masks are returned as "-1" */ -int netmask_to_netbits2 (in_addr_t netmask) +int +netmask_to_netbits2(in_addr_t netmask) { - int i; - const int addrlen = sizeof (in_addr_t) * 8; + int i; + const int addrlen = sizeof(in_addr_t) * 8; - for (i = 0; i <= addrlen; ++i) + for (i = 0; i <= addrlen; ++i) { - in_addr_t mask = netbits_to_netmask (i); - if (mask == netmask) - { - return i; - } + in_addr_t mask = netbits_to_netmask(i); + if (mask == netmask) + { + return i; + } } - return -1; + return -1; } @@ -3697,67 +4016,73 @@ int netmask_to_netbits2 (in_addr_t netmask) #if defined(_WIN32) static void -add_host_route_if_nonlocal (struct route_bypass *rb, const in_addr_t addr) +add_host_route_if_nonlocal(struct route_bypass *rb, const in_addr_t addr) { - if (test_local_addr(addr, NULL) == TLA_NONLOCAL && addr != 0 && addr != IPV4_NETMASK_HOST) - add_bypass_address (rb, addr); + if (test_local_addr(addr, NULL) == TLA_NONLOCAL && addr != 0 && addr != IPV4_NETMASK_HOST) + { + add_bypass_address(rb, addr); + } } static void -add_host_route_array (struct route_bypass *rb, const IP_ADDR_STRING *iplist) +add_host_route_array(struct route_bypass *rb, const IP_ADDR_STRING *iplist) { - while (iplist) + while (iplist) { - bool succeed = false; - const in_addr_t ip = getaddr (GETADDR_HOST_ORDER, iplist->IpAddress.String, 0, &succeed, NULL); - if (succeed) - { - add_host_route_if_nonlocal (rb, ip); - } - iplist = iplist->Next; + bool succeed = false; + const in_addr_t ip = getaddr(GETADDR_HOST_ORDER, iplist->IpAddress.String, 0, &succeed, NULL); + if (succeed) + { + add_host_route_if_nonlocal(rb, ip); + } + iplist = iplist->Next; } } static void -get_bypass_addresses (struct route_bypass *rb, const unsigned int flags) +get_bypass_addresses(struct route_bypass *rb, const unsigned int flags) { - struct gc_arena gc = gc_new (); - /*bool ret_bool = false;*/ + struct gc_arena gc = gc_new(); + /*bool ret_bool = false;*/ - /* get full routing table */ - const MIB_IPFORWARDTABLE *routes = get_windows_routing_table (&gc); + /* get full routing table */ + const MIB_IPFORWARDTABLE *routes = get_windows_routing_table(&gc); - /* get the route which represents the default gateway */ - const MIB_IPFORWARDROW *row = get_default_gateway_row (routes); + /* get the route which represents the default gateway */ + const MIB_IPFORWARDROW *row = get_default_gateway_row(routes); - if (row) + if (row) { - /* get the adapter which the default gateway is associated with */ - const IP_ADAPTER_INFO *dgi = get_adapter_info (row->dwForwardIfIndex, &gc); + /* get the adapter which the default gateway is associated with */ + const IP_ADAPTER_INFO *dgi = get_adapter_info(row->dwForwardIfIndex, &gc); - /* get extra adapter info, such as DNS addresses */ - const IP_PER_ADAPTER_INFO *pai = get_per_adapter_info (row->dwForwardIfIndex, &gc); + /* get extra adapter info, such as DNS addresses */ + const IP_PER_ADAPTER_INFO *pai = get_per_adapter_info(row->dwForwardIfIndex, &gc); - /* Bypass DHCP server address */ - if ((flags & RG_BYPASS_DHCP) && dgi && dgi->DhcpEnabled) - add_host_route_array (rb, &dgi->DhcpServer); + /* Bypass DHCP server address */ + if ((flags & RG_BYPASS_DHCP) && dgi && dgi->DhcpEnabled) + { + add_host_route_array(rb, &dgi->DhcpServer); + } - /* Bypass DNS server addresses */ - if ((flags & RG_BYPASS_DNS) && pai) - add_host_route_array (rb, &pai->DnsServerList); + /* Bypass DNS server addresses */ + if ((flags & RG_BYPASS_DNS) && pai) + { + add_host_route_array(rb, &pai->DnsServerList); + } } - gc_free (&gc); + gc_free(&gc); } -#else +#else /* if defined(_WIN32) */ static void -get_bypass_addresses (struct route_bypass *rb, const unsigned int flags) /* PLATFORM-SPECIFIC */ +get_bypass_addresses(struct route_bypass *rb, const unsigned int flags) /* PLATFORM-SPECIFIC */ { } -#endif +#endif /* if defined(_WIN32) */ /* * Test if addr is reachable via a local interface (return ILA_LOCAL), @@ -3771,47 +4096,51 @@ get_bypass_addresses (struct route_bypass *rb, const unsigned int flags) /* PLA #if defined(_WIN32) int -test_local_addr (const in_addr_t addr, const struct route_gateway_info *rgi) +test_local_addr(const in_addr_t addr, const struct route_gateway_info *rgi) { - struct gc_arena gc = gc_new (); - const in_addr_t nonlocal_netmask = 0x80000000L; /* routes with netmask <= to this are considered non-local */ - int ret = TLA_NONLOCAL; + struct gc_arena gc = gc_new(); + const in_addr_t nonlocal_netmask = 0x80000000L; /* routes with netmask <= to this are considered non-local */ + int ret = TLA_NONLOCAL; - /* get full routing table */ - const MIB_IPFORWARDTABLE *rt = get_windows_routing_table (&gc); - if (rt) + /* get full routing table */ + const MIB_IPFORWARDTABLE *rt = get_windows_routing_table(&gc); + if (rt) { - int i; - for (i = 0; i < rt->dwNumEntries; ++i) - { - const MIB_IPFORWARDROW *row = &rt->table[i]; - const in_addr_t net = ntohl (row->dwForwardDest); - const in_addr_t mask = ntohl (row->dwForwardMask); - if (mask > nonlocal_netmask && (addr & mask) == net) - { - ret = TLA_LOCAL; - break; - } - } + int i; + for (i = 0; i < rt->dwNumEntries; ++i) + { + const MIB_IPFORWARDROW *row = &rt->table[i]; + const in_addr_t net = ntohl(row->dwForwardDest); + const in_addr_t mask = ntohl(row->dwForwardMask); + if (mask > nonlocal_netmask && (addr & mask) == net) + { + ret = TLA_LOCAL; + break; + } + } } - gc_free (&gc); - return ret; + gc_free(&gc); + return ret; } -#else +#else /* if defined(_WIN32) */ int -test_local_addr (const in_addr_t addr, const struct route_gateway_info *rgi) /* PLATFORM-SPECIFIC */ +test_local_addr(const in_addr_t addr, const struct route_gateway_info *rgi) /* PLATFORM-SPECIFIC */ { - if (rgi) + if (rgi) { - if (local_route (addr, 0xFFFFFFFF, rgi->gateway.addr, rgi)) - return TLA_LOCAL; - else - return TLA_NONLOCAL; + if (local_route(addr, 0xFFFFFFFF, rgi->gateway.addr, rgi)) + { + return TLA_LOCAL; + } + else + { + return TLA_NONLOCAL; + } } - return TLA_NOT_IMPLEMENTED; + return TLA_NOT_IMPLEMENTED; } -#endif +#endif /* if defined(_WIN32) */ diff --git a/src/openvpn/route.h b/src/openvpn/route.h index c358681e548..dcc7ded800a 100644 --- a/src/openvpn/route.h +++ b/src/openvpn/route.h @@ -52,32 +52,32 @@ struct route_bypass { -# define N_ROUTE_BYPASS 8 - int n_bypass; - in_addr_t bypass[N_ROUTE_BYPASS]; +#define N_ROUTE_BYPASS 8 + int n_bypass; + in_addr_t bypass[N_ROUTE_BYPASS]; }; struct route_special_addr { - /* bits indicating which members below are defined */ -# define RTSA_REMOTE_ENDPOINT (1<<0) -# define RTSA_REMOTE_HOST (1<<1) -# define RTSA_DEFAULT_METRIC (1<<2) - unsigned int flags; - - in_addr_t remote_endpoint; - in_addr_t remote_host; - int remote_host_local; /* TLA_x value */ - struct route_bypass bypass; - int default_metric; + /* bits indicating which members below are defined */ +#define RTSA_REMOTE_ENDPOINT (1<<0) +#define RTSA_REMOTE_HOST (1<<1) +#define RTSA_DEFAULT_METRIC (1<<2) + unsigned int flags; + + in_addr_t remote_endpoint; + in_addr_t remote_host; + int remote_host_local; /* TLA_x value */ + struct route_bypass bypass; + int default_metric; }; struct route_option { - struct route_option *next; - const char *network; - const char *netmask; - const char *gateway; - const char *metric; + struct route_option *next; + const char *network; + const char *netmask; + const char *gateway; + const char *metric; }; /* redirect-gateway flags */ @@ -91,226 +91,234 @@ struct route_option { #define RG_BLOCK_LOCAL (1<<7) struct route_option_list { - unsigned int flags; /* RG_x flags */ - struct route_option *routes; - struct gc_arena *gc; + unsigned int flags; /* RG_x flags */ + struct route_option *routes; + struct gc_arena *gc; }; struct route_ipv6_option { - struct route_ipv6_option *next; - const char *prefix; /* e.g. "2001:db8:1::/64" */ - const char *gateway; /* e.g. "2001:db8:0::2" */ - const char *metric; /* e.g. "5" */ + struct route_ipv6_option *next; + const char *prefix; /* e.g. "2001:db8:1::/64" */ + const char *gateway; /* e.g. "2001:db8:0::2" */ + const char *metric; /* e.g. "5" */ }; struct route_ipv6_option_list { - unsigned int flags; /* RG_x flags, see route_option-list */ - struct route_ipv6_option *routes_ipv6; - struct gc_arena *gc; + unsigned int flags; /* RG_x flags, see route_option-list */ + struct route_ipv6_option *routes_ipv6; + struct gc_arena *gc; }; struct route_ipv4 { -# define RT_DEFINED (1<<0) -# define RT_ADDED (1<<1) -# define RT_METRIC_DEFINED (1<<2) - struct route_ipv4 *next; - unsigned int flags; - const struct route_option *option; - in_addr_t network; - in_addr_t netmask; - in_addr_t gateway; - int metric; +#define RT_DEFINED (1<<0) +#define RT_ADDED (1<<1) +#define RT_METRIC_DEFINED (1<<2) + struct route_ipv4 *next; + unsigned int flags; + const struct route_option *option; + in_addr_t network; + in_addr_t netmask; + in_addr_t gateway; + int metric; }; struct route_ipv6 { - struct route_ipv6 *next; - unsigned int flags; /* RT_ flags, see route_ipv4 */ - struct in6_addr network; - unsigned int netbits; - struct in6_addr gateway; - int metric; - /* gateway interface */ -# ifdef _WIN32 - DWORD adapter_index; /* interface or ~0 if undefined */ + struct route_ipv6 *next; + unsigned int flags; /* RT_ flags, see route_ipv4 */ + struct in6_addr network; + unsigned int netbits; + struct in6_addr gateway; + int metric; + /* gateway interface */ +#ifdef _WIN32 + DWORD adapter_index; /* interface or ~0 if undefined */ #else - char * iface; /* interface name (null terminated) */ + char *iface; /* interface name (null terminated) */ #endif }; struct route_gateway_address { - in_addr_t addr; - in_addr_t netmask; + in_addr_t addr; + in_addr_t netmask; }; struct route_gateway_info { -# define RGI_ADDR_DEFINED (1<<0) /* set if gateway.addr defined */ -# define RGI_NETMASK_DEFINED (1<<1) /* set if gateway.netmask defined */ -# define RGI_HWADDR_DEFINED (1<<2) /* set if hwaddr is defined */ -# define RGI_IFACE_DEFINED (1<<3) /* set if iface is defined */ -# define RGI_OVERFLOW (1<<4) /* set if more interface addresses than will fit in addrs */ -# define RGI_ON_LINK (1<<5) - unsigned int flags; - - /* gateway interface */ -# ifdef _WIN32 - DWORD adapter_index; /* interface or ~0 if undefined */ +#define RGI_ADDR_DEFINED (1<<0) /* set if gateway.addr defined */ +#define RGI_NETMASK_DEFINED (1<<1) /* set if gateway.netmask defined */ +#define RGI_HWADDR_DEFINED (1<<2) /* set if hwaddr is defined */ +#define RGI_IFACE_DEFINED (1<<3) /* set if iface is defined */ +#define RGI_OVERFLOW (1<<4) /* set if more interface addresses than will fit in addrs */ +#define RGI_ON_LINK (1<<5) + unsigned int flags; + + /* gateway interface */ +#ifdef _WIN32 + DWORD adapter_index; /* interface or ~0 if undefined */ #else - char iface[16]; /* interface name (null terminated), may be empty */ + char iface[16]; /* interface name (null terminated), may be empty */ #endif - /* gateway interface hardware address */ - uint8_t hwaddr[6]; + /* gateway interface hardware address */ + uint8_t hwaddr[6]; - /* gateway/router address */ - struct route_gateway_address gateway; + /* gateway/router address */ + struct route_gateway_address gateway; - /* address/netmask pairs bound to interface */ -# define RGI_N_ADDRESSES 8 - int n_addrs; /* len of addrs, may be 0 */ - struct route_gateway_address addrs[RGI_N_ADDRESSES]; /* local addresses attached to iface */ + /* address/netmask pairs bound to interface */ +#define RGI_N_ADDRESSES 8 + int n_addrs; /* len of addrs, may be 0 */ + struct route_gateway_address addrs[RGI_N_ADDRESSES]; /* local addresses attached to iface */ }; struct route_ipv6_gateway_address { - struct in6_addr addr_ipv6; - int netbits_ipv6; + struct in6_addr addr_ipv6; + int netbits_ipv6; }; struct route_ipv6_gateway_info { /* RGI_ flags used as in route_gateway_info */ - unsigned int flags; + unsigned int flags; - /* gateway interface */ -# ifdef _WIN32 - DWORD adapter_index; /* interface or ~0 if undefined */ + /* gateway interface */ +#ifdef _WIN32 + DWORD adapter_index; /* interface or ~0 if undefined */ #else - char iface[16]; /* interface name (null terminated), may be empty */ + char iface[16]; /* interface name (null terminated), may be empty */ #endif - /* gateway interface hardware address */ - uint8_t hwaddr[6]; + /* gateway interface hardware address */ + uint8_t hwaddr[6]; - /* gateway/router address */ - struct route_ipv6_gateway_address gateway; + /* gateway/router address */ + struct route_ipv6_gateway_address gateway; - /* address/netmask pairs bound to interface */ -# define RGI_N_ADDRESSES 8 - int n_addrs; /* len of addrs, may be 0 */ - struct route_ipv6_gateway_address addrs[RGI_N_ADDRESSES]; /* local addresses attached to iface */ + /* address/netmask pairs bound to interface */ +#define RGI_N_ADDRESSES 8 + int n_addrs; /* len of addrs, may be 0 */ + struct route_ipv6_gateway_address addrs[RGI_N_ADDRESSES]; /* local addresses attached to iface */ }; struct route_list { -# define RL_DID_REDIRECT_DEFAULT_GATEWAY (1<<0) -# define RL_DID_LOCAL (1<<1) -# define RL_ROUTES_ADDED (1<<2) - unsigned int iflags; - - struct route_special_addr spec; - struct route_gateway_info rgi; - unsigned int flags; /* RG_x flags */ - struct route_ipv4 *routes; - struct gc_arena gc; +#define RL_DID_REDIRECT_DEFAULT_GATEWAY (1<<0) +#define RL_DID_LOCAL (1<<1) +#define RL_ROUTES_ADDED (1<<2) + unsigned int iflags; + + struct route_special_addr spec; + struct route_gateway_info rgi; + unsigned int flags; /* RG_x flags */ + struct route_ipv4 *routes; + struct gc_arena gc; }; struct route_ipv6_list { - unsigned int iflags; /* RL_ flags, see route_list */ + unsigned int iflags; /* RL_ flags, see route_list */ - unsigned int spec_flags; /* RTSA_ flags, route_special_addr */ - struct in6_addr remote_endpoint_ipv6; /* inside tun */ - struct in6_addr remote_host_ipv6; /* --remote address */ - int default_metric; + unsigned int spec_flags; /* RTSA_ flags, route_special_addr */ + struct in6_addr remote_endpoint_ipv6; /* inside tun */ + struct in6_addr remote_host_ipv6; /* --remote address */ + int default_metric; - struct route_ipv6_gateway_info rgi6; - unsigned int flags; /* RG_x flags, see route_option_list */ - struct route_ipv6 *routes_ipv6; - struct gc_arena gc; + struct route_ipv6_gateway_info rgi6; + unsigned int flags; /* RG_x flags, see route_option_list */ + struct route_ipv6 *routes_ipv6; + struct gc_arena gc; }; #if P2MP /* internal OpenVPN route */ struct iroute { - in_addr_t network; - int netbits; - struct iroute *next; + in_addr_t network; + int netbits; + struct iroute *next; }; struct iroute_ipv6 { - struct in6_addr network; - unsigned int netbits; - struct iroute_ipv6 *next; + struct in6_addr network; + unsigned int netbits; + struct iroute_ipv6 *next; }; #endif -struct route_option_list *new_route_option_list (struct gc_arena *a); -struct route_ipv6_option_list *new_route_ipv6_option_list (struct gc_arena *a); - -struct route_option_list *clone_route_option_list (const struct route_option_list *src, struct gc_arena *a); -struct route_ipv6_option_list *clone_route_ipv6_option_list (const struct route_ipv6_option_list *src, struct gc_arena *a); -void copy_route_option_list (struct route_option_list *dest, const struct route_option_list *src, struct gc_arena *a); -void copy_route_ipv6_option_list (struct route_ipv6_option_list *dest, - const struct route_ipv6_option_list *src, - struct gc_arena *a); - -void add_route_ipv6 (struct route_ipv6 *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es); -void delete_route_ipv6 (const struct route_ipv6 *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es); - -void add_route (struct route_ipv4 *r, - const struct tuntap *tt, - unsigned int flags, - const struct route_gateway_info *rgi, - const struct env_set *es); - -void add_route_to_option_list (struct route_option_list *l, - const char *network, - const char *netmask, - const char *gateway, - const char *metric); - -void add_route_ipv6_to_option_list (struct route_ipv6_option_list *l, - const char *prefix, - const char *gateway, - const char *metric); - -bool init_route_list (struct route_list *rl, - const struct route_option_list *opt, - const char *remote_endpoint, - int default_metric, - in_addr_t remote_host, - struct env_set *es); - -bool init_route_ipv6_list (struct route_ipv6_list *rl6, - const struct route_ipv6_option_list *opt6, - const char *remote_endpoint, - int default_metric, - const struct in6_addr *remote_host, - struct env_set *es); - -void route_list_add_vpn_gateway (struct route_list *rl, - struct env_set *es, - const in_addr_t addr); - -void add_routes (struct route_list *rl, - struct route_ipv6_list *rl6, - const struct tuntap *tt, - unsigned int flags, - const struct env_set *es); - -void delete_routes (struct route_list *rl, - struct route_ipv6_list *rl6, - const struct tuntap *tt, - unsigned int flags, - const struct env_set *es); - -void setenv_routes (struct env_set *es, const struct route_list *rl); -void setenv_routes_ipv6 (struct env_set *es, const struct route_ipv6_list *rl6); - - - -bool is_special_addr (const char *addr_str); - -void get_default_gateway (struct route_gateway_info *rgi); -void get_default_gateway_ipv6 (struct route_ipv6_gateway_info *rgi, - const struct in6_addr *dest); +struct route_option_list *new_route_option_list(struct gc_arena *a); + +struct route_ipv6_option_list *new_route_ipv6_option_list(struct gc_arena *a); + +struct route_option_list *clone_route_option_list(const struct route_option_list *src, struct gc_arena *a); + +struct route_ipv6_option_list *clone_route_ipv6_option_list(const struct route_ipv6_option_list *src, struct gc_arena *a); + +void copy_route_option_list(struct route_option_list *dest, const struct route_option_list *src, struct gc_arena *a); + +void copy_route_ipv6_option_list(struct route_ipv6_option_list *dest, + const struct route_ipv6_option_list *src, + struct gc_arena *a); + +void add_route_ipv6(struct route_ipv6 *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es); + +void delete_route_ipv6(const struct route_ipv6 *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es); + +void add_route(struct route_ipv4 *r, + const struct tuntap *tt, + unsigned int flags, + const struct route_gateway_info *rgi, + const struct env_set *es); + +void add_route_to_option_list(struct route_option_list *l, + const char *network, + const char *netmask, + const char *gateway, + const char *metric); + +void add_route_ipv6_to_option_list(struct route_ipv6_option_list *l, + const char *prefix, + const char *gateway, + const char *metric); + +bool init_route_list(struct route_list *rl, + const struct route_option_list *opt, + const char *remote_endpoint, + int default_metric, + in_addr_t remote_host, + struct env_set *es); + +bool init_route_ipv6_list(struct route_ipv6_list *rl6, + const struct route_ipv6_option_list *opt6, + const char *remote_endpoint, + int default_metric, + const struct in6_addr *remote_host, + struct env_set *es); + +void route_list_add_vpn_gateway(struct route_list *rl, + struct env_set *es, + const in_addr_t addr); + +void add_routes(struct route_list *rl, + struct route_ipv6_list *rl6, + const struct tuntap *tt, + unsigned int flags, + const struct env_set *es); + +void delete_routes(struct route_list *rl, + struct route_ipv6_list *rl6, + const struct tuntap *tt, + unsigned int flags, + const struct env_set *es); + +void setenv_routes(struct env_set *es, const struct route_list *rl); + +void setenv_routes_ipv6(struct env_set *es, const struct route_ipv6_list *rl6); + + + +bool is_special_addr(const char *addr_str); + +void get_default_gateway(struct route_gateway_info *rgi); + +void get_default_gateway_ipv6(struct route_ipv6_gateway_info *rgi, + const struct in6_addr *dest); + void print_default_gateway(const int msglevel, const struct route_gateway_info *rgi, const struct route_ipv6_gateway_info *rgi6); @@ -324,52 +332,66 @@ void print_default_gateway(const int msglevel, #define TLA_NOT_IMPLEMENTED 0 #define TLA_NONLOCAL 1 #define TLA_LOCAL 2 -int test_local_addr (const in_addr_t addr, const struct route_gateway_info *rgi); +int test_local_addr(const in_addr_t addr, const struct route_gateway_info *rgi); #ifndef ENABLE_SMALL -void print_route_options (const struct route_option_list *rol, - int level); +void print_route_options(const struct route_option_list *rol, + int level); + #endif -void print_routes (const struct route_list *rl, int level); +void print_routes(const struct route_list *rl, int level); #ifdef _WIN32 -void show_routes (int msglev); -bool test_routes (const struct route_list *rl, const struct tuntap *tt); -bool add_route_ipapi (const struct route_ipv4 *r, const struct tuntap *tt, DWORD adapter_index); -bool del_route_ipapi (const struct route_ipv4 *r, const struct tuntap *tt); +void show_routes(int msglev); -#else -static inline bool test_routes (const struct route_list *rl, const struct tuntap *tt) { return true; } +bool test_routes(const struct route_list *rl, const struct tuntap *tt); + +bool add_route_ipapi(const struct route_ipv4 *r, const struct tuntap *tt, DWORD adapter_index); + +bool del_route_ipapi(const struct route_ipv4 *r, const struct tuntap *tt); + +#else /* ifdef _WIN32 */ +static inline bool +test_routes(const struct route_list *rl, const struct tuntap *tt) { + return true; +} #endif -bool netmask_to_netbits (const in_addr_t network, const in_addr_t netmask, int *netbits); -int netmask_to_netbits2 (in_addr_t netmask); +bool netmask_to_netbits(const in_addr_t network, const in_addr_t netmask, int *netbits); + +int netmask_to_netbits2(in_addr_t netmask); static inline in_addr_t -netbits_to_netmask (const int netbits) +netbits_to_netmask(const int netbits) { - const int addrlen = sizeof (in_addr_t) * 8; - in_addr_t mask = 0; - if (netbits > 0 && netbits <= addrlen) - mask = IPV4_NETMASK_HOST << (addrlen-netbits); - return mask; + const int addrlen = sizeof(in_addr_t) * 8; + in_addr_t mask = 0; + if (netbits > 0 && netbits <= addrlen) + { + mask = IPV4_NETMASK_HOST << (addrlen-netbits); + } + return mask; } static inline bool -route_list_vpn_gateway_needed (const struct route_list *rl) +route_list_vpn_gateway_needed(const struct route_list *rl) { - if (!rl) - return false; - else - return !(rl->spec.flags & RTSA_REMOTE_ENDPOINT); + if (!rl) + { + return false; + } + else + { + return !(rl->spec.flags & RTSA_REMOTE_ENDPOINT); + } } static inline int route_did_redirect_default_gateway(const struct route_list *rl) { - return rl && BOOL_CAST(rl->iflags & RL_DID_REDIRECT_DEFAULT_GATEWAY); + return rl && BOOL_CAST(rl->iflags & RL_DID_REDIRECT_DEFAULT_GATEWAY); } -#endif +#endif /* ifndef ROUTE_H */ diff --git a/src/openvpn/schedule.c b/src/openvpn/schedule.c index 471330f004e..4495b1e891d 100644 --- a/src/openvpn/schedule.c +++ b/src/openvpn/schedule.c @@ -43,10 +43,10 @@ struct status { - int sru; - int ins; - int coll; - int lsteps; + int sru; + int ins; + int coll; + int lsteps; }; static struct status z; @@ -55,31 +55,33 @@ static struct status z; #ifdef ENABLE_DEBUG static void -schedule_entry_debug_info (const char *caller, const struct schedule_entry *e) +schedule_entry_debug_info(const char *caller, const struct schedule_entry *e) { - struct gc_arena gc = gc_new (); - if (e) + struct gc_arena gc = gc_new(); + if (e) { - dmsg (D_SCHEDULER, "SCHEDULE: %s wakeup=[%s] pri=%u", - caller, - tv_string_abs (&e->tv, &gc), - e->pri); + dmsg(D_SCHEDULER, "SCHEDULE: %s wakeup=[%s] pri=%u", + caller, + tv_string_abs(&e->tv, &gc), + e->pri); } - else + else { - dmsg (D_SCHEDULER, "SCHEDULE: %s NULL", - caller); + dmsg(D_SCHEDULER, "SCHEDULE: %s NULL", + caller); } - gc_free (&gc); + gc_free(&gc); } #endif static inline void -schedule_set_pri (struct schedule_entry *e) +schedule_set_pri(struct schedule_entry *e) { - e->pri = random (); - if (e->pri < 1) - e->pri = 1; + e->pri = random(); + if (e->pri < 1) + { + e->pri = 1; + } } /* This is the master key comparison routine. A key is @@ -88,28 +90,42 @@ schedule_set_pri (struct schedule_entry *e) * that keys do not collide. */ static inline int -schedule_entry_compare (const struct schedule_entry *e1, - const struct schedule_entry *e2) +schedule_entry_compare(const struct schedule_entry *e1, + const struct schedule_entry *e2) { - if (e1->tv.tv_sec < e2->tv.tv_sec) - return -1; - else if (e1->tv.tv_sec > e2->tv.tv_sec) - return 1; - else + if (e1->tv.tv_sec < e2->tv.tv_sec) + { + return -1; + } + else if (e1->tv.tv_sec > e2->tv.tv_sec) { - if (e1->tv.tv_usec < e2->tv.tv_usec) - return -1; - else if (e1->tv.tv_usec > e2->tv.tv_usec) - return 1; - else - { - if (e1->pri < e2->pri) - return -1; - else if (e1->pri > e2->pri) - return 1; - else - return 0; - } + return 1; + } + else + { + if (e1->tv.tv_usec < e2->tv.tv_usec) + { + return -1; + } + else if (e1->tv.tv_usec > e2->tv.tv_usec) + { + return 1; + } + else + { + if (e1->pri < e2->pri) + { + return -1; + } + else if (e1->pri > e2->pri) + { + return 1; + } + else + { + return 0; + } + } } } @@ -117,28 +133,34 @@ schedule_entry_compare (const struct schedule_entry *e1, * Detach a btree node from its parent */ static inline void -schedule_detach_parent (struct schedule *s, struct schedule_entry *e) +schedule_detach_parent(struct schedule *s, struct schedule_entry *e) { - if (e) + if (e) { - if (e->parent) - { - if (e->parent->lt == e) - e->parent->lt = NULL; - else if (e->parent->gt == e) - e->parent->gt = NULL; - else - { - /* parent <-> child linkage is corrupted */ - ASSERT (0); - } - e->parent = NULL; - } - else - { - if (s->root == e) /* last element deleted, tree is empty */ - s->root = NULL; - } + if (e->parent) + { + if (e->parent->lt == e) + { + e->parent->lt = NULL; + } + else if (e->parent->gt == e) + { + e->parent->gt = NULL; + } + else + { + /* parent <-> child linkage is corrupted */ + ASSERT(0); + } + e->parent = NULL; + } + else + { + if (s->root == e) /* last element deleted, tree is empty */ + { + s->root = NULL; + } + } } } @@ -154,61 +176,69 @@ schedule_detach_parent (struct schedule *s, struct schedule_entry *e) * and is guaranteed to be unique. */ static void -schedule_rotate_up (struct schedule *s, struct schedule_entry *e) +schedule_rotate_up(struct schedule *s, struct schedule_entry *e) { - if (e && e->parent) + if (e && e->parent) { - struct schedule_entry *lt = e->lt; - struct schedule_entry *gt = e->gt; - struct schedule_entry *p = e->parent; - struct schedule_entry *gp = p->parent; - - if (gp) /* if grandparent exists, modify its child link */ - { - if (gp->gt == p) - gp->gt = e; - else if (gp->lt == p) - gp->lt = e; - else - { - ASSERT (0); - } - } - else /* no grandparent, now we are the root */ - { - s->root = e; - } - - /* grandparent is now our parent */ - e->parent = gp; - - /* parent is now our child */ - p->parent = e; - - /* reorient former parent's links - to reflect new position in the tree */ - if (p->gt == e) - { - e->lt = p; - p->gt = lt; - if (lt) - lt->parent = p; - } - else if (p->lt == e) - { - e->gt = p; - p->lt = gt; - if (gt) - gt->parent = p; - } - else - { - /* parent <-> child linkage is corrupted */ - ASSERT (0); - } + struct schedule_entry *lt = e->lt; + struct schedule_entry *gt = e->gt; + struct schedule_entry *p = e->parent; + struct schedule_entry *gp = p->parent; + + if (gp) /* if grandparent exists, modify its child link */ + { + if (gp->gt == p) + { + gp->gt = e; + } + else if (gp->lt == p) + { + gp->lt = e; + } + else + { + ASSERT(0); + } + } + else /* no grandparent, now we are the root */ + { + s->root = e; + } + + /* grandparent is now our parent */ + e->parent = gp; + + /* parent is now our child */ + p->parent = e; + + /* reorient former parent's links + * to reflect new position in the tree */ + if (p->gt == e) + { + e->lt = p; + p->gt = lt; + if (lt) + { + lt->parent = p; + } + } + else if (p->lt == e) + { + e->gt = p; + p->lt = gt; + if (gt) + { + gt->parent = p; + } + } + else + { + /* parent <-> child linkage is corrupted */ + ASSERT(0); + } #ifdef SCHEDULE_TEST - ++z.sru; + ++z.sru; #endif } } @@ -220,28 +250,36 @@ schedule_rotate_up (struct schedule *s, struct schedule_entry *e) * until we are childless. Then delete. */ void -schedule_remove_node (struct schedule *s, struct schedule_entry *e) +schedule_remove_node(struct schedule *s, struct schedule_entry *e) { - while (e->lt || e->gt) + while (e->lt || e->gt) { - if (e->lt) - { - if (e->gt) - { - if (e->lt->pri < e->gt->pri) - schedule_rotate_up (s, e->lt); - else - schedule_rotate_up (s, e->gt); - } - else - schedule_rotate_up (s, e->lt); - } - else if (e->gt) - schedule_rotate_up (s, e->gt); + if (e->lt) + { + if (e->gt) + { + if (e->lt->pri < e->gt->pri) + { + schedule_rotate_up(s, e->lt); + } + else + { + schedule_rotate_up(s, e->gt); + } + } + else + { + schedule_rotate_up(s, e->lt); + } + } + else if (e->gt) + { + schedule_rotate_up(s, e->gt); + } } - schedule_detach_parent (s, e); - e->pri = 0; + schedule_detach_parent(s, e); + e->pri = 0; } /* @@ -249,57 +287,57 @@ schedule_remove_node (struct schedule *s, struct schedule_entry *e) * regard for balance. */ static void -schedule_insert (struct schedule *s, struct schedule_entry *e) +schedule_insert(struct schedule *s, struct schedule_entry *e) { - struct schedule_entry *c = s->root; - while (true) + struct schedule_entry *c = s->root; + while (true) { - const int comp = schedule_entry_compare (e, c); + const int comp = schedule_entry_compare(e, c); #ifdef SCHEDULE_TEST - ++z.ins; + ++z.ins; #endif - if (comp == -1) - { - if (c->lt) - { - c = c->lt; - continue; - } - else - { - c->lt = e; - e->parent = c; - break; - } - } - else if (comp == 1) - { - if (c->gt) - { - c = c->gt; - continue; - } - else - { - c->gt = e; - e->parent = c; - break; - } - } - else - { - /* rare key/priority collision -- no big deal, - just choose another priority and retry */ + if (comp == -1) + { + if (c->lt) + { + c = c->lt; + continue; + } + else + { + c->lt = e; + e->parent = c; + break; + } + } + else if (comp == 1) + { + if (c->gt) + { + c = c->gt; + continue; + } + else + { + c->gt = e; + e->parent = c; + break; + } + } + else + { + /* rare key/priority collision -- no big deal, + * just choose another priority and retry */ #ifdef SCHEDULE_TEST - ++z.coll; + ++z.coll; #endif - schedule_set_pri (e); - /* msg (M_INFO, "PRI COLLISION pri=%u", e->pri); */ - c = s->root; - continue; - } + schedule_set_pri(e); + /* msg (M_INFO, "PRI COLLISION pri=%u", e->pri); */ + c = s->root; + continue; + } } } @@ -308,55 +346,65 @@ schedule_insert (struct schedule *s, struct schedule_entry *e) * there and re-insert it based on its current key. */ void -schedule_add_modify (struct schedule *s, struct schedule_entry *e) +schedule_add_modify(struct schedule *s, struct schedule_entry *e) { #ifdef ENABLE_DEBUG - if (check_debug_level (D_SCHEDULER)) - schedule_entry_debug_info ("schedule_add_modify", e); + if (check_debug_level(D_SCHEDULER)) + { + schedule_entry_debug_info("schedule_add_modify", e); + } #endif - /* already in tree, remove */ - if (IN_TREE (e)) - schedule_remove_node (s, e); + /* already in tree, remove */ + if (IN_TREE(e)) + { + schedule_remove_node(s, e); + } - /* set random priority */ - schedule_set_pri (e); + /* set random priority */ + schedule_set_pri(e); - if (s->root) - schedule_insert (s, e); /* trivial insert into tree */ - else - s->root = e; /* tree was empty, we are the first element */ + if (s->root) + { + schedule_insert(s, e); /* trivial insert into tree */ + } + else + { + s->root = e; /* tree was empty, we are the first element */ - /* This is the magic of the randomized treap algorithm which - keeps the tree balanced. Move the node up the tree until - its own priority is greater than that of its parent */ - while (e->parent && e->parent->pri > e->pri) - schedule_rotate_up (s, e); + } + /* This is the magic of the randomized treap algorithm which + * keeps the tree balanced. Move the node up the tree until + * its own priority is greater than that of its parent */ + while (e->parent && e->parent->pri > e->pri) + schedule_rotate_up(s, e); } /* * Find the earliest event to be scheduled */ struct schedule_entry * -schedule_find_least (struct schedule_entry *e) +schedule_find_least(struct schedule_entry *e) { - if (e) + if (e) { - while (e->lt) - { + while (e->lt) + { #ifdef SCHEDULE_TEST - ++z.lsteps; + ++z.lsteps; #endif - e = e->lt; - } + e = e->lt; + } } - + #ifdef ENABLE_DEBUG - if (check_debug_level (D_SCHEDULER)) - schedule_entry_debug_info ("schedule_find_least", e); + if (check_debug_level(D_SCHEDULER)) + { + schedule_entry_debug_info("schedule_find_least", e); + } #endif - return e; + return e; } /* @@ -364,25 +412,25 @@ schedule_find_least (struct schedule_entry *e) */ struct schedule * -schedule_init (void) +schedule_init(void) { - struct schedule *s; + struct schedule *s; - ALLOC_OBJ_CLEAR (s, struct schedule); - return s; + ALLOC_OBJ_CLEAR(s, struct schedule); + return s; } void -schedule_free (struct schedule *s) +schedule_free(struct schedule *s) { - free (s); + free(s); } void -schedule_remove_entry (struct schedule *s, struct schedule_entry *e) +schedule_remove_entry(struct schedule *s, struct schedule_entry *e) { - s->earliest_wakeup = NULL; /* invalidate cache */ - schedule_remove_node (s, e); + s->earliest_wakeup = NULL; /* invalidate cache */ + schedule_remove_node(s, e); } /* @@ -392,9 +440,9 @@ schedule_remove_entry (struct schedule *s, struct schedule_entry *e) #ifdef SCHEDULE_TEST static inline struct schedule_entry * -schedule_find_earliest_wakeup (struct schedule *s) +schedule_find_earliest_wakeup(struct schedule *s) { - return schedule_find_least (s->root); + return schedule_find_least(s->root); } /* @@ -402,258 +450,274 @@ schedule_find_earliest_wakeup (struct schedule *s) * internally consistent. */ int -schedule_debug_entry (const struct schedule_entry* e, - int depth, - int *count, - struct timeval *least, - const struct timeval *min, - const struct timeval *max) +schedule_debug_entry(const struct schedule_entry *e, + int depth, + int *count, + struct timeval *least, + const struct timeval *min, + const struct timeval *max) { - struct gc_arena gc = gc_new (); - int maxdepth = depth; - if (e) + struct gc_arena gc = gc_new(); + int maxdepth = depth; + if (e) { - int d; - - ASSERT (e != e->lt); - ASSERT (e != e->gt); - ASSERT (e != e->parent); - ASSERT (!e->parent || e->parent != e->lt); - ASSERT (!e->parent || e->parent != e->gt); - ASSERT (!e->lt || e->lt != e->gt); - - if (e->lt) - { - ASSERT (e->lt->parent == e); - ASSERT (schedule_entry_compare (e->lt, e) == -1); - ASSERT (e->lt->pri >= e->pri); - } - - if (e->gt) - { - ASSERT (e->gt->parent == e); - ASSERT (schedule_entry_compare (e->gt, e)); - ASSERT (e->gt->pri >= e->pri); - } - - ASSERT (tv_le (min, &e->tv)); - ASSERT (tv_le (&e->tv, max)); - - if (count) - ++(*count); - - if (least && tv_lt (&e->tv, least)) - *least = e->tv; - - d = schedule_debug_entry (e->lt, depth+1, count, least, min, &e->tv); - if (d > maxdepth) - maxdepth = d; - - d = schedule_debug_entry (e->gt, depth+1, count, least, &e->tv, max); - if (d > maxdepth) - maxdepth = d; + int d; + + ASSERT(e != e->lt); + ASSERT(e != e->gt); + ASSERT(e != e->parent); + ASSERT(!e->parent || e->parent != e->lt); + ASSERT(!e->parent || e->parent != e->gt); + ASSERT(!e->lt || e->lt != e->gt); + + if (e->lt) + { + ASSERT(e->lt->parent == e); + ASSERT(schedule_entry_compare(e->lt, e) == -1); + ASSERT(e->lt->pri >= e->pri); + } + + if (e->gt) + { + ASSERT(e->gt->parent == e); + ASSERT(schedule_entry_compare(e->gt, e)); + ASSERT(e->gt->pri >= e->pri); + } + + ASSERT(tv_le(min, &e->tv)); + ASSERT(tv_le(&e->tv, max)); + + if (count) + { + ++(*count); + } + + if (least && tv_lt(&e->tv, least)) + { + *least = e->tv; + } + + d = schedule_debug_entry(e->lt, depth+1, count, least, min, &e->tv); + if (d > maxdepth) + { + maxdepth = d; + } + + d = schedule_debug_entry(e->gt, depth+1, count, least, &e->tv, max); + if (d > maxdepth) + { + maxdepth = d; + } } - gc_free (&gc); - return maxdepth; + gc_free(&gc); + return maxdepth; } int -schedule_debug (struct schedule *s, int *count, struct timeval *least) +schedule_debug(struct schedule *s, int *count, struct timeval *least) { - struct timeval min; - struct timeval max; + struct timeval min; + struct timeval max; - min.tv_sec = 0; - min.tv_usec = 0; - max.tv_sec = 0x7FFFFFFF; - max.tv_usec = 0x7FFFFFFF; + min.tv_sec = 0; + min.tv_usec = 0; + max.tv_sec = 0x7FFFFFFF; + max.tv_usec = 0x7FFFFFFF; - if (s->root) + if (s->root) { - ASSERT (s->root->parent == NULL); + ASSERT(s->root->parent == NULL); } - return schedule_debug_entry (s->root, 0, count, least, &min, &max); + return schedule_debug_entry(s->root, 0, count, least, &min, &max); } #if 1 void -tv_randomize (struct timeval *tv) +tv_randomize(struct timeval *tv) { - tv->tv_sec += random() % 100; - tv->tv_usec = random () % 100; + tv->tv_sec += random() % 100; + tv->tv_usec = random() % 100; } -#else +#else /* if 1 */ void -tv_randomize (struct timeval *tv) +tv_randomize(struct timeval *tv) { - struct gc_arena gc = gc_new (); - long int choice = get_random (); - if ((choice & 0xFF) == 0) - tv->tv_usec += ((choice >> 8) & 0xFF); - else - prng_bytes ((uint8_t *)tv, sizeof (struct timeval)); - gc_free (&gc); + struct gc_arena gc = gc_new(); + long int choice = get_random(); + if ((choice & 0xFF) == 0) + { + tv->tv_usec += ((choice >> 8) & 0xFF); + } + else + { + prng_bytes((uint8_t *)tv, sizeof(struct timeval)); + } + gc_free(&gc); } -#endif +#endif /* if 1 */ void -schedule_verify (struct schedule *s) +schedule_verify(struct schedule *s) { - struct gc_arena gc = gc_new (); - struct timeval least; - int count; - int maxlev; - struct schedule_entry* e; - const struct status zz = z; + struct gc_arena gc = gc_new(); + struct timeval least; + int count; + int maxlev; + struct schedule_entry *e; + const struct status zz = z; - least.tv_sec = least.tv_usec = 0x7FFFFFFF; + least.tv_sec = least.tv_usec = 0x7FFFFFFF; - count = 0; + count = 0; - maxlev = schedule_debug (s, &count, &least); + maxlev = schedule_debug(s, &count, &least); - e = schedule_find_earliest_wakeup (s); + e = schedule_find_earliest_wakeup(s); - if (e) + if (e) { - printf ("Verification Phase count=%d maxlev=%d sru=%d ins=%d coll=%d ls=%d l=%s", - count, - maxlev, - zz.sru, - zz.ins, - zz.coll, - zz.lsteps, - tv_string (&e->tv, &gc)); - - if (!tv_eq (&least, &e->tv)) - printf (" [COMPUTED DIFFERENT MIN VALUES!]"); - - printf ("\n"); + printf("Verification Phase count=%d maxlev=%d sru=%d ins=%d coll=%d ls=%d l=%s", + count, + maxlev, + zz.sru, + zz.ins, + zz.coll, + zz.lsteps, + tv_string(&e->tv, &gc)); + + if (!tv_eq(&least, &e->tv)) + { + printf(" [COMPUTED DIFFERENT MIN VALUES!]"); + } + + printf("\n"); } - - CLEAR (z); - gc_free (&gc); + + CLEAR(z); + gc_free(&gc); } void -schedule_randomize_array (struct schedule_entry **array, int size) +schedule_randomize_array(struct schedule_entry **array, int size) { - int i; - for (i = 0; i < size; ++i) + int i; + for (i = 0; i < size; ++i) { - const int src = get_random () % size; - struct schedule_entry *tmp = array [i]; - if (i != src) - { - array [i] = array [src]; - array [src] = tmp; - } + const int src = get_random() % size; + struct schedule_entry *tmp = array [i]; + if (i != src) + { + array [i] = array [src]; + array [src] = tmp; + } } } void -schedule_print_work (struct schedule_entry *e, int indent) +schedule_print_work(struct schedule_entry *e, int indent) { - struct gc_arena gc = gc_new (); - int i; - for (i = 0; i < indent; ++i) - printf (" "); - if (e) + struct gc_arena gc = gc_new(); + int i; + for (i = 0; i < indent; ++i) + printf(" "); + if (e) + { + printf("%s [%u] e=" ptr_format ", p=" ptr_format " lt=" ptr_format " gt=" ptr_format "\n", + tv_string(&e->tv, &gc), + e->pri, + (ptr_type)e, + (ptr_type)e->parent, + (ptr_type)e->lt, + (ptr_type)e->gt); + schedule_print_work(e->lt, indent+1); + schedule_print_work(e->gt, indent+1); + } + else { - printf ("%s [%u] e=" ptr_format ", p=" ptr_format " lt=" ptr_format " gt=" ptr_format "\n", - tv_string (&e->tv, &gc), - e->pri, - (ptr_type)e, - (ptr_type)e->parent, - (ptr_type)e->lt, - (ptr_type)e->gt); - schedule_print_work (e->lt, indent+1); - schedule_print_work (e->gt, indent+1); + printf("NULL\n"); } - else - printf ("NULL\n"); - gc_free (&gc); + gc_free(&gc); } void -schedule_print (struct schedule *s) +schedule_print(struct schedule *s) { - printf ("*************************\n"); - schedule_print_work (s->root, 0); + printf("*************************\n"); + schedule_print_work(s->root, 0); } void -schedule_test (void) +schedule_test(void) { - struct gc_arena gc = gc_new (); - int n = 1000; - int n_mod = 25; + struct gc_arena gc = gc_new(); + int n = 1000; + int n_mod = 25; - int i, j; - struct schedule_entry **array; - struct schedule *s = schedule_init (); - struct schedule_entry* e; + int i, j; + struct schedule_entry **array; + struct schedule *s = schedule_init(); + struct schedule_entry *e; - CLEAR (z); - ALLOC_ARRAY (array, struct schedule_entry *, n); + CLEAR(z); + ALLOC_ARRAY(array, struct schedule_entry *, n); - printf ("Creation/Insertion Phase\n"); + printf("Creation/Insertion Phase\n"); - for (i = 0; i < n; ++i) + for (i = 0; i < n; ++i) { - ALLOC_OBJ_CLEAR (array[i], struct schedule_entry); - tv_randomize (&array[i]->tv); - /*schedule_print (s);*/ - /*schedule_verify (s);*/ - schedule_add_modify (s, array[i]); + ALLOC_OBJ_CLEAR(array[i], struct schedule_entry); + tv_randomize(&array[i]->tv); + /*schedule_print (s);*/ + /*schedule_verify (s);*/ + schedule_add_modify(s, array[i]); } - schedule_randomize_array (array, n); + schedule_randomize_array(array, n); - /*schedule_print (s);*/ - schedule_verify (s); + /*schedule_print (s);*/ + schedule_verify(s); - for (j = 1; j <= n_mod; ++j) + for (j = 1; j <= n_mod; ++j) { - printf ("Modification Phase Pass %d\n", j); - - for (i = 0; i < n; ++i) - { - e = schedule_find_earliest_wakeup (s); - /*printf ("BEFORE %s\n", tv_string (&e->tv, &gc));*/ - tv_randomize (&e->tv); - /*printf ("AFTER %s\n", tv_string (&e->tv, &gc));*/ - schedule_add_modify (s, e); - /*schedule_verify (s);*/ - /*schedule_print (s);*/ - } - schedule_verify (s); - /*schedule_print (s);*/ + printf("Modification Phase Pass %d\n", j); + + for (i = 0; i < n; ++i) + { + e = schedule_find_earliest_wakeup(s); + /*printf ("BEFORE %s\n", tv_string (&e->tv, &gc));*/ + tv_randomize(&e->tv); + /*printf ("AFTER %s\n", tv_string (&e->tv, &gc));*/ + schedule_add_modify(s, e); + /*schedule_verify (s);*/ + /*schedule_print (s);*/ + } + schedule_verify(s); + /*schedule_print (s);*/ } - /*printf ("INS=%d\n", z.ins);*/ + /*printf ("INS=%d\n", z.ins);*/ - while ((e = schedule_find_earliest_wakeup (s))) + while ((e = schedule_find_earliest_wakeup(s))) { - schedule_remove_node (s, e); - /*schedule_verify (s);*/ + schedule_remove_node(s, e); + /*schedule_verify (s);*/ } - schedule_verify (s); + schedule_verify(s); - printf ("S->ROOT is %s\n", s->root ? "NOT NULL" : "NULL"); + printf("S->ROOT is %s\n", s->root ? "NOT NULL" : "NULL"); - for (i = 0; i < n; ++i) + for (i = 0; i < n; ++i) { - free (array[i]); + free(array[i]); } - free (array); - free (s); - gc_free (&gc); + free(array); + free(s); + gc_free(&gc); } -#endif -#endif +#endif /* ifdef SCHEDULE_TEST */ +#endif /* if P2MP_SERVER */ diff --git a/src/openvpn/schedule.h b/src/openvpn/schedule.h index 71c6d8ca548..bdd443f9cc7 100644 --- a/src/openvpn/schedule.h +++ b/src/openvpn/schedule.h @@ -46,27 +46,30 @@ struct schedule_entry { - struct timeval tv; /* wakeup time */ - unsigned int pri; /* random treap priority */ - struct schedule_entry *parent; /* treap (btree) links */ - struct schedule_entry *lt; - struct schedule_entry *gt; + struct timeval tv; /* wakeup time */ + unsigned int pri; /* random treap priority */ + struct schedule_entry *parent; /* treap (btree) links */ + struct schedule_entry *lt; + struct schedule_entry *gt; }; struct schedule { - struct schedule_entry *earliest_wakeup; /* cached earliest wakeup */ - struct schedule_entry *root; /* the root of the treap (btree) */ + struct schedule_entry *earliest_wakeup; /* cached earliest wakeup */ + struct schedule_entry *root; /* the root of the treap (btree) */ }; /* Public functions */ -struct schedule *schedule_init (void); -void schedule_free (struct schedule *s); -void schedule_remove_entry (struct schedule *s, struct schedule_entry *e); +struct schedule *schedule_init(void); + +void schedule_free(struct schedule *s); + +void schedule_remove_entry(struct schedule *s, struct schedule_entry *e); #ifdef SCHEDULE_TEST -void schedule_test (void); +void schedule_test(void); + #endif /* Private Functions */ @@ -74,9 +77,11 @@ void schedule_test (void); /* is node already in tree? */ #define IN_TREE(e) ((e)->pri) -struct schedule_entry *schedule_find_least (struct schedule_entry *e); -void schedule_add_modify (struct schedule *s, struct schedule_entry *e); -void schedule_remove_node (struct schedule *s, struct schedule_entry *e); +struct schedule_entry *schedule_find_least(struct schedule_entry *e); + +void schedule_add_modify(struct schedule *s, struct schedule_entry *e); + +void schedule_remove_node(struct schedule *s, struct schedule_entry *e); /* Public inline functions */ @@ -93,16 +98,16 @@ void schedule_remove_node (struct schedule *s, struct schedule_entry *e); * an opaque object. */ static inline void -schedule_add_entry (struct schedule *s, - struct schedule_entry *e, - const struct timeval *tv, - unsigned int sigma) +schedule_add_entry(struct schedule *s, + struct schedule_entry *e, + const struct timeval *tv, + unsigned int sigma) { - if (!IN_TREE (e) || !sigma || !tv_within_sigma (tv, &e->tv, sigma)) + if (!IN_TREE(e) || !sigma || !tv_within_sigma(tv, &e->tv, sigma)) { - e->tv = *tv; - schedule_add_modify (s, e); - s->earliest_wakeup = NULL; /* invalidate cache */ + e->tv = *tv; + schedule_add_modify(s, e); + s->earliest_wakeup = NULL; /* invalidate cache */ } } @@ -113,20 +118,24 @@ schedule_add_entry (struct schedule *s, * is randomized every time an entry is re-added). */ static inline struct schedule_entry * -schedule_get_earliest_wakeup (struct schedule *s, - struct timeval *wakeup) +schedule_get_earliest_wakeup(struct schedule *s, + struct timeval *wakeup) { - struct schedule_entry *ret; + struct schedule_entry *ret; - /* cache result */ - if (!s->earliest_wakeup) - s->earliest_wakeup = schedule_find_least (s->root); - ret = s->earliest_wakeup; - if (ret) - *wakeup = ret->tv; + /* cache result */ + if (!s->earliest_wakeup) + { + s->earliest_wakeup = schedule_find_least(s->root); + } + ret = s->earliest_wakeup; + if (ret) + { + *wakeup = ret->tv; + } - return ret; + return ret; } -#endif -#endif +#endif /* if P2MP_SERVER */ +#endif /* ifndef SCHEDULE_H */ diff --git a/src/openvpn/session_id.c b/src/openvpn/session_id.c index 0ebff657e2d..029608e5f9d 100644 --- a/src/openvpn/session_id.c +++ b/src/openvpn/session_id.c @@ -51,17 +51,19 @@ const struct session_id x_session_id_zero; void -session_id_random (struct session_id *sid) +session_id_random(struct session_id *sid) { - prng_bytes (sid->id, SID_SIZE); + prng_bytes(sid->id, SID_SIZE); } const char * -session_id_print (const struct session_id *sid, struct gc_arena *gc) +session_id_print(const struct session_id *sid, struct gc_arena *gc) { - return format_hex (sid->id, SID_SIZE, 0, gc); + return format_hex(sid->id, SID_SIZE, 0, gc); } -#else -static void dummy(void) {} +#else /* ifdef ENABLE_CRYPTO */ +static void +dummy(void) { +} #endif /* ENABLE_CRYPTO */ diff --git a/src/openvpn/session_id.h b/src/openvpn/session_id.h index 2a1f41fdc58..0fb8f6ed34b 100644 --- a/src/openvpn/session_id.h +++ b/src/openvpn/session_id.h @@ -40,47 +40,47 @@ struct session_id { - uint8_t id[8]; + uint8_t id[8]; }; extern const struct session_id x_session_id_zero; -#define SID_SIZE (sizeof (x_session_id_zero.id)) +#define SID_SIZE (sizeof(x_session_id_zero.id)) static inline bool -session_id_equal (const struct session_id *sid1, - const struct session_id *sid2) +session_id_equal(const struct session_id *sid1, + const struct session_id *sid2) { - return !memcmp (sid1->id, sid2->id, SID_SIZE); + return !memcmp(sid1->id, sid2->id, SID_SIZE); } static inline bool -session_id_defined (const struct session_id *sid1) +session_id_defined(const struct session_id *sid1) { - return memcmp (sid1->id, &x_session_id_zero.id, SID_SIZE) != 0; + return memcmp(sid1->id, &x_session_id_zero.id, SID_SIZE) != 0; } static inline bool -session_id_read (struct session_id *sid, struct buffer *buf) +session_id_read(struct session_id *sid, struct buffer *buf) { - return buf_read (buf, sid->id, SID_SIZE); + return buf_read(buf, sid->id, SID_SIZE); } static inline bool -session_id_write_prepend (const struct session_id *sid, struct buffer *buf) +session_id_write_prepend(const struct session_id *sid, struct buffer *buf) { - return buf_write_prepend (buf, sid->id, SID_SIZE); + return buf_write_prepend(buf, sid->id, SID_SIZE); } static inline bool -session_id_write (const struct session_id *sid, struct buffer *buf) +session_id_write(const struct session_id *sid, struct buffer *buf) { - return buf_write (buf, sid->id, SID_SIZE); + return buf_write(buf, sid->id, SID_SIZE); } -void session_id_random (struct session_id *sid); +void session_id_random(struct session_id *sid); -const char *session_id_print (const struct session_id *sid, struct gc_arena *gc); +const char *session_id_print(const struct session_id *sid, struct gc_arena *gc); #endif /* SESSION_ID_H */ #endif /* ENABLE_CRYPTO */ diff --git a/src/openvpn/shaper.c b/src/openvpn/shaper.c index c8a7d38b2d3..05c179e6343 100644 --- a/src/openvpn/shaper.c +++ b/src/openvpn/shaper.c @@ -39,63 +39,65 @@ * than delay, set timeval to delay. */ bool -shaper_soonest_event (struct timeval *tv, int delay) +shaper_soonest_event(struct timeval *tv, int delay) { - bool ret = false; - if (delay < 1000000) + bool ret = false; + if (delay < 1000000) { - if (tv->tv_sec) - { - tv->tv_sec = 0; - tv->tv_usec = delay; - ret = true; - } - else if (delay < tv->tv_usec) - { - tv->tv_usec = delay; - ret = true; - } + if (tv->tv_sec) + { + tv->tv_sec = 0; + tv->tv_usec = delay; + ret = true; + } + else if (delay < tv->tv_usec) + { + tv->tv_usec = delay; + ret = true; + } } - else + else { - const int sec = delay / 1000000; - const int usec = delay % 1000000; + const int sec = delay / 1000000; + const int usec = delay % 1000000; - if (sec < tv->tv_sec) - { - tv->tv_sec = sec; - tv->tv_usec = usec; - ret = true; - } - else if (sec == tv->tv_sec) - { - if (usec < tv->tv_usec) - { - tv->tv_usec = usec; - ret = true; - } - } + if (sec < tv->tv_sec) + { + tv->tv_sec = sec; + tv->tv_usec = usec; + ret = true; + } + else if (sec == tv->tv_sec) + { + if (usec < tv->tv_usec) + { + tv->tv_usec = usec; + ret = true; + } + } } #ifdef SHAPER_DEBUG - dmsg (D_SHAPER_DEBUG, "SHAPER shaper_soonest_event sec=%d usec=%d ret=%d", - (int)tv->tv_sec, (int)tv->tv_usec, (int)ret); + dmsg(D_SHAPER_DEBUG, "SHAPER shaper_soonest_event sec=%d usec=%d ret=%d", + (int)tv->tv_sec, (int)tv->tv_usec, (int)ret); #endif - return ret; + return ret; } void -shaper_reset_wakeup (struct shaper *s) +shaper_reset_wakeup(struct shaper *s) { - CLEAR (s->wakeup); + CLEAR(s->wakeup); } void -shaper_msg (struct shaper *s) +shaper_msg(struct shaper *s) { - msg (M_INFO, "Output Traffic Shaping initialized at %d bytes per second", - s->bytes_per_second); + msg(M_INFO, "Output Traffic Shaping initialized at %d bytes per second", + s->bytes_per_second); } -#else -static void dummy(void) {} +#else /* ifdef ENABLE_FEATURE_SHAPER */ +static void +dummy(void) { +} #endif /* ENABLE_FEATURE_SHAPER */ diff --git a/src/openvpn/shaper.h b/src/openvpn/shaper.h index fa132c40bf1..21b4fb67d01 100644 --- a/src/openvpn/shaper.h +++ b/src/openvpn/shaper.h @@ -47,54 +47,55 @@ #define SHAPER_USE_FP -struct shaper +struct shaper { - int bytes_per_second; - struct timeval wakeup; + int bytes_per_second; + struct timeval wakeup; #ifdef SHAPER_USE_FP - double factor; + double factor; #else - int factor; + int factor; #endif }; -void shaper_msg (struct shaper *s); -void shaper_reset_wakeup (struct shaper *s); +void shaper_msg(struct shaper *s); + +void shaper_reset_wakeup(struct shaper *s); /* * We want to wake up in delay microseconds. If timeval is larger * than delay, set timeval to delay. */ -bool shaper_soonest_event (struct timeval *tv, int delay); +bool shaper_soonest_event(struct timeval *tv, int delay); /* * inline functions */ static inline void -shaper_reset (struct shaper *s, int bytes_per_second) +shaper_reset(struct shaper *s, int bytes_per_second) { - s->bytes_per_second = constrain_int (bytes_per_second, SHAPER_MIN, SHAPER_MAX); + s->bytes_per_second = constrain_int(bytes_per_second, SHAPER_MIN, SHAPER_MAX); #ifdef SHAPER_USE_FP - s->factor = 1000000.0 / (double)s->bytes_per_second; + s->factor = 1000000.0 / (double)s->bytes_per_second; #else - s->factor = 1000000 / s->bytes_per_second; + s->factor = 1000000 / s->bytes_per_second; #endif } static inline void -shaper_init (struct shaper *s, int bytes_per_second) +shaper_init(struct shaper *s, int bytes_per_second) { - shaper_reset (s, bytes_per_second); - shaper_reset_wakeup (s); + shaper_reset(s, bytes_per_second); + shaper_reset_wakeup(s); } static inline int -shaper_current_bandwidth (struct shaper *s) +shaper_current_bandwidth(struct shaper *s) { - return s->bytes_per_second; + return s->bytes_per_second; } /* @@ -102,21 +103,21 @@ shaper_current_bandwidth (struct shaper *s) * time, or 0 if no delay. */ static inline int -shaper_delay (struct shaper* s) +shaper_delay(struct shaper *s) { - struct timeval tv; - int delay = 0; + struct timeval tv; + int delay = 0; - if (tv_defined (&s->wakeup)) + if (tv_defined(&s->wakeup)) { - ASSERT (!openvpn_gettimeofday (&tv, NULL)); - delay = tv_subtract (&s->wakeup, &tv, SHAPER_MAX_TIMEOUT); + ASSERT(!openvpn_gettimeofday(&tv, NULL)); + delay = tv_subtract(&s->wakeup, &tv, SHAPER_MAX_TIMEOUT); #ifdef SHAPER_DEBUG - dmsg (D_SHAPER_DEBUG, "SHAPER shaper_delay delay=%d", delay); + dmsg(D_SHAPER_DEBUG, "SHAPER shaper_delay delay=%d", delay); #endif } - return delay > 0 ? delay : 0; + return delay > 0 ? delay : 0; } @@ -127,31 +128,31 @@ shaper_delay (struct shaper* s) * based on target throughput (s->bytes_per_second). */ static inline void -shaper_wrote_bytes (struct shaper* s, int nbytes) +shaper_wrote_bytes(struct shaper *s, int nbytes) { - struct timeval tv; + struct timeval tv; - /* compute delay in microseconds */ - tv.tv_sec = 0; + /* compute delay in microseconds */ + tv.tv_sec = 0; #ifdef SHAPER_USE_FP - tv.tv_usec = min_int ((int)((double)max_int (nbytes, 100) * s->factor), (SHAPER_MAX_TIMEOUT*1000000)); + tv.tv_usec = min_int((int)((double)max_int(nbytes, 100) * s->factor), (SHAPER_MAX_TIMEOUT*1000000)); #else - tv.tv_usec = s->bytes_per_second - ? min_int (max_int (nbytes, 100) * s->factor, (SHAPER_MAX_TIMEOUT*1000000)) - : 0; + tv.tv_usec = s->bytes_per_second + ? min_int(max_int(nbytes, 100) * s->factor, (SHAPER_MAX_TIMEOUT*1000000)) + : 0; #endif - if (tv.tv_usec) + if (tv.tv_usec) { - ASSERT (!openvpn_gettimeofday (&s->wakeup, NULL)); - tv_add (&s->wakeup, &tv); + ASSERT(!openvpn_gettimeofday(&s->wakeup, NULL)); + tv_add(&s->wakeup, &tv); #ifdef SHAPER_DEBUG - dmsg (D_SHAPER_DEBUG, "SHAPER shaper_wrote_bytes bytes=%d delay=%d sec=%d usec=%d", - nbytes, - (int)tv.tv_usec, - (int)s->wakeup.tv_sec, - (int)s->wakeup.tv_usec); + dmsg(D_SHAPER_DEBUG, "SHAPER shaper_wrote_bytes bytes=%d delay=%d sec=%d usec=%d", + nbytes, + (int)tv.tv_usec, + (int)s->wakeup.tv_sec, + (int)s->wakeup.tv_usec); #endif } } @@ -163,16 +164,16 @@ shaper_wrote_bytes (struct shaper* s, int nbytes) * Return true if bandwidth changed. */ static inline bool -shaper_change_pct (struct shaper *s, int pct) +shaper_change_pct(struct shaper *s, int pct) { - const int orig_bandwidth = s->bytes_per_second; - const int new_bandwidth = orig_bandwidth + (orig_bandwidth * pct / 100); - ASSERT (s->bytes_per_second); - shaper_reset (s, new_bandwidth); - return s->bytes_per_second != orig_bandwidth; + const int orig_bandwidth = s->bytes_per_second; + const int new_bandwidth = orig_bandwidth + (orig_bandwidth * pct / 100); + ASSERT(s->bytes_per_second); + shaper_reset(s, new_bandwidth); + return s->bytes_per_second != orig_bandwidth; } #endif #endif /* ENABLE_FEATURE_SHAPER */ -#endif +#endif /* ifndef SHAPER_H */ diff --git a/src/openvpn/sig.c b/src/openvpn/sig.c index b3ae645e2b2..bd473e32eea 100644 --- a/src/openvpn/sig.c +++ b/src/openvpn/sig.c @@ -47,164 +47,182 @@ struct signal_info siginfo_static; /* GLOBAL */ struct signame { - int value; - const char *upper; - const char *lower; + int value; + const char *upper; + const char *lower; }; static const struct signame signames[] = { - { SIGINT, "SIGINT", "sigint"}, - { SIGTERM, "SIGTERM", "sigterm" }, - { SIGHUP, "SIGHUP", "sighup" }, - { SIGUSR1, "SIGUSR1", "sigusr1" }, - { SIGUSR2, "SIGUSR2", "sigusr2" } + { SIGINT, "SIGINT", "sigint"}, + { SIGTERM, "SIGTERM", "sigterm" }, + { SIGHUP, "SIGHUP", "sighup" }, + { SIGUSR1, "SIGUSR1", "sigusr1" }, + { SIGUSR2, "SIGUSR2", "sigusr2" } }; int -parse_signal (const char *signame) +parse_signal(const char *signame) { - int i; - for (i = 0; i < (int)SIZE (signames); ++i) + int i; + for (i = 0; i < (int)SIZE(signames); ++i) { - if (!strcmp (signame, signames[i].upper)) - return signames[i].value; + if (!strcmp(signame, signames[i].upper)) + { + return signames[i].value; + } } - return -1; + return -1; } const char * -signal_name (const int sig, const bool upper) +signal_name(const int sig, const bool upper) { - int i; - for (i = 0; i < (int)SIZE (signames); ++i) + int i; + for (i = 0; i < (int)SIZE(signames); ++i) { - if (sig == signames[i].value) - return upper ? signames[i].upper : signames[i].lower; + if (sig == signames[i].value) + { + return upper ? signames[i].upper : signames[i].lower; + } } - return "UNKNOWN"; + return "UNKNOWN"; } const char * -signal_description (const int signum, const char *sigtext) +signal_description(const int signum, const char *sigtext) { - if (sigtext) - return sigtext; - else - return signal_name (signum, false); + if (sigtext) + { + return sigtext; + } + else + { + return signal_name(signum, false); + } } void -throw_signal (const int signum) +throw_signal(const int signum) { - siginfo_static.signal_received = signum; - siginfo_static.source = SIG_SOURCE_HARD; + siginfo_static.signal_received = signum; + siginfo_static.source = SIG_SOURCE_HARD; } void -throw_signal_soft (const int signum, const char *signal_text) +throw_signal_soft(const int signum, const char *signal_text) { - siginfo_static.signal_received = signum; - siginfo_static.source = SIG_SOURCE_SOFT; - siginfo_static.signal_text = signal_text; + siginfo_static.signal_received = signum; + siginfo_static.source = SIG_SOURCE_SOFT; + siginfo_static.signal_text = signal_text; } static void -signal_reset (struct signal_info *si) +signal_reset(struct signal_info *si) { - if (si) + if (si) { - si->signal_received = 0; - si->signal_text = NULL; - si->source = SIG_SOURCE_SOFT; + si->signal_received = 0; + si->signal_text = NULL; + si->source = SIG_SOURCE_SOFT; } } void -print_signal (const struct signal_info *si, const char *title, int msglevel) +print_signal(const struct signal_info *si, const char *title, int msglevel) { - if (si) + if (si) { - const char *type = (si->signal_text ? si->signal_text : ""); - const char *t = (title ? title : "process"); - const char *hs = NULL; - switch (si->source) + const char *type = (si->signal_text ? si->signal_text : ""); + const char *t = (title ? title : "process"); + const char *hs = NULL; + switch (si->source) { - case SIG_SOURCE_SOFT: - hs= "soft"; - break; - case SIG_SOURCE_HARD: - hs = "hard"; - break; - case SIG_SOURCE_CONNECTION_FAILED: - hs = "connection failed(soft)"; - break; - default: - ASSERT(0); + case SIG_SOURCE_SOFT: + hs = "soft"; + break; + + case SIG_SOURCE_HARD: + hs = "hard"; + break; + + case SIG_SOURCE_CONNECTION_FAILED: + hs = "connection failed(soft)"; + break; + + default: + ASSERT(0); } - switch (si->signal_received) - { - case SIGINT: - case SIGTERM: - msg (msglevel, "%s[%s,%s] received, %s exiting", - signal_name (si->signal_received, true), hs, type, t); - break; - case SIGHUP: - case SIGUSR1: - msg (msglevel, "%s[%s,%s] received, %s restarting", - signal_name (si->signal_received, true), hs, type, t); - break; - default: - msg (msglevel, "Unknown signal %d [%s,%s] received by %s", si->signal_received, hs, type, t); - break; - } + switch (si->signal_received) + { + case SIGINT: + case SIGTERM: + msg(msglevel, "%s[%s,%s] received, %s exiting", + signal_name(si->signal_received, true), hs, type, t); + break; + + case SIGHUP: + case SIGUSR1: + msg(msglevel, "%s[%s,%s] received, %s restarting", + signal_name(si->signal_received, true), hs, type, t); + break; + + default: + msg(msglevel, "Unknown signal %d [%s,%s] received by %s", si->signal_received, hs, type, t); + break; + } + } + else + { + msg(msglevel, "Unknown signal received"); } - else - msg (msglevel, "Unknown signal received"); } /* * Call management interface with restart info */ void -signal_restart_status (const struct signal_info *si) +signal_restart_status(const struct signal_info *si) { #ifdef ENABLE_MANAGEMENT - if (management) + if (management) { - int state = -1; - switch (si->signal_received) - { - case SIGINT: - case SIGTERM: - state = OPENVPN_STATE_EXITING; - break; - case SIGHUP: - case SIGUSR1: - state = OPENVPN_STATE_RECONNECTING; - break; - } - - if (state >= 0) - management_set_state (management, - state, - si->signal_text ? si->signal_text : signal_name (si->signal_received, true), - NULL, - NULL, - NULL, - NULL); + int state = -1; + switch (si->signal_received) + { + case SIGINT: + case SIGTERM: + state = OPENVPN_STATE_EXITING; + break; + + case SIGHUP: + case SIGUSR1: + state = OPENVPN_STATE_RECONNECTING; + break; + } + + if (state >= 0) + { + management_set_state(management, + state, + si->signal_text ? si->signal_text : signal_name(si->signal_received, true), + NULL, + NULL, + NULL, + NULL); + } } -#endif +#endif /* ifdef ENABLE_MANAGEMENT */ } #ifdef HAVE_SIGNAL_H /* normal signal handler, when we are in event loop */ static void -signal_handler (const int signum) +signal_handler(const int signum) { - throw_signal (signum); - signal (signum, signal_handler); + throw_signal(signum); + signal(signum, signal_handler); } #endif @@ -219,46 +237,50 @@ static int signal_mode; /* GLOBAL */ #endif void -pre_init_signal_catch (void) +pre_init_signal_catch(void) { #ifndef _WIN32 #ifdef HAVE_SIGNAL_H - signal_mode = SM_PRE_INIT; - signal (SIGINT, signal_handler); - signal (SIGTERM, signal_handler); - signal (SIGHUP, SIG_IGN); - signal (SIGUSR1, SIG_IGN); - signal (SIGUSR2, SIG_IGN); - signal (SIGPIPE, SIG_IGN); + signal_mode = SM_PRE_INIT; + signal(SIGINT, signal_handler); + signal(SIGTERM, signal_handler); + signal(SIGHUP, SIG_IGN); + signal(SIGUSR1, SIG_IGN); + signal(SIGUSR2, SIG_IGN); + signal(SIGPIPE, SIG_IGN); #endif /* HAVE_SIGNAL_H */ #endif /* _WIN32 */ } void -post_init_signal_catch (void) +post_init_signal_catch(void) { #ifndef _WIN32 #ifdef HAVE_SIGNAL_H - signal_mode = SM_POST_INIT; - signal (SIGINT, signal_handler); - signal (SIGTERM, signal_handler); - signal (SIGHUP, signal_handler); - signal (SIGUSR1, signal_handler); - signal (SIGUSR2, signal_handler); - signal (SIGPIPE, SIG_IGN); + signal_mode = SM_POST_INIT; + signal(SIGINT, signal_handler); + signal(SIGTERM, signal_handler); + signal(SIGHUP, signal_handler); + signal(SIGUSR1, signal_handler); + signal(SIGUSR2, signal_handler); + signal(SIGPIPE, SIG_IGN); #endif /* HAVE_SIGNAL_H */ #endif } /* called after daemonization to retain signal settings */ void -restore_signal_state (void) +restore_signal_state(void) { #ifdef HAVE_SIGNAL_H - if (signal_mode == SM_PRE_INIT) - pre_init_signal_catch (); - else if (signal_mode == SM_POST_INIT) - post_init_signal_catch (); + if (signal_mode == SM_PRE_INIT) + { + pre_init_signal_catch(); + } + else if (signal_mode == SM_POST_INIT) + { + post_init_signal_catch(); + } #endif } @@ -268,38 +290,42 @@ restore_signal_state (void) * Triggered by SIGUSR2 or F2 on Windows. */ void -print_status (const struct context *c, struct status_output *so) +print_status(const struct context *c, struct status_output *so) { - struct gc_arena gc = gc_new (); + struct gc_arena gc = gc_new(); - status_reset (so); + status_reset(so); - status_printf (so, "OpenVPN STATISTICS"); - status_printf (so, "Updated,%s", time_string (0, 0, false, &gc)); - status_printf (so, "TUN/TAP read bytes," counter_format, c->c2.tun_read_bytes); - status_printf (so, "TUN/TAP write bytes," counter_format, c->c2.tun_write_bytes); - status_printf (so, "TCP/UDP read bytes," counter_format, c->c2.link_read_bytes); - status_printf (so, "TCP/UDP write bytes," counter_format, c->c2.link_write_bytes); - status_printf (so, "Auth read bytes," counter_format, c->c2.link_read_bytes_auth); + status_printf(so, "OpenVPN STATISTICS"); + status_printf(so, "Updated,%s", time_string(0, 0, false, &gc)); + status_printf(so, "TUN/TAP read bytes," counter_format, c->c2.tun_read_bytes); + status_printf(so, "TUN/TAP write bytes," counter_format, c->c2.tun_write_bytes); + status_printf(so, "TCP/UDP read bytes," counter_format, c->c2.link_read_bytes); + status_printf(so, "TCP/UDP write bytes," counter_format, c->c2.link_write_bytes); + status_printf(so, "Auth read bytes," counter_format, c->c2.link_read_bytes_auth); #ifdef USE_COMP - if (c->c2.comp_context) - comp_print_stats (c->c2.comp_context, so); + if (c->c2.comp_context) + { + comp_print_stats(c->c2.comp_context, so); + } #endif #ifdef PACKET_TRUNCATION_CHECK - status_printf (so, "TUN read truncations," counter_format, c->c2.n_trunc_tun_read); - status_printf (so, "TUN write truncations," counter_format, c->c2.n_trunc_tun_write); - status_printf (so, "Pre-encrypt truncations," counter_format, c->c2.n_trunc_pre_encrypt); - status_printf (so, "Post-decrypt truncations," counter_format, c->c2.n_trunc_post_decrypt); + status_printf(so, "TUN read truncations," counter_format, c->c2.n_trunc_tun_read); + status_printf(so, "TUN write truncations," counter_format, c->c2.n_trunc_tun_write); + status_printf(so, "Pre-encrypt truncations," counter_format, c->c2.n_trunc_pre_encrypt); + status_printf(so, "Post-decrypt truncations," counter_format, c->c2.n_trunc_post_decrypt); #endif #ifdef _WIN32 - if (tuntap_defined (c->c1.tuntap)) - status_printf (so, "TAP-WIN32 driver status,\"%s\"", - tap_win_getinfo (c->c1.tuntap, &gc)); + if (tuntap_defined(c->c1.tuntap)) + { + status_printf(so, "TAP-WIN32 driver status,\"%s\"", + tap_win_getinfo(c->c1.tuntap, &gc)); + } #endif - status_printf (so, "END"); - status_flush (so); - gc_free (&gc); + status_printf(so, "END"); + status_flush(so); + gc_free(&gc); } #ifdef ENABLE_OCC @@ -309,71 +335,73 @@ print_status (const struct context *c, struct status_output *so) */ static void -process_explicit_exit_notification_init (struct context *c) +process_explicit_exit_notification_init(struct context *c) { - msg (M_INFO, "SIGTERM received, sending exit notification to peer"); - event_timeout_init (&c->c2.explicit_exit_notification_interval, 1, 0); - reset_coarse_timers (c); - signal_reset (c->sig); - halt_non_edge_triggered_signals (); - c->c2.explicit_exit_notification_time_wait = now; + msg(M_INFO, "SIGTERM received, sending exit notification to peer"); + event_timeout_init(&c->c2.explicit_exit_notification_interval, 1, 0); + reset_coarse_timers(c); + signal_reset(c->sig); + halt_non_edge_triggered_signals(); + c->c2.explicit_exit_notification_time_wait = now; } void -process_explicit_exit_notification_timer_wakeup (struct context *c) +process_explicit_exit_notification_timer_wakeup(struct context *c) { - if (event_timeout_trigger (&c->c2.explicit_exit_notification_interval, - &c->c2.timeval, - ETT_DEFAULT)) + if (event_timeout_trigger(&c->c2.explicit_exit_notification_interval, + &c->c2.timeval, + ETT_DEFAULT)) { - ASSERT (c->c2.explicit_exit_notification_time_wait && c->options.ce.explicit_exit_notification); - if (now >= c->c2.explicit_exit_notification_time_wait + c->options.ce.explicit_exit_notification) - { - event_timeout_clear (&c->c2.explicit_exit_notification_interval); - c->sig->signal_received = SIGTERM; - c->sig->signal_text = "exit-with-notification"; - } - else - { - c->c2.occ_op = OCC_EXIT; - } + ASSERT(c->c2.explicit_exit_notification_time_wait && c->options.ce.explicit_exit_notification); + if (now >= c->c2.explicit_exit_notification_time_wait + c->options.ce.explicit_exit_notification) + { + event_timeout_clear(&c->c2.explicit_exit_notification_interval); + c->sig->signal_received = SIGTERM; + c->sig->signal_text = "exit-with-notification"; + } + else + { + c->c2.occ_op = OCC_EXIT; + } } } -#endif +#endif /* ifdef ENABLE_OCC */ /* * Process signals */ void -remap_signal (struct context *c) +remap_signal(struct context *c) { - if (c->sig->signal_received == SIGUSR1 && c->options.remap_sigusr1) - c->sig->signal_received = c->options.remap_sigusr1; + if (c->sig->signal_received == SIGUSR1 && c->options.remap_sigusr1) + { + c->sig->signal_received = c->options.remap_sigusr1; + } } static void -process_sigusr2 (const struct context *c) +process_sigusr2(const struct context *c) { - struct status_output *so = status_open (NULL, 0, M_INFO, NULL, 0); - print_status (c, so); - status_close (so); - signal_reset (c->sig); + struct status_output *so = status_open(NULL, 0, M_INFO, NULL, 0); + print_status(c, so); + status_close(so); + signal_reset(c->sig); } static bool -process_sigterm (struct context *c) +process_sigterm(struct context *c) { - bool ret = true; + bool ret = true; #ifdef ENABLE_OCC - if (c->options.ce.explicit_exit_notification - && !c->c2.explicit_exit_notification_time_wait) + if (c->options.ce.explicit_exit_notification + && !c->c2.explicit_exit_notification_time_wait) { - process_explicit_exit_notification_init (c); - ret = false; + process_explicit_exit_notification_init(c); + ret = false; } #endif - return ret; + return ret; } /** @@ -382,55 +410,59 @@ process_sigterm (struct context *c) * which implies the loop cannot continue, remap to SIGTERM to exit promptly. */ static bool -ignore_restart_signals (struct context *c) +ignore_restart_signals(struct context *c) { - bool ret = false; + bool ret = false; #ifdef ENABLE_OCC - if ( (c->sig->signal_received == SIGUSR1 || c->sig->signal_received == SIGHUP) && - event_timeout_defined(&c->c2.explicit_exit_notification_interval) ) + if ( (c->sig->signal_received == SIGUSR1 || c->sig->signal_received == SIGHUP) + && event_timeout_defined(&c->c2.explicit_exit_notification_interval) ) { - if (c->sig->source == SIG_SOURCE_HARD) - { - msg (M_INFO, "Ignoring %s received during exit notification", - signal_name(c->sig->signal_received, true)); - signal_reset (c->sig); + if (c->sig->source == SIG_SOURCE_HARD) + { + msg(M_INFO, "Ignoring %s received during exit notification", + signal_name(c->sig->signal_received, true)); + signal_reset(c->sig); ret = true; - } - else - { - msg (M_INFO, "Converting soft %s received during exit notification to SIGTERM", - signal_name(c->sig->signal_received, true)); + } + else + { + msg(M_INFO, "Converting soft %s received during exit notification to SIGTERM", + signal_name(c->sig->signal_received, true)); register_signal(c, SIGTERM, "exit-with-notification"); ret = false; - } + } } #endif - return ret; + return ret; } bool -process_signal (struct context *c) +process_signal(struct context *c) { - bool ret = true; + bool ret = true; - if (ignore_restart_signals (c)) - ret = false; - else if (c->sig->signal_received == SIGTERM || c->sig->signal_received == SIGINT) + if (ignore_restart_signals(c)) + { + ret = false; + } + else if (c->sig->signal_received == SIGTERM || c->sig->signal_received == SIGINT) { - ret = process_sigterm (c); + ret = process_sigterm(c); } - else if (c->sig->signal_received == SIGUSR2) + else if (c->sig->signal_received == SIGUSR2) { - process_sigusr2 (c); - ret = false; + process_sigusr2(c); + ret = false; } - return ret; + return ret; } void -register_signal (struct context *c, int sig, const char *text) +register_signal(struct context *c, int sig, const char *text) { - if (c->sig->signal_received != SIGTERM) - c->sig->signal_received = sig; - c->sig->signal_text = text; + if (c->sig->signal_received != SIGTERM) + { + c->sig->signal_received = sig; + } + c->sig->signal_text = text; } diff --git a/src/openvpn/sig.h b/src/openvpn/sig.h index 2875a4c9c79..9536a6e2df6 100644 --- a/src/openvpn/sig.h +++ b/src/openvpn/sig.h @@ -43,9 +43,9 @@ */ struct signal_info { - volatile int signal_received; - volatile int source; - const char *signal_text; + volatile int signal_received; + volatile int source; + const char *signal_text; }; #define IS_SIG(c) ((c)->sig->signal_received) @@ -54,60 +54,70 @@ struct context; extern struct signal_info siginfo_static; -int parse_signal (const char *signame); -const char *signal_name (const int sig, const bool upper); -const char *signal_description (const int signum, const char *sigtext); -void throw_signal (const int signum); -void throw_signal_soft (const int signum, const char *signal_text); +int parse_signal(const char *signame); -void pre_init_signal_catch (void); -void post_init_signal_catch (void); -void restore_signal_state (void); +const char *signal_name(const int sig, const bool upper); -void print_signal (const struct signal_info *si, const char *title, int msglevel); -void print_status (const struct context *c, struct status_output *so); +const char *signal_description(const int signum, const char *sigtext); -void remap_signal (struct context *c); +void throw_signal(const int signum); -void signal_restart_status (const struct signal_info *si); +void throw_signal_soft(const int signum, const char *signal_text); -bool process_signal (struct context *c); +void pre_init_signal_catch(void); -void register_signal (struct context *c, int sig, const char *text); +void post_init_signal_catch(void); + +void restore_signal_state(void); + +void print_signal(const struct signal_info *si, const char *title, int msglevel); + +void print_status(const struct context *c, struct status_output *so); + +void remap_signal(struct context *c); + +void signal_restart_status(const struct signal_info *si); + +bool process_signal(struct context *c); + +void register_signal(struct context *c, int sig, const char *text); #ifdef ENABLE_OCC -void process_explicit_exit_notification_timer_wakeup (struct context *c); +void process_explicit_exit_notification_timer_wakeup(struct context *c); + #endif #ifdef _WIN32 static inline void -get_signal (volatile int *sig) +get_signal(volatile int *sig) { - *sig = win32_signal_get (&win32_signal); + *sig = win32_signal_get(&win32_signal); } static inline void -halt_non_edge_triggered_signals (void) +halt_non_edge_triggered_signals(void) { - win32_signal_close (&win32_signal); + win32_signal_close(&win32_signal); } -#else +#else /* ifdef _WIN32 */ static inline void -get_signal (volatile int *sig) +get_signal(volatile int *sig) { - const int i = siginfo_static.signal_received; - if (i) - *sig = i; + const int i = siginfo_static.signal_received; + if (i) + { + *sig = i; + } } static inline void -halt_non_edge_triggered_signals (void) +halt_non_edge_triggered_signals(void) { } -#endif +#endif /* ifdef _WIN32 */ -#endif +#endif /* ifndef SIG_H */ diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c index ce53ee88eeb..516a8f663fd 100644 --- a/src/openvpn/socket.c +++ b/src/openvpn/socket.c @@ -45,14 +45,14 @@ #include "memdbg.h" const int proto_overhead[] = { /* indexed by PROTO_x */ - 0, - IPv4_UDP_HEADER_SIZE, /* IPv4 */ - IPv4_TCP_HEADER_SIZE, - IPv4_TCP_HEADER_SIZE, - IPv6_UDP_HEADER_SIZE, /* IPv6 */ - IPv6_TCP_HEADER_SIZE, - IPv6_TCP_HEADER_SIZE, - IPv6_TCP_HEADER_SIZE, + 0, + IPv4_UDP_HEADER_SIZE, /* IPv4 */ + IPv4_TCP_HEADER_SIZE, + IPv4_TCP_HEADER_SIZE, + IPv6_UDP_HEADER_SIZE, /* IPv6 */ + IPv6_TCP_HEADER_SIZE, + IPv6_TCP_HEADER_SIZE, + IPv6_TCP_HEADER_SIZE, }; /* @@ -62,10 +62,14 @@ static unsigned int sf2gaf(const unsigned int getaddr_flags, const unsigned int sockflags) { - if (sockflags & SF_HOST_RANDOMIZE) - return getaddr_flags | GETADDR_RANDOMIZE; - else - return getaddr_flags; + if (sockflags & SF_HOST_RANDOMIZE) + { + return getaddr_flags | GETADDR_RANDOMIZE; + } + else + { + return getaddr_flags; + } } /* @@ -78,201 +82,232 @@ sf2gaf(const unsigned int getaddr_flags, * resolve_retry_seconds seconds. */ in_addr_t -getaddr (unsigned int flags, - const char *hostname, - int resolve_retry_seconds, - bool *succeeded, - volatile int *signal_received) -{ - struct addrinfo *ai; - int status; - status = openvpn_getaddrinfo (flags & ~GETADDR_HOST_ORDER, hostname, NULL, - resolve_retry_seconds, signal_received, AF_INET, &ai); - if(status==0) { - struct in_addr ia; - if(succeeded) - *succeeded=true; - ia = ((struct sockaddr_in*)ai->ai_addr)->sin_addr; - freeaddrinfo(ai); - return (flags & GETADDR_HOST_ORDER) ? ntohl (ia.s_addr) : ia.s_addr; - } else { - if(succeeded) - *succeeded =false; - return 0; - } +getaddr(unsigned int flags, + const char *hostname, + int resolve_retry_seconds, + bool *succeeded, + volatile int *signal_received) +{ + struct addrinfo *ai; + int status; + status = openvpn_getaddrinfo(flags & ~GETADDR_HOST_ORDER, hostname, NULL, + resolve_retry_seconds, signal_received, AF_INET, &ai); + if (status==0) + { + struct in_addr ia; + if (succeeded) + { + *succeeded = true; + } + ia = ((struct sockaddr_in *)ai->ai_addr)->sin_addr; + freeaddrinfo(ai); + return (flags & GETADDR_HOST_ORDER) ? ntohl(ia.s_addr) : ia.s_addr; + } + else + { + if (succeeded) + { + *succeeded = false; + } + return 0; + } } static inline bool -streqnull (const char* a, const char* b) +streqnull(const char *a, const char *b) { - if (a == NULL && b == NULL) - return true; - else if (a == NULL || b == NULL) - return false; - else - return streq (a, b); + if (a == NULL && b == NULL) + { + return true; + } + else if (a == NULL || b == NULL) + { + return false; + } + else + { + return streq(a, b); + } } /* - get_cached_dns_entry return 0 on success and -1 - otherwise. (like getaddrinfo) + * get_cached_dns_entry return 0 on success and -1 + * otherwise. (like getaddrinfo) */ static int -get_cached_dns_entry (struct cached_dns_entry* dns_cache, - const char* hostname, - const char* servname, - int ai_family, - int resolve_flags, - struct addrinfo **ai) +get_cached_dns_entry(struct cached_dns_entry *dns_cache, + const char *hostname, + const char *servname, + int ai_family, + int resolve_flags, + struct addrinfo **ai) { - struct cached_dns_entry *ph; - int flags; + struct cached_dns_entry *ph; + int flags; - /* Only use flags that are relevant for the structure */ - flags = resolve_flags & GETADDR_CACHE_MASK; + /* Only use flags that are relevant for the structure */ + flags = resolve_flags & GETADDR_CACHE_MASK; - for (ph = dns_cache; ph ; ph = ph->next) + for (ph = dns_cache; ph; ph = ph->next) { - if (streqnull (ph->hostname, hostname) && - streqnull (ph->servname, servname) && - ph->ai_family == ai_family && - ph->flags == flags) - { - *ai = ph->ai; - return 0; - } + if (streqnull(ph->hostname, hostname) + && streqnull(ph->servname, servname) + && ph->ai_family == ai_family + && ph->flags == flags) + { + *ai = ph->ai; + return 0; + } } - return -1; + return -1; } static int -do_preresolve_host (struct context *c, - const char *hostname, - const char *servname, - const int af, - const int flags) +do_preresolve_host(struct context *c, + const char *hostname, + const char *servname, + const int af, + const int flags) { - struct addrinfo *ai; - int status; + struct addrinfo *ai; + int status; - if (get_cached_dns_entry(c->c1.dns_cache, - hostname, - servname, - af, - flags, - &ai) == 0 ) + if (get_cached_dns_entry(c->c1.dns_cache, + hostname, + servname, + af, + flags, + &ai) == 0) { - /* entry already cached, return success */ - return 0; + /* entry already cached, return success */ + return 0; } - status = openvpn_getaddrinfo (flags, hostname, servname, - c->options.resolve_retry_seconds, NULL, - af, &ai); - if (status == 0) + status = openvpn_getaddrinfo(flags, hostname, servname, + c->options.resolve_retry_seconds, NULL, + af, &ai); + if (status == 0) { - struct cached_dns_entry *ph; + struct cached_dns_entry *ph; - ALLOC_OBJ_CLEAR_GC (ph, struct cached_dns_entry, &c->gc); - ph->ai = ai; - ph->hostname = hostname; - ph->servname = servname; - ph->flags = flags & GETADDR_CACHE_MASK; + ALLOC_OBJ_CLEAR_GC(ph, struct cached_dns_entry, &c->gc); + ph->ai = ai; + ph->hostname = hostname; + ph->servname = servname; + ph->flags = flags & GETADDR_CACHE_MASK; - if (!c->c1.dns_cache) - c->c1.dns_cache = ph; - else - { - struct cached_dns_entry *prev = c->c1.dns_cache; - while (prev->next) - prev = prev->next; - prev->next = ph; - } + if (!c->c1.dns_cache) + { + c->c1.dns_cache = ph; + } + else + { + struct cached_dns_entry *prev = c->c1.dns_cache; + while (prev->next) + prev = prev->next; + prev->next = ph; + } - gc_addspecial (ai, &gc_freeaddrinfo_callback, &c->gc); + gc_addspecial(ai, &gc_freeaddrinfo_callback, &c->gc); } - return status; + return status; } void -do_preresolve (struct context *c) -{ - int i; - struct connection_list *l = c->options.connection_list; - const unsigned int preresolve_flags = GETADDR_RESOLVE| - GETADDR_UPDATE_MANAGEMENT_STATE| - GETADDR_MENTION_RESOLVE_RETRY| - GETADDR_FATAL; - - - for (i = 0; i < l->len; ++i) - { - int status; - const char *remote; - int flags = preresolve_flags; - - struct connection_entry* ce = c->options.connection_list->array[i]; - - if (proto_is_dgram(ce->proto)) - flags |= GETADDR_DATAGRAM; - - if (c->options.sockflags & SF_HOST_RANDOMIZE) - flags |= GETADDR_RANDOMIZE; - - if (c->options.ip_remote_hint) - remote = c->options.ip_remote_hint; - else - remote = ce->remote; - - /* HTTP remote hostname does not need to be resolved */ - if (! ce->http_proxy_options) - { - status = do_preresolve_host (c, remote, ce->remote_port, ce->af, flags); - if (status != 0) - goto err; - } - - /* Preresolve proxy */ - if (ce->http_proxy_options) - { - status = do_preresolve_host (c, - ce->http_proxy_options->server, - ce->http_proxy_options->port, - ce->af, - preresolve_flags); - - if (status != 0) - goto err; - } - - if (ce->socks_proxy_server) - { - status = do_preresolve_host (c, - ce->socks_proxy_server, - ce->socks_proxy_port, - ce->af, - flags); - if (status != 0) - goto err; - } - - if (ce->bind_local) - { - flags |= GETADDR_PASSIVE; - flags &= ~GETADDR_RANDOMIZE; - status = do_preresolve_host (c, ce->local, ce->local_port, ce->af, flags); - if (status != 0) - goto err; - - } +do_preresolve(struct context *c) +{ + int i; + struct connection_list *l = c->options.connection_list; + const unsigned int preresolve_flags = GETADDR_RESOLVE + |GETADDR_UPDATE_MANAGEMENT_STATE + |GETADDR_MENTION_RESOLVE_RETRY + |GETADDR_FATAL; + + + for (i = 0; i < l->len; ++i) + { + int status; + const char *remote; + int flags = preresolve_flags; + + struct connection_entry *ce = c->options.connection_list->array[i]; + + if (proto_is_dgram(ce->proto)) + { + flags |= GETADDR_DATAGRAM; + } + + if (c->options.sockflags & SF_HOST_RANDOMIZE) + { + flags |= GETADDR_RANDOMIZE; + } + + if (c->options.ip_remote_hint) + { + remote = c->options.ip_remote_hint; + } + else + { + remote = ce->remote; + } + + /* HTTP remote hostname does not need to be resolved */ + if (!ce->http_proxy_options) + { + status = do_preresolve_host(c, remote, ce->remote_port, ce->af, flags); + if (status != 0) + { + goto err; + } + } + + /* Preresolve proxy */ + if (ce->http_proxy_options) + { + status = do_preresolve_host(c, + ce->http_proxy_options->server, + ce->http_proxy_options->port, + ce->af, + preresolve_flags); + + if (status != 0) + { + goto err; + } + } + + if (ce->socks_proxy_server) + { + status = do_preresolve_host(c, + ce->socks_proxy_server, + ce->socks_proxy_port, + ce->af, + flags); + if (status != 0) + { + goto err; + } + } + + if (ce->bind_local) + { + flags |= GETADDR_PASSIVE; + flags &= ~GETADDR_RANDOMIZE; + status = do_preresolve_host(c, ce->local, ce->local_port, ce->af, flags); + if (status != 0) + { + goto err; + } + + } } return; - err: - throw_signal_soft (SIGHUP, "Preresolving failed"); +err: + throw_signal_soft(SIGHUP, "Preresolving failed"); } /* @@ -280,185 +315,220 @@ do_preresolve (struct context *c) * If resolve error, try again for resolve_retry_seconds seconds. */ int -openvpn_getaddrinfo (unsigned int flags, - const char *hostname, - const char *servname, - int resolve_retry_seconds, - volatile int *signal_received, - int ai_family, - struct addrinfo **res) +openvpn_getaddrinfo(unsigned int flags, + const char *hostname, + const char *servname, + int resolve_retry_seconds, + volatile int *signal_received, + int ai_family, + struct addrinfo **res) { - struct addrinfo hints; - int status; - int sigrec = 0; - int msglevel = (flags & GETADDR_FATAL) ? M_FATAL : D_RESOLVE_ERRORS; - struct gc_arena gc = gc_new (); - const char *print_hostname; - const char *print_servname; + struct addrinfo hints; + int status; + int sigrec = 0; + int msglevel = (flags & GETADDR_FATAL) ? M_FATAL : D_RESOLVE_ERRORS; + struct gc_arena gc = gc_new(); + const char *print_hostname; + const char *print_servname; - ASSERT(res); + ASSERT(res); - ASSERT (hostname || servname); - ASSERT (!(flags & GETADDR_HOST_ORDER)); + ASSERT(hostname || servname); + ASSERT(!(flags & GETADDR_HOST_ORDER)); - if (hostname && (flags & GETADDR_RANDOMIZE)) - hostname = hostname_randomize(hostname, &gc); + if (hostname && (flags & GETADDR_RANDOMIZE)) + { + hostname = hostname_randomize(hostname, &gc); + } - if(hostname) - print_hostname = hostname; - else - print_hostname = "undefined"; + if (hostname) + { + print_hostname = hostname; + } + else + { + print_hostname = "undefined"; + } - if(servname) - print_servname = servname; - else - print_servname = ""; + if (servname) + { + print_servname = servname; + } + else + { + print_servname = ""; + } - if (flags & GETADDR_MSG_VIRT_OUT) - msglevel |= M_MSG_VIRT_OUT; + if (flags & GETADDR_MSG_VIRT_OUT) + { + msglevel |= M_MSG_VIRT_OUT; + } - if ((flags & (GETADDR_FATAL_ON_SIGNAL|GETADDR_WARN_ON_SIGNAL)) - && !signal_received) - signal_received = &sigrec; + if ((flags & (GETADDR_FATAL_ON_SIGNAL|GETADDR_WARN_ON_SIGNAL)) + && !signal_received) + { + signal_received = &sigrec; + } - /* try numeric ipv6 addr first */ - CLEAR(hints); - hints.ai_family = ai_family; - hints.ai_flags = AI_NUMERICHOST; + /* try numeric ipv6 addr first */ + CLEAR(hints); + hints.ai_family = ai_family; + hints.ai_flags = AI_NUMERICHOST; - if(flags & GETADDR_PASSIVE) - hints.ai_flags |= AI_PASSIVE; + if (flags & GETADDR_PASSIVE) + { + hints.ai_flags |= AI_PASSIVE; + } - if(flags & GETADDR_DATAGRAM) - hints.ai_socktype = SOCK_DGRAM; - else - hints.ai_socktype = SOCK_STREAM; + if (flags & GETADDR_DATAGRAM) + { + hints.ai_socktype = SOCK_DGRAM; + } + else + { + hints.ai_socktype = SOCK_STREAM; + } - status = getaddrinfo(hostname, servname, &hints, res); + status = getaddrinfo(hostname, servname, &hints, res); - if (status != 0) /* parse as numeric address failed? */ + if (status != 0) /* parse as numeric address failed? */ { - const int fail_wait_interval = 5; /* seconds */ - /* Add +4 to cause integer division rounding up (1 + 4) = 5, (0+4)/5=0 */ - int resolve_retries = (flags & GETADDR_TRY_ONCE) ? 1 : - ((resolve_retry_seconds + 4)/ fail_wait_interval); - const char *fmt; - int level = 0; + const int fail_wait_interval = 5; /* seconds */ + /* Add +4 to cause integer division rounding up (1 + 4) = 5, (0+4)/5=0 */ + int resolve_retries = (flags & GETADDR_TRY_ONCE) ? 1 : + ((resolve_retry_seconds + 4)/ fail_wait_interval); + const char *fmt; + int level = 0; - fmt = "RESOLVE: Cannot resolve host address: %s:%s (%s)"; - if ((flags & GETADDR_MENTION_RESOLVE_RETRY) - && !resolve_retry_seconds) - fmt = "RESOLVE: Cannot resolve host address: %s:%s (%s) (I would have retried this name query if you had specified the --resolv-retry option.)"; + fmt = "RESOLVE: Cannot resolve host address: %s:%s (%s)"; + if ((flags & GETADDR_MENTION_RESOLVE_RETRY) + && !resolve_retry_seconds) + { + fmt = "RESOLVE: Cannot resolve host address: %s:%s (%s) (I would have retried this name query if you had specified the --resolv-retry option.)"; + } - if (!(flags & GETADDR_RESOLVE) || status == EAI_FAIL) + if (!(flags & GETADDR_RESOLVE) || status == EAI_FAIL) { - msg (msglevel, "RESOLVE: Cannot parse IP address: %s:%s (%s)", - print_hostname,print_servname, gai_strerror(status)); - goto done; + msg(msglevel, "RESOLVE: Cannot parse IP address: %s:%s (%s)", + print_hostname,print_servname, gai_strerror(status)); + goto done; } #ifdef ENABLE_MANAGEMENT - if (flags & GETADDR_UPDATE_MANAGEMENT_STATE) + if (flags & GETADDR_UPDATE_MANAGEMENT_STATE) { - if (management) - management_set_state (management, - OPENVPN_STATE_RESOLVE, - NULL, - NULL, - NULL, - NULL, - NULL); + if (management) + { + management_set_state(management, + OPENVPN_STATE_RESOLVE, + NULL, + NULL, + NULL, + NULL, + NULL); + } } #endif - /* - * Resolve hostname - */ - while (true) + /* + * Resolve hostname + */ + while (true) { #ifndef _WIN32 - res_init (); + res_init(); #endif - /* try hostname lookup */ - hints.ai_flags &= ~AI_NUMERICHOST; - dmsg (D_SOCKET_DEBUG, "GETADDRINFO flags=0x%04x ai_family=%d ai_socktype=%d", - flags, hints.ai_family, hints.ai_socktype); - status = getaddrinfo(hostname, servname, &hints, res); + /* try hostname lookup */ + hints.ai_flags &= ~AI_NUMERICHOST; + dmsg(D_SOCKET_DEBUG, "GETADDRINFO flags=0x%04x ai_family=%d ai_socktype=%d", + flags, hints.ai_family, hints.ai_socktype); + status = getaddrinfo(hostname, servname, &hints, res); - if (signal_received) + if (signal_received) { - get_signal (signal_received); - if (*signal_received) /* were we interrupted by a signal? */ + get_signal(signal_received); + if (*signal_received) /* were we interrupted by a signal? */ { - if (*signal_received == SIGUSR1) /* ignore SIGUSR1 */ + if (*signal_received == SIGUSR1) /* ignore SIGUSR1 */ { - msg (level, "RESOLVE: Ignored SIGUSR1 signal received during DNS resolution attempt"); - *signal_received = 0; + msg(level, "RESOLVE: Ignored SIGUSR1 signal received during DNS resolution attempt"); + *signal_received = 0; } - else + else { - /* turn success into failure (interrupted syscall) */ - if (0 == status) { - ASSERT(res); - freeaddrinfo(*res); - *res = NULL; - status = EAI_AGAIN; /* = temporary failure */ - errno = EINTR; - } - goto done; + /* turn success into failure (interrupted syscall) */ + if (0 == status) + { + ASSERT(res); + freeaddrinfo(*res); + *res = NULL; + status = EAI_AGAIN; /* = temporary failure */ + errno = EINTR; + } + goto done; } } } - /* success? */ - if (0 == status) - break; + /* success? */ + if (0 == status) + { + break; + } - /* resolve lookup failed, should we - continue or fail? */ - level = msglevel; - if (resolve_retries > 0) - level = D_RESOLVE_ERRORS; + /* resolve lookup failed, should we + * continue or fail? */ + level = msglevel; + if (resolve_retries > 0) + { + level = D_RESOLVE_ERRORS; + } - msg (level, - fmt, - print_hostname, - print_servname, - gai_strerror(status)); + msg(level, + fmt, + print_hostname, + print_servname, + gai_strerror(status)); - if (--resolve_retries <= 0) - goto done; + if (--resolve_retries <= 0) + { + goto done; + } - openvpn_sleep (fail_wait_interval); + openvpn_sleep(fail_wait_interval); } - ASSERT(res); + ASSERT(res); - /* hostname resolve succeeded */ + /* hostname resolve succeeded */ - /* - * Do not choose an IP Addresse by random or change the order * - * of IP addresses, doing so will break RFC 3484 address selection * - */ + /* + * Do not choose an IP Addresse by random or change the order * + * of IP addresses, doing so will break RFC 3484 address selection * + */ } - else + else { - /* IP address parse succeeded */ + /* IP address parse succeeded */ } - done: - if (signal_received && *signal_received) +done: + if (signal_received && *signal_received) { - int level = 0; - if (flags & GETADDR_FATAL_ON_SIGNAL) - level = M_FATAL; - else if (flags & GETADDR_WARN_ON_SIGNAL) - level = M_WARN; - msg (level, "RESOLVE: signal received during DNS resolution attempt"); + int level = 0; + if (flags & GETADDR_FATAL_ON_SIGNAL) + { + level = M_FATAL; + } + else if (flags & GETADDR_WARN_ON_SIGNAL) + { + level = M_WARN; + } + msg(level, "RESOLVE: signal received during DNS resolution attempt"); } - gc_free (&gc); - return status; + gc_free(&gc); + return status; } /* @@ -466,220 +536,260 @@ openvpn_getaddrinfo (unsigned int flags, * isn't very good about error checking. */ int -openvpn_inet_aton (const char *dotted_quad, struct in_addr *addr) +openvpn_inet_aton(const char *dotted_quad, struct in_addr *addr) { - unsigned int a, b, c, d; + unsigned int a, b, c, d; - CLEAR (*addr); - if (sscanf (dotted_quad, "%u.%u.%u.%u", &a, &b, &c, &d) == 4) + CLEAR(*addr); + if (sscanf(dotted_quad, "%u.%u.%u.%u", &a, &b, &c, &d) == 4) { - if (a < 256 && b < 256 && c < 256 && d < 256) - { - addr->s_addr = htonl (a<<24 | b<<16 | c<<8 | d); - return OIA_IP; /* good dotted quad */ - } + if (a < 256 && b < 256 && c < 256 && d < 256) + { + addr->s_addr = htonl(a<<24 | b<<16 | c<<8 | d); + return OIA_IP; /* good dotted quad */ + } + } + if (string_class(dotted_quad, CC_DIGIT|CC_DOT, 0)) + { + return OIA_ERROR; /* probably a badly formatted dotted quad */ + } + else + { + return OIA_HOSTNAME; /* probably a hostname */ } - if (string_class (dotted_quad, CC_DIGIT|CC_DOT, 0)) - return OIA_ERROR; /* probably a badly formatted dotted quad */ - else - return OIA_HOSTNAME; /* probably a hostname */ } bool -ip_addr_dotted_quad_safe (const char *dotted_quad) +ip_addr_dotted_quad_safe(const char *dotted_quad) { - /* verify non-NULL */ - if (!dotted_quad) - return false; + /* verify non-NULL */ + if (!dotted_quad) + { + return false; + } - /* verify length is within limits */ - if (strlen (dotted_quad) > 15) - return false; + /* verify length is within limits */ + if (strlen(dotted_quad) > 15) + { + return false; + } + + /* verify that all chars are either numeric or '.' and that no numeric + * substring is greater than 3 chars */ + { + int nnum = 0; + const char *p = dotted_quad; + int c; + + while ((c = *p++)) + { + if (c >= '0' && c <= '9') + { + ++nnum; + if (nnum > 3) + { + return false; + } + } + else if (c == '.') + { + nnum = 0; + } + else + { + return false; + } + } + } - /* verify that all chars are either numeric or '.' and that no numeric - substring is greater than 3 chars */ - { - int nnum = 0; - const char *p = dotted_quad; - int c; - - while ((c = *p++)) - { - if (c >= '0' && c <= '9') - { - ++nnum; - if (nnum > 3) - return false; - } - else if (c == '.') - { - nnum = 0; - } - else - return false; - } - } - - /* verify that string will convert to IP address */ - { - struct in_addr a; - return openvpn_inet_aton (dotted_quad, &a) == OIA_IP; - } + /* verify that string will convert to IP address */ + { + struct in_addr a; + return openvpn_inet_aton(dotted_quad, &a) == OIA_IP; + } } bool -ipv6_addr_safe (const char *ipv6_text_addr) +ipv6_addr_safe(const char *ipv6_text_addr) { - /* verify non-NULL */ - if (!ipv6_text_addr) - return false; + /* verify non-NULL */ + if (!ipv6_text_addr) + { + return false; + } - /* verify length is within limits */ - if (strlen (ipv6_text_addr) > INET6_ADDRSTRLEN ) - return false; + /* verify length is within limits */ + if (strlen(ipv6_text_addr) > INET6_ADDRSTRLEN) + { + return false; + } - /* verify that string will convert to IPv6 address */ - { - struct in6_addr a6; - return inet_pton( AF_INET6, ipv6_text_addr, &a6 ) == 1; - } + /* verify that string will convert to IPv6 address */ + { + struct in6_addr a6; + return inet_pton( AF_INET6, ipv6_text_addr, &a6 ) == 1; + } } static bool -dns_addr_safe (const char *addr) +dns_addr_safe(const char *addr) { - if (addr) + if (addr) { - const size_t len = strlen (addr); - return len > 0 && len <= 255 && string_class (addr, CC_ALNUM|CC_DASH|CC_DOT, 0); + const size_t len = strlen(addr); + return len > 0 && len <= 255 && string_class(addr, CC_ALNUM|CC_DASH|CC_DOT, 0); + } + else + { + return false; } - else - return false; } bool -ip_or_dns_addr_safe (const char *addr, const bool allow_fqdn) +ip_or_dns_addr_safe(const char *addr, const bool allow_fqdn) { - if (ip_addr_dotted_quad_safe (addr)) - return true; - else if (allow_fqdn) - return dns_addr_safe (addr); - else - return false; + if (ip_addr_dotted_quad_safe(addr)) + { + return true; + } + else if (allow_fqdn) + { + return dns_addr_safe(addr); + } + else + { + return false; + } } bool -mac_addr_safe (const char *mac_addr) +mac_addr_safe(const char *mac_addr) { - /* verify non-NULL */ - if (!mac_addr) - return false; + /* verify non-NULL */ + if (!mac_addr) + { + return false; + } - /* verify length is within limits */ - if (strlen (mac_addr) > 17) - return false; + /* verify length is within limits */ + if (strlen(mac_addr) > 17) + { + return false; + } - /* verify that all chars are either alphanumeric or ':' and that no - alphanumeric substring is greater than 2 chars */ - { - int nnum = 0; - const char *p = mac_addr; - int c; - - while ((c = *p++)) - { - if ( (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') ) - { - ++nnum; - if (nnum > 2) - return false; - } - else if (c == ':') - { - nnum = 0; - } - else - return false; - } - } - - /* error-checking is left to script invoked in lladdr.c */ - return true; + /* verify that all chars are either alphanumeric or ':' and that no + * alphanumeric substring is greater than 2 chars */ + { + int nnum = 0; + const char *p = mac_addr; + int c; + + while ((c = *p++)) + { + if ( (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') ) + { + ++nnum; + if (nnum > 2) + { + return false; + } + } + else if (c == ':') + { + nnum = 0; + } + else + { + return false; + } + } + } + + /* error-checking is left to script invoked in lladdr.c */ + return true; } static int -socket_get_sndbuf (int sd) +socket_get_sndbuf(int sd) { #if defined(HAVE_GETSOCKOPT) && defined(SOL_SOCKET) && defined(SO_SNDBUF) - int val; - socklen_t len; + int val; + socklen_t len; - len = sizeof (val); - if (getsockopt (sd, SOL_SOCKET, SO_SNDBUF, (void *) &val, &len) == 0 - && len == sizeof (val)) - return val; + len = sizeof(val); + if (getsockopt(sd, SOL_SOCKET, SO_SNDBUF, (void *) &val, &len) == 0 + && len == sizeof(val)) + { + return val; + } #endif - return 0; + return 0; } static void -socket_set_sndbuf (int sd, int size) +socket_set_sndbuf(int sd, int size) { #if defined(HAVE_SETSOCKOPT) && defined(SOL_SOCKET) && defined(SO_SNDBUF) - if (setsockopt (sd, SOL_SOCKET, SO_SNDBUF, (void *) &size, sizeof (size)) != 0) + if (setsockopt(sd, SOL_SOCKET, SO_SNDBUF, (void *) &size, sizeof(size)) != 0) { - msg (M_WARN, "NOTE: setsockopt SO_SNDBUF=%d failed", size); + msg(M_WARN, "NOTE: setsockopt SO_SNDBUF=%d failed", size); } #endif } static int -socket_get_rcvbuf (int sd) +socket_get_rcvbuf(int sd) { #if defined(HAVE_GETSOCKOPT) && defined(SOL_SOCKET) && defined(SO_RCVBUF) - int val; - socklen_t len; + int val; + socklen_t len; - len = sizeof (val); - if (getsockopt (sd, SOL_SOCKET, SO_RCVBUF, (void *) &val, &len) == 0 - && len == sizeof (val)) - return val; + len = sizeof(val); + if (getsockopt(sd, SOL_SOCKET, SO_RCVBUF, (void *) &val, &len) == 0 + && len == sizeof(val)) + { + return val; + } #endif - return 0; + return 0; } static bool -socket_set_rcvbuf (int sd, int size) +socket_set_rcvbuf(int sd, int size) { #if defined(HAVE_SETSOCKOPT) && defined(SOL_SOCKET) && defined(SO_RCVBUF) - if (setsockopt (sd, SOL_SOCKET, SO_RCVBUF, (void *) &size, sizeof (size)) != 0) + if (setsockopt(sd, SOL_SOCKET, SO_RCVBUF, (void *) &size, sizeof(size)) != 0) { - msg (M_WARN, "NOTE: setsockopt SO_RCVBUF=%d failed", size); - return false; + msg(M_WARN, "NOTE: setsockopt SO_RCVBUF=%d failed", size); + return false; } - return true; + return true; #endif } static void -socket_set_buffers (int fd, const struct socket_buffer_size *sbs) +socket_set_buffers(int fd, const struct socket_buffer_size *sbs) { - if (sbs) + if (sbs) { - const int sndbuf_old = socket_get_sndbuf (fd); - const int rcvbuf_old = socket_get_rcvbuf (fd); + const int sndbuf_old = socket_get_sndbuf(fd); + const int rcvbuf_old = socket_get_rcvbuf(fd); + + if (sbs->sndbuf) + { + socket_set_sndbuf(fd, sbs->sndbuf); + } - if (sbs->sndbuf) - socket_set_sndbuf (fd, sbs->sndbuf); + if (sbs->rcvbuf) + { + socket_set_rcvbuf(fd, sbs->rcvbuf); + } - if (sbs->rcvbuf) - socket_set_rcvbuf (fd, sbs->rcvbuf); - - msg (D_OSBUF, "Socket Buffers: R=[%d->%d] S=[%d->%d]", - rcvbuf_old, - socket_get_rcvbuf (fd), - sndbuf_old, - socket_get_sndbuf (fd)); + msg(D_OSBUF, "Socket Buffers: R=[%d->%d] S=[%d->%d]", + rcvbuf_old, + socket_get_rcvbuf(fd), + sndbuf_old, + socket_get_sndbuf(fd)); } } @@ -688,60 +798,70 @@ socket_set_buffers (int fd, const struct socket_buffer_size *sbs) */ static bool -socket_set_tcp_nodelay (int sd, int state) +socket_set_tcp_nodelay(int sd, int state) { #if defined(_WIN32) || (defined(HAVE_SETSOCKOPT) && defined(IPPROTO_TCP) && defined(TCP_NODELAY)) - if (setsockopt (sd, IPPROTO_TCP, TCP_NODELAY, (void *) &state, sizeof (state)) != 0) + if (setsockopt(sd, IPPROTO_TCP, TCP_NODELAY, (void *) &state, sizeof(state)) != 0) { - msg (M_WARN, "NOTE: setsockopt TCP_NODELAY=%d failed", state); - return false; + msg(M_WARN, "NOTE: setsockopt TCP_NODELAY=%d failed", state); + return false; } - else + else { - dmsg (D_OSBUF, "Socket flags: TCP_NODELAY=%d succeeded", state); - return true; + dmsg(D_OSBUF, "Socket flags: TCP_NODELAY=%d succeeded", state); + return true; } -#else - msg (M_WARN, "NOTE: setsockopt TCP_NODELAY=%d failed (No kernel support)", state); - return false; +#else /* if defined(_WIN32) || (defined(HAVE_SETSOCKOPT) && defined(IPPROTO_TCP) && defined(TCP_NODELAY)) */ + msg(M_WARN, "NOTE: setsockopt TCP_NODELAY=%d failed (No kernel support)", state); + return false; #endif } static inline void -socket_set_mark (int sd, int mark) +socket_set_mark(int sd, int mark) { #if defined(TARGET_LINUX) && HAVE_DECL_SO_MARK - if (mark && setsockopt (sd, SOL_SOCKET, SO_MARK, (void *) &mark, sizeof (mark)) != 0) - msg (M_WARN, "NOTE: setsockopt SO_MARK=%d failed", mark); + if (mark && setsockopt(sd, SOL_SOCKET, SO_MARK, (void *) &mark, sizeof(mark)) != 0) + { + msg(M_WARN, "NOTE: setsockopt SO_MARK=%d failed", mark); + } #endif } static bool -socket_set_flags (int sd, unsigned int sockflags) +socket_set_flags(int sd, unsigned int sockflags) { - if (sockflags & SF_TCP_NODELAY) - return socket_set_tcp_nodelay (sd, 1); - else - return true; + if (sockflags & SF_TCP_NODELAY) + { + return socket_set_tcp_nodelay(sd, 1); + } + else + { + return true; + } } bool -link_socket_update_flags (struct link_socket *ls, unsigned int sockflags) +link_socket_update_flags(struct link_socket *ls, unsigned int sockflags) { - if (ls && socket_defined (ls->sd)) - return socket_set_flags (ls->sd, ls->sockflags = sockflags); - else - return false; + if (ls && socket_defined(ls->sd)) + { + return socket_set_flags(ls->sd, ls->sockflags = sockflags); + } + else + { + return false; + } } void -link_socket_update_buffer_sizes (struct link_socket *ls, int rcvbuf, int sndbuf) +link_socket_update_buffer_sizes(struct link_socket *ls, int rcvbuf, int sndbuf) { - if (ls && socket_defined (ls->sd)) + if (ls && socket_defined(ls->sd)) { - ls->socket_buffer_sizes.sndbuf = sndbuf; - ls->socket_buffer_sizes.rcvbuf = rcvbuf; - socket_set_buffers (ls->sd, &ls->socket_buffer_sizes); + ls->socket_buffer_sizes.sndbuf = sndbuf; + ls->socket_buffer_sizes.rcvbuf = rcvbuf; + socket_set_buffers(ls->sd, &ls->socket_buffer_sizes); } } @@ -751,149 +871,166 @@ link_socket_update_buffer_sizes (struct link_socket *ls, int rcvbuf, int sndbuf) */ socket_descriptor_t -create_socket_tcp (struct addrinfo* addrinfo) +create_socket_tcp(struct addrinfo *addrinfo) { - socket_descriptor_t sd; + socket_descriptor_t sd; - ASSERT (addrinfo); - ASSERT (addrinfo->ai_socktype == SOCK_STREAM); + ASSERT(addrinfo); + ASSERT(addrinfo->ai_socktype == SOCK_STREAM); - if ((sd = socket (addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol)) < 0) - msg (M_ERR, "Cannot create TCP socket"); + if ((sd = socket(addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol)) < 0) + { + msg(M_ERR, "Cannot create TCP socket"); + } #ifndef _WIN32 /* using SO_REUSEADDR on Windows will cause bind to succeed on port conflicts! */ - /* set SO_REUSEADDR on socket */ - { - int on = 1; - if (setsockopt (sd, SOL_SOCKET, SO_REUSEADDR, - (void *) &on, sizeof (on)) < 0) - msg (M_ERR, "TCP: Cannot setsockopt SO_REUSEADDR on TCP socket"); - } + /* set SO_REUSEADDR on socket */ + { + int on = 1; + if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, + (void *) &on, sizeof(on)) < 0) + { + msg(M_ERR, "TCP: Cannot setsockopt SO_REUSEADDR on TCP socket"); + } + } #endif - /* set socket file descriptor to not pass across execs, so that - scripts don't have access to it */ - set_cloexec (sd); + /* set socket file descriptor to not pass across execs, so that + * scripts don't have access to it */ + set_cloexec(sd); - return sd; + return sd; } static socket_descriptor_t -create_socket_udp (struct addrinfo* addrinfo, const unsigned int flags) +create_socket_udp(struct addrinfo *addrinfo, const unsigned int flags) { - socket_descriptor_t sd; + socket_descriptor_t sd; - ASSERT (addrinfo); - ASSERT (addrinfo->ai_socktype == SOCK_DGRAM); + ASSERT(addrinfo); + ASSERT(addrinfo->ai_socktype == SOCK_DGRAM); - if ((sd = socket (addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol)) < 0) - msg (M_ERR, "UDP: Cannot create UDP/UDP6 socket"); + if ((sd = socket(addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol)) < 0) + { + msg(M_ERR, "UDP: Cannot create UDP/UDP6 socket"); + } #if ENABLE_IP_PKTINFO - else if (flags & SF_USE_IP_PKTINFO) + else if (flags & SF_USE_IP_PKTINFO) { - int pad = 1; - if(addrinfo->ai_family == AF_INET) + int pad = 1; + if (addrinfo->ai_family == AF_INET) { #if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) - if (setsockopt (sd, SOL_IP, IP_PKTINFO, - (void*)&pad, sizeof(pad)) < 0) - msg(M_ERR, "UDP: failed setsockopt for IP_PKTINFO"); + if (setsockopt(sd, SOL_IP, IP_PKTINFO, + (void *)&pad, sizeof(pad)) < 0) + { + msg(M_ERR, "UDP: failed setsockopt for IP_PKTINFO"); + } #elif defined(IP_RECVDSTADDR) - if (setsockopt (sd, IPPROTO_IP, IP_RECVDSTADDR, - (void*)&pad, sizeof(pad)) < 0) - msg(M_ERR, "UDP: failed setsockopt for IP_RECVDSTADDR"); -#else + if (setsockopt(sd, IPPROTO_IP, IP_RECVDSTADDR, + (void *)&pad, sizeof(pad)) < 0) + { + msg(M_ERR, "UDP: failed setsockopt for IP_RECVDSTADDR"); + } +#else /* if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) */ #error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h) #endif } - else if (addrinfo->ai_family == AF_INET6 ) + else if (addrinfo->ai_family == AF_INET6) { #ifndef IPV6_RECVPKTINFO /* Some older Darwin platforms require this */ - if (setsockopt (sd, IPPROTO_IPV6, IPV6_PKTINFO, - (void*)&pad, sizeof(pad)) < 0) + if (setsockopt(sd, IPPROTO_IPV6, IPV6_PKTINFO, + (void *)&pad, sizeof(pad)) < 0) #else - if (setsockopt (sd, IPPROTO_IPV6, IPV6_RECVPKTINFO, - (void*)&pad, sizeof(pad)) < 0) + if (setsockopt(sd, IPPROTO_IPV6, IPV6_RECVPKTINFO, + (void *)&pad, sizeof(pad)) < 0) #endif - msg(M_ERR, "UDP: failed setsockopt for IPV6_RECVPKTINFO"); + { msg(M_ERR, "UDP: failed setsockopt for IPV6_RECVPKTINFO");} } } -#endif +#endif /* if ENABLE_IP_PKTINFO */ - /* set socket file descriptor to not pass across execs, so that - scripts don't have access to it */ - set_cloexec (sd); + /* set socket file descriptor to not pass across execs, so that + * scripts don't have access to it */ + set_cloexec(sd); - return sd; + return sd; } -static void bind_local (struct link_socket *sock, const sa_family_t ai_family) +static void +bind_local(struct link_socket *sock, const sa_family_t ai_family) { /* bind to local address/port */ if (sock->bind_local) - { + { if (sock->socks_proxy && sock->info.proto == PROTO_UDP) - socket_bind (sock->ctrl_sd, sock->info.lsa->bind_local, - ai_family, "SOCKS", false); + { + socket_bind(sock->ctrl_sd, sock->info.lsa->bind_local, + ai_family, "SOCKS", false); + } else - socket_bind (sock->sd, sock->info.lsa->bind_local, - ai_family, - "TCP/UDP", sock->info.bind_ipv6_only); - } + { + socket_bind(sock->sd, sock->info.lsa->bind_local, + ai_family, + "TCP/UDP", sock->info.bind_ipv6_only); + } + } } static void -create_socket (struct link_socket* sock, struct addrinfo* addr) +create_socket(struct link_socket *sock, struct addrinfo *addr) { - if (addr->ai_protocol == IPPROTO_UDP || addr->ai_socktype == SOCK_DGRAM) + if (addr->ai_protocol == IPPROTO_UDP || addr->ai_socktype == SOCK_DGRAM) { - sock->sd = create_socket_udp (addr, sock->sockflags); - sock->sockflags |= SF_GETADDRINFO_DGRAM; + sock->sd = create_socket_udp(addr, sock->sockflags); + sock->sockflags |= SF_GETADDRINFO_DGRAM; - /* Assume that control socket and data socket to the socks proxy - * are using the same IP family */ - if (sock->socks_proxy) - { - /* Construct a temporary addrinfo to create the socket, - * currently resolve two remote addresses is not supported, - * TODO: Rewrite the whole resolve_remote */ - struct addrinfo addrinfo_tmp = *addr; - addrinfo_tmp.ai_socktype = SOCK_STREAM; - addrinfo_tmp.ai_protocol = IPPROTO_TCP; - sock->ctrl_sd = create_socket_tcp (&addrinfo_tmp); - } + /* Assume that control socket and data socket to the socks proxy + * are using the same IP family */ + if (sock->socks_proxy) + { + /* Construct a temporary addrinfo to create the socket, + * currently resolve two remote addresses is not supported, + * TODO: Rewrite the whole resolve_remote */ + struct addrinfo addrinfo_tmp = *addr; + addrinfo_tmp.ai_socktype = SOCK_STREAM; + addrinfo_tmp.ai_protocol = IPPROTO_TCP; + sock->ctrl_sd = create_socket_tcp(&addrinfo_tmp); + } } - else if (addr->ai_protocol == IPPROTO_TCP || addr->ai_socktype == SOCK_STREAM) + else if (addr->ai_protocol == IPPROTO_TCP || addr->ai_socktype == SOCK_STREAM) { - sock->sd = create_socket_tcp (addr); + sock->sd = create_socket_tcp(addr); } - else + else { - ASSERT (0); + ASSERT(0); } /* set socket buffers based on --sndbuf and --rcvbuf options */ - socket_set_buffers (sock->sd, &sock->socket_buffer_sizes); + socket_set_buffers(sock->sd, &sock->socket_buffer_sizes); /* set socket to --mark packets with given value */ - socket_set_mark (sock->sd, sock->mark); + socket_set_mark(sock->sd, sock->mark); - bind_local (sock, addr->ai_family); + bind_local(sock, addr->ai_family); } #ifdef TARGET_ANDROID -static void protect_fd_nonlocal (int fd, const struct sockaddr* addr) +static void +protect_fd_nonlocal(int fd, const struct sockaddr *addr) { - /* pass socket FD to management interface to pass on to VPNService API - * as "protected socket" (exempt from being routed into tunnel) - */ - if (addr_local (addr)) { - msg(D_SOCKET_DEBUG, "Address is local, not protecting socket fd %d", fd); - return; - } + /* pass socket FD to management interface to pass on to VPNService API + * as "protected socket" (exempt from being routed into tunnel) + */ + if (addr_local(addr)) + { + msg(D_SOCKET_DEBUG, "Address is local, not protecting socket fd %d", fd); + return; + } - msg(D_SOCKET_DEBUG, "Protecting socket fd %d", fd); - management->connection.fdtosend = fd; - management_android_control (management, "PROTECTFD", __func__); + msg(D_SOCKET_DEBUG, "Protecting socket fd %d", fd); + management->connection.fdtosend = fd; + management_android_control(management, "PROTECTFD", __func__); } #endif @@ -901,440 +1038,488 @@ static void protect_fd_nonlocal (int fd, const struct sockaddr* addr) * Functions used for establishing a TCP stream connection. */ static void -socket_do_listen (socket_descriptor_t sd, - const struct addrinfo *local, - bool do_listen, - bool do_set_nonblock) -{ - struct gc_arena gc = gc_new (); - if (do_listen) - { - ASSERT(local); - msg (M_INFO, "Listening for incoming TCP connection on %s", - print_sockaddr (local->ai_addr, &gc)); - if (listen (sd, 1)) - msg (M_ERR, "TCP: listen() failed"); +socket_do_listen(socket_descriptor_t sd, + const struct addrinfo *local, + bool do_listen, + bool do_set_nonblock) +{ + struct gc_arena gc = gc_new(); + if (do_listen) + { + ASSERT(local); + msg(M_INFO, "Listening for incoming TCP connection on %s", + print_sockaddr(local->ai_addr, &gc)); + if (listen(sd, 1)) + { + msg(M_ERR, "TCP: listen() failed"); + } } - /* set socket to non-blocking mode */ - if (do_set_nonblock) - set_nonblock (sd); + /* set socket to non-blocking mode */ + if (do_set_nonblock) + { + set_nonblock(sd); + } - gc_free (&gc); + gc_free(&gc); } socket_descriptor_t -socket_do_accept (socket_descriptor_t sd, - struct link_socket_actual *act, - const bool nowait) +socket_do_accept(socket_descriptor_t sd, + struct link_socket_actual *act, + const bool nowait) { - /* af_addr_size WILL return 0 in this case if AFs other than AF_INET - * are compiled because act is empty here. - * could use getsockname() to support later remote_len check - */ - socklen_t remote_len_af = af_addr_size(act->dest.addr.sa.sa_family); - socklen_t remote_len = sizeof(act->dest.addr); - socket_descriptor_t new_sd = SOCKET_UNDEFINED; + /* af_addr_size WILL return 0 in this case if AFs other than AF_INET + * are compiled because act is empty here. + * could use getsockname() to support later remote_len check + */ + socklen_t remote_len_af = af_addr_size(act->dest.addr.sa.sa_family); + socklen_t remote_len = sizeof(act->dest.addr); + socket_descriptor_t new_sd = SOCKET_UNDEFINED; - CLEAR (*act); + CLEAR(*act); #ifdef HAVE_GETPEERNAME - if (nowait) + if (nowait) { - new_sd = getpeername (sd, &act->dest.addr.sa, &remote_len); + new_sd = getpeername(sd, &act->dest.addr.sa, &remote_len); - if (!socket_defined (new_sd)) - msg (D_LINK_ERRORS | M_ERRNO, "TCP: getpeername() failed"); - else - new_sd = sd; - } -#else - if (nowait) - msg (M_WARN, "TCP: this OS does not provide the getpeername() function"); + if (!socket_defined(new_sd)) + { + msg(D_LINK_ERRORS | M_ERRNO, "TCP: getpeername() failed"); + } + else + { + new_sd = sd; + } + } +#else /* ifdef HAVE_GETPEERNAME */ + if (nowait) + { + msg(M_WARN, "TCP: this OS does not provide the getpeername() function"); + } #endif - else + else { - new_sd = accept (sd, &act->dest.addr.sa, &remote_len); + new_sd = accept(sd, &act->dest.addr.sa, &remote_len); } #if 0 /* For debugging only, test the effect of accept() failures */ - { - static int foo = 0; - ++foo; - if (foo & 1) - new_sd = -1; - } + { + static int foo = 0; + ++foo; + if (foo & 1) + { + new_sd = -1; + } + } #endif - if (!socket_defined (new_sd)) + if (!socket_defined(new_sd)) { - msg (D_LINK_ERRORS | M_ERRNO, "TCP: accept(%d) failed", sd); + msg(D_LINK_ERRORS | M_ERRNO, "TCP: accept(%d) failed", sd); } - /* only valid if we have remote_len_af!=0 */ - else if (remote_len_af && remote_len != remote_len_af) + /* only valid if we have remote_len_af!=0 */ + else if (remote_len_af && remote_len != remote_len_af) { - msg (D_LINK_ERRORS, "TCP: Received strange incoming connection with unknown address length=%d", remote_len); - openvpn_close_socket (new_sd); - new_sd = SOCKET_UNDEFINED; + msg(D_LINK_ERRORS, "TCP: Received strange incoming connection with unknown address length=%d", remote_len); + openvpn_close_socket(new_sd); + new_sd = SOCKET_UNDEFINED; } - else + else { - /* set socket file descriptor to not pass across execs, so that - scripts don't have access to it */ - set_cloexec (sd); + /* set socket file descriptor to not pass across execs, so that + * scripts don't have access to it */ + set_cloexec(sd); } - return new_sd; + return new_sd; } static void -tcp_connection_established (const struct link_socket_actual *act) +tcp_connection_established(const struct link_socket_actual *act) { - struct gc_arena gc = gc_new (); - msg (M_INFO, "TCP connection established with %s", - print_link_socket_actual (act, &gc)); - gc_free (&gc); + struct gc_arena gc = gc_new(); + msg(M_INFO, "TCP connection established with %s", + print_link_socket_actual(act, &gc)); + gc_free(&gc); } static int -socket_listen_accept (socket_descriptor_t sd, - struct link_socket_actual *act, - const char *remote_dynamic, - const struct addrinfo *local, - bool do_listen, - bool nowait, - volatile int *signal_received) -{ - struct gc_arena gc = gc_new (); - /* struct openvpn_sockaddr *remote = &act->dest; */ - struct openvpn_sockaddr remote_verify = act->dest; - int new_sd = SOCKET_UNDEFINED; - - CLEAR (*act); - socket_do_listen (sd, local, do_listen, true); - - while (true) - { - int status; - fd_set reads; - struct timeval tv; - - FD_ZERO (&reads); - openvpn_fd_set (sd, &reads); - tv.tv_sec = 0; - tv.tv_usec = 0; - - status = select (sd + 1, &reads, NULL, NULL, &tv); - - get_signal (signal_received); - if (*signal_received) - { - gc_free (&gc); - return sd; - } - - if (status < 0) - msg (D_LINK_ERRORS | M_ERRNO, "TCP: select() failed"); - - if (status <= 0) - { - openvpn_sleep (1); - continue; - } - - new_sd = socket_do_accept (sd, act, nowait); - - if (socket_defined (new_sd)) - { - struct addrinfo* ai = NULL; - if(remote_dynamic) - openvpn_getaddrinfo(0, remote_dynamic, NULL, 1, NULL, +socket_listen_accept(socket_descriptor_t sd, + struct link_socket_actual *act, + const char *remote_dynamic, + const struct addrinfo *local, + bool do_listen, + bool nowait, + volatile int *signal_received) +{ + struct gc_arena gc = gc_new(); + /* struct openvpn_sockaddr *remote = &act->dest; */ + struct openvpn_sockaddr remote_verify = act->dest; + int new_sd = SOCKET_UNDEFINED; + + CLEAR(*act); + socket_do_listen(sd, local, do_listen, true); + + while (true) + { + int status; + fd_set reads; + struct timeval tv; + + FD_ZERO(&reads); + openvpn_fd_set(sd, &reads); + tv.tv_sec = 0; + tv.tv_usec = 0; + + status = select(sd + 1, &reads, NULL, NULL, &tv); + + get_signal(signal_received); + if (*signal_received) + { + gc_free(&gc); + return sd; + } + + if (status < 0) + { + msg(D_LINK_ERRORS | M_ERRNO, "TCP: select() failed"); + } + + if (status <= 0) + { + openvpn_sleep(1); + continue; + } + + new_sd = socket_do_accept(sd, act, nowait); + + if (socket_defined(new_sd)) + { + struct addrinfo *ai = NULL; + if (remote_dynamic) + { + openvpn_getaddrinfo(0, remote_dynamic, NULL, 1, NULL, remote_verify.addr.sa.sa_family, &ai); + } - if(ai && !addrlist_match(&remote_verify, ai)) + if (ai && !addrlist_match(&remote_verify, ai)) { - msg (M_WARN, - "TCP NOTE: Rejected connection attempt from %s due to --remote setting", - print_link_socket_actual (act, &gc)); - if (openvpn_close_socket (new_sd)) - msg (M_ERR, "TCP: close socket failed (new_sd)"); - freeaddrinfo(ai); + msg(M_WARN, + "TCP NOTE: Rejected connection attempt from %s due to --remote setting", + print_link_socket_actual(act, &gc)); + if (openvpn_close_socket(new_sd)) + { + msg(M_ERR, "TCP: close socket failed (new_sd)"); + } + freeaddrinfo(ai); } - else + else { - if(ai) - freeaddrinfo(ai); - break; + if (ai) + { + freeaddrinfo(ai); + } + break; } - } - openvpn_sleep (1); + } + openvpn_sleep(1); } - if (!nowait && openvpn_close_socket (sd)) - msg (M_ERR, "TCP: close socket failed (sd)"); + if (!nowait && openvpn_close_socket(sd)) + { + msg(M_ERR, "TCP: close socket failed (sd)"); + } - tcp_connection_established (act); + tcp_connection_established(act); - gc_free (&gc); - return new_sd; + gc_free(&gc); + return new_sd; } /* older mingw versions and WinXP do not have this define, * but Vista and up support the functionality - just define it here */ #ifdef _WIN32 -# ifndef IPV6_V6ONLY -# define IPV6_V6ONLY 27 -# endif +#ifndef IPV6_V6ONLY +#define IPV6_V6ONLY 27 +#endif #endif void -socket_bind (socket_descriptor_t sd, - struct addrinfo *local, - int ai_family, - const char *prefix, - bool ipv6only) +socket_bind(socket_descriptor_t sd, + struct addrinfo *local, + int ai_family, + const char *prefix, + bool ipv6only) { - struct gc_arena gc = gc_new (); + struct gc_arena gc = gc_new(); - /* FIXME (schwabe) - * getaddrinfo for the bind address might return multiple AF_INET/AF_INET6 - * entries for the requested protocol. - * For example if an address has multiple A records - * What is the correct way to deal with it? - */ + /* FIXME (schwabe) + * getaddrinfo for the bind address might return multiple AF_INET/AF_INET6 + * entries for the requested protocol. + * For example if an address has multiple A records + * What is the correct way to deal with it? + */ - struct addrinfo* cur; + struct addrinfo *cur; - ASSERT(local); + ASSERT(local); - /* find the first addrinfo with correct ai_family */ - for (cur = local; cur; cur=cur->ai_next) + /* find the first addrinfo with correct ai_family */ + for (cur = local; cur; cur = cur->ai_next) + { + if (cur->ai_family == ai_family) + { + break; + } + } + if (!cur) { - if(cur->ai_family == ai_family) - break; + msg(M_FATAL, "%s: Socket bind failed: Addr to bind has no %s record", + prefix, addr_family_name(ai_family)); } - if (!cur) - msg (M_FATAL, "%s: Socket bind failed: Addr to bind has no %s record", - prefix, addr_family_name(ai_family)); - if (ai_family == AF_INET6) + if (ai_family == AF_INET6) { - int v6only = ipv6only ? 1: 0; /* setsockopt must have an "int" */ + int v6only = ipv6only ? 1 : 0; /* setsockopt must have an "int" */ - msg (M_INFO, "setsockopt(IPV6_V6ONLY=%d)", v6only); - if (setsockopt (sd, IPPROTO_IPV6, IPV6_V6ONLY, (void *) &v6only, sizeof(v6only))) - { - msg (M_NONFATAL|M_ERRNO, "Setting IPV6_V6ONLY=%d failed", v6only); - } + msg(M_INFO, "setsockopt(IPV6_V6ONLY=%d)", v6only); + if (setsockopt(sd, IPPROTO_IPV6, IPV6_V6ONLY, (void *) &v6only, sizeof(v6only))) + { + msg(M_NONFATAL|M_ERRNO, "Setting IPV6_V6ONLY=%d failed", v6only); + } } - if (bind (sd, cur->ai_addr, cur->ai_addrlen)) + if (bind(sd, cur->ai_addr, cur->ai_addrlen)) { - const int errnum = openvpn_errno (); - msg (M_FATAL, "%s: Socket bind failed on local address %s: %s", - prefix, - print_sockaddr_ex (local->ai_addr, ":", PS_SHOW_PORT, &gc), - strerror_ts (errnum, &gc)); + const int errnum = openvpn_errno(); + msg(M_FATAL, "%s: Socket bind failed on local address %s: %s", + prefix, + print_sockaddr_ex(local->ai_addr, ":", PS_SHOW_PORT, &gc), + strerror_ts(errnum, &gc)); } - gc_free (&gc); + gc_free(&gc); } int -openvpn_connect (socket_descriptor_t sd, - const struct sockaddr *remote, - int connect_timeout, - volatile int *signal_received) +openvpn_connect(socket_descriptor_t sd, + const struct sockaddr *remote, + int connect_timeout, + volatile int *signal_received) { - int status = 0; + int status = 0; #ifdef TARGET_ANDROID - protect_fd_nonlocal(sd, remote); + protect_fd_nonlocal(sd, remote); #endif #ifdef CONNECT_NONBLOCK - set_nonblock (sd); - status = connect (sd, remote, af_addr_size(remote->sa_family)); - if (status) - status = openvpn_errno (); - if ( + set_nonblock(sd); + status = connect(sd, remote, af_addr_size(remote->sa_family)); + if (status) + { + status = openvpn_errno(); + } + if ( #ifdef _WIN32 - status == WSAEWOULDBLOCK + status == WSAEWOULDBLOCK #else - status == EINPROGRESS + status == EINPROGRESS #endif - ) + ) { - while (true) - { + while (true) + { #if POLL - struct pollfd fds[1]; - fds[0].fd = sd; - fds[0].events = POLLOUT; - status = poll(fds, 1, 0); + struct pollfd fds[1]; + fds[0].fd = sd; + fds[0].events = POLLOUT; + status = poll(fds, 1, 0); #else - fd_set writes; - struct timeval tv; + fd_set writes; + struct timeval tv; - FD_ZERO (&writes); - openvpn_fd_set (sd, &writes); - tv.tv_sec = 0; - tv.tv_usec = 0; + FD_ZERO(&writes); + openvpn_fd_set(sd, &writes); + tv.tv_sec = 0; + tv.tv_usec = 0; - status = select (sd + 1, NULL, &writes, NULL, &tv); + status = select(sd + 1, NULL, &writes, NULL, &tv); #endif - if (signal_received) - { - get_signal (signal_received); - if (*signal_received) - { - status = 0; - break; - } - } - if (status < 0) - { - status = openvpn_errno (); - break; - } - if (status <= 0) - { - if (--connect_timeout < 0) - { + if (signal_received) + { + get_signal(signal_received); + if (*signal_received) + { + status = 0; + break; + } + } + if (status < 0) + { + status = openvpn_errno(); + break; + } + if (status <= 0) + { + if (--connect_timeout < 0) + { #ifdef _WIN32 - status = WSAETIMEDOUT; + status = WSAETIMEDOUT; #else - status = ETIMEDOUT; + status = ETIMEDOUT; #endif - break; - } - openvpn_sleep (1); - continue; - } - - /* got it */ - { - int val = 0; - socklen_t len; - - len = sizeof (val); - if (getsockopt (sd, SOL_SOCKET, SO_ERROR, (void *) &val, &len) == 0 - && len == sizeof (val)) - status = val; - else - status = openvpn_errno (); - break; - } - } + break; + } + openvpn_sleep(1); + continue; + } + + /* got it */ + { + int val = 0; + socklen_t len; + + len = sizeof(val); + if (getsockopt(sd, SOL_SOCKET, SO_ERROR, (void *) &val, &len) == 0 + && len == sizeof(val)) + { + status = val; + } + else + { + status = openvpn_errno(); + } + break; + } + } } -#else - status = connect (sd, remote, af_addr_size(remote->sa_family)); - if (status) - status = openvpn_errno (); -#endif +#else /* ifdef CONNECT_NONBLOCK */ + status = connect(sd, remote, af_addr_size(remote->sa_family)); + if (status) + { + status = openvpn_errno(); + } +#endif /* ifdef CONNECT_NONBLOCK */ - return status; + return status; } -void set_actual_address (struct link_socket_actual* actual, struct addrinfo* ai) +void +set_actual_address(struct link_socket_actual *actual, struct addrinfo *ai) { - CLEAR (*actual); - ASSERT (ai); + CLEAR(*actual); + ASSERT(ai); if (ai->ai_family == AF_INET) + { actual->dest.addr.in4 = - *((struct sockaddr_in*) ai->ai_addr); + *((struct sockaddr_in *) ai->ai_addr); + } else if (ai->ai_family == AF_INET6) + { actual->dest.addr.in6 = - *((struct sockaddr_in6*) ai->ai_addr); + *((struct sockaddr_in6 *) ai->ai_addr); + } else + { ASSERT(0); + } } void -socket_connect (socket_descriptor_t* sd, - const struct sockaddr* dest, - const int connect_timeout, - struct signal_info* sig_info) +socket_connect(socket_descriptor_t *sd, + const struct sockaddr *dest, + const int connect_timeout, + struct signal_info *sig_info) { - struct gc_arena gc = gc_new (); - int status; + struct gc_arena gc = gc_new(); + int status; #ifdef CONNECT_NONBLOCK - msg (M_INFO, "Attempting to establish TCP connection with %s [nonblock]", - print_sockaddr (dest, &gc)); + msg(M_INFO, "Attempting to establish TCP connection with %s [nonblock]", + print_sockaddr(dest, &gc)); #else - msg (M_INFO, "Attempting to establish TCP connection with %s", - print_sockaddr (dest, &gc)); + msg(M_INFO, "Attempting to establish TCP connection with %s", + print_sockaddr(dest, &gc)); #endif #ifdef ENABLE_MANAGEMENT - if (management) - management_set_state (management, - OPENVPN_STATE_TCP_CONNECT, - NULL, - NULL, - NULL, - NULL, - NULL); + if (management) + { + management_set_state(management, + OPENVPN_STATE_TCP_CONNECT, + NULL, + NULL, + NULL, + NULL, + NULL); + } #endif - /* Set the actual address */ - status = openvpn_connect (*sd, dest, connect_timeout, &sig_info->signal_received); + /* Set the actual address */ + status = openvpn_connect(*sd, dest, connect_timeout, &sig_info->signal_received); - get_signal (&sig_info->signal_received); - if (sig_info->signal_received) - goto done; + get_signal(&sig_info->signal_received); + if (sig_info->signal_received) + { + goto done; + } - if (status) { + if (status) + { - msg (D_LINK_ERRORS, - "TCP: connect to %s failed: %s", - print_sockaddr (dest, &gc), - strerror_ts (status, &gc)); + msg(D_LINK_ERRORS, + "TCP: connect to %s failed: %s", + print_sockaddr(dest, &gc), + strerror_ts(status, &gc)); - openvpn_close_socket (*sd); - *sd = SOCKET_UNDEFINED; - sig_info->signal_received = SIGUSR1; - sig_info->source = SIG_SOURCE_CONNECTION_FAILED; - } else { - msg (M_INFO, "TCP connection established with %s", - print_sockaddr (dest, &gc)); - } + openvpn_close_socket(*sd); + *sd = SOCKET_UNDEFINED; + sig_info->signal_received = SIGUSR1; + sig_info->source = SIG_SOURCE_CONNECTION_FAILED; + } + else + { + msg(M_INFO, "TCP connection established with %s", + print_sockaddr(dest, &gc)); + } - done: - gc_free (&gc); +done: + gc_free(&gc); } /* For stream protocols, allocate a buffer to build up packet. - Called after frame has been finalized. */ + * Called after frame has been finalized. */ static void -socket_frame_init (const struct frame *frame, struct link_socket *sock) +socket_frame_init(const struct frame *frame, struct link_socket *sock) { #ifdef _WIN32 - overlapped_io_init (&sock->reads, frame, FALSE, false); - overlapped_io_init (&sock->writes, frame, TRUE, false); - sock->rw_handle.read = sock->reads.overlapped.hEvent; - sock->rw_handle.write = sock->writes.overlapped.hEvent; + overlapped_io_init(&sock->reads, frame, FALSE, false); + overlapped_io_init(&sock->writes, frame, TRUE, false); + sock->rw_handle.read = sock->reads.overlapped.hEvent; + sock->rw_handle.write = sock->writes.overlapped.hEvent; #endif - if (link_socket_connection_oriented (sock)) + if (link_socket_connection_oriented(sock)) { #ifdef _WIN32 - stream_buf_init (&sock->stream_buf, - &sock->reads.buf_init, - sock->sockflags, - sock->info.proto); + stream_buf_init(&sock->stream_buf, + &sock->reads.buf_init, + sock->sockflags, + sock->info.proto); #else - alloc_buf_sock_tun (&sock->stream_buf_data, - frame, - false, - FRAME_HEADROOM_MARKER_READ_STREAM); - - stream_buf_init (&sock->stream_buf, - &sock->stream_buf_data, - sock->sockflags, - sock->info.proto); + alloc_buf_sock_tun(&sock->stream_buf_data, + frame, + false, + FRAME_HEADROOM_MARKER_READ_STREAM); + + stream_buf_init(&sock->stream_buf, + &sock->stream_buf_data, + sock->sockflags, + sock->info.proto); #endif } } @@ -1344,792 +1529,864 @@ socket_frame_init (const struct frame *frame, struct link_socket *sock) * to us by the OS. */ void -frame_adjust_path_mtu (struct frame *frame, int pmtu, int proto) +frame_adjust_path_mtu(struct frame *frame, int pmtu, int proto) { - frame_set_mtu_dynamic (frame, pmtu - datagram_overhead (proto), SET_MTU_UPPER_BOUND); + frame_set_mtu_dynamic(frame, pmtu - datagram_overhead(proto), SET_MTU_UPPER_BOUND); } static void -resolve_bind_local (struct link_socket *sock, const sa_family_t af) +resolve_bind_local(struct link_socket *sock, const sa_family_t af) { - struct gc_arena gc = gc_new (); + struct gc_arena gc = gc_new(); - /* resolve local address if undefined */ - if (!sock->info.lsa->bind_local) + /* resolve local address if undefined */ + if (!sock->info.lsa->bind_local) { - int flags = GETADDR_RESOLVE | GETADDR_WARN_ON_SIGNAL | - GETADDR_FATAL | GETADDR_PASSIVE; - int status; + int flags = GETADDR_RESOLVE | GETADDR_WARN_ON_SIGNAL + |GETADDR_FATAL | GETADDR_PASSIVE; + int status; - if(proto_is_dgram(sock->info.proto)) - flags |= GETADDR_DATAGRAM; + if (proto_is_dgram(sock->info.proto)) + { + flags |= GETADDR_DATAGRAM; + } - /* will return AF_{INET|INET6}from local_host */ - status = get_cached_dns_entry (sock->dns_cache, - sock->local_host, - sock->local_port, - af, - flags, - &sock->info.lsa->bind_local); + /* will return AF_{INET|INET6}from local_host */ + status = get_cached_dns_entry(sock->dns_cache, + sock->local_host, + sock->local_port, + af, + flags, + &sock->info.lsa->bind_local); - if (status) - status = openvpn_getaddrinfo(flags, sock->local_host, sock->local_port, 0, - NULL, af, &sock->info.lsa->bind_local); + if (status) + { + status = openvpn_getaddrinfo(flags, sock->local_host, sock->local_port, 0, + NULL, af, &sock->info.lsa->bind_local); + } - if(status !=0) { - msg (M_FATAL, "getaddrinfo() failed for local \"%s:%s\": %s", - sock->local_host, sock->local_port, - gai_strerror(status)); - } + if (status !=0) + { + msg(M_FATAL, "getaddrinfo() failed for local \"%s:%s\": %s", + sock->local_host, sock->local_port, + gai_strerror(status)); + } } - gc_free (&gc); + gc_free(&gc); } static void -resolve_remote (struct link_socket *sock, - int phase, - const char **remote_dynamic, - volatile int *signal_received) -{ - struct gc_arena gc = gc_new (); - - /* resolve remote address if undefined */ - if (!sock->info.lsa->remote_list) - { - if (sock->remote_host) - { - unsigned int flags = sf2gaf(GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE, sock->sockflags); - int retry = 0; - int status = -1; - struct addrinfo* ai; - if (proto_is_dgram(sock->info.proto)) - flags |= GETADDR_DATAGRAM; - - if (sock->resolve_retry_seconds == RESOLV_RETRY_INFINITE) - { - if (phase == 2) - flags |= (GETADDR_TRY_ONCE | GETADDR_FATAL); - retry = 0; - } - else if (phase == 1) - { - if (sock->resolve_retry_seconds) - { - retry = 0; - } - else - { - flags |= (GETADDR_FATAL | GETADDR_MENTION_RESOLVE_RETRY); - retry = 0; - } - } - else if (phase == 2) - { - if (sock->resolve_retry_seconds) - { - flags |= GETADDR_FATAL; - retry = sock->resolve_retry_seconds; - } - else - { - ASSERT (0); - } - } - else - { - ASSERT (0); - } - - - status = get_cached_dns_entry (sock->dns_cache, - sock->remote_host, - sock->remote_port, - sock->info.af, - flags, &ai); - if (status) - status = openvpn_getaddrinfo (flags, sock->remote_host, sock->remote_port, - retry, signal_received, sock->info.af, &ai); - - if(status == 0) { - sock->info.lsa->remote_list = ai; - sock->info.lsa->current_remote = ai; - - dmsg (D_SOCKET_DEBUG, "RESOLVE_REMOTE flags=0x%04x phase=%d rrs=%d sig=%d status=%d", - flags, - phase, - retry, - signal_received ? *signal_received : -1, - status); - } - if (signal_received) - { - if (*signal_received) - goto done; - } - if (status!=0) - { - if (signal_received) - *signal_received = SIGUSR1; - goto done; - } - } - } - - /* should we re-use previous active remote address? */ - if (link_socket_actual_defined (&sock->info.lsa->actual)) - { - msg (M_INFO, "TCP/UDP: Preserving recently used remote address: %s", - print_link_socket_actual (&sock->info.lsa->actual, &gc)); - if (remote_dynamic) - *remote_dynamic = NULL; - } - else - { - CLEAR (sock->info.lsa->actual); - if(sock->info.lsa->current_remote) - { - set_actual_address (&sock->info.lsa->actual, - sock->info.lsa->current_remote); - } - } - - done: - gc_free (&gc); +resolve_remote(struct link_socket *sock, + int phase, + const char **remote_dynamic, + volatile int *signal_received) +{ + struct gc_arena gc = gc_new(); + + /* resolve remote address if undefined */ + if (!sock->info.lsa->remote_list) + { + if (sock->remote_host) + { + unsigned int flags = sf2gaf(GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE, sock->sockflags); + int retry = 0; + int status = -1; + struct addrinfo *ai; + if (proto_is_dgram(sock->info.proto)) + { + flags |= GETADDR_DATAGRAM; + } + + if (sock->resolve_retry_seconds == RESOLV_RETRY_INFINITE) + { + if (phase == 2) + { + flags |= (GETADDR_TRY_ONCE | GETADDR_FATAL); + } + retry = 0; + } + else if (phase == 1) + { + if (sock->resolve_retry_seconds) + { + retry = 0; + } + else + { + flags |= (GETADDR_FATAL | GETADDR_MENTION_RESOLVE_RETRY); + retry = 0; + } + } + else if (phase == 2) + { + if (sock->resolve_retry_seconds) + { + flags |= GETADDR_FATAL; + retry = sock->resolve_retry_seconds; + } + else + { + ASSERT(0); + } + } + else + { + ASSERT(0); + } + + + status = get_cached_dns_entry(sock->dns_cache, + sock->remote_host, + sock->remote_port, + sock->info.af, + flags, &ai); + if (status) + { + status = openvpn_getaddrinfo(flags, sock->remote_host, sock->remote_port, + retry, signal_received, sock->info.af, &ai); + } + + if (status == 0) + { + sock->info.lsa->remote_list = ai; + sock->info.lsa->current_remote = ai; + + dmsg(D_SOCKET_DEBUG, "RESOLVE_REMOTE flags=0x%04x phase=%d rrs=%d sig=%d status=%d", + flags, + phase, + retry, + signal_received ? *signal_received : -1, + status); + } + if (signal_received) + { + if (*signal_received) + { + goto done; + } + } + if (status!=0) + { + if (signal_received) + { + *signal_received = SIGUSR1; + } + goto done; + } + } + } + + /* should we re-use previous active remote address? */ + if (link_socket_actual_defined(&sock->info.lsa->actual)) + { + msg(M_INFO, "TCP/UDP: Preserving recently used remote address: %s", + print_link_socket_actual(&sock->info.lsa->actual, &gc)); + if (remote_dynamic) + { + *remote_dynamic = NULL; + } + } + else + { + CLEAR(sock->info.lsa->actual); + if (sock->info.lsa->current_remote) + { + set_actual_address(&sock->info.lsa->actual, + sock->info.lsa->current_remote); + } + } + +done: + gc_free(&gc); } struct link_socket * -link_socket_new (void) +link_socket_new(void) { - struct link_socket *sock; + struct link_socket *sock; - ALLOC_OBJ_CLEAR (sock, struct link_socket); - sock->sd = SOCKET_UNDEFINED; - sock->ctrl_sd = SOCKET_UNDEFINED; - return sock; + ALLOC_OBJ_CLEAR(sock, struct link_socket); + sock->sd = SOCKET_UNDEFINED; + sock->ctrl_sd = SOCKET_UNDEFINED; + return sock; } void -link_socket_init_phase1 (struct link_socket *sock, - const char *local_host, - const char *local_port, - const char *remote_host, - const char *remote_port, - struct cached_dns_entry *dns_cache, - int proto, - sa_family_t af, - bool bind_ipv6_only, - int mode, - const struct link_socket *accept_from, - struct http_proxy_info *http_proxy, - struct socks_proxy_info *socks_proxy, +link_socket_init_phase1(struct link_socket *sock, + const char *local_host, + const char *local_port, + const char *remote_host, + const char *remote_port, + struct cached_dns_entry *dns_cache, + int proto, + sa_family_t af, + bool bind_ipv6_only, + int mode, + const struct link_socket *accept_from, + struct http_proxy_info *http_proxy, + struct socks_proxy_info *socks_proxy, #ifdef ENABLE_DEBUG - int gremlin, + int gremlin, #endif - bool bind_local, - bool remote_float, - int inetd, - struct link_socket_addr *lsa, - const char *ipchange_command, - const struct plugin_list *plugins, - int resolve_retry_seconds, - int mtu_discover_type, - int rcvbuf, - int sndbuf, - int mark, - struct event_timeout* server_poll_timeout, - unsigned int sockflags) -{ - ASSERT (sock); - - sock->local_host = local_host; - sock->local_port = local_port; - sock->remote_host = remote_host; - sock->remote_port = remote_port; - sock->dns_cache = dns_cache; - sock->http_proxy = http_proxy; - sock->socks_proxy = socks_proxy; - sock->bind_local = bind_local; - sock->inetd = inetd; - sock->resolve_retry_seconds = resolve_retry_seconds; - sock->mtu_discover_type = mtu_discover_type; + bool bind_local, + bool remote_float, + int inetd, + struct link_socket_addr *lsa, + const char *ipchange_command, + const struct plugin_list *plugins, + int resolve_retry_seconds, + int mtu_discover_type, + int rcvbuf, + int sndbuf, + int mark, + struct event_timeout *server_poll_timeout, + unsigned int sockflags) +{ + ASSERT(sock); + + sock->local_host = local_host; + sock->local_port = local_port; + sock->remote_host = remote_host; + sock->remote_port = remote_port; + sock->dns_cache = dns_cache; + sock->http_proxy = http_proxy; + sock->socks_proxy = socks_proxy; + sock->bind_local = bind_local; + sock->inetd = inetd; + sock->resolve_retry_seconds = resolve_retry_seconds; + sock->mtu_discover_type = mtu_discover_type; #ifdef ENABLE_DEBUG - sock->gremlin = gremlin; + sock->gremlin = gremlin; #endif - sock->socket_buffer_sizes.rcvbuf = rcvbuf; - sock->socket_buffer_sizes.sndbuf = sndbuf; + sock->socket_buffer_sizes.rcvbuf = rcvbuf; + sock->socket_buffer_sizes.sndbuf = sndbuf; - sock->sockflags = sockflags; - sock->mark = mark; + sock->sockflags = sockflags; + sock->mark = mark; - sock->info.proto = proto; - sock->info.af = af; - sock->info.remote_float = remote_float; - sock->info.lsa = lsa; - sock->info.bind_ipv6_only = bind_ipv6_only; - sock->info.ipchange_command = ipchange_command; - sock->info.plugins = plugins; - sock->server_poll_timeout = server_poll_timeout; + sock->info.proto = proto; + sock->info.af = af; + sock->info.remote_float = remote_float; + sock->info.lsa = lsa; + sock->info.bind_ipv6_only = bind_ipv6_only; + sock->info.ipchange_command = ipchange_command; + sock->info.plugins = plugins; + sock->server_poll_timeout = server_poll_timeout; - sock->mode = mode; - if (mode == LS_MODE_TCP_ACCEPT_FROM) + sock->mode = mode; + if (mode == LS_MODE_TCP_ACCEPT_FROM) { - ASSERT (accept_from); - ASSERT (sock->info.proto == PROTO_TCP_SERVER); - ASSERT (!sock->inetd); - sock->sd = accept_from->sd; + ASSERT(accept_from); + ASSERT(sock->info.proto == PROTO_TCP_SERVER); + ASSERT(!sock->inetd); + sock->sd = accept_from->sd; } - /* are we running in HTTP proxy mode? */ - if (sock->http_proxy) + /* are we running in HTTP proxy mode? */ + if (sock->http_proxy) { - ASSERT (sock->info.proto == PROTO_TCP_CLIENT); - ASSERT (!sock->inetd); + ASSERT(sock->info.proto == PROTO_TCP_CLIENT); + ASSERT(!sock->inetd); - /* the proxy server */ - sock->remote_host = http_proxy->options.server; - sock->remote_port = http_proxy->options.port; + /* the proxy server */ + sock->remote_host = http_proxy->options.server; + sock->remote_port = http_proxy->options.port; - /* the OpenVPN server we will use the proxy to connect to */ - sock->proxy_dest_host = remote_host; - sock->proxy_dest_port = remote_port; + /* the OpenVPN server we will use the proxy to connect to */ + sock->proxy_dest_host = remote_host; + sock->proxy_dest_port = remote_port; } - /* or in Socks proxy mode? */ - else if (sock->socks_proxy) + /* or in Socks proxy mode? */ + else if (sock->socks_proxy) { - ASSERT (!sock->inetd); + ASSERT(!sock->inetd); - /* the proxy server */ - sock->remote_host = socks_proxy->server; - sock->remote_port = socks_proxy->port; + /* the proxy server */ + sock->remote_host = socks_proxy->server; + sock->remote_port = socks_proxy->port; - /* the OpenVPN server we will use the proxy to connect to */ - sock->proxy_dest_host = remote_host; - sock->proxy_dest_port = remote_port; + /* the OpenVPN server we will use the proxy to connect to */ + sock->proxy_dest_host = remote_host; + sock->proxy_dest_port = remote_port; } - else + else { - sock->remote_host = remote_host; - sock->remote_port = remote_port; + sock->remote_host = remote_host; + sock->remote_port = remote_port; } - /* bind behavior for TCP server vs. client */ - if (sock->info.proto == PROTO_TCP_SERVER) + /* bind behavior for TCP server vs. client */ + if (sock->info.proto == PROTO_TCP_SERVER) { - if (sock->mode == LS_MODE_TCP_ACCEPT_FROM) - sock->bind_local = false; - else - sock->bind_local = true; + if (sock->mode == LS_MODE_TCP_ACCEPT_FROM) + { + sock->bind_local = false; + } + else + { + sock->bind_local = true; + } } - /* were we started by inetd or xinetd? */ - if (sock->inetd) + /* were we started by inetd or xinetd? */ + if (sock->inetd) { - ASSERT (sock->info.proto != PROTO_TCP_CLIENT); - ASSERT (socket_defined (inetd_socket_descriptor)); - sock->sd = inetd_socket_descriptor; - set_cloexec (sock->sd); /* not created by create_socket*() */ + ASSERT(sock->info.proto != PROTO_TCP_CLIENT); + ASSERT(socket_defined(inetd_socket_descriptor)); + sock->sd = inetd_socket_descriptor; + set_cloexec(sock->sd); /* not created by create_socket*() */ } - else if (mode != LS_MODE_TCP_ACCEPT_FROM) + else if (mode != LS_MODE_TCP_ACCEPT_FROM) { - if (sock->bind_local) { - resolve_bind_local (sock, sock->info.af); - } - resolve_remote (sock, 1, NULL, NULL); + if (sock->bind_local) + { + resolve_bind_local(sock, sock->info.af); + } + resolve_remote(sock, 1, NULL, NULL); } } static -void phase2_inetd (struct link_socket* sock, const struct frame *frame, - const char *remote_dynamic, volatile int *signal_received) +void +phase2_inetd(struct link_socket *sock, const struct frame *frame, + const char *remote_dynamic, volatile int *signal_received) { - bool remote_changed = false; + bool remote_changed = false; - if (sock->info.proto == PROTO_TCP_SERVER) { - /* AF_INET as default (and fallback) for inetd */ - sock->info.lsa->actual.dest.addr.sa.sa_family = AF_INET; -#ifdef HAVE_GETSOCKNAME + if (sock->info.proto == PROTO_TCP_SERVER) { - /* inetd: hint family type for dest = local's */ - struct openvpn_sockaddr local_addr; - socklen_t addrlen = sizeof(local_addr); - if (getsockname (sock->sd, &local_addr.addr.sa, &addrlen) == 0) { - sock->info.lsa->actual.dest.addr.sa.sa_family = local_addr.addr.sa.sa_family; - dmsg (D_SOCKET_DEBUG, "inetd(%s): using sa_family=%d from getsockname(%d)", - proto2ascii(sock->info.proto, sock->info.af, false), - local_addr.addr.sa.sa_family, sock->sd); - } else - msg (M_WARN, "inetd(%s): getsockname(%d) failed, using AF_INET", - proto2ascii(sock->info.proto, sock->info.af, false), sock->sd); - } -#else - msg (M_WARN, "inetd(%s): this OS does not provide the getsockname() " - "function, using AF_INET", - proto2ascii(sock->info.proto, false)); -#endif - sock->sd = - socket_listen_accept (sock->sd, - &sock->info.lsa->actual, - remote_dynamic, - sock->info.lsa->bind_local, - false, - sock->inetd == INETD_NOWAIT, - signal_received); + /* AF_INET as default (and fallback) for inetd */ + sock->info.lsa->actual.dest.addr.sa.sa_family = AF_INET; +#ifdef HAVE_GETSOCKNAME + { + /* inetd: hint family type for dest = local's */ + struct openvpn_sockaddr local_addr; + socklen_t addrlen = sizeof(local_addr); + if (getsockname(sock->sd, &local_addr.addr.sa, &addrlen) == 0) + { + sock->info.lsa->actual.dest.addr.sa.sa_family = local_addr.addr.sa.sa_family; + dmsg(D_SOCKET_DEBUG, "inetd(%s): using sa_family=%d from getsockname(%d)", + proto2ascii(sock->info.proto, sock->info.af, false), + local_addr.addr.sa.sa_family, sock->sd); + } + else + { + msg(M_WARN, "inetd(%s): getsockname(%d) failed, using AF_INET", + proto2ascii(sock->info.proto, sock->info.af, false), sock->sd); + } + } +#else /* ifdef HAVE_GETSOCKNAME */ + msg(M_WARN, "inetd(%s): this OS does not provide the getsockname() " + "function, using AF_INET", + proto2ascii(sock->info.proto, false)); +#endif /* ifdef HAVE_GETSOCKNAME */ + sock->sd = + socket_listen_accept(sock->sd, + &sock->info.lsa->actual, + remote_dynamic, + sock->info.lsa->bind_local, + false, + sock->inetd == INETD_NOWAIT, + signal_received); - } - ASSERT (!remote_changed); + } + ASSERT(!remote_changed); } static void -phase2_set_socket_flags (struct link_socket* sock) +phase2_set_socket_flags(struct link_socket *sock) { - /* set misc socket parameters */ - socket_set_flags (sock->sd, sock->sockflags); + /* set misc socket parameters */ + socket_set_flags(sock->sd, sock->sockflags); - /* set socket to non-blocking mode */ - set_nonblock (sock->sd); + /* set socket to non-blocking mode */ + set_nonblock(sock->sd); - /* set Path MTU discovery options on the socket */ - set_mtu_discover_type (sock->sd, sock->mtu_discover_type, sock->info.af); + /* set Path MTU discovery options on the socket */ + set_mtu_discover_type(sock->sd, sock->mtu_discover_type, sock->info.af); #if EXTENDED_SOCKET_ERROR_CAPABILITY - /* if the OS supports it, enable extended error passing on the socket */ - set_sock_extended_error_passing (sock->sd); + /* if the OS supports it, enable extended error passing on the socket */ + set_sock_extended_error_passing(sock->sd); #endif } static void -linksock_print_addr (struct link_socket *sock) -{ - struct gc_arena gc = gc_new (); - const int msglevel = (sock->mode == LS_MODE_TCP_ACCEPT_FROM) ? D_INIT_MEDIUM : M_INFO; - - /* print local address */ - if (sock->inetd) - msg (msglevel, "%s link local: [inetd]", proto2ascii (sock->info.proto, sock->info.af, true)); - else if (sock->bind_local) - { - sa_family_t ai_family = sock->info.lsa->actual.dest.addr.sa.sa_family; - /* Socket is always bound on the first matching address, - * For bound sockets with no remote addr this is the element of - * the list */ - struct addrinfo *cur; - for (cur = sock->info.lsa->bind_local; cur; cur=cur->ai_next) - { - if(!ai_family || ai_family == cur->ai_family) - break; - } - ASSERT (cur); - msg (msglevel, "%s link local (bound): %s", - proto2ascii (sock->info.proto, sock->info.af, true), - print_sockaddr(cur->ai_addr,&gc)); - } - else - msg (msglevel, "%s link local: (not bound)", - proto2ascii (sock->info.proto, sock->info.af, true)); - - /* print active remote address */ - msg (msglevel, "%s link remote: %s", - proto2ascii (sock->info.proto, sock->info.af, true), - print_link_socket_actual_ex (&sock->info.lsa->actual, - ":", - PS_SHOW_PORT_IF_DEFINED, - &gc)); - gc_free(&gc); +linksock_print_addr(struct link_socket *sock) +{ + struct gc_arena gc = gc_new(); + const int msglevel = (sock->mode == LS_MODE_TCP_ACCEPT_FROM) ? D_INIT_MEDIUM : M_INFO; + + /* print local address */ + if (sock->inetd) + { + msg(msglevel, "%s link local: [inetd]", proto2ascii(sock->info.proto, sock->info.af, true)); + } + else if (sock->bind_local) + { + sa_family_t ai_family = sock->info.lsa->actual.dest.addr.sa.sa_family; + /* Socket is always bound on the first matching address, + * For bound sockets with no remote addr this is the element of + * the list */ + struct addrinfo *cur; + for (cur = sock->info.lsa->bind_local; cur; cur = cur->ai_next) + { + if (!ai_family || ai_family == cur->ai_family) + { + break; + } + } + ASSERT(cur); + msg(msglevel, "%s link local (bound): %s", + proto2ascii(sock->info.proto, sock->info.af, true), + print_sockaddr(cur->ai_addr,&gc)); + } + else + { + msg(msglevel, "%s link local: (not bound)", + proto2ascii(sock->info.proto, sock->info.af, true)); + } + + /* print active remote address */ + msg(msglevel, "%s link remote: %s", + proto2ascii(sock->info.proto, sock->info.af, true), + print_link_socket_actual_ex(&sock->info.lsa->actual, + ":", + PS_SHOW_PORT_IF_DEFINED, + &gc)); + gc_free(&gc); } static void -phase2_tcp_server (struct link_socket *sock, const char *remote_dynamic, - volatile int *signal_received) -{ - switch (sock->mode) - { - case LS_MODE_DEFAULT: - sock->sd = socket_listen_accept (sock->sd, - &sock->info.lsa->actual, - remote_dynamic, - sock->info.lsa->bind_local, - true, - false, - signal_received); - break; - case LS_MODE_TCP_LISTEN: - socket_do_listen (sock->sd, - sock->info.lsa->bind_local, - true, - false); - break; - case LS_MODE_TCP_ACCEPT_FROM: - sock->sd = socket_do_accept (sock->sd, - &sock->info.lsa->actual, - false); - if (!socket_defined (sock->sd)) - { - *signal_received = SIGTERM; - return; - } - tcp_connection_established (&sock->info.lsa->actual); - break; - default: - ASSERT (0); +phase2_tcp_server(struct link_socket *sock, const char *remote_dynamic, + volatile int *signal_received) +{ + switch (sock->mode) + { + case LS_MODE_DEFAULT: + sock->sd = socket_listen_accept(sock->sd, + &sock->info.lsa->actual, + remote_dynamic, + sock->info.lsa->bind_local, + true, + false, + signal_received); + break; + + case LS_MODE_TCP_LISTEN: + socket_do_listen(sock->sd, + sock->info.lsa->bind_local, + true, + false); + break; + + case LS_MODE_TCP_ACCEPT_FROM: + sock->sd = socket_do_accept(sock->sd, + &sock->info.lsa->actual, + false); + if (!socket_defined(sock->sd)) + { + *signal_received = SIGTERM; + return; + } + tcp_connection_established(&sock->info.lsa->actual); + break; + + default: + ASSERT(0); } } static void -phase2_tcp_client (struct link_socket *sock, struct signal_info *sig_info) +phase2_tcp_client(struct link_socket *sock, struct signal_info *sig_info) { - bool proxy_retry = false; - do { - socket_connect (&sock->sd, - sock->info.lsa->current_remote->ai_addr, - get_server_poll_remaining_time (sock->server_poll_timeout), - sig_info); + bool proxy_retry = false; + do { + socket_connect(&sock->sd, + sock->info.lsa->current_remote->ai_addr, + get_server_poll_remaining_time(sock->server_poll_timeout), + sig_info); - if (sig_info->signal_received) - return; + if (sig_info->signal_received) + { + return; + } - if (sock->http_proxy) - { - proxy_retry = establish_http_proxy_passthru (sock->http_proxy, - sock->sd, - sock->proxy_dest_host, - sock->proxy_dest_port, - sock->server_poll_timeout, - &sock->stream_buf.residual, - &sig_info->signal_received); - } - else if (sock->socks_proxy) - { - establish_socks_proxy_passthru (sock->socks_proxy, - sock->sd, - sock->proxy_dest_host, - sock->proxy_dest_port, - &sig_info->signal_received); - } - if (proxy_retry) - { - openvpn_close_socket (sock->sd); - sock->sd = create_socket_tcp (sock->info.lsa->current_remote); - } + if (sock->http_proxy) + { + proxy_retry = establish_http_proxy_passthru(sock->http_proxy, + sock->sd, + sock->proxy_dest_host, + sock->proxy_dest_port, + sock->server_poll_timeout, + &sock->stream_buf.residual, + &sig_info->signal_received); + } + else if (sock->socks_proxy) + { + establish_socks_proxy_passthru(sock->socks_proxy, + sock->sd, + sock->proxy_dest_host, + sock->proxy_dest_port, + &sig_info->signal_received); + } + if (proxy_retry) + { + openvpn_close_socket(sock->sd); + sock->sd = create_socket_tcp(sock->info.lsa->current_remote); + } - } while (proxy_retry); + } while (proxy_retry); } static void -phase2_socks_client (struct link_socket *sock, struct signal_info *sig_info) +phase2_socks_client(struct link_socket *sock, struct signal_info *sig_info) { - socket_connect (&sock->ctrl_sd, - sock->info.lsa->current_remote->ai_addr, - get_server_poll_remaining_time (sock->server_poll_timeout), - sig_info); + socket_connect(&sock->ctrl_sd, + sock->info.lsa->current_remote->ai_addr, + get_server_poll_remaining_time(sock->server_poll_timeout), + sig_info); if (sig_info->signal_received) - return; + { + return; + } - establish_socks_proxy_udpassoc (sock->socks_proxy, - sock->ctrl_sd, - sock->sd, - &sock->socks_relay.dest, - &sig_info->signal_received); + establish_socks_proxy_udpassoc(sock->socks_proxy, + sock->ctrl_sd, + sock->sd, + &sock->socks_relay.dest, + &sig_info->signal_received); if (sig_info->signal_received) - return; + { + return; + } sock->remote_host = sock->proxy_dest_host; sock->remote_port = sock->proxy_dest_port; addr_zero_host(&sock->info.lsa->actual.dest); if (sock->info.lsa->remote_list) - { - freeaddrinfo(sock->info.lsa->remote_list); - sock->info.lsa->current_remote = NULL; - sock->info.lsa->remote_list = NULL; - } + { + freeaddrinfo(sock->info.lsa->remote_list); + sock->info.lsa->current_remote = NULL; + sock->info.lsa->remote_list = NULL; + } - resolve_remote (sock, 1, NULL, &sig_info->signal_received); + resolve_remote(sock, 1, NULL, &sig_info->signal_received); } /* finalize socket initialization */ void -link_socket_init_phase2 (struct link_socket *sock, - const struct frame *frame, - struct signal_info *sig_info) -{ - const char *remote_dynamic = NULL; - int sig_save = 0; - - ASSERT (sock); - ASSERT (sig_info); - - if (sig_info->signal_received) - { - sig_save = sig_info->signal_received; - sig_info->signal_received = 0; - } - - /* initialize buffers */ - socket_frame_init (frame, sock); - - /* - * Pass a remote name to connect/accept so that - * they can test for dynamic IP address changes - * and throw a SIGUSR1 if appropriate. - */ - if (sock->resolve_retry_seconds) - remote_dynamic = sock->remote_host; - - /* were we started by inetd or xinetd? */ - if (sock->inetd) - { - phase2_inetd (sock, frame, remote_dynamic, &sig_info->signal_received); - if (sig_info->signal_received) - goto done; - - } - else - { - /* Second chance to resolv/create socket */ - resolve_remote (sock, 2, &remote_dynamic, &sig_info->signal_received); - - /* If a valid remote has been found, create the socket with its addrinfo */ - if (sock->info.lsa->current_remote) - create_socket (sock, sock->info.lsa->current_remote); - - /* If socket has not already been created create it now */ - if (sock->sd == SOCKET_UNDEFINED) - { - /* If we have no --remote and have still not figured out the - * protocol family to use we will use the first of the bind */ - - if (sock->bind_local && !sock->remote_host && sock->info.lsa->bind_local) - { - /* Warn if this is because neither v4 or v6 was specified - * and we should not connect a remote */ - if (sock->info.af == AF_UNSPEC) - { - msg (M_WARN, "Could not determine IPv4/IPv6 protocol. Using %s", - addr_family_name(sock->info.lsa->bind_local->ai_family)); - sock->info.af = sock->info.lsa->bind_local->ai_family; - } - - create_socket (sock, sock->info.lsa->bind_local); - } - } - - /* Socket still undefined, give a warning and abort connection */ - if (sock->sd == SOCKET_UNDEFINED) - { - msg (M_WARN, "Could not determine IPv4/IPv6 protocol"); - sig_info->signal_received = SIGUSR1; - goto done; - } - - if (sig_info->signal_received) - goto done; - - if (sock->info.proto == PROTO_TCP_SERVER) - { - phase2_tcp_server (sock, remote_dynamic, - &sig_info->signal_received); - } - else if (sock->info.proto == PROTO_TCP_CLIENT) - { - phase2_tcp_client (sock, sig_info); - - } - else if (sock->info.proto == PROTO_UDP && sock->socks_proxy) - { - phase2_socks_client (sock, sig_info); - } +link_socket_init_phase2(struct link_socket *sock, + const struct frame *frame, + struct signal_info *sig_info) +{ + const char *remote_dynamic = NULL; + int sig_save = 0; + + ASSERT(sock); + ASSERT(sig_info); + + if (sig_info->signal_received) + { + sig_save = sig_info->signal_received; + sig_info->signal_received = 0; + } + + /* initialize buffers */ + socket_frame_init(frame, sock); + + /* + * Pass a remote name to connect/accept so that + * they can test for dynamic IP address changes + * and throw a SIGUSR1 if appropriate. + */ + if (sock->resolve_retry_seconds) + { + remote_dynamic = sock->remote_host; + } + + /* were we started by inetd or xinetd? */ + if (sock->inetd) + { + phase2_inetd(sock, frame, remote_dynamic, &sig_info->signal_received); + if (sig_info->signal_received) + { + goto done; + } + + } + else + { + /* Second chance to resolv/create socket */ + resolve_remote(sock, 2, &remote_dynamic, &sig_info->signal_received); + + /* If a valid remote has been found, create the socket with its addrinfo */ + if (sock->info.lsa->current_remote) + { + create_socket(sock, sock->info.lsa->current_remote); + } + + /* If socket has not already been created create it now */ + if (sock->sd == SOCKET_UNDEFINED) + { + /* If we have no --remote and have still not figured out the + * protocol family to use we will use the first of the bind */ + + if (sock->bind_local && !sock->remote_host && sock->info.lsa->bind_local) + { + /* Warn if this is because neither v4 or v6 was specified + * and we should not connect a remote */ + if (sock->info.af == AF_UNSPEC) + { + msg(M_WARN, "Could not determine IPv4/IPv6 protocol. Using %s", + addr_family_name(sock->info.lsa->bind_local->ai_family)); + sock->info.af = sock->info.lsa->bind_local->ai_family; + } + + create_socket(sock, sock->info.lsa->bind_local); + } + } + + /* Socket still undefined, give a warning and abort connection */ + if (sock->sd == SOCKET_UNDEFINED) + { + msg(M_WARN, "Could not determine IPv4/IPv6 protocol"); + sig_info->signal_received = SIGUSR1; + goto done; + } + + if (sig_info->signal_received) + { + goto done; + } + + if (sock->info.proto == PROTO_TCP_SERVER) + { + phase2_tcp_server(sock, remote_dynamic, + &sig_info->signal_received); + } + else if (sock->info.proto == PROTO_TCP_CLIENT) + { + phase2_tcp_client(sock, sig_info); + + } + else if (sock->info.proto == PROTO_UDP && sock->socks_proxy) + { + phase2_socks_client(sock, sig_info); + } #ifdef TARGET_ANDROID - if (sock->sd != -1) - protect_fd_nonlocal (sock->sd, &sock->info.lsa->actual.dest.addr.sa); + if (sock->sd != -1) + { + protect_fd_nonlocal(sock->sd, &sock->info.lsa->actual.dest.addr.sa); + } #endif - if (sig_info->signal_received) - goto done; + if (sig_info->signal_received) + { + goto done; + } } - phase2_set_socket_flags(sock); - linksock_print_addr(sock); + phase2_set_socket_flags(sock); + linksock_print_addr(sock); - done: - if (sig_save) +done: + if (sig_save) { - if (!sig_info->signal_received) - sig_info->signal_received = sig_save; + if (!sig_info->signal_received) + { + sig_info->signal_received = sig_save; + } } } void -link_socket_close (struct link_socket *sock) +link_socket_close(struct link_socket *sock) { - if (sock) + if (sock) { #ifdef ENABLE_DEBUG - const int gremlin = GREMLIN_CONNECTION_FLOOD_LEVEL (sock->gremlin); + const int gremlin = GREMLIN_CONNECTION_FLOOD_LEVEL(sock->gremlin); #else - const int gremlin = 0; + const int gremlin = 0; #endif - if (socket_defined (sock->sd)) - { + if (socket_defined(sock->sd)) + { #ifdef _WIN32 - close_net_event_win32 (&sock->listen_handle, sock->sd, 0); + close_net_event_win32(&sock->listen_handle, sock->sd, 0); #endif - if (!gremlin) - { - msg (D_LOW, "TCP/UDP: Closing socket"); - if (openvpn_close_socket (sock->sd)) - msg (M_WARN | M_ERRNO, "TCP/UDP: Close Socket failed"); - } - sock->sd = SOCKET_UNDEFINED; + if (!gremlin) + { + msg(D_LOW, "TCP/UDP: Closing socket"); + if (openvpn_close_socket(sock->sd)) + { + msg(M_WARN | M_ERRNO, "TCP/UDP: Close Socket failed"); + } + } + sock->sd = SOCKET_UNDEFINED; #ifdef _WIN32 - if (!gremlin) - { - overlapped_io_close (&sock->reads); - overlapped_io_close (&sock->writes); - } + if (!gremlin) + { + overlapped_io_close(&sock->reads); + overlapped_io_close(&sock->writes); + } #endif - } + } - if (socket_defined (sock->ctrl_sd)) - { - if (openvpn_close_socket (sock->ctrl_sd)) - msg (M_WARN | M_ERRNO, "TCP/UDP: Close Socket (ctrl_sd) failed"); - sock->ctrl_sd = SOCKET_UNDEFINED; - } + if (socket_defined(sock->ctrl_sd)) + { + if (openvpn_close_socket(sock->ctrl_sd)) + { + msg(M_WARN | M_ERRNO, "TCP/UDP: Close Socket (ctrl_sd) failed"); + } + sock->ctrl_sd = SOCKET_UNDEFINED; + } - stream_buf_close (&sock->stream_buf); - free_buf (&sock->stream_buf_data); - if (!gremlin) - free (sock); + stream_buf_close(&sock->stream_buf); + free_buf(&sock->stream_buf_data); + if (!gremlin) + { + free(sock); + } } } /* for stream protocols, allow for packet length prefix */ void -socket_adjust_frame_parameters (struct frame *frame, int proto) +socket_adjust_frame_parameters(struct frame *frame, int proto) { - if (link_socket_proto_connection_oriented (proto)) - frame_add_to_extra_frame (frame, sizeof (packet_size_type)); + if (link_socket_proto_connection_oriented(proto)) + { + frame_add_to_extra_frame(frame, sizeof(packet_size_type)); + } } void -setenv_trusted (struct env_set *es, const struct link_socket_info *info) +setenv_trusted(struct env_set *es, const struct link_socket_info *info) { - setenv_link_socket_actual (es, "trusted", &info->lsa->actual, SA_IP_PORT); + setenv_link_socket_actual(es, "trusted", &info->lsa->actual, SA_IP_PORT); } static void -ipchange_fmt (const bool include_cmd, struct argv *argv, const struct link_socket_info *info, struct gc_arena *gc) +ipchange_fmt(const bool include_cmd, struct argv *argv, const struct link_socket_info *info, struct gc_arena *gc) { - const char *host = print_sockaddr_ex (&info->lsa->actual.dest.addr.sa, " ", PS_SHOW_PORT , gc); - if (include_cmd) + const char *host = print_sockaddr_ex(&info->lsa->actual.dest.addr.sa, " ", PS_SHOW_PORT, gc); + if (include_cmd) + { + argv_parse_cmd(argv, info->ipchange_command); + argv_printf_cat(argv, "%s", host); + } + else { - argv_parse_cmd (argv, info->ipchange_command); - argv_printf_cat (argv, "%s", host); + argv_printf(argv, "%s", host); } - else - argv_printf (argv, "%s", host); } void -link_socket_connection_initiated (const struct buffer *buf, - struct link_socket_info *info, - const struct link_socket_actual *act, - const char *common_name, - struct env_set *es) +link_socket_connection_initiated(const struct buffer *buf, + struct link_socket_info *info, + const struct link_socket_actual *act, + const char *common_name, + struct env_set *es) { - struct gc_arena gc = gc_new (); - - info->lsa->actual = *act; /* Note: skip this line for --force-dest */ - setenv_trusted (es, info); - info->connection_established = true; + struct gc_arena gc = gc_new(); + + info->lsa->actual = *act; /* Note: skip this line for --force-dest */ + setenv_trusted(es, info); + info->connection_established = true; - /* Print connection initiated message, with common name if available */ - { - struct buffer out = alloc_buf_gc (256, &gc); - if (common_name) - buf_printf (&out, "[%s] ", common_name); - buf_printf (&out, "Peer Connection Initiated with %s", print_link_socket_actual (&info->lsa->actual, &gc)); - msg (M_INFO, "%s", BSTR (&out)); - } + /* Print connection initiated message, with common name if available */ + { + struct buffer out = alloc_buf_gc(256, &gc); + if (common_name) + { + buf_printf(&out, "[%s] ", common_name); + } + buf_printf(&out, "Peer Connection Initiated with %s", print_link_socket_actual(&info->lsa->actual, &gc)); + msg(M_INFO, "%s", BSTR(&out)); + } - /* set environmental vars */ - setenv_str (es, "common_name", common_name); + /* set environmental vars */ + setenv_str(es, "common_name", common_name); - /* Process --ipchange plugin */ - if (plugin_defined (info->plugins, OPENVPN_PLUGIN_IPCHANGE)) + /* Process --ipchange plugin */ + if (plugin_defined(info->plugins, OPENVPN_PLUGIN_IPCHANGE)) { - struct argv argv = argv_new (); - ipchange_fmt (false, &argv, info, &gc); - if (plugin_call (info->plugins, OPENVPN_PLUGIN_IPCHANGE, &argv, NULL, es) != OPENVPN_PLUGIN_FUNC_SUCCESS) - msg (M_WARN, "WARNING: ipchange plugin call failed"); - argv_reset (&argv); + struct argv argv = argv_new(); + ipchange_fmt(false, &argv, info, &gc); + if (plugin_call(info->plugins, OPENVPN_PLUGIN_IPCHANGE, &argv, NULL, es) != OPENVPN_PLUGIN_FUNC_SUCCESS) + { + msg(M_WARN, "WARNING: ipchange plugin call failed"); + } + argv_reset(&argv); } - /* Process --ipchange option */ - if (info->ipchange_command) + /* Process --ipchange option */ + if (info->ipchange_command) { - struct argv argv = argv_new (); - setenv_str (es, "script_type", "ipchange"); - ipchange_fmt (true, &argv, info, &gc); - openvpn_run_script (&argv, es, 0, "--ipchange"); - argv_reset (&argv); + struct argv argv = argv_new(); + setenv_str(es, "script_type", "ipchange"); + ipchange_fmt(true, &argv, info, &gc); + openvpn_run_script(&argv, es, 0, "--ipchange"); + argv_reset(&argv); } - gc_free (&gc); + gc_free(&gc); } void -link_socket_bad_incoming_addr (struct buffer *buf, - const struct link_socket_info *info, - const struct link_socket_actual *from_addr) -{ - struct gc_arena gc = gc_new (); - struct addrinfo* ai; - - switch(from_addr->dest.addr.sa.sa_family) - { - case AF_INET: - case AF_INET6: - msg (D_LINK_ERRORS, - "TCP/UDP: Incoming packet rejected from %s[%d], expected peer address: %s (allow this incoming source address/port by removing --remote or adding --float)", - print_link_socket_actual (from_addr, &gc), - (int)from_addr->dest.addr.sa.sa_family, - print_sockaddr_ex (info->lsa->remote_list->ai_addr,":" ,PS_SHOW_PORT, &gc)); - /* print additional remote addresses */ - for(ai=info->lsa->remote_list->ai_next;ai;ai=ai->ai_next) { - msg(D_LINK_ERRORS,"or from peer address: %s", - print_sockaddr_ex(ai->ai_addr,":",PS_SHOW_PORT, &gc)); - } - break; +link_socket_bad_incoming_addr(struct buffer *buf, + const struct link_socket_info *info, + const struct link_socket_actual *from_addr) +{ + struct gc_arena gc = gc_new(); + struct addrinfo *ai; + + switch (from_addr->dest.addr.sa.sa_family) + { + case AF_INET: + case AF_INET6: + msg(D_LINK_ERRORS, + "TCP/UDP: Incoming packet rejected from %s[%d], expected peer address: %s (allow this incoming source address/port by removing --remote or adding --float)", + print_link_socket_actual(from_addr, &gc), + (int)from_addr->dest.addr.sa.sa_family, + print_sockaddr_ex(info->lsa->remote_list->ai_addr,":",PS_SHOW_PORT, &gc)); + /* print additional remote addresses */ + for (ai = info->lsa->remote_list->ai_next; ai; ai = ai->ai_next) { + msg(D_LINK_ERRORS,"or from peer address: %s", + print_sockaddr_ex(ai->ai_addr,":",PS_SHOW_PORT, &gc)); + } + break; } - buf->len = 0; - gc_free (&gc); + buf->len = 0; + gc_free(&gc); } void -link_socket_bad_outgoing_addr (void) +link_socket_bad_outgoing_addr(void) { - dmsg (D_READ_WRITE, "TCP/UDP: No outgoing address to send packet"); + dmsg(D_READ_WRITE, "TCP/UDP: No outgoing address to send packet"); } in_addr_t -link_socket_current_remote (const struct link_socket_info *info) +link_socket_current_remote(const struct link_socket_info *info) { - const struct link_socket_addr *lsa = info->lsa; + const struct link_socket_addr *lsa = info->lsa; -/* - * This logic supports "redirect-gateway" semantic, which +/* + * This logic supports "redirect-gateway" semantic, which * makes sense only for PF_INET routes over PF_INET endpoints * * Maybe in the future consider PF_INET6 endpoints also ... @@ -2138,22 +2395,30 @@ link_socket_current_remote (const struct link_socket_info *info) * For --remote entries with multiple addresses this * only return the actual endpoint we have sucessfully connected to */ - if (lsa->actual.dest.addr.sa.sa_family != AF_INET) - return IPV4_INVALID_ADDR; - - if (link_socket_actual_defined (&lsa->actual)) - return ntohl (lsa->actual.dest.addr.in4.sin_addr.s_addr); - else if (lsa->current_remote) - return ntohl (((struct sockaddr_in*)lsa->current_remote->ai_addr) - ->sin_addr.s_addr); - else - return 0; + if (lsa->actual.dest.addr.sa.sa_family != AF_INET) + { + return IPV4_INVALID_ADDR; + } + + if (link_socket_actual_defined(&lsa->actual)) + { + return ntohl(lsa->actual.dest.addr.in4.sin_addr.s_addr); + } + else if (lsa->current_remote) + { + return ntohl(((struct sockaddr_in *)lsa->current_remote->ai_addr) + ->sin_addr.s_addr); + } + else + { + return 0; + } } const struct in6_addr * -link_socket_current_remote_ipv6 (const struct link_socket_info *info) +link_socket_current_remote_ipv6(const struct link_socket_info *info) { - const struct link_socket_addr *lsa = info->lsa; + const struct link_socket_addr *lsa = info->lsa; /* This logic supports "redirect-gateway" semantic, * for PF_INET6 routes over PF_INET6 endpoints @@ -2161,50 +2426,58 @@ link_socket_current_remote_ipv6 (const struct link_socket_info *info) * For --remote entries with multiple addresses this * only return the actual endpoint we have sucessfully connected to */ - if (lsa->actual.dest.addr.sa.sa_family != AF_INET6) - return NULL; + if (lsa->actual.dest.addr.sa.sa_family != AF_INET6) + { + return NULL; + } - if (link_socket_actual_defined (&lsa->actual)) - return &(lsa->actual.dest.addr.in6.sin6_addr); - else if (lsa->current_remote) - return &(((struct sockaddr_in6*)lsa->current_remote->ai_addr) ->sin6_addr); - else - return NULL; + if (link_socket_actual_defined(&lsa->actual)) + { + return &(lsa->actual.dest.addr.in6.sin6_addr); + } + else if (lsa->current_remote) + { + return &(((struct sockaddr_in6 *)lsa->current_remote->ai_addr)->sin6_addr); + } + else + { + return NULL; + } } /* * Return a status string describing socket state. */ const char * -socket_stat (const struct link_socket *s, unsigned int rwflags, struct gc_arena *gc) +socket_stat(const struct link_socket *s, unsigned int rwflags, struct gc_arena *gc) { - struct buffer out = alloc_buf_gc (64, gc); - if (s) + struct buffer out = alloc_buf_gc(64, gc); + if (s) { - if (rwflags & EVENT_READ) - { - buf_printf (&out, "S%s", - (s->rwflags_debug & EVENT_READ) ? "R" : "r"); + if (rwflags & EVENT_READ) + { + buf_printf(&out, "S%s", + (s->rwflags_debug & EVENT_READ) ? "R" : "r"); #ifdef _WIN32 - buf_printf (&out, "%s", - overlapped_io_state_ascii (&s->reads)); + buf_printf(&out, "%s", + overlapped_io_state_ascii(&s->reads)); #endif - } - if (rwflags & EVENT_WRITE) - { - buf_printf (&out, "S%s", - (s->rwflags_debug & EVENT_WRITE) ? "W" : "w"); + } + if (rwflags & EVENT_WRITE) + { + buf_printf(&out, "S%s", + (s->rwflags_debug & EVENT_WRITE) ? "W" : "w"); #ifdef _WIN32 - buf_printf (&out, "%s", - overlapped_io_state_ascii (&s->writes)); + buf_printf(&out, "%s", + overlapped_io_state_ascii(&s->writes)); #endif - } + } } - else + else { - buf_printf (&out, "S?"); + buf_printf(&out, "S?"); } - return BSTR (&out); + return BSTR(&out); } /* @@ -2213,152 +2486,160 @@ socket_stat (const struct link_socket *s, unsigned int rwflags, struct gc_arena */ static inline void -stream_buf_reset (struct stream_buf *sb) +stream_buf_reset(struct stream_buf *sb) { - dmsg (D_STREAM_DEBUG, "STREAM: RESET"); - sb->residual_fully_formed = false; - sb->buf = sb->buf_init; - buf_reset (&sb->next); - sb->len = -1; + dmsg(D_STREAM_DEBUG, "STREAM: RESET"); + sb->residual_fully_formed = false; + sb->buf = sb->buf_init; + buf_reset(&sb->next); + sb->len = -1; } void -stream_buf_init (struct stream_buf *sb, - struct buffer *buf, - const unsigned int sockflags, - const int proto) -{ - sb->buf_init = *buf; - sb->maxlen = sb->buf_init.len; - sb->buf_init.len = 0; - sb->residual = alloc_buf (sb->maxlen); - sb->error = false; +stream_buf_init(struct stream_buf *sb, + struct buffer *buf, + const unsigned int sockflags, + const int proto) +{ + sb->buf_init = *buf; + sb->maxlen = sb->buf_init.len; + sb->buf_init.len = 0; + sb->residual = alloc_buf(sb->maxlen); + sb->error = false; #if PORT_SHARE - sb->port_share_state = ((sockflags & SF_PORT_SHARE) && (proto == PROTO_TCP_SERVER)) - ? PS_ENABLED - : PS_DISABLED; + sb->port_share_state = ((sockflags & SF_PORT_SHARE) && (proto == PROTO_TCP_SERVER)) + ? PS_ENABLED + : PS_DISABLED; #endif - stream_buf_reset (sb); + stream_buf_reset(sb); - dmsg (D_STREAM_DEBUG, "STREAM: INIT maxlen=%d", sb->maxlen); + dmsg(D_STREAM_DEBUG, "STREAM: INIT maxlen=%d", sb->maxlen); } static inline void -stream_buf_set_next (struct stream_buf *sb) +stream_buf_set_next(struct stream_buf *sb) { - /* set up 'next' for next i/o read */ - sb->next = sb->buf; - sb->next.offset = sb->buf.offset + sb->buf.len; - sb->next.len = (sb->len >= 0 ? sb->len : sb->maxlen) - sb->buf.len; - dmsg (D_STREAM_DEBUG, "STREAM: SET NEXT, buf=[%d,%d] next=[%d,%d] len=%d maxlen=%d", - sb->buf.offset, sb->buf.len, - sb->next.offset, sb->next.len, - sb->len, sb->maxlen); - ASSERT (sb->next.len > 0); - ASSERT (buf_safe (&sb->buf, sb->next.len)); + /* set up 'next' for next i/o read */ + sb->next = sb->buf; + sb->next.offset = sb->buf.offset + sb->buf.len; + sb->next.len = (sb->len >= 0 ? sb->len : sb->maxlen) - sb->buf.len; + dmsg(D_STREAM_DEBUG, "STREAM: SET NEXT, buf=[%d,%d] next=[%d,%d] len=%d maxlen=%d", + sb->buf.offset, sb->buf.len, + sb->next.offset, sb->next.len, + sb->len, sb->maxlen); + ASSERT(sb->next.len > 0); + ASSERT(buf_safe(&sb->buf, sb->next.len)); } static inline void -stream_buf_get_final (struct stream_buf *sb, struct buffer *buf) +stream_buf_get_final(struct stream_buf *sb, struct buffer *buf) { - dmsg (D_STREAM_DEBUG, "STREAM: GET FINAL len=%d", - buf_defined (&sb->buf) ? sb->buf.len : -1); - ASSERT (buf_defined (&sb->buf)); - *buf = sb->buf; + dmsg(D_STREAM_DEBUG, "STREAM: GET FINAL len=%d", + buf_defined(&sb->buf) ? sb->buf.len : -1); + ASSERT(buf_defined(&sb->buf)); + *buf = sb->buf; } static inline void -stream_buf_get_next (struct stream_buf *sb, struct buffer *buf) +stream_buf_get_next(struct stream_buf *sb, struct buffer *buf) { - dmsg (D_STREAM_DEBUG, "STREAM: GET NEXT len=%d", - buf_defined (&sb->next) ? sb->next.len : -1); - ASSERT (buf_defined (&sb->next)); - *buf = sb->next; + dmsg(D_STREAM_DEBUG, "STREAM: GET NEXT len=%d", + buf_defined(&sb->next) ? sb->next.len : -1); + ASSERT(buf_defined(&sb->next)); + *buf = sb->next; } bool -stream_buf_read_setup_dowork (struct link_socket* sock) +stream_buf_read_setup_dowork(struct link_socket *sock) { - if (sock->stream_buf.residual.len && !sock->stream_buf.residual_fully_formed) + if (sock->stream_buf.residual.len && !sock->stream_buf.residual_fully_formed) { - ASSERT (buf_copy (&sock->stream_buf.buf, &sock->stream_buf.residual)); - ASSERT (buf_init (&sock->stream_buf.residual, 0)); - sock->stream_buf.residual_fully_formed = stream_buf_added (&sock->stream_buf, 0); - dmsg (D_STREAM_DEBUG, "STREAM: RESIDUAL FULLY FORMED [%s], len=%d", - sock->stream_buf.residual_fully_formed ? "YES" : "NO", - sock->stream_buf.residual.len); + ASSERT(buf_copy(&sock->stream_buf.buf, &sock->stream_buf.residual)); + ASSERT(buf_init(&sock->stream_buf.residual, 0)); + sock->stream_buf.residual_fully_formed = stream_buf_added(&sock->stream_buf, 0); + dmsg(D_STREAM_DEBUG, "STREAM: RESIDUAL FULLY FORMED [%s], len=%d", + sock->stream_buf.residual_fully_formed ? "YES" : "NO", + sock->stream_buf.residual.len); } - if (!sock->stream_buf.residual_fully_formed) - stream_buf_set_next (&sock->stream_buf); - return !sock->stream_buf.residual_fully_formed; + if (!sock->stream_buf.residual_fully_formed) + { + stream_buf_set_next(&sock->stream_buf); + } + return !sock->stream_buf.residual_fully_formed; } bool -stream_buf_added (struct stream_buf *sb, - int length_added) +stream_buf_added(struct stream_buf *sb, + int length_added) { - dmsg (D_STREAM_DEBUG, "STREAM: ADD length_added=%d", length_added); - if (length_added > 0) - sb->buf.len += length_added; + dmsg(D_STREAM_DEBUG, "STREAM: ADD length_added=%d", length_added); + if (length_added > 0) + { + sb->buf.len += length_added; + } - /* if length unknown, see if we can get the length prefix from - the head of the buffer */ - if (sb->len < 0 && sb->buf.len >= (int) sizeof (packet_size_type)) + /* if length unknown, see if we can get the length prefix from + * the head of the buffer */ + if (sb->len < 0 && sb->buf.len >= (int) sizeof(packet_size_type)) { - packet_size_type net_size; + packet_size_type net_size; #if PORT_SHARE - if (sb->port_share_state == PS_ENABLED) - { - if (!is_openvpn_protocol (&sb->buf)) - { - msg (D_STREAM_ERRORS, "Non-OpenVPN client protocol detected"); - sb->port_share_state = PS_FOREIGN; - sb->error = true; - return false; - } - else - sb->port_share_state = PS_DISABLED; - } + if (sb->port_share_state == PS_ENABLED) + { + if (!is_openvpn_protocol(&sb->buf)) + { + msg(D_STREAM_ERRORS, "Non-OpenVPN client protocol detected"); + sb->port_share_state = PS_FOREIGN; + sb->error = true; + return false; + } + else + { + sb->port_share_state = PS_DISABLED; + } + } #endif - ASSERT (buf_read (&sb->buf, &net_size, sizeof (net_size))); - sb->len = ntohps (net_size); + ASSERT(buf_read(&sb->buf, &net_size, sizeof(net_size))); + sb->len = ntohps(net_size); - if (sb->len < 1 || sb->len > sb->maxlen) - { - msg (M_WARN, "WARNING: Bad encapsulated packet length from peer (%d), which must be > 0 and <= %d -- please ensure that --tun-mtu or --link-mtu is equal on both peers -- this condition could also indicate a possible active attack on the TCP link -- [Attempting restart...]", sb->len, sb->maxlen); - stream_buf_reset (sb); - sb->error = true; - return false; - } + if (sb->len < 1 || sb->len > sb->maxlen) + { + msg(M_WARN, "WARNING: Bad encapsulated packet length from peer (%d), which must be > 0 and <= %d -- please ensure that --tun-mtu or --link-mtu is equal on both peers -- this condition could also indicate a possible active attack on the TCP link -- [Attempting restart...]", sb->len, sb->maxlen); + stream_buf_reset(sb); + sb->error = true; + return false; + } } - /* is our incoming packet fully read? */ - if (sb->len > 0 && sb->buf.len >= sb->len) + /* is our incoming packet fully read? */ + if (sb->len > 0 && sb->buf.len >= sb->len) { - /* save any residual data that's part of the next packet */ - ASSERT (buf_init (&sb->residual, 0)); - if (sb->buf.len > sb->len) - ASSERT (buf_copy_excess (&sb->residual, &sb->buf, sb->len)); - dmsg (D_STREAM_DEBUG, "STREAM: ADD returned TRUE, buf_len=%d, residual_len=%d", - BLEN (&sb->buf), - BLEN (&sb->residual)); - return true; + /* save any residual data that's part of the next packet */ + ASSERT(buf_init(&sb->residual, 0)); + if (sb->buf.len > sb->len) + { + ASSERT(buf_copy_excess(&sb->residual, &sb->buf, sb->len)); + } + dmsg(D_STREAM_DEBUG, "STREAM: ADD returned TRUE, buf_len=%d, residual_len=%d", + BLEN(&sb->buf), + BLEN(&sb->residual)); + return true; } - else + else { - dmsg (D_STREAM_DEBUG, "STREAM: ADD returned FALSE (have=%d need=%d)", sb->buf.len, sb->len); - stream_buf_set_next (sb); - return false; + dmsg(D_STREAM_DEBUG, "STREAM: ADD returned FALSE (have=%d need=%d)", sb->buf.len, sb->len); + stream_buf_set_next(sb); + return false; } } void -stream_buf_close (struct stream_buf* sb) +stream_buf_close(struct stream_buf *sb) { - free_buf (&sb->residual); + free_buf(&sb->residual); } /* @@ -2367,14 +2648,16 @@ stream_buf_close (struct stream_buf* sb) * TCP socket, for use in server mode. */ event_t -socket_listen_event_handle (struct link_socket *s) +socket_listen_event_handle(struct link_socket *s) { #ifdef _WIN32 - if (!defined_net_event_win32 (&s->listen_handle)) - init_net_event_win32 (&s->listen_handle, FD_ACCEPT, s->sd, 0); - return &s->listen_handle; -#else - return s->sd; + if (!defined_net_event_win32(&s->listen_handle)) + { + init_net_event_win32(&s->listen_handle, FD_ACCEPT, s->sd, 0); + } + return &s->listen_handle; +#else /* ifdef _WIN32 */ + return s->sd; #endif } @@ -2383,72 +2666,90 @@ socket_listen_event_handle (struct link_socket *s) */ const char * -print_sockaddr_ex (const struct sockaddr *sa, - const char* separator, - const unsigned int flags, - struct gc_arena *gc) -{ - struct buffer out = alloc_buf_gc (128, gc); - bool addr_is_defined = false; - char hostaddr[NI_MAXHOST] = ""; - char servname[NI_MAXSERV] = ""; - int status; +print_sockaddr_ex(const struct sockaddr *sa, + const char *separator, + const unsigned int flags, + struct gc_arena *gc) +{ + struct buffer out = alloc_buf_gc(128, gc); + bool addr_is_defined = false; + char hostaddr[NI_MAXHOST] = ""; + char servname[NI_MAXSERV] = ""; + int status; + + socklen_t salen = 0; + switch (sa->sa_family) + { + case AF_INET: + if (!(flags & PS_DONT_SHOW_FAMILY)) + { + buf_puts(&out, "[AF_INET]"); + } + salen = sizeof(struct sockaddr_in); + addr_is_defined = ((struct sockaddr_in *) sa)->sin_addr.s_addr != 0; + break; - socklen_t salen = 0; - switch(sa->sa_family) - { - case AF_INET: - if (!(flags & PS_DONT_SHOW_FAMILY)) - buf_puts (&out, "[AF_INET]"); - salen = sizeof (struct sockaddr_in); - addr_is_defined = ((struct sockaddr_in*) sa)->sin_addr.s_addr != 0; - break; - case AF_INET6: - if (!(flags & PS_DONT_SHOW_FAMILY)) - buf_puts (&out, "[AF_INET6]"); - salen = sizeof (struct sockaddr_in6); - addr_is_defined = !IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6*) sa)->sin6_addr); - break; - case AF_UNSPEC: - if (!(flags & PS_DONT_SHOW_FAMILY)) - return "[AF_UNSPEC]"; - else - return ""; - default: - ASSERT(0); + case AF_INET6: + if (!(flags & PS_DONT_SHOW_FAMILY)) + { + buf_puts(&out, "[AF_INET6]"); + } + salen = sizeof(struct sockaddr_in6); + addr_is_defined = !IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *) sa)->sin6_addr); + break; + + case AF_UNSPEC: + if (!(flags & PS_DONT_SHOW_FAMILY)) + { + return "[AF_UNSPEC]"; + } + else + { + return ""; + } + + default: + ASSERT(0); } - status = getnameinfo(sa, salen, hostaddr, sizeof (hostaddr), - servname, sizeof(servname), NI_NUMERICHOST | NI_NUMERICSERV); + status = getnameinfo(sa, salen, hostaddr, sizeof(hostaddr), + servname, sizeof(servname), NI_NUMERICHOST | NI_NUMERICSERV); - if(status!=0) { - buf_printf(&out,"[nameinfo() err: %s]",gai_strerror(status)); - return BSTR(&out); - } + if (status!=0) + { + buf_printf(&out,"[nameinfo() err: %s]",gai_strerror(status)); + return BSTR(&out); + } - if (!(flags & PS_DONT_SHOW_ADDR)) + if (!(flags & PS_DONT_SHOW_ADDR)) { - if (addr_is_defined) - buf_puts (&out, hostaddr); - else - buf_puts (&out, "[undef]"); + if (addr_is_defined) + { + buf_puts(&out, hostaddr); + } + else + { + buf_puts(&out, "[undef]"); + } } - if ((flags & PS_SHOW_PORT) || (flags & PS_SHOW_PORT_IF_DEFINED)) + if ((flags & PS_SHOW_PORT) || (flags & PS_SHOW_PORT_IF_DEFINED)) { - if (separator) - buf_puts (&out, separator); + if (separator) + { + buf_puts(&out, separator); + } - buf_puts (&out, servname); + buf_puts(&out, servname); } - return BSTR (&out); + return BSTR(&out); } const char * -print_link_socket_actual (const struct link_socket_actual *act, struct gc_arena *gc) +print_link_socket_actual(const struct link_socket_actual *act, struct gc_arena *gc) { - return print_link_socket_actual_ex (act, ":", PS_SHOW_PORT|PS_SHOW_PKTINFO, gc); + return print_link_socket_actual_ex(act, ":", PS_SHOW_PORT|PS_SHOW_PKTINFO, gc); } #ifndef IF_NAMESIZE @@ -2456,62 +2757,69 @@ print_link_socket_actual (const struct link_socket_actual *act, struct gc_arena #endif const char * -print_link_socket_actual_ex (const struct link_socket_actual *act, - const char *separator, - const unsigned int flags, - struct gc_arena *gc) +print_link_socket_actual_ex(const struct link_socket_actual *act, + const char *separator, + const unsigned int flags, + struct gc_arena *gc) { - if (act) + if (act) { - char ifname[IF_NAMESIZE] = "[undef]"; - struct buffer out = alloc_buf_gc (128, gc); - buf_printf (&out, "%s", print_sockaddr_ex (&act->dest.addr.sa, separator, flags, gc)); + char ifname[IF_NAMESIZE] = "[undef]"; + struct buffer out = alloc_buf_gc(128, gc); + buf_printf(&out, "%s", print_sockaddr_ex(&act->dest.addr.sa, separator, flags, gc)); #if ENABLE_IP_PKTINFO - if ((flags & PS_SHOW_PKTINFO) && addr_defined_ipi(act)) - { - switch(act->dest.addr.sa.sa_family) - { - case AF_INET: - { - struct openvpn_sockaddr sa; - CLEAR (sa); - sa.addr.in4.sin_family = AF_INET; + if ((flags & PS_SHOW_PKTINFO) && addr_defined_ipi(act)) + { + switch (act->dest.addr.sa.sa_family) + { + case AF_INET: + { + struct openvpn_sockaddr sa; + CLEAR(sa); + sa.addr.in4.sin_family = AF_INET; #if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) - sa.addr.in4.sin_addr = act->pi.in4.ipi_spec_dst; - if_indextoname(act->pi.in4.ipi_ifindex, ifname); + sa.addr.in4.sin_addr = act->pi.in4.ipi_spec_dst; + if_indextoname(act->pi.in4.ipi_ifindex, ifname); #elif defined(IP_RECVDSTADDR) - sa.addr.in4.sin_addr = act->pi.in4; - ifname[0]=0; -#else + sa.addr.in4.sin_addr = act->pi.in4; + ifname[0] = 0; +#else /* if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) */ #error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h) #endif - buf_printf (&out, " (via %s%%%s)", - print_sockaddr_ex (&sa.addr.sa, separator, 0, gc), - ifname); - } - break; - case AF_INET6: - { - struct sockaddr_in6 sin6; - char buf[INET6_ADDRSTRLEN] = "[undef]"; - CLEAR(sin6); - sin6.sin6_family = AF_INET6; - sin6.sin6_addr = act->pi.in6.ipi6_addr; - if_indextoname(act->pi.in6.ipi6_ifindex, ifname); - if (getnameinfo((struct sockaddr *)&sin6, sizeof (struct sockaddr_in6), - buf, sizeof (buf), NULL, 0, NI_NUMERICHOST) == 0) - buf_printf (&out, " (via %s%%%s)", buf, ifname); - else - buf_printf (&out, " (via [getnameinfo() err]%%%s)", ifname); - } - break; - } - } -#endif - return BSTR (&out); + buf_printf(&out, " (via %s%%%s)", + print_sockaddr_ex(&sa.addr.sa, separator, 0, gc), + ifname); + } + break; + + case AF_INET6: + { + struct sockaddr_in6 sin6; + char buf[INET6_ADDRSTRLEN] = "[undef]"; + CLEAR(sin6); + sin6.sin6_family = AF_INET6; + sin6.sin6_addr = act->pi.in6.ipi6_addr; + if_indextoname(act->pi.in6.ipi6_ifindex, ifname); + if (getnameinfo((struct sockaddr *)&sin6, sizeof(struct sockaddr_in6), + buf, sizeof(buf), NULL, 0, NI_NUMERICHOST) == 0) + { + buf_printf(&out, " (via %s%%%s)", buf, ifname); + } + else + { + buf_printf(&out, " (via [getnameinfo() err]%%%s)", ifname); + } + } + break; + } + } +#endif /* if ENABLE_IP_PKTINFO */ + return BSTR(&out); + } + else + { + return "[NULL]"; } - else - return "[NULL]"; } /* @@ -2519,19 +2827,19 @@ print_link_socket_actual_ex (const struct link_socket_actual *act, * to an ascii dotted quad. */ const char * -print_in_addr_t (in_addr_t addr, unsigned int flags, struct gc_arena *gc) +print_in_addr_t(in_addr_t addr, unsigned int flags, struct gc_arena *gc) { - struct in_addr ia; - struct buffer out = alloc_buf_gc (64, gc); + struct in_addr ia; + struct buffer out = alloc_buf_gc(64, gc); - if (addr || !(flags & IA_EMPTY_IF_UNDEF)) + if (addr || !(flags & IA_EMPTY_IF_UNDEF)) { - CLEAR (ia); - ia.s_addr = (flags & IA_NET_ORDER) ? addr : htonl (addr); + CLEAR(ia); + ia.s_addr = (flags & IA_NET_ORDER) ? addr : htonl(addr); - buf_printf (&out, "%s", inet_ntoa (ia)); + buf_printf(&out, "%s", inet_ntoa(ia)); } - return BSTR (&out); + return BSTR(&out); } /* @@ -2539,133 +2847,139 @@ print_in_addr_t (in_addr_t addr, unsigned int flags, struct gc_arena *gc) * to an ascii representation of an IPv6 address */ const char * -print_in6_addr (struct in6_addr a6, unsigned int flags, struct gc_arena *gc) +print_in6_addr(struct in6_addr a6, unsigned int flags, struct gc_arena *gc) { - struct buffer out = alloc_buf_gc (64, gc); - char tmp_out_buf[64]; /* inet_ntop wants pointer to buffer */ + struct buffer out = alloc_buf_gc(64, gc); + char tmp_out_buf[64]; /* inet_ntop wants pointer to buffer */ - if ( memcmp(&a6, &in6addr_any, sizeof(a6)) != 0 || - !(flags & IA_EMPTY_IF_UNDEF)) + if (memcmp(&a6, &in6addr_any, sizeof(a6)) != 0 + || !(flags & IA_EMPTY_IF_UNDEF)) { - inet_ntop (AF_INET6, &a6, tmp_out_buf, sizeof(tmp_out_buf)-1); - buf_printf (&out, "%s", tmp_out_buf ); + inet_ntop(AF_INET6, &a6, tmp_out_buf, sizeof(tmp_out_buf)-1); + buf_printf(&out, "%s", tmp_out_buf ); } - return BSTR (&out); + return BSTR(&out); } #ifndef UINT8_MAX -# define UINT8_MAX 0xff +#define UINT8_MAX 0xff #endif /* add some offset to an ipv6 address * (add in steps of 8 bits, taking overflow into next round) */ -struct in6_addr add_in6_addr( struct in6_addr base, uint32_t add ) +struct in6_addr +add_in6_addr( struct in6_addr base, uint32_t add ) { int i; - for( i=15; i>=0 && add > 0 ; i-- ) + for (i = 15; i>=0 && add > 0; i--) { - register int carry; - register uint32_t h; + register int carry; + register uint32_t h; - h = (unsigned char) base.s6_addr[i]; - base.s6_addr[i] = (h+add) & UINT8_MAX; + h = (unsigned char) base.s6_addr[i]; + base.s6_addr[i] = (h+add) & UINT8_MAX; - /* using explicit carry for the 8-bit additions will catch + /* using explicit carry for the 8-bit additions will catch * 8-bit and(!) 32-bit overruns nicely */ - carry = ((h & 0xff) + (add & 0xff)) >> 8; - add = (add>>8) + carry; + carry = ((h & 0xff) + (add & 0xff)) >> 8; + add = (add>>8) + carry; } return base; } /* set environmental variables for ip/port in *addr */ void -setenv_sockaddr (struct env_set *es, const char *name_prefix, const struct openvpn_sockaddr *addr, const unsigned int flags) -{ - char name_buf[256]; - - char buf[128]; - switch(addr->addr.sa.sa_family) - { - case AF_INET: - if (flags & SA_IP_PORT) - openvpn_snprintf (name_buf, sizeof (name_buf), "%s_ip", name_prefix); - else - openvpn_snprintf (name_buf, sizeof (name_buf), "%s", name_prefix); - - setenv_str (es, name_buf, inet_ntoa (addr->addr.in4.sin_addr)); - - if ((flags & SA_IP_PORT) && addr->addr.in4.sin_port) - { - openvpn_snprintf (name_buf, sizeof (name_buf), "%s_port", name_prefix); - setenv_int (es, name_buf, ntohs (addr->addr.in4.sin_port)); - } - break; - case AF_INET6: - if ( IN6_IS_ADDR_V4MAPPED( &addr->addr.in6.sin6_addr )) - { - struct in_addr ia; - memcpy (&ia.s_addr, &addr->addr.in6.sin6_addr.s6_addr[12], - sizeof (ia.s_addr)); - openvpn_snprintf (name_buf, sizeof (name_buf), "%s_ip", name_prefix); - openvpn_snprintf (buf, sizeof(buf), "%s", inet_ntoa(ia) ); - } - else - { - openvpn_snprintf (name_buf, sizeof (name_buf), "%s_ip6", name_prefix); - getnameinfo(&addr->addr.sa, sizeof (struct sockaddr_in6), - buf, sizeof(buf), NULL, 0, NI_NUMERICHOST); - } - setenv_str (es, name_buf, buf); - - if ((flags & SA_IP_PORT) && addr->addr.in6.sin6_port) - { - openvpn_snprintf (name_buf, sizeof (name_buf), "%s_port", name_prefix); - setenv_int (es, name_buf, ntohs (addr->addr.in6.sin6_port)); - } - break; +setenv_sockaddr(struct env_set *es, const char *name_prefix, const struct openvpn_sockaddr *addr, const unsigned int flags) +{ + char name_buf[256]; + + char buf[128]; + switch (addr->addr.sa.sa_family) + { + case AF_INET: + if (flags & SA_IP_PORT) + { + openvpn_snprintf(name_buf, sizeof(name_buf), "%s_ip", name_prefix); + } + else + { + openvpn_snprintf(name_buf, sizeof(name_buf), "%s", name_prefix); + } + + setenv_str(es, name_buf, inet_ntoa(addr->addr.in4.sin_addr)); + + if ((flags & SA_IP_PORT) && addr->addr.in4.sin_port) + { + openvpn_snprintf(name_buf, sizeof(name_buf), "%s_port", name_prefix); + setenv_int(es, name_buf, ntohs(addr->addr.in4.sin_port)); + } + break; + + case AF_INET6: + if (IN6_IS_ADDR_V4MAPPED( &addr->addr.in6.sin6_addr )) + { + struct in_addr ia; + memcpy(&ia.s_addr, &addr->addr.in6.sin6_addr.s6_addr[12], + sizeof(ia.s_addr)); + openvpn_snprintf(name_buf, sizeof(name_buf), "%s_ip", name_prefix); + openvpn_snprintf(buf, sizeof(buf), "%s", inet_ntoa(ia) ); + } + else + { + openvpn_snprintf(name_buf, sizeof(name_buf), "%s_ip6", name_prefix); + getnameinfo(&addr->addr.sa, sizeof(struct sockaddr_in6), + buf, sizeof(buf), NULL, 0, NI_NUMERICHOST); + } + setenv_str(es, name_buf, buf); + + if ((flags & SA_IP_PORT) && addr->addr.in6.sin6_port) + { + openvpn_snprintf(name_buf, sizeof(name_buf), "%s_port", name_prefix); + setenv_int(es, name_buf, ntohs(addr->addr.in6.sin6_port)); + } + break; } } void -setenv_in_addr_t (struct env_set *es, const char *name_prefix, in_addr_t addr, const unsigned int flags) +setenv_in_addr_t(struct env_set *es, const char *name_prefix, in_addr_t addr, const unsigned int flags) { - if (addr || !(flags & SA_SET_IF_NONZERO)) + if (addr || !(flags & SA_SET_IF_NONZERO)) { - struct openvpn_sockaddr si; - CLEAR (si); - si.addr.in4.sin_family = AF_INET; - si.addr.in4.sin_addr.s_addr = htonl (addr); - setenv_sockaddr (es, name_prefix, &si, flags); + struct openvpn_sockaddr si; + CLEAR(si); + si.addr.in4.sin_family = AF_INET; + si.addr.in4.sin_addr.s_addr = htonl(addr); + setenv_sockaddr(es, name_prefix, &si, flags); } } void -setenv_in6_addr (struct env_set *es, - const char *name_prefix, - const struct in6_addr *addr, - const unsigned int flags) +setenv_in6_addr(struct env_set *es, + const char *name_prefix, + const struct in6_addr *addr, + const unsigned int flags) { - if (!IN6_IS_ADDR_UNSPECIFIED (addr) || !(flags & SA_SET_IF_NONZERO)) + if (!IN6_IS_ADDR_UNSPECIFIED(addr) || !(flags & SA_SET_IF_NONZERO)) { - struct openvpn_sockaddr si; - CLEAR (si); - si.addr.in6.sin6_family = AF_INET6; - si.addr.in6.sin6_addr = *addr; - setenv_sockaddr (es, name_prefix, &si, flags); + struct openvpn_sockaddr si; + CLEAR(si); + si.addr.in6.sin6_family = AF_INET6; + si.addr.in6.sin6_addr = *addr; + setenv_sockaddr(es, name_prefix, &si, flags); } } void -setenv_link_socket_actual (struct env_set *es, - const char *name_prefix, - const struct link_socket_actual *act, - const unsigned int flags) +setenv_link_socket_actual(struct env_set *es, + const char *name_prefix, + const struct link_socket_actual *act, + const unsigned int flags) { - setenv_sockaddr (es, name_prefix, &act->dest, flags); + setenv_sockaddr(es, name_prefix, &act->dest, flags); } /* @@ -2673,37 +2987,39 @@ setenv_link_socket_actual (struct env_set *es, */ struct proto_names { - const char *short_form; - const char *display_form; - sa_family_t proto_af; - int proto; + const char *short_form; + const char *display_form; + sa_family_t proto_af; + int proto; }; /* Indexed by PROTO_x */ static const struct proto_names proto_names[] = { - {"proto-uninitialized", "proto-NONE", AF_UNSPEC, PROTO_NONE}, - /* try IPv4 and IPv6 (client), bind dual-stack (server) */ - {"udp", "UDP", AF_UNSPEC, PROTO_UDP}, - {"tcp-server", "TCP_SERVER", AF_UNSPEC, PROTO_TCP_SERVER}, - {"tcp-client", "TCP_CLIENT", AF_UNSPEC, PROTO_TCP_CLIENT}, - {"tcp", "TCP", AF_UNSPEC, PROTO_TCP}, - /* force IPv4 */ - {"udp4", "UDPv4", AF_INET, PROTO_UDP}, - {"tcp4-server","TCPv4_SERVER", AF_INET, PROTO_TCP_SERVER}, - {"tcp4-client","TCPv4_CLIENT", AF_INET, PROTO_TCP_CLIENT}, - {"tcp4", "TCPv4", AF_INET, PROTO_TCP}, - /* force IPv6 */ - {"udp6" ,"UDPv6", AF_INET6, PROTO_UDP}, - {"tcp6-server","TCPv6_SERVER", AF_INET6, PROTO_TCP_SERVER}, - {"tcp6-client","TCPv6_CLIENT", AF_INET6, PROTO_TCP_CLIENT}, - {"tcp6" ,"TCPv6", AF_INET6, PROTO_TCP}, + {"proto-uninitialized", "proto-NONE", AF_UNSPEC, PROTO_NONE}, + /* try IPv4 and IPv6 (client), bind dual-stack (server) */ + {"udp", "UDP", AF_UNSPEC, PROTO_UDP}, + {"tcp-server", "TCP_SERVER", AF_UNSPEC, PROTO_TCP_SERVER}, + {"tcp-client", "TCP_CLIENT", AF_UNSPEC, PROTO_TCP_CLIENT}, + {"tcp", "TCP", AF_UNSPEC, PROTO_TCP}, + /* force IPv4 */ + {"udp4", "UDPv4", AF_INET, PROTO_UDP}, + {"tcp4-server","TCPv4_SERVER", AF_INET, PROTO_TCP_SERVER}, + {"tcp4-client","TCPv4_CLIENT", AF_INET, PROTO_TCP_CLIENT}, + {"tcp4", "TCPv4", AF_INET, PROTO_TCP}, + /* force IPv6 */ + {"udp6","UDPv6", AF_INET6, PROTO_UDP}, + {"tcp6-server","TCPv6_SERVER", AF_INET6, PROTO_TCP_SERVER}, + {"tcp6-client","TCPv6_CLIENT", AF_INET6, PROTO_TCP_CLIENT}, + {"tcp6","TCPv6", AF_INET6, PROTO_TCP}, }; bool proto_is_net(int proto) { - if (proto < 0 || proto >= PROTO_N) - ASSERT(0); + if (proto < 0 || proto >= PROTO_N) + { + ASSERT(0); + } return proto != PROTO_NONE; } bool @@ -2715,81 +3031,96 @@ proto_is_dgram(int proto) bool proto_is_udp(int proto) { - if (proto < 0 || proto >= PROTO_N) - ASSERT(0); - return proto == PROTO_UDP; + if (proto < 0 || proto >= PROTO_N) + { + ASSERT(0); + } + return proto == PROTO_UDP; } bool proto_is_tcp(int proto) { - if (proto < 0 || proto >= PROTO_N) - ASSERT(0); - return proto == PROTO_TCP_CLIENT || proto == PROTO_TCP_SERVER; + if (proto < 0 || proto >= PROTO_N) + { + ASSERT(0); + } + return proto == PROTO_TCP_CLIENT || proto == PROTO_TCP_SERVER; } int -ascii2proto (const char* proto_name) +ascii2proto(const char *proto_name) { - int i; - for (i = 0; i < SIZE (proto_names); ++i) - if (!strcmp (proto_name, proto_names[i].short_form)) - return proto_names[i].proto; - return -1; + int i; + for (i = 0; i < SIZE(proto_names); ++i) + if (!strcmp(proto_name, proto_names[i].short_form)) + { + return proto_names[i].proto; + } + return -1; } sa_family_t -ascii2af (const char* proto_name) +ascii2af(const char *proto_name) { int i; - for (i = 0; i < SIZE (proto_names); ++i) - if (!strcmp (proto_name, proto_names[i].short_form)) + for (i = 0; i < SIZE(proto_names); ++i) + if (!strcmp(proto_name, proto_names[i].short_form)) + { return proto_names[i].proto_af; + } return 0; } const char * -proto2ascii (int proto, sa_family_t af, bool display_form) +proto2ascii(int proto, sa_family_t af, bool display_form) { - unsigned int i; - for (i = 0; i < SIZE (proto_names); ++i) + unsigned int i; + for (i = 0; i < SIZE(proto_names); ++i) { - if(proto_names[i].proto_af == af && proto_names[i].proto == proto) + if (proto_names[i].proto_af == af && proto_names[i].proto == proto) { - if(display_form) - return proto_names[i].display_form; - else - return proto_names[i].short_form; + if (display_form) + { + return proto_names[i].display_form; + } + else + { + return proto_names[i].short_form; + } } } - return "[unknown protocol]"; + return "[unknown protocol]"; } const char * -proto2ascii_all (struct gc_arena *gc) +proto2ascii_all(struct gc_arena *gc) { - struct buffer out = alloc_buf_gc (256, gc); - int i; + struct buffer out = alloc_buf_gc(256, gc); + int i; - for (i = 0; i < SIZE (proto_names); ++i) + for (i = 0; i < SIZE(proto_names); ++i) { - if (i) - buf_printf(&out, " "); - buf_printf(&out, "[%s]", proto_names[i].short_form); + if (i) + { + buf_printf(&out, " "); + } + buf_printf(&out, "[%s]", proto_names[i].short_form); } - return BSTR (&out); + return BSTR(&out); } const char * -addr_family_name (int af) +addr_family_name(int af) { - switch (af) + switch (af) { - case AF_INET: return "AF_INET"; - case AF_INET6: return "AF_INET6"; + case AF_INET: return "AF_INET"; + + case AF_INET6: return "AF_INET6"; } - return "AF_UNSPEC"; + return "AF_UNSPEC"; } /* @@ -2804,22 +3135,28 @@ addr_family_name (int af) * has always sent UDPv4, TCPv4 over the wire. Keep these * strings for backward compatbility */ -const char* -proto_remote (int proto, bool remote) +const char * +proto_remote(int proto, bool remote) { - ASSERT (proto >= 0 && proto < PROTO_N); - if (proto == PROTO_UDP) - return "UDPv4"; + ASSERT(proto >= 0 && proto < PROTO_N); + if (proto == PROTO_UDP) + { + return "UDPv4"; + } - if ( (remote && proto == PROTO_TCP_CLIENT) || - (!remote && proto == PROTO_TCP_SERVER)) - return "TCPv4_SERVER"; - if ( (remote && proto == PROTO_TCP_SERVER) || - (!remote && proto == PROTO_TCP_CLIENT)) - return "TCPv4_CLIENT"; + if ( (remote && proto == PROTO_TCP_CLIENT) + || (!remote && proto == PROTO_TCP_SERVER)) + { + return "TCPv4_SERVER"; + } + if ( (remote && proto == PROTO_TCP_SERVER) + || (!remote && proto == PROTO_TCP_CLIENT)) + { + return "TCPv4_CLIENT"; + } - ASSERT (0); - return ""; /* Make the compiler happy */ + ASSERT(0); + return ""; /* Make the compiler happy */ } /* @@ -2827,11 +3164,11 @@ proto_remote (int proto, bool remote) * we expect are considered to be fatal errors. */ void -bad_address_length (int actual, int expected) +bad_address_length(int actual, int expected) { - msg (M_FATAL, "ERROR: received strange incoming packet with an address length of %d -- we only accept address lengths of %d.", - actual, - expected); + msg(M_FATAL, "ERROR: received strange incoming packet with an address length of %d -- we only accept address lengths of %d.", + actual, + expected); } /* @@ -2839,36 +3176,42 @@ bad_address_length (int actual, int expected) */ int -link_socket_read_tcp (struct link_socket *sock, - struct buffer *buf) +link_socket_read_tcp(struct link_socket *sock, + struct buffer *buf) { - int len = 0; + int len = 0; - if (!sock->stream_buf.residual_fully_formed) + if (!sock->stream_buf.residual_fully_formed) { #ifdef _WIN32 - len = socket_finalize (sock->sd, &sock->reads, buf, NULL); + len = socket_finalize(sock->sd, &sock->reads, buf, NULL); #else - struct buffer frag; - stream_buf_get_next (&sock->stream_buf, &frag); - len = recv (sock->sd, BPTR (&frag), BLEN (&frag), MSG_NOSIGNAL); + struct buffer frag; + stream_buf_get_next(&sock->stream_buf, &frag); + len = recv(sock->sd, BPTR(&frag), BLEN(&frag), MSG_NOSIGNAL); #endif - if (!len) - sock->stream_reset = true; - if (len <= 0) - return buf->len = len; + if (!len) + { + sock->stream_reset = true; + } + if (len <= 0) + { + return buf->len = len; + } } - if (sock->stream_buf.residual_fully_formed - || stream_buf_added (&sock->stream_buf, len)) /* packet complete? */ + if (sock->stream_buf.residual_fully_formed + || stream_buf_added(&sock->stream_buf, len)) /* packet complete? */ + { + stream_buf_get_final(&sock->stream_buf, buf); + stream_buf_reset(&sock->stream_buf); + return buf->len; + } + else { - stream_buf_get_final (&sock->stream_buf, buf); - stream_buf_reset (&sock->stream_buf); - return buf->len; + return buf->len = 0; /* no error, but packet is still incomplete */ } - else - return buf->len = 0; /* no error, but packet is still incomplete */ } #ifndef _WIN32 @@ -2879,202 +3222,208 @@ link_socket_read_tcp (struct link_socket *sock, * both IPv4 and IPv6 destination addresses, plus padding (see RFC 2292) */ #if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) -#define PKTINFO_BUF_SIZE max_int( CMSG_SPACE(sizeof (struct in6_pktinfo)), \ - CMSG_SPACE(sizeof (struct in_pktinfo)) ) +#define PKTINFO_BUF_SIZE max_int( CMSG_SPACE(sizeof(struct in6_pktinfo)), \ + CMSG_SPACE(sizeof(struct in_pktinfo)) ) #else -#define PKTINFO_BUF_SIZE max_int( CMSG_SPACE(sizeof (struct in6_pktinfo)), \ - CMSG_SPACE(sizeof (struct in_addr)) ) +#define PKTINFO_BUF_SIZE max_int( CMSG_SPACE(sizeof(struct in6_pktinfo)), \ + CMSG_SPACE(sizeof(struct in_addr)) ) #endif static socklen_t -link_socket_read_udp_posix_recvmsg (struct link_socket *sock, - struct buffer *buf, - struct link_socket_actual *from) -{ - struct iovec iov; - uint8_t pktinfo_buf[PKTINFO_BUF_SIZE]; - struct msghdr mesg; - socklen_t fromlen = sizeof (from->dest.addr); - - iov.iov_base = BPTR (buf); - iov.iov_len = buf_forward_capacity_total (buf); - mesg.msg_iov = &iov; - mesg.msg_iovlen = 1; - mesg.msg_name = &from->dest.addr; - mesg.msg_namelen = fromlen; - mesg.msg_control = pktinfo_buf; - mesg.msg_controllen = sizeof pktinfo_buf; - buf->len = recvmsg (sock->sd, &mesg, 0); - if (buf->len >= 0) - { - struct cmsghdr *cmsg; - fromlen = mesg.msg_namelen; - cmsg = CMSG_FIRSTHDR (&mesg); - if (cmsg != NULL - && CMSG_NXTHDR (&mesg, cmsg) == NULL +link_socket_read_udp_posix_recvmsg(struct link_socket *sock, + struct buffer *buf, + struct link_socket_actual *from) +{ + struct iovec iov; + uint8_t pktinfo_buf[PKTINFO_BUF_SIZE]; + struct msghdr mesg; + socklen_t fromlen = sizeof(from->dest.addr); + + iov.iov_base = BPTR(buf); + iov.iov_len = buf_forward_capacity_total(buf); + mesg.msg_iov = &iov; + mesg.msg_iovlen = 1; + mesg.msg_name = &from->dest.addr; + mesg.msg_namelen = fromlen; + mesg.msg_control = pktinfo_buf; + mesg.msg_controllen = sizeof pktinfo_buf; + buf->len = recvmsg(sock->sd, &mesg, 0); + if (buf->len >= 0) + { + struct cmsghdr *cmsg; + fromlen = mesg.msg_namelen; + cmsg = CMSG_FIRSTHDR(&mesg); + if (cmsg != NULL + && CMSG_NXTHDR(&mesg, cmsg) == NULL #if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) - && cmsg->cmsg_level == SOL_IP - && cmsg->cmsg_type == IP_PKTINFO - && cmsg->cmsg_len >= CMSG_LEN(sizeof(struct in_pktinfo)) ) + && cmsg->cmsg_level == SOL_IP + && cmsg->cmsg_type == IP_PKTINFO + && cmsg->cmsg_len >= CMSG_LEN(sizeof(struct in_pktinfo)) ) #elif defined(IP_RECVDSTADDR) - && cmsg->cmsg_level == IPPROTO_IP - && cmsg->cmsg_type == IP_RECVDSTADDR - && cmsg->cmsg_len >= CMSG_LEN(sizeof(struct in_addr)) ) -#else + && cmsg->cmsg_level == IPPROTO_IP + && cmsg->cmsg_type == IP_RECVDSTADDR + && cmsg->cmsg_len >= CMSG_LEN(sizeof(struct in_addr)) ) +#else /* if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) */ #error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h) #endif - { + { #if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) - struct in_pktinfo *pkti = (struct in_pktinfo *) CMSG_DATA (cmsg); - from->pi.in4.ipi_ifindex = pkti->ipi_ifindex; - from->pi.in4.ipi_spec_dst = pkti->ipi_spec_dst; + struct in_pktinfo *pkti = (struct in_pktinfo *) CMSG_DATA(cmsg); + from->pi.in4.ipi_ifindex = pkti->ipi_ifindex; + from->pi.in4.ipi_spec_dst = pkti->ipi_spec_dst; #elif defined(IP_RECVDSTADDR) - from->pi.in4 = *(struct in_addr*) CMSG_DATA (cmsg); -#else + from->pi.in4 = *(struct in_addr *) CMSG_DATA(cmsg); +#else /* if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) */ #error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h) #endif - } - else if (cmsg != NULL - && CMSG_NXTHDR (&mesg, cmsg) == NULL - && cmsg->cmsg_level == IPPROTO_IPV6 - && cmsg->cmsg_type == IPV6_PKTINFO - && cmsg->cmsg_len >= CMSG_LEN(sizeof(struct in6_pktinfo)) ) - { - struct in6_pktinfo *pkti6 = (struct in6_pktinfo *) CMSG_DATA (cmsg); - from->pi.in6.ipi6_ifindex = pkti6->ipi6_ifindex; - from->pi.in6.ipi6_addr = pkti6->ipi6_addr; - } - else if (cmsg != NULL) - { - msg(M_WARN, "CMSG received that cannot be parsed (cmsg_level=%d, cmsg_type=%d, cmsg=len=%d)", (int)cmsg->cmsg_level, (int)cmsg->cmsg_type, (int)cmsg->cmsg_len ); - } - } - - return fromlen; + } + else if (cmsg != NULL + && CMSG_NXTHDR(&mesg, cmsg) == NULL + && cmsg->cmsg_level == IPPROTO_IPV6 + && cmsg->cmsg_type == IPV6_PKTINFO + && cmsg->cmsg_len >= CMSG_LEN(sizeof(struct in6_pktinfo)) ) + { + struct in6_pktinfo *pkti6 = (struct in6_pktinfo *) CMSG_DATA(cmsg); + from->pi.in6.ipi6_ifindex = pkti6->ipi6_ifindex; + from->pi.in6.ipi6_addr = pkti6->ipi6_addr; + } + else if (cmsg != NULL) + { + msg(M_WARN, "CMSG received that cannot be parsed (cmsg_level=%d, cmsg_type=%d, cmsg=len=%d)", (int)cmsg->cmsg_level, (int)cmsg->cmsg_type, (int)cmsg->cmsg_len ); + } + } + + return fromlen; } -#endif +#endif /* if ENABLE_IP_PKTINFO */ int -link_socket_read_udp_posix (struct link_socket *sock, - struct buffer *buf, - struct link_socket_actual *from) +link_socket_read_udp_posix(struct link_socket *sock, + struct buffer *buf, + struct link_socket_actual *from) { - socklen_t fromlen = sizeof (from->dest.addr); - socklen_t expectedlen = af_addr_size(sock->info.af); - addr_zero_host(&from->dest); + socklen_t fromlen = sizeof(from->dest.addr); + socklen_t expectedlen = af_addr_size(sock->info.af); + addr_zero_host(&from->dest); #if ENABLE_IP_PKTINFO - /* Both PROTO_UDPv4 and PROTO_UDPv6 */ - if (sock->info.proto == PROTO_UDP && sock->sockflags & SF_USE_IP_PKTINFO) - fromlen = link_socket_read_udp_posix_recvmsg (sock, buf, from); - else + /* Both PROTO_UDPv4 and PROTO_UDPv6 */ + if (sock->info.proto == PROTO_UDP && sock->sockflags & SF_USE_IP_PKTINFO) + { + fromlen = link_socket_read_udp_posix_recvmsg(sock, buf, from); + } + else #endif - buf->len = recvfrom (sock->sd, BPTR (buf), buf_forward_capacity(buf), 0, - &from->dest.addr.sa, &fromlen); - /* FIXME: won't do anything when sock->info.af == AF_UNSPEC */ - if (buf->len >= 0 && expectedlen && fromlen != expectedlen) - bad_address_length (fromlen, expectedlen); - return buf->len; + buf->len = recvfrom(sock->sd, BPTR(buf), buf_forward_capacity(buf), 0, + &from->dest.addr.sa, &fromlen); + /* FIXME: won't do anything when sock->info.af == AF_UNSPEC */ + if (buf->len >= 0 && expectedlen && fromlen != expectedlen) + { + bad_address_length(fromlen, expectedlen); + } + return buf->len; } -#endif +#endif /* ifndef _WIN32 */ /* * Socket Write Routines */ int -link_socket_write_tcp (struct link_socket *sock, - struct buffer *buf, - struct link_socket_actual *to) -{ - packet_size_type len = BLEN (buf); - dmsg (D_STREAM_DEBUG, "STREAM: WRITE %d offset=%d", (int)len, buf->offset); - ASSERT (len <= sock->stream_buf.maxlen); - len = htonps (len); - ASSERT (buf_write_prepend (buf, &len, sizeof (len))); +link_socket_write_tcp(struct link_socket *sock, + struct buffer *buf, + struct link_socket_actual *to) +{ + packet_size_type len = BLEN(buf); + dmsg(D_STREAM_DEBUG, "STREAM: WRITE %d offset=%d", (int)len, buf->offset); + ASSERT(len <= sock->stream_buf.maxlen); + len = htonps(len); + ASSERT(buf_write_prepend(buf, &len, sizeof(len))); #ifdef _WIN32 - return link_socket_write_win32 (sock, buf, to); + return link_socket_write_win32(sock, buf, to); #else - return link_socket_write_tcp_posix (sock, buf, to); + return link_socket_write_tcp_posix(sock, buf, to); #endif } #if ENABLE_IP_PKTINFO size_t -link_socket_write_udp_posix_sendmsg (struct link_socket *sock, - struct buffer *buf, - struct link_socket_actual *to) -{ - struct iovec iov; - struct msghdr mesg; - struct cmsghdr *cmsg; - uint8_t pktinfo_buf[PKTINFO_BUF_SIZE]; - - iov.iov_base = BPTR (buf); - iov.iov_len = BLEN (buf); - mesg.msg_iov = &iov; - mesg.msg_iovlen = 1; - switch (to->dest.addr.sa.sa_family) - { - case AF_INET: - { - mesg.msg_name = &to->dest.addr.sa; - mesg.msg_namelen = sizeof (struct sockaddr_in); - mesg.msg_control = pktinfo_buf; - mesg.msg_flags = 0; +link_socket_write_udp_posix_sendmsg(struct link_socket *sock, + struct buffer *buf, + struct link_socket_actual *to) +{ + struct iovec iov; + struct msghdr mesg; + struct cmsghdr *cmsg; + uint8_t pktinfo_buf[PKTINFO_BUF_SIZE]; + + iov.iov_base = BPTR(buf); + iov.iov_len = BLEN(buf); + mesg.msg_iov = &iov; + mesg.msg_iovlen = 1; + switch (to->dest.addr.sa.sa_family) + { + case AF_INET: + { + mesg.msg_name = &to->dest.addr.sa; + mesg.msg_namelen = sizeof(struct sockaddr_in); + mesg.msg_control = pktinfo_buf; + mesg.msg_flags = 0; #if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) - mesg.msg_controllen = CMSG_SPACE(sizeof (struct in_pktinfo)); - cmsg = CMSG_FIRSTHDR (&mesg); - cmsg->cmsg_len = CMSG_LEN(sizeof (struct in_pktinfo)); - cmsg->cmsg_level = SOL_IP; - cmsg->cmsg_type = IP_PKTINFO; - { - struct in_pktinfo *pkti; - pkti = (struct in_pktinfo *) CMSG_DATA (cmsg); - pkti->ipi_ifindex = to->pi.in4.ipi_ifindex; - pkti->ipi_spec_dst = to->pi.in4.ipi_spec_dst; - pkti->ipi_addr.s_addr = 0; - } + mesg.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo)); + cmsg = CMSG_FIRSTHDR(&mesg); + cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); + cmsg->cmsg_level = SOL_IP; + cmsg->cmsg_type = IP_PKTINFO; + { + struct in_pktinfo *pkti; + pkti = (struct in_pktinfo *) CMSG_DATA(cmsg); + pkti->ipi_ifindex = to->pi.in4.ipi_ifindex; + pkti->ipi_spec_dst = to->pi.in4.ipi_spec_dst; + pkti->ipi_addr.s_addr = 0; + } #elif defined(IP_RECVDSTADDR) - ASSERT( CMSG_SPACE(sizeof (struct in_addr)) <= sizeof(pktinfo_buf) ); - mesg.msg_controllen = CMSG_SPACE(sizeof (struct in_addr)); - cmsg = CMSG_FIRSTHDR (&mesg); - cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr)); - cmsg->cmsg_level = IPPROTO_IP; - cmsg->cmsg_type = IP_RECVDSTADDR; - *(struct in_addr *) CMSG_DATA (cmsg) = to->pi.in4; -#else + ASSERT( CMSG_SPACE(sizeof(struct in_addr)) <= sizeof(pktinfo_buf) ); + mesg.msg_controllen = CMSG_SPACE(sizeof(struct in_addr)); + cmsg = CMSG_FIRSTHDR(&mesg); + cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr)); + cmsg->cmsg_level = IPPROTO_IP; + cmsg->cmsg_type = IP_RECVDSTADDR; + *(struct in_addr *) CMSG_DATA(cmsg) = to->pi.in4; +#else /* if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) */ #error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h) -#endif - break; - } - case AF_INET6: - { - struct in6_pktinfo *pkti6; - mesg.msg_name = &to->dest.addr.sa; - mesg.msg_namelen = sizeof (struct sockaddr_in6); - - ASSERT( CMSG_SPACE(sizeof (struct in6_pktinfo)) <= sizeof(pktinfo_buf) ); - mesg.msg_control = pktinfo_buf; - mesg.msg_controllen = CMSG_SPACE(sizeof (struct in6_pktinfo)); - mesg.msg_flags = 0; - cmsg = CMSG_FIRSTHDR (&mesg); - cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); - cmsg->cmsg_level = IPPROTO_IPV6; - cmsg->cmsg_type = IPV6_PKTINFO; - - pkti6 = (struct in6_pktinfo *) CMSG_DATA (cmsg); - pkti6->ipi6_ifindex = to->pi.in6.ipi6_ifindex; - pkti6->ipi6_addr = to->pi.in6.ipi6_addr; - break; - } - default: ASSERT(0); - } - return sendmsg (sock->sd, &mesg, 0); +#endif /* if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) */ + break; + } + + case AF_INET6: + { + struct in6_pktinfo *pkti6; + mesg.msg_name = &to->dest.addr.sa; + mesg.msg_namelen = sizeof(struct sockaddr_in6); + + ASSERT( CMSG_SPACE(sizeof(struct in6_pktinfo)) <= sizeof(pktinfo_buf) ); + mesg.msg_control = pktinfo_buf; + mesg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)); + mesg.msg_flags = 0; + cmsg = CMSG_FIRSTHDR(&mesg); + cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); + cmsg->cmsg_level = IPPROTO_IPV6; + cmsg->cmsg_type = IPV6_PKTINFO; + + pkti6 = (struct in6_pktinfo *) CMSG_DATA(cmsg); + pkti6->ipi6_ifindex = to->pi.in6.ipi6_ifindex; + pkti6->ipi6_addr = to->pi.in6.ipi6_addr; + break; + } + + default: ASSERT(0); + } + return sendmsg(sock->sd, &mesg, 0); } -#endif +#endif /* if ENABLE_IP_PKTINFO */ /* * Win32 overlapped socket I/O functions. @@ -3083,335 +3432,347 @@ link_socket_write_udp_posix_sendmsg (struct link_socket *sock, #ifdef _WIN32 int -socket_recv_queue (struct link_socket *sock, int maxsize) -{ - if (sock->reads.iostate == IOSTATE_INITIAL) - { - WSABUF wsabuf[1]; - int status; - - /* reset buf to its initial state */ - if (proto_is_udp(sock->info.proto)) - { - sock->reads.buf = sock->reads.buf_init; - } - else if (proto_is_tcp(sock->info.proto)) - { - stream_buf_get_next (&sock->stream_buf, &sock->reads.buf); - } - else - { - ASSERT (0); - } - - /* Win32 docs say it's okay to allocate the wsabuf on the stack */ - wsabuf[0].buf = BPTR (&sock->reads.buf); - wsabuf[0].len = maxsize ? maxsize : BLEN (&sock->reads.buf); - - /* check for buffer overflow */ - ASSERT (wsabuf[0].len <= BLEN (&sock->reads.buf)); - - /* the overlapped read will signal this event on I/O completion */ - ASSERT (ResetEvent (sock->reads.overlapped.hEvent)); - sock->reads.flags = 0; - - if (proto_is_udp(sock->info.proto)) - { - sock->reads.addr_defined = true; - sock->reads.addrlen = sizeof (sock->reads.addr6); - status = WSARecvFrom( - sock->sd, - wsabuf, - 1, - &sock->reads.size, - &sock->reads.flags, - (struct sockaddr *) &sock->reads.addr, - &sock->reads.addrlen, - &sock->reads.overlapped, - NULL); - } - else if (proto_is_tcp(sock->info.proto)) - { - sock->reads.addr_defined = false; - status = WSARecv( - sock->sd, - wsabuf, - 1, - &sock->reads.size, - &sock->reads.flags, - &sock->reads.overlapped, - NULL); - } - else - { - status = 0; - ASSERT (0); - } - - if (!status) /* operation completed immediately? */ - { - /* FIXME: won't do anything when sock->info.af == AF_UNSPEC */ - int af_len = af_addr_size (sock->info.af); - if (sock->reads.addr_defined && af_len && sock->reads.addrlen != af_len) - bad_address_length (sock->reads.addrlen, af_len); - sock->reads.iostate = IOSTATE_IMMEDIATE_RETURN; - - /* since we got an immediate return, we must signal the event object ourselves */ - ASSERT (SetEvent (sock->reads.overlapped.hEvent)); - sock->reads.status = 0; - - dmsg (D_WIN32_IO, "WIN32 I/O: Socket Receive immediate return [%d,%d]", - (int) wsabuf[0].len, - (int) sock->reads.size); - } - else - { - status = WSAGetLastError (); - if (status == WSA_IO_PENDING) /* operation queued? */ - { - sock->reads.iostate = IOSTATE_QUEUED; - sock->reads.status = status; - dmsg (D_WIN32_IO, "WIN32 I/O: Socket Receive queued [%d]", - (int) wsabuf[0].len); - } - else /* error occurred */ - { - struct gc_arena gc = gc_new (); - ASSERT (SetEvent (sock->reads.overlapped.hEvent)); - sock->reads.iostate = IOSTATE_IMMEDIATE_RETURN; - sock->reads.status = status; - dmsg (D_WIN32_IO, "WIN32 I/O: Socket Receive error [%d]: %s", - (int) wsabuf[0].len, - strerror_win32 (status, &gc)); - gc_free (&gc); - } - } - } - return sock->reads.iostate; +socket_recv_queue(struct link_socket *sock, int maxsize) +{ + if (sock->reads.iostate == IOSTATE_INITIAL) + { + WSABUF wsabuf[1]; + int status; + + /* reset buf to its initial state */ + if (proto_is_udp(sock->info.proto)) + { + sock->reads.buf = sock->reads.buf_init; + } + else if (proto_is_tcp(sock->info.proto)) + { + stream_buf_get_next(&sock->stream_buf, &sock->reads.buf); + } + else + { + ASSERT(0); + } + + /* Win32 docs say it's okay to allocate the wsabuf on the stack */ + wsabuf[0].buf = BPTR(&sock->reads.buf); + wsabuf[0].len = maxsize ? maxsize : BLEN(&sock->reads.buf); + + /* check for buffer overflow */ + ASSERT(wsabuf[0].len <= BLEN(&sock->reads.buf)); + + /* the overlapped read will signal this event on I/O completion */ + ASSERT(ResetEvent(sock->reads.overlapped.hEvent)); + sock->reads.flags = 0; + + if (proto_is_udp(sock->info.proto)) + { + sock->reads.addr_defined = true; + sock->reads.addrlen = sizeof(sock->reads.addr6); + status = WSARecvFrom( + sock->sd, + wsabuf, + 1, + &sock->reads.size, + &sock->reads.flags, + (struct sockaddr *) &sock->reads.addr, + &sock->reads.addrlen, + &sock->reads.overlapped, + NULL); + } + else if (proto_is_tcp(sock->info.proto)) + { + sock->reads.addr_defined = false; + status = WSARecv( + sock->sd, + wsabuf, + 1, + &sock->reads.size, + &sock->reads.flags, + &sock->reads.overlapped, + NULL); + } + else + { + status = 0; + ASSERT(0); + } + + if (!status) /* operation completed immediately? */ + { + /* FIXME: won't do anything when sock->info.af == AF_UNSPEC */ + int af_len = af_addr_size(sock->info.af); + if (sock->reads.addr_defined && af_len && sock->reads.addrlen != af_len) + { + bad_address_length(sock->reads.addrlen, af_len); + } + sock->reads.iostate = IOSTATE_IMMEDIATE_RETURN; + + /* since we got an immediate return, we must signal the event object ourselves */ + ASSERT(SetEvent(sock->reads.overlapped.hEvent)); + sock->reads.status = 0; + + dmsg(D_WIN32_IO, "WIN32 I/O: Socket Receive immediate return [%d,%d]", + (int) wsabuf[0].len, + (int) sock->reads.size); + } + else + { + status = WSAGetLastError(); + if (status == WSA_IO_PENDING) /* operation queued? */ + { + sock->reads.iostate = IOSTATE_QUEUED; + sock->reads.status = status; + dmsg(D_WIN32_IO, "WIN32 I/O: Socket Receive queued [%d]", + (int) wsabuf[0].len); + } + else /* error occurred */ + { + struct gc_arena gc = gc_new(); + ASSERT(SetEvent(sock->reads.overlapped.hEvent)); + sock->reads.iostate = IOSTATE_IMMEDIATE_RETURN; + sock->reads.status = status; + dmsg(D_WIN32_IO, "WIN32 I/O: Socket Receive error [%d]: %s", + (int) wsabuf[0].len, + strerror_win32(status, &gc)); + gc_free(&gc); + } + } + } + return sock->reads.iostate; } int -socket_send_queue (struct link_socket *sock, struct buffer *buf, const struct link_socket_actual *to) -{ - if (sock->writes.iostate == IOSTATE_INITIAL) - { - WSABUF wsabuf[1]; - int status; - - /* make a private copy of buf */ - sock->writes.buf = sock->writes.buf_init; - sock->writes.buf.len = 0; - ASSERT (buf_copy (&sock->writes.buf, buf)); - - /* Win32 docs say it's okay to allocate the wsabuf on the stack */ - wsabuf[0].buf = BPTR (&sock->writes.buf); - wsabuf[0].len = BLEN (&sock->writes.buf); - - /* the overlapped write will signal this event on I/O completion */ - ASSERT (ResetEvent (sock->writes.overlapped.hEvent)); - sock->writes.flags = 0; - - if (proto_is_udp(sock->info.proto)) - { - /* set destination address for UDP writes */ - sock->writes.addr_defined = true; - if (to->dest.addr.sa.sa_family == AF_INET6) - { - sock->writes.addr6 = to->dest.addr.in6; - sock->writes.addrlen = sizeof (sock->writes.addr6); - } - else - { - sock->writes.addr = to->dest.addr.in4; - sock->writes.addrlen = sizeof (sock->writes.addr); - } - - status = WSASendTo( - sock->sd, - wsabuf, - 1, - &sock->writes.size, - sock->writes.flags, - (struct sockaddr *) &sock->writes.addr, - sock->writes.addrlen, - &sock->writes.overlapped, - NULL); - } - else if (proto_is_tcp(sock->info.proto)) - { - /* destination address for TCP writes was established on connection initiation */ - sock->writes.addr_defined = false; - - status = WSASend( - sock->sd, - wsabuf, - 1, - &sock->writes.size, - sock->writes.flags, - &sock->writes.overlapped, - NULL); - } - else - { - status = 0; - ASSERT (0); - } - - if (!status) /* operation completed immediately? */ - { - sock->writes.iostate = IOSTATE_IMMEDIATE_RETURN; - - /* since we got an immediate return, we must signal the event object ourselves */ - ASSERT (SetEvent (sock->writes.overlapped.hEvent)); - - sock->writes.status = 0; - - dmsg (D_WIN32_IO, "WIN32 I/O: Socket Send immediate return [%d,%d]", - (int) wsabuf[0].len, - (int) sock->writes.size); - } - else - { - status = WSAGetLastError (); - if (status == WSA_IO_PENDING) /* operation queued? */ - { - sock->writes.iostate = IOSTATE_QUEUED; - sock->writes.status = status; - dmsg (D_WIN32_IO, "WIN32 I/O: Socket Send queued [%d]", - (int) wsabuf[0].len); - } - else /* error occurred */ - { - struct gc_arena gc = gc_new (); - ASSERT (SetEvent (sock->writes.overlapped.hEvent)); - sock->writes.iostate = IOSTATE_IMMEDIATE_RETURN; - sock->writes.status = status; - - dmsg (D_WIN32_IO, "WIN32 I/O: Socket Send error [%d]: %s", - (int) wsabuf[0].len, - strerror_win32 (status, &gc)); - - gc_free (&gc); - } - } - } - return sock->writes.iostate; +socket_send_queue(struct link_socket *sock, struct buffer *buf, const struct link_socket_actual *to) +{ + if (sock->writes.iostate == IOSTATE_INITIAL) + { + WSABUF wsabuf[1]; + int status; + + /* make a private copy of buf */ + sock->writes.buf = sock->writes.buf_init; + sock->writes.buf.len = 0; + ASSERT(buf_copy(&sock->writes.buf, buf)); + + /* Win32 docs say it's okay to allocate the wsabuf on the stack */ + wsabuf[0].buf = BPTR(&sock->writes.buf); + wsabuf[0].len = BLEN(&sock->writes.buf); + + /* the overlapped write will signal this event on I/O completion */ + ASSERT(ResetEvent(sock->writes.overlapped.hEvent)); + sock->writes.flags = 0; + + if (proto_is_udp(sock->info.proto)) + { + /* set destination address for UDP writes */ + sock->writes.addr_defined = true; + if (to->dest.addr.sa.sa_family == AF_INET6) + { + sock->writes.addr6 = to->dest.addr.in6; + sock->writes.addrlen = sizeof(sock->writes.addr6); + } + else + { + sock->writes.addr = to->dest.addr.in4; + sock->writes.addrlen = sizeof(sock->writes.addr); + } + + status = WSASendTo( + sock->sd, + wsabuf, + 1, + &sock->writes.size, + sock->writes.flags, + (struct sockaddr *) &sock->writes.addr, + sock->writes.addrlen, + &sock->writes.overlapped, + NULL); + } + else if (proto_is_tcp(sock->info.proto)) + { + /* destination address for TCP writes was established on connection initiation */ + sock->writes.addr_defined = false; + + status = WSASend( + sock->sd, + wsabuf, + 1, + &sock->writes.size, + sock->writes.flags, + &sock->writes.overlapped, + NULL); + } + else + { + status = 0; + ASSERT(0); + } + + if (!status) /* operation completed immediately? */ + { + sock->writes.iostate = IOSTATE_IMMEDIATE_RETURN; + + /* since we got an immediate return, we must signal the event object ourselves */ + ASSERT(SetEvent(sock->writes.overlapped.hEvent)); + + sock->writes.status = 0; + + dmsg(D_WIN32_IO, "WIN32 I/O: Socket Send immediate return [%d,%d]", + (int) wsabuf[0].len, + (int) sock->writes.size); + } + else + { + status = WSAGetLastError(); + if (status == WSA_IO_PENDING) /* operation queued? */ + { + sock->writes.iostate = IOSTATE_QUEUED; + sock->writes.status = status; + dmsg(D_WIN32_IO, "WIN32 I/O: Socket Send queued [%d]", + (int) wsabuf[0].len); + } + else /* error occurred */ + { + struct gc_arena gc = gc_new(); + ASSERT(SetEvent(sock->writes.overlapped.hEvent)); + sock->writes.iostate = IOSTATE_IMMEDIATE_RETURN; + sock->writes.status = status; + + dmsg(D_WIN32_IO, "WIN32 I/O: Socket Send error [%d]: %s", + (int) wsabuf[0].len, + strerror_win32(status, &gc)); + + gc_free(&gc); + } + } + } + return sock->writes.iostate; } int -socket_finalize (SOCKET s, - struct overlapped_io *io, - struct buffer *buf, - struct link_socket_actual *from) -{ - int ret = -1; - BOOL status; - - switch (io->iostate) - { - case IOSTATE_QUEUED: - status = WSAGetOverlappedResult( - s, - &io->overlapped, - &io->size, - FALSE, - &io->flags - ); - if (status) - { - /* successful return for a queued operation */ - if (buf) - *buf = io->buf; - ret = io->size; - io->iostate = IOSTATE_INITIAL; - ASSERT (ResetEvent (io->overlapped.hEvent)); - - dmsg (D_WIN32_IO, "WIN32 I/O: Socket Completion success [%d]", ret); - } - else - { - /* error during a queued operation */ - ret = -1; - if (WSAGetLastError() != WSA_IO_INCOMPLETE) - { - /* if no error (i.e. just not finished yet), then DON'T execute this code */ - io->iostate = IOSTATE_INITIAL; - ASSERT (ResetEvent (io->overlapped.hEvent)); - msg (D_WIN32_IO | M_ERRNO, "WIN32 I/O: Socket Completion error"); - } - } - break; - - case IOSTATE_IMMEDIATE_RETURN: - io->iostate = IOSTATE_INITIAL; - ASSERT (ResetEvent (io->overlapped.hEvent)); - if (io->status) - { - /* error return for a non-queued operation */ - WSASetLastError (io->status); - ret = -1; - msg (D_WIN32_IO | M_ERRNO, "WIN32 I/O: Socket Completion non-queued error"); - } - else - { - /* successful return for a non-queued operation */ - if (buf) - *buf = io->buf; - ret = io->size; - dmsg (D_WIN32_IO, "WIN32 I/O: Socket Completion non-queued success [%d]", ret); - } - break; - - case IOSTATE_INITIAL: /* were we called without proper queueing? */ - WSASetLastError (WSAEINVAL); - ret = -1; - dmsg (D_WIN32_IO, "WIN32 I/O: Socket Completion BAD STATE"); - break; - - default: - ASSERT (0); - } - - /* return from address if requested */ - if (from) - { - if (ret >= 0 && io->addr_defined) - { - /* TODO(jjo): streamline this mess */ - /* in this func we dont have relevant info about the PF_ of this - * endpoint, as link_socket_actual will be zero for the 1st received packet - * - * Test for inets PF_ possible sizes - */ - switch (io->addrlen) - { - case sizeof(struct sockaddr_in): - case sizeof(struct sockaddr_in6): - /* TODO(jjo): for some reason (?) I'm getting 24,28 for AF_INET6 - * under _WIN32*/ - case sizeof(struct sockaddr_in6)-4: - break; - default: - bad_address_length (io->addrlen, af_addr_size(io->addr.sin_family)); - } - - switch (io->addr.sin_family) - { - case AF_INET: - from->dest.addr.in4 = io->addr; - break; - case AF_INET6: - from->dest.addr.in6 = io->addr6; - break; - } - } - else - CLEAR (from->dest.addr); - } - - if (buf) - buf->len = ret; - return ret; +socket_finalize(SOCKET s, + struct overlapped_io *io, + struct buffer *buf, + struct link_socket_actual *from) +{ + int ret = -1; + BOOL status; + + switch (io->iostate) + { + case IOSTATE_QUEUED: + status = WSAGetOverlappedResult( + s, + &io->overlapped, + &io->size, + FALSE, + &io->flags + ); + if (status) + { + /* successful return for a queued operation */ + if (buf) + { + *buf = io->buf; + } + ret = io->size; + io->iostate = IOSTATE_INITIAL; + ASSERT(ResetEvent(io->overlapped.hEvent)); + + dmsg(D_WIN32_IO, "WIN32 I/O: Socket Completion success [%d]", ret); + } + else + { + /* error during a queued operation */ + ret = -1; + if (WSAGetLastError() != WSA_IO_INCOMPLETE) + { + /* if no error (i.e. just not finished yet), then DON'T execute this code */ + io->iostate = IOSTATE_INITIAL; + ASSERT(ResetEvent(io->overlapped.hEvent)); + msg(D_WIN32_IO | M_ERRNO, "WIN32 I/O: Socket Completion error"); + } + } + break; + + case IOSTATE_IMMEDIATE_RETURN: + io->iostate = IOSTATE_INITIAL; + ASSERT(ResetEvent(io->overlapped.hEvent)); + if (io->status) + { + /* error return for a non-queued operation */ + WSASetLastError(io->status); + ret = -1; + msg(D_WIN32_IO | M_ERRNO, "WIN32 I/O: Socket Completion non-queued error"); + } + else + { + /* successful return for a non-queued operation */ + if (buf) + { + *buf = io->buf; + } + ret = io->size; + dmsg(D_WIN32_IO, "WIN32 I/O: Socket Completion non-queued success [%d]", ret); + } + break; + + case IOSTATE_INITIAL: /* were we called without proper queueing? */ + WSASetLastError(WSAEINVAL); + ret = -1; + dmsg(D_WIN32_IO, "WIN32 I/O: Socket Completion BAD STATE"); + break; + + default: + ASSERT(0); + } + + /* return from address if requested */ + if (from) + { + if (ret >= 0 && io->addr_defined) + { + /* TODO(jjo): streamline this mess */ + /* in this func we dont have relevant info about the PF_ of this + * endpoint, as link_socket_actual will be zero for the 1st received packet + * + * Test for inets PF_ possible sizes + */ + switch (io->addrlen) + { + case sizeof(struct sockaddr_in): + case sizeof(struct sockaddr_in6): + /* TODO(jjo): for some reason (?) I'm getting 24,28 for AF_INET6 + * under _WIN32*/ + case sizeof(struct sockaddr_in6)-4: + break; + + default: + bad_address_length(io->addrlen, af_addr_size(io->addr.sin_family)); + } + + switch (io->addr.sin_family) + { + case AF_INET: + from->dest.addr.in4 = io->addr; + break; + + case AF_INET6: + from->dest.addr.in6 = io->addr6; + break; + } + } + else + { + CLEAR(from->dest.addr); + } + } + + if (buf) + { + buf->len = ret; + } + return ret; } #endif /* _WIN32 */ @@ -3421,45 +3782,49 @@ socket_finalize (SOCKET s, */ unsigned int -socket_set (struct link_socket *s, - struct event_set *es, - unsigned int rwflags, - void *arg, - unsigned int *persistent) -{ - if (s) - { - if ((rwflags & EVENT_READ) && !stream_buf_read_setup (s)) - { - ASSERT (!persistent); - rwflags &= ~EVENT_READ; - } - +socket_set(struct link_socket *s, + struct event_set *es, + unsigned int rwflags, + void *arg, + unsigned int *persistent) +{ + if (s) + { + if ((rwflags & EVENT_READ) && !stream_buf_read_setup(s)) + { + ASSERT(!persistent); + rwflags &= ~EVENT_READ; + } + #ifdef _WIN32 - if (rwflags & EVENT_READ) - socket_recv_queue (s, 0); + if (rwflags & EVENT_READ) + { + socket_recv_queue(s, 0); + } #endif - /* if persistent is defined, call event_ctl only if rwflags has changed since last call */ - if (!persistent || *persistent != rwflags) - { - event_ctl (es, socket_event_handle (s), rwflags, arg); - if (persistent) - *persistent = rwflags; - } + /* if persistent is defined, call event_ctl only if rwflags has changed since last call */ + if (!persistent || *persistent != rwflags) + { + event_ctl(es, socket_event_handle(s), rwflags, arg); + if (persistent) + { + *persistent = rwflags; + } + } - s->rwflags_debug = rwflags; + s->rwflags_debug = rwflags; } - return rwflags; + return rwflags; } void -sd_close (socket_descriptor_t *sd) +sd_close(socket_descriptor_t *sd) { - if (sd && socket_defined (*sd)) + if (sd && socket_defined(*sd)) { - openvpn_close_socket (*sd); - *sd = SOCKET_UNDEFINED; + openvpn_close_socket(*sd); + *sd = SOCKET_UNDEFINED; } } @@ -3470,128 +3835,150 @@ sd_close (socket_descriptor_t *sd) */ const char * -sockaddr_unix_name (const struct sockaddr_un *local, const char *null) +sockaddr_unix_name(const struct sockaddr_un *local, const char *null) { - if (local && local->sun_family == PF_UNIX) - return local->sun_path; - else - return null; + if (local && local->sun_family == PF_UNIX) + { + return local->sun_path; + } + else + { + return null; + } } socket_descriptor_t -create_socket_unix (void) +create_socket_unix(void) { - socket_descriptor_t sd; + socket_descriptor_t sd; - if ((sd = socket (PF_UNIX, SOCK_STREAM, 0)) < 0) - msg (M_ERR, "Cannot create unix domain socket"); + if ((sd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) + { + msg(M_ERR, "Cannot create unix domain socket"); + } - /* set socket file descriptor to not pass across execs, so that - scripts don't have access to it */ - set_cloexec (sd); + /* set socket file descriptor to not pass across execs, so that + * scripts don't have access to it */ + set_cloexec(sd); - return sd; + return sd; } void -socket_bind_unix (socket_descriptor_t sd, - struct sockaddr_un *local, - const char *prefix) +socket_bind_unix(socket_descriptor_t sd, + struct sockaddr_un *local, + const char *prefix) { - struct gc_arena gc = gc_new (); + struct gc_arena gc = gc_new(); #ifdef HAVE_UMASK - const mode_t orig_umask = umask (0); + const mode_t orig_umask = umask(0); #endif - if (bind (sd, (struct sockaddr *) local, sizeof (struct sockaddr_un))) + if (bind(sd, (struct sockaddr *) local, sizeof(struct sockaddr_un))) { - const int errnum = openvpn_errno (); - msg (M_FATAL, "%s: Socket bind[%d] failed on unix domain socket %s: %s", - prefix, - (int)sd, - sockaddr_unix_name (local, "NULL"), - strerror_ts (errnum, &gc)); + const int errnum = openvpn_errno(); + msg(M_FATAL, "%s: Socket bind[%d] failed on unix domain socket %s: %s", + prefix, + (int)sd, + sockaddr_unix_name(local, "NULL"), + strerror_ts(errnum, &gc)); } #ifdef HAVE_UMASK - umask (orig_umask); + umask(orig_umask); #endif - gc_free (&gc); + gc_free(&gc); } socket_descriptor_t -socket_accept_unix (socket_descriptor_t sd, - struct sockaddr_un *remote) +socket_accept_unix(socket_descriptor_t sd, + struct sockaddr_un *remote) { - socklen_t remote_len = sizeof (struct sockaddr_un); - socket_descriptor_t ret; + socklen_t remote_len = sizeof(struct sockaddr_un); + socket_descriptor_t ret; - CLEAR (*remote); - ret = accept (sd, (struct sockaddr *) remote, &remote_len); - if ( ret >= 0 ) + CLEAR(*remote); + ret = accept(sd, (struct sockaddr *) remote, &remote_len); + if (ret >= 0) { - /* set socket file descriptor to not pass across execs, so that - scripts don't have access to it */ - set_cloexec (ret); + /* set socket file descriptor to not pass across execs, so that + * scripts don't have access to it */ + set_cloexec(ret); } - return ret; + return ret; } int -socket_connect_unix (socket_descriptor_t sd, - struct sockaddr_un *remote) +socket_connect_unix(socket_descriptor_t sd, + struct sockaddr_un *remote) { - int status = connect (sd, (struct sockaddr *) remote, sizeof (struct sockaddr_un)); - if (status) - status = openvpn_errno (); - return status; + int status = connect(sd, (struct sockaddr *) remote, sizeof(struct sockaddr_un)); + if (status) + { + status = openvpn_errno(); + } + return status; } void -sockaddr_unix_init (struct sockaddr_un *local, const char *path) +sockaddr_unix_init(struct sockaddr_un *local, const char *path) { - local->sun_family = PF_UNIX; - strncpynt (local->sun_path, path, sizeof (local->sun_path)); + local->sun_family = PF_UNIX; + strncpynt(local->sun_path, path, sizeof(local->sun_path)); } void -socket_delete_unix (const struct sockaddr_un *local) +socket_delete_unix(const struct sockaddr_un *local) { - const char *name = sockaddr_unix_name (local, NULL); + const char *name = sockaddr_unix_name(local, NULL); #ifdef HAVE_UNLINK - if (name && strlen (name)) - unlink (name); + if (name && strlen(name)) + { + unlink(name); + } #endif } bool -unix_socket_get_peer_uid_gid (const socket_descriptor_t sd, int *uid, int *gid) +unix_socket_get_peer_uid_gid(const socket_descriptor_t sd, int *uid, int *gid) { #ifdef HAVE_GETPEEREID - uid_t u; - gid_t g; - if (getpeereid (sd, &u, &g) == -1) - return false; - if (uid) - *uid = u; - if (gid) - *gid = g; - return true; + uid_t u; + gid_t g; + if (getpeereid(sd, &u, &g) == -1) + { + return false; + } + if (uid) + { + *uid = u; + } + if (gid) + { + *gid = g; + } + return true; #elif defined(SO_PEERCRED) - struct ucred peercred; - socklen_t so_len = sizeof(peercred); - if (getsockopt(sd, SOL_SOCKET, SO_PEERCRED, &peercred, &so_len) == -1) + struct ucred peercred; + socklen_t so_len = sizeof(peercred); + if (getsockopt(sd, SOL_SOCKET, SO_PEERCRED, &peercred, &so_len) == -1) + { + return false; + } + if (uid) + { + *uid = peercred.uid; + } + if (gid) + { + *gid = peercred.gid; + } + return true; +#else /* ifdef HAVE_GETPEEREID */ return false; - if (uid) - *uid = peercred.uid; - if (gid) - *gid = peercred.gid; - return true; -#else - return false; -#endif +#endif /* ifdef HAVE_GETPEEREID */ } -#endif +#endif /* if UNIX_SOCK_SUPPORT */ diff --git a/src/openvpn/socket.h b/src/openvpn/socket.h index 2a82d8894f6..2f70eca5c28 100644 --- a/src/openvpn/socket.h +++ b/src/openvpn/socket.h @@ -47,7 +47,7 @@ */ #define RESOLV_RETRY_INFINITE 1000000000 -/* +/* * packet_size_type is used to communicate packet size * over the wire when stream oriented protocols are * being used @@ -64,12 +64,12 @@ typedef uint16_t packet_size_type; /* OpenVPN sockaddr struct */ struct openvpn_sockaddr { - /*int dummy;*/ /* add offset to force a bug if sa not explicitly dereferenced */ - union { - struct sockaddr sa; - struct sockaddr_in in4; - struct sockaddr_in6 in6; - } addr; + /*int dummy;*/ /* add offset to force a bug if sa not explicitly dereferenced */ + union { + struct sockaddr sa; + struct sockaddr_in in4; + struct sockaddr_in6 in6; + } addr; }; /* struct to hold preresolved host names */ @@ -85,42 +85,42 @@ struct cached_dns_entry { /* actual address of remote, based on source address of received packets */ struct link_socket_actual { - /*int dummy;*/ /* add offset to force a bug if dest not explicitly dereferenced */ + /*int dummy;*/ /* add offset to force a bug if dest not explicitly dereferenced */ - struct openvpn_sockaddr dest; + struct openvpn_sockaddr dest; #if ENABLE_IP_PKTINFO - union { + union { #if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) - struct in_pktinfo in4; + struct in_pktinfo in4; #elif defined(IP_RECVDSTADDR) - struct in_addr in4; + struct in_addr in4; #endif - struct in6_pktinfo in6; - } pi; + struct in6_pktinfo in6; + } pi; #endif }; /* IP addresses which are persistant across SIGUSR1s */ struct link_socket_addr { - struct addrinfo* bind_local; - struct addrinfo* remote_list; /* complete remote list */ - struct addrinfo* current_remote; /* remote used in the - current connection attempt */ - struct link_socket_actual actual; /* reply to this address */ + struct addrinfo *bind_local; + struct addrinfo *remote_list; /* complete remote list */ + struct addrinfo *current_remote; /* remote used in the + * current connection attempt */ + struct link_socket_actual actual; /* reply to this address */ }; struct link_socket_info { - struct link_socket_addr *lsa; - bool connection_established; - const char *ipchange_command; - const struct plugin_list *plugins; - bool remote_float; - int proto; /* Protocol (PROTO_x defined below) */ - sa_family_t af; /* Address family like AF_INET, AF_INET6 or AF_UNSPEC*/ - bool bind_ipv6_only; - int mtu_changed; /* Set to true when mtu value is changed */ + struct link_socket_addr *lsa; + bool connection_established; + const char *ipchange_command; + const struct plugin_list *plugins; + bool remote_float; + int proto; /* Protocol (PROTO_x defined below) */ + sa_family_t af; /* Address family like AF_INET, AF_INET6 or AF_UNSPEC*/ + bool bind_ipv6_only; + int mtu_changed; /* Set to true when mtu value is changed */ }; /* @@ -129,22 +129,22 @@ struct link_socket_info */ struct stream_buf { - struct buffer buf_init; - struct buffer residual; - int maxlen; - bool residual_fully_formed; + struct buffer buf_init; + struct buffer residual; + int maxlen; + bool residual_fully_formed; - struct buffer buf; - struct buffer next; - int len; /* -1 if not yet known */ + struct buffer buf; + struct buffer next; + int len; /* -1 if not yet known */ - bool error; /* if true, fatal TCP error has occurred, - requiring that connection be restarted */ + bool error; /* if true, fatal TCP error has occurred, + * requiring that connection be restarted */ #if PORT_SHARE -# define PS_DISABLED 0 -# define PS_ENABLED 1 -# define PS_FOREIGN 2 - int port_share_state; +#define PS_DISABLED 0 +#define PS_ENABLED 1 +#define PS_FOREIGN 2 + int port_share_state; #endif }; @@ -153,8 +153,8 @@ struct stream_buf */ struct socket_buffer_size { - int rcvbuf; - int sndbuf; + int rcvbuf; + int sndbuf; }; /* @@ -164,88 +164,88 @@ struct socket_buffer_size */ struct link_socket { - struct link_socket_info info; + struct link_socket_info info; - socket_descriptor_t sd; - socket_descriptor_t ctrl_sd; /* only used for UDP over Socks */ + socket_descriptor_t sd; + socket_descriptor_t ctrl_sd; /* only used for UDP over Socks */ #ifdef _WIN32 - struct overlapped_io reads; - struct overlapped_io writes; - struct rw_handle rw_handle; - struct rw_handle listen_handle; /* For listening on TCP socket in server mode */ + struct overlapped_io reads; + struct overlapped_io writes; + struct rw_handle rw_handle; + struct rw_handle listen_handle; /* For listening on TCP socket in server mode */ #endif - /* used for printing status info only */ - unsigned int rwflags_debug; + /* used for printing status info only */ + unsigned int rwflags_debug; - /* used for long-term queueing of pre-accepted socket listen */ - bool listen_persistent_queued; + /* used for long-term queueing of pre-accepted socket listen */ + bool listen_persistent_queued; - const char *remote_host; - const char *remote_port; - const char *local_host; - const char *local_port; - struct cached_dns_entry *dns_cache; - bool bind_local; + const char *remote_host; + const char *remote_port; + const char *local_host; + const char *local_port; + struct cached_dns_entry *dns_cache; + bool bind_local; -# define INETD_NONE 0 -# define INETD_WAIT 1 -# define INETD_NOWAIT 2 - int inetd; +#define INETD_NONE 0 +#define INETD_WAIT 1 +#define INETD_NOWAIT 2 + int inetd; -# define LS_MODE_DEFAULT 0 -# define LS_MODE_TCP_LISTEN 1 -# define LS_MODE_TCP_ACCEPT_FROM 2 - int mode; +#define LS_MODE_DEFAULT 0 +#define LS_MODE_TCP_LISTEN 1 +#define LS_MODE_TCP_ACCEPT_FROM 2 + int mode; - int resolve_retry_seconds; - int mtu_discover_type; + int resolve_retry_seconds; + int mtu_discover_type; - struct socket_buffer_size socket_buffer_sizes; + struct socket_buffer_size socket_buffer_sizes; - int mtu; /* OS discovered MTU, or 0 if unknown */ + int mtu; /* OS discovered MTU, or 0 if unknown */ -# define SF_USE_IP_PKTINFO (1<<0) -# define SF_TCP_NODELAY (1<<1) -# define SF_PORT_SHARE (1<<2) -# define SF_HOST_RANDOMIZE (1<<3) -# define SF_GETADDRINFO_DGRAM (1<<4) - unsigned int sockflags; - int mark; +#define SF_USE_IP_PKTINFO (1<<0) +#define SF_TCP_NODELAY (1<<1) +#define SF_PORT_SHARE (1<<2) +#define SF_HOST_RANDOMIZE (1<<3) +#define SF_GETADDRINFO_DGRAM (1<<4) + unsigned int sockflags; + int mark; - /* for stream sockets */ - struct stream_buf stream_buf; - struct buffer stream_buf_data; - bool stream_reset; + /* for stream sockets */ + struct stream_buf stream_buf; + struct buffer stream_buf_data; + bool stream_reset; - /* HTTP proxy */ - struct http_proxy_info *http_proxy; + /* HTTP proxy */ + struct http_proxy_info *http_proxy; - /* Socks proxy */ - struct socks_proxy_info *socks_proxy; - struct link_socket_actual socks_relay; /* Socks UDP relay address */ + /* Socks proxy */ + struct socks_proxy_info *socks_proxy; + struct link_socket_actual socks_relay; /* Socks UDP relay address */ - /* The OpenVPN server we will use the proxy to connect to */ - const char *proxy_dest_host; - const char *proxy_dest_port; + /* The OpenVPN server we will use the proxy to connect to */ + const char *proxy_dest_host; + const char *proxy_dest_port; - /* Pointer to the server-poll to trigger the timeout in function which have - * their own loop instead of using the main oop */ - struct event_timeout* server_poll_timeout; + /* Pointer to the server-poll to trigger the timeout in function which have + * their own loop instead of using the main oop */ + struct event_timeout *server_poll_timeout; #if PASSTOS_CAPABILITY - /* used to get/set TOS. */ + /* used to get/set TOS. */ #if defined(TARGET_LINUX) - uint8_t ptos; + uint8_t ptos; #else /* all the BSDs, Solaris, MacOS use plain "int" -> see "man ip" there */ - int ptos; + int ptos; #endif - bool ptos_defined; + bool ptos_defined; #endif #ifdef ENABLE_DEBUG - int gremlin; /* --gremlin bits */ + int gremlin; /* --gremlin bits */ #endif }; @@ -261,36 +261,36 @@ struct link_socket #define openvpn_close_socket(s) closesocket(s) -int socket_recv_queue (struct link_socket *sock, int maxsize); +int socket_recv_queue(struct link_socket *sock, int maxsize); -int socket_send_queue (struct link_socket *sock, - struct buffer *buf, - const struct link_socket_actual *to); +int socket_send_queue(struct link_socket *sock, + struct buffer *buf, + const struct link_socket_actual *to); -int socket_finalize ( - SOCKET s, - struct overlapped_io *io, - struct buffer *buf, - struct link_socket_actual *from); +int socket_finalize( + SOCKET s, + struct overlapped_io *io, + struct buffer *buf, + struct link_socket_actual *from); -#else +#else /* ifdef _WIN32 */ #define openvpn_close_socket(s) close(s) #endif -struct link_socket *link_socket_new (void); +struct link_socket *link_socket_new(void); -void socket_bind (socket_descriptor_t sd, - struct addrinfo *local, - int af_family, - const char *prefix, - bool ipv6only); +void socket_bind(socket_descriptor_t sd, + struct addrinfo *local, + int af_family, + const char *prefix, + bool ipv6only); -int openvpn_connect (socket_descriptor_t sd, - const struct sockaddr *remote, - int connect_timeout, - volatile int *signal_received); +int openvpn_connect(socket_descriptor_t sd, + const struct sockaddr *remote, + int connect_timeout, + volatile int *signal_received); @@ -299,49 +299,49 @@ int openvpn_connect (socket_descriptor_t sd, */ void -link_socket_init_phase1 (struct link_socket *sock, - const char *local_host, - const char *local_port, - const char *remote_host, - const char *remote_port, - struct cached_dns_entry *dns_cache, - int proto, - sa_family_t af, - bool bind_ipv6_only, - int mode, - const struct link_socket *accept_from, - struct http_proxy_info *http_proxy, - struct socks_proxy_info *socks_proxy, +link_socket_init_phase1(struct link_socket *sock, + const char *local_host, + const char *local_port, + const char *remote_host, + const char *remote_port, + struct cached_dns_entry *dns_cache, + int proto, + sa_family_t af, + bool bind_ipv6_only, + int mode, + const struct link_socket *accept_from, + struct http_proxy_info *http_proxy, + struct socks_proxy_info *socks_proxy, #ifdef ENABLE_DEBUG - int gremlin, + int gremlin, #endif - bool bind_local, - bool remote_float, - int inetd, - struct link_socket_addr *lsa, - const char *ipchange_command, - const struct plugin_list *plugins, - int resolve_retry_seconds, - int mtu_discover_type, - int rcvbuf, - int sndbuf, - int mark, - struct event_timeout* server_poll_timeout, - unsigned int sockflags); - -void link_socket_init_phase2 (struct link_socket *sock, - const struct frame *frame, - struct signal_info *sig_info); + bool bind_local, + bool remote_float, + int inetd, + struct link_socket_addr *lsa, + const char *ipchange_command, + const struct plugin_list *plugins, + int resolve_retry_seconds, + int mtu_discover_type, + int rcvbuf, + int sndbuf, + int mark, + struct event_timeout *server_poll_timeout, + unsigned int sockflags); + +void link_socket_init_phase2(struct link_socket *sock, + const struct frame *frame, + struct signal_info *sig_info); void do_preresolve(struct context *c); -void socket_adjust_frame_parameters (struct frame *frame, int proto); +void socket_adjust_frame_parameters(struct frame *frame, int proto); -void frame_adjust_path_mtu (struct frame *frame, int pmtu, int proto); +void frame_adjust_path_mtu(struct frame *frame, int pmtu, int proto); -void link_socket_close (struct link_socket *sock); +void link_socket_close(struct link_socket *sock); -void sd_close (socket_descriptor_t *sd); +void sd_close(socket_descriptor_t *sd); #define PS_SHOW_PORT_IF_DEFINED (1<<0) #define PS_SHOW_PORT (1<<1) @@ -349,102 +349,109 @@ void sd_close (socket_descriptor_t *sd); #define PS_DONT_SHOW_ADDR (1<<3) #define PS_DONT_SHOW_FAMILY (1<<4) -const char *print_sockaddr_ex (const struct sockaddr *addr, - const char* separator, - const unsigned int flags, - struct gc_arena *gc); +const char *print_sockaddr_ex(const struct sockaddr *addr, + const char *separator, + const unsigned int flags, + struct gc_arena *gc); static inline -const char *print_openvpn_sockaddr_ex (const struct openvpn_sockaddr *addr, - const char* separator, - const unsigned int flags, - struct gc_arena *gc) +const char * +print_openvpn_sockaddr_ex(const struct openvpn_sockaddr *addr, + const char *separator, + const unsigned int flags, + struct gc_arena *gc) { return print_sockaddr_ex(&addr->addr.sa, separator, flags, gc); } static inline -const char *print_openvpn_sockaddr (const struct openvpn_sockaddr *addr, - struct gc_arena *gc) +const char * +print_openvpn_sockaddr(const struct openvpn_sockaddr *addr, + struct gc_arena *gc) { - return print_sockaddr_ex (&addr->addr.sa, ":", PS_SHOW_PORT, gc); + return print_sockaddr_ex(&addr->addr.sa, ":", PS_SHOW_PORT, gc); } static inline -const char *print_sockaddr (const struct sockaddr *addr, - struct gc_arena *gc) +const char * +print_sockaddr(const struct sockaddr *addr, + struct gc_arena *gc) { - return print_sockaddr_ex (addr, ":", PS_SHOW_PORT, gc); + return print_sockaddr_ex(addr, ":", PS_SHOW_PORT, gc); } -const char *print_link_socket_actual_ex (const struct link_socket_actual *act, - const char* separator, - const unsigned int flags, - struct gc_arena *gc); +const char *print_link_socket_actual_ex(const struct link_socket_actual *act, + const char *separator, + const unsigned int flags, + struct gc_arena *gc); -const char *print_link_socket_actual (const struct link_socket_actual *act, - struct gc_arena *gc); +const char *print_link_socket_actual(const struct link_socket_actual *act, + struct gc_arena *gc); #define IA_EMPTY_IF_UNDEF (1<<0) #define IA_NET_ORDER (1<<1) -const char *print_in_addr_t (in_addr_t addr, unsigned int flags, struct gc_arena *gc); -const char *print_in6_addr (struct in6_addr addr6, unsigned int flags, struct gc_arena *gc); +const char *print_in_addr_t(in_addr_t addr, unsigned int flags, struct gc_arena *gc); + +const char *print_in6_addr(struct in6_addr addr6, unsigned int flags, struct gc_arena *gc); + struct in6_addr add_in6_addr( struct in6_addr base, uint32_t add ); #define SA_IP_PORT (1<<0) #define SA_SET_IF_NONZERO (1<<1) -void setenv_sockaddr (struct env_set *es, - const char *name_prefix, - const struct openvpn_sockaddr *addr, - const unsigned int flags); +void setenv_sockaddr(struct env_set *es, + const char *name_prefix, + const struct openvpn_sockaddr *addr, + const unsigned int flags); -void setenv_in_addr_t (struct env_set *es, - const char *name_prefix, - in_addr_t addr, - const unsigned int flags); - -void setenv_in6_addr (struct env_set *es, +void setenv_in_addr_t(struct env_set *es, const char *name_prefix, - const struct in6_addr *addr, + in_addr_t addr, const unsigned int flags); -void setenv_link_socket_actual (struct env_set *es, - const char *name_prefix, - const struct link_socket_actual *act, - const unsigned int flags); +void setenv_in6_addr(struct env_set *es, + const char *name_prefix, + const struct in6_addr *addr, + const unsigned int flags); + +void setenv_link_socket_actual(struct env_set *es, + const char *name_prefix, + const struct link_socket_actual *act, + const unsigned int flags); -void bad_address_length (int actual, int expected); +void bad_address_length(int actual, int expected); /* IPV4_INVALID_ADDR: returned by link_socket_current_remote() * to ease redirect-gateway logic for ipv4 tunnels on ipv6 endpoints */ #define IPV4_INVALID_ADDR 0xffffffff -in_addr_t link_socket_current_remote (const struct link_socket_info *info); -const struct in6_addr * link_socket_current_remote_ipv6 - (const struct link_socket_info *info); +in_addr_t link_socket_current_remote(const struct link_socket_info *info); + +const struct in6_addr *link_socket_current_remote_ipv6 + (const struct link_socket_info *info); -void link_socket_connection_initiated (const struct buffer *buf, - struct link_socket_info *info, - const struct link_socket_actual *addr, - const char *common_name, - struct env_set *es); +void link_socket_connection_initiated(const struct buffer *buf, + struct link_socket_info *info, + const struct link_socket_actual *addr, + const char *common_name, + struct env_set *es); -void link_socket_bad_incoming_addr (struct buffer *buf, - const struct link_socket_info *info, - const struct link_socket_actual *from_addr); +void link_socket_bad_incoming_addr(struct buffer *buf, + const struct link_socket_info *info, + const struct link_socket_actual *from_addr); -void set_actual_address (struct link_socket_actual* actual, - struct addrinfo* ai); +void set_actual_address(struct link_socket_actual *actual, + struct addrinfo *ai); -void link_socket_bad_outgoing_addr (void); +void link_socket_bad_outgoing_addr(void); -void setenv_trusted (struct env_set *es, const struct link_socket_info *info); +void setenv_trusted(struct env_set *es, const struct link_socket_info *info); -bool link_socket_update_flags (struct link_socket *ls, unsigned int sockflags); -void link_socket_update_buffer_sizes (struct link_socket *ls, int rcvbuf, int sndbuf); +bool link_socket_update_flags(struct link_socket *ls, unsigned int sockflags); + +void link_socket_update_buffer_sizes(struct link_socket *ls, int rcvbuf, int sndbuf); /* * Low-level functions @@ -454,51 +461,58 @@ void link_socket_update_buffer_sizes (struct link_socket *ls, int rcvbuf, int sn #define OIA_HOSTNAME 0 #define OIA_IP 1 #define OIA_ERROR -1 -int openvpn_inet_aton (const char *dotted_quad, struct in_addr *addr); +int openvpn_inet_aton(const char *dotted_quad, struct in_addr *addr); /* integrity validation on pulled options */ -bool ip_addr_dotted_quad_safe (const char *dotted_quad); -bool ip_or_dns_addr_safe (const char *addr, const bool allow_fqdn); -bool mac_addr_safe (const char *mac_addr); -bool ipv6_addr_safe (const char *ipv6_text_addr); +bool ip_addr_dotted_quad_safe(const char *dotted_quad); + +bool ip_or_dns_addr_safe(const char *addr, const bool allow_fqdn); + +bool mac_addr_safe(const char *mac_addr); -socket_descriptor_t create_socket_tcp (struct addrinfo*); +bool ipv6_addr_safe(const char *ipv6_text_addr); + +socket_descriptor_t create_socket_tcp(struct addrinfo *); + +socket_descriptor_t socket_do_accept(socket_descriptor_t sd, + struct link_socket_actual *act, + const bool nowait); -socket_descriptor_t socket_do_accept (socket_descriptor_t sd, - struct link_socket_actual *act, - const bool nowait); /* * proto related */ bool proto_is_net(int proto); + bool proto_is_dgram(int proto); + bool proto_is_udp(int proto); + bool proto_is_tcp(int proto); #if UNIX_SOCK_SUPPORT -socket_descriptor_t create_socket_unix (void); +socket_descriptor_t create_socket_unix(void); -void socket_bind_unix (socket_descriptor_t sd, - struct sockaddr_un *local, - const char *prefix); +void socket_bind_unix(socket_descriptor_t sd, + struct sockaddr_un *local, + const char *prefix); -socket_descriptor_t socket_accept_unix (socket_descriptor_t sd, - struct sockaddr_un *remote); +socket_descriptor_t socket_accept_unix(socket_descriptor_t sd, + struct sockaddr_un *remote); -int socket_connect_unix (socket_descriptor_t sd, - struct sockaddr_un *remote); +int socket_connect_unix(socket_descriptor_t sd, + struct sockaddr_un *remote); -void sockaddr_unix_init (struct sockaddr_un *local, const char *path); +void sockaddr_unix_init(struct sockaddr_un *local, const char *path); -const char *sockaddr_unix_name (const struct sockaddr_un *local, const char *null); +const char *sockaddr_unix_name(const struct sockaddr_un *local, const char *null); -void socket_delete_unix (const struct sockaddr_un *local); +void socket_delete_unix(const struct sockaddr_un *local); -bool unix_socket_get_peer_uid_gid (const socket_descriptor_t sd, int *uid, int *gid); +bool unix_socket_get_peer_uid_gid(const socket_descriptor_t sd, int *uid, int *gid); -#endif +#endif /* if UNIX_SOCK_SUPPORT */ /* * DNS resolution @@ -517,44 +531,49 @@ bool unix_socket_get_peer_uid_gid (const socket_descriptor_t sd, int *uid, int * #define GETADDR_PASSIVE (1<<10) #define GETADDR_DATAGRAM (1<<11) -#define GETADDR_CACHE_MASK (GETADDR_DATAGRAM|GETADDR_PASSIVE) +#define GETADDR_CACHE_MASK (GETADDR_DATAGRAM|GETADDR_PASSIVE) -in_addr_t getaddr (unsigned int flags, - const char *hostname, - int resolve_retry_seconds, - bool *succeeded, - volatile int *signal_received); +in_addr_t getaddr(unsigned int flags, + const char *hostname, + int resolve_retry_seconds, + bool *succeeded, + volatile int *signal_received); -int openvpn_getaddrinfo (unsigned int flags, - const char *hostname, - const char *servname, - int resolve_retry_seconds, - volatile int *signal_received, - int ai_family, - struct addrinfo **res); +int openvpn_getaddrinfo(unsigned int flags, + const char *hostname, + const char *servname, + int resolve_retry_seconds, + volatile int *signal_received, + int ai_family, + struct addrinfo **res); /* * Transport protocol naming and other details. */ -/* +/* * Use enum's instead of #define to allow for easier * optional proto support */ enum proto_num { - PROTO_NONE, /* catch for uninitialized */ - PROTO_UDP, - PROTO_TCP, - PROTO_TCP_SERVER, - PROTO_TCP_CLIENT, - PROTO_N + PROTO_NONE, /* catch for uninitialized */ + PROTO_UDP, + PROTO_TCP, + PROTO_TCP_SERVER, + PROTO_TCP_CLIENT, + PROTO_N }; -int ascii2proto (const char* proto_name); -sa_family_t ascii2af (const char* proto_name); -const char *proto2ascii (int proto, sa_family_t af, bool display_form); -const char *proto2ascii_all (struct gc_arena *gc); -const char *proto_remote (int proto, bool remote); +int ascii2proto(const char *proto_name); + +sa_family_t ascii2af(const char *proto_name); + +const char *proto2ascii(int proto, sa_family_t af, bool display_form); + +const char *proto2ascii_all(struct gc_arena *gc); + +const char *proto_remote(int proto, bool remote); + const char *addr_family_name(int af); /* @@ -568,10 +587,10 @@ const char *addr_family_name(int af); extern const int proto_overhead[]; static inline int -datagram_overhead (int proto) +datagram_overhead(int proto) { - ASSERT (proto >= 0 && proto < PROTO_N); - return proto_overhead [proto]; + ASSERT(proto >= 0 && proto < PROTO_N); + return proto_overhead [proto]; } /* @@ -579,343 +598,392 @@ datagram_overhead (int proto) */ static inline bool -link_socket_proto_connection_oriented (int proto) +link_socket_proto_connection_oriented(int proto) { - return !proto_is_dgram(proto); + return !proto_is_dgram(proto); } static inline bool -link_socket_connection_oriented (const struct link_socket *sock) +link_socket_connection_oriented(const struct link_socket *sock) { - if (sock) - return link_socket_proto_connection_oriented (sock->info.proto); - else - return false; + if (sock) + { + return link_socket_proto_connection_oriented(sock->info.proto); + } + else + { + return false; + } } static inline bool -addr_defined (const struct openvpn_sockaddr *addr) +addr_defined(const struct openvpn_sockaddr *addr) { - if (!addr) return 0; - switch (addr->addr.sa.sa_family) { - case AF_INET: return addr->addr.in4.sin_addr.s_addr != 0; - case AF_INET6: return !IN6_IS_ADDR_UNSPECIFIED(&addr->addr.in6.sin6_addr); - default: return 0; - } + if (!addr) + { + return 0; + } + switch (addr->addr.sa.sa_family) { + case AF_INET: return addr->addr.in4.sin_addr.s_addr != 0; + + case AF_INET6: return !IN6_IS_ADDR_UNSPECIFIED(&addr->addr.in6.sin6_addr); + + default: return 0; + } } static inline bool -addr_local (const struct sockaddr *addr) +addr_local(const struct sockaddr *addr) { if (!addr) - return false; + { + return false; + } switch (addr->sa_family) { - case AF_INET: - return ((const struct sockaddr_in*)addr)->sin_addr.s_addr == htonl(INADDR_LOOPBACK); - case AF_INET6: - return IN6_IS_ADDR_LOOPBACK(&((const struct sockaddr_in6*)addr)->sin6_addr); - default: - return false; + case AF_INET: + return ((const struct sockaddr_in *)addr)->sin_addr.s_addr == htonl(INADDR_LOOPBACK); + + case AF_INET6: + return IN6_IS_ADDR_LOOPBACK(&((const struct sockaddr_in6 *)addr)->sin6_addr); + + default: + return false; } } static inline bool -addr_defined_ipi (const struct link_socket_actual *lsa) +addr_defined_ipi(const struct link_socket_actual *lsa) { #if ENABLE_IP_PKTINFO - if (!lsa) return 0; - switch (lsa->dest.addr.sa.sa_family) { + if (!lsa) + { + return 0; + } + switch (lsa->dest.addr.sa.sa_family) { #if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) - case AF_INET: return lsa->pi.in4.ipi_spec_dst.s_addr != 0; + case AF_INET: return lsa->pi.in4.ipi_spec_dst.s_addr != 0; + #elif defined(IP_RECVDSTADDR) - case AF_INET: return lsa->pi.in4.s_addr != 0; + case AF_INET: return lsa->pi.in4.s_addr != 0; + #endif - case AF_INET6: return !IN6_IS_ADDR_UNSPECIFIED(&lsa->pi.in6.ipi6_addr); - default: return 0; - } -#else - ASSERT(0); + case AF_INET6: return !IN6_IS_ADDR_UNSPECIFIED(&lsa->pi.in6.ipi6_addr); + + default: return 0; + } +#else /* if ENABLE_IP_PKTINFO */ + ASSERT(0); #endif - return false; + return false; } static inline bool -link_socket_actual_defined (const struct link_socket_actual *act) +link_socket_actual_defined(const struct link_socket_actual *act) { - return act && addr_defined (&act->dest); + return act && addr_defined(&act->dest); } static inline bool -addr_match (const struct openvpn_sockaddr *a1, const struct openvpn_sockaddr *a2) +addr_match(const struct openvpn_sockaddr *a1, const struct openvpn_sockaddr *a2) { - switch(a1->addr.sa.sa_family) { - case AF_INET: - return a1->addr.in4.sin_addr.s_addr == a2->addr.in4.sin_addr.s_addr; - case AF_INET6: - return IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr, &a2->addr.in6.sin6_addr); - } - ASSERT(0); - return false; + switch (a1->addr.sa.sa_family) { + case AF_INET: + return a1->addr.in4.sin_addr.s_addr == a2->addr.in4.sin_addr.s_addr; + + case AF_INET6: + return IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr, &a2->addr.in6.sin6_addr); + } + ASSERT(0); + return false; } static inline bool -addrlist_match (const struct openvpn_sockaddr *a1, const struct addrinfo *addrlist) +addrlist_match(const struct openvpn_sockaddr *a1, const struct addrinfo *addrlist) { - const struct addrinfo *curele; - for (curele = addrlist; curele; curele=curele->ai_next) + const struct addrinfo *curele; + for (curele = addrlist; curele; curele = curele->ai_next) { - switch(a1->addr.sa.sa_family) + switch (a1->addr.sa.sa_family) { - case AF_INET: - if (a1->addr.in4.sin_addr.s_addr == ((struct sockaddr_in*)curele->ai_addr)->sin_addr.s_addr) - return true; - break; - case AF_INET6: - if (IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr, &((struct sockaddr_in6*) curele->ai_addr)->sin6_addr)) - return true; - break; - default: - ASSERT(0); + case AF_INET: + if (a1->addr.in4.sin_addr.s_addr == ((struct sockaddr_in *)curele->ai_addr)->sin_addr.s_addr) + { + return true; + } + break; + + case AF_INET6: + if (IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr, &((struct sockaddr_in6 *) curele->ai_addr)->sin6_addr)) + { + return true; + } + break; + + default: + ASSERT(0); } } - return false; + return false; } static inline in_addr_t -addr_host (const struct openvpn_sockaddr *addr) +addr_host(const struct openvpn_sockaddr *addr) { - /* - * "public" addr returned is checked against ifconfig for - * possible clash: non sense for now given - * that we do ifconfig only IPv4 - */ - if(addr->addr.sa.sa_family != AF_INET) - return 0; - return ntohl (addr->addr.in4.sin_addr.s_addr); + /* + * "public" addr returned is checked against ifconfig for + * possible clash: non sense for now given + * that we do ifconfig only IPv4 + */ + if (addr->addr.sa.sa_family != AF_INET) + { + return 0; + } + return ntohl(addr->addr.in4.sin_addr.s_addr); } static inline bool -addrlist_port_match (const struct openvpn_sockaddr *a1, const struct addrinfo *a2) +addrlist_port_match(const struct openvpn_sockaddr *a1, const struct addrinfo *a2) { - const struct addrinfo *curele; - for(curele=a2;curele;curele = curele->ai_next) + const struct addrinfo *curele; + for (curele = a2; curele; curele = curele->ai_next) { - switch(a1->addr.sa.sa_family) + switch (a1->addr.sa.sa_family) { - case AF_INET: - if (curele->ai_family == AF_INET - && a1->addr.in4.sin_addr.s_addr == ((struct sockaddr_in*)curele->ai_addr)->sin_addr.s_addr - && a1->addr.in4.sin_port == ((struct sockaddr_in*)curele->ai_addr)->sin_port) - return true; + case AF_INET: + if (curele->ai_family == AF_INET + && a1->addr.in4.sin_addr.s_addr == ((struct sockaddr_in *)curele->ai_addr)->sin_addr.s_addr + && a1->addr.in4.sin_port == ((struct sockaddr_in *)curele->ai_addr)->sin_port) + { + return true; + } break; - case AF_INET6: + + case AF_INET6: if (curele->ai_family == AF_INET6 - && IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr, &((struct sockaddr_in6*) curele->ai_addr)->sin6_addr) - && a1->addr.in6.sin6_port == ((struct sockaddr_in6*) curele->ai_addr)->sin6_port) + && IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr, &((struct sockaddr_in6 *) curele->ai_addr)->sin6_addr) + && a1->addr.in6.sin6_port == ((struct sockaddr_in6 *) curele->ai_addr)->sin6_port) + { return true; + } break; - default: + + default: ASSERT(0); } } - return false; + return false; } static inline bool -addr_port_match (const struct openvpn_sockaddr *a1, const struct openvpn_sockaddr *a2) +addr_port_match(const struct openvpn_sockaddr *a1, const struct openvpn_sockaddr *a2) { - switch(a1->addr.sa.sa_family) { - case AF_INET: - return a1->addr.in4.sin_addr.s_addr == a2->addr.in4.sin_addr.s_addr - && a1->addr.in4.sin_port == a2->addr.in4.sin_port; - case AF_INET6: - return IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr, &a2->addr.in6.sin6_addr) - && a1->addr.in6.sin6_port == a2->addr.in6.sin6_port; - } - ASSERT(0); - return false; + switch (a1->addr.sa.sa_family) { + case AF_INET: + return a1->addr.in4.sin_addr.s_addr == a2->addr.in4.sin_addr.s_addr + && a1->addr.in4.sin_port == a2->addr.in4.sin_port; + + case AF_INET6: + return IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr, &a2->addr.in6.sin6_addr) + && a1->addr.in6.sin6_port == a2->addr.in6.sin6_port; + } + ASSERT(0); + return false; } static inline bool -addr_match_proto (const struct openvpn_sockaddr *a1, - const struct openvpn_sockaddr *a2, - const int proto) +addr_match_proto(const struct openvpn_sockaddr *a1, + const struct openvpn_sockaddr *a2, + const int proto) { - return link_socket_proto_connection_oriented (proto) - ? addr_match (a1, a2) - : addr_port_match (a1, a2); + return link_socket_proto_connection_oriented(proto) + ? addr_match(a1, a2) + : addr_port_match(a1, a2); } static inline bool -addrlist_match_proto (const struct openvpn_sockaddr *a1, - struct addrinfo *addr_list, - const int proto) +addrlist_match_proto(const struct openvpn_sockaddr *a1, + struct addrinfo *addr_list, + const int proto) { - return link_socket_proto_connection_oriented (proto) - ? addrlist_match (a1, addr_list) - : addrlist_port_match (a1, addr_list); + return link_socket_proto_connection_oriented(proto) + ? addrlist_match(a1, addr_list) + : addrlist_port_match(a1, addr_list); } static inline void addr_zero_host(struct openvpn_sockaddr *addr) { - switch(addr->addr.sa.sa_family) { - case AF_INET: - addr->addr.in4.sin_addr.s_addr = 0; - break; - case AF_INET6: - memset(&addr->addr.in6.sin6_addr, 0, sizeof (struct in6_addr)); - break; - } + switch (addr->addr.sa.sa_family) { + case AF_INET: + addr->addr.in4.sin_addr.s_addr = 0; + break; + + case AF_INET6: + memset(&addr->addr.in6.sin6_addr, 0, sizeof(struct in6_addr)); + break; + } } static inline void addr_copy_sa(struct openvpn_sockaddr *dst, const struct openvpn_sockaddr *src) { - dst->addr = src->addr; + dst->addr = src->addr; } static inline bool addr_inet4or6(struct sockaddr *addr) { - return addr->sa_family == AF_INET || addr->sa_family == AF_INET6; + return addr->sa_family == AF_INET || addr->sa_family == AF_INET6; } int addr_guess_family(sa_family_t af,const char *name); + static inline int af_addr_size(sa_family_t af) { - switch(af) { - case AF_INET: return sizeof (struct sockaddr_in); - case AF_INET6: return sizeof (struct sockaddr_in6); - default: + switch (af) { + case AF_INET: return sizeof(struct sockaddr_in); + + case AF_INET6: return sizeof(struct sockaddr_in6); + + default: #if 0 - /* could be called from socket_do_accept() with empty addr */ - msg (M_ERR, "Bad address family: %d\n", af); - ASSERT(0); + /* could be called from socket_do_accept() with empty addr */ + msg(M_ERR, "Bad address family: %d\n", af); + ASSERT(0); #endif - return 0; - } + return 0; + } } static inline bool -link_socket_actual_match (const struct link_socket_actual *a1, const struct link_socket_actual *a2) +link_socket_actual_match(const struct link_socket_actual *a1, const struct link_socket_actual *a2) { - return addr_port_match (&a1->dest, &a2->dest); + return addr_port_match(&a1->dest, &a2->dest); } #if PORT_SHARE static inline bool -socket_foreign_protocol_detected (const struct link_socket *sock) +socket_foreign_protocol_detected(const struct link_socket *sock) { - return link_socket_connection_oriented (sock) - && sock->stream_buf.port_share_state == PS_FOREIGN; + return link_socket_connection_oriented(sock) + && sock->stream_buf.port_share_state == PS_FOREIGN; } static inline const struct buffer * -socket_foreign_protocol_head (const struct link_socket *sock) +socket_foreign_protocol_head(const struct link_socket *sock) { - return &sock->stream_buf.buf; + return &sock->stream_buf.buf; } static inline int -socket_foreign_protocol_sd (const struct link_socket *sock) +socket_foreign_protocol_sd(const struct link_socket *sock) { - return sock->sd; + return sock->sd; } -#endif +#endif /* if PORT_SHARE */ static inline bool -socket_connection_reset (const struct link_socket *sock, int status) +socket_connection_reset(const struct link_socket *sock, int status) { - if (link_socket_connection_oriented (sock)) + if (link_socket_connection_oriented(sock)) { - if (sock->stream_reset || sock->stream_buf.error) - return true; - else if (status < 0) - { - const int err = openvpn_errno (); + if (sock->stream_reset || sock->stream_buf.error) + { + return true; + } + else if (status < 0) + { + const int err = openvpn_errno(); #ifdef _WIN32 - return err == WSAECONNRESET || err == WSAECONNABORTED; + return err == WSAECONNRESET || err == WSAECONNABORTED; #else - return err == ECONNRESET; + return err == ECONNRESET; #endif - } + } } - return false; + return false; } static inline bool -link_socket_verify_incoming_addr (struct buffer *buf, - const struct link_socket_info *info, - const struct link_socket_actual *from_addr) +link_socket_verify_incoming_addr(struct buffer *buf, + const struct link_socket_info *info, + const struct link_socket_actual *from_addr) { - if (buf->len > 0) + if (buf->len > 0) { - switch (from_addr->dest.addr.sa.sa_family) { - case AF_INET6: - case AF_INET: - if (!link_socket_actual_defined (from_addr)) - return false; - if (info->remote_float || (!info->lsa->remote_list)) - return true; - if (addrlist_match_proto (&from_addr->dest, info->lsa->remote_list, info->proto)) - return true; - } + switch (from_addr->dest.addr.sa.sa_family) { + case AF_INET6: + case AF_INET: + if (!link_socket_actual_defined(from_addr)) + { + return false; + } + if (info->remote_float || (!info->lsa->remote_list)) + { + return true; + } + if (addrlist_match_proto(&from_addr->dest, info->lsa->remote_list, info->proto)) + { + return true; + } + } } - return false; + return false; } static inline void -link_socket_get_outgoing_addr (struct buffer *buf, - const struct link_socket_info *info, - struct link_socket_actual **act) +link_socket_get_outgoing_addr(struct buffer *buf, + const struct link_socket_info *info, + struct link_socket_actual **act) { - if (buf->len > 0) + if (buf->len > 0) { - struct link_socket_addr *lsa = info->lsa; - if (link_socket_actual_defined (&lsa->actual)) - *act = &lsa->actual; - else - { - link_socket_bad_outgoing_addr (); - buf->len = 0; - *act = NULL; - } + struct link_socket_addr *lsa = info->lsa; + if (link_socket_actual_defined(&lsa->actual)) + { + *act = &lsa->actual; + } + else + { + link_socket_bad_outgoing_addr(); + buf->len = 0; + *act = NULL; + } } } static inline void -link_socket_set_outgoing_addr (const struct buffer *buf, - struct link_socket_info *info, - const struct link_socket_actual *act, - const char *common_name, - struct env_set *es) +link_socket_set_outgoing_addr(const struct buffer *buf, + struct link_socket_info *info, + const struct link_socket_actual *act, + const char *common_name, + struct env_set *es) { - if (!buf || buf->len > 0) + if (!buf || buf->len > 0) { - struct link_socket_addr *lsa = info->lsa; - if ( - /* new or changed address? */ - (!info->connection_established - || !addr_match_proto (&act->dest, &lsa->actual.dest, info->proto) - ) - && - /* address undef or address == remote or --float */ - (info->remote_float || - (!lsa->remote_list || addrlist_match_proto (&act->dest, lsa->remote_list, info->proto)) - ) - ) - { - link_socket_connection_initiated (buf, info, act, common_name, es); - } + struct link_socket_addr *lsa = info->lsa; + if ( + /* new or changed address? */ + (!info->connection_established + || !addr_match_proto(&act->dest, &lsa->actual.dest, info->proto) + ) + && + /* address undef or address == remote or --float */ + (info->remote_float + || (!lsa->remote_list || addrlist_match_proto(&act->dest, lsa->remote_list, info->proto)) + ) + ) + { + link_socket_connection_initiated(buf, info, act, common_name, es); + } } } @@ -925,76 +993,82 @@ link_socket_set_outgoing_addr (const struct buffer *buf, * such as TCP. */ -void stream_buf_init (struct stream_buf *sb, - struct buffer *buf, - const unsigned int sockflags, - const int proto); +void stream_buf_init(struct stream_buf *sb, + struct buffer *buf, + const unsigned int sockflags, + const int proto); -void stream_buf_close (struct stream_buf* sb); -bool stream_buf_added (struct stream_buf *sb, int length_added); +void stream_buf_close(struct stream_buf *sb); + +bool stream_buf_added(struct stream_buf *sb, int length_added); static inline bool -stream_buf_read_setup (struct link_socket* sock) +stream_buf_read_setup(struct link_socket *sock) { - bool stream_buf_read_setup_dowork (struct link_socket* sock); - if (link_socket_connection_oriented (sock)) - return stream_buf_read_setup_dowork (sock); - else - return true; + bool stream_buf_read_setup_dowork(struct link_socket *sock); + + if (link_socket_connection_oriented(sock)) + { + return stream_buf_read_setup_dowork(sock); + } + else + { + return true; + } } /* * Socket Read Routines */ -int link_socket_read_tcp (struct link_socket *sock, - struct buffer *buf); +int link_socket_read_tcp(struct link_socket *sock, + struct buffer *buf); #ifdef _WIN32 static inline int -link_socket_read_udp_win32 (struct link_socket *sock, - struct buffer *buf, - struct link_socket_actual *from) +link_socket_read_udp_win32(struct link_socket *sock, + struct buffer *buf, + struct link_socket_actual *from) { - return socket_finalize (sock->sd, &sock->reads, buf, from); + return socket_finalize(sock->sd, &sock->reads, buf, from); } -#else +#else /* ifdef _WIN32 */ -int link_socket_read_udp_posix (struct link_socket *sock, - struct buffer *buf, - struct link_socket_actual *from); +int link_socket_read_udp_posix(struct link_socket *sock, + struct buffer *buf, + struct link_socket_actual *from); #endif /* read a TCP or UDP packet from link */ static inline int -link_socket_read (struct link_socket *sock, - struct buffer *buf, - struct link_socket_actual *from) +link_socket_read(struct link_socket *sock, + struct buffer *buf, + struct link_socket_actual *from) { - if (proto_is_udp(sock->info.proto)) /* unified UDPv4 and UDPv6 */ + if (proto_is_udp(sock->info.proto)) /* unified UDPv4 and UDPv6 */ { - int res; + int res; #ifdef _WIN32 - res = link_socket_read_udp_win32 (sock, buf, from); + res = link_socket_read_udp_win32(sock, buf, from); #else - res = link_socket_read_udp_posix (sock, buf, from); + res = link_socket_read_udp_posix(sock, buf, from); #endif - return res; + return res; } - else if (proto_is_tcp(sock->info.proto)) /* unified TCPv4 and TCPv6 */ + else if (proto_is_tcp(sock->info.proto)) /* unified TCPv4 and TCPv6 */ { - /* from address was returned by accept */ - addr_copy_sa(&from->dest, &sock->info.lsa->actual.dest); - return link_socket_read_tcp (sock, buf); + /* from address was returned by accept */ + addr_copy_sa(&from->dest, &sock->info.lsa->actual.dest); + return link_socket_read_tcp(sock, buf); } - else + else { - ASSERT (0); - return -1; /* NOTREACHED */ + ASSERT(0); + return -1; /* NOTREACHED */ } } @@ -1002,97 +1076,103 @@ link_socket_read (struct link_socket *sock, * Socket Write routines */ -int link_socket_write_tcp (struct link_socket *sock, - struct buffer *buf, - struct link_socket_actual *to); +int link_socket_write_tcp(struct link_socket *sock, + struct buffer *buf, + struct link_socket_actual *to); #ifdef _WIN32 static inline int -link_socket_write_win32 (struct link_socket *sock, - struct buffer *buf, - struct link_socket_actual *to) +link_socket_write_win32(struct link_socket *sock, + struct buffer *buf, + struct link_socket_actual *to) { - int err = 0; - int status = 0; - if (overlapped_io_active (&sock->writes)) + int err = 0; + int status = 0; + if (overlapped_io_active(&sock->writes)) { - status = socket_finalize (sock->sd, &sock->writes, NULL, NULL); - if (status < 0) - err = WSAGetLastError (); + status = socket_finalize(sock->sd, &sock->writes, NULL, NULL); + if (status < 0) + { + err = WSAGetLastError(); + } } - socket_send_queue (sock, buf, to); - if (status < 0) + socket_send_queue(sock, buf, to); + if (status < 0) { - WSASetLastError (err); - return status; + WSASetLastError(err); + return status; + } + else + { + return BLEN(buf); } - else - return BLEN (buf); } -#else +#else /* ifdef _WIN32 */ static inline size_t -link_socket_write_udp_posix (struct link_socket *sock, - struct buffer *buf, - struct link_socket_actual *to) +link_socket_write_udp_posix(struct link_socket *sock, + struct buffer *buf, + struct link_socket_actual *to) { #if ENABLE_IP_PKTINFO - size_t link_socket_write_udp_posix_sendmsg (struct link_socket *sock, - struct buffer *buf, - struct link_socket_actual *to); - - if (proto_is_udp(sock->info.proto) && (sock->sockflags & SF_USE_IP_PKTINFO) - && addr_defined_ipi(to)) - return link_socket_write_udp_posix_sendmsg (sock, buf, to); - else + size_t link_socket_write_udp_posix_sendmsg(struct link_socket *sock, + struct buffer *buf, + struct link_socket_actual *to); + + if (proto_is_udp(sock->info.proto) && (sock->sockflags & SF_USE_IP_PKTINFO) + && addr_defined_ipi(to)) + { + return link_socket_write_udp_posix_sendmsg(sock, buf, to); + } + else #endif - return sendto (sock->sd, BPTR (buf), BLEN (buf), 0, - (struct sockaddr *) &to->dest.addr.sa, - (socklen_t) af_addr_size(to->dest.addr.sa.sa_family)); + return sendto(sock->sd, BPTR(buf), BLEN(buf), 0, + (struct sockaddr *) &to->dest.addr.sa, + (socklen_t) af_addr_size(to->dest.addr.sa.sa_family)); } static inline size_t -link_socket_write_tcp_posix (struct link_socket *sock, - struct buffer *buf, - struct link_socket_actual *to) +link_socket_write_tcp_posix(struct link_socket *sock, + struct buffer *buf, + struct link_socket_actual *to) { - return send (sock->sd, BPTR (buf), BLEN (buf), MSG_NOSIGNAL); + return send(sock->sd, BPTR(buf), BLEN(buf), MSG_NOSIGNAL); } -#endif +#endif /* ifdef _WIN32 */ static inline size_t -link_socket_write_udp (struct link_socket *sock, - struct buffer *buf, - struct link_socket_actual *to) +link_socket_write_udp(struct link_socket *sock, + struct buffer *buf, + struct link_socket_actual *to) { #ifdef _WIN32 - return link_socket_write_win32 (sock, buf, to); + return link_socket_write_win32(sock, buf, to); #else - return link_socket_write_udp_posix (sock, buf, to); + return link_socket_write_udp_posix(sock, buf, to); #endif } /* write a TCP or UDP packet to link */ static inline int -link_socket_write (struct link_socket *sock, - struct buffer *buf, - struct link_socket_actual *to) +link_socket_write(struct link_socket *sock, + struct buffer *buf, + struct link_socket_actual *to) { - if (proto_is_udp(sock->info.proto)) /* unified UDPv4 and UDPv6 */ + if (proto_is_udp(sock->info.proto)) /* unified UDPv4 and UDPv6 */ { - return link_socket_write_udp (sock, buf, to); + return link_socket_write_udp(sock, buf, to); } - else if (proto_is_tcp(sock->info.proto)) /* unified TCPv4 and TCPv6 */ + else if (proto_is_tcp(sock->info.proto)) /* unified TCPv4 and TCPv6 */ { - return link_socket_write_tcp (sock, buf, to); + return link_socket_write_tcp(sock, buf, to); } - else + else { - ASSERT (0); - return -1; /* NOTREACHED */ + ASSERT(0); + return -1; /* NOTREACHED */ } } @@ -1102,13 +1182,13 @@ link_socket_write (struct link_socket *sock, * Extract TOS bits. Assumes that ipbuf is a valid IPv4 packet. */ static inline void -link_socket_extract_tos (struct link_socket *ls, const struct buffer *ipbuf) +link_socket_extract_tos(struct link_socket *ls, const struct buffer *ipbuf) { - if (ls && ipbuf) + if (ls && ipbuf) { - struct openvpn_iphdr *iph = (struct openvpn_iphdr *) BPTR (ipbuf); - ls->ptos = iph->tos; - ls->ptos_defined = true; + struct openvpn_iphdr *iph = (struct openvpn_iphdr *) BPTR(ipbuf); + ls->ptos = iph->tos; + ls->ptos_defined = true; } } @@ -1117,63 +1197,65 @@ link_socket_extract_tos (struct link_socket *ls, const struct buffer *ipbuf) * from tunnel packet. */ static inline void -link_socket_set_tos (struct link_socket *ls) +link_socket_set_tos(struct link_socket *ls) { - if (ls && ls->ptos_defined) - setsockopt (ls->sd, IPPROTO_IP, IP_TOS, (const void *)&ls->ptos, sizeof (ls->ptos)); + if (ls && ls->ptos_defined) + { + setsockopt(ls->sd, IPPROTO_IP, IP_TOS, (const void *)&ls->ptos, sizeof(ls->ptos)); + } } -#endif +#endif /* if PASSTOS_CAPABILITY */ /* * Socket I/O wait functions */ static inline bool -socket_read_residual (const struct link_socket *s) +socket_read_residual(const struct link_socket *s) { - return s && s->stream_buf.residual_fully_formed; + return s && s->stream_buf.residual_fully_formed; } static inline event_t -socket_event_handle (const struct link_socket *s) +socket_event_handle(const struct link_socket *s) { #ifdef _WIN32 - return &s->rw_handle; + return &s->rw_handle; #else - return s->sd; + return s->sd; #endif } -event_t socket_listen_event_handle (struct link_socket *s); +event_t socket_listen_event_handle(struct link_socket *s); unsigned int -socket_set (struct link_socket *s, - struct event_set *es, - unsigned int rwflags, - void *arg, - unsigned int *persistent); +socket_set(struct link_socket *s, + struct event_set *es, + unsigned int rwflags, + void *arg, + unsigned int *persistent); static inline void -socket_set_listen_persistent (struct link_socket *s, - struct event_set *es, - void *arg) +socket_set_listen_persistent(struct link_socket *s, + struct event_set *es, + void *arg) { - if (s && !s->listen_persistent_queued) + if (s && !s->listen_persistent_queued) { - event_ctl (es, socket_listen_event_handle (s), EVENT_READ, arg); - s->listen_persistent_queued = true; + event_ctl(es, socket_listen_event_handle(s), EVENT_READ, arg); + s->listen_persistent_queued = true; } } static inline void -socket_reset_listen_persistent (struct link_socket *s) +socket_reset_listen_persistent(struct link_socket *s) { #ifdef _WIN32 - reset_net_event_win32 (&s->listen_handle, s->sd); + reset_net_event_win32(&s->listen_handle, s->sd); #endif } -const char *socket_stat (const struct link_socket *s, unsigned int rwflags, struct gc_arena *gc); +const char *socket_stat(const struct link_socket *s, unsigned int rwflags, struct gc_arena *gc); #endif /* SOCKET_H */ diff --git a/src/openvpn/socks.c b/src/openvpn/socks.c index 5a9ea6cdefe..da4c8247c93 100644 --- a/src/openvpn/socks.c +++ b/src/openvpn/socks.c @@ -48,466 +48,503 @@ #include "memdbg.h" -#define UP_TYPE_SOCKS "SOCKS Proxy" +#define UP_TYPE_SOCKS "SOCKS Proxy" void -socks_adjust_frame_parameters (struct frame *frame, int proto) +socks_adjust_frame_parameters(struct frame *frame, int proto) { - if (proto == PROTO_UDP) - frame_add_to_extra_link (frame, 10); + if (proto == PROTO_UDP) + { + frame_add_to_extra_link(frame, 10); + } } struct socks_proxy_info * -socks_proxy_new (const char *server, - const char *port, - const char *authfile) +socks_proxy_new(const char *server, + const char *port, + const char *authfile) { - struct socks_proxy_info *p; + struct socks_proxy_info *p; - ALLOC_OBJ_CLEAR (p, struct socks_proxy_info); + ALLOC_OBJ_CLEAR(p, struct socks_proxy_info); - ASSERT (server); - ASSERT (port); + ASSERT(server); + ASSERT(port); - strncpynt (p->server, server, sizeof (p->server)); - p->port = port; + strncpynt(p->server, server, sizeof(p->server)); + p->port = port; - if (authfile) - strncpynt (p->authfile, authfile, sizeof (p->authfile)); - else - p->authfile[0] = 0; + if (authfile) + { + strncpynt(p->authfile, authfile, sizeof(p->authfile)); + } + else + { + p->authfile[0] = 0; + } - p->defined = true; + p->defined = true; - return p; + return p; } void -socks_proxy_close (struct socks_proxy_info *sp) -{ - free (sp); -} - -static bool -socks_username_password_auth (struct socks_proxy_info *p, - socket_descriptor_t sd, - volatile int *signal_received) +socks_proxy_close(struct socks_proxy_info *sp) { - char to_send[516]; - char buf[2]; - int len = 0; - const int timeout_sec = 5; - struct user_pass creds; - ssize_t size; - - creds.defined = 0; - if (!get_user_pass (&creds, p->authfile, UP_TYPE_SOCKS, GET_USER_PASS_MANAGEMENT)) - { - msg (M_NONFATAL, "SOCKS failed to get username/password."); - return false; - } - - if( (strlen(creds.username) > 255) || (strlen(creds.password) > 255) ) { - msg (M_NONFATAL, - "SOCKS username and/or password exceeds 255 characters. " - "Authentication not possible."); - return false; - } - openvpn_snprintf (to_send, sizeof (to_send), "\x01%c%s%c%s", (int) strlen(creds.username), - creds.username, (int) strlen(creds.password), creds.password); - size = send (sd, to_send, strlen(to_send), MSG_NOSIGNAL); - - if (size != strlen (to_send)) - { - msg (D_LINK_ERRORS | M_ERRNO, "socks_username_password_auth: TCP port write failed on send()"); - return false; - } - - while (len < 2) - { - int status; - ssize_t size; - fd_set reads; - struct timeval tv; - char c; - - FD_ZERO (&reads); - openvpn_fd_set (sd, &reads); - tv.tv_sec = timeout_sec; - tv.tv_usec = 0; - - status = select (sd + 1, &reads, NULL, NULL, &tv); - - get_signal (signal_received); - if (*signal_received) - return false; - - /* timeout? */ - if (status == 0) - { - msg (D_LINK_ERRORS | M_ERRNO, "socks_username_password_auth: TCP port read timeout expired"); - return false; - } - - /* error */ - if (status < 0) - { - msg (D_LINK_ERRORS | M_ERRNO, "socks_username_password_auth: TCP port read failed on select()"); - return false; - } - - /* read single char */ - size = recv(sd, &c, 1, MSG_NOSIGNAL); - - /* error? */ - if (size != 1) - { - msg (D_LINK_ERRORS | M_ERRNO, "socks_username_password_auth: TCP port read failed on recv()"); - return false; - } - - /* store char in buffer */ - buf[len++] = c; - } - - /* VER = 5, SUCCESS = 0 --> auth success */ - if (buf[0] != 5 && buf[1] != 0) - { - msg (D_LINK_ERRORS, "socks_username_password_auth: server refused the authentication"); - return false; - } - - return true; + free(sp); } static bool -socks_handshake (struct socks_proxy_info *p, - socket_descriptor_t sd, - volatile int *signal_received) +socks_username_password_auth(struct socks_proxy_info *p, + socket_descriptor_t sd, + volatile int *signal_received) { - char buf[2]; - int len = 0; - const int timeout_sec = 5; - ssize_t size; - - /* VER = 5, NMETHODS = 1, METHODS = [0 (no auth)] */ - char method_sel[3] = { 0x05, 0x01, 0x00 }; - if (p->authfile[0]) - method_sel[2] = 0x02; /* METHODS = [2 (plain login)] */ - - size = send (sd, method_sel, sizeof (method_sel), MSG_NOSIGNAL); - if (size != sizeof (method_sel)) + char to_send[516]; + char buf[2]; + int len = 0; + const int timeout_sec = 5; + struct user_pass creds; + ssize_t size; + + creds.defined = 0; + if (!get_user_pass(&creds, p->authfile, UP_TYPE_SOCKS, GET_USER_PASS_MANAGEMENT)) { - msg (D_LINK_ERRORS | M_ERRNO, "socks_handshake: TCP port write failed on send()"); - return false; + msg(M_NONFATAL, "SOCKS failed to get username/password."); + return false; } - while (len < 2) + if ( (strlen(creds.username) > 255) || (strlen(creds.password) > 255) ) { - int status; - ssize_t size; - fd_set reads; - struct timeval tv; - char c; - - FD_ZERO (&reads); - openvpn_fd_set (sd, &reads); - tv.tv_sec = timeout_sec; - tv.tv_usec = 0; - - status = select (sd + 1, &reads, NULL, NULL, &tv); - - get_signal (signal_received); - if (*signal_received) - return false; - - /* timeout? */ - if (status == 0) - { - msg (D_LINK_ERRORS | M_ERRNO, "socks_handshake: TCP port read timeout expired"); - return false; - } - - /* error */ - if (status < 0) - { - msg (D_LINK_ERRORS | M_ERRNO, "socks_handshake: TCP port read failed on select()"); - return false; - } - - /* read single char */ - size = recv(sd, &c, 1, MSG_NOSIGNAL); - - /* error? */ - if (size != 1) - { - msg (D_LINK_ERRORS | M_ERRNO, "socks_handshake: TCP port read failed on recv()"); - return false; - } - - /* store char in buffer */ - buf[len++] = c; + msg(M_NONFATAL, + "SOCKS username and/or password exceeds 255 characters. " + "Authentication not possible."); + return false; } + openvpn_snprintf(to_send, sizeof(to_send), "\x01%c%s%c%s", (int) strlen(creds.username), + creds.username, (int) strlen(creds.password), creds.password); + size = send(sd, to_send, strlen(to_send), MSG_NOSIGNAL); - /* VER == 5 */ - if (buf[0] != '\x05') + if (size != strlen(to_send)) { - msg (D_LINK_ERRORS, "socks_handshake: Socks proxy returned bad status"); - return false; + msg(D_LINK_ERRORS | M_ERRNO, "socks_username_password_auth: TCP port write failed on send()"); + return false; } - /* validate that the auth method returned is the one sent */ - if (buf[1] != method_sel[2]) + while (len < 2) { - msg (D_LINK_ERRORS, "socks_handshake: Socks proxy returned unexpected auth"); - return false; + int status; + ssize_t size; + fd_set reads; + struct timeval tv; + char c; + + FD_ZERO(&reads); + openvpn_fd_set(sd, &reads); + tv.tv_sec = timeout_sec; + tv.tv_usec = 0; + + status = select(sd + 1, &reads, NULL, NULL, &tv); + + get_signal(signal_received); + if (*signal_received) + { + return false; + } + + /* timeout? */ + if (status == 0) + { + msg(D_LINK_ERRORS | M_ERRNO, "socks_username_password_auth: TCP port read timeout expired"); + return false; + } + + /* error */ + if (status < 0) + { + msg(D_LINK_ERRORS | M_ERRNO, "socks_username_password_auth: TCP port read failed on select()"); + return false; + } + + /* read single char */ + size = recv(sd, &c, 1, MSG_NOSIGNAL); + + /* error? */ + if (size != 1) + { + msg(D_LINK_ERRORS | M_ERRNO, "socks_username_password_auth: TCP port read failed on recv()"); + return false; + } + + /* store char in buffer */ + buf[len++] = c; } - /* select the appropriate authentication method */ - switch (buf[1]) + /* VER = 5, SUCCESS = 0 --> auth success */ + if (buf[0] != 5 && buf[1] != 0) { - case 0: /* no authentication */ - break; - - case 2: /* login/password */ - if (!p->authfile[0]) - { - msg(D_LINK_ERRORS, "socks_handshake: server asked for username/login auth but we were " - "not provided any credentials"); - return false; - } - - if (!socks_username_password_auth(p, sd, signal_received)) - return false; - - break; - - default: /* unknown auth method */ - msg(D_LINK_ERRORS, "socks_handshake: unknown SOCKS auth method"); - return false; + msg(D_LINK_ERRORS, "socks_username_password_auth: server refused the authentication"); + return false; } - return true; + return true; } static bool -recv_socks_reply (socket_descriptor_t sd, - struct openvpn_sockaddr *addr, - volatile int *signal_received) +socks_handshake(struct socks_proxy_info *p, + socket_descriptor_t sd, + volatile int *signal_received) { - char atyp = '\0'; - int alen = 0; - int len = 0; - char buf[22]; - const int timeout_sec = 5; + char buf[2]; + int len = 0; + const int timeout_sec = 5; + ssize_t size; + + /* VER = 5, NMETHODS = 1, METHODS = [0 (no auth)] */ + char method_sel[3] = { 0x05, 0x01, 0x00 }; + if (p->authfile[0]) + { + method_sel[2] = 0x02; /* METHODS = [2 (plain login)] */ - if (addr != NULL) + } + size = send(sd, method_sel, sizeof(method_sel), MSG_NOSIGNAL); + if (size != sizeof(method_sel)) { - addr->addr.in4.sin_family = AF_INET; - addr->addr.in4.sin_addr.s_addr = htonl (INADDR_ANY); - addr->addr.in4.sin_port = htons (0); + msg(D_LINK_ERRORS | M_ERRNO, "socks_handshake: TCP port write failed on send()"); + return false; } - while (len < 4 + alen + 2) + while (len < 2) { - int status; - ssize_t size; - fd_set reads; - struct timeval tv; - char c; - - FD_ZERO (&reads); - openvpn_fd_set (sd, &reads); - tv.tv_sec = timeout_sec; - tv.tv_usec = 0; - - status = select (sd + 1, &reads, NULL, NULL, &tv); - - get_signal (signal_received); - if (*signal_received) - return false; - - /* timeout? */ - if (status == 0) - { - msg (D_LINK_ERRORS | M_ERRNO, "recv_socks_reply: TCP port read timeout expired"); - return false; - } - - /* error */ - if (status < 0) - { - msg (D_LINK_ERRORS | M_ERRNO, "recv_socks_reply: TCP port read failed on select()"); - return false; - } - - /* read single char */ - size = recv(sd, &c, 1, MSG_NOSIGNAL); + int status; + ssize_t size; + fd_set reads; + struct timeval tv; + char c; + + FD_ZERO(&reads); + openvpn_fd_set(sd, &reads); + tv.tv_sec = timeout_sec; + tv.tv_usec = 0; + + status = select(sd + 1, &reads, NULL, NULL, &tv); + + get_signal(signal_received); + if (*signal_received) + { + return false; + } + + /* timeout? */ + if (status == 0) + { + msg(D_LINK_ERRORS | M_ERRNO, "socks_handshake: TCP port read timeout expired"); + return false; + } + + /* error */ + if (status < 0) + { + msg(D_LINK_ERRORS | M_ERRNO, "socks_handshake: TCP port read failed on select()"); + return false; + } + + /* read single char */ + size = recv(sd, &c, 1, MSG_NOSIGNAL); + + /* error? */ + if (size != 1) + { + msg(D_LINK_ERRORS | M_ERRNO, "socks_handshake: TCP port read failed on recv()"); + return false; + } + + /* store char in buffer */ + buf[len++] = c; + } - /* error? */ - if (size != 1) - { - msg (D_LINK_ERRORS | M_ERRNO, "recv_socks_reply: TCP port read failed on recv()"); - return false; - } + /* VER == 5 */ + if (buf[0] != '\x05') + { + msg(D_LINK_ERRORS, "socks_handshake: Socks proxy returned bad status"); + return false; + } - if (len == 3) - atyp = c; + /* validate that the auth method returned is the one sent */ + if (buf[1] != method_sel[2]) + { + msg(D_LINK_ERRORS, "socks_handshake: Socks proxy returned unexpected auth"); + return false; + } - if (len == 4) - { - switch (atyp) - { - case '\x01': /* IP V4 */ - alen = 4; - break; + /* select the appropriate authentication method */ + switch (buf[1]) + { + case 0: /* no authentication */ + break; + + case 2: /* login/password */ + if (!p->authfile[0]) + { + msg(D_LINK_ERRORS, "socks_handshake: server asked for username/login auth but we were " + "not provided any credentials"); + return false; + } + + if (!socks_username_password_auth(p, sd, signal_received)) + { + return false; + } + + break; + + default: /* unknown auth method */ + msg(D_LINK_ERRORS, "socks_handshake: unknown SOCKS auth method"); + return false; + } - case '\x03': /* DOMAINNAME */ - alen = (unsigned char) c; - break; + return true; +} - case '\x04': /* IP V6 */ - alen = 16; - break; +static bool +recv_socks_reply(socket_descriptor_t sd, + struct openvpn_sockaddr *addr, + volatile int *signal_received) +{ + char atyp = '\0'; + int alen = 0; + int len = 0; + char buf[22]; + const int timeout_sec = 5; - default: - msg (D_LINK_ERRORS, "recv_socks_reply: Socks proxy returned bad address type"); - return false; - } - } + if (addr != NULL) + { + addr->addr.in4.sin_family = AF_INET; + addr->addr.in4.sin_addr.s_addr = htonl(INADDR_ANY); + addr->addr.in4.sin_port = htons(0); + } - /* store char in buffer */ - if (len < (int)sizeof(buf)) - buf[len] = c; - ++len; + while (len < 4 + alen + 2) + { + int status; + ssize_t size; + fd_set reads; + struct timeval tv; + char c; + + FD_ZERO(&reads); + openvpn_fd_set(sd, &reads); + tv.tv_sec = timeout_sec; + tv.tv_usec = 0; + + status = select(sd + 1, &reads, NULL, NULL, &tv); + + get_signal(signal_received); + if (*signal_received) + { + return false; + } + + /* timeout? */ + if (status == 0) + { + msg(D_LINK_ERRORS | M_ERRNO, "recv_socks_reply: TCP port read timeout expired"); + return false; + } + + /* error */ + if (status < 0) + { + msg(D_LINK_ERRORS | M_ERRNO, "recv_socks_reply: TCP port read failed on select()"); + return false; + } + + /* read single char */ + size = recv(sd, &c, 1, MSG_NOSIGNAL); + + /* error? */ + if (size != 1) + { + msg(D_LINK_ERRORS | M_ERRNO, "recv_socks_reply: TCP port read failed on recv()"); + return false; + } + + if (len == 3) + { + atyp = c; + } + + if (len == 4) + { + switch (atyp) + { + case '\x01': /* IP V4 */ + alen = 4; + break; + + case '\x03': /* DOMAINNAME */ + alen = (unsigned char) c; + break; + + case '\x04': /* IP V6 */ + alen = 16; + break; + + default: + msg(D_LINK_ERRORS, "recv_socks_reply: Socks proxy returned bad address type"); + return false; + } + } + + /* store char in buffer */ + if (len < (int)sizeof(buf)) + { + buf[len] = c; + } + ++len; } - /* VER == 5 && REP == 0 (succeeded) */ - if (buf[0] != '\x05' || buf[1] != '\x00') + /* VER == 5 && REP == 0 (succeeded) */ + if (buf[0] != '\x05' || buf[1] != '\x00') { - msg (D_LINK_ERRORS, "recv_socks_reply: Socks proxy returned bad reply"); - return false; + msg(D_LINK_ERRORS, "recv_socks_reply: Socks proxy returned bad reply"); + return false; } - /* ATYP == 1 (IP V4 address) */ - if (atyp == '\x01' && addr != NULL) + /* ATYP == 1 (IP V4 address) */ + if (atyp == '\x01' && addr != NULL) { - memcpy (&addr->addr.in4.sin_addr, buf + 4, sizeof (addr->addr.in4.sin_addr)); - memcpy (&addr->addr.in4.sin_port, buf + 8, sizeof (addr->addr.in4.sin_port)); + memcpy(&addr->addr.in4.sin_addr, buf + 4, sizeof(addr->addr.in4.sin_addr)); + memcpy(&addr->addr.in4.sin_port, buf + 8, sizeof(addr->addr.in4.sin_port)); } - return true; + return true; } static int -port_from_servname(const char* servname) +port_from_servname(const char *servname) { - int port =0; + int port = 0; port = atoi(servname); - if(port >0 && port < 65536) + if (port >0 && port < 65536) + { return port; + } - struct servent* service; + struct servent *service; service = getservbyname(servname, NULL); - if(service) + if (service) + { return service->s_port; + } return 0; } void -establish_socks_proxy_passthru (struct socks_proxy_info *p, - socket_descriptor_t sd, /* already open to proxy */ - const char *host, /* openvpn server remote */ - const char *servname, /* openvpn server port */ - volatile int *signal_received) +establish_socks_proxy_passthru(struct socks_proxy_info *p, + socket_descriptor_t sd, /* already open to proxy */ + const char *host, /* openvpn server remote */ + const char *servname, /* openvpn server port */ + volatile int *signal_received) { - char buf[128]; - size_t len; + char buf[128]; + size_t len; - if (!socks_handshake (p, sd, signal_received)) - goto error; + if (!socks_handshake(p, sd, signal_received)) + { + goto error; + } - /* format Socks CONNECT message */ - buf[0] = '\x05'; /* VER = 5 */ - buf[1] = '\x01'; /* CMD = 1 (CONNECT) */ - buf[2] = '\x00'; /* RSV */ - buf[3] = '\x03'; /* ATYP = 3 (DOMAINNAME) */ + /* format Socks CONNECT message */ + buf[0] = '\x05'; /* VER = 5 */ + buf[1] = '\x01'; /* CMD = 1 (CONNECT) */ + buf[2] = '\x00'; /* RSV */ + buf[3] = '\x03'; /* ATYP = 3 (DOMAINNAME) */ - len = strlen(host); - len = (5 + len + 2 > sizeof(buf)) ? (sizeof(buf) - 5 - 2) : len; + len = strlen(host); + len = (5 + len + 2 > sizeof(buf)) ? (sizeof(buf) - 5 - 2) : len; - buf[4] = (char) len; - memcpy(buf + 5, host, len); + buf[4] = (char) len; + memcpy(buf + 5, host, len); - int port = port_from_servname (servname); - if (port ==0) + int port = port_from_servname(servname); + if (port ==0) { - msg (D_LINK_ERRORS, "establish_socks_proxy_passthrough: Cannot convert %s to port number", servname); - goto error; + msg(D_LINK_ERRORS, "establish_socks_proxy_passthrough: Cannot convert %s to port number", servname); + goto error; } - buf[5 + len] = (char) (port >> 8); - buf[5 + len + 1] = (char) (port & 0xff); + buf[5 + len] = (char) (port >> 8); + buf[5 + len + 1] = (char) (port & 0xff); - { - const ssize_t size = send (sd, buf, 5 + len + 2, MSG_NOSIGNAL); - if ((int)size != 5 + (int)len + 2) - { - msg (D_LINK_ERRORS | M_ERRNO, "establish_socks_proxy_passthru: TCP port write failed on send()"); - goto error; - } - } + { + const ssize_t size = send(sd, buf, 5 + len + 2, MSG_NOSIGNAL); + if ((int)size != 5 + (int)len + 2) + { + msg(D_LINK_ERRORS | M_ERRNO, "establish_socks_proxy_passthru: TCP port write failed on send()"); + goto error; + } + } - /* receive reply from Socks proxy and discard */ - if (!recv_socks_reply (sd, NULL, signal_received)) - goto error; + /* receive reply from Socks proxy and discard */ + if (!recv_socks_reply(sd, NULL, signal_received)) + { + goto error; + } - return; + return; - error: - if (!*signal_received) - *signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- socks error */ - return; +error: + if (!*signal_received) + { + *signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- socks error */ + } + return; } void -establish_socks_proxy_udpassoc (struct socks_proxy_info *p, - socket_descriptor_t ctrl_sd, /* already open to proxy */ - socket_descriptor_t udp_sd, - struct openvpn_sockaddr *relay_addr, - volatile int *signal_received) +establish_socks_proxy_udpassoc(struct socks_proxy_info *p, + socket_descriptor_t ctrl_sd, /* already open to proxy */ + socket_descriptor_t udp_sd, + struct openvpn_sockaddr *relay_addr, + volatile int *signal_received) { - if (!socks_handshake (p, ctrl_sd, signal_received)) - goto error; - - { - /* send Socks UDP ASSOCIATE message */ - /* VER = 5, CMD = 3 (UDP ASSOCIATE), RSV = 0, ATYP = 1 (IP V4), - BND.ADDR = 0, BND.PORT = 0 */ - const ssize_t size = send (ctrl_sd, - "\x05\x03\x00\x01\x00\x00\x00\x00\x00\x00", - 10, MSG_NOSIGNAL); - if (size != 10) - { - msg (D_LINK_ERRORS | M_ERRNO, "establish_socks_proxy_passthru: TCP port write failed on send()"); - goto error; - } - } - - /* receive reply from Socks proxy */ - CLEAR (*relay_addr); - if (!recv_socks_reply (ctrl_sd, relay_addr, signal_received)) - goto error; - - return; - - error: - if (!*signal_received) - *signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- socks error */ - return; + if (!socks_handshake(p, ctrl_sd, signal_received)) + { + goto error; + } + + { + /* send Socks UDP ASSOCIATE message */ + /* VER = 5, CMD = 3 (UDP ASSOCIATE), RSV = 0, ATYP = 1 (IP V4), + * BND.ADDR = 0, BND.PORT = 0 */ + const ssize_t size = send(ctrl_sd, + "\x05\x03\x00\x01\x00\x00\x00\x00\x00\x00", + 10, MSG_NOSIGNAL); + if (size != 10) + { + msg(D_LINK_ERRORS | M_ERRNO, "establish_socks_proxy_passthru: TCP port write failed on send()"); + goto error; + } + } + + /* receive reply from Socks proxy */ + CLEAR(*relay_addr); + if (!recv_socks_reply(ctrl_sd, relay_addr, signal_received)) + { + goto error; + } + + return; + +error: + if (!*signal_received) + { + *signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- socks error */ + } + return; } /* @@ -517,29 +554,35 @@ establish_socks_proxy_udpassoc (struct socks_proxy_info *p, * Run after UDP read. */ void -socks_process_incoming_udp (struct buffer *buf, - struct link_socket_actual *from) +socks_process_incoming_udp(struct buffer *buf, + struct link_socket_actual *from) { - int atyp; + int atyp; - if (BLEN (buf) < 10) - goto error; + if (BLEN(buf) < 10) + { + goto error; + } - buf_read_u16 (buf); - if (buf_read_u8 (buf) != 0) - goto error; + buf_read_u16(buf); + if (buf_read_u8(buf) != 0) + { + goto error; + } - atyp = buf_read_u8 (buf); - if (atyp != 1) /* ATYP == 1 (IP V4) */ - goto error; + atyp = buf_read_u8(buf); + if (atyp != 1) /* ATYP == 1 (IP V4) */ + { + goto error; + } - buf_read (buf, &from->dest.addr.in4.sin_addr, sizeof (from->dest.addr.in4.sin_addr)); - buf_read (buf, &from->dest.addr.in4.sin_port, sizeof (from->dest.addr.in4.sin_port)); + buf_read(buf, &from->dest.addr.in4.sin_addr, sizeof(from->dest.addr.in4.sin_addr)); + buf_read(buf, &from->dest.addr.in4.sin_port, sizeof(from->dest.addr.in4.sin_port)); - return; + return; - error: - buf->len = 0; +error: + buf->len = 0; } /* @@ -550,24 +593,24 @@ socks_process_incoming_udp (struct buffer *buf, * Returns the size of the header. */ int -socks_process_outgoing_udp (struct buffer *buf, - const struct link_socket_actual *to) +socks_process_outgoing_udp(struct buffer *buf, + const struct link_socket_actual *to) { - /* - * Get a 10 byte subset buffer prepended to buf -- - * we expect these bytes will be here because - * we allocated frame space in socks_adjust_frame_parameters. - */ - struct buffer head = buf_sub (buf, 10, true); - - /* crash if not enough headroom in buf */ - ASSERT (buf_defined (&head)); - - buf_write_u16 (&head, 0); /* RSV = 0 */ - buf_write_u8 (&head, 0); /* FRAG = 0 */ - buf_write_u8 (&head, '\x01'); /* ATYP = 1 (IP V4) */ - buf_write (&head, &to->dest.addr.in4.sin_addr, sizeof (to->dest.addr.in4.sin_addr)); - buf_write (&head, &to->dest.addr.in4.sin_port, sizeof (to->dest.addr.in4.sin_port)); - - return 10; + /* + * Get a 10 byte subset buffer prepended to buf -- + * we expect these bytes will be here because + * we allocated frame space in socks_adjust_frame_parameters. + */ + struct buffer head = buf_sub(buf, 10, true); + + /* crash if not enough headroom in buf */ + ASSERT(buf_defined(&head)); + + buf_write_u16(&head, 0); /* RSV = 0 */ + buf_write_u8(&head, 0); /* FRAG = 0 */ + buf_write_u8(&head, '\x01'); /* ATYP = 1 (IP V4) */ + buf_write(&head, &to->dest.addr.in4.sin_addr, sizeof(to->dest.addr.in4.sin_addr)); + buf_write(&head, &to->dest.addr.in4.sin_port, sizeof(to->dest.addr.in4.sin_port)); + + return 10; } diff --git a/src/openvpn/socks.h b/src/openvpn/socks.h index a2843b9b446..d0b18f164fa 100644 --- a/src/openvpn/socks.h +++ b/src/openvpn/socks.h @@ -36,37 +36,37 @@ struct openvpn_sockaddr; struct link_socket_actual; struct socks_proxy_info { - bool defined; + bool defined; - char server[128]; - const char *port; - char authfile[256]; + char server[128]; + const char *port; + char authfile[256]; }; -void socks_adjust_frame_parameters (struct frame *frame, int proto); +void socks_adjust_frame_parameters(struct frame *frame, int proto); -struct socks_proxy_info *socks_proxy_new (const char *server, - const char *port, - const char *authfile); +struct socks_proxy_info *socks_proxy_new(const char *server, + const char *port, + const char *authfile); -void socks_proxy_close (struct socks_proxy_info *sp); +void socks_proxy_close(struct socks_proxy_info *sp); -void establish_socks_proxy_passthru (struct socks_proxy_info *p, - socket_descriptor_t sd, /* already open to proxy */ - const char *host, /* openvpn server remote */ - const char *servname, /* openvpn server port */ - volatile int *signal_received); +void establish_socks_proxy_passthru(struct socks_proxy_info *p, + socket_descriptor_t sd, /* already open to proxy */ + const char *host, /* openvpn server remote */ + const char *servname, /* openvpn server port */ + volatile int *signal_received); -void establish_socks_proxy_udpassoc (struct socks_proxy_info *p, - socket_descriptor_t ctrl_sd, /* already open to proxy */ - socket_descriptor_t udp_sd, - struct openvpn_sockaddr *relay_addr, - volatile int *signal_received); +void establish_socks_proxy_udpassoc(struct socks_proxy_info *p, + socket_descriptor_t ctrl_sd, /* already open to proxy */ + socket_descriptor_t udp_sd, + struct openvpn_sockaddr *relay_addr, + volatile int *signal_received); -void socks_process_incoming_udp (struct buffer *buf, - struct link_socket_actual *from); +void socks_process_incoming_udp(struct buffer *buf, + struct link_socket_actual *from); -int socks_process_outgoing_udp (struct buffer *buf, - const struct link_socket_actual *to); +int socks_process_outgoing_udp(struct buffer *buf, + const struct link_socket_actual *to); -#endif +#endif /* ifndef SOCKS_H */ diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index f7217d38a4c..1022fb6409f 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -70,12 +70,12 @@ static const char ssl_default_options_string[] = "V0 UNDEF"; #endif static inline const char * -local_options_string (const struct tls_session *session) +local_options_string(const struct tls_session *session) { #ifdef ENABLE_OCC - return session->opt->local_options; + return session->opt->local_options; #else - return ssl_default_options_string; + return ssl_default_options_string; #endif } @@ -94,19 +94,19 @@ static int tls_packets_sent; /* GLOBAL */ void show_tls_performance_stats(void) { - msg (D_TLS_DEBUG_LOW, "TLS Handshakes, success=%f%% (good=%d, bad=%d), retransmits=%f%%", - (double) tls_handshake_success / (tls_handshake_success + tls_handshake_error) * 100.0, - tls_handshake_success, tls_handshake_error, - (double) (tls_packets_sent - tls_packets_generated) / tls_packets_generated * 100.0); + msg(D_TLS_DEBUG_LOW, "TLS Handshakes, success=%f%% (good=%d, bad=%d), retransmits=%f%%", + (double) tls_handshake_success / (tls_handshake_success + tls_handshake_error) * 100.0, + tls_handshake_success, tls_handshake_error, + (double) (tls_packets_sent - tls_packets_generated) / tls_packets_generated * 100.0); } -#else +#else /* ifdef MEASURE_TLS_HANDSHAKE_STATS */ #define INCR_SENT #define INCR_GENERATED #define INCR_SUCCESS #define INCR_ERROR -#endif +#endif /* ifdef MEASURE_TLS_HANDSHAKE_STATS */ /** * SSL/TLS Cipher suite name translation table @@ -261,47 +261,48 @@ static const tls_cipher_name_pair tls_cipher_name_translation_table[] = { * Note that the implicit IV is based on the HMAC key, but only in AEAD modes * where the HMAC key is not used for an actual HMAC. * - * @param ctx Encrypt/decrypt key context - * @param key HMAC key, used to calculate implicit IV - * @param key_len HMAC key length + * @param ctx Encrypt/decrypt key context + * @param key HMAC key, used to calculate implicit IV + * @param key_len HMAC key length */ static void key_ctx_update_implicit_iv(struct key_ctx *ctx, uint8_t *key, size_t key_len); const tls_cipher_name_pair * -tls_get_cipher_name_pair (const char * cipher_name, size_t len) { - const tls_cipher_name_pair * pair = tls_cipher_name_translation_table; +tls_get_cipher_name_pair(const char *cipher_name, size_t len) { + const tls_cipher_name_pair *pair = tls_cipher_name_translation_table; - while (pair->openssl_name != NULL) { - if ((strlen(pair->openssl_name) == len && 0 == memcmp (cipher_name, pair->openssl_name, len)) || - (strlen(pair->iana_name) == len && 0 == memcmp (cipher_name, pair->iana_name, len))) { - return pair; - } - pair++; - } + while (pair->openssl_name != NULL) { + if ((strlen(pair->openssl_name) == len && 0 == memcmp(cipher_name, pair->openssl_name, len)) + || (strlen(pair->iana_name) == len && 0 == memcmp(cipher_name, pair->iana_name, len))) + { + return pair; + } + pair++; + } - // No entry found, return NULL - return NULL; + /* No entry found, return NULL */ + return NULL; } /** * Limit the reneg_bytes value when using a small-block (<128 bytes) cipher. * - * @param cipher The current cipher (may be NULL). - * @param reneg_bytes Pointer to the current reneg_bytes, updated if needed. - * May *not* be NULL. + * @param cipher The current cipher (may be NULL). + * @param reneg_bytes Pointer to the current reneg_bytes, updated if needed. + * May *not* be NULL. */ static void -tls_limit_reneg_bytes (const cipher_kt_t *cipher, int *reneg_bytes) +tls_limit_reneg_bytes(const cipher_kt_t *cipher, int *reneg_bytes) { - if (cipher && (cipher_kt_block_size(cipher) < 128/8)) + if (cipher && (cipher_kt_block_size(cipher) < 128/8)) { - if (*reneg_bytes == -1) /* Not user-specified */ - { - msg (M_WARN, "WARNING: cipher with small block size in use, " - "reducing reneg-bytes to 64MB to mitigate SWEET32 attacks."); - *reneg_bytes = 64 * 1024 * 1024; - } + if (*reneg_bytes == -1) /* Not user-specified */ + { + msg(M_WARN, "WARNING: cipher with small block size in use, " + "reducing reneg-bytes to 64MB to mitigate SWEET32 attacks."); + *reneg_bytes = 64 * 1024 * 1024; + } } } @@ -314,51 +315,51 @@ tls_limit_reneg_bytes (const cipher_kt_t *cipher, int *reneg_bytes) void tls_adjust_frame_parameters(struct frame *frame) { - frame_add_to_extra_frame (frame, 1); /* space for opcode */ + frame_add_to_extra_frame(frame, 1); /* space for opcode */ } /* * Max number of bytes we will add - * to control channel packet. + * to control channel packet. */ static void tls_init_control_channel_frame_parameters(const struct frame *data_channel_frame, - struct frame *frame) + struct frame *frame) { - /* - * frame->extra_frame is already initialized with tls_auth buffer requirements, - * if --tls-auth is enabled. - */ - - /* inherit link MTU and extra_link from data channel */ - frame->link_mtu = data_channel_frame->link_mtu; - frame->extra_link = data_channel_frame->extra_link; - - /* set extra_frame */ - tls_adjust_frame_parameters (frame); - reliable_ack_adjust_frame_parameters (frame, CONTROL_SEND_ACK_MAX); - frame_add_to_extra_frame (frame, SID_SIZE + sizeof (packet_id_type)); - - /* set dynamic link MTU to cap control channel packets at 1250 bytes */ - ASSERT (TUN_LINK_DELTA (frame) < min_int (frame->link_mtu, 1250)); - frame->link_mtu_dynamic = min_int (frame->link_mtu, 1250) - TUN_LINK_DELTA (frame); + /* + * frame->extra_frame is already initialized with tls_auth buffer requirements, + * if --tls-auth is enabled. + */ + + /* inherit link MTU and extra_link from data channel */ + frame->link_mtu = data_channel_frame->link_mtu; + frame->extra_link = data_channel_frame->extra_link; + + /* set extra_frame */ + tls_adjust_frame_parameters(frame); + reliable_ack_adjust_frame_parameters(frame, CONTROL_SEND_ACK_MAX); + frame_add_to_extra_frame(frame, SID_SIZE + sizeof(packet_id_type)); + + /* set dynamic link MTU to cap control channel packets at 1250 bytes */ + ASSERT(TUN_LINK_DELTA(frame) < min_int(frame->link_mtu, 1250)); + frame->link_mtu_dynamic = min_int(frame->link_mtu, 1250) - TUN_LINK_DELTA(frame); } void -init_ssl_lib () +init_ssl_lib() { - tls_init_lib (); + tls_init_lib(); - crypto_init_lib (); + crypto_init_lib(); } void -free_ssl_lib () +free_ssl_lib() { - crypto_uninit_lib (); - prng_uninit(); - - tls_free_lib(); + crypto_uninit_lib(); + prng_uninit(); + + tls_free_lib(); } /* @@ -369,25 +370,27 @@ free_ssl_lib () static struct user_pass passbuf; /* GLOBAL */ void -pem_password_setup (const char *auth_file) +pem_password_setup(const char *auth_file) { - if (!strlen (passbuf.password)) - get_user_pass (&passbuf, auth_file, UP_TYPE_PRIVATE_KEY, GET_USER_PASS_MANAGEMENT|GET_USER_PASS_PASSWORD_ONLY); + if (!strlen(passbuf.password)) + { + get_user_pass(&passbuf, auth_file, UP_TYPE_PRIVATE_KEY, GET_USER_PASS_MANAGEMENT|GET_USER_PASS_PASSWORD_ONLY); + } } int -pem_password_callback (char *buf, int size, int rwflag, void *u) +pem_password_callback(char *buf, int size, int rwflag, void *u) { - if (buf) + if (buf) { - /* prompt for password even if --askpass wasn't specified */ - pem_password_setup (NULL); - strncpynt (buf, passbuf.password, size); - purge_user_pass (&passbuf, false); + /* prompt for password even if --askpass wasn't specified */ + pem_password_setup(NULL); + strncpynt(buf, passbuf.password, size); + purge_user_pass(&passbuf, false); - return strlen (buf); + return strlen(buf); } - return 0; + return 0; } /* @@ -402,36 +405,40 @@ static char *auth_challenge; /* GLOBAL */ #endif void -auth_user_pass_setup (const char *auth_file, const struct static_challenge_info *sci) +auth_user_pass_setup(const char *auth_file, const struct static_challenge_info *sci) { - auth_user_pass_enabled = true; - if (!auth_user_pass.defined) + auth_user_pass_enabled = true; + if (!auth_user_pass.defined) { #if AUTO_USERID - get_user_pass_auto_userid (&auth_user_pass, auth_file); + get_user_pass_auto_userid(&auth_user_pass, auth_file); #else -# ifdef ENABLE_CLIENT_CR - if (auth_challenge) /* dynamic challenge/response */ - get_user_pass_cr (&auth_user_pass, - auth_file, - UP_TYPE_AUTH, - GET_USER_PASS_MANAGEMENT|GET_USER_PASS_DYNAMIC_CHALLENGE, - auth_challenge); - else if (sci) /* static challenge response */ - { - int flags = GET_USER_PASS_MANAGEMENT|GET_USER_PASS_STATIC_CHALLENGE; - if (sci->flags & SC_ECHO) - flags |= GET_USER_PASS_STATIC_CHALLENGE_ECHO; - get_user_pass_cr (&auth_user_pass, - auth_file, - UP_TYPE_AUTH, - flags, - sci->challenge_text); - } - else -# endif - get_user_pass (&auth_user_pass, auth_file, UP_TYPE_AUTH, GET_USER_PASS_MANAGEMENT); -#endif +#ifdef ENABLE_CLIENT_CR + if (auth_challenge) /* dynamic challenge/response */ + { + get_user_pass_cr(&auth_user_pass, + auth_file, + UP_TYPE_AUTH, + GET_USER_PASS_MANAGEMENT|GET_USER_PASS_DYNAMIC_CHALLENGE, + auth_challenge); + } + else if (sci) /* static challenge response */ + { + int flags = GET_USER_PASS_MANAGEMENT|GET_USER_PASS_STATIC_CHALLENGE; + if (sci->flags & SC_ECHO) + { + flags |= GET_USER_PASS_STATIC_CHALLENGE_ECHO; + } + get_user_pass_cr(&auth_user_pass, + auth_file, + UP_TYPE_AUTH, + flags, + sci->challenge_text); + } + else +#endif /* ifdef ENABLE_CLIENT_CR */ + get_user_pass(&auth_user_pass, auth_file, UP_TYPE_AUTH, GET_USER_PASS_MANAGEMENT); +#endif /* if AUTO_USERID */ } } @@ -439,54 +446,54 @@ auth_user_pass_setup (const char *auth_file, const struct static_challenge_info * Disable password caching */ void -ssl_set_auth_nocache (void) +ssl_set_auth_nocache(void) { - passbuf.nocache = true; - auth_user_pass.nocache = true; + passbuf.nocache = true; + auth_user_pass.nocache = true; } /* * Set an authentication token */ void -ssl_set_auth_token (const char *token) +ssl_set_auth_token(const char *token) { - set_auth_token (&auth_user_pass, token); + set_auth_token(&auth_user_pass, token); } /* * Forget private key password AND auth-user-pass username/password. */ void -ssl_purge_auth (const bool auth_user_pass_only) +ssl_purge_auth(const bool auth_user_pass_only) { - if (!auth_user_pass_only) + if (!auth_user_pass_only) { #ifdef ENABLE_PKCS11 - pkcs11_logout (); + pkcs11_logout(); #endif - purge_user_pass (&passbuf, true); + purge_user_pass(&passbuf, true); } - purge_user_pass (&auth_user_pass, true); + purge_user_pass(&auth_user_pass, true); #ifdef ENABLE_CLIENT_CR - ssl_purge_auth_challenge(); + ssl_purge_auth_challenge(); #endif } #ifdef ENABLE_CLIENT_CR void -ssl_purge_auth_challenge (void) +ssl_purge_auth_challenge(void) { - free (auth_challenge); - auth_challenge = NULL; + free(auth_challenge); + auth_challenge = NULL; } void -ssl_put_auth_challenge (const char *cr_str) +ssl_put_auth_challenge(const char *cr_str) { - ssl_purge_auth_challenge(); - auth_challenge = string_alloc(cr_str, NULL); + ssl_purge_auth_challenge(); + auth_challenge = string_alloc(cr_str, NULL); } #endif @@ -499,17 +506,27 @@ ssl_put_auth_challenge (const char *cr_str) int tls_version_parse(const char *vstr, const char *extra) { - const int max_version = tls_version_max(); - if (!strcmp(vstr, "1.0") && TLS_VER_1_0 <= max_version) - return TLS_VER_1_0; - else if (!strcmp(vstr, "1.1") && TLS_VER_1_1 <= max_version) - return TLS_VER_1_1; - else if (!strcmp(vstr, "1.2") && TLS_VER_1_2 <= max_version) - return TLS_VER_1_2; - else if (extra && !strcmp(extra, "or-highest")) - return max_version; - else - return TLS_VER_BAD; + const int max_version = tls_version_max(); + if (!strcmp(vstr, "1.0") && TLS_VER_1_0 <= max_version) + { + return TLS_VER_1_0; + } + else if (!strcmp(vstr, "1.1") && TLS_VER_1_1 <= max_version) + { + return TLS_VER_1_1; + } + else if (!strcmp(vstr, "1.2") && TLS_VER_1_2 <= max_version) + { + return TLS_VER_1_2; + } + else if (extra && !strcmp(extra, "or-highest")) + { + return max_version; + } + else + { + return TLS_VER_BAD; + } } /** @@ -525,39 +542,41 @@ tls_version_parse(const char *vstr, const char *extra) */ static void tls_ctx_reload_crl(struct tls_root_ctx *ssl_ctx, const char *crl_file, - const char *crl_file_inline) + const char *crl_file_inline) { - /* if something goes wrong with stat(), we'll store 0 as mtime */ - platform_stat_t crl_stat = {0}; - - /* - * an inline CRL can't change at runtime, therefore there is no need to - * reload it. It will be reloaded upon config change + SIGHUP. - * Use always '1' as dummy timestamp in this case: it will trigger the - * first load, but will prevent any future reload. - */ - if (crl_file_inline) + /* if something goes wrong with stat(), we'll store 0 as mtime */ + platform_stat_t crl_stat = {0}; + + /* + * an inline CRL can't change at runtime, therefore there is no need to + * reload it. It will be reloaded upon config change + SIGHUP. + * Use always '1' as dummy timestamp in this case: it will trigger the + * first load, but will prevent any future reload. + */ + if (crl_file_inline) { - crl_stat.st_mtime = 1; + crl_stat.st_mtime = 1; } - else if (platform_stat(crl_file, &crl_stat) < 0) + else if (platform_stat(crl_file, &crl_stat) < 0) { - msg(M_WARN, "WARNING: Failed to stat CRL file, not (re)loading CRL."); - return; + msg(M_WARN, "WARNING: Failed to stat CRL file, not (re)loading CRL."); + return; } - /* - * Store the CRL if this is the first time or if the file was changed since - * the last load. - * Note: Windows does not support tv_nsec. - */ - if ((ssl_ctx->crl_last_size == crl_stat.st_size) && - (ssl_ctx->crl_last_mtime.tv_sec == crl_stat.st_mtime)) - return; + /* + * Store the CRL if this is the first time or if the file was changed since + * the last load. + * Note: Windows does not support tv_nsec. + */ + if ((ssl_ctx->crl_last_size == crl_stat.st_size) + && (ssl_ctx->crl_last_mtime.tv_sec == crl_stat.st_mtime)) + { + return; + } - ssl_ctx->crl_last_mtime.tv_sec = crl_stat.st_mtime; - ssl_ctx->crl_last_size = crl_stat.st_size; - backend_tls_ctx_reload_crl(ssl_ctx, crl_file, crl_file_inline); + ssl_ctx->crl_last_mtime.tv_sec = crl_stat.st_mtime; + ssl_ctx->crl_last_size = crl_stat.st_size; + backend_tls_ctx_reload_crl(ssl_ctx, crl_file, crl_file_inline); } /* @@ -565,197 +584,229 @@ tls_ctx_reload_crl(struct tls_root_ctx *ssl_ctx, const char *crl_file, * All files are in PEM format. */ void -init_ssl (const struct options *options, struct tls_root_ctx *new_ctx) +init_ssl(const struct options *options, struct tls_root_ctx *new_ctx) { - ASSERT(NULL != new_ctx); + ASSERT(NULL != new_ctx); - tls_clear_error(); + tls_clear_error(); - if (options->tls_server) + if (options->tls_server) { - tls_ctx_server_new(new_ctx); + tls_ctx_server_new(new_ctx); - if (options->dh_file) - tls_ctx_load_dh_params(new_ctx, options->dh_file, - options->dh_file_inline); + if (options->dh_file) + { + tls_ctx_load_dh_params(new_ctx, options->dh_file, + options->dh_file_inline); + } } - else /* if client */ + else /* if client */ { - tls_ctx_client_new(new_ctx); + tls_ctx_client_new(new_ctx); } - tls_ctx_set_options(new_ctx, options->ssl_flags); + tls_ctx_set_options(new_ctx, options->ssl_flags); - if (options->pkcs12_file) + if (options->pkcs12_file) { - if (0 != tls_ctx_load_pkcs12(new_ctx, options->pkcs12_file, - options->pkcs12_file_inline, !options->ca_file)) - goto err; + if (0 != tls_ctx_load_pkcs12(new_ctx, options->pkcs12_file, + options->pkcs12_file_inline, !options->ca_file)) + { + goto err; + } } #ifdef ENABLE_PKCS11 - else if (options->pkcs11_providers[0]) + else if (options->pkcs11_providers[0]) { - if (!tls_ctx_use_pkcs11 (new_ctx, options->pkcs11_id_management, options->pkcs11_id)) - { - msg (M_WARN, "Cannot load certificate \"%s\" using PKCS#11 interface", - options->pkcs11_id); - goto err; - } + if (!tls_ctx_use_pkcs11(new_ctx, options->pkcs11_id_management, options->pkcs11_id)) + { + msg(M_WARN, "Cannot load certificate \"%s\" using PKCS#11 interface", + options->pkcs11_id); + goto err; + } } #endif #ifdef ENABLE_CRYPTOAPI - else if (options->cryptoapi_cert) + else if (options->cryptoapi_cert) { - tls_ctx_load_cryptoapi(new_ctx, options->cryptoapi_cert); + tls_ctx_load_cryptoapi(new_ctx, options->cryptoapi_cert); } #endif #ifdef MANAGMENT_EXTERNAL_KEY - else if ((options->management_flags & MF_EXTERNAL_KEY) && - (options->cert_file || options->management_flags & MF_EXTERNAL_CERT)) - { - if (options->cert_file) { - tls_ctx_use_external_private_key(new_ctx, options->cert_file, - options->cert_file_inline); - } else { - char *external_certificate = management_query_cert(management, - options->management_certificate); - tls_ctx_use_external_private_key(new_ctx, INLINE_FILE_TAG, - external_certificate); - free(external_certificate); - } + else if ((options->management_flags & MF_EXTERNAL_KEY) + && (options->cert_file || options->management_flags & MF_EXTERNAL_CERT)) + { + if (options->cert_file) + { + tls_ctx_use_external_private_key(new_ctx, options->cert_file, + options->cert_file_inline); + } + else + { + char *external_certificate = management_query_cert(management, + options->management_certificate); + tls_ctx_use_external_private_key(new_ctx, INLINE_FILE_TAG, + external_certificate); + free(external_certificate); + } } #endif - else - { - /* Load Certificate */ - if (options->cert_file) - { - tls_ctx_load_cert_file(new_ctx, options->cert_file, options->cert_file_inline); - } - - /* Load Private Key */ - if (options->priv_key_file) - { - if (0 != tls_ctx_load_priv_file(new_ctx, options->priv_key_file, options->priv_key_file_inline)) - goto err; - } + else + { + /* Load Certificate */ + if (options->cert_file) + { + tls_ctx_load_cert_file(new_ctx, options->cert_file, options->cert_file_inline); + } + + /* Load Private Key */ + if (options->priv_key_file) + { + if (0 != tls_ctx_load_priv_file(new_ctx, options->priv_key_file, options->priv_key_file_inline)) + { + goto err; + } + } } - if (options->ca_file || options->ca_path) + if (options->ca_file || options->ca_path) { - tls_ctx_load_ca(new_ctx, options->ca_file, options->ca_file_inline, - options->ca_path, options->tls_server); + tls_ctx_load_ca(new_ctx, options->ca_file, options->ca_file_inline, + options->ca_path, options->tls_server); } - /* Load extra certificates that are part of our own certificate - chain but shouldn't be included in the verify chain */ - if (options->extra_certs_file) + /* Load extra certificates that are part of our own certificate + * chain but shouldn't be included in the verify chain */ + if (options->extra_certs_file) { - tls_ctx_load_extra_certs(new_ctx, options->extra_certs_file, options->extra_certs_file_inline); + tls_ctx_load_extra_certs(new_ctx, options->extra_certs_file, options->extra_certs_file_inline); } - /* Check certificate notBefore and notAfter */ - tls_ctx_check_cert_time(new_ctx); + /* Check certificate notBefore and notAfter */ + tls_ctx_check_cert_time(new_ctx); - /* Read CRL */ - if (options->crl_file && !(options->ssl_flags & SSLF_CRL_VERIFY_DIR)) + /* Read CRL */ + if (options->crl_file && !(options->ssl_flags & SSLF_CRL_VERIFY_DIR)) { - tls_ctx_reload_crl(new_ctx, options->crl_file, options->crl_file_inline); + tls_ctx_reload_crl(new_ctx, options->crl_file, options->crl_file_inline); } - /* Once keys and cert are loaded, load ECDH parameters */ - if (options->tls_server) - tls_ctx_load_ecdh_params(new_ctx, options->ecdh_curve); + /* Once keys and cert are loaded, load ECDH parameters */ + if (options->tls_server) + { + tls_ctx_load_ecdh_params(new_ctx, options->ecdh_curve); + } - /* Allowable ciphers */ - tls_ctx_restrict_ciphers(new_ctx, options->cipher_list); + /* Allowable ciphers */ + tls_ctx_restrict_ciphers(new_ctx, options->cipher_list); #ifdef ENABLE_CRYPTO_MBEDTLS - /* Personalise the random by mixing in the certificate */ - tls_ctx_personalise_random (new_ctx); + /* Personalise the random by mixing in the certificate */ + tls_ctx_personalise_random(new_ctx); #endif - tls_clear_error (); - return; + tls_clear_error(); + return; - err: - tls_clear_error (); - tls_ctx_free (new_ctx); - return; +err: + tls_clear_error(); + tls_ctx_free(new_ctx); + return; } /* * Map internal constants to ascii names. */ static const char * -state_name (int state) -{ - switch (state) - { - case S_UNDEF: - return "S_UNDEF"; - case S_INITIAL: - return "S_INITIAL"; - case S_PRE_START: - return "S_PRE_START"; - case S_START: - return "S_START"; - case S_SENT_KEY: - return "S_SENT_KEY"; - case S_GOT_KEY: - return "S_GOT_KEY"; - case S_ACTIVE: - return "S_ACTIVE"; - case S_NORMAL_OP: - return "S_NORMAL_OP"; - case S_ERROR: - return "S_ERROR"; - default: - return "S_???"; +state_name(int state) +{ + switch (state) + { + case S_UNDEF: + return "S_UNDEF"; + + case S_INITIAL: + return "S_INITIAL"; + + case S_PRE_START: + return "S_PRE_START"; + + case S_START: + return "S_START"; + + case S_SENT_KEY: + return "S_SENT_KEY"; + + case S_GOT_KEY: + return "S_GOT_KEY"; + + case S_ACTIVE: + return "S_ACTIVE"; + + case S_NORMAL_OP: + return "S_NORMAL_OP"; + + case S_ERROR: + return "S_ERROR"; + + default: + return "S_???"; } } static const char * -packet_opcode_name (int op) -{ - switch (op) - { - case P_CONTROL_HARD_RESET_CLIENT_V1: - return "P_CONTROL_HARD_RESET_CLIENT_V1"; - case P_CONTROL_HARD_RESET_SERVER_V1: - return "P_CONTROL_HARD_RESET_SERVER_V1"; - case P_CONTROL_HARD_RESET_CLIENT_V2: - return "P_CONTROL_HARD_RESET_CLIENT_V2"; - case P_CONTROL_HARD_RESET_SERVER_V2: - return "P_CONTROL_HARD_RESET_SERVER_V2"; - case P_CONTROL_SOFT_RESET_V1: - return "P_CONTROL_SOFT_RESET_V1"; - case P_CONTROL_V1: - return "P_CONTROL_V1"; - case P_ACK_V1: - return "P_ACK_V1"; - case P_DATA_V1: - return "P_DATA_V1"; - case P_DATA_V2: - return "P_DATA_V2"; - default: - return "P_???"; +packet_opcode_name(int op) +{ + switch (op) + { + case P_CONTROL_HARD_RESET_CLIENT_V1: + return "P_CONTROL_HARD_RESET_CLIENT_V1"; + + case P_CONTROL_HARD_RESET_SERVER_V1: + return "P_CONTROL_HARD_RESET_SERVER_V1"; + + case P_CONTROL_HARD_RESET_CLIENT_V2: + return "P_CONTROL_HARD_RESET_CLIENT_V2"; + + case P_CONTROL_HARD_RESET_SERVER_V2: + return "P_CONTROL_HARD_RESET_SERVER_V2"; + + case P_CONTROL_SOFT_RESET_V1: + return "P_CONTROL_SOFT_RESET_V1"; + + case P_CONTROL_V1: + return "P_CONTROL_V1"; + + case P_ACK_V1: + return "P_ACK_V1"; + + case P_DATA_V1: + return "P_DATA_V1"; + + case P_DATA_V2: + return "P_DATA_V2"; + + default: + return "P_???"; } } static const char * -session_index_name (int index) +session_index_name(int index) { - switch (index) + switch (index) { - case TM_ACTIVE: - return "TM_ACTIVE"; - case TM_UNTRUSTED: - return "TM_UNTRUSTED"; - case TM_LAME_DUCK: - return "TM_LAME_DUCK"; - default: - return "TM_???"; + case TM_ACTIVE: + return "TM_ACTIVE"; + + case TM_UNTRUSTED: + return "TM_UNTRUSTED"; + + case TM_LAME_DUCK: + return "TM_LAME_DUCK"; + + default: + return "TM_???"; } } @@ -763,20 +814,20 @@ session_index_name (int index) * For debugging. */ static const char * -print_key_id (struct tls_multi *multi, struct gc_arena *gc) +print_key_id(struct tls_multi *multi, struct gc_arena *gc) { - int i; - struct buffer out = alloc_buf_gc (256, gc); + int i; + struct buffer out = alloc_buf_gc(256, gc); - for (i = 0; i < KEY_SCAN_SIZE; ++i) + for (i = 0; i < KEY_SCAN_SIZE; ++i) { - struct key_state *ks = multi->key_scan[i]; - buf_printf (&out, " [key#%d state=%s id=%d sid=%s]", i, - state_name (ks->state), ks->key_id, - session_id_print (&ks->session_id_remote, gc)); + struct key_state *ks = multi->key_scan[i]; + buf_printf(&out, " [key#%d state=%s id=%d sid=%s]", i, + state_name(ks->state), ks->key_id, + session_id_print(&ks->session_id_remote, gc)); } - return BSTR (&out); + return BSTR(&out); } /* @@ -787,17 +838,25 @@ print_key_id (struct tls_multi *multi, struct gc_arena *gc) * form of hard reset is used. */ static bool -is_hard_reset (int op, int key_method) +is_hard_reset(int op, int key_method) { - if (!key_method || key_method == 1) - if (op == P_CONTROL_HARD_RESET_CLIENT_V1 || op == P_CONTROL_HARD_RESET_SERVER_V1) - return true; + if (!key_method || key_method == 1) + { + if (op == P_CONTROL_HARD_RESET_CLIENT_V1 || op == P_CONTROL_HARD_RESET_SERVER_V1) + { + return true; + } + } - if (!key_method || key_method >= 2) - if (op == P_CONTROL_HARD_RESET_CLIENT_V2 || op == P_CONTROL_HARD_RESET_SERVER_V2) - return true; + if (!key_method || key_method >= 2) + { + if (op == P_CONTROL_HARD_RESET_CLIENT_V2 || op == P_CONTROL_HARD_RESET_SERVER_V2) + { + return true; + } + } - return false; + return false; } /** @addtogroup control_processor @@ -824,66 +883,68 @@ is_hard_reset (int op, int key_method) * been allocated before calling this function. */ static void -key_state_init (struct tls_session *session, struct key_state *ks) -{ - update_time (); - - CLEAR (*ks); - - /* - * Build TLS object that reads/writes ciphertext - * to/from memory BIOs. - */ - key_state_ssl_init(&ks->ks_ssl, &session->opt->ssl_ctx, session->opt->server, - session); - - /* Set control-channel initiation mode */ - ks->initial_opcode = session->initial_opcode; - session->initial_opcode = P_CONTROL_SOFT_RESET_V1; - ks->state = S_INITIAL; - ks->key_id = session->key_id; - - /* - * key_id increments to KEY_ID_MASK then recycles back to 1. - * This way you know that if key_id is 0, it is the first key. - */ - ++session->key_id; - session->key_id &= P_KEY_ID_MASK; - if (!session->key_id) - session->key_id = 1; - - /* allocate key source material object */ - ALLOC_OBJ_CLEAR (ks->key_src, struct key_source2); - - /* allocate reliability objects */ - ALLOC_OBJ_CLEAR (ks->send_reliable, struct reliable); - ALLOC_OBJ_CLEAR (ks->rec_reliable, struct reliable); - ALLOC_OBJ_CLEAR (ks->rec_ack, struct reliable_ack); - - /* allocate buffers */ - ks->plaintext_read_buf = alloc_buf (TLS_CHANNEL_BUF_SIZE); - ks->plaintext_write_buf = alloc_buf (TLS_CHANNEL_BUF_SIZE); - ks->ack_write_buf = alloc_buf (BUF_SIZE (&session->opt->frame)); - reliable_init (ks->send_reliable, BUF_SIZE (&session->opt->frame), - FRAME_HEADROOM (&session->opt->frame), TLS_RELIABLE_N_SEND_BUFFERS, - ks->key_id ? false : session->opt->xmit_hold); - reliable_init (ks->rec_reliable, BUF_SIZE (&session->opt->frame), - FRAME_HEADROOM (&session->opt->frame), TLS_RELIABLE_N_REC_BUFFERS, - false); - reliable_set_timeout (ks->send_reliable, session->opt->packet_timeout); - - /* init packet ID tracker */ - if (session->opt->replay) - { - packet_id_init (&ks->crypto_options.packet_id, - session->opt->replay_window, session->opt->replay_time, "SSL", - ks->key_id); - } - - ks->crypto_options.pid_persist = NULL; +key_state_init(struct tls_session *session, struct key_state *ks) +{ + update_time(); + + CLEAR(*ks); + + /* + * Build TLS object that reads/writes ciphertext + * to/from memory BIOs. + */ + key_state_ssl_init(&ks->ks_ssl, &session->opt->ssl_ctx, session->opt->server, + session); + + /* Set control-channel initiation mode */ + ks->initial_opcode = session->initial_opcode; + session->initial_opcode = P_CONTROL_SOFT_RESET_V1; + ks->state = S_INITIAL; + ks->key_id = session->key_id; + + /* + * key_id increments to KEY_ID_MASK then recycles back to 1. + * This way you know that if key_id is 0, it is the first key. + */ + ++session->key_id; + session->key_id &= P_KEY_ID_MASK; + if (!session->key_id) + { + session->key_id = 1; + } + + /* allocate key source material object */ + ALLOC_OBJ_CLEAR(ks->key_src, struct key_source2); + + /* allocate reliability objects */ + ALLOC_OBJ_CLEAR(ks->send_reliable, struct reliable); + ALLOC_OBJ_CLEAR(ks->rec_reliable, struct reliable); + ALLOC_OBJ_CLEAR(ks->rec_ack, struct reliable_ack); + + /* allocate buffers */ + ks->plaintext_read_buf = alloc_buf(TLS_CHANNEL_BUF_SIZE); + ks->plaintext_write_buf = alloc_buf(TLS_CHANNEL_BUF_SIZE); + ks->ack_write_buf = alloc_buf(BUF_SIZE(&session->opt->frame)); + reliable_init(ks->send_reliable, BUF_SIZE(&session->opt->frame), + FRAME_HEADROOM(&session->opt->frame), TLS_RELIABLE_N_SEND_BUFFERS, + ks->key_id ? false : session->opt->xmit_hold); + reliable_init(ks->rec_reliable, BUF_SIZE(&session->opt->frame), + FRAME_HEADROOM(&session->opt->frame), TLS_RELIABLE_N_REC_BUFFERS, + false); + reliable_set_timeout(ks->send_reliable, session->opt->packet_timeout); + + /* init packet ID tracker */ + if (session->opt->replay) + { + packet_id_init(&ks->crypto_options.packet_id, + session->opt->replay_window, session->opt->replay_time, "SSL", + ks->key_id); + } + + ks->crypto_options.pid_persist = NULL; #ifdef MANAGEMENT_DEF_AUTH - ks->mda_key_id = session->opt->mda_context->mda_key_id_counter++; + ks->mda_key_id = session->opt->mda_context->mda_key_id_counter++; #endif } @@ -902,44 +963,50 @@ key_state_init (struct tls_session *session, struct key_state *ks) * should be overwritten with 0s. */ static void -key_state_free (struct key_state *ks, bool clear) +key_state_free(struct key_state *ks, bool clear) { - ks->state = S_UNDEF; + ks->state = S_UNDEF; - key_state_ssl_free(&ks->ks_ssl); + key_state_ssl_free(&ks->ks_ssl); - free_key_ctx_bi (&ks->crypto_options.key_ctx_bi); - free_buf (&ks->plaintext_read_buf); - free_buf (&ks->plaintext_write_buf); - free_buf (&ks->ack_write_buf); - buffer_list_free(ks->paybuf); + free_key_ctx_bi(&ks->crypto_options.key_ctx_bi); + free_buf(&ks->plaintext_read_buf); + free_buf(&ks->plaintext_write_buf); + free_buf(&ks->ack_write_buf); + buffer_list_free(ks->paybuf); - if (ks->send_reliable) + if (ks->send_reliable) { - reliable_free (ks->send_reliable); - free (ks->send_reliable); + reliable_free(ks->send_reliable); + free(ks->send_reliable); } - if (ks->rec_reliable) + if (ks->rec_reliable) { - reliable_free (ks->rec_reliable); - free (ks->rec_reliable); + reliable_free(ks->rec_reliable); + free(ks->rec_reliable); } - if (ks->rec_ack) - free (ks->rec_ack); + if (ks->rec_ack) + { + free(ks->rec_ack); + } - if (ks->key_src) - free (ks->key_src); + if (ks->key_src) + { + free(ks->key_src); + } - packet_id_free (&ks->crypto_options.packet_id); + packet_id_free(&ks->crypto_options.packet_id); #ifdef PLUGIN_DEF_AUTH - key_state_rm_auth_control_file (ks); + key_state_rm_auth_control_file(ks); #endif - if (clear) - secure_memzero (ks, sizeof (*ks)); + if (clear) + { + secure_memzero(ks, sizeof(*ks)); + } } /** @} name Functions for initialization and cleanup of key_state structures */ @@ -950,20 +1017,20 @@ key_state_free (struct key_state *ks, bool clear) /** * Returns whether or not the server should check for username/password * - * @param session The current TLS session + * @param session The current TLS session * - * @return true if username and password verification is enabled, - * false if not. + * @return true if username and password verification is enabled, + * false if not. */ static inline bool tls_session_user_pass_enabled(struct tls_session *session) { - return (session->opt->auth_user_pass_verify_script - || plugin_defined (session->opt->plugins, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY) + return (session->opt->auth_user_pass_verify_script + || plugin_defined(session->opt->plugins, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY) #ifdef MANAGEMENT_DEF_AUTH - || management_enable_def_auth (management) + || management_enable_def_auth(management) #endif - ); + ); } @@ -988,54 +1055,54 @@ tls_session_user_pass_enabled(struct tls_session *session) * been allocated before calling this function. */ static void -tls_session_init (struct tls_multi *multi, struct tls_session *session) +tls_session_init(struct tls_multi *multi, struct tls_session *session) { - struct gc_arena gc = gc_new (); + struct gc_arena gc = gc_new(); - dmsg (D_TLS_DEBUG, "TLS: tls_session_init: entry"); + dmsg(D_TLS_DEBUG, "TLS: tls_session_init: entry"); - CLEAR (*session); + CLEAR(*session); - /* Set options data to point to parent's option structure */ - session->opt = &multi->opt; - - /* Randomize session # if it is 0 */ - while (!session_id_defined(&session->session_id)) - session_id_random (&session->session_id); + /* Set options data to point to parent's option structure */ + session->opt = &multi->opt; - /* Are we a TLS server or client? */ - ASSERT (session->opt->key_method >= 1); - if (session->opt->key_method == 1) + /* Randomize session # if it is 0 */ + while (!session_id_defined(&session->session_id)) + session_id_random(&session->session_id); + + /* Are we a TLS server or client? */ + ASSERT(session->opt->key_method >= 1); + if (session->opt->key_method == 1) { - session->initial_opcode = session->opt->server ? - P_CONTROL_HARD_RESET_SERVER_V1 : P_CONTROL_HARD_RESET_CLIENT_V1; + session->initial_opcode = session->opt->server ? + P_CONTROL_HARD_RESET_SERVER_V1 : P_CONTROL_HARD_RESET_CLIENT_V1; } - else /* session->opt->key_method >= 2 */ + else /* session->opt->key_method >= 2 */ { - session->initial_opcode = session->opt->server ? - P_CONTROL_HARD_RESET_SERVER_V2 : P_CONTROL_HARD_RESET_CLIENT_V2; + session->initial_opcode = session->opt->server ? + P_CONTROL_HARD_RESET_SERVER_V2 : P_CONTROL_HARD_RESET_CLIENT_V2; } - /* Initialize control channel authentication parameters */ - session->tls_wrap = session->opt->tls_wrap; - session->tls_wrap.work = alloc_buf (BUF_SIZE (&session->opt->frame)); + /* Initialize control channel authentication parameters */ + session->tls_wrap = session->opt->tls_wrap; + session->tls_wrap.work = alloc_buf(BUF_SIZE(&session->opt->frame)); - /* initialize packet ID replay window for --tls-auth */ - packet_id_init (&session->tls_wrap.opt.packet_id, - session->opt->replay_window, - session->opt->replay_time, - "TLS_WRAP", session->key_id); + /* initialize packet ID replay window for --tls-auth */ + packet_id_init(&session->tls_wrap.opt.packet_id, + session->opt->replay_window, + session->opt->replay_time, + "TLS_WRAP", session->key_id); - /* load most recent packet-id to replay protect on --tls-auth */ - packet_id_persist_load_obj (session->tls_wrap.opt.pid_persist, - &session->tls_wrap.opt.packet_id); + /* load most recent packet-id to replay protect on --tls-auth */ + packet_id_persist_load_obj(session->tls_wrap.opt.pid_persist, + &session->tls_wrap.opt.packet_id); - key_state_init (session, &session->key[KS_PRIMARY]); + key_state_init(session, &session->key[KS_PRIMARY]); - dmsg (D_TLS_DEBUG, "TLS: tls_session_init: new session object, sid=%s", - session_id_print (&session->session_id, &gc)); + dmsg(D_TLS_DEBUG, "TLS: tls_session_init: new session object, sid=%s", + session_id_print(&session->session_id, &gc)); - gc_free (&gc); + gc_free(&gc); } /** @@ -1051,25 +1118,31 @@ tls_session_init (struct tls_multi *multi, struct tls_session *session) * object should be overwritten with 0s. */ static void -tls_session_free (struct tls_session *session, bool clear) +tls_session_free(struct tls_session *session, bool clear) { - int i; + int i; - if (packet_id_initialized(&session->tls_wrap.opt.packet_id)) - packet_id_free (&session->tls_wrap.opt.packet_id); + if (packet_id_initialized(&session->tls_wrap.opt.packet_id)) + { + packet_id_free(&session->tls_wrap.opt.packet_id); + } - free_buf (&session->tls_wrap.work); + free_buf(&session->tls_wrap.work); - for (i = 0; i < KS_SIZE; ++i) - key_state_free (&session->key[i], false); + for (i = 0; i < KS_SIZE; ++i) + key_state_free(&session->key[i], false); - if (session->common_name) - free (session->common_name); + if (session->common_name) + { + free(session->common_name); + } - cert_hash_free (session->cert_hash_set); + cert_hash_free(session->cert_hash_set); - if (clear) - secure_memzero (session, sizeof (*session)); + if (clear) + { + secure_memzero(session, sizeof(*session)); + } } /** @} name Functions for initialization and cleanup of tls_session structures */ @@ -1078,31 +1151,35 @@ tls_session_free (struct tls_session *session, bool clear) static void -move_session (struct tls_multi* multi, int dest, int src, bool reinit_src) +move_session(struct tls_multi *multi, int dest, int src, bool reinit_src) { - msg (D_TLS_DEBUG_LOW, "TLS: move_session: dest=%s src=%s reinit_src=%d", - session_index_name(dest), - session_index_name(src), - reinit_src); - ASSERT (src != dest); - ASSERT (src >= 0 && src < TM_SIZE); - ASSERT (dest >= 0 && dest < TM_SIZE); - tls_session_free (&multi->session[dest], false); - multi->session[dest] = multi->session[src]; - - if (reinit_src) - tls_session_init (multi, &multi->session[src]); - else - secure_memzero (&multi->session[src], sizeof (multi->session[src])); + msg(D_TLS_DEBUG_LOW, "TLS: move_session: dest=%s src=%s reinit_src=%d", + session_index_name(dest), + session_index_name(src), + reinit_src); + ASSERT(src != dest); + ASSERT(src >= 0 && src < TM_SIZE); + ASSERT(dest >= 0 && dest < TM_SIZE); + tls_session_free(&multi->session[dest], false); + multi->session[dest] = multi->session[src]; + + if (reinit_src) + { + tls_session_init(multi, &multi->session[src]); + } + else + { + secure_memzero(&multi->session[src], sizeof(multi->session[src])); + } - dmsg (D_TLS_DEBUG, "TLS: move_session: exit"); + dmsg(D_TLS_DEBUG, "TLS: move_session: exit"); } static void -reset_session (struct tls_multi *multi, struct tls_session *session) +reset_session(struct tls_multi *multi, struct tls_session *session) { - tls_session_free (session, false); - tls_session_init (multi, session); + tls_session_free(session, false); + tls_session_init(multi, session); } /* @@ -1110,11 +1187,15 @@ reset_session (struct tls_multi *multi, struct tls_session *session) * called again. */ static inline void -compute_earliest_wakeup (interval_t *earliest, interval_t seconds_from_now) { - if (seconds_from_now < *earliest) - *earliest = seconds_from_now; - if (*earliest < 0) - *earliest = 0; +compute_earliest_wakeup(interval_t *earliest, interval_t seconds_from_now) { + if (seconds_from_now < *earliest) + { + *earliest = seconds_from_now; + } + if (*earliest < 0) + { + *earliest = 0; + } } /* @@ -1122,60 +1203,68 @@ compute_earliest_wakeup (interval_t *earliest, interval_t seconds_from_now) { * no longer be used. */ static inline bool -lame_duck_must_die (const struct tls_session* session, interval_t *wakeup) -{ - const struct key_state* lame = &session->key[KS_LAME_DUCK]; - if (lame->state >= S_INITIAL) - { - const time_t local_now = now; - ASSERT (lame->must_die); /* a lame duck key must always have an expiration */ - if (local_now < lame->must_die) - { - compute_earliest_wakeup (wakeup, lame->must_die - local_now); - return false; - } - else - return true; - } - else if (lame->state == S_ERROR) - return true; - else - return false; +lame_duck_must_die(const struct tls_session *session, interval_t *wakeup) +{ + const struct key_state *lame = &session->key[KS_LAME_DUCK]; + if (lame->state >= S_INITIAL) + { + const time_t local_now = now; + ASSERT(lame->must_die); /* a lame duck key must always have an expiration */ + if (local_now < lame->must_die) + { + compute_earliest_wakeup(wakeup, lame->must_die - local_now); + return false; + } + else + { + return true; + } + } + else if (lame->state == S_ERROR) + { + return true; + } + else + { + return false; + } } struct tls_multi * -tls_multi_init (struct tls_options *tls_options) +tls_multi_init(struct tls_options *tls_options) { - struct tls_multi *ret; + struct tls_multi *ret; - ALLOC_OBJ_CLEAR (ret, struct tls_multi); + ALLOC_OBJ_CLEAR(ret, struct tls_multi); - /* get command line derived options */ - ret->opt = *tls_options; + /* get command line derived options */ + ret->opt = *tls_options; - /* set up list of keys to be scanned by data channel encrypt and decrypt routines */ - ASSERT (SIZE (ret->key_scan) == 3); - ret->key_scan[0] = &ret->session[TM_ACTIVE].key[KS_PRIMARY]; - ret->key_scan[1] = &ret->session[TM_ACTIVE].key[KS_LAME_DUCK]; - ret->key_scan[2] = &ret->session[TM_LAME_DUCK].key[KS_LAME_DUCK]; + /* set up list of keys to be scanned by data channel encrypt and decrypt routines */ + ASSERT(SIZE(ret->key_scan) == 3); + ret->key_scan[0] = &ret->session[TM_ACTIVE].key[KS_PRIMARY]; + ret->key_scan[1] = &ret->session[TM_ACTIVE].key[KS_LAME_DUCK]; + ret->key_scan[2] = &ret->session[TM_LAME_DUCK].key[KS_LAME_DUCK]; - /* By default not use P_DATA_V2 */ - ret->use_peer_id = false; + /* By default not use P_DATA_V2 */ + ret->use_peer_id = false; - return ret; + return ret; } void -tls_multi_init_finalize (struct tls_multi* multi, const struct frame* frame) +tls_multi_init_finalize(struct tls_multi *multi, const struct frame *frame) { - tls_init_control_channel_frame_parameters (frame, &multi->opt.frame); - - /* initialize the active and untrusted sessions */ + tls_init_control_channel_frame_parameters(frame, &multi->opt.frame); + + /* initialize the active and untrusted sessions */ - tls_session_init (multi, &multi->session[TM_ACTIVE]); + tls_session_init(multi, &multi->session[TM_ACTIVE]); - if (!multi->opt.single_session) - tls_session_init (multi, &multi->session[TM_UNTRUSTED]); + if (!multi->opt.single_session) + { + tls_session_init(multi, &multi->session[TM_UNTRUSTED]); + } } /* @@ -1183,33 +1272,33 @@ tls_multi_init_finalize (struct tls_multi* multi, const struct frame* frame) */ struct tls_auth_standalone * -tls_auth_standalone_init (struct tls_options *tls_options, - struct gc_arena *gc) +tls_auth_standalone_init(struct tls_options *tls_options, + struct gc_arena *gc) { - struct tls_auth_standalone *tas; + struct tls_auth_standalone *tas; - ALLOC_OBJ_CLEAR_GC (tas, struct tls_auth_standalone, gc); + ALLOC_OBJ_CLEAR_GC(tas, struct tls_auth_standalone, gc); - tas->tls_wrap = tls_options->tls_wrap; + tas->tls_wrap = tls_options->tls_wrap; - /* - * Standalone tls-auth is in read-only mode with respect to TLS - * control channel state. After we build a new client instance - * object, we will process this session-initiating packet for real. - */ - tas->tls_wrap.opt.flags |= CO_IGNORE_PACKET_ID; + /* + * Standalone tls-auth is in read-only mode with respect to TLS + * control channel state. After we build a new client instance + * object, we will process this session-initiating packet for real. + */ + tas->tls_wrap.opt.flags |= CO_IGNORE_PACKET_ID; - /* get initial frame parms, still need to finalize */ - tas->frame = tls_options->frame; + /* get initial frame parms, still need to finalize */ + tas->frame = tls_options->frame; - return tas; + return tas; } void -tls_auth_standalone_finalize (struct tls_auth_standalone *tas, - const struct frame *frame) +tls_auth_standalone_finalize(struct tls_auth_standalone *tas, + const struct frame *frame) { - tls_init_control_channel_frame_parameters (frame, &tas->frame); + tls_init_control_channel_frame_parameters(frame, &tas->frame); } /* @@ -1218,14 +1307,14 @@ tls_auth_standalone_finalize (struct tls_auth_standalone *tas, * sets. */ void -tls_multi_init_set_options (struct tls_multi* multi, - const char *local, - const char *remote) +tls_multi_init_set_options(struct tls_multi *multi, + const char *local, + const char *remote) { #ifdef ENABLE_OCC - /* initialize options string */ - multi->opt.local_options = local; - multi->opt.remote_options = remote; + /* initialize options string */ + multi->opt.local_options = local; + multi->opt.remote_options = remote; #endif } @@ -1233,43 +1322,49 @@ tls_multi_init_set_options (struct tls_multi* multi, * Cleanup a tls_multi structure and free associated memory allocations. */ void -tls_multi_free (struct tls_multi *multi, bool clear) +tls_multi_free(struct tls_multi *multi, bool clear) { - int i; + int i; - ASSERT (multi); + ASSERT(multi); #ifdef MANAGEMENT_DEF_AUTH - man_def_auth_set_client_reason(multi, NULL); + man_def_auth_set_client_reason(multi, NULL); #endif #if P2MP_SERVER - free (multi->peer_info); + free(multi->peer_info); #endif - if (multi->locked_cn) - free (multi->locked_cn); + if (multi->locked_cn) + { + free(multi->locked_cn); + } - if (multi->locked_username) - free (multi->locked_username); + if (multi->locked_username) + { + free(multi->locked_username); + } - cert_hash_free (multi->locked_cert_hash_set); + cert_hash_free(multi->locked_cert_hash_set); - if (multi->auth_token) + if (multi->auth_token) { - secure_memzero (multi->auth_token, AUTH_TOKEN_SIZE); - free (multi->auth_token); + secure_memzero(multi->auth_token, AUTH_TOKEN_SIZE); + free(multi->auth_token); } - free (multi->remote_ciphername); + free(multi->remote_ciphername); - for (i = 0; i < TM_SIZE; ++i) - tls_session_free (&multi->session[i], false); + for (i = 0; i < TM_SIZE; ++i) + tls_session_free(&multi->session[i], false); - if (clear) - secure_memzero (multi, sizeof (*multi)); + if (clear) + { + secure_memzero(multi, sizeof(*multi)); + } - free(multi); + free(multi); } @@ -1285,51 +1380,53 @@ tls_multi_free (struct tls_multi *multi, bool clear) #define SWAP_BUF_SIZE 256 static bool -swap_hmac (struct buffer *buf, const struct crypto_options *co, bool incoming) +swap_hmac(struct buffer *buf, const struct crypto_options *co, bool incoming) { - const struct key_ctx *ctx; + const struct key_ctx *ctx; - ASSERT (co); + ASSERT(co); - ctx = (incoming ? &co->key_ctx_bi.decrypt : &co->key_ctx_bi.encrypt); - ASSERT (ctx->hmac); + ctx = (incoming ? &co->key_ctx_bi.decrypt : &co->key_ctx_bi.encrypt); + ASSERT(ctx->hmac); - { - /* hmac + packet_id (8 bytes) */ - const int hmac_size = hmac_ctx_size (ctx->hmac) + packet_id_size (true); + { + /* hmac + packet_id (8 bytes) */ + const int hmac_size = hmac_ctx_size(ctx->hmac) + packet_id_size(true); - /* opcode + session_id */ - const int osid_size = 1 + SID_SIZE; + /* opcode + session_id */ + const int osid_size = 1 + SID_SIZE; - int e1, e2; - uint8_t *b = BPTR (buf); - uint8_t buf1[SWAP_BUF_SIZE]; - uint8_t buf2[SWAP_BUF_SIZE]; + int e1, e2; + uint8_t *b = BPTR(buf); + uint8_t buf1[SWAP_BUF_SIZE]; + uint8_t buf2[SWAP_BUF_SIZE]; - if (incoming) - { - e1 = osid_size; - e2 = hmac_size; - } - else - { - e1 = hmac_size; - e2 = osid_size; - } - - ASSERT (e1 <= SWAP_BUF_SIZE && e2 <= SWAP_BUF_SIZE); - - if (buf->len >= e1 + e2) - { - memcpy (buf1, b, e1); - memcpy (buf2, b + e1, e2); - memcpy (b, buf2, e2); - memcpy (b + e2, buf1, e1); - return true; - } - else - return false; - } + if (incoming) + { + e1 = osid_size; + e2 = hmac_size; + } + else + { + e1 = hmac_size; + e2 = osid_size; + } + + ASSERT(e1 <= SWAP_BUF_SIZE && e2 <= SWAP_BUF_SIZE); + + if (buf->len >= e1 + e2) + { + memcpy(buf1, b, e1); + memcpy(buf2, b + e1, e2); + memcpy(b, buf2, e2); + memcpy(b + e2, buf1, e1); + return true; + } + else + { + return false; + } + } } #undef SWAP_BUF_SIZE @@ -1338,115 +1435,115 @@ swap_hmac (struct buffer *buf, const struct crypto_options *co, bool incoming) * Write a control channel authentication record. */ static void -write_control_auth (struct tls_session *session, - struct key_state *ks, - struct buffer *buf, - struct link_socket_actual **to_link_addr, - int opcode, - int max_ack, - bool prepend_ack) +write_control_auth(struct tls_session *session, + struct key_state *ks, + struct buffer *buf, + struct link_socket_actual **to_link_addr, + int opcode, + int max_ack, + bool prepend_ack) { - uint8_t header = ks->key_id | (opcode << P_OPCODE_SHIFT); - struct buffer null = clear_buf (); + uint8_t header = ks->key_id | (opcode << P_OPCODE_SHIFT); + struct buffer null = clear_buf(); - ASSERT (link_socket_actual_defined (&ks->remote_addr)); - ASSERT (reliable_ack_write - (ks->rec_ack, buf, &ks->session_id_remote, max_ack, prepend_ack)); + ASSERT(link_socket_actual_defined(&ks->remote_addr)); + ASSERT(reliable_ack_write + (ks->rec_ack, buf, &ks->session_id_remote, max_ack, prepend_ack)); - if (session->tls_wrap.mode == TLS_WRAP_AUTH || - session->tls_wrap.mode == TLS_WRAP_NONE) + if (session->tls_wrap.mode == TLS_WRAP_AUTH + || session->tls_wrap.mode == TLS_WRAP_NONE) { - ASSERT (session_id_write_prepend (&session->session_id, buf)); - ASSERT (buf_write_prepend (buf, &header, sizeof(header))); + ASSERT(session_id_write_prepend(&session->session_id, buf)); + ASSERT(buf_write_prepend(buf, &header, sizeof(header))); } - if (session->tls_wrap.mode == TLS_WRAP_AUTH) + if (session->tls_wrap.mode == TLS_WRAP_AUTH) { - /* no encryption, only write hmac */ - openvpn_encrypt (buf, null, &session->tls_wrap.opt); - ASSERT (swap_hmac (buf, &session->tls_wrap.opt, false)); + /* no encryption, only write hmac */ + openvpn_encrypt(buf, null, &session->tls_wrap.opt); + ASSERT(swap_hmac(buf, &session->tls_wrap.opt, false)); } - else if (session->tls_wrap.mode == TLS_WRAP_CRYPT) + else if (session->tls_wrap.mode == TLS_WRAP_CRYPT) { - ASSERT (buf_init (&session->tls_wrap.work, buf->offset)); - ASSERT (buf_write (&session->tls_wrap.work, &header, sizeof(header))); - ASSERT (session_id_write (&session->session_id, &session->tls_wrap.work)); - if (tls_crypt_wrap (buf, &session->tls_wrap.work, &session->tls_wrap.opt)) - { - /* Don't change the original data in buf, it's used by the reliability - * layer to resend on failure. */ - *buf = session->tls_wrap.work; - } - else - { - buf->len = 0; - return; - } + ASSERT(buf_init(&session->tls_wrap.work, buf->offset)); + ASSERT(buf_write(&session->tls_wrap.work, &header, sizeof(header))); + ASSERT(session_id_write(&session->session_id, &session->tls_wrap.work)); + if (tls_crypt_wrap(buf, &session->tls_wrap.work, &session->tls_wrap.opt)) + { + /* Don't change the original data in buf, it's used by the reliability + * layer to resend on failure. */ + *buf = session->tls_wrap.work; + } + else + { + buf->len = 0; + return; + } } - *to_link_addr = &ks->remote_addr; + *to_link_addr = &ks->remote_addr; } /* * Read a control channel authentication record. */ static bool -read_control_auth (struct buffer *buf, - struct tls_wrap_ctx *ctx, - const struct link_socket_actual *from) +read_control_auth(struct buffer *buf, + struct tls_wrap_ctx *ctx, + const struct link_socket_actual *from) { - struct gc_arena gc = gc_new (); - bool ret = false; + struct gc_arena gc = gc_new(); + bool ret = false; - if (ctx->mode == TLS_WRAP_AUTH) + if (ctx->mode == TLS_WRAP_AUTH) { - struct buffer null = clear_buf (); + struct buffer null = clear_buf(); - /* move the hmac record to the front of the packet */ - if (!swap_hmac (buf, &ctx->opt, true)) - { - msg (D_TLS_ERRORS, - "TLS Error: cannot locate HMAC in incoming packet from %s", - print_link_socket_actual (from, &gc)); - gc_free (&gc); - return false; - } + /* move the hmac record to the front of the packet */ + if (!swap_hmac(buf, &ctx->opt, true)) + { + msg(D_TLS_ERRORS, + "TLS Error: cannot locate HMAC in incoming packet from %s", + print_link_socket_actual(from, &gc)); + gc_free(&gc); + return false; + } - /* authenticate only (no decrypt) and remove the hmac record - from the head of the buffer */ - openvpn_decrypt (buf, null, &ctx->opt, NULL, BPTR (buf)); - if (!buf->len) - { - msg (D_TLS_ERRORS, - "TLS Error: incoming packet authentication failed from %s", - print_link_socket_actual (from, &gc)); - goto cleanup; - } + /* authenticate only (no decrypt) and remove the hmac record + * from the head of the buffer */ + openvpn_decrypt(buf, null, &ctx->opt, NULL, BPTR(buf)); + if (!buf->len) + { + msg(D_TLS_ERRORS, + "TLS Error: incoming packet authentication failed from %s", + print_link_socket_actual(from, &gc)); + goto cleanup; + } } - else if (ctx->mode == TLS_WRAP_CRYPT) + else if (ctx->mode == TLS_WRAP_CRYPT) { - struct buffer tmp = alloc_buf (buf_forward_capacity_total (buf)); - if (!tls_crypt_unwrap (buf, &tmp, &ctx->opt)) - { - msg (D_TLS_ERRORS, "TLS Error: tls-crypt unwrapping failed from %s", - print_link_socket_actual (from, &gc)); - goto cleanup; - } - ASSERT (buf_init (buf, buf->offset)); - ASSERT (buf_copy (buf, &tmp)); - free_buf (&tmp); + struct buffer tmp = alloc_buf(buf_forward_capacity_total(buf)); + if (!tls_crypt_unwrap(buf, &tmp, &ctx->opt)) + { + msg(D_TLS_ERRORS, "TLS Error: tls-crypt unwrapping failed from %s", + print_link_socket_actual(from, &gc)); + goto cleanup; + } + ASSERT(buf_init(buf, buf->offset)); + ASSERT(buf_copy(buf, &tmp)); + free_buf(&tmp); } - if (ctx->mode == TLS_WRAP_NONE || ctx->mode == TLS_WRAP_AUTH) + if (ctx->mode == TLS_WRAP_NONE || ctx->mode == TLS_WRAP_AUTH) { - /* advance buffer pointer past opcode & session_id since our caller - already read it */ - buf_advance (buf, SID_SIZE + 1); + /* advance buffer pointer past opcode & session_id since our caller + * already read it */ + buf_advance(buf, SID_SIZE + 1); } - ret = true; + ret = true; cleanup: - gc_free (&gc); - return ret; + gc_free(&gc); + return ret; } /* @@ -1454,113 +1551,113 @@ read_control_auth (struct buffer *buf, */ static void -key_source_print (const struct key_source *k, - const char *prefix) +key_source_print(const struct key_source *k, + const char *prefix) { - struct gc_arena gc = gc_new (); - - VALGRIND_MAKE_READABLE ((void *)k->pre_master, sizeof (k->pre_master)); - VALGRIND_MAKE_READABLE ((void *)k->random1, sizeof (k->random1)); - VALGRIND_MAKE_READABLE ((void *)k->random2, sizeof (k->random2)); - - dmsg (D_SHOW_KEY_SOURCE, - "%s pre_master: %s", - prefix, - format_hex (k->pre_master, sizeof (k->pre_master), 0, &gc)); - dmsg (D_SHOW_KEY_SOURCE, - "%s random1: %s", - prefix, - format_hex (k->random1, sizeof (k->random1), 0, &gc)); - dmsg (D_SHOW_KEY_SOURCE, - "%s random2: %s", - prefix, - format_hex (k->random2, sizeof (k->random2), 0, &gc)); - - gc_free (&gc); + struct gc_arena gc = gc_new(); + + VALGRIND_MAKE_READABLE((void *)k->pre_master, sizeof(k->pre_master)); + VALGRIND_MAKE_READABLE((void *)k->random1, sizeof(k->random1)); + VALGRIND_MAKE_READABLE((void *)k->random2, sizeof(k->random2)); + + dmsg(D_SHOW_KEY_SOURCE, + "%s pre_master: %s", + prefix, + format_hex(k->pre_master, sizeof(k->pre_master), 0, &gc)); + dmsg(D_SHOW_KEY_SOURCE, + "%s random1: %s", + prefix, + format_hex(k->random1, sizeof(k->random1), 0, &gc)); + dmsg(D_SHOW_KEY_SOURCE, + "%s random2: %s", + prefix, + format_hex(k->random2, sizeof(k->random2), 0, &gc)); + + gc_free(&gc); } static void -key_source2_print (const struct key_source2 *k) +key_source2_print(const struct key_source2 *k) { - key_source_print (&k->client, "Client"); - key_source_print (&k->server, "Server"); + key_source_print(&k->client, "Client"); + key_source_print(&k->server, "Server"); } /* * Generate the hash required by for the \c tls1_PRF function. * - * @param md_kt Message digest to use - * @param sec Secret to base the hash on - * @param sec_len Length of the secret - * @param seed Seed to hash - * @param seed_len Length of the seed - * @param out Output buffer - * @param olen Length of the output buffer + * @param md_kt Message digest to use + * @param sec Secret to base the hash on + * @param sec_len Length of the secret + * @param seed Seed to hash + * @param seed_len Length of the seed + * @param out Output buffer + * @param olen Length of the output buffer */ void tls1_P_hash(const md_kt_t *md_kt, - const uint8_t *sec, - int sec_len, - const uint8_t *seed, - int seed_len, - uint8_t *out, - int olen) -{ - struct gc_arena gc = gc_new (); - int chunk; - hmac_ctx_t ctx; - hmac_ctx_t ctx_tmp; - uint8_t A1[MAX_HMAC_KEY_LENGTH]; - unsigned int A1_len; + const uint8_t *sec, + int sec_len, + const uint8_t *seed, + int seed_len, + uint8_t *out, + int olen) +{ + struct gc_arena gc = gc_new(); + int chunk; + hmac_ctx_t ctx; + hmac_ctx_t ctx_tmp; + uint8_t A1[MAX_HMAC_KEY_LENGTH]; + unsigned int A1_len; #ifdef ENABLE_DEBUG - const int olen_orig = olen; - const uint8_t *out_orig = out; + const int olen_orig = olen; + const uint8_t *out_orig = out; #endif - CLEAR(ctx); - CLEAR(ctx_tmp); + CLEAR(ctx); + CLEAR(ctx_tmp); - dmsg (D_SHOW_KEY_SOURCE, "tls1_P_hash sec: %s", format_hex (sec, sec_len, 0, &gc)); - dmsg (D_SHOW_KEY_SOURCE, "tls1_P_hash seed: %s", format_hex (seed, seed_len, 0, &gc)); + dmsg(D_SHOW_KEY_SOURCE, "tls1_P_hash sec: %s", format_hex(sec, sec_len, 0, &gc)); + dmsg(D_SHOW_KEY_SOURCE, "tls1_P_hash seed: %s", format_hex(seed, seed_len, 0, &gc)); - chunk = md_kt_size(md_kt); - A1_len = md_kt_size(md_kt); + chunk = md_kt_size(md_kt); + A1_len = md_kt_size(md_kt); - hmac_ctx_init(&ctx, sec, sec_len, md_kt); - hmac_ctx_init(&ctx_tmp, sec, sec_len, md_kt); + hmac_ctx_init(&ctx, sec, sec_len, md_kt); + hmac_ctx_init(&ctx_tmp, sec, sec_len, md_kt); - hmac_ctx_update(&ctx,seed,seed_len); - hmac_ctx_final(&ctx, A1); + hmac_ctx_update(&ctx,seed,seed_len); + hmac_ctx_final(&ctx, A1); - for (;;) + for (;; ) { - hmac_ctx_reset(&ctx); - hmac_ctx_reset(&ctx_tmp); - hmac_ctx_update(&ctx,A1,A1_len); - hmac_ctx_update(&ctx_tmp,A1,A1_len); - hmac_ctx_update(&ctx,seed,seed_len); + hmac_ctx_reset(&ctx); + hmac_ctx_reset(&ctx_tmp); + hmac_ctx_update(&ctx,A1,A1_len); + hmac_ctx_update(&ctx_tmp,A1,A1_len); + hmac_ctx_update(&ctx,seed,seed_len); - if (olen > chunk) - { - hmac_ctx_final(&ctx, out); - out+=chunk; - olen-=chunk; - hmac_ctx_final(&ctx_tmp, A1); /* calc the next A1 value */ - } - else /* last one */ - { - hmac_ctx_final(&ctx, A1); - memcpy(out,A1,olen); - break; - } + if (olen > chunk) + { + hmac_ctx_final(&ctx, out); + out += chunk; + olen -= chunk; + hmac_ctx_final(&ctx_tmp, A1); /* calc the next A1 value */ + } + else /* last one */ + { + hmac_ctx_final(&ctx, A1); + memcpy(out,A1,olen); + break; + } } - hmac_ctx_cleanup(&ctx); - hmac_ctx_cleanup(&ctx_tmp); - secure_memzero (A1, sizeof (A1)); + hmac_ctx_cleanup(&ctx); + hmac_ctx_cleanup(&ctx_tmp); + secure_memzero(A1, sizeof(A1)); - dmsg (D_SHOW_KEY_SOURCE, "tls1_P_hash out: %s", format_hex (out_orig, olen_orig, 0, &gc)); - gc_free (&gc); + dmsg(D_SHOW_KEY_SOURCE, "tls1_P_hash out: %s", format_hex(out_orig, olen_orig, 0, &gc)); + gc_free(&gc); } /* @@ -1584,221 +1681,227 @@ tls1_P_hash(const md_kt_t *md_kt, */ static void tls1_PRF(const uint8_t *label, - int label_len, - const uint8_t *sec, - int slen, - uint8_t *out1, - int olen) + int label_len, + const uint8_t *sec, + int slen, + uint8_t *out1, + int olen) { - struct gc_arena gc = gc_new (); - const md_kt_t *md5 = md_kt_get("MD5"); - const md_kt_t *sha1 = md_kt_get("SHA1"); - int len,i; - const uint8_t *S1,*S2; - uint8_t *out2; + struct gc_arena gc = gc_new(); + const md_kt_t *md5 = md_kt_get("MD5"); + const md_kt_t *sha1 = md_kt_get("SHA1"); + int len,i; + const uint8_t *S1,*S2; + uint8_t *out2; - out2 = (uint8_t *) gc_malloc (olen, false, &gc); + out2 = (uint8_t *) gc_malloc(olen, false, &gc); - len=slen/2; - S1=sec; - S2= &(sec[len]); - len+=(slen&1); /* add for odd, make longer */ + len = slen/2; + S1 = sec; + S2 = &(sec[len]); + len += (slen&1); /* add for odd, make longer */ - tls1_P_hash(md5 ,S1,len,label,label_len,out1,olen); - tls1_P_hash(sha1,S2,len,label,label_len,out2,olen); + tls1_P_hash(md5,S1,len,label,label_len,out1,olen); + tls1_P_hash(sha1,S2,len,label,label_len,out2,olen); - for (i=0; iid, SID_SIZE)); - if (server_sid) - ASSERT (buf_write (&seed, server_sid->id, SID_SIZE)); + if (client_sid) + { + ASSERT(buf_write(&seed, client_sid->id, SID_SIZE)); + } + if (server_sid) + { + ASSERT(buf_write(&seed, server_sid->id, SID_SIZE)); + } - /* compute PRF */ - tls1_PRF (BPTR(&seed), BLEN(&seed), secret, secret_len, output, output_len); + /* compute PRF */ + tls1_PRF(BPTR(&seed), BLEN(&seed), secret, secret_len, output, output_len); - buf_clear (&seed); - free_buf (&seed); + buf_clear(&seed); + free_buf(&seed); - VALGRIND_MAKE_READABLE ((void *)output, output_len); + VALGRIND_MAKE_READABLE((void *)output, output_len); } -/* +/* * Using source entropy from local and remote hosts, mix into * master key. */ static bool -generate_key_expansion (struct key_ctx_bi *key, - const struct key_type *key_type, - const struct key_source2 *key_src, - const struct session_id *client_sid, - const struct session_id *server_sid, - bool server) -{ - uint8_t master[48] = { 0 }; - struct key2 key2 = { 0 }; - bool ret = false; - - if (key->initialized) - { - msg (D_TLS_ERRORS, "TLS Error: key already initialized"); - goto exit; - } - - /* debugging print of source key material */ - key_source2_print (key_src); - - /* compute master secret */ - openvpn_PRF (key_src->client.pre_master, - sizeof(key_src->client.pre_master), - KEY_EXPANSION_ID " master secret", - key_src->client.random1, - sizeof(key_src->client.random1), - key_src->server.random1, - sizeof(key_src->server.random1), - NULL, - NULL, - master, - sizeof(master)); - - /* compute key expansion */ - openvpn_PRF (master, - sizeof(master), - KEY_EXPANSION_ID " key expansion", - key_src->client.random2, - sizeof(key_src->client.random2), - key_src->server.random2, - sizeof(key_src->server.random2), - client_sid, - server_sid, - (uint8_t*)key2.keys, - sizeof(key2.keys)); - - key2.n = 2; - - key2_print (&key2, key_type, "Master Encrypt", "Master Decrypt"); - - /* check for weak keys */ - for (int i = 0; i < 2; ++i) - { - fixup_key (&key2.keys[i], key_type); - if (!check_key (&key2.keys[i], key_type)) - { - msg (D_TLS_ERRORS, "TLS Error: Bad dynamic key generated"); - goto exit; - } - } - - /* Initialize OpenSSL key contexts */ - - ASSERT (server == true || server == false); - - init_key_ctx (&key->encrypt, - &key2.keys[(int)server], - key_type, - OPENVPN_OP_ENCRYPT, - "Data Channel Encrypt"); - - init_key_ctx (&key->decrypt, - &key2.keys[1-(int)server], - key_type, - OPENVPN_OP_DECRYPT, - "Data Channel Decrypt"); - - /* Initialize implicit IVs */ - key_ctx_update_implicit_iv (&key->encrypt, key2.keys[(int)server].hmac, - MAX_HMAC_KEY_LENGTH); - key_ctx_update_implicit_iv (&key->decrypt, key2.keys[1-(int)server].hmac, - MAX_HMAC_KEY_LENGTH); - - key->initialized = true; - ret = true; - - exit: - secure_memzero (&master, sizeof (master)); - secure_memzero (&key2, sizeof (key2)); - - return ret; +generate_key_expansion(struct key_ctx_bi *key, + const struct key_type *key_type, + const struct key_source2 *key_src, + const struct session_id *client_sid, + const struct session_id *server_sid, + bool server) +{ + uint8_t master[48] = { 0 }; + struct key2 key2 = { 0 }; + bool ret = false; + + if (key->initialized) + { + msg(D_TLS_ERRORS, "TLS Error: key already initialized"); + goto exit; + } + + /* debugging print of source key material */ + key_source2_print(key_src); + + /* compute master secret */ + openvpn_PRF(key_src->client.pre_master, + sizeof(key_src->client.pre_master), + KEY_EXPANSION_ID " master secret", + key_src->client.random1, + sizeof(key_src->client.random1), + key_src->server.random1, + sizeof(key_src->server.random1), + NULL, + NULL, + master, + sizeof(master)); + + /* compute key expansion */ + openvpn_PRF(master, + sizeof(master), + KEY_EXPANSION_ID " key expansion", + key_src->client.random2, + sizeof(key_src->client.random2), + key_src->server.random2, + sizeof(key_src->server.random2), + client_sid, + server_sid, + (uint8_t *)key2.keys, + sizeof(key2.keys)); + + key2.n = 2; + + key2_print(&key2, key_type, "Master Encrypt", "Master Decrypt"); + + /* check for weak keys */ + for (int i = 0; i < 2; ++i) + { + fixup_key(&key2.keys[i], key_type); + if (!check_key(&key2.keys[i], key_type)) + { + msg(D_TLS_ERRORS, "TLS Error: Bad dynamic key generated"); + goto exit; + } + } + + /* Initialize OpenSSL key contexts */ + + ASSERT(server == true || server == false); + + init_key_ctx(&key->encrypt, + &key2.keys[(int)server], + key_type, + OPENVPN_OP_ENCRYPT, + "Data Channel Encrypt"); + + init_key_ctx(&key->decrypt, + &key2.keys[1-(int)server], + key_type, + OPENVPN_OP_DECRYPT, + "Data Channel Decrypt"); + + /* Initialize implicit IVs */ + key_ctx_update_implicit_iv(&key->encrypt, key2.keys[(int)server].hmac, + MAX_HMAC_KEY_LENGTH); + key_ctx_update_implicit_iv(&key->decrypt, key2.keys[1-(int)server].hmac, + MAX_HMAC_KEY_LENGTH); + + key->initialized = true; + ret = true; + +exit: + secure_memzero(&master, sizeof(master)); + secure_memzero(&key2, sizeof(key2)); + + return ret; } static void key_ctx_update_implicit_iv(struct key_ctx *ctx, uint8_t *key, size_t key_len) { - const cipher_kt_t *cipher_kt = cipher_ctx_get_cipher_kt (ctx->cipher); + const cipher_kt_t *cipher_kt = cipher_ctx_get_cipher_kt(ctx->cipher); - /* Only use implicit IV in AEAD cipher mode, where HMAC key is not used */ - if (cipher_kt_mode_aead (cipher_kt)) + /* Only use implicit IV in AEAD cipher mode, where HMAC key is not used */ + if (cipher_kt_mode_aead(cipher_kt)) { - size_t impl_iv_len = 0; - ASSERT (cipher_kt_iv_size (cipher_kt) >= OPENVPN_AEAD_MIN_IV_LEN); - impl_iv_len = cipher_kt_iv_size (cipher_kt) - sizeof (packet_id_type); - ASSERT (impl_iv_len <= OPENVPN_MAX_IV_LENGTH); - ASSERT (impl_iv_len <= key_len); - memcpy (ctx->implicit_iv, key, impl_iv_len); - ctx->implicit_iv_len = impl_iv_len; + size_t impl_iv_len = 0; + ASSERT(cipher_kt_iv_size(cipher_kt) >= OPENVPN_AEAD_MIN_IV_LEN); + impl_iv_len = cipher_kt_iv_size(cipher_kt) - sizeof(packet_id_type); + ASSERT(impl_iv_len <= OPENVPN_MAX_IV_LENGTH); + ASSERT(impl_iv_len <= key_len); + memcpy(ctx->implicit_iv, key, impl_iv_len); + ctx->implicit_iv_len = impl_iv_len; } } bool tls_item_in_cipher_list(const char *item, const char *list) { - char *tmp_ciphers = string_alloc (list, NULL); - char *tmp_ciphers_orig = tmp_ciphers; + char *tmp_ciphers = string_alloc(list, NULL); + char *tmp_ciphers_orig = tmp_ciphers; - const char *token = strtok (tmp_ciphers, ":"); - while(token) + const char *token = strtok(tmp_ciphers, ":"); + while (token) { - if (0 == strcmp (token, item)) - break; - token = strtok (NULL, ":"); + if (0 == strcmp(token, item)) + { + break; + } + token = strtok(NULL, ":"); } - free(tmp_ciphers_orig); + free(tmp_ciphers_orig); - return token != NULL; + return token != NULL; } void tls_poor_mans_ncp(struct options *o, const char *remote_ciphername) { - if (o->ncp_enabled && remote_ciphername && - 0 != strcmp(o->ciphername, remote_ciphername)) + if (o->ncp_enabled && remote_ciphername + && 0 != strcmp(o->ciphername, remote_ciphername)) { - if (tls_item_in_cipher_list(remote_ciphername, o->ncp_ciphers)) - { - o->ciphername = string_alloc(remote_ciphername, &o->gc); - msg (D_TLS_DEBUG_LOW, "Using peer cipher '%s'", o->ciphername); - } + if (tls_item_in_cipher_list(remote_ciphername, o->ncp_ciphers)) + { + o->ciphername = string_alloc(remote_ciphername, &o->gc); + msg(D_TLS_DEBUG_LOW, "Using peer cipher '%s'", o->ciphername); + } } } @@ -1811,162 +1914,184 @@ tls_poor_mans_ncp(struct options *o, const char *remote_ciphername) static bool tls_session_generate_data_channel_keys(struct tls_session *session) { - bool ret = false; - struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */ - const struct session_id *client_sid = session->opt->server ? - &ks->session_id_remote : &session->session_id; - const struct session_id *server_sid = !session->opt->server ? - &ks->session_id_remote : &session->session_id; - - ASSERT (ks->authenticated); - - ks->crypto_options.flags = session->opt->crypto_flags; - if (!generate_key_expansion (&ks->crypto_options.key_ctx_bi, - &session->opt->key_type, ks->key_src, client_sid, server_sid, - session->opt->server)) + bool ret = false; + struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */ + const struct session_id *client_sid = session->opt->server ? + &ks->session_id_remote : &session->session_id; + const struct session_id *server_sid = !session->opt->server ? + &ks->session_id_remote : &session->session_id; + + ASSERT(ks->authenticated); + + ks->crypto_options.flags = session->opt->crypto_flags; + if (!generate_key_expansion(&ks->crypto_options.key_ctx_bi, + &session->opt->key_type, ks->key_src, client_sid, server_sid, + session->opt->server)) { - msg (D_TLS_ERRORS, "TLS Error: generate_key_expansion failed"); - goto cleanup; + msg(D_TLS_ERRORS, "TLS Error: generate_key_expansion failed"); + goto cleanup; } - tls_limit_reneg_bytes (session->opt->key_type.cipher, - &session->opt->renegotiate_bytes); + tls_limit_reneg_bytes(session->opt->key_type.cipher, + &session->opt->renegotiate_bytes); - ret = true; + ret = true; cleanup: - secure_memzero (ks->key_src, sizeof (*ks->key_src)); - return ret; + secure_memzero(ks->key_src, sizeof(*ks->key_src)); + return ret; } bool tls_session_update_crypto_params(struct tls_session *session, - const struct options *options, struct frame *frame) + const struct options *options, struct frame *frame) { - if (!session->opt->server && - 0 != strcmp(options->ciphername, session->opt->config_ciphername) && - !tls_item_in_cipher_list(options->ciphername, options->ncp_ciphers)) + if (!session->opt->server + && 0 != strcmp(options->ciphername, session->opt->config_ciphername) + && !tls_item_in_cipher_list(options->ciphername, options->ncp_ciphers)) { - msg (D_TLS_ERRORS, "Error: pushed cipher not allowed - %s not in %s or %s", - options->ciphername, session->opt->config_ciphername, - options->ncp_ciphers); - return false; + msg(D_TLS_ERRORS, "Error: pushed cipher not allowed - %s not in %s or %s", + options->ciphername, session->opt->config_ciphername, + options->ncp_ciphers); + return false; } - init_key_type (&session->opt->key_type, options->ciphername, - options->authname, options->keysize, true, true); + init_key_type(&session->opt->key_type, options->ciphername, + options->authname, options->keysize, true, true); - bool packet_id_long_form = cipher_kt_mode_ofb_cfb (session->opt->key_type.cipher); - session->opt->crypto_flags &= ~(CO_PACKET_ID_LONG_FORM); - if (packet_id_long_form) - session->opt->crypto_flags |= CO_PACKET_ID_LONG_FORM; + bool packet_id_long_form = cipher_kt_mode_ofb_cfb(session->opt->key_type.cipher); + session->opt->crypto_flags &= ~(CO_PACKET_ID_LONG_FORM); + if (packet_id_long_form) + { + session->opt->crypto_flags |= CO_PACKET_ID_LONG_FORM; + } - /* Update frame parameters: undo worst-case overhead, add actual overhead */ - frame_add_to_extra_frame (frame, -(crypto_max_overhead())); - crypto_adjust_frame_parameters (frame, &session->opt->key_type, - options->use_iv, options->replay, packet_id_long_form); - frame_finalize(frame, options->ce.link_mtu_defined, options->ce.link_mtu, - options->ce.tun_mtu_defined, options->ce.tun_mtu); - frame_init_mssfix(frame, options); - frame_print (frame, D_MTU_INFO, "Data Channel MTU parms"); + /* Update frame parameters: undo worst-case overhead, add actual overhead */ + frame_add_to_extra_frame(frame, -(crypto_max_overhead())); + crypto_adjust_frame_parameters(frame, &session->opt->key_type, + options->use_iv, options->replay, packet_id_long_form); + frame_finalize(frame, options->ce.link_mtu_defined, options->ce.link_mtu, + options->ce.tun_mtu_defined, options->ce.tun_mtu); + frame_init_mssfix(frame, options); + frame_print(frame, D_MTU_INFO, "Data Channel MTU parms"); - return tls_session_generate_data_channel_keys (session); + return tls_session_generate_data_channel_keys(session); } static bool -random_bytes_to_buf (struct buffer *buf, - uint8_t *out, - int outlen) +random_bytes_to_buf(struct buffer *buf, + uint8_t *out, + int outlen) { - if (!rand_bytes (out, outlen)) - msg (M_FATAL, "ERROR: Random number generator cannot obtain entropy for key generation [SSL]"); - if (!buf_write (buf, out, outlen)) - return false; - return true; + if (!rand_bytes(out, outlen)) + { + msg(M_FATAL, "ERROR: Random number generator cannot obtain entropy for key generation [SSL]"); + } + if (!buf_write(buf, out, outlen)) + { + return false; + } + return true; } static bool -key_source2_randomize_write (struct key_source2 *k2, - struct buffer *buf, - bool server) +key_source2_randomize_write(struct key_source2 *k2, + struct buffer *buf, + bool server) { - struct key_source *k = &k2->client; - if (server) - k = &k2->server; + struct key_source *k = &k2->client; + if (server) + { + k = &k2->server; + } - CLEAR (*k); + CLEAR(*k); - if (!server) + if (!server) { - if (!random_bytes_to_buf (buf, k->pre_master, sizeof (k->pre_master))) - return false; + if (!random_bytes_to_buf(buf, k->pre_master, sizeof(k->pre_master))) + { + return false; + } } - if (!random_bytes_to_buf (buf, k->random1, sizeof (k->random1))) - return false; - if (!random_bytes_to_buf (buf, k->random2, sizeof (k->random2))) - return false; + if (!random_bytes_to_buf(buf, k->random1, sizeof(k->random1))) + { + return false; + } + if (!random_bytes_to_buf(buf, k->random2, sizeof(k->random2))) + { + return false; + } - return true; + return true; } static int -key_source2_read (struct key_source2 *k2, - struct buffer *buf, - bool server) +key_source2_read(struct key_source2 *k2, + struct buffer *buf, + bool server) { - struct key_source *k = &k2->client; + struct key_source *k = &k2->client; - if (!server) - k = &k2->server; + if (!server) + { + k = &k2->server; + } - CLEAR (*k); + CLEAR(*k); - if (server) + if (server) { - if (!buf_read (buf, k->pre_master, sizeof (k->pre_master))) - return 0; + if (!buf_read(buf, k->pre_master, sizeof(k->pre_master))) + { + return 0; + } } - if (!buf_read (buf, k->random1, sizeof (k->random1))) - return 0; - if (!buf_read (buf, k->random2, sizeof (k->random2))) - return 0; + if (!buf_read(buf, k->random1, sizeof(k->random1))) + { + return 0; + } + if (!buf_read(buf, k->random2, sizeof(k->random2))) + { + return 0; + } - return 1; + return 1; } static void -flush_payload_buffer (struct key_state *ks) +flush_payload_buffer(struct key_state *ks) { - struct buffer *b; + struct buffer *b; - while ((b = buffer_list_peek (ks->paybuf))) + while ((b = buffer_list_peek(ks->paybuf))) { - key_state_write_plaintext_const (&ks->ks_ssl, b->data, b->len); - buffer_list_pop (ks->paybuf); + key_state_write_plaintext_const(&ks->ks_ssl, b->data, b->len); + buffer_list_pop(ks->paybuf); } } /* true if no in/out acknowledgements pending */ #define FULL_SYNC \ - (reliable_empty(ks->send_reliable) && reliable_ack_empty (ks->rec_ack)) + (reliable_empty(ks->send_reliable) && reliable_ack_empty(ks->rec_ack)) /* * Move the active key to the lame duck key and reinitialize the * active key. */ static void -key_state_soft_reset (struct tls_session *session) +key_state_soft_reset(struct tls_session *session) { - struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */ - struct key_state *ks_lame = &session->key[KS_LAME_DUCK]; /* retiring key */ + struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */ + struct key_state *ks_lame = &session->key[KS_LAME_DUCK]; /* retiring key */ - ks->must_die = now + session->opt->transition_window; /* remaining lifetime of old key */ - key_state_free (ks_lame, false); - *ks_lame = *ks; + ks->must_die = now + session->opt->transition_window; /* remaining lifetime of old key */ + key_state_free(ks_lame, false); + *ks_lame = *ks; - key_state_init (session, ks); - ks->session_id_remote = ks_lame->session_id_remote; - ks->remote_addr = ks_lame->remote_addr; + key_state_init(session, ks); + ks->session_id_remote = ks_lame->session_id_remote; + ks->remote_addr = ks_lame->remote_addr; } /* @@ -1974,63 +2099,79 @@ key_state_soft_reset (struct tls_session *session) */ static bool -write_empty_string (struct buffer *buf) +write_empty_string(struct buffer *buf) { - if (!buf_write_u16 (buf, 0)) - return false; - return true; + if (!buf_write_u16(buf, 0)) + { + return false; + } + return true; } static bool -write_string (struct buffer *buf, const char *str, const int maxlen) +write_string(struct buffer *buf, const char *str, const int maxlen) { - const int len = strlen (str) + 1; - if (len < 1 || (maxlen >= 0 && len > maxlen)) - return false; - if (!buf_write_u16 (buf, len)) - return false; - if (!buf_write (buf, str, len)) - return false; - return true; + const int len = strlen(str) + 1; + if (len < 1 || (maxlen >= 0 && len > maxlen)) + { + return false; + } + if (!buf_write_u16(buf, len)) + { + return false; + } + if (!buf_write(buf, str, len)) + { + return false; + } + return true; } static bool -read_string (struct buffer *buf, char *str, const unsigned int capacity) +read_string(struct buffer *buf, char *str, const unsigned int capacity) { - const int len = buf_read_u16 (buf); - if (len < 1 || len > (int)capacity) - return false; - if (!buf_read (buf, str, len)) - return false; - str[len-1] = '\0'; - return true; -} - -static char * -read_string_alloc (struct buffer *buf) + const int len = buf_read_u16(buf); + if (len < 1 || len > (int)capacity) + { + return false; + } + if (!buf_read(buf, str, len)) + { + return false; + } + str[len-1] = '\0'; + return true; +} + +static char * +read_string_alloc(struct buffer *buf) { - const int len = buf_read_u16 (buf); - char *str; + const int len = buf_read_u16(buf); + char *str; - if (len < 1) - return NULL; - str = (char *) malloc(len); - check_malloc_return(str); - if (!buf_read (buf, str, len)) + if (len < 1) { - free (str); - return NULL; + return NULL; } - str[len-1] = '\0'; - return str; + str = (char *) malloc(len); + check_malloc_return(str); + if (!buf_read(buf, str, len)) + { + free(str); + return NULL; + } + str[len-1] = '\0'; + return str; } void -read_string_discard (struct buffer *buf) +read_string_discard(struct buffer *buf) { - char *data = read_string_alloc(buf); - if (data) - free (data); + char *data = read_string_alloc(buf); + if (data) + { + free(data); + } } /* @@ -2039,461 +2180,494 @@ read_string_discard (struct buffer *buf) */ static bool -key_method_1_write (struct buffer *buf, struct tls_session *session) +key_method_1_write(struct buffer *buf, struct tls_session *session) { - struct key key; - struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */ + struct key key; + struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */ - ASSERT (session->opt->key_method == 1); - ASSERT (buf_init (buf, 0)); + ASSERT(session->opt->key_method == 1); + ASSERT(buf_init(buf, 0)); - generate_key_random (&key, &session->opt->key_type); - if (!check_key (&key, &session->opt->key_type)) + generate_key_random(&key, &session->opt->key_type); + if (!check_key(&key, &session->opt->key_type)) { - msg (D_TLS_ERRORS, "TLS Error: Bad encrypting key generated"); - return false; + msg(D_TLS_ERRORS, "TLS Error: Bad encrypting key generated"); + return false; } - if (!write_key (&key, &session->opt->key_type, buf)) + if (!write_key(&key, &session->opt->key_type, buf)) { - msg (D_TLS_ERRORS, "TLS Error: write_key failed"); - return false; + msg(D_TLS_ERRORS, "TLS Error: write_key failed"); + return false; } - init_key_ctx (&ks->crypto_options.key_ctx_bi.encrypt, &key, - &session->opt->key_type, OPENVPN_OP_ENCRYPT, - "Data Channel Encrypt"); - secure_memzero (&key, sizeof (key)); + init_key_ctx(&ks->crypto_options.key_ctx_bi.encrypt, &key, + &session->opt->key_type, OPENVPN_OP_ENCRYPT, + "Data Channel Encrypt"); + secure_memzero(&key, sizeof(key)); - /* send local options string */ - { - const char *local_options = local_options_string (session); - const int optlen = strlen (local_options) + 1; - if (!buf_write (buf, local_options, optlen)) - { - msg (D_TLS_ERRORS, "TLS Error: KM1 write options failed"); - return false; - } - } + /* send local options string */ + { + const char *local_options = local_options_string(session); + const int optlen = strlen(local_options) + 1; + if (!buf_write(buf, local_options, optlen)) + { + msg(D_TLS_ERRORS, "TLS Error: KM1 write options failed"); + return false; + } + } - return true; + return true; } static bool push_peer_info(struct buffer *buf, struct tls_session *session) { - struct gc_arena gc = gc_new (); - bool ret = false; + struct gc_arena gc = gc_new(); + bool ret = false; #ifdef ENABLE_PUSH_PEER_INFO - if (session->opt->push_peer_info_detail > 0) + if (session->opt->push_peer_info_detail > 0) { - struct env_set *es = session->opt->es; - struct env_item *e; - struct buffer out = alloc_buf_gc (512*3, &gc); + struct env_set *es = session->opt->es; + struct env_item *e; + struct buffer out = alloc_buf_gc(512*3, &gc); - /* push version */ - buf_printf (&out, "IV_VER=%s\n", PACKAGE_VERSION); + /* push version */ + buf_printf(&out, "IV_VER=%s\n", PACKAGE_VERSION); - /* push platform */ + /* push platform */ #if defined(TARGET_LINUX) - buf_printf (&out, "IV_PLAT=linux\n"); + buf_printf(&out, "IV_PLAT=linux\n"); #elif defined(TARGET_SOLARIS) - buf_printf (&out, "IV_PLAT=solaris\n"); + buf_printf(&out, "IV_PLAT=solaris\n"); #elif defined(TARGET_OPENBSD) - buf_printf (&out, "IV_PLAT=openbsd\n"); + buf_printf(&out, "IV_PLAT=openbsd\n"); #elif defined(TARGET_DARWIN) - buf_printf (&out, "IV_PLAT=mac\n"); + buf_printf(&out, "IV_PLAT=mac\n"); #elif defined(TARGET_NETBSD) - buf_printf (&out, "IV_PLAT=netbsd\n"); + buf_printf(&out, "IV_PLAT=netbsd\n"); #elif defined(TARGET_FREEBSD) - buf_printf (&out, "IV_PLAT=freebsd\n"); + buf_printf(&out, "IV_PLAT=freebsd\n"); #elif defined(TARGET_ANDROID) - buf_printf (&out, "IV_PLAT=android\n"); + buf_printf(&out, "IV_PLAT=android\n"); #elif defined(_WIN32) - buf_printf (&out, "IV_PLAT=win\n"); + buf_printf(&out, "IV_PLAT=win\n"); #endif - /* support for P_DATA_V2 */ - buf_printf(&out, "IV_PROTO=2\n"); + /* support for P_DATA_V2 */ + buf_printf(&out, "IV_PROTO=2\n"); - /* support for Negotiable Crypto Paramters */ - if (session->opt->ncp_enabled && - (session->opt->mode == MODE_SERVER || session->opt->pull)) - { - buf_printf(&out, "IV_NCP=2\n"); - } + /* support for Negotiable Crypto Paramters */ + if (session->opt->ncp_enabled + && (session->opt->mode == MODE_SERVER || session->opt->pull)) + { + buf_printf(&out, "IV_NCP=2\n"); + } - /* push compression status */ + /* push compression status */ #ifdef USE_COMP - comp_generate_peer_info_string(&session->opt->comp_options, &out); + comp_generate_peer_info_string(&session->opt->comp_options, &out); #endif - /* support for redirecting IPv6 gateway */ - buf_printf(&out, "IV_RGI6=1\n"); + /* support for redirecting IPv6 gateway */ + buf_printf(&out, "IV_RGI6=1\n"); - if (session->opt->push_peer_info_detail >= 2) + if (session->opt->push_peer_info_detail >= 2) { - /* push mac addr */ - struct route_gateway_info rgi; - get_default_gateway (&rgi); - if (rgi.flags & RGI_HWADDR_DEFINED) - buf_printf (&out, "IV_HWADDR=%s\n", format_hex_ex (rgi.hwaddr, 6, 0, 1, ":", &gc)); - buf_printf (&out, "IV_SSL=%s\n", get_ssl_library_version() ); + /* push mac addr */ + struct route_gateway_info rgi; + get_default_gateway(&rgi); + if (rgi.flags & RGI_HWADDR_DEFINED) + { + buf_printf(&out, "IV_HWADDR=%s\n", format_hex_ex(rgi.hwaddr, 6, 0, 1, ":", &gc)); + } + buf_printf(&out, "IV_SSL=%s\n", get_ssl_library_version() ); #if defined(_WIN32) - buf_printf (&out, "IV_PLAT_VER=%s\n", win32_version_string (&gc, false)); + buf_printf(&out, "IV_PLAT_VER=%s\n", win32_version_string(&gc, false)); #endif } - /* push env vars that begin with UV_, IV_PLAT_VER and IV_GUI_VER */ - for (e=es->list; e != NULL; e=e->next) - { - if (e->string) - { - if ((((strncmp(e->string, "UV_", 3)==0 || - strncmp(e->string, "IV_PLAT_VER=", sizeof("IV_PLAT_VER=")-1)==0) - && session->opt->push_peer_info_detail >= 2) - || (strncmp(e->string,"IV_GUI_VER=",sizeof("IV_GUI_VER=")-1)==0)) - && buf_safe(&out, strlen(e->string)+1)) - buf_printf (&out, "%s\n", e->string); - } - } - - if (!write_string(buf, BSTR(&out), -1)) - goto error; - } - else -#endif + /* push env vars that begin with UV_, IV_PLAT_VER and IV_GUI_VER */ + for (e = es->list; e != NULL; e = e->next) + { + if (e->string) + { + if ((((strncmp(e->string, "UV_", 3)==0 + || strncmp(e->string, "IV_PLAT_VER=", sizeof("IV_PLAT_VER=")-1)==0) + && session->opt->push_peer_info_detail >= 2) + || (strncmp(e->string,"IV_GUI_VER=",sizeof("IV_GUI_VER=")-1)==0)) + && buf_safe(&out, strlen(e->string)+1)) + { + buf_printf(&out, "%s\n", e->string); + } + } + } + + if (!write_string(buf, BSTR(&out), -1)) + { + goto error; + } + } + else +#endif /* ifdef ENABLE_PUSH_PEER_INFO */ { - if (!write_empty_string (buf)) /* no peer info */ - goto error; + if (!write_empty_string(buf)) /* no peer info */ + { + goto error; + } } - ret = true; + ret = true; - error: - gc_free (&gc); - return ret; +error: + gc_free(&gc); + return ret; } static bool -key_method_2_write (struct buffer *buf, struct tls_session *session) +key_method_2_write(struct buffer *buf, struct tls_session *session) { - struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */ + struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */ - ASSERT (session->opt->key_method == 2); - ASSERT (buf_init (buf, 0)); + ASSERT(session->opt->key_method == 2); + ASSERT(buf_init(buf, 0)); - /* write a uint32 0 */ - if (!buf_write_u32 (buf, 0)) - goto error; + /* write a uint32 0 */ + if (!buf_write_u32(buf, 0)) + { + goto error; + } - /* write key_method + flags */ - if (!buf_write_u8 (buf, (session->opt->key_method & KEY_METHOD_MASK))) - goto error; + /* write key_method + flags */ + if (!buf_write_u8(buf, (session->opt->key_method & KEY_METHOD_MASK))) + { + goto error; + } - /* write key source material */ - if (!key_source2_randomize_write (ks->key_src, buf, session->opt->server)) - goto error; + /* write key source material */ + if (!key_source2_randomize_write(ks->key_src, buf, session->opt->server)) + { + goto error; + } - /* write options string */ - { - if (!write_string (buf, local_options_string (session), TLS_OPTIONS_LEN)) - goto error; - } + /* write options string */ + { + if (!write_string(buf, local_options_string(session), TLS_OPTIONS_LEN)) + { + goto error; + } + } - /* write username/password if specified */ - if (auth_user_pass_enabled) + /* write username/password if specified */ + if (auth_user_pass_enabled) { #ifdef ENABLE_CLIENT_CR - auth_user_pass_setup (session->opt->auth_user_pass_file, session->opt->sci); + auth_user_pass_setup(session->opt->auth_user_pass_file, session->opt->sci); #else - auth_user_pass_setup (session->opt->auth_user_pass_file, NULL); + auth_user_pass_setup(session->opt->auth_user_pass_file, NULL); #endif - if (!write_string (buf, auth_user_pass.username, -1)) - goto error; - if (!write_string (buf, auth_user_pass.password, -1)) - goto error; - purge_user_pass (&auth_user_pass, false); + if (!write_string(buf, auth_user_pass.username, -1)) + { + goto error; + } + if (!write_string(buf, auth_user_pass.password, -1)) + { + goto error; + } + purge_user_pass(&auth_user_pass, false); } - else + else { - if (!write_empty_string (buf)) /* no username */ - goto error; - if (!write_empty_string (buf)) /* no password */ - goto error; + if (!write_empty_string(buf)) /* no username */ + { + goto error; + } + if (!write_empty_string(buf)) /* no password */ + { + goto error; + } } - if (!push_peer_info (buf, session)) - goto error; + if (!push_peer_info(buf, session)) + { + goto error; + } - /* Generate tunnel keys if we're a TLS server. - * If we're a p2mp server and IV_NCP >= 2 is negotiated, the first key - * generation is postponed until after the pull/push, so we can process pushed - * cipher directives. - */ - if (session->opt->server && !(session->opt->ncp_enabled && - session->opt->mode == MODE_SERVER && ks->key_id <= 0)) + /* Generate tunnel keys if we're a TLS server. + * If we're a p2mp server and IV_NCP >= 2 is negotiated, the first key + * generation is postponed until after the pull/push, so we can process pushed + * cipher directives. + */ + if (session->opt->server && !(session->opt->ncp_enabled + && session->opt->mode == MODE_SERVER && ks->key_id <= 0)) { - if (ks->authenticated) - { - if (!tls_session_generate_data_channel_keys (session)) - { - msg (D_TLS_ERRORS, "TLS Error: server generate_key_expansion failed"); - goto error; - } - } + if (ks->authenticated) + { + if (!tls_session_generate_data_channel_keys(session)) + { + msg(D_TLS_ERRORS, "TLS Error: server generate_key_expansion failed"); + goto error; + } + } } - return true; + return true; - error: - msg (D_TLS_ERRORS, "TLS Error: Key Method #2 write failed"); - secure_memzero (ks->key_src, sizeof (*ks->key_src)); - return false; +error: + msg(D_TLS_ERRORS, "TLS Error: Key Method #2 write failed"); + secure_memzero(ks->key_src, sizeof(*ks->key_src)); + return false; } static bool -key_method_1_read (struct buffer *buf, struct tls_session *session) +key_method_1_read(struct buffer *buf, struct tls_session *session) { - int status; - struct key key; - struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */ + int status; + struct key key; + struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */ - ASSERT (session->opt->key_method == 1); + ASSERT(session->opt->key_method == 1); - if (!session->verified) + if (!session->verified) { - msg (D_TLS_ERRORS, - "TLS Error: Certificate verification failed (key-method 1)"); - goto error; + msg(D_TLS_ERRORS, + "TLS Error: Certificate verification failed (key-method 1)"); + goto error; } - status = read_key (&key, &session->opt->key_type, buf); - if (status != 1) + status = read_key(&key, &session->opt->key_type, buf); + if (status != 1) { - msg (D_TLS_ERRORS, - "TLS Error: Error reading data channel key from plaintext buffer"); - goto error; + msg(D_TLS_ERRORS, + "TLS Error: Error reading data channel key from plaintext buffer"); + goto error; } - if (!check_key (&key, &session->opt->key_type)) + if (!check_key(&key, &session->opt->key_type)) { - msg (D_TLS_ERRORS, "TLS Error: Bad decrypting key received from peer"); - goto error; + msg(D_TLS_ERRORS, "TLS Error: Bad decrypting key received from peer"); + goto error; } - if (buf->len < 1) + if (buf->len < 1) { - msg (D_TLS_ERRORS, "TLS Error: Missing options string"); - goto error; + msg(D_TLS_ERRORS, "TLS Error: Missing options string"); + goto error; } #ifdef ENABLE_OCC - /* compare received remote options string - with our locally computed options string */ - if (!session->opt->disable_occ && - !options_cmp_equal_safe ((char *) BPTR (buf), session->opt->remote_options, buf->len)) + /* compare received remote options string + * with our locally computed options string */ + if (!session->opt->disable_occ + && !options_cmp_equal_safe((char *) BPTR(buf), session->opt->remote_options, buf->len)) { - options_warning_safe ((char *) BPTR (buf), session->opt->remote_options, buf->len); + options_warning_safe((char *) BPTR(buf), session->opt->remote_options, buf->len); } #endif - buf_clear (buf); + buf_clear(buf); - init_key_ctx (&ks->crypto_options.key_ctx_bi.decrypt, &key, - &session->opt->key_type, OPENVPN_OP_DECRYPT, - "Data Channel Decrypt"); - secure_memzero (&key, sizeof (key)); - ks->authenticated = true; - return true; + init_key_ctx(&ks->crypto_options.key_ctx_bi.decrypt, &key, + &session->opt->key_type, OPENVPN_OP_DECRYPT, + "Data Channel Decrypt"); + secure_memzero(&key, sizeof(key)); + ks->authenticated = true; + return true; - error: - buf_clear (buf); - secure_memzero (&key, sizeof (key)); - return false; +error: + buf_clear(buf); + secure_memzero(&key, sizeof(key)); + return false; } static bool -key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_session *session) +key_method_2_read(struct buffer *buf, struct tls_multi *multi, struct tls_session *session) { - struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */ + struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */ - int key_method_flags; - bool username_status, password_status; + int key_method_flags; + bool username_status, password_status; - struct gc_arena gc = gc_new (); - char *options; - struct user_pass *up; + struct gc_arena gc = gc_new(); + char *options; + struct user_pass *up; - /* allocate temporary objects */ - ALLOC_ARRAY_CLEAR_GC (options, char, TLS_OPTIONS_LEN, &gc); + /* allocate temporary objects */ + ALLOC_ARRAY_CLEAR_GC(options, char, TLS_OPTIONS_LEN, &gc); - ASSERT (session->opt->key_method == 2); + ASSERT(session->opt->key_method == 2); - /* discard leading uint32 */ - if (!buf_advance (buf, 4)) { - msg (D_TLS_ERRORS, "TLS ERROR: Plaintext buffer too short (%d bytes).", - buf->len); - goto error; - } + /* discard leading uint32 */ + if (!buf_advance(buf, 4)) + { + msg(D_TLS_ERRORS, "TLS ERROR: Plaintext buffer too short (%d bytes).", + buf->len); + goto error; + } - /* get key method */ - key_method_flags = buf_read_u8 (buf); - if ((key_method_flags & KEY_METHOD_MASK) != 2) + /* get key method */ + key_method_flags = buf_read_u8(buf); + if ((key_method_flags & KEY_METHOD_MASK) != 2) { - msg (D_TLS_ERRORS, - "TLS ERROR: Unknown key_method/flags=%d received from remote host", - key_method_flags); - goto error; + msg(D_TLS_ERRORS, + "TLS ERROR: Unknown key_method/flags=%d received from remote host", + key_method_flags); + goto error; } - /* get key source material (not actual keys yet) */ - if (!key_source2_read (ks->key_src, buf, session->opt->server)) + /* get key source material (not actual keys yet) */ + if (!key_source2_read(ks->key_src, buf, session->opt->server)) { - msg (D_TLS_ERRORS, "TLS Error: Error reading remote data channel key source entropy from plaintext buffer"); - goto error; + msg(D_TLS_ERRORS, "TLS Error: Error reading remote data channel key source entropy from plaintext buffer"); + goto error; } - /* get options */ - if (!read_string (buf, options, TLS_OPTIONS_LEN)) + /* get options */ + if (!read_string(buf, options, TLS_OPTIONS_LEN)) { - msg (D_TLS_ERRORS, "TLS Error: Failed to read required OCC options string"); - goto error; + msg(D_TLS_ERRORS, "TLS Error: Failed to read required OCC options string"); + goto error; } - ks->authenticated = false; + ks->authenticated = false; - /* always extract username + password fields from buf, even if not - * authenticating for it, because otherwise we can't get at the - * peer_info data which follows behind - */ - ALLOC_OBJ_CLEAR_GC (up, struct user_pass, &gc); - username_status = read_string (buf, up->username, USER_PASS_LEN); - password_status = read_string (buf, up->password, USER_PASS_LEN); + /* always extract username + password fields from buf, even if not + * authenticating for it, because otherwise we can't get at the + * peer_info data which follows behind + */ + ALLOC_OBJ_CLEAR_GC(up, struct user_pass, &gc); + username_status = read_string(buf, up->username, USER_PASS_LEN); + password_status = read_string(buf, up->password, USER_PASS_LEN); #if P2MP_SERVER - /* get peer info from control channel */ - free (multi->peer_info); - multi->peer_info = read_string_alloc (buf); - if ( multi->peer_info ) - output_peer_info_env (session->opt->es, multi->peer_info); - - free (multi->remote_ciphername); - multi->remote_ciphername = - options_string_extract_option (options, "cipher", NULL); - - if (tls_peer_info_ncp_ver (multi->peer_info) < 2) - { - /* Peer does not support NCP, but leave NCP enabled if the local and - * remote cipher do not match to attempt 'poor-man's NCP'. - */ - if (multi->remote_ciphername == NULL || - 0 == strcmp(multi->remote_ciphername, multi->opt.config_ciphername)) - { - session->opt->ncp_enabled = false; - } + /* get peer info from control channel */ + free(multi->peer_info); + multi->peer_info = read_string_alloc(buf); + if (multi->peer_info) + { + output_peer_info_env(session->opt->es, multi->peer_info); } -#endif - if (tls_session_user_pass_enabled(session)) + free(multi->remote_ciphername); + multi->remote_ciphername = + options_string_extract_option(options, "cipher", NULL); + + if (tls_peer_info_ncp_ver(multi->peer_info) < 2) + { + /* Peer does not support NCP, but leave NCP enabled if the local and + * remote cipher do not match to attempt 'poor-man's NCP'. + */ + if (multi->remote_ciphername == NULL + || 0 == strcmp(multi->remote_ciphername, multi->opt.config_ciphername)) + { + session->opt->ncp_enabled = false; + } + } +#endif /* if P2MP_SERVER */ + + if (tls_session_user_pass_enabled(session)) { - /* Perform username/password authentication */ - if (!username_status || !password_status) - { - CLEAR (*up); - if (!(session->opt->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL)) - { - msg (D_TLS_ERRORS, "TLS Error: Auth Username/Password was not provided by peer"); - goto error; - } - } + /* Perform username/password authentication */ + if (!username_status || !password_status) + { + CLEAR(*up); + if (!(session->opt->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL)) + { + msg(D_TLS_ERRORS, "TLS Error: Auth Username/Password was not provided by peer"); + goto error; + } + } - verify_user_pass(up, multi, session); + verify_user_pass(up, multi, session); } - else + else { - /* Session verification should have occurred during TLS negotiation*/ - if (!session->verified) - { - msg (D_TLS_ERRORS, - "TLS Error: Certificate verification failed (key-method 2)"); - goto error; - } - ks->authenticated = true; + /* Session verification should have occurred during TLS negotiation*/ + if (!session->verified) + { + msg(D_TLS_ERRORS, + "TLS Error: Certificate verification failed (key-method 2)"); + goto error; + } + ks->authenticated = true; } - /* clear username and password from memory */ - secure_memzero (up, sizeof (*up)); + /* clear username and password from memory */ + secure_memzero(up, sizeof(*up)); - /* Perform final authentication checks */ - if (ks->authenticated) + /* Perform final authentication checks */ + if (ks->authenticated) { - verify_final_auth_checks(multi, session); + verify_final_auth_checks(multi, session); } #ifdef ENABLE_OCC - /* check options consistency */ - if (!session->opt->disable_occ && - !options_cmp_equal (options, session->opt->remote_options)) + /* check options consistency */ + if (!session->opt->disable_occ + && !options_cmp_equal(options, session->opt->remote_options)) { - options_warning (options, session->opt->remote_options); - if (session->opt->ssl_flags & SSLF_OPT_VERIFY) - { - msg (D_TLS_ERRORS, "Option inconsistency warnings triggering disconnect due to --opt-verify"); - ks->authenticated = false; - } + options_warning(options, session->opt->remote_options); + if (session->opt->ssl_flags & SSLF_OPT_VERIFY) + { + msg(D_TLS_ERRORS, "Option inconsistency warnings triggering disconnect due to --opt-verify"); + ks->authenticated = false; + } } #endif - buf_clear (buf); + buf_clear(buf); - /* - * Call OPENVPN_PLUGIN_TLS_FINAL plugin if defined, for final - * veto opportunity over authentication decision. - */ - if (ks->authenticated && plugin_defined (session->opt->plugins, OPENVPN_PLUGIN_TLS_FINAL)) + /* + * Call OPENVPN_PLUGIN_TLS_FINAL plugin if defined, for final + * veto opportunity over authentication decision. + */ + if (ks->authenticated && plugin_defined(session->opt->plugins, OPENVPN_PLUGIN_TLS_FINAL)) { - key_state_export_keying_material(&ks->ks_ssl, session); + key_state_export_keying_material(&ks->ks_ssl, session); - if (plugin_call (session->opt->plugins, OPENVPN_PLUGIN_TLS_FINAL, NULL, NULL, session->opt->es) != OPENVPN_PLUGIN_FUNC_SUCCESS) - ks->authenticated = false; + if (plugin_call(session->opt->plugins, OPENVPN_PLUGIN_TLS_FINAL, NULL, NULL, session->opt->es) != OPENVPN_PLUGIN_FUNC_SUCCESS) + { + ks->authenticated = false; + } - setenv_del (session->opt->es, "exported_keying_material"); + setenv_del(session->opt->es, "exported_keying_material"); } - /* - * Generate tunnel keys if we're a client. - * If --pull is enabled, the first key generation is postponed until after the - * pull/push, so we can process pushed cipher directives. - */ - if (!session->opt->server && (!session->opt->pull || ks->key_id > 0)) + /* + * Generate tunnel keys if we're a client. + * If --pull is enabled, the first key generation is postponed until after the + * pull/push, so we can process pushed cipher directives. + */ + if (!session->opt->server && (!session->opt->pull || ks->key_id > 0)) { - if (!tls_session_generate_data_channel_keys (session)) - { - msg (D_TLS_ERRORS, "TLS Error: client generate_key_expansion failed"); - goto error; - } + if (!tls_session_generate_data_channel_keys(session)) + { + msg(D_TLS_ERRORS, "TLS Error: client generate_key_expansion failed"); + goto error; + } } - gc_free (&gc); - return true; + gc_free(&gc); + return true; - error: - secure_memzero (ks->key_src, sizeof (*ks->key_src)); - buf_clear (buf); - gc_free (&gc); - return false; +error: + secure_memzero(ks->key_src, sizeof(*ks->key_src)); + buf_clear(buf); + gc_free(&gc); + return false; } static int -auth_deferred_expire_window (const struct tls_options *o) +auth_deferred_expire_window(const struct tls_options *o) { - int ret = o->handshake_window; - const int r2 = o->renegotiate_seconds / 2; + int ret = o->handshake_window; + const int r2 = o->renegotiate_seconds / 2; - if (o->renegotiate_seconds && r2 < ret) - ret = r2; - return ret; + if (o->renegotiate_seconds && r2 < ret) + { + ret = r2; + } + return ret; } /* @@ -2506,382 +2680,397 @@ auth_deferred_expire_window (const struct tls_options *o) * want to send to our peer. */ static bool -tls_process (struct tls_multi *multi, - struct tls_session *session, - struct buffer *to_link, - struct link_socket_actual **to_link_addr, - struct link_socket_info *to_link_socket_info, - interval_t *wakeup) -{ - struct gc_arena gc = gc_new (); - struct buffer *buf; - bool state_change = false; - bool active = false; - struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */ - struct key_state *ks_lame = &session->key[KS_LAME_DUCK]; /* retiring key */ - - /* Make sure we were initialized and that we're not in an error state */ - ASSERT (ks->state != S_UNDEF); - ASSERT (ks->state != S_ERROR); - ASSERT (session_id_defined (&session->session_id)); - - /* Should we trigger a soft reset? -- new key, keeps old key for a while */ - if (ks->state >= S_ACTIVE && - ((session->opt->renegotiate_seconds - && now >= ks->established + session->opt->renegotiate_seconds) - || (session->opt->renegotiate_bytes > 0 - && ks->n_bytes >= session->opt->renegotiate_bytes) - || (session->opt->renegotiate_packets - && ks->n_packets >= session->opt->renegotiate_packets) - || (packet_id_close_to_wrapping (&ks->crypto_options.packet_id.send)))) - { - msg (D_TLS_DEBUG_LOW, - "TLS: soft reset sec=%d bytes=" counter_format "/%d pkts=" counter_format "/%d", - (int)(ks->established + session->opt->renegotiate_seconds - now), - ks->n_bytes, session->opt->renegotiate_bytes, - ks->n_packets, session->opt->renegotiate_packets); - key_state_soft_reset (session); - } - - /* Kill lame duck key transition_window seconds after primary key negotiation */ - if (lame_duck_must_die (session, wakeup)) { - key_state_free (ks_lame, true); - msg (D_TLS_DEBUG_LOW, "TLS: tls_process: killed expiring key"); - } - - do - { - update_time (); - - dmsg (D_TLS_DEBUG, "TLS: tls_process: chg=%d ks=%s lame=%s to_link->len=%d wakeup=%d", - state_change, - state_name (ks->state), - state_name (ks_lame->state), - to_link->len, - *wakeup); - - state_change = false; - - /* - * TLS activity is finished once we get to S_ACTIVE, - * though we will still process acknowledgements. - * - * CHANGED with 2.0 -> now we may send tunnel configuration - * info over the control channel. - */ - - /* Initial handshake */ - if (ks->state == S_INITIAL) - { - buf = reliable_get_buf_output_sequenced (ks->send_reliable); - if (buf) - { - ks->must_negotiate = now + session->opt->handshake_window; - ks->auth_deferred_expire = now + auth_deferred_expire_window (session->opt); - - /* null buffer */ - reliable_mark_active_outgoing (ks->send_reliable, buf, ks->initial_opcode); - INCR_GENERATED; - - ks->state = S_PRE_START; - state_change = true; - dmsg (D_TLS_DEBUG, "TLS: Initial Handshake, sid=%s", - session_id_print (&session->session_id, &gc)); +tls_process(struct tls_multi *multi, + struct tls_session *session, + struct buffer *to_link, + struct link_socket_actual **to_link_addr, + struct link_socket_info *to_link_socket_info, + interval_t *wakeup) +{ + struct gc_arena gc = gc_new(); + struct buffer *buf; + bool state_change = false; + bool active = false; + struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */ + struct key_state *ks_lame = &session->key[KS_LAME_DUCK]; /* retiring key */ + + /* Make sure we were initialized and that we're not in an error state */ + ASSERT(ks->state != S_UNDEF); + ASSERT(ks->state != S_ERROR); + ASSERT(session_id_defined(&session->session_id)); + + /* Should we trigger a soft reset? -- new key, keeps old key for a while */ + if (ks->state >= S_ACTIVE + && ((session->opt->renegotiate_seconds + && now >= ks->established + session->opt->renegotiate_seconds) + || (session->opt->renegotiate_bytes > 0 + && ks->n_bytes >= session->opt->renegotiate_bytes) + || (session->opt->renegotiate_packets + && ks->n_packets >= session->opt->renegotiate_packets) + || (packet_id_close_to_wrapping(&ks->crypto_options.packet_id.send)))) + { + msg(D_TLS_DEBUG_LOW, + "TLS: soft reset sec=%d bytes=" counter_format "/%d pkts=" counter_format "/%d", + (int)(ks->established + session->opt->renegotiate_seconds - now), + ks->n_bytes, session->opt->renegotiate_bytes, + ks->n_packets, session->opt->renegotiate_packets); + key_state_soft_reset(session); + } + + /* Kill lame duck key transition_window seconds after primary key negotiation */ + if (lame_duck_must_die(session, wakeup)) + { + key_state_free(ks_lame, true); + msg(D_TLS_DEBUG_LOW, "TLS: tls_process: killed expiring key"); + } + + do + { + update_time(); + + dmsg(D_TLS_DEBUG, "TLS: tls_process: chg=%d ks=%s lame=%s to_link->len=%d wakeup=%d", + state_change, + state_name(ks->state), + state_name(ks_lame->state), + to_link->len, + *wakeup); + + state_change = false; + + /* + * TLS activity is finished once we get to S_ACTIVE, + * though we will still process acknowledgements. + * + * CHANGED with 2.0 -> now we may send tunnel configuration + * info over the control channel. + */ + + /* Initial handshake */ + if (ks->state == S_INITIAL) + { + buf = reliable_get_buf_output_sequenced(ks->send_reliable); + if (buf) + { + ks->must_negotiate = now + session->opt->handshake_window; + ks->auth_deferred_expire = now + auth_deferred_expire_window(session->opt); + + /* null buffer */ + reliable_mark_active_outgoing(ks->send_reliable, buf, ks->initial_opcode); + INCR_GENERATED; + + ks->state = S_PRE_START; + state_change = true; + dmsg(D_TLS_DEBUG, "TLS: Initial Handshake, sid=%s", + session_id_print(&session->session_id, &gc)); #ifdef ENABLE_MANAGEMENT - if (management && ks->initial_opcode != P_CONTROL_SOFT_RESET_V1) - { - management_set_state (management, - OPENVPN_STATE_WAIT, - NULL, - NULL, - NULL, - NULL, - NULL); - } + if (management && ks->initial_opcode != P_CONTROL_SOFT_RESET_V1) + { + management_set_state(management, + OPENVPN_STATE_WAIT, + NULL, + NULL, + NULL, + NULL, + NULL); + } #endif - } - } - - /* Are we timed out on receive? */ - if (now >= ks->must_negotiate) - { - if (ks->state < S_ACTIVE) - { - msg (D_TLS_ERRORS, - "TLS Error: TLS key negotiation failed to occur within %d seconds (check your network connectivity)", - session->opt->handshake_window); - goto error; - } - else /* assume that ks->state == S_ACTIVE */ - { - dmsg (D_TLS_DEBUG_MED, "STATE S_NORMAL_OP"); - ks->state = S_NORMAL_OP; - ks->must_negotiate = 0; - } - } - - /* Wait for Initial Handshake ACK */ - if (ks->state == S_PRE_START && FULL_SYNC) - { - ks->state = S_START; - state_change = true; - - /* - * Attempt CRL reload before TLS negotiation. Won't be performed if - * the file was not modified since the last reload - */ - if (session->opt->crl_file && - !(session->opt->ssl_flags & SSLF_CRL_VERIFY_DIR)) - { - tls_ctx_reload_crl(&session->opt->ssl_ctx, - session->opt->crl_file, session->opt->crl_file_inline); - } - - dmsg (D_TLS_DEBUG_MED, "STATE S_START"); - } - - /* Wait for ACK */ - if (((ks->state == S_GOT_KEY && !session->opt->server) || - (ks->state == S_SENT_KEY && session->opt->server))) - { - if (FULL_SYNC) - { - ks->established = now; - dmsg (D_TLS_DEBUG_MED, "STATE S_ACTIVE"); - if (check_debug_level (D_HANDSHAKE)) - print_details (&ks->ks_ssl, "Control Channel:"); - state_change = true; - ks->state = S_ACTIVE; - INCR_SUCCESS; - - /* Set outgoing address for data channel packets */ - link_socket_set_outgoing_addr (NULL, to_link_socket_info, &ks->remote_addr, session->common_name, session->opt->es); - - /* Flush any payload packets that were buffered before our state transitioned to S_ACTIVE */ - flush_payload_buffer (ks); + } + } + + /* Are we timed out on receive? */ + if (now >= ks->must_negotiate) + { + if (ks->state < S_ACTIVE) + { + msg(D_TLS_ERRORS, + "TLS Error: TLS key negotiation failed to occur within %d seconds (check your network connectivity)", + session->opt->handshake_window); + goto error; + } + else /* assume that ks->state == S_ACTIVE */ + { + dmsg(D_TLS_DEBUG_MED, "STATE S_NORMAL_OP"); + ks->state = S_NORMAL_OP; + ks->must_negotiate = 0; + } + } + + /* Wait for Initial Handshake ACK */ + if (ks->state == S_PRE_START && FULL_SYNC) + { + ks->state = S_START; + state_change = true; + + /* + * Attempt CRL reload before TLS negotiation. Won't be performed if + * the file was not modified since the last reload + */ + if (session->opt->crl_file + && !(session->opt->ssl_flags & SSLF_CRL_VERIFY_DIR)) + { + tls_ctx_reload_crl(&session->opt->ssl_ctx, + session->opt->crl_file, session->opt->crl_file_inline); + } + + dmsg(D_TLS_DEBUG_MED, "STATE S_START"); + } + + /* Wait for ACK */ + if (((ks->state == S_GOT_KEY && !session->opt->server) + || (ks->state == S_SENT_KEY && session->opt->server))) + { + if (FULL_SYNC) + { + ks->established = now; + dmsg(D_TLS_DEBUG_MED, "STATE S_ACTIVE"); + if (check_debug_level(D_HANDSHAKE)) + { + print_details(&ks->ks_ssl, "Control Channel:"); + } + state_change = true; + ks->state = S_ACTIVE; + INCR_SUCCESS; + + /* Set outgoing address for data channel packets */ + link_socket_set_outgoing_addr(NULL, to_link_socket_info, &ks->remote_addr, session->common_name, session->opt->es); + + /* Flush any payload packets that were buffered before our state transitioned to S_ACTIVE */ + flush_payload_buffer(ks); #ifdef MEASURE_TLS_HANDSHAKE_STATS - show_tls_performance_stats(); + show_tls_performance_stats(); #endif - } - } - - /* Reliable buffer to outgoing TCP/UDP (send up to CONTROL_SEND_ACK_MAX ACKs - for previously received packets) */ - if (!to_link->len && reliable_can_send (ks->send_reliable)) - { - int opcode; - struct buffer b; - - buf = reliable_send (ks->send_reliable, &opcode); - ASSERT (buf); - b = *buf; - INCR_SENT; - - write_control_auth (session, ks, &b, to_link_addr, opcode, - CONTROL_SEND_ACK_MAX, true); - *to_link = b; - active = true; - state_change = true; - dmsg (D_TLS_DEBUG, "Reliable -> TCP/UDP"); - break; - } - - /* Write incoming ciphertext to TLS object */ - buf = reliable_get_buf_sequenced (ks->rec_reliable); - if (buf) - { - int status = 0; - if (buf->len) - { - status = key_state_write_ciphertext (&ks->ks_ssl, buf); - if (status == -1) - { - msg (D_TLS_ERRORS, - "TLS Error: Incoming Ciphertext -> TLS object write error"); - goto error; - } - } - else - { - status = 1; - } - if (status == 1) - { - reliable_mark_deleted (ks->rec_reliable, buf, true); - state_change = true; - dmsg (D_TLS_DEBUG, "Incoming Ciphertext -> TLS"); - } - } - - /* Read incoming plaintext from TLS object */ - buf = &ks->plaintext_read_buf; - if (!buf->len) - { - int status; - - ASSERT (buf_init (buf, 0)); - status = key_state_read_plaintext (&ks->ks_ssl, buf, TLS_CHANNEL_BUF_SIZE); - update_time (); - if (status == -1) - { - msg (D_TLS_ERRORS, "TLS Error: TLS object -> incoming plaintext read error"); - goto error; - } - if (status == 1) - { - state_change = true; - dmsg (D_TLS_DEBUG, "TLS -> Incoming Plaintext"); - } - } - - /* Send Key */ - buf = &ks->plaintext_write_buf; - if (!buf->len && ((ks->state == S_START && !session->opt->server) || - (ks->state == S_GOT_KEY && session->opt->server))) - { - if (session->opt->key_method == 1) - { - if (!key_method_1_write (buf, session)) - goto error; - } - else if (session->opt->key_method == 2) - { - if (!key_method_2_write (buf, session)) - goto error; - } - else - { - ASSERT (0); - } - - state_change = true; - dmsg (D_TLS_DEBUG_MED, "STATE S_SENT_KEY"); - ks->state = S_SENT_KEY; - } - - /* Receive Key */ - buf = &ks->plaintext_read_buf; - if (buf->len - && ((ks->state == S_SENT_KEY && !session->opt->server) - || (ks->state == S_START && session->opt->server))) - { - if (session->opt->key_method == 1) - { - if (!key_method_1_read (buf, session)) - goto error; - } - else if (session->opt->key_method == 2) - { - if (!key_method_2_read (buf, multi, session)) - goto error; - } - else - { - ASSERT (0); - } - - state_change = true; - dmsg (D_TLS_DEBUG_MED, "STATE S_GOT_KEY"); - ks->state = S_GOT_KEY; - } - - /* Write outgoing plaintext to TLS object */ - buf = &ks->plaintext_write_buf; - if (buf->len) - { - int status = key_state_write_plaintext (&ks->ks_ssl, buf); - if (status == -1) - { - msg (D_TLS_ERRORS, - "TLS ERROR: Outgoing Plaintext -> TLS object write error"); - goto error; - } - if (status == 1) - { - state_change = true; - dmsg (D_TLS_DEBUG, "Outgoing Plaintext -> TLS"); - } - } - - /* Outgoing Ciphertext to reliable buffer */ - if (ks->state >= S_START) - { - buf = reliable_get_buf_output_sequenced (ks->send_reliable); - if (buf) - { - int status = key_state_read_ciphertext (&ks->ks_ssl, buf, PAYLOAD_SIZE_DYNAMIC (&multi->opt.frame)); - if (status == -1) - { - msg (D_TLS_ERRORS, - "TLS Error: Ciphertext -> reliable TCP/UDP transport read error"); - goto error; - } - if (status == 1) - { - reliable_mark_active_outgoing (ks->send_reliable, buf, P_CONTROL_V1); - INCR_GENERATED; - state_change = true; - dmsg (D_TLS_DEBUG, "Outgoing Ciphertext -> Reliable"); - } - } - } - } - while (state_change); - - update_time (); - - /* Send 1 or more ACKs (each received control packet gets one ACK) */ - if (!to_link->len && !reliable_ack_empty (ks->rec_ack)) - { - struct buffer buf = ks->ack_write_buf; - ASSERT (buf_init (&buf, FRAME_HEADROOM (&multi->opt.frame))); - write_control_auth (session, ks, &buf, to_link_addr, P_ACK_V1, - RELIABLE_ACK_SIZE, false); - *to_link = buf; - active = true; - dmsg (D_TLS_DEBUG, "Dedicated ACK -> TCP/UDP"); - } - - /* When should we wake up again? */ - { - if (ks->state >= S_INITIAL) - { - compute_earliest_wakeup (wakeup, - reliable_send_timeout (ks->send_reliable)); - - if (ks->must_negotiate) - compute_earliest_wakeup (wakeup, ks->must_negotiate - now); - } - - if (ks->established && session->opt->renegotiate_seconds) - compute_earliest_wakeup (wakeup, - ks->established + session->opt->renegotiate_seconds - now); - - /* prevent event-loop spinning by setting minimum wakeup of 1 second */ - if (*wakeup <= 0) - { - *wakeup = 1; - - /* if we had something to send to remote, but to_link was busy, - let caller know we need to be called again soon */ - active = true; - } - - dmsg (D_TLS_DEBUG, "TLS: tls_process: timeout set to %d", *wakeup); - - gc_free (&gc); - return active; - } + } + } + + /* Reliable buffer to outgoing TCP/UDP (send up to CONTROL_SEND_ACK_MAX ACKs + * for previously received packets) */ + if (!to_link->len && reliable_can_send(ks->send_reliable)) + { + int opcode; + struct buffer b; + + buf = reliable_send(ks->send_reliable, &opcode); + ASSERT(buf); + b = *buf; + INCR_SENT; + + write_control_auth(session, ks, &b, to_link_addr, opcode, + CONTROL_SEND_ACK_MAX, true); + *to_link = b; + active = true; + state_change = true; + dmsg(D_TLS_DEBUG, "Reliable -> TCP/UDP"); + break; + } + + /* Write incoming ciphertext to TLS object */ + buf = reliable_get_buf_sequenced(ks->rec_reliable); + if (buf) + { + int status = 0; + if (buf->len) + { + status = key_state_write_ciphertext(&ks->ks_ssl, buf); + if (status == -1) + { + msg(D_TLS_ERRORS, + "TLS Error: Incoming Ciphertext -> TLS object write error"); + goto error; + } + } + else + { + status = 1; + } + if (status == 1) + { + reliable_mark_deleted(ks->rec_reliable, buf, true); + state_change = true; + dmsg(D_TLS_DEBUG, "Incoming Ciphertext -> TLS"); + } + } + + /* Read incoming plaintext from TLS object */ + buf = &ks->plaintext_read_buf; + if (!buf->len) + { + int status; + + ASSERT(buf_init(buf, 0)); + status = key_state_read_plaintext(&ks->ks_ssl, buf, TLS_CHANNEL_BUF_SIZE); + update_time(); + if (status == -1) + { + msg(D_TLS_ERRORS, "TLS Error: TLS object -> incoming plaintext read error"); + goto error; + } + if (status == 1) + { + state_change = true; + dmsg(D_TLS_DEBUG, "TLS -> Incoming Plaintext"); + } + } + + /* Send Key */ + buf = &ks->plaintext_write_buf; + if (!buf->len && ((ks->state == S_START && !session->opt->server) + || (ks->state == S_GOT_KEY && session->opt->server))) + { + if (session->opt->key_method == 1) + { + if (!key_method_1_write(buf, session)) + { + goto error; + } + } + else if (session->opt->key_method == 2) + { + if (!key_method_2_write(buf, session)) + { + goto error; + } + } + else + { + ASSERT(0); + } + + state_change = true; + dmsg(D_TLS_DEBUG_MED, "STATE S_SENT_KEY"); + ks->state = S_SENT_KEY; + } + + /* Receive Key */ + buf = &ks->plaintext_read_buf; + if (buf->len + && ((ks->state == S_SENT_KEY && !session->opt->server) + || (ks->state == S_START && session->opt->server))) + { + if (session->opt->key_method == 1) + { + if (!key_method_1_read(buf, session)) + { + goto error; + } + } + else if (session->opt->key_method == 2) + { + if (!key_method_2_read(buf, multi, session)) + { + goto error; + } + } + else + { + ASSERT(0); + } + + state_change = true; + dmsg(D_TLS_DEBUG_MED, "STATE S_GOT_KEY"); + ks->state = S_GOT_KEY; + } + + /* Write outgoing plaintext to TLS object */ + buf = &ks->plaintext_write_buf; + if (buf->len) + { + int status = key_state_write_plaintext(&ks->ks_ssl, buf); + if (status == -1) + { + msg(D_TLS_ERRORS, + "TLS ERROR: Outgoing Plaintext -> TLS object write error"); + goto error; + } + if (status == 1) + { + state_change = true; + dmsg(D_TLS_DEBUG, "Outgoing Plaintext -> TLS"); + } + } + + /* Outgoing Ciphertext to reliable buffer */ + if (ks->state >= S_START) + { + buf = reliable_get_buf_output_sequenced(ks->send_reliable); + if (buf) + { + int status = key_state_read_ciphertext(&ks->ks_ssl, buf, PAYLOAD_SIZE_DYNAMIC(&multi->opt.frame)); + if (status == -1) + { + msg(D_TLS_ERRORS, + "TLS Error: Ciphertext -> reliable TCP/UDP transport read error"); + goto error; + } + if (status == 1) + { + reliable_mark_active_outgoing(ks->send_reliable, buf, P_CONTROL_V1); + INCR_GENERATED; + state_change = true; + dmsg(D_TLS_DEBUG, "Outgoing Ciphertext -> Reliable"); + } + } + } + } + while (state_change); + + update_time(); + + /* Send 1 or more ACKs (each received control packet gets one ACK) */ + if (!to_link->len && !reliable_ack_empty(ks->rec_ack)) + { + struct buffer buf = ks->ack_write_buf; + ASSERT(buf_init(&buf, FRAME_HEADROOM(&multi->opt.frame))); + write_control_auth(session, ks, &buf, to_link_addr, P_ACK_V1, + RELIABLE_ACK_SIZE, false); + *to_link = buf; + active = true; + dmsg(D_TLS_DEBUG, "Dedicated ACK -> TCP/UDP"); + } + + /* When should we wake up again? */ + { + if (ks->state >= S_INITIAL) + { + compute_earliest_wakeup(wakeup, + reliable_send_timeout(ks->send_reliable)); + + if (ks->must_negotiate) + { + compute_earliest_wakeup(wakeup, ks->must_negotiate - now); + } + } + + if (ks->established && session->opt->renegotiate_seconds) + { + compute_earliest_wakeup(wakeup, + ks->established + session->opt->renegotiate_seconds - now); + } + + /* prevent event-loop spinning by setting minimum wakeup of 1 second */ + if (*wakeup <= 0) + { + *wakeup = 1; + + /* if we had something to send to remote, but to_link was busy, + * let caller know we need to be called again soon */ + active = true; + } + + dmsg(D_TLS_DEBUG, "TLS: tls_process: timeout set to %d", *wakeup); + + gc_free(&gc); + return active; + } error: - tls_clear_error(); - ks->state = S_ERROR; - msg (D_TLS_ERRORS, "TLS Error: TLS handshake failed"); - INCR_ERROR; - gc_free (&gc); - return false; + tls_clear_error(); + ks->state = S_ERROR; + msg(D_TLS_ERRORS, "TLS Error: TLS handshake failed"); + INCR_ERROR; + gc_free(&gc); + return false; } /* @@ -2892,154 +3081,168 @@ tls_process (struct tls_multi *multi, */ int -tls_multi_process (struct tls_multi *multi, - struct buffer *to_link, - struct link_socket_actual **to_link_addr, - struct link_socket_info *to_link_socket_info, - interval_t *wakeup) -{ - struct gc_arena gc = gc_new (); - int i; - int active = TLSMP_INACTIVE; - bool error = false; - int tas; - - perf_push (PERF_TLS_MULTI_PROCESS); - - tls_clear_error (); - - /* - * Process each session object having state of S_INITIAL or greater, - * and which has a defined remote IP addr. - */ - - for (i = 0; i < TM_SIZE; ++i) - { - struct tls_session *session = &multi->session[i]; - struct key_state *ks = &session->key[KS_PRIMARY]; - struct key_state *ks_lame = &session->key[KS_LAME_DUCK]; - - /* set initial remote address */ - if (i == TM_ACTIVE && ks->state == S_INITIAL && - link_socket_actual_defined (&to_link_socket_info->lsa->actual)) - ks->remote_addr = to_link_socket_info->lsa->actual; - - dmsg (D_TLS_DEBUG, - "TLS: tls_multi_process: i=%d state=%s, mysid=%s, stored-sid=%s, stored-ip=%s", - i, - state_name (ks->state), - session_id_print (&session->session_id, &gc), - session_id_print (&ks->session_id_remote, &gc), - print_link_socket_actual (&ks->remote_addr, &gc)); - - if (ks->state >= S_INITIAL && link_socket_actual_defined (&ks->remote_addr)) - { - struct link_socket_actual *tla = NULL; - - update_time (); - - if (tls_process (multi, session, to_link, &tla, - to_link_socket_info, wakeup)) - active = TLSMP_ACTIVE; - - /* - * If tls_process produced an outgoing packet, - * return the link_socket_actual object (which - * contains the outgoing address). - */ - if (tla) - { - multi->to_link_addr = *tla; - *to_link_addr = &multi->to_link_addr; - } - - /* - * If tls_process hits an error: - * (1) If the session has an unexpired lame duck key, preserve it. - * (2) Reinitialize the session. - * (3) Increment soft error count - */ - if (ks->state == S_ERROR) - { - ++multi->n_soft_errors; - - if (i == TM_ACTIVE) - error = true; - - if (i == TM_ACTIVE - && ks_lame->state >= S_ACTIVE - && !multi->opt.single_session) - move_session (multi, TM_LAME_DUCK, TM_ACTIVE, true); - else - reset_session (multi, session); - } - } - } - - update_time (); - - tas = tls_authentication_status (multi, TLS_MULTI_AUTH_STATUS_INTERVAL); - - /* - * If lame duck session expires, kill it. - */ - if (lame_duck_must_die (&multi->session[TM_LAME_DUCK], wakeup)) { - tls_session_free (&multi->session[TM_LAME_DUCK], true); - msg (D_TLS_DEBUG_LOW, "TLS: tls_multi_process: killed expiring key"); - } - - /* - * If untrusted session achieves TLS authentication, - * move it to active session, usurping any prior session. - * - * A semi-trusted session is one in which the certificate authentication - * succeeded (if cert verification is enabled) but the username/password - * verification failed. A semi-trusted session can forward data on the - * TLS control channel but not on the tunnel channel. - */ - if (DECRYPT_KEY_ENABLED (multi, &multi->session[TM_UNTRUSTED].key[KS_PRIMARY])) { - move_session (multi, TM_ACTIVE, TM_UNTRUSTED, true); - msg (D_TLS_DEBUG_LOW, "TLS: tls_multi_process: untrusted session promoted to %strusted", - tas == TLS_AUTHENTICATION_SUCCEEDED ? "" : "semi-"); - } - - /* - * A hard error means that TM_ACTIVE hit an S_ERROR state and that no - * other key state objects are S_ACTIVE or higher. - */ - if (error) - { - for (i = 0; i < (int) SIZE (multi->key_scan); ++i) - { - if (multi->key_scan[i]->state >= S_ACTIVE) - goto nohard; - } - ++multi->n_hard_errors; - } - nohard: +tls_multi_process(struct tls_multi *multi, + struct buffer *to_link, + struct link_socket_actual **to_link_addr, + struct link_socket_info *to_link_socket_info, + interval_t *wakeup) +{ + struct gc_arena gc = gc_new(); + int i; + int active = TLSMP_INACTIVE; + bool error = false; + int tas; + + perf_push(PERF_TLS_MULTI_PROCESS); + + tls_clear_error(); + + /* + * Process each session object having state of S_INITIAL or greater, + * and which has a defined remote IP addr. + */ + + for (i = 0; i < TM_SIZE; ++i) + { + struct tls_session *session = &multi->session[i]; + struct key_state *ks = &session->key[KS_PRIMARY]; + struct key_state *ks_lame = &session->key[KS_LAME_DUCK]; + + /* set initial remote address */ + if (i == TM_ACTIVE && ks->state == S_INITIAL + && link_socket_actual_defined(&to_link_socket_info->lsa->actual)) + { + ks->remote_addr = to_link_socket_info->lsa->actual; + } + + dmsg(D_TLS_DEBUG, + "TLS: tls_multi_process: i=%d state=%s, mysid=%s, stored-sid=%s, stored-ip=%s", + i, + state_name(ks->state), + session_id_print(&session->session_id, &gc), + session_id_print(&ks->session_id_remote, &gc), + print_link_socket_actual(&ks->remote_addr, &gc)); + + if (ks->state >= S_INITIAL && link_socket_actual_defined(&ks->remote_addr)) + { + struct link_socket_actual *tla = NULL; + + update_time(); + + if (tls_process(multi, session, to_link, &tla, + to_link_socket_info, wakeup)) + { + active = TLSMP_ACTIVE; + } + + /* + * If tls_process produced an outgoing packet, + * return the link_socket_actual object (which + * contains the outgoing address). + */ + if (tla) + { + multi->to_link_addr = *tla; + *to_link_addr = &multi->to_link_addr; + } + + /* + * If tls_process hits an error: + * (1) If the session has an unexpired lame duck key, preserve it. + * (2) Reinitialize the session. + * (3) Increment soft error count + */ + if (ks->state == S_ERROR) + { + ++multi->n_soft_errors; + + if (i == TM_ACTIVE) + { + error = true; + } + + if (i == TM_ACTIVE + && ks_lame->state >= S_ACTIVE + && !multi->opt.single_session) + { + move_session(multi, TM_LAME_DUCK, TM_ACTIVE, true); + } + else + { + reset_session(multi, session); + } + } + } + } + + update_time(); + + tas = tls_authentication_status(multi, TLS_MULTI_AUTH_STATUS_INTERVAL); + + /* + * If lame duck session expires, kill it. + */ + if (lame_duck_must_die(&multi->session[TM_LAME_DUCK], wakeup)) + { + tls_session_free(&multi->session[TM_LAME_DUCK], true); + msg(D_TLS_DEBUG_LOW, "TLS: tls_multi_process: killed expiring key"); + } + + /* + * If untrusted session achieves TLS authentication, + * move it to active session, usurping any prior session. + * + * A semi-trusted session is one in which the certificate authentication + * succeeded (if cert verification is enabled) but the username/password + * verification failed. A semi-trusted session can forward data on the + * TLS control channel but not on the tunnel channel. + */ + if (DECRYPT_KEY_ENABLED(multi, &multi->session[TM_UNTRUSTED].key[KS_PRIMARY])) + { + move_session(multi, TM_ACTIVE, TM_UNTRUSTED, true); + msg(D_TLS_DEBUG_LOW, "TLS: tls_multi_process: untrusted session promoted to %strusted", + tas == TLS_AUTHENTICATION_SUCCEEDED ? "" : "semi-"); + } + + /* + * A hard error means that TM_ACTIVE hit an S_ERROR state and that no + * other key state objects are S_ACTIVE or higher. + */ + if (error) + { + for (i = 0; i < (int) SIZE(multi->key_scan); ++i) + { + if (multi->key_scan[i]->state >= S_ACTIVE) + { + goto nohard; + } + } + ++multi->n_hard_errors; + } +nohard: #ifdef ENABLE_DEBUG - /* DEBUGGING -- flood peer with repeating connection attempts */ - { - const int throw_level = GREMLIN_CONNECTION_FLOOD_LEVEL (multi->opt.gremlin); - if (throw_level) - { - for (i = 0; i < (int) SIZE (multi->key_scan); ++i) - { - if (multi->key_scan[i]->state >= throw_level) - { - ++multi->n_hard_errors; - ++multi->n_soft_errors; - } - } - } - } + /* DEBUGGING -- flood peer with repeating connection attempts */ + { + const int throw_level = GREMLIN_CONNECTION_FLOOD_LEVEL(multi->opt.gremlin); + if (throw_level) + { + for (i = 0; i < (int) SIZE(multi->key_scan); ++i) + { + if (multi->key_scan[i]->state >= throw_level) + { + ++multi->n_hard_errors; + ++multi->n_soft_errors; + } + } + } + } #endif - perf_pop (); - gc_free (&gc); + perf_pop(); + gc_free(&gc); - return (tas == TLS_AUTHENTICATION_FAILED) ? TLSMP_KILL : active; + return (tas == TLS_AUTHENTICATION_FAILED) ? TLSMP_KILL : active; } /* @@ -3073,456 +3276,465 @@ tls_multi_process (struct tls_multi *multi, */ bool -tls_pre_decrypt (struct tls_multi *multi, - const struct link_socket_actual *from, - struct buffer *buf, - struct crypto_options **opt, - bool floated, - const uint8_t **ad_start) -{ - struct gc_arena gc = gc_new (); - bool ret = false; - - if (buf->len > 0) - { - int i; - int op; - int key_id; - - /* get opcode and key ID */ - { - uint8_t c = *BPTR (buf); - op = c >> P_OPCODE_SHIFT; - key_id = c & P_KEY_ID_MASK; - } - - if ((op == P_DATA_V1) || (op == P_DATA_V2)) - { - /* data channel packet */ - for (i = 0; i < KEY_SCAN_SIZE; ++i) - { - struct key_state *ks = multi->key_scan[i]; - - /* - * This is the basic test of TLS state compatibility between a local OpenVPN - * instance and its remote peer. - * - * If the test fails, it tells us that we are getting a packet from a source - * which claims reference to a prior negotiated TLS session, but the local - * OpenVPN instance has no memory of such a negotiation. - * - * It almost always occurs on UDP sessions when the passive side of the - * connection is restarted without the active side restarting as well (the - * passive side is the server which only listens for the connections, the - * active side is the client which initiates connections). - */ - if (DECRYPT_KEY_ENABLED (multi, ks) - && key_id == ks->key_id - && ks->authenticated +tls_pre_decrypt(struct tls_multi *multi, + const struct link_socket_actual *from, + struct buffer *buf, + struct crypto_options **opt, + bool floated, + const uint8_t **ad_start) +{ + struct gc_arena gc = gc_new(); + bool ret = false; + + if (buf->len > 0) + { + int i; + int op; + int key_id; + + /* get opcode and key ID */ + { + uint8_t c = *BPTR(buf); + op = c >> P_OPCODE_SHIFT; + key_id = c & P_KEY_ID_MASK; + } + + if ((op == P_DATA_V1) || (op == P_DATA_V2)) + { + /* data channel packet */ + for (i = 0; i < KEY_SCAN_SIZE; ++i) + { + struct key_state *ks = multi->key_scan[i]; + + /* + * This is the basic test of TLS state compatibility between a local OpenVPN + * instance and its remote peer. + * + * If the test fails, it tells us that we are getting a packet from a source + * which claims reference to a prior negotiated TLS session, but the local + * OpenVPN instance has no memory of such a negotiation. + * + * It almost always occurs on UDP sessions when the passive side of the + * connection is restarted without the active side restarting as well (the + * passive side is the server which only listens for the connections, the + * active side is the client which initiates connections). + */ + if (DECRYPT_KEY_ENABLED(multi, ks) + && key_id == ks->key_id + && ks->authenticated #ifdef ENABLE_DEF_AUTH - && !ks->auth_deferred + && !ks->auth_deferred #endif - && (floated || link_socket_actual_match (from, &ks->remote_addr))) - { - if (!ks->crypto_options.key_ctx_bi.initialized) - { - msg (D_TLS_DEBUG_LOW, - "Key %s [%d] not initialized (yet), dropping packet.", - print_link_socket_actual (from, &gc), key_id); - goto error_lite; - } - - /* return appropriate data channel decrypt key in opt */ - *opt = &ks->crypto_options; - if (op == P_DATA_V2) - { - *ad_start = BPTR(buf); - } - ASSERT (buf_advance (buf, 1)); - if (op == P_DATA_V1) - { - *ad_start = BPTR(buf); - } - else if (op == P_DATA_V2) - { - if (buf->len < 4) - { - msg (D_TLS_ERRORS, "Protocol error: received P_DATA_V2 from %s but length is < 4", - print_link_socket_actual (from, &gc)); - goto error; - } - ASSERT (buf_advance (buf, 3)); - } - - ++ks->n_packets; - ks->n_bytes += buf->len; - dmsg (D_TLS_KEYSELECT, - "TLS: tls_pre_decrypt, key_id=%d, IP=%s", - key_id, print_link_socket_actual (from, &gc)); - gc_free (&gc); - return ret; - } - } - - msg (D_TLS_ERRORS, - "TLS Error: local/remote TLS keys are out of sync: %s [%d]", - print_link_socket_actual (from, &gc), key_id); - goto error_lite; - } - else /* control channel packet */ - { - bool do_burst = false; - bool new_link = false; - struct session_id sid; /* remote session ID */ - - /* verify legal opcode */ - if (op < P_FIRST_OPCODE || op > P_LAST_OPCODE) - { - msg (D_TLS_ERRORS, - "TLS Error: unknown opcode received from %s op=%d", - print_link_socket_actual (from, &gc), op); - goto error; - } - - /* hard reset ? */ - if (is_hard_reset (op, 0)) - { - /* verify client -> server or server -> client connection */ - if (((op == P_CONTROL_HARD_RESET_CLIENT_V1 - || op == P_CONTROL_HARD_RESET_CLIENT_V2) && !multi->opt.server) - || ((op == P_CONTROL_HARD_RESET_SERVER_V1 - || op == P_CONTROL_HARD_RESET_SERVER_V2) && multi->opt.server)) - { - msg (D_TLS_ERRORS, - "TLS Error: client->client or server->server connection attempted from %s", - print_link_socket_actual (from, &gc)); - goto error; - } - } - - /* - * Authenticate Packet - */ - dmsg (D_TLS_DEBUG, "TLS: control channel, op=%s, IP=%s", - packet_opcode_name (op), print_link_socket_actual (from, &gc)); - - /* get remote session-id */ - { - struct buffer tmp = *buf; - buf_advance (&tmp, 1); - if (!session_id_read (&sid, &tmp) || !session_id_defined (&sid)) - { - msg (D_TLS_ERRORS, - "TLS Error: session-id not found in packet from %s", - print_link_socket_actual (from, &gc)); - goto error; - } - } - - /* use session ID to match up packet with appropriate tls_session object */ - for (i = 0; i < TM_SIZE; ++i) - { - struct tls_session *session = &multi->session[i]; - struct key_state *ks = &session->key[KS_PRIMARY]; - - dmsg (D_TLS_DEBUG, - "TLS: initial packet test, i=%d state=%s, mysid=%s, rec-sid=%s, rec-ip=%s, stored-sid=%s, stored-ip=%s", - i, - state_name (ks->state), - session_id_print (&session->session_id, &gc), - session_id_print (&sid, &gc), - print_link_socket_actual (from, &gc), - session_id_print (&ks->session_id_remote, &gc), - print_link_socket_actual (&ks->remote_addr, &gc)); - - if (session_id_equal (&ks->session_id_remote, &sid)) - /* found a match */ - { - if (i == TM_LAME_DUCK) { - msg (D_TLS_ERRORS, - "TLS ERROR: received control packet with stale session-id=%s", - session_id_print (&sid, &gc)); - goto error; - } - dmsg (D_TLS_DEBUG, - "TLS: found match, session[%d], sid=%s", - i, session_id_print (&sid, &gc)); - break; - } - } - - /* - * Initial packet received. - */ - - if (i == TM_SIZE && is_hard_reset (op, 0)) - { - struct tls_session *session = &multi->session[TM_ACTIVE]; - struct key_state *ks = &session->key[KS_PRIMARY]; - - if (!is_hard_reset (op, multi->opt.key_method)) - { - msg (D_TLS_ERRORS, "TLS ERROR: initial packet local/remote key_method mismatch, local key_method=%d, op=%s", - multi->opt.key_method, - packet_opcode_name (op)); - goto error; - } - - /* - * If we have no session currently in progress, the initial packet will - * open a new session in TM_ACTIVE rather than TM_UNTRUSTED. - */ - if (!session_id_defined (&ks->session_id_remote)) - { - if (multi->opt.single_session && multi->n_sessions) - { - msg (D_TLS_ERRORS, - "TLS Error: Cannot accept new session request from %s due to session context expire or --single-session [1]", - print_link_socket_actual (from, &gc)); - goto error; - } + && (floated || link_socket_actual_match(from, &ks->remote_addr))) + { + if (!ks->crypto_options.key_ctx_bi.initialized) + { + msg(D_TLS_DEBUG_LOW, + "Key %s [%d] not initialized (yet), dropping packet.", + print_link_socket_actual(from, &gc), key_id); + goto error_lite; + } + + /* return appropriate data channel decrypt key in opt */ + *opt = &ks->crypto_options; + if (op == P_DATA_V2) + { + *ad_start = BPTR(buf); + } + ASSERT(buf_advance(buf, 1)); + if (op == P_DATA_V1) + { + *ad_start = BPTR(buf); + } + else if (op == P_DATA_V2) + { + if (buf->len < 4) + { + msg(D_TLS_ERRORS, "Protocol error: received P_DATA_V2 from %s but length is < 4", + print_link_socket_actual(from, &gc)); + goto error; + } + ASSERT(buf_advance(buf, 3)); + } + + ++ks->n_packets; + ks->n_bytes += buf->len; + dmsg(D_TLS_KEYSELECT, + "TLS: tls_pre_decrypt, key_id=%d, IP=%s", + key_id, print_link_socket_actual(from, &gc)); + gc_free(&gc); + return ret; + } + } + + msg(D_TLS_ERRORS, + "TLS Error: local/remote TLS keys are out of sync: %s [%d]", + print_link_socket_actual(from, &gc), key_id); + goto error_lite; + } + else /* control channel packet */ + { + bool do_burst = false; + bool new_link = false; + struct session_id sid; /* remote session ID */ + + /* verify legal opcode */ + if (op < P_FIRST_OPCODE || op > P_LAST_OPCODE) + { + msg(D_TLS_ERRORS, + "TLS Error: unknown opcode received from %s op=%d", + print_link_socket_actual(from, &gc), op); + goto error; + } + + /* hard reset ? */ + if (is_hard_reset(op, 0)) + { + /* verify client -> server or server -> client connection */ + if (((op == P_CONTROL_HARD_RESET_CLIENT_V1 + || op == P_CONTROL_HARD_RESET_CLIENT_V2) && !multi->opt.server) + || ((op == P_CONTROL_HARD_RESET_SERVER_V1 + || op == P_CONTROL_HARD_RESET_SERVER_V2) && multi->opt.server)) + { + msg(D_TLS_ERRORS, + "TLS Error: client->client or server->server connection attempted from %s", + print_link_socket_actual(from, &gc)); + goto error; + } + } + + /* + * Authenticate Packet + */ + dmsg(D_TLS_DEBUG, "TLS: control channel, op=%s, IP=%s", + packet_opcode_name(op), print_link_socket_actual(from, &gc)); + + /* get remote session-id */ + { + struct buffer tmp = *buf; + buf_advance(&tmp, 1); + if (!session_id_read(&sid, &tmp) || !session_id_defined(&sid)) + { + msg(D_TLS_ERRORS, + "TLS Error: session-id not found in packet from %s", + print_link_socket_actual(from, &gc)); + goto error; + } + } + + /* use session ID to match up packet with appropriate tls_session object */ + for (i = 0; i < TM_SIZE; ++i) + { + struct tls_session *session = &multi->session[i]; + struct key_state *ks = &session->key[KS_PRIMARY]; + + dmsg(D_TLS_DEBUG, + "TLS: initial packet test, i=%d state=%s, mysid=%s, rec-sid=%s, rec-ip=%s, stored-sid=%s, stored-ip=%s", + i, + state_name(ks->state), + session_id_print(&session->session_id, &gc), + session_id_print(&sid, &gc), + print_link_socket_actual(from, &gc), + session_id_print(&ks->session_id_remote, &gc), + print_link_socket_actual(&ks->remote_addr, &gc)); + + if (session_id_equal(&ks->session_id_remote, &sid)) + /* found a match */ + { + if (i == TM_LAME_DUCK) + { + msg(D_TLS_ERRORS, + "TLS ERROR: received control packet with stale session-id=%s", + session_id_print(&sid, &gc)); + goto error; + } + dmsg(D_TLS_DEBUG, + "TLS: found match, session[%d], sid=%s", + i, session_id_print(&sid, &gc)); + break; + } + } + + /* + * Initial packet received. + */ + + if (i == TM_SIZE && is_hard_reset(op, 0)) + { + struct tls_session *session = &multi->session[TM_ACTIVE]; + struct key_state *ks = &session->key[KS_PRIMARY]; + + if (!is_hard_reset(op, multi->opt.key_method)) + { + msg(D_TLS_ERRORS, "TLS ERROR: initial packet local/remote key_method mismatch, local key_method=%d, op=%s", + multi->opt.key_method, + packet_opcode_name(op)); + goto error; + } + + /* + * If we have no session currently in progress, the initial packet will + * open a new session in TM_ACTIVE rather than TM_UNTRUSTED. + */ + if (!session_id_defined(&ks->session_id_remote)) + { + if (multi->opt.single_session && multi->n_sessions) + { + msg(D_TLS_ERRORS, + "TLS Error: Cannot accept new session request from %s due to session context expire or --single-session [1]", + print_link_socket_actual(from, &gc)); + goto error; + } #ifdef ENABLE_MANAGEMENT - if (management) - { - management_set_state (management, - OPENVPN_STATE_AUTH, - NULL, - NULL, - NULL, - NULL, - NULL); - } + if (management) + { + management_set_state(management, + OPENVPN_STATE_AUTH, + NULL, + NULL, + NULL, + NULL, + NULL); + } #endif - msg (D_TLS_DEBUG_LOW, - "TLS: Initial packet from %s, sid=%s", - print_link_socket_actual (from, &gc), - session_id_print (&sid, &gc)); - - do_burst = true; - new_link = true; - i = TM_ACTIVE; - session->untrusted_addr = *from; - } - } - - if (i == TM_SIZE && is_hard_reset (op, 0)) - { - /* - * No match with existing sessions, - * probably a new session. - */ - struct tls_session *session = &multi->session[TM_UNTRUSTED]; - - /* - * If --single-session, don't allow any hard-reset connection request - * unless it the the first packet of the session. - */ - if (multi->opt.single_session) - { - msg (D_TLS_ERRORS, - "TLS Error: Cannot accept new session request from %s due to session context expire or --single-session [2]", - print_link_socket_actual (from, &gc)); - goto error; - } - - if (!is_hard_reset (op, multi->opt.key_method)) - { - msg (D_TLS_ERRORS, "TLS ERROR: new session local/remote key_method mismatch, local key_method=%d, op=%s", - multi->opt.key_method, - packet_opcode_name (op)); - goto error; - } - - if (!read_control_auth (buf, &session->tls_wrap, from)) - goto error; - - /* - * New session-initiating control packet is authenticated at this point, - * assuming that the --tls-auth command line option was used. - * - * Without --tls-auth, we leave authentication entirely up to TLS. - */ - msg (D_TLS_DEBUG_LOW, - "TLS: new session incoming connection from %s", - print_link_socket_actual (from, &gc)); - - new_link = true; - i = TM_UNTRUSTED; - session->untrusted_addr = *from; - } - else - { - struct tls_session *session = &multi->session[i]; - struct key_state *ks = &session->key[KS_PRIMARY]; - - /* - * Packet must belong to an existing session. - */ - if (i != TM_ACTIVE && i != TM_UNTRUSTED) - { - msg (D_TLS_ERRORS, - "TLS Error: Unroutable control packet received from %s (si=%d op=%s)", - print_link_socket_actual (from, &gc), - i, - packet_opcode_name (op)); - goto error; - } - - /* - * Verify remote IP address - */ - if (!new_link && !link_socket_actual_match (&ks->remote_addr, from)) - { - msg (D_TLS_ERRORS, "TLS Error: Received control packet from unexpected IP addr: %s", - print_link_socket_actual (from, &gc)); - goto error; - } - - /* - * Remote is requesting a key renegotiation - */ - if (op == P_CONTROL_SOFT_RESET_V1 - && DECRYPT_KEY_ENABLED (multi, ks)) - { - if (!read_control_auth (buf, &session->tls_wrap, from)) - goto error; - - key_state_soft_reset (session); - - dmsg (D_TLS_DEBUG, - "TLS: received P_CONTROL_SOFT_RESET_V1 s=%d sid=%s", - i, session_id_print (&sid, &gc)); - } - else - { - /* - * Remote responding to our key renegotiation request? - */ - if (op == P_CONTROL_SOFT_RESET_V1) - do_burst = true; - - if (!read_control_auth (buf, &session->tls_wrap, from)) - goto error; - - dmsg (D_TLS_DEBUG, - "TLS: received control channel packet s#=%d sid=%s", - i, session_id_print (&sid, &gc)); - } - } - - /* - * We have an authenticated packet (if --tls-auth was set). - * Now pass to our reliability level which deals with - * packet acknowledgements, retransmits, sequencing, etc. - */ - { - struct tls_session *session = &multi->session[i]; - struct key_state *ks = &session->key[KS_PRIMARY]; - - /* Make sure we were initialized and that we're not in an error state */ - ASSERT (ks->state != S_UNDEF); - ASSERT (ks->state != S_ERROR); - ASSERT (session_id_defined (&session->session_id)); - - /* Let our caller know we processed a control channel packet */ - ret = true; - - /* - * Set our remote address and remote session_id - */ - if (new_link) - { - ks->session_id_remote = sid; - ks->remote_addr = *from; - ++multi->n_sessions; - } - else if (!link_socket_actual_match (&ks->remote_addr, from)) - { - msg (D_TLS_ERRORS, - "TLS Error: Existing session control channel packet from unknown IP address: %s", - print_link_socket_actual (from, &gc)); - goto error; - } - - /* - * Should we do a retransmit of all unacknowledged packets in - * the send buffer? This improves the start-up efficiency of the - * initial key negotiation after the 2nd peer comes online. - */ - if (do_burst && !session->burst) - { - reliable_schedule_now (ks->send_reliable); - session->burst = true; - } - - /* Check key_id */ - if (ks->key_id != key_id) - { - msg (D_TLS_ERRORS, - "TLS ERROR: local/remote key IDs out of sync (%d/%d) ID: %s", - ks->key_id, key_id, print_key_id (multi, &gc)); - goto error; - } - - /* - * Process incoming ACKs for packets we can now - * delete from reliable send buffer - */ - { - /* buffers all packet IDs to delete from send_reliable */ - struct reliable_ack send_ack; - - send_ack.len = 0; - if (!reliable_ack_read (&send_ack, buf, &session->session_id)) - { - msg (D_TLS_ERRORS, - "TLS Error: reading acknowledgement record from packet"); - goto error; - } - reliable_send_purge (ks->send_reliable, &send_ack); - } - - if (op != P_ACK_V1 && reliable_can_get (ks->rec_reliable)) - { - packet_id_type id; - - /* Extract the packet ID from the packet */ - if (reliable_ack_read_packet_id (buf, &id)) - { - /* Avoid deadlock by rejecting packet that would de-sequentialize receive buffer */ - if (reliable_wont_break_sequentiality (ks->rec_reliable, id)) - { - if (reliable_not_replay (ks->rec_reliable, id)) - { - /* Save incoming ciphertext packet to reliable buffer */ - struct buffer *in = reliable_get_buf (ks->rec_reliable); - ASSERT (in); - ASSERT (buf_copy (in, buf)); - reliable_mark_active_incoming (ks->rec_reliable, in, id, op); - } - - /* Process outgoing acknowledgment for packet just received, even if it's a replay */ - reliable_ack_acknowledge_packet_id (ks->rec_ack, id); - } - } - } - } - } - } - - done: - buf->len = 0; - *opt = NULL; - gc_free (&gc); - return ret; - - error: - ++multi->n_soft_errors; - error_lite: - tls_clear_error(); - goto done; + msg(D_TLS_DEBUG_LOW, + "TLS: Initial packet from %s, sid=%s", + print_link_socket_actual(from, &gc), + session_id_print(&sid, &gc)); + + do_burst = true; + new_link = true; + i = TM_ACTIVE; + session->untrusted_addr = *from; + } + } + + if (i == TM_SIZE && is_hard_reset(op, 0)) + { + /* + * No match with existing sessions, + * probably a new session. + */ + struct tls_session *session = &multi->session[TM_UNTRUSTED]; + + /* + * If --single-session, don't allow any hard-reset connection request + * unless it the the first packet of the session. + */ + if (multi->opt.single_session) + { + msg(D_TLS_ERRORS, + "TLS Error: Cannot accept new session request from %s due to session context expire or --single-session [2]", + print_link_socket_actual(from, &gc)); + goto error; + } + + if (!is_hard_reset(op, multi->opt.key_method)) + { + msg(D_TLS_ERRORS, "TLS ERROR: new session local/remote key_method mismatch, local key_method=%d, op=%s", + multi->opt.key_method, + packet_opcode_name(op)); + goto error; + } + + if (!read_control_auth(buf, &session->tls_wrap, from)) + { + goto error; + } + + /* + * New session-initiating control packet is authenticated at this point, + * assuming that the --tls-auth command line option was used. + * + * Without --tls-auth, we leave authentication entirely up to TLS. + */ + msg(D_TLS_DEBUG_LOW, + "TLS: new session incoming connection from %s", + print_link_socket_actual(from, &gc)); + + new_link = true; + i = TM_UNTRUSTED; + session->untrusted_addr = *from; + } + else + { + struct tls_session *session = &multi->session[i]; + struct key_state *ks = &session->key[KS_PRIMARY]; + + /* + * Packet must belong to an existing session. + */ + if (i != TM_ACTIVE && i != TM_UNTRUSTED) + { + msg(D_TLS_ERRORS, + "TLS Error: Unroutable control packet received from %s (si=%d op=%s)", + print_link_socket_actual(from, &gc), + i, + packet_opcode_name(op)); + goto error; + } + + /* + * Verify remote IP address + */ + if (!new_link && !link_socket_actual_match(&ks->remote_addr, from)) + { + msg(D_TLS_ERRORS, "TLS Error: Received control packet from unexpected IP addr: %s", + print_link_socket_actual(from, &gc)); + goto error; + } + + /* + * Remote is requesting a key renegotiation + */ + if (op == P_CONTROL_SOFT_RESET_V1 + && DECRYPT_KEY_ENABLED(multi, ks)) + { + if (!read_control_auth(buf, &session->tls_wrap, from)) + { + goto error; + } + + key_state_soft_reset(session); + + dmsg(D_TLS_DEBUG, + "TLS: received P_CONTROL_SOFT_RESET_V1 s=%d sid=%s", + i, session_id_print(&sid, &gc)); + } + else + { + /* + * Remote responding to our key renegotiation request? + */ + if (op == P_CONTROL_SOFT_RESET_V1) + { + do_burst = true; + } + + if (!read_control_auth(buf, &session->tls_wrap, from)) + { + goto error; + } + + dmsg(D_TLS_DEBUG, + "TLS: received control channel packet s#=%d sid=%s", + i, session_id_print(&sid, &gc)); + } + } + + /* + * We have an authenticated packet (if --tls-auth was set). + * Now pass to our reliability level which deals with + * packet acknowledgements, retransmits, sequencing, etc. + */ + { + struct tls_session *session = &multi->session[i]; + struct key_state *ks = &session->key[KS_PRIMARY]; + + /* Make sure we were initialized and that we're not in an error state */ + ASSERT(ks->state != S_UNDEF); + ASSERT(ks->state != S_ERROR); + ASSERT(session_id_defined(&session->session_id)); + + /* Let our caller know we processed a control channel packet */ + ret = true; + + /* + * Set our remote address and remote session_id + */ + if (new_link) + { + ks->session_id_remote = sid; + ks->remote_addr = *from; + ++multi->n_sessions; + } + else if (!link_socket_actual_match(&ks->remote_addr, from)) + { + msg(D_TLS_ERRORS, + "TLS Error: Existing session control channel packet from unknown IP address: %s", + print_link_socket_actual(from, &gc)); + goto error; + } + + /* + * Should we do a retransmit of all unacknowledged packets in + * the send buffer? This improves the start-up efficiency of the + * initial key negotiation after the 2nd peer comes online. + */ + if (do_burst && !session->burst) + { + reliable_schedule_now(ks->send_reliable); + session->burst = true; + } + + /* Check key_id */ + if (ks->key_id != key_id) + { + msg(D_TLS_ERRORS, + "TLS ERROR: local/remote key IDs out of sync (%d/%d) ID: %s", + ks->key_id, key_id, print_key_id(multi, &gc)); + goto error; + } + + /* + * Process incoming ACKs for packets we can now + * delete from reliable send buffer + */ + { + /* buffers all packet IDs to delete from send_reliable */ + struct reliable_ack send_ack; + + send_ack.len = 0; + if (!reliable_ack_read(&send_ack, buf, &session->session_id)) + { + msg(D_TLS_ERRORS, + "TLS Error: reading acknowledgement record from packet"); + goto error; + } + reliable_send_purge(ks->send_reliable, &send_ack); + } + + if (op != P_ACK_V1 && reliable_can_get(ks->rec_reliable)) + { + packet_id_type id; + + /* Extract the packet ID from the packet */ + if (reliable_ack_read_packet_id(buf, &id)) + { + /* Avoid deadlock by rejecting packet that would de-sequentialize receive buffer */ + if (reliable_wont_break_sequentiality(ks->rec_reliable, id)) + { + if (reliable_not_replay(ks->rec_reliable, id)) + { + /* Save incoming ciphertext packet to reliable buffer */ + struct buffer *in = reliable_get_buf(ks->rec_reliable); + ASSERT(in); + ASSERT(buf_copy(in, buf)); + reliable_mark_active_incoming(ks->rec_reliable, in, id, op); + } + + /* Process outgoing acknowledgment for packet just received, even if it's a replay */ + reliable_ack_acknowledge_packet_id(ks->rec_ack, id); + } + } + } + } + } + } + +done: + buf->len = 0; + *opt = NULL; + gc_free(&gc); + return ret; + +error: + ++multi->n_soft_errors; +error_lite: + tls_clear_error(); + goto done; } /* @@ -3537,191 +3749,195 @@ tls_pre_decrypt (struct tls_multi *multi, * on the UDP port listener in --mode server mode. */ bool -tls_pre_decrypt_lite (const struct tls_auth_standalone *tas, - const struct link_socket_actual *from, - const struct buffer *buf) - -{ - struct gc_arena gc = gc_new (); - bool ret = false; - - if (buf->len > 0) - { - int op; - int key_id; - - /* get opcode and key ID */ - { - uint8_t c = *BPTR (buf); - op = c >> P_OPCODE_SHIFT; - key_id = c & P_KEY_ID_MASK; - } - - /* this packet is from an as-yet untrusted source, so - scrutinize carefully */ - - if (op != P_CONTROL_HARD_RESET_CLIENT_V2) - { - /* - * This can occur due to bogus data or DoS packets. - */ - dmsg (D_TLS_STATE_ERRORS, - "TLS State Error: No TLS state for client %s, opcode=%d", - print_link_socket_actual (from, &gc), - op); - goto error; - } - - if (key_id != 0) - { - dmsg (D_TLS_STATE_ERRORS, - "TLS State Error: Unknown key ID (%d) received from %s -- 0 was expected", - key_id, - print_link_socket_actual (from, &gc)); - goto error; - } - - if (buf->len > EXPANDED_SIZE_DYNAMIC (&tas->frame)) - { - dmsg (D_TLS_STATE_ERRORS, - "TLS State Error: Large packet (size %d) received from %s -- a packet no larger than %d bytes was expected", - buf->len, - print_link_socket_actual (from, &gc), - EXPANDED_SIZE_DYNAMIC (&tas->frame)); - goto error; - } - - { - struct buffer newbuf = clone_buf (buf); - struct tls_wrap_ctx tls_wrap_tmp = tas->tls_wrap; - bool status; - - /* HMAC test, if --tls-auth was specified */ - status = read_control_auth (&newbuf, &tls_wrap_tmp, from); - free_buf (&newbuf); - if (!status) - goto error; - - /* - * At this point, if --tls-auth is being used, we know that - * the packet has passed the HMAC test, but we don't know if - * it is a replay yet. We will attempt to defeat replays - * by not advancing to the S_START state until we - * receive an ACK from our first reply to the client - * that includes an HMAC of our randomly generated 64 bit - * session ID. - * - * On the other hand if --tls-auth is not being used, we - * will proceed to begin the TLS authentication - * handshake with only cursory integrity checks having - * been performed, since we will be leaving the task - * of authentication solely up to TLS. - */ - - ret = true; - } - } - gc_free (&gc); - return ret; - - error: - tls_clear_error(); - gc_free (&gc); - return ret; +tls_pre_decrypt_lite(const struct tls_auth_standalone *tas, + const struct link_socket_actual *from, + const struct buffer *buf) + +{ + struct gc_arena gc = gc_new(); + bool ret = false; + + if (buf->len > 0) + { + int op; + int key_id; + + /* get opcode and key ID */ + { + uint8_t c = *BPTR(buf); + op = c >> P_OPCODE_SHIFT; + key_id = c & P_KEY_ID_MASK; + } + + /* this packet is from an as-yet untrusted source, so + * scrutinize carefully */ + + if (op != P_CONTROL_HARD_RESET_CLIENT_V2) + { + /* + * This can occur due to bogus data or DoS packets. + */ + dmsg(D_TLS_STATE_ERRORS, + "TLS State Error: No TLS state for client %s, opcode=%d", + print_link_socket_actual(from, &gc), + op); + goto error; + } + + if (key_id != 0) + { + dmsg(D_TLS_STATE_ERRORS, + "TLS State Error: Unknown key ID (%d) received from %s -- 0 was expected", + key_id, + print_link_socket_actual(from, &gc)); + goto error; + } + + if (buf->len > EXPANDED_SIZE_DYNAMIC(&tas->frame)) + { + dmsg(D_TLS_STATE_ERRORS, + "TLS State Error: Large packet (size %d) received from %s -- a packet no larger than %d bytes was expected", + buf->len, + print_link_socket_actual(from, &gc), + EXPANDED_SIZE_DYNAMIC(&tas->frame)); + goto error; + } + + { + struct buffer newbuf = clone_buf(buf); + struct tls_wrap_ctx tls_wrap_tmp = tas->tls_wrap; + bool status; + + /* HMAC test, if --tls-auth was specified */ + status = read_control_auth(&newbuf, &tls_wrap_tmp, from); + free_buf(&newbuf); + if (!status) + { + goto error; + } + + /* + * At this point, if --tls-auth is being used, we know that + * the packet has passed the HMAC test, but we don't know if + * it is a replay yet. We will attempt to defeat replays + * by not advancing to the S_START state until we + * receive an ACK from our first reply to the client + * that includes an HMAC of our randomly generated 64 bit + * session ID. + * + * On the other hand if --tls-auth is not being used, we + * will proceed to begin the TLS authentication + * handshake with only cursory integrity checks having + * been performed, since we will be leaving the task + * of authentication solely up to TLS. + */ + + ret = true; + } + } + gc_free(&gc); + return ret; + +error: + tls_clear_error(); + gc_free(&gc); + return ret; } /* Choose the key with which to encrypt a data packet */ void -tls_pre_encrypt (struct tls_multi *multi, - struct buffer *buf, struct crypto_options **opt) -{ - multi->save_ks = NULL; - if (buf->len > 0) - { - int i; - struct key_state *ks_select = NULL; - for (i = 0; i < KEY_SCAN_SIZE; ++i) - { - struct key_state *ks = multi->key_scan[i]; - if (ks->state >= S_ACTIVE - && ks->authenticated - && ks->crypto_options.key_ctx_bi.initialized +tls_pre_encrypt(struct tls_multi *multi, + struct buffer *buf, struct crypto_options **opt) +{ + multi->save_ks = NULL; + if (buf->len > 0) + { + int i; + struct key_state *ks_select = NULL; + for (i = 0; i < KEY_SCAN_SIZE; ++i) + { + struct key_state *ks = multi->key_scan[i]; + if (ks->state >= S_ACTIVE + && ks->authenticated + && ks->crypto_options.key_ctx_bi.initialized #ifdef ENABLE_DEF_AUTH - && !ks->auth_deferred + && !ks->auth_deferred #endif - ) - { - if (!ks_select) - ks_select = ks; - if (now >= ks->auth_deferred_expire) - { - ks_select = ks; - break; - } - } - } - - if (ks_select) - { - *opt = &ks_select->crypto_options; - multi->save_ks = ks_select; - dmsg (D_TLS_KEYSELECT, "TLS: tls_pre_encrypt: key_id=%d", ks_select->key_id); - return; - } - else - { - struct gc_arena gc = gc_new (); - dmsg (D_TLS_KEYSELECT, "TLS Warning: no data channel send key available: %s", - print_key_id (multi, &gc)); - gc_free (&gc); - } - } - - buf->len = 0; - *opt = NULL; + ) + { + if (!ks_select) + { + ks_select = ks; + } + if (now >= ks->auth_deferred_expire) + { + ks_select = ks; + break; + } + } + } + + if (ks_select) + { + *opt = &ks_select->crypto_options; + multi->save_ks = ks_select; + dmsg(D_TLS_KEYSELECT, "TLS: tls_pre_encrypt: key_id=%d", ks_select->key_id); + return; + } + else + { + struct gc_arena gc = gc_new(); + dmsg(D_TLS_KEYSELECT, "TLS Warning: no data channel send key available: %s", + print_key_id(multi, &gc)); + gc_free(&gc); + } + } + + buf->len = 0; + *opt = NULL; } void -tls_prepend_opcode_v1 (const struct tls_multi *multi, struct buffer *buf) +tls_prepend_opcode_v1(const struct tls_multi *multi, struct buffer *buf) { - struct key_state *ks = multi->save_ks; - uint8_t op; + struct key_state *ks = multi->save_ks; + uint8_t op; - msg (D_TLS_DEBUG, __func__); + msg(D_TLS_DEBUG, __func__); - ASSERT (ks); + ASSERT(ks); - op = (P_DATA_V1 << P_OPCODE_SHIFT) | ks->key_id; - ASSERT (buf_write_prepend (buf, &op, 1)); + op = (P_DATA_V1 << P_OPCODE_SHIFT) | ks->key_id; + ASSERT(buf_write_prepend(buf, &op, 1)); } void -tls_prepend_opcode_v2 (const struct tls_multi *multi, struct buffer *buf) +tls_prepend_opcode_v2(const struct tls_multi *multi, struct buffer *buf) { - struct key_state *ks = multi->save_ks; - uint32_t peer; + struct key_state *ks = multi->save_ks; + uint32_t peer; - msg (D_TLS_DEBUG, __func__); + msg(D_TLS_DEBUG, __func__); - ASSERT (ks); + ASSERT(ks); - peer = htonl(((P_DATA_V2 << P_OPCODE_SHIFT) | ks->key_id) << 24 - | (multi->peer_id & 0xFFFFFF)); - ASSERT (buf_write_prepend (buf, &peer, 4)); + peer = htonl(((P_DATA_V2 << P_OPCODE_SHIFT) | ks->key_id) << 24 + | (multi->peer_id & 0xFFFFFF)); + ASSERT(buf_write_prepend(buf, &peer, 4)); } void -tls_post_encrypt (struct tls_multi *multi, struct buffer *buf) +tls_post_encrypt(struct tls_multi *multi, struct buffer *buf) { - struct key_state *ks = multi->save_ks; - multi->save_ks = NULL; + struct key_state *ks = multi->save_ks; + multi->save_ks = NULL; - if (buf->len > 0) + if (buf->len > 0) { - ASSERT (ks); + ASSERT(ks); - ++ks->n_packets; - ks->n_bytes += buf->len; + ++ks->n_packets; + ks->n_bytes += buf->len; } } @@ -3731,129 +3947,139 @@ tls_post_encrypt (struct tls_multi *multi, struct buffer *buf) */ bool -tls_send_payload (struct tls_multi *multi, - const uint8_t *data, - int size) +tls_send_payload(struct tls_multi *multi, + const uint8_t *data, + int size) { - struct tls_session *session; - struct key_state *ks; - bool ret = false; + struct tls_session *session; + struct key_state *ks; + bool ret = false; - tls_clear_error(); + tls_clear_error(); - ASSERT (multi); + ASSERT(multi); - session = &multi->session[TM_ACTIVE]; - ks = &session->key[KS_PRIMARY]; + session = &multi->session[TM_ACTIVE]; + ks = &session->key[KS_PRIMARY]; - if (ks->state >= S_ACTIVE) + if (ks->state >= S_ACTIVE) { - if (key_state_write_plaintext_const (&ks->ks_ssl, data, size) == 1) - ret = true; + if (key_state_write_plaintext_const(&ks->ks_ssl, data, size) == 1) + { + ret = true; + } } - else + else { - if (!ks->paybuf) - ks->paybuf = buffer_list_new (0); - buffer_list_push_data (ks->paybuf, data, (size_t)size); - ret = true; + if (!ks->paybuf) + { + ks->paybuf = buffer_list_new(0); + } + buffer_list_push_data(ks->paybuf, data, (size_t)size); + ret = true; } - tls_clear_error(); + tls_clear_error(); - return ret; + return ret; } bool -tls_rec_payload (struct tls_multi *multi, - struct buffer *buf) +tls_rec_payload(struct tls_multi *multi, + struct buffer *buf) { - struct tls_session *session; - struct key_state *ks; - bool ret = false; + struct tls_session *session; + struct key_state *ks; + bool ret = false; - tls_clear_error(); + tls_clear_error(); - ASSERT (multi); + ASSERT(multi); - session = &multi->session[TM_ACTIVE]; - ks = &session->key[KS_PRIMARY]; + session = &multi->session[TM_ACTIVE]; + ks = &session->key[KS_PRIMARY]; - if (ks->state >= S_ACTIVE && BLEN (&ks->plaintext_read_buf)) + if (ks->state >= S_ACTIVE && BLEN(&ks->plaintext_read_buf)) { - if (buf_copy (buf, &ks->plaintext_read_buf)) - ret = true; - ks->plaintext_read_buf.len = 0; + if (buf_copy(buf, &ks->plaintext_read_buf)) + { + ret = true; + } + ks->plaintext_read_buf.len = 0; } - tls_clear_error(); + tls_clear_error(); - return ret; + return ret; } void -tls_update_remote_addr (struct tls_multi *multi, const struct link_socket_actual *addr) +tls_update_remote_addr(struct tls_multi *multi, const struct link_socket_actual *addr) { - struct gc_arena gc = gc_new (); - int i, j; + struct gc_arena gc = gc_new(); + int i, j; - for (i = 0; i < TM_SIZE; ++i) + for (i = 0; i < TM_SIZE; ++i) { - struct tls_session *session = &multi->session[i]; + struct tls_session *session = &multi->session[i]; - for (j = 0; j < KS_SIZE; ++j) - { - struct key_state *ks = &session->key[j]; + for (j = 0; j < KS_SIZE; ++j) + { + struct key_state *ks = &session->key[j]; - if (!link_socket_actual_defined(&ks->remote_addr) || - link_socket_actual_match (addr, &ks->remote_addr)) - continue; + if (!link_socket_actual_defined(&ks->remote_addr) + || link_socket_actual_match(addr, &ks->remote_addr)) + { + continue; + } - dmsg (D_TLS_KEYSELECT, "TLS: tls_update_remote_addr from IP=%s to IP=%s", - print_link_socket_actual (&ks->remote_addr, &gc), - print_link_socket_actual (addr, &gc)); + dmsg(D_TLS_KEYSELECT, "TLS: tls_update_remote_addr from IP=%s to IP=%s", + print_link_socket_actual(&ks->remote_addr, &gc), + print_link_socket_actual(addr, &gc)); - ks->remote_addr = *addr; - } + ks->remote_addr = *addr; + } } - gc_free (&gc); + gc_free(&gc); } int tls_peer_info_ncp_ver(const char *peer_info) { - const char *ncpstr = peer_info ? strstr (peer_info, "IV_NCP=") : NULL; - if (ncpstr) + const char *ncpstr = peer_info ? strstr(peer_info, "IV_NCP=") : NULL; + if (ncpstr) { - int ncp = 0; - int r = sscanf(ncpstr, "IV_NCP=%d", &ncp); - if (r == 1) - return ncp; + int ncp = 0; + int r = sscanf(ncpstr, "IV_NCP=%d", &ncp); + if (r == 1) + { + return ncp; + } } - return 0; + return 0; } bool tls_check_ncp_cipher_list(const char *list) { - bool unsupported_cipher_found = false; + bool unsupported_cipher_found = false; - ASSERT (list); + ASSERT(list); - char * const tmp_ciphers = string_alloc (list, NULL); - const char *token = strtok (tmp_ciphers, ":"); - while (token) + char *const tmp_ciphers = string_alloc(list, NULL); + const char *token = strtok(tmp_ciphers, ":"); + while (token) { - if (!cipher_kt_get (translate_cipher_name_from_openvpn (token))) - { - msg (M_WARN, "Unsupported cipher in --ncp-ciphers: %s", token); - unsupported_cipher_found = true; - } - token = strtok (NULL, ":"); + if (!cipher_kt_get(translate_cipher_name_from_openvpn(token))) + { + msg(M_WARN, "Unsupported cipher in --ncp-ciphers: %s", token); + unsupported_cipher_found = true; + } + token = strtok(NULL, ":"); } - free (tmp_ciphers); + free(tmp_ciphers); - return 0 < strlen(list) && !unsupported_cipher_found; + return 0 < strlen(list) && !unsupported_cipher_found; } /* @@ -3861,99 +4087,125 @@ tls_check_ncp_cipher_list(const char *list) { * into a garbage collectable string which is returned. */ const char * -protocol_dump (struct buffer *buffer, unsigned int flags, struct gc_arena *gc) +protocol_dump(struct buffer *buffer, unsigned int flags, struct gc_arena *gc) { - struct buffer out = alloc_buf_gc (256, gc); - struct buffer buf = *buffer; + struct buffer out = alloc_buf_gc(256, gc); + struct buffer buf = *buffer; - uint8_t c; - int op; - int key_id; + uint8_t c; + int op; + int key_id; - int tls_auth_hmac_size = (flags & PD_TLS_AUTH_HMAC_SIZE_MASK); + int tls_auth_hmac_size = (flags & PD_TLS_AUTH_HMAC_SIZE_MASK); - if (buf.len <= 0) + if (buf.len <= 0) { - buf_printf (&out, "DATA UNDEF len=%d", buf.len); - goto done; + buf_printf(&out, "DATA UNDEF len=%d", buf.len); + goto done; } - if (!(flags & PD_TLS)) - goto print_data; + if (!(flags & PD_TLS)) + { + goto print_data; + } - /* - * Initial byte (opcode) - */ - if (!buf_read (&buf, &c, sizeof (c))) - goto done; - op = (c >> P_OPCODE_SHIFT); - key_id = c & P_KEY_ID_MASK; - buf_printf (&out, "%s kid=%d", packet_opcode_name (op), key_id); + /* + * Initial byte (opcode) + */ + if (!buf_read(&buf, &c, sizeof(c))) + { + goto done; + } + op = (c >> P_OPCODE_SHIFT); + key_id = c & P_KEY_ID_MASK; + buf_printf(&out, "%s kid=%d", packet_opcode_name(op), key_id); - if ((op == P_DATA_V1) || (op == P_DATA_V2)) - goto print_data; + if ((op == P_DATA_V1) || (op == P_DATA_V2)) + { + goto print_data; + } - /* - * Session ID - */ - { - struct session_id sid; + /* + * Session ID + */ + { + struct session_id sid; - if (!session_id_read (&sid, &buf)) - goto done; - if (flags & PD_VERBOSE) - buf_printf (&out, " sid=%s", session_id_print (&sid, gc)); - } + if (!session_id_read(&sid, &buf)) + { + goto done; + } + if (flags & PD_VERBOSE) + { + buf_printf(&out, " sid=%s", session_id_print(&sid, gc)); + } + } - /* - * tls-auth hmac + packet_id - */ - if (tls_auth_hmac_size) + /* + * tls-auth hmac + packet_id + */ + if (tls_auth_hmac_size) { - struct packet_id_net pin; - uint8_t tls_auth_hmac[MAX_HMAC_KEY_LENGTH]; + struct packet_id_net pin; + uint8_t tls_auth_hmac[MAX_HMAC_KEY_LENGTH]; - ASSERT (tls_auth_hmac_size <= MAX_HMAC_KEY_LENGTH); + ASSERT(tls_auth_hmac_size <= MAX_HMAC_KEY_LENGTH); - if (!buf_read (&buf, tls_auth_hmac, tls_auth_hmac_size)) - goto done; - if (flags & PD_VERBOSE) - buf_printf (&out, " tls_hmac=%s", format_hex (tls_auth_hmac, tls_auth_hmac_size, 0, gc)); + if (!buf_read(&buf, tls_auth_hmac, tls_auth_hmac_size)) + { + goto done; + } + if (flags & PD_VERBOSE) + { + buf_printf(&out, " tls_hmac=%s", format_hex(tls_auth_hmac, tls_auth_hmac_size, 0, gc)); + } - if (!packet_id_read (&pin, &buf, true)) - goto done; - buf_printf(&out, " pid=%s", packet_id_net_print (&pin, (flags & PD_VERBOSE), gc)); + if (!packet_id_read(&pin, &buf, true)) + { + goto done; + } + buf_printf(&out, " pid=%s", packet_id_net_print(&pin, (flags & PD_VERBOSE), gc)); } - /* - * ACK list - */ - buf_printf (&out, " %s", reliable_ack_print(&buf, (flags & PD_VERBOSE), gc)); + /* + * ACK list + */ + buf_printf(&out, " %s", reliable_ack_print(&buf, (flags & PD_VERBOSE), gc)); - if (op == P_ACK_V1) - goto done; + if (op == P_ACK_V1) + { + goto done; + } - /* - * Packet ID - */ - { - packet_id_type l; - if (!buf_read (&buf, &l, sizeof (l))) - goto done; - l = ntohpid (l); - buf_printf (&out, " pid=" packet_id_format, (packet_id_print_type)l); - } + /* + * Packet ID + */ + { + packet_id_type l; + if (!buf_read(&buf, &l, sizeof(l))) + { + goto done; + } + l = ntohpid(l); + buf_printf(&out, " pid=" packet_id_format, (packet_id_print_type)l); + } print_data: - if (flags & PD_SHOW_DATA) - buf_printf (&out, " DATA %s", format_hex (BPTR (&buf), BLEN (&buf), 80, gc)); - else - buf_printf (&out, " DATA len=%d", buf.len); + if (flags & PD_SHOW_DATA) + { + buf_printf(&out, " DATA %s", format_hex(BPTR(&buf), BLEN(&buf), 80, gc)); + } + else + { + buf_printf(&out, " DATA len=%d", buf.len); + } done: - return BSTR (&out); + return BSTR(&out); } -#else -static void dummy(void) {} +#else /* if defined(ENABLE_CRYPTO) */ +static void +dummy(void) { +} #endif /* ENABLE_CRYPTO */ diff --git a/src/openvpn/ssl.h b/src/openvpn/ssl.h index c971b758670..a78d4621262 100644 --- a/src/openvpn/ssl.h +++ b/src/openvpn/ssl.h @@ -87,7 +87,7 @@ */ #define TLS_MULTI_REFRESH 15 /* call tls_multi_process once every n seconds */ #define TLS_MULTI_HORIZON 2 /* call tls_multi_process frequently for n seconds after - every packet sent/received action */ + * every packet sent/received action */ /* * The SSL/TLS worker thread will wait at most this many seconds for the @@ -129,25 +129,25 @@ */ struct tls_auth_standalone { - struct tls_wrap_ctx tls_wrap; - struct frame frame; + struct tls_wrap_ctx tls_wrap; + struct frame frame; }; /* * Prepare the SSL library for use */ -void init_ssl_lib (void); +void init_ssl_lib(void); /* * Free any internal state that the SSL library might have */ -void free_ssl_lib (void); +void free_ssl_lib(void); /** * Build master SSL context object that serves for the whole of OpenVPN * instantiation */ -void init_ssl (const struct options *options, struct tls_root_ctx *ctx); +void init_ssl(const struct options *options, struct tls_root_ctx *ctx); /** @addtogroup control_processor * @{ */ @@ -169,7 +169,7 @@ void init_ssl (const struct options *options, struct tls_root_ctx *ctx); * * @return A newly allocated and initialized \c tls_multi structure. */ -struct tls_multi *tls_multi_init (struct tls_options *tls_options); +struct tls_multi *tls_multi_init(struct tls_options *tls_options); /** * Finalize initialization of a \c tls_multi structure. @@ -186,28 +186,28 @@ struct tls_multi *tls_multi_init (struct tls_options *tls_options); * @param frame - The data channel's \c frame structure. */ void tls_multi_init_finalize(struct tls_multi *multi, - const struct frame *frame); + const struct frame *frame); /* * Initialize a standalone tls-auth verification object. */ -struct tls_auth_standalone *tls_auth_standalone_init (struct tls_options *tls_options, - struct gc_arena *gc); +struct tls_auth_standalone *tls_auth_standalone_init(struct tls_options *tls_options, + struct gc_arena *gc); /* * Finalize a standalone tls-auth verification object. */ -void tls_auth_standalone_finalize (struct tls_auth_standalone *tas, - const struct frame *frame); +void tls_auth_standalone_finalize(struct tls_auth_standalone *tas, + const struct frame *frame); /* * Set local and remote option compatibility strings. * Used to verify compatibility of local and remote option * sets. */ -void tls_multi_init_set_options(struct tls_multi* multi, - const char *local, - const char *remote); +void tls_multi_init_set_options(struct tls_multi *multi, + const char *local, + const char *remote); /** * Cleanup a \c tls_multi structure and free associated memory @@ -221,7 +221,7 @@ void tls_multi_init_set_options(struct tls_multi* multi, * @param clear - Whether the memory allocated for the \a multi * object should be overwritten with 0s. */ -void tls_multi_free (struct tls_multi *multi, bool clear); +void tls_multi_free(struct tls_multi *multi, bool clear); /** @} name Functions for initialization and cleanup of tls_multi structures */ @@ -237,11 +237,11 @@ void tls_multi_free (struct tls_multi *multi, bool clear); * Basically decides if we should call tls_process for * the active or untrusted sessions. */ -int tls_multi_process (struct tls_multi *multi, - struct buffer *to_link, - struct link_socket_actual **to_link_addr, - struct link_socket_info *to_link_socket_info, - interval_t *wakeup); +int tls_multi_process(struct tls_multi *multi, + struct buffer *to_link, + struct link_socket_actual **to_link_addr, + struct link_socket_info *to_link_socket_info, + interval_t *wakeup); /**************************************************************************/ @@ -296,12 +296,12 @@ int tls_multi_process (struct tls_multi *multi, * @li False if the packet is a data channel packet, or if an error * occurred during processing of a control channel packet. */ -bool tls_pre_decrypt (struct tls_multi *multi, - const struct link_socket_actual *from, - struct buffer *buf, - struct crypto_options **opt, - bool floated, - const uint8_t **ad_start); +bool tls_pre_decrypt(struct tls_multi *multi, + const struct link_socket_actual *from, + struct buffer *buf, + struct crypto_options **opt, + bool floated, + const uint8_t **ad_start); /**************************************************************************/ @@ -339,9 +339,9 @@ bool tls_pre_decrypt (struct tls_multi *multi, * @li False if the packet is not valid, did not pass the HMAC firewall * test, or some other error occurred. */ -bool tls_pre_decrypt_lite (const struct tls_auth_standalone *tas, - const struct link_socket_actual *from, - const struct buffer *buf); +bool tls_pre_decrypt_lite(const struct tls_auth_standalone *tas, + const struct link_socket_actual *from, + const struct buffer *buf); /** @@ -357,8 +357,8 @@ bool tls_pre_decrypt_lite (const struct tls_auth_standalone *tas, * @param buf - The buffer containing the outgoing packet. * @param opt - Returns a crypto options structure with the security parameters. */ -void tls_pre_encrypt (struct tls_multi *multi, - struct buffer *buf, struct crypto_options **opt); +void tls_pre_encrypt(struct tls_multi *multi, + struct buffer *buf, struct crypto_options **opt); /** @@ -374,7 +374,7 @@ void tls_pre_encrypt (struct tls_multi *multi, * @ingroup data_crypto */ void -tls_prepend_opcode_v1 (const struct tls_multi *multi, struct buffer *buf); +tls_prepend_opcode_v1(const struct tls_multi *multi, struct buffer *buf); /** * Prepend an OpenVPN data channel P_DATA_V2 header to the packet. The @@ -393,7 +393,7 @@ tls_prepend_opcode_v1 (const struct tls_multi *multi, struct buffer *buf); * @ingroup data_crypto */ void -tls_prepend_opcode_v2 (const struct tls_multi *multi, struct buffer *buf); +tls_prepend_opcode_v2(const struct tls_multi *multi, struct buffer *buf); /** * Perform some accounting for the key state used. @@ -402,7 +402,7 @@ tls_prepend_opcode_v2 (const struct tls_multi *multi, struct buffer *buf); * @param multi - The TLS state for this packet's destination VPN tunnel. * @param buf - The buffer containing the outgoing packet. */ -void tls_post_encrypt (struct tls_multi *multi, struct buffer *buf); +void tls_post_encrypt(struct tls_multi *multi, struct buffer *buf); /** @} name Functions for managing security parameter state for data channel packets */ @@ -410,26 +410,26 @@ void tls_post_encrypt (struct tls_multi *multi, struct buffer *buf); * Setup private key file password. If auth_file is given, use the * credentials stored in the file. */ -void pem_password_setup (const char *auth_file); +void pem_password_setup(const char *auth_file); /* * Setup authentication username and password. If auth_file is given, use the * credentials stored in the file. */ -void auth_user_pass_setup (const char *auth_file, const struct static_challenge_info *sc_info); +void auth_user_pass_setup(const char *auth_file, const struct static_challenge_info *sc_info); /* * Ensure that no caching is performed on authentication information */ -void ssl_set_auth_nocache (void); +void ssl_set_auth_nocache(void); /* * Purge any stored authentication information, both for key files and tunnel * authentication. If PCKS #11 is enabled, purge authentication for that too. */ -void ssl_purge_auth (const bool auth_user_pass_only); +void ssl_purge_auth(const bool auth_user_pass_only); -void ssl_set_auth_token (const char *token); +void ssl_set_auth_token(const char *token); #ifdef ENABLE_CLIENT_CR /* @@ -437,8 +437,10 @@ void ssl_set_auth_token (const char *token); * reason string and return a dynamically allocated * auth_challenge_info struct. */ -void ssl_purge_auth_challenge (void); -void ssl_put_auth_challenge (const char *cr_str); +void ssl_purge_auth_challenge(void); + +void ssl_put_auth_challenge(const char *cr_str); + #endif /* @@ -449,15 +451,15 @@ void tls_adjust_frame_parameters(struct frame *frame); /* * Send a payload over the TLS control channel */ -bool tls_send_payload (struct tls_multi *multi, - const uint8_t *data, - int size); +bool tls_send_payload(struct tls_multi *multi, + const uint8_t *data, + int size); /* * Receive a payload through the TLS control channel */ -bool tls_rec_payload (struct tls_multi *multi, - struct buffer *buf); +bool tls_rec_payload(struct tls_multi *multi, + struct buffer *buf); /** * Updates remote address in TLS sessions. @@ -465,22 +467,22 @@ bool tls_rec_payload (struct tls_multi *multi, * @param multi - Tunnel to update * @param addr - new address */ -void tls_update_remote_addr (struct tls_multi *multi, - const struct link_socket_actual *addr); +void tls_update_remote_addr(struct tls_multi *multi, + const struct link_socket_actual *addr); /** * Update TLS session crypto parameters (cipher and auth) and derive data * channel keys based on the supplied options. * - * @param session The TLS session to update. - * @param options The options to use when updating session. - * @param frame The frame options for this session (frame overhead is - * adjusted based on the selected cipher/auth). + * @param session The TLS session to update. + * @param options The options to use when updating session. + * @param frame The frame options for this session (frame overhead is + * adjusted based on the selected cipher/auth). * * @return true if updating succeeded, false otherwise. */ bool tls_session_update_crypto_params(struct tls_session *session, - const struct options *options, struct frame *frame); + const struct options *options, struct frame *frame); /** * "Poor man's NCP": Use peer cipher if it is an allowed (NCP) cipher. @@ -495,7 +497,7 @@ void tls_poor_mans_ncp(struct options *o, const char *remote_ciphername); static inline char * tls_get_peer_info(const struct tls_multi *multi) { - return multi->peer_info; + return multi->peer_info; } #endif @@ -508,7 +510,7 @@ int tls_peer_info_ncp_ver(const char *peer_info); /** * Check whether the ciphers in the supplied list are supported. * - * @param list Colon-separated list of ciphers + * @param list Colon-separated list of ciphers * * @returns true iff all ciphers in list are supported. */ @@ -526,39 +528,43 @@ bool tls_item_in_cipher_list(const char *item, const char *list); */ static inline bool -tls_initial_packet_received (const struct tls_multi *multi) +tls_initial_packet_received(const struct tls_multi *multi) { - return multi->n_sessions > 0; + return multi->n_sessions > 0; } static inline bool -tls_test_auth_deferred_interval (const struct tls_multi *multi) +tls_test_auth_deferred_interval(const struct tls_multi *multi) { - if (multi) + if (multi) { - const struct key_state *ks = &multi->session[TM_ACTIVE].key[KS_PRIMARY]; - return now < ks->auth_deferred_expire; + const struct key_state *ks = &multi->session[TM_ACTIVE].key[KS_PRIMARY]; + return now < ks->auth_deferred_expire; } - return false; + return false; } static inline int -tls_test_payload_len (const struct tls_multi *multi) +tls_test_payload_len(const struct tls_multi *multi) { - if (multi) + if (multi) { - const struct key_state *ks = &multi->session[TM_ACTIVE].key[KS_PRIMARY]; - if (ks->state >= S_ACTIVE) - return BLEN (&ks->plaintext_read_buf); + const struct key_state *ks = &multi->session[TM_ACTIVE].key[KS_PRIMARY]; + if (ks->state >= S_ACTIVE) + { + return BLEN(&ks->plaintext_read_buf); + } } - return 0; + return 0; } static inline void -tls_set_single_session (struct tls_multi *multi) +tls_set_single_session(struct tls_multi *multi) { - if (multi) - multi->opt.single_session = true; + if (multi) + { + multi->opt.single_session = true; + } } /* @@ -569,9 +575,9 @@ tls_set_single_session (struct tls_multi *multi) #define PD_TLS (1<<9) #define PD_VERBOSE (1<<10) -const char *protocol_dump (struct buffer *buffer, - unsigned int flags, - struct gc_arena *gc); +const char *protocol_dump(struct buffer *buffer, + unsigned int flags, + struct gc_arena *gc); /* * debugging code @@ -579,11 +585,12 @@ const char *protocol_dump (struct buffer *buffer, #ifdef MEASURE_TLS_HANDSHAKE_STATS void show_tls_performance_stats(void); + #endif /*#define EXTRACT_X509_FIELD_TEST*/ -void extract_x509_field_test (void); +void extract_x509_field_test(void); #endif /* ENABLE_CRYPTO */ -#endif +#endif /* ifndef OPENVPN_SSL_H */ diff --git a/src/openvpn/ssl_backend.h b/src/openvpn/ssl_backend.h index 3fbd2b4fbef..b36451248e0 100644 --- a/src/openvpn/ssl_backend.h +++ b/src/openvpn/ssl_backend.h @@ -57,11 +57,11 @@ struct tls_session; /** * Get a tls_cipher_name_pair containing OpenSSL and IANA names for supplied TLS cipher name * - * @param cipher_name Can be either OpenSSL or IANA cipher name - * @return tls_cipher_name_pair* if found, NULL otherwise + * @param cipher_name Can be either OpenSSL or IANA cipher name + * @return tls_cipher_name_pair* if found, NULL otherwise */ typedef struct { const char *openssl_name; const char *iana_name; } tls_cipher_name_pair; -const tls_cipher_name_pair *tls_get_cipher_name_pair (const char *cipher_name, size_t len); +const tls_cipher_name_pair *tls_get_cipher_name_pair(const char *cipher_name, size_t len); /* * @@ -72,12 +72,12 @@ const tls_cipher_name_pair *tls_get_cipher_name_pair (const char *cipher_name, s /** * Callback to retrieve the user's password * - * @param buf Buffer to return the password in - * @param size Size of the buffer - * @param rwflag Unused, needed for OpenSSL compatibility - * @param u Unused, needed for OpenSSL compatibility + * @param buf Buffer to return the password in + * @param size Size of the buffer + * @param rwflag Unused, needed for OpenSSL compatibility + * @param u Unused, needed for OpenSSL compatibility */ -int pem_password_callback (char *buf, int size, int rwflag, void *u); +int pem_password_callback(char *buf, int size, int rwflag, void *u); /* * @@ -95,6 +95,7 @@ void tls_init_lib(); * Free any global SSL library-specific data structures. */ void tls_free_lib(); + /** * Clear the underlying SSL library's error state. */ @@ -103,10 +104,10 @@ void tls_clear_error(); /** * Parse a TLS version specifier * - * @param vstr The TLS version string - * @param extra An optional extra parameter, may be NULL + * @param vstr The TLS version string + * @param extra An optional extra parameter, may be NULL * - * @return One of the TLS_VER_x constants or TLS_VER_BAD + * @return One of the TLS_VER_x constants or TLS_VER_BAD * if a parse error should be flagged. */ #define TLS_VER_BAD -1 @@ -120,7 +121,7 @@ int tls_version_parse(const char *vstr, const char *extra); * Return the maximum TLS version (as a TLS_VER_x constant) * supported by current SSL implementation * - * @return One of the TLS_VER_x constants (but not TLS_VER_BAD). + * @return One of the TLS_VER_x constants (but not TLS_VER_BAD). */ int tls_version_max(void); @@ -129,30 +130,30 @@ int tls_version_max(void); /** * Initialise a library-specific TLS context for a server. * - * @param ctx TLS context to initialise + * @param ctx TLS context to initialise */ void tls_ctx_server_new(struct tls_root_ctx *ctx); /** * Initialises a library-specific TLS context for a client. * - * @param ctx TLS context to initialise + * @param ctx TLS context to initialise */ void tls_ctx_client_new(struct tls_root_ctx *ctx); /** * Frees the library-specific TLSv1 context * - * @param ctx TLS context to free + * @param ctx TLS context to free */ void tls_ctx_free(struct tls_root_ctx *ctx); /** * Checks whether the given TLS context is initialised * - * @param ctx TLS context to check + * @param ctx TLS context to check * - * @return true if the context is initialised, false if not. + * @return true if the context is initialised, false if not. */ bool tls_ctx_initialised(struct tls_root_ctx *ctx); @@ -162,17 +163,17 @@ bool tls_ctx_initialised(struct tls_root_ctx *ctx); * Examples include disabling session caching, the password callback to use, * and session verification parameters. * - * @param ctx TLS context to set options on - * @param ssl_flags SSL flags to set + * @param ctx TLS context to set options on + * @param ssl_flags SSL flags to set */ -void tls_ctx_set_options (struct tls_root_ctx *ctx, unsigned int ssl_flags); +void tls_ctx_set_options(struct tls_root_ctx *ctx, unsigned int ssl_flags); /** * Restrict the list of ciphers that can be used within the TLS context. * - * @param ctx TLS context to restrict, must be valid. - * @param ciphers String containing : delimited cipher names, or NULL to use - * sane defaults. + * @param ctx TLS context to restrict, must be valid. + * @param ciphers String containing : delimited cipher names, or NULL to use + * sane defaults. */ void tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers); @@ -181,21 +182,21 @@ void tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers); * either not yet valid or has expired. Note that this is a non-fatal error, * since we compare against the system time, which might be incorrect. * - * @param ctx TLS context to get our certificate from. + * @param ctx TLS context to get our certificate from. */ -void tls_ctx_check_cert_time (const struct tls_root_ctx *ctx); +void tls_ctx_check_cert_time(const struct tls_root_ctx *ctx); /** * Load Diffie Hellman Parameters, and load them into the library-specific * TLS context. * - * @param ctx TLS context to use - * @param dh_file The file name to load the parameters from, or - * "[[INLINE]]" in the case of inline files. - * @param dh_file_inline A string containing the parameters + * @param ctx TLS context to use + * @param dh_file The file name to load the parameters from, or + * "[[INLINE]]" in the case of inline files. + * @param dh_file_inline A string containing the parameters */ void tls_ctx_load_dh_params(struct tls_root_ctx *ctx, const char *dh_file, - const char *dh_file_inline); + const char *dh_file_inline); /** * Load Elliptic Curve Parameters, and load them into the library-specific @@ -205,61 +206,62 @@ void tls_ctx_load_dh_params(struct tls_root_ctx *ctx, const char *dh_file, * @param curve_name The name of the elliptic curve to load. */ void tls_ctx_load_ecdh_params(struct tls_root_ctx *ctx, const char *curve_name - ); + ); /** * Load PKCS #12 file for key, cert and (optionally) CA certs, and add to * library-specific TLS context. * - * @param ctx TLS context to use - * @param pkcs12_file The file name to load the information from, or - * "[[INLINE]]" in the case of inline files. - * @param pkcs12_file_inline A string containing the information + * @param ctx TLS context to use + * @param pkcs12_file The file name to load the information from, or + * "[[INLINE]]" in the case of inline files. + * @param pkcs12_file_inline A string containing the information * - * @return 1 if an error occurred, 0 if parsing was - * successful. + * @return 1 if an error occurred, 0 if parsing was + * successful. */ int tls_ctx_load_pkcs12(struct tls_root_ctx *ctx, const char *pkcs12_file, - const char *pkcs12_file_inline, bool load_ca_file - ); + const char *pkcs12_file_inline, bool load_ca_file + ); /** * Use Windows cryptoapi for key and cert, and add to library-specific TLS * context. * - * @param ctx TLS context to use - * @param crypto_api_cert String representing the certificate to load. + * @param ctx TLS context to use + * @param crypto_api_cert String representing the certificate to load. */ #ifdef ENABLE_CRYPTOAPI void tls_ctx_load_cryptoapi(struct tls_root_ctx *ctx, const char *cryptoapi_cert); + #endif /* _WIN32 */ /** * Load certificate file into the given TLS context. If the given certificate * file contains a certificate chain, load the whole chain. * - * @param ctx TLS context to use - * @param cert_file The file name to load the certificate from, or - * "[[INLINE]]" in the case of inline files. - * @param cert_file_inline A string containing the certificate + * @param ctx TLS context to use + * @param cert_file The file name to load the certificate from, or + * "[[INLINE]]" in the case of inline files. + * @param cert_file_inline A string containing the certificate */ -void tls_ctx_load_cert_file (struct tls_root_ctx *ctx, const char *cert_file, - const char *cert_file_inline); +void tls_ctx_load_cert_file(struct tls_root_ctx *ctx, const char *cert_file, + const char *cert_file_inline); /** * Load private key file into the given TLS context. * - * @param ctx TLS context to use - * @param priv_key_file The file name to load the private key from, or - * "[[INLINE]]" in the case of inline files. - * @param priv_key_file_inline A string containing the private key + * @param ctx TLS context to use + * @param priv_key_file The file name to load the private key from, or + * "[[INLINE]]" in the case of inline files. + * @param priv_key_file_inline A string containing the private key * - * @return 1 if an error occurred, 0 if parsing was - * successful. + * @return 1 if an error occurred, 0 if parsing was + * successful. */ -int tls_ctx_load_priv_file (struct tls_root_ctx *ctx, const char *priv_key_file, - const char *priv_key_file_inline - ); +int tls_ctx_load_priv_file(struct tls_root_ctx *ctx, const char *priv_key_file, + const char *priv_key_file_inline + ); #ifdef MANAGMENT_EXTERNAL_KEY @@ -267,16 +269,17 @@ int tls_ctx_load_priv_file (struct tls_root_ctx *ctx, const char *priv_key_file, * Tell the management interface to load the given certificate and the external * private key matching the given certificate. * - * @param ctx TLS context to use - * @param cert_file The file name to load the certificate from, or - * "[[INLINE]]" in the case of inline files. - * @param cert_file_inline A string containing the certificate + * @param ctx TLS context to use + * @param cert_file The file name to load the certificate from, or + * "[[INLINE]]" in the case of inline files. + * @param cert_file_inline A string containing the certificate * - * @return 1 if an error occurred, 0 if parsing was - * successful. + * @return 1 if an error occurred, 0 if parsing was + * successful. */ -int tls_ctx_use_external_private_key (struct tls_root_ctx *ctx, - const char *cert_file, const char *cert_file_inline); +int tls_ctx_use_external_private_key(struct tls_root_ctx *ctx, + const char *cert_file, const char *cert_file_inline); + #endif @@ -285,15 +288,15 @@ int tls_ctx_use_external_private_key (struct tls_root_ctx *ctx, * * Note that not all SSL libraries support loading from a path. * - * @param ctx TLS context to use - * @param ca_file The file name to load the CAs from, or - * "[[INLINE]]" in the case of inline files. - * @param ca_file_inline A string containing the CAs - * @param ca_path The path to load the CAs from + * @param ctx TLS context to use + * @param ca_file The file name to load the CAs from, or + * "[[INLINE]]" in the case of inline files. + * @param ca_file_inline A string containing the CAs + * @param ca_path The path to load the CAs from */ -void tls_ctx_load_ca (struct tls_root_ctx *ctx, const char *ca_file, - const char *ca_file_inline, const char *ca_path, bool tls_server - ); +void tls_ctx_load_ca(struct tls_root_ctx *ctx, const char *ca_file, + const char *ca_file_inline, const char *ca_path, bool tls_server + ); /** * Load extra certificate authority certificates from the given file or path. @@ -301,23 +304,24 @@ void tls_ctx_load_ca (struct tls_root_ctx *ctx, const char *ca_file, * chain but shouldn't be included in the verify chain. * * - * @param ctx TLS context to use - * @param extra_certs_file The file name to load the certs from, or - * "[[INLINE]]" in the case of inline files. - * @param extra_certs_file_inline A string containing the certs + * @param ctx TLS context to use + * @param extra_certs_file The file name to load the certs from, or + * "[[INLINE]]" in the case of inline files. + * @param extra_certs_file_inline A string containing the certs */ -void tls_ctx_load_extra_certs (struct tls_root_ctx *ctx, const char *extra_certs_file, - const char *extra_certs_file_inline - ); +void tls_ctx_load_extra_certs(struct tls_root_ctx *ctx, const char *extra_certs_file, + const char *extra_certs_file_inline + ); #ifdef ENABLE_CRYPTO_MBEDTLS /** * Add a personalisation string to the mbed TLS RNG, based on the certificate * loaded into the given context. * - * @param ctx TLS context to use + * @param ctx TLS context to use */ void tls_ctx_personalise_random(struct tls_root_ctx *ctx); + #endif /* ************************************** @@ -330,18 +334,18 @@ void tls_ctx_personalise_random(struct tls_root_ctx *ctx); * Initialise the SSL channel part of the given key state. Settings will be * loaded from a previously initialised TLS context. * - * @param ks_ssl The SSL channel's state info to initialise - * @param ssl_ctx The TLS context to use when initialising the channel. - * @param is_server Initialise a server? - * @param session The session associated with the given key_state + * @param ks_ssl The SSL channel's state info to initialise + * @param ssl_ctx The TLS context to use when initialising the channel. + * @param is_server Initialise a server? + * @param session The session associated with the given key_state */ void key_state_ssl_init(struct key_state_ssl *ks_ssl, - const struct tls_root_ctx *ssl_ctx, bool is_server, struct tls_session *session); + const struct tls_root_ctx *ssl_ctx, bool is_server, struct tls_session *session); /** * Free the SSL channel part of the given key state. * - * @param ks_ssl The SSL channel's state info to free + * @param ks_ssl The SSL channel's state info to free */ void key_state_ssl_free(struct key_state_ssl *ks_ssl); @@ -354,7 +358,7 @@ void key_state_ssl_free(struct key_state_ssl *ks_ssl); * @param crl_inline A string containing the CRL */ void backend_tls_ctx_reload_crl(struct tls_root_ctx *ssl_ctx, - const char *crl_file, const char *crl_inline); + const char *crl_file, const char *crl_inline); /** * Keying Material Exporters [RFC 5705] allows additional keying material to be @@ -367,7 +371,7 @@ void backend_tls_ctx_reload_crl(struct tls_root_ctx *ssl_ctx, void key_state_export_keying_material(struct key_state_ssl *ks_ssl, - struct tls_session *session) __attribute__((nonnull)); + struct tls_session *session) __attribute__((nonnull)); /**************************************************************************/ /** @addtogroup control_tls @@ -393,7 +397,7 @@ key_state_export_keying_material(struct key_state_ssl *ks_ssl, * again later to retry. * - \c -1: An error occurred. */ -int key_state_write_plaintext (struct key_state_ssl *ks_ssl, struct buffer *buf); +int key_state_write_plaintext(struct key_state_ssl *ks_ssl, struct buffer *buf); /** * Insert plaintext data into the TLS module. @@ -410,8 +414,8 @@ int key_state_write_plaintext (struct key_state_ssl *ks_ssl, struct buffer *buf) * again later to retry. * - \c -1: An error occurred. */ -int key_state_write_plaintext_const (struct key_state_ssl *ks_ssl, - const uint8_t *data, int len); +int key_state_write_plaintext_const(struct key_state_ssl *ks_ssl, + const uint8_t *data, int len); /** * Extract ciphertext data from the TLS module. @@ -431,8 +435,8 @@ int key_state_write_plaintext_const (struct key_state_ssl *ks_ssl, * later to retry. * - \c -1: An error occurred. */ -int key_state_read_ciphertext (struct key_state_ssl *ks_ssl, struct buffer *buf, - int maxlen); +int key_state_read_ciphertext(struct key_state_ssl *ks_ssl, struct buffer *buf, + int maxlen); /** @} name Functions for packets to be sent to a remote OpenVPN peer */ @@ -457,8 +461,8 @@ int key_state_read_ciphertext (struct key_state_ssl *ks_ssl, struct buffer *buf, * again later to retry. * - \c -1: An error occurred. */ -int key_state_write_ciphertext (struct key_state_ssl *ks_ssl, - struct buffer *buf); +int key_state_write_ciphertext(struct key_state_ssl *ks_ssl, + struct buffer *buf); /** * Extract plaintext data from the TLS module. @@ -478,8 +482,8 @@ int key_state_write_ciphertext (struct key_state_ssl *ks_ssl, * later to retry. * - \c -1: An error occurred. */ -int key_state_read_plaintext (struct key_state_ssl *ks_ssl, struct buffer *buf, - int maxlen); +int key_state_read_plaintext(struct key_state_ssl *ks_ssl, struct buffer *buf, + int maxlen); /** @} name Functions for packets received from a remote OpenVPN peer */ @@ -496,32 +500,32 @@ int key_state_read_plaintext (struct key_state_ssl *ks_ssl, struct buffer *buf, /* * Print a one line summary of SSL/TLS session handshake. */ -void print_details (struct key_state_ssl * ks_ssl, const char *prefix); +void print_details(struct key_state_ssl *ks_ssl, const char *prefix); /* * Show the TLS ciphers that are available for us to use in the OpenSSL * library. * - * @param - list of allowed TLS cipher, or NULL. + * @param - list of allowed TLS cipher, or NULL. */ -void show_available_tls_ciphers (const char *tls_ciphers); +void show_available_tls_ciphers(const char *tls_ciphers); /* * Show the available elliptic curves in the crypto library */ -void show_available_curves (void); +void show_available_curves(void); /* * The OpenSSL library has a notion of preference in TLS ciphers. Higher * preference == more secure. Return the highest preference cipher. */ -void get_highest_preference_tls_cipher (char *buf, int size); +void get_highest_preference_tls_cipher(char *buf, int size); /** * return a pointer to a static memory area containing the * name and version number of the SSL library in use */ -const char * get_ssl_library_version(void); +const char *get_ssl_library_version(void); #endif /* ENABLE_CRYPTO */ #endif /* SSL_BACKEND_H_ */ diff --git a/src/openvpn/ssl_common.h b/src/openvpn/ssl_common.h index 8164bbcd4eb..018da27e37a 100644 --- a/src/openvpn/ssl_common.h +++ b/src/openvpn/ssl_common.h @@ -107,13 +107,13 @@ * @ingroup control_processor */ struct key_source { - uint8_t pre_master[48]; /**< Random used for master secret + uint8_t pre_master[48]; /**< Random used for master secret * generation, provided only by client * OpenVPN peer. */ - uint8_t random1[32]; /**< Seed used for master secret + uint8_t random1[32]; /**< Seed used for master secret * generation, provided by both client * and server. */ - uint8_t random2[32]; /**< Seed used for key expansion, provided + uint8_t random2[32]; /**< Seed used for key expansion, provided * by both client and server. */ }; @@ -124,8 +124,8 @@ struct key_source { * @ingroup control_processor */ struct key_source2 { - struct key_source client; /**< Random provided by client. */ - struct key_source server; /**< Random provided by server. */ + struct key_source client; /**< Random provided by client. */ + struct key_source server; /**< Random provided by server. */ }; /** @@ -148,58 +148,58 @@ struct key_source2 { */ struct key_state { - int state; + int state; - /** - * Key id for this key_state, inherited from struct tls_session. - * @see tls_session::key_id. - */ - int key_id; + /** + * Key id for this key_state, inherited from struct tls_session. + * @see tls_session::key_id. + */ + int key_id; - struct key_state_ssl ks_ssl; /* contains SSL object and BIOs for the control channel */ + struct key_state_ssl ks_ssl; /* contains SSL object and BIOs for the control channel */ - time_t established; /* when our state went S_ACTIVE */ - time_t must_negotiate; /* key negotiation times out if not finished before this time */ - time_t must_die; /* this object is destroyed at this time */ + time_t established; /* when our state went S_ACTIVE */ + time_t must_negotiate; /* key negotiation times out if not finished before this time */ + time_t must_die; /* this object is destroyed at this time */ - int initial_opcode; /* our initial P_ opcode */ - struct session_id session_id_remote; /* peer's random session ID */ - struct link_socket_actual remote_addr; /* peer's IP addr */ + int initial_opcode; /* our initial P_ opcode */ + struct session_id session_id_remote; /* peer's random session ID */ + struct link_socket_actual remote_addr; /* peer's IP addr */ - struct crypto_options crypto_options;/* data channel crypto options */ + struct crypto_options crypto_options;/* data channel crypto options */ - struct key_source2 *key_src; /* source entropy for key expansion */ + struct key_source2 *key_src; /* source entropy for key expansion */ - struct buffer plaintext_read_buf; - struct buffer plaintext_write_buf; - struct buffer ack_write_buf; + struct buffer plaintext_read_buf; + struct buffer plaintext_write_buf; + struct buffer ack_write_buf; - struct reliable *send_reliable; /* holds a copy of outgoing packets until ACK received */ - struct reliable *rec_reliable; /* order incoming ciphertext packets before we pass to TLS */ - struct reliable_ack *rec_ack; /* buffers all packet IDs we want to ACK back to sender */ + struct reliable *send_reliable; /* holds a copy of outgoing packets until ACK received */ + struct reliable *rec_reliable; /* order incoming ciphertext packets before we pass to TLS */ + struct reliable_ack *rec_ack; /* buffers all packet IDs we want to ACK back to sender */ - struct buffer_list *paybuf; + struct buffer_list *paybuf; - counter_type n_bytes; /* how many bytes sent/recvd since last key exchange */ - counter_type n_packets; /* how many packets sent/recvd since last key exchange */ + counter_type n_bytes; /* how many bytes sent/recvd since last key exchange */ + counter_type n_packets; /* how many packets sent/recvd since last key exchange */ - /* - * If bad username/password, TLS connection will come up but 'authenticated' will be false. - */ - bool authenticated; - time_t auth_deferred_expire; + /* + * If bad username/password, TLS connection will come up but 'authenticated' will be false. + */ + bool authenticated; + time_t auth_deferred_expire; #ifdef ENABLE_DEF_AUTH - /* If auth_deferred is true, authentication is being deferred */ - bool auth_deferred; + /* If auth_deferred is true, authentication is being deferred */ + bool auth_deferred; #ifdef MANAGEMENT_DEF_AUTH - unsigned int mda_key_id; - unsigned int mda_status; + unsigned int mda_key_id; + unsigned int mda_status; #endif #ifdef PLUGIN_DEF_AUTH - unsigned int auth_control_status; - time_t acf_last_mod; - char *auth_control_file; + unsigned int auth_control_status; + time_t acf_last_mod; + char *auth_control_file; #endif #endif }; @@ -207,13 +207,13 @@ struct key_state /** Control channel wrapping (--tls-auth/--tls-crypt) context */ struct tls_wrap_ctx { - enum { - TLS_WRAP_NONE = 0, /**< No control channel wrapping */ - TLS_WRAP_AUTH, /**< Control channel authentication */ - TLS_WRAP_CRYPT, /**< Control channel encryption and authentication */ - } mode; /**< Control channel wrapping mode */ - struct crypto_options opt; /**< Crypto state */ - struct buffer work; /**< Work buffer (only for --tls-crypt) */ + enum { + TLS_WRAP_NONE = 0, /**< No control channel wrapping */ + TLS_WRAP_AUTH, /**< Control channel authentication */ + TLS_WRAP_CRYPT, /**< Control channel encryption and authentication */ + } mode; /**< Control channel wrapping mode */ + struct crypto_options opt; /**< Crypto state */ + struct buffer work; /**< Work buffer (only for --tls-crypt) */ }; /* @@ -222,129 +222,129 @@ struct tls_wrap_ctx */ struct tls_options { - /* our master TLS context from which all SSL objects derived */ - struct tls_root_ctx ssl_ctx; + /* our master TLS context from which all SSL objects derived */ + struct tls_root_ctx ssl_ctx; - /* data channel cipher, hmac, and key lengths */ - struct key_type key_type; + /* data channel cipher, hmac, and key lengths */ + struct key_type key_type; - /* true if we are a TLS server, client otherwise */ - bool server; + /* true if we are a TLS server, client otherwise */ + bool server; - /* if true, don't xmit until first packet from peer is received */ - bool xmit_hold; + /* if true, don't xmit until first packet from peer is received */ + bool xmit_hold; #ifdef ENABLE_OCC - /* local and remote options strings - that must match between client and server */ - const char *local_options; - const char *remote_options; + /* local and remote options strings + * that must match between client and server */ + const char *local_options; + const char *remote_options; #endif - /* from command line */ - int key_method; - bool replay; - bool single_session; + /* from command line */ + int key_method; + bool replay; + bool single_session; #ifdef ENABLE_OCC - bool disable_occ; + bool disable_occ; #endif - int mode; - bool pull; + int mode; + bool pull; #ifdef ENABLE_PUSH_PEER_INFO - int push_peer_info_detail; + int push_peer_info_detail; #endif - int transition_window; - int handshake_window; - interval_t packet_timeout; - int renegotiate_bytes; - int renegotiate_packets; - interval_t renegotiate_seconds; - - /* cert verification parms */ - const char *verify_command; - const char *verify_export_cert; - int verify_x509_type; - const char *verify_x509_name; - const char *crl_file; - const char *crl_file_inline; - int ns_cert_type; - unsigned remote_cert_ku[MAX_PARMS]; - const char *remote_cert_eku; - uint8_t *verify_hash; - char *x509_username_field; - - /* allow openvpn config info to be - passed over control channel */ - bool pass_config_info; - - /* struct crypto_option flags */ - unsigned int crypto_flags; - - int replay_window; /* --replay-window parm */ - int replay_time; /* --replay-window parm */ - bool tcp_mode; - - const char *config_ciphername; - const char *config_authname; - bool ncp_enabled; - - /** TLS handshake wrapping state */ - struct tls_wrap_ctx tls_wrap; - - /* frame parameters for TLS control channel */ - struct frame frame; - - /* used for username/password authentication */ - const char *auth_user_pass_verify_script; - bool auth_user_pass_verify_script_via_file; - const char *tmp_dir; - const char *auth_user_pass_file; - bool auth_token_generate; /**< Generate auth-tokens on successful user/pass auth, + int transition_window; + int handshake_window; + interval_t packet_timeout; + int renegotiate_bytes; + int renegotiate_packets; + interval_t renegotiate_seconds; + + /* cert verification parms */ + const char *verify_command; + const char *verify_export_cert; + int verify_x509_type; + const char *verify_x509_name; + const char *crl_file; + const char *crl_file_inline; + int ns_cert_type; + unsigned remote_cert_ku[MAX_PARMS]; + const char *remote_cert_eku; + uint8_t *verify_hash; + char *x509_username_field; + + /* allow openvpn config info to be + * passed over control channel */ + bool pass_config_info; + + /* struct crypto_option flags */ + unsigned int crypto_flags; + + int replay_window; /* --replay-window parm */ + int replay_time; /* --replay-window parm */ + bool tcp_mode; + + const char *config_ciphername; + const char *config_authname; + bool ncp_enabled; + + /** TLS handshake wrapping state */ + struct tls_wrap_ctx tls_wrap; + + /* frame parameters for TLS control channel */ + struct frame frame; + + /* used for username/password authentication */ + const char *auth_user_pass_verify_script; + bool auth_user_pass_verify_script_via_file; + const char *tmp_dir; + const char *auth_user_pass_file; + bool auth_token_generate; /**< Generate auth-tokens on successful user/pass auth, * set via options->auth_token_generate. */ - unsigned int auth_token_lifetime; + unsigned int auth_token_lifetime; - /* use the client-config-dir as a positive authenticator */ - const char *client_config_dir_exclusive; + /* use the client-config-dir as a positive authenticator */ + const char *client_config_dir_exclusive; - /* instance-wide environment variable set */ - struct env_set *es; - const struct plugin_list *plugins; + /* instance-wide environment variable set */ + struct env_set *es; + const struct plugin_list *plugins; - /* compression parms */ + /* compression parms */ #ifdef USE_COMP - struct compress_options comp_options; + struct compress_options comp_options; #endif - /* configuration file SSL-related boolean and low-permutation options */ -# define SSLF_CLIENT_CERT_NOT_REQUIRED (1<<0) -# define SSLF_CLIENT_CERT_OPTIONAL (1<<1) -# define SSLF_USERNAME_AS_COMMON_NAME (1<<2) -# define SSLF_AUTH_USER_PASS_OPTIONAL (1<<3) -# define SSLF_OPT_VERIFY (1<<4) -# define SSLF_CRL_VERIFY_DIR (1<<5) -# define SSLF_TLS_VERSION_MIN_SHIFT 6 -# define SSLF_TLS_VERSION_MIN_MASK 0xF /* (uses bit positions 6 to 9) */ -# define SSLF_TLS_VERSION_MAX_SHIFT 10 -# define SSLF_TLS_VERSION_MAX_MASK 0xF /* (uses bit positions 10 to 13) */ - unsigned int ssl_flags; + /* configuration file SSL-related boolean and low-permutation options */ +#define SSLF_CLIENT_CERT_NOT_REQUIRED (1<<0) +#define SSLF_CLIENT_CERT_OPTIONAL (1<<1) +#define SSLF_USERNAME_AS_COMMON_NAME (1<<2) +#define SSLF_AUTH_USER_PASS_OPTIONAL (1<<3) +#define SSLF_OPT_VERIFY (1<<4) +#define SSLF_CRL_VERIFY_DIR (1<<5) +#define SSLF_TLS_VERSION_MIN_SHIFT 6 +#define SSLF_TLS_VERSION_MIN_MASK 0xF /* (uses bit positions 6 to 9) */ +#define SSLF_TLS_VERSION_MAX_SHIFT 10 +#define SSLF_TLS_VERSION_MAX_MASK 0xF /* (uses bit positions 10 to 13) */ + unsigned int ssl_flags; #ifdef MANAGEMENT_DEF_AUTH - struct man_def_auth_context *mda_context; + struct man_def_auth_context *mda_context; #endif - const struct x509_track *x509_track; + const struct x509_track *x509_track; #ifdef ENABLE_CLIENT_CR - const struct static_challenge_info *sci; + const struct static_challenge_info *sci; #endif - /* --gremlin bits */ - int gremlin; + /* --gremlin bits */ + int gremlin; - /* Keying Material Exporter [RFC 5705] parameters */ - const char *ekm_label; - size_t ekm_label_size; - size_t ekm_size; + /* Keying Material Exporter [RFC 5705] parameters */ + const char *ekm_label; + size_t ekm_label_size; + size_t ekm_size; }; /** @addtogroup control_processor @@ -383,43 +383,43 @@ struct tls_options */ struct tls_session { - /* const options and config info */ - struct tls_options *opt; + /* const options and config info */ + struct tls_options *opt; - /* during hard reset used to control burst retransmit */ - bool burst; + /* during hard reset used to control burst retransmit */ + bool burst; - /* authenticate control packets */ - struct tls_wrap_ctx tls_wrap; + /* authenticate control packets */ + struct tls_wrap_ctx tls_wrap; - int initial_opcode; /* our initial P_ opcode */ - struct session_id session_id; /* our random session ID */ + int initial_opcode; /* our initial P_ opcode */ + struct session_id session_id; /* our random session ID */ - /** - * The current active key id, used to keep track of renegotiations. - * key_id increments with each soft reset to KEY_ID_MASK then recycles back - * to 1. This way you know that if key_id is 0, it is the first key. - */ - int key_id; + /** + * The current active key id, used to keep track of renegotiations. + * key_id increments with each soft reset to KEY_ID_MASK then recycles back + * to 1. This way you know that if key_id is 0, it is the first key. + */ + int key_id; - int limit_next; /* used for traffic shaping on the control channel */ + int limit_next; /* used for traffic shaping on the control channel */ - int verify_maxlevel; + int verify_maxlevel; - char *common_name; + char *common_name; - struct cert_hash_set *cert_hash_set; + struct cert_hash_set *cert_hash_set; #ifdef ENABLE_PF - uint32_t common_name_hashval; + uint32_t common_name_hashval; #endif - bool verified; /* true if peer certificate was verified against CA */ + bool verified; /* true if peer certificate was verified against CA */ - /* not-yet-authenticated incoming client */ - struct link_socket_actual untrusted_addr; + /* not-yet-authenticated incoming client */ + struct link_socket_actual untrusted_addr; - struct key_state key[KS_SIZE]; + struct key_state key[KS_SIZE]; }; /** @addtogroup control_processor @@ -477,89 +477,89 @@ struct tls_session */ struct tls_multi { - /* used to coordinate access between main thread and TLS thread */ - /*MUTEX_PTR_DEFINE (mutex);*/ - - /* const options and config info */ - struct tls_options opt; - - struct key_state* key_scan[KEY_SCAN_SIZE]; - /**< List of \c key_state objects in the - * order they should be scanned by data - * channel modules. */ - - /* - * used by tls_pre_encrypt to communicate the encrypt key - * to tls_post_encrypt() - */ - struct key_state *save_ks; /* temporary pointer used between pre/post routines */ - - /* - * Used to return outgoing address from - * tls_multi_process. - */ - struct link_socket_actual to_link_addr; - - int n_sessions; /**< Number of sessions negotiated thus + /* used to coordinate access between main thread and TLS thread */ + /*MUTEX_PTR_DEFINE (mutex);*/ + + /* const options and config info */ + struct tls_options opt; + + struct key_state *key_scan[KEY_SCAN_SIZE]; + /**< List of \c key_state objects in the + * order they should be scanned by data + * channel modules. */ + + /* + * used by tls_pre_encrypt to communicate the encrypt key + * to tls_post_encrypt() + */ + struct key_state *save_ks; /* temporary pointer used between pre/post routines */ + + /* + * Used to return outgoing address from + * tls_multi_process. + */ + struct link_socket_actual to_link_addr; + + int n_sessions; /**< Number of sessions negotiated thus * far. */ - /* - * Number of errors. - */ - int n_hard_errors; /* errors due to TLS negotiation failure */ - int n_soft_errors; /* errors due to unrecognized or failed-to-authenticate incoming packets */ + /* + * Number of errors. + */ + int n_hard_errors; /* errors due to TLS negotiation failure */ + int n_soft_errors; /* errors due to unrecognized or failed-to-authenticate incoming packets */ - /* - * Our locked common name, username, and cert hashes (cannot change during the life of this tls_multi object) - */ - char *locked_cn; - char *locked_username; - struct cert_hash_set *locked_cert_hash_set; + /* + * Our locked common name, username, and cert hashes (cannot change during the life of this tls_multi object) + */ + char *locked_cn; + char *locked_username; + struct cert_hash_set *locked_cert_hash_set; #ifdef ENABLE_DEF_AUTH - /* - * An error message to send to client on AUTH_FAILED - */ - char *client_reason; + /* + * An error message to send to client on AUTH_FAILED + */ + char *client_reason; - /* Time of last call to tls_authentication_status */ - time_t tas_last; + /* Time of last call to tls_authentication_status */ + time_t tas_last; #endif #if P2MP_SERVER - /* - * A multi-line string of general-purpose info received from peer - * over control channel. - */ - char *peer_info; + /* + * A multi-line string of general-purpose info received from peer + * over control channel. + */ + char *peer_info; #endif - /* For P_DATA_V2 */ - uint32_t peer_id; - bool use_peer_id; + /* For P_DATA_V2 */ + uint32_t peer_id; + bool use_peer_id; - char *remote_ciphername; /**< cipher specified in peer's config file */ + char *remote_ciphername; /**< cipher specified in peer's config file */ - char *auth_token; /**< If server sends a generated auth-token, + char *auth_token; /**< If server sends a generated auth-token, * this is the token to use for future * user/pass authentications in this session. */ - time_t auth_token_tstamp; /**< timestamp of the generated token */ - bool auth_token_sent; /**< If server uses --auth-gen-token and - * token has been sent to client */ - /* - * Our session objects. - */ - struct tls_session session[TM_SIZE]; - /**< Array of \c tls_session objects - * representing control channel - * sessions with the remote peer. */ + time_t auth_token_tstamp; /**< timestamp of the generated token */ + bool auth_token_sent; /**< If server uses --auth-gen-token and + * token has been sent to client */ + /* + * Our session objects. + */ + struct tls_session session[TM_SIZE]; + /**< Array of \c tls_session objects + * representing control channel + * sessions with the remote peer. */ }; #define SHOW_TLS_CIPHER_LIST_WARNING \ - "Be aware that that whether a cipher suite in this list can actually work\n" \ - "depends on the specific setup of both peers. See the man page entries of\n" \ - "--tls-cipher and --show-tls for more details.\n\n" + "Be aware that that whether a cipher suite in this list can actually work\n" \ + "depends on the specific setup of both peers. See the man page entries of\n" \ + "--tls-cipher and --show-tls for more details.\n\n" #endif /* SSL_COMMON_H_ */ diff --git a/src/openvpn/ssl_mbedtls.c b/src/openvpn/ssl_mbedtls.c index 985a39fefd4..b6b600d1bb8 100644 --- a/src/openvpn/ssl_mbedtls.c +++ b/src/openvpn/ssl_mbedtls.c @@ -81,74 +81,87 @@ tls_clear_error() void tls_ctx_server_new(struct tls_root_ctx *ctx) { - ASSERT(NULL != ctx); - CLEAR(*ctx); + ASSERT(NULL != ctx); + CLEAR(*ctx); - ALLOC_OBJ_CLEAR(ctx->dhm_ctx, mbedtls_dhm_context); + ALLOC_OBJ_CLEAR(ctx->dhm_ctx, mbedtls_dhm_context); - ALLOC_OBJ_CLEAR(ctx->ca_chain, mbedtls_x509_crt); + ALLOC_OBJ_CLEAR(ctx->ca_chain, mbedtls_x509_crt); - ctx->endpoint = MBEDTLS_SSL_IS_SERVER; - ctx->initialised = true; + ctx->endpoint = MBEDTLS_SSL_IS_SERVER; + ctx->initialised = true; } void tls_ctx_client_new(struct tls_root_ctx *ctx) { - ASSERT(NULL != ctx); - CLEAR(*ctx); + ASSERT(NULL != ctx); + CLEAR(*ctx); - ALLOC_OBJ_CLEAR(ctx->dhm_ctx, mbedtls_dhm_context); - ALLOC_OBJ_CLEAR(ctx->ca_chain, mbedtls_x509_crt); + ALLOC_OBJ_CLEAR(ctx->dhm_ctx, mbedtls_dhm_context); + ALLOC_OBJ_CLEAR(ctx->ca_chain, mbedtls_x509_crt); - ctx->endpoint = MBEDTLS_SSL_IS_CLIENT; - ctx->initialised = true; + ctx->endpoint = MBEDTLS_SSL_IS_CLIENT; + ctx->initialised = true; } void tls_ctx_free(struct tls_root_ctx *ctx) { - if (ctx) + if (ctx) { - mbedtls_pk_free(ctx->priv_key); - if (ctx->priv_key) - free(ctx->priv_key); - - mbedtls_x509_crt_free(ctx->ca_chain); - if (ctx->ca_chain) - free(ctx->ca_chain); - - mbedtls_x509_crt_free(ctx->crt_chain); - if (ctx->crt_chain) - free(ctx->crt_chain); - - mbedtls_dhm_free(ctx->dhm_ctx); - if (ctx->dhm_ctx) - free(ctx->dhm_ctx); - - mbedtls_x509_crl_free(ctx->crl); - if (ctx->crl) - { - free(ctx->crl); - } + mbedtls_pk_free(ctx->priv_key); + if (ctx->priv_key) + { + free(ctx->priv_key); + } + + mbedtls_x509_crt_free(ctx->ca_chain); + if (ctx->ca_chain) + { + free(ctx->ca_chain); + } + + mbedtls_x509_crt_free(ctx->crt_chain); + if (ctx->crt_chain) + { + free(ctx->crt_chain); + } + + mbedtls_dhm_free(ctx->dhm_ctx); + if (ctx->dhm_ctx) + { + free(ctx->dhm_ctx); + } + + mbedtls_x509_crl_free(ctx->crl); + if (ctx->crl) + { + free(ctx->crl); + } #if defined(ENABLE_PKCS11) - if (ctx->priv_key_pkcs11 != NULL) { - mbedtls_pkcs11_priv_key_free(ctx->priv_key_pkcs11); - free(ctx->priv_key_pkcs11); - } + if (ctx->priv_key_pkcs11 != NULL) + { + mbedtls_pkcs11_priv_key_free(ctx->priv_key_pkcs11); + free(ctx->priv_key_pkcs11); + } #endif #if defined(MANAGMENT_EXTERNAL_KEY) - if (ctx->external_key != NULL) - free(ctx->external_key); + if (ctx->external_key != NULL) + { + free(ctx->external_key); + } #endif - if (ctx->allowed_ciphers) - free(ctx->allowed_ciphers); + if (ctx->allowed_ciphers) + { + free(ctx->allowed_ciphers); + } - CLEAR(*ctx); + CLEAR(*ctx); - ctx->initialised = false; + ctx->initialised = false; } } @@ -156,8 +169,8 @@ tls_ctx_free(struct tls_root_ctx *ctx) bool tls_ctx_initialised(struct tls_root_ctx *ctx) { - ASSERT(NULL != ctx); - return ctx->initialised; + ASSERT(NULL != ctx); + return ctx->initialised; } void @@ -167,226 +180,242 @@ key_state_export_keying_material(struct key_state_ssl *ssl, } void -tls_ctx_set_options (struct tls_root_ctx *ctx, unsigned int ssl_flags) +tls_ctx_set_options(struct tls_root_ctx *ctx, unsigned int ssl_flags) { } static const char * -tls_translate_cipher_name (const char * cipher_name) { - const tls_cipher_name_pair * pair = tls_get_cipher_name_pair(cipher_name, strlen(cipher_name)); +tls_translate_cipher_name(const char *cipher_name) { + const tls_cipher_name_pair *pair = tls_get_cipher_name_pair(cipher_name, strlen(cipher_name)); - if (NULL == pair) + if (NULL == pair) { - // No translation found, return original - return cipher_name; + /* No translation found, return original */ + return cipher_name; } - if (0 != strcmp(cipher_name, pair->iana_name)) + if (0 != strcmp(cipher_name, pair->iana_name)) { - // Deprecated name found, notify user - msg(M_WARN, "Deprecated cipher suite name '%s', please use IANA name '%s'", pair->openssl_name, pair->iana_name); + /* Deprecated name found, notify user */ + msg(M_WARN, "Deprecated cipher suite name '%s', please use IANA name '%s'", pair->openssl_name, pair->iana_name); } - return pair->iana_name; + return pair->iana_name; } void tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers) { - char *tmp_ciphers, *tmp_ciphers_orig, *token; - int i, cipher_count; - int ciphers_len; + char *tmp_ciphers, *tmp_ciphers_orig, *token; + int i, cipher_count; + int ciphers_len; - if (NULL == ciphers) - return; /* Nothing to do */ + if (NULL == ciphers) + { + return; /* Nothing to do */ - ciphers_len = strlen (ciphers); + } + ciphers_len = strlen(ciphers); - ASSERT (NULL != ctx); - ASSERT (0 != ciphers_len); + ASSERT(NULL != ctx); + ASSERT(0 != ciphers_len); - /* Get number of ciphers */ - for (i = 0, cipher_count = 1; i < ciphers_len; i++) - if (ciphers[i] == ':') - cipher_count++; + /* Get number of ciphers */ + for (i = 0, cipher_count = 1; i < ciphers_len; i++) + if (ciphers[i] == ':') + { + cipher_count++; + } - /* Allocate an array for them */ - ALLOC_ARRAY_CLEAR(ctx->allowed_ciphers, int, cipher_count+1) + /* Allocate an array for them */ + ALLOC_ARRAY_CLEAR(ctx->allowed_ciphers, int, cipher_count+1) - /* Parse allowed ciphers, getting IDs */ - i = 0; - tmp_ciphers_orig = tmp_ciphers = string_alloc (ciphers, NULL); + /* Parse allowed ciphers, getting IDs */ + i = 0; + tmp_ciphers_orig = tmp_ciphers = string_alloc(ciphers, NULL); - token = strtok (tmp_ciphers, ":"); - while(token) + token = strtok(tmp_ciphers, ":"); + while (token) { - ctx->allowed_ciphers[i] = mbedtls_ssl_get_ciphersuite_id ( - tls_translate_cipher_name (token)); - if (0 != ctx->allowed_ciphers[i]) - i++; - token = strtok (NULL, ":"); + ctx->allowed_ciphers[i] = mbedtls_ssl_get_ciphersuite_id( + tls_translate_cipher_name(token)); + if (0 != ctx->allowed_ciphers[i]) + { + i++; + } + token = strtok(NULL, ":"); } - free(tmp_ciphers_orig); + free(tmp_ciphers_orig); } void -tls_ctx_check_cert_time (const struct tls_root_ctx *ctx) +tls_ctx_check_cert_time(const struct tls_root_ctx *ctx) { - ASSERT (ctx); - if (ctx->crt_chain == NULL) + ASSERT(ctx); + if (ctx->crt_chain == NULL) { - return; /* Nothing to check if there is no certificate */ + return; /* Nothing to check if there is no certificate */ } - if (mbedtls_x509_time_is_future (&ctx->crt_chain->valid_from)) + if (mbedtls_x509_time_is_future(&ctx->crt_chain->valid_from)) { - msg (M_WARN, "WARNING: Your certificate is not yet valid!"); + msg(M_WARN, "WARNING: Your certificate is not yet valid!"); } - if (mbedtls_x509_time_is_past (&ctx->crt_chain->valid_to)) + if (mbedtls_x509_time_is_past(&ctx->crt_chain->valid_to)) { - msg (M_WARN, "WARNING: Your certificate has expired!"); + msg(M_WARN, "WARNING: Your certificate has expired!"); } } void -tls_ctx_load_dh_params (struct tls_root_ctx *ctx, const char *dh_file, - const char *dh_inline - ) +tls_ctx_load_dh_params(struct tls_root_ctx *ctx, const char *dh_file, + const char *dh_inline + ) { - if (!strcmp (dh_file, INLINE_FILE_TAG) && dh_inline) - { - if (!mbed_ok(mbedtls_dhm_parse_dhm(ctx->dhm_ctx, - (const unsigned char *) dh_inline, strlen(dh_inline)+1))) - msg (M_FATAL, "Cannot read inline DH parameters"); - } -else - { - if (!mbed_ok(mbedtls_dhm_parse_dhmfile(ctx->dhm_ctx, dh_file))) - msg (M_FATAL, "Cannot read DH parameters from file %s", dh_file); - } - - msg (D_TLS_DEBUG_LOW, "Diffie-Hellman initialized with " counter_format " bit key", - (counter_type) 8 * mbedtls_mpi_size(&ctx->dhm_ctx->P)); + if (!strcmp(dh_file, INLINE_FILE_TAG) && dh_inline) + { + if (!mbed_ok(mbedtls_dhm_parse_dhm(ctx->dhm_ctx, + (const unsigned char *) dh_inline, strlen(dh_inline)+1))) + { + msg(M_FATAL, "Cannot read inline DH parameters"); + } + } + else + { + if (!mbed_ok(mbedtls_dhm_parse_dhmfile(ctx->dhm_ctx, dh_file))) + { + msg(M_FATAL, "Cannot read DH parameters from file %s", dh_file); + } + } + + msg(D_TLS_DEBUG_LOW, "Diffie-Hellman initialized with " counter_format " bit key", + (counter_type) 8 * mbedtls_mpi_size(&ctx->dhm_ctx->P)); } void -tls_ctx_load_ecdh_params (struct tls_root_ctx *ctx, const char *curve_name - ) +tls_ctx_load_ecdh_params(struct tls_root_ctx *ctx, const char *curve_name + ) { if (NULL != curve_name) - msg(M_WARN, "WARNING: mbed TLS builds do not support specifying an ECDH " - "curve, using default curves."); + { + msg(M_WARN, "WARNING: mbed TLS builds do not support specifying an ECDH " + "curve, using default curves."); + } } int tls_ctx_load_pkcs12(struct tls_root_ctx *ctx, const char *pkcs12_file, - const char *pkcs12_file_inline, - bool load_ca_file - ) + const char *pkcs12_file_inline, + bool load_ca_file + ) { - msg(M_FATAL, "PKCS #12 files not yet supported for mbed TLS."); - return 0; + msg(M_FATAL, "PKCS #12 files not yet supported for mbed TLS."); + return 0; } #ifdef ENABLE_CRYPTOAPI void tls_ctx_load_cryptoapi(struct tls_root_ctx *ctx, const char *cryptoapi_cert) { - msg(M_FATAL, "Windows CryptoAPI not yet supported for mbed TLS."); + msg(M_FATAL, "Windows CryptoAPI not yet supported for mbed TLS."); } #endif /* _WIN32 */ void -tls_ctx_load_cert_file (struct tls_root_ctx *ctx, const char *cert_file, - const char *cert_inline - ) +tls_ctx_load_cert_file(struct tls_root_ctx *ctx, const char *cert_file, + const char *cert_inline + ) { - ASSERT(NULL != ctx); + ASSERT(NULL != ctx); - if (!ctx->crt_chain) + if (!ctx->crt_chain) { - ALLOC_OBJ_CLEAR(ctx->crt_chain, mbedtls_x509_crt); + ALLOC_OBJ_CLEAR(ctx->crt_chain, mbedtls_x509_crt); } - if (!strcmp (cert_file, INLINE_FILE_TAG) && cert_inline) + if (!strcmp(cert_file, INLINE_FILE_TAG) && cert_inline) { - if (!mbed_ok(mbedtls_x509_crt_parse(ctx->crt_chain, - (const unsigned char *) cert_inline, strlen(cert_inline)+1))) - msg (M_FATAL, "Cannot load inline certificate file"); + if (!mbed_ok(mbedtls_x509_crt_parse(ctx->crt_chain, + (const unsigned char *) cert_inline, strlen(cert_inline)+1))) + { + msg(M_FATAL, "Cannot load inline certificate file"); + } } - else + else { - if (!mbed_ok(mbedtls_x509_crt_parse_file(ctx->crt_chain, cert_file))) - { - msg (M_FATAL, "Cannot load certificate file %s", cert_file); - } + if (!mbed_ok(mbedtls_x509_crt_parse_file(ctx->crt_chain, cert_file))) + { + msg(M_FATAL, "Cannot load certificate file %s", cert_file); + } } } int -tls_ctx_load_priv_file (struct tls_root_ctx *ctx, const char *priv_key_file, - const char *priv_key_inline - ) +tls_ctx_load_priv_file(struct tls_root_ctx *ctx, const char *priv_key_file, + const char *priv_key_inline + ) { - int status; - ASSERT(NULL != ctx); + int status; + ASSERT(NULL != ctx); - if (!ctx->priv_key) + if (!ctx->priv_key) { - ALLOC_OBJ_CLEAR(ctx->priv_key, mbedtls_pk_context); + ALLOC_OBJ_CLEAR(ctx->priv_key, mbedtls_pk_context); } - if (!strcmp (priv_key_file, INLINE_FILE_TAG) && priv_key_inline) + if (!strcmp(priv_key_file, INLINE_FILE_TAG) && priv_key_inline) { - status = mbedtls_pk_parse_key(ctx->priv_key, - (const unsigned char *) priv_key_inline, strlen(priv_key_inline)+1, - NULL, 0); - - if (MBEDTLS_ERR_PK_PASSWORD_REQUIRED == status) - { - char passbuf[512] = {0}; - pem_password_callback(passbuf, 512, 0, NULL); - status = mbedtls_pk_parse_key(ctx->priv_key, - (const unsigned char *) priv_key_inline, - strlen(priv_key_inline)+1, (unsigned char *) passbuf, - strlen(passbuf)); - } + status = mbedtls_pk_parse_key(ctx->priv_key, + (const unsigned char *) priv_key_inline, strlen(priv_key_inline)+1, + NULL, 0); + + if (MBEDTLS_ERR_PK_PASSWORD_REQUIRED == status) + { + char passbuf[512] = {0}; + pem_password_callback(passbuf, 512, 0, NULL); + status = mbedtls_pk_parse_key(ctx->priv_key, + (const unsigned char *) priv_key_inline, + strlen(priv_key_inline)+1, (unsigned char *) passbuf, + strlen(passbuf)); + } } - else + else { - status = mbedtls_pk_parse_keyfile(ctx->priv_key, priv_key_file, NULL); - if (MBEDTLS_ERR_PK_PASSWORD_REQUIRED == status) - { - char passbuf[512] = {0}; - pem_password_callback(passbuf, 512, 0, NULL); - status = mbedtls_pk_parse_keyfile(ctx->priv_key, priv_key_file, passbuf); - } + status = mbedtls_pk_parse_keyfile(ctx->priv_key, priv_key_file, NULL); + if (MBEDTLS_ERR_PK_PASSWORD_REQUIRED == status) + { + char passbuf[512] = {0}; + pem_password_callback(passbuf, 512, 0, NULL); + status = mbedtls_pk_parse_keyfile(ctx->priv_key, priv_key_file, passbuf); + } } - if (!mbed_ok(status)) + if (!mbed_ok(status)) { #ifdef ENABLE_MANAGEMENT - if (management && (MBEDTLS_ERR_PK_PASSWORD_MISMATCH == status)) - management_auth_failure (management, UP_TYPE_PRIVATE_KEY, NULL); + if (management && (MBEDTLS_ERR_PK_PASSWORD_MISMATCH == status)) + { + management_auth_failure(management, UP_TYPE_PRIVATE_KEY, NULL); + } #endif - msg (M_WARN, "Cannot load private key file %s", priv_key_file); - return 1; + msg(M_WARN, "Cannot load private key file %s", priv_key_file); + return 1; } - if (!mbed_ok(mbedtls_pk_check_pair(&ctx->crt_chain->pk, ctx->priv_key))) + if (!mbed_ok(mbedtls_pk_check_pair(&ctx->crt_chain->pk, ctx->priv_key))) { - msg (M_WARN, "Private key does not match the certificate"); - return 1; + msg(M_WARN, "Private key does not match the certificate"); + return 1; } - return 0; + return 0; } #ifdef MANAGMENT_EXTERNAL_KEY struct external_context { - size_t signature_length; + size_t signature_length; }; /** @@ -408,187 +437,220 @@ struct external_context { * * @return 0 on success, non-zero mbed TLS error code on failure. */ -static inline int external_pkcs1_sign( void *ctx_voidptr, - int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, int mode, - mbedtls_md_type_t md_alg, unsigned int hashlen, const unsigned char *hash, - unsigned char *sig ) +static inline int +external_pkcs1_sign( void *ctx_voidptr, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, int mode, + mbedtls_md_type_t md_alg, unsigned int hashlen, const unsigned char *hash, + unsigned char *sig ) { - struct external_context * const ctx = ctx_voidptr; - char *in_b64 = NULL; - char *out_b64 = NULL; - int rv; - unsigned char *p = sig; - size_t asn_len = 0, oid_size = 0, sig_len = 0; - const char *oid = NULL; - - if( NULL == ctx ) - return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; - - if( MBEDTLS_RSA_PRIVATE != mode ) - return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; - - /* - * Support a wide range of hashes. TLSv1.1 and before only need SIG_RSA_RAW, - * but TLSv1.2 needs the full suite of hashes. - * - * This code has been taken from mbed TLS pkcs11_sign(), under the GPLv2.0+. - */ - if( md_alg != MBEDTLS_MD_NONE ) + struct external_context *const ctx = ctx_voidptr; + char *in_b64 = NULL; + char *out_b64 = NULL; + int rv; + unsigned char *p = sig; + size_t asn_len = 0, oid_size = 0, sig_len = 0; + const char *oid = NULL; + + if (NULL == ctx) { - const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type( md_alg ); - if( md_info == NULL ) - return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); - - if (!mbed_ok(mbedtls_oid_get_oid_by_md( md_alg, &oid, &oid_size ))) - return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } - hashlen = mbedtls_md_get_size( md_info ); - asn_len = 10 + oid_size; + if (MBEDTLS_RSA_PRIVATE != mode) + { + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; } - sig_len = ctx->signature_length; - if ( (SIZE_MAX - hashlen) < asn_len || (hashlen + asn_len) > sig_len ) - return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + /* + * Support a wide range of hashes. TLSv1.1 and before only need SIG_RSA_RAW, + * but TLSv1.2 needs the full suite of hashes. + * + * This code has been taken from mbed TLS pkcs11_sign(), under the GPLv2.0+. + */ + if (md_alg != MBEDTLS_MD_NONE) + { + const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type( md_alg ); + if (md_info == NULL) + { + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + } + + if (!mbed_ok(mbedtls_oid_get_oid_by_md( md_alg, &oid, &oid_size ))) + { + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + } + + hashlen = mbedtls_md_get_size( md_info ); + asn_len = 10 + oid_size; + } - if( md_alg != MBEDTLS_MD_NONE ) + sig_len = ctx->signature_length; + if ( (SIZE_MAX - hashlen) < asn_len || (hashlen + asn_len) > sig_len) { - /* - * DigestInfo ::= SEQUENCE { - * digestAlgorithm DigestAlgorithmIdentifier, - * digest Digest } - * - * DigestAlgorithmIdentifier ::= AlgorithmIdentifier - * - * Digest ::= OCTET STRING - */ - *p++ = MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED; - *p++ = (unsigned char) ( 0x08 + oid_size + hashlen ); - *p++ = MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED; - *p++ = (unsigned char) ( 0x04 + oid_size ); - *p++ = MBEDTLS_ASN1_OID; - *p++ = oid_size & 0xFF; - memcpy( p, oid, oid_size ); - p += oid_size; - *p++ = MBEDTLS_ASN1_NULL; - *p++ = 0x00; - *p++ = MBEDTLS_ASN1_OCTET_STRING; - *p++ = hashlen; + return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + } - /* Determine added ASN length */ - asn_len = p - sig; - } + if (md_alg != MBEDTLS_MD_NONE) + { + /* + * DigestInfo ::= SEQUENCE { + * digestAlgorithm DigestAlgorithmIdentifier, + * digest Digest } + * + * DigestAlgorithmIdentifier ::= AlgorithmIdentifier + * + * Digest ::= OCTET STRING + */ + *p++ = MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED; + *p++ = (unsigned char) ( 0x08 + oid_size + hashlen ); + *p++ = MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED; + *p++ = (unsigned char) ( 0x04 + oid_size ); + *p++ = MBEDTLS_ASN1_OID; + *p++ = oid_size & 0xFF; + memcpy( p, oid, oid_size ); + p += oid_size; + *p++ = MBEDTLS_ASN1_NULL; + *p++ = 0x00; + *p++ = MBEDTLS_ASN1_OCTET_STRING; + *p++ = hashlen; + + /* Determine added ASN length */ + asn_len = p - sig; + } - /* Copy the hash to be signed */ - memcpy( p, hash, hashlen ); + /* Copy the hash to be signed */ + memcpy( p, hash, hashlen ); - /* convert 'from' to base64 */ - if (openvpn_base64_encode (sig, asn_len + hashlen, &in_b64) <= 0) + /* convert 'from' to base64 */ + if (openvpn_base64_encode(sig, asn_len + hashlen, &in_b64) <= 0) { - rv = MBEDTLS_ERR_RSA_BAD_INPUT_DATA; - goto done; + rv = MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + goto done; } - /* call MI for signature */ - if (management) - out_b64 = management_query_rsa_sig (management, in_b64); - if (!out_b64) + /* call MI for signature */ + if (management) { - rv = MBEDTLS_ERR_RSA_PRIVATE_FAILED; - goto done; + out_b64 = management_query_rsa_sig(management, in_b64); + } + if (!out_b64) + { + rv = MBEDTLS_ERR_RSA_PRIVATE_FAILED; + goto done; } - /* decode base64 signature to binary and verify length */ - if ( openvpn_base64_decode (out_b64, sig, ctx->signature_length) != - ctx->signature_length ) + /* decode base64 signature to binary and verify length */ + if (openvpn_base64_decode(out_b64, sig, ctx->signature_length) != + ctx->signature_length) { - rv = MBEDTLS_ERR_RSA_PRIVATE_FAILED; - goto done; + rv = MBEDTLS_ERR_RSA_PRIVATE_FAILED; + goto done; } - rv = 0; + rv = 0; done: - if (in_b64) - free (in_b64); - if (out_b64) - free (out_b64); - return rv; + if (in_b64) + { + free(in_b64); + } + if (out_b64) + { + free(out_b64); + } + return rv; } -static inline size_t external_key_len(void *vctx) +static inline size_t +external_key_len(void *vctx) { - struct external_context * const ctx = vctx; + struct external_context *const ctx = vctx; - return ctx->signature_length; + return ctx->signature_length; } int -tls_ctx_use_external_private_key (struct tls_root_ctx *ctx, - const char *cert_file, const char *cert_file_inline) +tls_ctx_use_external_private_key(struct tls_root_ctx *ctx, + const char *cert_file, const char *cert_file_inline) { - ASSERT(NULL != ctx); + ASSERT(NULL != ctx); - tls_ctx_load_cert_file(ctx, cert_file, cert_file_inline); + tls_ctx_load_cert_file(ctx, cert_file, cert_file_inline); - if (ctx->crt_chain == NULL) - return 0; + if (ctx->crt_chain == NULL) + { + return 0; + } - ALLOC_OBJ_CLEAR (ctx->external_key, struct external_context); - ctx->external_key->signature_length = mbedtls_pk_get_len (&ctx->crt_chain->pk); + ALLOC_OBJ_CLEAR(ctx->external_key, struct external_context); + ctx->external_key->signature_length = mbedtls_pk_get_len(&ctx->crt_chain->pk); - ALLOC_OBJ_CLEAR (ctx->priv_key, mbedtls_pk_context); - if (!mbed_ok (mbedtls_pk_setup_rsa_alt (ctx->priv_key, ctx->external_key, - NULL, external_pkcs1_sign, external_key_len))) - return 0; + ALLOC_OBJ_CLEAR(ctx->priv_key, mbedtls_pk_context); + if (!mbed_ok(mbedtls_pk_setup_rsa_alt(ctx->priv_key, ctx->external_key, + NULL, external_pkcs1_sign, external_key_len))) + { + return 0; + } - return 1; + return 1; } -#endif +#endif /* ifdef MANAGMENT_EXTERNAL_KEY */ -void tls_ctx_load_ca (struct tls_root_ctx *ctx, const char *ca_file, - const char *ca_inline, const char *ca_path, bool tls_server - ) +void +tls_ctx_load_ca(struct tls_root_ctx *ctx, const char *ca_file, + const char *ca_inline, const char *ca_path, bool tls_server + ) { - if (ca_path) - msg(M_FATAL, "ERROR: mbed TLS cannot handle the capath directive"); + if (ca_path) + { + msg(M_FATAL, "ERROR: mbed TLS cannot handle the capath directive"); + } - if (ca_file && !strcmp (ca_file, INLINE_FILE_TAG) && ca_inline) + if (ca_file && !strcmp(ca_file, INLINE_FILE_TAG) && ca_inline) { - if (!mbed_ok (mbedtls_x509_crt_parse (ctx->ca_chain, - (const unsigned char *) ca_inline, strlen(ca_inline)+1))) - msg (M_FATAL, "Cannot load inline CA certificates"); + if (!mbed_ok(mbedtls_x509_crt_parse(ctx->ca_chain, + (const unsigned char *) ca_inline, strlen(ca_inline)+1))) + { + msg(M_FATAL, "Cannot load inline CA certificates"); + } } - else + else { - /* Load CA file for verifying peer supplied certificate */ - if (!mbed_ok (mbedtls_x509_crt_parse_file (ctx->ca_chain, ca_file))) - msg (M_FATAL, "Cannot load CA certificate file %s", ca_file); + /* Load CA file for verifying peer supplied certificate */ + if (!mbed_ok(mbedtls_x509_crt_parse_file(ctx->ca_chain, ca_file))) + { + msg(M_FATAL, "Cannot load CA certificate file %s", ca_file); + } } } void -tls_ctx_load_extra_certs (struct tls_root_ctx *ctx, const char *extra_certs_file, - const char *extra_certs_inline - ) +tls_ctx_load_extra_certs(struct tls_root_ctx *ctx, const char *extra_certs_file, + const char *extra_certs_inline + ) { - ASSERT(NULL != ctx); + ASSERT(NULL != ctx); - if (!ctx->crt_chain) + if (!ctx->crt_chain) { - ALLOC_OBJ_CLEAR (ctx->crt_chain, mbedtls_x509_crt); + ALLOC_OBJ_CLEAR(ctx->crt_chain, mbedtls_x509_crt); } - if (!strcmp (extra_certs_file, INLINE_FILE_TAG) && extra_certs_inline) + if (!strcmp(extra_certs_file, INLINE_FILE_TAG) && extra_certs_inline) { - if (!mbed_ok(mbedtls_x509_crt_parse(ctx->crt_chain, - (const unsigned char *) extra_certs_inline, - strlen(extra_certs_inline)+1))) - msg (M_FATAL, "Cannot load inline extra-certs file"); + if (!mbed_ok(mbedtls_x509_crt_parse(ctx->crt_chain, + (const unsigned char *) extra_certs_inline, + strlen(extra_certs_inline)+1))) + { + msg(M_FATAL, "Cannot load inline extra-certs file"); + } } - else + else { - if (!mbed_ok(mbedtls_x509_crt_parse_file(ctx->crt_chain, extra_certs_file))) - msg (M_FATAL, "Cannot load extra-certs file: %s", extra_certs_file); + if (!mbed_ok(mbedtls_x509_crt_parse_file(ctx->crt_chain, extra_certs_file))) + { + msg(M_FATAL, "Cannot load extra-certs file: %s", extra_certs_file); + } } } @@ -602,131 +664,149 @@ tls_ctx_load_extra_certs (struct tls_root_ctx *ctx, const char *extra_certs_file * "Endless buffer" */ -static inline void buf_free_entry(buffer_entry *entry) +static inline void +buf_free_entry(buffer_entry *entry) { - if (NULL != entry) + if (NULL != entry) { - free(entry->data); - free(entry); + free(entry->data); + free(entry); } } -static void buf_free_entries(endless_buffer *buf) +static void +buf_free_entries(endless_buffer *buf) { - while(buf->first_block) + while (buf->first_block) { - buffer_entry *cur_block = buf->first_block; - buf->first_block = cur_block->next_block; - buf_free_entry(cur_block); + buffer_entry *cur_block = buf->first_block; + buf->first_block = cur_block->next_block; + buf_free_entry(cur_block); } - buf->last_block = NULL; + buf->last_block = NULL; } -static int endless_buf_read( endless_buffer *in, unsigned char * out, size_t out_len ) +static int +endless_buf_read( endless_buffer *in, unsigned char *out, size_t out_len ) { - size_t read_len = 0; - - if (in->first_block == NULL) - return MBEDTLS_ERR_SSL_WANT_READ; + size_t read_len = 0; - while (in->first_block != NULL && read_len < out_len) + if (in->first_block == NULL) { - int block_len = in->first_block->length - in->data_start; - if (block_len <= out_len - read_len) - { - buffer_entry *cur_entry = in->first_block; - memcpy(out + read_len, cur_entry->data + in->data_start, - block_len); - - read_len += block_len; - - in->first_block = cur_entry->next_block; - in->data_start = 0; - - if (in->first_block == NULL) - in->last_block = NULL; + return MBEDTLS_ERR_SSL_WANT_READ; + } - buf_free_entry(cur_entry); - } - else - { - memcpy(out + read_len, in->first_block->data + in->data_start, - out_len - read_len); - in->data_start += out_len - read_len; - read_len = out_len; - } + while (in->first_block != NULL && read_len < out_len) + { + int block_len = in->first_block->length - in->data_start; + if (block_len <= out_len - read_len) + { + buffer_entry *cur_entry = in->first_block; + memcpy(out + read_len, cur_entry->data + in->data_start, + block_len); + + read_len += block_len; + + in->first_block = cur_entry->next_block; + in->data_start = 0; + + if (in->first_block == NULL) + { + in->last_block = NULL; + } + + buf_free_entry(cur_entry); + } + else + { + memcpy(out + read_len, in->first_block->data + in->data_start, + out_len - read_len); + in->data_start += out_len - read_len; + read_len = out_len; + } } - return read_len; + return read_len; } -static int endless_buf_write( endless_buffer *out, const unsigned char *in, size_t len ) +static int +endless_buf_write( endless_buffer *out, const unsigned char *in, size_t len ) { - buffer_entry *new_block = malloc(sizeof(buffer_entry)); - if (NULL == new_block) - return MBEDTLS_ERR_NET_SEND_FAILED; + buffer_entry *new_block = malloc(sizeof(buffer_entry)); + if (NULL == new_block) + { + return MBEDTLS_ERR_NET_SEND_FAILED; + } - new_block->data = malloc(len); - if (NULL == new_block->data) + new_block->data = malloc(len); + if (NULL == new_block->data) { - free(new_block); - return MBEDTLS_ERR_NET_SEND_FAILED; + free(new_block); + return MBEDTLS_ERR_NET_SEND_FAILED; } - new_block->length = len; - new_block->next_block = NULL; + new_block->length = len; + new_block->next_block = NULL; - memcpy(new_block->data, in, len); + memcpy(new_block->data, in, len); - if (NULL == out->first_block) - out->first_block = new_block; + if (NULL == out->first_block) + { + out->first_block = new_block; + } - if (NULL != out->last_block) - out->last_block->next_block = new_block; + if (NULL != out->last_block) + { + out->last_block->next_block = new_block; + } - out->last_block = new_block; + out->last_block = new_block; - return len; + return len; } -static int ssl_bio_read( void *ctx, unsigned char *out, size_t out_len) +static int +ssl_bio_read( void *ctx, unsigned char *out, size_t out_len) { - bio_ctx *my_ctx = (bio_ctx *) ctx; - return endless_buf_read (&my_ctx->in, out, out_len); + bio_ctx *my_ctx = (bio_ctx *) ctx; + return endless_buf_read(&my_ctx->in, out, out_len); } -static int ssl_bio_write( void *ctx, const unsigned char *in, size_t in_len) +static int +ssl_bio_write( void *ctx, const unsigned char *in, size_t in_len) { - bio_ctx *my_ctx = (bio_ctx *) ctx; - return endless_buf_write (&my_ctx->out, in, in_len); + bio_ctx *my_ctx = (bio_ctx *) ctx; + return endless_buf_write(&my_ctx->out, in, in_len); } -static void my_debug( void *ctx, int level, const char *file, int line, - const char *str ) +static void +my_debug( void *ctx, int level, const char *file, int line, + const char *str ) { - int my_loglevel = (level < 3) ? D_TLS_DEBUG_MED : D_TLS_DEBUG; - msg (my_loglevel, "mbed TLS msg (%s:%d): %s", file, line, str); + int my_loglevel = (level < 3) ? D_TLS_DEBUG_MED : D_TLS_DEBUG; + msg(my_loglevel, "mbed TLS msg (%s:%d): %s", file, line, str); } /* * Further personalise the RNG using a hash of the public key */ -void tls_ctx_personalise_random(struct tls_root_ctx *ctx) +void +tls_ctx_personalise_random(struct tls_root_ctx *ctx) { - static char old_sha256_hash[32] = {0}; - unsigned char sha256_hash[32] = {0}; - mbedtls_ctr_drbg_context *cd_ctx = rand_ctx_get(); + static char old_sha256_hash[32] = {0}; + unsigned char sha256_hash[32] = {0}; + mbedtls_ctr_drbg_context *cd_ctx = rand_ctx_get(); - if (NULL != ctx->crt_chain) + if (NULL != ctx->crt_chain) { - mbedtls_x509_crt *cert = ctx->crt_chain; - - mbedtls_sha256(cert->tbs.p, cert->tbs.len, sha256_hash, false); - if ( 0 != memcmp(old_sha256_hash, sha256_hash, sizeof(sha256_hash))) - { - mbedtls_ctr_drbg_update(cd_ctx, sha256_hash, 32); - memcpy(old_sha256_hash, sha256_hash, sizeof(old_sha256_hash)); - } + mbedtls_x509_crt *cert = ctx->crt_chain; + + mbedtls_sha256(cert->tbs.p, cert->tbs.len, sha256_hash, false); + if (0 != memcmp(old_sha256_hash, sha256_hash, sizeof(sha256_hash))) + { + mbedtls_ctr_drbg_update(cd_ctx, sha256_hash, 32); + memcpy(old_sha256_hash, sha256_hash, sizeof(old_sha256_hash)); + } } } @@ -734,11 +814,11 @@ int tls_version_max(void) { #if defined(MBEDTLS_SSL_MAJOR_VERSION_3) && defined(MBEDTLS_SSL_MINOR_VERSION_3) - return TLS_VER_1_2; + return TLS_VER_1_2; #elif defined(MBEDTLS_SSL_MAJOR_VERSION_3) && defined(MBEDTLS_SSL_MINOR_VERSION_2) - return TLS_VER_1_1; + return TLS_VER_1_1; #else - return TLS_VER_1_0; + return TLS_VER_1_0; #endif } @@ -746,391 +826,415 @@ tls_version_max(void) * Convert an OpenVPN tls-version variable to mbed TLS format (i.e. a major and * minor ssl version number). * - * @param tls_ver The tls-version variable to convert. - * @param major Returns the TLS major version in mbed TLS format. - * Must be a valid pointer. - * @param minor Returns the TLS minor version in mbed TLS format. - * Must be a valid pointer. + * @param tls_ver The tls-version variable to convert. + * @param major Returns the TLS major version in mbed TLS format. + * Must be a valid pointer. + * @param minor Returns the TLS minor version in mbed TLS format. + * Must be a valid pointer. */ -static void tls_version_to_major_minor(int tls_ver, int *major, int *minor) { - ASSERT(major); - ASSERT(minor); - - switch (tls_ver) - { - case TLS_VER_1_0: - *major = MBEDTLS_SSL_MAJOR_VERSION_3; - *minor = MBEDTLS_SSL_MINOR_VERSION_1; - break; - case TLS_VER_1_1: - *major = MBEDTLS_SSL_MAJOR_VERSION_3; - *minor = MBEDTLS_SSL_MINOR_VERSION_2; - break; - case TLS_VER_1_2: - *major = MBEDTLS_SSL_MAJOR_VERSION_3; - *minor = MBEDTLS_SSL_MINOR_VERSION_3; - break; - default: - msg(M_FATAL, "%s: invalid TLS version %d", __func__, tls_ver); - break; - } +static void +tls_version_to_major_minor(int tls_ver, int *major, int *minor) { + ASSERT(major); + ASSERT(minor); + + switch (tls_ver) + { + case TLS_VER_1_0: + *major = MBEDTLS_SSL_MAJOR_VERSION_3; + *minor = MBEDTLS_SSL_MINOR_VERSION_1; + break; + + case TLS_VER_1_1: + *major = MBEDTLS_SSL_MAJOR_VERSION_3; + *minor = MBEDTLS_SSL_MINOR_VERSION_2; + break; + + case TLS_VER_1_2: + *major = MBEDTLS_SSL_MAJOR_VERSION_3; + *minor = MBEDTLS_SSL_MINOR_VERSION_3; + break; + + default: + msg(M_FATAL, "%s: invalid TLS version %d", __func__, tls_ver); + break; + } } void backend_tls_ctx_reload_crl(struct tls_root_ctx *ctx, const char *crl_file, - const char *crl_inline) + const char *crl_inline) { - ASSERT (crl_file); + ASSERT(crl_file); - if (ctx->crl == NULL) + if (ctx->crl == NULL) { - ALLOC_OBJ_CLEAR(ctx->crl, mbedtls_x509_crl); + ALLOC_OBJ_CLEAR(ctx->crl, mbedtls_x509_crl); } - mbedtls_x509_crl_free(ctx->crl); + mbedtls_x509_crl_free(ctx->crl); - if (!strcmp (crl_file, INLINE_FILE_TAG) && crl_inline) + if (!strcmp(crl_file, INLINE_FILE_TAG) && crl_inline) { - if (!mbed_ok(mbedtls_x509_crl_parse(ctx->crl, - (const unsigned char *)crl_inline, strlen(crl_inline)+1))) - { - msg (M_WARN, "CRL: cannot parse inline CRL"); - goto err; - } + if (!mbed_ok(mbedtls_x509_crl_parse(ctx->crl, + (const unsigned char *)crl_inline, strlen(crl_inline)+1))) + { + msg(M_WARN, "CRL: cannot parse inline CRL"); + goto err; + } } - else + else { - if (!mbed_ok(mbedtls_x509_crl_parse_file(ctx->crl, crl_file))) - { - msg (M_WARN, "CRL: cannot read CRL from file %s", crl_file); - goto err; - } + if (!mbed_ok(mbedtls_x509_crl_parse_file(ctx->crl, crl_file))) + { + msg(M_WARN, "CRL: cannot read CRL from file %s", crl_file); + goto err; + } } - return; + return; err: - mbedtls_x509_crl_free(ctx->crl); + mbedtls_x509_crl_free(ctx->crl); } -void key_state_ssl_init(struct key_state_ssl *ks_ssl, - const struct tls_root_ctx *ssl_ctx, bool is_server, struct tls_session *session) +void +key_state_ssl_init(struct key_state_ssl *ks_ssl, + const struct tls_root_ctx *ssl_ctx, bool is_server, struct tls_session *session) { - ASSERT(NULL != ssl_ctx); - ASSERT(ks_ssl); - CLEAR(*ks_ssl); - - /* Initialise SSL config */ - mbedtls_ssl_config_init(&ks_ssl->ssl_config); - mbedtls_ssl_config_defaults(&ks_ssl->ssl_config, ssl_ctx->endpoint, - MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT); + ASSERT(NULL != ssl_ctx); + ASSERT(ks_ssl); + CLEAR(*ks_ssl); + + /* Initialise SSL config */ + mbedtls_ssl_config_init(&ks_ssl->ssl_config); + mbedtls_ssl_config_defaults(&ks_ssl->ssl_config, ssl_ctx->endpoint, + MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT); #ifdef MBEDTLS_DEBUG_C - mbedtls_debug_set_threshold(3); + mbedtls_debug_set_threshold(3); #endif - mbedtls_ssl_conf_dbg (&ks_ssl->ssl_config, my_debug, NULL); - mbedtls_ssl_conf_rng (&ks_ssl->ssl_config, mbedtls_ctr_drbg_random, - rand_ctx_get()); + mbedtls_ssl_conf_dbg(&ks_ssl->ssl_config, my_debug, NULL); + mbedtls_ssl_conf_rng(&ks_ssl->ssl_config, mbedtls_ctr_drbg_random, + rand_ctx_get()); - if (ssl_ctx->allowed_ciphers) - mbedtls_ssl_conf_ciphersuites (&ks_ssl->ssl_config, ssl_ctx->allowed_ciphers); + if (ssl_ctx->allowed_ciphers) + { + mbedtls_ssl_conf_ciphersuites(&ks_ssl->ssl_config, ssl_ctx->allowed_ciphers); + } - /* Disable record splitting (for now). OpenVPN assumes records are sent - * unfragmented, and changing that will require thorough review and - * testing. Since OpenVPN is not susceptible to BEAST, we can just - * disable record splitting as a quick fix. */ + /* Disable record splitting (for now). OpenVPN assumes records are sent + * unfragmented, and changing that will require thorough review and + * testing. Since OpenVPN is not susceptible to BEAST, we can just + * disable record splitting as a quick fix. */ #if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING) - mbedtls_ssl_conf_cbc_record_splitting (&ks_ssl->ssl_config, - MBEDTLS_SSL_CBC_RECORD_SPLITTING_DISABLED); + mbedtls_ssl_conf_cbc_record_splitting(&ks_ssl->ssl_config, + MBEDTLS_SSL_CBC_RECORD_SPLITTING_DISABLED); #endif /* MBEDTLS_SSL_CBC_RECORD_SPLITTING */ - /* Initialise authentication information */ - if (is_server) - mbed_ok (mbedtls_ssl_conf_dh_param_ctx(&ks_ssl->ssl_config, - ssl_ctx->dhm_ctx)); + /* Initialise authentication information */ + if (is_server) + { + mbed_ok(mbedtls_ssl_conf_dh_param_ctx(&ks_ssl->ssl_config, + ssl_ctx->dhm_ctx)); + } - mbed_ok (mbedtls_ssl_conf_own_cert(&ks_ssl->ssl_config, ssl_ctx->crt_chain, - ssl_ctx->priv_key)); + mbed_ok(mbedtls_ssl_conf_own_cert(&ks_ssl->ssl_config, ssl_ctx->crt_chain, + ssl_ctx->priv_key)); - /* Initialise SSL verification */ + /* Initialise SSL verification */ #if P2MP_SERVER - if (session->opt->ssl_flags & SSLF_CLIENT_CERT_OPTIONAL) + if (session->opt->ssl_flags & SSLF_CLIENT_CERT_OPTIONAL) { - mbedtls_ssl_conf_authmode(&ks_ssl->ssl_config, MBEDTLS_SSL_VERIFY_OPTIONAL); + mbedtls_ssl_conf_authmode(&ks_ssl->ssl_config, MBEDTLS_SSL_VERIFY_OPTIONAL); } - else if (!(session->opt->ssl_flags & SSLF_CLIENT_CERT_NOT_REQUIRED)) + else if (!(session->opt->ssl_flags & SSLF_CLIENT_CERT_NOT_REQUIRED)) #endif - { - mbedtls_ssl_conf_authmode (&ks_ssl->ssl_config, MBEDTLS_SSL_VERIFY_REQUIRED); - } - mbedtls_ssl_conf_verify (&ks_ssl->ssl_config, verify_callback, session); - - /* TODO: mbed TLS does not currently support sending the CA chain to the client */ - mbedtls_ssl_conf_ca_chain (&ks_ssl->ssl_config, ssl_ctx->ca_chain, ssl_ctx->crl); - - /* Initialize minimum TLS version */ - { - const int tls_version_min = - (session->opt->ssl_flags >> SSLF_TLS_VERSION_MIN_SHIFT) & - SSLF_TLS_VERSION_MIN_MASK; - - /* default to TLS 1.0 */ - int major = MBEDTLS_SSL_MAJOR_VERSION_3; - int minor = MBEDTLS_SSL_MINOR_VERSION_1; - - if (tls_version_min > TLS_VER_UNSPEC) - tls_version_to_major_minor(tls_version_min, &major, &minor); - - mbedtls_ssl_conf_min_version(&ks_ssl->ssl_config, major, minor); - } - - /* Initialize maximum TLS version */ - { - const int tls_version_max = - (session->opt->ssl_flags >> SSLF_TLS_VERSION_MAX_SHIFT) & - SSLF_TLS_VERSION_MAX_MASK; - - if (tls_version_max > TLS_VER_UNSPEC) - { - int major, minor; - tls_version_to_major_minor(tls_version_max, &major, &minor); - mbedtls_ssl_conf_max_version(&ks_ssl->ssl_config, major, minor); - } - } - - /* Initialise SSL context */ - ALLOC_OBJ_CLEAR(ks_ssl->ctx, mbedtls_ssl_context); - mbedtls_ssl_init(ks_ssl->ctx); - mbedtls_ssl_setup(ks_ssl->ctx, &ks_ssl->ssl_config); - - /* Initialise BIOs */ - CLEAR (ks_ssl->bio_ctx); - mbedtls_ssl_set_bio (ks_ssl->ctx, &ks_ssl->bio_ctx, ssl_bio_write, - ssl_bio_read, NULL); + { + mbedtls_ssl_conf_authmode(&ks_ssl->ssl_config, MBEDTLS_SSL_VERIFY_REQUIRED); + } + mbedtls_ssl_conf_verify(&ks_ssl->ssl_config, verify_callback, session); + + /* TODO: mbed TLS does not currently support sending the CA chain to the client */ + mbedtls_ssl_conf_ca_chain(&ks_ssl->ssl_config, ssl_ctx->ca_chain, ssl_ctx->crl); + + /* Initialize minimum TLS version */ + { + const int tls_version_min = + (session->opt->ssl_flags >> SSLF_TLS_VERSION_MIN_SHIFT) + &SSLF_TLS_VERSION_MIN_MASK; + + /* default to TLS 1.0 */ + int major = MBEDTLS_SSL_MAJOR_VERSION_3; + int minor = MBEDTLS_SSL_MINOR_VERSION_1; + + if (tls_version_min > TLS_VER_UNSPEC) + { + tls_version_to_major_minor(tls_version_min, &major, &minor); + } + + mbedtls_ssl_conf_min_version(&ks_ssl->ssl_config, major, minor); + } + + /* Initialize maximum TLS version */ + { + const int tls_version_max = + (session->opt->ssl_flags >> SSLF_TLS_VERSION_MAX_SHIFT) + &SSLF_TLS_VERSION_MAX_MASK; + + if (tls_version_max > TLS_VER_UNSPEC) + { + int major, minor; + tls_version_to_major_minor(tls_version_max, &major, &minor); + mbedtls_ssl_conf_max_version(&ks_ssl->ssl_config, major, minor); + } + } + + /* Initialise SSL context */ + ALLOC_OBJ_CLEAR(ks_ssl->ctx, mbedtls_ssl_context); + mbedtls_ssl_init(ks_ssl->ctx); + mbedtls_ssl_setup(ks_ssl->ctx, &ks_ssl->ssl_config); + + /* Initialise BIOs */ + CLEAR(ks_ssl->bio_ctx); + mbedtls_ssl_set_bio(ks_ssl->ctx, &ks_ssl->bio_ctx, ssl_bio_write, + ssl_bio_read, NULL); } void key_state_ssl_free(struct key_state_ssl *ks_ssl) { - if (ks_ssl) { - if (ks_ssl->ctx) - { - mbedtls_ssl_free(ks_ssl->ctx); - free(ks_ssl->ctx); - } - mbedtls_ssl_config_free(&ks_ssl->ssl_config); - buf_free_entries(&ks_ssl->bio_ctx.in); - buf_free_entries(&ks_ssl->bio_ctx.out); - CLEAR(*ks_ssl); - } + if (ks_ssl) + { + if (ks_ssl->ctx) + { + mbedtls_ssl_free(ks_ssl->ctx); + free(ks_ssl->ctx); + } + mbedtls_ssl_config_free(&ks_ssl->ssl_config); + buf_free_entries(&ks_ssl->bio_ctx.in); + buf_free_entries(&ks_ssl->bio_ctx.out); + CLEAR(*ks_ssl); + } } int -key_state_write_plaintext (struct key_state_ssl *ks, struct buffer *buf) +key_state_write_plaintext(struct key_state_ssl *ks, struct buffer *buf) { - int retval = 0; + int retval = 0; - ASSERT (buf); + ASSERT(buf); - retval = key_state_write_plaintext_const(ks, BPTR(buf), BLEN(buf)); + retval = key_state_write_plaintext_const(ks, BPTR(buf), BLEN(buf)); - if (1 == retval) + if (1 == retval) { - memset (BPTR (buf), 0, BLEN (buf)); /* erase data just written */ - buf->len = 0; + memset(BPTR(buf), 0, BLEN(buf)); /* erase data just written */ + buf->len = 0; } - return retval; + return retval; } int -key_state_write_plaintext_const (struct key_state_ssl *ks, const uint8_t *data, int len) +key_state_write_plaintext_const(struct key_state_ssl *ks, const uint8_t *data, int len) { - int retval = 0; - perf_push (PERF_BIO_WRITE_PLAINTEXT); + int retval = 0; + perf_push(PERF_BIO_WRITE_PLAINTEXT); - ASSERT (NULL != ks); - ASSERT (len >= 0); + ASSERT(NULL != ks); + ASSERT(len >= 0); - if (0 == len) + if (0 == len) { - perf_pop (); - return 0; + perf_pop(); + return 0; } - ASSERT (data); + ASSERT(data); - retval = mbedtls_ssl_write(ks->ctx, data, len); + retval = mbedtls_ssl_write(ks->ctx, data, len); - if (retval < 0) + if (retval < 0) { - perf_pop (); - if (MBEDTLS_ERR_SSL_WANT_WRITE == retval || MBEDTLS_ERR_SSL_WANT_READ == retval) - return 0; - mbed_log_err (D_TLS_ERRORS, retval, - "TLS ERROR: write tls_write_plaintext_const error"); - return -1; + perf_pop(); + if (MBEDTLS_ERR_SSL_WANT_WRITE == retval || MBEDTLS_ERR_SSL_WANT_READ == retval) + { + return 0; + } + mbed_log_err(D_TLS_ERRORS, retval, + "TLS ERROR: write tls_write_plaintext_const error"); + return -1; } - if (retval != len) + if (retval != len) { - msg (D_TLS_ERRORS, - "TLS ERROR: write tls_write_plaintext_const incomplete %d/%d", - retval, len); - perf_pop (); - return -1; + msg(D_TLS_ERRORS, + "TLS ERROR: write tls_write_plaintext_const incomplete %d/%d", + retval, len); + perf_pop(); + return -1; } - /* successful write */ - dmsg (D_HANDSHAKE_VERBOSE, "write tls_write_plaintext_const %d bytes", retval); + /* successful write */ + dmsg(D_HANDSHAKE_VERBOSE, "write tls_write_plaintext_const %d bytes", retval); - perf_pop (); - return 1; + perf_pop(); + return 1; } int -key_state_read_ciphertext (struct key_state_ssl *ks, struct buffer *buf, - int maxlen) +key_state_read_ciphertext(struct key_state_ssl *ks, struct buffer *buf, + int maxlen) { - int retval = 0; - int len = 0; + int retval = 0; + int len = 0; - perf_push (PERF_BIO_READ_CIPHERTEXT); + perf_push(PERF_BIO_READ_CIPHERTEXT); - ASSERT (NULL != ks); - ASSERT (buf); - ASSERT (buf->len >= 0); + ASSERT(NULL != ks); + ASSERT(buf); + ASSERT(buf->len >= 0); - if (buf->len) + if (buf->len) { - perf_pop (); - return 0; + perf_pop(); + return 0; } - len = buf_forward_capacity (buf); - if (maxlen < len) - len = maxlen; + len = buf_forward_capacity(buf); + if (maxlen < len) + { + len = maxlen; + } - retval = endless_buf_read(&ks->bio_ctx.out, BPTR(buf), len); + retval = endless_buf_read(&ks->bio_ctx.out, BPTR(buf), len); - /* Error during read, check for retry error */ - if (retval < 0) + /* Error during read, check for retry error */ + if (retval < 0) { - perf_pop (); - if (MBEDTLS_ERR_SSL_WANT_WRITE == retval || MBEDTLS_ERR_SSL_WANT_READ == retval) - return 0; - mbed_log_err (D_TLS_ERRORS, retval, "TLS_ERROR: read tls_read_ciphertext error"); - buf->len = 0; - return -1; + perf_pop(); + if (MBEDTLS_ERR_SSL_WANT_WRITE == retval || MBEDTLS_ERR_SSL_WANT_READ == retval) + { + return 0; + } + mbed_log_err(D_TLS_ERRORS, retval, "TLS_ERROR: read tls_read_ciphertext error"); + buf->len = 0; + return -1; } - /* Nothing read, try again */ - if (0 == retval) + /* Nothing read, try again */ + if (0 == retval) { - buf->len = 0; - perf_pop (); - return 0; + buf->len = 0; + perf_pop(); + return 0; } - /* successful read */ - dmsg (D_HANDSHAKE_VERBOSE, "read tls_read_ciphertext %d bytes", retval); - buf->len = retval; - perf_pop (); - return 1; + /* successful read */ + dmsg(D_HANDSHAKE_VERBOSE, "read tls_read_ciphertext %d bytes", retval); + buf->len = retval; + perf_pop(); + return 1; } int -key_state_write_ciphertext (struct key_state_ssl *ks, struct buffer *buf) +key_state_write_ciphertext(struct key_state_ssl *ks, struct buffer *buf) { - int retval = 0; - perf_push (PERF_BIO_WRITE_CIPHERTEXT); + int retval = 0; + perf_push(PERF_BIO_WRITE_CIPHERTEXT); - ASSERT (NULL != ks); - ASSERT (buf); - ASSERT (buf->len >= 0); + ASSERT(NULL != ks); + ASSERT(buf); + ASSERT(buf->len >= 0); - if (0 == buf->len) + if (0 == buf->len) { - perf_pop (); - return 0; + perf_pop(); + return 0; } - retval = endless_buf_write(&ks->bio_ctx.in, BPTR(buf), buf->len); + retval = endless_buf_write(&ks->bio_ctx.in, BPTR(buf), buf->len); - if (retval < 0) + if (retval < 0) { - perf_pop (); - - if (MBEDTLS_ERR_SSL_WANT_WRITE == retval || MBEDTLS_ERR_SSL_WANT_READ == retval) - return 0; - mbed_log_err (D_TLS_ERRORS, retval, - "TLS ERROR: write tls_write_ciphertext error"); - return -1; + perf_pop(); + + if (MBEDTLS_ERR_SSL_WANT_WRITE == retval || MBEDTLS_ERR_SSL_WANT_READ == retval) + { + return 0; + } + mbed_log_err(D_TLS_ERRORS, retval, + "TLS ERROR: write tls_write_ciphertext error"); + return -1; } - if (retval != buf->len) + if (retval != buf->len) { - msg (D_TLS_ERRORS, "TLS ERROR: write tls_write_ciphertext incomplete %d/%d", - retval, buf->len); - perf_pop (); - return -1; + msg(D_TLS_ERRORS, "TLS ERROR: write tls_write_ciphertext incomplete %d/%d", + retval, buf->len); + perf_pop(); + return -1; } - /* successful write */ - dmsg (D_HANDSHAKE_VERBOSE, "write tls_write_ciphertext %d bytes", retval); + /* successful write */ + dmsg(D_HANDSHAKE_VERBOSE, "write tls_write_ciphertext %d bytes", retval); - memset (BPTR (buf), 0, BLEN (buf)); /* erase data just written */ - buf->len = 0; + memset(BPTR(buf), 0, BLEN(buf)); /* erase data just written */ + buf->len = 0; - perf_pop (); - return 1; + perf_pop(); + return 1; } int -key_state_read_plaintext (struct key_state_ssl *ks, struct buffer *buf, - int maxlen) +key_state_read_plaintext(struct key_state_ssl *ks, struct buffer *buf, + int maxlen) { - int retval = 0; - int len = 0; + int retval = 0; + int len = 0; - perf_push (PERF_BIO_READ_PLAINTEXT); + perf_push(PERF_BIO_READ_PLAINTEXT); - ASSERT (NULL != ks); - ASSERT (buf); - ASSERT (buf->len >= 0); + ASSERT(NULL != ks); + ASSERT(buf); + ASSERT(buf->len >= 0); - if (buf->len) + if (buf->len) { - perf_pop (); - return 0; + perf_pop(); + return 0; } - len = buf_forward_capacity (buf); - if (maxlen < len) - len = maxlen; + len = buf_forward_capacity(buf); + if (maxlen < len) + { + len = maxlen; + } - retval = mbedtls_ssl_read(ks->ctx, BPTR(buf), len); + retval = mbedtls_ssl_read(ks->ctx, BPTR(buf), len); - /* Error during read, check for retry error */ - if (retval < 0) + /* Error during read, check for retry error */ + if (retval < 0) { - if (MBEDTLS_ERR_SSL_WANT_WRITE == retval || MBEDTLS_ERR_SSL_WANT_READ == retval) - return 0; - mbed_log_err (D_TLS_ERRORS, retval, "TLS_ERROR: read tls_read_plaintext error"); - buf->len = 0; - perf_pop (); - return -1; + if (MBEDTLS_ERR_SSL_WANT_WRITE == retval || MBEDTLS_ERR_SSL_WANT_READ == retval) + { + return 0; + } + mbed_log_err(D_TLS_ERRORS, retval, "TLS_ERROR: read tls_read_plaintext error"); + buf->len = 0; + perf_pop(); + return -1; } - /* Nothing read, try again */ - if (0 == retval) + /* Nothing read, try again */ + if (0 == retval) { - buf->len = 0; - perf_pop (); - return 0; + buf->len = 0; + perf_pop(); + return 0; } - /* successful read */ - dmsg (D_HANDSHAKE_VERBOSE, "read tls_read_plaintext %d bytes", retval); - buf->len = retval; + /* successful read */ + dmsg(D_HANDSHAKE_VERBOSE, "read tls_read_plaintext %d bytes", retval); + buf->len = retval; - perf_pop (); - return 1; + perf_pop(); + return 1; } /* ************************************** @@ -1141,82 +1245,88 @@ key_state_read_plaintext (struct key_state_ssl *ks, struct buffer *buf, * ***************************************/ void -print_details (struct key_state_ssl * ks_ssl, const char *prefix) +print_details(struct key_state_ssl *ks_ssl, const char *prefix) { - const mbedtls_x509_crt *cert; - char s1[256]; - char s2[256]; - - s1[0] = s2[0] = 0; - openvpn_snprintf (s1, sizeof (s1), "%s %s, cipher %s", - prefix, - mbedtls_ssl_get_version (ks_ssl->ctx), - mbedtls_ssl_get_ciphersuite (ks_ssl->ctx)); - - cert = mbedtls_ssl_get_peer_cert (ks_ssl->ctx); - if (cert != NULL) + const mbedtls_x509_crt *cert; + char s1[256]; + char s2[256]; + + s1[0] = s2[0] = 0; + openvpn_snprintf(s1, sizeof(s1), "%s %s, cipher %s", + prefix, + mbedtls_ssl_get_version(ks_ssl->ctx), + mbedtls_ssl_get_ciphersuite(ks_ssl->ctx)); + + cert = mbedtls_ssl_get_peer_cert(ks_ssl->ctx); + if (cert != NULL) { - openvpn_snprintf (s2, sizeof (s2), ", %u bit key", - (unsigned int) mbedtls_pk_get_bitlen (&cert->pk)); + openvpn_snprintf(s2, sizeof(s2), ", %u bit key", + (unsigned int) mbedtls_pk_get_bitlen(&cert->pk)); } - msg (D_HANDSHAKE, "%s%s", s1, s2); + msg(D_HANDSHAKE, "%s%s", s1, s2); } void -show_available_tls_ciphers (const char *cipher_list) +show_available_tls_ciphers(const char *cipher_list) { - struct tls_root_ctx tls_ctx; - const int *ciphers = mbedtls_ssl_list_ciphersuites (); + struct tls_root_ctx tls_ctx; + const int *ciphers = mbedtls_ssl_list_ciphersuites(); - tls_ctx_server_new(&tls_ctx); - tls_ctx_restrict_ciphers(&tls_ctx, cipher_list); + tls_ctx_server_new(&tls_ctx); + tls_ctx_restrict_ciphers(&tls_ctx, cipher_list); - if (tls_ctx.allowed_ciphers) - ciphers = tls_ctx.allowed_ciphers; + if (tls_ctx.allowed_ciphers) + { + ciphers = tls_ctx.allowed_ciphers; + } #ifndef ENABLE_SMALL - printf ("Available TLS Ciphers,\n"); - printf ("listed in order of preference:\n\n"); + printf("Available TLS Ciphers,\n"); + printf("listed in order of preference:\n\n"); #endif - while (*ciphers != 0) + while (*ciphers != 0) { - printf ("%s\n", mbedtls_ssl_get_ciphersuite_name (*ciphers)); - ciphers++; + printf("%s\n", mbedtls_ssl_get_ciphersuite_name(*ciphers)); + ciphers++; } - printf ("\n" SHOW_TLS_CIPHER_LIST_WARNING); + printf("\n" SHOW_TLS_CIPHER_LIST_WARNING); - tls_ctx_free(&tls_ctx); + tls_ctx_free(&tls_ctx); } void -show_available_curves (void) +show_available_curves(void) { - const mbedtls_ecp_curve_info *pcurve = mbedtls_ecp_curve_list (); + const mbedtls_ecp_curve_info *pcurve = mbedtls_ecp_curve_list(); - if (NULL == pcurve) - msg (M_FATAL, "Cannot retrieve curve list from mbed TLS"); + if (NULL == pcurve) + { + msg(M_FATAL, "Cannot retrieve curve list from mbed TLS"); + } - /* Print curve list */ - printf ("Available Elliptic curves, listed in order of preference:\n\n"); - while (MBEDTLS_ECP_DP_NONE != pcurve->grp_id) + /* Print curve list */ + printf("Available Elliptic curves, listed in order of preference:\n\n"); + while (MBEDTLS_ECP_DP_NONE != pcurve->grp_id) { - printf("%s\n", pcurve->name); - pcurve++; + printf("%s\n", pcurve->name); + pcurve++; } } void -get_highest_preference_tls_cipher (char *buf, int size) +get_highest_preference_tls_cipher(char *buf, int size) { - const char *cipher_name; - const int *ciphers = mbedtls_ssl_list_ciphersuites(); - if (*ciphers == 0) - msg (M_FATAL, "Cannot retrieve list of supported SSL ciphers."); + const char *cipher_name; + const int *ciphers = mbedtls_ssl_list_ciphersuites(); + if (*ciphers == 0) + { + msg(M_FATAL, "Cannot retrieve list of supported SSL ciphers."); + } - cipher_name = mbedtls_ssl_get_ciphersuite_name(*ciphers); - strncpynt (buf, cipher_name, size); + cipher_name = mbedtls_ssl_get_ciphersuite_name(*ciphers); + strncpynt(buf, cipher_name, size); } const char * @@ -1225,7 +1335,7 @@ get_ssl_library_version(void) static char mbedtls_version[30]; unsigned int pv = mbedtls_version_get_number(); sprintf( mbedtls_version, "mbed TLS %d.%d.%d", - (pv>>24)&0xff, (pv>>16)&0xff, (pv>>8)&0xff ); + (pv>>24)&0xff, (pv>>16)&0xff, (pv>>8)&0xff ); return mbedtls_version; } diff --git a/src/openvpn/ssl_mbedtls.h b/src/openvpn/ssl_mbedtls.h index a4a7f05c7b1..dfd2ec9a249 100644 --- a/src/openvpn/ssl_mbedtls.h +++ b/src/openvpn/ssl_mbedtls.h @@ -65,29 +65,29 @@ typedef struct { * Either \c priv_key_pkcs11 or \c priv_key must be filled in. */ struct tls_root_ctx { - bool initialised; /**< True if the context has been initialised */ + bool initialised; /**< True if the context has been initialised */ - int endpoint; /**< Whether or not this is a server or a client */ + int endpoint; /**< Whether or not this is a server or a client */ - mbedtls_dhm_context *dhm_ctx; /**< Diffie-Helmann-Merkle context */ - mbedtls_x509_crt *crt_chain; /**< Local Certificate chain */ - mbedtls_x509_crt *ca_chain; /**< CA chain for remote verification */ - mbedtls_pk_context *priv_key; /**< Local private key */ + mbedtls_dhm_context *dhm_ctx; /**< Diffie-Helmann-Merkle context */ + mbedtls_x509_crt *crt_chain; /**< Local Certificate chain */ + mbedtls_x509_crt *ca_chain; /**< CA chain for remote verification */ + mbedtls_pk_context *priv_key; /**< Local private key */ mbedtls_x509_crl *crl; /**< Certificate Revocation List */ struct timespec crl_last_mtime; /**< CRL last modification time */ - off_t crl_last_size; /**< size of last loaded CRL */ + off_t crl_last_size; /**< size of last loaded CRL */ #if defined(ENABLE_PKCS11) - mbedtls_pkcs11_context *priv_key_pkcs11; /**< PKCS11 private key */ + mbedtls_pkcs11_context *priv_key_pkcs11; /**< PKCS11 private key */ #endif #ifdef MANAGMENT_EXTERNAL_KEY struct external_context *external_key; /**< Management external key */ #endif - int * allowed_ciphers; /**< List of allowed ciphers for this connection */ + int *allowed_ciphers; /**< List of allowed ciphers for this connection */ }; struct key_state_ssl { - mbedtls_ssl_config ssl_config; /**< mbedTLS global ssl config */ - mbedtls_ssl_context *ctx; /**< mbedTLS connection context */ + mbedtls_ssl_config ssl_config; /**< mbedTLS global ssl config */ + mbedtls_ssl_context *ctx; /**< mbedTLS connection context */ bio_ctx bio_ctx; }; diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c index 4f472ffc9f9..1f156d6866e 100644 --- a/src/openvpn/ssl_openssl.c +++ b/src/openvpn/ssl_openssl.c @@ -71,97 +71,104 @@ int mydata_index; /* GLOBAL */ void tls_init_lib() { - SSL_library_init(); + SSL_library_init(); #ifndef ENABLE_SMALL - SSL_load_error_strings(); + SSL_load_error_strings(); #endif - OpenSSL_add_all_algorithms (); + OpenSSL_add_all_algorithms(); - mydata_index = SSL_get_ex_new_index(0, "struct session *", NULL, NULL, NULL); - ASSERT (mydata_index >= 0); + mydata_index = SSL_get_ex_new_index(0, "struct session *", NULL, NULL, NULL); + ASSERT(mydata_index >= 0); } void tls_free_lib() { - EVP_cleanup(); + EVP_cleanup(); #ifndef ENABLE_SMALL - ERR_free_strings(); + ERR_free_strings(); #endif } void tls_clear_error() { - ERR_clear_error (); + ERR_clear_error(); } void tls_ctx_server_new(struct tls_root_ctx *ctx) { - ASSERT(NULL != ctx); + ASSERT(NULL != ctx); - ctx->ctx = SSL_CTX_new (SSLv23_server_method ()); + ctx->ctx = SSL_CTX_new(SSLv23_server_method()); - if (ctx->ctx == NULL) - crypto_msg (M_FATAL, "SSL_CTX_new SSLv23_server_method"); + if (ctx->ctx == NULL) + { + crypto_msg(M_FATAL, "SSL_CTX_new SSLv23_server_method"); + } } void tls_ctx_client_new(struct tls_root_ctx *ctx) { - ASSERT(NULL != ctx); + ASSERT(NULL != ctx); - ctx->ctx = SSL_CTX_new (SSLv23_client_method ()); + ctx->ctx = SSL_CTX_new(SSLv23_client_method()); - if (ctx->ctx == NULL) - crypto_msg (M_FATAL, "SSL_CTX_new SSLv23_client_method"); + if (ctx->ctx == NULL) + { + crypto_msg(M_FATAL, "SSL_CTX_new SSLv23_client_method"); + } } void tls_ctx_free(struct tls_root_ctx *ctx) { - ASSERT(NULL != ctx); - if (NULL != ctx->ctx) - SSL_CTX_free (ctx->ctx); - ctx->ctx = NULL; + ASSERT(NULL != ctx); + if (NULL != ctx->ctx) + { + SSL_CTX_free(ctx->ctx); + } + ctx->ctx = NULL; } -bool tls_ctx_initialised(struct tls_root_ctx *ctx) +bool +tls_ctx_initialised(struct tls_root_ctx *ctx) { - ASSERT(NULL != ctx); - return NULL != ctx->ctx; + ASSERT(NULL != ctx); + return NULL != ctx->ctx; } void key_state_export_keying_material(struct key_state_ssl *ssl, struct tls_session *session) { - if (session->opt->ekm_size > 0) + if (session->opt->ekm_size > 0) { #if (OPENSSL_VERSION_NUMBER >= 0x10001000) - unsigned int size = session->opt->ekm_size; - struct gc_arena gc = gc_new(); - unsigned char* ekm = (unsigned char*) gc_malloc(size, true, &gc); - - if (SSL_export_keying_material(ssl->ssl, ekm, size, - session->opt->ekm_label, session->opt->ekm_label_size, NULL, 0, 0)) - { - unsigned int len = (size * 2) + 2; - - const char *key = format_hex_ex (ekm, size, len, 0, NULL, &gc); - setenv_str (session->opt->es, "exported_keying_material", key); - - dmsg(D_TLS_DEBUG_MED, "%s: exported keying material: %s", - __func__, key); - } - else - { - msg (M_WARN, "WARNING: Export keying material failed!"); - setenv_del (session->opt->es, "exported_keying_material"); - } - gc_free(&gc); -#endif + unsigned int size = session->opt->ekm_size; + struct gc_arena gc = gc_new(); + unsigned char *ekm = (unsigned char *) gc_malloc(size, true, &gc); + + if (SSL_export_keying_material(ssl->ssl, ekm, size, + session->opt->ekm_label, session->opt->ekm_label_size, NULL, 0, 0)) + { + unsigned int len = (size * 2) + 2; + + const char *key = format_hex_ex(ekm, size, len, 0, NULL, &gc); + setenv_str(session->opt->es, "exported_keying_material", key); + + dmsg(D_TLS_DEBUG_MED, "%s: exported keying material: %s", + __func__, key); + } + else + { + msg(M_WARN, "WARNING: Export keying material failed!"); + setenv_del(session->opt->es, "exported_keying_material"); + } + gc_free(&gc); +#endif /* if (OPENSSL_VERSION_NUMBER >= 0x10001000) */ } } @@ -173,21 +180,21 @@ key_state_export_keying_material(struct key_state_ssl *ssl, #define INFO_CALLBACK_SSL_CONST const #endif static void -info_callback (INFO_CALLBACK_SSL_CONST SSL * s, int where, int ret) +info_callback(INFO_CALLBACK_SSL_CONST SSL *s, int where, int ret) { - if (where & SSL_CB_LOOP) + if (where & SSL_CB_LOOP) { - dmsg (D_HANDSHAKE_VERBOSE, "SSL state (%s): %s", - where & SSL_ST_CONNECT ? "connect" : - where & SSL_ST_ACCEPT ? "accept" : - "undefined", SSL_state_string_long (s)); + dmsg(D_HANDSHAKE_VERBOSE, "SSL state (%s): %s", + where & SSL_ST_CONNECT ? "connect" : + where &SSL_ST_ACCEPT ? "accept" : + "undefined", SSL_state_string_long(s)); } - else if (where & SSL_CB_ALERT) + else if (where & SSL_CB_ALERT) { - dmsg (D_HANDSHAKE_VERBOSE, "SSL alert (%s): %s: %s", - where & SSL_CB_READ ? "read" : "write", - SSL_alert_type_string_long (ret), - SSL_alert_desc_string_long (ret)); + dmsg(D_HANDSHAKE_VERBOSE, "SSL alert (%s): %s: %s", + where & SSL_CB_READ ? "read" : "write", + SSL_alert_type_string_long(ret), + SSL_alert_desc_string_long(ret)); } } @@ -200,632 +207,732 @@ int tls_version_max(void) { #if defined(SSL_OP_NO_TLSv1_2) - return TLS_VER_1_2; + return TLS_VER_1_2; #elif defined(SSL_OP_NO_TLSv1_1) - return TLS_VER_1_1; + return TLS_VER_1_1; #else - return TLS_VER_1_0; + return TLS_VER_1_0; #endif } void -tls_ctx_set_options (struct tls_root_ctx *ctx, unsigned int ssl_flags) +tls_ctx_set_options(struct tls_root_ctx *ctx, unsigned int ssl_flags) { - ASSERT(NULL != ctx); - - /* default certificate verification flags */ - int flags = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT; + ASSERT(NULL != ctx); - /* process SSL options including minimum TLS version we will accept from peer */ - { - long sslopt = SSL_OP_SINGLE_DH_USE | SSL_OP_NO_TICKET | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3; - int tls_ver_max = TLS_VER_UNSPEC; - const int tls_ver_min = - (ssl_flags >> SSLF_TLS_VERSION_MIN_SHIFT) & SSLF_TLS_VERSION_MIN_MASK; + /* default certificate verification flags */ + int flags = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT; - tls_ver_max = - (ssl_flags >> SSLF_TLS_VERSION_MAX_SHIFT) & SSLF_TLS_VERSION_MAX_MASK; - if (tls_ver_max <= TLS_VER_UNSPEC) - tls_ver_max = tls_version_max(); + /* process SSL options including minimum TLS version we will accept from peer */ + { + long sslopt = SSL_OP_SINGLE_DH_USE | SSL_OP_NO_TICKET | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3; + int tls_ver_max = TLS_VER_UNSPEC; + const int tls_ver_min = + (ssl_flags >> SSLF_TLS_VERSION_MIN_SHIFT) & SSLF_TLS_VERSION_MIN_MASK; + + tls_ver_max = + (ssl_flags >> SSLF_TLS_VERSION_MAX_SHIFT) & SSLF_TLS_VERSION_MAX_MASK; + if (tls_ver_max <= TLS_VER_UNSPEC) + { + tls_ver_max = tls_version_max(); + } - if (tls_ver_min > TLS_VER_1_0 || tls_ver_max < TLS_VER_1_0) - sslopt |= SSL_OP_NO_TLSv1; + if (tls_ver_min > TLS_VER_1_0 || tls_ver_max < TLS_VER_1_0) + { + sslopt |= SSL_OP_NO_TLSv1; + } #ifdef SSL_OP_NO_TLSv1_1 - if (tls_ver_min > TLS_VER_1_1 || tls_ver_max < TLS_VER_1_1) - sslopt |= SSL_OP_NO_TLSv1_1; + if (tls_ver_min > TLS_VER_1_1 || tls_ver_max < TLS_VER_1_1) + { + sslopt |= SSL_OP_NO_TLSv1_1; + } #endif #ifdef SSL_OP_NO_TLSv1_2 - if (tls_ver_min > TLS_VER_1_2 || tls_ver_max < TLS_VER_1_2) - sslopt |= SSL_OP_NO_TLSv1_2; + if (tls_ver_min > TLS_VER_1_2 || tls_ver_max < TLS_VER_1_2) + { + sslopt |= SSL_OP_NO_TLSv1_2; + } #endif #ifdef SSL_OP_NO_COMPRESSION - /* Disable compression - flag not available in OpenSSL 0.9.8 */ - sslopt |= SSL_OP_NO_COMPRESSION; + /* Disable compression - flag not available in OpenSSL 0.9.8 */ + sslopt |= SSL_OP_NO_COMPRESSION; #endif - SSL_CTX_set_options (ctx->ctx, sslopt); - } + SSL_CTX_set_options(ctx->ctx, sslopt); + } #ifdef SSL_MODE_RELEASE_BUFFERS - SSL_CTX_set_mode (ctx->ctx, SSL_MODE_RELEASE_BUFFERS); + SSL_CTX_set_mode(ctx->ctx, SSL_MODE_RELEASE_BUFFERS); #endif - SSL_CTX_set_session_cache_mode (ctx->ctx, SSL_SESS_CACHE_OFF); - SSL_CTX_set_default_passwd_cb (ctx->ctx, pem_password_callback); + SSL_CTX_set_session_cache_mode(ctx->ctx, SSL_SESS_CACHE_OFF); + SSL_CTX_set_default_passwd_cb(ctx->ctx, pem_password_callback); - /* Require peer certificate verification */ + /* Require peer certificate verification */ #if P2MP_SERVER - if (ssl_flags & SSLF_CLIENT_CERT_NOT_REQUIRED) + if (ssl_flags & SSLF_CLIENT_CERT_NOT_REQUIRED) { - flags = 0; + flags = 0; } - else if (ssl_flags & SSLF_CLIENT_CERT_OPTIONAL) + else if (ssl_flags & SSLF_CLIENT_CERT_OPTIONAL) { - flags = SSL_VERIFY_PEER; + flags = SSL_VERIFY_PEER; } #endif - SSL_CTX_set_verify (ctx->ctx, flags, verify_callback); + SSL_CTX_set_verify(ctx->ctx, flags, verify_callback); - SSL_CTX_set_info_callback (ctx->ctx, info_callback); + SSL_CTX_set_info_callback(ctx->ctx, info_callback); } void tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers) { - if (ciphers == NULL) + if (ciphers == NULL) { - /* Use sane default TLS cipher list */ - if(!SSL_CTX_set_cipher_list(ctx->ctx, - /* Use openssl's default list as a basis */ - "DEFAULT" - /* Disable export ciphers and openssl's 'low' and 'medium' ciphers */ - ":!EXP:!LOW:!MEDIUM" - /* Disable static (EC)DH keys (no forward secrecy) */ - ":!kDH:!kECDH" - /* Disable DSA private keys */ - ":!DSS" - /* Disable unsupported TLS modes */ - ":!PSK:!SRP:!kRSA")) - crypto_msg (M_FATAL, "Failed to set default TLS cipher list."); - return; + /* Use sane default TLS cipher list */ + if (!SSL_CTX_set_cipher_list(ctx->ctx, + /* Use openssl's default list as a basis */ + "DEFAULT" + /* Disable export ciphers and openssl's 'low' and 'medium' ciphers */ + ":!EXP:!LOW:!MEDIUM" + /* Disable static (EC)DH keys (no forward secrecy) */ + ":!kDH:!kECDH" + /* Disable DSA private keys */ + ":!DSS" + /* Disable unsupported TLS modes */ + ":!PSK:!SRP:!kRSA")) + { + crypto_msg(M_FATAL, "Failed to set default TLS cipher list."); + } + return; } - /* Parse supplied cipher list and pass on to OpenSSL */ - size_t begin_of_cipher, end_of_cipher; + /* Parse supplied cipher list and pass on to OpenSSL */ + size_t begin_of_cipher, end_of_cipher; + + const char *current_cipher; + size_t current_cipher_len; - const char *current_cipher; - size_t current_cipher_len; + const tls_cipher_name_pair *cipher_pair; - const tls_cipher_name_pair *cipher_pair; + char openssl_ciphers[4096]; + size_t openssl_ciphers_len = 0; + openssl_ciphers[0] = '\0'; - char openssl_ciphers[4096]; - size_t openssl_ciphers_len = 0; - openssl_ciphers[0] = '\0'; + ASSERT(NULL != ctx); - ASSERT(NULL != ctx); + /* Translate IANA cipher suite names to OpenSSL names */ + begin_of_cipher = end_of_cipher = 0; + for (; begin_of_cipher < strlen(ciphers); begin_of_cipher = end_of_cipher) { + end_of_cipher += strcspn(&ciphers[begin_of_cipher], ":"); + cipher_pair = tls_get_cipher_name_pair(&ciphers[begin_of_cipher], end_of_cipher - begin_of_cipher); + + if (NULL == cipher_pair) + { + /* No translation found, use original */ + current_cipher = &ciphers[begin_of_cipher]; + current_cipher_len = end_of_cipher - begin_of_cipher; + + /* Issue warning on missing translation */ + /* %.*s format specifier expects length of type int, so guarantee */ + /* that length is small enough and cast to int. */ + msg(D_LOW, "No valid translation found for TLS cipher '%.*s'", + constrain_int(current_cipher_len, 0, 256), current_cipher); + } + else + { + /* Use OpenSSL name */ + current_cipher = cipher_pair->openssl_name; + current_cipher_len = strlen(current_cipher); - // Translate IANA cipher suite names to OpenSSL names - begin_of_cipher = end_of_cipher = 0; - for (; begin_of_cipher < strlen(ciphers); begin_of_cipher = end_of_cipher) { - end_of_cipher += strcspn(&ciphers[begin_of_cipher], ":"); - cipher_pair = tls_get_cipher_name_pair(&ciphers[begin_of_cipher], end_of_cipher - begin_of_cipher); + if (end_of_cipher - begin_of_cipher == current_cipher_len + && 0 != memcmp(&ciphers[begin_of_cipher], cipher_pair->iana_name, + end_of_cipher - begin_of_cipher)) + { + /* Non-IANA name used, show warning */ + msg(M_WARN, "Deprecated TLS cipher name '%s', please use IANA name '%s'", cipher_pair->openssl_name, cipher_pair->iana_name); + } + } - if (NULL == cipher_pair) + /* Make sure new cipher name fits in cipher string */ + if (((sizeof(openssl_ciphers)-1) - openssl_ciphers_len) < current_cipher_len) { - // No translation found, use original - current_cipher = &ciphers[begin_of_cipher]; - current_cipher_len = end_of_cipher - begin_of_cipher; - - // Issue warning on missing translation - // %.*s format specifier expects length of type int, so guarantee - // that length is small enough and cast to int. - msg (D_LOW, "No valid translation found for TLS cipher '%.*s'", - constrain_int(current_cipher_len, 0, 256), current_cipher); + msg(M_FATAL, + "Failed to set restricted TLS cipher list, too long (>%d).", + (int)sizeof(openssl_ciphers)-1); } - else - { - // Use OpenSSL name - current_cipher = cipher_pair->openssl_name; - current_cipher_len = strlen(current_cipher); - - if (end_of_cipher - begin_of_cipher == current_cipher_len && - 0 != memcmp (&ciphers[begin_of_cipher], cipher_pair->iana_name, - end_of_cipher - begin_of_cipher)) - { - // Non-IANA name used, show warning - msg (M_WARN, "Deprecated TLS cipher name '%s', please use IANA name '%s'", cipher_pair->openssl_name, cipher_pair->iana_name); - } - } - - // Make sure new cipher name fits in cipher string - if (((sizeof(openssl_ciphers)-1) - openssl_ciphers_len) < current_cipher_len) - { - msg (M_FATAL, - "Failed to set restricted TLS cipher list, too long (>%d).", - (int)sizeof(openssl_ciphers)-1); - } - - // Concatenate cipher name to OpenSSL cipher string - memcpy(&openssl_ciphers[openssl_ciphers_len], current_cipher, current_cipher_len); - openssl_ciphers_len += current_cipher_len; - openssl_ciphers[openssl_ciphers_len] = ':'; - openssl_ciphers_len++; - - end_of_cipher++; - } - - if (openssl_ciphers_len > 0) - openssl_ciphers[openssl_ciphers_len-1] = '\0'; - - // Set OpenSSL cipher list - if(!SSL_CTX_set_cipher_list(ctx->ctx, openssl_ciphers)) - crypto_msg (M_FATAL, "Failed to set restricted TLS cipher list: %s", openssl_ciphers); + + /* Concatenate cipher name to OpenSSL cipher string */ + memcpy(&openssl_ciphers[openssl_ciphers_len], current_cipher, current_cipher_len); + openssl_ciphers_len += current_cipher_len; + openssl_ciphers[openssl_ciphers_len] = ':'; + openssl_ciphers_len++; + + end_of_cipher++; + } + + if (openssl_ciphers_len > 0) + { + openssl_ciphers[openssl_ciphers_len-1] = '\0'; + } + + /* Set OpenSSL cipher list */ + if (!SSL_CTX_set_cipher_list(ctx->ctx, openssl_ciphers)) + { + crypto_msg(M_FATAL, "Failed to set restricted TLS cipher list: %s", openssl_ciphers); + } } void -tls_ctx_check_cert_time (const struct tls_root_ctx *ctx) +tls_ctx_check_cert_time(const struct tls_root_ctx *ctx) { - int ret; - const X509 *cert; + int ret; + const X509 *cert; - ASSERT (ctx); + ASSERT(ctx); #if OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(LIBRESSL_VERSION_NUMBER) - /* OpenSSL 1.0.2 and up */ - cert = SSL_CTX_get0_certificate (ctx->ctx); + /* OpenSSL 1.0.2 and up */ + cert = SSL_CTX_get0_certificate(ctx->ctx); #else - /* OpenSSL 1.0.1 and earlier need an SSL object to get at the certificate */ - SSL *ssl = SSL_new (ctx->ctx); - cert = SSL_get_certificate (ssl); + /* OpenSSL 1.0.1 and earlier need an SSL object to get at the certificate */ + SSL *ssl = SSL_new(ctx->ctx); + cert = SSL_get_certificate(ssl); #endif - if (cert == NULL) + if (cert == NULL) { - goto cleanup; /* Nothing to check if there is no certificate */ + goto cleanup; /* Nothing to check if there is no certificate */ } - ret = X509_cmp_time (X509_get_notBefore (cert), NULL); - if (ret == 0) + ret = X509_cmp_time(X509_get_notBefore(cert), NULL); + if (ret == 0) { - msg (D_TLS_DEBUG_MED, "Failed to read certificate notBefore field."); + msg(D_TLS_DEBUG_MED, "Failed to read certificate notBefore field."); } - if (ret > 0) + if (ret > 0) { - msg (M_WARN, "WARNING: Your certificate is not yet valid!"); + msg(M_WARN, "WARNING: Your certificate is not yet valid!"); } - ret = X509_cmp_time (X509_get_notAfter (cert), NULL); - if (ret == 0) + ret = X509_cmp_time(X509_get_notAfter(cert), NULL); + if (ret == 0) { - msg (D_TLS_DEBUG_MED, "Failed to read certificate notAfter field."); + msg(D_TLS_DEBUG_MED, "Failed to read certificate notAfter field."); } - if (ret < 0) + if (ret < 0) { - msg (M_WARN, "WARNING: Your certificate has expired!"); + msg(M_WARN, "WARNING: Your certificate has expired!"); } cleanup: #if OPENSSL_VERSION_NUMBER < 0x10002000L || defined(LIBRESSL_VERSION_NUMBER) - SSL_free (ssl); + SSL_free(ssl); #endif - return; + return; } void -tls_ctx_load_dh_params (struct tls_root_ctx *ctx, const char *dh_file, - const char *dh_file_inline - ) +tls_ctx_load_dh_params(struct tls_root_ctx *ctx, const char *dh_file, + const char *dh_file_inline + ) { - DH *dh; - BIO *bio; + DH *dh; + BIO *bio; - ASSERT(NULL != ctx); + ASSERT(NULL != ctx); - if (!strcmp (dh_file, INLINE_FILE_TAG) && dh_file_inline) + if (!strcmp(dh_file, INLINE_FILE_TAG) && dh_file_inline) { - if (!(bio = BIO_new_mem_buf ((char *)dh_file_inline, -1))) - crypto_msg (M_FATAL, "Cannot open memory BIO for inline DH parameters"); + if (!(bio = BIO_new_mem_buf((char *)dh_file_inline, -1))) + { + crypto_msg(M_FATAL, "Cannot open memory BIO for inline DH parameters"); + } } - else + else { - /* Get Diffie Hellman Parameters */ - if (!(bio = BIO_new_file (dh_file, "r"))) - crypto_msg (M_FATAL, "Cannot open %s for DH parameters", dh_file); + /* Get Diffie Hellman Parameters */ + if (!(bio = BIO_new_file(dh_file, "r"))) + { + crypto_msg(M_FATAL, "Cannot open %s for DH parameters", dh_file); + } } - dh = PEM_read_bio_DHparams (bio, NULL, NULL, NULL); - BIO_free (bio); + dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); + BIO_free(bio); - if (!dh) - crypto_msg (M_FATAL, "Cannot load DH parameters from %s", dh_file); - if (!SSL_CTX_set_tmp_dh (ctx->ctx, dh)) - crypto_msg (M_FATAL, "SSL_CTX_set_tmp_dh"); + if (!dh) + { + crypto_msg(M_FATAL, "Cannot load DH parameters from %s", dh_file); + } + if (!SSL_CTX_set_tmp_dh(ctx->ctx, dh)) + { + crypto_msg(M_FATAL, "SSL_CTX_set_tmp_dh"); + } - msg (D_TLS_DEBUG_LOW, "Diffie-Hellman initialized with %d bit key", - 8 * DH_size (dh)); + msg(D_TLS_DEBUG_LOW, "Diffie-Hellman initialized with %d bit key", + 8 * DH_size(dh)); - DH_free (dh); + DH_free(dh); } void -tls_ctx_load_ecdh_params (struct tls_root_ctx *ctx, const char *curve_name - ) +tls_ctx_load_ecdh_params(struct tls_root_ctx *ctx, const char *curve_name + ) { #ifndef OPENSSL_NO_EC - int nid = NID_undef; - EC_KEY *ecdh = NULL; - const char *sname = NULL; + int nid = NID_undef; + EC_KEY *ecdh = NULL; + const char *sname = NULL; - /* Generate a new ECDH key for each SSL session (for non-ephemeral ECDH) */ - SSL_CTX_set_options(ctx->ctx, SSL_OP_SINGLE_ECDH_USE); + /* Generate a new ECDH key for each SSL session (for non-ephemeral ECDH) */ + SSL_CTX_set_options(ctx->ctx, SSL_OP_SINGLE_ECDH_USE); #if OPENSSL_VERSION_NUMBER >= 0x10002000L - /* OpenSSL 1.0.2 and newer can automatically handle ECDH parameter loading */ - if (NULL == curve_name) { - SSL_CTX_set_ecdh_auto(ctx->ctx, 1); - return; - } + /* OpenSSL 1.0.2 and newer can automatically handle ECDH parameter loading */ + if (NULL == curve_name) + { + SSL_CTX_set_ecdh_auto(ctx->ctx, 1); + return; + } #endif - /* For older OpenSSL, we'll have to do the parameter loading on our own */ - if (curve_name != NULL) + /* For older OpenSSL, we'll have to do the parameter loading on our own */ + if (curve_name != NULL) { - /* Use user supplied curve if given */ - msg (D_TLS_DEBUG, "Using user specified ECDH curve (%s)", curve_name); - nid = OBJ_sn2nid(curve_name); + /* Use user supplied curve if given */ + msg(D_TLS_DEBUG, "Using user specified ECDH curve (%s)", curve_name); + nid = OBJ_sn2nid(curve_name); } - else + else { - /* Extract curve from key */ - EC_KEY *eckey = NULL; - const EC_GROUP *ecgrp = NULL; - EVP_PKEY *pkey = NULL; + /* Extract curve from key */ + EC_KEY *eckey = NULL; + const EC_GROUP *ecgrp = NULL; + EVP_PKEY *pkey = NULL; - /* Little hack to get private key ref from SSL_CTX, yay OpenSSL... */ - SSL ssl; - ssl.cert = ctx->ctx->cert; - pkey = SSL_get_privatekey(&ssl); + /* Little hack to get private key ref from SSL_CTX, yay OpenSSL... */ + SSL ssl; + ssl.cert = ctx->ctx->cert; + pkey = SSL_get_privatekey(&ssl); - msg (D_TLS_DEBUG, "Extracting ECDH curve from private key"); + msg(D_TLS_DEBUG, "Extracting ECDH curve from private key"); - if (pkey != NULL && (eckey = EVP_PKEY_get1_EC_KEY(pkey)) != NULL && - (ecgrp = EC_KEY_get0_group(eckey)) != NULL) - nid = EC_GROUP_get_curve_name(ecgrp); + if (pkey != NULL && (eckey = EVP_PKEY_get1_EC_KEY(pkey)) != NULL + && (ecgrp = EC_KEY_get0_group(eckey)) != NULL) + { + nid = EC_GROUP_get_curve_name(ecgrp); + } } - /* Translate NID back to name , just for kicks */ - sname = OBJ_nid2sn(nid); - if (sname == NULL) sname = "(Unknown)"; + /* Translate NID back to name , just for kicks */ + sname = OBJ_nid2sn(nid); + if (sname == NULL) + { + sname = "(Unknown)"; + } - /* Create new EC key and set as ECDH key */ - if (NID_undef == nid || NULL == (ecdh = EC_KEY_new_by_curve_name(nid))) + /* Create new EC key and set as ECDH key */ + if (NID_undef == nid || NULL == (ecdh = EC_KEY_new_by_curve_name(nid))) { - /* Creating key failed, fall back on sane default */ - ecdh = EC_KEY_new_by_curve_name(NID_secp384r1); - const char *source = (NULL == curve_name) ? - "extract curve from certificate" : "use supplied curve"; - msg (D_TLS_DEBUG_LOW, - "Failed to %s (%s), using secp384r1 instead.", source, sname); - sname = OBJ_nid2sn(NID_secp384r1); + /* Creating key failed, fall back on sane default */ + ecdh = EC_KEY_new_by_curve_name(NID_secp384r1); + const char *source = (NULL == curve_name) ? + "extract curve from certificate" : "use supplied curve"; + msg(D_TLS_DEBUG_LOW, + "Failed to %s (%s), using secp384r1 instead.", source, sname); + sname = OBJ_nid2sn(NID_secp384r1); } - if (!SSL_CTX_set_tmp_ecdh(ctx->ctx, ecdh)) - crypto_msg (M_FATAL, "SSL_CTX_set_tmp_ecdh: cannot add curve"); + if (!SSL_CTX_set_tmp_ecdh(ctx->ctx, ecdh)) + { + crypto_msg(M_FATAL, "SSL_CTX_set_tmp_ecdh: cannot add curve"); + } - msg (D_TLS_DEBUG_LOW, "ECDH curve %s added", sname); + msg(D_TLS_DEBUG_LOW, "ECDH curve %s added", sname); - EC_KEY_free(ecdh); -#else - msg (M_DEBUG, "Your OpenSSL library was built without elliptic curve support." - " Skipping ECDH parameter loading."); + EC_KEY_free(ecdh); +#else /* ifndef OPENSSL_NO_EC */ + msg(M_DEBUG, "Your OpenSSL library was built without elliptic curve support." + " Skipping ECDH parameter loading."); #endif /* OPENSSL_NO_EC */ } int tls_ctx_load_pkcs12(struct tls_root_ctx *ctx, const char *pkcs12_file, - const char *pkcs12_file_inline, - bool load_ca_file - ) + const char *pkcs12_file_inline, + bool load_ca_file + ) { - FILE *fp; - EVP_PKEY *pkey; - X509 *cert; - STACK_OF(X509) *ca = NULL; - PKCS12 *p12; - int i; - char password[256]; - - ASSERT(NULL != ctx); - - if (!strcmp (pkcs12_file, INLINE_FILE_TAG) && pkcs12_file_inline) - { - BIO *b64 = BIO_new(BIO_f_base64()); - BIO *bio = BIO_new_mem_buf((void *) pkcs12_file_inline, - (int) strlen(pkcs12_file_inline)); - ASSERT(b64 && bio); - BIO_push(b64, bio); - p12 = d2i_PKCS12_bio(b64, NULL); - if (!p12) - crypto_msg (M_FATAL, "Error reading inline PKCS#12 file"); - BIO_free(b64); - BIO_free(bio); - } - else - { - /* Load the PKCS #12 file */ - if (!(fp = platform_fopen(pkcs12_file, "rb"))) - crypto_msg (M_FATAL, "Error opening file %s", pkcs12_file); - p12 = d2i_PKCS12_fp(fp, NULL); - fclose(fp); - if (!p12) - crypto_msg (M_FATAL, "Error reading PKCS#12 file %s", pkcs12_file); - } - - /* Parse the PKCS #12 file */ - if (!PKCS12_parse(p12, "", &pkey, &cert, &ca)) - { - pem_password_callback (password, sizeof(password) - 1, 0, NULL); - /* Reparse the PKCS #12 file with password */ - ca = NULL; - if (!PKCS12_parse(p12, password, &pkey, &cert, &ca)) - { + FILE *fp; + EVP_PKEY *pkey; + X509 *cert; + STACK_OF(X509) *ca = NULL; + PKCS12 *p12; + int i; + char password[256]; + + ASSERT(NULL != ctx); + + if (!strcmp(pkcs12_file, INLINE_FILE_TAG) && pkcs12_file_inline) + { + BIO *b64 = BIO_new(BIO_f_base64()); + BIO *bio = BIO_new_mem_buf((void *) pkcs12_file_inline, + (int) strlen(pkcs12_file_inline)); + ASSERT(b64 && bio); + BIO_push(b64, bio); + p12 = d2i_PKCS12_bio(b64, NULL); + if (!p12) + { + crypto_msg(M_FATAL, "Error reading inline PKCS#12 file"); + } + BIO_free(b64); + BIO_free(bio); + } + else + { + /* Load the PKCS #12 file */ + if (!(fp = platform_fopen(pkcs12_file, "rb"))) + { + crypto_msg(M_FATAL, "Error opening file %s", pkcs12_file); + } + p12 = d2i_PKCS12_fp(fp, NULL); + fclose(fp); + if (!p12) + { + crypto_msg(M_FATAL, "Error reading PKCS#12 file %s", pkcs12_file); + } + } + + /* Parse the PKCS #12 file */ + if (!PKCS12_parse(p12, "", &pkey, &cert, &ca)) + { + pem_password_callback(password, sizeof(password) - 1, 0, NULL); + /* Reparse the PKCS #12 file with password */ + ca = NULL; + if (!PKCS12_parse(p12, password, &pkey, &cert, &ca)) + { #ifdef ENABLE_MANAGEMENT - if (management && (ERR_GET_REASON (ERR_peek_error()) == PKCS12_R_MAC_VERIFY_FAILURE)) - management_auth_failure (management, UP_TYPE_PRIVATE_KEY, NULL); + if (management && (ERR_GET_REASON(ERR_peek_error()) == PKCS12_R_MAC_VERIFY_FAILURE)) + { + management_auth_failure(management, UP_TYPE_PRIVATE_KEY, NULL); + } #endif - PKCS12_free(p12); - return 1; - } - } - PKCS12_free(p12); - - /* Load Certificate */ - if (!SSL_CTX_use_certificate (ctx->ctx, cert)) - crypto_msg (M_FATAL, "Cannot use certificate"); - - /* Load Private Key */ - if (!SSL_CTX_use_PrivateKey (ctx->ctx, pkey)) - crypto_msg (M_FATAL, "Cannot use private key"); - - /* Check Private Key */ - if (!SSL_CTX_check_private_key (ctx->ctx)) - crypto_msg (M_FATAL, "Private key does not match the certificate"); - - /* Set Certificate Verification chain */ - if (load_ca_file) - { - /* Add CAs from PKCS12 to the cert store and mark them as trusted. - * They're also used to fill in the chain of intermediate certs as - * necessary. - */ - if (ca && sk_X509_num(ca)) - { - for (i = 0; i < sk_X509_num(ca); i++) - { - if (!X509_STORE_add_cert(ctx->ctx->cert_store,sk_X509_value(ca, i))) - crypto_msg (M_FATAL,"Cannot add certificate to certificate chain (X509_STORE_add_cert)"); - if (!SSL_CTX_add_client_CA(ctx->ctx, sk_X509_value(ca, i))) - crypto_msg (M_FATAL,"Cannot add certificate to client CA list (SSL_CTX_add_client_CA)"); - } - } - } else { - /* If trusted CA certs were loaded from a PEM file, and we ignore the - * ones in PKCS12, do load PKCS12-provided certs to the client extra - * certs chain just in case they include intermediate CAs needed to - * prove my identity to the other end. This does not make them trusted. - */ - if (ca && sk_X509_num(ca)) - { - for (i = 0; i < sk_X509_num(ca); i++) - { - if (!SSL_CTX_add_extra_chain_cert(ctx->ctx,sk_X509_value(ca, i))) - crypto_msg (M_FATAL, "Cannot add extra certificate to chain (SSL_CTX_add_extra_chain_cert)"); - } - } - } - return 0; + PKCS12_free(p12); + return 1; + } + } + PKCS12_free(p12); + + /* Load Certificate */ + if (!SSL_CTX_use_certificate(ctx->ctx, cert)) + { + crypto_msg(M_FATAL, "Cannot use certificate"); + } + + /* Load Private Key */ + if (!SSL_CTX_use_PrivateKey(ctx->ctx, pkey)) + { + crypto_msg(M_FATAL, "Cannot use private key"); + } + + /* Check Private Key */ + if (!SSL_CTX_check_private_key(ctx->ctx)) + { + crypto_msg(M_FATAL, "Private key does not match the certificate"); + } + + /* Set Certificate Verification chain */ + if (load_ca_file) + { + /* Add CAs from PKCS12 to the cert store and mark them as trusted. + * They're also used to fill in the chain of intermediate certs as + * necessary. + */ + if (ca && sk_X509_num(ca)) + { + for (i = 0; i < sk_X509_num(ca); i++) + { + if (!X509_STORE_add_cert(ctx->ctx->cert_store,sk_X509_value(ca, i))) + { + crypto_msg(M_FATAL,"Cannot add certificate to certificate chain (X509_STORE_add_cert)"); + } + if (!SSL_CTX_add_client_CA(ctx->ctx, sk_X509_value(ca, i))) + { + crypto_msg(M_FATAL,"Cannot add certificate to client CA list (SSL_CTX_add_client_CA)"); + } + } + } + } + else + { + /* If trusted CA certs were loaded from a PEM file, and we ignore the + * ones in PKCS12, do load PKCS12-provided certs to the client extra + * certs chain just in case they include intermediate CAs needed to + * prove my identity to the other end. This does not make them trusted. + */ + if (ca && sk_X509_num(ca)) + { + for (i = 0; i < sk_X509_num(ca); i++) + { + if (!SSL_CTX_add_extra_chain_cert(ctx->ctx,sk_X509_value(ca, i))) + { + crypto_msg(M_FATAL, "Cannot add extra certificate to chain (SSL_CTX_add_extra_chain_cert)"); + } + } + } + } + return 0; } #ifdef ENABLE_CRYPTOAPI void tls_ctx_load_cryptoapi(struct tls_root_ctx *ctx, const char *cryptoapi_cert) { - ASSERT(NULL != ctx); + ASSERT(NULL != ctx); - /* Load Certificate and Private Key */ - if (!SSL_CTX_use_CryptoAPI_certificate (ctx->ctx, cryptoapi_cert)) - crypto_msg (M_FATAL, "Cannot load certificate \"%s\" from Microsoft Certificate Store", cryptoapi_cert); + /* Load Certificate and Private Key */ + if (!SSL_CTX_use_CryptoAPI_certificate(ctx->ctx, cryptoapi_cert)) + { + crypto_msg(M_FATAL, "Cannot load certificate \"%s\" from Microsoft Certificate Store", cryptoapi_cert); + } } #endif /* ENABLE_CRYPTOAPI */ static void -tls_ctx_add_extra_certs (struct tls_root_ctx *ctx, BIO *bio) +tls_ctx_add_extra_certs(struct tls_root_ctx *ctx, BIO *bio) { - X509 *cert; - for (;;) + X509 *cert; + for (;; ) { - cert = NULL; - if (!PEM_read_bio_X509 (bio, &cert, 0, NULL)) /* takes ownership of cert */ - break; - if (!cert) - crypto_msg (M_FATAL, "Error reading extra certificate"); - if (SSL_CTX_add_extra_chain_cert(ctx->ctx, cert) != 1) - crypto_msg (M_FATAL, "Error adding extra certificate"); + cert = NULL; + if (!PEM_read_bio_X509(bio, &cert, 0, NULL)) /* takes ownership of cert */ + { + break; + } + if (!cert) + { + crypto_msg(M_FATAL, "Error reading extra certificate"); + } + if (SSL_CTX_add_extra_chain_cert(ctx->ctx, cert) != 1) + { + crypto_msg(M_FATAL, "Error adding extra certificate"); + } } } /* Like tls_ctx_load_cert, but returns a copy of the certificate in **X509 */ static void -tls_ctx_load_cert_file_and_copy (struct tls_root_ctx *ctx, - const char *cert_file, const char *cert_file_inline, X509 **x509 - ) +tls_ctx_load_cert_file_and_copy(struct tls_root_ctx *ctx, + const char *cert_file, const char *cert_file_inline, X509 **x509 + ) { - BIO *in = NULL; - X509 *x = NULL; - int ret = 0; - bool inline_file = false; + BIO *in = NULL; + X509 *x = NULL; + int ret = 0; + bool inline_file = false; - ASSERT (NULL != ctx); - if (NULL != x509) - ASSERT (NULL == *x509); + ASSERT(NULL != ctx); + if (NULL != x509) + { + ASSERT(NULL == *x509); + } - inline_file = (strcmp (cert_file, INLINE_FILE_TAG) == 0); + inline_file = (strcmp(cert_file, INLINE_FILE_TAG) == 0); - if (inline_file && cert_file_inline) - in = BIO_new_mem_buf ((char *)cert_file_inline, -1); - else - in = BIO_new_file (cert_file, "r"); + if (inline_file && cert_file_inline) + { + in = BIO_new_mem_buf((char *)cert_file_inline, -1); + } + else + { + in = BIO_new_file(cert_file, "r"); + } - if (in == NULL) + if (in == NULL) { - SSLerr (SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_SYS_LIB); - goto end; + SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_SYS_LIB); + goto end; } - x = PEM_read_bio_X509 (in, NULL, ctx->ctx->default_passwd_callback, - ctx->ctx->default_passwd_callback_userdata); - if (x == NULL) + x = PEM_read_bio_X509(in, NULL, ctx->ctx->default_passwd_callback, + ctx->ctx->default_passwd_callback_userdata); + if (x == NULL) { - SSLerr (SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_PEM_LIB); - goto end; + SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_PEM_LIB); + goto end; } - ret = SSL_CTX_use_certificate (ctx->ctx, x); - if (ret) - tls_ctx_add_extra_certs (ctx, in); + ret = SSL_CTX_use_certificate(ctx->ctx, x); + if (ret) + { + tls_ctx_add_extra_certs(ctx, in); + } end: - if (!ret) + if (!ret) { - if (inline_file) - crypto_msg (M_FATAL, "Cannot load inline certificate file"); - else - crypto_msg (M_FATAL, "Cannot load certificate file %s", cert_file); + if (inline_file) + { + crypto_msg(M_FATAL, "Cannot load inline certificate file"); + } + else + { + crypto_msg(M_FATAL, "Cannot load certificate file %s", cert_file); + } } - if (in != NULL) - BIO_free(in); - if (x509) - *x509 = x; - else if (x) - X509_free (x); + if (in != NULL) + { + BIO_free(in); + } + if (x509) + { + *x509 = x; + } + else if (x) + { + X509_free(x); + } } void -tls_ctx_load_cert_file (struct tls_root_ctx *ctx, const char *cert_file, - const char *cert_file_inline) +tls_ctx_load_cert_file(struct tls_root_ctx *ctx, const char *cert_file, + const char *cert_file_inline) { - tls_ctx_load_cert_file_and_copy (ctx, cert_file, cert_file_inline, NULL); + tls_ctx_load_cert_file_and_copy(ctx, cert_file, cert_file_inline, NULL); } void -tls_ctx_free_cert_file (X509 *x509) +tls_ctx_free_cert_file(X509 *x509) { - X509_free(x509); + X509_free(x509); } int -tls_ctx_load_priv_file (struct tls_root_ctx *ctx, const char *priv_key_file, - const char *priv_key_file_inline - ) +tls_ctx_load_priv_file(struct tls_root_ctx *ctx, const char *priv_key_file, + const char *priv_key_file_inline + ) { - SSL_CTX *ssl_ctx = NULL; - BIO *in = NULL; - EVP_PKEY *pkey = NULL; - int ret = 1; + SSL_CTX *ssl_ctx = NULL; + BIO *in = NULL; + EVP_PKEY *pkey = NULL; + int ret = 1; - ASSERT(NULL != ctx); + ASSERT(NULL != ctx); - ssl_ctx = ctx->ctx; + ssl_ctx = ctx->ctx; - if (!strcmp (priv_key_file, INLINE_FILE_TAG) && priv_key_file_inline) - in = BIO_new_mem_buf ((char *)priv_key_file_inline, -1); - else - in = BIO_new_file (priv_key_file, "r"); + if (!strcmp(priv_key_file, INLINE_FILE_TAG) && priv_key_file_inline) + { + in = BIO_new_mem_buf((char *)priv_key_file_inline, -1); + } + else + { + in = BIO_new_file(priv_key_file, "r"); + } - if (!in) - goto end; + if (!in) + { + goto end; + } - pkey = PEM_read_bio_PrivateKey (in, NULL, - ssl_ctx->default_passwd_callback, - ssl_ctx->default_passwd_callback_userdata); - if (!pkey) - goto end; + pkey = PEM_read_bio_PrivateKey(in, NULL, + ssl_ctx->default_passwd_callback, + ssl_ctx->default_passwd_callback_userdata); + if (!pkey) + { + goto end; + } - if (!SSL_CTX_use_PrivateKey (ssl_ctx, pkey)) + if (!SSL_CTX_use_PrivateKey(ssl_ctx, pkey)) { #ifdef ENABLE_MANAGEMENT - if (management && (ERR_GET_REASON (ERR_peek_error()) == EVP_R_BAD_DECRYPT)) - management_auth_failure (management, UP_TYPE_PRIVATE_KEY, NULL); + if (management && (ERR_GET_REASON(ERR_peek_error()) == EVP_R_BAD_DECRYPT)) + { + management_auth_failure(management, UP_TYPE_PRIVATE_KEY, NULL); + } #endif - crypto_msg (M_WARN, "Cannot load private key file %s", priv_key_file); - goto end; + crypto_msg(M_WARN, "Cannot load private key file %s", priv_key_file); + goto end; } - /* Check Private Key */ - if (!SSL_CTX_check_private_key (ssl_ctx)) - crypto_msg (M_FATAL, "Private key does not match the certificate"); - ret = 0; + /* Check Private Key */ + if (!SSL_CTX_check_private_key(ssl_ctx)) + { + crypto_msg(M_FATAL, "Private key does not match the certificate"); + } + ret = 0; end: - if (pkey) - EVP_PKEY_free (pkey); - if (in) - BIO_free (in); - return ret; + if (pkey) + { + EVP_PKEY_free(pkey); + } + if (in) + { + BIO_free(in); + } + return ret; } void backend_tls_ctx_reload_crl(struct tls_root_ctx *ssl_ctx, const char *crl_file, - const char *crl_inline) + const char *crl_inline) { - X509_CRL *crl = NULL; - BIO *in = NULL; + X509_CRL *crl = NULL; + BIO *in = NULL; - X509_STORE *store = SSL_CTX_get_cert_store(ssl_ctx->ctx); - if (!store) - crypto_msg (M_FATAL, "Cannot get certificate store"); + X509_STORE *store = SSL_CTX_get_cert_store(ssl_ctx->ctx); + if (!store) + { + crypto_msg(M_FATAL, "Cannot get certificate store"); + } - /* Always start with a cleared CRL list, for that we - * we need to manually find the CRL object from the stack - * and remove it */ - for (int i = 0; i < sk_X509_OBJECT_num(store->objs); i++) + /* Always start with a cleared CRL list, for that we + * we need to manually find the CRL object from the stack + * and remove it */ + for (int i = 0; i < sk_X509_OBJECT_num(store->objs); i++) { - X509_OBJECT* obj = sk_X509_OBJECT_value(store->objs, i); - ASSERT(obj); - if (obj->type == X509_LU_CRL) - { - sk_X509_OBJECT_delete(store->objs, i); - X509_OBJECT_free_contents(obj); - OPENSSL_free(obj); - } + X509_OBJECT *obj = sk_X509_OBJECT_value(store->objs, i); + ASSERT(obj); + if (obj->type == X509_LU_CRL) + { + sk_X509_OBJECT_delete(store->objs, i); + X509_OBJECT_free_contents(obj); + OPENSSL_free(obj); + } } - X509_STORE_set_flags (store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); + X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); - if (!strcmp (crl_file, INLINE_FILE_TAG) && crl_inline) - in = BIO_new_mem_buf ((char *)crl_inline, -1); - else - in = BIO_new_file (crl_file, "r"); + if (!strcmp(crl_file, INLINE_FILE_TAG) && crl_inline) + { + in = BIO_new_mem_buf((char *)crl_inline, -1); + } + else + { + in = BIO_new_file(crl_file, "r"); + } - if (in == NULL) + if (in == NULL) { - msg (M_WARN, "CRL: cannot read: %s", crl_file); - goto end; + msg(M_WARN, "CRL: cannot read: %s", crl_file); + goto end; } - crl = PEM_read_bio_X509_CRL(in, NULL, NULL, NULL); - if (crl == NULL) + crl = PEM_read_bio_X509_CRL(in, NULL, NULL, NULL); + if (crl == NULL) { - msg (M_WARN, "CRL: cannot read CRL from file %s", crl_file); - goto end; + msg(M_WARN, "CRL: cannot read CRL from file %s", crl_file); + goto end; } - if (!X509_STORE_add_crl(store, crl)) + if (!X509_STORE_add_crl(store, crl)) { - msg (M_WARN, "CRL: cannot add %s to store", crl_file); - goto end; + msg(M_WARN, "CRL: cannot add %s to store", crl_file); + goto end; } end: - X509_CRL_free(crl); - BIO_free(in); + X509_CRL_free(crl); + BIO_free(in); } @@ -835,294 +942,352 @@ backend_tls_ctx_reload_crl(struct tls_root_ctx *ssl_ctx, const char *crl_file, static int rsa_pub_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) { - ASSERT(0); - return -1; + ASSERT(0); + return -1; } /* verify arbitrary data */ static int rsa_pub_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) { - ASSERT(0); - return -1; + ASSERT(0); + return -1; } /* decrypt */ static int rsa_priv_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) { - ASSERT(0); - return -1; + ASSERT(0); + return -1; } /* called at RSA_free */ static int rsa_finish(RSA *rsa) { - free ((void*)rsa->meth); - rsa->meth = NULL; - return 1; + free((void *)rsa->meth); + rsa->meth = NULL; + return 1; } /* sign arbitrary data */ static int rsa_priv_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) { - /* optional app data in rsa->meth->app_data; */ - char *in_b64 = NULL; - char *out_b64 = NULL; - int ret = -1; - int len; - - if (padding != RSA_PKCS1_PADDING) - { - RSAerr (RSA_F_RSA_EAY_PRIVATE_ENCRYPT, RSA_R_UNKNOWN_PADDING_TYPE); - goto done; - } - - /* convert 'from' to base64 */ - if (openvpn_base64_encode (from, flen, &in_b64) <= 0) - goto done; - - /* call MI for signature */ - if (management) - out_b64 = management_query_rsa_sig (management, in_b64); - if (!out_b64) - goto done; - - /* decode base64 signature to binary */ - len = RSA_size(rsa); - ret = openvpn_base64_decode (out_b64, to, len); - - /* verify length */ - if (ret != len) - ret = -1; - - done: - if (in_b64) - free (in_b64); - if (out_b64) - free (out_b64); - return ret; -} + /* optional app data in rsa->meth->app_data; */ + char *in_b64 = NULL; + char *out_b64 = NULL; + int ret = -1; + int len; -int -tls_ctx_use_external_private_key (struct tls_root_ctx *ctx, - const char *cert_file, const char *cert_file_inline) -{ - RSA *rsa = NULL; - RSA *pub_rsa; - RSA_METHOD *rsa_meth; - X509 *cert = NULL; + if (padding != RSA_PKCS1_PADDING) + { + RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, RSA_R_UNKNOWN_PADDING_TYPE); + goto done; + } - ASSERT (NULL != ctx); + /* convert 'from' to base64 */ + if (openvpn_base64_encode(from, flen, &in_b64) <= 0) + { + goto done; + } - tls_ctx_load_cert_file_and_copy (ctx, cert_file, cert_file_inline, &cert); + /* call MI for signature */ + if (management) + { + out_b64 = management_query_rsa_sig(management, in_b64); + } + if (!out_b64) + { + goto done; + } - ASSERT (NULL != cert); + /* decode base64 signature to binary */ + len = RSA_size(rsa); + ret = openvpn_base64_decode(out_b64, to, len); - /* allocate custom RSA method object */ - ALLOC_OBJ_CLEAR (rsa_meth, RSA_METHOD); - rsa_meth->name = "OpenVPN external private key RSA Method"; - rsa_meth->rsa_pub_enc = rsa_pub_enc; - rsa_meth->rsa_pub_dec = rsa_pub_dec; - rsa_meth->rsa_priv_enc = rsa_priv_enc; - rsa_meth->rsa_priv_dec = rsa_priv_dec; - rsa_meth->init = NULL; - rsa_meth->finish = rsa_finish; - rsa_meth->flags = RSA_METHOD_FLAG_NO_CHECK; - rsa_meth->app_data = NULL; + /* verify length */ + if (ret != len) + { + ret = -1; + } - /* allocate RSA object */ - rsa = RSA_new(); - if (rsa == NULL) +done: + if (in_b64) { - SSLerr(SSL_F_SSL_USE_PRIVATEKEY, ERR_R_MALLOC_FAILURE); - goto err; + free(in_b64); } + if (out_b64) + { + free(out_b64); + } + return ret; +} - /* get the public key */ - ASSERT(cert->cert_info->key->pkey); /* NULL before SSL_CTX_use_certificate() is called */ - pub_rsa = cert->cert_info->key->pkey->pkey.rsa; +int +tls_ctx_use_external_private_key(struct tls_root_ctx *ctx, + const char *cert_file, const char *cert_file_inline) +{ + RSA *rsa = NULL; + RSA *pub_rsa; + RSA_METHOD *rsa_meth; + X509 *cert = NULL; + + ASSERT(NULL != ctx); + + tls_ctx_load_cert_file_and_copy(ctx, cert_file, cert_file_inline, &cert); + + ASSERT(NULL != cert); + + /* allocate custom RSA method object */ + ALLOC_OBJ_CLEAR(rsa_meth, RSA_METHOD); + rsa_meth->name = "OpenVPN external private key RSA Method"; + rsa_meth->rsa_pub_enc = rsa_pub_enc; + rsa_meth->rsa_pub_dec = rsa_pub_dec; + rsa_meth->rsa_priv_enc = rsa_priv_enc; + rsa_meth->rsa_priv_dec = rsa_priv_dec; + rsa_meth->init = NULL; + rsa_meth->finish = rsa_finish; + rsa_meth->flags = RSA_METHOD_FLAG_NO_CHECK; + rsa_meth->app_data = NULL; + + /* allocate RSA object */ + rsa = RSA_new(); + if (rsa == NULL) + { + SSLerr(SSL_F_SSL_USE_PRIVATEKEY, ERR_R_MALLOC_FAILURE); + goto err; + } - /* initialize RSA object */ - rsa->n = BN_dup(pub_rsa->n); - rsa->flags |= RSA_FLAG_EXT_PKEY; - if (!RSA_set_method(rsa, rsa_meth)) - goto err; + /* get the public key */ + ASSERT(cert->cert_info->key->pkey); /* NULL before SSL_CTX_use_certificate() is called */ + pub_rsa = cert->cert_info->key->pkey->pkey.rsa; - /* bind our custom RSA object to ssl_ctx */ - if (!SSL_CTX_use_RSAPrivateKey(ctx->ctx, rsa)) - goto err; + /* initialize RSA object */ + rsa->n = BN_dup(pub_rsa->n); + rsa->flags |= RSA_FLAG_EXT_PKEY; + if (!RSA_set_method(rsa, rsa_meth)) + { + goto err; + } - X509_free(cert); - RSA_free(rsa); /* doesn't necessarily free, just decrements refcount */ - return 1; + /* bind our custom RSA object to ssl_ctx */ + if (!SSL_CTX_use_RSAPrivateKey(ctx->ctx, rsa)) + { + goto err; + } - err: - if (cert) X509_free(cert); - if (rsa) - RSA_free(rsa); - else + RSA_free(rsa); /* doesn't necessarily free, just decrements refcount */ + return 1; + +err: + if (cert) + { + X509_free(cert); + } + if (rsa) + { + RSA_free(rsa); + } + else { - if (rsa_meth) - free(rsa_meth); + if (rsa_meth) + { + free(rsa_meth); + } } - crypto_msg (M_FATAL, "Cannot enable SSL external private key capability"); - return 0; + crypto_msg(M_FATAL, "Cannot enable SSL external private key capability"); + return 0; } -#endif +#endif /* ifdef MANAGMENT_EXTERNAL_KEY */ static int -sk_x509_name_cmp(const X509_NAME * const *a, const X509_NAME * const *b) +sk_x509_name_cmp(const X509_NAME *const *a, const X509_NAME *const *b) { - return X509_NAME_cmp (*a, *b); + return X509_NAME_cmp(*a, *b); } void -tls_ctx_load_ca (struct tls_root_ctx *ctx, const char *ca_file, - const char *ca_file_inline, - const char *ca_path, bool tls_server - ) +tls_ctx_load_ca(struct tls_root_ctx *ctx, const char *ca_file, + const char *ca_file_inline, + const char *ca_path, bool tls_server + ) { - STACK_OF(X509_INFO) *info_stack = NULL; - STACK_OF(X509_NAME) *cert_names = NULL; - X509_LOOKUP *lookup = NULL; - X509_STORE *store = NULL; - X509_NAME *xn = NULL; - BIO *in = NULL; - int i, added = 0, prev = 0; - - ASSERT(NULL != ctx); - - store = SSL_CTX_get_cert_store(ctx->ctx); - if (!store) - crypto_msg (M_FATAL, "Cannot get certificate store"); + STACK_OF(X509_INFO) *info_stack = NULL; + STACK_OF(X509_NAME) *cert_names = NULL; + X509_LOOKUP *lookup = NULL; + X509_STORE *store = NULL; + X509_NAME *xn = NULL; + BIO *in = NULL; + int i, added = 0, prev = 0; + + ASSERT(NULL != ctx); + + store = SSL_CTX_get_cert_store(ctx->ctx); + if (!store) + { + crypto_msg(M_FATAL, "Cannot get certificate store"); + } - /* Try to add certificates and CRLs from ca_file */ - if (ca_file) + /* Try to add certificates and CRLs from ca_file */ + if (ca_file) { - if (!strcmp (ca_file, INLINE_FILE_TAG) && ca_file_inline) - in = BIO_new_mem_buf ((char *)ca_file_inline, -1); - else - in = BIO_new_file (ca_file, "r"); + if (!strcmp(ca_file, INLINE_FILE_TAG) && ca_file_inline) + { + in = BIO_new_mem_buf((char *)ca_file_inline, -1); + } + else + { + in = BIO_new_file(ca_file, "r"); + } - if (in) - info_stack = PEM_X509_INFO_read_bio (in, NULL, NULL, NULL); + if (in) + { + info_stack = PEM_X509_INFO_read_bio(in, NULL, NULL, NULL); + } - if (info_stack) + if (info_stack) { - for (i = 0; i < sk_X509_INFO_num (info_stack); i++) + for (i = 0; i < sk_X509_INFO_num(info_stack); i++) { - X509_INFO *info = sk_X509_INFO_value (info_stack, i); - if (info->crl) - X509_STORE_add_crl (store, info->crl); - - if (tls_server && !info->x509) + X509_INFO *info = sk_X509_INFO_value(info_stack, i); + if (info->crl) { - crypto_msg (M_FATAL, "X509 name was missing in TLS mode"); + X509_STORE_add_crl(store, info->crl); } - if (info->x509) + if (tls_server && !info->x509) { - X509_STORE_add_cert (store, info->x509); - added++; + crypto_msg(M_FATAL, "X509 name was missing in TLS mode"); + } - if (!tls_server) - continue; + if (info->x509) + { + X509_STORE_add_cert(store, info->x509); + added++; - /* Use names of CAs as a client CA list */ - if (cert_names == NULL) + if (!tls_server) { - cert_names = sk_X509_NAME_new (sk_x509_name_cmp); - if (!cert_names) continue; } - xn = X509_get_subject_name (info->x509); - if (!xn) - continue; + /* Use names of CAs as a client CA list */ + if (cert_names == NULL) + { + cert_names = sk_X509_NAME_new(sk_x509_name_cmp); + if (!cert_names) + { + continue; + } + } - /* Don't add duplicate CA names */ - if (sk_X509_NAME_find (cert_names, xn) == -1) + xn = X509_get_subject_name(info->x509); + if (!xn) { - xn = X509_NAME_dup (xn); - if (!xn) continue; - sk_X509_NAME_push (cert_names, xn); + } + + /* Don't add duplicate CA names */ + if (sk_X509_NAME_find(cert_names, xn) == -1) + { + xn = X509_NAME_dup(xn); + if (!xn) + { + continue; + } + sk_X509_NAME_push(cert_names, xn); } } - if (tls_server) { - int cnum = sk_X509_NAME_num (cert_names); - if (cnum != (prev + 1)) - { - crypto_msg (M_WARN, - "Cannot load CA certificate file %s (entry %d did not validate)", - np(ca_file), added); - } - prev = cnum; - } + if (tls_server) + { + int cnum = sk_X509_NAME_num(cert_names); + if (cnum != (prev + 1)) + { + crypto_msg(M_WARN, + "Cannot load CA certificate file %s (entry %d did not validate)", + np(ca_file), added); + } + prev = cnum; + } } - sk_X509_INFO_pop_free (info_stack, X509_INFO_free); + sk_X509_INFO_pop_free(info_stack, X509_INFO_free); } - if (tls_server) - SSL_CTX_set_client_CA_list (ctx->ctx, cert_names); + if (tls_server) + { + SSL_CTX_set_client_CA_list(ctx->ctx, cert_names); + } - if (!added) - { - crypto_msg (M_FATAL, - "Cannot load CA certificate file %s (no entries were read)", - np(ca_file)); - } + if (!added) + { + crypto_msg(M_FATAL, + "Cannot load CA certificate file %s (no entries were read)", + np(ca_file)); + } - if (tls_server) { - int cnum = sk_X509_NAME_num (cert_names); - if (cnum != added) - { - crypto_msg (M_FATAL, "Cannot load CA certificate file %s (only %d " - "of %d entries were valid X509 names)", - np(ca_file), cnum, added); - } - } + if (tls_server) + { + int cnum = sk_X509_NAME_num(cert_names); + if (cnum != added) + { + crypto_msg(M_FATAL, "Cannot load CA certificate file %s (only %d " + "of %d entries were valid X509 names)", + np(ca_file), cnum, added); + } + } - if (in) - BIO_free (in); + if (in) + { + BIO_free(in); + } } - /* Set a store for certs (CA & CRL) with a lookup on the "capath" hash directory */ - if (ca_path) + /* Set a store for certs (CA & CRL) with a lookup on the "capath" hash directory */ + if (ca_path) { - lookup = X509_STORE_add_lookup (store, X509_LOOKUP_hash_dir ()); - if (lookup && X509_LOOKUP_add_dir (lookup, ca_path, X509_FILETYPE_PEM)) - msg(M_WARN, "WARNING: experimental option --capath %s", ca_path); - else - crypto_msg (M_FATAL, "Cannot add lookup at --capath %s", ca_path); - X509_STORE_set_flags (store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); + lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir()); + if (lookup && X509_LOOKUP_add_dir(lookup, ca_path, X509_FILETYPE_PEM)) + { + msg(M_WARN, "WARNING: experimental option --capath %s", ca_path); + } + else + { + crypto_msg(M_FATAL, "Cannot add lookup at --capath %s", ca_path); + } + X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); } } void -tls_ctx_load_extra_certs (struct tls_root_ctx *ctx, const char *extra_certs_file, - const char *extra_certs_file_inline - ) +tls_ctx_load_extra_certs(struct tls_root_ctx *ctx, const char *extra_certs_file, + const char *extra_certs_file_inline + ) { - BIO *in; - if (!strcmp (extra_certs_file, INLINE_FILE_TAG) && extra_certs_file_inline) - in = BIO_new_mem_buf ((char *)extra_certs_file_inline, -1); - else - in = BIO_new_file (extra_certs_file, "r"); - - if (in == NULL) - crypto_msg (M_FATAL, "Cannot load extra-certs file: %s", extra_certs_file); - else - tls_ctx_add_extra_certs (ctx, in); - - BIO_free (in); + BIO *in; + if (!strcmp(extra_certs_file, INLINE_FILE_TAG) && extra_certs_file_inline) + { + in = BIO_new_mem_buf((char *)extra_certs_file_inline, -1); + } + else + { + in = BIO_new_file(extra_certs_file, "r"); + } + + if (in == NULL) + { + crypto_msg(M_FATAL, "Cannot load extra-certs file: %s", extra_certs_file); + } + else + { + tls_ctx_add_extra_certs(ctx, in); + } + + BIO_free(in); } /* ************************************** @@ -1148,56 +1313,58 @@ static const int biofp_reopen_interval = 600; /* GLOBAL */ static void close_biofp() { - if (biofp) + if (biofp) { - ASSERT (!fclose (biofp)); - biofp = NULL; + ASSERT(!fclose(biofp)); + biofp = NULL; } } static void open_biofp() { - const time_t current = time (NULL); - const pid_t pid = getpid (); + const time_t current = time(NULL); + const pid_t pid = getpid(); - if (biofp_last_open + biofp_reopen_interval < current) - close_biofp(); - if (!biofp) + if (biofp_last_open + biofp_reopen_interval < current) + { + close_biofp(); + } + if (!biofp) { - char fn[256]; - openvpn_snprintf(fn, sizeof(fn), "bio/%d-%d.log", pid, biofp_toggle); - biofp = fopen (fn, "w"); - ASSERT (biofp); - biofp_last_open = time (NULL); - biofp_toggle ^= 1; + char fn[256]; + openvpn_snprintf(fn, sizeof(fn), "bio/%d-%d.log", pid, biofp_toggle); + biofp = fopen(fn, "w"); + ASSERT(biofp); + biofp_last_open = time(NULL); + biofp_toggle ^= 1; } } static void -bio_debug_data (const char *mode, BIO *bio, const uint8_t *buf, int len, const char *desc) +bio_debug_data(const char *mode, BIO *bio, const uint8_t *buf, int len, const char *desc) { - struct gc_arena gc = gc_new (); - if (len > 0) + struct gc_arena gc = gc_new(); + if (len > 0) { - open_biofp(); - fprintf(biofp, "BIO_%s %s time=" time_format " bio=" ptr_format " len=%d data=%s\n", - mode, desc, time (NULL), (ptr_type)bio, len, format_hex (buf, len, 0, &gc)); - fflush (biofp); + open_biofp(); + fprintf(biofp, "BIO_%s %s time=" time_format " bio=" ptr_format " len=%d data=%s\n", + mode, desc, time(NULL), (ptr_type)bio, len, format_hex(buf, len, 0, &gc)); + fflush(biofp); } - gc_free (&gc); + gc_free(&gc); } static void -bio_debug_oc (const char *mode, BIO *bio) +bio_debug_oc(const char *mode, BIO *bio) { - open_biofp(); - fprintf(biofp, "BIO %s time=" time_format " bio=" ptr_format "\n", - mode, time (NULL), (ptr_type)bio); - fflush (biofp); + open_biofp(); + fprintf(biofp, "BIO %s time=" time_format " bio=" ptr_format "\n", + mode, time(NULL), (ptr_type)bio); + fflush(biofp); } -#endif +#endif /* ifdef BIO_DEBUG */ /* * OpenVPN's interface to SSL/TLS authentication, @@ -1205,64 +1372,65 @@ bio_debug_oc (const char *mode, BIO *bio) * through "memory BIOs". */ static BIO * -getbio (BIO_METHOD * type, const char *desc) +getbio(BIO_METHOD *type, const char *desc) { - BIO *ret; - ret = BIO_new (type); - if (!ret) - crypto_msg (M_FATAL, "Error creating %s BIO", desc); - return ret; + BIO *ret; + ret = BIO_new(type); + if (!ret) + { + crypto_msg(M_FATAL, "Error creating %s BIO", desc); + } + return ret; } /* * Write to an OpenSSL BIO in non-blocking mode. */ static int -bio_write (BIO *bio, const uint8_t *data, int size, const char *desc) +bio_write(BIO *bio, const uint8_t *data, int size, const char *desc) { - int i; - int ret = 0; - ASSERT (size >= 0); - if (size) - { - /* - * Free the L_TLS lock prior to calling BIO routines - * so that foreground thread can still call - * tls_pre_decrypt or tls_pre_encrypt, - * allowing tunnel packet forwarding to continue. - */ + int i; + int ret = 0; + ASSERT(size >= 0); + if (size) + { + /* + * Free the L_TLS lock prior to calling BIO routines + * so that foreground thread can still call + * tls_pre_decrypt or tls_pre_encrypt, + * allowing tunnel packet forwarding to continue. + */ #ifdef BIO_DEBUG - bio_debug_data ("write", bio, data, size, desc); + bio_debug_data("write", bio, data, size, desc); #endif - i = BIO_write (bio, data, size); - - if (i < 0) - { - if (BIO_should_retry (bio)) - { - ; - } - else - { - crypto_msg (D_TLS_ERRORS, "TLS ERROR: BIO write %s error", desc); - ret = -1; - ERR_clear_error (); - } - } - else if (i != size) - { - crypto_msg (D_TLS_ERRORS, "TLS ERROR: BIO write %s incomplete %d/%d", - desc, i, size); - ret = -1; - ERR_clear_error (); - } - else - { /* successful write */ - dmsg (D_HANDSHAKE_VERBOSE, "BIO write %s %d bytes", desc, i); - ret = 1; - } - } - return ret; + i = BIO_write(bio, data, size); + + if (i < 0) + { + if (BIO_should_retry(bio)) + { + } + else + { + crypto_msg(D_TLS_ERRORS, "TLS ERROR: BIO write %s error", desc); + ret = -1; + ERR_clear_error(); + } + } + else if (i != size) + { + crypto_msg(D_TLS_ERRORS, "TLS ERROR: BIO write %s incomplete %d/%d", + desc, i, size); + ret = -1; + ERR_clear_error(); + } + else + { /* successful write */ + dmsg(D_HANDSHAKE_VERBOSE, "BIO write %s %d bytes", desc, i); + ret = 1; + } + } + return ret; } /* @@ -1271,12 +1439,12 @@ bio_write (BIO *bio, const uint8_t *data, int size, const char *desc) */ static void -bio_write_post (const int status, struct buffer *buf) +bio_write_post(const int status, struct buffer *buf) { - if (status == 1) /* success status return from bio_write? */ + if (status == 1) /* success status return from bio_write? */ { - memset (BPTR (buf), 0, BLEN (buf)); /* erase data just written */ - buf->len = 0; + memset(BPTR(buf), 0, BLEN(buf)); /* erase data just written */ + buf->len = 0; } } @@ -1284,183 +1452,191 @@ bio_write_post (const int status, struct buffer *buf) * Read from an OpenSSL BIO in non-blocking mode. */ static int -bio_read (BIO *bio, struct buffer *buf, int maxlen, const char *desc) +bio_read(BIO *bio, struct buffer *buf, int maxlen, const char *desc) { - int i; - int ret = 0; - ASSERT (buf->len >= 0); - if (buf->len) + int i; + int ret = 0; + ASSERT(buf->len >= 0); + if (buf->len) { - ; } - else + else { - int len = buf_forward_capacity (buf); - if (maxlen < len) - len = maxlen; + int len = buf_forward_capacity(buf); + if (maxlen < len) + { + len = maxlen; + } - /* - * BIO_read brackets most of the serious RSA - * key negotiation number crunching. - */ - i = BIO_read (bio, BPTR (buf), len); + /* + * BIO_read brackets most of the serious RSA + * key negotiation number crunching. + */ + i = BIO_read(bio, BPTR(buf), len); - VALGRIND_MAKE_READABLE ((void *) &i, sizeof (i)); + VALGRIND_MAKE_READABLE((void *) &i, sizeof(i)); #ifdef BIO_DEBUG - bio_debug_data ("read", bio, BPTR (buf), i, desc); + bio_debug_data("read", bio, BPTR(buf), i, desc); #endif - if (i < 0) - { - if (BIO_should_retry (bio)) - { - ; - } - else - { - crypto_msg (D_TLS_ERRORS, "TLS_ERROR: BIO read %s error", desc); - buf->len = 0; - ret = -1; - ERR_clear_error (); - } - } - else if (!i) - { - buf->len = 0; - } - else - { /* successful read */ - dmsg (D_HANDSHAKE_VERBOSE, "BIO read %s %d bytes", desc, i); - buf->len = i; - ret = 1; - VALGRIND_MAKE_READABLE ((void *) BPTR (buf), BLEN (buf)); - } - } - return ret; + if (i < 0) + { + if (BIO_should_retry(bio)) + { + } + else + { + crypto_msg(D_TLS_ERRORS, "TLS_ERROR: BIO read %s error", desc); + buf->len = 0; + ret = -1; + ERR_clear_error(); + } + } + else if (!i) + { + buf->len = 0; + } + else + { /* successful read */ + dmsg(D_HANDSHAKE_VERBOSE, "BIO read %s %d bytes", desc, i); + buf->len = i; + ret = 1; + VALGRIND_MAKE_READABLE((void *) BPTR(buf), BLEN(buf)); + } + } + return ret; } void key_state_ssl_init(struct key_state_ssl *ks_ssl, const struct tls_root_ctx *ssl_ctx, bool is_server, struct tls_session *session) { - ASSERT(NULL != ssl_ctx); - ASSERT(ks_ssl); - CLEAR (*ks_ssl); + ASSERT(NULL != ssl_ctx); + ASSERT(ks_ssl); + CLEAR(*ks_ssl); - ks_ssl->ssl = SSL_new (ssl_ctx->ctx); - if (!ks_ssl->ssl) - crypto_msg (M_FATAL, "SSL_new failed"); + ks_ssl->ssl = SSL_new(ssl_ctx->ctx); + if (!ks_ssl->ssl) + { + crypto_msg(M_FATAL, "SSL_new failed"); + } - /* put session * in ssl object so we can access it - from verify callback*/ - SSL_set_ex_data (ks_ssl->ssl, mydata_index, session); + /* put session * in ssl object so we can access it + * from verify callback*/ + SSL_set_ex_data(ks_ssl->ssl, mydata_index, session); - ks_ssl->ssl_bio = getbio (BIO_f_ssl (), "ssl_bio"); - ks_ssl->ct_in = getbio (BIO_s_mem (), "ct_in"); - ks_ssl->ct_out = getbio (BIO_s_mem (), "ct_out"); + ks_ssl->ssl_bio = getbio(BIO_f_ssl(), "ssl_bio"); + ks_ssl->ct_in = getbio(BIO_s_mem(), "ct_in"); + ks_ssl->ct_out = getbio(BIO_s_mem(), "ct_out"); #ifdef BIO_DEBUG - bio_debug_oc ("open ssl_bio", ks_ssl->ssl_bio); - bio_debug_oc ("open ct_in", ks_ssl->ct_in); - bio_debug_oc ("open ct_out", ks_ssl->ct_out); + bio_debug_oc("open ssl_bio", ks_ssl->ssl_bio); + bio_debug_oc("open ct_in", ks_ssl->ct_in); + bio_debug_oc("open ct_out", ks_ssl->ct_out); #endif - if (is_server) - SSL_set_accept_state (ks_ssl->ssl); - else - SSL_set_connect_state (ks_ssl->ssl); + if (is_server) + { + SSL_set_accept_state(ks_ssl->ssl); + } + else + { + SSL_set_connect_state(ks_ssl->ssl); + } - SSL_set_bio (ks_ssl->ssl, ks_ssl->ct_in, ks_ssl->ct_out); - BIO_set_ssl (ks_ssl->ssl_bio, ks_ssl->ssl, BIO_NOCLOSE); + SSL_set_bio(ks_ssl->ssl, ks_ssl->ct_in, ks_ssl->ct_out); + BIO_set_ssl(ks_ssl->ssl_bio, ks_ssl->ssl, BIO_NOCLOSE); } -void key_state_ssl_free(struct key_state_ssl *ks_ssl) +void +key_state_ssl_free(struct key_state_ssl *ks_ssl) { - if (ks_ssl->ssl) { + if (ks_ssl->ssl) + { #ifdef BIO_DEBUG - bio_debug_oc ("close ssl_bio", ks_ssl->ssl_bio); - bio_debug_oc ("close ct_in", ks_ssl->ct_in); - bio_debug_oc ("close ct_out", ks_ssl->ct_out); + bio_debug_oc("close ssl_bio", ks_ssl->ssl_bio); + bio_debug_oc("close ct_in", ks_ssl->ct_in); + bio_debug_oc("close ct_out", ks_ssl->ct_out); #endif - BIO_free_all(ks_ssl->ssl_bio); - SSL_free (ks_ssl->ssl); - } + BIO_free_all(ks_ssl->ssl_bio); + SSL_free(ks_ssl->ssl); + } } int -key_state_write_plaintext (struct key_state_ssl *ks_ssl, struct buffer *buf) +key_state_write_plaintext(struct key_state_ssl *ks_ssl, struct buffer *buf) { - int ret = 0; - perf_push (PERF_BIO_WRITE_PLAINTEXT); + int ret = 0; + perf_push(PERF_BIO_WRITE_PLAINTEXT); #ifdef ENABLE_CRYPTO_OPENSSL - ASSERT (NULL != ks_ssl); + ASSERT(NULL != ks_ssl); - ret = bio_write (ks_ssl->ssl_bio, BPTR(buf), BLEN(buf), - "tls_write_plaintext"); - bio_write_post (ret, buf); + ret = bio_write(ks_ssl->ssl_bio, BPTR(buf), BLEN(buf), + "tls_write_plaintext"); + bio_write_post(ret, buf); #endif /* ENABLE_CRYPTO_OPENSSL */ - perf_pop (); - return ret; + perf_pop(); + return ret; } int -key_state_write_plaintext_const (struct key_state_ssl *ks_ssl, const uint8_t *data, int len) +key_state_write_plaintext_const(struct key_state_ssl *ks_ssl, const uint8_t *data, int len) { - int ret = 0; - perf_push (PERF_BIO_WRITE_PLAINTEXT); + int ret = 0; + perf_push(PERF_BIO_WRITE_PLAINTEXT); - ASSERT (NULL != ks_ssl); + ASSERT(NULL != ks_ssl); - ret = bio_write (ks_ssl->ssl_bio, data, len, "tls_write_plaintext_const"); + ret = bio_write(ks_ssl->ssl_bio, data, len, "tls_write_plaintext_const"); - perf_pop (); - return ret; + perf_pop(); + return ret; } int -key_state_read_ciphertext (struct key_state_ssl *ks_ssl, struct buffer *buf, - int maxlen) +key_state_read_ciphertext(struct key_state_ssl *ks_ssl, struct buffer *buf, + int maxlen) { - int ret = 0; - perf_push (PERF_BIO_READ_CIPHERTEXT); + int ret = 0; + perf_push(PERF_BIO_READ_CIPHERTEXT); - ASSERT (NULL != ks_ssl); + ASSERT(NULL != ks_ssl); - ret = bio_read (ks_ssl->ct_out, buf, maxlen, "tls_read_ciphertext"); + ret = bio_read(ks_ssl->ct_out, buf, maxlen, "tls_read_ciphertext"); - perf_pop (); - return ret; + perf_pop(); + return ret; } int -key_state_write_ciphertext (struct key_state_ssl *ks_ssl, struct buffer *buf) +key_state_write_ciphertext(struct key_state_ssl *ks_ssl, struct buffer *buf) { - int ret = 0; - perf_push (PERF_BIO_WRITE_CIPHERTEXT); + int ret = 0; + perf_push(PERF_BIO_WRITE_CIPHERTEXT); - ASSERT (NULL != ks_ssl); + ASSERT(NULL != ks_ssl); - ret = bio_write (ks_ssl->ct_in, BPTR(buf), BLEN(buf), "tls_write_ciphertext"); - bio_write_post (ret, buf); + ret = bio_write(ks_ssl->ct_in, BPTR(buf), BLEN(buf), "tls_write_ciphertext"); + bio_write_post(ret, buf); - perf_pop (); - return ret; + perf_pop(); + return ret; } int -key_state_read_plaintext (struct key_state_ssl *ks_ssl, struct buffer *buf, - int maxlen) +key_state_read_plaintext(struct key_state_ssl *ks_ssl, struct buffer *buf, + int maxlen) { - int ret = 0; - perf_push (PERF_BIO_READ_PLAINTEXT); + int ret = 0; + perf_push(PERF_BIO_READ_PLAINTEXT); - ASSERT (NULL != ks_ssl); + ASSERT(NULL != ks_ssl); - ret = bio_read (ks_ssl->ssl_bio, buf, maxlen, "tls_read_plaintext"); + ret = bio_read(ks_ssl->ssl_bio, buf, maxlen, "tls_read_plaintext"); - perf_pop (); - return ret; + perf_pop(); + return ret; } /* ************************************** @@ -1471,84 +1647,91 @@ key_state_read_plaintext (struct key_state_ssl *ks_ssl, struct buffer *buf, * ***************************************/ void -print_details (struct key_state_ssl * ks_ssl, const char *prefix) +print_details(struct key_state_ssl *ks_ssl, const char *prefix) { - const SSL_CIPHER *ciph; - X509 *cert; - char s1[256]; - char s2[256]; - - s1[0] = s2[0] = 0; - ciph = SSL_get_current_cipher (ks_ssl->ssl); - openvpn_snprintf (s1, sizeof (s1), "%s %s, cipher %s %s", - prefix, - SSL_get_version (ks_ssl->ssl), - SSL_CIPHER_get_version (ciph), - SSL_CIPHER_get_name (ciph)); - cert = SSL_get_peer_certificate (ks_ssl->ssl); - if (cert != NULL) - { - EVP_PKEY *pkey = X509_get_pubkey (cert); - if (pkey != NULL) - { - if (pkey->type == EVP_PKEY_RSA && pkey->pkey.rsa != NULL - && pkey->pkey.rsa->n != NULL) - { - openvpn_snprintf (s2, sizeof (s2), ", %d bit RSA", - BN_num_bits (pkey->pkey.rsa->n)); - } - else if (pkey->type == EVP_PKEY_DSA && pkey->pkey.dsa != NULL - && pkey->pkey.dsa->p != NULL) - { - openvpn_snprintf (s2, sizeof (s2), ", %d bit DSA", - BN_num_bits (pkey->pkey.dsa->p)); - } - EVP_PKEY_free (pkey); - } - X509_free (cert); - } - /* The SSL API does not allow us to look at temporary RSA/DH keys, - * otherwise we should print their lengths too */ - msg (D_HANDSHAKE, "%s%s", s1, s2); + const SSL_CIPHER *ciph; + X509 *cert; + char s1[256]; + char s2[256]; + + s1[0] = s2[0] = 0; + ciph = SSL_get_current_cipher(ks_ssl->ssl); + openvpn_snprintf(s1, sizeof(s1), "%s %s, cipher %s %s", + prefix, + SSL_get_version(ks_ssl->ssl), + SSL_CIPHER_get_version(ciph), + SSL_CIPHER_get_name(ciph)); + cert = SSL_get_peer_certificate(ks_ssl->ssl); + if (cert != NULL) + { + EVP_PKEY *pkey = X509_get_pubkey(cert); + if (pkey != NULL) + { + if (pkey->type == EVP_PKEY_RSA && pkey->pkey.rsa != NULL + && pkey->pkey.rsa->n != NULL) + { + openvpn_snprintf(s2, sizeof(s2), ", %d bit RSA", + BN_num_bits(pkey->pkey.rsa->n)); + } + else if (pkey->type == EVP_PKEY_DSA && pkey->pkey.dsa != NULL + && pkey->pkey.dsa->p != NULL) + { + openvpn_snprintf(s2, sizeof(s2), ", %d bit DSA", + BN_num_bits(pkey->pkey.dsa->p)); + } + EVP_PKEY_free(pkey); + } + X509_free(cert); + } + /* The SSL API does not allow us to look at temporary RSA/DH keys, + * otherwise we should print their lengths too */ + msg(D_HANDSHAKE, "%s%s", s1, s2); } void -show_available_tls_ciphers (const char *cipher_list) +show_available_tls_ciphers(const char *cipher_list) { - struct tls_root_ctx tls_ctx; - SSL *ssl; - const char *cipher_name; - const tls_cipher_name_pair *pair; - int priority = 0; - - tls_ctx.ctx = SSL_CTX_new (SSLv23_method ()); - if (!tls_ctx.ctx) - crypto_msg (M_FATAL, "Cannot create SSL_CTX object"); + struct tls_root_ctx tls_ctx; + SSL *ssl; + const char *cipher_name; + const tls_cipher_name_pair *pair; + int priority = 0; + + tls_ctx.ctx = SSL_CTX_new(SSLv23_method()); + if (!tls_ctx.ctx) + { + crypto_msg(M_FATAL, "Cannot create SSL_CTX object"); + } - ssl = SSL_new (tls_ctx.ctx); - if (!ssl) - crypto_msg (M_FATAL, "Cannot create SSL object"); + ssl = SSL_new(tls_ctx.ctx); + if (!ssl) + { + crypto_msg(M_FATAL, "Cannot create SSL object"); + } - tls_ctx_restrict_ciphers(&tls_ctx, cipher_list); + tls_ctx_restrict_ciphers(&tls_ctx, cipher_list); - printf ("Available TLS Ciphers,\n"); - printf ("listed in order of preference:\n\n"); - while ((cipher_name = SSL_get_cipher_list (ssl, priority++))) + printf("Available TLS Ciphers,\n"); + printf("listed in order of preference:\n\n"); + while ((cipher_name = SSL_get_cipher_list(ssl, priority++))) { - pair = tls_get_cipher_name_pair(cipher_name, strlen(cipher_name)); + pair = tls_get_cipher_name_pair(cipher_name, strlen(cipher_name)); - if (NULL == pair) { - // No translation found, print warning - printf ("%s (No IANA name known to OpenVPN, use OpenSSL name.)\n", cipher_name); - } else { - printf ("%s\n", pair->iana_name); - } + if (NULL == pair) + { + /* No translation found, print warning */ + printf("%s (No IANA name known to OpenVPN, use OpenSSL name.)\n", cipher_name); + } + else + { + printf("%s\n", pair->iana_name); + } } - printf ("\n" SHOW_TLS_CIPHER_LIST_WARNING); + printf("\n" SHOW_TLS_CIPHER_LIST_WARNING); - SSL_free (ssl); - SSL_CTX_free (tls_ctx.ctx); + SSL_free(ssl); + SSL_CTX_free(tls_ctx.ctx); } /* @@ -1559,54 +1742,61 @@ void show_available_curves() { #ifndef OPENSSL_NO_EC - EC_builtin_curve *curves = NULL; - size_t crv_len = 0; - size_t n = 0; - - crv_len = EC_get_builtin_curves(NULL, 0); - ALLOC_ARRAY(curves, EC_builtin_curve, crv_len); - if (EC_get_builtin_curves(curves, crv_len)) - { - printf ("Available Elliptic curves:\n"); - for (n = 0; n < crv_len; n++) - { - const char *sname; - sname = OBJ_nid2sn(curves[n].nid); - if (sname == NULL) sname = ""; - - printf("%s\n", sname); - } - } - else - { - crypto_msg (M_FATAL, "Cannot get list of builtin curves"); - } - free(curves); -#else - msg (M_WARN, "Your OpenSSL library was built without elliptic curve support. " - "No curves available."); -#endif + EC_builtin_curve *curves = NULL; + size_t crv_len = 0; + size_t n = 0; + + crv_len = EC_get_builtin_curves(NULL, 0); + ALLOC_ARRAY(curves, EC_builtin_curve, crv_len); + if (EC_get_builtin_curves(curves, crv_len)) + { + printf("Available Elliptic curves:\n"); + for (n = 0; n < crv_len; n++) + { + const char *sname; + sname = OBJ_nid2sn(curves[n].nid); + if (sname == NULL) + { + sname = ""; + } + + printf("%s\n", sname); + } + } + else + { + crypto_msg(M_FATAL, "Cannot get list of builtin curves"); + } + free(curves); +#else /* ifndef OPENSSL_NO_EC */ + msg(M_WARN, "Your OpenSSL library was built without elliptic curve support. " + "No curves available."); +#endif /* ifndef OPENSSL_NO_EC */ } void -get_highest_preference_tls_cipher (char *buf, int size) +get_highest_preference_tls_cipher(char *buf, int size) { - SSL_CTX *ctx; - SSL *ssl; - const char *cipher_name; - - ctx = SSL_CTX_new (SSLv23_method ()); - if (!ctx) - crypto_msg (M_FATAL, "Cannot create SSL_CTX object"); - ssl = SSL_new (ctx); - if (!ssl) - crypto_msg (M_FATAL, "Cannot create SSL object"); - - cipher_name = SSL_get_cipher_list (ssl, 0); - strncpynt (buf, cipher_name, size); - - SSL_free (ssl); - SSL_CTX_free (ctx); + SSL_CTX *ctx; + SSL *ssl; + const char *cipher_name; + + ctx = SSL_CTX_new(SSLv23_method()); + if (!ctx) + { + crypto_msg(M_FATAL, "Cannot create SSL_CTX object"); + } + ssl = SSL_new(ctx); + if (!ssl) + { + crypto_msg(M_FATAL, "Cannot create SSL object"); + } + + cipher_name = SSL_get_cipher_list(ssl, 0); + strncpynt(buf, cipher_name, size); + + SSL_free(ssl); + SSL_CTX_free(ctx); } const char * diff --git a/src/openvpn/ssl_openssl.h b/src/openvpn/ssl_openssl.h index 115ac43eef7..5f7771366ba 100644 --- a/src/openvpn/ssl_openssl.h +++ b/src/openvpn/ssl_openssl.h @@ -40,7 +40,7 @@ * resumption (and the accompanying SSL_OP_NO_TICKET flag). */ #ifndef SSL_OP_NO_TICKET -# define SSL_OP_NO_TICKET 0 +#define SSL_OP_NO_TICKET 0 #endif /** @@ -54,10 +54,10 @@ struct tls_root_ctx { }; struct key_state_ssl { - SSL *ssl; /* SSL object -- new obj created for each new key */ - BIO *ssl_bio; /* read/write plaintext from here */ - BIO *ct_in; /* write ciphertext to here */ - BIO *ct_out; /* read ciphertext from here */ + SSL *ssl; /* SSL object -- new obj created for each new key */ + BIO *ssl_bio; /* read/write plaintext from here */ + BIO *ct_in; /* write ciphertext to here */ + BIO *ct_out; /* read ciphertext from here */ }; /** @@ -66,6 +66,6 @@ struct key_state_ssl { */ extern int mydata_index; /* GLOBAL */ -void openssl_set_mydata_index (void); +void openssl_set_mydata_index(void); #endif /* SSL_OPENSSL_H_ */ diff --git a/src/openvpn/ssl_verify.c b/src/openvpn/ssl_verify.c index 4328828bed2..54a34166210 100644 --- a/src/openvpn/ssl_verify.c +++ b/src/openvpn/ssl_verify.c @@ -58,36 +58,40 @@ #define COMMON_NAME_CHAR_CLASS (CC_ALNUM|CC_UNDERBAR|CC_DASH|CC_DOT|CC_AT|CC_SLASH) static void -string_mod_remap_name (char *str, const unsigned int restrictive_flags) +string_mod_remap_name(char *str, const unsigned int restrictive_flags) { - if (compat_flag (COMPAT_FLAG_QUERY | COMPAT_NAMES) - && !compat_flag (COMPAT_FLAG_QUERY | COMPAT_NO_NAME_REMAPPING)) - string_mod (str, restrictive_flags, 0, '_'); - else - string_mod (str, CC_PRINT, CC_CRLF, '_'); + if (compat_flag(COMPAT_FLAG_QUERY | COMPAT_NAMES) + && !compat_flag(COMPAT_FLAG_QUERY | COMPAT_NO_NAME_REMAPPING)) + { + string_mod(str, restrictive_flags, 0, '_'); + } + else + { + string_mod(str, CC_PRINT, CC_CRLF, '_'); + } } /* * Export the untrusted IP address and port to the environment */ static void -setenv_untrusted (struct tls_session *session) +setenv_untrusted(struct tls_session *session) { - setenv_link_socket_actual (session->opt->es, "untrusted", &session->untrusted_addr, SA_IP_PORT); + setenv_link_socket_actual(session->opt->es, "untrusted", &session->untrusted_addr, SA_IP_PORT); } /* * Remove authenticated state from all sessions in the given tunnel */ static void -tls_deauthenticate (struct tls_multi *multi) +tls_deauthenticate(struct tls_multi *multi) { - if (multi) + if (multi) { - int i, j; - for (i = 0; i < TM_SIZE; ++i) - for (j = 0; j < KS_SIZE; ++j) - multi->session[i].key[j].authenticated = false; + int i, j; + for (i = 0; i < TM_SIZE; ++i) + for (j = 0; j < KS_SIZE; ++j) + multi->session[i].key[j].authenticated = false; } } @@ -95,28 +99,32 @@ tls_deauthenticate (struct tls_multi *multi) * Set the given session's common_name */ static void -set_common_name (struct tls_session *session, const char *common_name) +set_common_name(struct tls_session *session, const char *common_name) { - if (session->common_name) + if (session->common_name) { - free (session->common_name); - session->common_name = NULL; + free(session->common_name); + session->common_name = NULL; #ifdef ENABLE_PF - session->common_name_hashval = 0; + session->common_name_hashval = 0; #endif } - if (common_name) + if (common_name) { - /* FIXME: Last alloc will never be freed */ - session->common_name = string_alloc (common_name, NULL); + /* FIXME: Last alloc will never be freed */ + session->common_name = string_alloc(common_name, NULL); #ifdef ENABLE_PF - { - const uint32_t len = (uint32_t) strlen (common_name); - if (len) - session->common_name_hashval = hash_func ((const uint8_t*)common_name, len+1, 0); - else - session->common_name_hashval = 0; - } + { + const uint32_t len = (uint32_t) strlen(common_name); + if (len) + { + session->common_name_hashval = hash_func((const uint8_t *)common_name, len+1, 0); + } + else + { + session->common_name_hashval = 0; + } + } #endif } } @@ -127,174 +135,208 @@ set_common_name (struct tls_session *session, const char *common_name) * null is false. */ const char * -tls_common_name (const struct tls_multi *multi, const bool null) +tls_common_name(const struct tls_multi *multi, const bool null) { - const char *ret = NULL; - if (multi) - ret = multi->session[TM_ACTIVE].common_name; - if (ret && strlen (ret)) - return ret; - else if (null) - return NULL; - else - return "UNDEF"; + const char *ret = NULL; + if (multi) + { + ret = multi->session[TM_ACTIVE].common_name; + } + if (ret && strlen(ret)) + { + return ret; + } + else if (null) + { + return NULL; + } + else + { + return "UNDEF"; + } } /* * Lock the common name for the given tunnel. */ void -tls_lock_common_name (struct tls_multi *multi) +tls_lock_common_name(struct tls_multi *multi) { - const char *cn = multi->session[TM_ACTIVE].common_name; - if (cn && !multi->locked_cn) - multi->locked_cn = string_alloc (cn, NULL); + const char *cn = multi->session[TM_ACTIVE].common_name; + if (cn && !multi->locked_cn) + { + multi->locked_cn = string_alloc(cn, NULL); + } } /* * Lock the username for the given tunnel */ static bool -tls_lock_username (struct tls_multi *multi, const char *username) +tls_lock_username(struct tls_multi *multi, const char *username) { - if (multi->locked_username) + if (multi->locked_username) { - if (!username || strcmp (username, multi->locked_username)) - { - msg (D_TLS_ERRORS, "TLS Auth Error: username attempted to change from '%s' to '%s' -- tunnel disabled", - multi->locked_username, - np(username)); + if (!username || strcmp(username, multi->locked_username)) + { + msg(D_TLS_ERRORS, "TLS Auth Error: username attempted to change from '%s' to '%s' -- tunnel disabled", + multi->locked_username, + np(username)); - /* disable the tunnel */ - tls_deauthenticate (multi); - return false; - } + /* disable the tunnel */ + tls_deauthenticate(multi); + return false; + } } - else + else { - if (username) - multi->locked_username = string_alloc (username, NULL); + if (username) + { + multi->locked_username = string_alloc(username, NULL); + } } - return true; + return true; } const char * -tls_username (const struct tls_multi *multi, const bool null) +tls_username(const struct tls_multi *multi, const bool null) { - const char *ret = NULL; - if (multi) - ret = multi->locked_username; - if (ret && strlen (ret)) - return ret; - else if (null) - return NULL; - else - return "UNDEF"; + const char *ret = NULL; + if (multi) + { + ret = multi->locked_username; + } + if (ret && strlen(ret)) + { + return ret; + } + else if (null) + { + return NULL; + } + else + { + return "UNDEF"; + } } void -cert_hash_remember (struct tls_session *session, const int error_depth, - const struct buffer *cert_hash) +cert_hash_remember(struct tls_session *session, const int error_depth, + const struct buffer *cert_hash) { - if (error_depth >= 0 && error_depth < MAX_CERT_DEPTH) + if (error_depth >= 0 && error_depth < MAX_CERT_DEPTH) { - if (!session->cert_hash_set) - { - ALLOC_OBJ_CLEAR (session->cert_hash_set, struct cert_hash_set); - } - if (!session->cert_hash_set->ch[error_depth]) - { - ALLOC_OBJ (session->cert_hash_set->ch[error_depth], struct cert_hash); - } + if (!session->cert_hash_set) + { + ALLOC_OBJ_CLEAR(session->cert_hash_set, struct cert_hash_set); + } + if (!session->cert_hash_set->ch[error_depth]) + { + ALLOC_OBJ(session->cert_hash_set->ch[error_depth], struct cert_hash); + } - struct cert_hash *ch = session->cert_hash_set->ch[error_depth]; - ASSERT (sizeof (ch->sha256_hash) == BLEN (cert_hash)); - memcpy (ch->sha256_hash, BPTR (cert_hash), sizeof (ch->sha256_hash)); + struct cert_hash *ch = session->cert_hash_set->ch[error_depth]; + ASSERT(sizeof(ch->sha256_hash) == BLEN(cert_hash)); + memcpy(ch->sha256_hash, BPTR(cert_hash), sizeof(ch->sha256_hash)); } } void -cert_hash_free (struct cert_hash_set *chs) +cert_hash_free(struct cert_hash_set *chs) { - if (chs) + if (chs) { - int i; - for (i = 0; i < MAX_CERT_DEPTH; ++i) - free (chs->ch[i]); - free (chs); + int i; + for (i = 0; i < MAX_CERT_DEPTH; ++i) + free(chs->ch[i]); + free(chs); } } bool -cert_hash_compare (const struct cert_hash_set *chs1, const struct cert_hash_set *chs2) +cert_hash_compare(const struct cert_hash_set *chs1, const struct cert_hash_set *chs2) { - if (chs1 && chs2) - { - int i; - for (i = 0; i < MAX_CERT_DEPTH; ++i) - { - const struct cert_hash *ch1 = chs1->ch[i]; - const struct cert_hash *ch2 = chs2->ch[i]; - - if (!ch1 && !ch2) - continue; - else if (ch1 && ch2 && !memcmp (ch1->sha256_hash, ch2->sha256_hash, - sizeof(ch1->sha256_hash))) - continue; - else - return false; - } - return true; - } - else if (!chs1 && !chs2) - return true; - else - return false; + if (chs1 && chs2) + { + int i; + for (i = 0; i < MAX_CERT_DEPTH; ++i) + { + const struct cert_hash *ch1 = chs1->ch[i]; + const struct cert_hash *ch2 = chs2->ch[i]; + + if (!ch1 && !ch2) + { + continue; + } + else if (ch1 && ch2 && !memcmp(ch1->sha256_hash, ch2->sha256_hash, + sizeof(ch1->sha256_hash))) + { + continue; + } + else + { + return false; + } + } + return true; + } + else if (!chs1 && !chs2) + { + return true; + } + else + { + return false; + } } static struct cert_hash_set * -cert_hash_copy (const struct cert_hash_set *chs) +cert_hash_copy(const struct cert_hash_set *chs) { - struct cert_hash_set *dest = NULL; - if (chs) - { - int i; - ALLOC_OBJ_CLEAR (dest, struct cert_hash_set); - for (i = 0; i < MAX_CERT_DEPTH; ++i) - { - const struct cert_hash *ch = chs->ch[i]; - if (ch) - { - ALLOC_OBJ (dest->ch[i], struct cert_hash); - memcpy (dest->ch[i]->sha256_hash, ch->sha256_hash, - sizeof(dest->ch[i]->sha256_hash)); - } - } - } - return dest; + struct cert_hash_set *dest = NULL; + if (chs) + { + int i; + ALLOC_OBJ_CLEAR(dest, struct cert_hash_set); + for (i = 0; i < MAX_CERT_DEPTH; ++i) + { + const struct cert_hash *ch = chs->ch[i]; + if (ch) + { + ALLOC_OBJ(dest->ch[i], struct cert_hash); + memcpy(dest->ch[i]->sha256_hash, ch->sha256_hash, + sizeof(dest->ch[i]->sha256_hash)); + } + } + } + return dest; } void -tls_lock_cert_hash_set (struct tls_multi *multi) +tls_lock_cert_hash_set(struct tls_multi *multi) { - const struct cert_hash_set *chs = multi->session[TM_ACTIVE].cert_hash_set; - if (chs && !multi->locked_cert_hash_set) - multi->locked_cert_hash_set = cert_hash_copy (chs); + const struct cert_hash_set *chs = multi->session[TM_ACTIVE].cert_hash_set; + if (chs && !multi->locked_cert_hash_set) + { + multi->locked_cert_hash_set = cert_hash_copy(chs); + } } /* * Returns the string associated with the given certificate type. */ static const char * -print_nsCertType (int type) +print_nsCertType(int type) { - switch (type) + switch (type) { - case NS_CERT_CHECK_SERVER: - return "SERVER"; - case NS_CERT_CHECK_CLIENT: - return "CLIENT"; - default: - return "?"; + case NS_CERT_CHECK_SERVER: + return "SERVER"; + + case NS_CERT_CHECK_CLIENT: + return "CLIENT"; + + default: + return "?"; } } @@ -308,72 +350,74 @@ print_nsCertType (int type) */ static result_t verify_peer_cert(const struct tls_options *opt, openvpn_x509_cert_t *peer_cert, - const char *subject, const char *common_name) + const char *subject, const char *common_name) { - /* verify certificate nsCertType */ - if (opt->ns_cert_type != NS_CERT_CHECK_NONE) - { - if (SUCCESS == x509_verify_ns_cert_type (peer_cert, opt->ns_cert_type)) - { - msg (D_HANDSHAKE, "VERIFY OK: nsCertType=%s", - print_nsCertType (opt->ns_cert_type)); - } - else - { - msg (D_HANDSHAKE, "VERIFY nsCertType ERROR: %s, require nsCertType=%s", - subject, print_nsCertType (opt->ns_cert_type)); - return FAILURE; /* Reject connection */ - } - } - - /* verify certificate ku */ - if (opt->remote_cert_ku[0] != 0) - { - if (SUCCESS == x509_verify_cert_ku (peer_cert, opt->remote_cert_ku, MAX_PARMS)) - { - msg (D_HANDSHAKE, "VERIFY KU OK"); - } + /* verify certificate nsCertType */ + if (opt->ns_cert_type != NS_CERT_CHECK_NONE) + { + if (SUCCESS == x509_verify_ns_cert_type(peer_cert, opt->ns_cert_type)) + { + msg(D_HANDSHAKE, "VERIFY OK: nsCertType=%s", + print_nsCertType(opt->ns_cert_type)); + } + else + { + msg(D_HANDSHAKE, "VERIFY nsCertType ERROR: %s, require nsCertType=%s", + subject, print_nsCertType(opt->ns_cert_type)); + return FAILURE; /* Reject connection */ + } + } + + /* verify certificate ku */ + if (opt->remote_cert_ku[0] != 0) + { + if (SUCCESS == x509_verify_cert_ku(peer_cert, opt->remote_cert_ku, MAX_PARMS)) + { + msg(D_HANDSHAKE, "VERIFY KU OK"); + } + else + { + msg(D_HANDSHAKE, "VERIFY KU ERROR"); + return FAILURE; /* Reject connection */ + } + } + + /* verify certificate eku */ + if (opt->remote_cert_eku != NULL) + { + if (SUCCESS == x509_verify_cert_eku(peer_cert, opt->remote_cert_eku)) + { + msg(D_HANDSHAKE, "VERIFY EKU OK"); + } else { - msg (D_HANDSHAKE, "VERIFY KU ERROR"); - return FAILURE; /* Reject connection */ - } + msg(D_HANDSHAKE, "VERIFY EKU ERROR"); + return FAILURE; /* Reject connection */ + } } - /* verify certificate eku */ - if (opt->remote_cert_eku != NULL) + /* verify X509 name or username against --verify-x509-[user]name */ + if (opt->verify_x509_type != VERIFY_X509_NONE) { - if (SUCCESS == x509_verify_cert_eku (peer_cert, opt->remote_cert_eku)) + if ( (opt->verify_x509_type == VERIFY_X509_SUBJECT_DN + && strcmp(opt->verify_x509_name, subject) == 0) + || (opt->verify_x509_type == VERIFY_X509_SUBJECT_RDN + && strcmp(opt->verify_x509_name, common_name) == 0) + || (opt->verify_x509_type == VERIFY_X509_SUBJECT_RDN_PREFIX + && strncmp(opt->verify_x509_name, common_name, + strlen(opt->verify_x509_name)) == 0) ) { - msg (D_HANDSHAKE, "VERIFY EKU OK"); - } - else - { - msg (D_HANDSHAKE, "VERIFY EKU ERROR"); - return FAILURE; /* Reject connection */ - } - } - - /* verify X509 name or username against --verify-x509-[user]name */ - if (opt->verify_x509_type != VERIFY_X509_NONE) - { - if ( (opt->verify_x509_type == VERIFY_X509_SUBJECT_DN - && strcmp (opt->verify_x509_name, subject) == 0) - || (opt->verify_x509_type == VERIFY_X509_SUBJECT_RDN - && strcmp (opt->verify_x509_name, common_name) == 0) - || (opt->verify_x509_type == VERIFY_X509_SUBJECT_RDN_PREFIX - && strncmp (opt->verify_x509_name, common_name, - strlen (opt->verify_x509_name)) == 0) ) - msg (D_HANDSHAKE, "VERIFY X509NAME OK: %s", subject); - else - { - msg (D_HANDSHAKE, "VERIFY X509NAME ERROR: %s, must be %s", - subject, opt->verify_x509_name); - return FAILURE; /* Reject connection */ - } - } - - return SUCCESS; + msg(D_HANDSHAKE, "VERIFY X509NAME OK: %s", subject); + } + else + { + msg(D_HANDSHAKE, "VERIFY X509NAME ERROR: %s, must be %s", + subject, opt->verify_x509_name); + return FAILURE; /* Reject connection */ + } + } + + return SUCCESS; } /* @@ -382,55 +426,59 @@ verify_peer_cert(const struct tls_options *opt, openvpn_x509_cert_t *peer_cert, */ static void verify_cert_set_env(struct env_set *es, openvpn_x509_cert_t *peer_cert, int cert_depth, - const char *subject, const char *common_name, - const struct x509_track *x509_track) + const char *subject, const char *common_name, + const struct x509_track *x509_track) { - char envname[64]; - char *serial = NULL; - struct gc_arena gc = gc_new (); + char envname[64]; + char *serial = NULL; + struct gc_arena gc = gc_new(); - /* Save X509 fields in environment */ - if (x509_track) - x509_setenv_track (x509_track, es, cert_depth, peer_cert); - else - x509_setenv (es, cert_depth, peer_cert); + /* Save X509 fields in environment */ + if (x509_track) + { + x509_setenv_track(x509_track, es, cert_depth, peer_cert); + } + else + { + x509_setenv(es, cert_depth, peer_cert); + } - /* export subject name string as environmental variable */ - openvpn_snprintf (envname, sizeof(envname), "tls_id_%d", cert_depth); - setenv_str (es, envname, subject); + /* export subject name string as environmental variable */ + openvpn_snprintf(envname, sizeof(envname), "tls_id_%d", cert_depth); + setenv_str(es, envname, subject); #if 0 - /* export common name string as environmental variable */ - openvpn_snprintf (envname, sizeof(envname), "tls_common_name_%d", cert_depth); - setenv_str (es, envname, common_name); + /* export common name string as environmental variable */ + openvpn_snprintf(envname, sizeof(envname), "tls_common_name_%d", cert_depth); + setenv_str(es, envname, common_name); #endif - /* export X509 cert fingerprints */ - { - struct buffer sha1 = x509_get_sha1_fingerprint(peer_cert, &gc); - struct buffer sha256 = x509_get_sha256_fingerprint(peer_cert, &gc); + /* export X509 cert fingerprints */ + { + struct buffer sha1 = x509_get_sha1_fingerprint(peer_cert, &gc); + struct buffer sha256 = x509_get_sha256_fingerprint(peer_cert, &gc); - openvpn_snprintf (envname, sizeof(envname), "tls_digest_%d", cert_depth); - setenv_str (es, envname, - format_hex_ex(BPTR(&sha1), BLEN(&sha1), 0, 1, ":", &gc)); + openvpn_snprintf(envname, sizeof(envname), "tls_digest_%d", cert_depth); + setenv_str(es, envname, + format_hex_ex(BPTR(&sha1), BLEN(&sha1), 0, 1, ":", &gc)); - openvpn_snprintf (envname, sizeof(envname), "tls_digest_sha256_%d", - cert_depth); - setenv_str (es, envname, - format_hex_ex(BPTR(&sha256), BLEN(&sha256), 0, 1, ":", &gc)); - } + openvpn_snprintf(envname, sizeof(envname), "tls_digest_sha256_%d", + cert_depth); + setenv_str(es, envname, + format_hex_ex(BPTR(&sha256), BLEN(&sha256), 0, 1, ":", &gc)); + } - /* export serial number as environmental variable */ - serial = backend_x509_get_serial(peer_cert, &gc); - openvpn_snprintf (envname, sizeof(envname), "tls_serial_%d", cert_depth); - setenv_str (es, envname, serial); + /* export serial number as environmental variable */ + serial = backend_x509_get_serial(peer_cert, &gc); + openvpn_snprintf(envname, sizeof(envname), "tls_serial_%d", cert_depth); + setenv_str(es, envname, serial); - /* export serial number in hex as environmental variable */ - serial = backend_x509_get_serial_hex(peer_cert, &gc); - openvpn_snprintf (envname, sizeof(envname), "tls_serial_hex_%d", cert_depth); - setenv_str (es, envname, serial); + /* export serial number in hex as environmental variable */ + serial = backend_x509_get_serial_hex(peer_cert, &gc); + openvpn_snprintf(envname, sizeof(envname), "tls_serial_hex_%d", cert_depth); + setenv_str(es, envname, serial); - gc_free(&gc); + gc_free(&gc); } /* @@ -438,59 +486,63 @@ verify_cert_set_env(struct env_set *es, openvpn_x509_cert_t *peer_cert, int cert */ static result_t verify_cert_call_plugin(const struct plugin_list *plugins, struct env_set *es, - int cert_depth, openvpn_x509_cert_t *cert, char *subject) + int cert_depth, openvpn_x509_cert_t *cert, char *subject) { - if (plugin_defined (plugins, OPENVPN_PLUGIN_TLS_VERIFY)) + if (plugin_defined(plugins, OPENVPN_PLUGIN_TLS_VERIFY)) { - int ret; - struct argv argv = argv_new (); + int ret; + struct argv argv = argv_new(); - argv_printf (&argv, "%d %s", cert_depth, subject); + argv_printf(&argv, "%d %s", cert_depth, subject); - ret = plugin_call_ssl (plugins, OPENVPN_PLUGIN_TLS_VERIFY, &argv, NULL, es, cert_depth, cert); + ret = plugin_call_ssl(plugins, OPENVPN_PLUGIN_TLS_VERIFY, &argv, NULL, es, cert_depth, cert); - argv_reset (&argv); + argv_reset(&argv); - if (ret == OPENVPN_PLUGIN_FUNC_SUCCESS) - { - msg (D_HANDSHAKE, "VERIFY PLUGIN OK: depth=%d, %s", - cert_depth, subject); - } - else - { - msg (D_HANDSHAKE, "VERIFY PLUGIN ERROR: depth=%d, %s", - cert_depth, subject); - return FAILURE; /* Reject connection */ - } + if (ret == OPENVPN_PLUGIN_FUNC_SUCCESS) + { + msg(D_HANDSHAKE, "VERIFY PLUGIN OK: depth=%d, %s", + cert_depth, subject); + } + else + { + msg(D_HANDSHAKE, "VERIFY PLUGIN ERROR: depth=%d, %s", + cert_depth, subject); + return FAILURE; /* Reject connection */ + } } - return SUCCESS; + return SUCCESS; } static const char * verify_cert_export_cert(openvpn_x509_cert_t *peercert, const char *tmp_dir, struct gc_arena *gc) { - FILE *peercert_file; - const char *peercert_filename=""; + FILE *peercert_file; + const char *peercert_filename = ""; - if(!tmp_dir) - return NULL; + if (!tmp_dir) + { + return NULL; + } - /* create tmp file to store peer cert */ - peercert_filename = create_temp_file (tmp_dir, "pcf", gc); + /* create tmp file to store peer cert */ + peercert_filename = create_temp_file(tmp_dir, "pcf", gc); - /* write peer-cert in tmp-file */ - peercert_file = fopen(peercert_filename, "w+"); - if(!peercert_file) + /* write peer-cert in tmp-file */ + peercert_file = fopen(peercert_filename, "w+"); + if (!peercert_file) { - msg (M_ERR, "Failed to open temporary file : %s", peercert_filename); - return NULL; + msg(M_ERR, "Failed to open temporary file : %s", peercert_filename); + return NULL; } - if (SUCCESS != x509_write_pem(peercert_file, peercert)) - msg (M_ERR, "Error writing PEM file containing certificate"); + if (SUCCESS != x509_write_pem(peercert_file, peercert)) + { + msg(M_ERR, "Error writing PEM file containing certificate"); + } - fclose(peercert_file); - return peercert_filename; + fclose(peercert_file); + return peercert_filename; } @@ -499,48 +551,50 @@ verify_cert_export_cert(openvpn_x509_cert_t *peercert, const char *tmp_dir, stru */ static result_t verify_cert_call_command(const char *verify_command, struct env_set *es, - int cert_depth, openvpn_x509_cert_t *cert, char *subject, const char *verify_export_cert) + int cert_depth, openvpn_x509_cert_t *cert, char *subject, const char *verify_export_cert) { - const char *tmp_file = NULL; - int ret; - struct gc_arena gc = gc_new(); - struct argv argv = argv_new (); + const char *tmp_file = NULL; + int ret; + struct gc_arena gc = gc_new(); + struct argv argv = argv_new(); - setenv_str (es, "script_type", "tls-verify"); + setenv_str(es, "script_type", "tls-verify"); - if (verify_export_cert) + if (verify_export_cert) { - if ((tmp_file=verify_cert_export_cert(cert, verify_export_cert, &gc))) - { - setenv_str(es, "peer_cert", tmp_file); - } + if ((tmp_file = verify_cert_export_cert(cert, verify_export_cert, &gc))) + { + setenv_str(es, "peer_cert", tmp_file); + } } - argv_parse_cmd (&argv, verify_command); - argv_printf_cat (&argv, "%d %s", cert_depth, subject); + argv_parse_cmd(&argv, verify_command); + argv_printf_cat(&argv, "%d %s", cert_depth, subject); - argv_msg_prefix (D_TLS_DEBUG, &argv, "TLS: executing verify command"); - ret = openvpn_run_script (&argv, es, 0, "--tls-verify script"); + argv_msg_prefix(D_TLS_DEBUG, &argv, "TLS: executing verify command"); + ret = openvpn_run_script(&argv, es, 0, "--tls-verify script"); - if (verify_export_cert) + if (verify_export_cert) { - if (tmp_file) - platform_unlink(tmp_file); + if (tmp_file) + { + platform_unlink(tmp_file); + } } - gc_free(&gc); - argv_reset (&argv); + gc_free(&gc); + argv_reset(&argv); - if (ret) + if (ret) { - msg (D_HANDSHAKE, "VERIFY SCRIPT OK: depth=%d, %s", - cert_depth, subject); - return SUCCESS; + msg(D_HANDSHAKE, "VERIFY SCRIPT OK: depth=%d, %s", + cert_depth, subject); + return SUCCESS; } - msg (D_HANDSHAKE, "VERIFY SCRIPT ERROR: depth=%d, %s", - cert_depth, subject); - return FAILURE; /* Reject connection */ + msg(D_HANDSHAKE, "VERIFY SCRIPT ERROR: depth=%d, %s", + cert_depth, subject); + return FAILURE; /* Reject connection */ } /* @@ -549,167 +603,179 @@ verify_cert_call_command(const char *verify_command, struct env_set *es, static result_t verify_check_crl_dir(const char *crl_dir, openvpn_x509_cert_t *cert) { - result_t ret = FAILURE; - char fn[256]; - int fd = -1; - struct gc_arena gc = gc_new(); + result_t ret = FAILURE; + char fn[256]; + int fd = -1; + struct gc_arena gc = gc_new(); - char *serial = backend_x509_get_serial(cert, &gc); + char *serial = backend_x509_get_serial(cert, &gc); - if (!openvpn_snprintf(fn, sizeof(fn), "%s%c%s", crl_dir, OS_SPECIFIC_DIRSEP, serial)) + if (!openvpn_snprintf(fn, sizeof(fn), "%s%c%s", crl_dir, OS_SPECIFIC_DIRSEP, serial)) { - msg (D_HANDSHAKE, "VERIFY CRL: filename overflow"); - goto cleanup; + msg(D_HANDSHAKE, "VERIFY CRL: filename overflow"); + goto cleanup; } - fd = platform_open (fn, O_RDONLY, 0); - if (fd >= 0) + fd = platform_open(fn, O_RDONLY, 0); + if (fd >= 0) { - msg (D_HANDSHAKE, "VERIFY CRL: certificate serial number %s is revoked", serial); - goto cleanup; + msg(D_HANDSHAKE, "VERIFY CRL: certificate serial number %s is revoked", serial); + goto cleanup; } - ret = SUCCESS; + ret = SUCCESS; cleanup: - if (fd != -1) - close(fd); - gc_free(&gc); - return ret; + if (fd != -1) + { + close(fd); + } + gc_free(&gc); + return ret; } result_t verify_cert(struct tls_session *session, openvpn_x509_cert_t *cert, int cert_depth) { - result_t ret = FAILURE; - char *subject = NULL; - char common_name[TLS_USERNAME_LEN+1] = {0}; /* null-terminated */ - const struct tls_options *opt; - struct gc_arena gc = gc_new(); + result_t ret = FAILURE; + char *subject = NULL; + char common_name[TLS_USERNAME_LEN+1] = {0}; /* null-terminated */ + const struct tls_options *opt; + struct gc_arena gc = gc_new(); - opt = session->opt; - ASSERT (opt); + opt = session->opt; + ASSERT(opt); - session->verified = false; + session->verified = false; - /* get the X509 name */ - subject = x509_get_subject(cert, &gc); - if (!subject) + /* get the X509 name */ + subject = x509_get_subject(cert, &gc); + if (!subject) { - msg (D_TLS_ERRORS, "VERIFY ERROR: depth=%d, could not extract X509 " - "subject string from certificate", cert_depth); - goto cleanup; + msg(D_TLS_ERRORS, "VERIFY ERROR: depth=%d, could not extract X509 " + "subject string from certificate", cert_depth); + goto cleanup; } - /* enforce character class restrictions in X509 name */ - string_mod_remap_name (subject, X509_NAME_CHAR_CLASS); - string_replace_leading (subject, '-', '_'); + /* enforce character class restrictions in X509 name */ + string_mod_remap_name(subject, X509_NAME_CHAR_CLASS); + string_replace_leading(subject, '-', '_'); - /* extract the username (default is CN) */ - if (SUCCESS != backend_x509_get_username (common_name, sizeof(common_name), - opt->x509_username_field, cert)) + /* extract the username (default is CN) */ + if (SUCCESS != backend_x509_get_username(common_name, sizeof(common_name), + opt->x509_username_field, cert)) { - if (!cert_depth) - { - msg (D_TLS_ERRORS, "VERIFY ERROR: could not extract %s from X509 " - "subject string ('%s') -- note that the username length is " - "limited to %d characters", - opt->x509_username_field, - subject, - TLS_USERNAME_LEN); - goto cleanup; - } + if (!cert_depth) + { + msg(D_TLS_ERRORS, "VERIFY ERROR: could not extract %s from X509 " + "subject string ('%s') -- note that the username length is " + "limited to %d characters", + opt->x509_username_field, + subject, + TLS_USERNAME_LEN); + goto cleanup; + } } - /* enforce character class restrictions in common name */ - string_mod_remap_name (common_name, COMMON_NAME_CHAR_CLASS); + /* enforce character class restrictions in common name */ + string_mod_remap_name(common_name, COMMON_NAME_CHAR_CLASS); - /* warn if cert chain is too deep */ - if (cert_depth >= MAX_CERT_DEPTH) + /* warn if cert chain is too deep */ + if (cert_depth >= MAX_CERT_DEPTH) { - msg (D_TLS_ERRORS, "TLS Error: Convoluted certificate chain detected with depth [%d] greater than %d", cert_depth, MAX_CERT_DEPTH); - goto cleanup; /* Reject connection */ + msg(D_TLS_ERRORS, "TLS Error: Convoluted certificate chain detected with depth [%d] greater than %d", cert_depth, MAX_CERT_DEPTH); + goto cleanup; /* Reject connection */ } - /* verify level 1 cert, i.e. the CA that signed our leaf cert */ - if (cert_depth == 1 && opt->verify_hash) + /* verify level 1 cert, i.e. the CA that signed our leaf cert */ + if (cert_depth == 1 && opt->verify_hash) { - struct buffer sha1_hash = x509_get_sha1_fingerprint(cert, &gc); - if (memcmp (BPTR (&sha1_hash), opt->verify_hash, BLEN(&sha1_hash))) - { - msg (D_TLS_ERRORS, "TLS Error: level-1 certificate hash verification failed"); - goto cleanup; - } + struct buffer sha1_hash = x509_get_sha1_fingerprint(cert, &gc); + if (memcmp(BPTR(&sha1_hash), opt->verify_hash, BLEN(&sha1_hash))) + { + msg(D_TLS_ERRORS, "TLS Error: level-1 certificate hash verification failed"); + goto cleanup; + } } - /* save common name in session object */ - if (cert_depth == 0) - set_common_name (session, common_name); + /* save common name in session object */ + if (cert_depth == 0) + { + set_common_name(session, common_name); + } - session->verify_maxlevel = max_int (session->verify_maxlevel, cert_depth); + session->verify_maxlevel = max_int(session->verify_maxlevel, cert_depth); - /* export certificate values to the environment */ - verify_cert_set_env(opt->es, cert, cert_depth, subject, common_name, - opt->x509_track); + /* export certificate values to the environment */ + verify_cert_set_env(opt->es, cert, cert_depth, subject, common_name, + opt->x509_track); - /* export current untrusted IP */ - setenv_untrusted (session); + /* export current untrusted IP */ + setenv_untrusted(session); - /* If this is the peer's own certificate, verify it */ - if (cert_depth == 0 && SUCCESS != verify_peer_cert(opt, cert, subject, common_name)) - goto cleanup; + /* If this is the peer's own certificate, verify it */ + if (cert_depth == 0 && SUCCESS != verify_peer_cert(opt, cert, subject, common_name)) + { + goto cleanup; + } - /* call --tls-verify plug-in(s), if registered */ - if (SUCCESS != verify_cert_call_plugin(opt->plugins, opt->es, cert_depth, cert, subject)) - goto cleanup; + /* call --tls-verify plug-in(s), if registered */ + if (SUCCESS != verify_cert_call_plugin(opt->plugins, opt->es, cert_depth, cert, subject)) + { + goto cleanup; + } - /* run --tls-verify script */ - if (opt->verify_command && SUCCESS != verify_cert_call_command(opt->verify_command, - opt->es, cert_depth, cert, subject, opt->verify_export_cert)) - goto cleanup; + /* run --tls-verify script */ + if (opt->verify_command && SUCCESS != verify_cert_call_command(opt->verify_command, + opt->es, cert_depth, cert, subject, opt->verify_export_cert)) + { + goto cleanup; + } - /* check peer cert against CRL */ - if (opt->crl_file) + /* check peer cert against CRL */ + if (opt->crl_file) { - if (opt->ssl_flags & SSLF_CRL_VERIFY_DIR) - { - if (SUCCESS != verify_check_crl_dir(opt->crl_file, cert)) - goto cleanup; - } - else - { - if (tls_verify_crl_missing (opt)) - { - msg (D_TLS_ERRORS, "VERIFY ERROR: CRL not loaded"); - goto cleanup; - } - } + if (opt->ssl_flags & SSLF_CRL_VERIFY_DIR) + { + if (SUCCESS != verify_check_crl_dir(opt->crl_file, cert)) + { + goto cleanup; + } + } + else + { + if (tls_verify_crl_missing(opt)) + { + msg(D_TLS_ERRORS, "VERIFY ERROR: CRL not loaded"); + goto cleanup; + } + } } - msg (D_HANDSHAKE, "VERIFY OK: depth=%d, %s", cert_depth, subject); - session->verified = true; - ret = SUCCESS; + msg(D_HANDSHAKE, "VERIFY OK: depth=%d, %s", cert_depth, subject); + session->verified = true; + ret = SUCCESS; cleanup: - if (ret != SUCCESS) + if (ret != SUCCESS) { - tls_clear_error(); /* always? */ - session->verified = false; /* double sure? */ + tls_clear_error(); /* always? */ + session->verified = false; /* double sure? */ } - gc_free(&gc); + gc_free(&gc); - return ret; + return ret; } /* *************************************************************************** - * Functions for the management of deferred authentication when using - * user/password authentication. - *************************************************************************** */ +* Functions for the management of deferred authentication when using +* user/password authentication. +*************************************************************************** */ #ifdef ENABLE_DEF_AUTH /* key_state_test_auth_control_file return values, - NOTE: acf_merge indexing depends on these values */ + * NOTE: acf_merge indexing depends on these values */ #define ACF_UNDEFINED 0 #define ACF_SUCCEEDED 1 #define ACF_DISABLED 2 @@ -718,27 +784,33 @@ verify_cert(struct tls_session *session, openvpn_x509_cert_t *cert, int cert_dep #ifdef MANAGEMENT_DEF_AUTH void -man_def_auth_set_client_reason (struct tls_multi *multi, const char *client_reason) +man_def_auth_set_client_reason(struct tls_multi *multi, const char *client_reason) { - if (multi->client_reason) + if (multi->client_reason) { - free (multi->client_reason); - multi->client_reason = NULL; + free(multi->client_reason); + multi->client_reason = NULL; + } + if (client_reason && strlen(client_reason)) + { + /* FIXME: Last alloc will never be freed */ + multi->client_reason = string_alloc(client_reason, NULL); } - if (client_reason && strlen (client_reason)) - /* FIXME: Last alloc will never be freed */ - multi->client_reason = string_alloc (client_reason, NULL); } static inline unsigned int -man_def_auth_test (const struct key_state *ks) +man_def_auth_test(const struct key_state *ks) { - if (management_enable_def_auth (management)) - return ks->mda_status; - else - return ACF_DISABLED; + if (management_enable_def_auth(management)) + { + return ks->mda_status; + } + else + { + return ACF_DISABLED; + } } -#endif +#endif /* ifdef MANAGEMENT_DEF_AUTH */ #ifdef PLUGIN_DEF_AUTH @@ -747,58 +819,63 @@ man_def_auth_test (const struct key_state *ks) */ void -key_state_rm_auth_control_file (struct key_state *ks) +key_state_rm_auth_control_file(struct key_state *ks) { - if (ks && ks->auth_control_file) + if (ks && ks->auth_control_file) { - platform_unlink (ks->auth_control_file); - free (ks->auth_control_file); - ks->auth_control_file = NULL; + platform_unlink(ks->auth_control_file); + free(ks->auth_control_file); + ks->auth_control_file = NULL; } } static void -key_state_gen_auth_control_file (struct key_state *ks, const struct tls_options *opt) +key_state_gen_auth_control_file(struct key_state *ks, const struct tls_options *opt) { - struct gc_arena gc = gc_new (); - const char *acf; + struct gc_arena gc = gc_new(); + const char *acf; - key_state_rm_auth_control_file (ks); - acf = create_temp_file (opt->tmp_dir, "acf", &gc); - if (acf) { - ks->auth_control_file = string_alloc (acf, NULL); - setenv_str (opt->es, "auth_control_file", ks->auth_control_file); - } /* FIXME: Should have better error handling? */ + key_state_rm_auth_control_file(ks); + acf = create_temp_file(opt->tmp_dir, "acf", &gc); + if (acf) + { + ks->auth_control_file = string_alloc(acf, NULL); + setenv_str(opt->es, "auth_control_file", ks->auth_control_file); + } /* FIXME: Should have better error handling? */ - gc_free (&gc); + gc_free(&gc); } static unsigned int -key_state_test_auth_control_file (struct key_state *ks) +key_state_test_auth_control_file(struct key_state *ks) { - if (ks && ks->auth_control_file) - { - unsigned int ret = ks->auth_control_status; - if (ret == ACF_UNDEFINED) - { - FILE *fp = fopen (ks->auth_control_file, "r"); - if (fp) - { - const int c = fgetc (fp); - if (c == '1') - ret = ACF_SUCCEEDED; - else if (c == '0') - ret = ACF_FAILED; - fclose (fp); - ks->auth_control_status = ret; - } - } - return ret; - } - return ACF_DISABLED; + if (ks && ks->auth_control_file) + { + unsigned int ret = ks->auth_control_status; + if (ret == ACF_UNDEFINED) + { + FILE *fp = fopen(ks->auth_control_file, "r"); + if (fp) + { + const int c = fgetc(fp); + if (c == '1') + { + ret = ACF_SUCCEEDED; + } + else if (c == '0') + { + ret = ACF_FAILED; + } + fclose(fp); + ks->auth_control_status = ret; + } + } + return ret; + } + return ACF_DISABLED; } -#endif +#endif /* ifdef PLUGIN_DEF_AUTH */ /* * Return current session authentication state. Return @@ -806,97 +883,110 @@ key_state_test_auth_control_file (struct key_state *ks) */ int -tls_authentication_status (struct tls_multi *multi, const int latency) +tls_authentication_status(struct tls_multi *multi, const int latency) { - bool deferred = false; - bool success = false; - bool active = false; + bool deferred = false; + bool success = false; + bool active = false; #ifdef ENABLE_DEF_AUTH - static const unsigned char acf_merge[] = - { - ACF_UNDEFINED, /* s1=ACF_UNDEFINED s2=ACF_UNDEFINED */ - ACF_UNDEFINED, /* s1=ACF_UNDEFINED s2=ACF_SUCCEEDED */ - ACF_UNDEFINED, /* s1=ACF_UNDEFINED s2=ACF_DISABLED */ - ACF_FAILED, /* s1=ACF_UNDEFINED s2=ACF_FAILED */ - ACF_UNDEFINED, /* s1=ACF_SUCCEEDED s2=ACF_UNDEFINED */ - ACF_SUCCEEDED, /* s1=ACF_SUCCEEDED s2=ACF_SUCCEEDED */ - ACF_SUCCEEDED, /* s1=ACF_SUCCEEDED s2=ACF_DISABLED */ - ACF_FAILED, /* s1=ACF_SUCCEEDED s2=ACF_FAILED */ - ACF_UNDEFINED, /* s1=ACF_DISABLED s2=ACF_UNDEFINED */ - ACF_SUCCEEDED, /* s1=ACF_DISABLED s2=ACF_SUCCEEDED */ - ACF_DISABLED, /* s1=ACF_DISABLED s2=ACF_DISABLED */ - ACF_FAILED, /* s1=ACF_DISABLED s2=ACF_FAILED */ - ACF_FAILED, /* s1=ACF_FAILED s2=ACF_UNDEFINED */ - ACF_FAILED, /* s1=ACF_FAILED s2=ACF_SUCCEEDED */ - ACF_FAILED, /* s1=ACF_FAILED s2=ACF_DISABLED */ - ACF_FAILED /* s1=ACF_FAILED s2=ACF_FAILED */ + static const unsigned char acf_merge[] = + { + ACF_UNDEFINED, /* s1=ACF_UNDEFINED s2=ACF_UNDEFINED */ + ACF_UNDEFINED, /* s1=ACF_UNDEFINED s2=ACF_SUCCEEDED */ + ACF_UNDEFINED, /* s1=ACF_UNDEFINED s2=ACF_DISABLED */ + ACF_FAILED, /* s1=ACF_UNDEFINED s2=ACF_FAILED */ + ACF_UNDEFINED, /* s1=ACF_SUCCEEDED s2=ACF_UNDEFINED */ + ACF_SUCCEEDED, /* s1=ACF_SUCCEEDED s2=ACF_SUCCEEDED */ + ACF_SUCCEEDED, /* s1=ACF_SUCCEEDED s2=ACF_DISABLED */ + ACF_FAILED, /* s1=ACF_SUCCEEDED s2=ACF_FAILED */ + ACF_UNDEFINED, /* s1=ACF_DISABLED s2=ACF_UNDEFINED */ + ACF_SUCCEEDED, /* s1=ACF_DISABLED s2=ACF_SUCCEEDED */ + ACF_DISABLED, /* s1=ACF_DISABLED s2=ACF_DISABLED */ + ACF_FAILED, /* s1=ACF_DISABLED s2=ACF_FAILED */ + ACF_FAILED, /* s1=ACF_FAILED s2=ACF_UNDEFINED */ + ACF_FAILED, /* s1=ACF_FAILED s2=ACF_SUCCEEDED */ + ACF_FAILED, /* s1=ACF_FAILED s2=ACF_DISABLED */ + ACF_FAILED /* s1=ACF_FAILED s2=ACF_FAILED */ }; #endif /* ENABLE_DEF_AUTH */ - if (multi) + if (multi) { - int i; + int i; #ifdef ENABLE_DEF_AUTH - if (latency && multi->tas_last && multi->tas_last + latency >= now) - return TLS_AUTHENTICATION_UNDEFINED; - multi->tas_last = now; + if (latency && multi->tas_last && multi->tas_last + latency >= now) + { + return TLS_AUTHENTICATION_UNDEFINED; + } + multi->tas_last = now; #endif /* ENABLE_DEF_AUTH */ - for (i = 0; i < KEY_SCAN_SIZE; ++i) - { - struct key_state *ks = multi->key_scan[i]; - if (DECRYPT_KEY_ENABLED (multi, ks)) - { - active = true; - if (ks->authenticated) - { + for (i = 0; i < KEY_SCAN_SIZE; ++i) + { + struct key_state *ks = multi->key_scan[i]; + if (DECRYPT_KEY_ENABLED(multi, ks)) + { + active = true; + if (ks->authenticated) + { #ifdef ENABLE_DEF_AUTH - unsigned int s1 = ACF_DISABLED; - unsigned int s2 = ACF_DISABLED; + unsigned int s1 = ACF_DISABLED; + unsigned int s2 = ACF_DISABLED; #ifdef PLUGIN_DEF_AUTH - s1 = key_state_test_auth_control_file (ks); + s1 = key_state_test_auth_control_file(ks); #endif /* PLUGIN_DEF_AUTH */ #ifdef MANAGEMENT_DEF_AUTH - s2 = man_def_auth_test (ks); + s2 = man_def_auth_test(ks); #endif /* MANAGEMENT_DEF_AUTH */ - ASSERT (s1 < 4 && s2 < 4); - switch (acf_merge[(s1<<2) + s2]) - { - case ACF_SUCCEEDED: - case ACF_DISABLED: - success = true; - ks->auth_deferred = false; - break; - case ACF_UNDEFINED: - if (now < ks->auth_deferred_expire) - deferred = true; - break; - case ACF_FAILED: - ks->authenticated = false; - break; - default: - ASSERT (0); - } + ASSERT(s1 < 4 && s2 < 4); + switch (acf_merge[(s1<<2) + s2]) + { + case ACF_SUCCEEDED: + case ACF_DISABLED: + success = true; + ks->auth_deferred = false; + break; + + case ACF_UNDEFINED: + if (now < ks->auth_deferred_expire) + { + deferred = true; + } + break; + + case ACF_FAILED: + ks->authenticated = false; + break; + + default: + ASSERT(0); + } #else /* !ENABLE_DEF_AUTH */ - success = true; + success = true; #endif /* ENABLE_DEF_AUTH */ - } - } - } + } + } + } } #if 0 - dmsg (D_TLS_ERRORS, "TAS: a=%d s=%d d=%d", active, success, deferred); + dmsg(D_TLS_ERRORS, "TAS: a=%d s=%d d=%d", active, success, deferred); #endif - if (success) - return TLS_AUTHENTICATION_SUCCEEDED; - else if (!active || deferred) - return TLS_AUTHENTICATION_DEFERRED; - else - return TLS_AUTHENTICATION_FAILED; + if (success) + { + return TLS_AUTHENTICATION_SUCCEEDED; + } + else if (!active || deferred) + { + return TLS_AUTHENTICATION_DEFERRED; + } + else + { + return TLS_AUTHENTICATION_FAILED; + } } #ifdef MANAGEMENT_DEF_AUTH @@ -905,26 +995,26 @@ tls_authentication_status (struct tls_multi *multi, const int latency) * to indicate auth failure/success. */ bool -tls_authenticate_key (struct tls_multi *multi, const unsigned int mda_key_id, const bool auth, const char *client_reason) +tls_authenticate_key(struct tls_multi *multi, const unsigned int mda_key_id, const bool auth, const char *client_reason) { - bool ret = false; - if (multi) - { - int i; - man_def_auth_set_client_reason (multi, client_reason); - for (i = 0; i < KEY_SCAN_SIZE; ++i) - { - struct key_state *ks = multi->key_scan[i]; - if (ks->mda_key_id == mda_key_id) - { - ks->mda_status = auth ? ACF_SUCCEEDED : ACF_FAILED; - ret = true; - } - } - } - return ret; + bool ret = false; + if (multi) + { + int i; + man_def_auth_set_client_reason(multi, client_reason); + for (i = 0; i < KEY_SCAN_SIZE; ++i) + { + struct key_state *ks = multi->key_scan[i]; + if (ks->mda_key_id == mda_key_id) + { + ks->mda_status = auth ? ACF_SUCCEEDED : ACF_FAILED; + ret = true; + } + } + } + return ret; } -#endif +#endif /* ifdef MANAGEMENT_DEF_AUTH */ /* **************************************************************************** @@ -941,124 +1031,135 @@ tls_authenticate_key (struct tls_multi *multi, const unsigned int mda_key_id, co * Verify the user name and password using a script */ static bool -verify_user_pass_script (struct tls_session *session, const struct user_pass *up) +verify_user_pass_script(struct tls_session *session, const struct user_pass *up) { - struct gc_arena gc = gc_new (); - struct argv argv = argv_new (); - const char *tmp_file = ""; - bool ret = false; - - /* Is username defined? */ - if ((session->opt->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL) || strlen (up->username)) - { - /* Set environmental variables prior to calling script */ - setenv_str (session->opt->es, "script_type", "user-pass-verify"); - - if (session->opt->auth_user_pass_verify_script_via_file) - { - struct status_output *so; - - tmp_file = create_temp_file (session->opt->tmp_dir, "up", &gc); - if( tmp_file ) { - so = status_open (tmp_file, 0, -1, NULL, STATUS_OUTPUT_WRITE); - status_printf (so, "%s", up->username); - status_printf (so, "%s", up->password); - if (!status_close (so)) - { - msg (D_TLS_ERRORS, "TLS Auth Error: could not write username/password to file: %s", - tmp_file); - goto done; - } - } else { - msg (D_TLS_ERRORS, "TLS Auth Error: could not create write " - "username/password to temp file"); - } - } - else - { - setenv_str (session->opt->es, "username", up->username); - setenv_str (session->opt->es, "password", up->password); - } - - /* setenv incoming cert common name for script */ - setenv_str (session->opt->es, "common_name", session->common_name); - - /* setenv client real IP address */ - setenv_untrusted (session); - - /* format command line */ - argv_parse_cmd (&argv, session->opt->auth_user_pass_verify_script); - argv_printf_cat (&argv, "%s", tmp_file); - - /* call command */ - ret = openvpn_run_script (&argv, session->opt->es, 0, - "--auth-user-pass-verify"); - - if (!session->opt->auth_user_pass_verify_script_via_file) - setenv_del (session->opt->es, "password"); - } - else - { - msg (D_TLS_ERRORS, "TLS Auth Error: peer provided a blank username"); - } - - done: - if (tmp_file && strlen (tmp_file) > 0) - platform_unlink (tmp_file); - - argv_reset (&argv); - gc_free (&gc); - return ret; + struct gc_arena gc = gc_new(); + struct argv argv = argv_new(); + const char *tmp_file = ""; + bool ret = false; + + /* Is username defined? */ + if ((session->opt->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL) || strlen(up->username)) + { + /* Set environmental variables prior to calling script */ + setenv_str(session->opt->es, "script_type", "user-pass-verify"); + + if (session->opt->auth_user_pass_verify_script_via_file) + { + struct status_output *so; + + tmp_file = create_temp_file(session->opt->tmp_dir, "up", &gc); + if (tmp_file) + { + so = status_open(tmp_file, 0, -1, NULL, STATUS_OUTPUT_WRITE); + status_printf(so, "%s", up->username); + status_printf(so, "%s", up->password); + if (!status_close(so)) + { + msg(D_TLS_ERRORS, "TLS Auth Error: could not write username/password to file: %s", + tmp_file); + goto done; + } + } + else + { + msg(D_TLS_ERRORS, "TLS Auth Error: could not create write " + "username/password to temp file"); + } + } + else + { + setenv_str(session->opt->es, "username", up->username); + setenv_str(session->opt->es, "password", up->password); + } + + /* setenv incoming cert common name for script */ + setenv_str(session->opt->es, "common_name", session->common_name); + + /* setenv client real IP address */ + setenv_untrusted(session); + + /* format command line */ + argv_parse_cmd(&argv, session->opt->auth_user_pass_verify_script); + argv_printf_cat(&argv, "%s", tmp_file); + + /* call command */ + ret = openvpn_run_script(&argv, session->opt->es, 0, + "--auth-user-pass-verify"); + + if (!session->opt->auth_user_pass_verify_script_via_file) + { + setenv_del(session->opt->es, "password"); + } + } + else + { + msg(D_TLS_ERRORS, "TLS Auth Error: peer provided a blank username"); + } + +done: + if (tmp_file && strlen(tmp_file) > 0) + { + platform_unlink(tmp_file); + } + + argv_reset(&argv); + gc_free(&gc); + return ret; } /* * Verify the username and password using a plugin */ static int -verify_user_pass_plugin (struct tls_session *session, const struct user_pass *up, const char *raw_username) +verify_user_pass_plugin(struct tls_session *session, const struct user_pass *up, const char *raw_username) { - int retval = OPENVPN_PLUGIN_FUNC_ERROR; + int retval = OPENVPN_PLUGIN_FUNC_ERROR; #ifdef PLUGIN_DEF_AUTH - struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */ + struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */ #endif - /* Is username defined? */ - if ((session->opt->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL) || strlen (up->username)) + /* Is username defined? */ + if ((session->opt->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL) || strlen(up->username)) { - /* set username/password in private env space */ - setenv_str (session->opt->es, "username", (raw_username ? raw_username : up->username)); - setenv_str (session->opt->es, "password", up->password); + /* set username/password in private env space */ + setenv_str(session->opt->es, "username", (raw_username ? raw_username : up->username)); + setenv_str(session->opt->es, "password", up->password); - /* setenv incoming cert common name for script */ - setenv_str (session->opt->es, "common_name", session->common_name); + /* setenv incoming cert common name for script */ + setenv_str(session->opt->es, "common_name", session->common_name); - /* setenv client real IP address */ - setenv_untrusted (session); + /* setenv client real IP address */ + setenv_untrusted(session); #ifdef PLUGIN_DEF_AUTH - /* generate filename for deferred auth control file */ - key_state_gen_auth_control_file (ks, session->opt); + /* generate filename for deferred auth control file */ + key_state_gen_auth_control_file(ks, session->opt); #endif - /* call command */ - retval = plugin_call (session->opt->plugins, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY, NULL, NULL, session->opt->es); + /* call command */ + retval = plugin_call(session->opt->plugins, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY, NULL, NULL, session->opt->es); #ifdef PLUGIN_DEF_AUTH - /* purge auth control filename (and file itself) for non-deferred returns */ - if (retval != OPENVPN_PLUGIN_FUNC_DEFERRED) - key_state_rm_auth_control_file (ks); + /* purge auth control filename (and file itself) for non-deferred returns */ + if (retval != OPENVPN_PLUGIN_FUNC_DEFERRED) + { + key_state_rm_auth_control_file(ks); + } #endif - setenv_del (session->opt->es, "password"); - if (raw_username) - setenv_str (session->opt->es, "username", up->username); + setenv_del(session->opt->es, "password"); + if (raw_username) + { + setenv_str(session->opt->es, "username", up->username); + } } - else + else { - msg (D_TLS_ERRORS, "TLS Auth Error (verify_user_pass_plugin): peer provided a blank username"); + msg(D_TLS_ERRORS, "TLS Auth Error (verify_user_pass_plugin): peer provided a blank username"); } - return retval; + return retval; } @@ -1072,287 +1173,309 @@ verify_user_pass_plugin (struct tls_session *session, const struct user_pass *up #define KMDA_DEF 3 static int -verify_user_pass_management (struct tls_session *session, const struct user_pass *up, const char *raw_username) +verify_user_pass_management(struct tls_session *session, const struct user_pass *up, const char *raw_username) { - int retval = KMDA_ERROR; - struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */ + int retval = KMDA_ERROR; + struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */ - /* Is username defined? */ - if ((session->opt->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL) || strlen (up->username)) + /* Is username defined? */ + if ((session->opt->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL) || strlen(up->username)) { - /* set username/password in private env space */ - setenv_str (session->opt->es, "username", (raw_username ? raw_username : up->username)); - setenv_str (session->opt->es, "password", up->password); + /* set username/password in private env space */ + setenv_str(session->opt->es, "username", (raw_username ? raw_username : up->username)); + setenv_str(session->opt->es, "password", up->password); - /* setenv incoming cert common name for script */ - setenv_str (session->opt->es, "common_name", session->common_name); + /* setenv incoming cert common name for script */ + setenv_str(session->opt->es, "common_name", session->common_name); - /* setenv client real IP address */ - setenv_untrusted (session); + /* setenv client real IP address */ + setenv_untrusted(session); - if (management) - management_notify_client_needing_auth (management, ks->mda_key_id, session->opt->mda_context, session->opt->es); + if (management) + { + management_notify_client_needing_auth(management, ks->mda_key_id, session->opt->mda_context, session->opt->es); + } - setenv_del (session->opt->es, "password"); - if (raw_username) - setenv_str (session->opt->es, "username", up->username); + setenv_del(session->opt->es, "password"); + if (raw_username) + { + setenv_str(session->opt->es, "username", up->username); + } - retval = KMDA_SUCCESS; + retval = KMDA_SUCCESS; } - else + else { - msg (D_TLS_ERRORS, "TLS Auth Error (verify_user_pass_management): peer provided a blank username"); + msg(D_TLS_ERRORS, "TLS Auth Error (verify_user_pass_management): peer provided a blank username"); } - return retval; + return retval; } -#endif +#endif /* ifdef MANAGEMENT_DEF_AUTH */ /* * Main username/password verification entry point */ void verify_user_pass(struct user_pass *up, struct tls_multi *multi, - struct tls_session *session) + struct tls_session *session) { - int s1 = OPENVPN_PLUGIN_FUNC_SUCCESS; - bool s2 = true; - struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */ + int s1 = OPENVPN_PLUGIN_FUNC_SUCCESS; + bool s2 = true; + struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */ - struct gc_arena gc = gc_new (); - char *raw_username = NULL; + struct gc_arena gc = gc_new(); + char *raw_username = NULL; #ifdef MANAGEMENT_DEF_AUTH - int man_def_auth = KMDA_UNDEF; + int man_def_auth = KMDA_UNDEF; - if (management_enable_def_auth (management)) - man_def_auth = KMDA_DEF; + if (management_enable_def_auth(management)) + { + man_def_auth = KMDA_DEF; + } #endif - /* - * Preserve the raw username before string_mod remapping, for plugins - * and management clients when in --compat-names mode - */ - if (compat_flag (COMPAT_FLAG_QUERY | COMPAT_NAMES)) + /* + * Preserve the raw username before string_mod remapping, for plugins + * and management clients when in --compat-names mode + */ + if (compat_flag(COMPAT_FLAG_QUERY | COMPAT_NAMES)) { - ALLOC_ARRAY_CLEAR_GC (raw_username, char, USER_PASS_LEN, &gc); - strcpy (raw_username, up->username); - string_mod (raw_username, CC_PRINT, CC_CRLF, '_'); + ALLOC_ARRAY_CLEAR_GC(raw_username, char, USER_PASS_LEN, &gc); + strcpy(raw_username, up->username); + string_mod(raw_username, CC_PRINT, CC_CRLF, '_'); } - /* enforce character class restrictions in username/password */ - string_mod_remap_name (up->username, COMMON_NAME_CHAR_CLASS); - string_mod (up->password, CC_PRINT, CC_CRLF, '_'); - - /* If server is configured with --auth-gen-token and we have an - * authentication token for this client, this authentication - * round will be done internally using the token instead of - * calling any external authentication modules. - */ - if (session->opt->auth_token_generate && multi->auth_token_sent - && NULL != multi->auth_token) + /* enforce character class restrictions in username/password */ + string_mod_remap_name(up->username, COMMON_NAME_CHAR_CLASS); + string_mod(up->password, CC_PRINT, CC_CRLF, '_'); + + /* If server is configured with --auth-gen-token and we have an + * authentication token for this client, this authentication + * round will be done internally using the token instead of + * calling any external authentication modules. + */ + if (session->opt->auth_token_generate && multi->auth_token_sent + && NULL != multi->auth_token) { - unsigned int ssl_flags = session->opt->ssl_flags; + unsigned int ssl_flags = session->opt->ssl_flags; - /* Ensure that the username has not changed */ - if (!tls_lock_username(multi, up->username)) + /* Ensure that the username has not changed */ + if (!tls_lock_username(multi, up->username)) { - ks->authenticated = false; - goto done; + ks->authenticated = false; + goto done; } - /* If auth-token lifetime has been enabled, - * ensure the token has not expired - */ - if (session->opt->auth_token_lifetime > 0 - && (multi->auth_token_tstamp + session->opt->auth_token_lifetime) < now) + /* If auth-token lifetime has been enabled, + * ensure the token has not expired + */ + if (session->opt->auth_token_lifetime > 0 + && (multi->auth_token_tstamp + session->opt->auth_token_lifetime) < now) { - msg (D_HANDSHAKE, "Auth-token for client expired\n"); - ks->authenticated = false; - goto done; + msg(D_HANDSHAKE, "Auth-token for client expired\n"); + ks->authenticated = false; + goto done; } - /* The core authentication of the token itself */ - if (memcmp_constant_time(multi->auth_token, up->password, - strlen(multi->auth_token)) != 0) + /* The core authentication of the token itself */ + if (memcmp_constant_time(multi->auth_token, up->password, + strlen(multi->auth_token)) != 0) { - secure_memzero (multi->auth_token, AUTH_TOKEN_SIZE); - free (multi->auth_token); - multi->auth_token = NULL; - multi->auth_token_sent = false; - ks->authenticated = false; - tls_deauthenticate (multi); - - msg (D_TLS_ERRORS, "TLS Auth Error: Auth-token verification " - "failed for username '%s' %s", up->username, - (ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) ? "[CN SET]" : ""); + secure_memzero(multi->auth_token, AUTH_TOKEN_SIZE); + free(multi->auth_token); + multi->auth_token = NULL; + multi->auth_token_sent = false; + ks->authenticated = false; + tls_deauthenticate(multi); + + msg(D_TLS_ERRORS, "TLS Auth Error: Auth-token verification " + "failed for username '%s' %s", up->username, + (ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) ? "[CN SET]" : ""); } - else + else { - ks->authenticated = true; - - if (ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) - set_common_name (session, up->username); - msg (D_HANDSHAKE, "TLS: Username/auth-token authentication " - "succeeded for username '%s' %s", - up->username, - (ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) ? "[CN SET]" : ""); + ks->authenticated = true; + + if (ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) + { + set_common_name(session, up->username); + } + msg(D_HANDSHAKE, "TLS: Username/auth-token authentication " + "succeeded for username '%s' %s", + up->username, + (ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) ? "[CN SET]" : ""); } - goto done; + goto done; } - /* call plugin(s) and/or script */ + /* call plugin(s) and/or script */ #ifdef MANAGEMENT_DEF_AUTH - if (man_def_auth == KMDA_DEF) - man_def_auth = verify_user_pass_management (session, up, raw_username); + if (man_def_auth == KMDA_DEF) + { + man_def_auth = verify_user_pass_management(session, up, raw_username); + } #endif - if (plugin_defined (session->opt->plugins, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY)) - s1 = verify_user_pass_plugin (session, up, raw_username); - if (session->opt->auth_user_pass_verify_script) - s2 = verify_user_pass_script (session, up); + if (plugin_defined(session->opt->plugins, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY)) + { + s1 = verify_user_pass_plugin(session, up, raw_username); + } + if (session->opt->auth_user_pass_verify_script) + { + s2 = verify_user_pass_script(session, up); + } - /* check sizing of username if it will become our common name */ - if ((session->opt->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) && strlen (up->username) > TLS_USERNAME_LEN) + /* check sizing of username if it will become our common name */ + if ((session->opt->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) && strlen(up->username) > TLS_USERNAME_LEN) { - msg (D_TLS_ERRORS, "TLS Auth Error: --username-as-common name specified and username is longer than the maximum permitted Common Name length of %d characters", TLS_USERNAME_LEN); - s1 = OPENVPN_PLUGIN_FUNC_ERROR; + msg(D_TLS_ERRORS, "TLS Auth Error: --username-as-common name specified and username is longer than the maximum permitted Common Name length of %d characters", TLS_USERNAME_LEN); + s1 = OPENVPN_PLUGIN_FUNC_ERROR; } - /* auth succeeded? */ - if ((s1 == OPENVPN_PLUGIN_FUNC_SUCCESS + /* auth succeeded? */ + if ((s1 == OPENVPN_PLUGIN_FUNC_SUCCESS #ifdef PLUGIN_DEF_AUTH - || s1 == OPENVPN_PLUGIN_FUNC_DEFERRED + || s1 == OPENVPN_PLUGIN_FUNC_DEFERRED #endif - ) && s2 + ) && s2 #ifdef MANAGEMENT_DEF_AUTH - && man_def_auth != KMDA_ERROR + && man_def_auth != KMDA_ERROR #endif - && tls_lock_username (multi, up->username)) + && tls_lock_username(multi, up->username)) { - ks->authenticated = true; + ks->authenticated = true; #ifdef PLUGIN_DEF_AUTH - if (s1 == OPENVPN_PLUGIN_FUNC_DEFERRED) - ks->auth_deferred = true; + if (s1 == OPENVPN_PLUGIN_FUNC_DEFERRED) + { + ks->auth_deferred = true; + } #endif #ifdef MANAGEMENT_DEF_AUTH - if (man_def_auth != KMDA_UNDEF) - ks->auth_deferred = true; + if (man_def_auth != KMDA_UNDEF) + { + ks->auth_deferred = true; + } #endif - if ((session->opt->auth_token_generate) && (NULL == multi->auth_token)) - { - /* Server is configured with --auth-gen-token but no token has yet - * been generated for this client. Generate one and save it. - */ - uint8_t tok[AUTH_TOKEN_SIZE]; - - if (!rand_bytes(tok, AUTH_TOKEN_SIZE)) - { - msg( M_FATAL, "Failed to get enough randomness for " - "authentication token"); - } - - /* The token should be longer than the input when - * being base64 encoded - */ - if( openvpn_base64_encode(tok, AUTH_TOKEN_SIZE, - &multi->auth_token) < AUTH_TOKEN_SIZE) - { - msg(D_TLS_ERRORS, "BASE64 encoding of token failed. " - "No auth-token will be activated now"); - if (multi->auth_token) - { - secure_memzero (multi->auth_token, AUTH_TOKEN_SIZE); - free (multi->auth_token); - multi->auth_token = NULL; - } - } - else - { - multi->auth_token_tstamp = now; - dmsg (D_SHOW_KEYS, "Generated token for client: %s", - multi->auth_token); - } - } - - if ((session->opt->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME)) - set_common_name (session, up->username); + if ((session->opt->auth_token_generate) && (NULL == multi->auth_token)) + { + /* Server is configured with --auth-gen-token but no token has yet + * been generated for this client. Generate one and save it. + */ + uint8_t tok[AUTH_TOKEN_SIZE]; + + if (!rand_bytes(tok, AUTH_TOKEN_SIZE)) + { + msg( M_FATAL, "Failed to get enough randomness for " + "authentication token"); + } + + /* The token should be longer than the input when + * being base64 encoded + */ + if (openvpn_base64_encode(tok, AUTH_TOKEN_SIZE, + &multi->auth_token) < AUTH_TOKEN_SIZE) + { + msg(D_TLS_ERRORS, "BASE64 encoding of token failed. " + "No auth-token will be activated now"); + if (multi->auth_token) + { + secure_memzero(multi->auth_token, AUTH_TOKEN_SIZE); + free(multi->auth_token); + multi->auth_token = NULL; + } + } + else + { + multi->auth_token_tstamp = now; + dmsg(D_SHOW_KEYS, "Generated token for client: %s", + multi->auth_token); + } + } + + if ((session->opt->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME)) + { + set_common_name(session, up->username); + } #ifdef ENABLE_DEF_AUTH - msg (D_HANDSHAKE, "TLS: Username/Password authentication %s for username '%s' %s", - ks->auth_deferred ? "deferred" : "succeeded", - up->username, - (session->opt->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) ? "[CN SET]" : ""); + msg(D_HANDSHAKE, "TLS: Username/Password authentication %s for username '%s' %s", + ks->auth_deferred ? "deferred" : "succeeded", + up->username, + (session->opt->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) ? "[CN SET]" : ""); #else - msg (D_HANDSHAKE, "TLS: Username/Password authentication %s for username '%s' %s", - "succeeded", - up->username, - (session->opt->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) ? "[CN SET]" : ""); + msg(D_HANDSHAKE, "TLS: Username/Password authentication %s for username '%s' %s", + "succeeded", + up->username, + (session->opt->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME) ? "[CN SET]" : ""); #endif } - else + else { - msg (D_TLS_ERRORS, "TLS Auth Error: Auth Username/Password verification failed for peer"); + msg(D_TLS_ERRORS, "TLS Auth Error: Auth Username/Password verification failed for peer"); } - done: - gc_free (&gc); +done: + gc_free(&gc); } void verify_final_auth_checks(struct tls_multi *multi, struct tls_session *session) { - struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */ + struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */ - /* While it shouldn't really happen, don't allow the common name to be NULL */ - if (!session->common_name) - set_common_name (session, ""); + /* While it shouldn't really happen, don't allow the common name to be NULL */ + if (!session->common_name) + { + set_common_name(session, ""); + } - /* Don't allow the CN to change once it's been locked */ - if (ks->authenticated && multi->locked_cn) + /* Don't allow the CN to change once it's been locked */ + if (ks->authenticated && multi->locked_cn) { - const char *cn = session->common_name; - if (cn && strcmp (cn, multi->locked_cn)) - { - msg (D_TLS_ERRORS, "TLS Auth Error: TLS object CN attempted to change from '%s' to '%s' -- tunnel disabled", - multi->locked_cn, - cn); + const char *cn = session->common_name; + if (cn && strcmp(cn, multi->locked_cn)) + { + msg(D_TLS_ERRORS, "TLS Auth Error: TLS object CN attempted to change from '%s' to '%s' -- tunnel disabled", + multi->locked_cn, + cn); - /* change the common name back to its original value and disable the tunnel */ - set_common_name (session, multi->locked_cn); - tls_deauthenticate (multi); - } + /* change the common name back to its original value and disable the tunnel */ + set_common_name(session, multi->locked_cn); + tls_deauthenticate(multi); + } } - /* Don't allow the cert hashes to change once they have been locked */ - if (ks->authenticated && multi->locked_cert_hash_set) + /* Don't allow the cert hashes to change once they have been locked */ + if (ks->authenticated && multi->locked_cert_hash_set) { - const struct cert_hash_set *chs = session->cert_hash_set; - if (chs && !cert_hash_compare (chs, multi->locked_cert_hash_set)) - { - msg (D_TLS_ERRORS, "TLS Auth Error: TLS object CN=%s client-provided SSL certs unexpectedly changed during mid-session reauth", - session->common_name); + const struct cert_hash_set *chs = session->cert_hash_set; + if (chs && !cert_hash_compare(chs, multi->locked_cert_hash_set)) + { + msg(D_TLS_ERRORS, "TLS Auth Error: TLS object CN=%s client-provided SSL certs unexpectedly changed during mid-session reauth", + session->common_name); - /* disable the tunnel */ - tls_deauthenticate (multi); - } + /* disable the tunnel */ + tls_deauthenticate(multi); + } } - /* verify --client-config-dir based authentication */ - if (ks->authenticated && session->opt->client_config_dir_exclusive) + /* verify --client-config-dir based authentication */ + if (ks->authenticated && session->opt->client_config_dir_exclusive) { - struct gc_arena gc = gc_new (); + struct gc_arena gc = gc_new(); - const char *cn = session->common_name; - const char *path = gen_path (session->opt->client_config_dir_exclusive, cn, &gc); - if (!cn || !strcmp (cn, CCD_DEFAULT) || !test_file (path)) - { - ks->authenticated = false; - msg (D_TLS_ERRORS, "TLS Auth Error: --client-config-dir authentication failed for common name '%s' file='%s'", - session->common_name, - path ? path : "UNDEF"); - } + const char *cn = session->common_name; + const char *path = gen_path(session->opt->client_config_dir_exclusive, cn, &gc); + if (!cn || !strcmp(cn, CCD_DEFAULT) || !test_file(path)) + { + ks->authenticated = false; + msg(D_TLS_ERRORS, "TLS Auth Error: --client-config-dir authentication failed for common name '%s' file='%s'", + session->common_name, + path ? path : "UNDEF"); + } - gc_free (&gc); + gc_free(&gc); } } #endif /* ENABLE_CRYPTO */ diff --git a/src/openvpn/ssl_verify.h b/src/openvpn/ssl_verify.h index 98312fd96e9..45ce3b0ac8e 100644 --- a/src/openvpn/ssl_verify.h +++ b/src/openvpn/ssl_verify.h @@ -55,12 +55,12 @@ /** Structure containing the hash for a single certificate */ struct cert_hash { - unsigned char sha256_hash[256/8]; + unsigned char sha256_hash[256/8]; }; /** Structure containing the hashes for a full certificate chain */ struct cert_hash_set { - struct cert_hash *ch[MAX_CERT_DEPTH]; /**< Array of certificate hashes */ + struct cert_hash *ch[MAX_CERT_DEPTH]; /**< Array of certificate hashes */ }; #define VERIFY_X509_NONE 0 @@ -79,7 +79,7 @@ struct cert_hash_set { * * TODO: document this function */ -int tls_authentication_status (struct tls_multi *multi, const int latency); +int tls_authentication_status(struct tls_multi *multi, const int latency); /** Check whether the \a ks \c key_state is ready to receive data channel * packets. @@ -94,46 +94,46 @@ int tls_authentication_status (struct tls_multi *multi, const int latency); /** * Remove the given key state's auth control file, if it exists. * - * @param ks The key state the remove the file for + * @param ks The key state the remove the file for */ -void key_state_rm_auth_control_file (struct key_state *ks); +void key_state_rm_auth_control_file(struct key_state *ks); /** * Frees the given set of certificate hashes. * - * @param chs The certificate hash set to free. + * @param chs The certificate hash set to free. */ -void cert_hash_free (struct cert_hash_set *chs); +void cert_hash_free(struct cert_hash_set *chs); /** * Locks the certificate hash set used in the given tunnel * - * @param multi The tunnel to lock + * @param multi The tunnel to lock */ -void tls_lock_cert_hash_set (struct tls_multi *multi); +void tls_lock_cert_hash_set(struct tls_multi *multi); /** * Locks the common name field for the given tunnel * - * @param multi The tunnel to lock + * @param multi The tunnel to lock */ -void tls_lock_common_name (struct tls_multi *multi); +void tls_lock_common_name(struct tls_multi *multi); /** * Returns the common name field for the given tunnel * - * @param multi The tunnel to return the common name for - * @param null Whether null may be returned. If not, "UNDEF" will be returned. + * @param multi The tunnel to return the common name for + * @param null Whether null may be returned. If not, "UNDEF" will be returned. */ -const char *tls_common_name (const struct tls_multi* multi, const bool null); +const char *tls_common_name(const struct tls_multi *multi, const bool null); /** * Returns the username field for the given tunnel * - * @param multi The tunnel to return the username for - * @param null Whether null may be returned. If not, "UNDEF" will be returned. + * @param multi The tunnel to return the username for + * @param null Whether null may be returned. If not, "UNDEF" will be returned. */ -const char *tls_username (const struct tls_multi *multi, const bool null); +const char *tls_username(const struct tls_multi *multi, const bool null); /** * Compares certificates hashes, returns true if hashes are equal. @@ -141,33 +141,33 @@ const char *tls_username (const struct tls_multi *multi, const bool null); * @param chs1 cert 1 hash set * @param chs2 cert 2 hash set */ -bool cert_hash_compare (const struct cert_hash_set *chs1, const struct cert_hash_set *chs2); +bool cert_hash_compare(const struct cert_hash_set *chs1, const struct cert_hash_set *chs2); #ifdef ENABLE_PF /** * Retrieve the given tunnel's common name and its hash value. * - * @param multi The tunnel to use - * @param cn Common name's string - * @param cn_hash Common name's hash value + * @param multi The tunnel to use + * @param cn Common name's string + * @param cn_hash Common name's hash value * * @return true if the common name was set, false otherwise. */ static inline bool -tls_common_name_hash (const struct tls_multi *multi, const char **cn, uint32_t *cn_hash) +tls_common_name_hash(const struct tls_multi *multi, const char **cn, uint32_t *cn_hash) { - if (multi) + if (multi) { - const struct tls_session *s = &multi->session[TM_ACTIVE]; - if (s->common_name && s->common_name[0] != '\0') - { - *cn = s->common_name; - *cn_hash = s->common_name_hashval; - return true; - } + const struct tls_session *s = &multi->session[TM_ACTIVE]; + if (s->common_name && s->common_name[0] != '\0') + { + *cn = s->common_name; + *cn_hash = s->common_name_hashval; + return true; + } } - return false; + return false; } #endif @@ -180,32 +180,32 @@ tls_common_name_hash (const struct tls_multi *multi, const char **cn, uint32_t * * session's primary key state's authenticated field. Authentication may also * be deferred, in which case the key state's auth_deferred field is filled in. * - * @param up The username and password to verify. - * @param multi The TLS multi structure to verify usernames against. - * @param session The current TLS session + * @param up The username and password to verify. + * @param multi The TLS multi structure to verify usernames against. + * @param session The current TLS session * */ void verify_user_pass(struct user_pass *up, struct tls_multi *multi, - struct tls_session *session); + struct tls_session *session); /** * Perform final authentication checks, including locking of the cn, the allowed * certificate hashes, and whether a client config entry exists in the * client config directory. * - * @param multi The TLS multi structure to verify locked structures. - * @param session The current TLS session + * @param multi The TLS multi structure to verify locked structures. + * @param session The current TLS session * */ void verify_final_auth_checks(struct tls_multi *multi, struct tls_session *session); struct x509_track { - const struct x509_track *next; - const char *name; -# define XT_FULL_CHAIN (1<<0) - unsigned int flags; - int nid; + const struct x509_track *next; + const char *name; +#define XT_FULL_CHAIN (1<<0) + unsigned int flags; + int nid; }; /* @@ -222,17 +222,19 @@ struct x509_track * TODO: document */ #ifdef MANAGEMENT_DEF_AUTH -bool tls_authenticate_key (struct tls_multi *multi, const unsigned int mda_key_id, const bool auth, const char *client_reason); -void man_def_auth_set_client_reason (struct tls_multi *multi, const char *client_reason); +bool tls_authenticate_key(struct tls_multi *multi, const unsigned int mda_key_id, const bool auth, const char *client_reason); + +void man_def_auth_set_client_reason(struct tls_multi *multi, const char *client_reason); + #endif static inline const char * -tls_client_reason (struct tls_multi *multi) +tls_client_reason(struct tls_multi *multi) { #ifdef ENABLE_DEF_AUTH - return multi->client_reason; + return multi->client_reason; #else - return NULL; + return NULL; #endif } diff --git a/src/openvpn/ssl_verify_backend.h b/src/openvpn/ssl_verify_backend.h index de304b9c29f..34edffb8381 100644 --- a/src/openvpn/ssl_verify_backend.h +++ b/src/openvpn/ssl_verify_backend.h @@ -33,7 +33,7 @@ /** * Result of verification function */ -typedef enum { SUCCESS=0, FAILURE=1 } result_t; +typedef enum { SUCCESS = 0, FAILURE = 1 } result_t; /* * Backend support functions. @@ -49,11 +49,11 @@ typedef enum { SUCCESS=0, FAILURE=1 } result_t; * This function must be called for every certificate in the certificate * chain during the certificate verification stage of the handshake. * - * @param session TLS Session associated with this tunnel - * @param cert Certificate to process - * @param cert_depth Depth of the current certificate + * @param session TLS Session associated with this tunnel + * @param cert Certificate to process + * @param cert_depth Depth of the current certificate * - * @return \c SUCCESS if verification was successful, \c FAILURE on failure. + * @return \c SUCCESS if verification was successful, \c FAILURE on failure. */ result_t verify_cert(struct tls_session *session, openvpn_x509_cert_t *cert, int cert_depth); @@ -64,12 +64,12 @@ result_t verify_cert(struct tls_session *session, openvpn_x509_cert_t *cert, int * Must be called for every certificate in the verification chain, whether it * is valid or not. * - * @param session TLS Session associated with this tunnel - * @param cert_depth Depth of the current certificate - * @param cert_hash Hash of the current certificate + * @param session TLS Session associated with this tunnel + * @param cert_depth Depth of the current certificate + * @param cert_hash Hash of the current certificate */ -void cert_hash_remember (struct tls_session *session, const int cert_depth, - const struct buffer *cert_hash); +void cert_hash_remember(struct tls_session *session, const int cert_depth, + const struct buffer *cert_hash); /* * Library-specific functions. @@ -80,34 +80,34 @@ void cert_hash_remember (struct tls_session *session, const int cert_depth, /* * Retrieve certificate's subject name. * - * @param cert Certificate to retrieve the subject from. - * @param gc Garbage collection arena to use when allocating string. + * @param cert Certificate to retrieve the subject from. + * @param gc Garbage collection arena to use when allocating string. * - * @return a string containing the subject + * @return a string containing the subject */ -char *x509_get_subject (openvpn_x509_cert_t *cert, struct gc_arena *gc); +char *x509_get_subject(openvpn_x509_cert_t *cert, struct gc_arena *gc); /** * Retrieve the certificate's SHA1 fingerprint. * - * @param cert Certificate to retrieve the fingerprint from. - * @param gc Garbage collection arena to use when allocating string. + * @param cert Certificate to retrieve the fingerprint from. + * @param gc Garbage collection arena to use when allocating string. * - * @return a string containing the certificate fingerprint + * @return a string containing the certificate fingerprint */ -struct buffer x509_get_sha1_fingerprint (openvpn_x509_cert_t *cert, - struct gc_arena *gc); +struct buffer x509_get_sha1_fingerprint(openvpn_x509_cert_t *cert, + struct gc_arena *gc); /** * Retrieve the certificate's SHA256 fingerprint. * - * @param cert Certificate to retrieve the fingerprint from. - * @param gc Garbage collection arena to use when allocating string. + * @param cert Certificate to retrieve the fingerprint from. + * @param gc Garbage collection arena to use when allocating string. * - * @return a string containing the certificate fingerprint + * @return a string containing the certificate fingerprint */ -struct buffer x509_get_sha256_fingerprint (openvpn_x509_cert_t *cert, - struct gc_arena *gc); +struct buffer x509_get_sha256_fingerprint(openvpn_x509_cert_t *cert, + struct gc_arena *gc); /* * Retrieve the certificate's username from the specified field. @@ -115,67 +115,67 @@ struct buffer x509_get_sha256_fingerprint (openvpn_x509_cert_t *cert, * If the field is prepended with ext: and ENABLE_X509ALTUSERNAME is enabled, * it will be loaded from an X.509 extension * - * @param cn Buffer to return the common name in. - * @param cn_len Length of the cn buffer. - * @param x509_username_field Name of the field to load from - * @param cert Certificate to retrieve the common name from. + * @param cn Buffer to return the common name in. + * @param cn_len Length of the cn buffer. + * @param x509_username_field Name of the field to load from + * @param cert Certificate to retrieve the common name from. * - * @return \c FAILURE, \c or SUCCESS + * @return \c FAILURE, \c or SUCCESS */ -result_t backend_x509_get_username (char *common_name, int cn_len, - char * x509_username_field, openvpn_x509_cert_t *peer_cert); +result_t backend_x509_get_username(char *common_name, int cn_len, + char *x509_username_field, openvpn_x509_cert_t *peer_cert); /* * Return the certificate's serial number in decimal string representation. * * The serial number is returned as a string, since it might be a bignum. * - * @param cert Certificate to retrieve the serial number from. - * @param gc Garbage collection arena to use when allocating string. + * @param cert Certificate to retrieve the serial number from. + * @param gc Garbage collection arena to use when allocating string. * - * @return String representation of the certificate's serial number - * in decimal notation, or NULL on error. + * @return String representation of the certificate's serial number + * in decimal notation, or NULL on error. */ -char *backend_x509_get_serial (openvpn_x509_cert_t *cert, struct gc_arena *gc); +char *backend_x509_get_serial(openvpn_x509_cert_t *cert, struct gc_arena *gc); /* * Return the certificate's serial number in hex string representation. * * The serial number is returned as a string, since it might be a bignum. * - * @param cert Certificate to retrieve the serial number from. - * @param gc Garbage collection arena to use when allocating string. + * @param cert Certificate to retrieve the serial number from. + * @param gc Garbage collection arena to use when allocating string. * - * @return String representation of the certificate's serial number - * in hex notation, or NULL on error. + * @return String representation of the certificate's serial number + * in hex notation, or NULL on error. */ -char *backend_x509_get_serial_hex (openvpn_x509_cert_t *cert, - struct gc_arena *gc); +char *backend_x509_get_serial_hex(openvpn_x509_cert_t *cert, + struct gc_arena *gc); /* * Save X509 fields to environment, using the naming convention: * * X509_{cert_depth}_{name}={value} * - * @param es Environment set to save variables in - * @param cert_depth Depth of the certificate - * @param cert Certificate to set the environment for + * @param es Environment set to save variables in + * @param cert_depth Depth of the certificate + * @param cert Certificate to set the environment for */ -void x509_setenv (struct env_set *es, int cert_depth, openvpn_x509_cert_t *cert); +void x509_setenv(struct env_set *es, int cert_depth, openvpn_x509_cert_t *cert); /* * Start tracking the given attribute. * * The tracked attributes are stored in ll_head. * - * @param ll_head The x509_track to store tracked atttributes in - * @param name Name of the attribute to track - * @param msglevel Message level for errors - * @param gc Garbage collection arena for temp data + * @param ll_head The x509_track to store tracked atttributes in + * @param name Name of the attribute to track + * @param msglevel Message level for errors + * @param gc Garbage collection arena for temp data * */ -void x509_track_add (const struct x509_track **ll_head, const char *name, - int msglevel, struct gc_arena *gc); +void x509_track_add(const struct x509_track **ll_head, const char *name, + int msglevel, struct gc_arena *gc); /* * Save X509 fields to environment, using the naming convention: @@ -193,60 +193,60 @@ void x509_track_add (const struct x509_track **ll_head, const char *name, * well as X509 V3 extensions. * * @param xt - * @param es Environment set to save variables in - * @param cert_depth Depth of the certificate - * @param cert Certificate to set the environment for + * @param es Environment set to save variables in + * @param cert_depth Depth of the certificate + * @param cert Certificate to set the environment for */ -void x509_setenv_track (const struct x509_track *xt, struct env_set *es, - const int depth, openvpn_x509_cert_t *x509); +void x509_setenv_track(const struct x509_track *xt, struct env_set *es, + const int depth, openvpn_x509_cert_t *x509); /* * Check X.509 Netscape certificate type field, if available. * - * @param cert Certificate to check. - * @param usage One of \c NS_CERT_CHECK_CLIENT, \c NS_CERT_CHECK_SERVER, - * or \c NS_CERT_CHECK_NONE. + * @param cert Certificate to check. + * @param usage One of \c NS_CERT_CHECK_CLIENT, \c NS_CERT_CHECK_SERVER, + * or \c NS_CERT_CHECK_NONE. * - * @return \c SUCCESS if NS_CERT_CHECK_NONE or if the certificate has - * the expected bit set. \c FAILURE if the certificate does - * not have NS cert type verification or the wrong bit set. + * @return \c SUCCESS if NS_CERT_CHECK_NONE or if the certificate has + * the expected bit set. \c FAILURE if the certificate does + * not have NS cert type verification or the wrong bit set. */ result_t x509_verify_ns_cert_type(const openvpn_x509_cert_t *cert, const int usage); /* * Verify X.509 key usage extension field. * - * @param cert Certificate to check. - * @param expected_ku Array of valid key usage values - * @param expected_len Length of the key usage array + * @param cert Certificate to check. + * @param expected_ku Array of valid key usage values + * @param expected_len Length of the key usage array * - * @return \c SUCCESS if one of the key usage values matches, \c FAILURE - * if key usage is not enabled, or the values do not match. + * @return \c SUCCESS if one of the key usage values matches, \c FAILURE + * if key usage is not enabled, or the values do not match. */ -result_t x509_verify_cert_ku (openvpn_x509_cert_t *x509, const unsigned * const expected_ku, - int expected_len); +result_t x509_verify_cert_ku(openvpn_x509_cert_t *x509, const unsigned *const expected_ku, + int expected_len); /* * Verify X.509 extended key usage extension field. * - * @param cert Certificate to check. - * @param expected_oid String representation of the expected Object ID. May be - * either the string representation of the numeric OID - * (e.g. \c "1.2.3.4", or the descriptive string matching - * the OID. + * @param cert Certificate to check. + * @param expected_oid String representation of the expected Object ID. May be + * either the string representation of the numeric OID + * (e.g. \c "1.2.3.4", or the descriptive string matching + * the OID. * - * @return \c SUCCESS if one of the expected OID matches one of the - * extended key usage fields, \c FAILURE if extended key - * usage is not enabled, or the values do not match. + * @return \c SUCCESS if one of the expected OID matches one of the + * extended key usage fields, \c FAILURE if extended key + * usage is not enabled, or the values do not match. */ -result_t x509_verify_cert_eku (openvpn_x509_cert_t *x509, const char * const expected_oid); +result_t x509_verify_cert_eku(openvpn_x509_cert_t *x509, const char *const expected_oid); /* * Store the given certificate in pem format in a temporary file in tmp_dir * - * @param cert Certificate to store - * @param tmp_dir Temporary directory to store the directory - * @param gc gc_arena to store temporary objects in + * @param cert Certificate to store + * @param tmp_dir Temporary directory to store the directory + * @param gc gc_arena to store temporary objects in * * */ diff --git a/src/openvpn/ssl_verify_mbedtls.c b/src/openvpn/ssl_verify_mbedtls.c index 42608235359..b8fbee89d03 100644 --- a/src/openvpn/ssl_verify_mbedtls.c +++ b/src/openvpn/ssl_verify_mbedtls.c @@ -48,293 +48,305 @@ #define MAX_SUBJECT_LENGTH 256 int -verify_callback (void *session_obj, mbedtls_x509_crt *cert, int cert_depth, - uint32_t *flags) +verify_callback(void *session_obj, mbedtls_x509_crt *cert, int cert_depth, + uint32_t *flags) { - struct tls_session *session = (struct tls_session *) session_obj; - struct gc_arena gc = gc_new(); + struct tls_session *session = (struct tls_session *) session_obj; + struct gc_arena gc = gc_new(); - ASSERT (cert); - ASSERT (session); + ASSERT(cert); + ASSERT(session); - session->verified = false; + session->verified = false; - /* Remember certificate hash */ - struct buffer cert_fingerprint = x509_get_sha256_fingerprint (cert, &gc); - cert_hash_remember (session, cert_depth, &cert_fingerprint); + /* Remember certificate hash */ + struct buffer cert_fingerprint = x509_get_sha256_fingerprint(cert, &gc); + cert_hash_remember(session, cert_depth, &cert_fingerprint); - /* did peer present cert which was signed by our root cert? */ - if (*flags != 0) + /* did peer present cert which was signed by our root cert? */ + if (*flags != 0) { - int ret = 0; - char errstr[512] = { 0 }; - char *subject = x509_get_subject(cert, &gc); - - ret = mbedtls_x509_crt_verify_info (errstr, sizeof(errstr)-1, "", *flags); - if (ret <= 0 && !openvpn_snprintf(errstr, sizeof(errstr), - "Could not retrieve error string, flags=%"PRIx32, *flags)) - { - errstr[0] = '\0'; - } - else - { - chomp(errstr); - } - - if (subject) - { - msg (D_TLS_ERRORS, "VERIFY ERROR: depth=%d, subject=%s: %s", - cert_depth, subject, errstr); - } - else - { - msg (D_TLS_ERRORS, "VERIFY ERROR: depth=%d, (could not extract X509 " - "subject string from certificate): %s", cert_depth, errstr); - } - - /* Leave flags set to non-zero to indicate that the cert is not ok */ + int ret = 0; + char errstr[512] = { 0 }; + char *subject = x509_get_subject(cert, &gc); + + ret = mbedtls_x509_crt_verify_info(errstr, sizeof(errstr)-1, "", *flags); + if (ret <= 0 && !openvpn_snprintf(errstr, sizeof(errstr), + "Could not retrieve error string, flags=%" PRIx32, *flags)) + { + errstr[0] = '\0'; + } + else + { + chomp(errstr); + } + + if (subject) + { + msg(D_TLS_ERRORS, "VERIFY ERROR: depth=%d, subject=%s: %s", + cert_depth, subject, errstr); + } + else + { + msg(D_TLS_ERRORS, "VERIFY ERROR: depth=%d, (could not extract X509 " + "subject string from certificate): %s", cert_depth, errstr); + } + + /* Leave flags set to non-zero to indicate that the cert is not ok */ } - else if (SUCCESS != verify_cert(session, cert, cert_depth)) + else if (SUCCESS != verify_cert(session, cert, cert_depth)) { - *flags |= MBEDTLS_X509_BADCERT_OTHER; + *flags |= MBEDTLS_X509_BADCERT_OTHER; } - gc_free(&gc); + gc_free(&gc); - /* - * PolarSSL/mbed TLS-1.2.0+ expects 0 on anything except fatal errors. - */ - return 0; + /* + * PolarSSL/mbed TLS-1.2.0+ expects 0 on anything except fatal errors. + */ + return 0; } #ifdef ENABLE_X509ALTUSERNAME -# warning "X509 alt user name not yet supported for mbed TLS" +#warning "X509 alt user name not yet supported for mbed TLS" #endif result_t -backend_x509_get_username (char *cn, int cn_len, - char *x509_username_field, mbedtls_x509_crt *cert) +backend_x509_get_username(char *cn, int cn_len, + char *x509_username_field, mbedtls_x509_crt *cert) { - mbedtls_x509_name *name; + mbedtls_x509_name *name; - ASSERT( cn != NULL ); + ASSERT( cn != NULL ); - name = &cert->subject; + name = &cert->subject; - /* Find common name */ - while( name != NULL ) - { - if (0 == memcmp (name->oid.p, MBEDTLS_OID_AT_CN, - MBEDTLS_OID_SIZE (MBEDTLS_OID_AT_CN))) - break; + /* Find common name */ + while (name != NULL) + { + if (0 == memcmp(name->oid.p, MBEDTLS_OID_AT_CN, + MBEDTLS_OID_SIZE(MBEDTLS_OID_AT_CN))) + { + break; + } - name = name->next; - } + name = name->next; + } - /* Not found, return an error if this is the peer's certificate */ - if( name == NULL ) - return FAILURE; + /* Not found, return an error if this is the peer's certificate */ + if (name == NULL) + { + return FAILURE; + } - /* Found, extract CN */ - if (cn_len > name->val.len) + /* Found, extract CN */ + if (cn_len > name->val.len) { - memcpy( cn, name->val.p, name->val.len ); - cn[name->val.len] = '\0'; + memcpy( cn, name->val.p, name->val.len ); + cn[name->val.len] = '\0'; } - else + else { - memcpy( cn, name->val.p, cn_len); - cn[cn_len-1] = '\0'; + memcpy( cn, name->val.p, cn_len); + cn[cn_len-1] = '\0'; } - return SUCCESS; + return SUCCESS; } char * -backend_x509_get_serial (mbedtls_x509_crt *cert, struct gc_arena *gc) +backend_x509_get_serial(mbedtls_x509_crt *cert, struct gc_arena *gc) { - char *buf = NULL; - size_t buflen = 0; - mbedtls_mpi serial_mpi = { 0 }; - - /* Transform asn1 integer serial into mbed TLS MPI */ - mbedtls_mpi_init(&serial_mpi); - if (!mbed_ok(mbedtls_mpi_read_binary(&serial_mpi, cert->serial.p, - cert->serial.len))) + char *buf = NULL; + size_t buflen = 0; + mbedtls_mpi serial_mpi = { 0 }; + + /* Transform asn1 integer serial into mbed TLS MPI */ + mbedtls_mpi_init(&serial_mpi); + if (!mbed_ok(mbedtls_mpi_read_binary(&serial_mpi, cert->serial.p, + cert->serial.len))) { - msg(M_WARN, "Failed to retrieve serial from certificate."); - goto end; + msg(M_WARN, "Failed to retrieve serial from certificate."); + goto end; } - /* Determine decimal representation length, allocate buffer */ - mbedtls_mpi_write_string(&serial_mpi, 10, NULL, 0, &buflen); - buf = gc_malloc(buflen, true, gc); + /* Determine decimal representation length, allocate buffer */ + mbedtls_mpi_write_string(&serial_mpi, 10, NULL, 0, &buflen); + buf = gc_malloc(buflen, true, gc); - /* Write MPI serial as decimal string into buffer */ - if (!mbed_ok(mbedtls_mpi_write_string(&serial_mpi, 10, buf, buflen, &buflen))) + /* Write MPI serial as decimal string into buffer */ + if (!mbed_ok(mbedtls_mpi_write_string(&serial_mpi, 10, buf, buflen, &buflen))) { - msg(M_WARN, "Failed to write serial to string."); - buf = NULL; - goto end; + msg(M_WARN, "Failed to write serial to string."); + buf = NULL; + goto end; } end: - mbedtls_mpi_free(&serial_mpi); - return buf; + mbedtls_mpi_free(&serial_mpi); + return buf; } char * -backend_x509_get_serial_hex (mbedtls_x509_crt *cert, struct gc_arena *gc) +backend_x509_get_serial_hex(mbedtls_x509_crt *cert, struct gc_arena *gc) { - char *buf = NULL; - size_t len = cert->serial.len * 3 + 1; + char *buf = NULL; + size_t len = cert->serial.len * 3 + 1; - buf = gc_malloc(len, true, gc); + buf = gc_malloc(len, true, gc); - if(mbedtls_x509_serial_gets(buf, len-1, &cert->serial) < 0) - buf = NULL; + if (mbedtls_x509_serial_gets(buf, len-1, &cert->serial) < 0) + { + buf = NULL; + } - return buf; + return buf; } static struct buffer -x509_get_fingerprint (const mbedtls_md_info_t *md_info, mbedtls_x509_crt *cert, - struct gc_arena *gc) +x509_get_fingerprint(const mbedtls_md_info_t *md_info, mbedtls_x509_crt *cert, + struct gc_arena *gc) { - const size_t md_size = mbedtls_md_get_size (md_info); - struct buffer fingerprint = alloc_buf_gc (md_size, gc); - mbedtls_md(md_info, cert->raw.p, cert->tbs.len, BPTR (&fingerprint)); - ASSERT (buf_inc_len(&fingerprint, md_size)); - return fingerprint; + const size_t md_size = mbedtls_md_get_size(md_info); + struct buffer fingerprint = alloc_buf_gc(md_size, gc); + mbedtls_md(md_info, cert->raw.p, cert->tbs.len, BPTR(&fingerprint)); + ASSERT(buf_inc_len(&fingerprint, md_size)); + return fingerprint; } struct buffer -x509_get_sha1_fingerprint (mbedtls_x509_crt *cert, struct gc_arena *gc) +x509_get_sha1_fingerprint(mbedtls_x509_crt *cert, struct gc_arena *gc) { - return x509_get_fingerprint(mbedtls_md_info_from_type(MBEDTLS_MD_SHA1), - cert, gc); + return x509_get_fingerprint(mbedtls_md_info_from_type(MBEDTLS_MD_SHA1), + cert, gc); } struct buffer -x509_get_sha256_fingerprint (mbedtls_x509_crt *cert, struct gc_arena *gc) +x509_get_sha256_fingerprint(mbedtls_x509_crt *cert, struct gc_arena *gc) { - return x509_get_fingerprint(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), - cert, gc); + return x509_get_fingerprint(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), + cert, gc); } char * x509_get_subject(mbedtls_x509_crt *cert, struct gc_arena *gc) { - char tmp_subject[MAX_SUBJECT_LENGTH] = {0}; - char *subject = NULL; + char tmp_subject[MAX_SUBJECT_LENGTH] = {0}; + char *subject = NULL; - int ret = 0; + int ret = 0; - ret = mbedtls_x509_dn_gets( tmp_subject, MAX_SUBJECT_LENGTH-1, &cert->subject ); - if (ret > 0) + ret = mbedtls_x509_dn_gets( tmp_subject, MAX_SUBJECT_LENGTH-1, &cert->subject ); + if (ret > 0) { - /* Allocate the required space for the subject */ - subject = string_alloc(tmp_subject, gc); + /* Allocate the required space for the subject */ + subject = string_alloc(tmp_subject, gc); } - return subject; + return subject; } static void -do_setenv_x509 (struct env_set *es, const char *name, char *value, int depth) +do_setenv_x509(struct env_set *es, const char *name, char *value, int depth) { - char *name_expand; - size_t name_expand_size; - - string_mod (value, CC_ANY, CC_CRLF, '?'); - msg (D_X509_ATTR, "X509 ATTRIBUTE name='%s' value='%s' depth=%d", name, value, depth); - name_expand_size = 64 + strlen (name); - name_expand = (char *) malloc (name_expand_size); - check_malloc_return (name_expand); - openvpn_snprintf (name_expand, name_expand_size, "X509_%d_%s", depth, name); - setenv_str (es, name_expand, value); - free (name_expand); + char *name_expand; + size_t name_expand_size; + + string_mod(value, CC_ANY, CC_CRLF, '?'); + msg(D_X509_ATTR, "X509 ATTRIBUTE name='%s' value='%s' depth=%d", name, value, depth); + name_expand_size = 64 + strlen(name); + name_expand = (char *) malloc(name_expand_size); + check_malloc_return(name_expand); + openvpn_snprintf(name_expand, name_expand_size, "X509_%d_%s", depth, name); + setenv_str(es, name_expand, value); + free(name_expand); } static char * asn1_buf_to_c_string(const mbedtls_asn1_buf *orig, struct gc_arena *gc) { - size_t i; - char *val; - - for (i = 0; i < orig->len; ++i) - if (orig->p[i] == '\0') - return "ERROR: embedded null value"; - val = gc_malloc(orig->len+1, false, gc); - memcpy(val, orig->p, orig->len); - val[orig->len] = '\0'; - return val; + size_t i; + char *val; + + for (i = 0; i < orig->len; ++i) + if (orig->p[i] == '\0') + { + return "ERROR: embedded null value"; + } + val = gc_malloc(orig->len+1, false, gc); + memcpy(val, orig->p, orig->len); + val[orig->len] = '\0'; + return val; } static void do_setenv_name(struct env_set *es, const struct x509_track *xt, - const mbedtls_x509_crt *cert, int depth, struct gc_arena *gc) + const mbedtls_x509_crt *cert, int depth, struct gc_arena *gc) { - const mbedtls_x509_name *xn; - for (xn = &cert->subject; xn != NULL; xn = xn->next) + const mbedtls_x509_name *xn; + for (xn = &cert->subject; xn != NULL; xn = xn->next) { - const char *xn_short_name = NULL; - if (0 == mbedtls_oid_get_attr_short_name (&xn->oid, &xn_short_name) && - 0 == strcmp (xt->name, xn_short_name)) - { - char *val_str = asn1_buf_to_c_string (&xn->val, gc); - do_setenv_x509 (es, xt->name, val_str, depth); - } + const char *xn_short_name = NULL; + if (0 == mbedtls_oid_get_attr_short_name(&xn->oid, &xn_short_name) + && 0 == strcmp(xt->name, xn_short_name)) + { + char *val_str = asn1_buf_to_c_string(&xn->val, gc); + do_setenv_x509(es, xt->name, val_str, depth); + } } } void -x509_track_add (const struct x509_track **ll_head, const char *name, int msglevel, struct gc_arena *gc) +x509_track_add(const struct x509_track **ll_head, const char *name, int msglevel, struct gc_arena *gc) { - struct x509_track *xt; - ALLOC_OBJ_CLEAR_GC (xt, struct x509_track, gc); - if (*name == '+') + struct x509_track *xt; + ALLOC_OBJ_CLEAR_GC(xt, struct x509_track, gc); + if (*name == '+') { - xt->flags |= XT_FULL_CHAIN; - ++name; + xt->flags |= XT_FULL_CHAIN; + ++name; } - xt->name = name; - xt->next = *ll_head; - *ll_head = xt; + xt->name = name; + xt->next = *ll_head; + *ll_head = xt; } void -x509_setenv_track (const struct x509_track *xt, struct env_set *es, - const int depth, mbedtls_x509_crt *cert) +x509_setenv_track(const struct x509_track *xt, struct env_set *es, + const int depth, mbedtls_x509_crt *cert) { - struct gc_arena gc = gc_new(); - while (xt) + struct gc_arena gc = gc_new(); + while (xt) { - if (depth == 0 || (xt->flags & XT_FULL_CHAIN)) - { - if (0 == strcmp(xt->name, "SHA1") || 0 == strcmp(xt->name, "SHA256")) - { - /* Fingerprint is not part of X509 structure */ - struct buffer cert_hash; - char *fingerprint; - - if (0 == strcmp(xt->name, "SHA1")) - cert_hash = x509_get_sha1_fingerprint(cert, &gc); - else - cert_hash = x509_get_sha256_fingerprint(cert, &gc); - - fingerprint = format_hex_ex(BPTR(&cert_hash), - BLEN(&cert_hash), 0, 1 | FHE_CAPS, ":", &gc); - do_setenv_x509(es, xt->name, fingerprint, depth); - } - else - { - do_setenv_name(es, xt, cert, depth, &gc); - } - } - xt = xt->next; + if (depth == 0 || (xt->flags & XT_FULL_CHAIN)) + { + if (0 == strcmp(xt->name, "SHA1") || 0 == strcmp(xt->name, "SHA256")) + { + /* Fingerprint is not part of X509 structure */ + struct buffer cert_hash; + char *fingerprint; + + if (0 == strcmp(xt->name, "SHA1")) + { + cert_hash = x509_get_sha1_fingerprint(cert, &gc); + } + else + { + cert_hash = x509_get_sha256_fingerprint(cert, &gc); + } + + fingerprint = format_hex_ex(BPTR(&cert_hash), + BLEN(&cert_hash), 0, 1 | FHE_CAPS, ":", &gc); + do_setenv_x509(es, xt->name, fingerprint, depth); + } + else + { + do_setenv_name(es, xt, cert, depth, &gc); + } + } + xt = xt->next; } - gc_free(&gc); + gc_free(&gc); } /* @@ -343,146 +355,159 @@ x509_setenv_track (const struct x509_track *xt, struct env_set *es, * X509_{cert_depth}_{name}={value} */ void -x509_setenv (struct env_set *es, int cert_depth, mbedtls_x509_crt *cert) +x509_setenv(struct env_set *es, int cert_depth, mbedtls_x509_crt *cert) { - int i; - unsigned char c; - const mbedtls_x509_name *name; - char s[128] = { 0 }; + int i; + unsigned char c; + const mbedtls_x509_name *name; + char s[128] = { 0 }; - name = &cert->subject; + name = &cert->subject; - while( name != NULL ) + while (name != NULL) { - char name_expand[64+8]; - const char *shortname; - - if( 0 == mbedtls_oid_get_attr_short_name(&name->oid, &shortname) ) - { - openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_%s", - cert_depth, shortname); - } - else - { - openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_\?\?", - cert_depth); - } - - for( i = 0; i < name->val.len; i++ ) - { - if( i >= (int) sizeof( s ) - 1 ) - break; - - c = name->val.p[i]; - if( c < 32 || c == 127 || ( c > 128 && c < 160 ) ) - s[i] = '?'; - else s[i] = c; - } - s[i] = '\0'; - - /* Check both strings, set environment variable */ - string_mod (name_expand, CC_PRINT, CC_CRLF, '_'); - string_mod ((char*)s, CC_PRINT, CC_CRLF, '_'); - setenv_str_incr (es, name_expand, (char*)s); - - name = name->next; + char name_expand[64+8]; + const char *shortname; + + if (0 == mbedtls_oid_get_attr_short_name(&name->oid, &shortname) ) + { + openvpn_snprintf(name_expand, sizeof(name_expand), "X509_%d_%s", + cert_depth, shortname); + } + else + { + openvpn_snprintf(name_expand, sizeof(name_expand), "X509_%d_\?\?", + cert_depth); + } + + for (i = 0; i < name->val.len; i++) + { + if (i >= (int) sizeof( s ) - 1) + { + break; + } + + c = name->val.p[i]; + if (c < 32 || c == 127 || ( c > 128 && c < 160 ) ) + { + s[i] = '?'; + } + else + { + s[i] = c; + } + } + s[i] = '\0'; + + /* Check both strings, set environment variable */ + string_mod(name_expand, CC_PRINT, CC_CRLF, '_'); + string_mod((char *)s, CC_PRINT, CC_CRLF, '_'); + setenv_str_incr(es, name_expand, (char *)s); + + name = name->next; } } result_t x509_verify_ns_cert_type(const mbedtls_x509_crt *cert, const int usage) { - if (usage == NS_CERT_CHECK_NONE) - return SUCCESS; - if (usage == NS_CERT_CHECK_CLIENT) - return ((cert->ext_types & MBEDTLS_X509_EXT_NS_CERT_TYPE) - && (cert->ns_cert_type & MBEDTLS_X509_NS_CERT_TYPE_SSL_CLIENT)) ? - SUCCESS : FAILURE; - if (usage == NS_CERT_CHECK_SERVER) - return ((cert->ext_types & MBEDTLS_X509_EXT_NS_CERT_TYPE) - && (cert->ns_cert_type & MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER)) ? - SUCCESS : FAILURE; - - return FAILURE; + if (usage == NS_CERT_CHECK_NONE) + { + return SUCCESS; + } + if (usage == NS_CERT_CHECK_CLIENT) + { + return ((cert->ext_types & MBEDTLS_X509_EXT_NS_CERT_TYPE) + && (cert->ns_cert_type & MBEDTLS_X509_NS_CERT_TYPE_SSL_CLIENT)) ? + SUCCESS : FAILURE; + } + if (usage == NS_CERT_CHECK_SERVER) + { + return ((cert->ext_types & MBEDTLS_X509_EXT_NS_CERT_TYPE) + && (cert->ns_cert_type & MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER)) ? + SUCCESS : FAILURE; + } + + return FAILURE; } result_t -x509_verify_cert_ku (mbedtls_x509_crt *cert, const unsigned * const expected_ku, - int expected_len) +x509_verify_cert_ku(mbedtls_x509_crt *cert, const unsigned *const expected_ku, + int expected_len) { - result_t fFound = FAILURE; + result_t fFound = FAILURE; - if(!(cert->ext_types & MBEDTLS_X509_EXT_KEY_USAGE)) + if (!(cert->ext_types & MBEDTLS_X509_EXT_KEY_USAGE)) { - msg (D_HANDSHAKE, "Certificate does not have key usage extension"); + msg(D_HANDSHAKE, "Certificate does not have key usage extension"); } - else + else { - int i; - unsigned nku = cert->key_usage; - - msg (D_HANDSHAKE, "Validating certificate key usage"); - for (i=0; SUCCESS != fFound && ikey_usage; + + msg(D_HANDSHAKE, "Validating certificate key usage"); + for (i = 0; SUCCESS != fFound && iext_types & MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE)) + if (!(cert->ext_types & MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE)) { - msg (D_HANDSHAKE, "Certificate does not have extended key usage extension"); + msg(D_HANDSHAKE, "Certificate does not have extended key usage extension"); } - else + else { - mbedtls_x509_sequence *oid_seq = &(cert->ext_key_usage); - - msg (D_HANDSHAKE, "Validating certificate extended key usage"); - while (oid_seq != NULL) - { - mbedtls_x509_buf *oid = &oid_seq->buf; - char oid_num_str[1024]; - const char *oid_str; - - if (0 == mbedtls_oid_get_extended_key_usage( oid, &oid_str )) - { - msg (D_HANDSHAKE, "++ Certificate has EKU (str) %s, expects %s", - oid_str, expected_oid); - if (!strcmp (expected_oid, oid_str)) - { - fFound = SUCCESS; - break; - } - } - - if (0 < mbedtls_oid_get_numeric_string( oid_num_str, - sizeof (oid_num_str), oid)) - { - msg (D_HANDSHAKE, "++ Certificate has EKU (oid) %s, expects %s", - oid_num_str, expected_oid); - if (!strcmp (expected_oid, oid_num_str)) - { - fFound = SUCCESS; - break; - } - } - oid_seq = oid_seq->next; - } + mbedtls_x509_sequence *oid_seq = &(cert->ext_key_usage); + + msg(D_HANDSHAKE, "Validating certificate extended key usage"); + while (oid_seq != NULL) + { + mbedtls_x509_buf *oid = &oid_seq->buf; + char oid_num_str[1024]; + const char *oid_str; + + if (0 == mbedtls_oid_get_extended_key_usage( oid, &oid_str )) + { + msg(D_HANDSHAKE, "++ Certificate has EKU (str) %s, expects %s", + oid_str, expected_oid); + if (!strcmp(expected_oid, oid_str)) + { + fFound = SUCCESS; + break; + } + } + + if (0 < mbedtls_oid_get_numeric_string( oid_num_str, + sizeof(oid_num_str), oid)) + { + msg(D_HANDSHAKE, "++ Certificate has EKU (oid) %s, expects %s", + oid_num_str, expected_oid); + if (!strcmp(expected_oid, oid_num_str)) + { + fFound = SUCCESS; + break; + } + } + oid_seq = oid_seq->next; + } } return fFound; @@ -491,19 +516,19 @@ x509_verify_cert_eku (mbedtls_x509_crt *cert, const char * const expected_oid) result_t x509_write_pem(FILE *peercert_file, mbedtls_x509_crt *peercert) { - msg (M_WARN, "mbed TLS does not support writing peer certificate in PEM format"); + msg(M_WARN, "mbed TLS does not support writing peer certificate in PEM format"); return FAILURE; } bool tls_verify_crl_missing(const struct tls_options *opt) { - if (opt->crl_file && !(opt->ssl_flags & SSLF_CRL_VERIFY_DIR) - && (opt->ssl_ctx.crl == NULL || opt->ssl_ctx.crl->version == 0)) + if (opt->crl_file && !(opt->ssl_flags & SSLF_CRL_VERIFY_DIR) + && (opt->ssl_ctx.crl == NULL || opt->ssl_ctx.crl->version == 0)) { - return true; + return true; } - return false; + return false; } #endif /* #if defined(ENABLE_CRYPTO) && defined(ENABLE_CRYPTO_MBEDTLS) */ diff --git a/src/openvpn/ssl_verify_mbedtls.h b/src/openvpn/ssl_verify_mbedtls.h index e26d08f89bb..a5252ffe6ad 100644 --- a/src/openvpn/ssl_verify_mbedtls.h +++ b/src/openvpn/ssl_verify_mbedtls.h @@ -70,8 +70,8 @@ typedef mbedtls_x509_crt openvpn_x509_cert_t; * * @return The return value is 0 unless a fatal error occurred. */ -int verify_callback (void *session_obj, mbedtls_x509_crt *cert, int cert_depth, - uint32_t *flags); +int verify_callback(void *session_obj, mbedtls_x509_crt *cert, int cert_depth, + uint32_t *flags); /** @} name Function for authenticating a new connection from a remote OpenVPN peer */ diff --git a/src/openvpn/ssl_verify_openssl.c b/src/openvpn/ssl_verify_openssl.c index 3d1c85e1119..04880d7f60c 100644 --- a/src/openvpn/ssl_verify_openssl.c +++ b/src/openvpn/ssl_verify_openssl.c @@ -48,117 +48,123 @@ #include int -verify_callback (int preverify_ok, X509_STORE_CTX * ctx) +verify_callback(int preverify_ok, X509_STORE_CTX *ctx) { - int ret = 0; - struct tls_session *session; - SSL *ssl; - struct gc_arena gc = gc_new(); - - /* get the tls_session pointer */ - ssl = X509_STORE_CTX_get_ex_data (ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); - ASSERT (ssl); - session = (struct tls_session *) SSL_get_ex_data (ssl, mydata_index); - ASSERT (session); - - struct buffer cert_hash = x509_get_sha256_fingerprint(ctx->current_cert, &gc); - cert_hash_remember (session, ctx->error_depth, &cert_hash); - - /* did peer present cert which was signed by our root cert? */ - if (!preverify_ok) + int ret = 0; + struct tls_session *session; + SSL *ssl; + struct gc_arena gc = gc_new(); + + /* get the tls_session pointer */ + ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); + ASSERT(ssl); + session = (struct tls_session *) SSL_get_ex_data(ssl, mydata_index); + ASSERT(session); + + struct buffer cert_hash = x509_get_sha256_fingerprint(ctx->current_cert, &gc); + cert_hash_remember(session, ctx->error_depth, &cert_hash); + + /* did peer present cert which was signed by our root cert? */ + if (!preverify_ok) { - /* get the X509 name */ - char *subject = x509_get_subject(ctx->current_cert, &gc); - - if (!subject) - { - subject = "(Failed to retrieve certificate subject)"; - } + /* get the X509 name */ + char *subject = x509_get_subject(ctx->current_cert, &gc); - /* Log and ignore missing CRL errors */ - if (ctx->error == X509_V_ERR_UNABLE_TO_GET_CRL) - { - msg (D_TLS_DEBUG_LOW, "VERIFY WARNING: depth=%d, %s: %s", - ctx->error_depth, - X509_verify_cert_error_string (ctx->error), - subject); - ret = 1; - goto cleanup; - } - - /* Remote site specified a certificate, but it's not correct */ - msg (D_TLS_ERRORS, "VERIFY ERROR: depth=%d, error=%s: %s", - ctx->error_depth, - X509_verify_cert_error_string (ctx->error), - subject); - - ERR_clear_error(); + if (!subject) + { + subject = "(Failed to retrieve certificate subject)"; + } - session->verified = false; - goto cleanup; + /* Log and ignore missing CRL errors */ + if (ctx->error == X509_V_ERR_UNABLE_TO_GET_CRL) + { + msg(D_TLS_DEBUG_LOW, "VERIFY WARNING: depth=%d, %s: %s", + ctx->error_depth, + X509_verify_cert_error_string(ctx->error), + subject); + ret = 1; + goto cleanup; + } + + /* Remote site specified a certificate, but it's not correct */ + msg(D_TLS_ERRORS, "VERIFY ERROR: depth=%d, error=%s: %s", + ctx->error_depth, + X509_verify_cert_error_string(ctx->error), + subject); + + ERR_clear_error(); + + session->verified = false; + goto cleanup; } - if (SUCCESS != verify_cert(session, ctx->current_cert, ctx->error_depth)) - goto cleanup; + if (SUCCESS != verify_cert(session, ctx->current_cert, ctx->error_depth)) + { + goto cleanup; + } - ret = 1; + ret = 1; cleanup: - gc_free(&gc); + gc_free(&gc); - return ret; + return ret; } #ifdef ENABLE_X509ALTUSERNAME static -bool extract_x509_extension(X509 *cert, char *fieldname, char *out, int size) +bool +extract_x509_extension(X509 *cert, char *fieldname, char *out, int size) { - bool retval = false; - char *buf = 0; - GENERAL_NAMES *extensions; - int nid = OBJ_txt2nid(fieldname); + bool retval = false; + char *buf = 0; + GENERAL_NAMES *extensions; + int nid = OBJ_txt2nid(fieldname); - extensions = (GENERAL_NAMES *)X509_get_ext_d2i(cert, nid, NULL, NULL); - if ( extensions ) + extensions = (GENERAL_NAMES *)X509_get_ext_d2i(cert, nid, NULL, NULL); + if (extensions) { - int numalts; - int i; - /* get amount of alternatives, - * RFC2459 claims there MUST be at least - * one, but we don't depend on it... - */ + int numalts; + int i; + /* get amount of alternatives, + * RFC2459 claims there MUST be at least + * one, but we don't depend on it... + */ - numalts = sk_GENERAL_NAME_num(extensions); + numalts = sk_GENERAL_NAME_num(extensions); - /* loop through all alternatives */ - for (i=0; itype) + switch (name->type) { - case GEN_EMAIL: - ASN1_STRING_to_UTF8((unsigned char**)&buf, name->d.ia5); - if ( strlen (buf) != name->d.ia5->length ) - { - msg (D_TLS_ERRORS, "ASN1 ERROR: string contained terminating zero"); - OPENSSL_free (buf); - } else { - strncpynt(out, buf, size); - OPENSSL_free(buf); - retval = true; - } - break; - default: - msg (D_TLS_DEBUG, "%s: ignoring general name field type %i", - __func__, name->type); - break; + case GEN_EMAIL: + ASN1_STRING_to_UTF8((unsigned char **)&buf, name->d.ia5); + if (strlen(buf) != name->d.ia5->length) + { + msg(D_TLS_ERRORS, "ASN1 ERROR: string contained terminating zero"); + OPENSSL_free(buf); + } + else + { + strncpynt(out, buf, size); + OPENSSL_free(buf); + retval = true; + } + break; + + default: + msg(D_TLS_DEBUG, "%s: ignoring general name field type %i", + __func__, name->type); + break; } - } - sk_GENERAL_NAME_free (extensions); + } + sk_GENERAL_NAME_free(extensions); } - return retval; + return retval; } #endif /* ENABLE_X509ALTUSERNAME */ @@ -175,154 +181,173 @@ bool extract_x509_extension(X509 *cert, char *fieldname, char *out, int size) * to contain result is grounds for error). */ static result_t -extract_x509_field_ssl (X509_NAME *x509, const char *field_name, char *out, - int size) +extract_x509_field_ssl(X509_NAME *x509, const char *field_name, char *out, + int size) { - int lastpos = -1; - int tmp = -1; - X509_NAME_ENTRY *x509ne = 0; - ASN1_STRING *asn1 = 0; - unsigned char *buf = NULL; - int nid = OBJ_txt2nid(field_name); - - ASSERT (size > 0); - *out = '\0'; - do { - lastpos = tmp; - tmp = X509_NAME_get_index_by_NID(x509, nid, lastpos); - } while (tmp > -1); - - /* Nothing found */ - if (lastpos == -1) - return FAILURE; + int lastpos = -1; + int tmp = -1; + X509_NAME_ENTRY *x509ne = 0; + ASN1_STRING *asn1 = 0; + unsigned char *buf = NULL; + int nid = OBJ_txt2nid(field_name); + + ASSERT(size > 0); + *out = '\0'; + do { + lastpos = tmp; + tmp = X509_NAME_get_index_by_NID(x509, nid, lastpos); + } while (tmp > -1); + + /* Nothing found */ + if (lastpos == -1) + { + return FAILURE; + } - x509ne = X509_NAME_get_entry(x509, lastpos); - if (!x509ne) - return FAILURE; + x509ne = X509_NAME_get_entry(x509, lastpos); + if (!x509ne) + { + return FAILURE; + } - asn1 = X509_NAME_ENTRY_get_data(x509ne); - if (!asn1) - return FAILURE; - tmp = ASN1_STRING_to_UTF8(&buf, asn1); - if (tmp <= 0) - return FAILURE; + asn1 = X509_NAME_ENTRY_get_data(x509ne); + if (!asn1) + { + return FAILURE; + } + tmp = ASN1_STRING_to_UTF8(&buf, asn1); + if (tmp <= 0) + { + return FAILURE; + } - strncpynt(out, (char *)buf, size); + strncpynt(out, (char *)buf, size); - { - const result_t ret = (strlen ((char *)buf) < size) ? SUCCESS: FAILURE; - OPENSSL_free (buf); - return ret; - } + { + const result_t ret = (strlen((char *)buf) < size) ? SUCCESS : FAILURE; + OPENSSL_free(buf); + return ret; + } } result_t -backend_x509_get_username (char *common_name, int cn_len, - char * x509_username_field, X509 *peer_cert) +backend_x509_get_username(char *common_name, int cn_len, + char *x509_username_field, X509 *peer_cert) { #ifdef ENABLE_X509ALTUSERNAME - if (strncmp("ext:",x509_username_field,4) == 0) + if (strncmp("ext:",x509_username_field,4) == 0) { - if (!extract_x509_extension (peer_cert, x509_username_field+4, common_name, cn_len)) - return FAILURE; - } else + if (!extract_x509_extension(peer_cert, x509_username_field+4, common_name, cn_len)) + { + return FAILURE; + } + } + else #endif - if (FAILURE == extract_x509_field_ssl (X509_get_subject_name (peer_cert), - x509_username_field, common_name, cn_len)) - return FAILURE; + if (FAILURE == extract_x509_field_ssl(X509_get_subject_name(peer_cert), + x509_username_field, common_name, cn_len)) + { + return FAILURE; + } - return SUCCESS; + return SUCCESS; } char * -backend_x509_get_serial (openvpn_x509_cert_t *cert, struct gc_arena *gc) +backend_x509_get_serial(openvpn_x509_cert_t *cert, struct gc_arena *gc) { - ASN1_INTEGER *asn1_i; - BIGNUM *bignum; - char *openssl_serial, *serial; + ASN1_INTEGER *asn1_i; + BIGNUM *bignum; + char *openssl_serial, *serial; - asn1_i = X509_get_serialNumber(cert); - bignum = ASN1_INTEGER_to_BN(asn1_i, NULL); - openssl_serial = BN_bn2dec(bignum); + asn1_i = X509_get_serialNumber(cert); + bignum = ASN1_INTEGER_to_BN(asn1_i, NULL); + openssl_serial = BN_bn2dec(bignum); - serial = string_alloc(openssl_serial, gc); + serial = string_alloc(openssl_serial, gc); - BN_free(bignum); - OPENSSL_free(openssl_serial); + BN_free(bignum); + OPENSSL_free(openssl_serial); - return serial; + return serial; } char * -backend_x509_get_serial_hex (openvpn_x509_cert_t *cert, struct gc_arena *gc) +backend_x509_get_serial_hex(openvpn_x509_cert_t *cert, struct gc_arena *gc) { - const ASN1_INTEGER *asn1_i = X509_get_serialNumber(cert); + const ASN1_INTEGER *asn1_i = X509_get_serialNumber(cert); - return format_hex_ex(asn1_i->data, asn1_i->length, 0, 1, ":", gc); + return format_hex_ex(asn1_i->data, asn1_i->length, 0, 1, ":", gc); } struct buffer -x509_get_sha1_fingerprint (X509 *cert, struct gc_arena *gc) +x509_get_sha1_fingerprint(X509 *cert, struct gc_arena *gc) { - struct buffer hash = alloc_buf_gc(sizeof(cert->sha1_hash), gc); - memcpy(BPTR(&hash), cert->sha1_hash, sizeof(cert->sha1_hash)); - ASSERT (buf_inc_len(&hash, sizeof (cert->sha1_hash))); - return hash; + struct buffer hash = alloc_buf_gc(sizeof(cert->sha1_hash), gc); + memcpy(BPTR(&hash), cert->sha1_hash, sizeof(cert->sha1_hash)); + ASSERT(buf_inc_len(&hash, sizeof(cert->sha1_hash))); + return hash; } struct buffer -x509_get_sha256_fingerprint (X509 *cert, struct gc_arena *gc) +x509_get_sha256_fingerprint(X509 *cert, struct gc_arena *gc) { - struct buffer hash = alloc_buf_gc((EVP_sha256())->md_size, gc); - X509_digest(cert, EVP_sha256(), BPTR(&hash), NULL); - ASSERT (buf_inc_len(&hash, (EVP_sha256())->md_size)); - return hash; + struct buffer hash = alloc_buf_gc((EVP_sha256())->md_size, gc); + X509_digest(cert, EVP_sha256(), BPTR(&hash), NULL); + ASSERT(buf_inc_len(&hash, (EVP_sha256())->md_size)); + return hash; } char * -x509_get_subject (X509 *cert, struct gc_arena *gc) +x509_get_subject(X509 *cert, struct gc_arena *gc) { - BIO *subject_bio = NULL; - BUF_MEM *subject_mem; - char *subject = NULL; - int maxlen = 0; - - /* - * Generate the subject string in OpenSSL proprietary format, - * when in --compat-names mode - */ - if (compat_flag (COMPAT_FLAG_QUERY | COMPAT_NAMES)) + BIO *subject_bio = NULL; + BUF_MEM *subject_mem; + char *subject = NULL; + int maxlen = 0; + + /* + * Generate the subject string in OpenSSL proprietary format, + * when in --compat-names mode + */ + if (compat_flag(COMPAT_FLAG_QUERY | COMPAT_NAMES)) { - subject = gc_malloc (256, false, gc); - X509_NAME_oneline (X509_get_subject_name (cert), subject, 256); - subject[255] = '\0'; - return subject; + subject = gc_malloc(256, false, gc); + X509_NAME_oneline(X509_get_subject_name(cert), subject, 256); + subject[255] = '\0'; + return subject; } - subject_bio = BIO_new (BIO_s_mem ()); - if (subject_bio == NULL) - goto err; + subject_bio = BIO_new(BIO_s_mem()); + if (subject_bio == NULL) + { + goto err; + } - X509_NAME_print_ex (subject_bio, X509_get_subject_name (cert), - 0, XN_FLAG_SEP_CPLUS_SPC | XN_FLAG_FN_SN | - ASN1_STRFLGS_UTF8_CONVERT | ASN1_STRFLGS_ESC_CTRL); + X509_NAME_print_ex(subject_bio, X509_get_subject_name(cert), + 0, XN_FLAG_SEP_CPLUS_SPC | XN_FLAG_FN_SN + |ASN1_STRFLGS_UTF8_CONVERT | ASN1_STRFLGS_ESC_CTRL); - if (BIO_eof (subject_bio)) - goto err; + if (BIO_eof(subject_bio)) + { + goto err; + } - BIO_get_mem_ptr (subject_bio, &subject_mem); + BIO_get_mem_ptr(subject_bio, &subject_mem); - maxlen = subject_mem->length + 1; - subject = gc_malloc (maxlen, false, gc); + maxlen = subject_mem->length + 1; + subject = gc_malloc(maxlen, false, gc); - memcpy (subject, subject_mem->data, maxlen); - subject[maxlen - 1] = '\0'; + memcpy(subject, subject_mem->data, maxlen); + subject[maxlen - 1] = '\0'; err: - if (subject_bio) - BIO_free (subject_bio); + if (subject_bio) + { + BIO_free(subject_bio); + } - return subject; + return subject; } @@ -348,121 +373,128 @@ x509_get_subject (X509 *cert, struct gc_arena *gc) */ void -x509_track_add (const struct x509_track **ll_head, const char *name, int msglevel, struct gc_arena *gc) +x509_track_add(const struct x509_track **ll_head, const char *name, int msglevel, struct gc_arena *gc) { - struct x509_track *xt; - ALLOC_OBJ_CLEAR_GC (xt, struct x509_track, gc); - if (*name == '+') + struct x509_track *xt; + ALLOC_OBJ_CLEAR_GC(xt, struct x509_track, gc); + if (*name == '+') + { + xt->flags |= XT_FULL_CHAIN; + ++name; + } + xt->name = name; + xt->nid = OBJ_txt2nid(name); + if (xt->nid != NID_undef) { - xt->flags |= XT_FULL_CHAIN; - ++name; + xt->next = *ll_head; + *ll_head = xt; } - xt->name = name; - xt->nid = OBJ_txt2nid(name); - if (xt->nid != NID_undef) + else { - xt->next = *ll_head; - *ll_head = xt; + msg(msglevel, "x509_track: no such attribute '%s'", name); } - else - msg(msglevel, "x509_track: no such attribute '%s'", name); } /* worker method for setenv_x509_track */ static void -do_setenv_x509 (struct env_set *es, const char *name, char *value, int depth) +do_setenv_x509(struct env_set *es, const char *name, char *value, int depth) { - char *name_expand; - size_t name_expand_size; - - string_mod (value, CC_ANY, CC_CRLF, '?'); - msg (D_X509_ATTR, "X509 ATTRIBUTE name='%s' value='%s' depth=%d", name, value, depth); - name_expand_size = 64 + strlen (name); - name_expand = (char *) malloc (name_expand_size); - check_malloc_return (name_expand); - openvpn_snprintf (name_expand, name_expand_size, "X509_%d_%s", depth, name); - setenv_str (es, name_expand, value); - free (name_expand); + char *name_expand; + size_t name_expand_size; + + string_mod(value, CC_ANY, CC_CRLF, '?'); + msg(D_X509_ATTR, "X509 ATTRIBUTE name='%s' value='%s' depth=%d", name, value, depth); + name_expand_size = 64 + strlen(name); + name_expand = (char *) malloc(name_expand_size); + check_malloc_return(name_expand); + openvpn_snprintf(name_expand, name_expand_size, "X509_%d_%s", depth, name); + setenv_str(es, name_expand, value); + free(name_expand); } void -x509_setenv_track (const struct x509_track *xt, struct env_set *es, const int depth, X509 *x509) +x509_setenv_track(const struct x509_track *xt, struct env_set *es, const int depth, X509 *x509) { - struct gc_arena gc = gc_new(); - X509_NAME *x509_name = X509_get_subject_name (x509); - const char nullc = '\0'; - - while (xt) - { - if (depth == 0 || (xt->flags & XT_FULL_CHAIN)) - { - switch (xt->nid) - { - case NID_sha1: - case NID_sha256: - { - struct buffer fp_buf; - char *fp_str = NULL; - - if (xt->nid == NID_sha1) - fp_buf = x509_get_sha1_fingerprint(x509, &gc); - else - fp_buf = x509_get_sha256_fingerprint(x509, &gc); - - fp_str = format_hex_ex(BPTR(&fp_buf), BLEN(&fp_buf), 0, - 1 | FHE_CAPS, ":", &gc); - do_setenv_x509(es, xt->name, fp_str, depth); - } - break; - default: - { - int i = X509_NAME_get_index_by_NID(x509_name, xt->nid, -1); - if (i >= 0) - { - X509_NAME_ENTRY *ent = X509_NAME_get_entry(x509_name, i); - if (ent) - { - ASN1_STRING *val = X509_NAME_ENTRY_get_data (ent); - unsigned char *buf; - buf = (unsigned char *)1; /* bug in OpenSSL 0.9.6b ASN1_STRING_to_UTF8 requires this workaround */ - if (ASN1_STRING_to_UTF8 (&buf, val) > 0) - { - do_setenv_x509(es, xt->name, (char *)buf, depth); - OPENSSL_free (buf); - } - } - } - else - { - i = X509_get_ext_by_NID(x509, xt->nid, -1); - if (i >= 0) - { - X509_EXTENSION *ext = X509_get_ext(x509, i); - if (ext) - { - BIO *bio = BIO_new(BIO_s_mem()); - if (bio) - { - if (X509V3_EXT_print(bio, ext, 0, 0)) - { - if (BIO_write(bio, &nullc, 1) == 1) - { - char *str; - BIO_get_mem_data(bio, &str); - do_setenv_x509(es, xt->name, str, depth); - } - } - BIO_free(bio); - } - } - } - } - } - } - } - xt = xt->next; - } - gc_free(&gc); + struct gc_arena gc = gc_new(); + X509_NAME *x509_name = X509_get_subject_name(x509); + const char nullc = '\0'; + + while (xt) + { + if (depth == 0 || (xt->flags & XT_FULL_CHAIN)) + { + switch (xt->nid) + { + case NID_sha1: + case NID_sha256: + { + struct buffer fp_buf; + char *fp_str = NULL; + + if (xt->nid == NID_sha1) + { + fp_buf = x509_get_sha1_fingerprint(x509, &gc); + } + else + { + fp_buf = x509_get_sha256_fingerprint(x509, &gc); + } + + fp_str = format_hex_ex(BPTR(&fp_buf), BLEN(&fp_buf), 0, + 1 | FHE_CAPS, ":", &gc); + do_setenv_x509(es, xt->name, fp_str, depth); + } + break; + + default: + { + int i = X509_NAME_get_index_by_NID(x509_name, xt->nid, -1); + if (i >= 0) + { + X509_NAME_ENTRY *ent = X509_NAME_get_entry(x509_name, i); + if (ent) + { + ASN1_STRING *val = X509_NAME_ENTRY_get_data(ent); + unsigned char *buf; + buf = (unsigned char *)1; /* bug in OpenSSL 0.9.6b ASN1_STRING_to_UTF8 requires this workaround */ + if (ASN1_STRING_to_UTF8(&buf, val) > 0) + { + do_setenv_x509(es, xt->name, (char *)buf, depth); + OPENSSL_free(buf); + } + } + } + else + { + i = X509_get_ext_by_NID(x509, xt->nid, -1); + if (i >= 0) + { + X509_EXTENSION *ext = X509_get_ext(x509, i); + if (ext) + { + BIO *bio = BIO_new(BIO_s_mem()); + if (bio) + { + if (X509V3_EXT_print(bio, ext, 0, 0)) + { + if (BIO_write(bio, &nullc, 1) == 1) + { + char *str; + BIO_get_mem_data(bio, &str); + do_setenv_x509(es, xt->name, str, depth); + } + } + BIO_free(bio); + } + } + } + } + } + } + } + xt = xt->next; + } + gc_free(&gc); } /* @@ -471,195 +503,227 @@ x509_setenv_track (const struct x509_track *xt, struct env_set *es, const int de * X509_{cert_depth}_{name}={value} */ void -x509_setenv (struct env_set *es, int cert_depth, openvpn_x509_cert_t *peer_cert) +x509_setenv(struct env_set *es, int cert_depth, openvpn_x509_cert_t *peer_cert) { - int i, n; - int fn_nid; - ASN1_OBJECT *fn; - ASN1_STRING *val; - X509_NAME_ENTRY *ent; - const char *objbuf; - unsigned char *buf; - char *name_expand; - size_t name_expand_size; - X509_NAME *x509 = X509_get_subject_name (peer_cert); - - n = X509_NAME_entry_count (x509); - for (i = 0; i < n; ++i) - { - ent = X509_NAME_get_entry (x509, i); - if (!ent) - continue; - fn = X509_NAME_ENTRY_get_object (ent); - if (!fn) - continue; - val = X509_NAME_ENTRY_get_data (ent); - if (!val) - continue; - fn_nid = OBJ_obj2nid (fn); - if (fn_nid == NID_undef) - continue; - objbuf = OBJ_nid2sn (fn_nid); - if (!objbuf) - continue; - buf = (unsigned char *)1; /* bug in OpenSSL 0.9.6b ASN1_STRING_to_UTF8 requires this workaround */ - if (ASN1_STRING_to_UTF8 (&buf, val) <= 0) - continue; - name_expand_size = 64 + strlen (objbuf); - name_expand = (char *) malloc (name_expand_size); - check_malloc_return (name_expand); - openvpn_snprintf (name_expand, name_expand_size, "X509_%d_%s", cert_depth, - objbuf); - string_mod (name_expand, CC_PRINT, CC_CRLF, '_'); - string_mod ((char*)buf, CC_PRINT, CC_CRLF, '_'); - setenv_str_incr (es, name_expand, (char*)buf); - free (name_expand); - OPENSSL_free (buf); + int i, n; + int fn_nid; + ASN1_OBJECT *fn; + ASN1_STRING *val; + X509_NAME_ENTRY *ent; + const char *objbuf; + unsigned char *buf; + char *name_expand; + size_t name_expand_size; + X509_NAME *x509 = X509_get_subject_name(peer_cert); + + n = X509_NAME_entry_count(x509); + for (i = 0; i < n; ++i) + { + ent = X509_NAME_get_entry(x509, i); + if (!ent) + { + continue; + } + fn = X509_NAME_ENTRY_get_object(ent); + if (!fn) + { + continue; + } + val = X509_NAME_ENTRY_get_data(ent); + if (!val) + { + continue; + } + fn_nid = OBJ_obj2nid(fn); + if (fn_nid == NID_undef) + { + continue; + } + objbuf = OBJ_nid2sn(fn_nid); + if (!objbuf) + { + continue; + } + buf = (unsigned char *)1; /* bug in OpenSSL 0.9.6b ASN1_STRING_to_UTF8 requires this workaround */ + if (ASN1_STRING_to_UTF8(&buf, val) <= 0) + { + continue; + } + name_expand_size = 64 + strlen(objbuf); + name_expand = (char *) malloc(name_expand_size); + check_malloc_return(name_expand); + openvpn_snprintf(name_expand, name_expand_size, "X509_%d_%s", cert_depth, + objbuf); + string_mod(name_expand, CC_PRINT, CC_CRLF, '_'); + string_mod((char *)buf, CC_PRINT, CC_CRLF, '_'); + setenv_str_incr(es, name_expand, (char *)buf); + free(name_expand); + OPENSSL_free(buf); } } result_t x509_verify_ns_cert_type(const openvpn_x509_cert_t *peer_cert, const int usage) { - if (usage == NS_CERT_CHECK_NONE) - return SUCCESS; - if (usage == NS_CERT_CHECK_CLIENT) - return ((peer_cert->ex_flags & EXFLAG_NSCERT) - && (peer_cert->ex_nscert & NS_SSL_CLIENT)) ? SUCCESS: FAILURE; - if (usage == NS_CERT_CHECK_SERVER) - return ((peer_cert->ex_flags & EXFLAG_NSCERT) - && (peer_cert->ex_nscert & NS_SSL_SERVER)) ? SUCCESS: FAILURE; - - return FAILURE; + if (usage == NS_CERT_CHECK_NONE) + { + return SUCCESS; + } + if (usage == NS_CERT_CHECK_CLIENT) + { + return ((peer_cert->ex_flags & EXFLAG_NSCERT) + && (peer_cert->ex_nscert & NS_SSL_CLIENT)) ? SUCCESS : FAILURE; + } + if (usage == NS_CERT_CHECK_SERVER) + { + return ((peer_cert->ex_flags & EXFLAG_NSCERT) + && (peer_cert->ex_nscert & NS_SSL_SERVER)) ? SUCCESS : FAILURE; + } + + return FAILURE; } result_t -x509_verify_cert_ku (X509 *x509, const unsigned * const expected_ku, - int expected_len) +x509_verify_cert_ku(X509 *x509, const unsigned *const expected_ku, + int expected_len) { - ASN1_BIT_STRING *ku = NULL; - result_t fFound = FAILURE; - - if ((ku = (ASN1_BIT_STRING *) X509_get_ext_d2i (x509, NID_key_usage, NULL, - NULL)) == NULL) - { - msg (D_HANDSHAKE, "Certificate does not have key usage extension"); - } - else - { - unsigned nku = 0; - int i; - for (i = 0; i < 8; i++) - { - if (ASN1_BIT_STRING_get_bit (ku, i)) - nku |= 1 << (7 - i); - } - - /* - * Fixup if no LSB bits - */ - if ((nku & 0xff) == 0) - { - nku >>= 8; - } - - msg (D_HANDSHAKE, "Validating certificate key usage"); - for (i = 0; fFound != SUCCESS && i < expected_len; i++) - { - if (expected_ku[i] != 0) - { - msg (D_HANDSHAKE, "++ Certificate has key usage %04x, expects " - "%04x", nku, expected_ku[i]); - - if (nku == expected_ku[i]) - fFound = SUCCESS; - } - } - } - - if (ku != NULL) - ASN1_BIT_STRING_free (ku); - - return fFound; + ASN1_BIT_STRING *ku = NULL; + result_t fFound = FAILURE; + + if ((ku = (ASN1_BIT_STRING *) X509_get_ext_d2i(x509, NID_key_usage, NULL, + NULL)) == NULL) + { + msg(D_HANDSHAKE, "Certificate does not have key usage extension"); + } + else + { + unsigned nku = 0; + int i; + for (i = 0; i < 8; i++) + { + if (ASN1_BIT_STRING_get_bit(ku, i)) + { + nku |= 1 << (7 - i); + } + } + + /* + * Fixup if no LSB bits + */ + if ((nku & 0xff) == 0) + { + nku >>= 8; + } + + msg(D_HANDSHAKE, "Validating certificate key usage"); + for (i = 0; fFound != SUCCESS && i < expected_len; i++) + { + if (expected_ku[i] != 0) + { + msg(D_HANDSHAKE, "++ Certificate has key usage %04x, expects " + "%04x", nku, expected_ku[i]); + + if (nku == expected_ku[i]) + { + fFound = SUCCESS; + } + } + } + } + + if (ku != NULL) + { + ASN1_BIT_STRING_free(ku); + } + + return fFound; } result_t -x509_verify_cert_eku (X509 *x509, const char * const expected_oid) +x509_verify_cert_eku(X509 *x509, const char *const expected_oid) { - EXTENDED_KEY_USAGE *eku = NULL; - result_t fFound = FAILURE; + EXTENDED_KEY_USAGE *eku = NULL; + result_t fFound = FAILURE; - if ((eku = (EXTENDED_KEY_USAGE *) X509_get_ext_d2i (x509, NID_ext_key_usage, - NULL, NULL)) == NULL) + if ((eku = (EXTENDED_KEY_USAGE *) X509_get_ext_d2i(x509, NID_ext_key_usage, + NULL, NULL)) == NULL) { - msg (D_HANDSHAKE, "Certificate does not have extended key usage extension"); + msg(D_HANDSHAKE, "Certificate does not have extended key usage extension"); } - else + else { - int i; + int i; - msg (D_HANDSHAKE, "Validating certificate extended key usage"); - for (i = 0; SUCCESS != fFound && i < sk_ASN1_OBJECT_num (eku); i++) - { - ASN1_OBJECT *oid = sk_ASN1_OBJECT_value (eku, i); - char szOid[1024]; + msg(D_HANDSHAKE, "Validating certificate extended key usage"); + for (i = 0; SUCCESS != fFound && i < sk_ASN1_OBJECT_num(eku); i++) + { + ASN1_OBJECT *oid = sk_ASN1_OBJECT_value(eku, i); + char szOid[1024]; - if (SUCCESS != fFound && OBJ_obj2txt (szOid, sizeof(szOid), oid, 0) != -1) - { - msg (D_HANDSHAKE, "++ Certificate has EKU (str) %s, expects %s", - szOid, expected_oid); - if (!strcmp (expected_oid, szOid)) - fFound = SUCCESS; - } - if (SUCCESS != fFound && OBJ_obj2txt (szOid, sizeof(szOid), oid, 1) != -1) - { - msg (D_HANDSHAKE, "++ Certificate has EKU (oid) %s, expects %s", - szOid, expected_oid); - if (!strcmp (expected_oid, szOid)) - fFound = SUCCESS; - } - } + if (SUCCESS != fFound && OBJ_obj2txt(szOid, sizeof(szOid), oid, 0) != -1) + { + msg(D_HANDSHAKE, "++ Certificate has EKU (str) %s, expects %s", + szOid, expected_oid); + if (!strcmp(expected_oid, szOid)) + { + fFound = SUCCESS; + } + } + if (SUCCESS != fFound && OBJ_obj2txt(szOid, sizeof(szOid), oid, 1) != -1) + { + msg(D_HANDSHAKE, "++ Certificate has EKU (oid) %s, expects %s", + szOid, expected_oid); + if (!strcmp(expected_oid, szOid)) + { + fFound = SUCCESS; + } + } + } } - if (eku != NULL) - sk_ASN1_OBJECT_pop_free (eku, ASN1_OBJECT_free); + if (eku != NULL) + { + sk_ASN1_OBJECT_pop_free(eku, ASN1_OBJECT_free); + } - return fFound; + return fFound; } result_t x509_write_pem(FILE *peercert_file, X509 *peercert) { - if (PEM_write_X509(peercert_file, peercert) < 0) + if (PEM_write_X509(peercert_file, peercert) < 0) { - msg (M_ERR, "Failed to write peer certificate in PEM format"); - return FAILURE; + msg(M_ERR, "Failed to write peer certificate in PEM format"); + return FAILURE; } - return SUCCESS; + return SUCCESS; } bool tls_verify_crl_missing(const struct tls_options *opt) { - if (!opt->crl_file || (opt->ssl_flags & SSLF_CRL_VERIFY_DIR)) + if (!opt->crl_file || (opt->ssl_flags & SSLF_CRL_VERIFY_DIR)) { - return false; + return false; } - X509_STORE *store = SSL_CTX_get_cert_store(opt->ssl_ctx.ctx); - if (!store) - crypto_msg (M_FATAL, "Cannot get certificate store"); + X509_STORE *store = SSL_CTX_get_cert_store(opt->ssl_ctx.ctx); + if (!store) + { + crypto_msg(M_FATAL, "Cannot get certificate store"); + } - for (int i = 0; i < sk_X509_OBJECT_num(store->objs); i++) + for (int i = 0; i < sk_X509_OBJECT_num(store->objs); i++) { - X509_OBJECT* obj = sk_X509_OBJECT_value(store->objs, i); - ASSERT(obj); - if (obj->type == X509_LU_CRL) - { - return false; - } + X509_OBJECT *obj = sk_X509_OBJECT_value(store->objs, i); + ASSERT(obj); + if (obj->type == X509_LU_CRL) + { + return false; + } } - return true; + return true; } #endif /* defined(ENABLE_CRYPTO) && defined(ENABLE_CRYPTO_OPENSSL) */ diff --git a/src/openvpn/ssl_verify_openssl.h b/src/openvpn/ssl_verify_openssl.h index 5a7e0a19840..934c1e9a7c9 100644 --- a/src/openvpn/ssl_verify_openssl.h +++ b/src/openvpn/ssl_verify_openssl.h @@ -69,7 +69,7 @@ typedef X509 openvpn_x509_cert_t; * - \c 0: failure, this certificate is not allowed to connect. * - \c 1: success, this certificate is allowed to connect. */ -int verify_callback (int preverify_ok, X509_STORE_CTX * ctx); +int verify_callback(int preverify_ok, X509_STORE_CTX *ctx); /** @} name Function for authenticating a new connection from a remote OpenVPN peer */ diff --git a/src/openvpn/status.c b/src/openvpn/status.c index b7ff484346b..cca623f7783 100644 --- a/src/openvpn/status.c +++ b/src/openvpn/status.c @@ -42,251 +42,292 @@ */ static const char * -print_status_mode (unsigned int flags) +print_status_mode(unsigned int flags) { - switch (flags) + switch (flags) { - case STATUS_OUTPUT_WRITE: - return "WRITE"; - case STATUS_OUTPUT_READ: - return "READ"; - case STATUS_OUTPUT_READ|STATUS_OUTPUT_WRITE: - return "READ/WRITE"; - default: - return "UNDEF"; + case STATUS_OUTPUT_WRITE: + return "WRITE"; + + case STATUS_OUTPUT_READ: + return "READ"; + + case STATUS_OUTPUT_READ|STATUS_OUTPUT_WRITE: + return "READ/WRITE"; + + default: + return "UNDEF"; } } struct status_output * -status_open (const char *filename, - const int refresh_freq, - const int msglevel, - const struct virtual_output *vout, - const unsigned int flags) +status_open(const char *filename, + const int refresh_freq, + const int msglevel, + const struct virtual_output *vout, + const unsigned int flags) { - struct status_output *so = NULL; - if (filename || msglevel >= 0 || vout) + struct status_output *so = NULL; + if (filename || msglevel >= 0 || vout) { - ALLOC_OBJ_CLEAR (so, struct status_output); - so->flags = flags; - so->msglevel = msglevel; - so->vout = vout; - so->fd = -1; - buf_reset (&so->read_buf); - event_timeout_clear (&so->et); - if (filename) + ALLOC_OBJ_CLEAR(so, struct status_output); + so->flags = flags; + so->msglevel = msglevel; + so->vout = vout; + so->fd = -1; + buf_reset(&so->read_buf); + event_timeout_clear(&so->et); + if (filename) { - switch (so->flags) + switch (so->flags) + { + case STATUS_OUTPUT_WRITE: + so->fd = platform_open(filename, + O_CREAT | O_TRUNC | O_WRONLY, + S_IRUSR | S_IWUSR); + break; + + case STATUS_OUTPUT_READ: + so->fd = platform_open(filename, + O_RDONLY, + S_IRUSR | S_IWUSR); + break; + + case STATUS_OUTPUT_READ|STATUS_OUTPUT_WRITE: + so->fd = platform_open(filename, + O_CREAT | O_RDWR, + S_IRUSR | S_IWUSR); + break; + + default: + ASSERT(0); + } + if (so->fd >= 0) + { + so->filename = string_alloc(filename, NULL); + set_cloexec(so->fd); + + /* allocate read buffer */ + if (so->flags & STATUS_OUTPUT_READ) + { + so->read_buf = alloc_buf(512); + } + } + else { - case STATUS_OUTPUT_WRITE: - so->fd = platform_open (filename, - O_CREAT | O_TRUNC | O_WRONLY, - S_IRUSR | S_IWUSR); - break; - case STATUS_OUTPUT_READ: - so->fd = platform_open (filename, - O_RDONLY, - S_IRUSR | S_IWUSR); - break; - case STATUS_OUTPUT_READ|STATUS_OUTPUT_WRITE: - so->fd = platform_open (filename, - O_CREAT | O_RDWR, - S_IRUSR | S_IWUSR); - break; - default: - ASSERT (0); + msg(M_WARN, "Note: cannot open %s for %s", filename, print_status_mode(so->flags)); + so->errors = true; } - if (so->fd >= 0) - { - so->filename = string_alloc (filename, NULL); - set_cloexec (so->fd); - - /* allocate read buffer */ - if (so->flags & STATUS_OUTPUT_READ) - so->read_buf = alloc_buf (512); - } - else - { - msg (M_WARN, "Note: cannot open %s for %s", filename, print_status_mode (so->flags)); - so->errors = true; - } - } - else - so->flags = STATUS_OUTPUT_WRITE; - - if ((so->flags & STATUS_OUTPUT_WRITE) && refresh_freq > 0) - { - event_timeout_init (&so->et, refresh_freq, 0); - } + } + else + { + so->flags = STATUS_OUTPUT_WRITE; + } + + if ((so->flags & STATUS_OUTPUT_WRITE) && refresh_freq > 0) + { + event_timeout_init(&so->et, refresh_freq, 0); + } } - return so; + return so; } bool -status_trigger (struct status_output *so) +status_trigger(struct status_output *so) { - if (so) + if (so) { - struct timeval null; - CLEAR (null); - return event_timeout_trigger (&so->et, &null, ETT_DEFAULT); + struct timeval null; + CLEAR(null); + return event_timeout_trigger(&so->et, &null, ETT_DEFAULT); + } + else + { + return false; } - else - return false; } bool -status_trigger_tv (struct status_output *so, struct timeval *tv) +status_trigger_tv(struct status_output *so, struct timeval *tv) { - if (so) - return event_timeout_trigger (&so->et, tv, ETT_DEFAULT); - else - return false; + if (so) + { + return event_timeout_trigger(&so->et, tv, ETT_DEFAULT); + } + else + { + return false; + } } void -status_reset (struct status_output *so) +status_reset(struct status_output *so) { - if (so && so->fd >= 0) - lseek (so->fd, (off_t)0, SEEK_SET); + if (so && so->fd >= 0) + { + lseek(so->fd, (off_t)0, SEEK_SET); + } } void -status_flush (struct status_output *so) +status_flush(struct status_output *so) { - if (so && so->fd >= 0 && (so->flags & STATUS_OUTPUT_WRITE)) + if (so && so->fd >= 0 && (so->flags & STATUS_OUTPUT_WRITE)) { #if defined(HAVE_FTRUNCATE) - { - const off_t off = lseek (so->fd, (off_t)0, SEEK_CUR); - if (ftruncate (so->fd, off) != 0) { - msg (M_WARN, "Failed to truncate status file: %s", strerror(errno)); - } - } + { + const off_t off = lseek(so->fd, (off_t)0, SEEK_CUR); + if (ftruncate(so->fd, off) != 0) + { + msg(M_WARN, "Failed to truncate status file: %s", strerror(errno)); + } + } #elif defined(HAVE_CHSIZE) - { - const long off = (long) lseek (so->fd, (off_t)0, SEEK_CUR); - chsize (so->fd, off); - } -#else + { + const long off = (long) lseek(so->fd, (off_t)0, SEEK_CUR); + chsize(so->fd, off); + } +#else /* if defined(HAVE_FTRUNCATE) */ #warning both ftruncate and chsize functions appear to be missing from this OS #endif - /* clear read buffer */ - if (buf_defined (&so->read_buf)) - { - ASSERT (buf_init (&so->read_buf, 0)); - } + /* clear read buffer */ + if (buf_defined(&so->read_buf)) + { + ASSERT(buf_init(&so->read_buf, 0)); + } } } /* return false if error occurred */ bool -status_close (struct status_output *so) +status_close(struct status_output *so) { - bool ret = true; - if (so) + bool ret = true; + if (so) { - if (so->errors) - ret = false; - if (so->fd >= 0) - { - if (close (so->fd) < 0) - ret = false; - } - if (so->filename) - free (so->filename); - if (buf_defined (&so->read_buf)) - free_buf (&so->read_buf); - free (so); + if (so->errors) + { + ret = false; + } + if (so->fd >= 0) + { + if (close(so->fd) < 0) + { + ret = false; + } + } + if (so->filename) + { + free(so->filename); + } + if (buf_defined(&so->read_buf)) + { + free_buf(&so->read_buf); + } + free(so); + } + else + { + ret = false; } - else - ret = false; - return ret; + return ret; } #define STATUS_PRINTF_MAXLEN 512 void -status_printf (struct status_output *so, const char *format, ...) +status_printf(struct status_output *so, const char *format, ...) { - if (so && (so->flags & STATUS_OUTPUT_WRITE)) + if (so && (so->flags & STATUS_OUTPUT_WRITE)) { - char buf[STATUS_PRINTF_MAXLEN+2]; /* leave extra bytes for CR, LF */ - va_list arglist; - int stat; - - va_start (arglist, format); - stat = vsnprintf (buf, STATUS_PRINTF_MAXLEN, format, arglist); - va_end (arglist); - buf[STATUS_PRINTF_MAXLEN - 1] = 0; - - if (stat < 0 || stat >= STATUS_PRINTF_MAXLEN) - so->errors = true; - - if (so->msglevel >= 0 && !so->errors) - msg (so->msglevel, "%s", buf); - - if (so->fd >= 0 && !so->errors) - { - int len; - strcat (buf, "\n"); - len = strlen (buf); - if (len > 0) - { - if (write (so->fd, buf, len) != len) - so->errors = true; - } - } - - if (so->vout && !so->errors) - { - chomp (buf); - (*so->vout->func) (so->vout->arg, so->vout->flags_default, buf); - } + char buf[STATUS_PRINTF_MAXLEN+2]; /* leave extra bytes for CR, LF */ + va_list arglist; + int stat; + + va_start(arglist, format); + stat = vsnprintf(buf, STATUS_PRINTF_MAXLEN, format, arglist); + va_end(arglist); + buf[STATUS_PRINTF_MAXLEN - 1] = 0; + + if (stat < 0 || stat >= STATUS_PRINTF_MAXLEN) + { + so->errors = true; + } + + if (so->msglevel >= 0 && !so->errors) + { + msg(so->msglevel, "%s", buf); + } + + if (so->fd >= 0 && !so->errors) + { + int len; + strcat(buf, "\n"); + len = strlen(buf); + if (len > 0) + { + if (write(so->fd, buf, len) != len) + { + so->errors = true; + } + } + } + + if (so->vout && !so->errors) + { + chomp(buf); + (*so->vout->func)(so->vout->arg, so->vout->flags_default, buf); + } } } bool -status_read (struct status_output *so, struct buffer *buf) +status_read(struct status_output *so, struct buffer *buf) { - bool ret = false; + bool ret = false; - if (so && so->fd >= 0 && (so->flags & STATUS_OUTPUT_READ)) + if (so && so->fd >= 0 && (so->flags & STATUS_OUTPUT_READ)) { - ASSERT (buf_defined (&so->read_buf)); - ASSERT (buf_defined (buf)); - while (true) - { - const int c = buf_read_u8 (&so->read_buf); + ASSERT(buf_defined(&so->read_buf)); + ASSERT(buf_defined(buf)); + while (true) + { + const int c = buf_read_u8(&so->read_buf); - /* read more of file into buffer */ - if (c == -1) - { - int len; + /* read more of file into buffer */ + if (c == -1) + { + int len; - ASSERT (buf_init (&so->read_buf, 0)); - len = read (so->fd, BPTR (&so->read_buf), BCAP (&so->read_buf)); - if (len <= 0) - break; + ASSERT(buf_init(&so->read_buf, 0)); + len = read(so->fd, BPTR(&so->read_buf), BCAP(&so->read_buf)); + if (len <= 0) + { + break; + } - ASSERT (buf_inc_len (&so->read_buf, len)); - continue; - } + ASSERT(buf_inc_len(&so->read_buf, len)); + continue; + } - ret = true; + ret = true; - if (c == '\r') - continue; + if (c == '\r') + { + continue; + } - if (c == '\n') - break; + if (c == '\n') + { + break; + } - buf_write_u8 (buf, c); - } + buf_write_u8(buf, c); + } - buf_null_terminate (buf); + buf_null_terminate(buf); } - return ret; + return ret; } diff --git a/src/openvpn/status.h b/src/openvpn/status.h index af16fd2a145..01fe33e730d 100644 --- a/src/openvpn/status.h +++ b/src/openvpn/status.h @@ -31,15 +31,15 @@ * virtual function interface for status output */ struct virtual_output { - void *arg; - unsigned int flags_default; - void (*func) (void *arg, const unsigned int flags, const char *str); + void *arg; + unsigned int flags_default; + void (*func) (void *arg, const unsigned int flags, const char *str); }; static inline void -virtual_output_print (const struct virtual_output *vo, const unsigned int flags, const char *str) +virtual_output_print(const struct virtual_output *vo, const unsigned int flags, const char *str) { - (*vo->func) (vo->arg, flags, str); + (*vo->func)(vo->arg, flags, str); } /* @@ -48,52 +48,61 @@ virtual_output_print (const struct virtual_output *vo, const unsigned int flags, struct status_output { -# define STATUS_OUTPUT_READ (1<<0) -# define STATUS_OUTPUT_WRITE (1<<1) - unsigned int flags; +#define STATUS_OUTPUT_READ (1<<0) +#define STATUS_OUTPUT_WRITE (1<<1) + unsigned int flags; - char *filename; - int fd; - int msglevel; - const struct virtual_output *vout; + char *filename; + int fd; + int msglevel; + const struct virtual_output *vout; - struct buffer read_buf; + struct buffer read_buf; - struct event_timeout et; + struct event_timeout et; - bool errors; + bool errors; }; -struct status_output *status_open (const char *filename, - const int refresh_freq, - const int msglevel, - const struct virtual_output *vout, - const unsigned int flags); - -bool status_trigger_tv (struct status_output *so, struct timeval *tv); -bool status_trigger (struct status_output *so); -void status_reset (struct status_output *so); -void status_flush (struct status_output *so); -bool status_close (struct status_output *so); -void status_printf (struct status_output *so, const char *format, ...) +struct status_output *status_open(const char *filename, + const int refresh_freq, + const int msglevel, + const struct virtual_output *vout, + const unsigned int flags); + +bool status_trigger_tv(struct status_output *so, struct timeval *tv); + +bool status_trigger(struct status_output *so); + +void status_reset(struct status_output *so); + +void status_flush(struct status_output *so); + +bool status_close(struct status_output *so); + +void status_printf(struct status_output *so, const char *format, ...) #ifdef __GNUC__ #if __USE_MINGW_ANSI_STDIO - __attribute__ ((format (gnu_printf, 2, 3))) +__attribute__ ((format(gnu_printf, 2, 3))) #else - __attribute__ ((format (__printf__, 2, 3))) +__attribute__ ((format(__printf__, 2, 3))) #endif #endif - ; +; -bool status_read (struct status_output *so, struct buffer *buf); +bool status_read(struct status_output *so, struct buffer *buf); static inline unsigned int -status_rw_flags (const struct status_output *so) +status_rw_flags(const struct status_output *so) { - if (so) - return so->flags; - else - return 0; + if (so) + { + return so->flags; + } + else + { + return 0; + } } -#endif +#endif /* ifndef STATUS_H */ diff --git a/src/openvpn/syshead.h b/src/openvpn/syshead.h index f5008b792bb..2f048966e9a 100644 --- a/src/openvpn/syshead.h +++ b/src/openvpn/syshead.h @@ -30,11 +30,11 @@ /* branch prediction hints */ #if defined(__GNUC__) -# define likely(x) __builtin_expect((x),1) -# define unlikely(x) __builtin_expect((x),0) +#define likely(x) __builtin_expect((x),1) +#define unlikely(x) __builtin_expect((x),0) #else -# define likely(x) (x) -# define unlikely(x) (x) +#define likely(x) (x) +#define unlikely(x) (x) #endif #ifdef _WIN32 @@ -45,7 +45,7 @@ #define srandom srand #endif -#ifdef _MSC_VER // Visual Studio +#ifdef _MSC_VER /* Visual Studio */ #define __func__ __FUNCTION__ #define __attribute__(x) #endif @@ -61,15 +61,15 @@ #endif #ifdef HAVE_SYS_WAIT_H -# include +#include #endif #ifndef _WIN32 #ifndef WEXITSTATUS -# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) +#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) #endif #ifndef WIFEXITED -# define WIFEXITED(stat_val) (((stat_val) & 255) == 0) +#define WIFEXITED(stat_val) (((stat_val) & 255) == 0) #endif #endif @@ -359,10 +359,10 @@ #endif /* TARGET_DARWIN */ #ifdef _WIN32 - // Missing declarations for MinGW 32. - // #if !defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 2 - typedef int MIB_TCP_STATE; - // #endif +/* Missing declarations for MinGW 32. */ +/* #if !defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 2 */ +typedef int MIB_TCP_STATE; +/* #endif */ #include #include #include @@ -385,12 +385,12 @@ * not to build a working executable. */ #ifdef PEDANTIC -# undef HAVE_CPP_VARARG_MACRO_GCC -# undef HAVE_CPP_VARARG_MACRO_ISO -# undef EMPTY_ARRAY_SIZE -# define EMPTY_ARRAY_SIZE 1 -# undef inline -# define inline +#undef HAVE_CPP_VARARG_MACRO_GCC +#undef HAVE_CPP_VARARG_MACRO_ISO +#undef EMPTY_ARRAY_SIZE +#define EMPTY_ARRAY_SIZE 1 +#undef inline +#define inline #endif /* @@ -422,7 +422,7 @@ * Does this platform support linux-style IP_PKTINFO * or bsd-style IP_RECVDSTADDR ? */ -#if defined(ENABLE_MULTIHOME) && ((defined(HAVE_IN_PKTINFO)&&defined(IP_PKTINFO)) || defined(IP_RECVDSTADDR)) && defined(HAVE_MSGHDR) && defined(HAVE_CMSGHDR) && defined(HAVE_IOVEC) && defined(CMSG_FIRSTHDR) && defined(CMSG_NXTHDR) && defined(HAVE_RECVMSG) && defined(HAVE_SENDMSG) +#if defined(ENABLE_MULTIHOME) && ((defined(HAVE_IN_PKTINFO) && defined(IP_PKTINFO)) || defined(IP_RECVDSTADDR)) && defined(HAVE_MSGHDR) && defined(HAVE_CMSGHDR) && defined(HAVE_IOVEC) && defined(CMSG_FIRSTHDR) && defined(CMSG_NXTHDR) && defined(HAVE_RECVMSG) && defined(HAVE_SENDMSG) #define ENABLE_IP_PKTINFO 1 #else #define ENABLE_IP_PKTINFO 0 @@ -488,9 +488,9 @@ typedef int socket_descriptor_t; #endif static inline int -socket_defined (const socket_descriptor_t sd) +socket_defined(const socket_descriptor_t sd) { - return sd != SOCKET_UNDEFINED; + return sd != SOCKET_UNDEFINED; } /* @@ -665,7 +665,7 @@ socket_defined (const socket_descriptor_t sd) #endif /* - * Do we have the capability to support the AUTO_USERID feature? + * Do we have the capability to support the AUTO_USERID feature? */ #if defined(ENABLE_AUTO_USERID) #define AUTO_USERID 1 @@ -690,8 +690,8 @@ socket_defined (const socket_descriptor_t sd) /* * Compression support */ -#if defined(ENABLE_LZO) || defined(ENABLE_LZ4) || \ - defined(ENABLE_COMP_STUB) +#if defined(ENABLE_LZO) || defined(ENABLE_LZ4) \ + || defined(ENABLE_COMP_STUB) #define USE_COMP #endif @@ -702,4 +702,4 @@ socket_defined (const socket_descriptor_t sd) #define ENABLE_MEMSTATS #endif -#endif +#endif /* ifndef SYSHEAD_H */ diff --git a/src/openvpn/tls_crypt.c b/src/openvpn/tls_crypt.c index d40532e89db..8173467d9ff 100644 --- a/src/openvpn/tls_crypt.c +++ b/src/openvpn/tls_crypt.c @@ -36,219 +36,220 @@ #include "tls_crypt.h" -int tls_crypt_buf_overhead(void) +int +tls_crypt_buf_overhead(void) { - return packet_id_size (true) + TLS_CRYPT_TAG_SIZE + TLS_CRYPT_BLOCK_SIZE; + return packet_id_size(true) + TLS_CRYPT_TAG_SIZE + TLS_CRYPT_BLOCK_SIZE; } void -tls_crypt_init_key (struct key_ctx_bi *key, const char *key_file, - const char *key_inline, bool tls_server) { - const int key_direction = tls_server ? - KEY_DIRECTION_NORMAL : KEY_DIRECTION_INVERSE; - - struct key_type kt; - kt.cipher = cipher_kt_get ("AES-256-CTR"); - kt.cipher_length = cipher_kt_key_size (kt.cipher); - kt.digest = md_kt_get ("SHA256"); - kt.hmac_length = md_kt_size (kt.digest); - - if (!kt.cipher) +tls_crypt_init_key(struct key_ctx_bi *key, const char *key_file, + const char *key_inline, bool tls_server) { + const int key_direction = tls_server ? + KEY_DIRECTION_NORMAL : KEY_DIRECTION_INVERSE; + + struct key_type kt; + kt.cipher = cipher_kt_get("AES-256-CTR"); + kt.cipher_length = cipher_kt_key_size(kt.cipher); + kt.digest = md_kt_get("SHA256"); + kt.hmac_length = md_kt_size(kt.digest); + + if (!kt.cipher) { - msg (M_FATAL, "ERROR: --tls-crypt requires AES-256-CTR support."); + msg(M_FATAL, "ERROR: --tls-crypt requires AES-256-CTR support."); } - if (!kt.digest) + if (!kt.digest) { - msg (M_FATAL, "ERROR: --tls-crypt requires HMAC-SHA-256 support."); + msg(M_FATAL, "ERROR: --tls-crypt requires HMAC-SHA-256 support."); } - crypto_read_openvpn_key (&kt, key, key_file, key_inline, key_direction, - "Control Channel Encryption", "tls-crypt"); + crypto_read_openvpn_key(&kt, key, key_file, key_inline, key_direction, + "Control Channel Encryption", "tls-crypt"); } void tls_crypt_adjust_frame_parameters(struct frame *frame) { - frame_add_to_extra_frame (frame, tls_crypt_buf_overhead()); + frame_add_to_extra_frame(frame, tls_crypt_buf_overhead()); - msg(D_MTU_DEBUG, "%s: Adjusting frame parameters for tls-crypt by %i bytes", - __func__, tls_crypt_buf_overhead()); + msg(D_MTU_DEBUG, "%s: Adjusting frame parameters for tls-crypt by %i bytes", + __func__, tls_crypt_buf_overhead()); } bool -tls_crypt_wrap (const struct buffer *src, struct buffer *dst, - struct crypto_options *opt) { - const struct key_ctx *ctx = &opt->key_ctx_bi.encrypt; - struct gc_arena gc; - - /* IV, packet-ID and implicit IV required for this mode. */ - ASSERT (ctx->cipher); - ASSERT (ctx->hmac); - ASSERT (packet_id_initialized(&opt->packet_id)); - ASSERT (hmac_ctx_size(ctx->hmac) == 256/8); - - gc_init (&gc); - - dmsg (D_PACKET_CONTENT, "TLS-CRYPT WRAP FROM: %s", - format_hex (BPTR (src), BLEN (src), 80, &gc)); - - /* Get packet ID */ - { - struct packet_id_net pin; - packet_id_alloc_outgoing (&opt->packet_id.send, &pin, true); - packet_id_write (&pin, dst, true, false); - } - - dmsg (D_PACKET_CONTENT, "TLS-CRYPT WRAP AD: %s", - format_hex (BPTR (dst), BLEN (dst), 0, &gc)); - - /* Buffer overflow check */ - if (!buf_safe (dst, BLEN (src) + TLS_CRYPT_BLOCK_SIZE + TLS_CRYPT_TAG_SIZE)) +tls_crypt_wrap(const struct buffer *src, struct buffer *dst, + struct crypto_options *opt) { + const struct key_ctx *ctx = &opt->key_ctx_bi.encrypt; + struct gc_arena gc; + + /* IV, packet-ID and implicit IV required for this mode. */ + ASSERT(ctx->cipher); + ASSERT(ctx->hmac); + ASSERT(packet_id_initialized(&opt->packet_id)); + ASSERT(hmac_ctx_size(ctx->hmac) == 256/8); + + gc_init(&gc); + + dmsg(D_PACKET_CONTENT, "TLS-CRYPT WRAP FROM: %s", + format_hex(BPTR(src), BLEN(src), 80, &gc)); + + /* Get packet ID */ { - msg (D_CRYPT_ERRORS, "TLS-CRYPT WRAP: buffer size error, " - "sc=%d so=%d sl=%d dc=%d do=%d dl=%d", src->capacity, src->offset, - src->len, dst->capacity, dst->offset, dst->len); - goto err; + struct packet_id_net pin; + packet_id_alloc_outgoing(&opt->packet_id.send, &pin, true); + packet_id_write(&pin, dst, true, false); } - /* Calculate auth tag and synthetic IV */ - { - uint8_t *tag = NULL; - hmac_ctx_reset (ctx->hmac); - hmac_ctx_update (ctx->hmac, BPTR (dst), BLEN (dst)); - hmac_ctx_update (ctx->hmac, BPTR (src), BLEN (src)); + dmsg(D_PACKET_CONTENT, "TLS-CRYPT WRAP AD: %s", + format_hex(BPTR(dst), BLEN(dst), 0, &gc)); + + /* Buffer overflow check */ + if (!buf_safe(dst, BLEN(src) + TLS_CRYPT_BLOCK_SIZE + TLS_CRYPT_TAG_SIZE)) + { + msg(D_CRYPT_ERRORS, "TLS-CRYPT WRAP: buffer size error, " + "sc=%d so=%d sl=%d dc=%d do=%d dl=%d", src->capacity, src->offset, + src->len, dst->capacity, dst->offset, dst->len); + goto err; + } + + /* Calculate auth tag and synthetic IV */ + { + uint8_t *tag = NULL; + hmac_ctx_reset(ctx->hmac); + hmac_ctx_update(ctx->hmac, BPTR(dst), BLEN(dst)); + hmac_ctx_update(ctx->hmac, BPTR(src), BLEN(src)); - ASSERT (tag = buf_write_alloc (dst, TLS_CRYPT_TAG_SIZE)); - hmac_ctx_final (ctx->hmac, tag); + ASSERT(tag = buf_write_alloc(dst, TLS_CRYPT_TAG_SIZE)); + hmac_ctx_final(ctx->hmac, tag); - dmsg (D_PACKET_CONTENT, "TLS-CRYPT WRAP TAG: %s", - format_hex (tag, TLS_CRYPT_TAG_SIZE, 0, &gc)); + dmsg(D_PACKET_CONTENT, "TLS-CRYPT WRAP TAG: %s", + format_hex(tag, TLS_CRYPT_TAG_SIZE, 0, &gc)); - /* Use the 128 most significant bits of the tag as IV */ - ASSERT (cipher_ctx_reset (ctx->cipher, tag)); - } + /* Use the 128 most significant bits of the tag as IV */ + ASSERT(cipher_ctx_reset(ctx->cipher, tag)); + } - /* Encrypt src */ - { - int outlen = 0; - ASSERT (cipher_ctx_update (ctx->cipher, BEND (dst), &outlen, - BPTR (src), BLEN(src))); - ASSERT (buf_inc_len (dst, outlen)); - ASSERT (cipher_ctx_final (ctx->cipher, BPTR (dst), &outlen)); - ASSERT (buf_inc_len (dst, outlen)); - } + /* Encrypt src */ + { + int outlen = 0; + ASSERT(cipher_ctx_update(ctx->cipher, BEND(dst), &outlen, + BPTR(src), BLEN(src))); + ASSERT(buf_inc_len(dst, outlen)); + ASSERT(cipher_ctx_final(ctx->cipher, BPTR(dst), &outlen)); + ASSERT(buf_inc_len(dst, outlen)); + } - dmsg (D_PACKET_CONTENT, "TLS-CRYPT WRAP TO: %s", - format_hex (BPTR (dst), BLEN (dst), 80, &gc)); + dmsg(D_PACKET_CONTENT, "TLS-CRYPT WRAP TO: %s", + format_hex(BPTR(dst), BLEN(dst), 80, &gc)); - gc_free (&gc); - return true; + gc_free(&gc); + return true; err: - crypto_clear_error(); - dst->len = 0; - gc_free (&gc); - return false; + crypto_clear_error(); + dst->len = 0; + gc_free(&gc); + return false; } bool -tls_crypt_unwrap (const struct buffer *src, struct buffer *dst, - struct crypto_options *opt) +tls_crypt_unwrap(const struct buffer *src, struct buffer *dst, + struct crypto_options *opt) { - static const char error_prefix[] = "tls-crypt unwrap error"; - const struct key_ctx *ctx = &opt->key_ctx_bi.decrypt; - struct gc_arena gc; + static const char error_prefix[] = "tls-crypt unwrap error"; + const struct key_ctx *ctx = &opt->key_ctx_bi.decrypt; + struct gc_arena gc; - gc_init (&gc); + gc_init(&gc); - ASSERT (opt); - ASSERT (src->len > 0); - ASSERT (ctx->cipher); - ASSERT (packet_id_initialized (&opt->packet_id) || - (opt->flags & CO_IGNORE_PACKET_ID)); + ASSERT(opt); + ASSERT(src->len > 0); + ASSERT(ctx->cipher); + ASSERT(packet_id_initialized(&opt->packet_id) + || (opt->flags & CO_IGNORE_PACKET_ID)); - dmsg (D_PACKET_CONTENT, "TLS-CRYPT UNWRAP FROM: %s", - format_hex (BPTR (src), BLEN (src), 80, &gc)); + dmsg(D_PACKET_CONTENT, "TLS-CRYPT UNWRAP FROM: %s", + format_hex(BPTR(src), BLEN(src), 80, &gc)); + + if (buf_len(src) < TLS_CRYPT_OFF_CT) + { + CRYPT_ERROR("packet too short"); + } + + /* Decrypt cipher text */ + { + int outlen = 0; + + /* Buffer overflow check (should never fail) */ + if (!buf_safe(dst, BLEN(src) - TLS_CRYPT_OFF_CT + TLS_CRYPT_BLOCK_SIZE)) + { + CRYPT_ERROR("potential buffer overflow"); + } + + if (!cipher_ctx_reset(ctx->cipher, BPTR(src) + TLS_CRYPT_OFF_TAG)) + { + CRYPT_ERROR("cipher reset failed"); + } + if (!cipher_ctx_update(ctx->cipher, BPTR(dst), &outlen, + BPTR(src) + TLS_CRYPT_OFF_CT, BLEN(src) - TLS_CRYPT_OFF_CT)) + { + CRYPT_ERROR("cipher update failed"); + } + ASSERT(buf_inc_len(dst, outlen)); + if (!cipher_ctx_final(ctx->cipher, BPTR(dst), &outlen)) + { + CRYPT_ERROR("cipher final failed"); + } + ASSERT(buf_inc_len(dst, outlen)); + } - if (buf_len (src) < TLS_CRYPT_OFF_CT) + /* Check authentication */ { - CRYPT_ERROR ("packet too short"); + const uint8_t *tag = BPTR(src) + TLS_CRYPT_OFF_TAG; + uint8_t tag_check[TLS_CRYPT_TAG_SIZE] = { 0 }; + + dmsg(D_PACKET_CONTENT, "TLS-CRYPT UNWRAP AD: %s", + format_hex(BPTR(src), TLS_CRYPT_OFF_TAG, 0, &gc)); + dmsg(D_PACKET_CONTENT, "TLS-CRYPT UNWRAP TO: %s", + format_hex(BPTR(dst), BLEN(dst), 80, &gc)); + + hmac_ctx_reset(ctx->hmac); + hmac_ctx_update(ctx->hmac, BPTR(src), TLS_CRYPT_OFF_TAG); + hmac_ctx_update(ctx->hmac, BPTR(dst), BLEN(dst)); + hmac_ctx_final(ctx->hmac, tag_check); + + if (memcmp_constant_time(tag, tag_check, sizeof(tag_check))) + { + dmsg(D_CRYPTO_DEBUG, "tag : %s", + format_hex(tag, sizeof(tag_check), 0, &gc)); + dmsg(D_CRYPTO_DEBUG, "tag_check: %s", + format_hex(tag_check, sizeof(tag_check), 0, &gc)); + CRYPT_ERROR("packet authentication failed"); + } } - /* Decrypt cipher text */ - { - int outlen = 0; - - /* Buffer overflow check (should never fail) */ - if (!buf_safe (dst, BLEN (src) - TLS_CRYPT_OFF_CT + TLS_CRYPT_BLOCK_SIZE)) - { - CRYPT_ERROR ("potential buffer overflow"); - } - - if (!cipher_ctx_reset (ctx->cipher, BPTR (src) + TLS_CRYPT_OFF_TAG)) - { - CRYPT_ERROR ("cipher reset failed"); - } - if (!cipher_ctx_update (ctx->cipher, BPTR (dst), &outlen, - BPTR (src) + TLS_CRYPT_OFF_CT, BLEN (src) - TLS_CRYPT_OFF_CT)) - { - CRYPT_ERROR ("cipher update failed"); - } - ASSERT (buf_inc_len (dst, outlen)); - if (!cipher_ctx_final (ctx->cipher, BPTR(dst), &outlen)) - { - CRYPT_ERROR ("cipher final failed"); - } - ASSERT (buf_inc_len (dst, outlen)); - } - - /* Check authentication */ - { - const uint8_t *tag = BPTR (src) + TLS_CRYPT_OFF_TAG; - uint8_t tag_check[TLS_CRYPT_TAG_SIZE] = { 0 }; - - dmsg (D_PACKET_CONTENT, "TLS-CRYPT UNWRAP AD: %s", - format_hex (BPTR (src), TLS_CRYPT_OFF_TAG, 0, &gc)); - dmsg (D_PACKET_CONTENT, "TLS-CRYPT UNWRAP TO: %s", - format_hex (BPTR (dst), BLEN (dst), 80, &gc)); - - hmac_ctx_reset (ctx->hmac); - hmac_ctx_update (ctx->hmac, BPTR (src), TLS_CRYPT_OFF_TAG); - hmac_ctx_update (ctx->hmac, BPTR (dst), BLEN (dst)); - hmac_ctx_final (ctx->hmac, tag_check); - - if (memcmp_constant_time (tag, tag_check, sizeof(tag_check))) - { - dmsg (D_CRYPTO_DEBUG, "tag : %s", - format_hex (tag, sizeof(tag_check), 0, &gc)); - dmsg (D_CRYPTO_DEBUG, "tag_check: %s", - format_hex (tag_check, sizeof(tag_check), 0, &gc)); - CRYPT_ERROR ("packet authentication failed"); - } - } - - /* Check replay */ - if (!(opt->flags & CO_IGNORE_PACKET_ID)) + /* Check replay */ + if (!(opt->flags & CO_IGNORE_PACKET_ID)) { - struct packet_id_net pin; - struct buffer tmp = *src; - ASSERT (buf_advance (&tmp, TLS_CRYPT_OFF_PID)); - ASSERT (packet_id_read (&pin, &tmp, true)); - if (!crypto_check_replay (opt, &pin, error_prefix, &gc)) - { - CRYPT_ERROR ("packet replay"); - } + struct packet_id_net pin; + struct buffer tmp = *src; + ASSERT(buf_advance(&tmp, TLS_CRYPT_OFF_PID)); + ASSERT(packet_id_read(&pin, &tmp, true)); + if (!crypto_check_replay(opt, &pin, error_prefix, &gc)) + { + CRYPT_ERROR("packet replay"); + } } - gc_free (&gc); - return true; + gc_free(&gc); + return true; - error_exit: - crypto_clear_error(); - dst->len = 0; - gc_free (&gc); - return false; +error_exit: + crypto_clear_error(); + dst->len = 0; + gc_free(&gc); + return false; } #endif /* EMABLE_CRYPTO */ diff --git a/src/openvpn/tls_crypt.h b/src/openvpn/tls_crypt.h index d1962c969c1..2c7831f5b3b 100644 --- a/src/openvpn/tls_crypt.h +++ b/src/openvpn/tls_crypt.h @@ -80,7 +80,7 @@ #include "session_id.h" #define TLS_CRYPT_TAG_SIZE (256/8) -#define TLS_CRYPT_PID_SIZE (sizeof (packet_id_type) + sizeof (net_time_t)) +#define TLS_CRYPT_PID_SIZE (sizeof(packet_id_type) + sizeof(net_time_t)) #define TLS_CRYPT_BLOCK_SIZE (128/8) #define TLS_CRYPT_OFF_PID (1 + SID_SIZE) @@ -90,15 +90,15 @@ /** * Initialize a key_ctx_bi structure for use with --tls-crypt. * - * @param key The key context to initialize - * @param key_file The file to read the key from (or the inline tag to - * indicate and inline key). - * @param key_inline Array containing (zero-terminated) inline key, or NULL - * if not used. - * @param tls_server Must be set to true is this is a TLS server instance. + * @param key The key context to initialize + * @param key_file The file to read the key from (or the inline tag to + * indicate and inline key). + * @param key_inline Array containing (zero-terminated) inline key, or NULL + * if not used. + * @param tls_server Must be set to true is this is a TLS server instance. */ -void tls_crypt_init_key (struct key_ctx_bi *key, const char *key_file, - const char *key_inline, bool tls_server); +void tls_crypt_init_key(struct key_ctx_bi *key, const char *key_file, + const char *key_inline, bool tls_server); /** * Returns the maximum overhead (in bytes) added to the destination buffer by @@ -114,30 +114,30 @@ void tls_crypt_adjust_frame_parameters(struct frame *frame); /** * Wrap a control channel packet (both authenticates and encrypts the data). * - * @param src Data to authenticate and encrypt. - * @param dst Any data present in this buffer is first authenticated, then - * the wrapped packet id and data from the src buffer are appended. - * Must have at least tls_crypt_buf_overhead()+BLEN(src) headroom. - * @param opt The crypto state for this --tls-crypt instance. + * @param src Data to authenticate and encrypt. + * @param dst Any data present in this buffer is first authenticated, then + * the wrapped packet id and data from the src buffer are appended. + * Must have at least tls_crypt_buf_overhead()+BLEN(src) headroom. + * @param opt The crypto state for this --tls-crypt instance. * * @returns true iff wrapping succeeded. */ -bool tls_crypt_wrap (const struct buffer *src, struct buffer *dst, - struct crypto_options *opt); +bool tls_crypt_wrap(const struct buffer *src, struct buffer *dst, + struct crypto_options *opt); /** * Unwrap a control channel packet (decrypts, authenticates and performs * replay checks). * - * @param src Data to decrypt and authenticate. - * @param dst Returns the decrypted data, if unwrapping was successful. - * @param opt The crypto state for this --tls-crypt instance. + * @param src Data to decrypt and authenticate. + * @param dst Returns the decrypted data, if unwrapping was successful. + * @param opt The crypto state for this --tls-crypt instance. * * @returns true iff unwrapping succeeded (data authenticated correctly and was * no replay). */ -bool tls_crypt_unwrap (const struct buffer *src, struct buffer *dst, - struct crypto_options *opt); +bool tls_crypt_unwrap(const struct buffer *src, struct buffer *dst, + struct crypto_options *opt); /** @} */ diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index 572e168b153..8dbdd4f9c53 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -63,150 +63,157 @@ #define NI_IP_NETMASK (1<<1) #define NI_OPTIONS (1<<2) -static void netsh_ifconfig (const struct tuntap_options *to, - const char *flex_name, - const in_addr_t ip, - const in_addr_t netmask, - const unsigned int flags); -static void netsh_set_dns6_servers (const struct in6_addr *addr_list, - const int addr_len, - const char *flex_name); -static void netsh_command (const struct argv *a, int n, int msglevel); +static void netsh_ifconfig(const struct tuntap_options *to, + const char *flex_name, + const in_addr_t ip, + const in_addr_t netmask, + const unsigned int flags); -static const char *netsh_get_id (const char *dev_node, struct gc_arena *gc); +static void netsh_set_dns6_servers(const struct in6_addr *addr_list, + const int addr_len, + const char *flex_name); -static DWORD get_adapter_index_flexible (const char *name); +static void netsh_command(const struct argv *a, int n, int msglevel); + +static const char *netsh_get_id(const char *dev_node, struct gc_arena *gc); + +static DWORD get_adapter_index_flexible(const char *name); static bool -do_address_service (const bool add, const short family, const struct tuntap *tt) +do_address_service(const bool add, const short family, const struct tuntap *tt) { - DWORD len; - bool ret = false; - ack_message_t ack; - struct gc_arena gc = gc_new (); - HANDLE pipe = tt->options.msg_channel; + DWORD len; + bool ret = false; + ack_message_t ack; + struct gc_arena gc = gc_new(); + HANDLE pipe = tt->options.msg_channel; - address_message_t addr = { - .header = { - (add ? msg_add_address : msg_del_address), - sizeof (address_message_t), - 0 }, - .family = family, - .iface = { .index = tt->adapter_index, .name = "" } - }; + address_message_t addr = { + .header = { + (add ? msg_add_address : msg_del_address), + sizeof(address_message_t), + 0 + }, + .family = family, + .iface = { .index = tt->adapter_index, .name = "" } + }; - if (addr.iface.index == TUN_ADAPTER_INDEX_INVALID) + if (addr.iface.index == TUN_ADAPTER_INDEX_INVALID) { - strncpy (addr.iface.name, tt->actual_name, sizeof (addr.iface.name)); - addr.iface.name[sizeof (addr.iface.name) - 1] = '\0'; + strncpy(addr.iface.name, tt->actual_name, sizeof(addr.iface.name)); + addr.iface.name[sizeof(addr.iface.name) - 1] = '\0'; } - if (addr.family == AF_INET) + if (addr.family == AF_INET) { - addr.address.ipv4.s_addr = tt->local; - addr.prefix_len = 32; + addr.address.ipv4.s_addr = tt->local; + addr.prefix_len = 32; } - else + else { - addr.address.ipv6 = tt->local_ipv6; - addr.prefix_len = tt->netbits_ipv6; + addr.address.ipv6 = tt->local_ipv6; + addr.prefix_len = tt->netbits_ipv6; } - if (!WriteFile (pipe, &addr, sizeof (addr), &len, NULL) || - !ReadFile (pipe, &ack, sizeof (ack), &len, NULL)) + if (!WriteFile(pipe, &addr, sizeof(addr), &len, NULL) + || !ReadFile(pipe, &ack, sizeof(ack), &len, NULL)) { - msg (M_WARN, "TUN: could not talk to service: %s [%lu]", - strerror_win32 (GetLastError (), &gc), GetLastError ()); - goto out; + msg(M_WARN, "TUN: could not talk to service: %s [%lu]", + strerror_win32(GetLastError(), &gc), GetLastError()); + goto out; } - if (ack.error_number != NO_ERROR) + if (ack.error_number != NO_ERROR) { - msg (M_WARN, "TUN: %s address failed using service: %s [status=%u if_index=%lu]", - (add ? "adding" : "deleting"), strerror_win32 (ack.error_number, &gc), - ack.error_number, addr.iface.index); - goto out; + msg(M_WARN, "TUN: %s address failed using service: %s [status=%u if_index=%lu]", + (add ? "adding" : "deleting"), strerror_win32(ack.error_number, &gc), + ack.error_number, addr.iface.index); + goto out; } - ret = true; + ret = true; out: - gc_free (&gc); - return ret; + gc_free(&gc); + return ret; } static bool -do_dns6_service (bool add, const struct tuntap *tt) +do_dns6_service(bool add, const struct tuntap *tt) { - DWORD len; - bool ret = false; - ack_message_t ack; - struct gc_arena gc = gc_new (); - HANDLE pipe = tt->options.msg_channel; - int addr_len = add ? tt->options.dns6_len : 0; + DWORD len; + bool ret = false; + ack_message_t ack; + struct gc_arena gc = gc_new(); + HANDLE pipe = tt->options.msg_channel; + int addr_len = add ? tt->options.dns6_len : 0; - if (addr_len == 0 && add) /* no addresses to add */ - return true; + if (addr_len == 0 && add) /* no addresses to add */ + { + return true; + } - dns_cfg_message_t dns = { - .header = { - (add ? msg_add_dns_cfg : msg_del_dns_cfg), - sizeof (dns_cfg_message_t), - 0 }, - .iface = { .index = tt->adapter_index, .name = "" }, - .domains = "", - .family = AF_INET6, - .addr_len = addr_len - }; + dns_cfg_message_t dns = { + .header = { + (add ? msg_add_dns_cfg : msg_del_dns_cfg), + sizeof(dns_cfg_message_t), + 0 + }, + .iface = { .index = tt->adapter_index, .name = "" }, + .domains = "", + .family = AF_INET6, + .addr_len = addr_len + }; - /* interface name is required */ - strncpy (dns.iface.name, tt->actual_name, sizeof (dns.iface.name)); - dns.iface.name[sizeof (dns.iface.name) - 1] = '\0'; + /* interface name is required */ + strncpy(dns.iface.name, tt->actual_name, sizeof(dns.iface.name)); + dns.iface.name[sizeof(dns.iface.name) - 1] = '\0'; - if (addr_len > _countof(dns.addr)) + if (addr_len > _countof(dns.addr)) { - addr_len = _countof(dns.addr); - dns.addr_len = addr_len; - msg(M_WARN, "Number of IPv6 DNS addresses sent to service truncated to %d", - addr_len); + addr_len = _countof(dns.addr); + dns.addr_len = addr_len; + msg(M_WARN, "Number of IPv6 DNS addresses sent to service truncated to %d", + addr_len); } - for (int i = 0; i < addr_len; ++i) + for (int i = 0; i < addr_len; ++i) { - dns.addr[i].ipv6 = tt->options.dns6[i]; + dns.addr[i].ipv6 = tt->options.dns6[i]; } - msg (D_LOW, "%s IPv6 dns servers on '%s' (if_index = %d) using service", - (add ? "Setting" : "Deleting"), dns.iface.name, dns.iface.index); + msg(D_LOW, "%s IPv6 dns servers on '%s' (if_index = %d) using service", + (add ? "Setting" : "Deleting"), dns.iface.name, dns.iface.index); - if (!WriteFile (pipe, &dns, sizeof (dns), &len, NULL) || - !ReadFile (pipe, &ack, sizeof (ack), &len, NULL)) + if (!WriteFile(pipe, &dns, sizeof(dns), &len, NULL) + || !ReadFile(pipe, &ack, sizeof(ack), &len, NULL)) { - msg (M_WARN, "TUN: could not talk to service: %s [%lu]", - strerror_win32 (GetLastError (), &gc), GetLastError ()); - goto out; + msg(M_WARN, "TUN: could not talk to service: %s [%lu]", + strerror_win32(GetLastError(), &gc), GetLastError()); + goto out; } - if (ack.error_number != NO_ERROR) + if (ack.error_number != NO_ERROR) { - msg (M_WARN, "TUN: %s IPv6 dns failed using service: %s [status=%u if_name=%s]", - (add ? "adding" : "deleting"), strerror_win32 (ack.error_number, &gc), - ack.error_number, dns.iface.name); - goto out; + msg(M_WARN, "TUN: %s IPv6 dns failed using service: %s [status=%u if_name=%s]", + (add ? "adding" : "deleting"), strerror_win32(ack.error_number, &gc), + ack.error_number, dns.iface.name); + goto out; } - msg (M_INFO, "IPv6 dns servers %s using service", (add ? "set" : "deleted")); - ret = true; + msg(M_INFO, "IPv6 dns servers %s using service", (add ? "set" : "deleted")); + ret = true; out: - gc_free (&gc); - return ret; + gc_free(&gc); + return ret; } -#endif +#endif /* ifdef _WIN32 */ #ifdef TARGET_SOLARIS -static void solaris_error_close (struct tuntap *tt, const struct env_set *es, const char *actual, bool unplumb_inet6); +static void solaris_error_close(struct tuntap *tt, const struct env_set *es, const char *actual, bool unplumb_inet6); + #include #endif @@ -216,46 +223,63 @@ static void solaris_error_close (struct tuntap *tt, const struct env_set *es, co #include #endif -static void clear_tuntap (struct tuntap *tuntap); +static void clear_tuntap(struct tuntap *tuntap); bool -is_dev_type (const char *dev, const char *dev_type, const char *match_type) +is_dev_type(const char *dev, const char *dev_type, const char *match_type) { - ASSERT (match_type); - if (!dev) - return false; - if (dev_type) - return !strcmp (dev_type, match_type); - else - return !strncmp (dev, match_type, strlen (match_type)); + ASSERT(match_type); + if (!dev) + { + return false; + } + if (dev_type) + { + return !strcmp(dev_type, match_type); + } + else + { + return !strncmp(dev, match_type, strlen(match_type)); + } } int -dev_type_enum (const char *dev, const char *dev_type) +dev_type_enum(const char *dev, const char *dev_type) { - if (is_dev_type (dev, dev_type, "tun")) - return DEV_TYPE_TUN; - else if (is_dev_type (dev, dev_type, "tap")) - return DEV_TYPE_TAP; - else if (is_dev_type (dev, dev_type, "null")) - return DEV_TYPE_NULL; - else - return DEV_TYPE_UNDEF; + if (is_dev_type(dev, dev_type, "tun")) + { + return DEV_TYPE_TUN; + } + else if (is_dev_type(dev, dev_type, "tap")) + { + return DEV_TYPE_TAP; + } + else if (is_dev_type(dev, dev_type, "null")) + { + return DEV_TYPE_NULL; + } + else + { + return DEV_TYPE_UNDEF; + } } const char * -dev_type_string (const char *dev, const char *dev_type) +dev_type_string(const char *dev, const char *dev_type) { - switch (dev_type_enum (dev, dev_type)) + switch (dev_type_enum(dev, dev_type)) { - case DEV_TYPE_TUN: - return "tun"; - case DEV_TYPE_TAP: - return "tap"; - case DEV_TYPE_NULL: - return "null"; - default: - return "[unknown-dev-type]"; + case DEV_TYPE_TUN: + return "tun"; + + case DEV_TYPE_TAP: + return "tap"; + + case DEV_TYPE_NULL: + return "null"; + + default: + return "[unknown-dev-type]"; } } @@ -264,21 +288,21 @@ dev_type_string (const char *dev, const char *dev_type) * before the device is actually opened. */ const char * -guess_tuntap_dev (const char *dev, - const char *dev_type, - const char *dev_node, - struct gc_arena *gc) +guess_tuntap_dev(const char *dev, + const char *dev_type, + const char *dev_node, + struct gc_arena *gc) { #ifdef _WIN32 - const int dt = dev_type_enum (dev, dev_type); - if (dt == DEV_TYPE_TUN || dt == DEV_TYPE_TAP) + const int dt = dev_type_enum(dev, dev_type); + if (dt == DEV_TYPE_TUN || dt == DEV_TYPE_TAP) { - return netsh_get_id (dev_node, gc); + return netsh_get_id(dev_node, gc); } #endif - /* default case */ - return dev; + /* default case */ + return dev; } @@ -293,34 +317,38 @@ static const char ifconfig_warn_how_to_silence[] = "(silence this warning with - * like an IPv4 address. */ static void -ifconfig_sanity_check (bool tun, in_addr_t addr, int topology) +ifconfig_sanity_check(bool tun, in_addr_t addr, int topology) { - struct gc_arena gc = gc_new (); - const bool looks_like_netmask = ((addr & 0xFF000000) == 0xFF000000); - if (tun) + struct gc_arena gc = gc_new(); + const bool looks_like_netmask = ((addr & 0xFF000000) == 0xFF000000); + if (tun) { - if (looks_like_netmask && (topology == TOP_NET30 || topology == TOP_P2P)) - msg (M_WARN, "WARNING: Since you are using --dev tun with a point-to-point topology, the second argument to --ifconfig must be an IP address. You are using something (%s) that looks more like a netmask. %s", - print_in_addr_t (addr, 0, &gc), - ifconfig_warn_how_to_silence); + if (looks_like_netmask && (topology == TOP_NET30 || topology == TOP_P2P)) + { + msg(M_WARN, "WARNING: Since you are using --dev tun with a point-to-point topology, the second argument to --ifconfig must be an IP address. You are using something (%s) that looks more like a netmask. %s", + print_in_addr_t(addr, 0, &gc), + ifconfig_warn_how_to_silence); + } } - else /* tap */ + else /* tap */ { - if (!looks_like_netmask) - msg (M_WARN, "WARNING: Since you are using --dev tap, the second argument to --ifconfig must be a netmask, for example something like 255.255.255.0. %s", - ifconfig_warn_how_to_silence); + if (!looks_like_netmask) + { + msg(M_WARN, "WARNING: Since you are using --dev tap, the second argument to --ifconfig must be a netmask, for example something like 255.255.255.0. %s", + ifconfig_warn_how_to_silence); + } } - gc_free (&gc); + gc_free(&gc); } /* * For TAP-style devices, generate a broadcast address. */ static in_addr_t -generate_ifconfig_broadcast_addr (in_addr_t local, - in_addr_t netmask) +generate_ifconfig_broadcast_addr(in_addr_t local, + in_addr_t netmask) { - return local | ~netmask; + return local | ~netmask; } /* @@ -328,63 +356,69 @@ generate_ifconfig_broadcast_addr (in_addr_t local, * clash with ifconfig addresses or subnet. */ static void -check_addr_clash (const char *name, - int type, - in_addr_t public, - in_addr_t local, - in_addr_t remote_netmask) +check_addr_clash(const char *name, + int type, + in_addr_t public, + in_addr_t local, + in_addr_t remote_netmask) { - struct gc_arena gc = gc_new (); + struct gc_arena gc = gc_new(); #if 0 - msg (M_INFO, "CHECK_ADDR_CLASH type=%d public=%s local=%s, remote_netmask=%s", - type, - print_in_addr_t (public, 0, &gc), - print_in_addr_t (local, 0, &gc), - print_in_addr_t (remote_netmask, 0, &gc)); + msg(M_INFO, "CHECK_ADDR_CLASH type=%d public=%s local=%s, remote_netmask=%s", + type, + print_in_addr_t(public, 0, &gc), + print_in_addr_t(local, 0, &gc), + print_in_addr_t(remote_netmask, 0, &gc)); #endif - if (public) - { - if (type == DEV_TYPE_TUN) - { - const in_addr_t test_netmask = 0xFFFFFF00; - const in_addr_t public_net = public & test_netmask; - const in_addr_t local_net = local & test_netmask; - const in_addr_t remote_net = remote_netmask & test_netmask; - - if (public == local || public == remote_netmask) - msg (M_WARN, - "WARNING: --%s address [%s] conflicts with --ifconfig address pair [%s, %s]. %s", - name, - print_in_addr_t (public, 0, &gc), - print_in_addr_t (local, 0, &gc), - print_in_addr_t (remote_netmask, 0, &gc), - ifconfig_warn_how_to_silence); - - if (public_net == local_net || public_net == remote_net) - msg (M_WARN, - "WARNING: potential conflict between --%s address [%s] and --ifconfig address pair [%s, %s] -- this is a warning only that is triggered when local/remote addresses exist within the same /24 subnet as --ifconfig endpoints. %s", - name, - print_in_addr_t (public, 0, &gc), - print_in_addr_t (local, 0, &gc), - print_in_addr_t (remote_netmask, 0, &gc), - ifconfig_warn_how_to_silence); - } - else if (type == DEV_TYPE_TAP) - { - const in_addr_t public_network = public & remote_netmask; - const in_addr_t virtual_network = local & remote_netmask; - if (public_network == virtual_network) - msg (M_WARN, - "WARNING: --%s address [%s] conflicts with --ifconfig subnet [%s, %s] -- local and remote addresses cannot be inside of the --ifconfig subnet. %s", - name, - print_in_addr_t (public, 0, &gc), - print_in_addr_t (local, 0, &gc), - print_in_addr_t (remote_netmask, 0, &gc), - ifconfig_warn_how_to_silence); - } - } - gc_free (&gc); + if (public) + { + if (type == DEV_TYPE_TUN) + { + const in_addr_t test_netmask = 0xFFFFFF00; + const in_addr_t public_net = public & test_netmask; + const in_addr_t local_net = local & test_netmask; + const in_addr_t remote_net = remote_netmask & test_netmask; + + if (public == local || public == remote_netmask) + { + msg(M_WARN, + "WARNING: --%s address [%s] conflicts with --ifconfig address pair [%s, %s]. %s", + name, + print_in_addr_t(public, 0, &gc), + print_in_addr_t(local, 0, &gc), + print_in_addr_t(remote_netmask, 0, &gc), + ifconfig_warn_how_to_silence); + } + + if (public_net == local_net || public_net == remote_net) + { + msg(M_WARN, + "WARNING: potential conflict between --%s address [%s] and --ifconfig address pair [%s, %s] -- this is a warning only that is triggered when local/remote addresses exist within the same /24 subnet as --ifconfig endpoints. %s", + name, + print_in_addr_t(public, 0, &gc), + print_in_addr_t(local, 0, &gc), + print_in_addr_t(remote_netmask, 0, &gc), + ifconfig_warn_how_to_silence); + } + } + else if (type == DEV_TYPE_TAP) + { + const in_addr_t public_network = public & remote_netmask; + const in_addr_t virtual_network = local & remote_netmask; + if (public_network == virtual_network) + { + msg(M_WARN, + "WARNING: --%s address [%s] conflicts with --ifconfig subnet [%s, %s] -- local and remote addresses cannot be inside of the --ifconfig subnet. %s", + name, + print_in_addr_t(public, 0, &gc), + print_in_addr_t(local, 0, &gc), + print_in_addr_t(remote_netmask, 0, &gc), + ifconfig_warn_how_to_silence); + } + } + } + gc_free(&gc); } /* @@ -395,51 +429,53 @@ check_addr_clash (const char *name, * off of a router set to 192.168.1.x. */ void -check_subnet_conflict (const in_addr_t ip, - const in_addr_t netmask, - const char *prefix) +check_subnet_conflict(const in_addr_t ip, + const in_addr_t netmask, + const char *prefix) { #if 0 /* too many false positives */ - struct gc_arena gc = gc_new (); - in_addr_t lan_gw = 0; - in_addr_t lan_netmask = 0; - - if (get_default_gateway (&lan_gw, &lan_netmask) && lan_netmask) - { - const in_addr_t lan_network = lan_gw & lan_netmask; - const in_addr_t network = ip & netmask; - - /* do the two subnets defined by network/netmask and lan_network/lan_netmask intersect? */ - if ((network & lan_netmask) == lan_network - || (lan_network & netmask) == network) - { - msg (M_WARN, "WARNING: potential %s subnet conflict between local LAN [%s/%s] and remote VPN [%s/%s]", - prefix, - print_in_addr_t (lan_network, 0, &gc), - print_in_addr_t (lan_netmask, 0, &gc), - print_in_addr_t (network, 0, &gc), - print_in_addr_t (netmask, 0, &gc)); - } - } - gc_free (&gc); -#endif + struct gc_arena gc = gc_new(); + in_addr_t lan_gw = 0; + in_addr_t lan_netmask = 0; + + if (get_default_gateway(&lan_gw, &lan_netmask) && lan_netmask) + { + const in_addr_t lan_network = lan_gw & lan_netmask; + const in_addr_t network = ip & netmask; + + /* do the two subnets defined by network/netmask and lan_network/lan_netmask intersect? */ + if ((network & lan_netmask) == lan_network + || (lan_network & netmask) == network) + { + msg(M_WARN, "WARNING: potential %s subnet conflict between local LAN [%s/%s] and remote VPN [%s/%s]", + prefix, + print_in_addr_t(lan_network, 0, &gc), + print_in_addr_t(lan_netmask, 0, &gc), + print_in_addr_t(network, 0, &gc), + print_in_addr_t(netmask, 0, &gc)); + } + } + gc_free(&gc); +#endif /* if 0 */ } void -warn_on_use_of_common_subnets (void) +warn_on_use_of_common_subnets(void) { - struct gc_arena gc = gc_new (); - struct route_gateway_info rgi; - const int needed = (RGI_ADDR_DEFINED|RGI_NETMASK_DEFINED); + struct gc_arena gc = gc_new(); + struct route_gateway_info rgi; + const int needed = (RGI_ADDR_DEFINED|RGI_NETMASK_DEFINED); - get_default_gateway (&rgi); - if ((rgi.flags & needed) == needed) + get_default_gateway(&rgi); + if ((rgi.flags & needed) == needed) { - const in_addr_t lan_network = rgi.gateway.addr & rgi.gateway.netmask; - if (lan_network == 0xC0A80000 || lan_network == 0xC0A80100) - msg (M_WARN, "NOTE: your local LAN uses the extremely common subnet address 192.168.0.x or 192.168.1.x. Be aware that this might create routing conflicts if you connect to the VPN server from public locations such as internet cafes that use the same subnet."); + const in_addr_t lan_network = rgi.gateway.addr & rgi.gateway.netmask; + if (lan_network == 0xC0A80000 || lan_network == 0xC0A80100) + { + msg(M_WARN, "NOTE: your local LAN uses the extremely common subnet address 192.168.0.x or 192.168.1.x. Be aware that this might create routing conflicts if you connect to the VPN server from public locations such as internet cafes that use the same subnet."); + } } - gc_free (&gc); + gc_free(&gc); } /* @@ -447,132 +483,140 @@ warn_on_use_of_common_subnets (void) * between peers. */ const char * -ifconfig_options_string (const struct tuntap* tt, bool remote, bool disable, struct gc_arena *gc) -{ - struct buffer out = alloc_buf_gc (256, gc); - if (tt->did_ifconfig_setup && !disable) - { - if (tt->type == DEV_TYPE_TAP || (tt->type == DEV_TYPE_TUN && tt->topology == TOP_SUBNET)) - { - buf_printf (&out, "%s %s", - print_in_addr_t (tt->local & tt->remote_netmask, 0, gc), - print_in_addr_t (tt->remote_netmask, 0, gc)); - } - else if (tt->type == DEV_TYPE_TUN) - { - const char *l, *r; - if (remote) - { - r = print_in_addr_t (tt->local, 0, gc); - l = print_in_addr_t (tt->remote_netmask, 0, gc); - } - else - { - l = print_in_addr_t (tt->local, 0, gc); - r = print_in_addr_t (tt->remote_netmask, 0, gc); - } - buf_printf (&out, "%s %s", r, l); - } - else - buf_printf (&out, "[undef]"); - } - return BSTR (&out); +ifconfig_options_string(const struct tuntap *tt, bool remote, bool disable, struct gc_arena *gc) +{ + struct buffer out = alloc_buf_gc(256, gc); + if (tt->did_ifconfig_setup && !disable) + { + if (tt->type == DEV_TYPE_TAP || (tt->type == DEV_TYPE_TUN && tt->topology == TOP_SUBNET)) + { + buf_printf(&out, "%s %s", + print_in_addr_t(tt->local & tt->remote_netmask, 0, gc), + print_in_addr_t(tt->remote_netmask, 0, gc)); + } + else if (tt->type == DEV_TYPE_TUN) + { + const char *l, *r; + if (remote) + { + r = print_in_addr_t(tt->local, 0, gc); + l = print_in_addr_t(tt->remote_netmask, 0, gc); + } + else + { + l = print_in_addr_t(tt->local, 0, gc); + r = print_in_addr_t(tt->remote_netmask, 0, gc); + } + buf_printf(&out, "%s %s", r, l); + } + else + { + buf_printf(&out, "[undef]"); + } + } + return BSTR(&out); } /* * Return a status string describing wait state. */ const char * -tun_stat (const struct tuntap *tt, unsigned int rwflags, struct gc_arena *gc) +tun_stat(const struct tuntap *tt, unsigned int rwflags, struct gc_arena *gc) { - struct buffer out = alloc_buf_gc (64, gc); - if (tt) + struct buffer out = alloc_buf_gc(64, gc); + if (tt) { - if (rwflags & EVENT_READ) - { - buf_printf (&out, "T%s", - (tt->rwflags_debug & EVENT_READ) ? "R" : "r"); + if (rwflags & EVENT_READ) + { + buf_printf(&out, "T%s", + (tt->rwflags_debug & EVENT_READ) ? "R" : "r"); #ifdef _WIN32 - buf_printf (&out, "%s", - overlapped_io_state_ascii (&tt->reads)); + buf_printf(&out, "%s", + overlapped_io_state_ascii(&tt->reads)); #endif - } - if (rwflags & EVENT_WRITE) - { - buf_printf (&out, "T%s", - (tt->rwflags_debug & EVENT_WRITE) ? "W" : "w"); + } + if (rwflags & EVENT_WRITE) + { + buf_printf(&out, "T%s", + (tt->rwflags_debug & EVENT_WRITE) ? "W" : "w"); #ifdef _WIN32 - buf_printf (&out, "%s", - overlapped_io_state_ascii (&tt->writes)); + buf_printf(&out, "%s", + overlapped_io_state_ascii(&tt->writes)); #endif - } + } } - else + else { - buf_printf (&out, "T?"); + buf_printf(&out, "T?"); } - return BSTR (&out); + return BSTR(&out); } /* * Return true for point-to-point topology, false for subnet topology */ bool -is_tun_p2p (const struct tuntap *tt) +is_tun_p2p(const struct tuntap *tt) { - bool tun = false; + bool tun = false; - if (tt->type == DEV_TYPE_TAP || (tt->type == DEV_TYPE_TUN && tt->topology == TOP_SUBNET)) - tun = false; - else if (tt->type == DEV_TYPE_TUN) - tun = true; - else - msg (M_FATAL, "Error: problem with tun vs. tap setting"); /* JYFIXME -- needs to be caught earlier, in init_tun? */ + if (tt->type == DEV_TYPE_TAP || (tt->type == DEV_TYPE_TUN && tt->topology == TOP_SUBNET)) + { + tun = false; + } + else if (tt->type == DEV_TYPE_TUN) + { + tun = true; + } + else + { + msg(M_FATAL, "Error: problem with tun vs. tap setting"); /* JYFIXME -- needs to be caught earlier, in init_tun? */ - return tun; + } + return tun; } /* * Set the ifconfig_* environment variables, both for IPv4 and IPv6 */ void -do_ifconfig_setenv (const struct tuntap *tt, struct env_set *es) +do_ifconfig_setenv(const struct tuntap *tt, struct env_set *es) { - struct gc_arena gc = gc_new (); - const char *ifconfig_local = print_in_addr_t (tt->local, 0, &gc); - const char *ifconfig_remote_netmask = print_in_addr_t (tt->remote_netmask, 0, &gc); + struct gc_arena gc = gc_new(); + const char *ifconfig_local = print_in_addr_t(tt->local, 0, &gc); + const char *ifconfig_remote_netmask = print_in_addr_t(tt->remote_netmask, 0, &gc); /* * Set environmental variables with ifconfig parameters. */ if (tt->did_ifconfig_setup) { - bool tun = is_tun_p2p (tt); + bool tun = is_tun_p2p(tt); - setenv_str (es, "ifconfig_local", ifconfig_local); - if (tun) - { - setenv_str (es, "ifconfig_remote", ifconfig_remote_netmask); - } - else - { - const char *ifconfig_broadcast = print_in_addr_t (tt->broadcast, 0, &gc); - setenv_str (es, "ifconfig_netmask", ifconfig_remote_netmask); - setenv_str (es, "ifconfig_broadcast", ifconfig_broadcast); - } + setenv_str(es, "ifconfig_local", ifconfig_local); + if (tun) + { + setenv_str(es, "ifconfig_remote", ifconfig_remote_netmask); + } + else + { + const char *ifconfig_broadcast = print_in_addr_t(tt->broadcast, 0, &gc); + setenv_str(es, "ifconfig_netmask", ifconfig_remote_netmask); + setenv_str(es, "ifconfig_broadcast", ifconfig_broadcast); + } } if (tt->did_ifconfig_ipv6_setup) { - const char *ifconfig_ipv6_local = print_in6_addr (tt->local_ipv6, 0, &gc); - const char *ifconfig_ipv6_remote = print_in6_addr (tt->remote_ipv6, 0, &gc); + const char *ifconfig_ipv6_local = print_in6_addr(tt->local_ipv6, 0, &gc); + const char *ifconfig_ipv6_remote = print_in6_addr(tt->remote_ipv6, 0, &gc); - setenv_str (es, "ifconfig_ipv6_local", ifconfig_ipv6_local); - setenv_int (es, "ifconfig_ipv6_netbits", tt->netbits_ipv6); - setenv_str (es, "ifconfig_ipv6_remote", ifconfig_ipv6_remote); + setenv_str(es, "ifconfig_ipv6_local", ifconfig_ipv6_local); + setenv_int(es, "ifconfig_ipv6_netbits", tt->netbits_ipv6); + setenv_str(es, "ifconfig_ipv6_remote", ifconfig_ipv6_remote); } - gc_free (&gc); + gc_free(&gc); } /* @@ -582,179 +626,191 @@ do_ifconfig_setenv (const struct tuntap *tt, struct env_set *es) * but don't execute yet. */ struct tuntap * -init_tun (const char *dev, /* --dev option */ - const char *dev_type, /* --dev-type option */ - int topology, /* one of the TOP_x values */ - const char *ifconfig_local_parm, /* --ifconfig parm 1 */ - const char *ifconfig_remote_netmask_parm, /* --ifconfig parm 2 */ - const char *ifconfig_ipv6_local_parm, /* --ifconfig parm 1 IPv6 */ - int ifconfig_ipv6_netbits_parm, - const char *ifconfig_ipv6_remote_parm, /* --ifconfig parm 2 IPv6 */ - struct addrinfo *local_public, - struct addrinfo *remote_public, - const bool strict_warn, - struct env_set *es) -{ - struct gc_arena gc = gc_new (); - struct tuntap *tt; - - ALLOC_OBJ (tt, struct tuntap); - clear_tuntap (tt); - - tt->type = dev_type_enum (dev, dev_type); - tt->topology = topology; - - if (ifconfig_local_parm && ifconfig_remote_netmask_parm) - { - bool tun = false; - - /* - * We only handle TUN/TAP devices here, not --dev null devices. - */ - tun = is_tun_p2p (tt); - - /* - * Convert arguments to binary IPv4 addresses. - */ - - tt->local = getaddr ( - GETADDR_RESOLVE - | GETADDR_HOST_ORDER - | GETADDR_FATAL_ON_SIGNAL - | GETADDR_FATAL, - ifconfig_local_parm, - 0, - NULL, - NULL); - - tt->remote_netmask = getaddr ( - (tun ? GETADDR_RESOLVE : 0) - | GETADDR_HOST_ORDER - | GETADDR_FATAL_ON_SIGNAL - | GETADDR_FATAL, - ifconfig_remote_netmask_parm, - 0, - NULL, - NULL); - - /* - * Look for common errors in --ifconfig parms - */ - if (strict_warn) - { - struct addrinfo *curele; - ifconfig_sanity_check (tt->type == DEV_TYPE_TUN, tt->remote_netmask, tt->topology); - - /* - * If local_public or remote_public addresses are defined, - * make sure they do not clash with our virtual subnet. - */ - - for(curele=local_public;curele;curele=curele->ai_next) { - if(curele->ai_family == AF_INET) - check_addr_clash ("local", - tt->type, - ((struct sockaddr_in*)curele->ai_addr)->sin_addr.s_addr, - tt->local, - tt->remote_netmask); - } - - for (curele=remote_public;curele;curele=curele->ai_next) { - if (curele->ai_family == AF_INET) - check_addr_clash ("remote", - tt->type, - ((struct sockaddr_in*)curele->ai_addr)->sin_addr.s_addr, - tt->local, - tt->remote_netmask); - } - - if (tt->type == DEV_TYPE_TAP || (tt->type == DEV_TYPE_TUN && tt->topology == TOP_SUBNET)) - check_subnet_conflict (tt->local, tt->remote_netmask, "TUN/TAP adapter"); - else if (tt->type == DEV_TYPE_TUN) - check_subnet_conflict (tt->local, IPV4_NETMASK_HOST, "TUN/TAP adapter"); - } - - /* - * If TAP-style interface, generate broadcast address. - */ - if (!tun) - { - tt->broadcast = generate_ifconfig_broadcast_addr (tt->local, tt->remote_netmask); - } +init_tun(const char *dev, /* --dev option */ + const char *dev_type, /* --dev-type option */ + int topology, /* one of the TOP_x values */ + const char *ifconfig_local_parm, /* --ifconfig parm 1 */ + const char *ifconfig_remote_netmask_parm, /* --ifconfig parm 2 */ + const char *ifconfig_ipv6_local_parm, /* --ifconfig parm 1 IPv6 */ + int ifconfig_ipv6_netbits_parm, + const char *ifconfig_ipv6_remote_parm, /* --ifconfig parm 2 IPv6 */ + struct addrinfo *local_public, + struct addrinfo *remote_public, + const bool strict_warn, + struct env_set *es) +{ + struct gc_arena gc = gc_new(); + struct tuntap *tt; + + ALLOC_OBJ(tt, struct tuntap); + clear_tuntap(tt); + + tt->type = dev_type_enum(dev, dev_type); + tt->topology = topology; + + if (ifconfig_local_parm && ifconfig_remote_netmask_parm) + { + bool tun = false; + + /* + * We only handle TUN/TAP devices here, not --dev null devices. + */ + tun = is_tun_p2p(tt); + + /* + * Convert arguments to binary IPv4 addresses. + */ + + tt->local = getaddr( + GETADDR_RESOLVE + | GETADDR_HOST_ORDER + | GETADDR_FATAL_ON_SIGNAL + | GETADDR_FATAL, + ifconfig_local_parm, + 0, + NULL, + NULL); + + tt->remote_netmask = getaddr( + (tun ? GETADDR_RESOLVE : 0) + | GETADDR_HOST_ORDER + | GETADDR_FATAL_ON_SIGNAL + | GETADDR_FATAL, + ifconfig_remote_netmask_parm, + 0, + NULL, + NULL); + + /* + * Look for common errors in --ifconfig parms + */ + if (strict_warn) + { + struct addrinfo *curele; + ifconfig_sanity_check(tt->type == DEV_TYPE_TUN, tt->remote_netmask, tt->topology); + + /* + * If local_public or remote_public addresses are defined, + * make sure they do not clash with our virtual subnet. + */ + + for (curele = local_public; curele; curele = curele->ai_next) { + if (curele->ai_family == AF_INET) + { + check_addr_clash("local", + tt->type, + ((struct sockaddr_in *)curele->ai_addr)->sin_addr.s_addr, + tt->local, + tt->remote_netmask); + } + } + + for (curele = remote_public; curele; curele = curele->ai_next) { + if (curele->ai_family == AF_INET) + { + check_addr_clash("remote", + tt->type, + ((struct sockaddr_in *)curele->ai_addr)->sin_addr.s_addr, + tt->local, + tt->remote_netmask); + } + } + + if (tt->type == DEV_TYPE_TAP || (tt->type == DEV_TYPE_TUN && tt->topology == TOP_SUBNET)) + { + check_subnet_conflict(tt->local, tt->remote_netmask, "TUN/TAP adapter"); + } + else if (tt->type == DEV_TYPE_TUN) + { + check_subnet_conflict(tt->local, IPV4_NETMASK_HOST, "TUN/TAP adapter"); + } + } + + /* + * If TAP-style interface, generate broadcast address. + */ + if (!tun) + { + tt->broadcast = generate_ifconfig_broadcast_addr(tt->local, tt->remote_netmask); + } #ifdef _WIN32 - /* - * Make sure that both ifconfig addresses are part of the - * same .252 subnet. - */ - if (tun) + /* + * Make sure that both ifconfig addresses are part of the + * same .252 subnet. + */ + if (tun) { - verify_255_255_255_252 (tt->local, tt->remote_netmask); - tt->adapter_netmask = ~3; + verify_255_255_255_252(tt->local, tt->remote_netmask); + tt->adapter_netmask = ~3; } - else + else { - tt->adapter_netmask = tt->remote_netmask; + tt->adapter_netmask = tt->remote_netmask; } #endif - tt->did_ifconfig_setup = true; + tt->did_ifconfig_setup = true; } - if (ifconfig_ipv6_local_parm && ifconfig_ipv6_remote_parm) + if (ifconfig_ipv6_local_parm && ifconfig_ipv6_remote_parm) { - /* - * Convert arguments to binary IPv6 addresses. - */ + /* + * Convert arguments to binary IPv6 addresses. + */ - if ( inet_pton( AF_INET6, ifconfig_ipv6_local_parm, &tt->local_ipv6 ) != 1 || - inet_pton( AF_INET6, ifconfig_ipv6_remote_parm, &tt->remote_ipv6 ) != 1 ) - { - msg( M_FATAL, "init_tun: problem converting IPv6 ifconfig addresses %s and %s to binary", ifconfig_ipv6_local_parm, ifconfig_ipv6_remote_parm ); - } - tt->netbits_ipv6 = ifconfig_ipv6_netbits_parm; + if (inet_pton( AF_INET6, ifconfig_ipv6_local_parm, &tt->local_ipv6 ) != 1 + || inet_pton( AF_INET6, ifconfig_ipv6_remote_parm, &tt->remote_ipv6 ) != 1) + { + msg( M_FATAL, "init_tun: problem converting IPv6 ifconfig addresses %s and %s to binary", ifconfig_ipv6_local_parm, ifconfig_ipv6_remote_parm ); + } + tt->netbits_ipv6 = ifconfig_ipv6_netbits_parm; - tt->did_ifconfig_ipv6_setup = true; + tt->did_ifconfig_ipv6_setup = true; } - /* - * Set environmental variables with ifconfig parameters. - */ - if (es) do_ifconfig_setenv(tt, es); + /* + * Set environmental variables with ifconfig parameters. + */ + if (es) + { + do_ifconfig_setenv(tt, es); + } - gc_free (&gc); - return tt; + gc_free(&gc); + return tt; } /* * Platform specific tun initializations */ void -init_tun_post (struct tuntap *tt, - const struct frame *frame, - const struct tuntap_options *options) +init_tun_post(struct tuntap *tt, + const struct frame *frame, + const struct tuntap_options *options) { - tt->options = *options; + tt->options = *options; #ifdef _WIN32 - overlapped_io_init (&tt->reads, frame, FALSE, true); - overlapped_io_init (&tt->writes, frame, TRUE, true); - tt->rw_handle.read = tt->reads.overlapped.hEvent; - tt->rw_handle.write = tt->writes.overlapped.hEvent; - tt->adapter_index = TUN_ADAPTER_INDEX_INVALID; + overlapped_io_init(&tt->reads, frame, FALSE, true); + overlapped_io_init(&tt->writes, frame, TRUE, true); + tt->rw_handle.read = tt->reads.overlapped.hEvent; + tt->rw_handle.write = tt->writes.overlapped.hEvent; + tt->adapter_index = TUN_ADAPTER_INDEX_INVALID; #endif } -#if defined(_WIN32) || \ - defined(TARGET_DARWIN) || defined(TARGET_NETBSD) || defined(TARGET_OPENBSD) +#if defined(_WIN32) \ + || defined(TARGET_DARWIN) || defined(TARGET_NETBSD) || defined(TARGET_OPENBSD) /* some of the platforms will auto-add a "network route" pointing * to the interface on "ifconfig tunX 2001:db8::1/64", others need * an extra call to "route add..." * -> helper function to simplify code below */ -void add_route_connected_v6_net(struct tuntap * tt, - const struct env_set *es) +void +add_route_connected_v6_net(struct tuntap *tt, + const struct env_set *es) { struct route_ipv6 r6; @@ -762,13 +818,14 @@ void add_route_connected_v6_net(struct tuntap * tt, r6.network = tt->local_ipv6; r6.netbits = tt->netbits_ipv6; r6.gateway = tt->local_ipv6; - r6.metric = 0; /* connected route */ + r6.metric = 0; /* connected route */ r6.flags = RT_DEFINED | RT_METRIC_DEFINED; - add_route_ipv6 (&r6, tt, 0, es); + add_route_ipv6(&r6, tt, 0, es); } -void delete_route_connected_v6_net(struct tuntap * tt, - const struct env_set *es) +void +delete_route_connected_v6_net(struct tuntap *tt, + const struct env_set *es) { struct route_ipv6 r6; @@ -776,14 +833,14 @@ void delete_route_connected_v6_net(struct tuntap * tt, r6.network = tt->local_ipv6; r6.netbits = tt->netbits_ipv6; r6.gateway = tt->local_ipv6; - r6.metric = 0; /* connected route */ + r6.metric = 0; /* connected route */ r6.flags = RT_DEFINED | RT_ADDED | RT_METRIC_DEFINED; - delete_route_ipv6 (&r6, tt, 0, es); + delete_route_ipv6(&r6, tt, 0, es); } -#endif +#endif /* if defined(_WIN32) || defined(TARGET_DARWIN) || defined(TARGET_NETBSD) || defined(TARGET_OPENBSD) */ -#if defined(TARGET_FREEBSD)||defined(TARGET_DRAGONFLY)||\ - defined(TARGET_OPENBSD) +#if defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY) \ + || defined(TARGET_OPENBSD) /* we can't use true subnet mode on tun on all platforms, as that * conflicts with IPv6 (wants to use ND then, which we don't do), * but the OSes want "a remote address that is different from ours" @@ -796,989 +853,1062 @@ void delete_route_connected_v6_net(struct tuntap * tt, in_addr_t create_arbitrary_remote( struct tuntap *tt ) { - in_addr_t remote; + in_addr_t remote; - remote = (tt->local & tt->remote_netmask) +1; + remote = (tt->local & tt->remote_netmask) +1; - if ( remote == tt->local ) remote ++; + if (remote == tt->local) + { + remote++; + } - return remote; + return remote; } #endif /* execute the ifconfig command through the shell */ void -do_ifconfig (struct tuntap *tt, - const char *actual, /* actual device name */ - int tun_mtu, - const struct env_set *es) +do_ifconfig(struct tuntap *tt, + const char *actual, /* actual device name */ + int tun_mtu, + const struct env_set *es) { - struct gc_arena gc = gc_new (); + struct gc_arena gc = gc_new(); - if (tt->did_ifconfig_setup) + if (tt->did_ifconfig_setup) { - bool tun = false; - const char *ifconfig_local = NULL; - const char *ifconfig_remote_netmask = NULL; - const char *ifconfig_broadcast = NULL; - const char *ifconfig_ipv6_local = NULL; - bool do_ipv6 = false; - struct argv argv = argv_new (); - - msg( M_DEBUG, "do_ifconfig, tt->did_ifconfig_ipv6_setup=%d", - tt->did_ifconfig_ipv6_setup ); - - /* - * We only handle TUN/TAP devices here, not --dev null devices. - */ - tun = is_tun_p2p (tt); - - /* - * Set ifconfig parameters - */ - ifconfig_local = print_in_addr_t (tt->local, 0, &gc); - ifconfig_remote_netmask = print_in_addr_t (tt->remote_netmask, 0, &gc); - - if (tt->did_ifconfig_ipv6_setup ) + bool tun = false; + const char *ifconfig_local = NULL; + const char *ifconfig_remote_netmask = NULL; + const char *ifconfig_broadcast = NULL; + const char *ifconfig_ipv6_local = NULL; + bool do_ipv6 = false; + struct argv argv = argv_new(); + + msg( M_DEBUG, "do_ifconfig, tt->did_ifconfig_ipv6_setup=%d", + tt->did_ifconfig_ipv6_setup ); + + /* + * We only handle TUN/TAP devices here, not --dev null devices. + */ + tun = is_tun_p2p(tt); + + /* + * Set ifconfig parameters + */ + ifconfig_local = print_in_addr_t(tt->local, 0, &gc); + ifconfig_remote_netmask = print_in_addr_t(tt->remote_netmask, 0, &gc); + + if (tt->did_ifconfig_ipv6_setup) { - ifconfig_ipv6_local = print_in6_addr (tt->local_ipv6, 0, &gc); - do_ipv6 = true; - } + ifconfig_ipv6_local = print_in6_addr(tt->local_ipv6, 0, &gc); + do_ipv6 = true; + } - /* - * If TAP-style device, generate broadcast address. - */ - if (!tun) - ifconfig_broadcast = print_in_addr_t (tt->broadcast, 0, &gc); + /* + * If TAP-style device, generate broadcast address. + */ + if (!tun) + { + ifconfig_broadcast = print_in_addr_t(tt->broadcast, 0, &gc); + } #ifdef ENABLE_MANAGEMENT - if (management) - { - management_set_state (management, - OPENVPN_STATE_ASSIGN_IP, - NULL, - &tt->local, - &tt->local_ipv6, - NULL, - NULL); - } + if (management) + { + management_set_state(management, + OPENVPN_STATE_ASSIGN_IP, + NULL, + &tt->local, + &tt->local_ipv6, + NULL, + NULL); + } #endif #if defined(TARGET_LINUX) #ifdef ENABLE_IPROUTE - /* - * Set the MTU for the device - */ - argv_printf (&argv, - "%s link set dev %s up mtu %d", - iproute_path, - actual, - tun_mtu - ); - argv_msg (M_INFO, &argv); - openvpn_execve_check (&argv, es, S_FATAL, "Linux ip link set failed"); - - if (tun) { - - /* - * Set the address for the device - */ - argv_printf (&argv, - "%s addr add dev %s local %s peer %s", - iproute_path, - actual, - ifconfig_local, - ifconfig_remote_netmask - ); - argv_msg (M_INFO, &argv); - openvpn_execve_check (&argv, es, S_FATAL, "Linux ip addr add failed"); - } else { - argv_printf (&argv, - "%s addr add dev %s %s/%d broadcast %s", - iproute_path, - actual, - ifconfig_local, - netmask_to_netbits2(tt->remote_netmask), - ifconfig_broadcast - ); - argv_msg (M_INFO, &argv); - openvpn_execve_check (&argv, es, S_FATAL, "Linux ip addr add failed"); - } - if ( do_ipv6 ) - { - argv_printf( &argv, - "%s -6 addr add %s/%d dev %s", - iproute_path, - ifconfig_ipv6_local, - tt->netbits_ipv6, - actual - ); - argv_msg (M_INFO, &argv); - openvpn_execve_check (&argv, es, S_FATAL, "Linux ip -6 addr add failed"); - } - tt->did_ifconfig = true; -#else - if (tun) - argv_printf (&argv, - "%s %s %s pointopoint %s mtu %d", - IFCONFIG_PATH, - actual, - ifconfig_local, - ifconfig_remote_netmask, - tun_mtu - ); - else - argv_printf (&argv, - "%s %s %s netmask %s mtu %d broadcast %s", - IFCONFIG_PATH, - actual, - ifconfig_local, - ifconfig_remote_netmask, - tun_mtu, - ifconfig_broadcast - ); - argv_msg (M_INFO, &argv); - openvpn_execve_check (&argv, es, S_FATAL, "Linux ifconfig failed"); - if ( do_ipv6 ) - { - argv_printf (&argv, - "%s %s add %s/%d", - IFCONFIG_PATH, - actual, - ifconfig_ipv6_local, - tt->netbits_ipv6 - ); - argv_msg (M_INFO, &argv); - openvpn_execve_check (&argv, es, S_FATAL, "Linux ifconfig inet6 failed"); - } - tt->did_ifconfig = true; + /* + * Set the MTU for the device + */ + argv_printf(&argv, + "%s link set dev %s up mtu %d", + iproute_path, + actual, + tun_mtu + ); + argv_msg(M_INFO, &argv); + openvpn_execve_check(&argv, es, S_FATAL, "Linux ip link set failed"); + + if (tun) + { + + /* + * Set the address for the device + */ + argv_printf(&argv, + "%s addr add dev %s local %s peer %s", + iproute_path, + actual, + ifconfig_local, + ifconfig_remote_netmask + ); + argv_msg(M_INFO, &argv); + openvpn_execve_check(&argv, es, S_FATAL, "Linux ip addr add failed"); + } + else + { + argv_printf(&argv, + "%s addr add dev %s %s/%d broadcast %s", + iproute_path, + actual, + ifconfig_local, + netmask_to_netbits2(tt->remote_netmask), + ifconfig_broadcast + ); + argv_msg(M_INFO, &argv); + openvpn_execve_check(&argv, es, S_FATAL, "Linux ip addr add failed"); + } + if (do_ipv6) + { + argv_printf( &argv, + "%s -6 addr add %s/%d dev %s", + iproute_path, + ifconfig_ipv6_local, + tt->netbits_ipv6, + actual + ); + argv_msg(M_INFO, &argv); + openvpn_execve_check(&argv, es, S_FATAL, "Linux ip -6 addr add failed"); + } + tt->did_ifconfig = true; +#else /* ifdef ENABLE_IPROUTE */ + if (tun) + { + argv_printf(&argv, + "%s %s %s pointopoint %s mtu %d", + IFCONFIG_PATH, + actual, + ifconfig_local, + ifconfig_remote_netmask, + tun_mtu + ); + } + else + { + argv_printf(&argv, + "%s %s %s netmask %s mtu %d broadcast %s", + IFCONFIG_PATH, + actual, + ifconfig_local, + ifconfig_remote_netmask, + tun_mtu, + ifconfig_broadcast + ); + } + argv_msg(M_INFO, &argv); + openvpn_execve_check(&argv, es, S_FATAL, "Linux ifconfig failed"); + if (do_ipv6) + { + argv_printf(&argv, + "%s %s add %s/%d", + IFCONFIG_PATH, + actual, + ifconfig_ipv6_local, + tt->netbits_ipv6 + ); + argv_msg(M_INFO, &argv); + openvpn_execve_check(&argv, es, S_FATAL, "Linux ifconfig inet6 failed"); + } + tt->did_ifconfig = true; #endif /*ENABLE_IPROUTE*/ #elif defined(TARGET_ANDROID) - if (do_ipv6) { - struct buffer out6 = alloc_buf_gc (64, &gc); - buf_printf (&out6, "%s/%d", ifconfig_ipv6_local,tt->netbits_ipv6); - management_android_control(management, "IFCONFIG6",buf_bptr(&out6)); - } - - struct buffer out = alloc_buf_gc (64, &gc); - - char* top; - switch(tt->topology) { - case TOP_NET30: - top="net30"; - break; - case TOP_P2P: - top="p2p"; - break; - case TOP_SUBNET: - top="subnet"; - break; - default: - top="undef"; - } - - buf_printf (&out, "%s %s %d %s", ifconfig_local, ifconfig_remote_netmask, tun_mtu, top); - management_android_control (management, "IFCONFIG", buf_bptr(&out)); + if (do_ipv6) + { + struct buffer out6 = alloc_buf_gc(64, &gc); + buf_printf(&out6, "%s/%d", ifconfig_ipv6_local,tt->netbits_ipv6); + management_android_control(management, "IFCONFIG6",buf_bptr(&out6)); + } -#elif defined(TARGET_SOLARIS) - /* Solaris 2.6 (and 7?) cannot set all parameters in one go... - * example: - * ifconfig tun2 10.2.0.2 10.2.0.1 mtu 1450 up - * ifconfig tun2 netmask 255.255.255.255 - */ - if (tun) - { - argv_printf (&argv, - "%s %s %s %s mtu %d up", - IFCONFIG_PATH, - actual, - ifconfig_local, - ifconfig_remote_netmask, - tun_mtu - ); - - argv_msg (M_INFO, &argv); - if (!openvpn_execve_check (&argv, es, 0, "Solaris ifconfig phase-1 failed")) - solaris_error_close (tt, es, actual, false); - - argv_printf (&argv, - "%s %s netmask 255.255.255.255", - IFCONFIG_PATH, - actual - ); - } - else - if (tt->topology == TOP_SUBNET) - { - argv_printf (&argv, - "%s %s %s %s netmask %s mtu %d up", - IFCONFIG_PATH, - actual, - ifconfig_local, - ifconfig_local, - ifconfig_remote_netmask, - tun_mtu - ); - } - else - argv_printf (&argv, - " %s %s %s netmask %s broadcast + up", - IFCONFIG_PATH, - actual, - ifconfig_local, - ifconfig_remote_netmask - ); + struct buffer out = alloc_buf_gc(64, &gc); - argv_msg (M_INFO, &argv); - if (!openvpn_execve_check (&argv, es, 0, "Solaris ifconfig phase-2 failed")) - solaris_error_close (tt, es, actual, false); - - if ( do_ipv6 ) - { - argv_printf (&argv, "%s %s inet6 unplumb", - IFCONFIG_PATH, actual ); - argv_msg (M_INFO, &argv); - openvpn_execve_check (&argv, es, 0, NULL); - - if ( tt->type == DEV_TYPE_TUN ) - { - const char *ifconfig_ipv6_remote = - print_in6_addr (tt->remote_ipv6, 0, &gc); - - argv_printf (&argv, - "%s %s inet6 plumb %s/%d %s up", - IFCONFIG_PATH, - actual, - ifconfig_ipv6_local, - tt->netbits_ipv6, - ifconfig_ipv6_remote - ); - } - else /* tap mode */ - { - /* base IPv6 tap interface needs to be brought up first - */ - argv_printf (&argv, "%s %s inet6 plumb up", - IFCONFIG_PATH, actual ); - argv_msg (M_INFO, &argv); - if (!openvpn_execve_check (&argv, es, 0, "Solaris ifconfig IPv6 (prepare) failed")) - solaris_error_close (tt, es, actual, true); - - /* we might need to do "ifconfig %s inet6 auto-dhcp drop" - * after the system has noticed the interface and fired up - * the DHCPv6 client - but this takes quite a while, and the - * server will ignore the DHCPv6 packets anyway. So we don't. - */ - - /* static IPv6 addresses need to go to a subinterface (tap0:1) - */ - argv_printf (&argv, - "%s %s inet6 addif %s/%d up", - IFCONFIG_PATH, actual, - ifconfig_ipv6_local, tt->netbits_ipv6 ); - } - argv_msg (M_INFO, &argv); - if (!openvpn_execve_check (&argv, es, 0, "Solaris ifconfig IPv6 failed")) - solaris_error_close (tt, es, actual, true); - } - - if (!tun && tt->topology == TOP_SUBNET) - { - /* Add a network route for the local tun interface */ - struct route_ipv4 r; - CLEAR (r); - r.flags = RT_DEFINED | RT_METRIC_DEFINED; - r.network = tt->local & tt->remote_netmask; - r.netmask = tt->remote_netmask; - r.gateway = tt->local; - r.metric = 0; - add_route (&r, tt, 0, NULL, es); - } - - tt->did_ifconfig = true; + char *top; + switch (tt->topology) { + case TOP_NET30: + top = "net30"; + break; -#elif defined(TARGET_OPENBSD) + case TOP_P2P: + top = "p2p"; + break; - in_addr_t remote_end; /* for "virtual" subnet topology */ - - /* - * On OpenBSD, tun interfaces are persistent if created with - * "ifconfig tunX create", and auto-destroyed if created by - * opening "/dev/tunX" (so we just use the /dev/tunX) - */ - - /* example: ifconfig tun2 10.2.0.2 10.2.0.1 mtu 1450 netmask 255.255.255.255 up */ - if (tun) - argv_printf (&argv, - "%s %s %s %s mtu %d netmask 255.255.255.255 up -link0", - IFCONFIG_PATH, - actual, - ifconfig_local, - ifconfig_remote_netmask, - tun_mtu - ); - else - if ( tt->topology == TOP_SUBNET ) - { - remote_end = create_arbitrary_remote( tt ); - argv_printf (&argv, - "%s %s %s %s mtu %d netmask %s up -link0", - IFCONFIG_PATH, - actual, - ifconfig_local, - print_in_addr_t (remote_end, 0, &gc), - tun_mtu, - ifconfig_remote_netmask - ); - } - else - argv_printf (&argv, - "%s %s %s netmask %s mtu %d broadcast %s link0", - IFCONFIG_PATH, - actual, - ifconfig_local, - ifconfig_remote_netmask, - tun_mtu, - ifconfig_broadcast - ); - argv_msg (M_INFO, &argv); - openvpn_execve_check (&argv, es, S_FATAL, "OpenBSD ifconfig failed"); - - /* Add a network route for the local tun interface */ - if (!tun && tt->topology == TOP_SUBNET) - { - struct route_ipv4 r; - CLEAR (r); - r.flags = RT_DEFINED; - r.network = tt->local & tt->remote_netmask; - r.netmask = tt->remote_netmask; - r.gateway = remote_end; - add_route (&r, tt, 0, NULL, es); - } - - if ( do_ipv6 ) - { - argv_printf (&argv, - "%s %s inet6 %s/%d", - IFCONFIG_PATH, - actual, - ifconfig_ipv6_local, - tt->netbits_ipv6 - ); - argv_msg (M_INFO, &argv); - openvpn_execve_check (&argv, es, S_FATAL, "OpenBSD ifconfig inet6 failed"); - - /* and, hooray, we explicitely need to add a route... */ - add_route_connected_v6_net(tt, es); - } - tt->did_ifconfig = true; + case TOP_SUBNET: + top = "subnet"; + break; -#elif defined(TARGET_NETBSD) + default: + top = "undef"; + } - if (tun) - argv_printf (&argv, - "%s %s %s %s mtu %d netmask 255.255.255.255 up", - IFCONFIG_PATH, - actual, - ifconfig_local, - ifconfig_remote_netmask, - tun_mtu - ); - else - if ( tt->topology == TOP_SUBNET ) - { - argv_printf (&argv, - "%s %s %s %s mtu %d netmask %s up", - IFCONFIG_PATH, - actual, - ifconfig_local, - ifconfig_local, - tun_mtu, - ifconfig_remote_netmask - ); - } - else - /* - * NetBSD has distinct tun and tap devices - * so we don't need the "link0" extra parameter to specify we want to do - * tunneling at the ethernet level - */ - argv_printf (&argv, - "%s %s %s netmask %s mtu %d broadcast %s", - IFCONFIG_PATH, - actual, - ifconfig_local, - ifconfig_remote_netmask, - tun_mtu, - ifconfig_broadcast - ); - argv_msg (M_INFO, &argv); - openvpn_execve_check (&argv, es, S_FATAL, "NetBSD ifconfig failed"); - - if ( do_ipv6 ) - { - argv_printf (&argv, - "%s %s inet6 %s/%d", - IFCONFIG_PATH, - actual, - ifconfig_ipv6_local, - tt->netbits_ipv6 - ); - argv_msg (M_INFO, &argv); - openvpn_execve_check (&argv, es, S_FATAL, "NetBSD ifconfig inet6 failed"); - - /* and, hooray, we explicitely need to add a route... */ - add_route_connected_v6_net(tt, es); - } - tt->did_ifconfig = true; + buf_printf(&out, "%s %s %d %s", ifconfig_local, ifconfig_remote_netmask, tun_mtu, top); + management_android_control(management, "IFCONFIG", buf_bptr(&out)); -#elif defined(TARGET_DARWIN) - /* - * Darwin (i.e. Mac OS X) seems to exhibit similar behaviour to OpenBSD... - */ - - argv_printf (&argv, - "%s %s delete", - IFCONFIG_PATH, - actual); - argv_msg (M_INFO, &argv); - openvpn_execve_check (&argv, es, 0, NULL); - msg (M_INFO, "NOTE: Tried to delete pre-existing tun/tap instance -- No Problem if failure"); - - - /* example: ifconfig tun2 10.2.0.2 10.2.0.1 mtu 1450 netmask 255.255.255.255 up */ - if (tun) - argv_printf (&argv, - "%s %s %s %s mtu %d netmask 255.255.255.255 up", - IFCONFIG_PATH, - actual, - ifconfig_local, - ifconfig_remote_netmask, - tun_mtu - ); - else - { - if (tt->topology == TOP_SUBNET) - argv_printf (&argv, - "%s %s %s %s netmask %s mtu %d up", - IFCONFIG_PATH, - actual, - ifconfig_local, - ifconfig_local, - ifconfig_remote_netmask, - tun_mtu - ); - else - argv_printf (&argv, - "%s %s %s netmask %s mtu %d up", - IFCONFIG_PATH, - actual, - ifconfig_local, - ifconfig_remote_netmask, - tun_mtu - ); - } - - argv_msg (M_INFO, &argv); - openvpn_execve_check (&argv, es, S_FATAL, "Mac OS X ifconfig failed"); - tt->did_ifconfig = true; - - /* Add a network route for the local tun interface */ - if (!tun && tt->topology == TOP_SUBNET) - { - struct route_ipv4 r; - CLEAR (r); - r.flags = RT_DEFINED; - r.network = tt->local & tt->remote_netmask; - r.netmask = tt->remote_netmask; - r.gateway = tt->local; - add_route (&r, tt, 0, NULL, es); - } - - if ( do_ipv6 ) - { - argv_printf (&argv, - "%s %s inet6 %s/%d", - IFCONFIG_PATH, - actual, - ifconfig_ipv6_local, - tt->netbits_ipv6 - ); - argv_msg (M_INFO, &argv); - openvpn_execve_check (&argv, es, S_FATAL, "MacOS X ifconfig inet6 failed"); - - /* and, hooray, we explicitely need to add a route... */ - add_route_connected_v6_net(tt, es); - } - -#elif defined(TARGET_FREEBSD)||defined(TARGET_DRAGONFLY) - - in_addr_t remote_end; /* for "virtual" subnet topology */ - - /* example: ifconfig tun2 10.2.0.2 10.2.0.1 mtu 1450 netmask 255.255.255.255 up */ - if (tun) - argv_printf (&argv, - "%s %s %s %s mtu %d netmask 255.255.255.255 up", - IFCONFIG_PATH, - actual, - ifconfig_local, - ifconfig_remote_netmask, - tun_mtu - ); - else if ( tt->topology == TOP_SUBNET ) - { - remote_end = create_arbitrary_remote( tt ); - argv_printf (&argv, - "%s %s %s %s mtu %d netmask %s up", - IFCONFIG_PATH, - actual, - ifconfig_local, - print_in_addr_t (remote_end, 0, &gc), - tun_mtu, - ifconfig_remote_netmask - ); - } - else - argv_printf (&argv, - "%s %s %s netmask %s mtu %d up", - IFCONFIG_PATH, - actual, - ifconfig_local, - ifconfig_remote_netmask, - tun_mtu - ); - - argv_msg (M_INFO, &argv); - openvpn_execve_check (&argv, es, S_FATAL, "FreeBSD ifconfig failed"); - tt->did_ifconfig = true; - - /* Add a network route for the local tun interface */ - if (!tun && tt->topology == TOP_SUBNET) - { - struct route_ipv4 r; - CLEAR (r); - r.flags = RT_DEFINED; - r.network = tt->local & tt->remote_netmask; - r.netmask = tt->remote_netmask; - r.gateway = remote_end; - add_route (&r, tt, 0, NULL, es); - } - - if ( do_ipv6 ) - { - argv_printf (&argv, - "%s %s inet6 %s/%d", - IFCONFIG_PATH, - actual, - ifconfig_ipv6_local, - tt->netbits_ipv6 - ); - argv_msg (M_INFO, &argv); - openvpn_execve_check (&argv, es, S_FATAL, "FreeBSD ifconfig inet6 failed"); - } +#elif defined(TARGET_SOLARIS) + /* Solaris 2.6 (and 7?) cannot set all parameters in one go... + * example: + * ifconfig tun2 10.2.0.2 10.2.0.1 mtu 1450 up + * ifconfig tun2 netmask 255.255.255.255 + */ + if (tun) + { + argv_printf(&argv, + "%s %s %s %s mtu %d up", + IFCONFIG_PATH, + actual, + ifconfig_local, + ifconfig_remote_netmask, + tun_mtu + ); + + argv_msg(M_INFO, &argv); + if (!openvpn_execve_check(&argv, es, 0, "Solaris ifconfig phase-1 failed")) + { + solaris_error_close(tt, es, actual, false); + } -#elif defined(TARGET_AIX) - { - /* AIX ifconfig will complain if it can't find ODM path in env */ - struct env_set *aix_es = env_set_create (NULL); - env_set_add( aix_es, "ODMDIR=/etc/objrepos" ); - - if (tun) - msg(M_FATAL, "no tun support on AIX (canthappen)"); - - /* example: ifconfig tap0 172.30.1.1 netmask 255.255.254.0 up */ - argv_printf (&argv, - "%s %s %s netmask %s mtu %d up", - IFCONFIG_PATH, - actual, - ifconfig_local, - ifconfig_remote_netmask, - tun_mtu - ); - - argv_msg (M_INFO, &argv); - openvpn_execve_check (&argv, aix_es, S_FATAL, "AIX ifconfig failed"); - tt->did_ifconfig = true; - - if ( do_ipv6 ) - { - argv_printf (&argv, - "%s %s inet6 %s/%d", - IFCONFIG_PATH, - actual, - ifconfig_ipv6_local, - tt->netbits_ipv6 - ); - argv_msg (M_INFO, &argv); - openvpn_execve_check (&argv, aix_es, S_FATAL, "AIX ifconfig inet6 failed"); - } - env_set_destroy (aix_es); - } -#elif defined (_WIN32) - { - ASSERT (actual != NULL); - - switch (tt->options.ip_win32_type) - { - case IPW32_SET_MANUAL: - msg (M_INFO, "******** NOTE: Please manually set the IP/netmask of '%s' to %s/%s (if it is not already set)", - actual, - ifconfig_local, - print_in_addr_t (tt->adapter_netmask, 0, &gc)); - break; - case IPW32_SET_NETSH: - netsh_ifconfig (&tt->options, - actual, - tt->local, - tt->adapter_netmask, - NI_IP_NETMASK|NI_OPTIONS); - - break; - } - tt->did_ifconfig = true; - } - - if ( do_ipv6 ) - { - if (tt->options.ip_win32_type == IPW32_SET_MANUAL) - { - msg (M_INFO, "******** NOTE: Please manually set the v6 IP of '%s' to %s (if it is not already set)", - actual, - ifconfig_ipv6_local); - } - else if (tt->options.msg_channel) - { - do_address_service (true, AF_INET6, tt); - do_dns6_service (true, tt); - } - else - { - /* example: netsh interface ipv6 set address interface=42 2001:608:8003::d store=active */ - char iface[64]; - openvpn_snprintf(iface, sizeof(iface), "interface=%lu", tt->adapter_index ); - argv_printf (&argv, - "%s%sc interface ipv6 set address %s %s store=active", - get_win_sys_path(), - NETSH_PATH_SUFFIX, - iface, - ifconfig_ipv6_local ); - netsh_command (&argv, 4, M_FATAL); - /* set ipv6 dns servers if any are specified */ - netsh_set_dns6_servers(tt->options.dns6, tt->options.dns6_len, actual); - } - - /* explicit route needed */ - if (tt->options.ip_win32_type != IPW32_SET_MANUAL) - { - add_route_connected_v6_net(tt, es); - } - } -#else - msg (M_FATAL, "Sorry, but I don't know how to do 'ifconfig' commands on this operating system. You should ifconfig your TUN/TAP device manually or use an --up script."); -#endif - argv_reset (&argv); - } - gc_free (&gc); -} + argv_printf(&argv, + "%s %s netmask 255.255.255.255", + IFCONFIG_PATH, + actual + ); + } + else if (tt->topology == TOP_SUBNET) + { + argv_printf(&argv, + "%s %s %s %s netmask %s mtu %d up", + IFCONFIG_PATH, + actual, + ifconfig_local, + ifconfig_local, + ifconfig_remote_netmask, + tun_mtu + ); + } + else + { + argv_printf(&argv, + " %s %s %s netmask %s broadcast + up", + IFCONFIG_PATH, + actual, + ifconfig_local, + ifconfig_remote_netmask + ); + } -static void -clear_tuntap (struct tuntap *tuntap) -{ - CLEAR (*tuntap); -#ifdef _WIN32 - tuntap->hand = NULL; -#else - tuntap->fd = -1; -#endif -#ifdef TARGET_SOLARIS - tuntap->ip_fd = -1; -#endif -} + argv_msg(M_INFO, &argv); + if (!openvpn_execve_check(&argv, es, 0, "Solaris ifconfig phase-2 failed")) + { + solaris_error_close(tt, es, actual, false); + } -static void -open_null (struct tuntap *tt) -{ - tt->actual_name = string_alloc ("null", NULL); -} + if (do_ipv6) + { + argv_printf(&argv, "%s %s inet6 unplumb", + IFCONFIG_PATH, actual ); + argv_msg(M_INFO, &argv); + openvpn_execve_check(&argv, es, 0, NULL); + if (tt->type == DEV_TYPE_TUN) + { + const char *ifconfig_ipv6_remote = + print_in6_addr(tt->remote_ipv6, 0, &gc); -#if defined (TARGET_OPENBSD) || (defined(TARGET_DARWIN) && HAVE_NET_IF_UTUN_H) + argv_printf(&argv, + "%s %s inet6 plumb %s/%d %s up", + IFCONFIG_PATH, + actual, + ifconfig_ipv6_local, + tt->netbits_ipv6, + ifconfig_ipv6_remote + ); + } + else /* tap mode */ + { + /* base IPv6 tap interface needs to be brought up first + */ + argv_printf(&argv, "%s %s inet6 plumb up", + IFCONFIG_PATH, actual ); + argv_msg(M_INFO, &argv); + if (!openvpn_execve_check(&argv, es, 0, "Solaris ifconfig IPv6 (prepare) failed")) + { + solaris_error_close(tt, es, actual, true); + } + + /* we might need to do "ifconfig %s inet6 auto-dhcp drop" + * after the system has noticed the interface and fired up + * the DHCPv6 client - but this takes quite a while, and the + * server will ignore the DHCPv6 packets anyway. So we don't. + */ + + /* static IPv6 addresses need to go to a subinterface (tap0:1) + */ + argv_printf(&argv, + "%s %s inet6 addif %s/%d up", + IFCONFIG_PATH, actual, + ifconfig_ipv6_local, tt->netbits_ipv6 ); + } + argv_msg(M_INFO, &argv); + if (!openvpn_execve_check(&argv, es, 0, "Solaris ifconfig IPv6 failed")) + { + solaris_error_close(tt, es, actual, true); + } + } -/* - * OpenBSD and Mac OS X when using utun - * have a slightly incompatible TUN device from - * the rest of the world, in that it prepends a - * uint32 to the beginning of the IP header - * to designate the protocol (why not just - * look at the version field in the IP header to - * determine v4 or v6?). - * - * We strip off this field on reads and - * put it back on writes. - * - * I have not tested TAP devices on OpenBSD, - * but I have conditionalized the special - * TUN handling code described above to - * go away for TAP devices. - */ + if (!tun && tt->topology == TOP_SUBNET) + { + /* Add a network route for the local tun interface */ + struct route_ipv4 r; + CLEAR(r); + r.flags = RT_DEFINED | RT_METRIC_DEFINED; + r.network = tt->local & tt->remote_netmask; + r.netmask = tt->remote_netmask; + r.gateway = tt->local; + r.metric = 0; + add_route(&r, tt, 0, NULL, es); + } -#include -#include + tt->did_ifconfig = true; -static inline int -header_modify_read_write_return (int len) -{ - if (len > 0) - return len > sizeof (u_int32_t) ? len - sizeof (u_int32_t) : 0; - else - return len; -} +#elif defined(TARGET_OPENBSD) -int -write_tun_header (struct tuntap* tt, uint8_t *buf, int len) -{ - if (tt->type == DEV_TYPE_TUN) - { - u_int32_t type; - struct iovec iv[2]; - struct ip *iph; + in_addr_t remote_end; /* for "virtual" subnet topology */ - iph = (struct ip *) buf; + /* + * On OpenBSD, tun interfaces are persistent if created with + * "ifconfig tunX create", and auto-destroyed if created by + * opening "/dev/tunX" (so we just use the /dev/tunX) + */ - if (iph->ip_v == 6) - type = htonl (AF_INET6); + /* example: ifconfig tun2 10.2.0.2 10.2.0.1 mtu 1450 netmask 255.255.255.255 up */ + if (tun) + { + argv_printf(&argv, + "%s %s %s %s mtu %d netmask 255.255.255.255 up -link0", + IFCONFIG_PATH, + actual, + ifconfig_local, + ifconfig_remote_netmask, + tun_mtu + ); + } + else if (tt->topology == TOP_SUBNET) + { + remote_end = create_arbitrary_remote( tt ); + argv_printf(&argv, + "%s %s %s %s mtu %d netmask %s up -link0", + IFCONFIG_PATH, + actual, + ifconfig_local, + print_in_addr_t(remote_end, 0, &gc), + tun_mtu, + ifconfig_remote_netmask + ); + } else - type = htonl (AF_INET); + { + argv_printf(&argv, + "%s %s %s netmask %s mtu %d broadcast %s link0", + IFCONFIG_PATH, + actual, + ifconfig_local, + ifconfig_remote_netmask, + tun_mtu, + ifconfig_broadcast + ); + } + argv_msg(M_INFO, &argv); + openvpn_execve_check(&argv, es, S_FATAL, "OpenBSD ifconfig failed"); - iv[0].iov_base = &type; - iv[0].iov_len = sizeof (type); - iv[1].iov_base = buf; - iv[1].iov_len = len; + /* Add a network route for the local tun interface */ + if (!tun && tt->topology == TOP_SUBNET) + { + struct route_ipv4 r; + CLEAR(r); + r.flags = RT_DEFINED; + r.network = tt->local & tt->remote_netmask; + r.netmask = tt->remote_netmask; + r.gateway = remote_end; + add_route(&r, tt, 0, NULL, es); + } - return header_modify_read_write_return (writev (tt->fd, iv, 2)); - } - else - return write (tt->fd, buf, len); -} + if (do_ipv6) + { + argv_printf(&argv, + "%s %s inet6 %s/%d", + IFCONFIG_PATH, + actual, + ifconfig_ipv6_local, + tt->netbits_ipv6 + ); + argv_msg(M_INFO, &argv); + openvpn_execve_check(&argv, es, S_FATAL, "OpenBSD ifconfig inet6 failed"); + + /* and, hooray, we explicitely need to add a route... */ + add_route_connected_v6_net(tt, es); + } + tt->did_ifconfig = true; -int -read_tun_header (struct tuntap* tt, uint8_t *buf, int len) -{ - if (tt->type == DEV_TYPE_TUN) - { - u_int32_t type; - struct iovec iv[2]; +#elif defined(TARGET_NETBSD) - iv[0].iov_base = &type; - iv[0].iov_len = sizeof (type); - iv[1].iov_base = buf; + if (tun) + { + argv_printf(&argv, + "%s %s %s %s mtu %d netmask 255.255.255.255 up", + IFCONFIG_PATH, + actual, + ifconfig_local, + ifconfig_remote_netmask, + tun_mtu + ); + } + else if (tt->topology == TOP_SUBNET) + { + argv_printf(&argv, + "%s %s %s %s mtu %d netmask %s up", + IFCONFIG_PATH, + actual, + ifconfig_local, + ifconfig_local, + tun_mtu, + ifconfig_remote_netmask + ); + } + else + { + /* + * NetBSD has distinct tun and tap devices + * so we don't need the "link0" extra parameter to specify we want to do + * tunneling at the ethernet level + */ + argv_printf(&argv, + "%s %s %s netmask %s mtu %d broadcast %s", + IFCONFIG_PATH, + actual, + ifconfig_local, + ifconfig_remote_netmask, + tun_mtu, + ifconfig_broadcast + ); + } + argv_msg(M_INFO, &argv); + openvpn_execve_check(&argv, es, S_FATAL, "NetBSD ifconfig failed"); + + if (do_ipv6) + { + argv_printf(&argv, + "%s %s inet6 %s/%d", + IFCONFIG_PATH, + actual, + ifconfig_ipv6_local, + tt->netbits_ipv6 + ); + argv_msg(M_INFO, &argv); + openvpn_execve_check(&argv, es, S_FATAL, "NetBSD ifconfig inet6 failed"); + + /* and, hooray, we explicitely need to add a route... */ + add_route_connected_v6_net(tt, es); + } + tt->did_ifconfig = true; + +#elif defined(TARGET_DARWIN) + /* + * Darwin (i.e. Mac OS X) seems to exhibit similar behaviour to OpenBSD... + */ + + argv_printf(&argv, + "%s %s delete", + IFCONFIG_PATH, + actual); + argv_msg(M_INFO, &argv); + openvpn_execve_check(&argv, es, 0, NULL); + msg(M_INFO, "NOTE: Tried to delete pre-existing tun/tap instance -- No Problem if failure"); + + + /* example: ifconfig tun2 10.2.0.2 10.2.0.1 mtu 1450 netmask 255.255.255.255 up */ + if (tun) + { + argv_printf(&argv, + "%s %s %s %s mtu %d netmask 255.255.255.255 up", + IFCONFIG_PATH, + actual, + ifconfig_local, + ifconfig_remote_netmask, + tun_mtu + ); + } + else + { + if (tt->topology == TOP_SUBNET) + { + argv_printf(&argv, + "%s %s %s %s netmask %s mtu %d up", + IFCONFIG_PATH, + actual, + ifconfig_local, + ifconfig_local, + ifconfig_remote_netmask, + tun_mtu + ); + } + else + { + argv_printf(&argv, + "%s %s %s netmask %s mtu %d up", + IFCONFIG_PATH, + actual, + ifconfig_local, + ifconfig_remote_netmask, + tun_mtu + ); + } + } + + argv_msg(M_INFO, &argv); + openvpn_execve_check(&argv, es, S_FATAL, "Mac OS X ifconfig failed"); + tt->did_ifconfig = true; + + /* Add a network route for the local tun interface */ + if (!tun && tt->topology == TOP_SUBNET) + { + struct route_ipv4 r; + CLEAR(r); + r.flags = RT_DEFINED; + r.network = tt->local & tt->remote_netmask; + r.netmask = tt->remote_netmask; + r.gateway = tt->local; + add_route(&r, tt, 0, NULL, es); + } + + if (do_ipv6) + { + argv_printf(&argv, + "%s %s inet6 %s/%d", + IFCONFIG_PATH, + actual, + ifconfig_ipv6_local, + tt->netbits_ipv6 + ); + argv_msg(M_INFO, &argv); + openvpn_execve_check(&argv, es, S_FATAL, "MacOS X ifconfig inet6 failed"); + + /* and, hooray, we explicitely need to add a route... */ + add_route_connected_v6_net(tt, es); + } + +#elif defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY) + + in_addr_t remote_end; /* for "virtual" subnet topology */ + + /* example: ifconfig tun2 10.2.0.2 10.2.0.1 mtu 1450 netmask 255.255.255.255 up */ + if (tun) + { + argv_printf(&argv, + "%s %s %s %s mtu %d netmask 255.255.255.255 up", + IFCONFIG_PATH, + actual, + ifconfig_local, + ifconfig_remote_netmask, + tun_mtu + ); + } + else if (tt->topology == TOP_SUBNET) + { + remote_end = create_arbitrary_remote( tt ); + argv_printf(&argv, + "%s %s %s %s mtu %d netmask %s up", + IFCONFIG_PATH, + actual, + ifconfig_local, + print_in_addr_t(remote_end, 0, &gc), + tun_mtu, + ifconfig_remote_netmask + ); + } + else + { + argv_printf(&argv, + "%s %s %s netmask %s mtu %d up", + IFCONFIG_PATH, + actual, + ifconfig_local, + ifconfig_remote_netmask, + tun_mtu + ); + } + + argv_msg(M_INFO, &argv); + openvpn_execve_check(&argv, es, S_FATAL, "FreeBSD ifconfig failed"); + tt->did_ifconfig = true; + + /* Add a network route for the local tun interface */ + if (!tun && tt->topology == TOP_SUBNET) + { + struct route_ipv4 r; + CLEAR(r); + r.flags = RT_DEFINED; + r.network = tt->local & tt->remote_netmask; + r.netmask = tt->remote_netmask; + r.gateway = remote_end; + add_route(&r, tt, 0, NULL, es); + } + + if (do_ipv6) + { + argv_printf(&argv, + "%s %s inet6 %s/%d", + IFCONFIG_PATH, + actual, + ifconfig_ipv6_local, + tt->netbits_ipv6 + ); + argv_msg(M_INFO, &argv); + openvpn_execve_check(&argv, es, S_FATAL, "FreeBSD ifconfig inet6 failed"); + } + +#elif defined(TARGET_AIX) + { + /* AIX ifconfig will complain if it can't find ODM path in env */ + struct env_set *aix_es = env_set_create(NULL); + env_set_add( aix_es, "ODMDIR=/etc/objrepos" ); + + if (tun) + { + msg(M_FATAL, "no tun support on AIX (canthappen)"); + } + + /* example: ifconfig tap0 172.30.1.1 netmask 255.255.254.0 up */ + argv_printf(&argv, + "%s %s %s netmask %s mtu %d up", + IFCONFIG_PATH, + actual, + ifconfig_local, + ifconfig_remote_netmask, + tun_mtu + ); + + argv_msg(M_INFO, &argv); + openvpn_execve_check(&argv, aix_es, S_FATAL, "AIX ifconfig failed"); + tt->did_ifconfig = true; + + if (do_ipv6) + { + argv_printf(&argv, + "%s %s inet6 %s/%d", + IFCONFIG_PATH, + actual, + ifconfig_ipv6_local, + tt->netbits_ipv6 + ); + argv_msg(M_INFO, &argv); + openvpn_execve_check(&argv, aix_es, S_FATAL, "AIX ifconfig inet6 failed"); + } + env_set_destroy(aix_es); + } +#elif defined (_WIN32) + { + ASSERT(actual != NULL); + + switch (tt->options.ip_win32_type) + { + case IPW32_SET_MANUAL: + msg(M_INFO, "******** NOTE: Please manually set the IP/netmask of '%s' to %s/%s (if it is not already set)", + actual, + ifconfig_local, + print_in_addr_t(tt->adapter_netmask, 0, &gc)); + break; + + case IPW32_SET_NETSH: + netsh_ifconfig(&tt->options, + actual, + tt->local, + tt->adapter_netmask, + NI_IP_NETMASK|NI_OPTIONS); + + break; + } + tt->did_ifconfig = true; + } + + if (do_ipv6) + { + if (tt->options.ip_win32_type == IPW32_SET_MANUAL) + { + msg(M_INFO, "******** NOTE: Please manually set the v6 IP of '%s' to %s (if it is not already set)", + actual, + ifconfig_ipv6_local); + } + else if (tt->options.msg_channel) + { + do_address_service(true, AF_INET6, tt); + do_dns6_service(true, tt); + } + else + { + /* example: netsh interface ipv6 set address interface=42 2001:608:8003::d store=active */ + char iface[64]; + openvpn_snprintf(iface, sizeof(iface), "interface=%lu", tt->adapter_index ); + argv_printf(&argv, + "%s%sc interface ipv6 set address %s %s store=active", + get_win_sys_path(), + NETSH_PATH_SUFFIX, + iface, + ifconfig_ipv6_local ); + netsh_command(&argv, 4, M_FATAL); + /* set ipv6 dns servers if any are specified */ + netsh_set_dns6_servers(tt->options.dns6, tt->options.dns6_len, actual); + } + + /* explicit route needed */ + if (tt->options.ip_win32_type != IPW32_SET_MANUAL) + { + add_route_connected_v6_net(tt, es); + } + } +#else /* if defined(TARGET_LINUX) */ + msg(M_FATAL, "Sorry, but I don't know how to do 'ifconfig' commands on this operating system. You should ifconfig your TUN/TAP device manually or use an --up script."); +#endif /* if defined(TARGET_LINUX) */ + argv_reset(&argv); + } + gc_free(&gc); +} + +static void +clear_tuntap(struct tuntap *tuntap) +{ + CLEAR(*tuntap); +#ifdef _WIN32 + tuntap->hand = NULL; +#else + tuntap->fd = -1; +#endif +#ifdef TARGET_SOLARIS + tuntap->ip_fd = -1; +#endif +} + +static void +open_null(struct tuntap *tt) +{ + tt->actual_name = string_alloc("null", NULL); +} + + +#if defined (TARGET_OPENBSD) || (defined(TARGET_DARWIN) && HAVE_NET_IF_UTUN_H) + +/* + * OpenBSD and Mac OS X when using utun + * have a slightly incompatible TUN device from + * the rest of the world, in that it prepends a + * uint32 to the beginning of the IP header + * to designate the protocol (why not just + * look at the version field in the IP header to + * determine v4 or v6?). + * + * We strip off this field on reads and + * put it back on writes. + * + * I have not tested TAP devices on OpenBSD, + * but I have conditionalized the special + * TUN handling code described above to + * go away for TAP devices. + */ + +#include +#include + +static inline int +header_modify_read_write_return(int len) +{ + if (len > 0) + { + return len > sizeof(u_int32_t) ? len - sizeof(u_int32_t) : 0; + } + else + { + return len; + } +} + +int +write_tun_header(struct tuntap *tt, uint8_t *buf, int len) +{ + if (tt->type == DEV_TYPE_TUN) + { + u_int32_t type; + struct iovec iv[2]; + struct ip *iph; + + iph = (struct ip *) buf; + + if (iph->ip_v == 6) + { + type = htonl(AF_INET6); + } + else + { + type = htonl(AF_INET); + } + + iv[0].iov_base = &type; + iv[0].iov_len = sizeof(type); + iv[1].iov_base = buf; iv[1].iov_len = len; - return header_modify_read_write_return (readv (tt->fd, iv, 2)); - } + return header_modify_read_write_return(writev(tt->fd, iv, 2)); + } else - return read (tt->fd, buf, len); + { + return write(tt->fd, buf, len); + } } -#endif + +int +read_tun_header(struct tuntap *tt, uint8_t *buf, int len) +{ + if (tt->type == DEV_TYPE_TUN) + { + u_int32_t type; + struct iovec iv[2]; + + iv[0].iov_base = &type; + iv[0].iov_len = sizeof(type); + iv[1].iov_base = buf; + iv[1].iov_len = len; + + return header_modify_read_write_return(readv(tt->fd, iv, 2)); + } + else + { + return read(tt->fd, buf, len); + } +} +#endif /* if defined (TARGET_OPENBSD) || (defined(TARGET_DARWIN) && HAVE_NET_IF_UTUN_H) */ #if !(defined(_WIN32) || defined(TARGET_LINUX)) static void -open_tun_generic (const char *dev, const char *dev_type, const char *dev_node, - bool dynamic, struct tuntap *tt) -{ - char tunname[256]; - char dynamic_name[256]; - bool dynamic_opened = false; - - if (tt->type == DEV_TYPE_NULL) - { - open_null (tt); - } - else - { - /* - * --dev-node specified, so open an explicit device node - */ - if (dev_node) - { - openvpn_snprintf (tunname, sizeof (tunname), "%s", dev_node); - } - else - { - /* - * dynamic open is indicated by --dev specified without - * explicit unit number. Try opening /dev/[dev]n - * where n = [0, 255]. - */ +open_tun_generic(const char *dev, const char *dev_type, const char *dev_node, + bool dynamic, struct tuntap *tt) +{ + char tunname[256]; + char dynamic_name[256]; + bool dynamic_opened = false; + + if (tt->type == DEV_TYPE_NULL) + { + open_null(tt); + } + else + { + /* + * --dev-node specified, so open an explicit device node + */ + if (dev_node) + { + openvpn_snprintf(tunname, sizeof(tunname), "%s", dev_node); + } + else + { + /* + * dynamic open is indicated by --dev specified without + * explicit unit number. Try opening /dev/[dev]n + * where n = [0, 255]. + */ #ifdef TARGET_NETBSD - /* on NetBSD, tap (but not tun) devices are opened by - * opening /dev/tap and then querying the system about the - * actual device name (tap0, tap1, ...) assigned - */ - if ( dynamic && strcmp( dev, "tap" ) == 0 ) - { - struct ifreq ifr; - if ((tt->fd = open ( "/dev/tap", O_RDWR)) < 0) - { - msg (M_FATAL, "Cannot allocate NetBSD TAP dev dynamically"); - } - if ( ioctl( tt->fd, TAPGIFNAME, (void*)&ifr ) < 0 ) - { - msg (M_FATAL, "Cannot query NetBSD TAP device name"); - } - CLEAR(dynamic_name); - strncpy( dynamic_name, ifr.ifr_name, sizeof(dynamic_name)-1 ); - dynamic_opened = true; - openvpn_snprintf (tunname, sizeof (tunname), "/dev/%s", dynamic_name ); - } - else + /* on NetBSD, tap (but not tun) devices are opened by + * opening /dev/tap and then querying the system about the + * actual device name (tap0, tap1, ...) assigned + */ + if (dynamic && strcmp( dev, "tap" ) == 0) + { + struct ifreq ifr; + if ((tt->fd = open( "/dev/tap", O_RDWR)) < 0) + { + msg(M_FATAL, "Cannot allocate NetBSD TAP dev dynamically"); + } + if (ioctl( tt->fd, TAPGIFNAME, (void *)&ifr ) < 0) + { + msg(M_FATAL, "Cannot query NetBSD TAP device name"); + } + CLEAR(dynamic_name); + strncpy( dynamic_name, ifr.ifr_name, sizeof(dynamic_name)-1 ); + dynamic_opened = true; + openvpn_snprintf(tunname, sizeof(tunname), "/dev/%s", dynamic_name ); + } + else #endif - if (dynamic && !has_digit((unsigned char *)dev)) - { - int i; - for (i = 0; i < 256; ++i) - { - openvpn_snprintf (tunname, sizeof (tunname), - "/dev/%s%d", dev, i); - openvpn_snprintf (dynamic_name, sizeof (dynamic_name), - "%s%d", dev, i); - if ((tt->fd = open (tunname, O_RDWR)) > 0) - { - dynamic_opened = true; - break; - } - msg (D_READ_WRITE | M_ERRNO, "Tried opening %s (failed)", tunname); - } - if (!dynamic_opened) - msg (M_FATAL, "Cannot allocate TUN/TAP dev dynamically"); - } - /* - * explicit unit number specified - */ - else - { - openvpn_snprintf (tunname, sizeof (tunname), "/dev/%s", dev); - } - } - - if (!dynamic_opened) - { - /* has named device existed before? if so, don't destroy at end */ - if ( if_nametoindex( dev ) > 0 ) - { - msg (M_INFO, "TUN/TAP device %s exists previously, keep at program end", dev ); - tt->persistent_if = true; - } - - if ((tt->fd = open (tunname, O_RDWR)) < 0) - msg (M_ERR, "Cannot open TUN/TAP dev %s", tunname); - } - - set_nonblock (tt->fd); - set_cloexec (tt->fd); /* don't pass fd to scripts */ - msg (M_INFO, "TUN/TAP device %s opened", tunname); - - /* tt->actual_name is passed to up and down scripts and used as the ifconfig dev name */ - tt->actual_name = string_alloc (dynamic_opened ? dynamic_name : dev, NULL); + if (dynamic && !has_digit((unsigned char *)dev)) + { + int i; + for (i = 0; i < 256; ++i) + { + openvpn_snprintf(tunname, sizeof(tunname), + "/dev/%s%d", dev, i); + openvpn_snprintf(dynamic_name, sizeof(dynamic_name), + "%s%d", dev, i); + if ((tt->fd = open(tunname, O_RDWR)) > 0) + { + dynamic_opened = true; + break; + } + msg(D_READ_WRITE | M_ERRNO, "Tried opening %s (failed)", tunname); + } + if (!dynamic_opened) + { + msg(M_FATAL, "Cannot allocate TUN/TAP dev dynamically"); + } + } + /* + * explicit unit number specified + */ + else + { + openvpn_snprintf(tunname, sizeof(tunname), "/dev/%s", dev); + } + } + + if (!dynamic_opened) + { + /* has named device existed before? if so, don't destroy at end */ + if (if_nametoindex( dev ) > 0) + { + msg(M_INFO, "TUN/TAP device %s exists previously, keep at program end", dev ); + tt->persistent_if = true; + } + + if ((tt->fd = open(tunname, O_RDWR)) < 0) + { + msg(M_ERR, "Cannot open TUN/TAP dev %s", tunname); + } + } + + set_nonblock(tt->fd); + set_cloexec(tt->fd); /* don't pass fd to scripts */ + msg(M_INFO, "TUN/TAP device %s opened", tunname); + + /* tt->actual_name is passed to up and down scripts and used as the ifconfig dev name */ + tt->actual_name = string_alloc(dynamic_opened ? dynamic_name : dev, NULL); } } #endif /* !_WIN32 && !TARGET_LINUX */ #if !defined(_WIN32) static void -close_tun_generic (struct tuntap *tt) +close_tun_generic(struct tuntap *tt) { - if (tt->fd >= 0) - close (tt->fd); - if (tt->actual_name) - free (tt->actual_name); - clear_tuntap (tt); + if (tt->fd >= 0) + { + close(tt->fd); + } + if (tt->actual_name) + { + free(tt->actual_name); + } + clear_tuntap(tt); } #endif /* !_WIN32 */ #if defined (TARGET_ANDROID) void -open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) +open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) { #define ANDROID_TUNNAME "vpnservice-tun" - struct user_pass up; - struct gc_arena gc = gc_new (); - bool opentun; + struct user_pass up; + struct gc_arena gc = gc_new(); + bool opentun; - int oldtunfd = tt->fd; + int oldtunfd = tt->fd; - /* Prefer IPv6 DNS servers, - * Android will use the DNS server in the order we specify*/ - for (int i = 0; i < tt->options.dns6_len; i++) { - management_android_control (management, "DNS6SERVER", - print_in6_addr (tt->options.dns6[i], 0, &gc)); - } + /* Prefer IPv6 DNS servers, + * Android will use the DNS server in the order we specify*/ + for (int i = 0; i < tt->options.dns6_len; i++) { + management_android_control(management, "DNS6SERVER", + print_in6_addr(tt->options.dns6[i], 0, &gc)); + } - for (int i = 0; i < tt->options.dns_len; i++) { - management_android_control (management, "DNSSERVER", - print_in_addr_t(tt->options.dns[i], 0, &gc)); - } + for (int i = 0; i < tt->options.dns_len; i++) { + management_android_control(management, "DNSSERVER", + print_in_addr_t(tt->options.dns[i], 0, &gc)); + } - if(tt->options.domain) - management_android_control (management, "DNSDOMAIN", tt->options.domain); + if (tt->options.domain) + { + management_android_control(management, "DNSDOMAIN", tt->options.domain); + } - int android_method = managment_android_persisttun_action (management); + int android_method = managment_android_persisttun_action(management); - /* Android 4.4 workaround */ - if (oldtunfd >=0 && android_method == ANDROID_OPEN_AFTER_CLOSE) + /* Android 4.4 workaround */ + if (oldtunfd >=0 && android_method == ANDROID_OPEN_AFTER_CLOSE) { - close(oldtunfd); - openvpn_sleep(2); + close(oldtunfd); + openvpn_sleep(2); } - if (oldtunfd >=0 && android_method == ANDROID_KEEP_OLD_TUN) { - /* keep the old fd */ - opentun = true; - } else { - opentun = management_android_control (management, "OPENTUN", dev); - /* Pick up the fd from management interface after calling the - * OPENTUN command */ - tt->fd = management->connection.lastfdreceived; - management->connection.lastfdreceived=-1; - } + if (oldtunfd >=0 && android_method == ANDROID_KEEP_OLD_TUN) + { + /* keep the old fd */ + opentun = true; + } + else + { + opentun = management_android_control(management, "OPENTUN", dev); + /* Pick up the fd from management interface after calling the + * OPENTUN command */ + tt->fd = management->connection.lastfdreceived; + management->connection.lastfdreceived = -1; + } - if (oldtunfd>=0 && android_method == ANDROID_OPEN_BEFORE_CLOSE) - close(oldtunfd); + if (oldtunfd>=0 && android_method == ANDROID_OPEN_BEFORE_CLOSE) + { + close(oldtunfd); + } - /* Set the actual name to a dummy name */ - tt->actual_name = string_alloc (ANDROID_TUNNAME, NULL); + /* Set the actual name to a dummy name */ + tt->actual_name = string_alloc(ANDROID_TUNNAME, NULL); - if ((tt->fd < 0) || !opentun) - msg (M_ERR, "ERROR: Cannot open TUN"); + if ((tt->fd < 0) || !opentun) + { + msg(M_ERR, "ERROR: Cannot open TUN"); + } - gc_free (&gc); + gc_free(&gc); } void -close_tun (struct tuntap *tt) +close_tun(struct tuntap *tt) { if (tt) { - close_tun_generic (tt); - free (tt); + close_tun_generic(tt); + free(tt); } } int -write_tun (struct tuntap* tt, uint8_t *buf, int len) +write_tun(struct tuntap *tt, uint8_t *buf, int len) { - return write (tt->fd, buf, len); + return write(tt->fd, buf, len); } int -read_tun (struct tuntap* tt, uint8_t *buf, int len) +read_tun(struct tuntap *tt, uint8_t *buf, int len) { - return read (tt->fd, buf, len); + return read(tt->fd, buf, len); } #elif defined(TARGET_LINUX) @@ -1790,117 +1920,126 @@ read_tun (struct tuntap* tt, uint8_t *buf, int len) #if !PEDANTIC void -open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) +open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) { - struct ifreq ifr; + struct ifreq ifr; - /* - * We handle --dev null specially, we do not open /dev/null for this. - */ - if (tt->type == DEV_TYPE_NULL) + /* + * We handle --dev null specially, we do not open /dev/null for this. + */ + if (tt->type == DEV_TYPE_NULL) { - open_null (tt); + open_null(tt); } - else + else { - /* - * Process --dev-node - */ - const char *node = dev_node; - if (!node) - node = "/dev/net/tun"; + /* + * Process --dev-node + */ + const char *node = dev_node; + if (!node) + { + node = "/dev/net/tun"; + } - /* - * Open the interface - */ - if ((tt->fd = open (node, O_RDWR)) < 0) - { - msg (M_ERR, "ERROR: Cannot open TUN/TAP dev %s", node); - } + /* + * Open the interface + */ + if ((tt->fd = open(node, O_RDWR)) < 0) + { + msg(M_ERR, "ERROR: Cannot open TUN/TAP dev %s", node); + } - /* - * Process --tun-ipv6 - */ - CLEAR (ifr); - ifr.ifr_flags = IFF_NO_PI; + /* + * Process --tun-ipv6 + */ + CLEAR(ifr); + ifr.ifr_flags = IFF_NO_PI; #if defined(IFF_ONE_QUEUE) && defined(SIOCSIFTXQLEN) - ifr.ifr_flags |= IFF_ONE_QUEUE; + ifr.ifr_flags |= IFF_ONE_QUEUE; #endif - /* - * Figure out if tun or tap device - */ - if (tt->type == DEV_TYPE_TUN) - { - ifr.ifr_flags |= IFF_TUN; - } - else if (tt->type == DEV_TYPE_TAP) - { - ifr.ifr_flags |= IFF_TAP; - } - else - { - msg (M_FATAL, "I don't recognize device %s as a tun or tap device", - dev); - } - - /* - * Set an explicit name, if --dev is not tun or tap - */ - if (strcmp(dev, "tun") && strcmp(dev, "tap")) - strncpynt (ifr.ifr_name, dev, IFNAMSIZ); - - /* - * Use special ioctl that configures tun/tap device with the parms - * we set in ifr - */ - if (ioctl (tt->fd, TUNSETIFF, (void *) &ifr) < 0) - { - msg (M_ERR, "ERROR: Cannot ioctl TUNSETIFF %s", dev); - } - - msg (M_INFO, "TUN/TAP device %s opened", ifr.ifr_name); - - /* - * Try making the TX send queue bigger - */ + /* + * Figure out if tun or tap device + */ + if (tt->type == DEV_TYPE_TUN) + { + ifr.ifr_flags |= IFF_TUN; + } + else if (tt->type == DEV_TYPE_TAP) + { + ifr.ifr_flags |= IFF_TAP; + } + else + { + msg(M_FATAL, "I don't recognize device %s as a tun or tap device", + dev); + } + + /* + * Set an explicit name, if --dev is not tun or tap + */ + if (strcmp(dev, "tun") && strcmp(dev, "tap")) + { + strncpynt(ifr.ifr_name, dev, IFNAMSIZ); + } + + /* + * Use special ioctl that configures tun/tap device with the parms + * we set in ifr + */ + if (ioctl(tt->fd, TUNSETIFF, (void *) &ifr) < 0) + { + msg(M_ERR, "ERROR: Cannot ioctl TUNSETIFF %s", dev); + } + + msg(M_INFO, "TUN/TAP device %s opened", ifr.ifr_name); + + /* + * Try making the TX send queue bigger + */ #if defined(IFF_ONE_QUEUE) && defined(SIOCSIFTXQLEN) - if (tt->options.txqueuelen) { - struct ifreq netifr; - int ctl_fd; - - if ((ctl_fd = socket (AF_INET, SOCK_DGRAM, 0)) >= 0) - { - CLEAR (netifr); - strncpynt (netifr.ifr_name, ifr.ifr_name, IFNAMSIZ); - netifr.ifr_qlen = tt->options.txqueuelen; - if (ioctl (ctl_fd, SIOCSIFTXQLEN, (void *) &netifr) >= 0) - msg (D_OSBUF, "TUN/TAP TX queue length set to %d", tt->options.txqueuelen); - else - msg (M_WARN | M_ERRNO, "Note: Cannot set tx queue length on %s", ifr.ifr_name); - close (ctl_fd); - } - else - { - msg (M_WARN | M_ERRNO, "Note: Cannot open control socket on %s", ifr.ifr_name); - } - } -#endif + if (tt->options.txqueuelen) + { + struct ifreq netifr; + int ctl_fd; - set_nonblock (tt->fd); - set_cloexec (tt->fd); - tt->actual_name = string_alloc (ifr.ifr_name, NULL); + if ((ctl_fd = socket(AF_INET, SOCK_DGRAM, 0)) >= 0) + { + CLEAR(netifr); + strncpynt(netifr.ifr_name, ifr.ifr_name, IFNAMSIZ); + netifr.ifr_qlen = tt->options.txqueuelen; + if (ioctl(ctl_fd, SIOCSIFTXQLEN, (void *) &netifr) >= 0) + { + msg(D_OSBUF, "TUN/TAP TX queue length set to %d", tt->options.txqueuelen); + } + else + { + msg(M_WARN | M_ERRNO, "Note: Cannot set tx queue length on %s", ifr.ifr_name); + } + close(ctl_fd); + } + else + { + msg(M_WARN | M_ERRNO, "Note: Cannot open control socket on %s", ifr.ifr_name); + } + } +#endif /* if defined(IFF_ONE_QUEUE) && defined(SIOCSIFTXQLEN) */ + + set_nonblock(tt->fd); + set_cloexec(tt->fd); + tt->actual_name = string_alloc(ifr.ifr_name, NULL); } - return; + return; } -#else +#else /* if !PEDANTIC */ void -open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) +open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) { - ASSERT (0); + ASSERT(0); } #endif /* !PENDANTIC */ @@ -1908,129 +2047,137 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tu #ifdef ENABLE_FEATURE_TUN_PERSIST void -tuncfg (const char *dev, const char *dev_type, const char *dev_node, int persist_mode, const char *username, const char *groupname, const struct tuntap_options *options) +tuncfg(const char *dev, const char *dev_type, const char *dev_node, int persist_mode, const char *username, const char *groupname, const struct tuntap_options *options) { - struct tuntap *tt; + struct tuntap *tt; - ALLOC_OBJ (tt, struct tuntap); - clear_tuntap (tt); - tt->type = dev_type_enum (dev, dev_type); - tt->options = *options; - open_tun (dev, dev_type, dev_node, tt); - if (ioctl (tt->fd, TUNSETPERSIST, persist_mode) < 0) - msg (M_ERR, "Cannot ioctl TUNSETPERSIST(%d) %s", persist_mode, dev); - if (username != NULL) + ALLOC_OBJ(tt, struct tuntap); + clear_tuntap(tt); + tt->type = dev_type_enum(dev, dev_type); + tt->options = *options; + open_tun(dev, dev_type, dev_node, tt); + if (ioctl(tt->fd, TUNSETPERSIST, persist_mode) < 0) + { + msg(M_ERR, "Cannot ioctl TUNSETPERSIST(%d) %s", persist_mode, dev); + } + if (username != NULL) { - struct platform_state_user platform_state_user; + struct platform_state_user platform_state_user; - if (!platform_user_get (username, &platform_state_user)) - msg (M_ERR, "Cannot get user entry for %s", username); - else - if (ioctl (tt->fd, TUNSETOWNER, platform_state_user.pw->pw_uid) < 0) - msg (M_ERR, "Cannot ioctl TUNSETOWNER(%s) %s", username, dev); + if (!platform_user_get(username, &platform_state_user)) + { + msg(M_ERR, "Cannot get user entry for %s", username); + } + else if (ioctl(tt->fd, TUNSETOWNER, platform_state_user.pw->pw_uid) < 0) + { + msg(M_ERR, "Cannot ioctl TUNSETOWNER(%s) %s", username, dev); + } } - if (groupname != NULL) + if (groupname != NULL) { - struct platform_state_group platform_state_group; + struct platform_state_group platform_state_group; - if (!platform_group_get (groupname, &platform_state_group)) - msg (M_ERR, "Cannot get group entry for %s", groupname); - else - if (ioctl (tt->fd, TUNSETGROUP, platform_state_group.gr->gr_gid) < 0) - msg (M_ERR, "Cannot ioctl TUNSETOWNER(%s) %s", groupname, dev); + if (!platform_group_get(groupname, &platform_state_group)) + { + msg(M_ERR, "Cannot get group entry for %s", groupname); + } + else if (ioctl(tt->fd, TUNSETGROUP, platform_state_group.gr->gr_gid) < 0) + { + msg(M_ERR, "Cannot ioctl TUNSETOWNER(%s) %s", groupname, dev); + } } - close_tun (tt); - msg (M_INFO, "Persist state set to: %s", (persist_mode ? "ON" : "OFF")); + close_tun(tt); + msg(M_INFO, "Persist state set to: %s", (persist_mode ? "ON" : "OFF")); } #endif /* ENABLE_FEATURE_TUN_PERSIST */ void -close_tun (struct tuntap *tt) +close_tun(struct tuntap *tt) { - if (tt) + if (tt) { - if (tt->type != DEV_TYPE_NULL && tt->did_ifconfig) - { - struct argv argv = argv_new (); - struct gc_arena gc = gc_new (); + if (tt->type != DEV_TYPE_NULL && tt->did_ifconfig) + { + struct argv argv = argv_new(); + struct gc_arena gc = gc_new(); #ifdef ENABLE_IPROUTE - if (is_tun_p2p (tt)) - { - argv_printf (&argv, - "%s addr del dev %s local %s peer %s", - iproute_path, - tt->actual_name, - print_in_addr_t (tt->local, 0, &gc), - print_in_addr_t (tt->remote_netmask, 0, &gc) - ); - } - else - { - argv_printf (&argv, - "%s addr del dev %s %s/%d", - iproute_path, - tt->actual_name, - print_in_addr_t (tt->local, 0, &gc), - netmask_to_netbits2(tt->remote_netmask) - ); - } -#else - argv_printf (&argv, - "%s %s 0.0.0.0", - IFCONFIG_PATH, - tt->actual_name - ); -#endif + if (is_tun_p2p(tt)) + { + argv_printf(&argv, + "%s addr del dev %s local %s peer %s", + iproute_path, + tt->actual_name, + print_in_addr_t(tt->local, 0, &gc), + print_in_addr_t(tt->remote_netmask, 0, &gc) + ); + } + else + { + argv_printf(&argv, + "%s addr del dev %s %s/%d", + iproute_path, + tt->actual_name, + print_in_addr_t(tt->local, 0, &gc), + netmask_to_netbits2(tt->remote_netmask) + ); + } +#else /* ifdef ENABLE_IPROUTE */ + argv_printf(&argv, + "%s %s 0.0.0.0", + IFCONFIG_PATH, + tt->actual_name + ); +#endif /* ifdef ENABLE_IPROUTE */ - argv_msg (M_INFO, &argv); - openvpn_execve_check (&argv, NULL, 0, "Linux ip addr del failed"); + argv_msg(M_INFO, &argv); + openvpn_execve_check(&argv, NULL, 0, "Linux ip addr del failed"); if (tt->did_ifconfig_ipv6_setup) - { - const char * ifconfig_ipv6_local = print_in6_addr (tt->local_ipv6, 0, &gc); + { + const char *ifconfig_ipv6_local = print_in6_addr(tt->local_ipv6, 0, &gc); #ifdef ENABLE_IPROUTE - argv_printf (&argv, "%s -6 addr del %s/%d dev %s", - iproute_path, - ifconfig_ipv6_local, - tt->netbits_ipv6, - tt->actual_name - ); - argv_msg (M_INFO, &argv); - openvpn_execve_check (&argv, NULL, 0, "Linux ip -6 addr del failed"); -#else - argv_printf (&argv, + argv_printf(&argv, "%s -6 addr del %s/%d dev %s", + iproute_path, + ifconfig_ipv6_local, + tt->netbits_ipv6, + tt->actual_name + ); + argv_msg(M_INFO, &argv); + openvpn_execve_check(&argv, NULL, 0, "Linux ip -6 addr del failed"); +#else /* ifdef ENABLE_IPROUTE */ + argv_printf(&argv, "%s %s del %s/%d", IFCONFIG_PATH, tt->actual_name, ifconfig_ipv6_local, tt->netbits_ipv6 ); - argv_msg (M_INFO, &argv); - openvpn_execve_check (&argv, NULL, 0, "Linux ifconfig inet6 del failed"); + argv_msg(M_INFO, &argv); + openvpn_execve_check(&argv, NULL, 0, "Linux ifconfig inet6 del failed"); #endif - } + } - argv_reset (&argv); - gc_free (&gc); - } - close_tun_generic (tt); - free (tt); + argv_reset(&argv); + gc_free(&gc); + } + close_tun_generic(tt); + free(tt); } } int -write_tun (struct tuntap* tt, uint8_t *buf, int len) +write_tun(struct tuntap *tt, uint8_t *buf, int len) { - return write (tt->fd, buf, len); + return write(tt->fd, buf, len); } int -read_tun (struct tuntap* tt, uint8_t *buf, int len) +read_tun(struct tuntap *tt, uint8_t *buf, int len) { - return read (tt->fd, buf, len); + return read(tt->fd, buf, len); } #elif defined(TARGET_SOLARIS) @@ -2040,332 +2187,387 @@ read_tun (struct tuntap* tt, uint8_t *buf, int len) #endif void -open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) -{ - int if_fd, ip_muxid, arp_muxid, arp_fd, ppa = -1; - struct lifreq ifr; - const char *ptr; - const char *ip_node, *arp_node; - const char *dev_tuntap_type; - int link_type; - bool is_tun; - struct strioctl strioc_if, strioc_ppa; - - /* improved generic TUN/TAP driver from - * http://www.whiteboard.ne.jp/~admin2/tuntap/ - * has IPv6 support - */ - CLEAR(ifr); +open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) +{ + int if_fd, ip_muxid, arp_muxid, arp_fd, ppa = -1; + struct lifreq ifr; + const char *ptr; + const char *ip_node, *arp_node; + const char *dev_tuntap_type; + int link_type; + bool is_tun; + struct strioctl strioc_if, strioc_ppa; + + /* improved generic TUN/TAP driver from + * http://www.whiteboard.ne.jp/~admin2/tuntap/ + * has IPv6 support + */ + CLEAR(ifr); - if (tt->type == DEV_TYPE_NULL) + if (tt->type == DEV_TYPE_NULL) { - open_null (tt); - return; + open_null(tt); + return; } - if (tt->type == DEV_TYPE_TUN) + if (tt->type == DEV_TYPE_TUN) { - ip_node = "/dev/udp"; - if (!dev_node) - dev_node = "/dev/tun"; - dev_tuntap_type = "tun"; - link_type = I_PLINK; - is_tun = true; + ip_node = "/dev/udp"; + if (!dev_node) + { + dev_node = "/dev/tun"; + } + dev_tuntap_type = "tun"; + link_type = I_PLINK; + is_tun = true; } - else if (tt->type == DEV_TYPE_TAP) + else if (tt->type == DEV_TYPE_TAP) { - ip_node = "/dev/udp"; - if (!dev_node) - dev_node = "/dev/tap"; - arp_node = dev_node; - dev_tuntap_type = "tap"; - link_type = I_PLINK; /* was: I_LINK */ - is_tun = false; + ip_node = "/dev/udp"; + if (!dev_node) + { + dev_node = "/dev/tap"; + } + arp_node = dev_node; + dev_tuntap_type = "tap"; + link_type = I_PLINK; /* was: I_LINK */ + is_tun = false; } - else + else { - msg (M_FATAL, "I don't recognize device %s as a tun or tap device", - dev); + msg(M_FATAL, "I don't recognize device %s as a tun or tap device", + dev); } - if ((tt->ip_fd = open (ip_node, O_RDWR, 0)) < 0) - msg (M_ERR, "Can't open %s", ip_node); + if ((tt->ip_fd = open(ip_node, O_RDWR, 0)) < 0) + { + msg(M_ERR, "Can't open %s", ip_node); + } + + if ((tt->fd = open(dev_node, O_RDWR, 0)) < 0) + { + msg(M_ERR, "Can't open %s", dev_node); + } - if ((tt->fd = open (dev_node, O_RDWR, 0)) < 0) - msg (M_ERR, "Can't open %s", dev_node); - - /* get unit number */ - if (*dev) + /* get unit number */ + if (*dev) { - ptr = dev; - while (*ptr && !isdigit ((int) *ptr)) - ptr++; - ppa = atoi (ptr); + ptr = dev; + while (*ptr && !isdigit((int) *ptr)) + ptr++; + ppa = atoi(ptr); } - /* Assign a new PPA and get its unit number. */ - strioc_ppa.ic_cmd = TUNNEWPPA; - strioc_ppa.ic_timout = 0; - strioc_ppa.ic_len = sizeof(ppa); - strioc_ppa.ic_dp = (char *)&ppa; + /* Assign a new PPA and get its unit number. */ + strioc_ppa.ic_cmd = TUNNEWPPA; + strioc_ppa.ic_timout = 0; + strioc_ppa.ic_len = sizeof(ppa); + strioc_ppa.ic_dp = (char *)&ppa; - if ( *ptr == '\0' ) /* no number given, try dynamic */ + if (*ptr == '\0') /* no number given, try dynamic */ { - bool found_one = false; - while( ! found_one && ppa < 64 ) - { - int new_ppa = ioctl (tt->fd, I_STR, &strioc_ppa); - if ( new_ppa >= 0 ) - { - msg( M_INFO, "open_tun: got dynamic interface '%s%d'", dev_tuntap_type, new_ppa ); - ppa = new_ppa; - found_one = true; - break; - } - if ( errno != EEXIST ) - msg (M_ERR, "open_tun: unexpected error trying to find free %s interface", dev_tuntap_type ); - ppa++; - } - if ( !found_one ) - msg (M_ERR, "open_tun: could not find free %s interface, give up.", dev_tuntap_type ); + bool found_one = false; + while (!found_one && ppa < 64) + { + int new_ppa = ioctl(tt->fd, I_STR, &strioc_ppa); + if (new_ppa >= 0) + { + msg( M_INFO, "open_tun: got dynamic interface '%s%d'", dev_tuntap_type, new_ppa ); + ppa = new_ppa; + found_one = true; + break; + } + if (errno != EEXIST) + { + msg(M_ERR, "open_tun: unexpected error trying to find free %s interface", dev_tuntap_type ); + } + ppa++; + } + if (!found_one) + { + msg(M_ERR, "open_tun: could not find free %s interface, give up.", dev_tuntap_type ); + } } - else /* try this particular one */ + else /* try this particular one */ { - if ((ppa = ioctl (tt->fd, I_STR, &strioc_ppa)) < 0) - msg (M_ERR, "Can't assign PPA for new interface (%s%d)", dev_tuntap_type, ppa ); + if ((ppa = ioctl(tt->fd, I_STR, &strioc_ppa)) < 0) + { + msg(M_ERR, "Can't assign PPA for new interface (%s%d)", dev_tuntap_type, ppa ); + } } - if ((if_fd = open (dev_node, O_RDWR, 0)) < 0) - msg (M_ERR, "Can't open %s (2)", dev_node); + if ((if_fd = open(dev_node, O_RDWR, 0)) < 0) + { + msg(M_ERR, "Can't open %s (2)", dev_node); + } - if (ioctl (if_fd, I_PUSH, "ip") < 0) - msg (M_ERR, "Can't push IP module"); + if (ioctl(if_fd, I_PUSH, "ip") < 0) + { + msg(M_ERR, "Can't push IP module"); + } - if (tt->type == DEV_TYPE_TUN) - { - /* Assign ppa according to the unit number returned by tun device */ - if (ioctl (if_fd, IF_UNITSEL, (char *) &ppa) < 0) - msg (M_ERR, "Can't set PPA %d", ppa); + if (tt->type == DEV_TYPE_TUN) + { + /* Assign ppa according to the unit number returned by tun device */ + if (ioctl(if_fd, IF_UNITSEL, (char *) &ppa) < 0) + { + msg(M_ERR, "Can't set PPA %d", ppa); + } } - tt->actual_name = (char *) malloc (32); - check_malloc_return (tt->actual_name); + tt->actual_name = (char *) malloc(32); + check_malloc_return(tt->actual_name); - openvpn_snprintf (tt->actual_name, 32, "%s%d", dev_tuntap_type, ppa); + openvpn_snprintf(tt->actual_name, 32, "%s%d", dev_tuntap_type, ppa); - if (tt->type == DEV_TYPE_TAP) + if (tt->type == DEV_TYPE_TAP) { - if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) < 0) - msg (M_ERR, "Can't get flags\n"); - strncpynt (ifr.lifr_name, tt->actual_name, sizeof (ifr.lifr_name)); - ifr.lifr_ppa = ppa; - /* Assign ppa according to the unit number returned by tun device */ - if (ioctl (if_fd, SIOCSLIFNAME, &ifr) < 0) - msg (M_ERR, "Can't set PPA %d", ppa); - if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) <0) - msg (M_ERR, "Can't get flags\n"); - /* Push arp module to if_fd */ - if (ioctl (if_fd, I_PUSH, "arp") < 0) - msg (M_ERR, "Can't push ARP module"); + if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) < 0) + { + msg(M_ERR, "Can't get flags\n"); + } + strncpynt(ifr.lifr_name, tt->actual_name, sizeof(ifr.lifr_name)); + ifr.lifr_ppa = ppa; + /* Assign ppa according to the unit number returned by tun device */ + if (ioctl(if_fd, SIOCSLIFNAME, &ifr) < 0) + { + msg(M_ERR, "Can't set PPA %d", ppa); + } + if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) <0) + { + msg(M_ERR, "Can't get flags\n"); + } + /* Push arp module to if_fd */ + if (ioctl(if_fd, I_PUSH, "arp") < 0) + { + msg(M_ERR, "Can't push ARP module"); + } - /* Pop any modules on the stream */ - while (true) + /* Pop any modules on the stream */ + while (true) + { + if (ioctl(tt->ip_fd, I_POP, NULL) < 0) { - if (ioctl (tt->ip_fd, I_POP, NULL) < 0) - break; + break; } - /* Push arp module to ip_fd */ - if (ioctl (tt->ip_fd, I_PUSH, "arp") < 0) - msg (M_ERR, "Can't push ARP module\n"); + } + /* Push arp module to ip_fd */ + if (ioctl(tt->ip_fd, I_PUSH, "arp") < 0) + { + msg(M_ERR, "Can't push ARP module\n"); + } - /* Open arp_fd */ - if ((arp_fd = open (arp_node, O_RDWR, 0)) < 0) - msg (M_ERR, "Can't open %s\n", arp_node); - /* Push arp module to arp_fd */ - if (ioctl (arp_fd, I_PUSH, "arp") < 0) - msg (M_ERR, "Can't push ARP module\n"); + /* Open arp_fd */ + if ((arp_fd = open(arp_node, O_RDWR, 0)) < 0) + { + msg(M_ERR, "Can't open %s\n", arp_node); + } + /* Push arp module to arp_fd */ + if (ioctl(arp_fd, I_PUSH, "arp") < 0) + { + msg(M_ERR, "Can't push ARP module\n"); + } - /* Set ifname to arp */ - strioc_if.ic_cmd = SIOCSLIFNAME; - strioc_if.ic_timout = 0; - strioc_if.ic_len = sizeof(ifr); - strioc_if.ic_dp = (char *)𝔦 - if (ioctl(arp_fd, I_STR, &strioc_if) < 0){ - msg (M_ERR, "Can't set ifname to arp\n"); - } - } + /* Set ifname to arp */ + strioc_if.ic_cmd = SIOCSLIFNAME; + strioc_if.ic_timout = 0; + strioc_if.ic_len = sizeof(ifr); + strioc_if.ic_dp = (char *)𝔦 + if (ioctl(arp_fd, I_STR, &strioc_if) < 0) + { + msg(M_ERR, "Can't set ifname to arp\n"); + } + } - if ((ip_muxid = ioctl (tt->ip_fd, link_type, if_fd)) < 0) - msg (M_ERR, "Can't link %s device to IP", dev_tuntap_type); + if ((ip_muxid = ioctl(tt->ip_fd, link_type, if_fd)) < 0) + { + msg(M_ERR, "Can't link %s device to IP", dev_tuntap_type); + } - if (tt->type == DEV_TYPE_TAP) { - if ((arp_muxid = ioctl (tt->ip_fd, link_type, arp_fd)) < 0) - msg (M_ERR, "Can't link %s device to ARP", dev_tuntap_type); - close (arp_fd); - } + if (tt->type == DEV_TYPE_TAP) + { + if ((arp_muxid = ioctl(tt->ip_fd, link_type, arp_fd)) < 0) + { + msg(M_ERR, "Can't link %s device to ARP", dev_tuntap_type); + } + close(arp_fd); + } - CLEAR (ifr); - strncpynt (ifr.lifr_name, tt->actual_name, sizeof (ifr.lifr_name)); - ifr.lifr_ip_muxid = ip_muxid; - if (tt->type == DEV_TYPE_TAP) { - ifr.lifr_arp_muxid = arp_muxid; - } + CLEAR(ifr); + strncpynt(ifr.lifr_name, tt->actual_name, sizeof(ifr.lifr_name)); + ifr.lifr_ip_muxid = ip_muxid; + if (tt->type == DEV_TYPE_TAP) + { + ifr.lifr_arp_muxid = arp_muxid; + } - if (ioctl (tt->ip_fd, SIOCSLIFMUXID, &ifr) < 0) + if (ioctl(tt->ip_fd, SIOCSLIFMUXID, &ifr) < 0) { - if (tt->type == DEV_TYPE_TAP) + if (tt->type == DEV_TYPE_TAP) { - ioctl (tt->ip_fd, I_PUNLINK , arp_muxid); + ioctl(tt->ip_fd, I_PUNLINK, arp_muxid); } - ioctl (tt->ip_fd, I_PUNLINK, ip_muxid); - msg (M_ERR, "Can't set multiplexor id"); + ioctl(tt->ip_fd, I_PUNLINK, ip_muxid); + msg(M_ERR, "Can't set multiplexor id"); } - set_nonblock (tt->fd); - set_cloexec (tt->fd); - set_cloexec (tt->ip_fd); + set_nonblock(tt->fd); + set_cloexec(tt->fd); + set_cloexec(tt->ip_fd); - msg (M_INFO, "TUN/TAP device %s opened", tt->actual_name); + msg(M_INFO, "TUN/TAP device %s opened", tt->actual_name); } static void -solaris_close_tun (struct tuntap *tt) -{ - if (tt) - { - /* IPv6 interfaces need to be 'manually' de-configured */ - if ( tt->did_ifconfig_ipv6_setup ) - { - struct argv argv = argv_new (); - argv_printf( &argv, "%s %s inet6 unplumb", - IFCONFIG_PATH, tt->actual_name ); - argv_msg (M_INFO, &argv); - openvpn_execve_check (&argv, NULL, 0, "Solaris ifconfig inet6 unplumb failed"); - argv_reset (&argv); - } - - if (tt->ip_fd >= 0) - { - struct lifreq ifr; - CLEAR (ifr); - strncpynt (ifr.lifr_name, tt->actual_name, sizeof (ifr.lifr_name)); - - if (ioctl (tt->ip_fd, SIOCGLIFFLAGS, &ifr) < 0) - msg (M_WARN | M_ERRNO, "Can't get iface flags"); - - if (ioctl (tt->ip_fd, SIOCGLIFMUXID, &ifr) < 0) - msg (M_WARN | M_ERRNO, "Can't get multiplexor id"); - - if (tt->type == DEV_TYPE_TAP) +solaris_close_tun(struct tuntap *tt) +{ + if (tt) + { + /* IPv6 interfaces need to be 'manually' de-configured */ + if (tt->did_ifconfig_ipv6_setup) + { + struct argv argv = argv_new(); + argv_printf( &argv, "%s %s inet6 unplumb", + IFCONFIG_PATH, tt->actual_name ); + argv_msg(M_INFO, &argv); + openvpn_execve_check(&argv, NULL, 0, "Solaris ifconfig inet6 unplumb failed"); + argv_reset(&argv); + } + + if (tt->ip_fd >= 0) + { + struct lifreq ifr; + CLEAR(ifr); + strncpynt(ifr.lifr_name, tt->actual_name, sizeof(ifr.lifr_name)); + + if (ioctl(tt->ip_fd, SIOCGLIFFLAGS, &ifr) < 0) + { + msg(M_WARN | M_ERRNO, "Can't get iface flags"); + } + + if (ioctl(tt->ip_fd, SIOCGLIFMUXID, &ifr) < 0) + { + msg(M_WARN | M_ERRNO, "Can't get multiplexor id"); + } + + if (tt->type == DEV_TYPE_TAP) { - if (ioctl (tt->ip_fd, I_PUNLINK, ifr.lifr_arp_muxid) < 0) - msg (M_WARN | M_ERRNO, "Can't unlink interface(arp)"); + if (ioctl(tt->ip_fd, I_PUNLINK, ifr.lifr_arp_muxid) < 0) + { + msg(M_WARN | M_ERRNO, "Can't unlink interface(arp)"); + } } - if (ioctl (tt->ip_fd, I_PUNLINK, ifr.lifr_ip_muxid) < 0) - msg (M_WARN | M_ERRNO, "Can't unlink interface(ip)"); + if (ioctl(tt->ip_fd, I_PUNLINK, ifr.lifr_ip_muxid) < 0) + { + msg(M_WARN | M_ERRNO, "Can't unlink interface(ip)"); + } - close (tt->ip_fd); - tt->ip_fd = -1; - } + close(tt->ip_fd); + tt->ip_fd = -1; + } - if (tt->fd >= 0) - { - close (tt->fd); - tt->fd = -1; - } + if (tt->fd >= 0) + { + close(tt->fd); + tt->fd = -1; + } } } /* - * Close TUN device. + * Close TUN device. */ void -close_tun (struct tuntap *tt) +close_tun(struct tuntap *tt) { - if (tt) + if (tt) { - solaris_close_tun (tt); + solaris_close_tun(tt); + + if (tt->actual_name) + { + free(tt->actual_name); + } - if (tt->actual_name) - free (tt->actual_name); - - clear_tuntap (tt); - free (tt); + clear_tuntap(tt); + free(tt); } } static void -solaris_error_close (struct tuntap *tt, const struct env_set *es, - const char *actual, bool unplumb_inet6 ) +solaris_error_close(struct tuntap *tt, const struct env_set *es, + const char *actual, bool unplumb_inet6 ) { - struct argv argv = argv_new (); + struct argv argv = argv_new(); - if (unplumb_inet6) + if (unplumb_inet6) { - argv_printf( &argv, "%s %s inet6 unplumb", - IFCONFIG_PATH, actual ); - argv_msg (M_INFO, &argv); - openvpn_execve_check (&argv, es, 0, "Solaris ifconfig inet6 unplumb failed"); + argv_printf( &argv, "%s %s inet6 unplumb", + IFCONFIG_PATH, actual ); + argv_msg(M_INFO, &argv); + openvpn_execve_check(&argv, es, 0, "Solaris ifconfig inet6 unplumb failed"); } - argv_printf (&argv, - "%s %s unplumb", - IFCONFIG_PATH, - actual); + argv_printf(&argv, + "%s %s unplumb", + IFCONFIG_PATH, + actual); - argv_msg (M_INFO, &argv); - openvpn_execve_check (&argv, es, 0, "Solaris ifconfig unplumb failed"); - close_tun (tt); - msg (M_FATAL, "Solaris ifconfig failed"); - argv_reset (&argv); + argv_msg(M_INFO, &argv); + openvpn_execve_check(&argv, es, 0, "Solaris ifconfig unplumb failed"); + close_tun(tt); + msg(M_FATAL, "Solaris ifconfig failed"); + argv_reset(&argv); } int -write_tun (struct tuntap* tt, uint8_t *buf, int len) +write_tun(struct tuntap *tt, uint8_t *buf, int len) { - struct strbuf sbuf; - sbuf.len = len; - sbuf.buf = (char *)buf; - return putmsg (tt->fd, NULL, &sbuf, 0) >= 0 ? sbuf.len : -1; + struct strbuf sbuf; + sbuf.len = len; + sbuf.buf = (char *)buf; + return putmsg(tt->fd, NULL, &sbuf, 0) >= 0 ? sbuf.len : -1; } int -read_tun (struct tuntap* tt, uint8_t *buf, int len) +read_tun(struct tuntap *tt, uint8_t *buf, int len) { - struct strbuf sbuf; - int f = 0; + struct strbuf sbuf; + int f = 0; - sbuf.maxlen = len; - sbuf.buf = (char *)buf; - return getmsg (tt->fd, NULL, &sbuf, &f) >= 0 ? sbuf.len : -1; + sbuf.maxlen = len; + sbuf.buf = (char *)buf; + return getmsg(tt->fd, NULL, &sbuf, &f) >= 0 ? sbuf.len : -1; } #elif defined(TARGET_OPENBSD) void -open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) +open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) { - open_tun_generic (dev, dev_type, dev_node, true, tt); + open_tun_generic(dev, dev_type, dev_node, true, tt); - /* Enable multicast on the interface */ - if (tt->fd >= 0) + /* Enable multicast on the interface */ + if (tt->fd >= 0) { - struct tuninfo info; + struct tuninfo info; - if (ioctl (tt->fd, TUNGIFINFO, &info) < 0) { - msg (M_WARN | M_ERRNO, "Can't get interface info: %s", - strerror(errno)); - } + if (ioctl(tt->fd, TUNGIFINFO, &info) < 0) + { + msg(M_WARN | M_ERRNO, "Can't get interface info: %s", + strerror(errno)); + } #ifdef IFF_MULTICAST /* openbsd 4.x doesn't have this */ - info.flags |= IFF_MULTICAST; + info.flags |= IFF_MULTICAST; #endif - if (ioctl (tt->fd, TUNSIFINFO, &info) < 0) { - msg (M_WARN | M_ERRNO, "Can't set interface info: %s", - strerror(errno)); - } + if (ioctl(tt->fd, TUNSIFINFO, &info) < 0) + { + msg(M_WARN | M_ERRNO, "Can't set interface info: %s", + strerror(errno)); + } } } @@ -2379,45 +2581,45 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tu */ void -close_tun (struct tuntap* tt) +close_tun(struct tuntap *tt) { - /* only *TAP* devices need destroying, tun devices auto-self-destruct - */ - if (tt && (tt->type == DEV_TYPE_TUN || tt->persistent_if ) ) + /* only *TAP* devices need destroying, tun devices auto-self-destruct + */ + if (tt && (tt->type == DEV_TYPE_TUN || tt->persistent_if ) ) { - close_tun_generic (tt); - free(tt); + close_tun_generic(tt); + free(tt); } - else if (tt) + else if (tt) { - struct gc_arena gc = gc_new (); - struct argv argv = argv_new (); + struct gc_arena gc = gc_new(); + struct argv argv = argv_new(); - /* setup command, close tun dev (clears tt->actual_name!), run command - */ + /* setup command, close tun dev (clears tt->actual_name!), run command + */ - argv_printf (&argv, "%s %s destroy", - IFCONFIG_PATH, tt->actual_name); + argv_printf(&argv, "%s %s destroy", + IFCONFIG_PATH, tt->actual_name); - close_tun_generic (tt); + close_tun_generic(tt); - argv_msg (M_INFO, &argv); - openvpn_execve_check (&argv, NULL, 0, "OpenBSD 'destroy tun interface' failed (non-critical)"); + argv_msg(M_INFO, &argv); + openvpn_execve_check(&argv, NULL, 0, "OpenBSD 'destroy tun interface' failed (non-critical)"); - free (tt); + free(tt); } } int write_tun(struct tuntap *tt, uint8_t *buf, int len) { - return write_tun_header (tt, buf, len); + return write_tun_header(tt, buf, len); } int -read_tun (struct tuntap *tt, uint8_t *buf, int len) +read_tun(struct tuntap *tt, uint8_t *buf, int len) { - return read_tun_header (tt, buf, len); + return read_tun_header(tt, buf, len); } #elif defined(TARGET_NETBSD) @@ -2437,26 +2639,26 @@ read_tun (struct tuntap *tt, uint8_t *buf, int len) */ void -open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) +open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) { - open_tun_generic (dev, dev_type, dev_node, true, tt); + open_tun_generic(dev, dev_type, dev_node, true, tt); if (tt->fd >= 0) - { + { int i = IFF_POINTOPOINT|IFF_MULTICAST; - ioctl (tt->fd, TUNSIFMODE, &i); /* multicast on */ + ioctl(tt->fd, TUNSIFMODE, &i); /* multicast on */ i = 0; - ioctl (tt->fd, TUNSLMODE, &i); /* link layer mode off */ + ioctl(tt->fd, TUNSLMODE, &i); /* link layer mode off */ - if ( tt->type == DEV_TYPE_TUN ) - { - i = 1; - if (ioctl (tt->fd, TUNSIFHEAD, &i) < 0) /* multi-af mode on */ - { - msg (M_WARN | M_ERRNO, "ioctl(TUNSIFHEAD): %s", strerror(errno)); - } - } - } + if (tt->type == DEV_TYPE_TUN) + { + i = 1; + if (ioctl(tt->fd, TUNSIFHEAD, &i) < 0) /* multi-af mode on */ + { + msg(M_WARN | M_ERRNO, "ioctl(TUNSIFHEAD): %s", strerror(errno)); + } + } + } } /* the current way OpenVPN handles tun devices on NetBSD leads to @@ -2464,117 +2666,135 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tu * need to be explicitely destroyed */ void -close_tun (struct tuntap *tt) +close_tun(struct tuntap *tt) { - /* only tun devices need destroying, tap devices auto-self-destruct - */ - if (tt && ( tt->type != DEV_TYPE_TUN || tt->persistent_if ) ) + /* only tun devices need destroying, tap devices auto-self-destruct + */ + if (tt && ( tt->type != DEV_TYPE_TUN || tt->persistent_if ) ) { - close_tun_generic (tt); - free(tt); + close_tun_generic(tt); + free(tt); } - else if (tt) + else if (tt) { - struct gc_arena gc = gc_new (); - struct argv argv = argv_new (); + struct gc_arena gc = gc_new(); + struct argv argv = argv_new(); - /* setup command, close tun dev (clears tt->actual_name!), run command - */ + /* setup command, close tun dev (clears tt->actual_name!), run command + */ - argv_printf (&argv, "%s %s destroy", - IFCONFIG_PATH, tt->actual_name); + argv_printf(&argv, "%s %s destroy", + IFCONFIG_PATH, tt->actual_name); - close_tun_generic (tt); + close_tun_generic(tt); - argv_msg (M_INFO, &argv); - openvpn_execve_check (&argv, NULL, 0, "NetBSD 'destroy tun interface' failed (non-critical)"); + argv_msg(M_INFO, &argv); + openvpn_execve_check(&argv, NULL, 0, "NetBSD 'destroy tun interface' failed (non-critical)"); - free (tt); + free(tt); } } static inline int -netbsd_modify_read_write_return (int len) +netbsd_modify_read_write_return(int len) { - if (len > 0) - return len > sizeof (u_int32_t) ? len - sizeof (u_int32_t) : 0; - else - return len; + if (len > 0) + { + return len > sizeof(u_int32_t) ? len - sizeof(u_int32_t) : 0; + } + else + { + return len; + } } int -write_tun (struct tuntap* tt, uint8_t *buf, int len) +write_tun(struct tuntap *tt, uint8_t *buf, int len) { - if (tt->type == DEV_TYPE_TUN) + if (tt->type == DEV_TYPE_TUN) { - u_int32_t type; - struct iovec iv[2]; - struct openvpn_iphdr *iph; + u_int32_t type; + struct iovec iv[2]; + struct openvpn_iphdr *iph; - iph = (struct openvpn_iphdr *) buf; + iph = (struct openvpn_iphdr *) buf; - if (OPENVPN_IPH_GET_VER(iph->version_len) == 6) - type = htonl (AF_INET6); - else - type = htonl (AF_INET); + if (OPENVPN_IPH_GET_VER(iph->version_len) == 6) + { + type = htonl(AF_INET6); + } + else + { + type = htonl(AF_INET); + } - iv[0].iov_base = (char *)&type; - iv[0].iov_len = sizeof (type); - iv[1].iov_base = buf; - iv[1].iov_len = len; + iv[0].iov_base = (char *)&type; + iv[0].iov_len = sizeof(type); + iv[1].iov_base = buf; + iv[1].iov_len = len; - return netbsd_modify_read_write_return (writev (tt->fd, iv, 2)); + return netbsd_modify_read_write_return(writev(tt->fd, iv, 2)); + } + else + { + return write(tt->fd, buf, len); } - else - return write (tt->fd, buf, len); } int -read_tun (struct tuntap* tt, uint8_t *buf, int len) +read_tun(struct tuntap *tt, uint8_t *buf, int len) { - if (tt->type == DEV_TYPE_TUN) + if (tt->type == DEV_TYPE_TUN) { - u_int32_t type; - struct iovec iv[2]; + u_int32_t type; + struct iovec iv[2]; - iv[0].iov_base = (char *)&type; - iv[0].iov_len = sizeof (type); - iv[1].iov_base = buf; - iv[1].iov_len = len; + iv[0].iov_base = (char *)&type; + iv[0].iov_len = sizeof(type); + iv[1].iov_base = buf; + iv[1].iov_len = len; - return netbsd_modify_read_write_return (readv (tt->fd, iv, 2)); + return netbsd_modify_read_write_return(readv(tt->fd, iv, 2)); + } + else + { + return read(tt->fd, buf, len); } - else - return read (tt->fd, buf, len); } #elif defined(TARGET_FREEBSD) static inline int -freebsd_modify_read_write_return (int len) +freebsd_modify_read_write_return(int len) { - if (len > 0) - return len > sizeof (u_int32_t) ? len - sizeof (u_int32_t) : 0; - else - return len; + if (len > 0) + { + return len > sizeof(u_int32_t) ? len - sizeof(u_int32_t) : 0; + } + else + { + return len; + } } void -open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) +open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) { - open_tun_generic (dev, dev_type, dev_node, true, tt); + open_tun_generic(dev, dev_type, dev_node, true, tt); - if (tt->fd >= 0 && tt->type == DEV_TYPE_TUN) + if (tt->fd >= 0 && tt->type == DEV_TYPE_TUN) { - int i = IFF_POINTOPOINT | IFF_MULTICAST; + int i = IFF_POINTOPOINT | IFF_MULTICAST; - if (ioctl (tt->fd, TUNSIFMODE, &i) < 0) { - msg (M_WARN | M_ERRNO, "ioctl(TUNSIFMODE): %s", strerror(errno)); - } - i = 1; - if (ioctl (tt->fd, TUNSIFHEAD, &i) < 0) { - msg (M_WARN | M_ERRNO, "ioctl(TUNSIFHEAD): %s", strerror(errno)); - } + if (ioctl(tt->fd, TUNSIFMODE, &i) < 0) + { + msg(M_WARN | M_ERRNO, "ioctl(TUNSIFMODE): %s", strerror(errno)); + } + i = 1; + if (ioctl(tt->fd, TUNSIFHEAD, &i) < 0) + { + msg(M_WARN | M_ERRNO, "ioctl(TUNSIFHEAD): %s", strerror(errno)); + } } } @@ -2586,159 +2806,179 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tu * we need to call "ifconfig ... destroy" for cleanup */ void -close_tun (struct tuntap *tt) +close_tun(struct tuntap *tt) { - if (tt && tt->persistent_if ) /* keep pre-existing if around */ + if (tt && tt->persistent_if) /* keep pre-existing if around */ { - close_tun_generic (tt); - free (tt); + close_tun_generic(tt); + free(tt); } - else if (tt) /* close and destroy */ + else if (tt) /* close and destroy */ { - struct argv argv = argv_new (); + struct argv argv = argv_new(); - /* setup command, close tun dev (clears tt->actual_name!), run command - */ + /* setup command, close tun dev (clears tt->actual_name!), run command + */ - argv_printf (&argv, "%s %s destroy", - IFCONFIG_PATH, tt->actual_name); + argv_printf(&argv, "%s %s destroy", + IFCONFIG_PATH, tt->actual_name); - close_tun_generic (tt); + close_tun_generic(tt); - argv_msg (M_INFO, &argv); - openvpn_execve_check (&argv, NULL, 0, "FreeBSD 'destroy tun interface' failed (non-critical)"); + argv_msg(M_INFO, &argv); + openvpn_execve_check(&argv, NULL, 0, "FreeBSD 'destroy tun interface' failed (non-critical)"); - free (tt); + free(tt); } } int -write_tun (struct tuntap* tt, uint8_t *buf, int len) +write_tun(struct tuntap *tt, uint8_t *buf, int len) { - if (tt->type == DEV_TYPE_TUN) + if (tt->type == DEV_TYPE_TUN) { - u_int32_t type; - struct iovec iv[2]; - struct ip *iph; + u_int32_t type; + struct iovec iv[2]; + struct ip *iph; - iph = (struct ip *) buf; + iph = (struct ip *) buf; - if (iph->ip_v == 6) - type = htonl (AF_INET6); - else - type = htonl (AF_INET); + if (iph->ip_v == 6) + { + type = htonl(AF_INET6); + } + else + { + type = htonl(AF_INET); + } - iv[0].iov_base = (char *)&type; - iv[0].iov_len = sizeof (type); - iv[1].iov_base = buf; - iv[1].iov_len = len; + iv[0].iov_base = (char *)&type; + iv[0].iov_len = sizeof(type); + iv[1].iov_base = buf; + iv[1].iov_len = len; - return freebsd_modify_read_write_return (writev (tt->fd, iv, 2)); + return freebsd_modify_read_write_return(writev(tt->fd, iv, 2)); + } + else + { + return write(tt->fd, buf, len); } - else - return write (tt->fd, buf, len); } int -read_tun (struct tuntap* tt, uint8_t *buf, int len) +read_tun(struct tuntap *tt, uint8_t *buf, int len) { - if (tt->type == DEV_TYPE_TUN) + if (tt->type == DEV_TYPE_TUN) { - u_int32_t type; - struct iovec iv[2]; + u_int32_t type; + struct iovec iv[2]; - iv[0].iov_base = (char *)&type; - iv[0].iov_len = sizeof (type); - iv[1].iov_base = buf; - iv[1].iov_len = len; + iv[0].iov_base = (char *)&type; + iv[0].iov_len = sizeof(type); + iv[1].iov_base = buf; + iv[1].iov_len = len; - return freebsd_modify_read_write_return (readv (tt->fd, iv, 2)); + return freebsd_modify_read_write_return(readv(tt->fd, iv, 2)); + } + else + { + return read(tt->fd, buf, len); } - else - return read (tt->fd, buf, len); } #elif defined(TARGET_DRAGONFLY) static inline int -dragonfly_modify_read_write_return (int len) +dragonfly_modify_read_write_return(int len) { - if (len > 0) - return len > sizeof (u_int32_t) ? len - sizeof (u_int32_t) : 0; - else - return len; + if (len > 0) + { + return len > sizeof(u_int32_t) ? len - sizeof(u_int32_t) : 0; + } + else + { + return len; + } } void -open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) +open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) { - open_tun_generic (dev, dev_type, dev_node, true, tt); + open_tun_generic(dev, dev_type, dev_node, true, tt); - if (tt->fd >= 0) + if (tt->fd >= 0) { - int i = 0; + int i = 0; - /* Disable extended modes */ - ioctl (tt->fd, TUNSLMODE, &i); - i = 1; - ioctl (tt->fd, TUNSIFHEAD, &i); + /* Disable extended modes */ + ioctl(tt->fd, TUNSLMODE, &i); + i = 1; + ioctl(tt->fd, TUNSIFHEAD, &i); } } void -close_tun (struct tuntap *tt) +close_tun(struct tuntap *tt) { - if (tt) + if (tt) + { + close_tun_generic(tt); + free(tt); + } +} + +int +write_tun(struct tuntap *tt, uint8_t *buf, int len) +{ + if (tt->type == DEV_TYPE_TUN) + { + u_int32_t type; + struct iovec iv[2]; + struct ip *iph; + + iph = (struct ip *) buf; + + if (iph->ip_v == 6) + { + type = htonl(AF_INET6); + } + else + { + type = htonl(AF_INET); + } + + iv[0].iov_base = (char *)&type; + iv[0].iov_len = sizeof(type); + iv[1].iov_base = buf; + iv[1].iov_len = len; + + return dragonfly_modify_read_write_return(writev(tt->fd, iv, 2)); + } + else { - close_tun_generic (tt); - free (tt); + return write(tt->fd, buf, len); } } int -write_tun (struct tuntap* tt, uint8_t *buf, int len) +read_tun(struct tuntap *tt, uint8_t *buf, int len) { - if (tt->type == DEV_TYPE_TUN) + if (tt->type == DEV_TYPE_TUN) { - u_int32_t type; - struct iovec iv[2]; - struct ip *iph; - - iph = (struct ip *) buf; - - if (iph->ip_v == 6) - type = htonl (AF_INET6); - else - type = htonl (AF_INET); + u_int32_t type; + struct iovec iv[2]; - iv[0].iov_base = (char *)&type; - iv[0].iov_len = sizeof (type); - iv[1].iov_base = buf; - iv[1].iov_len = len; + iv[0].iov_base = (char *)&type; + iv[0].iov_len = sizeof(type); + iv[1].iov_base = buf; + iv[1].iov_len = len; - return dragonfly_modify_read_write_return (writev (tt->fd, iv, 2)); + return dragonfly_modify_read_write_return(readv(tt->fd, iv, 2)); } - else - return write (tt->fd, buf, len); -} - -int -read_tun (struct tuntap* tt, uint8_t *buf, int len) -{ - if (tt->type == DEV_TYPE_TUN) + else { - u_int32_t type; - struct iovec iv[2]; - - iv[0].iov_base = (char *)&type; - iv[0].iov_len = sizeof (type); - iv[1].iov_base = buf; - iv[1].iov_len = len; - - return dragonfly_modify_read_write_return (readv (tt->fd, iv, 2)); + return read(tt->fd, buf, len); } - else - return read (tt->fd, buf, len); } #elif defined(TARGET_DARWIN) @@ -2760,1012 +3000,1099 @@ read_tun (struct tuntap* tt, uint8_t *buf, int len) #ifdef HAVE_NET_IF_UTUN_H /* Helper functions that tries to open utun device - return -2 on early initialization failures (utun not supported - at all (old OS X) and -1 on initlization failure of utun - device (utun works but utunX is already used */ + * return -2 on early initialization failures (utun not supported + * at all (old OS X) and -1 on initlization failure of utun + * device (utun works but utunX is already used */ static -int utun_open_helper (struct ctl_info ctlInfo, int utunnum) +int +utun_open_helper(struct ctl_info ctlInfo, int utunnum) { - struct sockaddr_ctl sc; - int fd; + struct sockaddr_ctl sc; + int fd; - fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL); + fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL); - if (fd < 0) + if (fd < 0) { - msg (M_INFO, "Opening utun (%s): %s", "socket(SYSPROTO_CONTROL)", - strerror (errno)); - return -2; + msg(M_INFO, "Opening utun (%s): %s", "socket(SYSPROTO_CONTROL)", + strerror(errno)); + return -2; } - if (ioctl(fd, CTLIOCGINFO, &ctlInfo) == -1) + if (ioctl(fd, CTLIOCGINFO, &ctlInfo) == -1) { - close (fd); - msg (M_INFO, "Opening utun (%s): %s", "ioctl(CTLIOCGINFO)", - strerror (errno)); - return -2; + close(fd); + msg(M_INFO, "Opening utun (%s): %s", "ioctl(CTLIOCGINFO)", + strerror(errno)); + return -2; } - sc.sc_id = ctlInfo.ctl_id; - sc.sc_len = sizeof(sc); - sc.sc_family = AF_SYSTEM; - sc.ss_sysaddr = AF_SYS_CONTROL; + sc.sc_id = ctlInfo.ctl_id; + sc.sc_len = sizeof(sc); + sc.sc_family = AF_SYSTEM; + sc.ss_sysaddr = AF_SYS_CONTROL; - sc.sc_unit = utunnum+1; + sc.sc_unit = utunnum+1; - /* If the connect is successful, a utun%d device will be created, where "%d" - * is (sc.sc_unit - 1) */ + /* If the connect is successful, a utun%d device will be created, where "%d" + * is (sc.sc_unit - 1) */ - if (connect (fd, (struct sockaddr *)&sc, sizeof(sc)) < 0) + if (connect(fd, (struct sockaddr *)&sc, sizeof(sc)) < 0) { - msg (M_INFO, "Opening utun (%s): %s", "connect(AF_SYS_CONTROL)", - strerror (errno)); - close(fd); - return -1; + msg(M_INFO, "Opening utun (%s): %s", "connect(AF_SYS_CONTROL)", + strerror(errno)); + close(fd); + return -1; } - set_nonblock (fd); - set_cloexec (fd); /* don't pass fd to scripts */ + set_nonblock(fd); + set_cloexec(fd); /* don't pass fd to scripts */ - return fd; + return fd; } void -open_darwin_utun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) +open_darwin_utun(const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) { - struct ctl_info ctlInfo; - int fd; - char utunname[20]; - int utunnum =-1; - socklen_t utunname_len = sizeof(utunname); + struct ctl_info ctlInfo; + int fd; + char utunname[20]; + int utunnum = -1; + socklen_t utunname_len = sizeof(utunname); - /* dev_node is simply utun, do the normal dynamic utun - * otherwise try to parse the utun number */ - if (dev_node && (strcmp("utun", dev_node) != 0 )) + /* dev_node is simply utun, do the normal dynamic utun + * otherwise try to parse the utun number */ + if (dev_node && (strcmp("utun", dev_node) != 0 )) { - if (sscanf(dev_node, "utun%d", &utunnum) != 1 ) - msg (M_FATAL, "Cannot parse 'dev-node %s' please use 'dev-node utunX'" - "to use a utun device number X", dev_node); + if (sscanf(dev_node, "utun%d", &utunnum) != 1) + { + msg(M_FATAL, "Cannot parse 'dev-node %s' please use 'dev-node utunX'" + "to use a utun device number X", dev_node); + } } - CLEAR (ctlInfo); - if (strlcpy(ctlInfo.ctl_name, UTUN_CONTROL_NAME, sizeof(ctlInfo.ctl_name)) >= - sizeof(ctlInfo.ctl_name)) + CLEAR(ctlInfo); + if (strlcpy(ctlInfo.ctl_name, UTUN_CONTROL_NAME, sizeof(ctlInfo.ctl_name)) >= + sizeof(ctlInfo.ctl_name)) { - msg (M_ERR, "Opening utun: UTUN_CONTROL_NAME too long"); + msg(M_ERR, "Opening utun: UTUN_CONTROL_NAME too long"); } - /* try to open first available utun device if no specific utun is requested */ - if (utunnum == -1) + /* try to open first available utun device if no specific utun is requested */ + if (utunnum == -1) { - for (utunnum=0; utunnum<255; utunnum++) + for (utunnum = 0; utunnum<255; utunnum++) { - fd = utun_open_helper (ctlInfo, utunnum); - /* Break if the fd is valid, - * or if early initalization failed (-2) */ - if (fd !=-1) - break; + fd = utun_open_helper(ctlInfo, utunnum); + /* Break if the fd is valid, + * or if early initalization failed (-2) */ + if (fd !=-1) + { + break; + } } } - else + else { - fd = utun_open_helper (ctlInfo, utunnum); + fd = utun_open_helper(ctlInfo, utunnum); } - /* opening an utun device failed */ - tt->fd = fd; + /* opening an utun device failed */ + tt->fd = fd; - if (fd < 0) - return; + if (fd < 0) + { + return; + } - /* Retrieve the assigned interface name. */ - if (getsockopt (fd, SYSPROTO_CONTROL, UTUN_OPT_IFNAME, utunname, &utunname_len)) - msg (M_ERR | M_ERRNO, "Error retrieving utun interface name"); + /* Retrieve the assigned interface name. */ + if (getsockopt(fd, SYSPROTO_CONTROL, UTUN_OPT_IFNAME, utunname, &utunname_len)) + { + msg(M_ERR | M_ERRNO, "Error retrieving utun interface name"); + } - tt->actual_name = string_alloc (utunname, NULL); + tt->actual_name = string_alloc(utunname, NULL); - msg (M_INFO, "Opened utun device %s", utunname); - tt->is_utun = true; + msg(M_INFO, "Opened utun device %s", utunname); + tt->is_utun = true; } -#endif +#endif /* ifdef HAVE_NET_IF_UTUN_H */ void -open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) +open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) { #ifdef HAVE_NET_IF_UTUN_H - /* If dev_node does not start start with utun assume regular tun/tap */ - if ((!dev_node && tt->type==DEV_TYPE_TUN) || - (dev_node && !strncmp (dev_node, "utun", 4))) + /* If dev_node does not start start with utun assume regular tun/tap */ + if ((!dev_node && tt->type==DEV_TYPE_TUN) + || (dev_node && !strncmp(dev_node, "utun", 4))) { - /* Check if user has specific dev_type tap and forced utun with - dev-node utun */ - if (tt->type!=DEV_TYPE_TUN) - msg (M_FATAL, "Cannot use utun devices with --dev-type %s", - dev_type_string (dev, dev_type)); + /* Check if user has specific dev_type tap and forced utun with + * dev-node utun */ + if (tt->type!=DEV_TYPE_TUN) + { + msg(M_FATAL, "Cannot use utun devices with --dev-type %s", + dev_type_string(dev, dev_type)); + } - /* Try utun first and fall back to normal tun if utun fails - and dev_node is not specified */ - open_darwin_utun(dev, dev_type, dev_node, tt); + /* Try utun first and fall back to normal tun if utun fails + * and dev_node is not specified */ + open_darwin_utun(dev, dev_type, dev_node, tt); - if (!tt->is_utun) + if (!tt->is_utun) { - if (!dev_node) + if (!dev_node) { - /* No explicit utun and utun failed, try the generic way) */ - msg (M_INFO, "Failed to open utun device. Falling back to /dev/tun device"); - open_tun_generic (dev, dev_type, NULL, true, tt); + /* No explicit utun and utun failed, try the generic way) */ + msg(M_INFO, "Failed to open utun device. Falling back to /dev/tun device"); + open_tun_generic(dev, dev_type, NULL, true, tt); } - else + else { - /* Specific utun device or generic utun request with no tun - fall back failed, consider this a fatal failure */ - msg (M_FATAL, "Cannot open utun device"); + /* Specific utun device or generic utun request with no tun + * fall back failed, consider this a fatal failure */ + msg(M_FATAL, "Cannot open utun device"); } } } - else -#endif + else +#endif /* ifdef HAVE_NET_IF_UTUN_H */ { - /* Use plain dev-node tun to select /dev/tun style - * Unset dev_node variable prior to passing to open_tun_generic to - * let open_tun_generic pick the first available tun device */ + /* Use plain dev-node tun to select /dev/tun style + * Unset dev_node variable prior to passing to open_tun_generic to + * let open_tun_generic pick the first available tun device */ - if (dev_node && strcmp (dev_node, "tun")==0) - dev_node=NULL; + if (dev_node && strcmp(dev_node, "tun")==0) + { + dev_node = NULL; + } - open_tun_generic (dev, dev_type, dev_node, true, tt); + open_tun_generic(dev, dev_type, dev_node, true, tt); } } void -close_tun (struct tuntap* tt) +close_tun(struct tuntap *tt) { - if (tt) + if (tt) { - struct gc_arena gc = gc_new (); - struct argv argv = argv_new (); + struct gc_arena gc = gc_new(); + struct argv argv = argv_new(); - if (tt->did_ifconfig_ipv6_setup ) - { - const char * ifconfig_ipv6_local = - print_in6_addr (tt->local_ipv6, 0, &gc); + if (tt->did_ifconfig_ipv6_setup) + { + const char *ifconfig_ipv6_local = + print_in6_addr(tt->local_ipv6, 0, &gc); - argv_printf (&argv, "%s delete -inet6 %s", - ROUTE_PATH, ifconfig_ipv6_local ); - argv_msg (M_INFO, &argv); - openvpn_execve_check (&argv, NULL, 0, "MacOS X 'remove inet6 route' failed (non-critical)"); - } + argv_printf(&argv, "%s delete -inet6 %s", + ROUTE_PATH, ifconfig_ipv6_local ); + argv_msg(M_INFO, &argv); + openvpn_execve_check(&argv, NULL, 0, "MacOS X 'remove inet6 route' failed (non-critical)"); + } - close_tun_generic (tt); - free (tt); - argv_reset (&argv); - gc_free (&gc); + close_tun_generic(tt); + free(tt); + argv_reset(&argv); + gc_free(&gc); } } int -write_tun (struct tuntap* tt, uint8_t *buf, int len) +write_tun(struct tuntap *tt, uint8_t *buf, int len) { #ifdef HAVE_NET_IF_UTUN_H - if (tt->is_utun) - return write_tun_header (tt, buf, len); - else + if (tt->is_utun) + { + return write_tun_header(tt, buf, len); + } + else #endif - return write (tt->fd, buf, len); + return write(tt->fd, buf, len); } int -read_tun (struct tuntap* tt, uint8_t *buf, int len) +read_tun(struct tuntap *tt, uint8_t *buf, int len) { #ifdef HAVE_NET_IF_UTUN_H - if (tt->is_utun) - return read_tun_header (tt, buf, len); - else + if (tt->is_utun) + { + return read_tun_header(tt, buf, len); + } + else #endif - return read (tt->fd, buf, len); + return read(tt->fd, buf, len); } #elif defined(TARGET_AIX) void -open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) +open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) { - char tunname[256]; - char dynamic_name[20]; - const char *p; + char tunname[256]; + char dynamic_name[20]; + const char *p; - if (tt->type == DEV_TYPE_NULL) + if (tt->type == DEV_TYPE_NULL) { - open_null (tt); - return; + open_null(tt); + return; } - if ( tt->type == DEV_TYPE_TUN) + if (tt->type == DEV_TYPE_TUN) { - msg(M_FATAL, "no support for 'tun' devices on AIX" ); + msg(M_FATAL, "no support for 'tun' devices on AIX" ); } - if ( strncmp( dev, "tap", 3 ) != 0 || dev_node ) + if (strncmp( dev, "tap", 3 ) != 0 || dev_node) { - msg(M_FATAL, "'--dev %s' and/or '--dev-node' not supported on AIX, use '--dev tap0', 'tap1', etc.", dev ); + msg(M_FATAL, "'--dev %s' and/or '--dev-node' not supported on AIX, use '--dev tap0', 'tap1', etc.", dev ); } - if ( strcmp( dev, "tap" ) == 0 ) /* find first free tap dev */ - { /* (= no /dev/tapN node) */ - int i; - for (i=0; i<99; i++ ) - { - openvpn_snprintf (tunname, sizeof (tunname), "/dev/tap%d", i); - if ( access( tunname, F_OK ) < 0 && errno == ENOENT ) - { break; } - } - if ( i >= 99 ) - msg( M_FATAL, "cannot find unused tap device" ); + if (strcmp( dev, "tap" ) == 0) /* find first free tap dev */ + { /* (= no /dev/tapN node) */ + int i; + for (i = 0; i<99; i++) + { + openvpn_snprintf(tunname, sizeof(tunname), "/dev/tap%d", i); + if (access( tunname, F_OK ) < 0 && errno == ENOENT) + { + break; + } + } + if (i >= 99) + { + msg( M_FATAL, "cannot find unused tap device" ); + } - openvpn_snprintf( dynamic_name, sizeof(dynamic_name), "tap%d", i ); - dev = dynamic_name; + openvpn_snprintf( dynamic_name, sizeof(dynamic_name), "tap%d", i ); + dev = dynamic_name; } - else /* name given, sanity check */ + else /* name given, sanity check */ { - /* ensure that dev name is "tap+" *only* */ - p = &dev[3]; - while( isdigit(*p) ) p++; - if ( *p != '\0' ) - msg( M_FATAL, "TAP device name must be '--dev tapNNNN'" ); + /* ensure that dev name is "tap+" *only* */ + p = &dev[3]; + while (isdigit(*p) ) p++; + if (*p != '\0') + { + msg( M_FATAL, "TAP device name must be '--dev tapNNNN'" ); + } - openvpn_snprintf (tunname, sizeof (tunname), "/dev/%s", dev); + openvpn_snprintf(tunname, sizeof(tunname), "/dev/%s", dev); } - /* pre-existing device? - */ - if ( access( tunname, F_OK ) < 0 && errno == ENOENT ) + /* pre-existing device? + */ + if (access( tunname, F_OK ) < 0 && errno == ENOENT) { - /* tunnel device must be created with 'ifconfig tapN create' - */ - struct argv argv = argv_new (); - struct env_set *es = env_set_create (NULL); - argv_printf (&argv, "%s %s create", IFCONFIG_PATH, dev); - argv_msg (M_INFO, &argv); - env_set_add( es, "ODMDIR=/etc/objrepos" ); - openvpn_execve_check (&argv, es, S_FATAL, "AIX 'create tun interface' failed"); - env_set_destroy (es); + /* tunnel device must be created with 'ifconfig tapN create' + */ + struct argv argv = argv_new(); + struct env_set *es = env_set_create(NULL); + argv_printf(&argv, "%s %s create", IFCONFIG_PATH, dev); + argv_msg(M_INFO, &argv); + env_set_add( es, "ODMDIR=/etc/objrepos" ); + openvpn_execve_check(&argv, es, S_FATAL, "AIX 'create tun interface' failed"); + env_set_destroy(es); } - else + else { - /* we didn't make it, we're not going to break it */ - tt->persistent_if = TRUE; + /* we didn't make it, we're not going to break it */ + tt->persistent_if = TRUE; } - if ((tt->fd = open (tunname, O_RDWR)) < 0) + if ((tt->fd = open(tunname, O_RDWR)) < 0) { - msg (M_ERR, "Cannot open TAP device '%s'", tunname); + msg(M_ERR, "Cannot open TAP device '%s'", tunname); } - set_nonblock (tt->fd); - set_cloexec (tt->fd); /* don't pass fd to scripts */ - msg (M_INFO, "TUN/TAP device %s opened", tunname); + set_nonblock(tt->fd); + set_cloexec(tt->fd); /* don't pass fd to scripts */ + msg(M_INFO, "TUN/TAP device %s opened", tunname); - /* tt->actual_name is passed to up and down scripts and used as the ifconfig dev name */ - tt->actual_name = string_alloc(dev, NULL); + /* tt->actual_name is passed to up and down scripts and used as the ifconfig dev name */ + tt->actual_name = string_alloc(dev, NULL); } /* tap devices need to be manually destroyed on AIX */ void -close_tun (struct tuntap* tt) +close_tun(struct tuntap *tt) { - struct gc_arena gc = gc_new (); - struct argv argv = argv_new (); - struct env_set *es = env_set_create (NULL); + struct gc_arena gc = gc_new(); + struct argv argv = argv_new(); + struct env_set *es = env_set_create(NULL); - if (!tt) return; + if (!tt) + { + return; + } - /* persistent devices need IP address unconfig, others need destroyal - */ - if (tt->persistent_if) + /* persistent devices need IP address unconfig, others need destroyal + */ + if (tt->persistent_if) { - argv_printf (&argv, "%s %s 0.0.0.0 down", - IFCONFIG_PATH, tt->actual_name); + argv_printf(&argv, "%s %s 0.0.0.0 down", + IFCONFIG_PATH, tt->actual_name); } - else + else { - argv_printf (&argv, "%s %s destroy", - IFCONFIG_PATH, tt->actual_name); + argv_printf(&argv, "%s %s destroy", + IFCONFIG_PATH, tt->actual_name); } - close_tun_generic (tt); - argv_msg (M_INFO, &argv); - env_set_add( es, "ODMDIR=/etc/objrepos" ); - openvpn_execve_check (&argv, es, 0, "AIX 'destroy tap interface' failed (non-critical)"); + close_tun_generic(tt); + argv_msg(M_INFO, &argv); + env_set_add( es, "ODMDIR=/etc/objrepos" ); + openvpn_execve_check(&argv, es, 0, "AIX 'destroy tap interface' failed (non-critical)"); - free(tt); - env_set_destroy (es); + free(tt); + env_set_destroy(es); } int -write_tun (struct tuntap* tt, uint8_t *buf, int len) +write_tun(struct tuntap *tt, uint8_t *buf, int len) { - return write (tt->fd, buf, len); + return write(tt->fd, buf, len); } int -read_tun (struct tuntap* tt, uint8_t *buf, int len) +read_tun(struct tuntap *tt, uint8_t *buf, int len) { - return read (tt->fd, buf, len); + return read(tt->fd, buf, len); } #elif defined(_WIN32) int -tun_read_queue (struct tuntap *tt, int maxsize) -{ - if (tt->reads.iostate == IOSTATE_INITIAL) - { - DWORD len; - BOOL status; - int err; - - /* reset buf to its initial state */ - tt->reads.buf = tt->reads.buf_init; - - len = maxsize ? maxsize : BLEN (&tt->reads.buf); - ASSERT (len <= BLEN (&tt->reads.buf)); - - /* the overlapped read will signal this event on I/O completion */ - ASSERT (ResetEvent (tt->reads.overlapped.hEvent)); - - status = ReadFile( - tt->hand, - BPTR (&tt->reads.buf), - len, - &tt->reads.size, - &tt->reads.overlapped - ); - - if (status) /* operation completed immediately? */ - { - /* since we got an immediate return, we must signal the event object ourselves */ - ASSERT (SetEvent (tt->reads.overlapped.hEvent)); - - tt->reads.iostate = IOSTATE_IMMEDIATE_RETURN; - tt->reads.status = 0; - - dmsg (D_WIN32_IO, "WIN32 I/O: TAP Read immediate return [%d,%d]", - (int) len, - (int) tt->reads.size); - } - else - { - err = GetLastError (); - if (err == ERROR_IO_PENDING) /* operation queued? */ - { - tt->reads.iostate = IOSTATE_QUEUED; - tt->reads.status = err; - dmsg (D_WIN32_IO, "WIN32 I/O: TAP Read queued [%d]", - (int) len); - } - else /* error occurred */ - { - struct gc_arena gc = gc_new (); - ASSERT (SetEvent (tt->reads.overlapped.hEvent)); - tt->reads.iostate = IOSTATE_IMMEDIATE_RETURN; - tt->reads.status = err; - dmsg (D_WIN32_IO, "WIN32 I/O: TAP Read error [%d] : %s", - (int) len, - strerror_win32 (status, &gc)); - gc_free (&gc); - } - } - } - return tt->reads.iostate; +tun_read_queue(struct tuntap *tt, int maxsize) +{ + if (tt->reads.iostate == IOSTATE_INITIAL) + { + DWORD len; + BOOL status; + int err; + + /* reset buf to its initial state */ + tt->reads.buf = tt->reads.buf_init; + + len = maxsize ? maxsize : BLEN(&tt->reads.buf); + ASSERT(len <= BLEN(&tt->reads.buf)); + + /* the overlapped read will signal this event on I/O completion */ + ASSERT(ResetEvent(tt->reads.overlapped.hEvent)); + + status = ReadFile( + tt->hand, + BPTR(&tt->reads.buf), + len, + &tt->reads.size, + &tt->reads.overlapped + ); + + if (status) /* operation completed immediately? */ + { + /* since we got an immediate return, we must signal the event object ourselves */ + ASSERT(SetEvent(tt->reads.overlapped.hEvent)); + + tt->reads.iostate = IOSTATE_IMMEDIATE_RETURN; + tt->reads.status = 0; + + dmsg(D_WIN32_IO, "WIN32 I/O: TAP Read immediate return [%d,%d]", + (int) len, + (int) tt->reads.size); + } + else + { + err = GetLastError(); + if (err == ERROR_IO_PENDING) /* operation queued? */ + { + tt->reads.iostate = IOSTATE_QUEUED; + tt->reads.status = err; + dmsg(D_WIN32_IO, "WIN32 I/O: TAP Read queued [%d]", + (int) len); + } + else /* error occurred */ + { + struct gc_arena gc = gc_new(); + ASSERT(SetEvent(tt->reads.overlapped.hEvent)); + tt->reads.iostate = IOSTATE_IMMEDIATE_RETURN; + tt->reads.status = err; + dmsg(D_WIN32_IO, "WIN32 I/O: TAP Read error [%d] : %s", + (int) len, + strerror_win32(status, &gc)); + gc_free(&gc); + } + } + } + return tt->reads.iostate; } int -tun_write_queue (struct tuntap *tt, struct buffer *buf) -{ - if (tt->writes.iostate == IOSTATE_INITIAL) - { - BOOL status; - int err; - - /* make a private copy of buf */ - tt->writes.buf = tt->writes.buf_init; - tt->writes.buf.len = 0; - ASSERT (buf_copy (&tt->writes.buf, buf)); - - /* the overlapped write will signal this event on I/O completion */ - ASSERT (ResetEvent (tt->writes.overlapped.hEvent)); - - status = WriteFile( - tt->hand, - BPTR (&tt->writes.buf), - BLEN (&tt->writes.buf), - &tt->writes.size, - &tt->writes.overlapped - ); - - if (status) /* operation completed immediately? */ - { - tt->writes.iostate = IOSTATE_IMMEDIATE_RETURN; - - /* since we got an immediate return, we must signal the event object ourselves */ - ASSERT (SetEvent (tt->writes.overlapped.hEvent)); - - tt->writes.status = 0; - - dmsg (D_WIN32_IO, "WIN32 I/O: TAP Write immediate return [%d,%d]", - BLEN (&tt->writes.buf), - (int) tt->writes.size); - } - else - { - err = GetLastError (); - if (err == ERROR_IO_PENDING) /* operation queued? */ - { - tt->writes.iostate = IOSTATE_QUEUED; - tt->writes.status = err; - dmsg (D_WIN32_IO, "WIN32 I/O: TAP Write queued [%d]", - BLEN (&tt->writes.buf)); - } - else /* error occurred */ - { - struct gc_arena gc = gc_new (); - ASSERT (SetEvent (tt->writes.overlapped.hEvent)); - tt->writes.iostate = IOSTATE_IMMEDIATE_RETURN; - tt->writes.status = err; - dmsg (D_WIN32_IO, "WIN32 I/O: TAP Write error [%d] : %s", - BLEN (&tt->writes.buf), - strerror_win32 (err, &gc)); - gc_free (&gc); - } - } - } - return tt->writes.iostate; +tun_write_queue(struct tuntap *tt, struct buffer *buf) +{ + if (tt->writes.iostate == IOSTATE_INITIAL) + { + BOOL status; + int err; + + /* make a private copy of buf */ + tt->writes.buf = tt->writes.buf_init; + tt->writes.buf.len = 0; + ASSERT(buf_copy(&tt->writes.buf, buf)); + + /* the overlapped write will signal this event on I/O completion */ + ASSERT(ResetEvent(tt->writes.overlapped.hEvent)); + + status = WriteFile( + tt->hand, + BPTR(&tt->writes.buf), + BLEN(&tt->writes.buf), + &tt->writes.size, + &tt->writes.overlapped + ); + + if (status) /* operation completed immediately? */ + { + tt->writes.iostate = IOSTATE_IMMEDIATE_RETURN; + + /* since we got an immediate return, we must signal the event object ourselves */ + ASSERT(SetEvent(tt->writes.overlapped.hEvent)); + + tt->writes.status = 0; + + dmsg(D_WIN32_IO, "WIN32 I/O: TAP Write immediate return [%d,%d]", + BLEN(&tt->writes.buf), + (int) tt->writes.size); + } + else + { + err = GetLastError(); + if (err == ERROR_IO_PENDING) /* operation queued? */ + { + tt->writes.iostate = IOSTATE_QUEUED; + tt->writes.status = err; + dmsg(D_WIN32_IO, "WIN32 I/O: TAP Write queued [%d]", + BLEN(&tt->writes.buf)); + } + else /* error occurred */ + { + struct gc_arena gc = gc_new(); + ASSERT(SetEvent(tt->writes.overlapped.hEvent)); + tt->writes.iostate = IOSTATE_IMMEDIATE_RETURN; + tt->writes.status = err; + dmsg(D_WIN32_IO, "WIN32 I/O: TAP Write error [%d] : %s", + BLEN(&tt->writes.buf), + strerror_win32(err, &gc)); + gc_free(&gc); + } + } + } + return tt->writes.iostate; } int -tun_finalize ( - HANDLE h, - struct overlapped_io *io, - struct buffer *buf) -{ - int ret = -1; - BOOL status; - - switch (io->iostate) - { - case IOSTATE_QUEUED: - status = GetOverlappedResult( - h, - &io->overlapped, - &io->size, - FALSE - ); - if (status) - { - /* successful return for a queued operation */ - if (buf) - *buf = io->buf; - ret = io->size; - io->iostate = IOSTATE_INITIAL; - ASSERT (ResetEvent (io->overlapped.hEvent)); - dmsg (D_WIN32_IO, "WIN32 I/O: TAP Completion success [%d]", ret); - } - else - { - /* error during a queued operation */ - ret = -1; - if (GetLastError() != ERROR_IO_INCOMPLETE) - { - /* if no error (i.e. just not finished yet), - then DON'T execute this code */ - io->iostate = IOSTATE_INITIAL; - ASSERT (ResetEvent (io->overlapped.hEvent)); - msg (D_WIN32_IO | M_ERRNO, "WIN32 I/O: TAP Completion error"); - } - } - break; - - case IOSTATE_IMMEDIATE_RETURN: - io->iostate = IOSTATE_INITIAL; - ASSERT (ResetEvent (io->overlapped.hEvent)); - if (io->status) - { - /* error return for a non-queued operation */ - SetLastError (io->status); - ret = -1; - msg (D_WIN32_IO | M_ERRNO, "WIN32 I/O: TAP Completion non-queued error"); - } - else - { - /* successful return for a non-queued operation */ - if (buf) - *buf = io->buf; - ret = io->size; - dmsg (D_WIN32_IO, "WIN32 I/O: TAP Completion non-queued success [%d]", ret); - } - break; - - case IOSTATE_INITIAL: /* were we called without proper queueing? */ - SetLastError (ERROR_INVALID_FUNCTION); - ret = -1; - dmsg (D_WIN32_IO, "WIN32 I/O: TAP Completion BAD STATE"); - break; - - default: - ASSERT (0); - } - - if (buf) - buf->len = ret; - return ret; +tun_finalize( + HANDLE h, + struct overlapped_io *io, + struct buffer *buf) +{ + int ret = -1; + BOOL status; + + switch (io->iostate) + { + case IOSTATE_QUEUED: + status = GetOverlappedResult( + h, + &io->overlapped, + &io->size, + FALSE + ); + if (status) + { + /* successful return for a queued operation */ + if (buf) + { + *buf = io->buf; + } + ret = io->size; + io->iostate = IOSTATE_INITIAL; + ASSERT(ResetEvent(io->overlapped.hEvent)); + dmsg(D_WIN32_IO, "WIN32 I/O: TAP Completion success [%d]", ret); + } + else + { + /* error during a queued operation */ + ret = -1; + if (GetLastError() != ERROR_IO_INCOMPLETE) + { + /* if no error (i.e. just not finished yet), + * then DON'T execute this code */ + io->iostate = IOSTATE_INITIAL; + ASSERT(ResetEvent(io->overlapped.hEvent)); + msg(D_WIN32_IO | M_ERRNO, "WIN32 I/O: TAP Completion error"); + } + } + break; + + case IOSTATE_IMMEDIATE_RETURN: + io->iostate = IOSTATE_INITIAL; + ASSERT(ResetEvent(io->overlapped.hEvent)); + if (io->status) + { + /* error return for a non-queued operation */ + SetLastError(io->status); + ret = -1; + msg(D_WIN32_IO | M_ERRNO, "WIN32 I/O: TAP Completion non-queued error"); + } + else + { + /* successful return for a non-queued operation */ + if (buf) + { + *buf = io->buf; + } + ret = io->size; + dmsg(D_WIN32_IO, "WIN32 I/O: TAP Completion non-queued success [%d]", ret); + } + break; + + case IOSTATE_INITIAL: /* were we called without proper queueing? */ + SetLastError(ERROR_INVALID_FUNCTION); + ret = -1; + dmsg(D_WIN32_IO, "WIN32 I/O: TAP Completion BAD STATE"); + break; + + default: + ASSERT(0); + } + + if (buf) + { + buf->len = ret; + } + return ret; } const struct tap_reg * -get_tap_reg (struct gc_arena *gc) -{ - HKEY adapter_key; - LONG status; - DWORD len; - struct tap_reg *first = NULL; - struct tap_reg *last = NULL; - int i = 0; - - status = RegOpenKeyEx( - HKEY_LOCAL_MACHINE, - ADAPTER_KEY, - 0, - KEY_READ, - &adapter_key); - - if (status != ERROR_SUCCESS) - msg (M_FATAL, "Error opening registry key: %s", ADAPTER_KEY); - - while (true) - { - char enum_name[256]; - char unit_string[256]; - HKEY unit_key; - char component_id_string[] = "ComponentId"; - char component_id[256]; - char net_cfg_instance_id_string[] = "NetCfgInstanceId"; - char net_cfg_instance_id[256]; - DWORD data_type; - - len = sizeof (enum_name); - status = RegEnumKeyEx( - adapter_key, - i, - enum_name, - &len, - NULL, - NULL, - NULL, - NULL); - if (status == ERROR_NO_MORE_ITEMS) - break; - else if (status != ERROR_SUCCESS) - msg (M_FATAL, "Error enumerating registry subkeys of key: %s", - ADAPTER_KEY); - - openvpn_snprintf (unit_string, sizeof(unit_string), "%s\\%s", - ADAPTER_KEY, enum_name); - - status = RegOpenKeyEx( - HKEY_LOCAL_MACHINE, - unit_string, - 0, - KEY_READ, - &unit_key); - - if (status != ERROR_SUCCESS) - dmsg (D_REGISTRY, "Error opening registry key: %s", unit_string); - else - { - len = sizeof (component_id); - status = RegQueryValueEx( - unit_key, - component_id_string, - NULL, - &data_type, - component_id, - &len); - - if (status != ERROR_SUCCESS || data_type != REG_SZ) - dmsg (D_REGISTRY, "Error opening registry key: %s\\%s", - unit_string, component_id_string); - else - { - len = sizeof (net_cfg_instance_id); - status = RegQueryValueEx( - unit_key, - net_cfg_instance_id_string, - NULL, - &data_type, - net_cfg_instance_id, - &len); - - if (status == ERROR_SUCCESS && data_type == REG_SZ) - { - if (!strcmp (component_id, TAP_WIN_COMPONENT_ID)) - { - struct tap_reg *reg; - ALLOC_OBJ_CLEAR_GC (reg, struct tap_reg, gc); - reg->guid = string_alloc (net_cfg_instance_id, gc); - - /* link into return list */ - if (!first) - first = reg; - if (last) - last->next = reg; - last = reg; - } - } - } - RegCloseKey (unit_key); - } - ++i; - } - - RegCloseKey (adapter_key); - return first; +get_tap_reg(struct gc_arena *gc) +{ + HKEY adapter_key; + LONG status; + DWORD len; + struct tap_reg *first = NULL; + struct tap_reg *last = NULL; + int i = 0; + + status = RegOpenKeyEx( + HKEY_LOCAL_MACHINE, + ADAPTER_KEY, + 0, + KEY_READ, + &adapter_key); + + if (status != ERROR_SUCCESS) + { + msg(M_FATAL, "Error opening registry key: %s", ADAPTER_KEY); + } + + while (true) + { + char enum_name[256]; + char unit_string[256]; + HKEY unit_key; + char component_id_string[] = "ComponentId"; + char component_id[256]; + char net_cfg_instance_id_string[] = "NetCfgInstanceId"; + char net_cfg_instance_id[256]; + DWORD data_type; + + len = sizeof(enum_name); + status = RegEnumKeyEx( + adapter_key, + i, + enum_name, + &len, + NULL, + NULL, + NULL, + NULL); + if (status == ERROR_NO_MORE_ITEMS) + { + break; + } + else if (status != ERROR_SUCCESS) + { + msg(M_FATAL, "Error enumerating registry subkeys of key: %s", + ADAPTER_KEY); + } + + openvpn_snprintf(unit_string, sizeof(unit_string), "%s\\%s", + ADAPTER_KEY, enum_name); + + status = RegOpenKeyEx( + HKEY_LOCAL_MACHINE, + unit_string, + 0, + KEY_READ, + &unit_key); + + if (status != ERROR_SUCCESS) + { + dmsg(D_REGISTRY, "Error opening registry key: %s", unit_string); + } + else + { + len = sizeof(component_id); + status = RegQueryValueEx( + unit_key, + component_id_string, + NULL, + &data_type, + component_id, + &len); + + if (status != ERROR_SUCCESS || data_type != REG_SZ) + { + dmsg(D_REGISTRY, "Error opening registry key: %s\\%s", + unit_string, component_id_string); + } + else + { + len = sizeof(net_cfg_instance_id); + status = RegQueryValueEx( + unit_key, + net_cfg_instance_id_string, + NULL, + &data_type, + net_cfg_instance_id, + &len); + + if (status == ERROR_SUCCESS && data_type == REG_SZ) + { + if (!strcmp(component_id, TAP_WIN_COMPONENT_ID)) + { + struct tap_reg *reg; + ALLOC_OBJ_CLEAR_GC(reg, struct tap_reg, gc); + reg->guid = string_alloc(net_cfg_instance_id, gc); + + /* link into return list */ + if (!first) + { + first = reg; + } + if (last) + { + last->next = reg; + } + last = reg; + } + } + } + RegCloseKey(unit_key); + } + ++i; + } + + RegCloseKey(adapter_key); + return first; } const struct panel_reg * -get_panel_reg (struct gc_arena *gc) -{ - LONG status; - HKEY network_connections_key; - DWORD len; - struct panel_reg *first = NULL; - struct panel_reg *last = NULL; - int i = 0; - - status = RegOpenKeyEx( - HKEY_LOCAL_MACHINE, - NETWORK_CONNECTIONS_KEY, - 0, - KEY_READ, - &network_connections_key); - - if (status != ERROR_SUCCESS) - msg (M_FATAL, "Error opening registry key: %s", NETWORK_CONNECTIONS_KEY); - - while (true) - { - char enum_name[256]; - char connection_string[256]; - HKEY connection_key; - WCHAR name_data[256]; - DWORD name_type; - const WCHAR name_string[] = L"Name"; - - len = sizeof (enum_name); - status = RegEnumKeyEx( - network_connections_key, - i, - enum_name, - &len, - NULL, - NULL, - NULL, - NULL); - if (status == ERROR_NO_MORE_ITEMS) - break; - else if (status != ERROR_SUCCESS) - msg (M_FATAL, "Error enumerating registry subkeys of key: %s", - NETWORK_CONNECTIONS_KEY); - - openvpn_snprintf (connection_string, sizeof(connection_string), - "%s\\%s\\Connection", - NETWORK_CONNECTIONS_KEY, enum_name); - - status = RegOpenKeyEx( - HKEY_LOCAL_MACHINE, - connection_string, - 0, - KEY_READ, - &connection_key); - - if (status != ERROR_SUCCESS) - dmsg (D_REGISTRY, "Error opening registry key: %s", connection_string); - else - { - len = sizeof (name_data); - status = RegQueryValueExW( - connection_key, - name_string, - NULL, - &name_type, - (LPBYTE) name_data, - &len); - - if (status != ERROR_SUCCESS || name_type != REG_SZ) - dmsg (D_REGISTRY, "Error opening registry key: %s\\%s\\%s", - NETWORK_CONNECTIONS_KEY, connection_string, name_string); - else - { - int n; - LPSTR name; - struct panel_reg *reg; - - ALLOC_OBJ_CLEAR_GC (reg, struct panel_reg, gc); - n = WideCharToMultiByte (CP_UTF8, 0, name_data, -1, NULL, 0, NULL, NULL); - name = gc_malloc (n, false, gc); - WideCharToMultiByte (CP_UTF8, 0, name_data, -1, name, n, NULL, NULL); - reg->name = name; - reg->guid = string_alloc (enum_name, gc); - - /* link into return list */ - if (!first) - first = reg; - if (last) - last->next = reg; - last = reg; - } - RegCloseKey (connection_key); - } - ++i; - } - - RegCloseKey (network_connections_key); - - return first; +get_panel_reg(struct gc_arena *gc) +{ + LONG status; + HKEY network_connections_key; + DWORD len; + struct panel_reg *first = NULL; + struct panel_reg *last = NULL; + int i = 0; + + status = RegOpenKeyEx( + HKEY_LOCAL_MACHINE, + NETWORK_CONNECTIONS_KEY, + 0, + KEY_READ, + &network_connections_key); + + if (status != ERROR_SUCCESS) + { + msg(M_FATAL, "Error opening registry key: %s", NETWORK_CONNECTIONS_KEY); + } + + while (true) + { + char enum_name[256]; + char connection_string[256]; + HKEY connection_key; + WCHAR name_data[256]; + DWORD name_type; + const WCHAR name_string[] = L"Name"; + + len = sizeof(enum_name); + status = RegEnumKeyEx( + network_connections_key, + i, + enum_name, + &len, + NULL, + NULL, + NULL, + NULL); + if (status == ERROR_NO_MORE_ITEMS) + { + break; + } + else if (status != ERROR_SUCCESS) + { + msg(M_FATAL, "Error enumerating registry subkeys of key: %s", + NETWORK_CONNECTIONS_KEY); + } + + openvpn_snprintf(connection_string, sizeof(connection_string), + "%s\\%s\\Connection", + NETWORK_CONNECTIONS_KEY, enum_name); + + status = RegOpenKeyEx( + HKEY_LOCAL_MACHINE, + connection_string, + 0, + KEY_READ, + &connection_key); + + if (status != ERROR_SUCCESS) + { + dmsg(D_REGISTRY, "Error opening registry key: %s", connection_string); + } + else + { + len = sizeof(name_data); + status = RegQueryValueExW( + connection_key, + name_string, + NULL, + &name_type, + (LPBYTE) name_data, + &len); + + if (status != ERROR_SUCCESS || name_type != REG_SZ) + { + dmsg(D_REGISTRY, "Error opening registry key: %s\\%s\\%s", + NETWORK_CONNECTIONS_KEY, connection_string, name_string); + } + else + { + int n; + LPSTR name; + struct panel_reg *reg; + + ALLOC_OBJ_CLEAR_GC(reg, struct panel_reg, gc); + n = WideCharToMultiByte(CP_UTF8, 0, name_data, -1, NULL, 0, NULL, NULL); + name = gc_malloc(n, false, gc); + WideCharToMultiByte(CP_UTF8, 0, name_data, -1, name, n, NULL, NULL); + reg->name = name; + reg->guid = string_alloc(enum_name, gc); + + /* link into return list */ + if (!first) + { + first = reg; + } + if (last) + { + last->next = reg; + } + last = reg; + } + RegCloseKey(connection_key); + } + ++i; + } + + RegCloseKey(network_connections_key); + + return first; } /* * Check that two addresses are part of the same 255.255.255.252 subnet. */ void -verify_255_255_255_252 (in_addr_t local, in_addr_t remote) +verify_255_255_255_252(in_addr_t local, in_addr_t remote) { - struct gc_arena gc = gc_new (); - const unsigned int mask = 3; - const char *err = NULL; + struct gc_arena gc = gc_new(); + const unsigned int mask = 3; + const char *err = NULL; - if (local == remote) + if (local == remote) { - err = "must be different"; - goto error; + err = "must be different"; + goto error; } - if ((local & (~mask)) != (remote & (~mask))) + if ((local & (~mask)) != (remote & (~mask))) { - err = "must exist within the same 255.255.255.252 subnet. This is a limitation of --dev tun when used with the TAP-WIN32 driver"; - goto error; + err = "must exist within the same 255.255.255.252 subnet. This is a limitation of --dev tun when used with the TAP-WIN32 driver"; + goto error; } - if ((local & mask) == 0 - || (local & mask) == 3 - || (remote & mask) == 0 - || (remote & mask) == 3) + if ((local & mask) == 0 + || (local & mask) == 3 + || (remote & mask) == 0 + || (remote & mask) == 3) { - err = "cannot use the first or last address within a given 255.255.255.252 subnet. This is a limitation of --dev tun when used with the TAP-WIN32 driver"; - goto error; + err = "cannot use the first or last address within a given 255.255.255.252 subnet. This is a limitation of --dev tun when used with the TAP-WIN32 driver"; + goto error; } - gc_free (&gc); - return; + gc_free(&gc); + return; - error: - msg (M_FATAL, "There is a problem in your selection of --ifconfig endpoints [local=%s, remote=%s]. The local and remote VPN endpoints %s. Try '" PACKAGE " --show-valid-subnets' option for more info.", - print_in_addr_t (local, 0, &gc), - print_in_addr_t (remote, 0, &gc), - err); - gc_free (&gc); +error: + msg(M_FATAL, "There is a problem in your selection of --ifconfig endpoints [local=%s, remote=%s]. The local and remote VPN endpoints %s. Try '" PACKAGE " --show-valid-subnets' option for more info.", + print_in_addr_t(local, 0, &gc), + print_in_addr_t(remote, 0, &gc), + err); + gc_free(&gc); } -void show_valid_win32_tun_subnets (void) +void +show_valid_win32_tun_subnets(void) { - int i; - int col = 0; - - printf ("On Windows, point-to-point IP support (i.e. --dev tun)\n"); - printf ("is emulated by the TAP-Windows driver. The major limitation\n"); - printf ("imposed by this approach is that the --ifconfig local and\n"); - printf ("remote endpoints must be part of the same 255.255.255.252\n"); - printf ("subnet. The following list shows examples of endpoint\n"); - printf ("pairs which satisfy this requirement. Only the final\n"); - printf ("component of the IP address pairs is at issue.\n\n"); - printf ("As an example, the following option would be correct:\n"); - printf (" --ifconfig 10.7.0.5 10.7.0.6 (on host A)\n"); - printf (" --ifconfig 10.7.0.6 10.7.0.5 (on host B)\n"); - printf ("because [5,6] is part of the below list.\n\n"); - - for (i = 0; i < 256; i += 4) + int i; + int col = 0; + + printf("On Windows, point-to-point IP support (i.e. --dev tun)\n"); + printf("is emulated by the TAP-Windows driver. The major limitation\n"); + printf("imposed by this approach is that the --ifconfig local and\n"); + printf("remote endpoints must be part of the same 255.255.255.252\n"); + printf("subnet. The following list shows examples of endpoint\n"); + printf("pairs which satisfy this requirement. Only the final\n"); + printf("component of the IP address pairs is at issue.\n\n"); + printf("As an example, the following option would be correct:\n"); + printf(" --ifconfig 10.7.0.5 10.7.0.6 (on host A)\n"); + printf(" --ifconfig 10.7.0.6 10.7.0.5 (on host B)\n"); + printf("because [5,6] is part of the below list.\n\n"); + + for (i = 0; i < 256; i += 4) + { + printf("[%3d,%3d] ", i+1, i+2); + if (++col > 4) + { + col = 0; + printf("\n"); + } + } + if (col) { - printf("[%3d,%3d] ", i+1, i+2); - if (++col > 4) - { - col = 0; - printf ("\n"); - } + printf("\n"); } - if (col) - printf ("\n"); } void -show_tap_win_adapters (int msglev, int warnlev) +show_tap_win_adapters(int msglev, int warnlev) { - struct gc_arena gc = gc_new (); + struct gc_arena gc = gc_new(); - bool warn_panel_null = false; - bool warn_panel_dup = false; - bool warn_tap_dup = false; + bool warn_panel_null = false; + bool warn_panel_dup = false; + bool warn_tap_dup = false; - int links; + int links; - const struct tap_reg *tr; - const struct tap_reg *tr1; - const struct panel_reg *pr; + const struct tap_reg *tr; + const struct tap_reg *tr1; + const struct panel_reg *pr; - const struct tap_reg *tap_reg = get_tap_reg (&gc); - const struct panel_reg *panel_reg = get_panel_reg (&gc); + const struct tap_reg *tap_reg = get_tap_reg(&gc); + const struct panel_reg *panel_reg = get_panel_reg(&gc); - msg (msglev, "Available TAP-WIN32 adapters [name, GUID]:"); + msg(msglev, "Available TAP-WIN32 adapters [name, GUID]:"); - /* loop through each TAP-Windows adapter registry entry */ - for (tr = tap_reg; tr != NULL; tr = tr->next) + /* loop through each TAP-Windows adapter registry entry */ + for (tr = tap_reg; tr != NULL; tr = tr->next) { - links = 0; + links = 0; - /* loop through each network connections entry in the control panel */ - for (pr = panel_reg; pr != NULL; pr = pr->next) - { - if (!strcmp (tr->guid, pr->guid)) - { - msg (msglev, "'%s' %s", pr->name, tr->guid); - ++links; - } - } + /* loop through each network connections entry in the control panel */ + for (pr = panel_reg; pr != NULL; pr = pr->next) + { + if (!strcmp(tr->guid, pr->guid)) + { + msg(msglev, "'%s' %s", pr->name, tr->guid); + ++links; + } + } - if (links > 1) - { - warn_panel_dup = true; - } - else if (links == 0) - { - /* a TAP adapter exists without a link from the network - connections control panel */ - warn_panel_null = true; - msg (msglev, "[NULL] %s", tr->guid); - } + if (links > 1) + { + warn_panel_dup = true; + } + else if (links == 0) + { + /* a TAP adapter exists without a link from the network + * connections control panel */ + warn_panel_null = true; + msg(msglev, "[NULL] %s", tr->guid); + } } - /* check for TAP-Windows adapter duplicated GUIDs */ - for (tr = tap_reg; tr != NULL; tr = tr->next) + /* check for TAP-Windows adapter duplicated GUIDs */ + for (tr = tap_reg; tr != NULL; tr = tr->next) { - for (tr1 = tap_reg; tr1 != NULL; tr1 = tr1->next) - { - if (tr != tr1 && !strcmp (tr->guid, tr1->guid)) - warn_tap_dup = true; - } + for (tr1 = tap_reg; tr1 != NULL; tr1 = tr1->next) + { + if (tr != tr1 && !strcmp(tr->guid, tr1->guid)) + { + warn_tap_dup = true; + } + } } - /* warn on registry inconsistencies */ - if (warn_tap_dup) - msg (warnlev, "WARNING: Some TAP-Windows adapters have duplicate GUIDs"); + /* warn on registry inconsistencies */ + if (warn_tap_dup) + { + msg(warnlev, "WARNING: Some TAP-Windows adapters have duplicate GUIDs"); + } - if (warn_panel_dup) - msg (warnlev, "WARNING: Some TAP-Windows adapters have duplicate links from the Network Connections control panel"); + if (warn_panel_dup) + { + msg(warnlev, "WARNING: Some TAP-Windows adapters have duplicate links from the Network Connections control panel"); + } - if (warn_panel_null) - msg (warnlev, "WARNING: Some TAP-Windows adapters have no link from the Network Connections control panel"); + if (warn_panel_null) + { + msg(warnlev, "WARNING: Some TAP-Windows adapters have no link from the Network Connections control panel"); + } - gc_free (&gc); + gc_free(&gc); } /* * Confirm that GUID is a TAP-Windows adapter. */ static bool -is_tap_win (const char *guid, const struct tap_reg *tap_reg) +is_tap_win(const char *guid, const struct tap_reg *tap_reg) { - const struct tap_reg *tr; + const struct tap_reg *tr; - for (tr = tap_reg; tr != NULL; tr = tr->next) + for (tr = tap_reg; tr != NULL; tr = tr->next) { - if (guid && !strcmp (tr->guid, guid)) - return true; + if (guid && !strcmp(tr->guid, guid)) + { + return true; + } } - return false; + return false; } static const char * -guid_to_name (const char *guid, const struct panel_reg *panel_reg) +guid_to_name(const char *guid, const struct panel_reg *panel_reg) { - const struct panel_reg *pr; + const struct panel_reg *pr; - for (pr = panel_reg; pr != NULL; pr = pr->next) + for (pr = panel_reg; pr != NULL; pr = pr->next) { - if (guid && !strcmp (pr->guid, guid)) - return pr->name; + if (guid && !strcmp(pr->guid, guid)) + { + return pr->name; + } } - return NULL; + return NULL; } static const char * -name_to_guid (const char *name, const struct tap_reg *tap_reg, const struct panel_reg *panel_reg) +name_to_guid(const char *name, const struct tap_reg *tap_reg, const struct panel_reg *panel_reg) { - const struct panel_reg *pr; + const struct panel_reg *pr; - for (pr = panel_reg; pr != NULL; pr = pr->next) + for (pr = panel_reg; pr != NULL; pr = pr->next) { - if (name && !strcmp (pr->name, name) && is_tap_win (pr->guid, tap_reg)) - return pr->guid; + if (name && !strcmp(pr->name, name) && is_tap_win(pr->guid, tap_reg)) + { + return pr->guid; + } } - return NULL; + return NULL; } static void -at_least_one_tap_win (const struct tap_reg *tap_reg) +at_least_one_tap_win(const struct tap_reg *tap_reg) { - if (!tap_reg) - msg (M_FATAL, "There are no TAP-Windows adapters on this system. You should be able to create a TAP-Windows adapter by going to Start -> All Programs -> TAP-Windows -> Utilities -> Add a new TAP-Windows virtual ethernet adapter."); + if (!tap_reg) + { + msg(M_FATAL, "There are no TAP-Windows adapters on this system. You should be able to create a TAP-Windows adapter by going to Start -> All Programs -> TAP-Windows -> Utilities -> Add a new TAP-Windows virtual ethernet adapter."); + } } /* - * Get an adapter GUID and optional actual_name from the + * Get an adapter GUID and optional actual_name from the * registry for the TAP device # = device_number. */ static const char * -get_unspecified_device_guid (const int device_number, - char *actual_name, - int actual_name_size, - const struct tap_reg *tap_reg_src, - const struct panel_reg *panel_reg_src, - struct gc_arena *gc) -{ - const struct tap_reg *tap_reg = tap_reg_src; - struct buffer ret = clear_buf (); - struct buffer actual = clear_buf (); - int i; - - ASSERT (device_number >= 0); - - /* Make sure we have at least one TAP adapter */ - if (!tap_reg) - return NULL; +get_unspecified_device_guid(const int device_number, + char *actual_name, + int actual_name_size, + const struct tap_reg *tap_reg_src, + const struct panel_reg *panel_reg_src, + struct gc_arena *gc) +{ + const struct tap_reg *tap_reg = tap_reg_src; + struct buffer ret = clear_buf(); + struct buffer actual = clear_buf(); + int i; + + ASSERT(device_number >= 0); + + /* Make sure we have at least one TAP adapter */ + if (!tap_reg) + { + return NULL; + } - /* The actual_name output buffer may be NULL */ - if (actual_name) + /* The actual_name output buffer may be NULL */ + if (actual_name) { - ASSERT (actual_name_size > 0); - buf_set_write (&actual, actual_name, actual_name_size); + ASSERT(actual_name_size > 0); + buf_set_write(&actual, actual_name, actual_name_size); } - /* Move on to specified device number */ - for (i = 0; i < device_number; i++) + /* Move on to specified device number */ + for (i = 0; i < device_number; i++) { - tap_reg = tap_reg->next; - if (!tap_reg) - return NULL; + tap_reg = tap_reg->next; + if (!tap_reg) + { + return NULL; + } } - /* Save Network Panel name (if exists) in actual_name */ - if (actual_name) + /* Save Network Panel name (if exists) in actual_name */ + if (actual_name) { - const char *act = guid_to_name (tap_reg->guid, panel_reg_src); - if (act) - buf_printf (&actual, "%s", act); - else - buf_printf (&actual, "%s", tap_reg->guid); + const char *act = guid_to_name(tap_reg->guid, panel_reg_src); + if (act) + { + buf_printf(&actual, "%s", act); + } + else + { + buf_printf(&actual, "%s", tap_reg->guid); + } } - /* Save GUID for return value */ - ret = alloc_buf_gc (256, gc); - buf_printf (&ret, "%s", tap_reg->guid); - return BSTR (&ret); + /* Save GUID for return value */ + ret = alloc_buf_gc(256, gc); + buf_printf(&ret, "%s", tap_reg->guid); + return BSTR(&ret); } /* @@ -3773,158 +4100,172 @@ get_unspecified_device_guid (const int device_number, * returning the GUID and optional actual_name. */ static const char * -get_device_guid (const char *name, - char *actual_name, - int actual_name_size, - const struct tap_reg *tap_reg, - const struct panel_reg *panel_reg, - struct gc_arena *gc) -{ - struct buffer ret = alloc_buf_gc (256, gc); - struct buffer actual = clear_buf (); - - /* Make sure we have at least one TAP adapter */ - if (!tap_reg) - return NULL; +get_device_guid(const char *name, + char *actual_name, + int actual_name_size, + const struct tap_reg *tap_reg, + const struct panel_reg *panel_reg, + struct gc_arena *gc) +{ + struct buffer ret = alloc_buf_gc(256, gc); + struct buffer actual = clear_buf(); + + /* Make sure we have at least one TAP adapter */ + if (!tap_reg) + { + return NULL; + } - /* The actual_name output buffer may be NULL */ - if (actual_name) + /* The actual_name output buffer may be NULL */ + if (actual_name) { - ASSERT (actual_name_size > 0); - buf_set_write (&actual, actual_name, actual_name_size); + ASSERT(actual_name_size > 0); + buf_set_write(&actual, actual_name, actual_name_size); } - /* Check if GUID was explicitly specified as --dev-node parameter */ - if (is_tap_win (name, tap_reg)) + /* Check if GUID was explicitly specified as --dev-node parameter */ + if (is_tap_win(name, tap_reg)) { - const char *act = guid_to_name (name, panel_reg); - buf_printf (&ret, "%s", name); - if (act) - buf_printf (&actual, "%s", act); - else - buf_printf (&actual, "%s", name); - return BSTR (&ret); + const char *act = guid_to_name(name, panel_reg); + buf_printf(&ret, "%s", name); + if (act) + { + buf_printf(&actual, "%s", act); + } + else + { + buf_printf(&actual, "%s", name); + } + return BSTR(&ret); } - /* Lookup TAP adapter in network connections list */ - { - const char *guid = name_to_guid (name, tap_reg, panel_reg); - if (guid) - { - buf_printf (&actual, "%s", name); - buf_printf (&ret, "%s", guid); - return BSTR (&ret); - } - } + /* Lookup TAP adapter in network connections list */ + { + const char *guid = name_to_guid(name, tap_reg, panel_reg); + if (guid) + { + buf_printf(&actual, "%s", name); + buf_printf(&ret, "%s", guid); + return BSTR(&ret); + } + } - return NULL; + return NULL; } /* * Get adapter info list */ const IP_ADAPTER_INFO * -get_adapter_info_list (struct gc_arena *gc) +get_adapter_info_list(struct gc_arena *gc) { - ULONG size = 0; - IP_ADAPTER_INFO *pi = NULL; - DWORD status; + ULONG size = 0; + IP_ADAPTER_INFO *pi = NULL; + DWORD status; - if ((status = GetAdaptersInfo (NULL, &size)) != ERROR_BUFFER_OVERFLOW) + if ((status = GetAdaptersInfo(NULL, &size)) != ERROR_BUFFER_OVERFLOW) { - msg (M_INFO, "GetAdaptersInfo #1 failed (status=%u) : %s", - (unsigned int)status, - strerror_win32 (status, gc)); + msg(M_INFO, "GetAdaptersInfo #1 failed (status=%u) : %s", + (unsigned int)status, + strerror_win32(status, gc)); } - else + else { - pi = (PIP_ADAPTER_INFO) gc_malloc (size, false, gc); - if ((status = GetAdaptersInfo (pi, &size)) == NO_ERROR) - return pi; - else - { - msg (M_INFO, "GetAdaptersInfo #2 failed (status=%u) : %s", - (unsigned int)status, - strerror_win32 (status, gc)); - } + pi = (PIP_ADAPTER_INFO) gc_malloc(size, false, gc); + if ((status = GetAdaptersInfo(pi, &size)) == NO_ERROR) + { + return pi; + } + else + { + msg(M_INFO, "GetAdaptersInfo #2 failed (status=%u) : %s", + (unsigned int)status, + strerror_win32(status, gc)); + } } - return pi; + return pi; } const IP_PER_ADAPTER_INFO * -get_per_adapter_info (const DWORD index, struct gc_arena *gc) -{ - ULONG size = 0; - IP_PER_ADAPTER_INFO *pi = NULL; - DWORD status; - - if (index != TUN_ADAPTER_INDEX_INVALID) - { - if ((status = GetPerAdapterInfo (index, NULL, &size)) != ERROR_BUFFER_OVERFLOW) - { - msg (M_INFO, "GetPerAdapterInfo #1 failed (status=%u) : %s", - (unsigned int)status, - strerror_win32 (status, gc)); - } - else - { - pi = (PIP_PER_ADAPTER_INFO) gc_malloc (size, false, gc); - if ((status = GetPerAdapterInfo ((ULONG)index, pi, &size)) == ERROR_SUCCESS) - return pi; - else - { - msg (M_INFO, "GetPerAdapterInfo #2 failed (status=%u) : %s", - (unsigned int)status, - strerror_win32 (status, gc)); - } - } - } - return pi; +get_per_adapter_info(const DWORD index, struct gc_arena *gc) +{ + ULONG size = 0; + IP_PER_ADAPTER_INFO *pi = NULL; + DWORD status; + + if (index != TUN_ADAPTER_INDEX_INVALID) + { + if ((status = GetPerAdapterInfo(index, NULL, &size)) != ERROR_BUFFER_OVERFLOW) + { + msg(M_INFO, "GetPerAdapterInfo #1 failed (status=%u) : %s", + (unsigned int)status, + strerror_win32(status, gc)); + } + else + { + pi = (PIP_PER_ADAPTER_INFO) gc_malloc(size, false, gc); + if ((status = GetPerAdapterInfo((ULONG)index, pi, &size)) == ERROR_SUCCESS) + { + return pi; + } + else + { + msg(M_INFO, "GetPerAdapterInfo #2 failed (status=%u) : %s", + (unsigned int)status, + strerror_win32(status, gc)); + } + } + } + return pi; } static const IP_INTERFACE_INFO * -get_interface_info_list (struct gc_arena *gc) +get_interface_info_list(struct gc_arena *gc) { - ULONG size = 0; - IP_INTERFACE_INFO *ii = NULL; - DWORD status; + ULONG size = 0; + IP_INTERFACE_INFO *ii = NULL; + DWORD status; - if ((status = GetInterfaceInfo (NULL, &size)) != ERROR_INSUFFICIENT_BUFFER) + if ((status = GetInterfaceInfo(NULL, &size)) != ERROR_INSUFFICIENT_BUFFER) { - msg (M_INFO, "GetInterfaceInfo #1 failed (status=%u) : %s", - (unsigned int)status, - strerror_win32 (status, gc)); + msg(M_INFO, "GetInterfaceInfo #1 failed (status=%u) : %s", + (unsigned int)status, + strerror_win32(status, gc)); } - else + else { - ii = (PIP_INTERFACE_INFO) gc_malloc (size, false, gc); - if ((status = GetInterfaceInfo (ii, &size)) == NO_ERROR) - return ii; - else - { - msg (M_INFO, "GetInterfaceInfo #2 failed (status=%u) : %s", - (unsigned int)status, - strerror_win32 (status, gc)); - } + ii = (PIP_INTERFACE_INFO) gc_malloc(size, false, gc); + if ((status = GetInterfaceInfo(ii, &size)) == NO_ERROR) + { + return ii; + } + else + { + msg(M_INFO, "GetInterfaceInfo #2 failed (status=%u) : %s", + (unsigned int)status, + strerror_win32(status, gc)); + } } - return ii; + return ii; } static const IP_ADAPTER_INDEX_MAP * -get_interface_info (DWORD index, struct gc_arena *gc) +get_interface_info(DWORD index, struct gc_arena *gc) { - const IP_INTERFACE_INFO *list = get_interface_info_list (gc); - if (list) + const IP_INTERFACE_INFO *list = get_interface_info_list(gc); + if (list) { - int i; - for (i = 0; i < list->NumAdapters; ++i) - { - const IP_ADAPTER_INDEX_MAP *inter = &list->Adapter[i]; - if (index == inter->Index) - return inter; - } + int i; + for (i = 0; i < list->NumAdapters; ++i) + { + const IP_ADAPTER_INDEX_MAP *inter = &list->Adapter[i]; + if (index == inter->Index) + { + return inter; + } + } } - return NULL; + return NULL; } /* @@ -3933,229 +4274,261 @@ get_interface_info (DWORD index, struct gc_arena *gc) */ const IP_ADAPTER_INFO * -get_adapter (const IP_ADAPTER_INFO *ai, DWORD index) +get_adapter(const IP_ADAPTER_INFO *ai, DWORD index) { - if (ai && index != TUN_ADAPTER_INDEX_INVALID) + if (ai && index != TUN_ADAPTER_INDEX_INVALID) { - const IP_ADAPTER_INFO *a; + const IP_ADAPTER_INFO *a; - /* find index in the linked list */ - for (a = ai; a != NULL; a = a->Next) - { - if (a->Index == index) - return a; - } + /* find index in the linked list */ + for (a = ai; a != NULL; a = a->Next) + { + if (a->Index == index) + { + return a; + } + } } - return NULL; + return NULL; } const IP_ADAPTER_INFO * -get_adapter_info (DWORD index, struct gc_arena *gc) +get_adapter_info(DWORD index, struct gc_arena *gc) { - return get_adapter (get_adapter_info_list (gc), index); + return get_adapter(get_adapter_info_list(gc), index); } static int -get_adapter_n_ip_netmask (const IP_ADAPTER_INFO *ai) +get_adapter_n_ip_netmask(const IP_ADAPTER_INFO *ai) { - if (ai) + if (ai) { - int n = 0; - const IP_ADDR_STRING *ip = &ai->IpAddressList; + int n = 0; + const IP_ADDR_STRING *ip = &ai->IpAddressList; - while (ip) - { - ++n; - ip = ip->Next; - } - return n; + while (ip) + { + ++n; + ip = ip->Next; + } + return n; + } + else + { + return 0; } - else - return 0; } static bool -get_adapter_ip_netmask (const IP_ADAPTER_INFO *ai, const int n, in_addr_t *ip, in_addr_t *netmask) +get_adapter_ip_netmask(const IP_ADAPTER_INFO *ai, const int n, in_addr_t *ip, in_addr_t *netmask) { - bool ret = false; - *ip = 0; - *netmask = 0; + bool ret = false; + *ip = 0; + *netmask = 0; - if (ai) + if (ai) { - const IP_ADDR_STRING *iplist = &ai->IpAddressList; - int i = 0; + const IP_ADDR_STRING *iplist = &ai->IpAddressList; + int i = 0; - while (iplist) - { - if (i == n) - break; - ++i; - iplist = iplist->Next; - } + while (iplist) + { + if (i == n) + { + break; + } + ++i; + iplist = iplist->Next; + } - if (iplist) - { - const unsigned int getaddr_flags = GETADDR_HOST_ORDER; - const char *ip_str = iplist->IpAddress.String; - const char *netmask_str = iplist->IpMask.String; - bool succeed1 = false; - bool succeed2 = false; + if (iplist) + { + const unsigned int getaddr_flags = GETADDR_HOST_ORDER; + const char *ip_str = iplist->IpAddress.String; + const char *netmask_str = iplist->IpMask.String; + bool succeed1 = false; + bool succeed2 = false; - if (ip_str && netmask_str && strlen (ip_str) && strlen (netmask_str)) - { - *ip = getaddr (getaddr_flags, ip_str, 0, &succeed1, NULL); - *netmask = getaddr (getaddr_flags, netmask_str, 0, &succeed2, NULL); - ret = (succeed1 == true && succeed2 == true); - } - } + if (ip_str && netmask_str && strlen(ip_str) && strlen(netmask_str)) + { + *ip = getaddr(getaddr_flags, ip_str, 0, &succeed1, NULL); + *netmask = getaddr(getaddr_flags, netmask_str, 0, &succeed2, NULL); + ret = (succeed1 == true && succeed2 == true); + } + } } - return ret; + return ret; } static bool -test_adapter_ip_netmask (const IP_ADAPTER_INFO *ai, const in_addr_t ip, const in_addr_t netmask) +test_adapter_ip_netmask(const IP_ADAPTER_INFO *ai, const in_addr_t ip, const in_addr_t netmask) { - if (ai) + if (ai) { - in_addr_t ip_adapter = 0; - in_addr_t netmask_adapter = 0; - const bool status = get_adapter_ip_netmask (ai, 0, &ip_adapter, &netmask_adapter); - return (status && ip_adapter == ip && netmask_adapter == netmask); + in_addr_t ip_adapter = 0; + in_addr_t netmask_adapter = 0; + const bool status = get_adapter_ip_netmask(ai, 0, &ip_adapter, &netmask_adapter); + return (status && ip_adapter == ip && netmask_adapter == netmask); + } + else + { + return false; } - else - return false; } const IP_ADAPTER_INFO * -get_tun_adapter (const struct tuntap *tt, const IP_ADAPTER_INFO *list) +get_tun_adapter(const struct tuntap *tt, const IP_ADAPTER_INFO *list) { - if (list && tt) - return get_adapter (list, tt->adapter_index); - else - return NULL; + if (list && tt) + { + return get_adapter(list, tt->adapter_index); + } + else + { + return NULL; + } } bool -is_adapter_up (const struct tuntap *tt, const IP_ADAPTER_INFO *list) +is_adapter_up(const struct tuntap *tt, const IP_ADAPTER_INFO *list) { - int i; - bool ret = false; + int i; + bool ret = false; - const IP_ADAPTER_INFO *ai = get_tun_adapter (tt, list); + const IP_ADAPTER_INFO *ai = get_tun_adapter(tt, list); - if (ai) + if (ai) { - const int n = get_adapter_n_ip_netmask (ai); + const int n = get_adapter_n_ip_netmask(ai); - /* loop once for every IP/netmask assigned to adapter */ - for (i = 0; i < n; ++i) - { - in_addr_t ip, netmask; - if (get_adapter_ip_netmask (ai, i, &ip, &netmask)) - { - if (tt->local && tt->adapter_netmask) - { - /* wait for our --ifconfig parms to match the actual adapter parms */ - if (tt->local == ip && tt->adapter_netmask == netmask) - ret = true; - } - else - { - /* --ifconfig was not defined, maybe using a real DHCP server */ - if (ip && netmask) - ret = true; - } - } - } + /* loop once for every IP/netmask assigned to adapter */ + for (i = 0; i < n; ++i) + { + in_addr_t ip, netmask; + if (get_adapter_ip_netmask(ai, i, &ip, &netmask)) + { + if (tt->local && tt->adapter_netmask) + { + /* wait for our --ifconfig parms to match the actual adapter parms */ + if (tt->local == ip && tt->adapter_netmask == netmask) + { + ret = true; + } + } + else + { + /* --ifconfig was not defined, maybe using a real DHCP server */ + if (ip && netmask) + { + ret = true; + } + } + } + } } - else - ret = true; /* this can occur when TAP adapter is bridged */ + else + { + ret = true; /* this can occur when TAP adapter is bridged */ - return ret; + } + return ret; } bool -is_ip_in_adapter_subnet (const IP_ADAPTER_INFO *ai, const in_addr_t ip, in_addr_t *highest_netmask) +is_ip_in_adapter_subnet(const IP_ADAPTER_INFO *ai, const in_addr_t ip, in_addr_t *highest_netmask) { - int i; - bool ret = false; + int i; + bool ret = false; - if (highest_netmask) - *highest_netmask = 0; + if (highest_netmask) + { + *highest_netmask = 0; + } - if (ai) + if (ai) { - const int n = get_adapter_n_ip_netmask (ai); - for (i = 0; i < n; ++i) - { - in_addr_t adapter_ip, adapter_netmask; - if (get_adapter_ip_netmask (ai, i, &adapter_ip, &adapter_netmask)) - { - if (adapter_ip && adapter_netmask && (ip & adapter_netmask) == (adapter_ip & adapter_netmask)) - { - if (highest_netmask && adapter_netmask > *highest_netmask) - *highest_netmask = adapter_netmask; - ret = true; - } - } - } + const int n = get_adapter_n_ip_netmask(ai); + for (i = 0; i < n; ++i) + { + in_addr_t adapter_ip, adapter_netmask; + if (get_adapter_ip_netmask(ai, i, &adapter_ip, &adapter_netmask)) + { + if (adapter_ip && adapter_netmask && (ip & adapter_netmask) == (adapter_ip & adapter_netmask)) + { + if (highest_netmask && adapter_netmask > *highest_netmask) + { + *highest_netmask = adapter_netmask; + } + ret = true; + } + } + } } - return ret; + return ret; } DWORD -adapter_index_of_ip (const IP_ADAPTER_INFO *list, - const in_addr_t ip, - int *count, - in_addr_t *netmask) -{ - struct gc_arena gc = gc_new (); - DWORD ret = TUN_ADAPTER_INDEX_INVALID; - in_addr_t highest_netmask = 0; - bool first = true; - - if (count) - *count = 0; - - while (list) - { - in_addr_t hn; - - if (is_ip_in_adapter_subnet (list, ip, &hn)) - { - if (first || hn > highest_netmask) - { - highest_netmask = hn; - if (count) - *count = 1; - ret = list->Index; - first = false; - } - else if (hn == highest_netmask) - { - if (count) - ++*count; - } - } - list = list->Next; - } - - dmsg (D_ROUTE_DEBUG, "DEBUG: IP Locate: ip=%s nm=%s index=%d count=%d", - print_in_addr_t (ip, 0, &gc), - print_in_addr_t (highest_netmask, 0, &gc), - (int)ret, - count ? *count : -1); - - if (ret == TUN_ADAPTER_INDEX_INVALID && count) - *count = 0; - - if (netmask) - *netmask = highest_netmask; - - gc_free (&gc); - return ret; +adapter_index_of_ip(const IP_ADAPTER_INFO *list, + const in_addr_t ip, + int *count, + in_addr_t *netmask) +{ + struct gc_arena gc = gc_new(); + DWORD ret = TUN_ADAPTER_INDEX_INVALID; + in_addr_t highest_netmask = 0; + bool first = true; + + if (count) + { + *count = 0; + } + + while (list) + { + in_addr_t hn; + + if (is_ip_in_adapter_subnet(list, ip, &hn)) + { + if (first || hn > highest_netmask) + { + highest_netmask = hn; + if (count) + { + *count = 1; + } + ret = list->Index; + first = false; + } + else if (hn == highest_netmask) + { + if (count) + { + ++*count; + } + } + } + list = list->Next; + } + + dmsg(D_ROUTE_DEBUG, "DEBUG: IP Locate: ip=%s nm=%s index=%d count=%d", + print_in_addr_t(ip, 0, &gc), + print_in_addr_t(highest_netmask, 0, &gc), + (int)ret, + count ? *count : -1); + + if (ret == TUN_ADAPTER_INDEX_INVALID && count) + { + *count = 0; + } + + if (netmask) + { + *netmask = highest_netmask; + } + + gc_free(&gc); + return ret; } /* @@ -4168,24 +4541,28 @@ adapter_index_of_ip (const IP_ADAPTER_INFO *list, #define DHCP_STATUS_DISABLED 2 static int -dhcp_status (DWORD index) +dhcp_status(DWORD index) { - struct gc_arena gc = gc_new (); - int ret = DHCP_STATUS_UNDEF; - if (index != TUN_ADAPTER_INDEX_INVALID) + struct gc_arena gc = gc_new(); + int ret = DHCP_STATUS_UNDEF; + if (index != TUN_ADAPTER_INDEX_INVALID) { - const IP_ADAPTER_INFO *ai = get_adapter_info (index, &gc); + const IP_ADAPTER_INFO *ai = get_adapter_info(index, &gc); - if (ai) - { - if (ai->DhcpEnabled) - ret = DHCP_STATUS_ENABLED; - else - ret = DHCP_STATUS_DISABLED; - } + if (ai) + { + if (ai->DhcpEnabled) + { + ret = DHCP_STATUS_ENABLED; + } + else + { + ret = DHCP_STATUS_DISABLED; + } + } } - gc_free (&gc); - return ret; + gc_free(&gc); + return ret; } /* @@ -4193,191 +4570,207 @@ dhcp_status (DWORD index) * to adapter (given by index) by previous calls to AddIPAddress. */ static void -delete_temp_addresses (DWORD index) -{ - struct gc_arena gc = gc_new (); - const IP_ADAPTER_INFO *a = get_adapter_info (index, &gc); - - if (a) - { - const IP_ADDR_STRING *ip = &a->IpAddressList; - while (ip) - { - DWORD status; - const DWORD context = ip->Context; - - if ((status = DeleteIPAddress ((ULONG) context)) == NO_ERROR) - { - msg (M_INFO, "Successfully deleted previously set dynamic IP/netmask: %s/%s", - ip->IpAddress.String, - ip->IpMask.String); - } - else - { - const char *empty = "0.0.0.0"; - if (strcmp (ip->IpAddress.String, empty) - || strcmp (ip->IpMask.String, empty)) - msg (M_INFO, "NOTE: could not delete previously set dynamic IP/netmask: %s/%s (status=%u)", - ip->IpAddress.String, - ip->IpMask.String, - (unsigned int)status); - } - ip = ip->Next; - } - } - gc_free (&gc); +delete_temp_addresses(DWORD index) +{ + struct gc_arena gc = gc_new(); + const IP_ADAPTER_INFO *a = get_adapter_info(index, &gc); + + if (a) + { + const IP_ADDR_STRING *ip = &a->IpAddressList; + while (ip) + { + DWORD status; + const DWORD context = ip->Context; + + if ((status = DeleteIPAddress((ULONG) context)) == NO_ERROR) + { + msg(M_INFO, "Successfully deleted previously set dynamic IP/netmask: %s/%s", + ip->IpAddress.String, + ip->IpMask.String); + } + else + { + const char *empty = "0.0.0.0"; + if (strcmp(ip->IpAddress.String, empty) + || strcmp(ip->IpMask.String, empty)) + { + msg(M_INFO, "NOTE: could not delete previously set dynamic IP/netmask: %s/%s (status=%u)", + ip->IpAddress.String, + ip->IpMask.String, + (unsigned int)status); + } + } + ip = ip->Next; + } + } + gc_free(&gc); } /* * Get interface index for use with IP Helper API functions. */ static DWORD -get_adapter_index_method_1 (const char *guid) +get_adapter_index_method_1(const char *guid) { - DWORD index; - ULONG aindex; - wchar_t wbuf[256]; - _snwprintf (wbuf, SIZE (wbuf), L"\\DEVICE\\TCPIP_%S", guid); - wbuf [SIZE(wbuf) - 1] = 0; - if (GetAdapterIndex (wbuf, &aindex) != NO_ERROR) - index = TUN_ADAPTER_INDEX_INVALID; - else - index = (DWORD)aindex; - return index; + DWORD index; + ULONG aindex; + wchar_t wbuf[256]; + _snwprintf(wbuf, SIZE(wbuf), L"\\DEVICE\\TCPIP_%S", guid); + wbuf [SIZE(wbuf) - 1] = 0; + if (GetAdapterIndex(wbuf, &aindex) != NO_ERROR) + { + index = TUN_ADAPTER_INDEX_INVALID; + } + else + { + index = (DWORD)aindex; + } + return index; } static DWORD -get_adapter_index_method_2 (const char *guid) +get_adapter_index_method_2(const char *guid) { - struct gc_arena gc = gc_new (); - DWORD index = TUN_ADAPTER_INDEX_INVALID; + struct gc_arena gc = gc_new(); + DWORD index = TUN_ADAPTER_INDEX_INVALID; - const IP_ADAPTER_INFO *list = get_adapter_info_list (&gc); + const IP_ADAPTER_INFO *list = get_adapter_info_list(&gc); - while (list) + while (list) { - if (!strcmp (guid, list->AdapterName)) - { - index = list->Index; - break; - } - list = list->Next; + if (!strcmp(guid, list->AdapterName)) + { + index = list->Index; + break; + } + list = list->Next; } - gc_free (&gc); - return index; + gc_free(&gc); + return index; } static DWORD -get_adapter_index (const char *guid) +get_adapter_index(const char *guid) { - DWORD index; - index = get_adapter_index_method_1 (guid); - if (index == TUN_ADAPTER_INDEX_INVALID) - index = get_adapter_index_method_2 (guid); - if (index == TUN_ADAPTER_INDEX_INVALID) - msg (M_INFO, "NOTE: could not get adapter index for %s", guid); - return index; + DWORD index; + index = get_adapter_index_method_1(guid); + if (index == TUN_ADAPTER_INDEX_INVALID) + { + index = get_adapter_index_method_2(guid); + } + if (index == TUN_ADAPTER_INDEX_INVALID) + { + msg(M_INFO, "NOTE: could not get adapter index for %s", guid); + } + return index; } static DWORD -get_adapter_index_flexible (const char *name) /* actual name or GUID */ +get_adapter_index_flexible(const char *name) /* actual name or GUID */ { - struct gc_arena gc = gc_new (); - DWORD index; - index = get_adapter_index_method_1 (name); - if (index == TUN_ADAPTER_INDEX_INVALID) - index = get_adapter_index_method_2 (name); - if (index == TUN_ADAPTER_INDEX_INVALID) + struct gc_arena gc = gc_new(); + DWORD index; + index = get_adapter_index_method_1(name); + if (index == TUN_ADAPTER_INDEX_INVALID) + { + index = get_adapter_index_method_2(name); + } + if (index == TUN_ADAPTER_INDEX_INVALID) + { + const struct tap_reg *tap_reg = get_tap_reg(&gc); + const struct panel_reg *panel_reg = get_panel_reg(&gc); + const char *guid = name_to_guid(name, tap_reg, panel_reg); + index = get_adapter_index_method_1(guid); + if (index == TUN_ADAPTER_INDEX_INVALID) + { + index = get_adapter_index_method_2(guid); + } + } + if (index == TUN_ADAPTER_INDEX_INVALID) { - const struct tap_reg *tap_reg = get_tap_reg (&gc); - const struct panel_reg *panel_reg = get_panel_reg (&gc); - const char *guid = name_to_guid (name, tap_reg, panel_reg); - index = get_adapter_index_method_1 (guid); - if (index == TUN_ADAPTER_INDEX_INVALID) - index = get_adapter_index_method_2 (guid); + msg(M_INFO, "NOTE: could not get adapter index for name/GUID '%s'", name); } - if (index == TUN_ADAPTER_INDEX_INVALID) - msg (M_INFO, "NOTE: could not get adapter index for name/GUID '%s'", name); - gc_free (&gc); - return index; + gc_free(&gc); + return index; } /* * Return a string representing a PIP_ADDR_STRING */ static const char * -format_ip_addr_string (const IP_ADDR_STRING *ip, struct gc_arena *gc) +format_ip_addr_string(const IP_ADDR_STRING *ip, struct gc_arena *gc) { - struct buffer out = alloc_buf_gc (256, gc); - while (ip) + struct buffer out = alloc_buf_gc(256, gc); + while (ip) { - buf_printf (&out, "%s", ip->IpAddress.String); - if (strlen (ip->IpMask.String)) - { - buf_printf (&out, "/"); - buf_printf (&out, "%s", ip->IpMask.String); - } - buf_printf (&out, " "); - ip = ip->Next; + buf_printf(&out, "%s", ip->IpAddress.String); + if (strlen(ip->IpMask.String)) + { + buf_printf(&out, "/"); + buf_printf(&out, "%s", ip->IpMask.String); + } + buf_printf(&out, " "); + ip = ip->Next; } - return BSTR (&out); + return BSTR(&out); } /* * Show info for a single adapter */ static void -show_adapter (int msglev, const IP_ADAPTER_INFO *a, struct gc_arena *gc) +show_adapter(int msglev, const IP_ADAPTER_INFO *a, struct gc_arena *gc) { - msg (msglev, "%s", a->Description); - msg (msglev, " Index = %d", (int)a->Index); - msg (msglev, " GUID = %s", a->AdapterName); - msg (msglev, " IP = %s", format_ip_addr_string (&a->IpAddressList, gc)); - msg (msglev, " MAC = %s", format_hex_ex (a->Address, a->AddressLength, 0, 1, ":", gc)); - msg (msglev, " GATEWAY = %s", format_ip_addr_string (&a->GatewayList, gc)); - if (a->DhcpEnabled) + msg(msglev, "%s", a->Description); + msg(msglev, " Index = %d", (int)a->Index); + msg(msglev, " GUID = %s", a->AdapterName); + msg(msglev, " IP = %s", format_ip_addr_string(&a->IpAddressList, gc)); + msg(msglev, " MAC = %s", format_hex_ex(a->Address, a->AddressLength, 0, 1, ":", gc)); + msg(msglev, " GATEWAY = %s", format_ip_addr_string(&a->GatewayList, gc)); + if (a->DhcpEnabled) { - msg (msglev, " DHCP SERV = %s", format_ip_addr_string (&a->DhcpServer, gc)); - msg (msglev, " DHCP LEASE OBTAINED = %s", time_string (a->LeaseObtained, 0, false, gc)); - msg (msglev, " DHCP LEASE EXPIRES = %s", time_string (a->LeaseExpires, 0, false, gc)); + msg(msglev, " DHCP SERV = %s", format_ip_addr_string(&a->DhcpServer, gc)); + msg(msglev, " DHCP LEASE OBTAINED = %s", time_string(a->LeaseObtained, 0, false, gc)); + msg(msglev, " DHCP LEASE EXPIRES = %s", time_string(a->LeaseExpires, 0, false, gc)); } - if (a->HaveWins) + if (a->HaveWins) { - msg (msglev, " PRI WINS = %s", format_ip_addr_string (&a->PrimaryWinsServer, gc)); - msg (msglev, " SEC WINS = %s", format_ip_addr_string (&a->SecondaryWinsServer, gc)); + msg(msglev, " PRI WINS = %s", format_ip_addr_string(&a->PrimaryWinsServer, gc)); + msg(msglev, " SEC WINS = %s", format_ip_addr_string(&a->SecondaryWinsServer, gc)); } - { - const IP_PER_ADAPTER_INFO *pai = get_per_adapter_info (a->Index, gc); - if (pai) - { - msg (msglev, " DNS SERV = %s", format_ip_addr_string (&pai->DnsServerList, gc)); - } - } + { + const IP_PER_ADAPTER_INFO *pai = get_per_adapter_info(a->Index, gc); + if (pai) + { + msg(msglev, " DNS SERV = %s", format_ip_addr_string(&pai->DnsServerList, gc)); + } + } } /* * Show current adapter list */ void -show_adapters (int msglev) +show_adapters(int msglev) { - struct gc_arena gc = gc_new (); - const IP_ADAPTER_INFO *ai = get_adapter_info_list (&gc); + struct gc_arena gc = gc_new(); + const IP_ADAPTER_INFO *ai = get_adapter_info_list(&gc); - msg (msglev, "SYSTEM ADAPTER LIST"); - if (ai) + msg(msglev, "SYSTEM ADAPTER LIST"); + if (ai) { - const IP_ADAPTER_INFO *a; + const IP_ADAPTER_INFO *a; - /* find index in the linked list */ - for (a = ai; a != NULL; a = a->Next) - { - show_adapter (msglev, a, &gc); - } + /* find index in the linked list */ + for (a = ai; a != NULL; a = a->Next) + { + show_adapter(msglev, a, &gc); + } } - gc_free (&gc); + gc_free(&gc); } /* @@ -4388,113 +4781,123 @@ show_adapters (int msglev) */ static void -tap_allow_nonadmin_access_handle (const char *device_path, HANDLE hand) +tap_allow_nonadmin_access_handle(const char *device_path, HANDLE hand) { - struct security_attributes sa; - BOOL status; + struct security_attributes sa; + BOOL status; - if (!init_security_attributes_allow_all (&sa)) - msg (M_ERR, "Error: init SA failed"); + if (!init_security_attributes_allow_all(&sa)) + { + msg(M_ERR, "Error: init SA failed"); + } - status = SetKernelObjectSecurity (hand, DACL_SECURITY_INFORMATION, &sa.sd); - if (!status) + status = SetKernelObjectSecurity(hand, DACL_SECURITY_INFORMATION, &sa.sd); + if (!status) { - msg (M_ERRNO, "Error: SetKernelObjectSecurity failed on %s", device_path); + msg(M_ERRNO, "Error: SetKernelObjectSecurity failed on %s", device_path); } - else + else { - msg (M_INFO|M_NOPREFIX, "TAP-Windows device: %s [Non-admin access allowed]", device_path); + msg(M_INFO|M_NOPREFIX, "TAP-Windows device: %s [Non-admin access allowed]", device_path); } } void -tap_allow_nonadmin_access (const char *dev_node) -{ - struct gc_arena gc = gc_new (); - const struct tap_reg *tap_reg = get_tap_reg (&gc); - const struct panel_reg *panel_reg = get_panel_reg (&gc); - const char *device_guid = NULL; - HANDLE hand; - char actual_buffer[256]; - char device_path[256]; - - at_least_one_tap_win (tap_reg); - - if (dev_node) - { - /* Get the device GUID for the device specified with --dev-node. */ - device_guid = get_device_guid (dev_node, actual_buffer, sizeof (actual_buffer), tap_reg, panel_reg, &gc); - - if (!device_guid) - msg (M_FATAL, "TAP-Windows adapter '%s' not found", dev_node); - - /* Open Windows TAP-Windows adapter */ - openvpn_snprintf (device_path, sizeof(device_path), "%s%s%s", - USERMODEDEVICEDIR, - device_guid, - TAP_WIN_SUFFIX); - - hand = CreateFile ( - device_path, - MAXIMUM_ALLOWED, - 0, /* was: FILE_SHARE_READ */ - 0, - OPEN_EXISTING, - FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, - 0 - ); - - if (hand == INVALID_HANDLE_VALUE) - msg (M_ERR, "CreateFile failed on TAP device: %s", device_path); - - tap_allow_nonadmin_access_handle (device_path, hand); - CloseHandle (hand); - } - else - { - int device_number = 0; - - /* Try opening all TAP devices */ - while (true) - { - device_guid = get_unspecified_device_guid (device_number, - actual_buffer, - sizeof (actual_buffer), - tap_reg, - panel_reg, - &gc); - - if (!device_guid) - break; - - /* Open Windows TAP-Windows adapter */ - openvpn_snprintf (device_path, sizeof(device_path), "%s%s%s", - USERMODEDEVICEDIR, - device_guid, - TAP_WIN_SUFFIX); - - hand = CreateFile ( - device_path, - MAXIMUM_ALLOWED, - 0, /* was: FILE_SHARE_READ */ - 0, - OPEN_EXISTING, - FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, - 0 - ); - - if (hand == INVALID_HANDLE_VALUE) - msg (M_WARN, "CreateFile failed on TAP device: %s", device_path); - else - { - tap_allow_nonadmin_access_handle (device_path, hand); - CloseHandle (hand); - } - - device_number++; - } - } - gc_free (&gc); +tap_allow_nonadmin_access(const char *dev_node) +{ + struct gc_arena gc = gc_new(); + const struct tap_reg *tap_reg = get_tap_reg(&gc); + const struct panel_reg *panel_reg = get_panel_reg(&gc); + const char *device_guid = NULL; + HANDLE hand; + char actual_buffer[256]; + char device_path[256]; + + at_least_one_tap_win(tap_reg); + + if (dev_node) + { + /* Get the device GUID for the device specified with --dev-node. */ + device_guid = get_device_guid(dev_node, actual_buffer, sizeof(actual_buffer), tap_reg, panel_reg, &gc); + + if (!device_guid) + { + msg(M_FATAL, "TAP-Windows adapter '%s' not found", dev_node); + } + + /* Open Windows TAP-Windows adapter */ + openvpn_snprintf(device_path, sizeof(device_path), "%s%s%s", + USERMODEDEVICEDIR, + device_guid, + TAP_WIN_SUFFIX); + + hand = CreateFile( + device_path, + MAXIMUM_ALLOWED, + 0, /* was: FILE_SHARE_READ */ + 0, + OPEN_EXISTING, + FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, + 0 + ); + + if (hand == INVALID_HANDLE_VALUE) + { + msg(M_ERR, "CreateFile failed on TAP device: %s", device_path); + } + + tap_allow_nonadmin_access_handle(device_path, hand); + CloseHandle(hand); + } + else + { + int device_number = 0; + + /* Try opening all TAP devices */ + while (true) + { + device_guid = get_unspecified_device_guid(device_number, + actual_buffer, + sizeof(actual_buffer), + tap_reg, + panel_reg, + &gc); + + if (!device_guid) + { + break; + } + + /* Open Windows TAP-Windows adapter */ + openvpn_snprintf(device_path, sizeof(device_path), "%s%s%s", + USERMODEDEVICEDIR, + device_guid, + TAP_WIN_SUFFIX); + + hand = CreateFile( + device_path, + MAXIMUM_ALLOWED, + 0, /* was: FILE_SHARE_READ */ + 0, + OPEN_EXISTING, + FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, + 0 + ); + + if (hand == INVALID_HANDLE_VALUE) + { + msg(M_WARN, "CreateFile failed on TAP device: %s", device_path); + } + else + { + tap_allow_nonadmin_access_handle(device_path, hand); + CloseHandle(hand); + } + + device_number++; + } + } + gc_free(&gc); } /* @@ -4503,68 +4906,80 @@ tap_allow_nonadmin_access (const char *dev_node) bool dhcp_release_by_adapter_index(const DWORD adapter_index) { - struct gc_arena gc = gc_new (); - bool ret = false; - const IP_ADAPTER_INDEX_MAP *inter = get_interface_info (adapter_index, &gc); + struct gc_arena gc = gc_new(); + bool ret = false; + const IP_ADAPTER_INDEX_MAP *inter = get_interface_info(adapter_index, &gc); - if (inter) + if (inter) { - DWORD status = IpReleaseAddress ((IP_ADAPTER_INDEX_MAP *)inter); - if (status == NO_ERROR) - { - msg (D_TUNTAP_INFO, "TAP: DHCP address released"); - ret = true; - } - else - msg (M_WARN, "NOTE: Release of DHCP-assigned IP address lease on TAP-Windows adapter failed: %s (code=%u)", - strerror_win32 (status, &gc), - (unsigned int)status); + DWORD status = IpReleaseAddress((IP_ADAPTER_INDEX_MAP *)inter); + if (status == NO_ERROR) + { + msg(D_TUNTAP_INFO, "TAP: DHCP address released"); + ret = true; + } + else + { + msg(M_WARN, "NOTE: Release of DHCP-assigned IP address lease on TAP-Windows adapter failed: %s (code=%u)", + strerror_win32(status, &gc), + (unsigned int)status); + } } - gc_free (&gc); - return ret; + gc_free(&gc); + return ret; } static bool -dhcp_release (const struct tuntap *tt) +dhcp_release(const struct tuntap *tt) { - if (tt && tt->options.ip_win32_type == IPW32_SET_DHCP_MASQ && tt->adapter_index != TUN_ADAPTER_INDEX_INVALID) - return dhcp_release_by_adapter_index (tt->adapter_index); - else - return false; + if (tt && tt->options.ip_win32_type == IPW32_SET_DHCP_MASQ && tt->adapter_index != TUN_ADAPTER_INDEX_INVALID) + { + return dhcp_release_by_adapter_index(tt->adapter_index); + } + else + { + return false; + } } bool -dhcp_renew_by_adapter_index (const DWORD adapter_index) +dhcp_renew_by_adapter_index(const DWORD adapter_index) { - struct gc_arena gc = gc_new (); - bool ret = false; - const IP_ADAPTER_INDEX_MAP *inter = get_interface_info (adapter_index, &gc); + struct gc_arena gc = gc_new(); + bool ret = false; + const IP_ADAPTER_INDEX_MAP *inter = get_interface_info(adapter_index, &gc); - if (inter) + if (inter) { - DWORD status = IpRenewAddress ((IP_ADAPTER_INDEX_MAP *)inter); - if (status == NO_ERROR) - { - msg (D_TUNTAP_INFO, "TAP: DHCP address renewal succeeded"); - ret = true; - } - else - msg (M_WARN, "WARNING: Failed to renew DHCP IP address lease on TAP-Windows adapter: %s (code=%u)", - strerror_win32 (status, &gc), - (unsigned int)status); + DWORD status = IpRenewAddress((IP_ADAPTER_INDEX_MAP *)inter); + if (status == NO_ERROR) + { + msg(D_TUNTAP_INFO, "TAP: DHCP address renewal succeeded"); + ret = true; + } + else + { + msg(M_WARN, "WARNING: Failed to renew DHCP IP address lease on TAP-Windows adapter: %s (code=%u)", + strerror_win32(status, &gc), + (unsigned int)status); + } } - gc_free (&gc); - return ret; + gc_free(&gc); + return ret; } static bool -dhcp_renew (const struct tuntap *tt) +dhcp_renew(const struct tuntap *tt) { - if (tt && tt->options.ip_win32_type == IPW32_SET_DHCP_MASQ && tt->adapter_index != TUN_ADAPTER_INDEX_INVALID) - return dhcp_renew_by_adapter_index (tt->adapter_index); - else - return false; + if (tt && tt->options.ip_win32_type == IPW32_SET_DHCP_MASQ && tt->adapter_index != TUN_ADAPTER_INDEX_INVALID) + { + return dhcp_renew_by_adapter_index(tt->adapter_index); + } + else + { + return false; + } } /* @@ -4572,124 +4987,138 @@ dhcp_renew (const struct tuntap *tt) */ static void -netsh_command (const struct argv *a, int n, int msglevel) +netsh_command(const struct argv *a, int n, int msglevel) { - int i; - for (i = 0; i < n; ++i) - { - bool status; - openvpn_sleep (1); - netcmd_semaphore_lock (); - argv_msg_prefix (M_INFO, a, "NETSH"); - status = openvpn_execve_check (a, NULL, 0, "ERROR: netsh command failed"); - netcmd_semaphore_release (); - if (status) - return; - openvpn_sleep (4); + int i; + for (i = 0; i < n; ++i) + { + bool status; + openvpn_sleep(1); + netcmd_semaphore_lock(); + argv_msg_prefix(M_INFO, a, "NETSH"); + status = openvpn_execve_check(a, NULL, 0, "ERROR: netsh command failed"); + netcmd_semaphore_release(); + if (status) + { + return; + } + openvpn_sleep(4); } - msg (msglevel, "NETSH: command failed"); + msg(msglevel, "NETSH: command failed"); } void -ipconfig_register_dns (const struct env_set *es) +ipconfig_register_dns(const struct env_set *es) { - struct argv argv = argv_new (); - bool status; - const char err[] = "ERROR: Windows ipconfig command failed"; + struct argv argv = argv_new(); + bool status; + const char err[] = "ERROR: Windows ipconfig command failed"; - msg (D_TUNTAP_INFO, "Start ipconfig commands for register-dns..."); - netcmd_semaphore_lock (); + msg(D_TUNTAP_INFO, "Start ipconfig commands for register-dns..."); + netcmd_semaphore_lock(); - argv_printf (&argv, "%s%sc /flushdns", - get_win_sys_path(), - WIN_IPCONFIG_PATH_SUFFIX); - argv_msg (D_TUNTAP_INFO, &argv); - status = openvpn_execve_check (&argv, es, 0, err); - argv_reset(&argv); + argv_printf(&argv, "%s%sc /flushdns", + get_win_sys_path(), + WIN_IPCONFIG_PATH_SUFFIX); + argv_msg(D_TUNTAP_INFO, &argv); + status = openvpn_execve_check(&argv, es, 0, err); + argv_reset(&argv); - argv_printf (&argv, "%s%sc /registerdns", - get_win_sys_path(), - WIN_IPCONFIG_PATH_SUFFIX); - argv_msg (D_TUNTAP_INFO, &argv); - status = openvpn_execve_check (&argv, es, 0, err); - argv_reset(&argv); + argv_printf(&argv, "%s%sc /registerdns", + get_win_sys_path(), + WIN_IPCONFIG_PATH_SUFFIX); + argv_msg(D_TUNTAP_INFO, &argv); + status = openvpn_execve_check(&argv, es, 0, err); + argv_reset(&argv); - netcmd_semaphore_release (); - msg (D_TUNTAP_INFO, "End ipconfig commands for register-dns..."); + netcmd_semaphore_release(); + msg(D_TUNTAP_INFO, "End ipconfig commands for register-dns..."); } void -ip_addr_string_to_array (in_addr_t *dest, int *dest_len, const IP_ADDR_STRING *src) +ip_addr_string_to_array(in_addr_t *dest, int *dest_len, const IP_ADDR_STRING *src) { - int i = 0; - while (src) + int i = 0; + while (src) { - const unsigned int getaddr_flags = GETADDR_HOST_ORDER; - const char *ip_str = src->IpAddress.String; - in_addr_t ip = 0; - bool succeed = false; + const unsigned int getaddr_flags = GETADDR_HOST_ORDER; + const char *ip_str = src->IpAddress.String; + in_addr_t ip = 0; + bool succeed = false; - if (i >= *dest_len) - break; - if (!ip_str || !strlen (ip_str)) - break; + if (i >= *dest_len) + { + break; + } + if (!ip_str || !strlen(ip_str)) + { + break; + } - ip = getaddr (getaddr_flags, ip_str, 0, &succeed, NULL); - if (!succeed) - break; - dest[i++] = ip; + ip = getaddr(getaddr_flags, ip_str, 0, &succeed, NULL); + if (!succeed) + { + break; + } + dest[i++] = ip; - src = src->Next; + src = src->Next; } - *dest_len = i; + *dest_len = i; #if 0 - { - struct gc_arena gc = gc_new (); - msg (M_INFO, "ip_addr_string_to_array [%d]", *dest_len); - for (i = 0; i < *dest_len; ++i) - { - msg (M_INFO, "%s", print_in_addr_t (dest[i], 0, &gc)); - } - gc_free (&gc); - } + { + struct gc_arena gc = gc_new(); + msg(M_INFO, "ip_addr_string_to_array [%d]", *dest_len); + for (i = 0; i < *dest_len; ++i) + { + msg(M_INFO, "%s", print_in_addr_t(dest[i], 0, &gc)); + } + gc_free(&gc); + } #endif } static bool -ip_addr_one_to_one (const in_addr_t *a1, const int a1len, const IP_ADDR_STRING *ias) +ip_addr_one_to_one(const in_addr_t *a1, const int a1len, const IP_ADDR_STRING *ias) { - in_addr_t a2[8]; - int a2len = SIZE(a2); - int i; + in_addr_t a2[8]; + int a2len = SIZE(a2); + int i; - ip_addr_string_to_array (a2, &a2len, ias); - /*msg (M_INFO, "a1len=%d a2len=%d", a1len, a2len);*/ - if (a1len != a2len) - return false; + ip_addr_string_to_array(a2, &a2len, ias); + /*msg (M_INFO, "a1len=%d a2len=%d", a1len, a2len);*/ + if (a1len != a2len) + { + return false; + } - for (i = 0; i < a1len; ++i) + for (i = 0; i < a1len; ++i) { - if (a1[i] != a2[i]) - return false; + if (a1[i] != a2[i]) + { + return false; + } } - return true; + return true; } static bool -ip_addr_member_of (const in_addr_t addr, const IP_ADDR_STRING *ias) +ip_addr_member_of(const in_addr_t addr, const IP_ADDR_STRING *ias) { - in_addr_t aa[8]; - int len = SIZE(aa); - int i; + in_addr_t aa[8]; + int len = SIZE(aa); + int i; - ip_addr_string_to_array (aa, &len, ias); - for (i = 0; i < len; ++i) + ip_addr_string_to_array(aa, &len, ias); + for (i = 0; i < len; ++i) { - if (addr == aa[i]) - return true; + if (addr == aa[i]) + { + return true; + } } - return false; + return false; } /** @@ -4699,273 +5128,289 @@ ip_addr_member_of (const in_addr_t addr, const IP_ADDR_STRING *ias) * No action is taken if number of addresses (addr_len) < 1. */ static void -netsh_set_dns6_servers (const struct in6_addr *addr_list, - const int addr_len, - const char *flex_name) +netsh_set_dns6_servers(const struct in6_addr *addr_list, + const int addr_len, + const char *flex_name) { - struct gc_arena gc = gc_new (); - struct argv argv = argv_new (); + struct gc_arena gc = gc_new(); + struct argv argv = argv_new(); for (int i = 0; i < addr_len; ++i) { - const char *fmt = (i == 0) ? - "%s%sc interface ipv6 set dns %s static %s" - : "%s%sc interface ipv6 add dns %s %s"; - argv_printf (&argv, fmt, get_win_sys_path(), - NETSH_PATH_SUFFIX, flex_name, - print_in6_addr (addr_list[i], 0, &gc)); + const char *fmt = (i == 0) ? + "%s%sc interface ipv6 set dns %s static %s" + : "%s%sc interface ipv6 add dns %s %s"; + argv_printf(&argv, fmt, get_win_sys_path(), + NETSH_PATH_SUFFIX, flex_name, + print_in6_addr(addr_list[i], 0, &gc)); - /* disable slow address validation on Windows 7 and higher */ - if (win32_version_info() >= WIN_7) - argv_printf_cat (&argv, "%s", "validate=no"); + /* disable slow address validation on Windows 7 and higher */ + if (win32_version_info() >= WIN_7) + { + argv_printf_cat(&argv, "%s", "validate=no"); + } - /* Treat errors while adding as non-fatal as we do not check for duplicates */ - netsh_command (&argv, 1, (i==0)? M_FATAL : M_NONFATAL); + /* Treat errors while adding as non-fatal as we do not check for duplicates */ + netsh_command(&argv, 1, (i==0) ? M_FATAL : M_NONFATAL); } - argv_reset (&argv); - gc_free (&gc); + argv_reset(&argv); + gc_free(&gc); } static void -netsh_ifconfig_options (const char *type, - const in_addr_t *addr_list, - const int addr_len, - const IP_ADDR_STRING *current, - const char *flex_name, - const bool test_first) -{ - struct gc_arena gc = gc_new (); - struct argv argv = argv_new (); - bool delete_first = false; - - /* first check if we should delete existing DNS/WINS settings from TAP interface */ - if (test_first) - { - if (!ip_addr_one_to_one (addr_list, addr_len, current)) - delete_first = true; - } - else - delete_first = true; - - /* delete existing DNS/WINS settings from TAP interface */ - if (delete_first) - { - argv_printf (&argv, "%s%sc interface ip delete %s %s all", - get_win_sys_path(), - NETSH_PATH_SUFFIX, - type, - flex_name); - netsh_command (&argv, 2, M_FATAL); - } - - /* add new DNS/WINS settings to TAP interface */ - { - int count = 0; - int i; - for (i = 0; i < addr_len; ++i) - { - if (delete_first || !test_first || !ip_addr_member_of (addr_list[i], current)) - { - const char *fmt = count ? - "%s%sc interface ip add %s %s %s" - : "%s%sc interface ip set %s %s static %s"; - - argv_printf (&argv, fmt, - get_win_sys_path(), - NETSH_PATH_SUFFIX, - type, - flex_name, - print_in_addr_t (addr_list[i], 0, &gc)); - netsh_command (&argv, 2, M_FATAL); - - ++count; - } - else - { - msg (M_INFO, "NETSH: \"%s\" %s %s [already set]", - flex_name, - type, - print_in_addr_t (addr_list[i], 0, &gc)); - } - } - } - - argv_reset (&argv); - gc_free (&gc); +netsh_ifconfig_options(const char *type, + const in_addr_t *addr_list, + const int addr_len, + const IP_ADDR_STRING *current, + const char *flex_name, + const bool test_first) +{ + struct gc_arena gc = gc_new(); + struct argv argv = argv_new(); + bool delete_first = false; + + /* first check if we should delete existing DNS/WINS settings from TAP interface */ + if (test_first) + { + if (!ip_addr_one_to_one(addr_list, addr_len, current)) + { + delete_first = true; + } + } + else + { + delete_first = true; + } + + /* delete existing DNS/WINS settings from TAP interface */ + if (delete_first) + { + argv_printf(&argv, "%s%sc interface ip delete %s %s all", + get_win_sys_path(), + NETSH_PATH_SUFFIX, + type, + flex_name); + netsh_command(&argv, 2, M_FATAL); + } + + /* add new DNS/WINS settings to TAP interface */ + { + int count = 0; + int i; + for (i = 0; i < addr_len; ++i) + { + if (delete_first || !test_first || !ip_addr_member_of(addr_list[i], current)) + { + const char *fmt = count ? + "%s%sc interface ip add %s %s %s" + : "%s%sc interface ip set %s %s static %s"; + + argv_printf(&argv, fmt, + get_win_sys_path(), + NETSH_PATH_SUFFIX, + type, + flex_name, + print_in_addr_t(addr_list[i], 0, &gc)); + netsh_command(&argv, 2, M_FATAL); + + ++count; + } + else + { + msg(M_INFO, "NETSH: \"%s\" %s %s [already set]", + flex_name, + type, + print_in_addr_t(addr_list[i], 0, &gc)); + } + } + } + + argv_reset(&argv); + gc_free(&gc); } static void -init_ip_addr_string2 (IP_ADDR_STRING *dest, const IP_ADDR_STRING *src1, const IP_ADDR_STRING *src2) +init_ip_addr_string2(IP_ADDR_STRING *dest, const IP_ADDR_STRING *src1, const IP_ADDR_STRING *src2) { - CLEAR (dest[0]); - CLEAR (dest[1]); - if (src1) + CLEAR(dest[0]); + CLEAR(dest[1]); + if (src1) { - dest[0] = *src1; - dest[0].Next = NULL; + dest[0] = *src1; + dest[0].Next = NULL; } - if (src2) + if (src2) { - dest[1] = *src2; - dest[0].Next = &dest[1]; - dest[1].Next = NULL; + dest[1] = *src2; + dest[0].Next = &dest[1]; + dest[1].Next = NULL; } } static void -netsh_ifconfig (const struct tuntap_options *to, - const char *flex_name, - const in_addr_t ip, - const in_addr_t netmask, - const unsigned int flags) -{ - struct gc_arena gc = gc_new (); - struct argv argv = argv_new (); - const IP_ADAPTER_INFO *ai = NULL; - const IP_PER_ADAPTER_INFO *pai = NULL; - - if (flags & NI_TEST_FIRST) - { - const IP_ADAPTER_INFO *list = get_adapter_info_list (&gc); - const int index = get_adapter_index_flexible (flex_name); - ai = get_adapter (list, index); - pai = get_per_adapter_info (index, &gc); - } - - if (flags & NI_IP_NETMASK) - { - if (test_adapter_ip_netmask (ai, ip, netmask)) - { - msg (M_INFO, "NETSH: \"%s\" %s/%s [already set]", - flex_name, - print_in_addr_t (ip, 0, &gc), - print_in_addr_t (netmask, 0, &gc)); - } - else - { - /* example: netsh interface ip set address my-tap static 10.3.0.1 255.255.255.0 */ - argv_printf (&argv, "%s%sc interface ip set address %s static %s %s", - get_win_sys_path(), - NETSH_PATH_SUFFIX, - flex_name, - print_in_addr_t (ip, 0, &gc), - print_in_addr_t (netmask, 0, &gc)); - - netsh_command (&argv, 4, M_FATAL); - } - } - - /* set WINS/DNS options */ - if (flags & NI_OPTIONS) - { - IP_ADDR_STRING wins[2]; - CLEAR (wins[0]); - CLEAR (wins[1]); - - netsh_ifconfig_options ("dns", - to->dns, - to->dns_len, - pai ? &pai->DnsServerList : NULL, - flex_name, - BOOL_CAST (flags & NI_TEST_FIRST)); - if (ai && ai->HaveWins) - init_ip_addr_string2 (wins, &ai->PrimaryWinsServer, &ai->SecondaryWinsServer); - - netsh_ifconfig_options ("wins", - to->wins, - to->wins_len, - ai ? wins : NULL, - flex_name, - BOOL_CAST (flags & NI_TEST_FIRST)); - } - - argv_reset (&argv); - gc_free (&gc); +netsh_ifconfig(const struct tuntap_options *to, + const char *flex_name, + const in_addr_t ip, + const in_addr_t netmask, + const unsigned int flags) +{ + struct gc_arena gc = gc_new(); + struct argv argv = argv_new(); + const IP_ADAPTER_INFO *ai = NULL; + const IP_PER_ADAPTER_INFO *pai = NULL; + + if (flags & NI_TEST_FIRST) + { + const IP_ADAPTER_INFO *list = get_adapter_info_list(&gc); + const int index = get_adapter_index_flexible(flex_name); + ai = get_adapter(list, index); + pai = get_per_adapter_info(index, &gc); + } + + if (flags & NI_IP_NETMASK) + { + if (test_adapter_ip_netmask(ai, ip, netmask)) + { + msg(M_INFO, "NETSH: \"%s\" %s/%s [already set]", + flex_name, + print_in_addr_t(ip, 0, &gc), + print_in_addr_t(netmask, 0, &gc)); + } + else + { + /* example: netsh interface ip set address my-tap static 10.3.0.1 255.255.255.0 */ + argv_printf(&argv, "%s%sc interface ip set address %s static %s %s", + get_win_sys_path(), + NETSH_PATH_SUFFIX, + flex_name, + print_in_addr_t(ip, 0, &gc), + print_in_addr_t(netmask, 0, &gc)); + + netsh_command(&argv, 4, M_FATAL); + } + } + + /* set WINS/DNS options */ + if (flags & NI_OPTIONS) + { + IP_ADDR_STRING wins[2]; + CLEAR(wins[0]); + CLEAR(wins[1]); + + netsh_ifconfig_options("dns", + to->dns, + to->dns_len, + pai ? &pai->DnsServerList : NULL, + flex_name, + BOOL_CAST(flags & NI_TEST_FIRST)); + if (ai && ai->HaveWins) + { + init_ip_addr_string2(wins, &ai->PrimaryWinsServer, &ai->SecondaryWinsServer); + } + + netsh_ifconfig_options("wins", + to->wins, + to->wins_len, + ai ? wins : NULL, + flex_name, + BOOL_CAST(flags & NI_TEST_FIRST)); + } + + argv_reset(&argv); + gc_free(&gc); } static void -netsh_enable_dhcp (const struct tuntap_options *to, - const char *actual_name) +netsh_enable_dhcp(const struct tuntap_options *to, + const char *actual_name) { - struct argv argv = argv_new (); + struct argv argv = argv_new(); - /* example: netsh interface ip set address my-tap dhcp */ - argv_printf (&argv, - "%s%sc interface ip set address %s dhcp", - get_win_sys_path(), - NETSH_PATH_SUFFIX, - actual_name); + /* example: netsh interface ip set address my-tap dhcp */ + argv_printf(&argv, + "%s%sc interface ip set address %s dhcp", + get_win_sys_path(), + NETSH_PATH_SUFFIX, + actual_name); - netsh_command (&argv, 4, M_FATAL); + netsh_command(&argv, 4, M_FATAL); - argv_reset (&argv); + argv_reset(&argv); } /* * Return a TAP name for netsh commands. */ static const char * -netsh_get_id (const char *dev_node, struct gc_arena *gc) +netsh_get_id(const char *dev_node, struct gc_arena *gc) { - const struct tap_reg *tap_reg = get_tap_reg (gc); - const struct panel_reg *panel_reg = get_panel_reg (gc); - struct buffer actual = alloc_buf_gc (256, gc); - const char *guid; + const struct tap_reg *tap_reg = get_tap_reg(gc); + const struct panel_reg *panel_reg = get_panel_reg(gc); + struct buffer actual = alloc_buf_gc(256, gc); + const char *guid; + + at_least_one_tap_win(tap_reg); + + if (dev_node) + { + guid = get_device_guid(dev_node, BPTR(&actual), BCAP(&actual), tap_reg, panel_reg, gc); + } + else + { + guid = get_unspecified_device_guid(0, BPTR(&actual), BCAP(&actual), tap_reg, panel_reg, gc); - at_least_one_tap_win (tap_reg); + if (get_unspecified_device_guid(1, NULL, 0, tap_reg, panel_reg, gc)) /* ambiguous if more than one TAP-Windows adapter */ + { + guid = NULL; + } + } - if (dev_node) + if (!guid) + { + return "NULL"; /* not found */ + } + else if (strcmp(BPTR(&actual), "NULL")) { - guid = get_device_guid (dev_node, BPTR (&actual), BCAP (&actual), tap_reg, panel_reg, gc); + return BPTR(&actual); /* control panel name */ } - else + else { - guid = get_unspecified_device_guid (0, BPTR (&actual), BCAP (&actual), tap_reg, panel_reg, gc); - - if (get_unspecified_device_guid (1, NULL, 0, tap_reg, panel_reg, gc)) /* ambiguous if more than one TAP-Windows adapter */ - guid = NULL; + return guid; /* no control panel name, return GUID instead */ } - - if (!guid) - return "NULL"; /* not found */ - else if (strcmp (BPTR (&actual), "NULL")) - return BPTR (&actual); /* control panel name */ - else - return guid; /* no control panel name, return GUID instead */ } /* * Called iteratively on TAP-Windows wait-for-initialization polling loop */ void -tun_standby_init (struct tuntap *tt) +tun_standby_init(struct tuntap *tt) { - tt->standby_iter = 0; + tt->standby_iter = 0; } bool -tun_standby (struct tuntap *tt) +tun_standby(struct tuntap *tt) { - bool ret = true; - ++tt->standby_iter; - if (tt->options.ip_win32_type == IPW32_SET_ADAPTIVE) + bool ret = true; + ++tt->standby_iter; + if (tt->options.ip_win32_type == IPW32_SET_ADAPTIVE) { - if (tt->standby_iter == IPW32_SET_ADAPTIVE_TRY_NETSH) - { - msg (M_INFO, "NOTE: now trying netsh (this may take some time)"); - netsh_ifconfig (&tt->options, - tt->actual_name, - tt->local, - tt->adapter_netmask, - NI_TEST_FIRST|NI_IP_NETMASK|NI_OPTIONS); - } - else if (tt->standby_iter >= IPW32_SET_ADAPTIVE_TRY_NETSH*2) - { - ret = false; - } + if (tt->standby_iter == IPW32_SET_ADAPTIVE_TRY_NETSH) + { + msg(M_INFO, "NOTE: now trying netsh (this may take some time)"); + netsh_ifconfig(&tt->options, + tt->actual_name, + tt->local, + tt->adapter_netmask, + NI_TEST_FIRST|NI_IP_NETMASK|NI_OPTIONS); + } + else if (tt->standby_iter >= IPW32_SET_ADAPTIVE_TRY_NETSH*2) + { + ret = false; + } } - return ret; + return ret; } /* @@ -4974,765 +5419,849 @@ tun_standby (struct tuntap *tt) */ static void -write_dhcp_u8 (struct buffer *buf, const int type, const int data, bool *error) +write_dhcp_u8(struct buffer *buf, const int type, const int data, bool *error) { - if (!buf_safe (buf, 3)) + if (!buf_safe(buf, 3)) { - *error = true; - msg (M_WARN, "write_dhcp_u8: buffer overflow building DHCP options"); - return; + *error = true; + msg(M_WARN, "write_dhcp_u8: buffer overflow building DHCP options"); + return; } - buf_write_u8 (buf, type); - buf_write_u8 (buf, 1); - buf_write_u8 (buf, data); + buf_write_u8(buf, type); + buf_write_u8(buf, 1); + buf_write_u8(buf, data); } static void -write_dhcp_u32_array (struct buffer *buf, const int type, const uint32_t *data, const unsigned int len, bool *error) +write_dhcp_u32_array(struct buffer *buf, const int type, const uint32_t *data, const unsigned int len, bool *error) { - if (len > 0) + if (len > 0) { - int i; - const int size = len * sizeof (uint32_t); + int i; + const int size = len * sizeof(uint32_t); - if (!buf_safe (buf, 2 + size)) - { - *error = true; - msg (M_WARN, "write_dhcp_u32_array: buffer overflow building DHCP options"); - return; - } - if (size < 1 || size > 255) - { - *error = true; - msg (M_WARN, "write_dhcp_u32_array: size (%d) must be > 0 and <= 255", size); - return; - } - buf_write_u8 (buf, type); - buf_write_u8 (buf, size); - for (i = 0; i < len; ++i) - buf_write_u32 (buf, data[i]); + if (!buf_safe(buf, 2 + size)) + { + *error = true; + msg(M_WARN, "write_dhcp_u32_array: buffer overflow building DHCP options"); + return; + } + if (size < 1 || size > 255) + { + *error = true; + msg(M_WARN, "write_dhcp_u32_array: size (%d) must be > 0 and <= 255", size); + return; + } + buf_write_u8(buf, type); + buf_write_u8(buf, size); + for (i = 0; i < len; ++i) + buf_write_u32(buf, data[i]); } } static void -write_dhcp_str (struct buffer *buf, const int type, const char *str, bool *error) +write_dhcp_str(struct buffer *buf, const int type, const char *str, bool *error) { - const int len = strlen (str); - if (!buf_safe (buf, 2 + len)) + const int len = strlen(str); + if (!buf_safe(buf, 2 + len)) { - *error = true; - msg (M_WARN, "write_dhcp_str: buffer overflow building DHCP options"); - return; + *error = true; + msg(M_WARN, "write_dhcp_str: buffer overflow building DHCP options"); + return; } - if (len < 1 || len > 255) + if (len < 1 || len > 255) { - *error = true; - msg (M_WARN, "write_dhcp_str: string '%s' must be > 0 bytes and <= 255 bytes", str); - return; + *error = true; + msg(M_WARN, "write_dhcp_str: string '%s' must be > 0 bytes and <= 255 bytes", str); + return; } - buf_write_u8 (buf, type); - buf_write_u8 (buf, len); - buf_write (buf, str, len); + buf_write_u8(buf, type); + buf_write_u8(buf, len); + buf_write(buf, str, len); } static bool -build_dhcp_options_string (struct buffer *buf, const struct tuntap_options *o) -{ - bool error = false; - if (o->domain) - write_dhcp_str (buf, 15, o->domain, &error); - - if (o->netbios_scope) - write_dhcp_str (buf, 47, o->netbios_scope, &error); - - if (o->netbios_node_type) - write_dhcp_u8 (buf, 46, o->netbios_node_type, &error); - - write_dhcp_u32_array (buf, 6, (uint32_t*)o->dns, o->dns_len, &error); - write_dhcp_u32_array (buf, 44, (uint32_t*)o->wins, o->wins_len, &error); - write_dhcp_u32_array (buf, 42, (uint32_t*)o->ntp, o->ntp_len, &error); - write_dhcp_u32_array (buf, 45, (uint32_t*)o->nbdd, o->nbdd_len, &error); - - /* the MS DHCP server option 'Disable Netbios-over-TCP/IP - is implemented as vendor option 001, value 002. - A value of 001 means 'leave NBT alone' which is the default */ - if (o->disable_nbt) - { - if (!buf_safe (buf, 8)) - { - msg (M_WARN, "build_dhcp_options_string: buffer overflow building DHCP options"); - return false; - } - buf_write_u8 (buf, 43); - buf_write_u8 (buf, 6); /* total length field */ - buf_write_u8 (buf, 0x001); - buf_write_u8 (buf, 4); /* length of the vendor specified field */ - buf_write_u32 (buf, 0x002); - } - return !error; +build_dhcp_options_string(struct buffer *buf, const struct tuntap_options *o) +{ + bool error = false; + if (o->domain) + { + write_dhcp_str(buf, 15, o->domain, &error); + } + + if (o->netbios_scope) + { + write_dhcp_str(buf, 47, o->netbios_scope, &error); + } + + if (o->netbios_node_type) + { + write_dhcp_u8(buf, 46, o->netbios_node_type, &error); + } + + write_dhcp_u32_array(buf, 6, (uint32_t *)o->dns, o->dns_len, &error); + write_dhcp_u32_array(buf, 44, (uint32_t *)o->wins, o->wins_len, &error); + write_dhcp_u32_array(buf, 42, (uint32_t *)o->ntp, o->ntp_len, &error); + write_dhcp_u32_array(buf, 45, (uint32_t *)o->nbdd, o->nbdd_len, &error); + + /* the MS DHCP server option 'Disable Netbios-over-TCP/IP + * is implemented as vendor option 001, value 002. + * A value of 001 means 'leave NBT alone' which is the default */ + if (o->disable_nbt) + { + if (!buf_safe(buf, 8)) + { + msg(M_WARN, "build_dhcp_options_string: buffer overflow building DHCP options"); + return false; + } + buf_write_u8(buf, 43); + buf_write_u8(buf, 6);/* total length field */ + buf_write_u8(buf, 0x001); + buf_write_u8(buf, 4);/* length of the vendor specified field */ + buf_write_u32(buf, 0x002); + } + return !error; } static void -fork_dhcp_action (struct tuntap *tt) +fork_dhcp_action(struct tuntap *tt) { - if (tt->options.dhcp_pre_release || tt->options.dhcp_renew) + if (tt->options.dhcp_pre_release || tt->options.dhcp_renew) { - struct gc_arena gc = gc_new (); - struct buffer cmd = alloc_buf_gc (256, &gc); - const int verb = 3; - const int pre_sleep = 1; - - buf_printf (&cmd, "openvpn --verb %d --tap-sleep %d", verb, pre_sleep); - if (tt->options.dhcp_pre_release) - buf_printf (&cmd, " --dhcp-pre-release"); - if (tt->options.dhcp_renew) - buf_printf (&cmd, " --dhcp-renew"); - buf_printf (&cmd, " --dhcp-internal %u", (unsigned int)tt->adapter_index); + struct gc_arena gc = gc_new(); + struct buffer cmd = alloc_buf_gc(256, &gc); + const int verb = 3; + const int pre_sleep = 1; + + buf_printf(&cmd, "openvpn --verb %d --tap-sleep %d", verb, pre_sleep); + if (tt->options.dhcp_pre_release) + { + buf_printf(&cmd, " --dhcp-pre-release"); + } + if (tt->options.dhcp_renew) + { + buf_printf(&cmd, " --dhcp-renew"); + } + buf_printf(&cmd, " --dhcp-internal %u", (unsigned int)tt->adapter_index); - fork_to_self (BSTR (&cmd)); - gc_free (&gc); + fork_to_self(BSTR(&cmd)); + gc_free(&gc); } } static void -register_dns_service (const struct tuntap *tt) +register_dns_service(const struct tuntap *tt) { - DWORD len; - HANDLE msg_channel = tt->options.msg_channel; - ack_message_t ack; - struct gc_arena gc = gc_new (); + DWORD len; + HANDLE msg_channel = tt->options.msg_channel; + ack_message_t ack; + struct gc_arena gc = gc_new(); - message_header_t rdns = { msg_register_dns, sizeof(message_header_t), 0 }; + message_header_t rdns = { msg_register_dns, sizeof(message_header_t), 0 }; - if (!WriteFile (msg_channel, &rdns, sizeof (rdns), &len, NULL) || - !ReadFile (msg_channel, &ack, sizeof (ack), &len, NULL)) + if (!WriteFile(msg_channel, &rdns, sizeof(rdns), &len, NULL) + || !ReadFile(msg_channel, &ack, sizeof(ack), &len, NULL)) { - msg (M_WARN, "Register_dns: could not talk to service: %s [status=0x%lx]", - strerror_win32 (GetLastError (), &gc), GetLastError ()); + msg(M_WARN, "Register_dns: could not talk to service: %s [status=0x%lx]", + strerror_win32(GetLastError(), &gc), GetLastError()); } - else if (ack.error_number != NO_ERROR) + else if (ack.error_number != NO_ERROR) { - msg (M_WARN, "Register_dns failed using service: %s [status=0x%x]", - strerror_win32 (ack.error_number, &gc), ack.error_number); + msg(M_WARN, "Register_dns failed using service: %s [status=0x%x]", + strerror_win32(ack.error_number, &gc), ack.error_number); } - else - msg (M_INFO, "Register_dns request sent to the service"); + else + { + msg(M_INFO, "Register_dns request sent to the service"); + } - gc_free (&gc); + gc_free(&gc); } void -fork_register_dns_action (struct tuntap *tt) +fork_register_dns_action(struct tuntap *tt) { - if (tt && tt->options.register_dns && tt->options.msg_channel) + if (tt && tt->options.register_dns && tt->options.msg_channel) { - register_dns_service (tt); + register_dns_service(tt); } - else if (tt && tt->options.register_dns) + else if (tt && tt->options.register_dns) { - struct gc_arena gc = gc_new (); - struct buffer cmd = alloc_buf_gc (256, &gc); - const int verb = 3; - - buf_printf (&cmd, "openvpn --verb %d --register-dns --rdns-internal", verb); - fork_to_self (BSTR (&cmd)); - gc_free (&gc); + struct gc_arena gc = gc_new(); + struct buffer cmd = alloc_buf_gc(256, &gc); + const int verb = 3; + + buf_printf(&cmd, "openvpn --verb %d --register-dns --rdns-internal", verb); + fork_to_self(BSTR(&cmd)); + gc_free(&gc); } } static uint32_t -dhcp_masq_addr (const in_addr_t local, const in_addr_t netmask, const int offset) +dhcp_masq_addr(const in_addr_t local, const in_addr_t netmask, const int offset) { - struct gc_arena gc = gc_new (); - in_addr_t dsa; /* DHCP server addr */ + struct gc_arena gc = gc_new(); + in_addr_t dsa; /* DHCP server addr */ - if (offset < 0) - dsa = (local | (~netmask)) + offset; - else - dsa = (local & netmask) + offset; + if (offset < 0) + { + dsa = (local | (~netmask)) + offset; + } + else + { + dsa = (local & netmask) + offset; + } - if (dsa == local) - msg (M_FATAL, "ERROR: There is a clash between the --ifconfig local address and the internal DHCP server address -- both are set to %s -- please use the --ip-win32 dynamic option to choose a different free address from the --ifconfig subnet for the internal DHCP server", print_in_addr_t (dsa, 0, &gc)); + if (dsa == local) + { + msg(M_FATAL, "ERROR: There is a clash between the --ifconfig local address and the internal DHCP server address -- both are set to %s -- please use the --ip-win32 dynamic option to choose a different free address from the --ifconfig subnet for the internal DHCP server", print_in_addr_t(dsa, 0, &gc)); + } - if ((local & netmask) != (dsa & netmask)) - msg (M_FATAL, "ERROR: --ip-win32 dynamic [offset] : offset is outside of --ifconfig subnet"); + if ((local & netmask) != (dsa & netmask)) + { + msg(M_FATAL, "ERROR: --ip-win32 dynamic [offset] : offset is outside of --ifconfig subnet"); + } - gc_free (&gc); - return htonl(dsa); + gc_free(&gc); + return htonl(dsa); } void -open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) +open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) { - struct gc_arena gc = gc_new (); - char device_path[256]; - const char *device_guid = NULL; - DWORD len; - bool dhcp_masq = false; - bool dhcp_masq_post = false; + struct gc_arena gc = gc_new(); + char device_path[256]; + const char *device_guid = NULL; + DWORD len; + bool dhcp_masq = false; + bool dhcp_masq_post = false; - /*netcmd_semaphore_lock ();*/ + /*netcmd_semaphore_lock ();*/ - msg( M_INFO, "open_tun"); + msg( M_INFO, "open_tun"); - if (tt->type == DEV_TYPE_NULL) + if (tt->type == DEV_TYPE_NULL) { - open_null (tt); - gc_free (&gc); - return; + open_null(tt); + gc_free(&gc); + return; } - else if (tt->type == DEV_TYPE_TAP || tt->type == DEV_TYPE_TUN) + else if (tt->type == DEV_TYPE_TAP || tt->type == DEV_TYPE_TUN) { - ; } - else + else { - msg (M_FATAL|M_NOPREFIX, "Unknown virtual device type: '%s'", dev); + msg(M_FATAL|M_NOPREFIX, "Unknown virtual device type: '%s'", dev); } - /* - * Lookup the device name in the registry, using the --dev-node high level name. - */ - { - const struct tap_reg *tap_reg = get_tap_reg (&gc); - const struct panel_reg *panel_reg = get_panel_reg (&gc); - char actual_buffer[256]; + /* + * Lookup the device name in the registry, using the --dev-node high level name. + */ + { + const struct tap_reg *tap_reg = get_tap_reg(&gc); + const struct panel_reg *panel_reg = get_panel_reg(&gc); + char actual_buffer[256]; - at_least_one_tap_win (tap_reg); + at_least_one_tap_win(tap_reg); - if (dev_node) - { - /* Get the device GUID for the device specified with --dev-node. */ - device_guid = get_device_guid (dev_node, actual_buffer, sizeof (actual_buffer), tap_reg, panel_reg, &gc); + if (dev_node) + { + /* Get the device GUID for the device specified with --dev-node. */ + device_guid = get_device_guid(dev_node, actual_buffer, sizeof(actual_buffer), tap_reg, panel_reg, &gc); - if (!device_guid) - msg (M_FATAL, "TAP-Windows adapter '%s' not found", dev_node); + if (!device_guid) + { + msg(M_FATAL, "TAP-Windows adapter '%s' not found", dev_node); + } - /* Open Windows TAP-Windows adapter */ - openvpn_snprintf (device_path, sizeof(device_path), "%s%s%s", - USERMODEDEVICEDIR, - device_guid, - TAP_WIN_SUFFIX); - - tt->hand = CreateFile ( - device_path, - GENERIC_READ | GENERIC_WRITE, - 0, /* was: FILE_SHARE_READ */ - 0, - OPEN_EXISTING, - FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, - 0 - ); - - if (tt->hand == INVALID_HANDLE_VALUE) - msg (M_ERR, "CreateFile failed on TAP device: %s", device_path); - } - else - { - int device_number = 0; + /* Open Windows TAP-Windows adapter */ + openvpn_snprintf(device_path, sizeof(device_path), "%s%s%s", + USERMODEDEVICEDIR, + device_guid, + TAP_WIN_SUFFIX); + + tt->hand = CreateFile( + device_path, + GENERIC_READ | GENERIC_WRITE, + 0, /* was: FILE_SHARE_READ */ + 0, + OPEN_EXISTING, + FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, + 0 + ); - /* Try opening all TAP devices until we find one available */ - while (true) - { - device_guid = get_unspecified_device_guid (device_number, - actual_buffer, - sizeof (actual_buffer), - tap_reg, - panel_reg, - &gc); + if (tt->hand == INVALID_HANDLE_VALUE) + { + msg(M_ERR, "CreateFile failed on TAP device: %s", device_path); + } + } + else + { + int device_number = 0; - if (!device_guid) - msg (M_FATAL, "All TAP-Windows adapters on this system are currently in use."); + /* Try opening all TAP devices until we find one available */ + while (true) + { + device_guid = get_unspecified_device_guid(device_number, + actual_buffer, + sizeof(actual_buffer), + tap_reg, + panel_reg, + &gc); + + if (!device_guid) + { + msg(M_FATAL, "All TAP-Windows adapters on this system are currently in use."); + } + + /* Open Windows TAP-Windows adapter */ + openvpn_snprintf(device_path, sizeof(device_path), "%s%s%s", + USERMODEDEVICEDIR, + device_guid, + TAP_WIN_SUFFIX); + + tt->hand = CreateFile( + device_path, + GENERIC_READ | GENERIC_WRITE, + 0, /* was: FILE_SHARE_READ */ + 0, + OPEN_EXISTING, + FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, + 0 + ); + + if (tt->hand == INVALID_HANDLE_VALUE) + { + msg(D_TUNTAP_INFO, "CreateFile failed on TAP device: %s", device_path); + } + else + { + break; + } + + device_number++; + } + } - /* Open Windows TAP-Windows adapter */ - openvpn_snprintf (device_path, sizeof(device_path), "%s%s%s", - USERMODEDEVICEDIR, - device_guid, - TAP_WIN_SUFFIX); - - tt->hand = CreateFile ( - device_path, - GENERIC_READ | GENERIC_WRITE, - 0, /* was: FILE_SHARE_READ */ - 0, - OPEN_EXISTING, - FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, - 0 - ); + /* translate high-level device name into a device instance + * GUID using the registry */ + tt->actual_name = string_alloc(actual_buffer, NULL); + } - if (tt->hand == INVALID_HANDLE_VALUE) - msg (D_TUNTAP_INFO, "CreateFile failed on TAP device: %s", device_path); - else - break; - - device_number++; - } - } - - /* translate high-level device name into a device instance - GUID using the registry */ - tt->actual_name = string_alloc (actual_buffer, NULL); - } - - msg (M_INFO, "TAP-WIN32 device [%s] opened: %s", tt->actual_name, device_path); - tt->adapter_index = get_adapter_index (device_guid); - - /* get driver version info */ - { - ULONG info[3]; - CLEAR (info); - if (DeviceIoControl (tt->hand, TAP_WIN_IOCTL_GET_VERSION, - &info, sizeof (info), - &info, sizeof (info), &len, NULL)) - { - msg (D_TUNTAP_INFO, "TAP-Windows Driver Version %d.%d %s", - (int) info[0], - (int) info[1], - (info[2] ? "(DEBUG)" : "")); - - } - if (!(info[0] == TAP_WIN_MIN_MAJOR && info[1] >= TAP_WIN_MIN_MINOR)) - msg (M_FATAL, "ERROR: This version of " PACKAGE_NAME " requires a TAP-Windows driver that is at least version %d.%d -- If you recently upgraded your " PACKAGE_NAME " distribution, a reboot is probably required at this point to get Windows to see the new driver.", - TAP_WIN_MIN_MAJOR, - TAP_WIN_MIN_MINOR); - - /* usage of numeric constants is ugly, but this is really tied to - * *this* version of the driver - */ - if (tt->type == DEV_TYPE_TUN && - info[0] == 9 && info[1] < 8) - { - msg( M_INFO, "WARNING: Tap-Win32 driver version %d.%d does not support IPv6 in TUN mode. IPv6 will not work. Upgrade your Tap-Win32 driver.", (int) info[0], (int) info[1] ); - } + msg(M_INFO, "TAP-WIN32 device [%s] opened: %s", tt->actual_name, device_path); + tt->adapter_index = get_adapter_index(device_guid); + + /* get driver version info */ + { + ULONG info[3]; + CLEAR(info); + if (DeviceIoControl(tt->hand, TAP_WIN_IOCTL_GET_VERSION, + &info, sizeof(info), + &info, sizeof(info), &len, NULL)) + { + msg(D_TUNTAP_INFO, "TAP-Windows Driver Version %d.%d %s", + (int) info[0], + (int) info[1], + (info[2] ? "(DEBUG)" : "")); + + } + if (!(info[0] == TAP_WIN_MIN_MAJOR && info[1] >= TAP_WIN_MIN_MINOR)) + { + msg(M_FATAL, "ERROR: This version of " PACKAGE_NAME " requires a TAP-Windows driver that is at least version %d.%d -- If you recently upgraded your " PACKAGE_NAME " distribution, a reboot is probably required at this point to get Windows to see the new driver.", + TAP_WIN_MIN_MAJOR, + TAP_WIN_MIN_MINOR); + } + + /* usage of numeric constants is ugly, but this is really tied to + * *this* version of the driver + */ + if (tt->type == DEV_TYPE_TUN + && info[0] == 9 && info[1] < 8) + { + msg( M_INFO, "WARNING: Tap-Win32 driver version %d.%d does not support IPv6 in TUN mode. IPv6 will not work. Upgrade your Tap-Win32 driver.", (int) info[0], (int) info[1] ); + } + + /* tap driver 9.8 (2.2.0 and 2.2.1 release) is buggy + */ + if (tt->type == DEV_TYPE_TUN + && info[0] == 9 && info[1] == 8) + { + msg( M_FATAL, "ERROR: Tap-Win32 driver version %d.%d is buggy regarding small IPv4 packets in TUN mode. Upgrade your Tap-Win32 driver.", (int) info[0], (int) info[1] ); + } + } + + /* get driver MTU */ + { + ULONG mtu; + if (DeviceIoControl(tt->hand, TAP_WIN_IOCTL_GET_MTU, + &mtu, sizeof(mtu), + &mtu, sizeof(mtu), &len, NULL)) + { + tt->post_open_mtu = (int) mtu; + msg(D_MTU_INFO, "TAP-Windows MTU=%d", (int) mtu); + } + } - /* tap driver 9.8 (2.2.0 and 2.2.1 release) is buggy + /* + * Preliminaries for setting TAP-Windows adapter TCP/IP + * properties via --ip-win32 dynamic or --ip-win32 adaptive. */ - if ( tt->type == DEV_TYPE_TUN && - info[0] == 9 && info[1] == 8) - { - msg( M_FATAL, "ERROR: Tap-Win32 driver version %d.%d is buggy regarding small IPv4 packets in TUN mode. Upgrade your Tap-Win32 driver.", (int) info[0], (int) info[1] ); - } - } - - /* get driver MTU */ - { - ULONG mtu; - if (DeviceIoControl (tt->hand, TAP_WIN_IOCTL_GET_MTU, - &mtu, sizeof (mtu), - &mtu, sizeof (mtu), &len, NULL)) - { - tt->post_open_mtu = (int) mtu; - msg (D_MTU_INFO, "TAP-Windows MTU=%d", (int) mtu); - } - } - - /* - * Preliminaries for setting TAP-Windows adapter TCP/IP - * properties via --ip-win32 dynamic or --ip-win32 adaptive. - */ - if (tt->did_ifconfig_setup) - { - if (tt->options.ip_win32_type == IPW32_SET_DHCP_MASQ) - { - /* - * If adapter is set to non-DHCP, set to DHCP mode. - */ - if (dhcp_status (tt->adapter_index) == DHCP_STATUS_DISABLED) - netsh_enable_dhcp (&tt->options, tt->actual_name); - dhcp_masq = true; - dhcp_masq_post = true; - } - else if (tt->options.ip_win32_type == IPW32_SET_ADAPTIVE) - { - /* - * If adapter is set to non-DHCP, use netsh right away. - */ - if (dhcp_status (tt->adapter_index) != DHCP_STATUS_ENABLED) - { - netsh_ifconfig (&tt->options, - tt->actual_name, - tt->local, - tt->adapter_netmask, - NI_TEST_FIRST|NI_IP_NETMASK|NI_OPTIONS); - } - else - { - dhcp_masq = true; - } - } - } - - /* set point-to-point mode if TUN device */ - - if (tt->type == DEV_TYPE_TUN) - { - if (!tt->did_ifconfig_setup) - { - msg (M_FATAL, "ERROR: --dev tun also requires --ifconfig"); - } - - if (tt->topology == TOP_SUBNET) - { - in_addr_t ep[3]; - BOOL status; - - ep[0] = htonl (tt->local); - ep[1] = htonl (tt->local & tt->remote_netmask); - ep[2] = htonl (tt->remote_netmask); - - status = DeviceIoControl (tt->hand, TAP_WIN_IOCTL_CONFIG_TUN, - ep, sizeof (ep), - ep, sizeof (ep), &len, NULL); - - msg (status ? M_INFO : M_FATAL, "Set TAP-Windows TUN subnet mode network/local/netmask = %s/%s/%s [%s]", - print_in_addr_t (ep[1], IA_NET_ORDER, &gc), - print_in_addr_t (ep[0], IA_NET_ORDER, &gc), - print_in_addr_t (ep[2], IA_NET_ORDER, &gc), - status ? "SUCCEEDED" : "FAILED"); - - } else { - - in_addr_t ep[2]; - ep[0] = htonl (tt->local); - ep[1] = htonl (tt->remote_netmask); - - if (!DeviceIoControl (tt->hand, TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT, - ep, sizeof (ep), - ep, sizeof (ep), &len, NULL)) - msg (M_FATAL, "ERROR: The TAP-Windows driver rejected a DeviceIoControl call to set Point-to-Point mode, which is required for --dev tun"); - } - } - - /* should we tell the TAP-Windows driver to masquerade as a DHCP server as a means - of setting the adapter address? */ - if (dhcp_masq) - { - uint32_t ep[4]; - - /* We will answer DHCP requests with a reply to set IP/subnet to these values */ - ep[0] = htonl (tt->local); - ep[1] = htonl (tt->adapter_netmask); - - /* At what IP address should the DHCP server masquerade at? */ - if (tt->type == DEV_TYPE_TUN) - { - if (tt->topology == TOP_SUBNET) - { - if (tt->options.dhcp_masq_custom_offset) - ep[2] = dhcp_masq_addr (tt->local, tt->remote_netmask, tt->options.dhcp_masq_offset); - else - ep[2] = dhcp_masq_addr (tt->local, tt->remote_netmask, -1); - } - else - ep[2] = htonl (tt->remote_netmask); - } - else - { - ASSERT (tt->type == DEV_TYPE_TAP); - ep[2] = dhcp_masq_addr (tt->local, tt->adapter_netmask, tt->options.dhcp_masq_custom_offset ? tt->options.dhcp_masq_offset : 0); - } - - /* lease time in seconds */ - ep[3] = (uint32_t) tt->options.dhcp_lease_time; - - ASSERT (ep[3] > 0); + if (tt->did_ifconfig_setup) + { + if (tt->options.ip_win32_type == IPW32_SET_DHCP_MASQ) + { + /* + * If adapter is set to non-DHCP, set to DHCP mode. + */ + if (dhcp_status(tt->adapter_index) == DHCP_STATUS_DISABLED) + { + netsh_enable_dhcp(&tt->options, tt->actual_name); + } + dhcp_masq = true; + dhcp_masq_post = true; + } + else if (tt->options.ip_win32_type == IPW32_SET_ADAPTIVE) + { + /* + * If adapter is set to non-DHCP, use netsh right away. + */ + if (dhcp_status(tt->adapter_index) != DHCP_STATUS_ENABLED) + { + netsh_ifconfig(&tt->options, + tt->actual_name, + tt->local, + tt->adapter_netmask, + NI_TEST_FIRST|NI_IP_NETMASK|NI_OPTIONS); + } + else + { + dhcp_masq = true; + } + } + } + + /* set point-to-point mode if TUN device */ + + if (tt->type == DEV_TYPE_TUN) + { + if (!tt->did_ifconfig_setup) + { + msg(M_FATAL, "ERROR: --dev tun also requires --ifconfig"); + } + + if (tt->topology == TOP_SUBNET) + { + in_addr_t ep[3]; + BOOL status; + + ep[0] = htonl(tt->local); + ep[1] = htonl(tt->local & tt->remote_netmask); + ep[2] = htonl(tt->remote_netmask); + + status = DeviceIoControl(tt->hand, TAP_WIN_IOCTL_CONFIG_TUN, + ep, sizeof(ep), + ep, sizeof(ep), &len, NULL); + + msg(status ? M_INFO : M_FATAL, "Set TAP-Windows TUN subnet mode network/local/netmask = %s/%s/%s [%s]", + print_in_addr_t(ep[1], IA_NET_ORDER, &gc), + print_in_addr_t(ep[0], IA_NET_ORDER, &gc), + print_in_addr_t(ep[2], IA_NET_ORDER, &gc), + status ? "SUCCEEDED" : "FAILED"); + + } + else + { + + in_addr_t ep[2]; + ep[0] = htonl(tt->local); + ep[1] = htonl(tt->remote_netmask); + + if (!DeviceIoControl(tt->hand, TAP_WIN_IOCTL_CONFIG_POINT_TO_POINT, + ep, sizeof(ep), + ep, sizeof(ep), &len, NULL)) + { + msg(M_FATAL, "ERROR: The TAP-Windows driver rejected a DeviceIoControl call to set Point-to-Point mode, which is required for --dev tun"); + } + } + } + + /* should we tell the TAP-Windows driver to masquerade as a DHCP server as a means + * of setting the adapter address? */ + if (dhcp_masq) + { + uint32_t ep[4]; + + /* We will answer DHCP requests with a reply to set IP/subnet to these values */ + ep[0] = htonl(tt->local); + ep[1] = htonl(tt->adapter_netmask); + + /* At what IP address should the DHCP server masquerade at? */ + if (tt->type == DEV_TYPE_TUN) + { + if (tt->topology == TOP_SUBNET) + { + if (tt->options.dhcp_masq_custom_offset) + { + ep[2] = dhcp_masq_addr(tt->local, tt->remote_netmask, tt->options.dhcp_masq_offset); + } + else + { + ep[2] = dhcp_masq_addr(tt->local, tt->remote_netmask, -1); + } + } + else + { + ep[2] = htonl(tt->remote_netmask); + } + } + else + { + ASSERT(tt->type == DEV_TYPE_TAP); + ep[2] = dhcp_masq_addr(tt->local, tt->adapter_netmask, tt->options.dhcp_masq_custom_offset ? tt->options.dhcp_masq_offset : 0); + } + + /* lease time in seconds */ + ep[3] = (uint32_t) tt->options.dhcp_lease_time; + + ASSERT(ep[3] > 0); #ifndef SIMULATE_DHCP_FAILED /* this code is disabled to simulate bad DHCP negotiation */ - if (!DeviceIoControl (tt->hand, TAP_WIN_IOCTL_CONFIG_DHCP_MASQ, - ep, sizeof (ep), - ep, sizeof (ep), &len, NULL)) - msg (M_FATAL, "ERROR: The TAP-Windows driver rejected a DeviceIoControl call to set TAP_WIN_IOCTL_CONFIG_DHCP_MASQ mode"); - - msg (M_INFO, "Notified TAP-Windows driver to set a DHCP IP/netmask of %s/%s on interface %s [DHCP-serv: %s, lease-time: %d]", - print_in_addr_t (tt->local, 0, &gc), - print_in_addr_t (tt->adapter_netmask, 0, &gc), - device_guid, - print_in_addr_t (ep[2], IA_NET_ORDER, &gc), - ep[3] - ); - - /* user-supplied DHCP options capability */ - if (tt->options.dhcp_options) - { - struct buffer buf = alloc_buf (256); - if (build_dhcp_options_string (&buf, &tt->options)) - { - msg (D_DHCP_OPT, "DHCP option string: %s", format_hex (BPTR (&buf), BLEN (&buf), 0, &gc)); - if (!DeviceIoControl (tt->hand, TAP_WIN_IOCTL_CONFIG_DHCP_SET_OPT, - BPTR (&buf), BLEN (&buf), - BPTR (&buf), BLEN (&buf), &len, NULL)) - msg (M_FATAL, "ERROR: The TAP-Windows driver rejected a TAP_WIN_IOCTL_CONFIG_DHCP_SET_OPT DeviceIoControl call"); - } - else - msg (M_WARN, "DHCP option string not set due to error"); - free_buf (&buf); - } -#endif + if (!DeviceIoControl(tt->hand, TAP_WIN_IOCTL_CONFIG_DHCP_MASQ, + ep, sizeof(ep), + ep, sizeof(ep), &len, NULL)) + { + msg(M_FATAL, "ERROR: The TAP-Windows driver rejected a DeviceIoControl call to set TAP_WIN_IOCTL_CONFIG_DHCP_MASQ mode"); + } + + msg(M_INFO, "Notified TAP-Windows driver to set a DHCP IP/netmask of %s/%s on interface %s [DHCP-serv: %s, lease-time: %d]", + print_in_addr_t(tt->local, 0, &gc), + print_in_addr_t(tt->adapter_netmask, 0, &gc), + device_guid, + print_in_addr_t(ep[2], IA_NET_ORDER, &gc), + ep[3] + ); + + /* user-supplied DHCP options capability */ + if (tt->options.dhcp_options) + { + struct buffer buf = alloc_buf(256); + if (build_dhcp_options_string(&buf, &tt->options)) + { + msg(D_DHCP_OPT, "DHCP option string: %s", format_hex(BPTR(&buf), BLEN(&buf), 0, &gc)); + if (!DeviceIoControl(tt->hand, TAP_WIN_IOCTL_CONFIG_DHCP_SET_OPT, + BPTR(&buf), BLEN(&buf), + BPTR(&buf), BLEN(&buf), &len, NULL)) + { + msg(M_FATAL, "ERROR: The TAP-Windows driver rejected a TAP_WIN_IOCTL_CONFIG_DHCP_SET_OPT DeviceIoControl call"); + } + } + else + { + msg(M_WARN, "DHCP option string not set due to error"); + } + free_buf(&buf); + } +#endif /* ifndef SIMULATE_DHCP_FAILED */ } - /* set driver media status to 'connected' */ - { - ULONG status = TRUE; - if (!DeviceIoControl (tt->hand, TAP_WIN_IOCTL_SET_MEDIA_STATUS, - &status, sizeof (status), - &status, sizeof (status), &len, NULL)) - msg (M_WARN, "WARNING: The TAP-Windows driver rejected a TAP_WIN_IOCTL_SET_MEDIA_STATUS DeviceIoControl call."); - } - - /* possible wait for adapter to come up */ - { - int s = tt->options.tap_sleep; - if (s > 0) - { - msg (M_INFO, "Sleeping for %d seconds...", s); - openvpn_sleep (s); - } - } - - /* possibly use IP Helper API to set IP address on adapter */ - { - const DWORD index = tt->adapter_index; - - /* flush arp cache */ - if (index != TUN_ADAPTER_INDEX_INVALID) - { - DWORD status = -1; - - if (tt->options.msg_channel) - { - ack_message_t ack; - flush_neighbors_message_t msg = { - .header = { - msg_flush_neighbors, - sizeof (flush_neighbors_message_t), - 0 }, - .family = AF_INET, - .iface = { .index = index, .name = "" } - }; - - if (!WriteFile (tt->options.msg_channel, &msg, sizeof (msg), &len, NULL) || - !ReadFile (tt->options.msg_channel, &ack, sizeof (ack), &len, NULL)) - msg (M_WARN, "TUN: could not talk to service: %s [%lu]", - strerror_win32 (GetLastError (), &gc), GetLastError ()); - - status = ack.error_number; - } + /* set driver media status to 'connected' */ + { + ULONG status = TRUE; + if (!DeviceIoControl(tt->hand, TAP_WIN_IOCTL_SET_MEDIA_STATUS, + &status, sizeof(status), + &status, sizeof(status), &len, NULL)) + { + msg(M_WARN, "WARNING: The TAP-Windows driver rejected a TAP_WIN_IOCTL_SET_MEDIA_STATUS DeviceIoControl call."); + } + } + + /* possible wait for adapter to come up */ + { + int s = tt->options.tap_sleep; + if (s > 0) + { + msg(M_INFO, "Sleeping for %d seconds...", s); + openvpn_sleep(s); + } + } + + /* possibly use IP Helper API to set IP address on adapter */ + { + const DWORD index = tt->adapter_index; + + /* flush arp cache */ + if (index != TUN_ADAPTER_INDEX_INVALID) + { + DWORD status = -1; + + if (tt->options.msg_channel) + { + ack_message_t ack; + flush_neighbors_message_t msg = { + .header = { + msg_flush_neighbors, + sizeof(flush_neighbors_message_t), + 0 + }, + .family = AF_INET, + .iface = { .index = index, .name = "" } + }; + + if (!WriteFile(tt->options.msg_channel, &msg, sizeof(msg), &len, NULL) + || !ReadFile(tt->options.msg_channel, &ack, sizeof(ack), &len, NULL)) + { + msg(M_WARN, "TUN: could not talk to service: %s [%lu]", + strerror_win32(GetLastError(), &gc), GetLastError()); + } + + status = ack.error_number; + } + else + { + status = FlushIpNetTable(index); + } + + if (status == NO_ERROR) + { + msg(M_INFO, "Successful ARP Flush on interface [%u] %s", + (unsigned int)index, + device_guid); + } + else if (status != -1) + { + msg(D_TUNTAP_INFO, "NOTE: FlushIpNetTable failed on interface [%u] %s (status=%u) : %s", + (unsigned int)index, + device_guid, + (unsigned int)status, + strerror_win32(status, &gc)); + } + } + + /* + * If the TAP-Windows driver is masquerading as a DHCP server + * make sure the TCP/IP properties for the adapter are + * set correctly. + */ + if (dhcp_masq_post) + { + /* check dhcp enable status */ + if (dhcp_status(index) == DHCP_STATUS_DISABLED) + { + msg(M_WARN, "WARNING: You have selected '--ip-win32 dynamic', which will not work unless the TAP-Windows TCP/IP properties are set to 'Obtain an IP address automatically'"); + } + + /* force an explicit DHCP lease renewal on TAP adapter? */ + if (tt->options.dhcp_pre_release) + { + dhcp_release(tt); + } + if (tt->options.dhcp_renew) + { + dhcp_renew(tt); + } + } else - status = FlushIpNetTable (index); - - if (status == NO_ERROR) - msg (M_INFO, "Successful ARP Flush on interface [%u] %s", - (unsigned int)index, - device_guid); - else if (status != -1) - msg (D_TUNTAP_INFO, "NOTE: FlushIpNetTable failed on interface [%u] %s (status=%u) : %s", - (unsigned int)index, - device_guid, - (unsigned int)status, - strerror_win32 (status, &gc)); - } + { + fork_dhcp_action(tt); + } - /* - * If the TAP-Windows driver is masquerading as a DHCP server - * make sure the TCP/IP properties for the adapter are - * set correctly. - */ - if (dhcp_masq_post) - { - /* check dhcp enable status */ - if (dhcp_status (index) == DHCP_STATUS_DISABLED) - msg (M_WARN, "WARNING: You have selected '--ip-win32 dynamic', which will not work unless the TAP-Windows TCP/IP properties are set to 'Obtain an IP address automatically'"); - - /* force an explicit DHCP lease renewal on TAP adapter? */ - if (tt->options.dhcp_pre_release) - dhcp_release (tt); - if (tt->options.dhcp_renew) - dhcp_renew (tt); - } - else - fork_dhcp_action (tt); - - if (tt->did_ifconfig_setup && tt->options.ip_win32_type == IPW32_SET_IPAPI) - { - DWORD status; - const char *error_suffix = "I am having trouble using the Windows 'IP helper API' to automatically set the IP address -- consider using other --ip-win32 methods (not 'ipapi')"; - - /* couldn't get adapter index */ - if (index == TUN_ADAPTER_INDEX_INVALID) - { - msg (M_FATAL, "ERROR: unable to get adapter index for interface %s -- %s", - device_guid, - error_suffix); - } - - /* check dhcp enable status */ - if (dhcp_status (index) == DHCP_STATUS_DISABLED) - msg (M_WARN, "NOTE: You have selected (explicitly or by default) '--ip-win32 ipapi', which has a better chance of working correctly if the TAP-Windows TCP/IP properties are set to 'Obtain an IP address automatically'"); - - /* delete previously added IP addresses which were not - correctly deleted */ - delete_temp_addresses (index); - - /* add a new IP address */ - if ((status = AddIPAddress (htonl(tt->local), - htonl(tt->adapter_netmask), - index, - &tt->ipapi_context, - &tt->ipapi_instance)) == NO_ERROR) - msg (M_INFO, "Succeeded in adding a temporary IP/netmask of %s/%s to interface %s using the Win32 IP Helper API", - print_in_addr_t (tt->local, 0, &gc), - print_in_addr_t (tt->adapter_netmask, 0, &gc), - device_guid - ); - else - msg (M_FATAL, "ERROR: AddIPAddress %s/%s failed on interface %s, index=%d, status=%u (windows error: '%s') -- %s", - print_in_addr_t (tt->local, 0, &gc), - print_in_addr_t (tt->adapter_netmask, 0, &gc), - device_guid, - (int)index, - (unsigned int)status, - strerror_win32 (status, &gc), - error_suffix); - tt->ipapi_context_defined = true; - } - } - /*netcmd_semaphore_release ();*/ - gc_free (&gc); + if (tt->did_ifconfig_setup && tt->options.ip_win32_type == IPW32_SET_IPAPI) + { + DWORD status; + const char *error_suffix = "I am having trouble using the Windows 'IP helper API' to automatically set the IP address -- consider using other --ip-win32 methods (not 'ipapi')"; + + /* couldn't get adapter index */ + if (index == TUN_ADAPTER_INDEX_INVALID) + { + msg(M_FATAL, "ERROR: unable to get adapter index for interface %s -- %s", + device_guid, + error_suffix); + } + + /* check dhcp enable status */ + if (dhcp_status(index) == DHCP_STATUS_DISABLED) + { + msg(M_WARN, "NOTE: You have selected (explicitly or by default) '--ip-win32 ipapi', which has a better chance of working correctly if the TAP-Windows TCP/IP properties are set to 'Obtain an IP address automatically'"); + } + + /* delete previously added IP addresses which were not + * correctly deleted */ + delete_temp_addresses(index); + + /* add a new IP address */ + if ((status = AddIPAddress(htonl(tt->local), + htonl(tt->adapter_netmask), + index, + &tt->ipapi_context, + &tt->ipapi_instance)) == NO_ERROR) + { + msg(M_INFO, "Succeeded in adding a temporary IP/netmask of %s/%s to interface %s using the Win32 IP Helper API", + print_in_addr_t(tt->local, 0, &gc), + print_in_addr_t(tt->adapter_netmask, 0, &gc), + device_guid + ); + } + else + { + msg(M_FATAL, "ERROR: AddIPAddress %s/%s failed on interface %s, index=%d, status=%u (windows error: '%s') -- %s", + print_in_addr_t(tt->local, 0, &gc), + print_in_addr_t(tt->adapter_netmask, 0, &gc), + device_guid, + (int)index, + (unsigned int)status, + strerror_win32(status, &gc), + error_suffix); + } + tt->ipapi_context_defined = true; + } + } + /*netcmd_semaphore_release ();*/ + gc_free(&gc); } const char * -tap_win_getinfo (const struct tuntap *tt, struct gc_arena *gc) +tap_win_getinfo(const struct tuntap *tt, struct gc_arena *gc) { - if (tt && tt->hand != NULL) + if (tt && tt->hand != NULL) { - struct buffer out = alloc_buf_gc (256, gc); - DWORD len; - if (DeviceIoControl (tt->hand, TAP_WIN_IOCTL_GET_INFO, - BSTR (&out), BCAP (&out), - BSTR (&out), BCAP (&out), - &len, NULL)) - { - return BSTR (&out); - } + struct buffer out = alloc_buf_gc(256, gc); + DWORD len; + if (DeviceIoControl(tt->hand, TAP_WIN_IOCTL_GET_INFO, + BSTR(&out), BCAP(&out), + BSTR(&out), BCAP(&out), + &len, NULL)) + { + return BSTR(&out); + } } - return NULL; + return NULL; } void -tun_show_debug (struct tuntap *tt) +tun_show_debug(struct tuntap *tt) { - if (tt && tt->hand != NULL) + if (tt && tt->hand != NULL) { - struct buffer out = alloc_buf (1024); - DWORD len; - while (DeviceIoControl (tt->hand, TAP_WIN_IOCTL_GET_LOG_LINE, - BSTR (&out), BCAP (&out), - BSTR (&out), BCAP (&out), - &len, NULL)) - { - msg (D_TAP_WIN_DEBUG, "TAP-Windows: %s", BSTR (&out)); - } - free_buf (&out); + struct buffer out = alloc_buf(1024); + DWORD len; + while (DeviceIoControl(tt->hand, TAP_WIN_IOCTL_GET_LOG_LINE, + BSTR(&out), BCAP(&out), + BSTR(&out), BCAP(&out), + &len, NULL)) + { + msg(D_TAP_WIN_DEBUG, "TAP-Windows: %s", BSTR(&out)); + } + free_buf(&out); } } void -close_tun (struct tuntap *tt) +close_tun(struct tuntap *tt) { - struct gc_arena gc = gc_new (); + struct gc_arena gc = gc_new(); - if (tt) + if (tt) { - if ( tt->did_ifconfig_ipv6_setup ) + if (tt->did_ifconfig_ipv6_setup) { - if (tt->options.msg_channel) + if (tt->options.msg_channel) { - do_address_service (false, AF_INET6, tt); - if (tt->options.dns6_len > 0) - do_dns6_service (false, tt); + do_address_service(false, AF_INET6, tt); + if (tt->options.dns6_len > 0) + { + do_dns6_service(false, tt); + } } - else + else { - const char *ifconfig_ipv6_local; - struct argv argv = argv_new (); - - /* remove route pointing to interface */ - delete_route_connected_v6_net(tt, NULL); - - /* "store=active" is needed in Windows 8(.1) to delete the - * address we added (pointed out by Cedric Tabary). - */ - - /* netsh interface ipv6 delete address \"%s\" %s */ - ifconfig_ipv6_local = print_in6_addr (tt->local_ipv6, 0, &gc); - argv_printf (&argv, - "%s%sc interface ipv6 delete address %s %s store=active", - get_win_sys_path(), - NETSH_PATH_SUFFIX, - tt->actual_name, - ifconfig_ipv6_local); - - netsh_command (&argv, 1, M_WARN); - - /* delete ipv6 dns servers if any were set */ - if (tt->options.dns6_len > 0) - { - argv_printf (&argv, - "%s%sc interface ipv6 delete dns %s all", - get_win_sys_path(), - NETSH_PATH_SUFFIX, - tt->actual_name); - netsh_command (&argv, 1, M_WARN); - } - argv_reset (&argv); + const char *ifconfig_ipv6_local; + struct argv argv = argv_new(); + + /* remove route pointing to interface */ + delete_route_connected_v6_net(tt, NULL); + + /* "store=active" is needed in Windows 8(.1) to delete the + * address we added (pointed out by Cedric Tabary). + */ + + /* netsh interface ipv6 delete address \"%s\" %s */ + ifconfig_ipv6_local = print_in6_addr(tt->local_ipv6, 0, &gc); + argv_printf(&argv, + "%s%sc interface ipv6 delete address %s %s store=active", + get_win_sys_path(), + NETSH_PATH_SUFFIX, + tt->actual_name, + ifconfig_ipv6_local); + + netsh_command(&argv, 1, M_WARN); + + /* delete ipv6 dns servers if any were set */ + if (tt->options.dns6_len > 0) + { + argv_printf(&argv, + "%s%sc interface ipv6 delete dns %s all", + get_win_sys_path(), + NETSH_PATH_SUFFIX, + tt->actual_name); + netsh_command(&argv, 1, M_WARN); + } + argv_reset(&argv); } - } + } #if 1 - if (tt->ipapi_context_defined) - { - DWORD status; - if ((status = DeleteIPAddress (tt->ipapi_context)) != NO_ERROR) - { - msg (M_WARN, "Warning: DeleteIPAddress[%u] failed on TAP-Windows adapter, status=%u : %s", - (unsigned int)tt->ipapi_context, - (unsigned int)status, - strerror_win32 (status, &gc)); - } - } + if (tt->ipapi_context_defined) + { + DWORD status; + if ((status = DeleteIPAddress(tt->ipapi_context)) != NO_ERROR) + { + msg(M_WARN, "Warning: DeleteIPAddress[%u] failed on TAP-Windows adapter, status=%u : %s", + (unsigned int)tt->ipapi_context, + (unsigned int)status, + strerror_win32(status, &gc)); + } + } #endif - if (tt->options.dhcp_release) - dhcp_release (tt); + if (tt->options.dhcp_release) + { + dhcp_release(tt); + } - if (tt->hand != NULL) - { - dmsg (D_WIN32_IO_LOW, "Attempting CancelIO on TAP-Windows adapter"); - if (!CancelIo (tt->hand)) - msg (M_WARN | M_ERRNO, "Warning: CancelIO failed on TAP-Windows adapter"); - } + if (tt->hand != NULL) + { + dmsg(D_WIN32_IO_LOW, "Attempting CancelIO on TAP-Windows adapter"); + if (!CancelIo(tt->hand)) + { + msg(M_WARN | M_ERRNO, "Warning: CancelIO failed on TAP-Windows adapter"); + } + } - dmsg (D_WIN32_IO_LOW, "Attempting close of overlapped read event on TAP-Windows adapter"); - overlapped_io_close (&tt->reads); + dmsg(D_WIN32_IO_LOW, "Attempting close of overlapped read event on TAP-Windows adapter"); + overlapped_io_close(&tt->reads); - dmsg (D_WIN32_IO_LOW, "Attempting close of overlapped write event on TAP-Windows adapter"); - overlapped_io_close (&tt->writes); + dmsg(D_WIN32_IO_LOW, "Attempting close of overlapped write event on TAP-Windows adapter"); + overlapped_io_close(&tt->writes); - if (tt->hand != NULL) - { - dmsg (D_WIN32_IO_LOW, "Attempting CloseHandle on TAP-Windows adapter"); - if (!CloseHandle (tt->hand)) - msg (M_WARN | M_ERRNO, "Warning: CloseHandle failed on TAP-Windows adapter"); - } + if (tt->hand != NULL) + { + dmsg(D_WIN32_IO_LOW, "Attempting CloseHandle on TAP-Windows adapter"); + if (!CloseHandle(tt->hand)) + { + msg(M_WARN | M_ERRNO, "Warning: CloseHandle failed on TAP-Windows adapter"); + } + } - if (tt->actual_name) - free (tt->actual_name); + if (tt->actual_name) + { + free(tt->actual_name); + } - clear_tuntap (tt); - free (tt); + clear_tuntap(tt); + free(tt); } - gc_free (&gc); + gc_free(&gc); } /* @@ -5740,83 +6269,91 @@ close_tun (struct tuntap *tt) */ struct ipset_names { - const char *short_form; + const char *short_form; }; /* Indexed by IPW32_SET_x */ static const struct ipset_names ipset_names[] = { - {"manual"}, - {"netsh"}, - {"ipapi"}, - {"dynamic"}, - {"adaptive"} + {"manual"}, + {"netsh"}, + {"ipapi"}, + {"dynamic"}, + {"adaptive"} }; int -ascii2ipset (const char* name) +ascii2ipset(const char *name) { - int i; - ASSERT (IPW32_SET_N == SIZE (ipset_names)); - for (i = 0; i < IPW32_SET_N; ++i) - if (!strcmp (name, ipset_names[i].short_form)) - return i; - return -1; + int i; + ASSERT(IPW32_SET_N == SIZE(ipset_names)); + for (i = 0; i < IPW32_SET_N; ++i) + if (!strcmp(name, ipset_names[i].short_form)) + { + return i; + } + return -1; } const char * -ipset2ascii (int index) +ipset2ascii(int index) { - ASSERT (IPW32_SET_N == SIZE (ipset_names)); - if (index < 0 || index >= IPW32_SET_N) - return "[unknown --ip-win32 type]"; - else - return ipset_names[index].short_form; + ASSERT(IPW32_SET_N == SIZE(ipset_names)); + if (index < 0 || index >= IPW32_SET_N) + { + return "[unknown --ip-win32 type]"; + } + else + { + return ipset_names[index].short_form; + } } const char * -ipset2ascii_all (struct gc_arena *gc) +ipset2ascii_all(struct gc_arena *gc) { - struct buffer out = alloc_buf_gc (256, gc); - int i; + struct buffer out = alloc_buf_gc(256, gc); + int i; - ASSERT (IPW32_SET_N == SIZE (ipset_names)); - for (i = 0; i < IPW32_SET_N; ++i) + ASSERT(IPW32_SET_N == SIZE(ipset_names)); + for (i = 0; i < IPW32_SET_N; ++i) { - if (i) - buf_printf(&out, " "); - buf_printf(&out, "[%s]", ipset2ascii(i)); + if (i) + { + buf_printf(&out, " "); + } + buf_printf(&out, "[%s]", ipset2ascii(i)); } - return BSTR (&out); + return BSTR(&out); } #else /* generic */ void -open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) +open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) { - open_tun_generic (dev, dev_type, dev_node, true, tt); + open_tun_generic(dev, dev_type, dev_node, true, tt); } void -close_tun (struct tuntap* tt) +close_tun(struct tuntap *tt) { - if (tt) + if (tt) { - close_tun_generic (tt); - free (tt); + close_tun_generic(tt); + free(tt); } } int -write_tun (struct tuntap* tt, uint8_t *buf, int len) +write_tun(struct tuntap *tt, uint8_t *buf, int len) { - return write (tt->fd, buf, len); + return write(tt->fd, buf, len); } int -read_tun (struct tuntap* tt, uint8_t *buf, int len) +read_tun(struct tuntap *tt, uint8_t *buf, int len) { - return read (tt->fd, buf, len); + return read(tt->fd, buf, len); } -#endif +#endif /* if defined (TARGET_ANDROID) */ diff --git a/src/openvpn/tun.h b/src/openvpn/tun.h index 9b5a1b7cca6..bc499bfa9ea 100644 --- a/src/openvpn/tun.h +++ b/src/openvpn/tun.h @@ -47,84 +47,84 @@ #define IPW32_SET_ADAPTIVE_TRY_NETSH 20 struct tuntap_options { - /* --ip-win32 options */ - bool ip_win32_defined; + /* --ip-win32 options */ + bool ip_win32_defined; -# define IPW32_SET_MANUAL 0 /* "--ip-win32 manual" */ -# define IPW32_SET_NETSH 1 /* "--ip-win32 netsh" */ -# define IPW32_SET_IPAPI 2 /* "--ip-win32 ipapi" */ -# define IPW32_SET_DHCP_MASQ 3 /* "--ip-win32 dynamic" */ -# define IPW32_SET_ADAPTIVE 4 /* "--ip-win32 adaptive" */ -# define IPW32_SET_N 5 - int ip_win32_type; +#define IPW32_SET_MANUAL 0 /* "--ip-win32 manual" */ +#define IPW32_SET_NETSH 1 /* "--ip-win32 netsh" */ +#define IPW32_SET_IPAPI 2 /* "--ip-win32 ipapi" */ +#define IPW32_SET_DHCP_MASQ 3 /* "--ip-win32 dynamic" */ +#define IPW32_SET_ADAPTIVE 4 /* "--ip-win32 adaptive" */ +#define IPW32_SET_N 5 + int ip_win32_type; #ifdef _WIN32 - HANDLE msg_channel; + HANDLE msg_channel; #endif - /* --ip-win32 dynamic options */ - bool dhcp_masq_custom_offset; - int dhcp_masq_offset; - int dhcp_lease_time; + /* --ip-win32 dynamic options */ + bool dhcp_masq_custom_offset; + int dhcp_masq_offset; + int dhcp_lease_time; - /* --tap-sleep option */ - int tap_sleep; + /* --tap-sleep option */ + int tap_sleep; - /* --dhcp-option options */ + /* --dhcp-option options */ - bool dhcp_options; + bool dhcp_options; - const char *domain; /* DOMAIN (15) */ + const char *domain; /* DOMAIN (15) */ - const char *netbios_scope; /* NBS (47) */ + const char *netbios_scope; /* NBS (47) */ - int netbios_node_type; /* NBT 1,2,4,8 (46) */ + int netbios_node_type; /* NBT 1,2,4,8 (46) */ #define N_DHCP_ADDR 4 /* Max # of addresses allowed for - DNS, WINS, etc. */ + * DNS, WINS, etc. */ - /* DNS (6) */ - in_addr_t dns[N_DHCP_ADDR]; - int dns_len; + /* DNS (6) */ + in_addr_t dns[N_DHCP_ADDR]; + int dns_len; - /* WINS (44) */ - in_addr_t wins[N_DHCP_ADDR]; - int wins_len; + /* WINS (44) */ + in_addr_t wins[N_DHCP_ADDR]; + int wins_len; - /* NTP (42) */ - in_addr_t ntp[N_DHCP_ADDR]; - int ntp_len; + /* NTP (42) */ + in_addr_t ntp[N_DHCP_ADDR]; + int ntp_len; - /* NBDD (45) */ - in_addr_t nbdd[N_DHCP_ADDR]; - int nbdd_len; + /* NBDD (45) */ + in_addr_t nbdd[N_DHCP_ADDR]; + int nbdd_len; - /* DISABLE_NBT (43, Vendor option 001) */ - bool disable_nbt; + /* DISABLE_NBT (43, Vendor option 001) */ + bool disable_nbt; - bool dhcp_renew; - bool dhcp_pre_release; - bool dhcp_release; + bool dhcp_renew; + bool dhcp_pre_release; + bool dhcp_release; - bool register_dns; + bool register_dns; - struct in6_addr dns6[N_DHCP_ADDR]; - int dns6_len; + struct in6_addr dns6[N_DHCP_ADDR]; + int dns6_len; }; #elif TARGET_LINUX struct tuntap_options { - int txqueuelen; + int txqueuelen; }; -#else +#else /* if defined(_WIN32) || defined(TARGET_ANDROID) */ struct tuntap_options { - int dummy; /* not used */ + int dummy; /* not used */ }; -#endif +#endif /* if defined(_WIN32) || defined(TARGET_ANDROID) */ /* * Define a TUN/TAP dev. @@ -132,78 +132,78 @@ struct tuntap_options { struct tuntap { -# define TUNNEL_TYPE(tt) ((tt) ? ((tt)->type) : DEV_TYPE_UNDEF) - int type; /* DEV_TYPE_x as defined in proto.h */ +#define TUNNEL_TYPE(tt) ((tt) ? ((tt)->type) : DEV_TYPE_UNDEF) + int type; /* DEV_TYPE_x as defined in proto.h */ -# define TUNNEL_TOPOLOGY(tt) ((tt) ? ((tt)->topology) : TOP_UNDEF) - int topology; /* one of the TOP_x values */ +#define TUNNEL_TOPOLOGY(tt) ((tt) ? ((tt)->topology) : TOP_UNDEF) + int topology; /* one of the TOP_x values */ - bool did_ifconfig_setup; - bool did_ifconfig_ipv6_setup; - bool did_ifconfig; + bool did_ifconfig_setup; + bool did_ifconfig_ipv6_setup; + bool did_ifconfig; - bool persistent_if; /* if existed before, keep on program end */ + bool persistent_if; /* if existed before, keep on program end */ - struct tuntap_options options; /* options set on command line */ + struct tuntap_options options; /* options set on command line */ - char *actual_name; /* actual name of TUN/TAP dev, usually including unit number */ + char *actual_name; /* actual name of TUN/TAP dev, usually including unit number */ - /* number of TX buffers */ - int txqueuelen; + /* number of TX buffers */ + int txqueuelen; - /* ifconfig parameters */ - in_addr_t local; - in_addr_t remote_netmask; - in_addr_t broadcast; + /* ifconfig parameters */ + in_addr_t local; + in_addr_t remote_netmask; + in_addr_t broadcast; - struct in6_addr local_ipv6; - struct in6_addr remote_ipv6; - int netbits_ipv6; + struct in6_addr local_ipv6; + struct in6_addr remote_ipv6; + int netbits_ipv6; #ifdef _WIN32 - HANDLE hand; - struct overlapped_io reads; - struct overlapped_io writes; - struct rw_handle rw_handle; - - /* used for setting interface address via IP Helper API - or DHCP masquerade */ - bool ipapi_context_defined; - ULONG ipapi_context; - ULONG ipapi_instance; - in_addr_t adapter_netmask; - - /* Windows adapter index for TAP-Windows adapter, - ~0 if undefined */ - DWORD adapter_index; - - int standby_iter; -#else - int fd; /* file descriptor for TUN/TAP dev */ + HANDLE hand; + struct overlapped_io reads; + struct overlapped_io writes; + struct rw_handle rw_handle; + + /* used for setting interface address via IP Helper API + * or DHCP masquerade */ + bool ipapi_context_defined; + ULONG ipapi_context; + ULONG ipapi_instance; + in_addr_t adapter_netmask; + + /* Windows adapter index for TAP-Windows adapter, + * ~0 if undefined */ + DWORD adapter_index; + + int standby_iter; +#else /* ifdef _WIN32 */ + int fd; /* file descriptor for TUN/TAP dev */ #endif #ifdef TARGET_SOLARIS - int ip_fd; + int ip_fd; #endif #ifdef HAVE_NET_IF_UTUN_H - bool is_utun; + bool is_utun; #endif - /* used for printing status info only */ - unsigned int rwflags_debug; + /* used for printing status info only */ + unsigned int rwflags_debug; - /* Some TUN/TAP drivers like to be ioctled for mtu - after open */ - int post_open_mtu; + /* Some TUN/TAP drivers like to be ioctled for mtu + * after open */ + int post_open_mtu; }; static inline bool -tuntap_defined (const struct tuntap *tt) +tuntap_defined(const struct tuntap *tt) { #ifdef _WIN32 - return tt && tt->hand != NULL; + return tt && tt->hand != NULL; #else - return tt && tt->fd >= 0; + return tt && tt->fd >= 0; #endif } @@ -211,71 +211,73 @@ tuntap_defined (const struct tuntap *tt) * Function prototypes */ -void open_tun (const char *dev, const char *dev_type, const char *dev_node, - struct tuntap *tt); +void open_tun(const char *dev, const char *dev_type, const char *dev_node, + struct tuntap *tt); -void close_tun (struct tuntap *tt); +void close_tun(struct tuntap *tt); -int write_tun (struct tuntap* tt, uint8_t *buf, int len); +int write_tun(struct tuntap *tt, uint8_t *buf, int len); -int read_tun (struct tuntap* tt, uint8_t *buf, int len); +int read_tun(struct tuntap *tt, uint8_t *buf, int len); -void tuncfg (const char *dev, const char *dev_type, const char *dev_node, - int persist_mode, const char *username, - const char *groupname, const struct tuntap_options *options); +void tuncfg(const char *dev, const char *dev_type, const char *dev_node, + int persist_mode, const char *username, + const char *groupname, const struct tuntap_options *options); -const char *guess_tuntap_dev (const char *dev, - const char *dev_type, - const char *dev_node, - struct gc_arena *gc); +const char *guess_tuntap_dev(const char *dev, + const char *dev_type, + const char *dev_node, + struct gc_arena *gc); -struct tuntap *init_tun (const char *dev, /* --dev option */ - const char *dev_type, /* --dev-type option */ - int topology, /* one of the TOP_x values */ - const char *ifconfig_local_parm, /* --ifconfig parm 1 */ - const char *ifconfig_remote_netmask_parm, /* --ifconfig parm 2 */ - const char *ifconfig_ipv6_local_parm, /* --ifconfig parm 1 / IPv6 */ - int ifconfig_ipv6_netbits_parm, /* --ifconfig parm 1 / bits */ - const char *ifconfig_ipv6_remote_parm, /* --ifconfig parm 2 / IPv6 */ - struct addrinfo *local_public, - struct addrinfo *remote_public, - const bool strict_warn, - struct env_set *es); +struct tuntap *init_tun(const char *dev, /* --dev option */ + const char *dev_type, /* --dev-type option */ + int topology, /* one of the TOP_x values */ + const char *ifconfig_local_parm, /* --ifconfig parm 1 */ + const char *ifconfig_remote_netmask_parm, /* --ifconfig parm 2 */ + const char *ifconfig_ipv6_local_parm, /* --ifconfig parm 1 / IPv6 */ + int ifconfig_ipv6_netbits_parm, /* --ifconfig parm 1 / bits */ + const char *ifconfig_ipv6_remote_parm, /* --ifconfig parm 2 / IPv6 */ + struct addrinfo *local_public, + struct addrinfo *remote_public, + const bool strict_warn, + struct env_set *es); -void init_tun_post (struct tuntap *tt, - const struct frame *frame, - const struct tuntap_options *options); +void init_tun_post(struct tuntap *tt, + const struct frame *frame, + const struct tuntap_options *options); -void do_ifconfig_setenv (const struct tuntap *tt, - struct env_set *es); +void do_ifconfig_setenv(const struct tuntap *tt, + struct env_set *es); -void do_ifconfig (struct tuntap *tt, - const char *actual, /* actual device name */ - int tun_mtu, - const struct env_set *es); +void do_ifconfig(struct tuntap *tt, + const char *actual, /* actual device name */ + int tun_mtu, + const struct env_set *es); -bool is_dev_type (const char *dev, const char *dev_type, const char *match_type); -int dev_type_enum (const char *dev, const char *dev_type); -const char *dev_type_string (const char *dev, const char *dev_type); +bool is_dev_type(const char *dev, const char *dev_type, const char *match_type); -const char *ifconfig_options_string (const struct tuntap* tt, bool remote, bool disable, struct gc_arena *gc); +int dev_type_enum(const char *dev, const char *dev_type); -bool is_tun_p2p (const struct tuntap *tt); +const char *dev_type_string(const char *dev, const char *dev_type); -void check_subnet_conflict (const in_addr_t ip, - const in_addr_t netmask, - const char *prefix); +const char *ifconfig_options_string(const struct tuntap *tt, bool remote, bool disable, struct gc_arena *gc); -void warn_on_use_of_common_subnets (void); +bool is_tun_p2p(const struct tuntap *tt); + +void check_subnet_conflict(const in_addr_t ip, + const in_addr_t netmask, + const char *prefix); + +void warn_on_use_of_common_subnets(void); /* * Inline functions */ static inline void -tun_adjust_frame_parameters (struct frame* frame, int size) +tun_adjust_frame_parameters(struct frame *frame, int size) { - frame_add_to_extra_tun (frame, size); + frame_add_to_extra_tun(frame, size); } /* @@ -292,21 +294,21 @@ static inline int ifconfig_order(void) { #if defined(TARGET_LINUX) - return IFCONFIG_AFTER_TUN_OPEN; + return IFCONFIG_AFTER_TUN_OPEN; #elif defined(TARGET_SOLARIS) - return IFCONFIG_AFTER_TUN_OPEN; + return IFCONFIG_AFTER_TUN_OPEN; #elif defined(TARGET_OPENBSD) - return IFCONFIG_AFTER_TUN_OPEN; + return IFCONFIG_AFTER_TUN_OPEN; #elif defined(TARGET_DARWIN) - return IFCONFIG_AFTER_TUN_OPEN; + return IFCONFIG_AFTER_TUN_OPEN; #elif defined(TARGET_NETBSD) - return IFCONFIG_AFTER_TUN_OPEN; + return IFCONFIG_AFTER_TUN_OPEN; #elif defined(_WIN32) - return IFCONFIG_AFTER_TUN_OPEN; + return IFCONFIG_AFTER_TUN_OPEN; #elif defined(TARGET_ANDROID) - return IFCONFIG_BEFORE_TUN_OPEN; -#else - return IFCONFIG_DEFAULT; + return IFCONFIG_BEFORE_TUN_OPEN; +#else /* if defined(TARGET_LINUX) */ + return IFCONFIG_DEFAULT; #endif } @@ -331,186 +333,208 @@ route_order(void) struct tap_reg { - const char *guid; - struct tap_reg *next; + const char *guid; + struct tap_reg *next; }; struct panel_reg { - const char *name; - const char *guid; - struct panel_reg *next; + const char *name; + const char *guid; + struct panel_reg *next; }; -int ascii2ipset (const char* name); -const char *ipset2ascii (int index); -const char *ipset2ascii_all (struct gc_arena *gc); +int ascii2ipset(const char *name); + +const char *ipset2ascii(int index); + +const char *ipset2ascii_all(struct gc_arena *gc); + +void verify_255_255_255_252(in_addr_t local, in_addr_t remote); + +const IP_ADAPTER_INFO *get_adapter_info_list(struct gc_arena *gc); + +const IP_ADAPTER_INFO *get_tun_adapter(const struct tuntap *tt, const IP_ADAPTER_INFO *list); + +const IP_ADAPTER_INFO *get_adapter_info(DWORD index, struct gc_arena *gc); -void verify_255_255_255_252 (in_addr_t local, in_addr_t remote); +const IP_PER_ADAPTER_INFO *get_per_adapter_info(const DWORD index, struct gc_arena *gc); -const IP_ADAPTER_INFO *get_adapter_info_list (struct gc_arena *gc); -const IP_ADAPTER_INFO *get_tun_adapter (const struct tuntap *tt, const IP_ADAPTER_INFO *list); +const IP_ADAPTER_INFO *get_adapter(const IP_ADAPTER_INFO *ai, DWORD index); -const IP_ADAPTER_INFO *get_adapter_info (DWORD index, struct gc_arena *gc); -const IP_PER_ADAPTER_INFO *get_per_adapter_info (const DWORD index, struct gc_arena *gc); -const IP_ADAPTER_INFO *get_adapter (const IP_ADAPTER_INFO *ai, DWORD index); +bool is_adapter_up(const struct tuntap *tt, const IP_ADAPTER_INFO *list); -bool is_adapter_up (const struct tuntap *tt, const IP_ADAPTER_INFO *list); -bool is_ip_in_adapter_subnet (const IP_ADAPTER_INFO *ai, const in_addr_t ip, in_addr_t *highest_netmask); +bool is_ip_in_adapter_subnet(const IP_ADAPTER_INFO *ai, const in_addr_t ip, in_addr_t *highest_netmask); -DWORD adapter_index_of_ip (const IP_ADAPTER_INFO *list, - const in_addr_t ip, - int *count, - in_addr_t *netmask); +DWORD adapter_index_of_ip(const IP_ADAPTER_INFO *list, + const in_addr_t ip, + int *count, + in_addr_t *netmask); -void show_tap_win_adapters (int msglev, int warnlev); -void show_adapters (int msglev); +void show_tap_win_adapters(int msglev, int warnlev); -void tap_allow_nonadmin_access (const char *dev_node); +void show_adapters(int msglev); -void show_valid_win32_tun_subnets (void); -const char *tap_win_getinfo (const struct tuntap *tt, struct gc_arena *gc); -void tun_show_debug (struct tuntap *tt); +void tap_allow_nonadmin_access(const char *dev_node); + +void show_valid_win32_tun_subnets(void); + +const char *tap_win_getinfo(const struct tuntap *tt, struct gc_arena *gc); + +void tun_show_debug(struct tuntap *tt); bool dhcp_release_by_adapter_index(const DWORD adapter_index); -bool dhcp_renew_by_adapter_index (const DWORD adapter_index); -void fork_register_dns_action (struct tuntap *tt); -void ipconfig_register_dns (const struct env_set *es); +bool dhcp_renew_by_adapter_index(const DWORD adapter_index); + +void fork_register_dns_action(struct tuntap *tt); + +void ipconfig_register_dns(const struct env_set *es); + +void tun_standby_init(struct tuntap *tt); -void tun_standby_init (struct tuntap *tt); -bool tun_standby (struct tuntap *tt); +bool tun_standby(struct tuntap *tt); -int tun_read_queue (struct tuntap *tt, int maxsize); -int tun_write_queue (struct tuntap *tt, struct buffer *buf); -int tun_finalize (HANDLE h, struct overlapped_io *io, struct buffer *buf); +int tun_read_queue(struct tuntap *tt, int maxsize); + +int tun_write_queue(struct tuntap *tt, struct buffer *buf); + +int tun_finalize(HANDLE h, struct overlapped_io *io, struct buffer *buf); static inline bool -tuntap_stop (int status) +tuntap_stop(int status) { - /* - * This corresponds to the STATUS_NO_SUCH_DEVICE - * error in tapdrvr.c. - */ - if (status < 0) + /* + * This corresponds to the STATUS_NO_SUCH_DEVICE + * error in tapdrvr.c. + */ + if (status < 0) { - return openvpn_errno () == ERROR_FILE_NOT_FOUND; + return openvpn_errno() == ERROR_FILE_NOT_FOUND; } - return false; + return false; } static inline bool tuntap_abort(int status) { - /* - * Typically generated when driver is halted. - */ - if (status < 0) + /* + * Typically generated when driver is halted. + */ + if (status < 0) { - return openvpn_errno() == ERROR_OPERATION_ABORTED; + return openvpn_errno() == ERROR_OPERATION_ABORTED; } - return false; + return false; } static inline int -tun_write_win32 (struct tuntap *tt, struct buffer *buf) +tun_write_win32(struct tuntap *tt, struct buffer *buf) { - int err = 0; - int status = 0; - if (overlapped_io_active (&tt->writes)) + int err = 0; + int status = 0; + if (overlapped_io_active(&tt->writes)) + { + status = tun_finalize(tt->hand, &tt->writes, NULL); + if (status < 0) + { + err = GetLastError(); + } + } + tun_write_queue(tt, buf); + if (status < 0) { - status = tun_finalize (tt->hand, &tt->writes, NULL); - if (status < 0) - err = GetLastError (); + SetLastError(err); + return status; } - tun_write_queue (tt, buf); - if (status < 0) + else { - SetLastError (err); - return status; + return BLEN(buf); } - else - return BLEN (buf); } static inline int -read_tun_buffered (struct tuntap *tt, struct buffer *buf, int maxsize) +read_tun_buffered(struct tuntap *tt, struct buffer *buf, int maxsize) { - return tun_finalize (tt->hand, &tt->reads, buf); + return tun_finalize(tt->hand, &tt->reads, buf); } static inline int -write_tun_buffered (struct tuntap *tt, struct buffer *buf) +write_tun_buffered(struct tuntap *tt, struct buffer *buf) { - return tun_write_win32 (tt, buf); + return tun_write_win32(tt, buf); } -#else +#else /* ifdef _WIN32 */ static inline bool -tuntap_stop (int status) +tuntap_stop(int status) { - return false; + return false; } static inline bool tuntap_abort(int status) { - return false; + return false; } static inline void -tun_standby_init (struct tuntap *tt) +tun_standby_init(struct tuntap *tt) { } static inline bool -tun_standby (struct tuntap *tt) +tun_standby(struct tuntap *tt) { - return true; + return true; } -#endif +#endif /* ifdef _WIN32 */ /* * TUN/TAP I/O wait functions */ static inline event_t -tun_event_handle (const struct tuntap *tt) +tun_event_handle(const struct tuntap *tt) { #ifdef _WIN32 - return &tt->rw_handle; + return &tt->rw_handle; #else - return tt->fd; + return tt->fd; #endif } static inline unsigned int -tun_set (struct tuntap *tt, - struct event_set *es, - unsigned int rwflags, - void *arg, - unsigned int *persistent) +tun_set(struct tuntap *tt, + struct event_set *es, + unsigned int rwflags, + void *arg, + unsigned int *persistent) { - if (tuntap_defined (tt)) + if (tuntap_defined(tt)) { - /* if persistent is defined, call event_ctl only if rwflags has changed since last call */ - if (!persistent || *persistent != rwflags) - { - event_ctl (es, tun_event_handle (tt), rwflags, arg); - if (persistent) - *persistent = rwflags; - } + /* if persistent is defined, call event_ctl only if rwflags has changed since last call */ + if (!persistent || *persistent != rwflags) + { + event_ctl(es, tun_event_handle(tt), rwflags, arg); + if (persistent) + { + *persistent = rwflags; + } + } #ifdef _WIN32 - if (rwflags & EVENT_READ) - tun_read_queue (tt, 0); + if (rwflags & EVENT_READ) + { + tun_read_queue(tt, 0); + } #endif - tt->rwflags_debug = rwflags; + tt->rwflags_debug = rwflags; } - return rwflags; + return rwflags; } -const char *tun_stat (const struct tuntap *tt, unsigned int rwflags, struct gc_arena *gc); +const char *tun_stat(const struct tuntap *tt, unsigned int rwflags, struct gc_arena *gc); #endif /* TUN_H */ diff --git a/src/openvpn/win32.c b/src/openvpn/win32.c index 00bc7ac2ed9..88fa3ecb28e 100644 --- a/src/openvpn/win32.c +++ b/src/openvpn/win32.c @@ -97,100 +97,112 @@ struct semaphore netcmd_semaphore; /* GLOBAL */ static char *win_sys_path = NULL; /* GLOBAL */ void -init_win32 (void) +init_win32(void) { - if (WSAStartup(0x0101, &wsa_state)) + if (WSAStartup(0x0101, &wsa_state)) { - msg (M_ERR, "WSAStartup failed"); + msg(M_ERR, "WSAStartup failed"); } - window_title_clear (&window_title); - win32_signal_clear (&win32_signal); + window_title_clear(&window_title); + win32_signal_clear(&win32_signal); } void -uninit_win32 (void) +uninit_win32(void) { - netcmd_semaphore_close (); - if (pause_exit_enabled) - { - if (win32_signal.mode == WSO_MODE_UNDEF) - { - struct win32_signal w; - win32_signal_open (&w, WSO_FORCE_CONSOLE, NULL, false); - win32_pause (&w); - win32_signal_close (&w); - } - else - win32_pause (&win32_signal); - } - window_title_restore (&window_title); - win32_signal_close (&win32_signal); - WSACleanup (); - free (win_sys_path); + netcmd_semaphore_close(); + if (pause_exit_enabled) + { + if (win32_signal.mode == WSO_MODE_UNDEF) + { + struct win32_signal w; + win32_signal_open(&w, WSO_FORCE_CONSOLE, NULL, false); + win32_pause(&w); + win32_signal_close(&w); + } + else + { + win32_pause(&win32_signal); + } + } + window_title_restore(&window_title); + win32_signal_close(&win32_signal); + WSACleanup(); + free(win_sys_path); } void -set_pause_exit_win32 (void) +set_pause_exit_win32(void) { - pause_exit_enabled = true; + pause_exit_enabled = true; } bool -init_security_attributes_allow_all (struct security_attributes *obj) +init_security_attributes_allow_all(struct security_attributes *obj) { - CLEAR (*obj); + CLEAR(*obj); - obj->sa.nLength = sizeof (SECURITY_ATTRIBUTES); - obj->sa.lpSecurityDescriptor = &obj->sd; - obj->sa.bInheritHandle = FALSE; - if (!InitializeSecurityDescriptor (&obj->sd, SECURITY_DESCRIPTOR_REVISION)) - return false; - if (!SetSecurityDescriptorDacl (&obj->sd, TRUE, NULL, FALSE)) - return false; - return true; + obj->sa.nLength = sizeof(SECURITY_ATTRIBUTES); + obj->sa.lpSecurityDescriptor = &obj->sd; + obj->sa.bInheritHandle = FALSE; + if (!InitializeSecurityDescriptor(&obj->sd, SECURITY_DESCRIPTOR_REVISION)) + { + return false; + } + if (!SetSecurityDescriptorDacl(&obj->sd, TRUE, NULL, FALSE)) + { + return false; + } + return true; } void -overlapped_io_init (struct overlapped_io *o, - const struct frame *frame, - BOOL event_state, - bool tuntap_buffer) /* if true: tuntap buffer, if false: socket buffer */ +overlapped_io_init(struct overlapped_io *o, + const struct frame *frame, + BOOL event_state, + bool tuntap_buffer) /* if true: tuntap buffer, if false: socket buffer */ { - CLEAR (*o); + CLEAR(*o); - /* manual reset event, initially set according to event_state */ - o->overlapped.hEvent = CreateEvent (NULL, TRUE, event_state, NULL); - if (o->overlapped.hEvent == NULL) - msg (M_ERR, "Error: overlapped_io_init: CreateEvent failed"); + /* manual reset event, initially set according to event_state */ + o->overlapped.hEvent = CreateEvent(NULL, TRUE, event_state, NULL); + if (o->overlapped.hEvent == NULL) + { + msg(M_ERR, "Error: overlapped_io_init: CreateEvent failed"); + } - /* allocate buffer for overlapped I/O */ - alloc_buf_sock_tun (&o->buf_init, frame, tuntap_buffer, 0); + /* allocate buffer for overlapped I/O */ + alloc_buf_sock_tun(&o->buf_init, frame, tuntap_buffer, 0); } void -overlapped_io_close (struct overlapped_io *o) +overlapped_io_close(struct overlapped_io *o) { - if (o->overlapped.hEvent) + if (o->overlapped.hEvent) { - if (!CloseHandle (o->overlapped.hEvent)) - msg (M_WARN | M_ERRNO, "Warning: CloseHandle failed on overlapped I/O event object"); + if (!CloseHandle(o->overlapped.hEvent)) + { + msg(M_WARN | M_ERRNO, "Warning: CloseHandle failed on overlapped I/O event object"); + } } - free_buf (&o->buf_init); + free_buf(&o->buf_init); } char * -overlapped_io_state_ascii (const struct overlapped_io *o) +overlapped_io_state_ascii(const struct overlapped_io *o) { - switch (o->iostate) + switch (o->iostate) { - case IOSTATE_INITIAL: - return "0"; - case IOSTATE_QUEUED: - return "Q"; - case IOSTATE_IMMEDIATE_RETURN: - return "1"; + case IOSTATE_INITIAL: + return "0"; + + case IOSTATE_QUEUED: + return "Q"; + + case IOSTATE_IMMEDIATE_RETURN: + return "1"; } - return "?"; + return "?"; } /* @@ -198,79 +210,99 @@ overlapped_io_state_ascii (const struct overlapped_io *o) */ void -init_net_event_win32 (struct rw_handle *event, long network_events, socket_descriptor_t sd, unsigned int flags) +init_net_event_win32(struct rw_handle *event, long network_events, socket_descriptor_t sd, unsigned int flags) { - /* manual reset events, initially set to unsignaled */ + /* manual reset events, initially set to unsignaled */ - /* initialize write event */ - if (!(flags & NE32_PERSIST_EVENT) || !event->write) + /* initialize write event */ + if (!(flags & NE32_PERSIST_EVENT) || !event->write) { - if (flags & NE32_WRITE_EVENT) - { - event->write = CreateEvent (NULL, TRUE, FALSE, NULL); - if (event->write == NULL) - msg (M_ERR, "Error: init_net_event_win32: CreateEvent (write) failed"); - } - else - event->write = NULL; + if (flags & NE32_WRITE_EVENT) + { + event->write = CreateEvent(NULL, TRUE, FALSE, NULL); + if (event->write == NULL) + { + msg(M_ERR, "Error: init_net_event_win32: CreateEvent (write) failed"); + } + } + else + { + event->write = NULL; + } } - /* initialize read event */ - if (!(flags & NE32_PERSIST_EVENT) || !event->read) + /* initialize read event */ + if (!(flags & NE32_PERSIST_EVENT) || !event->read) { - event->read = CreateEvent (NULL, TRUE, FALSE, NULL); - if (event->read == NULL) - msg (M_ERR, "Error: init_net_event_win32: CreateEvent (read) failed"); + event->read = CreateEvent(NULL, TRUE, FALSE, NULL); + if (event->read == NULL) + { + msg(M_ERR, "Error: init_net_event_win32: CreateEvent (read) failed"); + } + } + + /* setup network events to change read event state */ + if (WSAEventSelect(sd, event->read, network_events) != 0) + { + msg(M_FATAL | M_ERRNO, "Error: init_net_event_win32: WSAEventSelect call failed"); } - - /* setup network events to change read event state */ - if (WSAEventSelect (sd, event->read, network_events) != 0) - msg (M_FATAL | M_ERRNO, "Error: init_net_event_win32: WSAEventSelect call failed"); } long -reset_net_event_win32 (struct rw_handle *event, socket_descriptor_t sd) +reset_net_event_win32(struct rw_handle *event, socket_descriptor_t sd) { - WSANETWORKEVENTS wne; - if (WSAEnumNetworkEvents (sd, event->read, &wne) != 0) + WSANETWORKEVENTS wne; + if (WSAEnumNetworkEvents(sd, event->read, &wne) != 0) + { + msg(M_FATAL | M_ERRNO, "Error: reset_net_event_win32: WSAEnumNetworkEvents call failed"); + return 0; /* NOTREACHED */ + } + else { - msg (M_FATAL | M_ERRNO, "Error: reset_net_event_win32: WSAEnumNetworkEvents call failed"); - return 0; /* NOTREACHED */ + return wne.lNetworkEvents; } - else - return wne.lNetworkEvents; } void -close_net_event_win32 (struct rw_handle *event, socket_descriptor_t sd, unsigned int flags) +close_net_event_win32(struct rw_handle *event, socket_descriptor_t sd, unsigned int flags) { - if (event->read) - { - if (socket_defined (sd)) - { - if (WSAEventSelect (sd, event->read, 0) != 0) - msg (M_WARN | M_ERRNO, "Warning: close_net_event_win32: WSAEventSelect call failed"); - } - if (!ResetEvent (event->read)) - msg (M_WARN | M_ERRNO, "Warning: ResetEvent (read) failed in close_net_event_win32"); - if (!(flags & NE32_PERSIST_EVENT)) - { - if (!CloseHandle (event->read)) - msg (M_WARN | M_ERRNO, "Warning: CloseHandle (read) failed in close_net_event_win32"); - event->read = NULL; - } - } - - if (event->write) - { - if (!ResetEvent (event->write)) - msg (M_WARN | M_ERRNO, "Warning: ResetEvent (write) failed in close_net_event_win32"); - if (!(flags & NE32_PERSIST_EVENT)) - { - if (!CloseHandle (event->write)) - msg (M_WARN | M_ERRNO, "Warning: CloseHandle (write) failed in close_net_event_win32"); - event->write = NULL; - } + if (event->read) + { + if (socket_defined(sd)) + { + if (WSAEventSelect(sd, event->read, 0) != 0) + { + msg(M_WARN | M_ERRNO, "Warning: close_net_event_win32: WSAEventSelect call failed"); + } + } + if (!ResetEvent(event->read)) + { + msg(M_WARN | M_ERRNO, "Warning: ResetEvent (read) failed in close_net_event_win32"); + } + if (!(flags & NE32_PERSIST_EVENT)) + { + if (!CloseHandle(event->read)) + { + msg(M_WARN | M_ERRNO, "Warning: CloseHandle (read) failed in close_net_event_win32"); + } + event->read = NULL; + } + } + + if (event->write) + { + if (!ResetEvent(event->write)) + { + msg(M_WARN | M_ERRNO, "Warning: ResetEvent (write) failed in close_net_event_win32"); + } + if (!(flags & NE32_PERSIST_EVENT)) + { + if (!CloseHandle(event->write)) + { + msg(M_WARN | M_ERRNO, "Warning: CloseHandle (write) failed in close_net_event_win32"); + } + event->write = NULL; + } } } @@ -279,54 +311,64 @@ close_net_event_win32 (struct rw_handle *event, socket_descriptor_t sd, unsigned */ void -net_event_win32_init (struct net_event_win32 *ne) +net_event_win32_init(struct net_event_win32 *ne) { - CLEAR (*ne); - ne->sd = SOCKET_UNDEFINED; + CLEAR(*ne); + ne->sd = SOCKET_UNDEFINED; } void -net_event_win32_start (struct net_event_win32 *ne, long network_events, socket_descriptor_t sd) +net_event_win32_start(struct net_event_win32 *ne, long network_events, socket_descriptor_t sd) { - ASSERT (!socket_defined (ne->sd)); - ne->sd = sd; - ne->event_mask = 0; - init_net_event_win32 (&ne->handle, network_events, sd, NE32_PERSIST_EVENT|NE32_WRITE_EVENT); + ASSERT(!socket_defined(ne->sd)); + ne->sd = sd; + ne->event_mask = 0; + init_net_event_win32(&ne->handle, network_events, sd, NE32_PERSIST_EVENT|NE32_WRITE_EVENT); } void -net_event_win32_reset_write (struct net_event_win32 *ne) +net_event_win32_reset_write(struct net_event_win32 *ne) { - BOOL status; - if (ne->event_mask & FD_WRITE) - status = SetEvent (ne->handle.write); - else - status = ResetEvent (ne->handle.write); - if (!status) - msg (M_WARN | M_ERRNO, "Warning: SetEvent/ResetEvent failed in net_event_win32_reset_write"); + BOOL status; + if (ne->event_mask & FD_WRITE) + { + status = SetEvent(ne->handle.write); + } + else + { + status = ResetEvent(ne->handle.write); + } + if (!status) + { + msg(M_WARN | M_ERRNO, "Warning: SetEvent/ResetEvent failed in net_event_win32_reset_write"); + } } void -net_event_win32_reset (struct net_event_win32 *ne) +net_event_win32_reset(struct net_event_win32 *ne) { - ne->event_mask |= reset_net_event_win32 (&ne->handle, ne->sd); + ne->event_mask |= reset_net_event_win32(&ne->handle, ne->sd); } void -net_event_win32_stop (struct net_event_win32 *ne) +net_event_win32_stop(struct net_event_win32 *ne) { - if (net_event_win32_defined (ne)) - close_net_event_win32 (&ne->handle, ne->sd, NE32_PERSIST_EVENT); - ne->sd = SOCKET_UNDEFINED; - ne->event_mask = 0; + if (net_event_win32_defined(ne)) + { + close_net_event_win32(&ne->handle, ne->sd, NE32_PERSIST_EVENT); + } + ne->sd = SOCKET_UNDEFINED; + ne->event_mask = 0; } void -net_event_win32_close (struct net_event_win32 *ne) +net_event_win32_close(struct net_event_win32 *ne) { - if (net_event_win32_defined (ne)) - close_net_event_win32 (&ne->handle, ne->sd, 0); - net_event_win32_init (ne); + if (net_event_win32_defined(ne)) + { + close_net_event_win32(&ne->handle, ne->sd, 0); + } + net_event_win32_init(ne); } /* @@ -340,19 +382,23 @@ net_event_win32_close (struct net_event_win32 *ne) static void win_trigger_event(struct win32_signal *ws) { - if (ws->mode == WSO_MODE_SERVICE && HANDLE_DEFINED(ws->in.read)) - SetEvent (ws->in.read); - else /* generate a key-press event */ + if (ws->mode == WSO_MODE_SERVICE && HANDLE_DEFINED(ws->in.read)) { - DWORD tmp; - INPUT_RECORD ir; - HANDLE stdin_handle = GetStdHandle(STD_INPUT_HANDLE); - - CLEAR(ir); - ir.EventType = KEY_EVENT; - ir.Event.KeyEvent.bKeyDown = true; - if (!stdin_handle || !WriteConsoleInput(stdin_handle, &ir, 1, &tmp)) - msg(M_WARN|M_ERRNO, "WARN: win_trigger_event: WriteConsoleInput"); + SetEvent(ws->in.read); + } + else /* generate a key-press event */ + { + DWORD tmp; + INPUT_RECORD ir; + HANDLE stdin_handle = GetStdHandle(STD_INPUT_HANDLE); + + CLEAR(ir); + ir.EventType = KEY_EVENT; + ir.Event.KeyEvent.bKeyDown = true; + if (!stdin_handle || !WriteConsoleInput(stdin_handle, &ir, 1, &tmp)) + { + msg(M_WARN|M_ERRNO, "WARN: win_trigger_event: WriteConsoleInput"); + } } } @@ -360,372 +406,429 @@ win_trigger_event(struct win32_signal *ws) * Callback to handle console ctrl events */ static bool WINAPI -win_ctrl_handler (DWORD signum) +win_ctrl_handler(DWORD signum) { - msg(D_LOW, "win_ctrl_handler: signal received (code=%lu)", (unsigned long) signum); - - if (siginfo_static.signal_received == SIGTERM) - return true; - - switch (signum) - { - case CTRL_C_EVENT: - case CTRL_BREAK_EVENT: - throw_signal(SIGTERM); - /* trigget the win32_signal to interrupt the event loop */ - win_trigger_event(&win32_signal); - return true; - break; - default: - msg(D_LOW, "win_ctrl_handler: signal (code=%lu) not handled", (unsigned long) signum); - break; - } - /* pass all other signals to the next handler */ - return false; + msg(D_LOW, "win_ctrl_handler: signal received (code=%lu)", (unsigned long) signum); + + if (siginfo_static.signal_received == SIGTERM) + { + return true; + } + + switch (signum) + { + case CTRL_C_EVENT: + case CTRL_BREAK_EVENT: + throw_signal(SIGTERM); + /* trigget the win32_signal to interrupt the event loop */ + win_trigger_event(&win32_signal); + return true; + break; + + default: + msg(D_LOW, "win_ctrl_handler: signal (code=%lu) not handled", (unsigned long) signum); + break; + } + /* pass all other signals to the next handler */ + return false; } void -win32_signal_clear (struct win32_signal *ws) +win32_signal_clear(struct win32_signal *ws) { - CLEAR (*ws); + CLEAR(*ws); } void -win32_signal_open (struct win32_signal *ws, - int force, - const char *exit_event_name, - bool exit_event_initial_state) +win32_signal_open(struct win32_signal *ws, + int force, + const char *exit_event_name, + bool exit_event_initial_state) { - CLEAR (*ws); - - ws->mode = WSO_MODE_UNDEF; - ws->in.read = INVALID_HANDLE_VALUE; - ws->in.write = INVALID_HANDLE_VALUE; - ws->console_mode_save = 0; - ws->console_mode_save_defined = false; - - if (force == WSO_NOFORCE || force == WSO_FORCE_CONSOLE) - { - /* - * Try to open console. - */ - ws->in.read = GetStdHandle (STD_INPUT_HANDLE); - if (ws->in.read != INVALID_HANDLE_VALUE) - { - if (GetConsoleMode (ws->in.read, &ws->console_mode_save)) - { - /* running on a console */ - const DWORD new_console_mode = ws->console_mode_save - & ~(ENABLE_WINDOW_INPUT - | ENABLE_PROCESSED_INPUT - | ENABLE_LINE_INPUT - | ENABLE_ECHO_INPUT - | ENABLE_MOUSE_INPUT); - - if (new_console_mode != ws->console_mode_save) - { - if (!SetConsoleMode (ws->in.read, new_console_mode)) - msg (M_ERR, "Error: win32_signal_open: SetConsoleMode failed"); - ws->console_mode_save_defined = true; - } - ws->mode = WSO_MODE_CONSOLE; - } - else - ws->in.read = INVALID_HANDLE_VALUE; /* probably running as a service */ - } - } - - /* - * If console open failed, assume we are running - * as a service. - */ - if ((force == WSO_NOFORCE || force == WSO_FORCE_SERVICE) - && !HANDLE_DEFINED (ws->in.read) && exit_event_name) - { - struct security_attributes sa; - - if (!init_security_attributes_allow_all (&sa)) - msg (M_ERR, "Error: win32_signal_open: init SA failed"); - - ws->in.read = CreateEvent (&sa.sa, - TRUE, - exit_event_initial_state ? TRUE : FALSE, - exit_event_name); - if (ws->in.read == NULL) - { - msg (M_WARN|M_ERRNO, "NOTE: CreateEvent '%s' failed", exit_event_name); - } - else - { - if (WaitForSingleObject (ws->in.read, 0) != WAIT_TIMEOUT) - msg (M_FATAL, "ERROR: Exit Event ('%s') is signaled", exit_event_name); - else - ws->mode = WSO_MODE_SERVICE; - } + CLEAR(*ws); + + ws->mode = WSO_MODE_UNDEF; + ws->in.read = INVALID_HANDLE_VALUE; + ws->in.write = INVALID_HANDLE_VALUE; + ws->console_mode_save = 0; + ws->console_mode_save_defined = false; + + if (force == WSO_NOFORCE || force == WSO_FORCE_CONSOLE) + { + /* + * Try to open console. + */ + ws->in.read = GetStdHandle(STD_INPUT_HANDLE); + if (ws->in.read != INVALID_HANDLE_VALUE) + { + if (GetConsoleMode(ws->in.read, &ws->console_mode_save)) + { + /* running on a console */ + const DWORD new_console_mode = ws->console_mode_save + & ~(ENABLE_WINDOW_INPUT + | ENABLE_PROCESSED_INPUT + | ENABLE_LINE_INPUT + | ENABLE_ECHO_INPUT + | ENABLE_MOUSE_INPUT); + + if (new_console_mode != ws->console_mode_save) + { + if (!SetConsoleMode(ws->in.read, new_console_mode)) + { + msg(M_ERR, "Error: win32_signal_open: SetConsoleMode failed"); + } + ws->console_mode_save_defined = true; + } + ws->mode = WSO_MODE_CONSOLE; + } + else + { + ws->in.read = INVALID_HANDLE_VALUE; /* probably running as a service */ + } + } + } + + /* + * If console open failed, assume we are running + * as a service. + */ + if ((force == WSO_NOFORCE || force == WSO_FORCE_SERVICE) + && !HANDLE_DEFINED(ws->in.read) && exit_event_name) + { + struct security_attributes sa; + + if (!init_security_attributes_allow_all(&sa)) + { + msg(M_ERR, "Error: win32_signal_open: init SA failed"); + } + + ws->in.read = CreateEvent(&sa.sa, + TRUE, + exit_event_initial_state ? TRUE : FALSE, + exit_event_name); + if (ws->in.read == NULL) + { + msg(M_WARN|M_ERRNO, "NOTE: CreateEvent '%s' failed", exit_event_name); + } + else + { + if (WaitForSingleObject(ws->in.read, 0) != WAIT_TIMEOUT) + { + msg(M_FATAL, "ERROR: Exit Event ('%s') is signaled", exit_event_name); + } + else + { + ws->mode = WSO_MODE_SERVICE; + } + } } /* set the ctrl handler in both console and service modes */ - if (!SetConsoleCtrlHandler ((PHANDLER_ROUTINE) win_ctrl_handler, true)) - msg (M_WARN|M_ERRNO, "WARN: SetConsoleCtrlHandler failed"); + if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE) win_ctrl_handler, true)) + { + msg(M_WARN|M_ERRNO, "WARN: SetConsoleCtrlHandler failed"); + } } static bool -keyboard_input_available (struct win32_signal *ws) +keyboard_input_available(struct win32_signal *ws) { - ASSERT (ws->mode == WSO_MODE_CONSOLE); - if (HANDLE_DEFINED (ws->in.read)) + ASSERT(ws->mode == WSO_MODE_CONSOLE); + if (HANDLE_DEFINED(ws->in.read)) { - DWORD n; - if (GetNumberOfConsoleInputEvents (ws->in.read, &n)) - return n > 0; + DWORD n; + if (GetNumberOfConsoleInputEvents(ws->in.read, &n)) + { + return n > 0; + } } - return false; + return false; } static unsigned int -keyboard_ir_to_key (INPUT_RECORD *ir) +keyboard_ir_to_key(INPUT_RECORD *ir) { - if (ir->Event.KeyEvent.uChar.AsciiChar == 0) - return ir->Event.KeyEvent.wVirtualScanCode; + if (ir->Event.KeyEvent.uChar.AsciiChar == 0) + { + return ir->Event.KeyEvent.wVirtualScanCode; + } - if ((ir->Event.KeyEvent.dwControlKeyState - & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) - && (ir->Event.KeyEvent.wVirtualKeyCode != 18)) - return ir->Event.KeyEvent.wVirtualScanCode * 256; + if ((ir->Event.KeyEvent.dwControlKeyState + & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) + && (ir->Event.KeyEvent.wVirtualKeyCode != 18)) + { + return ir->Event.KeyEvent.wVirtualScanCode * 256; + } - return ir->Event.KeyEvent.uChar.AsciiChar; + return ir->Event.KeyEvent.uChar.AsciiChar; } static unsigned int -win32_keyboard_get (struct win32_signal *ws) +win32_keyboard_get(struct win32_signal *ws) { - ASSERT (ws->mode == WSO_MODE_CONSOLE); - if (HANDLE_DEFINED (ws->in.read)) - { - INPUT_RECORD ir; - do { - DWORD n; - if (!keyboard_input_available (ws)) - return 0; - if (!ReadConsoleInput (ws->in.read, &ir, 1, &n)) - return 0; - } while (ir.EventType != KEY_EVENT || ir.Event.KeyEvent.bKeyDown != TRUE); - - return keyboard_ir_to_key (&ir); - } - else - return 0; + ASSERT(ws->mode == WSO_MODE_CONSOLE); + if (HANDLE_DEFINED(ws->in.read)) + { + INPUT_RECORD ir; + do { + DWORD n; + if (!keyboard_input_available(ws)) + { + return 0; + } + if (!ReadConsoleInput(ws->in.read, &ir, 1, &n)) + { + return 0; + } + } while (ir.EventType != KEY_EVENT || ir.Event.KeyEvent.bKeyDown != TRUE); + + return keyboard_ir_to_key(&ir); + } + else + { + return 0; + } } void -win32_signal_close (struct win32_signal *ws) +win32_signal_close(struct win32_signal *ws) { - if (ws->mode == WSO_MODE_SERVICE && HANDLE_DEFINED (ws->in.read)) - CloseHandle (ws->in.read); - if (ws->console_mode_save_defined) + if (ws->mode == WSO_MODE_SERVICE && HANDLE_DEFINED(ws->in.read)) { - if (!SetConsoleMode (ws->in.read, ws->console_mode_save)) - msg (M_ERR, "Error: win32_signal_close: SetConsoleMode failed"); + CloseHandle(ws->in.read); } - CLEAR (*ws); + if (ws->console_mode_save_defined) + { + if (!SetConsoleMode(ws->in.read, ws->console_mode_save)) + { + msg(M_ERR, "Error: win32_signal_close: SetConsoleMode failed"); + } + } + CLEAR(*ws); } /* * Return true if interrupt occurs in service mode. */ bool -win32_service_interrupt (struct win32_signal *ws) +win32_service_interrupt(struct win32_signal *ws) { - if (ws->mode == WSO_MODE_SERVICE) + if (ws->mode == WSO_MODE_SERVICE) { - if (HANDLE_DEFINED (ws->in.read) - && WaitForSingleObject (ws->in.read, 0) == WAIT_OBJECT_0) - return true; + if (HANDLE_DEFINED(ws->in.read) + && WaitForSingleObject(ws->in.read, 0) == WAIT_OBJECT_0) + { + return true; + } } - return false; + return false; } int -win32_signal_get (struct win32_signal *ws) +win32_signal_get(struct win32_signal *ws) { - int ret = 0; - if (siginfo_static.signal_received) - { - ret = siginfo_static.signal_received; - } - else - { - if (ws->mode == WSO_MODE_SERVICE) - { - if (win32_service_interrupt (ws)) - ret = SIGTERM; - } - else if (ws->mode == WSO_MODE_CONSOLE) - { - switch (win32_keyboard_get (ws)) - { - case 0x3B: /* F1 -> USR1 */ - ret = SIGUSR1; - break; - case 0x3C: /* F2 -> USR2 */ - ret = SIGUSR2; - break; - case 0x3D: /* F3 -> HUP */ - ret = SIGHUP; - break; - case 0x3E: /* F4 -> TERM */ - ret = SIGTERM; - break; - case 0x03: /* CTRL-C -> TERM */ - ret = SIGTERM; - break; - } - } - if (ret) - { - siginfo_static.signal_received = ret; - siginfo_static.source = SIG_SOURCE_HARD; - } - } - return ret; + int ret = 0; + if (siginfo_static.signal_received) + { + ret = siginfo_static.signal_received; + } + else + { + if (ws->mode == WSO_MODE_SERVICE) + { + if (win32_service_interrupt(ws)) + { + ret = SIGTERM; + } + } + else if (ws->mode == WSO_MODE_CONSOLE) + { + switch (win32_keyboard_get(ws)) + { + case 0x3B: /* F1 -> USR1 */ + ret = SIGUSR1; + break; + + case 0x3C: /* F2 -> USR2 */ + ret = SIGUSR2; + break; + + case 0x3D: /* F3 -> HUP */ + ret = SIGHUP; + break; + + case 0x3E: /* F4 -> TERM */ + ret = SIGTERM; + break; + + case 0x03: /* CTRL-C -> TERM */ + ret = SIGTERM; + break; + } + } + if (ret) + { + siginfo_static.signal_received = ret; + siginfo_static.source = SIG_SOURCE_HARD; + } + } + return ret; } void -win32_pause (struct win32_signal *ws) +win32_pause(struct win32_signal *ws) { - if (ws->mode == WSO_MODE_CONSOLE && HANDLE_DEFINED (ws->in.read)) + if (ws->mode == WSO_MODE_CONSOLE && HANDLE_DEFINED(ws->in.read)) { - int status; - msg (M_INFO|M_NOPREFIX, "Press any key to continue..."); - do { - status = WaitForSingleObject (ws->in.read, INFINITE); - } while (!win32_keyboard_get (ws)); + int status; + msg(M_INFO|M_NOPREFIX, "Press any key to continue..."); + do { + status = WaitForSingleObject(ws->in.read, INFINITE); + } while (!win32_keyboard_get(ws)); } } /* window functions */ void -window_title_clear (struct window_title *wt) +window_title_clear(struct window_title *wt) { - CLEAR (*wt); + CLEAR(*wt); } void -window_title_save (struct window_title *wt) +window_title_save(struct window_title *wt) { - if (!wt->saved) + if (!wt->saved) { - if (!GetConsoleTitle (wt->old_window_title, sizeof (wt->old_window_title))) - { - wt->old_window_title[0] = 0; - wt->saved = false; - } - else - wt->saved = true; + if (!GetConsoleTitle(wt->old_window_title, sizeof(wt->old_window_title))) + { + wt->old_window_title[0] = 0; + wt->saved = false; + } + else + { + wt->saved = true; + } } } void -window_title_restore (const struct window_title *wt) +window_title_restore(const struct window_title *wt) { - if (wt->saved) - SetConsoleTitle (wt->old_window_title); + if (wt->saved) + { + SetConsoleTitle(wt->old_window_title); + } } void -window_title_generate (const char *title) +window_title_generate(const char *title) { - struct gc_arena gc = gc_new (); - struct buffer out = alloc_buf_gc (256, &gc); - if (!title) - title = ""; - buf_printf (&out, "[%s] " PACKAGE_NAME " " PACKAGE_VERSION " F4:EXIT F1:USR1 F2:USR2 F3:HUP", title); - SetConsoleTitle (BSTR (&out)); - gc_free (&gc); + struct gc_arena gc = gc_new(); + struct buffer out = alloc_buf_gc(256, &gc); + if (!title) + { + title = ""; + } + buf_printf(&out, "[%s] " PACKAGE_NAME " " PACKAGE_VERSION " F4:EXIT F1:USR1 F2:USR2 F3:HUP", title); + SetConsoleTitle(BSTR(&out)); + gc_free(&gc); } /* semaphore functions */ void -semaphore_clear (struct semaphore *s) +semaphore_clear(struct semaphore *s) { - CLEAR (*s); + CLEAR(*s); } void -semaphore_open (struct semaphore *s, const char *name) +semaphore_open(struct semaphore *s, const char *name) { - struct security_attributes sa; + struct security_attributes sa; - s->locked = false; - s->name = name; - s->hand = NULL; + s->locked = false; + s->name = name; + s->hand = NULL; - if (init_security_attributes_allow_all (&sa)) - s->hand = CreateSemaphore(&sa.sa, 1, 1, name); + if (init_security_attributes_allow_all(&sa)) + { + s->hand = CreateSemaphore(&sa.sa, 1, 1, name); + } - if (s->hand == NULL) - msg (M_WARN|M_ERRNO, "WARNING: Cannot create Win32 semaphore '%s'", name); - else - dmsg (D_SEMAPHORE, "Created Win32 semaphore '%s'", s->name); + if (s->hand == NULL) + { + msg(M_WARN|M_ERRNO, "WARNING: Cannot create Win32 semaphore '%s'", name); + } + else + { + dmsg(D_SEMAPHORE, "Created Win32 semaphore '%s'", s->name); + } } bool -semaphore_lock (struct semaphore *s, int timeout_milliseconds) +semaphore_lock(struct semaphore *s, int timeout_milliseconds) { - bool ret = true; - - if (s->hand) - { - DWORD status; - ASSERT (!s->locked); - - dmsg (D_SEMAPHORE_LOW, "Attempting to lock Win32 semaphore '%s' prior to net shell command (timeout = %d sec)", - s->name, - timeout_milliseconds / 1000); - status = WaitForSingleObject (s->hand, timeout_milliseconds); - if (status == WAIT_FAILED) - msg (M_ERR, "Wait failed on Win32 semaphore '%s'", s->name); - ret = (status == WAIT_TIMEOUT) ? false : true; - if (ret) - { - dmsg (D_SEMAPHORE, "Locked Win32 semaphore '%s'", s->name); - s->locked = true; - } - else - { - dmsg (D_SEMAPHORE, "Wait on Win32 semaphore '%s' timed out after %d milliseconds", - s->name, - timeout_milliseconds); - } - } - return ret; + bool ret = true; + + if (s->hand) + { + DWORD status; + ASSERT(!s->locked); + + dmsg(D_SEMAPHORE_LOW, "Attempting to lock Win32 semaphore '%s' prior to net shell command (timeout = %d sec)", + s->name, + timeout_milliseconds / 1000); + status = WaitForSingleObject(s->hand, timeout_milliseconds); + if (status == WAIT_FAILED) + { + msg(M_ERR, "Wait failed on Win32 semaphore '%s'", s->name); + } + ret = (status == WAIT_TIMEOUT) ? false : true; + if (ret) + { + dmsg(D_SEMAPHORE, "Locked Win32 semaphore '%s'", s->name); + s->locked = true; + } + else + { + dmsg(D_SEMAPHORE, "Wait on Win32 semaphore '%s' timed out after %d milliseconds", + s->name, + timeout_milliseconds); + } + } + return ret; } void -semaphore_release (struct semaphore *s) +semaphore_release(struct semaphore *s) { - if (s->hand) + if (s->hand) { - ASSERT (s->locked); - dmsg (D_SEMAPHORE, "Releasing Win32 semaphore '%s'", s->name); - if (!ReleaseSemaphore(s->hand, 1, NULL)) - msg (M_WARN | M_ERRNO, "ReleaseSemaphore failed on Win32 semaphore '%s'", - s->name); - s->locked = false; + ASSERT(s->locked); + dmsg(D_SEMAPHORE, "Releasing Win32 semaphore '%s'", s->name); + if (!ReleaseSemaphore(s->hand, 1, NULL)) + { + msg(M_WARN | M_ERRNO, "ReleaseSemaphore failed on Win32 semaphore '%s'", + s->name); + } + s->locked = false; } } void -semaphore_close (struct semaphore *s) +semaphore_close(struct semaphore *s) { - if (s->hand) + if (s->hand) { - if (s->locked) - semaphore_release (s); - dmsg (D_SEMAPHORE, "Closing Win32 semaphore '%s'", s->name); - CloseHandle (s->hand); - s->hand = NULL; + if (s->locked) + { + semaphore_release(s); + } + dmsg(D_SEMAPHORE, "Closing Win32 semaphore '%s'", s->name); + CloseHandle(s->hand); + s->hand = NULL; } } @@ -735,35 +838,39 @@ semaphore_close (struct semaphore *s) */ void -netcmd_semaphore_init (void) +netcmd_semaphore_init(void) { - semaphore_open (&netcmd_semaphore, PACKAGE "_netcmd"); + semaphore_open(&netcmd_semaphore, PACKAGE "_netcmd"); } void -netcmd_semaphore_close (void) +netcmd_semaphore_close(void) { - semaphore_close (&netcmd_semaphore); + semaphore_close(&netcmd_semaphore); } void -netcmd_semaphore_lock (void) +netcmd_semaphore_lock(void) { - const int timeout_seconds = 600; + const int timeout_seconds = 600; - if (!netcmd_semaphore.hand) - netcmd_semaphore_init (); + if (!netcmd_semaphore.hand) + { + netcmd_semaphore_init(); + } - if (!semaphore_lock (&netcmd_semaphore, timeout_seconds * 1000)) - msg (M_FATAL, "Cannot lock net command semaphore"); + if (!semaphore_lock(&netcmd_semaphore, timeout_seconds * 1000)) + { + msg(M_FATAL, "Cannot lock net command semaphore"); + } } void -netcmd_semaphore_release (void) +netcmd_semaphore_release(void) { - semaphore_release (&netcmd_semaphore); - /* netcmd_semaphore has max count of 1 - safe to close after release */ - semaphore_close (&netcmd_semaphore); + semaphore_release(&netcmd_semaphore); + /* netcmd_semaphore has max count of 1 - safe to close after release */ + semaphore_close(&netcmd_semaphore); } /* @@ -778,54 +885,78 @@ netcmd_semaphore_release (void) */ static bool -cmp_prefix (const char *str, const bool n, const char *pre) +cmp_prefix(const char *str, const bool n, const char *pre) { - size_t i = 0; + size_t i = 0; - if (!str) - return false; + if (!str) + { + return false; + } - while (true) - { - const int c1 = pre[i]; - int c2 = str[i]; - ++i; - if (c1 == '\0') - { - if (n) - { - if (isdigit (c2)) - c2 = str[i]; - else - return false; - } - return c2 == '\0' || c2 == '.'; - } - else if (c2 == '\0') - return false; - if (c1 != tolower(c2)) - return false; + while (true) + { + const int c1 = pre[i]; + int c2 = str[i]; + ++i; + if (c1 == '\0') + { + if (n) + { + if (isdigit(c2)) + { + c2 = str[i]; + } + else + { + return false; + } + } + return c2 == '\0' || c2 == '.'; + } + else if (c2 == '\0') + { + return false; + } + if (c1 != tolower(c2)) + { + return false; + } } } bool -win_safe_filename (const char *fn) +win_safe_filename(const char *fn) { - if (cmp_prefix (fn, false, "con")) - return false; - if (cmp_prefix (fn, false, "prn")) - return false; - if (cmp_prefix (fn, false, "aux")) - return false; - if (cmp_prefix (fn, false, "nul")) - return false; - if (cmp_prefix (fn, true, "com")) - return false; - if (cmp_prefix (fn, true, "lpt")) - return false; - if (cmp_prefix (fn, false, "clock$")) - return false; - return true; + if (cmp_prefix(fn, false, "con")) + { + return false; + } + if (cmp_prefix(fn, false, "prn")) + { + return false; + } + if (cmp_prefix(fn, false, "aux")) + { + return false; + } + if (cmp_prefix(fn, false, "nul")) + { + return false; + } + if (cmp_prefix(fn, true, "com")) + { + return false; + } + if (cmp_prefix(fn, true, "lpt")) + { + return false; + } + if (cmp_prefix(fn, false, "clock$")) + { + return false; + } + return true; } /* @@ -833,372 +964,397 @@ win_safe_filename (const char *fn) */ static char * -env_block (const struct env_set *es) +env_block(const struct env_set *es) { - char force_path[256]; - char *sysroot = get_win_sys_path(); - - if (!openvpn_snprintf(force_path, sizeof(force_path), "PATH=%s\\System32;%s;%s\\System32\\Wbem", - sysroot, sysroot, sysroot)) - msg(M_WARN, "env_block: default path truncated to %s", force_path); - - if (es) - { - struct env_item *e; - char *ret; - char *p; - size_t nchars = 1; - bool path_seen = false; - - for (e = es->list; e != NULL; e = e->next) - nchars += strlen (e->string) + 1; - - nchars += strlen(force_path)+1; - - ret = (char *) malloc (nchars); - check_malloc_return (ret); - - p = ret; - for (e = es->list; e != NULL; e = e->next) - { - if (env_allowed (e->string)) - { - strcpy (p, e->string); - p += strlen (e->string) + 1; - } - if ( strncmp(e->string, "PATH=", 5 ) == 0 ) - path_seen = true; - } - - /* make sure PATH is set */ - if ( !path_seen ) - { - msg( M_INFO, "env_block: add %s", force_path ); - strcpy( p, force_path ); - p += strlen(force_path) + 1; - } - - *p = '\0'; - return ret; - } - else - return NULL; + char force_path[256]; + char *sysroot = get_win_sys_path(); + + if (!openvpn_snprintf(force_path, sizeof(force_path), "PATH=%s\\System32;%s;%s\\System32\\Wbem", + sysroot, sysroot, sysroot)) + { + msg(M_WARN, "env_block: default path truncated to %s", force_path); + } + + if (es) + { + struct env_item *e; + char *ret; + char *p; + size_t nchars = 1; + bool path_seen = false; + + for (e = es->list; e != NULL; e = e->next) + nchars += strlen(e->string) + 1; + + nchars += strlen(force_path)+1; + + ret = (char *) malloc(nchars); + check_malloc_return(ret); + + p = ret; + for (e = es->list; e != NULL; e = e->next) + { + if (env_allowed(e->string)) + { + strcpy(p, e->string); + p += strlen(e->string) + 1; + } + if (strncmp(e->string, "PATH=", 5 ) == 0) + { + path_seen = true; + } + } + + /* make sure PATH is set */ + if (!path_seen) + { + msg( M_INFO, "env_block: add %s", force_path ); + strcpy( p, force_path ); + p += strlen(force_path) + 1; + } + + *p = '\0'; + return ret; + } + else + { + return NULL; + } } static WCHAR * -wide_cmd_line (const struct argv *a, struct gc_arena *gc) +wide_cmd_line(const struct argv *a, struct gc_arena *gc) { - size_t nchars = 1; - size_t maxlen = 0; - size_t i; - struct buffer buf; - char *work = NULL; + size_t nchars = 1; + size_t maxlen = 0; + size_t i; + struct buffer buf; + char *work = NULL; - if (!a) - return NULL; + if (!a) + { + return NULL; + } - for (i = 0; i < a->argc; ++i) + for (i = 0; i < a->argc; ++i) { - const char *arg = a->argv[i]; - const size_t len = strlen (arg); - nchars += len + 3; - if (len > maxlen) - maxlen = len; + const char *arg = a->argv[i]; + const size_t len = strlen(arg); + nchars += len + 3; + if (len > maxlen) + { + maxlen = len; + } } - work = gc_malloc (maxlen + 1, false, gc); - check_malloc_return (work); - buf = alloc_buf_gc (nchars, gc); + work = gc_malloc(maxlen + 1, false, gc); + check_malloc_return(work); + buf = alloc_buf_gc(nchars, gc); - for (i = 0; i < a->argc; ++i) + for (i = 0; i < a->argc; ++i) { - const char *arg = a->argv[i]; - strcpy (work, arg); - string_mod (work, CC_PRINT, CC_DOUBLE_QUOTE|CC_CRLF, '_'); - if (i) - buf_printf (&buf, " "); - if (string_class (work, CC_ANY, CC_SPACE)) - buf_printf (&buf, "%s", work); - else - buf_printf (&buf, "\"%s\"", work); + const char *arg = a->argv[i]; + strcpy(work, arg); + string_mod(work, CC_PRINT, CC_DOUBLE_QUOTE|CC_CRLF, '_'); + if (i) + { + buf_printf(&buf, " "); + } + if (string_class(work, CC_ANY, CC_SPACE)) + { + buf_printf(&buf, "%s", work); + } + else + { + buf_printf(&buf, "\"%s\"", work); + } } - return wide_string (BSTR (&buf), gc); + return wide_string(BSTR(&buf), gc); } /* * Attempt to simulate fork/execve on Windows */ int -openvpn_execve (const struct argv *a, const struct env_set *es, const unsigned int flags) +openvpn_execve(const struct argv *a, const struct env_set *es, const unsigned int flags) { - int ret = -1; - static bool exec_warn = false; + int ret = -1; + static bool exec_warn = false; - if (a && a->argv[0]) + if (a && a->argv[0]) { - if (openvpn_execve_allowed (flags)) - { - struct gc_arena gc = gc_new (); - STARTUPINFOW start_info; - PROCESS_INFORMATION proc_info; + if (openvpn_execve_allowed(flags)) + { + struct gc_arena gc = gc_new(); + STARTUPINFOW start_info; + PROCESS_INFORMATION proc_info; - char *env = env_block (es); - WCHAR *cl = wide_cmd_line (a, &gc); - WCHAR *cmd = wide_string (a->argv[0], &gc); + char *env = env_block(es); + WCHAR *cl = wide_cmd_line(a, &gc); + WCHAR *cmd = wide_string(a->argv[0], &gc); - /* this allows console programs to run, and is ignored otherwise */ - DWORD proc_flags = CREATE_NO_WINDOW; + /* this allows console programs to run, and is ignored otherwise */ + DWORD proc_flags = CREATE_NO_WINDOW; - CLEAR (start_info); - CLEAR (proc_info); + CLEAR(start_info); + CLEAR(proc_info); - /* fill in STARTUPINFO struct */ - GetStartupInfoW(&start_info); - start_info.cb = sizeof(start_info); - start_info.dwFlags = STARTF_USESHOWWINDOW; - start_info.wShowWindow = SW_HIDE; + /* fill in STARTUPINFO struct */ + GetStartupInfoW(&start_info); + start_info.cb = sizeof(start_info); + start_info.dwFlags = STARTF_USESHOWWINDOW; + start_info.wShowWindow = SW_HIDE; - if (CreateProcessW (cmd, cl, NULL, NULL, FALSE, proc_flags, env, NULL, &start_info, &proc_info)) + if (CreateProcessW(cmd, cl, NULL, NULL, FALSE, proc_flags, env, NULL, &start_info, &proc_info)) { - DWORD exit_status = 0; - CloseHandle (proc_info.hThread); - WaitForSingleObject (proc_info.hProcess, INFINITE); - if (GetExitCodeProcess (proc_info.hProcess, &exit_status)) - ret = (int)exit_status; - else - msg (M_WARN|M_ERRNO, "openvpn_execve: GetExitCodeProcess %S failed", cmd); - CloseHandle (proc_info.hProcess); + DWORD exit_status = 0; + CloseHandle(proc_info.hThread); + WaitForSingleObject(proc_info.hProcess, INFINITE); + if (GetExitCodeProcess(proc_info.hProcess, &exit_status)) + { + ret = (int)exit_status; + } + else + { + msg(M_WARN|M_ERRNO, "openvpn_execve: GetExitCodeProcess %S failed", cmd); + } + CloseHandle(proc_info.hProcess); } - else + else { - msg (M_WARN|M_ERRNO, "openvpn_execve: CreateProcess %S failed", cmd); + msg(M_WARN|M_ERRNO, "openvpn_execve: CreateProcess %S failed", cmd); } - free (env); - gc_free (&gc); + free(env); + gc_free(&gc); + } + else if (!exec_warn && (script_security < SSEC_SCRIPTS)) + { + msg(M_WARN, SCRIPT_SECURITY_WARNING); + exec_warn = true; } - else if (!exec_warn && (script_security < SSEC_SCRIPTS)) - { - msg (M_WARN, SCRIPT_SECURITY_WARNING); - exec_warn = true; - } } - else + else { - msg (M_WARN, "openvpn_execve: called with empty argv"); + msg(M_WARN, "openvpn_execve: called with empty argv"); } - return ret; + return ret; } WCHAR * -wide_string (const char* utf8, struct gc_arena *gc) +wide_string(const char *utf8, struct gc_arena *gc) { - int n = MultiByteToWideChar (CP_UTF8, 0, utf8, -1, NULL, 0); - WCHAR *ucs16 = gc_malloc (n * sizeof (WCHAR), false, gc); - MultiByteToWideChar (CP_UTF8, 0, utf8, -1, ucs16, n); - return ucs16; + int n = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0); + WCHAR *ucs16 = gc_malloc(n * sizeof(WCHAR), false, gc); + MultiByteToWideChar(CP_UTF8, 0, utf8, -1, ucs16, n); + return ucs16; } /* * call ourself in another process */ void -fork_to_self (const char *cmdline) +fork_to_self(const char *cmdline) { - STARTUPINFO start_info; - PROCESS_INFORMATION proc_info; - char self_exe[256]; - char *cl = string_alloc (cmdline, NULL); - DWORD status; - - CLEAR (start_info); - CLEAR (proc_info); - CLEAR (self_exe); - - status = GetModuleFileName (NULL, self_exe, sizeof(self_exe)); - if (status == 0 || status == sizeof(self_exe)) + STARTUPINFO start_info; + PROCESS_INFORMATION proc_info; + char self_exe[256]; + char *cl = string_alloc(cmdline, NULL); + DWORD status; + + CLEAR(start_info); + CLEAR(proc_info); + CLEAR(self_exe); + + status = GetModuleFileName(NULL, self_exe, sizeof(self_exe)); + if (status == 0 || status == sizeof(self_exe)) { - msg (M_WARN|M_ERRNO, "fork_to_self: CreateProcess failed: cannot get module name via GetModuleFileName"); - goto done; + msg(M_WARN|M_ERRNO, "fork_to_self: CreateProcess failed: cannot get module name via GetModuleFileName"); + goto done; } - /* fill in STARTUPINFO struct */ - GetStartupInfo(&start_info); - start_info.cb = sizeof(start_info); - start_info.dwFlags = STARTF_USESHOWWINDOW; - start_info.wShowWindow = SW_HIDE; + /* fill in STARTUPINFO struct */ + GetStartupInfo(&start_info); + start_info.cb = sizeof(start_info); + start_info.dwFlags = STARTF_USESHOWWINDOW; + start_info.wShowWindow = SW_HIDE; - if (CreateProcess (self_exe, cl, NULL, NULL, FALSE, 0, NULL, NULL, &start_info, &proc_info)) + if (CreateProcess(self_exe, cl, NULL, NULL, FALSE, 0, NULL, NULL, &start_info, &proc_info)) { - CloseHandle (proc_info.hThread); - CloseHandle (proc_info.hProcess); + CloseHandle(proc_info.hThread); + CloseHandle(proc_info.hProcess); } - else + else { - msg (M_WARN|M_ERRNO, "fork_to_self: CreateProcess failed: %s", cmdline); + msg(M_WARN|M_ERRNO, "fork_to_self: CreateProcess failed: %s", cmdline); } - done: - free (cl); +done: + free(cl); } char * -get_win_sys_path (void) +get_win_sys_path(void) { - ASSERT (win_sys_path); - return win_sys_path; + ASSERT(win_sys_path); + return win_sys_path; } void -set_win_sys_path (const char *newpath, struct env_set *es) +set_win_sys_path(const char *newpath, struct env_set *es) { - free (win_sys_path); - win_sys_path = string_alloc (newpath, NULL); - setenv_str (es, SYS_PATH_ENV_VAR_NAME, win_sys_path); /* route.exe needs this */ + free(win_sys_path); + win_sys_path = string_alloc(newpath, NULL); + setenv_str(es, SYS_PATH_ENV_VAR_NAME, win_sys_path); /* route.exe needs this */ } void -set_win_sys_path_via_env (struct env_set *es) +set_win_sys_path_via_env(struct env_set *es) { - char buf[256]; - DWORD status = GetEnvironmentVariable (SYS_PATH_ENV_VAR_NAME, buf, sizeof(buf)); - if (!status) - msg (M_ERR, "Cannot find environmental variable %s", SYS_PATH_ENV_VAR_NAME); - if (status > sizeof (buf) - 1) - msg (M_FATAL, "String overflow attempting to read environmental variable %s", SYS_PATH_ENV_VAR_NAME); - set_win_sys_path (buf, es); + char buf[256]; + DWORD status = GetEnvironmentVariable(SYS_PATH_ENV_VAR_NAME, buf, sizeof(buf)); + if (!status) + { + msg(M_ERR, "Cannot find environmental variable %s", SYS_PATH_ENV_VAR_NAME); + } + if (status > sizeof(buf) - 1) + { + msg(M_FATAL, "String overflow attempting to read environmental variable %s", SYS_PATH_ENV_VAR_NAME); + } + set_win_sys_path(buf, es); } const char * win_get_tempdir() { - static char tmpdir[MAX_PATH]; - WCHAR wtmpdir[MAX_PATH]; + static char tmpdir[MAX_PATH]; + WCHAR wtmpdir[MAX_PATH]; - if (!GetTempPathW(_countof(wtmpdir), wtmpdir)) + if (!GetTempPathW(_countof(wtmpdir), wtmpdir)) { - /* Warn if we can't find a valid temporary directory, which should - * be unlikely. - */ - msg (M_WARN, "Could not find a suitable temporary directory." - " (GetTempPath() failed). Consider using --tmp-dir"); - return NULL; + /* Warn if we can't find a valid temporary directory, which should + * be unlikely. + */ + msg(M_WARN, "Could not find a suitable temporary directory." + " (GetTempPath() failed). Consider using --tmp-dir"); + return NULL; } - if (WideCharToMultiByte (CP_UTF8, 0, wtmpdir, -1, NULL, 0, NULL, NULL) > sizeof (tmpdir)) + if (WideCharToMultiByte(CP_UTF8, 0, wtmpdir, -1, NULL, 0, NULL, NULL) > sizeof(tmpdir)) { - msg (M_WARN, "Could not get temporary directory. Path is too long." - " Consider using --tmp-dir"); - return NULL; + msg(M_WARN, "Could not get temporary directory. Path is too long." + " Consider using --tmp-dir"); + return NULL; } - WideCharToMultiByte (CP_UTF8, 0, wtmpdir, -1, tmpdir, sizeof (tmpdir), NULL, NULL); - return tmpdir; + WideCharToMultiByte(CP_UTF8, 0, wtmpdir, -1, tmpdir, sizeof(tmpdir), NULL, NULL); + return tmpdir; } static bool -win_block_dns_service (bool add, int index, const HANDLE pipe) +win_block_dns_service(bool add, int index, const HANDLE pipe) { - DWORD len; - bool ret = false; - ack_message_t ack; - struct gc_arena gc = gc_new (); - - block_dns_message_t data = { - .header = { - (add ? msg_add_block_dns : msg_del_block_dns), - sizeof (block_dns_message_t), - 0 }, - .iface = { .index = index, .name = "" } - }; - - if (!WriteFile (pipe, &data, sizeof (data), &len, NULL) || - !ReadFile (pipe, &ack, sizeof (ack), &len, NULL)) + DWORD len; + bool ret = false; + ack_message_t ack; + struct gc_arena gc = gc_new(); + + block_dns_message_t data = { + .header = { + (add ? msg_add_block_dns : msg_del_block_dns), + sizeof(block_dns_message_t), + 0 + }, + .iface = { .index = index, .name = "" } + }; + + if (!WriteFile(pipe, &data, sizeof(data), &len, NULL) + || !ReadFile(pipe, &ack, sizeof(ack), &len, NULL)) { - msg (M_WARN, "Block_DNS: could not talk to service: %s [%lu]", - strerror_win32 (GetLastError (), &gc), GetLastError ()); - goto out; + msg(M_WARN, "Block_DNS: could not talk to service: %s [%lu]", + strerror_win32(GetLastError(), &gc), GetLastError()); + goto out; } - if (ack.error_number != NO_ERROR) + if (ack.error_number != NO_ERROR) { - msg (M_WARN, "Block_DNS: %s block dns filters using service failed: %s [status=0x%x if_index=%d]", - (add ? "adding" : "deleting"), strerror_win32 (ack.error_number, &gc), - ack.error_number, data.iface.index); - goto out; + msg(M_WARN, "Block_DNS: %s block dns filters using service failed: %s [status=0x%x if_index=%d]", + (add ? "adding" : "deleting"), strerror_win32(ack.error_number, &gc), + ack.error_number, data.iface.index); + goto out; } - ret = true; - msg (M_INFO, "%s outside dns using service succeeded.", (add ? "Blocking" : "Unblocking")); + ret = true; + msg(M_INFO, "%s outside dns using service succeeded.", (add ? "Blocking" : "Unblocking")); out: - gc_free (&gc); - return ret; + gc_free(&gc); + return ret; } static void -block_dns_msg_handler (DWORD err, const char *msg) +block_dns_msg_handler(DWORD err, const char *msg) { - struct gc_arena gc = gc_new (); + struct gc_arena gc = gc_new(); - if (err == 0) + if (err == 0) { - msg (M_INFO, "%s", msg); + msg(M_INFO, "%s", msg); } - else + else { - msg (M_WARN, "Error in add_block_dns_filters(): %s : %s [status=0x%lx]", - msg, strerror_win32 (err, &gc), err); + msg(M_WARN, "Error in add_block_dns_filters(): %s : %s [status=0x%lx]", + msg, strerror_win32(err, &gc), err); } - gc_free (&gc); + gc_free(&gc); } bool -win_wfp_block_dns (const NET_IFINDEX index, const HANDLE msg_channel) +win_wfp_block_dns(const NET_IFINDEX index, const HANDLE msg_channel) { - WCHAR openvpnpath[MAX_PATH]; - bool ret = false; - DWORD status; + WCHAR openvpnpath[MAX_PATH]; + bool ret = false; + DWORD status; - if (msg_channel) + if (msg_channel) { - dmsg (D_LOW, "Using service to add block dns filters"); - ret = win_block_dns_service (true, index, msg_channel); - goto out; + dmsg(D_LOW, "Using service to add block dns filters"); + ret = win_block_dns_service(true, index, msg_channel); + goto out; } - status = GetModuleFileNameW (NULL, openvpnpath, sizeof(openvpnpath)); - if (status == 0 || status == sizeof(openvpnpath)) + status = GetModuleFileNameW(NULL, openvpnpath, sizeof(openvpnpath)); + if (status == 0 || status == sizeof(openvpnpath)) { - msg (M_WARN|M_ERRNO, "block_dns: cannot get executable path"); - goto out; + msg(M_WARN|M_ERRNO, "block_dns: cannot get executable path"); + goto out; } - status = add_block_dns_filters (&m_hEngineHandle, index, openvpnpath, - block_dns_msg_handler); - ret = (status == 0); + status = add_block_dns_filters(&m_hEngineHandle, index, openvpnpath, + block_dns_msg_handler); + ret = (status == 0); out: - return ret; + return ret; } bool win_wfp_uninit(const HANDLE msg_channel) { - dmsg (D_LOW, "Uninitializing WFP"); + dmsg(D_LOW, "Uninitializing WFP"); if (msg_channel) - { - msg (D_LOW, "Using service to delete block dns filters"); - win_block_dns_service (false, -1, msg_channel); - } + { + msg(D_LOW, "Using service to delete block dns filters"); + win_block_dns_service(false, -1, msg_channel); + } else - { - delete_block_dns_filters (m_hEngineHandle); + { + delete_block_dns_filters(m_hEngineHandle); m_hEngineHandle = NULL; - } + } return true; } @@ -1208,7 +1364,7 @@ win32_version_info() { if (!IsWindowsXPOrGreater()) { - msg (M_FATAL, "Error: Windows version must be XP or greater."); + msg(M_FATAL, "Error: Windows version must be XP or greater."); } if (!IsWindowsVistaOrGreater()) @@ -1235,13 +1391,13 @@ bool win32_is_64bit() { #if defined(_WIN64) - return true; // 64-bit programs run only on Win64 + return true; /* 64-bit programs run only on Win64 */ #elif defined(_WIN32) - // 32-bit programs run on both 32-bit and 64-bit Windows + /* 32-bit programs run on both 32-bit and 64-bit Windows */ BOOL f64 = FALSE; return IsWow64Process(GetCurrentProcess(), &f64) && f64; -#else - return false; // Win64 does not support Win16 +#else /* if defined(_WIN64) */ + return false; /* Win64 does not support Win16 */ #endif } @@ -1249,31 +1405,35 @@ const char * win32_version_string(struct gc_arena *gc, bool add_name) { int version = win32_version_info(); - struct buffer out = alloc_buf_gc (256, gc); + struct buffer out = alloc_buf_gc(256, gc); switch (version) { case WIN_XP: - buf_printf (&out, "5.1%s", add_name ? " (Windows XP)" : ""); + buf_printf(&out, "5.1%s", add_name ? " (Windows XP)" : ""); break; + case WIN_VISTA: - buf_printf (&out, "6.0%s", add_name ? " (Windows Vista)" : ""); + buf_printf(&out, "6.0%s", add_name ? " (Windows Vista)" : ""); break; + case WIN_7: - buf_printf (&out, "6.1%s", add_name ? " (Windows 7)" : ""); + buf_printf(&out, "6.1%s", add_name ? " (Windows 7)" : ""); break; + case WIN_8: - buf_printf (&out, "6.2%s", add_name ? " (Windows 8 or greater)" : ""); + buf_printf(&out, "6.2%s", add_name ? " (Windows 8 or greater)" : ""); break; + default: - msg (M_NONFATAL, "Unknown Windows version: %d", version); - buf_printf (&out, "0.0%s", add_name ? " (unknown)" : ""); + msg(M_NONFATAL, "Unknown Windows version: %d", version); + buf_printf(&out, "0.0%s", add_name ? " (unknown)" : ""); break; } - buf_printf (&out, win32_is_64bit() ? " 64bit" : " 32bit"); + buf_printf(&out, win32_is_64bit() ? " 64bit" : " 32bit"); return (const char *)out.data; } -#endif +#endif /* ifdef _WIN32 */ diff --git a/src/openvpn/win32.h b/src/openvpn/win32.h index 11e42f4b4eb..5d2e1fb13bb 100644 --- a/src/openvpn/win32.h +++ b/src/openvpn/win32.h @@ -43,18 +43,19 @@ /* MSVC headers do not define this macro, so do it here */ #ifndef IN6_ARE_ADDR_EQUAL #define IN6_ARE_ADDR_EQUAL(a,b) \ - (memcmp ((const void*)(a), (const void*)(b), sizeof (struct in6_addr)) == 0) + (memcmp((const void *)(a), (const void *)(b), sizeof(struct in6_addr)) == 0) #endif -void init_win32 (void); -void uninit_win32 (void); +void init_win32(void); -void set_pause_exit_win32 (void); +void uninit_win32(void); + +void set_pause_exit_win32(void); struct security_attributes { - SECURITY_ATTRIBUTES sa; - SECURITY_DESCRIPTOR sd; + SECURITY_ATTRIBUTES sa; + SECURITY_DESCRIPTOR sd; }; #define HANDLE_DEFINED(h) ((h) != NULL && (h) != INVALID_HANDLE_VALUE) @@ -64,13 +65,13 @@ struct security_attributes */ struct window_title { - bool saved; - char old_window_title [256]; + bool saved; + char old_window_title [256]; }; struct rw_handle { - HANDLE read; - HANDLE write; + HANDLE read; + HANDLE write; }; /* @@ -81,14 +82,16 @@ struct rw_handle { #define NE32_WRITE_EVENT (1<<1) static inline bool -defined_net_event_win32 (const struct rw_handle *event) +defined_net_event_win32(const struct rw_handle *event) { - return event->read != NULL; + return event->read != NULL; } -void init_net_event_win32 (struct rw_handle *event, long network_events, socket_descriptor_t sd, unsigned int flags); -long reset_net_event_win32 (struct rw_handle *event, socket_descriptor_t sd); -void close_net_event_win32 (struct rw_handle *event, socket_descriptor_t sd, unsigned int flags); +void init_net_event_win32(struct rw_handle *event, long network_events, socket_descriptor_t sd, unsigned int flags); + +long reset_net_event_win32(struct rw_handle *event, socket_descriptor_t sd); + +void close_net_event_win32(struct rw_handle *event, socket_descriptor_t sd, unsigned int flags); /* * A stateful variant of the net_event_win32 functions above @@ -96,124 +99,132 @@ void close_net_event_win32 (struct rw_handle *event, socket_descriptor_t sd, uns struct net_event_win32 { - struct rw_handle handle; - socket_descriptor_t sd; - long event_mask; + struct rw_handle handle; + socket_descriptor_t sd; + long event_mask; }; -void net_event_win32_init (struct net_event_win32 *ne); -void net_event_win32_start (struct net_event_win32 *ne, long network_events, socket_descriptor_t sd); -void net_event_win32_reset (struct net_event_win32 *ne); -void net_event_win32_reset_write (struct net_event_win32 *ne); -void net_event_win32_stop (struct net_event_win32 *ne); -void net_event_win32_close (struct net_event_win32 *ne); +void net_event_win32_init(struct net_event_win32 *ne); + +void net_event_win32_start(struct net_event_win32 *ne, long network_events, socket_descriptor_t sd); + +void net_event_win32_reset(struct net_event_win32 *ne); + +void net_event_win32_reset_write(struct net_event_win32 *ne); + +void net_event_win32_stop(struct net_event_win32 *ne); + +void net_event_win32_close(struct net_event_win32 *ne); static inline bool -net_event_win32_defined (const struct net_event_win32 *ne) +net_event_win32_defined(const struct net_event_win32 *ne) { - return defined_net_event_win32 (&ne->handle); + return defined_net_event_win32(&ne->handle); } static inline struct rw_handle * -net_event_win32_get_event (struct net_event_win32 *ne) +net_event_win32_get_event(struct net_event_win32 *ne) { - return &ne->handle; + return &ne->handle; } static inline long -net_event_win32_get_event_mask (const struct net_event_win32 *ne) +net_event_win32_get_event_mask(const struct net_event_win32 *ne) { - return ne->event_mask; + return ne->event_mask; } static inline void -net_event_win32_clear_selected_events (struct net_event_win32 *ne, long selected_events) +net_event_win32_clear_selected_events(struct net_event_win32 *ne, long selected_events) { - ne->event_mask &= ~selected_events; + ne->event_mask &= ~selected_events; } /* * Signal handling */ struct win32_signal { -# define WSO_MODE_UNDEF 0 -# define WSO_MODE_SERVICE 1 -# define WSO_MODE_CONSOLE 2 - int mode; - struct rw_handle in; - DWORD console_mode_save; - bool console_mode_save_defined; +#define WSO_MODE_UNDEF 0 +#define WSO_MODE_SERVICE 1 +#define WSO_MODE_CONSOLE 2 + int mode; + struct rw_handle in; + DWORD console_mode_save; + bool console_mode_save_defined; }; extern struct win32_signal win32_signal; /* static/global */ extern struct window_title window_title; /* static/global */ -void win32_signal_clear (struct win32_signal *ws); +void win32_signal_clear(struct win32_signal *ws); /* win32_signal_open startup type */ #define WSO_NOFORCE 0 #define WSO_FORCE_SERVICE 1 #define WSO_FORCE_CONSOLE 2 -void win32_signal_open (struct win32_signal *ws, - int force, /* set to WSO force parm */ - const char *exit_event_name, - bool exit_event_initial_state); +void win32_signal_open(struct win32_signal *ws, + int force, /* set to WSO force parm */ + const char *exit_event_name, + bool exit_event_initial_state); -void win32_signal_close (struct win32_signal *ws); +void win32_signal_close(struct win32_signal *ws); -int win32_signal_get (struct win32_signal *ws); +int win32_signal_get(struct win32_signal *ws); -void win32_pause (struct win32_signal *ws); +void win32_pause(struct win32_signal *ws); -bool win32_service_interrupt (struct win32_signal *ws); +bool win32_service_interrupt(struct win32_signal *ws); /* * Set the text on the window title bar */ -void window_title_clear (struct window_title *wt); -void window_title_save (struct window_title *wt); -void window_title_restore (const struct window_title *wt); -void window_title_generate (const char *title); +void window_title_clear(struct window_title *wt); + +void window_title_save(struct window_title *wt); + +void window_title_restore(const struct window_title *wt); -/* +void window_title_generate(const char *title); + +/* * We try to do all Win32 I/O using overlapped * (i.e. asynchronous) I/O for a performance win. */ struct overlapped_io { -# define IOSTATE_INITIAL 0 -# define IOSTATE_QUEUED 1 /* overlapped I/O has been queued */ -# define IOSTATE_IMMEDIATE_RETURN 2 /* I/O function returned immediately without queueing */ - int iostate; - OVERLAPPED overlapped; - DWORD size; - DWORD flags; - int status; - bool addr_defined; - union { - struct sockaddr_in addr; - struct sockaddr_in6 addr6; - }; - int addrlen; - struct buffer buf_init; - struct buffer buf; +#define IOSTATE_INITIAL 0 +#define IOSTATE_QUEUED 1 /* overlapped I/O has been queued */ +#define IOSTATE_IMMEDIATE_RETURN 2 /* I/O function returned immediately without queueing */ + int iostate; + OVERLAPPED overlapped; + DWORD size; + DWORD flags; + int status; + bool addr_defined; + union { + struct sockaddr_in addr; + struct sockaddr_in6 addr6; + }; + int addrlen; + struct buffer buf_init; + struct buffer buf; }; -void overlapped_io_init (struct overlapped_io *o, - const struct frame *frame, - BOOL event_state, - bool tuntap_buffer); +void overlapped_io_init(struct overlapped_io *o, + const struct frame *frame, + BOOL event_state, + bool tuntap_buffer); -void overlapped_io_close (struct overlapped_io *o); +void overlapped_io_close(struct overlapped_io *o); static inline bool -overlapped_io_active (struct overlapped_io *o) +overlapped_io_active(struct overlapped_io *o) { - return o->iostate == IOSTATE_QUEUED || o->iostate == IOSTATE_IMMEDIATE_RETURN; + return o->iostate == IOSTATE_QUEUED || o->iostate == IOSTATE_IMMEDIATE_RETURN; } -char *overlapped_io_state_ascii (const struct overlapped_io *o); +char *overlapped_io_state_ascii(const struct overlapped_io *o); /* * Use to control access to resources that only one @@ -223,16 +234,20 @@ char *overlapped_io_state_ascii (const struct overlapped_io *o); struct semaphore { - const char *name; - bool locked; - HANDLE hand; + const char *name; + bool locked; + HANDLE hand; }; -void semaphore_clear (struct semaphore *s); -void semaphore_open (struct semaphore *s, const char *name); -bool semaphore_lock (struct semaphore *s, int timeout_milliseconds); -void semaphore_release (struct semaphore *s); -void semaphore_close (struct semaphore *s); +void semaphore_clear(struct semaphore *s); + +void semaphore_open(struct semaphore *s, const char *name); + +bool semaphore_lock(struct semaphore *s, int timeout_milliseconds); + +void semaphore_release(struct semaphore *s); + +void semaphore_close(struct semaphore *s); /* * Special global semaphore used to protect network @@ -243,35 +258,41 @@ void semaphore_close (struct semaphore *s); */ extern struct semaphore netcmd_semaphore; -void netcmd_semaphore_init (void); -void netcmd_semaphore_close (void); -void netcmd_semaphore_lock (void); -void netcmd_semaphore_release (void); +void netcmd_semaphore_init(void); + +void netcmd_semaphore_close(void); + +void netcmd_semaphore_lock(void); + +void netcmd_semaphore_release(void); /* Set Win32 security attributes structure to allow all access */ -bool init_security_attributes_allow_all (struct security_attributes *obj); +bool init_security_attributes_allow_all(struct security_attributes *obj); /* return true if filename is safe to be used on Windows */ -bool win_safe_filename (const char *fn); +bool win_safe_filename(const char *fn); /* add constant environmental variables needed by Windows */ struct env_set; /* get and set the current windows system path */ -void set_win_sys_path (const char *newpath, struct env_set *es); -void set_win_sys_path_via_env (struct env_set *es); -char *get_win_sys_path (void); +void set_win_sys_path(const char *newpath, struct env_set *es); + +void set_win_sys_path_via_env(struct env_set *es); + +char *get_win_sys_path(void); /* call self in a subprocess */ -void fork_to_self (const char *cmdline); +void fork_to_self(const char *cmdline); /* Find temporary directory */ const char *win_get_tempdir(); /* Convert a string from UTF-8 to UCS-2 */ -WCHAR *wide_string (const char* utf8, struct gc_arena *gc); +WCHAR *wide_string(const char *utf8, struct gc_arena *gc); bool win_wfp_block_dns(const NET_IFINDEX index, const HANDLE msg_channel); + bool win_wfp_uninit(const HANDLE msg_channel); #define WIN_XP 0 @@ -282,10 +303,10 @@ bool win_wfp_uninit(const HANDLE msg_channel); int win32_version_info(); /* -String representation of Windows version number and name, see -https://msdn.microsoft.com/en-us/library/windows/desktop/ms724832(v=vs.85).aspx -*/ -const char * win32_version_string(struct gc_arena *gc, bool add_name); + * String representation of Windows version number and name, see + * https://msdn.microsoft.com/en-us/library/windows/desktop/ms724832(v=vs.85).aspx + */ +const char *win32_version_string(struct gc_arena *gc, bool add_name); -#endif -#endif +#endif /* ifndef OPENVPN_WIN32_H */ +#endif /* ifdef _WIN32 */ diff --git a/src/openvpnserv/automatic.c b/src/openvpnserv/automatic.c index aa7618f4724..dc57cada3a4 100644 --- a/src/openvpnserv/automatic.c +++ b/src/openvpnserv/automatic.c @@ -48,17 +48,17 @@ static SERVICE_STATUS_HANDLE service; static SERVICE_STATUS status; openvpn_service_t automatic_service = { - automatic, - TEXT(PACKAGE_NAME "ServiceLegacy"), - TEXT(PACKAGE_NAME " Legacy Service"), - TEXT(SERVICE_DEPENDENCIES), - SERVICE_DEMAND_START + automatic, + TEXT(PACKAGE_NAME "ServiceLegacy"), + TEXT(PACKAGE_NAME " Legacy Service"), + TEXT(SERVICE_DEPENDENCIES), + SERVICE_DEMAND_START }; struct security_attributes { - SECURITY_ATTRIBUTES sa; - SECURITY_DESCRIPTOR sd; + SECURITY_ATTRIBUTES sa; + SECURITY_DESCRIPTOR sd; }; /* @@ -74,18 +74,22 @@ static HANDLE exit_event = NULL; bool -init_security_attributes_allow_all (struct security_attributes *obj) +init_security_attributes_allow_all(struct security_attributes *obj) { - CLEAR (*obj); + CLEAR(*obj); - obj->sa.nLength = sizeof (SECURITY_ATTRIBUTES); - obj->sa.lpSecurityDescriptor = &obj->sd; - obj->sa.bInheritHandle = TRUE; - if (!InitializeSecurityDescriptor (&obj->sd, SECURITY_DESCRIPTOR_REVISION)) - return false; - if (!SetSecurityDescriptorDacl (&obj->sd, TRUE, NULL, FALSE)) - return false; - return true; + obj->sa.nLength = sizeof(SECURITY_ATTRIBUTES); + obj->sa.lpSecurityDescriptor = &obj->sd; + obj->sa.bInheritHandle = TRUE; + if (!InitializeSecurityDescriptor(&obj->sd, SECURITY_DESCRIPTOR_REVISION)) + { + return false; + } + if (!SetSecurityDescriptorDacl(&obj->sd, TRUE, NULL, FALSE)) + { + return false; + } + return true; } /* @@ -98,318 +102,342 @@ init_security_attributes_allow_all (struct security_attributes *obj) #define EXIT_EVENT_NAME TEXT(PACKAGE "_exit_1") HANDLE -create_event (LPCTSTR name, bool allow_all, bool initial_state, bool manual_reset) +create_event(LPCTSTR name, bool allow_all, bool initial_state, bool manual_reset) { - if (allow_all) + if (allow_all) { - struct security_attributes sa; - if (!init_security_attributes_allow_all (&sa)) - return NULL; - return CreateEvent (&sa.sa, (BOOL)manual_reset, (BOOL)initial_state, name); + struct security_attributes sa; + if (!init_security_attributes_allow_all(&sa)) + { + return NULL; + } + return CreateEvent(&sa.sa, (BOOL)manual_reset, (BOOL)initial_state, name); + } + else + { + return CreateEvent(NULL, (BOOL)manual_reset, (BOOL)initial_state, name); } - else - return CreateEvent (NULL, (BOOL)manual_reset, (BOOL)initial_state, name); } void -close_if_open (HANDLE h) +close_if_open(HANDLE h) { - if (h != NULL) - CloseHandle (h); + if (h != NULL) + { + CloseHandle(h); + } } static bool -match (const WIN32_FIND_DATA *find, LPCTSTR ext) +match(const WIN32_FIND_DATA *find, LPCTSTR ext) { - int i; + int i; - if (find->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - return false; + if (find->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + return false; + } - if (!_tcslen (ext)) - return true; + if (!_tcslen(ext)) + { + return true; + } - i = _tcslen (find->cFileName) - _tcslen (ext) - 1; - if (i < 1) - return false; + i = _tcslen(find->cFileName) - _tcslen(ext) - 1; + if (i < 1) + { + return false; + } - return find->cFileName[i] == '.' && !_tcsicmp (find->cFileName + i + 1, ext); + return find->cFileName[i] == '.' && !_tcsicmp(find->cFileName + i + 1, ext); } /* * Modify the extension on a filename. */ static bool -modext (LPTSTR dest, int size, LPCTSTR src, LPCTSTR newext) +modext(LPTSTR dest, int size, LPCTSTR src, LPCTSTR newext) { - int i; + int i; - if (size > 0 && (_tcslen (src) + 1) <= size) + if (size > 0 && (_tcslen(src) + 1) <= size) { - _tcscpy (dest, src); - dest [size - 1] = TEXT('\0'); - i = _tcslen (dest); - while (--i >= 0) + _tcscpy(dest, src); + dest [size - 1] = TEXT('\0'); + i = _tcslen(dest); + while (--i >= 0) { - if (dest[i] == TEXT('\\')) - break; - if (dest[i] == TEXT('.')) + if (dest[i] == TEXT('\\')) + { + break; + } + if (dest[i] == TEXT('.')) { - dest[i] = TEXT('\0'); - break; + dest[i] = TEXT('\0'); + break; } } - if (_tcslen (dest) + _tcslen(newext) + 2 <= size) + if (_tcslen(dest) + _tcslen(newext) + 2 <= size) { - _tcscat (dest, TEXT(".")); - _tcscat (dest, newext); - return true; + _tcscat(dest, TEXT(".")); + _tcscat(dest, newext); + return true; } - dest[0] = TEXT('\0'); + dest[0] = TEXT('\0'); } - return false; + return false; } static DWORD WINAPI -ServiceCtrlAutomatic (DWORD ctrl_code, DWORD event, LPVOID data, LPVOID ctx) +ServiceCtrlAutomatic(DWORD ctrl_code, DWORD event, LPVOID data, LPVOID ctx) { - SERVICE_STATUS *status = ctx; - switch (ctrl_code) + SERVICE_STATUS *status = ctx; + switch (ctrl_code) { - case SERVICE_CONTROL_STOP: - status->dwCurrentState = SERVICE_STOP_PENDING; - ReportStatusToSCMgr (service, status); - if (exit_event) - SetEvent (exit_event); - return NO_ERROR; - - case SERVICE_CONTROL_INTERROGATE: - return NO_ERROR; - - default: - return ERROR_CALL_NOT_IMPLEMENTED; + case SERVICE_CONTROL_STOP: + status->dwCurrentState = SERVICE_STOP_PENDING; + ReportStatusToSCMgr(service, status); + if (exit_event) + { + SetEvent(exit_event); + } + return NO_ERROR; + + case SERVICE_CONTROL_INTERROGATE: + return NO_ERROR; + + default: + return ERROR_CALL_NOT_IMPLEMENTED; } } VOID WINAPI -ServiceStartAutomatic (DWORD dwArgc, LPTSTR *lpszArgv) +ServiceStartAutomatic(DWORD dwArgc, LPTSTR *lpszArgv) { - DWORD error = NO_ERROR; - settings_t settings; + DWORD error = NO_ERROR; + settings_t settings; - service = RegisterServiceCtrlHandlerEx (automatic_service.name, ServiceCtrlAutomatic, &status); - if (!service) - return; + service = RegisterServiceCtrlHandlerEx(automatic_service.name, ServiceCtrlAutomatic, &status); + if (!service) + { + return; + } - status.dwServiceType = SERVICE_WIN32_SHARE_PROCESS; - status.dwCurrentState = SERVICE_START_PENDING; - status.dwServiceSpecificExitCode = NO_ERROR; - status.dwWin32ExitCode = NO_ERROR; - status.dwWaitHint = 3000; + status.dwServiceType = SERVICE_WIN32_SHARE_PROCESS; + status.dwCurrentState = SERVICE_START_PENDING; + status.dwServiceSpecificExitCode = NO_ERROR; + status.dwWin32ExitCode = NO_ERROR; + status.dwWaitHint = 3000; - if (!ReportStatusToSCMgr(service, &status)) + if (!ReportStatusToSCMgr(service, &status)) { - MsgToEventLog (M_ERR, TEXT("ReportStatusToSCMgr #1 failed")); - goto finish; + MsgToEventLog(M_ERR, TEXT("ReportStatusToSCMgr #1 failed")); + goto finish; } - /* - * Create our exit event - */ - exit_event = create_event (EXIT_EVENT_NAME, false, false, true); - if (!exit_event) + /* + * Create our exit event + */ + exit_event = create_event(EXIT_EVENT_NAME, false, false, true); + if (!exit_event) { - MsgToEventLog (M_ERR, TEXT("CreateEvent failed")); - goto finish; + MsgToEventLog(M_ERR, TEXT("CreateEvent failed")); + goto finish; } - /* - * If exit event is already signaled, it means we were not - * shut down properly. - */ - if (WaitForSingleObject (exit_event, 0) != WAIT_TIMEOUT) + /* + * If exit event is already signaled, it means we were not + * shut down properly. + */ + if (WaitForSingleObject(exit_event, 0) != WAIT_TIMEOUT) { - MsgToEventLog (M_ERR, TEXT("Exit event is already signaled -- we were not shut down properly")); - goto finish; + MsgToEventLog(M_ERR, TEXT("Exit event is already signaled -- we were not shut down properly")); + goto finish; } - if (!ReportStatusToSCMgr(service, &status)) + if (!ReportStatusToSCMgr(service, &status)) { - MsgToEventLog (M_ERR, TEXT("ReportStatusToSCMgr #2 failed")); - goto finish; + MsgToEventLog(M_ERR, TEXT("ReportStatusToSCMgr #2 failed")); + goto finish; } - /* - * Read info from registry in key HKLM\SOFTWARE\OpenVPN - */ - error = GetOpenvpnSettings (&settings); - if (error != ERROR_SUCCESS) - goto finish; - - /* - * Instantiate an OpenVPN process for each configuration - * file found. - */ - { - WIN32_FIND_DATA find_obj; - HANDLE find_handle; - BOOL more_files; - TCHAR find_string[MAX_PATH]; - - openvpn_sntprintf (find_string, MAX_PATH, TEXT("%s\\*"), settings.config_dir); - - find_handle = FindFirstFile (find_string, &find_obj); - if (find_handle == INVALID_HANDLE_VALUE) - { - MsgToEventLog (M_ERR, TEXT("Cannot get configuration file list using: %s"), find_string); + /* + * Read info from registry in key HKLM\SOFTWARE\OpenVPN + */ + error = GetOpenvpnSettings(&settings); + if (error != ERROR_SUCCESS) + { goto finish; - } + } /* - * Loop over each config file + * Instantiate an OpenVPN process for each configuration + * file found. */ - do { - HANDLE log_handle = NULL; - STARTUPINFO start_info; - PROCESS_INFORMATION proc_info; - struct security_attributes sa; - TCHAR log_file[MAX_PATH]; - TCHAR log_path[MAX_PATH]; - TCHAR command_line[256]; - - CLEAR (start_info); - CLEAR (proc_info); - CLEAR (sa); - - if (!ReportStatusToSCMgr(service, &status)) + { + WIN32_FIND_DATA find_obj; + HANDLE find_handle; + BOOL more_files; + TCHAR find_string[MAX_PATH]; + + openvpn_sntprintf(find_string, MAX_PATH, TEXT("%s\\*"), settings.config_dir); + + find_handle = FindFirstFile(find_string, &find_obj); + if (find_handle == INVALID_HANDLE_VALUE) { - MsgToEventLog (M_ERR, TEXT("ReportStatusToSCMgr #3 failed")); - FindClose (find_handle); - goto finish; + MsgToEventLog(M_ERR, TEXT("Cannot get configuration file list using: %s"), find_string); + goto finish; } - /* does file have the correct type and extension? */ - if (match (&find_obj, settings.ext_string)) - { - /* get log file pathname */ - if (!modext (log_file, _countof (log_file), find_obj.cFileName, TEXT("log"))) + /* + * Loop over each config file + */ + do { + HANDLE log_handle = NULL; + STARTUPINFO start_info; + PROCESS_INFORMATION proc_info; + struct security_attributes sa; + TCHAR log_file[MAX_PATH]; + TCHAR log_path[MAX_PATH]; + TCHAR command_line[256]; + + CLEAR(start_info); + CLEAR(proc_info); + CLEAR(sa); + + if (!ReportStatusToSCMgr(service, &status)) { - MsgToEventLog (M_ERR, TEXT("Cannot construct logfile name based on: %s"), find_obj.cFileName); - FindClose (find_handle); - goto finish; + MsgToEventLog(M_ERR, TEXT("ReportStatusToSCMgr #3 failed")); + FindClose(find_handle); + goto finish; } - openvpn_sntprintf (log_path, _countof (log_path), - TEXT("%s\\%s"), settings.log_dir, log_file); - - /* construct command line */ - openvpn_sntprintf (command_line, _countof (command_line), TEXT(PACKAGE " --service %s 1 --config \"%s\""), - EXIT_EVENT_NAME, - find_obj.cFileName); - /* Make security attributes struct for logfile handle so it can - be inherited. */ - if (!init_security_attributes_allow_all (&sa)) + /* does file have the correct type and extension? */ + if (match(&find_obj, settings.ext_string)) { - error = MsgToEventLog (M_SYSERR, TEXT("InitializeSecurityDescriptor start_" PACKAGE " failed")); - goto finish; - } + /* get log file pathname */ + if (!modext(log_file, _countof(log_file), find_obj.cFileName, TEXT("log"))) + { + MsgToEventLog(M_ERR, TEXT("Cannot construct logfile name based on: %s"), find_obj.cFileName); + FindClose(find_handle); + goto finish; + } + openvpn_sntprintf(log_path, _countof(log_path), + TEXT("%s\\%s"), settings.log_dir, log_file); - /* open logfile as stdout/stderr for soon-to-be-spawned subprocess */ - log_handle = CreateFile (log_path, - GENERIC_WRITE, - FILE_SHARE_READ, - &sa.sa, - settings.append ? OPEN_ALWAYS : CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL, - NULL); + /* construct command line */ + openvpn_sntprintf(command_line, _countof(command_line), TEXT(PACKAGE " --service %s 1 --config \"%s\""), + EXIT_EVENT_NAME, + find_obj.cFileName); - if (log_handle == INVALID_HANDLE_VALUE) - { - error = MsgToEventLog (M_SYSERR, TEXT("Cannot open logfile: %s"), log_path); - FindClose (find_handle); - goto finish; - } + /* Make security attributes struct for logfile handle so it can + * be inherited. */ + if (!init_security_attributes_allow_all(&sa)) + { + error = MsgToEventLog(M_SYSERR, TEXT("InitializeSecurityDescriptor start_" PACKAGE " failed")); + goto finish; + } - /* append to logfile? */ - if (settings.append) - { - if (SetFilePointer (log_handle, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER) + /* open logfile as stdout/stderr for soon-to-be-spawned subprocess */ + log_handle = CreateFile(log_path, + GENERIC_WRITE, + FILE_SHARE_READ, + &sa.sa, + settings.append ? OPEN_ALWAYS : CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if (log_handle == INVALID_HANDLE_VALUE) { - error = MsgToEventLog (M_SYSERR, TEXT("Cannot seek to end of logfile: %s"), log_path); - FindClose (find_handle); - goto finish; + error = MsgToEventLog(M_SYSERR, TEXT("Cannot open logfile: %s"), log_path); + FindClose(find_handle); + goto finish; } - } - /* fill in STARTUPINFO struct */ - GetStartupInfo(&start_info); - start_info.cb = sizeof(start_info); - start_info.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW; - start_info.wShowWindow = SW_HIDE; - start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE); - start_info.hStdOutput = start_info.hStdError = log_handle; - - /* create an OpenVPN process for one config file */ - if (!CreateProcess(settings.exe_path, - command_line, - NULL, - NULL, - TRUE, - settings.priority | CREATE_NEW_CONSOLE, - NULL, - settings.config_dir, - &start_info, - &proc_info)) - { - error = MsgToEventLog (M_SYSERR, TEXT("CreateProcess failed, exe='%s' cmdline='%s' dir='%s'"), - settings.exe_path, - command_line, - settings.config_dir); - - FindClose (find_handle); - CloseHandle (log_handle); - goto finish; - } + /* append to logfile? */ + if (settings.append) + { + if (SetFilePointer(log_handle, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER) + { + error = MsgToEventLog(M_SYSERR, TEXT("Cannot seek to end of logfile: %s"), log_path); + FindClose(find_handle); + goto finish; + } + } - /* close unneeded handles */ - Sleep (1000); /* try to prevent race if we close logfile - handle before child process DUPs it */ - if (!CloseHandle (proc_info.hProcess) - || !CloseHandle (proc_info.hThread) - || !CloseHandle (log_handle)) - { - error = MsgToEventLog (M_SYSERR, TEXT("CloseHandle failed")); - goto finish; + /* fill in STARTUPINFO struct */ + GetStartupInfo(&start_info); + start_info.cb = sizeof(start_info); + start_info.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW; + start_info.wShowWindow = SW_HIDE; + start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE); + start_info.hStdOutput = start_info.hStdError = log_handle; + + /* create an OpenVPN process for one config file */ + if (!CreateProcess(settings.exe_path, + command_line, + NULL, + NULL, + TRUE, + settings.priority | CREATE_NEW_CONSOLE, + NULL, + settings.config_dir, + &start_info, + &proc_info)) + { + error = MsgToEventLog(M_SYSERR, TEXT("CreateProcess failed, exe='%s' cmdline='%s' dir='%s'"), + settings.exe_path, + command_line, + settings.config_dir); + + FindClose(find_handle); + CloseHandle(log_handle); + goto finish; + } + + /* close unneeded handles */ + Sleep(1000); /* try to prevent race if we close logfile + * handle before child process DUPs it */ + if (!CloseHandle(proc_info.hProcess) + || !CloseHandle(proc_info.hThread) + || !CloseHandle(log_handle)) + { + error = MsgToEventLog(M_SYSERR, TEXT("CloseHandle failed")); + goto finish; + } } - } - /* more files to process? */ - more_files = FindNextFile (find_handle, &find_obj); + /* more files to process? */ + more_files = FindNextFile(find_handle, &find_obj); - } while (more_files); + } while (more_files); - FindClose (find_handle); - } + FindClose(find_handle); + } - /* we are now fully started */ - status.dwCurrentState = SERVICE_RUNNING; - status.dwWaitHint = 0; - if (!ReportStatusToSCMgr(service, &status)) + /* we are now fully started */ + status.dwCurrentState = SERVICE_RUNNING; + status.dwWaitHint = 0; + if (!ReportStatusToSCMgr(service, &status)) { - MsgToEventLog (M_ERR, TEXT("ReportStatusToSCMgr SERVICE_RUNNING failed")); - goto finish; + MsgToEventLog(M_ERR, TEXT("ReportStatusToSCMgr SERVICE_RUNNING failed")); + goto finish; } - /* wait for our shutdown signal */ - if (WaitForSingleObject (exit_event, INFINITE) != WAIT_OBJECT_0) - MsgToEventLog (M_ERR, TEXT("wait for shutdown signal failed")); + /* wait for our shutdown signal */ + if (WaitForSingleObject(exit_event, INFINITE) != WAIT_OBJECT_0) + { + MsgToEventLog(M_ERR, TEXT("wait for shutdown signal failed")); + } finish: - if (exit_event) - CloseHandle (exit_event); + if (exit_event) + { + CloseHandle(exit_event); + } - status.dwCurrentState = SERVICE_STOPPED; - status.dwWin32ExitCode = error; - ReportStatusToSCMgr (service, &status); + status.dwCurrentState = SERVICE_STOPPED; + status.dwWin32ExitCode = error; + ReportStatusToSCMgr(service, &status); } diff --git a/src/openvpnserv/common.c b/src/openvpnserv/common.c index eafee205d25..c7abe0d3969 100644 --- a/src/openvpnserv/common.c +++ b/src/openvpnserv/common.c @@ -29,202 +29,236 @@ * that don't guarantee null termination for size > 0. */ int -openvpn_vsntprintf (LPTSTR str, size_t size, LPCTSTR format, va_list arglist) +openvpn_vsntprintf(LPTSTR str, size_t size, LPCTSTR format, va_list arglist) { - int len = -1; - if (size > 0) + int len = -1; + if (size > 0) { - len = _vsntprintf (str, size, format, arglist); - str[size - 1] = 0; + len = _vsntprintf(str, size, format, arglist); + str[size - 1] = 0; } - return (len >= 0 && len < size); + return (len >= 0 && len < size); } int -openvpn_sntprintf (LPTSTR str, size_t size, LPCTSTR format, ...) +openvpn_sntprintf(LPTSTR str, size_t size, LPCTSTR format, ...) { - va_list arglist; - int len = -1; - if (size > 0) + va_list arglist; + int len = -1; + if (size > 0) { - va_start (arglist, format); - len = openvpn_vsntprintf (str, size, format, arglist); - va_end (arglist); + va_start(arglist, format); + len = openvpn_vsntprintf(str, size, format, arglist); + va_end(arglist); } - return len; + return len; } #define REG_KEY TEXT("SOFTWARE\\" PACKAGE_NAME) static DWORD -GetRegString (HKEY key, LPCTSTR value, LPTSTR data, DWORD size) +GetRegString(HKEY key, LPCTSTR value, LPTSTR data, DWORD size) { - DWORD type; - LONG status = RegQueryValueEx (key, value, NULL, &type, (LPBYTE) data, &size); + DWORD type; + LONG status = RegQueryValueEx(key, value, NULL, &type, (LPBYTE) data, &size); - if (status == ERROR_SUCCESS && type != REG_SZ) - status = ERROR_DATATYPE_MISMATCH; + if (status == ERROR_SUCCESS && type != REG_SZ) + { + status = ERROR_DATATYPE_MISMATCH; + } - if (status != ERROR_SUCCESS) + if (status != ERROR_SUCCESS) { - SetLastError (status); - return MsgToEventLog (M_SYSERR, TEXT("Error querying registry value: HKLM\\%s\\%s"), REG_KEY, value); + SetLastError(status); + return MsgToEventLog(M_SYSERR, TEXT("Error querying registry value: HKLM\\%s\\%s"), REG_KEY, value); } - return ERROR_SUCCESS; + return ERROR_SUCCESS; } DWORD -GetOpenvpnSettings (settings_t *s) +GetOpenvpnSettings(settings_t *s) { - TCHAR priority[64]; - TCHAR append[2]; - DWORD error; - HKEY key; - - LONG status = RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_KEY, 0, KEY_READ, &key); - if (status != ERROR_SUCCESS) - { - SetLastError (status); - return MsgToEventLog (M_SYSERR, TEXT("Could not open Registry key HKLM\\%s not found"), REG_KEY); - } - - error = GetRegString (key, TEXT("exe_path"), s->exe_path, sizeof (s->exe_path)); - if (error != ERROR_SUCCESS) - goto out; - - error = GetRegString (key, TEXT("config_dir"), s->config_dir, sizeof (s->config_dir)); - if (error != ERROR_SUCCESS) - goto out; - - error = GetRegString (key, TEXT("config_ext"), s->ext_string, sizeof (s->ext_string)); - if (error != ERROR_SUCCESS) - goto out; - - error = GetRegString (key, TEXT("log_dir"), s->log_dir, sizeof (s->log_dir)); - if (error != ERROR_SUCCESS) - goto out; - - error = GetRegString (key, TEXT("priority"), priority, sizeof (priority)); - if (error != ERROR_SUCCESS) - goto out; - - error = GetRegString (key, TEXT("log_append"), append, sizeof (append)); - if (error != ERROR_SUCCESS) - goto out; - - /* read if present, else use default */ - error = GetRegString (key, TEXT("ovpn_admin_group"), s->ovpn_admin_group, sizeof (s->ovpn_admin_group)); - if (error != ERROR_SUCCESS) - { - openvpn_sntprintf(s->ovpn_admin_group, _countof(s->ovpn_admin_group), OVPN_ADMIN_GROUP); - error = 0; /* this error is not fatal */ - } - /* set process priority */ - if (!_tcsicmp (priority, TEXT("IDLE_PRIORITY_CLASS"))) - s->priority = IDLE_PRIORITY_CLASS; - else if (!_tcsicmp (priority, TEXT("BELOW_NORMAL_PRIORITY_CLASS"))) - s->priority = BELOW_NORMAL_PRIORITY_CLASS; - else if (!_tcsicmp (priority, TEXT("NORMAL_PRIORITY_CLASS"))) - s->priority = NORMAL_PRIORITY_CLASS; - else if (!_tcsicmp (priority, TEXT("ABOVE_NORMAL_PRIORITY_CLASS"))) - s->priority = ABOVE_NORMAL_PRIORITY_CLASS; - else if (!_tcsicmp (priority, TEXT("HIGH_PRIORITY_CLASS"))) - s->priority = HIGH_PRIORITY_CLASS; - else - { - SetLastError (ERROR_INVALID_DATA); - error = MsgToEventLog (M_SYSERR, TEXT("Unknown priority name: %s"), priority); - goto out; - } - - /* set log file append/truncate flag */ - if (append[0] == TEXT('0')) - s->append = FALSE; - else if (append[0] == TEXT('1')) - s->append = TRUE; - else - { - SetLastError (ERROR_INVALID_DATA); - error = MsgToEventLog (M_ERR, TEXT("Log file append flag (given as '%s') must be '0' or '1'"), append); - goto out; + TCHAR priority[64]; + TCHAR append[2]; + DWORD error; + HKEY key; + + LONG status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_KEY, 0, KEY_READ, &key); + if (status != ERROR_SUCCESS) + { + SetLastError(status); + return MsgToEventLog(M_SYSERR, TEXT("Could not open Registry key HKLM\\%s not found"), REG_KEY); + } + + error = GetRegString(key, TEXT("exe_path"), s->exe_path, sizeof(s->exe_path)); + if (error != ERROR_SUCCESS) + { + goto out; + } + + error = GetRegString(key, TEXT("config_dir"), s->config_dir, sizeof(s->config_dir)); + if (error != ERROR_SUCCESS) + { + goto out; + } + + error = GetRegString(key, TEXT("config_ext"), s->ext_string, sizeof(s->ext_string)); + if (error != ERROR_SUCCESS) + { + goto out; + } + + error = GetRegString(key, TEXT("log_dir"), s->log_dir, sizeof(s->log_dir)); + if (error != ERROR_SUCCESS) + { + goto out; + } + + error = GetRegString(key, TEXT("priority"), priority, sizeof(priority)); + if (error != ERROR_SUCCESS) + { + goto out; + } + + error = GetRegString(key, TEXT("log_append"), append, sizeof(append)); + if (error != ERROR_SUCCESS) + { + goto out; + } + + /* read if present, else use default */ + error = GetRegString(key, TEXT("ovpn_admin_group"), s->ovpn_admin_group, sizeof(s->ovpn_admin_group)); + if (error != ERROR_SUCCESS) + { + openvpn_sntprintf(s->ovpn_admin_group, _countof(s->ovpn_admin_group), OVPN_ADMIN_GROUP); + error = 0; /* this error is not fatal */ + } + /* set process priority */ + if (!_tcsicmp(priority, TEXT("IDLE_PRIORITY_CLASS"))) + { + s->priority = IDLE_PRIORITY_CLASS; + } + else if (!_tcsicmp(priority, TEXT("BELOW_NORMAL_PRIORITY_CLASS"))) + { + s->priority = BELOW_NORMAL_PRIORITY_CLASS; + } + else if (!_tcsicmp(priority, TEXT("NORMAL_PRIORITY_CLASS"))) + { + s->priority = NORMAL_PRIORITY_CLASS; + } + else if (!_tcsicmp(priority, TEXT("ABOVE_NORMAL_PRIORITY_CLASS"))) + { + s->priority = ABOVE_NORMAL_PRIORITY_CLASS; + } + else if (!_tcsicmp(priority, TEXT("HIGH_PRIORITY_CLASS"))) + { + s->priority = HIGH_PRIORITY_CLASS; + } + else + { + SetLastError(ERROR_INVALID_DATA); + error = MsgToEventLog(M_SYSERR, TEXT("Unknown priority name: %s"), priority); + goto out; + } + + /* set log file append/truncate flag */ + if (append[0] == TEXT('0')) + { + s->append = FALSE; + } + else if (append[0] == TEXT('1')) + { + s->append = TRUE; + } + else + { + SetLastError(ERROR_INVALID_DATA); + error = MsgToEventLog(M_ERR, TEXT("Log file append flag (given as '%s') must be '0' or '1'"), append); + goto out; } out: - RegCloseKey (key); - return error; + RegCloseKey(key); + return error; } LPCTSTR -GetLastErrorText () +GetLastErrorText() { - static TCHAR buf[256]; - DWORD len; - LPTSTR tmp = NULL; + static TCHAR buf[256]; + DWORD len; + LPTSTR tmp = NULL; - len = FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY, - NULL, GetLastError(), LANG_NEUTRAL, (LPTSTR)&tmp, 0, NULL); + len = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY, + NULL, GetLastError(), LANG_NEUTRAL, (LPTSTR)&tmp, 0, NULL); - if (len == 0 || (long) _countof (buf) < (long) len + 14) - buf[0] = TEXT('\0'); - else + if (len == 0 || (long) _countof(buf) < (long) len + 14) + { + buf[0] = TEXT('\0'); + } + else { - tmp[_tcslen (tmp) - 2] = TEXT('\0'); /* remove CR/LF characters */ - openvpn_sntprintf (buf, _countof (buf), TEXT("%s (0x%x)"), tmp, GetLastError()); + tmp[_tcslen(tmp) - 2] = TEXT('\0'); /* remove CR/LF characters */ + openvpn_sntprintf(buf, _countof(buf), TEXT("%s (0x%x)"), tmp, GetLastError()); } - if (tmp) - LocalFree (tmp); + if (tmp) + { + LocalFree(tmp); + } - return buf; + return buf; } DWORD -MsgToEventLog (DWORD flags, LPCTSTR format, ...) +MsgToEventLog(DWORD flags, LPCTSTR format, ...) { - HANDLE hEventSource; - TCHAR msg[2][256]; - DWORD error = 0; - LPCTSTR err_msg = TEXT(""); - va_list arglist; + HANDLE hEventSource; + TCHAR msg[2][256]; + DWORD error = 0; + LPCTSTR err_msg = TEXT(""); + va_list arglist; - if (flags & MSG_FLAGS_SYS_CODE) + if (flags & MSG_FLAGS_SYS_CODE) { - error = GetLastError (); - err_msg = GetLastErrorText (); + error = GetLastError(); + err_msg = GetLastErrorText(); } - hEventSource = RegisterEventSource (NULL, APPNAME); - if (hEventSource != NULL) + hEventSource = RegisterEventSource(NULL, APPNAME); + if (hEventSource != NULL) { - openvpn_sntprintf (msg[0], _countof (msg[0]), - TEXT("%s%s: %s"), APPNAME, - (flags & MSG_FLAGS_ERROR) ? TEXT(" error") : TEXT(""), err_msg); - - va_start (arglist, format); - openvpn_vsntprintf (msg[1], _countof (msg[1]), format, arglist); - va_end (arglist); - - const TCHAR *mesg[] = { msg[0], msg[1] }; - ReportEvent (hEventSource, flags & MSG_FLAGS_ERROR ? - EVENTLOG_ERROR_TYPE : EVENTLOG_INFORMATION_TYPE, - 0, 0, NULL, 2, 0, mesg, NULL); - DeregisterEventSource (hEventSource); + openvpn_sntprintf(msg[0], _countof(msg[0]), + TEXT("%s%s: %s"), APPNAME, + (flags & MSG_FLAGS_ERROR) ? TEXT(" error") : TEXT(""), err_msg); + + va_start(arglist, format); + openvpn_vsntprintf(msg[1], _countof(msg[1]), format, arglist); + va_end(arglist); + + const TCHAR *mesg[] = { msg[0], msg[1] }; + ReportEvent(hEventSource, flags & MSG_FLAGS_ERROR ? + EVENTLOG_ERROR_TYPE : EVENTLOG_INFORMATION_TYPE, + 0, 0, NULL, 2, 0, mesg, NULL); + DeregisterEventSource(hEventSource); } - return error; + return error; } /* Convert a utf8 string to utf16. Caller should free the result */ wchar_t * -utf8to16 (const char *utf8) +utf8to16(const char *utf8) { - int n = MultiByteToWideChar (CP_UTF8, 0, utf8, -1, NULL, 0); - wchar_t *utf16 = malloc (n * sizeof (wchar_t)); - if (!utf16) - return NULL; - MultiByteToWideChar (CP_UTF8, 0, utf8, -1, utf16, n); - return utf16; + int n = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0); + wchar_t *utf16 = malloc(n * sizeof(wchar_t)); + if (!utf16) + { + return NULL; + } + MultiByteToWideChar(CP_UTF8, 0, utf8, -1, utf16, n); + return utf16; } diff --git a/src/openvpnserv/interactive.c b/src/openvpnserv/interactive.c index ec54216bb44..9cbe25c4d7f 100644 --- a/src/openvpnserv/interactive.c +++ b/src/openvpnserv/interactive.c @@ -61,265 +61,291 @@ static HANDLE rdns_semaphore = NULL; openvpn_service_t interactive_service = { - interactive, - TEXT(PACKAGE_NAME "ServiceInteractive"), - TEXT(PACKAGE_NAME " Interactive Service"), - TEXT(SERVICE_DEPENDENCIES), - SERVICE_AUTO_START + interactive, + TEXT(PACKAGE_NAME "ServiceInteractive"), + TEXT(PACKAGE_NAME " Interactive Service"), + TEXT(SERVICE_DEPENDENCIES), + SERVICE_AUTO_START }; typedef struct { - WCHAR *directory; - WCHAR *options; - WCHAR *std_input; + WCHAR *directory; + WCHAR *options; + WCHAR *std_input; } STARTUP_DATA; /* Datatype for linked lists */ typedef struct _list_item { - struct _list_item *next; - LPVOID data; + struct _list_item *next; + LPVOID data; } list_item_t; /* Datatypes for undo information */ typedef enum { - address, - route, - block_dns, - undo_dns4, - undo_dns6, - _undo_type_max + address, + route, + block_dns, + undo_dns4, + undo_dns6, + _undo_type_max } undo_type_t; -typedef list_item_t* undo_lists_t[_undo_type_max]; +typedef list_item_t *undo_lists_t[_undo_type_max]; static DWORD -AddListItem (list_item_t **pfirst, LPVOID data) +AddListItem(list_item_t **pfirst, LPVOID data) { - list_item_t *new_item = malloc (sizeof (list_item_t)); - if (new_item == NULL) - return ERROR_OUTOFMEMORY; + list_item_t *new_item = malloc(sizeof(list_item_t)); + if (new_item == NULL) + { + return ERROR_OUTOFMEMORY; + } - new_item->next = *pfirst; - new_item->data = data; + new_item->next = *pfirst; + new_item->data = data; - *pfirst = new_item; - return NO_ERROR; + *pfirst = new_item; + return NO_ERROR; } typedef BOOL (*match_fn_t) (LPVOID item, LPVOID ctx); static LPVOID -RemoveListItem (list_item_t **pfirst, match_fn_t match, LPVOID ctx) +RemoveListItem(list_item_t **pfirst, match_fn_t match, LPVOID ctx) { - LPVOID data = NULL; - list_item_t **pnext; + LPVOID data = NULL; + list_item_t **pnext; - for (pnext = pfirst; *pnext; pnext = &(*pnext)->next) + for (pnext = pfirst; *pnext; pnext = &(*pnext)->next) { - list_item_t *item = *pnext; - if (!match (item->data, ctx)) - continue; + list_item_t *item = *pnext; + if (!match(item->data, ctx)) + { + continue; + } - /* Found item, remove from the list and free memory */ - *pnext = item->next; - data = item->data; - free (item); - break; + /* Found item, remove from the list and free memory */ + *pnext = item->next; + data = item->data; + free(item); + break; } - return data; + return data; } static HANDLE -CloseHandleEx (LPHANDLE handle) +CloseHandleEx(LPHANDLE handle) { - if (handle && *handle && *handle != INVALID_HANDLE_VALUE) + if (handle && *handle && *handle != INVALID_HANDLE_VALUE) { - CloseHandle (*handle); - *handle = INVALID_HANDLE_VALUE; + CloseHandle(*handle); + *handle = INVALID_HANDLE_VALUE; } - return INVALID_HANDLE_VALUE; + return INVALID_HANDLE_VALUE; } static HANDLE -InitOverlapped (LPOVERLAPPED overlapped) +InitOverlapped(LPOVERLAPPED overlapped) { - ZeroMemory (overlapped, sizeof (OVERLAPPED)); - overlapped->hEvent = CreateEvent (NULL, TRUE, FALSE, NULL); - return overlapped->hEvent; + ZeroMemory(overlapped, sizeof(OVERLAPPED)); + overlapped->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + return overlapped->hEvent; } static BOOL -ResetOverlapped (LPOVERLAPPED overlapped) +ResetOverlapped(LPOVERLAPPED overlapped) { - HANDLE io_event = overlapped->hEvent; - if (!ResetEvent (io_event)) - return FALSE; - ZeroMemory (overlapped, sizeof (OVERLAPPED)); - overlapped->hEvent = io_event; - return TRUE; + HANDLE io_event = overlapped->hEvent; + if (!ResetEvent(io_event)) + { + return FALSE; + } + ZeroMemory(overlapped, sizeof(OVERLAPPED)); + overlapped->hEvent = io_event; + return TRUE; } typedef enum { - peek, - read, - write + peek, + read, + write } async_op_t; static DWORD -AsyncPipeOp (async_op_t op, HANDLE pipe, LPVOID buffer, DWORD size, DWORD count, LPHANDLE events) +AsyncPipeOp(async_op_t op, HANDLE pipe, LPVOID buffer, DWORD size, DWORD count, LPHANDLE events) { - int i; - BOOL success; - HANDLE io_event; - DWORD res, bytes = 0; - OVERLAPPED overlapped; - LPHANDLE handles = NULL; + int i; + BOOL success; + HANDLE io_event; + DWORD res, bytes = 0; + OVERLAPPED overlapped; + LPHANDLE handles = NULL; - io_event = InitOverlapped (&overlapped); - if (!io_event) - goto out; + io_event = InitOverlapped(&overlapped); + if (!io_event) + { + goto out; + } - handles = malloc ((count + 1) * sizeof (HANDLE)); - if (!handles) - goto out; + handles = malloc((count + 1) * sizeof(HANDLE)); + if (!handles) + { + goto out; + } - if (op == write) - success = WriteFile (pipe, buffer, size, NULL, &overlapped); - else - success = ReadFile (pipe, buffer, size, NULL, &overlapped); - if (!success && GetLastError () != ERROR_IO_PENDING && GetLastError () != ERROR_MORE_DATA) - goto out; + if (op == write) + { + success = WriteFile(pipe, buffer, size, NULL, &overlapped); + } + else + { + success = ReadFile(pipe, buffer, size, NULL, &overlapped); + } + if (!success && GetLastError() != ERROR_IO_PENDING && GetLastError() != ERROR_MORE_DATA) + { + goto out; + } - handles[0] = io_event; - for (i = 0; i < count; i++) - handles[i + 1] = events[i]; + handles[0] = io_event; + for (i = 0; i < count; i++) + handles[i + 1] = events[i]; - res = WaitForMultipleObjects (count + 1, handles, FALSE, - op == peek ? INFINITE : IO_TIMEOUT); - if (res != WAIT_OBJECT_0) + res = WaitForMultipleObjects(count + 1, handles, FALSE, + op == peek ? INFINITE : IO_TIMEOUT); + if (res != WAIT_OBJECT_0) { - CancelIo (pipe); - goto out; + CancelIo(pipe); + goto out; } - if (op == peek) - PeekNamedPipe (pipe, NULL, 0, NULL, &bytes, NULL); - else - GetOverlappedResult (pipe, &overlapped, &bytes, TRUE); + if (op == peek) + { + PeekNamedPipe(pipe, NULL, 0, NULL, &bytes, NULL); + } + else + { + GetOverlappedResult(pipe, &overlapped, &bytes, TRUE); + } out: - CloseHandleEx (&io_event); - free (handles); - return bytes; + CloseHandleEx(&io_event); + free(handles); + return bytes; } static DWORD -PeekNamedPipeAsync (HANDLE pipe, DWORD count, LPHANDLE events) +PeekNamedPipeAsync(HANDLE pipe, DWORD count, LPHANDLE events) { - return AsyncPipeOp (peek, pipe, NULL, 0, count, events); + return AsyncPipeOp(peek, pipe, NULL, 0, count, events); } static DWORD -ReadPipeAsync (HANDLE pipe, LPVOID buffer, DWORD size, DWORD count, LPHANDLE events) +ReadPipeAsync(HANDLE pipe, LPVOID buffer, DWORD size, DWORD count, LPHANDLE events) { - return AsyncPipeOp (read, pipe, buffer, size, count, events); + return AsyncPipeOp(read, pipe, buffer, size, count, events); } static DWORD -WritePipeAsync (HANDLE pipe, LPVOID data, DWORD size, DWORD count, LPHANDLE events) +WritePipeAsync(HANDLE pipe, LPVOID data, DWORD size, DWORD count, LPHANDLE events) { - return AsyncPipeOp (write, pipe, data, size, count, events); + return AsyncPipeOp(write, pipe, data, size, count, events); } static VOID -ReturnProcessId (HANDLE pipe, DWORD pid, DWORD count, LPHANDLE events) +ReturnProcessId(HANDLE pipe, DWORD pid, DWORD count, LPHANDLE events) { - const WCHAR msg[] = L"Process ID"; - WCHAR buf[22 + _countof(msg)]; /* 10 chars each for error and PID and 2 for line breaks */ + const WCHAR msg[] = L"Process ID"; + WCHAR buf[22 + _countof(msg)]; /* 10 chars each for error and PID and 2 for line breaks */ - /* - * Same format as error messages (3 line string) with error = 0 in - * 0x%08x format, PID on line 2 and a description "Process ID" on line 3 - */ - _snwprintf (buf, _countof(buf), L"0x%08x\n0x%08x\n%s", 0, pid, msg); - buf[_countof(buf) - 1] = '\0'; + /* + * Same format as error messages (3 line string) with error = 0 in + * 0x%08x format, PID on line 2 and a description "Process ID" on line 3 + */ + _snwprintf(buf, _countof(buf), L"0x%08x\n0x%08x\n%s", 0, pid, msg); + buf[_countof(buf) - 1] = '\0'; - WritePipeAsync (pipe, buf, wcslen (buf) * 2, count, events); + WritePipeAsync(pipe, buf, wcslen(buf) * 2, count, events); } static VOID -ReturnError (HANDLE pipe, DWORD error, LPCWSTR func, DWORD count, LPHANDLE events) +ReturnError(HANDLE pipe, DWORD error, LPCWSTR func, DWORD count, LPHANDLE events) { - DWORD result_len; - LPWSTR result = L"0xffffffff\nFormatMessage failed\nCould not return result"; - DWORD_PTR args[] = { - (DWORD_PTR) error, - (DWORD_PTR) func, - (DWORD_PTR) "" - }; + DWORD result_len; + LPWSTR result = L"0xffffffff\nFormatMessage failed\nCould not return result"; + DWORD_PTR args[] = { + (DWORD_PTR) error, + (DWORD_PTR) func, + (DWORD_PTR) "" + }; - if (error != ERROR_OPENVPN_STARTUP) + if (error != ERROR_OPENVPN_STARTUP) { - FormatMessageW (FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_IGNORE_INSERTS, - 0, error, 0, (LPWSTR) &args[2], 0, NULL); + FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM + |FORMAT_MESSAGE_ALLOCATE_BUFFER + |FORMAT_MESSAGE_IGNORE_INSERTS, + 0, error, 0, (LPWSTR) &args[2], 0, NULL); } - result_len = FormatMessageW (FORMAT_MESSAGE_FROM_STRING | - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_ARGUMENT_ARRAY, - L"0x%1!08x!\n%2!s!\n%3!s!", 0, 0, - (LPWSTR) &result, 0, (va_list*) args); + result_len = FormatMessageW(FORMAT_MESSAGE_FROM_STRING + |FORMAT_MESSAGE_ALLOCATE_BUFFER + |FORMAT_MESSAGE_ARGUMENT_ARRAY, + L"0x%1!08x!\n%2!s!\n%3!s!", 0, 0, + (LPWSTR) &result, 0, (va_list *) args); - WritePipeAsync (pipe, result, wcslen (result) * 2, count, events); + WritePipeAsync(pipe, result, wcslen(result) * 2, count, events); #ifdef UNICODE - MsgToEventLog (MSG_FLAGS_ERROR, result); + MsgToEventLog(MSG_FLAGS_ERROR, result); #else - MsgToEventLog (MSG_FLAGS_ERROR, "%S", result); + MsgToEventLog(MSG_FLAGS_ERROR, "%S", result); #endif - if (error != ERROR_OPENVPN_STARTUP) - LocalFree ((LPVOID) args[2]); - if (result_len) - LocalFree (result); + if (error != ERROR_OPENVPN_STARTUP) + { + LocalFree((LPVOID) args[2]); + } + if (result_len) + { + LocalFree(result); + } } static VOID -ReturnLastError (HANDLE pipe, LPCWSTR func) +ReturnLastError(HANDLE pipe, LPCWSTR func) { - ReturnError (pipe, GetLastError (), func, 1, &exit_event); + ReturnError(pipe, GetLastError(), func, 1, &exit_event); } static VOID -ReturnOpenvpnOutput (HANDLE pipe, HANDLE ovpn_output, DWORD count, LPHANDLE events) +ReturnOpenvpnOutput(HANDLE pipe, HANDLE ovpn_output, DWORD count, LPHANDLE events) { - WCHAR *wide_output = NULL; - CHAR output[512]; - DWORD size; + WCHAR *wide_output = NULL; + CHAR output[512]; + DWORD size; - ReadFile (ovpn_output, output, sizeof (output), &size, NULL); - if (size == 0) - return; + ReadFile(ovpn_output, output, sizeof(output), &size, NULL); + if (size == 0) + { + return; + } - wide_output = malloc ((size) * sizeof (WCHAR)); - if (wide_output) + wide_output = malloc((size) * sizeof(WCHAR)); + if (wide_output) { - MultiByteToWideChar (CP_UTF8, 0, output, size, wide_output, size); - wide_output[size - 1] = 0; + MultiByteToWideChar(CP_UTF8, 0, output, size, wide_output, size); + wide_output[size - 1] = 0; } - ReturnError (pipe, ERROR_OPENVPN_STARTUP, wide_output, count, events); - free (wide_output); + ReturnError(pipe, ERROR_OPENVPN_STARTUP, wide_output, count, events); + free(wide_output); } /* @@ -328,7 +354,7 @@ ReturnOpenvpnOutput (HANDLE pipe, HANDLE ovpn_output, DWORD count, LPHANDLE even * Returns true on success */ static BOOL -ValidateOptions (HANDLE pipe, const WCHAR *workdir, const WCHAR *options) +ValidateOptions(HANDLE pipe, const WCHAR *workdir, const WCHAR *options) { WCHAR **argv; int argc; @@ -340,15 +366,15 @@ ValidateOptions (HANDLE pipe, const WCHAR *workdir, const WCHAR *options) " by adding your account to the \"%s\" group"; const WCHAR *msg2 = L"You have specified an option (%s) that may be used" - " only with admin approval. This error may be avoided" - " by adding your account to the \"%s\" group"; + " only with admin approval. This error may be avoided" + " by adding your account to the \"%s\" group"; - argv = CommandLineToArgvW (options, &argc); + argv = CommandLineToArgvW(options, &argc); if (!argv) { - ReturnLastError (pipe, L"CommandLineToArgvW"); - ReturnError (pipe, ERROR_STARTUP_DATA, L"Cannot validate options", 1, &exit_event); + ReturnLastError(pipe, L"CommandLineToArgvW"); + ReturnError(pipe, ERROR_STARTUP_DATA, L"Cannot validate options", 1, &exit_event); goto out; } @@ -366,12 +392,12 @@ ValidateOptions (HANDLE pipe, const WCHAR *workdir, const WCHAR *options) { WCHAR *argv_tmp[2] = { L"--config", argv[0] }; - if (!CheckOption (workdir, 2, argv_tmp, &settings)) + if (!CheckOption(workdir, 2, argv_tmp, &settings)) { - snwprintf (buf, _countof(buf), msg1, argv[0], workdir, - settings.ovpn_admin_group); + snwprintf(buf, _countof(buf), msg1, argv[0], workdir, + settings.ovpn_admin_group); buf[_countof(buf) - 1] = L'\0'; - ReturnError (pipe, ERROR_STARTUP_DATA, buf, 1, &exit_event); + ReturnError(pipe, ERROR_STARTUP_DATA, buf, 1, &exit_event); } goto out; } @@ -379,23 +405,25 @@ ValidateOptions (HANDLE pipe, const WCHAR *workdir, const WCHAR *options) for (i = 0; i < argc; ++i) { if (!IsOption(argv[i])) + { continue; + } - if (!CheckOption (workdir, argc-i, &argv[i], &settings)) + if (!CheckOption(workdir, argc-i, &argv[i], &settings)) { if (wcscmp(L"--config", argv[i]) == 0 && argc-i > 1) { - snwprintf (buf, _countof(buf), msg1, argv[i+1], workdir, - settings.ovpn_admin_group); + snwprintf(buf, _countof(buf), msg1, argv[i+1], workdir, + settings.ovpn_admin_group); buf[_countof(buf) - 1] = L'\0'; - ReturnError (pipe, ERROR_STARTUP_DATA, buf, 1, &exit_event); + ReturnError(pipe, ERROR_STARTUP_DATA, buf, 1, &exit_event); } else { - snwprintf (buf, _countof(buf), msg2, argv[i], - settings.ovpn_admin_group); + snwprintf(buf, _countof(buf), msg2, argv[i], + settings.ovpn_admin_group); buf[_countof(buf) - 1] = L'\0'; - ReturnError (pipe, ERROR_STARTUP_DATA, buf, 1, &exit_event); + ReturnError(pipe, ERROR_STARTUP_DATA, buf, 1, &exit_event); } goto out; } @@ -406,427 +434,494 @@ ValidateOptions (HANDLE pipe, const WCHAR *workdir, const WCHAR *options) out: if (argv) - LocalFree (argv); + { + LocalFree(argv); + } return ret; } static BOOL -GetStartupData (HANDLE pipe, STARTUP_DATA *sud) +GetStartupData(HANDLE pipe, STARTUP_DATA *sud) { - size_t len; - BOOL ret = FALSE; - WCHAR *data = NULL; - DWORD size, bytes, read; + size_t len; + BOOL ret = FALSE; + WCHAR *data = NULL; + DWORD size, bytes, read; - bytes = PeekNamedPipeAsync (pipe, 1, &exit_event); - if (bytes == 0) + bytes = PeekNamedPipeAsync(pipe, 1, &exit_event); + if (bytes == 0) { - MsgToEventLog (M_SYSERR, TEXT("PeekNamedPipeAsync failed")); - ReturnLastError (pipe, L"PeekNamedPipeAsync"); - goto out; + MsgToEventLog(M_SYSERR, TEXT("PeekNamedPipeAsync failed")); + ReturnLastError(pipe, L"PeekNamedPipeAsync"); + goto out; } - size = bytes / sizeof (*data); - data = malloc (bytes); - if (data == NULL) + size = bytes / sizeof(*data); + data = malloc(bytes); + if (data == NULL) { - MsgToEventLog (M_SYSERR, TEXT("malloc failed")); - ReturnLastError (pipe, L"malloc"); - goto out; + MsgToEventLog(M_SYSERR, TEXT("malloc failed")); + ReturnLastError(pipe, L"malloc"); + goto out; } - read = ReadPipeAsync (pipe, data, bytes, 1, &exit_event); - if (bytes != read) - { - MsgToEventLog (M_SYSERR, TEXT("ReadPipeAsync failed")); - ReturnLastError (pipe, L"ReadPipeAsync"); - goto out; - } + read = ReadPipeAsync(pipe, data, bytes, 1, &exit_event); + if (bytes != read) + { + MsgToEventLog(M_SYSERR, TEXT("ReadPipeAsync failed")); + ReturnLastError(pipe, L"ReadPipeAsync"); + goto out; + } - if (data[size - 1] != 0) + if (data[size - 1] != 0) { - MsgToEventLog (M_ERR, TEXT("Startup data is not NULL terminated")); - ReturnError (pipe, ERROR_STARTUP_DATA, L"GetStartupData", 1, &exit_event); - goto out; + MsgToEventLog(M_ERR, TEXT("Startup data is not NULL terminated")); + ReturnError(pipe, ERROR_STARTUP_DATA, L"GetStartupData", 1, &exit_event); + goto out; } - sud->directory = data; - len = wcslen (sud->directory) + 1; - size -= len; - if (size <= 0) + sud->directory = data; + len = wcslen(sud->directory) + 1; + size -= len; + if (size <= 0) { - MsgToEventLog (M_ERR, TEXT("Startup data ends at working directory")); - ReturnError (pipe, ERROR_STARTUP_DATA, L"GetStartupData", 1, &exit_event); - goto out; + MsgToEventLog(M_ERR, TEXT("Startup data ends at working directory")); + ReturnError(pipe, ERROR_STARTUP_DATA, L"GetStartupData", 1, &exit_event); + goto out; } - sud->options = sud->directory + len; - len = wcslen (sud->options) + 1; - size -= len; - if (size <= 0) + sud->options = sud->directory + len; + len = wcslen(sud->options) + 1; + size -= len; + if (size <= 0) { - MsgToEventLog (M_ERR, TEXT("Startup data ends at command line options")); - ReturnError (pipe, ERROR_STARTUP_DATA, L"GetStartupData", 1, &exit_event); - goto out; + MsgToEventLog(M_ERR, TEXT("Startup data ends at command line options")); + ReturnError(pipe, ERROR_STARTUP_DATA, L"GetStartupData", 1, &exit_event); + goto out; } - sud->std_input = sud->options + len; - data = NULL; /* don't free data */ - ret = TRUE; + sud->std_input = sud->options + len; + data = NULL; /* don't free data */ + ret = TRUE; out: - free (data); - return ret; + free(data); + return ret; } static VOID -FreeStartupData (STARTUP_DATA *sud) +FreeStartupData(STARTUP_DATA *sud) { - free (sud->directory); + free(sud->directory); } static SOCKADDR_INET -sockaddr_inet (short family, inet_address_t *addr) +sockaddr_inet(short family, inet_address_t *addr) { - SOCKADDR_INET sa_inet; - ZeroMemory (&sa_inet, sizeof (sa_inet)); - sa_inet.si_family = family; - if (family == AF_INET) - sa_inet.Ipv4.sin_addr = addr->ipv4; - else if (family == AF_INET6) - sa_inet.Ipv6.sin6_addr = addr->ipv6; - return sa_inet; + SOCKADDR_INET sa_inet; + ZeroMemory(&sa_inet, sizeof(sa_inet)); + sa_inet.si_family = family; + if (family == AF_INET) + { + sa_inet.Ipv4.sin_addr = addr->ipv4; + } + else if (family == AF_INET6) + { + sa_inet.Ipv6.sin6_addr = addr->ipv6; + } + return sa_inet; } static DWORD -InterfaceLuid (const char *iface_name, PNET_LUID luid) +InterfaceLuid(const char *iface_name, PNET_LUID luid) { - NETIO_STATUS status; - LPWSTR wide_name; - int n; + NETIO_STATUS status; + LPWSTR wide_name; + int n; - typedef NETIO_STATUS WINAPI (*ConvertInterfaceAliasToLuidFn) (LPCWSTR, PNET_LUID); - static ConvertInterfaceAliasToLuidFn ConvertInterfaceAliasToLuid = NULL; - if (!ConvertInterfaceAliasToLuid) + typedef NETIO_STATUS WINAPI (*ConvertInterfaceAliasToLuidFn) (LPCWSTR, PNET_LUID); + static ConvertInterfaceAliasToLuidFn ConvertInterfaceAliasToLuid = NULL; + if (!ConvertInterfaceAliasToLuid) { - HMODULE iphlpapi = GetModuleHandle (TEXT("iphlpapi.dll")); - if (iphlpapi == NULL) - return GetLastError (); + HMODULE iphlpapi = GetModuleHandle(TEXT("iphlpapi.dll")); + if (iphlpapi == NULL) + { + return GetLastError(); + } - ConvertInterfaceAliasToLuid = (ConvertInterfaceAliasToLuidFn) GetProcAddress (iphlpapi, "ConvertInterfaceAliasToLuid"); - if (!ConvertInterfaceAliasToLuid) - return GetLastError (); + ConvertInterfaceAliasToLuid = (ConvertInterfaceAliasToLuidFn) GetProcAddress(iphlpapi, "ConvertInterfaceAliasToLuid"); + if (!ConvertInterfaceAliasToLuid) + { + return GetLastError(); + } } - n = MultiByteToWideChar (CP_UTF8, 0, iface_name, -1, NULL, 0); - wide_name = malloc (n * sizeof (WCHAR)); - MultiByteToWideChar (CP_UTF8, 0, iface_name, -1, wide_name, n); - status = ConvertInterfaceAliasToLuid (wide_name, luid); - free (wide_name); + n = MultiByteToWideChar(CP_UTF8, 0, iface_name, -1, NULL, 0); + wide_name = malloc(n * sizeof(WCHAR)); + MultiByteToWideChar(CP_UTF8, 0, iface_name, -1, wide_name, n); + status = ConvertInterfaceAliasToLuid(wide_name, luid); + free(wide_name); - return status; + return status; } static BOOL -CmpAddress (LPVOID item, LPVOID address) +CmpAddress(LPVOID item, LPVOID address) { - return memcmp (item, address, sizeof (MIB_UNICASTIPADDRESS_ROW)) == 0 ? TRUE : FALSE; + return memcmp(item, address, sizeof(MIB_UNICASTIPADDRESS_ROW)) == 0 ? TRUE : FALSE; } static DWORD -DeleteAddress (PMIB_UNICASTIPADDRESS_ROW addr_row) +DeleteAddress(PMIB_UNICASTIPADDRESS_ROW addr_row) { - typedef NETIOAPI_API (*DeleteUnicastIpAddressEntryFn) (const PMIB_UNICASTIPADDRESS_ROW); - static DeleteUnicastIpAddressEntryFn DeleteUnicastIpAddressEntry = NULL; + typedef NETIOAPI_API (*DeleteUnicastIpAddressEntryFn) (const PMIB_UNICASTIPADDRESS_ROW); + static DeleteUnicastIpAddressEntryFn DeleteUnicastIpAddressEntry = NULL; - if (!DeleteUnicastIpAddressEntry) + if (!DeleteUnicastIpAddressEntry) { - HMODULE iphlpapi = GetModuleHandle (TEXT("iphlpapi.dll")); - if (iphlpapi == NULL) - return GetLastError (); + HMODULE iphlpapi = GetModuleHandle(TEXT("iphlpapi.dll")); + if (iphlpapi == NULL) + { + return GetLastError(); + } - DeleteUnicastIpAddressEntry = (DeleteUnicastIpAddressEntryFn) GetProcAddress (iphlpapi, "DeleteUnicastIpAddressEntry"); - if (!DeleteUnicastIpAddressEntry) - return GetLastError (); + DeleteUnicastIpAddressEntry = (DeleteUnicastIpAddressEntryFn) GetProcAddress(iphlpapi, "DeleteUnicastIpAddressEntry"); + if (!DeleteUnicastIpAddressEntry) + { + return GetLastError(); + } } - return DeleteUnicastIpAddressEntry (addr_row); + return DeleteUnicastIpAddressEntry(addr_row); } static DWORD -HandleAddressMessage (address_message_t *msg, undo_lists_t *lists) +HandleAddressMessage(address_message_t *msg, undo_lists_t *lists) { - DWORD err; - PMIB_UNICASTIPADDRESS_ROW addr_row; - BOOL add = msg->header.type == msg_add_address; + DWORD err; + PMIB_UNICASTIPADDRESS_ROW addr_row; + BOOL add = msg->header.type == msg_add_address; - typedef NETIOAPI_API (*CreateUnicastIpAddressEntryFn) (const PMIB_UNICASTIPADDRESS_ROW); - typedef NETIOAPI_API (*InitializeUnicastIpAddressEntryFn) (PMIB_UNICASTIPADDRESS_ROW); - static CreateUnicastIpAddressEntryFn CreateUnicastIpAddressEntry = NULL; - static InitializeUnicastIpAddressEntryFn InitializeUnicastIpAddressEntry = NULL; + typedef NETIOAPI_API (*CreateUnicastIpAddressEntryFn) (const PMIB_UNICASTIPADDRESS_ROW); + typedef NETIOAPI_API (*InitializeUnicastIpAddressEntryFn) (PMIB_UNICASTIPADDRESS_ROW); + static CreateUnicastIpAddressEntryFn CreateUnicastIpAddressEntry = NULL; + static InitializeUnicastIpAddressEntryFn InitializeUnicastIpAddressEntry = NULL; - if (!CreateUnicastIpAddressEntry || !InitializeUnicastIpAddressEntry) + if (!CreateUnicastIpAddressEntry || !InitializeUnicastIpAddressEntry) { - HMODULE iphlpapi = GetModuleHandle (TEXT("iphlpapi.dll")); - if (iphlpapi == NULL) - return GetLastError (); + HMODULE iphlpapi = GetModuleHandle(TEXT("iphlpapi.dll")); + if (iphlpapi == NULL) + { + return GetLastError(); + } - CreateUnicastIpAddressEntry = (CreateUnicastIpAddressEntryFn) GetProcAddress (iphlpapi, "CreateUnicastIpAddressEntry"); - if (!CreateUnicastIpAddressEntry) - return GetLastError (); + CreateUnicastIpAddressEntry = (CreateUnicastIpAddressEntryFn) GetProcAddress(iphlpapi, "CreateUnicastIpAddressEntry"); + if (!CreateUnicastIpAddressEntry) + { + return GetLastError(); + } - InitializeUnicastIpAddressEntry = (InitializeUnicastIpAddressEntryFn) GetProcAddress (iphlpapi, "InitializeUnicastIpAddressEntry"); - if (!InitializeUnicastIpAddressEntry) - return GetLastError (); + InitializeUnicastIpAddressEntry = (InitializeUnicastIpAddressEntryFn) GetProcAddress(iphlpapi, "InitializeUnicastIpAddressEntry"); + if (!InitializeUnicastIpAddressEntry) + { + return GetLastError(); + } } - addr_row = malloc (sizeof (*addr_row)); - if (addr_row == NULL) - return ERROR_OUTOFMEMORY; + addr_row = malloc(sizeof(*addr_row)); + if (addr_row == NULL) + { + return ERROR_OUTOFMEMORY; + } - InitializeUnicastIpAddressEntry (addr_row); - addr_row->Address = sockaddr_inet (msg->family, &msg->address); - addr_row->OnLinkPrefixLength = (UINT8) msg->prefix_len; + InitializeUnicastIpAddressEntry(addr_row); + addr_row->Address = sockaddr_inet(msg->family, &msg->address); + addr_row->OnLinkPrefixLength = (UINT8) msg->prefix_len; - if (msg->iface.index != -1) + if (msg->iface.index != -1) { - addr_row->InterfaceIndex = msg->iface.index; + addr_row->InterfaceIndex = msg->iface.index; } - else + else { - NET_LUID luid; - err = InterfaceLuid (msg->iface.name, &luid); - if (err) - goto out; - addr_row->InterfaceLuid = luid; + NET_LUID luid; + err = InterfaceLuid(msg->iface.name, &luid); + if (err) + { + goto out; + } + addr_row->InterfaceLuid = luid; } - if (add) + if (add) { - err = CreateUnicastIpAddressEntry (addr_row); - if (err) - goto out; + err = CreateUnicastIpAddressEntry(addr_row); + if (err) + { + goto out; + } - err = AddListItem (&(*lists)[address], addr_row); - if (err) - DeleteAddress (addr_row); + err = AddListItem(&(*lists)[address], addr_row); + if (err) + { + DeleteAddress(addr_row); + } } - else + else { - err = DeleteAddress (addr_row); - if (err) - goto out; + err = DeleteAddress(addr_row); + if (err) + { + goto out; + } - free (RemoveListItem (&(*lists)[address], CmpAddress, addr_row)); + free(RemoveListItem(&(*lists)[address], CmpAddress, addr_row)); } out: - if (!add || err) - free (addr_row); + if (!add || err) + { + free(addr_row); + } - return err; + return err; } static BOOL -CmpRoute (LPVOID item, LPVOID route) +CmpRoute(LPVOID item, LPVOID route) { - return memcmp (item, route, sizeof (MIB_IPFORWARD_ROW2)) == 0 ? TRUE : FALSE; + return memcmp(item, route, sizeof(MIB_IPFORWARD_ROW2)) == 0 ? TRUE : FALSE; } static DWORD -DeleteRoute (PMIB_IPFORWARD_ROW2 fwd_row) +DeleteRoute(PMIB_IPFORWARD_ROW2 fwd_row) { - typedef NETIOAPI_API (*DeleteIpForwardEntry2Fn) (PMIB_IPFORWARD_ROW2); - static DeleteIpForwardEntry2Fn DeleteIpForwardEntry2 = NULL; + typedef NETIOAPI_API (*DeleteIpForwardEntry2Fn) (PMIB_IPFORWARD_ROW2); + static DeleteIpForwardEntry2Fn DeleteIpForwardEntry2 = NULL; - if (!DeleteIpForwardEntry2) + if (!DeleteIpForwardEntry2) { - HMODULE iphlpapi = GetModuleHandle (TEXT("iphlpapi.dll")); - if (iphlpapi == NULL) - return GetLastError (); + HMODULE iphlpapi = GetModuleHandle(TEXT("iphlpapi.dll")); + if (iphlpapi == NULL) + { + return GetLastError(); + } - DeleteIpForwardEntry2 = (DeleteIpForwardEntry2Fn) GetProcAddress (iphlpapi, "DeleteIpForwardEntry2"); - if (!DeleteIpForwardEntry2) - return GetLastError (); + DeleteIpForwardEntry2 = (DeleteIpForwardEntry2Fn) GetProcAddress(iphlpapi, "DeleteIpForwardEntry2"); + if (!DeleteIpForwardEntry2) + { + return GetLastError(); + } } - return DeleteIpForwardEntry2 (fwd_row); + return DeleteIpForwardEntry2(fwd_row); } static DWORD -HandleRouteMessage (route_message_t *msg, undo_lists_t *lists) +HandleRouteMessage(route_message_t *msg, undo_lists_t *lists) { - DWORD err; - PMIB_IPFORWARD_ROW2 fwd_row; - BOOL add = msg->header.type == msg_add_route; + DWORD err; + PMIB_IPFORWARD_ROW2 fwd_row; + BOOL add = msg->header.type == msg_add_route; - typedef NETIOAPI_API (*CreateIpForwardEntry2Fn) (PMIB_IPFORWARD_ROW2); - static CreateIpForwardEntry2Fn CreateIpForwardEntry2 = NULL; + typedef NETIOAPI_API (*CreateIpForwardEntry2Fn) (PMIB_IPFORWARD_ROW2); + static CreateIpForwardEntry2Fn CreateIpForwardEntry2 = NULL; - if (!CreateIpForwardEntry2) + if (!CreateIpForwardEntry2) { - HMODULE iphlpapi = GetModuleHandle (TEXT("iphlpapi.dll")); - if (iphlpapi == NULL) - return GetLastError (); + HMODULE iphlpapi = GetModuleHandle(TEXT("iphlpapi.dll")); + if (iphlpapi == NULL) + { + return GetLastError(); + } - CreateIpForwardEntry2 = (CreateIpForwardEntry2Fn) GetProcAddress (iphlpapi, "CreateIpForwardEntry2"); - if (!CreateIpForwardEntry2) - return GetLastError (); + CreateIpForwardEntry2 = (CreateIpForwardEntry2Fn) GetProcAddress(iphlpapi, "CreateIpForwardEntry2"); + if (!CreateIpForwardEntry2) + { + return GetLastError(); + } } - fwd_row = malloc (sizeof (*fwd_row)); - if (fwd_row == NULL) - return ERROR_OUTOFMEMORY; + fwd_row = malloc(sizeof(*fwd_row)); + if (fwd_row == NULL) + { + return ERROR_OUTOFMEMORY; + } - ZeroMemory (fwd_row, sizeof (*fwd_row)); - fwd_row->ValidLifetime = 0xffffffff; - fwd_row->PreferredLifetime = 0xffffffff; - fwd_row->Protocol = MIB_IPPROTO_NETMGMT; - fwd_row->Metric = msg->metric; - fwd_row->DestinationPrefix.Prefix = sockaddr_inet (msg->family, &msg->prefix); - fwd_row->DestinationPrefix.PrefixLength = (UINT8) msg->prefix_len; - fwd_row->NextHop = sockaddr_inet (msg->family, &msg->gateway); + ZeroMemory(fwd_row, sizeof(*fwd_row)); + fwd_row->ValidLifetime = 0xffffffff; + fwd_row->PreferredLifetime = 0xffffffff; + fwd_row->Protocol = MIB_IPPROTO_NETMGMT; + fwd_row->Metric = msg->metric; + fwd_row->DestinationPrefix.Prefix = sockaddr_inet(msg->family, &msg->prefix); + fwd_row->DestinationPrefix.PrefixLength = (UINT8) msg->prefix_len; + fwd_row->NextHop = sockaddr_inet(msg->family, &msg->gateway); - if (msg->iface.index != -1) + if (msg->iface.index != -1) { - fwd_row->InterfaceIndex = msg->iface.index; + fwd_row->InterfaceIndex = msg->iface.index; } - else if (strlen (msg->iface.name)) + else if (strlen(msg->iface.name)) { - NET_LUID luid; - err = InterfaceLuid (msg->iface.name, &luid); - if (err) - goto out; - fwd_row->InterfaceLuid = luid; + NET_LUID luid; + err = InterfaceLuid(msg->iface.name, &luid); + if (err) + { + goto out; + } + fwd_row->InterfaceLuid = luid; } - if (add) + if (add) { - err = CreateIpForwardEntry2 (fwd_row); - if (err) - goto out; + err = CreateIpForwardEntry2(fwd_row); + if (err) + { + goto out; + } - err = AddListItem (&(*lists)[route], fwd_row); - if (err) - DeleteRoute (fwd_row); + err = AddListItem(&(*lists)[route], fwd_row); + if (err) + { + DeleteRoute(fwd_row); + } } - else + else { - err = DeleteRoute (fwd_row); - if (err) - goto out; + err = DeleteRoute(fwd_row); + if (err) + { + goto out; + } - free (RemoveListItem (&(*lists)[route], CmpRoute, fwd_row)); + free(RemoveListItem(&(*lists)[route], CmpRoute, fwd_row)); } out: - if (!add || err) - free (fwd_row); + if (!add || err) + { + free(fwd_row); + } - return err; + return err; } static DWORD -HandleFlushNeighborsMessage (flush_neighbors_message_t *msg) +HandleFlushNeighborsMessage(flush_neighbors_message_t *msg) { - typedef NETIOAPI_API (*FlushIpNetTable2Fn) (ADDRESS_FAMILY, NET_IFINDEX); - static FlushIpNetTable2Fn flush_fn = NULL; + typedef NETIOAPI_API (*FlushIpNetTable2Fn) (ADDRESS_FAMILY, NET_IFINDEX); + static FlushIpNetTable2Fn flush_fn = NULL; - if (msg->family == AF_INET) - return FlushIpNetTable (msg->iface.index); + if (msg->family == AF_INET) + { + return FlushIpNetTable(msg->iface.index); + } - if (!flush_fn) + if (!flush_fn) { - HMODULE iphlpapi = GetModuleHandle (TEXT("iphlpapi.dll")); - if (iphlpapi == NULL) - return GetLastError (); + HMODULE iphlpapi = GetModuleHandle(TEXT("iphlpapi.dll")); + if (iphlpapi == NULL) + { + return GetLastError(); + } - flush_fn = (FlushIpNetTable2Fn) GetProcAddress (iphlpapi, "FlushIpNetTable2"); - if (!flush_fn) + flush_fn = (FlushIpNetTable2Fn) GetProcAddress(iphlpapi, "FlushIpNetTable2"); + if (!flush_fn) { - if (GetLastError () == ERROR_PROC_NOT_FOUND) - return WSAEPFNOSUPPORT; - else - return GetLastError (); + if (GetLastError() == ERROR_PROC_NOT_FOUND) + { + return WSAEPFNOSUPPORT; + } + else + { + return GetLastError(); + } } } - return flush_fn (msg->family, msg->iface.index); + return flush_fn(msg->family, msg->iface.index); } static void -BlockDNSErrHandler (DWORD err, const char *msg) +BlockDNSErrHandler(DWORD err, const char *msg) { - TCHAR buf[256]; - LPCTSTR err_str; + TCHAR buf[256]; + LPCTSTR err_str; - if (!err) return; + if (!err) + { + return; + } - err_str = TEXT("Unknown Win32 Error"); + err_str = TEXT("Unknown Win32 Error"); - if (FormatMessage (FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM - | FORMAT_MESSAGE_ARGUMENT_ARRAY, - NULL, err, 0, buf, sizeof (buf), NULL)) + if (FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_ARGUMENT_ARRAY, + NULL, err, 0, buf, sizeof(buf), NULL)) { - err_str = buf; + err_str = buf; } #ifdef UNICODE - MsgToEventLog (M_ERR, L"%S (status = %lu): %s", msg, err, err_str); + MsgToEventLog(M_ERR, L"%S (status = %lu): %s", msg, err, err_str); #else - MsgToEventLog (M_ERR, "%s (status = %lu): %s", msg, err, err_str); + MsgToEventLog(M_ERR, "%s (status = %lu): %s", msg, err, err_str); #endif } /* Use an always-true match_fn to get the head of the list */ static BOOL -CmpEngine (LPVOID item, LPVOID any) +CmpEngine(LPVOID item, LPVOID any) { - return TRUE; + return TRUE; } static DWORD -HandleBlockDNSMessage (const block_dns_message_t *msg, undo_lists_t *lists) +HandleBlockDNSMessage(const block_dns_message_t *msg, undo_lists_t *lists) { - DWORD err = 0; - HANDLE engine = NULL; - LPCWSTR exe_path; + DWORD err = 0; + HANDLE engine = NULL; + LPCWSTR exe_path; #ifdef UNICODE - exe_path = settings.exe_path; + exe_path = settings.exe_path; #else - WCHAR wide_path[MAX_PATH]; - MultiByteToWideChar (CP_UTF8, 0, settings.exe_path, MAX_PATH, wide_path, MAX_PATH); - exe_path = wide_path; + WCHAR wide_path[MAX_PATH]; + MultiByteToWideChar(CP_UTF8, 0, settings.exe_path, MAX_PATH, wide_path, MAX_PATH); + exe_path = wide_path; #endif - if (msg->header.type == msg_add_block_dns) + if (msg->header.type == msg_add_block_dns) { - err = add_block_dns_filters (&engine, msg->iface.index, exe_path, BlockDNSErrHandler); - if (!err) - err = AddListItem (&(*lists)[block_dns], engine); + err = add_block_dns_filters(&engine, msg->iface.index, exe_path, BlockDNSErrHandler); + if (!err) + { + err = AddListItem(&(*lists)[block_dns], engine); + } } - else + else { - engine = RemoveListItem (&(*lists)[block_dns], CmpEngine, NULL); - if (engine) + engine = RemoveListItem(&(*lists)[block_dns], CmpEngine, NULL); + if (engine) + { + err = delete_block_dns_filters(engine); + engine = NULL; + } + else { - err = delete_block_dns_filters (engine); - engine = NULL; + MsgToEventLog(M_ERR, TEXT("No previous block DNS filters to delete")); } - else - MsgToEventLog (M_ERR, TEXT("No previous block DNS filters to delete")); } - if (err && engine) + if (err && engine) { - delete_block_dns_filters (engine); + delete_block_dns_filters(engine); } - return err; + return err; } /* @@ -835,133 +930,141 @@ HandleBlockDNSMessage (const block_dns_message_t *msg, undo_lists_t *lists) * the return value is the windows error code WAIT_TIMEOUT = 0x102 */ static DWORD -ExecCommand (const WCHAR *argv0, const WCHAR *cmdline, DWORD timeout) +ExecCommand(const WCHAR *argv0, const WCHAR *cmdline, DWORD timeout) { - DWORD exit_code; - STARTUPINFOW si; - PROCESS_INFORMATION pi; - DWORD proc_flags = CREATE_NO_WINDOW|CREATE_UNICODE_ENVIRONMENT; - WCHAR *cmdline_dup = NULL; + DWORD exit_code; + STARTUPINFOW si; + PROCESS_INFORMATION pi; + DWORD proc_flags = CREATE_NO_WINDOW|CREATE_UNICODE_ENVIRONMENT; + WCHAR *cmdline_dup = NULL; - ZeroMemory (&si, sizeof(si)); - ZeroMemory (&pi, sizeof(pi)); + ZeroMemory(&si, sizeof(si)); + ZeroMemory(&pi, sizeof(pi)); - si.cb = sizeof(si); + si.cb = sizeof(si); - /* CreateProcess needs a modifiable cmdline: make a copy */ - cmdline_dup = wcsdup (cmdline); - if ( cmdline_dup && CreateProcessW (argv0, cmdline_dup, NULL, NULL, FALSE, + /* CreateProcess needs a modifiable cmdline: make a copy */ + cmdline_dup = wcsdup(cmdline); + if (cmdline_dup && CreateProcessW(argv0, cmdline_dup, NULL, NULL, FALSE, proc_flags, NULL, NULL, &si, &pi) ) { - WaitForSingleObject (pi.hProcess, timeout ? timeout : INFINITE); - if (!GetExitCodeProcess (pi.hProcess, &exit_code)) + WaitForSingleObject(pi.hProcess, timeout ? timeout : INFINITE); + if (!GetExitCodeProcess(pi.hProcess, &exit_code)) { - MsgToEventLog (M_SYSERR, TEXT("ExecCommand: Error getting exit_code:")); - exit_code = GetLastError(); + MsgToEventLog(M_SYSERR, TEXT("ExecCommand: Error getting exit_code:")); + exit_code = GetLastError(); } - else if (exit_code == STILL_ACTIVE) + else if (exit_code == STILL_ACTIVE) { - exit_code = WAIT_TIMEOUT; /* Windows error code 0x102 */ + exit_code = WAIT_TIMEOUT; /* Windows error code 0x102 */ - /* kill without impunity */ - TerminateProcess (pi.hProcess, exit_code); - MsgToEventLog (M_ERR, TEXT("ExecCommand: \"%s %s\" killed after timeout"), - argv0, cmdline); + /* kill without impunity */ + TerminateProcess(pi.hProcess, exit_code); + MsgToEventLog(M_ERR, TEXT("ExecCommand: \"%s %s\" killed after timeout"), + argv0, cmdline); } - else if (exit_code) - MsgToEventLog (M_ERR, TEXT("ExecCommand: \"%s %s\" exited with status = %lu"), + else if (exit_code) + { + MsgToEventLog(M_ERR, TEXT("ExecCommand: \"%s %s\" exited with status = %lu"), argv0, cmdline, exit_code); - else - MsgToEventLog (M_INFO, TEXT("ExecCommand: \"%s %s\" completed"), argv0, cmdline); + } + else + { + MsgToEventLog(M_INFO, TEXT("ExecCommand: \"%s %s\" completed"), argv0, cmdline); + } - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); } - else + else { - exit_code = GetLastError(); - MsgToEventLog (M_SYSERR, TEXT("ExecCommand: could not run \"%s %s\" :"), - argv0, cmdline); + exit_code = GetLastError(); + MsgToEventLog(M_SYSERR, TEXT("ExecCommand: could not run \"%s %s\" :"), + argv0, cmdline); } - free (cmdline_dup); - return exit_code; + free(cmdline_dup); + return exit_code; } /* * Entry point for register-dns thread. */ static DWORD WINAPI -RegisterDNS (LPVOID unused) +RegisterDNS(LPVOID unused) { - DWORD err; - DWORD i; - WCHAR sys_path[MAX_PATH]; - DWORD timeout = RDNS_TIMEOUT * 1000; /* in milliseconds */ + DWORD err; + DWORD i; + WCHAR sys_path[MAX_PATH]; + DWORD timeout = RDNS_TIMEOUT * 1000; /* in milliseconds */ - /* default path of ipconfig command */ - WCHAR ipcfg[MAX_PATH] = L"C:\\Windows\\system32\\ipconfig.exe"; + /* default path of ipconfig command */ + WCHAR ipcfg[MAX_PATH] = L"C:\\Windows\\system32\\ipconfig.exe"; - struct + struct { - WCHAR *argv0; - WCHAR *cmdline; - DWORD timeout; + WCHAR *argv0; + WCHAR *cmdline; + DWORD timeout; } cmds [] = { - { ipcfg, L"ipconfig /flushdns", timeout }, - { ipcfg, L"ipconfig /registerdns", timeout }, - }; - int ncmds = sizeof (cmds) / sizeof (cmds[0]); + { ipcfg, L"ipconfig /flushdns", timeout }, + { ipcfg, L"ipconfig /registerdns", timeout }, + }; + int ncmds = sizeof(cmds) / sizeof(cmds[0]); - HANDLE wait_handles[2] = {rdns_semaphore, exit_event}; + HANDLE wait_handles[2] = {rdns_semaphore, exit_event}; - if(GetSystemDirectory(sys_path, MAX_PATH)) + if (GetSystemDirectory(sys_path, MAX_PATH)) { - _snwprintf (ipcfg, MAX_PATH, L"%s\\%s", sys_path, L"ipconfig.exe"); - ipcfg[MAX_PATH-1] = L'\0'; + _snwprintf(ipcfg, MAX_PATH, L"%s\\%s", sys_path, L"ipconfig.exe"); + ipcfg[MAX_PATH-1] = L'\0'; } - if (WaitForMultipleObjects (2, wait_handles, FALSE, timeout) == WAIT_OBJECT_0) + if (WaitForMultipleObjects(2, wait_handles, FALSE, timeout) == WAIT_OBJECT_0) { - /* Semaphore locked */ - for (i = 0; i < ncmds; ++i) + /* Semaphore locked */ + for (i = 0; i < ncmds; ++i) + { + ExecCommand(cmds[i].argv0, cmds[i].cmdline, cmds[i].timeout); + } + err = 0; + if (!ReleaseSemaphore(rdns_semaphore, 1, NULL) ) { - ExecCommand (cmds[i].argv0, cmds[i].cmdline, cmds[i].timeout); + err = MsgToEventLog(M_SYSERR, TEXT("RegisterDNS: Failed to release regsiter-dns semaphore:")); } - err = 0; - if ( !ReleaseSemaphore (rdns_semaphore, 1, NULL) ) - err = MsgToEventLog (M_SYSERR, TEXT("RegisterDNS: Failed to release regsiter-dns semaphore:")); } - else + else { - MsgToEventLog (M_ERR, TEXT("RegisterDNS: Failed to lock register-dns semaphore")); - err = ERROR_SEM_TIMEOUT; /* Windows error code 0x79 */ + MsgToEventLog(M_ERR, TEXT("RegisterDNS: Failed to lock register-dns semaphore")); + err = ERROR_SEM_TIMEOUT; /* Windows error code 0x79 */ } - return err; + return err; } static DWORD -HandleRegisterDNSMessage (void) +HandleRegisterDNSMessage(void) { - DWORD err; - HANDLE thread = NULL; + DWORD err; + HANDLE thread = NULL; - /* Delegate this job to a sub-thread */ - thread = CreateThread (NULL, 0, RegisterDNS, NULL, 0, NULL); + /* Delegate this job to a sub-thread */ + thread = CreateThread(NULL, 0, RegisterDNS, NULL, 0, NULL); - /* - * We don't add these thread handles to the undo list -- the thread and - * processes it spawns are all supposed to terminate or timeout by themselves. - */ - if (thread) + /* + * We don't add these thread handles to the undo list -- the thread and + * processes it spawns are all supposed to terminate or timeout by themselves. + */ + if (thread) + { + err = 0; + CloseHandle(thread); + } + else { - err = 0; - CloseHandle (thread); + err = GetLastError(); } - else - err = GetLastError(); - return err; + return err; } /** @@ -974,845 +1077,904 @@ HandleRegisterDNSMessage (void) * If addr is null and action = "delete" all addresses are deleted. */ static DWORD -netsh_dns_cmd (const wchar_t *action, const wchar_t *proto, const wchar_t *if_name, const wchar_t *addr) +netsh_dns_cmd(const wchar_t *action, const wchar_t *proto, const wchar_t *if_name, const wchar_t *addr) { - DWORD err = 0; - int timeout = 30000; /* in msec */ - wchar_t argv0[MAX_PATH]; + DWORD err = 0; + int timeout = 30000; /* in msec */ + wchar_t argv0[MAX_PATH]; - if (!addr) + if (!addr) { - if (wcscmp(action, L"delete") == 0) - addr = L"all"; - else /* nothing to do -- return success*/ - goto out; + if (wcscmp(action, L"delete") == 0) + { + addr = L"all"; + } + else /* nothing to do -- return success*/ + { + goto out; + } } - /* Path of netsh */ - int n = GetSystemDirectory (argv0, MAX_PATH); - if (n > 0 && n < MAX_PATH) /* got system directory */ - { - wcsncat(argv0, L"\\netsh.exe", MAX_PATH - n - 1); - } - else - { - wcsncpy(argv0, L"C:\\Windows\\system32\\netsh.exe", MAX_PATH); - } + /* Path of netsh */ + int n = GetSystemDirectory(argv0, MAX_PATH); + if (n > 0 && n < MAX_PATH) /* got system directory */ + { + wcsncat(argv0, L"\\netsh.exe", MAX_PATH - n - 1); + } + else + { + wcsncpy(argv0, L"C:\\Windows\\system32\\netsh.exe", MAX_PATH); + } - /* cmd template: - * netsh interface $proto $action dns $if_name $addr [validate=no] - */ - const wchar_t *fmt = L"netsh interface %s %s dns \"%s\" %s"; + /* cmd template: + * netsh interface $proto $action dns $if_name $addr [validate=no] + */ + const wchar_t *fmt = L"netsh interface %s %s dns \"%s\" %s"; - /* max cmdline length in wchars -- include room for worst case and some */ - int ncmdline = wcslen(fmt) + wcslen(if_name) + wcslen(addr) + 32 + 1; - wchar_t *cmdline = malloc(ncmdline*sizeof(wchar_t)); - if (!cmdline) - { - err = ERROR_OUTOFMEMORY; - goto out; - } + /* max cmdline length in wchars -- include room for worst case and some */ + int ncmdline = wcslen(fmt) + wcslen(if_name) + wcslen(addr) + 32 + 1; + wchar_t *cmdline = malloc(ncmdline*sizeof(wchar_t)); + if (!cmdline) + { + err = ERROR_OUTOFMEMORY; + goto out; + } - openvpn_sntprintf (cmdline, ncmdline, fmt, proto, action, if_name, addr); + openvpn_sntprintf(cmdline, ncmdline, fmt, proto, action, if_name, addr); - if (IsWindows7OrGreater()) + if (IsWindows7OrGreater()) { - wcsncat(cmdline, L" validate=no", ncmdline - wcslen(cmdline) - 1); + wcsncat(cmdline, L" validate=no", ncmdline - wcslen(cmdline) - 1); } - err = ExecCommand (argv0, cmdline, timeout); + err = ExecCommand(argv0, cmdline, timeout); out: - free (cmdline); - return err; + free(cmdline); + return err; } /* Delete all IPv4 or IPv6 dns servers for an interface */ static DWORD DeleteDNS(short family, wchar_t *if_name) { - wchar_t *proto = (family == AF_INET6) ? L"ipv6" : L"ip"; - return netsh_dns_cmd (L"delete", proto, if_name, NULL); + wchar_t *proto = (family == AF_INET6) ? L"ipv6" : L"ip"; + return netsh_dns_cmd(L"delete", proto, if_name, NULL); } /* Add an IPv4 or IPv6 dns server to an interface */ static DWORD AddDNS(short family, wchar_t *if_name, wchar_t *addr) { - wchar_t *proto = (family == AF_INET6) ? L"ipv6" : L"ip"; - return netsh_dns_cmd (L"add", proto, if_name, addr); + wchar_t *proto = (family == AF_INET6) ? L"ipv6" : L"ip"; + return netsh_dns_cmd(L"add", proto, if_name, addr); } static BOOL -CmpWString (LPVOID item, LPVOID str) +CmpWString(LPVOID item, LPVOID str) { - return (wcscmp (item, str) == 0) ? TRUE : FALSE; + return (wcscmp(item, str) == 0) ? TRUE : FALSE; } static DWORD -HandleDNSConfigMessage (const dns_cfg_message_t *msg, undo_lists_t *lists) +HandleDNSConfigMessage(const dns_cfg_message_t *msg, undo_lists_t *lists) { - DWORD err = 0; - wchar_t addr[46]; /* large enough to hold string representation of an ipv4 / ipv6 address */ - undo_type_t undo_type = (msg->family == AF_INET6) ? undo_dns4 : undo_dns6; - int addr_len = msg->addr_len; + DWORD err = 0; + wchar_t addr[46]; /* large enough to hold string representation of an ipv4 / ipv6 address */ + undo_type_t undo_type = (msg->family == AF_INET6) ? undo_dns4 : undo_dns6; + int addr_len = msg->addr_len; - /* sanity check */ - if (addr_len > _countof(msg->addr)) - addr_len = _countof(msg->addr); + /* sanity check */ + if (addr_len > _countof(msg->addr)) + { + addr_len = _countof(msg->addr); + } - if (!msg->iface.name[0]) /* interface name is required */ - return ERROR_MESSAGE_DATA; + if (!msg->iface.name[0]) /* interface name is required */ + { + return ERROR_MESSAGE_DATA; + } - wchar_t *wide_name = utf8to16(msg->iface.name); /* utf8 to wide-char */ - if (!wide_name) - return ERROR_OUTOFMEMORY; + wchar_t *wide_name = utf8to16(msg->iface.name); /* utf8 to wide-char */ + if (!wide_name) + { + return ERROR_OUTOFMEMORY; + } - /* We delete all current addresses before adding any - * OR if the message type is del_dns_cfg - */ - if (addr_len > 0 || msg->header.type == msg_del_dns_cfg) + /* We delete all current addresses before adding any + * OR if the message type is del_dns_cfg + */ + if (addr_len > 0 || msg->header.type == msg_del_dns_cfg) { - err = DeleteDNS(msg->family, wide_name); - if (err) - goto out; - free (RemoveListItem (&(*lists)[undo_type], CmpWString, wide_name)); + err = DeleteDNS(msg->family, wide_name); + if (err) + { + goto out; + } + free(RemoveListItem(&(*lists)[undo_type], CmpWString, wide_name)); } - if (msg->header.type == msg_del_dns_cfg) /* job done */ - goto out; + if (msg->header.type == msg_del_dns_cfg) /* job done */ + { + goto out; + } - for (int i = 0; i < addr_len; ++i) + for (int i = 0; i < addr_len; ++i) { - if (msg->family == AF_INET6) - RtlIpv6AddressToStringW (&msg->addr[i].ipv6, addr); - else - RtlIpv4AddressToStringW (&msg->addr[i].ipv4, addr); - err = AddDNS(msg->family, wide_name, addr); - if (i == 0 && err) - goto out; - /* We do not check for duplicate addresses, so any error in adding - * additional addresses is ignored. - */ + if (msg->family == AF_INET6) + { + RtlIpv6AddressToStringW(&msg->addr[i].ipv6, addr); + } + else + { + RtlIpv4AddressToStringW(&msg->addr[i].ipv4, addr); + } + err = AddDNS(msg->family, wide_name, addr); + if (i == 0 && err) + { + goto out; + } + /* We do not check for duplicate addresses, so any error in adding + * additional addresses is ignored. + */ } - if (msg->addr_len > 0) + if (msg->addr_len > 0) { - wchar_t *tmp_name = wcsdup(wide_name); - if (!tmp_name || AddListItem(&(*lists)[undo_type], tmp_name)) + wchar_t *tmp_name = wcsdup(wide_name); + if (!tmp_name || AddListItem(&(*lists)[undo_type], tmp_name)) { - free(tmp_name); - DeleteDNS(msg->family, wide_name); - err = ERROR_OUTOFMEMORY; - goto out; + free(tmp_name); + DeleteDNS(msg->family, wide_name); + err = ERROR_OUTOFMEMORY; + goto out; } } - err = 0; + err = 0; out: - free(wide_name); - return err; + free(wide_name); + return err; } static VOID -HandleMessage (HANDLE pipe, DWORD bytes, DWORD count, LPHANDLE events, undo_lists_t *lists) +HandleMessage(HANDLE pipe, DWORD bytes, DWORD count, LPHANDLE events, undo_lists_t *lists) { - DWORD read; - union { - message_header_t header; - address_message_t address; - route_message_t route; - flush_neighbors_message_t flush_neighbors; - block_dns_message_t block_dns; - dns_cfg_message_t dns; - } msg; - ack_message_t ack = { - .header = { - .type = msg_acknowledgement, - .size = sizeof (ack), - .message_id = -1 - }, - .error_number = ERROR_MESSAGE_DATA - }; - - read = ReadPipeAsync (pipe, &msg, bytes, count, events); - if (read != bytes || read < sizeof (msg.header) || read != msg.header.size) - goto out; - - ack.header.message_id = msg.header.message_id; - - switch (msg.header.type) - { - case msg_add_address: - case msg_del_address: - if (msg.header.size == sizeof (msg.address)) - ack.error_number = HandleAddressMessage (&msg.address, lists); - break; - - case msg_add_route: - case msg_del_route: - if (msg.header.size == sizeof (msg.route)) - ack.error_number = HandleRouteMessage (&msg.route, lists); - break; - - case msg_flush_neighbors: - if (msg.header.size == sizeof (msg.flush_neighbors)) - ack.error_number = HandleFlushNeighborsMessage (&msg.flush_neighbors); - break; - - case msg_add_block_dns: - case msg_del_block_dns: - if (msg.header.size == sizeof (msg.block_dns)) - ack.error_number = HandleBlockDNSMessage (&msg.block_dns, lists); - break; - - case msg_register_dns: - ack.error_number = HandleRegisterDNSMessage (); - break; + DWORD read; + union { + message_header_t header; + address_message_t address; + route_message_t route; + flush_neighbors_message_t flush_neighbors; + block_dns_message_t block_dns; + dns_cfg_message_t dns; + } msg; + ack_message_t ack = { + .header = { + .type = msg_acknowledgement, + .size = sizeof(ack), + .message_id = -1 + }, + .error_number = ERROR_MESSAGE_DATA + }; + + read = ReadPipeAsync(pipe, &msg, bytes, count, events); + if (read != bytes || read < sizeof(msg.header) || read != msg.header.size) + { + goto out; + } - case msg_add_dns_cfg: - case msg_del_dns_cfg: - ack.error_number = HandleDNSConfigMessage (&msg.dns, lists); - break; + ack.header.message_id = msg.header.message_id; + + switch (msg.header.type) + { + case msg_add_address: + case msg_del_address: + if (msg.header.size == sizeof(msg.address)) + { + ack.error_number = HandleAddressMessage(&msg.address, lists); + } + break; + + case msg_add_route: + case msg_del_route: + if (msg.header.size == sizeof(msg.route)) + { + ack.error_number = HandleRouteMessage(&msg.route, lists); + } + break; - default: - ack.error_number = ERROR_MESSAGE_TYPE; - MsgToEventLog (MSG_FLAGS_ERROR, TEXT("Unknown message type %d"), msg.header.type); - break; + case msg_flush_neighbors: + if (msg.header.size == sizeof(msg.flush_neighbors)) + { + ack.error_number = HandleFlushNeighborsMessage(&msg.flush_neighbors); + } + break; + + case msg_add_block_dns: + case msg_del_block_dns: + if (msg.header.size == sizeof(msg.block_dns)) + { + ack.error_number = HandleBlockDNSMessage(&msg.block_dns, lists); + } + break; + + case msg_register_dns: + ack.error_number = HandleRegisterDNSMessage(); + break; + + case msg_add_dns_cfg: + case msg_del_dns_cfg: + ack.error_number = HandleDNSConfigMessage(&msg.dns, lists); + break; + + default: + ack.error_number = ERROR_MESSAGE_TYPE; + MsgToEventLog(MSG_FLAGS_ERROR, TEXT("Unknown message type %d"), msg.header.type); + break; } out: - WritePipeAsync (pipe, &ack, sizeof (ack), count, events); + WritePipeAsync(pipe, &ack, sizeof(ack), count, events); } static VOID -Undo (undo_lists_t *lists) +Undo(undo_lists_t *lists) { - undo_type_t type; - for (type = 0; type < _undo_type_max; type++) + undo_type_t type; + for (type = 0; type < _undo_type_max; type++) { - list_item_t **pnext = &(*lists)[type]; - while (*pnext) + list_item_t **pnext = &(*lists)[type]; + while (*pnext) { - list_item_t *item = *pnext; - switch (type) + list_item_t *item = *pnext; + switch (type) { - case address: - DeleteAddress (item->data); - break; - - case route: - DeleteRoute (item->data); - break; - - case undo_dns4: - DeleteDNS(AF_INET, item->data); - break; - - case undo_dns6: - DeleteDNS(AF_INET6, item->data); - break; - - case block_dns: - delete_block_dns_filters (item->data); - item->data = NULL; - break; + case address: + DeleteAddress(item->data); + break; + + case route: + DeleteRoute(item->data); + break; + + case undo_dns4: + DeleteDNS(AF_INET, item->data); + break; + + case undo_dns6: + DeleteDNS(AF_INET6, item->data); + break; + + case block_dns: + delete_block_dns_filters(item->data); + item->data = NULL; + break; } - /* Remove from the list and free memory */ - *pnext = item->next; - free (item->data); - free (item); + /* Remove from the list and free memory */ + *pnext = item->next; + free(item->data); + free(item); } } } static DWORD WINAPI -RunOpenvpn (LPVOID p) +RunOpenvpn(LPVOID p) { - HANDLE pipe = p; - HANDLE ovpn_pipe, svc_pipe; - PTOKEN_USER svc_user, ovpn_user; - HANDLE svc_token = NULL, imp_token = NULL, pri_token = NULL; - HANDLE stdin_read = NULL, stdin_write = NULL; - HANDLE stdout_write = NULL; - DWORD pipe_mode, len, exit_code = 0; - STARTUP_DATA sud = { 0, 0, 0 }; - STARTUPINFOW startup_info; - PROCESS_INFORMATION proc_info; - LPVOID user_env = NULL; - TCHAR ovpn_pipe_name[36]; - LPCWSTR exe_path; - WCHAR *cmdline = NULL; - size_t cmdline_size; - undo_lists_t undo_lists; - - SECURITY_ATTRIBUTES inheritable = { - .nLength = sizeof (inheritable), - .lpSecurityDescriptor = NULL, - .bInheritHandle = TRUE - }; - - PACL ovpn_dacl; - EXPLICIT_ACCESS ea[2]; - SECURITY_DESCRIPTOR ovpn_sd; - SECURITY_ATTRIBUTES ovpn_sa = { - .nLength = sizeof (ovpn_sa), - .lpSecurityDescriptor = &ovpn_sd, - .bInheritHandle = FALSE - }; - - ZeroMemory (&ea, sizeof (ea)); - ZeroMemory (&startup_info, sizeof (startup_info)); - ZeroMemory (&undo_lists, sizeof (undo_lists)); - ZeroMemory (&proc_info, sizeof (proc_info)); - - if (!GetStartupData (pipe, &sud)) - goto out; - - if (!InitializeSecurityDescriptor (&ovpn_sd, SECURITY_DESCRIPTOR_REVISION)) - { - ReturnLastError (pipe, L"InitializeSecurityDescriptor"); - goto out; - } - - /* Get SID of user the service is running under */ - if (!OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &svc_token)) - { - ReturnLastError (pipe, L"OpenProcessToken"); - goto out; - } - len = 0; - svc_user = NULL; - while (!GetTokenInformation (svc_token, TokenUser, svc_user, len, &len)) - { - if (GetLastError () != ERROR_INSUFFICIENT_BUFFER) + HANDLE pipe = p; + HANDLE ovpn_pipe, svc_pipe; + PTOKEN_USER svc_user, ovpn_user; + HANDLE svc_token = NULL, imp_token = NULL, pri_token = NULL; + HANDLE stdin_read = NULL, stdin_write = NULL; + HANDLE stdout_write = NULL; + DWORD pipe_mode, len, exit_code = 0; + STARTUP_DATA sud = { 0, 0, 0 }; + STARTUPINFOW startup_info; + PROCESS_INFORMATION proc_info; + LPVOID user_env = NULL; + TCHAR ovpn_pipe_name[36]; + LPCWSTR exe_path; + WCHAR *cmdline = NULL; + size_t cmdline_size; + undo_lists_t undo_lists; + + SECURITY_ATTRIBUTES inheritable = { + .nLength = sizeof(inheritable), + .lpSecurityDescriptor = NULL, + .bInheritHandle = TRUE + }; + + PACL ovpn_dacl; + EXPLICIT_ACCESS ea[2]; + SECURITY_DESCRIPTOR ovpn_sd; + SECURITY_ATTRIBUTES ovpn_sa = { + .nLength = sizeof(ovpn_sa), + .lpSecurityDescriptor = &ovpn_sd, + .bInheritHandle = FALSE + }; + + ZeroMemory(&ea, sizeof(ea)); + ZeroMemory(&startup_info, sizeof(startup_info)); + ZeroMemory(&undo_lists, sizeof(undo_lists)); + ZeroMemory(&proc_info, sizeof(proc_info)); + + if (!GetStartupData(pipe, &sud)) + { + goto out; + } + + if (!InitializeSecurityDescriptor(&ovpn_sd, SECURITY_DESCRIPTOR_REVISION)) + { + ReturnLastError(pipe, L"InitializeSecurityDescriptor"); + goto out; + } + + /* Get SID of user the service is running under */ + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &svc_token)) + { + ReturnLastError(pipe, L"OpenProcessToken"); + goto out; + } + len = 0; + svc_user = NULL; + while (!GetTokenInformation(svc_token, TokenUser, svc_user, len, &len)) + { + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { - ReturnLastError (pipe, L"GetTokenInformation (service token)"); - goto out; + ReturnLastError(pipe, L"GetTokenInformation (service token)"); + goto out; } - free (svc_user); - svc_user = malloc (len); - if (svc_user == NULL) + free(svc_user); + svc_user = malloc(len); + if (svc_user == NULL) { - ReturnLastError (pipe, L"malloc (service token user)"); - goto out; + ReturnLastError(pipe, L"malloc (service token user)"); + goto out; } } - if (!IsValidSid (svc_user->User.Sid)) + if (!IsValidSid(svc_user->User.Sid)) { - ReturnLastError (pipe, L"IsValidSid (service token user)"); - goto out; + ReturnLastError(pipe, L"IsValidSid (service token user)"); + goto out; } - if (!ImpersonateNamedPipeClient (pipe)) + if (!ImpersonateNamedPipeClient(pipe)) { - ReturnLastError (pipe, L"ImpersonateNamedPipeClient"); - goto out; + ReturnLastError(pipe, L"ImpersonateNamedPipeClient"); + goto out; } - if (!OpenThreadToken (GetCurrentThread (), TOKEN_ALL_ACCESS, FALSE, &imp_token)) + if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, FALSE, &imp_token)) { - ReturnLastError (pipe, L"OpenThreadToken"); - goto out; + ReturnLastError(pipe, L"OpenThreadToken"); + goto out; } - len = 0; - ovpn_user = NULL; - while (!GetTokenInformation (imp_token, TokenUser, ovpn_user, len, &len)) + len = 0; + ovpn_user = NULL; + while (!GetTokenInformation(imp_token, TokenUser, ovpn_user, len, &len)) { - if (GetLastError () != ERROR_INSUFFICIENT_BUFFER) + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { - ReturnLastError (pipe, L"GetTokenInformation (impersonation token)"); - goto out; + ReturnLastError(pipe, L"GetTokenInformation (impersonation token)"); + goto out; } - free (ovpn_user); - ovpn_user = malloc (len); - if (ovpn_user == NULL) + free(ovpn_user); + ovpn_user = malloc(len); + if (ovpn_user == NULL) { - ReturnLastError (pipe, L"malloc (impersonation token user)"); - goto out; + ReturnLastError(pipe, L"malloc (impersonation token user)"); + goto out; } } - if (!IsValidSid (ovpn_user->User.Sid)) + if (!IsValidSid(ovpn_user->User.Sid)) { - ReturnLastError (pipe, L"IsValidSid (impersonation token user)"); - goto out; + ReturnLastError(pipe, L"IsValidSid (impersonation token user)"); + goto out; } - /* Check user is authorized or options are white-listed */ - if (!IsAuthorizedUser (ovpn_user->User.Sid, &settings) && - !ValidateOptions (pipe, sud.directory, sud.options)) + /* Check user is authorized or options are white-listed */ + if (!IsAuthorizedUser(ovpn_user->User.Sid, &settings) + && !ValidateOptions(pipe, sud.directory, sud.options)) { - goto out; + goto out; } - /* OpenVPN process DACL entry for access by service and user */ - ea[0].grfAccessPermissions = SPECIFIC_RIGHTS_ALL | STANDARD_RIGHTS_ALL; - ea[0].grfAccessMode = SET_ACCESS; - ea[0].grfInheritance = NO_INHERITANCE; - ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID; - ea[0].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN; - ea[0].Trustee.ptstrName = (LPTSTR) svc_user->User.Sid; - ea[1].grfAccessPermissions = READ_CONTROL | SYNCHRONIZE | PROCESS_VM_READ | - SYNCHRONIZE | PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION; - ea[1].grfAccessMode = SET_ACCESS; - ea[1].grfInheritance = NO_INHERITANCE; - ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID; - ea[1].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN; - ea[1].Trustee.ptstrName = (LPTSTR) ovpn_user->User.Sid; - - /* Set owner and DACL of OpenVPN security descriptor */ - if (!SetSecurityDescriptorOwner (&ovpn_sd, svc_user->User.Sid, FALSE)) - { - ReturnLastError (pipe, L"SetSecurityDescriptorOwner"); - goto out; + /* OpenVPN process DACL entry for access by service and user */ + ea[0].grfAccessPermissions = SPECIFIC_RIGHTS_ALL | STANDARD_RIGHTS_ALL; + ea[0].grfAccessMode = SET_ACCESS; + ea[0].grfInheritance = NO_INHERITANCE; + ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID; + ea[0].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN; + ea[0].Trustee.ptstrName = (LPTSTR) svc_user->User.Sid; + ea[1].grfAccessPermissions = READ_CONTROL | SYNCHRONIZE | PROCESS_VM_READ + |SYNCHRONIZE | PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION; + ea[1].grfAccessMode = SET_ACCESS; + ea[1].grfInheritance = NO_INHERITANCE; + ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID; + ea[1].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN; + ea[1].Trustee.ptstrName = (LPTSTR) ovpn_user->User.Sid; + + /* Set owner and DACL of OpenVPN security descriptor */ + if (!SetSecurityDescriptorOwner(&ovpn_sd, svc_user->User.Sid, FALSE)) + { + ReturnLastError(pipe, L"SetSecurityDescriptorOwner"); + goto out; } - if (SetEntriesInAcl (2, ea, NULL, &ovpn_dacl) != ERROR_SUCCESS) + if (SetEntriesInAcl(2, ea, NULL, &ovpn_dacl) != ERROR_SUCCESS) { - ReturnLastError (pipe, L"SetEntriesInAcl"); - goto out; + ReturnLastError(pipe, L"SetEntriesInAcl"); + goto out; } - if (!SetSecurityDescriptorDacl (&ovpn_sd, TRUE, ovpn_dacl, FALSE)) + if (!SetSecurityDescriptorDacl(&ovpn_sd, TRUE, ovpn_dacl, FALSE)) { - ReturnLastError (pipe, L"SetSecurityDescriptorDacl"); - goto out; + ReturnLastError(pipe, L"SetSecurityDescriptorDacl"); + goto out; } - /* Create primary token from impersonation token */ - if (!DuplicateTokenEx (imp_token, TOKEN_ALL_ACCESS, NULL, 0, TokenPrimary, &pri_token)) + /* Create primary token from impersonation token */ + if (!DuplicateTokenEx(imp_token, TOKEN_ALL_ACCESS, NULL, 0, TokenPrimary, &pri_token)) { - ReturnLastError (pipe, L"DuplicateTokenEx"); - goto out; + ReturnLastError(pipe, L"DuplicateTokenEx"); + goto out; } - /* use /dev/null for stdout of openvpn (client should use --log for output) */ - stdout_write = CreateFile(_T("NUL"), GENERIC_WRITE, FILE_SHARE_WRITE, - &inheritable, OPEN_EXISTING, 0, NULL); - if (stdout_write == INVALID_HANDLE_VALUE) + /* use /dev/null for stdout of openvpn (client should use --log for output) */ + stdout_write = CreateFile(_T("NUL"), GENERIC_WRITE, FILE_SHARE_WRITE, + &inheritable, OPEN_EXISTING, 0, NULL); + if (stdout_write == INVALID_HANDLE_VALUE) { - ReturnLastError (pipe, L"CreateFile for stdout"); - goto out; + ReturnLastError(pipe, L"CreateFile for stdout"); + goto out; } - if (!CreatePipe(&stdin_read, &stdin_write, &inheritable, 0) || - !SetHandleInformation(stdin_write, HANDLE_FLAG_INHERIT, 0)) + if (!CreatePipe(&stdin_read, &stdin_write, &inheritable, 0) + || !SetHandleInformation(stdin_write, HANDLE_FLAG_INHERIT, 0)) { - ReturnLastError (pipe, L"CreatePipe"); - goto out; + ReturnLastError(pipe, L"CreatePipe"); + goto out; } - openvpn_sntprintf (ovpn_pipe_name, _countof (ovpn_pipe_name), - TEXT("\\\\.\\pipe\\openvpn\\service_%lu"), GetCurrentThreadId ()); - ovpn_pipe = CreateNamedPipe (ovpn_pipe_name, - PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_OVERLAPPED, - PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 1, 128, 128, 0, NULL); - if (ovpn_pipe == INVALID_HANDLE_VALUE) + openvpn_sntprintf(ovpn_pipe_name, _countof(ovpn_pipe_name), + TEXT("\\\\.\\pipe\\openvpn\\service_%lu"), GetCurrentThreadId()); + ovpn_pipe = CreateNamedPipe(ovpn_pipe_name, + PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_OVERLAPPED, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 1, 128, 128, 0, NULL); + if (ovpn_pipe == INVALID_HANDLE_VALUE) { - ReturnLastError (pipe, L"CreateNamedPipe"); - goto out; + ReturnLastError(pipe, L"CreateNamedPipe"); + goto out; } - svc_pipe = CreateFile (ovpn_pipe_name, GENERIC_READ | GENERIC_WRITE, 0, - &inheritable, OPEN_EXISTING, 0, NULL); - if (svc_pipe == INVALID_HANDLE_VALUE) + svc_pipe = CreateFile(ovpn_pipe_name, GENERIC_READ | GENERIC_WRITE, 0, + &inheritable, OPEN_EXISTING, 0, NULL); + if (svc_pipe == INVALID_HANDLE_VALUE) { - ReturnLastError (pipe, L"CreateFile"); - goto out; + ReturnLastError(pipe, L"CreateFile"); + goto out; } - pipe_mode = PIPE_READMODE_MESSAGE; - if (!SetNamedPipeHandleState (svc_pipe, &pipe_mode, NULL, NULL)) + pipe_mode = PIPE_READMODE_MESSAGE; + if (!SetNamedPipeHandleState(svc_pipe, &pipe_mode, NULL, NULL)) { - ReturnLastError (pipe, L"SetNamedPipeHandleState"); - goto out; + ReturnLastError(pipe, L"SetNamedPipeHandleState"); + goto out; } - cmdline_size = wcslen (sud.options) + 128; - cmdline = malloc (cmdline_size * sizeof (*cmdline)); - if (cmdline == NULL) + cmdline_size = wcslen(sud.options) + 128; + cmdline = malloc(cmdline_size * sizeof(*cmdline)); + if (cmdline == NULL) { - ReturnLastError (pipe, L"malloc"); - goto out; + ReturnLastError(pipe, L"malloc"); + goto out; } - openvpn_sntprintf (cmdline, cmdline_size, L"openvpn %s --msg-channel %lu", - sud.options, svc_pipe); + openvpn_sntprintf(cmdline, cmdline_size, L"openvpn %s --msg-channel %lu", + sud.options, svc_pipe); - if (!CreateEnvironmentBlock (&user_env, imp_token, FALSE)) + if (!CreateEnvironmentBlock(&user_env, imp_token, FALSE)) { - ReturnLastError (pipe, L"CreateEnvironmentBlock"); - goto out; + ReturnLastError(pipe, L"CreateEnvironmentBlock"); + goto out; } - startup_info.cb = sizeof (startup_info); - startup_info.lpDesktop = L"winsta0\\default"; - startup_info.dwFlags = STARTF_USESTDHANDLES; - startup_info.hStdInput = stdin_read; - startup_info.hStdOutput = stdout_write; - startup_info.hStdError = stdout_write; + startup_info.cb = sizeof(startup_info); + startup_info.lpDesktop = L"winsta0\\default"; + startup_info.dwFlags = STARTF_USESTDHANDLES; + startup_info.hStdInput = stdin_read; + startup_info.hStdOutput = stdout_write; + startup_info.hStdError = stdout_write; #ifdef UNICODE - exe_path = settings.exe_path; + exe_path = settings.exe_path; #else - WCHAR wide_path[MAX_PATH]; - MultiByteToWideChar (CP_UTF8, 0, settings.exe_path, MAX_PATH, wide_path, MAX_PATH); - exe_path = wide_path; + WCHAR wide_path[MAX_PATH]; + MultiByteToWideChar(CP_UTF8, 0, settings.exe_path, MAX_PATH, wide_path, MAX_PATH); + exe_path = wide_path; #endif - // TODO: make sure HKCU is correct or call LoadUserProfile() - if (!CreateProcessAsUserW (pri_token, exe_path, cmdline, &ovpn_sa, NULL, TRUE, - settings.priority | CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT, - user_env, sud.directory, &startup_info, &proc_info)) + /* TODO: make sure HKCU is correct or call LoadUserProfile() */ + if (!CreateProcessAsUserW(pri_token, exe_path, cmdline, &ovpn_sa, NULL, TRUE, + settings.priority | CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT, + user_env, sud.directory, &startup_info, &proc_info)) { - ReturnLastError (pipe, L"CreateProcessAsUser"); - goto out; + ReturnLastError(pipe, L"CreateProcessAsUser"); + goto out; } - if (!RevertToSelf ()) + if (!RevertToSelf()) { - TerminateProcess (proc_info.hProcess, 1); - ReturnLastError (pipe, L"RevertToSelf"); - goto out; + TerminateProcess(proc_info.hProcess, 1); + ReturnLastError(pipe, L"RevertToSelf"); + goto out; } - ReturnProcessId (pipe, proc_info.dwProcessId, 1, &exit_event); + ReturnProcessId(pipe, proc_info.dwProcessId, 1, &exit_event); - CloseHandleEx (&stdout_write); - CloseHandleEx (&stdin_read); - CloseHandleEx (&svc_pipe); + CloseHandleEx(&stdout_write); + CloseHandleEx(&stdin_read); + CloseHandleEx(&svc_pipe); - DWORD input_size = WideCharToMultiByte (CP_UTF8, 0, sud.std_input, -1, NULL, 0, NULL, NULL); - LPSTR input = NULL; - if (input_size && (input = malloc (input_size))) + DWORD input_size = WideCharToMultiByte(CP_UTF8, 0, sud.std_input, -1, NULL, 0, NULL, NULL); + LPSTR input = NULL; + if (input_size && (input = malloc(input_size))) { - DWORD written; - WideCharToMultiByte (CP_UTF8, 0, sud.std_input, -1, input, input_size, NULL, NULL); - WriteFile (stdin_write, input, strlen (input), &written, NULL); - free (input); + DWORD written; + WideCharToMultiByte(CP_UTF8, 0, sud.std_input, -1, input, input_size, NULL, NULL); + WriteFile(stdin_write, input, strlen(input), &written, NULL); + free(input); } - while (TRUE) + while (TRUE) { - DWORD bytes = PeekNamedPipeAsync (ovpn_pipe, 1, &exit_event); - if (bytes == 0) - break; + DWORD bytes = PeekNamedPipeAsync(ovpn_pipe, 1, &exit_event); + if (bytes == 0) + { + break; + } - HandleMessage (ovpn_pipe, bytes, 1, &exit_event, &undo_lists); + HandleMessage(ovpn_pipe, bytes, 1, &exit_event, &undo_lists); } - WaitForSingleObject (proc_info.hProcess, IO_TIMEOUT); - GetExitCodeProcess (proc_info.hProcess, &exit_code); - if (exit_code == STILL_ACTIVE) - TerminateProcess (proc_info.hProcess, 1); - else if (exit_code != 0) + WaitForSingleObject(proc_info.hProcess, IO_TIMEOUT); + GetExitCodeProcess(proc_info.hProcess, &exit_code); + if (exit_code == STILL_ACTIVE) { - WCHAR buf[256]; - int len = _snwprintf (buf, _countof (buf), - L"OpenVPN exited with error: exit code = %lu", exit_code); - buf[_countof (buf) - 1] = L'\0'; - ReturnError (pipe, ERROR_OPENVPN_STARTUP, buf, 1, &exit_event); + TerminateProcess(proc_info.hProcess, 1); } - Undo (&undo_lists); + else if (exit_code != 0) + { + WCHAR buf[256]; + int len = _snwprintf(buf, _countof(buf), + L"OpenVPN exited with error: exit code = %lu", exit_code); + buf[_countof(buf) - 1] = L'\0'; + ReturnError(pipe, ERROR_OPENVPN_STARTUP, buf, 1, &exit_event); + } + Undo(&undo_lists); out: - FlushFileBuffers (pipe); - DisconnectNamedPipe (pipe); - - free (ovpn_user); - free (svc_user); - free (cmdline); - DestroyEnvironmentBlock (user_env); - FreeStartupData (&sud); - CloseHandleEx (&proc_info.hProcess); - CloseHandleEx (&proc_info.hThread); - CloseHandleEx (&stdin_read); - CloseHandleEx (&stdin_write); - CloseHandleEx (&stdout_write); - CloseHandleEx (&svc_token); - CloseHandleEx (&imp_token); - CloseHandleEx (&pri_token); - CloseHandleEx (&ovpn_pipe); - CloseHandleEx (&svc_pipe); - CloseHandleEx (&pipe); - - return 0; + FlushFileBuffers(pipe); + DisconnectNamedPipe(pipe); + + free(ovpn_user); + free(svc_user); + free(cmdline); + DestroyEnvironmentBlock(user_env); + FreeStartupData(&sud); + CloseHandleEx(&proc_info.hProcess); + CloseHandleEx(&proc_info.hThread); + CloseHandleEx(&stdin_read); + CloseHandleEx(&stdin_write); + CloseHandleEx(&stdout_write); + CloseHandleEx(&svc_token); + CloseHandleEx(&imp_token); + CloseHandleEx(&pri_token); + CloseHandleEx(&ovpn_pipe); + CloseHandleEx(&svc_pipe); + CloseHandleEx(&pipe); + + return 0; } static DWORD WINAPI -ServiceCtrlInteractive (DWORD ctrl_code, DWORD event, LPVOID data, LPVOID ctx) +ServiceCtrlInteractive(DWORD ctrl_code, DWORD event, LPVOID data, LPVOID ctx) { - SERVICE_STATUS *status = ctx; - switch (ctrl_code) + SERVICE_STATUS *status = ctx; + switch (ctrl_code) { - case SERVICE_CONTROL_STOP: - status->dwCurrentState = SERVICE_STOP_PENDING; - ReportStatusToSCMgr (service, status); - if (exit_event) - SetEvent (exit_event); - return NO_ERROR; + case SERVICE_CONTROL_STOP: + status->dwCurrentState = SERVICE_STOP_PENDING; + ReportStatusToSCMgr(service, status); + if (exit_event) + { + SetEvent(exit_event); + } + return NO_ERROR; - case SERVICE_CONTROL_INTERROGATE: - return NO_ERROR; + case SERVICE_CONTROL_INTERROGATE: + return NO_ERROR; - default: - return ERROR_CALL_NOT_IMPLEMENTED; + default: + return ERROR_CALL_NOT_IMPLEMENTED; } } static HANDLE -CreateClientPipeInstance (VOID) +CreateClientPipeInstance(VOID) { - HANDLE pipe = NULL; - PACL old_dacl, new_dacl; - PSECURITY_DESCRIPTOR sd; - static EXPLICIT_ACCESS ea[2]; - static BOOL initialized = FALSE; - DWORD flags = PIPE_ACCESS_DUPLEX | WRITE_DAC | FILE_FLAG_OVERLAPPED; + HANDLE pipe = NULL; + PACL old_dacl, new_dacl; + PSECURITY_DESCRIPTOR sd; + static EXPLICIT_ACCESS ea[2]; + static BOOL initialized = FALSE; + DWORD flags = PIPE_ACCESS_DUPLEX | WRITE_DAC | FILE_FLAG_OVERLAPPED; - if (!initialized) + if (!initialized) { - PSID everyone, anonymous; + PSID everyone, anonymous; - ConvertStringSidToSid (TEXT("S-1-1-0"), &everyone); - ConvertStringSidToSid (TEXT("S-1-5-7"), &anonymous); + ConvertStringSidToSid(TEXT("S-1-1-0"), &everyone); + ConvertStringSidToSid(TEXT("S-1-5-7"), &anonymous); - ea[0].grfAccessPermissions = FILE_GENERIC_WRITE; - ea[0].grfAccessMode = GRANT_ACCESS; - ea[0].grfInheritance = NO_INHERITANCE; - ea[0].Trustee.pMultipleTrustee = NULL; - ea[0].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE; - ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID; - ea[0].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN; - ea[0].Trustee.ptstrName = (LPTSTR) everyone; + ea[0].grfAccessPermissions = FILE_GENERIC_WRITE; + ea[0].grfAccessMode = GRANT_ACCESS; + ea[0].grfInheritance = NO_INHERITANCE; + ea[0].Trustee.pMultipleTrustee = NULL; + ea[0].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE; + ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID; + ea[0].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN; + ea[0].Trustee.ptstrName = (LPTSTR) everyone; - ea[1].grfAccessPermissions = 0; - ea[1].grfAccessMode = REVOKE_ACCESS; - ea[1].grfInheritance = NO_INHERITANCE; - ea[1].Trustee.pMultipleTrustee = NULL; - ea[1].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE; - ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID; - ea[1].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN; - ea[1].Trustee.ptstrName = (LPTSTR) anonymous; + ea[1].grfAccessPermissions = 0; + ea[1].grfAccessMode = REVOKE_ACCESS; + ea[1].grfInheritance = NO_INHERITANCE; + ea[1].Trustee.pMultipleTrustee = NULL; + ea[1].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE; + ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID; + ea[1].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN; + ea[1].Trustee.ptstrName = (LPTSTR) anonymous; - flags |= FILE_FLAG_FIRST_PIPE_INSTANCE; - initialized = TRUE; + flags |= FILE_FLAG_FIRST_PIPE_INSTANCE; + initialized = TRUE; } - pipe = CreateNamedPipe (TEXT("\\\\.\\pipe\\openvpn\\service"), flags, - PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, - PIPE_UNLIMITED_INSTANCES, 1024, 1024, 0, NULL); - if (pipe == INVALID_HANDLE_VALUE) + pipe = CreateNamedPipe(TEXT("\\\\.\\pipe\\openvpn\\service"), flags, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, + PIPE_UNLIMITED_INSTANCES, 1024, 1024, 0, NULL); + if (pipe == INVALID_HANDLE_VALUE) { - MsgToEventLog (M_SYSERR, TEXT("Could not create named pipe")); - return INVALID_HANDLE_VALUE; + MsgToEventLog(M_SYSERR, TEXT("Could not create named pipe")); + return INVALID_HANDLE_VALUE; } - if (GetSecurityInfo (pipe, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, + if (GetSecurityInfo(pipe, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, &old_dacl, NULL, &sd) != ERROR_SUCCESS) { - MsgToEventLog (M_SYSERR, TEXT("Could not get pipe security info")); - return CloseHandleEx (&pipe); + MsgToEventLog(M_SYSERR, TEXT("Could not get pipe security info")); + return CloseHandleEx(&pipe); } - if (SetEntriesInAcl (2, ea, old_dacl, &new_dacl) != ERROR_SUCCESS) + if (SetEntriesInAcl(2, ea, old_dacl, &new_dacl) != ERROR_SUCCESS) { - MsgToEventLog (M_SYSERR, TEXT("Could not set entries in new acl")); - return CloseHandleEx (&pipe); + MsgToEventLog(M_SYSERR, TEXT("Could not set entries in new acl")); + return CloseHandleEx(&pipe); } - if (SetSecurityInfo (pipe, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, + if (SetSecurityInfo(pipe, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, new_dacl, NULL) != ERROR_SUCCESS) { - MsgToEventLog (M_SYSERR, TEXT("Could not set pipe security info")); - return CloseHandleEx (&pipe); + MsgToEventLog(M_SYSERR, TEXT("Could not set pipe security info")); + return CloseHandleEx(&pipe); } - return pipe; + return pipe; } static DWORD -UpdateWaitHandles (LPHANDLE *handles_ptr, LPDWORD count, - HANDLE io_event, HANDLE exit_event, list_item_t *threads) +UpdateWaitHandles(LPHANDLE *handles_ptr, LPDWORD count, + HANDLE io_event, HANDLE exit_event, list_item_t *threads) { - static DWORD size = 10; - static LPHANDLE handles = NULL; - DWORD pos = 0; + static DWORD size = 10; + static LPHANDLE handles = NULL; + DWORD pos = 0; - if (handles == NULL) + if (handles == NULL) { - handles = malloc (size * sizeof (HANDLE)); - *handles_ptr = handles; - if (handles == NULL) - return ERROR_OUTOFMEMORY; + handles = malloc(size * sizeof(HANDLE)); + *handles_ptr = handles; + if (handles == NULL) + { + return ERROR_OUTOFMEMORY; + } } - handles[pos++] = io_event; + handles[pos++] = io_event; - if (!threads) - handles[pos++] = exit_event; + if (!threads) + { + handles[pos++] = exit_event; + } - while (threads) + while (threads) { - if (pos == size) + if (pos == size) { - LPHANDLE tmp; - size += 10; - tmp = realloc (handles, size * sizeof (HANDLE)); - if (tmp == NULL) + LPHANDLE tmp; + size += 10; + tmp = realloc(handles, size * sizeof(HANDLE)); + if (tmp == NULL) { - size -= 10; - *count = pos; - return ERROR_OUTOFMEMORY; + size -= 10; + *count = pos; + return ERROR_OUTOFMEMORY; } - handles = tmp; - *handles_ptr = handles; + handles = tmp; + *handles_ptr = handles; } - handles[pos++] = threads->data; - threads = threads->next; + handles[pos++] = threads->data; + threads = threads->next; } - *count = pos; - return NO_ERROR; + *count = pos; + return NO_ERROR; } static VOID -FreeWaitHandles (LPHANDLE h) +FreeWaitHandles(LPHANDLE h) { - free (h); + free(h); } VOID WINAPI -ServiceStartInteractive (DWORD dwArgc, LPTSTR *lpszArgv) +ServiceStartInteractive(DWORD dwArgc, LPTSTR *lpszArgv) { - HANDLE pipe, io_event = NULL; - OVERLAPPED overlapped; - DWORD error = NO_ERROR; - list_item_t *threads = NULL; - PHANDLE handles = NULL; - DWORD handle_count; - BOOL CmpHandle (LPVOID item, LPVOID hnd) { return item == hnd; } - - service = RegisterServiceCtrlHandlerEx (interactive_service.name, ServiceCtrlInteractive, &status); - if (!service) - return; - - status.dwServiceType = SERVICE_WIN32_SHARE_PROCESS; - status.dwCurrentState = SERVICE_START_PENDING; - status.dwServiceSpecificExitCode = NO_ERROR; - status.dwWin32ExitCode = NO_ERROR; - status.dwWaitHint = 3000; - ReportStatusToSCMgr (service, &status); - - /* Read info from registry in key HKLM\SOFTWARE\OpenVPN */ - error = GetOpenvpnSettings (&settings); - if (error != ERROR_SUCCESS) - goto out; - - io_event = InitOverlapped (&overlapped); - exit_event = CreateEvent (NULL, TRUE, FALSE, NULL); - if (!exit_event || !io_event) - { - error = MsgToEventLog (M_SYSERR, TEXT("Could not create event")); - goto out; - } - - rdns_semaphore = CreateSemaphoreW (NULL, 1, 1, NULL); - if (!rdns_semaphore) - { - error = MsgToEventLog (M_SYSERR, TEXT("Could not create semaphore for register-dns")); - goto out; - } - - error = UpdateWaitHandles (&handles, &handle_count, io_event, exit_event, threads); - if (error != NO_ERROR) - goto out; - - pipe = CreateClientPipeInstance (); - if (pipe == INVALID_HANDLE_VALUE) - goto out; - - status.dwCurrentState = SERVICE_RUNNING; - status.dwWaitHint = 0; - ReportStatusToSCMgr (service, &status); - - while (TRUE) - { - if (ConnectNamedPipe (pipe, &overlapped) == FALSE && - GetLastError () != ERROR_PIPE_CONNECTED && - GetLastError () != ERROR_IO_PENDING) + HANDLE pipe, io_event = NULL; + OVERLAPPED overlapped; + DWORD error = NO_ERROR; + list_item_t *threads = NULL; + PHANDLE handles = NULL; + DWORD handle_count; + BOOL + CmpHandle(LPVOID item, LPVOID hnd) { + return item == hnd; + } + + service = RegisterServiceCtrlHandlerEx(interactive_service.name, ServiceCtrlInteractive, &status); + if (!service) + { + return; + } + + status.dwServiceType = SERVICE_WIN32_SHARE_PROCESS; + status.dwCurrentState = SERVICE_START_PENDING; + status.dwServiceSpecificExitCode = NO_ERROR; + status.dwWin32ExitCode = NO_ERROR; + status.dwWaitHint = 3000; + ReportStatusToSCMgr(service, &status); + + /* Read info from registry in key HKLM\SOFTWARE\OpenVPN */ + error = GetOpenvpnSettings(&settings); + if (error != ERROR_SUCCESS) + { + goto out; + } + + io_event = InitOverlapped(&overlapped); + exit_event = CreateEvent(NULL, TRUE, FALSE, NULL); + if (!exit_event || !io_event) + { + error = MsgToEventLog(M_SYSERR, TEXT("Could not create event")); + goto out; + } + + rdns_semaphore = CreateSemaphoreW(NULL, 1, 1, NULL); + if (!rdns_semaphore) + { + error = MsgToEventLog(M_SYSERR, TEXT("Could not create semaphore for register-dns")); + goto out; + } + + error = UpdateWaitHandles(&handles, &handle_count, io_event, exit_event, threads); + if (error != NO_ERROR) + { + goto out; + } + + pipe = CreateClientPipeInstance(); + if (pipe == INVALID_HANDLE_VALUE) + { + goto out; + } + + status.dwCurrentState = SERVICE_RUNNING; + status.dwWaitHint = 0; + ReportStatusToSCMgr(service, &status); + + while (TRUE) + { + if (ConnectNamedPipe(pipe, &overlapped) == FALSE + && GetLastError() != ERROR_PIPE_CONNECTED + && GetLastError() != ERROR_IO_PENDING) { - MsgToEventLog (M_SYSERR, TEXT("Could not connect pipe")); - break; + MsgToEventLog(M_SYSERR, TEXT("Could not connect pipe")); + break; } - error = WaitForMultipleObjects (handle_count, handles, FALSE, INFINITE); - if (error == WAIT_OBJECT_0) + error = WaitForMultipleObjects(handle_count, handles, FALSE, INFINITE); + if (error == WAIT_OBJECT_0) { - /* Client connected, spawn a worker thread for it */ - HANDLE next_pipe = CreateClientPipeInstance (); - HANDLE thread = CreateThread (NULL, 0, RunOpenvpn, pipe, CREATE_SUSPENDED, NULL); - if (thread) + /* Client connected, spawn a worker thread for it */ + HANDLE next_pipe = CreateClientPipeInstance(); + HANDLE thread = CreateThread(NULL, 0, RunOpenvpn, pipe, CREATE_SUSPENDED, NULL); + if (thread) { - error = AddListItem (&threads, thread); - if (!error) - error = UpdateWaitHandles (&handles, &handle_count, io_event, exit_event, threads); - if (error) + error = AddListItem(&threads, thread); + if (!error) + { + error = UpdateWaitHandles(&handles, &handle_count, io_event, exit_event, threads); + } + if (error) + { + ReturnError(pipe, error, L"Insufficient resources to service new clients", 1, &exit_event); + /* Update wait handles again after removing the last worker thread */ + RemoveListItem(&threads, CmpHandle, thread); + UpdateWaitHandles(&handles, &handle_count, io_event, exit_event, threads); + TerminateThread(thread, 1); + CloseHandleEx(&thread); + CloseHandleEx(&pipe); + } + else { - ReturnError (pipe, error, L"Insufficient resources to service new clients", 1, &exit_event); - /* Update wait handles again after removing the last worker thread */ - RemoveListItem (&threads, CmpHandle, thread); - UpdateWaitHandles (&handles, &handle_count, io_event, exit_event, threads); - TerminateThread (thread, 1); - CloseHandleEx (&thread); - CloseHandleEx (&pipe); + ResumeThread(thread); } - else - ResumeThread (thread); } - else - CloseHandleEx (&pipe); + else + { + CloseHandleEx(&pipe); + } - ResetOverlapped (&overlapped); - pipe = next_pipe; + ResetOverlapped(&overlapped); + pipe = next_pipe; } - else + else { - CancelIo (pipe); - if (error == WAIT_FAILED) + CancelIo(pipe); + if (error == WAIT_FAILED) { - MsgToEventLog (M_SYSERR, TEXT("WaitForMultipleObjects failed")); - SetEvent (exit_event); - /* Give some time for worker threads to exit and then terminate */ - Sleep (1000); - break; + MsgToEventLog(M_SYSERR, TEXT("WaitForMultipleObjects failed")); + SetEvent(exit_event); + /* Give some time for worker threads to exit and then terminate */ + Sleep(1000); + break; } - if (!threads) + if (!threads) { - /* exit event signaled */ - CloseHandleEx (&pipe); - ResetEvent (exit_event); - error = NO_ERROR; - break; + /* exit event signaled */ + CloseHandleEx(&pipe); + ResetEvent(exit_event); + error = NO_ERROR; + break; } - /* Worker thread ended */ - HANDLE thread = RemoveListItem (&threads, CmpHandle, handles[error]); - UpdateWaitHandles (&handles, &handle_count, io_event, exit_event, threads); - CloseHandleEx (&thread); + /* Worker thread ended */ + HANDLE thread = RemoveListItem(&threads, CmpHandle, handles[error]); + UpdateWaitHandles(&handles, &handle_count, io_event, exit_event, threads); + CloseHandleEx(&thread); } } out: - FreeWaitHandles (handles); - CloseHandleEx (&io_event); - CloseHandleEx (&exit_event); - CloseHandleEx (&rdns_semaphore); - - status.dwCurrentState = SERVICE_STOPPED; - status.dwWin32ExitCode = error; - ReportStatusToSCMgr (service, &status); + FreeWaitHandles(handles); + CloseHandleEx(&io_event); + CloseHandleEx(&exit_event); + CloseHandleEx(&rdns_semaphore); + + status.dwCurrentState = SERVICE_STOPPED; + status.dwWin32ExitCode = error; + ReportStatusToSCMgr(service, &status); } diff --git a/src/openvpnserv/service.c b/src/openvpnserv/service.c index 82f55512fc8..b79e9993a9e 100644 --- a/src/openvpnserv/service.c +++ b/src/openvpnserv/service.c @@ -19,227 +19,257 @@ openvpn_service_t openvpn_service[_service_max]; BOOL -ReportStatusToSCMgr (SERVICE_STATUS_HANDLE service, SERVICE_STATUS *status) +ReportStatusToSCMgr(SERVICE_STATUS_HANDLE service, SERVICE_STATUS *status) { - static DWORD dwCheckPoint = 1; - BOOL res = TRUE; - - if (status->dwCurrentState == SERVICE_START_PENDING) - status->dwControlsAccepted = 0; - else - status->dwControlsAccepted = SERVICE_ACCEPT_STOP; - - if (status->dwCurrentState == SERVICE_RUNNING || - status->dwCurrentState == SERVICE_STOPPED) - status->dwCheckPoint = 0; - else - status->dwCheckPoint = dwCheckPoint++; - - /* Report the status of the service to the service control manager. */ - res = SetServiceStatus (service, status); - if (!res) - MsgToEventLog(MSG_FLAGS_ERROR, TEXT("SetServiceStatus")); - - return res; + static DWORD dwCheckPoint = 1; + BOOL res = TRUE; + + if (status->dwCurrentState == SERVICE_START_PENDING) + { + status->dwControlsAccepted = 0; + } + else + { + status->dwControlsAccepted = SERVICE_ACCEPT_STOP; + } + + if (status->dwCurrentState == SERVICE_RUNNING + || status->dwCurrentState == SERVICE_STOPPED) + { + status->dwCheckPoint = 0; + } + else + { + status->dwCheckPoint = dwCheckPoint++; + } + + /* Report the status of the service to the service control manager. */ + res = SetServiceStatus(service, status); + if (!res) + { + MsgToEventLog(MSG_FLAGS_ERROR, TEXT("SetServiceStatus")); + } + + return res; } static int -CmdInstallServices () +CmdInstallServices() { - SC_HANDLE service; - SC_HANDLE svc_ctl_mgr; - TCHAR path[512]; - int i, ret = _service_max; - - if (GetModuleFileName (NULL, path + 1, 510) == 0) - { - _tprintf (TEXT("Unable to install service - %s\n"), GetLastErrorText ()); - return 1; - } - - path[0] = TEXT('\"'); - _tcscat (path, TEXT("\"")); - - svc_ctl_mgr = OpenSCManager (NULL, NULL, SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE); - if (svc_ctl_mgr == NULL) + SC_HANDLE service; + SC_HANDLE svc_ctl_mgr; + TCHAR path[512]; + int i, ret = _service_max; + + if (GetModuleFileName(NULL, path + 1, 510) == 0) { - _tprintf (TEXT("OpenSCManager failed - %s\n"), GetLastErrorText ()); - return 1; + _tprintf(TEXT("Unable to install service - %s\n"), GetLastErrorText()); + return 1; } - for (i = 0; i < _service_max; i++) + path[0] = TEXT('\"'); + _tcscat(path, TEXT("\"")); + + svc_ctl_mgr = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE); + if (svc_ctl_mgr == NULL) { - service = CreateService (svc_ctl_mgr, - openvpn_service[i].name, - openvpn_service[i].display_name, - SERVICE_QUERY_STATUS, - SERVICE_WIN32_SHARE_PROCESS, - openvpn_service[i].start_type, - SERVICE_ERROR_NORMAL, - path, NULL, NULL, - openvpn_service[i].dependencies, - NULL, NULL); - if (service) + _tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText()); + return 1; + } + + for (i = 0; i < _service_max; i++) + { + service = CreateService(svc_ctl_mgr, + openvpn_service[i].name, + openvpn_service[i].display_name, + SERVICE_QUERY_STATUS, + SERVICE_WIN32_SHARE_PROCESS, + openvpn_service[i].start_type, + SERVICE_ERROR_NORMAL, + path, NULL, NULL, + openvpn_service[i].dependencies, + NULL, NULL); + if (service) + { + _tprintf(TEXT("%s installed.\n"), openvpn_service[i].display_name); + CloseServiceHandle(service); + --ret; + } + else { - _tprintf (TEXT("%s installed.\n"), openvpn_service[i].display_name); - CloseServiceHandle (service); - --ret; + _tprintf(TEXT("CreateService failed - %s\n"), GetLastErrorText()); } - else - _tprintf (TEXT("CreateService failed - %s\n"), GetLastErrorText ()); } - CloseServiceHandle (svc_ctl_mgr); - return ret; + CloseServiceHandle(svc_ctl_mgr); + return ret; } static int -CmdStartService (openvpn_service_type type) +CmdStartService(openvpn_service_type type) { - int ret = 1; - SC_HANDLE svc_ctl_mgr; - SC_HANDLE service; + int ret = 1; + SC_HANDLE svc_ctl_mgr; + SC_HANDLE service; - svc_ctl_mgr = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS); - if (svc_ctl_mgr == NULL) + svc_ctl_mgr = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); + if (svc_ctl_mgr == NULL) { - _tprintf (TEXT("OpenSCManager failed - %s\n"), GetLastErrorText ()); - return 1; + _tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText()); + return 1; } - service = OpenService (svc_ctl_mgr, openvpn_service[type].name, SERVICE_ALL_ACCESS); - if (service) + service = OpenService(svc_ctl_mgr, openvpn_service[type].name, SERVICE_ALL_ACCESS); + if (service) { - if (StartService (service, 0, NULL)) + if (StartService(service, 0, NULL)) { - _tprintf (TEXT("Service Started\n")); - ret = 0; + _tprintf(TEXT("Service Started\n")); + ret = 0; + } + else + { + _tprintf(TEXT("StartService failed - %s\n"), GetLastErrorText()); } - else - _tprintf (TEXT("StartService failed - %s\n"), GetLastErrorText ()); - CloseServiceHandle(service); + CloseServiceHandle(service); } - else + else { - _tprintf (TEXT("OpenService failed - %s\n"), GetLastErrorText ()); + _tprintf(TEXT("OpenService failed - %s\n"), GetLastErrorText()); } - CloseServiceHandle(svc_ctl_mgr); - return ret; + CloseServiceHandle(svc_ctl_mgr); + return ret; } static int -CmdRemoveServices () +CmdRemoveServices() { - SC_HANDLE service; - SC_HANDLE svc_ctl_mgr; - SERVICE_STATUS status; - int i, ret = _service_max; + SC_HANDLE service; + SC_HANDLE svc_ctl_mgr; + SERVICE_STATUS status; + int i, ret = _service_max; - svc_ctl_mgr = OpenSCManager (NULL, NULL, SC_MANAGER_CONNECT); - if (svc_ctl_mgr == NULL) + svc_ctl_mgr = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); + if (svc_ctl_mgr == NULL) { - _tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText ()); - return 1; + _tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText()); + return 1; } - for (i = 0; i < _service_max; i++) + for (i = 0; i < _service_max; i++) { - openvpn_service_t *ovpn_svc = &openvpn_service[i]; - service = OpenService (svc_ctl_mgr, ovpn_svc->name, - DELETE | SERVICE_STOP | SERVICE_QUERY_STATUS); - if (service == NULL) + openvpn_service_t *ovpn_svc = &openvpn_service[i]; + service = OpenService(svc_ctl_mgr, ovpn_svc->name, + DELETE | SERVICE_STOP | SERVICE_QUERY_STATUS); + if (service == NULL) { - _tprintf (TEXT("OpenService failed - %s\n"), GetLastErrorText ()); - goto out; + _tprintf(TEXT("OpenService failed - %s\n"), GetLastErrorText()); + goto out; } - /* try to stop the service */ - if (ControlService (service, SERVICE_CONTROL_STOP, &status)) + /* try to stop the service */ + if (ControlService(service, SERVICE_CONTROL_STOP, &status)) { - _tprintf (TEXT("Stopping %s."), ovpn_svc->display_name); - Sleep (1000); + _tprintf(TEXT("Stopping %s."), ovpn_svc->display_name); + Sleep(1000); - while (QueryServiceStatus (service, &status)) + while (QueryServiceStatus(service, &status)) { - if (status.dwCurrentState == SERVICE_STOP_PENDING) + if (status.dwCurrentState == SERVICE_STOP_PENDING) { - _tprintf (TEXT(".")); - Sleep (1000); + _tprintf(TEXT(".")); + Sleep(1000); + } + else + { + break; } - else - break; } - if (status.dwCurrentState == SERVICE_STOPPED) - _tprintf (TEXT("\n%s stopped.\n"), ovpn_svc->display_name); - else - _tprintf (TEXT("\n%s failed to stop.\n"), ovpn_svc->display_name); + if (status.dwCurrentState == SERVICE_STOPPED) + { + _tprintf(TEXT("\n%s stopped.\n"), ovpn_svc->display_name); + } + else + { + _tprintf(TEXT("\n%s failed to stop.\n"), ovpn_svc->display_name); + } } - /* now remove the service */ - if (DeleteService (service)) + /* now remove the service */ + if (DeleteService(service)) { - _tprintf (TEXT("%s removed.\n"), ovpn_svc->display_name); - --ret; + _tprintf(TEXT("%s removed.\n"), ovpn_svc->display_name); + --ret; + } + else + { + _tprintf(TEXT("DeleteService failed - %s\n"), GetLastErrorText()); } - else - _tprintf (TEXT("DeleteService failed - %s\n"), GetLastErrorText ()); - CloseServiceHandle (service); + CloseServiceHandle(service); } out: - CloseServiceHandle (svc_ctl_mgr); - return ret; + CloseServiceHandle(svc_ctl_mgr); + return ret; } int -_tmain (int argc, TCHAR *argv[]) +_tmain(int argc, TCHAR *argv[]) { - SERVICE_TABLE_ENTRY dispatchTable[] = { - { automatic_service.name, ServiceStartAutomatic }, - { interactive_service.name, ServiceStartInteractive }, - { NULL, NULL } - }; - - openvpn_service[0] = automatic_service; - openvpn_service[1] = interactive_service; - - if (argc > 1 && (*argv[1] == TEXT('-') || *argv[1] == TEXT('/'))) - { - if (_tcsicmp (TEXT("install"), argv[1] + 1) == 0) - return CmdInstallServices (); - else if (_tcsicmp (TEXT("remove"), argv[1] + 1) == 0) - return CmdRemoveServices (); - else if (_tcsicmp (TEXT("start"), argv[1] + 1) == 0) - { - BOOL is_auto = argc < 3 || _tcsicmp (TEXT("interactive"), argv[2]) != 0; - return CmdStartService (is_auto ? automatic : interactive); - } - else - goto dispatch; + SERVICE_TABLE_ENTRY dispatchTable[] = { + { automatic_service.name, ServiceStartAutomatic }, + { interactive_service.name, ServiceStartInteractive }, + { NULL, NULL } + }; - return 0; - } + openvpn_service[0] = automatic_service; + openvpn_service[1] = interactive_service; - /* If it doesn't match any of the above parameters - * the service control manager may be starting the service - * so we must call StartServiceCtrlDispatcher - */ + if (argc > 1 && (*argv[1] == TEXT('-') || *argv[1] == TEXT('/'))) + { + if (_tcsicmp(TEXT("install"), argv[1] + 1) == 0) + { + return CmdInstallServices(); + } + else if (_tcsicmp(TEXT("remove"), argv[1] + 1) == 0) + { + return CmdRemoveServices(); + } + else if (_tcsicmp(TEXT("start"), argv[1] + 1) == 0) + { + BOOL is_auto = argc < 3 || _tcsicmp(TEXT("interactive"), argv[2]) != 0; + return CmdStartService(is_auto ? automatic : interactive); + } + else + { + goto dispatch; + } + + return 0; + } + + /* If it doesn't match any of the above parameters + * the service control manager may be starting the service + * so we must call StartServiceCtrlDispatcher + */ dispatch: - _tprintf (TEXT("%s -install to install the services\n"), APPNAME); - _tprintf (TEXT("%s -start to start a service (\"automatic\" or \"interactive\")\n"), APPNAME); - _tprintf (TEXT("%s -remove to remove the services\n"), APPNAME); - _tprintf (TEXT("\nStartServiceCtrlDispatcher being called.\n")); - _tprintf (TEXT("This may take several seconds. Please wait.\n")); + _tprintf(TEXT("%s -install to install the services\n"), APPNAME); + _tprintf(TEXT("%s -start to start a service (\"automatic\" or \"interactive\")\n"), APPNAME); + _tprintf(TEXT("%s -remove to remove the services\n"), APPNAME); + _tprintf(TEXT("\nStartServiceCtrlDispatcher being called.\n")); + _tprintf(TEXT("This may take several seconds. Please wait.\n")); - if (!StartServiceCtrlDispatcher (dispatchTable)) - MsgToEventLog (MSG_FLAGS_ERROR, TEXT("StartServiceCtrlDispatcher failed.")); + if (!StartServiceCtrlDispatcher(dispatchTable)) + { + MsgToEventLog(MSG_FLAGS_ERROR, TEXT("StartServiceCtrlDispatcher failed.")); + } - return 0; + return 0; } diff --git a/src/openvpnserv/service.h b/src/openvpnserv/service.h index c5d745f6d8b..f907e69c355 100644 --- a/src/openvpnserv/service.h +++ b/src/openvpnserv/service.h @@ -48,48 +48,51 @@ #define M_ERR (MSG_FLAGS_ERROR) /* error */ typedef enum { - automatic, - interactive, - _service_max + automatic, + interactive, + _service_max } openvpn_service_type; typedef struct { - openvpn_service_type type; - TCHAR *name; - TCHAR *display_name; - TCHAR *dependencies; - DWORD start_type; + openvpn_service_type type; + TCHAR *name; + TCHAR *display_name; + TCHAR *dependencies; + DWORD start_type; } openvpn_service_t; #define MAX_NAME 256 typedef struct { - TCHAR exe_path[MAX_PATH]; - TCHAR config_dir[MAX_PATH]; - TCHAR ext_string[16]; - TCHAR log_dir[MAX_PATH]; - TCHAR ovpn_admin_group[MAX_NAME]; - DWORD priority; - BOOL append; + TCHAR exe_path[MAX_PATH]; + TCHAR config_dir[MAX_PATH]; + TCHAR ext_string[16]; + TCHAR log_dir[MAX_PATH]; + TCHAR ovpn_admin_group[MAX_NAME]; + DWORD priority; + BOOL append; } settings_t; extern openvpn_service_t automatic_service; extern openvpn_service_t interactive_service; -VOID WINAPI ServiceStartAutomatic (DWORD argc, LPTSTR *argv); -VOID WINAPI ServiceStartInteractive (DWORD argc, LPTSTR *argv); +VOID WINAPI ServiceStartAutomatic(DWORD argc, LPTSTR *argv); -int openvpn_vsntprintf (LPTSTR str, size_t size, LPCTSTR format, va_list arglist); -int openvpn_sntprintf (LPTSTR str, size_t size, LPCTSTR format, ...); +VOID WINAPI ServiceStartInteractive(DWORD argc, LPTSTR *argv); -DWORD GetOpenvpnSettings (settings_t *s); +int openvpn_vsntprintf(LPTSTR str, size_t size, LPCTSTR format, va_list arglist); -BOOL ReportStatusToSCMgr (SERVICE_STATUS_HANDLE service, SERVICE_STATUS *status); +int openvpn_sntprintf(LPTSTR str, size_t size, LPCTSTR format, ...); -LPCTSTR GetLastErrorText (); -DWORD MsgToEventLog (DWORD flags, LPCTSTR lpszMsg, ...); +DWORD GetOpenvpnSettings(settings_t *s); + +BOOL ReportStatusToSCMgr(SERVICE_STATUS_HANDLE service, SERVICE_STATUS *status); + +LPCTSTR GetLastErrorText(); + +DWORD MsgToEventLog(DWORD flags, LPCTSTR lpszMsg, ...); /* Convert a utf8 string to utf16. Caller should free the result */ -wchar_t *utf8to16 (const char *utf8); +wchar_t *utf8to16(const char *utf8); -#endif +#endif /* ifndef _SERVICE_H */ diff --git a/src/openvpnserv/validate.c b/src/openvpnserv/validate.c index 7458d75a4ec..c9c3855491b 100644 --- a/src/openvpnserv/validate.c +++ b/src/openvpnserv/validate.c @@ -29,41 +29,41 @@ #include static const WCHAR *white_list[] = - { - L"auth-retry", - L"config", - L"log", - L"log-append", - L"management", - L"management-forget-disconnect", - L"management-hold", - L"management-query-passwords", - L"management-query-proxy", - L"management-signal", - L"management-up-down", - L"mute", - L"setenv", - L"service", - L"verb", - - NULL /* last value */ - }; +{ + L"auth-retry", + L"config", + L"log", + L"log-append", + L"management", + L"management-forget-disconnect", + L"management-hold", + L"management-query-passwords", + L"management-query-proxy", + L"management-signal", + L"management-up-down", + L"mute", + L"setenv", + L"service", + L"verb", + + NULL /* last value */ +}; /* * Check workdir\fname is inside config_dir * The logic here is simple: we may reject some valid paths if ..\ is in any of the strings */ static BOOL -CheckConfigPath (const WCHAR *workdir, const WCHAR *fname, const settings_t *s) +CheckConfigPath(const WCHAR *workdir, const WCHAR *fname, const settings_t *s) { WCHAR tmp[MAX_PATH]; const WCHAR *config_file = NULL; const WCHAR *config_dir = NULL; /* convert fname to full path */ - if (PathIsRelativeW (fname) ) + if (PathIsRelativeW(fname) ) { - snwprintf (tmp, _countof(tmp), L"%s\\%s", workdir, fname); + snwprintf(tmp, _countof(tmp), L"%s\\%s", workdir, fname); tmp[_countof(tmp)-1] = L'\0'; config_file = tmp; } @@ -75,17 +75,19 @@ CheckConfigPath (const WCHAR *workdir, const WCHAR *fname, const settings_t *s) #ifdef UNICODE config_dir = s->config_dir; #else - if (MultiByteToWideChar (CP_UTF8, 0, s->config_dir, -1, widepath, MAX_PATH) == 0) + if (MultiByteToWideChar(CP_UTF8, 0, s->config_dir, -1, widepath, MAX_PATH) == 0) { - MsgToEventLog (M_SYSERR, TEXT("Failed to convert config_dir name to WideChar")); + MsgToEventLog(M_SYSERR, TEXT("Failed to convert config_dir name to WideChar")); return FALSE; } config_dir = widepath; #endif - if (wcsncmp (config_dir, config_file, wcslen(config_dir)) == 0 && - wcsstr (config_file + wcslen(config_dir), L"..") == NULL ) + if (wcsncmp(config_dir, config_file, wcslen(config_dir)) == 0 + && wcsstr(config_file + wcslen(config_dir), L"..") == NULL) + { return TRUE; + } return FALSE; } @@ -96,14 +98,16 @@ CheckConfigPath (const WCHAR *workdir, const WCHAR *fname, const settings_t *s) * Returns index to the item if found, -1 otherwise. */ static int -OptionLookup (const WCHAR *name, const WCHAR *white_list[]) +OptionLookup(const WCHAR *name, const WCHAR *white_list[]) { int i; - for (i = 0 ; white_list[i]; i++) + for (i = 0; white_list[i]; i++) { - if ( wcscmp(white_list[i], name) == 0 ) + if (wcscmp(white_list[i], name) == 0) + { return i; + } } return -1; @@ -114,7 +118,7 @@ OptionLookup (const WCHAR *name, const WCHAR *white_list[]) * Get the local name of the group using the SID. */ static BOOL -GetBuiltinAdminGroupName (WCHAR *name, DWORD nlen) +GetBuiltinAdminGroupName(WCHAR *name, DWORD nlen) { BOOL b = FALSE; PSID admin_sid = NULL; @@ -126,15 +130,17 @@ GetBuiltinAdminGroupName (WCHAR *name, DWORD nlen) admin_sid = malloc(sid_size); if (!admin_sid) + { return FALSE; + } b = CreateWellKnownSid(WinBuiltinAdministratorsSid, NULL, admin_sid, &sid_size); - if(b) + if (b) { b = LookupAccountSidW(NULL, admin_sid, name, &nlen, domain, &dlen, &snu); } - free (admin_sid); + free(admin_sid); return b; } @@ -144,7 +150,7 @@ GetBuiltinAdminGroupName (WCHAR *name, DWORD nlen) * the group specified in s->ovpn_admin_group */ BOOL -IsAuthorizedUser (SID *sid, settings_t *s) +IsAuthorizedUser(SID *sid, settings_t *s) { LOCALGROUP_USERS_INFO_0 *groups = NULL; DWORD nread; @@ -160,19 +166,19 @@ IsAuthorizedUser (SID *sid, settings_t *s) SID_NAME_USE sid_type; /* Get username */ - if (!LookupAccountSidW (NULL, sid, username, &len, domain, &len, &sid_type)) + if (!LookupAccountSidW(NULL, sid, username, &len, domain, &len, &sid_type)) { - MsgToEventLog (M_SYSERR, TEXT("LookupAccountSid")); + MsgToEventLog(M_SYSERR, TEXT("LookupAccountSid")); goto out; } /* Get an array of groups the user is member of */ - err = NetUserGetLocalGroups (NULL, username, 0, LG_INCLUDE_INDIRECT, (LPBYTE *) &groups, - MAX_PREFERRED_LENGTH, &nread, &nmax); + err = NetUserGetLocalGroups(NULL, username, 0, LG_INCLUDE_INDIRECT, (LPBYTE *) &groups, + MAX_PREFERRED_LENGTH, &nread, &nmax); if (err && err != ERROR_MORE_DATA) { - SetLastError (err); - MsgToEventLog (M_SYSERR, TEXT("NetUserGetLocalGroups")); + SetLastError(err); + MsgToEventLog(M_SYSERR, TEXT("NetUserGetLocalGroups")); goto out; } @@ -182,7 +188,7 @@ IsAuthorizedUser (SID *sid, settings_t *s) } else { - MsgToEventLog (M_SYSERR, TEXT("Failed to get the name of Administrators group. Using the default.")); + MsgToEventLog(M_SYSERR, TEXT("Failed to get the name of Administrators group. Using the default.")); /* use the default value */ admin_group[0] = SYSTEM_ADMIN_GROUP; } @@ -191,25 +197,25 @@ IsAuthorizedUser (SID *sid, settings_t *s) admin_group[1] = s->ovpn_admin_group; #else tmp = NULL; - len = MultiByteToWideChar (CP_UTF8, 0, s->ovpn_admin_group, -1, NULL, 0); - if (len == 0 || (tmp = malloc (len*sizeof(WCHAR))) == NULL) + len = MultiByteToWideChar(CP_UTF8, 0, s->ovpn_admin_group, -1, NULL, 0); + if (len == 0 || (tmp = malloc(len*sizeof(WCHAR))) == NULL) { - MsgToEventLog (M_SYSERR, TEXT("Failed to convert admin group name to WideChar")); + MsgToEventLog(M_SYSERR, TEXT("Failed to convert admin group name to WideChar")); goto out; } - MultiByteToWideChar (CP_UTF8, 0, s->ovpn_admin_group, -1, tmp, len); + MultiByteToWideChar(CP_UTF8, 0, s->ovpn_admin_group, -1, tmp, len); admin_group[1] = tmp; #endif /* Check if user's groups include any of the admin groups */ for (i = 0; i < nread; i++) { - if ( wcscmp (groups[i].lgrui0_name, admin_group[0]) == 0 || - wcscmp (groups[i].lgrui0_name, admin_group[1]) == 0 - ) + if (wcscmp(groups[i].lgrui0_name, admin_group[0]) == 0 + || wcscmp(groups[i].lgrui0_name, admin_group[1]) == 0 + ) { - MsgToEventLog (M_INFO, TEXT("Authorizing user %s by virtue of membership in group %s"), - username, groups[i].lgrui0_name); + MsgToEventLog(M_INFO, TEXT("Authorizing user %s by virtue of membership in group %s"), + username, groups[i].lgrui0_name); ret = TRUE; break; } @@ -217,8 +223,10 @@ IsAuthorizedUser (SID *sid, settings_t *s) out: if (groups) - NetApiBufferFree (groups); - free (tmp); + { + NetApiBufferFree(groups); + } + free(tmp); return ret; } @@ -229,21 +237,23 @@ IsAuthorizedUser (SID *sid, settings_t *s) * The caller should set argc to the number of valid elements in argv[] array. */ BOOL -CheckOption (const WCHAR *workdir, int argc, WCHAR *argv[], const settings_t *s) +CheckOption(const WCHAR *workdir, int argc, WCHAR *argv[], const settings_t *s) { /* Do not modify argv or *argv -- ideally it should be const WCHAR *const *, but alas...*/ - if ( wcscmp (argv[0], L"--config") == 0 && - argc > 1 && - !CheckConfigPath (workdir, argv[1], s) - ) + if (wcscmp(argv[0], L"--config") == 0 + && argc > 1 + && !CheckConfigPath(workdir, argv[1], s) + ) { return FALSE; } /* option name starts at 2 characters from argv[i] */ - if (OptionLookup (argv[0] + 2, white_list) == -1) /* not found */ + if (OptionLookup(argv[0] + 2, white_list) == -1) /* not found */ + { return FALSE; + } return TRUE; } diff --git a/src/openvpnserv/validate.h b/src/openvpnserv/validate.h index 0d0270a9c41..ece8704c789 100644 --- a/src/openvpnserv/validate.h +++ b/src/openvpnserv/validate.h @@ -34,15 +34,15 @@ /* The last one may be reset in registry: HKLM\Software\OpenVPN\ovpn_admin_group */ BOOL -IsAuthorizedUser (SID *sid, settings_t *s); +IsAuthorizedUser(SID *sid, settings_t *s); BOOL -CheckOption (const WCHAR *workdir, int narg, WCHAR *argv[], const settings_t *s); +CheckOption(const WCHAR *workdir, int narg, WCHAR *argv[], const settings_t *s); static inline BOOL -IsOption (const WCHAR *o) +IsOption(const WCHAR *o) { - return (wcsncmp (o, L"--", 2) == 0); + return (wcsncmp(o, L"--", 2) == 0); } -#endif +#endif /* ifndef VALIDATE_H */ diff --git a/src/plugins/auth-pam/auth-pam.c b/src/plugins/auth-pam/auth-pam.c index 5ad3ec8ec28..458141120b9 100644 --- a/src/plugins/auth-pam/auth-pam.c +++ b/src/plugins/auth-pam/auth-pam.c @@ -68,14 +68,14 @@ */ struct auth_pam_context { - /* Foreground's socket to background process */ - int foreground_fd; + /* Foreground's socket to background process */ + int foreground_fd; - /* Process ID of background process */ - pid_t background_pid; + /* Process ID of background process */ + pid_t background_pid; - /* Verbosity level of OpenVPN */ - int verb; + /* Verbosity level of OpenVPN */ + int verb; }; /* @@ -90,13 +90,13 @@ struct auth_pam_context #define N_NAME_VALUE 16 struct name_value { - const char *name; - const char *value; + const char *name; + const char *value; }; struct name_value_list { - int len; - struct name_value data[N_NAME_VALUE]; + int len; + struct name_value data[N_NAME_VALUE]; }; /* @@ -104,17 +104,17 @@ struct name_value_list { * to the PAM conversation function. */ struct user_pass { - int verb; + int verb; - char username[128]; - char password[128]; - char common_name[128]; + char username[128]; + char password[128]; + char common_name[128]; - const struct name_value_list *name_value_list; + const struct name_value_list *name_value_list; }; /* Background process function */ -static void pam_server (int fd, const char *service, int verb, const struct name_value_list *name_value_list); +static void pam_server(int fd, const char *service, int verb, const struct name_value_list *name_value_list); /* @@ -122,54 +122,66 @@ static void pam_server (int fd, const char *service, int verb, const struct name */ static int -recv_control (int fd) +recv_control(int fd) { - unsigned char c; - const ssize_t size = read (fd, &c, sizeof (c)); - if (size == sizeof (c)) - return c; - else + unsigned char c; + const ssize_t size = read(fd, &c, sizeof(c)); + if (size == sizeof(c)) { - /*fprintf (stderr, "AUTH-PAM: DEBUG recv_control.read=%d\n", (int)size);*/ - return -1; + return c; + } + else + { + /*fprintf (stderr, "AUTH-PAM: DEBUG recv_control.read=%d\n", (int)size);*/ + return -1; } } static int -send_control (int fd, int code) +send_control(int fd, int code) { - unsigned char c = (unsigned char) code; - const ssize_t size = write (fd, &c, sizeof (c)); - if (size == sizeof (c)) - return (int) size; - else - return -1; + unsigned char c = (unsigned char) code; + const ssize_t size = write(fd, &c, sizeof(c)); + if (size == sizeof(c)) + { + return (int) size; + } + else + { + return -1; + } } static int -recv_string (int fd, char *buffer, int len) +recv_string(int fd, char *buffer, int len) { - if (len > 0) + if (len > 0) { - ssize_t size; - memset (buffer, 0, len); - size = read (fd, buffer, len); - buffer[len-1] = 0; - if (size >= 1) - return (int)size; + ssize_t size; + memset(buffer, 0, len); + size = read(fd, buffer, len); + buffer[len-1] = 0; + if (size >= 1) + { + return (int)size; + } } - return -1; + return -1; } static int -send_string (int fd, const char *string) +send_string(int fd, const char *string) { - const int len = strlen (string) + 1; - const ssize_t size = write (fd, string, len); - if (size == len) - return (int) size; - else - return -1; + const int len = strlen(string) + 1; + const ssize_t size = write(fd, string, len); + if (size == len) + { + return (int) size; + } + else + { + return -1; + } } #ifdef DO_DAEMONIZE @@ -180,28 +192,30 @@ send_string (int fd, const char *string) * "daemon_log_redirect" env var is true. */ static void -daemonize (const char *envp[]) +daemonize(const char *envp[]) { - const char *daemon_string = get_env ("daemon", envp); - if (daemon_string && daemon_string[0] == '1') - { - const char *log_redirect = get_env ("daemon_log_redirect", envp); - int fd = -1; - if (log_redirect && log_redirect[0] == '1') - fd = dup (2); - if (daemon (0, 0) < 0) - { - fprintf (stderr, "AUTH-PAM: daemonization failed\n"); - } - else if (fd >= 3) - { - dup2 (fd, 2); - close (fd); - } + const char *daemon_string = get_env("daemon", envp); + if (daemon_string && daemon_string[0] == '1') + { + const char *log_redirect = get_env("daemon_log_redirect", envp); + int fd = -1; + if (log_redirect && log_redirect[0] == '1') + { + fd = dup(2); + } + if (daemon(0, 0) < 0) + { + fprintf(stderr, "AUTH-PAM: daemonization failed\n"); + } + else if (fd >= 3) + { + dup2(fd, 2); + close(fd); + } } } -#endif +#endif /* ifdef DO_DAEMONIZE */ /* * Close most of parent's fds. @@ -214,14 +228,16 @@ daemonize (const char *envp[]) * fds from crossing a fork(). */ static void -close_fds_except (int keep) +close_fds_except(int keep) { - int i; - closelog (); - for (i = 3; i <= 100; ++i) + int i; + closelog(); + for (i = 3; i <= 100; ++i) { - if (i != keep) - close (i); + if (i != keep) + { + close(i); + } } } @@ -230,243 +246,263 @@ close_fds_except (int keep) * deal with them. */ static void -set_signals (void) +set_signals(void) { - signal (SIGTERM, SIG_DFL); + signal(SIGTERM, SIG_DFL); - signal (SIGINT, SIG_IGN); - signal (SIGHUP, SIG_IGN); - signal (SIGUSR1, SIG_IGN); - signal (SIGUSR2, SIG_IGN); - signal (SIGPIPE, SIG_IGN); + signal(SIGINT, SIG_IGN); + signal(SIGHUP, SIG_IGN); + signal(SIGUSR1, SIG_IGN); + signal(SIGUSR2, SIG_IGN); + signal(SIGPIPE, SIG_IGN); } /* * Return 1 if query matches match. */ static int -name_value_match (const char *query, const char *match) +name_value_match(const char *query, const char *match) { - while (!isalnum (*query)) + while (!isalnum(*query)) { - if (*query == '\0') - return 0; - ++query; + if (*query == '\0') + { + return 0; + } + ++query; } - return strncasecmp (match, query, strlen (match)) == 0; + return strncasecmp(match, query, strlen(match)) == 0; } OPENVPN_EXPORT openvpn_plugin_handle_t -openvpn_plugin_open_v1 (unsigned int *type_mask, const char *argv[], const char *envp[]) +openvpn_plugin_open_v1(unsigned int *type_mask, const char *argv[], const char *envp[]) { - pid_t pid; - int fd[2]; - - struct auth_pam_context *context; - struct name_value_list name_value_list; - - const int base_parms = 2; - - /* - * Allocate our context - */ - context = (struct auth_pam_context *) calloc (1, sizeof (struct auth_pam_context)); - if (!context) - goto error; - context->foreground_fd = -1; - - /* - * Intercept the --auth-user-pass-verify callback. - */ - *type_mask = OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY); + pid_t pid; + int fd[2]; + + struct auth_pam_context *context; + struct name_value_list name_value_list; - /* - * Make sure we have two string arguments: the first is the .so name, - * the second is the PAM service type. - */ - if (string_array_len (argv) < base_parms) + const int base_parms = 2; + + /* + * Allocate our context + */ + context = (struct auth_pam_context *) calloc(1, sizeof(struct auth_pam_context)); + if (!context) { - fprintf (stderr, "AUTH-PAM: need PAM service parameter\n"); - goto error; + goto error; } - - /* - * See if we have optional name/value pairs to match against - * PAM module queried fields in the conversation function. - */ - name_value_list.len = 0; - if (string_array_len (argv) > base_parms) + context->foreground_fd = -1; + + /* + * Intercept the --auth-user-pass-verify callback. + */ + *type_mask = OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY); + + /* + * Make sure we have two string arguments: the first is the .so name, + * the second is the PAM service type. + */ + if (string_array_len(argv) < base_parms) { - const int nv_len = string_array_len (argv) - base_parms; - int i; - - if ((nv_len & 1) == 1 || (nv_len / 2) > N_NAME_VALUE) - { - fprintf (stderr, "AUTH-PAM: bad name/value list length\n"); - goto error; - } - - name_value_list.len = nv_len / 2; - for (i = 0; i < name_value_list.len; ++i) - { - const int base = base_parms + i * 2; - name_value_list.data[i].name = argv[base]; - name_value_list.data[i].value = argv[base+1]; - } + fprintf(stderr, "AUTH-PAM: need PAM service parameter\n"); + goto error; } - /* - * Get verbosity level from environment - */ - { - const char *verb_string = get_env ("verb", envp); - if (verb_string) - context->verb = atoi (verb_string); - } - - /* - * Make a socket for foreground and background processes - * to communicate. - */ - if (socketpair (PF_UNIX, SOCK_DGRAM, 0, fd) == -1) + /* + * See if we have optional name/value pairs to match against + * PAM module queried fields in the conversation function. + */ + name_value_list.len = 0; + if (string_array_len(argv) > base_parms) { - fprintf (stderr, "AUTH-PAM: socketpair call failed\n"); - goto error; + const int nv_len = string_array_len(argv) - base_parms; + int i; + + if ((nv_len & 1) == 1 || (nv_len / 2) > N_NAME_VALUE) + { + fprintf(stderr, "AUTH-PAM: bad name/value list length\n"); + goto error; + } + + name_value_list.len = nv_len / 2; + for (i = 0; i < name_value_list.len; ++i) + { + const int base = base_parms + i * 2; + name_value_list.data[i].name = argv[base]; + name_value_list.data[i].value = argv[base+1]; + } } - /* - * Fork off the privileged process. It will remain privileged - * even after the foreground process drops its privileges. - */ - pid = fork (); - - if (pid) + /* + * Get verbosity level from environment + */ { - int status; - - /* - * Foreground Process - */ - - context->background_pid = pid; + const char *verb_string = get_env("verb", envp); + if (verb_string) + { + context->verb = atoi(verb_string); + } + } - /* close our copy of child's socket */ - close (fd[1]); + /* + * Make a socket for foreground and background processes + * to communicate. + */ + if (socketpair(PF_UNIX, SOCK_DGRAM, 0, fd) == -1) + { + fprintf(stderr, "AUTH-PAM: socketpair call failed\n"); + goto error; + } - /* don't let future subprocesses inherit child socket */ - if (fcntl (fd[0], F_SETFD, FD_CLOEXEC) < 0) - fprintf (stderr, "AUTH-PAM: Set FD_CLOEXEC flag on socket file descriptor failed\n"); + /* + * Fork off the privileged process. It will remain privileged + * even after the foreground process drops its privileges. + */ + pid = fork(); - /* wait for background child process to initialize */ - status = recv_control (fd[0]); - if (status == RESPONSE_INIT_SUCCEEDED) - { - context->foreground_fd = fd[0]; - return (openvpn_plugin_handle_t) context; - } + if (pid) + { + int status; + + /* + * Foreground Process + */ + + context->background_pid = pid; + + /* close our copy of child's socket */ + close(fd[1]); + + /* don't let future subprocesses inherit child socket */ + if (fcntl(fd[0], F_SETFD, FD_CLOEXEC) < 0) + { + fprintf(stderr, "AUTH-PAM: Set FD_CLOEXEC flag on socket file descriptor failed\n"); + } + + /* wait for background child process to initialize */ + status = recv_control(fd[0]); + if (status == RESPONSE_INIT_SUCCEEDED) + { + context->foreground_fd = fd[0]; + return (openvpn_plugin_handle_t) context; + } } - else + else { - /* - * Background Process - */ + /* + * Background Process + */ - /* close all parent fds except our socket back to parent */ - close_fds_except (fd[1]); + /* close all parent fds except our socket back to parent */ + close_fds_except(fd[1]); - /* Ignore most signals (the parent will receive them) */ - set_signals (); + /* Ignore most signals (the parent will receive them) */ + set_signals(); #ifdef DO_DAEMONIZE - /* Daemonize if --daemon option is set. */ - daemonize (envp); + /* Daemonize if --daemon option is set. */ + daemonize(envp); #endif - /* execute the event loop */ - pam_server (fd[1], argv[1], context->verb, &name_value_list); + /* execute the event loop */ + pam_server(fd[1], argv[1], context->verb, &name_value_list); - close (fd[1]); + close(fd[1]); - exit (0); - return 0; /* NOTREACHED */ + exit(0); + return 0; /* NOTREACHED */ } - error: - if (context) - free (context); - return NULL; +error: + if (context) + { + free(context); + } + return NULL; } OPENVPN_EXPORT int -openvpn_plugin_func_v1 (openvpn_plugin_handle_t handle, const int type, const char *argv[], const char *envp[]) +openvpn_plugin_func_v1(openvpn_plugin_handle_t handle, const int type, const char *argv[], const char *envp[]) { - struct auth_pam_context *context = (struct auth_pam_context *) handle; - - if (type == OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY && context->foreground_fd >= 0) - { - /* get username/password from envp string array */ - const char *username = get_env ("username", envp); - const char *password = get_env ("password", envp); - const char *common_name = get_env ("common_name", envp) ? get_env ("common_name", envp) : ""; - - if (username && strlen (username) > 0 && password) - { - if (send_control (context->foreground_fd, COMMAND_VERIFY) == -1 - || send_string (context->foreground_fd, username) == -1 - || send_string (context->foreground_fd, password) == -1 - || send_string (context->foreground_fd, common_name) == -1) - { - fprintf (stderr, "AUTH-PAM: Error sending auth info to background process\n"); - } - else - { - const int status = recv_control (context->foreground_fd); - if (status == RESPONSE_VERIFY_SUCCEEDED) - return OPENVPN_PLUGIN_FUNC_SUCCESS; - if (status == -1) - fprintf (stderr, "AUTH-PAM: Error receiving auth confirmation from background process\n"); - } - } - } - return OPENVPN_PLUGIN_FUNC_ERROR; + struct auth_pam_context *context = (struct auth_pam_context *) handle; + + if (type == OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY && context->foreground_fd >= 0) + { + /* get username/password from envp string array */ + const char *username = get_env("username", envp); + const char *password = get_env("password", envp); + const char *common_name = get_env("common_name", envp) ? get_env("common_name", envp) : ""; + + if (username && strlen(username) > 0 && password) + { + if (send_control(context->foreground_fd, COMMAND_VERIFY) == -1 + || send_string(context->foreground_fd, username) == -1 + || send_string(context->foreground_fd, password) == -1 + || send_string(context->foreground_fd, common_name) == -1) + { + fprintf(stderr, "AUTH-PAM: Error sending auth info to background process\n"); + } + else + { + const int status = recv_control(context->foreground_fd); + if (status == RESPONSE_VERIFY_SUCCEEDED) + { + return OPENVPN_PLUGIN_FUNC_SUCCESS; + } + if (status == -1) + { + fprintf(stderr, "AUTH-PAM: Error receiving auth confirmation from background process\n"); + } + } + } + } + return OPENVPN_PLUGIN_FUNC_ERROR; } OPENVPN_EXPORT void -openvpn_plugin_close_v1 (openvpn_plugin_handle_t handle) +openvpn_plugin_close_v1(openvpn_plugin_handle_t handle) { - struct auth_pam_context *context = (struct auth_pam_context *) handle; - - if (DEBUG (context->verb)) - fprintf (stderr, "AUTH-PAM: close\n"); + struct auth_pam_context *context = (struct auth_pam_context *) handle; - if (context->foreground_fd >= 0) + if (DEBUG(context->verb)) { - /* tell background process to exit */ - if (send_control (context->foreground_fd, COMMAND_EXIT) == -1) - fprintf (stderr, "AUTH-PAM: Error signaling background process to exit\n"); - - /* wait for background process to exit */ - if (context->background_pid > 0) - waitpid (context->background_pid, NULL, 0); + fprintf(stderr, "AUTH-PAM: close\n"); + } - close (context->foreground_fd); - context->foreground_fd = -1; + if (context->foreground_fd >= 0) + { + /* tell background process to exit */ + if (send_control(context->foreground_fd, COMMAND_EXIT) == -1) + { + fprintf(stderr, "AUTH-PAM: Error signaling background process to exit\n"); + } + + /* wait for background process to exit */ + if (context->background_pid > 0) + { + waitpid(context->background_pid, NULL, 0); + } + + close(context->foreground_fd); + context->foreground_fd = -1; } - free (context); + free(context); } OPENVPN_EXPORT void -openvpn_plugin_abort_v1 (openvpn_plugin_handle_t handle) +openvpn_plugin_abort_v1(openvpn_plugin_handle_t handle) { - struct auth_pam_context *context = (struct auth_pam_context *) handle; + struct auth_pam_context *context = (struct auth_pam_context *) handle; - /* tell background process to exit */ - if (context && context->foreground_fd >= 0) + /* tell background process to exit */ + if (context && context->foreground_fd >= 0) { - send_control (context->foreground_fd, COMMAND_EXIT); - close (context->foreground_fd); - context->foreground_fd = -1; + send_control(context->foreground_fd, COMMAND_EXIT); + close(context->foreground_fd); + context->foreground_fd = -1; } } @@ -474,111 +510,137 @@ openvpn_plugin_abort_v1 (openvpn_plugin_handle_t handle) * PAM conversation function */ static int -my_conv (int n, const struct pam_message **msg_array, - struct pam_response **response_array, void *appdata_ptr) +my_conv(int n, const struct pam_message **msg_array, + struct pam_response **response_array, void *appdata_ptr) { - const struct user_pass *up = ( const struct user_pass *) appdata_ptr; - struct pam_response *aresp; - int i; - int ret = PAM_SUCCESS; - - *response_array = NULL; - - if (n <= 0 || n > PAM_MAX_NUM_MSG) - return (PAM_CONV_ERR); - if ((aresp = calloc (n, sizeof *aresp)) == NULL) - return (PAM_BUF_ERR); - - /* loop through each PAM-module query */ - for (i = 0; i < n; ++i) - { - const struct pam_message *msg = msg_array[i]; - aresp[i].resp_retcode = 0; - aresp[i].resp = NULL; - - if (DEBUG (up->verb)) - { - fprintf (stderr, "AUTH-PAM: BACKGROUND: my_conv[%d] query='%s' style=%d\n", - i, - msg->msg ? msg->msg : "NULL", - msg->msg_style); - } - - if (up->name_value_list && up->name_value_list->len > 0) - { - /* use name/value list match method */ - const struct name_value_list *list = up->name_value_list; - int j; - - /* loop through name/value pairs */ - for (j = 0; j < list->len; ++j) - { - const char *match_name = list->data[j].name; - const char *match_value = list->data[j].value; - - if (name_value_match (msg->msg, match_name)) - { - /* found name/value match */ - aresp[i].resp = NULL; - - if (DEBUG (up->verb)) - fprintf (stderr, "AUTH-PAM: BACKGROUND: name match found, query/match-string ['%s', '%s'] = '%s'\n", - msg->msg, - match_name, - match_value); - - if (strstr(match_value, "USERNAME")) - aresp[i].resp = searchandreplace(match_value, "USERNAME", up->username); - else if (strstr(match_value, "PASSWORD")) - aresp[i].resp = searchandreplace(match_value, "PASSWORD", up->password); - else if (strstr(match_value, "COMMONNAME")) - aresp[i].resp = searchandreplace(match_value, "COMMONNAME", up->common_name); - else - aresp[i].resp = strdup (match_value); - - if (aresp[i].resp == NULL) - ret = PAM_CONV_ERR; - break; - } - } - - if (j == list->len) - ret = PAM_CONV_ERR; - } - else - { - /* use PAM_PROMPT_ECHO_x hints */ - switch (msg->msg_style) - { - case PAM_PROMPT_ECHO_OFF: - aresp[i].resp = strdup (up->password); - if (aresp[i].resp == NULL) - ret = PAM_CONV_ERR; - break; - - case PAM_PROMPT_ECHO_ON: - aresp[i].resp = strdup (up->username); - if (aresp[i].resp == NULL) - ret = PAM_CONV_ERR; - break; - - case PAM_ERROR_MSG: - case PAM_TEXT_INFO: - break; - - default: - ret = PAM_CONV_ERR; - break; - } - } - } - - if (ret == PAM_SUCCESS) - *response_array = aresp; - else - free(aresp); - - return ret; + const struct user_pass *up = ( const struct user_pass *) appdata_ptr; + struct pam_response *aresp; + int i; + int ret = PAM_SUCCESS; + + *response_array = NULL; + + if (n <= 0 || n > PAM_MAX_NUM_MSG) + { + return (PAM_CONV_ERR); + } + if ((aresp = calloc(n, sizeof *aresp)) == NULL) + { + return (PAM_BUF_ERR); + } + + /* loop through each PAM-module query */ + for (i = 0; i < n; ++i) + { + const struct pam_message *msg = msg_array[i]; + aresp[i].resp_retcode = 0; + aresp[i].resp = NULL; + + if (DEBUG(up->verb)) + { + fprintf(stderr, "AUTH-PAM: BACKGROUND: my_conv[%d] query='%s' style=%d\n", + i, + msg->msg ? msg->msg : "NULL", + msg->msg_style); + } + + if (up->name_value_list && up->name_value_list->len > 0) + { + /* use name/value list match method */ + const struct name_value_list *list = up->name_value_list; + int j; + + /* loop through name/value pairs */ + for (j = 0; j < list->len; ++j) + { + const char *match_name = list->data[j].name; + const char *match_value = list->data[j].value; + + if (name_value_match(msg->msg, match_name)) + { + /* found name/value match */ + aresp[i].resp = NULL; + + if (DEBUG(up->verb)) + { + fprintf(stderr, "AUTH-PAM: BACKGROUND: name match found, query/match-string ['%s', '%s'] = '%s'\n", + msg->msg, + match_name, + match_value); + } + + if (strstr(match_value, "USERNAME")) + { + aresp[i].resp = searchandreplace(match_value, "USERNAME", up->username); + } + else if (strstr(match_value, "PASSWORD")) + { + aresp[i].resp = searchandreplace(match_value, "PASSWORD", up->password); + } + else if (strstr(match_value, "COMMONNAME")) + { + aresp[i].resp = searchandreplace(match_value, "COMMONNAME", up->common_name); + } + else + { + aresp[i].resp = strdup(match_value); + } + + if (aresp[i].resp == NULL) + { + ret = PAM_CONV_ERR; + } + break; + } + } + + if (j == list->len) + { + ret = PAM_CONV_ERR; + } + } + else + { + /* use PAM_PROMPT_ECHO_x hints */ + switch (msg->msg_style) + { + case PAM_PROMPT_ECHO_OFF: + aresp[i].resp = strdup(up->password); + if (aresp[i].resp == NULL) + { + ret = PAM_CONV_ERR; + } + break; + + case PAM_PROMPT_ECHO_ON: + aresp[i].resp = strdup(up->username); + if (aresp[i].resp == NULL) + { + ret = PAM_CONV_ERR; + } + break; + + case PAM_ERROR_MSG: + case PAM_TEXT_INFO: + break; + + default: + ret = PAM_CONV_ERR; + break; + } + } + } + + if (ret == PAM_SUCCESS) + { + *response_array = aresp; + } + else + { + free(aresp); + } + + return ret; } /* @@ -587,156 +649,166 @@ my_conv (int n, const struct pam_message **msg_array, * to be authenticated. */ static int -pam_auth (const char *service, const struct user_pass *up) +pam_auth(const char *service, const struct user_pass *up) { - struct pam_conv conv; - pam_handle_t *pamh = NULL; - int status = PAM_SUCCESS; - int ret = 0; - const int name_value_list_provided = (up->name_value_list && up->name_value_list->len > 0); - - /* Initialize PAM */ - conv.conv = my_conv; - conv.appdata_ptr = (void *)up; - status = pam_start (service, name_value_list_provided ? NULL : up->username, &conv, &pamh); - if (status == PAM_SUCCESS) - { - /* Call PAM to verify username/password */ - status = pam_authenticate(pamh, 0); - if (status == PAM_SUCCESS) - status = pam_acct_mgmt (pamh, 0); - if (status == PAM_SUCCESS) - ret = 1; - - /* Output error message if failed */ - if (!ret) - { - fprintf (stderr, "AUTH-PAM: BACKGROUND: user '%s' failed to authenticate: %s\n", - up->username, - pam_strerror (pamh, status)); - } - - /* Close PAM */ - pam_end (pamh, status); - } - - return ret; + struct pam_conv conv; + pam_handle_t *pamh = NULL; + int status = PAM_SUCCESS; + int ret = 0; + const int name_value_list_provided = (up->name_value_list && up->name_value_list->len > 0); + + /* Initialize PAM */ + conv.conv = my_conv; + conv.appdata_ptr = (void *)up; + status = pam_start(service, name_value_list_provided ? NULL : up->username, &conv, &pamh); + if (status == PAM_SUCCESS) + { + /* Call PAM to verify username/password */ + status = pam_authenticate(pamh, 0); + if (status == PAM_SUCCESS) + { + status = pam_acct_mgmt(pamh, 0); + } + if (status == PAM_SUCCESS) + { + ret = 1; + } + + /* Output error message if failed */ + if (!ret) + { + fprintf(stderr, "AUTH-PAM: BACKGROUND: user '%s' failed to authenticate: %s\n", + up->username, + pam_strerror(pamh, status)); + } + + /* Close PAM */ + pam_end(pamh, status); + } + + return ret; } /* * Background process -- runs with privilege. */ static void -pam_server (int fd, const char *service, int verb, const struct name_value_list *name_value_list) +pam_server(int fd, const char *service, int verb, const struct name_value_list *name_value_list) { - struct user_pass up; - int command; + struct user_pass up; + int command; #ifdef USE_PAM_DLOPEN - static const char pam_so[] = "libpam.so"; + static const char pam_so[] = "libpam.so"; #endif - /* - * Do initialization - */ - if (DEBUG (verb)) - fprintf (stderr, "AUTH-PAM: BACKGROUND: INIT service='%s'\n", service); + /* + * Do initialization + */ + if (DEBUG(verb)) + { + fprintf(stderr, "AUTH-PAM: BACKGROUND: INIT service='%s'\n", service); + } #ifdef USE_PAM_DLOPEN - /* - * Load PAM shared object - */ - if (!dlopen_pam (pam_so)) + /* + * Load PAM shared object + */ + if (!dlopen_pam(pam_so)) { - fprintf (stderr, "AUTH-PAM: BACKGROUND: could not load PAM lib %s: %s\n", pam_so, dlerror()); - send_control (fd, RESPONSE_INIT_FAILED); - goto done; + fprintf(stderr, "AUTH-PAM: BACKGROUND: could not load PAM lib %s: %s\n", pam_so, dlerror()); + send_control(fd, RESPONSE_INIT_FAILED); + goto done; } #endif - /* - * Tell foreground that we initialized successfully - */ - if (send_control (fd, RESPONSE_INIT_SUCCEEDED) == -1) + /* + * Tell foreground that we initialized successfully + */ + if (send_control(fd, RESPONSE_INIT_SUCCEEDED) == -1) { - fprintf (stderr, "AUTH-PAM: BACKGROUND: write error on response socket [1]\n"); - goto done; + fprintf(stderr, "AUTH-PAM: BACKGROUND: write error on response socket [1]\n"); + goto done; } - /* - * Event loop - */ - while (1) + /* + * Event loop + */ + while (1) { - memset (&up, 0, sizeof (up)); - up.verb = verb; - up.name_value_list = name_value_list; - - /* get a command from foreground process */ - command = recv_control (fd); - - if (DEBUG (verb)) - fprintf (stderr, "AUTH-PAM: BACKGROUND: received command code: %d\n", command); - - switch (command) - { - case COMMAND_VERIFY: - if (recv_string (fd, up.username, sizeof (up.username)) == -1 - || recv_string (fd, up.password, sizeof (up.password)) == -1 - || recv_string (fd, up.common_name, sizeof (up.common_name)) == -1) - { - fprintf (stderr, "AUTH-PAM: BACKGROUND: read error on command channel: code=%d, exiting\n", - command); - goto done; - } - - if (DEBUG (verb)) - { + memset(&up, 0, sizeof(up)); + up.verb = verb; + up.name_value_list = name_value_list; + + /* get a command from foreground process */ + command = recv_control(fd); + + if (DEBUG(verb)) + { + fprintf(stderr, "AUTH-PAM: BACKGROUND: received command code: %d\n", command); + } + + switch (command) + { + case COMMAND_VERIFY: + if (recv_string(fd, up.username, sizeof(up.username)) == -1 + || recv_string(fd, up.password, sizeof(up.password)) == -1 + || recv_string(fd, up.common_name, sizeof(up.common_name)) == -1) + { + fprintf(stderr, "AUTH-PAM: BACKGROUND: read error on command channel: code=%d, exiting\n", + command); + goto done; + } + + if (DEBUG(verb)) + { #if 0 - fprintf (stderr, "AUTH-PAM: BACKGROUND: USER/PASS: %s/%s\n", - up.username, up.password); + fprintf(stderr, "AUTH-PAM: BACKGROUND: USER/PASS: %s/%s\n", + up.username, up.password); #else - fprintf (stderr, "AUTH-PAM: BACKGROUND: USER: %s\n", up.username); + fprintf(stderr, "AUTH-PAM: BACKGROUND: USER: %s\n", up.username); #endif - } - - if (pam_auth (service, &up)) /* Succeeded */ - { - if (send_control (fd, RESPONSE_VERIFY_SUCCEEDED) == -1) - { - fprintf (stderr, "AUTH-PAM: BACKGROUND: write error on response socket [2]\n"); - goto done; - } - } - else /* Failed */ - { - if (send_control (fd, RESPONSE_VERIFY_FAILED) == -1) - { - fprintf (stderr, "AUTH-PAM: BACKGROUND: write error on response socket [3]\n"); - goto done; - } - } - break; - - case COMMAND_EXIT: - goto done; - - case -1: - fprintf (stderr, "AUTH-PAM: BACKGROUND: read error on command channel\n"); - goto done; - - default: - fprintf (stderr, "AUTH-PAM: BACKGROUND: unknown command code: code=%d, exiting\n", - command); - goto done; - } - } - done: + } + + if (pam_auth(service, &up)) /* Succeeded */ + { + if (send_control(fd, RESPONSE_VERIFY_SUCCEEDED) == -1) + { + fprintf(stderr, "AUTH-PAM: BACKGROUND: write error on response socket [2]\n"); + goto done; + } + } + else /* Failed */ + { + if (send_control(fd, RESPONSE_VERIFY_FAILED) == -1) + { + fprintf(stderr, "AUTH-PAM: BACKGROUND: write error on response socket [3]\n"); + goto done; + } + } + break; + + case COMMAND_EXIT: + goto done; + + case -1: + fprintf(stderr, "AUTH-PAM: BACKGROUND: read error on command channel\n"); + goto done; + + default: + fprintf(stderr, "AUTH-PAM: BACKGROUND: unknown command code: code=%d, exiting\n", + command); + goto done; + } + } +done: #ifdef USE_PAM_DLOPEN - dlclose_pam (); + dlclose_pam(); #endif - if (DEBUG (verb)) - fprintf (stderr, "AUTH-PAM: BACKGROUND: EXIT\n"); + if (DEBUG(verb)) + { + fprintf(stderr, "AUTH-PAM: BACKGROUND: EXIT\n"); + } - return; + return; } diff --git a/src/plugins/auth-pam/pamdl.c b/src/plugins/auth-pam/pamdl.c index 26e98215de4..02ea71a4873 100644 --- a/src/plugins/auth-pam/pamdl.c +++ b/src/plugins/auth-pam/pamdl.c @@ -21,125 +21,136 @@ static void *libpam_h = NULL; #define RESOLVE_PAM_FUNCTION(x, y, z, err) \ { \ - union { const void *tpointer; y (*fn) z ; } fptr; \ - fptr.tpointer = dlsym(libpam_h, #x); real_##x = fptr.fn; \ - if (real_##x == NULL) { \ - fprintf (stderr, "PAMDL: unable to resolve '%s': %s\n", #x, dlerror()); \ - return err; \ - } \ + union { const void *tpointer; y(*fn) z; } fptr; \ + fptr.tpointer = dlsym(libpam_h, #x); real_ ## x = fptr.fn; \ + if (real_ ## x == NULL) { \ + fprintf(stderr, "PAMDL: unable to resolve '%s': %s\n", #x, dlerror()); \ + return err; \ + } \ } int -dlopen_pam (const char *so) +dlopen_pam(const char *so) { - if (libpam_h == NULL) + if (libpam_h == NULL) { - libpam_h = dlopen(so, RTLD_GLOBAL|RTLD_NOW); + libpam_h = dlopen(so, RTLD_GLOBAL|RTLD_NOW); } - return libpam_h != NULL; + return libpam_h != NULL; } void -dlclose_pam (void) +dlclose_pam(void) { - if (libpam_h != NULL) + if (libpam_h != NULL) { - dlclose(libpam_h); - libpam_h = NULL; + dlclose(libpam_h); + libpam_h = NULL; } } -int pam_start(const char *service_name, const char *user, - const struct pam_conv *pam_conversation, - pam_handle_t **pamh) +int +pam_start(const char *service_name, const char *user, + const struct pam_conv *pam_conversation, + pam_handle_t **pamh) { int (*real_pam_start)(const char *, const char *, - const struct pam_conv *, - pam_handle_t **); + const struct pam_conv *, + pam_handle_t **); RESOLVE_PAM_FUNCTION(pam_start, int, (const char *, const char *, - const struct pam_conv *, - pam_handle_t **), PAM_ABORT); + const struct pam_conv *, + pam_handle_t **), PAM_ABORT); return real_pam_start(service_name, user, pam_conversation, pamh); } -int pam_end(pam_handle_t *pamh, int pam_status) +int +pam_end(pam_handle_t *pamh, int pam_status) { int (*real_pam_end)(pam_handle_t *, int); RESOLVE_PAM_FUNCTION(pam_end, int, (pam_handle_t *, int), PAM_ABORT); return real_pam_end(pamh, pam_status); } -int pam_set_item(pam_handle_t *pamh, int item_type, const void *item) +int +pam_set_item(pam_handle_t *pamh, int item_type, const void *item) { int (*real_pam_set_item)(pam_handle_t *, int, const void *); RESOLVE_PAM_FUNCTION(pam_set_item, int, - (pam_handle_t *, int, const void *), PAM_ABORT); + (pam_handle_t *, int, const void *), PAM_ABORT); return real_pam_set_item(pamh, item_type, item); } -int pam_get_item(const pam_handle_t *pamh, int item_type, const void **item) +int +pam_get_item(const pam_handle_t *pamh, int item_type, const void **item) { int (*real_pam_get_item)(const pam_handle_t *, int, const void **); RESOLVE_PAM_FUNCTION(pam_get_item, int, - (const pam_handle_t *, int, const void **), - PAM_ABORT); + (const pam_handle_t *, int, const void **), + PAM_ABORT); return real_pam_get_item(pamh, item_type, item); } -int pam_fail_delay(pam_handle_t *pamh, unsigned int musec_delay) +int +pam_fail_delay(pam_handle_t *pamh, unsigned int musec_delay) { int (*real_pam_fail_delay)(pam_handle_t *, unsigned int); RESOLVE_PAM_FUNCTION(pam_fail_delay, int, (pam_handle_t *, unsigned int), - PAM_ABORT); + PAM_ABORT); return real_pam_fail_delay(pamh, musec_delay); } -typedef const char * const_char_pointer; +typedef const char *const_char_pointer; -const_char_pointer pam_strerror(pam_handle_t *pamh, int errnum) +const_char_pointer +pam_strerror(pam_handle_t *pamh, int errnum) { const_char_pointer (*real_pam_strerror)(pam_handle_t *, int); RESOLVE_PAM_FUNCTION(pam_strerror, const_char_pointer, - (pam_handle_t *, int), NULL); + (pam_handle_t *, int), NULL); return real_pam_strerror(pamh, errnum); } -int pam_putenv(pam_handle_t *pamh, const char *name_value) +int +pam_putenv(pam_handle_t *pamh, const char *name_value) { int (*real_pam_putenv)(pam_handle_t *, const char *); RESOLVE_PAM_FUNCTION(pam_putenv, int, (pam_handle_t *, const char *), - PAM_ABORT); + PAM_ABORT); return real_pam_putenv(pamh, name_value); } -const_char_pointer pam_getenv(pam_handle_t *pamh, const char *name) +const_char_pointer +pam_getenv(pam_handle_t *pamh, const char *name) { const_char_pointer (*real_pam_getenv)(pam_handle_t *, const char *); RESOLVE_PAM_FUNCTION(pam_getenv, const_char_pointer, - (pam_handle_t *, const char *), NULL); + (pam_handle_t *, const char *), NULL); return real_pam_getenv(pamh, name); } -typedef char ** char_ppointer; -char_ppointer pam_getenvlist(pam_handle_t *pamh) +typedef char **char_ppointer; +char_ppointer +pam_getenvlist(pam_handle_t *pamh) { char_ppointer (*real_pam_getenvlist)(pam_handle_t *); RESOLVE_PAM_FUNCTION(pam_getenvlist, char_ppointer, (pam_handle_t *), - NULL); + NULL); return real_pam_getenvlist(pamh); } /* Authentication management */ -int pam_authenticate(pam_handle_t *pamh, int flags) +int +pam_authenticate(pam_handle_t *pamh, int flags) { int (*real_pam_authenticate)(pam_handle_t *, int); RESOLVE_PAM_FUNCTION(pam_authenticate, int, (pam_handle_t *, int), - PAM_ABORT); + PAM_ABORT); return real_pam_authenticate(pamh, flags); } -int pam_setcred(pam_handle_t *pamh, int flags) +int +pam_setcred(pam_handle_t *pamh, int flags) { int (*real_pam_setcred)(pam_handle_t *, int); RESOLVE_PAM_FUNCTION(pam_setcred, int, (pam_handle_t *, int), PAM_ABORT); @@ -148,7 +159,8 @@ int pam_setcred(pam_handle_t *pamh, int flags) /* Account Management API's */ -int pam_acct_mgmt(pam_handle_t *pamh, int flags) +int +pam_acct_mgmt(pam_handle_t *pamh, int flags) { int (*real_pam_acct_mgmt)(pam_handle_t *, int); RESOLVE_PAM_FUNCTION(pam_acct_mgmt, int, (pam_handle_t *, int), PAM_ABORT); @@ -157,28 +169,31 @@ int pam_acct_mgmt(pam_handle_t *pamh, int flags) /* Session Management API's */ -int pam_open_session(pam_handle_t *pamh, int flags) +int +pam_open_session(pam_handle_t *pamh, int flags) { int (*real_pam_open_session)(pam_handle_t *, int); RESOLVE_PAM_FUNCTION(pam_open_session, int, (pam_handle_t *, int), - PAM_ABORT); + PAM_ABORT); return real_pam_open_session(pamh, flags); } -int pam_close_session(pam_handle_t *pamh, int flags) +int +pam_close_session(pam_handle_t *pamh, int flags) { int (*real_pam_close_session)(pam_handle_t *, int); RESOLVE_PAM_FUNCTION(pam_close_session, int, (pam_handle_t *, int), - PAM_ABORT); + PAM_ABORT); return real_pam_close_session(pamh, flags); } /* Password Management API's */ -int pam_chauthtok(pam_handle_t *pamh, int flags) +int +pam_chauthtok(pam_handle_t *pamh, int flags) { int (*real_pam_chauthtok)(pam_handle_t *, int); RESOLVE_PAM_FUNCTION(pam_chauthtok, int, (pam_handle_t *, int), PAM_ABORT); return real_pam_chauthtok(pamh, flags); } -#endif +#endif /* ifdef USE_PAM_DLOPEN */ diff --git a/src/plugins/auth-pam/pamdl.h b/src/plugins/auth-pam/pamdl.h index 12ba0684c99..15ca85e4ae8 100644 --- a/src/plugins/auth-pam/pamdl.h +++ b/src/plugins/auth-pam/pamdl.h @@ -1,5 +1,7 @@ #ifdef USE_PAM_DLOPEN /* Dynamically load and unload the PAM library */ -int dlopen_pam (const char *so); -void dlclose_pam (void); +int dlopen_pam(const char *so); + +void dlclose_pam(void); + #endif diff --git a/src/plugins/auth-pam/utils.c b/src/plugins/auth-pam/utils.c index 4f2bec1e5f9..e4f4d195cdc 100644 --- a/src/plugins/auth-pam/utils.c +++ b/src/plugins/auth-pam/utils.c @@ -43,71 +43,81 @@ char * searchandreplace(const char *tosearch, const char *searchfor, const char *replacewith) { - if (!tosearch || !searchfor || !replacewith) return NULL; + if (!tosearch || !searchfor || !replacewith) + { + return NULL; + } - size_t tosearchlen = strlen(tosearch); - size_t replacewithlen = strlen(replacewith); - size_t templen = tosearchlen * replacewithlen; + size_t tosearchlen = strlen(tosearch); + size_t replacewithlen = strlen(replacewith); + size_t templen = tosearchlen * replacewithlen; - if (tosearchlen == 0 || strlen(searchfor) == 0 || replacewithlen == 0) { - return NULL; - } + if (tosearchlen == 0 || strlen(searchfor) == 0 || replacewithlen == 0) + { + return NULL; + } - bool is_potential_integer_overflow = (templen == SIZE_MAX) || (templen / tosearchlen != replacewithlen); + bool is_potential_integer_overflow = (templen == SIZE_MAX) || (templen / tosearchlen != replacewithlen); - if (is_potential_integer_overflow) { - return NULL; - } + if (is_potential_integer_overflow) + { + return NULL; + } - // state: all parameters are valid + /* state: all parameters are valid */ - const char *searching=tosearch; - char *scratch; + const char *searching = tosearch; + char *scratch; - char temp[templen+1]; - temp[0]=0; + char temp[templen+1]; + temp[0] = 0; - scratch = strstr(searching,searchfor); - if (!scratch) return strdup(tosearch); + scratch = strstr(searching,searchfor); + if (!scratch) + { + return strdup(tosearch); + } - while (scratch) { - strncat(temp,searching,scratch-searching); - strcat(temp,replacewith); + while (scratch) { + strncat(temp,searching,scratch-searching); + strcat(temp,replacewith); - searching=scratch+strlen(searchfor); - scratch = strstr(searching,searchfor); - } - return strdup(temp); + searching = scratch+strlen(searchfor); + scratch = strstr(searching,searchfor); + } + return strdup(temp); } const char * -get_env (const char *name, const char *envp[]) +get_env(const char *name, const char *envp[]) { - if (envp) + if (envp) { - int i; - const int namelen = strlen (name); - for (i = 0; envp[i]; ++i) - { - if (!strncmp (envp[i], name, namelen)) - { - const char *cp = envp[i] + namelen; - if (*cp == '=') - return cp + 1; - } - } + int i; + const int namelen = strlen(name); + for (i = 0; envp[i]; ++i) + { + if (!strncmp(envp[i], name, namelen)) + { + const char *cp = envp[i] + namelen; + if (*cp == '=') + { + return cp + 1; + } + } + } } - return NULL; + return NULL; } int -string_array_len (const char *array[]) +string_array_len(const char *array[]) { - int i = 0; - if (array) + int i = 0; + if (array) { - while (array[i]) - ++i; + while (array[i]) + ++i; } - return i; + return i; } diff --git a/src/plugins/auth-pam/utils.h b/src/plugins/auth-pam/utils.h index 2f7204030e7..810f7b9632d 100644 --- a/src/plugins/auth-pam/utils.h +++ b/src/plugins/auth-pam/utils.h @@ -52,7 +52,7 @@ searchandreplace(const char *tosearch, const char *searchfor, const char *replac * @return Returns a pointer to the value of the enviroment variable if found, otherwise NULL is returned. */ const char * -get_env (const char *name, const char *envp[]); +get_env(const char *name, const char *envp[]); /** * Return the length of a string array @@ -61,6 +61,6 @@ get_env (const char *name, const char *envp[]); * */ int -string_array_len (const char *array[]); +string_array_len(const char *array[]); #endif diff --git a/src/plugins/down-root/down-root.c b/src/plugins/down-root/down-root.c index 6931becf7ab..c940d61ae42 100644 --- a/src/plugins/down-root/down-root.c +++ b/src/plugins/down-root/down-root.c @@ -59,7 +59,7 @@ #define RESPONSE_SCRIPT_FAILED 13 /* Background process function */ -static void down_root_server (const int fd, char * const * argv, char * const *envp, const int verb); +static void down_root_server(const int fd, char *const *argv, char *const *envp, const int verb); /* * Plugin state, used by foreground @@ -85,19 +85,21 @@ struct down_root_context * if found or NULL otherwise. */ static const char * -get_env (const char *name, const char *envp[]) +get_env(const char *name, const char *envp[]) { if (envp) { int i; - const int namelen = strlen (name); + const int namelen = strlen(name); for (i = 0; envp[i]; ++i) { - if (!strncmp (envp[i], name, namelen)) + if (!strncmp(envp[i], name, namelen)) { const char *cp = envp[i] + namelen; if (*cp == '=') + { return cp + 1; + } } } } @@ -108,7 +110,7 @@ get_env (const char *name, const char *envp[]) * Return the length of a string array */ static int -string_array_len (const char *array[]) +string_array_len(const char *array[]) { int i = 0; if (array) @@ -124,25 +126,33 @@ string_array_len (const char *array[]) */ static int -recv_control (int fd) +recv_control(int fd) { unsigned char c; - const ssize_t size = read (fd, &c, sizeof (c)); - if (size == sizeof (c)) + const ssize_t size = read(fd, &c, sizeof(c)); + if (size == sizeof(c)) + { return c; + } else + { return -1; + } } static int -send_control (int fd, int code) +send_control(int fd, int code) { unsigned char c = (unsigned char) code; - const ssize_t size = write (fd, &c, sizeof (c)); - if (size == sizeof (c)) + const ssize_t size = write(fd, &c, sizeof(c)); + if (size == sizeof(c)) + { return (int) size; + } else + { return -1; + } } /* @@ -151,23 +161,25 @@ send_control (int fd, int code) * "daemon_log_redirect" env var is true. */ static void -daemonize (const char *envp[]) +daemonize(const char *envp[]) { - const char *daemon_string = get_env ("daemon", envp); + const char *daemon_string = get_env("daemon", envp); if (daemon_string && daemon_string[0] == '1') { - const char *log_redirect = get_env ("daemon_log_redirect", envp); + const char *log_redirect = get_env("daemon_log_redirect", envp); int fd = -1; if (log_redirect && log_redirect[0] == '1') - fd = dup (2); - if (daemon (0, 0) < 0) { - warn ("DOWN-ROOT: daemonization failed"); + fd = dup(2); + } + if (daemon(0, 0) < 0) + { + warn("DOWN-ROOT: daemonization failed"); } else if (fd >= 3) { - dup2 (fd, 2); - close (fd); + dup2(fd, 2); + close(fd); } } } @@ -183,14 +195,16 @@ daemonize (const char *envp[]) * fds from crossing a fork(). */ static void -close_fds_except (int keep) +close_fds_except(int keep) { int i; - closelog (); + closelog(); for (i = 3; i <= 100; ++i) { if (i != keep) - close (i); + { + close(i); + } } } @@ -199,28 +213,28 @@ close_fds_except (int keep) * deal with them. */ static void -set_signals (void) +set_signals(void) { - signal (SIGTERM, SIG_DFL); + signal(SIGTERM, SIG_DFL); - signal (SIGINT, SIG_IGN); - signal (SIGHUP, SIG_IGN); - signal (SIGUSR1, SIG_IGN); - signal (SIGUSR2, SIG_IGN); - signal (SIGPIPE, SIG_IGN); + signal(SIGINT, SIG_IGN); + signal(SIGHUP, SIG_IGN); + signal(SIGUSR1, SIG_IGN); + signal(SIGUSR2, SIG_IGN); + signal(SIGPIPE, SIG_IGN); } static void -free_context (struct down_root_context *context) +free_context(struct down_root_context *context) { if (context) { if (context->command) { - free (context->command); + free(context->command); } - free (context); + free(context); } } @@ -229,7 +243,7 @@ free_context (struct down_root_context *context) * calling execve() */ static int -run_script(char * const *argv, char * const *envp) +run_script(char *const *argv, char *const *envp) { pid_t pid; int ret = 0; @@ -241,14 +255,14 @@ run_script(char * const *argv, char * const *envp) /* If execve() fails to run, exit child with exit code 127 */ err(127, "DOWN-ROOT: Failed execute: %s", argv[0]); } - else if (pid < (pid_t)0 ) + else if (pid < (pid_t)0) { - warn ("DOWN-ROOT: Failed to fork child to run %s", argv[0]); + warn("DOWN-ROOT: Failed to fork child to run %s", argv[0]); return -1; } else /* parent side */ { - if( waitpid (pid, &ret, 0) != pid ) + if (waitpid(pid, &ret, 0) != pid) { /* waitpid does not return error information via errno */ fprintf(stderr, "DOWN-ROOT: waitpid() failed, don't know exit code of child (%s)\n", argv[0]); @@ -259,7 +273,7 @@ run_script(char * const *argv, char * const *envp) } OPENVPN_EXPORT openvpn_plugin_handle_t -openvpn_plugin_open_v1 (unsigned int *type_mask, const char *argv[], const char *envp[]) +openvpn_plugin_open_v1(unsigned int *type_mask, const char *argv[], const char *envp[]) { struct down_root_context *context; int i = 0; @@ -267,10 +281,10 @@ openvpn_plugin_open_v1 (unsigned int *type_mask, const char *argv[], const char /* * Allocate our context */ - context = (struct down_root_context *) calloc (1, sizeof (struct down_root_context)); + context = (struct down_root_context *) calloc(1, sizeof(struct down_root_context)); if (!context) { - warn ("DOWN-ROOT: Could not allocate memory for plug-in context"); + warn("DOWN-ROOT: Could not allocate memory for plug-in context"); goto error; } context->foreground_fd = -1; @@ -278,15 +292,15 @@ openvpn_plugin_open_v1 (unsigned int *type_mask, const char *argv[], const char /* * Intercept the --up and --down callbacks */ - *type_mask = OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_UP) | OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_DOWN); + *type_mask = OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_UP) | OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_DOWN); /* * Make sure we have two string arguments: the first is the .so name, * the second is the script command. */ - if (string_array_len (argv) < 2) + if (string_array_len(argv) < 2) { - fprintf (stderr, "DOWN-ROOT: need down script command\n"); + fprintf(stderr, "DOWN-ROOT: need down script command\n"); goto error; } @@ -296,7 +310,7 @@ openvpn_plugin_open_v1 (unsigned int *type_mask, const char *argv[], const char context->command = calloc(string_array_len(argv), sizeof(char *)); if (!context->command) { - warn ("DOWN-ROOT: Could not allocate memory for command array"); + warn("DOWN-ROOT: Could not allocate memory for command array"); goto error; } @@ -310,20 +324,22 @@ openvpn_plugin_open_v1 (unsigned int *type_mask, const char *argv[], const char * Get verbosity level from environment */ { - const char *verb_string = get_env ("verb", envp); + const char *verb_string = get_env("verb", envp); if (verb_string) - context->verb = atoi (verb_string); + { + context->verb = atoi(verb_string); + } } return (openvpn_plugin_handle_t) context; error: - free_context (context); + free_context(context); return NULL; } OPENVPN_EXPORT int -openvpn_plugin_func_v1 (openvpn_plugin_handle_t handle, const int type, const char *argv[], const char *envp[]) +openvpn_plugin_func_v1(openvpn_plugin_handle_t handle, const int type, const char *argv[], const char *envp[]) { struct down_root_context *context = (struct down_root_context *) handle; @@ -336,9 +352,9 @@ openvpn_plugin_func_v1 (openvpn_plugin_handle_t handle, const int type, const ch * Make a socket for foreground and background processes * to communicate. */ - if (socketpair (PF_UNIX, SOCK_DGRAM, 0, fd) == -1) + if (socketpair(PF_UNIX, SOCK_DGRAM, 0, fd) == -1) { - warn ("DOWN-ROOT: socketpair call failed"); + warn("DOWN-ROOT: socketpair call failed"); return OPENVPN_PLUGIN_FUNC_ERROR; } @@ -346,7 +362,7 @@ openvpn_plugin_func_v1 (openvpn_plugin_handle_t handle, const int type, const ch * Fork off the privileged process. It will remain privileged * even after the foreground process drops its privileges. */ - pid = fork (); + pid = fork(); if (pid) { @@ -359,16 +375,16 @@ openvpn_plugin_func_v1 (openvpn_plugin_handle_t handle, const int type, const ch context->background_pid = pid; /* close our copy of child's socket */ - close (fd[1]); + close(fd[1]); /* don't let future subprocesses inherit child socket */ - if (fcntl (fd[0], F_SETFD, FD_CLOEXEC) < 0) + if (fcntl(fd[0], F_SETFD, FD_CLOEXEC) < 0) { - warn ("DOWN-ROOT: Set FD_CLOEXEC flag on socket file descriptor failed"); + warn("DOWN-ROOT: Set FD_CLOEXEC flag on socket file descriptor failed"); } /* wait for background child process to initialize */ - status = recv_control (fd[0]); + status = recv_control(fd[0]); if (status == RESPONSE_INIT_SUCCEEDED) { context->foreground_fd = fd[0]; @@ -382,36 +398,38 @@ openvpn_plugin_func_v1 (openvpn_plugin_handle_t handle, const int type, const ch */ /* close all parent fds except our socket back to parent */ - close_fds_except (fd[1]); + close_fds_except(fd[1]); /* Ignore most signals (the parent will receive them) */ - set_signals (); + set_signals(); /* Daemonize if --daemon option is set. */ - daemonize (envp); + daemonize(envp); /* execute the event loop */ - down_root_server (fd[1], context->command, (char * const *) envp, context->verb); + down_root_server(fd[1], context->command, (char *const *) envp, context->verb); - close (fd[1]); - exit (0); + close(fd[1]); + exit(0); return 0; /* NOTREACHED */ } } else if (type == OPENVPN_PLUGIN_DOWN && context->foreground_fd >= 0) { - if (send_control (context->foreground_fd, COMMAND_RUN_SCRIPT) == -1) + if (send_control(context->foreground_fd, COMMAND_RUN_SCRIPT) == -1) { - warn ("DOWN-ROOT: Error sending script execution signal to background process"); + warn("DOWN-ROOT: Error sending script execution signal to background process"); } else { - const int status = recv_control (context->foreground_fd); + const int status = recv_control(context->foreground_fd); if (status == RESPONSE_SCRIPT_SUCCEEDED) + { return OPENVPN_PLUGIN_FUNC_SUCCESS; + } if (status == -1) { - warn ("DOWN-ROOT: Error receiving script execution confirmation from background process"); + warn("DOWN-ROOT: Error receiving script execution confirmation from background process"); } } } @@ -419,42 +437,46 @@ openvpn_plugin_func_v1 (openvpn_plugin_handle_t handle, const int type, const ch } OPENVPN_EXPORT void -openvpn_plugin_close_v1 (openvpn_plugin_handle_t handle) +openvpn_plugin_close_v1(openvpn_plugin_handle_t handle) { struct down_root_context *context = (struct down_root_context *) handle; - if (DEBUG (context->verb)) - fprintf (stderr, "DOWN-ROOT: close\n"); + if (DEBUG(context->verb)) + { + fprintf(stderr, "DOWN-ROOT: close\n"); + } if (context->foreground_fd >= 0) { /* tell background process to exit */ - if (send_control (context->foreground_fd, COMMAND_EXIT) == -1) + if (send_control(context->foreground_fd, COMMAND_EXIT) == -1) { - warn ("DOWN-ROOT: Error signalling background process to exit"); + warn("DOWN-ROOT: Error signalling background process to exit"); } /* wait for background process to exit */ if (context->background_pid > 0) - waitpid (context->background_pid, NULL, 0); + { + waitpid(context->background_pid, NULL, 0); + } - close (context->foreground_fd); + close(context->foreground_fd); context->foreground_fd = -1; } - free_context (context); + free_context(context); } OPENVPN_EXPORT void -openvpn_plugin_abort_v1 (openvpn_plugin_handle_t handle) +openvpn_plugin_abort_v1(openvpn_plugin_handle_t handle) { struct down_root_context *context = (struct down_root_context *) handle; if (context && context->foreground_fd >= 0) { /* tell background process to exit */ - send_control (context->foreground_fd, COMMAND_EXIT); - close (context->foreground_fd); + send_control(context->foreground_fd, COMMAND_EXIT); + close(context->foreground_fd); context->foreground_fd = -1; } } @@ -463,20 +485,22 @@ openvpn_plugin_abort_v1 (openvpn_plugin_handle_t handle) * Background process -- runs with privilege. */ static void -down_root_server (const int fd, char * const *argv, char * const *envp, const int verb) +down_root_server(const int fd, char *const *argv, char *const *envp, const int verb) { /* * Do initialization */ - if (DEBUG (verb)) - fprintf (stderr, "DOWN-ROOT: BACKGROUND: INIT command='%s'\n", argv[0]); + if (DEBUG(verb)) + { + fprintf(stderr, "DOWN-ROOT: BACKGROUND: INIT command='%s'\n", argv[0]); + } /* * Tell foreground that we initialized successfully */ - if (send_control (fd, RESPONSE_INIT_SUCCEEDED) == -1) + if (send_control(fd, RESPONSE_INIT_SUCCEEDED) == -1) { - warn ("DOWN-ROOT: BACKGROUND: write error on response socket [1]"); + warn("DOWN-ROOT: BACKGROUND: write error on response socket [1]"); goto done; } @@ -489,59 +513,63 @@ down_root_server (const int fd, char * const *argv, char * const *envp, const in int exit_code = -1; /* get a command from foreground process */ - command_code = recv_control (fd); + command_code = recv_control(fd); - if (DEBUG (verb)) - fprintf (stderr, "DOWN-ROOT: BACKGROUND: received command code: %d\n", command_code); + if (DEBUG(verb)) + { + fprintf(stderr, "DOWN-ROOT: BACKGROUND: received command code: %d\n", command_code); + } switch (command_code) { - case COMMAND_RUN_SCRIPT: - if ( (exit_code = run_script(argv, envp)) == 0 ) /* Succeeded */ - { - if (send_control (fd, RESPONSE_SCRIPT_SUCCEEDED) == -1) + case COMMAND_RUN_SCRIPT: + if ( (exit_code = run_script(argv, envp)) == 0) /* Succeeded */ { - warn ("DOWN-ROOT: BACKGROUND: write error on response socket [2]"); - goto done; + if (send_control(fd, RESPONSE_SCRIPT_SUCCEEDED) == -1) + { + warn("DOWN-ROOT: BACKGROUND: write error on response socket [2]"); + goto done; + } } - } - else /* Failed */ - { - fprintf(stderr, "DOWN-ROOT: BACKGROUND: %s exited with exit code %i\n", argv[0], exit_code); - if (send_control (fd, RESPONSE_SCRIPT_FAILED) == -1) + else /* Failed */ { - warn ("DOWN-ROOT: BACKGROUND: write error on response socket [3]"); - goto done; + fprintf(stderr, "DOWN-ROOT: BACKGROUND: %s exited with exit code %i\n", argv[0], exit_code); + if (send_control(fd, RESPONSE_SCRIPT_FAILED) == -1) + { + warn("DOWN-ROOT: BACKGROUND: write error on response socket [3]"); + goto done; + } } - } - break; + break; - case COMMAND_EXIT: - goto done; + case COMMAND_EXIT: + goto done; - case -1: - warn ("DOWN-ROOT: BACKGROUND: read error on command channel"); - goto done; + case -1: + warn("DOWN-ROOT: BACKGROUND: read error on command channel"); + goto done; - default: - fprintf (stderr, "DOWN-ROOT: BACKGROUND: unknown command code: code=%d, exiting\n", - command_code); - goto done; + default: + fprintf(stderr, "DOWN-ROOT: BACKGROUND: unknown command code: code=%d, exiting\n", + command_code); + goto done; } } done: - if (DEBUG (verb)) - fprintf (stderr, "DOWN-ROOT: BACKGROUND: EXIT\n"); + if (DEBUG(verb)) + { + fprintf(stderr, "DOWN-ROOT: BACKGROUND: EXIT\n"); + } return; } /* -Local variables: -c-file-style: "bsd" -c-basic-offset: 4 -indent-tabs-mode: nil -End: -*/ + * Local variables: + * c-file-style: "bsd" + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/tests/unit_tests/example_test/test.c b/tests/unit_tests/example_test/test.c index 9986898f0b5..d48e5f55f81 100644 --- a/tests/unit_tests/example_test/test.c +++ b/tests/unit_tests/example_test/test.c @@ -6,40 +6,46 @@ #include #include -static int setup(void **state) { - int *answer = malloc(sizeof(int)); +static int +setup(void **state) { + int *answer = malloc(sizeof(int)); - *answer=42; - *state=answer; + *answer = 42; + *state = answer; - return 0; + return 0; } -static int teardown(void **state) { - free(*state); +static int +teardown(void **state) { + free(*state); - return 0; + return 0; } -static void null_test_success(void **state) { +static void +null_test_success(void **state) { (void) state; } -static void int_test_success(void **state) { - int *answer = *state; - assert_int_equal(*answer, 42); +static void +int_test_success(void **state) { + int *answer = *state; + assert_int_equal(*answer, 42); } -static void failing_test(void **state) { - // This tests fails to test that make check fails - assert_int_equal(0, 42); +static void +failing_test(void **state) { + /* This tests fails to test that make check fails */ + assert_int_equal(0, 42); } -int main(void) { +int +main(void) { const struct CMUnitTest tests[] = { cmocka_unit_test(null_test_success), cmocka_unit_test_setup_teardown(int_test_success, setup, teardown), -// cmocka_unit_test(failing_test), +/* cmocka_unit_test(failing_test), */ }; return cmocka_run_group_tests_name("success_test", tests, NULL, NULL); diff --git a/tests/unit_tests/example_test/test2.c b/tests/unit_tests/example_test/test2.c index f99da9e6a97..b5d4fa60fbb 100644 --- a/tests/unit_tests/example_test/test2.c +++ b/tests/unit_tests/example_test/test2.c @@ -7,12 +7,14 @@ #include -static void test_true(void **state) { +static void +test_true(void **state) { (void) state; } -int main(void) { +int +main(void) { const struct CMUnitTest tests[] = { cmocka_unit_test(test_true), }; diff --git a/tests/unit_tests/openvpn/mock_msg.c b/tests/unit_tests/openvpn/mock_msg.c index 54b60176167..b6f1a46ec9b 100644 --- a/tests/unit_tests/openvpn/mock_msg.c +++ b/tests/unit_tests/openvpn/mock_msg.c @@ -39,39 +39,46 @@ unsigned int x_debug_level = 0; /* Default to (almost) no debugging output */ bool fatal_error_triggered = false; -void mock_set_debug_level(int level) +void +mock_set_debug_level(int level) { - x_debug_level = level; + x_debug_level = level; } -void x_msg_va (const unsigned int flags, const char *format, - va_list arglist) +void +x_msg_va(const unsigned int flags, const char *format, + va_list arglist) { - if (flags & M_FATAL) + if (flags & M_FATAL) { - fatal_error_triggered = true; - printf("FATAL ERROR:"); + fatal_error_triggered = true; + printf("FATAL ERROR:"); } - vprintf(format, arglist); - printf("\n"); + vprintf(format, arglist); + printf("\n"); } -void x_msg (const unsigned int flags, const char *format, ...) +void +x_msg(const unsigned int flags, const char *format, ...) { - va_list arglist; - va_start (arglist, format); - x_msg_va (flags, format, arglist); - va_end (arglist); + va_list arglist; + va_start(arglist, format); + x_msg_va(flags, format, arglist); + va_end(arglist); } void -assert_failed (const char *filename, int line, const char *condition) +assert_failed(const char *filename, int line, const char *condition) { - if (condition) - printf ("Assertion failed at %s:%d (%s)", filename, line, condition); - else - printf ("Assertion failed at %s:%d", filename, line); - exit (1); + if (condition) + { + printf("Assertion failed at %s:%d (%s)", filename, line, condition); + } + else + { + printf("Assertion failed at %s:%d", filename, line); + } + exit(1); } /* @@ -79,14 +86,14 @@ assert_failed (const char *filename, int line, const char *condition) * to allocate memory as part of its operation. */ void -out_of_memory (void) +out_of_memory(void) { - fprintf (stderr, "Out of Memory\n"); - exit (1); + fprintf(stderr, "Out of Memory\n"); + exit(1); } bool -dont_mute (unsigned int flags) +dont_mute(unsigned int flags) { - return true; + return true; } diff --git a/tests/unit_tests/openvpn/test_argv.c b/tests/unit_tests/openvpn/test_argv.c index 4d17557485c..8c90eb9c32f 100644 --- a/tests/unit_tests/openvpn/test_argv.c +++ b/tests/unit_tests/openvpn/test_argv.c @@ -18,17 +18,17 @@ * which makes things difficult beyond any recognition */ size_t -adjust_power_of_2 (size_t u) +adjust_power_of_2(size_t u) { - size_t ret = 1; + size_t ret = 1; - while (ret < u) + while (ret < u) { - ret <<= 1; - assert (ret > 0); + ret <<= 1; + assert(ret > 0); } - return ret; + return ret; } /* Defines for use in the tests and the mock parse_line() */ @@ -39,156 +39,160 @@ adjust_power_of_2 (size_t u) #define SCRIPT_CMD "\"" PATH1 PATH2 "\"" PARAM1 "\"" PARAM2 "\"" int -__wrap_parse_line (const char *line, char **p, const int n, const char *file, - const int line_num, int msglevel, struct gc_arena *gc) +__wrap_parse_line(const char *line, char **p, const int n, const char *file, + const int line_num, int msglevel, struct gc_arena *gc) { - p[0] = PATH1 PATH2; - p[1] = PARAM1; - p[2] = PARAM2; - return 3; + p[0] = PATH1 PATH2; + p[1] = PARAM1; + p[2] = PARAM2; + return 3; } static void -argv_printf__multiple_spaces_in_format__parsed_as_one (void **state) +argv_printf__multiple_spaces_in_format__parsed_as_one(void **state) { - struct argv a = argv_new (); + struct argv a = argv_new(); - argv_printf (&a, " %s %s %d ", PATH1, PATH2, 42); - assert_int_equal (a.argc, 3); + argv_printf(&a, " %s %s %d ", PATH1, PATH2, 42); + assert_int_equal(a.argc, 3); - argv_reset (&a); + argv_reset(&a); } static void -argv_printf_cat__multiple_spaces_in_format__parsed_as_one (void **state) +argv_printf_cat__multiple_spaces_in_format__parsed_as_one(void **state) { - struct argv a = argv_new (); + struct argv a = argv_new(); - argv_printf (&a, "%s ", PATH1); - argv_printf_cat (&a, " %s %s", PATH2, PARAM1); - assert_int_equal (a.argc, 3); + argv_printf(&a, "%s ", PATH1); + argv_printf_cat(&a, " %s %s", PATH2, PARAM1); + assert_int_equal(a.argc, 3); - argv_reset (&a); + argv_reset(&a); } static void -argv_printf__combined_path_with_spaces__argc_correct (void **state) +argv_printf__combined_path_with_spaces__argc_correct(void **state) { - struct argv a = argv_new (); + struct argv a = argv_new(); - argv_printf (&a, "%s%sc", PATH1, PATH2); - assert_int_equal (a.argc, 1); + argv_printf(&a, "%s%sc", PATH1, PATH2); + assert_int_equal(a.argc, 1); - argv_printf (&a, "%s%sc %d", PATH1, PATH2, 42); - assert_int_equal (a.argc, 2); + argv_printf(&a, "%s%sc %d", PATH1, PATH2, 42); + assert_int_equal(a.argc, 2); - argv_printf (&a, "foo %s%sc %s x y", PATH2, PATH1, "foo"); - assert_int_equal (a.argc, 5); + argv_printf(&a, "foo %s%sc %s x y", PATH2, PATH1, "foo"); + assert_int_equal(a.argc, 5); - argv_reset (&a); + argv_reset(&a); } static void -argv_parse_cmd__command_string__argc_correct (void **state) +argv_parse_cmd__command_string__argc_correct(void **state) { - struct argv a = argv_new (); + struct argv a = argv_new(); - argv_parse_cmd (&a, SCRIPT_CMD); - assert_int_equal (a.argc, 3); + argv_parse_cmd(&a, SCRIPT_CMD); + assert_int_equal(a.argc, 3); - argv_reset (&a); + argv_reset(&a); } static void -argv_parse_cmd__command_and_extra_options__argc_correct (void **state) +argv_parse_cmd__command_and_extra_options__argc_correct(void **state) { - struct argv a = argv_new (); + struct argv a = argv_new(); - argv_parse_cmd (&a, SCRIPT_CMD); - argv_printf_cat (&a, "bar baz %d %s", 42, PATH1); - assert_int_equal (a.argc, 7); + argv_parse_cmd(&a, SCRIPT_CMD); + argv_printf_cat(&a, "bar baz %d %s", 42, PATH1); + assert_int_equal(a.argc, 7); - argv_reset (&a); + argv_reset(&a); } static void -argv_printf_cat__used_twice__argc_correct (void **state) +argv_printf_cat__used_twice__argc_correct(void **state) { - struct argv a = argv_new (); + struct argv a = argv_new(); - argv_printf (&a, "%s %s %s", PATH1, PATH2, PARAM1); - argv_printf_cat (&a, "%s", PARAM2); - argv_printf_cat (&a, "foo"); - assert_int_equal (a.argc, 5); + argv_printf(&a, "%s %s %s", PATH1, PATH2, PARAM1); + argv_printf_cat(&a, "%s", PARAM2); + argv_printf_cat(&a, "foo"); + assert_int_equal(a.argc, 5); - argv_reset (&a); + argv_reset(&a); } static void -argv_str__multiple_argv__correct_output (void **state) +argv_str__multiple_argv__correct_output(void **state) { - struct argv a = argv_new (); - struct gc_arena gc = gc_new (); - const char *output; - - argv_printf (&a, "%s%sc", PATH1, PATH2); - argv_printf_cat (&a, "%s", PARAM1); - argv_printf_cat (&a, "%s", PARAM2); - output = argv_str (&a, &gc, PA_BRACKET); - assert_string_equal (output, "[" PATH1 PATH2 "] [" PARAM1 "] [" PARAM2 "]"); - - argv_reset (&a); - gc_free (&gc); + struct argv a = argv_new(); + struct gc_arena gc = gc_new(); + const char *output; + + argv_printf(&a, "%s%sc", PATH1, PATH2); + argv_printf_cat(&a, "%s", PARAM1); + argv_printf_cat(&a, "%s", PARAM2); + output = argv_str(&a, &gc, PA_BRACKET); + assert_string_equal(output, "[" PATH1 PATH2 "] [" PARAM1 "] [" PARAM2 "]"); + + argv_reset(&a); + gc_free(&gc); } static void -argv_insert_head__empty_argv__head_only (void **state) +argv_insert_head__empty_argv__head_only(void **state) { - struct argv a = argv_new (); - struct argv b; + struct argv a = argv_new(); + struct argv b; - b = argv_insert_head (&a, PATH1); - assert_int_equal (b.argc, 1); - assert_string_equal (b.argv[0], PATH1); - argv_reset (&b); + b = argv_insert_head(&a, PATH1); + assert_int_equal(b.argc, 1); + assert_string_equal(b.argv[0], PATH1); + argv_reset(&b); - argv_reset (&a); + argv_reset(&a); } static void -argv_insert_head__non_empty_argv__head_added (void **state) +argv_insert_head__non_empty_argv__head_added(void **state) { - struct argv a = argv_new (); - struct argv b; - int i; - - argv_printf (&a, "%s", PATH2); - b = argv_insert_head (&a, PATH1); - assert_int_equal (b.argc, a.argc + 1); - for (i = 0; i < b.argc; i++) { - if (i == 0) - assert_string_equal (b.argv[i], PATH1); - else - assert_string_equal (b.argv[i], a.argv[i - 1]); - } - argv_reset (&b); - - argv_reset (&a); + struct argv a = argv_new(); + struct argv b; + int i; + + argv_printf(&a, "%s", PATH2); + b = argv_insert_head(&a, PATH1); + assert_int_equal(b.argc, a.argc + 1); + for (i = 0; i < b.argc; i++) { + if (i == 0) + { + assert_string_equal(b.argv[i], PATH1); + } + else + { + assert_string_equal(b.argv[i], a.argv[i - 1]); + } + } + argv_reset(&b); + + argv_reset(&a); } int main(void) { - const struct CMUnitTest tests[] = { - cmocka_unit_test (argv_printf__multiple_spaces_in_format__parsed_as_one), - cmocka_unit_test (argv_printf_cat__multiple_spaces_in_format__parsed_as_one), - cmocka_unit_test (argv_printf__combined_path_with_spaces__argc_correct), - cmocka_unit_test (argv_parse_cmd__command_string__argc_correct), - cmocka_unit_test (argv_parse_cmd__command_and_extra_options__argc_correct), - cmocka_unit_test (argv_printf_cat__used_twice__argc_correct), - cmocka_unit_test (argv_str__multiple_argv__correct_output), - cmocka_unit_test (argv_insert_head__non_empty_argv__head_added), - }; - - return cmocka_run_group_tests_name ("argv", tests, NULL, NULL); + const struct CMUnitTest tests[] = { + cmocka_unit_test(argv_printf__multiple_spaces_in_format__parsed_as_one), + cmocka_unit_test(argv_printf_cat__multiple_spaces_in_format__parsed_as_one), + cmocka_unit_test(argv_printf__combined_path_with_spaces__argc_correct), + cmocka_unit_test(argv_parse_cmd__command_string__argc_correct), + cmocka_unit_test(argv_parse_cmd__command_and_extra_options__argc_correct), + cmocka_unit_test(argv_printf_cat__used_twice__argc_correct), + cmocka_unit_test(argv_str__multiple_argv__correct_output), + cmocka_unit_test(argv_insert_head__non_empty_argv__head_added), + }; + + return cmocka_run_group_tests_name("argv", tests, NULL, NULL); } diff --git a/tests/unit_tests/openvpn/test_tls_crypt.c b/tests/unit_tests/openvpn/test_tls_crypt.c index 473a232f145..3650aa869e8 100644 --- a/tests/unit_tests/openvpn/test_tls_crypt.c +++ b/tests/unit_tests/openvpn/test_tls_crypt.c @@ -44,32 +44,33 @@ #include "mock_msg.h" -#define TESTBUF_SIZE 128 +#define TESTBUF_SIZE 128 const char plaintext_short[1]; struct test_context { - struct crypto_options co; - struct key_type kt; - struct buffer source; - struct buffer ciphertext; - struct buffer unwrapped; + struct crypto_options co; + struct key_type kt; + struct buffer source; + struct buffer ciphertext; + struct buffer unwrapped; }; -static int setup(void **state) { +static int +setup(void **state) { struct test_context *ctx = calloc(1, sizeof(*ctx)); - ctx->kt.cipher = cipher_kt_get ("AES-256-CTR"); - ctx->kt.cipher_length = cipher_kt_key_size (ctx->kt.cipher); - ctx->kt.digest = md_kt_get ("SHA256"); - ctx->kt.hmac_length = md_kt_size (ctx->kt.digest); + ctx->kt.cipher = cipher_kt_get("AES-256-CTR"); + ctx->kt.cipher_length = cipher_kt_key_size(ctx->kt.cipher); + ctx->kt.digest = md_kt_get("SHA256"); + ctx->kt.hmac_length = md_kt_size(ctx->kt.digest); struct key key = { 0 }; - init_key_ctx (&ctx->co.key_ctx_bi.encrypt, &key, &ctx->kt, true, "TEST"); - init_key_ctx (&ctx->co.key_ctx_bi.decrypt, &key, &ctx->kt, false, "TEST"); + init_key_ctx(&ctx->co.key_ctx_bi.encrypt, &key, &ctx->kt, true, "TEST"); + init_key_ctx(&ctx->co.key_ctx_bi.decrypt, &key, &ctx->kt, false, "TEST"); - packet_id_init (&ctx->co.packet_id, 0, 0, "test", 0); + packet_id_init(&ctx->co.packet_id, 0, 0, "test", 0); ctx->source = alloc_buf(TESTBUF_SIZE); ctx->ciphertext = alloc_buf(TESTBUF_SIZE); @@ -86,14 +87,15 @@ static int setup(void **state) { return 0; } -static int teardown(void **state) { +static int +teardown(void **state) { struct test_context *ctx = (struct test_context *) *state; - free_buf (&ctx->source); - free_buf (&ctx->ciphertext); - free_buf (&ctx->unwrapped); + free_buf(&ctx->source); + free_buf(&ctx->ciphertext); + free_buf(&ctx->unwrapped); - free_key_ctx_bi (&ctx->co.key_ctx_bi); + free_key_ctx_bi(&ctx->co.key_ctx_bi); free(ctx); @@ -103,92 +105,98 @@ static int teardown(void **state) { /** * Check that short messages are successfully wrapped-and-unwrapped. */ -static void tls_crypt_loopback(void **state) { - struct test_context *ctx = (struct test_context *) *state; - - assert_true (tls_crypt_wrap (&ctx->source, &ctx->ciphertext, &ctx->co)); - assert_true (BLEN(&ctx->source) < BLEN(&ctx->ciphertext)); - assert_true (tls_crypt_unwrap (&ctx->ciphertext, &ctx->unwrapped, &ctx->co)); - assert_int_equal(BLEN(&ctx->source), BLEN(&ctx->unwrapped)); - assert_memory_equal(BPTR(&ctx->source), BPTR(&ctx->unwrapped), - BLEN(&ctx->source)); +static void +tls_crypt_loopback(void **state) { + struct test_context *ctx = (struct test_context *) *state; + + assert_true(tls_crypt_wrap(&ctx->source, &ctx->ciphertext, &ctx->co)); + assert_true(BLEN(&ctx->source) < BLEN(&ctx->ciphertext)); + assert_true(tls_crypt_unwrap(&ctx->ciphertext, &ctx->unwrapped, &ctx->co)); + assert_int_equal(BLEN(&ctx->source), BLEN(&ctx->unwrapped)); + assert_memory_equal(BPTR(&ctx->source), BPTR(&ctx->unwrapped), + BLEN(&ctx->source)); } /** * Check that zero-byte messages are successfully wrapped-and-unwrapped. */ -static void tls_crypt_loopback_zero_len(void **state) { - struct test_context *ctx = (struct test_context *) *state; +static void +tls_crypt_loopback_zero_len(void **state) { + struct test_context *ctx = (struct test_context *) *state; - buf_clear(&ctx->source); + buf_clear(&ctx->source); - assert_true (tls_crypt_wrap (&ctx->source, &ctx->ciphertext, &ctx->co)); - assert_true (BLEN(&ctx->source) < BLEN(&ctx->ciphertext)); - assert_true (tls_crypt_unwrap (&ctx->ciphertext, &ctx->unwrapped, &ctx->co)); - assert_int_equal(BLEN(&ctx->source), BLEN(&ctx->unwrapped)); - assert_memory_equal(BPTR(&ctx->source), BPTR(&ctx->unwrapped), - BLEN(&ctx->source)); + assert_true(tls_crypt_wrap(&ctx->source, &ctx->ciphertext, &ctx->co)); + assert_true(BLEN(&ctx->source) < BLEN(&ctx->ciphertext)); + assert_true(tls_crypt_unwrap(&ctx->ciphertext, &ctx->unwrapped, &ctx->co)); + assert_int_equal(BLEN(&ctx->source), BLEN(&ctx->unwrapped)); + assert_memory_equal(BPTR(&ctx->source), BPTR(&ctx->unwrapped), + BLEN(&ctx->source)); } /** * Check that max-length messages are successfully wrapped-and-unwrapped. */ -static void tls_crypt_loopback_max_len(void **state) { - struct test_context *ctx = (struct test_context *) *state; - - buf_clear(&ctx->source); - assert_non_null (buf_write_alloc (&ctx->source, - TESTBUF_SIZE - BLEN (&ctx->ciphertext) - tls_crypt_buf_overhead())); - - assert_true (tls_crypt_wrap (&ctx->source, &ctx->ciphertext, &ctx->co)); - assert_true (BLEN(&ctx->source) < BLEN(&ctx->ciphertext)); - assert_true (tls_crypt_unwrap (&ctx->ciphertext, &ctx->unwrapped, &ctx->co)); - assert_int_equal(BLEN(&ctx->source), BLEN(&ctx->unwrapped)); - assert_memory_equal(BPTR(&ctx->source), BPTR(&ctx->unwrapped), - BLEN(&ctx->source)); +static void +tls_crypt_loopback_max_len(void **state) { + struct test_context *ctx = (struct test_context *) *state; + + buf_clear(&ctx->source); + assert_non_null(buf_write_alloc(&ctx->source, + TESTBUF_SIZE - BLEN(&ctx->ciphertext) - tls_crypt_buf_overhead())); + + assert_true(tls_crypt_wrap(&ctx->source, &ctx->ciphertext, &ctx->co)); + assert_true(BLEN(&ctx->source) < BLEN(&ctx->ciphertext)); + assert_true(tls_crypt_unwrap(&ctx->ciphertext, &ctx->unwrapped, &ctx->co)); + assert_int_equal(BLEN(&ctx->source), BLEN(&ctx->unwrapped)); + assert_memory_equal(BPTR(&ctx->source), BPTR(&ctx->unwrapped), + BLEN(&ctx->source)); } /** * Check that too-long messages are gracefully rejected. */ -static void tls_crypt_fail_msg_too_long(void **state) { - struct test_context *ctx = (struct test_context *) *state; +static void +tls_crypt_fail_msg_too_long(void **state) { + struct test_context *ctx = (struct test_context *) *state; - buf_clear(&ctx->source); - assert_non_null (buf_write_alloc (&ctx->source, - TESTBUF_SIZE - BLEN (&ctx->ciphertext) - tls_crypt_buf_overhead() + 1)); - assert_false (tls_crypt_wrap (&ctx->source, &ctx->ciphertext, &ctx->co)); + buf_clear(&ctx->source); + assert_non_null(buf_write_alloc(&ctx->source, + TESTBUF_SIZE - BLEN(&ctx->ciphertext) - tls_crypt_buf_overhead() + 1)); + assert_false(tls_crypt_wrap(&ctx->source, &ctx->ciphertext, &ctx->co)); } /** * Check that packets that were wrapped (or unwrapped) with a different key * are not accepted. */ -static void tls_crypt_fail_invalid_key(void **state) { - struct test_context *ctx = (struct test_context *) *state; +static void +tls_crypt_fail_invalid_key(void **state) { + struct test_context *ctx = (struct test_context *) *state; - /* Change decrypt key */ - struct key key = { { 1 } }; - free_key_ctx (&ctx->co.key_ctx_bi.decrypt); - init_key_ctx (&ctx->co.key_ctx_bi.decrypt, &key, &ctx->kt, false, "TEST"); + /* Change decrypt key */ + struct key key = { { 1 } }; + free_key_ctx(&ctx->co.key_ctx_bi.decrypt); + init_key_ctx(&ctx->co.key_ctx_bi.decrypt, &key, &ctx->kt, false, "TEST"); - assert_true (tls_crypt_wrap (&ctx->source, &ctx->ciphertext, &ctx->co)); - assert_true (BLEN(&ctx->source) < BLEN(&ctx->ciphertext)); - assert_false (tls_crypt_unwrap (&ctx->ciphertext, &ctx->unwrapped, &ctx->co)); + assert_true(tls_crypt_wrap(&ctx->source, &ctx->ciphertext, &ctx->co)); + assert_true(BLEN(&ctx->source) < BLEN(&ctx->ciphertext)); + assert_false(tls_crypt_unwrap(&ctx->ciphertext, &ctx->unwrapped, &ctx->co)); } /** * Check that replayed packets are not accepted. */ -static void tls_crypt_fail_replay(void **state) { - struct test_context *ctx = (struct test_context *) *state; - - assert_true (tls_crypt_wrap (&ctx->source, &ctx->ciphertext, &ctx->co)); - assert_true (BLEN(&ctx->source) < BLEN(&ctx->ciphertext)); - struct buffer tmp = ctx->ciphertext; - assert_true (tls_crypt_unwrap (&tmp, &ctx->unwrapped, &ctx->co)); - buf_clear (&ctx->unwrapped); - assert_false (tls_crypt_unwrap (&ctx->ciphertext, &ctx->unwrapped, &ctx->co)); +static void +tls_crypt_fail_replay(void **state) { + struct test_context *ctx = (struct test_context *) *state; + + assert_true(tls_crypt_wrap(&ctx->source, &ctx->ciphertext, &ctx->co)); + assert_true(BLEN(&ctx->source) < BLEN(&ctx->ciphertext)); + struct buffer tmp = ctx->ciphertext; + assert_true(tls_crypt_unwrap(&tmp, &ctx->unwrapped, &ctx->co)); + buf_clear(&ctx->unwrapped); + assert_false(tls_crypt_unwrap(&ctx->ciphertext, &ctx->unwrapped, &ctx->co)); } /** @@ -196,34 +204,36 @@ static void tls_crypt_fail_replay(void **state) { * is used for the first control channel packet that arrives, because we don't * know the packet ID yet. */ -static void tls_crypt_ignore_replay(void **state) { - struct test_context *ctx = (struct test_context *) *state; +static void +tls_crypt_ignore_replay(void **state) { + struct test_context *ctx = (struct test_context *) *state; - ctx->co.flags |= CO_IGNORE_PACKET_ID; + ctx->co.flags |= CO_IGNORE_PACKET_ID; - assert_true (tls_crypt_wrap (&ctx->source, &ctx->ciphertext, &ctx->co)); - assert_true (BLEN(&ctx->source) < BLEN(&ctx->ciphertext)); - struct buffer tmp = ctx->ciphertext; - assert_true (tls_crypt_unwrap (&tmp, &ctx->unwrapped, &ctx->co)); - buf_clear (&ctx->unwrapped); - assert_true (tls_crypt_unwrap (&ctx->ciphertext, &ctx->unwrapped, &ctx->co)); + assert_true(tls_crypt_wrap(&ctx->source, &ctx->ciphertext, &ctx->co)); + assert_true(BLEN(&ctx->source) < BLEN(&ctx->ciphertext)); + struct buffer tmp = ctx->ciphertext; + assert_true(tls_crypt_unwrap(&tmp, &ctx->unwrapped, &ctx->co)); + buf_clear(&ctx->unwrapped); + assert_true(tls_crypt_unwrap(&ctx->ciphertext, &ctx->unwrapped, &ctx->co)); } -int main(void) { +int +main(void) { const struct CMUnitTest tests[] = { - cmocka_unit_test_setup_teardown(tls_crypt_loopback, setup, teardown), - cmocka_unit_test_setup_teardown(tls_crypt_loopback_zero_len, - setup, teardown), - cmocka_unit_test_setup_teardown(tls_crypt_loopback_max_len, - setup, teardown), - cmocka_unit_test_setup_teardown(tls_crypt_fail_msg_too_long, - setup, teardown), - cmocka_unit_test_setup_teardown(tls_crypt_fail_invalid_key, - setup, teardown), - cmocka_unit_test_setup_teardown(tls_crypt_fail_replay, - setup, teardown), - cmocka_unit_test_setup_teardown(tls_crypt_ignore_replay, - setup, teardown), + cmocka_unit_test_setup_teardown(tls_crypt_loopback, setup, teardown), + cmocka_unit_test_setup_teardown(tls_crypt_loopback_zero_len, + setup, teardown), + cmocka_unit_test_setup_teardown(tls_crypt_loopback_max_len, + setup, teardown), + cmocka_unit_test_setup_teardown(tls_crypt_fail_msg_too_long, + setup, teardown), + cmocka_unit_test_setup_teardown(tls_crypt_fail_invalid_key, + setup, teardown), + cmocka_unit_test_setup_teardown(tls_crypt_fail_replay, + setup, teardown), + cmocka_unit_test_setup_teardown(tls_crypt_ignore_replay, + setup, teardown), }; #if defined(ENABLE_CRYPTO_OPENSSL) diff --git a/tests/unit_tests/plugins/auth-pam/test_search_and_replace.c b/tests/unit_tests/plugins/auth-pam/test_search_and_replace.c index 70e472f32fc..e80bffbcd1d 100644 --- a/tests/unit_tests/plugins/auth-pam/test_search_and_replace.c +++ b/tests/unit_tests/plugins/auth-pam/test_search_and_replace.c @@ -8,63 +8,70 @@ #include "utils.h" -static void pass_any_null_param__returns_null() { +static void +pass_any_null_param__returns_null() { - char DUMMY[] = "DUMMY"; + char DUMMY[] = "DUMMY"; - assert_null(searchandreplace(NULL,DUMMY,DUMMY)); - assert_null(searchandreplace(DUMMY,NULL,DUMMY)); - assert_null(searchandreplace(DUMMY,DUMMY,NULL)); + assert_null(searchandreplace(NULL,DUMMY,DUMMY)); + assert_null(searchandreplace(DUMMY,NULL,DUMMY)); + assert_null(searchandreplace(DUMMY,DUMMY,NULL)); } -static void pass_any_empty_string__returns_null() { +static void +pass_any_empty_string__returns_null() { - char DUMMY[] = "DUMMY"; - char EMPTY[] = ""; + char DUMMY[] = "DUMMY"; + char EMPTY[] = ""; - assert_null(searchandreplace(EMPTY,DUMMY,DUMMY)); - assert_null(searchandreplace(DUMMY,EMPTY,DUMMY)); - assert_null(searchandreplace(DUMMY,DUMMY,EMPTY)); + assert_null(searchandreplace(EMPTY,DUMMY,DUMMY)); + assert_null(searchandreplace(DUMMY,EMPTY,DUMMY)); + assert_null(searchandreplace(DUMMY,DUMMY,EMPTY)); } -static void replace_single_char__one_time__match_is_replaced() { - char *replaced = searchandreplace("X","X","Y"); +static void +replace_single_char__one_time__match_is_replaced() { + char *replaced = searchandreplace("X","X","Y"); - assert_non_null(replaced); - assert_string_equal("Y", replaced); + assert_non_null(replaced); + assert_string_equal("Y", replaced); - free(replaced); + free(replaced); } -static void replace_single_char__multiple_times__match_all_matches_are_replaced() { - char *replaced = searchandreplace("XaX","X","Y"); +static void +replace_single_char__multiple_times__match_all_matches_are_replaced() { + char *replaced = searchandreplace("XaX","X","Y"); - assert_non_null(replaced); - assert_string_equal ("YaY", replaced); + assert_non_null(replaced); + assert_string_equal("YaY", replaced); - free(replaced); + free(replaced); } -static void replace_longer_text__multiple_times__match_all_matches_are_replaced() { - char *replaced = searchandreplace("XXaXX","XX","YY"); +static void +replace_longer_text__multiple_times__match_all_matches_are_replaced() { + char *replaced = searchandreplace("XXaXX","XX","YY"); - assert_non_null(replaced); - assert_string_equal ("YYaYY", replaced); + assert_non_null(replaced); + assert_string_equal("YYaYY", replaced); - free(replaced); + free(replaced); } -static void pattern_not_found__returns_original() { - char *replaced = searchandreplace("abc","X","Y"); +static void +pattern_not_found__returns_original() { + char *replaced = searchandreplace("abc","X","Y"); - assert_non_null(replaced); - assert_string_equal ("abc", replaced); + assert_non_null(replaced); + assert_string_equal("abc", replaced); - free(replaced); + free(replaced); } -int main(void) { +int +main(void) { const struct CMUnitTest tests[] = { cmocka_unit_test(pass_any_null_param__returns_null), cmocka_unit_test(pass_any_empty_string__returns_null), From ec4dff3bbdcc9fedf7844701dc5aa2679d503667 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Thu, 15 Dec 2016 22:46:06 +0100 Subject: [PATCH 447/643] Don't reopen tun if cipher changes When the pulled options change, OpenVPN will attempt to reopen the tun device. That might fail if the process has already dropper privileges, and is not needed unless the tun MTU is changed. This patch therefore ignores the cipher value for the digest if a fixed tun-mtu is used. Additionally, this patch changes the md_ctx_update() call to include the trailing zero byte of each option, to make sure that parsing "foo,bar" results in a different hash than "foobar". (Sorry for not catching that during the review...) The unit tests are a bit lame, but it secretly serves as a way to lower the bar for adding more buffer.c unit tests. Trac: #761 Signed-off-by: Steffan Karger Acked-by: David Sommerseth Message-Id: <1481838366-32335-1-git-send-email-steffan@karger.me> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13579.html Signed-off-by: David Sommerseth --- src/openvpn/buffer.h | 8 ++++ src/openvpn/push.c | 15 +++++-- tests/unit_tests/openvpn/Makefile.am | 8 +++- tests/unit_tests/openvpn/test_buffer.c | 56 ++++++++++++++++++++++++++ 4 files changed, 82 insertions(+), 5 deletions(-) create mode 100644 tests/unit_tests/openvpn/test_buffer.c diff --git a/src/openvpn/buffer.h b/src/openvpn/buffer.h index 6bd5e206c51..a1a130c9b3f 100644 --- a/src/openvpn/buffer.h +++ b/src/openvpn/buffer.h @@ -923,6 +923,14 @@ const char *string_mod_const(const char *str, void string_replace_leading(char *str, const char match, const char replace); +/** Return true iff str starts with prefix */ +static inline bool +strprefix(const char *str, const char *prefix) +{ + return 0 == strncmp(str, prefix, strlen(prefix)); +} + + #ifdef CHARACTER_CLASS_DEBUG void character_class_debug(void); diff --git a/src/openvpn/push.c b/src/openvpn/push.c index 34c65c49413..b6e12e1f4a6 100644 --- a/src/openvpn/push.c +++ b/src/openvpn/push.c @@ -677,17 +677,23 @@ process_incoming_push_request(struct context *c) #endif /* if P2MP_SERVER */ static void -push_update_digest(md_ctx_t *ctx, struct buffer *buf) +push_update_digest(md_ctx_t *ctx, struct buffer *buf, const struct options *opt) { char line[OPTION_PARM_SIZE]; while (buf_parse(buf, ',', line, sizeof(line))) { /* peer-id might change on restart and this should not trigger reopening tun */ - if (strstr(line, "peer-id ") != line) + if (strprefix(line, "peer-id ")) { - md_ctx_update(ctx, (const uint8_t *) line, strlen(line)); + continue; + } + /* tun reopen only needed if cipher change can change tun MTU */ + if (strprefix(line, "cipher ") && !opt->ce.tun_mtu_defined) + { + continue; } } + md_ctx_update(ctx, (const uint8_t *) line, strlen(line)+1); } int @@ -730,7 +736,8 @@ process_incoming_push_msg(struct context *c, option_types_found, c->c2.es)) { - push_update_digest(&c->c2.pulled_options_state, &buf_orig); + push_update_digest(&c->c2.pulled_options_state, &buf_orig, + &c->options); switch (c->options.push_continuation) { case 0: diff --git a/tests/unit_tests/openvpn/Makefile.am b/tests/unit_tests/openvpn/Makefile.am index 632ff587eff..fafe6b27431 100644 --- a/tests/unit_tests/openvpn/Makefile.am +++ b/tests/unit_tests/openvpn/Makefile.am @@ -1,6 +1,6 @@ AUTOMAKE_OPTIONS = foreign -check_PROGRAMS = argv_testdriver +check_PROGRAMS = argv_testdriver buffer_testdriver if ENABLE_CRYPTO check_PROGRAMS += tls_crypt_testdriver @@ -21,6 +21,12 @@ argv_testdriver_SOURCES = test_argv.c mock_msg.c \ $(openvpn_srcdir)/buffer.c \ $(openvpn_srcdir)/argv.c +buffer_testdriver_CFLAGS = @TEST_CFLAGS@ -I$(openvpn_srcdir) -I$(compat_srcdir) +buffer_testdriver_LDFLAGS = @TEST_LDFLAGS@ -L$(openvpn_srcdir) -Wl,--wrap=parse_line +buffer_testdriver_SOURCES = test_buffer.c mock_msg.c \ + $(openvpn_srcdir)/buffer.c \ + $(openvpn_srcdir)/platform.c + tls_crypt_testdriver_CFLAGS = @TEST_CFLAGS@ \ -I$(openvpn_includedir) -I$(compat_srcdir) -I$(openvpn_srcdir) \ $(OPTIONAL_CRYPTO_CFLAGS) diff --git a/tests/unit_tests/openvpn/test_buffer.c b/tests/unit_tests/openvpn/test_buffer.c new file mode 100644 index 00000000000..5d254375bea --- /dev/null +++ b/tests/unit_tests/openvpn/test_buffer.c @@ -0,0 +1,56 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2016 Fox Crypto B.V. + * + * 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 + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#elif defined(_MSC_VER) +#include "config-msvc.h" +#endif + +#include "syshead.h" + +#include +#include + +#include "buffer.h" + +static void +buffer_strprefix(void **state) +{ + assert_true(strprefix("123456", "123456")); + assert_true(strprefix("123456", "123")); + assert_true(strprefix("123456", "")); + assert_false(strprefix("123456", "456")); + assert_false(strprefix("12", "123")); +} + +int +main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test(buffer_strprefix), + }; + + return cmocka_run_group_tests_name("buffer", tests, NULL, NULL); +} From 5d4cabff18718981a66ab9066b49297e42cb22b4 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Fri, 16 Dec 2016 11:25:07 +0100 Subject: [PATCH 448/643] auth-gen-token: Hardening memory cleanup on auth-token failuers Further improve the memory management when a clients --auth-token fails the server side token authentication enabled via --auth-gen-token. v2 - Add ASSERT() if base64 encoding of token fails v3 - Use proper boolean logic in ASSERT() v4 - Rebase against The Great Reformatting Signed-off-by: David Sommerseth Acked-by: Steffan Karger Message-Id: <1481883907-26413-1-git-send-email-davids@openvpn.net> URL: http://www.mail-archive.com/search?l=mid&q=1481883907-26413-1-git-send-email-davids@openvpn.net --- src/openvpn/ssl_verify.c | 46 +++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/src/openvpn/ssl_verify.c b/src/openvpn/ssl_verify.c index 54a34166210..e90120291c9 100644 --- a/src/openvpn/ssl_verify.c +++ b/src/openvpn/ssl_verify.c @@ -1213,6 +1213,21 @@ verify_user_pass_management(struct tls_session *session, const struct user_pass } #endif /* ifdef MANAGEMENT_DEF_AUTH */ +/** + * Wipes the authentication token out of the memory, frees and cleans up related buffers and flags + * + * @param multi Pointer to a multi object holding the auth_token variables + */ +static void +wipe_auth_token(struct tls_multi *multi) +{ + secure_memzero(multi->auth_token, AUTH_TOKEN_SIZE); + free(multi->auth_token); + multi->auth_token = NULL; + multi->auth_token_sent = false; +} + + /* * Main username/password verification entry point */ @@ -1264,6 +1279,7 @@ verify_user_pass(struct user_pass *up, struct tls_multi *multi, /* Ensure that the username has not changed */ if (!tls_lock_username(multi, up->username)) { + wipe_auth_token(multi); ks->authenticated = false; goto done; } @@ -1275,6 +1291,7 @@ verify_user_pass(struct user_pass *up, struct tls_multi *multi, && (multi->auth_token_tstamp + session->opt->auth_token_lifetime) < now) { msg(D_HANDSHAKE, "Auth-token for client expired\n"); + wipe_auth_token(multi); ks->authenticated = false; goto done; } @@ -1283,10 +1300,7 @@ verify_user_pass(struct user_pass *up, struct tls_multi *multi, if (memcmp_constant_time(multi->auth_token, up->password, strlen(multi->auth_token)) != 0) { - secure_memzero(multi->auth_token, AUTH_TOKEN_SIZE); - free(multi->auth_token); - multi->auth_token = NULL; - multi->auth_token_sent = false; + wipe_auth_token(multi); ks->authenticated = false; tls_deauthenticate(multi); @@ -1374,30 +1388,18 @@ verify_user_pass(struct user_pass *up, struct tls_multi *multi, /* The token should be longer than the input when * being base64 encoded */ - if (openvpn_base64_encode(tok, AUTH_TOKEN_SIZE, - &multi->auth_token) < AUTH_TOKEN_SIZE) - { - msg(D_TLS_ERRORS, "BASE64 encoding of token failed. " - "No auth-token will be activated now"); - if (multi->auth_token) - { - secure_memzero(multi->auth_token, AUTH_TOKEN_SIZE); - free(multi->auth_token); - multi->auth_token = NULL; - } - } - else - { - multi->auth_token_tstamp = now; - dmsg(D_SHOW_KEYS, "Generated token for client: %s", - multi->auth_token); - } + ASSERT(openvpn_base64_encode(tok, AUTH_TOKEN_SIZE, + &multi->auth_token) > AUTH_TOKEN_SIZE); + multi->auth_token_tstamp = now; + dmsg(D_SHOW_KEYS, "Generated token for client: %s", + multi->auth_token); } if ((session->opt->ssl_flags & SSLF_USERNAME_AS_COMMON_NAME)) { set_common_name(session, up->username); } + #ifdef ENABLE_DEF_AUTH msg(D_HANDSHAKE, "TLS: Username/Password authentication %s for username '%s' %s", ks->auth_deferred ? "deferred" : "succeeded", From a5ae0138eed240a23f46c0f091f1830ab36396c2 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Fri, 16 Dec 2016 11:58:51 +0100 Subject: [PATCH 449/643] Preparing OpenVPN v2.4_rc2 release Signed-off-by: David Sommerseth --- ChangeLog | 33 +++++++++++++++++++++++++++++++++ version.m4 | 2 +- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 59e679d4476..8ff692dd029 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,39 @@ OpenVPN Change Log Copyright (C) 2002-2016 OpenVPN Technologies, Inc. +2016.12.16 -- Version 2.4_rc2 +David Sommerseth (9): + Fix wrong configure.ac parsing of --enable-async-push + Changes: Further improve systemd unit file updates + systemd: Intermediate --chroot fix with the new sd_notify() implementation + Further enhance async-push feature description + Changes.rst: Mainatiner update on C99 + dev-tools: Add reformat-all.sh for code style unification + The Great Reformatting - first phase + Merge 'reformatting' branch into master + auth-gen-token: Hardening memory cleanup on auth-token failuers + +Gert Doering (1): + Refactor setting close-on-exec for socket FDs + +Lev Stipakov (2): + Arm inotify only in server mode + Add "async push" feature to Changes.rst + +Magnus Kroken (1): + mbedtls: include correct net/net_sockets header according to version + +Selva Nair (2): + Correctly state the default dhcp server address in man page + Unhide a line in man page by fixing a typo + +Steffan Karger (4): + Fix (and cleanup) crypto flags in combination with NCP + Deprecate --no-iv + man: mention that --ecdh-curve does not work on mbed TLS builds + Don't reopen tun if cipher changes + + 2016.12.01 -- Version 2.4_rc1 Antonio Quartulli (1): reload CRL only if file was modified diff --git a/version.m4 b/version.m4 index 60313a3611c..a8496f4edee 100644 --- a/version.m4 +++ b/version.m4 @@ -3,7 +3,7 @@ define([PRODUCT_NAME], [OpenVPN]) define([PRODUCT_TARNAME], [openvpn]) define([PRODUCT_VERSION_MAJOR], [2]) define([PRODUCT_VERSION_MINOR], [4]) -define([PRODUCT_VERSION_PATCH], [_rc1]) +define([PRODUCT_VERSION_PATCH], [_rc2]) m4_append([PRODUCT_VERSION], [PRODUCT_VERSION_MAJOR]) m4_append([PRODUCT_VERSION], [PRODUCT_VERSION_MINOR], [[.]]) m4_append([PRODUCT_VERSION], [PRODUCT_VERSION_PATCH], [[]]) From 0b159a62ed1c9d60e0c7001b025d2d016a90057f Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Mon, 19 Dec 2016 19:52:12 +0100 Subject: [PATCH 450/643] dev-tools: Added script for updating copyright years in files Very simple tool which modifies the Copyright lines in all git checked-in files with an updated year. Lines only listing a single year (2016) will be modified to list a range instead. Only the Copyright lines owners of specific owners will be modified. The script will need to be slightly updated to cover more owners. See the UPDATE_COPYRIGHT_LINES line in the script for the currently set owners. v2 - On-the-fly-commit-update: use vendor/ instead of cmocka and add @sophos.com to the list of copyright holders to update Signed-off-by: David Sommerseth Acked-by: Steffan Karger Message-Id: <1482173532-25132-1-git-send-email-davids@openvpn.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13645.html (cherry picked from commit da8f11f895bb78174d4412d82a6992c398da495a) --- dev-tools/update-copyright.sh | 50 +++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100755 dev-tools/update-copyright.sh diff --git a/dev-tools/update-copyright.sh b/dev-tools/update-copyright.sh new file mode 100755 index 00000000000..10f22358a4b --- /dev/null +++ b/dev-tools/update-copyright.sh @@ -0,0 +1,50 @@ +#!/bin/sh +# update-copyright-sh - Simple tool to update the Copyright lines +# in all files checked into git +# +# Copyright (C) 2016 David Sommerseth +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License. +# +# 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; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# + +# Basic shell sanity +set -eu + +# Simple argument control +if [ $# -ne 1 ]; then + echo "Usage: $0 " + exit 1 +fi + +# Only update Copyright lines with these owners +# The 'or' operator is GNU sed specific, and must be \| +UPDATE_COPYRIGHT_LINES="@openvpn\.net\|@fox-it\.com\|@sophos.com\|@eurephia\.net\|@greenie\.muc\.de" +COPY_YEAR="$1" + +cd "$(git rev-parse --show-toplevel)" +for file in $(git ls-files | grep -v vendor/); +do + echo -n "Updating $file ..." + # The first sed operation covers 20xx-20yy copyright lines, + # The second sed operation changes 20xx -> 20xx-20yy + sed -e "/$UPDATE_COPYRIGHT_LINES/s/\(Copyright (C) 20..-\)\(20..\)[[:blank:]]\+/\1$COPY_YEAR /" \ + -e "/$UPDATE_COPYRIGHT_LINES/s/\(Copyright (C) \)\(20..\)[[:blank:]]\+/\1\2-$COPY_YEAR /" \ + -i $file + echo " Done" +done +echo +echo "** All files updated with $COPY_YEAR as the ending copyright year" +echo +exit 0 From a0006fa431d2109a55ecc741a34510aea00dd608 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Wed, 21 Dec 2016 21:00:54 +0100 Subject: [PATCH 451/643] Update copyrights Signed-off-by: David Sommerseth Acked-by: Steffan Karger Message-Id: <1482350454-27280-4-git-send-email-davids@openvpn.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13655.html --- COPYING | 2 +- ChangeLog | 2 +- Makefile.am | 2 +- PORTS | 2 +- build/Makefile.am | 2 +- build/msvc/Makefile.am | 2 +- build/msvc/msvc-generate/Makefile.am | 2 +- configure.ac | 2 +- dev-tools/reformat-all.sh | 2 +- dev-tools/update-copyright.sh | 2 +- distro/Makefile.am | 2 +- distro/rpm/Makefile.am | 2 +- doc/Makefile.am | 2 +- doc/doxygen/doc_compression.h | 2 +- doc/doxygen/doc_control_processor.h | 2 +- doc/doxygen/doc_control_tls.h | 2 +- doc/doxygen/doc_data_control.h | 2 +- doc/doxygen/doc_data_crypto.h | 2 +- doc/doxygen/doc_eventloop.h | 2 +- doc/doxygen/doc_external_multiplexer.h | 2 +- doc/doxygen/doc_fragmentation.h | 2 +- doc/doxygen/doc_internal_multiplexer.h | 2 +- doc/doxygen/doc_key_generation.h | 2 +- doc/doxygen/doc_mainpage.h | 2 +- doc/doxygen/doc_memory_management.h | 2 +- doc/doxygen/doc_protocol_overview.h | 2 +- doc/doxygen/doc_reliable.h | 2 +- doc/doxygen/doc_tunnel_state.h | 2 +- doc/openvpn.8 | 2 +- include/Makefile.am | 2 +- include/openvpn-msg.h | 2 +- include/openvpn-plugin.h.in | 2 +- sample/Makefile.am | 2 +- sample/sample-plugins/defer/simple.c | 2 +- .../keying-material-exporter-demo/keyingmaterialexporter.c | 2 +- sample/sample-plugins/log/log.c | 2 +- sample/sample-plugins/log/log_v3.c | 2 +- sample/sample-plugins/simple/simple.c | 2 +- src/Makefile.am | 2 +- src/compat/Makefile.am | 2 +- src/compat/compat-gettimeofday.c | 2 +- src/openvpn/Makefile.am | 2 +- src/openvpn/argv.c | 2 +- src/openvpn/argv.h | 2 +- src/openvpn/basic.h | 2 +- src/openvpn/block_dns.c | 2 +- src/openvpn/buffer.c | 2 +- src/openvpn/buffer.h | 2 +- src/openvpn/circ_list.h | 2 +- src/openvpn/clinat.c | 2 +- src/openvpn/clinat.h | 2 +- src/openvpn/common.h | 2 +- src/openvpn/comp-lz4.c | 4 ++-- src/openvpn/comp-lz4.h | 4 ++-- src/openvpn/comp.c | 2 +- src/openvpn/comp.h | 2 +- src/openvpn/compstub.c | 2 +- src/openvpn/console.c | 4 ++-- src/openvpn/console.h | 4 ++-- src/openvpn/console_builtin.c | 4 ++-- src/openvpn/crypto.c | 4 ++-- src/openvpn/crypto.h | 4 ++-- src/openvpn/crypto_backend.h | 4 ++-- src/openvpn/crypto_mbedtls.c | 4 ++-- src/openvpn/crypto_mbedtls.h | 4 ++-- src/openvpn/crypto_openssl.c | 4 ++-- src/openvpn/crypto_openssl.h | 4 ++-- src/openvpn/dhcp.c | 2 +- src/openvpn/dhcp.h | 2 +- src/openvpn/errlevel.h | 2 +- src/openvpn/error.c | 2 +- src/openvpn/error.h | 2 +- src/openvpn/event.c | 2 +- src/openvpn/event.h | 2 +- src/openvpn/fdmisc.c | 2 +- src/openvpn/fdmisc.h | 2 +- src/openvpn/forward-inline.h | 2 +- src/openvpn/forward.c | 2 +- src/openvpn/forward.h | 2 +- src/openvpn/fragment.c | 2 +- src/openvpn/fragment.h | 2 +- src/openvpn/gremlin.c | 2 +- src/openvpn/gremlin.h | 2 +- src/openvpn/helper.c | 2 +- src/openvpn/helper.h | 2 +- src/openvpn/httpdigest.c | 2 +- src/openvpn/httpdigest.h | 2 +- src/openvpn/init.c | 2 +- src/openvpn/init.h | 2 +- src/openvpn/integer.h | 2 +- src/openvpn/interval.c | 2 +- src/openvpn/interval.h | 2 +- src/openvpn/list.c | 2 +- src/openvpn/list.h | 2 +- src/openvpn/lzo.c | 2 +- src/openvpn/lzo.h | 2 +- src/openvpn/manage.c | 2 +- src/openvpn/manage.h | 2 +- src/openvpn/mbuf.c | 2 +- src/openvpn/mbuf.h | 2 +- src/openvpn/memdbg.h | 2 +- src/openvpn/misc.c | 4 ++-- src/openvpn/misc.h | 2 +- src/openvpn/mroute.c | 2 +- src/openvpn/mroute.h | 2 +- src/openvpn/mss.c | 2 +- src/openvpn/mss.h | 2 +- src/openvpn/mstats.c | 2 +- src/openvpn/mstats.h | 2 +- src/openvpn/mtcp.c | 2 +- src/openvpn/mtcp.h | 2 +- src/openvpn/mtu.c | 2 +- src/openvpn/mtu.h | 2 +- src/openvpn/mudp.c | 2 +- src/openvpn/mudp.h | 2 +- src/openvpn/multi.c | 2 +- src/openvpn/multi.h | 2 +- src/openvpn/occ-inline.h | 2 +- src/openvpn/occ.c | 2 +- src/openvpn/occ.h | 2 +- src/openvpn/openvpn.c | 2 +- src/openvpn/openvpn.h | 2 +- src/openvpn/options.c | 4 ++-- src/openvpn/options.h | 2 +- src/openvpn/otime.c | 2 +- src/openvpn/otime.h | 2 +- src/openvpn/packet_id.c | 2 +- src/openvpn/packet_id.h | 2 +- src/openvpn/perf.c | 2 +- src/openvpn/perf.h | 2 +- src/openvpn/pf-inline.h | 2 +- src/openvpn/pf.c | 2 +- src/openvpn/pf.h | 2 +- src/openvpn/ping-inline.h | 2 +- src/openvpn/ping.c | 2 +- src/openvpn/ping.h | 2 +- src/openvpn/pkcs11.c | 2 +- src/openvpn/pkcs11.h | 2 +- src/openvpn/pkcs11_backend.h | 4 ++-- src/openvpn/pkcs11_mbedtls.c | 4 ++-- src/openvpn/pkcs11_openssl.c | 4 ++-- src/openvpn/platform.c | 2 +- src/openvpn/platform.h | 2 +- src/openvpn/plugin.c | 2 +- src/openvpn/plugin.h | 2 +- src/openvpn/pool.c | 2 +- src/openvpn/pool.h | 2 +- src/openvpn/proto.c | 2 +- src/openvpn/proto.h | 2 +- src/openvpn/proxy.c | 2 +- src/openvpn/proxy.h | 2 +- src/openvpn/ps.c | 2 +- src/openvpn/ps.h | 2 +- src/openvpn/push.c | 2 +- src/openvpn/push.h | 2 +- src/openvpn/pushlist.h | 2 +- src/openvpn/reliable.c | 2 +- src/openvpn/reliable.h | 2 +- src/openvpn/route.c | 2 +- src/openvpn/route.h | 2 +- src/openvpn/schedule.c | 2 +- src/openvpn/schedule.h | 2 +- src/openvpn/session_id.c | 2 +- src/openvpn/session_id.h | 2 +- src/openvpn/shaper.c | 2 +- src/openvpn/shaper.h | 2 +- src/openvpn/sig.c | 2 +- src/openvpn/sig.h | 2 +- src/openvpn/socket.c | 2 +- src/openvpn/socket.h | 2 +- src/openvpn/socks.c | 2 +- src/openvpn/socks.h | 2 +- src/openvpn/ssl.c | 4 ++-- src/openvpn/ssl.h | 4 ++-- src/openvpn/ssl_backend.h | 4 ++-- src/openvpn/ssl_common.h | 4 ++-- src/openvpn/ssl_mbedtls.c | 4 ++-- src/openvpn/ssl_mbedtls.h | 4 ++-- src/openvpn/ssl_openssl.c | 4 ++-- src/openvpn/ssl_openssl.h | 4 ++-- src/openvpn/ssl_verify.c | 4 ++-- src/openvpn/ssl_verify.h | 4 ++-- src/openvpn/ssl_verify_backend.h | 4 ++-- src/openvpn/ssl_verify_mbedtls.c | 4 ++-- src/openvpn/ssl_verify_mbedtls.h | 4 ++-- src/openvpn/ssl_verify_openssl.c | 4 ++-- src/openvpn/ssl_verify_openssl.h | 4 ++-- src/openvpn/status.c | 2 +- src/openvpn/status.h | 2 +- src/openvpn/syshead.h | 2 +- src/openvpn/tls_crypt.c | 2 +- src/openvpn/tls_crypt.h | 2 +- src/openvpn/tun.c | 2 +- src/openvpn/tun.h | 2 +- src/openvpn/win32.c | 2 +- src/openvpn/win32.h | 2 +- src/openvpnserv/Makefile.am | 2 +- src/openvpnserv/automatic.c | 2 +- src/openvpnserv/common.c | 2 +- src/openvpnserv/interactive.c | 2 +- src/openvpnserv/service.h | 2 +- src/plugins/Makefile.am | 2 +- src/plugins/auth-pam/auth-pam.c | 2 +- src/plugins/auth-pam/utils.c | 2 +- src/plugins/auth-pam/utils.h | 2 +- src/plugins/down-root/down-root.c | 2 +- tests/Makefile.am | 2 +- tests/unit_tests/openvpn/mock_msg.c | 2 +- tests/unit_tests/openvpn/mock_msg.h | 2 +- tests/unit_tests/openvpn/test_buffer.c | 2 +- tests/unit_tests/openvpn/test_tls_crypt.c | 2 +- 211 files changed, 243 insertions(+), 243 deletions(-) diff --git a/COPYING b/COPYING index f6e5c431b12..f88ad79bb77 100644 --- a/COPYING +++ b/COPYING @@ -1,6 +1,6 @@ OpenVPN (TM) -- An Open Source VPN daemon -Copyright (C) 2002-2010 OpenVPN Technologies, Inc. +Copyright (C) 2002-2017 OpenVPN Technologies, Inc. This distribution contains multiple components, some of which fall under different licenses. By using OpenVPN diff --git a/ChangeLog b/ChangeLog index 8ff692dd029..8ae08637f6e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,5 @@ OpenVPN Change Log -Copyright (C) 2002-2016 OpenVPN Technologies, Inc. +Copyright (C) 2002-2017 OpenVPN Technologies, Inc. 2016.12.16 -- Version 2.4_rc2 David Sommerseth (9): diff --git a/Makefile.am b/Makefile.am index 8e9581b33ec..d1a72dab171 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5,7 +5,7 @@ # packet encryption, packet authentication, and # packet compression. # -# Copyright (C) 2002-2010 OpenVPN Technologies, Inc. +# Copyright (C) 2002-2017 OpenVPN Technologies, Inc. # Copyright (C) 2010 David Sommerseth # Copyright (C) 2006-2012 Alon Bar-Lev # diff --git a/PORTS b/PORTS index 735493c7c6b..5a9de662df9 100644 --- a/PORTS +++ b/PORTS @@ -1,5 +1,5 @@ OpenVPN -Copyright (C) 2002-2010 OpenVPN Technologies, Inc. +Copyright (C) 2002-2017 OpenVPN Technologies, Inc. OpenVPN has been written to try to avoid features that are not standardized well across different diff --git a/build/Makefile.am b/build/Makefile.am index b53ff52d3b2..4191a994bcc 100644 --- a/build/Makefile.am +++ b/build/Makefile.am @@ -5,7 +5,7 @@ # packet encryption, packet authentication, and # packet compression. # -# Copyright (C) 2002-2010 OpenVPN Technologies, Inc. +# Copyright (C) 2002-2017 OpenVPN Technologies, Inc. # MAINTAINERCLEANFILES = \ diff --git a/build/msvc/Makefile.am b/build/msvc/Makefile.am index 7dc3def0469..85a613b2901 100644 --- a/build/msvc/Makefile.am +++ b/build/msvc/Makefile.am @@ -5,7 +5,7 @@ # packet encryption, packet authentication, and # packet compression. # -# Copyright (C) 2002-2010 OpenVPN Technologies, Inc. +# Copyright (C) 2002-2017 OpenVPN Technologies, Inc. # Copyright (C) 2006-2012 Alon Bar-Lev # diff --git a/build/msvc/msvc-generate/Makefile.am b/build/msvc/msvc-generate/Makefile.am index 539fb6cefa8..2151b42303d 100644 --- a/build/msvc/msvc-generate/Makefile.am +++ b/build/msvc/msvc-generate/Makefile.am @@ -5,7 +5,7 @@ # packet encryption, packet authentication, and # packet compression. # -# Copyright (C) 2002-2010 OpenVPN Technologies, Inc. +# Copyright (C) 2002-2017 OpenVPN Technologies, Inc. # Copyright (C) 2006-2012 Alon Bar-Lev # diff --git a/configure.ac b/configure.ac index 4f086eab230..43487b01dd5 100644 --- a/configure.ac +++ b/configure.ac @@ -4,7 +4,7 @@ dnl session authentication and key exchange, dnl packet encryption, packet authentication, and dnl packet compression. dnl -dnl Copyright (C) 2002-2010 OpenVPN Technologies, Inc. +dnl Copyright (C) 2002-2017 OpenVPN Technologies, Inc. dnl Copyright (C) 2006-2012 Alon Bar-Lev dnl dnl This program is free software; you can redistribute it and/or modify diff --git a/dev-tools/reformat-all.sh b/dev-tools/reformat-all.sh index cf42bd028cd..e253ab2b435 100755 --- a/dev-tools/reformat-all.sh +++ b/dev-tools/reformat-all.sh @@ -2,7 +2,7 @@ # reformat-all.sh - Reformat all git files in the checked out # git branch using uncrustify. # -# Copyright (C) 2016 - David Sommerseth +# Copyright (C) 2016-2017 - David Sommerseth # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License diff --git a/dev-tools/update-copyright.sh b/dev-tools/update-copyright.sh index 10f22358a4b..755d1e030ee 100755 --- a/dev-tools/update-copyright.sh +++ b/dev-tools/update-copyright.sh @@ -2,7 +2,7 @@ # update-copyright-sh - Simple tool to update the Copyright lines # in all files checked into git # -# Copyright (C) 2016 David Sommerseth +# Copyright (C) 2016-2017 David Sommerseth # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License diff --git a/distro/Makefile.am b/distro/Makefile.am index bd65b79be83..7a9ffd0fbc7 100644 --- a/distro/Makefile.am +++ b/distro/Makefile.am @@ -5,7 +5,7 @@ # packet encryption, packet authentication, and # packet compression. # -# Copyright (C) 2002-2010 OpenVPN Technologies, Inc. +# Copyright (C) 2002-2017 OpenVPN Technologies, Inc. # Copyright (C) 2006-2012 Alon Bar-Lev # diff --git a/distro/rpm/Makefile.am b/distro/rpm/Makefile.am index 536061dd1b2..37ee099a55e 100644 --- a/distro/rpm/Makefile.am +++ b/distro/rpm/Makefile.am @@ -5,7 +5,7 @@ # packet encryption, packet authentication, and # packet compression. # -# Copyright (C) 2002-2010 OpenVPN Technologies, Inc. +# Copyright (C) 2002-2017 OpenVPN Technologies, Inc. # Copyright (C) 2006-2012 Alon Bar-Lev # diff --git a/doc/Makefile.am b/doc/Makefile.am index d33e1edd8d0..dedd1fa5cf5 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -5,7 +5,7 @@ # packet encryption, packet authentication, and # packet compression. # -# Copyright (C) 2002-2010 OpenVPN Technologies, Inc. +# Copyright (C) 2002-2017 OpenVPN Technologies, Inc. # Copyright (C) 2006-2012 Alon Bar-Lev # diff --git a/doc/doxygen/doc_compression.h b/doc/doxygen/doc_compression.h index bdc4a7ed833..3213164b823 100644 --- a/doc/doxygen/doc_compression.h +++ b/doc/doxygen/doc_compression.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2010 Fox Crypto B.V. + * Copyright (C) 2010-2017 Fox Crypto B.V. * * * This program is free software; you can redistribute it and/or modify diff --git a/doc/doxygen/doc_control_processor.h b/doc/doxygen/doc_control_processor.h index 072dc3729c2..797bf0f4366 100644 --- a/doc/doxygen/doc_control_processor.h +++ b/doc/doxygen/doc_control_processor.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2010 Fox Crypto B.V. + * Copyright (C) 2010-2017 Fox Crypto B.V. * * * This program is free software; you can redistribute it and/or modify diff --git a/doc/doxygen/doc_control_tls.h b/doc/doxygen/doc_control_tls.h index aba55f775b0..fc5c96a57ee 100644 --- a/doc/doxygen/doc_control_tls.h +++ b/doc/doxygen/doc_control_tls.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2010 Fox Crypto B.V. + * Copyright (C) 2010-2017 Fox Crypto B.V. * * * This program is free software; you can redistribute it and/or modify diff --git a/doc/doxygen/doc_data_control.h b/doc/doxygen/doc_data_control.h index d0f65ba39f6..c527f70c1ad 100644 --- a/doc/doxygen/doc_data_control.h +++ b/doc/doxygen/doc_data_control.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2010 Fox Crypto B.V. + * Copyright (C) 2010-2017 Fox Crypto B.V. * * * This program is free software; you can redistribute it and/or modify diff --git a/doc/doxygen/doc_data_crypto.h b/doc/doxygen/doc_data_crypto.h index 11726724ee1..571171e139e 100644 --- a/doc/doxygen/doc_data_crypto.h +++ b/doc/doxygen/doc_data_crypto.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2010 Fox Crypto B.V. + * Copyright (C) 2010-2017 Fox Crypto B.V. * * * This program is free software; you can redistribute it and/or modify diff --git a/doc/doxygen/doc_eventloop.h b/doc/doxygen/doc_eventloop.h index a860db68af2..10d41c45aa2 100644 --- a/doc/doxygen/doc_eventloop.h +++ b/doc/doxygen/doc_eventloop.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2010 Fox Crypto B.V. + * Copyright (C) 2010-2017 Fox Crypto B.V. * * * This program is free software; you can redistribute it and/or modify diff --git a/doc/doxygen/doc_external_multiplexer.h b/doc/doxygen/doc_external_multiplexer.h index 76532557575..bc64c33609b 100644 --- a/doc/doxygen/doc_external_multiplexer.h +++ b/doc/doxygen/doc_external_multiplexer.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2010 Fox Crypto B.V. + * Copyright (C) 2010-2017 Fox Crypto B.V. * * * This program is free software; you can redistribute it and/or modify diff --git a/doc/doxygen/doc_fragmentation.h b/doc/doxygen/doc_fragmentation.h index ef34cdb27bb..34d73d618eb 100644 --- a/doc/doxygen/doc_fragmentation.h +++ b/doc/doxygen/doc_fragmentation.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2010 Fox Crypto B.V. + * Copyright (C) 2010-2017 Fox Crypto B.V. * * * This program is free software; you can redistribute it and/or modify diff --git a/doc/doxygen/doc_internal_multiplexer.h b/doc/doxygen/doc_internal_multiplexer.h index 5142dd0de48..d38231b4409 100644 --- a/doc/doxygen/doc_internal_multiplexer.h +++ b/doc/doxygen/doc_internal_multiplexer.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2010 Fox Crypto B.V. + * Copyright (C) 2010-2017 Fox Crypto B.V. * * * This program is free software; you can redistribute it and/or modify diff --git a/doc/doxygen/doc_key_generation.h b/doc/doxygen/doc_key_generation.h index 903a46521bc..43ca150d2b8 100644 --- a/doc/doxygen/doc_key_generation.h +++ b/doc/doxygen/doc_key_generation.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2010 Fox Crypto B.V. + * Copyright (C) 2010-2017 Fox Crypto B.V. * * * This program is free software; you can redistribute it and/or modify diff --git a/doc/doxygen/doc_mainpage.h b/doc/doxygen/doc_mainpage.h index ed8e324e7bf..685e0b9dcbf 100644 --- a/doc/doxygen/doc_mainpage.h +++ b/doc/doxygen/doc_mainpage.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2010 Fox Crypto B.V. + * Copyright (C) 2010-2017 Fox Crypto B.V. * * * This program is free software; you can redistribute it and/or modify diff --git a/doc/doxygen/doc_memory_management.h b/doc/doxygen/doc_memory_management.h index f948783e0d6..0e85d9376e8 100644 --- a/doc/doxygen/doc_memory_management.h +++ b/doc/doxygen/doc_memory_management.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2010 Fox Crypto B.V. + * Copyright (C) 2010-2017 Fox Crypto B.V. * * * This program is free software; you can redistribute it and/or modify diff --git a/doc/doxygen/doc_protocol_overview.h b/doc/doxygen/doc_protocol_overview.h index 9edafcfb8b8..46d2e123d0d 100644 --- a/doc/doxygen/doc_protocol_overview.h +++ b/doc/doxygen/doc_protocol_overview.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2010-2014 Fox Crypto B.V. + * Copyright (C) 2010-2017 Fox Crypto B.V. * * * This program is free software; you can redistribute it and/or modify diff --git a/doc/doxygen/doc_reliable.h b/doc/doxygen/doc_reliable.h index 5264906ad73..a6d8f2f1f7c 100644 --- a/doc/doxygen/doc_reliable.h +++ b/doc/doxygen/doc_reliable.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2010 Fox Crypto B.V. + * Copyright (C) 2010-2017 Fox Crypto B.V. * * * This program is free software; you can redistribute it and/or modify diff --git a/doc/doxygen/doc_tunnel_state.h b/doc/doxygen/doc_tunnel_state.h index 6c93e71bf24..4433dbed5c5 100644 --- a/doc/doxygen/doc_tunnel_state.h +++ b/doc/doxygen/doc_tunnel_state.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2010 Fox Crypto B.V. + * Copyright (C) 2010-2017 Fox Crypto B.V. * * * This program is free software; you can redistribute it and/or modify diff --git a/doc/openvpn.8 b/doc/openvpn.8 index f0797998cc2..b1ca9ed9cf7 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -4,7 +4,7 @@ .\" packet encryption, packet authentication, and .\" packet compression. .\" -.\" Copyright (C) 2002-2016 OpenVPN Technologies, Inc. +.\" Copyright (C) 2002-2017 OpenVPN Technologies, Inc. .\" .\" This program is free software; you can redistribute it and/or modify .\" it under the terms of the GNU General Public License version 2 diff --git a/include/Makefile.am b/include/Makefile.am index 498b3b54d56..a52c4278bce 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -5,7 +5,7 @@ # packet encryption, packet authentication, and # packet compression. # -# Copyright (C) 2002-2010 OpenVPN Technologies, Inc. +# Copyright (C) 2002-2017 OpenVPN Technologies, Inc. # Copyright (C) 2006-2012 Alon Bar-Lev # diff --git a/include/openvpn-msg.h b/include/openvpn-msg.h index 4c9e63c7a5f..5f3c96ca793 100644 --- a/include/openvpn-msg.h +++ b/include/openvpn-msg.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2013 Heiko Hund + * Copyright (C) 2013-2017 Heiko Hund * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/include/openvpn-plugin.h.in b/include/openvpn-plugin.h.in index f17b7535936..0b303520a30 100644 --- a/include/openvpn-plugin.h.in +++ b/include/openvpn-plugin.h.in @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/sample/Makefile.am b/sample/Makefile.am index be30c88a7df..58ae9658b5a 100644 --- a/sample/Makefile.am +++ b/sample/Makefile.am @@ -5,7 +5,7 @@ # packet encryption, packet authentication, and # packet compression. # -# Copyright (C) 2002-2010 OpenVPN Technologies, Inc. +# Copyright (C) 2002-2017 OpenVPN Technologies, Inc. # Copyright (C) 2006-2012 Alon Bar-Lev # diff --git a/sample/sample-plugins/defer/simple.c b/sample/sample-plugins/defer/simple.c index 1d70ad1dec2..ad1bbb0fd09 100644 --- a/sample/sample-plugins/defer/simple.c +++ b/sample/sample-plugins/defer/simple.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/sample/sample-plugins/keying-material-exporter-demo/keyingmaterialexporter.c b/sample/sample-plugins/keying-material-exporter-demo/keyingmaterialexporter.c index 9827ed1822e..177977df337 100644 --- a/sample/sample-plugins/keying-material-exporter-demo/keyingmaterialexporter.c +++ b/sample/sample-plugins/keying-material-exporter-demo/keyingmaterialexporter.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/sample/sample-plugins/log/log.c b/sample/sample-plugins/log/log.c index 390c37f0c47..02016285a06 100644 --- a/sample/sample-plugins/log/log.c +++ b/sample/sample-plugins/log/log.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/sample/sample-plugins/log/log_v3.c b/sample/sample-plugins/log/log_v3.c index 317604d1e8a..9037225a2f4 100644 --- a/sample/sample-plugins/log/log_v3.c +++ b/sample/sample-plugins/log/log_v3.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2009 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * Copyright (C) 2010 David Sommerseth * * This program is free software; you can redistribute it and/or modify diff --git a/sample/sample-plugins/simple/simple.c b/sample/sample-plugins/simple/simple.c index 4beab48cf32..f59533334e2 100644 --- a/sample/sample-plugins/simple/simple.c +++ b/sample/sample-plugins/simple/simple.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/Makefile.am b/src/Makefile.am index c04468a5b28..eb5b0070f3e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -5,7 +5,7 @@ # packet encryption, packet authentication, and # packet compression. # -# Copyright (C) 2002-2010 OpenVPN Technologies, Inc. +# Copyright (C) 2002-2017 OpenVPN Technologies, Inc. # Copyright (C) 2006-2012 Alon Bar-Lev # diff --git a/src/compat/Makefile.am b/src/compat/Makefile.am index 0a9d1c25edf..444a8f8b067 100644 --- a/src/compat/Makefile.am +++ b/src/compat/Makefile.am @@ -5,7 +5,7 @@ # packet encryption, packet authentication, and # packet compression. # -# Copyright (C) 2002-2010 OpenVPN Technologies, Inc. +# Copyright (C) 2002-2017 OpenVPN Technologies, Inc. # Copyright (C) 2006-2012 Alon Bar-Lev # diff --git a/src/compat/compat-gettimeofday.c b/src/compat/compat-gettimeofday.c index 027bc4a092f..d53e360f0d3 100644 --- a/src/compat/compat-gettimeofday.c +++ b/src/compat/compat-gettimeofday.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/Makefile.am b/src/openvpn/Makefile.am index 4c18449b5ed..bea294b3559 100644 --- a/src/openvpn/Makefile.am +++ b/src/openvpn/Makefile.am @@ -5,7 +5,7 @@ # packet encryption, packet authentication, and # packet compression. # -# Copyright (C) 2002-2010 OpenVPN Technologies, Inc. +# Copyright (C) 2002-2017 OpenVPN Technologies, Inc. # Copyright (C) 2006-2012 Alon Bar-Lev # diff --git a/src/openvpn/argv.c b/src/openvpn/argv.c index 27cda0c6254..cc813ed55c5 100644 --- a/src/openvpn/argv.c +++ b/src/openvpn/argv.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/argv.h b/src/openvpn/argv.h index 8e263e1eb12..1dd6dd7da2c 100644 --- a/src/openvpn/argv.h +++ b/src/openvpn/argv.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/basic.h b/src/openvpn/basic.h index 48d4d9bd6e6..dac6f011243 100644 --- a/src/openvpn/basic.h +++ b/src/openvpn/basic.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/block_dns.c b/src/openvpn/block_dns.c index 81c2929bbb0..e31765eed63 100644 --- a/src/openvpn/block_dns.c +++ b/src/openvpn/block_dns.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * 2015-2016 * 2016 Selva Nair * diff --git a/src/openvpn/buffer.c b/src/openvpn/buffer.c index b1d2fbf739f..2defd1814fb 100644 --- a/src/openvpn/buffer.c +++ b/src/openvpn/buffer.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/buffer.h b/src/openvpn/buffer.h index a1a130c9b3f..28b224e09ed 100644 --- a/src/openvpn/buffer.h +++ b/src/openvpn/buffer.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/circ_list.h b/src/openvpn/circ_list.h index b4324d8e50a..ecf2a7f3647 100644 --- a/src/openvpn/circ_list.h +++ b/src/openvpn/circ_list.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/clinat.c b/src/openvpn/clinat.c index 08d7acf42fa..9158437c19f 100644 --- a/src/openvpn/clinat.c +++ b/src/openvpn/clinat.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/clinat.h b/src/openvpn/clinat.h index e0c8ec51765..cdaf2a8bdb2 100644 --- a/src/openvpn/clinat.h +++ b/src/openvpn/clinat.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/common.h b/src/openvpn/common.h index 6352b01f274..cd988d4519f 100644 --- a/src/openvpn/common.h +++ b/src/openvpn/common.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/comp-lz4.c b/src/openvpn/comp-lz4.c index 6b7c49b60f2..fa65f87e8c3 100644 --- a/src/openvpn/comp-lz4.c +++ b/src/openvpn/comp-lz4.c @@ -5,8 +5,8 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2012 OpenVPN Technologies, Inc. - * Copyright (C) 2013 Gert Doering + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. + * Copyright (C) 2013-2017 Gert Doering * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/comp-lz4.h b/src/openvpn/comp-lz4.h index 65f4f8ec367..8621e931121 100644 --- a/src/openvpn/comp-lz4.h +++ b/src/openvpn/comp-lz4.h @@ -5,8 +5,8 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2012 OpenVPN Technologies, Inc. - * Copyright (C) 2013 Gert Doering + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. + * Copyright (C) 2013-2017 Gert Doering * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/comp.c b/src/openvpn/comp.c index 5f563aed838..0182a7cf660 100644 --- a/src/openvpn/comp.c +++ b/src/openvpn/comp.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2012 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/comp.h b/src/openvpn/comp.h index 7410c92bab4..3c0b18ecae6 100644 --- a/src/openvpn/comp.h +++ b/src/openvpn/comp.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2012 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/compstub.c b/src/openvpn/compstub.c index 7082b99fd19..5070c82e2a0 100644 --- a/src/openvpn/compstub.c +++ b/src/openvpn/compstub.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2012 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/console.c b/src/openvpn/console.c index ec64d42fb21..90c8a94c5c2 100644 --- a/src/openvpn/console.c +++ b/src/openvpn/console.c @@ -5,9 +5,9 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * Copyright (C) 2014-2015 David Sommerseth - * Copyright (C) 2016 David Sommerseth + * Copyright (C) 2016-2017 David Sommerseth * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/console.h b/src/openvpn/console.h index 495414a11cc..2c7f3e965c2 100644 --- a/src/openvpn/console.h +++ b/src/openvpn/console.h @@ -5,9 +5,9 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * Copyright (C) 2014-2015 David Sommerseth - * Copyright (C) 2016 David Sommerseth + * Copyright (C) 2016-2017 David Sommerseth * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/console_builtin.c b/src/openvpn/console_builtin.c index 2d0c15fb907..13b9d7e7a81 100644 --- a/src/openvpn/console_builtin.c +++ b/src/openvpn/console_builtin.c @@ -5,9 +5,9 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2016 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * Copyright (C) 2014-2015 David Sommerseth - * Copyright (C) 2016 David Sommerseth + * Copyright (C) 2016-2017 David Sommerseth * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c index b28eb9d757a..7119abc61e3 100644 --- a/src/openvpn/crypto.c +++ b/src/openvpn/crypto.c @@ -5,8 +5,8 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. - * Copyright (C) 2010-2016 Fox Crypto B.V. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. + * Copyright (C) 2010-2017 Fox Crypto B.V. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/crypto.h b/src/openvpn/crypto.h index 56761baab8c..61e9b5982bd 100644 --- a/src/openvpn/crypto.h +++ b/src/openvpn/crypto.h @@ -5,8 +5,8 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. - * Copyright (C) 2010-2014 Fox Crypto B.V. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. + * Copyright (C) 2010-2017 Fox Crypto B.V. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/crypto_backend.h b/src/openvpn/crypto_backend.h index a4b2b43e20b..2c79baa15c2 100644 --- a/src/openvpn/crypto_backend.h +++ b/src/openvpn/crypto_backend.h @@ -5,8 +5,8 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. - * Copyright (C) 2010 Fox Crypto B.V. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. + * Copyright (C) 2010-2017 Fox Crypto B.V. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/crypto_mbedtls.c b/src/openvpn/crypto_mbedtls.c index 89915bc04e3..942684ce03f 100644 --- a/src/openvpn/crypto_mbedtls.c +++ b/src/openvpn/crypto_mbedtls.c @@ -5,8 +5,8 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. - * Copyright (C) 2010 Fox Crypto B.V. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. + * Copyright (C) 2010-2017 Fox Crypto B.V. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/crypto_mbedtls.h b/src/openvpn/crypto_mbedtls.h index 16f9007cc60..d9b14461b0b 100644 --- a/src/openvpn/crypto_mbedtls.h +++ b/src/openvpn/crypto_mbedtls.h @@ -5,8 +5,8 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. - * Copyright (C) 2010 Fox Crypto B.V. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. + * Copyright (C) 2010-2017 Fox Crypto B.V. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/crypto_openssl.c b/src/openvpn/crypto_openssl.c index 4e783167651..b016d98a9fd 100644 --- a/src/openvpn/crypto_openssl.c +++ b/src/openvpn/crypto_openssl.c @@ -5,8 +5,8 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. - * Copyright (C) 2010 Fox Crypto B.V. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. + * Copyright (C) 2010-2017 Fox Crypto B.V. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/crypto_openssl.h b/src/openvpn/crypto_openssl.h index 6cf009e2253..56ec6e1c67f 100644 --- a/src/openvpn/crypto_openssl.h +++ b/src/openvpn/crypto_openssl.h @@ -5,8 +5,8 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. - * Copyright (C) 2010 Fox Crypto B.V. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. + * Copyright (C) 2010-2017 Fox Crypto B.V. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/dhcp.c b/src/openvpn/dhcp.c index 9c706ed9f94..c17a22e631a 100644 --- a/src/openvpn/dhcp.c +++ b/src/openvpn/dhcp.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/dhcp.h b/src/openvpn/dhcp.h index ee0f438a48f..d4068702d74 100644 --- a/src/openvpn/dhcp.h +++ b/src/openvpn/dhcp.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/errlevel.h b/src/openvpn/errlevel.h index b3a9f8140f1..c4dd5189392 100644 --- a/src/openvpn/errlevel.h +++ b/src/openvpn/errlevel.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/error.c b/src/openvpn/error.c index 6c07cdec145..e78f2723911 100644 --- a/src/openvpn/error.c +++ b/src/openvpn/error.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/error.h b/src/openvpn/error.h index eb9f8c08fbe..df4eee72c19 100644 --- a/src/openvpn/error.h +++ b/src/openvpn/error.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/event.c b/src/openvpn/event.c index a13e0dc95aa..f4922e0a94d 100644 --- a/src/openvpn/event.c +++ b/src/openvpn/event.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/event.h b/src/openvpn/event.h index 5e66d482ed1..6a6e029a948 100644 --- a/src/openvpn/event.h +++ b/src/openvpn/event.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/fdmisc.c b/src/openvpn/fdmisc.c index 3851c43d143..401069da84a 100644 --- a/src/openvpn/fdmisc.c +++ b/src/openvpn/fdmisc.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/fdmisc.h b/src/openvpn/fdmisc.h index bd9b47ca220..1e84a088d5e 100644 --- a/src/openvpn/fdmisc.h +++ b/src/openvpn/fdmisc.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/forward-inline.h b/src/openvpn/forward-inline.h index 6bce755f66c..97e1cd68915 100644 --- a/src/openvpn/forward-inline.h +++ b/src/openvpn/forward-inline.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c index ab560562492..8102e94975b 100644 --- a/src/openvpn/forward.c +++ b/src/openvpn/forward.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/forward.h b/src/openvpn/forward.h index 82f7bbf09ba..ae86e7a6d46 100644 --- a/src/openvpn/forward.h +++ b/src/openvpn/forward.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/fragment.c b/src/openvpn/fragment.c index 87b93805747..6fbfe084a95 100644 --- a/src/openvpn/fragment.c +++ b/src/openvpn/fragment.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/fragment.h b/src/openvpn/fragment.h index 407321259e6..a24b524282c 100644 --- a/src/openvpn/fragment.h +++ b/src/openvpn/fragment.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/gremlin.c b/src/openvpn/gremlin.c index e8b10a7e141..5bff5e8e1ee 100644 --- a/src/openvpn/gremlin.c +++ b/src/openvpn/gremlin.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/gremlin.h b/src/openvpn/gremlin.h index c60048cfdee..8f4186492aa 100644 --- a/src/openvpn/gremlin.h +++ b/src/openvpn/gremlin.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/helper.c b/src/openvpn/helper.c index 1fc4c861863..adcc4f8362c 100644 --- a/src/openvpn/helper.c +++ b/src/openvpn/helper.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/helper.h b/src/openvpn/helper.h index d78c02f7200..593d1edf52e 100644 --- a/src/openvpn/helper.h +++ b/src/openvpn/helper.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/httpdigest.c b/src/openvpn/httpdigest.c index c5f0d927474..01301c01352 100644 --- a/src/openvpn/httpdigest.c +++ b/src/openvpn/httpdigest.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/httpdigest.h b/src/openvpn/httpdigest.h index fff7d4655da..b074fb28585 100644 --- a/src/openvpn/httpdigest.h +++ b/src/openvpn/httpdigest.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/init.c b/src/openvpn/init.c index f6a5ac7d969..9a3e29d3f74 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/init.h b/src/openvpn/init.h index d742bc7c7e0..3b97d84e40e 100644 --- a/src/openvpn/init.h +++ b/src/openvpn/init.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/integer.h b/src/openvpn/integer.h index ee9a43eab97..bae8f16214c 100644 --- a/src/openvpn/integer.h +++ b/src/openvpn/integer.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/interval.c b/src/openvpn/interval.c index 108b778835c..99e72a0fc29 100644 --- a/src/openvpn/interval.c +++ b/src/openvpn/interval.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/interval.h b/src/openvpn/interval.h index 0507ed2187e..5ed64a92c19 100644 --- a/src/openvpn/interval.h +++ b/src/openvpn/interval.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/list.c b/src/openvpn/list.c index 4d64b4cdfa7..fb9f6641e05 100644 --- a/src/openvpn/list.c +++ b/src/openvpn/list.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/list.h b/src/openvpn/list.h index 72fb2c9e0a8..6270f880159 100644 --- a/src/openvpn/list.h +++ b/src/openvpn/list.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/lzo.c b/src/openvpn/lzo.c index e587268aa57..3d6891ed2e2 100644 --- a/src/openvpn/lzo.c +++ b/src/openvpn/lzo.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/lzo.h b/src/openvpn/lzo.h index f9eddcc0401..85937b25ccc 100644 --- a/src/openvpn/lzo.h +++ b/src/openvpn/lzo.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/manage.c b/src/openvpn/manage.c index b6520c0d4cd..763f6c6dd55 100644 --- a/src/openvpn/manage.c +++ b/src/openvpn/manage.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/manage.h b/src/openvpn/manage.h index 7e022f01231..6e5cb9b00f3 100644 --- a/src/openvpn/manage.h +++ b/src/openvpn/manage.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/mbuf.c b/src/openvpn/mbuf.c index a8388c49ec5..7a23e590786 100644 --- a/src/openvpn/mbuf.c +++ b/src/openvpn/mbuf.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/mbuf.h b/src/openvpn/mbuf.h index c6375e37a83..cfaef5802f6 100644 --- a/src/openvpn/mbuf.h +++ b/src/openvpn/mbuf.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/memdbg.h b/src/openvpn/memdbg.h index 4906f882170..ee30b15fa77 100644 --- a/src/openvpn/memdbg.h +++ b/src/openvpn/memdbg.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/misc.c b/src/openvpn/misc.c index 7c769a83cea..87f03bea318 100644 --- a/src/openvpn/misc.c +++ b/src/openvpn/misc.c @@ -5,9 +5,9 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * Copyright (C) 2014-2015 David Sommerseth - * Copyright (C) 2016 David Sommerseth + * Copyright (C) 2016-2017 David Sommerseth * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/misc.h b/src/openvpn/misc.h index 606c46552c0..16be6219cee 100644 --- a/src/openvpn/misc.h +++ b/src/openvpn/misc.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/mroute.c b/src/openvpn/mroute.c index cdcd061fa82..8b466b6c1ff 100644 --- a/src/openvpn/mroute.c +++ b/src/openvpn/mroute.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/mroute.h b/src/openvpn/mroute.h index 9da41ee1ed5..069834874e5 100644 --- a/src/openvpn/mroute.h +++ b/src/openvpn/mroute.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/mss.c b/src/openvpn/mss.c index af3457b4403..5b110d2f892 100644 --- a/src/openvpn/mss.c +++ b/src/openvpn/mss.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/mss.h b/src/openvpn/mss.h index 6d18fb975f1..afe7a32b28e 100644 --- a/src/openvpn/mss.h +++ b/src/openvpn/mss.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/mstats.c b/src/openvpn/mstats.c index 3dad866a8ae..8ab1d022975 100644 --- a/src/openvpn/mstats.c +++ b/src/openvpn/mstats.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2011 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/mstats.h b/src/openvpn/mstats.h index 7a5cc68029a..f87a8580e8f 100644 --- a/src/openvpn/mstats.h +++ b/src/openvpn/mstats.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2011 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/mtcp.c b/src/openvpn/mtcp.c index 4fab23fb454..b5471b11a80 100644 --- a/src/openvpn/mtcp.c +++ b/src/openvpn/mtcp.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/mtcp.h b/src/openvpn/mtcp.h index a11e56e60f0..835b8fd0fdb 100644 --- a/src/openvpn/mtcp.h +++ b/src/openvpn/mtcp.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/mtu.c b/src/openvpn/mtu.c index 416a11e9604..73eab21ad19 100644 --- a/src/openvpn/mtu.c +++ b/src/openvpn/mtu.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/mtu.h b/src/openvpn/mtu.h index 0d5402d0034..471e51ead3d 100644 --- a/src/openvpn/mtu.h +++ b/src/openvpn/mtu.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/mudp.c b/src/openvpn/mudp.c index 35a8d3c73cb..64ce4d7595f 100644 --- a/src/openvpn/mudp.c +++ b/src/openvpn/mudp.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/mudp.h b/src/openvpn/mudp.h index 89ec78c507f..a98d64d78e4 100644 --- a/src/openvpn/mudp.h +++ b/src/openvpn/mudp.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index 3480579bf7d..f6f3f5d98f2 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/multi.h b/src/openvpn/multi.h index 7508fe27f28..b4ffd6959ca 100644 --- a/src/openvpn/multi.h +++ b/src/openvpn/multi.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/occ-inline.h b/src/openvpn/occ-inline.h index 5b656d4c65c..84fe1acfbcd 100644 --- a/src/openvpn/occ-inline.h +++ b/src/openvpn/occ-inline.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/occ.c b/src/openvpn/occ.c index 046d03b1a6d..b4ccc4de57b 100644 --- a/src/openvpn/occ.c +++ b/src/openvpn/occ.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/occ.h b/src/openvpn/occ.h index cb5d957fb84..843ceb2855a 100644 --- a/src/openvpn/occ.h +++ b/src/openvpn/occ.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/openvpn.c b/src/openvpn/openvpn.c index 9a1ff9ce446..888acda6adc 100644 --- a/src/openvpn/openvpn.c +++ b/src/openvpn/openvpn.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/openvpn.h b/src/openvpn/openvpn.h index 36c53e8f47b..37edec4f725 100644 --- a/src/openvpn/openvpn.h +++ b/src/openvpn/openvpn.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/options.c b/src/openvpn/options.c index b34350222b7..bfedb6ae06e 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2013 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * Copyright (C) 2008-2013 David Sommerseth * * This program is free software; you can redistribute it and/or modify @@ -4137,7 +4137,7 @@ usage_version(void) show_windows_version( M_INFO|M_NOPREFIX ); #endif msg(M_INFO|M_NOPREFIX, "Originally developed by James Yonan"); - msg(M_INFO|M_NOPREFIX, "Copyright (C) 2002-2016 OpenVPN Technologies, Inc. "); + msg(M_INFO|M_NOPREFIX, "Copyright (C) 2002-2017 OpenVPN Technologies, Inc. "); #ifndef ENABLE_SMALL #ifdef CONFIGURE_DEFINES msg(M_INFO|M_NOPREFIX, "Compile time defines: %s", CONFIGURE_DEFINES); diff --git a/src/openvpn/options.h b/src/openvpn/options.h index 3fd0f23083e..b3ab0293463 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/otime.c b/src/openvpn/otime.c index cc487e50862..22abda07437 100644 --- a/src/openvpn/otime.c +++ b/src/openvpn/otime.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/otime.h b/src/openvpn/otime.h index 2b596ff2f72..eede63d200d 100644 --- a/src/openvpn/otime.h +++ b/src/openvpn/otime.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/packet_id.c b/src/openvpn/packet_id.c index 64d19c59d97..fe13e1d8a52 100644 --- a/src/openvpn/packet_id.c +++ b/src/openvpn/packet_id.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/packet_id.h b/src/openvpn/packet_id.h index d4019ff7c1d..ecc25a6c3b5 100644 --- a/src/openvpn/packet_id.h +++ b/src/openvpn/packet_id.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/perf.c b/src/openvpn/perf.c index e012eb4166f..51e051ab1b4 100644 --- a/src/openvpn/perf.c +++ b/src/openvpn/perf.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/perf.h b/src/openvpn/perf.h index f277b1e96df..f0430a14596 100644 --- a/src/openvpn/perf.h +++ b/src/openvpn/perf.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/pf-inline.h b/src/openvpn/pf-inline.h index beaae5c7e48..a0f5cc7c856 100644 --- a/src/openvpn/pf-inline.h +++ b/src/openvpn/pf-inline.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/pf.c b/src/openvpn/pf.c index 7db4ba97a80..56b6858bb3f 100644 --- a/src/openvpn/pf.c +++ b/src/openvpn/pf.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/pf.h b/src/openvpn/pf.h index e5c951f2ece..38326835bba 100644 --- a/src/openvpn/pf.h +++ b/src/openvpn/pf.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/ping-inline.h b/src/openvpn/ping-inline.h index 10291003197..2fa1d5c9a07 100644 --- a/src/openvpn/ping-inline.h +++ b/src/openvpn/ping-inline.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/ping.c b/src/openvpn/ping.c index 1af31ccb6c2..0496b72e237 100644 --- a/src/openvpn/ping.c +++ b/src/openvpn/ping.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/ping.h b/src/openvpn/ping.h index 6f060c6d654..e839ce78dd6 100644 --- a/src/openvpn/ping.h +++ b/src/openvpn/ping.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/pkcs11.c b/src/openvpn/pkcs11.c index f77d4cd36ad..6858846b9e7 100644 --- a/src/openvpn/pkcs11.c +++ b/src/openvpn/pkcs11.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/pkcs11.h b/src/openvpn/pkcs11.h index 621796dbf6f..3747d3ab230 100644 --- a/src/openvpn/pkcs11.h +++ b/src/openvpn/pkcs11.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/pkcs11_backend.h b/src/openvpn/pkcs11_backend.h index e883d0c458e..9606899f363 100644 --- a/src/openvpn/pkcs11_backend.h +++ b/src/openvpn/pkcs11_backend.h @@ -5,8 +5,8 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. - * Copyright (C) 2010 Fox Crypto B.V. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. + * Copyright (C) 2010-2017 Fox Crypto B.V. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/pkcs11_mbedtls.c b/src/openvpn/pkcs11_mbedtls.c index 874618cfebf..bdca893d4d4 100644 --- a/src/openvpn/pkcs11_mbedtls.c +++ b/src/openvpn/pkcs11_mbedtls.c @@ -5,8 +5,8 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. - * Copyright (C) 2010 Fox Crypto B.V. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. + * Copyright (C) 2010-2017 Fox Crypto B.V. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/pkcs11_openssl.c b/src/openvpn/pkcs11_openssl.c index bab4c900b68..6244cc7e6f5 100644 --- a/src/openvpn/pkcs11_openssl.c +++ b/src/openvpn/pkcs11_openssl.c @@ -5,8 +5,8 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. - * Copyright (C) 2010 Fox Crypto B.V. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. + * Copyright (C) 2010-2017 Fox Crypto B.V. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/platform.c b/src/openvpn/platform.c index 3deed32665e..952d633bb94 100644 --- a/src/openvpn/platform.c +++ b/src/openvpn/platform.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/platform.h b/src/openvpn/platform.h index a43ee13b678..62396a99d80 100644 --- a/src/openvpn/platform.h +++ b/src/openvpn/platform.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/plugin.c b/src/openvpn/plugin.c index dab9c93fcd4..17eb2d8c5c8 100644 --- a/src/openvpn/plugin.c +++ b/src/openvpn/plugin.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/plugin.h b/src/openvpn/plugin.h index 7f0cbd430c5..4ded5293d1f 100644 --- a/src/openvpn/plugin.h +++ b/src/openvpn/plugin.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/pool.c b/src/openvpn/pool.c index 8d5dc1bea1f..aa0bc2b8d78 100644 --- a/src/openvpn/pool.c +++ b/src/openvpn/pool.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/pool.h b/src/openvpn/pool.h index 5638b9f3269..c3e11909bf1 100644 --- a/src/openvpn/pool.h +++ b/src/openvpn/pool.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/proto.c b/src/openvpn/proto.c index acf35f5cb68..40e07147a58 100644 --- a/src/openvpn/proto.c +++ b/src/openvpn/proto.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/proto.h b/src/openvpn/proto.h index 1b560a3aa67..bfcb36da683 100644 --- a/src/openvpn/proto.h +++ b/src/openvpn/proto.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/proxy.c b/src/openvpn/proxy.c index 7a06038c2c7..dd327a2f080 100644 --- a/src/openvpn/proxy.c +++ b/src/openvpn/proxy.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/proxy.h b/src/openvpn/proxy.h index 892277bca2b..c20a676a836 100644 --- a/src/openvpn/proxy.h +++ b/src/openvpn/proxy.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/ps.c b/src/openvpn/ps.c index bca670c74e1..21b12cad845 100644 --- a/src/openvpn/ps.c +++ b/src/openvpn/ps.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/ps.h b/src/openvpn/ps.h index cbfe9b8765c..0fc1ee4e7bc 100644 --- a/src/openvpn/ps.h +++ b/src/openvpn/ps.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/push.c b/src/openvpn/push.c index b6e12e1f4a6..f5154756a9c 100644 --- a/src/openvpn/push.c +++ b/src/openvpn/push.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/push.h b/src/openvpn/push.h index 38cf5c1042c..86900c8b8fe 100644 --- a/src/openvpn/push.h +++ b/src/openvpn/push.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/pushlist.h b/src/openvpn/pushlist.h index 5471b1b2305..58fc8708594 100644 --- a/src/openvpn/pushlist.h +++ b/src/openvpn/pushlist.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/reliable.c b/src/openvpn/reliable.c index 36719166d8b..57cdd785408 100644 --- a/src/openvpn/reliable.c +++ b/src/openvpn/reliable.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/reliable.h b/src/openvpn/reliable.h index 84cd1e27a9a..455168a59f7 100644 --- a/src/openvpn/reliable.h +++ b/src/openvpn/reliable.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/route.c b/src/openvpn/route.c index 01c37874be7..0c93dcdf736 100644 --- a/src/openvpn/route.c +++ b/src/openvpn/route.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/route.h b/src/openvpn/route.h index dcc7ded800a..03ee8cde61f 100644 --- a/src/openvpn/route.h +++ b/src/openvpn/route.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/schedule.c b/src/openvpn/schedule.c index 4495b1e891d..610bfa42304 100644 --- a/src/openvpn/schedule.c +++ b/src/openvpn/schedule.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/schedule.h b/src/openvpn/schedule.h index bdd443f9cc7..f2a6813356d 100644 --- a/src/openvpn/schedule.h +++ b/src/openvpn/schedule.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/session_id.c b/src/openvpn/session_id.c index 029608e5f9d..b23f0f45959 100644 --- a/src/openvpn/session_id.c +++ b/src/openvpn/session_id.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/session_id.h b/src/openvpn/session_id.h index 0fb8f6ed34b..2b0ceb82471 100644 --- a/src/openvpn/session_id.h +++ b/src/openvpn/session_id.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/shaper.c b/src/openvpn/shaper.c index 05c179e6343..eb459ef1e0d 100644 --- a/src/openvpn/shaper.c +++ b/src/openvpn/shaper.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/shaper.h b/src/openvpn/shaper.h index 21b4fb67d01..d97221a5064 100644 --- a/src/openvpn/shaper.h +++ b/src/openvpn/shaper.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/sig.c b/src/openvpn/sig.c index bd473e32eea..9f4841aa4d3 100644 --- a/src/openvpn/sig.c +++ b/src/openvpn/sig.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/sig.h b/src/openvpn/sig.h index 9536a6e2df6..5783731ba0f 100644 --- a/src/openvpn/sig.h +++ b/src/openvpn/sig.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c index 516a8f663fd..ae1283250f4 100644 --- a/src/openvpn/socket.c +++ b/src/openvpn/socket.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/socket.h b/src/openvpn/socket.h index 2f70eca5c28..63e601e8fe7 100644 --- a/src/openvpn/socket.h +++ b/src/openvpn/socket.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/socks.c b/src/openvpn/socks.c index da4c8247c93..b50cac3d687 100644 --- a/src/openvpn/socks.c +++ b/src/openvpn/socks.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/socks.h b/src/openvpn/socks.h index d0b18f164fa..17e75e1b011 100644 --- a/src/openvpn/socks.h +++ b/src/openvpn/socks.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 1022fb6409f..15f62f2afd7 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -5,8 +5,8 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. - * Copyright (C) 2010 Fox Crypto B.V. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. + * Copyright (C) 2010-2017 Fox Crypto B.V. * Copyright (C) 2008-2013 David Sommerseth * * This program is free software; you can redistribute it and/or modify diff --git a/src/openvpn/ssl.h b/src/openvpn/ssl.h index a78d4621262..ed1344e7b2f 100644 --- a/src/openvpn/ssl.h +++ b/src/openvpn/ssl.h @@ -5,8 +5,8 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. - * Copyright (C) 2010 Fox Crypto B.V. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. + * Copyright (C) 2010-2017 Fox Crypto B.V. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/ssl_backend.h b/src/openvpn/ssl_backend.h index b36451248e0..206400ffd1f 100644 --- a/src/openvpn/ssl_backend.h +++ b/src/openvpn/ssl_backend.h @@ -5,8 +5,8 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. - * Copyright (C) 2010 Fox Crypto B.V. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. + * Copyright (C) 2010-2017 Fox Crypto B.V. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/ssl_common.h b/src/openvpn/ssl_common.h index 018da27e37a..9a16d77e2be 100644 --- a/src/openvpn/ssl_common.h +++ b/src/openvpn/ssl_common.h @@ -5,8 +5,8 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. - * Copyright (C) 2010 Fox Crypto B.V. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. + * Copyright (C) 2010-2017 Fox Crypto B.V. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/ssl_mbedtls.c b/src/openvpn/ssl_mbedtls.c index b6b600d1bb8..5c84e300505 100644 --- a/src/openvpn/ssl_mbedtls.c +++ b/src/openvpn/ssl_mbedtls.c @@ -5,8 +5,8 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. - * Copyright (C) 2010 Fox Crypto B.V. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. + * Copyright (C) 2010-2017 Fox Crypto B.V. * Copyright (C) 2006-2010, Brainspark B.V. * * This program is free software; you can redistribute it and/or modify diff --git a/src/openvpn/ssl_mbedtls.h b/src/openvpn/ssl_mbedtls.h index dfd2ec9a249..1bc53ce8e26 100644 --- a/src/openvpn/ssl_mbedtls.h +++ b/src/openvpn/ssl_mbedtls.h @@ -5,8 +5,8 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. - * Copyright (C) 2010 Fox Crypto B.V. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. + * Copyright (C) 2010-2017 Fox Crypto B.V. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c index 1f156d6866e..eae1e22669a 100644 --- a/src/openvpn/ssl_openssl.c +++ b/src/openvpn/ssl_openssl.c @@ -5,8 +5,8 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. - * Copyright (C) 2010 Fox Crypto B.V. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. + * Copyright (C) 2010-2017 Fox Crypto B.V. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/ssl_openssl.h b/src/openvpn/ssl_openssl.h index 5f7771366ba..c64c65f8122 100644 --- a/src/openvpn/ssl_openssl.h +++ b/src/openvpn/ssl_openssl.h @@ -5,8 +5,8 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. - * Copyright (C) 2010 Fox Crypto B.V. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. + * Copyright (C) 2010-2017 Fox Crypto B.V. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/ssl_verify.c b/src/openvpn/ssl_verify.c index e90120291c9..334eb2923a4 100644 --- a/src/openvpn/ssl_verify.c +++ b/src/openvpn/ssl_verify.c @@ -5,8 +5,8 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. - * Copyright (C) 2010 Fox Crypto B.V. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. + * Copyright (C) 2010-2017 Fox Crypto B.V. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/ssl_verify.h b/src/openvpn/ssl_verify.h index 45ce3b0ac8e..ffab2189ba9 100644 --- a/src/openvpn/ssl_verify.h +++ b/src/openvpn/ssl_verify.h @@ -5,8 +5,8 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. - * Copyright (C) 2010 Fox Crypto B.V. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. + * Copyright (C) 2010-2017 Fox Crypto B.V. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/ssl_verify_backend.h b/src/openvpn/ssl_verify_backend.h index 34edffb8381..c4330ba3d2c 100644 --- a/src/openvpn/ssl_verify_backend.h +++ b/src/openvpn/ssl_verify_backend.h @@ -5,8 +5,8 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. - * Copyright (C) 2010 Fox Crypto B.V. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. + * Copyright (C) 2010-2017 Fox Crypto B.V. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/ssl_verify_mbedtls.c b/src/openvpn/ssl_verify_mbedtls.c index b8fbee89d03..f01569fdaaf 100644 --- a/src/openvpn/ssl_verify_mbedtls.c +++ b/src/openvpn/ssl_verify_mbedtls.c @@ -5,8 +5,8 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. - * Copyright (C) 2010 Fox Crypto B.V. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. + * Copyright (C) 2010-2017 Fox Crypto B.V. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/ssl_verify_mbedtls.h b/src/openvpn/ssl_verify_mbedtls.h index a5252ffe6ad..3c7107352d1 100644 --- a/src/openvpn/ssl_verify_mbedtls.h +++ b/src/openvpn/ssl_verify_mbedtls.h @@ -5,8 +5,8 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. - * Copyright (C) 2010 Fox Crypto B.V. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. + * Copyright (C) 2010-2017 Fox Crypto B.V. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/ssl_verify_openssl.c b/src/openvpn/ssl_verify_openssl.c index 04880d7f60c..e9692a09b65 100644 --- a/src/openvpn/ssl_verify_openssl.c +++ b/src/openvpn/ssl_verify_openssl.c @@ -5,8 +5,8 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. - * Copyright (C) 2010 Fox Crypto B.V. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. + * Copyright (C) 2010-2017 Fox Crypto B.V. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/ssl_verify_openssl.h b/src/openvpn/ssl_verify_openssl.h index 934c1e9a7c9..1db6fe6f3a6 100644 --- a/src/openvpn/ssl_verify_openssl.h +++ b/src/openvpn/ssl_verify_openssl.h @@ -5,8 +5,8 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. - * Copyright (C) 2010 Fox Crypto B.V. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. + * Copyright (C) 2010-2017 Fox Crypto B.V. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/status.c b/src/openvpn/status.c index cca623f7783..e47f35c2707 100644 --- a/src/openvpn/status.c +++ b/src/openvpn/status.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/status.h b/src/openvpn/status.h index 01fe33e730d..590ae41eef9 100644 --- a/src/openvpn/status.h +++ b/src/openvpn/status.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/syshead.h b/src/openvpn/syshead.h index 2f048966e9a..a1b60476b8c 100644 --- a/src/openvpn/syshead.h +++ b/src/openvpn/syshead.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/tls_crypt.c b/src/openvpn/tls_crypt.c index 8173467d9ff..c227b098f17 100644 --- a/src/openvpn/tls_crypt.c +++ b/src/openvpn/tls_crypt.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2016 Fox Crypto B.V. + * Copyright (C) 2016-2017 Fox Crypto B.V. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/tls_crypt.h b/src/openvpn/tls_crypt.h index 2c7831f5b3b..47f75d0f7fd 100644 --- a/src/openvpn/tls_crypt.h +++ b/src/openvpn/tls_crypt.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2016 Fox Crypto B.V. + * Copyright (C) 2016-2017 Fox Crypto B.V. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index 8dbdd4f9c53..f8128449b8b 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/tun.h b/src/openvpn/tun.h index bc499bfa9ea..f4b600c22fb 100644 --- a/src/openvpn/tun.h +++ b/src/openvpn/tun.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/win32.c b/src/openvpn/win32.c index 88fa3ecb28e..e26f54d8093 100644 --- a/src/openvpn/win32.c +++ b/src/openvpn/win32.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpn/win32.h b/src/openvpn/win32.h index 5d2e1fb13bb..4ee44fd3606 100644 --- a/src/openvpn/win32.h +++ b/src/openvpn/win32.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpnserv/Makefile.am b/src/openvpnserv/Makefile.am index 58ecd91198f..21efc7c5262 100644 --- a/src/openvpnserv/Makefile.am +++ b/src/openvpnserv/Makefile.am @@ -5,7 +5,7 @@ # packet encryption, packet authentication, and # packet compression. # -# Copyright (C) 2002-2010 OpenVPN Technologies, Inc. +# Copyright (C) 2002-2017 OpenVPN Technologies, Inc. # Copyright (C) 2006-2012 Alon Bar-Lev # diff --git a/src/openvpnserv/automatic.c b/src/openvpnserv/automatic.c index dc57cada3a4..6be6c6dfae3 100644 --- a/src/openvpnserv/automatic.c +++ b/src/openvpnserv/automatic.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpnserv/common.c b/src/openvpnserv/common.c index c7abe0d3969..3b9b396b045 100644 --- a/src/openvpnserv/common.c +++ b/src/openvpnserv/common.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2011 Heiko Hund + * Copyright (C) 2011-2017 Heiko Hund * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpnserv/interactive.c b/src/openvpnserv/interactive.c index 9cbe25c4d7f..dbe2b9b5872 100644 --- a/src/openvpnserv/interactive.c +++ b/src/openvpnserv/interactive.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2012 Heiko Hund + * Copyright (C) 2012-2017 Heiko Hund * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/openvpnserv/service.h b/src/openvpnserv/service.h index f907e69c355..b1130c90677 100644 --- a/src/openvpnserv/service.h +++ b/src/openvpnserv/service.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2013 Heiko Hund + * Copyright (C) 2013-2017 Heiko Hund * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am index 17b72b94460..ca90496302c 100644 --- a/src/plugins/Makefile.am +++ b/src/plugins/Makefile.am @@ -5,7 +5,7 @@ # packet encryption, packet authentication, and # packet compression. # -# Copyright (C) 2002-2010 OpenVPN Technologies, Inc. +# Copyright (C) 2002-2017 OpenVPN Technologies, Inc. # Copyright (C) 2006-2012 Alon Bar-Lev # diff --git a/src/plugins/auth-pam/auth-pam.c b/src/plugins/auth-pam/auth-pam.c index 458141120b9..d3e2c89d834 100644 --- a/src/plugins/auth-pam/auth-pam.c +++ b/src/plugins/auth-pam/auth-pam.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/plugins/auth-pam/utils.c b/src/plugins/auth-pam/utils.c index e4f4d195cdc..4f8fb0ad67f 100644 --- a/src/plugins/auth-pam/utils.c +++ b/src/plugins/auth-pam/utils.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/plugins/auth-pam/utils.h b/src/plugins/auth-pam/utils.h index 810f7b9632d..fbc9705b40b 100644 --- a/src/plugins/auth-pam/utils.h +++ b/src/plugins/auth-pam/utils.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/src/plugins/down-root/down-root.c b/src/plugins/down-root/down-root.c index c940d61ae42..ae85ecba25f 100644 --- a/src/plugins/down-root/down-root.c +++ b/src/plugins/down-root/down-root.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2013 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * Copyright (C) 2013 David Sommerseth * * This program is free software; you can redistribute it and/or modify diff --git a/tests/Makefile.am b/tests/Makefile.am index e55928b5747..0795680c222 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -5,7 +5,7 @@ # packet encryption, packet authentication, and # packet compression. # -# Copyright (C) 2002-2010 OpenVPN Technologies, Inc. +# Copyright (C) 2002-2017 OpenVPN Technologies, Inc. # Copyright (C) 2006-2012 Alon Bar-Lev # diff --git a/tests/unit_tests/openvpn/mock_msg.c b/tests/unit_tests/openvpn/mock_msg.c index b6f1a46ec9b..eb0d5e9b7db 100644 --- a/tests/unit_tests/openvpn/mock_msg.c +++ b/tests/unit_tests/openvpn/mock_msg.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2016 Fox Crypto B.V. + * Copyright (C) 2016-2017 Fox Crypto B.V. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/tests/unit_tests/openvpn/mock_msg.h b/tests/unit_tests/openvpn/mock_msg.h index 5d93a1a33e7..e0933c69f32 100644 --- a/tests/unit_tests/openvpn/mock_msg.h +++ b/tests/unit_tests/openvpn/mock_msg.h @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2016 Fox Crypto B.V. + * Copyright (C) 2016-2017 Fox Crypto B.V. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/tests/unit_tests/openvpn/test_buffer.c b/tests/unit_tests/openvpn/test_buffer.c index 5d254375bea..5158eb87321 100644 --- a/tests/unit_tests/openvpn/test_buffer.c +++ b/tests/unit_tests/openvpn/test_buffer.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2016 Fox Crypto B.V. + * Copyright (C) 2016-2017 Fox Crypto B.V. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 diff --git a/tests/unit_tests/openvpn/test_tls_crypt.c b/tests/unit_tests/openvpn/test_tls_crypt.c index 3650aa869e8..7b014e072fa 100644 --- a/tests/unit_tests/openvpn/test_tls_crypt.c +++ b/tests/unit_tests/openvpn/test_tls_crypt.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2016 Fox Crypto B.V. + * Copyright (C) 2016-2017 Fox Crypto B.V. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 From 203d7c8b1fdab065aa0b2a522abe00dc39fa433a Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Fri, 23 Dec 2016 17:07:44 +0100 Subject: [PATCH 452/643] docs: Further enhance the documentation related to SWEET32 The git master/2.4 code lacked some useful information about the changes to --reneg-bytes, SWEET32 and weak ciphers (less than 128-bits cipher blocks) v2 - Fixed a couple of grammar/typo issues Signed-off-by: David Sommerseth Acked-by: Steffan Karger Message-Id: <1482509264-24550-1-git-send-email-davids@openvpn.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13682.html (cherry picked from commit a256aee8e70ceb7059b9da69bc3e7cccbd094916) --- Changes.rst | 6 ++++++ doc/openvpn.8 | 13 ++++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/Changes.rst b/Changes.rst index 8508fa3fa4d..df5ccb631a2 100644 --- a/Changes.rst +++ b/Changes.rst @@ -182,6 +182,12 @@ Deprecated features User-visible Changes -------------------- +- When using ciphers with cipher blocks less than 128-bits + OpenVPN will complain loudly if the configuration uses ciphers considered + weak, such as the SWEET32 attack vector. In such scenarios, OpenVPN will by + default do a renegotiation for each 64MB of transported data (``--reneg-bytes``). + This renegotiation can be disabled, but is HIGHLY DISCOURAGED. + - For certificate DNs with duplicate fields, e.g. "OU=one,OU=two", both fields are now exported to the environment, where each second and later occurrence of a field get _$N appended to it's field name, starting at N=1. For the diff --git a/doc/openvpn.8 b/doc/openvpn.8 index b1ca9ed9cf7..b1bb39c720c 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -4876,11 +4876,18 @@ such as TCP expect this role to be left to them. .B \-\-reneg\-bytes n Renegotiate data channel key after .B n -bytes sent or received (disabled by default). +bytes sent or received (disabled by default with an exception, see below). OpenVPN allows the lifetime of a key -to be expressed as a number of bytes encrypted/decrypted, a number of packets, or -a number of seconds. A key renegotiation will be forced +to be expressed as a number of bytes encrypted/decrypted, a number of packets, +or a number of seconds. A key renegotiation will be forced if any of these three criteria are met by either peer. + +If using ciphers with cipher block sizes less than 128-bits, \-\-reneg\-bytes is +set to 64MB by default, unless it is explicitly disabled by setting the value to +0, but this is +.B HIGHLY DISCOURAGED +as this is designed to add some protection against the SWEET32 attack vector. +For more information see the \-\-cipher option. .\"********************************************************* .TP .B \-\-reneg\-pkts n From 9b42853eea285ad54aed8b466e7f5a789a943933 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sun, 25 Dec 2016 23:38:25 +0100 Subject: [PATCH 453/643] Document that RSA_SIGN can also request TLS 1.2 signatures Ever since we support TLS 1.2 (OpenVPN 2.3.3+), the RSA_SIGN might not only request MD5-SHA1 'TLS signatures', but also other variants. Document this by updating the implementation hints, and explicitly stating that we expect a PKCS#1 1.5 signature. Trac: #764 Signed-off-by: Steffan Karger Acked-by: Arne Schwabe Message-Id: <1482705505-20302-1-git-send-email-steffan@karger.me> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13714.html Signed-off-by: David Sommerseth (cherry picked from commit 1e36b814073c0f56c77e4922cc105f00b8558e7e) --- doc/management-notes.txt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/doc/management-notes.txt b/doc/management-notes.txt index dd870ebc75a..29c3aadf2ab 100644 --- a/doc/management-notes.txt +++ b/doc/management-notes.txt @@ -773,8 +773,9 @@ via a notification as follows: >RSA_SIGN:[BASE64_DATA] -The management interface client should then sign BASE64_DATA -using the private key and return the SSL signature as follows: +The management interface client should then create a PKCS#1 v1.5 signature of +the (decoded) BASE64_DATA using the private key and return the SSL signature as +follows: rsa-sig [BASE64_SIG_LINE] @@ -783,8 +784,8 @@ rsa-sig . END -Base64 encoded output of RSA_sign(NID_md5_sha1,... will provide a -correct signature. +Base64 encoded output of RSA_private_encrypt() (OpenSSL) or mbedtls_pk_sign() +(mbed TLS) will provide a correct signature. This capability is intended to allow the use of arbitrary cryptographic service providers with OpenVPN via the management interface. From ebd24617f97c63fbe40a07e855ae3469f96474d7 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sun, 25 Dec 2016 23:02:14 +0100 Subject: [PATCH 454/643] man: encourage user to read on about --tls-crypt As suggested by krzee in trac #790, refer to the --tls-crypt option form the --tls-auth section of the man page, to encourage users to check out the --tls-crypt feature. Trac: #790 Signed-off-by: Steffan Karger Acked-by: David Sommerseth Message-Id: <1482703334-18949-1-git-send-email-steffan@karger.me> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13713.html Signed-off-by: David Sommerseth (cherry picked from commit 403dfe1bfdbdf6e5f8abac3401a96852562aec54) --- doc/openvpn.8 | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index b1bb39c720c..eb85d233060 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -5036,6 +5036,11 @@ key file used with .B \-\-tls\-auth gives a peer nothing more than the power to initiate a TLS handshake. It is not used to encrypt or authenticate any tunnel data. + +Use +.B \-\-tls\-crypt +instead if you want to use the key file to not only authenticate, but also +encrypt the TLS control channel. .\"********************************************************* .TP .B \-\-tls\-crypt keyfile From 554504c5e2692c3e6cfd3feae10c9d5c8ec363f8 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Sun, 25 Dec 2016 11:59:19 +0100 Subject: [PATCH 455/643] Remove IV_RGI6=1 peer-info signalling. This is no longer needed, as anything 2.4 or later is known to have this functionality, and IV_VER can be used to detect this on the server. Signed-off-by: Gert Doering Acked-by: Steffan Karger Acked-by: David Sommerseth Message-Id: <20161225105919.25792-1-gert@greenie.muc.de> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13706.html Signed-off-by: David Sommerseth (cherry picked from commit 392c9e47f6418612bc2a4932faf22bb711e65a54) --- src/openvpn/ssl.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 15f62f2afd7..cff40529f3c 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -2270,9 +2270,6 @@ push_peer_info(struct buffer *buf, struct tls_session *session) comp_generate_peer_info_string(&session->opt->comp_options, &out); #endif - /* support for redirecting IPv6 gateway */ - buf_printf(&out, "IV_RGI6=1\n"); - if (session->opt->push_peer_info_detail >= 2) { /* push mac addr */ From febeb485a2e9c5ca67705c95b088f70e3e5d5fdc Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Mon, 26 Dec 2016 13:26:43 +0100 Subject: [PATCH 456/643] man: Remove references to no longer present IV_RGI6 peer-info Commit 554504c5e2692c3e6cfd3f removed the IV_RGI6 peer-info singaling but forgot to update the man page. Removing this reference as well. Signed-off-by: David Sommerseth Acked-by: Arne Schwabe Message-Id: <1482755203-23968-1-git-send-email-davids@openvpn.net> URL: http://www.mail-archive.com/search?l=mid&q=1482755203-23968-1-git-send-email-davids@openvpn.net (cherry picked from commit 4ba943b02aa728aa077a0b3be79626b0f20ea8a7) --- doc/openvpn.8 | 4 ---- 1 file changed, 4 deletions(-) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index eb85d233060..7bd6d9d6b64 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -2989,10 +2989,6 @@ IV_LZO_STUB=1 -- if client was built with LZO stub capability IV_LZ4=1 -- if the client supports LZ4 compressions. -IV_RGI6=1 -- if the client supports -.B \-\-redirect\-gateway -for ipv6 - IV_PROTO=2 -- if the client supports peer-id floating mechansim IV_NCP=2 -- negotiable ciphers, client supports From 1fd40c781882426c4ed0770725a58d043c000816 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Mon, 26 Dec 2016 20:15:43 +0100 Subject: [PATCH 457/643] Textual fixes for Changes.rst We will likely refer many people to the Changes.rst file once we've released 2.4. This commits tries to polish the language a bit, and adds two real changes: - Remove duplicate mention of the changes --tls-cipher defaults - Move the 'redirect-gateway' behavioural change from 'features' to 'behavioural changes'. v2 - On the fly commit changes, based on comments from Selva Nair. DS also added a few minor corrections on top of that. Signed-off-by: Steffan Karger Acked-by: David Sommerseth Message-Id: <1482779743-9548-1-git-send-email-steffan@karger.me> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13732.html Signed-off-by: David Sommerseth (cherry picked from commit f38942d1440575e23d9f8713db435b434381486e) --- Changes.rst | 138 ++++++++++++++++++++++++++-------------------------- 1 file changed, 68 insertions(+), 70 deletions(-) diff --git a/Changes.rst b/Changes.rst index df5ccb631a2..7ffd89e0e4a 100644 --- a/Changes.rst +++ b/Changes.rst @@ -4,19 +4,22 @@ Version 2.4.0 New features ------------ -Peer ID support - Added new packet format P_DATA_V2, which includes peer-id. If - server and client support it, client sends all data packets in - the new format. When data packet arrives, server identifies peer +Seamless client IP/port floating + Added new packet format P_DATA_V2, which includes peer-id. If both the + server and client support it, the client sends all data packets in + the new format. When a data packet arrives, the server identifies peer by peer-id. If peer's ip/port has changed, server assumes that client has floated, verifies HMAC and updates ip/port in internal structs. + This allows the connection to be immediatly restored, instead of requiring + a TLS handshake before the server accepts packets from the new client + ip/port. -Cipher negotiation - Data channel ciphers are now by default negotiated. If a client advertises - support for Negotiable Crypto Parameters (NCP), the server will choose a - cipher (by default AES-256-GCM) for the data channel, and tell the client - to use that cipher. Data channel cipher negotiation can be controlled - using ``--ncp-ciphers`` and ``--ncp-disable``. +Data channel cipher negotiation + Data channel ciphers (``--cipher``) are now by default negotiated. If a + client advertises support for Negotiable Crypto Parameters (NCP), the + server will choose a cipher (by default AES-256-GCM) for the data channel, + and tell the client to use that cipher. Data channel cipher negotiation + can be controlled using ``--ncp-ciphers`` and ``--ncp-disable``. A more limited version also works in client-to-server and server-to-client scenarios where one of the end points uses a v2.4 client or server and the @@ -33,29 +36,29 @@ Cipher negotiation AEAD (GCM) data channel cipher support The data channel now supports AEAD ciphers (currently only GCM). The AEAD - packet format has a smaller overhead than the CBC packet format, (e.g. 20 - bytes per packet for AES-128-GCM instead of 36 bytes per packet for - AES-128-CBC + HMAC-SHA1). + packet format has a smaller crypto overhead than the CBC packet format, + (e.g. 20 bytes per packet for AES-128-GCM instead of 36 bytes per packet + for AES-128-CBC + HMAC-SHA1). ECDH key exchange The TLS control channel now supports for elliptic curve diffie-hellmann key exchange (ECDH). -Dualstack client connect +Dualstack round-robin DNS client connect Instead of only using the first address of each ``--remote`` OpenVPN will now try all addresses (IPv6 and IPv4) of a ``--remote`` entry. Support for providing IPv6 DNS servers - A new DHCP sub-options ``DNS6`` is added alongside with the already existing - ``DNS`` sub-option. This is used to provide DNS resolvers available over - IPv6. This will be pushed to clients and `` --up`` scripts and ``--plugin`` - can act upon it through the ``foreign_option_`` environment variables. + A new DHCP sub-option ``DNS6`` is added alongside with the already existing + ``DNS`` sub-option. This is used to provide DNS resolvers available over + IPv6. This may be pushed to clients where `` --up`` scripts and ``--plugin`` + can act upon it through the ``foreign_option_`` environment variables. - Support for the Windows client picking up this new sub-option is added, - however IPv6 DNS resolvers needs to be configured via ``netsh`` which requires - administrator privileges if the new interactive services on Windows is not - being used. If the interactive services is used, this service will execute - ``netsh`` in the background with the proper privileges. + Support for the Windows client picking up this new sub-option is added, + however IPv6 DNS resolvers need to be configured via ``netsh`` which requires + administrator privileges unless the new interactive services on Windows is + being used. If the interactive service is used, this service will execute + ``netsh`` in the background with the proper privileges. New improved Windows Background service The new OpenVPNService is based on openvpnserv2, a complete rewrite of the OpenVPN @@ -79,50 +82,44 @@ New interactive Windows service files under %USERPROFILE%\\OpenVPN\\config for use with the interactive service. -redirect-gateway - if no flags are given, and the interactive service is used, "def1" - is implicitly set (because "delete and later reinstall the existing - default route" does not work well here). If not using the service, - the old behaviour is kept. - redirect-gateway ipv6 OpenVPN has now feature parity between IPv4 and IPv6 for redirect gateway including the handling of overlapping IPv6 routes with - IPv6 remote VPN server address + IPv6 remote VPN server address. LZ4 Compression and pushable compression Additionally to LZO compression OpenVPN now also supports LZ4 compression. Compression options are now pushable from the server. -pull-filter +Filter pulled options client-side: pull-filter New option to explicitly allow or reject options pushed by the server. May be used multiple times and is applied in the order specified. -push-remove - new option to remove options on a per-client basis from the "push" list - (more fine-grained than ``--push-reset``) +Per-client remove push options: push-remove + New option to remove options on a per-client basis from the "push" list + (more fine-grained than ``--push-reset``). Http proxy password inside config file Http proxy passwords can be specified with the inline file option ```` .. ```` -Windows version +Windows version detection Windows version is detected, logged and possibly signalled to server - (IV_PLAT_VER= if ``--push-peer-info`` is set on client) + (IV_PLAT_VER= if ``--push-peer-info`` is set on client). Authentication tokens - In situations where it is not suitable to save users passwords on the client - OpenVPN have since v2.3 had support for --auth-token. This option is + In situations where it is not suitable to save user passwords on the client, + OpenVPN has support for pushing a --auth-token since v2.3. This option is pushed from the server to the client with a token value to be used instead of the users password. For this to work, the authentication plug-in would need to implement this support as well. In OpenVPN 2.4 --auth-gen-token is introduced, which will allow the OpenVPN server to generate a random token and push it to the client without any changes to the authentication modules. When the clients need to re-authenticate the OpenVPN server will - instead of sending the re-authentication request to the authentication - module do the authentication internally. This feature is especially - useful in configurations which adds One Time Password (OTP) authentication - schemes, as this allows the tunnel to be renegotiated regularly without + do the authentication internally, instead of sending the re-authentication + request to the authentication module . This feature is especially + useful in configurations which use One Time Password (OTP) authentication + schemes, as this allows the tunnel keys to be renegotiated regularly without any need to supply new OTP codes. keying-material-exporter @@ -130,12 +127,12 @@ keying-material-exporter derived from existing TLS channel. Mac OS X Keychain management client - added contrib/keychain-mcd which allows to use Mac OS X keychain - certificates with OpenVPN + Added contrib/keychain-mcd which allows to use Mac OS X keychain + certificates with OpenVPN. Android platform support Support for running on Android using Android's VPNService API has been added. - See doc/android.txt for more details. This support is primarily used in + See doc/android.txt for more details. This support is primarily used in the OpenVPN for Android app (https://github.com/schwabe/ics-openvpn) AIX platform support @@ -150,7 +147,7 @@ Control channel encryption (``--tls-crypt``) Asynchronous push reply Plug-ins providing support for deferred authentication can benefit from a more responsive authentication where the server sends PUSH_REPLY immediately once - the authentication result is ready instead of waiting for the the client to + the authentication result is ready, instead of waiting for the the client to to send PUSH_REQUEST once more. This requires OpenVPN to be built with ``./configure --enable-async-push``. This is a compile-time only switch. @@ -169,23 +166,23 @@ Deprecated features that would previously be accepted. If this occurs, OpenVPN will log the crypto library's error description. -- ``--tls-remote`` is removed in 2.4, as indicated in the 2.3 man-pages. A similar - functionality is provided via ``--verify-x509-name`` which does the same job in +- ``--tls-remote`` is removed in 2.4, as indicated in the 2.3 man-pages. Similar + functionality is provided via ``--verify-x509-name``, which does the same job in a better way. -- ``--compat-names`` and ``--no-name-remapping`` was deprecated in 2.3 and will +- ``--compat-names`` and ``--no-name-remapping`` were deprecated in 2.3 and will be removed in 2.5. All scripts and plug-ins depending on the old non-standard X.509 subject formatting must be updated to the standardized formatting. See the man page for more information. -- ``--no-iv`` is deprecated in 2.4 and will be remove in 2.5. +- ``--no-iv`` is deprecated in 2.4 and will be removed in 2.5. User-visible Changes -------------------- -- When using ciphers with cipher blocks less than 128-bits +- When using ciphers with cipher blocks less than 128-bits, OpenVPN will complain loudly if the configuration uses ciphers considered weak, such as the SWEET32 attack vector. In such scenarios, OpenVPN will by - default do a renegotiation for each 64MB of transported data (``--reneg-bytes``). + default renegotiate for each 64MB of transported data (``--reneg-bytes``). This renegotiation can be disabled, but is HIGHLY DISCOURAGED. - For certificate DNs with duplicate fields, e.g. "OU=one,OU=two", both fields @@ -195,18 +192,14 @@ User-visible Changes Note that this breaks setups that rely on the fact that OpenVPN would previously (incorrectly) only export the last occurence of a field. -- proto udp and proto tcp specify to use IPv4 and IPv6. The new - options proto udp4 and tcp4 specify to use IPv4 only. +- ``proto udp`` and ``proto tcp`` now use both IPv4 and IPv6. The new + options ``proto udp4`` and ``proto tcp4`` use IPv4 only. - ``--sndbuf`` and ``--recvbuf`` default now to OS defaults instead of 64k -- OpenVPN exits with an error if an option has extra parameters; +- OpenVPN exits with an error if an option has extra parameters; previously they were silently ignored -- The default of ``--tls-cipher`` is now "DEFAULT:!EXP:!PSK:!SRP:!kRSA" - instead of "DEFAULT" to always select perfect forward security - cipher suites - - ``--tls-auth`` always requires OpenVPN static key files and will no longer work with free form files @@ -230,11 +223,11 @@ User-visible Changes - mbed TLS builds: minimum RSA key size is now 2048 bits. Shorter keys will not be accepted, both local and from the peer. -- ``--connect-timeout`` specifies now the timeout until the first TLS packet +- ``--connect-timeout`` now specifies the timeout until the first TLS packet is received (identical to ``--server-poll-timeout``) and this timeout now includes the removed socks proxy timeout and http proxy timeout. - In ``--static`` mode connect-timeout specifies the timeout for TCP and + In ``--static`` mode ``connect-timeout`` specifies the timeout for TCP and proxy connection establishment - ``--connect-retry-max`` now specifies the maximum number of unsuccessful @@ -262,26 +255,31 @@ User-visible Changes capable. The ``--tun-ipv6`` option is ignored (behaves like it is always on). -- On the client side recursively routed packets, which have same destination - as the VPN server, are dropped. This could be disabled with +- On the client side recursively routed packets, which have the same destination + as the VPN server, are dropped. This can be disabled with --allow-recursive-routing option. -- on Windows, when the ``--register-dns`` option is set, OpenVPN no longer +- On Windows, when the ``--register-dns`` option is set, OpenVPN no longer restarts the ``dnscache`` service - this had unwanted side effects, and seems to be no longer necessary with currently supported Windows versions. +- If no flags are given, and the interactive Windows service is used, "def1" + is implicitly set (because "delete and later reinstall the existing + default route" does not work well here). If not using the service, + the old behaviour is kept. + - OpenVPN now reloads a CRL only if the modication time or file size has changed, instead of for each new connection. This reduces the connection setup time, in particular when using large CRLs. -- OpenVPN now ships with more up-to-date systemd unit files which takes advantage +- OpenVPN now ships with more up-to-date systemd unit files which take advantage of the improved service management as well as some hardening steps. The configuration files are picked up from the /etc/openvpn/server/ and /etc/openvpn/client/ directories (depending on unit file). This also avoids these new unit files and how they work to collide with older pre-existing unit files. -- using ``--no-iv`` (which is generally not a recommended setup) will +- Using ``--no-iv`` (which is generally not a recommended setup) will require explicitly disabling NCP with ``--disable-ncp``. This is intentional because NCP will by default use AES-GCM, which requires an IV - so we want users of that option to consciously reconsider. @@ -299,8 +297,8 @@ Maintainer-visible changes files instead of older ones, to provide a unified behaviour across systemd based Linux distributions. -- With OpenVPN v2.4, the project have moved over to depend on and actively use - the official C99 standard (-std=c99). This may on some older compiler/libc - headers combinations fail. On most of these situations it is recommended to - do use -std=gnu99 in CFLAGS. This is known to be needed when doing +- With OpenVPN v2.4, the project has moved over to depend on and actively use + the official C99 standard (-std=c99). This may fail on some older compiler/libc + header combinations. In most of these situations it is recommended to + use -std=gnu99 in CFLAGS. This is known to be needed when doing i386/i686 builds on RHEL5. From b83ff52a594ce1e8ff2d63533819206f67aa5dea Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Tue, 27 Dec 2016 11:52:24 +0100 Subject: [PATCH 458/643] build: Ensure Changes.rst is shipped and installed as a doc file Signed-off-by: David Sommerseth Acked-by: Arne Schwabe Message-Id: <1482835944-563-1-git-send-email-davids@openvpn.net> URL: http://www.mail-archive.com/search?l=mid&q=1482835944-563-1-git-send-email-davids@openvpn.net (cherry picked from commit 7fb22ea0bc483b5a128bcc23ce9a156c8fadac3a) --- Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile.am b/Makefile.am index d1a72dab171..1197aadb3dc 100644 --- a/Makefile.am +++ b/Makefile.am @@ -60,6 +60,7 @@ dist_doc_DATA = \ README \ README.IPv6 \ README.polarssl \ + Changes.rst \ COPYRIGHT.GPL \ COPYING From 307abe7b32e951ece58c7964b3fa72536aee6724 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Mon, 26 Dec 2016 13:46:05 +0100 Subject: [PATCH 459/643] Preparing OpenVPN v2.4.0 release Signed-off-by: David Sommerseth --- ChangeLog | 17 +++++++++++++++++ version.m4 | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 8ae08637f6e..9ecf4f0a081 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,23 @@ OpenVPN Change Log Copyright (C) 2002-2017 OpenVPN Technologies, Inc. +2016.12.26 -- Version 2.4.0 +David Sommerseth (5): + dev-tools: Added script for updating copyright years in files + Update copyrights + docs: Further enhance the documentation related to SWEET32 + man: Remove references to no longer present IV_RGI6 peer-info + build: Ensure Changes.rst is shipped and installed as a doc file + +Gert Doering (1): + Remove IV_RGI6=1 peer-info signalling. + +Steffan Karger (3): + Document that RSA_SIGN can also request TLS 1.2 signatures + man: encourage user to read on about --tls-crypt + Textual fixes for Changes.rst + + 2016.12.16 -- Version 2.4_rc2 David Sommerseth (9): Fix wrong configure.ac parsing of --enable-async-push diff --git a/version.m4 b/version.m4 index a8496f4edee..3238d0bb002 100644 --- a/version.m4 +++ b/version.m4 @@ -3,7 +3,7 @@ define([PRODUCT_NAME], [OpenVPN]) define([PRODUCT_TARNAME], [openvpn]) define([PRODUCT_VERSION_MAJOR], [2]) define([PRODUCT_VERSION_MINOR], [4]) -define([PRODUCT_VERSION_PATCH], [_rc2]) +define([PRODUCT_VERSION_PATCH], [.0]) m4_append([PRODUCT_VERSION], [PRODUCT_VERSION_MAJOR]) m4_append([PRODUCT_VERSION], [PRODUCT_VERSION_MINOR], [[.]]) m4_append([PRODUCT_VERSION], [PRODUCT_VERSION_PATCH], [[]]) From bf72ae68c05922c289056f2f851ed36014449cdf Mon Sep 17 00:00:00 2001 From: Selva Nair Date: Tue, 3 Jan 2017 16:42:18 -0500 Subject: [PATCH 460/643] Fix push options digest update Trac: #812 Signed-off-by: Selva Nair Acked-by: Steffan Karger Message-Id: <1483479738-17672-1-git-send-email-selva.nair@gmail.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13816.html Signed-off-by: Gert Doering (cherry picked from commit a5dbf8c8dab23c47407c3f833c4f4aae52408af1) --- src/openvpn/push.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openvpn/push.c b/src/openvpn/push.c index f5154756a9c..c9c04a630c9 100644 --- a/src/openvpn/push.c +++ b/src/openvpn/push.c @@ -692,8 +692,8 @@ push_update_digest(md_ctx_t *ctx, struct buffer *buf, const struct options *opt) { continue; } + md_ctx_update(ctx, (const uint8_t *) line, strlen(line)+1); } - md_ctx_update(ctx, (const uint8_t *) line, strlen(line)+1); } int From 6650911256b2e636b4a2d754cfe60e949f213f91 Mon Sep 17 00:00:00 2001 From: Gisle Vanem Date: Mon, 2 Jan 2017 17:17:51 +0100 Subject: [PATCH 461/643] Crash in options.c When compiling with --disable-crypto, openvpn would crash on --help as commit 5d429efd97 introduce and extra %d into the "usage_message" string but forgot to add it to the #ifndef ENABLE_CRYPTO fprintf() call. Acked-by: Gert Doering Message-Id: <9d41f9dd-a587-5c1e-2e0d-ebb6c921f4ae@yahoo.no> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13808.html Signed-off-by: Gert Doering (cherry picked from commit 49629380a7bdba25c24c9d410b79946fe29249f0) --- src/openvpn/options.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/openvpn/options.c b/src/openvpn/options.c index bfedb6ae06e..5df2dba2737 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -4080,6 +4080,7 @@ usage(void) fprintf(fp, usage_message, title_string, o.ce.connect_retry_seconds, + o.ce.connect_retry_seconds_max, o.ce.local_port, o.ce.remote_port, TUN_MTU_DEFAULT, TAP_MTU_EXTRA_DEFAULT, o.verbosity); From 139cd1b14c57501bee36c1ec1dc5a037617ec29e Mon Sep 17 00:00:00 2001 From: Selva Nair Date: Tue, 3 Jan 2017 15:38:03 -0500 Subject: [PATCH 462/643] Always release dhcp address in close_tun() on Windows. Also make sure --dhcp-pre-release results in not just dhcp_release() in open_tun() but a subsequent dhcp_renew() as well. Else dhcp transaction gets aborted as this call to release() happens after the adapter status is changed to connected. Fixes Trac #807 (but can't say the same for Trac #665 without knowing how to reproduce it) v2: Mark --dhcp-release as obsolete in manpage and option parser, and remove the unused dhcp_release variable. Enforce dhcp-renew with dhcp-pre-release while parsing the option instead of in open_tun(). Trac: #807 Signed-off-by: Selva Nair Acked-by: Gert Doering Message-Id: <1483475883-17450-1-git-send-email-selva.nair@gmail.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13814.html Signed-off-by: Gert Doering (cherry picked from commit db5b9b45508ea8f66ea80565279af3edd9300499) --- doc/openvpn.8 | 4 +--- src/openvpn/options.c | 6 ++---- src/openvpn/tun.c | 5 +---- src/openvpn/tun.h | 1 - 4 files changed, 4 insertions(+), 12 deletions(-) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 7bd6d9d6b64..3e4c2e79af9 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -5819,9 +5819,7 @@ flag. .TP .B \-\-dhcp\-release Ask Windows to release the TAP adapter lease on shutdown. -This option has the same caveats as -.B \-\-dhcp\-renew -above. +This option has no effect now, as it is enabled by default starting with version 2.4.1. .\"********************************************************* .TP .B \-\-register\-dns diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 5df2dba2737..5eaff42c0dc 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -716,7 +716,6 @@ static const char usage_message[] = "--dhcp-renew : Ask Windows to renew the TAP adapter lease on startup.\n" "--dhcp-pre-release : Ask Windows to release the previous TAP adapter lease on\n" " startup.\n" - "--dhcp-release : Ask Windows to release the TAP adapter lease on shutdown.\n" "--register-dns : Run ipconfig /flushdns and ipconfig /registerdns\n" " on connection initiation.\n" "--tap-sleep n : Sleep for n seconds after TAP adapter open before\n" @@ -1214,7 +1213,6 @@ show_tuntap_options(const struct tuntap_options *o) SHOW_BOOL(dhcp_options); SHOW_BOOL(dhcp_renew); SHOW_BOOL(dhcp_pre_release); - SHOW_BOOL(dhcp_release); SHOW_STR(domain); SHOW_STR(netbios_scope); SHOW_INT(netbios_node_type); @@ -7201,11 +7199,11 @@ add_option(struct options *options, { VERIFY_PERMISSION(OPT_P_IPWIN32); options->tuntap_options.dhcp_pre_release = true; + options->tuntap_options.dhcp_renew = true; } else if (streq(p[0], "dhcp-release") && !p[1]) { - VERIFY_PERMISSION(OPT_P_IPWIN32); - options->tuntap_options.dhcp_release = true; + msg(M_WARN, "Obsolete option --dhcp-release detected. This is now on by default"); } else if (streq(p[0], "dhcp-internal") && p[1] && !p[2]) /* standalone method for internal use */ { diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index f8128449b8b..ec9997edacf 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -6224,10 +6224,7 @@ close_tun(struct tuntap *tt) } #endif - if (tt->options.dhcp_release) - { - dhcp_release(tt); - } + dhcp_release(tt); if (tt->hand != NULL) { diff --git a/src/openvpn/tun.h b/src/openvpn/tun.h index f4b600c22fb..b39fe157355 100644 --- a/src/openvpn/tun.h +++ b/src/openvpn/tun.h @@ -104,7 +104,6 @@ struct tuntap_options { bool dhcp_renew; bool dhcp_pre_release; - bool dhcp_release; bool register_dns; From 6204fccb2441b5bae8b3f6e0b31a4a0b232fc8e6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 28 Dec 2016 08:54:20 +0100 Subject: [PATCH 463/643] man: fix formatting for alternative option This looked like... --server-poll-timeout n --connect-timeout n when connecting to [...] ... and this patch changes this to... --server-poll-timeout n, --connect-timeout n When connecting to [...] ... preserving correct highlighting. Signed-off-by: Christian Hesse Acked-by: David Sommerseth Message-Id: <20161228075420.348-1-list@eworm.de> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13747.html Signed-off-by: David Sommerseth (cherry picked from commit d0d8a4b5f875bc802117647b20a3caa6d4fdb375) --- doc/openvpn.8 | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 3e4c2e79af9..e3d603e12e4 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -3969,9 +3969,8 @@ See management\-notes.txt in the OpenVPN distribution for a description of the OpenVPN challenge/response protocol. .\"********************************************************* .TP -.B \-\-server\-poll\-timeout n -.B \-\-connect\-timeout n -when connecting to a remote server do not wait for more than +\fB\-\-server\-poll\-timeout n\fR, \fB\-\-connect\-timeout n\fR +When connecting to a remote server do not wait for more than .B n seconds waiting for a response before trying the next server. The default value is 120s. This timeout includes proxy and TCP From a853cd060eb61df77055cbb92e97ad7f245f2316 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Tue, 10 Jan 2017 21:34:32 +0100 Subject: [PATCH 464/643] management: >REMOTE operation would overwrite ce change indicator If the management interface on a client received a signal while waiting for input on the management channel, the "connection entry changed" status would be overwritten even though nothing was changed. Which could lead into connecting to the wrong server. This patch improves this by adding a check if a bool value was changed to false. This change happens only on signals. Further, the former 'ret' value have been renamed to 'ce_changed', to clarify what the expected return value contains. Plus adding some comments related to this. And finally do some code style cleanup, breaking up too long lines, adding some air here and there to improve the readability. Signed-off-by: David Sommerseth Cc: Selva Nair Acked-by: Selva Nair Message-Id: <1484080473-10415-1-git-send-email-davids@openvpn.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13851.html Signed-off-by: David Sommerseth (cherry picked from commit e81f313a71e548638d9e9679226ee84b3b614f13) --- src/openvpn/init.c | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 9a3e29d3f74..4786232c2df 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -252,31 +252,42 @@ ce_management_query_remote(struct context *c) { struct gc_arena gc = gc_new(); volatile struct connection_entry *ce = &c->options.ce; - int ret = true; + int ce_changed = true; /* presume the connection entry will be changed */ + update_time(); if (management) { struct buffer out = alloc_buf_gc(256, &gc); - buf_printf(&out, ">REMOTE:%s,%s,%s", np(ce->remote), ce->remote_port, proto2ascii(ce->proto, ce->af, false)); + + buf_printf(&out, ">REMOTE:%s,%s,%s", np(ce->remote), ce->remote_port, + proto2ascii(ce->proto, ce->af, false)); management_notify_generic(management, BSTR(&out)); - ce->flags &= ~(CE_MAN_QUERY_REMOTE_MASK<flags |= (CE_MAN_QUERY_REMOTE_QUERY<flags>>CE_MAN_QUERY_REMOTE_SHIFT) & CE_MAN_QUERY_REMOTE_MASK) == CE_MAN_QUERY_REMOTE_QUERY) + + ce->flags &= ~(CE_MAN_QUERY_REMOTE_MASK << CE_MAN_QUERY_REMOTE_SHIFT); + ce->flags |= (CE_MAN_QUERY_REMOTE_QUERY << CE_MAN_QUERY_REMOTE_SHIFT); + while (((ce->flags >> CE_MAN_QUERY_REMOTE_SHIFT) + & CE_MAN_QUERY_REMOTE_MASK) == CE_MAN_QUERY_REMOTE_QUERY) { management_event_loop_n_seconds(management, 1); if (IS_SIG(c)) { - ret = false; + ce_changed = false; /* connection entry have not been set */ break; } } } + gc_free(&gc); + + if (ce_changed) { - const int flags = ((ce->flags>>CE_MAN_QUERY_REMOTE_SHIFT) & CE_MAN_QUERY_REMOTE_MASK); - ret = (flags != CE_MAN_QUERY_REMOTE_SKIP); + /* If it is likely a connection entry was modified, + * check what changed in the flags and that it was not skipped + */ + const int flags = ((ce->flags >> CE_MAN_QUERY_REMOTE_SHIFT) + & CE_MAN_QUERY_REMOTE_MASK); + ce_changed = (flags != CE_MAN_QUERY_REMOTE_SKIP); } - gc_free(&gc); - return ret; + return ce_changed; } #endif /* ENABLE_MANAGEMENT */ From 977f0b9ff4b600212b603279153ff1b1b10cf527 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Tue, 10 Jan 2017 21:34:33 +0100 Subject: [PATCH 465/643] management: Remove a redundant #ifdef block Bascially removes two independent #ifdef ENABLE_MANAGEMENT blocks into a single block, which makes the logic flow more easy to read. Signed-off-by: David Sommerseth Cc: Selva Nair Acked-by: Selva Nair Message-Id: <1484080473-10415-2-git-send-email-davids@openvpn.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13852.html Signed-off-by: David Sommerseth (cherry picked from commit 7b02cc2aa8318dc8f2677064dadcbec295b2f937) --- src/openvpn/init.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 4786232c2df..5296345e1e1 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -414,11 +414,7 @@ next_connection_entry(struct context *c) break; } } - else -#endif - -#ifdef ENABLE_MANAGEMENT - if (ce_defined && management && management_query_proxy_enabled(management)) + else if (ce_defined && management && management_query_proxy_enabled(management)) { ce_defined = ce_management_query_proxy(c); if (IS_SIG(c)) From 9c2506d4395de67dbc520b6458f25e99b99376eb Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sat, 14 Jan 2017 15:10:20 +0100 Subject: [PATCH 466/643] More broadly enforce Allman style and braces-around-conditionals We want { and } aligned, which means also adding a newline between each for() and {, while() and {, etc. Also, we agreed to always use braces with conditionals. The previous uncrustify config added these for if()s, now also add these for while() and for(). Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1484403020-6857-1-git-send-email-steffan@karger.me> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13875.html Signed-off-by: David Sommerseth (cherry picked from commit 4cd4899e8e80efae03c584a760fd107251735723) --- dev-tools/uncrustify.conf | 8 ++++ src/compat/compat-daemon.c | 3 +- src/compat/compat-dirname.c | 7 +++- src/compat/compat-inet_ntop.c | 3 +- src/compat/compat-inet_pton.c | 3 +- src/compat/compat-versionhelpers.h | 36 ++++++++++------ src/openvpn/argv.c | 10 +++++ src/openvpn/base64.c | 11 +++-- src/openvpn/buffer.c | 9 +++- src/openvpn/buffer.h | 2 + src/openvpn/comp-lz4.c | 3 +- src/openvpn/compstub.c | 3 +- src/openvpn/console.c | 6 ++- src/openvpn/crypto.c | 18 +++++--- src/openvpn/crypto.h | 3 +- src/openvpn/crypto_mbedtls.h | 3 +- src/openvpn/crypto_openssl.c | 9 ++-- src/openvpn/cryptoapi.c | 9 +++- src/openvpn/dhcp.c | 11 +++-- src/openvpn/error.c | 3 +- src/openvpn/error.h | 3 +- src/openvpn/event.c | 4 ++ src/openvpn/fragment.c | 9 +++- src/openvpn/gremlin.c | 15 ++++--- src/openvpn/httpdigest.c | 3 +- src/openvpn/init.c | 11 ++++- src/openvpn/interval.h | 3 +- src/openvpn/list.c | 6 ++- src/openvpn/lzo.c | 3 +- src/openvpn/manage.c | 15 +++++-- src/openvpn/mbuf.c | 3 +- src/openvpn/misc.c | 9 +++- src/openvpn/mroute.c | 3 +- src/openvpn/mss.c | 3 +- src/openvpn/mtcp.c | 3 +- src/openvpn/multi.c | 14 ++++++- src/openvpn/ntlm.c | 11 +++-- src/openvpn/occ.c | 3 +- src/openvpn/openvpn.c | 6 ++- src/openvpn/options.c | 52 +++++++++++++++++++++-- src/openvpn/otime.h | 3 +- src/openvpn/packet_id.c | 3 +- src/openvpn/perf.c | 5 ++- src/openvpn/perf.h | 9 ++-- src/openvpn/pkcs11.c | 66 ++++++++++++++++++++---------- src/openvpn/plugin.c | 11 ++++- src/openvpn/pool.c | 2 + src/openvpn/proxy.c | 10 ++++- src/openvpn/reliable.c | 7 +++- src/openvpn/route.c | 13 +++++- src/openvpn/route.h | 3 +- src/openvpn/schedule.c | 4 ++ src/openvpn/session_id.c | 3 +- src/openvpn/shaper.c | 3 +- src/openvpn/socket.c | 12 +++++- src/openvpn/socket.h | 24 +++++++---- src/openvpn/ssl.c | 26 +++++++++--- src/openvpn/ssl_mbedtls.c | 8 +++- src/openvpn/ssl_openssl.c | 3 +- src/openvpn/ssl_verify.c | 6 +++ src/openvpn/ssl_verify_mbedtls.c | 2 + src/openvpn/ssl_verify_openssl.c | 3 +- src/openvpn/tls_crypt.c | 6 ++- src/openvpn/tun.c | 26 +++++++++--- src/openvpn/win32.c | 8 +++- src/openvpnserv/automatic.c | 3 +- src/openvpnserv/interactive.c | 5 ++- src/plugins/auth-pam/utils.c | 5 ++- src/plugins/down-root/down-root.c | 2 + 69 files changed, 477 insertions(+), 143 deletions(-) diff --git a/dev-tools/uncrustify.conf b/dev-tools/uncrustify.conf index 95e0b2a1444..d8ea870ec8d 100644 --- a/dev-tools/uncrustify.conf +++ b/dev-tools/uncrustify.conf @@ -9,6 +9,11 @@ nl_brace_else=add nl_elseif_brace=add nl_else_brace=add nl_else_if=remove +nl_for_brace=add +nl_while_brace=add +nl_switch_brace=add +nl_fdef_brace=add +nl_do_brace=add sp_func_proto_paren=Remove sp_func_def_paren=Remove sp_func_call_paren=Remove @@ -44,6 +49,9 @@ nl_after_func_proto=2 # Always use scoping braces for conditionals mod_full_brace_if=add mod_full_brace_if_chain=false +mod_full_brace_while=add +mod_full_brace_for=add +mod_full_brace_do=add # Annotate #else and #endif statements mod_add_long_ifdef_endif_comment=20 diff --git a/src/compat/compat-daemon.c b/src/compat/compat-daemon.c index 509394254ae..b54e81361c1 100644 --- a/src/compat/compat-daemon.c +++ b/src/compat/compat-daemon.c @@ -58,7 +58,8 @@ int daemon(int nochdir, int noclose) { #if defined(HAVE_FORK) && defined(HAVE_SETSID) - switch (fork()) { + switch (fork()) + { case -1: return (-1); diff --git a/src/compat/compat-dirname.c b/src/compat/compat-dirname.c index 7687108a98c..7747dbdb934 100644 --- a/src/compat/compat-dirname.c +++ b/src/compat/compat-dirname.c @@ -44,7 +44,8 @@ __memrchr(const char *str, int c, size_t n) const char *end = str; end += n - 1; /* Go to the end of the string */ - while (end >= str) { + while (end >= str) + { if (c == *end) { return end; @@ -82,10 +83,12 @@ dirname(char *path) char *runp; for (runp = last_slash; runp != path; --runp) + { if (runp[-1] != separator) { break; } + } /* The '/' is the last character, we have to look further. */ if (runp != path) @@ -100,10 +103,12 @@ dirname(char *path) char *runp; for (runp = last_slash; runp != path; --runp) + { if (runp[-1] != separator) { break; } + } /* Terminate the path. */ if (runp == path) diff --git a/src/compat/compat-inet_ntop.c b/src/compat/compat-inet_ntop.c index dd7abb5aab3..07d0dde9199 100644 --- a/src/compat/compat-inet_ntop.c +++ b/src/compat/compat-inet_ntop.c @@ -52,7 +52,8 @@ inet_ntop(int af, const void *src, char *dst, socklen_t size) ZeroMemory(&ss, sizeof(ss)); ss.ss_family = af; - switch (af) { + switch (af) + { case AF_INET: ((struct sockaddr_in *)&ss)->sin_addr = *(struct in_addr *)src; break; diff --git a/src/compat/compat-inet_pton.c b/src/compat/compat-inet_pton.c index 1e41fa27496..170e2945577 100644 --- a/src/compat/compat-inet_pton.c +++ b/src/compat/compat-inet_pton.c @@ -59,7 +59,8 @@ inet_pton(int af, const char *src, void *dst) if (WSAStringToAddress(src_copy, af, NULL, (struct sockaddr *)&ss, &size) == 0) { - switch (af) { + switch (af) + { case AF_INET: *(struct in_addr *)dst = ((struct sockaddr_in *)&ss)->sin_addr; return 1; diff --git a/src/compat/compat-versionhelpers.h b/src/compat/compat-versionhelpers.h index a7930564610..251fb0471e2 100644 --- a/src/compat/compat-versionhelpers.h +++ b/src/compat/compat-versionhelpers.h @@ -30,62 +30,74 @@ IsWindowsVersionOrGreater(WORD major, WORD minor, WORD servpack) } VERSIONHELPERAPI -IsWindowsXPOrGreater(void) { +IsWindowsXPOrGreater(void) +{ return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 0); } VERSIONHELPERAPI -IsWindowsXPSP1OrGreater(void) { +IsWindowsXPSP1OrGreater(void) +{ return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 1); } VERSIONHELPERAPI -IsWindowsXPSP2OrGreater(void) { +IsWindowsXPSP2OrGreater(void) +{ return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 2); } VERSIONHELPERAPI -IsWindowsXPSP3OrGreater(void) { +IsWindowsXPSP3OrGreater(void) +{ return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 3); } VERSIONHELPERAPI -IsWindowsVistaOrGreater(void) { +IsWindowsVistaOrGreater(void) +{ return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 0); } VERSIONHELPERAPI -IsWindowsVistaSP1OrGreater(void) { +IsWindowsVistaSP1OrGreater(void) +{ return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 1); } VERSIONHELPERAPI -IsWindowsVistaSP2OrGreater(void) { +IsWindowsVistaSP2OrGreater(void) +{ return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 2); } VERSIONHELPERAPI -IsWindows7OrGreater(void) { +IsWindows7OrGreater(void) +{ return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN7), LOBYTE(_WIN32_WINNT_WIN7), 0); } VERSIONHELPERAPI -IsWindows7SP1OrGreater(void) { +IsWindows7SP1OrGreater(void) +{ return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN7), LOBYTE(_WIN32_WINNT_WIN7), 1); } VERSIONHELPERAPI -IsWindows8OrGreater(void) { +IsWindows8OrGreater(void) +{ return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN8), LOBYTE(_WIN32_WINNT_WIN8), 0); } VERSIONHELPERAPI -IsWindows8Point1OrGreater(void) { +IsWindows8Point1OrGreater(void) +{ return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINBLUE), LOBYTE(_WIN32_WINNT_WINBLUE), 0); } VERSIONHELPERAPI -IsWindowsServer(void) { +IsWindowsServer(void) +{ OSVERSIONINFOEXW vi = {sizeof(vi),0,0,0,0,{0},0,0,0,VER_NT_WORKSTATION}; return !VerifyVersionInfoW(&vi, VER_PRODUCT_TYPE, VerSetConditionMask(0, VER_PRODUCT_TYPE, VER_EQUAL)); } diff --git a/src/openvpn/argv.c b/src/openvpn/argv.c index cc813ed55c5..59caa6f3d4e 100644 --- a/src/openvpn/argv.c +++ b/src/openvpn/argv.c @@ -60,7 +60,9 @@ argv_reset(struct argv *a) { size_t i; for (i = 0; i < a->argc; ++i) + { free(a->argv[i]); + } free(a->argv); argv_init(a); } @@ -74,7 +76,9 @@ argv_extend(struct argv *a, const size_t newcap) size_t i; ALLOC_ARRAY_CLEAR(newargv, char *, newcap); for (i = 0; i < a->argc; ++i) + { newargv[i] = a->argv[i]; + } free(a->argv); a->argv = newargv; a->capacity = newcap; @@ -104,11 +108,15 @@ argv_clone(const struct argv *a, const size_t headroom) argv_init(&r); for (i = 0; i < headroom; ++i) + { argv_append(&r, NULL); + } if (a) { for (i = 0; i < a->argc; ++i) + { argv_append(&r, string_alloc(a->argv[i], NULL)); + } } return r; } @@ -332,7 +340,9 @@ argv_parse_cmd(struct argv *a, const char *s) { int i; for (i = 0; i < nparms; ++i) + { argv_append(a, string_alloc(parms[i], NULL)); + } } else { diff --git a/src/openvpn/base64.c b/src/openvpn/base64.c index c799ede17f6..0ac65e992af 100644 --- a/src/openvpn/base64.c +++ b/src/openvpn/base64.c @@ -69,7 +69,8 @@ openvpn_base64_encode(const void *data, int size, char **str) } q = (const unsigned char *) data; i = 0; - for (i = 0; i < size; ) { + for (i = 0; i < size; ) + { c = q[i++]; c *= 256; if (i < size) @@ -107,10 +108,12 @@ pos(char c) { char *p; for (p = base64_chars; *p; p++) + { if (*p == c) { return p - base64_chars; } + } return -1; } @@ -126,7 +129,8 @@ token_decode(const char *token) { return DECODE_ERROR; } - for (i = 0; i < 4; i++) { + for (i = 0; i < 4; i++) + { val *= 64; if (token[i] == '=') { @@ -164,7 +168,8 @@ openvpn_base64_decode(const char *str, void *data, int size) { e = q + size; } - for (p = str; *p && (*p == '=' || strchr(base64_chars, *p)); p += 4) { + for (p = str; *p && (*p == '=' || strchr(base64_chars, *p)); p += 4) + { unsigned int val = token_decode(p); unsigned int marker = (val >> 24) & 0xff; if (val == DECODE_ERROR) diff --git a/src/openvpn/buffer.c b/src/openvpn/buffer.c index 2defd1814fb..7e46387d3a9 100644 --- a/src/openvpn/buffer.c +++ b/src/openvpn/buffer.c @@ -443,7 +443,9 @@ gc_transfer(struct gc_arena *dest, struct gc_arena *src) if (e) { while (e->next != NULL) + { e = e->next; + } e->next = dest->list; dest->list = src->list; src->list = NULL; @@ -599,7 +601,8 @@ void rm_trailing_chars(char *str, const char *what_to_delete) { bool modified; - do { + do + { const int len = strlen(str); modified = false; if (len > 0) @@ -682,7 +685,9 @@ string_array_len(const char **array) if (array) { while (array[i]) + { ++i; + } } return i; } @@ -1320,7 +1325,9 @@ buffer_list_file(const char *fn, int max_line_len) { bl = buffer_list_new(0); while (fgets(line, max_line_len, fp) != NULL) + { buffer_list_push(bl, (unsigned char *)line); + } free(line); } fclose(fp); diff --git a/src/openvpn/buffer.h b/src/openvpn/buffer.h index 28b224e09ed..59d12abded0 100644 --- a/src/openvpn/buffer.h +++ b/src/openvpn/buffer.h @@ -404,7 +404,9 @@ secure_memzero(void *data, size_t len) #else volatile char *p = (volatile char *) data; while (len--) + { *p++ = 0; + } #endif } diff --git a/src/openvpn/comp-lz4.c b/src/openvpn/comp-lz4.c index fa65f87e8c3..e1f83e7fec6 100644 --- a/src/openvpn/comp-lz4.c +++ b/src/openvpn/comp-lz4.c @@ -316,6 +316,7 @@ const struct compress_alg lz4v2_alg = { #else /* if defined(ENABLE_LZ4) */ static void -dummy(void) { +dummy(void) +{ } #endif /* ENABLE_LZ4 */ diff --git a/src/openvpn/compstub.c b/src/openvpn/compstub.c index 5070c82e2a0..dd9c175b900 100644 --- a/src/openvpn/compstub.c +++ b/src/openvpn/compstub.c @@ -179,6 +179,7 @@ const struct compress_alg comp_stub_alg = { #else /* if defined(USE_COMP) */ static void -dummy(void) { +dummy(void) +{ } #endif /* USE_STUB */ diff --git a/src/openvpn/console.c b/src/openvpn/console.c index 90c8a94c5c2..2c418ac8dea 100644 --- a/src/openvpn/console.c +++ b/src/openvpn/console.c @@ -49,7 +49,8 @@ query_user_clear() { int i; - for (i = 0; i < QUERY_USER_NUMSLOTS; i++) { + for (i = 0; i < QUERY_USER_NUMSLOTS; i++) + { CLEAR(query_user[i]); } } @@ -68,7 +69,8 @@ query_user_add(char *prompt, size_t prompt_len, ASSERT( prompt_len > 0 && prompt != NULL && resp_len > 0 && resp != NULL ); /* Seek to the last unused slot */ - for (i = 0; i < QUERY_USER_NUMSLOTS; i++) { + for (i = 0; i < QUERY_USER_NUMSLOTS; i++) + { if (query_user[i].prompt == NULL) { break; diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c index 7119abc61e3..1369c0f7c35 100644 --- a/src/openvpn/crypto.c +++ b/src/openvpn/crypto.c @@ -65,7 +65,8 @@ static void openvpn_encrypt_aead(struct buffer *buf, struct buffer work, - struct crypto_options *opt) { + struct crypto_options *opt) +{ #ifdef HAVE_AEAD_CIPHER_MODES struct gc_arena gc; int outlen = 0; @@ -329,7 +330,8 @@ openvpn_encrypt(struct buffer *buf, struct buffer work, bool crypto_check_replay(struct crypto_options *opt, const struct packet_id_net *pin, const char *error_prefix, - struct gc_arena *gc) { + struct gc_arena *gc) +{ bool ret = false; packet_id_reap_test(&opt->packet_id.rec); if (packet_id_test(&opt->packet_id.rec, pin)) @@ -1019,7 +1021,8 @@ generate_key_random(struct key *key, const struct key_type *kt) struct gc_arena gc = gc_new(); - do { + do + { CLEAR(*key); if (kt) { @@ -1795,7 +1798,8 @@ get_random() } static const cipher_name_pair * -get_cipher_name_pair(const char *cipher_name) { +get_cipher_name_pair(const char *cipher_name) +{ const cipher_name_pair *pair; size_t i = 0; @@ -1815,7 +1819,8 @@ get_cipher_name_pair(const char *cipher_name) { } const char * -translate_cipher_name_from_openvpn(const char *cipher_name) { +translate_cipher_name_from_openvpn(const char *cipher_name) +{ const cipher_name_pair *pair = get_cipher_name_pair(cipher_name); if (NULL == pair) @@ -1827,7 +1832,8 @@ translate_cipher_name_from_openvpn(const char *cipher_name) { } const char * -translate_cipher_name_to_openvpn(const char *cipher_name) { +translate_cipher_name_to_openvpn(const char *cipher_name) +{ const cipher_name_pair *pair = get_cipher_name_pair(cipher_name); if (NULL == pair) diff --git a/src/openvpn/crypto.h b/src/openvpn/crypto.h index 61e9b5982bd..6ca0bc81b3d 100644 --- a/src/openvpn/crypto.h +++ b/src/openvpn/crypto.h @@ -496,7 +496,8 @@ void crypto_read_openvpn_key(const struct key_type *key_type, * Returns 0 when data is equal, non-zero otherwise. */ static inline int -memcmp_constant_time(const void *a, const void *b, size_t size) { +memcmp_constant_time(const void *a, const void *b, size_t size) +{ const uint8_t *a1 = a; const uint8_t *b1 = b; int ret = 0; diff --git a/src/openvpn/crypto_mbedtls.h b/src/openvpn/crypto_mbedtls.h index d9b14461b0b..525b256a6fe 100644 --- a/src/openvpn/crypto_mbedtls.h +++ b/src/openvpn/crypto_mbedtls.h @@ -122,7 +122,8 @@ bool mbed_log_func_line(unsigned int flags, int errval, const char *func, /** Wraps mbed_log_func_line() to prevent function calls for non-errors */ static inline bool mbed_log_func_line_lite(unsigned int flags, int errval, - const char *func, int line) { + const char *func, int line) +{ if (errval) { return mbed_log_func_line(flags, errval, func, line); diff --git a/src/openvpn/crypto_openssl.c b/src/openvpn/crypto_openssl.c index b016d98a9fd..e4557156106 100644 --- a/src/openvpn/crypto_openssl.c +++ b/src/openvpn/crypto_openssl.c @@ -186,7 +186,8 @@ crypto_clear_error(void) } void -crypto_print_openssl_errors(const unsigned int flags) { +crypto_print_openssl_errors(const unsigned int flags) +{ size_t err = 0; while ((err = ERR_get_error())) @@ -551,8 +552,10 @@ cipher_kt_iv_size(const EVP_CIPHER *cipher_kt) } int -cipher_kt_block_size(const EVP_CIPHER *cipher) { - /* OpenSSL reports OFB/CFB/GCM cipher block sizes as '1 byte'. To work +cipher_kt_block_size(const EVP_CIPHER *cipher) +{ + /* + * OpenSSL reports OFB/CFB/GCM cipher block sizes as '1 byte'. To work * around that, try to replace the mode with 'CBC' and return the block size * reported for that cipher, if possible. If that doesn't work, just return * the value reported by OpenSSL. diff --git a/src/openvpn/cryptoapi.c b/src/openvpn/cryptoapi.c index 69a5a32df68..d90cc5d29a2 100644 --- a/src/openvpn/cryptoapi.c +++ b/src/openvpn/cryptoapi.c @@ -281,7 +281,9 @@ rsa_priv_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, i } /* and now, we have to reverse the byte-order in the result from CryptSignHash()... */ for (i = 0; i < len; i++) + { to[i] = buf[len - i - 1]; + } free(buf); CryptDestroyHash(hash); @@ -389,7 +391,9 @@ find_certificate_in_store(const char *cert_prop, HCERTSTORE cert_store) } hash[i] = x; /* skip any space(s) between hex numbers */ - for (p++; *p && *p == ' '; p++) ; + for (p++; *p && *p == ' '; p++) + { + } } blob.cbData = i; blob.pbData = (unsigned char *) &hash; @@ -547,7 +551,8 @@ SSL_CTX_use_CryptoAPI_certificate(SSL_CTX *ssl_ctx, const char *cert_prop) #else /* ifdef ENABLE_CRYPTOAPI */ #ifdef _MSC_VER /* Dummy function needed to avoid empty file compiler warning in Microsoft VC */ static void -dummy(void) { +dummy(void) +{ } #endif #endif /* _WIN32 */ diff --git a/src/openvpn/dhcp.c b/src/openvpn/dhcp.c index c17a22e631a..4ffa9d622bd 100644 --- a/src/openvpn/dhcp.c +++ b/src/openvpn/dhcp.c @@ -160,17 +160,20 @@ udp_checksum(const uint8_t *buf, /* make 16 bit words out of every two adjacent 8 bit words and */ /* calculate the sum of all 16 bit words */ - for (i = 0; i < len_udp; i += 2) { + for (i = 0; i < len_udp; i += 2) + { word16 = ((buf[i] << 8) & 0xFF00) + ((i + 1 < len_udp) ? (buf[i+1] & 0xFF) : 0); sum += word16; } /* add the UDP pseudo header which contains the IP source and destination addresses */ - for (i = 0; i < 4; i += 2) { + for (i = 0; i < 4; i += 2) + { word16 = ((src_addr[i] << 8) & 0xFF00) + (src_addr[i+1] & 0xFF); sum += word16; } - for (i = 0; i < 4; i += 2) { + for (i = 0; i < 4; i += 2) + { word16 = ((dest_addr[i] << 8) & 0xFF00) + (dest_addr[i+1] & 0xFF); sum += word16; } @@ -180,7 +183,9 @@ udp_checksum(const uint8_t *buf, /* keep only the last 16 bits of the 32 bit calculated sum and add the carries */ while (sum >> 16) + { sum = (sum & 0xFFFF) + (sum >> 16); + } /* Take the one's complement of sum */ return ((uint16_t) ~sum); diff --git a/src/openvpn/error.c b/src/openvpn/error.c index e78f2723911..dbff81df65d 100644 --- a/src/openvpn/error.c +++ b/src/openvpn/error.c @@ -836,7 +836,8 @@ strerror_win32(DWORD errnum, struct gc_arena *gc) * Posix equivalents. */ #if 1 - switch (errnum) { + switch (errnum) + { /* * When the TAP-Windows driver returns STATUS_UNSUCCESSFUL, this code * gets returned to user space. diff --git a/src/openvpn/error.h b/src/openvpn/error.h index df4eee72c19..c86b956c5ec 100644 --- a/src/openvpn/error.h +++ b/src/openvpn/error.h @@ -394,7 +394,8 @@ ignore_sys_error(const int err) /** Convert fatal errors to nonfatal, don't touch other errors */ static inline unsigned int -nonfatal(const unsigned int err) { +nonfatal(const unsigned int err) +{ return err & M_FATAL ? (err ^ M_FATAL) | M_NONFATAL : err; } diff --git a/src/openvpn/event.c b/src/openvpn/event.c index f4922e0a94d..e77bc4c6b97 100644 --- a/src/openvpn/event.c +++ b/src/openvpn/event.c @@ -394,11 +394,13 @@ we_wait(struct event_set *es, const struct timeval *tv, struct event_set_return { int i; for (i = 0; i < wes->n_events; ++i) + { dmsg(D_EVENT_WAIT, "[%d] ev=%p rwflags=0x%04x arg=" ptr_format, i, wes->events[i], wes->esr[i].rwflags, (ptr_type)wes->esr[i].arg); + } } #endif @@ -922,7 +924,9 @@ se_reset(struct event_set *es) FD_ZERO(&ses->readfds); FD_ZERO(&ses->writefds); for (i = 0; i <= ses->maxfd; ++i) + { ses->args[i] = NULL; + } ses->maxfd = -1; } diff --git a/src/openvpn/fragment.c b/src/openvpn/fragment.c index 6fbfe084a95..c504a4fdd6e 100644 --- a/src/openvpn/fragment.c +++ b/src/openvpn/fragment.c @@ -44,7 +44,9 @@ fragment_list_buf_init(struct fragment_list *list, const struct frame *frame) { int i; for (i = 0; i < N_FRAG_BUF; ++i) + { list->fragments[i].buf = alloc_buf(BUF_SIZE(frame)); + } } static void @@ -52,7 +54,9 @@ fragment_list_buf_free(struct fragment_list *list) { int i; for (i = 0; i < N_FRAG_BUF; ++i) + { free_buf(&list->fragments[i].buf); + } } /* @@ -67,7 +71,9 @@ fragment_list_get_buf(struct fragment_list *list, int seq_id) { int i; for (i = 0; i < N_FRAG_BUF; ++i) + { list->fragments[i].defined = false; + } list->index = 0; list->seq_id = seq_id; diff = 0; @@ -433,6 +439,7 @@ fragment_wakeup(struct fragment_master *f, struct frame *frame) #else /* ifdef ENABLE_FRAGMENT */ static void -dummy(void) { +dummy(void) +{ } #endif /* ifdef ENABLE_FRAGMENT */ diff --git a/src/openvpn/gremlin.c b/src/openvpn/gremlin.c index 5bff5e8e1ee..b077ae330d7 100644 --- a/src/openvpn/gremlin.c +++ b/src/openvpn/gremlin.c @@ -95,7 +95,8 @@ get_packet_flood_parms(int level) * Return true with probability 1/n */ static bool -flip(int n) { +flip(int n) +{ return (get_random() % n) == 0; } @@ -104,7 +105,8 @@ flip(int n) { * low and high. */ static int -roll(int low, int high) { +roll(int low, int high) +{ int ret; ASSERT(low <= high); ret = low + (get_random() % (high - low + 1)); @@ -181,7 +183,8 @@ ask_gremlin(int flags) * Possibly corrupt a packet. */ void -corrupt_gremlin(struct buffer *buf, int flags) { +corrupt_gremlin(struct buffer *buf, int flags) +{ const int corrupt_level = GREMLIN_CORRUPT_LEVEL(flags); if (corrupt_level) { @@ -194,7 +197,8 @@ corrupt_gremlin(struct buffer *buf, int flags) { uint8_t r = roll(0, 255); int method = roll(0, 5); - switch (method) { + switch (method) + { case 0: /* corrupt the first byte */ *BPTR(buf) = r; break; @@ -232,6 +236,7 @@ corrupt_gremlin(struct buffer *buf, int flags) { #else /* ifdef ENABLE_DEBUG */ static void -dummy(void) { +dummy(void) +{ } #endif /* ifdef ENABLE_DEBUG */ diff --git a/src/openvpn/httpdigest.c b/src/openvpn/httpdigest.c index 01301c01352..ae4a638fbf9 100644 --- a/src/openvpn/httpdigest.c +++ b/src/openvpn/httpdigest.c @@ -44,7 +44,8 @@ CvtHex( unsigned short i; unsigned char j; - for (i = 0; i < HASHLEN; i++) { + for (i = 0; i < HASHLEN; i++) + { j = (Bin[i] >> 4) & 0xf; if (j <= 9) { diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 5296345e1e1..a540c68da28 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -342,7 +342,8 @@ next_connection_entry(struct context *c) struct connection_entry *ce; int n_cycles = 0; - do { + do + { ce_defined = true; if (c->options.no_advance && l->current >= 0) { @@ -540,8 +541,10 @@ context_init_1(struct context *c) int i; pkcs11_initialize(true, c->options.pkcs11_pin_cache_period); for (i = 0; ioptions.pkcs11_providers[i] != NULL; i++) + { pkcs11_addProvider(c->options.pkcs11_providers[i], c->options.pkcs11_protected_authentication[i], c->options.pkcs11_private_mode[i], c->options.pkcs11_cert_private[i]); + } } #endif @@ -621,7 +624,9 @@ init_static(void) { int i; for (i = 0; i < argc; ++i) + { msg(M_INFO, "argv[%d] = '%s'", i, argv[i]); + } } #endif @@ -767,7 +772,9 @@ init_static(void) { int i; for (i = 0; i < SIZE(text); ++i) + { buffer_list_push(bl, (unsigned char *)text[i]); + } } printf("[cap=%d i=%d] *************************\n", listcap, iter); if (!(iter & 8)) @@ -790,7 +797,9 @@ init_static(void) int c; printf("'"); while ((c = buf_read_u8(buf)) >= 0) + { putchar(c); + } printf("'\n"); buffer_list_advance(bl, 0); } diff --git a/src/openvpn/interval.h b/src/openvpn/interval.h index 5ed64a92c19..e87d751cb44 100644 --- a/src/openvpn/interval.h +++ b/src/openvpn/interval.h @@ -106,7 +106,8 @@ interval_schedule_wakeup(struct interval *top, interval_t *wakeup) * In wakeup seconds, interval_test will return true once. */ static inline void -interval_future_trigger(struct interval *top, interval_t wakeup) { +interval_future_trigger(struct interval *top, interval_t wakeup) +{ if (wakeup) { #if INTERVAL_DEBUG diff --git a/src/openvpn/list.c b/src/openvpn/list.c index fb9f6641e05..d08b5994ef8 100644 --- a/src/openvpn/list.c +++ b/src/openvpn/list.c @@ -476,7 +476,8 @@ list_test(void) int inc = 0; int count = 0; - for (base = 0; base < hash_n_buckets(hash); base += inc) { + for (base = 0; base < hash_n_buckets(hash); base += inc) + { struct hash_iterator hi; struct hash_element *he; inc = (get_random() % 3) + 1; @@ -670,6 +671,7 @@ hash_func(const uint8_t *k, uint32_t length, uint32_t initval) #else /* if P2MP_SERVER */ static void -dummy(void) { +dummy(void) +{ } #endif /* P2MP_SERVER */ diff --git a/src/openvpn/lzo.c b/src/openvpn/lzo.c index 3d6891ed2e2..155507dd07c 100644 --- a/src/openvpn/lzo.c +++ b/src/openvpn/lzo.c @@ -267,6 +267,7 @@ const struct compress_alg lzo_alg = { #else /* if defined(ENABLE_LZO) */ static void -dummy(void) { +dummy(void) +{ } #endif /* ENABLE_LZO */ diff --git a/src/openvpn/manage.c b/src/openvpn/manage.c index 763f6c6dd55..58b65c29b17 100644 --- a/src/openvpn/manage.c +++ b/src/openvpn/manage.c @@ -1984,7 +1984,9 @@ man_process_command(struct management *man, const char *line) { int i; for (i = 0; i < nparms; ++i) + { msg(M_INFO, "[%d] '%s'", i, parms[i]); + } } #endif @@ -3088,7 +3090,8 @@ management_io(struct management *man) if (net_events & FD_READ) { while (man_read(man) > 0) - ; + { + } net_event_win32_clear_selected_events(&man->connection.ne32, FD_READ); } @@ -3311,7 +3314,8 @@ man_wait_for_client_connection(struct management *man, { msg(D_MANAGEMENT, "Need information from management interface, waiting..."); } - do { + do + { man_standalone_event_loop(man, signal_received, expire); if (signal_received && *signal_received) { @@ -3929,7 +3933,9 @@ log_history_free_contents(struct log_history *h) { int i; for (i = 0; i < h->size; ++i) + { log_entry_free_contents(&h->array[log_index(h, i)]); + } free(h->array); } @@ -3973,7 +3979,9 @@ log_history_resize(struct log_history *h, const int capacity) log_history_obj_init(&newlog, capacity); for (i = 0; i < h->size; ++i) + { log_history_add(&newlog, &h->array[log_index(h, i)]); + } log_history_free_contents(h); *h = newlog; @@ -3995,6 +4003,7 @@ log_history_ref(const struct log_history *h, const int index) #else /* ifdef ENABLE_MANAGEMENT */ static void -dummy(void) { +dummy(void) +{ } #endif /* ENABLE_MANAGEMENT */ diff --git a/src/openvpn/mbuf.c b/src/openvpn/mbuf.c index 7a23e590786..ceee0fd5d74 100644 --- a/src/openvpn/mbuf.c +++ b/src/openvpn/mbuf.c @@ -174,6 +174,7 @@ mbuf_dereference_instance(struct mbuf_set *ms, struct multi_instance *mi) #else /* if P2MP */ static void -dummy(void) { +dummy(void) +{ } #endif /* P2MP */ diff --git a/src/openvpn/misc.c b/src/openvpn/misc.c index 87f03bea318..a2f45b61c1a 100644 --- a/src/openvpn/misc.c +++ b/src/openvpn/misc.c @@ -650,7 +650,8 @@ const char * env_set_get(const struct env_set *es, const char *name) { const struct env_item *item = es->list; - while (item && !env_string_equal(item->string, name)) { + while (item && !env_string_equal(item->string, name)) + { item = item->next; } return item ? item->string : NULL; @@ -1547,7 +1548,9 @@ make_env_array(const struct env_set *es, if (es) { for (e = es->list; e != NULL; e = e->next) + { ++n; + } } /* alloc return array */ @@ -1609,7 +1612,9 @@ make_inline_array(const char *str, struct gc_arena *gc) buf_set_read(&buf, (const uint8_t *) str, strlen(str)); while (buf_parse(&buf, '\n', line, sizeof(line))) + { ++len; + } /* alloc return array */ ALLOC_ARRAY_CLEAR_GC(ret, char *, len + 1, gc); @@ -1639,7 +1644,9 @@ make_arg_copy(char **p, struct gc_arena *gc) ALLOC_ARRAY_CLEAR_GC(ret, char *, max_parms, gc); for (i = 0; i < len; ++i) + { ret[i] = p[i]; + } return (const char **)ret; } diff --git a/src/openvpn/mroute.c b/src/openvpn/mroute.c index 8b466b6c1ff..33c2ef43196 100644 --- a/src/openvpn/mroute.c +++ b/src/openvpn/mroute.c @@ -562,6 +562,7 @@ mroute_helper_free(struct mroute_helper *mh) #else /* if P2MP_SERVER */ static void -dummy(void) { +dummy(void) +{ } #endif /* P2MP_SERVER */ diff --git a/src/openvpn/mss.c b/src/openvpn/mss.c index 5b110d2f892..51e1ae00c6f 100644 --- a/src/openvpn/mss.c +++ b/src/openvpn/mss.c @@ -161,7 +161,8 @@ mss_fixup_dowork(struct buffer *buf, uint16_t maxmss) for (olen = hlen - sizeof(struct openvpn_tcphdr), opt = (uint8_t *)(tc + 1); olen > 0; - olen -= optlen, opt += optlen) { + olen -= optlen, opt += optlen) + { if (*opt == OPENVPN_TCPOPT_EOL) { break; diff --git a/src/openvpn/mtcp.c b/src/openvpn/mtcp.c index b5471b11a80..195d08d38ac 100644 --- a/src/openvpn/mtcp.c +++ b/src/openvpn/mtcp.c @@ -587,7 +587,8 @@ multi_tcp_action(struct multi_context *m, struct multi_instance *mi, int action, { bool tun_input_pending = false; - do { + do + { dmsg(D_MULTI_DEBUG, "MULTI TCP: multi_tcp_action a=%s p=%d", pract(action), poll); diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index f6f3f5d98f2..56009b7320a 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -537,10 +537,14 @@ multi_del_iroutes(struct multi_context *m, if (TUNNEL_TYPE(mi->context.c1.tuntap) == DEV_TYPE_TUN) { for (ir = mi->context.options.iroutes; ir != NULL; ir = ir->next) + { mroute_helper_del_iroute46(m->route_helper, ir->netbits); + } for (ir6 = mi->context.options.iroutes_ipv6; ir6 != NULL; ir6 = ir6->next) + { mroute_helper_del_iroute46(m->route_helper, ir6->netbits); + } } } @@ -819,7 +823,8 @@ multi_create_instance(struct multi_context *m, const struct mroute_addr *real) mi->did_iter = true; #ifdef MANAGEMENT_DEF_AUTH - do { + do + { mi->context.c2.mda_context.cid = m->cid_counter++; } while (!hash_add(m->cid_hash, &mi->context.c2.mda_context.cid, mi, false)); mi->did_cid_hash = true; @@ -2949,10 +2954,14 @@ gremlin_flood_clients(struct multi_context *m) parm.packet_size); for (i = 0; i < parm.packet_size; ++i) + { ASSERT(buf_write_u8(&buf, get_random() & 0xFF)); + } for (i = 0; i < parm.n_packets; ++i) + { multi_bcast(m, &buf, NULL, NULL); + } gc_free(&gc); } @@ -3375,6 +3384,7 @@ tunnel_server(struct context *top) #else /* if P2MP_SERVER */ static void -dummy(void) { +dummy(void) +{ } #endif /* P2MP_SERVER */ diff --git a/src/openvpn/ntlm.c b/src/openvpn/ntlm.c index e78af9e6f42..0c436812ece 100644 --- a/src/openvpn/ntlm.c +++ b/src/openvpn/ntlm.c @@ -124,7 +124,8 @@ gen_nonce(unsigned char *nonce) /* Generates 8 random bytes to be used as client nonce */ int i; - for (i = 0; i<8; i++) { + for (i = 0; i<8; i++) + { nonce[i] = (unsigned char)get_random(); } } @@ -135,7 +136,10 @@ my_strupr(unsigned char *str) /* converts string to uppercase in place */ unsigned char *tmp = str; - do *str = toupper(*str); while (*(++str)); + do + { + *str = toupper(*str); + } while (*(++str)); return tmp; } @@ -373,6 +377,7 @@ ntlm_phase_3(const struct http_proxy_info *p, const char *phase_2, struct gc_are #else /* if NTLM */ static void -dummy(void) { +dummy(void) +{ } #endif /* if NTLM */ diff --git a/src/openvpn/occ.c b/src/openvpn/occ.c index b4ccc4de57b..e720f6c68a4 100644 --- a/src/openvpn/occ.c +++ b/src/openvpn/occ.c @@ -430,6 +430,7 @@ process_received_occ_msg(struct context *c) #else /* ifdef ENABLE_OCC */ static void -dummy(void) { +dummy(void) +{ } #endif /* ifdef ENABLE_OCC */ diff --git a/src/openvpn/openvpn.c b/src/openvpn/openvpn.c index 888acda6adc..3cb33b6e272 100644 --- a/src/openvpn/openvpn.c +++ b/src/openvpn/openvpn.c @@ -332,7 +332,8 @@ openvpn_main(int argc, char *argv[]) #ifdef _WIN32 int -wmain(int argc, wchar_t *wargv[]) { +wmain(int argc, wchar_t *wargv[]) +{ char **argv; int ret; int i; @@ -361,7 +362,8 @@ wmain(int argc, wchar_t *wargv[]) { } #else /* ifdef _WIN32 */ int -main(int argc, char *argv[]) { +main(int argc, char *argv[]) +{ return openvpn_main(argc, argv); } #endif /* ifdef _WIN32 */ diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 5eaff42c0dc..6682bb76b11 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -998,7 +998,9 @@ setenv_settings(struct env_set *es, const struct options *o) { int i; for (i = 0; i < o->connection_list->len; ++i) + { setenv_connection_entry(es, o->connection_list->array[i], i+1); + } } else { @@ -1759,7 +1761,9 @@ show_settings(const struct options *o) { int i; for (i = 0; ipkcs11_providers[i] != NULL; i++) + { SHOW_PARM(pkcs11_providers, o->pkcs11_providers[i], "%s"); + } } { int i; for (i = 0; ipkcs11_protected_authentication[i] ? "ENABLED" : "DISABLED", "%s"); + } } { int i; for (i = 0; ipkcs11_private_mode[i], "%08x"); + } } { int i; for (i = 0; ipkcs11_cert_private[i] ? "ENABLED" : "DISABLED", "%s"); + } } SHOW_INT(pkcs11_pin_cache_period); SHOW_STR(pkcs11_id); @@ -2937,7 +2949,9 @@ options_postprocess_verify(const struct options *o) { int i; for (i = 0; i < o->connection_list->len; ++i) + { options_postprocess_verify_ce(o, o->connection_list->array[i]); + } } else { @@ -2988,7 +3002,9 @@ options_postprocess_mutate(struct options *o) ASSERT(o->connection_list); for (i = 0; i < o->connection_list->len; ++i) + { options_postprocess_mutate_ce(o, o->connection_list->array[i]); + } #ifdef ENABLE_CRYPTO if (o->tls_server) @@ -3801,7 +3817,9 @@ options_warning_safe_scan1(const int msglevel, char *p = gc_malloc(OPTION_PARM_SIZE, true, &gc); while (buf_parse(&b, delim, p, OPTION_PARM_SIZE)) + { options_warning_safe_scan2(msglevel, delim, report_inconsistent, p, b2_src, b1_name, b2_name); + } gc_free(&gc); } @@ -4429,7 +4447,10 @@ read_inline_file(struct in_src *is, const char *close_tag, struct gc_arena *gc) { char *line_ptr = line; /* Remove leading spaces */ - while (isspace(*line_ptr)) line_ptr++; + while (isspace(*line_ptr)) + { + line_ptr++; + } if (!strncmp(line_ptr, close_tag, strlen(close_tag))) { endtagfound = true; @@ -5319,18 +5340,24 @@ add_option(struct options *options, VERIFY_PERMISSION(OPT_P_GENERAL); /* Find out how many options to be ignored */ for (i = 1; p[i]; i++) + { numignored++; + } /* add number of options already ignored */ for (i = 0; options->ignore_unknown_option && options->ignore_unknown_option[i]; i++) + { numignored++; + } /* Allocate array */ ALLOC_ARRAY_GC(ignore, const char *, numignored+1, &options->gc); for (i = 0; options->ignore_unknown_option && options->ignore_unknown_option[i]; i++) + { ignore[i] = options->ignore_unknown_option[i]; + } options->ignore_unknown_option = ignore; @@ -6014,7 +6041,8 @@ add_option(struct options *options, struct http_custom_header *custom_header = NULL; int i; /* Find the first free header */ - for (i = 0; i < MAX_CUSTOM_HTTP_HEADER; i++) { + for (i = 0; i < MAX_CUSTOM_HTTP_HEADER; i++) + { if (!ho->custom_headers[i].name) { custom_header = &ho->custom_headers[i]; @@ -7907,7 +7935,9 @@ add_option(struct options *options, VERIFY_PERMISSION(OPT_P_GENERAL); for (j = 1; j < MAX_PARMS && p[j] != NULL; ++j) + { sscanf(p[j], "%x", &(options->remote_cert_ku[j-1])); + } } else if (streq(p[0], "remote-cert-eku") && p[1] && !p[2]) { @@ -8036,10 +8066,16 @@ add_option(struct options *options, if (strncmp("ext:", s, 4) != 0) { size_t i = 0; - while (s[i] && !isupper(s[i])) i++; + while (s[i] && !isupper(s[i])) + { + i++; + } if (strlen(s) == i) { - while ((*s = toupper(*s)) != '\0') s++; + while ((*s = toupper(*s)) != '\0') + { + s++; + } msg(M_WARN, "DEPRECATED FEATURE: automatically upcased the " "--x509-username-field parameter to '%s'; please update your" "configuration", p[1]); @@ -8093,7 +8129,9 @@ add_option(struct options *options, VERIFY_PERMISSION(OPT_P_GENERAL); for (j = 1; j < MAX_PARMS && p[j] != NULL; ++j) + { options->pkcs11_providers[j-1] = p[j]; + } } else if (streq(p[0], "pkcs11-protected-authentication")) { @@ -8102,7 +8140,9 @@ add_option(struct options *options, VERIFY_PERMISSION(OPT_P_GENERAL); for (j = 1; j < MAX_PARMS && p[j] != NULL; ++j) + { options->pkcs11_protected_authentication[j-1] = atoi(p[j]) != 0 ? 1 : 0; + } } else if (streq(p[0], "pkcs11-private-mode") && p[1]) { @@ -8111,7 +8151,9 @@ add_option(struct options *options, VERIFY_PERMISSION(OPT_P_GENERAL); for (j = 1; j < MAX_PARMS && p[j] != NULL; ++j) + { sscanf(p[j], "%x", &(options->pkcs11_private_mode[j-1])); + } } else if (streq(p[0], "pkcs11-cert-private")) { @@ -8120,7 +8162,9 @@ add_option(struct options *options, VERIFY_PERMISSION(OPT_P_GENERAL); for (j = 1; j < MAX_PARMS && p[j] != NULL; ++j) + { options->pkcs11_cert_private[j-1] = atoi(p[j]) != 0 ? 1 : 0; + } } else if (streq(p[0], "pkcs11-pin-cache") && p[1] && !p[2]) { diff --git a/src/openvpn/otime.h b/src/openvpn/otime.h index eede63d200d..ad066b6e7c6 100644 --- a/src/openvpn/otime.h +++ b/src/openvpn/otime.h @@ -289,7 +289,8 @@ tv_within_sigma(const struct timeval *t1, const struct timeval *t2, unsigned int * called again. */ static inline void -interval_earliest_wakeup(interval_t *wakeup, time_t at, time_t current) { +interval_earliest_wakeup(interval_t *wakeup, time_t at, time_t current) +{ if (at > current) { const interval_t delta = (interval_t) (at - current); diff --git a/src/openvpn/packet_id.c b/src/openvpn/packet_id.c index fe13e1d8a52..e34c228b7f6 100644 --- a/src/openvpn/packet_id.c +++ b/src/openvpn/packet_id.c @@ -629,7 +629,8 @@ packet_id_interactive_test() packet_id_init(&pid, seq_backtrack, time_backtrack); - while (true) { + while (true) + { char buf[80]; if (!fgets(buf, sizeof(buf), stdin)) { diff --git a/src/openvpn/perf.c b/src/openvpn/perf.c index 51e051ab1b4..3603f4e1998 100644 --- a/src/openvpn/perf.c +++ b/src/openvpn/perf.c @@ -147,12 +147,14 @@ push_perf_index(int pindex) { int i; for (i = 0; i < sindex; ++i) + { if (perf_set.stack[i] == pindex) { perf_print_state(M_INFO); msg(M_FATAL, "PERF: push_perf_index %s failed", metric_names [pindex]); } + } perf_set.stack[sindex] = pindex; perf_set.stack_len = newlen; @@ -321,7 +323,8 @@ perf_print_state(int lev) #else /* ifdef ENABLE_PERFORMANCE_METRICS */ #ifdef _MSC_VER /* Dummy function needed to avoid empty file compiler warning in Microsoft VC */ static void -dummy(void) { +dummy(void) +{ } #endif #endif /* ifdef ENABLE_PERFORMANCE_METRICS */ diff --git a/src/openvpn/perf.h b/src/openvpn/perf.h index f0430a14596..a6708436532 100644 --- a/src/openvpn/perf.h +++ b/src/openvpn/perf.h @@ -76,13 +76,16 @@ void perf_output_results(void); #else /* ifdef ENABLE_PERFORMANCE_METRICS */ static inline void -perf_push(int type) { +perf_push(int type) +{ } static inline void -perf_pop(void) { +perf_pop(void) +{ } static inline void -perf_output_results(void) { +perf_output_results(void) +{ } #endif /* ifdef ENABLE_PERFORMANCE_METRICS */ diff --git a/src/openvpn/pkcs11.c b/src/openvpn/pkcs11.c index 6858846b9e7..3e494e51f1a 100644 --- a/src/openvpn/pkcs11.c +++ b/src/openvpn/pkcs11.c @@ -45,21 +45,24 @@ static time_t -__mytime(void) { +__mytime(void) +{ return openvpn_time(NULL); } #if !defined(_WIN32) static int -__mygettimeofday(struct timeval *tv) { +__mygettimeofday(struct timeval *tv) +{ return gettimeofday(tv, NULL); } #endif static void -__mysleep(const unsigned long usec) { +__mysleep(const unsigned long usec) +{ #if defined(_WIN32) Sleep(usec/1000); #else @@ -84,10 +87,12 @@ static unsigned _pkcs11_msg_pkcs112openvpn( const unsigned flags - ) { + ) +{ unsigned openvpn_flags; - switch (flags) { + switch (flags) + { case PKCS11H_LOG_DEBUG2: openvpn_flags = D_PKCS11_DEBUG; break; @@ -124,7 +129,8 @@ static unsigned _pkcs11_msg_openvpn2pkcs11( const unsigned flags - ) { + ) +{ unsigned pkcs11_flags; if ((flags & D_PKCS11_DEBUG) != 0) @@ -166,7 +172,8 @@ _pkcs11_openvpn_log( unsigned flags, const char *const szFormat, va_list args - ) { + ) +{ char Buffer[10*1024]; (void)global_data; @@ -184,7 +191,8 @@ _pkcs11_openvpn_token_prompt( void *const user_data, const pkcs11h_token_id_t token, const unsigned retry - ) { + ) +{ struct user_pass token_resp; (void)global_data; @@ -229,7 +237,8 @@ _pkcs11_openvpn_pin_prompt( const unsigned retry, char *const pin, const size_t pin_max - ) { + ) +{ struct user_pass token_pass; char prompt[1024]; @@ -275,7 +284,8 @@ bool pkcs11_initialize( const bool protected_auth, const int nPINCachePeriod - ) { + ) +{ CK_RV rv = CKR_FUNCTION_FAILED; dmsg( @@ -347,7 +357,8 @@ pkcs11_initialize( } void -pkcs11_terminate() { +pkcs11_terminate() +{ dmsg( D_PKCS11_DEBUG, "PKCS#11: pkcs11_terminate - entered" @@ -367,7 +378,8 @@ pkcs11_addProvider( const bool protected_auth, const unsigned private_mode, const bool cert_private - ) { + ) +{ CK_RV rv = CKR_OK; ASSERT(provider!=NULL); @@ -411,12 +423,14 @@ pkcs11_addProvider( } int -pkcs11_logout() { +pkcs11_logout() +{ return pkcs11h_logout() == CKR_OK; } int -pkcs11_management_id_count() { +pkcs11_management_id_count() +{ pkcs11h_certificate_id_list_t id_list = NULL; pkcs11h_certificate_id_list_t t = NULL; CK_RV rv = CKR_OK; @@ -441,7 +455,8 @@ pkcs11_management_id_count() { goto cleanup; } - for (count = 0, t = id_list; t != NULL; t = t->next) { + for (count = 0, t = id_list; t != NULL; t = t->next) + { count++; } @@ -467,7 +482,8 @@ pkcs11_management_id_get( const int index, char **id, char **base64 - ) { + ) +{ pkcs11h_certificate_id_list_t id_list = NULL; pkcs11h_certificate_id_list_t entry = NULL; #if 0 /* certificate_id seems to be unused -- JY */ @@ -511,7 +527,8 @@ pkcs11_management_id_get( entry = id_list; count = 0; - while (entry != NULL && count != index) { + while (entry != NULL && count != index) + { count++; entry = entry->next; } @@ -653,7 +670,8 @@ tls_ctx_use_pkcs11( struct tls_root_ctx *const ssl_ctx, bool pkcs11_id_management, const char *const pkcs11_id - ) { + ) +{ pkcs11h_certificate_id_t certificate_id = NULL; pkcs11h_certificate_t certificate = NULL; CK_RV rv = CKR_OK; @@ -784,7 +802,8 @@ _pkcs11_openvpn_show_pkcs11_ids_pin_prompt( const unsigned retry, char *const pin, const size_t pin_max - ) { + ) +{ struct gc_arena gc = gc_new(); struct buffer pass_prompt = alloc_buf_gc(128, &gc); @@ -817,7 +836,8 @@ void show_pkcs11_ids( const char *const provider, bool cert_private - ) { + ) +{ struct gc_arena gc = gc_new(); pkcs11h_certificate_id_list_t user_certificates = NULL; pkcs11h_certificate_id_list_t current = NULL; @@ -888,7 +908,8 @@ show_pkcs11_ids( "--pkcs11-id option please remember to use single quote mark.\n" ) ); - for (current = user_certificates; current != NULL; current = current->next) { + for (current = user_certificates; current != NULL; current = current->next) + { pkcs11h_certificate_t certificate = NULL; char *dn = NULL; char serial[1024] = {0}; @@ -1006,7 +1027,8 @@ show_pkcs11_ids( #else /* if defined(ENABLE_PKCS11) */ #ifdef _MSC_VER /* Dummy function needed to avoid empty file compiler warning in Microsoft VC */ static void -dummy(void) { +dummy(void) +{ } #endif #endif /* ENABLE_PKCS11 */ diff --git a/src/openvpn/plugin.c b/src/openvpn/plugin.c index 17eb2d8c5c8..e530c0c5f3e 100644 --- a/src/openvpn/plugin.c +++ b/src/openvpn/plugin.c @@ -745,7 +745,9 @@ plugin_common_close(struct plugin_common *pc) int i; for (i = 0; i < pc->n; ++i) + { plugin_close_item(&pc->plugins[i]); + } free(pc); } } @@ -883,7 +885,9 @@ plugin_abort(void) int i; for (i = 0; i < pc->n; ++i) + { plugin_abort_item(&pc->plugins[i]); + } } } @@ -964,7 +968,9 @@ plugin_return_get_column(const struct plugin_return *src, dest->n = 0; for (i = 0; i < src->n; ++i) + { dest->list[i] = openvpn_plugin_string_list_find(src->list[i], colname); + } dest->n = i; } @@ -973,7 +979,9 @@ plugin_return_free(struct plugin_return *pr) { int i; for (i = 0; i < pr->n; ++i) + { openvpn_plugin_string_list_free(pr->list[i]); + } pr->n = 0; } @@ -1003,6 +1011,7 @@ plugin_return_print(const int msglevel, const char *prefix, const struct plugin_ #else /* ifdef ENABLE_PLUGIN */ static void -dummy(void) { +dummy(void) +{ } #endif /* ENABLE_PLUGIN */ diff --git a/src/openvpn/pool.c b/src/openvpn/pool.c index aa0bc2b8d78..9543a9d3224 100644 --- a/src/openvpn/pool.c +++ b/src/openvpn/pool.c @@ -215,7 +215,9 @@ ifconfig_pool_free(struct ifconfig_pool *pool) { int i; for (i = 0; i < pool->size; ++i) + { ifconfig_pool_entry_free(&pool->list[i], true); + } free(pool->list); free(pool); } diff --git a/src/openvpn/proxy.c b/src/openvpn/proxy.c index dd327a2f080..b0ed32796ce 100644 --- a/src/openvpn/proxy.c +++ b/src/openvpn/proxy.c @@ -381,7 +381,9 @@ get_key_value(const char *str, /* source string */ bool escape = false; for (c = max_key_len-1; (*str && (*str != '=') && c--); ) + { *key++ = *str++; + } *key = '\0'; if ('=' != *str++) @@ -475,7 +477,9 @@ get_pa_var(const char *key, const char *pa, struct gc_arena *gc) ++content; } while (*content && isspace(*content)) + { ++content; + } } } @@ -774,7 +778,8 @@ establish_http_proxy_passthru(struct http_proxy_info *p, /* receive and discard everything else */ while (recv_line(sd, NULL, 0, 2, true, NULL, signal_received)) - ; + { + } /* now send the phase 3 reply */ @@ -1041,7 +1046,8 @@ establish_http_proxy_passthru(struct http_proxy_info *p, * start of the OpenVPN data stream (put it in lookahead). */ while (recv_line(sd, NULL, 0, 2, false, lookahead, signal_received)) - ; + { + } /* reset queried_creds so that we don't think that the next creds request is due to an auth error */ p->queried_creds = false; diff --git a/src/openvpn/reliable.c b/src/openvpn/reliable.c index 57cdd785408..9de974bf9d5 100644 --- a/src/openvpn/reliable.c +++ b/src/openvpn/reliable.c @@ -112,10 +112,12 @@ reliable_ack_packet_id_present(struct reliable_ack *ack, packet_id_type pid) { int i; for (i = 0; i < ack->len; ++i) + { if (ack->packet_id[i] == pid) { return true; } + } return false; } @@ -242,7 +244,9 @@ reliable_ack_write(struct reliable_ack *ack, ASSERT(session_id_defined(sid)); ASSERT(session_id_write(sid, &sub)); for (i = 0, j = n; j < ack->len; ) + { ack->packet_id[i++] = ack->packet_id[j++]; + } ack->len = i; } @@ -802,6 +806,7 @@ reliable_debug_print(const struct reliable *rel, char *desc) #else /* ifdef ENABLE_CRYPTO */ static void -dummy(void) { +dummy(void) +{ } #endif /* ENABLE_CRYPTO */ diff --git a/src/openvpn/route.c b/src/openvpn/route.c index 0c93dcdf736..223cb5f4c37 100644 --- a/src/openvpn/route.c +++ b/src/openvpn/route.c @@ -1281,7 +1281,9 @@ print_route_options(const struct route_option_list *rol, (rol->flags & RG_LOCAL) != 0); } for (ro = rol->routes; ro; ro = ro->next) + { print_route_option(ro, level); + } } void @@ -1375,7 +1377,9 @@ print_routes(const struct route_list *rl, int level) { struct route_ipv4 *r; for (r = rl->routes; r; r = r->next) + { print_route(r, level); + } } static void @@ -1404,7 +1408,9 @@ setenv_routes(struct env_set *es, const struct route_list *rl) int i = 1; struct route_ipv4 *r; for (r = rl->routes; r; r = r->next) + { setenv_route(es, r, i++); + } } static void @@ -1433,7 +1439,9 @@ setenv_routes_ipv6(struct env_set *es, const struct route_ipv6_list *rl6) int i = 1; struct route_ipv6 *r6; for (r6 = rl6->routes_ipv6; r6; r6 = r6->next) + { setenv_route_ipv6(es, r6, i++); + } } /* @@ -2623,7 +2631,9 @@ test_routes(const struct route_list *rl, const struct tuntap *tt) { struct route_ipv4 *r; for (r = rl->routes, len = 0; r; r = r->next, ++len) + { test_route_helper(&ret, &count, &good, &ambig, adapters, r->gateway); + } if ((rl->flags & RG_ENABLE) && (rl->spec.flags & RTSA_REMOTE_ENDPOINT)) { @@ -3608,7 +3618,8 @@ get_default_gateway(struct route_gateway_info *rgi) msg(M_WARN, "GDG: problem writing to routing socket"); goto done; } - do { + do + { l = read(sockfd, (char *)&m_rtmsg, sizeof(m_rtmsg)); } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid)); close(sockfd); diff --git a/src/openvpn/route.h b/src/openvpn/route.h index 03ee8cde61f..d6836abf3f7 100644 --- a/src/openvpn/route.h +++ b/src/openvpn/route.h @@ -354,7 +354,8 @@ bool del_route_ipapi(const struct route_ipv4 *r, const struct tuntap *tt); #else /* ifdef _WIN32 */ static inline bool -test_routes(const struct route_list *rl, const struct tuntap *tt) { +test_routes(const struct route_list *rl, const struct tuntap *tt) +{ return true; } #endif diff --git a/src/openvpn/schedule.c b/src/openvpn/schedule.c index 610bfa42304..8a9eb3f9e3b 100644 --- a/src/openvpn/schedule.c +++ b/src/openvpn/schedule.c @@ -377,7 +377,9 @@ schedule_add_modify(struct schedule *s, struct schedule_entry *e) * keeps the tree balanced. Move the node up the tree until * its own priority is greater than that of its parent */ while (e->parent && e->parent->pri > e->pri) + { schedule_rotate_up(s, e); + } } /* @@ -623,7 +625,9 @@ schedule_print_work(struct schedule_entry *e, int indent) struct gc_arena gc = gc_new(); int i; for (i = 0; i < indent; ++i) + { printf(" "); + } if (e) { printf("%s [%u] e=" ptr_format ", p=" ptr_format " lt=" ptr_format " gt=" ptr_format "\n", diff --git a/src/openvpn/session_id.c b/src/openvpn/session_id.c index b23f0f45959..04caf39a2e0 100644 --- a/src/openvpn/session_id.c +++ b/src/openvpn/session_id.c @@ -64,6 +64,7 @@ session_id_print(const struct session_id *sid, struct gc_arena *gc) #else /* ifdef ENABLE_CRYPTO */ static void -dummy(void) { +dummy(void) +{ } #endif /* ENABLE_CRYPTO */ diff --git a/src/openvpn/shaper.c b/src/openvpn/shaper.c index eb459ef1e0d..bb936acb2a0 100644 --- a/src/openvpn/shaper.c +++ b/src/openvpn/shaper.c @@ -98,6 +98,7 @@ shaper_msg(struct shaper *s) #else /* ifdef ENABLE_FEATURE_SHAPER */ static void -dummy(void) { +dummy(void) +{ } #endif /* ENABLE_FEATURE_SHAPER */ diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c index ae1283250f4..82d0967d1a8 100644 --- a/src/openvpn/socket.c +++ b/src/openvpn/socket.c @@ -205,7 +205,9 @@ do_preresolve_host(struct context *c, { struct cached_dns_entry *prev = c->c1.dns_cache; while (prev->next) + { prev = prev->next; + } prev->next = ph; } @@ -2008,7 +2010,8 @@ static void phase2_tcp_client(struct link_socket *sock, struct signal_info *sig_info) { bool proxy_retry = false; - do { + do + { socket_connect(&sock->sd, sock->info.lsa->current_remote->ai_addr, get_server_poll_remaining_time(sock->server_poll_timeout), @@ -2364,7 +2367,8 @@ link_socket_bad_incoming_addr(struct buffer *buf, (int)from_addr->dest.addr.sa.sa_family, print_sockaddr_ex(info->lsa->remote_list->ai_addr,":",PS_SHOW_PORT, &gc)); /* print additional remote addresses */ - for (ai = info->lsa->remote_list->ai_next; ai; ai = ai->ai_next) { + for (ai = info->lsa->remote_list->ai_next; ai; ai = ai->ai_next) + { msg(D_LINK_ERRORS,"or from peer address: %s", print_sockaddr_ex(ai->ai_addr,":",PS_SHOW_PORT, &gc)); } @@ -3053,10 +3057,12 @@ ascii2proto(const char *proto_name) { int i; for (i = 0; i < SIZE(proto_names); ++i) + { if (!strcmp(proto_name, proto_names[i].short_form)) { return proto_names[i].proto; } + } return -1; } @@ -3065,10 +3071,12 @@ ascii2af(const char *proto_name) { int i; for (i = 0; i < SIZE(proto_names); ++i) + { if (!strcmp(proto_name, proto_names[i].short_form)) { return proto_names[i].proto_af; } + } return 0; } diff --git a/src/openvpn/socket.h b/src/openvpn/socket.h index 63e601e8fe7..3d96aab04ac 100644 --- a/src/openvpn/socket.h +++ b/src/openvpn/socket.h @@ -623,7 +623,8 @@ addr_defined(const struct openvpn_sockaddr *addr) { return 0; } - switch (addr->addr.sa.sa_family) { + switch (addr->addr.sa.sa_family) + { case AF_INET: return addr->addr.in4.sin_addr.s_addr != 0; case AF_INET6: return !IN6_IS_ADDR_UNSPECIFIED(&addr->addr.in6.sin6_addr); @@ -639,7 +640,8 @@ addr_local(const struct sockaddr *addr) { return false; } - switch (addr->sa_family) { + switch (addr->sa_family) + { case AF_INET: return ((const struct sockaddr_in *)addr)->sin_addr.s_addr == htonl(INADDR_LOOPBACK); @@ -660,7 +662,8 @@ addr_defined_ipi(const struct link_socket_actual *lsa) { return 0; } - switch (lsa->dest.addr.sa.sa_family) { + switch (lsa->dest.addr.sa.sa_family) + { #if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) case AF_INET: return lsa->pi.in4.ipi_spec_dst.s_addr != 0; @@ -687,7 +690,8 @@ link_socket_actual_defined(const struct link_socket_actual *act) static inline bool addr_match(const struct openvpn_sockaddr *a1, const struct openvpn_sockaddr *a2) { - switch (a1->addr.sa.sa_family) { + switch (a1->addr.sa.sa_family) + { case AF_INET: return a1->addr.in4.sin_addr.s_addr == a2->addr.in4.sin_addr.s_addr; @@ -781,7 +785,8 @@ addrlist_port_match(const struct openvpn_sockaddr *a1, const struct addrinfo *a2 static inline bool addr_port_match(const struct openvpn_sockaddr *a1, const struct openvpn_sockaddr *a2) { - switch (a1->addr.sa.sa_family) { + switch (a1->addr.sa.sa_family) + { case AF_INET: return a1->addr.in4.sin_addr.s_addr == a2->addr.in4.sin_addr.s_addr && a1->addr.in4.sin_port == a2->addr.in4.sin_port; @@ -818,7 +823,8 @@ addrlist_match_proto(const struct openvpn_sockaddr *a1, static inline void addr_zero_host(struct openvpn_sockaddr *addr) { - switch (addr->addr.sa.sa_family) { + switch (addr->addr.sa.sa_family) + { case AF_INET: addr->addr.in4.sin_addr.s_addr = 0; break; @@ -846,7 +852,8 @@ int addr_guess_family(sa_family_t af,const char *name); static inline int af_addr_size(sa_family_t af) { - switch (af) { + switch (af) + { case AF_INET: return sizeof(struct sockaddr_in); case AF_INET6: return sizeof(struct sockaddr_in6); @@ -919,7 +926,8 @@ link_socket_verify_incoming_addr(struct buffer *buf, { if (buf->len > 0) { - switch (from_addr->dest.addr.sa.sa_family) { + switch (from_addr->dest.addr.sa.sa_family) + { case AF_INET6: case AF_INET: if (!link_socket_actual_defined(from_addr)) diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index cff40529f3c..fe5ea940954 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -269,10 +269,12 @@ static void key_ctx_update_implicit_iv(struct key_ctx *ctx, uint8_t *key, size_t key_len); const tls_cipher_name_pair * -tls_get_cipher_name_pair(const char *cipher_name, size_t len) { +tls_get_cipher_name_pair(const char *cipher_name, size_t len) +{ const tls_cipher_name_pair *pair = tls_cipher_name_translation_table; - while (pair->openssl_name != NULL) { + while (pair->openssl_name != NULL) + { if ((strlen(pair->openssl_name) == len && 0 == memcmp(cipher_name, pair->openssl_name, len)) || (strlen(pair->iana_name) == len && 0 == memcmp(cipher_name, pair->iana_name, len))) { @@ -1068,7 +1070,9 @@ tls_session_init(struct tls_multi *multi, struct tls_session *session) /* Randomize session # if it is 0 */ while (!session_id_defined(&session->session_id)) + { session_id_random(&session->session_id); + } /* Are we a TLS server or client? */ ASSERT(session->opt->key_method >= 1); @@ -1130,7 +1134,9 @@ tls_session_free(struct tls_session *session, bool clear) free_buf(&session->tls_wrap.work); for (i = 0; i < KS_SIZE; ++i) + { key_state_free(&session->key[i], false); + } if (session->common_name) { @@ -1187,7 +1193,8 @@ reset_session(struct tls_multi *multi, struct tls_session *session) * called again. */ static inline void -compute_earliest_wakeup(interval_t *earliest, interval_t seconds_from_now) { +compute_earliest_wakeup(interval_t *earliest, interval_t seconds_from_now) +{ if (seconds_from_now < *earliest) { *earliest = seconds_from_now; @@ -1357,7 +1364,9 @@ tls_multi_free(struct tls_multi *multi, bool clear) free(multi->remote_ciphername); for (i = 0; i < TM_SIZE; ++i) + { tls_session_free(&multi->session[i], false); + } if (clear) { @@ -1705,7 +1714,9 @@ tls1_PRF(const uint8_t *label, tls1_P_hash(sha1,S2,len,label,label_len,out2,olen); for (i = 0; icipher); /* Only use implicit IV in AEAD cipher mode, where HMAC key is not used */ @@ -4058,7 +4070,8 @@ tls_peer_info_ncp_ver(const char *peer_info) } bool -tls_check_ncp_cipher_list(const char *list) { +tls_check_ncp_cipher_list(const char *list) +{ bool unsupported_cipher_found = false; ASSERT(list); @@ -4203,6 +4216,7 @@ protocol_dump(struct buffer *buffer, unsigned int flags, struct gc_arena *gc) #else /* if defined(ENABLE_CRYPTO) */ static void -dummy(void) { +dummy(void) +{ } #endif /* ENABLE_CRYPTO */ diff --git a/src/openvpn/ssl_mbedtls.c b/src/openvpn/ssl_mbedtls.c index 5c84e300505..ba8dadfae91 100644 --- a/src/openvpn/ssl_mbedtls.c +++ b/src/openvpn/ssl_mbedtls.c @@ -185,7 +185,8 @@ tls_ctx_set_options(struct tls_root_ctx *ctx, unsigned int ssl_flags) } static const char * -tls_translate_cipher_name(const char *cipher_name) { +tls_translate_cipher_name(const char *cipher_name) +{ const tls_cipher_name_pair *pair = tls_get_cipher_name_pair(cipher_name, strlen(cipher_name)); if (NULL == pair) @@ -222,10 +223,12 @@ tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers) /* Get number of ciphers */ for (i = 0, cipher_count = 1; i < ciphers_len; i++) + { if (ciphers[i] == ':') { cipher_count++; } + } /* Allocate an array for them */ ALLOC_ARRAY_CLEAR(ctx->allowed_ciphers, int, cipher_count+1) @@ -833,7 +836,8 @@ tls_version_max(void) * Must be a valid pointer. */ static void -tls_version_to_major_minor(int tls_ver, int *major, int *minor) { +tls_version_to_major_minor(int tls_ver, int *major, int *minor) +{ ASSERT(major); ASSERT(minor); diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c index eae1e22669a..8266595623e 100644 --- a/src/openvpn/ssl_openssl.c +++ b/src/openvpn/ssl_openssl.c @@ -321,7 +321,8 @@ tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers) /* Translate IANA cipher suite names to OpenSSL names */ begin_of_cipher = end_of_cipher = 0; - for (; begin_of_cipher < strlen(ciphers); begin_of_cipher = end_of_cipher) { + for (; begin_of_cipher < strlen(ciphers); begin_of_cipher = end_of_cipher) + { end_of_cipher += strcspn(&ciphers[begin_of_cipher], ":"); cipher_pair = tls_get_cipher_name_pair(&ciphers[begin_of_cipher], end_of_cipher - begin_of_cipher); diff --git a/src/openvpn/ssl_verify.c b/src/openvpn/ssl_verify.c index 334eb2923a4..9f12ab8b273 100644 --- a/src/openvpn/ssl_verify.c +++ b/src/openvpn/ssl_verify.c @@ -90,8 +90,12 @@ tls_deauthenticate(struct tls_multi *multi) { int i, j; for (i = 0; i < TM_SIZE; ++i) + { for (j = 0; j < KS_SIZE; ++j) + { multi->session[i].key[j].authenticated = false; + } + } } } @@ -248,7 +252,9 @@ cert_hash_free(struct cert_hash_set *chs) { int i; for (i = 0; i < MAX_CERT_DEPTH; ++i) + { free(chs->ch[i]); + } free(chs); } } diff --git a/src/openvpn/ssl_verify_mbedtls.c b/src/openvpn/ssl_verify_mbedtls.c index f01569fdaaf..4068dd30eaa 100644 --- a/src/openvpn/ssl_verify_mbedtls.c +++ b/src/openvpn/ssl_verify_mbedtls.c @@ -269,10 +269,12 @@ asn1_buf_to_c_string(const mbedtls_asn1_buf *orig, struct gc_arena *gc) char *val; for (i = 0; i < orig->len; ++i) + { if (orig->p[i] == '\0') { return "ERROR: embedded null value"; } + } val = gc_malloc(orig->len+1, false, gc); memcpy(val, orig->p, orig->len); val[orig->len] = '\0'; diff --git a/src/openvpn/ssl_verify_openssl.c b/src/openvpn/ssl_verify_openssl.c index e9692a09b65..274e2bbf96b 100644 --- a/src/openvpn/ssl_verify_openssl.c +++ b/src/openvpn/ssl_verify_openssl.c @@ -193,7 +193,8 @@ extract_x509_field_ssl(X509_NAME *x509, const char *field_name, char *out, ASSERT(size > 0); *out = '\0'; - do { + do + { lastpos = tmp; tmp = X509_NAME_get_index_by_NID(x509, nid, lastpos); } while (tmp > -1); diff --git a/src/openvpn/tls_crypt.c b/src/openvpn/tls_crypt.c index c227b098f17..804c27926ae 100644 --- a/src/openvpn/tls_crypt.c +++ b/src/openvpn/tls_crypt.c @@ -44,7 +44,8 @@ tls_crypt_buf_overhead(void) void tls_crypt_init_key(struct key_ctx_bi *key, const char *key_file, - const char *key_inline, bool tls_server) { + const char *key_inline, bool tls_server) +{ const int key_direction = tls_server ? KEY_DIRECTION_NORMAL : KEY_DIRECTION_INVERSE; @@ -79,7 +80,8 @@ tls_crypt_adjust_frame_parameters(struct frame *frame) bool tls_crypt_wrap(const struct buffer *src, struct buffer *dst, - struct crypto_options *opt) { + struct crypto_options *opt) +{ const struct key_ctx *ctx = &opt->key_ctx_bi.encrypt; struct gc_arena gc; diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index ec9997edacf..31585b325ea 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -694,7 +694,8 @@ init_tun(const char *dev, /* --dev option */ * make sure they do not clash with our virtual subnet. */ - for (curele = local_public; curele; curele = curele->ai_next) { + for (curele = local_public; curele; curele = curele->ai_next) + { if (curele->ai_family == AF_INET) { check_addr_clash("local", @@ -705,7 +706,8 @@ init_tun(const char *dev, /* --dev option */ } } - for (curele = remote_public; curele; curele = curele->ai_next) { + for (curele = remote_public; curele; curele = curele->ai_next) + { if (curele->ai_family == AF_INET) { check_addr_clash("remote", @@ -1036,7 +1038,8 @@ do_ifconfig(struct tuntap *tt, struct buffer out = alloc_buf_gc(64, &gc); char *top; - switch (tt->topology) { + switch (tt->topology) + { case TOP_NET30: top = "net30"; break; @@ -1835,12 +1838,14 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun /* Prefer IPv6 DNS servers, * Android will use the DNS server in the order we specify*/ - for (int i = 0; i < tt->options.dns6_len; i++) { + for (int i = 0; i < tt->options.dns6_len; i++) + { management_android_control(management, "DNS6SERVER", print_in6_addr(tt->options.dns6[i], 0, &gc)); } - for (int i = 0; i < tt->options.dns_len; i++) { + for (int i = 0; i < tt->options.dns_len; i++) + { management_android_control(management, "DNSSERVER", print_in_addr_t(tt->options.dns[i], 0, &gc)); } @@ -2254,7 +2259,9 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun { ptr = dev; while (*ptr && !isdigit((int) *ptr)) + { ptr++; + } ppa = atoi(ptr); } @@ -3277,7 +3284,10 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun { /* ensure that dev name is "tap+" *only* */ p = &dev[3]; - while (isdigit(*p) ) p++; + while (isdigit(*p) ) + { + p++; + } if (*p != '\0') { msg( M_FATAL, "TAP device name must be '--dev tapNNNN'" ); @@ -5455,7 +5465,9 @@ write_dhcp_u32_array(struct buffer *buf, const int type, const uint32_t *data, c buf_write_u8(buf, type); buf_write_u8(buf, size); for (i = 0; i < len; ++i) + { buf_write_u32(buf, data[i]); + } } } @@ -6284,10 +6296,12 @@ ascii2ipset(const char *name) int i; ASSERT(IPW32_SET_N == SIZE(ipset_names)); for (i = 0; i < IPW32_SET_N; ++i) + { if (!strcmp(name, ipset_names[i].short_form)) { return i; } + } return -1; } diff --git a/src/openvpn/win32.c b/src/openvpn/win32.c index e26f54d8093..18e7aee187c 100644 --- a/src/openvpn/win32.c +++ b/src/openvpn/win32.c @@ -569,7 +569,8 @@ win32_keyboard_get(struct win32_signal *ws) if (HANDLE_DEFINED(ws->in.read)) { INPUT_RECORD ir; - do { + do + { DWORD n; if (!keyboard_input_available(ws)) { @@ -681,7 +682,8 @@ win32_pause(struct win32_signal *ws) { int status; msg(M_INFO|M_NOPREFIX, "Press any key to continue..."); - do { + do + { status = WaitForSingleObject(ws->in.read, INFINITE); } while (!win32_keyboard_get(ws)); } @@ -984,7 +986,9 @@ env_block(const struct env_set *es) bool path_seen = false; for (e = es->list; e != NULL; e = e->next) + { nchars += strlen(e->string) + 1; + } nchars += strlen(force_path)+1; diff --git a/src/openvpnserv/automatic.c b/src/openvpnserv/automatic.c index 6be6c6dfae3..b9a377a59f1 100644 --- a/src/openvpnserv/automatic.c +++ b/src/openvpnserv/automatic.c @@ -293,7 +293,8 @@ ServiceStartAutomatic(DWORD dwArgc, LPTSTR *lpszArgv) /* * Loop over each config file */ - do { + do + { HANDLE log_handle = NULL; STARTUPINFO start_info; PROCESS_INFORMATION proc_info; diff --git a/src/openvpnserv/interactive.c b/src/openvpnserv/interactive.c index dbe2b9b5872..11b475c4e50 100644 --- a/src/openvpnserv/interactive.c +++ b/src/openvpnserv/interactive.c @@ -215,7 +215,9 @@ AsyncPipeOp(async_op_t op, HANDLE pipe, LPVOID buffer, DWORD size, DWORD count, handles[0] = io_event; for (i = 0; i < count; i++) + { handles[i + 1] = events[i]; + } res = WaitForMultipleObjects(count + 1, handles, FALSE, op == peek ? INFINITE : IO_TIMEOUT); @@ -1840,7 +1842,8 @@ ServiceStartInteractive(DWORD dwArgc, LPTSTR *lpszArgv) PHANDLE handles = NULL; DWORD handle_count; BOOL - CmpHandle(LPVOID item, LPVOID hnd) { + CmpHandle(LPVOID item, LPVOID hnd) + { return item == hnd; } diff --git a/src/plugins/auth-pam/utils.c b/src/plugins/auth-pam/utils.c index 4f8fb0ad67f..724a4379eea 100644 --- a/src/plugins/auth-pam/utils.c +++ b/src/plugins/auth-pam/utils.c @@ -78,7 +78,8 @@ searchandreplace(const char *tosearch, const char *searchfor, const char *replac return strdup(tosearch); } - while (scratch) { + while (scratch) + { strncat(temp,searching,scratch-searching); strcat(temp,replacewith); @@ -117,7 +118,9 @@ string_array_len(const char *array[]) if (array) { while (array[i]) + { ++i; + } } return i; } diff --git a/src/plugins/down-root/down-root.c b/src/plugins/down-root/down-root.c index ae85ecba25f..ab6b483a9b3 100644 --- a/src/plugins/down-root/down-root.c +++ b/src/plugins/down-root/down-root.c @@ -116,7 +116,9 @@ string_array_len(const char *array[]) if (array) { while (array[i]) + { ++i; + } } return i; } From 2f5f1d8fffcba26d21d47cbcb1e99e0e1c313568 Mon Sep 17 00:00:00 2001 From: Selva Nair Date: Wed, 18 Jan 2017 15:42:52 -0500 Subject: [PATCH 467/643] Add a check for -Wl, --wrap support in linker - Also make tests that require --wrap option to be conditional on this support [ DS: Removed AC_DEFINE([HAVE_LD_WRAP_SUPPORT],...) at commit time as we now see no real use for such a #define in config.h ] Signed-off-by: Selva Nair Acked-by: Gert Doering Acked-by: David Sommerseth Message-Id: <1484772172-19758-1-git-send-email-selva.nair@gmail.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13897.html Signed-off-by: David Sommerseth (cherry picked from commit f91ab283a407e25c4b32aecb390911b212ce2694) --- configure.ac | 25 +++++++++++++++++++++++++ tests/unit_tests/openvpn/Makefile.am | 6 +++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 43487b01dd5..8783109f801 100644 --- a/configure.ac +++ b/configure.ac @@ -582,6 +582,30 @@ AC_COMPILE_IFELSE( [AC_MSG_RESULT([no])] ) +saved_LDFLAGS="$LDFLAGS" +LDFLAGS="$LDFLAGS -Wl,--wrap=exit" +AC_MSG_CHECKING([linker supports --wrap]) +AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [[ + void exit(int); + void __real_exit(int); + void __wrap_exit(int i) { + __real_exit(i); + } + ]], + [[ + exit(0); + ]] + )], + [ + AC_MSG_RESULT([yes]) + have_ld_wrap_support=yes + ], + [AC_MSG_RESULT([no])], +) +LDFLAGS="$saved_LDFLAGS" + dnl We emulate signals in Windows AC_CHECK_DECLS( [SIGHUP], @@ -1244,6 +1268,7 @@ AM_CONDITIONAL([GIT_CHECKOUT], [test "${GIT_CHECKOUT}" = "yes"]) AM_CONDITIONAL([ENABLE_PLUGIN_AUTH_PAM], [test "${enable_plugin_auth_pam}" = "yes"]) AM_CONDITIONAL([ENABLE_PLUGIN_DOWN_ROOT], [test "${enable_plugin_down_root}" = "yes"]) AM_CONDITIONAL([ENABLE_CRYPTO], [test "${enable_crypto}" = "yes"]) +AM_CONDITIONAL([HAVE_LD_WRAP_SUPPORT], [test "${have_ld_wrap_support}" = "yes"]) plugindir="${with_plugindir}" sampledir="\$(docdir)/sample" diff --git a/tests/unit_tests/openvpn/Makefile.am b/tests/unit_tests/openvpn/Makefile.am index fafe6b27431..b902b2098fc 100644 --- a/tests/unit_tests/openvpn/Makefile.am +++ b/tests/unit_tests/openvpn/Makefile.am @@ -1,6 +1,10 @@ AUTOMAKE_OPTIONS = foreign -check_PROGRAMS = argv_testdriver buffer_testdriver +check_PROGRAMS= + +if HAVE_LD_WRAP_SUPPORT +check_PROGRAMS += argv_testdriver buffer_testdriver +endif if ENABLE_CRYPTO check_PROGRAMS += tls_crypt_testdriver From 2a7c994ca5b1583bc0f78c46be5b3a827f970b9a Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Fri, 20 Jan 2017 22:04:57 +0100 Subject: [PATCH 468/643] git: Merge .gitignore files into a single file We already track a lot of files over the whole directory structure in the main .gitignore file. But a few additional ones had been added into some of the subdirectories. This unifies all these files into a master file for the whole project, making it easier to know where to look at and edit if changes needs to be done. Signed-off-by: David Sommerseth Acked-by: Steffan Karger Message-Id: <20170120210457.3383-1-davids@openvpn.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13916.html Signed-off-by: David Sommerseth (cherry picked from commit d14b3c60c7796736e07bc3cddb0ab3a58475793e) --- .gitignore | 4 ++++ sample/sample-keys/.gitignore | 1 - tests/unit_tests/.gitignore | 1 - vendor/.gitignore | 2 -- 4 files changed, 4 insertions(+), 4 deletions(-) delete mode 100644 sample/sample-keys/.gitignore delete mode 100644 tests/unit_tests/.gitignore delete mode 100644 vendor/.gitignore diff --git a/.gitignore b/.gitignore index fc1e223aecf..e6da21c6343 100644 --- a/.gitignore +++ b/.gitignore @@ -51,11 +51,15 @@ config-msvc-local.h config-msvc-version.h doc/openvpn.8.html distro/rpm/openvpn.spec +sample/sample-keys/sample-ca/ +vendor/.build +vendor/dist tests/t_client.sh tests/t_client-*-20??????-??????/ t_client.rc t_client_ips.rc +tests/unit_tests/**/*_testdriver src/openvpn/openvpn include/openvpn-plugin.h diff --git a/sample/sample-keys/.gitignore b/sample/sample-keys/.gitignore deleted file mode 100644 index f148752848c..00000000000 --- a/sample/sample-keys/.gitignore +++ /dev/null @@ -1 +0,0 @@ -sample-ca/ diff --git a/tests/unit_tests/.gitignore b/tests/unit_tests/.gitignore deleted file mode 100644 index 8655de8341f..00000000000 --- a/tests/unit_tests/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*_testdriver diff --git a/vendor/.gitignore b/vendor/.gitignore deleted file mode 100644 index e11dfecddf4..00000000000 --- a/vendor/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -.build/ -dist/ From 5cf585ce605d2328d7a2bb5cf44e82b8b196b551 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sun, 22 Jan 2017 17:04:41 +0100 Subject: [PATCH 469/643] Use SHA256 for the internal digest, instead of MD5 Our internal options digest uses MD5 hashes to store the state, instead of storing the full options string. There's nothing wrong with that, but it would still be better to use SHA256 because: * That makes it easier to make OpenVPN "FIPS-compliant" (forbids MD5) * We don't have to explain anymore that MD5 is fine too The slightly less bytes for the digest (16 instead of 32) and operations per connection setup are not worth sticking to MD5. Note that might SHA256 not be available in de crypto lib, OpenVPN will refuse to start and shout "Message hash algorithm 'SHA256' not found". Signed-off-by: Steffan Karger Acked-by: David Sommerseth Message-Id: <1485101081-9784-1-git-send-email-steffan@karger.me> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13926.html Signed-off-by: David Sommerseth (cherry picked from commit 5b48e8c9f85442936f744c3c550d9d41fe8c7b60) --- src/openvpn/crypto.h | 6 +++--- src/openvpn/crypto_mbedtls.h | 1 + src/openvpn/crypto_openssl.h | 1 + src/openvpn/init.c | 10 +++++----- src/openvpn/openvpn.h | 6 +++--- src/openvpn/push.c | 8 ++++---- 6 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/openvpn/crypto.h b/src/openvpn/crypto.h index 6ca0bc81b3d..09ff9f02f02 100644 --- a/src/openvpn/crypto.h +++ b/src/openvpn/crypto.h @@ -132,9 +132,9 @@ #include "packet_id.h" #include "mtu.h" -/** Wrapper struct to pass around MD5 digests */ -struct md5_digest { - uint8_t digest[MD5_DIGEST_LENGTH]; +/** Wrapper struct to pass around SHA256 digests */ +struct sha256_digest { + uint8_t digest[SHA256_DIGEST_LENGTH]; }; /* diff --git a/src/openvpn/crypto_mbedtls.h b/src/openvpn/crypto_mbedtls.h index 525b256a6fe..da2db166aa3 100644 --- a/src/openvpn/crypto_mbedtls.h +++ b/src/openvpn/crypto_mbedtls.h @@ -73,6 +73,7 @@ typedef mbedtls_md_context_t hmac_ctx_t; #define MD4_DIGEST_LENGTH 16 #define MD5_DIGEST_LENGTH 16 #define SHA_DIGEST_LENGTH 20 +#define SHA256_DIGEST_LENGTH 32 #define DES_KEY_LENGTH 8 /** diff --git a/src/openvpn/crypto_openssl.h b/src/openvpn/crypto_openssl.h index 56ec6e1c67f..f8ddbc86652 100644 --- a/src/openvpn/crypto_openssl.h +++ b/src/openvpn/crypto_openssl.h @@ -33,6 +33,7 @@ #include #include #include +#include /** Generic cipher key type %context. */ typedef EVP_CIPHER cipher_kt_t; diff --git a/src/openvpn/init.c b/src/openvpn/init.c index a540c68da28..7b35cca8c80 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -1919,12 +1919,12 @@ tun_abort() * equal, or either one is all-zeroes. */ static bool -options_hash_changed_or_zero(const struct md5_digest *a, - const struct md5_digest *b) +options_hash_changed_or_zero(const struct sha256_digest *a, + const struct sha256_digest *b) { - const struct md5_digest zero = {{0}}; - return memcmp(a, b, sizeof(struct md5_digest)) - || !memcmp(a, &zero, sizeof(struct md5_digest)); + const struct sha256_digest zero = {{0}}; + return memcmp(a, b, sizeof(struct sha256_digest)) + || !memcmp(a, &zero, sizeof(struct sha256_digest)); } #endif /* P2MP */ diff --git a/src/openvpn/openvpn.h b/src/openvpn/openvpn.h index 37edec4f725..893296edc53 100644 --- a/src/openvpn/openvpn.h +++ b/src/openvpn/openvpn.h @@ -202,7 +202,7 @@ struct context_1 #endif /* if client mode, hash of option strings we pulled from server */ - struct md5_digest pulled_options_digest_save; + struct sha256_digest pulled_options_digest_save; /**< Hash of option strings received from the * remote OpenVPN server. Only used in * client-mode. */ @@ -471,9 +471,9 @@ struct context_2 bool did_pre_pull_restore; /* hash of pulled options, so we can compare when options change */ - bool pulled_options_md5_init_done; + bool pulled_options_digest_init_done; md_ctx_t pulled_options_state; - struct md5_digest pulled_options_digest; + struct sha256_digest pulled_options_digest; struct event_timeout scheduled_exit; int scheduled_exit_signal; diff --git a/src/openvpn/push.c b/src/openvpn/push.c index c9c04a630c9..8c3104ed769 100644 --- a/src/openvpn/push.c +++ b/src/openvpn/push.c @@ -720,10 +720,10 @@ process_incoming_push_msg(struct context *c, if (ch == ',') { struct buffer buf_orig = buf; - if (!c->c2.pulled_options_md5_init_done) + if (!c->c2.pulled_options_digest_init_done) { - md_ctx_init(&c->c2.pulled_options_state, md_kt_get("MD5")); - c->c2.pulled_options_md5_init_done = true; + md_ctx_init(&c->c2.pulled_options_state, md_kt_get("SHA256")); + c->c2.pulled_options_digest_init_done = true; } if (!c->c2.did_pre_pull_restore) { @@ -744,7 +744,7 @@ process_incoming_push_msg(struct context *c, case 1: md_ctx_final(&c->c2.pulled_options_state, c->c2.pulled_options_digest.digest); md_ctx_cleanup(&c->c2.pulled_options_state); - c->c2.pulled_options_md5_init_done = false; + c->c2.pulled_options_digest_init_done = false; ret = PUSH_MSG_REPLY; break; From 041fd6488434b5df01f86dd873b536a2b690ee13 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Wed, 25 Jan 2017 00:23:44 +0100 Subject: [PATCH 470/643] systemd: Move the READY=1 signalling to an earlier point Currently, OpenVPN will first tell systemd it is ready once the log will be appended with "Initialization Sequence Completed". This turns out to cause some issues several places. First, it adds challenges if --chroot is used in the configuration; this is already fixed. Secondly, it will cause havoc on static key p2p mode configurations where the log line above will not happen before either sides have completed establishing a connection. And thirdly, if a client configuration fails to establish a connection within 90 seconds, it will also fail. For the third case this may not be a critical issue itself, as the host just needs to get an Internet access established first - which in some scenarios may take much longer than those 90 seconds systemd grants after the OpenVPN client configuration is started. The approach this patch takes is to consider OpenVPN ready when all the initial preparations and configurations have completed - but before a connection to a remote side have been attempted. This also removes the need for specially handling the --chroot scenario. The final "Initialization Sequence Completed" message update is kept (though slightly simplified) to indicate we're in a good state - even though this update will not be visible if --chroot is used (which was the situation also before this patch). Trac: #827, #801 Signed-off-by: David Sommerseth Acked-by: Gert Doering Acked-by: Christian Hesse Message-Id: <20170124232344.7825-1-davids@openvpn.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13945.html Signed-off-by: David Sommerseth (cherry picked from commit e83a8684f0a0d944e9d53cdad2b543cfd1b6fbae) --- src/openvpn/init.c | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 7b35cca8c80..ef1c757b9ca 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -562,6 +562,15 @@ context_init_1(struct context *c) } #endif +#ifdef ENABLE_SYSTEMD + /* We can report the PID via getpid() to systemd here as OpenVPN will not + * do any fork due to daemon() a future call. + * See possibly_become_daemon() [init.c] for more details. + */ + sd_notifyf(0, "READY=1\nSTATUS=Pre-connection initialization succesfull\nMAINPID=%lu", + (unsigned long) getpid()); +#endif + } void @@ -1042,24 +1051,6 @@ do_uid_gid_chroot(struct context *c, bool no_delay) { if (no_delay) { -#ifdef ENABLE_SYSTEMD - /* If OpenVPN is started by systemd, the OpenVPN process needs - * to provide a preliminary status report to systemd. This is - * needed as $NOTIFY_SOCKET will not be available inside the - * chroot, which sd_notify()/sd_notifyf() depends on. - * - * This approach is the simplest and the most non-intrusive - * solution right before the 2.4_rc2 release. - * - * TODO: Consider altnernative solutions - bind mount? - * systemd does not grok OpenVPN configuration files, thus cannot - * have a sane way to know if OpenVPN will chroot or not and to - * which subdirectory it will chroot into. - */ - sd_notifyf(0, "READY=1\n" - "STATUS=Entering chroot, most of the init completed successfully\n" - "MAINPID=%lu", (unsigned long) getpid()); -#endif platform_chroot(c->options.chroot_dir); } else if (c->first_time) @@ -1409,7 +1400,7 @@ initialization_sequence_completed(struct context *c, const unsigned int flags) else { #ifdef ENABLE_SYSTEMD - sd_notifyf(0, "READY=1\nSTATUS=%s\nMAINPID=%lu", message, (unsigned long) getpid()); + sd_notifyf(0, "STATUS=%s", message); #endif msg(M_INFO, "%s", message); } From a125229f509b593dff7ecc24e21b3de384b3fa98 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 24 Jan 2017 15:39:46 +0100 Subject: [PATCH 471/643] systemd: Use automake tools to install unit files If systemd is enabled we install unit files to $libdir/systemd/system (or the path specified by SYSTEMD_UNIT_DIR). The unit files are generated on the fly with matching $sbindir. Signed-off-by: Christian Hesse Acked-by: David Sommerseth Message-Id: <20170124143947.27385-1-list@eworm.de> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13940.html Signed-off-by: David Sommerseth (cherry picked from commit ca5b4c2aad2370be7862660d274b7485f2d0af71) --- .gitignore | 1 + configure.ac | 10 +++++++ distro/Makefile.am | 4 +-- distro/systemd/Makefile.am | 26 +++++++++++++++++++ ...nt@.service => openvpn-client@.service.in} | 2 +- ...er@.service => openvpn-server@.service.in} | 2 +- 6 files changed, 40 insertions(+), 5 deletions(-) create mode 100644 distro/systemd/Makefile.am rename distro/systemd/{openvpn-client@.service => openvpn-client@.service.in} (90%) rename distro/systemd/{openvpn-server@.service => openvpn-server@.service.in} (91%) diff --git a/.gitignore b/.gitignore index e6da21c6343..30e289bbed6 100644 --- a/.gitignore +++ b/.gitignore @@ -51,6 +51,7 @@ config-msvc-local.h config-msvc-version.h doc/openvpn.8.html distro/rpm/openvpn.spec +distro/systemd/*.service sample/sample-keys/sample-ca/ vendor/.build vendor/dist diff --git a/configure.ac b/configure.ac index 8783109f801..48d8f0cdb31 100644 --- a/configure.ac +++ b/configure.ac @@ -378,6 +378,7 @@ AC_ARG_VAR([NETSTAT], [path to netstat utility]) # tests AC_ARG_VAR([MAN2HTML], [path to man2html utility]) AC_ARG_VAR([GIT], [path to git utility]) AC_ARG_VAR([SYSTEMD_ASK_PASSWORD], [path to systemd-ask-password utility]) +AC_ARG_VAR([SYSTEMD_UNIT_DIR], [Path of systemd unit directory @<:@default=LIBDIR/systemd/system@:>@]) AC_PATH_PROGS([IFCONFIG], [ifconfig],, [$PATH:/usr/local/sbin:/usr/sbin:/sbin]) AC_PATH_PROGS([ROUTE], [route],, [$PATH:/usr/local/sbin:/usr/sbin:/sbin]) AC_PATH_PROGS([IPROUTE], [ip],, [$PATH:/usr/local/sbin:/usr/sbin:/sbin]) @@ -1099,6 +1100,12 @@ if test "$enable_systemd" = "yes" ; then OPTIONAL_SYSTEMD_LIBS="${libsystemd_LIBS}" AC_DEFINE(ENABLE_SYSTEMD, 1, [Enable systemd integration]) LIBS="${saved_LIBS}" + + if test -n "${SYSTEMD_UNIT_DIR}"; then + systemdunitdir="${SYSTEMD_UNIT_DIR}" + else + systemdunitdir="\${libdir}/systemd/system" + fi fi @@ -1275,6 +1282,8 @@ sampledir="\$(docdir)/sample" AC_SUBST([plugindir]) AC_SUBST([sampledir]) +AC_SUBST([systemdunitdir]) + VENDOR_SRC_ROOT="\$(abs_top_srcdir)/vendor/" VENDOR_DIST_ROOT="\$(abs_top_builddir)/vendor/dist" VENDOR_BUILD_ROOT="\$(abs_top_builddir)/vendor/.build" @@ -1313,6 +1322,7 @@ AC_CONFIG_FILES([ distro/Makefile distro/rpm/Makefile distro/rpm/openvpn.spec + distro/systemd/Makefile include/Makefile src/Makefile src/compat/Makefile diff --git a/distro/Makefile.am b/distro/Makefile.am index 7a9ffd0fbc7..eb0e5540b1d 100644 --- a/distro/Makefile.am +++ b/distro/Makefile.am @@ -12,6 +12,4 @@ MAINTAINERCLEANFILES = \ $(srcdir)/Makefile.in -SUBDIRS = rpm - -EXTRA_DIST = systemd/openvpn-client@.service systemd/openvpn-server@.service +SUBDIRS = rpm systemd diff --git a/distro/systemd/Makefile.am b/distro/systemd/Makefile.am new file mode 100644 index 00000000000..b10c6edac3a --- /dev/null +++ b/distro/systemd/Makefile.am @@ -0,0 +1,26 @@ +# +# OpenVPN -- An application to securely tunnel IP networks +# over a single UDP port, with support for SSL/TLS-based +# session authentication and key exchange, +# packet encryption, packet authentication, and +# packet compression. +# +# Copyright (C) 2017 OpenVPN Technologies, Inc. +# + +%.service: %.service.in Makefile + $(AM_V_GEN)sed -e 's|\@sbindir\@|$(sbindir)|' \ + $< > $@.tmp && mv $@.tmp $@ + +EXTRA_DIST = \ + openvpn-client@.service.in \ + openvpn-server@.service.in + +if ENABLE_SYSTEMD +systemdunit_DATA = \ + openvpn-client@.service \ + openvpn-server@.service +endif + +MAINTAINERCLEANFILES = \ + $(srcdir)/Makefile.in diff --git a/distro/systemd/openvpn-client@.service b/distro/systemd/openvpn-client@.service.in similarity index 90% rename from distro/systemd/openvpn-client@.service rename to distro/systemd/openvpn-client@.service.in index 5618af3a37b..d9337729a7b 100644 --- a/distro/systemd/openvpn-client@.service +++ b/distro/systemd/openvpn-client@.service.in @@ -12,7 +12,7 @@ PrivateTmp=true RuntimeDirectory=openvpn-client RuntimeDirectoryMode=0710 WorkingDirectory=/etc/openvpn/client -ExecStart=/usr/sbin/openvpn --suppress-timestamps --nobind --config %i.conf +ExecStart=@sbindir@/openvpn --suppress-timestamps --nobind --config %i.conf CapabilityBoundingSet=CAP_IPC_LOCK CAP_NET_ADMIN CAP_NET_RAW CAP_SETGID CAP_SETUID CAP_SYS_CHROOT CAP_DAC_OVERRIDE LimitNPROC=10 DeviceAllow=/dev/null rw diff --git a/distro/systemd/openvpn-server@.service b/distro/systemd/openvpn-server@.service.in similarity index 91% rename from distro/systemd/openvpn-server@.service rename to distro/systemd/openvpn-server@.service.in index b9b4dba18bb..da5c78e1a1f 100644 --- a/distro/systemd/openvpn-server@.service +++ b/distro/systemd/openvpn-server@.service.in @@ -12,7 +12,7 @@ PrivateTmp=true RuntimeDirectory=openvpn-server RuntimeDirectoryMode=0710 WorkingDirectory=/etc/openvpn/server -ExecStart=/usr/sbin/openvpn --status %t/openvpn-server/status-%i.log --status-version 2 --suppress-timestamps --config %i.conf +ExecStart=@sbindir@/openvpn --status %t/openvpn-server/status-%i.log --status-version 2 --suppress-timestamps --config %i.conf CapabilityBoundingSet=CAP_IPC_LOCK CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW CAP_SETGID CAP_SETUID CAP_SYS_CHROOT CAP_DAC_OVERRIDE LimitNPROC=10 DeviceAllow=/dev/null rw From e5492222a9ae5d31d69cc9e5cb57dc094cda556e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 24 Jan 2017 15:39:47 +0100 Subject: [PATCH 472/643] systemd: Do not race on RuntimeDirectory Different unit instances create and destroy the same RuntimeDirectory. This leads to running instances where the status file (and possibly more runtime data) is no longer accessible. So do not handle this in unit files but provide a tmpfiles.d configuration and let systemd-tmpfiles do the work. Nobody will (unintentionally) delete the directories and its content. As /run is volatile we do not have to care about cleanup. Signed-off-by: Christian Hesse Acked-by: David Sommerseth Message-Id: <20170124143947.27385-2-list@eworm.de> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13939.html Signed-off-by: David Sommerseth (cherry picked from commit 3de7be7b17de879a78eea4afe4c918c6104c635d) --- configure.ac | 8 ++++++++ distro/systemd/Makefile.am | 6 ++++++ distro/systemd/openvpn-client@.service.in | 2 -- distro/systemd/openvpn-server@.service.in | 2 -- distro/systemd/tmpfiles-openvpn.conf | 2 ++ 5 files changed, 16 insertions(+), 4 deletions(-) create mode 100644 distro/systemd/tmpfiles-openvpn.conf diff --git a/configure.ac b/configure.ac index 48d8f0cdb31..79fb1ba2499 100644 --- a/configure.ac +++ b/configure.ac @@ -379,6 +379,7 @@ AC_ARG_VAR([MAN2HTML], [path to man2html utility]) AC_ARG_VAR([GIT], [path to git utility]) AC_ARG_VAR([SYSTEMD_ASK_PASSWORD], [path to systemd-ask-password utility]) AC_ARG_VAR([SYSTEMD_UNIT_DIR], [Path of systemd unit directory @<:@default=LIBDIR/systemd/system@:>@]) +AC_ARG_VAR([TMPFILES_DIR], [Path of tmpfiles directory @<:@default=LIBDIR/tmpfiles.d@:>@]) AC_PATH_PROGS([IFCONFIG], [ifconfig],, [$PATH:/usr/local/sbin:/usr/sbin:/sbin]) AC_PATH_PROGS([ROUTE], [route],, [$PATH:/usr/local/sbin:/usr/sbin:/sbin]) AC_PATH_PROGS([IPROUTE], [ip],, [$PATH:/usr/local/sbin:/usr/sbin:/sbin]) @@ -1106,6 +1107,12 @@ if test "$enable_systemd" = "yes" ; then else systemdunitdir="\${libdir}/systemd/system" fi + + if test -n "${TMPFILES_DIR}"; then + tmpfilesdir="${TMPFILES_DIR}" + else + tmpfilesdir="\${libdir}/tmpfiles.d" + fi fi @@ -1283,6 +1290,7 @@ AC_SUBST([plugindir]) AC_SUBST([sampledir]) AC_SUBST([systemdunitdir]) +AC_SUBST([tmpfilesdir]) VENDOR_SRC_ROOT="\$(abs_top_srcdir)/vendor/" VENDOR_DIST_ROOT="\$(abs_top_builddir)/vendor/dist" diff --git a/distro/systemd/Makefile.am b/distro/systemd/Makefile.am index b10c6edac3a..1e3f3eaad8e 100644 --- a/distro/systemd/Makefile.am +++ b/distro/systemd/Makefile.am @@ -13,6 +13,7 @@ $< > $@.tmp && mv $@.tmp $@ EXTRA_DIST = \ + tmpfiles-openvpn.conf \ openvpn-client@.service.in \ openvpn-server@.service.in @@ -20,6 +21,11 @@ if ENABLE_SYSTEMD systemdunit_DATA = \ openvpn-client@.service \ openvpn-server@.service +tmpfiles_DATA = \ + tmpfiles-openvpn.conf + +install-data-hook: + mv $(DESTDIR)$(tmpfilesdir)/tmpfiles-openvpn.conf $(DESTDIR)$(tmpfilesdir)/openvpn.conf endif MAINTAINERCLEANFILES = \ diff --git a/distro/systemd/openvpn-client@.service.in b/distro/systemd/openvpn-client@.service.in index d9337729a7b..1be1e33225f 100644 --- a/distro/systemd/openvpn-client@.service.in +++ b/distro/systemd/openvpn-client@.service.in @@ -9,8 +9,6 @@ Documentation=https://community.openvpn.net/openvpn/wiki/HOWTO [Service] Type=notify PrivateTmp=true -RuntimeDirectory=openvpn-client -RuntimeDirectoryMode=0710 WorkingDirectory=/etc/openvpn/client ExecStart=@sbindir@/openvpn --suppress-timestamps --nobind --config %i.conf CapabilityBoundingSet=CAP_IPC_LOCK CAP_NET_ADMIN CAP_NET_RAW CAP_SETGID CAP_SETUID CAP_SYS_CHROOT CAP_DAC_OVERRIDE diff --git a/distro/systemd/openvpn-server@.service.in b/distro/systemd/openvpn-server@.service.in index da5c78e1a1f..3dccaf25398 100644 --- a/distro/systemd/openvpn-server@.service.in +++ b/distro/systemd/openvpn-server@.service.in @@ -9,8 +9,6 @@ Documentation=https://community.openvpn.net/openvpn/wiki/HOWTO [Service] Type=notify PrivateTmp=true -RuntimeDirectory=openvpn-server -RuntimeDirectoryMode=0710 WorkingDirectory=/etc/openvpn/server ExecStart=@sbindir@/openvpn --status %t/openvpn-server/status-%i.log --status-version 2 --suppress-timestamps --config %i.conf CapabilityBoundingSet=CAP_IPC_LOCK CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW CAP_SETGID CAP_SETUID CAP_SYS_CHROOT CAP_DAC_OVERRIDE diff --git a/distro/systemd/tmpfiles-openvpn.conf b/distro/systemd/tmpfiles-openvpn.conf new file mode 100644 index 00000000000..bb79671eb4b --- /dev/null +++ b/distro/systemd/tmpfiles-openvpn.conf @@ -0,0 +1,2 @@ +d /run/openvpn-client 0710 root root - +d /run/openvpn-server 0710 root root - From ba3ccaf92d379f8a2efad80cee7dc2806088f421 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 27 Dec 2016 23:18:32 +0100 Subject: [PATCH 473/643] systemd: Add more security feature for systemd units ProtectSystem=true mounts the /usr and /boot directories read-only. ProtectHome=true makes the directories /home, /root and /run/user inaccessible and empty for the process. See systemd.exec(5) [0] for details. v2: Replace ProtectSystem=strict with ProtectSystem=true. Some configurations may want to write to /etc or the like. [0] https://www.freedesktop.org/software/systemd/man/systemd.exec.html Signed-off-by: Christian Hesse Acked-by: David Sommerseth Message-Id: <20161227221832.610-1-list@eworm.de> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13743.html Signed-off-by: David Sommerseth (cherry picked from commit 76096c605fcac4815674b6ae76ac1f31f03a8186) --- distro/systemd/openvpn-client@.service.in | 2 ++ distro/systemd/openvpn-server@.service.in | 2 ++ 2 files changed, 4 insertions(+) diff --git a/distro/systemd/openvpn-client@.service.in b/distro/systemd/openvpn-client@.service.in index 1be1e33225f..49e3f51cc54 100644 --- a/distro/systemd/openvpn-client@.service.in +++ b/distro/systemd/openvpn-client@.service.in @@ -15,6 +15,8 @@ CapabilityBoundingSet=CAP_IPC_LOCK CAP_NET_ADMIN CAP_NET_RAW CAP_SETGID CAP_SETU LimitNPROC=10 DeviceAllow=/dev/null rw DeviceAllow=/dev/net/tun rw +ProtectSystem=true +ProtectHome=true [Install] WantedBy=multi-user.target diff --git a/distro/systemd/openvpn-server@.service.in b/distro/systemd/openvpn-server@.service.in index 3dccaf25398..9a8a2c730c2 100644 --- a/distro/systemd/openvpn-server@.service.in +++ b/distro/systemd/openvpn-server@.service.in @@ -15,6 +15,8 @@ CapabilityBoundingSet=CAP_IPC_LOCK CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RA LimitNPROC=10 DeviceAllow=/dev/null rw DeviceAllow=/dev/net/tun rw +ProtectSystem=true +ProtectHome=true [Install] WantedBy=multi-user.target From 05baa0ecf841852fbf29ef39ee9cd1d4cac990cf Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 25 Jan 2017 21:19:47 +0100 Subject: [PATCH 474/643] Clean up plugin path handling Drop --with-plugindir, instead use an environment variable PLUGINDIR to specify the plugin directory. This puts a define into include/openvpn-plugin.h.in which has the plugin directory. The configure script does not know about the final plugin path. Thus we have to make Make generate the final header file for us. As the path is always available remove the compile time condition (and dead code) from src/openvpn/plugin.c. v2: The configure script can not evaluate the final $libdir path. So use make to create a header file on the containing the final path. v3: Fix whitespace errors and gitignore location. v4: No extra header file, generate src/openvpn/plugin.h on the fly. Remove condition and dead code. v5: Move the define to include/openvpn-plugin.h.in and let make generate the final header file. Signed-off-by: Christian Hesse Acked-by: David Sommerseth Message-Id: <20170125201947.17197-1-list@eworm.de> URL: http://www.mail-archive.com/search?l=mid&q=20170125201947.17197-1-list@eworm.de Signed-off-by: David Sommerseth (cherry picked from commit 4590c3831d0400096fab08aa1ed7f909da870ced) --- configure.ac | 16 +++++++--------- include/Makefile.am | 7 +++++++ include/openvpn-plugin.h.in | 2 ++ src/openvpn/plugin.c | 10 +--------- 4 files changed, 17 insertions(+), 18 deletions(-) diff --git a/configure.ac b/configure.ac index 79fb1ba2499..f305c54880d 100644 --- a/configure.ac +++ b/configure.ac @@ -38,7 +38,7 @@ AC_DEFINE([OPENVPN_VERSION_MINOR], [PRODUCT_VERSION_MINOR], [OpenVPN minor versi AC_DEFINE([OPENVPN_VERSION_PATCH], ["PRODUCT_VERSION_PATCH"], [OpenVPN patch level - may be a string or integer]) AC_CONFIG_AUX_DIR([.]) -AC_CONFIG_HEADERS([config.h include/openvpn-plugin.h]) +AC_CONFIG_HEADERS([config.h]) AC_CONFIG_SRCDIR([src/openvpn/syshead.h]) AC_CONFIG_MACRO_DIR([m4]) @@ -301,13 +301,12 @@ AC_ARG_WITH( [with_crypto_library="openssl"] ) -AC_ARG_WITH( - [plugindir], - [AS_HELP_STRING([--with-plugindir], [plugin directory @<:@default=LIBDIR/openvpn@:>@])], - , - [with_plugindir="\$(libdir)/openvpn/plugins"] -) - +AC_ARG_VAR([PLUGINDIR], [Path of plug-in directory @<:@default=LIBDIR/openvpn/plugins@:>@]) +if test -n "${PLUGINDIR}"; then + plugindir="${PLUGINDIR}" +else + plugindir="\${libdir}/openvpn/plugins" +fi AC_DEFINE_UNQUOTED([TARGET_ALIAS], ["${host}"], [A string representing our host]) case "$host" in @@ -1284,7 +1283,6 @@ AM_CONDITIONAL([ENABLE_PLUGIN_DOWN_ROOT], [test "${enable_plugin_down_root}" = " AM_CONDITIONAL([ENABLE_CRYPTO], [test "${enable_crypto}" = "yes"]) AM_CONDITIONAL([HAVE_LD_WRAP_SUPPORT], [test "${have_ld_wrap_support}" = "yes"]) -plugindir="${with_plugindir}" sampledir="\$(docdir)/sample" AC_SUBST([plugindir]) AC_SUBST([sampledir]) diff --git a/include/Makefile.am b/include/Makefile.am index a52c4278bce..37962a6f21e 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -16,3 +16,10 @@ MAINTAINERCLEANFILES = \ include_HEADERS = \ openvpn-plugin.h \ openvpn-msg.h + +openvpn-plugin.h: openvpn-plugin.h.in Makefile + $(AM_V_GEN)sed -e 's|\@PLUGINDIR\@|$(plugindir)|' \ + -e 's|\@OPENVPN_VERSION_MAJOR\@|$(OPENVPN_VERSION_MAJOR)|' \ + -e 's|\@OPENVPN_VERSION_MINOR\@|$(OPENVPN_VERSION_MINOR)|' \ + -e 's|\@OPENVPN_VERSION_PATCH\@|$(OPENVPN_VERSION_PATCH)|' \ + $< > $@.tmp && mv $@.tmp $@ diff --git a/include/openvpn-plugin.h.in b/include/openvpn-plugin.h.in index 0b303520a30..a084fc1a7d0 100644 --- a/include/openvpn-plugin.h.in +++ b/include/openvpn-plugin.h.in @@ -27,6 +27,8 @@ #define OPENVPN_PLUGIN_VERSION 3 +#define PLUGIN_LIBDIR "@PLUGINDIR@" + #ifdef ENABLE_CRYPTO #ifdef ENABLE_CRYPTO_MBEDTLS #include diff --git a/src/openvpn/plugin.c b/src/openvpn/plugin.c index e530c0c5f3e..f77702786f4 100644 --- a/src/openvpn/plugin.c +++ b/src/openvpn/plugin.c @@ -234,23 +234,15 @@ plugin_init_item(struct plugin *p, const struct plugin_option *o) #ifndef _WIN32 p->handle = NULL; -#if defined(PLUGIN_LIBDIR) + if (!absolute_pathname(p->so_pathname)) { char full[PATH_MAX]; openvpn_snprintf(full, sizeof(full), "%s/%s", PLUGIN_LIBDIR, p->so_pathname); p->handle = dlopen(full, RTLD_NOW); -#if defined(ENABLE_PLUGIN_SEARCH) - if (!p->handle) - { - rel = true; - p->handle = dlopen(p->so_pathname, RTLD_NOW); - } -#endif } else -#endif { rel = !absolute_pathname(p->so_pathname); p->handle = dlopen(p->so_pathname, RTLD_NOW); From cb17255b1f7600b3255d1e018cfc426b40da4044 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 27 Jan 2017 09:49:27 +0100 Subject: [PATCH 475/643] plugin: Remove GNUism in openvpn-plugin.h generation The plugin path handling cleanup (4590c383) introduced GNUism and broke builds on system not using GNU Make (like *BSD). Revert back to let configure generate the header file. Instead let make add an extra CFLAG that defines PLUGIN_LIBDIR. Signed-off-by: Christian Hesse Acked-by: Gert Doering Message-Id: <20170127084927.21040-1-list@eworm.de> URL: http://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13966.html Signed-off-by: David Sommerseth (cherry picked from commit 631812fe29c69d0034628ab8321cb4016cb4fc2d) --- configure.ac | 2 +- include/Makefile.am | 7 ------- include/openvpn-plugin.h.in | 2 -- src/openvpn/Makefile.am | 4 +++- 4 files changed, 4 insertions(+), 11 deletions(-) diff --git a/configure.ac b/configure.ac index f305c54880d..b29f8b410df 100644 --- a/configure.ac +++ b/configure.ac @@ -38,7 +38,7 @@ AC_DEFINE([OPENVPN_VERSION_MINOR], [PRODUCT_VERSION_MINOR], [OpenVPN minor versi AC_DEFINE([OPENVPN_VERSION_PATCH], ["PRODUCT_VERSION_PATCH"], [OpenVPN patch level - may be a string or integer]) AC_CONFIG_AUX_DIR([.]) -AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_HEADERS([config.h include/openvpn-plugin.h]) AC_CONFIG_SRCDIR([src/openvpn/syshead.h]) AC_CONFIG_MACRO_DIR([m4]) diff --git a/include/Makefile.am b/include/Makefile.am index 37962a6f21e..a52c4278bce 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -16,10 +16,3 @@ MAINTAINERCLEANFILES = \ include_HEADERS = \ openvpn-plugin.h \ openvpn-msg.h - -openvpn-plugin.h: openvpn-plugin.h.in Makefile - $(AM_V_GEN)sed -e 's|\@PLUGINDIR\@|$(plugindir)|' \ - -e 's|\@OPENVPN_VERSION_MAJOR\@|$(OPENVPN_VERSION_MAJOR)|' \ - -e 's|\@OPENVPN_VERSION_MINOR\@|$(OPENVPN_VERSION_MINOR)|' \ - -e 's|\@OPENVPN_VERSION_PATCH\@|$(OPENVPN_VERSION_PATCH)|' \ - $< > $@.tmp && mv $@.tmp $@ diff --git a/include/openvpn-plugin.h.in b/include/openvpn-plugin.h.in index a084fc1a7d0..0b303520a30 100644 --- a/include/openvpn-plugin.h.in +++ b/include/openvpn-plugin.h.in @@ -27,8 +27,6 @@ #define OPENVPN_PLUGIN_VERSION 3 -#define PLUGIN_LIBDIR "@PLUGINDIR@" - #ifdef ENABLE_CRYPTO #ifdef ENABLE_CRYPTO_MBEDTLS #include diff --git a/src/openvpn/Makefile.am b/src/openvpn/Makefile.am index bea294b3559..3f978553162 100644 --- a/src/openvpn/Makefile.am +++ b/src/openvpn/Makefile.am @@ -27,7 +27,9 @@ AM_CFLAGS = \ $(OPTIONAL_CRYPTO_CFLAGS) \ $(OPTIONAL_LZO_CFLAGS) \ $(OPTIONAL_LZ4_CFLAGS) \ - $(OPTIONAL_PKCS11_HELPER_CFLAGS) + $(OPTIONAL_PKCS11_HELPER_CFLAGS) \ + -DPLUGIN_LIBDIR=\"${plugindir}\" + if WIN32 # we want unicode entry point but not the macro AM_CFLAGS += -municode -UUNICODE From 31af45abfad7e3f0fbafc82b2daef3400a93359c Mon Sep 17 00:00:00 2001 From: Ilya Shipitsin Date: Sun, 29 Jan 2017 11:58:11 +0500 Subject: [PATCH 476/643] Resolve several travis-ci issues MBEDTLS_VERSION, OPENSSL_VERSION were defined twice - in both .travis.yml and .travis/build-deps.sh files, the last one defined OPENSSL_VERSION via nonexistent OPENSSL_VERION variable, which lead us to use openssl-1.0.1 instead of openssl-1.0.2, I removed variable definition from build-deps.sh "cache: [ apt: true ]" is not a travis supported option, it was introduced by mistake, I removed it LD_LIBRARY_PATH was defined for the entire test run, it includes custom openssl build, which was picked by "wget", so "wget" could not verify SSL cert at https://www.openssl.org sometimes. We do not want wget to pick our custom LD_LIBRARY_PATH, so I moved that variable to "script" section LD_LIBRARY_PATH was defined for both linux and osx environments, for the second DYLD_LIBRARY_PATH must be defined instead v2: Upgrade openssl, mbedtls to the most recent versions v3: DYLD_LIBRARY_PATH was defined via LD_LIBRARY_PATH by mistake Acked-by: Selva Nair Message-Id: <1485673091-7600-1-git-send-email-chipitsine@gmail.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13983.html Signed-off-by: David Sommerseth (cherry picked from commit 208c03ea145ed89083c43267733487c99a805069) --- .travis.yml | 8 ++++---- .travis/build-deps.sh | 2 -- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 369db97c970..a68374ae1f8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,13 +12,12 @@ env: global: - JOBS=3 - PREFIX="${HOME}/opt" - - MBEDTLS_VERSION="2.2.1" + - MBEDTLS_VERSION="2.4.0" - MBEDTLS_CFLAGS="-I${PREFIX}/include" - MBEDTLS_LIBS="-L${PREFIX}/lib -lmbedtls -lmbedx509 -lmbedcrypto" - - OPENSSL_VERSION="1.0.1t" + - OPENSSL_VERSION="1.0.2k" - OPENSSL_CFLAGS="-I${PREFIX}/include" - OPENSSL_LIBS="-L${PREFIX}/lib -lssl -lcrypto" - - LD_LIBRARY_PATH="${PREFIX}/lib:${LD_LIBRARY_PATH}" matrix: include: @@ -63,7 +62,6 @@ addons: - linux-libc-dev cache: - apt: true ccache: true directories: - download-cache @@ -77,6 +75,8 @@ install: - .travis/build-deps.sh > build-deps.log 2>&1 || (cat build-deps.log && exit 1) script: + - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then export LD_LIBRARY_PATH="${PREFIX}/lib:${LD_LIBRARY_PATH}"; fi + - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then export DYLD_LIBRARY_PATH="${PREFIX}/lib:${DYLD_LIBRARY_PATH}"; fi - autoreconf -vi - ./configure --with-crypto-library="${SSLLIB}" ${EXTRA_CONFIG} || (cat config.log && exit 1) - make -j$JOBS diff --git a/.travis/build-deps.sh b/.travis/build-deps.sh index bda54eea394..3ffba0bc02b 100755 --- a/.travis/build-deps.sh +++ b/.travis/build-deps.sh @@ -2,8 +2,6 @@ set -eux # Set defaults -MBEDTLS_VERSION="${MBEDTLS_VERSION:-2.2.1}" -OPENSSL_VERSION="${OPENSSL_VERION:-1.0.2h}" PREFIX="${PREFIX:-${HOME}/opt}" download_mbedtls () { From fb802b9b0d9366093b5567c0f3e9845b2f30e9cc Mon Sep 17 00:00:00 2001 From: Olivier Wahrenberger Date: Mon, 13 Feb 2017 19:38:26 +0100 Subject: [PATCH 477/643] Fix building with LibreSSL 2.5.1 by cleaning a hack. Similar to what is done in curl: https://github.com/curl/curl/blob/028391df5d84d9fae3433afdee9261d565900355/lib/vtls/openssl.c#L603-L619 Use SSL_CTX_get0_privatekey() for OpenSSL >= 1.0.2 Signed-off-by: Olivier Wahrenberger Acked-by: Steffan Karger Message-Id: <20170213183826.73008-1-O2Graphics@users.noreply.github.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14045.html Signed-off-by: Gert Doering (cherry picked from commit dcfd3b6173d8cdb4658de23db1dd0bd932b390d2) --- src/openvpn/ssl_openssl.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c index 8266595623e..abf69c91a60 100644 --- a/src/openvpn/ssl_openssl.c +++ b/src/openvpn/ssl_openssl.c @@ -508,10 +508,18 @@ tls_ctx_load_ecdh_params(struct tls_root_ctx *ctx, const char *curve_name const EC_GROUP *ecgrp = NULL; EVP_PKEY *pkey = NULL; +#if OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(LIBRESSL_VERSION_NUMBER) + pkey = SSL_CTX_get0_privatekey(ctx->ctx); +#else /* Little hack to get private key ref from SSL_CTX, yay OpenSSL... */ - SSL ssl; - ssl.cert = ctx->ctx->cert; - pkey = SSL_get_privatekey(&ssl); + SSL *ssl = SSL_new(ctx->ctx); + if (!ssl) + { + crypto_msg(M_FATAL, "SSL_new failed"); + } + pkey = SSL_get_privatekey(ssl); + SSL_free(ssl); +#endif msg(D_TLS_DEBUG, "Extracting ECDH curve from private key"); From c4c359736e3ab7f06a21f1eab09e6fd4cf2bef2f Mon Sep 17 00:00:00 2001 From: Emmanuel Deloget Date: Fri, 17 Feb 2017 23:00:53 +0100 Subject: [PATCH 478/643] OpenSSL: check for the SSL reason, not the full error OpenSSL 1.1 changed the SSLv3 API and removed many SSL_L_SSL3_* constants. Moreover, new code might use different function code for the same error. Thus, we extract the error reason from the error code before we compare it instead of trying to rebuild an error code that might not be correct. The new version is compatible with OpenSSL 1.0.x as well as with older versions (starting at 0.9.8). Signed-off-by: Emmanuel Deloget Acked-by: Steffan Karger Message-Id: <0e0d4a67192b563cd07d3f06685f85e34c304142.1487368114.git.logout@free.fr> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14087.html Signed-off-by: Gert Doering (cherry picked from commit 6ddc43d1bf9b3ea3ee5db8c50d56a98fe4db4c97) --- src/openvpn/crypto_openssl.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/openvpn/crypto_openssl.c b/src/openvpn/crypto_openssl.c index e4557156106..a66ee71e5af 100644 --- a/src/openvpn/crypto_openssl.c +++ b/src/openvpn/crypto_openssl.c @@ -193,8 +193,7 @@ crypto_print_openssl_errors(const unsigned int flags) while ((err = ERR_get_error())) { /* Be more clear about frequently occurring "no shared cipher" error */ - if (err == ERR_PACK(ERR_LIB_SSL,SSL_F_SSL3_GET_CLIENT_HELLO, - SSL_R_NO_SHARED_CIPHER)) + if (ERR_GET_REASON(err) == SSL_R_NO_SHARED_CIPHER) { msg(D_CRYPT_ERRORS, "TLS error: The server has no TLS ciphersuites " "in common with the client. Your --tls-cipher setting might be " From a9743bf25e661d66ca7537adfe457e75afc947c4 Mon Sep 17 00:00:00 2001 From: Selva Nair Date: Sat, 14 Jan 2017 16:16:29 -0500 Subject: [PATCH 479/643] Fix user's group membership check in interactive service to work with domains Currently the username unqualified by the domain is used to validate a user which fails for domain users. Instead authorize the user (i) if the built-in admin group or ovpn_admin group is in the process token (ii) else if the user's SID is in the built-in admin or ovpn_admin groups The second check is needed to recognize dynamic updates to group membership on the local machine that will not be reflected in the token. These checks do not require connection to a domain controller and will work even when user is logged in with cached credentials. Trac: #810 v2: include the token check as described above Signed-off-by: Selva Nair Acked-by: Gert Doering Message-Id: <1484428589-7882-1-git-send-email-selva.nair@gmail.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13877.html Signed-off-by: Gert Doering (cherry picked from commit e82733a1ab78062feca28578fe505b275a2356a6) --- src/openvpnserv/interactive.c | 2 +- src/openvpnserv/validate.c | 171 +++++++++++++++++++++++++--------- src/openvpnserv/validate.h | 2 +- 3 files changed, 130 insertions(+), 45 deletions(-) diff --git a/src/openvpnserv/interactive.c b/src/openvpnserv/interactive.c index 11b475c4e50..2bce598a77b 100644 --- a/src/openvpnserv/interactive.c +++ b/src/openvpnserv/interactive.c @@ -1477,7 +1477,7 @@ RunOpenvpn(LPVOID p) } /* Check user is authorized or options are white-listed */ - if (!IsAuthorizedUser(ovpn_user->User.Sid, &settings) + if (!IsAuthorizedUser(ovpn_user->User.Sid, imp_token, settings.ovpn_admin_group) && !ValidateOptions(pipe, sud.directory, sud.options)) { goto out; diff --git a/src/openvpnserv/validate.c b/src/openvpnserv/validate.c index c9c3855491b..894c51b1b55 100644 --- a/src/openvpnserv/validate.c +++ b/src/openvpnserv/validate.c @@ -49,6 +49,9 @@ static const WCHAR *white_list[] = NULL /* last value */ }; +static BOOL IsUserInGroup(PSID sid, const PTOKEN_GROUPS groups, const WCHAR *group_name); +static PTOKEN_GROUPS GetTokenGroups(const HANDLE token); + /* * Check workdir\fname is inside config_dir * The logic here is simple: we may reject some valid paths if ..\ is in any of the strings @@ -147,21 +150,16 @@ GetBuiltinAdminGroupName(WCHAR *name, DWORD nlen) /* * Check whether user is a member of Administrators group or - * the group specified in s->ovpn_admin_group + * the group specified in ovpn_admin_group */ BOOL -IsAuthorizedUser(SID *sid, settings_t *s) +IsAuthorizedUser(PSID sid, const HANDLE token, const WCHAR *ovpn_admin_group) { - LOCALGROUP_USERS_INFO_0 *groups = NULL; - DWORD nread; - DWORD nmax; - WCHAR *tmp = NULL; const WCHAR *admin_group[2]; WCHAR username[MAX_NAME]; WCHAR domain[MAX_NAME]; WCHAR sysadmin_group[MAX_NAME]; - DWORD err, len = MAX_NAME; - int i; + DWORD len = MAX_NAME; BOOL ret = FALSE; SID_NAME_USE sid_type; @@ -169,17 +167,9 @@ IsAuthorizedUser(SID *sid, settings_t *s) if (!LookupAccountSidW(NULL, sid, username, &len, domain, &len, &sid_type)) { MsgToEventLog(M_SYSERR, TEXT("LookupAccountSid")); - goto out; - } - - /* Get an array of groups the user is member of */ - err = NetUserGetLocalGroups(NULL, username, 0, LG_INCLUDE_INDIRECT, (LPBYTE *) &groups, - MAX_PREFERRED_LENGTH, &nread, &nmax); - if (err && err != ERROR_MORE_DATA) - { - SetLastError(err); - MsgToEventLog(M_SYSERR, TEXT("NetUserGetLocalGroups")); - goto out; + /* not fatal as this is now used only for logging */ + username[0] = '\0'; + domain[0] = '\0'; } if (GetBuiltinAdminGroupName(sysadmin_group, _countof(sysadmin_group))) @@ -192,41 +182,136 @@ IsAuthorizedUser(SID *sid, settings_t *s) /* use the default value */ admin_group[0] = SYSTEM_ADMIN_GROUP; } + admin_group[1] = ovpn_admin_group; -#ifdef UNICODE - admin_group[1] = s->ovpn_admin_group; -#else - tmp = NULL; - len = MultiByteToWideChar(CP_UTF8, 0, s->ovpn_admin_group, -1, NULL, 0); - if (len == 0 || (tmp = malloc(len*sizeof(WCHAR))) == NULL) + PTOKEN_GROUPS token_groups = GetTokenGroups(token); + for (int i = 0; i < 2; ++i) { - MsgToEventLog(M_SYSERR, TEXT("Failed to convert admin group name to WideChar")); - goto out; + ret = IsUserInGroup(sid, token_groups, admin_group[i]); + if (ret) + { + MsgToEventLog(M_INFO, TEXT("Authorizing user '%s@%s' by virtue of membership in group '%s'"), + username, domain, admin_group[i]); + goto out; + } } - MultiByteToWideChar(CP_UTF8, 0, s->ovpn_admin_group, -1, tmp, len); - admin_group[1] = tmp; -#endif - /* Check if user's groups include any of the admin groups */ - for (i = 0; i < nread; i++) +out: + free(token_groups); + return ret; +} + +/** + * Get a list of groups in token. + * Returns a pointer to TOKEN_GROUPS struct or NULL on error. + * The caller should free the returned pointer. + */ +static PTOKEN_GROUPS +GetTokenGroups(const HANDLE token) +{ + PTOKEN_GROUPS groups = NULL; + DWORD buf_size = 0; + + if (!GetTokenInformation(token, TokenGroups, groups, buf_size, &buf_size) + && GetLastError() == ERROR_INSUFFICIENT_BUFFER) + { + groups = malloc(buf_size); + } + if (!groups) + { + MsgToEventLog(M_SYSERR, L"GetTokenGroups"); + } + else if (!GetTokenInformation(token, TokenGroups, groups, buf_size, &buf_size)) { - if (wcscmp(groups[i].lgrui0_name, admin_group[0]) == 0 - || wcscmp(groups[i].lgrui0_name, admin_group[1]) == 0 - ) + MsgToEventLog(M_SYSERR, L"GetTokenInformation"); + free(groups); + } + return groups; +} + +/* + * Find SID from name + * + * On input sid buffer should have space for at least sid_size bytes. + * Returns true on success, false on failure. + * Suggest: in caller allocate sid to hold SECURITY_MAX_SID_SIZE bytes + */ +static BOOL +LookupSID(const WCHAR *name, PSID sid, DWORD sid_size) +{ + SID_NAME_USE su; + WCHAR domain[MAX_NAME]; + DWORD dlen = _countof(domain); + + if (!LookupAccountName(NULL, name, sid, &sid_size, domain, &dlen, &su)) + { + return FALSE; /* not fatal as the group may not exist */ + } + return TRUE; +} + +/** + * User is in group if the token groups contain the SID of the group + * of if the user is a direct member of the group. The latter check + * catches dynamic changes in group membership in the local user + * database not reflected in the token. + * If token_groups or sid is NULL the corresponding check is skipped. + * + * Using sid and list of groups in token avoids reference to domains so that + * this could be completed without access to a Domain Controller. + * + * Returns true if the user is in the group, false otherwise. + */ +static BOOL +IsUserInGroup(PSID sid, const PTOKEN_GROUPS token_groups, const WCHAR *group_name) +{ + BOOL ret = FALSE; + DWORD_PTR resume = 0; + DWORD err; + BYTE grp_sid[SECURITY_MAX_SID_SIZE]; + int nloop = 0; /* a counter used to not get stuck in the do .. while() */ + + /* first check in the token groups */ + if (token_groups && LookupSID(group_name, (PSID) grp_sid, _countof(grp_sid))) + { + for (DWORD i = 0; i < token_groups->GroupCount; ++i) { - MsgToEventLog(M_INFO, TEXT("Authorizing user %s by virtue of membership in group %s"), - username, groups[i].lgrui0_name); - ret = TRUE; - break; + if (EqualSid((PSID) grp_sid, token_groups->Groups[i].Sid)) + { + return TRUE; + } } } -out: - if (groups) + /* check user's SID is a member of the group */ + if (!sid) + { + return FALSE; + } + do + { + DWORD nread, nmax; + LOCALGROUP_MEMBERS_INFO_0 *members = NULL; + err = NetLocalGroupGetMembers(NULL, group_name, 0, (LPBYTE *) &members, + MAX_PREFERRED_LENGTH, &nread, &nmax, &resume); + if ((err != NERR_Success && err != ERROR_MORE_DATA)) + { + break; + } + /* If a match is already found, ret == TRUE and the loop is skipped */ + for (int i = 0; i < nread && !ret; ++i) + { + ret = EqualSid(members[i].lgrmi0_sid, sid); + } + NetApiBufferFree(members); + /* MSDN says the lookup should always iterate until err != ERROR_MORE_DATA */ + } while (err == ERROR_MORE_DATA && nloop++ < 100); + + if (err != NERR_Success && err != NERR_GroupNotFound) { - NetApiBufferFree(groups); + SetLastError(err); + MsgToEventLog(M_SYSERR, TEXT("In NetLocalGroupGetMembers for group '%s'"), group_name); } - free(tmp); return ret; } diff --git a/src/openvpnserv/validate.h b/src/openvpnserv/validate.h index ece8704c789..033e0e4cfa4 100644 --- a/src/openvpnserv/validate.h +++ b/src/openvpnserv/validate.h @@ -34,7 +34,7 @@ /* The last one may be reset in registry: HKLM\Software\OpenVPN\ovpn_admin_group */ BOOL -IsAuthorizedUser(SID *sid, settings_t *s); +IsAuthorizedUser(PSID sid, const HANDLE token, const WCHAR *ovpn_admin_group); BOOL CheckOption(const WCHAR *workdir, int narg, WCHAR *argv[], const settings_t *s); From c74d574417b8b491fe6ad44e89843af8479cc9be Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Tue, 31 Jan 2017 19:21:31 +0800 Subject: [PATCH 480/643] attempt to add IPv6 route even when no IPv6 address was configured Even if no IPv6 address is configured, OpenVPN still supports transporting IPv6 segments, therefore adding an IPv6 route should always be allowed. However, the route might fail to be installed or may just not work as expected, therefore, a proper warning should be printed to inform the user of the possible pitfall. Always allow adding an IPv6 route and print a WARNING when no IPv6 address is configured for the interface. Trac: #832 Signed-off-by: Antonio Quartulli Acked-by: Gert Doering Message-Id: <20170131112131.13570-1-a@unstable.cc> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13994.html Signed-off-by: Gert Doering (cherry picked from commit 2b7650e7ec9241745e4f66c932d6cffaece927d7) --- src/openvpn/route.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/openvpn/route.c b/src/openvpn/route.c index 223cb5f4c37..0145db3c6f9 100644 --- a/src/openvpn/route.c +++ b/src/openvpn/route.c @@ -1196,6 +1196,15 @@ add_routes(struct route_list *rl, struct route_ipv6_list *rl6, const struct tunt if (rl6 && !(rl6->iflags & RL_ROUTES_ADDED) ) { struct route_ipv6 *r; + + if (!tt->did_ifconfig_ipv6_setup) + { + msg(M_INFO, "WARNING: OpenVPN was configured to add an IPv6 " + "route over %s. However, no IPv6 has been configured for " + "this interface, therefore the route installation may " + "fail or may not work as expected.", tt->actual_name); + } + for (r = rl6->routes_ipv6; r; r = r->next) { if (flags & ROUTE_DELETE_FIRST) @@ -1882,14 +1891,6 @@ add_route_ipv6(struct route_ipv6 *r6, const struct tuntap *tt, unsigned int flag } #endif - if (!tt->did_ifconfig_ipv6_setup) - { - msg( M_INFO, "add_route_ipv6(): not adding %s/%d: " - "no IPv6 address been configured on interface %s", - network, r6->netbits, device); - return; - } - msg( M_INFO, "add_route_ipv6(%s/%d -> %s metric %d) dev %s", network, r6->netbits, gateway, r6->metric, device ); From 5340f56b62c9fe7ad892e815029321f378660714 Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Fri, 20 Jan 2017 00:25:18 +0800 Subject: [PATCH 481/643] fix redirect-gateway behaviour when an IPv4 default route does not exist When no IPv4 default route exists, the "redirect-gateway" routine aborts even if the sub-option "local" was specified or if we are connecting to the remote host using IPv6. This is not expected because in either case OpenVPN should not bother checking the existence of the default route as it is not required at all. Therefore, skip the IPv4 default route check when "local" is specified or we are connecting to an IPv6 remote host. Signed-off-by: Antonio Quartulli Acked-by: Gert Doering Message-Id: <20170119162518.31752-1-a@unstable.cc> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13905.html Signed-off-by: Gert Doering (cherry picked from commit 14670a9d654be48f92b58ac47e6f74d3dcfe1733) --- src/openvpn/route.c | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/src/openvpn/route.c b/src/openvpn/route.c index 0145db3c6f9..7e536effeb9 100644 --- a/src/openvpn/route.c +++ b/src/openvpn/route.c @@ -986,11 +986,19 @@ redirect_default_route_to_vpn(struct route_list *rl, const struct tuntap *tt, un if (rl && rl->flags & RG_ENABLE) { + bool local = rl->flags & RG_LOCAL; + if (!(rl->spec.flags & RTSA_REMOTE_ENDPOINT) && (rl->flags & RG_REROUTE_GW)) { msg(M_WARN, "%s VPN gateway parameter (--route-gateway or --ifconfig) is missing", err); } - else if (!(rl->rgi.flags & RGI_ADDR_DEFINED)) + /* + * check if a default route is defined, unless: + * - we are connecting to a remote host in our network + * - we are connecting to a non-IPv4 remote host (i.e. we use IPv6) + */ + else if (!(rl->rgi.flags & RGI_ADDR_DEFINED) && !local + && (rl->spec.remote_host != IPV4_INVALID_ADDR)) { msg(M_WARN, "%s Cannot read current default gateway from system", err); } @@ -1001,7 +1009,6 @@ redirect_default_route_to_vpn(struct route_list *rl, const struct tuntap *tt, un else { #ifndef TARGET_ANDROID - bool local = BOOL_CAST(rl->flags & RG_LOCAL); if (rl->flags & RG_AUTO_LOCAL) { const int tla = rl->spec.remote_host_local; @@ -1066,14 +1073,13 @@ redirect_default_route_to_vpn(struct route_list *rl, const struct tuntap *tt, un } else { - /* delete default route */ - del_route3(0, - 0, - rl->rgi.gateway.addr, - tt, - flags | ROUTE_REF_GW, - &rl->rgi, - es); + /* don't try to remove the def route if it does not exist */ + if (rl->rgi.flags & RGI_ADDR_DEFINED) + { + /* delete default route */ + del_route3(0, 0, rl->rgi.gateway.addr, tt, + flags | ROUTE_REF_GW, &rl->rgi, es); + } /* add new default route */ add_route3(0, @@ -1145,15 +1151,12 @@ undo_redirect_default_route_to_vpn(struct route_list *rl, const struct tuntap *t flags, &rl->rgi, es); - - /* restore original default route */ - add_route3(0, - 0, - rl->rgi.gateway.addr, - tt, - flags | ROUTE_REF_GW, - &rl->rgi, - es); + /* restore original default route if there was any */ + if (rl->rgi.flags & RGI_ADDR_DEFINED) + { + add_route3(0, 0, rl->rgi.gateway.addr, tt, + flags | ROUTE_REF_GW, &rl->rgi, es); + } } } From 58efba5013f6dae4136cc038af9ffd23796cbc0d Mon Sep 17 00:00:00 2001 From: Emmanuel Deloget Date: Fri, 17 Feb 2017 23:00:48 +0100 Subject: [PATCH 482/643] OpenSSL: don't use direct access to the internal of X509_STORE_CTX OpenSSL 1.1 does not allow us to directly access the internal of any data type, including X509_STORE_CTX. We have to use the defined functions to do so. Fortunately, these functions have existed since the dawn of time so we don't have any compatibility issue here. Signed-off-by: Emmanuel Deloget Acked-by: Steffan Karger Message-Id: <11477a0a3cf636572c84e0110a6f1b726bc60c2c.1487368114.git.logout@free.fr> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14085.html Signed-off-by: Gert Doering (cherry picked from commit 88046ad9e8e333259ae6fb4a295a9931a1a0e47f) --- src/openvpn/ssl_verify_openssl.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/openvpn/ssl_verify_openssl.c b/src/openvpn/ssl_verify_openssl.c index 274e2bbf96b..0dca09998f3 100644 --- a/src/openvpn/ssl_verify_openssl.c +++ b/src/openvpn/ssl_verify_openssl.c @@ -61,14 +61,15 @@ verify_callback(int preverify_ok, X509_STORE_CTX *ctx) session = (struct tls_session *) SSL_get_ex_data(ssl, mydata_index); ASSERT(session); - struct buffer cert_hash = x509_get_sha256_fingerprint(ctx->current_cert, &gc); - cert_hash_remember(session, ctx->error_depth, &cert_hash); + X509 *current_cert = X509_STORE_CTX_get_current_cert(ctx); + struct buffer cert_hash = x509_get_sha256_fingerprint(current_cert, &gc); + cert_hash_remember(session, X509_STORE_CTX_get_error_depth(ctx), &cert_hash); /* did peer present cert which was signed by our root cert? */ if (!preverify_ok) { /* get the X509 name */ - char *subject = x509_get_subject(ctx->current_cert, &gc); + char *subject = x509_get_subject(current_cert, &gc); if (!subject) { @@ -76,11 +77,11 @@ verify_callback(int preverify_ok, X509_STORE_CTX *ctx) } /* Log and ignore missing CRL errors */ - if (ctx->error == X509_V_ERR_UNABLE_TO_GET_CRL) + if (X509_STORE_CTX_get_error(ctx) == X509_V_ERR_UNABLE_TO_GET_CRL) { msg(D_TLS_DEBUG_LOW, "VERIFY WARNING: depth=%d, %s: %s", - ctx->error_depth, - X509_verify_cert_error_string(ctx->error), + X509_STORE_CTX_get_error_depth(ctx), + X509_verify_cert_error_string(X509_STORE_CTX_get_error(ctx)), subject); ret = 1; goto cleanup; @@ -88,8 +89,8 @@ verify_callback(int preverify_ok, X509_STORE_CTX *ctx) /* Remote site specified a certificate, but it's not correct */ msg(D_TLS_ERRORS, "VERIFY ERROR: depth=%d, error=%s: %s", - ctx->error_depth, - X509_verify_cert_error_string(ctx->error), + X509_STORE_CTX_get_error_depth(ctx), + X509_verify_cert_error_string(X509_STORE_CTX_get_error(ctx)), subject); ERR_clear_error(); @@ -98,7 +99,7 @@ verify_callback(int preverify_ok, X509_STORE_CTX *ctx) goto cleanup; } - if (SUCCESS != verify_cert(session, ctx->current_cert, ctx->error_depth)) + if (SUCCESS != verify_cert(session, current_cert, X509_STORE_CTX_get_error_depth(ctx))) { goto cleanup; } From b936ddfb631e3a4b219bd035f7110da5679b2d12 Mon Sep 17 00:00:00 2001 From: Emmanuel Deloget Date: Fri, 17 Feb 2017 23:00:40 +0100 Subject: [PATCH 483/643] OpenSSL: don't use direct access to the internal of SSL_CTX OpenSSL 1.1 does not allow us to directly access the internal of any data type, including SSL_CTX. We have to use the defined functions to do so. Compatibility with OpenSSL 1.0 is kept by defining the corresponding functions when they are not found in the library. Signed-off-by: Emmanuel Deloget Acked-by: Steffan Karger Message-Id: URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14088.html Signed-off-by: Gert Doering (cherry picked from commit 6554ac9fed9c5680f22aa4722e6e07ebf3aa3441) --- configure.ac | 9 +++++ src/openvpn/openssl_compat.h | 74 ++++++++++++++++++++++++++++++++++++ src/openvpn/ssl_openssl.c | 13 ++++--- 3 files changed, 91 insertions(+), 5 deletions(-) create mode 100644 src/openvpn/openssl_compat.h diff --git a/configure.ac b/configure.ac index b29f8b410df..5fe5d6046ce 100644 --- a/configure.ac +++ b/configure.ac @@ -898,6 +898,15 @@ if test "${enable_crypto}" = "yes" -a "${with_crypto_library}" = "openssl"; then [have_crypto_aead_modes="no"; break] ) + AC_CHECK_FUNCS( + [ \ + SSL_CTX_get_default_passwd_cb \ + SSL_CTX_get_default_passwd_cb_userdata \ + ], + , + [] + ) + CFLAGS="${saved_CFLAGS}" LIBS="${saved_LIBS}" diff --git a/src/openvpn/openssl_compat.h b/src/openvpn/openssl_compat.h new file mode 100644 index 00000000000..59bad9ff24d --- /dev/null +++ b/src/openvpn/openssl_compat.h @@ -0,0 +1,74 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single TCP/UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. + * Copyright (C) 2010-2017 Fox Crypto B.V. + * + * 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 + */ + +/** + * @file OpenSSL compatibility stub + * + * This file provide compatibility stubs for the OpenSSL libraries + * prior to version 1.1. This version introduces many changes in the + * library interface, including the fact that various objects and + * structures are not fully opaque. + */ + +#ifndef OPENSSL_COMPAT_H_ +#define OPENSSL_COMPAT_H_ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#elif defined(_MSC_VER) +#include "config-msvc.h" +#endif + +#include + +#if !defined(HAVE_SSL_CTX_GET_DEFAULT_PASSWD_CB_USERDATA) +/** + * Fetch the default password callback user data from the SSL context + * + * @param ctx SSL context + * @return The password callback user data + */ +static inline void * +SSL_CTX_get_default_passwd_cb_userdata(SSL_CTX *ctx) +{ + return ctx ? ctx->default_passwd_callback_userdata : NULL; +} +#endif + +#if !defined(HAVE_SSL_CTX_GET_DEFAULT_PASSWD_CB) +/** + * Fetch the default password callback from the SSL context + * + * @param ctx SSL context + * @return The password callback + */ +static inline pem_password_cb * +SSL_CTX_get_default_passwd_cb(SSL_CTX *ctx) +{ + return ctx ? ctx->default_passwd_callback : NULL; +} +#endif + +#endif /* OPENSSL_COMPAT_H_ */ diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c index abf69c91a60..39e92f8cdae 100644 --- a/src/openvpn/ssl_openssl.c +++ b/src/openvpn/ssl_openssl.c @@ -45,6 +45,7 @@ #include "ssl_backend.h" #include "ssl_common.h" #include "base64.h" +#include "openssl_compat.h" #ifdef ENABLE_CRYPTOAPI #include "cryptoapi.h" @@ -658,7 +659,8 @@ tls_ctx_load_pkcs12(struct tls_root_ctx *ctx, const char *pkcs12_file, { for (i = 0; i < sk_X509_num(ca); i++) { - if (!X509_STORE_add_cert(ctx->ctx->cert_store,sk_X509_value(ca, i))) + X509_STORE *cert_store = SSL_CTX_get_cert_store(ctx->ctx); + if (!X509_STORE_add_cert(cert_store,sk_X509_value(ca, i))) { crypto_msg(M_FATAL,"Cannot add certificate to certificate chain (X509_STORE_add_cert)"); } @@ -760,8 +762,9 @@ tls_ctx_load_cert_file_and_copy(struct tls_root_ctx *ctx, goto end; } - x = PEM_read_bio_X509(in, NULL, ctx->ctx->default_passwd_callback, - ctx->ctx->default_passwd_callback_userdata); + x = PEM_read_bio_X509(in, NULL, + SSL_CTX_get_default_passwd_cb(ctx->ctx), + SSL_CTX_get_default_passwd_cb_userdata(ctx->ctx)); if (x == NULL) { SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_PEM_LIB); @@ -843,8 +846,8 @@ tls_ctx_load_priv_file(struct tls_root_ctx *ctx, const char *priv_key_file, } pkey = PEM_read_bio_PrivateKey(in, NULL, - ssl_ctx->default_passwd_callback, - ssl_ctx->default_passwd_callback_userdata); + SSL_CTX_get_default_passwd_cb(ctx->ctx), + SSL_CTX_get_default_passwd_cb_userdata(ctx->ctx)); if (!pkey) { goto end; From 24bca7bee2ee5c48880a197ce9727bbc5a0149e5 Mon Sep 17 00:00:00 2001 From: Emmanuel Deloget Date: Fri, 17 Feb 2017 23:00:41 +0100 Subject: [PATCH 484/643] OpenSSL: don't use direct access to the internal of X509_STORE OpenSSL 1.1 does not allow us to directly access the internal of any data type, including X509_STORE. We have to use the defined functions to do so. Compatibility with OpenSSL 1.0 is kept by defining the corresponding functions when they are not found in the library. Signed-off-by: Emmanuel Deloget Acked-by: Steffan Karger Message-Id: <8e6d66e3a9a40abb3d7c99c48ba59bad1037d0ef.1487368114.git.logout@free.fr> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14076.html Signed-off-by: Gert Doering (cherry picked from commit f05665df4150c6a345eec5432a02fd799bea0f2c) --- configure.ac | 1 + src/openvpn/openssl_compat.h | 15 +++++++++++++++ src/openvpn/ssl_openssl.c | 7 ++++--- src/openvpn/ssl_verify_openssl.c | 6 ++++-- 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index 5fe5d6046ce..415128c9f86 100644 --- a/configure.ac +++ b/configure.ac @@ -902,6 +902,7 @@ if test "${enable_crypto}" = "yes" -a "${with_crypto_library}" = "openssl"; then [ \ SSL_CTX_get_default_passwd_cb \ SSL_CTX_get_default_passwd_cb_userdata \ + X509_STORE_get0_objects \ ], , [] diff --git a/src/openvpn/openssl_compat.h b/src/openvpn/openssl_compat.h index 59bad9ff24d..016008bc170 100644 --- a/src/openvpn/openssl_compat.h +++ b/src/openvpn/openssl_compat.h @@ -42,6 +42,7 @@ #endif #include +#include #if !defined(HAVE_SSL_CTX_GET_DEFAULT_PASSWD_CB_USERDATA) /** @@ -71,4 +72,18 @@ SSL_CTX_get_default_passwd_cb(SSL_CTX *ctx) } #endif +#if !defined(HAVE_X509_STORE_GET0_OBJECTS) +/** + * Fetch the X509 object stack from the X509 store + * + * @param store X509 object store + * @return the X509 object stack + */ +static inline STACK_OF(X509_OBJECT) * +X509_STORE_get0_objects(X509_STORE *store) +{ + return store ? store->objs : NULL; +} +#endif + #endif /* OPENSSL_COMPAT_H_ */ diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c index 39e92f8cdae..e57de43a748 100644 --- a/src/openvpn/ssl_openssl.c +++ b/src/openvpn/ssl_openssl.c @@ -900,13 +900,14 @@ backend_tls_ctx_reload_crl(struct tls_root_ctx *ssl_ctx, const char *crl_file, /* Always start with a cleared CRL list, for that we * we need to manually find the CRL object from the stack * and remove it */ - for (int i = 0; i < sk_X509_OBJECT_num(store->objs); i++) + STACK_OF(X509_OBJECT) *objs = X509_STORE_get0_objects(store); + for (int i = 0; i < sk_X509_OBJECT_num(objs); i++) { - X509_OBJECT *obj = sk_X509_OBJECT_value(store->objs, i); + X509_OBJECT *obj = sk_X509_OBJECT_value(objs, i); ASSERT(obj); if (obj->type == X509_LU_CRL) { - sk_X509_OBJECT_delete(store->objs, i); + sk_X509_OBJECT_delete(objs, i); X509_OBJECT_free_contents(obj); OPENSSL_free(obj); } diff --git a/src/openvpn/ssl_verify_openssl.c b/src/openvpn/ssl_verify_openssl.c index 0dca09998f3..238924865de 100644 --- a/src/openvpn/ssl_verify_openssl.c +++ b/src/openvpn/ssl_verify_openssl.c @@ -43,6 +43,7 @@ #include "ssl_openssl.h" #include "ssl_verify.h" #include "ssl_verify_backend.h" +#include "openssl_compat.h" #include #include @@ -716,9 +717,10 @@ tls_verify_crl_missing(const struct tls_options *opt) crypto_msg(M_FATAL, "Cannot get certificate store"); } - for (int i = 0; i < sk_X509_OBJECT_num(store->objs); i++) + STACK_OF(X509_OBJECT) *objs = X509_STORE_get0_objects(store); + for (int i = 0; i < sk_X509_OBJECT_num(objs); i++) { - X509_OBJECT *obj = sk_X509_OBJECT_value(store->objs, i); + X509_OBJECT *obj = sk_X509_OBJECT_value(objs, i); ASSERT(obj); if (obj->type == X509_LU_CRL) { From d782597ede843266fd2c7854a6f90ec7ce4bb92b Mon Sep 17 00:00:00 2001 From: Emmanuel Deloget Date: Fri, 17 Feb 2017 23:00:42 +0100 Subject: [PATCH 485/643] OpenSSL: don't use direct access to the internal of X509_OBJECT OpenSSL 1.1 does not allow us to directly access the internal of any data type, including X509_OBJECT. We have to use the defined functions to do so. Compatibility with OpenSSL 1.0 is kept by defining the corresponding functions when they are not found in the library. Signed-off-by: Emmanuel Deloget Acked-by: Steffan Karger Message-Id: URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14080.html Signed-off-by: Gert Doering (cherry picked from commit 47191f49890ee5c53fa78a8ce9bf96b9c8d27a82) --- configure.ac | 2 ++ src/openvpn/openssl_compat.h | 31 +++++++++++++++++++++++++++++++ src/openvpn/ssl_openssl.c | 5 ++--- src/openvpn/ssl_verify_openssl.c | 2 +- 4 files changed, 36 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index 415128c9f86..789ad08fbaa 100644 --- a/configure.ac +++ b/configure.ac @@ -903,6 +903,8 @@ if test "${enable_crypto}" = "yes" -a "${with_crypto_library}" = "openssl"; then SSL_CTX_get_default_passwd_cb \ SSL_CTX_get_default_passwd_cb_userdata \ X509_STORE_get0_objects \ + X509_OBJECT_free \ + X509_OBJECT_get_type \ ], , [] diff --git a/src/openvpn/openssl_compat.h b/src/openvpn/openssl_compat.h index 016008bc170..458a6adbe2b 100644 --- a/src/openvpn/openssl_compat.h +++ b/src/openvpn/openssl_compat.h @@ -86,4 +86,35 @@ X509_STORE_get0_objects(X509_STORE *store) } #endif +#if !defined(HAVE_X509_OBJECT_FREE) +/** + * Destroy a X509 object + * + * @param obj X509 object + */ +static inline void +X509_OBJECT_free(X509_OBJECT *obj) +{ + if (obj) + { + X509_OBJECT_free_contents(obj); + OPENSSL_free(obj); + } +} +#endif + +#if !defined(HAVE_X509_OBJECT_GET_TYPE) +/** + * Get the type of an X509 object + * + * @param obj X509 object + * @return The underlying object type + */ +static inline int +X509_OBJECT_get_type(const X509_OBJECT *obj) +{ + return obj ? obj->type : X509_LU_FAIL; +} +#endif + #endif /* OPENSSL_COMPAT_H_ */ diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c index e57de43a748..bf0f643f254 100644 --- a/src/openvpn/ssl_openssl.c +++ b/src/openvpn/ssl_openssl.c @@ -905,11 +905,10 @@ backend_tls_ctx_reload_crl(struct tls_root_ctx *ssl_ctx, const char *crl_file, { X509_OBJECT *obj = sk_X509_OBJECT_value(objs, i); ASSERT(obj); - if (obj->type == X509_LU_CRL) + if (X509_OBJECT_get_type(obj) == X509_LU_CRL) { sk_X509_OBJECT_delete(objs, i); - X509_OBJECT_free_contents(obj); - OPENSSL_free(obj); + X509_OBJECT_free(obj); } } diff --git a/src/openvpn/ssl_verify_openssl.c b/src/openvpn/ssl_verify_openssl.c index 238924865de..5c2c5b75208 100644 --- a/src/openvpn/ssl_verify_openssl.c +++ b/src/openvpn/ssl_verify_openssl.c @@ -722,7 +722,7 @@ tls_verify_crl_missing(const struct tls_options *opt) { X509_OBJECT *obj = sk_X509_OBJECT_value(objs, i); ASSERT(obj); - if (obj->type == X509_LU_CRL) + if (X509_OBJECT_get_type(obj) == X509_LU_CRL) { return false; } From c9b4313eae6fc59f7d075edf23a7f59b137ba11f Mon Sep 17 00:00:00 2001 From: Simon Matter Date: Tue, 21 Feb 2017 20:34:15 +0100 Subject: [PATCH 486/643] Fix segfault when using crypto lib without AES-256-CTR or SHA256 Openvpn segfaults on RHEL5/CentOS5 when using --tls-crypt, because it doesn't have AES-256-CTR support: openvpn[15330]: OpenVPN 2.4.0 x86_64-redhat-linux-gnu [SSL (OpenSSL)] [LZO] [LZ4] [EPOLL] [MH/PKTINFO] built on Jan 17 2017 openvpn[15330]: library versions: OpenSSL 0.9.8e-fips-rhel5 01 Jul 2008, LZO 2.09, LZ4 1.7.5 openvpn[15331]: NOTE: the current --script-security setting may allow this configuration to call user-defined scripts kernel: openvpn[15331]: segfault at 0000000000000008 rip 000000000040ebe0 rsp 00007fffdcfc5738 error 4 This patch fixes it so it shows: openvpn[424]: ERROR: --tls-crypt requires AES-256-CTR support. openvpn[424]: Exiting due to fatal error Trac: #825 Acked-by: Steffan Karger Message-Id: <345db0ac-f6e8-8490-a80a-ffbd81972c07@karger.me> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14138.html Signed-off-by: Gert Doering (cherry picked from commit 2fe5547c1df854d41611633ea533649fe88e3031) --- src/openvpn/tls_crypt.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/openvpn/tls_crypt.c b/src/openvpn/tls_crypt.c index 804c27926ae..e2fdbed2f42 100644 --- a/src/openvpn/tls_crypt.c +++ b/src/openvpn/tls_crypt.c @@ -51,9 +51,7 @@ tls_crypt_init_key(struct key_ctx_bi *key, const char *key_file, struct key_type kt; kt.cipher = cipher_kt_get("AES-256-CTR"); - kt.cipher_length = cipher_kt_key_size(kt.cipher); kt.digest = md_kt_get("SHA256"); - kt.hmac_length = md_kt_size(kt.digest); if (!kt.cipher) { @@ -64,6 +62,9 @@ tls_crypt_init_key(struct key_ctx_bi *key, const char *key_file, msg(M_FATAL, "ERROR: --tls-crypt requires HMAC-SHA-256 support."); } + kt.cipher_length = cipher_kt_key_size(kt.cipher); + kt.hmac_length = md_kt_size(kt.digest); + crypto_read_openvpn_key(&kt, key, key_file, key_inline, key_direction, "Control Channel Encryption", "tls-crypt"); } From bbc671c2fdf6287605ef5057b1d44811bcd81785 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Thu, 23 Feb 2017 09:49:54 +0100 Subject: [PATCH 487/643] Add openssl_compat.h to openvpn_SOURCES Commit b936ddfb63 introduced a new header file but forgot to include it in the list of openvpn_SOURCES, so it did not get bundled in the generated tarballs. Signed-off-by: Gert Doering Acked-by: Steffan Karger Message-Id: <20170223084954.58464-1-gert@greenie.muc.de> URL: http://www.mail-archive.com/search?l=mid&q=20170223084954.58464-1-gert@greenie.muc.de Signed-off-by: Gert Doering (cherry picked from commit 827c05732b0414dbf3cc05bf4ae6bfda042eadd3) --- src/openvpn/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/src/openvpn/Makefile.am b/src/openvpn/Makefile.am index 3f978553162..fcc22d684f9 100644 --- a/src/openvpn/Makefile.am +++ b/src/openvpn/Makefile.am @@ -81,6 +81,7 @@ openvpn_SOURCES = \ multi.c multi.h \ ntlm.c ntlm.h \ occ.c occ.h occ-inline.h \ + openssl_compat.h \ pkcs11.c pkcs11.h pkcs11_backend.h \ pkcs11_openssl.c \ pkcs11_mbedtls.c \ From b97a5cc044dc6db3f0e1f9f06a6f5da522f0a33a Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Thu, 23 Feb 2017 11:35:38 +0100 Subject: [PATCH 488/643] OpenSSL: 1.1 fallout - fix configure on old autoconf Older versions of autoconf generate an empty "else fi" block for empty fields in an AC_CHECK_FUNCS() macro. This breaks on e.g. RHEL6. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1487846138-22231-1-git-send-email-steffan.karger@fox-it.com> URL: http://www.mail-archive.com/search?l=mid&q=1487846138-22231-1-git-send-email-steffan.karger@fox-it.com Signed-off-by: Gert Doering (cherry picked from commit 07372a0fdeb3638204d197d0614f776a0eb73ab9) --- configure.ac | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 789ad08fbaa..0c55d783275 100644 --- a/configure.ac +++ b/configure.ac @@ -905,9 +905,7 @@ if test "${enable_crypto}" = "yes" -a "${with_crypto_library}" = "openssl"; then X509_STORE_get0_objects \ X509_OBJECT_free \ X509_OBJECT_get_type \ - ], - , - [] + ] ) CFLAGS="${saved_CFLAGS}" From 4c241acc67c1d6b42dbe1f6199c75d9f7f228ac2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 24 Feb 2017 13:22:52 +0100 Subject: [PATCH 489/643] fix typo in notification message Signed-off-by: Christian Hesse Acked-by: Gert Doering Message-Id: <20170224122252.15199-1-list@eworm.de> URL: http://www.mail-archive.com/search?l=mid&q=20170224122252.15199-1-list@eworm.de Signed-off-by: Gert Doering (cherry picked from commit b13bc6c9570e00d12e26bb3b8e5bf9bdb0b16eff) --- src/openvpn/init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openvpn/init.c b/src/openvpn/init.c index ef1c757b9ca..8f9578d09ac 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -567,7 +567,7 @@ context_init_1(struct context *c) * do any fork due to daemon() a future call. * See possibly_become_daemon() [init.c] for more details. */ - sd_notifyf(0, "READY=1\nSTATUS=Pre-connection initialization succesfull\nMAINPID=%lu", + sd_notifyf(0, "READY=1\nSTATUS=Pre-connection initialization successful\nMAINPID=%lu", (unsigned long) getpid()); #endif From 2085c1f3875b9c96ac739941712247b805677efa Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Fri, 24 Feb 2017 14:52:22 +0100 Subject: [PATCH 490/643] Fix '--dev null' To test whether a server is reachable and all the key handling is right, openvpn can connect with "--dev null --ifconfig-noexec" to avoid needing to the client with elevated privileges. This was erroring out for no good reason (because the "set environment variables appropriately" code didn't know if this is a tun or tap device...) - treat --dev null as "tap", done. Signed-off-by: Gert Doering Acked-by: Steffan Karger Message-Id: <20170224135222.44640-1-gert@greenie.muc.de> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14186.html Signed-off-by: Gert Doering (cherry picked from commit 22c5381b71710ad0e1dbbccc1d5680fccb602311) --- src/openvpn/tun.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index 31585b325ea..3504fbf4653 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -560,7 +560,9 @@ is_tun_p2p(const struct tuntap *tt) { bool tun = false; - if (tt->type == DEV_TYPE_TAP || (tt->type == DEV_TYPE_TUN && tt->topology == TOP_SUBNET)) + if (tt->type == DEV_TYPE_TAP + || (tt->type == DEV_TYPE_TUN && tt->topology == TOP_SUBNET) + || tt->type == DEV_TYPE_NULL ) { tun = false; } From 44bac2926d6b445a7773a24bb7c295b54f4be35e Mon Sep 17 00:00:00 2001 From: Emmanuel Deloget Date: Thu, 23 Feb 2017 15:35:56 +0100 Subject: [PATCH 491/643] OpenSSL: don't use direct access to the internal of RSA_METHOD OpenSSL 1.1 does not allow us to directly access the internal of any data type, including RSA_METHOD. We have to use the defined functions to do so. Compatibility with OpenSSL 1.0 is kept by defining the corresponding functions when they are not found in the library. Signed-off-by: Emmanuel Deloget Acked-by: Steffan Karger Message-Id: <79d89580db6fd92c059dabc4f5f4d83b72bb9d3d.1487859361.git.logout@free.fr> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14175.html Signed-off-by: Gert Doering (cherry picked from commit 09776c5b52df13121504e07894a26d5cd1883317) --- configure.ac | 9 ++ src/openvpn/openssl_compat.h | 190 +++++++++++++++++++++++++++++++++++ src/openvpn/ssl_openssl.c | 22 ++-- 3 files changed, 210 insertions(+), 11 deletions(-) diff --git a/configure.ac b/configure.ac index 0c55d783275..2406ad8d6bf 100644 --- a/configure.ac +++ b/configure.ac @@ -905,6 +905,15 @@ if test "${enable_crypto}" = "yes" -a "${with_crypto_library}" = "openssl"; then X509_STORE_get0_objects \ X509_OBJECT_free \ X509_OBJECT_get_type \ + RSA_meth_new \ + RSA_meth_free \ + RSA_meth_set_pub_enc \ + RSA_meth_set_pub_dec \ + RSA_meth_set_priv_enc \ + RSA_meth_set_priv_dec \ + RSA_meth_set_init \ + RSA_meth_set_finish \ + RSA_meth_set0_app_data \ ] ) diff --git a/src/openvpn/openssl_compat.h b/src/openvpn/openssl_compat.h index 458a6adbe2b..e98e8dffc57 100644 --- a/src/openvpn/openssl_compat.h +++ b/src/openvpn/openssl_compat.h @@ -41,6 +41,8 @@ #include "config-msvc.h" #endif +#include "buffer.h" + #include #include @@ -117,4 +119,192 @@ X509_OBJECT_get_type(const X509_OBJECT *obj) } #endif +#if !defined(HAVE_RSA_METH_NEW) +/** + * Allocate a new RSA method object + * + * @param name The object name + * @param flags Configuration flags + * @return A new RSA method object + */ +static inline RSA_METHOD * +RSA_meth_new(const char *name, int flags) +{ + RSA_METHOD *rsa_meth = NULL; + ALLOC_OBJ_CLEAR(rsa_meth, RSA_METHOD); + rsa_meth->name = string_alloc(name, NULL); + rsa_meth->flags = flags; + return rsa_meth; +} +#endif + +#if !defined(HAVE_RSA_METH_FREE) +/** + * Free an existing RSA_METHOD object + * + * @param meth The RSA_METHOD object + */ +static inline void +RSA_meth_free(RSA_METHOD *meth) +{ + if (meth) + { + free(meth->name); + free(meth); + } +} +#endif + +#if !defined(HAVE_RSA_METH_SET_PUB_ENC) +/** + * Set the public encoding function of an RSA_METHOD object + * + * @param meth The RSA_METHOD object + * @param pub_enc the public encoding function + * @return 1 on success, 0 on error + */ +static inline int +RSA_meth_set_pub_enc(RSA_METHOD *meth, + int (*pub_enc) (int flen, const unsigned char *from, + unsigned char *to, RSA *rsa, + int padding)) +{ + if (meth) + { + meth->rsa_pub_enc = pub_enc; + return 1; + } + return 0; +} +#endif + +#if !defined(HAVE_RSA_METH_SET_PUB_DEC) +/** + * Set the public decoding function of an RSA_METHOD object + * + * @param meth The RSA_METHOD object + * @param pub_dec the public decoding function + * @return 1 on success, 0 on error + */ +static inline int +RSA_meth_set_pub_dec(RSA_METHOD *meth, + int (*pub_dec) (int flen, const unsigned char *from, + unsigned char *to, RSA *rsa, + int padding)) +{ + if (meth) + { + meth->rsa_pub_dec = pub_dec; + return 1; + } + return 0; +} +#endif + +#if !defined(HAVE_RSA_METH_SET_PRIV_ENC) +/** + * Set the private encoding function of an RSA_METHOD object + * + * @param meth The RSA_METHOD object + * @param priv_enc the private encoding function + * @return 1 on success, 0 on error + */ +static inline int +RSA_meth_set_priv_enc(RSA_METHOD *meth, + int (*priv_enc) (int flen, const unsigned char *from, + unsigned char *to, RSA *rsa, + int padding)) +{ + if (meth) + { + meth->rsa_priv_enc = priv_enc; + return 1; + } + return 0; +} +#endif + +#if !defined(HAVE_RSA_METH_SET_PRIV_DEC) +/** + * Set the private decoding function of an RSA_METHOD object + * + * @param meth The RSA_METHOD object + * @param priv_dec the private decoding function + * @return 1 on success, 0 on error + */ +static inline int +RSA_meth_set_priv_dec(RSA_METHOD *meth, + int (*priv_dec) (int flen, const unsigned char *from, + unsigned char *to, RSA *rsa, + int padding)) +{ + if (meth) + { + meth->rsa_priv_dec = priv_dec; + return 1; + } + return 0; +} +#endif + +#if !defined(HAVE_RSA_METH_SET_INIT) +/** + * Set the init function of an RSA_METHOD object + * + * @param meth The RSA_METHOD object + * @param init the init function + * @return 1 on success, 0 on error + */ +static inline int +RSA_meth_set_init(RSA_METHOD *meth, int (*init) (RSA *rsa)) +{ + if (meth) + { + meth->init = init; + return 1; + } + return 0; +} +#endif + +#if !defined(HAVE_RSA_METH_SET_FINISH) +/** + * Set the finish function of an RSA_METHOD object + * + * @param meth The RSA_METHOD object + * @param finish the finish function + * @return 1 on success, 0 on error + */ +static inline int +RSA_meth_set_finish(RSA_METHOD *meth, int (*finish) (RSA *rsa)) +{ + if (meth) + { + meth->finish = finish; + return 1; + } + return 0; +} +#endif + +#if !defined(HAVE_RSA_METH_SET0_APP_DATA) +/** + * Set the application data of an RSA_METHOD object + * + * @param meth The RSA_METHOD object + * @param app_data Application data + * @return 1 on success, 0 on error + */ +static inline int +RSA_meth_set0_app_data(RSA_METHOD *meth, void *app_data) +{ + if (meth) + { + meth->app_data = app_data; + return 1; + } + return 0; +} +#endif + #endif /* OPENSSL_COMPAT_H_ */ diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c index bf0f643f254..f011e067025 100644 --- a/src/openvpn/ssl_openssl.c +++ b/src/openvpn/ssl_openssl.c @@ -978,7 +978,7 @@ rsa_priv_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, i static int rsa_finish(RSA *rsa) { - free((void *)rsa->meth); + RSA_meth_free(rsa->meth); rsa->meth = NULL; return 1; } @@ -1053,16 +1053,16 @@ tls_ctx_use_external_private_key(struct tls_root_ctx *ctx, ASSERT(NULL != cert); /* allocate custom RSA method object */ - ALLOC_OBJ_CLEAR(rsa_meth, RSA_METHOD); - rsa_meth->name = "OpenVPN external private key RSA Method"; - rsa_meth->rsa_pub_enc = rsa_pub_enc; - rsa_meth->rsa_pub_dec = rsa_pub_dec; - rsa_meth->rsa_priv_enc = rsa_priv_enc; - rsa_meth->rsa_priv_dec = rsa_priv_dec; - rsa_meth->init = NULL; - rsa_meth->finish = rsa_finish; - rsa_meth->flags = RSA_METHOD_FLAG_NO_CHECK; - rsa_meth->app_data = NULL; + rsa_meth = RSA_meth_new("OpenVPN external private key RSA Method", + RSA_METHOD_FLAG_NO_CHECK); + check_malloc_return(rsa_meth); + RSA_meth_set_pub_enc(rsa_meth, rsa_pub_enc); + RSA_meth_set_pub_dec(rsa_meth, rsa_pub_dec); + RSA_meth_set_priv_enc(rsa_meth, rsa_priv_enc); + RSA_meth_set_priv_dec(rsa_meth, rsa_priv_dec); + RSA_meth_set_init(rsa_meth, NULL); + RSA_meth_set_finish(rsa_meth, rsa_finish); + RSA_meth_set0_app_data(rsa_meth, NULL); /* allocate RSA object */ rsa = RSA_new(); From d702b2539d43a3326d76cc1764fedf237fc6744f Mon Sep 17 00:00:00 2001 From: Emmanuel Deloget Date: Fri, 17 Feb 2017 23:00:52 +0100 Subject: [PATCH 492/643] OpenSSL: SSLeay symbols are no longer available in OpenSSL 1.1 The old symbols do not exist anymore but the library gained new equivalent symbols (OSSL). Use them instead of the old ones Signed-off-by: Emmanuel Deloget Acked-by: Steffan Karger Message-Id: <9ce17efda7b1ed100e73554b1916c0bfa687d9d1.1487368114.git.logout@free.fr> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14089.html Signed-off-by: Gert Doering (cherry picked from commit c828ffc648eebda20e2f9087248944fa0f52a582) --- src/openvpn/openssl_compat.h | 5 +++++ src/openvpn/ssl_openssl.c | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/openvpn/openssl_compat.h b/src/openvpn/openssl_compat.h index e98e8dffc57..92f014d57f3 100644 --- a/src/openvpn/openssl_compat.h +++ b/src/openvpn/openssl_compat.h @@ -307,4 +307,9 @@ RSA_meth_set0_app_data(RSA_METHOD *meth, void *app_data) } #endif +/* SSLeay symbols have been renamed in OpenSSL 1.1 */ +#if !defined(RSA_F_RSA_OSSL_PRIVATE_ENCRYPT) +#define RSA_F_RSA_OSSL_PRIVATE_ENCRYPT RSA_F_RSA_EAY_PRIVATE_ENCRYPT +#endif + #endif /* OPENSSL_COMPAT_H_ */ diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c index f011e067025..d7cc2ba44aa 100644 --- a/src/openvpn/ssl_openssl.c +++ b/src/openvpn/ssl_openssl.c @@ -995,7 +995,7 @@ rsa_priv_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, i if (padding != RSA_PKCS1_PADDING) { - RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, RSA_R_UNKNOWN_PADDING_TYPE); + RSAerr(RSA_F_RSA_OSSL_PRIVATE_ENCRYPT, RSA_R_UNKNOWN_PADDING_TYPE); goto done; } From 0fa3df510c10820d00b8f5c77a8730f90189f30d Mon Sep 17 00:00:00 2001 From: Emmanuel Deloget Date: Mon, 20 Feb 2017 15:32:34 +0100 Subject: [PATCH 493/643] OpenSSL: use EVP_CipherInit_ex() instead of EVP_CipherInit() The behavior of EVP_CipherInit() changed in OpenSSL 1.1 -- instead of clearing the context when the cipher parameter was !NULL, it now clears the context unconditionnaly. As a result, subsequent calls to the function with additional information now fails. The bulk work is done by EVP_CipherInit_ex() which has been part of the OpenSSL interface since the dawn of time (0.9.8 already has it). Thus, the change allows us to get the old behavior back instead of relying on dirty tricks. Signed-off-by: Emmanuel Deloget Acked-by: Steffan Karger Message-Id: <2faff7647151d7fe362c1c5db9f97e520444d09b.1487600539.git.logout@free.fr> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14120.html Signed-off-by: Gert Doering (cherry picked from commit 8d00afae88b626c9cf14170a943b33a7ed378070) --- src/openvpn/crypto_openssl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/openvpn/crypto_openssl.c b/src/openvpn/crypto_openssl.c index a66ee71e5af..5549d708345 100644 --- a/src/openvpn/crypto_openssl.c +++ b/src/openvpn/crypto_openssl.c @@ -671,7 +671,7 @@ cipher_ctx_init(EVP_CIPHER_CTX *ctx, uint8_t *key, int key_len, crypto_msg(M_FATAL, "EVP set key size"); } #endif - if (!EVP_CipherInit(ctx, NULL, key, NULL, enc)) + if (!EVP_CipherInit_ex(ctx, NULL, NULL, key, NULL, enc)) { crypto_msg(M_FATAL, "EVP cipher init #2"); } @@ -724,7 +724,7 @@ cipher_ctx_get_cipher_kt(const cipher_ctx_t *ctx) int cipher_ctx_reset(EVP_CIPHER_CTX *ctx, uint8_t *iv_buf) { - return EVP_CipherInit(ctx, NULL, NULL, iv_buf, -1); + return EVP_CipherInit_ex(ctx, NULL, NULL, NULL, iv_buf, -1); } int From 39e847e0c002b0d08bb3612e1b67e74369debf63 Mon Sep 17 00:00:00 2001 From: Ilya Shipitsin Date: Sun, 5 Mar 2017 20:21:32 +0300 Subject: [PATCH 494/643] travis-ci: remove unused files Those files were commited by mistake. I implemented building dependencies in 4 separate scripts, later Steffan Karger combined all 4 scripts into "build-deps.sh". Signed-off-by: Ilya Shipitsin Acked-by: Steffan Karger Message-Id: <1488734492-5319-1-git-send-email-chipitsine@gmail.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14234.html Signed-off-by: Gert Doering (cherry picked from commit 85ac77c90bba0a912625ad6926a9595c3192f902) --- .travis/build-mbedtls-linux.sh | 9 --------- .travis/build-mbedtls-osx.sh | 9 --------- .travis/build-openssl-linux.sh | 12 ------------ .travis/build-openssl-osx.sh | 11 ----------- 4 files changed, 41 deletions(-) delete mode 100755 .travis/build-mbedtls-linux.sh delete mode 100755 .travis/build-mbedtls-osx.sh delete mode 100755 .travis/build-openssl-linux.sh delete mode 100755 .travis/build-openssl-osx.sh diff --git a/.travis/build-mbedtls-linux.sh b/.travis/build-mbedtls-linux.sh deleted file mode 100755 index dc92aafe6af..00000000000 --- a/.travis/build-mbedtls-linux.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh - -if [ ! -f download-cache/mbedtls-${MBEDTLS_VERSION}-apache.tgz ]; then - wget -O download-cache/mbedtls-${MBEDTLS_VERSION}-apache.tgz https://tls.mbed.org/download/mbedtls-${MBEDTLS_VERSION}-apache.tgz; -fi - -tar zxf download-cache/mbedtls-${MBEDTLS_VERSION}-apache.tgz -cd mbedtls-${MBEDTLS_VERSION} && make > build.log 2>&1 || (cat build.log && exit 1) -make install DESTDIR=$MBEDTLS_PREFIX && cd .. diff --git a/.travis/build-mbedtls-osx.sh b/.travis/build-mbedtls-osx.sh deleted file mode 100755 index dc92aafe6af..00000000000 --- a/.travis/build-mbedtls-osx.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh - -if [ ! -f download-cache/mbedtls-${MBEDTLS_VERSION}-apache.tgz ]; then - wget -O download-cache/mbedtls-${MBEDTLS_VERSION}-apache.tgz https://tls.mbed.org/download/mbedtls-${MBEDTLS_VERSION}-apache.tgz; -fi - -tar zxf download-cache/mbedtls-${MBEDTLS_VERSION}-apache.tgz -cd mbedtls-${MBEDTLS_VERSION} && make > build.log 2>&1 || (cat build.log && exit 1) -make install DESTDIR=$MBEDTLS_PREFIX && cd .. diff --git a/.travis/build-openssl-linux.sh b/.travis/build-openssl-linux.sh deleted file mode 100755 index 84f4aaeba04..00000000000 --- a/.travis/build-openssl-linux.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh - -if [ ! -f download-cache/openssl-${OPENSSL_VERSION}.tar.gz ]; then - wget -O download-cache/openssl-${OPENSSL_VERSION}.tar.gz https://www.openssl.org/source/openssl-${OPENSSL_VERSION}.tar.gz; -fi - -tar zxf download-cache/openssl-${OPENSSL_VERSION}.tar.gz -cd openssl-${OPENSSL_VERSION}/ -./config shared --prefix=$OPENSSL_PREFIX -DPURIFY > build.log 2>&1 || (cat build.log && exit 1) -make > build.log 2>&1 || (cat build.log && exit 1) -make install_sw > build.log 2>&1 || (cat build.log && exit 1) -cd .. diff --git a/.travis/build-openssl-osx.sh b/.travis/build-openssl-osx.sh deleted file mode 100755 index 61c80168ab9..00000000000 --- a/.travis/build-openssl-osx.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh - -if [ ! -f download-cache/openssl-${OPENSSL_VERSION}.tar.gz ]; then - wget -O download-cache/openssl-${OPENSSL_VERSION}.tar.gz https://www.openssl.org/source/openssl-${OPENSSL_VERSION}.tar.gz; -fi - -tar zxf download-cache/openssl-${OPENSSL_VERSION}.tar.gz -cd openssl-${OPENSSL_VERSION}/ -./Configure darwin64-x86_64-cc shared --prefix=$OPENSSL_PREFIX -DPURIFY > build.log 2>&1 || (cat build.log && exit 1) -make depend install > build.log 2>&1 || (cat build.log && exit 1) -cd .. From 8be20c210e3907209af08ede9f23d62b83665bd1 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Thu, 9 Mar 2017 11:47:35 +0100 Subject: [PATCH 495/643] Fix types in WIN32 socket_listen_accept() SOCKET_UNDEFINED is of type socket_descriptor_t (or SOCKET, in MS types), so new_sd should be too. Also, the return value of this function is always stored in a socket_descriptor_t variable, so it should return that type (which makes sense now, because it returns new_sd) instead of an int. Signed-off-by: Steffan Karger Acked-by: Arne Schwabe Message-Id: <1489056455-6004-1-git-send-email-steffan.karger@fox-it.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14239.html Signed-off-by: Gert Doering (cherry picked from commit 33e1a869fc6edb6bce5816b11dbecfaca57b20d4) --- src/openvpn/socket.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c index 82d0967d1a8..c1c0eaa0e03 100644 --- a/src/openvpn/socket.c +++ b/src/openvpn/socket.c @@ -1146,7 +1146,7 @@ tcp_connection_established(const struct link_socket_actual *act) gc_free(&gc); } -static int +static socket_descriptor_t socket_listen_accept(socket_descriptor_t sd, struct link_socket_actual *act, const char *remote_dynamic, @@ -1158,7 +1158,7 @@ socket_listen_accept(socket_descriptor_t sd, struct gc_arena gc = gc_new(); /* struct openvpn_sockaddr *remote = &act->dest; */ struct openvpn_sockaddr remote_verify = act->dest; - int new_sd = SOCKET_UNDEFINED; + socket_descriptor_t new_sd = SOCKET_UNDEFINED; CLEAR(*act); socket_do_listen(sd, local, do_listen, true); From 19d6cd4e63557c983cb0ab5094688c974588c2ff Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Thu, 9 Mar 2017 09:13:32 +0100 Subject: [PATCH 496/643] Remove duplicate X509 env variables Commit 13b585e8 added support for multiple X509 env variables with the same name, but as a side effect caused these variables to pile up for each renegotiation. The old code would simply overwrite the old variables (as long as an equally-long chain was used for the new session). To stop the variables from piling up, this commit removes any old X509 env variables if we start negotiating a new TLS session. Trac: #854 Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1489047212-31994-1-git-send-email-steffan@karger.me> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14237.html Signed-off-by: Gert Doering (cherry picked from commit fd0361813cd3d5a55f3408a018e2ed776d79fef6) --- src/openvpn/ssl.c | 3 +++ src/openvpn/ssl_verify.c | 17 +++++++++++++++++ src/openvpn/ssl_verify.h | 3 +++ 3 files changed, 23 insertions(+) diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index fe5ea940954..2d596aca226 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -2822,6 +2822,9 @@ tls_process(struct tls_multi *multi, session->opt->crl_file, session->opt->crl_file_inline); } + /* New connection, remove any old X509 env variables */ + tls_x509_clear_env(session->opt->es); + dmsg(D_TLS_DEBUG_MED, "STATE S_START"); } diff --git a/src/openvpn/ssl_verify.c b/src/openvpn/ssl_verify.c index 9f12ab8b273..a6e9be3a814 100644 --- a/src/openvpn/ssl_verify.c +++ b/src/openvpn/ssl_verify.c @@ -1486,4 +1486,21 @@ verify_final_auth_checks(struct tls_multi *multi, struct tls_session *session) gc_free(&gc); } } + +void +tls_x509_clear_env(struct env_set *es) +{ + struct env_item *item = es->list; + while (item) + { + struct env_item *next = item->next; + if (item->string + && 0 == strncmp("X509_", item->string, strlen("X509_"))) + { + env_set_del(es, item->string); + } + item = next; + } +} + #endif /* ENABLE_CRYPTO */ diff --git a/src/openvpn/ssl_verify.h b/src/openvpn/ssl_verify.h index ffab2189ba9..d91799e113e 100644 --- a/src/openvpn/ssl_verify.h +++ b/src/openvpn/ssl_verify.h @@ -238,6 +238,9 @@ tls_client_reason(struct tls_multi *multi) #endif } +/** Remove any X509_ env variables from env_set es */ +void tls_x509_clear_env(struct env_set *es); + #endif /* ENABLE_CRYPTO */ #endif /* SSL_VERIFY_H_ */ From 3fa863100033e7d6d0cbb19361a52efbe097e69d Mon Sep 17 00:00:00 2001 From: Eric Thorpe Date: Thu, 16 Mar 2017 09:40:31 +1100 Subject: [PATCH 497/643] Fix Building Using MSVC This patch enables the building of OpenVPN for the 2.4 and master branches using MSVC (Visual Studio 2013 / MSVC v120), which currently doesn't work with 2.4 or a clone of master. 2013 is being used as it reduces the complexity of the redistributable requirements and has mostly complete C99 support. Further changes will be necessary for 2015 support when the switch is made. Note the changes to config-msvc-version.h.in are more of a work around. It was a simpler approach when compared to modifying msvc-generate.js to handle m4 syntax, and so it may be dropped if there is an intention to update the javascript generator. Signed-off by: Eric Thorpe Acked-by: Gert Doering Message-Id: URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14268.html Signed-off-by: Gert Doering (cherry picked from commit 5ab106db7b091c6409fd0a7e43f557a7931c200f) --- config-msvc-version.h.in | 8 ++++++-- config-msvc.h | 1 + src/openvpn/openvpn.vcxproj | 7 +++++++ src/openvpn/openvpn.vcxproj.filters | 26 +++++++++++++++++++++++++- 4 files changed, 39 insertions(+), 3 deletions(-) diff --git a/config-msvc-version.h.in b/config-msvc-version.h.in index 4bc89e7b41d..7977cb84ec7 100644 --- a/config-msvc-version.h.in +++ b/config-msvc-version.h.in @@ -1,8 +1,12 @@ #define PACKAGE_NAME "@PRODUCT_NAME@" -#define PACKAGE_STRING "@PRODUCT_NAME@ @PRODUCT_VERSION@" +#define PACKAGE_STRING "@PRODUCT_NAME@ @PRODUCT_VERSION_MAJOR@.@PRODUCT_VERSION_MINOR@@PRODUCT_VERSION_PATCH@" #define PACKAGE_TARNAME "@PRODUCT_TARNAME@" #define PACKAGE "@PRODUCT_TARNAME@" -#define PACKAGE_VERSION "@PRODUCT_VERSION@" +#define PRODUCT_VERSION_MAJOR "@PRODUCT_VERSION_MAJOR@" +#define PRODUCT_VERSION_MINOR "@PRODUCT_VERSION_MINOR@" +#define PRODUCT_VERSION_PATCH "@PRODUCT_VERSION_PATCH@" +#define PACKAGE_VERSION "@PRODUCT_VERSION_MAJOR@.@PRODUCT_VERSION_MINOR@.@PRODUCT_VERSION_PATCH@" +#define PRODUCT_VERSION "@PRODUCT_VERSION_MAJOR@.@PRODUCT_VERSION_MINOR@.@PRODUCT_VERSION_PATCH@" #define PRODUCT_BUGREPORT "@PRODUCT_BUGREPORT@" #define OPENVPN_VERSION_RESOURCE @PRODUCT_VERSION_RESOURCE@ #define TAP_WIN_COMPONENT_ID "@PRODUCT_TAP_WIN_COMPONENT_ID@" diff --git a/config-msvc.h b/config-msvc.h index 3e71c854077..9b97e7121f6 100644 --- a/config-msvc.h +++ b/config-msvc.h @@ -126,6 +126,7 @@ typedef __int64 int64_t; typedef __int32 int32_t; typedef __int16 int16_t; typedef __int8 int8_t; +typedef uint16_t in_port_t; #ifdef HAVE_CONFIG_MSVC_LOCAL_H #include diff --git a/src/openvpn/openvpn.vcxproj b/src/openvpn/openvpn.vcxproj index 8dfbea520a9..d1c0fdec2a9 100644 --- a/src/openvpn/openvpn.vcxproj +++ b/src/openvpn/openvpn.vcxproj @@ -99,13 +99,16 @@ + + + @@ -164,12 +167,15 @@ + + + @@ -249,6 +255,7 @@ + diff --git a/src/openvpn/openvpn.vcxproj.filters b/src/openvpn/openvpn.vcxproj.filters index 8b6a2696204..30df5ec299f 100644 --- a/src/openvpn/openvpn.vcxproj.filters +++ b/src/openvpn/openvpn.vcxproj.filters @@ -216,6 +216,18 @@ Source Files + + Source Files + + + Source Files + + + Source Files + + + Source Files + @@ -464,10 +476,22 @@ Header Files + + Header Files + + + Header Files + + + Header Files + + + Header Files + Resource Files - + \ No newline at end of file From 633138564d611b5abeff232c89dccb1b86def449 Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Thu, 16 Mar 2017 16:21:17 +0800 Subject: [PATCH 498/643] CRL: use time_t instead of struct timespec to store last mtime As of now, we store the last mtime for the CRL file in a timespec object. However we store seconds only and we ignore the subsecond field (this came into being because not all platforms have nanoseconds precision in timespec). Given the above, we can safely replace the timespec object with a simple time_t. Reported-by: Gert Doering Signed-off-by: Antonio Quartulli Acked-by: Gert Doering Message-Id: <20170316082117.21020-1-a@unstable.cc> URL: http://www.mail-archive.com/search?l=mid&q=20170316082117.21020-1-a@unstable.cc Signed-off-by: Gert Doering (cherry picked from commit f3705dd1e711ee9f8546b841e4b18e9e9a224975) --- src/openvpn/ssl.c | 4 ++-- src/openvpn/ssl_mbedtls.h | 2 +- src/openvpn/ssl_openssl.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 2d596aca226..1033e581ea1 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -571,12 +571,12 @@ tls_ctx_reload_crl(struct tls_root_ctx *ssl_ctx, const char *crl_file, * Note: Windows does not support tv_nsec. */ if ((ssl_ctx->crl_last_size == crl_stat.st_size) - && (ssl_ctx->crl_last_mtime.tv_sec == crl_stat.st_mtime)) + && (ssl_ctx->crl_last_mtime == crl_stat.st_mtime)) { return; } - ssl_ctx->crl_last_mtime.tv_sec = crl_stat.st_mtime; + ssl_ctx->crl_last_mtime = crl_stat.st_mtime; ssl_ctx->crl_last_size = crl_stat.st_size; backend_tls_ctx_reload_crl(ssl_ctx, crl_file, crl_file_inline); } diff --git a/src/openvpn/ssl_mbedtls.h b/src/openvpn/ssl_mbedtls.h index 1bc53ce8e26..d8f717ce1bd 100644 --- a/src/openvpn/ssl_mbedtls.h +++ b/src/openvpn/ssl_mbedtls.h @@ -74,7 +74,7 @@ struct tls_root_ctx { mbedtls_x509_crt *ca_chain; /**< CA chain for remote verification */ mbedtls_pk_context *priv_key; /**< Local private key */ mbedtls_x509_crl *crl; /**< Certificate Revocation List */ - struct timespec crl_last_mtime; /**< CRL last modification time */ + time_t crl_last_mtime; /**< CRL last modification time */ off_t crl_last_size; /**< size of last loaded CRL */ #if defined(ENABLE_PKCS11) mbedtls_pkcs11_context *priv_key_pkcs11; /**< PKCS11 private key */ diff --git a/src/openvpn/ssl_openssl.h b/src/openvpn/ssl_openssl.h index c64c65f8122..6ca4cb6de43 100644 --- a/src/openvpn/ssl_openssl.h +++ b/src/openvpn/ssl_openssl.h @@ -49,7 +49,7 @@ */ struct tls_root_ctx { SSL_CTX *ctx; - struct timespec crl_last_mtime; + time_t crl_last_mtime; off_t crl_last_size; }; From ce40258ddd0170df60633baab2c3d17f2c104671 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Thu, 16 Mar 2017 10:12:17 +0100 Subject: [PATCH 499/643] Fix non-C99-compliant builds: don't use const size_t as array length Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1489655537-19164-1-git-send-email-steffan@karger.me> URL: http://www.mail-archive.com/search?l=mid&q=1489655537-19164-1-git-send-email-steffan@karger.me Signed-off-by: Gert Doering (cherry picked from commit db1b4d96bfe7e744a0dec8f86cb041c32fb87964) --- src/openvpn/crypto_openssl.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/openvpn/crypto_openssl.c b/src/openvpn/crypto_openssl.c index 5549d708345..881a2d1342b 100644 --- a/src/openvpn/crypto_openssl.c +++ b/src/openvpn/crypto_openssl.c @@ -286,8 +286,7 @@ show_available_ciphers() size_t i; /* If we ever exceed this, we must be more selective */ - const size_t cipher_list_len = 1000; - const EVP_CIPHER *cipher_list[cipher_list_len]; + const EVP_CIPHER *cipher_list[1000]; size_t num_ciphers = 0; #ifndef ENABLE_SMALL printf("The following ciphers and cipher modes are available for use\n" @@ -312,7 +311,7 @@ show_available_ciphers() { cipher_list[num_ciphers++] = cipher; } - if (num_ciphers == cipher_list_len) + if (num_ciphers == (sizeof(cipher_list)/sizeof(*cipher_list))) { msg(M_WARN, "WARNING: Too many ciphers, not showing all"); break; From 57637d0f677d824dacdc83d858357ccc80723f45 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sat, 4 Mar 2017 19:49:57 +0100 Subject: [PATCH 500/643] Deprecate --ns-cert-type The nsCertType x509 extension is very old, and barely used. We already have had an alternative for a long time: --remote-cert-tls uses the far more common keyUsage and extendedKeyUsage extensions instead. OpenSSL 1.1 longer exposes an API to (separately) check the nsCertType x509 extension. Since we want be able to migrate to OpenSSL 1.1, we should deprecate this option immediately. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1488653397-2309-1-git-send-email-steffan@karger.me> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14222.html Signed-off-by: Gert Doering (cherry picked from commit 2dc332266449d5378f1fe04f950cbebf128ec9c9) --- Changes.rst | 13 +++++++++++-- doc/openvpn.8 | 8 ++++++-- src/openvpn/init.c | 4 ++++ src/openvpn/options.c | 4 ++-- tests/t_client.rc-sample | 2 +- 5 files changed, 24 insertions(+), 7 deletions(-) diff --git a/Changes.rst b/Changes.rst index 7ffd89e0e4a..0af29e3271d 100644 --- a/Changes.rst +++ b/Changes.rst @@ -1,5 +1,5 @@ -Version 2.4.0 -============= +Overview of changes in 2.4 +========================== New features @@ -302,3 +302,12 @@ Maintainer-visible changes header combinations. In most of these situations it is recommended to use -std=gnu99 in CFLAGS. This is known to be needed when doing i386/i686 builds on RHEL5. + + +Version 2.4.1 +============= + - ``--ns-cert-type`` is deprecated. Use ``--remote-cert-tls`` instead. + The nsCertType x509 extension is very old, and barely used. + ``--remote-cert-tls`` uses the far more common keyUsage and extendedKeyUsage + extension instead. Make sure your certificates carry these to be able to + use ``--remote-cert-tls``. diff --git a/doc/openvpn.8 b/doc/openvpn.8 index e3d603e12e4..f6822ec713b 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -327,7 +327,7 @@ http\-proxy 192.168.0.8 8080 persist\-key persist\-tun pkcs12 client.p12 -ns\-cert\-type server +remote\-cert\-tls server verb 3 .in -4 .ft @@ -5313,7 +5313,11 @@ as X509__=. Multiple options can be defined to track multiple attributes. .\"********************************************************* .TP -.B \-\-ns\-cert\-type client|server +.B \-\-ns\-cert\-type client|server (DEPRECATED) +This option is deprecated. Use the more modern equivalent +.B \-\-remote\-cert\-tls +instead. This option will be removed in OpenVPN 2.5. + Require that peer certificate was signed with an explicit .B nsCertType designation of "client" or "server". diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 8f9578d09ac..c7e6fd1ae11 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -3004,6 +3004,10 @@ do_option_warnings(struct context *c) { msg(M_WARN, "WARNING: No server certificate verification method has been enabled. See http://openvpn.net/howto.html#mitm for more info."); } + if (o->ns_cert_type) + { + msg(M_WARN, "WARNING: --ns-cert-type is DEPRECATED. Use --remote-cert-tls instead."); + } #endif /* ifdef ENABLE_CRYPTO */ /* If a script is used, print appropiate warnings */ diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 6682bb76b11..a104bb07544 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -636,8 +636,8 @@ static const char usage_message[] = "--verify-x509-name name: Accept connections only from a host with X509 subject\n" " DN name. The remote host must also pass all other tests\n" " of verification.\n" - "--ns-cert-type t: Require that peer certificate was signed with an explicit\n" - " nsCertType designation t = 'client' | 'server'.\n" + "--ns-cert-type t: (DEPRECATED) Require that peer certificate was signed with \n" + " an explicit nsCertType designation t = 'client' | 'server'.\n" "--x509-track x : Save peer X509 attribute x in environment for use by\n" " plugins and management interface.\n" #if defined(ENABLE_CRYPTO_OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x10001000 diff --git a/tests/t_client.rc-sample b/tests/t_client.rc-sample index 4fdea487658..355e8bb8afe 100644 --- a/tests/t_client.rc-sample +++ b/tests/t_client.rc-sample @@ -40,7 +40,7 @@ TEST_RUN_LIST="1 2" # OPENVPN_BASE_P2MP="--client --ca $CA_CERT \ --cert $CLIENT_CERT --key $CLIENT_KEY \ - --ns-cert-type server --nobind --comp-lzo --verb 3" + --remote-cert-tls server --nobind --comp-lzo --verb 3" # base config for p2p tests # From 60b23236329e6921729f51e7689042a29c794a6b Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Wed, 15 Mar 2017 22:20:20 +0100 Subject: [PATCH 501/643] Be less picky about keyUsage extensions We long recommended users to use --ns-cert-type to distinguish between client and server certificates, but that extension is long deprecated and now can even no longer be accurately checked in OpenSSL 1.1+. We support a more modern alternative, --remote-cert-tls (which expands to --remote-cert-ku + --remote-cert-eku), but are overly strict in checking the keyUsage. This patch makes our implementation less picky, so that correct-but-slightly-weird certicates will not immediately be rejected. We currently allow users to specify a list of allowed keyUsage values, and require that the remote certificate matches one of these values exactly. This is for more strict than keyUsage usually requires; which is that a certificate is okay to use if it can *at least* be used for our intended purpose. This patch changes the behaviour to match that, by using the library-provided mbedtls_x509_crt_check_key_usage() function in mbed TLS builds, and performing the 'at least bits xyz' check for OpenSSL builds (OpenSSL unfortunately does not expose a similar function). Furthermore, this patch adds better error messages when the checking fails; it now explains that is expects to match either of the supplied values, and only does so if the check actually failed. This patch also changes --remote-cert-tls to still require a specific EKU, but only *some* keyUsage value. Both our supported crypto libraries will check the keyUsage value for correctness during the handshake, but only if it is present. So this still enforces a correct keyUsage, but is a bit less picky about certificates that do not exactly match expectations. This patch should be applied together with the 'deprecate --ns-cert-type' patch I sent earlier. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1489612820-15284-1-git-send-email-steffan@karger.me> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14265.html Signed-off-by: Gert Doering (cherry picked from commit 92a5b9fb76cbb7f43a6aa86994ff559f06c55c7a) --- Changes.rst | 7 ++++ doc/openvpn.8 | 33 +++++++++------ src/openvpn/options.c | 15 +++---- src/openvpn/ssl_verify.h | 3 ++ src/openvpn/ssl_verify_mbedtls.c | 42 ++++++++++++------- src/openvpn/ssl_verify_openssl.c | 72 +++++++++++++++++--------------- 6 files changed, 102 insertions(+), 70 deletions(-) diff --git a/Changes.rst b/Changes.rst index 0af29e3271d..2a94990e5e1 100644 --- a/Changes.rst +++ b/Changes.rst @@ -306,6 +306,13 @@ Maintainer-visible changes Version 2.4.1 ============= + - ``--remote-cert-ku`` now only requires the certificate to have at least the + bits set of one of the values in the supplied list, instead of requiring an + exact match to one of the values in the list. + - ``--remote-cert-tls`` now only requires that a keyUsage is present in the + certificate, and leaves the verification of the value up to the crypto + library, which has more information (i.e. the key exchange method in use) + to verify that the keyUsage is correct. - ``--ns-cert-type`` is deprecated. Use ``--remote-cert-tls`` instead. The nsCertType x509 extension is very old, and barely used. ``--remote-cert-tls`` uses the far more common keyUsage and extendedKeyUsage diff --git a/doc/openvpn.8 b/doc/openvpn.8 index f6822ec713b..89229fb0016 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -5344,15 +5344,25 @@ or .B \-\-tls\-verify. .\"********************************************************* .TP -.B \-\-remote\-cert\-ku v... +.B \-\-remote\-cert\-ku [v...] Require that peer certificate was signed with an explicit .B key usage. -This is a useful security option for clients, to ensure that -the host they connect to is a designated server. +If present in the certificate, the keyUsage value is validated by the TLS +library during the TLS handshake. Specifying this option without arguments +requires this extension to be present (so the TLS library will verify it). -The key usage should be encoded in hex, more than one key -usage can be specified. +If the list +.B v... +is also supplied, the keyUsage field must have +.B at least +the same bits set as the bits in +.B one of +the values supplied in the list +.B v... + +The key usage values in the list must be encoded in hex, e.g. +"\-\-remote\-cert\-ku a0" .\"********************************************************* .TP .B \-\-remote\-cert\-eku oid @@ -5373,24 +5383,21 @@ and .B extended key usage based on RFC3280 TLS rules. -This is a useful security option for clients, to ensure that -the host they connect to is a designated server. +This is a useful security option for clients, to ensure that the host they +connect to is a designated server. Or the other way around; for a server to +verify that only hosts with a client certificate can connect. The .B \-\-remote\-cert\-tls client option is equivalent to .B -\-\-remote\-cert\-ku 80 08 88 \-\-remote\-cert\-eku "TLS Web Client Authentication" - -The key usage is digitalSignature and/or keyAgreement. +\-\-remote\-cert\-ku \-\-remote\-cert\-eku "TLS Web Client Authentication" The .B \-\-remote\-cert\-tls server option is equivalent to .B -\-\-remote\-cert\-ku a0 88 \-\-remote\-cert\-eku "TLS Web Server Authentication" - -The key usage is digitalSignature and ( keyEncipherment or keyAgreement ). +\-\-remote\-cert\-ku \-\-remote\-cert\-eku "TLS Web Server Authentication" This is an important security precaution to protect against a man-in-the-middle attack where an authorized client diff --git a/src/openvpn/options.c b/src/openvpn/options.c index a104bb07544..9fef3945175 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -7930,14 +7930,18 @@ add_option(struct options *options, } else if (streq(p[0], "remote-cert-ku")) { - int j; - VERIFY_PERMISSION(OPT_P_GENERAL); + size_t j; for (j = 1; j < MAX_PARMS && p[j] != NULL; ++j) { sscanf(p[j], "%x", &(options->remote_cert_ku[j-1])); } + if (j == 1) + { + /* No specific KU required, but require KU to be present */ + options->remote_cert_ku[0] = OPENVPN_KU_REQUIRED; + } } else if (streq(p[0], "remote-cert-eku") && p[1] && !p[2]) { @@ -7950,15 +7954,12 @@ add_option(struct options *options, if (streq(p[1], "server")) { - options->remote_cert_ku[0] = 0xa0; - options->remote_cert_ku[1] = 0x88; + options->remote_cert_ku[0] = OPENVPN_KU_REQUIRED; options->remote_cert_eku = "TLS Web Server Authentication"; } else if (streq(p[1], "client")) { - options->remote_cert_ku[0] = 0x80; - options->remote_cert_ku[1] = 0x08; - options->remote_cert_ku[2] = 0x88; + options->remote_cert_ku[0] = OPENVPN_KU_REQUIRED; options->remote_cert_eku = "TLS Web Client Authentication"; } else diff --git a/src/openvpn/ssl_verify.h b/src/openvpn/ssl_verify.h index d91799e113e..278c5cbeac0 100644 --- a/src/openvpn/ssl_verify.h +++ b/src/openvpn/ssl_verify.h @@ -218,6 +218,9 @@ struct x509_track /** Do not perform Netscape certificate type verification */ #define NS_CERT_CHECK_CLIENT (1<<1) +/** Require keyUsage to be present in cert (0xFFFF is an invalid KU value) */ +#define OPENVPN_KU_REQUIRED (0xFFFF) + /* * TODO: document */ diff --git a/src/openvpn/ssl_verify_mbedtls.c b/src/openvpn/ssl_verify_mbedtls.c index 4068dd30eaa..c32e48154e3 100644 --- a/src/openvpn/ssl_verify_mbedtls.c +++ b/src/openvpn/ssl_verify_mbedtls.c @@ -437,32 +437,42 @@ result_t x509_verify_cert_ku(mbedtls_x509_crt *cert, const unsigned *const expected_ku, int expected_len) { - result_t fFound = FAILURE; + msg(D_HANDSHAKE, "Validating certificate key usage"); if (!(cert->ext_types & MBEDTLS_X509_EXT_KEY_USAGE)) { - msg(D_HANDSHAKE, "Certificate does not have key usage extension"); + msg(D_TLS_ERRORS, + "ERROR: Certificate does not have key usage extension"); + return FAILURE; } - else + + if (expected_ku[0] == OPENVPN_KU_REQUIRED) { - int i; - unsigned nku = cert->key_usage; + /* Extension required, value checked by TLS library */ + return SUCCESS; + } - msg(D_HANDSHAKE, "Validating certificate key usage"); - for (i = 0; SUCCESS != fFound && ikey_usage); + for (size_t i = 0; i < expected_len && expected_ku[i]; i++) + { + msg(D_TLS_ERRORS, " * %04x", expected_ku[i]); } } + return fFound; } diff --git a/src/openvpn/ssl_verify_openssl.c b/src/openvpn/ssl_verify_openssl.c index 5c2c5b75208..5624daac59e 100644 --- a/src/openvpn/ssl_verify_openssl.c +++ b/src/openvpn/ssl_verify_openssl.c @@ -590,55 +590,59 @@ result_t x509_verify_cert_ku(X509 *x509, const unsigned *const expected_ku, int expected_len) { - ASN1_BIT_STRING *ku = NULL; - result_t fFound = FAILURE; + ASN1_BIT_STRING *ku = X509_get_ext_d2i(x509, NID_key_usage, NULL, NULL); - if ((ku = (ASN1_BIT_STRING *) X509_get_ext_d2i(x509, NID_key_usage, NULL, - NULL)) == NULL) + if (ku == NULL) { - msg(D_HANDSHAKE, "Certificate does not have key usage extension"); + msg(D_TLS_ERRORS, "Certificate does not have key usage extension"); + return FAILURE; } - else + + if (expected_ku[0] == OPENVPN_KU_REQUIRED) { - unsigned nku = 0; - int i; - for (i = 0; i < 8; i++) - { - if (ASN1_BIT_STRING_get_bit(ku, i)) - { - nku |= 1 << (7 - i); - } - } + /* Extension required, value checked by TLS library */ + return SUCCESS; + } - /* - * Fixup if no LSB bits - */ - if ((nku & 0xff) == 0) + unsigned nku = 0; + for (size_t i = 0; i < 8; i++) + { + if (ASN1_BIT_STRING_get_bit(ku, i)) { - nku >>= 8; + nku |= 1 << (7 - i); } + } - msg(D_HANDSHAKE, "Validating certificate key usage"); - for (i = 0; fFound != SUCCESS && i < expected_len; i++) - { - if (expected_ku[i] != 0) - { - msg(D_HANDSHAKE, "++ Certificate has key usage %04x, expects " - "%04x", nku, expected_ku[i]); + /* + * Fixup if no LSB bits + */ + if ((nku & 0xff) == 0) + { + nku >>= 8; + } - if (nku == expected_ku[i]) - { - fFound = SUCCESS; - } - } + msg(D_HANDSHAKE, "Validating certificate key usage"); + result_t fFound = FAILURE; + for (size_t i = 0; fFound != SUCCESS && i < expected_len; i++) + { + if (expected_ku[i] != 0 && (nku & expected_ku[i]) == expected_ku[i]) + { + fFound = SUCCESS; } } - if (ku != NULL) + if (fFound != SUCCESS) { - ASN1_BIT_STRING_free(ku); + msg(D_TLS_ERRORS, + "ERROR: Certificate has key usage %04x, expected one of:", nku); + for (size_t i = 0; i < expected_len && expected_ku[i]; i++) + { + msg(D_TLS_ERRORS, " * %04x", expected_ku[i]); + } } + ASN1_BIT_STRING_free(ku); + return fFound; } From d21bed998bca21ab44e769896b0e9a8b4bfc0be1 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Fri, 27 Jan 2017 15:21:20 +0100 Subject: [PATCH 502/643] plugin: Improve the handling of default plug-in directory OpenVPN uses a default plug-in directore, set using PLUGINDIR when running ./configure. If this is set, it will use $LIBDIR/openvpn/plugin. When using --plugin, OpenVPN will load plug-ins from this directory with the only exception if the plug-in filename is based on an absolute path. Any other relative paths are relative to the PLUGINDIR. This patch adds a third variant, using plug-in paths starting with '.' In this case, OpenVPN will use the relative directory of where OpenVPN was started, or the directory OpenVPN have changed into due to --cd being used before the actual --plugin option. Signed-off-by: David Sommerseth Acked-by: Gert Doering Message-Id: <20170127142120.10492-1-davids@openvpn.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13970.html Signed-off-by: Gert Doering (cherry picked from commit f9609f1df9d8c070245b7c008dc54ac9ccdbe231) --- doc/openvpn.8 | 28 ++++++++++++++++++++++++++++ src/openvpn/plugin.c | 18 +++++++++++++++++- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 89229fb0016..f29b72f427f 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -2712,6 +2712,34 @@ to the module initialization function. Multiple plugin modules may be loaded into one OpenVPN process. +The +.B module-pathname +argument can be just a filename or a filename with a relative +or absolute path. The format of the filename and path defines +if the plug-in will be loaded from a default plug-in directory +or outside this directory. + +.nf +.ft 3 +.in +4 +.B \-\-plugin path\ \ \ \ \ \ \ \ Effective directory used +==================================================== + myplug.so DEFAULT_DIR/myplug.so + subdir/myplug.so DEFAULT_DIR/subdir/myplug.so + ./subdir/myplug.so CWD/subdir/myplug.so + /usr/lib/my/plug.so /usr/lib/my/plug.so +.in -4 +.fi + +DEFAULT_DIR is replaced by the default plug-in directory, +which is configured at the build time of OpenVPN. CWD is the +current directory where OpenVPN was started or the directory +OpenVPN have swithed into via the +.B\-\-cd +option before the +.B\-\-plugin +option. + For more information and examples on how to build OpenVPN plug-in modules, see the README file in the .B plugin diff --git a/src/openvpn/plugin.c b/src/openvpn/plugin.c index f77702786f4..05cbae3eff9 100644 --- a/src/openvpn/plugin.c +++ b/src/openvpn/plugin.c @@ -235,7 +235,23 @@ plugin_init_item(struct plugin *p, const struct plugin_option *o) p->handle = NULL; - if (!absolute_pathname(p->so_pathname)) + /* If the plug-in filename is not an absolute path, + * or beginning with '.', it should use the PLUGIN_LIBDIR + * as the base directory for loading the plug-in. + * + * This means the following scenarios are loaded from these places: + * --plugin fancyplug.so -> $PLUGIN_LIBDIR/fancyplug.so + * --plugin my/fancyplug.so -> $PLUGIN_LIBDIR/my/fancyplug.so + * --plugin ./fancyplug.so -> $CWD/fancyplug.so + * --plugin /usr/lib/my/fancyplug.so -> /usr/lib/my/fancyplug.so + * + * Please note that $CWD means the directory OpenVPN is either started from + * or the directory OpenVPN have changed into using --cd before --plugin + * was parsed. + * + */ + if (!absolute_pathname(p->so_pathname) + && p->so_pathname[0] != '.') { char full[PATH_MAX]; From 0dc790818876dac6e1cf1a82eda8ea15a538a333 Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Mon, 30 Jan 2017 23:26:58 +0800 Subject: [PATCH 503/643] ignore remote-random-hostname if a numeric host is provided Although it does not make sense to specify remote-random-hostname when a numeric hostname is provided (being it the remote, the http proxy or the socks server), this is still a valid configuration. For this reason, this combination should still work as expected, which means ignoring the randomization and directly using the numeric IP. Signed-off-by: Antonio Quartulli Acked-by: Gert Doering Message-Id: <20170130152658.15786-1-a@unstable.cc> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13993.html Signed-off-by: Gert Doering (cherry picked from commit 3c748aeb5e4b82c449e7de28846a3915ab45aeec) --- src/openvpn/socket.c | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c index c1c0eaa0e03..7d3dd60cb45 100644 --- a/src/openvpn/socket.c +++ b/src/openvpn/socket.c @@ -338,20 +338,6 @@ openvpn_getaddrinfo(unsigned int flags, ASSERT(hostname || servname); ASSERT(!(flags & GETADDR_HOST_ORDER)); - if (hostname && (flags & GETADDR_RANDOMIZE)) - { - hostname = hostname_randomize(hostname, &gc); - } - - if (hostname) - { - print_hostname = hostname; - } - else - { - print_hostname = "undefined"; - } - if (servname) { print_servname = servname; @@ -402,6 +388,20 @@ openvpn_getaddrinfo(unsigned int flags, const char *fmt; int level = 0; + if (hostname && (flags & GETADDR_RANDOMIZE)) + { + hostname = hostname_randomize(hostname, &gc); + } + + if (hostname) + { + print_hostname = hostname; + } + else + { + print_hostname = "undefined"; + } + fmt = "RESOLVE: Cannot resolve host address: %s:%s (%s)"; if ((flags & GETADDR_MENTION_RESOLVE_RETRY) && !resolve_retry_seconds) @@ -512,6 +512,10 @@ openvpn_getaddrinfo(unsigned int flags, else { /* IP address parse succeeded */ + if (flags & GETADDR_RANDOMIZE) + { + msg(M_WARN, "WARNING: ignoring --remote-random-hostname because the hostname is an IP address"); + } } done: From 860d79bc4eadd934390829bee0de37e5ded8907a Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Sat, 25 Feb 2017 03:02:29 +0100 Subject: [PATCH 504/643] cleanup: Remove faulty env processing functions The env_set_add_to_environmenti() and env_set_remove_from_environment() functions where not used in the code at all and they would cause an ASSERT() in setenv_str_ex() later on, as it would not allow the struct env_set *es pointer to be NULL (misc.c:807). Signed-off-by: David Sommerseth Acked-by: Gert Doering Message-Id: <20170225020229.17287-1-davids@openvpn.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14195.html Signed-off-by: Gert Doering (cherry picked from commit a87f119afcfcc1c855a6ea2ba3d765966f1f2591) --- src/openvpn/misc.c | 51 ---------------------------------------------- src/openvpn/misc.h | 4 ---- 2 files changed, 55 deletions(-) diff --git a/src/openvpn/misc.c b/src/openvpn/misc.c index a2f45b61c1a..68d06876759 100644 --- a/src/openvpn/misc.c +++ b/src/openvpn/misc.c @@ -701,57 +701,6 @@ env_set_inherit(struct env_set *es, const struct env_set *src) } } -void -env_set_add_to_environment(const struct env_set *es) -{ - if (es) - { - struct gc_arena gc = gc_new(); - const struct env_item *e; - - e = es->list; - - while (e) - { - const char *name; - const char *value; - - if (deconstruct_name_value(e->string, &name, &value, &gc)) - { - setenv_str(NULL, name, value); - } - - e = e->next; - } - gc_free(&gc); - } -} - -void -env_set_remove_from_environment(const struct env_set *es) -{ - if (es) - { - struct gc_arena gc = gc_new(); - const struct env_item *e; - - e = es->list; - - while (e) - { - const char *name; - const char *value; - - if (deconstruct_name_value(e->string, &name, &value, &gc)) - { - setenv_del(NULL, name); - } - - e = e->next; - } - gc_free(&gc); - } -} /* add/modify/delete environmental strings */ diff --git a/src/openvpn/misc.h b/src/openvpn/misc.h index 16be6219cee..009767fdcb4 100644 --- a/src/openvpn/misc.h +++ b/src/openvpn/misc.h @@ -161,10 +161,6 @@ void env_set_print(int msglevel, const struct env_set *es); void env_set_inherit(struct env_set *es, const struct env_set *src); -void env_set_add_to_environment(const struct env_set *es); - -void env_set_remove_from_environment(const struct env_set *es); - /* Make arrays of strings */ const char **make_env_array(const struct env_set *es, From 46e65494194f0bba0c63be8360b56ed595949720 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Sun, 19 Mar 2017 20:10:49 +0100 Subject: [PATCH 505/643] Fix installation of IPv6 host route to VPN server when using iservice. The "prepare IPv6 route message to interactive service" was properly handing the correct interface index (r->adapter_index) for this case, but then always overwrote the gateway address with our magic tun/tap fe80::8 value. Only do this for "on tap adapter" routes. Pinpointed by Selva Nair. Trac #850 Signed-off-by: Gert Doering Acked-by: Selva Nair Message-Id: <20170319191049.23970-1-gert@greenie.muc.de> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14282.html Signed-off-by: Gert Doering (cherry picked from commit 27740b376c1ca89a43dcff5c8309f1e1afecc5c9) --- src/openvpn/route.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/openvpn/route.c b/src/openvpn/route.c index 7e536effeb9..08998d5f4df 100644 --- a/src/openvpn/route.c +++ b/src/openvpn/route.c @@ -3061,8 +3061,10 @@ do_route_ipv6_service(const bool add, const struct route_ipv6 *r, const struct t /* In TUN mode we use a special link-local address as the next hop. * The tapdrvr knows about it and will answer neighbor discovery packets. + * (only do this for routes actually using the tun/tap device) */ - if (tt->type == DEV_TYPE_TUN) + if (tt->type == DEV_TYPE_TUN + && msg.iface.index == tt->adapter_index ) { inet_pton(AF_INET6, "fe80::8", &msg.gateway.ipv6); } From 037669f3dd05d725d34f43e85eb2aad5f18ec90c Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Sun, 19 Mar 2017 19:41:35 +0100 Subject: [PATCH 506/643] Make ENABLE_OCC no longer depend on !ENABLE_SMALL OCC is useful functionality which (according to LEDE devs) adds only about 3k to the binary size - and if the embedded router folks can afford this trade-off, everyone else can :-) Inspired by https://git.lede-project.org/?p=source.git;a=commit;h=b613c96d94bcdcda7abb3 be68ea1c281ce5fbb47 Signed-off-by: Gert Doering Acked-by: Steffan Karger Message-Id: <20170319184135.23548-1-gert@greenie.muc.de> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14281.html Signed-off-by: Gert Doering (cherry picked from commit 363af65178b8bbb482df958d6570c8763aee5d1d) --- src/openvpn/syshead.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/openvpn/syshead.h b/src/openvpn/syshead.h index a1b60476b8c..f4458648ed0 100644 --- a/src/openvpn/syshead.h +++ b/src/openvpn/syshead.h @@ -589,9 +589,7 @@ socket_defined(const socket_descriptor_t sd) /* * Should we include OCC (options consistency check) code? */ -#ifndef ENABLE_SMALL #define ENABLE_OCC -#endif /* * Should we include NTLM proxy functionality From bb9d4c91c95f245dea87735e4e05661e04931b33 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Tue, 21 Mar 2017 20:46:16 +0100 Subject: [PATCH 507/643] Preparing for release v2.4.1 (ChangeLog, version.m4) Signed-off-by: Gert Doering --- ChangeLog | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ version.m4 | 4 +-- 2 files changed, 75 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9ecf4f0a081..450e0f53da5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,79 @@ OpenVPN Change Log Copyright (C) 2002-2017 OpenVPN Technologies, Inc. +2017.03.21 -- Version 2.4.1 +Antonio Quartulli (4): + attempt to add IPv6 route even when no IPv6 address was configured + fix redirect-gateway behaviour when an IPv4 default route does not exist + CRL: use time_t instead of struct timespec to store last mtime + ignore remote-random-hostname if a numeric host is provided + +Christian Hesse (7): + man: fix formatting for alternative option + systemd: Use automake tools to install unit files + systemd: Do not race on RuntimeDirectory + systemd: Add more security feature for systemd units + Clean up plugin path handling + plugin: Remove GNUism in openvpn-plugin.h generation + fix typo in notification message + +David Sommerseth (6): + management: >REMOTE operation would overwrite ce change indicator + management: Remove a redundant #ifdef block + git: Merge .gitignore files into a single file + systemd: Move the READY=1 signalling to an earlier point + plugin: Improve the handling of default plug-in directory + cleanup: Remove faulty env processing functions + +Emmanuel Deloget (8): + OpenSSL: check for the SSL reason, not the full error + OpenSSL: don't use direct access to the internal of X509_STORE_CTX + OpenSSL: don't use direct access to the internal of SSL_CTX + OpenSSL: don't use direct access to the internal of X509_STORE + OpenSSL: don't use direct access to the internal of X509_OBJECT + OpenSSL: don't use direct access to the internal of RSA_METHOD + OpenSSL: SSLeay symbols are no longer available in OpenSSL 1.1 + OpenSSL: use EVP_CipherInit_ex() instead of EVP_CipherInit() + +Eric Thorpe (1): + Fix Building Using MSVC + +Gert Doering (4): + Add openssl_compat.h to openvpn_SOURCES + Fix '--dev null' + Fix installation of IPv6 host route to VPN server when using iservice. + Make ENABLE_OCC no longer depend on !ENABLE_SMALL + +Gisle Vanem (1): + Crash in options.c + +Ilya Shipitsin (2): + Resolve several travis-ci issues + travis-ci: remove unused files + +Olivier Wahrenberger (1): + Fix building with LibreSSL 2.5.1 by cleaning a hack. + +Selva Nair (4): + Fix push options digest update + Always release dhcp address in close_tun() on Windows. + Add a check for -Wl, --wrap support in linker + Fix user's group membership check in interactive service to work with domains + +Simon Matter (1): + Fix segfault when using crypto lib without AES-256-CTR or SHA256 + +Steffan Karger (8): + More broadly enforce Allman style and braces-around-conditionals + Use SHA256 for the internal digest, instead of MD5 + OpenSSL: 1.1 fallout - fix configure on old autoconf + Fix types in WIN32 socket_listen_accept() + Remove duplicate X509 env variables + Fix non-C99-compliant builds: don't use const size_t as array length + Deprecate --ns-cert-type + Be less picky about keyUsage extensions + + 2016.12.26 -- Version 2.4.0 David Sommerseth (5): dev-tools: Added script for updating copyright years in files diff --git a/version.m4 b/version.m4 index 3238d0bb002..9636f739a7d 100644 --- a/version.m4 +++ b/version.m4 @@ -3,12 +3,12 @@ define([PRODUCT_NAME], [OpenVPN]) define([PRODUCT_TARNAME], [openvpn]) define([PRODUCT_VERSION_MAJOR], [2]) define([PRODUCT_VERSION_MINOR], [4]) -define([PRODUCT_VERSION_PATCH], [.0]) +define([PRODUCT_VERSION_PATCH], [.1]) m4_append([PRODUCT_VERSION], [PRODUCT_VERSION_MAJOR]) m4_append([PRODUCT_VERSION], [PRODUCT_VERSION_MINOR], [[.]]) m4_append([PRODUCT_VERSION], [PRODUCT_VERSION_PATCH], [[]]) define([PRODUCT_BUGREPORT], [openvpn-users@lists.sourceforge.net]) -define([PRODUCT_VERSION_RESOURCE], [2,4,0,0]) +define([PRODUCT_VERSION_RESOURCE], [2,4,1,0]) dnl define the TAP version define([PRODUCT_TAP_WIN_COMPONENT_ID], [tap0901]) define([PRODUCT_TAP_WIN_MIN_MAJOR], [9]) From a52fd9575e82569ce93408f44799c68704261887 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Tue, 28 Mar 2017 22:53:46 +0200 Subject: [PATCH 508/643] auth-token: Ensure tokens are always wiped on de-auth If tls_deauthenticate() was called, it could in some scenarios leave the authentication token for a session in memory. This change just ensures auth-tokens are always wiped as soon as a TLS session is considered broken. Signed-off-by: David Sommerseth Acked-by: Steffan Karger Message-Id: <20170328205346.18844-1-davids@openvpn.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14344.html Signed-off-by: David Sommerseth (cherry picked from commit daab0a9fa8ff4f40e8a34707db0ac156d49fbfcb) --- src/openvpn/ssl_verify.c | 47 +++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/src/openvpn/ssl_verify.c b/src/openvpn/ssl_verify.c index a6e9be3a814..ac1e110a8fe 100644 --- a/src/openvpn/ssl_verify.c +++ b/src/openvpn/ssl_verify.c @@ -80,6 +80,28 @@ setenv_untrusted(struct tls_session *session) setenv_link_socket_actual(session->opt->es, "untrusted", &session->untrusted_addr, SA_IP_PORT); } + +/** + * Wipes the authentication token out of the memory, frees and cleans up related buffers and flags + * + * @param multi Pointer to a multi object holding the auth_token variables + */ +static void +wipe_auth_token(struct tls_multi *multi) +{ + if(multi) + { + if (multi->auth_token) + { + secure_memzero(multi->auth_token, AUTH_TOKEN_SIZE); + free(multi->auth_token); + } + multi->auth_token = NULL; + multi->auth_token_sent = false; + } +} + + /* * Remove authenticated state from all sessions in the given tunnel */ @@ -88,10 +110,10 @@ tls_deauthenticate(struct tls_multi *multi) { if (multi) { - int i, j; - for (i = 0; i < TM_SIZE; ++i) + wipe_auth_token(multi); + for (int i = 0; i < TM_SIZE; ++i) { - for (j = 0; j < KS_SIZE; ++j) + for (int j = 0; j < KS_SIZE; ++j) { multi->session[i].key[j].authenticated = false; } @@ -1219,21 +1241,6 @@ verify_user_pass_management(struct tls_session *session, const struct user_pass } #endif /* ifdef MANAGEMENT_DEF_AUTH */ -/** - * Wipes the authentication token out of the memory, frees and cleans up related buffers and flags - * - * @param multi Pointer to a multi object holding the auth_token variables - */ -static void -wipe_auth_token(struct tls_multi *multi) -{ - secure_memzero(multi->auth_token, AUTH_TOKEN_SIZE); - free(multi->auth_token); - multi->auth_token = NULL; - multi->auth_token_sent = false; -} - - /* * Main username/password verification entry point */ @@ -1285,7 +1292,7 @@ verify_user_pass(struct user_pass *up, struct tls_multi *multi, /* Ensure that the username has not changed */ if (!tls_lock_username(multi, up->username)) { - wipe_auth_token(multi); + /* auth-token cleared in tls_lock_username() on failure */ ks->authenticated = false; goto done; } @@ -1306,7 +1313,6 @@ verify_user_pass(struct user_pass *up, struct tls_multi *multi, if (memcmp_constant_time(multi->auth_token, up->password, strlen(multi->auth_token)) != 0) { - wipe_auth_token(multi); ks->authenticated = false; tls_deauthenticate(multi); @@ -1478,6 +1484,7 @@ verify_final_auth_checks(struct tls_multi *multi, struct tls_session *session) if (!cn || !strcmp(cn, CCD_DEFAULT) || !test_file(path)) { ks->authenticated = false; + wipe_auth_token(multi); msg(D_TLS_ERRORS, "TLS Auth Error: --client-config-dir authentication failed for common name '%s' file='%s'", session->common_name, path ? path : "UNDEF"); From 8731dfa7caaf8b6d8757492f331e0b4c79851412 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Wed, 29 Mar 2017 11:49:25 +0200 Subject: [PATCH 509/643] docs: Fixed man-page warnings discoverd by rpmlint Running rpmlint against Fedora RPM packages revealed these warnings: W: manual-page-warning /usr/share/man/man8/openvpn.8.gz 2738: a special character is not allowed in a name W: manual-page-warning /usr/share/man/man8/openvpn.8.gz 2740: a special character is not allowed in a name This is just a typo mistake in the .B formatting, missing a trailing space. Signed-off-by: David Sommerseth Acked-by: Steffan Karger Message-Id: <20170329094925.25644-1-davids@openvpn.net> URL: http://www.mail-archive.com/search?l=mid&q=20170329094925.25644-1-davids@openvpn.net Signed-off-by: David Sommerseth (cherry picked from commit 9636196d5efb719cf1011397a360d46bccb3fe29) --- doc/openvpn.8 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index f29b72f427f..a9f5db7c750 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -2735,9 +2735,9 @@ DEFAULT_DIR is replaced by the default plug-in directory, which is configured at the build time of OpenVPN. CWD is the current directory where OpenVPN was started or the directory OpenVPN have swithed into via the -.B\-\-cd +.B \-\-cd option before the -.B\-\-plugin +.B \-\-plugin option. For more information and examples on how to build OpenVPN From 1935729fe6d6badd978e9dfdd3402857b3d000a0 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Tue, 11 Apr 2017 00:28:28 +0200 Subject: [PATCH 510/643] Make --cipher/--auth none more explicit on the risks The warning provided to --cipher and --auth using the 'none' setting may not have been too clearly understandable to non-developers or people not fully understanding encryption and cryptography. This tries to improve that. While at it, also break up the long source lines. Signed-off-by: David Sommerseth Acked-by: Steffan Karger Message-Id: <20170410222828.23612-1-davids@openvpn.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14436.html Signed-off-by: David Sommerseth (cherry picked from commit 7a1b6a0dd706a81897457b0456a951c0b30bbcfb) --- src/openvpn/crypto.c | 11 +++++++++-- src/openvpn/init.c | 5 ++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c index 1369c0f7c35..b6dc7571672 100644 --- a/src/openvpn/crypto.c +++ b/src/openvpn/crypto.c @@ -806,7 +806,10 @@ init_key_type(struct key_type *kt, const char *ciphername, { if (warn) { - msg(M_WARN, "******* WARNING *******: null cipher specified, no encryption will be used"); + msg(M_WARN, "******* WARNING *******: '--cipher none' was specified. " + "This means NO encryption will be performed and tunnelled " + "data WILL be transmitted in clear text over the network! " + "PLEASE DO RECONSIDER THIS SETTING!"); } } if (strcmp(authname, "none") != 0) @@ -826,7 +829,11 @@ init_key_type(struct key_type *kt, const char *ciphername, { if (warn) { - msg(M_WARN, "******* WARNING *******: null MAC specified, no authentication will be used"); + msg(M_WARN, "******* WARNING *******: '--auth none' was specified. " + "This means no authentication will be performed on received " + "packets, meaning you CANNOT trust that the data received by " + "the remote side have NOT been manipulated. " + "PLEASE DO RECONSIDER THIS SETTING!"); } } } diff --git a/src/openvpn/init.c b/src/openvpn/init.c index c7e6fd1ae11..4c78d0b7ea4 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -2759,7 +2759,10 @@ do_init_crypto_none(const struct context *c) { ASSERT(!c->options.test_crypto); msg(M_WARN, - "******* WARNING *******: all encryption and authentication features disabled -- all data will be tunnelled as cleartext"); + "******* WARNING *******: All encryption and authentication features " + "disabled -- All data will be tunnelled as clear text and will not be " + "protected against man-in-the-middle changes. " + "PLEASE DO RECONSIDER THIS CONFIGURATION!"); } #endif /* ifdef ENABLE_CRYPTO */ From 653d39192297880b4fbc6a53cce6f8692782e1b7 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Fri, 5 May 2017 19:44:51 +0200 Subject: [PATCH 511/643] cleanup: merge packet_id_alloc_outgoing() into packet_id_write() The functions packet_id_alloc_outgoing() and packet_id_write() were always called in tandem. Instead of forcing the caller to allocate a packet_id_net to do so, merge the two functions. This simplifies the API and reduces the chance on mistakes in the future. This patch adds unit tests to verify the behaviour of packet_id_write(). Verifying that we assert out correctly required the change to mock_msg.c. Signed-off-by: Steffan Karger Acked-by: Gert Doering Acked-by: David Sommerseth Message-Id: <1494006291-3522-1-git-send-email-steffan.karger@fox-it.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14541.html Signed-off-by: Gert Doering (cherry picked from commit a87e1431baccd49a9344cfc63ab7446c4317fa2f) --- src/openvpn/crypto.c | 20 ++- src/openvpn/packet_id.c | 24 +++- src/openvpn/packet_id.h | 35 ++--- src/openvpn/tls_crypt.c | 6 +- tests/unit_tests/openvpn/Makefile.am | 13 +- tests/unit_tests/openvpn/mock_msg.c | 15 +- tests/unit_tests/openvpn/test_packet_id.c | 168 ++++++++++++++++++++++ 7 files changed, 228 insertions(+), 53 deletions(-) create mode 100644 tests/unit_tests/openvpn/test_packet_id.c diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c index b6dc7571672..ced6b2cf01d 100644 --- a/src/openvpn/crypto.c +++ b/src/openvpn/crypto.c @@ -86,7 +86,6 @@ openvpn_encrypt_aead(struct buffer *buf, struct buffer work, /* Prepare IV */ { struct buffer iv_buffer; - struct packet_id_net pin; uint8_t iv[OPENVPN_MAX_IV_LENGTH] = {0}; const int iv_len = cipher_ctx_iv_length(ctx->cipher); @@ -95,8 +94,7 @@ openvpn_encrypt_aead(struct buffer *buf, struct buffer work, buf_set_write(&iv_buffer, iv, iv_len); /* IV starts with packet id to make the IV unique for packet */ - packet_id_alloc_outgoing(&opt->packet_id.send, &pin, false); - ASSERT(packet_id_write(&pin, &iv_buffer, false, false)); + ASSERT(packet_id_write(&opt->packet_id.send, &iv_buffer, false, false)); /* Remainder of IV consists of implicit part (unique per session) */ ASSERT(buf_write(&iv_buffer, ctx->implicit_iv, ctx->implicit_iv_len)); @@ -199,23 +197,21 @@ openvpn_encrypt_v1(struct buffer *buf, struct buffer work, /* Put packet ID in plaintext buffer */ if (packet_id_initialized(&opt->packet_id)) { - struct packet_id_net pin; - packet_id_alloc_outgoing(&opt->packet_id.send, &pin, BOOL_CAST(opt->flags & CO_PACKET_ID_LONG_FORM)); - ASSERT(packet_id_write(&pin, buf, BOOL_CAST(opt->flags & CO_PACKET_ID_LONG_FORM), true)); + ASSERT(packet_id_write(&opt->packet_id.send, buf, + opt->flags & CO_PACKET_ID_LONG_FORM, + true)); } } else if (cipher_kt_mode_ofb_cfb(cipher_kt)) { - struct packet_id_net pin; struct buffer b; /* IV and packet-ID required for this mode. */ ASSERT(opt->flags & CO_USE_IV); ASSERT(packet_id_initialized(&opt->packet_id)); - packet_id_alloc_outgoing(&opt->packet_id.send, &pin, true); buf_set_write(&b, iv_buf, iv_size); - ASSERT(packet_id_write(&pin, &b, true, false)); + ASSERT(packet_id_write(&opt->packet_id.send, &b, true, false)); } else /* We only support CBC, CFB, or OFB modes right now */ { @@ -265,9 +261,9 @@ openvpn_encrypt_v1(struct buffer *buf, struct buffer work, { if (packet_id_initialized(&opt->packet_id)) { - struct packet_id_net pin; - packet_id_alloc_outgoing(&opt->packet_id.send, &pin, BOOL_CAST(opt->flags & CO_PACKET_ID_LONG_FORM)); - ASSERT(packet_id_write(&pin, buf, BOOL_CAST(opt->flags & CO_PACKET_ID_LONG_FORM), true)); + ASSERT(packet_id_write(&opt->packet_id.send, buf, + BOOL_CAST(opt->flags & CO_PACKET_ID_LONG_FORM), + true)); } if (ctx->hmac) { diff --git a/src/openvpn/packet_id.c b/src/openvpn/packet_id.c index e34c228b7f6..5175fb08dfb 100644 --- a/src/openvpn/packet_id.c +++ b/src/openvpn/packet_id.c @@ -325,12 +325,30 @@ packet_id_read(struct packet_id_net *pin, struct buffer *buf, bool long_form) return true; } +static void +packet_id_send_update(struct packet_id_send *p, bool long_form) +{ + if (!p->time) + { + p->time = now; + } + p->id++; + if (!p->id) + { + ASSERT(long_form); + p->time = now; + p->id = 1; + } +} + bool -packet_id_write(const struct packet_id_net *pin, struct buffer *buf, bool long_form, bool prepend) +packet_id_write(struct packet_id_send *p, struct buffer *buf, bool long_form, + bool prepend) { - packet_id_type net_id = htonpid(pin->id); - net_time_t net_time = htontime(pin->time); + packet_id_send_update(p, long_form); + const packet_id_type net_id = htonpid(p->id); + const net_time_t net_time = htontime(p->time); if (prepend) { if (long_form) diff --git a/src/openvpn/packet_id.h b/src/openvpn/packet_id.h index ecc25a6c3b5..109e56aad5a 100644 --- a/src/openvpn/packet_id.h +++ b/src/openvpn/packet_id.h @@ -254,7 +254,18 @@ const char *packet_id_persist_print(const struct packet_id_persist *p, struct gc bool packet_id_read(struct packet_id_net *pin, struct buffer *buf, bool long_form); -bool packet_id_write(const struct packet_id_net *pin, struct buffer *buf, bool long_form, bool prepend); +/** + * Write a packet ID to buf, and update the packet ID state. + * + * @param p Packet ID state. + * @param buf Buffer to write the packet ID too + * @param long_form If true, also update and write time_t to buf + * @param prepend If true, prepend to buffer, otherwise apppend. + * + * @return true if successful, false otherwise. + */ +bool packet_id_write(struct packet_id_send *p, struct buffer *buf, + bool long_form, bool prepend); /* * Inline functions. @@ -304,28 +315,6 @@ packet_id_close_to_wrapping(const struct packet_id_send *p) return p->id >= PACKET_ID_WRAP_TRIGGER; } -/* - * Allocate an outgoing packet id. - * Sequence number ranges from 1 to 2^32-1. - * In long_form, a time_t is added as well. - */ -static inline void -packet_id_alloc_outgoing(struct packet_id_send *p, struct packet_id_net *pin, bool long_form) -{ - if (!p->time) - { - p->time = now; - } - pin->id = ++p->id; - if (!pin->id) - { - ASSERT(long_form); - p->time = now; - pin->id = p->id = 1; - } - pin->time = p->time; -} - static inline bool check_timestamp_delta(time_t remote, unsigned int max_delta) { diff --git a/src/openvpn/tls_crypt.c b/src/openvpn/tls_crypt.c index e2fdbed2f42..e47d25cb73f 100644 --- a/src/openvpn/tls_crypt.c +++ b/src/openvpn/tls_crypt.c @@ -98,11 +98,7 @@ tls_crypt_wrap(const struct buffer *src, struct buffer *dst, format_hex(BPTR(src), BLEN(src), 80, &gc)); /* Get packet ID */ - { - struct packet_id_net pin; - packet_id_alloc_outgoing(&opt->packet_id.send, &pin, true); - packet_id_write(&pin, dst, true, false); - } + ASSERT(packet_id_write(&opt->packet_id.send, dst, true, false)); dmsg(D_PACKET_CONTENT, "TLS-CRYPT WRAP AD: %s", format_hex(BPTR(dst), BLEN(dst), 0, &gc)); diff --git a/tests/unit_tests/openvpn/Makefile.am b/tests/unit_tests/openvpn/Makefile.am index b902b2098fc..5d7123e2046 100644 --- a/tests/unit_tests/openvpn/Makefile.am +++ b/tests/unit_tests/openvpn/Makefile.am @@ -3,7 +3,7 @@ AUTOMAKE_OPTIONS = foreign check_PROGRAMS= if HAVE_LD_WRAP_SUPPORT -check_PROGRAMS += argv_testdriver buffer_testdriver +check_PROGRAMS += argv_testdriver buffer_testdriver packet_id_testdriver endif if ENABLE_CRYPTO @@ -31,6 +31,17 @@ buffer_testdriver_SOURCES = test_buffer.c mock_msg.c \ $(openvpn_srcdir)/buffer.c \ $(openvpn_srcdir)/platform.c +packet_id_testdriver_CFLAGS = @TEST_CFLAGS@ \ + -I$(openvpn_includedir) -I$(compat_srcdir) -I$(openvpn_srcdir) \ + $(OPTIONAL_CRYPTO_CFLAGS) +packet_id_testdriver_LDFLAGS = @TEST_LDFLAGS@ \ + $(OPTIONAL_CRYPTO_LIBS) +packet_id_testdriver_SOURCES = test_packet_id.c mock_msg.c \ + $(openvpn_srcdir)/buffer.c \ + $(openvpn_srcdir)/otime.c \ + $(openvpn_srcdir)/packet_id.c \ + $(openvpn_srcdir)/platform.c + tls_crypt_testdriver_CFLAGS = @TEST_CFLAGS@ \ -I$(openvpn_includedir) -I$(compat_srcdir) -I$(openvpn_srcdir) \ $(OPTIONAL_CRYPTO_CFLAGS) diff --git a/tests/unit_tests/openvpn/mock_msg.c b/tests/unit_tests/openvpn/mock_msg.c index eb0d5e9b7db..060588fae5e 100644 --- a/tests/unit_tests/openvpn/mock_msg.c +++ b/tests/unit_tests/openvpn/mock_msg.c @@ -29,9 +29,12 @@ #endif #include -#include +#include #include #include +#include +#include + #include "errlevel.h" #include "error.h" @@ -70,14 +73,8 @@ x_msg(const unsigned int flags, const char *format, ...) void assert_failed(const char *filename, int line, const char *condition) { - if (condition) - { - printf("Assertion failed at %s:%d (%s)", filename, line, condition); - } - else - { - printf("Assertion failed at %s:%d", filename, line); - } + mock_assert(false, condition ? condition : "", filename, line); + /* Keep compiler happy. Should not happen, mock_assert() does not return */ exit(1); } diff --git a/tests/unit_tests/openvpn/test_packet_id.c b/tests/unit_tests/openvpn/test_packet_id.c new file mode 100644 index 00000000000..5627a5b658e --- /dev/null +++ b/tests/unit_tests/openvpn/test_packet_id.c @@ -0,0 +1,168 @@ +/* + * OpenVPN -- An application to securely tunnel IP networks + * over a single UDP port, with support for SSL/TLS-based + * session authentication and key exchange, + * packet encryption, packet authentication, and + * packet compression. + * + * Copyright (C) 2016 Fox Crypto B.V. + * + * 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 + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#elif defined(_MSC_VER) +#include "config-msvc.h" +#endif + +#include "syshead.h" + +#include +#include +#include +#include + +#include "packet_id.h" + +#include "mock_msg.h" + +struct test_packet_id_write_data { + struct { + uint32_t buf_id; + uint32_t buf_time; + } test_buf_data; + struct buffer test_buf; + struct packet_id_send pis; +}; + +static int +test_packet_id_write_setup(void **state) { + struct test_packet_id_write_data *data = + calloc(1, sizeof(struct test_packet_id_write_data)); + + if (!data) + { + return -1; + } + + data->test_buf.data = (void *) &data->test_buf_data; + data->test_buf.capacity = sizeof(data->test_buf_data); + + *state = data; + return 0; +} + +static int +test_packet_id_write_teardown(void **state) { + free(*state); + return 0; +} + +static void +test_packet_id_write_short(void **state) +{ + struct test_packet_id_write_data *data = *state; + + now = 5010; + assert_true(packet_id_write(&data->pis, &data->test_buf, false, false)); + assert_true(data->pis.id == 1); + assert_true(data->test_buf_data.buf_id == htonl(1)); + assert_true(data->test_buf_data.buf_time == 0); +} + +static void +test_packet_id_write_long(void **state) +{ + struct test_packet_id_write_data *data = *state; + + now = 5010; + assert_true(packet_id_write(&data->pis, &data->test_buf, true, false)); + assert(data->pis.id == 1); + assert(data->pis.time == now); + assert_true(data->test_buf_data.buf_id == htonl(1)); + assert_true(data->test_buf_data.buf_time == htonl(now)); +} + +static void +test_packet_id_write_short_prepend(void **state) +{ + struct test_packet_id_write_data *data = *state; + + data->test_buf.offset = sizeof(packet_id_type); + now = 5010; + assert_true(packet_id_write(&data->pis, &data->test_buf, false, true)); + assert_true(data->pis.id == 1); + assert_true(data->test_buf_data.buf_id == htonl(1)); + assert_true(data->test_buf_data.buf_time == 0); +} + +static void +test_packet_id_write_long_prepend(void **state) +{ + struct test_packet_id_write_data *data = *state; + + data->test_buf.offset = sizeof(data->test_buf_data); + now = 5010; + assert_true(packet_id_write(&data->pis, &data->test_buf, true, true)); + assert(data->pis.id == 1); + assert(data->pis.time == now); + assert_true(data->test_buf_data.buf_id == htonl(1)); + assert_true(data->test_buf_data.buf_time == htonl(now)); +} + +static void +test_packet_id_write_short_wrap(void **state) +{ + struct test_packet_id_write_data *data = *state; + + data->pis.id = ~0; + expect_assert_failure( + packet_id_write(&data->pis, &data->test_buf, false, false)); +} + +static void +test_packet_id_write_long_wrap(void **state) +{ + struct test_packet_id_write_data *data = *state; + + data->pis.id = ~0; + now = 5010; + assert_true(packet_id_write(&data->pis, &data->test_buf, true, false)); + assert(data->pis.id == 1); + assert(data->pis.time == now); + assert_true(data->test_buf_data.buf_id == htonl(1)); + assert_true(data->test_buf_data.buf_time == htonl(now)); +} + +int +main(void) { + const struct CMUnitTest tests[] = { + cmocka_unit_test_setup_teardown(test_packet_id_write_short, + test_packet_id_write_setup, test_packet_id_write_teardown), + cmocka_unit_test_setup_teardown(test_packet_id_write_long, + test_packet_id_write_setup, test_packet_id_write_teardown), + cmocka_unit_test_setup_teardown(test_packet_id_write_short_prepend, + test_packet_id_write_setup, test_packet_id_write_teardown), + cmocka_unit_test_setup_teardown(test_packet_id_write_long_prepend, + test_packet_id_write_setup, test_packet_id_write_teardown), + cmocka_unit_test_setup_teardown(test_packet_id_write_short_wrap, + test_packet_id_write_setup, test_packet_id_write_teardown), + cmocka_unit_test_setup_teardown(test_packet_id_write_long_wrap, + test_packet_id_write_setup, test_packet_id_write_teardown), + }; + + return cmocka_run_group_tests_name("packet_id tests", tests, NULL, NULL); +} From 4aaa29dabda6513329fbff778828797f19c5b4ea Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Fri, 5 May 2017 22:07:28 +0200 Subject: [PATCH 512/643] Don't run packet_id unit tests for --disable-crypto builds Because there is no packet_id in those builds... This fixes 'make check' for --disable-crypto builds, caught by travis. Signed-off-by: Steffan Karger Acked-by: David Sommerseth Message-Id: <1494014848-20099-1-git-send-email-steffan.karger@fox-it.com> URL: http://www.mail-archive.com/search?l=mid&q=1494014848-20099-1-git-send-email-steffan.karger@fox-it.com Signed-off-by: David Sommerseth (cherry picked from commit dcfcc594759b3a768cd4d40508cbacae114c274b) --- tests/unit_tests/openvpn/Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unit_tests/openvpn/Makefile.am b/tests/unit_tests/openvpn/Makefile.am index 5d7123e2046..3bd382c2dfc 100644 --- a/tests/unit_tests/openvpn/Makefile.am +++ b/tests/unit_tests/openvpn/Makefile.am @@ -3,11 +3,11 @@ AUTOMAKE_OPTIONS = foreign check_PROGRAMS= if HAVE_LD_WRAP_SUPPORT -check_PROGRAMS += argv_testdriver buffer_testdriver packet_id_testdriver +check_PROGRAMS += argv_testdriver buffer_testdriver endif if ENABLE_CRYPTO -check_PROGRAMS += tls_crypt_testdriver +check_PROGRAMS += packet_id_testdriver tls_crypt_testdriver endif TESTS = $(check_PROGRAMS) From de7eccea0d6cc70726f89ae30f8f8b7b5775c6a4 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Fri, 5 May 2017 22:14:46 +0200 Subject: [PATCH 513/643] Fix Changes.rst layout The extra space before each line made the 2.4.1 section stand out from the other sections. Signed-off-by: Steffan Karger Acked-by: David Sommerseth Message-Id: <1494015286-20368-1-git-send-email-steffan.karger@fox-it.com> URL: http://www.mail-archive.com/search?l=mid&q=1494015286-20368-1-git-send-email-steffan.karger@fox-it.com Signed-off-by: David Sommerseth (cherry picked from commit 7ad917760136807298c39d9260ff6bb074db03a4) --- Changes.rst | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Changes.rst b/Changes.rst index 2a94990e5e1..c1583b396a9 100644 --- a/Changes.rst +++ b/Changes.rst @@ -306,15 +306,15 @@ Maintainer-visible changes Version 2.4.1 ============= - - ``--remote-cert-ku`` now only requires the certificate to have at least the - bits set of one of the values in the supplied list, instead of requiring an - exact match to one of the values in the list. - - ``--remote-cert-tls`` now only requires that a keyUsage is present in the - certificate, and leaves the verification of the value up to the crypto - library, which has more information (i.e. the key exchange method in use) - to verify that the keyUsage is correct. - - ``--ns-cert-type`` is deprecated. Use ``--remote-cert-tls`` instead. - The nsCertType x509 extension is very old, and barely used. - ``--remote-cert-tls`` uses the far more common keyUsage and extendedKeyUsage - extension instead. Make sure your certificates carry these to be able to - use ``--remote-cert-tls``. +- ``--remote-cert-ku`` now only requires the certificate to have at least the + bits set of one of the values in the supplied list, instead of requiring an + exact match to one of the values in the list. +- ``--remote-cert-tls`` now only requires that a keyUsage is present in the + certificate, and leaves the verification of the value up to the crypto + library, which has more information (i.e. the key exchange method in use) + to verify that the keyUsage is correct. +- ``--ns-cert-type`` is deprecated. Use ``--remote-cert-tls`` instead. + The nsCertType x509 extension is very old, and barely used. + ``--remote-cert-tls`` uses the far more common keyUsage and extendedKeyUsage + extension instead. Make sure your certificates carry these to be able to + use ``--remote-cert-tls``. From f5d41cc68407f77f8fab41e242fa1d651c55c257 Mon Sep 17 00:00:00 2001 From: Hristo Venev Date: Thu, 4 May 2017 00:10:48 +0100 Subject: [PATCH 514/643] Fix extract_x509_field_ssl for external objects, v2 Only fields known to OpenSSL have a NID. OBJ_txt2obj allows specifying fields by numeric OID. Signed-off-by: Hristo Venev Acked-by: Steffan Karger Message-Id: <1493853048.30207.1.camel@venev.name> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14535.html Signed-off-by: David Sommerseth (cherry picked from commit 69311687da55b8c0e6966b25c94c72494ea44e57) --- src/openvpn/ssl_verify_openssl.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/openvpn/ssl_verify_openssl.c b/src/openvpn/ssl_verify_openssl.c index 5624daac59e..de4b5da4b96 100644 --- a/src/openvpn/ssl_verify_openssl.c +++ b/src/openvpn/ssl_verify_openssl.c @@ -191,16 +191,24 @@ extract_x509_field_ssl(X509_NAME *x509, const char *field_name, char *out, X509_NAME_ENTRY *x509ne = 0; ASN1_STRING *asn1 = 0; unsigned char *buf = NULL; - int nid = OBJ_txt2nid(field_name); + ASN1_OBJECT *field_name_obj = OBJ_txt2obj(field_name, 0); + + if (field_name_obj == NULL) + { + msg(D_TLS_ERRORS, "Invalid X509 attribute name '%s'", field_name); + return FAILURE; + } ASSERT(size > 0); *out = '\0'; do { lastpos = tmp; - tmp = X509_NAME_get_index_by_NID(x509, nid, lastpos); + tmp = X509_NAME_get_index_by_OBJ(x509, field_name_obj, lastpos); } while (tmp > -1); + ASN1_OBJECT_free(field_name_obj); + /* Nothing found */ if (lastpos == -1) { From d7a13af789daecf38fb6a3ca2d6e6cf0ab939a73 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sun, 7 May 2017 13:01:18 +0200 Subject: [PATCH 515/643] Fix memory leak in x509_verify_cert_ku() If keyUsage was only required to be present, but no specific value was required, we would omit to free the extracted string. This happens as of 2.4.1, if --remote-cert-tls is used. In that case we leak a bit of memory on each TLS (re)negotiation. Signed-off-by: Steffan Karger Acked-by: David Sommerseth Message-Id: <1494154878-18403-1-git-send-email-steffan@karger.me> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14563.html Signed-off-by: David Sommerseth (cherry picked from commit 7b94d3bbbea46efcea12e1df24da52fe508d0173) --- Changes.rst | 9 +++++++++ src/openvpn/ssl_verify_openssl.c | 1 + 2 files changed, 10 insertions(+) diff --git a/Changes.rst b/Changes.rst index c1583b396a9..3dba7e0ef51 100644 --- a/Changes.rst +++ b/Changes.rst @@ -318,3 +318,12 @@ Version 2.4.1 ``--remote-cert-tls`` uses the far more common keyUsage and extendedKeyUsage extension instead. Make sure your certificates carry these to be able to use ``--remote-cert-tls``. + + +Version 2.4.2 +============= + +Bugfixes +-------- +- Fix memory leak introduced in 2.4.1: if --remote-cert-tls is used, we leaked + some memory on each TLS (re)negotiation. diff --git a/src/openvpn/ssl_verify_openssl.c b/src/openvpn/ssl_verify_openssl.c index de4b5da4b96..4906c7d3d2d 100644 --- a/src/openvpn/ssl_verify_openssl.c +++ b/src/openvpn/ssl_verify_openssl.c @@ -609,6 +609,7 @@ x509_verify_cert_ku(X509 *x509, const unsigned *const expected_ku, if (expected_ku[0] == OPENVPN_KU_REQUIRED) { /* Extension required, value checked by TLS library */ + ASN1_BIT_STRING_free(ku); return SUCCESS; } From 1ebd3ade5f3fcdefa40790f2e9d16c473bac370a Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Tue, 9 May 2017 10:12:43 +0200 Subject: [PATCH 516/643] mbedtls: correctly check return value in pkcs11_certificate_dn() mbedtls_x509_dn_gets() would not always return -1 error, which could cause us to incorrectly continue after the function call failed. To fix this, just call our own x509_get_subject(), which does all the neccesary error checking correctly. pkcs11_certificate_dn() is only called by show_pkcs11_ids(), to list the certificates on the pkcs11 token. Therefor, this mistake did not have a security impact. This issue was found by Quarkslab during the OSTIF-founded security audit (issue 5.3). Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1494317563-6303-1-git-send-email-steffan.karger@fox-it.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14591.html Signed-off-by: David Sommerseth (cherry picked from commit 423bb16e8a8fe22a907f469074a25533208fa0bc) --- src/openvpn/pkcs11_mbedtls.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/openvpn/pkcs11_mbedtls.c b/src/openvpn/pkcs11_mbedtls.c index bdca893d4d4..dee97bc472e 100644 --- a/src/openvpn/pkcs11_mbedtls.c +++ b/src/openvpn/pkcs11_mbedtls.c @@ -39,6 +39,7 @@ #include "errlevel.h" #include "pkcs11_backend.h" +#include "ssl_verify_backend.h" #include #include @@ -82,8 +83,6 @@ char * pkcs11_certificate_dn(pkcs11h_certificate_t cert, struct gc_arena *gc) { char *ret = NULL; - char dn[1024] = {0}; - mbedtls_x509_crt mbed_crt = {0}; if (mbedtls_pkcs11_x509_cert_bind(&mbed_crt, cert)) @@ -92,14 +91,12 @@ pkcs11_certificate_dn(pkcs11h_certificate_t cert, struct gc_arena *gc) goto cleanup; } - if (-1 == mbedtls_x509_dn_gets(dn, sizeof(dn), &mbed_crt.subject)) + if (!(ret = x509_get_subject(&mbed_crt, gc))) { msg(M_FATAL, "PKCS#11: mbed TLS cannot parse subject"); goto cleanup; } - ret = string_alloc(dn, gc); - cleanup: mbedtls_x509_crt_free(&mbed_crt); From e9bb49ba2ff372fad9ca1d1ab9fbdf9761cf2a40 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Mon, 8 May 2017 16:19:39 +0200 Subject: [PATCH 517/643] plugin: Fix documentation typo for type_mask The v3 plug-in API was slightly misleading, as that interface does not need to use an int pointer to setting the type_mask from the plug-in. Signed-off-by: David Sommerseth Acked-by: Selva Nair Message-Id: <20170508141939.31224-1-davids@openvpn.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14576.html Signed-off-by: David Sommerseth (cherry picked from commit 26e3427cfa128c5d8ac7e212769ba29afac4f3d9) --- include/openvpn-plugin.h.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/openvpn-plugin.h.in b/include/openvpn-plugin.h.in index 0b303520a30..d43a29a923e 100644 --- a/include/openvpn-plugin.h.in +++ b/include/openvpn-plugin.h.in @@ -328,12 +328,12 @@ struct openvpn_plugin_args_open_in * * STRUCT MEMBERS * - * *type_mask : The plug-in should set this value to the logical OR of all script + * type_mask : The plug-in should set this value to the logical OR of all script * types which the plug-in wants to intercept. For example, if the * script wants to intercept the client-connect and client-disconnect * script types: * - * *type_mask = OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_CLIENT_CONNECT) + * type_mask = OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_CLIENT_CONNECT) * | OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_CLIENT_DISCONNECT) * * *handle : Pointer to a global plug-in context, created by the plug-in. This pointer From 03d01f4f69cfc6768343b9f0f2dde2049e4882d2 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Mon, 8 May 2017 23:44:38 +0200 Subject: [PATCH 518/643] Restore pre-NCP frame parameters for new sessions As reported in trac #879, as of the introduction of NCP we always adjust the frame parameters on session negotiations, but do not reset the frame state for a new session on an existing state instance. That caused the frame parameters to be reduced for each reconnect, resulting in smaller and smaller packet size limits until no traffic could go through the tunnel at all. This patch resolves that omission. Trac: #879 Signed-off-by: Steffan Karger Acked-by: David Sommerseth Acked-by: Arne Schwabe Message-Id: <1494279878-24601-1-git-send-email-steffan@karger.me> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14589.html Signed-off-by: David Sommerseth (cherry picked from commit 9900e023bcc49964d33e6f22c2b6223f8932acf8) --- src/openvpn/forward.c | 7 +++++++ src/openvpn/init.c | 2 ++ src/openvpn/openvpn.h | 3 ++- src/openvpn/ssl.c | 9 +-------- src/openvpn/ssl.h | 8 ++++++++ 5 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c index 8102e94975b..2f3f3c5dae7 100644 --- a/src/openvpn/forward.c +++ b/src/openvpn/forward.c @@ -866,9 +866,16 @@ process_incoming_link_part1(struct context *c, struct link_socket_info *lsi, boo * will load crypto_options with the correct encryption key * and return false. */ + uint8_t opcode = *BPTR(&c->c2.buf) >> P_OPCODE_SHIFT; if (tls_pre_decrypt(c->c2.tls_multi, &c->c2.from, &c->c2.buf, &co, floated, &ad_start)) { + /* Restore pre-NCP frame parameters */ + if (is_hard_reset(opcode, c->options.key_method)) + { + c->c2.frame = c->c2.frame_initial; + } + interval_action(&c->c2.tmp_int); /* reset packet received timer if TLS packet */ diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 4c78d0b7ea4..607e2a5b7e6 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -4069,6 +4069,8 @@ init_instance(struct context *c, const struct env_set *env, const unsigned int f c->c2.did_open_tun = do_open_tun(c); } + c->c2.frame_initial = c->c2.frame; + /* print MTU info */ do_print_data_channel_mtu_parms(c); diff --git a/src/openvpn/openvpn.h b/src/openvpn/openvpn.h index 893296edc53..f8682d1735d 100644 --- a/src/openvpn/openvpn.h +++ b/src/openvpn/openvpn.h @@ -263,7 +263,8 @@ struct context_2 struct link_socket_actual from; /* address of incoming datagram */ /* MTU frame parameters */ - struct frame frame; + struct frame frame; /* Active frame parameters */ + struct frame frame_initial; /* Restored on new session */ #ifdef ENABLE_FRAGMENT /* Object to handle advanced MTU negotiation and datagram fragmentation */ diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 1033e581ea1..630b77f9272 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -832,14 +832,7 @@ print_key_id(struct tls_multi *multi, struct gc_arena *gc) return BSTR(&out); } -/* - * Given a key_method, return true if op - * represents the required form of hard_reset. - * - * If key_method = 0, return true if any - * form of hard reset is used. - */ -static bool +bool is_hard_reset(int op, int key_method) { if (!key_method || key_method == 1) diff --git a/src/openvpn/ssl.h b/src/openvpn/ssl.h index ed1344e7b2f..03688ca6e6b 100644 --- a/src/openvpn/ssl.h +++ b/src/openvpn/ssl.h @@ -591,6 +591,14 @@ void show_tls_performance_stats(void); /*#define EXTRACT_X509_FIELD_TEST*/ void extract_x509_field_test(void); +/** + * Given a key_method, return true if opcode represents the required form of + * hard_reset. + * + * If key_method == 0, return true if any form of hard reset is used. + */ +bool is_hard_reset(int op, int key_method); + #endif /* ENABLE_CRYPTO */ #endif /* ifndef OPENVPN_SSL_H */ From 174c27e7b4b2b86809ac61dd4afee01a74321e0f Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Fri, 5 May 2017 20:46:22 +0200 Subject: [PATCH 519/643] plugin: Export secure_memzero() to plug-ins The provides plug-ins with a safe and secure way to santize sensitive information such as passwords, by re-using the secure_memzero() implementation in OpenVPN. Signed-off-by: David Sommerseth Acked-by: Selva Nair Message-Id: <20170505184622.24520-1-davids@openvpn.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14546.html Signed-off-by: David Sommerseth (cherry picked from commit f018dfcc3631f165232afa3d13dc2a608bdb6ce7) --- include/openvpn-plugin.h.in | 25 ++++++++++++++++++++++--- src/openvpn/plugin.c | 3 ++- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/include/openvpn-plugin.h.in b/include/openvpn-plugin.h.in index d43a29a923e..5e6f874375e 100644 --- a/include/openvpn-plugin.h.in +++ b/include/openvpn-plugin.h.in @@ -199,7 +199,8 @@ struct openvpn_plugin_string_list /* openvpn_plugin_{open,func}_v3() related structs */ -/* Defines version of the v3 plugin argument structs +/** + * Defines version of the v3 plugin argument structs * * Whenever one or more of these structs are modified, this constant * must be updated. A changelog should be appended in this comment @@ -218,8 +219,10 @@ struct openvpn_plugin_string_list * 3 Added ovpn_version, ovpn_version_major, ovpn_version_minor * and ovpn_version_patch to provide the runtime version of * OpenVPN to plug-ins. + * + * 4 Exported secure_memzero() as plugin_secure_memzero() */ -#define OPENVPN_PLUGINv3_STRUCTVER 3 +#define OPENVPN_PLUGINv3_STRUCTVER 4 /** * Definitions needed for the plug-in callback functions. @@ -255,9 +258,18 @@ typedef void (*plugin_vlog_t)(openvpn_plugin_log_flags_t flags, const char *plugin_name, const char *format, va_list arglist) _ovpn_chk_fmt (3, 0); - #undef _ovpn_chk_fmt +/** + * Export of secure_memzero() to be used inside plug-ins + * + * @param data Pointer to data to zeroise + * @param len Length of data, in bytes + * + */ +typedef void (*plugin_secure_memzero_t)(void *data, size_t len); + + /** * Used by the openvpn_plugin_open_v3() function to pass callback * function pointers to the plug-in. @@ -267,11 +279,18 @@ typedef void (*plugin_vlog_t)(openvpn_plugin_log_flags_t flags, * Messages will only be displayed if the plugin_name parameter * is set. PLOG_DEBUG messages will only be displayed with plug-in * debug log verbosity (at the time of writing that's verb >= 7). + * + * plugin_secure_memzero + * : Use this function to securely wipe sensitive information from + * memory. This function is declared in a way that the compiler + * will not remove these function calls during the compiler + * optimization phase. */ struct openvpn_plugin_callbacks { plugin_log_t plugin_log; plugin_vlog_t plugin_vlog; + plugin_secure_memzero_t plugin_secure_memzero; }; /** diff --git a/src/openvpn/plugin.c b/src/openvpn/plugin.c index 05cbae3eff9..a652d528505 100644 --- a/src/openvpn/plugin.c +++ b/src/openvpn/plugin.c @@ -410,7 +410,8 @@ plugin_log(openvpn_plugin_log_flags_t flags, const char *name, const char *forma static struct openvpn_plugin_callbacks callbacks = { plugin_log, - plugin_vlog + plugin_vlog, + secure_memzero /* plugin_secure_memzero */ }; From 47d80b95646a3cf62c9cd46ab589c442124c0474 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Tue, 9 May 2017 20:32:44 +0200 Subject: [PATCH 520/643] Always clear username/password from memory on error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This issue was found by Quarkslab during the OSTIF-founded security audit (issue 5.4), we are with their analysis: "There’s a special case where the client username and password are not erased when the server is launched without an external script or authentication plugin. While being invalid, this configuration does not raise any error. If the client transmits its credentials and the session is not established (for instance if the certificates chain has not been verified), these credentials are not erased from memory by the server. The likelihood of an occurrence of this issue in real life is exceptionally low since an attacker needs elevated privileges on the server to exploit this kind of information leak. The severity of this issue is rated as very low." Signed-off-by: Steffan Karger Acked-by: David Sommerseth Message-Id: <1494354764-19354-1-git-send-email-steffan.karger@fox-it.com> URL: http://www.mail-archive.com/search?l=mid&q=1494354764-19354-1-git-send-email-steffan.karger@fox-it.com Signed-off-by: David Sommerseth (cherry picked from commit 2b60198e08a9d7e8de9beeb65a587ee34107efe8) --- src/openvpn/ssl.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 630b77f9272..d2f4730bfb4 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -2492,7 +2492,7 @@ key_method_2_read(struct buffer *buf, struct tls_multi *multi, struct tls_sessio struct gc_arena gc = gc_new(); char *options; - struct user_pass *up; + struct user_pass *up = NULL; /* allocate temporary objects */ ALLOC_ARRAY_CLEAR_GC(options, char, TLS_OPTIONS_LEN, &gc); @@ -2654,6 +2654,10 @@ key_method_2_read(struct buffer *buf, struct tls_multi *multi, struct tls_sessio error: secure_memzero(ks->key_src, sizeof(*ks->key_src)); + if (up) + { + secure_memzero(up, sizeof(*up)); + } buf_clear(buf); gc_free(&gc); return false; From 4702cf5a898f33693f4f705038e1b4f2568bde71 Mon Sep 17 00:00:00 2001 From: Selva Nair Date: Tue, 9 May 2017 15:44:29 -0400 Subject: [PATCH 521/643] In auth-pam plugin clear the password after use v2: Change the plugin open to use v3 API so that secure_memzero() exported from OpenVPN can be used. v3: Relaxe API compatibility check: struct version 4 or higher will have secure_memzero exported. Note: context is cast as (openvpn_plugin_handle_t *) for consistency with the current plugin header. If/when the header is fixed, change this cast as well. Signed-off-by: Selva Nair Acked-by: David Sommerseth Message-Id: <1494359069-13824-1-git-send-email-selva.nair@gmail.com> URL: http://www.mail-archive.com/search?l=mid&q=1494359069-13824-1-git-send-email-selva.nair@gmail.com Signed-off-by: David Sommerseth (cherry picked from commit f403b9a2bf93f0fa35ee8316c2d219f48638a3e5) --- src/plugins/auth-pam/auth-pam.c | 31 ++++++++++++++++++++++----- src/plugins/auth-pam/auth-pam.exports | 2 +- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/plugins/auth-pam/auth-pam.c b/src/plugins/auth-pam/auth-pam.c index d3e2c89d834..54471a3947e 100644 --- a/src/plugins/auth-pam/auth-pam.c +++ b/src/plugins/auth-pam/auth-pam.c @@ -63,6 +63,9 @@ #define RESPONSE_VERIFY_SUCCEEDED 12 #define RESPONSE_VERIFY_FAILED 13 +/* Pointers to functions exported from openvpn */ +static plugin_secure_memzero_t plugin_secure_memzero = NULL; + /* * Plugin state, used by foreground */ @@ -274,8 +277,10 @@ name_value_match(const char *query, const char *match) return strncasecmp(match, query, strlen(match)) == 0; } -OPENVPN_EXPORT openvpn_plugin_handle_t -openvpn_plugin_open_v1(unsigned int *type_mask, const char *argv[], const char *envp[]) +OPENVPN_EXPORT int +openvpn_plugin_open_v3(const int v3structver, + struct openvpn_plugin_args_open_in const *args, + struct openvpn_plugin_args_open_return *ret) { pid_t pid; int fd[2]; @@ -285,6 +290,16 @@ openvpn_plugin_open_v1(unsigned int *type_mask, const char *argv[], const char * const int base_parms = 2; + const char **argv = args->argv; + const char **envp = args->envp; + + /* Check API compatibility -- struct version 4 or higher needed */ + if (v3structver < 4) + { + fprintf(stderr, "AUTH-PAM: This plugin is incompatible with the running version of OpenVPN\n"); + return OPENVPN_PLUGIN_FUNC_ERROR; + } + /* * Allocate our context */ @@ -298,7 +313,10 @@ openvpn_plugin_open_v1(unsigned int *type_mask, const char *argv[], const char * /* * Intercept the --auth-user-pass-verify callback. */ - *type_mask = OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY); + ret->type_mask = OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY); + + /* Save global pointers to functions exported from openvpn */ + plugin_secure_memzero = args->callbacks->plugin_secure_memzero; /* * Make sure we have two string arguments: the first is the .so name, @@ -386,7 +404,8 @@ openvpn_plugin_open_v1(unsigned int *type_mask, const char *argv[], const char * if (status == RESPONSE_INIT_SUCCEEDED) { context->foreground_fd = fd[0]; - return (openvpn_plugin_handle_t) context; + ret->handle = (openvpn_plugin_handle_t *) context; + return OPENVPN_PLUGIN_FUNC_SUCCESS; } } else @@ -420,7 +439,7 @@ openvpn_plugin_open_v1(unsigned int *type_mask, const char *argv[], const char * { free(context); } - return NULL; + return OPENVPN_PLUGIN_FUNC_ERROR; } OPENVPN_EXPORT int @@ -785,6 +804,7 @@ pam_server(int fd, const char *service, int verb, const struct name_value_list * goto done; } } + plugin_secure_memzero(up.password, sizeof(up.password)); break; case COMMAND_EXIT: @@ -802,6 +822,7 @@ pam_server(int fd, const char *service, int verb, const struct name_value_list * } done: + plugin_secure_memzero(up.password, sizeof(up.password)); #ifdef USE_PAM_DLOPEN dlclose_pam(); #endif diff --git a/src/plugins/auth-pam/auth-pam.exports b/src/plugins/auth-pam/auth-pam.exports index b07937cc30e..597e33f6a21 100644 --- a/src/plugins/auth-pam/auth-pam.exports +++ b/src/plugins/auth-pam/auth-pam.exports @@ -1,4 +1,4 @@ -openvpn_plugin_open_v1 +openvpn_plugin_open_v3 openvpn_plugin_func_v1 openvpn_plugin_close_v1 openvpn_plugin_abort_v1 From 9444506e45df86e6c8fbabfbf4a97c538cd971f4 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Tue, 9 May 2017 20:42:48 +0200 Subject: [PATCH 522/643] Document tls-crypt security considerations in man page The tls-crypt commit message contained an elaborate discussion on the function's security properties. This commit adds the gist of that discussion, "rotate keys periodically" to the man page. (The 'real' solution will follow later: add support for per-client tls-crypt keys. That will make tls-crypt useful for VPN providers too.) Note to non-crypto-geek reviewers: please verify that this text is clear enough to explain you when you need to replace tls-crypt keys. Note to crypto-geek reviewers: please check the numbers - see the --tls-crypt commit message (c6e24fa3) for details. [DS: Fixed a few typos on-the-fly during commit] Signed-off-by: Steffan Karger Acked-by: Selva Nair Message-Id: <1494355368-20238-1-git-send-email-steffan.karger@fox-it.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14610.html Signed-off-by: David Sommerseth (cherry picked from commit 5806f66eb927a6a698c0f067f563d7bc2203a376) --- doc/openvpn.8 | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index a9f5db7c750..3a0fa9b28f4 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -5091,6 +5091,29 @@ In contrast to .B \-\-tls\-crypt does *not* require the user to set .B \-\-key\-direction\fR. + +.B Security Considerations + +All peers use the same +.B \-\-tls-crypt +pre-shared group key to authenticate and encrypt control channel messages. To +ensure that IV collisions remain unlikely, this key should not be used to +encrypt more than 2^48 client-to-server or 2^48 server-to-client control +channel messages. A typical initial negotiation is about 10 packets in each +direction. Assuming both initial negotiation and renegotiations are at most +2^16 (65536) packets (to be conservative), and (re)negotiations happen each +minute for each user (24/7), this limits the tls\-crypt key lifetime to 8171 +years divided by the number of users. So a setup with 1000 users should rotate +the key at least once each eight years. (And a setup with 8000 users each +year.) + +If IV collisions were to occur, this could result in the security of +.B \-\-tls\-crypt +degrading to the same security as using +.B \-\-tls\-auth\fR. +That is, the control channel still benefits from the extra protection against +active man-in-the-middle-attacks and DoS attacks, but may no longer offer +extra privacy and post-quantum security on top of what TLS itself offers. .\"********************************************************* .TP .B \-\-askpass [file] From 66b99a0753352c5cc43e11e39835b6423112df98 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Tue, 9 May 2017 21:30:08 +0200 Subject: [PATCH 523/643] Don't assert out on receiving too-large control packets (CVE-2017-7478) Commit 3c1b19e0 changed the maximum size of accepted control channel packets. This was needed for crypto negotiation (which is needed for a nice transition to a new default cipher), but exposed a DoS vulnerability. The vulnerability was found during the OpenVPN 2.4 code audit by Quarkslab (commisioned by OSTIF). To fix the issue, we should not ASSERT() on external input (in this case the received packet size), but instead gracefully error out and drop the invalid packet. CVE: 2017-7478 Signed-off-by: Steffan Karger Acked-by: David Sommerseth Message-Id: <1494358209-4568-2-git-send-email-steffan.karger@fox-it.com> URL: http://www.mail-archive.com/search?l=mid&q=1494358209-4568-2-git-send-email-steffan.karger@fox-it.com Signed-off-by: David Sommerseth (cherry picked from commit 5774cf4c25e1d8bf4e544702db8f157f111c9d93) --- Changes.rst | 8 ++++++++ src/openvpn/ssl.c | 7 ++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Changes.rst b/Changes.rst index 3dba7e0ef51..734ef7310ca 100644 --- a/Changes.rst +++ b/Changes.rst @@ -327,3 +327,11 @@ Bugfixes -------- - Fix memory leak introduced in 2.4.1: if --remote-cert-tls is used, we leaked some memory on each TLS (re)negotiation. + +Security +-------- +- Fix a pre-authentication denial-of-service attack on both clients and servers. + By sending a too-large control packet, OpenVPN 2.4.0 or 2.4.1 can be forced + to hit an ASSERT() and stop the process. If ``--tls-auth`` or ``--tls-crypt`` + is used, only attackers that have the ``--tls-auth`` or ``--tls-crypt`` key + can mount an attack. (OSTIF/Quarkslab audit finding 5.1, CVE-2017-7478) diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index d2f4730bfb4..51c7b95fe35 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -3720,7 +3720,12 @@ tls_pre_decrypt(struct tls_multi *multi, /* Save incoming ciphertext packet to reliable buffer */ struct buffer *in = reliable_get_buf(ks->rec_reliable); ASSERT(in); - ASSERT(buf_copy(in, buf)); + if(!buf_copy(in, buf)) + { + msg(D_MULTI_DROPPED, + "Incoming control channel packet too big, dropping."); + goto error; + } reliable_mark_active_incoming(ks->rec_reliable, in, id, op); } From 591a4e574c43cb9e820950f15dcaabda261def78 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Tue, 9 May 2017 21:30:09 +0200 Subject: [PATCH 524/643] Drop packets instead of assert out if packet id rolls over (CVE-2017-7479) Previously, if a mode was selected where packet ids are not allowed to roll over, but renegotiation does not succeed for some reason (e.g. no password entered in time, certificate expired or a malicious peer that refuses the renegotiaion on purpose) we would continue to use the old keys. Until the packet ID would roll over and we would ASSERT() out. Given that this can be triggered on purpose by an authenticated peer, this is a fix for an authenticated remote DoS vulnerability. An attack is rather inefficient though; a peer would need to get us to send 2^32 packets (min-size packet is IP+UDP+OPCODE+PID+TAG (no payload), results in (20+8+1+4+16)*2^32 bytes, or approx. 196 GB). This is a fix for finding 5.2 from the OSTIF / Quarkslab audit. CVE: 2017-7479 Signed-off-by: Steffan Karger Acked-by: Gert Doering Acked-by: David Sommerseth Message-Id: <1494358209-4568-3-git-send-email-steffan.karger@fox-it.com> URL: http://www.mail-archive.com/search?l=mid&q=1494358209-4568-3-git-send-email-steffan.karger@fox-it.com Signed-off-by: David Sommerseth (cherry picked from commit e498cb0ea8d3a451b39eaf6f9b6a7488f18250b8) --- Changes.rst | 4 ++++ src/openvpn/crypto.c | 25 +++++++++++++++-------- src/openvpn/packet_id.c | 22 ++++++++++++++------ src/openvpn/packet_id.h | 1 + src/openvpn/tls_crypt.c | 6 +++++- tests/unit_tests/openvpn/test_packet_id.c | 11 ++++++++-- 6 files changed, 51 insertions(+), 18 deletions(-) diff --git a/Changes.rst b/Changes.rst index 734ef7310ca..5a02ad0d931 100644 --- a/Changes.rst +++ b/Changes.rst @@ -335,3 +335,7 @@ Security to hit an ASSERT() and stop the process. If ``--tls-auth`` or ``--tls-crypt`` is used, only attackers that have the ``--tls-auth`` or ``--tls-crypt`` key can mount an attack. (OSTIF/Quarkslab audit finding 5.1, CVE-2017-7478) +- Fix an authenticated remote DoS vulnerability that could be triggered by + causing a packet id roll over. An attack is rather inefficient; a peer + would need to get us to send at least about 196 GB of data. + (OSTIF/Quarkslab audit finding 5.2, CVE-2017-7479) diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c index ced6b2cf01d..4b5427917fc 100644 --- a/src/openvpn/crypto.c +++ b/src/openvpn/crypto.c @@ -94,7 +94,11 @@ openvpn_encrypt_aead(struct buffer *buf, struct buffer work, buf_set_write(&iv_buffer, iv, iv_len); /* IV starts with packet id to make the IV unique for packet */ - ASSERT(packet_id_write(&opt->packet_id.send, &iv_buffer, false, false)); + if (!packet_id_write(&opt->packet_id.send, &iv_buffer, false, false)) + { + msg(D_CRYPT_ERRORS, "ENCRYPT ERROR: packet ID roll over"); + goto err; + } /* Remainder of IV consists of implicit part (unique per session) */ ASSERT(buf_write(&iv_buffer, ctx->implicit_iv, ctx->implicit_iv_len)); @@ -195,11 +199,13 @@ openvpn_encrypt_v1(struct buffer *buf, struct buffer work, } /* Put packet ID in plaintext buffer */ - if (packet_id_initialized(&opt->packet_id)) + if (packet_id_initialized(&opt->packet_id) + && !packet_id_write(&opt->packet_id.send, buf, + opt->flags & CO_PACKET_ID_LONG_FORM, + true)) { - ASSERT(packet_id_write(&opt->packet_id.send, buf, - opt->flags & CO_PACKET_ID_LONG_FORM, - true)); + msg(D_CRYPT_ERRORS, "ENCRYPT ERROR: packet ID roll over"); + goto err; } } else if (cipher_kt_mode_ofb_cfb(cipher_kt)) @@ -259,11 +265,12 @@ openvpn_encrypt_v1(struct buffer *buf, struct buffer work, } else /* No Encryption */ { - if (packet_id_initialized(&opt->packet_id)) + if (packet_id_initialized(&opt->packet_id) + && !packet_id_write(&opt->packet_id.send, buf, + opt->flags & CO_PACKET_ID_LONG_FORM, true)) { - ASSERT(packet_id_write(&opt->packet_id.send, buf, - BOOL_CAST(opt->flags & CO_PACKET_ID_LONG_FORM), - true)); + msg(D_CRYPT_ERRORS, "ENCRYPT ERROR: packet ID roll over"); + goto err; } if (ctx->hmac) { diff --git a/src/openvpn/packet_id.c b/src/openvpn/packet_id.c index 5175fb08dfb..10fe402d6a5 100644 --- a/src/openvpn/packet_id.c +++ b/src/openvpn/packet_id.c @@ -325,27 +325,37 @@ packet_id_read(struct packet_id_net *pin, struct buffer *buf, bool long_form) return true; } -static void +static bool packet_id_send_update(struct packet_id_send *p, bool long_form) { if (!p->time) { p->time = now; } - p->id++; - if (!p->id) + if (p->id == PACKET_ID_MAX) { - ASSERT(long_form); + /* Packet ID only allowed to roll over if using long form and time has + * moved forward since last roll over. + */ + if (!long_form || now <= p->time) + { + return false; + } p->time = now; - p->id = 1; + p->id = 0; } + p->id++; + return true; } bool packet_id_write(struct packet_id_send *p, struct buffer *buf, bool long_form, bool prepend) { - packet_id_send_update(p, long_form); + if (!packet_id_send_update(p, long_form)) + { + return false; + } const packet_id_type net_id = htonpid(p->id); const net_time_t net_time = htontime(p->time); diff --git a/src/openvpn/packet_id.h b/src/openvpn/packet_id.h index 109e56aad5a..aceacf8a6d5 100644 --- a/src/openvpn/packet_id.h +++ b/src/openvpn/packet_id.h @@ -50,6 +50,7 @@ * to for network transmission. */ typedef uint32_t packet_id_type; +#define PACKET_ID_MAX UINT32_MAX typedef uint32_t net_time_t; /* diff --git a/src/openvpn/tls_crypt.c b/src/openvpn/tls_crypt.c index e47d25cb73f..7f59b1d67cf 100644 --- a/src/openvpn/tls_crypt.c +++ b/src/openvpn/tls_crypt.c @@ -98,7 +98,11 @@ tls_crypt_wrap(const struct buffer *src, struct buffer *dst, format_hex(BPTR(src), BLEN(src), 80, &gc)); /* Get packet ID */ - ASSERT(packet_id_write(&opt->packet_id.send, dst, true, false)); + if (!packet_id_write(&opt->packet_id.send, dst, true, false)) + { + msg(D_CRYPT_ERRORS, "TLS-CRYPT ERROR: packet ID roll over."); + goto err; + } dmsg(D_PACKET_CONTENT, "TLS-CRYPT WRAP AD: %s", format_hex(BPTR(dst), BLEN(dst), 0, &gc)); diff --git a/tests/unit_tests/openvpn/test_packet_id.c b/tests/unit_tests/openvpn/test_packet_id.c index 5627a5b658e..0a785adba0d 100644 --- a/tests/unit_tests/openvpn/test_packet_id.c +++ b/tests/unit_tests/openvpn/test_packet_id.c @@ -129,8 +129,7 @@ test_packet_id_write_short_wrap(void **state) struct test_packet_id_write_data *data = *state; data->pis.id = ~0; - expect_assert_failure( - packet_id_write(&data->pis, &data->test_buf, false, false)); + assert_false(packet_id_write(&data->pis, &data->test_buf, false, false)); } static void @@ -139,8 +138,16 @@ test_packet_id_write_long_wrap(void **state) struct test_packet_id_write_data *data = *state; data->pis.id = ~0; + data->pis.time = 5006; + + /* Write fails if time did not change */ + now = 5006; + assert_false(packet_id_write(&data->pis, &data->test_buf, true, false)); + + /* Write succeeds if time moved forward */ now = 5010; assert_true(packet_id_write(&data->pis, &data->test_buf, true, false)); + assert(data->pis.id == 1); assert(data->pis.time == now); assert_true(data->test_buf_data.buf_id == htonl(1)); From 3c28855760c389d15384238d0e089132da98949b Mon Sep 17 00:00:00 2001 From: ValdikSS Date: Wed, 10 May 2017 21:47:53 +0300 Subject: [PATCH 525/643] Set a low interface metric for tap adapter when block-outside-dns is in use Windows 10 before Creators Update used to resolve DNS using all available adapters and IP addresses in parallel. Now it still resolves addresses using all available adapters but in a round-robin way, beginning with random adapter. This behaviour introduces significant delay when block-outside-dns is in use. Fortunately, setting low metric for the TAP interface solves this issue, making Windows always pick TAP adapter first and disable round-robin. Signed-off-by: ValdikSS Acked-by: Selva Nair Message-Id: <20170510184753.27145-1-valdikss@gmail.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14624.html Signed-off-by: David Sommerseth (cherry picked from commit 27aa87283f6e766507287649aa5a63f1f5172645) --- src/openvpn/block_dns.c | 78 +++++++++++++++++++++++++++++++++++ src/openvpn/block_dns.h | 30 ++++++++++++++ src/openvpn/init.c | 4 +- src/openvpn/win32.c | 39 +++++++++++++++++- src/openvpn/win32.h | 2 +- src/openvpnserv/interactive.c | 70 ++++++++++++++++++++++++++++--- 6 files changed, 213 insertions(+), 10 deletions(-) diff --git a/src/openvpn/block_dns.c b/src/openvpn/block_dns.c index e31765eed63..d916aff2865 100644 --- a/src/openvpn/block_dns.c +++ b/src/openvpn/block_dns.c @@ -110,6 +110,9 @@ DEFINE_GUID( static WCHAR *FIREWALL_NAME = L"OpenVPN"; +VOID NETIOAPI_API_ +InitializeIpInterfaceEntry(PMIB_IPINTERFACE_ROW Row); + /* * Default msg handler does nothing */ @@ -341,4 +344,79 @@ delete_block_dns_filters(HANDLE engine_handle) return err; } +/* + * Returns interface metric value for specified interface index. + * + * Arguments: + * index : The index of TAP adapter. + * family : Address family (AF_INET for IPv4 and AF_INET6 for IPv6). + * Returns positive metric value or zero for automatic metric on success, + * a less then zero error code on failure. + */ + +int +get_interface_metric(const NET_IFINDEX index, const ADDRESS_FAMILY family) +{ + DWORD err = 0; + MIB_IPINTERFACE_ROW ipiface; + InitializeIpInterfaceEntry(&ipiface); + ipiface.Family = family; + ipiface.InterfaceIndex = index; + err = GetIpInterfaceEntry(&ipiface); + if (err == NO_ERROR) + { + if (ipiface.UseAutomaticMetric) + { + return 0; + } + return ipiface.Metric; + } + return -err; +} + +/* + * Sets interface metric value for specified interface index. + * + * Arguments: + * index : The index of TAP adapter. + * family : Address family (AF_INET for IPv4 and AF_INET6 for IPv6). + * metric : Metric value. 0 for automatic metric. + * Returns 0 on success, a non-zero status code of the last failed action on failure. + */ + +DWORD +set_interface_metric(const NET_IFINDEX index, const ADDRESS_FAMILY family, + const ULONG metric) +{ + DWORD err = 0; + MIB_IPINTERFACE_ROW ipiface; + InitializeIpInterfaceEntry(&ipiface); + ipiface.Family = family; + ipiface.InterfaceIndex = index; + err = GetIpInterfaceEntry(&ipiface); + if (err == NO_ERROR) + { + if (family == AF_INET) + { + /* required for IPv4 as per MSDN */ + ipiface.SitePrefixLength = 0; + } + ipiface.Metric = metric; + if (metric == 0) + { + ipiface.UseAutomaticMetric = TRUE; + } + else + { + ipiface.UseAutomaticMetric = FALSE; + } + err = SetIpInterfaceEntry(&ipiface); + if (err == NO_ERROR) + { + return 0; + } + } + return err; +} + #endif /* ifdef _WIN32 */ diff --git a/src/openvpn/block_dns.h b/src/openvpn/block_dns.h index a7dadc46812..dc607ff6dad 100644 --- a/src/openvpn/block_dns.h +++ b/src/openvpn/block_dns.h @@ -27,6 +27,9 @@ #ifndef OPENVPN_BLOCK_DNS_H #define OPENVPN_BLOCK_DNS_H +/* Any value less than 5 should work fine. 3 is choosen without any real reason. */ +#define BLOCK_DNS_IFACE_METRIC 3 + typedef void (*block_dns_msg_handler_t) (DWORD err, const char *msg); DWORD @@ -36,5 +39,32 @@ DWORD add_block_dns_filters(HANDLE *engine, int iface_index, const WCHAR *exe_path, block_dns_msg_handler_t msg_handler_callback); +/** + * Returns interface metric value for specified interface index. + * + * @param index The index of TAP adapter + * @param family Address family (AF_INET for IPv4 and AF_INET6 for IPv6) + * + * @return positive metric value or zero for automatic metric on success, + * a less then zero error code on failure. + */ + +int +get_interface_metric(const NET_IFINDEX index, const ADDRESS_FAMILY family); + +/** + * Sets interface metric value for specified interface index. + * + * @param index The index of TAP adapter + * @param family Address family (AF_INET for IPv4 and AF_INET6 for IPv6) + * @param metric Metric value. 0 for automatic metric + * + * @return 0 on success, a non-zero status code of the last failed action on failure. + */ + +DWORD +set_interface_metric(const NET_IFINDEX index, const ADDRESS_FAMILY family, + const ULONG metric); + #endif #endif diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 607e2a5b7e6..66126ef740e 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -1837,7 +1837,7 @@ do_close_tun(struct context *c, bool force) #if defined(_WIN32) if (c->options.block_outside_dns) { - if (!win_wfp_uninit(c->options.msg_channel)) + if (!win_wfp_uninit(adapter_index, c->options.msg_channel)) { msg(M_FATAL, "Uninitialising WFP failed!"); } @@ -1877,7 +1877,7 @@ do_close_tun(struct context *c, bool force) #if defined(_WIN32) if (c->options.block_outside_dns) { - if (!win_wfp_uninit(c->options.msg_channel)) + if (!win_wfp_uninit(adapter_index, c->options.msg_channel)) { msg(M_FATAL, "Uninitialising WFP failed!"); } diff --git a/src/openvpn/win32.c b/src/openvpn/win32.c index 18e7aee187c..0cbf5fde5a7 100644 --- a/src/openvpn/win32.c +++ b/src/openvpn/win32.c @@ -60,6 +60,12 @@ */ static HANDLE m_hEngineHandle = NULL; /* GLOBAL */ +/* + * TAP adapter original metric value + */ +static int tap_metric_v4 = -1; /* GLOBAL */ +static int tap_metric_v6 = -1; /* GLOBAL */ + /* * Windows internal socket API state (opaque). */ @@ -1337,6 +1343,27 @@ win_wfp_block_dns(const NET_IFINDEX index, const HANDLE msg_channel) status = add_block_dns_filters(&m_hEngineHandle, index, openvpnpath, block_dns_msg_handler); + if (status == 0) + { + tap_metric_v4 = get_interface_metric(index, AF_INET); + tap_metric_v6 = get_interface_metric(index, AF_INET6); + if (tap_metric_v4 < 0) + { + /* error, should not restore metric */ + tap_metric_v4 = -1; + } + if (tap_metric_v6 < 0) + { + /* error, should not restore metric */ + tap_metric_v6 = -1; + } + status = set_interface_metric(index, AF_INET, BLOCK_DNS_IFACE_METRIC); + if (!status) + { + set_interface_metric(index, AF_INET6, BLOCK_DNS_IFACE_METRIC); + } + } + ret = (status == 0); out: @@ -1345,19 +1372,27 @@ win_wfp_block_dns(const NET_IFINDEX index, const HANDLE msg_channel) } bool -win_wfp_uninit(const HANDLE msg_channel) +win_wfp_uninit(const NET_IFINDEX index, const HANDLE msg_channel) { dmsg(D_LOW, "Uninitializing WFP"); if (msg_channel) { msg(D_LOW, "Using service to delete block dns filters"); - win_block_dns_service(false, -1, msg_channel); + win_block_dns_service(false, index, msg_channel); } else { delete_block_dns_filters(m_hEngineHandle); m_hEngineHandle = NULL; + if (tap_metric_v4 >= 0) + { + set_interface_metric(index, AF_INET, tap_metric_v4); + } + if (tap_metric_v6 >= 0) + { + set_interface_metric(index, AF_INET6, tap_metric_v6); + } } return true; diff --git a/src/openvpn/win32.h b/src/openvpn/win32.h index 4ee44fd3606..cd1f101c2d4 100644 --- a/src/openvpn/win32.h +++ b/src/openvpn/win32.h @@ -293,7 +293,7 @@ WCHAR *wide_string(const char *utf8, struct gc_arena *gc); bool win_wfp_block_dns(const NET_IFINDEX index, const HANDLE msg_channel); -bool win_wfp_uninit(const HANDLE msg_channel); +bool win_wfp_uninit(const NET_IFINDEX index, const HANDLE msg_channel); #define WIN_XP 0 #define WIN_VISTA 1 diff --git a/src/openvpnserv/interactive.c b/src/openvpnserv/interactive.c index 2bce598a77b..68ab0576be0 100644 --- a/src/openvpnserv/interactive.c +++ b/src/openvpnserv/interactive.c @@ -94,6 +94,13 @@ typedef enum { } undo_type_t; typedef list_item_t *undo_lists_t[_undo_type_max]; +typedef struct { + HANDLE engine; + int index; + int metric_v4; + int metric_v6; +} block_dns_data_t; + static DWORD AddListItem(list_item_t **pfirst, LPVOID data) @@ -885,6 +892,7 @@ static DWORD HandleBlockDNSMessage(const block_dns_message_t *msg, undo_lists_t *lists) { DWORD err = 0; + block_dns_data_t *interface_data; HANDLE engine = NULL; LPCWSTR exe_path; @@ -901,16 +909,57 @@ HandleBlockDNSMessage(const block_dns_message_t *msg, undo_lists_t *lists) err = add_block_dns_filters(&engine, msg->iface.index, exe_path, BlockDNSErrHandler); if (!err) { - err = AddListItem(&(*lists)[block_dns], engine); + interface_data = malloc(sizeof(block_dns_data_t)); + if (!interface_data) + { + return ERROR_OUTOFMEMORY; + } + interface_data->engine = engine; + interface_data->index = msg->iface.index; + interface_data->metric_v4 = get_interface_metric(msg->iface.index, + AF_INET); + if (interface_data->metric_v4 < 0) + { + interface_data->metric_v4 = -1; + } + interface_data->metric_v6 = get_interface_metric(msg->iface.index, + AF_INET6); + if (interface_data->metric_v6 < 0) + { + interface_data->metric_v6 = -1; + } + err = AddListItem(&(*lists)[block_dns], interface_data); + if (!err) + { + err = set_interface_metric(msg->iface.index, AF_INET, + BLOCK_DNS_IFACE_METRIC); + if (!err) + { + set_interface_metric(msg->iface.index, AF_INET6, + BLOCK_DNS_IFACE_METRIC); + } + } } } else { - engine = RemoveListItem(&(*lists)[block_dns], CmpEngine, NULL); - if (engine) + interface_data = RemoveListItem(&(*lists)[block_dns], CmpEngine, NULL); + if (interface_data) { + engine = interface_data->engine; err = delete_block_dns_filters(engine); engine = NULL; + if (interface_data->metric_v4 >= 0) + { + set_interface_metric(msg->iface.index, AF_INET, + interface_data->metric_v4); + } + if (interface_data->metric_v6 >= 0) + { + set_interface_metric(msg->iface.index, AF_INET6, + interface_data->metric_v6); + } + free(interface_data); } else { @@ -1325,6 +1374,7 @@ static VOID Undo(undo_lists_t *lists) { undo_type_t type; + block_dns_data_t *interface_data; for (type = 0; type < _undo_type_max; type++) { list_item_t **pnext = &(*lists)[type]; @@ -1350,8 +1400,18 @@ Undo(undo_lists_t *lists) break; case block_dns: - delete_block_dns_filters(item->data); - item->data = NULL; + interface_data = (block_dns_data_t*)(item->data); + delete_block_dns_filters(interface_data->engine); + if (interface_data->metric_v4 >= 0) + { + set_interface_metric(interface_data->index, AF_INET, + interface_data->metric_v4); + } + if (interface_data->metric_v6 >= 0) + { + set_interface_metric(interface_data->index, AF_INET6, + interface_data->metric_v6); + } break; } From 85161685f42f2d8c69604e0825e75fe1287e57bd Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Thu, 11 May 2017 02:41:34 +0200 Subject: [PATCH 526/643] Preparing v2.4.2 release Signed-off-by: David Sommerseth --- ChangeLog | 29 +++++++++++++++++++++++++++++ version.m4 | 4 ++-- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 450e0f53da5..00c2e2f86c8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,35 @@ OpenVPN Change Log Copyright (C) 2002-2017 OpenVPN Technologies, Inc. +2017.05.11 -- Version 2.4.2 +David Sommerseth (5): + auth-token: Ensure tokens are always wiped on de-auth + docs: Fixed man-page warnings discoverd by rpmlint + Make --cipher/--auth none more explicit on the risks + plugin: Fix documentation typo for type_mask + plugin: Export secure_memzero() to plug-ins + +Hristo Venev (1): + Fix extract_x509_field_ssl for external objects, v2 + +Selva Nair (1): + In auth-pam plugin clear the password after use + +Steffan Karger (10): + cleanup: merge packet_id_alloc_outgoing() into packet_id_write() + Don't run packet_id unit tests for --disable-crypto builds + Fix Changes.rst layout + Fix memory leak in x509_verify_cert_ku() + mbedtls: correctly check return value in pkcs11_certificate_dn() + Restore pre-NCP frame parameters for new sessions + Always clear username/password from memory on error + Document tls-crypt security considerations in man page + Don't assert out on receiving too-large control packets (CVE-2017-7478) + Drop packets instead of assert out if packet id rolls over (CVE-2017-7479) + +ValdikSS (1): + Set a low interface metric for tap adapter when block-outside-dns is in use + 2017.03.21 -- Version 2.4.1 Antonio Quartulli (4): attempt to add IPv6 route even when no IPv6 address was configured diff --git a/version.m4 b/version.m4 index 9636f739a7d..73ca1e89151 100644 --- a/version.m4 +++ b/version.m4 @@ -3,12 +3,12 @@ define([PRODUCT_NAME], [OpenVPN]) define([PRODUCT_TARNAME], [openvpn]) define([PRODUCT_VERSION_MAJOR], [2]) define([PRODUCT_VERSION_MINOR], [4]) -define([PRODUCT_VERSION_PATCH], [.1]) +define([PRODUCT_VERSION_PATCH], [.2]) m4_append([PRODUCT_VERSION], [PRODUCT_VERSION_MAJOR]) m4_append([PRODUCT_VERSION], [PRODUCT_VERSION_MINOR], [[.]]) m4_append([PRODUCT_VERSION], [PRODUCT_VERSION_PATCH], [[]]) define([PRODUCT_BUGREPORT], [openvpn-users@lists.sourceforge.net]) -define([PRODUCT_VERSION_RESOURCE], [2,4,1,0]) +define([PRODUCT_VERSION_RESOURCE], [2,4,2,0]) dnl define the TAP version define([PRODUCT_TAP_WIN_COMPONENT_ID], [tap0901]) define([PRODUCT_TAP_WIN_MIN_MAJOR], [9]) From 9092397ce02616b06c5c748de0b45775c7aa1e73 Mon Sep 17 00:00:00 2001 From: Selva Nair Date: Thu, 11 May 2017 21:32:34 -0400 Subject: [PATCH 527/643] Pass correct buffer size to GetModuleFileNameW() Fixes finding 5.6 of OSTIF/Quarkslab audit Signed-off-by: Selva Nair Acked-by: Gert Doering Message-Id: <1494552754-30060-1-git-send-email-selva.nair@gmail.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14647.html Signed-off-by: Gert Doering (cherry picked from commit 986b930862c7fecb2a42645f1dc23a53ab2cf6bb) --- src/openvpn/win32.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/openvpn/win32.c b/src/openvpn/win32.c index 0cbf5fde5a7..9a0368144f7 100644 --- a/src/openvpn/win32.c +++ b/src/openvpn/win32.c @@ -1334,8 +1334,8 @@ win_wfp_block_dns(const NET_IFINDEX index, const HANDLE msg_channel) goto out; } - status = GetModuleFileNameW(NULL, openvpnpath, sizeof(openvpnpath)); - if (status == 0 || status == sizeof(openvpnpath)) + status = GetModuleFileNameW(NULL, openvpnpath, _countof(openvpnpath)); + if (status == 0 || status == _countof(openvpnpath)) { msg(M_WARN|M_ERRNO, "block_dns: cannot get executable path"); goto out; From 4ae06ef696638efcf4cd045e4541877ef5a92e68 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Mon, 15 May 2017 16:43:55 +0200 Subject: [PATCH 528/643] Log the negotiated (NCP) cipher To make it clear that NCP is in effect, print a log message (at --verb 2) to show that we selected a cipher using NCP. Signed-off-by: Steffan Karger Acked-by: Arne Schwabe Message-Id: <1494859435-16379-1-git-send-email-steffan.karger@fox-it.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14656.html Signed-off-by: Gert Doering (cherry picked from commit d4071dd1553ea5a70ab03659c623ff2ceeefaf9e) --- src/openvpn/ssl.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 51c7b95fe35..4be720edaa3 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -1959,6 +1959,12 @@ tls_session_update_crypto_params(struct tls_session *session, return false; } + if (strcmp(options->ciphername, session->opt->config_ciphername)) + { + msg(D_HANDSHAKE, "Data Channel: using negotiated cipher '%s'", + options->ciphername); + } + init_key_type(&session->opt->key_type, options->ciphername, options->authname, options->keysize, true, true); From 37b3409681ee04b7cb7c246a7fd701a883e582e2 Mon Sep 17 00:00:00 2001 From: Matthias Andree Date: Mon, 15 May 2017 23:48:45 +0200 Subject: [PATCH 529/643] Make openvpn-plugin.h self-contained again. 2.4.2 introduced a declaration that references size_t, so use the C99 way of declaring it, and add #include . Note this may break on non-C99-compliant versions of MS Visual Studio. Signed-off-by: Matthias Andree Acked-by: Gert Doering Message-Id: <1494884925-12539-1-git-send-email-matthias.andree@gmx.de> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14658.html Signed-off-by: Gert Doering (cherry picked from commit cf9deedf425c945906d5cc482fb962796d21f123) --- include/openvpn-plugin.h.in | 1 + 1 file changed, 1 insertion(+) diff --git a/include/openvpn-plugin.h.in b/include/openvpn-plugin.h.in index 5e6f874375e..aa71b497461 100644 --- a/include/openvpn-plugin.h.in +++ b/include/openvpn-plugin.h.in @@ -44,6 +44,7 @@ typedef X509 openvpn_x509_cert_t; #endif #include +#include #ifdef __cplusplus extern "C" { From 5d5437710c282b1a60a892d1910160027a81db92 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Thu, 4 May 2017 22:42:01 +0200 Subject: [PATCH 530/643] crypto: Enable SHA256 fingerprint checking in --verify-hash This enhances --verify-hash with an optional algorithm flag. If not provided, it defaults to SHA1 to preserve backwards compatbilitity with existing configurations. The only valid flags are SHA1 and SHA256. In addition enhance the layout of the --verify-hash section in the man page. Signed-off-by: David Sommerseth Acked-by: Steffan Karger Message-Id: <20170504204201.1257-1-davids@openvpn.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14538.html Signed-off-by: Gert Doering (cherry picked from commit 2193d7c08484d56ed07ba2e649abc2d08adcb245) --- Changes.rst | 5 +++++ doc/openvpn.8 | 18 +++++++++++++++--- src/openvpn/crypto_backend.h | 6 ++++++ src/openvpn/init.c | 1 + src/openvpn/options.c | 22 +++++++++++++++++++--- src/openvpn/options.h | 5 +++++ src/openvpn/ssl_common.h | 1 + src/openvpn/ssl_verify.c | 27 +++++++++++++++++++++++++-- 8 files changed, 77 insertions(+), 8 deletions(-) diff --git a/Changes.rst b/Changes.rst index 5a02ad0d931..fbe0fc46f9a 100644 --- a/Changes.rst +++ b/Changes.rst @@ -303,6 +303,11 @@ Maintainer-visible changes use -std=gnu99 in CFLAGS. This is known to be needed when doing i386/i686 builds on RHEL5. +Version 2.4.3 +============= +- ``--verify-hash`` can now take an optional flag which changes the hashing + algorithm. It can be either SHA1 or SHA256. The default if not provided is + SHA1 to preserve backwards compatibility with existing configurations. Version 2.4.1 ============= diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 3a0fa9b28f4..7cacc3ad35f 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -4695,15 +4695,27 @@ and Not available with PolarSSL. .\"********************************************************* .TP -.B \-\-verify\-hash hash -Specify SHA1 fingerprint for level-1 cert. The level-1 cert is the +.B \-\-verify\-hash hash [algo] +Specify SHA1 or SHA256 fingerprint for level-1 cert. The level-1 cert is the CA (or intermediate cert) that signs the leaf certificate, and is one removed from the leaf certificate in the direction of the root. When accepting a connection from a peer, the level-1 cert fingerprint must match .B hash or certificate verification will fail. Hash is specified -as XX:XX:... For example: AD:B0:95:D8:09:C8:36:45:12:A9:89:C8:90:09:CB:13:72:A6:AD:16 +as XX:XX:... For example: + +.nf +.ft 3 +.in +4 +AD:B0:95:D8:09:C8:36:45:12:A9:89:C8:90:09:CB:13:72:A6:AD:16 +.in -4 +.ft +.fi + +The +.B algo +flag can be either SHA1 or SHA256. If not provided, it defaults to SHA1. .\"********************************************************* .TP .B \-\-pkcs11\-cert\-private [0|1]... diff --git a/src/openvpn/crypto_backend.h b/src/openvpn/crypto_backend.h index 2c79baa15c2..9b113d7b933 100644 --- a/src/openvpn/crypto_backend.h +++ b/src/openvpn/crypto_backend.h @@ -47,6 +47,12 @@ /* Maximum HMAC digest size (bytes) */ #define OPENVPN_MAX_HMAC_SIZE 64 +/** Types referencing specific message digest hashing algorithms */ +typedef enum { + MD_SHA1, + MD_SHA256 +} hash_algo_type ; + /** Struct used in cipher name translation table */ typedef struct { const char *openvpn_name; /**< Cipher name used by OpenVPN */ diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 66126ef740e..90d8314a356 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -2632,6 +2632,7 @@ do_init_crypto_tls(struct context *c, const unsigned int flags) memmove(to.remote_cert_ku, options->remote_cert_ku, sizeof(to.remote_cert_ku)); to.remote_cert_eku = options->remote_cert_eku; to.verify_hash = options->verify_hash; + to.verify_hash_algo = options->verify_hash_algo; #ifdef ENABLE_X509ALTUSERNAME to.x509_username_field = (char *) options->x509_username_field; #else diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 9fef3945175..4ce46b147f7 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -592,7 +592,8 @@ static const char usage_message[] = "--x509-username-field : Field in x509 certificate containing the username.\n" " Default is CN in the Subject field.\n" #endif - "--verify-hash : Specify SHA1 fingerprint for level-1 cert.\n" + "--verify-hash hash [algo] : Specify fingerprint for level-1 certificate.\n" + " Valid algo flags are SHA1 and SHA256. \n" #ifdef _WIN32 "--cryptoapicert select-string : Load the certificate and private key from the\n" " Windows Certificate System Store.\n" @@ -7703,10 +7704,25 @@ add_option(struct options *options, options->extra_certs_file_inline = p[2]; } } - else if (streq(p[0], "verify-hash") && p[1] && !p[2]) + else if (streq(p[0], "verify-hash") && p[1] && !p[3]) { VERIFY_PERMISSION(OPT_P_GENERAL); - options->verify_hash = parse_hash_fingerprint(p[1], SHA_DIGEST_LENGTH, msglevel, &options->gc); + + if (!p[2] || (p[2] && streq(p[2], "SHA1"))) + { + options->verify_hash = parse_hash_fingerprint(p[1], SHA_DIGEST_LENGTH, msglevel, &options->gc); + options->verify_hash_algo = MD_SHA1; + } + else if (p[2] && streq(p[2], "SHA256")) + { + options->verify_hash = parse_hash_fingerprint(p[1], SHA256_DIGEST_LENGTH, msglevel, &options->gc); + options->verify_hash_algo = MD_SHA256; + } + else + { + msg(msglevel, "invalid or unsupported hashing algorithm: %s (only SHA1 and SHA256 are valid)", p[2]); + goto err; + } } #ifdef ENABLE_CRYPTOAPI else if (streq(p[0], "cryptoapicert") && p[1] && !p[2]) diff --git a/src/openvpn/options.h b/src/openvpn/options.h index b3ab0293463..1d598fc3fb3 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -42,6 +42,10 @@ #include "comp.h" #include "pushlist.h" #include "clinat.h" +#ifdef ENABLE_CRYPTO +#include "crypto_backend.h" +#endif + /* * Maximum number of parameters associated with an option, @@ -519,6 +523,7 @@ struct options unsigned remote_cert_ku[MAX_PARMS]; const char *remote_cert_eku; uint8_t *verify_hash; + hash_algo_type verify_hash_algo; unsigned int ssl_flags; /* set to SSLF_x flags from ssl.h */ #ifdef ENABLE_PKCS11 diff --git a/src/openvpn/ssl_common.h b/src/openvpn/ssl_common.h index 9a16d77e2be..a99d24d652a 100644 --- a/src/openvpn/ssl_common.h +++ b/src/openvpn/ssl_common.h @@ -271,6 +271,7 @@ struct tls_options unsigned remote_cert_ku[MAX_PARMS]; const char *remote_cert_eku; uint8_t *verify_hash; + hash_algo_type verify_hash_algo; char *x509_username_field; /* allow openvpn config info to be diff --git a/src/openvpn/ssl_verify.c b/src/openvpn/ssl_verify.c index ac1e110a8fe..078b65ad64c 100644 --- a/src/openvpn/ssl_verify.c +++ b/src/openvpn/ssl_verify.c @@ -718,8 +718,31 @@ verify_cert(struct tls_session *session, openvpn_x509_cert_t *cert, int cert_dep /* verify level 1 cert, i.e. the CA that signed our leaf cert */ if (cert_depth == 1 && opt->verify_hash) { - struct buffer sha1_hash = x509_get_sha1_fingerprint(cert, &gc); - if (memcmp(BPTR(&sha1_hash), opt->verify_hash, BLEN(&sha1_hash))) + struct buffer ca_hash = {0}; + + switch (opt->verify_hash_algo) + { + case MD_SHA1: + ca_hash = x509_get_sha1_fingerprint(cert, &gc); + break; + + case MD_SHA256: + ca_hash = x509_get_sha256_fingerprint(cert, &gc); + break; + + default: + /* This should normally not happen at all; the algorithm used + * is parsed by add_option() [options.c] and set to a predefined + * value in an enumerated type. So if this unlikely scenario + * happens, consider this a failure + */ + msg(M_WARN, "Unexpected invalid algorithm used with " + "--verify-hash (%i)", opt->verify_hash_algo); + ret = FAILURE; + goto cleanup; + } + + if (memcmp(BPTR(&ca_hash), opt->verify_hash, BLEN(&ca_hash))) { msg(D_TLS_ERRORS, "TLS Error: level-1 certificate hash verification failed"); goto cleanup; From 13c05ca4e9da88ef30a778c16a97f0c0d767b448 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Thu, 18 May 2017 12:22:46 +0200 Subject: [PATCH 531/643] Fix NCP behaviour on TLS reconnect. If a client reconnects on a hard-restart from the same port (due to --bind in use on the client), both sides will handle this as a "reconnect" and not a "full new connect" internally, re-using existing crypto context. The client will still ask the server for pushed options, and the server code to handle this refuses to do NCP if a key has already been negotiated (because there is no way to *change* the cipher after that) - which ends up in "the client uses the non-negotiated cipher from the config file, while the server uses the previously-negotiated NCP cipher", and nothing works. The easy workaround: if we find us in the situation that we think NCP has already been done, just re-push "cipher o->ciphername" with the current cipher for this client context. All credits for this go to Stefan Behrens who found and diagnosed the issue in trac #887, came up with a first patch to solve the issue quite similar to this (simplified) one, and helped testing. Trac: #887 Acked-by: Steffan Karger Message-Id: <20170518102246.5496-1-gert@greenie.muc.de> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14666.html Signed-off-by: Gert Doering (cherry picked from commit 5634cecf71ee9a92227bc9c8414c614d1b741abb) --- src/openvpn/push.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/openvpn/push.c b/src/openvpn/push.c index 8c3104ed769..bcef0ef49c4 100644 --- a/src/openvpn/push.c +++ b/src/openvpn/push.c @@ -372,15 +372,17 @@ prepare_push_reply(struct context *c, struct gc_arena *gc, /* Push cipher if client supports Negotiable Crypto Parameters */ if (tls_peer_info_ncp_ver(peer_info) >= 2 && o->ncp_enabled) { - /* if we have already created our key, we cannot change our own - * cipher, so disable NCP and warn = explain why + /* if we have already created our key, we cannot *change* our own + * cipher -> so log the fact and push the "what we have now" cipher + * (so the client is always told what we expect it to use) */ const struct tls_session *session = &tls_multi->session[TM_ACTIVE]; if (session->key[KS_PRIMARY].crypto_options.key_ctx_bi.initialized) { msg( M_INFO, "PUSH: client wants to negotiate cipher (NCP), but " "server has already generated data channel keys, " - "ignoring client request" ); + "re-sending previously negotiated cipher '%s'", + o->ciphername ); } else { @@ -388,8 +390,8 @@ prepare_push_reply(struct context *c, struct gc_arena *gc, * TODO: actual negotiation, instead of server dictatorship. */ char *push_cipher = string_alloc(o->ncp_ciphers, &o->gc); o->ciphername = strtok(push_cipher, ":"); - push_option_fmt(gc, push_list, M_USAGE, "cipher %s", o->ciphername); } + push_option_fmt(gc, push_list, M_USAGE, "cipher %s", o->ciphername); } else if (o->ncp_enabled) { From a91c54de67312f4026db61fd2b0e98cbd11e5323 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sun, 14 May 2017 21:00:41 +0200 Subject: [PATCH 532/643] Avoid a 1 byte overcopy in x509_get_subject (ssl_verify_openssl.c) This is the equivalent of the 2.3 patch (04c84548c2) by Guido Vranken, adjusted to code in the master and release/2.4 branches. Trac: #890 Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <143540d4-e8ea-b533-ad1a-8ae33bfd1133@karger.me> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14653.html Signed-off-by: Gert Doering (cherry picked from commit 3fbc9d2b1b1e75b227107057b92ce6b786b5bea1) --- src/openvpn/ssl_verify_openssl.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/openvpn/ssl_verify_openssl.c b/src/openvpn/ssl_verify_openssl.c index 4906c7d3d2d..1dfd45a451f 100644 --- a/src/openvpn/ssl_verify_openssl.c +++ b/src/openvpn/ssl_verify_openssl.c @@ -315,7 +315,6 @@ x509_get_subject(X509 *cert, struct gc_arena *gc) BIO *subject_bio = NULL; BUF_MEM *subject_mem; char *subject = NULL; - int maxlen = 0; /* * Generate the subject string in OpenSSL proprietary format, @@ -346,11 +345,10 @@ x509_get_subject(X509 *cert, struct gc_arena *gc) BIO_get_mem_ptr(subject_bio, &subject_mem); - maxlen = subject_mem->length + 1; - subject = gc_malloc(maxlen, false, gc); + subject = gc_malloc(subject_mem->length + 1, false, gc); - memcpy(subject, subject_mem->data, maxlen); - subject[maxlen - 1] = '\0'; + memcpy(subject, subject_mem->data, subject_mem->length); + subject[subject_mem->length] = '\0'; err: if (subject_bio) From 212e24ddc7b60fc2d2303ccf5893054e952232bb Mon Sep 17 00:00:00 2001 From: Steven McDonald Date: Fri, 14 Apr 2017 03:31:29 +1000 Subject: [PATCH 533/643] Fix gateway detection with OpenBSD routing domains When OpenVPN is started using a non-default routing table on OpenBSD (e.g., with 'route -T10 exec openvpn ...'), it hangs forever trying to read its default gateway from a PF_ROUTE socket. This is because rtm_tableid is not being initialised after bzeroing the rt_msghdr we write to the socket, so we end up asking the kernel for the default route in routing table 0. By default, the OpenBSD kernel will not respond to requests for routing table 0 from a process running in a different routing table, and even if it did, it would give us the wrong default gateway. The solution here is to set rtm_tableid to the value returned by getrtable(2), which always succeeds and returns the calling process's current routing table. This patch makes the test suite (without a t_client.rc) pass when run in a non-default routing table, where it would fail previously. It has also been successfully tested in client mode against both git master and OpenVPN 2.4.1 from ports on an OpenBSD -current system. Acked-by: Gert Doering Message-Id: <20170413173129.87367-1-steven@steven-mcdonald.id.au> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14461.html Signed-off-by: Gert Doering (cherry picked from commit 3dd30bfe5fdf9f34afe7f847b4e30156982d9ff0) --- src/openvpn/route.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/openvpn/route.c b/src/openvpn/route.c index 08998d5f4df..33cdc0b0e88 100644 --- a/src/openvpn/route.c +++ b/src/openvpn/route.c @@ -3597,6 +3597,9 @@ get_default_gateway(struct route_gateway_info *rgi) rtm.rtm_flags = RTF_UP | RTF_GATEWAY; rtm.rtm_version = RTM_VERSION; rtm.rtm_seq = ++seq; +#ifdef TARGET_OPENBSD + rtm.rtm_tableid = getrtable(); +#endif rtm.rtm_addrs = rtm_addrs; so_dst.sa_family = AF_INET; @@ -3812,6 +3815,9 @@ get_default_gateway_ipv6(struct route_ipv6_gateway_info *rgi6, rtm.rtm_flags = RTF_UP; rtm.rtm_version = RTM_VERSION; rtm.rtm_seq = ++seq; +#ifdef TARGET_OPENBSD + rtm.rtm_tableid = getrtable(); +#endif so_dst.sin6_family = AF_INET6; so_mask.sin6_family = AF_INET6; From a4d200a34617388e45837b7a9a8ccb25a7b1aa99 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Thu, 18 May 2017 21:13:11 +0200 Subject: [PATCH 534/643] Remove erroneous limitation on max number of args for --plugin Commit 3d6a4cded2 introduced a maximum limit of possible arguments for most options, to error out on config lines with too-many args. Commit 82acf21634 extended the limit for "--plugin" to accept "one mandatory, one optional" argument. Both are wrong - "--plugin" can accept an arbitrary number of arguments, but this is not directly obvious from options.c, one needs to check plugins.c / plugin_option_list_add() and misc.c / make_extended_arg_array() to see that. Thus, remove the max limit for "--plugin" completely. (Reported by SviMik on IRC) Signed-off-by: Gert Doering Acked-by: Steffan Karger Message-Id: <20170518191311.4769-1-gert@greenie.muc.de> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14678.html Signed-off-by: Gert Doering (cherry picked from commit 3f181eaa324892845e0857d80c154512d9e8c59c) --- src/openvpn/options.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 4ce46b147f7..57818e132ac 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -5168,7 +5168,7 @@ add_option(struct options *options, } #endif /* ifdef ENABLE_MANAGEMENT */ #ifdef ENABLE_PLUGIN - else if (streq(p[0], "plugin") && p[1] && !p[3]) + else if (streq(p[0], "plugin") && p[1]) { VERIFY_PERMISSION(OPT_P_PLUGIN); if (!options->plugin_list) From 69f00d8ce6862772919e2714adb72f13f3e92ca7 Mon Sep 17 00:00:00 2001 From: Guido Vranken Date: Thu, 8 Jun 2017 00:44:15 +0200 Subject: [PATCH 535/643] refactor my_strupr Refactor my_strupr such that it will not check and possibly alter bytes after the string's null terminator for strings of length 0. Signed-off-by: Guido Vranken Acked-by: Gert Doering Message-Id: URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14756.html Signed-off-by: Gert Doering (cherry picked from commit 69162924de3600bfe8ae9708a1d6e3f4515ef995) --- src/openvpn/ntlm.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/openvpn/ntlm.c b/src/openvpn/ntlm.c index 0c436812ece..93483379baf 100644 --- a/src/openvpn/ntlm.c +++ b/src/openvpn/ntlm.c @@ -130,17 +130,16 @@ gen_nonce(unsigned char *nonce) } } -unsigned char * +void my_strupr(unsigned char *str) { /* converts string to uppercase in place */ - unsigned char *tmp = str; - do + while (*str) { *str = toupper(*str); - } while (*(++str)); - return tmp; + str++; + } } static int From ec204e172f524e40ec6dcefaffb4b0ffd182fe2e Mon Sep 17 00:00:00 2001 From: Guido Vranken Date: Thu, 8 Jun 2017 16:36:54 +0200 Subject: [PATCH 536/643] Fix 2 memory leaks in proxy authentication routine Signed-off-by: Guido Vranken Acked-by: Gert Doering Message-Id: URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14758.html Signed-off-by: Gert Doering (cherry picked from commit 8d606cd3f6bce304874b1d7745d40d11f64ea17d) --- src/openvpn/proxy.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/openvpn/proxy.c b/src/openvpn/proxy.c index b0ed32796ce..8ff09ba90c9 100644 --- a/src/openvpn/proxy.c +++ b/src/openvpn/proxy.c @@ -318,6 +318,7 @@ get_proxy_authenticate(socket_descriptor_t sd, { if (!recv_line(sd, buf, sizeof(buf), timeout, true, NULL, signal_received)) { + free(*data); *data = NULL; return HTTP_AUTH_NONE; } @@ -991,6 +992,7 @@ establish_http_proxy_passthru(struct http_proxy_info *p, if (p->options.auth_retry == PAR_NCT && method == HTTP_AUTH_BASIC) { msg(D_PROXY, "HTTP proxy: support for basic auth and other cleartext proxy auth methods is disabled"); + free(pa); goto error; } p->auth_method = method; From 42fc73b969f4e34fd985a0be59d162fb2ee498e1 Mon Sep 17 00:00:00 2001 From: Guido Vranken Date: Fri, 9 Jun 2017 00:04:36 +0200 Subject: [PATCH 537/643] Fix memory leak in add_option() for option 'connection' This patch ensures that if an error occurs while processing the 'connection' directive of an options specification, the variable 'struct options sub', which is initialized with init_options(), is properly freed with uninit_options(). Signed-off-by: Guido Vranken Acked-by: Gert Doering Message-Id: URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14764.html Signed-off-by: Gert Doering (cherry picked from commit d89e14d92623731d2fa6343a11072caab32e13cd) --- src/openvpn/options.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 57818e132ac..41129ca093e 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -5318,12 +5318,14 @@ add_option(struct options *options, if (!sub.ce.remote) { msg(msglevel, "Each 'connection' block must contain exactly one 'remote' directive"); + uninit_options(&sub); goto err; } e = alloc_connection_entry(options, msglevel); if (!e) { + uninit_options(&sub); goto err; } *e = sub.ce; From 29ba477801998aff4e0ae7c1edc50b4ac9d145d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Courr=C3=A8ges-Anglas?= Date: Sat, 10 Jun 2017 16:48:44 +0200 Subject: [PATCH 538/643] Fix an unaligned access on OpenBSD/sparc64 The pointer to the packet content doesn't seem to be word-aligned, resulting in a SIGBUS when accessing it as a pointer to struct ip that contains bit fields. Replace with struct openvpn_iphdr and OPENVPN_IPH_GET_VER, which only does a one byte access and thus isn't affected by alignement. Acked-by: Gert Doering Message-Id: <87ink3vpcs.fsf@ritchie.wxcvbn.org> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14769.html Signed-off-by: Gert Doering --- src/openvpn/tun.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index 3504fbf4653..0ca0c19ed24 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -1654,11 +1654,11 @@ write_tun_header(struct tuntap *tt, uint8_t *buf, int len) { u_int32_t type; struct iovec iv[2]; - struct ip *iph; + struct openvpn_iphdr *iph; - iph = (struct ip *) buf; + iph = (struct openvpn_iphdr *) buf; - if (iph->ip_v == 6) + if (OPENVPN_IPH_GET_VER(iph->version_len) == 6) { type = htonl(AF_INET6); } From fc6b630e8b2f2c3ec2a18b3791f419d99c9fefb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Courr=C3=A8ges-Anglas?= Date: Sat, 10 Jun 2017 19:31:21 +0200 Subject: [PATCH 539/643] Missing include for socket-flags TCP_NODELAY on OpenBSD Signed-off-by: Jeremie Courreges-Anglas Acked-by: Gert Doering Message-Id: <87fuf7u455.fsf@ritchie.wxcvbn.org> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14772.html Signed-off-by: Gert Doering (cherry picked from commit e5b236eaba4512f86da917a0a63dd0f84e1b02db) --- src/openvpn/syshead.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/openvpn/syshead.h b/src/openvpn/syshead.h index f4458648ed0..14b6662a186 100644 --- a/src/openvpn/syshead.h +++ b/src/openvpn/syshead.h @@ -288,6 +288,10 @@ #include #endif +#ifdef HAVE_NETINET_TCP_H +#include +#endif + #ifdef HAVE_NET_IF_TUN_H #include #endif From 110f1e14da97918592a36d4405c807e76d9ad51c Mon Sep 17 00:00:00 2001 From: Guido Vranken Date: Thu, 8 Jun 2017 01:02:38 +0200 Subject: [PATCH 540/643] Ensure option array p[] is always NULL-terminated Add one element (a terminating NULL pointer) to the array into which parse_line() stores the arguments. This prevents that options that traverse this array until a terminator is seen (for instance options that call no_more_than_n_args) will peek beyond buffer bounds. In the worst case this might lead to a crash (stack overflow, not likely in practice). Signed-off-by: Guido Vranken Acked-by: Gert Doering Message-Id: URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14757.html Signed-off-by: Gert Doering (cherry picked from commit 8b03d3d9307b407b0da98ebefb052b1fa87aefe7) --- src/openvpn/options.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 41129ca093e..ddd47b2891c 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -4547,7 +4547,7 @@ read_config_file(struct options *options, FILE *fp; int line_num; char line[OPTION_LINE_SIZE+1]; - char *p[MAX_PARMS]; + char *p[MAX_PARMS+1]; ++level; if (level <= max_recursive_levels) @@ -4579,7 +4579,7 @@ read_config_file(struct options *options, { offset = 3; } - if (parse_line(line + offset, p, SIZE(p), file, line_num, msglevel, &options->gc)) + if (parse_line(line + offset, p, SIZE(p)-1, file, line_num, msglevel, &options->gc)) { bypass_doubledash(&p[0]); check_inline_file_via_fp(fp, p, &options->gc); @@ -4621,10 +4621,10 @@ read_config_string(const char *prefix, while (buf_parse(&multiline, '\n', line, sizeof(line))) { - char *p[MAX_PARMS]; + char *p[MAX_PARMS+1]; CLEAR(p); ++line_num; - if (parse_line(line, p, SIZE(p), prefix, line_num, msglevel, &options->gc)) + if (parse_line(line, p, SIZE(p)-1, prefix, line_num, msglevel, &options->gc)) { bypass_doubledash(&p[0]); check_inline_file_via_buf(&multiline, p, &options->gc); @@ -4755,14 +4755,14 @@ apply_push_options(struct options *options, while (buf_parse(buf, ',', line, sizeof(line))) { - char *p[MAX_PARMS]; + char *p[MAX_PARMS+1]; CLEAR(p); ++line_num; if (!apply_pull_filter(options, line)) { return false; /* Cause push/pull error and stop push processing */ } - if (parse_line(line, p, SIZE(p), file, line_num, msglevel, &options->gc)) + if (parse_line(line, p, SIZE(p)-1, file, line_num, msglevel, &options->gc)) { add_option(options, p, file, line_num, 0, msglevel, permission_mask, option_types_found, es); } From 84372cb6a67d1c088b01ed253697199995a8ab85 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Mon, 15 May 2017 16:44:43 +0200 Subject: [PATCH 541/643] Skip tls-crypt unit tests if required crypto mode not supported Instead of failing the test with an unclear error, print that the a required crypto primitive is not supported and skip the test. This is for example the case when using the system-supplied openssl on SLES11, which does not support AES-256-CTR. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1494859483-16466-1-git-send-email-steffan.karger@fox-it.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14657.html Signed-off-by: Gert Doering (cherry picked from commit 534c8f24bd8ceeaebb326f53363a4e40e970df1e) --- tests/unit_tests/openvpn/test_tls_crypt.c | 39 ++++++++++++++++++++--- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/tests/unit_tests/openvpn/test_tls_crypt.c b/tests/unit_tests/openvpn/test_tls_crypt.c index 7b014e072fa..262b1984ce0 100644 --- a/tests/unit_tests/openvpn/test_tls_crypt.c +++ b/tests/unit_tests/openvpn/test_tls_crypt.c @@ -58,11 +58,22 @@ struct test_context { static int setup(void **state) { - struct test_context *ctx = calloc(1, sizeof(*ctx)); + struct test_context *ctx = calloc(1, sizeof(*ctx)); + *state = ctx; ctx->kt.cipher = cipher_kt_get("AES-256-CTR"); - ctx->kt.cipher_length = cipher_kt_key_size(ctx->kt.cipher); ctx->kt.digest = md_kt_get("SHA256"); + if (!ctx->kt.cipher) + { + printf("No AES-256-CTR support, skipping test.\n"); + return 0; + } + if (!ctx->kt.digest) + { + printf("No HMAC-SHA256 support, skipping test.\n"); + return 0; + } + ctx->kt.cipher_length = cipher_kt_key_size(ctx->kt.cipher); ctx->kt.hmac_length = md_kt_size(ctx->kt.digest); struct key key = { 0 }; @@ -82,8 +93,6 @@ setup(void **state) { /* Write dummy opcode and session id */ buf_write(&ctx->ciphertext, "012345678", 1 + 8); - *state = ctx; - return 0; } @@ -102,6 +111,14 @@ teardown(void **state) { return 0; } +static void skip_if_tls_crypt_not_supported(struct test_context *ctx) +{ + if (!ctx->kt.cipher || !ctx->kt.digest) + { + skip(); + } +} + /** * Check that short messages are successfully wrapped-and-unwrapped. */ @@ -109,6 +126,8 @@ static void tls_crypt_loopback(void **state) { struct test_context *ctx = (struct test_context *) *state; + skip_if_tls_crypt_not_supported(ctx); + assert_true(tls_crypt_wrap(&ctx->source, &ctx->ciphertext, &ctx->co)); assert_true(BLEN(&ctx->source) < BLEN(&ctx->ciphertext)); assert_true(tls_crypt_unwrap(&ctx->ciphertext, &ctx->unwrapped, &ctx->co)); @@ -124,6 +143,8 @@ static void tls_crypt_loopback_zero_len(void **state) { struct test_context *ctx = (struct test_context *) *state; + skip_if_tls_crypt_not_supported(ctx); + buf_clear(&ctx->source); assert_true(tls_crypt_wrap(&ctx->source, &ctx->ciphertext, &ctx->co)); @@ -141,6 +162,8 @@ static void tls_crypt_loopback_max_len(void **state) { struct test_context *ctx = (struct test_context *) *state; + skip_if_tls_crypt_not_supported(ctx); + buf_clear(&ctx->source); assert_non_null(buf_write_alloc(&ctx->source, TESTBUF_SIZE - BLEN(&ctx->ciphertext) - tls_crypt_buf_overhead())); @@ -160,6 +183,8 @@ static void tls_crypt_fail_msg_too_long(void **state) { struct test_context *ctx = (struct test_context *) *state; + skip_if_tls_crypt_not_supported(ctx); + buf_clear(&ctx->source); assert_non_null(buf_write_alloc(&ctx->source, TESTBUF_SIZE - BLEN(&ctx->ciphertext) - tls_crypt_buf_overhead() + 1)); @@ -174,6 +199,8 @@ static void tls_crypt_fail_invalid_key(void **state) { struct test_context *ctx = (struct test_context *) *state; + skip_if_tls_crypt_not_supported(ctx); + /* Change decrypt key */ struct key key = { { 1 } }; free_key_ctx(&ctx->co.key_ctx_bi.decrypt); @@ -191,6 +218,8 @@ static void tls_crypt_fail_replay(void **state) { struct test_context *ctx = (struct test_context *) *state; + skip_if_tls_crypt_not_supported(ctx); + assert_true(tls_crypt_wrap(&ctx->source, &ctx->ciphertext, &ctx->co)); assert_true(BLEN(&ctx->source) < BLEN(&ctx->ciphertext)); struct buffer tmp = ctx->ciphertext; @@ -208,6 +237,8 @@ static void tls_crypt_ignore_replay(void **state) { struct test_context *ctx = (struct test_context *) *state; + skip_if_tls_crypt_not_supported(ctx); + ctx->co.flags |= CO_IGNORE_PACKET_ID; assert_true(tls_crypt_wrap(&ctx->source, &ctx->ciphertext, &ctx->co)); From b52c1ff43b23c3cf438fb99b807a7309d3229a56 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Mon, 22 May 2017 15:54:13 +0200 Subject: [PATCH 542/643] openssl: fix overflow check for long --tls-cipher option The length check in tls_ctx_restrict_ciphers() did not check for overflow, which could lead to a stack buffer overflow. This has no real-world impact, because --tls-cipher can only be specified by entities that are allowed to supply config settings. Since those entities can also change --script-security and call scripts and/or plugins, these users already have code execution at the level of the openvpn process. In other words: the attacker would not gain any capabilities. Nevertheless, a nasty bug that we should fix. This bug was discovered and reported to the OpenVPN security team by Guido Vranken. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1495461253-20111-1-git-send-email-steffan.karger@fox-it.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14716.html Signed-off-by: Gert Doering (cherry picked from commit e6bf7e033d063535a4414a4cf49c8f367ecdbb4f) --- src/openvpn/ssl_openssl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c index d7cc2ba44aa..8117435e944 100644 --- a/src/openvpn/ssl_openssl.c +++ b/src/openvpn/ssl_openssl.c @@ -355,7 +355,8 @@ tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers) } /* Make sure new cipher name fits in cipher string */ - if (((sizeof(openssl_ciphers)-1) - openssl_ciphers_len) < current_cipher_len) + if ((SIZE_MAX - openssl_ciphers_len) < current_cipher_len + || ((sizeof(openssl_ciphers)-1) < openssl_ciphers_len + current_cipher_len)) { msg(M_FATAL, "Failed to set restricted TLS cipher list, too long (>%d).", From bf547b8ac79b15a2b2dc59e27c0cb2ade73a3941 Mon Sep 17 00:00:00 2001 From: Guido Vranken Date: Fri, 16 Jun 2017 02:58:56 +0200 Subject: [PATCH 543/643] Fix a null-pointer dereference in establish_http_proxy_passthru() Prevents that the client crashes if the peer does not specify the 'realm' and/or 'nonce' values. These pointers are dereferenced in DigestCalcHA1() and DigestCalcResponse(); hence, if not set, a null-pointer dereference would occur. Signed-off-by: Guido Vranken Acked-by: Gert Doering Message-Id: <1497574736-2092-1-git-send-email-gv@guidovranken.nl> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14844.html Signed-off-by: Gert Doering (cherry picked from commit 14865773ad64d861128bc80ad44c37bdc307c996) --- src/openvpn/proxy.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/openvpn/proxy.c b/src/openvpn/proxy.c index 8ff09ba90c9..112e99b9cfa 100644 --- a/src/openvpn/proxy.c +++ b/src/openvpn/proxy.c @@ -876,6 +876,13 @@ establish_http_proxy_passthru(struct http_proxy_info *p, const char *algor = get_pa_var("algorithm", pa, &gc); const char *opaque = get_pa_var("opaque", pa, &gc); + if ( !realm || !nonce ) + { + msg(D_LINK_ERRORS, "HTTP proxy: digest auth failed, malformed response " + "from server: realm= or nonce= missing" ); + goto error; + } + /* generate a client nonce */ ASSERT(rand_bytes(cnonce_raw, sizeof(cnonce_raw))); cnonce = make_base64_string2(cnonce_raw, sizeof(cnonce_raw), &gc); From b11f646ebfd148de807ca8744040397c5e4b47de Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Wed, 29 Mar 2017 11:36:48 +0200 Subject: [PATCH 544/643] copyright: Update GPLv2 license texts The COPYRIGHT.GPL file was slightly out-of-sync with the last GPLv2 license from Free Software Foundation, Inc. The changes are primarily a new address, which required touching almost all the project files. Except of that, it is just minor adjustments to formatting, removal of form-feed characters and referencing "GNU Lesser General Public License" instead of "GNU Library General Public License". Signed-off-by: David Sommerseth Acked-by: Gert Doering Message-Id: <20170329093648.10156-1-davids@openvpn.net> URL: https://www.mail-archive.com/search?l=mid&q=20170329093648.10156-1-davids@openvpn.net Signed-off-by: Gert Doering (cherry picked from commit caa54ac398db25b72d7d1d633d2ee330b5b8a3e9) --- COPYRIGHT.GPL | 39 +++++++++---------- Makefile.am | 7 ++-- compat.m4 | 7 ++-- configure.ac | 7 ++-- contrib/keychain-mcd/cert_data.c | 7 ++-- contrib/keychain-mcd/cert_data.h | 7 ++-- contrib/keychain-mcd/common_osx.c | 7 ++-- contrib/keychain-mcd/common_osx.h | 7 ++-- contrib/keychain-mcd/crypto_osx.c | 7 ++-- contrib/keychain-mcd/crypto_osx.h | 7 ++-- contrib/keychain-mcd/main.c | 7 ++-- doc/doxygen/doc_compression.h | 7 ++-- doc/doxygen/doc_control_processor.h | 7 ++-- doc/doxygen/doc_control_tls.h | 7 ++-- doc/doxygen/doc_data_control.h | 7 ++-- doc/doxygen/doc_data_crypto.h | 7 ++-- doc/doxygen/doc_eventloop.h | 7 ++-- doc/doxygen/doc_external_multiplexer.h | 7 ++-- doc/doxygen/doc_fragmentation.h | 7 ++-- doc/doxygen/doc_internal_multiplexer.h | 7 ++-- doc/doxygen/doc_key_generation.h | 7 ++-- doc/doxygen/doc_mainpage.h | 7 ++-- doc/doxygen/doc_memory_management.h | 7 ++-- doc/doxygen/doc_protocol_overview.h | 7 ++-- doc/doxygen/doc_reliable.h | 7 ++-- doc/doxygen/doc_tunnel_state.h | 7 ++-- doc/openvpn.8 | 7 ++-- include/openvpn-msg.h | 7 ++-- include/openvpn-plugin.h.in | 7 ++-- m4/pkg.m4 | 6 +-- sample/sample-plugins/defer/simple.c | 7 ++-- .../keyingmaterialexporter.c | 7 ++-- sample/sample-plugins/log/log.c | 7 ++-- sample/sample-plugins/log/log_v3.c | 7 ++-- sample/sample-plugins/simple/simple.c | 7 ++-- src/compat/compat-basename.c | 7 ++-- src/compat/compat-daemon.c | 7 ++-- src/compat/compat-dirname.c | 7 ++-- src/compat/compat-gettimeofday.c | 7 ++-- src/compat/compat-inet_ntop.c | 7 ++-- src/compat/compat-inet_pton.c | 7 ++-- src/compat/compat.h | 7 ++-- src/openvpn/argv.c | 7 ++-- src/openvpn/argv.h | 7 ++-- src/openvpn/basic.h | 7 ++-- src/openvpn/block_dns.c | 7 ++-- src/openvpn/block_dns.h | 7 ++-- src/openvpn/buffer.c | 7 ++-- src/openvpn/buffer.h | 7 ++-- src/openvpn/circ_list.h | 7 ++-- src/openvpn/clinat.c | 7 ++-- src/openvpn/clinat.h | 7 ++-- src/openvpn/common.h | 7 ++-- src/openvpn/comp-lz4.c | 7 ++-- src/openvpn/comp-lz4.h | 7 ++-- src/openvpn/comp.c | 7 ++-- src/openvpn/comp.h | 7 ++-- src/openvpn/compstub.c | 7 ++-- src/openvpn/console.c | 7 ++-- src/openvpn/console.h | 9 ++--- src/openvpn/console_builtin.c | 7 ++-- src/openvpn/console_systemd.c | 7 ++-- src/openvpn/crypto.c | 7 ++-- src/openvpn/crypto.h | 7 ++-- src/openvpn/crypto_backend.h | 7 ++-- src/openvpn/crypto_mbedtls.c | 7 ++-- src/openvpn/crypto_mbedtls.h | 7 ++-- src/openvpn/crypto_openssl.c | 7 ++-- src/openvpn/crypto_openssl.h | 7 ++-- src/openvpn/dhcp.c | 7 ++-- src/openvpn/dhcp.h | 7 ++-- src/openvpn/errlevel.h | 7 ++-- src/openvpn/error.c | 7 ++-- src/openvpn/error.h | 7 ++-- src/openvpn/event.c | 7 ++-- src/openvpn/event.h | 7 ++-- src/openvpn/fdmisc.c | 7 ++-- src/openvpn/fdmisc.h | 7 ++-- src/openvpn/forward-inline.h | 7 ++-- src/openvpn/forward.c | 7 ++-- src/openvpn/forward.h | 7 ++-- src/openvpn/fragment.c | 7 ++-- src/openvpn/fragment.h | 7 ++-- src/openvpn/gremlin.c | 7 ++-- src/openvpn/gremlin.h | 7 ++-- src/openvpn/helper.c | 7 ++-- src/openvpn/helper.h | 7 ++-- src/openvpn/httpdigest.c | 7 ++-- src/openvpn/httpdigest.h | 7 ++-- src/openvpn/init.c | 7 ++-- src/openvpn/init.h | 7 ++-- src/openvpn/integer.h | 7 ++-- src/openvpn/interval.c | 7 ++-- src/openvpn/interval.h | 7 ++-- src/openvpn/list.c | 7 ++-- src/openvpn/list.h | 7 ++-- src/openvpn/lzo.c | 7 ++-- src/openvpn/lzo.h | 7 ++-- src/openvpn/manage.c | 7 ++-- src/openvpn/manage.h | 7 ++-- src/openvpn/mbuf.c | 7 ++-- src/openvpn/mbuf.h | 7 ++-- src/openvpn/memdbg.h | 7 ++-- src/openvpn/misc.c | 7 ++-- src/openvpn/misc.h | 7 ++-- src/openvpn/mroute.c | 7 ++-- src/openvpn/mroute.h | 7 ++-- src/openvpn/mss.c | 7 ++-- src/openvpn/mss.h | 7 ++-- src/openvpn/mstats.c | 7 ++-- src/openvpn/mstats.h | 7 ++-- src/openvpn/mtcp.c | 7 ++-- src/openvpn/mtcp.h | 7 ++-- src/openvpn/mtu.c | 7 ++-- src/openvpn/mtu.h | 7 ++-- src/openvpn/mudp.c | 7 ++-- src/openvpn/mudp.h | 7 ++-- src/openvpn/multi.c | 7 ++-- src/openvpn/multi.h | 7 ++-- src/openvpn/ntlm.c | 7 ++-- src/openvpn/occ-inline.h | 7 ++-- src/openvpn/occ.c | 7 ++-- src/openvpn/occ.h | 7 ++-- src/openvpn/openssl_compat.h | 7 ++-- src/openvpn/openvpn.c | 7 ++-- src/openvpn/openvpn.h | 7 ++-- src/openvpn/options.c | 7 ++-- src/openvpn/options.h | 7 ++-- src/openvpn/otime.c | 7 ++-- src/openvpn/otime.h | 7 ++-- src/openvpn/packet_id.c | 7 ++-- src/openvpn/packet_id.h | 7 ++-- src/openvpn/perf.c | 7 ++-- src/openvpn/perf.h | 7 ++-- src/openvpn/pf-inline.h | 7 ++-- src/openvpn/pf.c | 7 ++-- src/openvpn/pf.h | 7 ++-- src/openvpn/ping-inline.h | 7 ++-- src/openvpn/ping.c | 7 ++-- src/openvpn/ping.h | 7 ++-- src/openvpn/pkcs11.c | 7 ++-- src/openvpn/pkcs11.h | 7 ++-- src/openvpn/pkcs11_backend.h | 7 ++-- src/openvpn/pkcs11_mbedtls.c | 7 ++-- src/openvpn/pkcs11_openssl.c | 7 ++-- src/openvpn/platform.c | 7 ++-- src/openvpn/platform.h | 7 ++-- src/openvpn/plugin.c | 7 ++-- src/openvpn/plugin.h | 7 ++-- src/openvpn/pool.c | 7 ++-- src/openvpn/pool.h | 7 ++-- src/openvpn/proto.c | 7 ++-- src/openvpn/proto.h | 7 ++-- src/openvpn/proxy.c | 7 ++-- src/openvpn/proxy.h | 7 ++-- src/openvpn/ps.c | 7 ++-- src/openvpn/ps.h | 7 ++-- src/openvpn/push.c | 7 ++-- src/openvpn/push.h | 7 ++-- src/openvpn/pushlist.h | 7 ++-- src/openvpn/reliable.c | 7 ++-- src/openvpn/reliable.h | 7 ++-- src/openvpn/route.c | 7 ++-- src/openvpn/route.h | 7 ++-- src/openvpn/schedule.c | 7 ++-- src/openvpn/schedule.h | 7 ++-- src/openvpn/session_id.c | 7 ++-- src/openvpn/session_id.h | 7 ++-- src/openvpn/shaper.c | 7 ++-- src/openvpn/shaper.h | 7 ++-- src/openvpn/sig.c | 7 ++-- src/openvpn/sig.h | 7 ++-- src/openvpn/socket.c | 7 ++-- src/openvpn/socket.h | 7 ++-- src/openvpn/socks.c | 7 ++-- src/openvpn/socks.h | 7 ++-- src/openvpn/ssl.c | 7 ++-- src/openvpn/ssl.h | 7 ++-- src/openvpn/ssl_backend.h | 7 ++-- src/openvpn/ssl_common.h | 7 ++-- src/openvpn/ssl_mbedtls.c | 7 ++-- src/openvpn/ssl_mbedtls.h | 7 ++-- src/openvpn/ssl_openssl.c | 7 ++-- src/openvpn/ssl_openssl.h | 7 ++-- src/openvpn/ssl_verify.c | 7 ++-- src/openvpn/ssl_verify.h | 7 ++-- src/openvpn/ssl_verify_backend.h | 7 ++-- src/openvpn/ssl_verify_mbedtls.c | 7 ++-- src/openvpn/ssl_verify_mbedtls.h | 7 ++-- src/openvpn/ssl_verify_openssl.c | 7 ++-- src/openvpn/ssl_verify_openssl.h | 7 ++-- src/openvpn/status.c | 7 ++-- src/openvpn/status.h | 7 ++-- src/openvpn/syshead.h | 7 ++-- src/openvpn/tls_crypt.c | 7 ++-- src/openvpn/tls_crypt.h | 7 ++-- src/openvpn/tun.c | 7 ++-- src/openvpn/tun.h | 7 ++-- src/openvpn/win32.c | 7 ++-- src/openvpn/win32.h | 7 ++-- src/openvpnserv/automatic.c | 7 ++-- src/openvpnserv/common.c | 7 ++-- src/openvpnserv/interactive.c | 7 ++-- src/openvpnserv/service.h | 7 ++-- src/openvpnserv/validate.c | 7 ++-- src/openvpnserv/validate.h | 7 ++-- src/plugins/auth-pam/auth-pam.c | 7 ++-- src/plugins/auth-pam/utils.c | 7 ++-- src/plugins/auth-pam/utils.h | 7 ++-- src/plugins/down-root/down-root.c | 7 ++-- tests/unit_tests/openvpn/mock_msg.c | 7 ++-- tests/unit_tests/openvpn/mock_msg.h | 7 ++-- tests/unit_tests/openvpn/test_buffer.c | 7 ++-- tests/unit_tests/openvpn/test_tls_crypt.c | 7 ++-- 214 files changed, 659 insertions(+), 872 deletions(-) diff --git a/COPYRIGHT.GPL b/COPYRIGHT.GPL index ff8a7f00274..2a591d0c452 100644 --- a/COPYRIGHT.GPL +++ b/COPYRIGHT.GPL @@ -1,12 +1,12 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. - Preamble + Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public @@ -15,7 +15,7 @@ software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to +the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not @@ -55,8 +55,8 @@ patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. - - GNU GENERAL PUBLIC LICENSE + + GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains @@ -110,7 +110,7 @@ above, provided that you also meet all of these conditions: License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) - + These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in @@ -168,7 +168,7 @@ access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. - + 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is @@ -225,7 +225,7 @@ impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. - + 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License @@ -255,7 +255,7 @@ make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. - NO WARRANTY + NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN @@ -277,9 +277,9 @@ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it @@ -302,10 +302,9 @@ the "copyright" line and a pointer to where the full notice is found. 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; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. @@ -335,5 +334,5 @@ necessary. Here is a sample; alter the names: This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General +library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. diff --git a/Makefile.am b/Makefile.am index 1197aadb3dc..87da1825971 100644 --- a/Makefile.am +++ b/Makefile.am @@ -18,10 +18,9 @@ # 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 +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # # This option prevents autoreconf from overriding our COPYING and diff --git a/compat.m4 b/compat.m4 index 4c132544c37..e54a72031b5 100644 --- a/compat.m4 +++ b/compat.m4 @@ -16,10 +16,9 @@ dnl but WITHOUT ANY WARRANTY; without even the implied warranty of dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the dnl GNU General Public License for more details. dnl -dnl You should have received a copy of the GNU General Public License -dnl along with this program (see the file COPYING included with this -dnl distribution); if not, write to the Free Software Foundation, Inc., -dnl 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +dnl You should have received a copy of the GNU General Public License along +dnl with this program; if not, write to the Free Software Foundation, Inc., +dnl 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. dnl Compatibility layer for diff --git a/src/openvpnserv/interactive.c b/src/openvpnserv/interactive.c index 68ab0576be0..607c8a91c9c 100644 --- a/src/openvpnserv/interactive.c +++ b/src/openvpnserv/interactive.c @@ -16,10 +16,9 @@ * 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 + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ diff --git a/src/openvpnserv/service.h b/src/openvpnserv/service.h index b1130c90677..9fe573e44d3 100644 --- a/src/openvpnserv/service.h +++ b/src/openvpnserv/service.h @@ -16,10 +16,9 @@ * 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 + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef _SERVICE_H diff --git a/src/openvpnserv/validate.c b/src/openvpnserv/validate.c index 894c51b1b55..f6a97e9cf50 100644 --- a/src/openvpnserv/validate.c +++ b/src/openvpnserv/validate.c @@ -16,10 +16,9 @@ * 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 + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "validate.h" diff --git a/src/openvpnserv/validate.h b/src/openvpnserv/validate.h index 033e0e4cfa4..cc443e6959a 100644 --- a/src/openvpnserv/validate.h +++ b/src/openvpnserv/validate.h @@ -17,10 +17,9 @@ * 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 + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef VALIDATE_H diff --git a/src/plugins/auth-pam/auth-pam.c b/src/plugins/auth-pam/auth-pam.c index 54471a3947e..ae514d79e26 100644 --- a/src/plugins/auth-pam/auth-pam.c +++ b/src/plugins/auth-pam/auth-pam.c @@ -16,10 +16,9 @@ * 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 + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* diff --git a/src/plugins/auth-pam/utils.c b/src/plugins/auth-pam/utils.c index 724a4379eea..4b900c7ab6a 100644 --- a/src/plugins/auth-pam/utils.c +++ b/src/plugins/auth-pam/utils.c @@ -16,10 +16,9 @@ * 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 + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* diff --git a/src/plugins/auth-pam/utils.h b/src/plugins/auth-pam/utils.h index fbc9705b40b..c0b4b1058c8 100644 --- a/src/plugins/auth-pam/utils.h +++ b/src/plugins/auth-pam/utils.h @@ -16,10 +16,9 @@ * 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 + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef _PLUGIN_AUTH_PAM_UTILS__H diff --git a/src/plugins/down-root/down-root.c b/src/plugins/down-root/down-root.c index ab6b483a9b3..4198184854e 100644 --- a/src/plugins/down-root/down-root.c +++ b/src/plugins/down-root/down-root.c @@ -17,10 +17,9 @@ * 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 + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* diff --git a/tests/unit_tests/openvpn/mock_msg.c b/tests/unit_tests/openvpn/mock_msg.c index 060588fae5e..4bd11ca54ae 100644 --- a/tests/unit_tests/openvpn/mock_msg.c +++ b/tests/unit_tests/openvpn/mock_msg.c @@ -16,10 +16,9 @@ * 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 + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifdef HAVE_CONFIG_H diff --git a/tests/unit_tests/openvpn/mock_msg.h b/tests/unit_tests/openvpn/mock_msg.h index e0933c69f32..2f8c8bf67be 100644 --- a/tests/unit_tests/openvpn/mock_msg.h +++ b/tests/unit_tests/openvpn/mock_msg.h @@ -16,10 +16,9 @@ * 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 + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef MOCK_MSG_H diff --git a/tests/unit_tests/openvpn/test_buffer.c b/tests/unit_tests/openvpn/test_buffer.c index 5158eb87321..69bb2e58c83 100644 --- a/tests/unit_tests/openvpn/test_buffer.c +++ b/tests/unit_tests/openvpn/test_buffer.c @@ -16,10 +16,9 @@ * 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 + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifdef HAVE_CONFIG_H diff --git a/tests/unit_tests/openvpn/test_tls_crypt.c b/tests/unit_tests/openvpn/test_tls_crypt.c index 262b1984ce0..9b820355c4f 100644 --- a/tests/unit_tests/openvpn/test_tls_crypt.c +++ b/tests/unit_tests/openvpn/test_tls_crypt.c @@ -16,10 +16,9 @@ * 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 + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifdef HAVE_CONFIG_H From e82f7005256f77a63a3191ab7fef67e0cf0a9d02 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Sun, 18 Jun 2017 11:22:44 +0200 Subject: [PATCH 545/643] Fix edge case with clients failing to set up cipher on empty PUSH_REPLY. The NCP (data channel crypto negotiation) code on the client side waits for an incoming PUSH_REPLY before setting up the data channel crypto parameters, because the PUSH_REPLY could contain a "cipher xxx" setting. In the particular case of a empty PUSH_REPLY message, the relevant code bits was not called because "we have not received any options, do not bother to look into it in more detail" - so, ciphers were not set up, resulting in an error message like this: Key [AF_INET]... [0] not initialized (yet), dropping packet. Remove that check, always init the crypto layer on PUSH_REPLY. Trac: #903 Signed-off-by: Gert Doering Acked-by: Steffan Karger Message-Id: <20170618092244.8801-1-gert@greenie.muc.de> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14856.html Signed-off-by: Gert Doering (cherry picked from commit bd230079d98bfe6aec70b7aedefdffcdbd0e56da) --- src/openvpn/init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 47f4debf94b..6fd95928827 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -1925,7 +1925,7 @@ do_up(struct context *c, bool pulled_options, unsigned int option_types_found) { reset_coarse_timers(c); - if (pulled_options && option_types_found) + if (pulled_options) { if (!do_deferred_options(c, option_types_found)) { From e78934adade51f79c847dcf0fee26905ebb9044d Mon Sep 17 00:00:00 2001 From: Emmanuel Deloget Date: Mon, 12 Jun 2017 15:43:23 +0200 Subject: [PATCH 546/643] OpenSSL: don't use direct access to the internal of X509 OpenSSL 1.1 does not allow us to directly access the internal of any data type, including X509. We have to use the defined functions to do so. In x509_verify_ns_cert_type() in particular, this means that we cannot directly check for the extended flags to find whether the certificate should be used as a client or as a server certificate. We need to leverage the X509_check_purpose() API yet this API is far stricter than the currently implemented check. So far, I have not been able to find a situation where this stricter test fails (although I must admit that I haven't tested that very well). We double-check the certificate purpose using "direct access" to the internal of the certificate object (of course, this is not a real direct access, but we still fetch ASN1 strings within the X509 object and we check the internal value of these strings). This allow us to warn the user if there is a discrepancy between the X509_check_purpose() return value and our internal, less strict check. We use these changes to make peer_cert a non-const parameter to x509_verify_ns_cert_type(). The underlying library waits for a non-const pointer, and forcing it to be a const pointer does not make much sense (please note that this has an effect on the mbedtls part too). Compatibility with OpenSSL 1.0 is kept by defining the corresponding functions when they are not found in the library. Signed-off-by: Emmanuel Deloget Acked-by: Steffan Karger Message-Id: <20170612134330.20971-2-logout@free.fr> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14792.html Signed-off-by: Gert Doering (cherry picked from commit 17d1ab90c228b1efbe774357bd3265b2af006899) --- configure.ac | 1 + src/openvpn/openssl_compat.h | 15 +++++++ src/openvpn/ssl_openssl.c | 3 +- src/openvpn/ssl_verify_backend.h | 2 +- src/openvpn/ssl_verify_mbedtls.c | 2 +- src/openvpn/ssl_verify_openssl.c | 68 +++++++++++++++++++++++++++----- 6 files changed, 78 insertions(+), 13 deletions(-) diff --git a/configure.ac b/configure.ac index a5878773043..10a2344f3e5 100644 --- a/configure.ac +++ b/configure.ac @@ -901,6 +901,7 @@ if test "${enable_crypto}" = "yes" -a "${with_crypto_library}" = "openssl"; then [ \ SSL_CTX_get_default_passwd_cb \ SSL_CTX_get_default_passwd_cb_userdata \ + X509_get0_pubkey \ X509_STORE_get0_objects \ X509_OBJECT_free \ X509_OBJECT_get_type \ diff --git a/src/openvpn/openssl_compat.h b/src/openvpn/openssl_compat.h index 811d559cb9a..612bfa567dc 100644 --- a/src/openvpn/openssl_compat.h +++ b/src/openvpn/openssl_compat.h @@ -73,6 +73,21 @@ SSL_CTX_get_default_passwd_cb(SSL_CTX *ctx) } #endif +#if !defined(HAVE_X509_GET0_PUBKEY) +/** + * Get the public key from a X509 certificate + * + * @param x X509 certificate + * @return The certificate public key + */ +static inline EVP_PKEY * +X509_get0_pubkey(const X509 *x) +{ + return (x && x->cert_info && x->cert_info->key) ? + x->cert_info->key->pkey : NULL; +} +#endif + #if !defined(HAVE_X509_STORE_GET0_OBJECTS) /** * Fetch the X509 object stack from the X509 store diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c index 612fa559eca..3f7c6d2a9ca 100644 --- a/src/openvpn/ssl_openssl.c +++ b/src/openvpn/ssl_openssl.c @@ -1073,7 +1073,8 @@ tls_ctx_use_external_private_key(struct tls_root_ctx *ctx, } /* get the public key */ - ASSERT(cert->cert_info->key->pkey); /* NULL before SSL_CTX_use_certificate() is called */ + EVP_PKEY *pkey = X509_get0_pubkey(cert); + ASSERT(pkey); /* NULL before SSL_CTX_use_certificate() is called */ pub_rsa = cert->cert_info->key->pkey->pkey.rsa; /* initialize RSA object */ diff --git a/src/openvpn/ssl_verify_backend.h b/src/openvpn/ssl_verify_backend.h index 3566053296f..978e54fdff6 100644 --- a/src/openvpn/ssl_verify_backend.h +++ b/src/openvpn/ssl_verify_backend.h @@ -210,7 +210,7 @@ void x509_setenv_track(const struct x509_track *xt, struct env_set *es, * the expected bit set. \c FAILURE if the certificate does * not have NS cert type verification or the wrong bit set. */ -result_t x509_verify_ns_cert_type(const openvpn_x509_cert_t *cert, const int usage); +result_t x509_verify_ns_cert_type(openvpn_x509_cert_t *cert, const int usage); /* * Verify X.509 key usage extension field. diff --git a/src/openvpn/ssl_verify_mbedtls.c b/src/openvpn/ssl_verify_mbedtls.c index d80b7a53b4c..27c5c3e149d 100644 --- a/src/openvpn/ssl_verify_mbedtls.c +++ b/src/openvpn/ssl_verify_mbedtls.c @@ -410,7 +410,7 @@ x509_setenv(struct env_set *es, int cert_depth, mbedtls_x509_crt *cert) } result_t -x509_verify_ns_cert_type(const mbedtls_x509_crt *cert, const int usage) +x509_verify_ns_cert_type(mbedtls_x509_crt *cert, const int usage) { if (usage == NS_CERT_CHECK_NONE) { diff --git a/src/openvpn/ssl_verify_openssl.c b/src/openvpn/ssl_verify_openssl.c index 5614a9daccb..2e9bc985009 100644 --- a/src/openvpn/ssl_verify_openssl.c +++ b/src/openvpn/ssl_verify_openssl.c @@ -293,18 +293,20 @@ backend_x509_get_serial_hex(openvpn_x509_cert_t *cert, struct gc_arena *gc) struct buffer x509_get_sha1_fingerprint(X509 *cert, struct gc_arena *gc) { - struct buffer hash = alloc_buf_gc(sizeof(cert->sha1_hash), gc); - memcpy(BPTR(&hash), cert->sha1_hash, sizeof(cert->sha1_hash)); - ASSERT(buf_inc_len(&hash, sizeof(cert->sha1_hash))); + const EVP_MD *sha1 = EVP_sha1(); + struct buffer hash = alloc_buf_gc(EVP_MD_size(sha1), gc); + X509_digest(cert, EVP_sha1(), BPTR(&hash), NULL); + ASSERT(buf_inc_len(&hash, EVP_MD_size(sha1))); return hash; } struct buffer x509_get_sha256_fingerprint(X509 *cert, struct gc_arena *gc) { - struct buffer hash = alloc_buf_gc((EVP_sha256())->md_size, gc); + const EVP_MD *sha256 = EVP_sha256(); + struct buffer hash = alloc_buf_gc(EVP_MD_size(sha256), gc); X509_digest(cert, EVP_sha256(), BPTR(&hash), NULL); - ASSERT(buf_inc_len(&hash, (EVP_sha256())->md_size)); + ASSERT(buf_inc_len(&hash, EVP_MD_size(sha256))); return hash; } @@ -571,7 +573,7 @@ x509_setenv(struct env_set *es, int cert_depth, openvpn_x509_cert_t *peer_cert) } result_t -x509_verify_ns_cert_type(const openvpn_x509_cert_t *peer_cert, const int usage) +x509_verify_ns_cert_type(openvpn_x509_cert_t *peer_cert, const int usage) { if (usage == NS_CERT_CHECK_NONE) { @@ -579,13 +581,59 @@ x509_verify_ns_cert_type(const openvpn_x509_cert_t *peer_cert, const int usage) } if (usage == NS_CERT_CHECK_CLIENT) { - return ((peer_cert->ex_flags & EXFLAG_NSCERT) - && (peer_cert->ex_nscert & NS_SSL_CLIENT)) ? SUCCESS : FAILURE; + /* + * Unfortunately, X509_check_purpose() does some weird thing that + * prevent it to take a const argument + */ + result_t result = X509_check_purpose(peer_cert, X509_PURPOSE_SSL_CLIENT, 0) ? + SUCCESS : FAILURE; + + /* + * old versions of OpenSSL allow us to make the less strict check we used to + * do. If this less strict check pass, warn user that this might not be the + * case when its distribution will update to OpenSSL 1.1 + */ + if (result == FAILURE) + { + ASN1_BIT_STRING *ns; + ns = X509_get_ext_d2i(peer_cert, NID_netscape_cert_type, NULL, NULL); + result = (ns && ns->length > 0 && (ns->data[0] & NS_SSL_CLIENT)) ? SUCCESS : FAILURE; + if (result == SUCCESS) + { + msg(M_WARN, "X509: Certificate is a client certificate yet it's purpose " + "cannot be verified (check may fail in the future)"); + } + ASN1_BIT_STRING_free(ns); + } + return result; } if (usage == NS_CERT_CHECK_SERVER) { - return ((peer_cert->ex_flags & EXFLAG_NSCERT) - && (peer_cert->ex_nscert & NS_SSL_SERVER)) ? SUCCESS : FAILURE; + /* + * Unfortunately, X509_check_purpose() does some weird thing that + * prevent it to take a const argument + */ + result_t result = X509_check_purpose(peer_cert, X509_PURPOSE_SSL_SERVER, 0) ? + SUCCESS : FAILURE; + + /* + * old versions of OpenSSL allow us to make the less strict check we used to + * do. If this less strict check pass, warn user that this might not be the + * case when its distribution will update to OpenSSL 1.1 + */ + if (result == FAILURE) + { + ASN1_BIT_STRING *ns; + ns = X509_get_ext_d2i(peer_cert, NID_netscape_cert_type, NULL, NULL); + result = (ns && ns->length > 0 && (ns->data[0] & NS_SSL_SERVER)) ? SUCCESS : FAILURE; + if (result == SUCCESS) + { + msg(M_WARN, "X509: Certificate is a server certificate yet it's purpose " + "cannot be verified (check may fail in the future)"); + } + ASN1_BIT_STRING_free(ns); + } + return result; } return FAILURE; From cc7c9122dc1d9e87d3f9b953b7d3b3db9166c540 Mon Sep 17 00:00:00 2001 From: Emmanuel Deloget Date: Mon, 12 Jun 2017 15:43:24 +0200 Subject: [PATCH 547/643] OpenSSL: don't use direct access to the internal of EVP_PKEY OpenSSL 1.1 does not allow us to directly access the internal of any data type, including EVP_PKEY. We have to use the defined functions to do so. Compatibility with OpenSSL 1.0 is kept by defining the corresponding functions when they are not found in the library. Signed-off-by: Emmanuel Deloget Acked-by: Steffan Karger Message-Id: <20170612134330.20971-3-logout@free.fr> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14795.html Signed-off-by: Gert Doering (cherry picked from commit b8ca5bc3593e539d0735a74b55ed41a792e55033) --- configure.ac | 3 +++ src/openvpn/openssl_compat.h | 42 ++++++++++++++++++++++++++++++++++++ src/openvpn/ssl_openssl.c | 6 +++--- 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 10a2344f3e5..16a6fd80951 100644 --- a/configure.ac +++ b/configure.ac @@ -905,6 +905,9 @@ if test "${enable_crypto}" = "yes" -a "${with_crypto_library}" = "openssl"; then X509_STORE_get0_objects \ X509_OBJECT_free \ X509_OBJECT_get_type \ + EVP_PKEY_id \ + EVP_PKEY_get0_RSA \ + EVP_PKEY_get0_DSA \ RSA_meth_new \ RSA_meth_free \ RSA_meth_set_pub_enc \ diff --git a/src/openvpn/openssl_compat.h b/src/openvpn/openssl_compat.h index 612bfa567dc..60498595320 100644 --- a/src/openvpn/openssl_compat.h +++ b/src/openvpn/openssl_compat.h @@ -133,6 +133,48 @@ X509_OBJECT_get_type(const X509_OBJECT *obj) } #endif +#if !defined(HAVE_EVP_PKEY_GET0_RSA) +/** + * Get the RSA object of a public key + * + * @param pkey Public key object + * @return The underlying RSA object + */ +static inline RSA * +EVP_PKEY_get0_RSA(EVP_PKEY *pkey) +{ + return pkey ? pkey->pkey.rsa : NULL; +} +#endif + +#if !defined(HAVE_EVP_PKEY_ID) +/** + * Get the PKEY type + * + * @param pkey Public key object + * @return The key type + */ +static inline int +EVP_PKEY_id(const EVP_PKEY *pkey) +{ + return pkey ? pkey->type : EVP_PKEY_NONE; +} +#endif + +#if !defined(HAVE_EVP_PKEY_GET0_DSA) +/** + * Get the DSA object of a public key + * + * @param pkey Public key object + * @return The underlying DSA object + */ +static inline DSA * +EVP_PKEY_get0_DSA(EVP_PKEY *pkey) +{ + return pkey ? pkey->pkey.dsa : NULL; +} +#endif + #if !defined(HAVE_RSA_METH_NEW) /** * Allocate a new RSA method object diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c index 3f7c6d2a9ca..a0e810098f7 100644 --- a/src/openvpn/ssl_openssl.c +++ b/src/openvpn/ssl_openssl.c @@ -1075,7 +1075,7 @@ tls_ctx_use_external_private_key(struct tls_root_ctx *ctx, /* get the public key */ EVP_PKEY *pkey = X509_get0_pubkey(cert); ASSERT(pkey); /* NULL before SSL_CTX_use_certificate() is called */ - pub_rsa = cert->cert_info->key->pkey->pkey.rsa; + pub_rsa = EVP_PKEY_get0_RSA(pkey); /* initialize RSA object */ rsa->n = BN_dup(pub_rsa->n); @@ -1680,13 +1680,13 @@ print_details(struct key_state_ssl *ks_ssl, const char *prefix) EVP_PKEY *pkey = X509_get_pubkey(cert); if (pkey != NULL) { - if (pkey->type == EVP_PKEY_RSA && pkey->pkey.rsa != NULL + if (EVP_PKEY_id(pkey) == EVP_PKEY_RSA && EVP_PKEY_get0_RSA(pkey) != NULL && pkey->pkey.rsa->n != NULL) { openvpn_snprintf(s2, sizeof(s2), ", %d bit RSA", BN_num_bits(pkey->pkey.rsa->n)); } - else if (pkey->type == EVP_PKEY_DSA && pkey->pkey.dsa != NULL + else if (EVP_PKEY_id(pkey) == EVP_PKEY_DSA && EVP_PKEY_get0_DSA(pkey) != NULL && pkey->pkey.dsa->p != NULL) { openvpn_snprintf(s2, sizeof(s2), ", %d bit DSA", From dd1ae0e48d0ce5c715ad6595b21c3cce1f4c8c6b Mon Sep 17 00:00:00 2001 From: Emmanuel Deloget Date: Mon, 12 Jun 2017 15:43:25 +0200 Subject: [PATCH 548/643] OpenSSL: don't use direct access to the internal of RSA OpenSSL 1.1 does not allow us to directly access the internal of any data type, including RSA. We have to use the defined functions to do so. Compatibility with OpenSSL 1.0 is kept by defining the corresponding functions when they are not found in the library. Signed-off-by: Emmanuel Deloget Acked-by: Steffan Karger Message-Id: <20170612134330.20971-4-logout@free.fr> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14790.html Signed-off-by: Gert Doering (cherry picked from commit f7780af6f1aaffcbbfb8b4dde0f2af052f84b28a) --- configure.ac | 4 ++ src/openvpn/openssl_compat.h | 100 +++++++++++++++++++++++++++++++++++ src/openvpn/ssl_openssl.c | 24 +++++---- 3 files changed, 119 insertions(+), 9 deletions(-) diff --git a/configure.ac b/configure.ac index 16a6fd80951..5f7b4f0aa03 100644 --- a/configure.ac +++ b/configure.ac @@ -908,6 +908,10 @@ if test "${enable_crypto}" = "yes" -a "${with_crypto_library}" = "openssl"; then EVP_PKEY_id \ EVP_PKEY_get0_RSA \ EVP_PKEY_get0_DSA \ + RSA_set_flags \ + RSA_bits \ + RSA_get0_key \ + RSA_set0_key \ RSA_meth_new \ RSA_meth_free \ RSA_meth_set_pub_enc \ diff --git a/src/openvpn/openssl_compat.h b/src/openvpn/openssl_compat.h index 60498595320..e3f20b739e0 100644 --- a/src/openvpn/openssl_compat.h +++ b/src/openvpn/openssl_compat.h @@ -175,6 +175,106 @@ EVP_PKEY_get0_DSA(EVP_PKEY *pkey) } #endif +#if !defined(HAVE_RSA_SET_FLAGS) +/** + * Set the RSA flags + * + * @param rsa The RSA object + * @param flags New flags value + */ +static inline void +RSA_set_flags(RSA *rsa, int flags) +{ + if (rsa) + { + rsa->flags = flags; + } +} +#endif + +#if !defined(HAVE_RSA_GET0_KEY) +/** + * Get the RSA parameters + * + * @param rsa The RSA object + * @param n The @c n parameter + * @param e The @c e parameter + * @param d The @c d parameter + */ +static inline void +RSA_get0_key(const RSA *rsa, const BIGNUM **n, + const BIGNUM **e, const BIGNUM **d) +{ + if (n != NULL) + { + *n = rsa ? rsa->n : NULL; + } + if (e != NULL) + { + *e = rsa ? rsa->e : NULL; + } + if (d != NULL) + { + *d = rsa ? rsa->d : NULL; + } +} +#endif + +#if !defined(HAVE_RSA_SET0_KEY) +/** + * Set the RSA parameters + * + * @param rsa The RSA object + * @param n The @c n parameter + * @param e The @c e parameter + * @param d The @c d parameter + * @return 1 on success, 0 on error + */ +static inline int +RSA_set0_key(RSA *rsa, BIGNUM *n, BIGNUM *e, BIGNUM *d) +{ + if ((rsa->n == NULL && n == NULL) + || (rsa->e == NULL && e == NULL)) + { + return 0; + } + + if (n != NULL) + { + BN_free(rsa->n); + rsa->n = n; + } + if (e != NULL) + { + BN_free(rsa->e); + rsa->e = e; + } + if (d != NULL) + { + BN_free(rsa->d); + rsa->d = d; + } + + return 1; +} +#endif + +#if !defined(HAVE_RSA_BITS) +/** + * Number of significant RSA bits + * + * @param rsa The RSA object ; shall not be NULL + * @return The number of RSA bits or 0 on error + */ +static inline int +RSA_bits(const RSA *rsa) +{ + const BIGNUM *n = NULL; + RSA_get0_key(rsa, &n, NULL, NULL); + return n ? BN_num_bits(n) : 0; +} +#endif + #if !defined(HAVE_RSA_METH_NEW) /** * Allocate a new RSA method object diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c index a0e810098f7..50ae29f971a 100644 --- a/src/openvpn/ssl_openssl.c +++ b/src/openvpn/ssl_openssl.c @@ -976,10 +976,13 @@ rsa_priv_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, i /* called at RSA_free */ static int -rsa_finish(RSA *rsa) +openvpn_extkey_rsa_finish(RSA *rsa) { - RSA_meth_free(rsa->meth); - rsa->meth = NULL; + /* meth was allocated in tls_ctx_use_external_private_key() ; since + * this function is called when the parent RSA object is destroyed, + * it is no longer used after this point so kill it. */ + const RSA_METHOD *meth = RSA_get_method(rsa); + RSA_meth_free((RSA_METHOD *)meth); return 1; } @@ -1061,7 +1064,7 @@ tls_ctx_use_external_private_key(struct tls_root_ctx *ctx, RSA_meth_set_priv_enc(rsa_meth, rsa_priv_enc); RSA_meth_set_priv_dec(rsa_meth, rsa_priv_dec); RSA_meth_set_init(rsa_meth, NULL); - RSA_meth_set_finish(rsa_meth, rsa_finish); + RSA_meth_set_finish(rsa_meth, openvpn_extkey_rsa_finish); RSA_meth_set0_app_data(rsa_meth, NULL); /* allocate RSA object */ @@ -1078,8 +1081,11 @@ tls_ctx_use_external_private_key(struct tls_root_ctx *ctx, pub_rsa = EVP_PKEY_get0_RSA(pkey); /* initialize RSA object */ - rsa->n = BN_dup(pub_rsa->n); - rsa->flags |= RSA_FLAG_EXT_PKEY; + const BIGNUM *n = NULL; + const BIGNUM *e = NULL; + RSA_get0_key(pub_rsa, &n, &e, NULL); + RSA_set0_key(rsa, BN_dup(n), BN_dup(e), NULL); + RSA_set_flags(rsa, RSA_flags(rsa) | RSA_FLAG_EXT_PKEY); if (!RSA_set_method(rsa, rsa_meth)) { goto err; @@ -1680,11 +1686,11 @@ print_details(struct key_state_ssl *ks_ssl, const char *prefix) EVP_PKEY *pkey = X509_get_pubkey(cert); if (pkey != NULL) { - if (EVP_PKEY_id(pkey) == EVP_PKEY_RSA && EVP_PKEY_get0_RSA(pkey) != NULL - && pkey->pkey.rsa->n != NULL) + if (EVP_PKEY_id(pkey) == EVP_PKEY_RSA && EVP_PKEY_get0_RSA(pkey) != NULL) { + RSA *rsa = EVP_PKEY_get0_RSA(pkey); openvpn_snprintf(s2, sizeof(s2), ", %d bit RSA", - BN_num_bits(pkey->pkey.rsa->n)); + RSA_bits(rsa)); } else if (EVP_PKEY_id(pkey) == EVP_PKEY_DSA && EVP_PKEY_get0_DSA(pkey) != NULL && pkey->pkey.dsa->p != NULL) From 6f5aa04456f29d7084e004c980e219a21a954fa9 Mon Sep 17 00:00:00 2001 From: Emmanuel Deloget Date: Mon, 12 Jun 2017 15:43:26 +0200 Subject: [PATCH 549/643] OpenSSL: don't use direct access to the internal of DSA OpenSSL 1.1 does not allow us to directly access the internal of any data type, including DSA. We have to use the defined functions to do so. Compatibility with OpenSSL 1.0 is kept by defining the corresponding functions when they are not found in the library. Signed-off-by: Emmanuel Deloget Acked-by: Steffan Karger Message-Id: <20170612134330.20971-5-logout@free.fr> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14791.html Signed-off-by: Gert Doering (cherry picked from commit c07c0358b553c519ed9d80e2e0a9ba48ca8850e4) --- configure.ac | 2 ++ src/openvpn/openssl_compat.h | 44 ++++++++++++++++++++++++++++++++++++ src/openvpn/ssl_openssl.c | 6 ++--- 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index 5f7b4f0aa03..6af96b8cea0 100644 --- a/configure.ac +++ b/configure.ac @@ -912,6 +912,8 @@ if test "${enable_crypto}" = "yes" -a "${with_crypto_library}" = "openssl"; then RSA_bits \ RSA_get0_key \ RSA_set0_key \ + DSA_get0_pqg \ + DSA_bits \ RSA_meth_new \ RSA_meth_free \ RSA_meth_set_pub_enc \ diff --git a/src/openvpn/openssl_compat.h b/src/openvpn/openssl_compat.h index e3f20b739e0..729fab6c56f 100644 --- a/src/openvpn/openssl_compat.h +++ b/src/openvpn/openssl_compat.h @@ -275,6 +275,50 @@ RSA_bits(const RSA *rsa) } #endif +#if !defined(HAVE_DSA_GET0_PQG) +/** + * Get the DSA parameters + * + * @param dsa The DSA object + * @param p The @c p parameter + * @param q The @c q parameter + * @param g The @c g parameter + */ +static inline void +DSA_get0_pqg(const DSA *dsa, const BIGNUM **p, + const BIGNUM **q, const BIGNUM **g) +{ + if (p != NULL) + { + *p = dsa ? dsa->p : NULL; + } + if (q != NULL) + { + *q = dsa ? dsa->q : NULL; + } + if (g != NULL) + { + *g = dsa ? dsa->g : NULL; + } +} +#endif + +#if !defined(HAVE_DSA_BITS) +/** + * Number of significant DSA bits + * + * @param rsa The DSA object ; shall not be NULL + * @return The number of DSA bits or 0 on error + */ +static inline int +DSA_bits(const DSA *dsa) +{ + const BIGNUM *p = NULL; + DSA_get0_pqg(dsa, &p, NULL, NULL); + return p ? BN_num_bits(p) : 0; +} +#endif + #if !defined(HAVE_RSA_METH_NEW) /** * Allocate a new RSA method object diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c index 50ae29f971a..e589dcd9fe3 100644 --- a/src/openvpn/ssl_openssl.c +++ b/src/openvpn/ssl_openssl.c @@ -1692,11 +1692,11 @@ print_details(struct key_state_ssl *ks_ssl, const char *prefix) openvpn_snprintf(s2, sizeof(s2), ", %d bit RSA", RSA_bits(rsa)); } - else if (EVP_PKEY_id(pkey) == EVP_PKEY_DSA && EVP_PKEY_get0_DSA(pkey) != NULL - && pkey->pkey.dsa->p != NULL) + else if (EVP_PKEY_id(pkey) == EVP_PKEY_DSA && EVP_PKEY_get0_DSA(pkey) != NULL) { + DSA *dsa = EVP_PKEY_get0_DSA(pkey); openvpn_snprintf(s2, sizeof(s2), ", %d bit DSA", - BN_num_bits(pkey->pkey.dsa->p)); + DSA_bits(dsa)); } EVP_PKEY_free(pkey); } From 57eaf994379e054203ce42338b4495588ae28c44 Mon Sep 17 00:00:00 2001 From: Emmanuel Deloget Date: Mon, 12 Jun 2017 15:43:30 +0200 Subject: [PATCH 550/643] OpenSSL: force meth->name as non-const when we free() it We are in control of meth->name (we string_alloc() it in RSA_meth_new()) so we know that we can free() it when it's no longer needed. Yet we have to force the value to be non-const to avoid a compiler warning -- due to the fact that OpenSSL defines the value as a const char*, regardless of its origin. Acked-by: Steffan Karger Message-Id: <20170612134330.20971-9-logout@free.fr> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14798.html Signed-off-by: Gert Doering (cherry picked from commit 3fd07c31fe8878dc75e760d151d291379c0f8743) --- src/openvpn/openssl_compat.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/openvpn/openssl_compat.h b/src/openvpn/openssl_compat.h index 729fab6c56f..eeacb525ded 100644 --- a/src/openvpn/openssl_compat.h +++ b/src/openvpn/openssl_compat.h @@ -349,7 +349,13 @@ RSA_meth_free(RSA_METHOD *meth) { if (meth) { - free(meth->name); + /* OpenSSL defines meth->name to be a const pointer, yet we + * feed it with an allocated string (from RSA_meth_new()). + * Thus we are allowed to free it here. In order to avoid a + * "passing 'const char *' to parameter of type 'void *' discards + * qualifiers" warning, we force the pointer to be a non-const value. + */ + free((char *)meth->name); free(meth); } } From d937bb7eccc77ceb668cf64a8b2109329ed2aecd Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sun, 18 Jun 2017 12:57:40 +0200 Subject: [PATCH 551/643] Add a DSA test key/cert pair to sample-keys Makes it easier to test changes to DSA-related code. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <20170618105740.10090-1-steffan@karger.me> URL: https://www.mail-archive.com/search?l=mid&q=20170618105740.10090-1-steffan@karger.me Signed-off-by: Gert Doering (cherry picked from commit 3d215d4c9d107fa153082e2bba8a3a9c8865be5d) --- sample/sample-keys/gen-sample-keys.sh | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/sample/sample-keys/gen-sample-keys.sh b/sample/sample-keys/gen-sample-keys.sh index 301cff2808a..920513a195a 100755 --- a/sample/sample-keys/gen-sample-keys.sh +++ b/sample/sample-keys/gen-sample-keys.sh @@ -61,6 +61,22 @@ openssl ca -batch -config openssl.cnf \ openssl ca -config openssl.cnf -revoke sample-ca/client-revoked.crt openssl ca -config openssl.cnf -gencrl -out sample-ca/ca.crl +# Create DSA server and client cert (signed by 'regular' RSA CA) +openssl dsaparam -out sample-ca/dsaparams.pem 2048 + +openssl req -new -newkey dsa:sample-ca/dsaparams.pem -nodes -config openssl.cnf \ + -extensions server \ + -keyout sample-ca/server-dsa.key -out sample-ca/server-dsa.csr \ + -subj "/C=KG/ST=NA/O=OpenVPN-TEST/CN=Test-Server-DSA/emailAddress=me@myhost.mydomain" +openssl ca -batch -config openssl.cnf -extensions server \ + -out sample-ca/server-dsa.crt -in sample-ca/server-dsa.csr + +openssl req -new -newkey dsa:sample-ca/dsaparams.pem -nodes -config openssl.cnf \ + -keyout sample-ca/client-dsa.key -out sample-ca/client-dsa.csr \ + -subj "/C=KG/ST=NA/O=OpenVPN-TEST/CN=Test-Client-DSA/emailAddress=me@myhost.mydomain" +openssl ca -batch -config openssl.cnf \ + -out sample-ca/client-dsa.crt -in sample-ca/client-dsa.csr + # Create EC server and client cert (signed by 'regular' RSA CA) openssl ecparam -out sample-ca/secp256k1.pem -name secp256k1 From d7b7f93e526a21919ad54ce8cce41c3acc39128d Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sat, 20 May 2017 14:57:55 +0200 Subject: [PATCH 552/643] Fix mbedtls fingerprint calculation Commit 'Migrate to mbed TLS 2.x' (86d8cd68) introduced a bug in mbedtls builds where we would calculate the certificate fingerprint over the (too-short) 'to-be-signed' length of the certificate, rather than over the certificate including the signature. Fix that. The security impact of the incorrect calculation is very minimal; the last few bytes (max 4, typically 4) are not verified by the fingerprint. We expect no real-world impact, because users that used this feature before will notice that it has suddenly stopped working, and users that didn't will notice that connection setup fails. Even if the user managed to somehow extract the incorrect hash (e.g. by reading out the tls_digest_* env vars using a --tls-verify script), the impact is miminal: the last 4 bytes must still be properly signed by the CA, and typically contain extension fields, or the last bytes of the public key (which are hard to choose). The most important bits of the certificate were always checked: the version, serial, signature algorithm, issuer, validity and subject. Signed-off-by: Steffan Karger Acked-by: Arne Schwabe Message-Id: <1495285075-4957-1-git-send-email-steffan@karger.me> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14711.html Signed-off-by: Gert Doering (cherry picked from commit 21a540f92bf65f39eb92967476eba0bcd2a34ef6) --- Changes.rst | 16 ++++++++++++++++ src/openvpn/ssl_verify_mbedtls.c | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/Changes.rst b/Changes.rst index fbe0fc46f9a..94cba070369 100644 --- a/Changes.rst +++ b/Changes.rst @@ -305,10 +305,26 @@ Maintainer-visible changes Version 2.4.3 ============= + +User-visible Changes +-------------------- - ``--verify-hash`` can now take an optional flag which changes the hashing algorithm. It can be either SHA1 or SHA256. The default if not provided is SHA1 to preserve backwards compatibility with existing configurations. +Bugfixes +-------- +- Fix fingerprint calculation in mbed TLS builds. This means that mbed TLS users + of OpenVPN 2.4.0, 2.4.1 and 2.4.2 that rely on the values of the + ``tls_digest_*`` env vars, or that use `--verify-hash` will have to change + the fingerprint values they check against. The security impact of the + incorrect calculation is very minimal; the last few bytes (max 4, typically + 4) are not verified by the fingerprint. We expect no real-world impact, + because users that used this feature before will notice that it has suddenly + stopped working, and users that didn't will notice that connection setup + fails if they specify correct fingerprints. + + Version 2.4.1 ============= - ``--remote-cert-ku`` now only requires the certificate to have at least the diff --git a/src/openvpn/ssl_verify_mbedtls.c b/src/openvpn/ssl_verify_mbedtls.c index 27c5c3e149d..2b7056c830b 100644 --- a/src/openvpn/ssl_verify_mbedtls.c +++ b/src/openvpn/ssl_verify_mbedtls.c @@ -208,7 +208,7 @@ x509_get_fingerprint(const mbedtls_md_info_t *md_info, mbedtls_x509_crt *cert, { const size_t md_size = mbedtls_md_get_size(md_info); struct buffer fingerprint = alloc_buf_gc(md_size, gc); - mbedtls_md(md_info, cert->raw.p, cert->tbs.len, BPTR(&fingerprint)); + mbedtls_md(md_info, cert->raw.p, cert->raw.len, BPTR(&fingerprint)); ASSERT(buf_inc_len(&fingerprint, md_size)); return fingerprint; } From 87a392369d812d8c2ac81174bb2d6fad17544408 Mon Sep 17 00:00:00 2001 From: Emmanuel Deloget Date: Mon, 12 Jun 2017 15:43:27 +0200 Subject: [PATCH 553/643] OpenSSL: don't use direct access to the internal of EVP_MD_CTX OpenSSL 1.1 does not allow us to directly access the internal of any data type, including EVP_MD_CTX. We have to use the defined functions to do so. Compatibility with OpenSSL 1.0 is kept by defining the corresponding functions when they are not found in the library. Signed-off-by: Emmanuel Deloget Acked-by: Steffan Karger Message-Id: <20170612134330.20971-6-logout@free.fr> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14793.html Signed-off-by: Gert Doering (cherry picked from commit c481ef002803f360743c72727ae3ca971ce59a5d) --- configure.ac | 3 ++ src/openvpn/crypto_backend.h | 14 +++++++ src/openvpn/crypto_mbedtls.c | 12 ++++++ src/openvpn/crypto_openssl.c | 18 +++++++-- src/openvpn/httpdigest.c | 78 ++++++++++++++++++------------------ src/openvpn/misc.c | 14 ++++--- src/openvpn/openssl_compat.h | 43 ++++++++++++++++++++ src/openvpn/openvpn.h | 2 +- src/openvpn/push.c | 11 +++-- 9 files changed, 143 insertions(+), 52 deletions(-) diff --git a/configure.ac b/configure.ac index 6af96b8cea0..02b09280571 100644 --- a/configure.ac +++ b/configure.ac @@ -899,6 +899,9 @@ if test "${enable_crypto}" = "yes" -a "${with_crypto_library}" = "openssl"; then AC_CHECK_FUNCS( [ \ + EVP_MD_CTX_new \ + EVP_MD_CTX_free \ + EVP_MD_CTX_reset \ SSL_CTX_get_default_passwd_cb \ SSL_CTX_get_default_passwd_cb_userdata \ X509_get0_pubkey \ diff --git a/src/openvpn/crypto_backend.h b/src/openvpn/crypto_backend.h index e2d2c96f138..f1da0432637 100644 --- a/src/openvpn/crypto_backend.h +++ b/src/openvpn/crypto_backend.h @@ -506,6 +506,20 @@ int md_kt_size(const md_kt_t *kt); */ int md_full(const md_kt_t *kt, const uint8_t *src, int src_len, uint8_t *dst); +/* + * Allocate a new message digest context + * + * @return a new zeroed MD context + */ +md_ctx_t *md_ctx_new(void); + +/* + * Free an existing, non-null message digest context + * + * @param ctx Message digest context + */ +void md_ctx_free(md_ctx_t *ctx); + /* * Initialises the given message digest context. * diff --git a/src/openvpn/crypto_mbedtls.c b/src/openvpn/crypto_mbedtls.c index e6388dd5bda..03cc1308229 100644 --- a/src/openvpn/crypto_mbedtls.c +++ b/src/openvpn/crypto_mbedtls.c @@ -765,6 +765,18 @@ md_full(const md_kt_t *kt, const uint8_t *src, int src_len, uint8_t *dst) return 0 == mbedtls_md(kt, src, src_len, dst); } +mbedtls_md_context_t * +md_ctx_new(void) +{ + mbedtls_md_context_t *ctx; + ALLOC_OBJ_CLEAR(ctx, mbedtls_md_context_t); + return ctx; +} + +void md_ctx_free(mbedtls_md_context_t *ctx) +{ + free(ctx); +} void md_ctx_init(mbedtls_md_context_t *ctx, const mbedtls_md_info_t *kt) diff --git a/src/openvpn/crypto_openssl.c b/src/openvpn/crypto_openssl.c index ee20902f072..3a5a26f8558 100644 --- a/src/openvpn/crypto_openssl.c +++ b/src/openvpn/crypto_openssl.c @@ -41,6 +41,7 @@ #include "integer.h" #include "crypto.h" #include "crypto_backend.h" +#include "openssl_compat.h" #include #include @@ -843,13 +844,24 @@ md_full(const EVP_MD *kt, const uint8_t *src, int src_len, uint8_t *dst) return EVP_Digest(src, src_len, dst, &in_md_len, kt, NULL); } +EVP_MD_CTX * +md_ctx_new(void) +{ + EVP_MD_CTX *ctx = EVP_MD_CTX_new(); + check_malloc_return(ctx); + return ctx; +} + +void md_ctx_free(EVP_MD_CTX *ctx) +{ + EVP_MD_CTX_free(ctx); +} + void md_ctx_init(EVP_MD_CTX *ctx, const EVP_MD *kt) { ASSERT(NULL != ctx && NULL != kt); - CLEAR(*ctx); - EVP_MD_CTX_init(ctx); EVP_DigestInit(ctx, kt); } @@ -857,7 +869,7 @@ md_ctx_init(EVP_MD_CTX *ctx, const EVP_MD *kt) void md_ctx_cleanup(EVP_MD_CTX *ctx) { - EVP_MD_CTX_cleanup(ctx); + EVP_MD_CTX_reset(ctx); } int diff --git a/src/openvpn/httpdigest.c b/src/openvpn/httpdigest.c index e578c85d4d4..c553f939c01 100644 --- a/src/openvpn/httpdigest.c +++ b/src/openvpn/httpdigest.c @@ -80,27 +80,28 @@ DigestCalcHA1( ) { HASH HA1; - md_ctx_t md5_ctx; + md_ctx_t *md5_ctx = md_ctx_new(); const md_kt_t *md5_kt = md_kt_get("MD5"); - md_ctx_init(&md5_ctx, md5_kt); - md_ctx_update(&md5_ctx, (const uint8_t *) pszUserName, strlen(pszUserName)); - md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1); - md_ctx_update(&md5_ctx, (const uint8_t *) pszRealm, strlen(pszRealm)); - md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1); - md_ctx_update(&md5_ctx, (const uint8_t *) pszPassword, strlen(pszPassword)); - md_ctx_final(&md5_ctx, HA1); + md_ctx_init(md5_ctx, md5_kt); + md_ctx_update(md5_ctx, (const uint8_t *) pszUserName, strlen(pszUserName)); + md_ctx_update(md5_ctx, (const uint8_t *) ":", 1); + md_ctx_update(md5_ctx, (const uint8_t *) pszRealm, strlen(pszRealm)); + md_ctx_update(md5_ctx, (const uint8_t *) ":", 1); + md_ctx_update(md5_ctx, (const uint8_t *) pszPassword, strlen(pszPassword)); + md_ctx_final(md5_ctx, HA1); if (pszAlg && strcasecmp(pszAlg, "md5-sess") == 0) { - md_ctx_init(&md5_ctx, md5_kt); - md_ctx_update(&md5_ctx, HA1, HASHLEN); - md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1); - md_ctx_update(&md5_ctx, (const uint8_t *) pszNonce, strlen(pszNonce)); - md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1); - md_ctx_update(&md5_ctx, (const uint8_t *) pszCNonce, strlen(pszCNonce)); - md_ctx_final(&md5_ctx, HA1); + md_ctx_init(md5_ctx, md5_kt); + md_ctx_update(md5_ctx, HA1, HASHLEN); + md_ctx_update(md5_ctx, (const uint8_t *) ":", 1); + md_ctx_update(md5_ctx, (const uint8_t *) pszNonce, strlen(pszNonce)); + md_ctx_update(md5_ctx, (const uint8_t *) ":", 1); + md_ctx_update(md5_ctx, (const uint8_t *) pszCNonce, strlen(pszCNonce)); + md_ctx_final(md5_ctx, HA1); } - md_ctx_cleanup(&md5_ctx); + md_ctx_cleanup(md5_ctx); + md_ctx_free(md5_ctx); CvtHex(HA1, SessionKey); } @@ -122,40 +123,41 @@ DigestCalcResponse( HASH RespHash; HASHHEX HA2Hex; - md_ctx_t md5_ctx; + md_ctx_t *md5_ctx = md_ctx_new(); const md_kt_t *md5_kt = md_kt_get("MD5"); /* calculate H(A2) */ - md_ctx_init(&md5_ctx, md5_kt); - md_ctx_update(&md5_ctx, (const uint8_t *) pszMethod, strlen(pszMethod)); - md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1); - md_ctx_update(&md5_ctx, (const uint8_t *) pszDigestUri, strlen(pszDigestUri)); + md_ctx_init(md5_ctx, md5_kt); + md_ctx_update(md5_ctx, (const uint8_t *) pszMethod, strlen(pszMethod)); + md_ctx_update(md5_ctx, (const uint8_t *) ":", 1); + md_ctx_update(md5_ctx, (const uint8_t *) pszDigestUri, strlen(pszDigestUri)); if (strcasecmp(pszQop, "auth-int") == 0) { - md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1); - md_ctx_update(&md5_ctx, HEntity, HASHHEXLEN); + md_ctx_update(md5_ctx, (const uint8_t *) ":", 1); + md_ctx_update(md5_ctx, HEntity, HASHHEXLEN); } - md_ctx_final(&md5_ctx, HA2); + md_ctx_final(md5_ctx, HA2); CvtHex(HA2, HA2Hex); /* calculate response */ - md_ctx_init(&md5_ctx, md5_kt); - md_ctx_update(&md5_ctx, HA1, HASHHEXLEN); - md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1); - md_ctx_update(&md5_ctx, (const uint8_t *) pszNonce, strlen(pszNonce)); - md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1); + md_ctx_init(md5_ctx, md5_kt); + md_ctx_update(md5_ctx, HA1, HASHHEXLEN); + md_ctx_update(md5_ctx, (const uint8_t *) ":", 1); + md_ctx_update(md5_ctx, (const uint8_t *) pszNonce, strlen(pszNonce)); + md_ctx_update(md5_ctx, (const uint8_t *) ":", 1); if (*pszQop) { - md_ctx_update(&md5_ctx, (const uint8_t *) pszNonceCount, strlen(pszNonceCount)); - md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1); - md_ctx_update(&md5_ctx, (const uint8_t *) pszCNonce, strlen(pszCNonce)); - md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1); - md_ctx_update(&md5_ctx, (const uint8_t *) pszQop, strlen(pszQop)); - md_ctx_update(&md5_ctx, (const uint8_t *) ":", 1); + md_ctx_update(md5_ctx, (const uint8_t *) pszNonceCount, strlen(pszNonceCount)); + md_ctx_update(md5_ctx, (const uint8_t *) ":", 1); + md_ctx_update(md5_ctx, (const uint8_t *) pszCNonce, strlen(pszCNonce)); + md_ctx_update(md5_ctx, (const uint8_t *) ":", 1); + md_ctx_update(md5_ctx, (const uint8_t *) pszQop, strlen(pszQop)); + md_ctx_update(md5_ctx, (const uint8_t *) ":", 1); } - md_ctx_update(&md5_ctx, HA2Hex, HASHHEXLEN); - md_ctx_final(&md5_ctx, RespHash); - md_ctx_cleanup(&md5_ctx); + md_ctx_update(md5_ctx, HA2Hex, HASHHEXLEN); + md_ctx_final(md5_ctx, RespHash); + md_ctx_cleanup(md5_ctx); + md_ctx_free(md5_ctx); CvtHex(RespHash, Response); } diff --git a/src/openvpn/misc.c b/src/openvpn/misc.c index d286c197f8d..df108b08d9e 100644 --- a/src/openvpn/misc.c +++ b/src/openvpn/misc.c @@ -1387,7 +1387,7 @@ get_user_pass_auto_userid(struct user_pass *up, const char *tag) static const uint8_t hashprefix[] = "AUTO_USERID_DIGEST"; const md_kt_t *md5_kt = md_kt_get("MD5"); - md_ctx_t ctx; + md_ctx_t *ctx; CLEAR(*up); buf_set_write(&buf, (uint8_t *)up->username, USER_PASS_LEN); @@ -1395,11 +1395,13 @@ get_user_pass_auto_userid(struct user_pass *up, const char *tag) if (get_default_gateway_mac_addr(macaddr)) { dmsg(D_AUTO_USERID, "GUPAU: macaddr=%s", format_hex_ex(macaddr, sizeof(macaddr), 0, 1, ":", &gc)); - md_ctx_init(&ctx, md5_kt); - md_ctx_update(&ctx, hashprefix, sizeof(hashprefix) - 1); - md_ctx_update(&ctx, macaddr, sizeof(macaddr)); - md_ctx_final(&ctx, digest); - md_ctx_cleanup(&ctx) + ctx = md_ctx_new(); + md_ctx_init(ctx, md5_kt); + md_ctx_update(ctx, hashprefix, sizeof(hashprefix) - 1); + md_ctx_update(ctx, macaddr, sizeof(macaddr)); + md_ctx_final(ctx, digest); + md_ctx_cleanup(ctx); + md_ctx_free(ctx); buf_printf(&buf, "%s", format_hex_ex(digest, sizeof(digest), 0, 256, " ", &gc)); } else diff --git a/src/openvpn/openssl_compat.h b/src/openvpn/openssl_compat.h index eeacb525ded..3d8fad106de 100644 --- a/src/openvpn/openssl_compat.h +++ b/src/openvpn/openssl_compat.h @@ -45,6 +45,49 @@ #include #include +#if !defined(HAVE_EVP_MD_CTX_RESET) +/** + * Reset a message digest context + * + * @param ctx The message digest context + * @return 1 on success, 0 on error + */ +static inline int +EVP_MD_CTX_reset(EVP_MD_CTX *ctx) +{ + EVP_MD_CTX_cleanup(ctx); + return 1; +} +#endif + +#if !defined(HAVE_EVP_MD_CTX_FREE) +/** + * Free an existing message digest context + * + * @param ctx The message digest context + */ +static inline void +EVP_MD_CTX_free(EVP_MD_CTX *ctx) +{ + free(ctx); +} +#endif + +#if !defined(HAVE_EVP_MD_CTX_NEW) +/** + * Allocate a new message digest object + * + * @return A zero'ed message digest object + */ +static inline EVP_MD_CTX * +EVP_MD_CTX_new(void) +{ + EVP_MD_CTX *ctx = NULL; + ALLOC_OBJ_CLEAR(ctx, EVP_MD_CTX); + return ctx; +} +#endif + #if !defined(HAVE_SSL_CTX_GET_DEFAULT_PASSWD_CB_USERDATA) /** * Fetch the default password callback user data from the SSL context diff --git a/src/openvpn/openvpn.h b/src/openvpn/openvpn.h index c01e8a2c224..9262e68ba0d 100644 --- a/src/openvpn/openvpn.h +++ b/src/openvpn/openvpn.h @@ -472,7 +472,7 @@ struct context_2 /* hash of pulled options, so we can compare when options change */ bool pulled_options_digest_init_done; - md_ctx_t pulled_options_state; + md_ctx_t *pulled_options_state; struct sha256_digest pulled_options_digest; struct event_timeout scheduled_exit; diff --git a/src/openvpn/push.c b/src/openvpn/push.c index 441d303e4cd..5947a31f8fe 100644 --- a/src/openvpn/push.c +++ b/src/openvpn/push.c @@ -723,7 +723,8 @@ process_incoming_push_msg(struct context *c, struct buffer buf_orig = buf; if (!c->c2.pulled_options_digest_init_done) { - md_ctx_init(&c->c2.pulled_options_state, md_kt_get("SHA256")); + c->c2.pulled_options_state = md_ctx_new(); + md_ctx_init(c->c2.pulled_options_state, md_kt_get("SHA256")); c->c2.pulled_options_digest_init_done = true; } if (!c->c2.did_pre_pull_restore) @@ -737,14 +738,16 @@ process_incoming_push_msg(struct context *c, option_types_found, c->c2.es)) { - push_update_digest(&c->c2.pulled_options_state, &buf_orig, + push_update_digest(c->c2.pulled_options_state, &buf_orig, &c->options); switch (c->options.push_continuation) { case 0: case 1: - md_ctx_final(&c->c2.pulled_options_state, c->c2.pulled_options_digest.digest); - md_ctx_cleanup(&c->c2.pulled_options_state); + md_ctx_final(c->c2.pulled_options_state, c->c2.pulled_options_digest.digest); + md_ctx_cleanup(c->c2.pulled_options_state); + md_ctx_free(c->c2.pulled_options_state); + c->c2.pulled_options_state = NULL; c->c2.pulled_options_digest_init_done = false; ret = PUSH_MSG_REPLY; break; From a5ac1ecf35f35cecbbb89111f914fe95c5560df2 Mon Sep 17 00:00:00 2001 From: Emmanuel Deloget Date: Mon, 12 Jun 2017 15:43:28 +0200 Subject: [PATCH 554/643] OpenSSL: don't use direct access to the internal of EVP_CIPHER_CTX OpenSSL 1.1 does not allow us to directly access the internal of any data type, including EVP_CIPHER_CTX. We have to use the defined functions to do so. Compatibility with OpenSSL 1.0 is kept by defining the corresponding functions when they are not found in the library. Signed-off-by: Emmanuel Deloget Acked-by: Steffan Karger Message-Id: <20170612134330.20971-7-logout@free.fr> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14796.html Signed-off-by: Gert Doering (cherry picked from commit 6cbd48a3ead23f004f25943d067fa668efdc580e) --- configure.ac | 2 ++ src/openvpn/crypto.c | 4 ++-- src/openvpn/crypto_backend.h | 14 ++++++++++++++ src/openvpn/crypto_mbedtls.c | 13 +++++++++++++ src/openvpn/crypto_openssl.c | 15 +++++++++++++-- src/openvpn/openssl_compat.h | 28 ++++++++++++++++++++++++++++ 6 files changed, 72 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index 02b09280571..652d19db703 100644 --- a/configure.ac +++ b/configure.ac @@ -899,6 +899,8 @@ if test "${enable_crypto}" = "yes" -a "${with_crypto_library}" = "openssl"; then AC_CHECK_FUNCS( [ \ + EVP_CIPHER_CTX_new \ + EVP_CIPHER_CTX_free \ EVP_MD_CTX_new \ EVP_MD_CTX_free \ EVP_MD_CTX_reset \ diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c index afc12e27b12..646e571f102 100644 --- a/src/openvpn/crypto.c +++ b/src/openvpn/crypto.c @@ -851,7 +851,7 @@ init_key_ctx(struct key_ctx *ctx, struct key *key, if (kt->cipher && kt->cipher_length > 0) { - ALLOC_OBJ(ctx->cipher, cipher_ctx_t); + ctx->cipher = cipher_ctx_new(); cipher_ctx_init(ctx->cipher, key->cipher, kt->cipher_length, kt->cipher, enc); @@ -900,7 +900,7 @@ free_key_ctx(struct key_ctx *ctx) if (ctx->cipher) { cipher_ctx_cleanup(ctx->cipher); - free(ctx->cipher); + cipher_ctx_free(ctx->cipher); ctx->cipher = NULL; } if (ctx->hmac) diff --git a/src/openvpn/crypto_backend.h b/src/openvpn/crypto_backend.h index f1da0432637..9679ee9b4f9 100644 --- a/src/openvpn/crypto_backend.h +++ b/src/openvpn/crypto_backend.h @@ -299,6 +299,20 @@ bool cipher_kt_mode_aead(const cipher_kt_t *cipher); * */ +/** + * Allocate a new cipher context + * + * @return a new cipher context + */ +cipher_ctx_t *cipher_ctx_new(void); + +/** + * Free a cipher context + * + * @param ctx Cipher context. + */ +void cipher_ctx_free(cipher_ctx_t *ctx); + /** * Initialise a cipher context, based on the given key and key type. * diff --git a/src/openvpn/crypto_mbedtls.c b/src/openvpn/crypto_mbedtls.c index 03cc1308229..5f16a1f0ff0 100644 --- a/src/openvpn/crypto_mbedtls.c +++ b/src/openvpn/crypto_mbedtls.c @@ -508,6 +508,19 @@ cipher_kt_mode_aead(const cipher_kt_t *cipher) * */ +mbedtls_cipher_context_t * +cipher_ctx_new(void) +{ + mbedtls_cipher_context_t *ctx; + ALLOC_OBJ(ctx, mbedtls_cipher_context_t); + return ctx; +} + +void +cipher_ctx_free(mbedtls_cipher_context_t *ctx) +{ + free(ctx); +} void cipher_ctx_init(mbedtls_cipher_context_t *ctx, uint8_t *key, int key_len, diff --git a/src/openvpn/crypto_openssl.c b/src/openvpn/crypto_openssl.c index 3a5a26f8558..f4470fc0a59 100644 --- a/src/openvpn/crypto_openssl.c +++ b/src/openvpn/crypto_openssl.c @@ -650,6 +650,19 @@ cipher_kt_mode_aead(const cipher_kt_t *cipher) * */ +cipher_ctx_t * +cipher_ctx_new(void) +{ + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); + check_malloc_return(ctx); + return ctx; +} + +void +cipher_ctx_free(EVP_CIPHER_CTX *ctx) +{ + EVP_CIPHER_CTX_free(ctx); +} void cipher_ctx_init(EVP_CIPHER_CTX *ctx, uint8_t *key, int key_len, @@ -657,8 +670,6 @@ cipher_ctx_init(EVP_CIPHER_CTX *ctx, uint8_t *key, int key_len, { ASSERT(NULL != kt && NULL != ctx); - CLEAR(*ctx); - EVP_CIPHER_CTX_init(ctx); if (!EVP_CipherInit(ctx, kt, NULL, NULL, enc)) { diff --git a/src/openvpn/openssl_compat.h b/src/openvpn/openssl_compat.h index 3d8fad106de..c9e2692bba2 100644 --- a/src/openvpn/openssl_compat.h +++ b/src/openvpn/openssl_compat.h @@ -88,6 +88,34 @@ EVP_MD_CTX_new(void) } #endif +#if !defined(HAVE_EVP_CIPHER_CTX_FREE) +/** + * Free an existing cipher context + * + * @param ctx The cipher context + */ +static inline void +EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *c) +{ + free(c); +} +#endif + +#if !defined(HAVE_EVP_CIPHER_CTX_NEW) +/** + * Allocate a new cipher context object + * + * @return A zero'ed cipher context object + */ +static inline EVP_CIPHER_CTX * +EVP_CIPHER_CTX_new(void) +{ + EVP_CIPHER_CTX *ctx = NULL; + ALLOC_OBJ_CLEAR(ctx, EVP_CIPHER_CTX); + return ctx; +} +#endif + #if !defined(HAVE_SSL_CTX_GET_DEFAULT_PASSWD_CB_USERDATA) /** * Fetch the default password callback user data from the SSL context From 2bf4aee4b043151bd2abe7101421fd74763f1230 Mon Sep 17 00:00:00 2001 From: Emmanuel Deloget Date: Mon, 12 Jun 2017 15:43:29 +0200 Subject: [PATCH 555/643] OpenSSL: don't use direct access to the internal of HMAC_CTX OpenSSL 1.1 does not allow us to directly access the internal of any data type, including HMAC_CTX. We have to use the defined functions to do so. Compatibility with OpenSSL 1.0 is kept by defining the corresponding functions when they are not found in the library. Signed-off-by: Emmanuel Deloget Acked-by: Steffan Karger Message-Id: <20170612134330.20971-8-logout@free.fr> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14797.html Signed-off-by: Gert Doering (cherry picked from commit aba98e9050eb54d72d921e70bcd422cb892b9c6c) --- configure.ac | 4 +++ src/openvpn/crypto.c | 4 +-- src/openvpn/crypto_backend.h | 14 ++++++++ src/openvpn/crypto_mbedtls.c | 15 +++++++++ src/openvpn/crypto_openssl.c | 17 ++++++++-- src/openvpn/ntlm.c | 12 +++---- src/openvpn/openssl_compat.h | 65 ++++++++++++++++++++++++++++++++++++ src/openvpn/ssl.c | 38 +++++++++++---------- 8 files changed, 140 insertions(+), 29 deletions(-) diff --git a/configure.ac b/configure.ac index 652d19db703..2f954a34934 100644 --- a/configure.ac +++ b/configure.ac @@ -901,6 +901,10 @@ if test "${enable_crypto}" = "yes" -a "${with_crypto_library}" = "openssl"; then [ \ EVP_CIPHER_CTX_new \ EVP_CIPHER_CTX_free \ + HMAC_CTX_new \ + HMAC_CTX_free \ + HMAC_CTX_reset \ + HMAC_CTX_init \ EVP_MD_CTX_new \ EVP_MD_CTX_free \ EVP_MD_CTX_reset \ diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c index 646e571f102..5f482d08f45 100644 --- a/src/openvpn/crypto.c +++ b/src/openvpn/crypto.c @@ -875,7 +875,7 @@ init_key_ctx(struct key_ctx *ctx, struct key *key, } if (kt->digest && kt->hmac_length > 0) { - ALLOC_OBJ(ctx->hmac, hmac_ctx_t); + ctx->hmac = hmac_ctx_new(); hmac_ctx_init(ctx->hmac, key->hmac, kt->hmac_length, kt->digest); msg(D_HANDSHAKE, @@ -906,7 +906,7 @@ free_key_ctx(struct key_ctx *ctx) if (ctx->hmac) { hmac_ctx_cleanup(ctx->hmac); - free(ctx->hmac); + hmac_ctx_free(ctx->hmac); ctx->hmac = NULL; } ctx->implicit_iv_len = 0; diff --git a/src/openvpn/crypto_backend.h b/src/openvpn/crypto_backend.h index 9679ee9b4f9..b7f519b5bac 100644 --- a/src/openvpn/crypto_backend.h +++ b/src/openvpn/crypto_backend.h @@ -582,6 +582,20 @@ void md_ctx_final(md_ctx_t *ctx, uint8_t *dst); * */ +/* + * Create a new HMAC context + * + * @return A new HMAC context + */ +hmac_ctx_t *hmac_ctx_new(void); + +/* + * Free an existing HMAC context + * + * @param ctx HMAC context to free + */ +void hmac_ctx_free(hmac_ctx_t *ctx); + /* * Initialises the given HMAC context, using the given digest * and key. diff --git a/src/openvpn/crypto_mbedtls.c b/src/openvpn/crypto_mbedtls.c index 5f16a1f0ff0..24bc3158f21 100644 --- a/src/openvpn/crypto_mbedtls.c +++ b/src/openvpn/crypto_mbedtls.c @@ -840,6 +840,21 @@ md_ctx_final(mbedtls_md_context_t *ctx, uint8_t *dst) /* * TODO: re-enable dmsg for crypto debug */ + +mbedtls_md_context_t * +hmac_ctx_new(void) +{ + mbedtls_md_context_t *ctx; + ALLOC_OBJ(ctx, mbedtls_md_context_t); + return ctx; +} + +void +hmac_ctx_free(mbedtls_md_context_t *ctx) +{ + free(ctx); +} + void hmac_ctx_init(mbedtls_md_context_t *ctx, const uint8_t *key, int key_len, const mbedtls_md_info_t *kt) diff --git a/src/openvpn/crypto_openssl.c b/src/openvpn/crypto_openssl.c index f4470fc0a59..a55e65c10be 100644 --- a/src/openvpn/crypto_openssl.c +++ b/src/openvpn/crypto_openssl.c @@ -910,6 +910,19 @@ md_ctx_final(EVP_MD_CTX *ctx, uint8_t *dst) * */ +HMAC_CTX * +hmac_ctx_new(void) +{ + HMAC_CTX *ctx = HMAC_CTX_new(); + check_malloc_return(ctx); + return ctx; +} + +void +hmac_ctx_free(HMAC_CTX *ctx) +{ + HMAC_CTX_free(ctx); +} void hmac_ctx_init(HMAC_CTX *ctx, const uint8_t *key, int key_len, @@ -917,8 +930,6 @@ hmac_ctx_init(HMAC_CTX *ctx, const uint8_t *key, int key_len, { ASSERT(NULL != kt && NULL != ctx); - CLEAR(*ctx); - HMAC_CTX_init(ctx); HMAC_Init_ex(ctx, key, key_len, kt, NULL); @@ -929,7 +940,7 @@ hmac_ctx_init(HMAC_CTX *ctx, const uint8_t *key, int key_len, void hmac_ctx_cleanup(HMAC_CTX *ctx) { - HMAC_CTX_cleanup(ctx); + HMAC_CTX_reset(ctx); } int diff --git a/src/openvpn/ntlm.c b/src/openvpn/ntlm.c index 69b7d426fd7..16d60d2cdd0 100644 --- a/src/openvpn/ntlm.c +++ b/src/openvpn/ntlm.c @@ -85,13 +85,13 @@ static void gen_hmac_md5(const char *data, int data_len, const char *key, int key_len,char *result) { const md_kt_t *md5_kt = md_kt_get("MD5"); - hmac_ctx_t hmac_ctx; - CLEAR(hmac_ctx); + hmac_ctx_t *hmac_ctx = hmac_ctx_new(); - hmac_ctx_init(&hmac_ctx, key, key_len, md5_kt); - hmac_ctx_update(&hmac_ctx, (const unsigned char *)data, data_len); - hmac_ctx_final(&hmac_ctx, (unsigned char *)result); - hmac_ctx_cleanup(&hmac_ctx); + hmac_ctx_init(hmac_ctx, key, key_len, md5_kt); + hmac_ctx_update(hmac_ctx, (const unsigned char *)data, data_len); + hmac_ctx_final(hmac_ctx, (unsigned char *)result); + hmac_ctx_cleanup(hmac_ctx); + hmac_ctx_free(hmac_ctx); } static void diff --git a/src/openvpn/openssl_compat.h b/src/openvpn/openssl_compat.h index c9e2692bba2..c765f0bb9f5 100644 --- a/src/openvpn/openssl_compat.h +++ b/src/openvpn/openssl_compat.h @@ -116,6 +116,71 @@ EVP_CIPHER_CTX_new(void) } #endif +#if !defined(HAVE_HMAC_CTX_RESET) +/** + * Reset a HMAC context + * + * @param ctx The HMAC context + * @return 1 on success, 0 on error + */ +static inline int +HMAC_CTX_reset(HMAC_CTX *ctx) +{ + HMAC_CTX_cleanup(ctx); + return 1; +} +#endif + +#if !defined(HAVE_HMAC_CTX_INIT) +/** + * Init a HMAC context + * + * @param ctx The HMAC context + * + * Contrary to many functions in this file, HMAC_CTX_init() is not + * an OpenSSL 1.1 function: it comes from previous versions and was + * removed in v1.1. As a consequence, there is no distincting in + * v1.1 between a cleanup, and init and a reset. Yet, previous OpenSSL + * version need this distinction. + * + * In order to respect previous OpenSSL versions, we implement init + * as reset for OpenSSL 1.1+. + */ +static inline void +HMAC_CTX_init(HMAC_CTX *ctx) +{ + HMAC_CTX_reset(ctx); +} +#endif + +#if !defined(HAVE_HMAC_CTX_FREE) +/** + * Free an existing HMAC context + * + * @param ctx The HMAC context + */ +static inline void +HMAC_CTX_free(HMAC_CTX *c) +{ + free(c); +} +#endif + +#if !defined(HAVE_HMAC_CTX_NEW) +/** + * Allocate a new HMAC context object + * + * @return A zero'ed HMAC context object + */ +static inline HMAC_CTX * +HMAC_CTX_new(void) +{ + HMAC_CTX *ctx = NULL; + ALLOC_OBJ_CLEAR(ctx, HMAC_CTX); + return ctx; +} +#endif + #if !defined(HAVE_SSL_CTX_GET_DEFAULT_PASSWD_CB_USERDATA) /** * Fetch the default password callback user data from the SSL context diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 80d92c3232f..2780ec0d5ec 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -1606,8 +1606,8 @@ tls1_P_hash(const md_kt_t *md_kt, { struct gc_arena gc = gc_new(); int chunk; - hmac_ctx_t ctx; - hmac_ctx_t ctx_tmp; + hmac_ctx_t *ctx; + hmac_ctx_t *ctx_tmp; uint8_t A1[MAX_HMAC_KEY_LENGTH]; unsigned int A1_len; @@ -1616,8 +1616,8 @@ tls1_P_hash(const md_kt_t *md_kt, const uint8_t *out_orig = out; #endif - CLEAR(ctx); - CLEAR(ctx_tmp); + ctx = hmac_ctx_new(); + ctx_tmp = hmac_ctx_new(); dmsg(D_SHOW_KEY_SOURCE, "tls1_P_hash sec: %s", format_hex(sec, sec_len, 0, &gc)); dmsg(D_SHOW_KEY_SOURCE, "tls1_P_hash seed: %s", format_hex(seed, seed_len, 0, &gc)); @@ -1625,36 +1625,38 @@ tls1_P_hash(const md_kt_t *md_kt, chunk = md_kt_size(md_kt); A1_len = md_kt_size(md_kt); - hmac_ctx_init(&ctx, sec, sec_len, md_kt); - hmac_ctx_init(&ctx_tmp, sec, sec_len, md_kt); + hmac_ctx_init(ctx, sec, sec_len, md_kt); + hmac_ctx_init(ctx_tmp, sec, sec_len, md_kt); - hmac_ctx_update(&ctx,seed,seed_len); - hmac_ctx_final(&ctx, A1); + hmac_ctx_update(ctx,seed,seed_len); + hmac_ctx_final(ctx, A1); for (;; ) { - hmac_ctx_reset(&ctx); - hmac_ctx_reset(&ctx_tmp); - hmac_ctx_update(&ctx,A1,A1_len); - hmac_ctx_update(&ctx_tmp,A1,A1_len); - hmac_ctx_update(&ctx,seed,seed_len); + hmac_ctx_reset(ctx); + hmac_ctx_reset(ctx_tmp); + hmac_ctx_update(ctx,A1,A1_len); + hmac_ctx_update(ctx_tmp,A1,A1_len); + hmac_ctx_update(ctx,seed,seed_len); if (olen > chunk) { - hmac_ctx_final(&ctx, out); + hmac_ctx_final(ctx, out); out += chunk; olen -= chunk; - hmac_ctx_final(&ctx_tmp, A1); /* calc the next A1 value */ + hmac_ctx_final(ctx_tmp, A1); /* calc the next A1 value */ } else /* last one */ { - hmac_ctx_final(&ctx, A1); + hmac_ctx_final(ctx, A1); memcpy(out,A1,olen); break; } } - hmac_ctx_cleanup(&ctx); - hmac_ctx_cleanup(&ctx_tmp); + hmac_ctx_cleanup(ctx); + hmac_ctx_free(ctx); + hmac_ctx_cleanup(ctx_tmp); + hmac_ctx_free(ctx_tmp); secure_memzero(A1, sizeof(A1)); dmsg(D_SHOW_KEY_SOURCE, "tls1_P_hash out: %s", format_hex(out_orig, olen_orig, 0, &gc)); From 529de430ce07d0c3210a4636b1cb4c89cc6c8fc1 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Sun, 18 Jun 2017 21:41:04 +0200 Subject: [PATCH 556/643] Fix potential 1-byte overread in TCP option parsing. A malformed TCP header could lead to a one-byte overread when searching for the MSS option (but as far as we know, with no adverse consequences). Change outer loop to always ensure there's one extra byte available in the buffer examined. Technically, this would cause OpenVPN to ignore the only single-byte TCP option available, 'NOP', if it ends up being the very last option in the buffer - so what, it's a NOP anyway, and all we are interested is MSS, which needs 4 bytes. (https://www.iana.org/assignments/tcp-parameters/tcp-parameters.xhtml) Found and reported by Guido Vranken . Trac: #745 Signed-off-by: Gert Doering Acked-by: Arne Schwabe Message-Id: <20170618194104.25179-1-gert@greenie.muc.de> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14874.html Signed-off-by: Gert Doering (cherry picked from commit 22046a88342878cf43a9a553c83470eeaf97f000) --- src/openvpn/mss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openvpn/mss.c b/src/openvpn/mss.c index ff24068194b..7c596d7812a 100644 --- a/src/openvpn/mss.c +++ b/src/openvpn/mss.c @@ -159,7 +159,7 @@ mss_fixup_dowork(struct buffer *buf, uint16_t maxmss) for (olen = hlen - sizeof(struct openvpn_tcphdr), opt = (uint8_t *)(tc + 1); - olen > 0; + olen > 1; olen -= optlen, opt += optlen) { if (*opt == OPENVPN_TCPOPT_EOL) From e4b0600c990b06ef4c94856e12b24a37110e0860 Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Sat, 25 Feb 2017 08:40:14 +0800 Subject: [PATCH 557/643] Ignore auth-nocache for auth-user-pass if auth-token is pushed When the auth-token option is pushed from the server to the client, the latter has to ignore the auth-nocache directive (if specified). The password will now be substituted by the unique token, therefore it can't be wiped out, otherwise the next renegotiation will fail. Trac: #840 Cc: David Sommerseth Signed-off-by: Antonio Quartulli Acked-by: Arne Schwabe Message-Id: <20170225004014.28638-1-a@unstable.cc> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14194.html Signed-off-by: David Sommerseth (cherry picked from commit 8d941f6fb640ca86b04d1025ef7adcd6d7034829) --- src/openvpn/init.c | 12 ++++++++++++ src/openvpn/misc.c | 7 ++++++- src/openvpn/misc.h | 2 ++ src/openvpn/ssl.c | 33 ++++++++++++++++++++++++++++++++- src/openvpn/ssl.h | 2 ++ 5 files changed, 54 insertions(+), 2 deletions(-) diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 6fd95928827..4c930ff1184 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -1382,6 +1382,18 @@ initialization_sequence_completed(struct context *c, const unsigned int flags) /* If we delayed UID/GID downgrade or chroot, do it now */ do_uid_gid_chroot(c, true); + /* + * In some cases (i.e. when receiving auth-token via + * push-reply) the auth-nocache option configured on the + * client is overridden; for this reason we have to wait + * for the push-reply message before attempting to wipe + * the user/pass entered by the user + */ + if (c->options.mode == MODE_POINT_TO_POINT) + { + delayed_auth_pass_purge(); + } + /* Test if errors */ if (flags & ISC_ERRORS) { diff --git a/src/openvpn/misc.c b/src/openvpn/misc.c index df108b08d9e..fbd9938540e 100644 --- a/src/openvpn/misc.c +++ b/src/openvpn/misc.c @@ -1430,7 +1430,11 @@ purge_user_pass(struct user_pass *up, const bool force) secure_memzero(up, sizeof(*up)); up->nocache = nocache; } - else if (!warn_shown) + /* + * don't show warning if the pass has been replaced by a token: this is an + * artificial "auth-nocache" + */ + else if (!warn_shown && (!up->tokenized)) { msg(M_WARN, "WARNING: this configuration may cache passwords in memory -- use the auth-nocache option to prevent this"); warn_shown = true; @@ -1444,6 +1448,7 @@ set_auth_token(struct user_pass *up, const char *token) { CLEAR(up->password); strncpynt(up->password, token, USER_PASS_LEN); + up->tokenized = true; } } diff --git a/src/openvpn/misc.h b/src/openvpn/misc.h index 94573b217fb..ce965492e91 100644 --- a/src/openvpn/misc.h +++ b/src/openvpn/misc.h @@ -201,6 +201,8 @@ struct user_pass { bool defined; bool nocache; + bool tokenized; /* true if password has been substituted by a token */ + bool wait_for_push; /* true if this object is waiting for a push-reply */ /* max length of username/password */ #ifdef ENABLE_PKCS11 diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 2780ec0d5ec..15cd94ad670 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -451,6 +451,8 @@ ssl_set_auth_nocache(void) { passbuf.nocache = true; auth_user_pass.nocache = true; + /* wait for push-reply, because auth-token may invert nocache */ + auth_user_pass.wait_for_push = true; } /* @@ -459,6 +461,14 @@ ssl_set_auth_nocache(void) void ssl_set_auth_token(const char *token) { + if (auth_user_pass.nocache) + { + msg(M_INFO, + "auth-token received, disabling auth-nocache for the " + "authentication token"); + auth_user_pass.nocache = false; + } + set_auth_token(&auth_user_pass, token); } @@ -2383,7 +2393,21 @@ key_method_2_write(struct buffer *buf, struct tls_session *session) { goto error; } - purge_user_pass(&auth_user_pass, false); + /* if auth-nocache was specified, the auth_user_pass object reaches + * a "complete" state only after having received the push-reply + * message. + * This is the case because auth-token statement in a push-reply would + * invert its nocache. + * + * For this reason, skip the purge operation here if no push-reply + * message has been received yet. + * + * This normally happens upon first negotiation only. + */ + if (!auth_user_pass.wait_for_push) + { + purge_user_pass(&auth_user_pass, false); + } } else { @@ -4226,6 +4250,13 @@ protocol_dump(struct buffer *buffer, unsigned int flags, struct gc_arena *gc) return BSTR(&out); } +void +delayed_auth_pass_purge(void) +{ + auth_user_pass.wait_for_push = false; + purge_user_pass(&auth_user_pass, false); +} + #else /* if defined(ENABLE_CRYPTO) */ static void dummy(void) diff --git a/src/openvpn/ssl.h b/src/openvpn/ssl.h index b119c166dff..56ea601372e 100644 --- a/src/openvpn/ssl.h +++ b/src/openvpn/ssl.h @@ -598,6 +598,8 @@ void extract_x509_field_test(void); */ bool is_hard_reset(int op, int key_method); +void delayed_auth_pass_purge(void); + #endif /* ENABLE_CRYPTO */ #endif /* ifndef OPENVPN_SSL_H */ From df5efe7e2cd23b2282526f2c41be2063d941dff1 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Mon, 19 Jun 2017 15:05:07 +0200 Subject: [PATCH 558/643] auth-token with auth-nocache fix broke --disable-crypto builds After adding commit 571165360db0392fa83e, it broke builds where the --disable-crypto was used with ./configure. This was due to the delayed_auth_pass_purge() which requires the crypto code paths being called from init.c without the proper #ifdef encapsulation. Signed-off-by: David Sommerseth Acked-by: Gert Doering Message-Id: <20170619130507.13892-1-davids@openvpn.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14883.html Signed-off-by: David Sommerseth (cherry picked from commit 5bde5b6d1875fd87b116c943084df0d2f6aee6d0) --- src/openvpn/init.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 4c930ff1184..0652ef4652b 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -1382,6 +1382,8 @@ initialization_sequence_completed(struct context *c, const unsigned int flags) /* If we delayed UID/GID downgrade or chroot, do it now */ do_uid_gid_chroot(c, true); + +#ifdef ENABLE_CRYPTO /* * In some cases (i.e. when receiving auth-token via * push-reply) the auth-nocache option configured on the @@ -1393,6 +1395,7 @@ initialization_sequence_completed(struct context *c, const unsigned int flags) { delayed_auth_pass_purge(); } +#endif /* ENABLE_CRYPTO */ /* Test if errors */ if (flags & ISC_ERRORS) From 67edada0beaf5ce6e47f13526b9f678dad4fc126 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Mon, 19 Jun 2017 11:28:36 +0200 Subject: [PATCH 559/643] mbedtls: fix --x509-track post-authentication remote DoS (CVE-2017-7522) asn1_buf_to_c_string() returned a literal string if the input ASN.1 string contained a NUL character, while the caller expects a mutable string. The caller will attempt to change this string, which allows a client to crash a server by sending a certificate with an embedded NUL character. (The other way around is not interesting, as servers are allowed to stop a client by design.) Impact analysis: * applies to mbedtls builds only * introduced in 2.4 (so 2.3 is not affected) * can only be exploited if the --x509-track option is used * requires the CA to sign a certificate with an embedded NUL in the certificate subject This bug was discovered and reported to the OpenVPN security team by Guido Vranken. CVE: 2017-7522 Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1497864520-12219-2-git-send-email-steffan.karger@fox-it.com> URL: https://www.mail-archive.com/search?l=mid&q=1497864520-12219-2-git-send-email-steffan.karger@fox-it.com Signed-off-by: Gert Doering (cherry picked from commit 426392940c7060300a10077c389f5156c790c2f6) --- Changes.rst | 8 ++++++++ src/openvpn/ssl_verify_mbedtls.c | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Changes.rst b/Changes.rst index 94cba070369..f1aed2d8b46 100644 --- a/Changes.rst +++ b/Changes.rst @@ -306,6 +306,14 @@ Maintainer-visible changes Version 2.4.3 ============= +Security +-------- +- CVE-2017-7522: Fix --x509-track post-authentication remote DoS + A client could crash a 2.4+ mbedtls server, if that server uses the + --x509-track option and the client has a correct, signed and unrevoked + certificate that contains an embedded NUL in the certificate subject. + Discovered and reported to the OpenVPN security team by Guido Vranken. + User-visible Changes -------------------- - ``--verify-hash`` can now take an optional flag which changes the hashing diff --git a/src/openvpn/ssl_verify_mbedtls.c b/src/openvpn/ssl_verify_mbedtls.c index 2b7056c830b..d3b36dcb11b 100644 --- a/src/openvpn/ssl_verify_mbedtls.c +++ b/src/openvpn/ssl_verify_mbedtls.c @@ -271,7 +271,7 @@ asn1_buf_to_c_string(const mbedtls_asn1_buf *orig, struct gc_arena *gc) { if (orig->p[i] == '\0') { - return "ERROR: embedded null value"; + return string_alloc("ERROR: embedded null value", gc); } } val = gc_malloc(orig->len+1, false, gc); From 20f1a472031f0e8ad207ed96acc46ddf51616b5e Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Mon, 19 Jun 2017 11:28:37 +0200 Subject: [PATCH 560/643] mbedtls: require C-string compatible types for --x509-username-field In the --x509-username-field extenstion, we handle the subject string as if it is a C string. Make this assumption explicit and reject incomatible ASN.1 string types. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1497864520-12219-3-git-send-email-steffan.karger@fox-it.com> URL: https://www.mail-archive.com/search?l=mid&q=1497864520-12219-3-git-send-email-steffan.karger@fox-it.com Signed-off-by: Gert Doering (cherry picked from commit 0007b2dbd12a83be3e4aeabc20550a5e16faf214) --- src/openvpn/ssl_verify_mbedtls.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/openvpn/ssl_verify_mbedtls.c b/src/openvpn/ssl_verify_mbedtls.c index d3b36dcb11b..838c2176699 100644 --- a/src/openvpn/ssl_verify_mbedtls.c +++ b/src/openvpn/ssl_verify_mbedtls.c @@ -267,6 +267,14 @@ asn1_buf_to_c_string(const mbedtls_asn1_buf *orig, struct gc_arena *gc) size_t i; char *val; + if (!(orig->tag == MBEDTLS_ASN1_UTF8_STRING + || orig->tag == MBEDTLS_ASN1_PRINTABLE_STRING + || orig->tag == MBEDTLS_ASN1_IA5_STRING)) + { + /* Only support C-string compatible types */ + return string_alloc("ERROR: unsupported ASN.1 string type", gc); + } + for (i = 0; i < orig->len; ++i) { if (orig->p[i] == '\0') From 2341f716198fa90193e040b3fdb16959a47c6c27 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Mon, 19 Jun 2017 11:28:38 +0200 Subject: [PATCH 561/643] Fix remote-triggerable memory leaks (CVE-2017-7521) Several of our OpenSSL-specific certificate-parsing code paths did not always clear all allocated memory. Since a client can cause a few bytes of memory to be leaked for each connection attempt, a client can cause a server to run out of memory and thereby kill the server. That makes this a (quite inefficient) DoS attack. When using the --x509-alt-username option on openssl builds with an extension (argument prefixed with "ext:", e.g. "ext:subjectAltName"), the code would not free all allocated memory. Fix this by using the proper free function. If ASN1_STRING_to_UTF8() returns 0, it didn't fail and *did* allocate memory. So also free the returned buffer if it returns 0. These issues were found, analysed and reported to the OpenVPN team by Guido Vranken. CVE: 2017-7521 Signed-off-by: Steffan Karger Acked-by: Gert Doering Acked-by: David Sommerseth Acked-by: Guido Vranken Message-Id: <1497864520-12219-4-git-send-email-steffan.karger@fox-it.com> URL: https://www.mail-archive.com/search?l=mid&q=1497864520-12219-4-git-send-email-steffan.karger@fox-it.com Signed-off-by: Gert Doering (cherry picked from commit 2d032c7fcdfd692c851ea2fa858b4c2d9ea7d52d) --- Changes.rst | 5 +++++ src/openvpn/ssl_verify_openssl.c | 9 ++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Changes.rst b/Changes.rst index f1aed2d8b46..89cfae87dfa 100644 --- a/Changes.rst +++ b/Changes.rst @@ -313,6 +313,11 @@ Security --x509-track option and the client has a correct, signed and unrevoked certificate that contains an embedded NUL in the certificate subject. Discovered and reported to the OpenVPN security team by Guido Vranken. +- CVE-2017-7521: Fix post-authentication remote-triggerable memory leaks + A client could cause a server to leak a few bytes each time it connects to the + server. That can eventuall cause the server to run out of memory, and thereby + causing the server process to terminate. Discovered and reported to the + OpenVPN security team by Guido Vranken. (OpenSSL builds only.) User-visible Changes -------------------- diff --git a/src/openvpn/ssl_verify_openssl.c b/src/openvpn/ssl_verify_openssl.c index 2e9bc985009..4698cdf4d24 100644 --- a/src/openvpn/ssl_verify_openssl.c +++ b/src/openvpn/ssl_verify_openssl.c @@ -163,7 +163,7 @@ extract_x509_extension(X509 *cert, char *fieldname, char *out, int size) break; } } - sk_GENERAL_NAME_free(extensions); + GENERAL_NAMES_free(extensions); } return retval; } @@ -225,8 +225,7 @@ extract_x509_field_ssl(X509_NAME *x509, const char *field_name, char *out, { return FAILURE; } - tmp = ASN1_STRING_to_UTF8(&buf, asn1); - if (tmp <= 0) + if (ASN1_STRING_to_UTF8(&buf, asn1) < 0) { return FAILURE; } @@ -467,7 +466,7 @@ x509_setenv_track(const struct x509_track *xt, struct env_set *es, const int dep ASN1_STRING *val = X509_NAME_ENTRY_get_data(ent); unsigned char *buf; buf = (unsigned char *)1; /* bug in OpenSSL 0.9.6b ASN1_STRING_to_UTF8 requires this workaround */ - if (ASN1_STRING_to_UTF8(&buf, val) > 0) + if (ASN1_STRING_to_UTF8(&buf, val) >= 0) { do_setenv_x509(es, xt->name, (char *)buf, depth); OPENSSL_free(buf); @@ -555,7 +554,7 @@ x509_setenv(struct env_set *es, int cert_depth, openvpn_x509_cert_t *peer_cert) continue; } buf = (unsigned char *)1; /* bug in OpenSSL 0.9.6b ASN1_STRING_to_UTF8 requires this workaround */ - if (ASN1_STRING_to_UTF8(&buf, val) <= 0) + if (ASN1_STRING_to_UTF8(&buf, val) < 0) { continue; } From b72472baa5f228acf211542a7511f6960479f4c8 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Mon, 19 Jun 2017 11:28:39 +0200 Subject: [PATCH 562/643] Restrict --x509-alt-username extension types The code never supported all extension types. Make this explicit by only allowing subjectAltName and issuerAltName (for which the current code does work). Using unsupported extension fields would most likely cause OpenVPN to crash as soon as a client connects. This does not have a real-world security impact, as such a configuration would not be possible to use in practice. This bug was discovered, analysed and reported to the OpenVPN team by Guido Vranken. Signed-off-by: Steffan Karger Acked-by: Gert Doering Acked-by: David Sommerseth Acked-by: Guido Vranken Message-Id: <1497864520-12219-5-git-send-email-steffan.karger@fox-it.com> URL: https://www.mail-archive.com/search?l=mid&q=1497864520-12219-5-git-send-email-steffan.karger@fox-it.com Signed-off-by: Gert Doering (cherry picked from commit d2a19185fd78030ce4a1bba6c9f83e0dac9e15a6) --- Changes.rst | 3 +++ doc/openvpn.8 | 2 ++ src/openvpn/options.c | 4 ++++ src/openvpn/ssl_verify_backend.h | 8 ++++++++ src/openvpn/ssl_verify_openssl.c | 19 ++++++++++++++++--- 5 files changed, 33 insertions(+), 3 deletions(-) diff --git a/Changes.rst b/Changes.rst index 89cfae87dfa..6fa1c0c66fe 100644 --- a/Changes.rst +++ b/Changes.rst @@ -324,6 +324,9 @@ User-visible Changes - ``--verify-hash`` can now take an optional flag which changes the hashing algorithm. It can be either SHA1 or SHA256. The default if not provided is SHA1 to preserve backwards compatibility with existing configurations. +- Restrict the supported --x509-alt-username extension fields to subjectAltName + and issuerAltName. Other extensions probably didn't work anyway, and would + cause OpenVPN to crash when a client connects. Bugfixes -------- diff --git a/doc/openvpn.8 b/doc/openvpn.8 index d48de898088..56c0f7a6943 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -5308,6 +5308,8 @@ option will match against the chosen .B fieldname instead of the Common Name. +Only the subjectAltName and issuerAltName X.509 extensions are supported. + .B Please note: This option has a feature which will convert an all-lowercase .B fieldname diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 5248b0660b6..fef5e9054af 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -8099,6 +8099,10 @@ add_option(struct options *options, "configuration", p[1]); } } + else if (!x509_username_field_ext_supported(s+4)) + { + msg(msglevel, "Unsupported x509-username-field extension: %s", s); + } options->x509_username_field = p[1]; } #endif /* ENABLE_X509ALTUSERNAME */ diff --git a/src/openvpn/ssl_verify_backend.h b/src/openvpn/ssl_verify_backend.h index 978e54fdff6..e8eaabe9e58 100644 --- a/src/openvpn/ssl_verify_backend.h +++ b/src/openvpn/ssl_verify_backend.h @@ -124,6 +124,14 @@ struct buffer x509_get_sha256_fingerprint(openvpn_x509_cert_t *cert, result_t backend_x509_get_username(char *common_name, int cn_len, char *x509_username_field, openvpn_x509_cert_t *peer_cert); +#ifdef ENABLE_X509ALTUSERNAME +/** + * Return true iff the supplied extension field is supported by the + * --x509-username-field option. + */ +bool x509_username_field_ext_supported(const char *extname); +#endif + /* * Return the certificate's serial number in decimal string representation. * diff --git a/src/openvpn/ssl_verify_openssl.c b/src/openvpn/ssl_verify_openssl.c index 4698cdf4d24..5679028a5ae 100644 --- a/src/openvpn/ssl_verify_openssl.c +++ b/src/openvpn/ssl_verify_openssl.c @@ -113,16 +113,29 @@ verify_callback(int preverify_ok, X509_STORE_CTX *ctx) } #ifdef ENABLE_X509ALTUSERNAME +bool x509_username_field_ext_supported(const char *fieldname) +{ + int nid = OBJ_txt2nid(fieldname); + return nid == NID_subject_alt_name || nid == NID_issuer_alt_name; +} + static bool extract_x509_extension(X509 *cert, char *fieldname, char *out, int size) { bool retval = false; char *buf = 0; - GENERAL_NAMES *extensions; - int nid = OBJ_txt2nid(fieldname); - extensions = (GENERAL_NAMES *)X509_get_ext_d2i(cert, nid, NULL, NULL); + if (!x509_username_field_ext_supported(fieldname)) + { + msg(D_TLS_ERRORS, + "ERROR: --x509-alt-username field 'ext:%s' not supported", + fieldname); + return false; + } + + int nid = OBJ_txt2nid(fieldname); + GENERAL_NAMES *extensions = X509_get_ext_d2i(cert, nid, NULL, NULL); if (extensions) { int numalts; From 040084067119dd5a9e15eb3bcfc0079debaa3777 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Mon, 19 Jun 2017 11:28:40 +0200 Subject: [PATCH 563/643] Fix potential double-free in --x509-alt-username (CVE-2017-7521) We didn't check the return value of ASN1_STRING_to_UTF8() in extract_x509_extension(). Ignoring such a failure could result in buf being free'd twice. An error in ASN1_STRING_to_UTF8() can be caused remotely if the peer can make the local process run out of memory. The problem can only be triggered for configurations that use the --x509-alt-username option with an x509 extension (i.e. the option parameter starts with "ext:"). This issue was discovered, analysed and reported to the OpenVPN team by Guido Vranken. Extensive testing by Guido Vranken gives confidence that this function is very unlikely to fail in real-world usage (using subjectAltName or issuerAltName extensions) for other reasons than memory exhaustion. CVE: 2017-7521 Signed-off-by: Steffan Karger Acked-by: Gert Doering Acked-by: David Sommerseth Acked-by: Guido Vranken Message-Id: <1497864520-12219-6-git-send-email-steffan.karger@fox-it.com> URL: https://www.mail-archive.com/search?l=mid&q=1497864520-12219-6-git-send-email-steffan.karger@fox-it.com Signed-off-by: Gert Doering (cherry picked from commit cb4e35ece4a5b70b10ef9013be3bff263d82f32b) --- Changes.rst | 7 +++++++ src/openvpn/ssl_verify_openssl.c | 5 ++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Changes.rst b/Changes.rst index 6fa1c0c66fe..726e591d059 100644 --- a/Changes.rst +++ b/Changes.rst @@ -318,6 +318,13 @@ Security server. That can eventuall cause the server to run out of memory, and thereby causing the server process to terminate. Discovered and reported to the OpenVPN security team by Guido Vranken. (OpenSSL builds only.) +- CVE-2017-7521: Fix a potential post-authentication remote code execution + attack on servers that use the ``--x509-alt-username`` option with an X.509 + extension field (option argument prefixed with ``ext:``). A client that can + cause a server to run out-of-memory (see above) might be able to cause the + server to double free, which in turn might lead to remote code execution. + Discovered and reported to the OpenVPN security team by Guido Vranken. + (OpenSSL builds only.) User-visible Changes -------------------- diff --git a/src/openvpn/ssl_verify_openssl.c b/src/openvpn/ssl_verify_openssl.c index 5679028a5ae..468b4956d87 100644 --- a/src/openvpn/ssl_verify_openssl.c +++ b/src/openvpn/ssl_verify_openssl.c @@ -156,7 +156,10 @@ extract_x509_extension(X509 *cert, char *fieldname, char *out, int size) switch (name->type) { case GEN_EMAIL: - ASN1_STRING_to_UTF8((unsigned char **)&buf, name->d.ia5); + if (ASN1_STRING_to_UTF8((unsigned char **)&buf, name->d.ia5) < 0) + { + continue; + } if (strlen(buf) != name->d.ia5->length) { msg(D_TLS_ERRORS, "ASN1 ERROR: string contained terminating zero"); From 043fe327878eba75efa13794c9845f85c3c629f2 Mon Sep 17 00:00:00 2001 From: Guido Vranken Date: Fri, 19 May 2017 14:04:25 +0200 Subject: [PATCH 564/643] Prevent two kinds of stack buffer OOB reads and a crash for invalid input data Pre-authentication remote crash/information disclosure for clients If clients use a HTTP proxy with NTLM authentication (i.e. "--http-proxy [|'auto'|'auto-nct'] ntlm2"), a man-in-the-middle attacker between the client and the proxy can cause the client to crash or disclose at most 96 bytes of stack memory. The disclosed stack memory is likely to contain the proxy password. If the proxy password is not reused, this is unlikely to compromise the security of the OpenVPN tunnel itself. Clients who do not use the --http-proxy option with ntlm2 authentication are not affected. CVE: 2017-7520 Signed-off-by: Guido Vranken Acked-by: Gert Doering Message-Id: URL: https://www.mail-archive.com/search?l=mid&q=CAO5O-EJvHKid-zTj+hmFG_3Gv78ixqCayE9=C62DZaxN32WNtQ@mail.gmail.com Signed-off-by: Gert Doering (cherry picked from commit 7718c8984f04b507c1885f363970e2124e3c6c77) --- src/openvpn/ntlm.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/openvpn/ntlm.c b/src/openvpn/ntlm.c index 16d60d2cdd0..0b1163ee465 100644 --- a/src/openvpn/ntlm.c +++ b/src/openvpn/ntlm.c @@ -195,7 +195,7 @@ ntlm_phase_3(const struct http_proxy_info *p, const char *phase_2, struct gc_are */ char pwbuf[sizeof(p->up.password) * 2]; /* for unicode password */ - char buf2[128]; /* decoded reply from proxy */ + unsigned char buf2[128]; /* decoded reply from proxy */ unsigned char phase3[464]; char md4_hash[MD4_DIGEST_LENGTH+5]; @@ -301,7 +301,13 @@ ntlm_phase_3(const struct http_proxy_info *p, const char *phase_2, struct gc_are tib_len = 96; } { - char *tib_ptr = buf2 + buf2[0x2c]; /* Get Target Information block pointer */ + char *tib_ptr; + int tib_pos = buf2[0x2c]; + if (tib_pos + tib_len > sizeof(buf2)) + { + return NULL; + } + tib_ptr = buf2 + tib_pos; /* Get Target Information block pointer */ memcpy(&ntlmv2_blob[0x1c], tib_ptr, tib_len); /* Copy Target Information block into the blob */ } } From ed28cde3d8bf3f1459b2f42f0e27d64801009f92 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Tue, 13 Jun 2017 22:08:32 +0200 Subject: [PATCH 565/643] Fix remotely-triggerable ASSERT() on malformed IPv6 packet. Correct sanity checks on IPv6 packet length in mss_fixup_ipv6(), and change the ASSERT() check in mss_fixup_dowork() into a simple "return" (= the TCP header will simply not be inspected further). CVE-2017-7508 has been assigned due to the serious nature of the bug: it can be used to remotely shutdown an openvpn server or client, if IPv6 and --mssfix are enabled and the IPv6 networks used inside the VPN are known. Found by Guido Vranken . v2: style changes CVE: 2017-7508 Signed-off-by: Gert Doering Acked-by: Steffan Karger Message-Id: <20170613200832.15027-1-gert@greenie.muc.de> URL: https://www.mail-archive.com/search?l=mid&q=20170613200832.15027-1-gert@greenie.muc.de Signed-off-by: Gert Doering (cherry picked from commit c3f47077a7756de5929094569421a95aa66f2022) --- src/openvpn/mss.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/openvpn/mss.c b/src/openvpn/mss.c index 7c596d7812a..c36e004648e 100644 --- a/src/openvpn/mss.c +++ b/src/openvpn/mss.c @@ -119,8 +119,12 @@ mss_fixup_ipv6(struct buffer *buf, int maxmss) return; } + /* skip IPv6 header (40 bytes), + * verify remainder is large enough to contain a full TCP header + */ newbuf = *buf; - if (buf_advance( &newbuf, 40 ) ) + if (buf_advance( &newbuf, 40 ) + && BLEN(&newbuf) >= (int) sizeof(struct openvpn_tcphdr)) { struct openvpn_tcphdr *tc = (struct openvpn_tcphdr *) BPTR(&newbuf); if (tc->flags & OPENVPN_TCPH_SYN_MASK) @@ -144,7 +148,10 @@ mss_fixup_dowork(struct buffer *buf, uint16_t maxmss) int accumulate; struct openvpn_tcphdr *tc; - ASSERT(BLEN(buf) >= (int) sizeof(struct openvpn_tcphdr)); + if (BLEN(buf) < (int) sizeof(struct openvpn_tcphdr)) + { + return; + } verify_align_4(buf); tc = (struct openvpn_tcphdr *) BPTR(buf); From db34435863eab6845d395848e472d940b053e436 Mon Sep 17 00:00:00 2001 From: Gert Doering Date: Mon, 19 Jun 2017 19:44:00 +0200 Subject: [PATCH 566/643] Preparing for release v2.4.3 (ChangeLog, version.m4, Changes.rst) (cherry picking commit ce05fb508a1841883df2067517c9a4706734db60 for updates and cleanup of Changes.rst) General cleanup help, UTF8 fixes, whitespace and quoting fixes for ChangeLog and Changes.rst provided by David Sommerseth --- ChangeLog | 62 ++++++++++++++++++++++++++++++++++ Changes.rst | 96 ++++++++++++++++++++++++++++++++++++++++++----------- version.m4 | 4 +-- 3 files changed, 141 insertions(+), 21 deletions(-) diff --git a/ChangeLog b/ChangeLog index 00c2e2f86c8..537beaafa43 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,68 @@ OpenVPN Change Log Copyright (C) 2002-2017 OpenVPN Technologies, Inc. +2017.06.21 -- Version 2.4.3 +Antonio Quartulli (1): + Ignore auth-nocache for auth-user-pass if auth-token is pushed + +David Sommerseth (3): + crypto: Enable SHA256 fingerprint checking in --verify-hash + copyright: Update GPLv2 license texts + auth-token with auth-nocache fix broke --disable-crypto builds + +Emmanuel Deloget (8): + OpenSSL: don't use direct access to the internal of X509 + OpenSSL: don't use direct access to the internal of EVP_PKEY + OpenSSL: don't use direct access to the internal of RSA + OpenSSL: don't use direct access to the internal of DSA + OpenSSL: force meth->name as non-const when we free() it + OpenSSL: don't use direct access to the internal of EVP_MD_CTX + OpenSSL: don't use direct access to the internal of EVP_CIPHER_CTX + OpenSSL: don't use direct access to the internal of HMAC_CTX + +Gert Doering (6): + Fix NCP behaviour on TLS reconnect. + Remove erroneous limitation on max number of args for --plugin + Fix edge case with clients failing to set up cipher on empty PUSH_REPLY. + Fix potential 1-byte overread in TCP option parsing. + Fix remotely-triggerable ASSERT() on malformed IPv6 packet. + Update Changes.rst with relevant info for 2.4.3 release. + +Guido Vranken (6): + refactor my_strupr + Fix 2 memory leaks in proxy authentication routine + Fix memory leak in add_option() for option 'connection' + Ensure option array p[] is always NULL-terminated + Fix a null-pointer dereference in establish_http_proxy_passthru() + Prevent two kinds of stack buffer OOB reads and a crash for invalid input data + +Jérémie Courrèges-Anglas (2): + Fix an unaligned access on OpenBSD/sparc64 + Missing include for socket-flags TCP_NODELAY on OpenBSD + +Matthias Andree (1): + Make openvpn-plugin.h self-contained again. + +Selva Nair (1): + Pass correct buffer size to GetModuleFileNameW() + +Steffan Karger (11): + Log the negotiated (NCP) cipher + Avoid a 1 byte overcopy in x509_get_subject (ssl_verify_openssl.c) + Skip tls-crypt unit tests if required crypto mode not supported + openssl: fix overflow check for long --tls-cipher option + Add a DSA test key/cert pair to sample-keys + Fix mbedtls fingerprint calculation + mbedtls: fix --x509-track post-authentication remote DoS (CVE-2017-7522) + mbedtls: require C-string compatible types for --x509-username-field + Fix remote-triggerable memory leaks (CVE-2017-7521) + Restrict --x509-alt-username extension types + Fix potential double-free in --x509-alt-username (CVE-2017-7521) + +Steven McDonald (1): + Fix gateway detection with OpenBSD routing domains + + 2017.05.11 -- Version 2.4.2 David Sommerseth (5): auth-token: Ensure tokens are always wiped on de-auth diff --git a/Changes.rst b/Changes.rst index 726e591d059..454dde43b74 100644 --- a/Changes.rst +++ b/Changes.rst @@ -177,6 +177,7 @@ Deprecated features - ``--no-iv`` is deprecated in 2.4 and will be removed in 2.5. + User-visible Changes -------------------- - When using ciphers with cipher blocks less than 128-bits, @@ -303,43 +304,82 @@ Maintainer-visible changes use -std=gnu99 in CFLAGS. This is known to be needed when doing i386/i686 builds on RHEL5. + + Version 2.4.3 ============= +New features +------------ +- Support building with OpenSSL 1.1 now (in addition to older versions) + +- On Win10, set low interface metric for TAP adapter when block-outside-dns + is in use, to make Windows prefer the TAP adapter for DNS queries + (avoiding large delays) + + Security -------- -- CVE-2017-7522: Fix --x509-track post-authentication remote DoS +- CVE-2017-7522: Fix ``--x509-track`` post-authentication remote DoS A client could crash a 2.4+ mbedtls server, if that server uses the - --x509-track option and the client has a correct, signed and unrevoked + ``--x509-track`` option and the client has a correct, signed and unrevoked certificate that contains an embedded NUL in the certificate subject. Discovered and reported to the OpenVPN security team by Guido Vranken. + - CVE-2017-7521: Fix post-authentication remote-triggerable memory leaks A client could cause a server to leak a few bytes each time it connects to the server. That can eventuall cause the server to run out of memory, and thereby causing the server process to terminate. Discovered and reported to the OpenVPN security team by Guido Vranken. (OpenSSL builds only.) + - CVE-2017-7521: Fix a potential post-authentication remote code execution - attack on servers that use the ``--x509-alt-username`` option with an X.509 + attack on servers that use the ``--x509-username-field`` option with an X.509 extension field (option argument prefixed with ``ext:``). A client that can cause a server to run out-of-memory (see above) might be able to cause the server to double free, which in turn might lead to remote code execution. Discovered and reported to the OpenVPN security team by Guido Vranken. (OpenSSL builds only.) +- CVE-2017-7520: Pre-authentication remote crash/information disclosure for + clients. If clients use a HTTP proxy with NTLM authentication (i.e. + ``--http-proxy [|'auto'|'auto-nct'] ntlm2``), + a man-in-the-middle attacker between the client and the proxy can cause + the client to crash or disclose at most 96 bytes of stack memory. The + disclosed stack memory is likely to contain the proxy password. If the + proxy password is not reused, this is unlikely to compromise the security + of the OpenVPN tunnel itself. Clients who do not use the ``--http-proxy`` + option with ntlm2 authentication are not affected. + +- CVE-2017-7508: Fix remotely-triggerable ASSERT() on malformed IPv6 packet. + This can be used to remotely shutdown an openvpn server or client, if + IPv6 and ``--mssfix`` are enabled and the IPv6 networks used inside the VPN + are known. + +- Fix null-pointer dereference when talking to a malicious http proxy + that returns a malformed Proxy-Authenticate: headers for digest auth. + +- Fix overflow check for long ``--tls-cipher`` option + +- Windows: Pass correct buffer size to ``GetModuleFileNameW()`` + (OSTIF/Quarkslabs audit, finding 5.6) + + User-visible Changes -------------------- - ``--verify-hash`` can now take an optional flag which changes the hashing algorithm. It can be either SHA1 or SHA256. The default if not provided is SHA1 to preserve backwards compatibility with existing configurations. -- Restrict the supported --x509-alt-username extension fields to subjectAltName + +- Restrict the supported ``--x509-username-field`` extension fields to subjectAltName and issuerAltName. Other extensions probably didn't work anyway, and would cause OpenVPN to crash when a client connects. + Bugfixes -------- - Fix fingerprint calculation in mbed TLS builds. This means that mbed TLS users of OpenVPN 2.4.0, 2.4.1 and 2.4.2 that rely on the values of the - ``tls_digest_*`` env vars, or that use `--verify-hash` will have to change + ``tls_digest_*`` env vars, or that use ``--verify-hash`` will have to change the fingerprint values they check against. The security impact of the incorrect calculation is very minimal; the last few bytes (max 4, typically 4) are not verified by the fingerprint. We expect no real-world impact, @@ -347,21 +387,19 @@ Bugfixes stopped working, and users that didn't will notice that connection setup fails if they specify correct fingerprints. +- Fix edge case with NCP when the server sends an empty PUSH_REPLY message + back, and the client would not initialize it's data channel crypto layer + properly (trac #903) -Version 2.4.1 -============= -- ``--remote-cert-ku`` now only requires the certificate to have at least the - bits set of one of the values in the supplied list, instead of requiring an - exact match to one of the values in the list. -- ``--remote-cert-tls`` now only requires that a keyUsage is present in the - certificate, and leaves the verification of the value up to the crypto - library, which has more information (i.e. the key exchange method in use) - to verify that the keyUsage is correct. -- ``--ns-cert-type`` is deprecated. Use ``--remote-cert-tls`` instead. - The nsCertType x509 extension is very old, and barely used. - ``--remote-cert-tls`` uses the far more common keyUsage and extendedKeyUsage - extension instead. Make sure your certificates carry these to be able to - use ``--remote-cert-tls``. +- Fix SIGSEGV on unaligned buffer access on OpenBSD/Sparc64 + +- Fix TCP_NODELAY on OpenBSD + +- Remove erroneous limitation on max number of args for --plugin + +- Fix NCP behaviour on TLS reconnect (Server would not send a proper + "cipher ..." message back to the client, leading to client and server + using different ciphers) (trac #887) Version 2.4.2 @@ -379,7 +417,27 @@ Security to hit an ASSERT() and stop the process. If ``--tls-auth`` or ``--tls-crypt`` is used, only attackers that have the ``--tls-auth`` or ``--tls-crypt`` key can mount an attack. (OSTIF/Quarkslab audit finding 5.1, CVE-2017-7478) + - Fix an authenticated remote DoS vulnerability that could be triggered by causing a packet id roll over. An attack is rather inefficient; a peer would need to get us to send at least about 196 GB of data. (OSTIF/Quarkslab audit finding 5.2, CVE-2017-7479) + + +Version 2.4.1 +============= +- ``--remote-cert-ku`` now only requires the certificate to have at least the + bits set of one of the values in the supplied list, instead of requiring an + exact match to one of the values in the list. + +- ``--remote-cert-tls`` now only requires that a keyUsage is present in the + certificate, and leaves the verification of the value up to the crypto + library, which has more information (i.e. the key exchange method in use) + to verify that the keyUsage is correct. + +- ``--ns-cert-type`` is deprecated. Use ``--remote-cert-tls`` instead. + The nsCertType x509 extension is very old, and barely used. + ``--remote-cert-tls`` uses the far more common keyUsage and extendedKeyUsage + extension instead. Make sure your certificates carry these to be able to + use ``--remote-cert-tls``. + diff --git a/version.m4 b/version.m4 index 73ca1e89151..f18193b595e 100644 --- a/version.m4 +++ b/version.m4 @@ -3,12 +3,12 @@ define([PRODUCT_NAME], [OpenVPN]) define([PRODUCT_TARNAME], [openvpn]) define([PRODUCT_VERSION_MAJOR], [2]) define([PRODUCT_VERSION_MINOR], [4]) -define([PRODUCT_VERSION_PATCH], [.2]) +define([PRODUCT_VERSION_PATCH], [.3]) m4_append([PRODUCT_VERSION], [PRODUCT_VERSION_MAJOR]) m4_append([PRODUCT_VERSION], [PRODUCT_VERSION_MINOR], [[.]]) m4_append([PRODUCT_VERSION], [PRODUCT_VERSION_PATCH], [[]]) define([PRODUCT_BUGREPORT], [openvpn-users@lists.sourceforge.net]) -define([PRODUCT_VERSION_RESOURCE], [2,4,2,0]) +define([PRODUCT_VERSION_RESOURCE], [2,4,3,0]) dnl define the TAP version define([PRODUCT_TAP_WIN_COMPONENT_ID], [tap0901]) define([PRODUCT_TAP_WIN_MIN_MAJOR], [9]) From 20884e5e64e8fb30d6b1cbf1f0749ebef5dea283 Mon Sep 17 00:00:00 2001 From: Emmanuel Deloget Date: Mon, 19 Jun 2017 17:35:13 +0200 Subject: [PATCH 567/643] OpenSSL: remove pre-1.1 function from the OpenSSL compat interface HMAC_CTX_init() has been removed from OpenSSL 1.1. Both this function and function HMAC_CTX_cleanup() has been replaced by HMAC_CTX_reset(). Commit aba98e9050eb54d72d921e70bcd422cb892b9c6c introduced support for HMAC_CTX_init() for OpenSSL 1.1+ while other functions were mimicking the OpenSSL 1.1 interface for earlier version. This is clearly not a good idea -- a better approach would be to provide the new interface for pre-1.1 versions in order to have the dependant code use only one interface version. To implement that, we remove HMAC_CTX_init() from our compatibility layer and implement HMAC_CTX_reset() in terms of a cleanup followed by an init (as the regular HMAC_CTX_reset() function does in OpenSSL 1.1. This change has a consequence on HMAC_CTX_free() which now need to cleanup() the HMAC context before freeing it. Acked-by: Steffan Karger Message-Id: <20170619153513.5420-1-logout@free.fr> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14889.html Signed-off-by: Gert Doering (cherry picked from commit 64b8a4ae9d7edb39f802d0d4cbdf9d46116f2461) --- configure.ac | 1 - src/openvpn/crypto_openssl.c | 2 +- src/openvpn/openssl_compat.h | 39 +++++++++++++----------------------- 3 files changed, 15 insertions(+), 27 deletions(-) diff --git a/configure.ac b/configure.ac index 2f954a34934..f2ee5b9ec6e 100644 --- a/configure.ac +++ b/configure.ac @@ -904,7 +904,6 @@ if test "${enable_crypto}" = "yes" -a "${with_crypto_library}" = "openssl"; then HMAC_CTX_new \ HMAC_CTX_free \ HMAC_CTX_reset \ - HMAC_CTX_init \ EVP_MD_CTX_new \ EVP_MD_CTX_free \ EVP_MD_CTX_reset \ diff --git a/src/openvpn/crypto_openssl.c b/src/openvpn/crypto_openssl.c index a55e65c10be..9cf3355b77c 100644 --- a/src/openvpn/crypto_openssl.c +++ b/src/openvpn/crypto_openssl.c @@ -930,7 +930,7 @@ hmac_ctx_init(HMAC_CTX *ctx, const uint8_t *key, int key_len, { ASSERT(NULL != kt && NULL != ctx); - HMAC_CTX_init(ctx); + HMAC_CTX_reset(ctx); HMAC_Init_ex(ctx, key, key_len, kt, NULL); /* make sure we used a big enough key */ diff --git a/src/openvpn/openssl_compat.h b/src/openvpn/openssl_compat.h index c765f0bb9f5..617410e02eb 100644 --- a/src/openvpn/openssl_compat.h +++ b/src/openvpn/openssl_compat.h @@ -120,6 +120,15 @@ EVP_CIPHER_CTX_new(void) /** * Reset a HMAC context * + * OpenSSL 1.1+ removes APIs HMAC_CTX_init() and HMAC_CTX_cleanup() + * and replace them with a single call that does a cleanup followed + * by an init. A proper _reset() for OpenSSL < 1.1 should perform + * a similar set of operations. + * + * It means that before we kill a HMAC context, we'll have to cleanup + * again, as we probably have allocated a few resources when we forced + * an init. + * * @param ctx The HMAC context * @return 1 on success, 0 on error */ @@ -127,42 +136,22 @@ static inline int HMAC_CTX_reset(HMAC_CTX *ctx) { HMAC_CTX_cleanup(ctx); + HMAC_CTX_init(ctx); return 1; } #endif -#if !defined(HAVE_HMAC_CTX_INIT) -/** - * Init a HMAC context - * - * @param ctx The HMAC context - * - * Contrary to many functions in this file, HMAC_CTX_init() is not - * an OpenSSL 1.1 function: it comes from previous versions and was - * removed in v1.1. As a consequence, there is no distincting in - * v1.1 between a cleanup, and init and a reset. Yet, previous OpenSSL - * version need this distinction. - * - * In order to respect previous OpenSSL versions, we implement init - * as reset for OpenSSL 1.1+. - */ -static inline void -HMAC_CTX_init(HMAC_CTX *ctx) -{ - HMAC_CTX_reset(ctx); -} -#endif - #if !defined(HAVE_HMAC_CTX_FREE) /** - * Free an existing HMAC context + * Cleanup and free an existing HMAC context * * @param ctx The HMAC context */ static inline void -HMAC_CTX_free(HMAC_CTX *c) +HMAC_CTX_free(HMAC_CTX *ctx) { - free(c); + HMAC_CTX_cleanup(ctx); + free(ctx); } #endif From c3e6e6889931d33cba02b75715edfedce5c8cdab Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Wed, 21 Jun 2017 23:21:31 +0200 Subject: [PATCH 568/643] Fix typo in extract_x509_extension() debug message This message should use the external name, not the internal one. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <20170621212131.6776-1-steffan@karger.me> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14939.html Signed-off-by: Gert Doering (cherry picked from commit 0402c7faadf907d4c0c1398e9250293527d4054f) --- src/openvpn/ssl_verify_openssl.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/openvpn/ssl_verify_openssl.c b/src/openvpn/ssl_verify_openssl.c index 468b4956d87..d3e3ca02d24 100644 --- a/src/openvpn/ssl_verify_openssl.c +++ b/src/openvpn/ssl_verify_openssl.c @@ -129,8 +129,7 @@ extract_x509_extension(X509 *cert, char *fieldname, char *out, int size) if (!x509_username_field_ext_supported(fieldname)) { msg(D_TLS_ERRORS, - "ERROR: --x509-alt-username field 'ext:%s' not supported", - fieldname); + "ERROR: --x509-username-field 'ext:%s' not supported", fieldname); return false; } From d3c0b2b6b743ef8db37f8c63dc77ffe6b421a2df Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Tue, 27 Jun 2017 20:00:47 +0800 Subject: [PATCH 569/643] crypto: correct typ0 in error message Signed-off-by: Antonio Quartulli Acked-by: Steffan Karger Message-Id: <20170627120047.12304-1-a@unstable.cc> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14975.html Signed-off-by: Gert Doering (cherry picked from commit 778aca3d251b6a563ffbabef95816fab863825e1) --- src/openvpn/crypto.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c index 5f482d08f45..db0265c2d94 100644 --- a/src/openvpn/crypto.c +++ b/src/openvpn/crypto.c @@ -1284,7 +1284,7 @@ read_key_file(struct key2 *key2, const char *file, const unsigned int flags) fd = platform_open(file, O_RDONLY, 0); if (fd == -1) { - msg(M_ERR, "Cannot open file key file '%s'", file); + msg(M_ERR, "Cannot open key file '%s'", file); } size = read(fd, in.data, in.capacity); if (size < 0) From 95c07b13ce112ceb8b15175fcae0d95c70e93eee Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Mon, 26 Jun 2017 13:13:26 +0200 Subject: [PATCH 570/643] Set tls-cipher restriction before loading certificates OpenSSL 1.1 does not allow MD5 signed certificates by default anymore. This can be enabled again by settings tls-cipher "DEFAULT:@SECLEVEL=0" but only if the cipher list is set before loading the certificates. This patch changes the order of loading. Acked-by: Christian Hesse Acked-by: Steffan Karger Message-Id: <1498475606-8337-1-git-send-email-arne@rfc2549.org> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14961.html Signed-off-by: Gert Doering (cherry picked from commit 26345ba61b8d5bccb1331894ab6d1468e3b09adf) --- src/openvpn/ssl.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 15cd94ad670..98f4741bddc 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -616,6 +616,11 @@ init_ssl(const struct options *options, struct tls_root_ctx *new_ctx) tls_ctx_client_new(new_ctx); } + /* Allowable ciphers */ + /* Since @SECLEVEL also influces loading of certificates, set the + * cipher restrictions before loading certificates */ + tls_ctx_restrict_ciphers(new_ctx, options->cipher_list); + tls_ctx_set_options(new_ctx, options->ssl_flags); if (options->pkcs12_file) @@ -708,9 +713,6 @@ init_ssl(const struct options *options, struct tls_root_ctx *new_ctx) tls_ctx_load_ecdh_params(new_ctx, options->ecdh_curve); } - /* Allowable ciphers */ - tls_ctx_restrict_ciphers(new_ctx, options->cipher_list); - #ifdef ENABLE_CRYPTO_MBEDTLS /* Personalise the random by mixing in the certificate */ tls_ctx_personalise_random(new_ctx); From 8b55a445385ce55244cb659b8cdd0dc3156550af Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Wed, 21 Jun 2017 23:10:43 +0200 Subject: [PATCH 571/643] Move adjust_power_of_2() to integer.h misc.c is a mess of incoherent functions, and is therefore included by virtually all our source files. That makes testing harder than it should be. As a first step of cleaning up misc.c, move adjust_power_of_2() to integer.h, which is a more suitable place for a function like this. This allows us to remove the duplicate implementation from test_argv.c. Signed-off-by: Steffan Karger Acked-by: Antonio Quartulli Message-Id: <20170621211043.6490-1-steffan@karger.me> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14940.html Signed-off-by: Gert Doering (cherry picked from commit 9fc0e963c757ffec3cc9fbf797fb7609f409c370) --- src/openvpn/argv.c | 1 + src/openvpn/integer.h | 18 ++++++++++++++++++ src/openvpn/list.c | 1 + src/openvpn/mbuf.c | 1 + src/openvpn/misc.c | 18 ------------------ src/openvpn/misc.h | 2 -- tests/unit_tests/openvpn/test_argv.c | 18 ------------------ 7 files changed, 21 insertions(+), 38 deletions(-) diff --git a/src/openvpn/argv.c b/src/openvpn/argv.c index a71d261ca03..95bdfeac4b5 100644 --- a/src/openvpn/argv.c +++ b/src/openvpn/argv.c @@ -36,6 +36,7 @@ #include "syshead.h" #include "argv.h" +#include "integer.h" #include "options.h" static void diff --git a/src/openvpn/integer.h b/src/openvpn/integer.h index 240781b7ba8..9bb00a38516 100644 --- a/src/openvpn/integer.h +++ b/src/openvpn/integer.h @@ -118,6 +118,24 @@ modulo_add(int x, int y, int mod) return sum; } +/* + * Return the next largest power of 2 + * or u if u is a power of 2. + */ +static inline size_t +adjust_power_of_2(size_t u) +{ + size_t ret = 1; + + while (ret < u) + { + ret <<= 1; + ASSERT(ret > 0); + } + + return ret; +} + static inline int index_verify(int index, int size, const char *file, int line) { diff --git a/src/openvpn/list.c b/src/openvpn/list.c index edca6f796e0..91765d20264 100644 --- a/src/openvpn/list.c +++ b/src/openvpn/list.c @@ -31,6 +31,7 @@ #if P2MP_SERVER +#include "integer.h" #include "list.h" #include "misc.h" diff --git a/src/openvpn/mbuf.c b/src/openvpn/mbuf.c index fafbce0138f..f969a2b5b30 100644 --- a/src/openvpn/mbuf.c +++ b/src/openvpn/mbuf.c @@ -33,6 +33,7 @@ #include "buffer.h" #include "error.h" +#include "integer.h" #include "misc.h" #include "mbuf.h" diff --git a/src/openvpn/misc.c b/src/openvpn/misc.c index fbd9938540e..965869a7cf1 100644 --- a/src/openvpn/misc.c +++ b/src/openvpn/misc.c @@ -1645,24 +1645,6 @@ openvpn_sleep(const int n) sleep(n); } -/* - * Return the next largest power of 2 - * or u if u is a power of 2. - */ -size_t -adjust_power_of_2(size_t u) -{ - size_t ret = 1; - - while (ret < u) - { - ret <<= 1; - ASSERT(ret > 0); - } - - return ret; -} - /* * Remove security-sensitive strings from control message * so that they will not be output to log file. diff --git a/src/openvpn/misc.h b/src/openvpn/misc.h index ce965492e91..3116ec424ea 100644 --- a/src/openvpn/misc.h +++ b/src/openvpn/misc.h @@ -327,8 +327,6 @@ extern const char *iproute_path; #define SSEC_PW_ENV 3 /* allow calling of built-in programs and user-defined scripts that may receive a password as an environmental variable */ extern int script_security; /* GLOBAL */ -/* return the next largest power of 2 */ -size_t adjust_power_of_2(size_t u); #define COMPAT_FLAG_QUERY 0 /** compat_flags operator: Query for a flag */ #define COMPAT_FLAG_SET (1<<0) /** compat_flags operator: Set a compat flag */ diff --git a/tests/unit_tests/openvpn/test_argv.c b/tests/unit_tests/openvpn/test_argv.c index 8c90eb9c32f..4a3ba559baf 100644 --- a/tests/unit_tests/openvpn/test_argv.c +++ b/tests/unit_tests/openvpn/test_argv.c @@ -13,24 +13,6 @@ #include "argv.h" #include "buffer.h" -/* - * This is defined here to prevent #include'ing misc.h - * which makes things difficult beyond any recognition - */ -size_t -adjust_power_of_2(size_t u) -{ - size_t ret = 1; - - while (ret < u) - { - ret <<= 1; - assert(ret > 0); - } - - return ret; -} - /* Defines for use in the tests and the mock parse_line() */ #define PATH1 "/s p a c e" #define PATH2 "/foo bar/baz" From 5852a035b444a41140a7fc7007b7df718a2e6c43 Mon Sep 17 00:00:00 2001 From: Ilya Shipitsin Date: Sat, 25 Feb 2017 23:00:04 +0500 Subject: [PATCH 572/643] travis-ci: add 3 missing patches from master to release/2.4 travis-ci: add 'make distcheck' to test scenario, V2 in rare cases openvpn is built from tarball, it happens during "installer build" process. "make distcheck" helps to prevent problems during such builds. V2: limit "make distcheck" to one build configuration Signed-off-by: Ilya Shipitsin Acked-by: Steffan Karger Message-Id: <1488045604-25460-1-git-send-email-chipitsine@gmail.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14208.html Signed-off-by: Gert Doering (cherry picked from commit 56e6bd8967d72c4374389dfd5cf32f5e3b86242c) v4, travis-ci: add 2 mingw "build only" configurations Inspired by https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg13032.html build options are taken from regular windows installer builds Signed-off-by: Ilya Shipitsin Acked-by: Steffan Karger Message-Id: <1494007697-6882-1-git-send-email-chipitsine@gmail.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14542.html Signed-off-by: David Sommerseth (cherry picked from commit 81ba70b39b78d7677aabab957421264800028f53) travis-ci: added gcc and clang openssl-1.1.0 builds openssl build script was modified according to official openssl manual: https://wiki.openssl.org/index.php/Compilation_and_Installation Acked-by: Steffan Karger Message-Id: <1497897488-15999-1-git-send-email-chipitsine@gmail.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14890.html Signed-off-by: Gert Doering (cherry picked from commit aeac1139a34321a7f770ca20bfef886a21a89fe9) --- .travis.yml | 29 ++++++++---- .travis/build-check.sh | 30 ++++++++++++ .travis/build-deps.sh | 102 ++++++++++++++++++++++++++++++++++++++--- 3 files changed, 144 insertions(+), 17 deletions(-) create mode 100755 .travis/build-check.sh diff --git a/.travis.yml b/.travis.yml index a68374ae1f8..db90e03a055 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,6 +12,9 @@ env: global: - JOBS=3 - PREFIX="${HOME}/opt" + - TAP_WINDOWS_VERSION=9.21.2 + - LZO_VERSION=2.10 + - PKCS11_HELPER_VERSION=1.11 - MBEDTLS_VERSION="2.4.0" - MBEDTLS_CFLAGS="-I${PREFIX}/include" - MBEDTLS_LIBS="-L${PREFIX}/lib -lmbedtls -lmbedx509 -lmbedcrypto" @@ -24,16 +27,22 @@ matrix: - env: SSLLIB="openssl" os: linux compiler: gcc + - env: SSLLIB="openssl" OPENSSL_VERSION="1.1.0f" + os: linux + compiler: gcc - env: SSLLIB="openssl" os: linux compiler: clang + - env: SSLLIB="openssl" OPENSSL_VERSION="1.1.0f" + os: linux + compiler: clang - env: SSLLIB="mbedtls" os: linux compiler: gcc - env: SSLLIB="mbedtls" os: linux compiler: clang - - env: SSLLIB="openssl" EXTRA_CONFIG="--disable-crypto" + - env: SSLLIB="openssl" EXTRA_CONFIG="--disable-crypto" EXTRA_SCRIPT="make distcheck" os: linux compiler: clang - env: SSLLIB="openssl" EXTRA_CONFIG="--disable-lzo" @@ -50,6 +59,12 @@ matrix: os: osx osx_image: xcode7.3 compiler: clang + - env: SSLLIB="openssl" CHOST=x86_64-w64-mingw32 + os: linux + compiler: ": Win64 build only" + - env: SSLLIB="openssl" CHOST=i686-w64-mingw32 + os: linux + compiler: ": Win32 build only" exclude: - compiler: gcc @@ -60,6 +75,7 @@ addons: - libpam0g-dev - liblz4-dev - linux-libc-dev + - man2html cache: ccache: true @@ -72,15 +88,8 @@ before_install: - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then brew install lzo; fi install: + - if [ ! -z "${CHOST}" ]; then unset CC; fi - .travis/build-deps.sh > build-deps.log 2>&1 || (cat build-deps.log && exit 1) script: - - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then export LD_LIBRARY_PATH="${PREFIX}/lib:${LD_LIBRARY_PATH}"; fi - - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then export DYLD_LIBRARY_PATH="${PREFIX}/lib:${DYLD_LIBRARY_PATH}"; fi - - autoreconf -vi - - ./configure --with-crypto-library="${SSLLIB}" ${EXTRA_CONFIG} || (cat config.log && exit 1) - - make -j$JOBS - - src/openvpn/openvpn --version || true - - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ldd src/openvpn/openvpn; fi - - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then otool -L src/openvpn/openvpn; fi - - make check + - .travis/build-check.sh diff --git a/.travis/build-check.sh b/.travis/build-check.sh new file mode 100755 index 00000000000..74f3ae10ce5 --- /dev/null +++ b/.travis/build-check.sh @@ -0,0 +1,30 @@ +#!/bin/sh +set -eux + +if [ "${TRAVIS_OS_NAME}" = "linux" ]; then + export LD_LIBRARY_PATH="${PREFIX}/lib:${LD_LIBRARY_PATH:-}" +fi + +if [ "${TRAVIS_OS_NAME}" = "osx" ]; then + export DYLD_LIBRARY_PATH="${PREFIX}/lib:${DYLD_LIBRARY_PATH:-}" +fi + +autoreconf -vi + +if [ -z ${CHOST+x} ]; then + ./configure --with-crypto-library="${SSLLIB}" ${EXTRA_CONFIG:-} || (cat config.log && exit 1) + make -j$JOBS + src/openvpn/openvpn --version || true + if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ldd src/openvpn/openvpn; fi + if [ "${TRAVIS_OS_NAME}" = "osx" ]; then otool -L src/openvpn/openvpn; fi + make check + ${EXTRA_SCRIPT:-} +else + export TAP_CFLAGS="-I${PWD}/tap-windows-${TAP_WINDOWS_VERSION}/include" + export LZO_CFLAGS="-I${PREFIX}/include" + export LZO_LIBS="-L${PREFIX}/lib -llzo2" + export PKCS11_HELPER_LIBS="-L${PREFIX}/lib -lpkcs11-helper" + export PKCS11_HELPER_CFLAGS="-I${PREFIX}/include" + ./configure --with-crypto-library="${SSLLIB}" --host=${CHOST} --build=x86_64-pc-linux-gnu --enable-pkcs11 --disable-plugins || (cat config.log && exit 1) + make -j${JOBS} +fi diff --git a/.travis/build-deps.sh b/.travis/build-deps.sh index 3ffba0bc02b..9cc18584f73 100755 --- a/.travis/build-deps.sh +++ b/.travis/build-deps.sh @@ -4,6 +4,55 @@ set -eux # Set defaults PREFIX="${PREFIX:-${HOME}/opt}" +download_tap_windows () { + if [ ! -f "download-cache/tap-windows-${TAP_WINDOWS_VERSION}.zip" ]; then + wget -P download-cache/ \ + "http://build.openvpn.net/downloads/releases/tap-windows-${TAP_WINDOWS_VERSION}.zip" + fi +} + +download_lzo () { + if [ ! -f "download-cache/lzo-${LZO_VERSION}.tar.gz" ]; then + wget -P download-cache/ \ + "http://www.oberhumer.com/opensource/lzo/download/lzo-${LZO_VERSION}.tar.gz" + fi +} + +build_lzo () { + if [ "$(cat ${PREFIX}/.lzo-version)" != "${LZO_VERSION}" ]; then + tar zxf download-cache/lzo-${LZO_VERSION}.tar.gz + ( + cd "lzo-${LZO_VERSION}" + + ./configure --host=${CHOST} --program-prefix='' \ + --libdir=${PREFIX}/lib --prefix=${PREFIX} --build=x86_64-pc-linux-gnu + make all install + ) + echo "${LZO_VERSION}" > "${PREFIX}/.lzo-version" + fi +} + +download_pkcs11_helper () { + if [ ! -f "pkcs11-helper-${PKCS11_HELPER_VERSION}.tar.bz2" ]; then + wget -P download-cache/ \ + "http://downloads.sourceforge.net/project/opensc/pkcs11-helper/pkcs11-helper-${PKCS11_HELPER_VERSION}.tar.bz2" + fi +} + +build_pkcs11_helper () { + if [ "$(cat ${PREFIX}/.pkcs11_helper-version)" != "${PKCS11_HELPER_VERSION}" ]; then + tar jxf download-cache/pkcs11-helper-${PKCS11_HELPER_VERSION}.tar.bz2 + ( + cd "pkcs11-helper-${PKCS11_HELPER_VERSION}" + + ./configure --host=${CHOST} --program-prefix='' --libdir=${PREFIX}/lib \ + --prefix=${PREFIX} --build=x86_64-pc-linux-gnu --disable-crypto-engine-gnutls --disable-crypto-engine-nss + make all install + ) + echo "${PKCS11_HELPER_VERSION}" > "${PREFIX}/.pkcs11_helper-version" + fi +} + download_mbedtls () { if [ ! -f "download-cache/mbedtls-${MBEDTLS_VERSION}-apache.tgz" ]; then wget -P download-cache/ \ @@ -31,27 +80,44 @@ download_openssl () { } build_openssl_linux () { - tar zxf "download-cache/openssl-${OPENSSL_VERSION}.tar.gz" ( cd "openssl-${OPENSSL_VERSION}/" - ./config shared --openssldir="${PREFIX}" -DPURIFY + ./config shared --prefix="${PREFIX}" --openssldir="${PREFIX}" -DPURIFY make all install_sw ) } build_openssl_osx () { - tar zxf "download-cache/openssl-${OPENSSL_VERSION}.tar.gz" ( cd "openssl-${OPENSSL_VERSION}/" ./Configure darwin64-x86_64-cc shared \ - --openssldir="${PREFIX}" -DPURIFY + --prefix="${PREFIX}" --openssldir="${PREFIX}" -DPURIFY make depend all install_sw ) } +build_openssl_mingw () { + ( + cd "openssl-${OPENSSL_VERSION}/" + + if [ "${CHOST}" = "i686-w64-mingw32" ]; then + export TARGET=mingw + elif [ "${CHOST}" = "x86_64-w64-mingw32" ]; then + export TARGET=mingw64 + fi + + ./Configure --cross-compile-prefix=${CHOST}- shared \ + ${TARGET} no-multilib no-capieng --prefix="${PREFIX}" --openssldir="${PREFIX}" -static-libgcc + make install + ) +} + build_openssl () { if [ "$(cat ${PREFIX}/.openssl-version)" != "${OPENSSL_VERSION}" ]; then - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then + tar zxf "download-cache/openssl-${OPENSSL_VERSION}.tar.gz" + if [ ! -z ${CHOST+x} ]; then + build_openssl_mingw + elif [ "${TRAVIS_OS_NAME}" = "osx" ]; then build_openssl_osx elif [ "${TRAVIS_OS_NAME}" = "linux" ]; then build_openssl_linux @@ -61,16 +127,25 @@ build_openssl () { } # Enable ccache -if [ "${TRAVIS_OS_NAME}" != "osx" ]; then +if [ "${TRAVIS_OS_NAME}" != "osx" ] && [ -z ${CHOST+x} ]; then # ccache not available on osx, see: # https://github.com/travis-ci/travis-ci/issues/5567 + # also ccache not enabled for cross builds mkdir -p "${HOME}/bin" ln -s "$(which ccache)" "${HOME}/bin/${CC}" PATH="${HOME}/bin:${PATH}" fi +if [ ! -z ${CHOST+x} ]; then + # + # openvpn requires at least mingw-gcc-4.9, which is available at xenial repo + # + sudo apt-add-repository "deb http://archive.ubuntu.com/ubuntu xenial main universe" + sudo apt-get update + sudo apt-get -y install dpkg mingw-w64 +fi + # Download and build crypto lib -mkdir -p download-cache if [ "${SSLLIB}" = "openssl" ]; then download_openssl build_openssl @@ -81,3 +156,16 @@ else echo "Invalid crypto lib: ${SSLLIB}" exit 1 fi + +# Download and build dependencies for mingw cross build +# dependencies are the same as in regular windows installer build +if [ ! -z ${CHOST+x} ]; then + download_tap_windows + unzip download-cache/tap-windows-${TAP_WINDOWS_VERSION}.zip + + download_lzo + build_lzo + + download_pkcs11_helper + build_pkcs11_helper +fi From 0f9575852bc981e75884d1a75b2e7c1f9af091f4 Mon Sep 17 00:00:00 2001 From: Emmanuel Deloget Date: Thu, 29 Jun 2017 16:21:18 +0200 Subject: [PATCH 573/643] OpenSSL: remove EVP_CIPHER_CTX_new() from the compat layer For unknown reason, the writer of the compat layer seemed to think that this function was only present in OpenSSL 1.1. This is not the case at all, since it has been introduced in OpenSSL before version 0.9.8. Thus, there is no need to add this function to the compat layer, and it can be safely removed. Signed-off-by: Emmanuel Deloget Acked-by: Steffan Karger Message-Id: <20170629142119.29502-1-logout@free.fr> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14989.html Signed-off-by: Gert Doering (cherry picked from commit a72d21a56a0223b8a50d05d88af64abcda0fc5dc) --- configure.ac | 1 - src/openvpn/openssl_compat.h | 15 --------------- 2 files changed, 16 deletions(-) diff --git a/configure.ac b/configure.ac index f2ee5b9ec6e..2e5c47fa473 100644 --- a/configure.ac +++ b/configure.ac @@ -899,7 +899,6 @@ if test "${enable_crypto}" = "yes" -a "${with_crypto_library}" = "openssl"; then AC_CHECK_FUNCS( [ \ - EVP_CIPHER_CTX_new \ EVP_CIPHER_CTX_free \ HMAC_CTX_new \ HMAC_CTX_free \ diff --git a/src/openvpn/openssl_compat.h b/src/openvpn/openssl_compat.h index 617410e02eb..cd25bd378b5 100644 --- a/src/openvpn/openssl_compat.h +++ b/src/openvpn/openssl_compat.h @@ -101,21 +101,6 @@ EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *c) } #endif -#if !defined(HAVE_EVP_CIPHER_CTX_NEW) -/** - * Allocate a new cipher context object - * - * @return A zero'ed cipher context object - */ -static inline EVP_CIPHER_CTX * -EVP_CIPHER_CTX_new(void) -{ - EVP_CIPHER_CTX *ctx = NULL; - ALLOC_OBJ_CLEAR(ctx, EVP_CIPHER_CTX); - return ctx; -} -#endif - #if !defined(HAVE_HMAC_CTX_RESET) /** * Reset a HMAC context From ebb5c70bf6acede8d941687ae0e40d827003fb2e Mon Sep 17 00:00:00 2001 From: Emmanuel Deloget Date: Thu, 29 Jun 2017 16:21:19 +0200 Subject: [PATCH 574/643] OpenSSL: remove EVP_CIPHER_CTX_free() from the compat layer For unknown reason, the writer of the compat layer seemed to think that this function was only present in OpenSSL 1.1. This is not the case at all, since it has been introduced in OpenSSL before version 0.9.8. Thus, there is no need to add this function to the compat layer, and it can be safely removed. Signed-off-by: Emmanuel Deloget Acked-by: Steffan Karger Message-Id: <20170629142119.29502-2-logout@free.fr> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14988.html Signed-off-by: Gert Doering (cherry picked from commit 7ee9a94fcbbde941bfed167229a64df0f7cdae0b) --- configure.ac | 1 - src/openvpn/openssl_compat.h | 13 ------------- 2 files changed, 14 deletions(-) diff --git a/configure.ac b/configure.ac index 2e5c47fa473..d372295ebd1 100644 --- a/configure.ac +++ b/configure.ac @@ -899,7 +899,6 @@ if test "${enable_crypto}" = "yes" -a "${with_crypto_library}" = "openssl"; then AC_CHECK_FUNCS( [ \ - EVP_CIPHER_CTX_free \ HMAC_CTX_new \ HMAC_CTX_free \ HMAC_CTX_reset \ diff --git a/src/openvpn/openssl_compat.h b/src/openvpn/openssl_compat.h index cd25bd378b5..36f68b01ea6 100644 --- a/src/openvpn/openssl_compat.h +++ b/src/openvpn/openssl_compat.h @@ -88,19 +88,6 @@ EVP_MD_CTX_new(void) } #endif -#if !defined(HAVE_EVP_CIPHER_CTX_FREE) -/** - * Free an existing cipher context - * - * @param ctx The cipher context - */ -static inline void -EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *c) -{ - free(c); -} -#endif - #if !defined(HAVE_HMAC_CTX_RESET) /** * Reset a HMAC context From e050c762e2bd3695275ee675f197f062c63e2b6f Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Wed, 28 Jun 2017 00:20:29 +0200 Subject: [PATCH 575/643] Undo cipher push in client options state if cipher is rejected Because of the way we re-use the options parser for both config files and pushed options, we always update the local options state when we accept an option. This resulted in a pushed cipher being rejected the first time it was pushed, but being accepted the second time. This patch is a minimal way to resolve this issue in the master and release/2.4 branches. I'll send a more invasive patch for master, to reset the entire options state on reconnects, later. Trac: #906 Signed-off-by: Steffan Karger Acked-by: Arne Schwabe Acked-by: Gert Doering Message-Id: <20170627222029.26623-1-steffan@karger.me> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14984.html Signed-off-by: Gert Doering (cherry picked from commit 3be9a1c1cd75627c30dca05bed28c84ad4dc1d37) --- src/openvpn/ssl.c | 4 +++- src/openvpn/ssl.h | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 98f4741bddc..cad9ce73715 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -1960,7 +1960,7 @@ tls_session_generate_data_channel_keys(struct tls_session *session) bool tls_session_update_crypto_params(struct tls_session *session, - const struct options *options, struct frame *frame) + struct options *options, struct frame *frame) { if (!session->opt->server && 0 != strcmp(options->ciphername, session->opt->config_ciphername) @@ -1969,6 +1969,8 @@ tls_session_update_crypto_params(struct tls_session *session, msg(D_TLS_ERRORS, "Error: pushed cipher not allowed - %s not in %s or %s", options->ciphername, session->opt->config_ciphername, options->ncp_ciphers); + /* undo cipher push, abort connection setup */ + options->ciphername = session->opt->config_ciphername; return false; } diff --git a/src/openvpn/ssl.h b/src/openvpn/ssl.h index 56ea601372e..0e0f68fa36c 100644 --- a/src/openvpn/ssl.h +++ b/src/openvpn/ssl.h @@ -481,7 +481,7 @@ void tls_update_remote_addr(struct tls_multi *multi, * @return true if updating succeeded, false otherwise. */ bool tls_session_update_crypto_params(struct tls_session *session, - const struct options *options, struct frame *frame); + struct options *options, struct frame *frame); /** * "Poor man's NCP": Use peer cipher if it is an allowed (NCP) cipher. From 67e3f0280937757ce716211829c82c3795d21ad1 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Wed, 28 Jun 2017 21:15:38 +0200 Subject: [PATCH 576/643] doc: The CRL processing is not a deprecated feature The note related to the CRL processing was somehow put into the deprecated section. This is quite confusing. Since this is a fairly important change, and there have been a noticable amount of supports questions related to OpenVPN not starting due to CRL errors, I put this into the "New features" section labelled as an improvement. Otherwise I fear this would drown in the list of "User-visible Changes" later on. Signed-off-by: David Sommerseth Acked-by: Steffan Karger Message-Id: <20170628191538.9135-1-davids@openvpn.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14985.html Signed-off-by: Gert Doering (cherry picked from commit f9ebfe1b5a011e55fb87a5026b1897c8ffb8f75e) --- Changes.rst | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Changes.rst b/Changes.rst index 454dde43b74..d94b3fbff64 100644 --- a/Changes.rst +++ b/Changes.rst @@ -44,6 +44,13 @@ ECDH key exchange The TLS control channel now supports for elliptic curve diffie-hellmann key exchange (ECDH). +Improved Certificate Revocation List (CRL) processing + CRLs are now handled by the crypto library (OpenSSL or mbed TLS), instead + of inside OpenVPN itself. The crypto library implementations are more + strict than the OpenVPN implementation was. This might reject peer + certificates that would previously be accepted. If this occurs, OpenVPN + will log the crypto library's error description. + Dualstack round-robin DNS client connect Instead of only using the first address of each ``--remote`` OpenVPN will now try all addresses (IPv6 and IPv4) of a ``--remote`` entry. @@ -160,12 +167,6 @@ Deprecated features will then use ``--key-method 2`` by default. Note that this requires changing the option in both the client and server side configs. -- CRLs are now handled by the crypto library (OpenSSL or mbed TLS), instead of - inside OpenVPN itself. The crypto library implementations are more strict - than the OpenVPN implementation was. This might reject peer certificates - that would previously be accepted. If this occurs, OpenVPN will log the - crypto library's error description. - - ``--tls-remote`` is removed in 2.4, as indicated in the 2.3 man-pages. Similar functionality is provided via ``--verify-x509-name``, which does the same job in a better way. From e80af83b361b7555a0c3369fe243c19f6c60bd60 Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Thu, 13 Jul 2017 16:05:26 +0800 Subject: [PATCH 577/643] use M_ERRNO instead of explicitly printing errno the msg() function will print the errno for us when provided with the M_ERRNO flag. Therefore, don't bother printing errno explicitly and always pass M_ERRNO to msg(). Signed-off-by: Antonio Quartulli Acked-by: Arne Schwabe Message-Id: <20170713080527.13299-1-a@unstable.cc> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15056.html Signed-off-by: Gert Doering (cherry picked from commit 56b396dcbc34ffd3cddeb2e65ae55c40eae51831) --- src/openvpn/manage.c | 14 ++++++-------- src/openvpn/misc.c | 6 ++---- src/openvpn/mtcp.c | 2 +- src/openvpn/mudp.c | 2 +- src/openvpn/multi.c | 2 +- src/openvpn/options.c | 3 +-- src/openvpn/socket.c | 13 +++++-------- src/openvpn/status.c | 2 +- src/openvpn/tun.c | 9 +++------ 9 files changed, 21 insertions(+), 32 deletions(-) diff --git a/src/openvpn/manage.c b/src/openvpn/manage.c index c2e8dc72d12..39ce8b3be14 100644 --- a/src/openvpn/manage.c +++ b/src/openvpn/manage.c @@ -1878,17 +1878,15 @@ man_connect(struct management *man) #if UNIX_SOCK_SUPPORT if (man->settings.flags & MF_UNIX_SOCK) { - msg(D_LINK_ERRORS, - "MANAGEMENT: connect to unix socket %s failed: %s", - sockaddr_unix_name(&man->settings.local_unix, "NULL"), - strerror_ts(status, &gc)); + msg(D_LINK_ERRORS | M_ERRNO, + "MANAGEMENT: connect to unix socket %s failed", + sockaddr_unix_name(&man->settings.local_unix, "NULL")); } else #endif - msg(D_LINK_ERRORS, - "MANAGEMENT: connect to %s failed: %s", - print_sockaddr(man->settings.local->ai_addr, &gc), - strerror_ts(status, &gc)); + msg(D_LINK_ERRORS | M_ERRNO, + "MANAGEMENT: connect to %s failed", + print_sockaddr(man->settings.local->ai_addr, &gc)); throw_signal_soft(SIGTERM, "management-connect-failed"); goto done; } diff --git a/src/openvpn/misc.c b/src/openvpn/misc.c index 965869a7cf1..ef779ee3021 100644 --- a/src/openvpn/misc.c +++ b/src/openvpn/misc.c @@ -928,10 +928,8 @@ create_temp_file(const char *directory, const char *prefix, struct gc_arena *gc) else if (fd == -1 && errno != EEXIST) { /* Something else went wrong, no need to retry. */ - struct gc_arena gcerr = gc_new(); - msg(M_FATAL, "Could not create temporary file '%s': %s", - retfname, strerror_ts(errno, &gcerr)); - gc_free(&gcerr); + msg(M_FATAL | M_ERRNO, "Could not create temporary file '%s'", + retfname); return NULL; } } diff --git a/src/openvpn/mtcp.c b/src/openvpn/mtcp.c index cb940d8a1f9..851643a99d4 100644 --- a/src/openvpn/mtcp.c +++ b/src/openvpn/mtcp.c @@ -797,7 +797,7 @@ tunnel_server_tcp(struct context *top) multi.top.c2.inotify_fd = inotify_init(); if (multi.top.c2.inotify_fd < 0) { - msg(D_MULTI_ERRORS, "MULTI: inotify_init error: %s", strerror(errno)); + msg(D_MULTI_ERRORS | M_ERRNO, "MULTI: inotify_init error"); } #endif diff --git a/src/openvpn/mudp.c b/src/openvpn/mudp.c index 793678d8aff..eb28ca2be51 100644 --- a/src/openvpn/mudp.c +++ b/src/openvpn/mudp.c @@ -325,7 +325,7 @@ tunnel_server_udp_single_threaded(struct context *top) multi.top.c2.inotify_fd = inotify_init(); if (multi.top.c2.inotify_fd < 0) { - msg(D_MULTI_ERRORS, "MULTI: inotify_init error: %s", strerror(errno)); + msg(D_MULTI_ERRORS | M_ERRNO, "MULTI: inotify_init error"); } #endif diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index 8d3d67fd507..7edfee1b136 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -2355,7 +2355,7 @@ multi_process_post(struct multi_context *m, struct multi_instance *mi, const uns } else { - msg(M_NONFATAL, "MULTI: inotify_add_watch error: %s", strerror(errno)); + msg(M_NONFATAL | M_ERRNO, "MULTI: inotify_add_watch error"); } } #endif diff --git a/src/openvpn/options.c b/src/openvpn/options.c index fef5e9054af..2d9972f0104 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -3148,8 +3148,7 @@ check_file_access(const int type, const char *file, const int mode, const char * /* Scream if an error is found */ if (errcode > 0) { - msg(M_NOPREFIX|M_OPTERR, "%s fails with '%s': %s", - opt, file, strerror(errno)); + msg(M_NOPREFIX | M_OPTERR | M_ERRNO, "%s fails with '%s'", opt, file); } /* Return true if an error occured */ diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c index 4e7e3f99820..a814b952c75 100644 --- a/src/openvpn/socket.c +++ b/src/openvpn/socket.c @@ -1297,11 +1297,9 @@ socket_bind(socket_descriptor_t sd, } if (bind(sd, cur->ai_addr, cur->ai_addrlen)) { - const int errnum = openvpn_errno(); - msg(M_FATAL, "%s: Socket bind failed on local address %s: %s", + msg(M_FATAL | M_ERRNO, "%s: Socket bind failed on local address %s", prefix, - print_sockaddr_ex(local->ai_addr, ":", PS_SHOW_PORT, &gc), - strerror_ts(errnum, &gc)); + print_sockaddr_ex(local->ai_addr, ":", PS_SHOW_PORT, &gc)); } gc_free(&gc); } @@ -3888,12 +3886,11 @@ socket_bind_unix(socket_descriptor_t sd, if (bind(sd, (struct sockaddr *) local, sizeof(struct sockaddr_un))) { - const int errnum = openvpn_errno(); - msg(M_FATAL, "%s: Socket bind[%d] failed on unix domain socket %s: %s", + msg(M_FATAL | M_ERRNO, + "%s: Socket bind[%d] failed on unix domain socket %s", prefix, (int)sd, - sockaddr_unix_name(local, "NULL"), - strerror_ts(errnum, &gc)); + sockaddr_unix_name(local, "NULL")); } #ifdef HAVE_UMASK diff --git a/src/openvpn/status.c b/src/openvpn/status.c index a1634083753..d2f0b13335b 100644 --- a/src/openvpn/status.c +++ b/src/openvpn/status.c @@ -178,7 +178,7 @@ status_flush(struct status_output *so) const off_t off = lseek(so->fd, (off_t)0, SEEK_CUR); if (ftruncate(so->fd, off) != 0) { - msg(M_WARN, "Failed to truncate status file: %s", strerror(errno)); + msg(M_WARN | M_ERRNO, "Failed to truncate status file"); } } #elif defined(HAVE_CHSIZE) diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index 75a156c13d5..c09f9700210 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -3022,16 +3022,14 @@ utun_open_helper(struct ctl_info ctlInfo, int utunnum) if (fd < 0) { - msg(M_INFO, "Opening utun (%s): %s", "socket(SYSPROTO_CONTROL)", - strerror(errno)); + msg(M_INFO | M_ERRNO, "Opening utun (socket(SYSPROTO_CONTROL))"); return -2; } if (ioctl(fd, CTLIOCGINFO, &ctlInfo) == -1) { close(fd); - msg(M_INFO, "Opening utun (%s): %s", "ioctl(CTLIOCGINFO)", - strerror(errno)); + msg(M_INFO | M_ERRNO, "Opening utun (ioctl(CTLIOCGINFO))"); return -2; } @@ -3049,8 +3047,7 @@ utun_open_helper(struct ctl_info ctlInfo, int utunnum) if (connect(fd, (struct sockaddr *)&sc, sizeof(sc)) < 0) { - msg(M_INFO, "Opening utun (%s): %s", "connect(AF_SYS_CONTROL)", - strerror(errno)); + msg(M_INFO | M_ERRNO, "Opening utun (connect(AF_SYS_CONTROL))"); close(fd); return -1; } From 9a17c4c04ceb5a1c1de5a21c19bde794ab5b4a48 Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Thu, 13 Jul 2017 16:05:27 +0800 Subject: [PATCH 578/643] don't print errno twice when passing the M_ERRNO flag to msg(), the latter will already print the errno message (in a form of a string and number) for us, hence there is no need to explicitly print it a second time. Signed-off-by: Antonio Quartulli Acked-by: Arne Schwabe Message-Id: <20170713080527.13299-2-a@unstable.cc> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15057.html Signed-off-by: Gert Doering (cherry picked from commit e441d861881669c97906652c3278cc9a6c69a417) --- src/openvpn/platform.c | 2 +- src/openvpn/tun.c | 12 +++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/openvpn/platform.c b/src/openvpn/platform.c index 2495523fdfc..d936890e9e6 100644 --- a/src/openvpn/platform.c +++ b/src/openvpn/platform.c @@ -159,7 +159,7 @@ platform_nice(int niceval) errno = 0; if (nice(niceval) < 0 && errno != 0) { - msg(M_WARN | M_ERRNO, "WARNING: nice %d failed: %s", niceval, strerror(errno)); + msg(M_WARN | M_ERRNO, "WARNING: nice %d failed", niceval); } else { diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index c09f9700210..68fb48890f7 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -2563,8 +2563,7 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun if (ioctl(tt->fd, TUNGIFINFO, &info) < 0) { - msg(M_WARN | M_ERRNO, "Can't get interface info: %s", - strerror(errno)); + msg(M_WARN | M_ERRNO, "Can't get interface info"); } #ifdef IFF_MULTICAST /* openbsd 4.x doesn't have this */ @@ -2573,8 +2572,7 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun if (ioctl(tt->fd, TUNSIFINFO, &info) < 0) { - msg(M_WARN | M_ERRNO, "Can't set interface info: %s", - strerror(errno)); + msg(M_WARN | M_ERRNO, "Can't set interface info"); } } } @@ -2663,7 +2661,7 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun i = 1; if (ioctl(tt->fd, TUNSIFHEAD, &i) < 0) /* multi-af mode on */ { - msg(M_WARN | M_ERRNO, "ioctl(TUNSIFHEAD): %s", strerror(errno)); + msg(M_WARN | M_ERRNO, "ioctl(TUNSIFHEAD)"); } } } @@ -2796,12 +2794,12 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun if (ioctl(tt->fd, TUNSIFMODE, &i) < 0) { - msg(M_WARN | M_ERRNO, "ioctl(TUNSIFMODE): %s", strerror(errno)); + msg(M_WARN | M_ERRNO, "ioctl(TUNSIFMODE)"); } i = 1; if (ioctl(tt->fd, TUNSIFHEAD, &i) < 0) { - msg(M_WARN | M_ERRNO, "ioctl(TUNSIFHEAD): %s", strerror(errno)); + msg(M_WARN | M_ERRNO, "ioctl(TUNSIFHEAD)"); } } } From 527bf0caad0b2cc353a27682b49d9ca8e6c0e435 Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Mon, 10 Jul 2017 12:34:39 +0800 Subject: [PATCH 579/643] ntlm: avoid useless cast The argument passed to my_strupr() is converted to an upper case string by means of toupper(). The latter expects a single signed int as argument, therefore it makes sense to have my_strupr() take a signed argument too and avoid an explicit and an implicit cast. Signed-off-by: Antonio Quartulli Acked-by: Steffan Karger Message-Id: <20170710043441.24770-3-a@unstable.cc> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15031.html Signed-off-by: Gert Doering (cherry picked from commit 1cdfc9302aad8570360d278aded5fb9f110ca2b6) --- src/openvpn/ntlm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/openvpn/ntlm.c b/src/openvpn/ntlm.c index 0b1163ee465..90d4875472f 100644 --- a/src/openvpn/ntlm.c +++ b/src/openvpn/ntlm.c @@ -130,7 +130,7 @@ gen_nonce(unsigned char *nonce) } void -my_strupr(unsigned char *str) +my_strupr(char *str) { /* converts string to uppercase in place */ @@ -271,7 +271,7 @@ ntlm_phase_3(const struct http_proxy_info *p, const char *phase_2, struct gc_are int tib_len; /* NTLMv2 hash */ - my_strupr((unsigned char *)strcpy(userdomain, username)); + my_strupr(strcpy(userdomain, username)); if (strlen(username) + strlen(domain) < sizeof(userdomain)) { strcat(userdomain, domain); From 0bc107b454c134a60e4a9d7fe7bcb5cb10743afe Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Wed, 12 Jul 2017 12:30:02 +0800 Subject: [PATCH 580/643] ntlm: unwrap multiple function calls In order to improve code readability it is better to unwrap multiple function calls onto multiple lines. Signed-off-by: Antonio Quartulli Acked-by: Gert Doering Message-Id: <20170712043002.11083-1-a@unstable.cc> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15041.html Signed-off-by: Gert Doering (cherry picked from commit ad7f7e56d34bbf477a7e5639f1b78b2c7e58186c) --- src/openvpn/ntlm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/openvpn/ntlm.c b/src/openvpn/ntlm.c index 90d4875472f..976142ddbe7 100644 --- a/src/openvpn/ntlm.c +++ b/src/openvpn/ntlm.c @@ -271,7 +271,8 @@ ntlm_phase_3(const struct http_proxy_info *p, const char *phase_2, struct gc_are int tib_len; /* NTLMv2 hash */ - my_strupr(strcpy(userdomain, username)); + strcpy(userdomain, username); + my_strupr(userdomain); if (strlen(username) + strlen(domain) < sizeof(userdomain)) { strcat(userdomain, domain); From 5315193bb9e83980ca24d4628c4e1adfb8f012a9 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Thu, 20 Jul 2017 13:39:00 +0200 Subject: [PATCH 581/643] Remove strerror_ts() This function was only called in string format functions, which already copy the contents, so all this ever did was adding redundant malloc() and free() calls. Also, this wasn't as thread-safe as it claims: another thread could still change the string value between the strerror() and buf_printf() calls. So, instead of a not needed false sense of thread-safeness, just be honest and use strerror() directly. (I think we should find a better place for everything currently in misc.c, and get rid of it all together. In this case, the better place is /dev/null. This patch is part of that effort.) Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1500550740-24773-1-git-send-email-steffan.karger@fox-it.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15105.html Signed-off-by: Gert Doering (cherry picked from commit fd2a29ab2668fea9c0ac972d5ec69f00232c88b6) --- configure.ac | 2 +- src/openvpn/error.c | 15 +++++---------- src/openvpn/manage.c | 5 ++--- src/openvpn/misc.c | 15 --------------- src/openvpn/misc.h | 6 ------ src/openvpn/socket.c | 6 ++---- 6 files changed, 10 insertions(+), 39 deletions(-) diff --git a/configure.ac b/configure.ac index d372295ebd1..148a086955b 100644 --- a/configure.ac +++ b/configure.ac @@ -662,7 +662,7 @@ AC_FUNC_FORK AC_CHECK_FUNCS([ \ daemon chroot getpwnam setuid nice system getpid dup dup2 \ - getpass strerror syslog openlog mlockall getgrnam setgid \ + getpass syslog openlog mlockall getgrnam setgid \ setgroups stat flock readv writev time gettimeofday \ ctime memset vsnprintf strdup \ setsid chdir putenv getpeername unlink \ diff --git a/src/openvpn/error.c b/src/openvpn/error.c index ce50ff9e0be..3817666b659 100644 --- a/src/openvpn/error.c +++ b/src/openvpn/error.c @@ -267,7 +267,7 @@ x_msg_va(const unsigned int flags, const char *format, va_list arglist) if ((flags & M_ERRNO) && e) { openvpn_snprintf(m2, ERR_BUF_SIZE, "%s: %s (errno=%d)", - m1, strerror_ts(e, &gc), e); + m1, strerror(e), e); SWAP; } @@ -693,20 +693,15 @@ x_check_status(int status, { if (extended_msg) { - msg(x_cs_info_level, "%s %s [%s]: %s (code=%d)", - description, + msg(x_cs_info_level, "%s %s [%s]: %s (code=%d)", description, sock ? proto2ascii(sock->info.proto, sock->info.af, true) : "", - extended_msg, - strerror_ts(my_errno, &gc), - my_errno); + extended_msg, strerror(my_errno), my_errno); } else { - msg(x_cs_info_level, "%s %s: %s (code=%d)", - description, + msg(x_cs_info_level, "%s %s: %s (code=%d)", description, sock ? proto2ascii(sock->info.proto, sock->info.af, true) : "", - strerror_ts(my_errno, &gc), - my_errno); + strerror(my_errno), my_errno); } if (x_cs_err_delay_ms) diff --git a/src/openvpn/manage.c b/src/openvpn/manage.c index 39ce8b3be14..2b85d25cc81 100644 --- a/src/openvpn/manage.c +++ b/src/openvpn/manage.c @@ -2006,9 +2006,8 @@ man_io_error(struct management *man, const char *prefix) if (!ignore_sys_error(err)) { struct gc_arena gc = gc_new(); - msg(D_MANAGEMENT, "MANAGEMENT: TCP %s error: %s", - prefix, - strerror_ts(err, &gc)); + msg(D_MANAGEMENT, "MANAGEMENT: TCP %s error: %s", prefix, + strerror(err)); gc_free(&gc); return true; } diff --git a/src/openvpn/misc.c b/src/openvpn/misc.c index ef779ee3021..f6d6c6ad6c6 100644 --- a/src/openvpn/misc.c +++ b/src/openvpn/misc.c @@ -444,21 +444,6 @@ init_random_seed(void) } } -/* thread-safe strerror */ - -const char * -strerror_ts(int errnum, struct gc_arena *gc) -{ -#ifdef HAVE_STRERROR - struct buffer out = alloc_buf_gc(256, gc); - - buf_printf(&out, "%s", openvpn_strerror(errnum, gc)); - return BSTR(&out); -#else - return "[error string unavailable]"; -#endif -} - /* * Set environmental variable (int or string). * diff --git a/src/openvpn/misc.h b/src/openvpn/misc.h index 3116ec424ea..bc267d73fc6 100644 --- a/src/openvpn/misc.h +++ b/src/openvpn/misc.h @@ -95,12 +95,6 @@ openvpn_run_script(const struct argv *a, const struct env_set *es, const unsigne } -#ifdef HAVE_STRERROR -/* a thread-safe version of strerror */ -const char *strerror_ts(int errnum, struct gc_arena *gc); - -#endif - /* Set standard file descriptors to /dev/null */ void set_std_files_to_null(bool stdin_only); diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c index a814b952c75..846df04beb9 100644 --- a/src/openvpn/socket.c +++ b/src/openvpn/socket.c @@ -1473,10 +1473,8 @@ socket_connect(socket_descriptor_t *sd, if (status) { - msg(D_LINK_ERRORS, - "TCP: connect to %s failed: %s", - print_sockaddr(dest, &gc), - strerror_ts(status, &gc)); + msg(D_LINK_ERRORS, "TCP: connect to %s failed: %s", + print_sockaddr(dest, &gc), strerror(status)); openvpn_close_socket(*sd); *sd = SOCKET_UNDEFINED; From 80ece420966b21b9a6cee2a36a19e3d200dcd3e7 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Thu, 20 Jul 2017 18:00:35 +0200 Subject: [PATCH 582/643] Move openvpn_sleep() to manage.c openvpn_sleep() is basically "service the management interface for x seconds, then return". Therefore, manage.c is a more suitable location than the random collection of unrelated stuff called misc.c. (I think we should find a better place for everything currently in misc.c, and get rid of it all together. This patch is part of that effort.) Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1500566435-29920-1-git-send-email-steffan.karger@fox-it.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15109.html Signed-off-by: Gert Doering (cherry picked from commit 45b2af9c7719d9a40c6c2b9d0693e4db0d917a04) --- src/openvpn/forward.c | 2 +- src/openvpn/init.c | 4 ++-- src/openvpn/manage.c | 20 ++++++++++++++++++-- src/openvpn/manage.h | 7 +++++++ src/openvpn/misc.c | 13 ------------- src/openvpn/misc.h | 6 ------ src/openvpn/socket.c | 8 ++++---- 7 files changed, 32 insertions(+), 28 deletions(-) diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c index 371ddca5849..c45d1259c43 100644 --- a/src/openvpn/forward.c +++ b/src/openvpn/forward.c @@ -756,7 +756,7 @@ read_incoming_link(struct context *c) if (event_timeout_defined(&c->c2.explicit_exit_notification_interval)) { msg(D_STREAM_ERRORS, "Connection reset during exit notification period, ignoring [%d]", status); - openvpn_sleep(1); + management_sleep(1); } else #endif diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 0652ef4652b..efe634f4eae 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -1969,7 +1969,7 @@ do_up(struct context *c, bool pulled_options, unsigned int option_types_found) /* if so, close tun, delete routes, then reinitialize tun and add routes */ msg(M_INFO, "NOTE: Pulled options changed on restart, will need to close and reopen TUN/TAP device."); do_close_tun(c, true); - openvpn_sleep(1); + management_sleep(1); c->c2.did_open_tun = do_open_tun(c); update_time(); } @@ -2263,7 +2263,7 @@ socket_restart_pause(struct context *c) if (sec) { msg(D_RESTART, "Restart pause, %d second(s)", sec); - openvpn_sleep(sec); + management_sleep(sec); } } diff --git a/src/openvpn/manage.c b/src/openvpn/manage.c index 2b85d25cc81..13be6f6d7af 100644 --- a/src/openvpn/manage.c +++ b/src/openvpn/manage.c @@ -3997,9 +3997,25 @@ log_history_ref(const struct log_history *h, const int index) } } +void +management_sleep(const int n) +{ + if (management) + { + management_event_loop_n_seconds(management, n); + } + else + { + sleep(n); + } +} + #else /* ifdef ENABLE_MANAGEMENT */ -static void -dummy(void) + +void +management_sleep(const int n) { + sleep(n); } + #endif /* ENABLE_MANAGEMENT */ diff --git a/src/openvpn/manage.h b/src/openvpn/manage.h index 542cc07a0d3..676be640e54 100644 --- a/src/openvpn/manage.h +++ b/src/openvpn/manage.h @@ -605,4 +605,11 @@ management_bytes_server(struct management *man, #endif /* MANAGEMENT_DEF_AUTH */ #endif /* ifdef ENABLE_MANAGEMENT */ + +/** + * A sleep function that services the management layer for n seconds rather + * than doing nothing. + */ +void management_sleep(const int n); + #endif /* ifndef MANAGE_H */ diff --git a/src/openvpn/misc.c b/src/openvpn/misc.c index f6d6c6ad6c6..ae96aa69025 100644 --- a/src/openvpn/misc.c +++ b/src/openvpn/misc.c @@ -1615,19 +1615,6 @@ make_extended_arg_array(char **p, struct gc_arena *gc) } } -void -openvpn_sleep(const int n) -{ -#ifdef ENABLE_MANAGEMENT - if (management) - { - management_event_loop_n_seconds(management, n); - return; - } -#endif - sleep(n); -} - /* * Remove security-sensitive strings from control message * so that they will not be output to log file. diff --git a/src/openvpn/misc.h b/src/openvpn/misc.h index bc267d73fc6..32b64e8bb15 100644 --- a/src/openvpn/misc.h +++ b/src/openvpn/misc.h @@ -292,12 +292,6 @@ bool env_safe_to_print(const char *str); /* returns true if environmental variable may be passed to an external program */ bool env_allowed(const char *str); -/* - * A sleep function that services the management layer for n - * seconds rather than doing nothing. - */ -void openvpn_sleep(const int n); - void configure_path(void); const char *sanitize_control_message(const char *str, struct gc_arena *gc); diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c index 846df04beb9..6e01fe10959 100644 --- a/src/openvpn/socket.c +++ b/src/openvpn/socket.c @@ -496,7 +496,7 @@ openvpn_getaddrinfo(unsigned int flags, goto done; } - openvpn_sleep(fail_wait_interval); + management_sleep(fail_wait_interval); } ASSERT(res); @@ -1193,7 +1193,7 @@ socket_listen_accept(socket_descriptor_t sd, if (status <= 0) { - openvpn_sleep(1); + management_sleep(1); continue; } @@ -1228,7 +1228,7 @@ socket_listen_accept(socket_descriptor_t sd, break; } } - openvpn_sleep(1); + management_sleep(1); } if (!nowait && openvpn_close_socket(sd)) @@ -1374,7 +1374,7 @@ openvpn_connect(socket_descriptor_t sd, #endif break; } - openvpn_sleep(1); + management_sleep(1); continue; } From 4a04be8b53df37cac0cd4df4d23a1e2210902232 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Thu, 20 Jul 2017 21:17:02 +0200 Subject: [PATCH 583/643] fixup: also change missed openvpn_sleep() occurrences 45b2af9c missed some openvpn_sleep() occurrences in platform-specific code in tun.c - fix that. Signed-off-by: Steffan Karger Acked-by: Gert Doering Message-Id: <1500578222-21689-1-git-send-email-steffan@karger.me> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15111.html Signed-off-by: Gert Doering (cherry picked from commit cdb262a6c78a29349789b7cf1813feaf7cc6e8c8) --- src/openvpn/tun.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c index 68fb48890f7..3639718c9d6 100644 --- a/src/openvpn/tun.c +++ b/src/openvpn/tun.c @@ -1862,7 +1862,7 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun if (oldtunfd >=0 && android_method == ANDROID_OPEN_AFTER_CLOSE) { close(oldtunfd); - openvpn_sleep(2); + management_sleep(2); } if (oldtunfd >=0 && android_method == ANDROID_KEEP_OLD_TUN) @@ -4999,7 +4999,7 @@ netsh_command(const struct argv *a, int n, int msglevel) for (i = 0; i < n; ++i) { bool status; - openvpn_sleep(1); + management_sleep(1); netcmd_semaphore_lock(); argv_msg_prefix(M_INFO, a, "NETSH"); status = openvpn_execve_check(a, NULL, 0, "ERROR: netsh command failed"); @@ -5008,7 +5008,7 @@ netsh_command(const struct argv *a, int n, int msglevel) { return; } - openvpn_sleep(4); + management_sleep(4); } msg(msglevel, "NETSH: command failed"); } @@ -5991,7 +5991,7 @@ open_tun(const char *dev, const char *dev_type, const char *dev_node, struct tun if (s > 0) { msg(M_INFO, "Sleeping for %d seconds...", s); - openvpn_sleep(s); + management_sleep(s); } } From f62720269db5299b8779780476c533fba00b354a Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Thu, 20 Jul 2017 16:23:38 +0800 Subject: [PATCH 584/643] route: improve error message - fix typ0 in message: NLSMG -> NLMSG - use strerror() to print a human readable message - don't print error message if error is ENETUNREACH: it means no route found Signed-off-by: Antonio Quartulli Acked-by: Gert Doering Message-Id: <20170720082338.1302-1-a@unstable.cc> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15101.html Signed-off-by: Gert Doering (cherry picked from commit 20d98427ef37e3b748dbcca2174cd243dcc963dc) --- src/openvpn/route.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/openvpn/route.c b/src/openvpn/route.c index a1811f41dfd..a8a4c66deaa 100644 --- a/src/openvpn/route.c +++ b/src/openvpn/route.c @@ -3441,7 +3441,14 @@ get_default_gateway_ipv6(struct route_ipv6_gateway_info *rgi6, if (nh->nlmsg_type == NLMSG_ERROR) { struct nlmsgerr *ne = (struct nlmsgerr *)NLMSG_DATA(nh); - msg(M_WARN, "GDG6: NLSMG_ERROR: error %d\n", ne->error); + + /* since linux-4.11 -ENETUNREACH is returned when no route can be + * found. Don't print any error message in this case */ + if (ne->error != -ENETUNREACH) + { + msg(M_WARN, "GDG6: NLMSG_ERROR: error %s\n", + strerror(-ne->error)); + } break; } From e7ae4040efc5c48e00374f8863da58eef32e0709 Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Fri, 7 Jul 2017 22:01:08 +0800 Subject: [PATCH 585/643] management: preserve wait_for_push field when asking for user/pass With the introduction of the wait_for_push field in the auth_user_pass structure, we have to make sure that such field is not accidentally erased when the management asks the user for user/pass. Erasing such field would mess up the logic introduced by ("Ignore auth-nocache for auth-user-pass if auth-token is pushed"). Thanks to David Sommerseth for the preliminary analysis and debugging. Reported-by: Steven Haigh Signed-off-by: Antonio Quartulli Tested-by: Steven Haigh Acked-by: David Sommerseth Message-Id: <20170707140108.31612-1-a@unstable.cc> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15015.html Signed-off-by: David Sommerseth (cherry picked from commit 3322c558fa742cb823fa919f682486973abc4f8e) --- src/openvpn/manage.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/openvpn/manage.c b/src/openvpn/manage.c index 13be6f6d7af..ff94824044e 100644 --- a/src/openvpn/manage.c +++ b/src/openvpn/manage.c @@ -3501,7 +3501,9 @@ management_query_user_pass(struct management *man, */ if (ret) { - man->connection.up_query.nocache = up->nocache; /* preserve caller's nocache setting */ + /* preserve caller's settings */ + man->connection.up_query.nocache = up->nocache; + man->connection.up_query.wait_for_push = up->wait_for_push; *up = man->connection.up_query; } secure_memzero(&man->connection.up_query, sizeof(man->connection.up_query)); From 8295f62f84be3dbc5203b9695d99a4f74fcb7295 Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Fri, 7 Jul 2017 18:22:38 +0800 Subject: [PATCH 586/643] tls-crypt: avoid warnings when --disable-crypto is used Avoid including the content of tls_crypt.h when --disable-crypto is used, as it will trigger some warnings due to missing structures declarations. Signed-off-by: Antonio Quartulli Acked-by: Steffan Karger Acked-by: David Sommerseth Message-Id: <20170707102238.8781-1-a@unstable.cc> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15014.html Signed-off-by: David Sommerseth (cherry picked from commit 2dfbf62b6ace1eb39f1ae7126bc5530a541bed58) --- src/openvpn/tls_crypt.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/openvpn/tls_crypt.h b/src/openvpn/tls_crypt.h index e8080df90ee..4071ac94c1f 100644 --- a/src/openvpn/tls_crypt.h +++ b/src/openvpn/tls_crypt.h @@ -74,6 +74,8 @@ #ifndef TLSCRYPT_H #define TLSCRYPT_H +#ifdef ENABLE_CRYPTO + #include "buffer.h" #include "crypto.h" #include "session_id.h" @@ -140,4 +142,6 @@ bool tls_crypt_unwrap(const struct buffer *src, struct buffer *dst, /** @} */ +#endif /* ENABLE_CRYPTO */ + #endif /* TLSCRYPT_H */ From cb438b513223744949e0958d9f14870880cfc407 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Tue, 25 Jul 2017 16:57:18 +0200 Subject: [PATCH 587/643] cleanup: Move write_pid() to where it is being used The write_pid() function is only used in openvpn.c, so no need to have that in the misc.[ch] mixed bag. [on-the-fly change: Added #include "platform.h"] Signed-off-by: David Sommerseth Acked-by: Steffan Karger Message-Id: <20170725145718.13175-1-davids@openvpn.net> URL: https://www.mail-archive.com/search?l=mid&q=20170725145718.13175-1-davids@openvpn.net Signed-off-by: David Sommerseth (cherry picked from commit c5b12817c9aa3ae97fbdd2c2a9a9ab605087dff1) --- src/openvpn/misc.c | 21 --------------------- src/openvpn/misc.h | 2 -- src/openvpn/openvpn.c | 22 ++++++++++++++++++++++ 3 files changed, 22 insertions(+), 23 deletions(-) diff --git a/src/openvpn/misc.c b/src/openvpn/misc.c index ae96aa69025..8a76bba89c6 100644 --- a/src/openvpn/misc.c +++ b/src/openvpn/misc.c @@ -142,27 +142,6 @@ run_up_down(const char *command, gc_free(&gc); } -/* Write our PID to a file */ -void -write_pid(const char *filename) -{ - if (filename) - { - unsigned int pid = 0; - FILE *fp = platform_fopen(filename, "w"); - if (!fp) - { - msg(M_ERR, "Open error on pid file %s", filename); - } - - pid = platform_getpid(); - fprintf(fp, "%u\n", pid); - if (fclose(fp)) - { - msg(M_ERR, "Close error on pid file %s", filename); - } - } -} /* * Set standard file descriptors to /dev/null diff --git a/src/openvpn/misc.h b/src/openvpn/misc.h index 32b64e8bb15..734e679c5ed 100644 --- a/src/openvpn/misc.h +++ b/src/openvpn/misc.h @@ -68,8 +68,6 @@ void run_up_down(const char *command, const char *script_type, struct env_set *es); -void write_pid(const char *filename); - /* system flags */ #define S_SCRIPT (1<<0) #define S_FATAL (1<<1) diff --git a/src/openvpn/openvpn.c b/src/openvpn/openvpn.c index 08c09e6bedb..e237ee5042c 100644 --- a/src/openvpn/openvpn.c +++ b/src/openvpn/openvpn.c @@ -33,6 +33,7 @@ #include "forward.h" #include "multi.h" #include "win32.h" +#include "platform.h" #include "memdbg.h" @@ -47,6 +48,27 @@ process_signal_p2p(struct context *c) return process_signal(c); } +/* Write our PID to a file */ +static void +write_pid(const char *filename) +{ + if (filename) + { + unsigned int pid = 0; + FILE *fp = platform_fopen(filename, "w"); + if (!fp) + { + msg(M_ERR, "Open error on pid file %s", filename); + } + + pid = platform_getpid(); + fprintf(fp, "%u\n", pid); + if (fclose(fp)) + { + msg(M_ERR, "Close error on pid file %s", filename); + } + } +} /**************************************************************************/ From 3ace1139e7aa00580300fb5bef37ac6d47378630 Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Mon, 10 Jul 2017 12:34:38 +0800 Subject: [PATCH 588/643] ntlm: convert binary buffers to uint8_t * Several binary buffers in the ntlm component are stored as char *, however this generates a lot of warnings, because hashing functions expect something unsigned. Convert binary buffers to uint8_t *, while use explicit cast for buffers that are really carrying a string inside. This commit removes several warnings from ntlm.c that you can catch with "-Wall -std=c99". [DS: Done minor typo-fixes in commit message at commit time] Signed-off-by: Antonio Quartulli Acked-by: Steffan Karger Message-Id: <20170710043441.24770-2-a@unstable.cc> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15032.html Signed-off-by: David Sommerseth (cherry picked from commit e7e4070cb7b90f4836b65c53360166e11fc3f383) --- src/openvpn/ntlm.c | 51 ++++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/src/openvpn/ntlm.c b/src/openvpn/ntlm.c index 976142ddbe7..393368e4138 100644 --- a/src/openvpn/ntlm.c +++ b/src/openvpn/ntlm.c @@ -71,31 +71,32 @@ create_des_keys(const unsigned char *hash, unsigned char *key) } static void -gen_md4_hash(const char *data, int data_len, char *result) +gen_md4_hash(const uint8_t *data, int data_len, uint8_t *result) { /* result is 16 byte md4 hash */ const md_kt_t *md4_kt = md_kt_get("MD4"); - char md[MD4_DIGEST_LENGTH]; + uint8_t md[MD4_DIGEST_LENGTH]; md_full(md4_kt, data, data_len, md); memcpy(result, md, MD4_DIGEST_LENGTH); } static void -gen_hmac_md5(const char *data, int data_len, const char *key, int key_len,char *result) +gen_hmac_md5(const uint8_t *data, int data_len, const uint8_t *key, int key_len, + uint8_t *result) { const md_kt_t *md5_kt = md_kt_get("MD5"); hmac_ctx_t *hmac_ctx = hmac_ctx_new(); hmac_ctx_init(hmac_ctx, key, key_len, md5_kt); - hmac_ctx_update(hmac_ctx, (const unsigned char *)data, data_len); - hmac_ctx_final(hmac_ctx, (unsigned char *)result); + hmac_ctx_update(hmac_ctx, data, data_len); + hmac_ctx_final(hmac_ctx, result); hmac_ctx_cleanup(hmac_ctx); hmac_ctx_free(hmac_ctx); } static void -gen_timestamp(unsigned char *timestamp) +gen_timestamp(uint8_t *timestamp) { /* Copies 8 bytes long timestamp into "timestamp" buffer. * Timestamp is Little-endian, 64-bit signed value representing the number of tenths of a microsecond since January 1, 1601. @@ -195,19 +196,19 @@ ntlm_phase_3(const struct http_proxy_info *p, const char *phase_2, struct gc_are */ char pwbuf[sizeof(p->up.password) * 2]; /* for unicode password */ - unsigned char buf2[128]; /* decoded reply from proxy */ - unsigned char phase3[464]; + uint8_t buf2[128]; /* decoded reply from proxy */ + uint8_t phase3[464]; - char md4_hash[MD4_DIGEST_LENGTH+5]; - char challenge[8], ntlm_response[24]; + uint8_t md4_hash[MD4_DIGEST_LENGTH + 5]; + uint8_t challenge[8], ntlm_response[24]; int i, ret_val; - char ntlmv2_response[144]; + uint8_t ntlmv2_response[144]; char userdomain_u[256]; /* for uppercase unicode username and domain */ char userdomain[128]; /* the same as previous but ascii */ - char ntlmv2_hash[MD5_DIGEST_LENGTH]; - char ntlmv2_hmacmd5[16]; - char *ntlmv2_blob = ntlmv2_response + 16; /* inside ntlmv2_response, length: 128 */ + uint8_t ntlmv2_hash[MD5_DIGEST_LENGTH]; + uint8_t ntlmv2_hmacmd5[16]; + uint8_t *ntlmv2_blob = ntlmv2_response + 16; /* inside ntlmv2_response, length: 128 */ int ntlmv2_blob_size = 0; int phase3_bufpos = 0x40; /* offset to next security buffer data to be added */ size_t len; @@ -246,12 +247,13 @@ ntlm_phase_3(const struct http_proxy_info *p, const char *phase_2, struct gc_are /* fill 1st 16 bytes with md4 hash, disregard terminating null */ - gen_md4_hash(pwbuf, unicodize(pwbuf, p->up.password) - 2, md4_hash); + gen_md4_hash((uint8_t *)pwbuf, unicodize(pwbuf, p->up.password) - 2, + md4_hash); /* pad to 21 bytes */ memset(md4_hash + MD4_DIGEST_LENGTH, 0, 5); - ret_val = openvpn_base64_decode( phase_2, (void *)buf2, -1); + ret_val = openvpn_base64_decode(phase_2, buf2, -1); if (ret_val < 0) { return NULL; @@ -282,15 +284,16 @@ ntlm_phase_3(const struct http_proxy_info *p, const char *phase_2, struct gc_are msg(M_INFO, "Warning: Username or domain too long"); } unicodize(userdomain_u, userdomain); - gen_hmac_md5(userdomain_u, 2 * strlen(userdomain), md4_hash, MD5_DIGEST_LENGTH, ntlmv2_hash); + gen_hmac_md5((uint8_t *)userdomain_u, 2 * strlen(userdomain), md4_hash, + MD5_DIGEST_LENGTH, ntlmv2_hash); /* NTLMv2 Blob */ memset(ntlmv2_blob, 0, 128); /* Clear blob buffer */ ntlmv2_blob[0x00] = 1; /* Signature */ ntlmv2_blob[0x01] = 1; /* Signature */ ntlmv2_blob[0x04] = 0; /* Reserved */ - gen_timestamp((unsigned char *)&ntlmv2_blob[0x08]); /* 64-bit Timestamp */ - gen_nonce((unsigned char *)&ntlmv2_blob[0x10]); /* 64-bit Client Nonce */ + gen_timestamp(&ntlmv2_blob[0x08]); /* 64-bit Timestamp */ + gen_nonce(&ntlmv2_blob[0x10]); /* 64-bit Client Nonce */ ntlmv2_blob[0x18] = 0; /* Unknown, zero should work */ /* Add target information block to the blob */ @@ -302,8 +305,8 @@ ntlm_phase_3(const struct http_proxy_info *p, const char *phase_2, struct gc_are tib_len = 96; } { - char *tib_ptr; - int tib_pos = buf2[0x2c]; + uint8_t *tib_ptr; + uint8_t tib_pos = buf2[0x2c]; if (tib_pos + tib_len > sizeof(buf2)) { return NULL; @@ -336,13 +339,13 @@ ntlm_phase_3(const struct http_proxy_info *p, const char *phase_2, struct gc_are { unsigned char key1[DES_KEY_LENGTH], key2[DES_KEY_LENGTH], key3[DES_KEY_LENGTH]; - create_des_keys((unsigned char *)md4_hash, key1); + create_des_keys(md4_hash, key1); cipher_des_encrypt_ecb(key1, challenge, ntlm_response); - create_des_keys((unsigned char *)&(md4_hash[DES_KEY_LENGTH-1]), key2); + create_des_keys(&md4_hash[DES_KEY_LENGTH - 1], key2); cipher_des_encrypt_ecb(key2, challenge, &ntlm_response[DES_KEY_LENGTH]); - create_des_keys((unsigned char *)&(md4_hash[2*(DES_KEY_LENGTH-1)]), key3); + create_des_keys(&md4_hash[2 * (DES_KEY_LENGTH - 1)], key3); cipher_des_encrypt_ecb(key3, challenge, &ntlm_response[DES_KEY_LENGTH*2]); } From 90f2edcbb7c1e890de96a9a44c87ca58dbd60b96 Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Mon, 10 Jul 2017 12:34:40 +0800 Subject: [PATCH 589/643] ntlm: restyle compressed multiple function calls The gen_md4_hash() function is receiving as first argument a buffer that is filled by a function invoked when evaluating the second argument. Although this is proper C, it makes the call invocation a bit obscure because it is not immediately easy to grasp how the 'pwbuf' buffer is filled. Unroll the multiple function call onto lines and make the core more readable. Signed-off-by: Antonio Quartulli Acked-by: Steffan Karger Message-Id: <20170710043441.24770-4-a@unstable.cc> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15030.html Signed-off-by: David Sommerseth (cherry picked from commit c2d08916f1b7933bec81422d1f14f84e9b1ef878) --- src/openvpn/ntlm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/openvpn/ntlm.c b/src/openvpn/ntlm.c index 393368e4138..8c322f74a5c 100644 --- a/src/openvpn/ntlm.c +++ b/src/openvpn/ntlm.c @@ -247,8 +247,8 @@ ntlm_phase_3(const struct http_proxy_info *p, const char *phase_2, struct gc_are /* fill 1st 16 bytes with md4 hash, disregard terminating null */ - gen_md4_hash((uint8_t *)pwbuf, unicodize(pwbuf, p->up.password) - 2, - md4_hash); + int unicode_len = unicodize(pwbuf, p->up.password) - 2; + gen_md4_hash((uint8_t *)pwbuf, unicode_len, md4_hash); /* pad to 21 bytes */ memset(md4_hash + MD4_DIGEST_LENGTH, 0, 5); From 8eb2f571e148e178e62a8fce20a06d4692203aeb Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Mon, 10 Jul 2017 12:34:41 +0800 Subject: [PATCH 590/643] ntlm: improve code style and readability This patch does not introduce any functional or behavioural change. The code in ntlm.c has been restyled to better to obey to the new coding style and its readability has been a improved a bit. Signed-off-by: Antonio Quartulli Acked-by: Steffan Karger Message-Id: <20170710043441.24770-5-a@unstable.cc> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15028.html Signed-off-by: David Sommerseth (cherry picked from commit c310f1ecba905f091e3a31cb3e6cba5ae75e996b) --- src/openvpn/ntlm.c | 74 ++++++++++++++++++++++++++++------------------ 1 file changed, 45 insertions(+), 29 deletions(-) diff --git a/src/openvpn/ntlm.c b/src/openvpn/ntlm.c index 8c322f74a5c..65c1cbf5d98 100644 --- a/src/openvpn/ntlm.c +++ b/src/openvpn/ntlm.c @@ -60,13 +60,13 @@ static void create_des_keys(const unsigned char *hash, unsigned char *key) { key[0] = hash[0]; - key[1] = ((hash[0]&1)<<7)|(hash[1]>>1); - key[2] = ((hash[1]&3)<<6)|(hash[2]>>2); - key[3] = ((hash[2]&7)<<5)|(hash[3]>>3); - key[4] = ((hash[3]&15)<<4)|(hash[4]>>4); - key[5] = ((hash[4]&31)<<3)|(hash[5]>>5); - key[6] = ((hash[5]&63)<<2)|(hash[6]>>6); - key[7] = ((hash[6]&127)<<1); + key[1] = ((hash[0] & 1) << 7) | (hash[1] >> 1); + key[2] = ((hash[1] & 3) << 6) | (hash[2] >> 2); + key[3] = ((hash[2] & 7) << 5) | (hash[3] >> 3); + key[4] = ((hash[3] & 15) << 4) | (hash[4] >> 4); + key[5] = ((hash[4] & 31) << 3) | (hash[5] >> 5); + key[6] = ((hash[5] & 63) << 2) | (hash[6] >> 6); + key[7] = ((hash[6] & 127) << 1); key_des_fixup(key, 8, 1); } @@ -99,7 +99,8 @@ static void gen_timestamp(uint8_t *timestamp) { /* Copies 8 bytes long timestamp into "timestamp" buffer. - * Timestamp is Little-endian, 64-bit signed value representing the number of tenths of a microsecond since January 1, 1601. + * Timestamp is Little-endian, 64-bit signed value representing the + * number of tenths of a microsecond since January 1, 1601. */ UINTEGER64 timestamp_ull; @@ -151,16 +152,17 @@ unicodize(char *dst, const char *src) { dst[i++] = *src; dst[i++] = 0; - } - while (*src++); + } while (*src++); return i; } static void -add_security_buffer(int sb_offset, void *data, int length, unsigned char *msg_buf, int *msg_bufpos) +add_security_buffer(int sb_offset, void *data, int length, + unsigned char *msg_buf, int *msg_bufpos) { - /* Adds security buffer data to a message and sets security buffer's offset and length */ + /* Adds security buffer data to a message and sets security buffer's + * offset and length */ msg_buf[sb_offset] = (unsigned char)length; msg_buf[sb_offset + 2] = msg_buf[sb_offset]; msg_buf[sb_offset + 4] = (unsigned char)(*msg_bufpos & 0xff); @@ -187,7 +189,8 @@ ntlm_phase_1(const struct http_proxy_info *p, struct gc_arena *gc) } const char * -ntlm_phase_3(const struct http_proxy_info *p, const char *phase_2, struct gc_arena *gc) +ntlm_phase_3(const struct http_proxy_info *p, const char *phase_2, + struct gc_arena *gc) { /* NTLM handshake * @@ -297,13 +300,16 @@ ntlm_phase_3(const struct http_proxy_info *p, const char *phase_2, struct gc_are ntlmv2_blob[0x18] = 0; /* Unknown, zero should work */ /* Add target information block to the blob */ - if (( *((long *)&buf2[0x14]) & 0x00800000) == 0x00800000) /* Check for Target Information block */ + + /* Check for Target Information block */ + if ((*((long *)&buf2[0x14]) & 0x00800000) == 0x00800000) { tib_len = buf2[0x28]; /* Get Target Information block size */ if (tib_len > 96) { tib_len = 96; } + { uint8_t *tib_ptr; uint8_t tib_pos = buf2[0x2c]; @@ -311,8 +317,10 @@ ntlm_phase_3(const struct http_proxy_info *p, const char *phase_2, struct gc_are { return NULL; } - tib_ptr = buf2 + tib_pos; /* Get Target Information block pointer */ - memcpy(&ntlmv2_blob[0x1c], tib_ptr, tib_len); /* Copy Target Information block into the blob */ + /* Get Target Information block pointer */ + tib_ptr = buf2 + tib_pos; + /* Copy Target Information block into the blob */ + memcpy(&ntlmv2_blob[0x1c], tib_ptr, tib_len); } } else @@ -320,7 +328,8 @@ ntlm_phase_3(const struct http_proxy_info *p, const char *phase_2, struct gc_are tib_len = 0; } - ntlmv2_blob[0x1c + tib_len] = 0; /* Unknown, zero works */ + /* Unknown, zero works */ + ntlmv2_blob[0x1c + tib_len] = 0; /* Get blob length */ ntlmv2_blob_size = 0x20 + tib_len; @@ -329,15 +338,18 @@ ntlm_phase_3(const struct http_proxy_info *p, const char *phase_2, struct gc_are memcpy(&ntlmv2_response[8], challenge, 8); /* hmac-md5 */ - gen_hmac_md5(&ntlmv2_response[8], ntlmv2_blob_size + 8, ntlmv2_hash, MD5_DIGEST_LENGTH, ntlmv2_hmacmd5); - - /* Add hmac-md5 result to the blob */ - memcpy(ntlmv2_response, ntlmv2_hmacmd5, MD5_DIGEST_LENGTH); /* Note: This overwrites challenge previously written at ntlmv2_response[8..15] */ + gen_hmac_md5(&ntlmv2_response[8], ntlmv2_blob_size + 8, ntlmv2_hash, + MD5_DIGEST_LENGTH, ntlmv2_hmacmd5); + /* Add hmac-md5 result to the blob. + * Note: This overwrites challenge previously written at + * ntlmv2_response[8..15] */ + memcpy(ntlmv2_response, ntlmv2_hmacmd5, MD5_DIGEST_LENGTH); } - else /* Generate NTLM response */ + else /* Generate NTLM response */ { - unsigned char key1[DES_KEY_LENGTH], key2[DES_KEY_LENGTH], key3[DES_KEY_LENGTH]; + unsigned char key1[DES_KEY_LENGTH], key2[DES_KEY_LENGTH]; + unsigned char key3[DES_KEY_LENGTH]; create_des_keys(md4_hash, key1); cipher_des_encrypt_ecb(key1, challenge, ntlm_response); @@ -346,7 +358,8 @@ ntlm_phase_3(const struct http_proxy_info *p, const char *phase_2, struct gc_are cipher_des_encrypt_ecb(key2, challenge, &ntlm_response[DES_KEY_LENGTH]); create_des_keys(&md4_hash[2 * (DES_KEY_LENGTH - 1)], key3); - cipher_des_encrypt_ecb(key3, challenge, &ntlm_response[DES_KEY_LENGTH*2]); + cipher_des_encrypt_ecb(key3, challenge, + &ntlm_response[DES_KEY_LENGTH * 2]); } @@ -357,7 +370,8 @@ ntlm_phase_3(const struct http_proxy_info *p, const char *phase_2, struct gc_are if (ntlmv2_enabled) /* NTLMv2 response */ { - add_security_buffer(0x14, ntlmv2_response, ntlmv2_blob_size + 16, phase3, &phase3_bufpos); + add_security_buffer(0x14, ntlmv2_response, ntlmv2_blob_size + 16, + phase3, &phase3_bufpos); } else /* NTLM response */ { @@ -365,12 +379,13 @@ ntlm_phase_3(const struct http_proxy_info *p, const char *phase_2, struct gc_are } /* username in ascii */ - add_security_buffer(0x24, username, strlen(username), phase3, &phase3_bufpos); + add_security_buffer(0x24, username, strlen(username), phase3, + &phase3_bufpos); - /* Set domain. If is empty, default domain will be used (i.e. proxy's domain) */ + /* Set domain. If is empty, default domain will be used + * (i.e. proxy's domain) */ add_security_buffer(0x1c, domain, strlen(domain), phase3, &phase3_bufpos); - /* other security buffers will be empty */ phase3[0x10] = phase3_bufpos; /* lm not used */ phase3[0x30] = phase3_bufpos; /* no workstation name supplied */ @@ -380,7 +395,8 @@ ntlm_phase_3(const struct http_proxy_info *p, const char *phase_2, struct gc_are phase3[0x3c] = 0x02; /* negotiate oem */ phase3[0x3d] = 0x02; /* negotiate ntlm */ - return ((const char *)make_base64_string2((unsigned char *)phase3, phase3_bufpos, gc)); + return ((const char *)make_base64_string2((unsigned char *)phase3, + phase3_bufpos, gc)); } #else /* if NTLM */ From 4b8d654d1339b9adb1f7d554b1f5c16e05123f18 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Sun, 23 Jul 2017 18:45:36 +0200 Subject: [PATCH 591/643] Print ec bit details, refuse management-external-key if key is not RSA V2: Print also curve details, add missing ifdef V3: Goto err instead of using M_FATAL, format fixes, use EC_GROUP_get_curve_name + OBJ_nid2sn instead of ECPKParameters_print, add compat headers for 1.0.2 V4: Formatting changes and change M_ERR to M_WARN Acked-by: Steffan Karger Message-Id: <1500828336-30314-1-git-send-email-arne@rfc2549.org> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15124.html Signed-off-by: David Sommerseth (cherry picked from commit bb23eca847c8edac9c3979b7f35468b74db00459) --- configure.ac | 2 ++ src/openvpn/openssl_compat.h | 32 ++++++++++++++++++++++++++++++++ src/openvpn/ssl_openssl.c | 29 +++++++++++++++++++++++++++-- 3 files changed, 61 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 148a086955b..2502166a657 100644 --- a/configure.ac +++ b/configure.ac @@ -914,6 +914,7 @@ if test "${enable_crypto}" = "yes" -a "${with_crypto_library}" = "openssl"; then EVP_PKEY_id \ EVP_PKEY_get0_RSA \ EVP_PKEY_get0_DSA \ + EVP_PKEY_get0_EC_KEY \ RSA_set_flags \ RSA_bits \ RSA_get0_key \ @@ -929,6 +930,7 @@ if test "${enable_crypto}" = "yes" -a "${with_crypto_library}" = "openssl"; then RSA_meth_set_init \ RSA_meth_set_finish \ RSA_meth_set0_app_data \ + EC_GROUP_order_bits ] ) diff --git a/src/openvpn/openssl_compat.h b/src/openvpn/openssl_compat.h index 36f68b01ea6..70b19aea913 100644 --- a/src/openvpn/openssl_compat.h +++ b/src/openvpn/openssl_compat.h @@ -244,6 +244,20 @@ EVP_PKEY_get0_RSA(EVP_PKEY *pkey) } #endif +#if !defined(HAVE_EVP_PKEY_GET0_EC_KEY) && !defined(OPENSSL_NO_EC) +/** + * Get the EC_KEY object of a public key + * + * @param pkey Public key object + * @return The underlying EC_KEY object + */ +static inline EC_KEY * +EVP_PKEY_get0_EC_KEY(EVP_PKEY *pkey) +{ + return pkey ? pkey->pkey.ec : NULL; +} +#endif + #if !defined(HAVE_EVP_PKEY_ID) /** * Get the PKEY type @@ -610,6 +624,24 @@ RSA_meth_set0_app_data(RSA_METHOD *meth, void *app_data) } #endif +#if !defined(HAVE_EC_GROUP_ORDER_BITS) && !defined(OPENSSL_NO_EC) +/** + * Gets the number of bits of the order of an EC_GROUP + * + * @param group EC_GROUP object + * @return number of bits of group order. + */ +static inline int +EC_GROUP_order_bits(const EC_GROUP *group) +{ + BIGNUM* order = BN_new(); + EC_GROUP_get_order(group, order, NULL); + int bits = BN_num_bits(order); + BN_free(order); + return bits; +} +#endif + /* SSLeay symbols have been renamed in OpenSSL 1.1 */ #if !defined(RSA_F_RSA_OSSL_PRIVATE_ENCRYPT) #define RSA_F_RSA_OSSL_PRIVATE_ENCRYPT RSA_F_RSA_EAY_PRIVATE_ENCRYPT diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c index e589dcd9fe3..0ac60357c2b 100644 --- a/src/openvpn/ssl_openssl.c +++ b/src/openvpn/ssl_openssl.c @@ -1080,6 +1080,13 @@ tls_ctx_use_external_private_key(struct tls_root_ctx *ctx, ASSERT(pkey); /* NULL before SSL_CTX_use_certificate() is called */ pub_rsa = EVP_PKEY_get0_RSA(pkey); + /* Certificate might not be RSA but DSA or EC */ + if (!pub_rsa) + { + crypto_msg(M_WARN, "management-external-key requires a RSA certificate"); + goto err; + } + /* initialize RSA object */ const BIGNUM *n = NULL; const BIGNUM *e = NULL; @@ -1686,18 +1693,36 @@ print_details(struct key_state_ssl *ks_ssl, const char *prefix) EVP_PKEY *pkey = X509_get_pubkey(cert); if (pkey != NULL) { - if (EVP_PKEY_id(pkey) == EVP_PKEY_RSA && EVP_PKEY_get0_RSA(pkey) != NULL) + if ((EVP_PKEY_id(pkey) == EVP_PKEY_RSA) && (EVP_PKEY_get0_RSA(pkey) != NULL)) { RSA *rsa = EVP_PKEY_get0_RSA(pkey); openvpn_snprintf(s2, sizeof(s2), ", %d bit RSA", RSA_bits(rsa)); } - else if (EVP_PKEY_id(pkey) == EVP_PKEY_DSA && EVP_PKEY_get0_DSA(pkey) != NULL) + else if ((EVP_PKEY_id(pkey) == EVP_PKEY_DSA) && (EVP_PKEY_get0_DSA(pkey) != NULL)) { DSA *dsa = EVP_PKEY_get0_DSA(pkey); openvpn_snprintf(s2, sizeof(s2), ", %d bit DSA", DSA_bits(dsa)); } +#ifndef OPENSSL_NO_EC + else if ((EVP_PKEY_id(pkey) == EVP_PKEY_EC) && (EVP_PKEY_get0_EC_KEY(pkey) != NULL)) + { + EC_KEY *ec = EVP_PKEY_get0_EC_KEY(pkey); + const EC_GROUP *group = EC_KEY_get0_group(ec); + const char* curve; + + int nid = EC_GROUP_get_curve_name(group); + if (nid == 0 || (curve = OBJ_nid2sn(nid)) == NULL) + { + curve = "Error getting curve name"; + } + + openvpn_snprintf(s2, sizeof(s2), ", %d bit EC, curve: %s", + EC_GROUP_order_bits(group), curve); + + } +#endif EVP_PKEY_free(pkey); } X509_free(cert); From b597ded895e372831bb19538e5591d5c52270a44 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Tue, 25 Jul 2017 15:03:14 +0200 Subject: [PATCH 592/643] contrib: Remove keychain-mcd code After the security audits performed by Cryptography Engineering the spring of 2017 [1], there were several concerns about the contrib code for the macOS keychain support. After more careful review of this code base, it was considered to be in such a bad shape that it will need a massive overhaul. There were more issues than what the security audit revealed. It was attempted several times to get in touch with the contributor of this code; with no response at all [2]. There has however been some discussions with the Tunnelblick project [3]. There is one person there willing to go through this and improve the situation. The main Tunnelblick maintainer is also willing to include the improved code to their project instead of having this as a contrib code in the upstream OpenVPN project. So this patch just removes the code which we will no longer ship as part of OpenVPN - and the Tunnelblick project will take over the responsibility for this code base on their own. And since this code base is purely macOS specific, this seems to be a far better place for this code to reside. Signed-off-by: David Sommerseth [1] [2] [3] Acked-by: Jonathan K. Bullard Message-Id: <20170725130314.12919-1-davids@openvpn.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15130.html Signed-off-by: David Sommerseth (cherry picked from commit 59e7e9fce8de6ea90d13baeaede83adc0b594e22) --- contrib/keychain-mcd/Makefile | 13 - contrib/keychain-mcd/cert_data.c | 866 ---------------------------- contrib/keychain-mcd/cert_data.h | 50 -- contrib/keychain-mcd/common_osx.c | 100 ---- contrib/keychain-mcd/common_osx.h | 38 -- contrib/keychain-mcd/crypto_osx.c | 79 --- contrib/keychain-mcd/crypto_osx.h | 44 -- contrib/keychain-mcd/keychain-mcd.8 | 161 ------ contrib/keychain-mcd/main.c | 310 ---------- 9 files changed, 1661 deletions(-) delete mode 100644 contrib/keychain-mcd/Makefile delete mode 100644 contrib/keychain-mcd/cert_data.c delete mode 100644 contrib/keychain-mcd/cert_data.h delete mode 100644 contrib/keychain-mcd/common_osx.c delete mode 100644 contrib/keychain-mcd/common_osx.h delete mode 100644 contrib/keychain-mcd/crypto_osx.c delete mode 100644 contrib/keychain-mcd/crypto_osx.h delete mode 100644 contrib/keychain-mcd/keychain-mcd.8 delete mode 100644 contrib/keychain-mcd/main.c diff --git a/contrib/keychain-mcd/Makefile b/contrib/keychain-mcd/Makefile deleted file mode 100644 index c6431df1587..00000000000 --- a/contrib/keychain-mcd/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -CFILES = cert_data.c common_osx.c crypto_osx.c main.c -OFILES = $(CFILES:.c=.o) ../../src/openvpn/base64.o -prog = keychain-mcd - -CC = gcc -CFLAGS = -Wall -LDFLAGS = -framework CoreFoundation -framework Security -framework CoreServices - -$(prog): $(OFILES) - $(CC) $(LDFLAGS) $(OFILES) -o $(prog) - -%.o: %.c - $(CC) $(CFLAGS) -c $< -o $@ diff --git a/contrib/keychain-mcd/cert_data.c b/contrib/keychain-mcd/cert_data.c deleted file mode 100644 index c04f68ec0f4..00000000000 --- a/contrib/keychain-mcd/cert_data.c +++ /dev/null @@ -1,866 +0,0 @@ -/* - * OpenVPN -- An application to securely tunnel IP networks - * over a single UDP port, with support for SSL/TLS-based - * session authentication and key exchange, - * packet encryption, packet authentication, and - * packet compression. - * - * Copyright (C) 2010 Brian Raderman - * Copyright (C) 2013-2015 Vasily Kulikov - * - * 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; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - - -#include "cert_data.h" -#include -#include - -#include "common_osx.h" -#include "crypto_osx.h" -#include - -CFStringRef kCertDataSubjectName = CFSTR("subject"), - kCertDataIssuerName = CFSTR("issuer"), - kCertDataSha1Name = CFSTR("SHA1"), - kCertDataMd5Name = CFSTR("MD5"), - kCertDataSerialName = CFSTR("serial"), - kCertNameFwdSlash = CFSTR("/"), - kCertNameEquals = CFSTR("="); -CFStringRef kCertNameOrganization = CFSTR("o"), - kCertNameOrganizationalUnit = CFSTR("ou"), - kCertNameCountry = CFSTR("c"), - kCertNameLocality = CFSTR("l"), - kCertNameState = CFSTR("st"), - kCertNameCommonName = CFSTR("cn"), - kCertNameEmail = CFSTR("e"); -CFStringRef kStringSpace = CFSTR(" "), - kStringEmpty = CFSTR(""); - -typedef struct _CertName -{ - CFArrayRef countryName, organization, organizationalUnit, commonName, description, emailAddress, - stateName, localityName; -} CertName, *CertNameRef; - -typedef struct _DescData -{ - CFStringRef name, value; -} DescData, *DescDataRef; - -void destroyDescData(DescDataRef pData); - -CertNameRef -createCertName() -{ - CertNameRef pCertName = (CertNameRef)malloc(sizeof(CertName)); - pCertName->countryName = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - pCertName->organization = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - pCertName->organizationalUnit = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - pCertName->commonName = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - pCertName->description = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - pCertName->emailAddress = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - pCertName->stateName = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - pCertName->localityName = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - return pCertName; -} - -void -destroyCertName(CertNameRef pCertName) -{ - if (!pCertName) - { - return; - } - - CFRelease(pCertName->countryName); - CFRelease(pCertName->organization); - CFRelease(pCertName->organizationalUnit); - CFRelease(pCertName->commonName); - CFRelease(pCertName->description); - CFRelease(pCertName->emailAddress); - CFRelease(pCertName->stateName); - CFRelease(pCertName->localityName); - free(pCertName); -} - -bool -CFStringRefCmpCString(CFStringRef cfstr, const char *str) -{ - CFStringRef tmp = CFStringCreateWithCStringNoCopy(NULL, str, kCFStringEncodingUTF8, kCFAllocatorNull); - CFComparisonResult cresult = CFStringCompare(cfstr, tmp, 0); - bool result = cresult == kCFCompareEqualTo; - CFRelease(tmp); - return result; -} - -CFDateRef -GetDateFieldFromCertificate(SecCertificateRef certificate, CFTypeRef oid) -{ - const void *keys[] = { oid }; - CFDictionaryRef dict = NULL; - CFErrorRef error; - CFDateRef date = NULL; - - CFArrayRef keySelection = CFArrayCreate(NULL, keys, sizeof(keys)/sizeof(keys[0]), &kCFTypeArrayCallBacks); - dict = SecCertificateCopyValues(certificate, keySelection, &error); - if (dict == NULL) - { - printErrorMsg("GetDateFieldFromCertificate: SecCertificateCopyValues", error); - goto release_ks; - } - CFDictionaryRef vals = dict ? CFDictionaryGetValue(dict, oid) : NULL; - CFNumberRef vals2 = vals ? CFDictionaryGetValue(vals, kSecPropertyKeyValue) : NULL; - if (vals2 == NULL) - { - goto release_dict; - } - - CFAbsoluteTime validityNotBefore; - if (CFNumberGetValue(vals2, kCFNumberDoubleType, &validityNotBefore)) - { - date = CFDateCreate(kCFAllocatorDefault,validityNotBefore); - } - -release_dict: - CFRelease(dict); -release_ks: - CFRelease(keySelection); - return date; -} - -CFArrayRef -GetFieldsFromCertificate(SecCertificateRef certificate, CFTypeRef oid) -{ - CFMutableArrayRef fields = CFArrayCreateMutable(NULL, 0, NULL); - CertNameRef pCertName = createCertName(); - const void *keys[] = { oid, }; - CFDictionaryRef dict; - CFErrorRef error; - - CFArrayRef keySelection = CFArrayCreate(NULL, keys, 1, NULL); - - dict = SecCertificateCopyValues(certificate, keySelection, &error); - if (dict == NULL) - { - printErrorMsg("GetFieldsFromCertificate: SecCertificateCopyValues", error); - CFRelease(keySelection); - CFRelease(fields); - destroyCertName(pCertName); - return NULL; - } - CFDictionaryRef vals = CFDictionaryGetValue(dict, oid); - CFArrayRef vals2 = vals ? CFDictionaryGetValue(vals, kSecPropertyKeyValue) : NULL; - if (vals2) - { - for (int i = 0; i < CFArrayGetCount(vals2); i++) { - CFDictionaryRef subDict = CFArrayGetValueAtIndex(vals2, i); - CFStringRef label = CFDictionaryGetValue(subDict, kSecPropertyKeyLabel); - CFStringRef value = CFDictionaryGetValue(subDict, kSecPropertyKeyValue); - - if (CFStringCompare(label, kSecOIDEmailAddress, 0) == kCFCompareEqualTo) - { - CFArrayAppendValue((CFMutableArrayRef)pCertName->emailAddress, value); - } - else if (CFStringCompare(label, kSecOIDCountryName, 0) == kCFCompareEqualTo) - { - CFArrayAppendValue((CFMutableArrayRef)pCertName->countryName, value); - } - else if (CFStringCompare(label, kSecOIDOrganizationName, 0) == kCFCompareEqualTo) - { - CFArrayAppendValue((CFMutableArrayRef)pCertName->organization, value); - } - else if (CFStringCompare(label, kSecOIDOrganizationalUnitName, 0) == kCFCompareEqualTo) - { - CFArrayAppendValue((CFMutableArrayRef)pCertName->organizationalUnit, value); - } - else if (CFStringCompare(label, kSecOIDCommonName, 0) == kCFCompareEqualTo) - { - CFArrayAppendValue((CFMutableArrayRef)pCertName->commonName, value); - } - else if (CFStringCompare(label, kSecOIDDescription, 0) == kCFCompareEqualTo) - { - CFArrayAppendValue((CFMutableArrayRef)pCertName->description, value); - } - else if (CFStringCompare(label, kSecOIDStateProvinceName, 0) == kCFCompareEqualTo) - { - CFArrayAppendValue((CFMutableArrayRef)pCertName->stateName, value); - } - else if (CFStringCompare(label, kSecOIDLocalityName, 0) == kCFCompareEqualTo) - { - CFArrayAppendValue((CFMutableArrayRef)pCertName->localityName, value); - } - } - CFArrayAppendValue(fields, pCertName); - } - - CFRelease(dict); - CFRelease(keySelection); - return fields; -} - -CertDataRef -createCertDataFromCertificate(SecCertificateRef certificate) -{ - CertDataRef pCertData = (CertDataRef)malloc(sizeof(CertData)); - pCertData->subject = GetFieldsFromCertificate(certificate, kSecOIDX509V1SubjectName); - pCertData->issuer = GetFieldsFromCertificate(certificate, kSecOIDX509V1IssuerName); - - CFDataRef data = SecCertificateCopyData(certificate); - if (data == NULL) - { - warnx("SecCertificateCopyData() returned NULL"); - destroyCertData(pCertData); - return NULL; - } - - unsigned char sha1[CC_SHA1_DIGEST_LENGTH]; - CC_SHA1(CFDataGetBytePtr(data), CFDataGetLength(data), sha1); - pCertData->sha1 = createHexString(sha1, CC_SHA1_DIGEST_LENGTH); - - unsigned char md5[CC_MD5_DIGEST_LENGTH]; - CC_MD5(CFDataGetBytePtr(data), CFDataGetLength(data), md5); - pCertData->md5 = createHexString((unsigned char *)md5, CC_MD5_DIGEST_LENGTH); - - CFDataRef serial = SecCertificateCopySerialNumber(certificate, NULL); - pCertData->serial = createHexString((unsigned char *)CFDataGetBytePtr(serial), CFDataGetLength(serial)); - CFRelease(serial); - - return pCertData; -} - -CFStringRef -stringFromRange(const char *cstring, CFRange range) -{ - CFStringRef str = CFStringCreateWithBytes(NULL, (uint8 *)&cstring[range.location], range.length, kCFStringEncodingUTF8, false); - CFMutableStringRef mutableStr = CFStringCreateMutableCopy(NULL, 0, str); - CFStringTrimWhitespace(mutableStr); - CFRelease(str); - return mutableStr; -} - -DescDataRef -createDescData(const char *description, CFRange nameRange, CFRange valueRange) -{ - DescDataRef pRetVal = (DescDataRef)malloc(sizeof(DescData)); - - memset(pRetVal, 0, sizeof(DescData)); - - if (nameRange.length > 0) - { - pRetVal->name = stringFromRange(description, nameRange); - } - - if (valueRange.length > 0) - { - pRetVal->value = stringFromRange(description, valueRange); - } - -#if 0 - fprintf(stderr, "name = '%s', value = '%s'\n", - CFStringGetCStringPtr(pRetVal->name, kCFStringEncodingUTF8), - CFStringGetCStringPtr(pRetVal->value, kCFStringEncodingUTF8)); -#endif - return pRetVal; -} - -void -destroyDescData(DescDataRef pData) -{ - if (pData->name) - { - CFRelease(pData->name); - } - - if (pData->value) - { - CFRelease(pData->value); - } - - free(pData); -} - -CFArrayRef -createDescDataPairs(const char *description) -{ - int numChars = strlen(description); - CFRange nameRange, valueRange; - DescDataRef pData; - CFMutableArrayRef retVal = CFArrayCreateMutable(NULL, 0, NULL); - - int i = 0; - - nameRange = CFRangeMake(0, 0); - valueRange = CFRangeMake(0, 0); - bool bInValue = false; - - while (i < numChars) - { - if (!bInValue && (description[i] != ':')) - { - nameRange.length++; - } - else if (bInValue && (description[i] != ':')) - { - valueRange.length++; - } - else if (!bInValue) - { - bInValue = true; - valueRange.location = i + 1; - valueRange.length = 0; - } - else /*(bInValue) */ - { - bInValue = false; - while (description[i] != ' ') - { - valueRange.length--; - i--; - } - - pData = createDescData(description, nameRange, valueRange); - CFArrayAppendValue(retVal, pData); - - nameRange.location = i + 1; - nameRange.length = 0; - } - - i++; - } - - pData = createDescData(description, nameRange, valueRange); - CFArrayAppendValue(retVal, pData); - return retVal; -} - -void -arrayDestroyDescData(const void *val, void *context) -{ - DescDataRef pData = (DescDataRef) val; - destroyDescData(pData); -} - - -int -parseNameComponent(CFStringRef dn, CFStringRef *pName, CFStringRef *pValue) -{ - CFArrayRef nameStrings = CFStringCreateArrayBySeparatingStrings(NULL, dn, kCertNameEquals); - - *pName = *pValue = NULL; - - if (CFArrayGetCount(nameStrings) != 2) - { - return 0; - } - - CFMutableStringRef str; - - str = CFStringCreateMutableCopy(NULL, 0, CFArrayGetValueAtIndex(nameStrings, 0)); - CFStringTrimWhitespace(str); - *pName = str; - - str = CFStringCreateMutableCopy(NULL, 0, CFArrayGetValueAtIndex(nameStrings, 1)); - CFStringTrimWhitespace(str); - *pValue = str; - - CFRelease(nameStrings); - return 1; -} - -int -tryAppendSingleCertField(CertNameRef pCertName, CFArrayRef where, CFStringRef key, - CFStringRef name, CFStringRef value) -{ - if (CFStringCompareWithOptions(name, key, CFRangeMake(0, CFStringGetLength(name)), kCFCompareCaseInsensitive) - == kCFCompareEqualTo) - { - CFArrayAppendValue((CFMutableArrayRef)where, value); - return 1; - } - return 0; -} - -int -appendCertField(CertNameRef pCert, CFStringRef name, CFStringRef value) -{ - struct { - CFArrayRef field; - CFStringRef key; - } fields[] = { - { pCert->organization, kCertNameOrganization}, - { pCert->organizationalUnit, kCertNameOrganizationalUnit}, - { pCert->countryName, kCertNameCountry}, - { pCert->localityName, kCertNameLocality}, - { pCert->stateName, kCertNameState}, - { pCert->commonName, kCertNameCommonName}, - { pCert->emailAddress, kCertNameEmail}, - }; - int i; - int ret = 0; - - for (i = 0; iname || !pDescData->value) - { - return 0; - } - - if (CFStringCompareWithOptions(pDescData->name, kCertDataSubjectName, CFRangeMake(0, CFStringGetLength(pDescData->name)), kCFCompareCaseInsensitive) == kCFCompareEqualTo) - { - ret = parseCertName(pDescData->value, (CFMutableArrayRef)pCertData->subject); - } - else if (CFStringCompareWithOptions(pDescData->name, kCertDataIssuerName, CFRangeMake(0, CFStringGetLength(pDescData->name)), kCFCompareCaseInsensitive) == kCFCompareEqualTo) - { - ret = parseCertName(pDescData->value, (CFMutableArrayRef)pCertData->issuer); - } - else if (CFStringCompareWithOptions(pDescData->name, kCertDataSha1Name, CFRangeMake(0, CFStringGetLength(pDescData->name)), kCFCompareCaseInsensitive) == kCFCompareEqualTo) - { - pCertData->sha1 = CFRetain(pDescData->value); - } - else if (CFStringCompareWithOptions(pDescData->name, kCertDataMd5Name, CFRangeMake(0, CFStringGetLength(pDescData->name)), kCFCompareCaseInsensitive) == kCFCompareEqualTo) - { - pCertData->md5 = CFRetain(pDescData->value); - } - else if (CFStringCompareWithOptions(pDescData->name, kCertDataSerialName, CFRangeMake(0, CFStringGetLength(pDescData->name)), kCFCompareCaseInsensitive) == kCFCompareEqualTo) - { - pCertData->serial = CFRetain(pDescData->value); - } - else - { - return 0; - } - - return ret; -} - -CertDataRef -createCertDataFromString(const char *description) -{ - CertDataRef pCertData = (CertDataRef)malloc(sizeof(CertData)); - pCertData->subject = CFArrayCreateMutable(NULL, 0, NULL); - pCertData->issuer = CFArrayCreateMutable(NULL, 0, NULL); - pCertData->sha1 = NULL; - pCertData->md5 = NULL; - pCertData->serial = NULL; - - CFArrayRef pairs = createDescDataPairs(description); - for (int i = 0; isubject) - { - CFArrayApplyFunction(pCertData->subject, CFRangeMake(0, CFArrayGetCount(pCertData->subject)), arrayDestroyCertName, NULL); - CFRelease(pCertData->subject); - } - - if (pCertData->issuer) - { - CFArrayApplyFunction(pCertData->issuer, CFRangeMake(0, CFArrayGetCount(pCertData->issuer)), arrayDestroyCertName, NULL); - CFRelease(pCertData->issuer); - } - - if (pCertData->sha1) - { - CFRelease(pCertData->sha1); - } - - if (pCertData->md5) - { - CFRelease(pCertData->md5); - } - - if (pCertData->serial) - { - CFRelease(pCertData->serial); - } - - free(pCertData); -} - -bool -stringArrayMatchesTemplate(CFArrayRef strings, CFArrayRef templateArray) -{ - int templateCount, stringCount, i; - - templateCount = CFArrayGetCount(templateArray); - - if (templateCount > 0) - { - stringCount = CFArrayGetCount(strings); - if (stringCount != templateCount) - { - return false; - } - - for (i = 0; i < stringCount; i++) - { - CFStringRef str, template; - - template = (CFStringRef)CFArrayGetValueAtIndex(templateArray, i); - str = (CFStringRef)CFArrayGetValueAtIndex(strings, i); - - if (CFStringCompareWithOptions(template, str, CFRangeMake(0, CFStringGetLength(template)), kCFCompareCaseInsensitive) != kCFCompareEqualTo) - { - return false; - } - } - } - - return true; - -} - -bool -certNameMatchesTemplate(CertNameRef pCertName, CertNameRef pTemplate) -{ - if (!stringArrayMatchesTemplate(pCertName->countryName, pTemplate->countryName)) - { - return false; - } - else if (!stringArrayMatchesTemplate(pCertName->organization, pTemplate->organization)) - { - return false; - } - else if (!stringArrayMatchesTemplate(pCertName->organizationalUnit, pTemplate->organizationalUnit)) - { - return false; - } - else if (!stringArrayMatchesTemplate(pCertName->commonName, pTemplate->commonName)) - { - return false; - } - else if (!stringArrayMatchesTemplate(pCertName->emailAddress, pTemplate->emailAddress)) - { - return false; - } - else if (!stringArrayMatchesTemplate(pCertName->stateName, pTemplate->stateName)) - { - return false; - } - else if (!stringArrayMatchesTemplate(pCertName->localityName, pTemplate->localityName)) - { - return false; - } - else - { - return true; - } -} - -bool -certNameArrayMatchesTemplate(CFArrayRef certNameArray, CFArrayRef templateArray) -{ - int templateCount, certCount, i; - - templateCount = CFArrayGetCount(templateArray); - - if (templateCount > 0) - { - certCount = CFArrayGetCount(certNameArray); - if (certCount != templateCount) - { - return false; - } - - for (i = 0; i < certCount; i++) - { - CertNameRef pName, pTemplateName; - - pTemplateName = (CertNameRef)CFArrayGetValueAtIndex(templateArray, i); - pName = (CertNameRef)CFArrayGetValueAtIndex(certNameArray, i); - - if (!certNameMatchesTemplate(pName, pTemplateName)) - { - return false; - } - } - } - - return true; -} - -bool -hexStringMatchesTemplate(CFStringRef str, CFStringRef template) -{ - if (template) - { - if (!str) - { - return false; - } - - CFMutableStringRef strMutable, templateMutable; - - strMutable = CFStringCreateMutableCopy(NULL, 0, str); - templateMutable = CFStringCreateMutableCopy(NULL, 0, template); - - CFStringFindAndReplace(strMutable, kStringSpace, kStringEmpty, CFRangeMake(0, CFStringGetLength(strMutable)), 0); - CFStringFindAndReplace(templateMutable, kStringSpace, kStringEmpty, CFRangeMake(0, CFStringGetLength(templateMutable)), 0); - - CFComparisonResult result = CFStringCompareWithOptions(templateMutable, strMutable, CFRangeMake(0, CFStringGetLength(templateMutable)), kCFCompareCaseInsensitive); - - CFRelease(strMutable); - CFRelease(templateMutable); - - if (result != kCFCompareEqualTo) - { - return false; - } - } - - return true; -} - -bool -certDataMatchesTemplate(CertDataRef pCertData, CertDataRef pTemplate) -{ - if (!certNameArrayMatchesTemplate(pCertData->subject, pTemplate->subject)) - { - return false; - } - - if (!certNameArrayMatchesTemplate(pCertData->issuer, pTemplate->issuer)) - { - return false; - } - - if (!hexStringMatchesTemplate(pCertData->sha1, pTemplate->sha1)) - { - return false; - } - - if (!hexStringMatchesTemplate(pCertData->md5, pTemplate->md5)) - { - return false; - } - - if (!hexStringMatchesTemplate(pCertData->serial, pTemplate->serial)) - { - return false; - } - - return true; -} - -bool -certExpired(SecCertificateRef certificate) -{ - bool result; - CFDateRef notAfter = GetDateFieldFromCertificate(certificate, kSecOIDX509V1ValidityNotAfter); - CFDateRef notBefore = GetDateFieldFromCertificate(certificate, kSecOIDX509V1ValidityNotBefore); - CFDateRef now = CFDateCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent()); - - if (!notAfter || !notBefore || !now) - { - warnx("GetDateFieldFromCertificate() returned NULL"); - result = true; - } - else - { - if (CFDateCompare(notBefore, now, NULL) != kCFCompareLessThan - || CFDateCompare(now, notAfter, NULL) != kCFCompareLessThan) - { - result = true; - } - else - { - result = false; - } - } - - CFRelease(notAfter); - CFRelease(notBefore); - CFRelease(now); - return result; -} - -SecIdentityRef -findIdentity(CertDataRef pCertDataTemplate) -{ - const void *keys[] = { - kSecClass, - kSecReturnRef, - kSecMatchLimit - }; - const void *values[] = { - kSecClassIdentity, - kCFBooleanTrue, - kSecMatchLimitAll - }; - CFArrayRef result = NULL; - - CFDictionaryRef query = CFDictionaryCreate(NULL, keys, values, - sizeof(keys) / sizeof(*keys), - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - OSStatus status = SecItemCopyMatching(query, (CFTypeRef *)&result); - CFRelease(query); - if (status != noErr) - { - warnx("No identities in keychain found"); - return NULL; - } - - SecIdentityRef bestIdentity = NULL; - CFDateRef bestNotBeforeDate = NULL; - - for (int i = 0; i - * Copyright (C) 2013-2015 Vasily Kulikov - * - * 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; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -#ifndef __cert_data_h__ -#define __cert_data_h__ - -#include -#include - -typedef struct _CertData -{ - CFArrayRef subject; - CFArrayRef issuer; - CFStringRef serial; - CFStringRef md5, sha1; -} CertData, *CertDataRef; - -CertDataRef createCertDataFromCertificate(SecCertificateRef certificate); - -CertDataRef createCertDataFromString(const char *description); - -void destroyCertData(CertDataRef pCertData); - -bool certDataMatchesTemplate(CertDataRef pCertData, CertDataRef pTemplate); - -void printCertData(CertDataRef pCertData); - -SecIdentityRef findIdentity(CertDataRef pCertDataTemplate); - -#endif /* ifndef __cert_data_h__ */ diff --git a/contrib/keychain-mcd/common_osx.c b/contrib/keychain-mcd/common_osx.c deleted file mode 100644 index f8178149773..00000000000 --- a/contrib/keychain-mcd/common_osx.c +++ /dev/null @@ -1,100 +0,0 @@ -/* - * OpenVPN -- An application to securely tunnel IP networks - * over a single UDP port, with support for SSL/TLS-based - * session authentication and key exchange, - * packet encryption, packet authentication, and - * packet compression. - * - * Copyright (C) 2010 Brian Raderman - * Copyright (C) 2013-2015 Vasily Kulikov - * - * 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; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -/* - #include "config.h" - #include "syshead.h" - #include "common.h" - #include "buffer.h" - #include "error.h" - */ - -#include "common_osx.h" -#include - -void -printCFString(CFStringRef str) -{ - CFIndex bufferLength = CFStringGetLength(str) + 1; - char *pBuffer = (char *)malloc(sizeof(char) * bufferLength); - CFStringGetCString(str, pBuffer, bufferLength, kCFStringEncodingUTF8); - warnx("%s\n", pBuffer); - free(pBuffer); -} - -char * -cfstringToCstr(CFStringRef str) -{ - CFIndex bufferLength = CFStringGetLength(str) + 1; - char *pBuffer = (char *)malloc(sizeof(char) * bufferLength); - CFStringGetCString(str, pBuffer, bufferLength, kCFStringEncodingUTF8); - return pBuffer; -} - -void -appendHexChar(CFMutableStringRef str, unsigned char halfByte) -{ - if (halfByte < 10) - { - CFStringAppendFormat(str, NULL, CFSTR("%d"), halfByte); - } - else - { - char tmp[2] = {'A'+halfByte-10, 0}; - CFStringAppendCString(str, tmp, kCFStringEncodingUTF8); - } -} - -CFStringRef -createHexString(unsigned char *pData, int length) -{ - unsigned char byte, low, high; - int i; - CFMutableStringRef str = CFStringCreateMutable(NULL, 0); - - for (i = 0; i < length; i++) - { - byte = pData[i]; - low = byte & 0x0F; - high = (byte >> 4); - - appendHexChar(str, high); - appendHexChar(str, low); - - if (i != (length - 1)) - { - CFStringAppendCString(str, " ", kCFStringEncodingUTF8); - } - } - - return str; -} - -void -printHex(unsigned char *pData, int length) -{ - CFStringRef hexStr = createHexString(pData, length); - printCFString(hexStr); - CFRelease(hexStr); -} diff --git a/contrib/keychain-mcd/common_osx.h b/contrib/keychain-mcd/common_osx.h deleted file mode 100644 index d37e059e9e9..00000000000 --- a/contrib/keychain-mcd/common_osx.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * OpenVPN -- An application to securely tunnel IP networks - * over a single UDP port, with support for SSL/TLS-based - * session authentication and key exchange, - * packet encryption, packet authentication, and - * packet compression. - * - * Copyright (C) 2010 Brian Raderman - * Copyright (C) 2013-2015 Vasily Kulikov - * - * 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; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef __common_osx_h__ -#define __common_osx_h__ - -#include - -void printCFString(CFStringRef str); - -char *cfstringToCstr(CFStringRef str); - -CFStringRef createHexString(unsigned char *pData, int length); - -void printHex(unsigned char *pData, int length); - -#endif /*__Common_osx_h__ */ diff --git a/contrib/keychain-mcd/crypto_osx.c b/contrib/keychain-mcd/crypto_osx.c deleted file mode 100644 index 27ac4f5b9d5..00000000000 --- a/contrib/keychain-mcd/crypto_osx.c +++ /dev/null @@ -1,79 +0,0 @@ -/* - * OpenVPN -- An application to securely tunnel IP networks - * over a single UDP port, with support for SSL/TLS-based - * session authentication and key exchange, - * packet encryption, packet authentication, and - * packet compression. - * - * Copyright (C) 2010 Brian Raderman - * Copyright (C) 2013-2015 Vasily Kulikov - * - * 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; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - - -#include -#include -#include - -#include "crypto_osx.h" -#include - -void -printErrorMsg(const char *func, CFErrorRef error) -{ - CFStringRef desc = CFErrorCopyDescription(error); - warnx("%s failed: %s", func, CFStringGetCStringPtr(desc, kCFStringEncodingUTF8)); - CFRelease(desc); -} - -void -printErrorStatusMsg(const char *func, OSStatus status) -{ - CFStringRef error; - error = SecCopyErrorMessageString(status, NULL); - if (error) - { - warnx("%s failed: %s", func, CFStringGetCStringPtr(error, kCFStringEncodingUTF8)); - CFRelease(error); - } - else - { - warnx("%s failed: %X", func, (int)status); - } -} - -void -signData(SecIdentityRef identity, const uint8_t *from, int flen, uint8_t *to, size_t *tlen) -{ - SecKeyRef privateKey = NULL; - OSStatus status; - - status = SecIdentityCopyPrivateKey(identity, &privateKey); - if (status != noErr) - { - printErrorStatusMsg("signData: SecIdentityCopyPrivateKey", status); - *tlen = 0; - return; - } - - status = SecKeyRawSign(privateKey, kSecPaddingPKCS1, from, flen, to, tlen); - CFRelease(privateKey); - if (status != noErr) - { - printErrorStatusMsg("signData: SecKeyRawSign", status); - *tlen = 0; - return; - } -} diff --git a/contrib/keychain-mcd/crypto_osx.h b/contrib/keychain-mcd/crypto_osx.h deleted file mode 100644 index 9f4b3f9d320..00000000000 --- a/contrib/keychain-mcd/crypto_osx.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * OpenVPN -- An application to securely tunnel IP networks - * over a single UDP port, with support for SSL/TLS-based - * session authentication and key exchange, - * packet encryption, packet authentication, and - * packet compression. - * - * Copyright (C) 2010 Brian Raderman - * Copyright (C) 2013-2015 Vasily Kulikov - * - * 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; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef __crypto_osx_h__ -#define __crypto_osx_h__ - -#include -#include - -extern OSStatus SecKeyRawSign( - SecKeyRef key, - SecPadding padding, - const uint8_t *dataToSign, - size_t dataToSignLen, - uint8_t *sig, - size_t *sigLen - ); - -void signData(SecIdentityRef identity, const uint8_t *from, int flen, uint8_t *to, size_t *tlen); - -void printErrorMsg(const char *func, CFErrorRef error); - -#endif /*__crypto_osx_h__ */ diff --git a/contrib/keychain-mcd/keychain-mcd.8 b/contrib/keychain-mcd/keychain-mcd.8 deleted file mode 100644 index 676b1646da5..00000000000 --- a/contrib/keychain-mcd/keychain-mcd.8 +++ /dev/null @@ -1,161 +0,0 @@ -.TH keychain-mcd 8 -.SH NAME - -keychain-mcd \- Mac OS X Keychain management daemon for OpenVPN - -.SH SYNOPSIS - -.B keychain-mcd -.I identity-template management-server-ip management-server-port -[ -.I password-file -] - -.SH DESCRIPTION - -.B keychain-mcd -is Mac OS X Keychain management daemon for OpenVPN. -It loads the certificate and private key from the Mac OSX Keychain (Mac OSX Only). -.B keychain-mcd -connects to OpenVPN via management interface and handles -certificate and private key commands (namely -.B NEED-CERTIFICATE -and -.B RSA-SIGN -commands). - -.B keychain-mcd -makes it possible to use any smart card supported by Mac OSX using the tokend interface, but also any -kind of certificate, residing in the Keychain, where you have access to -the private key. This option has been tested on the client side with an Aladdin eToken -on Mac OSX Leopard and with software certificates stored in the Keychain on Mac OS X. - -Note that Mac OS X might need to present the user with an authentication GUI when the Keychain -is accessed by keychain-mcd. - -Use -.B keychain-mcd -along with -.B --management-external-key -and/or -.B --management-external-cert -passed to -.B openvpn. - -.SH OPTIONS - -.TP -.BR identity-template - -A select string which is used to choose a keychain identity from -Mac OS X Keychain or -.I auto -if the identity template is passed from openvpn. - -\fBSubject\fR, \fBIssuer\fR, \fBSerial\fR, \fBSHA1\fR, \fBMD5\fR selectors can be used. - -To select a certificate based on a string search in the -certificate's subject and/or issuer: - -.nf - -"SUBJECT:c=US/o=Apple Inc./ou=me.com/cn=username ISSUER:c=US/o=Apple Computer, Inc./ou=Apple Computer Certificate Authority/cn=Apple .Mac Certificate Authority" - -.fi - -.I "Distinguished Name Component Abbreviations:" -.br -o = organization -.br -ou = organizational unit -.br -c = country -.br -l = locality -.br -st = state -.br -cn = common name -.br -e = email -.br - -All of the distinguished name components are optional, although you do need to specify at least one of them. You can -add spaces around the '/' and '=' characters, e.g. "SUBJECT: c = US / o = Apple Inc.". You do not need to specify -both the subject and the issuer, one or the other will work fine. -The identity searching algorithm will return the -certificate it finds that matches all of the criteria you have specified. -If there are several certificates matching all of the criteria then the youngest certificate is returned -(i.e. with the greater "not before" validity field). -You can also include the MD5 and/or SHA1 thumbprints and/or serial number -along with the subject and issuer. - -To select a certificate based on certificate's MD5 or SHA1 thumbprint: - -.nf -"SHA1: 30 F7 3A 7A B7 73 2A 98 54 33 4A A7 00 6F 6E AC EC D1 EF 02" - -"MD5: D5 F5 11 F1 38 EB 5F 4D CF 23 B6 94 E8 33 D8 B5" -.fi - -Again, you can include both the SHA1 and the MD5 thumbprints, but you can also use just one of them. -The thumbprint hex strings can easily be copy-and-pasted from the OSX Keychain Access GUI in the Applications/Utilities folder. -The hex string comparison is not case sensitive. - -To select a certificate based on certificate's serial number: - -"Serial: 3E 9B 6F 02 00 00 00 01 1F 20" - -If -.BR identity-template -equals to -.I auto -then the actual identity template is -obtained from argument of NEED-CERTIFICATE notification of openvpn. -In this case the argument of NEED-CERTIFICATE must begin with 'macosx-keychain:' prefix -and the rest of it must contain the actual identity template in the format described above. - - -.TP -.BR management-server-ip -OpenVPN management IP to connect to. -Both IPv4 and IPv6 addresses can be used. - -.TP -.BR management-server-port -OpenVPN management port to connect to. -Use -.B unix -for -.I management-server-port -and socket path for -.I management-server-ip -to connect to a local unix socket. - -.TP -.BR password-file - -Password file containing the management password on first line. -The password will be used to connect to -.B openvpn -management interface. - -Pass -.I password-file -to -.B keychain-mcd -if -.I pw-file -was specified in -.B --management -option to -.B openvpn. - - -.SH AUTHOR - -Vasily Kulikov - -.SH "SEE ALSO" - -.BR openvpn (8) diff --git a/contrib/keychain-mcd/main.c b/contrib/keychain-mcd/main.c deleted file mode 100644 index c1d091ea6dc..00000000000 --- a/contrib/keychain-mcd/main.c +++ /dev/null @@ -1,310 +0,0 @@ -/* - * OpenVPN -- An application to securely tunnel IP networks - * over a single UDP port, with support for SSL/TLS-based - * session authentication and key exchange, - * packet encryption, packet authentication, and - * packet compression. - * - * Copyright (C) 2015 Vasily Kulikov - * - * 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; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "cert_data.h" -#include "crypto_osx.h" -#include "../../src/openvpn/base64.h" - - -SecIdentityRef -template_to_identity(const char *template) -{ - SecIdentityRef identity; - CertDataRef pCertDataTemplate = createCertDataFromString(template); - if (pCertDataTemplate == NULL) - { - errx(1, "Bad certificate template"); - } - identity = findIdentity(pCertDataTemplate); - if (identity == NULL) - { - errx(1, "No such identify"); - } - fprintf(stderr, "Identity found\n"); - destroyCertData(pCertDataTemplate); - return identity; -} - -int -connect_to_management_server(const char *ip, const char *port) -{ - int fd; - struct sockaddr_un addr_un; - struct sockaddr *addr; - size_t addr_len; - - if (strcmp(port, "unix") == 0) - { - addr = (struct sockaddr *)&addr_un; - addr_len = sizeof(addr_un); - - addr_un.sun_family = AF_UNIX; - strncpy(addr_un.sun_path, ip, sizeof(addr_un.sun_path)); - fd = socket(AF_UNIX, SOCK_STREAM, 0); - } - else - { - int rv; - struct addrinfo *result; - struct addrinfo hints; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - - rv = getaddrinfo(ip, port, &hints, &result); - if (rv < 0) - { - errx(1, "getaddrinfo: %s", gai_strerror(rv)); - } - if (result == NULL) - { - errx(1, "getaddrinfo returned 0 addressed"); - } - - /* Use the first found address */ - fd = socket(result->ai_family, result->ai_socktype, result->ai_protocol); - addr = result->ai_addr; - addr_len = result->ai_addrlen; - } - if (fd < 0) - { - err(1, "socket"); - } - - if (connect(fd, addr, addr_len) < 0) - { - err(1, "connect"); - } - - return fd; -} - -int -is_prefix(const char *s, const char *prefix) -{ - return strncmp(s, prefix, strlen(prefix)) == 0; -} - -void -handle_rsasign(FILE *man_file, SecIdentityRef identity, const char *input) -{ - const char *input_b64 = strchr(input, ':') + 1; - char *input_binary; - int input_len; - char *output_binary; - size_t output_len; - char *output_b64; - - input_len = strlen(input_b64)*8/6 + 4; - input_binary = malloc(input_len); - input_len = openvpn_base64_decode(input_b64, input_binary, input_len); - if (input_len < 0) - { - errx(1, "openvpn_base64_decode: overflow"); - } - - output_len = 1024; - output_binary = malloc(output_len); - signData(identity, (const uint8_t *)input_binary, input_len, (uint8_t *)output_binary, &output_len); - if (output_len == 0) - { - errx(1, "handle_rsasign: failed to sign data"); - } - - openvpn_base64_encode(output_binary, output_len, &output_b64); - fprintf(man_file, "rsa-sig\n%s\nEND\n", output_b64); - free(output_b64); - free(input_binary); - free(output_binary); - - fprintf(stderr, "Handled RSA_SIGN command\n"); -} - -void -handle_needcertificate(FILE *man_file, SecIdentityRef identity) -{ - OSStatus status; - SecCertificateRef certificate = NULL; - CFDataRef data; - const unsigned char *cert; - size_t cert_len; - char *result_b64, *tmp_b64; - - status = SecIdentityCopyCertificate(identity, &certificate); - if (status != noErr) - { - const char *msg = GetMacOSStatusErrorString(status); - err(1, "SecIdentityCopyCertificate() failed: %s", msg); - } - - data = SecCertificateCopyData(certificate); - if (data == NULL) - { - err(1, "SecCertificateCopyData() returned NULL"); - } - - cert = CFDataGetBytePtr(data); - cert_len = CFDataGetLength(data); - - openvpn_base64_encode(cert, cert_len, &result_b64); -#if 0 - fprintf(stderr, "certificate %s\n", result_b64); -#endif - - fprintf(man_file, "certificate\n"); - fprintf(man_file, "-----BEGIN CERTIFICATE-----\n"); - tmp_b64 = result_b64; - while (strlen(tmp_b64) > 64) { - fprintf(man_file, "%.64s\n", tmp_b64); - tmp_b64 += 64; - } - if (*tmp_b64) - { - fprintf(man_file, "%s\n", tmp_b64); - } - fprintf(man_file, "-----END CERTIFICATE-----\n"); - fprintf(man_file, "END\n"); - - free(result_b64); - CFRelease(data); - CFRelease(certificate); - - fprintf(stderr, "Handled NEED 'cert' command\n"); -} - -void -management_loop(SecIdentityRef identity, int man_fd, const char *password) -{ - char *buffer = NULL; - size_t buffer_len = 0; - FILE *man = fdopen(man_fd, "w+"); - if (man == 0) - { - err(1, "fdopen"); - } - - if (password) - { - fprintf(man, "%s\n", password); - } - - while (1) { - if (getline(&buffer, &buffer_len, man) < 0) - { - err(1, "getline"); - } -#if 0 - fprintf(stderr, "M: %s", buffer); -#endif - - if (is_prefix(buffer, ">RSA_SIGN:")) - { - handle_rsasign(man, identity, buffer); - } - if (is_prefix(buffer, ">NEED-CERTIFICATE")) - { - if (!identity) - { - const char prefix[] = ">NEED-CERTIFICATE:macosx-keychain:"; - if (!is_prefix(buffer, prefix)) - { - errx(1, "No identity template is passed via command line and " \ - "NEED-CERTIFICATE management interface command " \ - "misses 'macosx-keychain' prefix."); - } - identity = template_to_identity(buffer+strlen(prefix)); - } - handle_needcertificate(man, identity); - } - if (is_prefix(buffer, ">FATAL")) - { - fprintf(stderr, "Fatal message from OpenVPN: %s\n", buffer+7); - } - if (is_prefix(buffer, ">INFO")) - { - fprintf(stderr, "INFO message from OpenVPN: %s\n", buffer+6); - } - } -} - -char * -read_password(const char *fname) -{ - char *password = NULL; - FILE *pwf = fopen(fname, "r"); - size_t n = 0; - - if (pwf == NULL) - { - errx(1, "fopen(%s) failed", fname); - } - if (getline(&password, &n, pwf) < 0) - { - err(1, "getline"); - } - fclose(pwf); - return password; -} - -int -main(int argc, char *argv[]) -{ - if (argc < 4) - { - err(1, "usage: %s []", argv[0]); - } - - char *identity_template = argv[1]; - char *s_ip = argv[2]; - char *s_port = argv[3]; - char *password = NULL; - int man_fd; - - if (argc > 4) - { - char *s_pw_file = argv[4]; - password = read_password(s_pw_file); - } - - SecIdentityRef identity = NULL; - if (strcmp(identity_template, "auto")) - { - identity = template_to_identity(identity_template); - } - man_fd = connect_to_management_server(s_ip, s_port); - fprintf(stderr, "Successfully connected to openvpn\n"); - - management_loop(identity, man_fd, password); -} From 4bd2f4ef5b765ede3df9ae77b16cbeed5b4f7963 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Tue, 25 Jul 2017 17:07:23 +0200 Subject: [PATCH 593/643] cleanup: Move init_random_seed() to where it is being used The init_random_seed() function is only used by the init_static() in init.c. As this function was pretty basic and it is only being called once, it was merged into init_static() instead of keeping it as a separate function. (I agree that calling functions often makes the code more readable, but I would rather see that as a part of cleaning up the whole init_static() function - in fact when moving all "unit tests" in init_static() to cmocka, it will not be too bad in the end.) Signed-off-by: David Sommerseth Acked-by: Steffan Karger Message-Id: <20170725150723.14919-1-davids@openvpn.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15136.html Signed-off-by: David Sommerseth (cherry picked from commit e74e3a4db891b3ace0a96461c597d86e87be06f0) --- src/openvpn/init.c | 17 +++++++++++++++-- src/openvpn/misc.c | 19 ------------------- src/openvpn/misc.h | 3 --- 3 files changed, 15 insertions(+), 24 deletions(-) diff --git a/src/openvpn/init.c b/src/openvpn/init.c index efe634f4eae..858614d3c0d 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -610,6 +610,7 @@ init_port_share(struct context *c) #endif /* if PORT_SHARE */ + bool init_static(void) { @@ -619,8 +620,20 @@ init_static(void) crypto_init_dmalloc(); #endif - init_random_seed(); /* init random() function, only used as - * source for weak random numbers */ + + /* + * Initialize random number seed. random() is only used + * when "weak" random numbers are acceptable. + * SSL library routines are always used when cryptographically + * strong random numbers are required. + */ + struct timeval tv; + if (!gettimeofday(&tv, NULL)) + { + const unsigned int seed = (unsigned int) tv.tv_sec ^ tv.tv_usec; + srandom(seed); + } + error_reset(); /* initialize error.c */ reset_check_status(); /* initialize status check code in socket.c */ diff --git a/src/openvpn/misc.c b/src/openvpn/misc.c index 8a76bba89c6..aff1bb2e53d 100644 --- a/src/openvpn/misc.c +++ b/src/openvpn/misc.c @@ -404,25 +404,6 @@ openvpn_popen(const struct argv *a, const struct env_set *es) -/* - * Initialize random number seed. random() is only used - * when "weak" random numbers are acceptable. - * OpenSSL routines are always used when cryptographically - * strong random numbers are required. - */ - -void -init_random_seed(void) -{ - struct timeval tv; - - if (!gettimeofday(&tv, NULL)) - { - const unsigned int seed = (unsigned int) tv.tv_sec ^ tv.tv_usec; - srandom(seed); - } -} - /* * Set environmental variable (int or string). * diff --git a/src/openvpn/misc.h b/src/openvpn/misc.h index 734e679c5ed..a7aa7622af3 100644 --- a/src/openvpn/misc.h +++ b/src/openvpn/misc.h @@ -100,9 +100,6 @@ void set_std_files_to_null(bool stdin_only); extern int inetd_socket_descriptor; void save_inetd_socket_descriptor(void); -/* init random() function, only used as source for weak random numbers, when !ENABLE_CRYPTO */ -void init_random_seed(void); - /* set/delete environmental variable */ void setenv_str_ex(struct env_set *es, const char *name, From 14f67c3c9091c4adf903c25eb88c0b281fa3b15f Mon Sep 17 00:00:00 2001 From: Ilya Shipitsin Date: Mon, 7 Aug 2017 18:23:00 +0500 Subject: [PATCH 594/643] travis-ci: update openssl to 1.0.2l, update mbedtls to 2.5.1 Acked-by: Steffan Karger Message-Id: <20170807132301.22759-2-chipitsine@gmail.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15171.html Signed-off-by: David Sommerseth (cherry picked from commit 4a9306255cf0e1cc056e66ed4fa0f2e687c137f6) --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index db90e03a055..7d842b104df 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,10 +15,10 @@ env: - TAP_WINDOWS_VERSION=9.21.2 - LZO_VERSION=2.10 - PKCS11_HELPER_VERSION=1.11 - - MBEDTLS_VERSION="2.4.0" + - MBEDTLS_VERSION="2.5.1" - MBEDTLS_CFLAGS="-I${PREFIX}/include" - MBEDTLS_LIBS="-L${PREFIX}/lib -lmbedtls -lmbedx509 -lmbedcrypto" - - OPENSSL_VERSION="1.0.2k" + - OPENSSL_VERSION="1.0.2l" - OPENSSL_CFLAGS="-I${PREFIX}/include" - OPENSSL_LIBS="-L${PREFIX}/lib -lssl -lcrypto" From 9fffbfd094203126d2c7b8039762cd258c36631e Mon Sep 17 00:00:00 2001 From: Ilya Shipitsin Date: Wed, 9 Aug 2017 13:12:19 +0500 Subject: [PATCH 595/643] travis-ci: update pkcs11-helper to 1.22 use pkcs11-helper from https://github.com/OpenSC/pkcs11-helper/ to match build process used in windows installer build Signed-off-by: Ilya Shipitsin Acked-by: Steffan Karger Message-Id: <20170809081219.10367-1-chipitsine@gmail.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15187.html Signed-off-by: David Sommerseth (cherry picked from commit 28dba48541f5b212c7510ab3b0776dc39044502a) --- .travis.yml | 2 +- .travis/build-deps.sh | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7d842b104df..0b53152904b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,7 @@ env: - PREFIX="${HOME}/opt" - TAP_WINDOWS_VERSION=9.21.2 - LZO_VERSION=2.10 - - PKCS11_HELPER_VERSION=1.11 + - PKCS11_HELPER_VERSION=1.22 - MBEDTLS_VERSION="2.5.1" - MBEDTLS_CFLAGS="-I${PREFIX}/include" - MBEDTLS_LIBS="-L${PREFIX}/lib -lmbedtls -lmbedx509 -lmbedcrypto" diff --git a/.travis/build-deps.sh b/.travis/build-deps.sh index 9cc18584f73..e787ababa3f 100755 --- a/.travis/build-deps.sh +++ b/.travis/build-deps.sh @@ -35,7 +35,7 @@ build_lzo () { download_pkcs11_helper () { if [ ! -f "pkcs11-helper-${PKCS11_HELPER_VERSION}.tar.bz2" ]; then wget -P download-cache/ \ - "http://downloads.sourceforge.net/project/opensc/pkcs11-helper/pkcs11-helper-${PKCS11_HELPER_VERSION}.tar.bz2" + "https://github.com/OpenSC/pkcs11-helper/releases/download/pkcs11-helper-${PKCS11_HELPER_VERSION}/pkcs11-helper-${PKCS11_HELPER_VERSION}.tar.bz2" fi } @@ -46,7 +46,11 @@ build_pkcs11_helper () { cd "pkcs11-helper-${PKCS11_HELPER_VERSION}" ./configure --host=${CHOST} --program-prefix='' --libdir=${PREFIX}/lib \ - --prefix=${PREFIX} --build=x86_64-pc-linux-gnu --disable-crypto-engine-gnutls --disable-crypto-engine-nss + --prefix=${PREFIX} --build=x86_64-pc-linux-gnu \ + --disable-crypto-engine-gnutls \ + --disable-crypto-engine-nss \ + --disable-crypto-engine-polarssl \ + --disable-crypto-engine-mbedtls make all install ) echo "${PKCS11_HELPER_VERSION}" > "${PREFIX}/.pkcs11_helper-version" From a0ee61b31ced8c49ed3926adaf8c42dca4702b49 Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Wed, 9 Aug 2017 15:42:37 +0800 Subject: [PATCH 596/643] OpenSSL: remove unreachable call to SSL_CTX_get0_privatekey() In tls_ctx_load_ecdh_params() the SSL_CTX_get0_privatekey() function is invoked only when "OPENSSL_VERSION_NUMBER >= 0x10002000L" and curve_name is NULL. However, under the very same conditions the code flow will lead to an earlier return, thus never reaching the invocation of SSL_CTX_get0_privatekey(). Restructure the surrounding code in order to make the if/else block a bit easier to read and get rid of the unreachable invocation. Signed-off-by: Antonio Quartulli Acked-by: Steffan Karger Message-Id: <20170809074237.31291-1-a@unstable.cc> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15186.html Signed-off-by: David Sommerseth (cherry picked from commit 5b004f99d069fe0238aacbb0b3288872a4d7ae17) --- src/openvpn/ssl_openssl.c | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c index 0ac60357c2b..c60983416a2 100644 --- a/src/openvpn/ssl_openssl.c +++ b/src/openvpn/ssl_openssl.c @@ -487,15 +487,7 @@ tls_ctx_load_ecdh_params(struct tls_root_ctx *ctx, const char *curve_name /* Generate a new ECDH key for each SSL session (for non-ephemeral ECDH) */ SSL_CTX_set_options(ctx->ctx, SSL_OP_SINGLE_ECDH_USE); -#if OPENSSL_VERSION_NUMBER >= 0x10002000L - /* OpenSSL 1.0.2 and newer can automatically handle ECDH parameter loading */ - if (NULL == curve_name) - { - SSL_CTX_set_ecdh_auto(ctx->ctx, 1); - return; - } -#endif - /* For older OpenSSL, we'll have to do the parameter loading on our own */ + if (curve_name != NULL) { /* Use user supplied curve if given */ @@ -504,14 +496,17 @@ tls_ctx_load_ecdh_params(struct tls_root_ctx *ctx, const char *curve_name } else { - /* Extract curve from key */ +#if OPENSSL_VERSION_NUMBER >= 0x10002000L + /* OpenSSL 1.0.2 and newer can automatically handle ECDH parameter + * loading */ + SSL_CTX_set_ecdh_auto(ctx->ctx, 1); + return; +#else + /* For older OpenSSL we have to extract the curve from key on our own */ EC_KEY *eckey = NULL; const EC_GROUP *ecgrp = NULL; EVP_PKEY *pkey = NULL; -#if OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(LIBRESSL_VERSION_NUMBER) - pkey = SSL_CTX_get0_privatekey(ctx->ctx); -#else /* Little hack to get private key ref from SSL_CTX, yay OpenSSL... */ SSL *ssl = SSL_new(ctx->ctx); if (!ssl) @@ -520,7 +515,6 @@ tls_ctx_load_ecdh_params(struct tls_root_ctx *ctx, const char *curve_name } pkey = SSL_get_privatekey(ssl); SSL_free(ssl); -#endif msg(D_TLS_DEBUG, "Extracting ECDH curve from private key"); @@ -529,6 +523,7 @@ tls_ctx_load_ecdh_params(struct tls_root_ctx *ctx, const char *curve_name { nid = EC_GROUP_get_curve_name(ecgrp); } +#endif } /* Translate NID back to name , just for kicks */ From b5d7474822c89ff18d1005d4e90064051f160ce4 Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Fri, 11 Aug 2017 17:07:40 +0800 Subject: [PATCH 597/643] make function declarations C99 compliant In the attempt of adhering to the C99 standard as much as possible, ensure that all the function declarations with no parameter contain the "void" keyword[1]. Defects identified with sparse[2]. [1] ISO/IEC 9899:1999 spec, TC3 - section 6.7.5.3 [1] https://sparse.wiki.kernel.org/index.php/Main_Page Signed-off-by: Antonio Quartulli Acked-by: Steffan Karger Message-Id: <20170811090744.31750-2-a@unstable.cc> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15203.html Signed-off-by: David Sommerseth (cherry picked from commit e2a0cad46e8f98399387c334fec912b7bb7097fc) --- src/openvpn/buffer.c | 2 +- src/openvpn/console.c | 2 +- src/openvpn/console.h | 8 ++++---- src/openvpn/console_builtin.c | 2 +- src/openvpn/console_systemd.c | 4 ++-- src/openvpn/crypto.c | 4 ++-- src/openvpn/crypto.h | 2 +- src/openvpn/crypto_mbedtls.c | 10 +++++----- src/openvpn/crypto_mbedtls.h | 4 ++-- src/openvpn/crypto_openssl.c | 6 +++--- src/openvpn/error.c | 6 +++--- src/openvpn/error.h | 2 +- src/openvpn/init.c | 2 +- src/openvpn/interval.h | 2 +- src/openvpn/manage.c | 2 +- src/openvpn/occ-inline.h | 2 +- src/openvpn/packet_id.c | 2 +- src/openvpn/packet_id.h | 2 +- src/openvpn/pkcs11.c | 6 +++--- src/openvpn/platform.c | 2 +- src/openvpn/ps.c | 2 +- src/openvpn/ssl.c | 4 ++-- src/openvpn/ssl_backend.h | 6 +++--- src/openvpn/ssl_mbedtls.c | 6 +++--- src/openvpn/ssl_openssl.c | 12 ++++++------ src/openvpn/win32.c | 6 +++--- src/openvpn/win32.h | 4 ++-- 27 files changed, 56 insertions(+), 56 deletions(-) diff --git a/src/openvpn/buffer.c b/src/openvpn/buffer.c index 87e27ec0a9d..a63ce14a42d 100644 --- a/src/openvpn/buffer.c +++ b/src/openvpn/buffer.c @@ -180,7 +180,7 @@ buf_assign(struct buffer *dest, const struct buffer *src) } struct buffer -clear_buf() +clear_buf(void) { struct buffer buf; CLEAR(buf); diff --git a/src/openvpn/console.c b/src/openvpn/console.c index eb6944d0ea6..7e1702416f6 100644 --- a/src/openvpn/console.c +++ b/src/openvpn/console.c @@ -44,7 +44,7 @@ struct _query_user query_user[QUERY_USER_NUMSLOTS]; /* GLOBAL */ void -query_user_clear() +query_user_clear(void) { int i; diff --git a/src/openvpn/console.h b/src/openvpn/console.h index aa51e6f6874..3f74e77e7bb 100644 --- a/src/openvpn/console.h +++ b/src/openvpn/console.h @@ -46,7 +46,7 @@ extern struct _query_user query_user[]; /**< Global variable, declared in conso * Wipes all data put into all of the query_user structs * */ -void query_user_clear(); +void query_user_clear(void); /** @@ -72,7 +72,7 @@ void query_user_add(char *prompt, size_t prompt_len, * * @return True if executing all the defined steps completed successfully */ -bool query_user_exec_builtin(); +bool query_user_exec_builtin(void); #if defined(ENABLE_SYSTEMD) @@ -83,7 +83,7 @@ bool query_user_exec_builtin(); * * @return True if executing all the defined steps completed successfully */ -bool query_user_exec(); +bool query_user_exec(void); #else /* ENABLE_SYSTEMD not defined*/ /** @@ -92,7 +92,7 @@ bool query_user_exec(); * */ static bool -query_user_exec() +query_user_exec(void) { return query_user_exec_builtin(); } diff --git a/src/openvpn/console_builtin.c b/src/openvpn/console_builtin.c index 7b95da9dd94..f005ed748de 100644 --- a/src/openvpn/console_builtin.c +++ b/src/openvpn/console_builtin.c @@ -267,7 +267,7 @@ get_console_input(const char *prompt, const bool echo, char *input, const int ca * */ bool -query_user_exec_builtin() +query_user_exec_builtin(void) { bool ret = true; /* Presume everything goes okay */ int i; diff --git a/src/openvpn/console_systemd.c b/src/openvpn/console_systemd.c index 8cee8c8ed54..e7a72ae3840 100644 --- a/src/openvpn/console_systemd.c +++ b/src/openvpn/console_systemd.c @@ -41,7 +41,7 @@ */ static bool -check_systemd_running() +check_systemd_running(void) { struct stat c; @@ -95,7 +95,7 @@ get_console_input_systemd(const char *prompt, const bool echo, char *input, cons * */ bool -query_user_exec() +query_user_exec(void) { bool ret = true; /* Presume everything goes okay */ int i; diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c index db0265c2d94..fbc73442d53 100644 --- a/src/openvpn/crypto.c +++ b/src/openvpn/crypto.c @@ -1716,7 +1716,7 @@ static int nonce_secret_len = 0; /* GLOBAL */ /* Reset the nonce value, also done periodically to refresh entropy */ static void -prng_reset_nonce() +prng_reset_nonce(void) { const int size = md_kt_size(nonce_md) + nonce_secret_len; #if 1 /* Must be 1 for real usage */ @@ -1795,7 +1795,7 @@ prng_bytes(uint8_t *output, int len) /* an analogue to the random() function, but use prng_bytes */ long int -get_random() +get_random(void) { long int l; prng_bytes((unsigned char *)&l, sizeof(l)); diff --git a/src/openvpn/crypto.h b/src/openvpn/crypto.h index 8818c010cc8..501d96783bb 100644 --- a/src/openvpn/crypto.h +++ b/src/openvpn/crypto.h @@ -459,7 +459,7 @@ void prng_init(const char *md_name, const int nonce_secret_len_parm); */ void prng_bytes(uint8_t *output, int len); -void prng_uninit(); +void prng_uninit(void); void test_crypto(struct crypto_options *co, struct frame *f); diff --git a/src/openvpn/crypto_mbedtls.c b/src/openvpn/crypto_mbedtls.c index 24bc3158f21..0cb7f81151d 100644 --- a/src/openvpn/crypto_mbedtls.c +++ b/src/openvpn/crypto_mbedtls.c @@ -159,7 +159,7 @@ print_cipher(const cipher_kt_t *info) } void -show_available_ciphers() +show_available_ciphers(void) { const int *ciphers = mbedtls_cipher_list(); @@ -196,7 +196,7 @@ show_available_ciphers() } void -show_available_digests() +show_available_digests(void) { const int *digests = mbedtls_md_list(); @@ -223,7 +223,7 @@ show_available_digests() } void -show_available_engines() +show_available_engines(void) { printf("Sorry, mbed TLS hardware crypto engine functionality is not " "available\n"); @@ -243,7 +243,7 @@ show_available_engines() * entropy gathering function. */ mbedtls_ctr_drbg_context * -rand_ctx_get() +rand_ctx_get(void) { static mbedtls_entropy_context ec = {0}; static mbedtls_ctr_drbg_context cd_ctx = {0}; @@ -280,7 +280,7 @@ rand_ctx_get() #ifdef ENABLE_PREDICTION_RESISTANCE void -rand_ctx_enable_prediction_resistance() +rand_ctx_enable_prediction_resistance(void) { mbedtls_ctr_drbg_context *cd_ctx = rand_ctx_get(); diff --git a/src/openvpn/crypto_mbedtls.h b/src/openvpn/crypto_mbedtls.h index a434ce3489a..4417b9240e1 100644 --- a/src/openvpn/crypto_mbedtls.h +++ b/src/openvpn/crypto_mbedtls.h @@ -85,13 +85,13 @@ typedef mbedtls_md_context_t hmac_ctx_t; * added. During initialisation, a personalisation string will be added based * on the time, the PID, and a pointer to the random context. */ -mbedtls_ctr_drbg_context *rand_ctx_get(); +mbedtls_ctr_drbg_context *rand_ctx_get(void); #ifdef ENABLE_PREDICTION_RESISTANCE /** * Enable prediction resistance on the random number generator. */ -void rand_ctx_enable_prediction_resistance(); +void rand_ctx_enable_prediction_resistance(void); #endif diff --git a/src/openvpn/crypto_openssl.c b/src/openvpn/crypto_openssl.c index 9cf3355b77c..9e8d3f3e1f2 100644 --- a/src/openvpn/crypto_openssl.c +++ b/src/openvpn/crypto_openssl.c @@ -280,7 +280,7 @@ print_cipher(const EVP_CIPHER *cipher) } void -show_available_ciphers() +show_available_ciphers(void) { int nid; size_t i; @@ -339,7 +339,7 @@ show_available_ciphers() } void -show_available_digests() +show_available_digests(void) { int nid; @@ -364,7 +364,7 @@ show_available_digests() } void -show_available_engines() +show_available_engines(void) { #if HAVE_OPENSSL_ENGINE /* Only defined for OpenSSL */ ENGINE *e; diff --git a/src/openvpn/error.c b/src/openvpn/error.c index 3817666b659..04bf0da5f85 100644 --- a/src/openvpn/error.c +++ b/src/openvpn/error.c @@ -159,7 +159,7 @@ set_machine_readable_output(bool parsable) } void -error_reset() +error_reset(void) { use_syslog = std_redir = false; suppress_timestamps = false; @@ -480,7 +480,7 @@ open_syslog(const char *pgmname, bool stdio_to_null) } void -close_syslog() +close_syslog(void) { #if SYSLOG_CAPABILITY if (use_syslog) @@ -635,7 +635,7 @@ unsigned int x_cs_verbose_level; /* GLOBAL */ unsigned int x_cs_err_delay_ms; /* GLOBAL */ void -reset_check_status() +reset_check_status(void) { x_cs_info_level = 0; x_cs_verbose_level = 0; diff --git a/src/openvpn/error.h b/src/openvpn/error.h index 14ef7e651b0..023cec463a2 100644 --- a/src/openvpn/error.h +++ b/src/openvpn/error.h @@ -261,7 +261,7 @@ void msg_forked(void); void open_syslog(const char *pgmname, bool stdio_to_null); -void close_syslog(); +void close_syslog(void); /* log file output */ void redirect_stdout_stderr(const char *file, bool append); diff --git a/src/openvpn/init.c b/src/openvpn/init.c index 858614d3c0d..a4fca504f3b 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -1917,7 +1917,7 @@ do_close_tun(struct context *c, bool force) } void -tun_abort() +tun_abort(void) { struct context *c = static_context; if (c) diff --git a/src/openvpn/interval.h b/src/openvpn/interval.h index 8095c0b9707..dd5dfbc8e5e 100644 --- a/src/openvpn/interval.h +++ b/src/openvpn/interval.h @@ -155,7 +155,7 @@ event_timeout_clear(struct event_timeout *et) } static inline struct event_timeout -event_timeout_clear_ret() +event_timeout_clear_ret(void) { struct event_timeout ret; event_timeout_clear(&ret); diff --git a/src/openvpn/manage.c b/src/openvpn/manage.c index ff94824044e..3bbe972e5aa 100644 --- a/src/openvpn/manage.c +++ b/src/openvpn/manage.c @@ -68,7 +68,7 @@ static void man_output_standalone(struct management *man, volatile int *signal_r static void man_reset_client_socket(struct management *man, const bool exiting); static void -man_help() +man_help(void) { msg(M_CLIENT, "Management Interface for %s", title_string); msg(M_CLIENT, "Commands:"); diff --git a/src/openvpn/occ-inline.h b/src/openvpn/occ-inline.h index 68e9098f29b..0fa8e5ba03b 100644 --- a/src/openvpn/occ-inline.h +++ b/src/openvpn/occ-inline.h @@ -31,7 +31,7 @@ */ static inline int -occ_reset_op() +occ_reset_op(void) { return -1; } diff --git a/src/openvpn/packet_id.c b/src/openvpn/packet_id.c index 30ae8fbcbdd..a3ff5722e1c 100644 --- a/src/openvpn/packet_id.c +++ b/src/openvpn/packet_id.c @@ -643,7 +643,7 @@ packet_id_debug_print(int msglevel, #ifdef PID_TEST void -packet_id_interactive_test() +packet_id_interactive_test(void) { struct packet_id pid; struct packet_id_net pin; diff --git a/src/openvpn/packet_id.h b/src/openvpn/packet_id.h index a370936cd6c..8509e5903b4 100644 --- a/src/openvpn/packet_id.h +++ b/src/openvpn/packet_id.h @@ -299,7 +299,7 @@ packet_id_persist_save_obj(struct packet_id_persist *p, const struct packet_id * const char *packet_id_net_print(const struct packet_id_net *pin, bool print_timestamp, struct gc_arena *gc); #ifdef PID_TEST -void packet_id_interactive_test(); +void packet_id_interactive_test(void); #endif diff --git a/src/openvpn/pkcs11.c b/src/openvpn/pkcs11.c index 60418280799..a0d0906aeaa 100644 --- a/src/openvpn/pkcs11.c +++ b/src/openvpn/pkcs11.c @@ -356,7 +356,7 @@ pkcs11_initialize( } void -pkcs11_terminate() +pkcs11_terminate(void) { dmsg( D_PKCS11_DEBUG, @@ -422,13 +422,13 @@ pkcs11_addProvider( } int -pkcs11_logout() +pkcs11_logout(void) { return pkcs11h_logout() == CKR_OK; } int -pkcs11_management_id_count() +pkcs11_management_id_count(void) { pkcs11h_certificate_id_list_t id_list = NULL; pkcs11h_certificate_id_list_t t = NULL; diff --git a/src/openvpn/platform.c b/src/openvpn/platform.c index d936890e9e6..e942ba94a74 100644 --- a/src/openvpn/platform.c +++ b/src/openvpn/platform.c @@ -173,7 +173,7 @@ platform_nice(int niceval) /* Get current PID */ unsigned int -platform_getpid() +platform_getpid(void) { #ifdef _WIN32 return (unsigned int) GetCurrentProcessId(); diff --git a/src/openvpn/ps.c b/src/openvpn/ps.c index c2b05cd9518..45e24ded8fd 100644 --- a/src/openvpn/ps.c +++ b/src/openvpn/ps.c @@ -172,7 +172,7 @@ send_control(const socket_descriptor_t fd, int code) } static int -cmsg_size() +cmsg_size(void) { return CMSG_SPACE(sizeof(socket_descriptor_t)); } diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index cad9ce73715..cfc53a705aa 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -347,7 +347,7 @@ tls_init_control_channel_frame_parameters(const struct frame *data_channel_frame } void -init_ssl_lib() +init_ssl_lib(void) { tls_init_lib(); @@ -355,7 +355,7 @@ init_ssl_lib() } void -free_ssl_lib() +free_ssl_lib(void) { crypto_uninit_lib(); prng_uninit(); diff --git a/src/openvpn/ssl_backend.h b/src/openvpn/ssl_backend.h index a738f0f497d..aba5a4deec5 100644 --- a/src/openvpn/ssl_backend.h +++ b/src/openvpn/ssl_backend.h @@ -88,17 +88,17 @@ int pem_password_callback(char *buf, int size, int rwflag, void *u); * Perform any static initialisation necessary by the library. * Called on OpenVPN initialisation */ -void tls_init_lib(); +void tls_init_lib(void); /** * Free any global SSL library-specific data structures. */ -void tls_free_lib(); +void tls_free_lib(void); /** * Clear the underlying SSL library's error state. */ -void tls_clear_error(); +void tls_clear_error(void); /** * Parse a TLS version specifier diff --git a/src/openvpn/ssl_mbedtls.c b/src/openvpn/ssl_mbedtls.c index ef583e67991..861d936dbd4 100644 --- a/src/openvpn/ssl_mbedtls.c +++ b/src/openvpn/ssl_mbedtls.c @@ -63,17 +63,17 @@ #include void -tls_init_lib() +tls_init_lib(void) { } void -tls_free_lib() +tls_free_lib(void) { } void -tls_clear_error() +tls_clear_error(void) { } diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c index c60983416a2..a911b7c3af1 100644 --- a/src/openvpn/ssl_openssl.c +++ b/src/openvpn/ssl_openssl.c @@ -69,7 +69,7 @@ int mydata_index; /* GLOBAL */ void -tls_init_lib() +tls_init_lib(void) { SSL_library_init(); #ifndef ENABLE_SMALL @@ -82,7 +82,7 @@ tls_init_lib() } void -tls_free_lib() +tls_free_lib(void) { EVP_cleanup(); #ifndef ENABLE_SMALL @@ -91,7 +91,7 @@ tls_free_lib() } void -tls_clear_error() +tls_clear_error(void) { ERR_clear_error(); } @@ -1332,7 +1332,7 @@ static time_t biofp_last_open; /* GLOBAL */ static const int biofp_reopen_interval = 600; /* GLOBAL */ static void -close_biofp() +close_biofp(void) { if (biofp) { @@ -1342,7 +1342,7 @@ close_biofp() } static void -open_biofp() +open_biofp(void) { const time_t current = time(NULL); const pid_t pid = getpid(); @@ -1778,7 +1778,7 @@ show_available_tls_ciphers(const char *cipher_list) * in the OpenSSL library. */ void -show_available_curves() +show_available_curves(void) { #ifndef OPENSSL_NO_EC EC_builtin_curve *curves = NULL; diff --git a/src/openvpn/win32.c b/src/openvpn/win32.c index d0b10bad517..95fea5dffae 100644 --- a/src/openvpn/win32.c +++ b/src/openvpn/win32.c @@ -1235,7 +1235,7 @@ set_win_sys_path_via_env(struct env_set *es) const char * -win_get_tempdir() +win_get_tempdir(void) { static char tmpdir[MAX_PATH]; WCHAR wtmpdir[MAX_PATH]; @@ -1398,7 +1398,7 @@ win_wfp_uninit(const NET_IFINDEX index, const HANDLE msg_channel) } int -win32_version_info() +win32_version_info(void) { if (!IsWindowsXPOrGreater()) { @@ -1426,7 +1426,7 @@ win32_version_info() } bool -win32_is_64bit() +win32_is_64bit(void) { #if defined(_WIN64) return true; /* 64-bit programs run only on Win64 */ diff --git a/src/openvpn/win32.h b/src/openvpn/win32.h index 21a1021a1b4..7fc57ccc408 100644 --- a/src/openvpn/win32.h +++ b/src/openvpn/win32.h @@ -285,7 +285,7 @@ char *get_win_sys_path(void); void fork_to_self(const char *cmdline); /* Find temporary directory */ -const char *win_get_tempdir(); +const char *win_get_tempdir(void); /* Convert a string from UTF-8 to UCS-2 */ WCHAR *wide_string(const char *utf8, struct gc_arena *gc); @@ -299,7 +299,7 @@ bool win_wfp_uninit(const NET_IFINDEX index, const HANDLE msg_channel); #define WIN_7 2 #define WIN_8 3 -int win32_version_info(); +int win32_version_info(void); /* * String representation of Windows version number and name, see From e096613927ee814c8e4ecb1219cfe2ece9bf26bc Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Fri, 11 Aug 2017 17:07:43 +0800 Subject: [PATCH 598/643] remove unused functions Signed-off-by: Antonio Quartulli Acked-by: Steffan Karger Message-Id: <20170811090744.31750-5-a@unstable.cc> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15205.html Signed-off-by: David Sommerseth (cherry picked from commit 4158f46f6474447520ebc7440050411eb8be8cb9) --- src/openvpn/misc.c | 23 ----------------------- src/openvpn/ssl.c | 10 ---------- src/openvpn/ssl_openssl.c | 6 ------ 3 files changed, 39 deletions(-) diff --git a/src/openvpn/misc.c b/src/openvpn/misc.c index aff1bb2e53d..0adb164e49a 100644 --- a/src/openvpn/misc.c +++ b/src/openvpn/misc.c @@ -429,29 +429,6 @@ construct_name_value(const char *name, const char *value, struct gc_arena *gc) return BSTR(&out); } -bool -deconstruct_name_value(const char *str, const char **name, const char **value, struct gc_arena *gc) -{ - char *cp; - - ASSERT(str); - ASSERT(name && value); - - *name = cp = string_alloc(str, gc); - *value = NULL; - - while ((*cp)) - { - if (*cp == '=' && !*value) - { - *cp = 0; - *value = cp + 1; - } - ++cp; - } - return *name && *value; -} - static bool env_string_equal(const char *s1, const char *s2) { diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index cfc53a705aa..e431541690a 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -2190,16 +2190,6 @@ read_string_alloc(struct buffer *buf) return str; } -void -read_string_discard(struct buffer *buf) -{ - char *data = read_string_alloc(buf); - if (data) - { - free(data); - } -} - /* * Handle the reading and writing of key data to and from * the TLS control channel (cleartext). diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c index a911b7c3af1..fef85c950b2 100644 --- a/src/openvpn/ssl_openssl.c +++ b/src/openvpn/ssl_openssl.c @@ -806,12 +806,6 @@ tls_ctx_load_cert_file(struct tls_root_ctx *ctx, const char *cert_file, tls_ctx_load_cert_file_and_copy(ctx, cert_file, cert_file_inline, NULL); } -void -tls_ctx_free_cert_file(X509 *x509) -{ - X509_free(x509); -} - int tls_ctx_load_priv_file(struct tls_root_ctx *ctx, const char *priv_key_file, const char *priv_key_file_inline From a5c2cb6046e7e23554b7bd71a52079b559129e0d Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Fri, 11 Aug 2017 17:07:44 +0800 Subject: [PATCH 599/643] use NULL instead of 0 when assigning pointers Signed-off-by: Antonio Quartulli Acked-by: Gert Doering Message-Id: <20170811090744.31750-6-a@unstable.cc> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15204.html Signed-off-by: David Sommerseth (cherry picked from commit 280150a02a117eb0cc9c34e69ebe9ec3f4ded0f4) --- src/openvpn/ps.c | 2 +- src/openvpn/ssl_openssl.c | 2 +- src/openvpn/ssl_verify_openssl.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/openvpn/ps.c b/src/openvpn/ps.c index 45e24ded8fd..5136a20c58e 100644 --- a/src/openvpn/ps.c +++ b/src/openvpn/ps.c @@ -922,7 +922,7 @@ port_share_open(const char *host, openvpn_close_socket(fd[1]); exit(0); - return 0; /* NOTREACHED */ + return NULL; /* NOTREACHED */ } error: diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c index fef85c950b2..c8356aca775 100644 --- a/src/openvpn/ssl_openssl.c +++ b/src/openvpn/ssl_openssl.c @@ -708,7 +708,7 @@ tls_ctx_add_extra_certs(struct tls_root_ctx *ctx, BIO *bio) for (;; ) { cert = NULL; - if (!PEM_read_bio_X509(bio, &cert, 0, NULL)) /* takes ownership of cert */ + if (!PEM_read_bio_X509(bio, &cert, NULL, NULL)) /* takes ownership of cert */ { break; } diff --git a/src/openvpn/ssl_verify_openssl.c b/src/openvpn/ssl_verify_openssl.c index d3e3ca02d24..95b08e0a4df 100644 --- a/src/openvpn/ssl_verify_openssl.c +++ b/src/openvpn/ssl_verify_openssl.c @@ -202,8 +202,8 @@ extract_x509_field_ssl(X509_NAME *x509, const char *field_name, char *out, { int lastpos = -1; int tmp = -1; - X509_NAME_ENTRY *x509ne = 0; - ASN1_STRING *asn1 = 0; + X509_NAME_ENTRY *x509ne = NULL; + ASN1_STRING *asn1 = NULL; unsigned char *buf = NULL; ASN1_OBJECT *field_name_obj = OBJ_txt2obj(field_name, 0); From d1e18d89d9ff4ce946f27d5b019c407bf750fe4b Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Fri, 11 Aug 2017 17:07:42 +0800 Subject: [PATCH 600/643] add missing static attribute to functions Functions used only in the file where they are defined and not exported in any header, should always defined as static in order to make the scope clear to the compiler and the developers. Add the static attribute where missing. Signed-off-by: Antonio Quartulli Acked-by: Steffan Karger Message-Id: <20170811090744.31750-4-a@unstable.cc> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15202.html Signed-off-by: David Sommerseth (cherry picked from commit 72bcdfdc19243c1ed6cb8568f62f0c35e8b70f5f) --- src/openvpn/comp-lz4.c | 2 +- src/openvpn/forward.c | 2 +- src/openvpn/manage.c | 6 +++--- src/openvpn/mtcp.c | 2 +- src/openvpn/multi.c | 4 ++-- src/openvpn/ntlm.c | 2 +- src/openvpn/options.c | 8 ++++---- src/openvpn/proxy.c | 2 +- src/openvpn/route.c | 4 ++-- src/openvpn/socket.c | 2 +- src/openvpn/ssl.c | 2 +- 11 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/openvpn/comp-lz4.c b/src/openvpn/comp-lz4.c index 6e40c325cfd..e056caa8a8c 100644 --- a/src/openvpn/comp-lz4.c +++ b/src/openvpn/comp-lz4.c @@ -185,7 +185,7 @@ lz4v2_compress(struct buffer *buf, struct buffer work, } } -void +static void do_lz4_decompress(size_t zlen_max, struct buffer *work, struct buffer *buf, diff --git a/src/openvpn/forward.c b/src/openvpn/forward.c index c45d1259c43..6cc593838cb 100644 --- a/src/openvpn/forward.c +++ b/src/openvpn/forward.c @@ -1007,7 +1007,7 @@ process_incoming_link_part2(struct context *c, struct link_socket_info *lsi, con } } -void +static void process_incoming_link(struct context *c) { perf_push(PERF_PROC_IN_LINK); diff --git a/src/openvpn/manage.c b/src/openvpn/manage.c index 3bbe972e5aa..88121a38883 100644 --- a/src/openvpn/manage.c +++ b/src/openvpn/manage.c @@ -3515,7 +3515,7 @@ management_query_user_pass(struct management *man, #ifdef MANAGMENT_EXTERNAL_KEY -int +static int management_query_multiline(struct management *man, const char *b64_data, const char *prompt, const char *cmd, int *state, struct buffer_list **input) { @@ -3591,7 +3591,7 @@ management_query_multiline(struct management *man, return ret; } -char * +static char * /* returns allocated base64 signature */ management_query_multiline_flatten_newline(struct management *man, const char *b64_data, const char *prompt, const char *cmd, int *state, struct buffer_list **input) @@ -3620,7 +3620,7 @@ management_query_multiline_flatten_newline(struct management *man, return result; } -char * +static char * /* returns allocated base64 signature */ management_query_multiline_flatten(struct management *man, const char *b64_data, const char *prompt, const char *cmd, int *state, struct buffer_list **input) diff --git a/src/openvpn/mtcp.c b/src/openvpn/mtcp.c index 851643a99d4..3cb5211373e 100644 --- a/src/openvpn/mtcp.c +++ b/src/openvpn/mtcp.c @@ -521,7 +521,7 @@ multi_tcp_dispatch(struct multi_context *m, struct multi_instance *mi, const int return touched; } -int +static int multi_tcp_post(struct multi_context *m, struct multi_instance *mi, const int action) { struct context *c = multi_tcp_context(m, mi); diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index 7edfee1b136..c798c438519 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -485,7 +485,7 @@ multi_instance_string(const struct multi_instance *mi, bool null, struct gc_aren } } -void +static void generate_prefix(struct multi_instance *mi) { struct gc_arena gc = gc_new(); @@ -2967,7 +2967,7 @@ gremlin_flood_clients(struct multi_context *m) } #endif /* ifdef ENABLE_DEBUG */ -bool +static bool stale_route_check_trigger(struct multi_context *m) { struct timeval null; diff --git a/src/openvpn/ntlm.c b/src/openvpn/ntlm.c index 65c1cbf5d98..167c10b8042 100644 --- a/src/openvpn/ntlm.c +++ b/src/openvpn/ntlm.c @@ -131,7 +131,7 @@ gen_nonce(unsigned char *nonce) } } -void +static void my_strupr(char *str) { /* converts string to uppercase in place */ diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 2d9972f0104..6191e488883 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -961,7 +961,7 @@ pull_filter_type_name(int type) #endif -void +static void setenv_connection_entry(struct env_set *es, const struct connection_entry *e, const int i) @@ -1441,7 +1441,7 @@ rol_check_alloc(struct options *options) } } -void +static void rol6_check_alloc(struct options *options) { if (!options->routes_ipv6) @@ -1872,7 +1872,7 @@ parse_http_proxy_override(const char *server, } } -void +static void options_postprocess_http_proxy_override(struct options *o) { const struct connection_list *l = o->connection_list; @@ -1989,7 +1989,7 @@ alloc_pull_filter(struct options *o, const int msglevel) return f; } -void +static void connection_entry_load_re(struct connection_entry *ce, const struct remote_entry *re) { if (re->remote) diff --git a/src/openvpn/proxy.c b/src/openvpn/proxy.c index 7a737eae397..2e815039662 100644 --- a/src/openvpn/proxy.c +++ b/src/openvpn/proxy.c @@ -550,7 +550,7 @@ http_proxy_close(struct http_proxy_info *hp) free(hp); } -bool +static bool add_proxy_headers(struct http_proxy_info *p, socket_descriptor_t sd, /* already open to proxy */ const char *host, /* openvpn server remote */ diff --git a/src/openvpn/route.c b/src/openvpn/route.c index a8a4c66deaa..1d8bb001541 100644 --- a/src/openvpn/route.c +++ b/src/openvpn/route.c @@ -518,14 +518,14 @@ add_route_ipv6_to_option_list(struct route_ipv6_option_list *l, l->routes_ipv6 = ro; } -void +static void clear_route_list(struct route_list *rl) { gc_free(&rl->gc); CLEAR(*rl); } -void +static void clear_route_ipv6_list(struct route_ipv6_list *rl6) { gc_free(&rl6->gc); diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c index 6e01fe10959..3d4f881e67e 100644 --- a/src/openvpn/socket.c +++ b/src/openvpn/socket.c @@ -1431,7 +1431,7 @@ set_actual_address(struct link_socket_actual *actual, struct addrinfo *ai) } -void +static void socket_connect(socket_descriptor_t *sd, const struct sockaddr *dest, const int connect_timeout, diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index e431541690a..e783fd1b8bb 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -1607,7 +1607,7 @@ key_source2_print(const struct key_source2 *k) * @param out Output buffer * @param olen Length of the output buffer */ -void +static void tls1_P_hash(const md_kt_t *md_kt, const uint8_t *sec, int sec_len, From 6f616aa6b7570db965b8eee1d8b8d182af4bb05f Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Thu, 20 Jul 2017 19:55:57 +0200 Subject: [PATCH 601/643] Always use default keysize for NCP'd ciphers If a peer has set --keysize, and NCP negotiates a cipher with a different key size (e.g. --keysize 128 + AES-256-GCM), that peer will exit with a "invalid key size" error. To prevent that, always set keysize=0 for NCP'd ciphers. Signed-off-by: Steffan Karger Acked-by: David Sommerseth Message-Id: <1500573357-20496-1-git-send-email-steffan@karger.me> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15110.html Signed-off-by: David Sommerseth (cherry picked from commit 956bb1c32fa40ee184919b3ce569c90643a01b5b) --- src/openvpn/ssl.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index e783fd1b8bb..1aad09d7890 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -1978,6 +1978,11 @@ tls_session_update_crypto_params(struct tls_session *session, { msg(D_HANDSHAKE, "Data Channel: using negotiated cipher '%s'", options->ciphername); + if (options->keysize) + { + msg(D_HANDSHAKE, "NCP: overriding user-set keysize with default"); + options->keysize = 0; + } } init_key_type(&session->opt->key_type, options->ciphername, From a91c38fbabf6f949990ef8a3801d56225a47a33f Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Tue, 25 Jul 2017 23:02:34 +0200 Subject: [PATCH 602/643] Move create_temp_file() out of #ifdef ENABLE_CRYPTO By using get_random() instead of prng_bytes(), we no longer have to place create_temp_file() inside #ifdef ENABLE_CRYPTO. The resulting filename now has 62 bits of entropy (2 * [0-INT_MAX]) instead of the previous 128 bits, but that should be plenty. Assuming an int is 32 bits, we would need about 2**31 (2147483648) files to have a (roughly) 0.5 chance of failing in one of the 6 attempts we do. (This is preparing to move the function out of misc.c, where I'd prefer to not have to add a #include "crypto.h".) Signed-off-by: Steffan Karger Acked-by: David Sommerseth Message-Id: <20170725210234.5673-1-steffan@karger.me> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15146.html Signed-off-by: David Sommerseth (cherry picked from commit cd5a74d0d7c6347b31e261e98ca8984819e594df) --- src/openvpn/misc.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/openvpn/misc.c b/src/openvpn/misc.c index 0adb164e49a..cd12f918622 100644 --- a/src/openvpn/misc.c +++ b/src/openvpn/misc.c @@ -808,8 +808,6 @@ test_file(const char *filename) return ret; } -#ifdef ENABLE_CRYPTO - /* create a temporary filename in directory */ const char * create_temp_file(const char *directory, const char *prefix, struct gc_arena *gc) @@ -822,15 +820,11 @@ create_temp_file(const char *directory, const char *prefix, struct gc_arena *gc) do { - uint8_t rndbytes[16]; - const char *rndstr; - ++attempts; ++counter; - prng_bytes(rndbytes, sizeof rndbytes); - rndstr = format_hex_ex(rndbytes, sizeof rndbytes, 40, 0, NULL, gc); - buf_printf(&fname, PACKAGE "_%s_%s.tmp", prefix, rndstr); + buf_printf(&fname, PACKAGE "_%s_%08lx%08lx.tmp", prefix, + (unsigned long) get_random(), (unsigned long) get_random()); retfname = gen_path(directory, BSTR(&fname), gc); if (!retfname) @@ -861,6 +855,8 @@ create_temp_file(const char *directory, const char *prefix, struct gc_arena *gc) return NULL; } +#ifdef ENABLE_CRYPTO + /* * Prepend a random string to hostname to prevent DNS caching. * For example, foo.bar.gov would be modified to .foo.bar.gov. From 9f390f0209aa119f7625a75ae309787bc6785831 Mon Sep 17 00:00:00 2001 From: Conrad Hoffmann Date: Wed, 2 Aug 2017 20:14:34 +0200 Subject: [PATCH 603/643] Use provided env vars in up/down script. This makes the down script work both as regular down script as well as with the down-root plugin. The up script is just changed for consistency. Signed-off-by: Conrad Hoffmann Acked-by: David Sommerseth Message-Id: <20170802181435.14549-2-ch@bitfehler.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15165.html Signed-off-by: David Sommerseth (cherry picked from commit 94c1ce22ebcc1f672bb80598afccc130aa01fafc) --- contrib/pull-resolv-conf/client.down | 2 +- contrib/pull-resolv-conf/client.up | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/contrib/pull-resolv-conf/client.down b/contrib/pull-resolv-conf/client.down index 05f2d4d5465..90bc5891ab2 100644 --- a/contrib/pull-resolv-conf/client.down +++ b/contrib/pull-resolv-conf/client.down @@ -37,7 +37,7 @@ PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/usr/local/sbin if type resolvconf >/dev/null 2>&1; then - resolvconf -d "${1}" -f + resolvconf -d "${dev}" -f elif [ -e /etc/resolv.conf.ovpnsave ] ; then # cp + rm rather than mv in case it's a symlink cp /etc/resolv.conf.ovpnsave /etc/resolv.conf diff --git a/contrib/pull-resolv-conf/client.up b/contrib/pull-resolv-conf/client.up index 8858b4766d9..260c038e9b1 100644 --- a/contrib/pull-resolv-conf/client.up +++ b/contrib/pull-resolv-conf/client.up @@ -87,11 +87,11 @@ elif [ $ndoms -gt 1 ]; then fi # This is the complete file - "$domains" has a leading space already -out="# resolv.conf autogenerated by ${0} (${1})${nl}${dns}${ds}${domains}" +out="# resolv.conf autogenerated by ${0} (${dev})${nl}${dns}${ds}${domains}" # use resolvconf if it's available if type resolvconf >/dev/null 2>&1; then - printf "%s\n" "${out}" | resolvconf -p -a "${1}" + printf "%s\n" "${out}" | resolvconf -p -a "${dev}" else # Preserve the existing resolv.conf if [ -e /etc/resolv.conf ] ; then From 597b6224e254775915956b8db45c090709b17b1a Mon Sep 17 00:00:00 2001 From: Conrad Hoffmann Date: Wed, 2 Aug 2017 20:14:35 +0200 Subject: [PATCH 604/643] Document down-root plugin usage in client.down Signed-off-by: Conrad Hoffmann Acked-by: David Sommerseth Message-Id: <20170802181435.14549-3-ch@bitfehler.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15164.html Signed-off-by: David Sommerseth (cherry picked from commit cbeff7b1b3f2815ee27f4479dca502c220fc4d15) --- contrib/pull-resolv-conf/client.down | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/contrib/pull-resolv-conf/client.down b/contrib/pull-resolv-conf/client.down index 90bc5891ab2..c9090b5650e 100644 --- a/contrib/pull-resolv-conf/client.down +++ b/contrib/pull-resolv-conf/client.down @@ -30,6 +30,10 @@ # the client "up" script will run fine, but the "down" script # will require the use of the OpenVPN "down-root" plugin # which is in the plugins/ directory of the OpenVPN source tree +# The config example above would have to be changed to: +# client +# up /etc/openvpn/client.up +# plugin openvpn-plugin-down-root.so "/etc/openvpn/client.down" # A horrid work around, from a security perspective, # is to run OpenVPN as root. THIS IS NOT RECOMMENDED. You have From 5ed5030c349326c5448fd87424c1a2283ccee18f Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Mon, 14 Aug 2017 15:19:37 +0200 Subject: [PATCH 605/643] sample-plugins: fix ASN1_STRING_to_UTF8 return value checks As we did in 2d032c7f for the ASN1_STRING_to_UTF8() calls in the core code, we should also free(buf) if the function returns 0. [DS: On-the-fly merge conflict fix: There was a conflict against the OpenSSL 0.9.6b workaround in v2.4. Since we no longer support anything older than OpenSSL 0.9.8 in release/2.4, whack that workaround and be more consistent with git master those two places] Signed-off-by: Steffan Karger Acked-by: David Sommerseth Message-Id: <1501238302-16714-1-git-send-email-steffan.karger@fox-it.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15161.html Signed-off-by: David Sommerseth (cherry picked from commit c43045ca0590364552fbd060cc65ee1c50a4866a) --- .../keying-material-exporter-demo/keyingmaterialexporter.c | 5 ++--- sample/sample-plugins/log/log_v3.c | 3 +-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/sample/sample-plugins/keying-material-exporter-demo/keyingmaterialexporter.c b/sample/sample-plugins/keying-material-exporter-demo/keyingmaterialexporter.c index 226eea6ac8d..c4839077b26 100644 --- a/sample/sample-plugins/keying-material-exporter-demo/keyingmaterialexporter.c +++ b/sample/sample-plugins/keying-material-exporter-demo/keyingmaterialexporter.c @@ -142,9 +142,8 @@ session_user_set(struct session *sess, X509 *x509) { continue; } - /* bug in OpenSSL 0.9.6b ASN1_STRING_to_UTF8 requires this workaround */ - unsigned char *buf = (unsigned char *)1; - if (ASN1_STRING_to_UTF8(&buf, val) <= 0) + unsigned char *buf = NULL; + if (ASN1_STRING_to_UTF8(&buf, val) < 0) { continue; } diff --git a/sample/sample-plugins/log/log_v3.c b/sample/sample-plugins/log/log_v3.c index 8b537dd7268..f913a19a783 100644 --- a/sample/sample-plugins/log/log_v3.c +++ b/sample/sample-plugins/log/log_v3.c @@ -227,8 +227,7 @@ x509_print_info(X509 *x509crt) { continue; } - buf = (unsigned char *)1; /* bug in OpenSSL 0.9.6b ASN1_STRING_to_UTF8 requires this workaround */ - if (ASN1_STRING_to_UTF8(&buf, val) <= 0) + if (ASN1_STRING_to_UTF8(&buf, val) < 0) { continue; } From e2ab4958528a352c3ddad02446c10814afe68f6b Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sat, 1 Jul 2017 13:29:51 +0200 Subject: [PATCH 606/643] Deprecate --keysize The --keysize option can only be used with already deprecated ciphers, such as CAST5, RC2 or BF. Deviating from the default keysize is generally not a good idea (see man page text), and otherwise only complicates our code. Since we will also remove the support for weak ciphers (ciphers with cipher block length less than 128 bits) in OpenVPN 2.6 as well, we start the deprecation of this option instantly. [DS: Slightly amended the patch, referencing OpenVPN 2.6 and added a few more details to Changes.rst and the commit message] Signed-off-by: Steffan Karger Acked-by: David Sommerseth Message-Id: <20170701112951.19119-1-steffan@karger.me> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15004.html Signed-off-by: David Sommerseth (cherry picked from commit ad178f01444d61e48fca83c4f0bc5d82270cee87) --- Changes.rst | 3 +++ doc/openvpn.8 | 3 +++ src/openvpn/options.c | 5 +++++ 3 files changed, 11 insertions(+) diff --git a/Changes.rst b/Changes.rst index d94b3fbff64..3d758f2ea80 100644 --- a/Changes.rst +++ b/Changes.rst @@ -178,6 +178,9 @@ Deprecated features - ``--no-iv`` is deprecated in 2.4 and will be removed in 2.5. +- ``--keysize`` is deprecated and will be removed in v2.6 together + with the support of ciphers with cipher block size less than 128 bits. + User-visible Changes -------------------- diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 56c0f7a6943..8170164b02e 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -4218,6 +4218,9 @@ negotiation. .\"********************************************************* .TP .B \-\-keysize n +.B DEPRECATED +This option will be removed in OpenVPN 2.6. + Size of cipher key in bits (optional). If unspecified, defaults to cipher-specific default. The .B \-\-show\-ciphers diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 6191e488883..2b096eb036d 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -2495,6 +2495,11 @@ options_postprocess_verify_ce(const struct options *options, const struct connec msg(M_WARN, "WARNING: --no-iv is deprecated and will be removed in 2.5"); } + if (options->keysize) + { + msg(M_WARN, "WARNING: --keysize is DEPRECATED and will be removed in OpenVPN 2.6"); + } + /* * Check consistency of replay options */ From e3da00918d2dd99c116f6da1a14a2a73b72829f4 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sat, 1 Jul 2017 13:22:08 +0200 Subject: [PATCH 607/643] Deprecate --no-replay Following the removal of --no-iv, and as suggested by both recent audits (and done by OpenVPN-NL for 7 years now), it's time to get rid of the --no-replay option. The only valid use case I can imagine is to slightly reduce the per-packet overhead for setups that do not use any authentication mechanism, but I do not believe that warrants keeping an option around that generally reduces security and makes our code more complex. Signed-off-by: Steffan Karger Acked-by: David Sommerseth Message-Id: <20170701112208.18803-1-steffan@karger.me> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15003.html Signed-off-by: David Sommerseth --- Changes.rst | 8 ++++++++ doc/openvpn.8 | 3 +++ src/openvpn/options.c | 7 ++++++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/Changes.rst b/Changes.rst index 3d758f2ea80..7d1912b5ace 100644 --- a/Changes.rst +++ b/Changes.rst @@ -310,6 +310,14 @@ Maintainer-visible changes +Version 2.4.4 +============= + +Deprecated features +------------------- +- ``--no-replay`` is deprecated and will be removed in OpenVPN 2.5. + + Version 2.4.3 ============= diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 8170164b02e..c98d94bf147 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -4261,6 +4261,9 @@ supported by OpenSSL. .\"********************************************************* .TP .B \-\-no\-replay +.B DEPRECATED +This option will be removed in OpenVPN 2.5. + (Advanced) Disable OpenVPN's protection against replay attacks. Don't use this option unless you are prepared to make a tradeoff of greater efficiency in exchange for less diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 2b096eb036d..ee53adfe8fe 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -545,7 +545,7 @@ static const char usage_message[] = #ifndef ENABLE_CRYPTO_MBEDTLS "--engine [name] : Enable OpenSSL hardware crypto engine functionality.\n" #endif - "--no-replay : Disable replay protection.\n" + "--no-replay : (DEPRECATED) Disable replay protection.\n" "--mute-replay-warnings : Silence the output of replay warnings to log file.\n" "--replay-window n [t] : Use a replay protection sliding window of size n\n" " and a time window of t seconds.\n" @@ -2500,6 +2500,11 @@ options_postprocess_verify_ce(const struct options *options, const struct connec msg(M_WARN, "WARNING: --keysize is DEPRECATED and will be removed in OpenVPN 2.6"); } + if (!options->replay) + { + msg(M_WARN, "WARNING: --no-replay is DEPRECATED and will be removed in OpenVPN 2.5"); + } + /* * Check consistency of replay options */ From 76a61caa3e46987344fb9a0b3dfbd81582a0ad64 Mon Sep 17 00:00:00 2001 From: Thomas Veerman via Openvpn-devel Date: Fri, 7 Jul 2017 21:59:41 +0200 Subject: [PATCH 608/643] Fix socks_proxy_port pointing to invalid data When setting the SOCKS proxy through the management interface, the socks_proxy_port pointer would be set to a value that's no longer valid by the time it's used by do_preresolve_host. Signed-off-by: Thomas Veerman Acked-by: Arne Schwabe Message-Id: <20170707195941.61773-1-thomas.veerman@wanwire.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15018.html Signed-off-by: David Sommerseth (cherry picked from commit aa9d3a5bdc5a1b395d37fbb8abb3ed6166856a1a) --- src/openvpn/init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openvpn/init.c b/src/openvpn/init.c index a4fca504f3b..cbb27cc7691 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -150,7 +150,7 @@ management_callback_proxy_cmd(void *arg, const char **p) else if (streq(p[1], "SOCKS")) { ce->socks_proxy_server = string_alloc(p[2], gc); - ce->socks_proxy_port = p[3]; + ce->socks_proxy_port = string_alloc(p[3], gc); ret = true; } } From 30e0778a57a8db3d57d144471a869647037a115b Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Wed, 16 Aug 2017 20:18:06 +0800 Subject: [PATCH 609/643] ntlm: avoid breaking anti-aliasing rules MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The problem is visible when compiling with -O2: ntlm.c: In function ‘ntlm_phase_3’: ntlm.c:305:9: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing] if ((*((long *)&buf2[0x14]) & 0x00800000) == 0x00800000) The spec suggests to interpret those 4 bytes as a long, but this needs to be done carefully. Signed-off-by: Antonio Quartulli Acked-by: Steffan Karger Message-Id: <20170816121806.26471-1-a@unstable.cc> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15268.html Signed-off-by: David Sommerseth (cherry picked from commit e84b6994b4d2b53bcebd5415a58de4cecd411a7b) --- src/openvpn/ntlm.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/openvpn/ntlm.c b/src/openvpn/ntlm.c index 167c10b8042..077fa3e2acb 100644 --- a/src/openvpn/ntlm.c +++ b/src/openvpn/ntlm.c @@ -302,7 +302,21 @@ ntlm_phase_3(const struct http_proxy_info *p, const char *phase_2, /* Add target information block to the blob */ /* Check for Target Information block */ - if ((*((long *)&buf2[0x14]) & 0x00800000) == 0x00800000) + /* The NTLM spec instructs to interpret these 4 consecutive bytes as a + * 32bit long integer. However, no endianness is specified. + * The code here and that found in other NTLM implementations point + * towards the assumption that the byte order on the wire has to + * match the order on the sending and receiving hosts. Probably NTLM has + * been thought to be always running on x86_64/i386 machine thus + * implying Little-Endian everywhere. + * + * This said, in case of future changes, we should keep in mind that the + * byte order on the wire for the NTLM header is LE. + */ + const size_t hoff = 0x14; + unsigned long flags = buf2[hoff] | (buf2[hoff + 1] << 8) | + (buf2[hoff + 2] << 16) | (buf2[hoff + 3] << 24); + if ((flags & 0x00800000) == 0x00800000) { tib_len = buf2[0x28]; /* Get Target Information block size */ if (tib_len > 96) From 12df7c26a5210052029acbf47bdf9aee673b34ee Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Wed, 16 Aug 2017 21:24:54 +0800 Subject: [PATCH 610/643] remove the --disable-multi config switch This switch is broken and unmaintained. However there wasn't any ticket about it so far, which means that it is practically unused. Get rid of it and simplify P2MP logic. Signed-off-by: Antonio Quartulli Acked-by: Steffan Karger Message-Id: <20170816132454.13046-1-a@unstable.cc> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15275.html Signed-off-by: David Sommerseth (cherry picked from commit 299a8f8f1aa10b5b0d006ae77c26de33d55d4a25) --- config-msvc.h | 1 - configure.ac | 8 -------- src/openvpn/syshead.h | 2 +- 3 files changed, 1 insertion(+), 10 deletions(-) diff --git a/config-msvc.h b/config-msvc.h index 9b97e7121f6..0bb153dfc14 100644 --- a/config-msvc.h +++ b/config-msvc.h @@ -4,7 +4,6 @@ #define ENABLE_DEF_AUTH 1 #define ENABLE_PF 1 -#define ENABLE_CLIENT_SERVER 1 #define ENABLE_CRYPTO 1 #define ENABLE_CRYPTO_OPENSSL 1 #define ENABLE_DEBUG 1 diff --git a/configure.ac b/configure.ac index 2502166a657..baeff41b073 100644 --- a/configure.ac +++ b/configure.ac @@ -98,13 +98,6 @@ AC_ARG_ENABLE( [enable_x509_alt_username="no"] ) -AC_ARG_ENABLE( - [multi], - [AS_HELP_STRING([--disable-multi], [disable client/server support (--mode server + client mode) @<:@default=yes@:>@])], - , - [enable_multi="yes"] -) - AC_ARG_ENABLE( [server], [AS_HELP_STRING([--disable-server], [disable server support only (but retain client support) @<:@default=yes@:>@])], @@ -1177,7 +1170,6 @@ if test "${enable_x509_alt_username}" = "yes"; then fi test "${ac_cv_header_sys_uio_h}" = "yes" && AC_DEFINE([HAVE_IOVEC], [1], [struct iovec needed for IPv6 support]) -test "${enable_multi}" = "yes" && AC_DEFINE([ENABLE_CLIENT_SERVER], [1], [Enable client/server capability]) test "${enable_server}" = "no" && AC_DEFINE([ENABLE_CLIENT_ONLY], [1], [Enable client capability only]) test "${enable_management}" = "yes" && AC_DEFINE([ENABLE_MANAGEMENT], [1], [Enable management server capability]) test "${enable_multihome}" = "yes" && AC_DEFINE([ENABLE_MULTIHOME], [1], [Enable multi-homed UDP server capability]) diff --git a/src/openvpn/syshead.h b/src/openvpn/syshead.h index 2973b5ad144..d9f5a34d57e 100644 --- a/src/openvpn/syshead.h +++ b/src/openvpn/syshead.h @@ -513,7 +513,7 @@ socket_defined(const socket_descriptor_t sd) * Do we have point-to-multipoint capability? */ -#if defined(ENABLE_CLIENT_SERVER) && defined(ENABLE_CRYPTO) && defined(HAVE_GETTIMEOFDAY_NANOSECONDS) +#if defined(ENABLE_CRYPTO) && defined(HAVE_GETTIMEOFDAY_NANOSECONDS) #define P2MP 1 #else #define P2MP 0 From 81b78cf5de03f843cdf917bb2ee350ba85f49cbd Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Tue, 15 Aug 2017 17:39:46 +0200 Subject: [PATCH 611/643] Move run_up_down() to init.c This function is only used in init.c, and is not easy to fit into a specific category because it both runs scripts and plugin hooks. Making it static in init.c is probably the best place for this function. (I think we should find a better place for everything currently in misc.c, and get rid of it all together. This patch is part of that effort.) Signed-off-by: Steffan Karger Acked-by: Antonio Quartulli Message-Id: <1502811586-19578-1-git-send-email-steffan.karger@fox-it.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15256.html Signed-off-by: David Sommerseth (cherry picked from commit 4a9d1d70d5b0ff04dbf26ba7e679733a54c694b6) --- src/openvpn/init.c | 88 +++++++++++++++++++++++++++++++++++++++++++++ src/openvpn/misc.c | 89 ---------------------------------------------- src/openvpn/misc.h | 17 --------- 3 files changed, 88 insertions(+), 106 deletions(-) diff --git a/src/openvpn/init.c b/src/openvpn/init.c index cbb27cc7691..133a9f50842 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -93,6 +93,94 @@ context_clear_all_except_first_time(struct context *c) c->persist = cpsave; } +/* + * Pass tunnel endpoint and MTU parms to a user-supplied script. + * Used to execute the up/down script/plugins. + */ +static void +run_up_down(const char *command, + const struct plugin_list *plugins, + int plugin_type, + const char *arg, +#ifdef _WIN32 + DWORD adapter_index, +#endif + const char *dev_type, + int tun_mtu, + int link_mtu, + const char *ifconfig_local, + const char *ifconfig_remote, + const char *context, + const char *signal_text, + const char *script_type, + struct env_set *es) +{ + struct gc_arena gc = gc_new(); + + if (signal_text) + { + setenv_str(es, "signal", signal_text); + } + setenv_str(es, "script_context", context); + setenv_int(es, "tun_mtu", tun_mtu); + setenv_int(es, "link_mtu", link_mtu); + setenv_str(es, "dev", arg); + if (dev_type) + { + setenv_str(es, "dev_type", dev_type); + } +#ifdef _WIN32 + setenv_int(es, "dev_idx", adapter_index); +#endif + + if (!ifconfig_local) + { + ifconfig_local = ""; + } + if (!ifconfig_remote) + { + ifconfig_remote = ""; + } + if (!context) + { + context = ""; + } + + if (plugin_defined(plugins, plugin_type)) + { + struct argv argv = argv_new(); + ASSERT(arg); + argv_printf(&argv, + "%s %d %d %s %s %s", + arg, + tun_mtu, link_mtu, + ifconfig_local, ifconfig_remote, + context); + + if (plugin_call(plugins, plugin_type, &argv, NULL, es) != OPENVPN_PLUGIN_FUNC_SUCCESS) + { + msg(M_FATAL, "ERROR: up/down plugin call failed"); + } + + argv_reset(&argv); + } + + if (command) + { + struct argv argv = argv_new(); + ASSERT(arg); + setenv_str(es, "script_type", script_type); + argv_parse_cmd(&argv, command); + argv_printf_cat(&argv, "%s %d %d %s %s %s", arg, tun_mtu, link_mtu, + ifconfig_local, ifconfig_remote, context); + argv_msg(M_INFO, &argv); + openvpn_run_script(&argv, es, S_FATAL, "--up/--down"); + argv_reset(&argv); + } + + gc_free(&gc); +} + /* * Should be called after options->ce is modified at the top * of a SIGUSR1 restart. diff --git a/src/openvpn/misc.c b/src/openvpn/misc.c index cd12f918622..8c7f6116937 100644 --- a/src/openvpn/misc.c +++ b/src/openvpn/misc.c @@ -54,95 +54,6 @@ const char *iproute_path = IPROUTE_PATH; /* GLOBAL */ /* contains an SSEC_x value defined in misc.h */ int script_security = SSEC_BUILT_IN; /* GLOBAL */ -/* - * Pass tunnel endpoint and MTU parms to a user-supplied script. - * Used to execute the up/down script/plugins. - */ -void -run_up_down(const char *command, - const struct plugin_list *plugins, - int plugin_type, - const char *arg, -#ifdef _WIN32 - DWORD adapter_index, -#endif - const char *dev_type, - int tun_mtu, - int link_mtu, - const char *ifconfig_local, - const char *ifconfig_remote, - const char *context, - const char *signal_text, - const char *script_type, - struct env_set *es) -{ - struct gc_arena gc = gc_new(); - - if (signal_text) - { - setenv_str(es, "signal", signal_text); - } - setenv_str(es, "script_context", context); - setenv_int(es, "tun_mtu", tun_mtu); - setenv_int(es, "link_mtu", link_mtu); - setenv_str(es, "dev", arg); - if (dev_type) - { - setenv_str(es, "dev_type", dev_type); - } -#ifdef _WIN32 - setenv_int(es, "dev_idx", adapter_index); -#endif - - if (!ifconfig_local) - { - ifconfig_local = ""; - } - if (!ifconfig_remote) - { - ifconfig_remote = ""; - } - if (!context) - { - context = ""; - } - - if (plugin_defined(plugins, plugin_type)) - { - struct argv argv = argv_new(); - ASSERT(arg); - argv_printf(&argv, - "%s %d %d %s %s %s", - arg, - tun_mtu, link_mtu, - ifconfig_local, ifconfig_remote, - context); - - if (plugin_call(plugins, plugin_type, &argv, NULL, es) != OPENVPN_PLUGIN_FUNC_SUCCESS) - { - msg(M_FATAL, "ERROR: up/down plugin call failed"); - } - - argv_reset(&argv); - } - - if (command) - { - struct argv argv = argv_new(); - ASSERT(arg); - setenv_str(es, "script_type", script_type); - argv_parse_cmd(&argv, command); - argv_printf_cat(&argv, "%s %d %d %s %s %s", arg, tun_mtu, link_mtu, - ifconfig_local, ifconfig_remote, context); - argv_msg(M_INFO, &argv); - openvpn_run_script(&argv, es, S_FATAL, "--up/--down"); - argv_reset(&argv); - } - - gc_free(&gc); -} - - /* * Set standard file descriptors to /dev/null */ diff --git a/src/openvpn/misc.h b/src/openvpn/misc.h index a7aa7622af3..eb39ce3f416 100644 --- a/src/openvpn/misc.h +++ b/src/openvpn/misc.h @@ -51,23 +51,6 @@ struct env_set { struct env_item *list; }; -void run_up_down(const char *command, - const struct plugin_list *plugins, - int plugin_type, - const char *arg, -#ifdef _WIN32 - DWORD adapter_index, -#endif - const char *dev_type, - int tun_mtu, - int link_mtu, - const char *ifconfig_local, - const char *ifconfig_remote, - const char *context, - const char *signal_text, - const char *script_type, - struct env_set *es); - /* system flags */ #define S_SCRIPT (1<<0) #define S_FATAL (1<<1) From d47228e71de6cbbf860746a50a3ecf8025e35653 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sat, 12 Aug 2017 11:53:52 +0200 Subject: [PATCH 612/643] tls-crypt: introduce tls_crypt_kt() Reduces code duplication (and prepares for tls-crypt-v2, which needs the same functionality at more places). Because tls_crypt_kt() is a static function we now need to include tls_crypt.c from the tests, rather than tls_crypt.h. Signed-off-by: Steffan Karger Acked-by: Antonio Quartulli Message-Id: <1502531632-16833-1-git-send-email-steffan.karger@fox-it.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15229.html Signed-off-by: David Sommerseth (cherry picked from commit 489c7bf93ec618e03dbd9618efbb6e251a65e76c) --- src/openvpn/tls_crypt.c | 40 +++++++++++++++-------- tests/unit_tests/openvpn/Makefile.am | 3 +- tests/unit_tests/openvpn/test_tls_crypt.c | 20 +++--------- 3 files changed, 32 insertions(+), 31 deletions(-) diff --git a/src/openvpn/tls_crypt.c b/src/openvpn/tls_crypt.c index e13bb4e96cb..403060de980 100644 --- a/src/openvpn/tls_crypt.c +++ b/src/openvpn/tls_crypt.c @@ -35,35 +35,47 @@ #include "tls_crypt.h" -int -tls_crypt_buf_overhead(void) -{ - return packet_id_size(true) + TLS_CRYPT_TAG_SIZE + TLS_CRYPT_BLOCK_SIZE; -} - -void -tls_crypt_init_key(struct key_ctx_bi *key, const char *key_file, - const char *key_inline, bool tls_server) +static struct key_type +tls_crypt_kt(void) { - const int key_direction = tls_server ? - KEY_DIRECTION_NORMAL : KEY_DIRECTION_INVERSE; - struct key_type kt; kt.cipher = cipher_kt_get("AES-256-CTR"); kt.digest = md_kt_get("SHA256"); if (!kt.cipher) { - msg(M_FATAL, "ERROR: --tls-crypt requires AES-256-CTR support."); + msg(M_WARN, "ERROR: --tls-crypt requires AES-256-CTR support."); + return (struct key_type) { 0 }; } if (!kt.digest) { - msg(M_FATAL, "ERROR: --tls-crypt requires HMAC-SHA-256 support."); + msg(M_WARN, "ERROR: --tls-crypt requires HMAC-SHA-256 support."); + return (struct key_type) { 0 }; } kt.cipher_length = cipher_kt_key_size(kt.cipher); kt.hmac_length = md_kt_size(kt.digest); + return kt; +} + +int +tls_crypt_buf_overhead(void) +{ + return packet_id_size(true) + TLS_CRYPT_TAG_SIZE + TLS_CRYPT_BLOCK_SIZE; +} + +void +tls_crypt_init_key(struct key_ctx_bi *key, const char *key_file, + const char *key_inline, bool tls_server) +{ + const int key_direction = tls_server ? + KEY_DIRECTION_NORMAL : KEY_DIRECTION_INVERSE; + struct key_type kt = tls_crypt_kt(); + if (!kt.cipher || !kt.digest) + { + msg (M_FATAL, "ERROR: --tls-crypt not supported"); + } crypto_read_openvpn_key(&kt, key, key_file, key_inline, key_direction, "Control Channel Encryption", "tls-crypt"); } diff --git a/tests/unit_tests/openvpn/Makefile.am b/tests/unit_tests/openvpn/Makefile.am index 3bd382c2dfc..7b44f42e876 100644 --- a/tests/unit_tests/openvpn/Makefile.am +++ b/tests/unit_tests/openvpn/Makefile.am @@ -54,5 +54,4 @@ tls_crypt_testdriver_SOURCES = test_tls_crypt.c mock_msg.c \ $(openvpn_srcdir)/crypto_openssl.c \ $(openvpn_srcdir)/otime.c \ $(openvpn_srcdir)/packet_id.c \ - $(openvpn_srcdir)/platform.c \ - $(openvpn_srcdir)/tls_crypt.c + $(openvpn_srcdir)/platform.c diff --git a/tests/unit_tests/openvpn/test_tls_crypt.c b/tests/unit_tests/openvpn/test_tls_crypt.c index 9b820355c4f..0a6a08fa70d 100644 --- a/tests/unit_tests/openvpn/test_tls_crypt.c +++ b/tests/unit_tests/openvpn/test_tls_crypt.c @@ -39,7 +39,7 @@ #include #include -#include "tls_crypt.h" +#include "tls_crypt.c" #include "mock_msg.h" @@ -60,23 +60,13 @@ setup(void **state) { struct test_context *ctx = calloc(1, sizeof(*ctx)); *state = ctx; - ctx->kt.cipher = cipher_kt_get("AES-256-CTR"); - ctx->kt.digest = md_kt_get("SHA256"); - if (!ctx->kt.cipher) - { - printf("No AES-256-CTR support, skipping test.\n"); - return 0; - } - if (!ctx->kt.digest) + struct key key = { 0 }; + + ctx->kt = tls_crypt_kt(); + if (!ctx->kt.cipher || !ctx->kt.digest) { - printf("No HMAC-SHA256 support, skipping test.\n"); return 0; } - ctx->kt.cipher_length = cipher_kt_key_size(ctx->kt.cipher); - ctx->kt.hmac_length = md_kt_size(ctx->kt.digest); - - struct key key = { 0 }; - init_key_ctx(&ctx->co.key_ctx_bi.encrypt, &key, &ctx->kt, true, "TEST"); init_key_ctx(&ctx->co.key_ctx_bi.decrypt, &key, &ctx->kt, false, "TEST"); From e710d709b7e604abd1e86b6fc04695a472aed977 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Tue, 15 Aug 2017 23:54:51 +0200 Subject: [PATCH 613/643] Highlight deprecated features We have quite a list of deprecated options currently. Ensure this is highlighted both in documentation and code. This patch builds on the wiki page [1] enlisting all deprecated features and their status. There are also some options not listed here, as there exists patches in release/2.4 which awaits an update for git master. [1] https://community.openvpn.net/openvpn/wiki/DeprecatedOptions Signed-off-by: David Sommerseth Acked-by: Steffan Karger Message-Id: <20170815215451.21662-1-davids@openvpn.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15261.html Signed-off-by: David Sommerseth (cherry picked from commit 6e4a817589de85481a5cbfe5bcae4fa872c9fb5d) --- Changes.rst | 15 +++++++++ doc/openvpn.8 | 75 ++++++++++++++++++++++++++++--------------- src/openvpn/options.c | 14 ++++---- 3 files changed, 73 insertions(+), 31 deletions(-) diff --git a/Changes.rst b/Changes.rst index 7d1912b5ace..f8921804d91 100644 --- a/Changes.rst +++ b/Changes.rst @@ -161,6 +161,9 @@ Asynchronous push reply Deprecated features ------------------- +For an up-to-date list of all deprecated options, see this wiki page: +https://community.openvpn.net/openvpn/wiki/DeprecatedOptions + - ``--key-method 1`` is deprecated in 2.4 and will be removed in 2.5. Migrate away from ``--key-method 1`` as soon as possible. The recommended approach is to remove the ``--key-method`` option from the configuration files, OpenVPN @@ -181,6 +184,18 @@ Deprecated features - ``--keysize`` is deprecated and will be removed in v2.6 together with the support of ciphers with cipher block size less than 128 bits. +- ``--comp-lzo`` is deprecated in OpenVPN 2.4. Use ``--compress`` instead. + +- ``--ifconfig-pool-linear`` has been deprecated since OpenVPN 2.1 and will be + removed in v2.5. Use ``--topology p2p`` instead. + +- ``--client-cert-not-required`` is deprecated in OpenVPN 2.4 and will be removed + in v2.5. Use ``--verify-client-cert none`` for a functional equivalent. + +- ``--ns-cert-type`` is deprecated in OpenVPN 2.3.18 and v2.4. It will be removed + in v2.5. Use the far better ``--remote-cert-tls`` option which replaces this + feature. + User-visible Changes -------------------- diff --git a/doc/openvpn.8 b/doc/openvpn.8 index c98d94bf147..f23aa435454 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -769,7 +769,8 @@ Only use when none of the connecting clients are Windows systems. This mode is functionally equivalent to the .B \-\-ifconfig\-pool\-linear -directive which is available in OpenVPN 2.0 and is now deprecated. +directive which is available in OpenVPN 2.0, is deprecated and will be +removed in OpenVPN 2.5 .B subnet \-\- Use a subnet rather than a point-to-point topology by @@ -2485,15 +2486,17 @@ setting to be pushed later. .\"********************************************************* .TP .B \-\-comp\-lzo [mode] +.B DEPRECATED +This option will be removed in a future OpenVPN release. Use the +newer +.B \-\-compress +instead. + Use LZO compression -- may add up to 1 byte per packet for incompressible data. .B mode may be "yes", "no", or "adaptive" (default). -This option is deprecated in favor of the newer -.B --compress -option. - In a server mode setup, it is possible to selectively turn compression on or off for individual clients. @@ -3107,9 +3110,13 @@ a common name and IP address. They do not guarantee that the given common name will always receive the given IP address. If you want guaranteed assignment, use .B \-\-ifconfig\-push + .\"********************************************************* .TP .B \-\-ifconfig\-pool\-linear +.B DEPRECATED +This option will be removed in OpenVPN 2.5 + Modifies the .B \-\-ifconfig\-pool directive to @@ -3672,15 +3679,16 @@ to empty strings (""). The authentication module/script MUST have logic to detect this condition and respond accordingly. .\"********************************************************* .TP -.B \-\-client\-cert\-not\-required (DEPRECATED) +.B \-\-client\-cert\-not\-required +.B DEPRECATED +This option will be removed in OpenVPN 2.5 + Don't require client certificate, client will authenticate using username/password only. Be aware that using this directive is less secure than requiring certificates from all clients. - .B Please note: -This option is now deprecated and will be removed in OpenVPN v2.5. -It is replaced by +This is replaced by .B \-\-verify\-client\-cert which allows for more flexibility. The option .B \-\-verify\-client\-cert none @@ -3745,7 +3753,10 @@ the authenticated username as the common name, rather than the common name from the client cert. .\"********************************************************* .TP -.B \-\-compat\-names [no\-remapping] (DEPRECATED) +.B \-\-compat\-names [no\-remapping] +.B DEPRECATED +This option will be removed in OpenVPN 2.5 + Until OpenVPN v2.3 the format of the X.509 Subject fields was formatted like this: .IP @@ -3793,7 +3804,10 @@ to make the transition to the new formatting less intrusive. It will be removed in OpenVPN v2.5. So please update your scripts/plug-ins where necessary. .\"********************************************************* .TP -.B \-\-no\-name\-remapping (DEPRECATED) +.B \-\-no\-name\-remapping +.B DEPRECATED +This option will be removed in OpenVPN 2.5 + The .B \-\-no\-name\-remapping option is an alias for @@ -4151,13 +4165,29 @@ For more information on HMAC see .B \-\-cipher alg Encrypt data channel packets with cipher algorithm .B alg. + The default is .B BF-CBC, -an abbreviation for Blowfish in Cipher Block Chaining mode. +an abbreviation for Blowfish in Cipher Block Chaining mode. When cipher +negotiation (NCP) is allowed, OpenVPN 2.4 and newer on both client and server +side will automatically upgrade to +.B AES-256-GCM. +See +.B \-\-ncp\-ciphers +and +.B \-\-ncp\-disable +for more details on NCP. -Using BF-CBC is no longer recommended, because of it's 64-bit block size. This +Using +.B BF-CBC +is no longer recommended, because of its 64-bit block size. This small block size allows attacks based on collisions, as demonstrated by SWEET32. -See https://community.openvpn.net/openvpn/wiki/SWEET32 for details. +See https://community.openvpn.net/openvpn/wiki/SWEET32 for details. Due to +this, support for +.B BF-CBC, DES, CAST5, IDEA +and +.B RC2 +ciphers will be removed in OpenVPN 2.6. To see other ciphers that are available with OpenVPN, use the .B \-\-show\-ciphers @@ -4167,14 +4197,6 @@ Set .B alg=none to disable encryption. -As of OpenVPN 2.4, cipher negotiation (NCP) can override the cipher specified by -.B \-\-cipher\fR. -See -.B \-\-ncp\-ciphers -and -.B \-\-ncp\-disable -for more on NCP. - .\"********************************************************* .TP .B \-\-ncp\-ciphers cipher_list @@ -4427,7 +4449,6 @@ This option only makes sense when replay protection is enabled .\"********************************************************* .TP .B \-\-no\-iv - .B DEPRECATED This option will be removed in OpenVPN 2.5. @@ -4827,6 +4848,9 @@ Certificate Store GUI. .\"********************************************************* .TP .B \-\-key\-method m +.B DEPRECATED +This option will be removed in OpenVPN 2.5 + Use data channel key negotiation method .B m. The key method must match on both sides of the connection. @@ -5383,8 +5407,9 @@ as X509__=. Multiple options can be defined to track multiple attributes. .\"********************************************************* .TP -.B \-\-ns\-cert\-type client|server (DEPRECATED) -This option is deprecated. Use the more modern equivalent +.B \-\-ns\-cert\-type client|server +.B DEPRECATED +This option will be removed in OpenVPN 2.5. Use the more modern equivalent .B \-\-remote\-cert\-tls instead. This option will be removed in OpenVPN 2.5. diff --git a/src/openvpn/options.c b/src/openvpn/options.c index ee53adfe8fe..a92702e37d6 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -415,8 +415,9 @@ static const char usage_message[] = " client instance.\n" "--ifconfig-pool start-IP end-IP [netmask] : Set aside a pool of subnets\n" " to be dynamically allocated to connecting clients.\n" - "--ifconfig-pool-linear : Use individual addresses rather than /30 subnets\n" - " in tun mode. Not compatible with Windows clients.\n" + "--ifconfig-pool-linear : (DEPRECATED) Use individual addresses rather \n" + " than /30 subnets\n in tun mode. Not compatible with\n" + " Windows clients.\n" "--ifconfig-pool-persist file [seconds] : Persist/unpersist ifconfig-pool\n" " data to file, at seconds intervals (default=600).\n" " If seconds=0, file will be treated as read-only.\n" @@ -434,7 +435,7 @@ static const char usage_message[] = " Only valid in a client-specific config file.\n" "--disable : Client is disabled.\n" " Only valid in a client-specific config file.\n" - "--client-cert-not-required : Don't require client certificate, client\n" + "--client-cert-not-required : (DEPRECATED) Don't require client certificate, client\n" " will authenticate using username/password.\n" "--verify-client-cert [none|optional|require] : perform no, optional or\n" " mandatory client certificate verification.\n" @@ -455,7 +456,7 @@ static const char usage_message[] = " with those of the server will be disconnected.\n" "--auth-user-pass-optional : Allow connections by clients that don't\n" " specify a username/password.\n" - "--no-name-remapping : Allow Common Name and X509 Subject to include\n" + "--no-name-remapping : (DEPRECATED) Allow Common Name and X509 Subject to include\n" " any printable character.\n" "--client-to-client : Internally route client-to-client traffic.\n" "--duplicate-cn : Allow multiple clients with the same common name to\n" @@ -539,7 +540,7 @@ static const char usage_message[] = "--prng alg [nsl] : For PRNG, use digest algorithm alg, and\n" " nonce_secret_len=nsl. Set alg=none to disable PRNG.\n" #ifdef HAVE_EVP_CIPHER_CTX_SET_KEY_LENGTH - "--keysize n : Size of cipher key in bits (optional).\n" + "--keysize n : (DEPRECATED) Size of cipher key in bits (optional).\n" " If unspecified, defaults to cipher-specific default.\n" #endif #ifndef ENABLE_CRYPTO_MBEDTLS @@ -564,7 +565,7 @@ static const char usage_message[] = "(These options are meaningful only for TLS-mode)\n" "--tls-server : Enable TLS and assume server role during TLS handshake.\n" "--tls-client : Enable TLS and assume client role during TLS handshake.\n" - "--key-method m : Data channel key exchange method. m should be a method\n" + "--key-method m : (DEPRECATED) Data channel key exchange method. m should be a method\n" " number, such as 1 (default), 2, etc.\n" "--ca file : Certificate authority file in .pem format containing\n" " root certificate.\n" @@ -6591,6 +6592,7 @@ add_option(struct options *options, { VERIFY_PERMISSION(OPT_P_GENERAL); options->topology = TOP_P2P; + msg(M_WARN, "DEPRECATED OPTION: --ifconfig-pool-linear, use --topology p2p instead"); } else if (streq(p[0], "ifconfig-ipv6-pool") && p[1] && !p[2]) { From 35e81e1a3d6809772f49f777ed6ec8e868505c6c Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Tue, 15 Aug 2017 22:53:01 +0200 Subject: [PATCH 614/643] Use consistent version references A simple clean-up where the version references have been unified all those places I could find now. The versioning scheme used is: * OpenVPN 2.x * v2.x We want to avoid: * 2.x (2.4 can be just an ordindary decimal number, OID reference, a version number or anything else) * OpenVPN v2.x (OpenVPN indicates we're talking about a version) In addition, several places where it made sense I tried to ensure the first version reference uses "OpenVPN 2.x" and the following references in the same section/paragraph uses "v2.x", to set the context for the version reference. In Changes.rst modified paragraphs exceeding 80 chars lines where reformatted as well. Signed-off-by: David Sommerseth Acked-by: Steffan Karger Message-Id: <20170815205301.14542-1-davids@openvpn.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15260.html Signed-off-by: David Sommerseth (cherry picked from commit 500854c3fc956b274790991e4d6771ad9bf6f641) --- Changes.rst | 53 ++++++++++++++------------ doc/openvpn.8 | 30 +++++++-------- sample/sample-config-files/client.conf | 2 +- sample/sample-config-files/server.conf | 4 +- src/openvpn/options.c | 8 ++-- 5 files changed, 50 insertions(+), 47 deletions(-) diff --git a/Changes.rst b/Changes.rst index f8921804d91..fd31d8779c5 100644 --- a/Changes.rst +++ b/Changes.rst @@ -164,25 +164,26 @@ Deprecated features For an up-to-date list of all deprecated options, see this wiki page: https://community.openvpn.net/openvpn/wiki/DeprecatedOptions -- ``--key-method 1`` is deprecated in 2.4 and will be removed in 2.5. Migrate - away from ``--key-method 1`` as soon as possible. The recommended approach - is to remove the ``--key-method`` option from the configuration files, OpenVPN - will then use ``--key-method 2`` by default. Note that this requires changing - the option in both the client and server side configs. +- ``--key-method 1`` is deprecated in OpenVPN 2.4 and will be removed in v2.5. + Migrate away from ``--key-method 1`` as soon as possible. The recommended + approach is to remove the ``--key-method`` option from the configuration + files, OpenVPN will then use ``--key-method 2`` by default. Note that this + requires changing the option in both the client and server side configs. -- ``--tls-remote`` is removed in 2.4, as indicated in the 2.3 man-pages. Similar - functionality is provided via ``--verify-x509-name``, which does the same job in - a better way. +- ``--tls-remote`` is removed in OpenVPN 2.4, as indicated in the v2.3 + man-pages. Similar functionality is provided via ``--verify-x509-name``, + which does the same job in a better way. -- ``--compat-names`` and ``--no-name-remapping`` were deprecated in 2.3 and will - be removed in 2.5. All scripts and plug-ins depending on the old non-standard - X.509 subject formatting must be updated to the standardized formatting. See - the man page for more information. +- ``--compat-names`` and ``--no-name-remapping`` were deprecated in OpenVPN 2.3 + and will be removed in v2.5. All scripts and plug-ins depending on the old + non-standard X.509 subject formatting must be updated to the standardized + formatting. See the man page for more information. -- ``--no-iv`` is deprecated in 2.4 and will be removed in 2.5. +- ``--no-iv`` is deprecated in OpenVPN 2.4 and will be removed in v2.5. -- ``--keysize`` is deprecated and will be removed in v2.6 together - with the support of ciphers with cipher block size less than 128 bits. +- ``--keysize`` is deprecated in OpenVPN 2.4 and will be removed in v2.6 + together with the support of ciphers with cipher block size less than + 128-bits. - ``--comp-lzo`` is deprecated in OpenVPN 2.4. Use ``--compress`` instead. @@ -317,7 +318,7 @@ Maintainer-visible changes files instead of older ones, to provide a unified behaviour across systemd based Linux distributions. -- With OpenVPN v2.4, the project has moved over to depend on and actively use +- With OpenVPN 2.4, the project has moved over to depend on and actively use the official C99 standard (-std=c99). This may fail on some older compiler/libc header combinations. In most of these situations it is recommended to use -std=gnu99 in CFLAGS. This is known to be needed when doing @@ -348,7 +349,7 @@ New features Security -------- - CVE-2017-7522: Fix ``--x509-track`` post-authentication remote DoS - A client could crash a 2.4+ mbedtls server, if that server uses the + A client could crash a v2.4+ mbedtls server, if that server uses the ``--x509-track`` option and the client has a correct, signed and unrevoked certificate that contains an embedded NUL in the certificate subject. Discovered and reported to the OpenVPN security team by Guido Vranken. @@ -405,7 +406,7 @@ User-visible Changes Bugfixes -------- - Fix fingerprint calculation in mbed TLS builds. This means that mbed TLS users - of OpenVPN 2.4.0, 2.4.1 and 2.4.2 that rely on the values of the + of OpenVPN 2.4.0, v2.4.1 and v2.4.2 that rely on the values of the ``tls_digest_*`` env vars, or that use ``--verify-hash`` will have to change the fingerprint values they check against. The security impact of the incorrect calculation is very minimal; the last few bytes (max 4, typically @@ -434,16 +435,18 @@ Version 2.4.2 Bugfixes -------- -- Fix memory leak introduced in 2.4.1: if --remote-cert-tls is used, we leaked - some memory on each TLS (re)negotiation. +- Fix memory leak introduced in OpenVPN 2.4.1: if ``--remote-cert-tls`` is + used, we leaked some memory on each TLS (re)negotiation. + Security -------- -- Fix a pre-authentication denial-of-service attack on both clients and servers. - By sending a too-large control packet, OpenVPN 2.4.0 or 2.4.1 can be forced - to hit an ASSERT() and stop the process. If ``--tls-auth`` or ``--tls-crypt`` - is used, only attackers that have the ``--tls-auth`` or ``--tls-crypt`` key - can mount an attack. (OSTIF/Quarkslab audit finding 5.1, CVE-2017-7478) +- Fix a pre-authentication denial-of-service attack on both clients and + servers. By sending a too-large control packet, OpenVPN 2.4.0 or v2.4.1 can + be forced to hit an ASSERT() and stop the process. If ``--tls-auth`` or + ``--tls-crypt`` is used, only attackers that have the ``--tls-auth`` or + ``--tls-crypt`` key can mount an attack. + (OSTIF/Quarkslab audit finding 5.1, CVE-2017-7478) - Fix an authenticated remote DoS vulnerability that could be triggered by causing a packet id roll over. An attack is rather inefficient; a peer diff --git a/doc/openvpn.8 b/doc/openvpn.8 index f23aa435454..eda2a4cdb56 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -1995,7 +1995,7 @@ could be either .B execve or .B system. -As of OpenVPN v2.3, this flag is no longer accepted. In most *nix environments the execve() +As of OpenVPN 2.3, this flag is no longer accepted. In most *nix environments the execve() approach has been used without any issues. Some directives such as \-\-up allow options to be passed to the external @@ -2007,7 +2007,7 @@ To run scripts in Windows in earlier OpenVPN versions you needed to either add a full path to the script interpreter which can parse the script or use the .B system -flag to run these scripts. As of OpenVPN v2.3 it is now a strict requirement to have +flag to run these scripts. As of OpenVPN 2.3 it is now a strict requirement to have full path to the script interpreter when running non-executables files. This is not needed for executable files, such as .exe, .com, .bat or .cmd files. For example, if you have a Visual Basic script, you must use this syntax now: @@ -2202,7 +2202,7 @@ passwords, or key pass phrases anymore. This has certain consequences, namely that using a password-protected private key will fail unless the .B \-\-askpass option is used to tell OpenVPN to ask for the pass phrase (this -requirement is new in 2.3.7, and is a consequence of calling daemon() +requirement is new in v2.3.7, and is a consequence of calling daemon() before initializing the crypto layer). Further, using @@ -2475,7 +2475,7 @@ The parameter may be "lzo", "lz4", or empty. LZO and LZ4 are different compression algorithms, with LZ4 generally offering the best performance with least CPU usage. -For backwards compatibility with OpenVPN versions before 2.4, use "lzo" +For backwards compatibility with OpenVPN versions before v2.4, use "lzo" (which is identical to the older option "\-\-comp\-lzo yes"). If the @@ -3775,13 +3775,13 @@ option, this old formatting and remapping will be re-enabled again. This is purely implemented for compatibility reasons when using older plug-ins or scripts which does not handle the new formatting or UTF-8 characters. .IP -In OpenVPN v2.3 the formatting of these fields changed into a more +In OpenVPN 2.3 the formatting of these fields changed into a more standardised format. It now looks like: .IP .B C=US, L=Somewhere, CN=John Doe, emailAddress=john@example.com .IP -The new default format in OpenVPN v2.3 also does not do the character remapping +The new default format in OpenVPN 2.3 also does not do the character remapping which happened earlier. This new format enables proper support for UTF\-8 characters in the usernames, X.509 Subject fields and Common Name variables and it complies to the RFC 2253, UTF\-8 String Representation of Distinguished @@ -3801,7 +3801,7 @@ carriage-return. no-remapping is only available on the server side. .B Please note: This option is immediately deprecated. It is only implemented to make the transition to the new formatting less intrusive. It will be -removed in OpenVPN v2.5. So please update your scripts/plug-ins where necessary. +removed in OpenVPN 2.5. So please update your scripts/plug-ins where necessary. .\"********************************************************* .TP .B \-\-no\-name\-remapping @@ -3817,7 +3817,7 @@ It ensures compatibility with server configurations using the option. .B Please note: -This option is now deprecated. It will be removed in OpenVPN v2.5. +This option is now deprecated. It will be removed in OpenVPN 2.5. So please make sure you support the new X.509 name formatting described with the .B \-\-compat\-names @@ -4227,8 +4227,8 @@ will inherit the cipher of the peer if that cipher is different from the local .B \-\-cipher setting, but the peer cipher is one of the ciphers specified in .B \-\-ncp\-ciphers\fR. -E.g. a non-NCP client (<=2.3, or with \-\-ncp\-disabled set) connecting to a -NCP server (2.4+) with "\-\-cipher BF-CBC" and "\-\-ncp-ciphers +E.g. a non-NCP client (<=v2.3, or with \-\-ncp\-disabled set) connecting to a +NCP server (v2.4+) with "\-\-cipher BF-CBC" and "\-\-ncp-ciphers AES-256-GCM:AES-256-CBC" set can either specify "\-\-cipher BF-CBC" or "\-\-cipher AES-256-CBC" and both will work. @@ -5038,8 +5038,8 @@ response. (required) is a file in OpenVPN static key format which can be generated by .B \-\-genkey -Older versions (up to 2.3) supported a freeform passphrase file. -This is no longer supported in newer versions (2.4+). +Older versions (up to OpenVPN 2.3) supported a freeform passphrase file. +This is no longer supported in newer versions (v2.4+). See the .B \-\-secret @@ -5597,7 +5597,7 @@ Write key to .B file. .\"********************************************************* .SS TUN/TAP persistent tunnel config mode: -Available with linux 2.4.7+. These options comprise a standalone mode +Available with Linux 2.4.7+. These options comprise a standalone mode of OpenVPN which can be used to create and delete persistent tunnels. .\"********************************************************* .TP @@ -5924,7 +5924,7 @@ flag. .TP .B \-\-dhcp\-release Ask Windows to release the TAP adapter lease on shutdown. -This option has no effect now, as it is enabled by default starting with version 2.4.1. +This option has no effect now, as it is enabled by default starting with OpenVPN 2.4.1. .\"********************************************************* .TP .B \-\-register\-dns @@ -6207,7 +6207,7 @@ isprint() function to return true. .B \-\-client\-config\-dir filename as derived from common name or username: Alphanumeric, underbar ('_'), dash ('-'), and dot ('.') except for "." or -".." as standalone strings. As of 2.0.1-rc6, the at ('@') character has +".." as standalone strings. As of v2.0.1-rc6, the at ('@') character has been added as well for compatibility with the common name character class. .B Environmental variable names: diff --git a/sample/sample-config-files/client.conf b/sample/sample-config-files/client.conf index f5c69e34ba5..5fd4a948f23 100644 --- a/sample/sample-config-files/client.conf +++ b/sample/sample-config-files/client.conf @@ -110,7 +110,7 @@ tls-auth ta.key 1 # Select a cryptographic cipher. # If the cipher option is used on the server # then you must also specify it here. -# Note that 2.4 client/server will automatically +# Note that v2.4 client/server will automatically # negotiate AES-256-GCM in TLS mode. # See also the ncp-cipher option in the manpage cipher AES-256-CBC diff --git a/sample/sample-config-files/server.conf b/sample/sample-config-files/server.conf index aa7d5b39a43..1dd477bd769 100644 --- a/sample/sample-config-files/server.conf +++ b/sample/sample-config-files/server.conf @@ -246,13 +246,13 @@ tls-auth ta.key 0 # This file is secret # Select a cryptographic cipher. # This config item must be copied to # the client config file as well. -# Note that 2.4 client/server will automatically +# Note that v2.4 client/server will automatically # negotiate AES-256-GCM in TLS mode. # See also the ncp-cipher option in the manpage cipher AES-256-CBC # Enable compression on the VPN link and push the -# option to the client (2.4+ only, for earlier +# option to the client (v2.4+ only, for earlier # versions see below) ;compress lz4-v2 ;push "compress lz4-v2" diff --git a/src/openvpn/options.c b/src/openvpn/options.c index a92702e37d6..79429d528b5 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -6208,7 +6208,7 @@ add_option(struct options *options, else if (streq(p[0], "max-routes") && !p[2]) { msg(M_WARN, "DEPRECATED OPTION: --max-routes option ignored." - "The number of routes is unlimited as of version 2.4. " + "The number of routes is unlimited as of OpenVPN 2.4. " "This option will be removed in a future version, " "please remove it from your configuration."); } @@ -7039,7 +7039,7 @@ add_option(struct options *options, VERIFY_PERMISSION(OPT_P_GENERAL); if (streq(p[1], "env")) { - msg(M_INFO, "NOTE: --win-sys env is default from OpenVPN v2.3. " + msg(M_INFO, "NOTE: --win-sys env is default from OpenVPN 2.3. " "This entry will now be ignored. " "Please remove this entry from your configuration file."); } @@ -7885,7 +7885,7 @@ add_option(struct options *options, msg(msglevel, "you cannot use --compat-names with --verify-x509-name"); goto err; } - msg(M_WARN, "DEPRECATED OPTION: --compat-names, please update your configuration. This will be removed in OpenVPN v2.5."); + msg(M_WARN, "DEPRECATED OPTION: --compat-names, please update your configuration. This will be removed in OpenVPN 2.5."); compat_flag(COMPAT_FLAG_SET | COMPAT_NAMES); #if P2MP_SERVER if (p[1] && streq(p[1], "no-remapping")) @@ -7901,7 +7901,7 @@ add_option(struct options *options, msg(msglevel, "you cannot use --no-name-remapping with --verify-x509-name"); goto err; } - msg(M_WARN, "DEPRECATED OPTION: --no-name-remapping, please update your configuration. This will be removed in OpenVPN v2.5."); + msg(M_WARN, "DEPRECATED OPTION: --no-name-remapping, please update your configuration. This will be removed in OpenVPN 2.5."); compat_flag(COMPAT_FLAG_SET | COMPAT_NAMES); compat_flag(COMPAT_FLAG_SET | COMPAT_NO_NAME_REMAPPING); #endif From 78b329180bc1f1365b421907c6ad370c448db406 Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Mon, 24 Jul 2017 22:35:59 +0800 Subject: [PATCH 615/643] rename mroute_extract_addr_ipv4 to mroute_extract_addr_ip mroute_extract_addr_ipv4() is able to extract an IPv4 as well as an IPv6. Remove the "v4" suffix from its name to make this behaviour more explicit. Signed-off-by: Antonio Quartulli Acked-by: David Sommerseth Message-Id: <20170724143559.11503-1-a@unstable.cc> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15129.html Signed-off-by: David Sommerseth (cherry picked from commit 3b38c43b8d7aa22b3df12029ff43e0414891e48c) --- src/openvpn/mroute.c | 7 +++---- src/openvpn/mroute.h | 8 ++++---- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/openvpn/mroute.c b/src/openvpn/mroute.c index 7b46a6a2d4b..74ee360c1be 100644 --- a/src/openvpn/mroute.c +++ b/src/openvpn/mroute.c @@ -159,9 +159,8 @@ mroute_extract_addr_arp(struct mroute_addr *src, #endif /* ifdef ENABLE_PF */ unsigned int -mroute_extract_addr_ipv4(struct mroute_addr *src, - struct mroute_addr *dest, - const struct buffer *buf) +mroute_extract_addr_ip(struct mroute_addr *src, struct mroute_addr *dest, + const struct buffer *buf) { unsigned int ret = 0; if (BLEN(buf) >= 1) @@ -267,7 +266,7 @@ mroute_extract_addr_ether(struct mroute_addr *src, switch (ntohs(eth->proto)) { case OPENVPN_ETH_P_IPV4: - ret |= (mroute_extract_addr_ipv4(esrc, edest, &b) << MROUTE_SEC_SHIFT); + ret |= (mroute_extract_addr_ip(esrc, edest, &b) << MROUTE_SEC_SHIFT); break; case OPENVPN_ETH_P_ARP: diff --git a/src/openvpn/mroute.h b/src/openvpn/mroute.h index e57a9506ed2..35361fbd506 100644 --- a/src/openvpn/mroute.h +++ b/src/openvpn/mroute.h @@ -181,9 +181,9 @@ mroute_extract_addr_from_packet(struct mroute_addr *src, const struct buffer *buf, int tunnel_type) { - unsigned int mroute_extract_addr_ipv4(struct mroute_addr *src, - struct mroute_addr *dest, - const struct buffer *buf); + unsigned int mroute_extract_addr_ip(struct mroute_addr *src, + struct mroute_addr *dest, + const struct buffer *buf); unsigned int mroute_extract_addr_ether(struct mroute_addr *src, struct mroute_addr *dest, @@ -195,7 +195,7 @@ mroute_extract_addr_from_packet(struct mroute_addr *src, verify_align_4(buf); if (tunnel_type == DEV_TYPE_TUN) { - ret = mroute_extract_addr_ipv4(src, dest, buf); + ret = mroute_extract_addr_ip(src, dest, buf); } else if (tunnel_type == DEV_TYPE_TAP) { From 9df6a9f66463e0b3ffe3c186b213e80942c13b52 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Fri, 7 Jul 2017 12:47:04 +0800 Subject: [PATCH 616/643] crypto: create function to initialize encrypt and decrypt key Instead of always initialize the encrypt and decrypt keys separately, implement an helper function init_key_ctx_bi() that takes care of both of them for us. Reduces code duplication and improves readability. Signed-off-by: Steffan Karger Acked-by: Antonio Quartulli Message-Id: <20170707044704.7239-1-a@unstable.cc> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15011.html Signed-off-by: David Sommerseth (cherry picked from commit 974513ea64020c956b531b1cabd76fdbac6655d8) --- src/openvpn/crypto.c | 29 +++++++++++++++++++++-------- src/openvpn/crypto.h | 4 ++++ src/openvpn/ssl.c | 17 ++--------------- 3 files changed, 27 insertions(+), 23 deletions(-) diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c index fbc73442d53..33d6fe1ad1c 100644 --- a/src/openvpn/crypto.c +++ b/src/openvpn/crypto.c @@ -894,6 +894,26 @@ init_key_ctx(struct key_ctx *ctx, struct key *key, gc_free(&gc); } +void +init_key_ctx_bi(struct key_ctx_bi *ctx, const struct key2 *key2, + int key_direction, const struct key_type *kt, const char *name) +{ + char log_prefix[128] = { 0 }; + struct key_direction_state kds; + + key_direction_state_init(&kds, key_direction); + + openvpn_snprintf(log_prefix, sizeof(log_prefix), "Outgoing %s", name); + init_key_ctx(&ctx->encrypt, &key2->keys[kds.out_key], kt, + OPENVPN_OP_ENCRYPT, log_prefix); + + openvpn_snprintf(log_prefix, sizeof(log_prefix), "Incoming %s", name); + init_key_ctx(&ctx->decrypt, &key2->keys[kds.in_key], kt, + OPENVPN_OP_DECRYPT, log_prefix); + + ctx->initialized = true; +} + void free_key_ctx(struct key_ctx *ctx) { @@ -1184,7 +1204,6 @@ crypto_read_openvpn_key(const struct key_type *key_type, { struct key2 key2; struct key_direction_state kds; - char log_prefix[128] = { 0 }; if (key_inline) { @@ -1209,13 +1228,7 @@ crypto_read_openvpn_key(const struct key_type *key_type, must_have_n_keys(key_file, opt_name, &key2, kds.need_keys); /* initialize key in both directions */ - openvpn_snprintf(log_prefix, sizeof(log_prefix), "Outgoing %s", key_name); - init_key_ctx(&ctx->encrypt, &key2.keys[kds.out_key], key_type, - OPENVPN_OP_ENCRYPT, log_prefix); - openvpn_snprintf(log_prefix, sizeof(log_prefix), "Incoming %s", key_name); - init_key_ctx(&ctx->decrypt, &key2.keys[kds.in_key], key_type, - OPENVPN_OP_DECRYPT, log_prefix); - + init_key_ctx_bi(ctx, &key2, key_direction, key_type, key_name); secure_memzero(&key2, sizeof(key2)); } diff --git a/src/openvpn/crypto.h b/src/openvpn/crypto.h index 501d96783bb..0cdd30fcd4b 100644 --- a/src/openvpn/crypto.h +++ b/src/openvpn/crypto.h @@ -323,6 +323,10 @@ void init_key_ctx(struct key_ctx *ctx, struct key *key, void free_key_ctx(struct key_ctx *ctx); +void init_key_ctx_bi(struct key_ctx_bi *ctx, const struct key2 *key2, + int key_direction, const struct key_type *kt, + const char *name); + void free_key_ctx_bi(struct key_ctx_bi *ctx); diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 1aad09d7890..bbc117c6d21 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -1840,20 +1840,8 @@ generate_key_expansion(struct key_ctx_bi *key, } /* Initialize OpenSSL key contexts */ - - ASSERT(server == true || server == false); - - init_key_ctx(&key->encrypt, - &key2.keys[(int)server], - key_type, - OPENVPN_OP_ENCRYPT, - "Data Channel Encrypt"); - - init_key_ctx(&key->decrypt, - &key2.keys[1-(int)server], - key_type, - OPENVPN_OP_DECRYPT, - "Data Channel Decrypt"); + int key_direction = server ? KEY_DIRECTION_INVERSE : KEY_DIRECTION_NORMAL; + init_key_ctx_bi(key, &key2, key_direction, key_type, "Data Channel"); /* Initialize implicit IVs */ key_ctx_update_implicit_iv(&key->encrypt, key2.keys[(int)server].hmac, @@ -1861,7 +1849,6 @@ generate_key_expansion(struct key_ctx_bi *key, key_ctx_update_implicit_iv(&key->decrypt, key2.keys[1-(int)server].hmac, MAX_HMAC_KEY_LENGTH); - key->initialized = true; ret = true; exit: From e12d5e35d56103357301d28e3f9ee0468e306bb1 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Tue, 8 Aug 2017 17:55:41 +0200 Subject: [PATCH 617/643] Add coverity static analysis to Travis CI config Enable coverity analysis for the release/2.4 branch. We can only do a limited number of coverity scans per week with our FOSS account, but since we only occasionally push commits, that should work out fine. But this limit is the reason we don't use the standard travis addon, because that would cause the coverity script to run on all of our matrix builds. That would cause us to reach our limit faster, and waste travis' resources. Since our FOSS coverity account doesn't handle multiple branches very well, we have to pick one branch to run coverity on. I think it's best to use the most recent stable branch for that (i.e. for now, release/2.4). Though for ease of maintenance, it's probably best to apply the patch to both master and release/2.4. Signed-off-by: Steffan Karger Acked-by: Antonio Quartulli Message-Id: <1502207741-31750-1-git-send-email-steffan.karger@fox-it.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15176.html Signed-off-by: David Sommerseth (cherry picked from commit 4a05f15c9aafe314ae4d3642813ebf234c09276e) --- .travis.yml | 8 +++++++- .travis/coverity.sh | 17 +++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100755 .travis/coverity.sh diff --git a/.travis.yml b/.travis.yml index 0b53152904b..79aa8c99023 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,10 +21,13 @@ env: - OPENSSL_VERSION="1.0.2l" - OPENSSL_CFLAGS="-I${PREFIX}/include" - OPENSSL_LIBS="-L${PREFIX}/lib -lssl -lcrypto" + # The next declaration is the encrypted COVERITY_SCAN_TOKEN, created + # via the "travis encrypt" command using the project repo's public key + - secure: "l9mSnEW4LJqjxftH5i1NdDaYfGmQB1mPXnSB3DXnsjzkCWZ+yJLfBemfQ0tx/wS7chBYxqUaUIMT0hw4zJVp/LANFJo2vfh//ymTS6h0uApRY1ofg9Pp1BFcV1laG6/u8pwSZ2EBy/GhCd3DS436oE8sYBRaFM9FU62L/oeQBfJ7r4ID/0eB1b8bqlbD4paty9MHui2P8EZJwR+KAD84prtfpZOcrSMxPh9OUhJxzxUvvVoP4s4+lZ5Kgg1bBQ3yzKGDqe8VOgK2BWCEuezqhMMc8oeKmAe7CUkoz5gsGYH++k3I9XzP9Z4xeJKoQnC/82qi4xkJmlaOxdionej9bHIcjfRt7D8j1J0U+wOj4p8VrDy7yHaxuN2fi0K5MGa/CaXQSrkna8dePniCng+xQ2MY/zxuRX2gA6xPNLUyQLU9LqIug7wj4z84Hk9iWib4L20MoPjeEo+vAUNq8FtjOPxMuHNpv4iGGx6kgJm7RXl5vC5hxfK6MprrnYe2U5Mcd8jpzagKBaKHL3zV2FxX9k0jRO9Mccz7M2WnaV0MQ6zcngzTN4+s0kCjhfGKd2F2ANT2Gkhj3Me36eNHfuE0dBbvYCMh4b3Mgd7b/OuXwQWdJ8PjJ1WHXjSOw5sHw1suaV6cEO2Meyz5j1tOkyOi0M9QF+LFenQ9vLH4sBCww8U=" matrix: include: - - env: SSLLIB="openssl" + - env: SSLLIB="openssl" RUN_COVERITY="1" os: linux compiler: gcc - env: SSLLIB="openssl" OPENSSL_VERSION="1.1.0f" @@ -91,5 +94,8 @@ install: - if [ ! -z "${CHOST}" ]; then unset CC; fi - .travis/build-deps.sh > build-deps.log 2>&1 || (cat build-deps.log && exit 1) +before_script: + - .travis/coverity.sh + script: - .travis/build-check.sh diff --git a/.travis/coverity.sh b/.travis/coverity.sh new file mode 100755 index 00000000000..8bb40f48135 --- /dev/null +++ b/.travis/coverity.sh @@ -0,0 +1,17 @@ +#!/bin/sh +set -eu + +RUN_COVERITY="${RUN_COVERITY:-0}" + +export COVERITY_SCAN_PROJECT_NAME="OpenVPN/openvpn" +export COVERITY_SCAN_BRANCH_PATTERN="release\/2.4" +export COVERITY_SCAN_NOTIFICATION_EMAIL="scan-reports@openvpn.net" +export COVERITY_SCAN_BUILD_COMMAND_PREPEND="autoreconf -vi && ./configure --enable-iproute2 && make clean" +export COVERITY_SCAN_BUILD_COMMAND="make" + +if [ "${RUN_COVERITY}" = "1" ]; then + # Ignore exit code, script exits with 1 if we're not on the right branch + curl -s "https://scan.coverity.com/scripts/travisci_build_coverity_scan.sh" | bash || true +else + echo "Skipping coverity scan because \$RUN_COVERITY != \"1\"" +fi From 3c4e2a39de509bb445a86fba9573f07880ac541c Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Wed, 16 Aug 2017 20:55:04 +0800 Subject: [PATCH 618/643] route: avoid definition of unused variables in certain configurations Although this patch adds more ifdefs, this is an easy fix towards a no-warning-build process. A proper cleanup should be carried out later on route.c. Signed-off-by: Antonio Quartulli Reviewed-by: Steffan Karger Acked-by: David Sommerseth Message-Id: <20170816125504.21181-1-a@unstable.cc> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15272.html Signed-off-by: David Sommerseth (cherry picked from commit 22e75ca1a88b83e83a12b7d7d0095651f547411d) --- src/openvpn/route.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/openvpn/route.c b/src/openvpn/route.c index 1d8bb001541..8c71e6ecb95 100644 --- a/src/openvpn/route.c +++ b/src/openvpn/route.c @@ -1530,7 +1530,9 @@ add_route(struct route_ipv4 *r, struct gc_arena gc; struct argv argv = argv_new(); const char *network; +#if !defined(ENABLE_IPROUTE) && !defined(TARGET_AIX) const char *netmask; +#endif const char *gateway; bool status = false; int is_local_route; @@ -1543,7 +1545,9 @@ add_route(struct route_ipv4 *r, gc_init(&gc); network = print_in_addr_t(r->network, 0, &gc); +#if !defined(ENABLE_IPROUTE) && !defined(TARGET_AIX) netmask = print_in_addr_t(r->netmask, 0, &gc); +#endif gateway = print_in_addr_t(r->gateway, 0, &gc); is_local_route = local_route(r->network, r->netmask, r->gateway, rgi); @@ -2132,8 +2136,12 @@ delete_route(struct route_ipv4 *r, struct gc_arena gc; struct argv argv = argv_new(); const char *network; +#if !defined(ENABLE_IPROUTE) && !defined(TARGET_AIX) const char *netmask; +#endif +#if !defined(TARGET_LINUX) && !defined(TARGET_ANDROID) const char *gateway; +#endif int is_local_route; if ((r->flags & (RT_DEFINED|RT_ADDED)) != (RT_DEFINED|RT_ADDED)) @@ -2144,8 +2152,12 @@ delete_route(struct route_ipv4 *r, gc_init(&gc); network = print_in_addr_t(r->network, 0, &gc); +#if !defined(ENABLE_IPROUTE) && !defined(TARGET_AIX) netmask = print_in_addr_t(r->netmask, 0, &gc); +#endif +#if !defined(TARGET_LINUX) && !defined(TARGET_ANDROID) gateway = print_in_addr_t(r->gateway, 0, &gc); +#endif is_local_route = local_route(r->network, r->netmask, r->gateway, rgi); if (is_local_route == LR_ERROR) From db52b6df6915d38a269bf68767faefd9cebf33bb Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Wed, 16 Aug 2017 19:04:50 +0200 Subject: [PATCH 619/643] tls-crypt: don't leak memory for incorrect tls-crypt messages If tls_crypt_unwrap() failed, we would jump to cleanup and forget to free the buffer. Instead, allocate the buffer through gc, which is free'd in the cleanup section. Signed-off-by: Steffan Karger Acked-by: David Sommerseth Message-Id: <20170816170450.10415-1-steffan@karger.me> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15282.html Signed-off-by: David Sommerseth (cherry picked from commit fca89379c53fe2c145db96a5bcd32327c4bcfa78) --- src/openvpn/ssl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index bbc117c6d21..0739cf7c1c7 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -1534,7 +1534,7 @@ read_control_auth(struct buffer *buf, } else if (ctx->mode == TLS_WRAP_CRYPT) { - struct buffer tmp = alloc_buf(buf_forward_capacity_total(buf)); + struct buffer tmp = alloc_buf_gc(buf_forward_capacity_total(buf), &gc); if (!tls_crypt_unwrap(buf, &tmp, &ctx->opt)) { msg(D_TLS_ERRORS, "TLS Error: tls-crypt unwrapping failed from %s", @@ -1543,7 +1543,7 @@ read_control_auth(struct buffer *buf, } ASSERT(buf_init(buf, buf->offset)); ASSERT(buf_copy(buf, &tmp)); - free_buf(&tmp); + buf_clear(&tmp); } if (ctx->mode == TLS_WRAP_NONE || ctx->mode == TLS_WRAP_AUTH) From 010ffbed20bcb19c59aeb6e46ae76d93c08c67ea Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Sat, 19 Aug 2017 15:52:09 +0800 Subject: [PATCH 620/643] fix a couple of typ0s in comments and strings Signed-off-by: Antonio Quartulli Acked-by: David Sommerseth Message-Id: <20170819075209.28520-1-a@unstable.cc> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15293.html Signed-off-by: David Sommerseth (cherry picked from commit 42d9f324f7362abfb9b51b24ef0fb7635b0194fc) --- configure.ac | 2 +- src/openvpn/block_dns.h | 2 +- src/openvpn/buffer.h | 2 +- src/openvpn/options.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index baeff41b073..db671875515 100644 --- a/configure.ac +++ b/configure.ac @@ -230,7 +230,7 @@ AC_ARG_ENABLE( AC_ARG_ENABLE( [werror], - [AS_HELP_STRING([--enable-werror], [promote compiler warnings to errors, will cause builds to fail is the compiler issues warnings (debugging option) @<:@default=no@:>@])], + [AS_HELP_STRING([--enable-werror], [promote compiler warnings to errors, will cause builds to fail if the compiler issues warnings (debugging option) @<:@default=no@:>@])], , [enable_werror="no"] ) diff --git a/src/openvpn/block_dns.h b/src/openvpn/block_dns.h index c4b6693b0bf..c9a9d7088e8 100644 --- a/src/openvpn/block_dns.h +++ b/src/openvpn/block_dns.h @@ -26,7 +26,7 @@ #ifndef OPENVPN_BLOCK_DNS_H #define OPENVPN_BLOCK_DNS_H -/* Any value less than 5 should work fine. 3 is choosen without any real reason. */ +/* Any value less than 5 should work fine. 3 is chosen without any real reason. */ #define BLOCK_DNS_IFACE_METRIC 3 typedef void (*block_dns_msg_handler_t) (DWORD err, const char *msg); diff --git a/src/openvpn/buffer.h b/src/openvpn/buffer.h index 8bc44287351..1ed56316c95 100644 --- a/src/openvpn/buffer.h +++ b/src/openvpn/buffer.h @@ -91,7 +91,7 @@ struct gc_entry }; /** - * Gargabe collection entry for a specially allocated structure that needs + * Garbage collection entry for a specially allocated structure that needs * a custom free function to be freed like struct addrinfo * */ diff --git a/src/openvpn/options.h b/src/openvpn/options.h index 67b9b94df43..01a7b267ca7 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -181,7 +181,7 @@ struct options /* enable forward compatibility for post-2.1 features */ bool forward_compatible; - /* list of options that should be ignored even if unkown */ + /* list of options that should be ignored even if unknown */ const char **ignore_unknown_option; /* persist parms */ From b437bf1c0f60cc5e42d70334bde83a2f9e09be88 Mon Sep 17 00:00:00 2001 From: Richard Bonhomme Date: Sat, 19 Aug 2017 21:37:35 +0100 Subject: [PATCH 621/643] man: Corrections to doc/openvpn.8 Correct usage example: --verify-x509-name name-stub- name-prefix This was to correct "--verfiy-x509-name Server -name-prexif" to "--verify-x509-name Server- name-prefix" Escape all dashes (with some exceptions) [DS: On-the-fly change - Updated copyright year from 2010 to 2017] Signed-off-by: Richard Bonhomme Acked-by: David Sommerseth Message-Id: <20170819203735.8681-1-fragmentux@gmail.com> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15297.html Signed-off-by: David Sommerseth (cherry picked from commit 510c8ade804566868a1e0aa4e046a69e576f4478) --- doc/openvpn.8 | 778 +++++++++++++++++++++++++------------------------- 1 file changed, 389 insertions(+), 389 deletions(-) diff --git a/doc/openvpn.8 b/doc/openvpn.8 index eda2a4cdb56..204374736ba 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -77,14 +77,14 @@ of its crypto capabilities from it. OpenVPN supports conventional encryption -using a pre-shared secret key +using a pre\-shared secret key .B (Static Key mode) or public key security .B (SSL/TLS mode) using client & server certificates. OpenVPN also -supports non-encrypted TCP/UDP tunnels. +supports non\-encrypted TCP/UDP tunnels. OpenVPN is designed to work with the .B TUN/TAP @@ -96,7 +96,7 @@ with a relatively lightweight footprint. .SH OPTIONS OpenVPN allows any option to be placed either on the command line or in a configuration file. Though all command line options are preceded -by a double-leading-dash ("\-\-"), this prefix can be removed when +by a double\-leading\-dash ("\-\-"), this prefix can be removed when an option is placed in a configuration file. .\"********************************************************* .TP @@ -126,7 +126,7 @@ can be used to enclose single parameters containing whitespace, and "#" or ";" characters in the first column can be used to denote comments. -Note that OpenVPN 2.0 and higher performs backslash-based shell +Note that OpenVPN 2.0 and higher performs backslash\-based shell escaping for characters not in single quotations, so the following mappings should be observed: @@ -164,7 +164,7 @@ Here is an example configuration file: .in +4 # # Sample OpenVPN configuration file for -# using a pre-shared static key. +# using a pre\-shared static key. # # '#' or ';' may be used to delimit comments. @@ -178,7 +178,7 @@ remote mypeer.mydomain # 10.1.0.2 is our remote VPN endpoint ifconfig 10.1.0.1 10.1.0.2 -# Our pre-shared static key +# Our pre\-shared static key secret static.key .in -4 .ft @@ -188,8 +188,8 @@ secret static.key .TP .B \-\-mode m Set OpenVPN major mode. By default, OpenVPN runs in -point-to-point mode ("p2p"). OpenVPN 2.0 introduces -a new mode ("server") which implements a multi-client +point\-to\-point mode ("p2p"). OpenVPN 2.0 introduces +a new mode ("server") which implements a multi\-client server capability. .\"********************************************************* .TP @@ -206,7 +206,7 @@ options may be specified for redundancy, each referring to a different OpenVPN server. Specifying multiple .B \-\-remote options for this purpose is a special case of the more -general connection-profile feature. See the +general connection\-profile feature. See the .B documentation below. @@ -243,7 +243,7 @@ the client with .B \-\-user and/or .B \-\-group, -AND the client is running a non-Windows OS, if the client needs +AND the client is running a non\-Windows OS, if the client needs to switch to a different server, and that server pushes back different TUN/TAP or route settings, the client may lack the necessary privileges to close and reopen the TUN/TAP interface. @@ -277,7 +277,7 @@ and IPv6 addresses, in the order getaddrinfo() returns them. .B \-\-remote\-random\-hostname Prepend a random string (6 bytes, 12 hex characters) to hostname to prevent DNS caching. For example, "foo.bar.gov" would be modified to -".foo.bar.gov". +".foo.bar.gov". .\"********************************************************* .TP .B @@ -404,7 +404,7 @@ When multiple .B \-\-remote address/ports are specified, or if connection profiles are being used, initially randomize the order of the list -as a kind of basic load-balancing measure. +as a kind of basic load\-balancing measure. .\"********************************************************* .TP .B \-\-proto p @@ -453,12 +453,12 @@ networks. This article outlines some of problems with tunneling IP over TCP: -.I http://sites.inka.de/sites/bigred/devel/tcp-tcp.html +.I http://sites.inka.de/sites/bigred/devel/tcp\-tcp.html There are certain cases, however, where using TCP may be advantageous from -a security and robustness perspective, such as tunneling non-IP or -application-level UDP protocols, or tunneling protocols which don't -possess a built-in reliability layer. +a security and robustness perspective, such as tunneling non\-IP or +application\-level UDP protocols, or tunneling protocols which don't +possess a built\-in reliability layer. .\"********************************************************* .TP .B \-\-connect\-retry n [max] @@ -489,12 +489,12 @@ Show sensed HTTP or SOCKS proxy settings. Currently, only Windows clients support this option. .\"********************************************************* .TP -.B \-\-http\-proxy server port [authfile|'auto'|'auto\-nct'] [auth-method] +.B \-\-http\-proxy server port [authfile|'auto'|'auto\-nct'] [auth\-method] Connect to remote host through an HTTP proxy at address .B server and port .B port. -If HTTP Proxy-Authenticate is required, +If HTTP Proxy\-Authenticate is required, .B authfile is a file containing a username and password on 2 lines, or "stdin" to prompt from console. Its content can also be specified @@ -522,7 +522,7 @@ exists on OpenVPN 2.1 or higher. The .B auto\-nct -flag (no clear-text auth) instructs OpenVPN to automatically +flag (no clear\-text auth) instructs OpenVPN to automatically determine the authentication method, but to reject weak authentication protocols such as HTTP Basic Authentication. .\"********************************************************* @@ -531,16 +531,16 @@ authentication protocols such as HTTP Basic Authentication. Set extended HTTP proxy options. Repeat to set multiple options. -.B VERSION version -- +.B VERSION version \-\- Set HTTP version number to .B version (default=1.0). -.B AGENT user-agent -- -Set HTTP "User-Agent" string to -.B user-agent. +.B AGENT user\-agent \-\- +Set HTTP "User\-Agent" string to +.B user\-agent. -.B CUSTOM\-HEADER name content -- +.B CUSTOM\-HEADER name content \-\- Adds the custom Header with .B name as name and @@ -588,7 +588,7 @@ at a known address, however if packets arrive from a new address and pass all authentication tests, the new address will take control of the session. This is useful when you are connecting to a peer which holds a dynamic address -such as a dial-in user or DHCP client. +such as a dial\-in user or DHCP client. Essentially, .B \-\-float @@ -601,12 +601,12 @@ option. .B \-\-ipchange cmd Run command .B cmd -when our remote ip-address is initially authenticated or +when our remote ip\-address is initially authenticated or changes. .B cmd consists of a path to script (or executable program), optionally -followed by arguments. The path and arguments may be single- or double-quoted +followed by arguments. The path and arguments may be single\- or double\-quoted and/or escaped using a backslash, and should be separated by one or more spaces. When @@ -656,7 +656,7 @@ and .B \-\-rport options to given port). The current default of 1194 represents the official IANA port number -assignment for OpenVPN and has been used since version 2.0-beta17. +assignment for OpenVPN and has been used since version 2.0\-beta17. Previous versions used port 5000 as the default. .\"********************************************************* .TP @@ -717,9 +717,9 @@ devices encapsulate IPv4 or IPv6 (OSI Layer 3) while devices encapsulate Ethernet 802.3 (OSI Layer 2). .\"********************************************************* .TP -.B \-\-dev\-type device-type +.B \-\-dev\-type device\-type Which device type are we using? -.B device-type +.B device\-type should be .B tun (OSI Layer 3) @@ -756,13 +756,13 @@ directive, this directive must always be compatible between client and server. can be one of: .B net30 \-\- -Use a point-to-point topology, by allocating one /30 subnet per client. -This is designed to allow point-to-point semantics when some +Use a point\-to\-point topology, by allocating one /30 subnet per client. +This is designed to allow point\-to\-point semantics when some or all of the connecting clients might be Windows systems. This is the default on OpenVPN 2.0. .B p2p \-\- -Use a point-to-point topology where the remote endpoint of the client's +Use a point\-to\-point topology where the remote endpoint of the client's tun interface always points to the local endpoint of the server's tun interface. This mode allocates a single IP address per connecting client. Only use @@ -773,7 +773,7 @@ directive which is available in OpenVPN 2.0, is deprecated and will be removed in OpenVPN 2.5 .B subnet \-\- -Use a subnet rather than a point-to-point topology by +Use a subnet rather than a point\-to\-point topology by configuring the tun interface with a local IP address and subnet mask, similar to the topology used in .B \-\-dev tap @@ -783,7 +783,7 @@ Windows as well. Only available when server and clients are OpenVPN 2.1 or higher, or OpenVPN 2.0.x which has been manually patched with the .B \-\-topology directive code. When used on Windows, requires version 8.2 or higher -of the TAP-Win32 driver. When used on *nix, requires that the tun +of the TAP\-Win32 driver. When used on *nix, requires that the tun driver supports an .BR ifconfig (8) command which sets a subnet instead of a remote endpoint IP address. @@ -819,7 +819,7 @@ When not specifying a .B \-\-dev\-node option openvpn will first try to open utun, and fall back to tun.kext. -On Windows systems, select the TAP-Win32 adapter which +On Windows systems, select the TAP\-Win32 adapter which is named .B node in the Network Connections Control Panel or the @@ -827,10 +827,10 @@ raw GUID of the adapter enclosed by braces. The .B \-\-show\-adapters option under Windows can also be used -to enumerate all available TAP-Win32 +to enumerate all available TAP\-Win32 adapters and will show both the network connections control panel name and the GUID for -each TAP-Win32 adapter. +each TAP\-Win32 adapter. .TP .B \-\-lladdr address Specify the link layer address, more commonly known as the MAC address. @@ -846,7 +846,7 @@ May be used in order to execute OpenVPN in unprivileged environment. Set TUN/TAP adapter parameters. .B l is the IP address of the local VPN endpoint. -For TUN devices in point-to-point mode, +For TUN devices in point\-to\-point mode, .B rn is the IP address of the remote VPN endpoint. For TAP devices, or TUN devices used with @@ -856,7 +856,7 @@ is the subnet mask of the virtual network segment which is being created or connected to. For TUN devices, which facilitate virtual -point-to-point IP connections (when used in +point\-to\-point IP connections (when used in .B \-\-topology net30 or .B p2p @@ -876,7 +876,7 @@ you will be pinging across the VPN. For TAP devices, which provide the ability to create virtual ethernet segments, or TUN devices in -.B --topology subnet +.B \-\-topology subnet mode (which create virtual "multipoint networks"), .B \-\-ifconfig is used to set an IP address and @@ -956,10 +956,10 @@ while at the same time providing portable semantics across OpenVPN's platform space. .B netmask -default -- 255.255.255.255 +default \-\- 255.255.255.255 .B gateway -default -- taken from +default \-\- taken from .B \-\-route\-gateway or the second parameter to .B \-\-ifconfig @@ -968,7 +968,7 @@ when is specified. .B metric -default -- taken from +default \-\- taken from .B \-\-route\-metric otherwise 0. @@ -984,7 +984,7 @@ also be specified as a DNS or /etc/hosts file resolvable name, or as one of three special keywords: .B vpn_gateway --- The remote VPN endpoint address +\-\- The remote VPN endpoint address (derived either from .B \-\-route\-gateway or the second parameter to @@ -994,11 +994,11 @@ when is specified). .B net_gateway --- The pre-existing IP default gateway, read from the routing +\-\- The pre\-existing IP default gateway, read from the routing table (not supported on all OSes). .B remote_host --- The +\-\- The .B \-\-remote address if OpenVPN is being run in client mode, and is undefined in server mode. .\"********************************************************* @@ -1013,7 +1013,7 @@ If .B dhcp is specified as the parameter, the gateway address will be extracted from a DHCP -negotiation with the OpenVPN server-side LAN. +negotiation with the OpenVPN server\-side LAN. .\"********************************************************* .TP .B \-\-route\-metric m @@ -1053,7 +1053,7 @@ On Windows, tries to be more intelligent by waiting .B w seconds (w=30 by default) -for the TAP-Win32 adapter to come up before adding routes. +for the TAP\-Win32 adapter to come up before adding routes. .\"********************************************************* .TP .B \-\-route\-up cmd @@ -1064,7 +1064,7 @@ after routes are added, subject to .B cmd consists of a path to script (or executable program), optionally -followed by arguments. The path and arguments may be single- or double-quoted +followed by arguments. The path and arguments may be single\- or double\-quoted and/or escaped using a backslash, and should be separated by one or more spaces. See the "Environmental Variables" section below for @@ -1078,7 +1078,7 @@ before routes are removed upon disconnection. .B cmd consists of a path to script (or executable program), optionally -followed by arguments. The path and arguments may be single- or double-quoted +followed by arguments. The path and arguments may be single\- or double\-quoted and/or escaped using a backslash, and should be separated by one or more spaces. See the "Environmental Variables" section below for @@ -1096,7 +1096,7 @@ When used with .B \-\-client or .B \-\-pull, -accept options pushed by server EXCEPT for routes, block-outside-dns and dhcp +accept options pushed by server EXCEPT for routes, block\-outside\-dns and dhcp options like DNS servers. When used on the client, this option effectively bars the @@ -1115,7 +1115,7 @@ and .\"********************************************************* .TP .B \-\-client\-nat snat|dnat network netmask alias -This pushable client option sets up a stateless one-to-one NAT +This pushable client option sets up a stateless one\-to\-one NAT rule on packet addresses (not ports), and is useful in cases where routes or ifconfig settings pushed to the client would create an IP numbering conflict. @@ -1141,14 +1141,14 @@ addresses in packets. .TP .B \-\-redirect\-gateway flags... Automatically execute routing commands to cause all outgoing IP traffic -to be redirected over the VPN. This is a client-side option. +to be redirected over the VPN. This is a client\-side option. This option performs three steps: .B (1) Create a static route for the .B \-\-remote -address which forwards to the pre-existing default gateway. +address which forwards to the pre\-existing default gateway. This is done so that .B (3) will not create a routing loop. @@ -1185,39 +1185,39 @@ Try to automatically determine whether to enable .B local flag above. -.B def1 -- +.B def1 \-\- Use this flag to override the default gateway by using 0.0.0.0/1 and 128.0.0.0/1 rather than 0.0.0.0/0. This has the benefit of overriding but not wiping out the original default gateway. -.B bypass-dhcp -- -Add a direct route to the DHCP server (if it is non-local) which +.B bypass\-dhcp \-\- +Add a direct route to the DHCP server (if it is non\-local) which bypasses the tunnel (Available on Windows clients, may not be available -on non-Windows clients). +on non\-Windows clients). -.B bypass-dns -- -Add a direct route to the DNS server(s) (if they are non-local) which +.B bypass\-dns \-\- +Add a direct route to the DNS server(s) (if they are non\-local) which bypasses the tunnel (Available on Windows clients, may not be available -on non-Windows clients). +on non\-Windows clients). -.B block-local -- +.B block\-local \-\- Block access to local LAN when the tunnel is active, except for the LAN gateway itself. This is accomplished by routing the local LAN (except for the LAN gateway address) into the tunnel. -.B ipv6 -- +.B ipv6 \-\- Redirect IPv6 routing into the tunnel. This works similar to the .B def1 flag, that is, more specific IPv6 routes are added (2000::/4, 3000::/4), covering the whole IPv6 unicast space. -.B !ipv4 -- -Do not redirect IPv4 traffic - typically used in the flag pair +.B !ipv4 \-\- +Do not redirect IPv4 traffic \- typically used in the flag pair .B "ipv6 !ipv4" -to redirect IPv6-only. +to redirect IPv6\-only. .\"********************************************************* .TP .B \-\-link\-mtu n @@ -1271,13 +1271,13 @@ Should we do Path MTU discovery on TCP/UDP channel? Only supported on OSes such as Linux that supports the necessary system call to set. .B 'no' --- Never send DF (Don't Fragment) frames +\-\- Never send DF (Don't Fragment) frames .br .B 'maybe' --- Use per-route hints +\-\- Use per\-route hints .br .B 'yes' --- Always DF (Don't Fragment) +\-\- Always DF (Don't Fragment) .br .\"********************************************************* .TP @@ -1357,7 +1357,7 @@ without IP level fragmentation. The .B \-\-mssfix option only makes sense when you are using the UDP protocol -for OpenVPN peer-to-peer communication, i.e. +for OpenVPN peer\-to\-peer communication, i.e. .B \-\-proto udp. .B \-\-mssfix @@ -1396,7 +1396,7 @@ parameter from the option. Therefore, one could lower the maximum UDP packet size -to 1300 (a good first try for solving MTU-related +to 1300 (a good first try for solving MTU\-related connection problems) with the following options: .B \-\-tun\-mtu 1500 \-\-fragment 1300 \-\-mssfix @@ -1459,11 +1459,11 @@ seconds before queuing the next write. It should be noted that OpenVPN supports multiple tunnels between the same two peers, allowing you -to construct full-speed and reduced bandwidth tunnels +to construct full\-speed and reduced bandwidth tunnels at the same time, -routing low-priority data such as off-site backups +routing low\-priority data such as off\-site backups over the reduced bandwidth tunnel, and other data -over the full-speed tunnel. +over the full\-speed tunnel. Also note that for low bandwidth tunnels (under 1000 bytes per second), you should probably @@ -1538,7 +1538,7 @@ This option can be combined with .B \-\-inactive, \-\-ping, and .B \-\-ping\-exit -to create a two-tiered inactivity disconnect. +to create a two\-tiered inactivity disconnect. For example, @@ -1561,7 +1561,7 @@ or other packet from remote. This option is useful in cases where the remote peer has a dynamic IP address and -a low-TTL DNS name is used to track the IP address using +a low\-TTL DNS name is used to track the IP address using a service such as .I http://dyndns.org/ + a dynamic DNS client such @@ -1571,7 +1571,7 @@ as If the peer cannot be reached, a restart will be triggered, causing the hostname used with .B \-\-remote -to be re-resolved (if +to be re\-resolved (if .B \-\-resolv\-retry is also specified). @@ -1677,12 +1677,12 @@ restarts. .B SIGUSR1 is a restart signal similar to .B SIGHUP, -but which offers finer-grained control over +but which offers finer\-grained control over reset options. .\"********************************************************* .TP .B \-\-persist\-key -Don't re-read key files across +Don't re\-read key files across .B SIGUSR1 or .B \-\-ping\-restart. @@ -1693,12 +1693,12 @@ to allow restarts triggered by the .B SIGUSR1 signal. Normally if you drop root privileges in OpenVPN, -the daemon cannot be restarted since it will now be unable to re-read protected +the daemon cannot be restarted since it will now be unable to re\-read protected key files. This option solves the problem by persisting keys across .B SIGUSR1 -resets, so they don't need to be re-read. +resets, so they don't need to be re\-read. .\"********************************************************* .TP .B \-\-persist\-local\-ip @@ -1755,7 +1755,7 @@ UID change). .B cmd consists of a path to script (or executable program), optionally -followed by arguments. The path and arguments may be single- or double-quoted +followed by arguments. The path and arguments may be single\- or double\-quoted and/or escaped using a backslash, and should be separated by one or more spaces. The up command is useful for specifying route @@ -1780,7 +1780,7 @@ additional parameters passed as environmental variables. Note that if .B cmd -includes arguments, all OpenVPN-generated arguments will be appended +includes arguments, all OpenVPN\-generated arguments will be appended to them to build an argument list with which the executable will be called. @@ -1812,7 +1812,7 @@ as the last parameter. NOTE: on restart, OpenVPN will not pass the full set of environment variables to the script. Namely, everything related to routing and -gateways will not be passed, as nothing needs to be done anyway - all +gateways will not be passed, as nothing needs to be done anyway \- all the routing setup is already in place. Additionally, the up\-restart script will run with the downgraded UID/GID settings (if configured). @@ -1821,7 +1821,7 @@ The following standalone example shows how the script can be called in both an initialization and restart context. (NOTE: for security reasons, don't run the following example unless UDP port 9999 is blocked by your firewall. Also, the example will run indefinitely, -so you should abort with control-c). +so you should abort with control\-c). .B openvpn \-\-dev tun \-\-port 9999 \-\-verb 4 \-\-ping\-restart 10 \-\-up 'echo up' \-\-down 'echo down' \-\-persist\-tun \-\-up\-restart @@ -1858,7 +1858,7 @@ mode, this option normally requires the use of to allow connection initiation to be sensed in the absence of tunnel data, since UDP is a "connectionless" protocol. -On Windows, this option will delay the TAP-Win32 media state +On Windows, this option will delay the TAP\-Win32 media state transitioning to "connected" until connection establishment, i.e. the receipt of the first authenticated packet from the peer. .\"********************************************************* @@ -1874,7 +1874,7 @@ UID change and/or ). .B cmd consists of a path to script (or executable program), optionally -followed by arguments. The path and arguments may be single- or double-quoted +followed by arguments. The path and arguments may be single\- or double\-quoted and/or escaped using a backslash, and should be separated by one or more spaces. Called with the same parameters and environmental @@ -1970,7 +1970,7 @@ is available since OpenVPN 2.3.3. .\"********************************************************* .TP .B \-\-script\-security level -This directive offers policy-level control over OpenVPN's usage of external programs +This directive offers policy\-level control over OpenVPN's usage of external programs and scripts. Lower .B level values are more restrictive, higher values are more permissive. Settings for @@ -1980,10 +1980,10 @@ values are more restrictive, higher values are more permissive. Settings for Strictly no calling of external programs. .br .B 1 \-\- -(Default) Only call built-in executables such as ifconfig, ip, route, or netsh. +(Default) Only call built\-in executables such as ifconfig, ip, route, or netsh. .br .B 2 \-\- -Allow calling of built-in executables and user-defined scripts. +Allow calling of built\-in executables and user\-defined scripts. .br .B 3 \-\- Allow passwords to be passed to scripts via environmental variables (potentially unsafe). @@ -2008,14 +2008,14 @@ versions you needed to either add a full path to the script interpreter which ca script or use the .B system flag to run these scripts. As of OpenVPN 2.3 it is now a strict requirement to have -full path to the script interpreter when running non-executables files. +full path to the script interpreter when running non\-executables files. This is not needed for executable files, such as .exe, .com, .bat or .cmd files. For example, if you have a Visual Basic script, you must use this syntax now: .nf .ft 3 .in +4 -\-\-up 'C:\\\\Windows\\\\System32\\\\wscript.exe C:\\\\Program\\ Files\\\\OpenVPN\\\\config\\\\my-up-script.vbs' +\-\-up 'C:\\\\Windows\\\\System32\\\\wscript.exe C:\\\\Program\\ Files\\\\OpenVPN\\\\config\\\\my\-up\-script.vbs' .in -4 .ft .fi @@ -2065,7 +2065,7 @@ signal to a DHCP reset), you should make use of one or more of the .B \-\-persist options to ensure that OpenVPN doesn't need to execute any privileged -operations in order to restart (such as re-reading key files +operations in order to restart (such as re\-reading key files or running .BR ifconfig on the TUN device). @@ -2111,7 +2111,7 @@ This can be desirable from a security standpoint. Since the chroot operation is delayed until after initialization, most OpenVPN options that reference -files will operate in a pre-chroot context. +files will operate in a pre\-chroot context. In many cases, the .B dir @@ -2146,7 +2146,7 @@ it inside the chroot directory (e.g. with mount \-\-bind). Since the setcon operation is delayed until after initialization, OpenVPN can be restricted to just -network-related system calls, whereas by applying the +network\-related system calls, whereas by applying the context before startup (such as the OpenVPN one provided in the SELinux Reference Policies) you will have to allow many things required only during initialization. @@ -2195,11 +2195,11 @@ that initialization scripts can test the return status of the openvpn command for a fairly reliable indication of whether the command has correctly initialized and entered the packet forwarding event loop. -In OpenVPN, the vast majority of errors which occur after initialization are non-fatal. +In OpenVPN, the vast majority of errors which occur after initialization are non\-fatal. Note: as soon as OpenVPN has daemonized, it can not ask for usernames, passwords, or key pass phrases anymore. This has certain consequences, -namely that using a password-protected private key will fail unless the +namely that using a password\-protected private key will fail unless the .B \-\-askpass option is used to tell OpenVPN to ask for the pass phrase (this requirement is new in v2.3.7, and is a consequence of calling daemon() @@ -2208,9 +2208,9 @@ before initializing the crypto layer). Further, using .B \-\-daemon together with -.B \-\-auth-user-pass +.B \-\-auth\-user\-pass (entered on console) and -.B \-\-auth-nocache +.B \-\-auth\-nocache will fail as soon as key renegotiation (and reauthentication) occurs. .\"********************************************************* .TP @@ -2347,7 +2347,7 @@ less than zero is higher priority). .\".B \-\-tls\-server .\"specified). .\" -.\"Using a TLS thread offloads the CPU-intensive process of SSL/TLS-based +.\"Using a TLS thread offloads the CPU\-intensive process of SSL/TLS\-based .\"key exchange to a background thread so that it does not become .\"a latency bottleneck in the tunnel packet forwarding process. .\" @@ -2369,7 +2369,7 @@ or TUN/TAP devices. In such cases, one can optimize the event loop by avoiding the poll/epoll/select call, improving CPU efficiency by 5% to 10%. -This option can only be used on non-Windows systems, when +This option can only be used on non\-Windows systems, when .B \-\-proto udp is specified, and when .B \-\-shaper @@ -2377,7 +2377,7 @@ is NOT specified. .\"********************************************************* .TP .B \-\-multihome -Configure a multi-homed UDP server. This option needs to be used when +Configure a multi\-homed UDP server. This option needs to be used when a server has more than one IP address (e.g. multiple interfaces, or secondary IP addresses), and is not using .B \-\-local @@ -2389,10 +2389,10 @@ processing, so it's not enabled by default. Note: this option is only relevant for UDP servers. -Note 2: if you do an IPv6+IPv4 dual-stack bind on a Linux machine with +Note 2: if you do an IPv6+IPv4 dual\-stack bind on a Linux machine with multiple IPv4 address, connections to IPv4 addresses will not work right on kernels before 3.15, due to missing kernel support for the -IPv4-mapped case (some distributions have ported this to earlier kernel +IPv4\-mapped case (some distributions have ported this to earlier kernel versions, though). .\"********************************************************* .TP @@ -2492,7 +2492,7 @@ newer .B \-\-compress instead. -Use LZO compression -- may add up to 1 byte per +Use LZO compression \-\- may add up to 1 byte per packet for incompressible data. .B mode may be "yes", "no", or "adaptive" (default). @@ -2500,7 +2500,7 @@ may be "yes", "no", or "adaptive" (default). In a server mode setup, it is possible to selectively turn compression on or off for individual clients. -First, make sure the client-side config file enables selective +First, make sure the client\-side config file enables selective compression by having at least one .B \-\-comp\-lzo directive, such as @@ -2539,19 +2539,19 @@ Normally, adaptive compression is enabled with Adaptive compression tries to optimize the case where you have compression enabled, but you are sending predominantly incompressible -(or pre-compressed) packets over the tunnel, such as an FTP or rsync transfer +(or pre\-compressed) packets over the tunnel, such as an FTP or rsync transfer of a large, compressed file. With adaptive compression, OpenVPN will periodically sample the compression process to measure its efficiency. If the data being sent over the tunnel is already compressed, the compression efficiency will be very low, triggering openvpn to disable -compression for a period of time until the next re-sample test. +compression for a period of time until the next re\-sample test. .\"********************************************************* .TP -.B \-\-management IP port [pw-file] +.B \-\-management IP port [pw\-file] Enable a TCP server on .B IP:port to handle daemon management functions. -.B pw-file, +.B pw\-file, if specified, is a password file (password on first line) or "stdin" to prompt from standard input. The password @@ -2618,28 +2618,28 @@ console. .B \-\-management\-query\-proxy Query management channel for proxy server information for a specific .B \-\-remote -(client-only). +(client\-only). .\"********************************************************* .TP .B \-\-management\-query\-remote Allow management interface to override .B \-\-remote -directives (client-only). +directives (client\-only). .\"********************************************************* .TP .B \-\-management\-external\-key Allows usage for external private key file instead of .B \-\-key -option (client-only). +option (client\-only). .\"********************************************************* .TP -.B \-\-management\-external\-cert certificate-hint +.B \-\-management\-external\-cert certificate\-hint Allows usage for external certificate instead of .B \-\-cert -option (client-only). -.B certificate-hint +option (client\-only). +.B certificate\-hint is an arbitrary string which is passed to a management -interface client as an argument of NEED-CERTIFICATE notification. +interface client as an argument of NEED\-CERTIFICATE notification. Requires \-\-management\-external\-key. .\"********************************************************* .TP @@ -2682,7 +2682,7 @@ Report tunnel up/down events to management interface. .B \-\-management\-client\-auth Gives management interface client the responsibility to authenticate clients after their client certificate -has been verified. See management-notes.txt in OpenVPN +has been verified. See management\-notes.txt in OpenVPN distribution for detailed notes. .\"********************************************************* .TP @@ -2704,21 +2704,21 @@ only allow connections from group .B g. .\"********************************************************* .TP -.B \-\-plugin module-pathname [init-string] -Load plug-in module from the file -.B module-pathname, +.B \-\-plugin module\-pathname [init\-string] +Load plug\-in module from the file +.B module\-pathname, passing -.B init-string +.B init\-string as an argument to the module initialization function. Multiple plugin modules may be loaded into one OpenVPN process. The -.B module-pathname +.B module\-pathname argument can be just a filename or a filename with a relative or absolute path. The format of the filename and path defines -if the plug-in will be loaded from a default plug-in directory +if the plug\-in will be loaded from a default plug\-in directory or outside this directory. .nf @@ -2733,7 +2733,7 @@ or outside this directory. .in -4 .fi -DEFAULT_DIR is replaced by the default plug-in directory, +DEFAULT_DIR is replaced by the default plug\-in directory, which is configured at the build time of OpenVPN. CWD is the current directory where OpenVPN was started or the directory OpenVPN have swithed into via the @@ -2743,7 +2743,7 @@ option before the option. For more information and examples on how to build OpenVPN -plug-in modules, see the README file in the +plug\-in modules, see the README file in the .B plugin folder of the OpenVPN source distribution. @@ -2766,7 +2766,7 @@ every module and script must return success (0) in order for the connection to be authenticated. .\"********************************************************* .TP -.B \-\-keying-material-exporter label len +.B \-\-keying\-material\-exporter label len Save Exported Keying Material [RFC5705] of len bytes (must be between 16 and 4095 bytes) using label in environment (exported_keying_material) for use by plugins in @@ -2778,7 +2778,7 @@ labels. In order to prevent this, labels MUST begin with "EXPORTER". This option requires OpenSSL 1.0.1 or newer. .\"********************************************************* .SS Server Mode -Starting with OpenVPN 2.0, a multi-client TCP/UDP server mode +Starting with OpenVPN 2.0, a multi\-client TCP/UDP server mode is supported, and can be enabled with the .B \-\-mode server option. In server mode, OpenVPN will listen on a single @@ -2796,7 +2796,7 @@ of OpenVPN's server mode. This directive will set up an OpenVPN server which will allocate addresses to clients out of the given network/netmask. The server itself will take the ".1" address of the given network -for use as the server-side endpoint of the local +for use as the server\-side endpoint of the local TUN/TAP interface. For example, @@ -2839,7 +2839,7 @@ if you are ethernet bridging. Use instead. .\"********************************************************* .TP -.B \-\-server\-bridge gateway netmask pool-start-IP pool-end-IP +.B \-\-server\-bridge gateway netmask pool\-start\-IP pool\-end\-IP .TP .B \-\-server\-bridge ['nogw'] @@ -2850,10 +2850,10 @@ of OpenVPN's server mode in ethernet bridging configurations. If .B \-\-server\-bridge -is used without any parameters, it will enable a DHCP-proxy +is used without any parameters, it will enable a DHCP\-proxy mode, where connecting OpenVPN clients will receive an IP address for their TAP adapter from the DHCP server running -on the OpenVPN server-side LAN. +on the OpenVPN server\-side LAN. Note that only clients that support the binding of a DHCP client with the TAP adapter (such as Windows) can support this mode. The optional @@ -2869,7 +2869,7 @@ with the .B brctl tool, and with Windows XP it is done in the Network Connections Panel by selecting the ethernet and -TAP adapters and right-clicking on "Bridge Connections". +TAP adapters and right\-clicking on "Bridge Connections". Next you you must manually set the IP/netmask on the bridge interface. The @@ -2886,9 +2886,9 @@ subnet. Finally, set aside a IP range in the bridged subnet, denoted by -.B pool-start-IP +.B pool\-start\-IP and -.B pool-end-IP, +.B pool\-end\-IP, for OpenVPN to allocate to connecting clients. @@ -2967,7 +2967,7 @@ This is a partial list of options which can currently be pushed: .TP .B \-\-push\-reset Don't inherit the global push list for a specific client instance. -Specify this option in a client-specific context such +Specify this option in a client\-specific context such as with a .B \-\-client\-config\-dir configuration file. This option will ignore @@ -2979,22 +2979,22 @@ options at the global config file level. selectively remove all .B \-\-push options matching "opt" from the option list for a client. "opt" is matched -as a substring against the whole option string to-be-pushed to the client, so +as a substring against the whole option string to\-be\-pushed to the client, so .B \-\-push\-remove route would remove all .B \-\-push route ... and -.B \-\-push route-ipv6 ... +.B \-\-push route\-ipv6 ... statements, while -.B \-\-push\-remove 'route-ipv6 2001:' +.B \-\-push\-remove 'route\-ipv6 2001:' would only remove IPv6 routes for 2001:... networks. .B \-\-push\-remove -can only be used in a client-specific context, like in a +can only be used in a client\-specific context, like in a .B \-\-client\-config\-dir file, or .B \-\-client\-connect -script or plugin -- similar to +script or plugin \-\- similar to .B \-\-push\-reset, just more selective. @@ -3011,22 +3011,22 @@ option with the new value. Push additional information about the client to server. The following data is always pushed to the server: -IV_VER= -- the client OpenVPN version +IV_VER= \-\- the client OpenVPN version -IV_PLAT=[linux|solaris|openbsd|mac|netbsd|freebsd|win] -- the client OS platform +IV_PLAT=[linux|solaris|openbsd|mac|netbsd|freebsd|win] \-\- the client OS platform -IV_LZO_STUB=1 -- if client was built with LZO stub capability +IV_LZO_STUB=1 \-\- if client was built with LZO stub capability -IV_LZ4=1 -- if the client supports LZ4 compressions. +IV_LZ4=1 \-\- if the client supports LZ4 compressions. -IV_PROTO=2 -- if the client supports peer-id floating mechansim +IV_PROTO=2 \-\- if the client supports peer\-id floating mechansim -IV_NCP=2 -- negotiable ciphers, client supports +IV_NCP=2 \-\- negotiable ciphers, client supports .B \-\-cipher pushed by the server, a value of 2 or greater indicates client -supports AES-GCM-128 and AES-GCM-256. +supports AES\-GCM\-128 and AES\-GCM\-256. -IV_UI_VER= -- the UI version of a UI if one is +IV_UI_VER= \-\- the UI version of a UI if one is running, for example "de.blinkt.openvpn 0.5.47" for the Android app. @@ -3034,13 +3034,13 @@ When .B \-\-push\-peer\-info is enabled the additional information consists of the following data: -IV_HWADDR= -- the MAC address of clients default gateway +IV_HWADDR= \-\- the MAC address of clients default gateway -IV_SSL= -- the ssl version used by the client, e.g. "OpenSSL 1.0.2f 28 Jan 2016". +IV_SSL= \-\- the ssl version used by the client, e.g. "OpenSSL 1.0.2f 28 Jan 2016". -IV_PLAT_VER=x.y - the version of the operating system, e.g. 6.1 for Windows 7. +IV_PLAT_VER=x.y \- the version of the operating system, e.g. 6.1 for Windows 7. -UV_= -- client environment variables whose names start with "UV_" +UV_= \-\- client environment variables whose names start with "UV_" .\"********************************************************* .TP .B \-\-disable @@ -3060,12 +3060,12 @@ or dynamically generated using a script. .\"********************************************************* .TP -.B \-\-ifconfig\-pool start-IP end-IP [netmask] +.B \-\-ifconfig\-pool start\-IP end\-IP [netmask] Set aside a pool of subnets to be dynamically allocated to connecting clients, similar -to a DHCP server. For tun-style +to a DHCP server. For tun\-style tunnels, each client will be given a /30 subnet (for -interoperability with Windows clients). For tap-style +interoperability with Windows clients). For tap\-style tunnels, individual addresses will be allocated, and the optional .B netmask @@ -3082,24 +3082,24 @@ at intervals (default=600), as well as on program startup and shutdown. -The goal of this option is to provide a long-term association +The goal of this option is to provide a long\-term association between clients (denoted by their common name) and the virtual -IP address assigned to them from the ifconfig-pool. -Maintaining a long-term +IP address assigned to them from the ifconfig\-pool. +Maintaining a long\-term association is good for clients because it allows them to effectively use the .B \-\-persist\-tun option. .B file -is a comma-delimited ASCII file, formatted as -,. +is a comma\-delimited ASCII file, formatted as +,. If .B seconds = 0, .B file -will be treated as read-only. This is useful if +will be treated as read\-only. This is useful if you would like to treat .B file as a configuration file. @@ -3176,17 +3176,17 @@ OpenVPN's internal client IP address selection algorithm works as follows: .B 1 --- Use +\-\- Use .B \-\-client\-connect script generated file for static IP (first choice). .br .B 2 --- Use +\-\- Use .B \-\-client\-config\-dir file for static IP (next choice). .br .B 3 --- Use +\-\- Use .B \-\-ifconfig\-pool allocation for dynamic IP (last choice). .br @@ -3246,15 +3246,15 @@ Because the OpenVPN server mode handles multiple clients through a single tun or tap interface, it is effectively a router. The .B \-\-client\-to\-client -flag tells OpenVPN to internally route client-to-client -traffic rather than pushing all client-originating traffic +flag tells OpenVPN to internally route client\-to\-client +traffic rather than pushing all client\-originating traffic to the TUN/TAP interface. When this option is used, each client will "see" the other clients which are currently connected. Otherwise, each client will only see the server. Don't use this option if you want to firewall tunnel traffic using -custom, per-client rules. +custom, per\-client rules. .\"********************************************************* .TP .B \-\-duplicate\-cn @@ -3270,11 +3270,11 @@ on client connection. .B cmd consists of a path to script (or executable program), optionally -followed by arguments. The path and arguments may be single- or double-quoted +followed by arguments. The path and arguments may be single\- or double\-quoted and/or escaped using a backslash, and should be separated by one or more spaces. The command is passed the common name -and IP address of the just-authenticated client +and IP address of the just\-authenticated client as environmental variables (see environmental variable section below). The command is also passed the pathname of a freshly created temporary file as the last argument @@ -3296,7 +3296,7 @@ Note that the return value of .B script is significant. If .B script -returns a non-zero error status, it will cause the client +returns a non\-zero error status, it will cause the client to be disconnected. .\"********************************************************* .TP @@ -3312,10 +3312,10 @@ successful (0) status returns. The exception to this rule is if the .B \-\-client\-disconnect -command or plugins are cascaded, and at least one client-connect -function succeeded, then ALL of the client-disconnect functions for +command or plugins are cascaded, and at least one client\-connect +function succeeded, then ALL of the client\-disconnect functions for scripts and plugins will be called on client instance object deletion, -even in cases where some of the related client-connect functions returned +even in cases where some of the related client\-connect functions returned an error status. The @@ -3335,7 +3335,7 @@ for custom client config files. After a connecting client has been authenticated, OpenVPN will look in this directory for a file having the same name as the client's X509 common name. If a matching file -exists, it will be opened and parsed for client-specific +exists, it will be opened and parsed for client\-specific configuration options. If no matching file is found, OpenVPN will instead try to open and parse a default file called "DEFAULT", which may be provided but is not required. Note that @@ -3354,7 +3354,7 @@ created, edited, or removed while the server is live, without needing to restart the server. The following -options are legal in a client-specific context: +options are legal in a client\-specific context: .B \-\-push, \-\-push\-reset, \-\-push\-remove, \-\-iroute, \-\-ifconfig\-push, and .B \-\-config. @@ -3380,7 +3380,7 @@ This directory will be used by in the following cases: * .B \-\-client\-connect -scripts to dynamically generate client-specific +scripts to dynamically generate client\-specific configuration files. * @@ -3459,7 +3459,7 @@ forcing the server to deplete virtual memory as its internal routing table expands. This directive can be used in a .B \-\-client\-config\-dir -file or auto-generated by a +file or auto\-generated by a .B \-\-client\-connect script to override the global value for a particular client. @@ -3515,7 +3515,7 @@ to validate client virtual addresses or routes. .B cmd consists of a path to script (or executable program), optionally -followed by arguments. The path and arguments may be single- or double-quoted +followed by arguments. The path and arguments may be single\- or double\-quoted and/or escaped using a backslash, and should be separated by one or more spaces. Three arguments will be appended to any arguments in @@ -3540,7 +3540,7 @@ client linked to this address. Only present for "add" or "update" operations, not "delete". On "add" or "update" methods, if the script returns -a failure code (non-zero), OpenVPN will reject the address +a failure code (non\-zero), OpenVPN will reject the address and will not modify its internal routing table. Normally, the @@ -3549,8 +3549,8 @@ script will use the information provided above to set appropriate firewall entries on the VPN TUN/TAP interface. Since OpenVPN provides the association between virtual IP or MAC address and the client's authenticated common name, -it allows a user-defined script to configure firewall access -policies with regard to the client's high-level common name, +it allows a user\-defined script to configure firewall access +policies with regard to the client's high\-level common name, rather than the low level client virtual addresses. .\"********************************************************* .TP @@ -3565,7 +3565,7 @@ provided by the client. .B cmd consists of a path to script (or executable program), optionally -followed by arguments. The path and arguments may be single- or double-quoted +followed by arguments. The path and arguments may be single\- or double\-quoted and/or escaped using a backslash, and should be separated by one or more spaces. If @@ -3604,18 +3604,18 @@ returning a success exit code (0) if the client's authentication request is to be accepted, or a failure code (1) to reject the client. -This directive is designed to enable a plugin-style interface +This directive is designed to enable a plugin\-style interface for extending OpenVPN's authentication capabilities. To protect against a client passing a maliciously formed username or password string, the username string must consist only of these characters: alphanumeric, underbar -('_'), dash ('-'), dot ('.'), or at ('@'). The password +('_'), dash ('\-'), dot ('.'), or at ('@'). The password string can consist of any printable characters except for CR or LF. Any illegal characters in either the username or password string will be converted to underbar ('_'). -Care must be taken by any user-defined scripts to avoid +Care must be taken by any user\-defined scripts to avoid creating a security vulnerability in the way that these strings are handled. Never use these strings in such a way that they might be escaped or evaluated by a shell interpreter. @@ -3644,7 +3644,7 @@ or it is set to 0, the token will never expire. This feature is useful for environments which is configured to use One Time Passwords (OTP) as part of the user/password authentications and that authentication mechanism does not -implement any auth-token support. +implement any auth\-token support. .\"********************************************************* .TP .B \-\-opt\-verify @@ -3670,10 +3670,10 @@ or is specified (or an authentication plugin module), the OpenVPN server daemon will require connecting clients to specify a username and password. This option makes the submission of a username/password -by clients optional, passing the responsibility to the user-defined authentication +by clients optional, passing the responsibility to the user\-defined authentication module/script to accept or deny the client based on other factors (such as the setting of X509 certificate fields). When this option is used, -and a connecting client does not submit a username/password, the user-defined +and a connecting client does not submit a username/password, the user\-defined authentication module/script will see the username and password as being set to empty strings (""). The authentication module/script MUST have logic to detect this condition and respond accordingly. @@ -3764,16 +3764,16 @@ like this: /C=US/L=Somewhere/CN=John Doe/emailAddress=john@example.com .IP In addition the old behaviour was to remap any character other than -alphanumeric, underscore ('_'), dash ('-'), dot ('.'), and slash ('/') to +alphanumeric, underscore ('_'), dash ('\-'), dot ('.'), and slash ('/') to underscore ('_'). The X.509 Subject string as returned by the .B tls_id environmental variable, could additionally contain colon (':') or equal ('='). .IP When using the .B \-\-compat\-names -option, this old formatting and remapping will be re-enabled again. This is -purely implemented for compatibility reasons when using older plug-ins or -scripts which does not handle the new formatting or UTF-8 characters. +option, this old formatting and remapping will be re\-enabled again. This is +purely implemented for compatibility reasons when using older plug\-ins or +scripts which does not handle the new formatting or UTF\-8 characters. .IP In OpenVPN 2.3 the formatting of these fields changed into a more standardised format. It now looks like: @@ -3796,12 +3796,12 @@ option to be compatible with the now deprecated \-\-no\-name\-remapping option. It is only available at the server. When this mode flag is used, the Common Name, Subject, and username strings are allowed to include any printable character including space, but excluding control characters such as tab, newline, and -carriage-return. no-remapping is only available on the server side. +carriage\-return. no\-remapping is only available on the server side. .B Please note: This option is immediately deprecated. It is only implemented to make the transition to the new formatting less intrusive. It will be -removed in OpenVPN 2.5. So please update your scripts/plug-ins where necessary. +removed in OpenVPN 2.5. So please update your scripts/plug\-ins where necessary. .\"********************************************************* .TP .B \-\-no\-name\-remapping @@ -3827,7 +3827,7 @@ option as soon as possible. .B \-\-port\-share host port [dir] When run in TCP server mode, share the OpenVPN port with another application, such as an HTTPS server. If OpenVPN -senses a connection to its port which is using a non-OpenVPN +senses a connection to its port which is using a non\-OpenVPN protocol, it will proxy the connection to the server at .B host:port. Currently only designed to work with HTTP/HTTPS, @@ -3871,7 +3871,7 @@ of OpenVPN's client mode. This directive is equivalent to: .TP .B \-\-pull This option must be used on a client which is connecting -to a multi-client server. It indicates to OpenVPN that it +to a multi\-client server. It indicates to OpenVPN that it should accept options pushed by the server, provided they are part of the legal set of pushable options (note that the .B \-\-pull @@ -3960,7 +3960,7 @@ the client. .TP .B \-\-auth\-retry type Controls how OpenVPN responds to username/password verification -errors such as the client-side response to an AUTH_FAILED message from the server +errors such as the client\-side response to an AUTH_FAILED message from the server or verification failure of the private key password. Normally used to prevent auth errors from being fatal @@ -3970,7 +3970,7 @@ of error. An AUTH_FAILED message is generated by the server if the client fails .B \-\-auth\-user\-pass -authentication, or if the server-side +authentication, or if the server\-side .B \-\-client\-connect script returns an error status when the client tries to connect. @@ -4019,7 +4019,7 @@ connect timeouts. .\"********************************************************* .TP .B \-\-explicit\-exit\-notify [n] -In UDP client mode or point-to-point mode, send server/peer an exit notification +In UDP client mode or point\-to\-point mode, send server/peer an exit notification if tunnel is restarted or OpenVPN process is exited. In client mode, on exit/restart, this option will tell the server to immediately close its client instance object @@ -4045,13 +4045,13 @@ When this option is set, OpenVPN will not drop incoming tun packets with same destination as host. .\"********************************************************* .SS Data Channel Encryption Options: -These options are meaningful for both Static & TLS-negotiated key modes +These options are meaningful for both Static & TLS\-negotiated key modes (must be compatible between peers). .\"********************************************************* .TP .B \-\-secret file [direction] -Enable Static Key encryption mode (non-TLS). -Use pre-shared secret +Enable Static Key encryption mode (non\-TLS). +Use pre\-shared secret .B file which was generated with .B \-\-genkey. @@ -4059,7 +4059,7 @@ which was generated with The optional .B direction parameter enables the use of 4 distinct keys -(HMAC-send, cipher-encrypt, HMAC-receive, cipher-decrypt), so that +(HMAC\-send, cipher\-encrypt, HMAC\-receive, cipher\-decrypt), so that each data flow direction has a different set of HMAC and cipher keys. This has a number of desirable security properties including eliminating certain kinds of DoS and message replay attacks. @@ -4079,7 +4079,7 @@ The .B direction parameter requires that .B file -contains a 2048 bit key. While pre-1.5 versions of OpenVPN +contains a 2048 bit key. While pre\-1.5 versions of OpenVPN generate 1024 bit key files, any version of OpenVPN which supports the .B direction @@ -4093,7 +4093,7 @@ the primary being ease of configuration. There are no certificates or certificate authorities or complicated negotiation handshakes and protocols. -The only requirement is that you have a pre-existing secure channel with +The only requirement is that you have a pre\-existing secure channel with your peer (such as .B ssh ) to initially copy the key. This requirement, along with the @@ -4106,13 +4106,13 @@ was able to steal your private key, he would gain no information to help him decrypt past sessions. Another advantageous aspect of Static Key encryption mode is that -it is a handshake-free protocol +it is a handshake\-free protocol without any distinguishing signature or feature (such as a header or protocol handshake sequence) that would mark the ciphertext packets as being generated by OpenVPN. Anyone eavesdropping on the wire would see nothing -but random-looking data. +but random\-looking data. .\"********************************************************* .TP .B \-\-key\-direction @@ -4125,7 +4125,7 @@ options. Useful when using inline files (See section on inline files). .TP .B \-\-auth alg Authenticate data channel packets and (if enabled) -.B tls-auth +.B tls\-auth control channel packets with HMAC using message digest algorithm .B alg. (The default is @@ -4135,7 +4135,7 @@ HMAC is a commonly used message authentication algorithm (MAC) that uses a data string, a secure hash algorithm, and a key, to produce a digital signature. -The OpenVPN data channel protocol uses encrypt-then-mac (i.e. first encrypt a +The OpenVPN data channel protocol uses encrypt\-then\-mac (i.e. first encrypt a packet, then HMAC the resulting ciphertext), which prevents padding oracle attacks. @@ -4145,9 +4145,9 @@ algorithm is ignored for the data channel, and the authentication method of the AEAD cipher is used instead. Note that .B alg still specifies the digest used for -.B tls-auth\fR. +.B tls\-auth\fR. -In static-key encryption mode, the HMAC key +In static\-key encryption mode, the HMAC key is included in the key file generated by .B \-\-genkey. In TLS mode, the HMAC key is dynamically generated and shared @@ -4167,11 +4167,11 @@ Encrypt data channel packets with cipher algorithm .B alg. The default is -.B BF-CBC, +.B BF\-CBC, an abbreviation for Blowfish in Cipher Block Chaining mode. When cipher negotiation (NCP) is allowed, OpenVPN 2.4 and newer on both client and server side will automatically upgrade to -.B AES-256-GCM. +.B AES\-256\-GCM. See .B \-\-ncp\-ciphers and @@ -4179,12 +4179,12 @@ and for more details on NCP. Using -.B BF-CBC -is no longer recommended, because of its 64-bit block size. This +.B BF\-CBC +is no longer recommended, because of its 64\-bit block size. This small block size allows attacks based on collisions, as demonstrated by SWEET32. See https://community.openvpn.net/openvpn/wiki/SWEET32 for details. Due to this, support for -.B BF-CBC, DES, CAST5, IDEA +.B BF\-CBC, DES, CAST5, IDEA and .B RC2 ciphers will be removed in OpenVPN 2.6. @@ -4203,20 +4203,20 @@ to disable encryption. Restrict the allowed ciphers to be negotiated to the ciphers in .B cipher_list\fR. .B cipher_list -is a colon-separated list of ciphers, and defaults to -"AES-256-GCM:AES-128-GCM". +is a colon\-separated list of ciphers, and defaults to +"AES\-256\-GCM:AES\-128\-GCM". For servers, the first cipher from .B cipher_list will be pushed to clients that support cipher negotiation. -Cipher negotiation is enabled in client-server mode only. I.e. if +Cipher negotiation is enabled in client\-server mode only. I.e. if .B \-\-mode -is set to 'server' (server-side, implied by setting +is set to 'server' (server\-side, implied by setting .B \-\-server ), or if .B \-\-pull -is specified (client-side, implied by setting \-\-client). +is specified (client\-side, implied by setting \-\-client). If both peers support and do not disable NCP, the negotiated cipher will override the cipher specified by @@ -4227,10 +4227,10 @@ will inherit the cipher of the peer if that cipher is different from the local .B \-\-cipher setting, but the peer cipher is one of the ciphers specified in .B \-\-ncp\-ciphers\fR. -E.g. a non-NCP client (<=v2.3, or with \-\-ncp\-disabled set) connecting to a -NCP server (v2.4+) with "\-\-cipher BF-CBC" and "\-\-ncp-ciphers -AES-256-GCM:AES-256-CBC" set can either specify "\-\-cipher BF-CBC" or -"\-\-cipher AES-256-CBC" and both will work. +E.g. a non\-NCP client (<=v2.3, or with \-\-ncp\-disabled set) connecting to a +NCP server (v2.4+) with "\-\-cipher BF\-CBC" and "\-\-ncp\-ciphers +AES\-256\-GCM:AES\-256\-CBC" set can either specify "\-\-cipher BF\-CBC" or +"\-\-cipher AES\-256\-CBC" and both will work. .\"********************************************************* .TP @@ -4244,19 +4244,19 @@ negotiation. This option will be removed in OpenVPN 2.6. Size of cipher key in bits (optional). -If unspecified, defaults to cipher-specific default. The +If unspecified, defaults to cipher\-specific default. The .B \-\-show\-ciphers option (see below) shows all available OpenSSL ciphers, their default key sizes, and whether the key size can be changed. Use care in changing a cipher's default key size. Many ciphers have not been extensively -cryptanalyzed with non-standard key lengths, and a +cryptanalyzed with non\-standard key lengths, and a larger key may offer no real guarantee of greater security, or may even reduce security. .\"********************************************************* .TP .B \-\-prng alg [nsl] -(Advanced) For PRNG (Pseudo-random number generator), +(Advanced) For PRNG (Pseudo\-random number generator), use digest algorithm .B alg (default=sha1), and set @@ -4267,14 +4267,14 @@ to the size in bytes of the nonce secret length (between 16 and 64). Set .B alg=none to disable the PRNG and use the OpenSSL RAND_bytes function -instead for all of OpenVPN's pseudo-random number needs. +instead for all of OpenVPN's pseudo\-random number needs. .\"********************************************************* .TP -.B \-\-engine [engine-name] -Enable OpenSSL hardware-based crypto engine functionality. +.B \-\-engine [engine\-name] +Enable OpenSSL hardware\-based crypto engine functionality. If -.B engine-name +.B engine\-name is specified, use a specific crypto engine. Use the .B \-\-show\-engines @@ -4330,7 +4330,7 @@ by IPSec. .\"********************************************************* .TP .B \-\-replay\-window n [t] -Use a replay protection sliding-window of size +Use a replay protection sliding\-window of size .B n and a time window of .B t @@ -4352,7 +4352,7 @@ option is specified. When OpenVPN tunnels IP packets over UDP, there is the possibility that packets might be dropped or delivered out of order. Because OpenVPN, like IPSec, is emulating the physical network layer, -it will accept an out-of-order packet sequence, and +it will accept an out\-of\-order packet sequence, and will deliver such packets in the same order they were received to the TCP/IP protocol stack, provided they satisfy several constraints. @@ -4381,7 +4381,7 @@ Satellite links in particular often require this. If you run OpenVPN at .B \-\-verb 4, -you will see the message "Replay-window backtrack occurred [x]" +you will see the message "Replay\-window backtrack occurred [x]" every time the maximum sequence number backtrack seen thus far increases. This can be used to calibrate .B n. @@ -4405,11 +4405,11 @@ reordering: Don't allow it. Since TCP guarantees reliability, any packet loss or reordering event can be assumed to be an attack. In this sense, it could be argued that TCP tunnel transport is preferred when -tunneling non-IP or UDP application protocols which might be vulnerable to a +tunneling non\-IP or UDP application protocols which might be vulnerable to a message deletion or reordering attack which falls within the normal operational parameters of IP networks. -So I would make the statement that one should never tunnel a non-IP protocol +So I would make the statement that one should never tunnel a non\-IP protocol or UDP application protocol over UDP, if the protocol might be vulnerable to a message deletion or reordering attack that falls within the normal operating parameters of what is to be expected from the physical IP layer. The problem @@ -4425,7 +4425,7 @@ packets. .\"********************************************************* .TP .B \-\-replay\-persist file -Persist replay-protection state across sessions using +Persist replay\-protection state across sessions using .B file to save and reload the state. @@ -4444,7 +4444,7 @@ which were already received by the prior session. This option only makes sense when replay protection is enabled (the default) and you are using either .B \-\-secret -(shared-secret key mode) or TLS mode with +(shared\-secret key mode) or TLS mode with .B \-\-tls\-auth. .\"********************************************************* .TP @@ -4464,11 +4464,11 @@ messages are being encrypted/decrypted with the same key. IV is implemented differently depending on the cipher mode used. -In CBC mode, OpenVPN uses a pseudo-random IV for each packet. +In CBC mode, OpenVPN uses a pseudo\-random IV for each packet. In CFB/OFB mode, OpenVPN uses a unique sequence number and time stamp as the IV. In fact, in CFB/OFB mode, OpenVPN uses a datagram -space-saving optimization that uses the unique identifier for +space\-saving optimization that uses the unique identifier for datagram replay protection as the IV. .\"********************************************************* .TP @@ -4487,7 +4487,7 @@ than 1.1. .\"********************************************************* .TP .B \-\-test\-crypto -Do a self-test of OpenVPN's crypto options by encrypting and +Do a self\-test of OpenVPN's crypto options by encrypting and decrypting test packets using the data channel encryption options specified above. This option does not require a peer to function, and therefore can be specified without @@ -4507,7 +4507,7 @@ or This option is very useful to test OpenVPN after it has been ported to a new platform, or to isolate problems in the compiler, OpenSSL -crypto library, or OpenVPN's crypto code. Since it is a self-test mode, +crypto library, or OpenVPN's crypto code. Since it is a self\-test mode, problems with encryption and authentication can be debugged independently of network and tunnel issues. .\"********************************************************* @@ -4523,7 +4523,7 @@ any mediation. The result is the best of both worlds: a fast data channel that forwards over UDP with only the overhead of encrypt, decrypt, and HMAC functions, and a control channel that provides all of the security features of TLS, -including certificate-based authentication and Diffie Hellman forward secrecy. +including certificate\-based authentication and Diffie Hellman forward secrecy. To use TLS mode, each peer that runs OpenVPN should have its own local certificate/key pair ( @@ -4546,12 +4546,12 @@ passing data. The OpenVPN project provides a set of scripts for managing RSA certificates & keys: -.I https://github.com/OpenVPN/easy-rsa +.I https://github.com/OpenVPN/easy\-rsa .\"********************************************************* .TP .B \-\-tls\-server Enable TLS and assume server role during TLS handshake. Note that -OpenVPN is designed as a peer-to-peer application. The designation +OpenVPN is designed as a peer\-to\-peer application. The designation of client or server is only for the purpose of negotiating the TLS control channel. .\"********************************************************* @@ -4591,11 +4591,11 @@ When using the option, you are required to supply valid CRLs for the CAs too. CAs in the capath directory are expected to be named .. CRLs are expected to be named .r. See the -.B -CApath +.B \-CApath option of .B openssl verify , and the -.B -hash +.B \-hash option of .B openssl x509 and @@ -4617,7 +4617,7 @@ requires peers to be using an SSL library that supports ECDH TLS cipher suites Use .B openssl dhparam \-out dh2048.pem 2048 -to generate 2048-bit DH parameters. Diffie Hellman parameters may be considered +to generate 2048\-bit DH parameters. Diffie Hellman parameters may be considered public. .\"********************************************************* .TP @@ -4625,13 +4625,13 @@ public. Specify the curve to use for elliptic curve Diffie Hellman. Available curves can be listed with .BR \-\-show\-curves . -The specified curve will only be used for ECDH TLS-ciphers. +The specified curve will only be used for ECDH TLS\-ciphers. This option is not supported in mbed TLS builds of OpenVPN. .\"********************************************************* .TP .B \-\-cert file -Local peer's signed certificate in .pem format -- must be signed +Local peer's signed certificate in .pem format \-\- must be signed by a certificate authority whose certificate is in .B \-\-ca file. Each peer in an OpenVPN link running in TLS mode should have its own @@ -4663,7 +4663,7 @@ Note that the command reads the location of the certificate authority key from its configuration file such as .B /usr/share/ssl/openssl.cnf --- note also +\-\- note also that for certificate authority functions, you must set up the files .B index.txt (may be empty) and @@ -4684,7 +4684,7 @@ local certificate chain. This option is useful for "split" CAs, where the CA for server certs is different than the CA for client certs. Putting certs in this file allows them to be used to complete the local -certificate chain without trusting them to verify the peer-submitted +certificate chain without trusting them to verify the peer\-submitted certificate, as would be the case if the certs were placed in the .B ca file. @@ -4701,7 +4701,7 @@ above). Sets the minimum TLS version we will accept from the peer (default is "1.0"). Examples for version -include "1.0", "1.1", or "1.2". If 'or-highest' is specified +include "1.0", "1.1", or "1.2". If 'or\-highest' is specified and version is not recognized, we will only accept the highest TLS version supported by the local SSL implementation. .\"********************************************************* @@ -4722,10 +4722,10 @@ Not available with PolarSSL. .\"********************************************************* .TP .B \-\-verify\-hash hash [algo] -Specify SHA1 or SHA256 fingerprint for level-1 cert. The level-1 cert is the +Specify SHA1 or SHA256 fingerprint for level\-1 cert. The level\-1 cert is the CA (or intermediate cert) that signs the leaf certificate, and is one removed from the leaf certificate in the direction of the root. -When accepting a connection from a peer, the level-1 cert +When accepting a connection from a peer, the level\-1 cert fingerprint must match .B hash or certificate verification will fail. Hash is specified @@ -4757,9 +4757,9 @@ option. .\"********************************************************* .TP .B \-\-pkcs11\-id\-management -Acquire PKCS#11 id from management interface. In this case a NEED-STR 'pkcs11-id-request' -real-time message will be triggered, application may use pkcs11-id-count command to -retrieve available number of certificates, and pkcs11-id-get command to retrieve certificate +Acquire PKCS#11 id from management interface. In this case a NEED\-STR 'pkcs11\-id\-request' +real\-time message will be triggered, application may use pkcs11\-id\-count command to +retrieve available number of certificates, and pkcs11\-id\-get command to retrieve certificate id and certificate body. .\"********************************************************* .TP @@ -4781,7 +4781,7 @@ This option can be used instead of and .B \-\-pkcs12. -If p11-kit is present on the system, its +If p11\-kit is present on the system, its .B p11\-kit\-proxy.so module will be loaded by default if either the .B \-\-pkcs11\-id @@ -4798,23 +4798,23 @@ A different mode can be specified for each provider. Mode is encoded as hex number, and can be a mask one of the following: .B 0 -(default) -- Try to determine automatically. +(default) \-\- Try to determine automatically. .br .B 1 --- Use sign. +\-\- Use sign. .br .B 2 --- Use sign recover. +\-\- Use sign recover. .br .B 4 --- Use decrypt. +\-\- Use decrypt. .br .B 8 --- Use unwrap. +\-\- Use unwrap. .br .\"********************************************************* .TP -.B \-\-cryptoapicert select-string +.B \-\-cryptoapicert select\-string Load the certificate and private key from the Windows Certificate System Store (Windows/OpenSSL Only). @@ -4842,7 +4842,7 @@ To select a certificate, based on certificate's thumbprint: .B cryptoapicert "THUMB:f6 49 24 41 01 b4 ..." -The thumbprint hex string can easily be copy-and-pasted from the Windows +The thumbprint hex string can easily be copy\-and\-pasted from the Windows Certificate Store GUI. .\"********************************************************* @@ -4860,7 +4860,7 @@ for protecting the tunnel data channel is generated and exchanged over the TLS session. In method 1 (the default for OpenVPN 1.x), both sides generate -random encrypt and HMAC-send keys which are forwarded to +random encrypt and HMAC\-send keys which are forwarded to the other host over the TLS channel. Method 1 is .B deprecated in OpenVPN 2.4 , and @@ -4910,7 +4910,7 @@ to see a list of TLS ciphers supported by your crypto library. Warning! .B \-\-tls\-cipher -is an expert feature, which - if used correcly - can improve the security of +is an expert feature, which \- if used correcly \- can improve the security of your VPN connection. But it is also easy to unwittingly use it to carefully align a gun with your foot, or just break your connection. Use with care! @@ -4929,7 +4929,7 @@ packet to its peer, it will expect to receive an acknowledgement within .B n seconds or it will retransmit the packet, subject -to a TCP-like exponential backoff algorithm. This parameter +to a TCP\-like exponential backoff algorithm. This parameter only applies to control channel packets. Data channel packets (which carry encrypted tunnel data) are never acknowledged, sequenced, or retransmitted by OpenVPN because @@ -4946,7 +4946,7 @@ to be expressed as a number of bytes encrypted/decrypted, a number of packets, or a number of seconds. A key renegotiation will be forced if any of these three criteria are met by either peer. -If using ciphers with cipher block sizes less than 128-bits, \-\-reneg\-bytes is +If using ciphers with cipher block sizes less than 128\-bits, \-\-reneg\-bytes is set to 64MB by default, unless it is explicitly disabled by setting the value to 0, but this is .B HIGHLY DISCOURAGED @@ -4965,7 +4965,7 @@ Renegotiate data channel key after .B n seconds (default=3600). -When using dual-factor authentication, note that this default value may +When using dual\-factor authentication, note that this default value may cause the end user to be challenged to reauthorize once per hour. Also, keep in mind that this option can be used on both the client and server, @@ -4980,7 +4980,7 @@ your chosen value on the other side. .\"********************************************************* .TP .B \-\-hand\-window n -Handshake Window -- the TLS-based key exchange must finalize within +Handshake Window \-\- the TLS\-based key exchange must finalize within .B n seconds of handshake initiation by any peer (default = 60 seconds). @@ -4994,7 +4994,7 @@ data. .\"********************************************************* .TP .B \-\-tran\-window n -Transition window -- our old key can live this many seconds +Transition window \-\- our old key can live this many seconds after a new a key renegotiation begins (default = 3600 seconds). This feature allows for a graceful transition from old to new key, and removes the key renegotiation sequence from the critical @@ -5057,7 +5057,7 @@ is specified with .B \-\-float. The rationale for -this feature is as follows. TLS requires a multi-packet exchange +this feature is as follows. TLS requires a multi\-packet exchange before it is able to authenticate a peer. During this time before authentication, OpenVPN is allocating resources (memory and CPU) to this potential peer. The potential peer is also @@ -5066,7 +5066,7 @@ it is sending. Most successful network attacks today seek to either exploit bugs in programs (such as buffer overflow attacks) or force a program to consume so many resources that it becomes unusable. Of course the first line of defense is always to produce clean, -well-audited code. OpenVPN has been written with buffer overflow +well\-audited code. OpenVPN has been written with buffer overflow attack prevention as a top priority. But as history has shown, many of the most widely used network applications have, from time to time, @@ -5122,8 +5122,8 @@ provides more privacy by hiding the certificate used for the TLS connection, .IP \[bu] makes it harder to identify OpenVPN traffic as such, .IP \[bu] -provides "poor-man's" post-quantum security, against attackers who will never -know the pre-shared key (i.e. no forward secrecy). +provides "poor\-man's" post\-quantum security, against attackers who will never +know the pre\-shared key (i.e. no forward secrecy). .RE .IP @@ -5136,10 +5136,10 @@ does *not* require the user to set .B Security Considerations All peers use the same -.B \-\-tls-crypt -pre-shared group key to authenticate and encrypt control channel messages. To +.B \-\-tls\-crypt +pre\-shared group key to authenticate and encrypt control channel messages. To ensure that IV collisions remain unlikely, this key should not be used to -encrypt more than 2^48 client-to-server or 2^48 server-to-client control +encrypt more than 2^48 client\-to\-server or 2^48 server\-to\-client control channel messages. A typical initial negotiation is about 10 packets in each direction. Assuming both initial negotiation and renegotiations are at most 2^16 (65536) packets (to be conservative), and (re)negotiations happen each @@ -5153,8 +5153,8 @@ If IV collisions were to occur, this could result in the security of degrading to the same security as using .B \-\-tls\-auth\fR. That is, the control channel still benefits from the extra protection against -active man-in-the-middle-attacks and DoS attacks, but may no longer offer -extra privacy and post-quantum security on top of what TLS itself offers. +active man\-in\-the\-middle\-attacks and DoS attacks, but may no longer offer +extra privacy and post\-quantum security on top of what TLS itself offers. .\"********************************************************* .TP .B \-\-askpass [file] @@ -5272,7 +5272,7 @@ should return 0 to allow the TLS handshake to proceed, or 1 to fail. .B cmd consists of a path to script (or executable program), optionally -followed by arguments. The path and arguments may be single- or double-quoted +followed by arguments. The path and arguments may be single\- or double\-quoted and/or escaped using a backslash, and should be separated by one or more spaces. When @@ -5341,13 +5341,13 @@ instead of the Common Name. Only the subjectAltName and issuerAltName X.509 extensions are supported. .B Please note: -This option has a feature which will convert an all-lowercase +This option has a feature which will convert an all\-lowercase .B fieldname -to uppercase characters, e.g., ou -> OU. A mixed-case +to uppercase characters, e.g., ou \-> OU. A mixed\-case .B fieldname or one having the .B ext: -prefix will be left as-is. This automatic upcasing feature +prefix will be left as\-is. This automatic upcasing feature is deprecated and will be removed in a future release. .\"********************************************************* .TP @@ -5361,18 +5361,18 @@ Which X.509 name is compared to depends on the setting of type. .B type can be "subject" to match the complete subject DN (default), -"name" to match a subject RDN or "name-prefix" to match a subject RDN prefix. +"name" to match a subject RDN or "name\-prefix" to match a subject RDN prefix. Which RDN is verified as name depends on the .B \-\-x509\-username\-field option. But it defaults to the common name (CN), e.g. a certificate with a -subject DN "C=KG, ST=NA, L=Bishkek, CN=Server-1" would be matched by: +subject DN "C=KG, ST=NA, L=Bishkek, CN=Server\-1" would be matched by: .B \-\-verify\-x509\-name 'C=KG, ST=NA, L=Bishkek, CN=Server\-1' and .B \-\-verify\-x509\-name Server\-1 name or you could use -.B \-\-verify\-x509\-name Server -name-prefix -if you want a client to only accept connections to "Server-1", "Server-2", etc. +.B \-\-verify\-x509\-name Server\- name\-prefix +if you want a client to only accept connections to "Server\-1", "Server\-2", etc. .B \-\-verify\-x509\-name is a useful replacement for the @@ -5391,7 +5391,7 @@ with designated servers. .B NOTE: Test against a name prefix only when you are using OpenVPN with a custom CA certificate that is under your control. -Never use this option with type "name-prefix" when your client certificates +Never use this option with type "name\-prefix" when your client certificates are signed by a third party, such as a commercial web CA. .\"********************************************************* .TP @@ -5430,7 +5430,7 @@ to "server", then the clients can verify this with .B \-\-ns\-cert\-type server. This is an important security precaution to protect against -a man-in-the-middle attack where an authorized client +a man\-in\-the\-middle attack where an authorized client attempts to connect to another client by impersonating the server. The attack is easily prevented by having clients verify the server certificate using any one of @@ -5495,7 +5495,7 @@ option is equivalent to \-\-remote\-cert\-ku \-\-remote\-cert\-eku "TLS Web Server Authentication" This is an important security precaution to protect against -a man-in-the-middle attack where an authorized client +a man\-in\-the\-middle attack where an authorized client attempts to connect to another client by impersonating the server. The attack is easily prevented by having clients verify the server certificate using any one of @@ -5567,7 +5567,7 @@ an ECDSA cipher suite will not work if you are using an RSA certificate, etc.). .TP .B \-\-show\-engines (Standalone) -Show currently available hardware-based crypto acceleration +Show currently available hardware\-based crypto acceleration engines supported by the OpenSSL library. .\"********************************************************* .TP @@ -5578,7 +5578,7 @@ Show all available elliptic curves to use with the option. .\"********************************************************* .SS Generate a random key: -Used only for non-TLS static key encryption mode. +Used only for non\-TLS static key encryption mode. .\"********************************************************* .TP .B \-\-genkey @@ -5587,7 +5587,7 @@ Generate a random key to be used as a shared secret, for use with the .B \-\-secret option. This file must be shared with the -peer over a pre-existing secure channel such as +peer over a pre\-existing secure channel such as .BR scp (1) . .\"********************************************************* @@ -5622,7 +5622,7 @@ and commands. These commands can be placed in the the same shell script which starts or terminates an OpenVPN session. -Another advantage is that open connections through the TUN/TAP-based tunnel +Another advantage is that open connections through the TUN/TAP\-based tunnel will not be reset if the OpenVPN peer restarts. This can be useful to provide uninterrupted connectivity through the tunnel in the event of a DHCP reset of the peer's public IP address (see the @@ -5636,7 +5636,7 @@ and .B \-\-tun\-mtu above). -On some platforms such as Windows, TAP-Win32 tunnels are persistent by +On some platforms such as Windows, TAP\-Win32 tunnels are persistent by default. .\"********************************************************* .TP @@ -5656,7 +5656,7 @@ Optional user to be owner of this tunnel. .B \-\-group group Optional group to be owner of this tunnel. .\"********************************************************* -.SS Windows-Specific Options: +.SS Windows\-Specific Options: .\"********************************************************* .TP .B \-\-win\-sys path @@ -5681,7 +5681,7 @@ is found in the configuration file. .B \-\-ip\-win32 method When using .B \-\-ifconfig -on Windows, set the TAP-Win32 adapter +on Windows, set the TAP\-Win32 adapter IP address and netmask using .B method. Don't use this option unless you are also using @@ -5694,13 +5694,13 @@ to the console telling the user to configure the adapter manually and indicating the IP/netmask which OpenVPN expects the adapter to be set to. -.B dynamic [offset] [lease-time] -- +.B dynamic [offset] [lease\-time] \-\- Automatically set the IP address and netmask by replying to DHCP query messages generated by the kernel. This mode is probably the "cleanest" solution -for setting the TCP/IP properties since it uses the well-known +for setting the TCP/IP properties since it uses the well\-known DHCP protocol. There are, however, two prerequisites for using -this mode: (1) The TCP/IP properties for the TAP-Win32 +this mode: (1) The TCP/IP properties for the TAP\-Win32 adapter must be set to "Obtain an IP address automatically," and (2) OpenVPN needs to claim an IP address in the subnet for use as the virtual DHCP server address. By default in @@ -5713,7 +5713,7 @@ virtual DHCP server address. In .B \-\-dev tun mode, OpenVPN will cause the DHCP server to masquerade as if it were coming from the remote endpoint. The optional offset parameter is -an integer which is > \-256 and < 256 and which defaults to -1. +an integer which is > \-256 and < 256 and which defaults to \-1. If offset is positive, the DHCP server will masquerade as the IP address at network address + offset. If offset is negative, the DHCP server will masquerade as the IP @@ -5724,17 +5724,17 @@ address is. OpenVPN will "claim" this address, so make sure to use a free address. Having said that, different OpenVPN instantiations, including different ends of the same connection, can share the same virtual DHCP server address. The -.B lease-time +.B lease\-time parameter controls the lease time of the DHCP assignment given to -the TAP-Win32 adapter, and is denoted in seconds. +the TAP\-Win32 adapter, and is denoted in seconds. Normally a very long lease time is preferred -because it prevents routes involving the TAP-Win32 adapter from +because it prevents routes involving the TAP\-Win32 adapter from being lost when the system goes to sleep. The default lease time is one year. .B netsh \-\- Automatically set the IP address and netmask using -the Windows command-line "netsh" +the Windows command\-line "netsh" command. This method appears to work correctly on Windows XP but not Windows 2000. @@ -5743,7 +5743,7 @@ Automatically set the IP address and netmask using the Windows IP Helper API. This approach does not have ideal semantics, though testing has indicated that it works okay in practice. If you use this option, -it is best to leave the TCP/IP properties for the TAP-Win32 +it is best to leave the TCP/IP properties for the TAP\-Win32 adapter in their default state, i.e. "Obtain an IP address automatically." @@ -5752,14 +5752,14 @@ automatically." .B dynamic method initially and fail over to .B netsh -if the DHCP negotiation with the TAP-Win32 adapter does +if the DHCP negotiation with the TAP\-Win32 adapter does not succeed in 20 seconds. Such failures have been known -to occur when certain third-party firewall packages installed +to occur when certain third\-party firewall packages installed on the client machine block the DHCP negotiation used by -the TAP-Win32 adapter. +the TAP\-Win32 adapter. Note that if the .B netsh -failover occurs, the TAP-Win32 adapter +failover occurs, the TAP\-Win32 adapter TCP/IP properties will be reset from DHCP to static, and this will cause future OpenVPN startups using the .B adaptive @@ -5773,7 +5773,7 @@ mode from using .B netsh, run OpenVPN at least once using the .B dynamic -mode to restore the TAP-Win32 adapter TCP/IP properties +mode to restore the TAP\-Win32 adapter TCP/IP properties to a DHCP configuration. .\"********************************************************* .TP @@ -5783,29 +5783,29 @@ Which method to use for adding routes on Windows? .B adaptive -(default) -- Try IP helper API first. If that fails, fall +(default) \-\- Try IP helper API first. If that fails, fall back to the route.exe shell command. .br .B ipapi --- Use IP helper API. +\-\- Use IP helper API. .br .B exe --- Call the route.exe shell command. +\-\- Call the route.exe shell command. .\"********************************************************* .TP .B \-\-dhcp\-option type [parm] -Set extended TAP-Win32 TCP/IP properties, must +Set extended TAP\-Win32 TCP/IP properties, must be used with .B \-\-ip\-win32 dynamic or .B \-\-ip\-win32 adaptive. This option can be used to set additional TCP/IP properties -on the TAP-Win32 adapter, and is particularly useful for +on the TAP\-Win32 adapter, and is particularly useful for configuring an OpenVPN client to access a Samba server across the VPN. .B DOMAIN name \-\- -Set Connection-specific DNS Suffix. +Set Connection\-specific DNS Suffix. .B DNS addr \-\- Set primary domain name server IPv4 address. Repeat @@ -5839,17 +5839,17 @@ to set secondary NTP server addresses. .B NBT type \-\- Set NetBIOS over TCP/IP Node type. Possible options: .B 1 -= b-node (broadcasts), += b\-node (broadcasts), .B 2 -= p-node (point-to-point += p\-node (point\-to\-point name queries to a WINS server), .B 4 -= m-node (broadcast += m\-node (broadcast then query name server), and .B 8 -= h-node (query name server, then broadcast). += h\-node (query name server, then broadcast). -.B NBS scope-id -- +.B NBS scope\-id \-\- Set NetBIOS over TCP/IP Scope. A NetBIOS Scope ID provides an extended naming service for the NetBIOS over TCP/IP (Known as NBT) module. The primary purpose of a NetBIOS scope ID is to isolate NetBIOS traffic on @@ -5861,14 +5861,14 @@ computers to use the same computer name, as they have different scope IDs. The Scope ID becomes a part of the NetBIOS name, making the name unique. (This description of NetBIOS scopes courtesy of NeonSurge@abyss.com) -.B DISABLE-NBT -- -Disable Netbios-over-TCP/IP. +.B DISABLE\-NBT \-\- +Disable Netbios\-over\-TCP/IP. Note that if .B \-\-dhcp\-option is pushed via .B \-\-push -to a non-windows client, the option will be saved in the client's +to a non\-windows client, the option will be saved in the client's environment before the up script is called, under the name "foreign_option_{n}". .\"********************************************************* @@ -5876,7 +5876,7 @@ the name "foreign_option_{n}". .B \-\-tap\-sleep n Cause OpenVPN to sleep for .B n -seconds immediately after the TAP-Win32 adapter state +seconds immediately after the TAP\-Win32 adapter state is set to "connected". This option is intended to be used to troubleshoot problems @@ -5885,7 +5885,7 @@ with the and .B \-\-ip\-win32 options, and is used to give -the TAP-Win32 adapter time to come up before +the TAP\-Win32 adapter time to come up before Windows IP Helper API operations are applied to it. .\"********************************************************* .TP @@ -5902,7 +5902,7 @@ TCP or UDP port 53 except one inside the tunnel. It uses Windows Filtering Platform (WFP) and works on Windows Vista or later. -This option is considered unknown on non-Windows platforms +This option is considered unknown on non\-Windows platforms and unsupported on Windows XP, resulting in fatal error. You may want to use .B \-\-setenv opt @@ -5917,7 +5917,7 @@ fatal errors. Ask Windows to renew the TAP adapter lease on startup. This option is normally unnecessary, as Windows automatically triggers a DHCP renegotiation on the TAP adapter when it -comes up, however if you set the TAP-Win32 adapter +comes up, however if you set the TAP\-Win32 adapter Media Status property to "Always Connected", you may need this flag. .\"********************************************************* @@ -5937,29 +5937,29 @@ recognizing pushed DNS servers. Put up a "press any key to continue" message on the console prior to OpenVPN program exit. This option is automatically used by the Windows explorer when OpenVPN is run on a configuration -file using the right-click explorer menu. +file using the right\-click explorer menu. .\"********************************************************* .TP -.B \-\-service exit-event [0|1] +.B \-\-service exit\-event [0|1] Should be used when OpenVPN is being automatically executed by another program in such a context that no interaction with the user via display or keyboard -is possible. In general, end-users should never need to explicitly +is possible. In general, end\-users should never need to explicitly use this option, as it is automatically added by the OpenVPN service wrapper when a given OpenVPN configuration is being run as a service. -.B exit-event +.B exit\-event is the name of a Windows global event object, and OpenVPN will continuously monitor the state of this event object and exit when it becomes signaled. The second parameter indicates the initial state of -.B exit-event +.B exit\-event and normally defaults to 0. Multiple OpenVPN processes can be simultaneously executed with the same -.B exit-event +.B exit\-event parameter. In any case, the controlling process can signal -.B exit-event, +.B exit\-event, causing all such OpenVPN processes to exit. When executing an OpenVPN process using the @@ -5975,9 +5975,9 @@ to write these messages to a file. .TP .B \-\-show\-adapters (Standalone) -Show available TAP-Win32 adapters which can be selected using the +Show available TAP\-Win32 adapters which can be selected using the .B \-\-dev\-node -option. On non-Windows systems, the +option. On non\-Windows systems, the .BR ifconfig (8) command provides similar functionality. .\"********************************************************* @@ -5985,14 +5985,14 @@ command provides similar functionality. .B \-\-allow\-nonadmin [TAP\-adapter] (Standalone) Set -.B TAP-adapter -to allow access from non-administrative accounts. If -.B TAP-adapter +.B TAP\-adapter +to allow access from non\-administrative accounts. If +.B TAP\-adapter is omitted, all TAP adapters on the system will be configured to allow -non-admin access. -The non-admin access setting will only persist for the length of time that -the TAP-Win32 device object and driver remain loaded, and will need -to be re-enabled after a reboot, or if the driver is unloaded +non\-admin access. +The non\-admin access setting will only persist for the length of time that +the TAP\-Win32 device object and driver remain loaded, and will need +to be re\-enabled after a reboot, or if the driver is unloaded and reloaded. This directive can only be used by an administrator. .\"********************************************************* @@ -6001,12 +6001,12 @@ This directive can only be used by an administrator. (Standalone) Show valid subnets for .B \-\-dev tun -emulation. Since the TAP-Win32 driver +emulation. Since the TAP\-Win32 driver exports an ethernet interface to Windows, and since TUN devices are -point-to-point in nature, it is necessary for the TAP-Win32 driver +point\-to\-point in nature, it is necessary for the TAP\-Win32 driver to impose certain constraints on TUN endpoint address selection. -Namely, the point-to-point endpoints used in TUN device emulation +Namely, the point\-to\-point endpoints used in TUN device emulation must be the middle two addresses of a /30 subnet (netmask 255.255.255.252). .\"********************************************************* .TP @@ -6023,7 +6023,7 @@ adapter list. Show PKCS#11 token object list. Specify cert_private as 1 if certificates are stored as private objects. -If p11-kit is present on the system, the +If p11\-kit is present on the system, the .B provider argument is optional; if omitted the default .B p11\-kit\-proxy.so @@ -6043,8 +6043,8 @@ is passed as argument, the IPv6 route for this host is reported. .\"********************************************************* .SS IPv6 Related Options .\"********************************************************* -The following options exist to support IPv6 tunneling in peer-to-peer -and client-server mode. All options are modeled after their IPv4 +The following options exist to support IPv6 tunneling in peer\-to\-peer +and client\-server mode. All options are modeled after their IPv4 counterparts, so more detailed explanations given there apply here as well (except for .B \-\-topology @@ -6066,7 +6066,7 @@ field from is used. .TP .B \-\-server\-ipv6 ipv6addr/bits -convenience-function to enable a number of IPv6 related options at +convenience\-function to enable a number of IPv6 related options at once, namely .B \-\-ifconfig\-ipv6, \-\-ifconfig\-ipv6\-pool and @@ -6083,14 +6083,14 @@ pool starts at and matches the offset determined from the start of the IPv4 pool. .TP .B \-\-ifconfig\-ipv6\-push ipv6addr/bits ipv6remote -for ccd/ per-client static IPv6 interface configuration, see +for ccd/ per\-client static IPv6 interface configuration, see .B \-\-client\-config\-dir and .B \-\-ifconfig\-push for more details. .TP .B \-\-iroute\-ipv6 ipv6addr/bits -for ccd/ per-client static IPv6 route configuration, see +for ccd/ per\-client static IPv6 route configuration, see .B \-\-iroute for more details how to setup and use this, and how .B \-\-iroute @@ -6101,7 +6101,7 @@ interact. .\"********************************************************* .SH SCRIPTING AND ENVIRONMENTAL VARIABLES OpenVPN exports a series -of environmental variables for use by user-defined scripts. +of environmental variables for use by user\-defined scripts. .\"********************************************************* .SS Script Order of Execution .\"********************************************************* @@ -6186,13 +6186,13 @@ Here is a brief rundown of OpenVPN's current string types and the permitted character class for each string: .B X509 Names: -Alphanumeric, underbar ('_'), dash ('-'), dot ('.'), at +Alphanumeric, underbar ('_'), dash ('\-'), dot ('.'), at ('@'), colon (':'), slash ('/'), and equal ('='). Alphanumeric is defined as a character which will cause the C library isalnum() function to return true. .B Common Names: -Alphanumeric, underbar ('_'), dash ('-'), dot ('.'), and at +Alphanumeric, underbar ('_'), dash ('\-'), dot ('.'), and at ('@'). .B \-\-auth\-user\-pass username: @@ -6206,8 +6206,8 @@ Printable is defined to be a character which will cause the C library isprint() function to return true. .B \-\-client\-config\-dir filename as derived from common name or username: -Alphanumeric, underbar ('_'), dash ('-'), and dot ('.') except for "." or -".." as standalone strings. As of v2.0.1-rc6, the at ('@') character has +Alphanumeric, underbar ('_'), dash ('\-'), and dot ('.') except for "." or +".." as standalone strings. As of v2.0.1\-rc6, the at ('@') character has been added as well for compatibility with the common name character class. .B Environmental variable names: @@ -6223,7 +6223,7 @@ character class for that string type will be remapped to underbar ('_'). Once set, a variable is persisted indefinitely until it is reset by a new value or a restart, -As of OpenVPN 2.0-beta12, in server mode, environmental +As of OpenVPN 2.0\-beta12, in server mode, environmental variables set by OpenVPN are scoped according to the client objects they are @@ -6305,7 +6305,7 @@ An option pushed via to a client which does not natively support it, such as .B \-\-dhcp\-option -on a non-Windows system, will be recorded to this +on a non\-Windows system, will be recorded to this environmental variable sequence prior to .B \-\-up script execution. @@ -6530,7 +6530,7 @@ Set on program initiation and reset on SIGHUP. .\"********************************************************* .TP .B route_net_gateway -The pre-existing default IP gateway in the system routing +The pre\-existing default IP gateway in the system routing table. Set prior to .B \-\-up @@ -6635,7 +6635,7 @@ or .\"********************************************************* .TP .B time_ascii -Client connection timestamp, formatted as a human-readable +Client connection timestamp, formatted as a human\-readable time string. Set prior to execution of the .B \-\-client\-connect @@ -6685,7 +6685,7 @@ is the verification level. Only set for TLS connections. Set prior to execution of .B \-\-tls\-verify script. This is in the form of a decimal string like "933971680", which is -suitable for doing serial-based OCSP queries (with OpenSSL, do not +suitable for doing serial\-based OCSP queries (with OpenSSL, do not prepend "0x" to the string) If something goes wrong while reading the value from the certificate it will be an empty string, so your code should check that. @@ -6786,12 +6786,12 @@ and 1 for the CA certificate. .ft 3 .in +4 X509_0_emailAddress=me@myhost.mydomain -X509_0_CN=Test-Client -X509_0_O=OpenVPN-TEST +X509_0_CN=Test\-Client +X509_0_O=OpenVPN\-TEST X509_0_ST=NA X509_0_C=KG X509_1_emailAddress=me@myhost.mydomain -X509_1_O=OpenVPN-TEST +X509_1_O=OpenVPN\-TEST X509_1_L=BISHKEK X509_1_ST=NA X509_1_C=KG @@ -6802,7 +6802,7 @@ X509_1_C=KG .SH INLINE FILE SUPPORT OpenVPN allows including files in the main configuration for the .B \-\-ca, \-\-cert, \-\-dh, \-\-extra\-certs, \-\-key, \-\-pkcs12, \-\-secret, -.B \-\-crl\-verify, \-\-http\-proxy\-user\-pass, \-\-tls-auth +.B \-\-crl\-verify, \-\-http\-proxy\-user\-pass, \-\-tls\-auth and .B \-\-tls\-crypt options. @@ -6818,9 +6818,9 @@ Here is an example of an inline file usage .ft 3 .in +4 ------BEGIN CERTIFICATE----- +\-\-\-\-\-BEGIN CERTIFICATE\-\-\-\-\- [...] ------END CERTIFICATE----- +\-\-\-\-\-END CERTIFICATE\-\-\-\-\- .in -4 .ft @@ -6836,15 +6836,15 @@ the inline file has to be base64 encoded. Encoding of a .p12 file into base64 ca .B SIGHUP Cause OpenVPN to close all TUN/TAP and network connections, -restart, re-read the configuration file (if any), +restart, re\-read the configuration file (if any), and reopen TUN/TAP and network connections. .\"********************************************************* .TP .B SIGUSR1 Like .B SIGHUP, -except don't re-read configuration file, and possibly don't close and reopen TUN/TAP -device, re-read key files, preserve local IP address/port, or preserve most recently authenticated +except don't re\-read configuration file, and possibly don't close and reopen TUN/TAP +device, re\-read key files, preserve local IP address/port, or preserve most recently authenticated remote IP address/port based on .B \-\-persist\-tun, \-\-persist\-key, \-\-persist\-local\-ip, and @@ -6924,7 +6924,7 @@ a UDP ping to its remote peer once every 15 seconds which will cause many stateful firewalls to forward packets in both directions without an explicit firewall rule). -If you are using a Linux iptables-based firewall, you may need to enter +If you are using a Linux iptables\-based firewall, you may need to enter the following command to allow incoming packets on the TUN device: .IP .B iptables \-A INPUT \-i tun+ \-j ACCEPT @@ -6964,7 +6964,7 @@ via .B ssh without using the VPN (since .B ssh -has its own built-in security) you would use the command +has its own built\-in security) you would use the command .B ssh alice.example.com. However in the same scenario, you could also use the command .B telnet 10.4.0.2 @@ -7009,7 +7009,7 @@ program. Omit the .B \-\-verb 9 option to have OpenVPN run quietly. .\"********************************************************* -.SS Example 2: A tunnel with static-key security (i.e. using a pre-shared secret) +.SS Example 2: A tunnel with static\-key security (i.e. using a pre\-shared secret) First build a static key on bob. .IP .B openvpn \-\-genkey \-\-secret key @@ -7042,13 +7042,13 @@ On alice: .IP .B ping 10.4.0.1 .\"********************************************************* -.SS Example 3: A tunnel with full TLS-based security +.SS Example 3: A tunnel with full TLS\-based security For this test, we will designate .B bob as the TLS client and .B alice as the TLS server. -.I Note that client or server designation only has meaning for the TLS subsystem. It has no bearing on OpenVPN's peer-to-peer, UDP-based communication model. +.I Note that client or server designation only has meaning for the TLS subsystem. It has no bearing on OpenVPN's peer\-to\-peer, UDP\-based communication model. First, build a separate certificate/key pair for both bob and alice (see above where @@ -7059,7 +7059,7 @@ Diffie Hellman parameters (see above where is discussed for more info). You can also use the included test files client.crt, client.key, server.crt, server.key and ca.crt. -The .crt files are certificates/public-keys, the .key +The .crt files are certificates/public\-keys, the .key files are private keys, and ca.crt is a certification authority who has signed both client.crt and server.crt. For Diffie Hellman @@ -7134,7 +7134,7 @@ in a script and execute with the option. .\"********************************************************* .SH FIREWALLS -OpenVPN's usage of a single UDP port makes it fairly firewall-friendly. +OpenVPN's usage of a single UDP port makes it fairly firewall\-friendly. You should add an entry to your firewall rules to allow incoming OpenVPN packets. On Linux 2.4+: .IP @@ -7143,7 +7143,7 @@ packets. On Linux 2.4+: This will allow incoming packets on UDP port 1194 (OpenVPN's default UDP port) from an OpenVPN peer at 1.2.3.4. -If you are using HMAC-based packet authentication (the default in any of +If you are using HMAC\-based packet authentication (the default in any of OpenVPN's secure modes), having the firewall filter on source address can be considered optional, since HMAC packet authentication is a much more secure method of verifying the authenticity of @@ -7236,11 +7236,11 @@ OpenSSL Project ( For more information on the TLS protocol, see .I http://www.ietf.org/rfc/rfc2246.txt -For more information on the LZO real-time compression library see +For more information on the LZO real\-time compression library see .I http://www.oberhumer.com/opensource/lzo/ .\"********************************************************* .SH COPYRIGHT -Copyright (C) 2002-2010 OpenVPN Technologies, Inc. This program is free software; +Copyright (C) 2002\-2017 OpenVPN Technologies, Inc. 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. From cac73d4b93e14f3bd5a1ed11b33f73adb29507a3 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Sun, 20 Aug 2017 11:19:04 +0200 Subject: [PATCH 622/643] travis: reorder matrix to speed up build The OSX and mingw builds are much slower than the other jobs. Our free travis account can only use 4 build executors in parallel. Run the slow builds earlier, so that when one or more of these finish, the free build executors will start building the configure variants in parallel with the slow ones. (Instead of doing the slow ones last, which results in using only 1-2 executors during the end stage.) Signed-off-by: Steffan Karger Acked-by: Antonio Quartulli Message-Id: <1503220744-5569-1-git-send-email-steffan@karger.me> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15302.html Signed-off-by: David Sommerseth (cherry picked from commit e0a6afa12ea14685d0497ab27453ccc2b09e6e1f) --- .travis.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index 79aa8c99023..366e6599079 100644 --- a/.travis.yml +++ b/.travis.yml @@ -45,15 +45,6 @@ matrix: - env: SSLLIB="mbedtls" os: linux compiler: clang - - env: SSLLIB="openssl" EXTRA_CONFIG="--disable-crypto" EXTRA_SCRIPT="make distcheck" - os: linux - compiler: clang - - env: SSLLIB="openssl" EXTRA_CONFIG="--disable-lzo" - os: linux - compiler: clang - - env: SSLLIB="openssl" EXTRA_CONFIG="--enable-small" - os: linux - compiler: clang - env: SSLLIB="openssl" os: osx osx_image: xcode7.3 @@ -68,6 +59,15 @@ matrix: - env: SSLLIB="openssl" CHOST=i686-w64-mingw32 os: linux compiler: ": Win32 build only" + - env: SSLLIB="openssl" EXTRA_CONFIG="--disable-crypto" EXTRA_SCRIPT="make distcheck" + os: linux + compiler: clang + - env: SSLLIB="openssl" EXTRA_CONFIG="--disable-lzo" + os: linux + compiler: clang + - env: SSLLIB="openssl" EXTRA_CONFIG="--enable-small" + os: linux + compiler: clang exclude: - compiler: gcc From 1bea2dc0f89af74281d30e1f27dea6c434ff0c5e Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Tue, 22 Aug 2017 13:47:15 +0200 Subject: [PATCH 623/643] docs: Replace all PolarSSL references to mbed TLS There were references in our documentation to the now deprecated PolarSSL library, which have changed name upstream to mbed TLS. In addition, where appropriate, the documentation now considers only mbed TLS 2.0 and newer. This is in accordance with the requirements ./configure sets. [DS: On-the-fly change - Updated Makefile.am to use README.mbedtls instead of README.polarssl. This ensures make dist and buildbots won't explode] Signed-off-by: David Sommerseth Acked-by: Steffan Karger Message-Id: <20170822114715.14225-1-davids@openvpn.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15309.html Signed-off-by: David Sommerseth (cherry picked from commit ed0e79938e801ec656d70cf02bcea4cdd0b79532) --- INSTALL | 4 ++-- Makefile.am | 4 ++-- README.polarssl => README.mbedtls | 10 +++++----- doc/doxygen/doc_data_crypto.h | 2 +- doc/doxygen/doc_key_generation.h | 6 +++--- doc/openvpn.8 | 16 +++++++--------- 6 files changed, 20 insertions(+), 22 deletions(-) rename README.polarssl => README.mbedtls (65%) diff --git a/INSTALL b/INSTALL index 97070604695..3a31e6f16c0 100644 --- a/INSTALL +++ b/INSTALL @@ -75,8 +75,8 @@ REQUIRES: OPTIONAL (but recommended): (1) OpenSSL library, necessary for encryption, version 0.9.8 or higher required, available from http://www.openssl.org/ - (2) PolarSSL library, an alternative for encryption, version 1.1 or higher - required, available from https://polarssl.org/ + (2) mbed TLS library, an alternative for encryption, version 2.0 or higher + required, available from https://tls.mbed.org/ (3) LZO real-time compression library, required for link compression, available from http://www.oberhumer.com/opensource/lzo/ OpenBSD users can use ports or packages to install lzo, but remember diff --git a/Makefile.am b/Makefile.am index 87da1825971..87af7241db7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -58,7 +58,7 @@ SUBDIRS = build distro include src sample doc vendor tests dist_doc_DATA = \ README \ README.IPv6 \ - README.polarssl \ + README.mbedtls \ Changes.rst \ COPYRIGHT.GPL \ COPYING @@ -68,7 +68,7 @@ dist_noinst_DATA = \ .gitattributes \ PORTS \ README.IPv6 TODO.IPv6 \ - README.polarssl \ + README.mbedtls \ openvpn.sln \ msvc-env.bat \ msvc-dev.bat \ diff --git a/README.polarssl b/README.mbedtls similarity index 65% rename from README.polarssl rename to README.mbedtls index 6f1fa51adcf..4875822da47 100644 --- a/README.polarssl +++ b/README.mbedtls @@ -1,18 +1,18 @@ -This version of OpenVPN has PolarSSL support. To enable follow the following +This version of OpenVPN has mbed TLS support. To enable follow the following instructions: To Build and Install, - ./configure --with-crypto-library=polarssl + ./configure --with-crypto-library=mbedtls make make install -This version depends on PolarSSL 1.3 (and requires at least 1.3.3). +This version depends on mbed TLS 2.0 (and requires at least 2.0.0). ************************************************************************* -Due to limitations in the PolarSSL library, the following features are missing -in the PolarSSL version of OpenVPN: +Due to limitations in the mbed TLS library, the following features are missing +in the mbed TLS version of OpenVPN: * PKCS#12 file support * --capath support - Loading certificate authorities from a directory diff --git a/doc/doxygen/doc_data_crypto.h b/doc/doxygen/doc_data_crypto.h index 925fcd52db1..c2b1866cb15 100644 --- a/doc/doxygen/doc_data_crypto.h +++ b/doc/doxygen/doc_data_crypto.h @@ -68,5 +68,5 @@ * * @par Crypto algorithms * This module uses the crypto algorithm implementations of the external - * crypto library (currently either OpenSSL (default), or PolarSSL). + * crypto library (currently either OpenSSL (default), or mbed TLS). */ diff --git a/doc/doxygen/doc_key_generation.h b/doc/doxygen/doc_key_generation.h index 4b225e09988..4109ac5df37 100644 --- a/doc/doxygen/doc_key_generation.h +++ b/doc/doxygen/doc_key_generation.h @@ -78,7 +78,7 @@ * * @subsection key_generation_random Source of random material * - * OpenVPN uses the either the OpenSSL library or the PolarSSL library as its + * OpenVPN uses the either the OpenSSL library or the mbed TLS library as its * source of random material. * * In OpenSSL, the \c RAND_bytes() function is called @@ -91,8 +91,8 @@ * - For OpenSSL's support for external crypto modules: * http://www.openssl.org/docs/crypto/engine.html * - * In PolarSSL, the Havege random number generator is used. For details, see - * the PolarSSL documentation. + * In mbed TLS, the Havege random number generator is used. For details, see + * the mbed TLS documentation. * * @section key_generation_exchange Key exchange: * diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 204374736ba..0b3e1ad7087 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -4473,7 +4473,7 @@ datagram replay protection as the IV. .\"********************************************************* .TP .B \-\-use\-prediction\-resistance -Enable prediction resistance on PolarSSL's RNG. +Enable prediction resistance on mbed TLS's RNG. Enabling prediction resistance causes the RNG to reseed in each call for random. Reseeding this often can quickly deplete the kernel @@ -4482,8 +4482,6 @@ entropy pool. If you need this option, please consider running a daemon that adds entropy to the kernel pool. -Note that this option only works with PolarSSL versions greater -than 1.1. .\"********************************************************* .TP .B \-\-test\-crypto @@ -4584,7 +4582,7 @@ they are distributed with OpenVPN, they are totally insecure. .TP .B \-\-capath dir Directory containing trusted certificates (CAs and CRLs). -Not available with PolarSSL. +Not available with mbed TLS. When using the .B \-\-capath @@ -4613,7 +4611,7 @@ Set .B file=none to disable Diffie Hellman key exchange (and use ECDH only). Note that this requires peers to be using an SSL library that supports ECDH TLS cipher suites -(e.g. OpenSSL 1.0.1+, or PolarSSL 1.3+). +(e.g. OpenSSL 1.0.1+, or mbed TLS 2.0+). Use .B openssl dhparam \-out dh2048.pem 2048 @@ -4718,7 +4716,7 @@ This option can be used instead of .B \-\-ca, \-\-cert, and .B \-\-key. -Not available with PolarSSL. +Not available with mbed TLS. .\"********************************************************* .TP .B \-\-verify\-hash hash [algo] @@ -4901,7 +4899,7 @@ channel, over which the keys that are used to protect the actual VPN traffic are exchanged. The supplied list of ciphers is (after potential OpenSSL/IANA name translation) -simply supplied to the crypto library. Please see the OpenSSL and/or PolarSSL +simply supplied to the crypto library. Please see the OpenSSL and/or mbed TLS documentation for details on the cipher list interpretation. Use @@ -4914,8 +4912,8 @@ is an expert feature, which \- if used correcly \- can improve the security of your VPN connection. But it is also easy to unwittingly use it to carefully align a gun with your foot, or just break your connection. Use with care! -The default for \-\-tls\-cipher is to use PolarSSL's default cipher list -when using PolarSSL or +The default for \-\-tls\-cipher is to use mbed TLS's default cipher list +when using mbed TLS or "DEFAULT:!EXP:!LOW:!MEDIUM:!kDH:!kECDH:!DSS:!PSK:!SRP:!kRSA" when using OpenSSL. .\"********************************************************* From 14e4c58b6f903c562475379bb806e26c42d6a52e Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Thu, 24 Aug 2017 15:55:47 +0800 Subject: [PATCH 624/643] fragment.c: simplify boolean expression !A || (A && B) is equivalent to the simpler !A || B therefore it is preferable to use the second version as it is simpler to parse while reading the code. Signed-off-by: Antonio Quartulli Acked-by: David Sommerseth Message-Id: <20170824075547.29844-1-a@unstable.cc> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15313.html Signed-off-by: David Sommerseth (cherry picked from commit 10ae9ed5fe7f09c7edb5af266149a9b5e9bcbaa4) --- src/openvpn/fragment.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openvpn/fragment.c b/src/openvpn/fragment.c index 38de62f12e9..84f012144c5 100644 --- a/src/openvpn/fragment.c +++ b/src/openvpn/fragment.c @@ -208,7 +208,7 @@ fragment_incoming(struct fragment_master *f, struct buffer *buf, } /* is this the first fragment for our sequence number? */ - if (!frag->defined || (frag->defined && frag->max_frag_size != size)) + if (!frag->defined || frag->max_frag_size != size) { frag->defined = true; frag->max_frag_size = size; From b1298bbb2be73e978bb5b555d1bd8722cf9b28b0 Mon Sep 17 00:00:00 2001 From: Gert van Dijk Date: Sun, 27 Aug 2017 18:15:15 +0200 Subject: [PATCH 625/643] Warn that DH config option is only meaningful in a tls-server context If specified in a tls-client context, don't try to open the file as it's not used. Worse even, if 'none' was specified to disable explicitly, it complained that the file 'none' could not be found. [DS: On-the-fly update - Prefixed the message with 'WARNING: '] Signed-off-by: Gert van Dijk Acked-by: Steffan Karger Acked-by: David Sommerseth Message-Id: <20170827161515.2424-1-gert@gertvandijk.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15332.html Signed-off-by: David Sommerseth (cherry picked from commit 47a0a80b7718fe88451c82bdfe838e5a6e3c4248) --- src/openvpn/options.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 79429d528b5..8dee5d13d0a 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -3027,6 +3027,13 @@ options_postprocess_mutate(struct options *o) o->dh_file = NULL; } } + else if (o->dh_file) + { + /* DH file is only meaningful in a tls-server context. */ + msg(M_WARN, "WARNING: Ignoring option 'dh' in tls-client mode, please only " + "include this in your server configuration"); + o->dh_file = NULL; + } /* cipher negotiation (NCP) currently assumes --pull or --mode server */ if (o->ncp_enabled From a4c5c4bba4963ad107d6bf6eb5937a4cde6c1a0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szil=C3=A1rd=20Pfeiffer?= Date: Mon, 4 Sep 2017 10:10:12 +0200 Subject: [PATCH 626/643] OpenSSL: Always set SSL_OP_CIPHER_SERVER_PREFERENCE flag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * safe bet to say that server admins are better at updating their configs than client users are and if client do want to restrict their ciphers, they should simply evict the ciphers they don't want from their cipher suite * mbed TLS and OpenSSL behave more similar with the SSL_OP_CIPHER_SERVER_PREFERENCE flag Signed-off-by: Szilárd Pfeiffer Acked-by: Steffan Karger Message-Id: <20170904081012.1975-1-coroner@pfeifferszilard.hu> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15356.html Signed-off-by: David Sommerseth (cherry picked from commit 5fd8e94d311825571931414064e4d13ed808f9b5) --- src/openvpn/ssl_openssl.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/openvpn/ssl_openssl.c b/src/openvpn/ssl_openssl.c index c8356aca775..b2663099d0d 100644 --- a/src/openvpn/ssl_openssl.c +++ b/src/openvpn/ssl_openssl.c @@ -253,6 +253,9 @@ tls_ctx_set_options(struct tls_root_ctx *ctx, unsigned int ssl_flags) sslopt |= SSL_OP_NO_TLSv1_2; } #endif +#ifdef SSL_OP_CIPHER_SERVER_PREFERENCE + sslopt |= SSL_OP_CIPHER_SERVER_PREFERENCE; +#endif #ifdef SSL_OP_NO_COMPRESSION /* Disable compression - flag not available in OpenSSL 0.9.8 */ sslopt |= SSL_OP_NO_COMPRESSION; From b49c1ca407e046debebf5633c117d679b9e20555 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Thu, 7 Sep 2017 01:47:05 +0200 Subject: [PATCH 627/643] systemd: Ensure systemd shuts down OpenVPN in a proper way By default, when systemd is stopping OpenVPN it will send the SIGTERM to all processes within the same process control-group. This can come as a surprise to plug-ins which may have fork()ed out child processes. So we tell systemd to only send the SIGTERM signal to the main OpenVPN process and let OpenVPN take care of the shutdown process on its own. If the main OpenVPN process does not stop within 90 seconds (unless changed), it will send SIGKILL to all remaining processes within the same process control-group. This issue have been reported in both Debian and Fedora. Trac: 581 Message-Id: <20170906234705.26202-1-davids@openvpn.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15369.html Signed-off-by: David Sommerseth [DS: Applied lazy-ack policy] (cherry picked from commit 29446a18e1f2b52d20f359253b085e96fe458367) --- distro/systemd/openvpn-client@.service.in | 1 + distro/systemd/openvpn-server@.service.in | 1 + 2 files changed, 2 insertions(+) diff --git a/distro/systemd/openvpn-client@.service.in b/distro/systemd/openvpn-client@.service.in index 49e3f51cc54..cbcef6533c3 100644 --- a/distro/systemd/openvpn-client@.service.in +++ b/distro/systemd/openvpn-client@.service.in @@ -17,6 +17,7 @@ DeviceAllow=/dev/null rw DeviceAllow=/dev/net/tun rw ProtectSystem=true ProtectHome=true +KillMode=process [Install] WantedBy=multi-user.target diff --git a/distro/systemd/openvpn-server@.service.in b/distro/systemd/openvpn-server@.service.in index 9a8a2c730c2..b343868a925 100644 --- a/distro/systemd/openvpn-server@.service.in +++ b/distro/systemd/openvpn-server@.service.in @@ -17,6 +17,7 @@ DeviceAllow=/dev/null rw DeviceAllow=/dev/net/tun rw ProtectSystem=true ProtectHome=true +KillMode=process [Install] WantedBy=multi-user.target From b3b7d073ce05fa6b11a28f9e70d66c4907274db5 Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Thu, 7 Sep 2017 17:55:30 +0800 Subject: [PATCH 628/643] tcp-server: ensure AF family is propagated to child context Commit 23d61c56 introduced the AF_UNSPEC socket family to be used when we don't know the actual one until the local socket binding is performed. In such case AF_UNSPEC is stored in the `ce.af` member of the `c->options` object, indicating that the family has to be determined at runtime. However, the determined value is never propagated back to the `options` object, which remains AF_UNSPEC and that is later used to initialize the TCP children contexts (UDP children contexts are unaffected). This unexpected setting can trigger weird behaviours, like the one reported in ticket #933. In this case the value AF_UNSPEC in combination with the changes implemented in 2bed089d are leading to a TCP server quitting with M_FATAL upon client connection. Note that the misbehaviour described in #933 can only be triggered when running a TCP server with mtu-disc set in the config (no matter the value). Fix this inconsistency by always propagating the AF family from the top to the child context when running in TCP server mode. As a direct consequence, this patch fixes Trac #933. Trac: 933 Signed-off-by: Antonio Quartulli Acked-by: Arne Schwabe Message-Id: <20170907095530.15972-1-a@unstable.cc> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15380.html Signed-off-by: David Sommerseth (cherry picked from commit 682e7feac3bd57e6ce7e60504cb4da5c894d0e18) --- src/openvpn/socket.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c index 3d4f881e67e..0fc91f2136d 100644 --- a/src/openvpn/socket.c +++ b/src/openvpn/socket.c @@ -1786,6 +1786,8 @@ link_socket_init_phase1(struct link_socket *sock, ASSERT(sock->info.proto == PROTO_TCP_SERVER); ASSERT(!sock->inetd); sock->sd = accept_from->sd; + /* inherit (possibly guessed) info AF from parent context */ + sock->info.af = accept_from->info.af; } /* are we running in HTTP proxy mode? */ From 1c112c38d46207905bff97969cf787baada59711 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Thu, 7 Sep 2017 01:52:02 +0200 Subject: [PATCH 629/643] systemd: Enable systemd's auto-restart feature for server profiles Systemd supervises services it has started and can act upon unexpected scenarios. This change will restart OpenVPN after 5 seconds if the OpenVPN process exits unexpectedly. The on-failure mode is the recommended mode by upstream systemd. This change have been tested on a test server for some month, and it works indeed as intended when provoking the OpenVPN process to stop. Signed-off-by: David Sommerseth Acked-by: David Sommerseth Message-Id: <20170906235202.26551-1-davids@openvpn.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15370.html Signed-off-by: David Sommerseth (cherry picked from commit a4686e99b047081f0ef6f7945450183088464aa5) --- distro/systemd/openvpn-server@.service.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/distro/systemd/openvpn-server@.service.in b/distro/systemd/openvpn-server@.service.in index b343868a925..a8366a04d3d 100644 --- a/distro/systemd/openvpn-server@.service.in +++ b/distro/systemd/openvpn-server@.service.in @@ -18,6 +18,8 @@ DeviceAllow=/dev/net/tun rw ProtectSystem=true ProtectHome=true KillMode=process +RestartSec=5s +Restart=on-failure [Install] WantedBy=multi-user.target From c7e259160b28e94e4ea7f0ef767f8134283af255 Mon Sep 17 00:00:00 2001 From: Steffan Karger Date: Tue, 15 Aug 2017 10:04:33 +0200 Subject: [PATCH 630/643] Fix bounds check in read_key() The bounds check in read_key() was performed after using the value, instead of before. If 'key-method 1' is used, this allowed an attacker to send a malformed packet to trigger a stack buffer overflow. Fix this by moving the input validation to before the writes. Note that 'key-method 1' has been replaced by 'key method 2' as the default in OpenVPN 2.0 (released on 2005-04-17), and explicitly deprecated in 2.4 and marked for removal in 2.5. This should limit the amount of users impacted by this issue. CVE: 2017-12166 Signed-off-by: Steffan Karger Acked-by: Gert Doering Acked-by: David Sommerseth Message-Id: <80690690-67ac-3320-1891-9fecedc6a1fa@fox-it.com> URL: https://www.mail-archive.com/search?l=mid&q=80690690-67ac-3320-1891-9fecedc6a1fa@fox-it.com Signed-off-by: David Sommerseth (cherry picked from commit 3b1a61e9fb27213c46f76312f4065816bee8ed01) --- src/openvpn/crypto.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c index 33d6fe1ad1c..03e880e279b 100644 --- a/src/openvpn/crypto.c +++ b/src/openvpn/crypto.c @@ -1689,6 +1689,11 @@ read_key(struct key *key, const struct key_type *kt, struct buffer *buf) goto read_err; } + if (cipher_length != kt->cipher_length || hmac_length != kt->hmac_length) + { + goto key_len_err; + } + if (!buf_read(buf, key->cipher, cipher_length)) { goto read_err; @@ -1698,11 +1703,6 @@ read_key(struct key *key, const struct key_type *kt, struct buffer *buf) goto read_err; } - if (cipher_length != kt->cipher_length || hmac_length != kt->hmac_length) - { - goto key_len_err; - } - return 1; read_err: From 38da61f3cc2f06ff7d3d174576dc5c6e87d6d174 Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Thu, 7 Sep 2017 19:20:04 +0200 Subject: [PATCH 631/643] lz4: Move towards a newer LZ4 API We are using a deprecated function, LZ4_compress_limitedOutput(), which will be removed with time. The correct function to use is LZ4_compress_default(). Both function takes the same number of arguments and data types, so the change is minimal. This patch will also enforce the system LZ4 library to be at least v1.7.1. If the system library is not found or it is older, it will be build using the bundled LZ4 library. The version number requirement is based on the LZ4 version we ship. The changes in configure.ac for the version check is modelled around the same approach we use for OpenSSL. Plus it does a few minor reformats and improvements to comply with more recommend autoconf coding style. This patch is a result of the discussions in this mail thread: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14135.html Acked-by: Gert Doering Message-Id: <20170907172004.22534-1-davids@openvpn.net> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg15396.html Signed-off-by: David Sommerseth (cherry picked from commit 5f6225c32e41a922069964d9d59c2fcd6589f74c) --- configure.ac | 70 ++++++++++++++++++++++++++++++------------ src/openvpn/comp-lz4.c | 3 +- 2 files changed, 52 insertions(+), 21 deletions(-) diff --git a/configure.ac b/configure.ac index db671875515..50d25456063 100644 --- a/configure.ac +++ b/configure.ac @@ -1068,37 +1068,67 @@ dnl AC_ARG_VAR([LZ4_CFLAGS], [C compiler flags for lz4]) AC_ARG_VAR([LZ4_LIBS], [linker flags for lz4]) if test "$enable_lz4" = "yes" && test "$enable_comp_stub" = "no"; then - AC_CHECKING([for LZ4 Library and Header files]) - havelz4lib=1 - - # if LZ4_LIBS is set, we assume it will work, otherwise test - if test -z "${LZ4_LIBS}"; then - AC_CHECK_LIB(lz4, LZ4_compress, - [ LZ4_LIBS="-llz4" ], - [ - AC_MSG_RESULT([LZ4 library not found.]) - havelz4lib=0 - ]) + if test -z "${LZ4_CFLAGS}" -a -z "${LZ4_LIBS}"; then + # if the user did not explicitly specify flags, try to autodetect + PKG_CHECK_MODULES([LZ4], + [liblz4 >= 1.7.1], + [have_lz4="yes"], + [] # If this fails, we will do another test next + ) fi saved_CFLAGS="${CFLAGS}" + saved_LIBS="${LIBS}" CFLAGS="${CFLAGS} ${LZ4_CFLAGS}" - AC_CHECK_HEADERS(lz4.h, - , - [ - AC_MSG_RESULT([LZ4 headers not found.]) - havelz4lib=0 - ]) + LIBS="${LIBS} ${LZ4_LIBS}" + + # If pkgconfig check failed or LZ4_CFLAGS/LZ4_LIBS env vars + # are used, check the version directly in the LZ4 include file + if test "${have_lz4}" != "yes"; then + AC_CHECK_HEADERS([lz4.h], + [have_lz4h="yes"], + []) + + if test "${have_lz4h}" = "yes" ; then + AC_MSG_CHECKING([additionally if system LZ4 version >= 1.7.1]) + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([[ +#include + ]], + [[ +/* Version encoding: MMNNPP (Major miNor Patch) - see lz4.h for details */ +#if LZ4_VERSION_NUMBER < 10701L +#error LZ4 is too old +#endif + ]] + )], + [ + AC_MSG_RESULT([ok]) + have_lz4="yes" + ], + [AC_MSG_RESULT([system LZ4 library is too old])] + ) + fi + fi + + # if LZ4_LIBS is set, we assume it will work, otherwise test + if test -z "${LZ4_LIBS}"; then + AC_CHECK_LIB([lz4], + [LZ4_compress], + [LZ4_LIBS="-llz4"], + [have_lz4="no"]) + fi - if test $havelz4lib = 0 ; then - AC_MSG_RESULT([LZ4 library or header not found, using version in src/compat/compat-lz4.*]) + if test "${have_lz4}" != "yes" ; then + AC_MSG_RESULT([ usuable LZ4 library or header not found, using version in src/compat/compat-lz4.*]) AC_DEFINE([NEED_COMPAT_LZ4], [1], [use copy of LZ4 source in compat/]) LZ4_LIBS="" fi OPTIONAL_LZ4_CFLAGS="${LZ4_CFLAGS}" OPTIONAL_LZ4_LIBS="${LZ4_LIBS}" - AC_DEFINE(ENABLE_LZ4, 1, [Enable LZ4 compression library]) + AC_DEFINE(ENABLE_LZ4, [1], [Enable LZ4 compression library]) CFLAGS="${saved_CFLAGS}" + LIBS="${saved_LIBS}" fi diff --git a/src/openvpn/comp-lz4.c b/src/openvpn/comp-lz4.c index e056caa8a8c..9598853ff60 100644 --- a/src/openvpn/comp-lz4.c +++ b/src/openvpn/comp-lz4.c @@ -43,6 +43,7 @@ #include "memdbg.h" + static void lz4_compress_init(struct compress_context *compctx) { @@ -86,7 +87,7 @@ do_lz4_compress(struct buffer *buf, return false; } - zlen = LZ4_compress_limitedOutput((const char *)BPTR(buf), (char *)BPTR(work), BLEN(buf), zlen_max ); + zlen = LZ4_compress_default((const char *)BPTR(buf), (char *)BPTR(work), BLEN(buf), zlen_max); if (zlen <= 0) { From 1f458322cdaffed02184df8c638bde69256a840a Mon Sep 17 00:00:00 2001 From: David Sommerseth Date: Mon, 25 Sep 2017 21:30:38 +0200 Subject: [PATCH 632/643] Prepare the release of OpenVPN 2.4.4 Signed-off-by: David Sommerseth --- ChangeLog | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++ Changes.rst | 39 ++++++++++++++++++++++- version.m4 | 4 +-- 3 files changed, 129 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 537beaafa43..591451cee68 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,95 @@ OpenVPN Change Log Copyright (C) 2002-2017 OpenVPN Technologies, Inc. +2017.09.25 -- Version 2.4.4 +Antonio Quartulli (23): + crypto: correct typ0 in error message + use M_ERRNO instead of explicitly printing errno + don't print errno twice + ntlm: avoid useless cast + ntlm: unwrap multiple function calls + route: improve error message + management: preserve wait_for_push field when asking for user/pass + tls-crypt: avoid warnings when --disable-crypto is used + ntlm: convert binary buffers to uint8_t * + ntlm: restyle compressed multiple function calls + ntlm: improve code style and readability + OpenSSL: remove unreachable call to SSL_CTX_get0_privatekey() + make function declarations C99 compliant + remove unused functions + use NULL instead of 0 when assigning pointers + add missing static attribute to functions + ntlm: avoid breaking anti-aliasing rules + remove the --disable-multi config switch + rename mroute_extract_addr_ipv4 to mroute_extract_addr_ip + route: avoid definition of unused variables in certain configurations + fix a couple of typ0s in comments and strings + fragment.c: simplify boolean expression + tcp-server: ensure AF family is propagated to child context + +Arne Schwabe (2): + Set tls-cipher restriction before loading certificates + Print ec bit details, refuse management-external-key if key is not RSA + +Conrad Hoffmann (2): + Use provided env vars in up/down script. + Document down-root plugin usage in client.down + +David Sommerseth (11): + doc: The CRL processing is not a deprecated feature + cleanup: Move write_pid() to where it is being used + contrib: Remove keychain-mcd code + cleanup: Move init_random_seed() to where it is being used + sample-plugins: fix ASN1_STRING_to_UTF8 return value checks + Highlight deprecated features + Use consistent version references + docs: Replace all PolarSSL references to mbed TLS + systemd: Ensure systemd shuts down OpenVPN in a proper way + systemd: Enable systemd's auto-restart feature for server profiles + lz4: Move towards a newer LZ4 API + +Emmanuel Deloget (3): + OpenSSL: remove pre-1.1 function from the OpenSSL compat interface + OpenSSL: remove EVP_CIPHER_CTX_new() from the compat layer + OpenSSL: remove EVP_CIPHER_CTX_free() from the compat layer + +Gert van Dijk (1): + Warn that DH config option is only meaningful in a tls-server context + +Ilya Shipitsin (3): + travis-ci: add 3 missing patches from master to release/2.4 + travis-ci: update openssl to 1.0.2l, update mbedtls to 2.5.1 + travis-ci: update pkcs11-helper to 1.22 + +Richard Bonhomme (1): + man: Corrections to doc/openvpn.8 + +Steffan Karger (17): + Fix typo in extract_x509_extension() debug message + Move adjust_power_of_2() to integer.h + Undo cipher push in client options state if cipher is rejected + Remove strerror_ts() + Move openvpn_sleep() to manage.c + fixup: also change missed openvpn_sleep() occurrences + Always use default keysize for NCP'd ciphers + Move create_temp_file() out of #ifdef ENABLE_CRYPTO + Deprecate --keysize + Deprecate --no-replay + Move run_up_down() to init.c + tls-crypt: introduce tls_crypt_kt() + crypto: create function to initialize encrypt and decrypt key + Add coverity static analysis to Travis CI config + tls-crypt: don't leak memory for incorrect tls-crypt messages + travis: reorder matrix to speed up build + Fix bounds check in read_key() + +Szilárd Pfeiffer (1): + OpenSSL: Always set SSL_OP_CIPHER_SERVER_PREFERENCE flag + +Thomas Veerman via Openvpn-devel (1): + Fix socks_proxy_port pointing to invalid data + + 2017.06.21 -- Version 2.4.3 Antonio Quartulli (1): Ignore auth-nocache for auth-user-pass if auth-token is pushed diff --git a/Changes.rst b/Changes.rst index fd31d8779c5..d5e12eba6ff 100644 --- a/Changes.rst +++ b/Changes.rst @@ -325,13 +325,50 @@ Maintainer-visible changes i386/i686 builds on RHEL5. - Version 2.4.4 ============= +This is primarily a maintenance release, with further improved OpenSSL 1.1 +integration, several minor bug fixes and other minor improvements. + +Bug fixes +--------- +- Fix issues when a pushed cipher via the Negotiable Crypto Parameters (NCP) is + rejected by the remote side + +- Ignore ``--keysize`` when NCP have resulted in a changed cipher. + +- Configurations using ``--auth-nocache`` and the management interface to provide + user credentials (like NetworkManager on Linux) on client side with servers + implementing authentication tokens (for example, using ``--auth-gen-token``) + will now behave correctly and not query the user for an, to them, unknown + authentication token on renegotiations of the tunnel. + +- Fix bug causing invalid or corrupt SOCKS port number when changing the + proxy via the management interface. + +- The man page should now have proper escaping of hyphens/minus characters + and have seen some minor corrections. + +User-visible Changes +-------------------- +- Linux servers with systemd which uses the ``openvpn-server@.service`` unit + file for server configurations will now utilize the automatic restart feature + in systemd. If the OpenVPN server process dies unexpectedly, systemd will + ensure the OpenVPN configuration will be restarted without any user interaction. Deprecated features ------------------- - ``--no-replay`` is deprecated and will be removed in OpenVPN 2.5. +- ``--keysize`` is deprecated in OpenVPN 2.4 and will be removed in v2.6 + +Security +-------- +- CVE-2017-12166: Fix bounds check for configurations using ``--key-method 1``. + Before this fix, it could allow an attacker to send a malformed packet to + trigger a stack overflow. This is considered to be a low risk issue, as + ``--key-method 2`` has been the default since OpenVPN 2.0 (released on + 2005-04-17). This option is already deprecated in v2.4 and will be + completely removed in v2.5. Version 2.4.3 diff --git a/version.m4 b/version.m4 index f18193b595e..48a12806746 100644 --- a/version.m4 +++ b/version.m4 @@ -3,12 +3,12 @@ define([PRODUCT_NAME], [OpenVPN]) define([PRODUCT_TARNAME], [openvpn]) define([PRODUCT_VERSION_MAJOR], [2]) define([PRODUCT_VERSION_MINOR], [4]) -define([PRODUCT_VERSION_PATCH], [.3]) +define([PRODUCT_VERSION_PATCH], [.4]) m4_append([PRODUCT_VERSION], [PRODUCT_VERSION_MAJOR]) m4_append([PRODUCT_VERSION], [PRODUCT_VERSION_MINOR], [[.]]) m4_append([PRODUCT_VERSION], [PRODUCT_VERSION_PATCH], [[]]) define([PRODUCT_BUGREPORT], [openvpn-users@lists.sourceforge.net]) -define([PRODUCT_VERSION_RESOURCE], [2,4,3,0]) +define([PRODUCT_VERSION_RESOURCE], [2,4,4,0]) dnl define the TAP version define([PRODUCT_TAP_WIN_COMPONENT_ID], [tap0901]) define([PRODUCT_TAP_WIN_MIN_MAJOR], [9]) From ebbca63efa1cfac50381902b6dc380c0b5101981 Mon Sep 17 00:00:00 2001 From: Fabian Knittel Date: Wed, 14 Apr 2010 00:16:29 +0200 Subject: [PATCH 633/643] client-connect: Split multi_connection_established into separate functions This patch splits up the multi_connection_established() function. Each new helper function does a specific job. Functions that do a similar job receive a similar calling interface. The patch tries not to reindent code, so that the real changes are as clearly visible as possible. (A follow-up patch will only do indentation changes.) Signed-off-by: Fabian Knittel --- src/openvpn/multi.c | 4680 +++++++++++++++++++---------------------- src/openvpn/options.h | 6 + 2 files changed, 2225 insertions(+), 2461 deletions(-) diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index c798c438519..648fddb9537 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -27,11 +27,6 @@ #include "config-msvc.h" #endif -#ifdef HAVE_SYS_INOTIFY_H -#include -#define INOTIFY_EVENT_BUFFER_SIZE 16384 -#endif - #include "syshead.h" #if P2MP_SERVER @@ -54,28 +49,22 @@ #ifdef MULTI_DEBUG_EVENT_LOOP static const char * -id(struct multi_instance *mi) +id (struct multi_instance *mi) { - if (mi) - { - return tls_common_name(mi->context.c2.tls_multi, false); - } - else - { - return "NULL"; - } + if (mi) + return tls_common_name (mi->context.c2.tls_multi, false); + else + return "NULL"; } #endif #ifdef MANAGEMENT_DEF_AUTH static void -set_cc_config(struct multi_instance *mi, struct buffer_list *cc_config) +set_cc_config (struct multi_instance *mi, struct buffer_list *cc_config) { - if (mi->cc_config) - { - buffer_list_free(mi->cc_config); - } - mi->cc_config = cc_config; + if (mi->cc_config) + buffer_list_free (mi->cc_config); + mi->cc_config = cc_config; } #endif @@ -83,443 +72,377 @@ static inline void update_mstat_n_clients(const int n_clients) { #ifdef ENABLE_MEMSTATS - if (mmap_stats) - { - mmap_stats->n_clients = n_clients; - } + if (mmap_stats) + mmap_stats->n_clients = n_clients; #endif } static bool -learn_address_script(const struct multi_context *m, - const struct multi_instance *mi, - const char *op, - const struct mroute_addr *addr) -{ - struct gc_arena gc = gc_new(); - struct env_set *es; - bool ret = true; - struct plugin_list *plugins; - - /* get environmental variable source */ - if (mi && mi->context.c2.es) - { - es = mi->context.c2.es; - } - else - { - es = env_set_create(&gc); - } - - /* get plugin source */ - if (mi) - { - plugins = mi->context.plugins; - } - else - { - plugins = m->top.plugins; - } - - if (plugin_defined(plugins, OPENVPN_PLUGIN_LEARN_ADDRESS)) - { - struct argv argv = argv_new(); - argv_printf(&argv, "%s %s", - op, - mroute_addr_print(addr, &gc)); - if (mi) - { - argv_printf_cat(&argv, "%s", tls_common_name(mi->context.c2.tls_multi, false)); - } - if (plugin_call(plugins, OPENVPN_PLUGIN_LEARN_ADDRESS, &argv, NULL, es) != OPENVPN_PLUGIN_FUNC_SUCCESS) - { - msg(M_WARN, "WARNING: learn-address plugin call failed"); - ret = false; - } - argv_reset(&argv); - } - - if (m->top.options.learn_address_script) - { - struct argv argv = argv_new(); - setenv_str(es, "script_type", "learn-address"); - argv_parse_cmd(&argv, m->top.options.learn_address_script); - argv_printf_cat(&argv, "%s %s", op, mroute_addr_print(addr, &gc)); - if (mi) - { - argv_printf_cat(&argv, "%s", tls_common_name(mi->context.c2.tls_multi, false)); - } - if (!openvpn_run_script(&argv, es, 0, "--learn-address")) - { - ret = false; - } - argv_reset(&argv); - } - - gc_free(&gc); - return ret; +learn_address_script (const struct multi_context *m, + const struct multi_instance *mi, + const char *op, + const struct mroute_addr *addr) +{ + struct gc_arena gc = gc_new (); + struct env_set *es; + bool ret = true; + struct plugin_list *plugins; + + /* get environmental variable source */ + if (mi && mi->context.c2.es) + es = mi->context.c2.es; + else + es = env_set_create (&gc); + + /* get plugin source */ + if (mi) + plugins = mi->context.plugins; + else + plugins = m->top.plugins; + + if (plugin_defined (plugins, OPENVPN_PLUGIN_LEARN_ADDRESS)) + { + struct argv argv = argv_new (); + argv_printf (&argv, "%s %s", + op, + mroute_addr_print (addr, &gc)); + if (mi) + argv_printf_cat (&argv, "%s", tls_common_name (mi->context.c2.tls_multi, false)); + if (plugin_call (plugins, OPENVPN_PLUGIN_LEARN_ADDRESS, &argv, NULL, es) != OPENVPN_PLUGIN_FUNC_SUCCESS) + { + msg (M_WARN, "WARNING: learn-address plugin call failed"); + ret = false; + } + argv_reset (&argv); + } + + if (m->top.options.learn_address_script) + { + struct argv argv = argv_new (); + setenv_str (es, "script_type", "learn-address"); + argv_printf (&argv, "%sc %s %s", + m->top.options.learn_address_script, + op, + mroute_addr_print (addr, &gc)); + if (mi) + argv_printf_cat (&argv, "%s", tls_common_name (mi->context.c2.tls_multi, false)); + if (!openvpn_run_script (&argv, es, 0, "--learn-address")) + ret = false; + argv_reset (&argv); + } + + gc_free (&gc); + return ret; } void -multi_ifconfig_pool_persist(struct multi_context *m, bool force) +multi_ifconfig_pool_persist (struct multi_context *m, bool force) { - /* write pool data to file */ - if (m->ifconfig_pool - && m->top.c1.ifconfig_pool_persist - && (force || ifconfig_pool_write_trigger(m->top.c1.ifconfig_pool_persist))) + /* write pool data to file */ + if (m->ifconfig_pool + && m->top.c1.ifconfig_pool_persist + && (force || ifconfig_pool_write_trigger (m->top.c1.ifconfig_pool_persist))) { - ifconfig_pool_write(m->top.c1.ifconfig_pool_persist, m->ifconfig_pool); + ifconfig_pool_write (m->top.c1.ifconfig_pool_persist, m->ifconfig_pool); } } static void -multi_reap_range(const struct multi_context *m, - int start_bucket, - int end_bucket) +multi_reap_range (const struct multi_context *m, + int start_bucket, + int end_bucket) { - struct gc_arena gc = gc_new(); - struct hash_iterator hi; - struct hash_element *he; + struct gc_arena gc = gc_new (); + struct hash_iterator hi; + struct hash_element *he; - if (start_bucket < 0) + if (start_bucket < 0) { - start_bucket = 0; - end_bucket = hash_n_buckets(m->vhash); + start_bucket = 0; + end_bucket = hash_n_buckets (m->vhash); } - dmsg(D_MULTI_DEBUG, "MULTI: REAP range %d -> %d", start_bucket, end_bucket); - hash_iterator_init_range(m->vhash, &hi, start_bucket, end_bucket); - while ((he = hash_iterator_next(&hi)) != NULL) + dmsg (D_MULTI_DEBUG, "MULTI: REAP range %d -> %d", start_bucket, end_bucket); + hash_iterator_init_range (m->vhash, &hi, start_bucket, end_bucket); + while ((he = hash_iterator_next (&hi)) != NULL) { - struct multi_route *r = (struct multi_route *) he->value; - if (!multi_route_defined(m, r)) - { - dmsg(D_MULTI_DEBUG, "MULTI: REAP DEL %s", - mroute_addr_print(&r->addr, &gc)); - learn_address_script(m, NULL, "delete", &r->addr); - multi_route_del(r); - hash_iterator_delete_element(&hi); - } + struct multi_route *r = (struct multi_route *) he->value; + if (!multi_route_defined (m, r)) + { + dmsg (D_MULTI_DEBUG, "MULTI: REAP DEL %s", + mroute_addr_print (&r->addr, &gc)); + learn_address_script (m, NULL, "delete", &r->addr); + multi_route_del (r); + hash_iterator_delete_element (&hi); + } } - hash_iterator_free(&hi); - gc_free(&gc); + hash_iterator_free (&hi); + gc_free (&gc); } static void -multi_reap_all(const struct multi_context *m) +multi_reap_all (const struct multi_context *m) { - multi_reap_range(m, -1, 0); + multi_reap_range (m, -1, 0); } static struct multi_reap * -multi_reap_new(int buckets_per_pass) +multi_reap_new (int buckets_per_pass) { - struct multi_reap *mr; - ALLOC_OBJ(mr, struct multi_reap); - mr->bucket_base = 0; - mr->buckets_per_pass = buckets_per_pass; - mr->last_call = now; - return mr; + struct multi_reap *mr; + ALLOC_OBJ (mr, struct multi_reap); + mr->bucket_base = 0; + mr->buckets_per_pass = buckets_per_pass; + mr->last_call = now; + return mr; } void -multi_reap_process_dowork(const struct multi_context *m) +multi_reap_process_dowork (const struct multi_context *m) { - struct multi_reap *mr = m->reaper; - if (mr->bucket_base >= hash_n_buckets(m->vhash)) - { - mr->bucket_base = 0; - } - multi_reap_range(m, mr->bucket_base, mr->bucket_base + mr->buckets_per_pass); - mr->bucket_base += mr->buckets_per_pass; - mr->last_call = now; + struct multi_reap *mr = m->reaper; + if (mr->bucket_base >= hash_n_buckets (m->vhash)) + mr->bucket_base = 0; + multi_reap_range (m, mr->bucket_base, mr->bucket_base + mr->buckets_per_pass); + mr->bucket_base += mr->buckets_per_pass; + mr->last_call = now; } static void -multi_reap_free(struct multi_reap *mr) +multi_reap_free (struct multi_reap *mr) { - free(mr); + free (mr); } /* * How many buckets in vhash to reap per pass. */ static int -reap_buckets_per_pass(int n_buckets) +reap_buckets_per_pass (int n_buckets) { - return constrain_int(n_buckets / REAP_DIVISOR, REAP_MIN, REAP_MAX); + return constrain_int (n_buckets / REAP_DIVISOR, REAP_MIN, REAP_MAX); } #ifdef MANAGEMENT_DEF_AUTH static uint32_t -cid_hash_function(const void *key, uint32_t iv) +cid_hash_function (const void *key, uint32_t iv) { - const unsigned long *k = (const unsigned long *)key; - return (uint32_t) *k; + const unsigned long *k = (const unsigned long *)key; + return (uint32_t) *k; } static bool -cid_compare_function(const void *key1, const void *key2) +cid_compare_function (const void *key1, const void *key2) { - const unsigned long *k1 = (const unsigned long *)key1; - const unsigned long *k2 = (const unsigned long *)key2; - return *k1 == *k2; + const unsigned long *k1 = (const unsigned long *)key1; + const unsigned long *k2 = (const unsigned long *)key2; + return *k1 == *k2; } #endif -#ifdef ENABLE_ASYNC_PUSH -static uint32_t -/* - * inotify watcher descriptors are used as hash value - */ -int_hash_function(const void *key, uint32_t iv) -{ - return (unsigned long)key; -} - -static bool -int_compare_function(const void *key1, const void *key2) -{ - return (unsigned long)key1 == (unsigned long)key2; -} -#endif - /* * Main initialization function, init multi_context object. */ void -multi_init(struct multi_context *m, struct context *t, bool tcp_mode, int thread_mode) -{ - int dev = DEV_TYPE_UNDEF; - - msg(D_MULTI_LOW, "MULTI: multi_init called, r=%d v=%d", - t->options.real_hash_size, - t->options.virtual_hash_size); - - /* - * Get tun/tap/null device type - */ - dev = dev_type_enum(t->options.dev, t->options.dev_type); - - /* - * Init our multi_context object. - */ - CLEAR(*m); - - m->thread_mode = thread_mode; - - /* - * Real address hash table (source port number is - * considered to be part of the address). Used - * to determine which client sent an incoming packet - * which is seen on the TCP/UDP socket. - */ - m->hash = hash_init(t->options.real_hash_size, - get_random(), - mroute_addr_hash_function, - mroute_addr_compare_function); - - /* - * Virtual address hash table. Used to determine - * which client to route a packet to. - */ - m->vhash = hash_init(t->options.virtual_hash_size, - get_random(), - mroute_addr_hash_function, - mroute_addr_compare_function); - - /* - * This hash table is a clone of m->hash but with a - * bucket size of one so that it can be used - * for fast iteration through the list. - */ - m->iter = hash_init(1, - get_random(), - mroute_addr_hash_function, - mroute_addr_compare_function); +multi_init (struct multi_context *m, struct context *t, bool tcp_mode, int thread_mode) +{ + int dev = DEV_TYPE_UNDEF; + + msg (D_MULTI_LOW, "MULTI: multi_init called, r=%d v=%d", + t->options.real_hash_size, + t->options.virtual_hash_size); + + /* + * Get tun/tap/null device type + */ + dev = dev_type_enum (t->options.dev, t->options.dev_type); + + /* + * Init our multi_context object. + */ + CLEAR (*m); + + m->thread_mode = thread_mode; + + /* + * Real address hash table (source port number is + * considered to be part of the address). Used + * to determine which client sent an incoming packet + * which is seen on the TCP/UDP socket. + */ + m->hash = hash_init (t->options.real_hash_size, + get_random (), + mroute_addr_hash_function, + mroute_addr_compare_function); + + /* + * Virtual address hash table. Used to determine + * which client to route a packet to. + */ + m->vhash = hash_init (t->options.virtual_hash_size, + get_random (), + mroute_addr_hash_function, + mroute_addr_compare_function); + + /* + * This hash table is a clone of m->hash but with a + * bucket size of one so that it can be used + * for fast iteration through the list. + */ + m->iter = hash_init (1, + get_random (), + mroute_addr_hash_function, + mroute_addr_compare_function); #ifdef MANAGEMENT_DEF_AUTH - m->cid_hash = hash_init(t->options.real_hash_size, - 0, - cid_hash_function, - cid_compare_function); -#endif - -#ifdef ENABLE_ASYNC_PUSH - /* - * Mapping between inotify watch descriptors and - * multi_instances. - */ - m->inotify_watchers = hash_init(t->options.real_hash_size, - get_random(), - int_hash_function, - int_compare_function); + m->cid_hash = hash_init (t->options.real_hash_size, + 0, + cid_hash_function, + cid_compare_function); #endif - /* - * This is our scheduler, for time-based wakeup - * events. - */ - m->schedule = schedule_init(); - - /* - * Limit frequency of incoming connections to control - * DoS. - */ - m->new_connection_limiter = frequency_limit_init(t->options.cf_max, - t->options.cf_per); - - /* - * Allocate broadcast/multicast buffer list - */ - m->mbuf = mbuf_init(t->options.n_bcast_buf); - - /* - * Different status file format options are available - */ - m->status_file_version = t->options.status_file_version; - - /* - * Possibly allocate an ifconfig pool, do it - * differently based on whether a tun or tap style - * tunnel. - */ - if (t->options.ifconfig_pool_defined) - { - int pool_type = IFCONFIG_POOL_INDIV; - - if (dev == DEV_TYPE_TUN && t->options.topology == TOP_NET30) - { - pool_type = IFCONFIG_POOL_30NET; - } - - m->ifconfig_pool = ifconfig_pool_init(pool_type, - t->options.ifconfig_pool_start, - t->options.ifconfig_pool_end, - t->options.duplicate_cn, - t->options.ifconfig_ipv6_pool_defined, - t->options.ifconfig_ipv6_pool_base, - t->options.ifconfig_ipv6_pool_netbits ); - - /* reload pool data from file */ - if (t->c1.ifconfig_pool_persist) - { - ifconfig_pool_read(t->c1.ifconfig_pool_persist, m->ifconfig_pool); - } + /* + * This is our scheduler, for time-based wakeup + * events. + */ + m->schedule = schedule_init (); + + /* + * Limit frequency of incoming connections to control + * DoS. + */ + m->new_connection_limiter = frequency_limit_init (t->options.cf_max, + t->options.cf_per); + + /* + * Allocate broadcast/multicast buffer list + */ + m->mbuf = mbuf_init (t->options.n_bcast_buf); + + /* + * Different status file format options are available + */ + m->status_file_version = t->options.status_file_version; + + /* + * Possibly allocate an ifconfig pool, do it + * differently based on whether a tun or tap style + * tunnel. + */ + if (t->options.ifconfig_pool_defined) + { + int pool_type = IFCONFIG_POOL_INDIV; + + if ( dev == DEV_TYPE_TUN && t->options.topology == TOP_NET30 ) + pool_type = IFCONFIG_POOL_30NET; + + m->ifconfig_pool = ifconfig_pool_init (pool_type, + t->options.ifconfig_pool_start, + t->options.ifconfig_pool_end, + t->options.duplicate_cn, + t->options.ifconfig_ipv6_pool_defined, + t->options.ifconfig_ipv6_pool_base, + t->options.ifconfig_ipv6_pool_netbits ); + + /* reload pool data from file */ + if (t->c1.ifconfig_pool_persist) + ifconfig_pool_read (t->c1.ifconfig_pool_persist, m->ifconfig_pool); + } + + /* + * Help us keep track of routing table. + */ + m->route_helper = mroute_helper_init (MULTI_CACHE_ROUTE_TTL); + + /* + * Initialize route and instance reaper. + */ + m->reaper = multi_reap_new (reap_buckets_per_pass (t->options.virtual_hash_size)); + + /* + * Get local ifconfig address + */ + CLEAR (m->local); + ASSERT (t->c1.tuntap); + mroute_extract_in_addr_t (&m->local, t->c1.tuntap->local); + + /* + * Per-client limits + */ + m->max_clients = t->options.max_clients; + + m->instances = calloc(m->max_clients, sizeof(struct multi_instance*)); + + /* + * Initialize multi-socket TCP I/O wait object + */ + if (tcp_mode) + m->mtcp = multi_tcp_init (t->options.max_clients, &m->max_clients); + m->tcp_queue_limit = t->options.tcp_queue_limit; + + /* + * Allow client <-> client communication, without going through + * tun/tap interface and network stack? + */ + m->enable_c2c = t->options.enable_c2c; + + /* initialize stale routes check timer */ + if (t->options.stale_routes_check_interval > 0) + { + msg (M_INFO, "Initializing stale route check timer to run every %i seconds and to removing routes with activity timeout older than %i seconds", + t->options.stale_routes_check_interval, t->options.stale_routes_ageing_time); + event_timeout_init (&m->stale_routes_check_et, t->options.stale_routes_check_interval, 0); } - - /* - * Help us keep track of routing table. - */ - m->route_helper = mroute_helper_init(MULTI_CACHE_ROUTE_TTL); - - /* - * Initialize route and instance reaper. - */ - m->reaper = multi_reap_new(reap_buckets_per_pass(t->options.virtual_hash_size)); - - /* - * Get local ifconfig address - */ - CLEAR(m->local); - ASSERT(t->c1.tuntap); - mroute_extract_in_addr_t(&m->local, t->c1.tuntap->local); - - /* - * Per-client limits - */ - m->max_clients = t->options.max_clients; - - m->instances = calloc(m->max_clients, sizeof(struct multi_instance *)); - - /* - * Initialize multi-socket TCP I/O wait object - */ - if (tcp_mode) - { - m->mtcp = multi_tcp_init(t->options.max_clients, &m->max_clients); - } - m->tcp_queue_limit = t->options.tcp_queue_limit; - - /* - * Allow client <-> client communication, without going through - * tun/tap interface and network stack? - */ - m->enable_c2c = t->options.enable_c2c; - - /* initialize stale routes check timer */ - if (t->options.stale_routes_check_interval > 0) - { - msg(M_INFO, "Initializing stale route check timer to run every %i seconds and to removing routes with activity timeout older than %i seconds", - t->options.stale_routes_check_interval, t->options.stale_routes_ageing_time); - event_timeout_init(&m->stale_routes_check_et, t->options.stale_routes_check_interval, 0); - } - - m->deferred_shutdown_signal.signal_received = 0; } const char * -multi_instance_string(const struct multi_instance *mi, bool null, struct gc_arena *gc) +multi_instance_string (const struct multi_instance *mi, bool null, struct gc_arena *gc) { - if (mi) + if (mi) { - struct buffer out = alloc_buf_gc(MULTI_PREFIX_MAX_LENGTH, gc); - const char *cn = tls_common_name(mi->context.c2.tls_multi, true); + struct buffer out = alloc_buf_gc (MULTI_PREFIX_MAX_LENGTH, gc); + const char *cn = tls_common_name (mi->context.c2.tls_multi, true); - if (cn) - { - buf_printf(&out, "%s/", cn); - } - buf_printf(&out, "%s", mroute_addr_print(&mi->real, gc)); - return BSTR(&out); - } - else if (null) - { - return NULL; - } - else - { - return "UNDEF"; + if (cn) + buf_printf (&out, "%s/", cn); + buf_printf (&out, "%s", mroute_addr_print (&mi->real, gc)); + return BSTR (&out); } + else if (null) + return NULL; + else + return "UNDEF"; } static void generate_prefix(struct multi_instance *mi) { - struct gc_arena gc = gc_new(); - const char *prefix = multi_instance_string(mi, true, &gc); - if (prefix) - { - strncpynt(mi->msg_prefix, prefix, sizeof(mi->msg_prefix)); - } - else - { - mi->msg_prefix[0] = '\0'; - } - set_prefix(mi); - gc_free(&gc); + struct gc_arena gc = gc_new(); + const char *prefix = multi_instance_string (mi, true, &gc); + if (prefix) + strncpynt(mi->msg_prefix, prefix, sizeof(mi->msg_prefix)); + else + mi->msg_prefix[0] = '\0'; + set_prefix (mi); + gc_free(&gc); } void -ungenerate_prefix(struct multi_instance *mi) +ungenerate_prefix (struct multi_instance *mi) { - mi->msg_prefix[0] = '\0'; - set_prefix(mi); + mi->msg_prefix[0] = '\0'; + set_prefix (mi); } static const char * -mi_prefix(const struct multi_instance *mi) +mi_prefix (const struct multi_instance *mi) { - if (mi && mi->msg_prefix[0]) - { - return mi->msg_prefix; - } - else - { - return "UNDEF_I"; - } + if (mi && mi->msg_prefix[0]) + return mi->msg_prefix; + else + return "UNDEF_I"; } /* @@ -528,12 +451,12 @@ mi_prefix(const struct multi_instance *mi) * CIDR netlengths. */ static void -multi_del_iroutes(struct multi_context *m, - struct multi_instance *mi) +multi_del_iroutes (struct multi_context *m, + struct multi_instance *mi) { - const struct iroute *ir; - const struct iroute_ipv6 *ir6; - if (TUNNEL_TYPE(mi->context.c1.tuntap) == DEV_TYPE_TUN) + const struct iroute *ir; + const struct iroute_ipv6 *ir6; + if (TUNNEL_TYPE (mi->context.c1.tuntap) == DEV_TYPE_TUN) { for (ir = mi->context.options.iroutes; ir != NULL; ir = ir->next) { @@ -548,217 +471,189 @@ multi_del_iroutes(struct multi_context *m, } static void -setenv_stats(struct context *c) +setenv_stats (struct context *c) { - setenv_counter(c->c2.es, "bytes_received", c->c2.link_read_bytes); - setenv_counter(c->c2.es, "bytes_sent", c->c2.link_write_bytes); + setenv_counter (c->c2.es, "bytes_received", c->c2.link_read_bytes); + setenv_counter (c->c2.es, "bytes_sent", c->c2.link_write_bytes); } static void -multi_client_disconnect_setenv(struct multi_context *m, - struct multi_instance *mi) +multi_client_disconnect_setenv (struct multi_context *m, + struct multi_instance *mi) { - /* setenv client real IP address */ - setenv_trusted(mi->context.c2.es, get_link_socket_info(&mi->context)); + /* setenv client real IP address */ + setenv_trusted (mi->context.c2.es, get_link_socket_info (&mi->context)); - /* setenv stats */ - setenv_stats(&mi->context); + /* setenv stats */ + setenv_stats (&mi->context); - /* setenv connection duration */ - { - const unsigned int duration = (unsigned int) now - mi->created; - setenv_unsigned(mi->context.c2.es, "time_duration", duration); - } + /* setenv connection duration */ + { + const unsigned int duration = (unsigned int) now - mi->created; + setenv_unsigned (mi->context.c2.es, "time_duration", duration); + } } static void -multi_client_disconnect_script(struct multi_context *m, - struct multi_instance *mi) -{ - if ((mi->context.c2.context_auth == CAS_SUCCEEDED && mi->connection_established_flag) - || mi->context.c2.context_auth == CAS_PARTIAL) - { - multi_client_disconnect_setenv(m, mi); - - if (plugin_defined(mi->context.plugins, OPENVPN_PLUGIN_CLIENT_DISCONNECT)) - { - if (plugin_call(mi->context.plugins, OPENVPN_PLUGIN_CLIENT_DISCONNECT, NULL, NULL, mi->context.c2.es) != OPENVPN_PLUGIN_FUNC_SUCCESS) - { - msg(M_WARN, "WARNING: client-disconnect plugin call failed"); - } - } - - if (mi->context.options.client_disconnect_script) - { - struct argv argv = argv_new(); - setenv_str(mi->context.c2.es, "script_type", "client-disconnect"); - argv_parse_cmd(&argv, mi->context.options.client_disconnect_script); - openvpn_run_script(&argv, mi->context.c2.es, 0, "--client-disconnect"); - argv_reset(&argv); - } +multi_client_disconnect_script (struct multi_context *m, + struct multi_instance *mi) +{ + if ((mi->context.c2.context_auth == CAS_SUCCEEDED && mi->connection_established_flag) + || mi->context.c2.context_auth == CAS_PARTIAL) + { + multi_client_disconnect_setenv (m, mi); + + if (plugin_defined (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_DISCONNECT)) + { + if (plugin_call (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_DISCONNECT, NULL, NULL, mi->context.c2.es) != OPENVPN_PLUGIN_FUNC_SUCCESS) + msg (M_WARN, "WARNING: client-disconnect plugin call failed"); + } + + if (mi->context.options.client_disconnect_script) + { + struct argv argv = argv_new (); + setenv_str (mi->context.c2.es, "script_type", "client-disconnect"); + argv_printf (&argv, "%sc", mi->context.options.client_disconnect_script); + openvpn_run_script (&argv, mi->context.c2.es, 0, "--client-disconnect"); + argv_reset (&argv); + } #ifdef MANAGEMENT_DEF_AUTH - if (management) - { - management_notify_client_close(management, &mi->context.c2.mda_context, mi->context.c2.es); - } + if (management) + management_notify_client_close (management, &mi->context.c2.mda_context, mi->context.c2.es); #endif } } void -multi_close_instance(struct multi_context *m, - struct multi_instance *mi, - bool shutdown) -{ - perf_push(PERF_MULTI_CLOSE_INSTANCE); - - ASSERT(!mi->halt); - mi->halt = true; - - dmsg(D_MULTI_DEBUG, "MULTI: multi_close_instance called"); - - /* adjust current client connection count */ - m->n_clients += mi->n_clients_delta; - update_mstat_n_clients(m->n_clients); - mi->n_clients_delta = 0; - - /* prevent dangling pointers */ - if (m->pending == mi) - { - multi_set_pending(m, NULL); - } - if (m->earliest_wakeup == mi) - { - m->earliest_wakeup = NULL; - } - - if (!shutdown) - { - if (mi->did_real_hash) - { - ASSERT(hash_remove(m->hash, &mi->real)); - } - if (mi->did_iter) - { - ASSERT(hash_remove(m->iter, &mi->real)); - } +multi_close_instance (struct multi_context *m, + struct multi_instance *mi, + bool shutdown) +{ + perf_push (PERF_MULTI_CLOSE_INSTANCE); + + ASSERT (!mi->halt); + mi->halt = true; + + dmsg (D_MULTI_DEBUG, "MULTI: multi_close_instance called"); + + /* adjust current client connection count */ + m->n_clients += mi->n_clients_delta; + update_mstat_n_clients(m->n_clients); + mi->n_clients_delta = 0; + + /* prevent dangling pointers */ + if (m->pending == mi) + multi_set_pending (m, NULL); + if (m->earliest_wakeup == mi) + m->earliest_wakeup = NULL; + + if (!shutdown) + { + if (mi->did_real_hash) + { + ASSERT (hash_remove (m->hash, &mi->real)); + } + if (mi->did_iter) + { + ASSERT (hash_remove (m->iter, &mi->real)); + } #ifdef MANAGEMENT_DEF_AUTH - if (mi->did_cid_hash) - { - ASSERT(hash_remove(m->cid_hash, &mi->context.c2.mda_context.cid)); - } + if (mi->did_cid_hash) + { + ASSERT (hash_remove (m->cid_hash, &mi->context.c2.mda_context.cid)); + } #endif -#ifdef ENABLE_ASYNC_PUSH - if (mi->inotify_watch != -1) - { - hash_remove(m->inotify_watchers, (void *) (unsigned long)mi->inotify_watch); - mi->inotify_watch = -1; - } -#endif - - if (mi->context.c2.tls_multi->peer_id != MAX_PEER_ID) - { - m->instances[mi->context.c2.tls_multi->peer_id] = NULL; - } - - schedule_remove_entry(m->schedule, (struct schedule_entry *) mi); + m->instances[mi->context.c2.tls_multi->peer_id] = NULL; - ifconfig_pool_release(m->ifconfig_pool, mi->vaddr_handle, false); + schedule_remove_entry (m->schedule, (struct schedule_entry *) mi); - if (mi->did_iroutes) + ifconfig_pool_release (m->ifconfig_pool, mi->vaddr_handle, false); + + if (mi->did_iroutes) { - multi_del_iroutes(m, mi); - mi->did_iroutes = false; + multi_del_iroutes (m, mi); + mi->did_iroutes = false; } - if (m->mtcp) - { - multi_tcp_dereference_instance(m->mtcp, mi); - } + if (m->mtcp) + multi_tcp_dereference_instance (m->mtcp, mi); - mbuf_dereference_instance(m->mbuf, mi); + mbuf_dereference_instance (m->mbuf, mi); } #ifdef MANAGEMENT_DEF_AUTH - set_cc_config(mi, NULL); + set_cc_config (mi, NULL); #endif - multi_client_disconnect_script(m, mi); + multi_client_disconnect_script (m, mi); - if (mi->did_open_context) - { - close_context(&mi->context, SIGTERM, CC_GC_FREE); - } + if (mi->did_open_context) + close_context (&mi->context, SIGTERM, CC_GC_FREE); - multi_tcp_instance_specific_free(mi); + multi_tcp_instance_specific_free (mi); - ungenerate_prefix(mi); + ungenerate_prefix (mi); - /* - * Don't actually delete the instance memory allocation yet, - * because virtual routes may still point to it. Let the - * vhash reaper deal with it. - */ - multi_instance_dec_refcount(mi); + /* + * Don't actually delete the instance memory allocation yet, + * because virtual routes may still point to it. Let the + * vhash reaper deal with it. + */ + multi_instance_dec_refcount (mi); - perf_pop(); + perf_pop (); } /* * Called on shutdown or restart. */ void -multi_uninit(struct multi_context *m) +multi_uninit (struct multi_context *m) { - if (m->thread_mode & MC_WORK_THREAD) + if (m->thread_mode & MC_WORK_THREAD) { - multi_top_free(m); - m->thread_mode = MC_UNDEF; + multi_top_free (m); + m->thread_mode = MC_UNDEF; } - else if (m->thread_mode) + else if (m->thread_mode) { - if (m->hash) - { - struct hash_iterator hi; - struct hash_element *he; + if (m->hash) + { + struct hash_iterator hi; + struct hash_element *he; - hash_iterator_init(m->iter, &hi); - while ((he = hash_iterator_next(&hi))) - { - struct multi_instance *mi = (struct multi_instance *) he->value; - mi->did_iter = false; - multi_close_instance(m, mi, true); - } - hash_iterator_free(&hi); + hash_iterator_init (m->iter, &hi); + while ((he = hash_iterator_next (&hi))) + { + struct multi_instance *mi = (struct multi_instance *) he->value; + mi->did_iter = false; + multi_close_instance (m, mi, true); + } + hash_iterator_free (&hi); - multi_reap_all(m); + multi_reap_all (m); - hash_free(m->hash); - hash_free(m->vhash); - hash_free(m->iter); + hash_free (m->hash); + hash_free (m->vhash); + hash_free (m->iter); #ifdef MANAGEMENT_DEF_AUTH - hash_free(m->cid_hash); + hash_free (m->cid_hash); #endif - m->hash = NULL; + m->hash = NULL; - free(m->instances); + free(m->instances); -#ifdef ENABLE_ASYNC_PUSH - hash_free(m->inotify_watchers); - m->inotify_watchers = NULL; -#endif - - schedule_free(m->schedule); - mbuf_free(m->mbuf); - ifconfig_pool_free(m->ifconfig_pool); - frequency_limit_free(m->new_connection_limiter); - multi_reap_free(m->reaper); - mroute_helper_free(m->route_helper); - multi_tcp_free(m->mtcp); - m->thread_mode = MC_UNDEF; - } + schedule_free (m->schedule); + mbuf_free (m->mbuf); + ifconfig_pool_free (m->ifconfig_pool); + frequency_limit_free (m->new_connection_limiter); + multi_reap_free (m->reaper); + mroute_helper_free (m->route_helper); + multi_tcp_free (m->mtcp); + m->thread_mode = MC_UNDEF; + } } } @@ -766,60 +661,56 @@ multi_uninit(struct multi_context *m) * Create a client instance object for a newly connected client. */ struct multi_instance * -multi_create_instance(struct multi_context *m, const struct mroute_addr *real) +multi_create_instance (struct multi_context *m, const struct mroute_addr *real) { - struct gc_arena gc = gc_new(); - struct multi_instance *mi; + struct gc_arena gc = gc_new (); + struct multi_instance *mi; - perf_push(PERF_MULTI_CREATE_INSTANCE); + perf_push (PERF_MULTI_CREATE_INSTANCE); - msg(D_MULTI_MEDIUM, "MULTI: multi_create_instance called"); + msg (D_MULTI_MEDIUM, "MULTI: multi_create_instance called"); - ALLOC_OBJ_CLEAR(mi, struct multi_instance); + ALLOC_OBJ_CLEAR (mi, struct multi_instance); - mi->gc = gc_new(); - multi_instance_inc_refcount(mi); - mi->vaddr_handle = -1; - mi->created = now; - mroute_addr_init(&mi->real); + mi->gc = gc_new (); + multi_instance_inc_refcount (mi); + mi->vaddr_handle = -1; + mi->created = now; + mroute_addr_init (&mi->real); - if (real) + if (real) { - mi->real = *real; - generate_prefix(mi); + mi->real = *real; + generate_prefix (mi); } - mi->did_open_context = true; - inherit_context_child(&mi->context, &m->top); - if (IS_SIG(&mi->context)) - { - goto err; - } + mi->did_open_context = true; + inherit_context_child (&mi->context, &m->top); + if (IS_SIG (&mi->context)) + goto err; - mi->context.c2.context_auth = CAS_PENDING; + mi->context.c2.context_auth = CAS_PENDING; - if (hash_n_elements(m->hash) >= m->max_clients) + if (hash_n_elements (m->hash) >= m->max_clients) { - msg(D_MULTI_ERRORS, "MULTI: new incoming connection would exceed maximum number of clients (%d)", m->max_clients); - goto err; + msg (D_MULTI_ERRORS, "MULTI: new incoming connection would exceed maximum number of clients (%d)", m->max_clients); + goto err; } - if (!real) /* TCP mode? */ + if (!real) /* TCP mode? */ { - if (!multi_tcp_instance_specific_init(m, mi)) - { - goto err; - } - generate_prefix(mi); + if (!multi_tcp_instance_specific_init (m, mi)) + goto err; + generate_prefix (mi); } - if (!hash_add(m->iter, &mi->real, mi, false)) + if (!hash_add (m->iter, &mi->real, mi, false)) { - msg(D_MULTI_LOW, "MULTI: unable to add real address [%s] to iterator hash table", - mroute_addr_print(&mi->real, &gc)); - goto err; + msg (D_MULTI_LOW, "MULTI: unable to add real address [%s] to iterator hash table", + mroute_addr_print (&mi->real, &gc)); + goto err; } - mi->did_iter = true; + mi->did_iter = true; #ifdef MANAGEMENT_DEF_AUTH do @@ -829,28 +720,23 @@ multi_create_instance(struct multi_context *m, const struct mroute_addr *real) mi->did_cid_hash = true; #endif - mi->context.c2.push_reply_deferred = true; - -#ifdef ENABLE_ASYNC_PUSH - mi->context.c2.push_request_received = false; - mi->inotify_watch = -1; -#endif + mi->context.c2.push_reply_deferred = true; - if (!multi_process_post(m, mi, MPP_PRE_SELECT)) + if (!multi_process_post (m, mi, MPP_PRE_SELECT)) { - msg(D_MULTI_ERRORS, "MULTI: signal occurred during client instance initialization"); - goto err; + msg (D_MULTI_ERRORS, "MULTI: signal occurred during client instance initialization"); + goto err; } - perf_pop(); - gc_free(&gc); - return mi; + perf_pop (); + gc_free (&gc); + return mi; -err: - multi_close_instance(m, mi, false); - perf_pop(); - gc_free(&gc); - return NULL; + err: + multi_close_instance (m, mi, false); + perf_pop (); + gc_free (&gc); + return NULL; } /* @@ -859,203 +745,188 @@ multi_create_instance(struct multi_context *m, const struct mroute_addr *real) * If status file is NULL, write to syslog. */ void -multi_print_status(struct multi_context *m, struct status_output *so, const int version) -{ - if (m->hash) - { - struct gc_arena gc_top = gc_new(); - struct hash_iterator hi; - const struct hash_element *he; - - status_reset(so); - - if (version == 1) /* WAS: m->status_file_version */ - { - /* - * Status file version 1 - */ - status_printf(so, "OpenVPN CLIENT LIST"); - status_printf(so, "Updated,%s", time_string(0, 0, false, &gc_top)); - status_printf(so, "Common Name,Real Address,Bytes Received,Bytes Sent,Connected Since"); - hash_iterator_init(m->hash, &hi); - while ((he = hash_iterator_next(&hi))) - { - struct gc_arena gc = gc_new(); - const struct multi_instance *mi = (struct multi_instance *) he->value; - - if (!mi->halt) - { - status_printf(so, "%s,%s," counter_format "," counter_format ",%s", - tls_common_name(mi->context.c2.tls_multi, false), - mroute_addr_print(&mi->real, &gc), - mi->context.c2.link_read_bytes, - mi->context.c2.link_write_bytes, - time_string(mi->created, 0, false, &gc)); - } - gc_free(&gc); - } - hash_iterator_free(&hi); - - status_printf(so, "ROUTING TABLE"); - status_printf(so, "Virtual Address,Common Name,Real Address,Last Ref"); - hash_iterator_init(m->vhash, &hi); - while ((he = hash_iterator_next(&hi))) - { - struct gc_arena gc = gc_new(); - const struct multi_route *route = (struct multi_route *) he->value; - - if (multi_route_defined(m, route)) - { - const struct multi_instance *mi = route->instance; - const struct mroute_addr *ma = &route->addr; - char flags[2] = {0, 0}; - - if (route->flags & MULTI_ROUTE_CACHE) - { - flags[0] = 'C'; - } - status_printf(so, "%s%s,%s,%s,%s", - mroute_addr_print(ma, &gc), - flags, - tls_common_name(mi->context.c2.tls_multi, false), - mroute_addr_print(&mi->real, &gc), - time_string(route->last_reference, 0, false, &gc)); - } - gc_free(&gc); - } - hash_iterator_free(&hi); - - status_printf(so, "GLOBAL STATS"); - if (m->mbuf) - { - status_printf(so, "Max bcast/mcast queue length,%d", - mbuf_maximum_queued(m->mbuf)); - } - - status_printf(so, "END"); - } - else if (version == 2 || version == 3) - { - const char sep = (version == 3) ? '\t' : ','; - - /* - * Status file version 2 and 3 - */ - status_printf(so, "TITLE%c%s", sep, title_string); - status_printf(so, "TIME%c%s%c%u", sep, time_string(now, 0, false, &gc_top), sep, (unsigned int)now); - status_printf(so, "HEADER%cCLIENT_LIST%cCommon Name%cReal Address%cVirtual Address%cVirtual IPv6 Address%cBytes Received%cBytes Sent%cConnected Since%cConnected Since (time_t)%cUsername%cClient ID%cPeer ID", - sep, sep, sep, sep, sep, sep, sep, sep, sep, sep, sep, sep); - hash_iterator_init(m->hash, &hi); - while ((he = hash_iterator_next(&hi))) - { - struct gc_arena gc = gc_new(); - const struct multi_instance *mi = (struct multi_instance *) he->value; - - if (!mi->halt) - { - status_printf(so, "CLIENT_LIST%c%s%c%s%c%s%c%s%c" counter_format "%c" counter_format "%c%s%c%u%c%s%c" +multi_print_status (struct multi_context *m, struct status_output *so, const int version) +{ + if (m->hash) + { + struct gc_arena gc_top = gc_new (); + struct hash_iterator hi; + const struct hash_element *he; + + status_reset (so); + + if (version == 1) /* WAS: m->status_file_version */ + { + /* + * Status file version 1 + */ + status_printf (so, "OpenVPN CLIENT LIST"); + status_printf (so, "Updated,%s", time_string (0, 0, false, &gc_top)); + status_printf (so, "Common Name,Real Address,Bytes Received,Bytes Sent,Connected Since"); + hash_iterator_init (m->hash, &hi); + while ((he = hash_iterator_next (&hi))) + { + struct gc_arena gc = gc_new (); + const struct multi_instance *mi = (struct multi_instance *) he->value; + + if (!mi->halt) + { + status_printf (so, "%s,%s," counter_format "," counter_format ",%s", + tls_common_name (mi->context.c2.tls_multi, false), + mroute_addr_print (&mi->real, &gc), + mi->context.c2.link_read_bytes, + mi->context.c2.link_write_bytes, + time_string (mi->created, 0, false, &gc)); + } + gc_free (&gc); + } + hash_iterator_free (&hi); + + status_printf (so, "ROUTING TABLE"); + status_printf (so, "Virtual Address,Common Name,Real Address,Last Ref"); + hash_iterator_init (m->vhash, &hi); + while ((he = hash_iterator_next (&hi))) + { + struct gc_arena gc = gc_new (); + const struct multi_route *route = (struct multi_route *) he->value; + + if (multi_route_defined (m, route)) + { + const struct multi_instance *mi = route->instance; + const struct mroute_addr *ma = &route->addr; + char flags[2] = {0, 0}; + + if (route->flags & MULTI_ROUTE_CACHE) + flags[0] = 'C'; + status_printf (so, "%s%s,%s,%s,%s", + mroute_addr_print (ma, &gc), + flags, + tls_common_name (mi->context.c2.tls_multi, false), + mroute_addr_print (&mi->real, &gc), + time_string (route->last_reference, 0, false, &gc)); + } + gc_free (&gc); + } + hash_iterator_free (&hi); + + status_printf (so, "GLOBAL STATS"); + if (m->mbuf) + status_printf (so, "Max bcast/mcast queue length,%d", + mbuf_maximum_queued (m->mbuf)); + + status_printf (so, "END"); + } + else if (version == 2 || version == 3) + { + const char sep = (version == 3) ? '\t' : ','; + + /* + * Status file version 2 and 3 + */ + status_printf (so, "TITLE%c%s", sep, title_string); + status_printf (so, "TIME%c%s%c%u", sep, time_string (now, 0, false, &gc_top), sep, (unsigned int)now); + status_printf (so, "HEADER%cCLIENT_LIST%cCommon Name%cReal Address%cVirtual Address%cVirtual IPv6 Address%cBytes Received%cBytes Sent%cConnected Since%cConnected Since (time_t)%cUsername%cClient ID%cPeer ID", + sep, sep, sep, sep, sep, sep, sep, sep, sep, sep, sep, sep); + hash_iterator_init (m->hash, &hi); + while ((he = hash_iterator_next (&hi))) + { + struct gc_arena gc = gc_new (); + const struct multi_instance *mi = (struct multi_instance *) he->value; + + if (!mi->halt) + { + status_printf (so, "CLIENT_LIST%c%s%c%s%c%s%c%s%c" counter_format "%c" counter_format "%c%s%c%u%c%s%c" #ifdef MANAGEMENT_DEF_AUTH - "%lu" + "%lu" #else - "" + "" #endif - "%c%" PRIu32, - sep, tls_common_name(mi->context.c2.tls_multi, false), - sep, mroute_addr_print(&mi->real, &gc), - sep, print_in_addr_t(mi->reporting_addr, IA_EMPTY_IF_UNDEF, &gc), - sep, print_in6_addr(mi->reporting_addr_ipv6, IA_EMPTY_IF_UNDEF, &gc), - sep, mi->context.c2.link_read_bytes, - sep, mi->context.c2.link_write_bytes, - sep, time_string(mi->created, 0, false, &gc), - sep, (unsigned int)mi->created, - sep, tls_username(mi->context.c2.tls_multi, false), + "%c%"PRIu32, + sep, tls_common_name (mi->context.c2.tls_multi, false), + sep, mroute_addr_print (&mi->real, &gc), + sep, print_in_addr_t (mi->reporting_addr, IA_EMPTY_IF_UNDEF, &gc), + sep, print_in6_addr (mi->reporting_addr_ipv6, IA_EMPTY_IF_UNDEF, &gc), + sep, mi->context.c2.link_read_bytes, + sep, mi->context.c2.link_write_bytes, + sep, time_string (mi->created, 0, false, &gc), + sep, (unsigned int)mi->created, + sep, tls_username (mi->context.c2.tls_multi, false), #ifdef MANAGEMENT_DEF_AUTH - sep, mi->context.c2.mda_context.cid, + sep, mi->context.c2.mda_context.cid, #else - sep, + sep, #endif - sep, mi->context.c2.tls_multi ? mi->context.c2.tls_multi->peer_id : UINT32_MAX); - } - gc_free(&gc); - } - hash_iterator_free(&hi); - - status_printf(so, "HEADER%cROUTING_TABLE%cVirtual Address%cCommon Name%cReal Address%cLast Ref%cLast Ref (time_t)", - sep, sep, sep, sep, sep, sep); - hash_iterator_init(m->vhash, &hi); - while ((he = hash_iterator_next(&hi))) - { - struct gc_arena gc = gc_new(); - const struct multi_route *route = (struct multi_route *) he->value; - - if (multi_route_defined(m, route)) - { - const struct multi_instance *mi = route->instance; - const struct mroute_addr *ma = &route->addr; - char flags[2] = {0, 0}; - - if (route->flags & MULTI_ROUTE_CACHE) - { - flags[0] = 'C'; - } - status_printf(so, "ROUTING_TABLE%c%s%s%c%s%c%s%c%s%c%u", - sep, mroute_addr_print(ma, &gc), flags, - sep, tls_common_name(mi->context.c2.tls_multi, false), - sep, mroute_addr_print(&mi->real, &gc), - sep, time_string(route->last_reference, 0, false, &gc), - sep, (unsigned int)route->last_reference); - } - gc_free(&gc); - } - hash_iterator_free(&hi); - - if (m->mbuf) - { - status_printf(so, "GLOBAL_STATS%cMax bcast/mcast queue length%c%d", - sep, sep, mbuf_maximum_queued(m->mbuf)); - } - - status_printf(so, "END"); - } - else - { - status_printf(so, "ERROR: bad status format version number"); - } + sep, mi->context.c2.tls_multi ? mi->context.c2.tls_multi->peer_id : UINT32_MAX); + } + gc_free (&gc); + } + hash_iterator_free (&hi); + + status_printf (so, "HEADER%cROUTING_TABLE%cVirtual Address%cCommon Name%cReal Address%cLast Ref%cLast Ref (time_t)", + sep, sep, sep, sep, sep, sep); + hash_iterator_init (m->vhash, &hi); + while ((he = hash_iterator_next (&hi))) + { + struct gc_arena gc = gc_new (); + const struct multi_route *route = (struct multi_route *) he->value; + + if (multi_route_defined (m, route)) + { + const struct multi_instance *mi = route->instance; + const struct mroute_addr *ma = &route->addr; + char flags[2] = {0, 0}; + + if (route->flags & MULTI_ROUTE_CACHE) + flags[0] = 'C'; + status_printf (so, "ROUTING_TABLE%c%s%s%c%s%c%s%c%s%c%u", + sep, mroute_addr_print (ma, &gc), flags, + sep, tls_common_name (mi->context.c2.tls_multi, false), + sep, mroute_addr_print (&mi->real, &gc), + sep, time_string (route->last_reference, 0, false, &gc), + sep, (unsigned int)route->last_reference); + } + gc_free (&gc); + } + hash_iterator_free (&hi); + + if (m->mbuf) + status_printf (so, "GLOBAL_STATS%cMax bcast/mcast queue length%c%d", + sep, sep, mbuf_maximum_queued (m->mbuf)); + + status_printf (so, "END"); + } + else + { + status_printf (so, "ERROR: bad status format version number"); + } #ifdef PACKET_TRUNCATION_CHECK - { - status_printf(so, "HEADER,ERRORS,Common Name,TUN Read Trunc,TUN Write Trunc,Pre-encrypt Trunc,Post-decrypt Trunc"); - hash_iterator_init(m->hash, &hi); - while ((he = hash_iterator_next(&hi))) - { - struct gc_arena gc = gc_new(); - const struct multi_instance *mi = (struct multi_instance *) he->value; - - if (!mi->halt) - { - status_printf(so, "ERRORS,%s," counter_format "," counter_format "," counter_format "," counter_format, - tls_common_name(mi->context.c2.tls_multi, false), - m->top.c2.n_trunc_tun_read, - mi->context.c2.n_trunc_tun_write, - mi->context.c2.n_trunc_pre_encrypt, - mi->context.c2.n_trunc_post_decrypt); - } - gc_free(&gc); - } - hash_iterator_free(&hi); - } -#endif /* ifdef PACKET_TRUNCATION_CHECK */ + { + status_printf (so, "HEADER,ERRORS,Common Name,TUN Read Trunc,TUN Write Trunc,Pre-encrypt Trunc,Post-decrypt Trunc"); + hash_iterator_init (m->hash, &hi); + while ((he = hash_iterator_next (&hi))) + { + struct gc_arena gc = gc_new (); + const struct multi_instance *mi = (struct multi_instance *) he->value; + + if (!mi->halt) + { + status_printf (so, "ERRORS,%s," counter_format "," counter_format "," counter_format "," counter_format, + tls_common_name (mi->context.c2.tls_multi, false), + m->top.c2.n_trunc_tun_read, + mi->context.c2.n_trunc_tun_write, + mi->context.c2.n_trunc_pre_encrypt, + mi->context.c2.n_trunc_post_decrypt); + } + gc_free (&gc); + } + hash_iterator_free (&hi); + } +#endif - status_flush(so); - gc_free(&gc_top); + status_flush (so); + gc_free (&gc_top); } - -#ifdef ENABLE_ASYNC_PUSH - if (m->inotify_watchers) - { - msg(D_MULTI_DEBUG, "inotify watchers count: %d\n", hash_n_elements(m->inotify_watchers)); - } -#endif } /* @@ -1067,243 +938,229 @@ multi_print_status(struct multi_context *m, struct status_output *so, const int * or NULL if none. */ static struct multi_instance * -multi_learn_addr(struct multi_context *m, - struct multi_instance *mi, - const struct mroute_addr *addr, - const unsigned int flags) -{ - struct hash_element *he; - const uint32_t hv = hash_value(m->vhash, addr); - struct hash_bucket *bucket = hash_bucket(m->vhash, hv); - struct multi_route *oldroute = NULL; - struct multi_instance *owner = NULL; - - /* if route currently exists, get the instance which owns it */ - he = hash_lookup_fast(m->vhash, bucket, addr, hv); - if (he) - { - oldroute = (struct multi_route *) he->value; - } - if (oldroute && multi_route_defined(m, oldroute)) - { - owner = oldroute->instance; - } - - /* do we need to add address to hash table? */ - if ((!owner || owner != mi) - && mroute_learnable_address(addr) - && !mroute_addr_equal(addr, &m->local)) - { - struct gc_arena gc = gc_new(); - struct multi_route *newroute; - bool learn_succeeded = false; - - ALLOC_OBJ(newroute, struct multi_route); - newroute->addr = *addr; - newroute->instance = mi; - newroute->flags = flags; - newroute->last_reference = now; - newroute->cache_generation = 0; - - /* The cache is invalidated when cache_generation is incremented */ - if (flags & MULTI_ROUTE_CACHE) - { - newroute->cache_generation = m->route_helper->cache_generation; - } - - if (oldroute) /* route already exists? */ - { - if (route_quota_test(m, mi) && learn_address_script(m, mi, "update", &newroute->addr)) - { - learn_succeeded = true; - owner = mi; - multi_instance_inc_refcount(mi); - route_quota_inc(mi); - - /* delete old route */ - multi_route_del(oldroute); - - /* modify hash table entry, replacing old route */ - he->key = &newroute->addr; - he->value = newroute; - } - } - else - { - if (route_quota_test(m, mi) && learn_address_script(m, mi, "add", &newroute->addr)) - { - learn_succeeded = true; - owner = mi; - multi_instance_inc_refcount(mi); - route_quota_inc(mi); - - /* add new route */ - hash_add_fast(m->vhash, bucket, &newroute->addr, hv, newroute); - } - } - - msg(D_MULTI_LOW, "MULTI: Learn%s: %s -> %s", - learn_succeeded ? "" : " FAILED", - mroute_addr_print(&newroute->addr, &gc), - multi_instance_string(mi, false, &gc)); - - if (!learn_succeeded) - { - free(newroute); - } - - gc_free(&gc); - } - - return owner; +multi_learn_addr (struct multi_context *m, + struct multi_instance *mi, + const struct mroute_addr *addr, + const unsigned int flags) +{ + struct hash_element *he; + const uint32_t hv = hash_value (m->vhash, addr); + struct hash_bucket *bucket = hash_bucket (m->vhash, hv); + struct multi_route *oldroute = NULL; + struct multi_instance *owner = NULL; + + /* if route currently exists, get the instance which owns it */ + he = hash_lookup_fast (m->vhash, bucket, addr, hv); + if (he) + oldroute = (struct multi_route *) he->value; + if (oldroute && multi_route_defined (m, oldroute)) + owner = oldroute->instance; + + /* do we need to add address to hash table? */ + if ((!owner || owner != mi) + && mroute_learnable_address (addr) + && !mroute_addr_equal (addr, &m->local)) + { + struct gc_arena gc = gc_new (); + struct multi_route *newroute; + bool learn_succeeded = false; + + ALLOC_OBJ (newroute, struct multi_route); + newroute->addr = *addr; + newroute->instance = mi; + newroute->flags = flags; + newroute->last_reference = now; + newroute->cache_generation = 0; + + /* The cache is invalidated when cache_generation is incremented */ + if (flags & MULTI_ROUTE_CACHE) + newroute->cache_generation = m->route_helper->cache_generation; + + if (oldroute) /* route already exists? */ + { + if (route_quota_test (m, mi) && learn_address_script (m, mi, "update", &newroute->addr)) + { + learn_succeeded = true; + owner = mi; + multi_instance_inc_refcount (mi); + route_quota_inc (mi); + + /* delete old route */ + multi_route_del (oldroute); + + /* modify hash table entry, replacing old route */ + he->key = &newroute->addr; + he->value = newroute; + } + } + else + { + if (route_quota_test (m, mi) && learn_address_script (m, mi, "add", &newroute->addr)) + { + learn_succeeded = true; + owner = mi; + multi_instance_inc_refcount (mi); + route_quota_inc (mi); + + /* add new route */ + hash_add_fast (m->vhash, bucket, &newroute->addr, hv, newroute); + } + } + + msg (D_MULTI_LOW, "MULTI: Learn%s: %s -> %s", + learn_succeeded ? "" : " FAILED", + mroute_addr_print (&newroute->addr, &gc), + multi_instance_string (mi, false, &gc)); + + if (!learn_succeeded) + free (newroute); + + gc_free (&gc); + } + + return owner; } /* * Get client instance based on virtual address. */ static struct multi_instance * -multi_get_instance_by_virtual_addr(struct multi_context *m, - const struct mroute_addr *addr, - bool cidr_routing) +multi_get_instance_by_virtual_addr (struct multi_context *m, + const struct mroute_addr *addr, + bool cidr_routing) { - struct multi_route *route; - struct multi_instance *ret = NULL; + struct multi_route *route; + struct multi_instance *ret = NULL; - /* check for local address */ - if (mroute_addr_equal(addr, &m->local)) - { - return NULL; - } + /* check for local address */ + if (mroute_addr_equal (addr, &m->local)) + return NULL; - route = (struct multi_route *) hash_lookup(m->vhash, addr); + route = (struct multi_route *) hash_lookup (m->vhash, addr); - /* does host route (possible cached) exist? */ - if (route && multi_route_defined(m, route)) + /* does host route (possible cached) exist? */ + if (route && multi_route_defined (m, route)) { - struct multi_instance *mi = route->instance; - route->last_reference = now; - ret = mi; + struct multi_instance *mi = route->instance; + route->last_reference = now; + ret = mi; } - else if (cidr_routing) /* do we need to regenerate a host route cache entry? */ + else if (cidr_routing) /* do we need to regenerate a host route cache entry? */ { - struct mroute_helper *rh = m->route_helper; - struct mroute_addr tryaddr; - int i; + struct mroute_helper *rh = m->route_helper; + struct mroute_addr tryaddr; + int i; - /* cycle through each CIDR length */ - for (i = 0; i < rh->n_net_len; ++i) - { - tryaddr = *addr; - tryaddr.type |= MR_WITH_NETBITS; - tryaddr.netbits = rh->net_len[i]; - mroute_addr_mask_host_bits(&tryaddr); + /* cycle through each CIDR length */ + for (i = 0; i < rh->n_net_len; ++i) + { + tryaddr = *addr; + tryaddr.type |= MR_WITH_NETBITS; + tryaddr.netbits = rh->net_len[i]; + mroute_addr_mask_host_bits (&tryaddr); - /* look up a possible route with netbits netmask */ - route = (struct multi_route *) hash_lookup(m->vhash, &tryaddr); + /* look up a possible route with netbits netmask */ + route = (struct multi_route *) hash_lookup (m->vhash, &tryaddr); - if (route && multi_route_defined(m, route)) - { - /* found an applicable route, cache host route */ - struct multi_instance *mi = route->instance; - multi_learn_addr(m, mi, addr, MULTI_ROUTE_CACHE|MULTI_ROUTE_AGEABLE); - ret = mi; - break; - } - } + if (route && multi_route_defined (m, route)) + { + /* found an applicable route, cache host route */ + struct multi_instance *mi = route->instance; + multi_learn_addr (m, mi, addr, MULTI_ROUTE_CACHE|MULTI_ROUTE_AGEABLE); + ret = mi; + break; + } + } } - + #ifdef ENABLE_DEBUG - if (check_debug_level(D_MULTI_DEBUG)) - { - struct gc_arena gc = gc_new(); - const char *addr_text = mroute_addr_print(addr, &gc); - if (ret) - { - dmsg(D_MULTI_DEBUG, "GET INST BY VIRT: %s -> %s via %s", - addr_text, - multi_instance_string(ret, false, &gc), - mroute_addr_print(&route->addr, &gc)); - } - else - { - dmsg(D_MULTI_DEBUG, "GET INST BY VIRT: %s [failed]", - addr_text); - } - gc_free(&gc); + if (check_debug_level (D_MULTI_DEBUG)) + { + struct gc_arena gc = gc_new (); + const char *addr_text = mroute_addr_print (addr, &gc); + if (ret) + { + dmsg (D_MULTI_DEBUG, "GET INST BY VIRT: %s -> %s via %s", + addr_text, + multi_instance_string (ret, false, &gc), + mroute_addr_print (&route->addr, &gc)); + } + else + { + dmsg (D_MULTI_DEBUG, "GET INST BY VIRT: %s [failed]", + addr_text); + } + gc_free (&gc); } #endif - ASSERT(!(ret && ret->halt)); - return ret; + ASSERT (!(ret && ret->halt)); + return ret; } /* * Helper function to multi_learn_addr(). */ static struct multi_instance * -multi_learn_in_addr_t(struct multi_context *m, - struct multi_instance *mi, - in_addr_t a, - int netbits, /* -1 if host route, otherwise # of network bits in address */ - bool primary) +multi_learn_in_addr_t (struct multi_context *m, + struct multi_instance *mi, + in_addr_t a, + int netbits, /* -1 if host route, otherwise # of network bits in address */ + bool primary) { - struct openvpn_sockaddr remote_si; - struct mroute_addr addr; + struct openvpn_sockaddr remote_si; + struct mroute_addr addr; - CLEAR(remote_si); - remote_si.addr.in4.sin_family = AF_INET; - remote_si.addr.in4.sin_addr.s_addr = htonl(a); - ASSERT(mroute_extract_openvpn_sockaddr(&addr, &remote_si, false)); + CLEAR (remote_si); + remote_si.addr.in4.sin_family = AF_INET; + remote_si.addr.in4.sin_addr.s_addr = htonl (a); + ASSERT (mroute_extract_openvpn_sockaddr (&addr, &remote_si, false)); - if (netbits >= 0) + if (netbits >= 0) { - addr.type |= MR_WITH_NETBITS; - addr.netbits = (uint8_t) netbits; + addr.type |= MR_WITH_NETBITS; + addr.netbits = (uint8_t) netbits; } - { - struct multi_instance *owner = multi_learn_addr(m, mi, &addr, 0); + { + struct multi_instance *owner = multi_learn_addr (m, mi, &addr, 0); #ifdef MANAGEMENT_DEF_AUTH - if (management && owner) - { - management_learn_addr(management, &mi->context.c2.mda_context, &addr, primary); - } + if (management && owner) + management_learn_addr (management, &mi->context.c2.mda_context, &addr, primary); #endif - return owner; - } + return owner; + } } static struct multi_instance * -multi_learn_in6_addr(struct multi_context *m, - struct multi_instance *mi, - struct in6_addr a6, - int netbits, /* -1 if host route, otherwise # of network bits in address */ - bool primary) +multi_learn_in6_addr (struct multi_context *m, + struct multi_instance *mi, + struct in6_addr a6, + int netbits, /* -1 if host route, otherwise # of network bits in address */ + bool primary) { - struct mroute_addr addr; + struct mroute_addr addr; - addr.len = 16; - addr.type = MR_ADDR_IPV6; - addr.netbits = 0; - addr.v6.addr = a6; + addr.len = 16; + addr.type = MR_ADDR_IPV6; + addr.netbits = 0; + memcpy( &addr.addr, &a6, sizeof(a6) ); - if (netbits >= 0) + if (netbits >= 0) { - addr.type |= MR_WITH_NETBITS; - addr.netbits = (uint8_t) netbits; - mroute_addr_mask_host_bits( &addr ); + addr.type |= MR_WITH_NETBITS; + addr.netbits = (uint8_t) netbits; + mroute_addr_mask_host_bits( &addr ); } - { - struct multi_instance *owner = multi_learn_addr(m, mi, &addr, 0); + { + struct multi_instance *owner = multi_learn_addr (m, mi, &addr, 0); #ifdef MANAGEMENT_DEF_AUTH - if (management && owner) - { - management_learn_addr(management, &mi->context.c2.mda_context, &addr, primary); - } + if (management && owner) + management_learn_addr (management, &mi->context.c2.mda_context, &addr, primary); #endif - return owner; - } + return owner; + } } /* @@ -1311,48 +1168,44 @@ multi_learn_in6_addr(struct multi_context *m, * to internal routing table. */ static void -multi_add_iroutes(struct multi_context *m, - struct multi_instance *mi) -{ - struct gc_arena gc = gc_new(); - const struct iroute *ir; - const struct iroute_ipv6 *ir6; - if (TUNNEL_TYPE(mi->context.c1.tuntap) == DEV_TYPE_TUN) - { - mi->did_iroutes = true; - for (ir = mi->context.options.iroutes; ir != NULL; ir = ir->next) - { - if (ir->netbits >= 0) - { - msg(D_MULTI_LOW, "MULTI: internal route %s/%d -> %s", - print_in_addr_t(ir->network, 0, &gc), - ir->netbits, - multi_instance_string(mi, false, &gc)); - } - else - { - msg(D_MULTI_LOW, "MULTI: internal route %s -> %s", - print_in_addr_t(ir->network, 0, &gc), - multi_instance_string(mi, false, &gc)); - } - - mroute_helper_add_iroute46(m->route_helper, ir->netbits); - - multi_learn_in_addr_t(m, mi, ir->network, ir->netbits, false); - } - for (ir6 = mi->context.options.iroutes_ipv6; ir6 != NULL; ir6 = ir6->next) - { - msg(D_MULTI_LOW, "MULTI: internal route %s/%d -> %s", - print_in6_addr(ir6->network, 0, &gc), - ir6->netbits, - multi_instance_string(mi, false, &gc)); - - mroute_helper_add_iroute46(m->route_helper, ir6->netbits); - - multi_learn_in6_addr(m, mi, ir6->network, ir6->netbits, false); - } - } - gc_free(&gc); +multi_add_iroutes (struct multi_context *m, + struct multi_instance *mi) +{ + struct gc_arena gc = gc_new (); + const struct iroute *ir; + const struct iroute_ipv6 *ir6; + if (TUNNEL_TYPE (mi->context.c1.tuntap) == DEV_TYPE_TUN) + { + mi->did_iroutes = true; + for (ir = mi->context.options.iroutes; ir != NULL; ir = ir->next) + { + if (ir->netbits >= 0) + msg (D_MULTI_LOW, "MULTI: internal route %s/%d -> %s", + print_in_addr_t (ir->network, 0, &gc), + ir->netbits, + multi_instance_string (mi, false, &gc)); + else + msg (D_MULTI_LOW, "MULTI: internal route %s -> %s", + print_in_addr_t (ir->network, 0, &gc), + multi_instance_string (mi, false, &gc)); + + mroute_helper_add_iroute46 (m->route_helper, ir->netbits); + + multi_learn_in_addr_t (m, mi, ir->network, ir->netbits, false); + } + for ( ir6 = mi->context.options.iroutes_ipv6; ir6 != NULL; ir6 = ir6->next ) + { + msg (D_MULTI_LOW, "MULTI: internal route %s/%d -> %s", + print_in6_addr (ir6->network, 0, &gc), + ir6->netbits, + multi_instance_string (mi, false, &gc)); + + mroute_helper_add_iroute46 (m->route_helper, ir6->netbits); + + multi_learn_in6_addr (m, mi, ir6->network, ir6->netbits, false); + } + } + gc_free (&gc); } /* @@ -1360,67 +1213,65 @@ multi_add_iroutes(struct multi_context *m, * same common name. */ static void -multi_delete_dup(struct multi_context *m, struct multi_instance *new_mi) -{ - if (new_mi) - { - const char *new_cn = tls_common_name(new_mi->context.c2.tls_multi, true); - if (new_cn) - { - struct hash_iterator hi; - struct hash_element *he; - int count = 0; - - hash_iterator_init(m->iter, &hi); - while ((he = hash_iterator_next(&hi))) - { - struct multi_instance *mi = (struct multi_instance *) he->value; - if (mi != new_mi && !mi->halt) - { - const char *cn = tls_common_name(mi->context.c2.tls_multi, true); - if (cn && !strcmp(cn, new_cn)) - { - mi->did_iter = false; - multi_close_instance(m, mi, false); - hash_iterator_delete_element(&hi); - ++count; - } - } - } - hash_iterator_free(&hi); - - if (count) - { - msg(D_MULTI_LOW, "MULTI: new connection by client '%s' will cause previous active sessions by this client to be dropped. Remember to use the --duplicate-cn option if you want multiple clients using the same certificate or username to concurrently connect.", new_cn); - } - } +multi_delete_dup (struct multi_context *m, struct multi_instance *new_mi) +{ + if (new_mi) + { + const char *new_cn = tls_common_name (new_mi->context.c2.tls_multi, true); + if (new_cn) + { + struct hash_iterator hi; + struct hash_element *he; + int count = 0; + + hash_iterator_init (m->iter, &hi); + while ((he = hash_iterator_next (&hi))) + { + struct multi_instance *mi = (struct multi_instance *) he->value; + if (mi != new_mi && !mi->halt) + { + const char *cn = tls_common_name (mi->context.c2.tls_multi, true); + if (cn && !strcmp (cn, new_cn)) + { + mi->did_iter = false; + multi_close_instance (m, mi, false); + hash_iterator_delete_element (&hi); + ++count; + } + } + } + hash_iterator_free (&hi); + + if (count) + msg (D_MULTI_LOW, "MULTI: new connection by client '%s' will cause previous active sessions by this client to be dropped. Remember to use the --duplicate-cn option if you want multiple clients using the same certificate or username to concurrently connect.", new_cn); + } } } static void -check_stale_routes(struct multi_context *m) +check_stale_routes (struct multi_context *m) { - struct gc_arena gc = gc_new(); - struct hash_iterator hi; - struct hash_element *he; + struct gc_arena gc = gc_new (); + struct hash_iterator hi; + struct hash_element *he; - dmsg(D_MULTI_DEBUG, "MULTI: Checking stale routes"); - hash_iterator_init_range(m->vhash, &hi, 0, hash_n_buckets(m->vhash)); - while ((he = hash_iterator_next(&hi)) != NULL) + dmsg (D_MULTI_DEBUG, "MULTI: Checking stale routes"); + hash_iterator_init_range (m->vhash, &hi, 0, hash_n_buckets (m->vhash)); + while ((he = hash_iterator_next (&hi)) != NULL) { - struct multi_route *r = (struct multi_route *) he->value; - if (multi_route_defined(m, r) && difftime(now, r->last_reference) >= m->top.options.stale_routes_ageing_time) + struct multi_route *r = (struct multi_route *) he->value; + if (multi_route_defined (m, r) && difftime(now, r->last_reference) >= m->top.options.stale_routes_ageing_time) { - dmsg(D_MULTI_DEBUG, "MULTI: Deleting stale route for address '%s'", - mroute_addr_print(&r->addr, &gc)); - learn_address_script(m, NULL, "delete", &r->addr); - multi_route_del(r); - hash_iterator_delete_element(&hi); + dmsg (D_MULTI_DEBUG, "MULTI: Deleting stale route for address '%s'", + mroute_addr_print (&r->addr, &gc)); + learn_address_script (m, NULL, "delete", &r->addr); + multi_route_del (r); + hash_iterator_delete_element (&hi); } } - hash_iterator_free(&hi); - gc_free(&gc); + hash_iterator_free (&hi); + gc_free (&gc); } /* @@ -1428,239 +1279,212 @@ check_stale_routes(struct multi_context *m) * complies with --ifconfig-push-constraint directive. */ static bool -ifconfig_push_constraint_satisfied(const struct context *c) +ifconfig_push_constraint_satisfied (const struct context *c) { - const struct options *o = &c->options; - if (o->push_ifconfig_constraint_defined && c->c2.push_ifconfig_defined) - { - return (o->push_ifconfig_constraint_netmask & c->c2.push_ifconfig_local) == o->push_ifconfig_constraint_network; - } - else - { - return true; - } + const struct options *o = &c->options; + if (o->push_ifconfig_constraint_defined && c->c2.push_ifconfig_defined) + return (o->push_ifconfig_constraint_netmask & c->c2.push_ifconfig_local) == o->push_ifconfig_constraint_network; + else + return true; } /* * Select a virtual address for a new client instance. * Use an --ifconfig-push directive, if given (static IP). - * Otherwise use an --ifconfig-pool address (dynamic IP). + * Otherwise use an --ifconfig-pool address (dynamic IP). */ static void -multi_select_virtual_addr(struct multi_context *m, struct multi_instance *mi) -{ - struct gc_arena gc = gc_new(); - - /* - * If ifconfig addresses were set by dynamic config file, - * release pool addresses, otherwise keep them. - */ - if (mi->context.options.push_ifconfig_defined) - { - /* ifconfig addresses were set statically, - * release dynamic allocation */ - if (mi->vaddr_handle >= 0) - { - ifconfig_pool_release(m->ifconfig_pool, mi->vaddr_handle, true); - mi->vaddr_handle = -1; - } - - mi->context.c2.push_ifconfig_defined = true; - mi->context.c2.push_ifconfig_local = mi->context.options.push_ifconfig_local; - mi->context.c2.push_ifconfig_remote_netmask = mi->context.options.push_ifconfig_remote_netmask; - mi->context.c2.push_ifconfig_local_alias = mi->context.options.push_ifconfig_local_alias; - - /* the current implementation does not allow "static IPv4, pool IPv6", - * (see below) so issue a warning if that happens - don't break the - * session, though, as we don't even know if this client WANTS IPv6 - */ - if (mi->context.options.ifconfig_ipv6_pool_defined - && !mi->context.options.push_ifconfig_ipv6_defined) - { - msg( M_INFO, "MULTI_sva: WARNING: if --ifconfig-push is used for IPv4, automatic IPv6 assignment from --ifconfig-ipv6-pool does not work. Use --ifconfig-ipv6-push for IPv6 then." ); - } - } - else if (m->ifconfig_pool && mi->vaddr_handle < 0) /* otherwise, choose a pool address */ - { - in_addr_t local = 0, remote = 0; - struct in6_addr remote_ipv6; - const char *cn = NULL; - - if (!mi->context.options.duplicate_cn) - { - cn = tls_common_name(mi->context.c2.tls_multi, true); - } - - CLEAR(remote_ipv6); - mi->vaddr_handle = ifconfig_pool_acquire(m->ifconfig_pool, &local, &remote, &remote_ipv6, cn); - if (mi->vaddr_handle >= 0) - { - const int tunnel_type = TUNNEL_TYPE(mi->context.c1.tuntap); - const int tunnel_topology = TUNNEL_TOPOLOGY(mi->context.c1.tuntap); - - msg( M_INFO, "MULTI_sva: pool returned IPv4=%s, IPv6=%s", - print_in_addr_t( remote, 0, &gc ), - (mi->context.options.ifconfig_ipv6_pool_defined - ? print_in6_addr( remote_ipv6, 0, &gc ) - : "(Not enabled)") ); - - /* set push_ifconfig_remote_netmask from pool ifconfig address(es) */ - mi->context.c2.push_ifconfig_local = remote; - if (tunnel_type == DEV_TYPE_TAP || (tunnel_type == DEV_TYPE_TUN && tunnel_topology == TOP_SUBNET)) - { - mi->context.c2.push_ifconfig_remote_netmask = mi->context.options.ifconfig_pool_netmask; - if (!mi->context.c2.push_ifconfig_remote_netmask) - { - mi->context.c2.push_ifconfig_remote_netmask = mi->context.c1.tuntap->remote_netmask; - } - } - else if (tunnel_type == DEV_TYPE_TUN) - { - if (tunnel_topology == TOP_P2P) - { - mi->context.c2.push_ifconfig_remote_netmask = mi->context.c1.tuntap->local; - } - else if (tunnel_topology == TOP_NET30) - { - mi->context.c2.push_ifconfig_remote_netmask = local; - } - } - - if (mi->context.c2.push_ifconfig_remote_netmask) - { - mi->context.c2.push_ifconfig_defined = true; - } - else - { - msg(D_MULTI_ERRORS, "MULTI: no --ifconfig-pool netmask parameter is available to push to %s", - multi_instance_string(mi, false, &gc)); - } - - if (mi->context.options.ifconfig_ipv6_pool_defined) - { - mi->context.c2.push_ifconfig_ipv6_local = remote_ipv6; - mi->context.c2.push_ifconfig_ipv6_remote = - mi->context.c1.tuntap->local_ipv6; - mi->context.c2.push_ifconfig_ipv6_netbits = - mi->context.options.ifconfig_ipv6_netbits; - mi->context.c2.push_ifconfig_ipv6_defined = true; - } - } - else - { - msg(D_MULTI_ERRORS, "MULTI: no free --ifconfig-pool addresses are available"); - } - } - - /* IPv6 push_ifconfig is a bit problematic - since IPv6 shares the - * pool handling with IPv4, the combination "static IPv4, dynamic IPv6" - * will fail (because no pool will be allocated in this case). - * OTOH, this doesn't make too much sense in reality - and the other - * way round ("dynamic IPv4, static IPv6") or "both static" makes sense - * -> and so it's implemented right now - */ - if (mi->context.options.push_ifconfig_ipv6_defined) - { - mi->context.c2.push_ifconfig_ipv6_local = - mi->context.options.push_ifconfig_ipv6_local; - mi->context.c2.push_ifconfig_ipv6_remote = - mi->context.options.push_ifconfig_ipv6_remote; - mi->context.c2.push_ifconfig_ipv6_netbits = - mi->context.options.push_ifconfig_ipv6_netbits; - mi->context.c2.push_ifconfig_ipv6_defined = true; - - msg( M_INFO, "MULTI_sva: push_ifconfig_ipv6 %s/%d", - print_in6_addr( mi->context.c2.push_ifconfig_ipv6_local, 0, &gc ), - mi->context.c2.push_ifconfig_ipv6_netbits ); - } +multi_select_virtual_addr (struct multi_context *m, struct multi_instance *mi) +{ + struct gc_arena gc = gc_new (); + + /* + * If ifconfig addresses were set by dynamic config file, + * release pool addresses, otherwise keep them. + */ + if (mi->context.options.push_ifconfig_defined) + { + /* ifconfig addresses were set statically, + release dynamic allocation */ + if (mi->vaddr_handle >= 0) + { + ifconfig_pool_release (m->ifconfig_pool, mi->vaddr_handle, true); + mi->vaddr_handle = -1; + } + + mi->context.c2.push_ifconfig_defined = true; + mi->context.c2.push_ifconfig_local = mi->context.options.push_ifconfig_local; + mi->context.c2.push_ifconfig_remote_netmask = mi->context.options.push_ifconfig_remote_netmask; +#ifdef ENABLE_CLIENT_NAT + mi->context.c2.push_ifconfig_local_alias = mi->context.options.push_ifconfig_local_alias; +#endif - gc_free(&gc); + /* the current implementation does not allow "static IPv4, pool IPv6", + * (see below) so issue a warning if that happens - don't break the + * session, though, as we don't even know if this client WANTS IPv6 + */ + if ( mi->context.c1.tuntap->ipv6 && + mi->context.options.ifconfig_ipv6_pool_defined && + ! mi->context.options.push_ifconfig_ipv6_defined ) + { + msg( M_INFO, "MULTI_sva: WARNING: if --ifconfig-push is used for IPv4, automatic IPv6 assignment from --ifconfig-ipv6-pool does not work. Use --ifconfig-ipv6-push for IPv6 then." ); + } + } + else if (m->ifconfig_pool && mi->vaddr_handle < 0) /* otherwise, choose a pool address */ + { + in_addr_t local=0, remote=0; + struct in6_addr remote_ipv6; + const char *cn = NULL; + + if (!mi->context.options.duplicate_cn) + cn = tls_common_name (mi->context.c2.tls_multi, true); + + CLEAR(remote_ipv6); + mi->vaddr_handle = ifconfig_pool_acquire (m->ifconfig_pool, &local, &remote, &remote_ipv6, cn); + if (mi->vaddr_handle >= 0) + { + const int tunnel_type = TUNNEL_TYPE (mi->context.c1.tuntap); + const int tunnel_topology = TUNNEL_TOPOLOGY (mi->context.c1.tuntap); + + msg( M_INFO, "MULTI_sva: pool returned IPv4=%s, IPv6=%s", + print_in_addr_t( remote, 0, &gc ), + (mi->context.options.ifconfig_ipv6_pool_defined + ? print_in6_addr( remote_ipv6, 0, &gc ) + : "(Not enabled)") ); + + /* set push_ifconfig_remote_netmask from pool ifconfig address(es) */ + mi->context.c2.push_ifconfig_local = remote; + if (tunnel_type == DEV_TYPE_TAP || (tunnel_type == DEV_TYPE_TUN && tunnel_topology == TOP_SUBNET)) + { + mi->context.c2.push_ifconfig_remote_netmask = mi->context.options.ifconfig_pool_netmask; + if (!mi->context.c2.push_ifconfig_remote_netmask) + mi->context.c2.push_ifconfig_remote_netmask = mi->context.c1.tuntap->remote_netmask; + } + else if (tunnel_type == DEV_TYPE_TUN) + { + if (tunnel_topology == TOP_P2P) + mi->context.c2.push_ifconfig_remote_netmask = mi->context.c1.tuntap->local; + else if (tunnel_topology == TOP_NET30) + mi->context.c2.push_ifconfig_remote_netmask = local; + } + + if (mi->context.c2.push_ifconfig_remote_netmask) + mi->context.c2.push_ifconfig_defined = true; + else + msg (D_MULTI_ERRORS, "MULTI: no --ifconfig-pool netmask parameter is available to push to %s", + multi_instance_string (mi, false, &gc)); + + if ( mi->context.options.ifconfig_ipv6_pool_defined ) + { + mi->context.c2.push_ifconfig_ipv6_local = remote_ipv6; + mi->context.c2.push_ifconfig_ipv6_remote = + mi->context.c1.tuntap->local_ipv6; + mi->context.c2.push_ifconfig_ipv6_netbits = + mi->context.options.ifconfig_ipv6_pool_netbits; + mi->context.c2.push_ifconfig_ipv6_defined = true; + } + } + else + { + msg (D_MULTI_ERRORS, "MULTI: no free --ifconfig-pool addresses are available"); + } + } + + /* IPv6 push_ifconfig is a bit problematic - since IPv6 shares the + * pool handling with IPv4, the combination "static IPv4, dynamic IPv6" + * will fail (because no pool will be allocated in this case). + * OTOH, this doesn't make too much sense in reality - and the other + * way round ("dynamic IPv4, static IPv6") or "both static" makes sense + * -> and so it's implemented right now + */ + if ( mi->context.c1.tuntap->ipv6 && + mi->context.options.push_ifconfig_ipv6_defined ) + { + mi->context.c2.push_ifconfig_ipv6_local = + mi->context.options.push_ifconfig_ipv6_local; + mi->context.c2.push_ifconfig_ipv6_remote = + mi->context.options.push_ifconfig_ipv6_remote; + mi->context.c2.push_ifconfig_ipv6_netbits = + mi->context.options.push_ifconfig_ipv6_netbits; + mi->context.c2.push_ifconfig_ipv6_defined = true; + + msg( M_INFO, "MULTI_sva: push_ifconfig_ipv6 %s/%d", + print_in6_addr( mi->context.c2.push_ifconfig_ipv6_local, 0, &gc ), + mi->context.c2.push_ifconfig_ipv6_netbits ); + } + + gc_free (&gc); } /* * Set virtual address environmental variables. */ static void -multi_set_virtual_addr_env(struct multi_context *m, struct multi_instance *mi) -{ - setenv_del(mi->context.c2.es, "ifconfig_pool_local_ip"); - setenv_del(mi->context.c2.es, "ifconfig_pool_remote_ip"); - setenv_del(mi->context.c2.es, "ifconfig_pool_netmask"); - - if (mi->context.c2.push_ifconfig_defined) - { - const int tunnel_type = TUNNEL_TYPE(mi->context.c1.tuntap); - const int tunnel_topology = TUNNEL_TOPOLOGY(mi->context.c1.tuntap); - - setenv_in_addr_t(mi->context.c2.es, - "ifconfig_pool_remote_ip", - mi->context.c2.push_ifconfig_local, - SA_SET_IF_NONZERO); - - if (tunnel_type == DEV_TYPE_TAP || (tunnel_type == DEV_TYPE_TUN && tunnel_topology == TOP_SUBNET)) - { - setenv_in_addr_t(mi->context.c2.es, - "ifconfig_pool_netmask", - mi->context.c2.push_ifconfig_remote_netmask, - SA_SET_IF_NONZERO); - } - else if (tunnel_type == DEV_TYPE_TUN) - { - setenv_in_addr_t(mi->context.c2.es, - "ifconfig_pool_local_ip", - mi->context.c2.push_ifconfig_remote_netmask, - SA_SET_IF_NONZERO); - } - } - - setenv_del(mi->context.c2.es, "ifconfig_pool_local_ip6"); - setenv_del(mi->context.c2.es, "ifconfig_pool_remote_ip6"); - setenv_del(mi->context.c2.es, "ifconfig_pool_ip6_netbits"); - - if (mi->context.c2.push_ifconfig_ipv6_defined) - { - setenv_in6_addr(mi->context.c2.es, - "ifconfig_pool_remote", - &mi->context.c2.push_ifconfig_ipv6_local, - SA_SET_IF_NONZERO); - setenv_in6_addr(mi->context.c2.es, - "ifconfig_pool_local", - &mi->context.c2.push_ifconfig_ipv6_remote, - SA_SET_IF_NONZERO); - setenv_int(mi->context.c2.es, - "ifconfig_pool_ip6_netbits", - mi->context.c2.push_ifconfig_ipv6_netbits); - } +multi_set_virtual_addr_env (struct multi_context *m, struct multi_instance *mi) +{ + setenv_del (mi->context.c2.es, "ifconfig_pool_local_ip"); + setenv_del (mi->context.c2.es, "ifconfig_pool_remote_ip"); + setenv_del (mi->context.c2.es, "ifconfig_pool_netmask"); + + if (mi->context.c2.push_ifconfig_defined) + { + const int tunnel_type = TUNNEL_TYPE (mi->context.c1.tuntap); + const int tunnel_topology = TUNNEL_TOPOLOGY (mi->context.c1.tuntap); + + setenv_in_addr_t (mi->context.c2.es, + "ifconfig_pool_remote_ip", + mi->context.c2.push_ifconfig_local, + SA_SET_IF_NONZERO); + + if (tunnel_type == DEV_TYPE_TAP || (tunnel_type == DEV_TYPE_TUN && tunnel_topology == TOP_SUBNET)) + { + setenv_in_addr_t (mi->context.c2.es, + "ifconfig_pool_netmask", + mi->context.c2.push_ifconfig_remote_netmask, + SA_SET_IF_NONZERO); + } + else if (tunnel_type == DEV_TYPE_TUN) + { + setenv_in_addr_t (mi->context.c2.es, + "ifconfig_pool_local_ip", + mi->context.c2.push_ifconfig_remote_netmask, + SA_SET_IF_NONZERO); + } + } + + /* TODO: I'm not exactly sure what these environment variables are + * used for, but if we have them for IPv4, we should also have + * them for IPv6, no? + */ } /* * Called after client-connect script is called */ static void -multi_client_connect_post(struct multi_context *m, - struct multi_instance *mi, - const char *dc_file, - unsigned int option_permissions_mask, - unsigned int *option_types_found) -{ - /* Did script generate a dynamic config file? */ - if (test_file(dc_file)) +multi_client_connect_post (struct multi_context *m, + struct multi_instance *mi, + const char *dc_file, + unsigned int *option_types_found) +{ + /* Did script generate a dynamic config file? */ + if (test_file (dc_file)) { - options_server_import(&mi->context.options, - dc_file, - D_IMPORT_ERRORS|M_OPTERR, - option_permissions_mask, - option_types_found, - mi->context.c2.es); - - /* - * If the --client-connect script generates a config file - * with an --ifconfig-push directive, it will override any - * --ifconfig-push directive from the --client-config-dir - * directory or any --ifconfig-pool dynamic address. - */ - multi_select_virtual_addr(m, mi); - multi_set_virtual_addr_env(m, mi); + options_server_import (&mi->context.options, + dc_file, + D_IMPORT_ERRORS|M_OPTERR, + CLIENT_CONNECT_OPT_MASK, + option_types_found, + mi->context.c2.es); + + /* + * If the --client-connect script generates a config file + * with an --ifconfig-push directive, it will override any + * --ifconfig-push directive from the --client-config-dir + * directory or any --ifconfig-pool dynamic address. + */ + multi_select_virtual_addr (m, mi); + multi_set_virtual_addr_env (m, mi); } } @@ -1670,111 +1494,140 @@ multi_client_connect_post(struct multi_context *m, * Called after client-connect plug-in is called */ static void -multi_client_connect_post_plugin(struct multi_context *m, - struct multi_instance *mi, - const struct plugin_return *pr, - unsigned int option_permissions_mask, - unsigned int *option_types_found) +multi_client_connect_post_plugin (struct multi_context *m, + struct multi_instance *mi, + const struct plugin_return *pr, + unsigned int *option_types_found) { - struct plugin_return config; + struct plugin_return config; - plugin_return_get_column(pr, &config, "config"); + plugin_return_get_column (pr, &config, "config"); - /* Did script generate a dynamic config file? */ - if (plugin_return_defined(&config)) + /* Did script generate a dynamic config file? */ + if (plugin_return_defined (&config)) { - int i; - for (i = 0; i < config.n; ++i) - { - if (config.list[i] && config.list[i]->value) - { - options_string_import(&mi->context.options, - config.list[i]->value, - D_IMPORT_ERRORS|M_OPTERR, - option_permissions_mask, - option_types_found, - mi->context.c2.es); - } - } + int i; + for (i = 0; i < config.n; ++i) + { + if (config.list[i] && config.list[i]->value) + options_string_import (&mi->context.options, + config.list[i]->value, + D_IMPORT_ERRORS|M_OPTERR, + CLIENT_CONNECT_OPT_MASK, + option_types_found, + mi->context.c2.es); + } - /* - * If the --client-connect script generates a config file - * with an --ifconfig-push directive, it will override any - * --ifconfig-push directive from the --client-config-dir - * directory or any --ifconfig-pool dynamic address. - */ - multi_select_virtual_addr(m, mi); - multi_set_virtual_addr_env(m, mi); + /* + * If the --client-connect script generates a config file + * with an --ifconfig-push directive, it will override any + * --ifconfig-push directive from the --client-config-dir + * directory or any --ifconfig-pool dynamic address. + */ + multi_select_virtual_addr (m, mi); + multi_set_virtual_addr_env (m, mi); } } -#endif /* ifdef ENABLE_PLUGIN */ - -#ifdef MANAGEMENT_DEF_AUTH +#endif /* * Called to load management-derived client-connect config */ static void -multi_client_connect_mda(struct multi_context *m, - struct multi_instance *mi, - const struct buffer_list *config, - unsigned int option_permissions_mask, - unsigned int *option_types_found) +multi_client_connect_mda (struct multi_context *m, + struct multi_instance *mi, + unsigned int *option_types_found, + int *cc_succeeded, + int *cc_succeeded_count) { - if (config) - { - struct buffer_entry *be; - - for (be = config->head; be != NULL; be = be->next) - { - const char *opt = BSTR(&be->buf); - options_string_import(&mi->context.options, - opt, - D_IMPORT_ERRORS|M_OPTERR, - option_permissions_mask, - option_types_found, - mi->context.c2.es); - } - - /* - * If the --client-connect script generates a config file - * with an --ifconfig-push directive, it will override any - * --ifconfig-push directive from the --client-config-dir - * directory or any --ifconfig-pool dynamic address. - */ - multi_select_virtual_addr(m, mi); - multi_set_virtual_addr_env(m, mi); +#ifdef MANAGEMENT_DEF_AUTH + if (mi->cc_config) + { + struct buffer_entry *be; + + for (be = mi->cc_config->head; be != NULL; be = be->next) + { + const char *opt = BSTR(&be->buf); + options_string_import (&mi->context.options, + opt, + D_IMPORT_ERRORS|M_OPTERR, + CLIENT_CONNECT_OPT_MASK, + option_types_found, + mi->context.c2.es); + } + + /* + * If the --client-connect script generates a config file + * with an --ifconfig-push directive, it will override any + * --ifconfig-push directive from the --client-config-dir + * directory or any --ifconfig-pool dynamic address. + */ + multi_select_virtual_addr (m, mi); + multi_set_virtual_addr_env (m, mi); + + ++*cc_succeeded_count; } +#endif } -#endif /* ifdef MANAGEMENT_DEF_AUTH */ - static void -multi_client_connect_setenv(struct multi_context *m, - struct multi_instance *mi) +multi_client_connect_setenv (struct multi_context *m, + struct multi_instance *mi) { - struct gc_arena gc = gc_new(); + struct gc_arena gc = gc_new (); - /* setenv incoming cert common name for script */ - setenv_str(mi->context.c2.es, "common_name", tls_common_name(mi->context.c2.tls_multi, true)); + /* setenv incoming cert common name for script */ + setenv_str (mi->context.c2.es, "common_name", tls_common_name (mi->context.c2.tls_multi, true)); - /* setenv client real IP address */ - setenv_trusted(mi->context.c2.es, get_link_socket_info(&mi->context)); + /* setenv client real IP address */ + setenv_trusted (mi->context.c2.es, get_link_socket_info (&mi->context)); - /* setenv client virtual IP address */ - multi_set_virtual_addr_env(m, mi); + /* setenv client virtual IP address */ + multi_set_virtual_addr_env (m, mi); - /* setenv connection time */ - { - const char *created_ascii = time_string(mi->created, 0, false, &gc); - setenv_str(mi->context.c2.es, "time_ascii", created_ascii); - setenv_unsigned(mi->context.c2.es, "time_unix", (unsigned int)mi->created); - } + /* setenv connection time */ + { + const char *created_ascii = time_string (mi->created, 0, false, &gc); + setenv_str (mi->context.c2.es, "time_ascii", created_ascii); + setenv_unsigned (mi->context.c2.es, "time_unix", (unsigned int)mi->created); + } - gc_free(&gc); + gc_free (&gc); } +static void +multi_client_connect_early_setup (struct multi_context *m, + struct multi_instance *mi); +static void +multi_client_connect_source_ccd (struct multi_context *m, + struct multi_instance *mi, + unsigned int *option_types_found); +static void +multi_client_connect_call_plugin_v1 (struct multi_context *m, + struct multi_instance *mi, + unsigned int *option_types_found, + int *cc_succeeded, + int *cc_succeeded_count); +static void +multi_client_connect_call_plugin_v2 (struct multi_context *m, + struct multi_instance *mi, + unsigned int *option_types_found, + int *cc_succeeded, + int *cc_succeeded_count); +static void +multi_client_connect_call_script (struct multi_context *m, + struct multi_instance *mi, + unsigned int *option_types_found, + int *cc_succeeded, + int *cc_succeeded_count); +static void +multi_client_connect_late_setup (struct multi_context *m, + struct multi_instance *mi, + const unsigned int option_types_found, + int cc_succeeded, + const int cc_succeeded_count); + /* * Called as soon as the SSL/TLS connection authenticates. * @@ -1785,401 +1638,413 @@ multi_client_connect_setenv(struct multi_context *m, * push */ static void -multi_connection_established(struct multi_context *m, struct multi_instance *mi) +multi_connection_established (struct multi_context *m, struct multi_instance *mi) { - if (tls_authentication_status(mi->context.c2.tls_multi, 0) == TLS_AUTHENTICATION_SUCCEEDED) + if (tls_authentication_status (mi->context.c2.tls_multi, 0) == TLS_AUTHENTICATION_SUCCEEDED) { - struct gc_arena gc = gc_new(); - unsigned int option_types_found = 0; + unsigned int option_types_found = 0; + int cc_succeeded = true; /* client connect script status */ + int cc_succeeded_count = 0; - const unsigned int option_permissions_mask = - OPT_P_INSTANCE - | OPT_P_INHERIT - | OPT_P_PUSH - | OPT_P_TIMER - | OPT_P_CONFIG - | OPT_P_ECHO - | OPT_P_COMP - | OPT_P_SOCKFLAGS; - - int cc_succeeded = true; /* client connect script status */ - int cc_succeeded_count = 0; - - ASSERT(mi->context.c1.tuntap); - - /* lock down the common name and cert hashes so they can't change during future TLS renegotiations */ - tls_lock_common_name(mi->context.c2.tls_multi); - tls_lock_cert_hash_set(mi->context.c2.tls_multi); - - /* generate a msg() prefix for this client instance */ - generate_prefix(mi); - - /* delete instances of previous clients with same common-name */ - if (!mi->context.options.duplicate_cn) - { - multi_delete_dup(m, mi); - } - - /* reset pool handle to null */ - mi->vaddr_handle = -1; - - /* - * Try to source a dynamic config file from the - * --client-config-dir directory. - */ - if (mi->context.options.client_config_dir) - { - const char *ccd_file; - - ccd_file = gen_path(mi->context.options.client_config_dir, - tls_common_name(mi->context.c2.tls_multi, false), - &gc); - - /* try common-name file */ - if (test_file(ccd_file)) - { - options_server_import(&mi->context.options, - ccd_file, - D_IMPORT_ERRORS|M_OPTERR, - option_permissions_mask, - &option_types_found, - mi->context.c2.es); - } - else /* try default file */ - { - ccd_file = gen_path(mi->context.options.client_config_dir, - CCD_DEFAULT, - &gc); + multi_client_connect_early_setup (m, mi); - if (test_file(ccd_file)) - { - options_server_import(&mi->context.options, - ccd_file, - D_IMPORT_ERRORS|M_OPTERR, - option_permissions_mask, - &option_types_found, - mi->context.c2.es); - } - } - } - - /* - * Select a virtual address from either --ifconfig-push in --client-config-dir file - * or --ifconfig-pool. - */ - multi_select_virtual_addr(m, mi); - - /* do --client-connect setenvs */ - multi_client_connect_setenv(m, mi); - -#ifdef ENABLE_PLUGIN - /* - * Call client-connect plug-in. - */ - - /* deprecated callback, use a file for passing back return info */ - if (plugin_defined(mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT)) - { - struct argv argv = argv_new(); - const char *dc_file = create_temp_file(mi->context.options.tmp_dir, "cc", &gc); - - if (!dc_file) - { - cc_succeeded = false; - goto script_depr_failed; - } - - argv_printf(&argv, "%s", dc_file); - if (plugin_call(mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT, &argv, NULL, mi->context.c2.es) != OPENVPN_PLUGIN_FUNC_SUCCESS) - { - msg(M_WARN, "WARNING: client-connect plugin call failed"); - cc_succeeded = false; - } - else - { - multi_client_connect_post(m, mi, dc_file, option_permissions_mask, &option_types_found); - ++cc_succeeded_count; - } - - if (!platform_unlink(dc_file)) - { - msg(D_MULTI_ERRORS, "MULTI: problem deleting temporary file: %s", - dc_file); - } - -script_depr_failed: - argv_reset(&argv); - } - - /* V2 callback, use a plugin_return struct for passing back return info */ - if (plugin_defined(mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT_V2)) - { - struct plugin_return pr; - - plugin_return_init(&pr); - - if (plugin_call(mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT_V2, NULL, &pr, mi->context.c2.es) != OPENVPN_PLUGIN_FUNC_SUCCESS) - { - msg(M_WARN, "WARNING: client-connect-v2 plugin call failed"); - cc_succeeded = false; - } - else - { - multi_client_connect_post_plugin(m, mi, &pr, option_permissions_mask, &option_types_found); - ++cc_succeeded_count; - } - - plugin_return_free(&pr); - } -#endif /* ifdef ENABLE_PLUGIN */ - - /* - * Run --client-connect script. - */ - if (mi->context.options.client_connect_script && cc_succeeded) - { - struct argv argv = argv_new(); - const char *dc_file = NULL; - - setenv_str(mi->context.c2.es, "script_type", "client-connect"); - - dc_file = create_temp_file(mi->context.options.tmp_dir, "cc", &gc); - if (!dc_file) - { - cc_succeeded = false; - goto script_failed; - } - - argv_parse_cmd(&argv, mi->context.options.client_connect_script); - argv_printf_cat(&argv, "%s", dc_file); - - if (openvpn_run_script(&argv, mi->context.c2.es, 0, "--client-connect")) - { - multi_client_connect_post(m, mi, dc_file, option_permissions_mask, &option_types_found); - ++cc_succeeded_count; - } - else - { - cc_succeeded = false; - } - - if (!platform_unlink(dc_file)) - { - msg(D_MULTI_ERRORS, "MULTI: problem deleting temporary file: %s", - dc_file); - } - -script_failed: - argv_reset(&argv); - } - - /* - * Check for client-connect script left by management interface client - */ -#ifdef MANAGEMENT_DEF_AUTH - if (cc_succeeded && mi->cc_config) - { - multi_client_connect_mda(m, mi, mi->cc_config, option_permissions_mask, &option_types_found); - ++cc_succeeded_count; - } -#endif + multi_client_connect_source_ccd (m, mi, &option_types_found); - /* - * Check for "disable" directive in client-config-dir file - * or config file generated by --client-connect script. - */ - if (mi->context.options.disable) - { - msg(D_MULTI_ERRORS, "MULTI: client has been rejected due to 'disable' directive"); - cc_succeeded = false; - cc_succeeded_count = 0; - } + /* + * Select a virtual address from either --ifconfig-push in + * --client-config-dir file or --ifconfig-pool. + */ + multi_select_virtual_addr (m, mi); - if (cc_succeeded) - { - /* - * Process sourced options. - */ - do_deferred_options(&mi->context, option_types_found); - - /* - * make sure we got ifconfig settings from somewhere - */ - if (!mi->context.c2.push_ifconfig_defined) - { - msg(D_MULTI_ERRORS, "MULTI: no dynamic or static remote --ifconfig address is available for %s", - multi_instance_string(mi, false, &gc)); - } + /* do --client-connect setenvs */ + multi_client_connect_setenv (m, mi); - /* - * make sure that ifconfig settings comply with constraints - */ - if (!ifconfig_push_constraint_satisfied(&mi->context)) - { - /* JYFIXME -- this should cause the connection to fail */ - msg(D_MULTI_ERRORS, "MULTI ERROR: primary virtual IP for %s (%s) violates tunnel network/netmask constraint (%s/%s)", - multi_instance_string(mi, false, &gc), - print_in_addr_t(mi->context.c2.push_ifconfig_local, 0, &gc), - print_in_addr_t(mi->context.options.push_ifconfig_constraint_network, 0, &gc), - print_in_addr_t(mi->context.options.push_ifconfig_constraint_netmask, 0, &gc)); - } + multi_client_connect_call_plugin_v1 (m, mi, &option_types_found, + &cc_succeeded, &cc_succeeded_count); - /* - * For routed tunnels, set up internal route to endpoint - * plus add all iroute routes. - */ - if (TUNNEL_TYPE(mi->context.c1.tuntap) == DEV_TYPE_TUN) - { - if (mi->context.c2.push_ifconfig_defined) - { - multi_learn_in_addr_t(m, mi, mi->context.c2.push_ifconfig_local, -1, true); - msg(D_MULTI_LOW, "MULTI: primary virtual IP for %s: %s", - multi_instance_string(mi, false, &gc), - print_in_addr_t(mi->context.c2.push_ifconfig_local, 0, &gc)); - } + multi_client_connect_call_plugin_v2 (m, mi, &option_types_found, + &cc_succeeded, &cc_succeeded_count); - if (mi->context.c2.push_ifconfig_ipv6_defined) - { - multi_learn_in6_addr(m, mi, mi->context.c2.push_ifconfig_ipv6_local, -1, true); - /* TODO: find out where addresses are "unlearned"!! */ - msg(D_MULTI_LOW, "MULTI: primary virtual IPv6 for %s: %s", - multi_instance_string(mi, false, &gc), - print_in6_addr(mi->context.c2.push_ifconfig_ipv6_local, 0, &gc)); - } + /* + * Run --client-connect script. + */ + if (cc_succeeded) + { + multi_client_connect_call_script (m, mi, &option_types_found, + &cc_succeeded, + &cc_succeeded_count); + } - /* add routes locally, pointing to new client, if - * --iroute options have been specified */ - multi_add_iroutes(m, mi); + /* + * Check for client-connect script left by management interface client + */ + if (cc_succeeded) + { + multi_client_connect_mda (m, mi, &option_types_found, + &cc_succeeded, &cc_succeeded_count); + } - /* - * iroutes represent subnets which are "owned" by a particular - * client. Therefore, do not actually push a route to a client - * if it matches one of the client's iroutes. - */ - remove_iroutes_from_push_route_list(&mi->context.options); - } - else if (mi->context.options.iroutes) - { - msg(D_MULTI_ERRORS, "MULTI: --iroute options rejected for %s -- iroute only works with tun-style tunnels", - multi_instance_string(mi, false, &gc)); - } + multi_client_connect_late_setup (m, mi, option_types_found, + cc_succeeded, cc_succeeded_count); - /* set our client's VPN endpoint for status reporting purposes */ - mi->reporting_addr = mi->context.c2.push_ifconfig_local; - mi->reporting_addr_ipv6 = mi->context.c2.push_ifconfig_ipv6_local; + /* set flag so we don't get called again */ + mi->connection_established_flag = true; + } - /* set context-level authentication flag */ - mi->context.c2.context_auth = CAS_SUCCEEDED; + /* + * Reply now to client's PUSH_REQUEST query + */ + mi->context.c2.push_reply_deferred = false; +} -#ifdef ENABLE_ASYNC_PUSH - /* authentication complete, send push reply */ - if (mi->context.c2.push_request_received) - { - process_incoming_push_request(&mi->context); - } -#endif - } - else - { - /* set context-level authentication flag */ - mi->context.c2.context_auth = cc_succeeded_count ? CAS_PARTIAL : CAS_FAILED; - } +static void +multi_client_connect_early_setup (struct multi_context *m, + struct multi_instance *mi) +{ + /* lock down the common name and cert hashes so they can't change during + future TLS renegotiations */ + tls_lock_common_name (mi->context.c2.tls_multi); + tls_lock_cert_hash_set (mi->context.c2.tls_multi); - /* set flag so we don't get called again */ - mi->connection_established_flag = true; + /* generate a msg() prefix for this client instance */ + generate_prefix (mi); - /* increment number of current authenticated clients */ - ++m->n_clients; - update_mstat_n_clients(m->n_clients); - --mi->n_clients_delta; + /* delete instances of previous clients with same common-name */ + if (!mi->context.options.duplicate_cn) + multi_delete_dup (m, mi); -#ifdef MANAGEMENT_DEF_AUTH - if (management) - { - management_connection_established(management, &mi->context.c2.mda_context, mi->context.c2.es); - } -#endif + /* reset pool handle to null */ + mi->vaddr_handle = -1; +} - gc_free(&gc); - } +/* + * Try to source a dynamic config file from the + * --client-config-dir directory. + */ +static void +multi_client_connect_source_ccd (struct multi_context *m, + struct multi_instance *mi, + unsigned int *option_types_found) +{ + if (mi->context.options.client_config_dir) + { + struct gc_arena gc = gc_new (); + const char *ccd_file; + + ccd_file = gen_path (mi->context.options.client_config_dir, + tls_common_name (mi->context.c2.tls_multi, false), + &gc); + + /* try common-name file */ + if (test_file (ccd_file)) + { + options_server_import (&mi->context.options, + ccd_file, + D_IMPORT_ERRORS|M_OPTERR, + CLIENT_CONNECT_OPT_MASK, + option_types_found, + mi->context.c2.es); + } + else /* try default file */ + { + ccd_file = gen_path (mi->context.options.client_config_dir, + CCD_DEFAULT, + &gc); + + if (test_file (ccd_file)) + { + options_server_import (&mi->context.options, + ccd_file, + D_IMPORT_ERRORS|M_OPTERR, + CLIENT_CONNECT_OPT_MASK, + option_types_found, + mi->context.c2.es); + } + } + + gc_free (&gc); + } +} - /* - * Reply now to client's PUSH_REQUEST query - */ - mi->context.c2.push_reply_deferred = false; +/* + * Call client-connect plug-in. + * + * deprecated callback, use a file for passing back return info + */ +static void +multi_client_connect_call_plugin_v1 (struct multi_context *m, + struct multi_instance *mi, + unsigned int *option_types_found, + int *cc_succeeded, + int *cc_succeeded_count) +{ +#ifdef ENABLE_PLUGIN + ASSERT (m); + ASSERT (mi); + ASSERT (option_types_found); + ASSERT (cc_succeeded); + ASSERT (cc_succeeded_count); + + if (plugin_defined (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT)) + { + int plug_ret; + struct gc_arena gc = gc_new (); + struct argv argv = argv_new (); + const char *dc_file = create_temp_file (mi->context.options.tmp_dir, "cc", &gc); + + if (!dc_file) + { + *cc_succeeded = false; + goto script_depr_failed; + } + + argv_printf (&argv, "%s", dc_file); + + plug_ret = plugin_call (mi->context.plugins, + OPENVPN_PLUGIN_CLIENT_CONNECT, + &argv, NULL, mi->context.c2.es); + argv_reset (&argv); + if (plug_ret != OPENVPN_PLUGIN_FUNC_SUCCESS) + { + msg (M_WARN, "WARNING: client-connect plugin call failed"); + *cc_succeeded = false; + } + else + { + multi_client_connect_post (m, mi, dc_file, option_types_found); + ++*cc_succeeded_count; + } +script_depr_failed: + gc_free (&gc); + } +#endif } -#ifdef ENABLE_ASYNC_PUSH /* - * Called when inotify event is fired, which happens when acf file is closed or deleted. - * Continues authentication and sends push_reply. + * Call client-connect plug-in. + * + * V2 callback, use a plugin_return struct for passing back return info */ -void -multi_process_file_closed(struct multi_context *m, const unsigned int mpp_flags) +static void +multi_client_connect_call_plugin_v2 (struct multi_context *m, + struct multi_instance *mi, + unsigned int *option_types_found, + int *cc_succeeded, + int *cc_succeeded_count) { - char buffer[INOTIFY_EVENT_BUFFER_SIZE]; - size_t buffer_i = 0; - int r = read(m->top.c2.inotify_fd, buffer, INOTIFY_EVENT_BUFFER_SIZE); +#ifdef ENABLE_PLUGIN + ASSERT (m); + ASSERT (mi); + ASSERT (option_types_found); + ASSERT (cc_succeeded); + ASSERT (cc_succeeded_count); + + if (plugin_defined (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT_V2)) + { + int plug_ret; + struct plugin_return pr; + + plugin_return_init (&pr); + + plug_ret = plugin_call (mi->context.plugins, + OPENVPN_PLUGIN_CLIENT_CONNECT_V2, + NULL, &pr, mi->context.c2.es); + if (plug_ret != OPENVPN_PLUGIN_FUNC_SUCCESS) + { + msg (M_WARN, "WARNING: client-connect-v2 plugin call failed"); + *cc_succeeded = false; + } + else + { + multi_client_connect_post_plugin (m, mi, &pr, option_types_found); + ++*cc_succeeded_count; + } + + plugin_return_free (&pr); + } +#endif +} - while (buffer_i < r) - { - /* parse inotify events */ - struct inotify_event *pevent = (struct inotify_event *) &buffer[buffer_i]; - size_t event_size = sizeof(struct inotify_event) + pevent->len; - buffer_i += event_size; +static void +multi_client_connect_call_script (struct multi_context *m, + struct multi_instance *mi, + unsigned int *option_types_found, + int *cc_succeeded, + int *cc_succeeded_count) +{ + ASSERT (m); + ASSERT (mi); + ASSERT (option_types_found); + ASSERT (cc_succeeded); + ASSERT (cc_succeeded_count); + + if (mi->context.options.client_connect_script) + { + struct gc_arena gc = gc_new (); + struct argv argv = argv_new (); + const char *dc_file; + + setenv_str (mi->context.c2.es, "script_type", "client-connect"); + + dc_file = create_temp_file (mi->context.options.tmp_dir, "cc", &gc); + if (!dc_file) + { + cc_succeeded = false; + goto script_failed; + } + + argv_printf (&argv, "%sc %s", + mi->context.options.client_connect_script, + dc_file); + + if (openvpn_run_script (&argv, mi->context.c2.es, 0, "--client-connect")) + { + multi_client_connect_post (m, mi, dc_file, option_types_found); + ++cc_succeeded_count; + } + else + cc_succeeded = false; +script_failed: + argv_reset (&argv); + gc_free (&gc); + } +} - msg(D_MULTI_DEBUG, "MULTI: modified fd %d, mask %d", pevent->wd, pevent->mask); +static void +multi_client_connect_late_setup (struct multi_context *m, + struct multi_instance *mi, + const unsigned int option_types_found, + int cc_succeeded, + const int cc_succeeded_count) +{ + struct gc_arena gc = gc_new (); + ASSERT (mi->context.c1.tuntap); + + /* + * Check for "disable" directive in client-config-dir file + * or config file generated by --client-connect script. + */ + if (mi->context.options.disable) + { + msg (D_MULTI_ERRORS, "MULTI: client has been rejected due to 'disable' directive"); + cc_succeeded = false; + } + + if (cc_succeeded) + { + /* + * Process sourced options. + */ + do_deferred_options (&mi->context, option_types_found); + + /* + * make sure we got ifconfig settings from somewhere + */ + if (!mi->context.c2.push_ifconfig_defined) + { + msg (D_MULTI_ERRORS, "MULTI: no dynamic or static remote --ifconfig address is available for %s", + multi_instance_string (mi, false, &gc)); + } + + /* + * make sure that ifconfig settings comply with constraints + */ + if (!ifconfig_push_constraint_satisfied (&mi->context)) + { + /* JYFIXME -- this should cause the connection to fail */ + msg (D_MULTI_ERRORS, "MULTI ERROR: primary virtual IP for %s (%s) violates tunnel network/netmask constraint (%s/%s)", + multi_instance_string (mi, false, &gc), + print_in_addr_t (mi->context.c2.push_ifconfig_local, 0, &gc), + print_in_addr_t (mi->context.options.push_ifconfig_constraint_network, 0, &gc), + print_in_addr_t (mi->context.options.push_ifconfig_constraint_netmask, 0, &gc)); + } + + /* + * For routed tunnels, set up internal route to endpoint + * plus add all iroute routes. + */ + if (TUNNEL_TYPE (mi->context.c1.tuntap) == DEV_TYPE_TUN) + { + if (mi->context.c2.push_ifconfig_defined) + { + multi_learn_in_addr_t (m, mi, mi->context.c2.push_ifconfig_local, -1, true); + msg (D_MULTI_LOW, "MULTI: primary virtual IP for %s: %s", + multi_instance_string (mi, false, &gc), + print_in_addr_t (mi->context.c2.push_ifconfig_local, 0, &gc)); + } + + if (mi->context.c2.push_ifconfig_ipv6_defined) + { + multi_learn_in6_addr (m, mi, mi->context.c2.push_ifconfig_ipv6_local, -1, true); + /* TODO: find out where addresses are "unlearned"!! */ + msg (D_MULTI_LOW, "MULTI: primary virtual IPv6 for %s: %s", + multi_instance_string (mi, false, &gc), + print_in6_addr (mi->context.c2.push_ifconfig_ipv6_local, 0, &gc)); + } + + /* add routes locally, pointing to new client, if + --iroute options have been specified */ + multi_add_iroutes (m, mi); + + /* + * iroutes represent subnets which are "owned" by a particular + * client. Therefore, do not actually push a route to a client + * if it matches one of the client's iroutes. + */ + remove_iroutes_from_push_route_list (&mi->context.options); + } + else if (mi->context.options.iroutes) + { + msg (D_MULTI_ERRORS, "MULTI: --iroute options rejected for %s -- iroute only works with tun-style tunnels", + multi_instance_string (mi, false, &gc)); + } + + /* set our client's VPN endpoint for status reporting purposes */ + mi->reporting_addr = mi->context.c2.push_ifconfig_local; + mi->reporting_addr_ipv6 = mi->context.c2.push_ifconfig_ipv6_local; + + /* set context-level authentication flag */ + mi->context.c2.context_auth = CAS_SUCCEEDED; + } + else + { + /* set context-level authentication flag */ + mi->context.c2.context_auth = cc_succeeded_count ? CAS_PARTIAL : CAS_FAILED; + } + + /* increment number of current authenticated clients */ + ++m->n_clients; + update_mstat_n_clients(m->n_clients); + --mi->n_clients_delta; - struct multi_instance *mi = hash_lookup(m->inotify_watchers, (void *) (unsigned long) pevent->wd); +#ifdef MANAGEMENT_DEF_AUTH + if (management) + management_connection_established (management, &mi->context.c2.mda_context, mi->context.c2.es); +#endif - if (pevent->mask & IN_CLOSE_WRITE) - { - if (mi) - { - /* continue authentication and send push_reply */ - multi_process_post(m, mi, mpp_flags); - } - else - { - msg(D_MULTI_ERRORS, "MULTI: multi_instance not found!"); - } - } - else if (pevent->mask & IN_IGNORED) - { - /* this event is _always_ fired when watch is removed or file is deleted */ - if (mi) - { - hash_remove(m->inotify_watchers, (void *) (unsigned long) pevent->wd); - mi->inotify_watch = -1; - } - } - else - { - msg(D_MULTI_ERRORS, "MULTI: unknown mask %d", pevent->mask); - } - } + gc_free (&gc); } -#endif /* ifdef ENABLE_ASYNC_PUSH */ + /* * Add a mbuf buffer to a particular * instance. */ void -multi_add_mbuf(struct multi_context *m, - struct multi_instance *mi, - struct mbuf_buffer *mb) +multi_add_mbuf (struct multi_context *m, + struct multi_instance *mi, + struct mbuf_buffer *mb) { - if (multi_output_queue_ready(m, mi)) + if (multi_output_queue_ready (m, mi)) { - struct mbuf_item item; - item.buffer = mb; - item.instance = mi; - mbuf_add_item(m->mbuf, &item); + struct mbuf_item item; + item.buffer = mb; + item.instance = mi; + mbuf_add_item (m->mbuf, &item); } - else + else { - msg(D_MULTI_DROPPED, "MULTI: packet dropped due to output saturation (multi_add_mbuf)"); + msg (D_MULTI_DROPPED, "MULTI: packet dropped due to output saturation (multi_add_mbuf)"); } } @@ -2187,18 +2052,18 @@ multi_add_mbuf(struct multi_context *m, * Add a packet to a client instance output queue. */ static inline void -multi_unicast(struct multi_context *m, - const struct buffer *buf, - struct multi_instance *mi) +multi_unicast (struct multi_context *m, + const struct buffer *buf, + struct multi_instance *mi) { - struct mbuf_buffer *mb; + struct mbuf_buffer *mb; - if (BLEN(buf) > 0) + if (BLEN (buf) > 0) { - mb = mbuf_alloc_buf(buf); - mb->flags = MF_UNICAST; - multi_add_mbuf(m, mi, mb); - mbuf_free_buf(mb); + mb = mbuf_alloc_buf (buf); + mb->flags = MF_UNICAST; + multi_add_mbuf (m, mi, mb); + mbuf_free_buf (mb); } } @@ -2206,61 +2071,61 @@ multi_unicast(struct multi_context *m, * Broadcast a packet to all clients. */ static void -multi_bcast(struct multi_context *m, - const struct buffer *buf, - const struct multi_instance *sender_instance, - const struct mroute_addr *sender_addr) +multi_bcast (struct multi_context *m, + const struct buffer *buf, + const struct multi_instance *sender_instance, + const struct mroute_addr *sender_addr) { - struct hash_iterator hi; - struct hash_element *he; - struct multi_instance *mi; - struct mbuf_buffer *mb; + struct hash_iterator hi; + struct hash_element *he; + struct multi_instance *mi; + struct mbuf_buffer *mb; - if (BLEN(buf) > 0) + if (BLEN (buf) > 0) { - perf_push(PERF_MULTI_BCAST); + perf_push (PERF_MULTI_BCAST); #ifdef MULTI_DEBUG_EVENT_LOOP - printf("BCAST len=%d\n", BLEN(buf)); + printf ("BCAST len=%d\n", BLEN (buf)); #endif - mb = mbuf_alloc_buf(buf); - hash_iterator_init(m->iter, &hi); - - while ((he = hash_iterator_next(&hi))) - { - mi = (struct multi_instance *) he->value; - if (mi != sender_instance && !mi->halt) - { + mb = mbuf_alloc_buf (buf); + hash_iterator_init (m->iter, &hi); + + while ((he = hash_iterator_next (&hi))) + { + mi = (struct multi_instance *) he->value; + if (mi != sender_instance && !mi->halt) + { #ifdef ENABLE_PF - if (sender_instance) - { - if (!pf_c2c_test(&sender_instance->context, &mi->context, "bcast_c2c")) - { - msg(D_PF_DROPPED_BCAST, "PF: client[%s] -> client[%s] packet dropped by BCAST packet filter", - mi_prefix(sender_instance), - mi_prefix(mi)); - continue; - } - } - if (sender_addr) - { - if (!pf_addr_test(&mi->context, sender_addr, "bcast_src_addr")) - { - struct gc_arena gc = gc_new(); - msg(D_PF_DROPPED_BCAST, "PF: addr[%s] -> client[%s] packet dropped by BCAST packet filter", - mroute_addr_print_ex(sender_addr, MAPF_SHOW_ARP, &gc), - mi_prefix(mi)); - gc_free(&gc); - continue; - } - } -#endif /* ifdef ENABLE_PF */ - multi_add_mbuf(m, mi, mb); - } - } + if (sender_instance) + { + if (!pf_c2c_test (&sender_instance->context, &mi->context, "bcast_c2c")) + { + msg (D_PF_DROPPED_BCAST, "PF: client[%s] -> client[%s] packet dropped by BCAST packet filter", + mi_prefix (sender_instance), + mi_prefix (mi)); + continue; + } + } + if (sender_addr) + { + if (!pf_addr_test (&mi->context, sender_addr, "bcast_src_addr")) + { + struct gc_arena gc = gc_new (); + msg (D_PF_DROPPED_BCAST, "PF: addr[%s] -> client[%s] packet dropped by BCAST packet filter", + mroute_addr_print_ex (sender_addr, MAPF_SHOW_ARP, &gc), + mi_prefix (mi)); + gc_free (&gc); + continue; + } + } +#endif + multi_add_mbuf (m, mi, mb); + } + } - hash_iterator_free(&hi); - mbuf_free_buf(mb); - perf_pop(); + hash_iterator_free (&hi); + mbuf_free_buf (mb); + perf_pop (); } } @@ -2276,39 +2141,35 @@ multi_bcast(struct multi_context *m, * Sigma should be no larger than TV_WITHIN_SIGMA_MAX_USEC */ static inline unsigned int -compute_wakeup_sigma(const struct timeval *delta) +compute_wakeup_sigma (const struct timeval *delta) { - if (delta->tv_sec < 1) + if (delta->tv_sec < 1) { - /* if < 1 sec, fuzz = # of microseconds / 8 */ - return delta->tv_usec >> 3; + /* if < 1 sec, fuzz = # of microseconds / 8 */ + return delta->tv_usec >> 3; } - else + else { - /* if < 10 minutes, fuzz = 13.1% of timeout */ - if (delta->tv_sec < 600) - { - return delta->tv_sec << 17; - } - else - { - return 120000000; /* if >= 10 minutes, fuzz = 2 minutes */ - } + /* if < 10 minutes, fuzz = 13.1% of timeout */ + if (delta->tv_sec < 600) + return delta->tv_sec << 17; + else + return 120000000; /* if >= 10 minutes, fuzz = 2 minutes */ } } static void -multi_schedule_context_wakeup(struct multi_context *m, struct multi_instance *mi) +multi_schedule_context_wakeup (struct multi_context *m, struct multi_instance *mi) { - /* calculate an absolute wakeup time */ - ASSERT(!openvpn_gettimeofday(&mi->wakeup, NULL)); - tv_add(&mi->wakeup, &mi->context.c2.timeval); + /* calculate an absolute wakeup time */ + ASSERT (!openvpn_gettimeofday (&mi->wakeup, NULL)); + tv_add (&mi->wakeup, &mi->context.c2.timeval); - /* tell scheduler to wake us up at some point in the future */ - schedule_add_entry(m->schedule, - (struct schedule_entry *) mi, - &mi->wakeup, - compute_wakeup_sigma(&mi->context.c2.timeval)); + /* tell scheduler to wake us up at some point in the future */ + schedule_add_entry (m->schedule, + (struct schedule_entry *) mi, + &mi->wakeup, + compute_wakeup_sigma (&mi->context.c2.timeval)); } /* @@ -2407,58 +2268,48 @@ multi_process_post(struct multi_context *m, struct multi_instance *mi, const uns return ret; } -void -multi_process_float(struct multi_context *m, struct multi_instance *mi) +void multi_process_float (struct multi_context* m, struct multi_instance* mi) { - struct mroute_addr real; - struct hash *hash = m->hash; - struct gc_arena gc = gc_new(); + struct mroute_addr real; + struct hash *hash = m->hash; + struct gc_arena gc = gc_new (); - if (!mroute_extract_openvpn_sockaddr(&real, &m->top.c2.from.dest, true)) - { - goto done; - } + if (!mroute_extract_openvpn_sockaddr (&real, &m->top.c2.from.dest, true)) + goto done; - const uint32_t hv = hash_value(hash, &real); - struct hash_bucket *bucket = hash_bucket(hash, hv); + const uint32_t hv = hash_value (hash, &real); + struct hash_bucket *bucket = hash_bucket (hash, hv); - /* make sure that we don't float to an address taken by another client */ - struct hash_element *he = hash_lookup_fast(hash, bucket, &real, hv); - if (he) + struct hash_element *he = hash_lookup_fast (hash, bucket, &real, hv); + if (he) { - struct multi_instance *ex_mi = (struct multi_instance *) he->value; - - struct tls_multi *m1 = mi->context.c2.tls_multi; - struct tls_multi *m2 = ex_mi->context.c2.tls_multi; + struct multi_instance *ex_mi = (struct multi_instance *) he->value; - /* do not float if target address is taken by client with another cert */ - if (!cert_hash_compare(m1->locked_cert_hash_set, m2->locked_cert_hash_set)) - { - msg(D_MULTI_LOW, "Disallow float to an address taken by another client %s", - multi_instance_string(ex_mi, false, &gc)); + const char *cn = tls_common_name (mi->context.c2.tls_multi, true); + const char *ex_cn = tls_common_name (ex_mi->context.c2.tls_multi, true); + if (cn && ex_cn && strcmp (cn, ex_cn)) + { + msg (D_MULTI_MEDIUM, "prevent float to %s", + multi_instance_string (ex_mi, false, &gc)); - mi->context.c2.buf.len = 0; + mi->context.c2.buf.len = 0; - goto done; - } + goto done; + } - msg(D_MULTI_MEDIUM, "closing instance %s", multi_instance_string(ex_mi, false, &gc)); - multi_close_instance(m, ex_mi, false); + msg (D_MULTI_MEDIUM, "closing instance %s", multi_instance_string (ex_mi, false, &gc)); + multi_close_instance(m, ex_mi, false); } - msg(D_MULTI_MEDIUM, "peer %" PRIu32 " (%s) floated from %s to %s", - mi->context.c2.tls_multi->peer_id, - tls_common_name(mi->context.c2.tls_multi, false), - mroute_addr_print(&mi->real, &gc), - print_link_socket_actual(&m->top.c2.from, &gc)); + msg (D_MULTI_MEDIUM, "peer %" PRIu32 " floated from %s to %s", mi->context.c2.tls_multi->peer_id, + mroute_addr_print (&mi->real, &gc), print_link_socket_actual (&m->top.c2.from, &gc)); - /* remove old address from hash table before changing address */ - ASSERT(hash_remove(m->hash, &mi->real)); - ASSERT(hash_remove(m->iter, &mi->real)); + ASSERT (hash_remove(m->hash, &mi->real)); + ASSERT (hash_remove(m->iter, &mi->real)); /* change external network address of the remote peer */ mi->real = real; - generate_prefix(mi); + generate_prefix (mi); mi->context.c2.from = m->top.c2.from; mi->context.c2.to_link_addr = &mi->context.c2.from; @@ -2467,17 +2318,18 @@ multi_process_float(struct multi_context *m, struct multi_instance *mi) mi->context.c2.link_socket = m->top.c2.link_socket; mi->context.c2.link_socket_info->lsa->actual = m->top.c2.from; - tls_update_remote_addr(mi->context.c2.tls_multi, &mi->context.c2.from); + tls_update_remote_addr (mi->context.c2.tls_multi, &mi->context.c2.from); - ASSERT(hash_add(m->hash, &mi->real, mi, false)); - ASSERT(hash_add(m->iter, &mi->real, mi, false)); + ASSERT (hash_add (m->hash, &mi->real, mi, false)); + ASSERT (hash_add (m->iter, &mi->real, mi, false)); #ifdef MANAGEMENT_DEF_AUTH - ASSERT(hash_add(m->cid_hash, &mi->context.c2.mda_context.cid, mi, true)); + hash_remove (m->cid_hash, &mi->context.c2.mda_context.cid); + hash_add (m->cid_hash, &mi->context.c2.mda_context.cid, mi, false); #endif done: - gc_free(&gc); + gc_free (&gc); } /* @@ -2485,230 +2337,224 @@ multi_process_float(struct multi_context *m, struct multi_instance *mi) * i.e. client -> server direction. */ bool -multi_process_incoming_link(struct multi_context *m, struct multi_instance *instance, const unsigned int mpp_flags) +multi_process_incoming_link (struct multi_context *m, struct multi_instance *instance, const unsigned int mpp_flags) { - struct gc_arena gc = gc_new(); + struct gc_arena gc = gc_new (); - struct context *c; - struct mroute_addr src, dest; - unsigned int mroute_flags; - struct multi_instance *mi; - bool ret = true; - bool floated = false; + struct context *c; + struct mroute_addr src, dest; + unsigned int mroute_flags; + struct multi_instance *mi; + bool ret = true; + bool floated = false; - if (m->pending) - { - return true; - } + if (m->pending) + return true; - if (!instance) + if (!instance) { #ifdef MULTI_DEBUG_EVENT_LOOP - printf("TCP/UDP -> TUN [%d]\n", BLEN(&m->top.c2.buf)); + printf ("TCP/UDP -> TUN [%d]\n", BLEN (&m->top.c2.buf)); #endif - multi_set_pending(m, multi_get_create_instance_udp(m, &floated)); - } - else - { - multi_set_pending(m, instance); - } - - if (m->pending) - { - set_prefix(m->pending); - - /* get instance context */ - c = &m->pending->context; - - if (!instance) - { - /* transfer packet pointer from top-level context buffer to instance */ - c->c2.buf = m->top.c2.buf; - - /* transfer from-addr from top-level context buffer to instance */ - if (!floated) - { - c->c2.from = m->top.c2.from; - } - } - - if (BLEN(&c->c2.buf) > 0) - { - struct link_socket_info *lsi; - const uint8_t *orig_buf; - - /* decrypt in instance context */ - - perf_push(PERF_PROC_IN_LINK); - lsi = get_link_socket_info(c); - orig_buf = c->c2.buf.data; - if (process_incoming_link_part1(c, lsi, floated)) - { - if (floated) - { - multi_process_float(m, m->pending); - } - - process_incoming_link_part2(c, lsi, orig_buf); - } - perf_pop(); - - if (TUNNEL_TYPE(m->top.c1.tuntap) == DEV_TYPE_TUN) - { - /* extract packet source and dest addresses */ - mroute_flags = mroute_extract_addr_from_packet(&src, - &dest, - NULL, - NULL, - &c->c2.to_tun, - DEV_TYPE_TUN); - - /* drop packet if extract failed */ - if (!(mroute_flags & MROUTE_EXTRACT_SUCCEEDED)) - { - c->c2.to_tun.len = 0; - } - /* make sure that source address is associated with this client */ - else if (multi_get_instance_by_virtual_addr(m, &src, true) != m->pending) - { - /* IPv6 link-local address (fe80::xxx)? */ - if ( (src.type & MR_ADDR_MASK) == MR_ADDR_IPV6 - && IN6_IS_ADDR_LINKLOCAL(&src.v6.addr) ) - { - /* do nothing, for now. TODO: add address learning */ - } - else - { - msg(D_MULTI_DROPPED, "MULTI: bad source address from client [%s], packet dropped", - mroute_addr_print(&src, &gc)); - } - c->c2.to_tun.len = 0; - } - /* client-to-client communication enabled? */ - else if (m->enable_c2c) - { - /* multicast? */ - if (mroute_flags & MROUTE_EXTRACT_MCAST) - { - /* for now, treat multicast as broadcast */ - multi_bcast(m, &c->c2.to_tun, m->pending, NULL); - } - else /* possible client to client routing */ - { - ASSERT(!(mroute_flags & MROUTE_EXTRACT_BCAST)); - mi = multi_get_instance_by_virtual_addr(m, &dest, true); - - /* if dest addr is a known client, route to it */ - if (mi) - { + multi_set_pending (m, multi_get_create_instance_udp (m, &floated)); + } + else + multi_set_pending (m, instance); + + if (m->pending) + { + set_prefix (m->pending); + + /* get instance context */ + c = &m->pending->context; + + if (!instance) + { + /* transfer packet pointer from top-level context buffer to instance */ + c->c2.buf = m->top.c2.buf; + + /* transfer from-addr from top-level context buffer to instance */ + if (!floated) + c->c2.from = m->top.c2.from; + } + + if (BLEN (&c->c2.buf) > 0) + { + struct link_socket_info *lsi; + const uint8_t *orig_buf; + + /* decrypt in instance context */ + + perf_push (PERF_PROC_IN_LINK); + lsi = get_link_socket_info (c); + orig_buf = c->c2.buf.data; + if (process_incoming_link_part1(c, lsi, floated)) + { + if (floated) + { + multi_process_float (m, m->pending); + } + + process_incoming_link_part2(c, lsi, orig_buf); + } + perf_pop (); + + if (TUNNEL_TYPE (m->top.c1.tuntap) == DEV_TYPE_TUN) + { + /* extract packet source and dest addresses */ + mroute_flags = mroute_extract_addr_from_packet (&src, + &dest, + NULL, + NULL, + &c->c2.to_tun, + DEV_TYPE_TUN); + + /* drop packet if extract failed */ + if (!(mroute_flags & MROUTE_EXTRACT_SUCCEEDED)) + { + c->c2.to_tun.len = 0; + } + /* make sure that source address is associated with this client */ + else if (multi_get_instance_by_virtual_addr (m, &src, true) != m->pending) + { + /* IPv6 link-local address (fe80::xxx)? */ + if ( (src.type & MR_ADDR_MASK) == MR_ADDR_IPV6 && + src.addr[0] == 0xfe && src.addr[1] == 0x80 ) + { + /* do nothing, for now. TODO: add address learning */ + } + else + { + msg (D_MULTI_DROPPED, "MULTI: bad source address from client [%s], packet dropped", + mroute_addr_print (&src, &gc)); + } + c->c2.to_tun.len = 0; + } + /* client-to-client communication enabled? */ + else if (m->enable_c2c) + { + /* multicast? */ + if (mroute_flags & MROUTE_EXTRACT_MCAST) + { + /* for now, treat multicast as broadcast */ + multi_bcast (m, &c->c2.to_tun, m->pending, NULL); + } + else /* possible client to client routing */ + { + ASSERT (!(mroute_flags & MROUTE_EXTRACT_BCAST)); + mi = multi_get_instance_by_virtual_addr (m, &dest, true); + + /* if dest addr is a known client, route to it */ + if (mi) + { #ifdef ENABLE_PF - if (!pf_c2c_test(c, &mi->context, "tun_c2c")) - { - msg(D_PF_DROPPED, "PF: client -> client[%s] packet dropped by TUN packet filter", - mi_prefix(mi)); - } - else + if (!pf_c2c_test (c, &mi->context, "tun_c2c")) + { + msg (D_PF_DROPPED, "PF: client -> client[%s] packet dropped by TUN packet filter", + mi_prefix (mi)); + } + else #endif - { - multi_unicast(m, &c->c2.to_tun, mi); - register_activity(c, BLEN(&c->c2.to_tun)); - } - c->c2.to_tun.len = 0; - } - } - } + { + multi_unicast (m, &c->c2.to_tun, mi); + register_activity (c, BLEN(&c->c2.to_tun)); + } + c->c2.to_tun.len = 0; + } + } + } #ifdef ENABLE_PF - if (c->c2.to_tun.len && !pf_addr_test(c, &dest, "tun_dest_addr")) - { - msg(D_PF_DROPPED, "PF: client -> addr[%s] packet dropped by TUN packet filter", - mroute_addr_print_ex(&dest, MAPF_SHOW_ARP, &gc)); - c->c2.to_tun.len = 0; - } + if (c->c2.to_tun.len && !pf_addr_test (c, &dest, "tun_dest_addr")) + { + msg (D_PF_DROPPED, "PF: client -> addr[%s] packet dropped by TUN packet filter", + mroute_addr_print_ex (&dest, MAPF_SHOW_ARP, &gc)); + c->c2.to_tun.len = 0; + } #endif - } - else if (TUNNEL_TYPE(m->top.c1.tuntap) == DEV_TYPE_TAP) - { + } + else if (TUNNEL_TYPE (m->top.c1.tuntap) == DEV_TYPE_TAP) + { #ifdef ENABLE_PF - struct mroute_addr edest; - mroute_addr_reset(&edest); + struct mroute_addr edest; + mroute_addr_reset (&edest); #endif - /* extract packet source and dest addresses */ - mroute_flags = mroute_extract_addr_from_packet(&src, - &dest, - NULL, + /* extract packet source and dest addresses */ + mroute_flags = mroute_extract_addr_from_packet (&src, + &dest, + NULL, #ifdef ENABLE_PF - &edest, + &edest, #else - NULL, + NULL, #endif - &c->c2.to_tun, - DEV_TYPE_TAP); - - if (mroute_flags & MROUTE_EXTRACT_SUCCEEDED) - { - if (multi_learn_addr(m, m->pending, &src, 0) == m->pending) - { - /* check for broadcast */ - if (m->enable_c2c) - { - if (mroute_flags & (MROUTE_EXTRACT_BCAST|MROUTE_EXTRACT_MCAST)) - { - multi_bcast(m, &c->c2.to_tun, m->pending, NULL); - } - else /* try client-to-client routing */ - { - mi = multi_get_instance_by_virtual_addr(m, &dest, false); - - /* if dest addr is a known client, route to it */ - if (mi) - { + &c->c2.to_tun, + DEV_TYPE_TAP); + + if (mroute_flags & MROUTE_EXTRACT_SUCCEEDED) + { + if (multi_learn_addr (m, m->pending, &src, 0) == m->pending) + { + /* check for broadcast */ + if (m->enable_c2c) + { + if (mroute_flags & (MROUTE_EXTRACT_BCAST|MROUTE_EXTRACT_MCAST)) + { + multi_bcast (m, &c->c2.to_tun, m->pending, NULL); + } + else /* try client-to-client routing */ + { + mi = multi_get_instance_by_virtual_addr (m, &dest, false); + + /* if dest addr is a known client, route to it */ + if (mi) + { #ifdef ENABLE_PF - if (!pf_c2c_test(c, &mi->context, "tap_c2c")) - { - msg(D_PF_DROPPED, "PF: client -> client[%s] packet dropped by TAP packet filter", - mi_prefix(mi)); - } - else + if (!pf_c2c_test (c, &mi->context, "tap_c2c")) + { + msg (D_PF_DROPPED, "PF: client -> client[%s] packet dropped by TAP packet filter", + mi_prefix (mi)); + } + else #endif - { - multi_unicast(m, &c->c2.to_tun, mi); - register_activity(c, BLEN(&c->c2.to_tun)); - } - c->c2.to_tun.len = 0; - } - } - } + { + multi_unicast (m, &c->c2.to_tun, mi); + register_activity (c, BLEN(&c->c2.to_tun)); + } + c->c2.to_tun.len = 0; + } + } + } #ifdef ENABLE_PF - if (c->c2.to_tun.len && !pf_addr_test(c, &edest, "tap_dest_addr")) - { - msg(D_PF_DROPPED, "PF: client -> addr[%s] packet dropped by TAP packet filter", - mroute_addr_print_ex(&edest, MAPF_SHOW_ARP, &gc)); - c->c2.to_tun.len = 0; - } + if (c->c2.to_tun.len && !pf_addr_test (c, &edest, "tap_dest_addr")) + { + msg (D_PF_DROPPED, "PF: client -> addr[%s] packet dropped by TAP packet filter", + mroute_addr_print_ex (&edest, MAPF_SHOW_ARP, &gc)); + c->c2.to_tun.len = 0; + } #endif - } - else - { - msg(D_MULTI_DROPPED, "MULTI: bad source address from client [%s], packet dropped", - mroute_addr_print(&src, &gc)); - c->c2.to_tun.len = 0; - } - } - else - { - c->c2.to_tun.len = 0; - } - } - } + } + else + { + msg (D_MULTI_DROPPED, "MULTI: bad source address from client [%s], packet dropped", + mroute_addr_print (&src, &gc)); + c->c2.to_tun.len = 0; + } + } + else + { + c->c2.to_tun.len = 0; + } + } + } - /* postprocess and set wakeup */ - ret = multi_process_post(m, m->pending, mpp_flags); + /* postprocess and set wakeup */ + ret = multi_process_post (m, m->pending, mpp_flags); - clear_prefix(); + clear_prefix (); } - gc_free(&gc); - return ret; + gc_free (&gc); + return ret; } /* @@ -2716,117 +2562,115 @@ multi_process_incoming_link(struct multi_context *m, struct multi_instance *inst * i.e. server -> client direction. */ bool -multi_process_incoming_tun(struct multi_context *m, const unsigned int mpp_flags) +multi_process_incoming_tun (struct multi_context *m, const unsigned int mpp_flags) { - struct gc_arena gc = gc_new(); - bool ret = true; + struct gc_arena gc = gc_new (); + bool ret = true; - if (BLEN(&m->top.c2.buf) > 0) + if (BLEN (&m->top.c2.buf) > 0) { - unsigned int mroute_flags; - struct mroute_addr src, dest; - const int dev_type = TUNNEL_TYPE(m->top.c1.tuntap); + unsigned int mroute_flags; + struct mroute_addr src, dest; + const int dev_type = TUNNEL_TYPE (m->top.c1.tuntap); #ifdef ENABLE_PF - struct mroute_addr esrc, *e1, *e2; - if (dev_type == DEV_TYPE_TUN) - { - e1 = NULL; - e2 = &src; - } - else - { - e1 = e2 = &esrc; - mroute_addr_reset(&esrc); - } + struct mroute_addr esrc, *e1, *e2; + if (dev_type == DEV_TYPE_TUN) + { + e1 = NULL; + e2 = &src; + } + else + { + e1 = e2 = &esrc; + mroute_addr_reset (&esrc); + } #endif #ifdef MULTI_DEBUG_EVENT_LOOP - printf("TUN -> TCP/UDP [%d]\n", BLEN(&m->top.c2.buf)); + printf ("TUN -> TCP/UDP [%d]\n", BLEN (&m->top.c2.buf)); #endif - if (m->pending) - { - return true; - } + if (m->pending) + return true; - /* - * Route an incoming tun/tap packet to - * the appropriate multi_instance object. - */ + /* + * Route an incoming tun/tap packet to + * the appropriate multi_instance object. + */ - mroute_flags = mroute_extract_addr_from_packet(&src, - &dest, + mroute_flags = mroute_extract_addr_from_packet (&src, + &dest, #ifdef ENABLE_PF - e1, + e1, #else - NULL, + NULL, #endif - NULL, - &m->top.c2.buf, - dev_type); - - if (mroute_flags & MROUTE_EXTRACT_SUCCEEDED) - { - struct context *c; - - /* broadcast or multicast dest addr? */ - if (mroute_flags & (MROUTE_EXTRACT_BCAST|MROUTE_EXTRACT_MCAST)) - { - /* for now, treat multicast as broadcast */ + NULL, + &m->top.c2.buf, + dev_type); + + if (mroute_flags & MROUTE_EXTRACT_SUCCEEDED) + { + struct context *c; + + /* broadcast or multicast dest addr? */ + if (mroute_flags & (MROUTE_EXTRACT_BCAST|MROUTE_EXTRACT_MCAST)) + { + /* for now, treat multicast as broadcast */ #ifdef ENABLE_PF - multi_bcast(m, &m->top.c2.buf, NULL, e2); + multi_bcast (m, &m->top.c2.buf, NULL, e2); #else - multi_bcast(m, &m->top.c2.buf, NULL, NULL); + multi_bcast (m, &m->top.c2.buf, NULL, NULL); #endif - } - else - { - multi_set_pending(m, multi_get_instance_by_virtual_addr(m, &dest, dev_type == DEV_TYPE_TUN)); - - if (m->pending) - { - /* get instance context */ - c = &m->pending->context; - - set_prefix(m->pending); + } + else + { + multi_set_pending (m, multi_get_instance_by_virtual_addr (m, &dest, dev_type == DEV_TYPE_TUN)); + + if (m->pending) + { + /* get instance context */ + c = &m->pending->context; + + set_prefix (m->pending); #ifdef ENABLE_PF - if (!pf_addr_test(c, e2, "tun_tap_src_addr")) - { - msg(D_PF_DROPPED, "PF: addr[%s] -> client packet dropped by packet filter", - mroute_addr_print_ex(&src, MAPF_SHOW_ARP, &gc)); - buf_reset_len(&c->c2.buf); - } - else + if (!pf_addr_test (c, e2, "tun_tap_src_addr")) + { + msg (D_PF_DROPPED, "PF: addr[%s] -> client packet dropped by packet filter", + mroute_addr_print_ex (&src, MAPF_SHOW_ARP, &gc)); + buf_reset_len (&c->c2.buf); + } + else #endif - { - if (multi_output_queue_ready(m, m->pending)) - { - /* transfer packet pointer from top-level context buffer to instance */ - c->c2.buf = m->top.c2.buf; - } - else - { - /* drop packet */ - msg(D_MULTI_DROPPED, "MULTI: packet dropped due to output saturation (multi_process_incoming_tun)"); - buf_reset_len(&c->c2.buf); - } - } - - /* encrypt in instance context */ - process_incoming_tun(c); - - /* postprocess and set wakeup */ - ret = multi_process_post(m, m->pending, mpp_flags); - - clear_prefix(); - } - } - } - } - gc_free(&gc); - return ret; + { + if (multi_output_queue_ready (m, m->pending)) + { + /* transfer packet pointer from top-level context buffer to instance */ + c->c2.buf = m->top.c2.buf; + } + else + { + /* drop packet */ + msg (D_MULTI_DROPPED, "MULTI: packet dropped due to output saturation (multi_process_incoming_tun)"); + buf_reset_len (&c->c2.buf); + } + } + + /* encrypt in instance context */ + process_incoming_tun (c); + + /* postprocess and set wakeup */ + ret = multi_process_post (m, m->pending, mpp_flags); + + clear_prefix (); + } + } + } + } + gc_free (&gc); + return ret; } /* @@ -2834,32 +2678,30 @@ multi_process_incoming_tun(struct multi_context *m, const unsigned int mpp_flags * queue. */ struct multi_instance * -multi_get_queue(struct mbuf_set *ms) +multi_get_queue (struct mbuf_set *ms) { - struct mbuf_item item; + struct mbuf_item item; - if (mbuf_extract_item(ms, &item)) /* cleartext IP packet */ + if (mbuf_extract_item (ms, &item)) /* cleartext IP packet */ { - unsigned int pip_flags = PIPV4_PASSTOS; + unsigned int pip_flags = PIPV4_PASSTOS; - set_prefix(item.instance); - item.instance->context.c2.buf = item.buffer->buf; - if (item.buffer->flags & MF_UNICAST) /* --mssfix doesn't make sense for broadcast or multicast */ - { - pip_flags |= PIP_MSSFIX; - } - process_ip_header(&item.instance->context, pip_flags, &item.instance->context.c2.buf); - encrypt_sign(&item.instance->context, true); - mbuf_free_buf(item.buffer); + set_prefix (item.instance); + item.instance->context.c2.buf = item.buffer->buf; + if (item.buffer->flags & MF_UNICAST) /* --mssfix doesn't make sense for broadcast or multicast */ + pip_flags |= PIP_MSSFIX; + process_ip_header (&item.instance->context, pip_flags, &item.instance->context.c2.buf); + encrypt_sign (&item.instance->context, true); + mbuf_free_buf (item.buffer); - dmsg(D_MULTI_DEBUG, "MULTI: C2C/MCAST/BCAST"); + dmsg (D_MULTI_DEBUG, "MULTI: C2C/MCAST/BCAST"); - clear_prefix(); - return item.instance; + clear_prefix (); + return item.instance; } - else + else { - return NULL; + return NULL; } } @@ -2868,52 +2710,44 @@ multi_get_queue(struct mbuf_set *ms) * client instance object needs timer-based service. */ bool -multi_process_timeout(struct multi_context *m, const unsigned int mpp_flags) +multi_process_timeout (struct multi_context *m, const unsigned int mpp_flags) { - bool ret = true; + bool ret = true; #ifdef MULTI_DEBUG_EVENT_LOOP - printf("%s -> TIMEOUT\n", id(m->earliest_wakeup)); + printf ("%s -> TIMEOUT\n", id(m->earliest_wakeup)); #endif - /* instance marked for wakeup? */ - if (m->earliest_wakeup) + /* instance marked for wakeup? */ + if (m->earliest_wakeup) { - if (m->earliest_wakeup == (struct multi_instance *)&m->deferred_shutdown_signal) - { - schedule_remove_entry(m->schedule, (struct schedule_entry *) &m->deferred_shutdown_signal); - throw_signal(m->deferred_shutdown_signal.signal_received); - } - else - { - set_prefix(m->earliest_wakeup); - ret = multi_process_post(m, m->earliest_wakeup, mpp_flags); - clear_prefix(); - } - m->earliest_wakeup = NULL; + set_prefix (m->earliest_wakeup); + ret = multi_process_post (m, m->earliest_wakeup, mpp_flags); + m->earliest_wakeup = NULL; + clear_prefix (); } - return ret; + return ret; } /* * Drop a TUN/TAP outgoing packet.. */ void -multi_process_drop_outgoing_tun(struct multi_context *m, const unsigned int mpp_flags) +multi_process_drop_outgoing_tun (struct multi_context *m, const unsigned int mpp_flags) { - struct multi_instance *mi = m->pending; + struct multi_instance *mi = m->pending; - ASSERT(mi); + ASSERT (mi); - set_prefix(mi); + set_prefix (mi); - msg(D_MULTI_ERRORS, "MULTI: Outgoing TUN queue full, dropped packet len=%d", - mi->context.c2.to_tun.len); + msg (D_MULTI_ERRORS, "MULTI: Outgoing TUN queue full, dropped packet len=%d", + mi->context.c2.to_tun.len); - buf_reset(&mi->context.c2.to_tun); + buf_reset (&mi->context.c2.to_tun); - multi_process_post(m, mi, mpp_flags); - clear_prefix(); + multi_process_post (m, mi, mpp_flags); + clear_prefix (); } /* @@ -2921,13 +2755,13 @@ multi_process_drop_outgoing_tun(struct multi_context *m, const unsigned int mpp_ */ void -route_quota_exceeded(const struct multi_context *m, const struct multi_instance *mi) +route_quota_exceeded (const struct multi_context *m, const struct multi_instance *mi) { - struct gc_arena gc = gc_new(); - msg(D_ROUTE_QUOTA, "MULTI ROUTE: route quota (%d) exceeded for %s (see --max-routes-per-client option)", - mi->context.options.max_routes_per_client, - multi_instance_string(mi, false, &gc)); - gc_free(&gc); + struct gc_arena gc = gc_new (); + msg (D_ROUTE_QUOTA, "MULTI ROUTE: route quota (%d) exceeded for %s (see --max-routes-per-client option)", + mi->context.options.max_routes_per_client, + multi_instance_string (mi, false, &gc)); + gc_free (&gc); } #ifdef ENABLE_DEBUG @@ -2935,22 +2769,22 @@ route_quota_exceeded(const struct multi_context *m, const struct multi_instance * Flood clients with random packets */ static void -gremlin_flood_clients(struct multi_context *m) +gremlin_flood_clients (struct multi_context *m) { - const int level = GREMLIN_PACKET_FLOOD_LEVEL(m->top.options.gremlin); - if (level) + const int level = GREMLIN_PACKET_FLOOD_LEVEL (m->top.options.gremlin); + if (level) { - struct gc_arena gc = gc_new(); - struct buffer buf = alloc_buf_gc(BUF_SIZE(&m->top.c2.frame), &gc); - struct packet_flood_parms parm = get_packet_flood_parms(level); - int i; + struct gc_arena gc = gc_new (); + struct buffer buf = alloc_buf_gc (BUF_SIZE (&m->top.c2.frame), &gc); + struct packet_flood_parms parm = get_packet_flood_parms (level); + int i; - ASSERT(buf_init(&buf, FRAME_HEADROOM(&m->top.c2.frame))); - parm.packet_size = min_int(parm.packet_size, MAX_RW_SIZE_TUN(&m->top.c2.frame)); + ASSERT (buf_init (&buf, FRAME_HEADROOM (&m->top.c2.frame))); + parm.packet_size = min_int (parm.packet_size, MAX_RW_SIZE_TUN (&m->top.c2.frame)); - msg(D_GREMLIN, "GREMLIN_FLOOD_CLIENTS: flooding clients with %d packets of size %d", - parm.n_packets, - parm.packet_size); + msg (D_GREMLIN, "GREMLIN_FLOOD_CLIENTS: flooding clients with %d packets of size %d", + parm.n_packets, + parm.packet_size); for (i = 0; i < parm.packet_size; ++i) { @@ -2962,105 +2796,61 @@ gremlin_flood_clients(struct multi_context *m) multi_bcast(m, &buf, NULL, NULL); } - gc_free(&gc); + gc_free (&gc); } } -#endif /* ifdef ENABLE_DEBUG */ +#endif static bool stale_route_check_trigger(struct multi_context *m) { - struct timeval null; - CLEAR(null); - return event_timeout_trigger(&m->stale_routes_check_et, &null, ETT_DEFAULT); + struct timeval null; + CLEAR (null); + return event_timeout_trigger (&m->stale_routes_check_et, &null, ETT_DEFAULT); } /* * Process timers in the top-level context */ void -multi_process_per_second_timers_dowork(struct multi_context *m) +multi_process_per_second_timers_dowork (struct multi_context *m) { - /* possibly reap instances/routes in vhash */ - multi_reap_process(m); + /* possibly reap instances/routes in vhash */ + multi_reap_process (m); - /* possibly print to status log */ - if (m->top.c1.status_output) + /* possibly print to status log */ + if (m->top.c1.status_output) { - if (status_trigger(m->top.c1.status_output)) - { - multi_print_status(m, m->top.c1.status_output, m->status_file_version); - } + if (status_trigger (m->top.c1.status_output)) + multi_print_status (m, m->top.c1.status_output, m->status_file_version); } - /* possibly flush ifconfig-pool file */ - multi_ifconfig_pool_persist(m, false); + /* possibly flush ifconfig-pool file */ + multi_ifconfig_pool_persist (m, false); #ifdef ENABLE_DEBUG - gremlin_flood_clients(m); + gremlin_flood_clients (m); #endif - /* Should we check for stale routes? */ - if (m->top.options.stale_routes_check_interval && stale_route_check_trigger(m)) - { - check_stale_routes(m); - } + /* Should we check for stale routes? */ + if (m->top.options.stale_routes_check_interval && stale_route_check_trigger (m)) + check_stale_routes (m); } void -multi_top_init(struct multi_context *m, const struct context *top) +multi_top_init (struct multi_context *m, const struct context *top, const bool alloc_buffers) { - inherit_context_top(&m->top, top); - m->top.c2.buffers = init_context_buffers(&top->c2.frame); + inherit_context_top (&m->top, top); + m->top.c2.buffers = NULL; + if (alloc_buffers) + m->top.c2.buffers = init_context_buffers (&top->c2.frame); } void -multi_top_free(struct multi_context *m) +multi_top_free (struct multi_context *m) { - close_context(&m->top, -1, CC_GC_FREE); - free_context_buffers(m->top.c2.buffers); -} - -static bool -is_exit_restart(int sig) -{ - return (sig == SIGUSR1 || sig == SIGTERM || sig == SIGHUP || sig == SIGINT); -} - -static void -multi_push_restart_schedule_exit(struct multi_context *m, bool next_server) -{ - struct hash_iterator hi; - struct hash_element *he; - struct timeval tv; - - /* tell all clients to restart */ - hash_iterator_init(m->iter, &hi); - while ((he = hash_iterator_next(&hi))) - { - struct multi_instance *mi = (struct multi_instance *) he->value; - if (!mi->halt) - { - send_control_channel_string(&mi->context, next_server ? "RESTART,[N]" : "RESTART", D_PUSH); - multi_schedule_context_wakeup(m, mi); - } - } - hash_iterator_free(&hi); - - /* reschedule signal */ - ASSERT(!openvpn_gettimeofday(&m->deferred_shutdown_signal.wakeup, NULL)); - tv.tv_sec = 2; - tv.tv_usec = 0; - tv_add(&m->deferred_shutdown_signal.wakeup, &tv); - - m->deferred_shutdown_signal.signal_received = m->top.sig->signal_received; - - schedule_add_entry(m->schedule, - (struct schedule_entry *) &m->deferred_shutdown_signal, - &m->deferred_shutdown_signal.wakeup, - compute_wakeup_sigma(&m->deferred_shutdown_signal.wakeup)); - - m->top.sig->signal_received = 0; + close_context (&m->top, -1, CC_GC_FREE); + free_context_buffers (m->top.c2.buffers); } /* @@ -3068,25 +2858,17 @@ multi_push_restart_schedule_exit(struct multi_context *m, bool next_server) * false if it should continue. */ bool -multi_process_signal(struct multi_context *m) +multi_process_signal (struct multi_context *m) { - if (m->top.sig->signal_received == SIGUSR2) - { - struct status_output *so = status_open(NULL, 0, M_INFO, NULL, 0); - multi_print_status(m, so, m->status_file_version); - status_close(so); - m->top.sig->signal_received = 0; - return false; - } - else if (proto_is_dgram(m->top.options.ce.proto) - && is_exit_restart(m->top.sig->signal_received) - && (m->deferred_shutdown_signal.signal_received == 0) - && m->top.options.ce.explicit_exit_notification != 0) + if (m->top.sig->signal_received == SIGUSR2) { - multi_push_restart_schedule_exit(m, m->top.options.ce.explicit_exit_notification == 2); - return false; + struct status_output *so = status_open (NULL, 0, M_INFO, NULL, 0); + multi_print_status (m, so, m->status_file_version); + status_close (so); + m->top.sig->signal_received = 0; + return false; } - return true; + return true; } /* @@ -3094,20 +2876,20 @@ multi_process_signal(struct multi_context *m) * reception of a soft signal. */ void -multi_close_instance_on_signal(struct multi_context *m, struct multi_instance *mi) +multi_close_instance_on_signal (struct multi_context *m, struct multi_instance *mi) { - remap_signal(&mi->context); - set_prefix(mi); - print_signal(mi->context.sig, "client-instance", D_MULTI_LOW); - clear_prefix(); - multi_close_instance(m, mi, false); + remap_signal (&mi->context); + set_prefix (mi); + print_signal (mi->context.sig, "client-instance", D_MULTI_LOW); + clear_prefix (); + multi_close_instance (m, mi, false); } static void -multi_signal_instance(struct multi_context *m, struct multi_instance *mi, const int sig) +multi_signal_instance (struct multi_context *m, struct multi_instance *mi, const int sig) { - mi->context.sig->signal_received = sig; - multi_close_instance_on_signal(m, mi); + mi->context.sig->signal_received = sig; + multi_close_instance_on_signal (m, mi); } /* @@ -3117,268 +2899,244 @@ multi_signal_instance(struct multi_context *m, struct multi_instance *mi, const #ifdef ENABLE_MANAGEMENT static void -management_callback_status(void *arg, const int version, struct status_output *so) +management_callback_status (void *arg, const int version, struct status_output *so) { - struct multi_context *m = (struct multi_context *) arg; + struct multi_context *m = (struct multi_context *) arg; - if (!version) - { - multi_print_status(m, so, m->status_file_version); - } - else - { - multi_print_status(m, so, version); - } + if (!version) + multi_print_status (m, so, m->status_file_version); + else + multi_print_status (m, so, version); } static int -management_callback_n_clients(void *arg) +management_callback_n_clients (void *arg) { - struct multi_context *m = (struct multi_context *) arg; - return m->n_clients; + struct multi_context *m = (struct multi_context *) arg; + return m->n_clients; } static int -management_callback_kill_by_cn(void *arg, const char *del_cn) +management_callback_kill_by_cn (void *arg, const char *del_cn) { - struct multi_context *m = (struct multi_context *) arg; - struct hash_iterator hi; - struct hash_element *he; - int count = 0; + struct multi_context *m = (struct multi_context *) arg; + struct hash_iterator hi; + struct hash_element *he; + int count = 0; - hash_iterator_init(m->iter, &hi); - while ((he = hash_iterator_next(&hi))) + hash_iterator_init (m->iter, &hi); + while ((he = hash_iterator_next (&hi))) { - struct multi_instance *mi = (struct multi_instance *) he->value; - if (!mi->halt) - { - const char *cn = tls_common_name(mi->context.c2.tls_multi, false); - if (cn && !strcmp(cn, del_cn)) - { - multi_signal_instance(m, mi, SIGTERM); - ++count; - } - } + struct multi_instance *mi = (struct multi_instance *) he->value; + if (!mi->halt) + { + const char *cn = tls_common_name (mi->context.c2.tls_multi, false); + if (cn && !strcmp (cn, del_cn)) + { + multi_signal_instance (m, mi, SIGTERM); + ++count; + } + } } - hash_iterator_free(&hi); - return count; + hash_iterator_free (&hi); + return count; } static int -management_callback_kill_by_addr(void *arg, const in_addr_t addr, const int port) -{ - struct multi_context *m = (struct multi_context *) arg; - struct hash_iterator hi; - struct hash_element *he; - struct openvpn_sockaddr saddr; - struct mroute_addr maddr; - int count = 0; - - CLEAR(saddr); - saddr.addr.in4.sin_family = AF_INET; - saddr.addr.in4.sin_addr.s_addr = htonl(addr); - saddr.addr.in4.sin_port = htons(port); - if (mroute_extract_openvpn_sockaddr(&maddr, &saddr, true)) - { - hash_iterator_init(m->iter, &hi); - while ((he = hash_iterator_next(&hi))) - { - struct multi_instance *mi = (struct multi_instance *) he->value; - if (!mi->halt && mroute_addr_equal(&maddr, &mi->real)) - { - multi_signal_instance(m, mi, SIGTERM); - ++count; - } - } - hash_iterator_free(&hi); - } - return count; +management_callback_kill_by_addr (void *arg, const in_addr_t addr, const int port) +{ + struct multi_context *m = (struct multi_context *) arg; + struct hash_iterator hi; + struct hash_element *he; + struct openvpn_sockaddr saddr; + struct mroute_addr maddr; + int count = 0; + + CLEAR (saddr); + saddr.addr.in4.sin_family = AF_INET; + saddr.addr.in4.sin_addr.s_addr = htonl (addr); + saddr.addr.in4.sin_port = htons (port); + if (mroute_extract_openvpn_sockaddr (&maddr, &saddr, true)) + { + hash_iterator_init (m->iter, &hi); + while ((he = hash_iterator_next (&hi))) + { + struct multi_instance *mi = (struct multi_instance *) he->value; + if (!mi->halt && mroute_addr_equal (&maddr, &mi->real)) + { + multi_signal_instance (m, mi, SIGTERM); + ++count; + } + } + hash_iterator_free (&hi); + } + return count; } static void -management_delete_event(void *arg, event_t event) +management_delete_event (void *arg, event_t event) { - struct multi_context *m = (struct multi_context *) arg; - if (m->mtcp) - { - multi_tcp_delete_event(m->mtcp, event); - } + struct multi_context *m = (struct multi_context *) arg; + if (m->mtcp) + multi_tcp_delete_event (m->mtcp, event); } -#endif /* ifdef ENABLE_MANAGEMENT */ +#endif #ifdef MANAGEMENT_DEF_AUTH static struct multi_instance * -lookup_by_cid(struct multi_context *m, const unsigned long cid) +lookup_by_cid (struct multi_context *m, const unsigned long cid) { - if (m) + if (m) { - struct multi_instance *mi = (struct multi_instance *) hash_lookup(m->cid_hash, &cid); - if (mi && !mi->halt) - { - return mi; - } + struct multi_instance *mi = (struct multi_instance *) hash_lookup (m->cid_hash, &cid); + if (mi && !mi->halt) + return mi; } - return NULL; + return NULL; } static bool -management_kill_by_cid(void *arg, const unsigned long cid, const char *kill_msg) +management_kill_by_cid (void *arg, const unsigned long cid, const char *kill_msg) { - struct multi_context *m = (struct multi_context *) arg; - struct multi_instance *mi = lookup_by_cid(m, cid); - if (mi) - { - send_restart(&mi->context, kill_msg); /* was: multi_signal_instance (m, mi, SIGTERM); */ - multi_schedule_context_wakeup(m, mi); - return true; - } - else + struct multi_context *m = (struct multi_context *) arg; + struct multi_instance *mi = lookup_by_cid (m, cid); + if (mi) { - return false; + send_restart (&mi->context, kill_msg); /* was: multi_signal_instance (m, mi, SIGTERM); */ + multi_schedule_context_wakeup(m, mi); + return true; } + else + return false; } static bool -management_client_auth(void *arg, - const unsigned long cid, - const unsigned int mda_key_id, - const bool auth, - const char *reason, - const char *client_reason, - struct buffer_list *cc_config) /* ownership transferred */ -{ - struct multi_context *m = (struct multi_context *) arg; - struct multi_instance *mi = lookup_by_cid(m, cid); - bool cc_config_owned = true; - bool ret = false; - - if (mi) - { - ret = tls_authenticate_key(mi->context.c2.tls_multi, mda_key_id, auth, client_reason); - if (ret) - { - if (auth) - { - if (!mi->connection_established_flag) - { - set_cc_config(mi, cc_config); - cc_config_owned = false; - } - } - else - { - if (reason) - { - msg(D_MULTI_LOW, "MULTI: connection rejected: %s, CLI:%s", reason, np(client_reason)); - } - if (mi->connection_established_flag) - { - send_auth_failed(&mi->context, client_reason); /* mid-session reauth failed */ - multi_schedule_context_wakeup(m, mi); - } - } - } - } - if (cc_config_owned && cc_config) - { - buffer_list_free(cc_config); - } - return ret; +management_client_auth (void *arg, + const unsigned long cid, + const unsigned int mda_key_id, + const bool auth, + const char *reason, + const char *client_reason, + struct buffer_list *cc_config) /* ownership transferred */ +{ + struct multi_context *m = (struct multi_context *) arg; + struct multi_instance *mi = lookup_by_cid (m, cid); + bool cc_config_owned = true; + bool ret = false; + + if (mi) + { + ret = tls_authenticate_key (mi->context.c2.tls_multi, mda_key_id, auth, client_reason); + if (ret) + { + if (auth) + { + if (!mi->connection_established_flag) + { + set_cc_config (mi, cc_config); + cc_config_owned = false; + } + } + else + { + if (reason) + msg (D_MULTI_LOW, "MULTI: connection rejected: %s, CLI:%s", reason, np(client_reason)); + if (mi->connection_established_flag) + { + send_auth_failed (&mi->context, client_reason); /* mid-session reauth failed */ + multi_schedule_context_wakeup(m, mi); + } + } + } + } + if (cc_config_owned && cc_config) + buffer_list_free (cc_config); + return ret; } static char * -management_get_peer_info(void *arg, const unsigned long cid) +management_get_peer_info (void *arg, const unsigned long cid) { - struct multi_context *m = (struct multi_context *) arg; - struct multi_instance *mi = lookup_by_cid(m, cid); - char *ret = NULL; + struct multi_context *m = (struct multi_context *) arg; + struct multi_instance *mi = lookup_by_cid (m, cid); + char *ret = NULL; - if (mi) - { - ret = tls_get_peer_info(mi->context.c2.tls_multi); - } + if (mi) + ret = tls_get_peer_info (mi->context.c2.tls_multi); - return ret; + return ret; } -#endif /* ifdef MANAGEMENT_DEF_AUTH */ +#endif #ifdef MANAGEMENT_PF static bool -management_client_pf(void *arg, - const unsigned long cid, - struct buffer_list *pf_config) /* ownership transferred */ +management_client_pf (void *arg, + const unsigned long cid, + struct buffer_list *pf_config) /* ownership transferred */ { - struct multi_context *m = (struct multi_context *) arg; - struct multi_instance *mi = lookup_by_cid(m, cid); - bool ret = false; + struct multi_context *m = (struct multi_context *) arg; + struct multi_instance *mi = lookup_by_cid (m, cid); + bool ret = false; - if (mi && pf_config) - { - ret = pf_load_from_buffer_list(&mi->context, pf_config); - } + if (mi && pf_config) + ret = pf_load_from_buffer_list (&mi->context, pf_config); - if (pf_config) - { - buffer_list_free(pf_config); - } - return ret; + if (pf_config) + buffer_list_free (pf_config); + return ret; } -#endif /* ifdef MANAGEMENT_PF */ +#endif void -init_management_callback_multi(struct multi_context *m) +init_management_callback_multi (struct multi_context *m) { #ifdef ENABLE_MANAGEMENT - if (management) - { - struct management_callback cb; - CLEAR(cb); - cb.arg = m; - cb.flags = MCF_SERVER; - cb.status = management_callback_status; - cb.show_net = management_show_net_callback; - cb.kill_by_cn = management_callback_kill_by_cn; - cb.kill_by_addr = management_callback_kill_by_addr; - cb.delete_event = management_delete_event; - cb.n_clients = management_callback_n_clients; + if (management) + { + struct management_callback cb; + CLEAR (cb); + cb.arg = m; + cb.flags = MCF_SERVER; + cb.status = management_callback_status; + cb.show_net = management_show_net_callback; + cb.kill_by_cn = management_callback_kill_by_cn; + cb.kill_by_addr = management_callback_kill_by_addr; + cb.delete_event = management_delete_event; + cb.n_clients = management_callback_n_clients; #ifdef MANAGEMENT_DEF_AUTH - cb.kill_by_cid = management_kill_by_cid; - cb.client_auth = management_client_auth; - cb.get_peer_info = management_get_peer_info; + cb.kill_by_cid = management_kill_by_cid; + cb.client_auth = management_client_auth; + cb.get_peer_info = management_get_peer_info; #endif #ifdef MANAGEMENT_PF - cb.client_pf = management_client_pf; + cb.client_pf = management_client_pf; #endif - management_set_callback(management, &cb); + management_set_callback (management, &cb); } -#endif /* ifdef ENABLE_MANAGEMENT */ +#endif } void -uninit_management_callback_multi(struct multi_context *m) +uninit_management_callback_multi (struct multi_context *m) { - uninit_management_callback(); + uninit_management_callback (); } /* * Top level event loop. */ void -tunnel_server(struct context *top) +tunnel_server (struct context *top) { - ASSERT(top->options.mode == MODE_SERVER); + ASSERT (top->options.mode == MODE_SERVER); - if (proto_is_dgram(top->options.ce.proto)) - { - tunnel_server_udp(top); - } - else - { - tunnel_server_tcp(top); - } + if (proto_is_dgram(top->options.ce.proto)) + tunnel_server_udp(top); + else + tunnel_server_tcp(top); } #else /* if P2MP_SERVER */ diff --git a/src/openvpn/options.h b/src/openvpn/options.h index 01a7b267ca7..2d2f52fbc5c 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -648,6 +648,12 @@ struct options #define OPT_P_DEFAULT (~(OPT_P_INSTANCE|OPT_P_PULL_MODE)) +#if P2MP_SERVER +#define CLIENT_CONNECT_OPT_MASK (OPT_P_INSTANCE | OPT_P_INHERIT | OPT_P_PUSH | \ + OPT_P_TIMER | OPT_P_CONFIG | OPT_P_ECHO | \ + OPT_P_COMP | OPT_P_SOCKFLAGS) +#endif + #if P2MP #define PULL_DEFINED(opt) ((opt)->pull) #if P2MP_SERVER From ed4ff5f435104d221dc9152024cfe4d5ba057b59 Mon Sep 17 00:00:00 2001 From: Fabian Knittel Date: Fri, 9 Dec 2011 11:24:10 +0100 Subject: [PATCH 634/643] client-connect: Properly indent all functions This patch adds proper indentation to all new helper functions. No functional changes are performed. Nothing is moved around. Signed-off-by: Fabian Knittel --- src/openvpn/multi.c | 408 ++++++++++++++++++++++---------------------- 1 file changed, 204 insertions(+), 204 deletions(-) diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index 648fddb9537..1aa087421fb 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -1701,20 +1701,20 @@ static void multi_client_connect_early_setup (struct multi_context *m, struct multi_instance *mi) { - /* lock down the common name and cert hashes so they can't change during - future TLS renegotiations */ - tls_lock_common_name (mi->context.c2.tls_multi); - tls_lock_cert_hash_set (mi->context.c2.tls_multi); + /* lock down the common name and cert hashes so they can't change during + future TLS renegotiations */ + tls_lock_common_name (mi->context.c2.tls_multi); + tls_lock_cert_hash_set (mi->context.c2.tls_multi); - /* generate a msg() prefix for this client instance */ - generate_prefix (mi); + /* generate a msg() prefix for this client instance */ + generate_prefix (mi); - /* delete instances of previous clients with same common-name */ - if (!mi->context.options.duplicate_cn) - multi_delete_dup (m, mi); + /* delete instances of previous clients with same common-name */ + if (!mi->context.options.duplicate_cn) + multi_delete_dup (m, mi); - /* reset pool handle to null */ - mi->vaddr_handle = -1; + /* reset pool handle to null */ + mi->vaddr_handle = -1; } /* @@ -1726,16 +1726,31 @@ multi_client_connect_source_ccd (struct multi_context *m, struct multi_instance *mi, unsigned int *option_types_found) { - if (mi->context.options.client_config_dir) + if (mi->context.options.client_config_dir) + { + struct gc_arena gc = gc_new (); + const char *ccd_file; + + ccd_file = gen_path (mi->context.options.client_config_dir, + tls_common_name (mi->context.c2.tls_multi, false), + &gc); + + /* try common-name file */ + if (test_file (ccd_file)) + { + options_server_import (&mi->context.options, + ccd_file, + D_IMPORT_ERRORS|M_OPTERR, + CLIENT_CONNECT_OPT_MASK, + option_types_found, + mi->context.c2.es); + } + else /* try default file */ { - struct gc_arena gc = gc_new (); - const char *ccd_file; - ccd_file = gen_path (mi->context.options.client_config_dir, - tls_common_name (mi->context.c2.tls_multi, false), + CCD_DEFAULT, &gc); - /* try common-name file */ if (test_file (ccd_file)) { options_server_import (&mi->context.options, @@ -1745,25 +1760,10 @@ multi_client_connect_source_ccd (struct multi_context *m, option_types_found, mi->context.c2.es); } - else /* try default file */ - { - ccd_file = gen_path (mi->context.options.client_config_dir, - CCD_DEFAULT, - &gc); - - if (test_file (ccd_file)) - { - options_server_import (&mi->context.options, - ccd_file, - D_IMPORT_ERRORS|M_OPTERR, - CLIENT_CONNECT_OPT_MASK, - option_types_found, - mi->context.c2.es); - } - } - - gc_free (&gc); } + + gc_free (&gc); + } } /* @@ -1779,44 +1779,44 @@ multi_client_connect_call_plugin_v1 (struct multi_context *m, int *cc_succeeded_count) { #ifdef ENABLE_PLUGIN - ASSERT (m); - ASSERT (mi); - ASSERT (option_types_found); - ASSERT (cc_succeeded); - ASSERT (cc_succeeded_count); + ASSERT (m); + ASSERT (mi); + ASSERT (option_types_found); + ASSERT (cc_succeeded); + ASSERT (cc_succeeded_count); - if (plugin_defined (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT)) - { - int plug_ret; - struct gc_arena gc = gc_new (); - struct argv argv = argv_new (); - const char *dc_file = create_temp_file (mi->context.options.tmp_dir, "cc", &gc); + if (plugin_defined (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT)) + { + int plug_ret; + struct gc_arena gc = gc_new (); + struct argv argv = argv_new (); + const char *dc_file = create_temp_file (mi->context.options.tmp_dir, "cc", &gc); - if (!dc_file) - { - *cc_succeeded = false; - goto script_depr_failed; - } + if (!dc_file) + { + *cc_succeeded = false; + goto script_depr_failed; + } - argv_printf (&argv, "%s", dc_file); + argv_printf (&argv, "%s", dc_file); - plug_ret = plugin_call (mi->context.plugins, - OPENVPN_PLUGIN_CLIENT_CONNECT, - &argv, NULL, mi->context.c2.es); - argv_reset (&argv); - if (plug_ret != OPENVPN_PLUGIN_FUNC_SUCCESS) - { - msg (M_WARN, "WARNING: client-connect plugin call failed"); - *cc_succeeded = false; - } - else - { - multi_client_connect_post (m, mi, dc_file, option_types_found); - ++*cc_succeeded_count; - } -script_depr_failed: - gc_free (&gc); + plug_ret = plugin_call (mi->context.plugins, + OPENVPN_PLUGIN_CLIENT_CONNECT, + &argv, NULL, mi->context.c2.es); + argv_reset (&argv); + if (plug_ret != OPENVPN_PLUGIN_FUNC_SUCCESS) + { + msg (M_WARN, "WARNING: client-connect plugin call failed"); + *cc_succeeded = false; } + else + { + multi_client_connect_post (m, mi, dc_file, option_types_found); + ++*cc_succeeded_count; + } +script_depr_failed: + gc_free (&gc); + } #endif } @@ -1833,35 +1833,35 @@ multi_client_connect_call_plugin_v2 (struct multi_context *m, int *cc_succeeded_count) { #ifdef ENABLE_PLUGIN - ASSERT (m); - ASSERT (mi); - ASSERT (option_types_found); - ASSERT (cc_succeeded); - ASSERT (cc_succeeded_count); - - if (plugin_defined (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT_V2)) - { - int plug_ret; - struct plugin_return pr; + ASSERT (m); + ASSERT (mi); + ASSERT (option_types_found); + ASSERT (cc_succeeded); + ASSERT (cc_succeeded_count); - plugin_return_init (&pr); + if (plugin_defined (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT_V2)) + { + int plug_ret; + struct plugin_return pr; - plug_ret = plugin_call (mi->context.plugins, - OPENVPN_PLUGIN_CLIENT_CONNECT_V2, - NULL, &pr, mi->context.c2.es); - if (plug_ret != OPENVPN_PLUGIN_FUNC_SUCCESS) - { - msg (M_WARN, "WARNING: client-connect-v2 plugin call failed"); - *cc_succeeded = false; - } - else - { - multi_client_connect_post_plugin (m, mi, &pr, option_types_found); - ++*cc_succeeded_count; - } + plugin_return_init (&pr); - plugin_return_free (&pr); + plug_ret = plugin_call (mi->context.plugins, + OPENVPN_PLUGIN_CLIENT_CONNECT_V2, + NULL, &pr, mi->context.c2.es); + if (plug_ret != OPENVPN_PLUGIN_FUNC_SUCCESS) + { + msg (M_WARN, "WARNING: client-connect-v2 plugin call failed"); + *cc_succeeded = false; + } + else + { + multi_client_connect_post_plugin (m, mi, &pr, option_types_found); + ++*cc_succeeded_count; } + + plugin_return_free (&pr); + } #endif } @@ -1872,42 +1872,42 @@ multi_client_connect_call_script (struct multi_context *m, int *cc_succeeded, int *cc_succeeded_count) { - ASSERT (m); - ASSERT (mi); - ASSERT (option_types_found); - ASSERT (cc_succeeded); - ASSERT (cc_succeeded_count); + ASSERT (m); + ASSERT (mi); + ASSERT (option_types_found); + ASSERT (cc_succeeded); + ASSERT (cc_succeeded_count); - if (mi->context.options.client_connect_script) - { - struct gc_arena gc = gc_new (); - struct argv argv = argv_new (); - const char *dc_file; + if (mi->context.options.client_connect_script) + { + struct gc_arena gc = gc_new (); + struct argv argv = argv_new (); + const char *dc_file; - setenv_str (mi->context.c2.es, "script_type", "client-connect"); + setenv_str (mi->context.c2.es, "script_type", "client-connect"); - dc_file = create_temp_file (mi->context.options.tmp_dir, "cc", &gc); - if (!dc_file) - { - cc_succeeded = false; - goto script_failed; - } + dc_file = create_temp_file (mi->context.options.tmp_dir, "cc", &gc); + if (!dc_file) + { + cc_succeeded = false; + goto script_failed; + } - argv_printf (&argv, "%sc %s", - mi->context.options.client_connect_script, - dc_file); + argv_printf (&argv, "%sc %s", + mi->context.options.client_connect_script, + dc_file); - if (openvpn_run_script (&argv, mi->context.c2.es, 0, "--client-connect")) - { - multi_client_connect_post (m, mi, dc_file, option_types_found); - ++cc_succeeded_count; - } - else - cc_succeeded = false; -script_failed: - argv_reset (&argv); - gc_free (&gc); + if (openvpn_run_script (&argv, mi->context.c2.es, 0, "--client-connect")) + { + multi_client_connect_post (m, mi, dc_file, option_types_found); + ++cc_succeeded_count; } + else + cc_succeeded = false; +script_failed: + argv_reset (&argv); + gc_free (&gc); + } } static void @@ -1917,112 +1917,112 @@ multi_client_connect_late_setup (struct multi_context *m, int cc_succeeded, const int cc_succeeded_count) { - struct gc_arena gc = gc_new (); - ASSERT (mi->context.c1.tuntap); + struct gc_arena gc = gc_new (); + ASSERT (mi->context.c1.tuntap); + /* + * Check for "disable" directive in client-config-dir file + * or config file generated by --client-connect script. + */ + if (mi->context.options.disable) + { + msg (D_MULTI_ERRORS, "MULTI: client has been rejected due to 'disable' directive"); + cc_succeeded = false; + } + + if (cc_succeeded) + { /* - * Check for "disable" directive in client-config-dir file - * or config file generated by --client-connect script. + * Process sourced options. */ - if (mi->context.options.disable) + do_deferred_options (&mi->context, option_types_found); + + /* + * make sure we got ifconfig settings from somewhere + */ + if (!mi->context.c2.push_ifconfig_defined) { - msg (D_MULTI_ERRORS, "MULTI: client has been rejected due to 'disable' directive"); - cc_succeeded = false; + msg (D_MULTI_ERRORS, "MULTI: no dynamic or static remote --ifconfig address is available for %s", + multi_instance_string (mi, false, &gc)); } - if (cc_succeeded) + /* + * make sure that ifconfig settings comply with constraints + */ + if (!ifconfig_push_constraint_satisfied (&mi->context)) { - /* - * Process sourced options. - */ - do_deferred_options (&mi->context, option_types_found); + /* JYFIXME -- this should cause the connection to fail */ + msg (D_MULTI_ERRORS, "MULTI ERROR: primary virtual IP for %s (%s) violates tunnel network/netmask constraint (%s/%s)", + multi_instance_string (mi, false, &gc), + print_in_addr_t (mi->context.c2.push_ifconfig_local, 0, &gc), + print_in_addr_t (mi->context.options.push_ifconfig_constraint_network, 0, &gc), + print_in_addr_t (mi->context.options.push_ifconfig_constraint_netmask, 0, &gc)); + } - /* - * make sure we got ifconfig settings from somewhere - */ - if (!mi->context.c2.push_ifconfig_defined) + /* + * For routed tunnels, set up internal route to endpoint + * plus add all iroute routes. + */ + if (TUNNEL_TYPE (mi->context.c1.tuntap) == DEV_TYPE_TUN) + { + if (mi->context.c2.push_ifconfig_defined) { - msg (D_MULTI_ERRORS, "MULTI: no dynamic or static remote --ifconfig address is available for %s", - multi_instance_string (mi, false, &gc)); + multi_learn_in_addr_t (m, mi, mi->context.c2.push_ifconfig_local, -1, true); + msg (D_MULTI_LOW, "MULTI: primary virtual IP for %s: %s", + multi_instance_string (mi, false, &gc), + print_in_addr_t (mi->context.c2.push_ifconfig_local, 0, &gc)); } - /* - * make sure that ifconfig settings comply with constraints - */ - if (!ifconfig_push_constraint_satisfied (&mi->context)) + if (mi->context.c2.push_ifconfig_ipv6_defined) { - /* JYFIXME -- this should cause the connection to fail */ - msg (D_MULTI_ERRORS, "MULTI ERROR: primary virtual IP for %s (%s) violates tunnel network/netmask constraint (%s/%s)", + multi_learn_in6_addr (m, mi, mi->context.c2.push_ifconfig_ipv6_local, -1, true); + /* TODO: find out where addresses are "unlearned"!! */ + msg (D_MULTI_LOW, "MULTI: primary virtual IPv6 for %s: %s", multi_instance_string (mi, false, &gc), - print_in_addr_t (mi->context.c2.push_ifconfig_local, 0, &gc), - print_in_addr_t (mi->context.options.push_ifconfig_constraint_network, 0, &gc), - print_in_addr_t (mi->context.options.push_ifconfig_constraint_netmask, 0, &gc)); + print_in6_addr (mi->context.c2.push_ifconfig_ipv6_local, 0, &gc)); } + /* add routes locally, pointing to new client, if + --iroute options have been specified */ + multi_add_iroutes (m, mi); + /* - * For routed tunnels, set up internal route to endpoint - * plus add all iroute routes. + * iroutes represent subnets which are "owned" by a particular + * client. Therefore, do not actually push a route to a client + * if it matches one of the client's iroutes. */ - if (TUNNEL_TYPE (mi->context.c1.tuntap) == DEV_TYPE_TUN) - { - if (mi->context.c2.push_ifconfig_defined) - { - multi_learn_in_addr_t (m, mi, mi->context.c2.push_ifconfig_local, -1, true); - msg (D_MULTI_LOW, "MULTI: primary virtual IP for %s: %s", - multi_instance_string (mi, false, &gc), - print_in_addr_t (mi->context.c2.push_ifconfig_local, 0, &gc)); - } - - if (mi->context.c2.push_ifconfig_ipv6_defined) - { - multi_learn_in6_addr (m, mi, mi->context.c2.push_ifconfig_ipv6_local, -1, true); - /* TODO: find out where addresses are "unlearned"!! */ - msg (D_MULTI_LOW, "MULTI: primary virtual IPv6 for %s: %s", - multi_instance_string (mi, false, &gc), - print_in6_addr (mi->context.c2.push_ifconfig_ipv6_local, 0, &gc)); - } - - /* add routes locally, pointing to new client, if - --iroute options have been specified */ - multi_add_iroutes (m, mi); - - /* - * iroutes represent subnets which are "owned" by a particular - * client. Therefore, do not actually push a route to a client - * if it matches one of the client's iroutes. - */ - remove_iroutes_from_push_route_list (&mi->context.options); - } - else if (mi->context.options.iroutes) - { - msg (D_MULTI_ERRORS, "MULTI: --iroute options rejected for %s -- iroute only works with tun-style tunnels", - multi_instance_string (mi, false, &gc)); - } - - /* set our client's VPN endpoint for status reporting purposes */ - mi->reporting_addr = mi->context.c2.push_ifconfig_local; - mi->reporting_addr_ipv6 = mi->context.c2.push_ifconfig_ipv6_local; - - /* set context-level authentication flag */ - mi->context.c2.context_auth = CAS_SUCCEEDED; + remove_iroutes_from_push_route_list (&mi->context.options); } - else + else if (mi->context.options.iroutes) { - /* set context-level authentication flag */ - mi->context.c2.context_auth = cc_succeeded_count ? CAS_PARTIAL : CAS_FAILED; + msg (D_MULTI_ERRORS, "MULTI: --iroute options rejected for %s -- iroute only works with tun-style tunnels", + multi_instance_string (mi, false, &gc)); } - /* increment number of current authenticated clients */ - ++m->n_clients; - update_mstat_n_clients(m->n_clients); - --mi->n_clients_delta; + /* set our client's VPN endpoint for status reporting purposes */ + mi->reporting_addr = mi->context.c2.push_ifconfig_local; + mi->reporting_addr_ipv6 = mi->context.c2.push_ifconfig_ipv6_local; + + /* set context-level authentication flag */ + mi->context.c2.context_auth = CAS_SUCCEEDED; + } + else + { + /* set context-level authentication flag */ + mi->context.c2.context_auth = cc_succeeded_count ? CAS_PARTIAL : CAS_FAILED; + } + + /* increment number of current authenticated clients */ + ++m->n_clients; + update_mstat_n_clients(m->n_clients); + --mi->n_clients_delta; #ifdef MANAGEMENT_DEF_AUTH - if (management) - management_connection_established (management, &mi->context.c2.mda_context, mi->context.c2.es); + if (management) + management_connection_established (management, &mi->context.c2.mda_context, mi->context.c2.es); #endif - gc_free (&gc); + gc_free (&gc); } From 189a38f3e28b4f2925303628fe35752fa294d2aa Mon Sep 17 00:00:00 2001 From: Fabian Knittel Date: Thu, 29 Apr 2010 12:28:35 +0200 Subject: [PATCH 635/643] client-connect: Refactor multi_client_connect_source_ccd Refactor multi_client_connect_source_ccd(), so that options_server_import() (or the success path in general) is only entered in one place within the function. Signed-off-by: Fabian Knittel --- src/openvpn/multi.c | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index 1aa087421fb..d030a891710 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -1736,7 +1736,19 @@ multi_client_connect_source_ccd (struct multi_context *m, &gc); /* try common-name file */ - if (test_file (ccd_file)) + if (!test_file (ccd_file)) + ccd_file = NULL; + + if (!ccd_file) + { + ccd_file = gen_path (mi->context.options.client_config_dir, + CCD_DEFAULT, &gc); + /* try default file */ + if (!test_file (ccd_file)) + ccd_file = NULL; + } + + if (ccd_file) { options_server_import (&mi->context.options, ccd_file, @@ -1744,22 +1756,7 @@ multi_client_connect_source_ccd (struct multi_context *m, CLIENT_CONNECT_OPT_MASK, option_types_found, mi->context.c2.es); - } - else /* try default file */ - { - ccd_file = gen_path (mi->context.options.client_config_dir, - CCD_DEFAULT, - &gc); - if (test_file (ccd_file)) - { - options_server_import (&mi->context.options, - ccd_file, - D_IMPORT_ERRORS|M_OPTERR, - CLIENT_CONNECT_OPT_MASK, - option_types_found, - mi->context.c2.es); - } } gc_free (&gc); From b97f9270b9fc5284642f484909896786c9f2a30e Mon Sep 17 00:00:00 2001 From: Fabian Knittel Date: Thu, 29 Apr 2010 12:29:26 +0200 Subject: [PATCH 636/643] client-connect: Move multi_client_connect_setenv into early_setup This patch moves multi_client_connect_setenv into multi_client_connect_early_setup and makes sure that every client-connect handling function updates the virtual address selection. Background: This unifies how the client-connect handling functions work. Signed-off-by: Fabian Knittel --- src/openvpn/multi.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index d030a891710..0fdbb2a3d73 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -1650,15 +1650,6 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi multi_client_connect_source_ccd (m, mi, &option_types_found); - /* - * Select a virtual address from either --ifconfig-push in - * --client-config-dir file or --ifconfig-pool. - */ - multi_select_virtual_addr (m, mi); - - /* do --client-connect setenvs */ - multi_client_connect_setenv (m, mi); - multi_client_connect_call_plugin_v1 (m, mi, &option_types_found, &cc_succeeded, &cc_succeeded_count); @@ -1715,6 +1706,10 @@ multi_client_connect_early_setup (struct multi_context *m, /* reset pool handle to null */ mi->vaddr_handle = -1; + + /* do --client-connect setenvs */ + multi_select_virtual_addr (m, mi); + multi_client_connect_setenv (m, mi); } /* @@ -1757,6 +1752,12 @@ multi_client_connect_source_ccd (struct multi_context *m, option_types_found, mi->context.c2.es); + /* + * Select a virtual address from either --ifconfig-push in + * --client-config-dir file or --ifconfig-pool. + */ + multi_select_virtual_addr (m, mi); + multi_set_virtual_addr_env (m, mi); } gc_free (&gc); From 06a5816bcb1ce1c856e56647cf56c765deec9ff3 Mon Sep 17 00:00:00 2001 From: Fabian Knittel Date: Fri, 9 Dec 2011 11:28:00 +0100 Subject: [PATCH 637/643] client-connect: Refactor to use return values instead of modifying a passed-in flag This patch changes the way the client-connect helper functions communicate with the main function. Instead of updating cc_succeeded and cc_succeeded_count, they now return either CC_RET_SUCCEEDED, CC_RET_FAILED or CC_RET_SKIPPED. In addition, the client-connect helpers are now called in completely identical ways. This is in preparation of handling the helpers as simple call-backs. Signed-off-by: Fabian Knittel --- src/openvpn/multi.c | 122 ++++++++++++++++++++++++++------------------ src/openvpn/multi.h | 11 +++- 2 files changed, 82 insertions(+), 51 deletions(-) diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index 0fdbb2a3d73..3dbb9289e1e 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -1534,13 +1534,12 @@ multi_client_connect_post_plugin (struct multi_context *m, /* * Called to load management-derived client-connect config */ -static void +static enum client_connect_return multi_client_connect_mda (struct multi_context *m, struct multi_instance *mi, - unsigned int *option_types_found, - int *cc_succeeded, - int *cc_succeeded_count) + unsigned int *option_types_found) { + enum client_connect_return ret = CC_RET_SKIPPED; #ifdef MANAGEMENT_DEF_AUTH if (mi->cc_config) { @@ -1566,9 +1565,10 @@ multi_client_connect_mda (struct multi_context *m, multi_select_virtual_addr (m, mi); multi_set_virtual_addr_env (m, mi); - ++*cc_succeeded_count; + ret = CC_RET_SUCCEEDED; } #endif + return ret; } static void @@ -1645,38 +1645,59 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi unsigned int option_types_found = 0; int cc_succeeded = true; /* client connect script status */ int cc_succeeded_count = 0; + enum client_connect_return ret; multi_client_connect_early_setup (m, mi); - multi_client_connect_source_ccd (m, mi, &option_types_found); + if (cc_succeeded) + { + ret = multi_client_connect_source_ccd (m, mi, &option_types_found); + if (ret == CC_RET_SUCCEEDED) + ++cc_succeeded_count; + else if (ret == CC_RET_FAILED) + cc_succeeded = false; + } - multi_client_connect_call_plugin_v1 (m, mi, &option_types_found, - &cc_succeeded, &cc_succeeded_count); + if (cc_succeeded) + { + ret = multi_client_connect_call_plugin_v1 (m, mi, + &option_types_found); + if (ret == CC_RET_SUCCEEDED) + ++cc_succeeded_count; + else if (ret == CC_RET_FAILED) + cc_succeeded = false; + } - multi_client_connect_call_plugin_v2 (m, mi, &option_types_found, - &cc_succeeded, &cc_succeeded_count); + if (cc_succeeded) + { + ret = multi_client_connect_call_plugin_v2 (m, mi, + &option_types_found); + if (ret == CC_RET_SUCCEEDED) + ++cc_succeeded_count; + else if (ret == CC_RET_FAILED) + cc_succeeded = false; + } - /* - * Run --client-connect script. - */ if (cc_succeeded) { - multi_client_connect_call_script (m, mi, &option_types_found, - &cc_succeeded, - &cc_succeeded_count); + ret = multi_client_connect_call_script (m, mi, &option_types_found); + if (ret == CC_RET_SUCCEEDED) + ++cc_succeeded_count; + else if (ret == CC_RET_FAILED) + cc_succeeded = false; } - /* - * Check for client-connect script left by management interface client - */ if (cc_succeeded) { - multi_client_connect_mda (m, mi, &option_types_found, - &cc_succeeded, &cc_succeeded_count); + ret = multi_client_connect_mda (m, mi, &option_types_found); + if (ret == CC_RET_SUCCEEDED) + ++cc_succeeded_count; + else if (ret == CC_RET_FAILED) + cc_succeeded = false; } - multi_client_connect_late_setup (m, mi, option_types_found, - cc_succeeded, cc_succeeded_count); + multi_client_connect_late_setup (m, mi, option_types_found, cc_succeeded, + cc_succeeded_count); /* set flag so we don't get called again */ mi->connection_established_flag = true; @@ -1716,11 +1737,13 @@ multi_client_connect_early_setup (struct multi_context *m, * Try to source a dynamic config file from the * --client-config-dir directory. */ -static void +static enum client_connect_return multi_client_connect_source_ccd (struct multi_context *m, struct multi_instance *mi, unsigned int *option_types_found) { + enum client_connect_return ret = CC_RET_SKIPPED; + if (mi->context.options.client_config_dir) { struct gc_arena gc = gc_new (); @@ -1758,10 +1781,14 @@ multi_client_connect_source_ccd (struct multi_context *m, */ multi_select_virtual_addr (m, mi); multi_set_virtual_addr_env (m, mi); + + ret = CC_RET_SUCCEEDED; } gc_free (&gc); } + + return ret; } /* @@ -1769,19 +1796,16 @@ multi_client_connect_source_ccd (struct multi_context *m, * * deprecated callback, use a file for passing back return info */ -static void +static enum client_connect_return multi_client_connect_call_plugin_v1 (struct multi_context *m, struct multi_instance *mi, - unsigned int *option_types_found, - int *cc_succeeded, - int *cc_succeeded_count) + unsigned int *option_types_found) { + enum client_connect_return ret = CC_RET_SKIPPED; #ifdef ENABLE_PLUGIN ASSERT (m); ASSERT (mi); ASSERT (option_types_found); - ASSERT (cc_succeeded); - ASSERT (cc_succeeded_count); if (plugin_defined (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT)) { @@ -1792,7 +1816,7 @@ multi_client_connect_call_plugin_v1 (struct multi_context *m, if (!dc_file) { - *cc_succeeded = false; + ret = CC_RET_FAILED; goto script_depr_failed; } @@ -1805,17 +1829,18 @@ multi_client_connect_call_plugin_v1 (struct multi_context *m, if (plug_ret != OPENVPN_PLUGIN_FUNC_SUCCESS) { msg (M_WARN, "WARNING: client-connect plugin call failed"); - *cc_succeeded = false; + ret = CC_RET_FAILED; } else { multi_client_connect_post (m, mi, dc_file, option_types_found); - ++*cc_succeeded_count; + ret = CC_RET_SUCCEEDED; } script_depr_failed: gc_free (&gc); } #endif + return ret; } /* @@ -1823,19 +1848,16 @@ multi_client_connect_call_plugin_v1 (struct multi_context *m, * * V2 callback, use a plugin_return struct for passing back return info */ -static void +static enum client_connect_return multi_client_connect_call_plugin_v2 (struct multi_context *m, struct multi_instance *mi, - unsigned int *option_types_found, - int *cc_succeeded, - int *cc_succeeded_count) + unsigned int *option_types_found) { + enum client_connect_return ret = CC_RET_SKIPPED; #ifdef ENABLE_PLUGIN ASSERT (m); ASSERT (mi); ASSERT (option_types_found); - ASSERT (cc_succeeded); - ASSERT (cc_succeeded_count); if (plugin_defined (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT_V2)) { @@ -1850,31 +1872,29 @@ multi_client_connect_call_plugin_v2 (struct multi_context *m, if (plug_ret != OPENVPN_PLUGIN_FUNC_SUCCESS) { msg (M_WARN, "WARNING: client-connect-v2 plugin call failed"); - *cc_succeeded = false; + ret = CC_RET_FAILED; } else { multi_client_connect_post_plugin (m, mi, &pr, option_types_found); - ++*cc_succeeded_count; + ret = CC_RET_SUCCEEDED; } plugin_return_free (&pr); } #endif + return ret; } -static void +static enum client_connect_return multi_client_connect_call_script (struct multi_context *m, struct multi_instance *mi, - unsigned int *option_types_found, - int *cc_succeeded, - int *cc_succeeded_count) + unsigned int *option_types_found) { + enum client_connect_return ret = CC_RET_SKIPPED; ASSERT (m); ASSERT (mi); ASSERT (option_types_found); - ASSERT (cc_succeeded); - ASSERT (cc_succeeded_count); if (mi->context.options.client_connect_script) { @@ -1887,7 +1907,7 @@ multi_client_connect_call_script (struct multi_context *m, dc_file = create_temp_file (mi->context.options.tmp_dir, "cc", &gc); if (!dc_file) { - cc_succeeded = false; + ret = CC_RET_FAILED; goto script_failed; } @@ -1898,14 +1918,16 @@ multi_client_connect_call_script (struct multi_context *m, if (openvpn_run_script (&argv, mi->context.c2.es, 0, "--client-connect")) { multi_client_connect_post (m, mi, dc_file, option_types_found); - ++cc_succeeded_count; + ret = CC_RET_SUCCEEDED; } else - cc_succeeded = false; + ret = CC_RET_FAILED; + script_failed: argv_reset (&argv); gc_free (&gc); } + return ret; } static void diff --git a/src/openvpn/multi.h b/src/openvpn/multi.h index 63afbaf0765..02624e12ab5 100644 --- a/src/openvpn/multi.h +++ b/src/openvpn/multi.h @@ -117,7 +117,6 @@ struct multi_instance { #endif }; - /** * Main OpenVPN server state structure. * @@ -191,6 +190,16 @@ struct multi_context { struct deferred_signal_schedule_entry deferred_shutdown_signal; }; +/** + * Return values used by the client connect call-back functions. + */ +enum client_connect_return +{ + CC_RET_FAILED, + CC_RET_SUCCEEDED, + CC_RET_SKIPPED +}; + /* * Host route */ From 0b2590e102455a9c1808cfbda5d5a304f87fc349 Mon Sep 17 00:00:00 2001 From: Fabian Knittel Date: Thu, 29 Apr 2010 11:46:44 +0200 Subject: [PATCH 638/643] client-connect: Refactor client-connect handling to calling a bunch of hooks in a loop This patch changes the calling of the client-connect functions into an array of hooks and a block of code that calls them in a loop. Signed-off-by: Fabian Knittel --- src/openvpn/multi.c | 57 +++++++++++++-------------------------------- 1 file changed, 16 insertions(+), 41 deletions(-) diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index 3dbb9289e1e..af9d1bd80e0 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -1642,6 +1642,18 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi { if (tls_authentication_status (mi->context.c2.tls_multi, 0) == TLS_AUTHENTICATION_SUCCEEDED) { + typedef enum client_connect_return_t (*multi_client_connect_handler)(struct multi_context *m, struct multi_instance *mi, unsigned int *option_types_found); + + multi_client_connect_handler handlers[] = { + multi_client_connect_source_ccd, + multi_client_connect_call_plugin_v1, + multi_client_connect_call_plugin_v2, + multi_client_connect_call_script, + multi_client_connect_mda, + NULL + }; + + int cur_handler = 0; unsigned int option_types_found = 0; int cc_succeeded = true; /* client connect script status */ int cc_succeeded_count = 0; @@ -1649,51 +1661,14 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi multi_client_connect_early_setup (m, mi); - if (cc_succeeded) + while (succeeded && handlers[cur_handler]) { - ret = multi_client_connect_source_ccd (m, mi, &option_types_found); + ret = handlers[cur_handler] (m, mi, &option_types_found); if (ret == CC_RET_SUCCEEDED) ++cc_succeeded_count; else if (ret == CC_RET_FAILED) - cc_succeeded = false; - } - - if (cc_succeeded) - { - ret = multi_client_connect_call_plugin_v1 (m, mi, - &option_types_found); - if (ret == CC_RET_SUCCEEDED) - ++cc_succeeded_count; - else if (ret == CC_RET_FAILED) - cc_succeeded = false; - } - - if (cc_succeeded) - { - ret = multi_client_connect_call_plugin_v2 (m, mi, - &option_types_found); - if (ret == CC_RET_SUCCEEDED) - ++cc_succeeded_count; - else if (ret == CC_RET_FAILED) - cc_succeeded = false; - } - - if (cc_succeeded) - { - ret = multi_client_connect_call_script (m, mi, &option_types_found); - if (ret == CC_RET_SUCCEEDED) - ++cc_succeeded_count; - else if (ret == CC_RET_FAILED) - cc_succeeded = false; - } - - if (cc_succeeded) - { - ret = multi_client_connect_mda (m, mi, &option_types_found); - if (ret == CC_RET_SUCCEEDED) - ++cc_succeeded_count; - else if (ret == CC_RET_FAILED) - cc_succeeded = false; + succeeded = false; + ++cur_handler; } multi_client_connect_late_setup (m, mi, option_types_found, cc_succeeded, From 1867e958921e90996adb9b0584d585c769625068 Mon Sep 17 00:00:00 2001 From: Fabian Knittel Date: Fri, 9 Dec 2011 11:54:36 +0100 Subject: [PATCH 639/643] client-connect: Add CC_RET_DEFERRED and cope with deferred client-connect This patch moves the state, that was previously tracked within the multi_connection_established() function, into struct client_connect_state. The multi_connection_established() function can now be exited and re-entered as many times as necessary - without losing the client-connect handling state. The patch also adds the new return value CC_RET_DEFERRED which indicates that the handler couldn't complete immediately, and needs to be called later. At that point multi_connection_established() will exit without indicating completion. Each client-connect handler now has an (optional) additional call-back: The call-back for handling the deferred case. If the main call-back returns CC_RET_DEFERRED, the next call to the handler will be through the deferred call-back. Signed-off-by: Fabian Knittel --- src/openvpn/multi.c | 255 +++++++++++++++++++++++++++++--------------- src/openvpn/multi.h | 18 ++++ 2 files changed, 185 insertions(+), 88 deletions(-) diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index af9d1bd80e0..d86aeb0ba6c 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -47,6 +47,9 @@ /*#define MULTI_DEBUG_EVENT_LOOP*/ +static void delete_client_connect_state (struct multi_instance *mi); + + #ifdef MULTI_DEBUG_EVENT_LOOP static const char * id (struct multi_instance *mi) @@ -587,6 +590,8 @@ multi_close_instance (struct multi_context *m, set_cc_config (mi, NULL); #endif + delete_client_connect_state (mi); + multi_client_disconnect_script (m, mi); if (mi->did_open_context) @@ -1596,94 +1601,6 @@ multi_client_connect_setenv (struct multi_context *m, gc_free (&gc); } -static void -multi_client_connect_early_setup (struct multi_context *m, - struct multi_instance *mi); -static void -multi_client_connect_source_ccd (struct multi_context *m, - struct multi_instance *mi, - unsigned int *option_types_found); -static void -multi_client_connect_call_plugin_v1 (struct multi_context *m, - struct multi_instance *mi, - unsigned int *option_types_found, - int *cc_succeeded, - int *cc_succeeded_count); -static void -multi_client_connect_call_plugin_v2 (struct multi_context *m, - struct multi_instance *mi, - unsigned int *option_types_found, - int *cc_succeeded, - int *cc_succeeded_count); -static void -multi_client_connect_call_script (struct multi_context *m, - struct multi_instance *mi, - unsigned int *option_types_found, - int *cc_succeeded, - int *cc_succeeded_count); -static void -multi_client_connect_late_setup (struct multi_context *m, - struct multi_instance *mi, - const unsigned int option_types_found, - int cc_succeeded, - const int cc_succeeded_count); - -/* - * Called as soon as the SSL/TLS connection authenticates. - * - * Instance-specific directives to be processed: - * - * iroute start-ip end-ip - * ifconfig-push local remote-netmask - * push - */ -static void -multi_connection_established (struct multi_context *m, struct multi_instance *mi) -{ - if (tls_authentication_status (mi->context.c2.tls_multi, 0) == TLS_AUTHENTICATION_SUCCEEDED) - { - typedef enum client_connect_return_t (*multi_client_connect_handler)(struct multi_context *m, struct multi_instance *mi, unsigned int *option_types_found); - - multi_client_connect_handler handlers[] = { - multi_client_connect_source_ccd, - multi_client_connect_call_plugin_v1, - multi_client_connect_call_plugin_v2, - multi_client_connect_call_script, - multi_client_connect_mda, - NULL - }; - - int cur_handler = 0; - unsigned int option_types_found = 0; - int cc_succeeded = true; /* client connect script status */ - int cc_succeeded_count = 0; - enum client_connect_return ret; - - multi_client_connect_early_setup (m, mi); - - while (succeeded && handlers[cur_handler]) - { - ret = handlers[cur_handler] (m, mi, &option_types_found); - if (ret == CC_RET_SUCCEEDED) - ++cc_succeeded_count; - else if (ret == CC_RET_FAILED) - succeeded = false; - ++cur_handler; - } - - multi_client_connect_late_setup (m, mi, option_types_found, cc_succeeded, - cc_succeeded_count); - - /* set flag so we don't get called again */ - mi->connection_established_flag = true; - } - - /* - * Reply now to client's PUSH_REQUEST query - */ - mi->context.c2.push_reply_deferred = false; -} - static void multi_client_connect_early_setup (struct multi_context *m, struct multi_instance *mi) @@ -2020,6 +1937,168 @@ multi_client_connect_late_setup (struct multi_context *m, gc_free (&gc); } +static enum client_connect_return +multi_client_connect_fail (struct multi_context *m, struct multi_instance *mi, + unsigned int *option_types_found) +{ + /* Called null call-back. This should never happen. */ + return CC_RET_FAILED; +} + +static void +new_client_connect_state (struct multi_instance *mi) +{ + ASSERT (mi); + ALLOC_OBJ_CLEAR (mi->client_connect_state, struct client_connect_state); + + mi->client_connect_state->succeeded = true; +} + +static void +delete_client_connect_state (struct multi_instance *mi) +{ + ASSERT (mi); + if (mi->client_connect_state) + { + free (mi->client_connect_state); + mi->client_connect_state = NULL; + } +} + +typedef enum client_connect_return (*client_connect_handler) + (struct multi_context *m, struct multi_instance *mi, + unsigned int *option_types_found); + +struct client_connect_handlers +{ + client_connect_handler main; + client_connect_handler deferred; +}; + +static const struct client_connect_handlers client_connect_handlers[] = { + { + main: multi_client_connect_source_ccd, + deferred: multi_client_connect_fail + }, + { + main: multi_client_connect_call_plugin_v1, + deferred: multi_client_connect_fail + }, + { + main: multi_client_connect_call_plugin_v2, + deferred: multi_client_connect_fail + }, + { + main: multi_client_connect_call_script, + deferred: multi_client_connect_fail + }, + { + main: multi_client_connect_mda, + deferred: multi_client_connect_fail + }, + { + /* End of list. */ + } +}; + +static enum client_connect_return +multi_client_handle_single (client_connect_handler handler, + struct multi_context *m, + struct multi_instance *mi) +{ + struct client_connect_state *ccs = mi->client_connect_state; + enum client_connect_return ret; + + ret = handler (m, mi, &ccs->option_types_found); + if (ret == CC_RET_SUCCEEDED) + ++ccs->succeeded_count; + else if (ret == CC_RET_FAILED) + ccs->succeeded = false; + else if (ret == CC_RET_DEFERRED) + { + /* Signal that we're deferring. */ + return ret; + } + return ret; +} + +/* + * Called as soon as the SSL/TLS connection authenticates. + * + * Instance-specific directives to be processed: + * + * iroute start-ip end-ip + * ifconfig-push local remote-netmask + * push + */ +static void +multi_connection_established (struct multi_context *m, struct multi_instance *mi) +{ + if (tls_authentication_status (mi->context.c2.tls_multi, 0) == TLS_AUTHENTICATION_SUCCEEDED) + { + struct client_connect_state *ccs = mi->client_connect_state; + enum client_connect_return ret; + + if (!ccs) + { + /* This is the first time that we run client-connect handlers + for this connection. */ + + new_client_connect_state (mi); + ccs = mi->client_connect_state; + + multi_client_connect_early_setup (m, mi); + } + else + { + /* We are returning from a deferred handler. Check whether the + handler has been completed yet. */ + + ASSERT (client_connect_handlers[ccs->cur_handler_idx].main); + ASSERT (client_connect_handlers[ccs->cur_handler_idx].deferred); + + ret = multi_client_handle_single + (client_connect_handlers[ccs->cur_handler_idx].deferred, m, + mi); + if (ret == CC_RET_DEFERRED) + return; + + /* Proceed to next handler. */ + ++ccs->cur_handler_idx; + } + + + /* Cycle through all (remaining) client-connect handlers until all + have completed, one of them fails or one of them defers. */ + while (ccs->succeeded && + client_connect_handlers[ccs->cur_handler_idx].main) + { + ret = multi_client_handle_single + (client_connect_handlers[ccs->cur_handler_idx].main, m, mi); + if (ret == CC_RET_DEFERRED) + return; + + /* Proceed to next handler. */ + ++ccs->cur_handler_idx; + } + + /* Done with all client-connect handlers now. */ + + multi_client_connect_late_setup (m, mi, ccs->option_types_found, + ccs->succeeded, ccs->succeeded_count); + + /* Clean-up. */ + delete_client_connect_state (mi); + + /* set flag so we don't get called again */ + mi->connection_established_flag = true; + } + + /* + * Reply now to client's PUSH_REQUEST query + */ + mi->context.c2.push_reply_deferred = false; +} /* * Add a mbuf buffer to a particular diff --git a/src/openvpn/multi.h b/src/openvpn/multi.h index 02624e12ab5..f59dffe02d7 100644 --- a/src/openvpn/multi.h +++ b/src/openvpn/multi.h @@ -55,6 +55,22 @@ struct multi_reap time_t last_call; }; +/** + * Detached client connection state. This is the state that is tracked while + * the client connect hooks are executed. + */ +struct client_connect_state +{ + /* Index of currently executed handler. */ + int cur_handler_idx; + /* Did all of the handlers succeed up to now? */ + bool succeeded; + /* How many handlers succeeded? */ + int succeeded_count; + /* Remember which option classes where processed for delayed option + handling. */ + unsigned int option_types_found; +}; struct deferred_signal_schedule_entry { @@ -115,6 +131,7 @@ struct multi_instance { #ifdef ENABLE_ASYNC_PUSH int inotify_watch; /* watch descriptor for acf */ #endif + struct client_connect_state *client_connect_state; }; /** @@ -197,6 +214,7 @@ enum client_connect_return { CC_RET_FAILED, CC_RET_SUCCEEDED, + CC_RET_DEFERRED, CC_RET_SKIPPED }; From 4462d47010a63f35351bcb263fb80631655c6fb1 Mon Sep 17 00:00:00 2001 From: Fabian Knittel Date: Thu, 15 Apr 2010 12:57:04 +0200 Subject: [PATCH 640/643] client-connect: Add deferred support to the client-connect script handler This patch introduces the concept of a return value file for the client-connect handlers. (This is very similar to the auth value file used during deferred authentication.) The file name is stored in the client_connect_state struct. In addition, the patch also allows the storage of the client config file name in struct client_connect_state. Both changes are used by the client-connect script handler to support deferred client-connection handling. The deferred return value file (deferred_ret_file) is passed to the actual script via the environment. If the script succeeds and writes the value for deferral into the deferred_ret_file, the handler knows to indicate deferral. Later on, the deferred handler checks whether the value of the deferred_ret_file has been updated to success or failure. Signed-off-by: Fabian Knittel --- src/openvpn/multi.c | 185 +++++++++++++++++++++++++++++++++++++++++--- src/openvpn/multi.h | 3 + 2 files changed, 177 insertions(+), 11 deletions(-) diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index d86aeb0ba6c..b38febd019c 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -1625,6 +1625,129 @@ multi_client_connect_early_setup (struct multi_context *m, multi_client_connect_setenv (m, mi); } + +static void +ccs_delete_deferred_ret_file (struct multi_instance *mi) +{ + struct client_connect_state *ccs = mi->client_connect_state; + if (ccs->deferred_ret_file) + { + setenv_del (mi->context.c2.es, "client_connect_deferred_file"); + if (!platform_unlink (ccs->deferred_ret_file)) + msg (D_MULTI_ERRORS, "MULTI: problem deleting temporary file: %s", + ccs->deferred_ret_file); + free (ccs->deferred_ret_file); + ccs->deferred_ret_file = NULL; + } +} + +static bool +ccs_gen_deferred_ret_file (struct multi_instance *mi) +{ + struct client_connect_state *ccs = mi->client_connect_state; + struct gc_arena gc = gc_new (); + const char *fn; + + if (ccs->deferred_ret_file) + ccs_delete_deferred_ret_file (mi); + + fn = create_temp_file (mi->context.options.tmp_dir, "ccr", &gc); + if (!fn) + { + gc_free (&gc); + return false; + } + ccs->deferred_ret_file = string_alloc (fn, NULL); + + setenv_str (mi->context.c2.es, "client_connect_deferred_file", + ccs->deferred_ret_file); + + gc_free (&gc); + return true; +} + +/* + * Tests whether the deferred return value file exists and returns the + * contained return value. + * + * Returns CC_RET_SKIPPED if the file doesn't exist or is empty. + * Returns CC_RET_DEFERRED, CC_RET_SUCCEEDED or CC_RET_FAILED depending on + * the value stored in the file. + */ +static enum client_connect_return +ccs_test_deferred_ret_file (struct multi_instance *mi) +{ + struct client_connect_state *ccs = mi->client_connect_state; + enum client_connect_return ret = CC_RET_SKIPPED; + FILE *fp = fopen (ccs->deferred_ret_file, "r"); + if (fp) + { + const int c = fgetc (fp); + switch (c) + { + case '0': + ret = CC_RET_FAILED; + break; + case '1': + ret = CC_RET_SUCCEEDED; + break; + case '2': + ret = CC_RET_DEFERRED; + break; + case EOF: + ret = CC_RET_SKIPPED; + break; + default: + /* We received an unknown/unexpected value. Assume failure. */ + ret = CC_RET_FAILED; + } + fclose (fp); + } + return ret; +} + + +static void +ccs_delete_config_file (struct multi_instance *mi) +{ + struct client_connect_state *ccs = mi->client_connect_state; + if (ccs->config_file) + { + setenv_del (mi->context.c2.es, "client_connect_config_file"); + if (!platform_unlink (ccs->config_file)) + msg (D_MULTI_ERRORS, "MULTI: problem deleting temporary file: %s", + ccs->config_file); + free (ccs->config_file); + ccs->config_file = NULL; + } +} + +static bool +ccs_gen_config_file (struct multi_instance *mi) +{ + struct client_connect_state *ccs = mi->client_connect_state; + struct gc_arena gc = gc_new (); + const char *fn; + + if (ccs->config_file) + ccs_delete_config_file (mi); + + fn = create_temp_file (mi->context.options.tmp_dir, "cc", &gc); + if (!fn) + { + gc_free (&gc); + return false; + } + ccs->config_file = string_alloc (fn, NULL); + + setenv_str (mi->context.c2.es, "client_connect_config_file", + ccs->config_file); + + gc_free (&gc); + return true; +} + + /* * Try to source a dynamic config file from the * --client-config-dir directory. @@ -1790,34 +1913,71 @@ multi_client_connect_call_script (struct multi_context *m, if (mi->context.options.client_connect_script) { - struct gc_arena gc = gc_new (); + struct client_connect_state *ccs = mi->client_connect_state; struct argv argv = argv_new (); - const char *dc_file; + ASSERT (ccs); setenv_str (mi->context.c2.es, "script_type", "client-connect"); - dc_file = create_temp_file (mi->context.options.tmp_dir, "cc", &gc); - if (!dc_file) + if (!ccs_gen_config_file (mi) || + !ccs_gen_deferred_ret_file (mi)) { ret = CC_RET_FAILED; - goto script_failed; + goto cleanup; } argv_printf (&argv, "%sc %s", mi->context.options.client_connect_script, - dc_file); + ccs->config_file); if (openvpn_run_script (&argv, mi->context.c2.es, 0, "--client-connect")) { - multi_client_connect_post (m, mi, dc_file, option_types_found); - ret = CC_RET_SUCCEEDED; + if (ccs_test_deferred_ret_file (mi) == CC_RET_DEFERRED) + ret = CC_RET_DEFERRED; + else + { + multi_client_connect_post (m, mi, ccs->config_file, + option_types_found); + ret = CC_RET_SUCCEEDED; + } } else ret = CC_RET_FAILED; -script_failed: +cleanup: + if (ret != CC_RET_DEFERRED) + { + ccs_delete_config_file (mi); + ccs_delete_deferred_ret_file (mi); + } + argv_reset (&argv); - gc_free (&gc); + } + return ret; +} + +static enum client_connect_return +multi_client_handle_deferred (struct multi_context *m, + struct multi_instance *mi, + unsigned int *option_types_found) +{ + struct client_connect_state *ccs = mi->client_connect_state; + enum client_connect_return ret = CC_RET_SKIPPED; + ASSERT (option_types_found); + ASSERT (ccs); + + ret = ccs_test_deferred_ret_file (mi); + + if (ret == CC_RET_SKIPPED) + /* Skipped and deferred are equivalent in this context. */ + ret = CC_RET_DEFERRED; + + if (ret != CC_RET_DEFERRED) + { + ccs_delete_deferred_ret_file (mi); + + multi_client_connect_post (m, mi, ccs->config_file, option_types_found); + ccs_delete_config_file (mi); } return ret; } @@ -1960,6 +2120,9 @@ delete_client_connect_state (struct multi_instance *mi) ASSERT (mi); if (mi->client_connect_state) { + ccs_delete_deferred_ret_file (mi); + ccs_delete_config_file (mi); + free (mi->client_connect_state); mi->client_connect_state = NULL; } @@ -1990,7 +2153,7 @@ static const struct client_connect_handlers client_connect_handlers[] = { }, { main: multi_client_connect_call_script, - deferred: multi_client_connect_fail + deferred: multi_client_handle_deferred }, { main: multi_client_connect_mda, diff --git a/src/openvpn/multi.h b/src/openvpn/multi.h index f59dffe02d7..e3da25cbcd5 100644 --- a/src/openvpn/multi.h +++ b/src/openvpn/multi.h @@ -70,6 +70,9 @@ struct client_connect_state /* Remember which option classes where processed for delayed option handling. */ unsigned int option_types_found; + + char *deferred_ret_file; + char *config_file; }; struct deferred_signal_schedule_entry From 67406dce22a3dbeb8e871f1900cd7506bc3eb69d Mon Sep 17 00:00:00 2001 From: Fabian Knittel Date: Thu, 15 Apr 2010 13:17:47 +0200 Subject: [PATCH 641/643] client-connect: Add deferred support to the client-connect plugin v1 handler Uses the infrastructure provided and used in the previous patch to provide deferral support to the v1 client-connect plugin handler as well. Signed-off-by: Fabian Knittel --- src/openvpn/multi.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index b38febd019c..f5372bac390 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -1818,6 +1818,7 @@ multi_client_connect_call_plugin_v1 (struct multi_context *m, { enum client_connect_return ret = CC_RET_SKIPPED; #ifdef ENABLE_PLUGIN + struct client_connect_state *ccs = mi->client_connect_state; ASSERT (m); ASSERT (mi); ASSERT (option_types_found); @@ -1825,34 +1826,41 @@ multi_client_connect_call_plugin_v1 (struct multi_context *m, if (plugin_defined (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT)) { int plug_ret; - struct gc_arena gc = gc_new (); struct argv argv = argv_new (); - const char *dc_file = create_temp_file (mi->context.options.tmp_dir, "cc", &gc); - if (!dc_file) + if (!ccs_gen_config_file (mi) || + !ccs_gen_deferred_ret_file (mi)) { ret = CC_RET_FAILED; - goto script_depr_failed; + goto cleanup; } - argv_printf (&argv, "%s", dc_file); + argv_printf (&argv, "%s", ccs->config_file); plug_ret = plugin_call (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT, &argv, NULL, mi->context.c2.es); argv_reset (&argv); - if (plug_ret != OPENVPN_PLUGIN_FUNC_SUCCESS) + if (plug_ret == OPENVPN_PLUGIN_FUNC_SUCCESS) + { + multi_client_connect_post (m, mi, ccs->config_file, + option_types_found); + ret = CC_RET_SUCCEEDED; + } + else if (plug_ret == OPENVPN_PLUGIN_FUNC_DEFERRED) + ret = CC_RET_DEFERRED; + else { msg (M_WARN, "WARNING: client-connect plugin call failed"); ret = CC_RET_FAILED; } - else + +cleanup: + if (ret != CC_RET_DEFERRED) { - multi_client_connect_post (m, mi, dc_file, option_types_found); - ret = CC_RET_SUCCEEDED; + ccs_delete_config_file (mi); + ccs_delete_deferred_ret_file (mi); } -script_depr_failed: - gc_free (&gc); } #endif return ret; @@ -2145,7 +2153,7 @@ static const struct client_connect_handlers client_connect_handlers[] = { }, { main: multi_client_connect_call_plugin_v1, - deferred: multi_client_connect_fail + deferred: multi_client_handle_deferred }, { main: multi_client_connect_call_plugin_v2, From ced51c656fbca94ad5c61410d6ec1c075174a011 Mon Sep 17 00:00:00 2001 From: Vladislav Yarmak Date: Wed, 15 Nov 2017 09:30:38 +0200 Subject: [PATCH 642/643] recover 2.3->2.4 changes in multi.c --- src/openvpn/multi.c | 265 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 230 insertions(+), 35 deletions(-) diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index f5372bac390..8fd34a35f30 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -5,7 +5,7 @@ * packet encryption, packet authentication, and * packet compression. * - * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -27,6 +27,11 @@ #include "config-msvc.h" #endif +#ifdef HAVE_SYS_INOTIFY_H +#include +#define INOTIFY_EVENT_BUFFER_SIZE 16384 +#endif + #include "syshead.h" #if P2MP_SERVER @@ -106,9 +111,8 @@ learn_address_script (const struct multi_context *m, if (plugin_defined (plugins, OPENVPN_PLUGIN_LEARN_ADDRESS)) { struct argv argv = argv_new (); - argv_printf (&argv, "%s %s", - op, - mroute_addr_print (addr, &gc)); + argv_parse_cmd(&argv, m->top.options.learn_address_script); + argv_printf_cat(&argv, "%s %s", op, mroute_addr_print(addr, &gc)); if (mi) argv_printf_cat (&argv, "%s", tls_common_name (mi->context.c2.tls_multi, false)); if (plugin_call (plugins, OPENVPN_PLUGIN_LEARN_ADDRESS, &argv, NULL, es) != OPENVPN_PLUGIN_FUNC_SUCCESS) @@ -245,6 +249,23 @@ cid_compare_function (const void *key1, const void *key2) #endif +#ifdef ENABLE_ASYNC_PUSH +static uint32_t +/* + * inotify watcher descriptors are used as hash value + */ +int_hash_function(const void *key, uint32_t iv) +{ + return (unsigned long)key; +} + +static bool +int_compare_function(const void *key1, const void *key2) +{ + return (unsigned long)key1 == (unsigned long)key2; +} +#endif + /* * Main initialization function, init multi_context object. */ @@ -306,6 +327,17 @@ multi_init (struct multi_context *m, struct context *t, bool tcp_mode, int threa cid_compare_function); #endif +#ifdef ENABLE_ASYNC_PUSH + /* + * Mapping between inotify watch descriptors and + * multi_instances. + */ + m->inotify_watchers = hash_init(t->options.real_hash_size, + get_random(), + int_hash_function, + int_compare_function); +#endif + /* * This is our scheduler, for time-based wakeup * events. @@ -398,6 +430,7 @@ multi_init (struct multi_context *m, struct context *t, bool tcp_mode, int threa t->options.stale_routes_check_interval, t->options.stale_routes_ageing_time); event_timeout_init (&m->stale_routes_check_et, t->options.stale_routes_check_interval, 0); } + m->deferred_shutdown_signal.signal_received = 0; } const char * @@ -516,7 +549,7 @@ multi_client_disconnect_script (struct multi_context *m, { struct argv argv = argv_new (); setenv_str (mi->context.c2.es, "script_type", "client-disconnect"); - argv_printf (&argv, "%sc", mi->context.options.client_disconnect_script); + argv_parse_cmd(&argv, mi->context.options.client_disconnect_script); openvpn_run_script (&argv, mi->context.c2.es, 0, "--client-disconnect"); argv_reset (&argv); } @@ -568,7 +601,16 @@ multi_close_instance (struct multi_context *m, } #endif +#ifdef ENABLE_ASYNC_PUSH + if (mi->inotify_watch != -1) + { + hash_remove(m->inotify_watchers, (void *) (unsigned long)mi->inotify_watch); + mi->inotify_watch = -1; + } +#endif + if (mi->context.c2.tls_multi->peer_id != MAX_PEER_ID) { m->instances[mi->context.c2.tls_multi->peer_id] = NULL; + } schedule_remove_entry (m->schedule, (struct schedule_entry *) mi); @@ -650,6 +692,11 @@ multi_uninit (struct multi_context *m) free(m->instances); +#ifdef ENABLE_ASYNC_PUSH + hash_free(m->inotify_watchers); + m->inotify_watchers = NULL; +#endif + schedule_free (m->schedule); mbuf_free (m->mbuf); ifconfig_pool_free (m->ifconfig_pool); @@ -727,6 +774,11 @@ multi_create_instance (struct multi_context *m, const struct mroute_addr *real) mi->context.c2.push_reply_deferred = true; +#ifdef ENABLE_ASYNC_PUSH + mi->context.c2.push_request_received = false; + mi->inotify_watch = -1; +#endif + if (!multi_process_post (m, mi, MPP_PRE_SELECT)) { msg (D_MULTI_ERRORS, "MULTI: signal occurred during client instance initialization"); @@ -927,11 +979,18 @@ multi_print_status (struct multi_context *m, struct status_output *so, const int } hash_iterator_free (&hi); } -#endif +#endif /* ifdef PACKET_TRUNCATION_CHECK */ status_flush (so); gc_free (&gc_top); } + +#ifdef ENABLE_ASYNC_PUSH + if (m->inotify_watchers) + { + msg(D_MULTI_DEBUG, "inotify watchers count: %d\n", hash_n_elements(m->inotify_watchers)); + } +#endif } /* @@ -1149,7 +1208,7 @@ multi_learn_in6_addr (struct multi_context *m, addr.len = 16; addr.type = MR_ADDR_IPV6; addr.netbits = 0; - memcpy( &addr.addr, &a6, sizeof(a6) ); + addr.v6.addr = a6; if (netbits >= 0) { @@ -1320,17 +1379,14 @@ multi_select_virtual_addr (struct multi_context *m, struct multi_instance *mi) mi->context.c2.push_ifconfig_defined = true; mi->context.c2.push_ifconfig_local = mi->context.options.push_ifconfig_local; mi->context.c2.push_ifconfig_remote_netmask = mi->context.options.push_ifconfig_remote_netmask; -#ifdef ENABLE_CLIENT_NAT mi->context.c2.push_ifconfig_local_alias = mi->context.options.push_ifconfig_local_alias; -#endif /* the current implementation does not allow "static IPv4, pool IPv6", * (see below) so issue a warning if that happens - don't break the * session, though, as we don't even know if this client WANTS IPv6 */ - if ( mi->context.c1.tuntap->ipv6 && - mi->context.options.ifconfig_ipv6_pool_defined && - ! mi->context.options.push_ifconfig_ipv6_defined ) + if (mi->context.options.ifconfig_ipv6_pool_defined + && !mi->context.options.push_ifconfig_ipv6_defined) { msg( M_INFO, "MULTI_sva: WARNING: if --ifconfig-push is used for IPv4, automatic IPv6 assignment from --ifconfig-ipv6-pool does not work. Use --ifconfig-ipv6-push for IPv6 then." ); } @@ -1385,7 +1441,7 @@ multi_select_virtual_addr (struct multi_context *m, struct multi_instance *mi) mi->context.c2.push_ifconfig_ipv6_remote = mi->context.c1.tuntap->local_ipv6; mi->context.c2.push_ifconfig_ipv6_netbits = - mi->context.options.ifconfig_ipv6_pool_netbits; + mi->context.options.ifconfig_ipv6_netbits; mi->context.c2.push_ifconfig_ipv6_defined = true; } } @@ -1402,8 +1458,7 @@ multi_select_virtual_addr (struct multi_context *m, struct multi_instance *mi) * way round ("dynamic IPv4, static IPv6") or "both static" makes sense * -> and so it's implemented right now */ - if ( mi->context.c1.tuntap->ipv6 && - mi->context.options.push_ifconfig_ipv6_defined ) + if (mi->context.options.push_ifconfig_ipv6_defined) { mi->context.c2.push_ifconfig_ipv6_local = mi->context.options.push_ifconfig_ipv6_local; @@ -1461,6 +1516,24 @@ multi_set_virtual_addr_env (struct multi_context *m, struct multi_instance *mi) * used for, but if we have them for IPv4, we should also have * them for IPv6, no? */ + setenv_del(mi->context.c2.es, "ifconfig_pool_local_ip6"); + setenv_del(mi->context.c2.es, "ifconfig_pool_remote_ip6"); + setenv_del(mi->context.c2.es, "ifconfig_pool_ip6_netbits"); + + if (mi->context.c2.push_ifconfig_ipv6_defined) + { + setenv_in6_addr(mi->context.c2.es, + "ifconfig_pool_remote", + &mi->context.c2.push_ifconfig_ipv6_local, + SA_SET_IF_NONZERO); + setenv_in6_addr(mi->context.c2.es, + "ifconfig_pool_local", + &mi->context.c2.push_ifconfig_ipv6_remote, + SA_SET_IF_NONZERO); + setenv_int(mi->context.c2.es, + "ifconfig_pool_ip6_netbits", + mi->context.c2.push_ifconfig_ipv6_netbits); + } } /* @@ -1934,9 +2007,8 @@ multi_client_connect_call_script (struct multi_context *m, goto cleanup; } - argv_printf (&argv, "%sc %s", - mi->context.options.client_connect_script, - ccs->config_file); + argv_parse_cmd(&argv, mi->context.options.client_connect_script); + argv_printf_cat(&argv, "%s", ccs->config_file); if (openvpn_run_script (&argv, mi->context.c2.es, 0, "--client-connect")) { @@ -2008,6 +2080,7 @@ multi_client_connect_late_setup (struct multi_context *m, { msg (D_MULTI_ERRORS, "MULTI: client has been rejected due to 'disable' directive"); cc_succeeded = false; + cc_succeeded_count = 0; } if (cc_succeeded) @@ -2085,6 +2158,14 @@ multi_client_connect_late_setup (struct multi_context *m, /* set context-level authentication flag */ mi->context.c2.context_auth = CAS_SUCCEEDED; + +#ifdef ENABLE_ASYNC_PUSH + /* authentication complete, send push reply */ + if (mi->context.c2.push_request_received) + { + process_incoming_push_request(&mi->context); + } +#endif } else { @@ -2271,6 +2352,58 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi mi->context.c2.push_reply_deferred = false; } +#ifdef ENABLE_ASYNC_PUSH +/* + * Called when inotify event is fired, which happens when acf file is closed or deleted. + * Continues authentication and sends push_reply. + */ +void +multi_process_file_closed(struct multi_context *m, const unsigned int mpp_flags) +{ + char buffer[INOTIFY_EVENT_BUFFER_SIZE]; + size_t buffer_i = 0; + int r = read(m->top.c2.inotify_fd, buffer, INOTIFY_EVENT_BUFFER_SIZE); + + while (buffer_i < r) + { + /* parse inotify events */ + struct inotify_event *pevent = (struct inotify_event *) &buffer[buffer_i]; + size_t event_size = sizeof(struct inotify_event) + pevent->len; + buffer_i += event_size; + + msg(D_MULTI_DEBUG, "MULTI: modified fd %d, mask %d", pevent->wd, pevent->mask); + + struct multi_instance *mi = hash_lookup(m->inotify_watchers, (void *) (unsigned long) pevent->wd); + + if (pevent->mask & IN_CLOSE_WRITE) + { + if (mi) + { + /* continue authentication and send push_reply */ + multi_process_post(m, mi, mpp_flags); + } + else + { + msg(D_MULTI_ERRORS, "MULTI: multi_instance not found!"); + } + } + else if (pevent->mask & IN_IGNORED) + { + /* this event is _always_ fired when watch is removed or file is deleted */ + if (mi) + { + hash_remove(m->inotify_watchers, (void *) (unsigned long) pevent->wd); + mi->inotify_watch = -1; + } + } + else + { + msg(D_MULTI_ERRORS, "MULTI: unknown mask %d", pevent->mask); + } + } +} +#endif /* ifdef ENABLE_ASYNC_PUSH */ + /* * Add a mbuf buffer to a particular * instance. @@ -2530,11 +2663,13 @@ void multi_process_float (struct multi_context* m, struct multi_instance* mi) { struct multi_instance *ex_mi = (struct multi_instance *) he->value; - const char *cn = tls_common_name (mi->context.c2.tls_multi, true); - const char *ex_cn = tls_common_name (ex_mi->context.c2.tls_multi, true); - if (cn && ex_cn && strcmp (cn, ex_cn)) + struct tls_multi *m1 = mi->context.c2.tls_multi; + struct tls_multi *m2 = ex_mi->context.c2.tls_multi; + + /* do not float if target address is taken by client with another cert */ + if (!cert_hash_compare(m1->locked_cert_hash_set, m2->locked_cert_hash_set)) { - msg (D_MULTI_MEDIUM, "prevent float to %s", + msg(D_MULTI_LOW, "Disallow float to an address taken by another client %s", multi_instance_string (ex_mi, false, &gc)); mi->context.c2.buf.len = 0; @@ -2546,9 +2681,13 @@ void multi_process_float (struct multi_context* m, struct multi_instance* mi) multi_close_instance(m, ex_mi, false); } - msg (D_MULTI_MEDIUM, "peer %" PRIu32 " floated from %s to %s", mi->context.c2.tls_multi->peer_id, - mroute_addr_print (&mi->real, &gc), print_link_socket_actual (&m->top.c2.from, &gc)); + msg(D_MULTI_MEDIUM, "peer %" PRIu32 " (%s) floated from %s to %s", + mi->context.c2.tls_multi->peer_id, + tls_common_name(mi->context.c2.tls_multi, false), + mroute_addr_print(&mi->real, &gc), + print_link_socket_actual(&m->top.c2.from, &gc)); + /* remove old address from hash table before changing address */ ASSERT (hash_remove(m->hash, &mi->real)); ASSERT (hash_remove(m->iter, &mi->real)); @@ -2569,8 +2708,7 @@ void multi_process_float (struct multi_context* m, struct multi_instance* mi) ASSERT (hash_add (m->iter, &mi->real, mi, false)); #ifdef MANAGEMENT_DEF_AUTH - hash_remove (m->cid_hash, &mi->context.c2.mda_context.cid); - hash_add (m->cid_hash, &mi->context.c2.mda_context.cid, mi, false); + ASSERT(hash_add(m->cid_hash, &mi->context.c2.mda_context.cid, mi, true)); #endif done: @@ -2663,8 +2801,8 @@ multi_process_incoming_link (struct multi_context *m, struct multi_instance *ins else if (multi_get_instance_by_virtual_addr (m, &src, true) != m->pending) { /* IPv6 link-local address (fe80::xxx)? */ - if ( (src.type & MR_ADDR_MASK) == MR_ADDR_IPV6 && - src.addr[0] == 0xfe && src.addr[1] == 0x80 ) + if ( (src.type & MR_ADDR_MASK) == MR_ADDR_IPV6 + && IN6_IS_ADDR_LINKLOCAL(&src.v6.addr) ) { /* do nothing, for now. TODO: add address learning */ } @@ -2966,10 +3104,19 @@ multi_process_timeout (struct multi_context *m, const unsigned int mpp_flags) /* instance marked for wakeup? */ if (m->earliest_wakeup) { - set_prefix (m->earliest_wakeup); - ret = multi_process_post (m, m->earliest_wakeup, mpp_flags); - m->earliest_wakeup = NULL; - clear_prefix (); + if (m->earliest_wakeup == (struct multi_instance *)&m->deferred_shutdown_signal) + { + schedule_remove_entry(m->schedule, (struct schedule_entry *) &m->deferred_shutdown_signal); + throw_signal(m->deferred_shutdown_signal.signal_received); + } + else + { + set_prefix (m->earliest_wakeup); + ret = multi_process_post (m, m->earliest_wakeup, mpp_flags); + m->earliest_wakeup = NULL; + clear_prefix (); + } + m->earliest_wakeup = NULL; } return ret; } @@ -3083,11 +3230,9 @@ multi_process_per_second_timers_dowork (struct multi_context *m) } void -multi_top_init (struct multi_context *m, const struct context *top, const bool alloc_buffers) +multi_top_init (struct multi_context *m, const struct context *top) { inherit_context_top (&m->top, top); - m->top.c2.buffers = NULL; - if (alloc_buffers) m->top.c2.buffers = init_context_buffers (&top->c2.frame); } @@ -3098,6 +3243,48 @@ multi_top_free (struct multi_context *m) free_context_buffers (m->top.c2.buffers); } +static bool +is_exit_restart(int sig) +{ + return (sig == SIGUSR1 || sig == SIGTERM || sig == SIGHUP || sig == SIGINT); +} + +static void +multi_push_restart_schedule_exit(struct multi_context *m, bool next_server) +{ + struct hash_iterator hi; + struct hash_element *he; + struct timeval tv; + + /* tell all clients to restart */ + hash_iterator_init(m->iter, &hi); + while ((he = hash_iterator_next(&hi))) + { + struct multi_instance *mi = (struct multi_instance *) he->value; + if (!mi->halt) + { + send_control_channel_string(&mi->context, next_server ? "RESTART,[N]" : "RESTART", D_PUSH); + multi_schedule_context_wakeup(m, mi); + } + } + hash_iterator_free(&hi); + + /* reschedule signal */ + ASSERT(!openvpn_gettimeofday(&m->deferred_shutdown_signal.wakeup, NULL)); + tv.tv_sec = 2; + tv.tv_usec = 0; + tv_add(&m->deferred_shutdown_signal.wakeup, &tv); + + m->deferred_shutdown_signal.signal_received = m->top.sig->signal_received; + + schedule_add_entry(m->schedule, + (struct schedule_entry *) &m->deferred_shutdown_signal, + &m->deferred_shutdown_signal.wakeup, + compute_wakeup_sigma(&m->deferred_shutdown_signal.wakeup)); + + m->top.sig->signal_received = 0; +} + /* * Return true if event loop should break, * false if it should continue. @@ -3113,6 +3300,14 @@ multi_process_signal (struct multi_context *m) m->top.sig->signal_received = 0; return false; } + else if (proto_is_dgram(m->top.options.ce.proto) + && is_exit_restart(m->top.sig->signal_received) + && (m->deferred_shutdown_signal.signal_received == 0) + && m->top.options.ce.explicit_exit_notification != 0) + { + multi_push_restart_schedule_exit(m, m->top.options.ce.explicit_exit_notification == 2); + return false; + } return true; } From c2b3266e4081fcd43ee6c0e5ba2d1a24d580b198 Mon Sep 17 00:00:00 2001 From: Vladislav Yarmak Date: Wed, 15 Nov 2017 09:48:13 +0200 Subject: [PATCH 643/643] modificator fix --- src/openvpn/multi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index 8fd34a35f30..39c85920a8e 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -2067,7 +2067,7 @@ multi_client_connect_late_setup (struct multi_context *m, struct multi_instance *mi, const unsigned int option_types_found, int cc_succeeded, - const int cc_succeeded_count) + int cc_succeeded_count) { struct gc_arena gc = gc_new (); ASSERT (mi->context.c1.tuntap);