Merge branch '1.1' into thkr-1.1-ponyhof
This commit is contained in:
commit
0fc873a161
19 changed files with 359 additions and 41 deletions
|
|
@ -50,7 +50,7 @@ struct ether_header {
|
|||
uint8_t ether_dhost[ETH_ALEN];
|
||||
uint8_t ether_shost[ETH_ALEN];
|
||||
uint16_t ether_type;
|
||||
} __attribute__ ((__packed__));
|
||||
} __attribute__ ((__gcc_struct__, __packed__));
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRUCT_ARPHDR
|
||||
|
|
@ -60,7 +60,7 @@ struct arphdr {
|
|||
uint8_t ar_hln;
|
||||
uint8_t ar_pln;
|
||||
uint16_t ar_op;
|
||||
} __attribute__ ((__packed__));
|
||||
} __attribute__ ((__gcc_struct__, __packed__));
|
||||
|
||||
#define ARPOP_REQUEST 1
|
||||
#define ARPOP_REPLY 2
|
||||
|
|
@ -78,7 +78,7 @@ struct ether_arp {
|
|||
uint8_t arp_spa[4];
|
||||
uint8_t arp_tha[ETH_ALEN];
|
||||
uint8_t arp_tpa[4];
|
||||
} __attribute__ ((__packed__));
|
||||
} __attribute__ ((__gcc_struct__, __packed__));
|
||||
#define arp_hrd ea_hdr.ar_hrd
|
||||
#define arp_pro ea_hdr.ar_pro
|
||||
#define arp_hln ea_hdr.ar_hln
|
||||
|
|
|
|||
|
|
@ -155,7 +155,11 @@ static void check_conffile(const char *fname, bool server) {
|
|||
}
|
||||
|
||||
int fsck(const char *argv0) {
|
||||
#ifdef HAVE_MINGW
|
||||
int uid = 0;
|
||||
#else
|
||||
uid_t uid = getuid();
|
||||
#endif
|
||||
|
||||
// Check that tinc.conf is readable.
|
||||
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ struct ip {
|
|||
uint8_t ip_p;
|
||||
uint16_t ip_sum;
|
||||
struct in_addr ip_src, ip_dst;
|
||||
} __attribute__ ((__packed__));
|
||||
} __attribute__ ((__gcc_struct__, __packed__));
|
||||
#endif
|
||||
|
||||
#ifndef IP_OFFMASK
|
||||
|
|
@ -143,7 +143,7 @@ struct icmp {
|
|||
#define icmp_radv icmp_dun.id_radv
|
||||
#define icmp_mask icmp_dun.id_mask
|
||||
#define icmp_data icmp_dun.id_data
|
||||
} __attribute__ ((__packed__));
|
||||
} __attribute__ ((__gcc_struct__, __packed__));
|
||||
#endif
|
||||
|
||||
#endif /* __TINC_IPV4_H__ */
|
||||
|
|
|
|||
12
src/ipv6.h
12
src/ipv6.h
|
|
@ -36,7 +36,7 @@ struct in6_addr {
|
|||
uint16_t u6_addr16[8];
|
||||
uint32_t u6_addr32[4];
|
||||
} in6_u;
|
||||
} __attribute__ ((__packed__));
|
||||
} __attribute__ ((__gcc_struct__, __packed__));
|
||||
#define s6_addr in6_u.u6_addr8
|
||||
#define s6_addr16 in6_u.u6_addr16
|
||||
#define s6_addr32 in6_u.u6_addr32
|
||||
|
|
@ -49,7 +49,7 @@ struct sockaddr_in6 {
|
|||
uint32_t sin6_flowinfo;
|
||||
struct in6_addr sin6_addr;
|
||||
uint32_t sin6_scope_id;
|
||||
} __attribute__ ((__packed__));
|
||||
} __attribute__ ((__gcc_struct__, __packed__));
|
||||
#endif
|
||||
|
||||
#ifndef IN6_IS_ADDR_V4MAPPED
|
||||
|
|
@ -72,7 +72,7 @@ struct ip6_hdr {
|
|||
} ip6_ctlun;
|
||||
struct in6_addr ip6_src;
|
||||
struct in6_addr ip6_dst;
|
||||
} __attribute__ ((__packed__));
|
||||
} __attribute__ ((__gcc_struct__, __packed__));
|
||||
#define ip6_vfc ip6_ctlun.ip6_un2_vfc
|
||||
#define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow
|
||||
#define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen
|
||||
|
|
@ -91,7 +91,7 @@ struct icmp6_hdr {
|
|||
uint16_t icmp6_un_data16[2];
|
||||
uint8_t icmp6_un_data8[4];
|
||||
} icmp6_dataun;
|
||||
} __attribute__ ((__packed__));
|
||||
} __attribute__ ((__gcc_struct__, __packed__));
|
||||
#define ICMP6_DST_UNREACH_NOROUTE 0
|
||||
#define ICMP6_DST_UNREACH 1
|
||||
#define ICMP6_PACKET_TOO_BIG 2
|
||||
|
|
@ -111,7 +111,7 @@ struct icmp6_hdr {
|
|||
struct nd_neighbor_solicit {
|
||||
struct icmp6_hdr nd_ns_hdr;
|
||||
struct in6_addr nd_ns_target;
|
||||
} __attribute__ ((__packed__));
|
||||
} __attribute__ ((__gcc_struct__, __packed__));
|
||||
#define ND_OPT_SOURCE_LINKADDR 1
|
||||
#define ND_OPT_TARGET_LINKADDR 2
|
||||
#define nd_ns_type nd_ns_hdr.icmp6_type
|
||||
|
|
@ -124,7 +124,7 @@ struct nd_neighbor_solicit {
|
|||
struct nd_opt_hdr {
|
||||
uint8_t nd_opt_type;
|
||||
uint8_t nd_opt_len;
|
||||
} __attribute__ ((__packed__));
|
||||
} __attribute__ ((__gcc_struct__, __packed__));
|
||||
#endif
|
||||
|
||||
#endif /* __TINC_IPV6_H__ */
|
||||
|
|
|
|||
|
|
@ -38,7 +38,9 @@ int device_fd = -1;
|
|||
static HANDLE device_handle = INVALID_HANDLE_VALUE;
|
||||
static io_t device_read_io;
|
||||
static OVERLAPPED device_read_overlapped;
|
||||
static OVERLAPPED device_write_overlapped;
|
||||
static vpn_packet_t device_read_packet;
|
||||
static vpn_packet_t device_write_packet;
|
||||
char *device = NULL;
|
||||
char *iface = NULL;
|
||||
static char *device_info = NULL;
|
||||
|
|
@ -175,6 +177,25 @@ static bool setup_device(void) {
|
|||
return false;
|
||||
}
|
||||
|
||||
/* Get version information from tap device */
|
||||
|
||||
{
|
||||
ULONG info[3] = {0};
|
||||
DWORD len;
|
||||
if(!DeviceIoControl(device_handle, TAP_IOCTL_GET_VERSION, &info, sizeof info, &info, sizeof info, &len, NULL))
|
||||
logger(DEBUG_ALWAYS, LOG_WARNING, "Could not get version information from Windows tap device %s (%s): %s", device, iface, winerror(GetLastError()));
|
||||
else {
|
||||
logger(DEBUG_ALWAYS, LOG_INFO, "TAP-Windows driver version: %lu.%lu%s", info[0], info[1], info[2] ? " (DEBUG)" : "");
|
||||
|
||||
/* Warn if using >=9.21. This is because starting from 9.21, TAP-Win32 seems to use a different, less efficient write path. */
|
||||
if(info[0] == 9 && info[1] >= 21)
|
||||
logger(DEBUG_ALWAYS, LOG_WARNING,
|
||||
"You are using the newer (>= 9.0.0.21, NDIS6) series of TAP-Win32 drivers. "
|
||||
"Using these drivers with tinc is not recommanded as it can result in poor performance. "
|
||||
"You might want to revert back to 9.0.0.9 instead.");
|
||||
}
|
||||
}
|
||||
|
||||
/* Get MAC address from tap device */
|
||||
|
||||
if(!DeviceIoControl(device_handle, TAP_IOCTL_GET_MAC, mymac.x, sizeof mymac.x, mymac.x, sizeof mymac.x, &len, 0)) {
|
||||
|
|
@ -200,8 +221,12 @@ static void enable_device(void) {
|
|||
DWORD len;
|
||||
DeviceIoControl(device_handle, TAP_IOCTL_SET_MEDIA_STATUS, &status, sizeof status, &status, sizeof status, &len, NULL);
|
||||
|
||||
io_add_event(&device_read_io, device_handle_read, NULL, CreateEvent(NULL, TRUE, FALSE, NULL));
|
||||
device_read_overlapped.hEvent = device_read_io.event;
|
||||
/* We don't use the write event directly, but GetOverlappedResult() does, internally. */
|
||||
|
||||
device_read_overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
device_write_overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
|
||||
io_add_event(&device_read_io, device_handle_read, NULL, device_read_overlapped.hEvent);
|
||||
device_issue_read();
|
||||
}
|
||||
|
||||
|
|
@ -210,10 +235,22 @@ static void disable_device(void) {
|
|||
|
||||
io_del(&device_read_io);
|
||||
CancelIo(device_handle);
|
||||
|
||||
/* According to MSDN, CancelIo() does not necessarily wait for the operation to complete.
|
||||
To prevent race conditions, make sure the operation is complete
|
||||
before we close the event it's referencing. */
|
||||
|
||||
DWORD len;
|
||||
if(!GetOverlappedResult(device_handle, &device_read_overlapped, &len, TRUE) && GetLastError() != ERROR_OPERATION_ABORTED)
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not wait for %s %s read to cancel: %s", device_info, device, winerror(GetLastError()));
|
||||
if(device_write_packet.len > 0 && !GetOverlappedResult(device_handle, &device_write_overlapped, &len, TRUE) && GetLastError() != ERROR_OPERATION_ABORTED)
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not wait for %s %s write to cancel: %s", device_info, device, winerror(GetLastError()));
|
||||
device_write_packet.len = 0;
|
||||
|
||||
CloseHandle(device_read_overlapped.hEvent);
|
||||
CloseHandle(device_write_overlapped.hEvent);
|
||||
|
||||
ULONG status = 0;
|
||||
DWORD len;
|
||||
DeviceIoControl(device_handle, TAP_IOCTL_SET_MEDIA_STATUS, &status, sizeof status, &status, sizeof status, &len, NULL);
|
||||
}
|
||||
|
||||
|
|
@ -231,12 +268,29 @@ static bool read_packet(vpn_packet_t *packet) {
|
|||
|
||||
static bool write_packet(vpn_packet_t *packet) {
|
||||
DWORD outlen;
|
||||
OVERLAPPED overlapped = {0};
|
||||
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Writing packet of %d bytes to %s",
|
||||
packet->len, device_info);
|
||||
|
||||
if(!WriteFile(device_handle, DATA(packet), packet->len, &outlen, &overlapped)) {
|
||||
if(device_write_packet.len > 0) {
|
||||
/* Make sure the previous write operation is finished before we start the next one;
|
||||
otherwise we end up with multiple write ops referencing the same OVERLAPPED structure,
|
||||
which according to MSDN is a no-no. */
|
||||
|
||||
if(!GetOverlappedResult(device_handle, &device_write_overlapped, &outlen, FALSE)) {
|
||||
int log_level = (GetLastError() == ERROR_IO_INCOMPLETE) ? DEBUG_TRAFFIC : DEBUG_ALWAYS;
|
||||
logger(log_level, LOG_ERR, "Error while checking previous write to %s %s: %s", device_info, device, winerror(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy the packet, since the write operation might still be ongoing after we return. */
|
||||
|
||||
memcpy(&device_write_packet, packet, sizeof *packet);
|
||||
|
||||
if(WriteFile(device_handle, DATA(&device_write_packet), device_write_packet.len, &outlen, &device_write_overlapped))
|
||||
device_write_packet.len = 0;
|
||||
else if (GetLastError() != ERROR_IO_PENDING) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while writing to %s %s: %s", device_info, device, winerror(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -143,6 +143,9 @@ extern int udp_discovery_keepalive_interval;
|
|||
extern int udp_discovery_interval;
|
||||
extern int udp_discovery_timeout;
|
||||
|
||||
extern int mtu_info_interval;
|
||||
extern int udp_info_interval;
|
||||
|
||||
extern listen_socket_t listen_socket[MAXSOCKETS];
|
||||
extern int listen_sockets;
|
||||
extern io_t unix_socket;
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ 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;
|
||||
unsigned replaywin = 32;
|
||||
bool localdiscovery = true;
|
||||
bool udp_discovery = true;
|
||||
int udp_discovery_keepalive_interval = 10;
|
||||
|
|
@ -688,9 +688,7 @@ static bool send_sptps_data_priv(node_t *to, node_t *from, int type, const void
|
|||
bool relay_supported = (relay->options >> 24) >= 4;
|
||||
bool tcponly = (myself->options | relay->options) & OPTION_TCPONLY;
|
||||
|
||||
/* Send it via TCP if it is a handshake packet, TCPOnly is in use, this is a relay packet that the other node cannot understand, or this packet is larger than the MTU.
|
||||
TODO: When relaying, the original sender does not know the end-to-end PMTU (it only knows the PMTU of the first hop).
|
||||
This can lead to scenarios where large packets are sent over UDP to relay, but then relay has no choice but fall back to TCP. */
|
||||
/* Send it via TCP if it is a handshake packet, TCPOnly is in use, this is a relay packet that the other node cannot understand, or this packet is larger than the MTU. */
|
||||
|
||||
if(type == SPTPS_HANDSHAKE || tcponly || (!direct && !relay_supported) || (type != PKT_PROBE && (len - SPTPS_DATAGRAM_OVERHEAD) > relay->minmtu)) {
|
||||
char buf[len * 4 / 3 + 5];
|
||||
|
|
@ -1138,7 +1136,7 @@ static void try_tx_sptps(node_t *n, bool mtu) {
|
|||
/* If we do have a static relay, try everything with that one instead. */
|
||||
|
||||
if(via != n)
|
||||
try_tx_sptps(via, mtu);
|
||||
return try_tx_sptps(via, mtu);
|
||||
|
||||
/* Otherwise, try to establish UDP connectivity. */
|
||||
|
||||
|
|
@ -1395,6 +1393,17 @@ skip_harder:
|
|||
return;
|
||||
}
|
||||
|
||||
/* The packet is supposed to come from the originator or its static relay
|
||||
(i.e. with no dynamic relays in between).
|
||||
If it did not, "help" the static relay by sending it UDP info.
|
||||
Note that we only do this if we're the destination or the static relay;
|
||||
otherwise every hop would initiate its own UDP info message, resulting in elevated chatter. */
|
||||
|
||||
if(n != from->via && to->via == myself)
|
||||
send_udp_info(myself, from);
|
||||
|
||||
/* If we're not the final recipient, relay the packet. */
|
||||
|
||||
if(to != myself) {
|
||||
send_sptps_data_priv(to, n, 0, DATA(&pkt), pkt.len - 2 * sizeof(node_id_t));
|
||||
try_tx_sptps(n, true);
|
||||
|
|
@ -1412,6 +1421,12 @@ skip_harder:
|
|||
n->sock = ls - listen_socket;
|
||||
if(direct && sockaddrcmp(&addr, &n->address))
|
||||
update_node_udp(n, &addr);
|
||||
|
||||
/* If the packet went through a relay, help the sender find the appropriate MTU
|
||||
through the relay path. */
|
||||
|
||||
if(!direct)
|
||||
send_mtu_info(myself, n, MTU);
|
||||
}
|
||||
|
||||
void handle_device_data(void *data, int flags) {
|
||||
|
|
|
|||
|
|
@ -547,6 +547,9 @@ bool setup_myself_reloadable(void) {
|
|||
get_config_int(lookup_config(config_tree, "UDPDiscoveryInterval"), &udp_discovery_interval);
|
||||
get_config_int(lookup_config(config_tree, "UDPDiscoveryTimeout"), &udp_discovery_timeout);
|
||||
|
||||
get_config_int(lookup_config(config_tree, "MTUInfoInterval"), &mtu_info_interval);
|
||||
get_config_int(lookup_config(config_tree, "UDPInfoInterval"), &udp_info_interval);
|
||||
|
||||
get_config_bool(lookup_config(config_tree, "DirectOnly"), &directonly);
|
||||
get_config_bool(lookup_config(config_tree, "LocalDiscovery"), &localdiscovery);
|
||||
|
||||
|
|
@ -696,7 +699,7 @@ static bool add_listen_address(char *address, bool bindto) {
|
|||
hint.ai_protocol = IPPROTO_TCP;
|
||||
hint.ai_flags = AI_PASSIVE;
|
||||
|
||||
#ifdef HAVE_DECL_RES_INIT
|
||||
#if HAVE_DECL_RES_INIT
|
||||
res_init();
|
||||
#endif
|
||||
int err = getaddrinfo(address && *address ? address : NULL, port, &hint, &ai);
|
||||
|
|
@ -886,14 +889,14 @@ static bool setup_myself(void) {
|
|||
}
|
||||
|
||||
if(get_config_int(lookup_config(config_tree, "UDPRcvBuf"), &udp_rcvbuf)) {
|
||||
if(udp_rcvbuf <= 0) {
|
||||
if(udp_rcvbuf < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "UDPRcvBuf cannot be negative!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(get_config_int(lookup_config(config_tree, "UDPSndBuf"), &udp_sndbuf)) {
|
||||
if(udp_sndbuf <= 0) {
|
||||
if(udp_sndbuf < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "UDPSndBuf cannot be negative!");
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,8 +43,8 @@
|
|||
int addressfamily = AF_UNSPEC;
|
||||
int maxtimeout = 900;
|
||||
int seconds_till_retry = 5;
|
||||
int udp_rcvbuf = 0;
|
||||
int udp_sndbuf = 0;
|
||||
int udp_rcvbuf = 1024 * 1024;
|
||||
int udp_sndbuf = 1024 * 1024;
|
||||
int max_connection_burst = 100;
|
||||
|
||||
listen_socket_t listen_socket[MAXSOCKETS];
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ struct addrinfo *str2addrinfo(const char *address, const char *service, int sock
|
|||
hint.ai_family = addressfamily;
|
||||
hint.ai_socktype = socktype;
|
||||
|
||||
#ifdef HAVE_DECL_RES_INIT
|
||||
#if HAVE_DECL_RES_INIT
|
||||
res_init();
|
||||
#endif
|
||||
err = getaddrinfo(address, service, &hint, &ai);
|
||||
|
|
|
|||
|
|
@ -95,6 +95,9 @@ typedef struct node_t {
|
|||
|
||||
struct timeval mtu_ping_sent; /* Last time a MTU probe was sent */
|
||||
|
||||
struct timeval mtu_info_sent; /* Last time a MTU_INFO message was sent */
|
||||
struct timeval udp_info_sent; /* Last time a UDP_INFO message was sent */
|
||||
|
||||
length_t maxrecentlen; /* Maximum size of recently received packets */
|
||||
|
||||
length_t mtu; /* Maximum size of packets to send to this node */
|
||||
|
|
|
|||
|
|
@ -41,6 +41,8 @@ static bool (*request_handlers[])(connection_t *, const char *) = {
|
|||
add_subnet_h, del_subnet_h,
|
||||
add_edge_h, del_edge_h,
|
||||
key_changed_h, req_key_h, ans_key_h, tcppacket_h, control_h,
|
||||
NULL, NULL, NULL, /* Not "real" requests (yet) */
|
||||
udp_info_h, mtu_info_h,
|
||||
};
|
||||
|
||||
/* Request names */
|
||||
|
|
@ -51,6 +53,7 @@ static char (*request_name[]) = {
|
|||
"PING", "PONG",
|
||||
"ADD_SUBNET", "DEL_SUBNET",
|
||||
"ADD_EDGE", "DEL_EDGE", "KEY_CHANGED", "REQ_KEY", "ANS_KEY", "PACKET", "CONTROL",
|
||||
"REQ_PUBKEY", "ANS_PUBKEY", "REQ_SPTPS", "UDP_INFO", "MTU_INFO",
|
||||
};
|
||||
|
||||
static splay_tree_t *past_request_tree;
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
/* Protocol version. Different major versions are incompatible. */
|
||||
|
||||
#define PROT_MAJOR 17
|
||||
#define PROT_MINOR 4 /* Should not exceed 255! */
|
||||
#define PROT_MINOR 6 /* Should not exceed 255! */
|
||||
|
||||
/* Silly Windows */
|
||||
|
||||
|
|
@ -49,6 +49,7 @@ typedef enum request_t {
|
|||
CONTROL,
|
||||
REQ_PUBKEY, ANS_PUBKEY,
|
||||
REQ_SPTPS,
|
||||
UDP_INFO, MTU_INFO,
|
||||
LAST /* Guardian for the highest request number */
|
||||
} request_t;
|
||||
|
||||
|
|
@ -108,6 +109,8 @@ extern void send_key_changed(void);
|
|||
extern bool send_req_key(struct node_t *);
|
||||
extern bool send_ans_key(struct node_t *);
|
||||
extern bool send_tcppacket(struct connection_t *, const struct vpn_packet_t *);
|
||||
extern bool send_udp_info(struct node_t *, struct node_t *);
|
||||
extern bool send_mtu_info(struct node_t *, struct node_t *, int);
|
||||
|
||||
/* Request handlers */
|
||||
|
||||
|
|
@ -130,5 +133,7 @@ extern bool req_key_h(struct connection_t *, const char *);
|
|||
extern bool ans_key_h(struct connection_t *, const char *);
|
||||
extern bool tcppacket_h(struct connection_t *, const char *);
|
||||
extern bool control_h(struct connection_t *, const char *);
|
||||
extern bool udp_info_h(struct connection_t *, const char *);
|
||||
extern bool mtu_info_h(struct connection_t *, const char *);
|
||||
|
||||
#endif /* __TINC_PROTOCOL_H__ */
|
||||
|
|
|
|||
|
|
@ -178,6 +178,7 @@ static bool req_key_ext_h(connection_t *c, const char *request, node_t *from, in
|
|||
from->last_req_key = now.tv_sec;
|
||||
sptps_start(&from->sptps, from, false, true, myself->connection->ecdsa, from->ecdsa, label, sizeof label, send_sptps_data, receive_sptps_record);
|
||||
sptps_receive_data(&from->sptps, buf, len);
|
||||
send_mtu_info(myself, from, MTU);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -194,6 +195,7 @@ static bool req_key_ext_h(connection_t *c, const char *request, node_t *from, in
|
|||
return true;
|
||||
}
|
||||
sptps_receive_data(&from->sptps, buf, len);
|
||||
send_mtu_info(myself, from, MTU);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -236,6 +238,13 @@ bool req_key_h(connection_t *c, const char *request) {
|
|||
return true;
|
||||
}
|
||||
|
||||
/* If this is a SPTPS packet, see if sending UDP info helps.
|
||||
Note that we only do this if we're the destination or the static relay;
|
||||
otherwise every hop would initiate its own UDP info message, resulting in elevated chatter. */
|
||||
|
||||
if(experimental && (reqno == REQ_KEY || reqno == REQ_SPTPS) && to->via == myself)
|
||||
send_udp_info(myself, from);
|
||||
|
||||
/* Check if this key request is for us */
|
||||
|
||||
if(to == myself) { /* Yes */
|
||||
|
|
@ -408,6 +417,8 @@ bool ans_key_h(connection_t *c, const char *request) {
|
|||
}
|
||||
}
|
||||
|
||||
send_mtu_info(myself, from, MTU);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,8 +28,11 @@
|
|||
#include "netutl.h"
|
||||
#include "protocol.h"
|
||||
#include "utils.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
int maxoutbufsize = 0;
|
||||
int mtu_info_interval = 5;
|
||||
int udp_info_interval = 5;
|
||||
|
||||
/* Status and error notification routines */
|
||||
|
||||
|
|
@ -191,3 +194,199 @@ bool tcppacket_h(connection_t *c, const char *request) {
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Transmitting UDP information */
|
||||
|
||||
bool send_udp_info(node_t *from, node_t *to) {
|
||||
/* If there's a static relay in the path, there's no point in sending the message
|
||||
farther than the static relay. */
|
||||
to = (to->via == myself) ? to->nexthop : to->via;
|
||||
|
||||
/* Skip cases where sending UDP info messages doesn't make sense.
|
||||
This is done here in order to avoid repeating the same logic in multiple callsites. */
|
||||
|
||||
if(to == myself)
|
||||
return true;
|
||||
|
||||
if(!to->status.reachable)
|
||||
return true;
|
||||
|
||||
if(from == myself) {
|
||||
if(to->connection)
|
||||
return true;
|
||||
|
||||
struct timeval elapsed;
|
||||
timersub(&now, &to->udp_info_sent, &elapsed);
|
||||
if(elapsed.tv_sec < udp_info_interval)
|
||||
return true;
|
||||
}
|
||||
|
||||
if((myself->options | from->options | to->options) & OPTION_TCPONLY)
|
||||
return true;
|
||||
|
||||
if((to->nexthop->options >> 24) < 5)
|
||||
return true;
|
||||
|
||||
char *from_address, *from_port;
|
||||
/* If we're the originator, the address we use is irrelevant
|
||||
because the first intermediate node will ignore it.
|
||||
We use our local address as it somewhat makes sense
|
||||
and it's simpler than introducing an encoding for "null" addresses anyway. */
|
||||
sockaddr2str((from != myself) ? &from->address : &to->nexthop->connection->edge->local_address, &from_address, &from_port);
|
||||
|
||||
bool x = send_request(to->nexthop->connection, "%d %s %s %s %s", UDP_INFO, from->name, to->name, from_address, from_port);
|
||||
|
||||
free(from_address);
|
||||
free(from_port);
|
||||
|
||||
if(from == myself)
|
||||
to->udp_info_sent = now;
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
bool udp_info_h(connection_t *c, const char* request) {
|
||||
char from_name[MAX_STRING_SIZE];
|
||||
char to_name[MAX_STRING_SIZE];
|
||||
char from_address[MAX_STRING_SIZE];
|
||||
char from_port[MAX_STRING_SIZE];
|
||||
|
||||
if(sscanf(request, "%*d "MAX_STRING" "MAX_STRING" "MAX_STRING" "MAX_STRING, from_name, to_name, from_address, from_port) != 4) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s)", "UDP_INFO", c->name, c->hostname);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!check_id(from_name) || !check_id(to_name)) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s): %s", "UDP_INFO", c->name, c->hostname, "invalid name");
|
||||
return false;
|
||||
}
|
||||
|
||||
node_t *from = lookup_node(from_name);
|
||||
if(!from) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Got %s from %s (%s) origin %s which does not exist in our connection list", "UDP_INFO", c->name, c->hostname, from_name);
|
||||
return true;
|
||||
}
|
||||
|
||||
if(from != from->via) {
|
||||
/* Not supposed to happen, as it means the message wandered past a static relay */
|
||||
logger(DEBUG_PROTOCOL, LOG_WARNING, "Got UDP info message from %s (%s) which we can't reach directly", from->name, from->hostname);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* If we have a direct edge to "from", we are in a better position
|
||||
to guess its address than it is itself. */
|
||||
if(!from->connection && !from->status.udp_confirmed) {
|
||||
sockaddr_t from_addr = str2sockaddr(from_address, from_port);
|
||||
if(sockaddrcmp(&from_addr, &from->address))
|
||||
update_node_udp(from, &from_addr);
|
||||
}
|
||||
|
||||
node_t *to = lookup_node(to_name);
|
||||
if(!to) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Got %s from %s (%s) destination %s which does not exist in our connection list", "UDP_INFO", c->name, c->hostname, to_name);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Send our own data (which could be what we just received) up the chain. */
|
||||
|
||||
return send_udp_info(from, to);
|
||||
}
|
||||
|
||||
/* Transmitting MTU information */
|
||||
|
||||
bool send_mtu_info(node_t *from, node_t *to, int mtu) {
|
||||
/* Skip cases where sending MTU info messages doesn't make sense.
|
||||
This is done here in order to avoid repeating the same logic in multiple callsites. */
|
||||
|
||||
if(to == myself)
|
||||
return true;
|
||||
|
||||
if(!to->status.reachable)
|
||||
return true;
|
||||
|
||||
if(from == myself) {
|
||||
if(to->connection)
|
||||
return true;
|
||||
|
||||
struct timeval elapsed;
|
||||
timersub(&now, &to->mtu_info_sent, &elapsed);
|
||||
if(elapsed.tv_sec < mtu_info_interval)
|
||||
return true;
|
||||
}
|
||||
|
||||
if((to->nexthop->options >> 24) < 6)
|
||||
return true;
|
||||
|
||||
/* We will send the passed-in MTU value, unless we believe ours is better. */
|
||||
|
||||
node_t *via = (from->via == myself) ? from->nexthop : from->via;
|
||||
if(from->minmtu == from->maxmtu && from->via == myself) {
|
||||
/* We have a direct measurement. Override the value entirely.
|
||||
Note that we only do that if we are sitting as a static relay in the path;
|
||||
otherwise, we can't guarantee packets will flow through us, and increasing
|
||||
MTU could therefore end up being too optimistic. */
|
||||
mtu = from->minmtu;
|
||||
} else if(via->minmtu == via->maxmtu) {
|
||||
/* Static relay. Ensure packets will make it through the entire relay path. */
|
||||
mtu = MIN(mtu, via->minmtu);
|
||||
} else if(via->nexthop->minmtu == via->nexthop->maxmtu) {
|
||||
/* Dynamic relay. Ensure packets will make it through the entire relay path. */
|
||||
mtu = MIN(mtu, via->nexthop->minmtu);
|
||||
}
|
||||
|
||||
if(from == myself)
|
||||
to->mtu_info_sent = now;
|
||||
|
||||
/* If none of the conditions above match in the steady state, it means we're using TCP,
|
||||
so the MTU is irrelevant. That said, it is still important to honor the MTU that was passed in,
|
||||
because other parts of the relay path might be able to use UDP, which means they care about the MTU. */
|
||||
|
||||
return send_request(to->nexthop->connection, "%d %s %s %d", MTU_INFO, from->name, to->name, mtu);
|
||||
}
|
||||
|
||||
bool mtu_info_h(connection_t *c, const char* request) {
|
||||
char from_name[MAX_STRING_SIZE];
|
||||
char to_name[MAX_STRING_SIZE];
|
||||
int mtu;
|
||||
|
||||
if(sscanf(request, "%*d "MAX_STRING" "MAX_STRING" %d", from_name, to_name, &mtu) != 3) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s)", "MTU_INFO", c->name, c->hostname);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(mtu < 512) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s): %s", "MTU_INFO", c->name, c->hostname, "invalid MTU");
|
||||
return false;
|
||||
}
|
||||
|
||||
mtu = MIN(mtu, MTU);
|
||||
|
||||
if(!check_id(from_name) || !check_id(to_name)) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s): %s", "MTU_INFO", c->name, c->hostname, "invalid name");
|
||||
return false;
|
||||
}
|
||||
|
||||
node_t *from = lookup_node(from_name);
|
||||
if(!from) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Got %s from %s (%s) origin %s which does not exist in our connection list", "MTU_INFO", c->name, c->hostname, from_name);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* If we don't know the current MTU for that node, use the one we received.
|
||||
Even if we're about to make our own measurements, the value we got from downstream nodes should be pretty close
|
||||
so it's a good idea to use it in the mean time. */
|
||||
if(from->mtu != mtu && from->minmtu != from->maxmtu) {
|
||||
logger(DEBUG_TRAFFIC, LOG_INFO, "Using provisional MTU %d for node %s (%s)", mtu, from->name, from->hostname);
|
||||
from->mtu = mtu;
|
||||
}
|
||||
|
||||
node_t *to = lookup_node(to_name);
|
||||
if(!to) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Got %s from %s (%s) destination %s which does not exist in our connection list", "MTU_INFO", c->name, c->hostname, to_name);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Continue passing the MTU value (or a better one if we have it) up the chain. */
|
||||
|
||||
return send_mtu_info(from, to, mtu);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1371,6 +1371,8 @@ const var_t variables[] = {
|
|||
{"UDPDiscoveryKeepaliveInterval", VAR_SERVER},
|
||||
{"UDPDiscoveryInterval", VAR_SERVER},
|
||||
{"UDPDiscoveryTimeout", VAR_SERVER},
|
||||
{"MTUInfoInterval", VAR_SERVER},
|
||||
{"UDPInfoInterval", VAR_SERVER},
|
||||
{"UDPRcvBuf", VAR_SERVER},
|
||||
{"UDPSndBuf", VAR_SERVER},
|
||||
{"VDEGroup", VAR_SERVER},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue