+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.9 Dec 26 2008
+
+ * Fixed tinc as a service under Windows 2003.
+
+ * Fixed reading configuration files that do not end with a newline.
+
+ * Fixed crashes in situations where hostnames could not be resolved or hosts
+ would disconnect at the same time as session keys were exchanged.
+
+ * Improved default settings of tun and tap devices on BSD platforms.
+
+ * Make IPv6 sockets bind only to IPv6 on Linux.
+
+ * Enable path MTU discovery by default.
+
+ * Fixed a memory leak that occured when connections were closed.
+
Version 1.0.8 May 16 2007
* Fixed some memory and resource leaks.
-This is the README file for tinc version 1.0.9. Installation
+This is the README file for tinc version 1.1-cvs. Installation
instructions may be found in the INSTALL file.
- tinc is Copyright (C) 1998-2007 by:
-tinc is Copyright (C) 1998-2008 by:
++tinc is Copyright (C) 1998-2009 by:
Ivo Timmermans,
Guus Sliepen <guus@tinc-vpn.org>,
extern bool get_config_address(const config_t *, struct addrinfo **);
extern bool get_config_subnet(const config_t *, struct subnet_t **);
-extern int read_config_file(avl_tree_t *, const char *);
+extern int read_config_file(splay_tree_t *, const char *);
extern bool read_server_config(void);
-extern FILE *ask_and_open(const char *, const char *);
+extern FILE *ask_and_open(const char *, const char *, const char *);
extern bool is_safe_path(const char *);
+ extern bool disable_old_keys(FILE *);
#endif /* __TINC_CONF_H__ */
if(c->hischallenge)
free(c->hischallenge);
- if(c->outbuf)
- free(c->outbuf);
-
- if(c->rsa_key)
- RSA_free(c->rsa_key);
+ if(c->config_tree)
+ exit_configuration(&c->config_tree);
+
+ if(c->buffer)
+ bufferevent_free(c->buffer);
+
+ if(event_initialized(&c->inevent))
+ event_del(&c->inevent);
free(c);
}
cp();
- logger(LOG_DEBUG, _("Connections:"));
-
for(node = connection_tree->head; node; node = node->next) {
c = node->data;
- logger(LOG_DEBUG, _(" %s at %s options %lx socket %d status %04x outbuf %d/%d/%d"),
- c->name, c->hostname, c->options, c->socket, c->status.value,
- c->outbufsize, c->outbufstart, c->outbuflen);
+ if(evbuffer_add_printf(out,
- _(" %s at %s options %lx socket %d status %04x\n"),
- c->name, c->hostname, c->options, c->socket,
- c->status.value) == -1)
++ _(" %s at %s options %lx socket %d status %04x\n"),
++ c->name, c->hostname, c->options, c->socket,
++ c->status.value) == -1)
+ return errno;
}
- logger(LOG_DEBUG, _("End of connections."));
+ return 0;
}
-bool read_connection_config(connection_t *c)
-{
+bool read_connection_config(connection_t *c) {
char *fname;
int x;
CloseHandle(device_handle);
kill(reader_pid, SIGKILL);
+
+ free(device);
+ free(iface);
}
-bool read_packet(vpn_packet_t *packet)
-{
- int lenin;
+bool read_packet(vpn_packet_t *packet) {
+ int inlen;
cp();
/* now dump all edges */
for(node = edge_weight_tree->head; node; node = node->next) {
e = node->data;
- fprintf(file, " %s -> %s;\n", e->from->name, e->to->name);
+ if(evbuffer_add_printf(out, " %s -> %s;\n",
+ e->from->name, e->to->name) == -1)
+ return errno;
}
- fprintf(file, "}\n");
-
- if(filename[0] == '|') {
- pclose(file);
- } else {
- fclose(file);
-#ifdef HAVE_MINGW
- unlink(filename);
-#endif
- rename(tmpname, filename);
- free(tmpname);
- }
+ if(evbuffer_add_printf(out, "}\n") == -1)
+ return errno;
+
+ return 0;
+}
+
+void graph(void) {
++ subnet_cache_flush();
+ sssp_dijkstra();
+ check_reachability();
+ mst_kruskal();
}
cp();
close(device_fd);
+
+ free(device);
+ free(iface);
}
-bool read_packet(vpn_packet_t *packet)
-{
- int lenin;
+bool read_packet(vpn_packet_t *packet) {
+ int inlen;
cp();
cp();
CloseHandle(device_handle);
+
+ free(device);
+ free(iface);
}
-bool read_packet(vpn_packet_t *packet)
-{
+bool read_packet(vpn_packet_t *packet) {
unsigned char bufno;
cp();
#define MTU 1518 /* 1500 bytes payload + 14 bytes ethernet header + 4 bytes VLAN tag */
#endif
-#define MAXSIZE (MTU + 4 + EVP_MAX_BLOCK_LENGTH + EVP_MAX_MD_SIZE + MTU/64 + 20) /* MTU + seqno + padding + HMAC + compressor overhead */
+#define MAXSIZE (MTU + 4 + CIPHER_MAX_BLOCK_SIZE + DIGEST_MAX_SIZE + MTU/64 + 20) /* MTU + seqno + padding + HMAC + compressor overhead */
#define MAXBUFSIZE ((MAXSIZE > 2048 ? MAXSIZE : 2048) + 128) /* Enough room for a request with a MAXSIZEd packet or a 8192 bits RSA key */
-#define MAXSOCKETS 128 /* Overkill... */
+#define MAXSOCKETS 8 /* Probably overkill... */
- #define MAXQUEUELENGTH 8 /* Maximum number of packats in a single queue */
-
typedef struct mac_t {
uint8_t x[6];
} mac_t;
uint8_t data[MAXSIZE];
} vpn_packet_t;
- typedef struct queue_element_t {
- void *packet;
- struct queue_element_t *prev;
- struct queue_element_t *next;
- } queue_element_t;
-
- typedef struct packet_queue_t {
- queue_element_t *head;
- queue_element_t *tail;
- } packet_queue_t;
-
typedef struct listen_socket_t {
+ struct event ev_tcp;
+ struct event ev_udp;
int tcp;
int udp;
sockaddr_t sa;
struct config_t *cfg;
struct addrinfo *ai;
struct addrinfo *aip;
+ struct event ev;
} outgoing_t;
+ extern list_t *outgoing_list;
+
extern int maxoutbufsize;
extern int seconds_till_retry;
extern int addressfamily;
len = 64;
memset(packet.data, 0, 14);
- RAND_pseudo_bytes(packet.data + 14, len - 14);
+ randomize(packet.data + 14, len - 14);
packet.len = len;
+ packet.priority = 0;
ifdebug(TRAFFIC) logger(LOG_INFO, _("Sending MTU probe length %d to %s (%s)"), len, n->name, n->hostname);
inpkt = outpkt;
}
- if(n->connection)
- n->connection->last_ping_time = now;
-
+ inpkt->priority = 0;
+
if(!inpkt->data[12] && !inpkt->data[13])
mtu_probe_h(n, inpkt);
else
int nextpkt = 0;
vpn_packet_t *outpkt;
int origlen;
- int outlen, outpad;
+ size_t outlen;
- vpn_packet_t *copy;
static int priority = 0;
int origpriority;
int sock;
}
}
- void flush_queue(node_t *n) {
- list_node_t *node, *next;
-
- cp();
-
- ifdebug(TRAFFIC) logger(LOG_INFO, _("Flushing queue for %s (%s)"), n->name, n->hostname);
-
- for(node = n->queue->head; node; node = next) {
- next = node->next;
- send_udppacket(n, node->data);
- list_delete_node(n->queue, node);
- }
- }
-
- void handle_incoming_vpn_data(int sock, short events, void *data) {
-void handle_incoming_vpn_data(int sock)
++void handle_incoming_vpn_data(int sock, short events, void *data)
+ {
vpn_packet_t pkt;
char *hostname;
sockaddr_t from;
execute_script("tinc-down", envp);
- EVP_CIPHER_CTX_cleanup(&packet_ctx);
-
+ if(myport) free(myport);
+
for(i = 0; i < 4; i++)
free(envp[i]);
c->allow_request = ID;
send_id(c);
-
- return true;
}
- void try_outgoing_connections(void) {
+ void free_outgoing(outgoing_t *outgoing) {
+ if(outgoing->ai)
+ freeaddrinfo(outgoing->ai);
+
+ if(outgoing->name)
+ free(outgoing->name);
+
+ free(outgoing);
+ }
+
+ void try_outgoing_connections(void)
+ {
static config_t *cfg = NULL;
char *name;
outgoing_t *outgoing;
-
+ connection_t *c;
- avl_node_t *node;
++ splay_node_t *node;
+
cp();
+ if(outgoing_list) {
+ for(node = connection_tree->head; node; node = node->next) {
+ c = node->data;
+ c->outgoing = NULL;
+ }
+
+ list_delete_list(outgoing_list);
+ }
+
+ outgoing_list = list_alloc((list_action_t)free_outgoing);
+
for(cfg = lookup_config(config_tree, "ConnectTo"); cfg; cfg = lookup_config_next(config_tree, cfg)) {
get_config_string(cfg, &name);
continue;
}
- outgoing = xmalloc_and_zero(sizeof(*outgoing));
+ outgoing = xmalloc_and_zero(sizeof *outgoing);
outgoing->name = name;
+ list_insert_tail(outgoing_list, outgoing);
setup_outgoing_connection(outgoing);
}
}
n->subnet_tree = new_subnet_tree();
n->edge_tree = new_edge_tree();
- n->queue = list_alloc((list_action_t) free);
- EVP_CIPHER_CTX_init(&n->packet_ctx);
n->mtu = MTU;
n->maxmtu = MTU;
return n;
}
-void free_node(node_t *n)
-{
+void free_node(node_t *n) {
cp();
- if(n->queue)
- list_delete_list(n->queue);
- if(n->key)
- free(n->key);
--
if(n->subnet_tree)
free_subnet_tree(n->subnet_tree);
int compression; /* Compressionlevel, 0 = no compression */
- list_t *queue; /* Queue for packets awaiting to be encrypted */
-
+ int distance;
struct node_t *nexthop; /* nearest node from us to him */
struct node_t *via; /* next hop for UDP packets */
{
cp();
- /* If there already is a lot of data in the outbuf buffer, discard this packet. */
+ /* If there already is a lot of data in the outbuf buffer, discard this packet.
+ We use a very simple Random Early Drop algorithm. */
- if(c->buffer->output->off > maxoutbufsize)
- if(2.0 * c->outbuflen / (double)maxoutbufsize - 1 > drand48())
++ if(2.0 * c->buffer->output->off / (double)maxoutbufsize - 1 > drand48())
return true;
if(!send_request(c, "%d %hd", PACKET, packet->len))
cp();
close(device_fd);
+
+ free(device);
+ free(iface);
}
-bool read_packet(vpn_packet_t *packet)
-{
- int lenin;
+bool read_packet(vpn_packet_t *packet) {
+ int inlen;
cp();
/* Generate checksum */
- checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
+ checksum = inet_checksum(&pseudo, sizeof pseudo, ~0);
checksum = inet_checksum(&ns, ns_size, checksum);
- checksum = inet_checksum(&opt, opt_size, checksum);
- checksum = inet_checksum(packet->data + ether_size + ip6_size + ns_size + opt_size, ETH_ALEN, checksum);
+ if(has_opt) {
+ checksum = inet_checksum(&opt, opt_size, checksum);
+ checksum = inet_checksum(packet->data + ether_size + ip6_size + ns_size + opt_size, ETH_ALEN, checksum);
+ }
if(checksum) {
ifdebug(TRAFFIC) logger(LOG_WARNING, _("Cannot route packet: checksum error for neighbor solicitation request"));
/* Generate checksum */
- checksum = inet_checksum(&pseudo, sizeof(pseudo), ~0);
+ checksum = inet_checksum(&pseudo, sizeof pseudo, ~0);
checksum = inet_checksum(&ns, ns_size, checksum);
- checksum = inet_checksum(&opt, opt_size, checksum);
- checksum = inet_checksum(packet->data + ether_size + ip6_size + ns_size + opt_size, ETH_ALEN, checksum);
+ if(has_opt) {
+ checksum = inet_checksum(&opt, opt_size, checksum);
+ checksum = inet_checksum(packet->data + ether_size + ip6_size + ns_size + opt_size, ETH_ALEN, checksum);
+ }
ns.nd_ns_hdr.icmp6_cksum = checksum;
cp();
close(device_fd);
+
+ free(device);
+ free(iface);
}
-bool read_packet(vpn_packet_t *packet)
-{
- int lenin;
+bool read_packet(vpn_packet_t *packet) {
+ int inlen;
cp();
/* lists type of subnet */
-avl_tree_t *subnet_tree;
+splay_tree_t *subnet_tree;
+ /* Subnet lookup cache */
+
+ static ipv4_t cache_ipv4_address[2];
+ static subnet_t *cache_ipv4_subnet[2];
+ static bool cache_ipv4_valid[2];
+ static int cache_ipv4_slot;
+
+ static ipv6_t cache_ipv6_address[2];
+ static subnet_t *cache_ipv6_subnet[2];
+ static bool cache_ipv6_valid[2];
+ static int cache_ipv6_slot;
+
+ void subnet_cache_flush() {
+ cache_ipv4_valid[0] = cache_ipv4_valid[1] = false;
+ cache_ipv6_valid[0] = cache_ipv6_valid[1] = false;
+ }
+
/* Subnet comparison */
static int subnet_compare_mac(const subnet_t *a, const subnet_t *b)
{
int result;
- result = memcmp(&a->net.mac.address, &b->net.mac.address, sizeof(mac_t));
+ result = memcmp(&a->net.mac.address, &b->net.mac.address, sizeof a->net.mac.address);
+ if(result)
+ return result;
+
+ result = a->weight - b->weight;
+
if(result || !a->owner || !b->owner)
return result;
{
cp();
- subnet_tree = avl_alloc_tree((avl_compare_t) subnet_compare, (avl_action_t) free_subnet);
+ subnet_tree = splay_alloc_tree((splay_compare_t) subnet_compare, (splay_action_t) free_subnet);
+
+ subnet_cache_flush();
}
void exit_subnets(void)
subnet->owner = n;
- avl_insert(subnet_tree, subnet);
- avl_insert(n->subnet_tree, subnet);
+ splay_insert(subnet_tree, subnet);
+ splay_insert(n->subnet_tree, subnet);
+
+ subnet_cache_flush();
}
void subnet_del(node_t *n, subnet_t *subnet)
{
cp();
- avl_delete(n->subnet_tree, subnet);
- avl_delete(subnet_tree, subnet);
+ splay_delete(n->subnet_tree, subnet);
+ splay_delete(subnet_tree, subnet);
+
+ subnet_cache_flush();
}
/* Ascii representation of subnets */
subnet_t *lookup_subnet_ipv4(const ipv4_t *address)
{
- subnet_t *p, subnet = {0};
+ subnet_t *p, *r = NULL, subnet = {0};
- avl_node_t *n;
++ splay_node_t *n;
+ int i;
cp();
subnet_t *lookup_subnet_ipv6(const ipv6_t *address)
{
- subnet_t *p, subnet = {0};
+ subnet_t *p, *r = NULL, subnet = {0};
- avl_node_t *n;
++ splay_node_t *n;
+ int i;
cp();
extern subnet_t *lookup_subnet_mac(const mac_t *);
extern subnet_t *lookup_subnet_ipv4(const ipv4_t *);
extern subnet_t *lookup_subnet_ipv6(const ipv6_t *);
-extern void dump_subnets(void);
+extern int dump_subnets(struct evbuffer *);
+ extern void subnet_cache_flush(void);
#endif /* __TINC_SUBNET_H__ */
}
}
- if (pidfilename) free(pidfilename);
+ static void free_names() {
+ if (identname) free(identname);
+ if (netname) free(netname);
++ if (controlsocketname) free(controlsocketname);
+ if (logfilename) free(logfilename);
+ if (confbase) free(confbase);
+ }
+
int main(int argc, char **argv)
{
program_name = argv[0];
close(write_fd);
unlink(device);
+
+ free(device);
+ if(iface) free(iface);
}
-bool read_packet(vpn_packet_t *packet)
-{
- int lenin;
+bool read_packet(vpn_packet_t *packet) {
+ int inlen;
cp();