The Great Reformatting - first phase

This is the first commit of the big reformatting task.  This
is performed by running the ./dev-tools/reformat-all.sh script.

This is based upon the v3 reformat-all.sh/uncrustify.conf version
which is now applied to git master.

Signed-off-by: David Sommerseth <davids@openvpn.net>
This commit is contained in:
David Sommerseth 2016-12-14 22:33:21 +01:00
parent 2417d55c49
commit 81d882d530
No known key found for this signature in database
GPG key ID: 86CF944C9671FDF2
204 changed files with 63438 additions and 55477 deletions

View file

@ -118,20 +118,20 @@
#define SIGUSR2 12
#define SIGTERM 15
typedef unsigned __int64 uint64_t;
typedef unsigned __int32 uint32_t;
typedef unsigned __int16 uint16_t;
typedef unsigned __int8 uint8_t;
typedef __int64 int64_t;
typedef __int32 int32_t;
typedef __int16 int16_t;
typedef __int8 int8_t;
typedef unsigned __int64 uint64_t;
typedef unsigned __int32 uint32_t;
typedef unsigned __int16 uint16_t;
typedef unsigned __int8 uint8_t;
typedef __int64 int64_t;
typedef __int32 int32_t;
typedef __int16 int16_t;
typedef __int8 int8_t;
#ifdef HAVE_CONFIG_MSVC_LOCAL_H
#include <config-msvc-local.h>
#endif
// Vista and above has implementation of inet_ntop / inet_pton
/* Vista and above has implementation of inet_ntop / inet_pton */
#if _WIN32_WINNT >= _WIN32_WINNT_VISTA
#define HAVE_INET_NTOP
#define HAVE_INET_PTON

File diff suppressed because it is too large Load diff

View file

@ -30,17 +30,22 @@
typedef struct _CertData
{
CFArrayRef subject;
CFArrayRef issuer;
CFStringRef serial;
CFStringRef md5, sha1;
CFArrayRef subject;
CFArrayRef issuer;
CFStringRef serial;
CFStringRef md5, sha1;
} CertData, *CertDataRef;
CertDataRef createCertDataFromCertificate(SecCertificateRef certificate);
CertDataRef createCertDataFromString(const char *description);
void destroyCertData(CertDataRef pCertData);
bool certDataMatchesTemplate(CertDataRef pCertData, CertDataRef pTemplate);
void printCertData(CertDataRef pCertData);
SecIdentityRef findIdentity(CertDataRef pCertDataTemplate);
#endif
#endif /* ifndef __cert_data_h__ */

View file

@ -24,71 +24,78 @@
*/
/*
#include "config.h"
#include "syshead.h"
#include "common.h"
#include "buffer.h"
#include "error.h"
*/
#include "config.h"
#include "syshead.h"
#include "common.h"
#include "buffer.h"
#include "error.h"
*/
#include "common_osx.h"
#include <err.h>
void printCFString(CFStringRef str)
void
printCFString(CFStringRef str)
{
CFIndex bufferLength = CFStringGetLength(str) + 1;
char *pBuffer = (char*)malloc(sizeof(char) * bufferLength);
CFStringGetCString(str, pBuffer, bufferLength, kCFStringEncodingUTF8);
warnx("%s\n", pBuffer);
free(pBuffer);
CFIndex bufferLength = CFStringGetLength(str) + 1;
char *pBuffer = (char *)malloc(sizeof(char) * bufferLength);
CFStringGetCString(str, pBuffer, bufferLength, kCFStringEncodingUTF8);
warnx("%s\n", pBuffer);
free(pBuffer);
}
char* cfstringToCstr(CFStringRef str)
char *
cfstringToCstr(CFStringRef str)
{
CFIndex bufferLength = CFStringGetLength(str) + 1;
char *pBuffer = (char*)malloc(sizeof(char) * bufferLength);
CFStringGetCString(str, pBuffer, bufferLength, kCFStringEncodingUTF8);
return pBuffer;
CFIndex bufferLength = CFStringGetLength(str) + 1;
char *pBuffer = (char *)malloc(sizeof(char) * bufferLength);
CFStringGetCString(str, pBuffer, bufferLength, kCFStringEncodingUTF8);
return pBuffer;
}
void appendHexChar(CFMutableStringRef str, unsigned char halfByte)
void
appendHexChar(CFMutableStringRef str, unsigned char halfByte)
{
if (halfByte < 10)
if (halfByte < 10)
{
CFStringAppendFormat (str, NULL, CFSTR("%d"), halfByte);
CFStringAppendFormat(str, NULL, CFSTR("%d"), halfByte);
}
else
else
{
char tmp[2] = {'A'+halfByte-10, 0};
CFStringAppendCString(str, tmp, kCFStringEncodingUTF8);
char tmp[2] = {'A'+halfByte-10, 0};
CFStringAppendCString(str, tmp, kCFStringEncodingUTF8);
}
}
CFStringRef createHexString(unsigned char *pData, int length)
CFStringRef
createHexString(unsigned char *pData, int length)
{
unsigned char byte, low, high;
int i;
CFMutableStringRef str = CFStringCreateMutable(NULL, 0);
unsigned char byte, low, high;
int i;
CFMutableStringRef str = CFStringCreateMutable(NULL, 0);
for(i = 0;i < length;i++)
for (i = 0; i < length; i++)
{
byte = pData[i];
low = byte & 0x0F;
high = (byte >> 4);
byte = pData[i];
low = byte & 0x0F;
high = (byte >> 4);
appendHexChar(str, high);
appendHexChar(str, low);
appendHexChar(str, high);
appendHexChar(str, low);
if (i != (length - 1))
CFStringAppendCString(str, " ", kCFStringEncodingUTF8);
if (i != (length - 1))
{
CFStringAppendCString(str, " ", kCFStringEncodingUTF8);
}
}
return str;
return str;
}
void printHex(unsigned char *pData, int length)
void
printHex(unsigned char *pData, int length)
{
CFStringRef hexStr = createHexString(pData, length);
printCFString(hexStr);
CFRelease(hexStr);
CFStringRef hexStr = createHexString(pData, length);
printCFString(hexStr);
CFRelease(hexStr);
}

View file

@ -29,8 +29,11 @@
#include <CoreFoundation/CoreFoundation.h>
void printCFString(CFStringRef str);
char* cfstringToCstr(CFStringRef str);
char *cfstringToCstr(CFStringRef str);
CFStringRef createHexString(unsigned char *pData, int length);
void printHex(unsigned char *pData, int length);
#endif //__Common_osx_h__
#endif /*__Common_osx_h__ */

View file

@ -31,45 +31,50 @@
#include "crypto_osx.h"
#include <err.h>
void printErrorMsg(const char *func, CFErrorRef error)
void
printErrorMsg(const char *func, CFErrorRef error)
{
CFStringRef desc = CFErrorCopyDescription(error);
warnx("%s failed: %s", func, CFStringGetCStringPtr(desc, kCFStringEncodingUTF8));
CFRelease(desc);
CFStringRef desc = CFErrorCopyDescription(error);
warnx("%s failed: %s", func, CFStringGetCStringPtr(desc, kCFStringEncodingUTF8));
CFRelease(desc);
}
void printErrorStatusMsg(const char *func, OSStatus status)
void
printErrorStatusMsg(const char *func, OSStatus status)
{
CFStringRef error;
error = SecCopyErrorMessageString(status, NULL);
if (error)
CFStringRef error;
error = SecCopyErrorMessageString(status, NULL);
if (error)
{
warnx("%s failed: %s", func, CFStringGetCStringPtr(error, kCFStringEncodingUTF8));
CFRelease(error);
warnx("%s failed: %s", func, CFStringGetCStringPtr(error, kCFStringEncodingUTF8));
CFRelease(error);
}
else
{
warnx("%s failed: %X", func, (int)status);
}
else
warnx("%s failed: %X", func, (int)status);
}
void signData(SecIdentityRef identity, const uint8_t *from, int flen, uint8_t *to, size_t *tlen)
void
signData(SecIdentityRef identity, const uint8_t *from, int flen, uint8_t *to, size_t *tlen)
{
SecKeyRef privateKey = NULL;
OSStatus status;
SecKeyRef privateKey = NULL;
OSStatus status;
status = SecIdentityCopyPrivateKey(identity, &privateKey);
if (status != noErr)
status = SecIdentityCopyPrivateKey(identity, &privateKey);
if (status != noErr)
{
printErrorStatusMsg("signData: SecIdentityCopyPrivateKey", status);
*tlen = 0;
return;
printErrorStatusMsg("signData: SecIdentityCopyPrivateKey", status);
*tlen = 0;
return;
}
status = SecKeyRawSign(privateKey, kSecPaddingPKCS1, from, flen, to, tlen);
CFRelease(privateKey);
if (status != noErr)
status = SecKeyRawSign(privateKey, kSecPaddingPKCS1, from, flen, to, tlen);
CFRelease(privateKey);
if (status != noErr)
{
printErrorStatusMsg("signData: SecKeyRawSign", status);
*tlen = 0;
return;
printErrorStatusMsg("signData: SecKeyRawSign", status);
*tlen = 0;
return;
}
}

View file

@ -29,16 +29,17 @@
#include <CoreFoundation/CoreFoundation.h>
#include <Security/Security.h>
extern OSStatus SecKeyRawSign (
SecKeyRef key,
SecPadding padding,
const uint8_t *dataToSign,
size_t dataToSignLen,
uint8_t *sig,
size_t *sigLen
);
extern OSStatus SecKeyRawSign(
SecKeyRef key,
SecPadding padding,
const uint8_t *dataToSign,
size_t dataToSignLen,
uint8_t *sig,
size_t *sigLen
);
void signData(SecIdentityRef identity, const uint8_t *from, int flen, uint8_t *to, size_t *tlen);
void printErrorMsg(const char *func, CFErrorRef error);
#endif //__crypto_osx_h__
#endif /*__crypto_osx_h__ */

View file

@ -38,36 +38,44 @@
#include "../../src/openvpn/base64.h"
SecIdentityRef template_to_identity(const char *template)
SecIdentityRef
template_to_identity(const char *template)
{
SecIdentityRef identity;
CertDataRef pCertDataTemplate = createCertDataFromString(template);
if (pCertDataTemplate == NULL)
{
errx(1, "Bad certificate template");
}
identity = findIdentity(pCertDataTemplate);
if (identity == NULL)
{
errx(1, "No such identify");
}
fprintf(stderr, "Identity found\n");
destroyCertData(pCertDataTemplate);
return identity;
}
int connect_to_management_server(const char *ip, const char *port)
int
connect_to_management_server(const char *ip, const char *port)
{
int fd;
struct sockaddr_un addr_un;
struct sockaddr *addr;
size_t addr_len;
if (strcmp(port, "unix") == 0) {
addr = (struct sockaddr*)&addr_un;
if (strcmp(port, "unix") == 0)
{
addr = (struct sockaddr *)&addr_un;
addr_len = sizeof(addr_un);
addr_un.sun_family = AF_UNIX;
strncpy(addr_un.sun_path, ip, sizeof(addr_un.sun_path));
fd = socket(AF_UNIX, SOCK_STREAM, 0);
}
else {
else
{
int rv;
struct addrinfo *result;
struct addrinfo hints;
@ -78,9 +86,13 @@ int connect_to_management_server(const char *ip, const char *port)
rv = getaddrinfo(ip, port, &hints, &result);
if (rv < 0)
{
errx(1, "getaddrinfo: %s", gai_strerror(rv));
}
if (result == NULL)
{
errx(1, "getaddrinfo returned 0 addressed");
}
/* Use the first found address */
fd = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
@ -88,20 +100,26 @@ int connect_to_management_server(const char *ip, const char *port)
addr_len = result->ai_addrlen;
}
if (fd < 0)
{
err(1, "socket");
}
if (connect(fd, addr, addr_len) < 0)
{
err(1, "connect");
}
return fd;
}
int is_prefix(const char *s, const char *prefix)
int
is_prefix(const char *s, const char *prefix)
{
return strncmp(s, prefix, strlen(prefix)) == 0;
}
void handle_rsasign(FILE *man_file, SecIdentityRef identity, const char *input)
void
handle_rsasign(FILE *man_file, SecIdentityRef identity, const char *input)
{
const char *input_b64 = strchr(input, ':') + 1;
char *input_binary;
@ -114,13 +132,17 @@ void handle_rsasign(FILE *man_file, SecIdentityRef identity, const char *input)
input_binary = malloc(input_len);
input_len = openvpn_base64_decode(input_b64, input_binary, input_len);
if (input_len < 0)
{
errx(1, "openvpn_base64_decode: overflow");
}
output_len = 1024;
output_binary = malloc(output_len);
signData(identity, (const uint8_t *)input_binary, input_len, (uint8_t *)output_binary, &output_len);
if (output_len == 0)
{
errx(1, "handle_rsasign: failed to sign data");
}
openvpn_base64_encode(output_binary, output_len, &output_b64);
fprintf(man_file, "rsa-sig\n%s\nEND\n", output_b64);
@ -131,7 +153,8 @@ void handle_rsasign(FILE *man_file, SecIdentityRef identity, const char *input)
fprintf(stderr, "Handled RSA_SIGN command\n");
}
void handle_needcertificate(FILE *man_file, SecIdentityRef identity)
void
handle_needcertificate(FILE *man_file, SecIdentityRef identity)
{
OSStatus status;
SecCertificateRef certificate = NULL;
@ -141,14 +164,17 @@ void handle_needcertificate(FILE *man_file, SecIdentityRef identity)
char *result_b64, *tmp_b64;
status = SecIdentityCopyCertificate(identity, &certificate);
if (status != noErr) {
if (status != noErr)
{
const char *msg = GetMacOSStatusErrorString(status);
err(1, "SecIdentityCopyCertificate() failed: %s", msg);
}
data = SecCertificateCopyData(certificate);
if (data == NULL)
{
err(1, "SecCertificateCopyData() returned NULL");
}
cert = CFDataGetBytePtr(data);
cert_len = CFDataGetLength(data);
@ -162,11 +188,13 @@ void handle_needcertificate(FILE *man_file, SecIdentityRef identity)
fprintf(man_file, "-----BEGIN CERTIFICATE-----\n");
tmp_b64 = result_b64;
while (strlen(tmp_b64) > 64) {
fprintf(man_file, "%.64s\n", tmp_b64);
tmp_b64 += 64;
fprintf(man_file, "%.64s\n", tmp_b64);
tmp_b64 += 64;
}
if (*tmp_b64)
fprintf(man_file, "%s\n", tmp_b64);
{
fprintf(man_file, "%s\n", tmp_b64);
}
fprintf(man_file, "-----END CERTIFICATE-----\n");
fprintf(man_file, "END\n");
@ -177,62 +205,87 @@ void handle_needcertificate(FILE *man_file, SecIdentityRef identity)
fprintf(stderr, "Handled NEED 'cert' command\n");
}
void management_loop(SecIdentityRef identity, int man_fd, const char *password)
void
management_loop(SecIdentityRef identity, int man_fd, const char *password)
{
char *buffer = NULL;
size_t buffer_len = 0;
FILE *man = fdopen(man_fd, "w+");
if (man == 0)
{
err(1, "fdopen");
}
if (password)
{
fprintf(man, "%s\n", password);
}
while (1) {
if (getline(&buffer, &buffer_len, man) < 0)
{
err(1, "getline");
}
#if 0
fprintf(stderr, "M: %s", buffer);
#endif
if (is_prefix(buffer, ">RSA_SIGN:"))
{
handle_rsasign(man, identity, buffer);
if (is_prefix(buffer, ">NEED-CERTIFICATE")) {
if (!identity) {
}
if (is_prefix(buffer, ">NEED-CERTIFICATE"))
{
if (!identity)
{
const char prefix[] = ">NEED-CERTIFICATE:macosx-keychain:";
if (!is_prefix(buffer, prefix))
errx(1, "No identity template is passed via command line and " \
"NEED-CERTIFICATE management interface command " \
"misses 'macosx-keychain' prefix.");
{
errx(1, "No identity template is passed via command line and " \
"NEED-CERTIFICATE management interface command " \
"misses 'macosx-keychain' prefix.");
}
identity = template_to_identity(buffer+strlen(prefix));
}
handle_needcertificate(man, identity);
}
if (is_prefix(buffer, ">FATAL"))
{
fprintf(stderr, "Fatal message from OpenVPN: %s\n", buffer+7);
}
if (is_prefix(buffer, ">INFO"))
{
fprintf(stderr, "INFO message from OpenVPN: %s\n", buffer+6);
}
}
}
char *read_password(const char *fname)
char *
read_password(const char *fname)
{
char *password = NULL;
FILE *pwf = fopen(fname, "r");
size_t n = 0;
if (pwf == NULL)
{
errx(1, "fopen(%s) failed", fname);
}
if (getline(&password, &n, pwf) < 0)
{
err(1, "getline");
}
fclose(pwf);
return password;
}
int main(int argc, char* argv[])
int
main(int argc, char *argv[])
{
if (argc < 4)
{
err(1, "usage: %s <identity_template> <management_ip> <management_port> [<pw-file>]", argv[0]);
}
char *identity_template = argv[1];
char *s_ip = argv[2];
@ -240,14 +293,17 @@ int main(int argc, char* argv[])
char *password = NULL;
int man_fd;
if (argc > 4) {
if (argc > 4)
{
char *s_pw_file = argv[4];
password = read_password(s_pw_file);
}
SecIdentityRef identity = NULL;
if (strcmp(identity_template, "auto"))
{
identity = template_to_identity(identity_template);
}
man_fd = connect_to_management_server(s_ip, s_port);
fprintf(stderr, "Successfully connected to openvpn\n");

View file

@ -26,90 +26,90 @@
#define OPENVPN_MSG_H_
typedef enum {
msg_acknowledgement,
msg_add_address,
msg_del_address,
msg_add_route,
msg_del_route,
msg_add_dns_cfg,
msg_del_dns_cfg,
msg_add_nbt_cfg,
msg_del_nbt_cfg,
msg_flush_neighbors,
msg_add_block_dns,
msg_del_block_dns,
msg_register_dns
msg_acknowledgement,
msg_add_address,
msg_del_address,
msg_add_route,
msg_del_route,
msg_add_dns_cfg,
msg_del_dns_cfg,
msg_add_nbt_cfg,
msg_del_nbt_cfg,
msg_flush_neighbors,
msg_add_block_dns,
msg_del_block_dns,
msg_register_dns
} message_type_t;
typedef struct {
message_type_t type;
size_t size;
int message_id;
message_type_t type;
size_t size;
int message_id;
} message_header_t;
typedef union {
struct in_addr ipv4;
struct in6_addr ipv6;
struct in_addr ipv4;
struct in6_addr ipv6;
} inet_address_t;
typedef struct {
int index;
char name[256];
int index;
char name[256];
} interface_t;
typedef struct {
message_header_t header;
short family;
inet_address_t address;
int prefix_len;
interface_t iface;
message_header_t header;
short family;
inet_address_t address;
int prefix_len;
interface_t iface;
} address_message_t;
typedef struct {
message_header_t header;
short family;
inet_address_t prefix;
int prefix_len;
inet_address_t gateway;
interface_t iface;
int metric;
message_header_t header;
short family;
inet_address_t prefix;
int prefix_len;
inet_address_t gateway;
interface_t iface;
int metric;
} route_message_t;
typedef struct {
message_header_t header;
interface_t iface;
char domains[512];
short family;
int addr_len;
inet_address_t addr[4]; /* support up to 4 dns addresses */
message_header_t header;
interface_t iface;
char domains[512];
short family;
int addr_len;
inet_address_t addr[4]; /* support up to 4 dns addresses */
} dns_cfg_message_t;
typedef struct {
message_header_t header;
interface_t iface;
int disable_nbt;
int nbt_type;
char scope_id[256];
struct in_addr primary_nbns;
struct in_addr secondary_nbns;
message_header_t header;
interface_t iface;
int disable_nbt;
int nbt_type;
char scope_id[256];
struct in_addr primary_nbns;
struct in_addr secondary_nbns;
} nbt_cfg_message_t;
// TODO: NTP
/* TODO: NTP */
typedef struct {
message_header_t header;
short family;
interface_t iface;
message_header_t header;
short family;
interface_t iface;
} flush_neighbors_message_t;
typedef struct {
message_header_t header;
int error_number;
message_header_t header;
int error_number;
} ack_message_t;
typedef struct {
message_header_t header;
interface_t iface;
message_header_t header;
interface_t iface;
} block_dns_message_t;
#endif
#endif /* ifndef OPENVPN_MSG_H_ */

View file

@ -34,7 +34,7 @@
#define __OPENVPN_X509_CERT_T_DECLARED
typedef mbedtls_x509_crt openvpn_x509_cert_t;
#endif
#else
#else /* ifdef ENABLE_CRYPTO_MBEDTLS */
#include <openssl/x509.h>
#ifndef __OPENVPN_X509_CERT_T_DECLARED
#define __OPENVPN_X509_CERT_T_DECLARED
@ -85,7 +85,7 @@ extern "C" {
*
* FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_CLIENT_CONNECT_V2
* FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_LEARN_ADDRESS
*
*
* [Client session ensues]
*
* For each "TLS soft reset", according to reneg-sec option (or similar):
@ -96,7 +96,7 @@ extern "C" {
* in the server chain)
* FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY
* FUNC: openvpn_plugin_func_v1 OPENVPN_PLUGIN_TLS_FINAL
*
*
* [If OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY returned OPENVPN_PLUGIN_FUNC_DEFERRED,
* we expect that authentication is verified via auth_control_file within
* the number of seconds defined by the "hand-window" option. Data channel traffic
@ -155,9 +155,9 @@ typedef void *openvpn_plugin_handle_t;
* For Windows (needs to be modified for MSVC)
*/
#if defined(_WIN32) && !defined(OPENVPN_PLUGIN_H)
# define OPENVPN_EXPORT __declspec(dllexport)
#define OPENVPN_EXPORT __declspec(dllexport)
#else
# define OPENVPN_EXPORT
#define OPENVPN_EXPORT
#endif
/*
@ -172,7 +172,7 @@ typedef void *openvpn_plugin_handle_t;
#define OPENVPN_PLUGIN_DEF typedef
#define OPENVPN_PLUGIN_FUNC(name) (*name)
#else
#else /* ifdef OPENVPN_PLUGIN_H */
/*
* We are compiling plugin.
@ -191,9 +191,9 @@ typedef void *openvpn_plugin_handle_t;
*/
struct openvpn_plugin_string_list
{
struct openvpn_plugin_string_list *next;
char *name;
char *value;
struct openvpn_plugin_string_list *next;
char *name;
char *value;
};
@ -226,35 +226,35 @@ struct openvpn_plugin_string_list
*/
typedef enum
{
PLOG_ERR = (1 << 0), /* Error condition message */
PLOG_WARN = (1 << 1), /* General warning message */
PLOG_NOTE = (1 << 2), /* Informational message */
PLOG_DEBUG = (1 << 3), /* Debug message, displayed if verb >= 7 */
PLOG_ERR = (1 << 0),/* Error condition message */
PLOG_WARN = (1 << 1),/* General warning message */
PLOG_NOTE = (1 << 2),/* Informational message */
PLOG_DEBUG = (1 << 3),/* Debug message, displayed if verb >= 7 */
PLOG_ERRNO = (1 << 8), /* Add error description to message */
PLOG_NOMUTE = (1 << 9), /* Mute setting does not apply for message */
PLOG_ERRNO = (1 << 8),/* Add error description to message */
PLOG_NOMUTE = (1 << 9), /* Mute setting does not apply for message */
} openvpn_plugin_log_flags_t;
#ifdef __GNUC__
#if __USE_MINGW_ANSI_STDIO
# define _ovpn_chk_fmt(a, b) __attribute__ ((format(gnu_printf, (a), (b))))
#define _ovpn_chk_fmt(a, b) __attribute__ ((format(gnu_printf, (a), (b))))
#else
# define _ovpn_chk_fmt(a, b) __attribute__ ((format(__printf__, (a), (b))))
#define _ovpn_chk_fmt(a, b) __attribute__ ((format(__printf__, (a), (b))))
#endif
#else
# define _ovpn_chk_fmt(a, b)
#else /* ifdef __GNUC__ */
#define _ovpn_chk_fmt(a, b)
#endif
typedef void (*plugin_log_t) (openvpn_plugin_log_flags_t flags,
typedef void (*plugin_log_t)(openvpn_plugin_log_flags_t flags,
const char *plugin_name,
const char *format, ...) _ovpn_chk_fmt (3, 4);
typedef void (*plugin_vlog_t)(openvpn_plugin_log_flags_t flags,
const char *plugin_name,
const char *format, ...) _ovpn_chk_fmt(3, 4);
typedef void (*plugin_vlog_t) (openvpn_plugin_log_flags_t flags,
const char *plugin_name,
const char *format,
va_list arglist) _ovpn_chk_fmt(3, 0);
const char *format,
va_list arglist) _ovpn_chk_fmt (3, 0);
#undef _ovpn_chk_fmt
@ -270,8 +270,8 @@ typedef void (*plugin_vlog_t) (openvpn_plugin_log_flags_t flags,
*/
struct openvpn_plugin_callbacks
{
plugin_log_t plugin_log;
plugin_vlog_t plugin_vlog;
plugin_log_t plugin_log;
plugin_vlog_t plugin_vlog;
};
/**
@ -281,9 +281,9 @@ struct openvpn_plugin_callbacks
* and the plug-in against OpenSSL.
*/
typedef enum {
SSLAPI_NONE,
SSLAPI_OPENSSL,
SSLAPI_MBEDTLS
SSLAPI_NONE,
SSLAPI_OPENSSL,
SSLAPI_MBEDTLS
} ovpnSSLAPI;
/**
@ -309,15 +309,15 @@ typedef enum {
*/
struct openvpn_plugin_args_open_in
{
const int type_mask;
const char ** const argv;
const char ** const envp;
struct openvpn_plugin_callbacks *callbacks;
const ovpnSSLAPI ssl_api;
const char *ovpn_version;
const unsigned int ovpn_version_major;
const unsigned int ovpn_version_minor;
const char * const ovpn_version_patch;
const int type_mask;
const char **const argv;
const char **const envp;
struct openvpn_plugin_callbacks *callbacks;
const ovpnSSLAPI ssl_api;
const char *ovpn_version;
const unsigned int ovpn_version_major;
const unsigned int ovpn_version_minor;
const char *const ovpn_version_patch;
};
@ -344,9 +344,9 @@ struct openvpn_plugin_args_open_in
*/
struct openvpn_plugin_args_open_return
{
int type_mask;
openvpn_plugin_handle_t *handle;
struct openvpn_plugin_string_list **return_list;
int type_mask;
openvpn_plugin_handle_t *handle;
struct openvpn_plugin_string_list **return_list;
};
/**
@ -379,17 +379,17 @@ struct openvpn_plugin_args_open_return
*/
struct openvpn_plugin_args_func_in
{
const int type;
const char ** const argv;
const char ** const envp;
openvpn_plugin_handle_t handle;
void *per_client_context;
const int type;
const char **const argv;
const char **const envp;
openvpn_plugin_handle_t handle;
void *per_client_context;
#ifdef ENABLE_CRYPTO
int current_cert_depth;
openvpn_x509_cert_t *current_cert;
int current_cert_depth;
openvpn_x509_cert_t *current_cert;
#else
int __current_cert_depth_disabled; /* Unused, for compatibility purposes only */
void *__current_cert_disabled; /* Unused, for compatibility purposes only */
int __current_cert_depth_disabled; /* Unused, for compatibility purposes only */
void *__current_cert_disabled; /* Unused, for compatibility purposes only */
#endif
};
@ -407,7 +407,7 @@ struct openvpn_plugin_args_func_in
*/
struct openvpn_plugin_args_func_return
{
struct openvpn_plugin_string_list **return_list;
struct openvpn_plugin_string_list **return_list;
};
/*
@ -441,7 +441,7 @@ struct openvpn_plugin_args_func_return
* FUNCTION: openvpn_plugin_open_v2
*
* REQUIRED: YES
*
*
* Called on initial plug-in load. OpenVPN will preserve plug-in state
* across SIGUSR1 restarts but not across SIGHUP restarts. A SIGHUP reset
* will cause the plugin to be closed and reopened.
@ -473,10 +473,10 @@ struct openvpn_plugin_args_func_return
* An openvpn_plugin_handle_t value on success, NULL on failure
*/
OPENVPN_PLUGIN_DEF openvpn_plugin_handle_t OPENVPN_PLUGIN_FUNC(openvpn_plugin_open_v2)
(unsigned int *type_mask,
const char *argv[],
const char *envp[],
struct openvpn_plugin_string_list **return_list);
(unsigned int *type_mask,
const char *argv[],
const char *envp[],
struct openvpn_plugin_string_list **return_list);
/*
* FUNCTION: openvpn_plugin_func_v2
@ -484,7 +484,7 @@ OPENVPN_PLUGIN_DEF openvpn_plugin_handle_t OPENVPN_PLUGIN_FUNC(openvpn_plugin_op
* Called to perform the work of a given script type.
*
* REQUIRED: YES
*
*
* ARGUMENTS
*
* handle : the openvpn_plugin_handle_t value which was returned by
@ -569,12 +569,12 @@ OPENVPN_PLUGIN_DEF openvpn_plugin_handle_t OPENVPN_PLUGIN_FUNC(openvpn_plugin_op
* authentication and client-specific packet filtering.
*/
OPENVPN_PLUGIN_DEF int OPENVPN_PLUGIN_FUNC(openvpn_plugin_func_v2)
(openvpn_plugin_handle_t handle,
const int type,
const char *argv[],
const char *envp[],
void *per_client_context,
struct openvpn_plugin_string_list **return_list);
(openvpn_plugin_handle_t handle,
const int type,
const char *argv[],
const char *envp[],
void *per_client_context,
struct openvpn_plugin_string_list **return_list);
/*
@ -589,8 +589,8 @@ OPENVPN_PLUGIN_DEF int OPENVPN_PLUGIN_FUNC(openvpn_plugin_func_v2)
* ARGUMENTS
*
* version : fixed value, defines the API version of the OpenVPN plug-in API. The plug-in
* should validate that this value is matching the OPENVPN_PLUGINv3_STRUCTVER
* value.
* should validate that this value is matching the OPENVPN_PLUGINv3_STRUCTVER
* value.
*
* arguments : Structure with all arguments available to the plug-in.
*
@ -601,9 +601,9 @@ OPENVPN_PLUGIN_DEF int OPENVPN_PLUGIN_FUNC(openvpn_plugin_func_v2)
* OPENVPN_PLUGIN_FUNC_SUCCESS on success, OPENVPN_PLUGIN_FUNC_ERROR on failure
*/
OPENVPN_PLUGIN_DEF int OPENVPN_PLUGIN_FUNC(openvpn_plugin_open_v3)
(const int version,
struct openvpn_plugin_args_open_in const *arguments,
struct openvpn_plugin_args_open_return *retptr);
(const int version,
struct openvpn_plugin_args_open_in const *arguments,
struct openvpn_plugin_args_open_return *retptr);
/*
* FUNCTION: openvpn_plugin_func_v3
@ -685,15 +685,15 @@ OPENVPN_PLUGIN_DEF int OPENVPN_PLUGIN_FUNC(openvpn_plugin_open_v3)
* authentication and client-specific packet filtering.
*/
OPENVPN_PLUGIN_DEF int OPENVPN_PLUGIN_FUNC(openvpn_plugin_func_v3)
(const int version,
struct openvpn_plugin_args_func_in const *arguments,
struct openvpn_plugin_args_func_return *retptr);
(const int version,
struct openvpn_plugin_args_func_in const *arguments,
struct openvpn_plugin_args_func_return *retptr);
/*
* FUNCTION: openvpn_plugin_close_v1
*
* REQUIRED: YES
*
*
* ARGUMENTS
*
* handle : the openvpn_plugin_handle_t value which was returned by
@ -702,13 +702,13 @@ OPENVPN_PLUGIN_DEF int OPENVPN_PLUGIN_FUNC(openvpn_plugin_func_v3)
* Called immediately prior to plug-in unload.
*/
OPENVPN_PLUGIN_DEF void OPENVPN_PLUGIN_FUNC(openvpn_plugin_close_v1)
(openvpn_plugin_handle_t handle);
(openvpn_plugin_handle_t handle);
/*
* FUNCTION: openvpn_plugin_abort_v1
*
* REQUIRED: NO
*
*
* ARGUMENTS
*
* handle : the openvpn_plugin_handle_t value which was returned by
@ -719,7 +719,7 @@ OPENVPN_PLUGIN_DEF void OPENVPN_PLUGIN_FUNC(openvpn_plugin_close_v1)
* openvpn_plugin_open callback.
*/
OPENVPN_PLUGIN_DEF void OPENVPN_PLUGIN_FUNC(openvpn_plugin_abort_v1)
(openvpn_plugin_handle_t handle);
(openvpn_plugin_handle_t handle);
/*
* FUNCTION: openvpn_plugin_client_constructor_v1
@ -736,7 +736,7 @@ OPENVPN_PLUGIN_DEF void OPENVPN_PLUGIN_FUNC(openvpn_plugin_abort_v1)
* return a void * to this memory region.
*
* REQUIRED: NO
*
*
* ARGUMENTS
*
* handle : the openvpn_plugin_handle_t value which was returned by
@ -747,8 +747,8 @@ OPENVPN_PLUGIN_DEF void OPENVPN_PLUGIN_FUNC(openvpn_plugin_abort_v1)
* void * pointer to plugin's private per-client memory region, or NULL
* if no memory region is required.
*/
OPENVPN_PLUGIN_DEF void * OPENVPN_PLUGIN_FUNC(openvpn_plugin_client_constructor_v1)
(openvpn_plugin_handle_t handle);
OPENVPN_PLUGIN_DEF void *OPENVPN_PLUGIN_FUNC(openvpn_plugin_client_constructor_v1)
(openvpn_plugin_handle_t handle);
/*
* FUNCTION: openvpn_plugin_client_destructor_v1
@ -756,7 +756,7 @@ OPENVPN_PLUGIN_DEF void * OPENVPN_PLUGIN_FUNC(openvpn_plugin_client_constructor_
* This function is called on client instance object destruction.
*
* REQUIRED: NO
*
*
* ARGUMENTS
*
* handle : the openvpn_plugin_handle_t value which was returned by
@ -766,7 +766,7 @@ OPENVPN_PLUGIN_DEF void * OPENVPN_PLUGIN_FUNC(openvpn_plugin_client_constructor_
* openvpn_plugin_client_constructor_v1, if defined.
*/
OPENVPN_PLUGIN_DEF void OPENVPN_PLUGIN_FUNC(openvpn_plugin_client_destructor_v1)
(openvpn_plugin_handle_t handle, void *per_client_context);
(openvpn_plugin_handle_t handle, void *per_client_context);
/*
* FUNCTION: openvpn_plugin_select_initialization_point_v1
@ -779,7 +779,7 @@ OPENVPN_PLUGIN_DEF void OPENVPN_PLUGIN_FUNC(openvpn_plugin_client_destructor_v1)
* OPENVPN_PLUGIN_INIT_PRE_CONFIG_PARSE.
*
* REQUIRED: NO
*
*
* RETURN VALUE:
*
* An OPENVPN_PLUGIN_INIT_x value.
@ -790,35 +790,35 @@ OPENVPN_PLUGIN_DEF void OPENVPN_PLUGIN_FUNC(openvpn_plugin_client_destructor_v1)
#define OPENVPN_PLUGIN_INIT_POST_UID_CHANGE 4
OPENVPN_PLUGIN_DEF int OPENVPN_PLUGIN_FUNC(openvpn_plugin_select_initialization_point_v1)
(void);
(void);
/*
* FUNCTION: openvpn_plugin_min_version_required_v1
*
* This function is called by OpenVPN to query the minimum
plugin interface version number required by the plugin.
* plugin interface version number required by the plugin.
*
* REQUIRED: NO
*
*
* RETURN VALUE
*
* The minimum OpenVPN plugin interface version number necessary to support
* this plugin.
*/
OPENVPN_PLUGIN_DEF int OPENVPN_PLUGIN_FUNC(openvpn_plugin_min_version_required_v1)
(void);
(void);
/*
* Deprecated functions which are still supported for backward compatibility.
*/
OPENVPN_PLUGIN_DEF openvpn_plugin_handle_t OPENVPN_PLUGIN_FUNC(openvpn_plugin_open_v1)
(unsigned int *type_mask,
const char *argv[],
const char *envp[]);
(unsigned int *type_mask,
const char *argv[],
const char *envp[]);
OPENVPN_PLUGIN_DEF int OPENVPN_PLUGIN_FUNC(openvpn_plugin_func_v1)
(openvpn_plugin_handle_t handle, const int type, const char *argv[], const char *envp[]);
(openvpn_plugin_handle_t handle, const int type, const char *argv[], const char *envp[]);
#ifdef __cplusplus
}

View file

@ -25,7 +25,7 @@
/*
* This file implements a simple OpenVPN plugin module which
* will test deferred authentication and packet filtering.
*
*
* Will run on Windows or *nix.
*
* Sample usage:
@ -68,13 +68,13 @@
*/
struct plugin_context {
int test_deferred_auth;
int test_packet_filter;
int test_deferred_auth;
int test_packet_filter;
};
struct plugin_per_client_context {
int n_calls;
bool generated_pf_file;
int n_calls;
bool generated_pf_file;
};
/*
@ -83,223 +83,258 @@ struct plugin_per_client_context {
* if found or NULL otherwise.
*/
static const char *
get_env (const char *name, const char *envp[])
get_env(const char *name, const char *envp[])
{
if (envp)
if (envp)
{
int i;
const int namelen = strlen (name);
for (i = 0; envp[i]; ++i)
{
if (!strncmp (envp[i], name, namelen))
{
const char *cp = envp[i] + namelen;
if (*cp == '=')
return cp + 1;
}
}
int i;
const int namelen = strlen(name);
for (i = 0; envp[i]; ++i)
{
if (!strncmp(envp[i], name, namelen))
{
const char *cp = envp[i] + namelen;
if (*cp == '=')
{
return cp + 1;
}
}
}
}
return NULL;
return NULL;
}
/* used for safe printf of possible NULL strings */
static const char *
np (const char *str)
np(const char *str)
{
if (str)
return str;
else
return "[NULL]";
if (str)
{
return str;
}
else
{
return "[NULL]";
}
}
static int
atoi_null0 (const char *str)
atoi_null0(const char *str)
{
if (str)
return atoi (str);
else
return 0;
if (str)
{
return atoi(str);
}
else
{
return 0;
}
}
OPENVPN_EXPORT openvpn_plugin_handle_t
openvpn_plugin_open_v1 (unsigned int *type_mask, const char *argv[], const char *envp[])
openvpn_plugin_open_v1(unsigned int *type_mask, const char *argv[], const char *envp[])
{
struct plugin_context *context;
struct plugin_context *context;
printf ("FUNC: openvpn_plugin_open_v1\n");
printf("FUNC: openvpn_plugin_open_v1\n");
/*
* Allocate our context
*/
context = (struct plugin_context *) calloc (1, sizeof (struct plugin_context));
/*
* Allocate our context
*/
context = (struct plugin_context *) calloc(1, sizeof(struct plugin_context));
context->test_deferred_auth = atoi_null0 (get_env ("test_deferred_auth", envp));
printf ("TEST_DEFERRED_AUTH %d\n", context->test_deferred_auth);
context->test_deferred_auth = atoi_null0(get_env("test_deferred_auth", envp));
printf("TEST_DEFERRED_AUTH %d\n", context->test_deferred_auth);
context->test_packet_filter = atoi_null0 (get_env ("test_packet_filter", envp));
printf ("TEST_PACKET_FILTER %d\n", context->test_packet_filter);
context->test_packet_filter = atoi_null0(get_env("test_packet_filter", envp));
printf("TEST_PACKET_FILTER %d\n", context->test_packet_filter);
/*
* Which callbacks to intercept.
*/
*type_mask =
OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_UP) |
OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_DOWN) |
OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_ROUTE_UP) |
OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_IPCHANGE) |
OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_TLS_VERIFY) |
OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY) |
OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_CLIENT_CONNECT_V2) |
OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_CLIENT_DISCONNECT) |
OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_LEARN_ADDRESS) |
OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_TLS_FINAL) |
OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_ENABLE_PF);
/*
* Which callbacks to intercept.
*/
*type_mask =
OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_UP)
|OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_DOWN)
|OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_ROUTE_UP)
|OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_IPCHANGE)
|OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_TLS_VERIFY)
|OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY)
|OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_CLIENT_CONNECT_V2)
|OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_CLIENT_DISCONNECT)
|OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_LEARN_ADDRESS)
|OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_TLS_FINAL)
|OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_ENABLE_PF);
return (openvpn_plugin_handle_t) context;
return (openvpn_plugin_handle_t) context;
}
static int
auth_user_pass_verify (struct plugin_context *context, struct plugin_per_client_context *pcc, const char *argv[], const char *envp[])
auth_user_pass_verify(struct plugin_context *context, struct plugin_per_client_context *pcc, const char *argv[], const char *envp[])
{
if (context->test_deferred_auth)
if (context->test_deferred_auth)
{
/* get username/password from envp string array */
const char *username = get_env ("username", envp);
const char *password = get_env ("password", envp);
/* get username/password from envp string array */
const char *username = get_env("username", envp);
const char *password = get_env("password", envp);
/* get auth_control_file filename from envp string array*/
const char *auth_control_file = get_env ("auth_control_file", envp);
/* get auth_control_file filename from envp string array*/
const char *auth_control_file = get_env("auth_control_file", envp);
printf ("DEFER u='%s' p='%s' acf='%s'\n",
np(username),
np(password),
np(auth_control_file));
printf("DEFER u='%s' p='%s' acf='%s'\n",
np(username),
np(password),
np(auth_control_file));
/* Authenticate asynchronously in n seconds */
if (auth_control_file)
{
char buf[256];
int auth = 2;
sscanf (username, "%d", &auth);
snprintf (buf, sizeof(buf), "( sleep %d ; echo AUTH %s %d ; echo %d >%s ) &",
context->test_deferred_auth,
auth_control_file,
auth,
pcc->n_calls < auth,
auth_control_file);
printf ("%s\n", buf);
system (buf);
pcc->n_calls++;
return OPENVPN_PLUGIN_FUNC_DEFERRED;
}
else
return OPENVPN_PLUGIN_FUNC_ERROR;
/* Authenticate asynchronously in n seconds */
if (auth_control_file)
{
char buf[256];
int auth = 2;
sscanf(username, "%d", &auth);
snprintf(buf, sizeof(buf), "( sleep %d ; echo AUTH %s %d ; echo %d >%s ) &",
context->test_deferred_auth,
auth_control_file,
auth,
pcc->n_calls < auth,
auth_control_file);
printf("%s\n", buf);
system(buf);
pcc->n_calls++;
return OPENVPN_PLUGIN_FUNC_DEFERRED;
}
else
{
return OPENVPN_PLUGIN_FUNC_ERROR;
}
}
else
{
return OPENVPN_PLUGIN_FUNC_SUCCESS;
}
else
return OPENVPN_PLUGIN_FUNC_SUCCESS;
}
static int
tls_final (struct plugin_context *context, struct plugin_per_client_context *pcc, const char *argv[], const char *envp[])
tls_final(struct plugin_context *context, struct plugin_per_client_context *pcc, const char *argv[], const char *envp[])
{
if (context->test_packet_filter)
if (context->test_packet_filter)
{
if (!pcc->generated_pf_file)
{
const char *pff = get_env ("pf_file", envp);
const char *cn = get_env ("username", envp);
if (pff && cn)
{
char buf[256];
snprintf (buf, sizeof(buf), "( sleep %d ; echo PF %s/%s ; cp \"%s.pf\" \"%s\" ) &",
context->test_packet_filter, cn, pff, cn, pff);
printf ("%s\n", buf);
system (buf);
pcc->generated_pf_file = true;
return OPENVPN_PLUGIN_FUNC_SUCCESS;
}
else
return OPENVPN_PLUGIN_FUNC_ERROR;
}
else
return OPENVPN_PLUGIN_FUNC_ERROR;
if (!pcc->generated_pf_file)
{
const char *pff = get_env("pf_file", envp);
const char *cn = get_env("username", envp);
if (pff && cn)
{
char buf[256];
snprintf(buf, sizeof(buf), "( sleep %d ; echo PF %s/%s ; cp \"%s.pf\" \"%s\" ) &",
context->test_packet_filter, cn, pff, cn, pff);
printf("%s\n", buf);
system(buf);
pcc->generated_pf_file = true;
return OPENVPN_PLUGIN_FUNC_SUCCESS;
}
else
{
return OPENVPN_PLUGIN_FUNC_ERROR;
}
}
else
{
return OPENVPN_PLUGIN_FUNC_ERROR;
}
}
else
{
return OPENVPN_PLUGIN_FUNC_SUCCESS;
}
else
return OPENVPN_PLUGIN_FUNC_SUCCESS;
}
OPENVPN_EXPORT int
openvpn_plugin_func_v2 (openvpn_plugin_handle_t handle,
const int type,
const char *argv[],
const char *envp[],
void *per_client_context,
struct openvpn_plugin_string_list **return_list)
openvpn_plugin_func_v2(openvpn_plugin_handle_t handle,
const int type,
const char *argv[],
const char *envp[],
void *per_client_context,
struct openvpn_plugin_string_list **return_list)
{
struct plugin_context *context = (struct plugin_context *) handle;
struct plugin_per_client_context *pcc = (struct plugin_per_client_context *) per_client_context;
switch (type)
struct plugin_context *context = (struct plugin_context *) handle;
struct plugin_per_client_context *pcc = (struct plugin_per_client_context *) per_client_context;
switch (type)
{
case OPENVPN_PLUGIN_UP:
printf ("OPENVPN_PLUGIN_UP\n");
return OPENVPN_PLUGIN_FUNC_SUCCESS;
case OPENVPN_PLUGIN_DOWN:
printf ("OPENVPN_PLUGIN_DOWN\n");
return OPENVPN_PLUGIN_FUNC_SUCCESS;
case OPENVPN_PLUGIN_ROUTE_UP:
printf ("OPENVPN_PLUGIN_ROUTE_UP\n");
return OPENVPN_PLUGIN_FUNC_SUCCESS;
case OPENVPN_PLUGIN_IPCHANGE:
printf ("OPENVPN_PLUGIN_IPCHANGE\n");
return OPENVPN_PLUGIN_FUNC_SUCCESS;
case OPENVPN_PLUGIN_TLS_VERIFY:
printf ("OPENVPN_PLUGIN_TLS_VERIFY\n");
return OPENVPN_PLUGIN_FUNC_SUCCESS;
case OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY:
printf ("OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY\n");
return auth_user_pass_verify (context, pcc, argv, envp);
case OPENVPN_PLUGIN_CLIENT_CONNECT_V2:
printf ("OPENVPN_PLUGIN_CLIENT_CONNECT_V2\n");
return OPENVPN_PLUGIN_FUNC_SUCCESS;
case OPENVPN_PLUGIN_CLIENT_DISCONNECT:
printf ("OPENVPN_PLUGIN_CLIENT_DISCONNECT\n");
return OPENVPN_PLUGIN_FUNC_SUCCESS;
case OPENVPN_PLUGIN_LEARN_ADDRESS:
printf ("OPENVPN_PLUGIN_LEARN_ADDRESS\n");
return OPENVPN_PLUGIN_FUNC_SUCCESS;
case OPENVPN_PLUGIN_TLS_FINAL:
printf ("OPENVPN_PLUGIN_TLS_FINAL\n");
return tls_final (context, pcc, argv, envp);
case OPENVPN_PLUGIN_ENABLE_PF:
printf ("OPENVPN_PLUGIN_ENABLE_PF\n");
if (context->test_packet_filter)
return OPENVPN_PLUGIN_FUNC_SUCCESS;
else
return OPENVPN_PLUGIN_FUNC_ERROR;
default:
printf ("OPENVPN_PLUGIN_?\n");
return OPENVPN_PLUGIN_FUNC_ERROR;
case OPENVPN_PLUGIN_UP:
printf("OPENVPN_PLUGIN_UP\n");
return OPENVPN_PLUGIN_FUNC_SUCCESS;
case OPENVPN_PLUGIN_DOWN:
printf("OPENVPN_PLUGIN_DOWN\n");
return OPENVPN_PLUGIN_FUNC_SUCCESS;
case OPENVPN_PLUGIN_ROUTE_UP:
printf("OPENVPN_PLUGIN_ROUTE_UP\n");
return OPENVPN_PLUGIN_FUNC_SUCCESS;
case OPENVPN_PLUGIN_IPCHANGE:
printf("OPENVPN_PLUGIN_IPCHANGE\n");
return OPENVPN_PLUGIN_FUNC_SUCCESS;
case OPENVPN_PLUGIN_TLS_VERIFY:
printf("OPENVPN_PLUGIN_TLS_VERIFY\n");
return OPENVPN_PLUGIN_FUNC_SUCCESS;
case OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY:
printf("OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY\n");
return auth_user_pass_verify(context, pcc, argv, envp);
case OPENVPN_PLUGIN_CLIENT_CONNECT_V2:
printf("OPENVPN_PLUGIN_CLIENT_CONNECT_V2\n");
return OPENVPN_PLUGIN_FUNC_SUCCESS;
case OPENVPN_PLUGIN_CLIENT_DISCONNECT:
printf("OPENVPN_PLUGIN_CLIENT_DISCONNECT\n");
return OPENVPN_PLUGIN_FUNC_SUCCESS;
case OPENVPN_PLUGIN_LEARN_ADDRESS:
printf("OPENVPN_PLUGIN_LEARN_ADDRESS\n");
return OPENVPN_PLUGIN_FUNC_SUCCESS;
case OPENVPN_PLUGIN_TLS_FINAL:
printf("OPENVPN_PLUGIN_TLS_FINAL\n");
return tls_final(context, pcc, argv, envp);
case OPENVPN_PLUGIN_ENABLE_PF:
printf("OPENVPN_PLUGIN_ENABLE_PF\n");
if (context->test_packet_filter)
{
return OPENVPN_PLUGIN_FUNC_SUCCESS;
}
else
{
return OPENVPN_PLUGIN_FUNC_ERROR;
}
default:
printf("OPENVPN_PLUGIN_?\n");
return OPENVPN_PLUGIN_FUNC_ERROR;
}
}
OPENVPN_EXPORT void *
openvpn_plugin_client_constructor_v1 (openvpn_plugin_handle_t handle)
openvpn_plugin_client_constructor_v1(openvpn_plugin_handle_t handle)
{
printf ("FUNC: openvpn_plugin_client_constructor_v1\n");
return calloc (1, sizeof (struct plugin_per_client_context));
printf("FUNC: openvpn_plugin_client_constructor_v1\n");
return calloc(1, sizeof(struct plugin_per_client_context));
}
OPENVPN_EXPORT void
openvpn_plugin_client_destructor_v1 (openvpn_plugin_handle_t handle, void *per_client_context)
openvpn_plugin_client_destructor_v1(openvpn_plugin_handle_t handle, void *per_client_context)
{
printf ("FUNC: openvpn_plugin_client_destructor_v1\n");
free (per_client_context);
printf("FUNC: openvpn_plugin_client_destructor_v1\n");
free(per_client_context);
}
OPENVPN_EXPORT void
openvpn_plugin_close_v1 (openvpn_plugin_handle_t handle)
openvpn_plugin_close_v1(openvpn_plugin_handle_t handle)
{
struct plugin_context *context = (struct plugin_context *) handle;
printf ("FUNC: openvpn_plugin_close_v1\n");
free (context);
struct plugin_context *context = (struct plugin_context *) handle;
printf("FUNC: openvpn_plugin_close_v1\n");
free(context);
}

View file

@ -41,23 +41,23 @@
#endif
#define ovpn_err(fmt, ...) \
plugin->log(PLOG_ERR, "SSO", fmt , ## __VA_ARGS__)
plugin->log(PLOG_ERR, "SSO", fmt, ## __VA_ARGS__)
#define ovpn_dbg(fmt, ...) \
plugin->log(PLOG_DEBUG, "SSO", fmt , ## __VA_ARGS__)
plugin->log(PLOG_DEBUG, "SSO", fmt, ## __VA_ARGS__)
#define ovpn_note(fmt, ...) \
plugin->log(PLOG_NOTE, "SSO", fmt , ## __VA_ARGS__)
plugin->log(PLOG_NOTE, "SSO", fmt, ## __VA_ARGS__)
enum endpoint { CLIENT = 1, SERVER = 2 };
struct plugin {
plugin_log_t log;
enum endpoint type;
int mask;
plugin_log_t log;
enum endpoint type;
int mask;
};
struct session {
char user[48];
char key [48];
char user[48];
char key [48];
};
/*
@ -69,201 +69,226 @@ struct session {
static const char *
get_env(const char *name, const char *envp[])
{
if (envp)
if (envp)
{
int i;
const int namelen = strlen (name);
for (i = 0; envp[i]; ++i)
{
if (!strncmp (envp[i], name, namelen))
{
const char *cp = envp[i] + namelen;
if (*cp == '=')
return cp + 1;
}
}
int i;
const int namelen = strlen(name);
for (i = 0; envp[i]; ++i)
{
if (!strncmp(envp[i], name, namelen))
{
const char *cp = envp[i] + namelen;
if (*cp == '=')
{
return cp + 1;
}
}
}
}
return NULL;
return NULL;
}
OPENVPN_EXPORT int
openvpn_plugin_open_v3 (const int version,
struct openvpn_plugin_args_open_in const *args,
struct openvpn_plugin_args_open_return *rv)
openvpn_plugin_open_v3(const int version,
struct openvpn_plugin_args_open_in const *args,
struct openvpn_plugin_args_open_return *rv)
{
struct plugin *plugin = calloc (1, sizeof(*plugin));
struct plugin *plugin = calloc(1, sizeof(*plugin));
plugin->type = get_env ("remote_1", args->envp) ? CLIENT : SERVER;
plugin->log = args->callbacks->plugin_log;
plugin->type = get_env("remote_1", args->envp) ? CLIENT : SERVER;
plugin->log = args->callbacks->plugin_log;
plugin->mask = OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_TLS_FINAL);
plugin->mask |= OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_TLS_VERIFY);
plugin->mask = OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_TLS_FINAL);
plugin->mask |= OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_TLS_VERIFY);
ovpn_note("vpn endpoint type=%s",plugin->type == CLIENT ? "client":"server");
ovpn_note("vpn endpoint type=%s",plugin->type == CLIENT ? "client" : "server");
rv->type_mask = plugin->mask;
rv->handle = (void *)plugin;
rv->type_mask = plugin->mask;
rv->handle = (void *)plugin;
return OPENVPN_PLUGIN_FUNC_SUCCESS;
return OPENVPN_PLUGIN_FUNC_SUCCESS;
}
static void
session_user_set(struct session *sess, X509 *x509)
{
int fn_nid;
ASN1_OBJECT *fn;
ASN1_STRING *val;
X509_NAME *x509_name;
X509_NAME_ENTRY *ent;
const char *objbuf;
int fn_nid;
ASN1_OBJECT *fn;
ASN1_STRING *val;
X509_NAME *x509_name;
X509_NAME_ENTRY *ent;
const char *objbuf;
x509_name = X509_get_subject_name (x509);
int i, n = X509_NAME_entry_count (x509_name);
for (i = 0; i < n; ++i)
x509_name = X509_get_subject_name(x509);
int i, n = X509_NAME_entry_count(x509_name);
for (i = 0; i < n; ++i)
{
if (!(ent = X509_NAME_get_entry (x509_name, i)))
continue;
if (!(fn = X509_NAME_ENTRY_get_object (ent)))
continue;
if (!(val = X509_NAME_ENTRY_get_data (ent)))
continue;
if ((fn_nid = OBJ_obj2nid (fn)) == NID_undef)
continue;
if (!(objbuf = OBJ_nid2sn (fn_nid)))
continue;
/* bug in OpenSSL 0.9.6b ASN1_STRING_to_UTF8 requires this workaround */
unsigned char *buf = (unsigned char *)1;
if (ASN1_STRING_to_UTF8 (&buf, val) <= 0)
continue;
if (!(ent = X509_NAME_get_entry(x509_name, i)))
{
continue;
}
if (!(fn = X509_NAME_ENTRY_get_object(ent)))
{
continue;
}
if (!(val = X509_NAME_ENTRY_get_data(ent)))
{
continue;
}
if ((fn_nid = OBJ_obj2nid(fn)) == NID_undef)
{
continue;
}
if (!(objbuf = OBJ_nid2sn(fn_nid)))
{
continue;
}
/* bug in OpenSSL 0.9.6b ASN1_STRING_to_UTF8 requires this workaround */
unsigned char *buf = (unsigned char *)1;
if (ASN1_STRING_to_UTF8(&buf, val) <= 0)
{
continue;
}
if (!strncasecmp(objbuf, "CN", 2))
snprintf(sess->user, sizeof(sess->user) - 1, (char *)buf);
if (!strncasecmp(objbuf, "CN", 2))
{
snprintf(sess->user, sizeof(sess->user) - 1, (char *)buf);
}
OPENSSL_free (buf);
OPENSSL_free(buf);
}
}
static int
tls_verify(struct openvpn_plugin_args_func_in const *args)
{
struct plugin *plugin = (struct plugin *)args->handle;
struct session *sess = (struct session *)args->per_client_context;
struct plugin *plugin = (struct plugin *)args->handle;
struct session *sess = (struct session *)args->per_client_context;
/* we store cert subject for the server end point only */
if (plugin->type != SERVER)
{
return OPENVPN_PLUGIN_FUNC_SUCCESS;
}
if (!args->current_cert)
{
ovpn_err("this example plugin requires client certificate");
return OPENVPN_PLUGIN_FUNC_ERROR;
}
session_user_set(sess, args->current_cert);
/* we store cert subject for the server end point only */
if (plugin->type != SERVER)
return OPENVPN_PLUGIN_FUNC_SUCCESS;
if (!args->current_cert) {
ovpn_err("this example plugin requires client certificate");
return OPENVPN_PLUGIN_FUNC_ERROR;
}
session_user_set(sess, args->current_cert);
return OPENVPN_PLUGIN_FUNC_SUCCESS;
}
static void
file_store(char *file, char *content)
{
FILE *f;
if (!(f = fopen(file, "w+")))
return;
FILE *f;
if (!(f = fopen(file, "w+")))
{
return;
}
fprintf(f, "%s", content);
fclose(f);
fprintf(f, "%s", content);
fclose(f);
}
static void
server_store(struct openvpn_plugin_args_func_in const *args)
{
struct plugin *plugin = (struct plugin *)args->handle;
struct session *sess = (struct session *)args->per_client_context;
struct plugin *plugin = (struct plugin *)args->handle;
struct session *sess = (struct session *)args->per_client_context;
char file[MAXPATH];
snprintf(file, sizeof(file) - 1, "/tmp/openvpn_sso_%s", sess->key);
ovpn_note("app session file: %s", file);
file_store(file, sess->user);
char file[MAXPATH];
snprintf(file, sizeof(file) - 1, "/tmp/openvpn_sso_%s", sess->key);
ovpn_note("app session file: %s", file);
file_store(file, sess->user);
}
static void
client_store(struct openvpn_plugin_args_func_in const *args)
{
struct plugin *plugin = (struct plugin *)args->handle;
struct session *sess = (struct session *)args->per_client_context;
struct plugin *plugin = (struct plugin *)args->handle;
struct session *sess = (struct session *)args->per_client_context;
char *file = "/tmp/openvpn_sso_user";
ovpn_note("app session file: %s", file);
file_store(file, sess->key);
char *file = "/tmp/openvpn_sso_user";
ovpn_note("app session file: %s", file);
file_store(file, sess->key);
}
static int
tls_final(struct openvpn_plugin_args_func_in const *args,
struct openvpn_plugin_args_func_return *rv)
{
struct plugin *plugin = (struct plugin *)args->handle;
struct session *sess = (struct session *)args->per_client_context;
struct plugin *plugin = (struct plugin *)args->handle;
struct session *sess = (struct session *)args->per_client_context;
const char *key;
if (!(key = get_env ("exported_keying_material", args->envp)))
return OPENVPN_PLUGIN_FUNC_ERROR;
const char *key;
if (!(key = get_env("exported_keying_material", args->envp)))
{
return OPENVPN_PLUGIN_FUNC_ERROR;
}
snprintf(sess->key, sizeof(sess->key) - 1, "%s", key);
ovpn_note("app session key: %s", sess->key);
snprintf(sess->key, sizeof(sess->key) - 1, "%s", key);
ovpn_note("app session key: %s", sess->key);
switch (plugin->type) {
case SERVER:
server_store(args);
break;
case CLIENT:
client_store(args);
switch (plugin->type) {
case SERVER:
server_store(args);
break;
case CLIENT:
client_store(args);
return OPENVPN_PLUGIN_FUNC_SUCCESS;
}
ovpn_note("app session user: %s", sess->user);
return OPENVPN_PLUGIN_FUNC_SUCCESS;
}
ovpn_note("app session user: %s", sess->user);
return OPENVPN_PLUGIN_FUNC_SUCCESS;
}
OPENVPN_EXPORT int
openvpn_plugin_func_v3 (const int version,
struct openvpn_plugin_args_func_in const *args,
struct openvpn_plugin_args_func_return *rv)
openvpn_plugin_func_v3(const int version,
struct openvpn_plugin_args_func_in const *args,
struct openvpn_plugin_args_func_return *rv)
{
switch(args->type) {
case OPENVPN_PLUGIN_TLS_VERIFY:
return tls_verify(args);
case OPENVPN_PLUGIN_TLS_FINAL:
return tls_final(args, rv);
}
return OPENVPN_PLUGIN_FUNC_SUCCESS;
switch (args->type) {
case OPENVPN_PLUGIN_TLS_VERIFY:
return tls_verify(args);
case OPENVPN_PLUGIN_TLS_FINAL:
return tls_final(args, rv);
}
return OPENVPN_PLUGIN_FUNC_SUCCESS;
}
OPENVPN_EXPORT void *
openvpn_plugin_client_constructor_v1(openvpn_plugin_handle_t handle)
{
struct plugin *plugin = (struct plugin *)handle;
struct session *sess = calloc (1, sizeof(*sess));
struct plugin *plugin = (struct plugin *)handle;
struct session *sess = calloc(1, sizeof(*sess));
ovpn_note("app session created");
ovpn_note("app session created");
return (void *)sess;
return (void *)sess;
}
OPENVPN_EXPORT void
openvpn_plugin_client_destructor_v1(openvpn_plugin_handle_t handle, void *ctx)
{
struct plugin *plugin = (struct plugin *)handle;
struct session *sess = (struct session *)ctx;
struct plugin *plugin = (struct plugin *)handle;
struct session *sess = (struct session *)ctx;
ovpn_note("app session key: %s", sess->key);
ovpn_note("app session destroyed");
ovpn_note("app session key: %s", sess->key);
ovpn_note("app session destroyed");
free (sess);
free(sess);
}
OPENVPN_EXPORT void
openvpn_plugin_close_v1 (openvpn_plugin_handle_t handle)
openvpn_plugin_close_v1(openvpn_plugin_handle_t handle)
{
struct plugin *plugin = (struct plugin *)handle;
free (plugin);
struct plugin *plugin = (struct plugin *)handle;
free(plugin);
}

View file

@ -39,8 +39,8 @@
* Our context, where we keep our state.
*/
struct plugin_context {
const char *username;
const char *password;
const char *username;
const char *password;
};
/*
@ -49,136 +49,154 @@ struct plugin_context {
* if found or NULL otherwise.
*/
static const char *
get_env (const char *name, const char *envp[])
get_env(const char *name, const char *envp[])
{
if (envp)
if (envp)
{
int i;
const int namelen = strlen (name);
for (i = 0; envp[i]; ++i)
{
if (!strncmp (envp[i], name, namelen))
{
const char *cp = envp[i] + namelen;
if (*cp == '=')
return cp + 1;
}
}
int i;
const int namelen = strlen(name);
for (i = 0; envp[i]; ++i)
{
if (!strncmp(envp[i], name, namelen))
{
const char *cp = envp[i] + namelen;
if (*cp == '=')
{
return cp + 1;
}
}
}
}
return NULL;
return NULL;
}
OPENVPN_EXPORT openvpn_plugin_handle_t
openvpn_plugin_open_v1 (unsigned int *type_mask, const char *argv[], const char *envp[])
openvpn_plugin_open_v1(unsigned int *type_mask, const char *argv[], const char *envp[])
{
struct plugin_context *context;
struct plugin_context *context;
/*
* Allocate our context
*/
context = (struct plugin_context *) calloc (1, sizeof (struct plugin_context));
/*
* Allocate our context
*/
context = (struct plugin_context *) calloc(1, sizeof(struct plugin_context));
/*
* Set the username/password we will require.
*/
context->username = "foo";
context->password = "bar";
/*
* Set the username/password we will require.
*/
context->username = "foo";
context->password = "bar";
/*
* Which callbacks to intercept.
*/
*type_mask =
OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_UP) |
OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_DOWN) |
OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_ROUTE_UP) |
OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_IPCHANGE) |
OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_TLS_VERIFY) |
OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY) |
OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_CLIENT_CONNECT_V2) |
OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_CLIENT_DISCONNECT) |
OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_LEARN_ADDRESS) |
OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_TLS_FINAL);
/*
* Which callbacks to intercept.
*/
*type_mask =
OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_UP)
|OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_DOWN)
|OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_ROUTE_UP)
|OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_IPCHANGE)
|OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_TLS_VERIFY)
|OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY)
|OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_CLIENT_CONNECT_V2)
|OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_CLIENT_DISCONNECT)
|OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_LEARN_ADDRESS)
|OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_TLS_FINAL);
return (openvpn_plugin_handle_t) context;
return (openvpn_plugin_handle_t) context;
}
void
show (const int type, const char *argv[], const char *envp[])
show(const int type, const char *argv[], const char *envp[])
{
size_t i;
switch (type)
size_t i;
switch (type)
{
case OPENVPN_PLUGIN_UP:
printf ("OPENVPN_PLUGIN_UP\n");
break;
case OPENVPN_PLUGIN_DOWN:
printf ("OPENVPN_PLUGIN_DOWN\n");
break;
case OPENVPN_PLUGIN_ROUTE_UP:
printf ("OPENVPN_PLUGIN_ROUTE_UP\n");
break;
case OPENVPN_PLUGIN_IPCHANGE:
printf ("OPENVPN_PLUGIN_IPCHANGE\n");
break;
case OPENVPN_PLUGIN_TLS_VERIFY:
printf ("OPENVPN_PLUGIN_TLS_VERIFY\n");
break;
case OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY:
printf ("OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY\n");
break;
case OPENVPN_PLUGIN_CLIENT_CONNECT_V2:
printf ("OPENVPN_PLUGIN_CLIENT_CONNECT_V2\n");
break;
case OPENVPN_PLUGIN_CLIENT_DISCONNECT:
printf ("OPENVPN_PLUGIN_CLIENT_DISCONNECT\n");
break;
case OPENVPN_PLUGIN_LEARN_ADDRESS:
printf ("OPENVPN_PLUGIN_LEARN_ADDRESS\n");
break;
case OPENVPN_PLUGIN_TLS_FINAL:
printf ("OPENVPN_PLUGIN_TLS_FINAL\n");
break;
default:
printf ("OPENVPN_PLUGIN_?\n");
break;
case OPENVPN_PLUGIN_UP:
printf("OPENVPN_PLUGIN_UP\n");
break;
case OPENVPN_PLUGIN_DOWN:
printf("OPENVPN_PLUGIN_DOWN\n");
break;
case OPENVPN_PLUGIN_ROUTE_UP:
printf("OPENVPN_PLUGIN_ROUTE_UP\n");
break;
case OPENVPN_PLUGIN_IPCHANGE:
printf("OPENVPN_PLUGIN_IPCHANGE\n");
break;
case OPENVPN_PLUGIN_TLS_VERIFY:
printf("OPENVPN_PLUGIN_TLS_VERIFY\n");
break;
case OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY:
printf("OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY\n");
break;
case OPENVPN_PLUGIN_CLIENT_CONNECT_V2:
printf("OPENVPN_PLUGIN_CLIENT_CONNECT_V2\n");
break;
case OPENVPN_PLUGIN_CLIENT_DISCONNECT:
printf("OPENVPN_PLUGIN_CLIENT_DISCONNECT\n");
break;
case OPENVPN_PLUGIN_LEARN_ADDRESS:
printf("OPENVPN_PLUGIN_LEARN_ADDRESS\n");
break;
case OPENVPN_PLUGIN_TLS_FINAL:
printf("OPENVPN_PLUGIN_TLS_FINAL\n");
break;
default:
printf("OPENVPN_PLUGIN_?\n");
break;
}
printf ("ARGV\n");
for (i = 0; argv[i] != NULL; ++i)
printf ("%d '%s'\n", (int)i, argv[i]);
printf("ARGV\n");
for (i = 0; argv[i] != NULL; ++i)
printf("%d '%s'\n", (int)i, argv[i]);
printf ("ENVP\n");
for (i = 0; envp[i] != NULL; ++i)
printf ("%d '%s'\n", (int)i, envp[i]);
printf("ENVP\n");
for (i = 0; envp[i] != NULL; ++i)
printf("%d '%s'\n", (int)i, envp[i]);
}
OPENVPN_EXPORT int
openvpn_plugin_func_v1 (openvpn_plugin_handle_t handle, const int type, const char *argv[], const char *envp[])
openvpn_plugin_func_v1(openvpn_plugin_handle_t handle, const int type, const char *argv[], const char *envp[])
{
struct plugin_context *context = (struct plugin_context *) handle;
struct plugin_context *context = (struct plugin_context *) handle;
show (type, argv, envp);
show(type, argv, envp);
/* check entered username/password against what we require */
if (type == OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY)
/* check entered username/password against what we require */
if (type == OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY)
{
/* get username/password from envp string array */
const char *username = get_env ("username", envp);
const char *password = get_env ("password", envp);
/* get username/password from envp string array */
const char *username = get_env("username", envp);
const char *password = get_env("password", envp);
if (username && !strcmp (username, context->username)
&& password && !strcmp (password, context->password))
return OPENVPN_PLUGIN_FUNC_SUCCESS;
else
return OPENVPN_PLUGIN_FUNC_ERROR;
if (username && !strcmp(username, context->username)
&& password && !strcmp(password, context->password))
{
return OPENVPN_PLUGIN_FUNC_SUCCESS;
}
else
{
return OPENVPN_PLUGIN_FUNC_ERROR;
}
}
else
{
return OPENVPN_PLUGIN_FUNC_SUCCESS;
}
else
return OPENVPN_PLUGIN_FUNC_SUCCESS;
}
OPENVPN_EXPORT void
openvpn_plugin_close_v1 (openvpn_plugin_handle_t handle)
openvpn_plugin_close_v1(openvpn_plugin_handle_t handle)
{
struct plugin_context *context = (struct plugin_context *) handle;
free (context);
struct plugin_context *context = (struct plugin_context *) handle;
free(context);
}

View file

@ -44,8 +44,8 @@
* Our context, where we keep our state.
*/
struct plugin_context {
const char *username;
const char *password;
const char *username;
const char *password;
};
/*
@ -54,205 +54,238 @@ struct plugin_context {
* if found or NULL otherwise.
*/
static const char *
get_env (const char *name, const char *envp[])
get_env(const char *name, const char *envp[])
{
if (envp)
if (envp)
{
int i;
const int namelen = strlen (name);
for (i = 0; envp[i]; ++i)
{
if (!strncmp (envp[i], name, namelen))
{
const char *cp = envp[i] + namelen;
if (*cp == '=')
return cp + 1;
}
}
int i;
const int namelen = strlen(name);
for (i = 0; envp[i]; ++i)
{
if (!strncmp(envp[i], name, namelen))
{
const char *cp = envp[i] + namelen;
if (*cp == '=')
{
return cp + 1;
}
}
}
}
return NULL;
return NULL;
}
OPENVPN_EXPORT int
openvpn_plugin_open_v3 (const int v3structver,
struct openvpn_plugin_args_open_in const *args,
struct openvpn_plugin_args_open_return *ret)
openvpn_plugin_open_v3(const int v3structver,
struct openvpn_plugin_args_open_in const *args,
struct openvpn_plugin_args_open_return *ret)
{
struct plugin_context *context = NULL;
struct plugin_context *context = NULL;
/* Check that we are API compatible */
if( v3structver != OPENVPN_PLUGINv3_STRUCTVER ) {
printf("log_v3: ** ERROR ** Incompatible plug-in interface between this plug-in and OpenVPN\n");
return OPENVPN_PLUGIN_FUNC_ERROR;
}
if( args->ssl_api != SSLAPI_OPENSSL ) {
printf("This plug-in can only be used against OpenVPN with OpenSSL\n");
return OPENVPN_PLUGIN_FUNC_ERROR;
}
/* Print some version information about the OpenVPN process using this plug-in */
printf("log_v3: OpenVPN %s (Major: %i, Minor: %i, Patch: %s)\n",
args->ovpn_version, args->ovpn_version_major,
args->ovpn_version_minor, args->ovpn_version_patch);
/* Which callbacks to intercept. */
ret->type_mask =
OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_UP) |
OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_DOWN) |
OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_ROUTE_UP) |
OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_IPCHANGE) |
OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_TLS_VERIFY) |
OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY) |
OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_CLIENT_CONNECT_V2) |
OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_CLIENT_DISCONNECT) |
OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_LEARN_ADDRESS) |
OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_TLS_FINAL);
/* Allocate our context */
context = (struct plugin_context *) calloc (1, sizeof (struct plugin_context));
/* Set the username/password we will require. */
context->username = "foo";
context->password = "bar";
/* Point the global context handle to our newly created context */
ret->handle = (void *) context;
return OPENVPN_PLUGIN_FUNC_SUCCESS;
}
void
show (const int type, const char *argv[], const char *envp[])
{
size_t i;
switch (type)
/* Check that we are API compatible */
if (v3structver != OPENVPN_PLUGINv3_STRUCTVER)
{
case OPENVPN_PLUGIN_UP:
printf ("OPENVPN_PLUGIN_UP\n");
break;
case OPENVPN_PLUGIN_DOWN:
printf ("OPENVPN_PLUGIN_DOWN\n");
break;
case OPENVPN_PLUGIN_ROUTE_UP:
printf ("OPENVPN_PLUGIN_ROUTE_UP\n");
break;
case OPENVPN_PLUGIN_IPCHANGE:
printf ("OPENVPN_PLUGIN_IPCHANGE\n");
break;
case OPENVPN_PLUGIN_TLS_VERIFY:
printf ("OPENVPN_PLUGIN_TLS_VERIFY\n");
break;
case OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY:
printf ("OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY\n");
break;
case OPENVPN_PLUGIN_CLIENT_CONNECT_V2:
printf ("OPENVPN_PLUGIN_CLIENT_CONNECT_V2\n");
break;
case OPENVPN_PLUGIN_CLIENT_DISCONNECT:
printf ("OPENVPN_PLUGIN_CLIENT_DISCONNECT\n");
break;
case OPENVPN_PLUGIN_LEARN_ADDRESS:
printf ("OPENVPN_PLUGIN_LEARN_ADDRESS\n");
break;
case OPENVPN_PLUGIN_TLS_FINAL:
printf ("OPENVPN_PLUGIN_TLS_FINAL\n");
break;
default:
printf ("OPENVPN_PLUGIN_?\n");
break;
printf("log_v3: ** ERROR ** Incompatible plug-in interface between this plug-in and OpenVPN\n");
return OPENVPN_PLUGIN_FUNC_ERROR;
}
printf ("ARGV\n");
for (i = 0; argv[i] != NULL; ++i)
printf ("%d '%s'\n", (int)i, argv[i]);
printf ("ENVP\n");
for (i = 0; envp[i] != NULL; ++i)
printf ("%d '%s'\n", (int)i, envp[i]);
}
static void
x509_print_info (X509 *x509crt)
{
int i, n;
int fn_nid;
ASN1_OBJECT *fn;
ASN1_STRING *val;
X509_NAME *x509_name;
X509_NAME_ENTRY *ent;
const char *objbuf;
unsigned char *buf;
x509_name = X509_get_subject_name (x509crt);
n = X509_NAME_entry_count (x509_name);
for (i = 0; i < n; ++i)
if (args->ssl_api != SSLAPI_OPENSSL)
{
ent = X509_NAME_get_entry (x509_name, i);
if (!ent)
continue;
fn = X509_NAME_ENTRY_get_object (ent);
if (!fn)
continue;
val = X509_NAME_ENTRY_get_data (ent);
if (!val)
continue;
fn_nid = OBJ_obj2nid (fn);
if (fn_nid == NID_undef)
continue;
objbuf = OBJ_nid2sn (fn_nid);
if (!objbuf)
continue;
buf = (unsigned char *)1; /* bug in OpenSSL 0.9.6b ASN1_STRING_to_UTF8 requires this workaround */
if (ASN1_STRING_to_UTF8 (&buf, val) <= 0)
continue;
printf("X509 %s: %s\n", objbuf, (char *)buf);
OPENSSL_free (buf);
printf("This plug-in can only be used against OpenVPN with OpenSSL\n");
return OPENVPN_PLUGIN_FUNC_ERROR;
}
}
/* Print some version information about the OpenVPN process using this plug-in */
printf("log_v3: OpenVPN %s (Major: %i, Minor: %i, Patch: %s)\n",
args->ovpn_version, args->ovpn_version_major,
args->ovpn_version_minor, args->ovpn_version_patch);
/* Which callbacks to intercept. */
ret->type_mask =
OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_UP)
|OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_DOWN)
|OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_ROUTE_UP)
|OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_IPCHANGE)
|OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_TLS_VERIFY)
|OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY)
|OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_CLIENT_CONNECT_V2)
|OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_CLIENT_DISCONNECT)
|OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_LEARN_ADDRESS)
|OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_TLS_FINAL);
/* Allocate our context */
context = (struct plugin_context *) calloc(1, sizeof(struct plugin_context));
OPENVPN_EXPORT int
openvpn_plugin_func_v3 (const int version,
struct openvpn_plugin_args_func_in const *args,
struct openvpn_plugin_args_func_return *retptr)
{
struct plugin_context *context = (struct plugin_context *) args->handle;
/* Set the username/password we will require. */
context->username = "foo";
context->password = "bar";
printf("\nopenvpn_plugin_func_v3() :::::>> ");
show (args->type, args->argv, args->envp);
/* Point the global context handle to our newly created context */
ret->handle = (void *) context;
/* Dump some X509 information if we're in the TLS_VERIFY phase */
if ((args->type == OPENVPN_PLUGIN_TLS_VERIFY) && args->current_cert ) {
printf("---- X509 Subject information ----\n");
printf("Certificate depth: %i\n", args->current_cert_depth);
x509_print_info(args->current_cert);
printf("----------------------------------\n");
}
/* check entered username/password against what we require */
if (args->type == OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY)
{
/* get username/password from envp string array */
const char *username = get_env ("username", args->envp);
const char *password = get_env ("password", args->envp);
if (username && !strcmp (username, context->username)
&& password && !strcmp (password, context->password))
return OPENVPN_PLUGIN_FUNC_SUCCESS;
else
return OPENVPN_PLUGIN_FUNC_ERROR;
}
else
return OPENVPN_PLUGIN_FUNC_SUCCESS;
}
OPENVPN_EXPORT void
openvpn_plugin_close_v1 (openvpn_plugin_handle_t handle)
void
show(const int type, const char *argv[], const char *envp[])
{
struct plugin_context *context = (struct plugin_context *) handle;
free (context);
size_t i;
switch (type)
{
case OPENVPN_PLUGIN_UP:
printf("OPENVPN_PLUGIN_UP\n");
break;
case OPENVPN_PLUGIN_DOWN:
printf("OPENVPN_PLUGIN_DOWN\n");
break;
case OPENVPN_PLUGIN_ROUTE_UP:
printf("OPENVPN_PLUGIN_ROUTE_UP\n");
break;
case OPENVPN_PLUGIN_IPCHANGE:
printf("OPENVPN_PLUGIN_IPCHANGE\n");
break;
case OPENVPN_PLUGIN_TLS_VERIFY:
printf("OPENVPN_PLUGIN_TLS_VERIFY\n");
break;
case OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY:
printf("OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY\n");
break;
case OPENVPN_PLUGIN_CLIENT_CONNECT_V2:
printf("OPENVPN_PLUGIN_CLIENT_CONNECT_V2\n");
break;
case OPENVPN_PLUGIN_CLIENT_DISCONNECT:
printf("OPENVPN_PLUGIN_CLIENT_DISCONNECT\n");
break;
case OPENVPN_PLUGIN_LEARN_ADDRESS:
printf("OPENVPN_PLUGIN_LEARN_ADDRESS\n");
break;
case OPENVPN_PLUGIN_TLS_FINAL:
printf("OPENVPN_PLUGIN_TLS_FINAL\n");
break;
default:
printf("OPENVPN_PLUGIN_?\n");
break;
}
printf("ARGV\n");
for (i = 0; argv[i] != NULL; ++i)
printf("%d '%s'\n", (int)i, argv[i]);
printf("ENVP\n");
for (i = 0; envp[i] != NULL; ++i)
printf("%d '%s'\n", (int)i, envp[i]);
}
static void
x509_print_info(X509 *x509crt)
{
int i, n;
int fn_nid;
ASN1_OBJECT *fn;
ASN1_STRING *val;
X509_NAME *x509_name;
X509_NAME_ENTRY *ent;
const char *objbuf;
unsigned char *buf;
x509_name = X509_get_subject_name(x509crt);
n = X509_NAME_entry_count(x509_name);
for (i = 0; i < n; ++i)
{
ent = X509_NAME_get_entry(x509_name, i);
if (!ent)
{
continue;
}
fn = X509_NAME_ENTRY_get_object(ent);
if (!fn)
{
continue;
}
val = X509_NAME_ENTRY_get_data(ent);
if (!val)
{
continue;
}
fn_nid = OBJ_obj2nid(fn);
if (fn_nid == NID_undef)
{
continue;
}
objbuf = OBJ_nid2sn(fn_nid);
if (!objbuf)
{
continue;
}
buf = (unsigned char *)1; /* bug in OpenSSL 0.9.6b ASN1_STRING_to_UTF8 requires this workaround */
if (ASN1_STRING_to_UTF8(&buf, val) <= 0)
{
continue;
}
printf("X509 %s: %s\n", objbuf, (char *)buf);
OPENSSL_free(buf);
}
}
OPENVPN_EXPORT int
openvpn_plugin_func_v3(const int version,
struct openvpn_plugin_args_func_in const *args,
struct openvpn_plugin_args_func_return *retptr)
{
struct plugin_context *context = (struct plugin_context *) args->handle;
printf("\nopenvpn_plugin_func_v3() :::::>> ");
show(args->type, args->argv, args->envp);
/* Dump some X509 information if we're in the TLS_VERIFY phase */
if ((args->type == OPENVPN_PLUGIN_TLS_VERIFY) && args->current_cert)
{
printf("---- X509 Subject information ----\n");
printf("Certificate depth: %i\n", args->current_cert_depth);
x509_print_info(args->current_cert);
printf("----------------------------------\n");
}
/* check entered username/password against what we require */
if (args->type == OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY)
{
/* get username/password from envp string array */
const char *username = get_env("username", args->envp);
const char *password = get_env("password", args->envp);
if (username && !strcmp(username, context->username)
&& password && !strcmp(password, context->password))
{
return OPENVPN_PLUGIN_FUNC_SUCCESS;
}
else
{
return OPENVPN_PLUGIN_FUNC_ERROR;
}
}
else
{
return OPENVPN_PLUGIN_FUNC_SUCCESS;
}
}
OPENVPN_EXPORT void
openvpn_plugin_close_v1(openvpn_plugin_handle_t handle)
{
struct plugin_context *context = (struct plugin_context *) handle;
free(context);
}

View file

@ -41,8 +41,8 @@
* Our context, where we keep our state.
*/
struct plugin_context {
const char *username;
const char *password;
const char *username;
const char *password;
};
/*
@ -51,70 +51,76 @@ struct plugin_context {
* if found or NULL otherwise.
*/
static const char *
get_env (const char *name, const char *envp[])
get_env(const char *name, const char *envp[])
{
if (envp)
if (envp)
{
int i;
const int namelen = strlen (name);
for (i = 0; envp[i]; ++i)
{
if (!strncmp (envp[i], name, namelen))
{
const char *cp = envp[i] + namelen;
if (*cp == '=')
return cp + 1;
}
}
int i;
const int namelen = strlen(name);
for (i = 0; envp[i]; ++i)
{
if (!strncmp(envp[i], name, namelen))
{
const char *cp = envp[i] + namelen;
if (*cp == '=')
{
return cp + 1;
}
}
}
}
return NULL;
return NULL;
}
OPENVPN_EXPORT openvpn_plugin_handle_t
openvpn_plugin_open_v1 (unsigned int *type_mask, const char *argv[], const char *envp[])
openvpn_plugin_open_v1(unsigned int *type_mask, const char *argv[], const char *envp[])
{
struct plugin_context *context;
struct plugin_context *context;
/*
* Allocate our context
*/
context = (struct plugin_context *) calloc (1, sizeof (struct plugin_context));
/*
* Allocate our context
*/
context = (struct plugin_context *) calloc(1, sizeof(struct plugin_context));
/*
* Set the username/password we will require.
*/
context->username = "foo";
context->password = "bar";
/*
* Set the username/password we will require.
*/
context->username = "foo";
context->password = "bar";
/*
* We are only interested in intercepting the
* --auth-user-pass-verify callback.
*/
*type_mask = OPENVPN_PLUGIN_MASK (OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY);
/*
* We are only interested in intercepting the
* --auth-user-pass-verify callback.
*/
*type_mask = OPENVPN_PLUGIN_MASK(OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY);
return (openvpn_plugin_handle_t) context;
return (openvpn_plugin_handle_t) context;
}
OPENVPN_EXPORT int
openvpn_plugin_func_v1 (openvpn_plugin_handle_t handle, const int type, const char *argv[], const char *envp[])
openvpn_plugin_func_v1(openvpn_plugin_handle_t handle, const int type, const char *argv[], const char *envp[])
{
struct plugin_context *context = (struct plugin_context *) handle;
struct plugin_context *context = (struct plugin_context *) handle;
/* get username/password from envp string array */
const char *username = get_env ("username", envp);
const char *password = get_env ("password", envp);
/* get username/password from envp string array */
const char *username = get_env("username", envp);
const char *password = get_env("password", envp);
/* check entered username/password against what we require */
if (username && !strcmp (username, context->username)
&& password && !strcmp (password, context->password))
return OPENVPN_PLUGIN_FUNC_SUCCESS;
else
return OPENVPN_PLUGIN_FUNC_ERROR;
/* check entered username/password against what we require */
if (username && !strcmp(username, context->username)
&& password && !strcmp(password, context->password))
{
return OPENVPN_PLUGIN_FUNC_SUCCESS;
}
else
{
return OPENVPN_PLUGIN_FUNC_ERROR;
}
}
OPENVPN_EXPORT void
openvpn_plugin_close_v1 (openvpn_plugin_handle_t handle)
openvpn_plugin_close_v1(openvpn_plugin_handle_t handle)
{
struct plugin_context *context = (struct plugin_context *) handle;
free (context);
struct plugin_context *context = (struct plugin_context *) handle;
free(context);
}

View file

@ -37,14 +37,15 @@
* This version is extended to handle both / and \ in path names
*/
char *
basename (char *filename)
basename(char *filename)
{
char *p = strrchr (filename, '/');
if (!p) {
/* If NULL, check for \ instead ... might be Windows a path */
p = strrchr (filename, '\\');
}
return p ? p + 1 : (char *) filename;
char *p = strrchr(filename, '/');
if (!p)
{
/* If NULL, check for \ instead ... might be Windows a path */
p = strrchr(filename, '\\');
}
return p ? p + 1 : (char *) filename;
}
#endif /* HAVE_BASENAME */

View file

@ -58,43 +58,52 @@ int
daemon(int nochdir, int noclose)
{
#if defined(HAVE_FORK) && defined(HAVE_SETSID)
switch (fork()) {
case -1:
return (-1);
case 0:
break;
default:
exit(0);
}
switch (fork()) {
case -1:
return (-1);
if (setsid() == -1)
return (-1);
case 0:
break;
if (!nochdir)
chdir("/");
default:
exit(0);
}
if (!noclose) {
if (setsid() == -1)
{
return (-1);
}
if (!nochdir)
{
chdir("/");
}
if (!noclose)
{
#if defined(HAVE_DUP) && defined(HAVE_DUP2)
int fd;
if ((fd = open ("/dev/null", O_RDWR, 0)) != -1) {
dup2 (fd, 0);
dup2 (fd, 1);
dup2 (fd, 2);
if (fd > 2) {
close (fd);
}
}
int fd;
if ((fd = open("/dev/null", O_RDWR, 0)) != -1)
{
dup2(fd, 0);
dup2(fd, 1);
dup2(fd, 2);
if (fd > 2)
{
close(fd);
}
}
#endif
}
}
return 0;
#else
(void)nochdir;
(void)noclose;
errno = EFAULT;
return -1;
#endif
return 0;
#else /* if defined(HAVE_FORK) && defined(HAVE_SETSID) */
(void)nochdir;
(void)noclose;
errno = EFAULT;
return -1;
#endif /* if defined(HAVE_FORK) && defined(HAVE_SETSID) */
}
#endif
#endif /* ifndef HAVE_DAEMON */

View file

@ -41,79 +41,102 @@
static const char *
__memrchr(const char *str, int c, size_t n)
{
const char *end = str;
const char *end = str;
end += n - 1; /* Go to the end of the string */
while (end >= str) {
if(c == *end)
return end;
else
end--;
}
return NULL;
end += n - 1; /* Go to the end of the string */
while (end >= str) {
if (c == *end)
{
return end;
}
else
{
end--;
}
}
return NULL;
}
/* Modified version based on glibc-2.14.1 by Ulrich Drepper <drepper@akkadia.org>
* This version is extended to handle both / and \ in path names.
*/
char *
dirname (char *path)
dirname(char *path)
{
static const char dot[] = ".";
char *last_slash;
char separator = '/';
static const char dot[] = ".";
char *last_slash;
char separator = '/';
/* Find last '/'. */
last_slash = path != NULL ? strrchr (path, '/') : NULL;
/* If NULL, check for \ instead ... might be Windows a path */
if (!last_slash) {
last_slash = path != NULL ? strrchr (path, '\\') : NULL;
separator = last_slash ? '\\' : '/'; /* Change the separator if \ was found */
}
if (last_slash != NULL && last_slash != path && last_slash[1] == '\0') {
/* Determine whether all remaining characters are slashes. */
char *runp;
for (runp = last_slash; runp != path; --runp)
if (runp[-1] != separator)
break;
/* The '/' is the last character, we have to look further. */
if (runp != path)
last_slash = (char *) __memrchr (path, separator, runp - path);
/* Find last '/'. */
last_slash = path != NULL ? strrchr(path, '/') : NULL;
/* If NULL, check for \ instead ... might be Windows a path */
if (!last_slash)
{
last_slash = path != NULL ? strrchr(path, '\\') : NULL;
separator = last_slash ? '\\' : '/'; /* Change the separator if \ was found */
}
if (last_slash != NULL) {
/* Determine whether all remaining characters are slashes. */
char *runp;
if (last_slash != NULL && last_slash != path && last_slash[1] == '\0')
{
/* Determine whether all remaining characters are slashes. */
char *runp;
for (runp = last_slash; runp != path; --runp)
if (runp[-1] != separator)
break;
for (runp = last_slash; runp != path; --runp)
if (runp[-1] != separator)
{
break;
}
/* Terminate the path. */
if (runp == path) {
/* The last slash is the first character in the string. We have to
return "/". As a special case we have to return "//" if there
are exactly two slashes at the beginning of the string. See
XBD 4.10 Path Name Resolution for more information. */
if (last_slash == path + 1)
++last_slash;
else
last_slash = path + 1;
}
else
last_slash = runp;
/* The '/' is the last character, we have to look further. */
if (runp != path)
{
last_slash = (char *) __memrchr(path, separator, runp - path);
}
}
last_slash[0] = '\0';
} else
/* This assignment is ill-designed but the XPG specs require to
return a string containing "." in any case no directory part is
found and so a static and constant string is required. */
path = (char *) dot;
if (last_slash != NULL)
{
/* Determine whether all remaining characters are slashes. */
char *runp;
return path;
for (runp = last_slash; runp != path; --runp)
if (runp[-1] != separator)
{
break;
}
/* Terminate the path. */
if (runp == path)
{
/* The last slash is the first character in the string. We have to
* return "/". As a special case we have to return "//" if there
* are exactly two slashes at the beginning of the string. See
* XBD 4.10 Path Name Resolution for more information. */
if (last_slash == path + 1)
{
++last_slash;
}
else
{
last_slash = path + 1;
}
}
else
{
last_slash = runp;
}
last_slash[0] = '\0';
}
else
{
/* This assignment is ill-designed but the XPG specs require to
* return a string containing "." in any case no directory part is
* found and so a static and constant string is required. */
path = (char *) dot;
}
return path;
}
#endif /* HAVE_DIRNAME */

View file

@ -48,12 +48,12 @@ static unsigned int last_msec = 0;
static int bt_last = 0;
static void
gettimeofday_calibrate (void)
gettimeofday_calibrate(void)
{
const time_t t = time(NULL);
const DWORD gtc = GetTickCount();
gtc_base = t - gtc/1000;
gtc_last = gtc;
const time_t t = time(NULL);
const DWORD gtc = GetTickCount();
gtc_base = t - gtc/1000;
gtc_last = gtc;
}
/*
@ -62,68 +62,72 @@ gettimeofday_calibrate (void)
* more processor cycles than GetTickCount.
*/
int
gettimeofday (struct timeval *tv, void *tz)
gettimeofday(struct timeval *tv, void *tz)
{
const DWORD gtc = GetTickCount();
int bt = 0;
time_t sec;
unsigned int msec;
const int backtrack_hold_seconds = 10;
const DWORD gtc = GetTickCount();
int bt = 0;
time_t sec;
unsigned int msec;
const int backtrack_hold_seconds = 10;
(void)tz;
(void)tz;
/* recalibrate at the dreaded 49.7 day mark */
if (!gtc_base || gtc < gtc_last)
gettimeofday_calibrate ();
gtc_last = gtc;
sec = gtc_base + gtc / 1000;
msec = gtc % 1000;
if (sec == last_sec)
/* recalibrate at the dreaded 49.7 day mark */
if (!gtc_base || gtc < gtc_last)
{
if (msec < last_msec)
{
msec = last_msec;
bt = 1;
}
gettimeofday_calibrate();
}
else if (sec < last_sec)
gtc_last = gtc;
sec = gtc_base + gtc / 1000;
msec = gtc % 1000;
if (sec == last_sec)
{
/* We try to dampen out backtracks of less than backtrack_hold_seconds.
Larger backtracks will be passed through and dealt with by the
TIME_BACKTRACK_PROTECTION code (if enabled) */
if (sec > last_sec - backtrack_hold_seconds)
{
sec = last_sec;
msec = last_msec;
}
bt = 1;
if (msec < last_msec)
{
msec = last_msec;
bt = 1;
}
}
else if (sec < last_sec)
{
/* We try to dampen out backtracks of less than backtrack_hold_seconds.
* Larger backtracks will be passed through and dealt with by the
* TIME_BACKTRACK_PROTECTION code (if enabled) */
if (sec > last_sec - backtrack_hold_seconds)
{
sec = last_sec;
msec = last_msec;
}
bt = 1;
}
tv->tv_sec = (long)last_sec = (long)sec;
tv->tv_usec = (last_msec = msec) * 1000;
tv->tv_sec = (long)last_sec = (long)sec;
tv->tv_usec = (last_msec = msec) * 1000;
if (bt && !bt_last)
gettimeofday_calibrate ();
bt_last = bt;
if (bt && !bt_last)
{
gettimeofday_calibrate();
}
bt_last = bt;
return 0;
return 0;
}
#else
#else /* ifdef _WIN32 */
#ifdef HAVE_TIME_H
#include <time.h>
#endif
int
gettimeofday (struct timeval *tv, void *tz)
gettimeofday(struct timeval *tv, void *tz)
{
(void)tz;
tv->tv_sec = time(NULL);
tv->tv_usec = 0;
return 0;
(void)tz;
tv->tv_sec = time(NULL);
tv->tv_usec = 0;
return 0;
}
#endif /* _WIN32 */

View file

@ -46,31 +46,33 @@
const char *
inet_ntop(int af, const void *src, char *dst, socklen_t size)
{
struct sockaddr_storage ss;
unsigned long s = size;
struct sockaddr_storage ss;
unsigned long s = size;
ZeroMemory(&ss, sizeof(ss));
ss.ss_family = af;
ZeroMemory(&ss, sizeof(ss));
ss.ss_family = af;
switch(af) {
case AF_INET:
((struct sockaddr_in *)&ss)->sin_addr = *(struct in_addr *)src;
break;
case AF_INET6:
((struct sockaddr_in6 *)&ss)->sin6_addr = *(struct in6_addr *)src;
break;
default:
return NULL;
}
/* cannot direclty use &size because of strict aliasing rules */
return (WSAAddressToString((struct sockaddr *)&ss, sizeof(ss), NULL, dst, &s) == 0)?
dst : NULL;
switch (af) {
case AF_INET:
((struct sockaddr_in *)&ss)->sin_addr = *(struct in_addr *)src;
break;
case AF_INET6:
((struct sockaddr_in6 *)&ss)->sin6_addr = *(struct in6_addr *)src;
break;
default:
return NULL;
}
/* cannot direclty use &size because of strict aliasing rules */
return (WSAAddressToString((struct sockaddr *)&ss, sizeof(ss), NULL, dst, &s) == 0) ?
dst : NULL;
}
#else
#else /* ifdef _WIN32 */
#error no emulation for inet_ntop
#endif
#endif /* ifdef _WIN32 */
#endif
#endif /* ifndef HAVE_INET_NTOP */

View file

@ -48,32 +48,34 @@
int
inet_pton(int af, const char *src, void *dst)
{
struct sockaddr_storage ss;
int size = sizeof(ss);
char src_copy[INET6_ADDRSTRLEN+1];
struct sockaddr_storage ss;
int size = sizeof(ss);
char src_copy[INET6_ADDRSTRLEN+1];
ZeroMemory(&ss, sizeof(ss));
/* stupid non-const API */
strncpy (src_copy, src, INET6_ADDRSTRLEN+1);
src_copy[INET6_ADDRSTRLEN] = 0;
ZeroMemory(&ss, sizeof(ss));
/* stupid non-const API */
strncpy(src_copy, src, INET6_ADDRSTRLEN+1);
src_copy[INET6_ADDRSTRLEN] = 0;
if (WSAStringToAddress(src_copy, af, NULL, (struct sockaddr *)&ss, &size) == 0) {
switch(af) {
case AF_INET:
*(struct in_addr *)dst = ((struct sockaddr_in *)&ss)->sin_addr;
return 1;
case AF_INET6:
*(struct in6_addr *)dst = ((struct sockaddr_in6 *)&ss)->sin6_addr;
return 1;
if (WSAStringToAddress(src_copy, af, NULL, (struct sockaddr *)&ss, &size) == 0)
{
switch (af) {
case AF_INET:
*(struct in_addr *)dst = ((struct sockaddr_in *)&ss)->sin_addr;
return 1;
case AF_INET6:
*(struct in6_addr *)dst = ((struct sockaddr_in6 *)&ss)->sin6_addr;
return 1;
}
}
}
return 0;
return 0;
}
#else
#else /* ifdef _WIN32 */
#error no emulation for inet_ntop
#endif
#endif /* ifdef _WIN32 */
#endif
#endif /* ifndef HAVE_INET_PTON */

View file

@ -18,64 +18,77 @@
#define _WIN32_WINNT_WINBLUE 0x0603
VERSIONHELPERAPI IsWindowsVersionOrGreater(WORD major, WORD minor, WORD servpack)
VERSIONHELPERAPI
IsWindowsVersionOrGreater(WORD major, WORD minor, WORD servpack)
{
OSVERSIONINFOEXW vi = {sizeof(vi),major,minor,0,0,{0},servpack};
return VerifyVersionInfoW(&vi, VER_MAJORVERSION|VER_MINORVERSION|VER_SERVICEPACKMAJOR,
VerSetConditionMask(VerSetConditionMask(VerSetConditionMask(0,
VER_MAJORVERSION,VER_GREATER_EQUAL),
VER_MINORVERSION,VER_GREATER_EQUAL),
VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL));
VerSetConditionMask(VerSetConditionMask(VerSetConditionMask(0,
VER_MAJORVERSION,VER_GREATER_EQUAL),
VER_MINORVERSION,VER_GREATER_EQUAL),
VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL));
}
VERSIONHELPERAPI IsWindowsXPOrGreater(void) {
VERSIONHELPERAPI
IsWindowsXPOrGreater(void) {
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 0);
}
VERSIONHELPERAPI IsWindowsXPSP1OrGreater(void) {
VERSIONHELPERAPI
IsWindowsXPSP1OrGreater(void) {
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 1);
}
VERSIONHELPERAPI IsWindowsXPSP2OrGreater(void) {
VERSIONHELPERAPI
IsWindowsXPSP2OrGreater(void) {
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 2);
}
VERSIONHELPERAPI IsWindowsXPSP3OrGreater(void) {
VERSIONHELPERAPI
IsWindowsXPSP3OrGreater(void) {
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 3);
}
VERSIONHELPERAPI IsWindowsVistaOrGreater(void) {
VERSIONHELPERAPI
IsWindowsVistaOrGreater(void) {
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 0);
}
VERSIONHELPERAPI IsWindowsVistaSP1OrGreater(void) {
VERSIONHELPERAPI
IsWindowsVistaSP1OrGreater(void) {
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 1);
}
VERSIONHELPERAPI IsWindowsVistaSP2OrGreater(void) {
VERSIONHELPERAPI
IsWindowsVistaSP2OrGreater(void) {
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 2);
}
VERSIONHELPERAPI IsWindows7OrGreater(void) {
VERSIONHELPERAPI
IsWindows7OrGreater(void) {
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN7), LOBYTE(_WIN32_WINNT_WIN7), 0);
}
VERSIONHELPERAPI IsWindows7SP1OrGreater(void) {
VERSIONHELPERAPI
IsWindows7SP1OrGreater(void) {
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN7), LOBYTE(_WIN32_WINNT_WIN7), 1);
}
VERSIONHELPERAPI IsWindows8OrGreater(void) {
VERSIONHELPERAPI
IsWindows8OrGreater(void) {
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN8), LOBYTE(_WIN32_WINNT_WIN8), 0);
}
VERSIONHELPERAPI IsWindows8Point1OrGreater(void) {
VERSIONHELPERAPI
IsWindows8Point1OrGreater(void) {
return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINBLUE), LOBYTE(_WIN32_WINNT_WINBLUE), 0);
}
VERSIONHELPERAPI IsWindowsServer(void) {
VERSIONHELPERAPI
IsWindowsServer(void) {
OSVERSIONINFOEXW vi = {sizeof(vi),0,0,0,0,{0},0,0,0,VER_NT_WORKSTATION};
return !VerifyVersionInfoW(&vi, VER_PRODUCT_TYPE, VerSetConditionMask(0, VER_PRODUCT_TYPE, VER_EQUAL));
}
#endif
#endif
#endif /* if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && !defined(__WIDL__) */
#endif /* ifndef _INC_VERSIONHELPERS */

View file

@ -42,27 +42,33 @@
#endif
#ifndef HAVE_DIRNAME
char * dirname(char *str);
char *dirname(char *str);
#endif /* HAVE_DIRNAME */
#ifndef HAVE_BASENAME
char * basename(char *str);
char *basename(char *str);
#endif /* HAVE_BASENAME */
#ifndef HAVE_GETTIMEOFDAY
int gettimeofday (struct timeval *tv, void *tz);
int gettimeofday(struct timeval *tv, void *tz);
#endif
#ifndef HAVE_DAEMON
int daemon(int nochdir, int noclose);
#endif
#ifndef HAVE_INET_NTOP
const char * inet_ntop(int af, const void *src, char *dst, socklen_t size);
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
#endif
#ifndef HAVE_INET_PTON
int inet_pton(int af, const char *src, void *dst);
#endif
#endif /* COMPAT_H */

View file

@ -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;
while (true)
if (*p == '\0')
{
const int c = *p;
if (c == '\0')
break;
if (term)
return NULL;
}
while (true)
{
const int c = *p;
if (c == '\0')
{
if (!isspace (c))
++termlen;
else
break;
}
else
if (term)
{
if (!isspace (c))
if (!isspace(c))
{
term = p;
termlen = 1;
++termlen;
}
else
{
break;
}
}
++p;
else
{
if (!isspace(c))
{
term = p;
termlen = 1;
}
}
++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;
char *ret;
ASSERT(termlen > 0);
ret = malloc(termlen + 1);
check_malloc_return(ret);
memcpy(ret, term, termlen);
ret[termlen] = '\0';
return ret;
}
else
{
return NULL;
}
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 *);
char numstr[64];
char *s = va_arg(arglist, char *);
if (!s)
s = "";
if (!s)
{
s = "";
}
openvpn_snprintf (numstr, sizeof (numstr), "%d", va_arg (arglist, int));
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);
{
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);
}
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;
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);
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);
}
void
argv_printf_cat (struct argv *a, const char *format, ...)
{
va_list arglist;
va_start (arglist, format);
argv_printf_arglist (a, format, arglist);
va_end (arglist);
va_list arglist;
argv_reset(a);
va_start(arglist, format);
argv_printf_arglist(a, format, arglist);
va_end(arglist);
}
void
argv_parse_cmd (struct argv *a, const char *s)
argv_printf_cat(struct argv *a, const char *format, ...)
{
int nparms;
char *parms[MAX_PARMS + 1];
struct gc_arena gc = gc_new ();
va_list arglist;
va_start(arglist, format);
argv_printf_arglist(a, format, arglist);
va_end(arglist);
}
argv_reset (a);
argv_extend (a, 1); /* ensure trailing NULL */
void
argv_parse_cmd(struct argv *a, const char *s)
{
int nparms;
char *parms[MAX_PARMS + 1];
struct gc_arena gc = gc_new();
nparms = parse_line (s, parms, MAX_PARMS, "SCRIPT-ARGV", 0, D_ARGV_PARSE_CMD, &gc);
if (nparms)
argv_reset(a);
argv_extend(a, 1); /* ensure trailing NULL */
nparms = parse_line(s, parms, MAX_PARMS, "SCRIPT-ARGV", 0, D_ARGV_PARSE_CMD, &gc);
if (nparms)
{
int i;
for (i = 0; i < nparms; ++i)
argv_append (a, string_alloc (parms[i], NULL));
int i;
for (i = 0; i < nparms; ++i)
argv_append(a, string_alloc(parms[i], NULL));
}
else
{
argv_append(a, string_alloc(s, NULL));
}
else
argv_append (a, string_alloc (s, NULL));
gc_free (&gc);
gc_free(&gc);
}

View file

@ -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 */

View file

@ -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;
}

View file

@ -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

View file

@ -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
);
FWPM_LAYER_ALE_AUTH_CONNECT_V4,
0xc38d57d1,
0x05a7,
0x4c33,
0x90, 0x4f, 0x7f, 0xbc, 0xee, 0xe6, 0x0e, 0x82
);
// 4a72393b-319f-44bc-84c3-ba54dcb3b6b4
/* 4a72393b-319f-44bc-84c3-ba54dcb3b6b4 */
DEFINE_GUID(
FWPM_LAYER_ALE_AUTH_CONNECT_V6,
0x4a72393b,
0x319f,
0x44bc,
0x84, 0xc3, 0xba, 0x54, 0xdc, 0xb3, 0xb6, 0xb4
);
FWPM_LAYER_ALE_AUTH_CONNECT_V6,
0x4a72393b,
0x319f,
0x44bc,
0x84, 0xc3, 0xba, 0x54, 0xdc, 0xb3, 0xb6, 0xb4
);
// d78e1e87-8644-4ea5-9437-d809ecefc971
/* d78e1e87-8644-4ea5-9437-d809ecefc971 */
DEFINE_GUID(
FWPM_CONDITION_ALE_APP_ID,
0xd78e1e87,
0x8644,
0x4ea5,
0x94, 0x37, 0xd8, 0x09, 0xec, 0xef, 0xc9, 0x71
);
FWPM_CONDITION_ALE_APP_ID,
0xd78e1e87,
0x8644,
0x4ea5,
0x94, 0x37, 0xd8, 0x09, 0xec, 0xef, 0xc9, 0x71
);
// c35a604d-d22b-4e1a-91b4-68f674ee674b
/* c35a604d-d22b-4e1a-91b4-68f674ee674b */
DEFINE_GUID(
FWPM_CONDITION_IP_REMOTE_PORT,
0xc35a604d,
0xd22b,
0x4e1a,
0x91, 0xb4, 0x68, 0xf6, 0x74, 0xee, 0x67, 0x4b
);
FWPM_CONDITION_IP_REMOTE_PORT,
0xc35a604d,
0xd22b,
0x4e1a,
0x91, 0xb4, 0x68, 0xf6, 0x74, 0xee, 0x67, 0x4b
);
// 4cd62a49-59c3-4969-b7f3-bda5d32890a4
/* 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;
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)
if (!msg_handler)
{
msg_handler (0, "Block_DNS: Using existing sublayer");
FwpmFreeMemory0 ((void **)&sublayer_ptr);
msg_handler = default_msg_handler;
}
else
/* 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);
* 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");
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 (err && *engine_handle)
if (openvpnblob)
{
FwpmEngineClose0 (*engine_handle);
*engine_handle = NULL;
FwpmFreeMemory0((void **)&openvpnblob);
}
return err;
if (err && *engine_handle)
{
FwpmEngineClose0(*engine_handle);
*engine_handle = NULL;
}
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 */

View file

@ -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

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -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 */

View file

@ -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));
gc_free (&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);
}
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);
for (i = 0; i < list->n; ++i)
if (check_debug_level(D_CLIENT_NAT))
{
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);
/* do NAT transform */
addr = (addr & ~e->netmask) | *to;
/* post-adjust IP checksum */
SUB_CHECKSUM_32(accumulate, addr);
/* write the modified address to packet */
*addr_ptr = addr;
/* mark as modified */
alog |= amask;
}
print_pkt(&h->ip, "BEFORE", direction, D_CLIENT_NAT);
}
if (alog)
for (i = 0; i < list->n; ++i)
{
if (check_debug_level (D_CLIENT_NAT))
print_pkt (&h->ip, "AFTER", direction, D_CLIENT_NAT);
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;
}
ADJUST_CHECKSUM(accumulate, h->ip.check);
if (((addr & e->netmask) == *from) && !(amask & alog))
{
/* pre-adjust IP checksum */
ADD_CHECKSUM_32(accumulate, addr);
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);
}
}
/* do NAT transform */
addr = (addr & ~e->netmask) | *to;
/* post-adjust IP checksum */
SUB_CHECKSUM_32(accumulate, addr);
/* write the modified address to packet */
*addr_ptr = addr;
/* mark as modified */
alog |= amask;
}
}
if (alog)
{
if (check_debug_level(D_CLIENT_NAT))
{
print_pkt(&h->ip, "AFTER", direction, D_CLIENT_NAT);
}
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);
}
}
}
}

View file

@ -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) */

View file

@ -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 */

View file

@ -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);
/* On error do_lz4_compress sets buf len to zero, just return */
if (buf->len == 0)
return;
/* 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;
}
bool compressed;
if (buf->len <= 0)
{
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;
return;
}
compressed = do_lz4_compress(buf, &work, compctx, frame);
/* On error do_lz4_compress sets buf len to zero, just return */
if (buf->len == 0)
{
return;
}
/* did compression save us anything? */
{
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;
compressed = do_lz4_compress(buf, &work, compctx, frame);
/* On Error just return */
if (buf->len == 0)
return;
/* did compression save us anything? Include 2 byte compression header
in calculation */
if (compressed && work.len + 2 < buf->len)
bool compressed;
if (buf->len <= 0)
{
ASSERT(buf_prepend(&work, 2));
uint8_t *head = BPTR (&work);
head[0] = COMP_ALGV2_INDICATOR_BYTE;
head[1] = COMP_ALGV2_LZ4_BYTE;
*buf = work;
return;
}
else
compressed = do_lz4_compress(buf, &work, compctx, frame);
/* On Error just return */
if (buf->len == 0)
{
compv2_escape_data_ifneeded(buf);
return;
}
/* did compression save us anything? Include 2 byte compression header
* in calculation */
if (compressed && work.len + 2 < buf->len)
{
ASSERT(buf_prepend(&work, 2));
uint8_t *head = BPTR(&work);
head[0] = COMP_ALGV2_INDICATOR_BYTE;
head[1] = COMP_ALGV2_LZ4_BYTE;
*buf = work;
}
else
{
compv2_escape_data_ifneeded(buf);
}
}
void
do_lz4_decompress(size_t zlen_max,
struct buffer *work,
struct buffer *buf,
struct compress_context *compctx)
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);
/* 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 */
{
do_lz4_decompress(zlen_max, &work, buf, compctx);
}
else if (c == NO_COMPRESS_BYTE_SWAP) /* packet was not compressed */
{
}
else
{
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)
{
size_t zlen_max = EXPANDED_SIZE(frame);
uint8_t c; /* flag indicating whether or not our peer compressed */
if (buf->len <= 0)
{
return;
}
ASSERT(buf_init(&work, FRAME_HEADROOM(frame)));
/* do unframing/swap (assumes buf->len > 0) */
uint8_t *head = BPTR(buf);
c = *head;
--buf->len;
*head = *BEND (buf);
}
if (c == LZ4_COMPRESS_BYTE) /* packet was compressed */
/* Not compressed */
if (c != COMP_ALGV2_INDICATOR_BYTE)
{
do_lz4_decompress(zlen_max, &work, buf, compctx);
}
else if (c == NO_COMPRESS_BYTE_SWAP) /* packet was not compressed */
{
;
}
else
{
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)
{
size_t zlen_max = EXPANDED_SIZE (frame);
uint8_t c; /* flag indicating whether or not our peer compressed */
if (buf->len <= 0)
return;
ASSERT (buf_init (&work, FRAME_HEADROOM (frame)));
/* do unframing/swap (assumes buf->len > 0) */
uint8_t *head = BPTR (buf);
c = *head;
/* Not compressed */
if (c != COMP_ALGV2_INDICATOR_BYTE) {
return;
}
/* Packet to short to make sense */
if (buf->len <= 1)
{
buf->len=0;
return;
return;
}
c = head[1];
if (c == COMP_ALGV2_LZ4_BYTE) /* packet was compressed */
/* Packet to short to make sense */
if (buf->len <= 1)
{
buf_advance(buf,2);
do_lz4_decompress(zlen_max, &work, buf, compctx);
buf->len = 0;
return;
}
else if (c == COMP_ALGV2_UNCOMPRESSED_BYTE)
c = head[1];
if (c == COMP_ALGV2_LZ4_BYTE) /* packet was compressed */
{
buf_advance(buf,2);
buf_advance(buf,2);
do_lz4_decompress(zlen_max, &work, buf, compctx);
}
else
else if (c == COMP_ALGV2_UNCOMPRESSED_BYTE)
{
dmsg (D_COMP_ERRORS, "Bad LZ4v2 decompression header byte: %d", c);
buf->len = 0;
buf_advance(buf,2);
}
else
{
dmsg(D_COMP_ERRORS, "Bad LZ4v2 decompression header byte: %d", c);
buf->len = 0;
}
}
const struct compress_alg lz4_alg = {
"lz4",
lz4_compress_init,
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 */

View file

@ -35,7 +35,7 @@ extern const struct compress_alg lz4v2_alg;
struct lz4_workspace
{
int dummy;
int dummy;
};
#endif /* ENABLE_LZ4 */

View file

@ -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");
}
}

View file

@ -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);
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);
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;
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;
/* 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 */

View file

@ -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)
{
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;
}
else
{
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)
{
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;
}
}
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;
}
}
}
static void
stubv2_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;
{
return;
}
if (compctx->flags & COMP_F_SWAP)
{
uint8_t *head = BPTR(buf);
uint8_t *tail = BEND(buf);
ASSERT(buf_safe(buf, 1));
++buf->len;
compv2_escape_data_ifneeded (buf);
/* move head byte of payload to tail */
*tail = *head;
*head = NO_COMPRESS_BYTE_SWAP;
}
else
{
uint8_t *header = buf_prepend(buf, 1);
*header = NO_COMPRESS_BYTE;
}
}
static void
stubv2_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)
{
if (buf->len <= 0)
return;
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;
}
}
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;
}
}
}
uint8_t *head = BPTR (buf);
/* no compression or packet to short*/
if (head[0] != COMP_ALGV2_INDICATOR_BYTE)
return;
static void
stubv2_compress(struct buffer *buf, struct buffer work,
struct compress_context *compctx,
const struct frame *frame)
{
if (buf->len <= 0)
{
return;
}
/* compression header (0x50) is present */
buf_advance(buf, 1);
compv2_escape_data_ifneeded(buf);
}
/* Packet buffer too short (only 1 byte) */
if (buf->len <= 0)
return;
static void
stubv2_decompress(struct buffer *buf, struct buffer work,
struct compress_context *compctx,
const struct frame *frame)
{
if (buf->len <= 0)
{
return;
}
head = BPTR (buf);
buf_advance(buf, 1);
uint8_t *head = BPTR(buf);
if (head[0] != COMP_ALGV2_UNCOMPRESSED_BYTE) {
dmsg (D_COMP_ERRORS, "Bad compression stubv2 decompression header byte: %d", *head);
buf->len = 0;
return;
}
/* no compression or packet to short*/
if (head[0] != COMP_ALGV2_INDICATOR_BYTE)
{
return;
}
/* compression header (0x50) is present */
buf_advance(buf, 1);
/* Packet buffer too short (only 1 byte) */
if (buf->len <= 0)
{
return;
}
head = BPTR(buf);
buf_advance(buf, 1);
if (head[0] != COMP_ALGV2_UNCOMPRESSED_BYTE)
{
dmsg(D_COMP_ERRORS, "Bad compression stubv2 decompression header byte: %d", *head);
buf->len = 0;
return;
}
}
const struct compress_alg compv2_stub_alg = {
"stubv2",
stub_compress_init,
stub_compress_uninit,
stubv2_compress,
stubv2_decompress
"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 */

View file

@ -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 */

View file

@ -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 */

View file

@ -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;

View file

@ -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;
}
memset (input, 0, capacity);
if (read (std_out, input, capacity-1) != 0)
if ((std_out = openvpn_popen(&argv, NULL)) < 0)
{
chomp (input);
ret = true;
return false;
}
close (std_out);
memset(input, 0, capacity);
if (read(std_out, input, capacity-1) != 0)
{
chomp(input);
ret = true;
}
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;

File diff suppressed because it is too large Load diff

View file

@ -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. */
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
#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;
}

View file

@ -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_ */

File diff suppressed because it is too large Load diff

View file

@ -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_ */

File diff suppressed because it is too large Load diff

View file

@ -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_ */

View file

@ -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
#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" },
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);
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;
}
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);
/* 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 */

View file

@ -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;
}
uint16_t word16;
uint32_t sum = 0;
int i;
/* 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;
}
/* 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;
}
/* the protocol number and the length of the UDP packet */
sum += (uint16_t) OPENVPN_IPPROTO_UDP + (uint16_t) len_udp;
/* 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;
}
/* 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);
/* 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));
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)
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);
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));
/* 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);
}
/* 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 ret;
}
}
}
return 0;
return 0;
}

View file

@ -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 */

View file

@ -176,4 +176,4 @@
/*#define D_THREAD_DEBUG LOGLEV(4, 70, M_DEBUG)*/ /* show pthread debug information */
#endif
#endif /* ifndef ERRLEVEL_H */

File diff suppressed because it is too large Load diff

View file

@ -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
#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, ...) 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
# 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, ...)
#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
#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_machine_readable_output (bool parsable);
void set_suppress_timestamps(bool suppressed);
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 x_check_status (int status,
const char *description,
struct link_socket *sock,
struct tuntap *tt);
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);
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 */

File diff suppressed because it is too large Load diff

View file

@ -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);
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);
/*
* 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 */

View file

@ -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");
}
}

View file

@ -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() */

View file

@ -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);
}
}

File diff suppressed because it is too large Load diff

View file

@ -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 */

View file

@ -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);
/* 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);
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);
/* 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);
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");
/* 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)));
}
/* 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");
/* 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);
/* 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;
/* 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");
}
/* 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;
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;
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;
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;
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;
}
/* 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));
/* 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);
/* 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 */
ASSERT(!last || !f->outgoing.len); /* outgoing buffer length should be zero after last fragment sent */
return true;
return true;
}
else
{
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 */

View file

@ -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 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 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 */

View file

@ -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;
initialized = true;
if (up_down_level)
up = false;
else
up = true;
if (up_down_level)
{
up = false;
}
else
{
up = true;
}
next = now;
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);
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 */
}
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 */

View file

@ -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 */

View file

@ -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);
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));
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);
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;
* 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");
}
/*
*
* 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;
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 */
/* 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;
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;
}
push_option( o, "tun-ipv6", M_USAGE );
}
/*
* 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 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)
{
if (o->client)
msg (M_USAGE, "--server-bridge and --client cannot be used together");
int netbits = -2;
bool status = false;
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->client)
{
msg(M_USAGE, "--server and --client cannot be used together");
}
if (o->shared_secret_file)
msg (M_USAGE, "--server-bridge and --secret cannot be used together (you must use SSL/TLS keys)");
if (o->server_bridge_defined || o->server_bridge_proxy_dhcp)
{
msg(M_USAGE, "--server and --server-bridge cannot be used together");
}
if (dev != DEV_TYPE_TAP)
msg (M_USAGE, "--server-bridge directive only makes sense with --dev tap");
if (o->shared_secret_file)
{
msg(M_USAGE, "--server and --secret cannot be used together (you must use SSL/TLS keys)");
}
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);
}
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");
}
o->mode = MODE_SERVER;
o->tls_server = true;
if (!(dev == DEV_TYPE_TAP || dev == DEV_TYPE_TUN))
{
msg(M_USAGE, "--server directive only makes sense with --dev tun or --dev tap");
}
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);
}
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;
}
}
else
/*
* 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);
}
}
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.");
/*
* 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;
}
/*
* 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
}

View file

@ -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

View file

@ -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 */

View file

@ -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 */

File diff suppressed because it is too large Load diff

View file

@ -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);
void management_show_net_callback (void *arg, const int msglevel);
bool open_management(struct context *c);
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 */

View file

@ -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 */

View file

@ -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;
}

View file

@ -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;
}
static inline void
event_timeout_reset (struct event_timeout* et)
{
if (et->defined)
et->last = now;
}
static inline void
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->defined = true;
et->n = (n >= 0) ? n : 0;
et->last = local_now;
}
static inline void
event_timeout_reset(struct event_timeout *et)
{
if (et->defined)
{
et->last = now;
}
}
static inline void
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;
}
}
/*
* 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 */

File diff suppressed because it is too large Load diff

View file

@ -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];
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;
he = hash_lookup_fast(hash, bucket, key, hv);
if (he)
{
ret = he->value;
}
return ret;
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;
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;
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;
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;
hv = hash_value(hash, key);
bucket = &hash->buckets[hv & hash->mask];
ret = hash_remove_fast(hash, bucket, key, hv);
return ret;
}
#endif /* P2MP_SERVER */

View file

@ -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;
}

View file

@ -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);

View file

@ -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;
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))
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 (buf, 1);
*header = NO_COMPRESS_BYTE;
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;
}
}
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;
ASSERT (buf_init (&work, FRAME_HEADROOM (frame)));
c = *BPTR (buf);
ASSERT (buf_advance (buf, 1));
if (c == LZO_COMPRESS_BYTE) /* packet was compressed */
if (buf->len <= 0)
{
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;
return;
}
else if (c == NO_COMPRESS_BYTE) /* packet was not compressed */
ASSERT(buf_init(&work, FRAME_HEADROOM(frame)));
c = *BPTR(buf);
ASSERT(buf_advance(buf, 1));
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;
}
else
else if (c == NO_COMPRESS_BYTE) /* packet was not compressed */
{
dmsg (D_COMP_ERRORS, "Bad LZO decompression header byte: %d", c);
buf->len = 0;
}
else
{
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 */

View file

@ -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 */

File diff suppressed because it is too large Load diff

View file

@ -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_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_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_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_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);
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);
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 */

View file

@ -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 */

View file

@ -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 */

View file

@ -49,7 +49,7 @@
#define VALGRIND_MAKE_READABLE(addr, len)
#else
#else /* ifdef USE_VALGRIND */
#define VALGRIND_MAKE_READABLE(addr, len)

File diff suppressed because it is too large Load diff

View file

@ -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);
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);
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_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_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_print (int msglevel, const struct env_set *es);
void env_set_destroy(struct env_set *es);
void env_set_inherit (struct env_set *es, const struct env_set *src);
bool env_set_del(struct env_set *es, const char *str);
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_add(struct env_set *es, const char *str);
const char *env_set_get(const struct env_set *es, const char *name);
void env_set_print(int msglevel, const struct env_set *es);
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_extended_arg_array (char **p, 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);
/* 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 */

View file

@ -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);
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;
/* multicast packet? */
if (mroute_is_mcast(arp->ip_dest))
{
ret |= MROUTE_EXTRACT_MCAST;
}
ret |= MROUTE_EXTRACT_SUCCEEDED;
}
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);
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);
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;
/* multicast packet? */
if (mroute_is_mcast(ip->daddr))
{
ret |= MROUTE_EXTRACT_MCAST;
}
/* IGMP message? */
if (ip->protocol == OPENVPN_IPPROTO_IGMP)
ret |= MROUTE_EXTRACT_IGMP;
/* 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);
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;
default:
msg (M_WARN, "IP packet with unknown IP version=%d seen",
OPENVPN_IPH_GET_VER (*BPTR(buf)));
}
ret |= MROUTE_EXTRACT_SUCCEEDED;
}
break;
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));
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;
/* 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;
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);
}
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 */

View file

@ -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);
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_helper_add_iroute46 (struct mroute_helper *mh, int netbits);
void mroute_helper_del_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);
/*
* 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_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_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 */

View file

@ -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;
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))
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;
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 ) )
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;
int hlen, olen, optlen;
uint8_t *opt;
uint16_t mssval;
int accumulate;
struct openvpn_tcphdr *tc;
ASSERT (BLEN (buf) >= (int) sizeof (struct openvpn_tcphdr));
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);
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);
}
}
/* 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);
}
}
}
}
}
}

View file

@ -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

View file

@ -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;
/* 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)
if (mmap_stats) /* already called? */
{
msg (M_ERR, "mstats_open: cannot open: %s", fn);
return;
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))
/* verify that filename is not too long */
if (strlen(fn) >= sizeof(mmap_fn))
{
msg (M_ERR, "mstats_open: write error: %s", fn);
close(fd);
return;
msg(M_FATAL, "mstats_open: filename too long");
}
/* mmap the file */
data = mmap(NULL, sizeof(struct mmap_stats), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if (data == MAP_FAILED)
/* 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: write error: %s", fn);
close(fd);
return;
msg(M_ERR, "mstats_open: cannot open: %s", fn);
return;
}
/* close the fd (mmap now controls the file) */
if (close(fd))
/* 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: close error: %s", fn);
msg(M_ERR, "mstats_open: write error: %s", fn);
close(fd);
return;
}
/* save filename so we can delete it later */
strcpy(mmap_fn, fn);
/* 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;
}
/* save a global pointer to memory-mapped region */
mmap_stats = (struct mmap_stats *)data;
/* close the fd (mmap now controls the file) */
if (close(fd))
{
msg(M_ERR, "mstats_open: close error: %s", fn);
}
msg (M_INFO, "memstats data will be written to %s", 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;
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) */

View file

@ -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;
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;
#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) */

File diff suppressed because it is too large Load diff

View file

@ -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 */

View file

@ -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_UPPER_BOUND) || mtu < frame->link_mtu_dynamic)
if (flags & SET_MTU_TUN)
{
frame->link_mtu_dynamic = constrain_int (
mtu,
EXPANDED_SIZE_MIN (frame),
EXPANDED_SIZE (frame));
mtu += TUN_LINK_DELTA(frame);
}
dmsg (D_MTU_DEBUG, "MTU DYNAMIC mtu=%d, flags=%u, %d -> %d",
orig_mtu,
flags,
orig_link_mtu_dynamic,
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));
}
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, " ]");
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);
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);
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;
*mtu = 0;
while (true)
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 */
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;
res = recvmsg(fd, &msg, MSG_ERRQUEUE);
if (res < 0)
{
goto exit;
}
e = NULL;
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;
}
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;
}
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 */

View file

@ -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);
int translate_mtu_discover_type_name (const char *name);
void set_mtu_discover_type(int sd, int mtu_type, sa_family_t proto_af);
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 */

Some files were not shown because too many files have changed in this diff Show more