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 #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 */
41 void
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 
52 unsigned int
53 calc_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 
62 size_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 
100 size_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 */
117  || options->comp.alg == COMP_ALG_LZO)
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 
141 size_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 
151 size_t
152 calc_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 
194 void
195 frame_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 
224 void
226 {
227  if (mtu_type >= 0)
228  {
229  switch (proto_af)
230  {
231 #if defined(IP_MTU_DISCOVER)
232  case AF_INET:
233  if (setsockopt(sd, IPPROTO_IP, IP_MTU_DISCOVER,
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:
244  if (setsockopt(sd, IPPROTO_IPV6, IPV6_MTU_DISCOVER,
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 
260 int
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 
287 struct probehdr
288 {
289  uint32_t ttl;
290  struct timeval tv;
291 };
292 
293 const char *
294 format_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 
329  for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg))
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 
397 exit:
398  buf_rmtail(&out, '|');
399  return BSTR(&out);
400 }
401 
402 void
403 set_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  {
411  msg(M_WARN | M_ERRNO,
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  {
420  msg(M_WARN | M_ERRNO,
421  "Note: enable extended error passing on TCP/UDP socket failed (IPV6_RECVERR)");
422  }
423 }
424 
425 #endif /* if EXTENDED_SOCKET_ERROR_CAPABILITY */
buf_safe
static bool buf_safe(const struct buffer *buf, size_t len)
Definition: buffer.h:538
compress_options::alg
int alg
Definition: comp.h:66
buf_rmtail
void buf_rmtail(struct buffer *buf, uint8_t remove)
Definition: buffer.c:562
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:1031
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:195
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:142
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:101
BSTR
#define BSTR(buf)
Definition: buffer.h:129
options::authname
const char * authname
Definition: options.h:561
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:88
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:63
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:261
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:152
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:222
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:783
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:42
key_type::cipher
const char * cipher
const name of the cipher
Definition: crypto.h:141
socket_descriptor_t
SOCKET socket_descriptor_t
Definition: syshead.h:429
common.h
COMP_ALG_STUB
#define COMP_ALG_STUB
Definition: comp.h:46
frame::mss_fix
uint16_t mss_fix
The actual MSS value that should be written to the payload packets.
Definition: mtu.h:118
gc_malloc
void * gc_malloc(size_t size, bool clear, struct gc_arena *a)
Definition: buffer.c:380
set_mtu_discover_type
void set_mtu_discover_type(socket_descriptor_t sd, int mtu_type, sa_family_t proto_af)
Definition: mtu.c:225
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:1039
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:53
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:768
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:670
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:744
COMP_ALG_LZO
#define COMP_ALG_LZO
Definition: comp.h:47
alloc_buf
struct buffer alloc_buf(size_t size)
Definition: buffer.c:62
connection_entry::tun_mtu
int tun_mtu
Definition: options.h:118
memdbg.h
options::ciphername
const char * ciphername
Definition: options.h:557
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:240
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