From 6b12bea62fe2e4bd8b5b6bd0e5ca7f53318705db Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Sat, 20 Dec 2003 19:47:53 +0000 Subject: [PATCH] Let tinc figure out the exact MTU of the link. --- src/connection.h | 3 +- src/graph.c | 8 ++++- src/net.c | 5 +-- src/net.h | 3 +- src/net_packet.c | 60 ++++++++++++++++++++++++++++++-- src/net_setup.c | 25 +++++++------- src/net_socket.c | 83 ++++++++++++++++++++++++++++----------------- src/node.c | 3 +- src/node.h | 32 ++++++++++------- src/protocol_auth.c | 5 ++- src/protocol_key.c | 4 ++- src/route.c | 40 ++++++++++++++++------ 12 files changed, 193 insertions(+), 78 deletions(-) diff --git a/src/connection.h b/src/connection.h index cc6ff718..175bf7ce 100644 --- a/src/connection.h +++ b/src/connection.h @@ -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 */ diff --git a/src/graph.c b/src/graph.c index cd7fbf36..d07dd681 100644 --- a/src/graph.c +++ b/src/graph.c @@ -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(); diff --git a/src/net.c b/src/net.c index 16449768..a6d2bb7a 100644 --- a/src/net.c +++ b/src/net.c @@ -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); diff --git a/src/net.h b/src/net.h index cadb76e8..5b145538 100644 --- a/src/net.h +++ b/src/net.h @@ -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) diff --git a/src/net_packet.c b/src/net_packet.c index af34d059..ac4ad427 100644 --- a/src/net_packet.c +++ b/src/net_packet.c @@ -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,7 +252,10 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) if(n->connection) 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) @@ -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; } diff --git a/src/net_setup.c b/src/net_setup.c index 2c07ec63..e71d4466 100644 --- a/src/net_setup.c +++ b/src/net_setup.c @@ -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,21 +272,20 @@ bool setup_myself(void) /* Check some options */ - if(get_config_bool(lookup_config(config_tree, "IndirectData"), &choice)) - if(choice) - myself->options |= OPTION_INDIRECT; + 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) && choice) + myself->options |= OPTION_TCPONLY; - if(get_config_bool(lookup_config(config_tree, "TCPOnly"), &choice)) - if(choice) - myself->options |= OPTION_TCPONLY; + 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, "IndirectData"), &choice)) - if(choice) - myself->options |= OPTION_INDIRECT; + 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, "TCPOnly"), &choice)) - if(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; diff --git a/src/net_socket.c b/src/net_socket.c index 4e4a0080..f7404314 100644 --- a/src/net_socket.c +++ b/src/net_socket.c @@ -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,13 +64,15 @@ 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); - logger(LOG_ERR, _("System call `%s' failed: %s"), "fcntl", - strerror(errno)); - return -1; + 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 @@ -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,29 +144,51 @@ int setup_vpn_in_socket(const sockaddr_t *sa) } #ifdef O_NONBLOCK - 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; + { + 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_SOCKET) && defined(SO_BINDTODEVICE) - if(get_config_string - (lookup_config(config_tree, "BindToInterface"), &iface)) { - memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_ifrn.ifrn_name, iface, IFNAMSIZ); +#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(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; +#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 diff --git a/src/node.c b/src/node.c index 0fdc1dcc..e0639149 100644 --- a/src/node.c +++ b/src/node.c @@ -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; } diff --git a/src/node.h b/src/node.h index 4407f993..7ce17ebf 100644 --- a/src/node.h +++ b/src/node.h @@ -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,13 +25,14 @@ #include "avl_tree.h" #include "connection.h" +#include "event.h" #include "list.h" #include "subnet.h" typedef struct node_status_t { int active:1; /* 1 if active.. */ 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 reachable:1; /* 1 if this node is reachable in the graph */ 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; 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 */ sockaddr_t address; /* his real (internet) ip to send UDP packets to */ @@ -47,30 +48,35 @@ typedef struct node_t { node_status_t status; - const EVP_CIPHER *cipher; /* Cipher type for UDP packets */ - char *key; /* Cipher key and iv */ + const EVP_CIPHER *cipher; /* Cipher type for UDP packets */ + char *key; /* Cipher key and iv */ 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 compression; /* Compressionlevel, 0 = no compression */ 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 */ - 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) */ - 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 */ + 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; diff --git a/src/protocol_auth.c b/src/protocol_auth.c index 8aad5834..b50e60db 100644 --- a/src/protocol_auth.c +++ b/src/protocol_auth.c @@ -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); } diff --git a/src/protocol_key.c b/src/protocol_key.c index 049fc1e8..b8b1f223 100644 --- a/src/protocol_key.c +++ b/src/protocol_key.c @@ -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); diff --git a/src/route.c b/src/route.c index d300e0c7..8924329b 100644 --- a/src/route.c +++ b/src/route.c @@ -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; @@ -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); packet->len = ether_size + ip_size + icmp_size + oldlen; - + 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[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}; @@ -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.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,8 +436,15 @@ 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); } -- 2.39.5