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 along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 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__ #ifndef __TINC_CONNECTION_H__
@ -30,6 +30,7 @@
#define OPTION_INDIRECT 0x0001 #define OPTION_INDIRECT 0x0001
#define OPTION_TCPONLY 0x0002 #define OPTION_TCPONLY 0x0002
#define OPTION_DONTFRAGMENT 0x0004
typedef struct connection_status_t { typedef struct connection_status_t {
int pinged:1; /* sent ping */ int pinged:1; /* sent ping */

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 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: /* We need to generate two trees from the graph:
@ -229,6 +229,12 @@ void sssp_bfs(void)
e->to->hostname = sockaddr2hostname(&e->to->address); e->to->hostname = sockaddr2hostname(&e->to->address);
avl_insert_node(node_udp_tree, node); 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(); node = avl_alloc_node();

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 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" #include "system.h"
@ -334,7 +334,8 @@ int main_loop(void)
while(running) { while(running) {
now = time(NULL); 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; tv.tv_usec = 0;
maxfd = build_fdset(&fset); maxfd = build_fdset(&fset);

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 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__ #ifndef __TINC_NET_H__
@ -150,6 +150,7 @@ extern int main_loop(void);
extern void terminate_connection(struct connection_t *, bool); extern void terminate_connection(struct connection_t *, bool);
extern void flush_queue(struct node_t *); extern void flush_queue(struct node_t *);
extern bool read_rsa_public_key(struct connection_t *); extern bool read_rsa_public_key(struct connection_t *);
extern void send_mtu_probe(struct node_t *);
#ifndef HAVE_MINGW #ifndef HAVE_MINGW
#define closesocket(s) close(s) #define closesocket(s) close(s)

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 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" #include "system.h"
@ -52,9 +52,58 @@ int keyexpires = 0;
EVP_CIPHER_CTX packet_ctx; 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 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 #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) static length_t compress_packet(uint8_t *dest, const uint8_t *source, length_t len, int level)
{ {
if(level == 10) { if(level == 10) {
@ -203,7 +252,10 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt)
if(n->connection) if(n->connection)
n->connection->last_ping_time = now; n->connection->last_ping_time = now;
receive_packet(n, inpkt); if(!inpkt->data[12] && !inpkt->data[13])
mtu_probe_h(n, inpkt);
else
receive_packet(n, inpkt);
} }
void receive_tcppacket(connection_t *c, char *buffer, int len) void receive_tcppacket(connection_t *c, char *buffer, int len)
@ -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) { 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)); 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; return;
} }

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 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" #include "system.h"
@ -272,21 +272,20 @@ bool setup_myself(void)
/* Check some options */ /* Check some options */
if(get_config_bool(lookup_config(config_tree, "IndirectData"), &choice)) if(get_config_bool(lookup_config(config_tree, "IndirectData"), &choice) && choice)
if(choice) myself->options |= OPTION_INDIRECT;
myself->options |= OPTION_INDIRECT;
if(get_config_bool(lookup_config(config_tree, "TCPOnly"), &choice)) if(get_config_bool(lookup_config(config_tree, "TCPOnly"), &choice) && choice)
if(choice) myself->options |= OPTION_TCPONLY;
myself->options |= OPTION_TCPONLY;
if(get_config_bool(lookup_config(myself->connection->config_tree, "IndirectData"), &choice)) if(get_config_bool(lookup_config(myself->connection->config_tree, "IndirectData"), &choice) && choice)
if(choice) myself->options |= OPTION_INDIRECT;
myself->options |= OPTION_INDIRECT;
if(get_config_bool(lookup_config(myself->connection->config_tree, "TCPOnly"), &choice)) if(get_config_bool(lookup_config(myself->connection->config_tree, "TCPOnly"), &choice) && choice)
if(choice) myself->options |= OPTION_TCPONLY;
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) if(myself->options & OPTION_TCPONLY)
myself->options |= OPTION_INDIRECT; myself->options |= OPTION_INDIRECT;

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 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" #include "system.h"
@ -49,13 +49,10 @@ int listen_sockets;
int setup_listen_socket(const sockaddr_t *sa) int setup_listen_socket(const sockaddr_t *sa)
{ {
int nfd, flags; int nfd;
char *addrstr; char *addrstr;
int option; int option;
char *iface; char *iface;
#ifdef SO_BINDTODEVICE
struct ifreq ifr;
#endif
cp(); cp();
@ -67,13 +64,15 @@ int setup_listen_socket(const sockaddr_t *sa)
} }
#ifdef O_NONBLOCK #ifdef O_NONBLOCK
flags = fcntl(nfd, F_GETFL); {
int flags = fcntl(nfd, F_GETFL);
if(fcntl(nfd, F_SETFL, flags | O_NONBLOCK) < 0) { if(fcntl(nfd, F_SETFL, flags | O_NONBLOCK) < 0) {
closesocket(nfd); closesocket(nfd);
logger(LOG_ERR, _("System call `%s' failed: %s"), "fcntl", logger(LOG_ERR, _("System call `%s' failed: %s"), "fcntl",
strerror(errno)); strerror(errno));
return -1; return -1;
}
} }
#endif #endif
@ -94,6 +93,8 @@ int setup_listen_socket(const sockaddr_t *sa)
if(get_config_string if(get_config_string
(lookup_config(config_tree, "BindToInterface"), &iface)) { (lookup_config(config_tree, "BindToInterface"), &iface)) {
#if defined(SOL_SOCKET) && defined(SO_BINDTODEVICE) #if defined(SOL_SOCKET) && defined(SO_BINDTODEVICE)
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr)); memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_ifrn.ifrn_name, iface, IFNAMSIZ); 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 setup_vpn_in_socket(const sockaddr_t *sa)
{ {
int nfd, flags; int nfd;
char *addrstr; char *addrstr;
int option; int option;
#if defined(SOL_SOCKET) && defined(SO_BINDTODEVICE)
char *iface;
struct ifreq ifr;
#endif
cp(); cp();
@ -147,29 +144,51 @@ int setup_vpn_in_socket(const sockaddr_t *sa)
} }
#ifdef O_NONBLOCK #ifdef O_NONBLOCK
flags = fcntl(nfd, F_GETFL); {
if(fcntl(nfd, F_SETFL, flags | O_NONBLOCK) < 0) { int flags = fcntl(nfd, F_GETFL);
closesocket(nfd);
logger(LOG_ERR, _("System call `%s' failed: %s"), "fcntl", if(fcntl(nfd, F_SETFL, flags | O_NONBLOCK) < 0) {
strerror(errno)); closesocket(nfd);
return -1; logger(LOG_ERR, _("System call `%s' failed: %s"), "fcntl",
strerror(errno));
return -1;
}
} }
#endif #endif
option = 1; option = 1;
setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option)); setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));
#if defined(SOL_SOCKET) && defined(SO_BINDTODEVICE) #if defined(SOL_IP) && defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO)
if(get_config_string {
(lookup_config(config_tree, "BindToInterface"), &iface)) { bool choice;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_ifrn.ifrn_name, iface, IFNAMSIZ);
if(setsockopt(nfd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr))) { if(get_config_bool(lookup_config(myself->connection->config_tree, "DontFragment"), &choice) && choice) {
closesocket(nfd); option = IP_PMTUDISC_DO;
logger(LOG_ERR, _("Can't bind to interface %s: %s"), iface, if(setsockopt(nfd, SOL_IP, IP_MTU_DISCOVER, &option, sizeof(option))) {
strerror(errno)); closesocket(nfd);
return -1; logger(LOG_ERR, _("Can't set MTU discovery mode: %s"), strerror(errno));
return -1;
}
}
}
#endif
#if defined(SOL_SOCKET) && defined(SO_BINDTODEVICE)
{
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);
if(setsockopt(nfd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr))) {
closesocket(nfd);
logger(LOG_ERR, _("Can't bind to interface %s: %s"), iface,
strerror(errno));
return -1;
}
} }
} }
#endif #endif

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 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" #include "system.h"
@ -80,6 +80,7 @@ node_t *new_node(void)
n->edge_tree = new_edge_tree(); n->edge_tree = new_edge_tree();
n->queue = list_alloc((list_action_t) free); n->queue = list_alloc((list_action_t) free);
EVP_CIPHER_CTX_init(&n->packet_ctx); EVP_CIPHER_CTX_init(&n->packet_ctx);
n->mtu = MTU;
return n; return n;
} }

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 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__ #ifndef __TINC_NODE_H__
@ -25,13 +25,14 @@
#include "avl_tree.h" #include "avl_tree.h"
#include "connection.h" #include "connection.h"
#include "event.h"
#include "list.h" #include "list.h"
#include "subnet.h" #include "subnet.h"
typedef struct node_status_t { typedef struct node_status_t {
int active:1; /* 1 if active.. */ int active:1; /* 1 if active.. */
int validkey:1; /* 1 if we currently have a valid key for him */ int validkey:1; /* 1 if we currently have a valid key for him */
int waitingforkey:1; /* 1 if we already sent out a request */ int waitingforkey:1; /* 1 if we already sent out a request */
int visited:1; /* 1 if this node has been visited by one of the graph algorithms */ int visited:1; /* 1 if this node has been visited by one of the graph algorithms */
int reachable:1; /* 1 if this node is reachable in the graph */ int reachable:1; /* 1 if this node is reachable in the graph */
int indirect:1; /* 1 if this node is not directly reachable by us */ int indirect:1; /* 1 if this node is not directly reachable by us */
@ -39,7 +40,7 @@ typedef struct node_status_t {
} node_status_t; } node_status_t;
typedef struct node_t { typedef struct node_t {
char *name; /* name of this node */ char *name; /* name of this node */
long int options; /* options turned on for this node */ long int options; /* options turned on for this node */
sockaddr_t address; /* his real (internet) ip to send UDP packets to */ sockaddr_t address; /* his real (internet) ip to send UDP packets to */
@ -47,30 +48,35 @@ typedef struct node_t {
node_status_t status; node_status_t status;
const EVP_CIPHER *cipher; /* Cipher type for UDP packets */ const EVP_CIPHER *cipher; /* Cipher type for UDP packets */
char *key; /* Cipher key and iv */ char *key; /* Cipher key and iv */
int keylength; /* Cipher key and iv length */ int keylength; /* Cipher key and iv length */
EVP_CIPHER_CTX packet_ctx; /* Cipher context */ EVP_CIPHER_CTX packet_ctx; /* Cipher context */
const EVP_MD *digest; /* Digest type for MAC */ const EVP_MD *digest; /* Digest type for MAC */
int maclength; /* Length of MAC */ int maclength; /* Length of MAC */
int compression; /* Compressionlevel, 0 = no compression */ int compression; /* Compressionlevel, 0 = no compression */
list_t *queue; /* Queue for packets awaiting to be encrypted */ list_t *queue; /* Queue for packets awaiting to be encrypted */
struct node_t *nexthop; /* nearest node from us to him */ struct node_t *nexthop; /* nearest node from us to him */
struct node_t *via; /* next hop for UDP packets */ struct node_t *via; /* next hop for UDP packets */
avl_tree_t *subnet_tree; /* Pointer to a tree of subnets belonging to this node */ avl_tree_t *subnet_tree; /* Pointer to a tree of subnets belonging to this node */
avl_tree_t *edge_tree; /* Edges with this node as one of the endpoints */ avl_tree_t *edge_tree; /* Edges with this node as one of the endpoints */
struct connection_t *connection; /* Connection associated with this node (if a direct connection exists) */ struct connection_t *connection; /* Connection associated with this node (if a direct connection exists) */
uint32_t sent_seqno; /* Sequence number last sent to this node */ uint32_t sent_seqno; /* Sequence number last sent to this node */
uint32_t received_seqno; /* Sequence number last received from this node */ uint32_t received_seqno; /* Sequence number last received from this node */
unsigned char late[16]; /* Bitfield marking late packets */ 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; } node_t;
extern struct node_t *myself; extern struct node_t *myself;

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 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" #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) if((get_config_bool(lookup_config(c->config_tree, "TCPOnly"), &choice) && choice) || myself->options & OPTION_TCPONLY)
c->options |= OPTION_TCPONLY | OPTION_INDIRECT; 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); 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 along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 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" #include "system.h"
@ -267,6 +267,8 @@ bool ans_key_h(connection_t *c)
return false; return false;
} }
if(from->options & OPTION_DONTFRAGMENT && !from->mtuprobes)
send_mtu_probe(from);
flush_queue(from); flush_queue(from);

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 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" #include "system.h"
@ -206,7 +206,7 @@ static __inline__ void route_mac(node_t *source, vpn_packet_t *packet)
/* RFC 792 */ /* 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 ip ip = {0};
struct icmp icmp = {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; 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) if(oldlen >= IP_MSS - ip_size - icmp_size)
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 */ /* Fill in ICMP header */
icmp.icmp_type = ICMP_DEST_UNREACH; icmp.icmp_type = type;
icmp.icmp_code = code; icmp.icmp_code = code;
icmp.icmp_cksum = 0; icmp.icmp_cksum = 0;
@ -269,7 +272,7 @@ static void route_ipv4_unreachable(node_t *source, vpn_packet_t *packet, uint8_t
memcpy(packet->data + ether_size + ip_size, &icmp, icmp_size); memcpy(packet->data + ether_size + ip_size, &icmp, icmp_size);
packet->len = ether_size + ip_size + icmp_size + oldlen; packet->len = ether_size + ip_size + icmp_size + oldlen;
send_packet(source, packet); send_packet(source, packet);
} }
@ -289,7 +292,7 @@ static __inline__ void route_ipv4_unicast(node_t *source, vpn_packet_t *packet)
packet->data[32], packet->data[32],
packet->data[33]); packet->data[33]);
route_ipv4_unreachable(source, packet, ICMP_NET_UNKNOWN); route_ipv4_unreachable(source, packet, ICMP_DEST_UNREACH, ICMP_NET_UNKNOWN);
return; return;
} }
@ -299,7 +302,14 @@ static __inline__ void route_ipv4_unicast(node_t *source, vpn_packet_t *packet)
} }
if(!subnet->owner->status.reachable) 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) if(priorityinheritance)
packet->priority = packet->data[15]; packet->priority = packet->data[15];
@ -319,7 +329,7 @@ static __inline__ void route_ipv4(node_t *source, vpn_packet_t *packet)
/* RFC 2463 */ /* 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 ip6_hdr ip6;
struct icmp6_hdr icmp6 = {0}; struct icmp6_hdr icmp6 = {0};
@ -347,6 +357,9 @@ static void route_ipv6_unreachable(node_t *source, vpn_packet_t *packet, uint8_t
pseudo.ip6_dst = ip6.ip6_src; pseudo.ip6_dst = ip6.ip6_src;
pseudo.length = packet->len - ether_size; 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) if(pseudo.length >= IP_MSS - ip6_size - icmp6_size)
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 */ /* Fill in ICMP header */
icmp6.icmp6_type = ICMP6_DST_UNREACH; icmp6.icmp6_type = type;
icmp6.icmp6_code = code; icmp6.icmp6_code = code;
icmp6.icmp6_cksum = 0; 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[50]),
ntohs(*(uint16_t *) &packet->data[52])); 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; return;
} }
@ -423,8 +436,15 @@ static __inline__ void route_ipv6_unicast(node_t *source, vpn_packet_t *packet)
} }
if(!subnet->owner->status.reachable) 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); send_packet(subnet->owner, packet);
} }