X-Git-Url: https://tinc-vpn.org/git/browse?p=tinc;a=blobdiff_plain;f=src%2Fnet_packet.c;h=18a898d30f3dba95fcc709cfb02981b2e9d3ef05;hp=b35f72d4aa744657ab95691cd6adf6b5d9fb07d7;hb=5a28aa7b8b0ab6237c2eab5f8b11253ea3ec5a05;hpb=23acc19bc090051156ad895caed61848f5afb144 diff --git a/src/net_packet.c b/src/net_packet.c index b35f72d4..18a898d3 100644 --- a/src/net_packet.c +++ b/src/net_packet.c @@ -1,8 +1,9 @@ /* net_packet.c -- Handles in- and outgoing VPN packets Copyright (C) 1998-2005 Ivo Timmermans, - 2000-2010 Guus Sliepen + 2000-2011 Guus Sliepen 2010 Timothy Redaelli + 2010 Brandon Black This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -42,7 +43,6 @@ #include "ethernet.h" #include "event.h" #include "graph.h" -#include "list.h" #include "logger.h" #include "net.h" #include "netutl.h" @@ -61,13 +61,21 @@ static char lzo_wrkmem[LZO1X_999_MEM_COMPRESS > LZO1X_1_MEM_COMPRESS ? LZO1X_999 static void send_udppacket(node_t *, vpn_packet_t *); unsigned replaywin = 16; +bool localdiscovery = false; #define MAX_SEQNO 1073741824 -// mtuprobes == 1..30: initial discovery, send bursts with 1 second interval -// mtuprobes == 31: sleep pinginterval seconds -// mtuprobes == 32: send 1 burst, sleep pingtimeout second -// mtuprobes == 33: no response from other side, restart PMTU discovery process +/* mtuprobes == 1..30: initial discovery, send bursts with 1 second interval + mtuprobes == 31: sleep pinginterval seconds + mtuprobes == 32: send 1 burst, sleep pingtimeout second + mtuprobes == 33: no response from other side, restart PMTU discovery process + + Probes are sent in batches of three, with random sizes between the lower and + upper boundaries for the MTU thus far discovered. + + In case local discovery is enabled, a fourth packet is added to each batch, + which will be broadcast to the local network. +*/ void send_mtu_probe(node_t *n) { vpn_packet_t packet; @@ -84,16 +92,21 @@ void send_mtu_probe(node_t *n) { } if(n->mtuprobes > 32) { + if(!n->minmtu) { + n->mtuprobes = 31; + timeout = pinginterval; + goto end; + } + ifdebug(TRAFFIC) logger(LOG_INFO, "%s (%s) did not respond to UDP ping, restarting PMTU discovery", n->name, n->hostname); n->mtuprobes = 1; n->minmtu = 0; n->maxmtu = MTU; } - if(n->mtuprobes >= 10 && !n->minmtu) { + if(n->mtuprobes >= 10 && n->mtuprobes < 32 && !n->minmtu) { ifdebug(TRAFFIC) logger(LOG_INFO, "No response to MTU probes from %s (%s)", n->name, n->hostname); - n->mtuprobes = 0; - return; + n->mtuprobes = 31; } if(n->mtuprobes == 30 || (n->mtuprobes < 30 && n->minmtu >= n->maxmtu)) { @@ -113,7 +126,7 @@ void send_mtu_probe(node_t *n) { timeout = pingtimeout; } - for(i = 0; i < 3; i++) { + for(i = 0; i < 3 + localdiscovery; i++) { if(n->maxmtu <= n->minmtu) len = n->maxmtu; else @@ -125,7 +138,7 @@ void send_mtu_probe(node_t *n) { memset(packet.data, 0, 14); RAND_pseudo_bytes(packet.data + 14, len - 14); packet.len = len; - packet.priority = 0; + packet.priority = i < 3 ? 0 : -1; ifdebug(TRAFFIC) logger(LOG_INFO, "Sending MTU probe length %d to %s (%s)", len, n->name, n->hostname); @@ -147,12 +160,17 @@ void mtu_probe_h(node_t *n, vpn_packet_t *packet, length_t len) { packet->data[0] = 1; send_udppacket(n, packet); } else { + if(n->mtuprobes > 30) { + if(n->minmtu) + n->mtuprobes = 30; + else + n->mtuprobes = 1; + } + if(len > n->maxmtu) len = n->maxmtu; if(n->minmtu < len) n->minmtu = len; - if(n->mtuprobes > 30) - n->mtuprobes = 30; } } @@ -298,9 +316,13 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) { if(replaywin) { if(inpkt->seqno != n->received_seqno + 1) { if(inpkt->seqno >= n->received_seqno + replaywin * 8) { + if(n->farfuture++ < replaywin >> 2) { + logger(LOG_WARNING, "Packet from %s (%s) is %d seqs in the future, dropped (%u)", + n->name, n->hostname, inpkt->seqno - n->received_seqno - 1, n->farfuture); + return; + } logger(LOG_WARNING, "Lost %d packets from %s (%s)", inpkt->seqno - n->received_seqno - 1, n->name, n->hostname); - memset(n->late, 0, replaywin); } else if (inpkt->seqno <= n->received_seqno) { if((n->received_seqno >= replaywin * 8 && inpkt->seqno <= n->received_seqno - replaywin * 8) || !(n->late[(inpkt->seqno / 8) % replaywin] & (1 << inpkt->seqno % 8))) { @@ -313,7 +335,8 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) { n->late[(i / 8) % replaywin] |= 1 << i % 8; } } - + + n->farfuture = 0; n->late[(inpkt->seqno / 8) % replaywin] &= ~(1 << inpkt->seqno % 8); } @@ -349,7 +372,7 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) { receive_packet(n, inpkt); } -void receive_tcppacket(connection_t *c, char *buffer, int len) { +void receive_tcppacket(connection_t *c, const char *buffer, int len) { vpn_packet_t outpkt; outpkt.len = len; @@ -374,7 +397,6 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) { static int priority = 0; #endif int origpriority; - int sock; if(!n->status.reachable) { ifdebug(TRAFFIC) logger(LOG_INFO, "Trying to send UDP packet to unreachable node %s (%s)", n->name, n->hostname); @@ -388,7 +410,7 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) { "No valid key known yet for %s (%s), forwarding via TCP", n->name, n->hostname); - if(n->last_req_key + 10 < now) { + if(n->last_req_key + 10 <= now) { send_req_key(n); n->last_req_key = now; } @@ -461,26 +483,51 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) { /* Determine which socket we have to use */ - for(sock = 0; sock < listen_sockets; sock++) - if(n->address.sa.sa_family == listen_socket[sock].sa.sa.sa_family) - break; - - if(sock >= listen_sockets) - sock = 0; /* If none is available, just use the first and hope for the best. */ + if(n->address.sa.sa_family != listen_socket[n->sock].sa.sa.sa_family) { + for(int sock = 0; sock < listen_sockets; sock++) { + if(n->address.sa.sa_family == listen_socket[sock].sa.sa.sa_family) { + n->sock = sock; + break; + } + } + } /* Send the packet */ + struct sockaddr *sa; + socklen_t sl; + int sock; + + /* Overloaded use of priority field: -1 means local broadcast */ + + if(origpriority == -1 && n->prevedge) { + struct sockaddr_in in; + in.sin_family = AF_INET; + in.sin_addr.s_addr = -1; + in.sin_port = n->prevedge->address.in.sin_port; + sa = (struct sockaddr *)∈ + sl = sizeof in; + sock = 0; + } else { + if(origpriority == -1) + origpriority = 0; + + sa = &(n->address.sa); + sl = SALEN(n->address.sa); + sock = n->sock; + } + #if defined(SOL_IP) && defined(IP_TOS) if(priorityinheritance && origpriority != priority - && listen_socket[sock].sa.sa.sa_family == AF_INET) { + && listen_socket[n->sock].sa.sa.sa_family == AF_INET) { priority = origpriority; ifdebug(TRAFFIC) logger(LOG_DEBUG, "Setting outgoing packet priority to %d", priority); - if(setsockopt(listen_socket[sock].udp, SOL_IP, IP_TOS, &priority, sizeof(priority))) /* SO_PRIORITY doesn't seem to work */ + if(setsockopt(listen_socket[n->sock].udp, SOL_IP, IP_TOS, &priority, sizeof(priority))) /* SO_PRIORITY doesn't seem to work */ logger(LOG_ERR, "System call `%s' failed: %s", "setsockopt", strerror(errno)); } #endif - if(sendto(listen_socket[sock].udp, (char *) &inpkt->seqno, inpkt->len, 0, &(n->address.sa), SALEN(n->address.sa)) < 0 && !sockwouldblock(sockerrno)) { + if(sendto(listen_socket[sock].udp, (char *) &inpkt->seqno, inpkt->len, 0, sa, sl) < 0 && !sockwouldblock(sockerrno)) { if(sockmsgsize(sockerrno)) { if(n->maxmtu >= origlen) n->maxmtu = origlen - 1; @@ -503,7 +550,7 @@ void send_packet(const node_t *n, vpn_packet_t *packet) { if(n == myself) { if(overwrite_mac) memcpy(packet->data, mymac.x, ETH_ALEN); - write_packet(packet); + devops.write(packet); return; } @@ -559,20 +606,21 @@ static node_t *try_harder(const sockaddr_t *from, const vpn_packet_t *pkt) { avl_node_t *node; edge_t *e; node_t *n = NULL; + bool hard = false; static time_t last_hard_try = 0; for(node = edge_weight_tree->head; node; node = node->next) { e = node->data; + if(e->to == myself) + continue; + if(sockaddrcmp_noport(from, &e->address)) { if(last_hard_try == now) continue; - last_hard_try = now; + hard = true; } - if(!n) - n = e->to; - if(!try_mac(e->to, pkt)) continue; @@ -580,6 +628,10 @@ static node_t *try_harder(const sockaddr_t *from, const vpn_packet_t *pkt) { break; } + if(hard) + last_hard_try = now; + + last_hard_try = now; return n; } @@ -590,7 +642,7 @@ void handle_incoming_vpn_data(int sock) { socklen_t fromlen = sizeof(from); node_t *n; - pkt.len = recvfrom(sock, (char *) &pkt.seqno, MAXSIZE, 0, &from.sa, &fromlen); + pkt.len = recvfrom(listen_socket[sock].udp, (char *) &pkt.seqno, MAXSIZE, 0, &from.sa, &fromlen); if(pkt.len < 0) { if(!sockwouldblock(sockerrno)) @@ -616,5 +668,7 @@ void handle_incoming_vpn_data(int sock) { return; } + n->sock = sock; + receive_udppacket(n, &pkt); }