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
177void
179{
181 {
182 const struct mtu_load_test *entry;
183
184 if (!c->c2.occ_mtu_load_n_tries)
185 {
186 msg(M_INFO,
187 "NOTE: Beginning empirical MTU test -- results should be available in 3 to 4 minutes.");
188 }
189
191 if (entry->op >= 0)
192 {
193 c->c2.occ_op = entry->op;
194 size_t payload_size =
196 size_t header_size =
198
199 c->c2.occ_mtu_load_size = payload_size + header_size;
200 }
201 else
202 {
203 msg(M_INFO, "NOTE: failed to empirically measure MTU (requires " PACKAGE_NAME
204 " 1.5 or higher at other end of connection).");
207 }
208 }
209}
210
211void
213{
214 bool doit = false;
215
216 c->c2.buf = c->c2.buffers->aux_buf;
220
221 switch (c->c2.occ_op)
222 {
223 case OCC_REQUEST:
224 if (!buf_write_u8(&c->c2.buf, OCC_REQUEST))
225 {
226 break;
227 }
228 dmsg(D_PACKET_CONTENT, "SENT OCC_REQUEST");
229 doit = true;
230 break;
231
232 case OCC_REPLY:
233 if (!c->c2.options_string_local)
234 {
235 break;
236 }
237 if (!buf_write_u8(&c->c2.buf, OCC_REPLY))
238 {
239 break;
240 }
242 strlen(c->c2.options_string_local) + 1))
243 {
244 break;
245 }
246 dmsg(D_PACKET_CONTENT, "SENT OCC_REPLY");
247 doit = true;
248 break;
249
250 case OCC_MTU_REQUEST:
252 {
253 break;
254 }
255 dmsg(D_PACKET_CONTENT, "SENT OCC_MTU_REQUEST");
256 doit = true;
257 break;
258
259 case OCC_MTU_REPLY:
260 if (!buf_write_u8(&c->c2.buf, OCC_MTU_REPLY))
261 {
262 break;
263 }
265 {
266 break;
267 }
269 {
270 break;
271 }
272 dmsg(D_PACKET_CONTENT, "SENT OCC_MTU_REPLY");
273 doit = true;
274 break;
275
278 {
279 break;
280 }
282 {
283 break;
284 }
285 dmsg(D_PACKET_CONTENT, "SENT OCC_MTU_LOAD_REQUEST");
286 doit = true;
287 break;
288
289 case OCC_MTU_LOAD:
290 {
291 int need_to_add;
292
293 if (!buf_write_u8(&c->c2.buf, OCC_MTU_LOAD))
294 {
295 break;
296 }
297 size_t proto_hdr, payload_hdr;
298 const struct key_type *kt = &c->c1.ks.key_type;
299
300 /* OCC message have comp/fragment headers but not ethernet headers */
301 payload_hdr = frame_calculate_payload_overhead(0, &c->options, kt);
302
303 /* Since we do not know the payload size we just pass 0 as size here */
304 proto_hdr = frame_calculate_protocol_header_size(kt, &c->options, false);
305
306 need_to_add = min_int(c->c2.occ_mtu_load_size, c->c2.frame.buf.payload_size)
307 - OCC_STRING_SIZE - sizeof(uint8_t) /* occ opcode */
308 - payload_hdr - proto_hdr;
309
310 while (need_to_add > 0)
311 {
312 /*
313 * Fill the load test packet with pseudo-random bytes.
314 */
315 if (!buf_write_u8(&c->c2.buf, get_random() & 0xFF))
316 {
317 break;
318 }
319 --need_to_add;
320 }
321 dmsg(D_PACKET_CONTENT, "SENT OCC_MTU_LOAD min_int(%d,%d)-%d-%d-%d-%d) size=%d",
323 (int)sizeof(uint8_t), (int)payload_hdr, (int)proto_hdr, BLEN(&c->c2.buf));
324 doit = true;
325 }
326 break;
327
328 case OCC_EXIT:
329 if (!buf_write_u8(&c->c2.buf, OCC_EXIT))
330 {
331 break;
332 }
333 dmsg(D_PACKET_CONTENT, "SENT OCC_EXIT");
334 doit = true;
335 break;
336 }
337
338 if (doit)
339 {
340 /*
341 * We will treat the packet like any other outgoing packet,
342 * compress, encrypt, sign, etc.
343 */
344 encrypt_sign(c, true);
345 }
346
347 c->c2.occ_op = -1;
348}
349
350void
352{
354 switch (buf_read_u8(&c->c2.buf))
355 {
356 case OCC_REQUEST:
357 dmsg(D_PACKET_CONTENT, "RECEIVED OCC_REQUEST");
358 c->c2.occ_op = OCC_REPLY;
359 break;
360
361 case OCC_MTU_REQUEST:
362 dmsg(D_PACKET_CONTENT, "RECEIVED OCC_MTU_REQUEST");
364 break;
365
367 dmsg(D_PACKET_CONTENT, "RECEIVED OCC_MTU_LOAD_REQUEST");
369 if (c->c2.occ_mtu_load_size >= 0)
370 {
372 }
373 break;
374
375 case OCC_REPLY:
376 dmsg(D_PACKET_CONTENT, "RECEIVED OCC_REPLY");
377 if (c->options.occ && !TLS_MODE(c) && c->c2.options_string_remote)
378 {
380 c->c2.buf.len))
381 {
383 c->c2.buf.len);
384 }
385 }
387 break;
388
389 case OCC_MTU_REPLY:
390 dmsg(D_PACKET_CONTENT, "RECEIVED OCC_MTU_REPLY");
393 if (c->options.mtu_test && c->c2.max_recv_size_remote > 0
394 && c->c2.max_send_size_remote > 0)
395 {
396 msg(M_INFO,
397 "NOTE: Empirical MTU test completed [Tried,Actual] local->remote=[%d,%d] remote->local=[%d,%d]",
404 {
405 msg(M_INFO,
406 "NOTE: This connection is unable to accommodate a UDP packet size of %d. Consider using --fragment or --mssfix options as a workaround.",
408 }
409 }
411 break;
412
413 case OCC_EXIT:
414 dmsg(D_STREAM_ERRORS, "OCC exit message received by peer");
415 register_signal(c->sig, SIGUSR1, "remote-exit");
416 break;
417 }
418 c->c2.buf.len = 0; /* don't pass packet on */
419}
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
long int get_random(void)
Definition crypto.c:1716
#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:407
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:614
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:351
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:212
const uint8_t occ_magic[]
Definition occ.c:54
void check_send_occ_load_test_dowork(struct context *c)
Definition occ.c:178
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:170
#define msg(flags,...)
Definition error.h:150
#define ASSERT(x)
Definition error.h:217
#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:4662
void options_warning_safe(char *actual, const char *expected, size_t actual_n)
Definition options.c:4685
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