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
8 * Copyright (C) 2002-2005 OpenVPN Solutions LLC <info@openvpn.net>
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.
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.
19 * You should have received a copy of the GNU General Public License
20 * along with this program (see the file COPYING included with this
21 * distribution); if not, write to the Free Software Foundation, Inc.,
22 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #include "config-win32.h"
41 /* allocate a buffer for socket or tun layer */
43 alloc_buf_sock_tun (struct buffer
*buf
,
44 const struct frame
*frame
,
45 const bool tuntap_buffer
,
46 const unsigned int align_mask
)
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));
56 frame_finalize (struct frame
*frame
,
57 bool link_mtu_defined
,
62 /* Set link_mtu based on command line options */
65 ASSERT (!link_mtu_defined
);
66 frame
->link_mtu
= tun_mtu
+ TUN_LINK_DELTA (frame
);
70 ASSERT (link_mtu_defined
);
71 frame
->link_mtu
= link_mtu
;
74 if (TUN_MTU_SIZE (frame
) < TUN_MTU_MIN
)
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");
80 frame
->link_mtu_dynamic
= frame
->link_mtu
;
82 frame
->extra_buffer
+= PAYLOAD_ALIGN
;
86 * Set the tun MTU dynamically.
89 frame_set_mtu_dynamic (struct frame
*frame
, int mtu
, unsigned int flags
)
93 const int orig_mtu
= mtu
;
94 const int orig_link_mtu_dynamic
= frame
->link_mtu_dynamic
;
99 if (flags
& SET_MTU_TUN
)
100 mtu
+= TUN_LINK_DELTA (frame
);
102 if (!(flags
& SET_MTU_UPPER_BOUND
) || mtu
< frame
->link_mtu_dynamic
)
104 frame
->link_mtu_dynamic
= constrain_int (
106 EXPANDED_SIZE_MIN (frame
),
107 EXPANDED_SIZE (frame
));
110 dmsg (D_MTU_DEBUG
, "MTU DYNAMIC mtu=%d, flags=%u, %d -> %d",
113 orig_link_mtu_dynamic
,
114 frame
->link_mtu_dynamic
);
118 * Move extra_frame octets into extra_tun. Used by fragmenting code
119 * to adjust frame relative to its position in the buffer processing
123 frame_subtract_extra (struct frame
*frame
, const struct frame
*src
)
125 frame
->extra_frame
-= src
->extra_frame
;
126 frame
->extra_tun
+= src
->extra_frame
;
130 frame_print (const struct frame
*frame
,
134 struct gc_arena gc
= gc_new ();
135 struct buffer out
= alloc_buf_gc (256, &gc
);
137 buf_printf (&out
, "%s ", prefix
);
138 buf_printf (&out
, "[");
139 buf_printf (&out
, " L:%d", frame
->link_mtu
);
140 buf_printf (&out
, " D:%d", frame
->link_mtu_dynamic
);
141 buf_printf (&out
, " EF:%d", frame
->extra_frame
);
142 buf_printf (&out
, " EB:%d", frame
->extra_buffer
);
143 buf_printf (&out
, " ET:%d", frame
->extra_tun
);
144 buf_printf (&out
, " EL:%d", frame
->extra_link
);
145 if (frame
->align_flags
&& frame
->align_adjust
)
146 buf_printf (&out
, " AF:%u/%d", frame
->align_flags
, frame
->align_adjust
);
147 buf_printf (&out
, " ]");
149 msg (level
, "%s", out
.data
);
153 #define MTUDISC_NOT_SUPPORTED_MSG "--mtu-disc is not supported on this OS"
156 set_mtu_discover_type (int sd
, int mtu_type
)
160 #if defined(HAVE_SETSOCKOPT) && defined(SOL_IP) && defined(IP_MTU_DISCOVER)
162 (sd
, SOL_IP
, IP_MTU_DISCOVER
, &mtu_type
, sizeof (mtu_type
)))
163 msg (M_ERR
, "Error setting IP_MTU_DISCOVER type=%d on TCP/UDP socket",
166 msg (M_FATAL
, MTUDISC_NOT_SUPPORTED_MSG
);
172 translate_mtu_discover_type_name (const char *name
)
174 #if defined(IP_PMTUDISC_DONT) && defined(IP_PMTUDISC_WANT) && defined(IP_PMTUDISC_DO)
175 if (!strcmp (name
, "yes"))
176 return IP_PMTUDISC_DO
;
177 if (!strcmp (name
, "maybe"))
178 return IP_PMTUDISC_WANT
;
179 if (!strcmp (name
, "no"))
180 return IP_PMTUDISC_DONT
;
182 "invalid --mtu-disc type: '%s' -- valid types are 'yes', 'maybe', or 'no'",
185 msg (M_FATAL
, MTUDISC_NOT_SUPPORTED_MSG
);
187 return -1; /* NOTREACHED */
190 #if EXTENDED_SOCKET_ERROR_CAPABILITY
194 * The following code is adapted from tracepath
195 * under the terms of the GPL.
196 * Copyright (C) Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>.
206 format_extended_socket_error (int fd
, int *mtu
, struct gc_arena
*gc
)
209 struct probehdr rcvbuf
;
212 struct cmsghdr
*cmsg
;
213 struct sock_extended_err
*e
;
214 struct sockaddr_in addr
;
215 struct buffer out
= alloc_buf_gc (256, gc
);
216 char *cbuf
= (char *) gc_malloc (256, false, gc
);
222 memset (&rcvbuf
, -1, sizeof (rcvbuf
));
223 iov
.iov_base
= &rcvbuf
;
224 iov
.iov_len
= sizeof (rcvbuf
);
225 msg
.msg_name
= (uint8_t *) &addr
;
226 msg
.msg_namelen
= sizeof (addr
);
230 msg
.msg_control
= cbuf
;
231 msg
.msg_controllen
= 256; /* size of cbuf */
233 res
= recvmsg (fd
, &msg
, MSG_ERRQUEUE
);
239 for (cmsg
= CMSG_FIRSTHDR (&msg
); cmsg
; cmsg
= CMSG_NXTHDR (&msg
, cmsg
))
241 if (cmsg
->cmsg_level
== SOL_IP
)
243 if (cmsg
->cmsg_type
== IP_RECVERR
)
245 e
= (struct sock_extended_err
*) CMSG_DATA (cmsg
);
249 buf_printf (&out
,"CMSG=%d|", cmsg
->cmsg_type
);
255 buf_printf (&out
, "NO-INFO|");
262 buf_printf (&out
, "ETIMEDOUT|");
265 buf_printf (&out
, "EMSGSIZE Path-MTU=%d|", e
->ee_info
);
269 buf_printf (&out
, "ECONNREFUSED|");
272 buf_printf (&out
, "EPROTO|");
275 buf_printf (&out
, "EHOSTUNREACH|");
278 buf_printf (&out
, "ENETUNREACH|");
281 buf_printf (&out
, "EACCES|");
284 buf_printf (&out
, "UNKNOWN|");
290 buf_rmtail (&out
, '|');
295 set_sock_extended_error_passing (int sd
)
298 if (setsockopt (sd
, SOL_IP
, IP_RECVERR
, &on
, sizeof (on
)))
299 msg (M_WARN
| M_ERRNO
,
300 "Note: enable extended error passing on TCP/UDP socket failed (IP_RECVERR)");