OpenVPN
mtu.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-2026 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 "common.h"
30#include "buffer.h"
31#include "error.h"
32#include "integer.h"
33#include "mtu.h"
34#include "options.h"
35#include "crypto.h"
36
37#include "memdbg.h"
38#include "ssl_common.h"
39
40/* allocate a buffer for socket or tun layer */
41void
42alloc_buf_sock_tun(struct buffer *buf, const struct frame *frame)
43{
44 /* allocate buffer for overlapped I/O */
45 *buf = alloc_buf(BUF_SIZE(frame));
47 buf->len = frame->buf.payload_size;
48 ASSERT(buf_safe(buf, 0));
49}
50
51unsigned int
52calc_packet_id_size_dc(const struct options *options, const struct key_type *kt)
53{
54 bool tlsmode = options->tls_server || options->tls_client;
56
57 /* epoch format uses a 64-bit packet id: 16 bit epoch + 48 bit per-epoch counter */
58 if (epoch)
59 {
60 return sizeof(uint64_t);
61 }
62
63 bool packet_id_long_form = !tlsmode || cipher_kt_mode_ofb_cfb(kt->cipher);
64
65 return packet_id_size(packet_id_long_form);
66}
67
68size_t
70 bool occ)
71{
72 /* Sum of all the overhead that reduces the usable packet size */
73 size_t header_size = 0;
74
75 bool tlsmode = options->tls_server || options->tls_client;
76
77 /* A socks proxy adds extra header to each packet
78 * (we only support Socks with IPv4, this value is different for IPv6) */
80 {
81 header_size += SOCKS_UDPv4_HEADROOM;
82 }
83
84 /* TCP stream based packets have a 16 bit length field */
86 {
87 header_size += 2;
88 }
89
90 /* Add the opcode and peerid */
91 if (tlsmode)
92 {
93 header_size += options->use_peer_id ? 4 : 1;
94 }
95
96 unsigned int pkt_id_size = calc_packet_id_size_dc(options, kt);
97
98 /* For figuring out the crypto overhead, we need the size of the payload
99 * including all headers that also get encrypted as part of the payload */
100 header_size += calculate_crypto_overhead(kt, pkt_id_size, occ);
101 return header_size;
102}
103
104
105size_t
106frame_calculate_payload_overhead(size_t extra_tun, const struct options *options,
107 const struct key_type *kt)
108{
109 size_t overhead = 0;
110
111 /* This is the overhead of tap device that is not included in the MTU itself
112 * i.e. Ethernet header that we still need to transmit as part of the
113 * payload, this is set to 0 by caller if not applicable */
114 overhead += extra_tun;
115
116#if defined(USE_COMP)
117 /* v1 Compression schemes add 1 byte header. V2 only adds a header when it
118 * does not increase the packet length. We ignore the unlikely escaping
119 * for tap here */
122 {
123 overhead += 1;
124 }
125#endif
126#if defined(ENABLE_FRAGMENT)
127 /* Add the size of the fragment header (uint32_t) */
128 if (options->ce.fragment)
129 {
130 overhead += 4;
131 }
132#endif
133
134 if (cipher_kt_mode_cbc(kt->cipher))
135 {
136 /* The packet id is part of the plain text payload instead of the
137 * cleartext protocol header and needs to be included in the payload
138 * overhead instead of the protocol header */
139 overhead += calc_packet_id_size_dc(options, kt);
140 }
141
142 return overhead;
143}
144
145size_t
147 const struct key_type *kt)
148{
149 size_t payload_size = options->ce.tun_mtu;
151 return payload_size;
152}
153
154size_t
155calc_options_string_link_mtu(const struct options *o, const struct frame *frame)
156{
157 struct key_type occ_kt;
158
159 /* neither --secret nor TLS mode */
160 if (!o->tls_client && !o->tls_server && !o->shared_secret_file)
161 {
162 init_key_type(&occ_kt, "none", "none", false, false);
163 return frame_calculate_payload_size(frame, o, &occ_kt);
164 }
165
166 /* o->ciphername might be BF-CBC even though the underlying SSL library
167 * does not support it. For this reason we workaround this corner case
168 * by pretending to have no encryption enabled and by manually adding
169 * the required packet overhead to the MTU computation.
170 */
171 const char *ciphername = o->ciphername;
172
173 size_t overhead = 0;
174
175 if (strcmp(o->ciphername, "BF-CBC") == 0)
176 {
177 /* none has no overhead, so use this to later add only --auth
178 * overhead */
179
180 /* overhead of BF-CBC: 64 bit block size, 64 bit IV size */
181 overhead += 64 / 8 + 64 / 8;
182 /* set ciphername to none, so its size does get added in the
183 * fake_kt and the cipher is not tried to be resolved */
184 ciphername = "none";
185 }
186
187 /* We pass tlsmode always true here since as we do not need to check if
188 * the ciphers are actually valid for non tls in occ calucation */
189 init_key_type(&occ_kt, ciphername, o->authname, true, false);
190
191 size_t payload = frame_calculate_payload_size(frame, o, &occ_kt);
192 overhead += frame_calculate_protocol_header_size(&occ_kt, o, true);
193
194 return payload + overhead;
195}
196
197void
198frame_print(const struct frame *frame, msglvl_t msglevel, const char *prefix)
199{
200 struct gc_arena gc = gc_new();
201 struct buffer out = alloc_buf_gc(256, &gc);
202 if (prefix)
203 {
204 buf_printf(&out, "%s ", prefix);
205 }
206 buf_printf(&out, "[");
207 buf_printf(&out, " mss_fix:%" PRIu16, frame->mss_fix);
208#ifdef ENABLE_FRAGMENT
209 buf_printf(&out, " max_frag:%d", frame->max_fragment_size);
210#endif
211 buf_printf(&out, " tun_mtu:%d", frame->tun_mtu);
212 buf_printf(&out, " tun_max_mtu:%d", frame->tun_max_mtu);
213 buf_printf(&out, " headroom:%d", frame->buf.headroom);
214 buf_printf(&out, " payload:%d", frame->buf.payload_size);
215 buf_printf(&out, " tailroom:%d", frame->buf.tailroom);
216 buf_printf(&out, " ET:%d", frame->extra_tun);
217 buf_printf(&out, " ]");
218
219 msg(msglevel, "%s", out.data);
220 gc_free(&gc);
221}
222
223#define MTUDISC_NOT_SUPPORTED_MSG "--mtu-disc is not supported on this OS"
224
225void
227{
228 if (mtu_type >= 0)
229 {
230 switch (proto_af)
231 {
232#if defined(IP_MTU_DISCOVER)
233 case AF_INET:
235 sizeof(mtu_type)))
236 {
237 msg(M_ERR, "Error setting IP_MTU_DISCOVER type=%d on TCP/UDP socket", mtu_type);
238 }
239 break;
240
241#endif
242#if defined(IPV6_MTU_DISCOVER)
243 case AF_INET6:
245 sizeof(mtu_type)))
246 {
247 msg(M_ERR, "Error setting IPV6_MTU_DISCOVER type=%d on TCP6/UDP6 socket",
248 mtu_type);
249 }
250 break;
251
252#endif
253 default:
255 break;
256 }
257 }
258}
259
260int
262{
263#if defined(IP_PMTUDISC_DONT) && defined(IP_PMTUDISC_WANT) && defined(IP_PMTUDISC_DO)
264 if (!strcmp(name, "yes"))
265 {
266 return IP_PMTUDISC_DO;
267 }
268 if (!strcmp(name, "maybe"))
269 {
270 return IP_PMTUDISC_WANT;
271 }
272 if (!strcmp(name, "no"))
273 {
274 return IP_PMTUDISC_DONT;
275 }
276 msg(M_FATAL, "invalid --mtu-disc type: '%s' -- valid types are 'yes', 'maybe', or 'no'", name);
277#else
279#endif
280 return -1; /* NOTREACHED */
281}
282
283#if EXTENDED_SOCKET_ERROR_CAPABILITY
284
285#include <linux/errqueue.h>
286
287struct probehdr
288{
289 uint32_t ttl;
290 struct timeval tv;
291};
292
293const char *
294format_extended_socket_error(int fd, int *mtu, struct gc_arena *gc)
295{
296 struct probehdr rcvbuf;
297 struct iovec iov;
298 struct msghdr msg;
299 struct cmsghdr *cmsg;
300 struct sock_extended_err *e;
301 struct sockaddr_storage addr;
302 struct buffer out = alloc_buf_gc(256, gc);
303 char *cbuf = (char *)gc_malloc(256, false, gc);
304
305 *mtu = 0;
306
307 while (true)
308 {
309 memset(&rcvbuf, -1, sizeof(rcvbuf));
310 iov.iov_base = &rcvbuf;
311 iov.iov_len = sizeof(rcvbuf);
312 msg.msg_name = (uint8_t *)&addr;
313 msg.msg_namelen = sizeof(addr);
314 msg.msg_iov = &iov;
315 msg.msg_iovlen = 1;
316 msg.msg_flags = 0;
317 msg.msg_control = cbuf;
318 msg.msg_controllen = 256; /* size of cbuf */
319
321 if (res < 0)
322 {
323 goto exit;
324 }
325
326 e = NULL;
327
329 {
330 if (cmsg->cmsg_level == SOL_IP)
331 {
332 if (cmsg->cmsg_type == IP_RECVERR)
333 {
334 e = (struct sock_extended_err *)CMSG_DATA(cmsg);
335 }
336 else
337 {
338 buf_printf(&out, "CMSG=%d|", cmsg->cmsg_type);
339 }
340 }
341 else if (cmsg->cmsg_level == IPPROTO_IPV6)
342 {
343 if (cmsg->cmsg_type == IPV6_RECVERR)
344 {
345 e = (struct sock_extended_err *)CMSG_DATA(cmsg);
346 }
347 else
348 {
349 buf_printf(&out, "CMSG=%d|", cmsg->cmsg_type);
350 }
351 }
352 }
353 if (e == NULL)
354 {
355 buf_printf(&out, "NO-INFO|");
356 goto exit;
357 }
358
359 switch (e->ee_errno)
360 {
361 case ETIMEDOUT:
362 buf_printf(&out, "ETIMEDOUT|");
363 break;
364
365 case EMSGSIZE:
366 buf_printf(&out, "EMSGSIZE Path-MTU=%d|", e->ee_info);
367 *mtu = e->ee_info;
368 break;
369
370 case ECONNREFUSED:
371 buf_printf(&out, "ECONNREFUSED|");
372 break;
373
374 case EPROTO:
375 buf_printf(&out, "EPROTO|");
376 break;
377
378 case EHOSTUNREACH:
379 buf_printf(&out, "EHOSTUNREACH|");
380 break;
381
382 case ENETUNREACH:
383 buf_printf(&out, "ENETUNREACH|");
384 break;
385
386 case EACCES:
387 buf_printf(&out, "EACCES|");
388 break;
389
390 default:
391 buf_printf(&out, "UNKNOWN|");
392 break;
393 }
394 }
395
396exit:
397 buf_rmtail(&out, '|');
398 return BSTR(&out);
399}
400
401void
402set_sock_extended_error_passing(int sd, sa_family_t proto_af)
403{
404 int on = 1;
405 /* see "man 7 ip" (on Linux)
406 * this works on IPv4 and IPv6(-dual-stack) sockets (v4-mapped)
407 */
408 if (setsockopt(sd, SOL_IP, IP_RECVERR, (void *)&on, sizeof(on)) != 0)
409 {
411 "Note: enable extended error passing on TCP/UDP socket failed (IP_RECVERR)");
412 }
413 /* see "man 7 ipv6" (on Linux)
414 * this only works on IPv6 sockets
415 */
416 if (proto_af == AF_INET6
417 && setsockopt(sd, IPPROTO_IPV6, IPV6_RECVERR, (void *)&on, sizeof(on)) != 0)
418 {
420 "Note: enable extended error passing on TCP/UDP socket failed (IPV6_RECVERR)");
421 }
422}
423
424#endif /* if EXTENDED_SOCKET_ERROR_CAPABILITY */
bool buf_printf(struct buffer *buf, const char *format,...)
Definition buffer.c:246
void * gc_malloc(size_t size, bool clear, struct gc_arena *a)
Definition buffer.c:341
struct buffer alloc_buf_gc(size_t size, struct gc_arena *gc)
Definition buffer.c:88
struct buffer alloc_buf(size_t size)
Definition buffer.c:63
void buf_rmtail(struct buffer *buf, uint8_t remove)
Definition buffer.c:522
#define BSTR(buf)
Definition buffer.h:130
static bool buf_safe(const struct buffer *buf, size_t len)
Definition buffer.h:520
static void gc_free(struct gc_arena *a)
Definition buffer.h:1081
#define buf_init(buf, offset)
Definition buffer.h:211
static struct gc_arena gc_new(void)
Definition buffer.h:1073
#define COMP_ALG_LZ4
LZ4 algorithm.
Definition comp.h:59
#define COMP_ALG_STUB
support compression command byte and framing without actual compression
Definition comp.h:56
#define COMP_ALG_LZO
LZO algorithm.
Definition comp.h:57
size_t calculate_crypto_overhead(const struct key_type *kt, unsigned int pkt_id_size, bool occ)
Calculate the maximum overhead that our encryption has on a packet.
Definition crypto.c:803
void init_key_type(struct key_type *kt, const char *ciphername, const char *authname, bool tls_mode, bool warn)
Initialize a key_type structure with.
Definition crypto.c:875
Data Channel Cryptography Module.
#define CO_EPOCH_DATA_KEY_FORMAT
Bit-flag indicating the epoch the data format.
Definition crypto.h:379
bool cipher_kt_mode_cbc(const char *ciphername)
Check if the supplied cipher is a supported CBC mode cipher.
bool cipher_kt_mode_ofb_cfb(const char *ciphername)
Check if the supplied cipher is a supported OFB or CFB mode cipher.
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:146
#define MTUDISC_NOT_SUPPORTED_MSG
Definition mtu.c:223
int translate_mtu_discover_type_name(const char *name)
Definition mtu.c:261
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:69
unsigned int calc_packet_id_size_dc(const struct options *options, const struct key_type *kt)
Return the size of the packet ID size that is currently in use by cipher and options for the data cha...
Definition mtu.c:52
void alloc_buf_sock_tun(struct buffer *buf, const struct frame *frame)
Definition mtu.c:42
void frame_print(const struct frame *frame, msglvl_t msglevel, const char *prefix)
Definition mtu.c:198
size_t calc_options_string_link_mtu(const struct options *o, const struct frame *frame)
Calculate the link-mtu to advertise to our peer.
Definition mtu.c:155
void set_mtu_discover_type(socket_descriptor_t sd, int mtu_type, sa_family_t proto_af)
Definition mtu.c:226
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:106
#define BUF_SIZE(f)
Definition mtu.h:188
#define SOCKS_UDPv4_HEADROOM
Definition mtu.h:106
#define M_FATAL
Definition error.h:90
#define M_ERR
Definition error.h:106
#define msg(flags,...)
Definition error.h:152
unsigned int msglvl_t
Definition error.h:77
#define ASSERT(x)
Definition error.h:219
#define M_WARN
Definition error.h:92
#define M_ERRNO
Definition error.h:95
static int packet_id_size(bool long_form)
Definition packet_id.h:322
static bool proto_is_udp(int proto)
Returns if the protocol being used is UDP.
static bool proto_is_tcp(int proto)
returns if the proto is a TCP variant (tcp-server, tcp-client or tcp)
Control Channel Common Data Structures.
Wrapper structure for dynamically allocated memory.
Definition buffer.h:61
uint8_t * data
Pointer to the allocated memory.
Definition buffer.h:68
int len
Length in bytes of the actual content within the allocated memory.
Definition buffer.h:66
const char * socks_proxy_server
Definition options.h:125
int fragment
Definition options.h:143
int proto
Definition options.h:111
int tun_mtu
Definition options.h:129
Packet geometry parameters.
Definition mtu.h:113
int tun_mtu
the (user) configured tun-mtu.
Definition mtu.h:147
int payload_size
the maximum size that a payload that our buffers can hold from either tun device or network link.
Definition mtu.h:118
int tun_max_mtu
the maximum tun-mtu size the buffers are are sized for.
Definition mtu.h:157
int extra_tun
Maximum number of bytes in excess of the tun/tap MTU that might be read from or written to the virtua...
Definition mtu.h:161
int headroom
the headroom in the buffer, this is choosen to allow all potential header to be added before the pack...
Definition mtu.h:124
uint16_t mss_fix
The actual MSS value that should be written to the payload packets.
Definition mtu.h:134
int max_fragment_size
The maximum size of a fragment.
Definition mtu.h:140
struct frame::@8 buf
int tailroom
the tailroom in the buffer.
Definition mtu.h:128
Garbage collection arena used to keep track of dynamically allocated memory.
Definition buffer.h:117
const char * cipher
const name of the cipher
Definition crypto.h:142
struct compress_options comp
Definition options.h:410
unsigned int imported_protocol_flags
Definition options.h:720
bool use_peer_id
Definition options.h:700
const char * authname
Definition options.h:581
struct connection_entry ce
Definition options.h:294
const char * ciphername
Definition options.h:575
bool tls_server
Definition options.h:591
bool tls_client
Definition options.h:592
const char * shared_secret_file
Definition options.h:571
unsigned short sa_family_t
Definition syshead.h:409
#define SOL_IP
Definition syshead.h:402
SOCKET socket_descriptor_t
Definition syshead.h:445
struct gc_arena gc
Definition test_ssl.c:133