Let tinc figure out the exact MTU of the link.

This commit is contained in:
Guus Sliepen 2003-12-20 19:47:53 +00:00
parent e8fbef5de6
commit 6b12bea62f
12 changed files with 193 additions and 78 deletions

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: connection.h,v 1.1.2.38 2003/11/17 15:30:16 guus Exp $
$Id: connection.h,v 1.1.2.39 2003/12/20 19:47:52 guus Exp $
*/
#ifndef __TINC_CONNECTION_H__
@ -30,6 +30,7 @@
#define OPTION_INDIRECT 0x0001
#define OPTION_TCPONLY 0x0002
#define OPTION_DONTFRAGMENT 0x0004
typedef struct connection_status_t {
int pinged:1; /* sent ping */

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: graph.c,v 1.1.2.30 2003/10/10 16:23:30 guus Exp $
$Id: graph.c,v 1.1.2.31 2003/12/20 19:47:52 guus Exp $
*/
/* We need to generate two trees from the graph:
@ -229,6 +229,12 @@ void sssp_bfs(void)
e->to->hostname = sockaddr2hostname(&e->to->address);
avl_insert_node(node_udp_tree, node);
if(e->to->options & OPTION_DONTFRAGMENT) {
e->to->mtuprobes = 0;
if(e->to->status.validkey)
send_mtu_probe(e->to);
}
}
node = avl_alloc_node();

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: net.c,v 1.35.4.202 2003/12/12 19:52:24 guus Exp $
$Id: net.c,v 1.35.4.203 2003/12/20 19:47:52 guus Exp $
*/
#include "system.h"
@ -334,7 +334,8 @@ int main_loop(void)
while(running) {
now = time(NULL);
tv.tv_sec = 1 + (rand() & 7); /* Approx. 5 seconds, randomized to prevent global synchronisation effects */
// tv.tv_sec = 1 + (rand() & 7); /* Approx. 5 seconds, randomized to prevent global synchronisation effects */
tv.tv_sec = 1;
tv.tv_usec = 0;
maxfd = build_fdset(&fset);

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: net.h,v 1.9.4.72 2003/10/08 12:09:37 guus Exp $
$Id: net.h,v 1.9.4.73 2003/12/20 19:47:52 guus Exp $
*/
#ifndef __TINC_NET_H__
@ -150,6 +150,7 @@ extern int main_loop(void);
extern void terminate_connection(struct connection_t *, bool);
extern void flush_queue(struct node_t *);
extern bool read_rsa_public_key(struct connection_t *);
extern void send_mtu_probe(struct node_t *);
#ifndef HAVE_MINGW
#define closesocket(s) close(s)

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: net_packet.c,v 1.1.2.44 2003/12/12 19:52:25 guus Exp $
$Id: net_packet.c,v 1.1.2.45 2003/12/20 19:47:52 guus Exp $
*/
#include "system.h"
@ -52,9 +52,58 @@ int keyexpires = 0;
EVP_CIPHER_CTX packet_ctx;
static char lzo_wrkmem[LZO1X_999_MEM_COMPRESS > LZO1X_1_MEM_COMPRESS ? LZO1X_999_MEM_COMPRESS : LZO1X_1_MEM_COMPRESS];
static void send_udppacket(node_t *, vpn_packet_t *);
#define MAX_SEQNO 1073741824
void send_mtu_probe(node_t *n)
{
vpn_packet_t packet;
int len, i;
cp();
n->mtuprobes++;
for(i = 0; i < 3; i++) {
if(n->mtuprobes >= 100 || n->probedmtu >= n->mtu) {
n->mtu = n->probedmtu;
ifdebug(TRAFFIC) logger(LOG_INFO, _("Fixing MTU of %s (%s) to %d after %d probes"), n->name, n->hostname, n->mtu, n->mtuprobes);
return;
}
len = n->probedmtu + 1 + random() % (n->mtu - n->probedmtu);
if(len < 64)
len = 64;
memset(packet.data, 0, 14);
RAND_pseudo_bytes(packet.data + 14, len - 14);
packet.len = len;
ifdebug(TRAFFIC) logger(LOG_INFO, _("Sending MTU probe length %d to %s (%s)"), len, n->name, n->hostname);
send_udppacket(n, &packet);
}
n->mtuevent = xmalloc(sizeof(*n->mtuevent));
n->mtuevent->handler = (event_handler_t)send_mtu_probe;
n->mtuevent->data = n;
n->mtuevent->time = now + 1;
event_add(n->mtuevent);
}
void mtu_probe_h(node_t *n, vpn_packet_t *packet) {
ifdebug(TRAFFIC) logger(LOG_INFO, _("Got MTU probe length %d from %s (%s)"), packet->len, n->name, n->hostname);
if(!packet->data[0]) {
packet->data[0] = 1;
send_packet(n, packet);
} else {
if(n->probedmtu < packet->len)
n->probedmtu = packet->len;
}
}
static length_t compress_packet(uint8_t *dest, const uint8_t *source, length_t len, int level)
{
if(level == 10) {
@ -203,6 +252,9 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt)
if(n->connection)
n->connection->last_ping_time = now;
if(!inpkt->data[12] && !inpkt->data[13])
mtu_probe_h(n, inpkt);
else
receive_packet(n, inpkt);
}
@ -328,6 +380,10 @@ static void send_udppacket(node_t *n, vpn_packet_t *inpkt)
if((sendto(listen_socket[sock].udp, (char *) &inpkt->seqno, inpkt->len, 0, &(n->address.sa), SALEN(n->address.sa))) < 0) {
logger(LOG_ERR, _("Error sending packet to %s (%s): %s"), n->name, n->hostname, strerror(errno));
if(errno == EMSGSIZE) {
if(n->mtu >= origlen)
n->mtu = origlen - 1;
}
return;
}

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: net_setup.c,v 1.1.2.47 2003/12/07 14:28:39 guus Exp $
$Id: net_setup.c,v 1.1.2.48 2003/12/20 19:47:52 guus Exp $
*/
#include "system.h"
@ -272,22 +272,21 @@ bool setup_myself(void)
/* Check some options */
if(get_config_bool(lookup_config(config_tree, "IndirectData"), &choice))
if(choice)
if(get_config_bool(lookup_config(config_tree, "IndirectData"), &choice) && choice)
myself->options |= OPTION_INDIRECT;
if(get_config_bool(lookup_config(config_tree, "TCPOnly"), &choice))
if(choice)
if(get_config_bool(lookup_config(config_tree, "TCPOnly"), &choice) && choice)
myself->options |= OPTION_TCPONLY;
if(get_config_bool(lookup_config(myself->connection->config_tree, "IndirectData"), &choice))
if(choice)
if(get_config_bool(lookup_config(myself->connection->config_tree, "IndirectData"), &choice) && choice)
myself->options |= OPTION_INDIRECT;
if(get_config_bool(lookup_config(myself->connection->config_tree, "TCPOnly"), &choice))
if(choice)
if(get_config_bool(lookup_config(myself->connection->config_tree, "TCPOnly"), &choice) && choice)
myself->options |= OPTION_TCPONLY;
if(get_config_bool(lookup_config(myself->connection->config_tree, "DontFragment"), &choice) && choice)
myself->options |= OPTION_DONTFRAGMENT;
if(myself->options & OPTION_TCPONLY)
myself->options |= OPTION_INDIRECT;

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: net_socket.c,v 1.1.2.35 2003/12/12 19:52:25 guus Exp $
$Id: net_socket.c,v 1.1.2.36 2003/12/20 19:47:52 guus Exp $
*/
#include "system.h"
@ -49,13 +49,10 @@ int listen_sockets;
int setup_listen_socket(const sockaddr_t *sa)
{
int nfd, flags;
int nfd;
char *addrstr;
int option;
char *iface;
#ifdef SO_BINDTODEVICE
struct ifreq ifr;
#endif
cp();
@ -67,7 +64,8 @@ int setup_listen_socket(const sockaddr_t *sa)
}
#ifdef O_NONBLOCK
flags = fcntl(nfd, F_GETFL);
{
int flags = fcntl(nfd, F_GETFL);
if(fcntl(nfd, F_SETFL, flags | O_NONBLOCK) < 0) {
closesocket(nfd);
@ -75,6 +73,7 @@ int setup_listen_socket(const sockaddr_t *sa)
strerror(errno));
return -1;
}
}
#endif
/* Optimize TCP settings */
@ -94,6 +93,8 @@ int setup_listen_socket(const sockaddr_t *sa)
if(get_config_string
(lookup_config(config_tree, "BindToInterface"), &iface)) {
#if defined(SOL_SOCKET) && defined(SO_BINDTODEVICE)
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_ifrn.ifrn_name, iface, IFNAMSIZ);
@ -129,13 +130,9 @@ int setup_listen_socket(const sockaddr_t *sa)
int setup_vpn_in_socket(const sockaddr_t *sa)
{
int nfd, flags;
int nfd;
char *addrstr;
int option;
#if defined(SOL_SOCKET) && defined(SO_BINDTODEVICE)
char *iface;
struct ifreq ifr;
#endif
cp();
@ -147,21 +144,42 @@ int setup_vpn_in_socket(const sockaddr_t *sa)
}
#ifdef O_NONBLOCK
flags = fcntl(nfd, F_GETFL);
{
int flags = fcntl(nfd, F_GETFL);
if(fcntl(nfd, F_SETFL, flags | O_NONBLOCK) < 0) {
closesocket(nfd);
logger(LOG_ERR, _("System call `%s' failed: %s"), "fcntl",
strerror(errno));
return -1;
}
}
#endif
option = 1;
setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));
#if defined(SOL_IP) && defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO)
{
bool choice;
if(get_config_bool(lookup_config(myself->connection->config_tree, "DontFragment"), &choice) && choice) {
option = IP_PMTUDISC_DO;
if(setsockopt(nfd, SOL_IP, IP_MTU_DISCOVER, &option, sizeof(option))) {
closesocket(nfd);
logger(LOG_ERR, _("Can't set MTU discovery mode: %s"), strerror(errno));
return -1;
}
}
}
#endif
#if defined(SOL_SOCKET) && defined(SO_BINDTODEVICE)
if(get_config_string
(lookup_config(config_tree, "BindToInterface"), &iface)) {
{
char *iface;
struct ifreq ifr;
if(get_config_string(lookup_config(config_tree, "BindToInterface"), &iface)) {
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_ifrn.ifrn_name, iface, IFNAMSIZ);
@ -172,6 +190,7 @@ int setup_vpn_in_socket(const sockaddr_t *sa)
return -1;
}
}
}
#endif
if(bind(nfd, &sa->sa, SALEN(sa->sa))) {

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: node.c,v 1.1.2.28 2003/08/28 21:05:10 guus Exp $
$Id: node.c,v 1.1.2.29 2003/12/20 19:47:52 guus Exp $
*/
#include "system.h"
@ -80,6 +80,7 @@ node_t *new_node(void)
n->edge_tree = new_edge_tree();
n->queue = list_alloc((list_action_t) free);
EVP_CIPHER_CTX_init(&n->packet_ctx);
n->mtu = MTU;
return n;
}

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: node.h,v 1.1.2.29 2003/07/30 21:52:41 guus Exp $
$Id: node.h,v 1.1.2.30 2003/12/20 19:47:52 guus Exp $
*/
#ifndef __TINC_NODE_H__
@ -25,6 +25,7 @@
#include "avl_tree.h"
#include "connection.h"
#include "event.h"
#include "list.h"
#include "subnet.h"
@ -71,6 +72,11 @@ typedef struct node_t {
uint32_t sent_seqno; /* Sequence number last sent to this node */
uint32_t received_seqno; /* Sequence number last received from this node */
unsigned char late[16]; /* Bitfield marking late packets */
length_t mtu; /* Maximum size of packets to send to this node */
length_t probedmtu; /* Probed MTU */
int mtuprobes; /* Number of probes */
event_t *mtuevent; /* Probe event */
} node_t;
extern struct node_t *myself;

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: protocol_auth.c,v 1.1.4.30 2003/11/17 15:30:18 guus Exp $
$Id: protocol_auth.c,v 1.1.4.31 2003/12/20 19:47:52 guus Exp $
*/
#include "system.h"
@ -476,6 +476,9 @@ bool send_ack(connection_t *c)
if((get_config_bool(lookup_config(c->config_tree, "TCPOnly"), &choice) && choice) || myself->options & OPTION_TCPONLY)
c->options |= OPTION_TCPONLY | OPTION_INDIRECT;
if((get_config_bool(lookup_config(c->config_tree, "DontFragment"), &choice) && choice) || myself->options & OPTION_DONTFRAGMENT)
c->options |= OPTION_DONTFRAGMENT;
return send_request(c, "%d %s %d %lx", ACK, myport, c->estimated_weight, c->options);
}

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: protocol_key.c,v 1.1.4.24 2003/11/17 15:30:18 guus Exp $
$Id: protocol_key.c,v 1.1.4.25 2003/12/20 19:47:53 guus Exp $
*/
#include "system.h"
@ -267,6 +267,8 @@ bool ans_key_h(connection_t *c)
return false;
}
if(from->options & OPTION_DONTFRAGMENT && !from->mtuprobes)
send_mtu_probe(from);
flush_queue(from);

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: route.c,v 1.1.2.71 2003/12/13 21:50:26 guus Exp $
$Id: route.c,v 1.1.2.72 2003/12/20 19:47:53 guus Exp $
*/
#include "system.h"
@ -206,7 +206,7 @@ static __inline__ void route_mac(node_t *source, vpn_packet_t *packet)
/* RFC 792 */
static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, uint8_t code)
static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, uint8_t type, uint8_t code)
{
struct ip ip = {0};
struct icmp icmp = {0};
@ -231,6 +231,9 @@ static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, uint8_t
oldlen = packet->len - ether_size;
if(type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED)
icmp.icmp_nextmtu = htons(packet->len - ether_size);
if(oldlen >= IP_MSS - ip_size - icmp_size)
oldlen = IP_MSS - ip_size - icmp_size;
@ -256,7 +259,7 @@ static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, uint8_t
/* Fill in ICMP header */
icmp.icmp_type = ICMP_DEST_UNREACH;
icmp.icmp_type = type;
icmp.icmp_code = code;
icmp.icmp_cksum = 0;
@ -289,7 +292,7 @@ static __inline__ void route_ipv4_unicast(node_t *source, vpn_packet_t *packet)
packet->data[32],
packet->data[33]);
route_ipv4_unreachable(source, packet, ICMP_NET_UNKNOWN);
route_ipv4_unreachable(source, packet, ICMP_DEST_UNREACH, ICMP_NET_UNKNOWN);
return;
}
@ -299,7 +302,14 @@ static __inline__ void route_ipv4_unicast(node_t *source, vpn_packet_t *packet)
}
if(!subnet->owner->status.reachable)
route_ipv4_unreachable(source, packet, ICMP_NET_UNREACH);
route_ipv4_unreachable(source, packet, ICMP_DEST_UNREACH, ICMP_NET_UNREACH);
if(subnet->owner->options & OPTION_DONTFRAGMENT && packet->len > subnet->owner->mtu && subnet->owner != myself) {
ifdebug(TRAFFIC) logger(LOG_INFO, _("Packet for %s (%s) length %d larger than MTU %d"), subnet->owner->name, subnet->owner->hostname, packet->len, subnet->owner->mtu);
packet->len = subnet->owner->mtu;
route_ipv4_unreachable(source, packet, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED);
return;
}
if(priorityinheritance)
packet->priority = packet->data[15];
@ -319,7 +329,7 @@ static __inline__ void route_ipv4(node_t *source, vpn_packet_t *packet)
/* RFC 2463 */
static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, uint8_t code)
static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, uint8_t type, uint8_t code)
{
struct ip6_hdr ip6;
struct icmp6_hdr icmp6 = {0};
@ -348,6 +358,9 @@ static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, uint8_t
pseudo.length = packet->len - ether_size;
if(type == ICMP6_PACKET_TOO_BIG)
icmp6.icmp6_mtu = htonl(pseudo.length);
if(pseudo.length >= IP_MSS - ip6_size - icmp6_size)
pseudo.length = IP_MSS - ip6_size - icmp6_size;
@ -366,7 +379,7 @@ static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, uint8_t
/* Fill in ICMP header */
icmp6.icmp6_type = ICMP6_DST_UNREACH;
icmp6.icmp6_type = type;
icmp6.icmp6_code = code;
icmp6.icmp6_cksum = 0;
@ -413,7 +426,7 @@ static __inline__ void route_ipv6_unicast(node_t *source, vpn_packet_t *packet)
ntohs(*(uint16_t *) &packet->data[50]),
ntohs(*(uint16_t *) &packet->data[52]));
route_ipv6_unreachable(source, packet, ICMP6_DST_UNREACH_ADDR);
route_ipv6_unreachable(source, packet, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR);
return;
}
@ -423,7 +436,14 @@ static __inline__ void route_ipv6_unicast(node_t *source, vpn_packet_t *packet)
}
if(!subnet->owner->status.reachable)
route_ipv6_unreachable(source, packet, ICMP6_DST_UNREACH_NOROUTE);
route_ipv6_unreachable(source, packet, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOROUTE);
if(subnet->owner->options & OPTION_DONTFRAGMENT && packet->len > subnet->owner->mtu && subnet->owner != myself) {
ifdebug(TRAFFIC) logger(LOG_INFO, _("Packet for %s (%s) length %d larger than MTU %d"), subnet->owner->name, subnet->owner->hostname, packet->len, subnet->owner->mtu);
packet->len = subnet->owner->mtu;
route_ipv6_unreachable(source, packet, ICMP6_PACKET_TOO_BIG, 0);
return;
}
send_packet(subnet->owner, packet);
}