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, uint64_t permission_mask,
15 uint64_t *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
70forge_msg(const char *src, const char *continuation, struct gc_arena *gc)
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
103 while (*str)
104 {
105 /* + ',' - '/0' */
106 if (strlen(str) > safe_cap)
107 {
108 size_t ci = find_first_comma_of_next_bundle(str, safe_cap);
109 if (!ci)
110 {
111 /* if no commas were found go to fail, do not send any message */
112 return false;
113 }
114 /* copy from current position to (ci - 1) */
115 str[ci] = '\0';
116 struct buffer tmp = forge_msg(str, ",push-continuation 2", gc);
117 buffer_list_push(msgs, BSTR(&tmp));
118 str += ci + 1;
119 }
120 else
121 {
122 if (msgs->head)
123 {
124 struct buffer tmp = forge_msg(str, ",push-continuation 1", gc);
125 buffer_list_push(msgs, BSTR(&tmp));
126 }
127 else
128 {
129 struct buffer tmp = forge_msg(str, NULL, gc);
130 buffer_list_push(msgs, BSTR(&tmp));
131 }
132 break;
133 }
134 }
135 return true;
136}
137
138/* send the message(s) prepared to one single client */
139static bool
141{
142 if (!msgs->head)
143 {
144 return false;
145 }
146
147 uint64_t option_types_found = 0;
148 struct context *c = &mi->context;
149 struct options o;
150 CLEAR(o);
151
152 /* Set canary values to detect ifconfig options in push-update messages.
153 * These placeholder strings will be overwritten to NULL by the option
154 * parser if -ifconfig or -ifconfig-ipv6 options are present in the
155 * push-update.
156 */
157 const char *canary = "canary";
158 o.ifconfig_local = canary;
159 o.ifconfig_ipv6_local = canary;
160
161 struct buffer_entry *e = msgs->head;
162 while (e)
163 {
165 {
166 uninit_options(&o);
167 return false;
168 }
169
170 /* After sending the control message, we parse it, miming the behavior
171 * of `process_incoming_push_msg()` and we fill an empty `options` struct
172 * with the new options. If an `ifconfig_local` or `ifconfig_ipv6_local`
173 * options is found we update the vhash accordingly, so that the pushed
174 * ifconfig/ifconfig-ipv6 options can actually work.
175 * If we don't do that, packets arriving from the client with the
176 * new address will be rejected and packets for the new address
177 * will not be routed towards the client.
178 * Using `buf_string_compare_advance()` we mimic the behavior
179 * inside `process_incoming_push_msg()`. However, we don't need
180 * to check the return value here because we just want to `advance`,
181 * meaning we skip the `push_update_cmd' we added earlier.
182 * Also we need to make a temporary copy so we can buf_advance()
183 * without modifying original buffer.
184 */
185 struct buffer tmp_msg = e->buf;
187 uint64_t permission_mask = pull_permission_mask(c);
188 if (process_push_update(c, &o, permission_mask, &option_types_found, &tmp_msg, true) == PUSH_MSG_ERROR)
189 {
190 msg(M_WARN, "Failed to process push update message sent to client ID: %u", c->c2.tls_multi->rx_peer_id);
191 }
192 e = e->next;
193 }
194
195 if (option_types_found & OPT_P_UP)
196 {
197 /* -ifconfig */
199 {
200 unlearn_ifconfig(m, mi);
201 }
202 /* -ifconfig-ipv6 */
204 {
206 }
207
208 if (o.ifconfig_local && !strcmp(o.ifconfig_local, canary))
209 {
210 o.ifconfig_local = NULL;
211 }
212 if (o.ifconfig_ipv6_local && !strcmp(o.ifconfig_ipv6_local, canary))
213 {
214 o.ifconfig_ipv6_local = NULL;
215 }
216
217 /* new ifconfig or new ifconfig-ipv6 */
219 }
220
221 uninit_options(&o);
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);
231 if (!(iv_proto_peer & IV_PROTO_PUSH_UPDATE))
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->rx_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
320 for (uint32_t i = 0; i <= m->max_peerid; i++)
321 {
322 struct multi_instance *curr_mi = m->instances[i];
323
324 if (!curr_mi || curr_mi->halt || !support_push_update(curr_mi))
325 {
326 continue;
327 }
328
329 /* Type is UPT_BROADCAST so we update every client */
330 if (!send_single_push_update(m, curr_mi, msgs))
331 {
332 msg(M_CLIENT, "ERROR: Peer ID: %u has not been updated", curr_mi->context.c2.tls_multi->rx_peer_id);
333 continue;
334 }
335 count++;
336 }
337
338 buffer_list_free(msgs);
339 gc_free(&gc);
340 return count;
341}
342
343#define RETURN_UPDATE_STATUS(n_sent) \
344 do \
345 { \
346 if ((n_sent) > 0) \
347 { \
348 msg(M_CLIENT, "SUCCESS: %d client(s) updated", (n_sent)); \
349 return true; \
350 } \
351 else \
352 { \
353 msg(M_CLIENT, "ERROR: no client updated"); \
354 return false; \
355 } \
356 } while (0)
357
358bool
360{
361 int n_sent = send_push_update(arg, NULL, options, UPT_BROADCAST, PUSH_BUNDLE_SIZE);
362
363 RETURN_UPDATE_STATUS(n_sent);
364}
365
366bool
367management_callback_send_push_update_by_cid(void *arg, unsigned long cid, const char *options)
368{
369 int n_sent = send_push_update(arg, &cid, options, UPT_BY_CID, PUSH_BUNDLE_SIZE);
370
371 RETURN_UPDATE_STATUS(n_sent);
372}
373#endif /* ifdef ENABLE_MANAGEMENT */
bool buf_string_compare_advance(struct buffer *src, const char *match)
Compare the head of src with match and advance past it if equal.
Definition buffer.c:724
bool buf_printf(struct buffer *buf, const char *format,...)
printf-style append to a buffer with overflow check.
Definition buffer.c:226
struct buffer_list * buffer_list_new(void)
Allocate an empty buffer list of capacity max_size.
Definition buffer.c:1158
void buffer_list_free(struct buffer_list *ol)
Frees a buffer list and all the buffers in it.
Definition buffer.c:1167
void * gc_malloc(size_t size, bool clear, struct gc_arena *a)
Allocate memory and, optionally, zero it.
Definition buffer.c:313
struct buffer alloc_buf_gc(size_t size, struct gc_arena *gc)
Allocate a buffer of the given size under garbage collection.
Definition buffer.c:77
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:1198
Buffer management functions and garbage collection.
#define BSTR(buf)
Return the buffer content pointer cast to char *.
Definition buffer.h:157
static int buf_read_u8(struct buffer *buf)
Read and consume a uint8_t from the front of a buffer.
Definition buffer.h:1490
static void gc_free(struct gc_arena *a)
Free all allocations in a garbage collection arena.
Definition buffer.h:1965
static struct gc_arena gc_new(void)
Allocate and return a new, empty garbage collection arena.
Definition buffer.h:1949
#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:404
uint64_t pull_permission_mask(const struct context *c)
Definition init.c:2513
struct multi_instance * lookup_by_cid(struct multi_context *m, const unsigned long cid)
Definition multi.c:4032
void unlearn_ifconfig_ipv6(struct multi_context *m, struct multi_instance *mi)
Definition multi.c:4419
void unlearn_ifconfig(struct multi_context *m, struct multi_instance *mi)
Definition multi.c:4407
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:4441
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:221
#define M_WARN
Definition error.h:92
void uninit_options(struct options *o)
Definition options.c:911
#define OPT_P_UP
Definition options.h:734
static bool dco_enabled(const struct options *o)
Returns whether the current configuration has dco enabled.
Definition options.h:973
bool apply_push_options(struct context *c, struct options *options, struct buffer *buf, uint64_t permission_mask, uint64_t *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
int process_push_update(struct context *c, struct options *o, uint64_t permission_mask, uint64_t *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
static bool support_push_update(const struct multi_instance *mi)
Definition push_util.c:227
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:140
#define RETURN_UPDATE_STATUS(n_sent)
Definition push_util.c:343
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:367
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:359
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
SSL utility functions.
static 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.h:77
One node in a buffer_list linked list.
Definition buffer.h:2152
struct buffer_entry * next
Pointer to the next node, or NULL.
Definition buffer.h:2154
struct buffer buf
The buffer stored in this list node.
Definition buffer.h:2153
A singly-linked list of buffers, with head/tail pointers for O(1) push.
Definition buffer.h:2159
struct buffer_entry * head
Next item to pop/peek.
Definition buffer.h:2160
Wrapper structure for dynamically allocated memory.
Definition buffer.h:71
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:324
Contains all state information for one tunnel.
Definition openvpn.h:471
struct context_2 c2
Level 2 context.
Definition openvpn.h:516
struct options options
Options loaded from command line or configuration file.
Definition openvpn.h:472
Garbage collection arena used to keep track of dynamically allocated memory.
Definition buffer.h:127
Main OpenVPN server state structure.
Definition multi.h:170
uint32_t max_peerid
highest currently allocated peer-id and maximum allocated/valid index in instances
Definition multi.h:174
struct context top
Storage structure for process-wide configuration.
Definition multi.h:217
struct multi_instance ** instances
Array of multi_instances with the size of max_clients.
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:150
const char * ifconfig_ipv6_local
Definition options.h:329
const char * ifconfig_local
Definition options.h:327
int push_continuation
Definition options.h:558
char * peer_info
A multi-line string of general-purpose info received from peer over control channel.
Definition ssl_common.h:677
uint32_t rx_peer_id
Definition ssl_common.h:704
#define SIGUSR1
Definition syshead.h:57
struct gc_arena gc
Definition test_ssl.c:122