diff options
Diffstat (limited to 'src/openvpn')
165 files changed, 59734 insertions, 52527 deletions
diff --git a/src/openvpn/Makefile.am b/src/openvpn/Makefile.am index 4c18449..bea294b 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. <sales@openvpn.net> +# Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> # Copyright (C) 2006-2012 Alon Bar-Lev <alon.barlev@gmail.com> # diff --git a/src/openvpn/Makefile.in b/src/openvpn/Makefile.in index 9ef9b28..95d4f59 100644 --- a/src/openvpn/Makefile.in +++ b/src/openvpn/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.14.1 from Makefile.am. +# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. @@ -21,7 +21,7 @@ # packet encryption, packet authentication, and # packet compression. # -# Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net> +# Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> # Copyright (C) 2006-2012 Alon Bar-Lev <alon.barlev@gmail.com> # @@ -655,14 +655,14 @@ distclean-compile: @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< diff --git a/src/openvpn/argv.c b/src/openvpn/argv.c index 596e59c..cc813ed 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 9aee641..1dd6dd7 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * 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,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 258b258..c799ede 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 92a195a..5679bc9 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/basic.h b/src/openvpn/basic.h index 48d4d9b..dac6f01 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * 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 cb3ce88..e31765e 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * 2015-2016 <iam@valdikss.org.ru> * 2016 Selva Nair <selva.nair@gmail.com> * @@ -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 @@ out: */ 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 f8b6d4f..a7dadc4 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 6af8dbb..2defd18 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 7747003..28b224e 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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; + int ret = buf->capacity - (buf->offset + buf->len); + if (ret < 0) + { + ret = 0; + } + return ret; + } + else + { + 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; + int ret = buf->capacity - buf->offset; + if (ret < 0) + { + ret = 0; + } + return ret; + } + else + { + 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,42 @@ 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); + +bool string_mod(char *str, const unsigned int inclusive, const unsigned int exclusive, 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); -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); + +/** Return true iff str starts with prefix */ +static inline bool +strprefix(const char *str, const char *prefix) +{ + return 0 == strncmp(str, prefix, strlen(prefix)); +} -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 +952,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 +1009,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 +1069,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 583701a..ecf2a7f 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 ddefe12..9158437 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 a5779e1..cdaf2a8 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 1134101..cd988d4 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 395f3d2..fa65f87 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. <sales@openvpn.net> - * Copyright (C) 2013 Gert Doering <gert@greenie.muc.de> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> + * Copyright (C) 2013-2017 Gert Doering <gert@greenie.muc.de> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 7774ca5..8621e93 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. <sales@openvpn.net> - * Copyright (C) 2013 Gert Doering <gert@greenie.muc.de> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> + * Copyright (C) 2013-2017 Gert Doering <gert@greenie.muc.de> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 499fef9..0182a7c 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 9ed9532..3c0b18e 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 9c6aad2..5070c82 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 c3bb7c3..90c8a94 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * Copyright (C) 2014-2015 David Sommerseth <davids@redhat.com> - * Copyright (C) 2016 David Sommerseth <davids@openvpn.net> + * Copyright (C) 2016-2017 David Sommerseth <davids@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 ec32cf6..2c7f3e9 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * Copyright (C) 2014-2015 David Sommerseth <davids@redhat.com> - * Copyright (C) 2016 David Sommerseth <davids@openvpn.net> + * Copyright (C) 2016-2017 David Sommerseth <davids@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 06994fd..13b9d7e 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * Copyright (C) 2014-2015 David Sommerseth <davids@redhat.com> - * Copyright (C) 2016 David Sommerseth <davids@openvpn.net> + * Copyright (C) 2016-2017 David Sommerseth <davids@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 8a953c9..1c0aa4c 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 708cc92..7119abc 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. <sales@openvpn.net> - * Copyright (C) 2010-2016 Fox Crypto B.V. <openvpn@fox-it.com> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> + * Copyright (C) 2010-2017 Fox Crypto B.V. <openvpn@fox-it.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 ff90745..61e9b59 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. <sales@openvpn.net> - * Copyright (C) 2010-2014 Fox Crypto B.V. <openvpn@fox-it.com> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> + * Copyright (C) 2010-2017 Fox Crypto B.V. <openvpn@fox-it.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 bf7d78c..2c79baa 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. <sales@openvpn.net> - * Copyright (C) 2010 Fox Crypto B.V. <openvpn@fox-it.com> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> + * Copyright (C) 2010-2017 Fox Crypto B.V. <openvpn@fox-it.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 6ad5924..942684c 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. <sales@openvpn.net> - * Copyright (C) 2010 Fox Crypto B.V. <openvpn@fox-it.com> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> + * Copyright (C) 2010-2017 Fox Crypto B.V. <openvpn@fox-it.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 574a63f..d9b1446 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. <sales@openvpn.net> - * Copyright (C) 2010 Fox Crypto B.V. <openvpn@fox-it.com> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> + * Copyright (C) 2010-2017 Fox Crypto B.V. <openvpn@fox-it.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 306b6c6..b016d98 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. <sales@openvpn.net> - * Copyright (C) 2010 Fox Crypto B.V. <openvpn@fox-it.com> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> + * Copyright (C) 2010-2017 Fox Crypto B.V. <openvpn@fox-it.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 f157041..56ec6e1 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. <sales@openvpn.net> - * Copyright (C) 2010 Fox Crypto B.V. <openvpn@fox-it.com> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> + * Copyright (C) 2010-2017 Fox Crypto B.V. <openvpn@fox-it.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 e107bd3..69a5a32 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 8d0b18a..c17a22e 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 e823a4a..d406870 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 9d56eb4..c4dd518 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 425bc30..e78f272 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 f43bc38..df4eee7 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 409ad13..f4922e0 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 565343d..6a6e029 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 ce01319..401069d 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 d34db9b..1e84a08 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 5d4e308..97e1cd6 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 b50a2e0..8102e94 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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,217 +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 */ - 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 0856aa7..ae86e7a 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 7ad1d61..6fbfe08 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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<<FRAG_SIZE_ROUND_SHIFT */ - if (size & FRAG_SIZE_ROUND_MASK) - FRAG_ERR ("bad fragment size"); - - /* is this the first fragment for our sequence number? */ - if (!frag->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<<FRAG_SIZE_ROUND_SHIFT */ + if (size & FRAG_SIZE_ROUND_MASK) + { + FRAG_ERR("bad fragment size"); + } + + /* is this the first fragment for our sequence number? */ + if (!frag->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 866573b..a24b524 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 f0aa7f6..5bff5e8 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 c0aeab1..8f41864 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 229523d..adcc4f8 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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.254 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 444969c..593d1ed 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 99bbda4..01301c0 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 8423841..b074fb2 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 74f1139..9a3e29d 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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<<CE_MAN_QUERY_REMOTE_SHIFT); - ce->flags |= ((flags&CE_MAN_QUERY_REMOTE_MASK)<<CE_MAN_QUERY_REMOTE_SHIFT); - } - } - return ret; +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<<CE_MAN_QUERY_REMOTE_SHIFT); + ce->flags |= ((flags&CE_MAN_QUERY_REMOTE_MASK)<<CE_MAN_QUERY_REMOTE_SHIFT); + } + } + return ret; } static bool -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<<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; - 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<<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; + 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;i<MAX_PARMS && c->options.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; i<MAX_PARMS && c->options.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,92 +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) -{ - 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) - { - /* chroot if requested */ - if (c->options.chroot_dir) - { - if (no_delay) - 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); - } +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 (c0 && !c0->uid_gid_chroot_set) + { + /* 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); + } + 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; + } } } @@ -1021,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; } /* @@ -1073,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 } } @@ -1134,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 } @@ -1152,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); + } } @@ -1166,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); } } @@ -1244,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; + } + management_set_state(management, + OPENVPN_STATE_CONNECTED, + detail, + tun_local, + tun_local6, + &local, + &remote); + if (tun_local) { - tun_local = &c->c1.tuntap->local; - tun_local6 = &c->c1.tuntap->local_ipv6; + 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 */ } /* @@ -1343,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 } @@ -1393,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; } /* @@ -1420,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; } /* @@ -1587,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); } } @@ -1742,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; } /* @@ -1975,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); } } @@ -2055,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 } @@ -2136,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); } /* @@ -2199,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); + + /* Set all command-line TLS-related options */ + CLEAR(to); - /* 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_and = ~(CO_PACKET_ID_LONG_FORM); - if (packet_id_long_form) - to.crypto_flags_or = 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; + 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"); } } @@ -2509,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); } } @@ -2793,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 @@ -2805,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 @@ -2818,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 } @@ -2898,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. @@ -2931,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); } } @@ -2958,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."); } } @@ -2975,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; } } @@ -2989,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 } @@ -3013,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 } @@ -3077,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 @@ -3092,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; } } @@ -3124,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; + } } } @@ -3155,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 } @@ -3188,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; } } @@ -3215,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 } @@ -3398,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 } @@ -3480,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(); } } @@ -3502,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 @@ -3972,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 524bc64..3b97d84 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 f0fc196..bae8f16 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 64494f1..99e72a0 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 59eb1f6..5ed64a9 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 ea6bd74..fb9f664 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * 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,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<n; ++i) h = hash( k[i], len[i], h); - -By Bob Jenkins, 1996. bob_jenkins@burtleburtle.net. You may use this -code any way you wish, private, educational, or commercial. It's free. - -See http://burlteburtle.net/bob/hash/evahash.html -Use for hash table lookup, or anything where one collision in 2^32 is -acceptable. Do NOT use for cryptographic purposes. - --------------------------------------------------------------------- - -mix -- mix 3 32-bit values reversibly. -For every delta with one or two bit set, and the deltas of all three - high bits or all three low bits, whether the original value of a,b,c - is almost all zero or is uniformly distributed, -* If mix() is run forward or backward, at least 32 bits in a,b,c - have at least 1/4 probability of changing. -* If mix() is run forward, every bit of c will change between 1/3 and - 2/3 of the time. (Well, 22/100 and 78/100 for some 2-bit deltas.) -mix() was built out of 36 single-cycle latency instructions in a - structure that could supported 2x parallelism, like so: - a -= b; - a -= c; x = (c>>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<n; ++i) h = hash( k[i], len[i], h); + * + * By Bob Jenkins, 1996. bob_jenkins@burtleburtle.net. You may use this + * code any way you wish, private, educational, or commercial. It's free. + * + * See http://burlteburtle.net/bob/hash/evahash.html + * Use for hash table lookup, or anything where one collision in 2^32 is + * acceptable. Do NOT use for cryptographic purposes. + * + * -------------------------------------------------------------------- + * + * mix -- mix 3 32-bit values reversibly. + * For every delta with one or two bit set, and the deltas of all three + * high bits or all three low bits, whether the original value of a,b,c + * is almost all zero or is uniformly distributed, + * If mix() is run forward or backward, at least 32 bits in a,b,c + * have at least 1/4 probability of changing. + * If mix() is run forward, every bit of c will change between 1/3 and + * 2/3 of the time. (Well, 22/100 and 78/100 for some 2-bit deltas.) + * mix() was built out of 36 single-cycle latency instructions in a + * structure that could supported 2x parallelism, like so: + * a -= b; + * a -= c; x = (c>>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 adde36b..6270f88 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 57f447b..ff71e48 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 d6c4256..f6ea2b1 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 25a839b..3d6891e 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 f33e587..85937b2 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 4918ed2..763f6c6 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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,901 +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_cloexec (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); - set_cloexec (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; } /* @@ -1928,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; + } + } } } @@ -2949,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) @@ -2969,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)); } } @@ -2995,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); } } @@ -3039,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); } /* @@ -3322,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); } /* @@ -3332,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; } /* @@ -3380,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); } /* @@ -3448,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); } /* @@ -3500,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 3ffced0..6e5cb9b 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 82f2388..7a23e59 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 1085adc..cfaef58 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 1f6bb67..ee30b15 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 4e06c91..87f03be 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * Copyright (C) 2014-2015 David Sommerseth <davids@redhat.com> - * Copyright (C) 2016 David Sommerseth <davids@openvpn.net> + * Copyright (C) 2016-2017 David Sommerseth <davids@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 b8bbaa7..16be621 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 c905af7..8b466b6 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 8f7a064..0698348 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 7298c7b..5b110d2 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 0d32943..afe7a32 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 3be493c..8ab1d02 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 dab05fe..f87a858 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 78e5ccd..b5471b1 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 b677b48..835b8fd 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * 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,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 8cbaa86..73eab21 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 0320545..471e51e 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 fec5e8d..64ce4d7 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 1f15d9d..a98d64d 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 4fc8b02..f6f3f5d 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 @@ done: * 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 0d369f3..b4ffd69 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 3390bdd..e78af9e 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 <domain> 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 <domain> 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 77903b0..b0a6821 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 516eb4d..84fe1ac 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 d71381d..b4ccc4d 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 5d88cc9..843ceb2 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 5fb2fd9..888acda 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 fa5cc1d..37edec4 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 47acd97..bfedb6a 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * Copyright (C) 2008-2013 David Sommerseth <dazo@users.sourceforge.net> * * This program is free software; you can redistribute it and/or modify @@ -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 <version> ['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 <version> : 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 <version> ['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 <version> : 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;i<MAX_PARMS;i++) - SHOW_INT (remote_cert_ku[i]); - } - SHOW_STR (remote_cert_eku); - SHOW_INT (ssl_flags); + 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; i<MAX_PARMS; i++) + SHOW_INT(remote_cert_ku[i]); + } + SHOW_STR(remote_cert_eku); + SHOW_INT(ssl_flags); - SHOW_INT (tls_timeout); + SHOW_INT(tls_timeout); - SHOW_INT (renegotiate_bytes); - SHOW_INT (renegotiate_packets); - SHOW_INT (renegotiate_seconds); + SHOW_INT(renegotiate_bytes); + SHOW_INT(renegotiate_packets); + SHOW_INT(renegotiate_seconds); - SHOW_INT (handshake_window); - SHOW_INT (transition_window); + SHOW_INT(handshake_window); + SHOW_INT(transition_window); - SHOW_BOOL (single_session); + SHOW_BOOL(single_session); #ifdef ENABLE_PUSH_PEER_INFO - SHOW_BOOL (push_peer_info); + SHOW_BOOL(push_peer_info); #endif - SHOW_BOOL (tls_exit); + SHOW_BOOL(tls_exit); - SHOW_STR (tls_auth_file); - SHOW_STR (tls_crypt_file); + SHOW_STR(tls_auth_file); + SHOW_STR(tls_crypt_file); #endif /* ENABLE_CRYPTO */ #ifdef ENABLE_PKCS11 - { - int i; - for (i=0;i<MAX_PARMS && o->pkcs11_providers[i] != NULL;i++) - SHOW_PARM (pkcs11_providers, o->pkcs11_providers[i], "%s"); - } - { - int i; - for (i=0;i<MAX_PARMS;i++) - SHOW_PARM (pkcs11_protected_authentication, o->pkcs11_protected_authentication[i] ? "ENABLED" : "DISABLED", "%s"); - } - { - int i; - for (i=0;i<MAX_PARMS;i++) - SHOW_PARM (pkcs11_private_mode, o->pkcs11_private_mode[i], "%08x"); - } - { - int i; - for (i=0;i<MAX_PARMS;i++) - SHOW_PARM (pkcs11_cert_private, o->pkcs11_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; i<MAX_PARMS && o->pkcs11_providers[i] != NULL; i++) + SHOW_PARM(pkcs11_providers, o->pkcs11_providers[i], "%s"); + } + { + int i; + for (i = 0; i<MAX_PARMS; i++) + SHOW_PARM(pkcs11_protected_authentication, o->pkcs11_protected_authentication[i] ? "ENABLED" : "DISABLED", "%s"); + } + { + int i; + for (i = 0; i<MAX_PARMS; i++) + SHOW_PARM(pkcs11_private_mode, o->pkcs11_private_mode[i], "%08x"); + } + { + int i; + for (i = 0; i<MAX_PARMS; i++) + SHOW_PARM(pkcs11_cert_private, o->pkcs11_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,945 +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"); - - /* - * 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); + 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); + } #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 (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 (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->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->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 (options->ifconfig_local, options->ifconfig_remote_netmask)) - msg (M_USAGE, "local and remote/netmask --ifconfig addresses must be different"); + 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 (ce->bind_defined && !ce->bind_local) - msg (M_USAGE, "--bind and --nobind can't be used together"); + 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->local && !ce->bind_local) - msg (M_USAGE, "--local and --nobind don't make sense when used together"); + if (ce->bind_defined && !ce->bind_local) + { + msg(M_USAGE, "--bind and --nobind can't be 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 && !ce->bind_local) + { + msg(M_USAGE, "--local 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->local_port_defined && !ce->bind_local) + { + msg(M_USAGE, "--lport and --nobind don't make sense when used together"); + } - /* - * Check for consistency of management options - */ + if (!ce->remote && !ce->bind_local) + { + msg(M_USAGE, "--nobind doesn't make sense unless used with --remote"); + } + + /* + * 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"); + 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->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->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->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->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 (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"); + /* + * 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"); - /* <connection> 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, "<connection> 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 ((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"); + } + /* <connection> 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, "<connection> 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 (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"); + 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)) + 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, "NCP cipher list contains unsupported ciphers."); + 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"); + /* + * 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"); + /* + * 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 (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"); + 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) + 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."); + 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) + 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."); + 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."); + 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."); + 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 + 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) && 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 + 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 (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 - } - else + 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 + <<SSLF_TLS_VERSION_MAX_SHIFT); + o->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 } @@ -2723,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. @@ -2797,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; } @@ -2847,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; } /* @@ -2882,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 */ @@ -2969,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 */ } @@ -2985,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 @@ -3066,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; } /* @@ -3132,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"); } - if (tt && o->mode == MODE_POINT_TO_POINT && !PULL_DEFINED(o)) + /* + * 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)) { - 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 @@ -3207,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); } /* @@ -3296,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); } } @@ -3532,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")) { - msg (msglevel, "--topology must be net30, p2p, or subnet"); - return TOP_UNDEF; + 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; } } 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"; } } @@ -3574,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 @@ -3688,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. <sales@openvpn.net>"); + msg(M_INFO|M_NOPREFIX, "Originally developed by James Yonan"); + msg(M_INFO|M_NOPREFIX, "Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net>"); #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, "</%s>", 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, "</%s>", 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; + } } } @@ -4201,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 <connection> blocks ", name, file, line); - else - msg (M_WARN, "Option '%s' is ignored by previous <connection> blocks", name); + if (file) + { + msg(M_WARN, "Option '%s' in %s:%d is ignored by previous <connection> blocks ", name, file, line); + } + else + { + msg(M_WARN, "Option '%s' is ignored by previous <connection> 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 @@ -4345,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]; - } + 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]) + else if (streq(p[0], "management-client-user") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->management_client_user = p[1]; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->management_client_user = p[1]; } - else if (streq (p[0], "management-client-group") && p[1] && !p[2]) + else if (streq(p[0], "management-client-group") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->management_client_group = p[1]; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->management_client_group = p[1]; } - else if (streq (p[0], "management-query-passwords") && !p[1]) + else if (streq(p[0], "management-query-passwords") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->management_flags |= MF_QUERY_PASSWORDS; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->management_flags |= MF_QUERY_PASSWORDS; } - else if (streq (p[0], "management-query-remote") && !p[1]) + else if (streq(p[0], "management-query-remote") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->management_flags |= MF_QUERY_REMOTE; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->management_flags |= MF_QUERY_REMOTE; } - else if (streq (p[0], "management-query-proxy") && !p[1]) + else if (streq(p[0], "management-query-proxy") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->management_flags |= MF_QUERY_PROXY; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->management_flags |= MF_QUERY_PROXY; } - else if (streq (p[0], "management-hold") && !p[1]) + else if (streq(p[0], "management-hold") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->management_flags |= MF_HOLD; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->management_flags |= MF_HOLD; } - else if (streq (p[0], "management-signal") && !p[1]) + else if (streq(p[0], "management-signal") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->management_flags |= MF_SIGNAL; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->management_flags |= MF_SIGNAL; } - else if (streq (p[0], "management-forget-disconnect") && !p[1]) + else if (streq(p[0], "management-forget-disconnect") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->management_flags |= MF_FORGET_DISCONNECT; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->management_flags |= MF_FORGET_DISCONNECT; } - else if (streq (p[0], "management-up-down") && !p[1]) + else if (streq(p[0], "management-up-down") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->management_flags |= MF_UP_DOWN; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->management_flags |= MF_UP_DOWN; } - else if (streq (p[0], "management-client") && !p[2]) + 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]; + 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]) + else if (streq(p[0], "management-external-key") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->management_flags |= MF_EXTERNAL_KEY; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->management_flags |= MF_EXTERNAL_KEY; } - else if (streq (p[0], "management-external-cert") && p[1] && !p[2]) + 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]; + 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]) + else if (streq(p[0], "management-client-auth") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->management_flags |= MF_CLIENT_AUTH; + 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]) + else if (streq(p[0], "management-client-pf") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->management_flags |= (MF_CLIENT_PF | MF_CLIENT_AUTH); + 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]) + else if (streq(p[0], "management-log-cache") && p[1] && !p[2]) { - int cache; + 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; + 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 +#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] && !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; - } + 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]) + 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; + 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; + else if (streq(p[1], "server")) + { + options->mode = MODE_SERVER; + } #endif - else - { - msg (msglevel, "Bad --mode parameter: %s", p[1]); - goto err; - } + else + { + msg(msglevel, "Bad --mode parameter: %s", p[1]); + goto err; + } } - else if (streq (p[0], "dev") && p[1] && !p[2]) + else if (streq(p[0], "dev") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->dev = p[1]; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->dev = p[1]; } - else if (streq (p[0], "dev-type") && p[1] && !p[2]) + else if (streq(p[0], "dev-type") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->dev_type = p[1]; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->dev_type = p[1]; } - else if (streq (p[0], "dev-node") && p[1] && !p[2]) + else if (streq(p[0], "dev-node") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->dev_node = p[1]; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->dev_node = p[1]; } - else if (streq (p[0], "lladdr") && p[1] && !p[2]) + 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; - } + 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]) + else if (streq(p[0], "topology") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_UP); - options->topology = parse_topology (p[1], msglevel); + VERIFY_PERMISSION(OPT_P_UP); + options->topology = parse_topology(p[1], msglevel); } - else if (streq (p[0], "tun-ipv6") && !p[1]) + 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."); + 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]) + else if (streq(p[0], "iproute") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - iproute_path = p[1]; + VERIFY_PERMISSION(OPT_P_GENERAL); + iproute_path = p[1]; } #endif - else if (streq (p[0], "ifconfig") && p[1] && p[2] && !p[3]) + 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; - } + 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]) + else if (streq(p[0], "ifconfig-ipv6") && p[1] && p[2] && !p[3]) { - unsigned int netbits; + 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_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; - } + 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]; + 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 - { - 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]) + else if (streq(p[0], "ifconfig-noexec") && !p[1]) { - VERIFY_PERMISSION (OPT_P_UP); - options->ifconfig_noexec = true; + VERIFY_PERMISSION(OPT_P_UP); + options->ifconfig_noexec = true; } - else if (streq (p[0], "ifconfig-nowarn") && !p[1]) + else if (streq(p[0], "ifconfig-nowarn") && !p[1]) { - VERIFY_PERMISSION (OPT_P_UP); - options->ifconfig_nowarn = true; + VERIFY_PERMISSION(OPT_P_UP); + options->ifconfig_nowarn = true; } - else if (streq (p[0], "local") && p[1] && !p[2]) + else if (streq(p[0], "local") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION); - options->ce.local = p[1]; + VERIFY_PERMISSION(OPT_P_GENERAL|OPT_P_CONNECTION); + options->ce.local = p[1]; } - else if (streq (p[0], "remote-random") && !p[1]) + else if (streq(p[0], "remote-random") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->remote_random = true; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->remote_random = true; } - else if (streq (p[0], "connection") && p[1] && !p[3]) + 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; + 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; - } + 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); - } + 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]) + else if (streq(p[0], "ignore-unknown-option") && p[1]) { - int i; - int j; - int numignored=0; - const char **ignore; + 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++; + 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++; + /* 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]; + /* 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; + options->ignore_unknown_option = ignore; - for (j=1;p[j];j++) + 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++; + /* 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; + 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; + 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; } #ifdef ENABLE_DEBUG - else if (streq (p[0], "gremlin") && p[1] && !p[2]) + else if (streq(p[0], "gremlin") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->gremlin = positive_atoi (p[1]); + VERIFY_PERMISSION(OPT_P_GENERAL); + options->gremlin = positive_atoi(p[1]); } #endif - else if (streq (p[0], "chroot") && p[1] && !p[2]) + else if (streq(p[0], "chroot") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->chroot_dir = p[1]; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->chroot_dir = p[1]; } - else if (streq (p[0], "cd") && p[1] && !p[2]) + 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]; + 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); + 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]) + else if (streq(p[0], "memstats") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->memstats_fn = p[1]; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->memstats_fn = p[1]; } #endif - else if (streq (p[0], "mlock") && !p[1]) + else if (streq(p[0], "mlock") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->mlock = true; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->mlock = true; } #if ENABLE_IP_PKTINFO - else if (streq (p[0], "multihome") && !p[1]) + else if (streq(p[0], "multihome") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->sockflags |= SF_USE_IP_PKTINFO; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->sockflags |= SF_USE_IP_PKTINFO; } #endif - else if (streq (p[0], "verb") && p[1] && !p[2]) + else if (streq(p[0], "verb") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_MESSAGES); - options->verbosity = positive_atoi (p[1]); + 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); + /* 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]) + else if (streq(p[0], "mute") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_MESSAGES); - options->mute = positive_atoi (p[1]); + VERIFY_PERMISSION(OPT_P_MESSAGES); + options->mute = positive_atoi(p[1]); } - else if (streq (p[0], "errors-to-stderr") && !p[1]) + else if (streq(p[0], "errors-to-stderr") && !p[1]) { - VERIFY_PERMISSION (OPT_P_MESSAGES); - errors_to_stderr(); + VERIFY_PERMISSION(OPT_P_MESSAGES); + errors_to_stderr(); } - else if (streq (p[0], "status") && p[1] && !p[3]) + 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]); - } + 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]) + else if (streq(p[0], "status-version") && p[1] && !p[2]) { - int version; + 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; + 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]) + 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; - } + 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]) + 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_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]) + 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; + 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]) + 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; + 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")) + 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; + 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]) + 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]); + 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]) + 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]); + 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]) + else if (streq(p[0], "mtu-test") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->mtu_test = true; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->mtu_test = true; } #endif - else if (streq (p[0], "nice") && p[1] && !p[2]) + else if (streq(p[0], "nice") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_NICE); - options->nice = atoi (p[1]); + VERIFY_PERMISSION(OPT_P_NICE); + options->nice = atoi(p[1]); } - else if (streq (p[0], "rcvbuf") && p[1] && !p[2]) + else if (streq(p[0], "rcvbuf") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_SOCKBUF); - options->rcvbuf = positive_atoi (p[1]); + VERIFY_PERMISSION(OPT_P_SOCKBUF); + options->rcvbuf = positive_atoi(p[1]); } - else if (streq (p[0], "sndbuf") && p[1] && !p[2]) + else if (streq(p[0], "sndbuf") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_SOCKBUF); - options->sndbuf = positive_atoi (p[1]); + VERIFY_PERMISSION(OPT_P_SOCKBUF); + options->sndbuf = positive_atoi(p[1]); } - else if (streq (p[0], "mark") && p[1] && !p[2]) + 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]); + VERIFY_PERMISSION(OPT_P_GENERAL); + options->mark = atoi(p[1]); #endif } - else if (streq (p[0], "socket-flags")) + 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]); - } + 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]) + else if (streq(p[0], "txqueuelen") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_GENERAL); + VERIFY_PERMISSION(OPT_P_GENERAL); #ifdef TARGET_LINUX - options->tuntap_options.txqueuelen = positive_atoi (p[1]); + options->tuntap_options.txqueuelen = positive_atoi(p[1]); #else - msg (msglevel, "--txqueuelen not supported on this OS"); - goto err; + msg(msglevel, "--txqueuelen not supported on this OS"); + goto err; #endif } - else if (streq (p[0], "shaper") && p[1] && !p[2]) + 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; + 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; + 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; + 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; - } - } + 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); + /* we need this here to handle pushed --redirect-gateway */ + remap_redirect_gateway_flags(options); #endif - options->routes->flags |= RG_ENABLE; + options->routes->flags |= RG_ENABLE; } - else if (streq (p[0], "remote-random-hostname") && !p[1]) + else if (streq(p[0], "remote-random-hostname") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->sockflags |= SF_HOST_RANDOMIZE; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->sockflags |= SF_HOST_RANDOMIZE; } - else if (streq (p[0], "setenv") && p[1] && !p[3]) + 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; - } + 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; + 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]) + else if (streq(p[0], "disable-occ") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->occ = false; + 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]) + 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_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); + VERIFY_PERMISSION(OPT_P_GENERAL); + options->ssl_flags |= SSLF_OPT_VERIFY; } - else if (streq (p[0], "learn-address") && p[1]) + else if (streq(p[0], "auth-user-pass-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->learn_address_script, - p[1], "learn-address", true); + 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]) + else if (streq(p[0], "tmp-dir") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->tmp_dir = p[1]; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->tmp_dir = p[1]; } - else if (streq (p[0], "client-config-dir") && p[1] && !p[2]) + else if (streq(p[0], "client-config-dir") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->client_config_dir = p[1]; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->client_config_dir = p[1]; } - 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], "ccd-exclusive") && !p[1]) { - int n_bcast_buf; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->ccd_exclusive = true; + } + else if (streq(p[0], "bcast-buffers") && p[1] && !p[2]) + { + 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_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], "tcp-queue-limit") && p[1] && !p[2]) + else if (streq(p[0], "tcp-queue-limit") && p[1] && !p[2]) { - int tcp_queue_limit; + 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; + 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; + 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->stale_routes_ageing_time = ageing_time; - options->stale_routes_check_interval = check_interval; + + 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; + } + options->stale_routes_ageing_time = ageing_time; + options->stale_routes_check_interval = check_interval; } #endif /* P2MP_SERVER */ - else if (streq (p[0], "client") && !p[1]) + else if (streq(p[0], "client") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->client = true; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->client = true; } - else if (streq (p[0], "pull") && !p[1]) + else if (streq(p[0], "pull") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->pull = true; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->pull = true; } - else if (streq (p[0], "push-continuation") && p[1] && !p[2]) + else if (streq(p[0], "push-continuation") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_PULL_MODE); - options->push_continuation = atoi(p[1]); + VERIFY_PERMISSION(OPT_P_PULL_MODE); + options->push_continuation = atoi(p[1]); } - else if (streq (p[0], "auth-user-pass") && !p[2]) + else if (streq(p[0], "auth-user-pass") && !p[2]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - if (p[1]) - { - options->auth_user_pass_file = p[1]; - } - else - options->auth_user_pass_file = "stdin"; + VERIFY_PERMISSION(OPT_P_GENERAL); + if (p[1]) + { + options->auth_user_pass_file = p[1]; + } + else + { + options->auth_user_pass_file = "stdin"; + } } - else if (streq (p[0], "auth-retry") && p[1] && !p[2]) + else if (streq(p[0], "auth-retry") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - auth_retry_set (msglevel, p[1]); + 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] && !p[3]) + 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]; - if (atoi(p[2])) - options->sc_info.flags |= SC_ECHO; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->sc_info.challenge_text = p[1]; + if (atoi(p[2])) + { + options->sc_info.flags |= SC_ECHO; + } } #endif -#endif - else if (streq (p[0], "msg-channel") && p[1]) +#endif /* if P2MP */ + 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)) + 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; + 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; + options->route_method = ROUTE_METHOD_SERVICE; +#else /* ifdef _WIN32 */ + 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; + 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); + } } -#endif + 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 /* ifdef _WIN32 */ #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; - } + 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; + } } -#endif +#endif /* if defined(_WIN32) || defined(TARGET_ANDROID) */ #ifdef _WIN32 - else if (streq (p[0], "show-adapters") && !p[1]) + 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 */ + 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") && !p[1]) + 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 */ + 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") && !p[1]) + else if (streq(p[0], "show-net-up") && !p[1]) { - VERIFY_PERMISSION (OPT_P_UP); - options->show_net_up = true; + VERIFY_PERMISSION(OPT_P_UP); + options->show_net_up = true; } - else if (streq (p[0], "tap-sleep") && p[1] && !p[2]) + else if (streq(p[0], "tap-sleep") && p[1] && !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; + 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; } - else if (streq (p[0], "dhcp-renew") && !p[1]) + else if (streq(p[0], "dhcp-renew") && !p[1]) { - VERIFY_PERMISSION (OPT_P_IPWIN32); - options->tuntap_options.dhcp_renew = true; + VERIFY_PERMISSION(OPT_P_IPWIN32); + options->tuntap_options.dhcp_renew = true; } - else if (streq (p[0], "dhcp-pre-release") && !p[1]) + else if (streq(p[0], "dhcp-pre-release") && !p[1]) { - VERIFY_PERMISSION (OPT_P_IPWIN32); - options->tuntap_options.dhcp_pre_release = true; + VERIFY_PERMISSION(OPT_P_IPWIN32); + options->tuntap_options.dhcp_pre_release = true; } - else if (streq (p[0], "dhcp-release") && !p[1]) + else if (streq(p[0], "dhcp-release") && !p[1]) { - VERIFY_PERMISSION (OPT_P_IPWIN32); - options->tuntap_options.dhcp_release = true; + VERIFY_PERMISSION(OPT_P_IPWIN32); + options->tuntap_options.dhcp_release = true; } - else if (streq (p[0], "dhcp-internal") && p[1] && !p[2]) /* 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); - 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 */ + 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], "register-dns") && !p[1]) + else if (streq(p[0], "register-dns") && !p[1]) { - VERIFY_PERMISSION (OPT_P_IPWIN32); - options->tuntap_options.register_dns = true; + VERIFY_PERMISSION(OPT_P_IPWIN32); + options->tuntap_options.register_dns = true; } - else if (streq (p[0], "block-outside-dns") && !p[1]) + else if (streq(p[0], "block-outside-dns") && !p[1]) { - VERIFY_PERMISSION (OPT_P_IPWIN32); - options->block_outside_dns = true; + VERIFY_PERMISSION(OPT_P_IPWIN32); + options->block_outside_dns = true; } - 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) - */ + 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) + */ { - 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); + 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 */ } - else if (streq (p[0], "show-valid-subnets") && !p[1]) + 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 */ + 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") && !p[1]) + else if (streq(p[0], "pause-exit") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - set_pause_exit_win32 (); + VERIFY_PERMISSION(OPT_P_GENERAL); + set_pause_exit_win32(); } - else if (streq (p[0], "service") && p[1] && !p[3]) + else if (streq(p[0], "service") && p[1] && !p[3]) { - 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_GENERAL); + options->exit_event_name = p[1]; + if (p[2]) + { + options->exit_event_initial_state = (atoi(p[2]) != 0); + } } - else if (streq (p[0], "allow-nonadmin") && !p[2]) + 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 */ + 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] && !p[2]) + 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"); + VERIFY_PERMISSION(OPT_P_GENERAL); + msg(M_WARN, "NOTE: --user option is not implemented on Windows"); } - else if (streq (p[0], "group") && p[1] && !p[2]) + 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"); + 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] && !p[2]) +#else /* ifdef _WIN32 */ + else if (streq(p[0], "user") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->username = p[1]; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->username = p[1]; } - else if (streq (p[0], "group") && p[1] && !p[2]) + else if (streq(p[0], "group") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->groupname = p[1]; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->groupname = p[1]; } - else if (streq (p[0], "dhcp-option") && p[1] && !p[3]) + else if (streq(p[0], "dhcp-option") && p[1] && !p[3]) { - VERIFY_PERMISSION (OPT_P_IPWIN32); - foreign_option (options, p, 3, es); + VERIFY_PERMISSION(OPT_P_IPWIN32); + foreign_option(options, p, 3, es); } - else if (streq (p[0], "route-method") && p[1] && !p[2]) /* 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); + VERIFY_PERMISSION(OPT_P_ROUTE_EXTRAS); } -#endif +#endif /* ifdef _WIN32 */ #if PASSTOS_CAPABILITY - else if (streq (p[0], "passtos") && !p[1]) + else if (streq(p[0], "passtos") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->passtos = true; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->passtos = true; } #endif #if defined(USE_COMP) - else if (streq (p[0], "comp-lzo") && !p[2]) + else if (streq(p[0], "comp-lzo") && !p[2]) { - VERIFY_PERMISSION (OPT_P_COMP); + VERIFY_PERMISSION(OPT_P_COMP); #if defined(ENABLE_LZO) - if (p[1] && streq (p[1], "no")) + if (p[1] && streq(p[1], "no")) #endif - { - options->comp.alg = COMP_ALG_STUB; - options->comp.flags = 0; - } + { + 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; - } + 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], "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; - } + 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[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; + } } #endif /* USE_COMP */ #ifdef ENABLE_CRYPTO - else if (streq (p[0], "show-ciphers") && !p[1]) + else if (streq(p[0], "show-ciphers") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->show_ciphers = true; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->show_ciphers = true; } - else if (streq (p[0], "show-digests") && !p[1]) + else if (streq(p[0], "show-digests") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->show_digests = true; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->show_digests = true; } - else if (streq (p[0], "show-engines") && !p[1]) + else if (streq(p[0], "show-engines") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->show_engines = true; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->show_engines = true; } - else if (streq (p[0], "key-direction") && p[1] && !p[2]) + else if (streq(p[0], "key-direction") && p[1] && !p[2]) { - int key_direction; + 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], "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]; + key_direction = ascii2keydirection(msglevel, p[1]); + if (key_direction >= 0) + { + options->key_direction = key_direction; + } + else + { + goto err; + } } - else if (streq (p[0], "cipher") && p[1] && !p[2]) + else if (streq(p[0], "secret") && p[1] && !p[3]) { - VERIFY_PERMISSION (OPT_P_NCP); - options->ciphername = 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], "ncp-ciphers") && p[1] && !p[2]) + else if (streq(p[0], "genkey") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_INSTANCE); - options->ncp_ciphers = p[1]; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->genkey = true; } - else if (streq (p[0], "ncp-disable") && !p[1]) + else if (streq(p[0], "auth") && p[1] && !p[2]) { - VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_INSTANCE); - options->ncp_enabled = false; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->authname = p[1]; } - else if (streq (p[0], "prng") && p[1] && !p[3]) + else if (streq(p[0], "cipher") && 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_NCP); + options->ciphername = p[1]; + } + else if (streq(p[0], "ncp-ciphers") && p[1] && !p[2]) + { + 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|OPT_P_INSTANCE); + options->ncp_enabled = false; + } + else if (streq(p[0], "prng") && p[1] && !p[3]) + { + 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], "no-replay") && !p[1]) + else if (streq(p[0], "no-replay") && !p[1]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - options->replay = false; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->replay = false; } - else if (streq (p[0], "replay-window") && !p[3]) + else if (streq(p[0], "replay-window") && !p[3]) { - VERIFY_PERMISSION (OPT_P_GENERAL); - if (p[1]) - { - int replay_window; + 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]) + 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->use_iv = false; + VERIFY_PERMISSION(OPT_P_GENERAL); + options->mute_replay_warnings = true; } - 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; + else if (streq(p[0], "no-iv") && !p[1]) + { + 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; } #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"; - } + 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) { - char *endp = NULL; - int i = strtol(provider, &endp, 10); + provider = DEFAULT_PKCS11_MODULE; + } + else if (!p[2]) + { + 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; - for (j = 1; j < MAX_PARMS && p[j] != NULL; ++j) - options->pkcs11_providers[j-1] = p[j]; + 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")) + 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; + + 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])); + 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 067728a..b3ab029 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 2c1e5b1..22abda0 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 c0b0f38..eede63d 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 9874519..fe13e1d 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 fb059b7..ecc25a6 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 910d171..51e051a 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 c531d9c..f0430a1 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 6b5dcb2..a0f5cc7 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 a3208db..56b6858 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 04adf0e..3832683 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 c724970..2fa1d5c 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 6dc0b4e..0496b72 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 88f5f3a..e839ce7 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 2621058..6858846 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 b49401c..3747d3a 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 7b7ec45..9606899 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. <sales@openvpn.net> - * Copyright (C) 2010 Fox Crypto B.V. <openvpn@fox-it.com> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> + * Copyright (C) 2010-2017 Fox Crypto B.V. <openvpn@fox-it.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 e208b61..bdca893 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. <sales@openvpn.net> - * Copyright (C) 2010 Fox Crypto B.V. <openvpn@fox-it.com> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> + * Copyright (C) 2010-2017 Fox Crypto B.V. <openvpn@fox-it.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 87eb166..6244cc7 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. <sales@openvpn.net> - * Copyright (C) 2010 Fox Crypto B.V. <openvpn@fox-it.com> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> + * Copyright (C) 2010-2017 Fox Crypto B.V. <openvpn@fox-it.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 6343647..952d633 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 fe2685a..62396a9 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 2443438..17eb2d8 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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<<OPENVPN_PLUGIN_N)-1); + return ((1<<OPENVPN_PLUGIN_N)-1); } struct plugin_option_list * -plugin_option_list_new (struct gc_arena *gc) +plugin_option_list_new(struct gc_arena *gc) { - struct plugin_option_list *ret; - ALLOC_OBJ_CLEAR_GC (ret, struct plugin_option_list, gc); - return ret; + struct plugin_option_list *ret; + ALLOC_OBJ_CLEAR_GC(ret, struct plugin_option_list, gc); + return ret; } bool -plugin_option_list_add (struct plugin_option_list *list, char **p, struct gc_arena *gc) +plugin_option_list_add(struct plugin_option_list *list, char **p, struct gc_arena *gc) { - if (list->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 b1e0458..4ded529 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 28c26b4..aa0bc2b 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 fc9d6ab..c3e1190 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 7b58e6a..40e0714 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 07612c8..bfcb36d 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 0f78020..dd327a2 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 7d2581c..c20a676 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 2cb68f1..21b12ca 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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<<P_OPCODE_SHIFT); + return p[0] == 0 + && p[1] >= 14 + && p[2] == (P_CONTROL_HARD_RESET_CLIENT_V2<<P_OPCODE_SHIFT); } - else if (len >= 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 e8919d4..0fc1ee4 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * 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,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 9953079..f515475 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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,451 @@ 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) +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))) + 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 (strprefix(line, "peer-id ")) + { + 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 -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, + &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); + 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 +769,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 1dfd80e..86900c8 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 b252676..58fc870 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 22883a7..57cdd78 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 828dcd3..455168a 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 fec12c1..0c93dcd 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -46,77 +46,83 @@ #include "memdbg.h" #if defined(TARGET_LINUX) || defined(TARGET_ANDROID) -#include <linux/rtnetlink.h> /* RTM_GETROUTE etc. */ +#include <linux/rtnetlink.h> /* 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); + special.s_addr = htonl(special.s_addr); + ret = openvpn_getaddrinfo(0, inet_ntoa(special), 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); } - 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; + r->netmask = getaddr( + GETADDR_HOST_ORDER + | GETADDR_WARN_ON_SIGNAL, + ro->netmask, + 0, + &status, + NULL); + if (!status) + { + goto fail; + } + } + else + { + 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 */ - /* 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; + 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; + } #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 <sys/types.h> #include <sys/socket.h> @@ -3215,8 +3508,8 @@ get_default_gateway_ipv6(struct route_ipv6_gateway_info *rgi6, #include <net/if_dl.h> 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 c358681..03ee8cd 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 471330f..610bfa4 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 71c6d8c..f2a6813 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 0ebff65..b23f0f4 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 2a1f41f..2b0ceb8 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 c8a7d38..eb459ef 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 fa132c4..d97221a 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 b3ae645..9f4841a 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 2875a4c..5783731 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 c233f2b..ae12832 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 (string_class(dotted_quad, CC_DIGIT|CC_DOT, 0)) + { + return OIA_ERROR; /* probably a badly formatted dotted quad */ + } + else { - 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 */ - } + 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; + } + } + } - /* 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; + /* 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,140 +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 - return sd; + /* set socket file descriptor to not pass across execs, so that + * scripts don't have access to it */ + set_cloexec(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 - return sd; +#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); + + 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 @@ -892,434 +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; + 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"); } -#else - 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); + } + /* only valid if we have remote_len_af!=0 */ + else if (remote_len_af && remote_len != remote_len_af) { - msg (D_LINK_ERRORS | M_ERRNO, "TCP: accept(%d) failed", sd); + 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; } - /* only valid if we have remote_len_af!=0 */ - else if (remote_len_af && remote_len != remote_len_af) + else { - 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; + /* 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->ai_family == ai_family) + { + break; + } + } + if (!cur) + { + 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 } } @@ -1329,798 +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; + 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 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); + /* 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); + argv_parse_cmd(argv, info->ipchange_command); + argv_printf_cat(argv, "%s", host); + } + else + { + 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 ... @@ -2129,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 @@ -2152,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); } /* @@ -2204,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); } /* @@ -2358,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 } @@ -2374,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 @@ -2447,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]"; } /* @@ -2510,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); } /* @@ -2530,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); } /* @@ -2664,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 @@ -2706,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"; } /* @@ -2795,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 */ } /* @@ -2818,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); } /* @@ -2830,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 @@ -2870,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. @@ -3074,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 */ @@ -3412,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; } } @@ -3461,117 +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"); - return sd; + 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; } 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); - return ret; + 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; } 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 2a82d88..63e601e 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 5a9ea6c..b50cac3 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 a2843b9..17e75e1 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 34d163f..cff4052 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. <sales@openvpn.net> - * Copyright (C) 2010 Fox Crypto B.V. <openvpn@fox-it.com> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> + * Copyright (C) 2010-2017 Fox Crypto B.V. <openvpn@fox-it.com> * Copyright (C) 2008-2013 David Sommerseth <dazo@users.sourceforge.net> * * This program is free software; you can redistribute it and/or modify @@ -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,69 +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; - 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; +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 } @@ -905,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 */ @@ -953,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 - ); + ); } @@ -991,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; - /* 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); + /* 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) + /* 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); } /** @@ -1054,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 */ @@ -1081,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); } /* @@ -1113,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; + } } /* @@ -1125,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]); + } } /* @@ -1186,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); } /* @@ -1221,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 } @@ -1236,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); } @@ -1288,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 @@ -1341,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; } /* @@ -1457,113 +1551,113 @@ cleanup: */ 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); } /* @@ -1587,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; i<olen; i++) - out1[i]^=out2[i]; + for (i = 0; i<olen; i++) + out1[i] ^= out2[i]; - secure_memzero (out2, olen); + secure_memzero(out2, olen); - dmsg (D_SHOW_KEY_SOURCE, "tls1_PRF out[%d]: %s", olen, format_hex (out1, olen, 0, &gc)); + dmsg(D_SHOW_KEY_SOURCE, "tls1_PRF out[%d]: %s", olen, format_hex(out1, olen, 0, &gc)); - gc_free (&gc); + gc_free(&gc); } static void -openvpn_PRF (const uint8_t *secret, - int secret_len, - const char *label, - const uint8_t *client_seed, - int client_seed_len, - const uint8_t *server_seed, - int server_seed_len, - const struct session_id *client_sid, - const struct session_id *server_sid, - uint8_t *output, - int output_len) +openvpn_PRF(const uint8_t *secret, + int secret_len, + const char *label, + const uint8_t *client_seed, + int client_seed_len, + const uint8_t *server_seed, + int server_seed_len, + const struct session_id *client_sid, + const struct session_id *server_sid, + uint8_t *output, + int output_len) { - /* concatenate seed components */ + /* concatenate seed components */ - struct buffer seed = alloc_buf (strlen (label) - + client_seed_len - + server_seed_len - + SID_SIZE * 2); + struct buffer seed = alloc_buf(strlen(label) + + client_seed_len + + server_seed_len + + SID_SIZE * 2); - ASSERT (buf_write (&seed, label, strlen (label))); - ASSERT (buf_write (&seed, client_seed, client_seed_len)); - ASSERT (buf_write (&seed, server_seed, server_seed_len)); + ASSERT(buf_write(&seed, label, strlen(label))); + ASSERT(buf_write(&seed, client_seed, client_seed_len)); + ASSERT(buf_write(&seed, server_seed, server_seed_len)); - if (client_sid) - ASSERT (buf_write (&seed, client_sid->id, 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); + } } } @@ -1814,161 +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); - - 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_and &= ~(CO_PACKET_ID_LONG_FORM); - if (packet_id_long_form) - session->opt->crypto_flags_and = 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; } /* @@ -1976,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; + 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) +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) + { + return NULL; + } + str = (char *) malloc(len); + check_malloc_return(str); + if (!buf_read(buf, str, len)) { - free (str); - return NULL; + free(str); + return NULL; } - str[len-1] = '\0'; - return str; + 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); + } } /* @@ -2041,461 +2180,491 @@ 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"); - - 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) { - /* 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; - } - } + /* 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; + } + } - 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; } /* @@ -2508,382 +2677,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; } /* @@ -2894,154 +3078,168 @@ error: */ 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; } /* @@ -3075,456 +3273,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; } /* @@ -3539,191 +3746,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; } } @@ -3733,129 +3944,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; } /* @@ -3863,99 +4084,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 c971b75..ed1344e 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. <sales@openvpn.net> - * Copyright (C) 2010 Fox Crypto B.V. <openvpn@fox-it.com> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> + * Copyright (C) 2010-2017 Fox Crypto B.V. <openvpn@fox-it.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 3fbd2b4..206400f 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. <sales@openvpn.net> - * Copyright (C) 2010 Fox Crypto B.V. <openvpn@fox-it.com> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> + * Copyright (C) 2010-2017 Fox Crypto B.V. <openvpn@fox-it.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 7938f41..9a16d77 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. <sales@openvpn.net> - * Copyright (C) 2010 Fox Crypto B.V. <openvpn@fox-it.com> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> + * Copyright (C) 2010-2017 Fox Crypto B.V. <openvpn@fox-it.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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,131 +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; - unsigned int crypto_flags_and; - unsigned int crypto_flags_or; - - 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 @@ -385,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 @@ -479,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 11ee65b..5c84e30 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. <sales@openvpn.net> - * Copyright (C) 2010 Fox Crypto B.V. <openvpn@fox-it.com> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> + * Copyright (C) 2010-2017 Fox Crypto B.V. <openvpn@fox-it.com> * Copyright (C) 2006-2010, Brainspark B.V. * * This program is free software; you can redistribute it and/or modify @@ -51,11 +51,17 @@ #include "ssl_verify_mbedtls.h" #include <mbedtls/debug.h> #include <mbedtls/error.h> -#include <mbedtls/net.h> +#include <mbedtls/version.h> + +#if MBEDTLS_VERSION_NUMBER >= 0x02040000 + #include <mbedtls/net_sockets.h> +#else + #include <mbedtls/net.h> +#endif + #include <mbedtls/oid.h> #include <mbedtls/pem.h> #include <mbedtls/sha256.h> -#include <mbedtls/version.h> void tls_init_lib() @@ -75,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; } } @@ -150,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 @@ -161,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; }; /** @@ -402,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) + { + out_b64 = management_query_rsa_sig(management, in_b64); + } + if (!out_b64) { - rv = MBEDTLS_ERR_RSA_PRIVATE_FAILED; - goto done; + 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); + } } } @@ -596,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)); + } } } @@ -728,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 } @@ -740,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; } /* ************************************** @@ -1135,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 * @@ -1219,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 a4a7f05..1bc53ce 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. <sales@openvpn.net> - * Copyright (C) 2010 Fox Crypto B.V. <openvpn@fox-it.com> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> + * Copyright (C) 2010-2017 Fox Crypto B.V. <openvpn@fox-it.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 4f472ff..eae1e22 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. <sales@openvpn.net> - * Copyright (C) 2010 Fox Crypto B.V. <openvpn@fox-it.com> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> + * Copyright (C) 2010-2017 Fox Crypto B.V. <openvpn@fox-it.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 @@ end: 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 115ac43..c64c65f 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. <sales@openvpn.net> - * Copyright (C) 2010 Fox Crypto B.V. <openvpn@fox-it.com> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> + * Copyright (C) 2010-2017 Fox Crypto B.V. <openvpn@fox-it.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 4328828..334eb29 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. <sales@openvpn.net> - * Copyright (C) 2010 Fox Crypto B.V. <openvpn@fox-it.com> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> + * Copyright (C) 2010-2017 Fox Crypto B.V. <openvpn@fox-it.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 KU ERROR"); - return FAILURE; /* Reject connection */ - } + 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 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 @@ cleanup: #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; + } + if (client_reason && strlen(client_reason)) { - free (multi->client_reason); - multi->client_reason = NULL; + /* 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,311 @@ 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 /* 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; } -#endif + /* * 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; + wipe_auth_token(multi); + 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"); + wipe_auth_token(multi); + 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]" : ""); + wipe_auth_token(multi); + 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 + */ + 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", - 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 98312fd..ffab218 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. <sales@openvpn.net> - * Copyright (C) 2010 Fox Crypto B.V. <openvpn@fox-it.com> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> + * Copyright (C) 2010-2017 Fox Crypto B.V. <openvpn@fox-it.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 de304b9..c4330ba 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. <sales@openvpn.net> - * Copyright (C) 2010 Fox Crypto B.V. <openvpn@fox-it.com> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> + * Copyright (C) 2010-2017 Fox Crypto B.V. <openvpn@fox-it.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 4260823..f01569f 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. <sales@openvpn.net> - * Copyright (C) 2010 Fox Crypto B.V. <openvpn@fox-it.com> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> + * Copyright (C) 2010-2017 Fox Crypto B.V. <openvpn@fox-it.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 && 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; - } - } - } + int i; + unsigned nku = cert->key_usage; + + msg(D_HANDSHAKE, "Validating certificate key usage"); + for (i = 0; SUCCESS != fFound && 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; + } + } + } } - return fFound; + return fFound; } result_t -x509_verify_cert_eku (mbedtls_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; + result_t fFound = FAILURE; - if (!(cert->ext_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 e26d08f..3c71073 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. <sales@openvpn.net> - * Copyright (C) 2010 Fox Crypto B.V. <openvpn@fox-it.com> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> + * Copyright (C) 2010-2017 Fox Crypto B.V. <openvpn@fox-it.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 3d1c85e..e9692a0 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. <sales@openvpn.net> - * Copyright (C) 2010 Fox Crypto B.V. <openvpn@fox-it.com> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> + * Copyright (C) 2010-2017 Fox Crypto B.V. <openvpn@fox-it.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -48,117 +48,123 @@ #include <openssl/err.h> 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; i<numalts; i++) + /* loop through all alternatives */ + for (i = 0; i<numalts; i++) { - /* get a handle to alternative name number i */ - const GENERAL_NAME *name = sk_GENERAL_NAME_value (extensions, i ); + /* get a handle to alternative name number i */ + const GENERAL_NAME *name = sk_GENERAL_NAME_value(extensions, i ); - switch (name->type) + 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 @@ err: */ 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 5a7e0a1..1db6fe6 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. <sales@openvpn.net> - * Copyright (C) 2010 Fox Crypto B.V. <openvpn@fox-it.com> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> + * Copyright (C) 2010-2017 Fox Crypto B.V. <openvpn@fox-it.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 b7ff484..e47f35c 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 af16fd2..590ae41 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 f5008b7..a1b6047 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 <sys/wait.h> +#include <sys/wait.h> #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 <naptypes.h> #include <ntddndis.h> #include <iphlpapi.h> @@ -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 d40532e..c227b09 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. <openvpn@fox-it.com> + * Copyright (C) 2016-2017 Fox Crypto B.V. <openvpn@fox-it.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 d1962c9..47f75d0 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. <openvpn@fox-it.com> + * Copyright (C) 2016-2017 Fox Crypto B.V. <openvpn@fox-it.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 572e168..f812844 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * 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,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 <stropts.h> #endif @@ -216,46 +223,63 @@ static void solaris_error_close (struct tuntap *tt, const struct env_set *es, co #include <sys/sys_domain.h> #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,712 +853,756 @@ 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)); + } + + 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)); #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 - ); - } + /* 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", + { + argv_printf(&argv, + " %s %s %s netmask %s broadcast + up", + IFCONFIG_PATH, + actual, + ifconfig_local, + ifconfig_remote_netmask + ); + } + + 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_local, - ifconfig_remote_netmask + 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); + } + } - 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; + 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; #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 - * 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; + 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; #elif defined(TARGET_NETBSD) - 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; + 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"); - } + /* + * 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); - } + { + /* 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); + { + 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); + gc_free(&gc); } static void -clear_tuntap (struct tuntap *tuntap) +clear_tuntap(struct tuntap *tuntap) { - CLEAR (*tuntap); + CLEAR(*tuntap); #ifdef _WIN32 - tuntap->hand = NULL; + tuntap->hand = NULL; #else - tuntap->fd = -1; + tuntap->fd = -1; #endif #ifdef TARGET_SOLARIS - tuntap->ip_fd = -1; + tuntap->ip_fd = -1; #endif } static void -open_null (struct tuntap *tt) +open_null(struct tuntap *tt) { - tt->actual_name = string_alloc ("null", NULL); + tt->actual_name = string_alloc("null", NULL); } @@ -1529,19 +1630,23 @@ open_null (struct tuntap *tt) #include <sys/uio.h> static inline int -header_modify_read_write_return (int len) +header_modify_read_write_return(int len) { if (len > 0) - return len > sizeof (u_int32_t) ? len - sizeof (u_int32_t) : 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) +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; @@ -1549,236 +1654,261 @@ write_tun_header (struct tuntap* tt, uint8_t *buf, int len) iph = (struct ip *) buf; if (iph->ip_v == 6) - type = htonl (AF_INET6); + { + type = htonl(AF_INET6); + } else - type = htonl (AF_INET); + { + type = htonl(AF_INET); + } iv[0].iov_base = &type; - iv[0].iov_len = sizeof (type); + iv[0].iov_len = sizeof(type); iv[1].iov_base = buf; iv[1].iov_len = len; - return header_modify_read_write_return (writev (tt->fd, iv, 2)); - } + return header_modify_read_write_return(writev(tt->fd, iv, 2)); + } else - return write (tt->fd, buf, len); + { + return write(tt->fd, buf, len); + } } int -read_tun_header (struct tuntap* tt, uint8_t *buf, int len) +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[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(readv(tt->fd, iv, 2)); + } else - return read (tt->fd, buf, len); + { + return read(tt->fd, buf, len); + } } -#endif +#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; + + 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); + 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) { - struct platform_state_user platform_state_user; + msg(M_ERR, "Cannot ioctl TUNSETPERSIST(%d) %s", persist_mode, dev); + } + if (username != NULL) + { + 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; + } + else if (tt->type == DEV_TYPE_TAP) { - 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/tap"; + } + arp_node = dev_node; + dev_tuntap_type = "tap"; + link_type = I_PLINK; /* was: I_LINK */ + is_tun = false; } - else if (tt->type == DEV_TYPE_TAP) + else { - 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; + msg(M_FATAL, "I don't recognize device %s as a tun or tap device", + dev); } - else + + if ((tt->ip_fd = open(ip_node, O_RDWR, 0)) < 0) { - msg (M_FATAL, "I don't recognize device %s as a tun or tap device", - dev); + 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); + 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) { - 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 dragonfly_modify_read_write_return (writev (tt->fd, iv, 2)); + return dragonfly_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 dragonfly_modify_read_write_return (readv (tt->fd, iv, 2)); + return dragonfly_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_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+<digits>" *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+<digits>" *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); - /* The actual_name output buffer may be NULL */ - if (actual_name) + /* Make sure we have at least one TAP adapter */ + if (!tap_reg) { - ASSERT (actual_name_size > 0); - buf_set_write (&actual, actual_name, actual_name_size); + return NULL; } - /* Move on to specified device number */ - for (i = 0; i < device_number; i++) + /* The actual_name output buffer may be NULL */ + if (actual_name) { - tap_reg = tap_reg->next; - if (!tap_reg) - return NULL; + ASSERT(actual_name_size > 0); + buf_set_write(&actual, actual_name, actual_name_size); } - /* Save Network Panel name (if exists) in actual_name */ - if (actual_name) + /* Move on to specified device number */ + for (i = 0; i < device_number; i++) { - 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); + tap_reg = tap_reg->next; + if (!tap_reg) + { + return NULL; + } } - /* Save GUID for return value */ - ret = alloc_buf_gc (256, gc); - buf_printf (&ret, "%s", tap_reg->guid); - return BSTR (&ret); + /* 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); + } + } + + /* 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(); - /* The actual_name output buffer may be NULL */ - if (actual_name) + /* Make sure we have at least one TAP adapter */ + if (!tap_reg) { - ASSERT (actual_name_size > 0); - buf_set_write (&actual, actual_name, actual_name_size); + return NULL; } - /* Check if GUID was explicitly specified as --dev-node parameter */ - if (is_tap_win (name, tap_reg)) + /* The actual_name output buffer may be NULL */ + if (actual_name) { - 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); + ASSERT(actual_name_size > 0); + buf_set_write(&actual, actual_name, actual_name_size); } - /* 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); - } - } + /* 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); + } - return NULL; + /* 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; } /* * 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) { - 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); + index = get_adapter_index_method_2(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; + 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) + { + msg(M_INFO, "NOTE: could not get adapter index for name/GUID '%s'", name); + } + 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); + at_least_one_tap_win(tap_reg); - if (dev_node) + if (dev_node) { - guid = get_device_guid (dev_node, BPTR (&actual), BCAP (&actual), tap_reg, panel_reg, gc); + guid = get_device_guid(dev_node, BPTR(&actual), BCAP(&actual), tap_reg, panel_reg, gc); } - else + else { - guid = get_unspecified_device_guid (0, BPTR (&actual), BCAP (&actual), tap_reg, panel_reg, gc); + 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; + if (get_unspecified_device_guid(1, NULL, 0, tap_reg, panel_reg, gc)) /* ambiguous if more than one TAP-Windows adapter */ + { + guid = NULL; + } } - 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 */ + 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; - fork_to_self (BSTR (&cmd)); - gc_free (&gc); + 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); } } 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] ); + } + } - /* tap driver 9.8 (2.2.0 and 2.2.1 release) is buggy + /* 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->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 9b5a1b7..f4b600c 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 00bc7ac..e26f54d 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 11e42f4..4ee44fd 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. <sales@openvpn.net> + * Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -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 */ |