Attention is currently required from: cron2, flichtenheld, mrbff, plaisthos.
Hello cron2, flichtenheld, plaisthos, I'd like you to reexamine a change. Please visit http://gerrit.openvpn.net/c/openvpn/+/869?usp=email to look at the new patch set (#6). The following approvals got outdated and were removed: Code-Review-1 by cron2 Change subject: PUSH_UPDATE message sender: enabling the server to send PUSH_UPDATE control messages ...................................................................... PUSH_UPDATE message sender: enabling the server to send PUSH_UPDATE control messages Using the management interface you can now target one or more clients (via broadcast, via cid, via common name, via address) and send a PUSH_UPDATE control message to update some options. Change-Id: Ie82bcc7a8e583de9156b185d71d1a323ed8df3fc Signed-off-by: Marco Baffo <ma...@mandelbit.com> --- M CMakeLists.txt M doc/management-notes.txt M src/openvpn/manage.c M src/openvpn/manage.h M src/openvpn/multi.c M src/openvpn/multi.h M src/openvpn/push.h M src/openvpn/push_util.c M tests/unit_tests/openvpn/Makefile.am M tests/unit_tests/openvpn/test_push_update_msg.c 10 files changed, 796 insertions(+), 6 deletions(-) git pull ssh://gerrit.openvpn.net:29418/openvpn refs/changes/69/869/6 diff --git a/CMakeLists.txt b/CMakeLists.txt index f597a89..185a312 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -832,6 +832,7 @@ src/openvpn/push_util.c src/openvpn/options_util.c src/openvpn/otime.c + src/openvpn/list.c ) if (TARGET test_argv) diff --git a/doc/management-notes.txt b/doc/management-notes.txt index f1d2930..58393da 100644 --- a/doc/management-notes.txt +++ b/doc/management-notes.txt @@ -1028,6 +1028,51 @@ stored outside of the filesystem (e.g. in Mac OS X Keychain) with OpenVPN via the management interface. +COMMAND -- push-update-broad (OpenVPN 2.7 or higher) +---------------------------------------------------- +Send a message to every connected client to update options at runtime. +The updatable options are: "block-ipv6", "block-outside-dns", "dhcp-option", +"dns", "ifconfig", "ifconfig-ipv6", "redirect-gateway", "redirect-private", +"route", "route-gateway", "route-ipv6", "route-metric", "topology", +"tun-mtu", "keepalive". When a valid option is pushed, the receiving client will +delete every previous value and set new value, so the update of the option will +not be incremental even when theoretically possible (ex. with "redirect-gateway"). +The '-' symbol in front of an option means the option should be removed. +When an option is used with '-', it cannot take any parameter. +The '?' symbol in front of an option means the option's update is optional +so if the client do not support it, that option will just be ignored without +making fail the entire command. The '-' and '?' symbols can be used together. + +Option Format Ex. + `-?option`, `-option`, `?option parameters` are valid formats, + `?-option` is not a valid format. + +Example + push-update-broad "route 10.10.10.1 255.255.255.255, -dns, ?tun-mtu 1400" + +COMMAND -- push-update-cid (OpenVPN 2.7 or higher) +---------------------------------------------------- +Same as push-update-broad but you must target a single client using client id. + +Example + push-update-cid 42 "route 10.10.10.1 255.255.255.255, -dns, ?tun-mtu 1400" + +COMMAND -- push-update-cn (OpenVPN 2.7 or higher) +---------------------------------------------------- +Same as push-update-broad but target the clients based on the provided common name +(usually just one client per common name is permitted except if "duplicate-cn" option is used). + +Example + push-update-cid Client0 "route 10.10.10.1 255.255.255.255, -dns, ?tun-mtu 1400" + +COMMAND -- push-update-addr (OpenVPN 2.7 or higher) +---------------------------------------------------- +Same as push-update-broad but target only the client(s) connecting from the +provided address (real address). Support both IPv4 and IPv6. + +Example + push-update-addr 9.9.9.9 1234 "route 10.10.10.1 255.255.255.255, -dns, ?tun-mtu 1400" + OUTPUT FORMAT ------------- diff --git a/src/openvpn/manage.c b/src/openvpn/manage.c index 0e73942..43d2097 100644 --- a/src/openvpn/manage.c +++ b/src/openvpn/manage.c @@ -24,7 +24,6 @@ #ifdef HAVE_CONFIG_H #include "config.h" #endif - #include "syshead.h" #ifdef ENABLE_MANAGEMENT @@ -42,6 +41,7 @@ #include "manage.h" #include "openvpn.h" #include "dco.h" +#include "push.h" #include "memdbg.h" @@ -124,6 +124,11 @@ msg(M_CLIENT, "username type u : Enter username u for a queried OpenVPN username."); msg(M_CLIENT, "verb [n] : Set log verbosity level to n, or show if n is absent."); msg(M_CLIENT, "version [n] : Set client's version to n or show current version of daemon."); + msg(M_CLIENT, "push-update-broad options : Broadcast a message to update the specified options."); + msg(M_CLIENT, " Ex. push-update-broad \"route something, -dns\""); + msg(M_CLIENT, "push-update-cid CID options : Send an update message to the client identified by CID."); + msg(M_CLIENT, "push-update-cn CN options : Send an update message to the client(s) with the specified Common Name."); + msg(M_CLIENT, "push-update-addr ip port options : Send an update message to the client(s) connecting from the provided address."); msg(M_CLIENT, "END"); } @@ -1334,6 +1339,154 @@ } static void +man_push_update(struct management *man, const char **p, const push_update_type type) +{ + if (type == UPT_BROADCAST) + { + if (!man->persist.callback.push_update_broadcast) + { + man_command_unsupported("push-update-broad"); + return; + } + + const bool status = (*man->persist.callback.push_update_broadcast)(man->persist.callback.arg, p[1]); + + if (status) + { + msg(M_CLIENT, "SUCCESS: push-update-broad command succeeded"); + } + else + { + msg(M_CLIENT, "ERROR: push-update-broad command failed"); + } + } + else if (type == UPT_BY_CID) + { + if (!man->persist.callback.push_update_by_cid) + { + man_command_unsupported("push-update-cid"); + return; + } + + unsigned long cid = 0; + + if (!parse_cid(p[1], &cid)) + { + msg(M_CLIENT, "ERROR: push-update-cid fail during cid parsing"); + return; + } + + const bool status = (*man->persist.callback.push_update_by_cid)(man->persist.callback.arg, cid, p[2]); + + if (status) + { + msg(M_CLIENT, "SUCCESS: push-update-cid command succeeded"); + } + else + { + msg(M_CLIENT, "ERROR: push-update-cid command failed"); + } + } + else if (type == UPT_BY_CN) + { + if (!man->persist.callback.push_update_by_cn) + { + man_command_unsupported("push-update-cn"); + return; + } + + const bool status = (*man->persist.callback.push_update_by_cn)(man->persist.callback.arg, p[1], p[2]); + + if (status) + { + msg(M_CLIENT, "SUCCESS: push-update-cn command succeeded"); + } + else + { + msg(M_CLIENT, "ERROR: push-update-cn command failed"); + } + } + else if (type == UPT_BY_ADDR) + { + if (!man->persist.callback.push_update_by_addr) + { + man_command_unsupported("push-update-addr"); + return; + } + + const char *ip_str = p[1]; + const char *port_str = p[2]; + const char *options = p[3]; + + if (!strlen(ip_str) || !strlen(port_str)) + { + msg(M_CLIENT, "ERROR: push-update-addr parse"); + return; + } + + struct addrinfo *res = NULL; + int port = atoi(port_str); + + if (port < 1 || port > 65535) + { + msg(M_CLIENT, "ERROR: port number is out of range: %s", port_str); + return; + } + + int status = openvpn_getaddrinfo(GETADDR_MSG_VIRT_OUT, ip_str, port_str, 0, NULL, AF_UNSPEC, &res); + + if (status != 0 || !res) + { + msg(M_CLIENT, "ERROR: error resolving address: %s (%s)", ip_str, gai_strerror(status)); + return; + } + + struct addrinfo *rp; + bool found_client = false; + + /* Iterate through resolved addresses */ + for (rp = res; rp != NULL; rp = rp->ai_next) + { + struct openvpn_sockaddr saddr; + struct mroute_addr maddr; + + CLEAR(saddr); + switch (rp->ai_family) + { + case AF_INET: + saddr.addr.in4 = *((struct sockaddr_in *)rp->ai_addr); + break; + + case AF_INET6: + saddr.addr.in6 = *((struct sockaddr_in6 *)rp->ai_addr); + break; + + default: + continue; + } + + if (!mroute_extract_openvpn_sockaddr(&maddr, &saddr, true)) + { + continue; + } + + if ((*man->persist.callback.push_update_by_addr)(man->persist.callback.arg, &maddr, options)) + { + msg(M_CLIENT, "SUCCESS: push-update sent to %s:%d", ip_str, port); + found_client = true; + break; + } + } + + if (!found_client) + { + msg(M_CLIENT, "ERROR: no client found at address %s:%d", ip_str, port); + } + freeaddrinfo(res); + } +} + +static void man_dispatch_command(struct management *man, struct status_output *so, const char **p, const int nparms) { struct gc_arena gc = gc_new(); @@ -1655,6 +1808,34 @@ man_remote(man, p); } } + else if (streq(p[0], "push-update-broad")) + { + if (man_need(man, p, 1, 0)) + { + man_push_update(man, p, UPT_BROADCAST); + } + } + else if (streq(p[0], "push-update-cid")) + { + if (man_need(man, p, 2, 0)) + { + man_push_update(man, p, UPT_BY_CID); + } + } + else if (streq(p[0], "push-update-cn")) + { + if (man_need(man, p, 2, 0)) + { + man_push_update(man, p, UPT_BY_CN); + } + } + else if (streq(p[0], "push-update-addr")) + { + if (man_need(man, p, 3, 0)) + { + man_push_update(man, p, UPT_BY_ADDR); + } + } #if 1 else if (streq(p[0], "test")) { diff --git a/src/openvpn/manage.h b/src/openvpn/manage.h index 02ceb82..aab0760 100644 --- a/src/openvpn/manage.h +++ b/src/openvpn/manage.h @@ -44,7 +44,6 @@ #define MF_EXTERNAL_KEY_PSSPAD (1<<16) #define MF_EXTERNAL_KEY_DIGEST (1<<17) - #ifdef ENABLE_MANAGEMENT #include "misc.h" @@ -205,6 +204,10 @@ #endif unsigned int (*remote_entry_count)(void *arg); bool (*remote_entry_get)(void *arg, unsigned int index, char **remote); + bool (*push_update_broadcast)(void *arg, const char *options); + bool (*push_update_by_cid)(void *arg, unsigned long cid, const char *options); + bool (*push_update_by_cn)(void *arg, const char *cn, const char *options); + bool (*push_update_by_addr)(void *arg, const struct mroute_addr *maddr, const char *options); }; /* diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index ec04369..2a8b725 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -4062,7 +4062,7 @@ } } -static struct multi_instance * +struct multi_instance * lookup_by_cid(struct multi_context *m, const unsigned long cid) { if (m) @@ -4210,6 +4210,10 @@ cb.client_auth = management_client_auth; cb.client_pending_auth = management_client_pending_auth; cb.get_peer_info = management_get_peer_info; + cb.push_update_broadcast = management_callback_send_push_update_broadcast; + cb.push_update_by_cid = management_callback_send_push_update_by_cid; + cb.push_update_by_cn = management_callback_send_push_update_by_cn; + cb.push_update_by_addr = management_callback_send_push_update_by_addr; management_set_callback(management, &cb); } #endif /* ifdef ENABLE_MANAGEMENT */ diff --git a/src/openvpn/multi.h b/src/openvpn/multi.h index e14ad60..b78bfc9 100644 --- a/src/openvpn/multi.h +++ b/src/openvpn/multi.h @@ -710,5 +710,10 @@ */ void multi_assign_peer_id(struct multi_context *m, struct multi_instance *mi); +#ifdef ENABLE_MANAGEMENT +struct multi_instance * +lookup_by_cid(struct multi_context *m, const unsigned long cid); + +#endif #endif /* MULTI_H */ diff --git a/src/openvpn/push.h b/src/openvpn/push.h index 4643c36..6127012 100644 --- a/src/openvpn/push.h +++ b/src/openvpn/push.h @@ -42,6 +42,16 @@ #define PUSH_OPT_TO_REMOVE (1<<0) #define PUSH_OPT_OPTIONAL (1<<1) +/* Push-update message sender modes */ +typedef enum { + UPT_BROADCAST = 0, + UPT_BY_ADDR = 1, + UPT_BY_CN = 2, +#ifdef ENABLE_MANAGEMENT + UPT_BY_CID = 3 +#endif +} push_update_type; + int process_incoming_push_request(struct context *c); /** @@ -134,4 +144,33 @@ void receive_auth_pending(struct context *c, const struct buffer *buffer); +/** + * @brief A function to send a PUSH_UPDATE control message from server to client(s). + * + * @param m the multi_context, contains all the clients connected to this server. + * @param target the target to which to send the message. It should be: + * `NULL` if `type == UPT_BROADCAST`, + * a `mroute_addr *` if `type == UPT_BY_ADDR`, + * a `char *` if `type == UPT_BY_CN`, + * an `unsigned long *` if `type == UPT_BY_CID`. + * @param msg a string containing the options to send. + * @param type the way to address the message (broadcast, by cid, by cn, by address). + * @param push_bundle_size the maximum size of a bundle of pushed option. Just use PUSH_BUNDLE_SIZE macro. + * @return the number of clients to which the message was sent. + */ +int +send_push_update(struct multi_context *m, const void *target, const char *msg, const push_update_type type, const int push_bundle_size); + +#ifdef ENABLE_MANAGEMENT + +bool management_callback_send_push_update_broadcast(void *arg, const char *options); + +bool management_callback_send_push_update_by_cid(void *arg, unsigned long cid, const char *options); + +bool management_callback_send_push_update_by_cn(void *arg, const char *cn, const char *options); + +bool management_callback_send_push_update_by_addr(void *arg, const struct mroute_addr *maddr, const char *options); + +#endif /* ifdef ENABLE_MANAGEMENT*/ + #endif /* ifndef PUSH_H */ diff --git a/src/openvpn/push_util.c b/src/openvpn/push_util.c index b4d1e8b..d79bf98 100644 --- a/src/openvpn/push_util.c +++ b/src/openvpn/push_util.c @@ -3,6 +3,8 @@ #endif #include "push.h" +#include "multi.h" +#include "ssl_verify.h" int process_incoming_push_update(struct context *c, @@ -42,3 +44,257 @@ return ret; } + +/** + * Return index of last `,` or `0` if it didn't find any. + * If there is a comma at index `0` it's an error anyway + */ +static int +find_first_comma_of_next_bundle(const char *str, int ix) +{ + while (ix > 0) + { + if (str[ix] == ',') + { + return ix; + } + ix--; + } + return 0; +} + +/* Allocate memory and asseble the final message */ +static char * +forge_msg(const char *src, const char *continuation, struct gc_arena *gc) +{ + int src_len = strlen(src); + int con_len = continuation ? strlen(continuation) : 0; + char *ret = gc_malloc((src_len + sizeof(push_update_cmd) + con_len + 2) * sizeof(char), true, gc); + int i = sizeof(push_update_cmd) -1; + + strcpy(ret, push_update_cmd); + ret[i++] = ','; + strcpy(&ret[i], src); + if (continuation) + { + i += src_len; + strcpy(&ret[i], continuation); + } + return ret; +} + +static char * +gc_strdup(const char *src, struct gc_arena *gc) +{ + char *ret = gc_malloc((strlen(src) + 1) * sizeof(char), true, gc); + + strcpy(ret, src); + return ret; +} + +/* It split the messagge (if necessay) and fill msgs with the message chunks. + * Return `false` on failure an `true` on success. + */ +static bool +message_splitter(char *str, char **msgs, struct gc_arena *gc, const int safe_cap) +{ + if (!str || !*str) + { + return false; + } + + int i = 0; + int im = 0; + + while (*str) + { + /* + ',' - '/0' */ + if (strlen(str) > safe_cap) + { + int ci = find_first_comma_of_next_bundle(str, safe_cap); + if (!ci) + { + /* if no commas were found go to fail, do not send any message */ + return false; + } + str[ci] = '\0'; + /* copy from i to (ci -1) */ + msgs[im] = forge_msg(str, ",push-continuation 2", gc); + i = ci + 1; + } + else + { + if (im) + { + msgs[im] = forge_msg(str, ",push-continuation 1", gc); + } + else + { + msgs[im] = forge_msg(str, NULL, gc); + } + i = strlen(str); + } + str = &str[i]; + im++; + } + return true; +} + +/* It actually send the already divided messagge to one single client */ +static bool +send_single_push_update(struct context *c, char **msgs) +{ + if (!msgs[0] || !*msgs[0]) + { + return false; + } + int i = 0; + while (msgs[i] && *msgs[i]) + { + if (!send_control_channel_string(c, msgs[i], D_PUSH)) + { + return false; + } + i++; + } + return true; +} + +int +send_push_update(struct multi_context *m, const void *target, const char *msg, const push_update_type type, const int push_bundle_size) +{ + if (!msg || !*msg || !m + || (!target && type != UPT_BROADCAST)) + { + return -EINVAL; + } + + struct gc_arena gc = gc_new(); + /* extra space for possible trailing ifconfig and push-continuation */ + const int extra = 84 + sizeof(push_update_cmd); + /* push_bundle_size is the maximum size of a message, so if the message + * we want to send exceeds that size we have to split it into smaller messages */ + const int safe_cap = push_bundle_size - extra; + int msgs_num = (strlen(msg) / safe_cap) + ((strlen(msg) % safe_cap) != 0); + char **msgs = gc_malloc(sizeof(char *) * (msgs_num + 1), true, &gc); + + msgs[msgs_num] = NULL; + if (!message_splitter(gc_strdup(msg, &gc), msgs, &gc, safe_cap)) + { + gc_free(&gc); + return -EINVAL; + } + +#ifdef ENABLE_MANAGEMENT + if (type == UPT_BY_CID) + { + struct multi_instance *mi = lookup_by_cid(m, *((unsigned long *)target)); + + if (!mi) + { + return -ENOENT; + } + if (!mi->halt + && send_single_push_update(&mi->context, msgs)) + { + gc_free(&gc); + return 1; + } + else + { + gc_free(&gc); + return 0; + } + } +#endif /* ifdef ENABLE_MANAGEMENT */ + + int count = 0; + struct hash_iterator hi; + const struct hash_element *he; + + hash_iterator_init(m->iter, &hi); + while ((he = hash_iterator_next(&hi))) + { + struct multi_instance *curr_mi = he->value; + + if (curr_mi->halt) + { + continue; + } + if (type == UPT_BY_ADDR && !mroute_addr_equal(target, &curr_mi->real)) + { + continue; + } + else if (type == UPT_BY_CN) + { + const char *curr_cn = tls_common_name(curr_mi->context.c2.tls_multi, false); + if (strcmp(curr_cn, target)) + { + continue; + } + } + /* Either we found a matching client or type is UPT_BROADCAST so we update every client */ + if (!send_single_push_update(&curr_mi->context, msgs)) + { + msg(M_CLIENT, "ERROR: Peer ID: %u has not been updated", + curr_mi->context.c2.tls_multi ? curr_mi->context.c2.tls_multi->peer_id : UINT32_MAX); + continue; + } + count++; + } + + hash_iterator_free(&hi); + gc_free(&gc); + return count; +} + +#ifdef ENABLE_MANAGEMENT +#define RETURN_UPDATE_STATUS(n_sent) \ + do { \ + if ((n_sent) > 0) { \ + msg(M_CLIENT, "SUCCESS: %d client(s) updated", (n_sent)); \ + return true; \ + } else { \ + msg(M_CLIENT, "ERROR: no client updated"); \ + return false; \ + } \ + } while (0) + + +bool +management_callback_send_push_update_broadcast(void *arg, const char *options) +{ + int n_sent = send_push_update(arg, NULL, options, UPT_BROADCAST, PUSH_BUNDLE_SIZE); + + RETURN_UPDATE_STATUS(n_sent); +} + +bool +management_callback_send_push_update_by_cid(void *arg, unsigned long cid, const char *options) +{ + int ret = send_push_update(arg, &cid, options, UPT_BY_CID, PUSH_BUNDLE_SIZE); + + if (ret == -ENOENT) + { + msg(M_CLIENT, "ERROR: no client found with CID: %lu", cid); + } + + return (ret > 0); +} + +bool +management_callback_send_push_update_by_cn(void *arg, const char *cn, const char *options) +{ + int n_sent = send_push_update(arg, cn, options, UPT_BY_CN, PUSH_BUNDLE_SIZE); + + RETURN_UPDATE_STATUS(n_sent); +} + +bool +management_callback_send_push_update_by_addr(void *arg, const struct mroute_addr *maddr, const char *options) +{ + int n_sent = send_push_update(arg, maddr, options, UPT_BY_ADDR, PUSH_BUNDLE_SIZE); + + RETURN_UPDATE_STATUS(n_sent); +} +#endif /* ifdef ENABLE_MANAGEMENT */ diff --git a/tests/unit_tests/openvpn/Makefile.am b/tests/unit_tests/openvpn/Makefile.am index 6fb7843..ef9c359 100644 --- a/tests/unit_tests/openvpn/Makefile.am +++ b/tests/unit_tests/openvpn/Makefile.am @@ -331,4 +331,5 @@ $(top_srcdir)/src/openvpn/platform.c \ $(top_srcdir)/src/openvpn/push_util.c \ $(top_srcdir)/src/openvpn/options_util.c \ - $(top_srcdir)/src/openvpn/otime.c \ No newline at end of file + $(top_srcdir)/src/openvpn/otime.c \ + $(top_srcdir)/src/openvpn/list.c \ No newline at end of file diff --git a/tests/unit_tests/openvpn/test_push_update_msg.c b/tests/unit_tests/openvpn/test_push_update_msg.c index d0876bc..549520b 100644 --- a/tests/unit_tests/openvpn/test_push_update_msg.c +++ b/tests/unit_tests/openvpn/test_push_update_msg.c @@ -8,6 +8,7 @@ #include <cmocka.h> #include "push.h" #include "options_util.h" +#include "multi.h" /* mocks */ @@ -94,6 +95,49 @@ } } +const char * +tls_common_name(const struct tls_multi *multi, const bool null) +{ + return NULL; +} + +#ifndef ENABLE_MANAGEMENT +bool +send_control_channel_string(struct context *c, const char *str, int msglevel) +{ + return true; +} +#else /* ifndef ENABLE_MANAGEMENT */ +char **res; +int i; + +bool +send_control_channel_string(struct context *c, const char *str, int msglevel) +{ + if (res && res[i] && strcmp(res[i], str)) + { + printf("\n\nexpected: %s\n\n actual: %s\n\n", res[i], str); + return false; + } + i++; + return true; +} + +struct multi_instance * +lookup_by_cid(struct multi_context *m, const unsigned long cid) +{ + return *(m->instances); +} + +bool +mroute_extract_openvpn_sockaddr(struct mroute_addr *addr, + const struct openvpn_sockaddr *osaddr, + bool use_port) +{ + return true; +} +#endif /* ifndef ENABLE_MANAGEMENT */ + /* tests */ static void @@ -124,7 +168,6 @@ free_buf(&buf); } - static void test_incoming_push_message_error2(void **state) { @@ -209,6 +252,205 @@ free_buf(&buf); } +#ifdef ENABLE_MANAGEMENT +char *r0[] = { + "PUSH_UPDATE,redirect-gateway local,route 192.168.1.0 255.255.255.0" +}; +char *r1[] = { + "PUSH_UPDATE,-dhcp-option,blablalalalalalalalalalalalalf, lalalalalalalalalalalalalalaf,push-continuation 2", + "PUSH_UPDATE, akakakakakakakakakakakaf, dhcp-option DNS 8.8.8.8,redirect-gateway local,push-continuation 2", + "PUSH_UPDATE,route 192.168.1.0 255.255.255.0,push-continuation 1" +}; +char *r3[] = { + "PUSH_UPDATE,,," +}; +char *r4[] = { + "PUSH_UPDATE,-dhcp-option, blablalalalalalalalalalalalalf, lalalalalalalalalalalalalalaf,push-continuation 2", + "PUSH_UPDATE, akakakakakakakakakakakaf,dhcp-option DNS 8.8.8.8, redirect-gateway local,push-continuation 2", + "PUSH_UPDATE, route 192.168.1.0 255.255.255.0,,push-continuation 1" +}; +char *r5[] = { + "PUSH_UPDATE,,-dhcp-option, blablalalalalalalalalalalalalf, lalalalalalalalalalalalalalaf,push-continuation 2", + "PUSH_UPDATE, akakakakakakakakakakakaf,dhcp-option DNS 8.8.8.8, redirect-gateway local,push-continuation 2", + "PUSH_UPDATE, route 192.168.1.0 255.255.255.0,push-continuation 1" +}; +char *r6[] = { + "PUSH_UPDATE,-dhcp-option,blablalalalalalalalalalalalalf, lalalalalalalalalalalalalalaf,push-continuation 2", + "PUSH_UPDATE, akakakakakakakakakakakaf, dhcp-option DNS 8.8.8.8, redirect-gateway 10.10.10.10,,push-continuation 2", + "PUSH_UPDATE, route 192.168.1.0 255.255.255.0,,push-continuation 1" +}; +char *r7[] = { + "PUSH_UPDATE,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,push-continuation 2", + "PUSH_UPDATE,,,,,,,,,,,,,,,,,,,push-continuation 1" +}; +char *r8[] = { + "PUSH_UPDATE,-dhcp-option,blablalalalalalalalalalalalalf, lalalalalalalalalalalalalalaf,push-continuation 2", + "PUSH_UPDATE, akakakakakakakakakakakaf, dhcp-option DNS 8.8.8.8,redirect-gateway\n local,push-continuation 2", + "PUSH_UPDATE,route 192.168.1.0 255.255.255.0\n\n\n,push-continuation 1" +}; +char *r9[] = { + "PUSH_UPDATE,," +}; + + +const char *msg0 = "redirect-gateway local,route 192.168.1.0 255.255.255.0"; +const char *msg1 = "-dhcp-option,blablalalalalalalalalalalalalf, lalalalalalalalalalalalalalaf," + " akakakakakakakakakakakaf, dhcp-option DNS 8.8.8.8,redirect-gateway local,route 192.168.1.0 255.255.255.0"; +const char *msg2 = ""; +const char *msg3 = ",,"; +const char *msg4 = "-dhcp-option, blablalalalalalalalalalalalalf, lalalalalalalalalalalalalalaf," + " akakakakakakakakakakakaf,dhcp-option DNS 8.8.8.8, redirect-gateway local, route 192.168.1.0 255.255.255.0,"; +const char *msg5 = ",-dhcp-option, blablalalalalalalalalalalalalf, lalalalalalalalalalalalalalaf," + " akakakakakakakakakakakaf,dhcp-option DNS 8.8.8.8, redirect-gateway local, route 192.168.1.0 255.255.255.0"; +const char *msg6 = "-dhcp-option,blablalalalalalalalalalalalalf, lalalalalalalalalalalalalalaf, akakakakakakakakakakakaf," + " dhcp-option DNS 8.8.8.8, redirect-gateway 10.10.10.10,, route 192.168.1.0 255.255.255.0,"; +const char *msg7 = ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"; +const char *msg8 = "-dhcp-option,blablalalalalalalalalalalalalf, lalalalalalalalalalalalalalaf, akakakakakakakakakakakaf," + " dhcp-option DNS 8.8.8.8,redirect-gateway\n local,route 192.168.1.0 255.255.255.0\n\n\n"; +const char *msg9 = ","; +const char *msg10 = "VoilĂ ! In view, a humble vaudevillian veteran cast vicariously as both victim and villain by the vicissitudes" + " of Fate. This visage no mere veneer of vanity is a vestige of the vox populi now vacant vanished. However this" + " valorous visitation of a by-gone vexation stands vivified and has vowed to vanquish these venal and virulent" + " vermin vanguarding vice and vouchsafing the violently vicious and voracious violation of volition. The only" + " verdict is vengeance; a vendetta held as a votive not in vain for the value and veracity of such shall one" + " day vindicate the vigilant and the virtuous. Verily this vichyssoise of verbiage veers most verbose so let" + " me simply add that it is my very good honor to meet you and you may call me V."; + +#define PUSH_BUNDLE_SIZE_TEST 184 + +static void +test_send_push_msg0(void **state) +{ + i = 0; + res = r0; + struct multi_context *m = *state; + const unsigned long cid = 0; + assert_int_equal(send_push_update(m, &cid, msg0, UPT_BY_CID, PUSH_BUNDLE_SIZE_TEST), 1); +} +static void +test_send_push_msg1(void **state) +{ + i = 0; + res = r1; + struct multi_context *m = *state; + const unsigned long cid = 0; + assert_int_equal(send_push_update(m, &cid, msg1, UPT_BY_CID, PUSH_BUNDLE_SIZE_TEST), 1); +} + +static void +test_send_push_msg2(void **state) +{ + i = 0; + res = NULL; + struct multi_context *m = *state; + const unsigned long cid = 0; + assert_int_equal(send_push_update(m, &cid, msg2, UPT_BY_CID, PUSH_BUNDLE_SIZE_TEST), -EINVAL); +} + +static void +test_send_push_msg3(void **state) +{ + i = 0; + res = r3; + struct multi_context *m = *state; + const unsigned long cid = 0; + assert_int_equal(send_push_update(m, &cid, msg3, UPT_BY_CID, PUSH_BUNDLE_SIZE_TEST), 1); +} + +static void +test_send_push_msg4(void **state) +{ + i = 0; + res = r4; + struct multi_context *m = *state; + const unsigned long cid = 0; + assert_int_equal(send_push_update(m, &cid, msg4, UPT_BY_CID, PUSH_BUNDLE_SIZE_TEST), 1); +} + +static void +test_send_push_msg5(void **state) +{ + i = 0; + res = r5; + struct multi_context *m = *state; + const unsigned long cid = 0; + assert_int_equal(send_push_update(m, &cid, msg5, UPT_BY_CID, PUSH_BUNDLE_SIZE_TEST), 1); +} + +static void +test_send_push_msg6(void **state) +{ + i = 0; + res = r6; + struct multi_context *m = *state; + const unsigned long cid = 0; + assert_int_equal(send_push_update(m, &cid, msg6, UPT_BY_CID, PUSH_BUNDLE_SIZE_TEST), 1); +} + +static void +test_send_push_msg7(void **state) +{ + i = 0; + res = r7; + struct multi_context *m = *state; + const unsigned long cid = 0; + assert_int_equal(send_push_update(m, &cid, msg7, UPT_BY_CID, PUSH_BUNDLE_SIZE_TEST), 1); +} + +static void +test_send_push_msg8(void **state) +{ + i = 0; + res = r8; + struct multi_context *m = *state; + const unsigned long cid = 0; + assert_int_equal(send_push_update(m, &cid, msg8, UPT_BY_CID, PUSH_BUNDLE_SIZE_TEST), 1); +} + +static void +test_send_push_msg9(void **state) +{ + i = 0; + res = r9; + struct multi_context *m = *state; + const unsigned long cid = 0; + assert_int_equal(send_push_update(m, &cid, msg9, UPT_BY_CID, PUSH_BUNDLE_SIZE_TEST), 1); +} + +static void +test_send_push_msg10(void **state) +{ + i = 0; + res = NULL; + struct multi_context *m = *state; + const unsigned long cid = 0; + assert_int_equal(send_push_update(m, &cid, msg10, UPT_BY_CID, PUSH_BUNDLE_SIZE_TEST), -EINVAL); +} + +#undef PUSH_BUNDLE_SIZE_TEST + +static int +setup2(void **state) +{ + struct multi_context *m = calloc(1, sizeof(struct multi_context)); + m->instances = calloc(1, sizeof(struct multi_instance *)); + struct multi_instance *mi = calloc(1, sizeof(struct multi_instance)); + *(m->instances) = mi; + *state = m; + return 0; +} + +static int +teardown2(void **state) +{ + struct multi_context *m = *state; + free(*(m->instances)); + free(m->instances); + free(m); + return 0; +} +#endif /* ifdef ENABLE_MANAGEMENT */ + static int setup(void **state) { @@ -238,7 +480,20 @@ cmocka_unit_test_setup_teardown(test_incoming_push_message_1, setup, teardown), cmocka_unit_test_setup_teardown(test_incoming_push_message_bad_format, setup, teardown), cmocka_unit_test_setup_teardown(test_incoming_push_message_mix, setup, teardown), - cmocka_unit_test_setup_teardown(test_incoming_push_message_mix2, setup, teardown) + cmocka_unit_test_setup_teardown(test_incoming_push_message_mix2, setup, teardown), +#ifdef ENABLE_MANAGEMENT + cmocka_unit_test_setup_teardown(test_send_push_msg0, setup2, teardown2), + cmocka_unit_test_setup_teardown(test_send_push_msg1, setup2, teardown2), + cmocka_unit_test_setup_teardown(test_send_push_msg2, setup2, teardown2), + cmocka_unit_test_setup_teardown(test_send_push_msg3, setup2, teardown2), + cmocka_unit_test_setup_teardown(test_send_push_msg4, setup2, teardown2), + cmocka_unit_test_setup_teardown(test_send_push_msg5, setup2, teardown2), + cmocka_unit_test_setup_teardown(test_send_push_msg6, setup2, teardown2), + cmocka_unit_test_setup_teardown(test_send_push_msg7, setup2, teardown2), + cmocka_unit_test_setup_teardown(test_send_push_msg8, setup2, teardown2), + cmocka_unit_test_setup_teardown(test_send_push_msg9, setup2, teardown2), + cmocka_unit_test_setup_teardown(test_send_push_msg10, setup2, teardown2) +#endif }; return cmocka_run_group_tests(tests, NULL, NULL); -- To view, visit http://gerrit.openvpn.net/c/openvpn/+/869?usp=email To unsubscribe, or for help writing mail filters, visit http://gerrit.openvpn.net/settings Gerrit-Project: openvpn Gerrit-Branch: master Gerrit-Change-Id: Ie82bcc7a8e583de9156b185d71d1a323ed8df3fc Gerrit-Change-Number: 869 Gerrit-PatchSet: 6 Gerrit-Owner: mrbff <ma...@mandelbit.com> Gerrit-Reviewer: cron2 <g...@greenie.muc.de> Gerrit-Reviewer: flichtenheld <fr...@lichtenheld.com> Gerrit-Reviewer: plaisthos <arne-open...@rfc2549.org> Gerrit-CC: openvpn-devel <openvpn-devel@lists.sourceforge.net> Gerrit-Attention: plaisthos <arne-open...@rfc2549.org> Gerrit-Attention: cron2 <g...@greenie.muc.de> Gerrit-Attention: flichtenheld <fr...@lichtenheld.com> Gerrit-Attention: mrbff <ma...@mandelbit.com> Gerrit-MessageType: newpatchset
_______________________________________________ Openvpn-devel mailing list Openvpn-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/openvpn-devel