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