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-2024 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, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 */
23
24#ifdef HAVE_CONFIG_H
25#include "config.h"
26#endif
27
28#include "syshead.h"
29
30#include "common.h"
31#include "buffer.h"
32#include "error.h"
33#include "integer.h"
34#include "mtu.h"
35#include "options.h"
36#include "crypto.h"
37
38#include "memdbg.h"
39
40/* allocate a buffer for socket or tun layer */
41void
43 const struct frame *frame)
44{
45 /* allocate buffer for overlapped I/O */
46 *buf = alloc_buf(BUF_SIZE(frame));
48 buf->len = frame->buf.payload_size;
49 ASSERT(buf_safe(buf, 0));
50}
51
52unsigned int
53calc_packet_id_size_dc(const struct options *options, const struct key_type *kt)
54{
55 bool tlsmode = options->tls_server || options->tls_client;
56
57 bool packet_id_long_form = !tlsmode || cipher_kt_mode_ofb_cfb(kt->cipher);
58
59 return packet_id_size(packet_id_long_form);
60}
61
62size_t
64 const struct options *options,
65 bool occ)
66{
67 /* Sum of all the overhead that reduces the usable packet size */
68 size_t header_size = 0;
69
70 bool tlsmode = options->tls_server || options->tls_client;
71
72 /* A socks proxy adds 10 byte of extra header to each packet
73 * (we only support Socks with IPv4, this value is different for IPv6) */
75 {
76 header_size += 10;
77 }
78
79 /* TCP stream based packets have a 16 bit length field */
81 {
82 header_size += 2;
83 }
84
85 /* Add the opcode and peerid */
86 if (tlsmode)
87 {
88 header_size += options->use_peer_id ? 4 : 1;
89 }
90
91 unsigned int pkt_id_size = calc_packet_id_size_dc(options, kt);
92
93 /* For figuring out the crypto overhead, we need the size of the payload
94 * including all headers that also get encrypted as part of the payload */
95 header_size += calculate_crypto_overhead(kt, pkt_id_size, occ);
96 return header_size;
97}
98
99
100size_t
102 const struct options *options,
103 const struct key_type *kt)
104{
105 size_t overhead = 0;
106
107 /* This is the overhead of tap device that is not included in the MTU itself
108 * i.e. Ethernet header that we still need to transmit as part of the
109 * payload, this is set to 0 by caller if not applicable */
110 overhead += extra_tun;
111
112#if defined(USE_COMP)
113 /* v1 Compression schemes add 1 byte header. V2 only adds a header when it
114 * does not increase the packet length. We ignore the unlikely escaping
115 * for tap here */
118 {
119 overhead += 1;
120 }
121#endif
122#if defined(ENABLE_FRAGMENT)
123 /* Add the size of the fragment header (uint32_t) */
124 if (options->ce.fragment)
125 {
126 overhead += 4;
127 }
128#endif
129
130 if (cipher_kt_mode_cbc(kt->cipher))
131 {
132 /* The packet id is part of the plain text payload instead of the
133 * cleartext protocol header and needs to be included in the payload
134 * overhead instead of the protocol header */
135 overhead += calc_packet_id_size_dc(options, kt);
136 }
137
138 return overhead;
139}
140
141size_t
143 const struct options *options,
144 const struct key_type *kt)
145{
146 size_t payload_size = options->ce.tun_mtu;
148 return payload_size;
149}
150
151size_t
152calc_options_string_link_mtu(const struct options *o, const struct frame *frame)
153{
154 struct key_type occ_kt;
155
156 /* neither --secret nor TLS mode */
157 if (!o->tls_client && !o->tls_server && !o->shared_secret_file)
158 {
159 init_key_type(&occ_kt, "none", "none", false, false);
160 return frame_calculate_payload_size(frame, o, &occ_kt);
161 }
162
163 /* o->ciphername might be BF-CBC even though the underlying SSL library
164 * does not support it. For this reason we workaround this corner case
165 * by pretending to have no encryption enabled and by manually adding
166 * the required packet overhead to the MTU computation.
167 */
168 const char *ciphername = o->ciphername;
169
170 size_t overhead = 0;
171
172 if (strcmp(o->ciphername, "BF-CBC") == 0)
173 {
174 /* none has no overhead, so use this to later add only --auth
175 * overhead */
176
177 /* overhead of BF-CBC: 64 bit block size, 64 bit IV size */
178 overhead += 64/8 + 64/8;
179 /* set ciphername to none, so its size does get added in the
180 * fake_kt and the cipher is not tried to be resolved */
181 ciphername = "none";
182 }
183
184 /* We pass tlsmode always true here since as we do not need to check if
185 * the ciphers are actually valid for non tls in occ calucation */
186 init_key_type(&occ_kt, ciphername, o->authname, true, false);
187
188 size_t payload = frame_calculate_payload_size(frame, o, &occ_kt);
189 overhead += frame_calculate_protocol_header_size(&occ_kt, o, true);
190
191 return payload + overhead;
192}
193
194void
195frame_print(const struct frame *frame,
196 int level,
197 const char *prefix)
198{
199 struct gc_arena gc = gc_new();
200 struct buffer out = alloc_buf_gc(256, &gc);
201 if (prefix)
202 {
203 buf_printf(&out, "%s ", prefix);
204 }
205 buf_printf(&out, "[");
206 buf_printf(&out, " mss_fix:%" PRIu16, frame->mss_fix);
207#ifdef ENABLE_FRAGMENT
208 buf_printf(&out, " max_frag:%d", frame->max_fragment_size);
209#endif
210 buf_printf(&out, " tun_mtu:%d", frame->tun_mtu);
211 buf_printf(&out, " tun_max_mtu:%d", frame->tun_max_mtu);
212 buf_printf(&out, " headroom:%d", frame->buf.headroom);
213 buf_printf(&out, " payload:%d", frame->buf.payload_size);
214 buf_printf(&out, " tailroom:%d", frame->buf.tailroom);
215 buf_printf(&out, " ET:%d", frame->extra_tun);
216 buf_printf(&out, " ]");
217
218 msg(level, "%s", out.data);
219 gc_free(&gc);
220}
221
222#define MTUDISC_NOT_SUPPORTED_MSG "--mtu-disc is not supported on this OS"
223
224void
226{
227 if (mtu_type >= 0)
228 {
229 switch (proto_af)
230 {
231#if defined(IP_MTU_DISCOVER)
232 case AF_INET:
234 (void *) &mtu_type, sizeof(mtu_type)))
235 {
236 msg(M_ERR, "Error setting IP_MTU_DISCOVER type=%d on TCP/UDP socket",
237 mtu_type);
238 }
239 break;
240
241#endif
242#if defined(IPV6_MTU_DISCOVER)
243 case AF_INET6:
245 (void *) &mtu_type, 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,
277 "invalid --mtu-disc type: '%s' -- valid types are 'yes', 'maybe', or 'no'",
278 name);
279#else /* if defined(IP_PMTUDISC_DONT) && defined(IP_PMTUDISC_WANT) && defined(IP_PMTUDISC_DO) */
281#endif
282 return -1; /* NOTREACHED */
283}
284
285#if EXTENDED_SOCKET_ERROR_CAPABILITY
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 int res;
297 struct probehdr rcvbuf;
298 struct iovec iov;
299 struct msghdr msg;
300 struct cmsghdr *cmsg;
301 struct sock_extended_err *e;
302 struct sockaddr_storage addr;
303 struct buffer out = alloc_buf_gc(256, gc);
304 char *cbuf = (char *) gc_malloc(256, false, gc);
305
306 *mtu = 0;
307
308 while (true)
309 {
310 memset(&rcvbuf, -1, sizeof(rcvbuf));
311 iov.iov_base = &rcvbuf;
312 iov.iov_len = sizeof(rcvbuf);
313 msg.msg_name = (uint8_t *) &addr;
314 msg.msg_namelen = sizeof(addr);
315 msg.msg_iov = &iov;
316 msg.msg_iovlen = 1;
317 msg.msg_flags = 0;
318 msg.msg_control = cbuf;
319 msg.msg_controllen = 256; /* size of cbuf */
320
321 res = recvmsg(fd, &msg, MSG_ERRQUEUE);
322 if (res < 0)
323 {
324 goto exit;
325 }
326
327 e = NULL;
328
330 {
331 if (cmsg->cmsg_level == SOL_IP)
332 {
333 if (cmsg->cmsg_type == IP_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 else if (cmsg->cmsg_level == IPPROTO_IPV6)
343 {
344 if (cmsg->cmsg_type == IPV6_RECVERR)
345 {
346 e = (struct sock_extended_err *) CMSG_DATA(cmsg);
347 }
348 else
349 {
350 buf_printf(&out, "CMSG=%d|", cmsg->cmsg_type);
351 }
352 }
353 }
354 if (e == NULL)
355 {
356 buf_printf(&out, "NO-INFO|");
357 goto exit;
358 }
359
360 switch (e->ee_errno)
361 {
362 case ETIMEDOUT:
363 buf_printf(&out, "ETIMEDOUT|");
364 break;
365
366 case EMSGSIZE:
367 buf_printf(&out, "EMSGSIZE Path-MTU=%d|", e->ee_info);
368 *mtu = e->ee_info;
369 break;
370
371 case ECONNREFUSED:
372 buf_printf(&out, "ECONNREFUSED|");
373 break;
374
375 case EPROTO:
376 buf_printf(&out, "EPROTO|");
377 break;
378
379 case EHOSTUNREACH:
380 buf_printf(&out, "EHOSTUNREACH|");
381 break;
382
383 case ENETUNREACH:
384 buf_printf(&out, "ENETUNREACH|");
385 break;
386
387 case EACCES:
388 buf_printf(&out, "EACCES|");
389 break;
390
391 default:
392 buf_printf(&out, "UNKNOWN|");
393 break;
394 }
395 }
396
397exit:
398 buf_rmtail(&out, '|');
399 return BSTR(&out);
400}
401
402void
403set_sock_extended_error_passing(int sd, sa_family_t proto_af)
404{
405 int on = 1;
406 /* see "man 7 ip" (on Linux)
407 * this works on IPv4 and IPv6(-dual-stack) sockets (v4-mapped)
408 */
409 if (setsockopt(sd, SOL_IP, IP_RECVERR, (void *) &on, sizeof(on)) != 0)
410 {
412 "Note: enable extended error passing on TCP/UDP socket failed (IP_RECVERR)");
413 }
414 /* see "man 7 ipv6" (on Linux)
415 * this only works on IPv6 sockets
416 */
417 if (proto_af == AF_INET6
418 && setsockopt(sd, IPPROTO_IPV6, IPV6_RECVERR, (void *) &on, sizeof(on)) != 0)
419 {
421 "Note: enable extended error passing on TCP/UDP socket failed (IPV6_RECVERR)");
422 }
423}
424
425#endif /* if EXTENDED_SOCKET_ERROR_CAPABILITY */
bool buf_printf(struct buffer *buf, const char *format,...)
Definition buffer.c:240
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:88
struct buffer alloc_buf(size_t size)
Definition buffer.c:62
void buf_rmtail(struct buffer *buf, uint8_t remove)
Definition buffer.c:518
#define BSTR(buf)
Definition buffer.h:129
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:1033
#define buf_init(buf, offset)
Definition buffer.h:209
static struct gc_arena gc_new(void)
Definition buffer.h:1025
#define COMP_ALG_LZ4
Definition comp.h:51
#define COMP_ALG_STUB
Definition comp.h:48
#define COMP_ALG_LZO
Definition comp.h:49
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:819
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:893
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:195
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:142
#define MTUDISC_NOT_SUPPORTED_MSG
Definition mtu.c:222
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:63
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:53
void alloc_buf_sock_tun(struct buffer *buf, const struct frame *frame)
Definition mtu.c:42
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:152
void set_mtu_discover_type(socket_descriptor_t sd, int mtu_type, sa_family_t proto_af)
Definition mtu.c:225
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:101
#define BUF_SIZE(f)
Definition mtu.h:172
#define M_FATAL
Definition error.h:89
#define M_ERR
Definition error.h:105
#define msg(flags,...)
Definition error.h:144
#define ASSERT(x)
Definition error.h:195
#define M_WARN
Definition error.h:91
#define M_ERRNO
Definition error.h:94
static int packet_id_size(bool long_form)
Definition packet_id.h:316
static bool proto_is_udp(int proto)
Returns if the protocol being used is UDP.
Definition socket.h:586
static bool proto_is_tcp(int proto)
returns if the proto is a TCP variant (tcp-server, tcp-client or tcp)
Definition socket.h:606
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:121
int fragment
Definition options.h:139
int proto
Definition options.h:107
int tun_mtu
Definition options.h:125
Packet geometry parameters.
Definition mtu.h:98
int tun_mtu
the (user) configured tun-mtu.
Definition mtu.h:131
int payload_size
the maximum size that a payload that our buffers can hold from either tun device or network link.
Definition mtu.h:102
int tun_max_mtu
the maximum tun-mtu size the buffers are are sized for.
Definition mtu.h:141
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:145
int headroom
the headroom in the buffer, this is choosen to allow all potential header to be added before the pack...
Definition mtu.h:108
uint16_t mss_fix
The actual MSS value that should be written to the payload packets.
Definition mtu.h:118
int max_fragment_size
The maximum size of a fragment.
Definition mtu.h:124
struct frame::@8 buf
int tailroom
the tailroom in the buffer.
Definition mtu.h:112
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:411
bool use_peer_id
Definition options.h:700
const char * authname
Definition options.h:578
struct connection_entry ce
Definition options.h:288
const char * ciphername
Definition options.h:572
bool tls_server
Definition options.h:591
bool tls_client
Definition options.h:592
const char * shared_secret_file
Definition options.h:568
unsigned short sa_family_t
Definition syshead.h:395
#define SOL_IP
Definition syshead.h:388
SOCKET socket_descriptor_t
Definition syshead.h:439
struct gc_arena gc
Definition test_ssl.c:155