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-2018 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 
39 #include "memdbg.h"
40 
41 /* allocate a buffer for socket or tun layer */
42 void
44  const struct frame *frame,
45  const bool tuntap_buffer,
46  const unsigned int align_mask)
47 {
48  /* allocate buffer for overlapped I/O */
49  *buf = alloc_buf(BUF_SIZE(frame));
50  ASSERT(buf_init(buf, FRAME_HEADROOM_ADJ(frame, align_mask)));
51  buf->len = tuntap_buffer ? MAX_RW_SIZE_TUN(frame) : MAX_RW_SIZE_LINK(frame);
52  ASSERT(buf_safe(buf, 0));
53 }
54 
55 void
57  bool link_mtu_defined,
58  int link_mtu,
59  bool tun_mtu_defined,
60  int tun_mtu)
61 {
62  /* Set link_mtu based on command line options */
63  if (tun_mtu_defined)
64  {
65  ASSERT(!link_mtu_defined);
66  frame->link_mtu = tun_mtu + TUN_LINK_DELTA(frame);
67  }
68  else
69  {
70  ASSERT(link_mtu_defined);
71  frame->link_mtu = link_mtu;
72  }
73 
74  if (TUN_MTU_SIZE(frame) < TUN_MTU_MIN)
75  {
76  msg(M_WARN, "TUN MTU value (%d) must be at least %d", TUN_MTU_SIZE(frame), TUN_MTU_MIN);
77  frame_print(frame, M_FATAL, "MTU is too small");
78  }
79 
80  frame->link_mtu_dynamic = frame->link_mtu;
81 }
82 
83 /*
84  * Set the tun MTU dynamically.
85  */
86 void
87 frame_set_mtu_dynamic(struct frame *frame, int mtu, unsigned int flags)
88 {
89 
90 #ifdef ENABLE_DEBUG
91  const int orig_mtu = mtu;
92  const int orig_link_mtu_dynamic = frame->link_mtu_dynamic;
93 #endif
94 
95  ASSERT(mtu >= 0);
96 
97  if (flags & SET_MTU_TUN)
98  {
99  mtu += TUN_LINK_DELTA(frame);
100  }
101 
102  if (!(flags & SET_MTU_UPPER_BOUND) || mtu < frame->link_mtu_dynamic)
103  {
105  mtu,
106  EXPANDED_SIZE_MIN(frame),
107  EXPANDED_SIZE(frame));
108  }
109 
110  dmsg(D_MTU_DEBUG, "MTU DYNAMIC mtu=%d, flags=%u, %d -> %d",
111  orig_mtu,
112  flags,
113  orig_link_mtu_dynamic,
114  frame->link_mtu_dynamic);
115 }
116 
117 /*
118  * Move extra_frame octets into extra_tun. Used by fragmenting code
119  * to adjust frame relative to its position in the buffer processing
120  * queue.
121  */
122 void
123 frame_subtract_extra(struct frame *frame, const struct frame *src)
124 {
125  frame->extra_frame -= src->extra_frame;
126  frame->extra_tun += src->extra_frame;
127 }
128 
129 void
130 frame_init_mssfix(struct frame *frame, const struct options *options)
131 {
132  if (options->ce.mssfix)
133  {
135  }
136 }
137 
138 void
139 frame_print(const struct frame *frame,
140  int level,
141  const char *prefix)
142 {
143  struct gc_arena gc = gc_new();
144  struct buffer out = alloc_buf_gc(256, &gc);
145  if (prefix)
146  {
147  buf_printf(&out, "%s ", prefix);
148  }
149  buf_printf(&out, "[");
150  buf_printf(&out, " L:%d", frame->link_mtu);
151  buf_printf(&out, " D:%d", frame->link_mtu_dynamic);
152  buf_printf(&out, " EF:%d", frame->extra_frame);
153  buf_printf(&out, " EB:%d", frame->extra_buffer);
154  buf_printf(&out, " ET:%d", frame->extra_tun);
155  buf_printf(&out, " EL:%d", frame->extra_link);
156  if (frame->align_flags && frame->align_adjust)
157  {
158  buf_printf(&out, " AF:%u/%d", frame->align_flags, frame->align_adjust);
159  }
160  buf_printf(&out, " ]");
161 
162  msg(level, "%s", out.data);
163  gc_free(&gc);
164 }
165 
166 #define MTUDISC_NOT_SUPPORTED_MSG "--mtu-disc is not supported on this OS"
167 
168 void
169 set_mtu_discover_type(int sd, int mtu_type, sa_family_t proto_af)
170 {
171  if (mtu_type >= 0)
172  {
173  switch (proto_af)
174  {
175 #if defined(HAVE_SETSOCKOPT) && defined(IP_MTU_DISCOVER)
176  case AF_INET:
177  if (setsockopt
178  (sd, IPPROTO_IP, IP_MTU_DISCOVER, &mtu_type, sizeof(mtu_type)))
179  {
180  msg(M_ERR, "Error setting IP_MTU_DISCOVER type=%d on TCP/UDP socket",
181  mtu_type);
182  }
183  break;
184 
185 #endif
186 #if defined(HAVE_SETSOCKOPT) && defined(IPV6_MTU_DISCOVER)
187  case AF_INET6:
188  if (setsockopt
189  (sd, IPPROTO_IPV6, IPV6_MTU_DISCOVER, &mtu_type, sizeof(mtu_type)))
190  {
191  msg(M_ERR, "Error setting IPV6_MTU_DISCOVER type=%d on TCP6/UDP6 socket",
192  mtu_type);
193  }
194  break;
195 
196 #endif
197  default:
199  break;
200  }
201  }
202 }
203 
204 int
206 {
207 #if defined(IP_PMTUDISC_DONT) && defined(IP_PMTUDISC_WANT) && defined(IP_PMTUDISC_DO)
208  if (!strcmp(name, "yes"))
209  {
210  return IP_PMTUDISC_DO;
211  }
212  if (!strcmp(name, "maybe"))
213  {
214  return IP_PMTUDISC_WANT;
215  }
216  if (!strcmp(name, "no"))
217  {
218  return IP_PMTUDISC_DONT;
219  }
220  msg(M_FATAL,
221  "invalid --mtu-disc type: '%s' -- valid types are 'yes', 'maybe', or 'no'",
222  name);
223 #else /* if defined(IP_PMTUDISC_DONT) && defined(IP_PMTUDISC_WANT) && defined(IP_PMTUDISC_DO) */
225 #endif
226  return -1; /* NOTREACHED */
227 }
228 
229 #if EXTENDED_SOCKET_ERROR_CAPABILITY
230 
231 struct probehdr
232 {
233  uint32_t ttl;
234  struct timeval tv;
235 };
236 
237 const char *
238 format_extended_socket_error(int fd, int *mtu, struct gc_arena *gc)
239 {
240  int res;
241  struct probehdr rcvbuf;
242  struct iovec iov;
243  struct msghdr msg;
244  struct cmsghdr *cmsg;
245  struct sock_extended_err *e;
246  struct sockaddr_in addr;
247  struct buffer out = alloc_buf_gc(256, gc);
248  char *cbuf = (char *) gc_malloc(256, false, gc);
249 
250  *mtu = 0;
251 
252  while (true)
253  {
254  memset(&rcvbuf, -1, sizeof(rcvbuf));
255  iov.iov_base = &rcvbuf;
256  iov.iov_len = sizeof(rcvbuf);
257  msg.msg_name = (uint8_t *) &addr;
258  msg.msg_namelen = sizeof(addr);
259  msg.msg_iov = &iov;
260  msg.msg_iovlen = 1;
261  msg.msg_flags = 0;
262  msg.msg_control = cbuf;
263  msg.msg_controllen = 256; /* size of cbuf */
264 
265  res = recvmsg(fd, &msg, MSG_ERRQUEUE);
266  if (res < 0)
267  {
268  goto exit;
269  }
270 
271  e = NULL;
272 
273  for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg))
274  {
275  if (cmsg->cmsg_level == SOL_IP)
276  {
277  if (cmsg->cmsg_type == IP_RECVERR)
278  {
279  e = (struct sock_extended_err *) CMSG_DATA(cmsg);
280  }
281  else
282  {
283  buf_printf(&out,"CMSG=%d|", cmsg->cmsg_type);
284  }
285  }
286  }
287  if (e == NULL)
288  {
289  buf_printf(&out, "NO-INFO|");
290  goto exit;
291  }
292 
293  switch (e->ee_errno)
294  {
295  case ETIMEDOUT:
296  buf_printf(&out, "ETIMEDOUT|");
297  break;
298 
299  case EMSGSIZE:
300  buf_printf(&out, "EMSGSIZE Path-MTU=%d|", e->ee_info);
301  *mtu = e->ee_info;
302  break;
303 
304  case ECONNREFUSED:
305  buf_printf(&out, "ECONNREFUSED|");
306  break;
307 
308  case EPROTO:
309  buf_printf(&out, "EPROTO|");
310  break;
311 
312  case EHOSTUNREACH:
313  buf_printf(&out, "EHOSTUNREACH|");
314  break;
315 
316  case ENETUNREACH:
317  buf_printf(&out, "ENETUNREACH|");
318  break;
319 
320  case EACCES:
321  buf_printf(&out, "EACCES|");
322  break;
323 
324  default:
325  buf_printf(&out, "UNKNOWN|");
326  break;
327  }
328  }
329 
330 exit:
331  buf_rmtail(&out, '|');
332  return BSTR(&out);
333 }
334 
335 void
336 set_sock_extended_error_passing(int sd)
337 {
338  int on = 1;
339  if (setsockopt(sd, SOL_IP, IP_RECVERR, (void *) &on, sizeof(on)))
340  {
341  msg(M_WARN | M_ERRNO,
342  "Note: enable extended error passing on TCP/UDP socket failed (IP_RECVERR)");
343  }
344 }
345 
346 #endif /* if EXTENDED_SOCKET_ERROR_CAPABILITY */
void frame_subtract_extra(struct frame *frame, const struct frame *src)
Definition: mtu.c:123
#define SET_MTU_TUN
Definition: mtu.h:220
Packet geometry parameters.
Definition: mtu.h:93
static void gc_free(struct gc_arena *a)
Definition: buffer.h:1023
#define EXPANDED_SIZE_MIN(f)
Definition: mtu.h:174
#define dmsg
Definition: error.h:174
static bool buf_safe(const struct buffer *buf, int len)
Definition: buffer.h:541
unsigned short sa_family_t
Definition: syshead.h:447
#define SET_MTU_UPPER_BOUND
Definition: mtu.h:221
struct buffer alloc_buf(size_t size)
Definition: buffer.c:64
bool buf_printf(struct buffer *buf, const char *format,...)
Definition: buffer.c:245
void set_mtu_discover_type(int sd, int mtu_type, sa_family_t proto_af)
Definition: mtu.c:169
#define ASSERT(x)
Definition: error.h:221
#define FRAME_HEADROOM_ADJ(f, fm)
Definition: mtu.h:188
list flags
int len
Length in bytes of the actual content within the allocated memory.
Definition: buffer.h:66
#define BUF_SIZE(f)
Definition: mtu.h:194
void frame_print(const struct frame *frame, int level, const char *prefix)
Definition: mtu.c:139
static struct gc_arena gc_new(void)
Definition: buffer.h:1015
int extra_buffer
Maximum number of bytes that processing steps could expand the internal work buffer.
Definition: mtu.h:107
int extra_link
Maximum number of bytes in excess of external network interface&#39;s MTU that might be read from or writ...
Definition: mtu.h:122
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:117
int mssfix
Definition: options.h:118
void * gc_malloc(size_t size, bool clear, struct gc_arena *a)
Definition: buffer.c:408
void frame_init_mssfix(struct frame *frame, const struct options *options)
Set the –mssfix option.
Definition: mtu.c:130
unsigned __int32 uint32_t
Definition: config-msvc.h:121
#define TUN_MTU_SIZE(f)
Definition: mtu.h:156
#define EXPANDED_SIZE(f)
Definition: mtu.h:172
int align_adjust
Definition: mtu.h:134
#define M_ERRNO
Definition: error.h:99
#define msg
Definition: error.h:173
struct connection_entry ce
Definition: options.h:213
#define MAX_RW_SIZE_LINK(f)
Definition: mtu.h:181
uint8_t * data
Pointer to the allocated memory.
Definition: buffer.h:68
#define MTUDISC_NOT_SUPPORTED_MSG
Definition: mtu.c:166
int translate_mtu_discover_type_name(const char *name)
Definition: mtu.c:205
int extra_frame
Maximum number of bytes that all processing steps together could add.
Definition: mtu.h:100
void alloc_buf_sock_tun(struct buffer *buf, const struct frame *frame, const bool tuntap_buffer, const unsigned int align_mask)
Definition: mtu.c:43
#define TUN_MTU_MIN
Definition: mtu.h:60
unsigned __int8 uint8_t
Definition: config-msvc.h:123
unsigned int align_flags
Definition: mtu.h:133
void frame_set_mtu_dynamic(struct frame *frame, int mtu, unsigned int flags)
Definition: mtu.c:87
#define M_ERR
Definition: error.h:110
#define D_MTU_DEBUG
Definition: errlevel.h:122
Wrapper structure for dynamically allocated memory.
Definition: buffer.h:60
#define M_FATAL
Definition: error.h:94
#define buf_init(buf, offset)
Definition: buffer.h:196
void frame_finalize(struct frame *frame, bool link_mtu_defined, int link_mtu, bool tun_mtu_defined, int tun_mtu)
Definition: mtu.c:56
void buf_rmtail(struct buffer *buf, uint8_t remove)
Definition: buffer.c:557
#define MAX_RW_SIZE_TUN(f)
Definition: mtu.h:180
int link_mtu
Maximum packet size to be sent over the external network interface.
Definition: mtu.h:94
struct buffer alloc_buf_gc(size_t size, struct gc_arena *gc)
Definition: buffer.c:90
static int constrain_int(int x, int min, int max)
Definition: integer.h:70
#define M_WARN
Definition: error.h:96
#define SOL_IP
Definition: syshead.h:440
Garbage collection arena used to keep track of dynamically allocated memory.
Definition: buffer.h:116
#define BSTR(buf)
Definition: buffer.h:129
#define TUN_LINK_DELTA(f)
Definition: mtu.h:151
int link_mtu_dynamic
Dynamic MTU value for the external network interface.
Definition: mtu.h:97