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