OpenVPN
push_util.c
Go to the documentation of this file.
1#ifdef HAVE_CONFIG_H
2#include "config.h"
3#endif
4
5#include "push.h"
6#include "buffer.h"
7
8#ifdef ENABLE_MANAGEMENT
9#include "multi.h"
10#include "ssl_util.h"
11#endif
12
13int
14process_push_update(struct context *c, struct options *o, unsigned int permission_mask,
15 unsigned int *option_types_found, struct buffer *buf, bool msg_sender)
16{
17 int ret = PUSH_MSG_ERROR;
18 const int ch = buf_read_u8(buf);
19 if (ch == ',')
20 {
21 if (apply_push_options(c, o, buf, permission_mask, option_types_found, c->c2.es,
22 true))
23 {
24 switch (o->push_continuation)
25 {
26 case 0:
27 case 1:
28 ret = PUSH_MSG_UPDATE;
29 break;
30
31 case 2:
33 break;
34 }
35 }
36 else if (!msg_sender)
37 {
38 throw_signal_soft(SIGUSR1, "Offending option received from server");
39 }
40 }
41 else if (ch == '\0')
42 {
43 ret = PUSH_MSG_UPDATE;
44 }
45
46 return ret;
47}
48
49#ifdef ENABLE_MANAGEMENT
54static size_t
55find_first_comma_of_next_bundle(const char *str, size_t ix)
56{
57 while (ix > 0)
58 {
59 if (str[ix] == ',')
60 {
61 return ix;
62 }
63 ix--;
64 }
65 return 0;
66}
67
68/* Allocate memory and assemble the final message */
69static struct buffer
71{
72 size_t src_len = strlen(src);
73 size_t con_len = continuation ? strlen(continuation) : 0;
74 struct buffer buf = alloc_buf_gc(src_len + sizeof(push_update_cmd) + con_len + 2, gc);
75
76 buf_printf(&buf, "%s,%s%s", push_update_cmd, src, continuation ? continuation : "");
77
78 return buf;
79}
80
81static char *
82gc_strdup(const char *src, struct gc_arena *gc)
83{
84 char *ret = gc_malloc((strlen(src) + 1) * sizeof(char), true, gc);
85
86 strcpy(ret, src);
87 return ret;
88}
89
90/* It split the messagge (if necessary) and fill msgs with the message chunks.
91 * Return `false` on failure an `true` on success.
92 */
93static bool
94message_splitter(const char *s, struct buffer_list *msgs, struct gc_arena *gc, const size_t safe_cap)
95{
96 if (!s || !*s)
97 {
98 return false;
99 }
100
101 char *str = gc_strdup(s, gc);
102 size_t i = 0;
103
104 while (*str)
105 {
106 /* + ',' - '/0' */
107 if (strlen(str) > safe_cap)
108 {
110 if (!ci)
111 {
112 /* if no commas were found go to fail, do not send any message */
113 return false;
114 }
115 str[ci] = '\0';
116 /* copy from i to (ci -1) */
117 struct buffer tmp = forge_msg(str, ",push-continuation 2", gc);
119 i = ci + 1;
120 }
121 else
122 {
123 if (msgs->head)
124 {
125 struct buffer tmp = forge_msg(str, ",push-continuation 1", gc);
127 }
128 else
129 {
130 struct buffer tmp = forge_msg(str, NULL, gc);
132 }
133 i = strlen(str);
134 }
135 str = &str[i];
136 }
137 return true;
138}
139
140/* send the message(s) prepared to one single client */
141static bool
143{
144 if (!msgs->head)
145 {
146 return false;
147 }
148
149 unsigned int option_types_found = 0;
150 struct context *c = &mi->context;
151 struct options o;
152 CLEAR(o);
153
154 /* Set canary values to detect ifconfig options in push-update messages.
155 * These placeholder strings will be overwritten to NULL by the option
156 * parser if -ifconfig or -ifconfig-ipv6 options are present in the
157 * push-update.
158 */
159 const char *canary = "canary";
160 o.ifconfig_local = canary;
161 o.ifconfig_ipv6_local = canary;
162
163 struct buffer_entry *e = msgs->head;
164 while (e)
165 {
167 {
168 return false;
169 }
170
171 /* After sending the control message, we parse it, miming the behavior
172 * of `process_incoming_push_msg()` and we fill an empty `options` struct
173 * with the new options. If an `ifconfig_local` or `ifconfig_ipv6_local`
174 * options is found we update the vhash accordingly, so that the pushed
175 * ifconfig/ifconfig-ipv6 options can actually work.
176 * If we don't do that, packets arriving from the client with the
177 * new address will be rejected and packets for the new address
178 * will not be routed towards the client.
179 * Using `buf_string_compare_advance()` we mimic the behavior
180 * inside `process_incoming_push_msg()`. However, we don't need
181 * to check the return value here because we just want to `advance`,
182 * meaning we skip the `push_update_cmd' we added earlier.
183 * Also we need to make a temporary copy so we can buf_advance()
184 * without modifying original buffer.
185 */
186 struct buffer tmp_msg = e->buf;
188 unsigned int permission_mask = pull_permission_mask(c);
189 if (process_push_update(c, &o, permission_mask, &option_types_found, &tmp_msg, true) == PUSH_MSG_ERROR)
190 {
191 msg(M_WARN, "Failed to process push update message sent to client ID: %u", c->c2.tls_multi->peer_id);
192 }
193 e = e->next;
194 }
195
196 if (option_types_found & OPT_P_UP)
197 {
198 /* -ifconfig */
199 if (!o.ifconfig_local && mi->context.c2.push_ifconfig_defined)
200 {
201 unlearn_ifconfig(m, mi);
202 }
203 /* -ifconfig-ipv6 */
204 if (!o.ifconfig_ipv6_local && mi->context.c2.push_ifconfig_ipv6_defined)
205 {
207 }
208
209 if (o.ifconfig_local && !strcmp(o.ifconfig_local, canary))
210 {
211 o.ifconfig_local = NULL;
212 }
213 if (o.ifconfig_ipv6_local && !strcmp(o.ifconfig_ipv6_local, canary))
214 {
215 o.ifconfig_ipv6_local = NULL;
216 }
217
218 /* new ifconfig or new ifconfig-ipv6 */
219 update_vhash(m, mi, o.ifconfig_local, o.ifconfig_ipv6_local);
220 }
221
222 return true;
223}
224
225/* Return true if the client supports push-update */
226static bool
228{
230 const unsigned int iv_proto_peer = extract_iv_proto(mi->context.c2.tls_multi->peer_info);
232 {
233 return false;
234 }
235
236 return true;
237}
238
253static int
254send_push_update(struct multi_context *m, const void *target, const char *msg, const push_update_type type, const size_t push_bundle_size)
255{
256 if (dco_enabled(&m->top.options))
257 {
258 msg(M_WARN, "WARN: PUSH_UPDATE messages cannot currently be sent while DCO is enabled."
259 " To send a PUSH_UPDATE message, be sure to use the --disable-dco option.");
260 return 0;
261 }
262
263 if (!msg || !*msg || !m || (!target && type != UPT_BROADCAST))
264 {
265 return -EINVAL;
266 }
267
268 struct gc_arena gc = gc_new();
269 /* extra space for possible trailing ifconfig and push-continuation */
270 const size_t extra = 84 + sizeof(push_update_cmd);
271 /* push_bundle_size is the maximum size of a message, so if the message
272 * we want to send exceeds that size we have to split it into smaller messages */
273 ASSERT(push_bundle_size > extra);
274 const size_t safe_cap = push_bundle_size - extra;
275 struct buffer_list *msgs = buffer_list_new();
276
277 if (!message_splitter(msg, msgs, &gc, safe_cap))
278 {
279 buffer_list_free(msgs);
280 gc_free(&gc);
281 return -EINVAL;
282 }
283
284 if (type == UPT_BY_CID)
285 {
286 struct multi_instance *mi = lookup_by_cid(m, *((unsigned long *)target));
287
288 if (!mi)
289 {
290 buffer_list_free(msgs);
291 gc_free(&gc);
292 return -ENOENT;
293 }
294
295 if (!support_push_update(mi))
296 {
297 msg(M_CLIENT, "PUSH_UPDATE: not sending message to unsupported peer with ID: %u", mi->context.c2.tls_multi->peer_id);
298 buffer_list_free(msgs);
299 gc_free(&gc);
300 return 0;
301 }
302
303 if (!mi->halt
304 && send_single_push_update(m, mi, msgs))
305 {
306 buffer_list_free(msgs);
307 gc_free(&gc);
308 return 1;
309 }
310 else
311 {
312 buffer_list_free(msgs);
313 gc_free(&gc);
314 return 0;
315 }
316 }
317
318 int count = 0;
319 struct hash_iterator hi;
320 const struct hash_element *he;
321
322 hash_iterator_init(m->iter, &hi);
323 while ((he = hash_iterator_next(&hi)))
324 {
325 struct multi_instance *curr_mi = he->value;
326
327 if (curr_mi->halt || !support_push_update(curr_mi))
328 {
329 continue;
330 }
331
332 /* Type is UPT_BROADCAST so we update every client */
333 if (!send_single_push_update(m, curr_mi, msgs))
334 {
335 msg(M_CLIENT, "ERROR: Peer ID: %u has not been updated", curr_mi->context.c2.tls_multi->peer_id);
336 continue;
337 }
338 count++;
339 }
340
342 buffer_list_free(msgs);
343 gc_free(&gc);
344 return count;
345}
346
347#define RETURN_UPDATE_STATUS(n_sent) \
348 do \
349 { \
350 if ((n_sent) > 0) \
351 { \
352 msg(M_CLIENT, "SUCCESS: %d client(s) updated", (n_sent)); \
353 return true; \
354 } \
355 else \
356 { \
357 msg(M_CLIENT, "ERROR: no client updated"); \
358 return false; \
359 } \
360 } while (0)
361
362bool
364{
365 int n_sent = send_push_update(arg, NULL, options, UPT_BROADCAST, PUSH_BUNDLE_SIZE);
366
367 RETURN_UPDATE_STATUS(n_sent);
368}
369
370bool
371management_callback_send_push_update_by_cid(void *arg, unsigned long cid, const char *options)
372{
373 int n_sent = send_push_update(arg, &cid, options, UPT_BY_CID, PUSH_BUNDLE_SIZE);
374
375 RETURN_UPDATE_STATUS(n_sent);
376}
377#endif /* ifdef ENABLE_MANAGEMENT */
bool buf_string_compare_advance(struct buffer *src, const char *match)
Definition buffer.c:788
bool buf_printf(struct buffer *buf, const char *format,...)
Definition buffer.c:241
struct buffer_list * buffer_list_new(void)
Allocate an empty buffer list of capacity max_size.
Definition buffer.c:1153
void buffer_list_free(struct buffer_list *ol)
Frees a buffer list and all the buffers in it.
Definition buffer.c:1162
void * gc_malloc(size_t size, bool clear, struct gc_arena *a)
Definition buffer.c:336
struct buffer alloc_buf_gc(size_t size, struct gc_arena *gc)
Definition buffer.c:89
void buffer_list_push(struct buffer_list *ol, const char *str)
Allocates and appends a new buffer containing str as data to ol.
Definition buffer.c:1193
#define BSTR(buf)
Definition buffer.h:128
static int buf_read_u8(struct buffer *buf)
Definition buffer.h:786
static void gc_free(struct gc_arena *a)
Definition buffer.h:1025
static struct gc_arena gc_new(void)
Definition buffer.h:1017
#define PUSH_BUNDLE_SIZE
Definition common.h:89
#define D_PUSH
Definition errlevel.h:82
bool send_control_channel_string(struct context *c, const char *str, msglvl_t msglevel)
Definition forward.c:398
unsigned int pull_permission_mask(const struct context *c)
Definition init.c:2520
void hash_iterator_free(struct hash_iterator *hi)
Definition list.c:270
struct hash_element * hash_iterator_next(struct hash_iterator *hi)
Definition list.c:276
void hash_iterator_init(struct hash *hash, struct hash_iterator *hi)
Definition list.c:234
struct multi_instance * lookup_by_cid(struct multi_context *m, const unsigned long cid)
Definition multi.c:3978
void unlearn_ifconfig_ipv6(struct multi_context *m, struct multi_instance *mi)
Definition multi.c:4346
void unlearn_ifconfig(struct multi_context *m, struct multi_instance *mi)
Definition multi.c:4334
void update_vhash(struct multi_context *m, struct multi_instance *mi, const char *new_ip, const char *new_ipv6)
Update the vhash with new IP/IPv6 addresses in the multi_context when a push-update message containin...
Definition multi.c:4368
Header file for server-mode related structures and functions.
#define CLEAR(x)
Definition basic.h:32
#define M_CLIENT
Definition error.h:108
#define msg(flags,...)
Definition error.h:152
#define ASSERT(x)
Definition error.h:219
#define M_WARN
Definition error.h:92
#define OPT_P_UP
Definition options.h:732
static bool dco_enabled(const struct options *o)
Returns whether the current configuration has dco enabled.
Definition options.h:992
bool apply_push_options(struct context *c, struct options *options, struct buffer *buf, unsigned int permission_mask, unsigned int *option_types_found, struct env_set *es, bool is_update)
push_update_type
Definition push.h:47
@ UPT_BY_CID
Definition push.h:49
@ UPT_BROADCAST
Definition push.h:48
#define PUSH_MSG_ERROR
Definition push.h:28
#define PUSH_MSG_UPDATE
Definition push.h:35
#define push_update_cmd
Definition push.h:38
#define PUSH_MSG_CONTINUATION
Definition push.h:33
static bool message_splitter(const char *s, struct buffer_list *msgs, struct gc_arena *gc, const size_t safe_cap)
Definition push_util.c:94
static struct buffer forge_msg(const char *src, const char *continuation, struct gc_arena *gc)
Definition push_util.c:70
static bool send_single_push_update(struct multi_context *m, struct multi_instance *mi, struct buffer_list *msgs)
Definition push_util.c:142
static bool support_push_update(struct multi_instance *mi)
Definition push_util.c:227
int process_push_update(struct context *c, struct options *o, unsigned int permission_mask, unsigned int *option_types_found, struct buffer *buf, bool msg_sender)
Handles the receiving of a push-update message and applies updates to the specified options.
Definition push_util.c:14
#define RETURN_UPDATE_STATUS(n_sent)
Definition push_util.c:347
static int send_push_update(struct multi_context *m, const void *target, const char *msg, const push_update_type type, const size_t push_bundle_size)
A function to send a PUSH_UPDATE control message from server to client(s).
Definition push_util.c:254
bool management_callback_send_push_update_by_cid(void *arg, unsigned long cid, const char *options)
Definition push_util.c:371
static size_t find_first_comma_of_next_bundle(const char *str, size_t ix)
Return index of last , or 0 if it didn't find any.
Definition push_util.c:55
bool management_callback_send_push_update_broadcast(void *arg, const char *options)
Definition push_util.c:363
static char * gc_strdup(const char *src, struct gc_arena *gc)
Definition push_util.c:82
void throw_signal_soft(const int signum, const char *signal_text)
Throw a soft global signal.
Definition sig.c:204
#define IV_PROTO_PUSH_UPDATE
Supports push-update.
Definition ssl.h:117
unsigned int extract_iv_proto(const char *peer_info)
Extracts the IV_PROTO variable and returns its value or 0 if it cannot be extracted.
Definition ssl_util.c:60
SSL utility functions.
Definition buffer.h:1119
struct buffer buf
Definition buffer.h:1120
struct buffer_entry * head
Definition buffer.h:1126
Wrapper structure for dynamically allocated memory.
Definition buffer.h:60
int len
Length in bytes of the actual content within the allocated memory.
Definition buffer.h:65
bool push_ifconfig_ipv6_defined
Definition openvpn.h:431
bool push_ifconfig_defined
Definition openvpn.h:425
struct env_set * es
Definition openvpn.h:420
struct tls_multi * tls_multi
TLS state structure for this VPN tunnel.
Definition openvpn.h:323
Contains all state information for one tunnel.
Definition openvpn.h:471
struct context_2 c2
Level 2 context.
Definition openvpn.h:514
Garbage collection arena used to keep track of dynamically allocated memory.
Definition buffer.h:116
void * value
Definition list.h:41
Main OpenVPN server state structure.
Definition multi.h:163
struct hash * iter
VPN tunnel instances indexed by real address of the remote peer, optimized for iteration.
Definition multi.h:171
Server-mode state structure for one single VPN tunnel.
Definition multi.h:102
struct context context
The context structure storing state for this VPN tunnel.
Definition multi.h:143
const char * ifconfig_ipv6_local
Definition options.h:328
const char * ifconfig_local
Definition options.h:326
int push_continuation
Definition options.h:556
char * peer_info
A multi-line string of general-purpose info received from peer over control channel.
Definition ssl_common.h:674
uint32_t peer_id
Definition ssl_common.h:701
#define SIGUSR1
Definition syshead.h:57
struct gc_arena gc
Definition test_ssl.c:131