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