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__
#define OPTION_INDIRECT 0x0001
#define OPTION_TCPONLY 0x0002
+#define OPTION_DONTFRAGMENT 0x0004
typedef struct connection_status_t {
int pinged:1; /* sent ping */
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:
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();
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"
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);
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__
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)
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"
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) {
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)
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;
}
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"
/* 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;
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"
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();
}
#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
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);
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();
}
#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
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"
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;
}
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__
#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 */
} 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 */
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;
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"
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);
}
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"
return false;
}
+ if(from->options & OPTION_DONTFRAGMENT && !from->mtuprobes)
+ send_mtu_probe(from);
flush_queue(from);
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"
/* 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};
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;
/* Fill in ICMP header */
- icmp.icmp_type = ICMP_DEST_UNREACH;
+ icmp.icmp_type = type;
icmp.icmp_code = code;
icmp.icmp_cksum = 0;
memcpy(packet->data + ether_size + ip_size, &icmp, icmp_size);
packet->len = ether_size + ip_size + icmp_size + oldlen;
-
+
send_packet(source, 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;
}
}
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];
/* 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};
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;
/* Fill in ICMP header */
- icmp6.icmp6_type = ICMP6_DST_UNREACH;
+ icmp6.icmp6_type = type;
icmp6.icmp6_code = code;
icmp6.icmp6_cksum = 0;
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;
}
}
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);
}