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
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 {
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);
118 str += ci + 1;
119 }
120 else
121 {
122 if (msgs->head)
123 {
124 struct buffer tmp = forge_msg(str, ",push-continuation 1", gc);
126 }
127 else
128 {
129 struct buffer tmp = forge_msg(str, NULL, gc);
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 return false;
167 }
168
169 /* After sending the control message, we parse it, miming the behavior
170 * of `process_incoming_push_msg()` and we fill an empty `options` struct
171 * with the new options. If an `ifconfig_local` or `ifconfig_ipv6_local`
172 * options is found we update the vhash accordingly, so that the pushed
173 * ifconfig/ifconfig-ipv6 options can actually work.
174 * If we don't do that, packets arriving from the client with the
175 * new address will be rejected and packets for the new address
176 * will not be routed towards the client.
177 * Using `buf_string_compare_advance()` we mimic the behavior
178 * inside `process_incoming_push_msg()`. However, we don't need
179 * to check the return value here because we just want to `advance`,
180 * meaning we skip the `push_update_cmd' we added earlier.
181 * Also we need to make a temporary copy so we can buf_advance()
182 * without modifying original buffer.
183 */
184 struct buffer tmp_msg = e->buf;
187 if (process_push_update(c, &o, permission_mask, &option_types_found, &tmp_msg, true) == PUSH_MSG_ERROR)
188 {
189 msg(M_WARN, "Failed to process push update message sent to client ID: %u", c->c2.tls_multi->rx_peer_id);
190 }
191 e = e->next;
192 }
193
194 if (option_types_found & OPT_P_UP)
195 {
196 /* -ifconfig */
197 if (!o.ifconfig_local && mi->context.c2.push_ifconfig_defined)
198 {
199 unlearn_ifconfig(m, mi);
200 }
201 /* -ifconfig-ipv6 */
202 if (!o.ifconfig_ipv6_local && mi->context.c2.push_ifconfig_ipv6_defined)
203 {
205 }
206
207 if (o.ifconfig_local && !strcmp(o.ifconfig_local, canary))
208 {
209 o.ifconfig_local = NULL;
210 }
211 if (o.ifconfig_ipv6_local && !strcmp(o.ifconfig_ipv6_local, canary))
212 {
213 o.ifconfig_ipv6_local = NULL;
214 }
215
216 /* new ifconfig or new ifconfig-ipv6 */
217 update_vhash(m, mi, o.ifconfig_local, o.ifconfig_ipv6_local);
218 }
219
220 return true;
221}
222
223/* Return true if the client supports push-update */
224static bool
226{
228 const unsigned int iv_proto_peer = extract_iv_proto(mi->context.c2.tls_multi->peer_info);
230 {
231 return false;
232 }
233
234 return true;
235}
236
251static int
252send_push_update(struct multi_context *m, const void *target, const char *msg, const push_update_type type, const size_t push_bundle_size)
253{
254 if (dco_enabled(&m->top.options))
255 {
256 msg(M_WARN, "WARN: PUSH_UPDATE messages cannot currently be sent while DCO is enabled."
257 " To send a PUSH_UPDATE message, be sure to use the --disable-dco option.");
258 return 0;
259 }
260
261 if (!msg || !*msg || !m || (!target && type != UPT_BROADCAST))
262 {
263 return -EINVAL;
264 }
265
266 struct gc_arena gc = gc_new();
267 /* extra space for possible trailing ifconfig and push-continuation */
268 const size_t extra = 84 + sizeof(push_update_cmd);
269 /* push_bundle_size is the maximum size of a message, so if the message
270 * we want to send exceeds that size we have to split it into smaller messages */
271 ASSERT(push_bundle_size > extra);
272 const size_t safe_cap = push_bundle_size - extra;
273 struct buffer_list *msgs = buffer_list_new();
274
275 if (!message_splitter(msg, msgs, &gc, safe_cap))
276 {
277 buffer_list_free(msgs);
278 gc_free(&gc);
279 return -EINVAL;
280 }
281
282 if (type == UPT_BY_CID)
283 {
284 struct multi_instance *mi = lookup_by_cid(m, *((unsigned long *)target));
285
286 if (!mi)
287 {
288 buffer_list_free(msgs);
289 gc_free(&gc);
290 return -ENOENT;
291 }
292
293 if (!support_push_update(mi))
294 {
295 msg(M_CLIENT, "PUSH_UPDATE: not sending message to unsupported peer with ID: %u", mi->context.c2.tls_multi->rx_peer_id);
296 buffer_list_free(msgs);
297 gc_free(&gc);
298 return 0;
299 }
300
301 if (!mi->halt
302 && send_single_push_update(m, mi, msgs))
303 {
304 buffer_list_free(msgs);
305 gc_free(&gc);
306 return 1;
307 }
308 else
309 {
310 buffer_list_free(msgs);
311 gc_free(&gc);
312 return 0;
313 }
314 }
315
316 int count = 0;
317
318 for (uint32_t i = 0; i <= m->max_peerid; i++)
319 {
320 struct multi_instance *curr_mi = m->instances[i];
321
322 if (!curr_mi || curr_mi->halt || !support_push_update(curr_mi))
323 {
324 continue;
325 }
326
327 /* Type is UPT_BROADCAST so we update every client */
328 if (!send_single_push_update(m, curr_mi, msgs))
329 {
330 msg(M_CLIENT, "ERROR: Peer ID: %u has not been updated", curr_mi->context.c2.tls_multi->rx_peer_id);
331 continue;
332 }
333 count++;
334 }
335
336 buffer_list_free(msgs);
337 gc_free(&gc);
338 return count;
339}
340
341#define RETURN_UPDATE_STATUS(n_sent) \
342 do \
343 { \
344 if ((n_sent) > 0) \
345 { \
346 msg(M_CLIENT, "SUCCESS: %d client(s) updated", (n_sent)); \
347 return true; \
348 } \
349 else \
350 { \
351 msg(M_CLIENT, "ERROR: no client updated"); \
352 return false; \
353 } \
354 } while (0)
355
356bool
358{
359 int n_sent = send_push_update(arg, NULL, options, UPT_BROADCAST, PUSH_BUNDLE_SIZE);
360
361 RETURN_UPDATE_STATUS(n_sent);
362}
363
364bool
365management_callback_send_push_update_by_cid(void *arg, unsigned long cid, const char *options)
366{
367 int n_sent = send_push_update(arg, &cid, options, UPT_BY_CID, PUSH_BUNDLE_SIZE);
368
369 RETURN_UPDATE_STATUS(n_sent);
370}
371#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:739
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:1156
void buffer_list_free(struct buffer_list *ol)
Frees a buffer list and all the buffers in it.
Definition buffer.c:1165
void * gc_malloc(size_t size, bool clear, struct gc_arena *a)
Allocate memory and, optionally, zero it.
Definition buffer.c:318
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:1196
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:1511
static void gc_free(struct gc_arena *a)
Free all allocations in a garbage collection arena.
Definition buffer.h:1974
static struct gc_arena gc_new(void)
Allocate and return a new, empty garbage collection arena.
Definition buffer.h:1958
#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
uint64_t pull_permission_mask(const struct context *c)
Definition init.c:2512
struct multi_instance * lookup_by_cid(struct multi_context *m, const unsigned long cid)
Definition multi.c:3987
void unlearn_ifconfig_ipv6(struct multi_context *m, struct multi_instance *mi)
Definition multi.c:4373
void unlearn_ifconfig(struct multi_context *m, struct multi_instance *mi)
Definition multi.c:4361
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:4395
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:961
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 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
static bool support_push_update(struct multi_instance *mi)
Definition push_util.c:225
#define RETURN_UPDATE_STATUS(n_sent)
Definition push_util.c:341
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:252
bool management_callback_send_push_update_by_cid(void *arg, unsigned long cid, const char *options)
Definition push_util.c:365
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:357
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:2161
struct buffer buf
The buffer stored in this list node.
Definition buffer.h:2162
A singly-linked list of buffers, with head/tail pointers for O(1) push.
Definition buffer.h:2168
struct buffer_entry * head
Next item to pop/peek.
Definition buffer.h:2169
Wrapper structure for dynamically allocated memory.
Definition buffer.h:71
int len
Length in bytes of the actual content within the allocated memory.
Definition buffer.h:76
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:514
Garbage collection arena used to keep track of dynamically allocated memory.
Definition buffer.h:127
Main OpenVPN server state structure.
Definition multi.h:162
uint32_t max_peerid
highest currently allocated peer-id and maximum allocated/valid index in instances
Definition multi.h:166
struct multi_instance ** instances
Array of multi_instances with the size of max_clients.
Definition multi.h:163
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:142
const char * ifconfig_ipv6_local
Definition options.h:329
const char * ifconfig_local
Definition options.h:327
int push_continuation
Definition options.h:557
char * peer_info
A multi-line string of general-purpose info received from peer over control channel.
Definition ssl_common.h:672
uint32_t rx_peer_id
Definition ssl_common.h:699
#define SIGUSR1
Definition syshead.h:57
struct gc_arena gc
Definition test_ssl.c:122