added MTU discovery and adjustment in IPv6

This commit is contained in:
Nikos Mavrogiannopoulos
2015-05-09 02:04:41 +02:00
committed by Nikos Mavrogiannopoulos
parent 0ca7389c5d
commit a80a07fa53
3 changed files with 68 additions and 23 deletions

View File

@@ -110,6 +110,19 @@ int y;
(const void *) &y, sizeof(y)) < 0)
perror("setsockopt(IP_DF) failed");
#endif
if (family == AF_INET6) {
#if defined(IPV6_DONTFRAG)
y = 1;
if (setsockopt(fd, IPPROTO_IPV6, IPV6_DONTFRAG,
(const void *) &y, sizeof(y)) < 0)
perror("setsockopt(IPV6_DF) failed");
#elif defined(IPV6_MTU_DISCOVER)
y = IP_PMTUDISC_DO;
if (setsockopt(fd, IPPROTO_IPV6, IPV6_MTU_DISCOVER,
(const void *) &y, sizeof(y)) < 0)
perror("setsockopt(IPV6_DF) failed");
#endif
}
}
#if defined(IP_PKTINFO)
y = 1;

View File

@@ -628,26 +628,54 @@ void mtu_set(worker_st * ws, unsigned mtu)
static
int mtu_not_ok(worker_st * ws)
{
unsigned min = MIN_MTU(ws);
if (ws->proto == AF_INET) {
unsigned min = MIN_MTU(ws);
ws->last_bad_mtu = ws->conn_mtu;
ws->last_bad_mtu = ws->conn_mtu;
if (ws->last_good_mtu == min) {
oclog(ws, LOG_INFO,
"could not calculate a sufficient MTU. Disabling DTLS.");
dtls_close(ws);
ws->udp_state = UP_DISABLED;
return -1;
if (ws->last_good_mtu == min) {
oclog(ws, LOG_INFO,
"could not calculate a sufficient MTU; disabling DTLS");
dtls_close(ws);
ws->udp_state = UP_DISABLED;
return -1;
}
if (ws->last_good_mtu >= ws->conn_mtu) {
ws->last_good_mtu = MAX(((2 * (ws->conn_mtu)) / 3), min);
}
mtu_set(ws, ws->last_good_mtu);
oclog(ws, LOG_DEBUG, "MTU %u is too large, switching to %u",
ws->last_bad_mtu, ws->conn_mtu);
} else if (ws->proto == AF_INET6) { /* IPv6 */
int mtu;
socklen_t len = sizeof(mtu);
if (getsockopt(ws->dtls_tptr.fd, IPPROTO_IPV6, IPV6_MTU, &mtu, &len) < 0 || mtu < 1280) {
oclog(ws, LOG_INFO, "cannot obtain IPv6 MTU (was %u); disabling DTLS",
ws->conn_mtu);
dtls_close(ws);
ws->udp_state = UP_DISABLED;
return -1;
}
mtu -= CSTP_DTLS_OVERHEAD - ws->proto_overhead;
if (mtu >= ws->conn_mtu) {
oclog(ws, LOG_INFO, "the provided IPv6 MTU is larger than the used (was %u, new %d); disabling DTLS",
ws->conn_mtu, mtu);
dtls_close(ws);
ws->udp_state = UP_DISABLED;
return -1;
}
if (ws->dtls_session) {
gnutls_dtls_set_mtu(ws->dtls_session, mtu);
ws->conn_mtu = gnutls_dtls_get_data_mtu(session);
mtu_send(ws, ws->conn_mtu);
}
}
if (ws->last_good_mtu >= ws->conn_mtu) {
ws->last_good_mtu = MAX(((2 * (ws->conn_mtu)) / 3), min);
}
mtu_set(ws, ws->last_good_mtu);
oclog(ws, LOG_DEBUG, "MTU %u is too large, switching to %u",
ws->last_bad_mtu, ws->conn_mtu);
return 0;
}
@@ -667,6 +695,9 @@ void mtu_ok(worker_st * ws)
{
unsigned int c;
if (ws->proto == AF_INET6)
return;
if (ws->last_bad_mtu == (ws->conn_mtu) + 1 ||
ws->last_bad_mtu == (ws->conn_mtu))
return;
@@ -1240,7 +1271,7 @@ static int connect_handler(worker_st * ws)
#endif
unsigned tls_pending, dtls_pending = 0, i;
struct timespec tnow;
unsigned proto_overhead = 0, ip6;
unsigned ip6;
socklen_t sl;
sigset_t emptyset, blockset;
@@ -1665,10 +1696,10 @@ static int connect_handler(worker_st * ws)
/* assume that if IPv6 is used over TCP then the same would be used over UDP */
if (ws->proto == AF_INET)
proto_overhead = 20; /* ip */
ws->proto_overhead = 20; /* ip */
else
proto_overhead = 40; /* ipv6 */
proto_overhead += 8; /* udp */
ws->proto_overhead = 40; /* ipv6 */
ws->proto_overhead += 8; /* udp */
/* crypto overhead for DTLS */
ws->crypto_overhead =
@@ -1681,14 +1712,14 @@ static int connect_handler(worker_st * ws)
oclog(ws, LOG_DEBUG,
"DTLS overhead is %u",
proto_overhead + ws->crypto_overhead);
ws->proto_overhead + ws->crypto_overhead);
/* plaintext MTU is the device MTU minus the overhead
* of the DTLS (+AnyConnect header) protocol.
*/
ws->conn_mtu =
MIN(ws->conn_mtu,
ws->vinfo.mtu - proto_overhead - ws->crypto_overhead);
ws->vinfo.mtu - ws->proto_overhead - ws->crypto_overhead);
ret =
cstp_printf(ws, "X-DTLS-MTU: %u\r\n", ws->conn_mtu);
@@ -1831,7 +1862,7 @@ static int connect_handler(worker_st * ws)
gettime(&tnow);
if (periodic_check
(ws, proto_overhead + ws->crypto_overhead, tnow.tv_sec,
(ws, ws->proto_overhead + ws->crypto_overhead, tnow.tv_sec,
ws->config->dpd) < 0)
goto exit;

View File

@@ -222,6 +222,7 @@ typedef struct worker_st {
* and the DTLS crypto overhead. */
unsigned conn_mtu;
unsigned crypto_overhead; /* estimated overhead of DTLS ciphersuite + DTLS CSTP HEADER */
unsigned proto_overhead; /* UDP + IP header size */
/* Indicates whether the new IPv6 headers will
* be sent or the old */