OpenVPN
occ.c
Go to the documentation of this file.
1/*
2 * OpenVPN -- An application to securely tunnel IP networks
3 * over a single TCP/UDP port, with support for SSL/TLS-based
4 * session authentication and key exchange,
5 * packet encryption, packet authentication, and
6 * packet compression.
7 *
8 * Copyright (C) 2002-2025 OpenVPN Inc <sales@openvpn.net>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2
12 * as published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, see <https://www.gnu.org/licenses/>.
21 */
22
23#ifdef HAVE_CONFIG_H
24#include "config.h"
25#endif
26
27#include "syshead.h"
28
29#include "occ.h"
30#include "forward.h"
31#include "memdbg.h"
32
33
34/*
35 * This random string identifies an OpenVPN
36 * Configuration Control packet.
37 * It should be of sufficient length and randomness
38 * so as not to collide with other tunnel data.
39 *
40 * The OCC protocol is as follows:
41 *
42 * occ_magic -- (16 octets)
43 *
44 * type [OCC_REQUEST | OCC_REPLY] (1 octet)
45 * null terminated options string if OCC_REPLY (variable)
46 *
47 * When encryption is used, the OCC packet
48 * is encapsulated within the encrypted
49 * envelope.
50 *
51 * OCC_STRING_SIZE must be set to sizeof (occ_magic)
52 */
53
54const uint8_t occ_magic[] = { 0x28, 0x7f, 0x34, 0x6b, 0xd4, 0xef, 0x7a, 0x81,
55 0x2d, 0x56, 0xb8, 0xd3, 0xaf, 0xc5, 0x45, 0x9c };
56
57static const struct mtu_load_test mtu_load_test_sequence[] = {
58
59 { OCC_MTU_LOAD_REQUEST, -1000 },
60 { OCC_MTU_LOAD, -1000 },
61 { OCC_MTU_LOAD_REQUEST, -1000 },
62 { OCC_MTU_LOAD, -1000 },
63 { OCC_MTU_LOAD_REQUEST, -1000 },
64 { OCC_MTU_LOAD, -1000 },
65
66 { OCC_MTU_LOAD_REQUEST, -750 },
67 { OCC_MTU_LOAD, -750 },
68 { OCC_MTU_LOAD_REQUEST, -750 },
69 { OCC_MTU_LOAD, -750 },
70 { OCC_MTU_LOAD_REQUEST, -750 },
71 { OCC_MTU_LOAD, -750 },
72
73 { OCC_MTU_LOAD_REQUEST, -500 },
74 { OCC_MTU_LOAD, -500 },
75 { OCC_MTU_LOAD_REQUEST, -500 },
76 { OCC_MTU_LOAD, -500 },
77 { OCC_MTU_LOAD_REQUEST, -500 },
78 { OCC_MTU_LOAD, -500 },
79
80 { OCC_MTU_LOAD_REQUEST, -400 },
81 { OCC_MTU_LOAD, -400 },
82 { OCC_MTU_LOAD_REQUEST, -400 },
83 { OCC_MTU_LOAD, -400 },
84 { OCC_MTU_LOAD_REQUEST, -400 },
85 { OCC_MTU_LOAD, -400 },
86
87 { OCC_MTU_LOAD_REQUEST, -300 },
88 { OCC_MTU_LOAD, -300 },
89 { OCC_MTU_LOAD_REQUEST, -300 },
90 { OCC_MTU_LOAD, -300 },
91 { OCC_MTU_LOAD_REQUEST, -300 },
92 { OCC_MTU_LOAD, -300 },
93
94 { OCC_MTU_LOAD_REQUEST, -200 },
95 { OCC_MTU_LOAD, -200 },
96 { OCC_MTU_LOAD_REQUEST, -200 },
97 { OCC_MTU_LOAD, -200 },
98 { OCC_MTU_LOAD_REQUEST, -200 },
99 { OCC_MTU_LOAD, -200 },
100
101 { OCC_MTU_LOAD_REQUEST, -150 },
102 { OCC_MTU_LOAD, -150 },
103 { OCC_MTU_LOAD_REQUEST, -150 },
104 { OCC_MTU_LOAD, -150 },
105 { OCC_MTU_LOAD_REQUEST, -150 },
106 { OCC_MTU_LOAD, -150 },
107
108 { OCC_MTU_LOAD_REQUEST, -100 },
109 { OCC_MTU_LOAD, -100 },
110 { OCC_MTU_LOAD_REQUEST, -100 },
111 { OCC_MTU_LOAD, -100 },
112 { OCC_MTU_LOAD_REQUEST, -100 },
113 { OCC_MTU_LOAD, -100 },
114
115 { OCC_MTU_LOAD_REQUEST, -50 },
116 { OCC_MTU_LOAD, -50 },
117 { OCC_MTU_LOAD_REQUEST, -50 },
118 { OCC_MTU_LOAD, -50 },
119 { OCC_MTU_LOAD_REQUEST, -50 },
120 { OCC_MTU_LOAD, -50 },
121
123 { OCC_MTU_LOAD, 0 },
125 { OCC_MTU_LOAD, 0 },
127 { OCC_MTU_LOAD, 0 },
128
129 { OCC_MTU_REQUEST, 0 },
130 { OCC_MTU_REQUEST, 0 },
131 { OCC_MTU_REQUEST, 0 },
132 { OCC_MTU_REQUEST, 0 },
133 { OCC_MTU_REQUEST, 0 },
134 { OCC_MTU_REQUEST, 0 },
135 { OCC_MTU_REQUEST, 0 },
136 { OCC_MTU_REQUEST, 0 },
137 { OCC_MTU_REQUEST, 0 },
138 { OCC_MTU_REQUEST, 0 },
139
140 { -1, 0 }
141};
142
143void
145{
146 if (++c->c2.occ_n_tries >= OCC_N_TRIES)
147 {
148 if (c->options.ce.remote)
149 {
150 /*
151 * No OCC_REPLY from peer after repeated attempts.
152 * Give up.
153 */
155 "NOTE: failed to obtain options consistency info from peer -- "
156 "this could occur if the remote peer is running a version of " PACKAGE_NAME
157 " before 1.5-beta8 or if there is a network connectivity problem, and will not necessarily prevent " PACKAGE_NAME
158 " from running (" counter_format " bytes received from peer, " counter_format
159 " bytes authenticated data channel traffic) -- you can disable the options consistency "
160 "check with --disable-occ.",
162 }
164 }
165 else
166 {
167 c->c2.occ_op = OCC_REQUEST;
168
169 /*
170 * If we don't hear back from peer, send another
171 * OCC_REQUEST in OCC_INTERVAL_SECONDS.
172 */
174 }
175}
176
177#if defined(__GNUC__) || defined(__clang__)
178#pragma GCC diagnostic push
179#pragma GCC diagnostic ignored "-Wconversion"
180#endif
181
182void
184{
186 {
187 const struct mtu_load_test *entry;
188
189 if (!c->c2.occ_mtu_load_n_tries)
190 {
191 msg(M_INFO,
192 "NOTE: Beginning empirical MTU test -- results should be available in 3 to 4 minutes.");
193 }
194
196 if (entry->op >= 0)
197 {
198 c->c2.occ_op = entry->op;
199 size_t payload_size =
201 size_t header_size =
203
204 c->c2.occ_mtu_load_size = payload_size + header_size;
205 }
206 else
207 {
208 msg(M_INFO, "NOTE: failed to empirically measure MTU (requires " PACKAGE_NAME
209 " 1.5 or higher at other end of connection).");
212 }
213 }
214}
215
216void
218{
219 bool doit = false;
220
221 c->c2.buf = c->c2.buffers->aux_buf;
225
226 switch (c->c2.occ_op)
227 {
228 case OCC_REQUEST:
229 if (!buf_write_u8(&c->c2.buf, OCC_REQUEST))
230 {
231 break;
232 }
233 dmsg(D_PACKET_CONTENT, "SENT OCC_REQUEST");
234 doit = true;
235 break;
236
237 case OCC_REPLY:
238 if (!c->c2.options_string_local)
239 {
240 break;
241 }
242 if (!buf_write_u8(&c->c2.buf, OCC_REPLY))
243 {
244 break;
245 }
247 strlen(c->c2.options_string_local) + 1))
248 {
249 break;
250 }
251 dmsg(D_PACKET_CONTENT, "SENT OCC_REPLY");
252 doit = true;
253 break;
254
255 case OCC_MTU_REQUEST:
257 {
258 break;
259 }
260 dmsg(D_PACKET_CONTENT, "SENT OCC_MTU_REQUEST");
261 doit = true;
262 break;
263
264 case OCC_MTU_REPLY:
265 if (!buf_write_u8(&c->c2.buf, OCC_MTU_REPLY))
266 {
267 break;
268 }
270 {
271 break;
272 }
274 {
275 break;
276 }
277 dmsg(D_PACKET_CONTENT, "SENT OCC_MTU_REPLY");
278 doit = true;
279 break;
280
283 {
284 break;
285 }
287 {
288 break;
289 }
290 dmsg(D_PACKET_CONTENT, "SENT OCC_MTU_LOAD_REQUEST");
291 doit = true;
292 break;
293
294 case OCC_MTU_LOAD:
295 {
296 int need_to_add;
297
298 if (!buf_write_u8(&c->c2.buf, OCC_MTU_LOAD))
299 {
300 break;
301 }
302 size_t proto_hdr, payload_hdr;
303 const struct key_type *kt = &c->c1.ks.key_type;
304
305 /* OCC message have comp/fragment headers but not ethernet headers */
306 payload_hdr = frame_calculate_payload_overhead(0, &c->options, kt);
307
308 /* Since we do not know the payload size we just pass 0 as size here */
309 proto_hdr = frame_calculate_protocol_header_size(kt, &c->options, false);
310
311 need_to_add = min_int(c->c2.occ_mtu_load_size, c->c2.frame.buf.payload_size)
312 - OCC_STRING_SIZE - sizeof(uint8_t) /* occ opcode */
313 - payload_hdr - proto_hdr;
314
315 while (need_to_add > 0)
316 {
317 /*
318 * Fill the load test packet with pseudo-random bytes.
319 */
320 if (!buf_write_u8(&c->c2.buf, get_random() & 0xFF))
321 {
322 break;
323 }
324 --need_to_add;
325 }
326 dmsg(D_PACKET_CONTENT, "SENT OCC_MTU_LOAD min_int(%d,%d)-%d-%d-%d-%d) size=%d",
328 (int)sizeof(uint8_t), (int)payload_hdr, (int)proto_hdr, BLEN(&c->c2.buf));
329 doit = true;
330 }
331 break;
332
333 case OCC_EXIT:
334 if (!buf_write_u8(&c->c2.buf, OCC_EXIT))
335 {
336 break;
337 }
338 dmsg(D_PACKET_CONTENT, "SENT OCC_EXIT");
339 doit = true;
340 break;
341 }
342
343 if (doit)
344 {
345 /*
346 * We will treat the packet like any other outgoing packet,
347 * compress, encrypt, sign, etc.
348 */
349 encrypt_sign(c, true);
350 }
351
352 c->c2.occ_op = -1;
353}
354
355#if defined(__GNUC__) || defined(__clang__)
356#pragma GCC diagnostic pop
357#endif
358
359void
361{
363 switch (buf_read_u8(&c->c2.buf))
364 {
365 case OCC_REQUEST:
366 dmsg(D_PACKET_CONTENT, "RECEIVED OCC_REQUEST");
367 c->c2.occ_op = OCC_REPLY;
368 break;
369
370 case OCC_MTU_REQUEST:
371 dmsg(D_PACKET_CONTENT, "RECEIVED OCC_MTU_REQUEST");
373 break;
374
376 dmsg(D_PACKET_CONTENT, "RECEIVED OCC_MTU_LOAD_REQUEST");
378 if (c->c2.occ_mtu_load_size >= 0)
379 {
381 }
382 break;
383
384 case OCC_REPLY:
385 dmsg(D_PACKET_CONTENT, "RECEIVED OCC_REPLY");
386 if (c->options.occ && !TLS_MODE(c) && c->c2.options_string_remote)
387 {
389 c->c2.buf.len))
390 {
392 c->c2.buf.len);
393 }
394 }
396 break;
397
398 case OCC_MTU_REPLY:
399 dmsg(D_PACKET_CONTENT, "RECEIVED OCC_MTU_REPLY");
402 if (c->options.mtu_test && c->c2.max_recv_size_remote > 0
403 && c->c2.max_send_size_remote > 0)
404 {
405 msg(M_INFO,
406 "NOTE: Empirical MTU test completed [Tried,Actual] local->remote=[%d,%d] remote->local=[%d,%d]",
413 {
414 msg(M_INFO,
415 "NOTE: This connection is unable to accommodate a UDP packet size of %d. Consider using --fragment or --mssfix options as a workaround.",
417 }
418 }
420 break;
421
422 case OCC_EXIT:
423 dmsg(D_STREAM_ERRORS, "OCC exit message received by peer");
424 register_signal(c->sig, SIGUSR1, "remote-exit");
425 break;
426 }
427 c->c2.buf.len = 0; /* don't pass packet on */
428}
static bool buf_write_u16(struct buffer *dest, uint16_t data)
Definition buffer.h:690
#define BPTR(buf)
Definition buffer.h:123
static int buf_read_u16(struct buffer *buf)
Definition buffer.h:787
static bool buf_safe(const struct buffer *buf, size_t len)
Definition buffer.h:518
static bool buf_advance(struct buffer *buf, int size)
Definition buffer.h:616
static bool buf_write(struct buffer *dest, const void *src, size_t size)
Definition buffer.h:660
static bool buf_write_u8(struct buffer *dest, uint8_t data)
Definition buffer.h:684
static int buf_read_u8(struct buffer *buf)
Definition buffer.h:774
#define BLEN(buf)
Definition buffer.h:126
#define buf_init(buf, offset)
Definition buffer.h:209
#define counter_format
Definition common.h:30
#define PACKAGE_NAME
Definition config.h:492
long int get_random(void)
Definition crypto.c:1725
#define D_SHOW_OCC
Definition errlevel.h:150
#define D_PACKET_CONTENT
Definition errlevel.h:167
#define D_STREAM_ERRORS
Definition errlevel.h:62
#define M_INFO
Definition errlevel.h:54
Interface functions to the internal and external multiplexers.
static bool connection_established(struct context *c)
Definition forward.h:408
void encrypt_sign(struct context *c, bool comp_frag)
Process a data channel packet that will be sent through a VPN tunnel.
Definition forward.c:620
static int min_int(int x, int y)
Definition integer.h:105
static void event_timeout_reset(struct event_timeout *et)
Resets a timer.
Definition interval.h:187
static void event_timeout_clear(struct event_timeout *et)
Clears the timeout and reset all values to 0.
Definition interval.h:153
size_t frame_calculate_payload_size(const struct frame *frame, const struct options *options, const struct key_type *kt)
Calculates the size of the payload according to tun-mtu and tap overhead.
Definition mtu.c:138
size_t frame_calculate_protocol_header_size(const struct key_type *kt, const struct options *options, bool occ)
Calculates the size of the OpenVPN protocol header.
Definition mtu.c:61
size_t frame_calculate_payload_overhead(size_t extra_tun, const struct options *options, const struct key_type *kt)
Calculates the size of the payload overhead according to tun-mtu and tap overhead.
Definition mtu.c:98
#define TUN_MTU_MIN
Definition mtu.h:59
void process_received_occ_msg(struct context *c)
Definition occ.c:360
void check_send_occ_req_dowork(struct context *c)
Definition occ.c:144
void check_send_occ_msg_dowork(struct context *c)
Definition occ.c:217
const uint8_t occ_magic[]
Definition occ.c:54
void check_send_occ_load_test_dowork(struct context *c)
Definition occ.c:183
static const struct mtu_load_test mtu_load_test_sequence[]
Definition occ.c:57
#define OCC_N_TRIES
Definition occ.h:46
#define OCC_REQUEST
Definition occ.h:35
#define OCC_REPLY
Definition occ.h:36
#define OCC_MTU_REPLY
Definition occ.h:55
#define OCC_STRING_SIZE
Definition occ.h:29
#define OCC_MTU_LOAD_REQUEST
Definition occ.h:51
#define OCC_MTU_REQUEST
Definition occ.h:53
#define OCC_EXIT
Definition occ.h:66
#define OCC_MTU_LOAD
Definition occ.h:52
#define dmsg(flags,...)
Definition error.h:172
#define msg(flags,...)
Definition error.h:152
#define ASSERT(x)
Definition error.h:219
#define TLS_MODE(c)
Definition openvpn.h:543
bool options_cmp_equal_safe(char *actual, const char *expected, size_t actual_n)
Definition options.c:4671
void options_warning_safe(char *actual, const char *expected, size_t actual_n)
Definition options.c:4694
void register_signal(struct signal_info *si, int signum, const char *signal_text)
Register a soft signal in the signal_info struct si respecting priority.
Definition sig.c:228
static bool proto_is_dgram(int proto)
Return if the protocol is datagram (UDP)
int len
Length in bytes of the actual content within the allocated memory.
Definition buffer.h:65
const char * remote
Definition options.h:111
int fragment
Definition options.h:138
int proto
Definition options.h:106
struct key_schedule ks
Definition openvpn.h:164
counter_type link_read_bytes
Definition openvpn.h:266
char * options_string_local
Definition openvpn.h:296
struct event_timeout occ_mtu_load_test_interval
Definition openvpn.h:317
int max_recv_size_local
Definition openvpn.h:308
int occ_mtu_load_size
Definition openvpn.h:315
int max_recv_size_remote
Definition openvpn.h:309
char * options_string_remote
Definition openvpn.h:297
int occ_mtu_load_n_tries
Definition openvpn.h:318
int max_send_size_local
Definition openvpn.h:310
int occ_op
Definition openvpn.h:299
struct frame frame
Definition openvpn.h:248
struct event_timeout occ_interval
Definition openvpn.h:301
counter_type link_read_bytes_auth
Definition openvpn.h:268
struct buffer buf
Definition openvpn.h:375
struct context_buffers * buffers
Definition openvpn.h:367
int max_send_size_remote
Definition openvpn.h:311
int occ_n_tries
Definition openvpn.h:300
struct buffer aux_buf
Definition openvpn.h:97
Contains all state information for one tunnel.
Definition openvpn.h:474
struct signal_info * sig
Internal error signaling object.
Definition openvpn.h:503
struct context_2 c2
Level 2 context.
Definition openvpn.h:517
struct options options
Options loaded from command line or configuration file.
Definition openvpn.h:475
struct context_1 c1
Level 1 context.
Definition openvpn.h:516
int payload_size
the maximum size that a payload that our buffers can hold from either tun device or network link.
Definition mtu.h:108
int headroom
the headroom in the buffer, this is choosen to allow all potential header to be added before the pack...
Definition mtu.h:114
struct frame::@8 buf
struct key_type key_type
Definition openvpn.h:57
int op
Definition occ.h:74
struct connection_entry ce
Definition options.h:290
bool mtu_test
Definition options.h:334
bool occ
Definition options.h:446