From: Guus Sliepen Date: Sun, 25 Mar 2012 22:35:31 +0000 (+0100) Subject: Merge branch 'master' of git://tinc-vpn.org/tinc into 1.1 X-Git-Tag: import-tinc-1.1~385 X-Git-Url: http://git.meshlink.io/?p=meshlink;a=commitdiff_plain;h=86c2990327fdf7ec1197aa73cb2b9a926a734db4 Merge branch 'master' of git://tinc-vpn.org/tinc into 1.1 Conflicts: NEWS README configure.in src/Makefile.am src/conf.c src/conf.h src/connection.c src/net.c src/tincd.c --- 86c2990327fdf7ec1197aa73cb2b9a926a734db4 diff --cc NEWS index 36f50606,e2215fce..a3850477 --- a/NEWS +++ b/NEWS @@@ -1,33 -1,29 +1,59 @@@ +Version 1.1pre2 Juli 17 2011 + + * .cookie files are renamed to .pid files, which are compatible with 1.0.x. + + * Experimental protocol enhancements that can be enabled with the option + ExperimentalProtocol = yes: + + * Ephemeral ECDH key exchange will be used for both the meta protocol and + UDP session keys. + * Key exchanges are signed with ECDSA. + * ECDSA public keys are automatically exchanged after RSA authentication if + nodes do not know each other's ECDSA public key yet. + +Version 1.1pre1 June 25 2011 + + * Control interface allows control of a running tinc daemon. Used by: + * tincctl, a commandline utility + * tinc-gui, a preliminary GUI implemented in Python/wxWidgets + + * Code cleanups and reorganization. + + * Repleacable cryptography backend, currently supports OpenSSL and libgcrypt. + + * Use libevent to handle I/O events and timeouts. + + * Use splay trees instead of AVL trees to manage internal datastructures. + + Thanks to Scott Lamb and Sven-Haegar Koch for their contributions to this + version of tinc. + + Version 1.0.18 March 25 2012 + + * Fixed IPv6 in switch mode by turning off DecrementTTL by default. + + * Allow a port number to be specified in BindToAddress, which also allows tinc + to listen on multiple ports. + + * Add support for multicast communication with UML/QEMU/KVM. + + Version 1.0.17 March 10 2012 + + * The DeviceType option can now be used to select dummy, raw socket, UML and + VDE devices without needing to recompile tinc. + + * Allow multiple BindToAddress statements. + + * Decrement TTL value of IPv4 and IPv6 packets. + + * Add LocalDiscovery option allowing tinc to detect peers that are behind the + same NAT. + + * Accept Subnets passed with the -o option when StrictSubnets = yes. + + * Disabling old RSA keys when generating new ones now also works properly on + Windows. + Version 1.0.16 July 23 2011 * Fixed a performance issue with TCP communication under Windows. diff --cc README index 09f6e6e9,ed1d2b42..f978028b --- a/README +++ b/README @@@ -1,7 -1,7 +1,7 @@@ -This is the README file for tinc version 1.0.18. Installation +This is the README file for tinc version 1.1pre2. Installation instructions may be found in the INSTALL file. - tinc is Copyright (C) 1998-2011 by: + tinc is Copyright (C) 1998-2012 by: Ivo Timmermans, Guus Sliepen , diff --cc src/Makefile.am index 255ce340,cd44eb64..e383e1f4 --- a/src/Makefile.am +++ b/src/Makefile.am @@@ -1,15 -1,13 +1,15 @@@ ## Produce this file with automake to get Makefile.in -sbin_PROGRAMS = tincd +sbin_PROGRAMS = tincd tincctl sptps_test -EXTRA_DIST = linux/device.c bsd/device.c solaris/device.c cygwin/device.c mingw/device.c mingw/common.h +EXTRA_DIST = linux bsd solaris cygwin mingw openssl gcrypt -tincd_SOURCES = conf.c connection.c edge.c event.c graph.c logger.c meta.c net.c net_packet.c net_setup.c \ - net_socket.c netutl.c node.c process.c protocol.c protocol_auth.c protocol_edge.c protocol_misc.c \ - protocol_key.c protocol_subnet.c route.c subnet.c tincd.c \ +tincd_SOURCES = \ + utils.c getopt.c getopt1.c list.c splay_tree.c dropin.c fake-getaddrinfo.c fake-getnameinfo.c \ + buffer.c conf.c connection.c control.c edge.c graph.c logger.c meta.c net.c net_packet.c net_setup.c \ + net_socket.c netutl.c node.c process.c protocol.c protocol_auth.c protocol_edge.c protocol_misc.c \ + protocol_key.c protocol_subnet.c route.c sptps.c subnet.c tincd.c \ - dummy_device.c raw_socket_device.c + dummy_device.c raw_socket_device.c multicast_device.c if UML tincd_SOURCES += uml_device.c diff --cc src/conf.c index d7df4e96,0fc9d8f4..f580a203 --- a/src/conf.c +++ b/src/conf.c @@@ -400,60 -400,130 +400,21 @@@ bool read_connection_config(connection_ return x; } -static void disable_old_keys(const char *filename) { - char tmpfile[PATH_MAX] = ""; - char buf[1024]; - bool disabled = false; - FILE *r, *w; - - r = fopen(filename, "r"); - if(!r) - return; - - snprintf(tmpfile, sizeof tmpfile, "%s.tmp", filename); - - w = fopen(tmpfile, "w"); - - while(fgets(buf, sizeof buf, r)) { - if(!strncmp(buf, "-----BEGIN RSA", 14)) { - buf[11] = 'O'; - buf[12] = 'L'; - buf[13] = 'D'; - disabled = true; - } - else if(!strncmp(buf, "-----END RSA", 12)) { - buf[ 9] = 'O'; - buf[10] = 'L'; - buf[11] = 'D'; - disabled = true; - } - if(w && fputs(buf, w) < 0) { - disabled = false; - break; - } - } - - if(w) - fclose(w); - fclose(r); - - if(!w && disabled) { - fprintf(stderr, "Warning: old key(s) found, remove them by hand!\n"); - return; - } - - if(disabled) { -#ifdef HAVE_MINGW - // We cannot atomically replace files on Windows. - char bakfile[PATH_MAX] = ""; - snprintf(bakfile, sizeof bakfile, "%s.bak", filename); - if(rename(filename, bakfile) || rename(tmpfile, filename)) { - rename(bakfile, filename); -#else - if(rename(tmpfile, filename)) { -#endif - fprintf(stderr, "Warning: old key(s) found, remove them by hand!\n"); - } else { -#ifdef HAVE_MINGW - unlink(bakfile); -#endif - fprintf(stderr, "Warning: old key(s) found and disabled.\n"); - } - } +bool append_config_file(const char *name, const char *key, const char *value) { + char *fname; + xasprintf(&fname, "%s/hosts/%s", confbase, name); - unlink(tmpfile); -} + FILE *fp = fopen(fname, "a"); -FILE *ask_and_open(const char *filename, const char *what) { - FILE *r; - char *directory; - char line[PATH_MAX]; - const char *fn; - - /* Check stdin and stdout */ - if(!isatty(0) || !isatty(1)) { - /* Argh, they are running us from a script or something. Write - the files to the current directory and let them burn in hell - for ever. */ - fn = filename; + if(!fp) { + logger(DEBUG_ALWAYS, LOG_ERR, "Cannot open config file %s: %s", fname, strerror(errno)); } else { - /* Ask for a file and/or directory name. */ - fprintf(stdout, "Please enter a file to save %s to [%s]: ", - what, filename); - fflush(stdout); - - fn = readline(stdin, line, sizeof line); - - if(!fn) { - fprintf(stderr, "Error while reading stdin: %s\n", - strerror(errno)); - return NULL; - } - - if(!strlen(fn)) - /* User just pressed enter. */ - fn = filename; - } - -#ifdef HAVE_MINGW - if(fn[0] != '\\' && fn[0] != '/' && !strchr(fn, ':')) { -#else - if(fn[0] != '/') { -#endif - /* The directory is a relative path or a filename. */ - char *p; - - directory = get_current_dir_name(); - xasprintf(&p, "%s/%s", directory, fn); - free(directory); - fn = p; + fprintf(fp, "\n# The following line was automatically added by tinc\n%s = %s\n", key, value); + fclose(fp); } - umask(0077); /* Disallow everything for group and other */ + - disable_old_keys(fn); - - /* Open it first to keep the inode busy */ - - r = fopen(fn, "a"); - - if(!r) { - fprintf(stderr, "Error opening file `%s': %s\n", - fn, strerror(errno)); - return NULL; - } + free(fname); - return r; + return fp; } - - bool disable_old_keys(FILE *f) { - char buf[100]; - long pos; - bool disabled = false; - - rewind(f); - pos = ftell(f); - - if(pos < 0) - return false; -- - while(fgets(buf, sizeof buf, f)) { - if(!strncmp(buf, "-----BEGIN RSA", 14)) { - buf[11] = 'O'; - buf[12] = 'L'; - buf[13] = 'D'; - if(fseek(f, pos, SEEK_SET)) - break; - if(fputs(buf, f) <= 0) - break; - disabled = true; - } - else if(!strncmp(buf, "-----END RSA", 12)) { - buf[ 9] = 'O'; - buf[10] = 'L'; - buf[11] = 'D'; - if(fseek(f, pos, SEEK_SET)) - break; - if(fputs(buf, f) <= 0) - break; - disabled = true; - } - pos = ftell(f); - if(pos < 0) - break; - } -- - return disabled; - } diff --cc src/conf.h index 1ae5b735,3a040c7b..743851a7 --- a/src/conf.h +++ b/src/conf.h @@@ -57,11 -57,11 +57,10 @@@ extern bool get_config_address(const co extern bool get_config_subnet(const config_t *, struct subnet_t **); extern config_t *parse_config_line(char *, const char *, int); -extern bool read_config_file(avl_tree_t *, const char *); -extern void read_config_options(avl_tree_t *, const char *); +extern bool read_config_file(splay_tree_t *, const char *); +extern void read_config_options(splay_tree_t *, const char *); extern bool read_server_config(void); extern bool read_connection_config(struct connection_t *); -extern FILE *ask_and_open(const char *, const char *); -extern bool is_safe_path(const char *); +extern bool append_config_file(const char *, const char *, const char *); - extern bool disable_old_keys(FILE *); #endif /* __TINC_CONF_H__ */ diff --cc src/connection.c index ee44e539,9b752fad..dd524486 --- a/src/connection.c +++ b/src/connection.c @@@ -51,46 -48,66 +51,49 @@@ void exit_connections(void) } connection_t *new_connection(void) { - connection_t *c; + return xmalloc_and_zero(sizeof(connection_t)); +} - void free_connection(connection_t *c) { - if(!c) - return; - - if(c->name) - free(c->name); - - if(c->hostname) - free(c->hostname); - - c = xmalloc_and_zero(sizeof(connection_t)); ++void free_connection_partially(connection_t *c) { + cipher_close(&c->incipher); + digest_close(&c->indigest); + cipher_close(&c->outcipher); + digest_close(&c->outdigest); - if(!c) - return NULL; + sptps_stop(&c->sptps); + ecdsa_free(&c->ecdsa); + rsa_free(&c->rsa); - gettimeofday(&c->start, NULL); + if(c->hischallenge) + free(c->hischallenge); - if(c->config_tree) - exit_configuration(&c->config_tree); - - return c; -} + buffer_clear(&c->inbuf); + buffer_clear(&c->outbuf); + + if(event_initialized(&c->inevent)) + event_del(&c->inevent); -void free_connection_partially(connection_t *c) { - free(c->inkey); - free(c->outkey); - free(c->mychallenge); - free(c->hischallenge); - free(c->outbuf); - - c->inkey = NULL; - c->outkey = NULL; - c->mychallenge = NULL; - c->hischallenge = NULL; - c->outbuf = NULL; - - c->buflen = 0; - c->reqlen = 0; - c->tcplen = 0; - c->allow_request = 0; - c->outbuflen = 0; - c->outbufsize = 0; - c->outbufstart = 0; - - if(c->inctx) { - EVP_CIPHER_CTX_cleanup(c->inctx); - free(c->inctx); - c->inctx = NULL; - } + if(event_initialized(&c->outevent)) + event_del(&c->outevent); - if(c->outctx) { - EVP_CIPHER_CTX_cleanup(c->outctx); - free(c->outctx); - c->outctx = NULL; - } + if(c->socket > 0) + closesocket(c->socket); - if(c->rsa_key) { - RSA_free(c->rsa_key); - c->rsa_key = NULL; - } ++ c->socket = -1; + } + + void free_connection(connection_t *c) { ++ if(!c) ++ return; ++ + free_connection_partially(c); + + free(c->name); + free(c->hostname); + + if(c->config_tree) + exit_configuration(&c->config_tree); + free(c); } diff --cc src/connection.h index 58eea4e6,fbe4e02c..2b6870e4 --- a/src/connection.h +++ b/src/connection.h @@@ -107,8 -107,9 +107,9 @@@ extern void init_connections(void) extern void exit_connections(void); extern connection_t *new_connection(void) __attribute__ ((__malloc__)); extern void free_connection(connection_t *); + extern void free_connection_partially(connection_t *); extern void connection_add(connection_t *); extern void connection_del(connection_t *); -extern void dump_connections(void); +extern bool dump_connections(struct connection_t *); #endif /* __TINC_CONNECTION_H__ */ diff --cc src/ipv4.h index 57d236d3,00000000..bd63ad04 mode 100644,000000..100644 --- a/src/ipv4.h +++ b/src/ipv4.h @@@ -1,149 -1,0 +1,149 @@@ +/* + ipv4.h -- missing IPv4 related definitions + Copyright (C) 2005 Ivo Timmermans - 2006 Guus Sliepen ++ 2006-2012 Guus Sliepen + + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef __TINC_IPV4_H__ +#define __TINC_IPV4_H__ + +#ifndef AF_INET +#define AF_INET 2 +#endif + +#ifndef IPPROTO_ICMP +#define IPPROTO_ICMP 1 +#endif + +#ifndef ICMP_DEST_UNREACH +#define ICMP_DEST_UNREACH 3 +#endif + +#ifndef ICMP_FRAG_NEEDED +#define ICMP_FRAG_NEEDED 4 +#endif + +#ifndef ICMP_NET_UNKNOWN +#define ICMP_NET_UNKNOWN 6 +#endif + +#ifndef ICMP_TIME_EXCEEDED +#define ICMP_TIME_EXCEEDED 11 +#endif + +#ifndef ICMP_EXC_TTL +#define ICMP_EXC_TTL 0 +#endif + +#ifndef ICMP_NET_UNREACH +#define ICMP_NET_UNREACH 0 +#endif + +#ifndef ICMP_NET_ANO +#define ICMP_NET_ANO 9 +#endif + +#ifndef IP_MSS +#define IP_MSS 576 +#endif + +#ifndef HAVE_STRUCT_IP +struct ip { +#if __BYTE_ORDER == __LITTLE_ENDIAN + unsigned int ip_hl:4; + unsigned int ip_v:4; +#else + unsigned int ip_v:4; + unsigned int ip_hl:4; +#endif + uint8_t ip_tos; + uint16_t ip_len; + uint16_t ip_id; + uint16_t ip_off; +#define IP_RF 0x8000 +#define IP_DF 0x4000 +#define IP_MF 0x2000 + uint8_t ip_ttl; + uint8_t ip_p; + uint16_t ip_sum; + struct in_addr ip_src, ip_dst; +} __attribute__ ((__packed__)); +#endif + +#ifndef IP_OFFMASK +#define IP_OFFMASK 0x1fff +#endif + +#ifndef HAVE_STRUCT_ICMP +struct icmp { + uint8_t icmp_type; + uint8_t icmp_code; + uint16_t icmp_cksum; + union { + uint8_t ih_pptr; + struct in_addr ih_gwaddr; + struct ih_idseq { + uint16_t icd_id; + uint16_t icd_seq; + } ih_idseq; + uint32_t ih_void; + + + struct ih_pmtu { + uint16_t ipm_void; + uint16_t ipm_nextmtu; + } ih_pmtu; + + struct ih_rtradv { + uint8_t irt_num_addrs; + uint8_t irt_wpa; + uint16_t irt_lifetime; + } ih_rtradv; + } icmp_hun; +#define icmp_pptr icmp_hun.ih_pptr +#define icmp_gwaddr icmp_hun.ih_gwaddr +#define icmp_id icmp_hun.ih_idseq.icd_id +#define icmp_seq icmp_hun.ih_idseq.icd_seq +#define icmp_void icmp_hun.ih_void +#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void +#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu +#define icmp_num_addrs icmp_hun.ih_rtradv.irt_num_addrs +#define icmp_wpa icmp_hun.ih_rtradv.irt_wpa +#define icmp_lifetime icmp_hun.ih_rtradv.irt_lifetime + union { + struct { + uint32_t its_otime; + uint32_t its_rtime; + uint32_t its_ttime; + } id_ts; + struct { + struct ip idi_ip; + } id_ip; + uint32_t id_mask; + uint8_t id_data[1]; + } icmp_dun; +#define icmp_otime icmp_dun.id_ts.its_otime +#define icmp_rtime icmp_dun.id_ts.its_rtime +#define icmp_ttime icmp_dun.id_ts.its_ttime +#define icmp_ip icmp_dun.id_ip.idi_ip +#define icmp_radv icmp_dun.id_radv +#define icmp_mask icmp_dun.id_mask +#define icmp_data icmp_dun.id_data +} __attribute__ ((__packed__)); +#endif + +#endif /* __TINC_IPV4_H__ */ diff --cc src/ipv6.h index d98001d6,00000000..6a4466f1 mode 100644,000000..100644 --- a/src/ipv6.h +++ b/src/ipv6.h @@@ -1,128 -1,0 +1,130 @@@ +/* + ipv6.h -- missing IPv6 related definitions + Copyright (C) 2005 Ivo Timmermans - 2006 Guus Sliepen ++ 2006-2012 Guus Sliepen + + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef __TINC_IPV6_H__ +#define __TINC_IPV6_H__ + +#ifndef AF_INET6 +#define AF_INET6 10 +#endif + +#ifndef IPPROTO_ICMPV6 +#define IPPROTO_ICMPV6 58 +#endif + +#ifndef HAVE_STRUCT_IN6_ADDR +struct in6_addr { + union { + uint8_t u6_addr8[16]; + uint16_t u6_addr16[8]; + uint32_t u6_addr32[4]; + } in6_u; +} __attribute__ ((__packed__)); +#define s6_addr in6_u.u6_addr8 +#define s6_addr16 in6_u.u6_addr16 +#define s6_addr32 in6_u.u6_addr32 +#endif + +#ifndef HAVE_STRUCT_SOCKADDR_IN6 +struct sockaddr_in6 { + uint16_t sin6_family; + uint16_t sin6_port; + uint32_t sin6_flowinfo; + struct in6_addr sin6_addr; + uint32_t sin6_scope_id; +} __attribute__ ((__packed__)); +#endif + +#ifndef IN6_IS_ADDR_V4MAPPED +#define IN6_IS_ADDR_V4MAPPED(a) \ + ((((__const uint32_t *) (a))[0] == 0) \ + && (((__const uint32_t *) (a))[1] == 0) \ + && (((__const uint32_t *) (a))[2] == htonl (0xffff))) +#endif + +#ifndef HAVE_STRUCT_IP6_HDR +struct ip6_hdr { + union { + struct ip6_hdrctl { + uint32_t ip6_un1_flow; + uint16_t ip6_un1_plen; + uint8_t ip6_un1_nxt; + uint8_t ip6_un1_hlim; + } ip6_un1; + uint8_t ip6_un2_vfc; + } ip6_ctlun; + struct in6_addr ip6_src; + struct in6_addr ip6_dst; +} __attribute__ ((__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 +#define ip6_nxt ip6_ctlun.ip6_un1.ip6_un1_nxt +#define ip6_hlim ip6_ctlun.ip6_un1.ip6_un1_hlim +#define ip6_hops ip6_ctlun.ip6_un1.ip6_un1_hlim +#endif + +#ifndef HAVE_STRUCT_ICMP6_HDR +struct icmp6_hdr { + uint8_t icmp6_type; + uint8_t icmp6_code; + uint16_t icmp6_cksum; + union { + uint32_t icmp6_un_data32[1]; + uint16_t icmp6_un_data16[2]; + uint8_t icmp6_un_data8[4]; + } icmp6_dataun; +} __attribute__ ((__packed__)); +#define ICMP6_DST_UNREACH_NOROUTE 0 +#define ICMP6_DST_UNREACH 1 +#define ICMP6_PACKET_TOO_BIG 2 ++#define ICMP6_TIME_EXCEEDED 3 +#define ICMP6_DST_UNREACH_ADMIN 1 +#define ICMP6_DST_UNREACH_ADDR 3 ++#define ICMP6_TIME_EXCEED_TRANSIT 0 +#define ND_NEIGHBOR_SOLICIT 135 +#define ND_NEIGHBOR_ADVERT 136 +#define icmp6_data32 icmp6_dataun.icmp6_un_data32 +#define icmp6_data16 icmp6_dataun.icmp6_un_data16 +#define icmp6_data8 icmp6_dataun.icmp6_un_data8 +#define icmp6_mtu icmp6_data32[0] +#endif + +#ifndef HAVE_STRUCT_ND_NEIGHBOR_SOLICIT +struct nd_neighbor_solicit { + struct icmp6_hdr nd_ns_hdr; + struct in6_addr nd_ns_target; +} __attribute__ ((__packed__)); +#define ND_OPT_SOURCE_LINKADDR 1 +#define ND_OPT_TARGET_LINKADDR 2 +#define nd_ns_type nd_ns_hdr.icmp6_type +#define nd_ns_code nd_ns_hdr.icmp6_code +#define nd_ns_cksum nd_ns_hdr.icmp6_cksum +#define nd_ns_reserved nd_ns_hdr.icmp6_data32[0] +#endif + +#ifndef HAVE_STRUCT_ND_OPT_HDR +struct nd_opt_hdr { + uint8_t nd_opt_type; + uint8_t nd_opt_len; +} __attribute__ ((__packed__)); +#endif + +#endif /* __TINC_IPV6_H__ */ diff --cc src/multicast_device.c index 00000000,0b232dbb..e5e9a3fb mode 000000,100644..100644 --- a/src/multicast_device.c +++ b/src/multicast_device.c @@@ -1,0 -1,228 +1,228 @@@ + /* + device.c -- multicast socket + Copyright (C) 2002-2005 Ivo Timmermans, + 2002-2012 Guus Sliepen + + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + + #include "system.h" + + #include "conf.h" + #include "device.h" + #include "net.h" + #include "logger.h" + #include "netutl.h" + #include "utils.h" + #include "route.h" + #include "xalloc.h" + + static char *device_info; + + static uint64_t device_total_in = 0; + static uint64_t device_total_out = 0; + + static struct addrinfo *ai = NULL; + static mac_t ignore_src = {{0}}; + + static bool setup_device(void) { + char *host; + char *port; + char *space; + int ttl = 1; + + device_info = "multicast socket"; + + get_config_string(lookup_config(config_tree, "Interface"), &iface); + + if(!get_config_string(lookup_config(config_tree, "Device"), &device)) { - logger(LOG_ERR, "Device variable required for %s", device_info); ++ logger(DEBUG_ALWAYS, LOG_ERR, "Device variable required for %s", device_info); + return false; + } + + host = xstrdup(device); + space = strchr(host, ' '); + if(!space) { - logger(LOG_ERR, "Port number required for %s", device_info); ++ logger(DEBUG_ALWAYS, LOG_ERR, "Port number required for %s", device_info); + return false; + } + + *space++ = 0; + port = space; + space = strchr(port, ' '); + + if(space) { + *space++ = 0; + ttl = atoi(space); + } + + ai = str2addrinfo(host, port, SOCK_DGRAM); + if(!ai) + return false; + + device_fd = socket(ai->ai_family, SOCK_DGRAM, IPPROTO_UDP); + if(device_fd < 0) { - logger(LOG_ERR, "Creating socket failed: %s", sockstrerror(sockerrno)); ++ logger(DEBUG_ALWAYS, LOG_ERR, "Creating socket failed: %s", sockstrerror(sockerrno)); + return false; + } + + #ifdef FD_CLOEXEC + fcntl(device_fd, F_SETFD, FD_CLOEXEC); + #endif + + static const int one = 1; + setsockopt(device_fd, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof one); + + if(bind(device_fd, ai->ai_addr, ai->ai_addrlen)) { + closesocket(device_fd); - logger(LOG_ERR, "Can't bind to %s %s: %s", host, port, sockstrerror(sockerrno)); ++ logger(DEBUG_ALWAYS, LOG_ERR, "Can't bind to %s %s: %s", host, port, sockstrerror(sockerrno)); + return false; + } + + switch(ai->ai_family) { + #ifdef IP_ADD_MEMBERSHIP + case AF_INET: { + struct ip_mreq mreq; + struct sockaddr_in in; + memcpy(&in, ai->ai_addr, sizeof in); + mreq.imr_multiaddr.s_addr = in.sin_addr.s_addr; + mreq.imr_interface.s_addr = htonl(INADDR_ANY); + if(setsockopt(device_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&mreq, sizeof mreq)) { - logger(LOG_ERR, "Cannot join multicast group %s %s: %s", host, port, sockstrerror(sockerrno)); ++ logger(DEBUG_ALWAYS, LOG_ERR, "Cannot join multicast group %s %s: %s", host, port, sockstrerror(sockerrno)); + closesocket(device_fd); + return false; + } + #ifdef IP_MULTICAST_LOOP + setsockopt(device_fd, IPPROTO_IP, IP_MULTICAST_LOOP, (const void *)&one, sizeof one); + #endif + #ifdef IP_MULTICAST_TTL + setsockopt(device_fd, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&ttl, sizeof ttl); + #endif + } break; + #endif + + #ifdef IPV6_JOIN_GROUP + case AF_INET6: { + struct ipv6_mreq mreq; + struct sockaddr_in6 in6; + memcpy(&in6, ai->ai_addr, sizeof in6); + memcpy(&mreq.ipv6mr_multiaddr, &in6.sin6_addr, sizeof mreq.ipv6mr_multiaddr); + mreq.ipv6mr_interface = in6.sin6_scope_id; + if(setsockopt(device_fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, (void *)&mreq, sizeof mreq)) { - logger(LOG_ERR, "Cannot join multicast group %s %s: %s", host, port, sockstrerror(sockerrno)); ++ logger(DEBUG_ALWAYS, LOG_ERR, "Cannot join multicast group %s %s: %s", host, port, sockstrerror(sockerrno)); + closesocket(device_fd); + return false; + } + #ifdef IPV6_MULTICAST_LOOP + setsockopt(device_fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (const void *)&one, sizeof one); + #endif + #ifdef IPV6_MULTICAST_HOPS + setsockopt(device_fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (void *)&ttl, sizeof ttl); + #endif + } break; + #endif + + default: - logger(LOG_ERR, "Multicast for address family %hx unsupported", ai->ai_family); ++ logger(DEBUG_ALWAYS, LOG_ERR, "Multicast for address family %hx unsupported", ai->ai_family); + closesocket(device_fd); + return false; + } + - logger(LOG_INFO, "%s is a %s", device, device_info); ++ logger(DEBUG_ALWAYS, LOG_INFO, "%s is a %s", device, device_info); + + return true; + } + + static void close_device(void) { + close(device_fd); + + free(device); + free(iface); + + if(ai) + freeaddrinfo(ai); + } + + static bool read_packet(vpn_packet_t *packet) { + int lenin; + + if((lenin = recv(device_fd, packet->data, MTU, 0)) <= 0) { - logger(LOG_ERR, "Error while reading from %s %s: %s", device_info, ++ logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info, + device, strerror(errno)); + return false; + } + + if(!memcmp(&ignore_src, packet->data + 6, sizeof ignore_src)) { - ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Ignoring loopback packet of %d bytes from %s", lenin, device_info); ++ logger(DEBUG_SCARY_THINGS, LOG_DEBUG, "Ignoring loopback packet of %d bytes from %s", lenin, device_info); + packet->len = 0; + return true; + } + + packet->len = lenin; + + device_total_in += packet->len; + - ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s", packet->len, ++ logger(DEBUG_TRAFFIC, LOG_DEBUG, "Read packet of %d bytes from %s", packet->len, + device_info); + + return true; + } + + static bool write_packet(vpn_packet_t *packet) { - ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s", ++ logger(DEBUG_TRAFFIC, LOG_DEBUG, "Writing packet of %d bytes to %s", + packet->len, device_info); + + if(sendto(device_fd, packet->data, packet->len, 0, ai->ai_addr, ai->ai_addrlen) < 0) { - logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device, ++ logger(DEBUG_ALWAYS, LOG_ERR, "Can't write to %s %s: %s", device_info, device, + strerror(errno)); + return false; + } + + device_total_out += packet->len; + + memcpy(&ignore_src, packet->data + 6, sizeof ignore_src); + + return true; + } + + static void dump_device_stats(void) { - logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device); - logger(LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in); - logger(LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out); ++ logger(DEBUG_ALWAYS, LOG_DEBUG, "Statistics for %s %s:", device_info, device); ++ logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in); ++ logger(DEBUG_ALWAYS, LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out); + } + + const devops_t multicast_devops = { + .setup = setup_device, + .close = close_device, + .read = read_packet, + .write = write_packet, + .dump_stats = dump_device_stats, + }; + + #if 0 + + static bool not_supported(void) { - logger(LOG_ERR, "Raw socket device not supported on this platform"); ++ logger(DEBUG_ALWAYS, LOG_ERR, "Raw socket device not supported on this platform"); + return false; + } + + const devops_t multicast_devops = { + .setup = not_supported, + .close = NULL, + .read = NULL, + .write = NULL, + .dump_stats = NULL, + }; + #endif diff --cc src/net.c index 10a2d206,9799feab..db5743af --- a/src/net.c +++ b/src/net.c @@@ -139,12 -204,14 +139,13 @@@ void terminate_connection(connection_t } } - /* Check if this was our outgoing connection */ + free_connection_partially(c); - if(c->outgoing) - retry_outgoing(c->outgoing); + /* Check if this was our outgoing connection */ - connection_del(c); + if(c->outgoing) { - c->status.remove = false; + do_outgoing_connection(c); + } } /* @@@ -170,10 -233,10 +171,10 @@@ static void timeout_handler(int fd, sho if(c->last_ping_time + pingtimeout <= now) { if(c->status.active) { if(c->status.pinged) { - ifdebug(CONNECTIONS) logger(LOG_INFO, "%s (%s) didn't respond to PING in %ld seconds", + logger(DEBUG_CONNECTIONS, LOG_INFO, "%s (%s) didn't respond to PING in %ld seconds", - c->name, c->hostname, now - c->last_ping_time); + c->name, c->hostname, (long)now - c->last_ping_time); - c->status.timeout = true; terminate_connection(c, true); + continue; } else if(c->last_ping_time + pinginterval <= now) { send_ping(c); } diff --cc src/tincd.c index a78ca0c4,443301e0..1008f88a --- a/src/tincd.c +++ b/src/tincd.c @@@ -357,9 -516,9 +357,9 @@@ int main(int argc, char **argv) make_names(); if(show_version) { - printf("%s version %s (built %s %s, protocol %d)\n", PACKAGE, - VERSION, __DATE__, __TIME__, PROT_CURRENT); + printf("%s version %s (built %s %s, protocol %d.%d)\n", PACKAGE, + VERSION, __DATE__, __TIME__, PROT_MAJOR, PROT_MINOR); - printf("Copyright (C) 1998-2011 Ivo Timmermans, Guus Sliepen and others.\n" + printf("Copyright (C) 1998-2012 Ivo Timmermans, Guus Sliepen and others.\n" "See the AUTHORS file for a complete list.\n\n" "tinc comes with ABSOLUTELY NO WARRANTY. This is free software,\n" "and you are welcome to redistribute it under certain conditions;\n" diff --cc src/vde_device.c index ab2ffdcd,e69ae802..815b956f --- a/src/vde_device.c +++ b/src/vde_device.c @@@ -99,9 -99,9 +99,9 @@@ static void close_device(void) } static bool read_packet(vpn_packet_t *packet) { - int lenin = plug.vde_recv(conn, packet->data, MTU, 0); + int lenin = (ssize_t)plug.vde_recv(conn, packet->data, MTU, 0); if(lenin <= 0) { - logger(LOG_ERR, "Error while reading from %s %s: %s", device_info, device, strerror(errno)); + logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info, device, strerror(errno)); running = false; return false; } @@@ -114,9 -114,9 +114,9 @@@ } static bool write_packet(vpn_packet_t *packet) { - if(plug.vde_send(conn, packet->data, packet->len, 0) < 0) { + if((ssize_t)plug.vde_send(conn, packet->data, packet->len, 0) < 0) { if(errno != EINTR && errno != EAGAIN) { - logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device, strerror(errno)); + logger(DEBUG_ALWAYS, LOG_ERR, "Can't write to %s %s: %s", device_info, device, strerror(errno)); running = false; }