From: Guus Sliepen Date: Sat, 17 Apr 2010 10:21:53 +0000 (+0200) Subject: Merge branch 'master' into 1.1 X-Git-Tag: import-tinc-1.1~550 X-Git-Url: https://git.meshlink.io/?a=commitdiff_plain;h=79e46d08a46f2fef2ee4e8eac7ba487007160564;p=meshlink Merge branch 'master' into 1.1 Conflicts: NEWS README configure.in src/net.c src/net.h --- 79e46d08a46f2fef2ee4e8eac7ba487007160564 diff --cc NEWS index 3b065969,b5ce4960..cee37ea8 --- a/NEWS +++ b/NEWS @@@ -1,9 -1,19 +1,25 @@@ +Version 1.1-cvs Work in progress + + * Use libevent to handle I/O events and timeouts. + + * Use splay trees instead of AVL trees. + + Version 1.0.14 not released yet + + * Fixed reading configuration files that do not end with a newline. Again. + + Version 1.0.13 Apr 11 2010 + + * Allow building tinc without LZO and/or Zlib. + + * Clamp MSS of TCP packets in both directions. + + * Experimental StrictSubnets, Forwarding and DirectOnly options, + giving more control over information and packets received from/sent to other + nodes. + + * Ensure tinc never sends symbolic names for ports over the wire. + Version 1.0.12 Feb 3 2010 * Really allow fast roaming of hosts to other nodes in a switched VPN. diff --cc src/conf.c index c734a0bb,ea33e9c3..d5bc9165 --- a/src/conf.c +++ b/src/conf.c @@@ -237,8 -237,7 +237,7 @@@ static char *readline(FILE * fp, char * Parse a configuration file and put the results in the configuration tree starting at *base. */ -bool read_config_file(avl_tree_t *config_tree, const char *fname) { +int read_config_file(splay_tree_t *config_tree, const char *fname) { - int err = -2; /* Parse error */ FILE *fp; char buffer[MAX_STRING_SIZE]; char *line; diff --cc src/ipv4.h index 80ab17c5,00000000..940c239c mode 100644,000000..100644 --- a/src/ipv4.h +++ b/src/ipv4.h @@@ -1,137 -1,0 +1,141 @@@ +/* + ipv4.h -- missing IPv4 related definitions + Copyright (C) 2005 Ivo Timmermans + 2006 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_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 fee74f5e,00000000..d98001d6 mode 100644,000000..100644 --- a/src/ipv6.h +++ b/src/ipv6.h @@@ -1,127 -1,0 +1,128 @@@ +/* + ipv6.h -- missing IPv6 related definitions + Copyright (C) 2005 Ivo Timmermans + 2006 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_DST_UNREACH_ADMIN 1 +#define ICMP6_DST_UNREACH_ADDR 3 +#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/net.c index 23b3e7ca,a04ba005..0e582364 --- a/src/net.c +++ b/src/net.c @@@ -220,115 -334,203 +220,145 @@@ void handle_meta_connection_data(int fd } } -/* - this is where it all happens... -*/ -int main_loop(void) { - fd_set readset, writeset; - struct timeval tv; - int r, maxfd; - time_t last_ping_check, last_config_check, last_graph_dump; - event_t *event; - - last_ping_check = now; - last_config_check = now; - last_graph_dump = now; - - srand(now); - - running = true; - - while(running) { - now = time(NULL); +static void sigterm_handler(int signal, short events, void *data) { + logger(LOG_NOTICE, "Got %s signal", strsignal(signal)); + event_loopexit(NULL); +} - // tv.tv_sec = 1 + (rand() & 7); /* Approx. 5 seconds, randomized to prevent global synchronisation effects */ - tv.tv_sec = 1; - tv.tv_usec = 0; +static void sighup_handler(int signal, short events, void *data) { + logger(LOG_NOTICE, "Got %s signal", strsignal(signal)); + reload_configuration(); +} - maxfd = build_fdset(&readset, &writeset); +int reload_configuration(void) { + connection_t *c; + splay_node_t *node, *next; + char *fname; + struct stat s; + static time_t last_config_check = 0; -#ifdef HAVE_MINGW - LeaveCriticalSection(&mutex); -#endif - r = select(maxfd + 1, &readset, &writeset, NULL, &tv); -#ifdef HAVE_MINGW - EnterCriticalSection(&mutex); -#endif + /* Reread our own configuration file */ - if(r < 0) { - if(!sockwouldblock(sockerrno)) { - logger(LOG_ERR, "Error while waiting for input: %s", sockstrerror(sockerrno)); - dump_connections(); - return 1; - } - } + exit_configuration(&config_tree); + init_configuration(&config_tree); - if(r > 0) - check_network_activity(&readset, &writeset); + if(!read_server_config()) { + logger(LOG_ERR, "Unable to reread configuration file, exitting."); + event_loopexit(NULL); + return EINVAL; + } - if(do_purge) { - purge(); - do_purge = false; + /* Close connections to hosts that have a changed or deleted host config file */ + + for(node = connection_tree->head; node; node = next) { + c = node->data; + next = node->next; + + if(c->outgoing) { + free(c->outgoing->name); + if(c->outgoing->ai) + freeaddrinfo(c->outgoing->ai); + free(c->outgoing); + c->outgoing = NULL; } + + xasprintf(&fname, "%s/hosts/%s", confbase, c->name); + if(stat(fname, &s) || s.st_mtime > last_config_check) + terminate_connection(c, c->status.active); + free(fname); + } - /* Let's check if everybody is still alive */ - - if(last_ping_check + pingtimeout < now) { - check_dead_connections(); - last_ping_check = now; - - if(routing_mode == RMODE_SWITCH) - age_subnets(); - - age_past_requests(); - - /* Should we regenerate our key? */ - - if(keyexpires < now) { - avl_node_t *node; - node_t *n; + last_config_check = time(NULL); - ifdebug(STATUS) logger(LOG_INFO, "Expiring symmetric keys"); ++ /* If StrictSubnet is set, expire deleted Subnets and read new ones in */ + - for(node = node_tree->head; node; node = node->next) { - n = node->data; - if(n->inkey) { - free(n->inkey); - n->inkey = NULL; - } - } ++ if(strictsubnets) { ++ subnet_t *subnet; + - send_key_changed(broadcast, myself); - keyexpires = now + keylifetime; - } ++ for(node = subnet_tree->head; node; node = node->next) { ++ subnet = node->data; ++ subnet->expires = 1; + } + - if(sigalrm) { - avl_node_t *node; - logger(LOG_INFO, "Flushing event queue"); - expire_events(); - for(node = connection_tree->head; node; node = node->next) { - connection_t *c = node->data; - send_ping(c); ++ load_all_subnets(); ++ ++ for(node = subnet_tree->head; node; node = next) { ++ next = node->next; ++ subnet = node->data; ++ if(subnet->expires == 1) { ++ send_del_subnet(broadcast, subnet); ++ if(subnet->owner->status.reachable) ++ subnet_update(subnet->owner, subnet, false); ++ subnet_del(subnet->owner, subnet); ++ } else if(subnet->expires == -1) { ++ subnet->expires = 0; ++ } else { ++ send_add_subnet(broadcast, subnet); ++ if(subnet->owner->status.reachable) ++ subnet_update(subnet->owner, subnet, true); + } - sigalrm = false; - } - - while((event = get_expired_event())) { - event->handler(event->data); - free_event(event); + } ++ } + - if(sighup) { - connection_t *c; - avl_node_t *node, *next; - char *fname; - struct stat s; - - sighup = false; - - /* Reread our own configuration file */ - - exit_configuration(&config_tree); - init_configuration(&config_tree); - - if(!read_server_config()) { - logger(LOG_ERR, "Unable to reread configuration file, exitting."); - return 1; - } - - /* Cancel non-active outgoing connections */ - - for(node = connection_tree->head; node; node = next) { - next = node->next; - c = node->data; - - c->outgoing = NULL; - - if(c->status.connecting) { - terminate_connection(c, false); - connection_del(c); - } - } - - /* Wipe list of outgoing connections */ - - for(list_node_t *node = outgoing_list->head; node; node = node->next) { - outgoing_t *outgoing = node->data; - - if(outgoing->event) - event_del(outgoing->event); - } - - list_delete_list(outgoing_list); - - /* Close connections to hosts that have a changed or deleted host config file */ - - for(node = connection_tree->head; node; node = node->next) { - c = node->data; - - xasprintf(&fname, "%s/hosts/%s", confbase, c->name); - if(stat(fname, &s) || s.st_mtime > last_config_check) - terminate_connection(c, c->status.active); - free(fname); - } + /* Try to make outgoing connections */ + + try_outgoing_connections(); - last_config_check = now; + return 0; +} - /* If StrictSubnet is set, expire deleted Subnets and read new ones in */ +void retry(void) { + connection_t *c; + splay_node_t *node; - if(strictsubnets) { - subnet_t *subnet; + for(node = connection_tree->head; node; node = node->next) { + c = node->data; + + if(c->outgoing && !c->node) { + if(timeout_initialized(&c->outgoing->ev)) + event_del(&c->outgoing->ev); + if(c->status.connecting) + close(c->socket); + c->outgoing->timeout = 0; + do_outgoing_connection(c); + } + } +} - for(node = subnet_tree->head; node; node = node->next) { - subnet = node->data; - subnet->expires = 1; - } +/* + this is where it all happens... +*/ +int main_loop(void) { + struct event timeout_event; + struct event sighup_event; + struct event sigterm_event; + struct event sigquit_event; - load_all_subnets(); - - for(node = subnet_tree->head; node; node = next) { - next = node->next; - subnet = node->data; - if(subnet->expires == 1) { - send_del_subnet(broadcast, subnet); - if(subnet->owner->status.reachable) - subnet_update(subnet->owner, subnet, false); - subnet_del(subnet->owner, subnet); - } else if(subnet->expires == -1) { - subnet->expires = 0; - } else { - send_add_subnet(broadcast, subnet); - if(subnet->owner->status.reachable) - subnet_update(subnet->owner, subnet, true); - } - } - } + timeout_set(&timeout_event, timeout_handler, &timeout_event); + event_add(&timeout_event, &(struct timeval){pingtimeout, 0}); - /* Try to make outgoing connections */ - - try_outgoing_connections(); - } - - /* Dump graph if wanted every 60 seconds*/ +#ifdef SIGHUP + signal_set(&sighup_event, SIGHUP, sighup_handler, NULL); + signal_add(&sighup_event, NULL); +#endif +#ifdef SIGTERM + signal_set(&sigterm_event, SIGTERM, sigterm_handler, NULL); + signal_add(&sigterm_event, NULL); +#endif +#ifdef SIGQUIT + signal_set(&sigquit_event, SIGQUIT, sigterm_handler, NULL); + signal_add(&sigquit_event, NULL); +#endif - if(last_graph_dump + 60 < now) { - dump_graph(); - last_graph_dump = now; - } + if(event_loop(0) < 0) { + logger(LOG_ERR, "Error while waiting for input: %s", strerror(errno)); + return 1; } + signal_del(&sighup_event); + signal_del(&sigterm_event); + signal_del(&sigquit_event); + event_del(&timeout_event); + return 0; } diff --cc src/net.h index 634e9e75,a97759fc..cd97e301 --- a/src/net.h +++ b/src/net.h @@@ -138,12 -139,7 +138,13 @@@ extern void terminate_connection(struc extern void flush_queue(struct node_t *); extern bool read_rsa_public_key(struct connection_t *); extern void send_mtu_probe(struct node_t *); +extern void handle_device_data(int, short, void *); +extern void handle_meta_connection_data(int, short, void *); +extern void regenerate_key(); +extern void purge(void); +extern void retry(void); +extern int reload_configuration(void); + extern void load_all_subnets(); #ifndef HAVE_MINGW #define closesocket(s) close(s) diff --cc src/net_setup.c index c2ae6491,cb70926a..593d8625 --- a/src/net_setup.c +++ b/src/net_setup.c @@@ -162,9 -209,9 +162,9 @@@ void load_all_subnets(void) struct dirent *ent; char *dname; char *fname; - avl_tree_t *config_tree; + splay_tree_t *config_tree; config_t *cfg; - subnet_t *s; + subnet_t *s, *s2; node_t *n; bool result; diff --cc src/protocol_auth.c index cf6b26f2,98d5b61d..8d4dfb93 --- a/src/protocol_auth.c +++ b/src/protocol_auth.c @@@ -399,9 -495,9 +399,9 @@@ static void send_everything(connection_ } } -bool ack_h(connection_t *c) { +bool ack_h(connection_t *c, char *request) { char hisport[MAX_STRING_SIZE]; - char *hisaddress, *dummy; + char *hisaddress; int weight, mtu; uint32_t options; node_t *n; diff --cc src/route.c index f18bd268,1caf738f..9897d0d7 --- a/src/route.c +++ b/src/route.c @@@ -50,10 -50,11 +50,13 @@@ static const size_t ip6_size = sizeof(s static const size_t icmp6_size = sizeof(struct icmp6_hdr); static const size_t ns_size = sizeof(struct nd_neighbor_solicit); static const size_t opt_size = sizeof(struct nd_opt_hdr); - #define max(a, b) ((a) > (b) ? (a) : (b)) + + #ifndef MAX + #define MAX(a, b) ((a) > (b) ? (a) : (b)) + #endif +static struct event age_subnets_event; + /* RFC 1071 */ static uint16_t inet_checksum(void *data, int len, uint16_t prevsum) { diff --cc src/subnet.h index df48f60e,e129a959..f22e6d58 --- a/src/subnet.h +++ b/src/subnet.h @@@ -64,6 -64,8 +64,8 @@@ typedef struct subnet_t #define MAXNETSTR 64 -extern avl_tree_t *subnet_tree; ++extern splay_tree_t *subnet_tree; + extern int subnet_compare(const struct subnet_t *, const struct subnet_t *); extern subnet_t *new_subnet(void) __attribute__ ((__malloc__)); extern void free_subnet(subnet_t *);