Using the management interface you can now target one or more clients
(via broadcast or via cid) and send a PUSH_UPDATE control message
to update some options. See doc/management-notes.txt for details.
Change-Id: Ie82bcc7a8e583de9156b185d71d1a323ed8df3fc
Signed-off-by: Marco Baffo <marco@mandelbit.com>
Acked-by: Gert Doering <gert@greenie.muc.de>
Message-Id: <20250903164826.13284-1-gert@greenie.muc.de>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg32807.html
Signed-off-by: Gert Doering <gert@greenie.muc.de>
| ... | ... |
@@ -874,9 +874,10 @@ if (BUILD_TESTING) |
| 874 | 874 |
target_sources(test_push_update_msg PRIVATE |
| 875 | 875 |
tests/unit_tests/openvpn/mock_msg.c |
| 876 | 876 |
tests/unit_tests/openvpn/mock_get_random.c |
| 877 |
- src/openvpn/push_util.c |
|
| 878 |
- src/openvpn/options_util.c |
|
| 879 |
- src/openvpn/otime.c |
|
| 877 |
+ src/openvpn/push_util.c |
|
| 878 |
+ src/openvpn/options_util.c |
|
| 879 |
+ src/openvpn/otime.c |
|
| 880 |
+ src/openvpn/list.c |
|
| 880 | 881 |
) |
| 881 | 882 |
|
| 882 | 883 |
if (TARGET test_argv) |
| ... | ... |
@@ -1028,6 +1028,35 @@ This capability is intended to allow the use of certificates |
| 1028 | 1028 |
stored outside of the filesystem (e.g. in Mac OS X Keychain) |
| 1029 | 1029 |
with OpenVPN via the management interface. |
| 1030 | 1030 |
|
| 1031 |
+COMMAND -- push-update-broad (OpenVPN 2.7 or higher) |
|
| 1032 |
+---------------------------------------------------- |
|
| 1033 |
+Send a message to every connected client to update options at runtime. |
|
| 1034 |
+The updatable options are: "block-ipv6", "block-outside-dns", "dhcp-option", |
|
| 1035 |
+"dns", "ifconfig", "ifconfig-ipv6", "redirect-gateway", "redirect-private", |
|
| 1036 |
+"route", "route-gateway", "route-ipv6", "route-metric", "topology", |
|
| 1037 |
+"tun-mtu", "keepalive". When a valid option is pushed, the receiving client will |
|
| 1038 |
+delete every previous value and set new value, so the update of the option will |
|
| 1039 |
+not be incremental even when theoretically possible (ex. with "redirect-gateway"). |
|
| 1040 |
+The '-' symbol in front of an option means the option should be removed. |
|
| 1041 |
+When an option is used with '-', it cannot take any parameter. |
|
| 1042 |
+The '?' symbol in front of an option means the option's update is optional |
|
| 1043 |
+so if the client do not support it, that option will just be ignored without |
|
| 1044 |
+making fail the entire command. The '-' and '?' symbols can be used together. |
|
| 1045 |
+ |
|
| 1046 |
+Option Format Ex. |
|
| 1047 |
+ `-?option`, `-option`, `?option parameters` are valid formats, |
|
| 1048 |
+ `?-option` is not a valid format. |
|
| 1049 |
+ |
|
| 1050 |
+Example |
|
| 1051 |
+ push-update-broad "route 10.10.10.1 255.255.255.255, -dns, ?tun-mtu 1400" |
|
| 1052 |
+ |
|
| 1053 |
+COMMAND -- push-update-cid (OpenVPN 2.7 or higher) |
|
| 1054 |
+---------------------------------------------------- |
|
| 1055 |
+Same as push-update-broad but you must target a single client using client id. |
|
| 1056 |
+ |
|
| 1057 |
+Example |
|
| 1058 |
+ push-update-cid 42 "route 10.10.10.1 255.255.255.255, -dns, ?tun-mtu 1400" |
|
| 1059 |
+ |
|
| 1031 | 1060 |
OUTPUT FORMAT |
| 1032 | 1061 |
------------- |
| 1033 | 1062 |
|
| ... | ... |
@@ -41,6 +41,7 @@ |
| 41 | 41 |
#include "manage.h" |
| 42 | 42 |
#include "openvpn.h" |
| 43 | 43 |
#include "dco.h" |
| 44 |
+#include "push.h" |
|
| 44 | 45 |
#include "multi.h" |
| 45 | 46 |
|
| 46 | 47 |
#include "memdbg.h" |
| ... | ... |
@@ -132,8 +133,10 @@ man_help(void) |
| 132 | 132 |
msg(M_CLIENT, "test n : Produce n lines of output for testing/debugging."); |
| 133 | 133 |
msg(M_CLIENT, "username type u : Enter username u for a queried OpenVPN username."); |
| 134 | 134 |
msg(M_CLIENT, "verb [n] : Set log verbosity level to n, or show if n is absent."); |
| 135 |
- msg(M_CLIENT, |
|
| 136 |
- "version [n] : Set client's version to n or show current version of daemon."); |
|
| 135 |
+ msg(M_CLIENT, "version [n] : Set client's version to n or show current version of daemon."); |
|
| 136 |
+ msg(M_CLIENT, "push-update-broad options : Broadcast a message to update the specified options."); |
|
| 137 |
+ msg(M_CLIENT, " Ex. push-update-broad \"route something, -dns\""); |
|
| 138 |
+ msg(M_CLIENT, "push-update-cid CID options : Send an update message to the client identified by CID."); |
|
| 137 | 139 |
msg(M_CLIENT, "END"); |
| 138 | 140 |
} |
| 139 | 141 |
|
| ... | ... |
@@ -1333,6 +1336,48 @@ set_client_version(struct management *man, const char *version) |
| 1333 | 1333 |
} |
| 1334 | 1334 |
|
| 1335 | 1335 |
static void |
| 1336 |
+man_push_update(struct management *man, const char **p, const push_update_type type) |
|
| 1337 |
+{
|
|
| 1338 |
+ bool status = false; |
|
| 1339 |
+ |
|
| 1340 |
+ if (type == UPT_BROADCAST) |
|
| 1341 |
+ {
|
|
| 1342 |
+ if (!man->persist.callback.push_update_broadcast) |
|
| 1343 |
+ {
|
|
| 1344 |
+ man_command_unsupported("push-update-broad");
|
|
| 1345 |
+ return; |
|
| 1346 |
+ } |
|
| 1347 |
+ |
|
| 1348 |
+ status = (*man->persist.callback.push_update_broadcast)(man->persist.callback.arg, p[1]); |
|
| 1349 |
+ } |
|
| 1350 |
+ else if (type == UPT_BY_CID) |
|
| 1351 |
+ {
|
|
| 1352 |
+ if (!man->persist.callback.push_update_by_cid) |
|
| 1353 |
+ {
|
|
| 1354 |
+ man_command_unsupported("push-update-cid");
|
|
| 1355 |
+ return; |
|
| 1356 |
+ } |
|
| 1357 |
+ |
|
| 1358 |
+ unsigned long cid = 0; |
|
| 1359 |
+ |
|
| 1360 |
+ if (!parse_cid(p[1], &cid)) |
|
| 1361 |
+ {
|
|
| 1362 |
+ msg(M_CLIENT, "ERROR: push-update-cid fail during cid parsing"); |
|
| 1363 |
+ return; |
|
| 1364 |
+ } |
|
| 1365 |
+ |
|
| 1366 |
+ status = (*man->persist.callback.push_update_by_cid)(man->persist.callback.arg, cid, p[2]); |
|
| 1367 |
+ } |
|
| 1368 |
+ |
|
| 1369 |
+ if (status) |
|
| 1370 |
+ {
|
|
| 1371 |
+ msg(M_CLIENT, "SUCCESS: push-update command succeeded"); |
|
| 1372 |
+ return; |
|
| 1373 |
+ } |
|
| 1374 |
+ msg(M_CLIENT, "ERROR: push-update command failed"); |
|
| 1375 |
+} |
|
| 1376 |
+ |
|
| 1377 |
+static void |
|
| 1336 | 1378 |
man_dispatch_command(struct management *man, struct status_output *so, const char **p, |
| 1337 | 1379 |
const int nparms) |
| 1338 | 1380 |
{
|
| ... | ... |
@@ -1655,6 +1700,20 @@ man_dispatch_command(struct management *man, struct status_output *so, const cha |
| 1655 | 1655 |
man_remote(man, p); |
| 1656 | 1656 |
} |
| 1657 | 1657 |
} |
| 1658 |
+ else if (streq(p[0], "push-update-broad")) |
|
| 1659 |
+ {
|
|
| 1660 |
+ if (man_need(man, p, 1, 0)) |
|
| 1661 |
+ {
|
|
| 1662 |
+ man_push_update(man, p, UPT_BROADCAST); |
|
| 1663 |
+ } |
|
| 1664 |
+ } |
|
| 1665 |
+ else if (streq(p[0], "push-update-cid")) |
|
| 1666 |
+ {
|
|
| 1667 |
+ if (man_need(man, p, 2, 0)) |
|
| 1668 |
+ {
|
|
| 1669 |
+ man_push_update(man, p, UPT_BY_CID); |
|
| 1670 |
+ } |
|
| 1671 |
+ } |
|
| 1658 | 1672 |
#if 1 |
| 1659 | 1673 |
else if (streq(p[0], "test")) |
| 1660 | 1674 |
{
|
| ... | ... |
@@ -43,7 +43,6 @@ |
| 43 | 43 |
#define MF_EXTERNAL_KEY_PSSPAD (1u << 16) |
| 44 | 44 |
#define MF_EXTERNAL_KEY_DIGEST (1u << 17) |
| 45 | 45 |
|
| 46 |
- |
|
| 47 | 46 |
#ifdef ENABLE_MANAGEMENT |
| 48 | 47 |
|
| 49 | 48 |
#include "misc.h" |
| ... | ... |
@@ -197,6 +196,8 @@ struct management_callback |
| 197 | 197 |
#endif |
| 198 | 198 |
unsigned int (*remote_entry_count)(void *arg); |
| 199 | 199 |
bool (*remote_entry_get)(void *arg, unsigned int index, char **remote); |
| 200 |
+ bool (*push_update_broadcast)(void *arg, const char *options); |
|
| 201 |
+ bool (*push_update_by_cid)(void *arg, unsigned long cid, const char *options); |
|
| 200 | 202 |
}; |
| 201 | 203 |
|
| 202 | 204 |
/* |
| ... | ... |
@@ -3996,7 +3996,7 @@ management_delete_event(void *arg, event_t event) |
| 3996 | 3996 |
} |
| 3997 | 3997 |
} |
| 3998 | 3998 |
|
| 3999 |
-static struct multi_instance * |
|
| 3999 |
+struct multi_instance * |
|
| 4000 | 4000 |
lookup_by_cid(struct multi_context *m, const unsigned long cid) |
| 4001 | 4001 |
{
|
| 4002 | 4002 |
if (m) |
| ... | ... |
@@ -4137,6 +4137,8 @@ init_management_callback_multi(struct multi_context *m) |
| 4137 | 4137 |
cb.client_auth = management_client_auth; |
| 4138 | 4138 |
cb.client_pending_auth = management_client_pending_auth; |
| 4139 | 4139 |
cb.get_peer_info = management_get_peer_info; |
| 4140 |
+ cb.push_update_broadcast = management_callback_send_push_update_broadcast; |
|
| 4141 |
+ cb.push_update_by_cid = management_callback_send_push_update_by_cid; |
|
| 4140 | 4142 |
management_set_callback(management, &cb); |
| 4141 | 4143 |
} |
| 4142 | 4144 |
#endif /* ifdef ENABLE_MANAGEMENT */ |
| ... | ... |
@@ -4261,3 +4263,47 @@ tunnel_server(struct context *top) |
| 4261 | 4261 |
multi_top_free(&multi); |
| 4262 | 4262 |
close_instance(top); |
| 4263 | 4263 |
} |
| 4264 |
+ |
|
| 4265 |
+/** |
|
| 4266 |
+ * Update the vhash with new IP/IPv6 addresses in the multi_context when a |
|
| 4267 |
+ * push-update message containing ifconfig/ifconfig-ipv6 options is sent |
|
| 4268 |
+ * from the server. This function should be called after a push-update |
|
| 4269 |
+ * and old_ip/old_ipv6 are the previous addresses of the client in |
|
| 4270 |
+ * ctx->options.ifconfig_local and ctx->options.ifconfig_ipv6_local. |
|
| 4271 |
+ */ |
|
| 4272 |
+void |
|
| 4273 |
+update_vhash(struct multi_context *m, struct multi_instance *mi, const char *old_ip, const char *old_ipv6) |
|
| 4274 |
+{
|
|
| 4275 |
+ struct in_addr addr; |
|
| 4276 |
+ struct in6_addr new_ipv6; |
|
| 4277 |
+ |
|
| 4278 |
+ if ((mi->context.options.ifconfig_local && (!old_ip || strcmp(old_ip, mi->context.options.ifconfig_local))) |
|
| 4279 |
+ && inet_pton(AF_INET, mi->context.options.ifconfig_local, &addr) == 1) |
|
| 4280 |
+ {
|
|
| 4281 |
+ in_addr_t new_ip = ntohl(addr.s_addr); |
|
| 4282 |
+ |
|
| 4283 |
+ /* Add new IP */ |
|
| 4284 |
+ multi_learn_in_addr_t(m, mi, new_ip, -1, true); |
|
| 4285 |
+ } |
|
| 4286 |
+ |
|
| 4287 |
+ /* TO DO: |
|
| 4288 |
+ * else if (old_ip) |
|
| 4289 |
+ * {
|
|
| 4290 |
+ * // remove old IP |
|
| 4291 |
+ * } |
|
| 4292 |
+ */ |
|
| 4293 |
+ |
|
| 4294 |
+ if ((mi->context.options.ifconfig_ipv6_local && (!old_ipv6 || strcmp(old_ipv6, mi->context.options.ifconfig_ipv6_local))) |
|
| 4295 |
+ && inet_pton(AF_INET6, mi->context.options.ifconfig_ipv6_local, &new_ipv6) == 1) |
|
| 4296 |
+ {
|
|
| 4297 |
+ /* Add new IPv6 */ |
|
| 4298 |
+ multi_learn_in6_addr(m, mi, new_ipv6, -1, true); |
|
| 4299 |
+ } |
|
| 4300 |
+ |
|
| 4301 |
+ /* TO DO: |
|
| 4302 |
+ * else if (old_ipv6) |
|
| 4303 |
+ * {
|
|
| 4304 |
+ * // remove old IPv6 |
|
| 4305 |
+ * } |
|
| 4306 |
+ */ |
|
| 4307 |
+} |
| ... | ... |
@@ -686,5 +686,12 @@ multi_set_pending(struct multi_context *m, struct multi_instance *mi) |
| 686 | 686 |
*/ |
| 687 | 687 |
void multi_assign_peer_id(struct multi_context *m, struct multi_instance *mi); |
| 688 | 688 |
|
| 689 |
+#ifdef ENABLE_MANAGEMENT |
|
| 690 |
+struct multi_instance * |
|
| 691 |
+lookup_by_cid(struct multi_context *m, const unsigned long cid); |
|
| 692 |
+#endif |
|
| 693 |
+ |
|
| 694 |
+void |
|
| 695 |
+update_vhash(struct multi_context *m, struct multi_instance *mi, const char *old_ip, const char *old_ipv6); |
|
| 689 | 696 |
|
| 690 | 697 |
#endif /* MULTI_H */ |
| ... | ... |
@@ -5488,7 +5488,6 @@ apply_push_options(struct context *c, struct options *options, struct buffer *bu |
| 5488 | 5488 |
{
|
| 5489 | 5489 |
continue; /* Ignoring this option */ |
| 5490 | 5490 |
} |
| 5491 |
- throw_signal_soft(SIGUSR1, "Offending option received from server"); |
|
| 5492 | 5491 |
return false; /* Cause push/pull error and stop push processing */ |
| 5493 | 5492 |
} |
| 5494 | 5493 |
|
| ... | ... |
@@ -236,11 +236,11 @@ check_push_update_option_flags(char *line, int *i, unsigned int *flags) |
| 236 | 236 |
{
|
| 237 | 237 |
if (*flags & PUSH_OPT_OPTIONAL) |
| 238 | 238 |
{
|
| 239 |
- msg(D_PUSH, "Pushed option is not updatable: '%s'. Ignoring.", line); |
|
| 239 |
+ msg(D_PUSH, "Pushed dispensable option is not updatable: '%s'. Ignoring.", line); |
|
| 240 | 240 |
} |
| 241 | 241 |
else |
| 242 | 242 |
{
|
| 243 |
- msg(M_WARN, "Pushed option is not updatable: '%s'. Restarting.", line); |
|
| 243 |
+ msg(M_WARN, "Pushed option is not updatable: '%s'.", line); |
|
| 244 | 244 |
return false; |
| 245 | 245 |
} |
| 246 | 246 |
} |
| ... | ... |
@@ -1073,6 +1073,10 @@ process_incoming_push_reply(struct context *c, unsigned int permission_mask, |
| 1073 | 1073 |
break; |
| 1074 | 1074 |
} |
| 1075 | 1075 |
} |
| 1076 |
+ else |
|
| 1077 |
+ {
|
|
| 1078 |
+ throw_signal_soft(SIGUSR1, "Offending option received from server"); |
|
| 1079 |
+ } |
|
| 1076 | 1080 |
} |
| 1077 | 1081 |
else if (ch == '\0') |
| 1078 | 1082 |
{
|
| ... | ... |
@@ -1100,7 +1104,7 @@ process_incoming_push_msg(struct context *c, const struct buffer *buffer, |
| 1100 | 1100 |
} |
| 1101 | 1101 |
else if (honor_received_options && buf_string_compare_advance(&buf, push_update_cmd)) |
| 1102 | 1102 |
{
|
| 1103 |
- return process_incoming_push_update(c, permission_mask, option_types_found, &buf); |
|
| 1103 |
+ return process_incoming_push_update(c, permission_mask, option_types_found, &buf, false); |
|
| 1104 | 1104 |
} |
| 1105 | 1105 |
else |
| 1106 | 1106 |
{
|
| ... | ... |
@@ -41,6 +41,15 @@ |
| 41 | 41 |
#define PUSH_OPT_TO_REMOVE (1 << 0) |
| 42 | 42 |
#define PUSH_OPT_OPTIONAL (1 << 1) |
| 43 | 43 |
|
| 44 |
+#ifdef ENABLE_MANAGEMENT |
|
| 45 |
+/* Push-update message sender modes */ |
|
| 46 |
+typedef enum |
|
| 47 |
+{
|
|
| 48 |
+ UPT_BROADCAST = 0, |
|
| 49 |
+ UPT_BY_CID = 1 |
|
| 50 |
+} push_update_type; |
|
| 51 |
+#endif |
|
| 52 |
+ |
|
| 44 | 53 |
int process_incoming_push_request(struct context *c); |
| 45 | 54 |
|
| 46 | 55 |
/** |
| ... | ... |
@@ -56,6 +65,7 @@ int process_incoming_push_request(struct context *c); |
| 56 | 56 |
* @param option_types_found A pointer to a variable that will be filled with the types of options |
| 57 | 57 |
* found in the message. |
| 58 | 58 |
* @param buf A buffer containing the received message. |
| 59 |
+ * @param msg_sender A boolean indicating if function is called by the message sender (server). |
|
| 59 | 60 |
* |
| 60 | 61 |
* @return |
| 61 | 62 |
* - `PUSH_MSG_UPDATE`: The message was processed successfully, and the updates were applied. |
| ... | ... |
@@ -65,7 +75,8 @@ int process_incoming_push_request(struct context *c); |
| 65 | 65 |
*/ |
| 66 | 66 |
|
| 67 | 67 |
int process_incoming_push_update(struct context *c, unsigned int permission_mask, |
| 68 |
- unsigned int *option_types_found, struct buffer *buf); |
|
| 68 |
+ unsigned int *option_types_found, struct buffer *buf, |
|
| 69 |
+ bool msg_sender); |
|
| 69 | 70 |
|
| 70 | 71 |
int process_incoming_push_msg(struct context *c, const struct buffer *buffer, |
| 71 | 72 |
bool honor_received_options, unsigned int permission_mask, |
| ... | ... |
@@ -127,4 +138,28 @@ void send_push_reply_auth_token(struct tls_multi *multi); |
| 127 | 127 |
*/ |
| 128 | 128 |
void receive_auth_pending(struct context *c, const struct buffer *buffer); |
| 129 | 129 |
|
| 130 |
+#ifdef ENABLE_MANAGEMENT |
|
| 131 |
+/** |
|
| 132 |
+ * @brief A function to send a PUSH_UPDATE control message from server to client(s). |
|
| 133 |
+ * |
|
| 134 |
+ * @param m the multi_context, contains all the clients connected to this server. |
|
| 135 |
+ * @param target the target to which to send the message. It should be: |
|
| 136 |
+ * `NULL` if `type == UPT_BROADCAST`, |
|
| 137 |
+ * a `mroute_addr *` if `type == UPT_BY_ADDR`, |
|
| 138 |
+ * a `char *` if `type == UPT_BY_CN`, |
|
| 139 |
+ * an `unsigned long *` if `type == UPT_BY_CID`. |
|
| 140 |
+ * @param msg a string containing the options to send. |
|
| 141 |
+ * @param type the way to address the message (broadcast, by cid, by cn, by address). |
|
| 142 |
+ * @param push_bundle_size the maximum size of a bundle of pushed option. Just use PUSH_BUNDLE_SIZE macro. |
|
| 143 |
+ * @return the number of clients to which the message was sent. |
|
| 144 |
+ */ |
|
| 145 |
+int |
|
| 146 |
+send_push_update(struct multi_context *m, const void *target, const char *msg, const push_update_type type, const int push_bundle_size); |
|
| 147 |
+ |
|
| 148 |
+bool management_callback_send_push_update_broadcast(void *arg, const char *options); |
|
| 149 |
+ |
|
| 150 |
+bool management_callback_send_push_update_by_cid(void *arg, unsigned long cid, const char *options); |
|
| 151 |
+ |
|
| 152 |
+#endif /* ifdef ENABLE_MANAGEMENT*/ |
|
| 153 |
+ |
|
| 130 | 154 |
#endif /* ifndef PUSH_H */ |
| ... | ... |
@@ -3,10 +3,16 @@ |
| 3 | 3 |
#endif |
| 4 | 4 |
|
| 5 | 5 |
#include "push.h" |
| 6 |
+#include "buffer.h" |
|
| 7 |
+ |
|
| 8 |
+#ifdef ENABLE_MANAGEMENT |
|
| 9 |
+#include "multi.h" |
|
| 10 |
+#endif |
|
| 6 | 11 |
|
| 7 | 12 |
int |
| 8 | 13 |
process_incoming_push_update(struct context *c, unsigned int permission_mask, |
| 9 |
- unsigned int *option_types_found, struct buffer *buf) |
|
| 14 |
+ unsigned int *option_types_found, struct buffer *buf, |
|
| 15 |
+ bool msg_sender) |
|
| 10 | 16 |
{
|
| 11 | 17 |
int ret = PUSH_MSG_ERROR; |
| 12 | 18 |
const uint8_t ch = buf_read_u8(buf); |
| ... | ... |
@@ -27,6 +33,10 @@ process_incoming_push_update(struct context *c, unsigned int permission_mask, |
| 27 | 27 |
break; |
| 28 | 28 |
} |
| 29 | 29 |
} |
| 30 |
+ else if (!msg_sender) |
|
| 31 |
+ {
|
|
| 32 |
+ throw_signal_soft(SIGUSR1, "Offending option received from server"); |
|
| 33 |
+ } |
|
| 30 | 34 |
} |
| 31 | 35 |
else if (ch == '\0') |
| 32 | 36 |
{
|
| ... | ... |
@@ -35,3 +45,260 @@ process_incoming_push_update(struct context *c, unsigned int permission_mask, |
| 35 | 35 |
|
| 36 | 36 |
return ret; |
| 37 | 37 |
} |
| 38 |
+ |
|
| 39 |
+#ifdef ENABLE_MANAGEMENT |
|
| 40 |
+/** |
|
| 41 |
+ * Return index of last `,` or `0` if it didn't find any. |
|
| 42 |
+ * If there is a comma at index `0` it's an error anyway |
|
| 43 |
+ */ |
|
| 44 |
+static int |
|
| 45 |
+find_first_comma_of_next_bundle(const char *str, int ix) |
|
| 46 |
+{
|
|
| 47 |
+ while (ix > 0) |
|
| 48 |
+ {
|
|
| 49 |
+ if (str[ix] == ',') |
|
| 50 |
+ {
|
|
| 51 |
+ return ix; |
|
| 52 |
+ } |
|
| 53 |
+ ix--; |
|
| 54 |
+ } |
|
| 55 |
+ return 0; |
|
| 56 |
+} |
|
| 57 |
+ |
|
| 58 |
+/* Allocate memory and assemble the final message */ |
|
| 59 |
+static struct buffer |
|
| 60 |
+forge_msg(const char *src, const char *continuation, struct gc_arena *gc) |
|
| 61 |
+{
|
|
| 62 |
+ int src_len = strlen(src); |
|
| 63 |
+ int con_len = continuation ? strlen(continuation) : 0; |
|
| 64 |
+ struct buffer buf = alloc_buf_gc(src_len + sizeof(push_update_cmd) + con_len + 2, gc); |
|
| 65 |
+ |
|
| 66 |
+ buf_printf(&buf, "%s,%s%s", push_update_cmd, src, continuation ? continuation : ""); |
|
| 67 |
+ |
|
| 68 |
+ return buf; |
|
| 69 |
+} |
|
| 70 |
+ |
|
| 71 |
+static char * |
|
| 72 |
+gc_strdup(const char *src, struct gc_arena *gc) |
|
| 73 |
+{
|
|
| 74 |
+ char *ret = gc_malloc((strlen(src) + 1) * sizeof(char), true, gc); |
|
| 75 |
+ |
|
| 76 |
+ strcpy(ret, src); |
|
| 77 |
+ return ret; |
|
| 78 |
+} |
|
| 79 |
+ |
|
| 80 |
+/* It split the messagge (if necessay) and fill msgs with the message chunks. |
|
| 81 |
+ * Return `false` on failure an `true` on success. |
|
| 82 |
+ */ |
|
| 83 |
+static bool |
|
| 84 |
+message_splitter(const char *s, struct buffer *msgs, struct gc_arena *gc, const int safe_cap) |
|
| 85 |
+{
|
|
| 86 |
+ if (!s || !*s) |
|
| 87 |
+ {
|
|
| 88 |
+ return false; |
|
| 89 |
+ } |
|
| 90 |
+ |
|
| 91 |
+ char *str = gc_strdup(s, gc); |
|
| 92 |
+ int i = 0; |
|
| 93 |
+ int im = 0; |
|
| 94 |
+ |
|
| 95 |
+ while (*str) |
|
| 96 |
+ {
|
|
| 97 |
+ /* + ',' - '/0' */ |
|
| 98 |
+ if (strlen(str) > safe_cap) |
|
| 99 |
+ {
|
|
| 100 |
+ int ci = find_first_comma_of_next_bundle(str, safe_cap); |
|
| 101 |
+ if (!ci) |
|
| 102 |
+ {
|
|
| 103 |
+ /* if no commas were found go to fail, do not send any message */ |
|
| 104 |
+ return false; |
|
| 105 |
+ } |
|
| 106 |
+ str[ci] = '\0'; |
|
| 107 |
+ /* copy from i to (ci -1) */ |
|
| 108 |
+ msgs[im] = forge_msg(str, ",push-continuation 2", gc); |
|
| 109 |
+ i = ci + 1; |
|
| 110 |
+ } |
|
| 111 |
+ else |
|
| 112 |
+ {
|
|
| 113 |
+ if (im) |
|
| 114 |
+ {
|
|
| 115 |
+ msgs[im] = forge_msg(str, ",push-continuation 1", gc); |
|
| 116 |
+ } |
|
| 117 |
+ else |
|
| 118 |
+ {
|
|
| 119 |
+ msgs[im] = forge_msg(str, NULL, gc); |
|
| 120 |
+ } |
|
| 121 |
+ i = strlen(str); |
|
| 122 |
+ } |
|
| 123 |
+ str = &str[i]; |
|
| 124 |
+ im++; |
|
| 125 |
+ } |
|
| 126 |
+ return true; |
|
| 127 |
+} |
|
| 128 |
+ |
|
| 129 |
+/* send the message(s) prepared to one single client */ |
|
| 130 |
+static bool |
|
| 131 |
+send_single_push_update(struct context *c, struct buffer *msgs, unsigned int *option_types_found) |
|
| 132 |
+{
|
|
| 133 |
+ if (!msgs[0].data || !*(msgs[0].data)) |
|
| 134 |
+ {
|
|
| 135 |
+ return false; |
|
| 136 |
+ } |
|
| 137 |
+ int i = -1; |
|
| 138 |
+ |
|
| 139 |
+ while (msgs[++i].data && *(msgs[i].data)) |
|
| 140 |
+ {
|
|
| 141 |
+ if (!send_control_channel_string(c, BSTR(&msgs[i]), D_PUSH)) |
|
| 142 |
+ {
|
|
| 143 |
+ return false; |
|
| 144 |
+ } |
|
| 145 |
+ |
|
| 146 |
+ /* After sending the control message, we update the options |
|
| 147 |
+ * server-side in the client's context so pushed options like |
|
| 148 |
+ * ifconfig/ifconfig-ipv6 can actually work. |
|
| 149 |
+ * If we don't do that, packets arriving from the client with the |
|
| 150 |
+ * new address will be rejected and packets for the new address |
|
| 151 |
+ * will not be routed towards the client. |
|
| 152 |
+ * For the same reason we later update the vhash too in |
|
| 153 |
+ * `send_push_update()` function. |
|
| 154 |
+ */ |
|
| 155 |
+ buf_string_compare_advance(&msgs[i], push_update_cmd); |
|
| 156 |
+ if (process_incoming_push_update(c, pull_permission_mask(c), option_types_found, &msgs[i], true) == PUSH_MSG_ERROR) |
|
| 157 |
+ {
|
|
| 158 |
+ msg(M_WARN, "Failed to process push update message sent to client ID: %u", |
|
| 159 |
+ c->c2.tls_multi ? c->c2.tls_multi->peer_id : UINT32_MAX); |
|
| 160 |
+ continue; |
|
| 161 |
+ } |
|
| 162 |
+ c->options.push_option_types_found |= *option_types_found; |
|
| 163 |
+ if (!options_postprocess_pull(&c->options, c->c2.es)) |
|
| 164 |
+ {
|
|
| 165 |
+ msg(M_WARN, "Failed to post-process push update message sent to client ID: %u", |
|
| 166 |
+ c->c2.tls_multi ? c->c2.tls_multi->peer_id : UINT32_MAX); |
|
| 167 |
+ } |
|
| 168 |
+ } |
|
| 169 |
+ return true; |
|
| 170 |
+} |
|
| 171 |
+ |
|
| 172 |
+int |
|
| 173 |
+send_push_update(struct multi_context *m, const void *target, const char *msg, const push_update_type type, const int push_bundle_size) |
|
| 174 |
+{
|
|
| 175 |
+ if (!msg || !*msg || !m |
|
| 176 |
+ || (!target && type != UPT_BROADCAST)) |
|
| 177 |
+ {
|
|
| 178 |
+ return -EINVAL; |
|
| 179 |
+ } |
|
| 180 |
+ |
|
| 181 |
+ struct gc_arena gc = gc_new(); |
|
| 182 |
+ /* extra space for possible trailing ifconfig and push-continuation */ |
|
| 183 |
+ const int extra = 84 + sizeof(push_update_cmd); |
|
| 184 |
+ /* push_bundle_size is the maximum size of a message, so if the message |
|
| 185 |
+ * we want to send exceeds that size we have to split it into smaller messages */ |
|
| 186 |
+ const int safe_cap = push_bundle_size - extra; |
|
| 187 |
+ int msgs_num = (strlen(msg) / safe_cap) + ((strlen(msg) % safe_cap) != 0); |
|
| 188 |
+ struct buffer *msgs = gc_malloc((msgs_num + 1) * sizeof(struct buffer), true, &gc); |
|
| 189 |
+ |
|
| 190 |
+ unsigned int option_types_found = 0; |
|
| 191 |
+ |
|
| 192 |
+ msgs[msgs_num].data = NULL; |
|
| 193 |
+ if (!message_splitter(msg, msgs, &gc, safe_cap)) |
|
| 194 |
+ {
|
|
| 195 |
+ gc_free(&gc); |
|
| 196 |
+ return -EINVAL; |
|
| 197 |
+ } |
|
| 198 |
+ |
|
| 199 |
+ if (type == UPT_BY_CID) |
|
| 200 |
+ {
|
|
| 201 |
+ struct multi_instance *mi = lookup_by_cid(m, *((unsigned long *)target)); |
|
| 202 |
+ |
|
| 203 |
+ if (!mi) |
|
| 204 |
+ {
|
|
| 205 |
+ return -ENOENT; |
|
| 206 |
+ } |
|
| 207 |
+ |
|
| 208 |
+ const char *old_ip = mi->context.options.ifconfig_local; |
|
| 209 |
+ const char *old_ipv6 = mi->context.options.ifconfig_ipv6_local; |
|
| 210 |
+ if (!mi->halt |
|
| 211 |
+ && send_single_push_update(&mi->context, msgs, &option_types_found)) |
|
| 212 |
+ {
|
|
| 213 |
+ if (option_types_found & OPT_P_UP) |
|
| 214 |
+ {
|
|
| 215 |
+ update_vhash(m, mi, old_ip, old_ipv6); |
|
| 216 |
+ } |
|
| 217 |
+ gc_free(&gc); |
|
| 218 |
+ return 1; |
|
| 219 |
+ } |
|
| 220 |
+ else |
|
| 221 |
+ {
|
|
| 222 |
+ gc_free(&gc); |
|
| 223 |
+ return 0; |
|
| 224 |
+ } |
|
| 225 |
+ } |
|
| 226 |
+ |
|
| 227 |
+ int count = 0; |
|
| 228 |
+ struct hash_iterator hi; |
|
| 229 |
+ const struct hash_element *he; |
|
| 230 |
+ |
|
| 231 |
+ hash_iterator_init(m->iter, &hi); |
|
| 232 |
+ while ((he = hash_iterator_next(&hi))) |
|
| 233 |
+ {
|
|
| 234 |
+ struct multi_instance *curr_mi = he->value; |
|
| 235 |
+ |
|
| 236 |
+ if (curr_mi->halt) |
|
| 237 |
+ {
|
|
| 238 |
+ continue; |
|
| 239 |
+ } |
|
| 240 |
+ |
|
| 241 |
+ /* Type is UPT_BROADCAST so we update every client */ |
|
| 242 |
+ option_types_found = 0; |
|
| 243 |
+ const char *old_ip = curr_mi->context.options.ifconfig_local; |
|
| 244 |
+ const char *old_ipv6 = curr_mi->context.options.ifconfig_ipv6_local; |
|
| 245 |
+ if (!send_single_push_update(&curr_mi->context, msgs, &option_types_found)) |
|
| 246 |
+ {
|
|
| 247 |
+ msg(M_CLIENT, "ERROR: Peer ID: %u has not been updated", |
|
| 248 |
+ curr_mi->context.c2.tls_multi ? curr_mi->context.c2.tls_multi->peer_id : UINT32_MAX); |
|
| 249 |
+ continue; |
|
| 250 |
+ } |
|
| 251 |
+ if (option_types_found & OPT_P_UP) |
|
| 252 |
+ {
|
|
| 253 |
+ update_vhash(m, curr_mi, old_ip, old_ipv6); |
|
| 254 |
+ } |
|
| 255 |
+ count++; |
|
| 256 |
+ } |
|
| 257 |
+ |
|
| 258 |
+ hash_iterator_free(&hi); |
|
| 259 |
+ gc_free(&gc); |
|
| 260 |
+ return count; |
|
| 261 |
+} |
|
| 262 |
+ |
|
| 263 |
+#define RETURN_UPDATE_STATUS(n_sent) \ |
|
| 264 |
+ do \ |
|
| 265 |
+ { \
|
|
| 266 |
+ if ((n_sent) > 0) \ |
|
| 267 |
+ { \
|
|
| 268 |
+ msg(M_CLIENT, "SUCCESS: %d client(s) updated", (n_sent)); \ |
|
| 269 |
+ return true; \ |
|
| 270 |
+ } \ |
|
| 271 |
+ else \ |
|
| 272 |
+ { \
|
|
| 273 |
+ msg(M_CLIENT, "ERROR: no client updated"); \ |
|
| 274 |
+ return false; \ |
|
| 275 |
+ } \ |
|
| 276 |
+ } while (0) |
|
| 277 |
+ |
|
| 278 |
+ |
|
| 279 |
+bool |
|
| 280 |
+management_callback_send_push_update_broadcast(void *arg, const char *options) |
|
| 281 |
+{
|
|
| 282 |
+ int n_sent = send_push_update(arg, NULL, options, UPT_BROADCAST, PUSH_BUNDLE_SIZE); |
|
| 283 |
+ |
|
| 284 |
+ RETURN_UPDATE_STATUS(n_sent); |
|
| 285 |
+} |
|
| 286 |
+ |
|
| 287 |
+bool |
|
| 288 |
+management_callback_send_push_update_by_cid(void *arg, unsigned long cid, const char *options) |
|
| 289 |
+{
|
|
| 290 |
+ int n_sent = send_push_update(arg, &cid, options, UPT_BY_CID, PUSH_BUNDLE_SIZE); |
|
| 291 |
+ |
|
| 292 |
+ RETURN_UPDATE_STATUS(n_sent); |
|
| 293 |
+} |
|
| 294 |
+#endif /* ifdef ENABLE_MANAGEMENT */ |
| ... | ... |
@@ -337,7 +337,8 @@ push_update_msg_testdriver_SOURCES = test_push_update_msg.c \ |
| 337 | 337 |
$(top_srcdir)/src/openvpn/platform.c \ |
| 338 | 338 |
$(top_srcdir)/src/openvpn/push_util.c \ |
| 339 | 339 |
$(top_srcdir)/src/openvpn/options_util.c \ |
| 340 |
- $(top_srcdir)/src/openvpn/otime.c |
|
| 340 |
+ $(top_srcdir)/src/openvpn/otime.c \ |
|
| 341 |
+ $(top_srcdir)/src/openvpn/list.c |
|
| 341 | 342 |
|
| 342 | 343 |
socket_testdriver_CFLAGS = \ |
| 343 | 344 |
-I$(top_srcdir)/include -I$(top_srcdir)/src/compat -I$(top_srcdir)/src/openvpn \ |
| ... | ... |
@@ -8,9 +8,16 @@ |
| 8 | 8 |
#include <cmocka.h> |
| 9 | 9 |
#include "push.h" |
| 10 | 10 |
#include "options_util.h" |
| 11 |
+#include "multi.h" |
|
| 11 | 12 |
|
| 12 | 13 |
/* mocks */ |
| 13 | 14 |
|
| 15 |
+void |
|
| 16 |
+throw_signal_soft(const int signum, const char *signal_text) |
|
| 17 |
+{
|
|
| 18 |
+ msg(M_WARN, "Offending option received from server"); |
|
| 19 |
+} |
|
| 20 |
+ |
|
| 14 | 21 |
unsigned int |
| 15 | 22 |
pull_permission_mask(const struct context *c) |
| 16 | 23 |
{
|
| ... | ... |
@@ -21,6 +28,18 @@ pull_permission_mask(const struct context *c) |
| 21 | 21 |
return flags; |
| 22 | 22 |
} |
| 23 | 23 |
|
| 24 |
+void |
|
| 25 |
+update_vhash(struct multi_context *m, struct multi_instance *mi, const char *old_ip, const char *old_ipv6) |
|
| 26 |
+{
|
|
| 27 |
+ return; |
|
| 28 |
+} |
|
| 29 |
+ |
|
| 30 |
+bool |
|
| 31 |
+options_postprocess_pull(struct options *options, struct env_set *es) |
|
| 32 |
+{
|
|
| 33 |
+ return true; |
|
| 34 |
+} |
|
| 35 |
+ |
|
| 24 | 36 |
bool |
| 25 | 37 |
apply_push_options(struct context *c, struct options *options, struct buffer *buf, |
| 26 | 38 |
unsigned int permission_mask, unsigned int *option_types_found, |
| ... | ... |
@@ -48,7 +67,6 @@ apply_push_options(struct context *c, struct options *options, struct buffer *bu |
| 48 | 48 |
{
|
| 49 | 49 |
continue; /* Ignoring this option */ |
| 50 | 50 |
} |
| 51 |
- msg(M_WARN, "Offending option received from server"); |
|
| 52 | 51 |
return false; /* Cause push/pull error and stop push processing */ |
| 53 | 52 |
} |
| 54 | 53 |
} |
| ... | ... |
@@ -77,7 +95,7 @@ process_incoming_push_msg(struct context *c, const struct buffer *buffer, |
| 77 | 77 |
} |
| 78 | 78 |
else if (honor_received_options && buf_string_compare_advance(&buf, push_update_cmd)) |
| 79 | 79 |
{
|
| 80 |
- return process_incoming_push_update(c, permission_mask, option_types_found, &buf); |
|
| 80 |
+ return process_incoming_push_update(c, permission_mask, option_types_found, &buf, false); |
|
| 81 | 81 |
} |
| 82 | 82 |
else |
| 83 | 83 |
{
|
| ... | ... |
@@ -85,6 +103,49 @@ process_incoming_push_msg(struct context *c, const struct buffer *buffer, |
| 85 | 85 |
} |
| 86 | 86 |
} |
| 87 | 87 |
|
| 88 |
+const char * |
|
| 89 |
+tls_common_name(const struct tls_multi *multi, const bool null) |
|
| 90 |
+{
|
|
| 91 |
+ return NULL; |
|
| 92 |
+} |
|
| 93 |
+ |
|
| 94 |
+#ifndef ENABLE_MANAGEMENT |
|
| 95 |
+bool |
|
| 96 |
+send_control_channel_string(struct context *c, const char *str, int msglevel) |
|
| 97 |
+{
|
|
| 98 |
+ return true; |
|
| 99 |
+} |
|
| 100 |
+#else /* ifndef ENABLE_MANAGEMENT */ |
|
| 101 |
+char **res; |
|
| 102 |
+int i; |
|
| 103 |
+ |
|
| 104 |
+bool |
|
| 105 |
+send_control_channel_string(struct context *c, const char *str, int msglevel) |
|
| 106 |
+{
|
|
| 107 |
+ if (res && res[i] && strcmp(res[i], str)) |
|
| 108 |
+ {
|
|
| 109 |
+ printf("\n\nexpected: %s\n\n actual: %s\n\n", res[i], str);
|
|
| 110 |
+ return false; |
|
| 111 |
+ } |
|
| 112 |
+ i++; |
|
| 113 |
+ return true; |
|
| 114 |
+} |
|
| 115 |
+ |
|
| 116 |
+struct multi_instance * |
|
| 117 |
+lookup_by_cid(struct multi_context *m, const unsigned long cid) |
|
| 118 |
+{
|
|
| 119 |
+ return *(m->instances); |
|
| 120 |
+} |
|
| 121 |
+ |
|
| 122 |
+bool |
|
| 123 |
+mroute_extract_openvpn_sockaddr(struct mroute_addr *addr, |
|
| 124 |
+ const struct openvpn_sockaddr *osaddr, |
|
| 125 |
+ bool use_port) |
|
| 126 |
+{
|
|
| 127 |
+ return true; |
|
| 128 |
+} |
|
| 129 |
+#endif /* ifndef ENABLE_MANAGEMENT */ |
|
| 130 |
+ |
|
| 88 | 131 |
/* tests */ |
| 89 | 132 |
|
| 90 | 133 |
static void |
| ... | ... |
@@ -120,7 +181,6 @@ test_incoming_push_message_error1(void **state) |
| 120 | 120 |
free_buf(&buf); |
| 121 | 121 |
} |
| 122 | 122 |
|
| 123 |
- |
|
| 124 | 123 |
static void |
| 125 | 124 |
test_incoming_push_message_error2(void **state) |
| 126 | 125 |
{
|
| ... | ... |
@@ -219,6 +279,207 @@ test_incoming_push_message_mix2(void **state) |
| 219 | 219 |
free_buf(&buf); |
| 220 | 220 |
} |
| 221 | 221 |
|
| 222 |
+#ifdef ENABLE_MANAGEMENT |
|
| 223 |
+char *r0[] = {
|
|
| 224 |
+ "PUSH_UPDATE,redirect-gateway local,route 192.168.1.0 255.255.255.0" |
|
| 225 |
+}; |
|
| 226 |
+char *r1[] = {
|
|
| 227 |
+ "PUSH_UPDATE,-dhcp-option,blablalalalalalalalalalalalalf, lalalalalalalalalalalalalalaf,push-continuation 2", |
|
| 228 |
+ "PUSH_UPDATE, akakakakakakakakakakakaf, dhcp-option DNS 8.8.8.8,redirect-gateway local,push-continuation 2", |
|
| 229 |
+ "PUSH_UPDATE,route 192.168.1.0 255.255.255.0,push-continuation 1" |
|
| 230 |
+}; |
|
| 231 |
+char *r3[] = {
|
|
| 232 |
+ "PUSH_UPDATE,,," |
|
| 233 |
+}; |
|
| 234 |
+char *r4[] = {
|
|
| 235 |
+ "PUSH_UPDATE,-dhcp-option, blablalalalalalalalalalalalalf, lalalalalalalalalalalalalalaf,push-continuation 2", |
|
| 236 |
+ "PUSH_UPDATE, akakakakakakakakakakakaf,dhcp-option DNS 8.8.8.8, redirect-gateway local,push-continuation 2", |
|
| 237 |
+ "PUSH_UPDATE, route 192.168.1.0 255.255.255.0,,push-continuation 1" |
|
| 238 |
+}; |
|
| 239 |
+char *r5[] = {
|
|
| 240 |
+ "PUSH_UPDATE,,-dhcp-option, blablalalalalalalalalalalalalf, lalalalalalalalalalalalalalaf,push-continuation 2", |
|
| 241 |
+ "PUSH_UPDATE, akakakakakakakakakakakaf,dhcp-option DNS 8.8.8.8, redirect-gateway local,push-continuation 2", |
|
| 242 |
+ "PUSH_UPDATE, route 192.168.1.0 255.255.255.0,push-continuation 1" |
|
| 243 |
+}; |
|
| 244 |
+char *r6[] = {
|
|
| 245 |
+ "PUSH_UPDATE,-dhcp-option,blablalalalalalalalalalalalalf, lalalalalalalalalalalalalalaf,push-continuation 2", |
|
| 246 |
+ "PUSH_UPDATE, akakakakakakakakakakakaf, dhcp-option DNS 8.8.8.8, redirect-gateway 10.10.10.10,,push-continuation 2", |
|
| 247 |
+ "PUSH_UPDATE, route 192.168.1.0 255.255.255.0,,push-continuation 1" |
|
| 248 |
+}; |
|
| 249 |
+char *r7[] = {
|
|
| 250 |
+ "PUSH_UPDATE,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,push-continuation 2", |
|
| 251 |
+ "PUSH_UPDATE,,,,,,,,,,,,,,,,,,,push-continuation 1" |
|
| 252 |
+}; |
|
| 253 |
+char *r8[] = {
|
|
| 254 |
+ "PUSH_UPDATE,-dhcp-option,blablalalalalalalalalalalalalf, lalalalalalalalalalalalalalaf,push-continuation 2", |
|
| 255 |
+ "PUSH_UPDATE, akakakakakakakakakakakaf, dhcp-option DNS 8.8.8.8,redirect-gateway\n local,push-continuation 2", |
|
| 256 |
+ "PUSH_UPDATE,route 192.168.1.0 255.255.255.0\n\n\n,push-continuation 1" |
|
| 257 |
+}; |
|
| 258 |
+char *r9[] = {
|
|
| 259 |
+ "PUSH_UPDATE,," |
|
| 260 |
+}; |
|
| 261 |
+ |
|
| 262 |
+ |
|
| 263 |
+const char *msg0 = "redirect-gateway local,route 192.168.1.0 255.255.255.0"; |
|
| 264 |
+const char *msg1 = "-dhcp-option,blablalalalalalalalalalalalalf, lalalalalalalalalalalalalalaf," |
|
| 265 |
+ " akakakakakakakakakakakaf, dhcp-option DNS 8.8.8.8,redirect-gateway local,route 192.168.1.0 255.255.255.0"; |
|
| 266 |
+const char *msg2 = ""; |
|
| 267 |
+const char *msg3 = ",,"; |
|
| 268 |
+const char *msg4 = "-dhcp-option, blablalalalalalalalalalalalalf, lalalalalalalalalalalalalalaf," |
|
| 269 |
+ " akakakakakakakakakakakaf,dhcp-option DNS 8.8.8.8, redirect-gateway local, route 192.168.1.0 255.255.255.0,"; |
|
| 270 |
+const char *msg5 = ",-dhcp-option, blablalalalalalalalalalalalalf, lalalalalalalalalalalalalalaf," |
|
| 271 |
+ " akakakakakakakakakakakaf,dhcp-option DNS 8.8.8.8, redirect-gateway local, route 192.168.1.0 255.255.255.0"; |
|
| 272 |
+const char *msg6 = "-dhcp-option,blablalalalalalalalalalalalalf, lalalalalalalalalalalalalalaf, akakakakakakakakakakakaf," |
|
| 273 |
+ " dhcp-option DNS 8.8.8.8, redirect-gateway 10.10.10.10,, route 192.168.1.0 255.255.255.0,"; |
|
| 274 |
+const char *msg7 = ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"; |
|
| 275 |
+const char *msg8 = "-dhcp-option,blablalalalalalalalalalalalalf, lalalalalalalalalalalalalalaf, akakakakakakakakakakakaf," |
|
| 276 |
+ " dhcp-option DNS 8.8.8.8,redirect-gateway\n local,route 192.168.1.0 255.255.255.0\n\n\n"; |
|
| 277 |
+const char *msg9 = ","; |
|
| 278 |
+ |
|
| 279 |
+const char *msg10 = "abandon ability able about above absent absorb abstract absurd abuse access accident account accuse achieve" |
|
| 280 |
+ "acid acoustic acquire across act action actor actress actual adapt add addict address adjust" |
|
| 281 |
+ "baby bachelor bacon badge bag balance balcony ball bamboo banana banner bar barely bargain barrel base basic" |
|
| 282 |
+ "basket battle beach bean beauty because become beef before begin behave behind" |
|
| 283 |
+ "cabbage cabin cable cactus cage cake call calm camera camp can canal cancel candy cannon canoe canvas canyon" |
|
| 284 |
+ "capable capital captain car carbon card cargo carpet carry cart case" |
|
| 285 |
+ "daisy damage damp dance danger daring dash daughter dawn day deal debate debris decade december decide decline" |
|
| 286 |
+ "decorate decrease deer defense define defy degree delay deliver demand demise denial"; |
|
| 287 |
+ |
|
| 288 |
+#define PUSH_BUNDLE_SIZE_TEST 184 |
|
| 289 |
+ |
|
| 290 |
+static void |
|
| 291 |
+test_send_push_msg0(void **state) |
|
| 292 |
+{
|
|
| 293 |
+ i = 0; |
|
| 294 |
+ res = r0; |
|
| 295 |
+ struct multi_context *m = *state; |
|
| 296 |
+ const unsigned long cid = 0; |
|
| 297 |
+ assert_int_equal(send_push_update(m, &cid, msg0, UPT_BY_CID, PUSH_BUNDLE_SIZE_TEST), 1); |
|
| 298 |
+} |
|
| 299 |
+static void |
|
| 300 |
+test_send_push_msg1(void **state) |
|
| 301 |
+{
|
|
| 302 |
+ i = 0; |
|
| 303 |
+ res = r1; |
|
| 304 |
+ struct multi_context *m = *state; |
|
| 305 |
+ const unsigned long cid = 0; |
|
| 306 |
+ assert_int_equal(send_push_update(m, &cid, msg1, UPT_BY_CID, PUSH_BUNDLE_SIZE_TEST), 1); |
|
| 307 |
+} |
|
| 308 |
+ |
|
| 309 |
+static void |
|
| 310 |
+test_send_push_msg2(void **state) |
|
| 311 |
+{
|
|
| 312 |
+ i = 0; |
|
| 313 |
+ res = NULL; |
|
| 314 |
+ struct multi_context *m = *state; |
|
| 315 |
+ const unsigned long cid = 0; |
|
| 316 |
+ assert_int_equal(send_push_update(m, &cid, msg2, UPT_BY_CID, PUSH_BUNDLE_SIZE_TEST), -EINVAL); |
|
| 317 |
+} |
|
| 318 |
+ |
|
| 319 |
+static void |
|
| 320 |
+test_send_push_msg3(void **state) |
|
| 321 |
+{
|
|
| 322 |
+ i = 0; |
|
| 323 |
+ res = r3; |
|
| 324 |
+ struct multi_context *m = *state; |
|
| 325 |
+ const unsigned long cid = 0; |
|
| 326 |
+ assert_int_equal(send_push_update(m, &cid, msg3, UPT_BY_CID, PUSH_BUNDLE_SIZE_TEST), 1); |
|
| 327 |
+} |
|
| 328 |
+ |
|
| 329 |
+static void |
|
| 330 |
+test_send_push_msg4(void **state) |
|
| 331 |
+{
|
|
| 332 |
+ i = 0; |
|
| 333 |
+ res = r4; |
|
| 334 |
+ struct multi_context *m = *state; |
|
| 335 |
+ const unsigned long cid = 0; |
|
| 336 |
+ assert_int_equal(send_push_update(m, &cid, msg4, UPT_BY_CID, PUSH_BUNDLE_SIZE_TEST), 1); |
|
| 337 |
+} |
|
| 338 |
+ |
|
| 339 |
+static void |
|
| 340 |
+test_send_push_msg5(void **state) |
|
| 341 |
+{
|
|
| 342 |
+ i = 0; |
|
| 343 |
+ res = r5; |
|
| 344 |
+ struct multi_context *m = *state; |
|
| 345 |
+ const unsigned long cid = 0; |
|
| 346 |
+ assert_int_equal(send_push_update(m, &cid, msg5, UPT_BY_CID, PUSH_BUNDLE_SIZE_TEST), 1); |
|
| 347 |
+} |
|
| 348 |
+ |
|
| 349 |
+static void |
|
| 350 |
+test_send_push_msg6(void **state) |
|
| 351 |
+{
|
|
| 352 |
+ i = 0; |
|
| 353 |
+ res = r6; |
|
| 354 |
+ struct multi_context *m = *state; |
|
| 355 |
+ const unsigned long cid = 0; |
|
| 356 |
+ assert_int_equal(send_push_update(m, &cid, msg6, UPT_BY_CID, PUSH_BUNDLE_SIZE_TEST), 1); |
|
| 357 |
+} |
|
| 358 |
+ |
|
| 359 |
+static void |
|
| 360 |
+test_send_push_msg7(void **state) |
|
| 361 |
+{
|
|
| 362 |
+ i = 0; |
|
| 363 |
+ res = r7; |
|
| 364 |
+ struct multi_context *m = *state; |
|
| 365 |
+ const unsigned long cid = 0; |
|
| 366 |
+ assert_int_equal(send_push_update(m, &cid, msg7, UPT_BY_CID, PUSH_BUNDLE_SIZE_TEST), 1); |
|
| 367 |
+} |
|
| 368 |
+ |
|
| 369 |
+static void |
|
| 370 |
+test_send_push_msg8(void **state) |
|
| 371 |
+{
|
|
| 372 |
+ i = 0; |
|
| 373 |
+ res = r8; |
|
| 374 |
+ struct multi_context *m = *state; |
|
| 375 |
+ const unsigned long cid = 0; |
|
| 376 |
+ assert_int_equal(send_push_update(m, &cid, msg8, UPT_BY_CID, PUSH_BUNDLE_SIZE_TEST), 1); |
|
| 377 |
+} |
|
| 378 |
+ |
|
| 379 |
+static void |
|
| 380 |
+test_send_push_msg9(void **state) |
|
| 381 |
+{
|
|
| 382 |
+ i = 0; |
|
| 383 |
+ res = r9; |
|
| 384 |
+ struct multi_context *m = *state; |
|
| 385 |
+ const unsigned long cid = 0; |
|
| 386 |
+ assert_int_equal(send_push_update(m, &cid, msg9, UPT_BY_CID, PUSH_BUNDLE_SIZE_TEST), 1); |
|
| 387 |
+} |
|
| 388 |
+ |
|
| 389 |
+static void |
|
| 390 |
+test_send_push_msg10(void **state) |
|
| 391 |
+{
|
|
| 392 |
+ i = 0; |
|
| 393 |
+ res = NULL; |
|
| 394 |
+ struct multi_context *m = *state; |
|
| 395 |
+ const unsigned long cid = 0; |
|
| 396 |
+ assert_int_equal(send_push_update(m, &cid, msg10, UPT_BY_CID, PUSH_BUNDLE_SIZE_TEST), -EINVAL); |
|
| 397 |
+} |
|
| 398 |
+ |
|
| 399 |
+#undef PUSH_BUNDLE_SIZE_TEST |
|
| 400 |
+ |
|
| 401 |
+static int |
|
| 402 |
+setup2(void **state) |
|
| 403 |
+{
|
|
| 404 |
+ struct multi_context *m = calloc(1, sizeof(struct multi_context)); |
|
| 405 |
+ m->instances = calloc(1, sizeof(struct multi_instance *)); |
|
| 406 |
+ struct multi_instance *mi = calloc(1, sizeof(struct multi_instance)); |
|
| 407 |
+ *(m->instances) = mi; |
|
| 408 |
+ *state = m; |
|
| 409 |
+ return 0; |
|
| 410 |
+} |
|
| 411 |
+ |
|
| 412 |
+static int |
|
| 413 |
+teardown2(void **state) |
|
| 414 |
+{
|
|
| 415 |
+ struct multi_context *m = *state; |
|
| 416 |
+ free(*(m->instances)); |
|
| 417 |
+ free(m->instances); |
|
| 418 |
+ free(m); |
|
| 419 |
+ return 0; |
|
| 420 |
+} |
|
| 421 |
+#endif /* ifdef ENABLE_MANAGEMENT */ |
|
| 422 |
+ |
|
| 222 | 423 |
static int |
| 223 | 424 |
setup(void **state) |
| 224 | 425 |
{
|
| ... | ... |
@@ -249,7 +510,20 @@ main(void) |
| 249 | 249 |
cmocka_unit_test_setup_teardown(test_incoming_push_message_1, setup, teardown), |
| 250 | 250 |
cmocka_unit_test_setup_teardown(test_incoming_push_message_bad_format, setup, teardown), |
| 251 | 251 |
cmocka_unit_test_setup_teardown(test_incoming_push_message_mix, setup, teardown), |
| 252 |
- cmocka_unit_test_setup_teardown(test_incoming_push_message_mix2, setup, teardown) |
|
| 252 |
+ cmocka_unit_test_setup_teardown(test_incoming_push_message_mix2, setup, teardown), |
|
| 253 |
+#ifdef ENABLE_MANAGEMENT |
|
| 254 |
+ cmocka_unit_test_setup_teardown(test_send_push_msg0, setup2, teardown2), |
|
| 255 |
+ cmocka_unit_test_setup_teardown(test_send_push_msg1, setup2, teardown2), |
|
| 256 |
+ cmocka_unit_test_setup_teardown(test_send_push_msg2, setup2, teardown2), |
|
| 257 |
+ cmocka_unit_test_setup_teardown(test_send_push_msg3, setup2, teardown2), |
|
| 258 |
+ cmocka_unit_test_setup_teardown(test_send_push_msg4, setup2, teardown2), |
|
| 259 |
+ cmocka_unit_test_setup_teardown(test_send_push_msg5, setup2, teardown2), |
|
| 260 |
+ cmocka_unit_test_setup_teardown(test_send_push_msg6, setup2, teardown2), |
|
| 261 |
+ cmocka_unit_test_setup_teardown(test_send_push_msg7, setup2, teardown2), |
|
| 262 |
+ cmocka_unit_test_setup_teardown(test_send_push_msg8, setup2, teardown2), |
|
| 263 |
+ cmocka_unit_test_setup_teardown(test_send_push_msg9, setup2, teardown2), |
|
| 264 |
+ cmocka_unit_test_setup_teardown(test_send_push_msg10, setup2, teardown2) |
|
| 265 |
+#endif |
|
| 253 | 266 |
}; |
| 254 | 267 |
|
| 255 | 268 |
return cmocka_run_group_tests(tests, NULL, NULL); |