- Non-blocking connect()s.

- Socket handling revamped to use sockaddr_t.
- tinc can now tunnel over IPv6.
- Handle all addresses and subnets in network byte order.
  Only convert them when they need to be printed.
- IPv6 subnets bigger than /128 now work.
- Use %s and strerror(errno) instead of %m.
This commit is contained in:
Guus Sliepen 2002-02-18 16:25:19 +00:00
parent fc674eaae1
commit c2b9c06062
33 changed files with 2487 additions and 2018 deletions

View file

@ -100,6 +100,12 @@ If you leave it out, remember to replace it with at least one space character.
Here are all valid variables, listed in alphabetical order.
The default value is given between parentheses.
.Bl -tag -width indent
.It Va AddressFamily Li = ipv4 | ipv6 | any Pq ipv4
This option affects the address family of listening and outgoing sockets.
If
.Qq any
is selected, then the listening sockets will be IPv6 sockets,
but on most platforms those will also accept IPv4 connections.
.It Va BindToInterface Li = Ar interface Bq experimental
If your computer has more than one network interface,
.Nm tinc

View file

@ -1,5 +1,5 @@
\input texinfo @c -*-texinfo-*-
@c $Id: tinc.texi,v 1.8.4.20 2002/02/11 15:59:18 guus Exp $
@c $Id: tinc.texi,v 1.8.4.21 2002/02/18 16:25:15 guus Exp $
@c %**start of header
@setfilename tinc.info
@settitle tinc Manual
@ -18,7 +18,7 @@ Copyright @copyright{} 1998-2002 Ivo Timmermans
<itimmermans@@bigfoot.com>, Guus Sliepen <guus@@sliepen.warande.net> and
Wessel Dankers <wsl@@nl.linux.org>.
$Id: tinc.texi,v 1.8.4.20 2002/02/11 15:59:18 guus Exp $
$Id: tinc.texi,v 1.8.4.21 2002/02/18 16:25:15 guus Exp $
Permission is granted to make and distribute verbatim copies of this
manual provided the copyright notice and this permission notice are
@ -43,7 +43,7 @@ Copyright @copyright{} 1998-2002 Ivo Timmermans
<itimmermans@@bigfoot.com>, Guus Sliepen <guus@@sliepen.warande.net> and
Wessel Dankers <wsl@@nl.linux.org>.
$Id: tinc.texi,v 1.8.4.20 2002/02/11 15:59:18 guus Exp $
$Id: tinc.texi,v 1.8.4.21 2002/02/18 16:25:15 guus Exp $
Permission is granted to make and distribute verbatim copies of this
manual provided the copyright notice and this permission notice are
@ -736,6 +736,12 @@ required directives are given in @strong{bold}.
@subsection Main configuration variables
@table @asis
@cindex AddressFamily
@item AddressFamily = <ipv4|ipv6|any> (ipv4)
This option affects the address family of listening and outgoing sockets.
If "any" is selected, then the listening sockets will be IPv6 sockets,
but on most platforms those will also accept IPv4 connections.
@cindex BindToInterface
@item BindToInterface = <interface>
If you have more than one network interface in your computer, tinc will

View file

@ -9,6 +9,9 @@ src/conf.c
src/connection.c
src/meta.c
src/net.c
src/net_packet.c
src/net_setup.c
src/net_socket.c
src/netutl.c
src/protocol.c
src/protocol_auth.c
@ -25,5 +28,6 @@ src/edge.c
src/graph.c
src/linux/device.c
src/freebsd/device.c
src/openbsd/device.c
src/solaris/device.c
src/netbsd/device.c
src/openbsd/device.c

806
po/nl.po

File diff suppressed because it is too large Load diff

View file

@ -1,13 +1,13 @@
## Produce this file with automake to get Makefile.in
# $Id: Makefile.am,v 1.4.4.19 2002/02/10 21:57:52 guus Exp $
# $Id: Makefile.am,v 1.4.4.20 2002/02/18 16:25:16 guus Exp $
sbin_PROGRAMS = tincd
EXTRA_DIST = linux/device.c freebsd/device.c openbsd/device.c solaris/device.c
tincd_SOURCES = conf.c connection.c device.c edge.c event.c graph.c meta.c net.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 = conf.c connection.c device.c edge.c event.c graph.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
INCLUDES = @INCLUDES@ -I$(top_builddir) -I$(top_srcdir)/lib -I$(top_srcdir)/intl

View file

@ -19,7 +19,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: conf.c,v 1.9.4.52 2002/02/10 21:57:53 guus Exp $
$Id: conf.c,v 1.9.4.53 2002/02/18 16:25:16 guus Exp $
*/
#include "config.h"
@ -56,14 +56,14 @@ char *netname = NULL; /* name of the vpn network */
int config_compare(config_t *a, config_t *b)
{
int result;
result = strcmp(a->variable, b->variable);
result = strcasecmp(a->variable, b->variable);
if(result)
return result;
result = a->line - b->line;
if(result)
return result;
else
@ -90,7 +90,7 @@ config_t *new_config(void)
config_t *cfg;
cp
cfg = (config_t *)xmalloc_and_zero(sizeof(*cfg));
return cfg;
}
@ -126,7 +126,7 @@ cp
if(!found)
return NULL;
if(strcmp(found->variable, variable))
return NULL;
@ -139,7 +139,7 @@ config_t *lookup_config_next(avl_tree_t *config_tree, config_t *cfg)
config_t *found;
cp
node = avl_search_node(config_tree, cfg);
if(node)
{
if(node->next)
@ -149,10 +149,10 @@ cp
return found;
}
}
return NULL;
}
int get_config_bool(config_t *cfg, int *result)
{
cp
@ -184,7 +184,7 @@ cp
if(sscanf(cfg->value, "%d", result) == 1)
return 1;
syslog(LOG_ERR, _("Integer expected for configuration variable %s in %s line %d"),
cfg->variable, cfg->file, cfg->line);
return 0;
@ -196,27 +196,26 @@ cp
if(!cfg)
return 0;
*result = cfg->value;
*result = xstrdup(cfg->value);
return 1;
}
int get_config_address(config_t *cfg, ipv4_t **result)
int get_config_address(config_t *cfg, struct addrinfo **result)
{
ipv4_t *ip;
struct addrinfo *ai;
cp
if(!cfg)
return 0;
ip = xmalloc(sizeof(*ip));
*ip = str2address(cfg->value);
ai = str2addrinfo(cfg->value, NULL, 0);
if(ip)
if(ai)
{
*result = ip;
*result = ai;
return 1;
}
syslog(LOG_ERR, _("IP address expected for configuration variable %s in %s line %d"),
syslog(LOG_ERR, _("Hostname or IP address expected for configuration variable %s in %s line %d"),
cfg->variable, cfg->file, cfg->line);
return 0;
}
@ -228,8 +227,11 @@ cp
return 0;
if(sscanf(cfg->value, "%hu", result) == 1)
return 1;
{
*result = htons(*result);
return 1;
}
syslog(LOG_ERR, _("Port number expected for configuration variable %s in %s line %d"),
cfg->variable, cfg->file, cfg->line);
return 0;
@ -250,20 +252,20 @@ cp
cfg->variable, cfg->file, cfg->line);
return 0;
}
/* Teach newbies what subnets are... */
if(subnet->type == SUBNET_IPV4)
if((subnet->net.ipv4.address & subnet->net.ipv4.mask) != subnet->net.ipv4.address)
{
syslog(LOG_ERR, _("Network address and mask length do not match for configuration variable %s in %s line %d"),
cfg->variable, cfg->file, cfg->line);
free(subnet);
return 0;
}
if(((subnet->type == SUBNET_IPV4) && maskcheck((char *)&subnet->net.ipv4.address, subnet->net.ipv4.masklength, sizeof(ipv4_t)))
|| ((subnet->type == SUBNET_IPV6) && maskcheck((char *)&subnet->net.ipv6.address, subnet->net.ipv6.masklength, sizeof(ipv6_t))))
{
syslog(LOG_ERR, _("Network address and mask length do not match for configuration variable %s in %s line %d"),
cfg->variable, cfg->file, cfg->line);
free(subnet);
return 0;
}
*result = subnet;
return 1;
}
@ -271,7 +273,7 @@ cp
Read exactly one line and strip the trailing newline if any. If the
file was on EOF, return NULL. Otherwise, return all the data in a
dynamically allocated buffer.
If line is non-NULL, it will be used as an initial buffer, to avoid
unnecessary mallocing each time this function is called. If buf is
given, and buf needs to be expanded, the var pointed to by buflen
@ -360,17 +362,17 @@ int read_config_file(avl_tree_t *config_tree, const char *fname)
int lineno = 0, ignore = 0;
config_t *cfg;
size_t bufsize;
cp
if((fp = fopen (fname, "r")) == NULL)
{
syslog(LOG_ERR, _("Cannot open config file %s: %m"), fname);
syslog(LOG_ERR, _("Cannot open config file %s: %s"), fname, strerror(errno));
return -3;
}
bufsize = 100;
buffer = xmalloc(bufsize);
for(;;)
{
if((line = readline(fp, &buffer, &bufsize)) == NULL)
@ -395,7 +397,7 @@ cp
if(!strcmp(variable, "-----BEGIN"))
ignore = 1;
if(!ignore)
{
if(((value = strtok(NULL, "\t\n\r =")) == NULL) || value[0] == '#')
@ -433,12 +435,11 @@ cp
x = read_config_file(config_tree, fname);
if(x == -1) /* System error: complain */
{
syslog(LOG_ERR, _("Failed to read `%s': %m"),
fname);
syslog(LOG_ERR, _("Failed to read `%s': %s"), fname, strerror(errno));
}
free(fname);
cp
return x;
return x;
}
int isadir(const char* f)
@ -466,10 +467,10 @@ int is_safe_path(const char *file)
}
p = strrchr(file, '/');
if(p == file) /* It's in the root */
p++;
x = *p;
*p = '\0';
@ -477,8 +478,7 @@ int is_safe_path(const char *file)
check1:
if(lstat(f, &s) < 0)
{
syslog(LOG_ERR, _("Couldn't stat `%s': %m"),
f);
syslog(LOG_ERR, _("Couldn't stat `%s': %s"), f, strerror(errno));
return 0;
}
@ -496,25 +496,24 @@ check1:
if(readlink(f, l, MAXBUFSIZE) < 0)
{
syslog(LOG_ERR, _("Unable to read symbolic link `%s': %m"), f);
syslog(LOG_ERR, _("Unable to read symbolic link `%s': %s"), f, strerror(errno));
return 0;
}
f = l;
goto check1;
}
*p = x;
f = file;
check2:
if(lstat(f, &s) < 0 && errno != ENOENT)
{
syslog(LOG_ERR, _("Couldn't stat `%s': %m"),
f);
syslog(LOG_ERR, _("Couldn't stat `%s': %s"), f, strerror(errno));
return 0;
}
if(errno == ENOENT)
return 1;
@ -532,10 +531,10 @@ check2:
if(readlink(f, l, MAXBUFSIZE) < 0)
{
syslog(LOG_ERR, _("Unable to read symbolic link `%s': %m"), f);
syslog(LOG_ERR, _("Unable to read symbolic link `%s': %s"), f, strerror(errno));
return 0;
}
f = l;
goto check2;
}
@ -547,7 +546,7 @@ check2:
f);
return 0;
}
return 1;
}
@ -587,7 +586,7 @@ FILE *ask_and_safe_open(const char* filename, const char* what, const char* mode
{
/* The directory is a relative path or a filename. */
char *p;
directory = get_current_dir_name();
asprintf(&p, "%s/%s", directory, fn);
free(fn);
@ -596,7 +595,7 @@ FILE *ask_and_safe_open(const char* filename, const char* what, const char* mode
}
umask(0077); /* Disallow everything for group and other */
/* Open it first to keep the inode busy */
if((r = fopen(fn, mode)) == NULL)
{
@ -605,7 +604,7 @@ FILE *ask_and_safe_open(const char* filename, const char* what, const char* mode
free(fn);
return NULL;
}
/* Then check the file for nasty attacks */
if(!is_safe_path(fn)) /* Do not permit any directories that are
readable or writeable by other users. */

View file

@ -17,12 +17,16 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: conf.h,v 1.6.4.31 2002/02/10 21:57:53 guus Exp $
$Id: conf.h,v 1.6.4.32 2002/02/18 16:25:16 guus Exp $
*/
#ifndef __TINC_CONF_H__
#define __TINC_CONF_H__
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <avl_tree.h>
#include "net.h"
#include "subnet.h"
@ -54,7 +58,7 @@ extern int get_config_bool(config_t *, int *);
extern int get_config_int(config_t *, int *);
extern int get_config_port(config_t *, port_t *);
extern int get_config_string(config_t *, char **);
extern int get_config_address(config_t *, ipv4_t **);
extern int get_config_address(config_t *, struct addrinfo **);
struct subnet_t; /* Needed for next line. */
extern int get_config_subnet(config_t *, struct subnet_t **);

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: connection.c,v 1.1.2.27 2002/02/10 21:57:53 guus Exp $
$Id: connection.c,v 1.1.2.28 2002/02/18 16:25:16 guus Exp $
*/
#include "config.h"
@ -44,7 +44,7 @@ avl_tree_t *connection_tree; /* Meta connections */
int connection_compare(connection_t *a, connection_t *b)
{
return a->socket - b->socket;
return a - b;
}
void init_connections(void)
@ -106,16 +106,6 @@ cp
cp
}
connection_t *lookup_connection(ipv4_t address, port_t port)
{
connection_t c;
cp
c.address = address;
c.port = port;
return avl_search(connection_tree, &c);
}
void dump_connections(void)
{
avl_node_t *node;
@ -126,9 +116,8 @@ cp
for(node = connection_tree->head; node; node = node->next)
{
c = (connection_t *)node->data;
syslog(LOG_DEBUG, _(" %s at %s port %hd options %ld socket %d status %04x"),
c->name, c->hostname, c->port, c->options,
c->socket, c->status);
syslog(LOG_DEBUG, _(" %s at %s options %ld socket %d status %04x"),
c->name, c->hostname, c->options, c->socket, c->status);
}
syslog(LOG_DEBUG, _("End of connections."));

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: connection.h,v 1.1.2.24 2002/02/10 21:57:53 guus Exp $
$Id: connection.h,v 1.1.2.25 2002/02/18 16:25:16 guus Exp $
*/
#ifndef __TINC_CONNECTION_H__
@ -52,6 +52,7 @@
typedef struct connection_status_t {
int pinged:1; /* sent ping */
int active:1; /* 1 if active.. */
int connecting:1; /* 1 if we are waiting for a non-blocking connect() to finish */
int termreq:1; /* the termination of this connection was requested */
int remove:1; /* Set to 1 if you want this connection removed */
int timeout:1; /* 1 if gotten timeout */
@ -64,8 +65,7 @@ typedef struct connection_status_t {
typedef struct connection_t {
char *name; /* name he claims to have */
ipv4_t address; /* his real (internet) ip */
port_t port; /* port number of meta connection */
sockaddr_t address; /* his real (internet) ip */
char *hostname; /* the hostname of its real ip */
int protocol_version; /* used protocol */
@ -77,7 +77,7 @@ typedef struct connection_t {
struct outgoing_t *outgoing; /* used to keep track of outgoing connections */
struct node_t *node; /* node associated with the other end */
struct edge_t *edge; /* edge associated with this connection */
struct edge_t *edge; /* edge associated with this connection */
RSA *rsa_key; /* his public/private key */
EVP_CIPHER *incipher; /* Cipher he will use to send data to us */
@ -109,7 +109,6 @@ extern connection_t *new_connection(void);
extern void free_connection(connection_t *);
extern void connection_add(connection_t *);
extern void connection_del(connection_t *);
extern connection_t *lookup_connection(ipv4_t, short unsigned int);
extern void dump_connections(void);
extern int read_connection_config(connection_t *);

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: edge.c,v 1.1.2.6 2002/02/10 21:57:54 guus Exp $
$Id: edge.c,v 1.1.2.7 2002/02/18 16:25:16 guus Exp $
*/
#include "config.h"
@ -47,7 +47,7 @@ int edge_compare(edge_t *a, edge_t *b)
int result;
result = strcmp(a->from.node->name, b->from.node->name);
if(result)
return result;
else
@ -69,7 +69,7 @@ int edge_name_compare(edge_t *a, edge_t *b)
{
int result;
char *name_a1, *name_a2, *name_b1, *name_b2;
if(strcmp(a->from.node->name, a->to.node->name) < 0)
name_a1 = a->from.node->name, name_a2 = a->to.node->name;
else
@ -81,7 +81,7 @@ int edge_name_compare(edge_t *a, edge_t *b)
name_b1 = b->to.node->name, name_b2 = b->from.node->name;
result = strcmp(name_a1, name_b1);
if(result)
return result;
else
@ -91,9 +91,9 @@ int edge_name_compare(edge_t *a, edge_t *b)
int edge_weight_compare(edge_t *a, edge_t *b)
{
int result;
result = a->weight - b->weight;
if(result)
return result;
else
@ -189,23 +189,28 @@ void dump_edges(void)
{
avl_node_t *node;
edge_t *e;
char *from_address, *to_address;
char *from_tcp, *from_udp;
char *to_tcp, *to_udp;
cp
syslog(LOG_DEBUG, _("Edges:"));
for(node = edge_tree->head; node; node = node->next)
{
e = (edge_t *)node->data;
from_address = address2str(e->from.address);
to_address = address2str(e->to.address);
syslog(LOG_DEBUG, _(" %s at %s port %hd - %s at %s port %hd options %ld weight %d"),
e->from.node->name, from_address, e->from.port,
e->to.node->name, to_address, e->to.port,
from_tcp = sockaddr2hostname(&e->from.tcpaddress);
from_udp = sockaddr2hostname(&e->from.udpaddress);
to_tcp = sockaddr2hostname(&e->to.tcpaddress);
to_udp = sockaddr2hostname(&e->to.udpaddress);
syslog(LOG_DEBUG, _(" %s tcp at %s udp at %s - %s tcp at %s udp at %s options %ld weight %d"),
e->from.node->name, from_tcp, from_udp,
e->to.node->name, to_tcp, to_udp,
e->options, e->weight);
free(from_address);
free(to_address);
free(from_tcp);
free(from_udp);
free(to_tcp);
free(to_udp);
}
syslog(LOG_DEBUG, _("End of edges."));
cp
}

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: edge.h,v 1.1.2.5 2002/02/10 21:57:54 guus Exp $
$Id: edge.h,v 1.1.2.6 2002/02/18 16:25:16 guus Exp $
*/
#ifndef __TINC_EDGE_H__
@ -25,14 +25,14 @@
#include <avl_tree.h>
#include "net.h"
#include "node.h"
#include "connection.h"
typedef struct halfconnection_t {
struct node_t *node; /* node associated with this end of the connection */
ipv4_t address; /* real (internet) ip on this end of the meta connection */
port_t port; /* port number of this end of the meta connection */
sockaddr_t tcpaddress; /* real (internet) ip on this end of the meta connection */
sockaddr_t udpaddress; /* real (internet) ip on this end of the vpn connection */
} halfconnection_t;
typedef struct edge_t {

View file

@ -17,12 +17,13 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: device.c,v 1.1.2.3 2002/02/11 12:33:01 guus Exp $
$Id: device.c,v 1.1.2.4 2002/02/18 16:25:19 guus Exp $
*/
#include "config.h"
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
@ -66,7 +67,7 @@ cp
cp
if((device_fd = open(device, O_RDWR | O_NONBLOCK)) < 0)
{
syslog(LOG_ERR, _("Could not open %s: %m"), device);
syslog(LOG_ERR, _("Could not open %s: %s"), device, strerror(errno));
return -1;
}
cp
@ -104,7 +105,7 @@ int read_packet(vpn_packet_t *packet)
cp
if((lenin = read(device_fd, packet->data, MTU)) <= 0)
{
syslog(LOG_ERR, _("Error while reading from %s %s: %m"), device_info, device);
syslog(LOG_ERR, _("Error while reading from %s %s: %s"), device_info, device, strerror(errno));
return -1;
}
@ -129,7 +130,7 @@ cp
if(write(device_fd, packet->data, packet->len) < 0)
{
syslog(LOG_ERR, _("Error while writing to %s %s: %m"), device_info, device);
syslog(LOG_ERR, _("Error while writing to %s %s: %s"), device_info, device, strerror(errno));
return -1;
}

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: graph.c,v 1.1.2.6 2002/02/10 21:57:54 guus Exp $
$Id: graph.c,v 1.1.2.7 2002/02/18 16:25:16 guus Exp $
*/
/* We need to generate two trees from the graph:
@ -186,17 +186,15 @@ void sssp_bfs(void)
to_hc.node->nexthop = (n->nexthop == myself) ? to_hc.node : n->nexthop;
to_hc.node->via = (e->options & OPTION_INDIRECT || n->via != n) ? n->via : to_hc.node;
to_hc.node->options = e->options;
if(to_hc.node->address != to_hc.address || to_hc.node->port != to_hc.port)
if(sockaddrcmp(&to_hc.node->address, &to_hc.udpaddress))
{
node = avl_unlink(node_udp_tree, to_hc.node);
to_hc.node->address = to_hc.address;
to_hc.node->port = to_hc.port;
to_hc.node->address = to_hc.udpaddress;
if(to_hc.node->hostname)
free(to_hc.node->hostname);
to_hc.node->hostname = hostlookup(htonl(to_hc.address));
to_hc.node->hostname = sockaddr2hostname(&to_hc.udpaddress);
avl_insert_node(node_udp_tree, node);
}
to_hc.node->port = to_hc.port;
node = avl_alloc_node();
node->data = to_hc.node;
avl_insert_before(todo_tree, from, node);

View file

@ -17,12 +17,13 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: device.c,v 1.1.2.6 2002/02/11 12:33:01 guus Exp $
$Id: device.c,v 1.1.2.7 2002/02/18 16:25:19 guus Exp $
*/
#include "config.h"
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
@ -85,7 +86,7 @@ cp
cp
if((device_fd = open(device, O_RDWR | O_NONBLOCK)) < 0)
{
syslog(LOG_ERR, _("Could not open %s: %m"), device);
syslog(LOG_ERR, _("Could not open %s: %s"), device, strerror(errno));
return -1;
}
cp
@ -154,7 +155,7 @@ cp
{
if((lenin = read(device_fd, packet->data, MTU)) <= 0)
{
syslog(LOG_ERR, _("Error while reading from %s %s: %m"), device_info, device);
syslog(LOG_ERR, _("Error while reading from %s %s: %s"), device_info, device, strerror(errno));
return -1;
}
@ -164,7 +165,7 @@ cp
{
if((lenin = read(device_fd, packet->data - 2, MTU + 2)) <= 0)
{
syslog(LOG_ERR, _("Error while reading from %s %s: %m"), device_info, device);
syslog(LOG_ERR, _("Error while reading from %s %s: %s"), device_info, device, strerror(errno));
return -1;
}
@ -193,7 +194,7 @@ cp
{
if(write(device_fd, packet->data, packet->len) < 0)
{
syslog(LOG_ERR, _("Can't write to %s %s: %m"), device_info, device);
syslog(LOG_ERR, _("Can't write to %s %s: %s"), device_info, device, strerror(errno));
return -1;
}
}
@ -202,7 +203,7 @@ cp
*(short int *)(packet->data - 2) = packet->len;
if(write(device_fd, packet->data - 2, packet->len + 2) < 0)
{
syslog(LOG_ERR, _("Can't write to %s %s: %m"), device_info, device);
syslog(LOG_ERR, _("Can't write to %s %s: %s"), device_info, device, strerror(errno));
return -1;
}
}

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: meta.c,v 1.1.2.23 2002/02/12 14:36:45 guus Exp $
$Id: meta.c,v 1.1.2.24 2002/02/18 16:25:16 guus Exp $
*/
#include "config.h"
@ -60,7 +60,7 @@ cp
if(write(c->socket, bufp, length) < 0)
{
syslog(LOG_ERR, _("Sending meta data to %s (%s) failed: %m"), c->name, c->hostname);
syslog(LOG_ERR, _("Sending meta data to %s (%s) failed: %s"), c->name, c->hostname, strerror(errno));
return -1;
}
cp
@ -91,7 +91,7 @@ int receive_meta(connection_t *c)
cp
if(getsockopt(c->socket, SOL_SOCKET, SO_ERROR, &x, &l) < 0)
{
syslog(LOG_ERR, _("This is a bug: %s:%d: %d:%m %s (%s)"), __FILE__, __LINE__, c->socket,
syslog(LOG_ERR, _("This is a bug: %s:%d: %d:%s %s (%s)"), __FILE__, __LINE__, c->socket, strerror(errno),
c->name, c->hostname);
return -1;
}
@ -125,8 +125,8 @@ cp
if(errno==EINTR)
return 0;
else
syslog(LOG_ERR, _("Metadata socket read error for %s (%s): %m"),
c->name, c->hostname);
syslog(LOG_ERR, _("Metadata socket read error for %s (%s): %s"),
c->name, c->hostname, strerror(errno));
return -1;
}

1361
src/net.c

File diff suppressed because it is too large Load diff

View file

@ -17,12 +17,15 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: net.h,v 1.9.4.38 2002/02/10 21:57:54 guus Exp $
$Id: net.h,v 1.9.4.39 2002/02/18 16:25:16 guus Exp $
*/
#ifndef __TINC_NET_H__
#define __TINC_NET_H__
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h>
#include "config.h"
@ -37,7 +40,10 @@ typedef struct mac_t
unsigned char x[6];
} mac_t;
typedef unsigned long ipv4_t;
typedef struct ipv4_t
{
unsigned char x[4];
} ipv4_t;
typedef struct ip_mask_t {
ipv4_t address;
@ -53,6 +59,14 @@ typedef unsigned short port_t;
typedef short length_t;
typedef union {
struct sockaddr sa;
struct sockaddr_in in;
struct sockaddr_in6 in6;
} sockaddr_t;
#define SA_PORT(s) ((s.sa.sa_family==AF_INET)?s.in.sin_port:(s.sa.sa_family==AF_INET6)?s.in6.sin6_port:0)
typedef struct vpn_packet_t {
length_t len; /* the actual number of bytes in the `data' field */
unsigned int seqno; /* 32 bits sequence number (network byte order of course) */
@ -73,16 +87,35 @@ typedef struct packet_queue_t {
typedef struct outgoing_t {
char *name;
int timeout;
struct config_t *cfg;
struct addrinfo *ai;
struct addrinfo *aip;
} outgoing_t;
extern int maxtimeout;
extern int seconds_till_retry;
extern int addressfamily;
extern char *request_name[];
extern char *status_text[];
#include "connection.h" /* Yes, very strange placement indeed, but otherwise the typedefs get all tangled up */
extern int tcp_socket;
extern int udp_socket;
extern int keyexpires;
extern int keylifetime;
extern int do_prune;
extern int do_purge;
extern char *myport;
extern void retry_outgoing(outgoing_t *);
extern void handle_incoming_vpn_data(void);
extern void finish_connecting(connection_t *);
extern void do_outgoing_connection(connection_t *);
extern int handle_new_meta_connection(void);
extern int setup_listen_socket(sockaddr_t *);
extern int setup_vpn_in_socket(sockaddr_t *);
extern void send_packet(struct node_t *, vpn_packet_t *);
extern void receive_packet(struct node_t *, vpn_packet_t *);
extern void receive_tcppacket(struct connection_t *, char *, int);

391
src/net_packet.c Normal file
View file

@ -0,0 +1,391 @@
/*
net_packet.c -- Handles in- and outgoing VPN packets
Copyright (C) 1998-2002 Ivo Timmermans <itimmermans@bigfoot.com>,
2000-2002 Guus Sliepen <guus@sliepen.warande.net>
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., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: net_packet.c,v 1.1.2.1 2002/02/18 16:25:16 guus Exp $
*/
#include "config.h"
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#ifdef HAVE_LINUX
#include <netinet/ip.h>
#include <netinet/tcp.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/types.h>
#include <syslog.h>
#include <unistd.h>
#include <sys/ioctl.h>
/* SunOS really wants sys/socket.h BEFORE net/if.h,
and FreeBSD wants these lines below the rest. */
#include <arpa/inet.h>
#include <sys/socket.h>
#include <net/if.h>
#include <openssl/rand.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/hmac.h>
#ifndef HAVE_RAND_PSEUDO_BYTES
#define RAND_pseudo_bytes RAND_bytes
#endif
#include <zlib.h>
#include <utils.h>
#include <xalloc.h>
#include <avl_tree.h>
#include <list.h>
#include "conf.h"
#include "connection.h"
#include "meta.h"
#include "net.h"
#include "netutl.h"
#include "process.h"
#include "protocol.h"
#include "subnet.h"
#include "graph.h"
#include "process.h"
#include "route.h"
#include "device.h"
#include "event.h"
#include "system.h"
int keylifetime = 0;
int keyexpires = 0;
#define MAX_SEQNO 1073741824
/* VPN packet I/O */
void receive_udppacket(node_t *n, vpn_packet_t *inpkt)
{
vpn_packet_t pkt1, pkt2;
vpn_packet_t *pkt[] = {&pkt1, &pkt2, &pkt1, &pkt2};
int nextpkt = 0;
vpn_packet_t *outpkt = pkt[0];
int outlen, outpad;
long int complen = MTU + 12;
EVP_CIPHER_CTX ctx;
char hmac[EVP_MAX_MD_SIZE];
cp
/* Check the message authentication code */
if(myself->digest && myself->maclength)
{
inpkt->len -= myself->maclength;
HMAC(myself->digest, myself->key, myself->keylength, (char *)&inpkt->seqno, inpkt->len, hmac, NULL);
if(memcmp(hmac, (char *)&inpkt->seqno + inpkt->len, myself->maclength))
{
syslog(LOG_DEBUG, _("Got unauthenticated packet from %s (%s)"), n->name, n->hostname);
return;
}
}
/* Decrypt the packet */
if(myself->cipher)
{
outpkt = pkt[nextpkt++];
EVP_DecryptInit(&ctx, myself->cipher, myself->key, myself->key + myself->cipher->key_len);
EVP_DecryptUpdate(&ctx, (char *)&outpkt->seqno, &outlen, (char *)&inpkt->seqno, inpkt->len);
EVP_DecryptFinal(&ctx, (char *)&outpkt->seqno + outlen, &outpad);
outpkt->len = outlen + outpad;
inpkt = outpkt;
}
/* Check the sequence number */
inpkt->len -= sizeof(inpkt->seqno);
inpkt->seqno = ntohl(inpkt->seqno);
if(inpkt->seqno <= n->received_seqno)
{
syslog(LOG_DEBUG, _("Got late or replayed packet from %s (%s), seqno %d"), n->name, n->hostname, inpkt->seqno);
return;
}
n->received_seqno = inpkt->seqno;
if(n->received_seqno > MAX_SEQNO)
keyexpires = 0;
/* Decompress the packet */
if(myself->compression)
{
outpkt = pkt[nextpkt++];
if(uncompress(outpkt->data, &complen, inpkt->data, inpkt->len) != Z_OK)
{
syslog(LOG_ERR, _("Error while uncompressing packet from %s (%s)"), n->name, n->hostname);
return;
}
outpkt->len = complen;
inpkt = outpkt;
}
receive_packet(n, inpkt);
cp
}
void receive_tcppacket(connection_t *c, char *buffer, int len)
{
vpn_packet_t outpkt;
cp
outpkt.len = len;
memcpy(outpkt.data, buffer, len);
receive_packet(c->node, &outpkt);
cp
}
void receive_packet(node_t *n, vpn_packet_t *packet)
{
cp
if(debug_lvl >= DEBUG_TRAFFIC)
syslog(LOG_DEBUG, _("Received packet of %d bytes from %s (%s)"), packet->len, n->name, n->hostname);
route_incoming(n, packet);
cp
}
void send_udppacket(node_t *n, vpn_packet_t *inpkt)
{
vpn_packet_t pkt1, pkt2;
vpn_packet_t *pkt[] = {&pkt1, &pkt2, &pkt1, &pkt2};
int nextpkt = 0;
vpn_packet_t *outpkt;
int outlen, outpad;
long int complen = MTU + 12;
EVP_CIPHER_CTX ctx;
vpn_packet_t *copy;
cp
if(!n->status.validkey)
{
if(debug_lvl >= DEBUG_TRAFFIC)
syslog(LOG_INFO, _("No valid key known yet for %s (%s), queueing packet"),
n->name, n->hostname);
/* Since packet is on the stack of handle_tap_input(),
we have to make a copy of it first. */
copy = xmalloc(sizeof(vpn_packet_t));
memcpy(copy, inpkt, sizeof(vpn_packet_t));
list_insert_tail(n->queue, copy);
if(!n->status.waitingforkey)
send_req_key(n->nexthop->connection, myself, n);
return;
}
/* Compress the packet */
if(n->compression)
{
outpkt = pkt[nextpkt++];
if(compress2(outpkt->data, &complen, inpkt->data, inpkt->len, n->compression) != Z_OK)
{
syslog(LOG_ERR, _("Error while compressing packet to %s (%s)"), n->name, n->hostname);
return;
}
outpkt->len = complen;
inpkt = outpkt;
}
/* Add sequence number */
inpkt->seqno = htonl(++(n->sent_seqno));
inpkt->len += sizeof(inpkt->seqno);
/* Encrypt the packet */
if(n->cipher)
{
outpkt = pkt[nextpkt++];
EVP_EncryptInit(&ctx, n->cipher, n->key, n->key + n->cipher->key_len);
EVP_EncryptUpdate(&ctx, (char *)&outpkt->seqno, &outlen, (char *)&inpkt->seqno, inpkt->len);
EVP_EncryptFinal(&ctx, (char *)&outpkt->seqno + outlen, &outpad);
outpkt->len = outlen + outpad;
inpkt = outpkt;
}
/* Add the message authentication code */
if(n->digest && n->maclength)
{
HMAC(n->digest, n->key, n->keylength, (char *)&inpkt->seqno, inpkt->len, (char *)&inpkt->seqno + inpkt->len, &outlen);
inpkt->len += n->maclength;
}
/* Send the packet */
if((sendto(udp_socket, (char *)&inpkt->seqno, inpkt->len, 0, &(n->address.sa), sizeof(sockaddr_t))) < 0)
{
syslog(LOG_ERR, _("Error sending packet to %s (%s): %s"),
n->name, n->hostname, strerror(errno));
return;
}
cp
}
/*
send a packet to the given vpn ip.
*/
void send_packet(node_t *n, vpn_packet_t *packet)
{
node_t *via;
cp
if(debug_lvl >= DEBUG_TRAFFIC)
syslog(LOG_ERR, _("Sending packet of %d bytes to %s (%s)"),
packet->len, n->name, n->hostname);
if(n == myself)
{
if(debug_lvl >= DEBUG_TRAFFIC)
{
syslog(LOG_NOTICE, _("Packet is looping back to us!"));
}
return;
}
if(!n->status.reachable)
{
if(debug_lvl >= DEBUG_TRAFFIC)
syslog(LOG_INFO, _("Node %s (%s) is not reachable"),
n->name, n->hostname);
return;
}
via = (n->via == myself)?n->nexthop:n->via;
if(via != n && debug_lvl >= DEBUG_TRAFFIC)
syslog(LOG_ERR, _("Sending packet to %s via %s (%s)"),
n->name, via->name, n->via->hostname);
if((myself->options | via->options) & OPTION_TCPONLY)
{
if(send_tcppacket(via->connection, packet))
terminate_connection(via->connection, 1);
}
else
send_udppacket(via, packet);
}
/* Broadcast a packet using the minimum spanning tree */
void broadcast_packet(node_t *from, vpn_packet_t *packet)
{
avl_node_t *node;
connection_t *c;
cp
if(debug_lvl >= DEBUG_TRAFFIC)
syslog(LOG_INFO, _("Broadcasting packet of %d bytes from %s (%s)"),
packet->len, from->name, from->hostname);
for(node = connection_tree->head; node; node = node->next)
{
c = (connection_t *)node->data;
if(c->status.active && c->status.mst && c != from->nexthop->connection)
send_packet(c->node, packet);
}
cp
}
void flush_queue(node_t *n)
{
list_node_t *node, *next;
cp
if(debug_lvl >= DEBUG_TRAFFIC)
syslog(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, (vpn_packet_t *)node->data);
list_delete_node(n->queue, node);
}
cp
}
void handle_incoming_vpn_data(void)
{
vpn_packet_t pkt;
int x, l = sizeof(x);
char *hostname;
sockaddr_t from;
socklen_t fromlen = sizeof(from);
node_t *n;
cp
if(getsockopt(udp_socket, SOL_SOCKET, SO_ERROR, &x, &l) < 0)
{
syslog(LOG_ERR, _("This is a bug: %s:%d: %d:%s"),
__FILE__, __LINE__, udp_socket, strerror(errno));
return;
}
if(x)
{
syslog(LOG_ERR, _("Incoming data socket error: %s"), strerror(x));
return;
}
if((pkt.len = recvfrom(udp_socket, (char *)&pkt.seqno, MAXSIZE, 0, &from.sa, &fromlen)) <= 0)
{
syslog(LOG_ERR, _("Receiving packet failed: %s"), strerror(errno));
return;
}
n = lookup_node_udp(&from);
if(!n)
{
hostname = sockaddr2hostname(&from);
syslog(LOG_WARNING, _("Received UDP packet from unknown source %s"), hostname);
free(hostname);
return;
}
/*
if(n->connection)
n->connection->last_ping_time = time(NULL);
*/
receive_udppacket(n, &pkt);
cp
}

557
src/net_setup.c Normal file
View file

@ -0,0 +1,557 @@
/*
net_setup.c -- Setup.
Copyright (C) 1998-2002 Ivo Timmermans <itimmermans@bigfoot.com>,
2000-2002 Guus Sliepen <guus@sliepen.warande.net>
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., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: net_setup.c,v 1.1.2.1 2002/02/18 16:25:16 guus Exp $
*/
#include "config.h"
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#ifdef HAVE_LINUX
#include <netinet/ip.h>
#include <netinet/tcp.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/types.h>
#include <syslog.h>
#include <unistd.h>
#include <sys/ioctl.h>
/* SunOS really wants sys/socket.h BEFORE net/if.h,
and FreeBSD wants these lines below the rest. */
#include <arpa/inet.h>
#include <sys/socket.h>
#include <net/if.h>
#include <openssl/pem.h>
#include <openssl/rsa.h>
#include <openssl/rand.h>
#include <utils.h>
#include <xalloc.h>
#include <avl_tree.h>
#include <list.h>
#include "conf.h"
#include "connection.h"
#include "meta.h"
#include "net.h"
#include "netutl.h"
#include "process.h"
#include "protocol.h"
#include "subnet.h"
#include "graph.h"
#include "process.h"
#include "route.h"
#include "device.h"
#include "event.h"
#include "system.h"
char *myport;
int read_rsa_public_key(connection_t *c)
{
FILE *fp;
char *fname;
char *key;
cp
if(!c->rsa_key)
c->rsa_key = RSA_new();
/* First, check for simple PublicKey statement */
if(get_config_string(lookup_config(c->config_tree, "PublicKey"), &key))
{
BN_hex2bn(&c->rsa_key->n, key);
BN_hex2bn(&c->rsa_key->e, "FFFF");
free(key);
return 0;
}
/* Else, check for PublicKeyFile statement and read it */
if(get_config_string(lookup_config(c->config_tree, "PublicKeyFile"), &fname))
{
if(is_safe_path(fname))
{
if((fp = fopen(fname, "r")) == NULL)
{
syslog(LOG_ERR, _("Error reading RSA public key file `%s': %s"),
fname, strerror(errno));
free(fname);
return -1;
}
free(fname);
c->rsa_key = PEM_read_RSAPublicKey(fp, &c->rsa_key, NULL, NULL);
fclose(fp);
if(!c->rsa_key)
{
syslog(LOG_ERR, _("Reading RSA public key file `%s' failed: %s"),
fname, strerror(errno));
return -1;
}
return 0;
}
else
{
free(fname);
return -1;
}
}
/* Else, check if a harnessed public key is in the config file */
asprintf(&fname, "%s/hosts/%s", confbase, c->name);
if((fp = fopen(fname, "r")))
{
c->rsa_key = PEM_read_RSAPublicKey(fp, &c->rsa_key, NULL, NULL);
fclose(fp);
}
free(fname);
if(c->rsa_key)
return 0;
else
{
syslog(LOG_ERR, _("No public key for %s specified!"), c->name);
return -1;
}
}
int read_rsa_private_key(void)
{
FILE *fp;
char *fname, *key;
cp
if(get_config_string(lookup_config(config_tree, "PrivateKey"), &key))
{
myself->connection->rsa_key = RSA_new();
BN_hex2bn(&myself->connection->rsa_key->d, key);
BN_hex2bn(&myself->connection->rsa_key->e, "FFFF");
free(key);
return 0;
}
if(!get_config_string(lookup_config(config_tree, "PrivateKeyFile"), &fname))
asprintf(&fname, "%s/rsa_key.priv", confbase);
if(is_safe_path(fname))
{
if((fp = fopen(fname, "r")) == NULL)
{
syslog(LOG_ERR, _("Error reading RSA private key file `%s': %s"),
fname, strerror(errno));
free(fname);
return -1;
}
free(fname);
myself->connection->rsa_key = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
fclose(fp);
if(!myself->connection->rsa_key)
{
syslog(LOG_ERR, _("Reading RSA private key file `%s' failed: %s"),
fname, strerror(errno));
return -1;
}
return 0;
}
free(fname);
return -1;
}
int check_rsa_key(RSA *rsa_key)
{
char *test1, *test2, *test3;
cp
if(rsa_key->p && rsa_key->q)
{
if(RSA_check_key(rsa_key) != 1)
return -1;
}
else
{
test1 = xmalloc(RSA_size(rsa_key));
test2 = xmalloc(RSA_size(rsa_key));
test3 = xmalloc(RSA_size(rsa_key));
if(RSA_public_encrypt(RSA_size(rsa_key), test1, test2, rsa_key, RSA_NO_PADDING) != RSA_size(rsa_key))
return -1;
if(RSA_private_decrypt(RSA_size(rsa_key), test2, test3, rsa_key, RSA_NO_PADDING) != RSA_size(rsa_key))
return -1;
if(memcmp(test1, test3, RSA_size(rsa_key)))
return -1;
}
cp
return 0;
}
/*
Configure node_t myself and set up the local sockets (listen only)
*/
int setup_myself(void)
{
config_t *cfg;
subnet_t *subnet;
char *name, *mode, *afname, *cipher, *digest;
struct addrinfo hint, *ai;
int choice;
cp
myself = new_node();
myself->connection = new_connection();
init_configuration(&myself->connection->config_tree);
asprintf(&myself->hostname, _("MYSELF"));
asprintf(&myself->connection->hostname, _("MYSELF"));
myself->connection->options = 0;
myself->connection->protocol_version = PROT_CURRENT;
if(!get_config_string(lookup_config(config_tree, "Name"), &name)) /* Not acceptable */
{
syslog(LOG_ERR, _("Name for tinc daemon required!"));
return -1;
}
if(check_id(name))
{
syslog(LOG_ERR, _("Invalid name for myself!"));
free(name);
return -1;
}
myself->name = name;
myself->connection->name = xstrdup(name);
cp
if(read_rsa_private_key())
return -1;
if(read_connection_config(myself->connection))
{
syslog(LOG_ERR, _("Cannot open host configuration file for myself!"));
return -1;
}
if(read_rsa_public_key(myself->connection))
return -1;
cp
if(check_rsa_key(myself->connection->rsa_key))
{
syslog(LOG_ERR, _("Invalid public/private keypair!"));
return -1;
}
if(!get_config_string(lookup_config(myself->connection->config_tree, "Port"), &myport))
asprintf(&myport, "655");
/* Read in all the subnets specified in the host configuration file */
cfg = lookup_config(myself->connection->config_tree, "Subnet");
while(cfg)
{
if(!get_config_subnet(cfg, &subnet))
return -1;
subnet_add(myself, subnet);
cfg = lookup_config_next(myself->connection->config_tree, cfg);
}
cp
/* Check some options */
if(get_config_bool(lookup_config(config_tree, "IndirectData"), &choice))
if(choice)
myself->options |= OPTION_INDIRECT;
if(get_config_bool(lookup_config(config_tree, "TCPOnly"), &choice))
if(choice)
myself->options |= OPTION_TCPONLY;
if(get_config_bool(lookup_config(myself->connection->config_tree, "IndirectData"), &choice))
if(choice)
myself->options |= OPTION_INDIRECT;
if(get_config_bool(lookup_config(myself->connection->config_tree, "TCPOnly"), &choice))
if(choice)
myself->options |= OPTION_TCPONLY;
if(myself->options & OPTION_TCPONLY)
myself->options |= OPTION_INDIRECT;
if(get_config_string(lookup_config(config_tree, "Mode"), &mode))
{
if(!strcasecmp(mode, "router"))
routing_mode = RMODE_ROUTER;
else if (!strcasecmp(mode, "switch"))
routing_mode = RMODE_SWITCH;
else if (!strcasecmp(mode, "hub"))
routing_mode = RMODE_HUB;
else
{
syslog(LOG_ERR, _("Invalid routing mode!"));
return -1;
}
free(mode);
}
else
routing_mode = RMODE_ROUTER;
if(get_config_int(lookup_config(myself->connection->config_tree, "MaxTimeout"), &maxtimeout))
{
if(maxtimeout <= 0)
{
syslog(LOG_ERR, _("Bogus maximum timeout!"));
return -1;
}
}
else
maxtimeout = 900;
if(get_config_string(lookup_config(config_tree, "AddressFamily"), &afname))
{
if(!strcasecmp(afname, "IPv4"))
addressfamily = AF_INET;
else if (!strcasecmp(afname, "IPv6"))
addressfamily = AF_INET6;
else if (!strcasecmp(afname, "any"))
addressfamily = AF_UNSPEC;
else
{
syslog(LOG_ERR, _("Invalid address family!"));
return -1;
}
free(afname);
}
else
addressfamily = AF_INET;
get_config_bool(lookup_config(config_tree, "Hostnames"), &hostnames);
cp
/* Generate packet encryption key */
if(get_config_string(lookup_config(myself->connection->config_tree, "Cipher"), &cipher))
{
if(!strcasecmp(cipher, "none"))
{
myself->cipher = NULL;
}
else
{
if(!(myself->cipher = EVP_get_cipherbyname(cipher)))
{
syslog(LOG_ERR, _("Unrecognized cipher type!"));
return -1;
}
}
}
else
myself->cipher = EVP_bf_cbc();
if(myself->cipher)
myself->keylength = myself->cipher->key_len + myself->cipher->iv_len;
else
myself->keylength = 1;
myself->key = (char *)xmalloc(myself->keylength);
RAND_pseudo_bytes(myself->key, myself->keylength);
if(!get_config_int(lookup_config(config_tree, "KeyExpire"), &keylifetime))
keylifetime = 3600;
keyexpires = time(NULL) + keylifetime;
/* Check if we want to use message authentication codes... */
if(get_config_string(lookup_config(myself->connection->config_tree, "Digest"), &digest))
{
if(!strcasecmp(digest, "none"))
{
myself->digest = NULL;
}
else
{
if(!(myself->digest = EVP_get_digestbyname(digest)))
{
syslog(LOG_ERR, _("Unrecognized digest type!"));
return -1;
}
}
}
else
myself->digest = EVP_sha1();
if(get_config_int(lookup_config(myself->connection->config_tree, "MACLength"), &myself->maclength))
{
if(myself->digest)
{
if(myself->maclength > myself->digest->md_size)
{
syslog(LOG_ERR, _("MAC length exceeds size of digest!"));
return -1;
}
else if (myself->maclength < 0)
{
syslog(LOG_ERR, _("Bogus MAC length!"));
return -1;
}
}
}
else
myself->maclength = 4;
/* Compression */
if(get_config_int(lookup_config(myself->connection->config_tree, "Compression"), &myself->compression))
{
if(myself->compression < 0 || myself->compression > 9)
{
syslog(LOG_ERR, _("Bogus compression level!"));
return -1;
}
}
else
myself->compression = 0;
cp
/* Done */
myself->nexthop = myself;
myself->via = myself;
myself->status.active = 1;
node_add(myself);
graph();
cp
/* Open sockets */
hint.ai_family = (addressfamily == AF_UNSPEC)?AF_INET6:addressfamily;
hint.ai_socktype = SOCK_STREAM;
hint.ai_protocol = IPPROTO_TCP;
hint.ai_flags = AI_PASSIVE;
if(getaddrinfo(NULL, myport, &hint, &ai) || !ai)
{
syslog(LOG_ERR, _("System call `%s' failed: %s"), "getaddrinfo", strerror(errno));
return -1;
}
if((tcp_socket = setup_listen_socket((sockaddr_t *)ai->ai_addr)) < 0)
{
syslog(LOG_ERR, _("Unable to set up a listening TCP socket!"));
return -1;
}
if((udp_socket = setup_vpn_in_socket((sockaddr_t *)ai->ai_addr)) < 0)
{
syslog(LOG_ERR, _("Unable to set up a listening UDP socket!"));
return -1;
}
freeaddrinfo(ai);
syslog(LOG_NOTICE, _("Ready: listening on port %s"), myport);
cp
return 0;
}
/*
setup all initial network connections
*/
int setup_network_connections(void)
{
cp
init_connections();
init_subnets();
init_nodes();
init_edges();
init_events();
if(get_config_int(lookup_config(config_tree, "PingTimeout"), &pingtimeout))
{
if(pingtimeout < 1)
{
pingtimeout = 86400;
}
}
else
pingtimeout = 60;
if(setup_device() < 0)
return -1;
/* Run tinc-up script to further initialize the tap interface */
execute_script("tinc-up");
if(setup_myself() < 0)
return -1;
try_outgoing_connections();
cp
return 0;
}
/*
close all open network connections
*/
void close_network_connections(void)
{
avl_node_t *node, *next;
connection_t *c;
cp
for(node = connection_tree->head; node; node = next)
{
next = node->next;
c = (connection_t *)node->data;
if(c->outgoing)
free(c->outgoing->name), free(c->outgoing);
terminate_connection(c, 0);
}
if(myself && myself->connection)
terminate_connection(myself->connection, 0);
close(udp_socket);
close(tcp_socket);
exit_events();
exit_edges();
exit_subnets();
exit_nodes();
exit_connections();
execute_script("tinc-down");
close_device();
cp
return;
}

456
src/net_socket.c Normal file
View file

@ -0,0 +1,456 @@
/*
net_socket.c -- Handle various kinds of sockets.
Copyright (C) 1998-2002 Ivo Timmermans <itimmermans@bigfoot.com>,
2000-2002 Guus Sliepen <guus@sliepen.warande.net>
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., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: net_socket.c,v 1.1.2.1 2002/02/18 16:25:16 guus Exp $
*/
#include "config.h"
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#ifdef HAVE_LINUX
#include <netinet/ip.h>
#include <netinet/tcp.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/types.h>
#include <syslog.h>
#include <unistd.h>
#include <sys/ioctl.h>
/* SunOS really wants sys/socket.h BEFORE net/if.h,
and FreeBSD wants these lines below the rest. */
#include <arpa/inet.h>
#include <sys/socket.h>
#include <net/if.h>
#include <utils.h>
#include <xalloc.h>
#include <avl_tree.h>
#include <list.h>
#include "conf.h"
#include "connection.h"
#include "meta.h"
#include "net.h"
#include "netutl.h"
#include "process.h"
#include "protocol.h"
#include "subnet.h"
#include "graph.h"
#include "process.h"
#include "route.h"
#include "device.h"
#include "event.h"
#include "system.h"
int addressfamily = AF_INET;
int maxtimeout = 900;
int seconds_till_retry = 5;
int tcp_socket = -1;
int udp_socket = -1;
/* Setup sockets */
int setup_listen_socket(sockaddr_t *sa)
{
int nfd, flags;
char *addrstr;
int option;
#ifdef HAVE_LINUX
char *interface;
#endif
cp
if((nfd = socket(sa->sa.sa_family, SOCK_STREAM, IPPROTO_TCP)) < 0)
{
syslog(LOG_ERR, _("Creating metasocket failed: %s"), strerror(errno));
return -1;
}
flags = fcntl(nfd, F_GETFL);
if(fcntl(nfd, F_SETFL, flags | O_NONBLOCK) < 0)
{
close(nfd);
syslog(LOG_ERR, _("System call `%s' failed: %s"), "fcntl", strerror(errno));
return -1;
}
/* Optimize TCP settings */
option = 1;
setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));
#ifdef HAVE_LINUX
setsockopt(nfd, SOL_TCP, TCP_NODELAY, &option, sizeof(option));
option = IPTOS_LOWDELAY;
setsockopt(nfd, SOL_IP, IP_TOS, &option, sizeof(option));
if(get_config_string(lookup_config(config_tree, "BindToInterface"), &interface))
if(setsockopt(nfd, SOL_SOCKET, SO_BINDTODEVICE, interface, strlen(interface)))
{
close(nfd);
syslog(LOG_ERR, _("Can't bind to interface %s: %s"), interface, strerror(errno));
return -1;
}
#endif
if(bind(nfd, &sa->sa, sizeof(*sa)))
{
close(nfd);
addrstr = sockaddr2hostname(sa);
syslog(LOG_ERR, _("Can't bind to %s/tcp: %s"), addrstr, strerror(errno));
free(addrstr);
return -1;
}
if(listen(nfd, 3))
{
close(nfd);
syslog(LOG_ERR, _("System call `%s' failed: %s"), "listen", strerror(errno));
return -1;
}
cp
return nfd;
}
int setup_vpn_in_socket(sockaddr_t *sa)
{
int nfd, flags;
char *addrstr;
int option;
#ifdef HAVE_LINUX
char *interface;
#endif
cp
if((nfd = socket(sa->sa.sa_family, SOCK_DGRAM, IPPROTO_UDP)) < 0)
{
syslog(LOG_ERR, _("Creating UDP socket failed: %s"), strerror(errno));
return -1;
}
flags = fcntl(nfd, F_GETFL);
if(fcntl(nfd, F_SETFL, flags | O_NONBLOCK) < 0)
{
close(nfd);
syslog(LOG_ERR, _("System call `%s' failed: %s"), "fcntl", strerror(errno));
return -1;
}
option = 1;
setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));
#ifdef HAVE_LINUX
if(get_config_string(lookup_config(config_tree, "BindToInterface"), &interface))
if(setsockopt(nfd, SOL_SOCKET, SO_BINDTODEVICE, interface, strlen(interface)))
{
close(nfd);
syslog(LOG_ERR, _("Can't bind to interface %s: %s"), interface, strerror(errno));
return -1;
}
#endif
if(bind(nfd, &sa->sa, sizeof(*sa)))
{
close(nfd);
addrstr = sockaddr2hostname(sa);
syslog(LOG_ERR, _("Can't bind to %s/udp: %s"), addrstr, strerror(errno));
free(addrstr);
return -1;
}
cp
return nfd;
}
void retry_outgoing(outgoing_t *outgoing)
{
event_t *event;
cp
outgoing->timeout += 5;
if(outgoing->timeout > maxtimeout)
outgoing->timeout = maxtimeout;
event = new_event();
event->handler = (event_handler_t)setup_outgoing_connection;
event->time = time(NULL) + outgoing->timeout;
event->data = outgoing;
event_add(event);
if(debug_lvl >= DEBUG_CONNECTIONS)
syslog(LOG_NOTICE, _("Trying to re-establish outgoing connection in %d seconds"), outgoing->timeout);
cp
}
int setup_outgoing_socket(connection_t *c)
{
int option;
cp
if(debug_lvl >= DEBUG_CONNECTIONS)
syslog(LOG_INFO, _("Trying to connect to %s (%s)"), c->name, c->hostname);
c->socket = socket(c->address.sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
if(c->socket == -1)
{
syslog(LOG_ERR, _("Creating socket for %s failed: %s"), c->hostname, strerror(errno));
return -1;
}
/* Optimize TCP settings */
#ifdef HAVE_LINUX
option = 1;
setsockopt(c->socket, SOL_TCP, TCP_NODELAY, &option, sizeof(option));
option = IPTOS_LOWDELAY;
setsockopt(c->socket, SOL_IP, IP_TOS, &option, sizeof(option));
#endif
/* Connect */
if(connect(c->socket, &c->address.sa, sizeof(c->address)) == -1)
{
close(c->socket);
syslog(LOG_ERR, _("%s: %s"), c->hostname, strerror(errno));
return -1;
}
if(debug_lvl >= DEBUG_CONNECTIONS)
syslog(LOG_INFO, _("Connected to %s (%s)"), c->name, c->hostname);
cp
return 0;
}
void finish_connecting(connection_t *c)
{
cp
if(debug_lvl >= DEBUG_CONNECTIONS)
syslog(LOG_INFO, _("Connected to %s (%s)"), c->name, c->hostname);
c->last_ping_time = time(NULL);
send_id(c);
cp
}
void do_outgoing_connection(connection_t *c)
{
char *address, *port;
int option, result, flags;
cp
begin:
if(!c->outgoing->ai)
{
if(!c->outgoing->cfg)
{
if(debug_lvl >= DEBUG_CONNECTIONS)
syslog(LOG_ERR, _("Could not set up a meta connection to %s"), c->name);
c->status.remove = 1;
do_prune = 1;
retry_outgoing(c->outgoing);
return;
}
get_config_string(c->outgoing->cfg, &address);
if(!get_config_string(lookup_config(c->config_tree, "Port"), &port))
asprintf(&port, "655");
c->outgoing->ai = str2addrinfo(address, port, SOCK_STREAM);
free(address);
free(port);
c->outgoing->aip = c->outgoing->ai;
c->outgoing->cfg = lookup_config_next(c->config_tree, c->outgoing->cfg);
}
if(!c->outgoing->aip)
{
freeaddrinfo(c->outgoing->ai);
c->outgoing->ai = NULL;
goto begin;
}
memcpy(&c->address, c->outgoing->aip->ai_addr, c->outgoing->aip->ai_addrlen);
c->outgoing->aip = c->outgoing->aip->ai_next;
if(c->hostname)
free(c->hostname);
c->hostname = sockaddr2hostname(&c->address);
if(debug_lvl >= DEBUG_CONNECTIONS)
syslog(LOG_INFO, _("Trying to connect to %s (%s)"), c->name, c->hostname);
c->socket = socket(c->address.sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
if(c->socket == -1)
{
if(debug_lvl >= DEBUG_CONNECTIONS)
syslog(LOG_ERR, _("Creating socket for %s failed: %s"), c->hostname, strerror(errno));
goto begin;
}
/* Optimize TCP settings */
#ifdef HAVE_LINUX
option = 1;
setsockopt(c->socket, SOL_TCP, TCP_NODELAY, &option, sizeof(option));
option = IPTOS_LOWDELAY;
setsockopt(c->socket, SOL_IP, IP_TOS, &option, sizeof(option));
#endif
/* Non-blocking */
flags = fcntl(c->socket, F_GETFL);
if(fcntl(c->socket, F_SETFL, flags | O_NONBLOCK) < 0)
{
syslog(LOG_ERR, _("fcntl for %s: %s"), c->hostname, strerror(errno));
}
/* Connect */
result = connect(c->socket, &c->address.sa, sizeof(c->address));
if(result == -1)
{
if(errno == EINPROGRESS)
{
c->status.connecting = 1;
return;
}
close(c->socket);
if(debug_lvl >= DEBUG_CONNECTIONS)
syslog(LOG_ERR, _("%s: %s"), c->hostname, strerror(errno));
goto begin;
}
finish_connecting(c);
return;
cp
}
void setup_outgoing_connection(outgoing_t *outgoing)
{
connection_t *c;
node_t *n;
cp
n = lookup_node(outgoing->name);
if(n)
if(n->connection)
{
if(debug_lvl >= DEBUG_CONNECTIONS)
syslog(LOG_INFO, _("Already connected to %s"), outgoing->name);
n->connection->outgoing = outgoing;
return;
}
c = new_connection();
c->name = xstrdup(outgoing->name);
init_configuration(&c->config_tree);
read_connection_config(c);
outgoing->cfg = lookup_config(c->config_tree, "Address");
if(!outgoing->cfg)
{
syslog(LOG_ERR, _("No address specified for %s"), c->name);
free_connection(c);
free(outgoing->name);
free(outgoing);
return;
}
c->outgoing = outgoing;
c->last_ping_time = time(NULL);
connection_add(c);
do_outgoing_connection(c);
}
/*
accept a new tcp connect and create a
new connection
*/
int handle_new_meta_connection()
{
connection_t *c;
sockaddr_t sa;
int fd, len = sizeof(sa);
cp
if((fd = accept(tcp_socket, &sa.sa, &len)) < 0)
{
syslog(LOG_ERR, _("Accepting a new connection failed: %s"), strerror(errno));
return -1;
}
c = new_connection();
c->address = sa;
c->hostname = sockaddr2hostname(&sa);
c->socket = fd;
c->last_ping_time = time(NULL);
if(debug_lvl >= DEBUG_CONNECTIONS)
syslog(LOG_NOTICE, _("Connection from %s"), c->hostname);
connection_add(c);
c->allow_request = ID;
send_id(c);
cp
return 0;
}
void try_outgoing_connections(void)
{
static config_t *cfg = NULL;
char *name;
outgoing_t *outgoing;
cp
for(cfg = lookup_config(config_tree, "ConnectTo"); cfg; cfg = lookup_config_next(config_tree, cfg))
{
get_config_string(cfg, &name);
if(check_id(name))
{
syslog(LOG_ERR, _("Invalid name for outgoing connection in %s line %d"), cfg->file, cfg->line);
free(name);
continue;
}
outgoing = xmalloc_and_zero(sizeof(*outgoing));
outgoing->name = name;
setup_outgoing_connection(outgoing);
}
}

View file

@ -17,12 +17,13 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: device.c,v 1.1.2.1 2002/02/12 14:40:12 guus Exp $
$Id: device.c,v 1.1.2.2 2002/02/18 16:25:19 guus Exp $
*/
#include "config.h"
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/stat.h>
@ -70,7 +71,7 @@ int setup_device(void)
cp
if((device_fd = open(device, O_RDWR | O_NONBLOCK)) < 0)
{
syslog(LOG_ERR, _("Could not open %s: %m"), device);
syslog(LOG_ERR, _("Could not open %s: %s"), device, strerror(errno));
return -1;
}
cp
@ -107,7 +108,7 @@ cp
if((lenin = readv(device_fd, vector, 2)) <= 0)
{
syslog(LOG_ERR, _("Error while reading from %s %s: %m"), device_info, device);
syslog(LOG_ERR, _("Error while reading from %s %s: %s"), device_info, device, strerror(errno));
return -1;
}
@ -145,7 +146,7 @@ cp
if(writev(device_fd, vector, 2) < 0)
{
syslog(LOG_ERR, _("Can't write to %s %s: %m"), device_info, device);
syslog(LOG_ERR, _("Can't write to %s %s: %s"), device_info, device, strerror(errno));
return -1;
}

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: netutl.c,v 1.12.4.23 2002/02/11 10:16:18 guus Exp $
$Id: netutl.c,v 1.12.4.24 2002/02/18 16:25:16 guus Exp $
*/
#include "config.h"
@ -28,6 +28,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/socket.h>
#include <syslog.h>
#include <arpa/inet.h>
@ -42,64 +43,183 @@
#include "system.h"
char *hostlookup(unsigned long addr)
{
char *name;
struct hostent *host = NULL;
struct in_addr in;
int lookup_hostname = 0;
cp
in.s_addr = addr;
get_config_bool(lookup_config(config_tree, "Hostnames"), &lookup_hostname);
if(lookup_hostname)
host = gethostbyaddr((char *)&in, sizeof(in), AF_INET);
if(!lookup_hostname || !host)
{
asprintf(&name, "%s", inet_ntoa(in));
}
else
{
asprintf(&name, "%s", host->h_name);
}
cp
return name;
}
int hostnames = 0;
/*
Turn a string into an IP address
return NULL on failure
Should support IPv6 and other stuff in the future.
Turn a string into a struct addrinfo.
Return NULL on failure.
*/
ipv4_t str2address(char *str)
struct addrinfo *str2addrinfo(char *address, char *service, int socktype)
{
ipv4_t address;
struct hostent *h;
struct addrinfo hint, *ai;
int err;
cp
if(!(h = gethostbyname(str)))
memset(&hint, 0, sizeof(hint));
hint.ai_family = addressfamily;
hint.ai_socktype = socktype;
if((err = getaddrinfo(address, service, &hint, &ai)))
{
if(debug_lvl >= DEBUG_ERROR)
syslog(LOG_WARNING, _("Error looking up `%s': %s\n"), str, strerror(errno));
return 0;
syslog(LOG_WARNING, _("Error looking up %s port %s: %s\n"), address, service, gai_strerror(err));
cp_trace();
return NULL;
}
address = ntohl(*((ipv4_t*)(h->h_addr_list[0])));
cp
return address;
return ai;
}
char *address2str(ipv4_t address)
sockaddr_t str2sockaddr(char *address, char *port)
{
struct addrinfo hint, *ai;
sockaddr_t result;
int err;
cp
memset(&hint, 0, sizeof(hint));
hint.ai_family = AF_UNSPEC;
hint.ai_flags = AI_NUMERICHOST;
hint.ai_socktype = SOCK_STREAM;
if((err = getaddrinfo(address, port, &hint, &ai) || !ai))
{
syslog(LOG_ERR, _("Error looking up %s port %s: %s\n"), address, port, gai_strerror(err));
cp_trace();
raise(SIGFPE);
exit(0);
}
result = *(sockaddr_t *)ai->ai_addr;
freeaddrinfo(ai);
cp
return result;
}
void sockaddr2str(sockaddr_t *sa, char **addrstr, char **portstr)
{
char address[NI_MAXHOST];
char port[NI_MAXSERV];
int err;
cp
if((err = getnameinfo((struct sockaddr *)sa, sizeof(sockaddr_t), address, sizeof(address), port, sizeof(port), NI_NUMERICHOST|NI_NUMERICSERV)))
{
syslog(LOG_ERR, _("Error while translating addresses: %s"), gai_strerror(err));
cp_trace();
raise(SIGFPE);
exit(0);
}
*addrstr = xstrdup(address);
*portstr = xstrdup(port);
cp
}
char *sockaddr2hostname(sockaddr_t *sa)
{
char *str;
char address[NI_MAXHOST] = "unknown";
char port[NI_MAXSERV] = "unknown";
int err;
cp
asprintf(&str, "%hu.%hu.%hu.%hu",
(unsigned short int)((address >> 24) & 255),
(unsigned short int)((address >> 16) & 255),
(unsigned short int)((address >> 8) & 255),
(unsigned short int)(address & 255));
if((err = getnameinfo((struct sockaddr *)sa, sizeof(sockaddr_t), address, sizeof(address), port, sizeof(port), hostnames?0:(NI_NUMERICHOST|NI_NUMERICSERV))))
{
syslog(LOG_ERR, _("Error while looking up hostname: %s"), gai_strerror(err));
}
asprintf(&str, _("%s port %s"), address, port);
cp
return str;
}
int sockaddrcmp(sockaddr_t *a, sockaddr_t *b)
{
int result;
cp
result = a->sa.sa_family - b->sa.sa_family;
if(result)
return result;
switch(a->sa.sa_family)
{
case AF_UNSPEC:
return 0;
case AF_INET:
return memcmp(&a->in, &b->in, sizeof(a->in));
case AF_INET6:
return memcmp(&a->in6, &b->in6, sizeof(a->in6));
default:
syslog(LOG_ERR, _("sockaddrcmp() was called with unknown address family %d, exitting!"), a->sa.sa_family);
cp_trace();
raise(SIGFPE);
exit(0);
}
cp
}
/* Subnet mask handling */
int maskcmp(char *a, char *b, int masklen, int len)
{
int i, m, result;
cp
for(m = masklen, i = 0; m > 8; m -= 8, i++)
if((result = a[i] - b[i]))
return result;
if(m)
return (a[i] & (0x100 - (m << 1))) - (b[i] & (0x100 - (m << 1)));
return 0;
}
void mask(char *a, int masklen, int len)
{
int i;
cp
i = masklen / 8;
masklen %= 8;
if(masklen)
a[i++] &= (0x100 - (masklen << 1));
for(; i < len; i++)
a[i] = 0;
}
void maskcpy(char *a, char *b, int masklen, int len)
{
int i, m;
cp
for(m = masklen, i = 0; m > 8; m -= 8, i++)
a[i] = b[i];
if(m)
{
a[i] = b[i] & (0x100 - (m << 1));
i++;
}
for(; i < len; i++)
a[i] = 0;
}
int maskcheck(char *a, int masklen, int len)
{
int i;
cp
i = masklen / 8;
masklen %= 8;
if(masklen)
if(a[i++] & ~(0x100 - (masklen << 1)))
return -1;
for(; i < len; i++)
if(a[i] != 0)
return -1;
return 0;
}

View file

@ -17,16 +17,29 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: netutl.h,v 1.2.4.9 2002/02/11 10:16:18 guus Exp $
$Id: netutl.h,v 1.2.4.10 2002/02/18 16:25:16 guus Exp $
*/
#ifndef __TINC_NETUTL_H__
#define __TINC_NETUTL_H__
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include "net.h"
extern int hostnames;
extern char *hostlookup(unsigned long);
extern ipv4_t str2address(char*);
extern char *address2str(ipv4_t);
extern struct addrinfo *str2addrinfo(char *, char *, int);
extern sockaddr_t str2sockaddr(char *, char *);
extern void sockaddr2str(sockaddr_t *, char **, char **);
extern char *sockaddr2hostname(sockaddr_t *);
extern int sockaddrcmp(sockaddr_t *, sockaddr_t *);
extern int maskcmp(char *, char *, int, int);
extern void maskcpy(char *, char *, int, int);
extern void mask(char *, int, int);
extern int maskcheck(char *, int, int);
#endif /* __TINC_NETUTL_H__ */

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: node.c,v 1.1.2.9 2002/02/11 15:59:18 guus Exp $
$Id: node.c,v 1.1.2.10 2002/02/18 16:25:16 guus Exp $
*/
#include "config.h"
@ -27,6 +27,7 @@
#include <avl_tree.h>
#include "node.h"
#include "netutl.h"
#include "net.h"
#include <utils.h>
#include <xalloc.h>
@ -45,14 +46,13 @@ int node_compare(node_t *a, node_t *b)
int node_udp_compare(node_t *a, node_t *b)
{
if(a->address < b->address)
return -1;
if (a->address > b->address)
return 1;
if (a->port < b->port)
return -1;
if (a->port > b->port)
return 1;
int result;
cp
result = sockaddrcmp(&a->address, &b->address);
if(result)
return result;
return (a->name && b->name)?strcmp(a->name, b->name):0;
}
@ -143,13 +143,13 @@ cp
return avl_search(node_tree, &n);
}
node_t *lookup_node_udp(ipv4_t address, port_t port)
node_t *lookup_node_udp(sockaddr_t *sa)
{
node_t n;
cp
n.address = *sa;
n.name = NULL;
n.address = address;
n.port = port;
return avl_search(node_udp_tree, &n);
}
@ -163,8 +163,8 @@ cp
for(node = node_tree->head; node; node = node->next)
{
n = (node_t *)node->data;
syslog(LOG_DEBUG, _(" %s at %s port %hd cipher %d digest %d maclength %d compression %d options %ld status %04x nexthop %s via %s"),
n->name, n->hostname, n->port, n->cipher?n->cipher->nid:0, n->digest?n->digest->type:0, n->maclength, n->compression, n->options,
syslog(LOG_DEBUG, _(" %s at %s cipher %d digest %d maclength %d compression %d options %ld status %04x nexthop %s via %s"),
n->name, n->hostname, n->cipher?n->cipher->nid:0, n->digest?n->digest->type:0, n->maclength, n->compression, n->options,
n->status, n->nexthop?n->nexthop->name:"-", n->via?n->via->name:"-");
}

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: node.h,v 1.1.2.11 2002/02/11 15:59:18 guus Exp $
$Id: node.h,v 1.1.2.12 2002/02/18 16:25:16 guus Exp $
*/
#ifndef __TINC_NODE_H__
@ -41,8 +41,7 @@ typedef struct node_t {
char *name; /* name of this node */
long int options; /* options turned on for this node */
ipv4_t address; /* his real (internet) ip to send UDP packets to */
port_t port; /* port number of UDP connection */
sockaddr_t address; /* his real (internet) ip to send UDP packets to */
char *hostname; /* the hostname of its real ip */
struct node_status_t status;
@ -78,11 +77,11 @@ extern avl_tree_t *node_udp_tree;
extern void init_nodes(void);
extern void exit_nodes(void);
extern node_t *new_node(void);
extern void free_node(node_t *n);
extern void node_add(node_t *n);
extern void node_del(node_t *n);
extern void free_node(node_t *);
extern void node_add(node_t *);
extern void node_del(node_t *);
extern node_t *lookup_node(char *);
extern node_t *lookup_node_udp(ipv4_t, port_t);
extern node_t *lookup_node_udp(sockaddr_t *);
extern void dump_nodes(void);
#endif /* __TINC_NODE_H__ */

View file

@ -17,12 +17,13 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: device.c,v 1.1.2.4 2002/02/11 12:33:01 guus Exp $
$Id: device.c,v 1.1.2.5 2002/02/18 16:25:19 guus Exp $
*/
#include "config.h"
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/stat.h>
@ -70,7 +71,7 @@ int setup_device(void)
cp
if((device_fd = open(device, O_RDWR | O_NONBLOCK)) < 0)
{
syslog(LOG_ERR, _("Could not open %s: %m"), device);
syslog(LOG_ERR, _("Could not open %s: %s"), device, strerror(errno));
return -1;
}
cp
@ -107,7 +108,7 @@ cp
if((lenin = readv(device_fd, vector, 2)) <= 0)
{
syslog(LOG_ERR, _("Error while reading from %s %s: %m"), device_info, device);
syslog(LOG_ERR, _("Error while reading from %s %s: %s"), device_info, device, strerror(errno));
return -1;
}
@ -145,7 +146,7 @@ cp
if(writev(device_fd, vector, 2) < 0)
{
syslog(LOG_ERR, _("Can't write to %s %s: %m"), device_info, device);
syslog(LOG_ERR, _("Can't write to %s %s: %s"), device_info, device, strerror(errno));
return -1;
}

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: process.c,v 1.1.2.34 2002/02/12 14:29:00 guus Exp $
$Id: process.c,v 1.1.2.35 2002/02/18 16:25:16 guus Exp $
*/
#include "config.h"
@ -255,8 +255,7 @@ int execute_script(const char *name)
cp
if((pid = fork()) < 0)
{
syslog(LOG_ERR, _("System call `%s' failed: %m"),
"fork");
syslog(LOG_ERR, _("System call `%s' failed: %s"), "fork", strerror(errno));
return -1;
}
@ -291,7 +290,7 @@ cp
}
else
{
syslog(LOG_ERR, _("System call `%s' failed: %m"), "waitpid");
syslog(LOG_ERR, _("System call `%s' failed: %s"), "waitpid", strerror(errno));
return -1;
}
}

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: protocol_auth.c,v 1.1.4.1 2002/02/11 10:05:58 guus Exp $
$Id: protocol_auth.c,v 1.1.4.2 2002/02/18 16:25:16 guus Exp $
*/
#include "config.h"
@ -413,16 +413,17 @@ int send_ack(connection_t *c)
to create node_t and edge_t structures. */
int x;
char *addrstr;
char *address, *port;
struct timeval now;
cp
/* Estimate weight */
gettimeofday(&now, NULL);
c->estimated_weight = (now.tv_sec - c->start.tv_sec) * 1000 + (now.tv_usec - c->start.tv_usec) / 1000;
addrstr = address2str(c->address);
x = send_request(c, "%d %hd %s %d %d", ACK, myself->port, addrstr, c->estimated_weight, c->options);
free(addrstr);
sockaddr2str(&c->address, &address, &port);
x = send_request(c, "%d %s %s %s %d %d", ACK, myport, address, port, c->estimated_weight, c->options);
free(address);
free(port);
cp
return x;
}
@ -462,15 +463,17 @@ void send_everything(connection_t *c)
int ack_h(connection_t *c)
{
port_t hisport;
char addrstr[MAX_STRING_SIZE];
char address[MAX_STRING_SIZE];
char port[MAX_STRING_SIZE];
char hisport[MAX_STRING_SIZE];
char *hisaddress, *dummy;
int weight;
int options;
node_t *n;
connection_t *other;
avl_node_t *node;
cp
if(sscanf(c->buffer, "%*d %hd "MAX_STRING" %d %d", &hisport, addrstr, &weight, &options) != 4)
if(sscanf(c->buffer, "%*d "MAX_STRING" "MAX_STRING" "MAX_STRING" %d %d", hisport, address, port, &weight, &options) != 5)
{
syslog(LOG_ERR, _("Got bad %s from %s (%s)"), "ACK", c->name, c->hostname);
return -1;
@ -484,12 +487,6 @@ cp
{
n = new_node();
n->name = xstrdup(c->name);
n->address = c->address;
n->hostname = xstrdup(c->hostname);
n->port = hisport;
/* FIXME: Also check if no other tinc daemon uses the same IP and port for UDP traffic */
node_add(n);
}
else
@ -512,17 +509,20 @@ cp
/* Create an edge_t for this connection */
c->edge = new_edge();
cp
c->edge->from.node = myself;
c->edge->from.address = str2address(addrstr);
c->edge->from.port = myself->port;
c->edge->from.tcpaddress = str2sockaddr(address, port);
c->edge->from.udpaddress = str2sockaddr(address, myport);
c->edge->to.node = n;
c->edge->to.address = c->address;
c->edge->to.port = hisport;
c->edge->to.tcpaddress = c->address;
sockaddr2str(&c->address, &hisaddress, &dummy);
c->edge->to.udpaddress = str2sockaddr(hisaddress, hisport);
free(hisaddress);
free(dummy);
c->edge->weight = (weight + c->estimated_weight) / 2;
c->edge->connection = c;
c->edge->options = c->options;
cp
edge_add(c->edge);
/* Activate this connection */

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: protocol_edge.c,v 1.1.4.1 2002/02/11 10:05:58 guus Exp $
$Id: protocol_edge.c,v 1.1.4.2 2002/02/18 16:25:18 guus Exp $
*/
#include "config.h"
@ -48,16 +48,25 @@
int send_add_edge(connection_t *c, edge_t *e)
{
int x;
char *from_addrstr, *to_addrstr;
char *from_tcpaddress, *from_tcpport, *from_udpaddress, *from_udpport;
char *to_tcpaddress, *to_tcpport, *to_udpaddress, *to_udpport;
cp
from_addrstr = address2str(e->from.address);
to_addrstr = address2str(e->to.address);
x = send_request(c, "%d %s %s %hd %s %s %hd %lx %d", ADD_EDGE,
e->from.node->name, from_addrstr, e->from.port,
e->to.node->name, to_addrstr, e->to.port,
sockaddr2str(&e->from.tcpaddress, &from_tcpaddress, &from_tcpport);
sockaddr2str(&e->from.udpaddress, &from_udpaddress, &from_udpport);
sockaddr2str(&e->to.tcpaddress, &to_tcpaddress, &to_tcpport);
sockaddr2str(&e->to.udpaddress, &to_udpaddress, &to_udpport);
x = send_request(c, "%d %s %s %s %s %s %s %s %s %lx %d", ADD_EDGE,
e->from.node->name, from_tcpaddress, from_tcpport, from_udpport,
e->to.node->name, to_tcpaddress, to_tcpport, to_udpport,
e->options, e->weight);
free(from_addrstr);
free(to_addrstr);
free(from_tcpaddress);
free(from_tcpport);
free(from_udpaddress);
free(from_udpport);
free(to_tcpaddress);
free(to_tcpport);
free(to_udpaddress);
free(to_udpport);
cp
return x;
}
@ -69,18 +78,22 @@ int add_edge_h(connection_t *c)
node_t *from, *to;
char from_name[MAX_STRING_SIZE];
char to_name[MAX_STRING_SIZE];
char from_addrstr[MAX_STRING_SIZE];
char to_addrstr[MAX_STRING_SIZE];
ipv4_t from_address, to_address;
port_t from_port, to_port;
char from_address[MAX_STRING_SIZE];
char from_tcpport[MAX_STRING_SIZE];
char from_udpport[MAX_STRING_SIZE];
char to_address[MAX_STRING_SIZE];
char to_tcpport[MAX_STRING_SIZE];
char to_udpport[MAX_STRING_SIZE];
sockaddr_t from_tcpaddress, from_udpaddress;
sockaddr_t to_tcpaddress, to_udpaddress;
long int options;
int weight;
avl_node_t *node;
cp
if(sscanf(c->buffer, "%*d "MAX_STRING" "MAX_STRING" %hd "MAX_STRING" "MAX_STRING" %hd %lx %d",
from_name, from_addrstr, &from_port,
to_name, to_addrstr, &to_port,
&options, &weight) != 8)
if(sscanf(c->buffer, "%*d "MAX_STRING" "MAX_STRING" "MAX_STRING" "MAX_STRING" "MAX_STRING" "MAX_STRING" "MAX_STRING" "MAX_STRING" %lx %d",
from_name, from_address, from_tcpport, from_udpport,
to_name, to_address, to_tcpport, to_udpport,
&options, &weight) != 10)
{
syslog(LOG_ERR, _("Got bad %s from %s (%s)"), "ADD_EDGE", c->name, c->hostname);
return -1;
@ -122,8 +135,10 @@ cp
/* Convert addresses */
from_address = str2address(from_addrstr);
to_address = str2address(to_addrstr);
from_tcpaddress = str2sockaddr(from_address, from_tcpport);
from_udpaddress = str2sockaddr(from_address, from_udpport);
to_tcpaddress = str2sockaddr(to_address, to_tcpport);
to_udpaddress = str2sockaddr(to_address, to_udpport);
/* Check if edge already exists */
@ -132,9 +147,9 @@ cp
if(e)
{
if(e->weight != weight || e->options != options
|| ((e->from.node == from) && (e->from.address != from_address || e->from.port != from_port || e->to.address != to_address || e->to.port != to_port))
|| ((e->from.node == to) && (e->from.address != to_address || e->from.port != to_port || e->to.address != from_address || e->to.port != from_port))
)
|| ((e->from.node == from) && (sockaddrcmp(&e->from.tcpaddress, &from_tcpaddress) || sockaddrcmp(&e->from.udpaddress, &from_udpaddress) || sockaddrcmp(&e->to.tcpaddress, &to_tcpaddress) || sockaddrcmp(&e->to.udpaddress, &to_udpaddress)))
|| ((e->from.node == to) && (sockaddrcmp(&e->from.tcpaddress, &to_tcpaddress) || sockaddrcmp(&e->from.udpaddress, &to_udpaddress) || sockaddrcmp(&e->to.tcpaddress, &from_tcpaddress) || sockaddrcmp(&e->to.udpaddress, &from_udpaddress)))
)
{
if(from == myself || to == myself)
{
@ -169,11 +184,11 @@ cp
e = new_edge();
e->from.node = from;
e->from.address = from_address;
e->from.port = from_port;
e->from.tcpaddress = from_tcpaddress;
e->from.udpaddress = from_udpaddress;
e->to.node = to;
e->to.address = to_address;
e->to.port = to_port;
e->to.tcpaddress = to_tcpaddress;
e->to.udpaddress = to_udpaddress;
e->options = options;
e->weight = weight;
edge_add(e);

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: route.c,v 1.1.2.22 2002/02/10 21:57:54 guus Exp $
$Id: route.c,v 1.1.2.23 2002/02/18 16:25:19 guus Exp $
*/
#include "config.h"
@ -105,23 +105,15 @@ cp
node_t *route_ipv4(vpn_packet_t *packet)
{
ipv4_t dest;
subnet_t *subnet;
cp
#ifdef HAVE_SOLARIS
/* The other form gives bus errors on a SparcStation 20. */
dest = ((packet->data[30] * 0x100 + packet->data[31]) * 0x100 + packet->data[32]) * 0x100 + packet->data[33];
#else
dest = ntohl(*((unsigned long*)(&packet->data[30])));
#endif
cp
subnet = lookup_subnet_ipv4(&dest);
subnet = lookup_subnet_ipv4((ipv4_t *)&packet->data[30]);
cp
if(!subnet)
{
if(debug_lvl >= DEBUG_TRAFFIC)
{
syslog(LOG_WARNING, _("Cannot route packet: unknown destination address %d.%d.%d.%d"),
syslog(LOG_WARNING, _("Cannot route packet: unknown IPv4 destination address %d.%d.%d.%d"),
packet->data[30], packet->data[31], packet->data[32], packet->data[33]);
}
@ -163,7 +155,6 @@ void route_arp(vpn_packet_t *packet)
struct ether_arp *arp;
subnet_t *subnet;
unsigned char ipbuf[4];
ipv4_t dest;
cp
/* First, snatch the source address from the ARP packet */
@ -193,8 +184,7 @@ cp
/* Check if the IP address exists on the VPN */
dest = ntohl(*((unsigned long*)(arp->arp_tpa)));
subnet = lookup_subnet_ipv4(&dest);
subnet = lookup_subnet_ipv4((ipv4_t *)arp->arp_tpa);
if(!subnet)
{

View file

@ -17,13 +17,14 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: device.c,v 1.1.2.6 2002/02/11 14:20:46 guus Exp $
$Id: device.c,v 1.1.2.7 2002/02/18 16:25:19 guus Exp $
*/
#include "config.h"
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
@ -71,7 +72,7 @@ cp
cp
if((device_fd = open(device, O_RDWR | O_NONBLOCK)) < 0)
{
syslog(LOG_ERR, _("Could not open %s: %m"), device);
syslog(LOG_ERR, _("Could not open %s: %s"), device, strerror(errno));
return -1;
}
cp
@ -82,34 +83,34 @@ cp
ppa = atoi(ptr);
if( (ip_fd = open("/dev/ip", O_RDWR, 0)) < 0){
syslog(LOG_ERR, _("Could not open /dev/ip: %m"));
syslog(LOG_ERR, _("Could not open /dev/ip: %s"), strerror(errno));
return -1;
}
/* Assign a new PPA and get its unit number. */
if( (ppa = ioctl(device_fd, TUNNEWPPA, ppa)) < 0){
syslog(LOG_ERR, _("Can't assign new interface: %m"));
syslog(LOG_ERR, _("Can't assign new interface: %s"), strerror(errno));
return -1;
}
if( (if_fd = open(device, O_RDWR, 0)) < 0){
syslog(LOG_ERR, _("Could not open %s twice: %m"), device);
syslog(LOG_ERR, _("Could not open %s twice: %s"), device, strerror(errno));
return -1;
}
if(ioctl(if_fd, I_PUSH, "ip") < 0){
syslog(LOG_ERR, _("Can't push IP module: %m"));
syslog(LOG_ERR, _("Can't push IP module: %s"), strerror(errno));
return -1;
}
/* Assign ppa according to the unit number returned by tun device */
if(ioctl(if_fd, IF_UNITSEL, (char *)&ppa) < 0){
syslog(LOG_ERR, _("Can't set PPA %d: %m"), ppa);
syslog(LOG_ERR, _("Can't set PPA %d: %s"), ppa, strerror(errno));
return -1;
}
if(ioctl(ip_fd, I_LINK, if_fd) < 0){
syslog(LOG_ERR, _("Can't link TUN device to IP: %m"));
syslog(LOG_ERR, _("Can't link TUN device to IP: %s"), strerror(errno));
return -1;
}
@ -145,7 +146,7 @@ int read_packet(vpn_packet_t *packet)
cp
if((lenin = read(device_fd, packet->data + 14, MTU - 14)) <= 0)
{
syslog(LOG_ERR, _("Error while reading from %s %s: %m"), device_info, device);
syslog(LOG_ERR, _("Error while reading from %s %s: %s"), device_info, device, strerror(errno));
return -1;
}
@ -176,7 +177,7 @@ cp
if(write(device_fd, packet->data + 14, packet->len - 14) < 0)
{
syslog(LOG_ERR, _("Can't write to %s %s: %m"), device_info, packet->len);
syslog(LOG_ERR, _("Can't write to %s %s: %s"), device_info, packet->len, strerror(errno));
return -1;
}

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: subnet.c,v 1.1.2.29 2002/02/10 21:57:54 guus Exp $
$Id: subnet.c,v 1.1.2.30 2002/02/18 16:25:19 guus Exp $
*/
#include "config.h"
@ -30,15 +30,17 @@
#include <netdb.h>
#include <netinet/in.h>
#include <utils.h>
#include <xalloc.h>
#include <avl_tree.h>
#include "conf.h"
#include "net.h"
#include "node.h"
#include "subnet.h"
#include "system.h"
#include "netutl.h"
#include <utils.h>
#include <xalloc.h>
#include <avl_tree.h>
#include "system.h"
/* lists type of subnet */
@ -54,48 +56,36 @@ cp
int subnet_compare_ipv4(subnet_t *a, subnet_t *b)
{
int result;
cp
/* We compare as if a subnet is a number that equals (address << 32 + netmask). */
if(a->net.ipv4.address < b->net.ipv4.address)
return -1;
else if(a->net.ipv4.address > b->net.ipv4.address)
return 1;
result = memcmp(&a->net.ipv4.address, &b->net.ipv4.address, sizeof(ipv4_t));
if(result)
return result;
if(a->net.ipv4.mask < b->net.ipv4.mask)
return -1;
else if(a->net.ipv4.mask > b->net.ipv4.mask)
return 1;
return 0;
return a->net.ipv4.masklength - b->net.ipv4.masklength;
}
int subnet_compare_ipv6(subnet_t *a, subnet_t *b)
{
int result;
cp
/* Same as ipv4 case, but with nasty 128 bit addresses */
result = memcmp(a->net.ipv6.address.x, b->net.ipv6.address.x, sizeof(ipv6_t));
result = memcmp(&a->net.ipv6.address, &b->net.ipv6.address, sizeof(ipv6_t));
if(result)
return result;
result = memcmp(a->net.ipv6.mask.x, b->net.ipv6.mask.x, sizeof(ipv6_t));
if(result)
return result;
return 0;
return a->net.ipv6.masklength - b->net.ipv6.masklength;
}
int subnet_compare(subnet_t *a, subnet_t *b)
{
int x;
int result;
cp
x = a->type - b->type;
if(x)
return x;
result = a->type - b->type;
if(result)
return result;
switch(a->type)
{
@ -186,101 +176,58 @@ subnet_t *str2net(char *subnetstr)
{
int i, l;
subnet_t *subnet;
unsigned short int x[6];
unsigned short int x[8];
cp
subnet = new_subnet();
cp
if(sscanf(subnetstr, "%hu.%hu.%hu.%hu/%d",
&x[0],
&x[1],
&x[2],
&x[3],
&subnet->net.ipv4.masklength) == 5)
&x[0], &x[1], &x[2], &x[3],
&l) == 5)
{
subnet->type = SUBNET_IPV4;
subnet->net.ipv4.address = (((((x[0] << 8) + x[1]) << 8) + x[2]) << 8) + x[3];
subnet->net.ipv4.mask = ~((1 << (32 - subnet->net.ipv4.masklength)) - 1);
subnet->net.ipv4.masklength = l;
for(i = 0; i < 4; i++)
subnet->net.ipv4.address.x[i] = x[i];
return subnet;
}
if(sscanf(subnetstr, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx/%d",
&subnet->net.ipv6.address.x[0],
&subnet->net.ipv6.address.x[1],
&subnet->net.ipv6.address.x[2],
&subnet->net.ipv6.address.x[3],
&subnet->net.ipv6.address.x[4],
&subnet->net.ipv6.address.x[5],
&subnet->net.ipv6.address.x[6],
&subnet->net.ipv6.address.x[7],
&subnet->net.ipv6.masklength) == 9)
&x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7],
&l) == 9)
{
subnet->type = SUBNET_IPV6;
for(l = subnet->net.ipv6.masklength, i = 0; i < 8; l -= 16, i++)
{
subnet->net.ipv6.address.x[i] = htons(subnet->net.ipv6.address.x[i]);
if(l >= 16)
subnet->net.ipv6.mask.x[i] = 65535;
else if (l > 0)
subnet->net.ipv6.mask.x[i] = htons(65536 - (1 << l));
else
subnet->net.ipv6.mask.x[i] = 0;
}
subnet->net.ipv6.masklength = l;
for(i = 0; i < 8; i++)
subnet->net.ipv6.address.x[i] = htons(x[i]);
return subnet;
}
if(sscanf(subnetstr, "%hu.%hu.%hu.%hu",
&x[0],
&x[1],
&x[2],
&x[3]) == 4)
&x[0], &x[1], &x[2], &x[3]) == 4)
{
subnet->type = SUBNET_IPV4;
subnet->net.ipv4.address = (((((x[0] << 8) + x[1]) << 8) + x[2]) << 8) + x[3];
subnet->net.ipv4.mask = ~0;
subnet->net.ipv4.masklength = 32;
for(i = 0; i < 4; i++)
subnet->net.ipv4.address.x[i] = x[i];
return subnet;
}
if(sscanf(subnetstr, "%hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx",
&subnet->net.ipv6.address.x[0],
&subnet->net.ipv6.address.x[1],
&subnet->net.ipv6.address.x[2],
&subnet->net.ipv6.address.x[3],
&subnet->net.ipv6.address.x[4],
&subnet->net.ipv6.address.x[5],
&subnet->net.ipv6.address.x[6],
&subnet->net.ipv6.address.x[7]) == 8)
&x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7]) == 8)
{
subnet->type = SUBNET_IPV6;
subnet->net.ipv6.masklength = 128;
for(l = subnet->net.ipv6.masklength, i = 0; i < 8; l -= 16, i++)
{
subnet->net.ipv6.address.x[i] = htons(subnet->net.ipv6.address.x[i]);
if(l >= 16)
subnet->net.ipv6.mask.x[i] = 65535;
else if (l > 0)
subnet->net.ipv6.mask.x[i] = htons(65536 - (1 << l));
else
subnet->net.ipv6.mask.x[i] = 0;
}
for(i = 0; i < 8; i++)
subnet->net.ipv6.address.x[i] = htons(x[i]);
return subnet;
}
if(sscanf(subnetstr, "%hx:%hx:%hx:%hx:%hx:%hx",
&x[0],
&x[1],
&x[2],
&x[3],
&x[4],
&x[5]) == 6)
&x[0], &x[1], &x[2], &x[3], &x[4], &x[5]) == 6)
{
subnet->type = SUBNET_MAC;
subnet->net.mac.address.x[0] = x[0];
subnet->net.mac.address.x[1] = x[1];
subnet->net.mac.address.x[2] = x[2];
subnet->net.mac.address.x[3] = x[3];
subnet->net.mac.address.x[4] = x[4];
subnet->net.mac.address.x[5] = x[5];
for(i = 0; i < 6; i++)
subnet->net.mac.address.x[i] = x[i];
return subnet;
}
@ -305,10 +252,10 @@ cp
break;
case SUBNET_IPV4:
asprintf(&netstr, "%hu.%hu.%hu.%hu/%d",
(unsigned short int)((subnet->net.ipv4.address >> 24) & 255),
(unsigned short int)((subnet->net.ipv4.address >> 16) & 255),
(unsigned short int)((subnet->net.ipv4.address >> 8) & 255),
(unsigned short int)(subnet->net.ipv4.address & 255),
subnet->net.ipv4.address.x[0],
subnet->net.ipv4.address.x[1],
subnet->net.ipv4.address.x[2],
subnet->net.ipv4.address.x[3],
subnet->net.ipv4.masklength);
break;
case SUBNET_IPV6:
@ -324,7 +271,9 @@ cp
subnet->net.ipv6.masklength);
break;
default:
asprintf(&netstr, _("unknown subnet type"));
syslog(LOG_ERR, _("net2str() was called with unknown subnet type %d, exitting!"), subnet->type);
cp_trace();
exit(0);
}
cp
return netstr;
@ -355,8 +304,8 @@ subnet_t *lookup_subnet_ipv4(ipv4_t *address)
subnet_t subnet, *p;
cp
subnet.type = SUBNET_IPV4;
subnet.net.ipv4.address = *address;
subnet.net.ipv4.mask = 0xFFFFFFFF;
memcpy(&subnet.net.ipv4.address, address, sizeof(ipv4_t));
subnet.net.ipv4.masklength = 32;
do
{
@ -368,14 +317,17 @@ cp
cp
if(p)
{
if ((*address & p->net.ipv4.mask) == p->net.ipv4.address)
if(p->type != SUBNET_IPV4)
return NULL;
if (!maskcmp((char *)address, (char *)&p->net.ipv4.address, p->net.ipv4.masklength, sizeof(ipv4_t)))
break;
else
{
/* Otherwise, see if there is a bigger enclosing subnet */
subnet.net.ipv4.mask = p->net.ipv4.mask << 1;
subnet.net.ipv4.address = p->net.ipv4.address & subnet.net.ipv4.mask;
subnet.net.ipv4.masklength = p->net.ipv4.masklength - 1;
maskcpy((char *)&subnet.net.ipv4.address, (char *)&p->net.ipv4.address, subnet.net.ipv4.masklength, sizeof(ipv4_t));
}
}
} while (p);
@ -386,18 +338,36 @@ cp
subnet_t *lookup_subnet_ipv6(ipv6_t *address)
{
subnet_t subnet, *p;
int i;
cp
subnet.type = SUBNET_IPV6;
memcpy(subnet.net.ipv6.address.x, address, sizeof(ipv6_t));
memset(subnet.net.ipv6.mask.x, 0xFF, 16);
memcpy(&subnet.net.ipv6.address, address, sizeof(ipv6_t));
subnet.net.ipv6.masklength = 128;
p = (subnet_t *)avl_search_closest_greater(subnet_tree, &subnet);
do
{
/* Go find subnet */
if(p)
for(i=0; i<8; i++)
if((address->x[i] & p->net.ipv6.address.x[i]) != p->net.ipv6.address.x[i])
return NULL;
p = (subnet_t *)avl_search_closest_smaller(subnet_tree, &subnet);
/* Check if the found subnet REALLY matches */
cp
if(p)
{
if(p->type != SUBNET_IPV6)
return NULL;
if (!maskcmp((char *)address, (char *)&p->net.ipv6.address, p->net.ipv6.masklength, sizeof(ipv6_t)))
break;
else
{
/* Otherwise, see if there is a bigger enclosing subnet */
subnet.net.ipv6.masklength = p->net.ipv6.masklength - 1;
maskcpy((char *)&subnet.net.ipv6.address, (char *)&p->net.ipv6.address, subnet.net.ipv6.masklength, sizeof(ipv6_t));
}
}
} while (p);
return p;
}

View file

@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
$Id: subnet.h,v 1.1.2.15 2002/02/10 21:57:54 guus Exp $
$Id: subnet.h,v 1.1.2.16 2002/02/18 16:25:19 guus Exp $
*/
#ifndef __TINC_SUBNET_H__
@ -41,14 +41,12 @@ typedef struct subnet_mac_t
typedef struct subnet_ipv4_t
{
ipv4_t address;
ipv4_t mask;
int masklength;
} subnet_ipv4_t;
typedef struct subnet_ipv6_t
{
ipv6_t address;
ipv6_t mask;
int masklength;
} subnet_ipv6_t;