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, int level, 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(level, "%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 int res;
287 struct probehdr rcvbuf;
288 struct iovec iov;
289 struct msghdr msg;
290 struct cmsghdr *cmsg;
291 struct sock_extended_err *e;
292 struct sockaddr_storage addr;
293 struct buffer out = alloc_buf_gc(256, gc);
294 char *cbuf = (char *)gc_malloc(256, false, gc);
295
296 *mtu = 0;
297
298 while (true)
299 {
300 memset(&rcvbuf, -1, sizeof(rcvbuf));
301 iov.iov_base = &rcvbuf;
302 iov.iov_len = sizeof(rcvbuf);
303 msg.msg_name = (uint8_t *)&addr;
304 msg.msg_namelen = sizeof(addr);
305 msg.msg_iov = &iov;
306 msg.msg_iovlen = 1;
307 msg.msg_flags = 0;
308 msg.msg_control = cbuf;
309 msg.msg_controllen = 256; /* size of cbuf */
310
311 res = recvmsg(fd, &msg, MSG_ERRQUEUE);
312 if (res < 0)
313 {
314 goto exit;
315 }
316
317 e = NULL;
318
320 {
321 if (cmsg->cmsg_level == SOL_IP)
322 {
323 if (cmsg->cmsg_type == IP_RECVERR)
324 {
325 e = (struct sock_extended_err *)CMSG_DATA(cmsg);
326 }
327 else
328 {
329 buf_printf(&out, "CMSG=%d|", cmsg->cmsg_type);
330 }
331 }
332 else if (cmsg->cmsg_level == IPPROTO_IPV6)
333 {
334 if (cmsg->cmsg_type == IPV6_RECVERR)
335 {
336 e = (struct sock_extended_err *)CMSG_DATA(cmsg);
337 }
338 else
339 {
340 buf_printf(&out, "CMSG=%d|", cmsg->cmsg_type);
341 }
342 }
343 }
344 if (e == NULL)
345 {
346 buf_printf(&out, "NO-INFO|");
347 goto exit;
348 }
349
350 switch (e->ee_errno)
351 {
352 case ETIMEDOUT:
353 buf_printf(&out, "ETIMEDOUT|");
354 break;
355
356 case EMSGSIZE:
357 buf_printf(&out, "EMSGSIZE Path-MTU=%d|", e->ee_info);
358 *mtu = e->ee_info;
359 break;
360
361 case ECONNREFUSED:
362 buf_printf(&out, "ECONNREFUSED|");
363 break;
364
365 case EPROTO:
366 buf_printf(&out, "EPROTO|");
367 break;
368
369 case EHOSTUNREACH:
370 buf_printf(&out, "EHOSTUNREACH|");
371 break;
372
373 case ENETUNREACH:
374 buf_printf(&out, "ENETUNREACH|");
375 break;
376
377 case EACCES:
378 buf_printf(&out, "EACCES|");
379 break;
380
381 default:
382 buf_printf(&out, "UNKNOWN|");
383 break;
384 }
385 }
386
387exit:
388 buf_rmtail(&out, '|');
389 return BSTR(&out);
390}
391
392void
393set_sock_extended_error_passing(int sd, sa_family_t proto_af)
394{
395 int on = 1;
396 /* see "man 7 ip" (on Linux)
397 * this works on IPv4 and IPv6(-dual-stack) sockets (v4-mapped)
398 */
399 if (setsockopt(sd, SOL_IP, IP_RECVERR, (void *)&on, sizeof(on)) != 0)
400 {
402 "Note: enable extended error passing on TCP/UDP socket failed (IP_RECVERR)");
403 }
404 /* see "man 7 ipv6" (on Linux)
405 * this only works on IPv6 sockets
406 */
407 if (proto_af == AF_INET6
408 && setsockopt(sd, IPPROTO_IPV6, IPV6_RECVERR, (void *)&on, sizeof(on)) != 0)
409 {
411 "Note: enable extended error passing on TCP/UDP socket failed (IPV6_RECVERR)");
412 }
413}
414
415#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:1015
#define buf_init(buf, offset)
Definition buffer.h:209
static struct gc_arena gc_new(void)
Definition buffer.h:1007
#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.
void frame_print(const struct frame *frame, int level, const char *prefix)
Definition mtu.c:190
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
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:88
#define M_ERR
Definition error.h:104
#define msg(flags,...)
Definition error.h:150
#define ASSERT(x)
Definition error.h:217
#define M_WARN
Definition error.h:90
#define M_ERRNO
Definition error.h:93
static int packet_id_size(bool long_form)
Definition packet_id.h:313
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:120
int fragment
Definition options.h:138
int proto
Definition options.h:106
int tun_mtu
Definition options.h:124
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:413
bool use_peer_id
Definition options.h:704
const char * authname
Definition options.h:582
struct connection_entry ce
Definition options.h:290
const char * ciphername
Definition options.h:576
bool tls_server
Definition options.h:595
bool tls_client
Definition options.h:596
const char * shared_secret_file
Definition options.h:572
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:154