Merge branch 'master' into 1.1
Conflicts: doc/tincd.8.in lib/pidfile.c src/graph.c src/net.c src/net.h src/net_packet.c src/net_setup.c src/net_socket.c src/netutl.c src/node.c src/node.h src/protocol_auth.c src/protocol_key.c src/tincd.c
This commit is contained in:
commit
5a132550de
23 changed files with 534 additions and 183 deletions
|
@ -304,6 +304,10 @@ or
|
|||
.Va PrivateKeyFile
|
||||
specified in the configuration file.
|
||||
|
||||
.It Va ProcessPriority Li = low | normal | high
|
||||
When this option is used the priority of the tincd process will be adjusted.
|
||||
Increasing the priority may help to reduce latency and packet loss on the VPN.
|
||||
|
||||
.It Va TunnelServer Li = yes | no Po no Pc Bq experimental
|
||||
When this option is enabled tinc will no longer forward information between other tinc daemons,
|
||||
and will only allow nodes and subnets on the VPN which are present in the
|
||||
|
|
|
@ -308,7 +308,7 @@ If the @file{net/if_tun.h} header file is missing, install it from the source pa
|
|||
@subsection Configuration of Darwin (MacOS/X) kernels
|
||||
|
||||
Tinc on Darwin relies on a tunnel driver for its data acquisition from the kernel.
|
||||
Tinc supports either the driver from @uref{http://www-user.rhrk.uni-kl.de/~nissler/tuntap/},
|
||||
Tinc supports either the driver from @uref{http://tuntaposx.sourceforge.net/},
|
||||
which supports both tun and tap style devices,
|
||||
and also the driver from from @uref{http://chrisp.de/en/projects/tunnel.html}.
|
||||
The former driver is recommended.
|
||||
|
@ -952,6 +952,11 @@ Note that there must be exactly one of PrivateKey
|
|||
or PrivateKeyFile
|
||||
specified in the configuration file.
|
||||
|
||||
@cindex ProcessPriority
|
||||
@item ProcessPriority = <low|normal|high>
|
||||
When this option is used the priority of the tincd process will be adjusted.
|
||||
Increasing the priority may help to reduce latency and packet loss on the VPN.
|
||||
|
||||
@cindex TunnelServer
|
||||
@item TunnelServer = <yes|no> (no) [experimental]
|
||||
When this option is enabled tinc will no longer forward information between other tinc daemons,
|
||||
|
@ -1523,6 +1528,23 @@ If @var{file} is omitted, the default is @file{@value{localstatedir}/log/tinc.@v
|
|||
Disables encryption and authentication.
|
||||
Only useful for debugging.
|
||||
|
||||
@item -R, --chroot
|
||||
Change process root directory to the directory where the config file is
|
||||
located (@file{@value{sysconfdir}/tinc/@var{netname}/} as determined by
|
||||
-n/--net option or as given by -c/--config option), for added security.
|
||||
The chroot is performed after all the initialization is done, after
|
||||
writing pid files and opening network sockets.
|
||||
|
||||
Note that this option alone does not do any good without -U/--user, below.
|
||||
|
||||
Note also that tinc can't run scripts anymore (such as tinc-down or host-up),
|
||||
unless it's setup to be runnable inside chroot environment.
|
||||
|
||||
@item -U, --user=@var{user}
|
||||
Switch to the given @var{user} after initialization, at the same time as
|
||||
chroot is performed (see --chroot above). With this option tinc drops
|
||||
privileges, for added security.
|
||||
|
||||
@item --help
|
||||
Display a short reminder of these runtime options and terminate.
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
.Nd tinc VPN daemon
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl cdDKnL
|
||||
.Op Fl cdDKnLRU
|
||||
.Op Fl -config Ns = Ns Ar DIR
|
||||
.Op Fl -no-detach
|
||||
.Op Fl -debug Ns Op = Ns Ar LEVEL
|
||||
|
@ -16,6 +16,8 @@
|
|||
.Op Fl -mlock
|
||||
.Op Fl -logfile Ns Op = Ns Ar FILE
|
||||
.Op Fl -bypass-security
|
||||
.Op Fl -chroot
|
||||
.Op Fl -user Ns = Ns Ar USER
|
||||
.Op Fl -help
|
||||
.Op Fl -version
|
||||
.Sh DESCRIPTION
|
||||
|
@ -70,6 +72,14 @@ is omitted, the default is
|
|||
.It Fl -bypass-security
|
||||
Disables encryption and authentication of the meta protocol.
|
||||
Only useful for debugging.
|
||||
.It Fl -chroot
|
||||
With this option tinc chroots into the directory where network
|
||||
config is located (@sysconfdir@/tinc/NETNAME if -n option is used,
|
||||
or to the directory specified with -c option) after initialization.
|
||||
.It Fl -user Ns = Ns Ar USER
|
||||
setuid to the specified
|
||||
.Ar USER
|
||||
after initialization.
|
||||
.It Fl -help
|
||||
Display short list of options.
|
||||
.It Fl -version
|
||||
|
|
|
@ -29,7 +29,7 @@ volatile char (*cp_file[]) = {"?", "?", "?", "?", "?", "?", "?", "?", "?", "?",
|
|||
volatile int cp_index = 0;
|
||||
#endif
|
||||
|
||||
char *hexadecimals = "0123456789ABCDEF";
|
||||
const char hexadecimals[] = "0123456789ABCDEF";
|
||||
|
||||
int charhex2bin(char c) {
|
||||
if(isdigit(c))
|
||||
|
@ -81,7 +81,7 @@ void cp_trace() {
|
|||
#include <w32api/windows.h>
|
||||
#endif
|
||||
|
||||
char *winerror(int err) {
|
||||
const char *winerror(int err) {
|
||||
static char buf[1024], *newline;
|
||||
|
||||
if (!FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
|
|
|
@ -39,7 +39,7 @@ extern void hex2bin(char *src, char *dst, int length);
|
|||
extern void bin2hex(char *src, char *dst, int length);
|
||||
|
||||
#ifdef HAVE_MINGW
|
||||
extern char *winerror(int);
|
||||
extern const char *winerror(int);
|
||||
#define strerror(x) ((x)>0?strerror(x):winerror(GetLastError()))
|
||||
#endif
|
||||
|
||||
|
|
27
src/graph.c
27
src/graph.c
|
@ -312,27 +312,8 @@ void sssp_bfs(void) {
|
|||
e->to->via = indirect ? n->via : e->to;
|
||||
e->to->options = e->options;
|
||||
|
||||
if(sockaddrcmp(&e->to->address, &e->address)) {
|
||||
node = splay_unlink(node_udp_tree, e->to);
|
||||
sockaddrfree(&e->to->address);
|
||||
sockaddrcpy(&e->to->address, &e->address);
|
||||
|
||||
if(e->to->hostname)
|
||||
free(e->to->hostname);
|
||||
|
||||
e->to->hostname = sockaddr2hostname(&e->to->address);
|
||||
|
||||
if(node)
|
||||
splay_insert_node(node_udp_tree, node);
|
||||
|
||||
if(e->to->options & OPTION_PMTU_DISCOVERY) {
|
||||
e->to->mtuprobes = 0;
|
||||
e->to->minmtu = 0;
|
||||
e->to->maxmtu = MTU;
|
||||
if(e->to->status.validkey)
|
||||
send_mtu_probe(e->to);
|
||||
}
|
||||
}
|
||||
if(e->to->address.sa.sa_family == AF_UNSPEC && e->address.sa.sa_family != AF_UNKNOWN)
|
||||
update_node_udp(e->to, &e->address);
|
||||
|
||||
list_insert_tail(todo_list, e->to);
|
||||
}
|
||||
|
@ -364,13 +345,13 @@ void check_reachability() {
|
|||
if(n->status.reachable) {
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Node %s (%s) became reachable"),
|
||||
n->name, n->hostname);
|
||||
splay_insert(node_udp_tree, n);
|
||||
} else {
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Node %s (%s) became unreachable"),
|
||||
n->name, n->hostname);
|
||||
splay_delete(node_udp_tree, n);
|
||||
}
|
||||
|
||||
/* TODO: only clear status.validkey if node is unreachable? */
|
||||
|
||||
n->status.validkey = false;
|
||||
n->status.waitingforkey = false;
|
||||
|
||||
|
|
|
@ -62,7 +62,8 @@ bool setup_device(void) {
|
|||
|
||||
if(!get_config_string(lookup_config(config_tree, "Interface"), &iface))
|
||||
#ifdef HAVE_LINUX_IF_TUN_H
|
||||
iface = xstrdup(netname);
|
||||
if (netname != NULL)
|
||||
iface = xstrdup(netname);
|
||||
#else
|
||||
iface = xstrdup(rindex(device, '/') ? rindex(device, '/') + 1 : device);
|
||||
#endif
|
||||
|
|
|
@ -131,7 +131,7 @@ extern int setup_vpn_in_socket(const sockaddr_t *);
|
|||
extern void send_packet(const struct node_t *, vpn_packet_t *);
|
||||
extern void receive_tcppacket(struct connection_t *, char *, int);
|
||||
extern void broadcast_packet(const struct node_t *, vpn_packet_t *);
|
||||
extern bool setup_network_connections(void);
|
||||
extern bool setup_network(void);
|
||||
extern void setup_outgoing_connection(struct outgoing_t *);
|
||||
extern void try_outgoing_connections(void);
|
||||
extern void close_network_connections(void);
|
||||
|
|
110
src/net_packet.c
110
src/net_packet.c
|
@ -49,6 +49,7 @@
|
|||
#endif
|
||||
|
||||
int keylifetime = 0;
|
||||
int keyexpires = 0;
|
||||
static char lzo_wrkmem[LZO1X_999_MEM_COMPRESS > LZO1X_1_MEM_COMPRESS ? LZO1X_999_MEM_COMPRESS : LZO1X_1_MEM_COMPRESS];
|
||||
|
||||
static void send_udppacket(node_t *, vpn_packet_t *);
|
||||
|
@ -99,15 +100,15 @@ void send_mtu_probe(node_t *n) {
|
|||
send_mtu_probe_handler(0, 0, n);
|
||||
}
|
||||
|
||||
void mtu_probe_h(node_t *n, vpn_packet_t *packet) {
|
||||
void mtu_probe_h(node_t *n, vpn_packet_t *packet, length_t len) {
|
||||
ifdebug(TRAFFIC) logger(LOG_INFO, _("Got MTU probe length %d from %s (%s)"), packet->len, n->name, n->hostname);
|
||||
|
||||
if(!packet->data[0]) {
|
||||
packet->data[0] = 1;
|
||||
send_packet(n, packet);
|
||||
} else {
|
||||
if(n->minmtu < packet->len)
|
||||
n->minmtu = packet->len;
|
||||
if(n->minmtu < len)
|
||||
n->minmtu = len;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -160,7 +161,16 @@ static void receive_packet(node_t *n, vpn_packet_t *packet) {
|
|||
route(n, packet);
|
||||
}
|
||||
|
||||
static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
|
||||
static bool try_mac(node_t *n, const vpn_packet_t *inpkt)
|
||||
{
|
||||
if(!digest_active(&n->indigest) || !n->inmaclength || inpkt->len < sizeof inpkt->seqno + n->inmaclength)
|
||||
return false;
|
||||
|
||||
return digest_verify(&n->indigest, &inpkt->seqno, inpkt->len, &inpkt->seqno + inpkt->len);
|
||||
}
|
||||
|
||||
static 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;
|
||||
|
@ -170,9 +180,15 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
|
|||
|
||||
cp();
|
||||
|
||||
if(!cipher_active(&n->incipher)) {
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Got packet from %s (%s) but he hasn't got our key yet"),
|
||||
n->name, n->hostname);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check packet length */
|
||||
|
||||
if(inpkt->len < sizeof inpkt->seqno + digest_length(&myself->digest)) {
|
||||
if(inpkt->len < sizeof inpkt->seqno + digest_length(&n->indigest)) {
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Got too short packet from %s (%s)"),
|
||||
n->name, n->hostname);
|
||||
return;
|
||||
|
@ -180,18 +196,18 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
|
|||
|
||||
/* Check the message authentication code */
|
||||
|
||||
if(digest_active(&myself->digest) && !digest_verify(&myself->digest, &inpkt->seqno, inpkt->len, &inpkt->seqno + inpkt->len)) {
|
||||
if(digest_active(&n->indigest) && !digest_verify(&n->indigest, &inpkt->seqno, inpkt->len, &inpkt->seqno + inpkt->len)) {
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Got unauthenticated packet from %s (%s)"), n->name, n->hostname);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Decrypt the packet */
|
||||
|
||||
if(cipher_active(&myself->cipher)) {
|
||||
if(cipher_active(&n->incipher)) {
|
||||
outpkt = pkt[nextpkt++];
|
||||
outlen = MAXSIZE;
|
||||
|
||||
if(!cipher_decrypt(&myself->cipher, &inpkt->seqno, inpkt->len, &outpkt->seqno, &outlen, true)) {
|
||||
if(!cipher_decrypt(&n->incipher, &inpkt->seqno, inpkt->len, &outpkt->seqno, &outlen, true)) {
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Error decrypting packet from %s (%s)"), n->name, n->hostname);
|
||||
return;
|
||||
}
|
||||
|
@ -233,22 +249,26 @@ static void receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
|
|||
|
||||
/* Decompress the packet */
|
||||
|
||||
if(myself->compression) {
|
||||
length_t origlen = inpkt->len;
|
||||
|
||||
if(n->incompression) {
|
||||
outpkt = pkt[nextpkt++];
|
||||
|
||||
if((outpkt->len = uncompress_packet(outpkt->data, inpkt->data, inpkt->len, myself->compression)) < 0) {
|
||||
if((outpkt->len = uncompress_packet(outpkt->data, inpkt->data, inpkt->len, n->incompression)) < 0) {
|
||||
ifdebug(TRAFFIC) logger(LOG_ERR, _("Error while uncompressing packet from %s (%s)"),
|
||||
n->name, n->hostname);
|
||||
return;
|
||||
}
|
||||
|
||||
inpkt = outpkt;
|
||||
|
||||
origlen -= MTU/64 + 20;
|
||||
}
|
||||
|
||||
inpkt->priority = 0;
|
||||
|
||||
if(!inpkt->data[12] && !inpkt->data[13])
|
||||
mtu_probe_h(n, inpkt);
|
||||
mtu_probe_h(n, inpkt, origlen);
|
||||
else
|
||||
receive_packet(n, inpkt);
|
||||
}
|
||||
|
@ -290,7 +310,7 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
|
|||
n->name, n->hostname);
|
||||
|
||||
if(!n->status.waitingforkey)
|
||||
send_req_key(n->nexthop->connection, myself, n);
|
||||
send_req_key(n);
|
||||
|
||||
n->status.waitingforkey = true;
|
||||
|
||||
|
@ -299,12 +319,14 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
|
|||
return;
|
||||
}
|
||||
|
||||
if(!n->minmtu && (inpkt->data[12] | inpkt->data[13])) {
|
||||
if(n->options & OPTION_PMTU_DISCOVERY && !n->minmtu && (inpkt->data[12] | inpkt->data[13])) {
|
||||
ifdebug(TRAFFIC) logger(LOG_INFO,
|
||||
_("No minimum MTU established yet for %s (%s), forwarding via TCP"),
|
||||
n->name, n->hostname);
|
||||
|
||||
send_tcppacket(n->nexthop->connection, origpkt);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
origlen = inpkt->len;
|
||||
|
@ -312,10 +334,10 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
|
|||
|
||||
/* Compress the packet */
|
||||
|
||||
if(n->compression) {
|
||||
if(n->outcompression) {
|
||||
outpkt = pkt[nextpkt++];
|
||||
|
||||
if((outpkt->len = compress_packet(outpkt->data, inpkt->data, inpkt->len, n->compression)) < 0) {
|
||||
if((outpkt->len = compress_packet(outpkt->data, inpkt->data, inpkt->len, n->outcompression)) < 0) {
|
||||
ifdebug(TRAFFIC) logger(LOG_ERR, _("Error while compressing packet to %s (%s)"),
|
||||
n->name, n->hostname);
|
||||
return;
|
||||
|
@ -331,11 +353,11 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
|
|||
|
||||
/* Encrypt the packet */
|
||||
|
||||
if(cipher_active(&n->cipher)) {
|
||||
if(cipher_active(&n->outcipher)) {
|
||||
outpkt = pkt[nextpkt++];
|
||||
outlen = MAXSIZE;
|
||||
|
||||
if(!cipher_encrypt(&n->cipher, &inpkt->seqno, inpkt->len, &outpkt->seqno, &outlen, true)) {
|
||||
if(!cipher_encrypt(&n->outcipher, &inpkt->seqno, inpkt->len, &outpkt->seqno, &outlen, true)) {
|
||||
ifdebug(TRAFFIC) logger(LOG_ERR, _("Error while encrypting packet to %s (%s)"), n->name, n->hostname);
|
||||
goto end;
|
||||
}
|
||||
|
@ -346,9 +368,9 @@ static void send_udppacket(node_t *n, vpn_packet_t *origpkt) {
|
|||
|
||||
/* Add the message authentication code */
|
||||
|
||||
if(digest_active(&n->digest)) {
|
||||
digest_create(&n->digest, &inpkt->seqno, inpkt->len, &inpkt->seqno + inpkt->len);
|
||||
inpkt->len += digest_length(&n->digest);
|
||||
if(digest_active(&n->outdigest)) {
|
||||
digest_create(&n->outdigest, &inpkt->seqno, inpkt->len, &inpkt->seqno + inpkt->len);
|
||||
inpkt->len += digest_length(&n->outdigest);
|
||||
}
|
||||
|
||||
/* Determine which socket we have to use */
|
||||
|
@ -434,9 +456,15 @@ void broadcast_packet(const node_t *from, vpn_packet_t *packet) {
|
|||
ifdebug(TRAFFIC) logger(LOG_INFO, _("Broadcasting packet of %d bytes from %s (%s)"),
|
||||
packet->len, from->name, from->hostname);
|
||||
|
||||
if(from != myself)
|
||||
if(from != myself) {
|
||||
send_packet(myself, packet);
|
||||
|
||||
// In TunnelServer mode, do not forward broadcast packets.
|
||||
// The MST might not be valid and create loops.
|
||||
if(tunnelserver)
|
||||
return;
|
||||
}
|
||||
|
||||
for(node = connection_tree->head; node; node = node->next) {
|
||||
c = node->data;
|
||||
|
||||
|
@ -445,6 +473,30 @@ void broadcast_packet(const node_t *from, vpn_packet_t *packet) {
|
|||
}
|
||||
}
|
||||
|
||||
static node_t *try_harder(const sockaddr_t *from, const vpn_packet_t *pkt) {
|
||||
splay_node_t *node;
|
||||
edge_t *e;
|
||||
node_t *n = NULL;
|
||||
|
||||
for(node = edge_weight_tree->head; node; node = node->next) {
|
||||
e = node->data;
|
||||
|
||||
if(sockaddrcmp_noport(from, &e->address))
|
||||
continue;
|
||||
|
||||
if(!n)
|
||||
n = e->to;
|
||||
|
||||
if(!try_mac(e->to, pkt))
|
||||
continue;
|
||||
|
||||
n = e->to;
|
||||
break;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
void handle_incoming_vpn_data(int sock, short events, void *data)
|
||||
{
|
||||
vpn_packet_t pkt;
|
||||
|
@ -467,11 +519,17 @@ void handle_incoming_vpn_data(int sock, short events, void *data)
|
|||
n = lookup_node_udp(&from);
|
||||
|
||||
if(!n) {
|
||||
hostname = sockaddr2hostname(&from);
|
||||
logger(LOG_WARNING, _("Received UDP packet from unknown source %s"),
|
||||
hostname);
|
||||
free(hostname);
|
||||
return;
|
||||
n = try_harder(&from, &pkt);
|
||||
if(n)
|
||||
update_node_udp(n, &from);
|
||||
else ifdebug(PROTOCOL) {
|
||||
hostname = sockaddr2hostname(&from);
|
||||
logger(LOG_WARNING, _("Received UDP packet from unknown source %s"), hostname);
|
||||
free(hostname);
|
||||
return;
|
||||
}
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
receive_udppacket(n, &pkt);
|
||||
|
|
|
@ -148,14 +148,8 @@ static void keyexpire_handler(int fd, short events, void *data) {
|
|||
}
|
||||
|
||||
void regenerate_key() {
|
||||
ifdebug(STATUS) logger(LOG_INFO, _("Regenerating symmetric key"));
|
||||
|
||||
if(!cipher_regenerate_key(&myself->cipher, true)) {
|
||||
logger(LOG_ERR, _("Error regenerating key!"));
|
||||
abort();
|
||||
}
|
||||
|
||||
if(timeout_initialized(&keyexpire_event)) {
|
||||
ifdebug(STATUS) logger(LOG_INFO, _("Expiring symmetric keys"));
|
||||
event_del(&keyexpire_event);
|
||||
send_key_changed(broadcast, myself);
|
||||
} else {
|
||||
|
@ -270,7 +264,7 @@ bool setup_myself(void) {
|
|||
|
||||
#if !defined(SOL_IP) || !defined(IP_TOS)
|
||||
if(priorityinheritance)
|
||||
logger(LOG_WARNING, _("PriorityInheritance not supported on this platform"));
|
||||
logger(LOG_WARNING, _("%s not supported on this platform"), "PriorityInheritance");
|
||||
#endif
|
||||
|
||||
if(!get_config_int(lookup_config(config_tree, "MACExpire"), &macexpire))
|
||||
|
@ -305,7 +299,7 @@ bool setup_myself(void) {
|
|||
if(!get_config_string(lookup_config(myself->connection->config_tree, "Cipher"), &cipher))
|
||||
cipher = xstrdup("blowfish");
|
||||
|
||||
if(!cipher_open_by_name(&myself->cipher, cipher)) {
|
||||
if(!cipher_open_by_name(&myself->incipher, cipher)) {
|
||||
logger(LOG_ERR, _("Unrecognized cipher type!"));
|
||||
return false;
|
||||
}
|
||||
|
@ -320,18 +314,18 @@ bool setup_myself(void) {
|
|||
if(!get_config_string(lookup_config(myself->connection->config_tree, "Digest"), &digest))
|
||||
digest = xstrdup("sha1");
|
||||
|
||||
if(!digest_open_by_name(&myself->digest, digest)) {
|
||||
if(!digest_open_by_name(&myself->indigest, digest)) {
|
||||
logger(LOG_ERR, _("Unrecognized digest type!"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!get_config_int(lookup_config(myself->connection->config_tree, "MACLength"), &myself->maclength))
|
||||
if(!get_config_int(lookup_config(myself->connection->config_tree, "MACLength"), &myself->inmaclength))
|
||||
|
||||
if(digest_active(&myself->digest)) {
|
||||
if(myself->maclength > digest_length(&myself->digest)) {
|
||||
if(digest_active(&myself->indigest)) {
|
||||
if(myself->inmaclength > digest_length(&myself->indigest)) {
|
||||
logger(LOG_ERR, _("MAC length exceeds size of digest!"));
|
||||
return false;
|
||||
} else if(myself->maclength < 0) {
|
||||
} else if(myself->inmaclength < 0) {
|
||||
logger(LOG_ERR, _("Bogus MAC length!"));
|
||||
return false;
|
||||
}
|
||||
|
@ -339,13 +333,13 @@ bool setup_myself(void) {
|
|||
|
||||
/* Compression */
|
||||
|
||||
if(get_config_int(lookup_config(myself->connection->config_tree, "Compression"), &myself->compression)) {
|
||||
if(myself->compression < 0 || myself->compression > 11) {
|
||||
if(get_config_int(lookup_config(myself->connection->config_tree, "Compression"), &myself->incompression)) {
|
||||
if(myself->incompression < 0 || myself->incompression > 11) {
|
||||
logger(LOG_ERR, _("Bogus compression level!"));
|
||||
return false;
|
||||
}
|
||||
} else
|
||||
myself->compression = 0;
|
||||
myself->incompression = 0;
|
||||
|
||||
myself->connection->outcompression = 0;
|
||||
|
||||
|
@ -467,9 +461,10 @@ bool setup_myself(void) {
|
|||
}
|
||||
|
||||
/*
|
||||
setup all initial network connections
|
||||
initialize network
|
||||
*/
|
||||
bool setup_network_connections(void) {
|
||||
bool setup_network(void)
|
||||
{
|
||||
cp();
|
||||
|
||||
init_connections();
|
||||
|
@ -496,8 +491,6 @@ bool setup_network_connections(void) {
|
|||
if(!setup_myself())
|
||||
return false;
|
||||
|
||||
try_outgoing_connections();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
119
src/net_socket.c
119
src/net_socket.c
|
@ -33,6 +33,8 @@
|
|||
#include "utils.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef WSAEINPROGRESS
|
||||
#define EINPROGRESS WSAEINPROGRESS
|
||||
#endif
|
||||
|
@ -80,7 +82,95 @@ static void configure_tcp(connection_t *c) {
|
|||
#endif
|
||||
}
|
||||
|
||||
int setup_listen_socket(const sockaddr_t *sa) {
|
||||
static bool bind_to_interface(int sd) { /* {{{ */
|
||||
char *iface;
|
||||
|
||||
#if defined(SOL_SOCKET) && defined(SO_BINDTODEVICE)
|
||||
struct ifreq ifr;
|
||||
int status;
|
||||
#endif /* defined(SOL_SOCKET) && defined(SO_BINDTODEVICE) */
|
||||
|
||||
if(!get_config_string (lookup_config (config_tree, "BindToInterface"), &iface))
|
||||
return true;
|
||||
|
||||
#if defined(SOL_SOCKET) && defined(SO_BINDTODEVICE)
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strncpy(ifr.ifr_ifrn.ifrn_name, iface, IFNAMSIZ);
|
||||
ifr.ifr_ifrn.ifrn_name[IFNAMSIZ - 1] = 0;
|
||||
|
||||
status = setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr));
|
||||
if(status) {
|
||||
logger(LOG_ERR, _("Can't bind to interface %s: %s"), iface,
|
||||
strerror(errno));
|
||||
return false;
|
||||
}
|
||||
#else /* if !defined(SOL_SOCKET) || !defined(SO_BINDTODEVICE) */
|
||||
logger(LOG_WARNING, _("%s not supported on this platform"), "BindToInterface");
|
||||
#endif
|
||||
|
||||
return true;
|
||||
} /* }}} bool bind_to_interface */
|
||||
|
||||
static bool bind_to_address(connection_t *c) { /* {{{ */
|
||||
char *node;
|
||||
struct addrinfo *ai_list;
|
||||
struct addrinfo *ai_ptr;
|
||||
struct addrinfo ai_hints;
|
||||
int status;
|
||||
|
||||
assert(c != NULL);
|
||||
assert(c->socket >= 0);
|
||||
|
||||
node = NULL;
|
||||
if(!get_config_string(lookup_config(config_tree, "BindToAddress"),
|
||||
&node))
|
||||
return true;
|
||||
|
||||
assert(node != NULL);
|
||||
|
||||
memset(&ai_hints, 0, sizeof(ai_hints));
|
||||
ai_hints.ai_family = c->address.sa.sa_family;
|
||||
/* We're called from `do_outgoing_connection' only. */
|
||||
ai_hints.ai_socktype = SOCK_STREAM;
|
||||
ai_hints.ai_protocol = IPPROTO_TCP;
|
||||
|
||||
ai_list = NULL;
|
||||
|
||||
status = getaddrinfo(node, /* service = */ NULL,
|
||||
&ai_hints, &ai_list);
|
||||
if(status) {
|
||||
free(node);
|
||||
logger(LOG_WARNING, _("Error looking up %s port %s: %s"),
|
||||
node, _("any"), gai_strerror(status));
|
||||
return false;
|
||||
}
|
||||
assert(ai_list != NULL);
|
||||
|
||||
status = -1;
|
||||
for(ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next) {
|
||||
status = bind(c->socket,
|
||||
ai_list->ai_addr, ai_list->ai_addrlen);
|
||||
if(!status)
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if(status) {
|
||||
logger(LOG_ERR, _("Can't bind to %s/tcp: %s"), node,
|
||||
strerror(errno));
|
||||
} else ifdebug(CONNECTIONS) {
|
||||
logger(LOG_DEBUG, "Successfully bound outgoing "
|
||||
"TCP socket to %s", node);
|
||||
}
|
||||
|
||||
free(node);
|
||||
freeaddrinfo(ai_list);
|
||||
|
||||
return status ? false : true;
|
||||
} /* }}} bool bind_to_address */
|
||||
|
||||
int setup_listen_socket(const sockaddr_t *sa)
|
||||
{
|
||||
int nfd;
|
||||
char *addrstr;
|
||||
int option;
|
||||
|
@ -120,7 +210,7 @@ int setup_listen_socket(const sockaddr_t *sa) {
|
|||
return -1;
|
||||
}
|
||||
#else
|
||||
logger(LOG_WARNING, _("BindToInterface not supported on this platform"));
|
||||
logger(LOG_WARNING, _("%s not supported on this platform"), "BindToInterface");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -202,24 +292,10 @@ int setup_vpn_in_socket(const sockaddr_t *sa) {
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined(SOL_SOCKET) && defined(SO_BINDTODEVICE)
|
||||
{
|
||||
char *iface;
|
||||
struct ifreq ifr;
|
||||
|
||||
if(get_config_string(lookup_config(config_tree, "BindToInterface"), &iface)) {
|
||||
memset(&ifr, 0, sizeof ifr);
|
||||
strncpy(ifr.ifr_ifrn.ifrn_name, iface, IFNAMSIZ);
|
||||
|
||||
if(setsockopt(nfd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof ifr)) {
|
||||
closesocket(nfd);
|
||||
logger(LOG_ERR, _("Can't bind to interface %s: %s"), iface,
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (!bind_to_interface(nfd)) {
|
||||
closesocket(nfd);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if(bind(nfd, &sa->sa, SALEN(sa->sa))) {
|
||||
closesocket(nfd);
|
||||
|
@ -231,7 +307,7 @@ int setup_vpn_in_socket(const sockaddr_t *sa) {
|
|||
}
|
||||
|
||||
return nfd;
|
||||
}
|
||||
} /* int setup_vpn_in_socket */
|
||||
|
||||
static void retry_outgoing_handler(int fd, short events, void *data) {
|
||||
setup_outgoing_connection(data);
|
||||
|
@ -329,6 +405,9 @@ begin:
|
|||
setsockopt(c->socket, SOL_IPV6, IPV6_V6ONLY, &option, sizeof option);
|
||||
#endif
|
||||
|
||||
bind_to_interface(c->socket);
|
||||
bind_to_address(c);
|
||||
|
||||
/* Optimize TCP settings */
|
||||
|
||||
configure_tcp(c);
|
||||
|
|
36
src/netutl.c
36
src/netutl.c
|
@ -140,7 +140,41 @@ char *sockaddr2hostname(const sockaddr_t *sa) {
|
|||
return str;
|
||||
}
|
||||
|
||||
int sockaddrcmp(const sockaddr_t *a, const sockaddr_t *b) {
|
||||
int sockaddrcmp_noport(const sockaddr_t *a, const 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_UNKNOWN:
|
||||
return strcmp(a->unknown.address, b->unknown.address);
|
||||
|
||||
case AF_INET:
|
||||
return memcmp(&a->in.sin_addr, &b->in.sin_addr, sizeof(a->in.sin_addr));
|
||||
|
||||
case AF_INET6:
|
||||
return memcmp(&a->in6.sin6_addr, &b->in6.sin6_addr, sizeof(a->in6.sin6_addr));
|
||||
|
||||
default:
|
||||
logger(LOG_ERR, _("sockaddrcmp() was called with unknown address family %d, exitting!"),
|
||||
a->sa.sa_family);
|
||||
cp_trace();
|
||||
raise(SIGFPE);
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
int sockaddrcmp(const sockaddr_t *a, const sockaddr_t *b)
|
||||
{
|
||||
int result;
|
||||
|
||||
cp();
|
||||
|
|
|
@ -32,6 +32,7 @@ extern sockaddr_t str2sockaddr(const char *, const char *);
|
|||
extern void sockaddr2str(const sockaddr_t *, char **, char **);
|
||||
extern char *sockaddr2hostname(const sockaddr_t *);
|
||||
extern int sockaddrcmp(const sockaddr_t *, const sockaddr_t *);
|
||||
extern int sockaddrcmp_noport(const sockaddr_t *, const sockaddr_t *);
|
||||
extern void sockaddrunmap(sockaddr_t *);
|
||||
extern void sockaddrfree(sockaddr_t *);
|
||||
extern void sockaddrcpy(sockaddr_t *, const sockaddr_t *);
|
||||
|
|
30
src/node.c
30
src/node.c
|
@ -90,8 +90,10 @@ void free_node(node_t *n) {
|
|||
|
||||
sockaddrfree(&n->address);
|
||||
|
||||
cipher_close(&n->cipher);
|
||||
digest_close(&n->digest);
|
||||
cipher_close(&n->incipher);
|
||||
digest_close(&n->indigest);
|
||||
cipher_close(&n->outcipher);
|
||||
digest_close(&n->outdigest);
|
||||
|
||||
event_del(&n->mtuevent);
|
||||
|
||||
|
@ -130,6 +132,7 @@ void node_del(node_t *n) {
|
|||
}
|
||||
|
||||
splay_delete(node_tree, n);
|
||||
splay_delete(node_udp_tree, n);
|
||||
}
|
||||
|
||||
node_t *lookup_node(char *name) {
|
||||
|
@ -153,6 +156,25 @@ node_t *lookup_node_udp(const sockaddr_t *sa) {
|
|||
return splay_search(node_udp_tree, &n);
|
||||
}
|
||||
|
||||
void update_node_udp(node_t *n, const sockaddr_t *sa)
|
||||
{
|
||||
splay_delete(node_udp_tree, n);
|
||||
|
||||
if(n->hostname)
|
||||
free(n->hostname);
|
||||
|
||||
if(sa) {
|
||||
n->address = *sa;
|
||||
n->hostname = sockaddr2hostname(&n->address);
|
||||
splay_delete(node_udp_tree, n);
|
||||
splay_insert(node_udp_tree, n);
|
||||
logger(LOG_DEBUG, "UDP address of %s set to %s", n->name, n->hostname);
|
||||
} else {
|
||||
memset(&n->address, 0, sizeof n->address);
|
||||
logger(LOG_DEBUG, "UDP address of %s cleared", n->name);
|
||||
}
|
||||
}
|
||||
|
||||
int dump_nodes(struct evbuffer *out) {
|
||||
splay_node_t *node;
|
||||
node_t *n;
|
||||
|
@ -162,8 +184,8 @@ int dump_nodes(struct evbuffer *out) {
|
|||
for(node = node_tree->head; node; node = node->next) {
|
||||
n = node->data;
|
||||
if(evbuffer_add_printf(out, _(" %s at %s cipher %d digest %d maclength %d compression %d options %lx status %04x nexthop %s via %s distance %d pmtu %d (min %d max %d)\n"),
|
||||
n->name, n->hostname, cipher_get_nid(&n->cipher),
|
||||
digest_get_nid(&n->digest), n->maclength, n->compression,
|
||||
n->name, n->hostname, cipher_get_nid(&n->outcipher),
|
||||
digest_get_nid(&n->outdigest), n->outmaclength, n->outcompression,
|
||||
n->options, *(uint32_t *)&n->status, n->nexthop ? n->nexthop->name : "-",
|
||||
n->via ? n->via->name : "-", n->distance, n->mtu, n->minmtu, n->maxmtu) == -1)
|
||||
return errno;
|
||||
|
|
14
src/node.h
14
src/node.h
|
@ -54,11 +54,16 @@ typedef struct node_t {
|
|||
|
||||
node_status_t status;
|
||||
|
||||
cipher_t cipher; /* Cipher for UDP packets */
|
||||
digest_t digest; /* Digest for UDP packets */
|
||||
int maclength; /* Portion of digest to use */
|
||||
cipher_t incipher; /* Cipher for UDP packets */
|
||||
digest_t indigest; /* Digest for UDP packets */
|
||||
int inmaclength; /* Portion of digest to use */
|
||||
|
||||
int compression; /* Compressionlevel, 0 = no compression */
|
||||
cipher_t outcipher; /* Cipher for UDP packets */
|
||||
digest_t outdigest; /* Digest for UDP packets */
|
||||
int outmaclength; /* Portion of digest to use */
|
||||
|
||||
int incompression; /* Compressionlevel, 0 = no compression */
|
||||
int outcompression; /* Compressionlevel, 0 = no compression */
|
||||
|
||||
int distance;
|
||||
struct node_t *nexthop; /* nearest node from us to him */
|
||||
|
@ -94,5 +99,6 @@ extern void node_del(node_t *);
|
|||
extern node_t *lookup_node(char *);
|
||||
extern node_t *lookup_node_udp(const sockaddr_t *);
|
||||
extern int dump_nodes(struct evbuffer *);
|
||||
extern void update_node_udp(node_t *, const sockaddr_t *);
|
||||
|
||||
#endif /* __TINC_NODE_H__ */
|
||||
|
|
|
@ -52,7 +52,7 @@ bool digest_open_sha1(digest_t *digest) {
|
|||
void digest_close(digest_t *digest) {
|
||||
}
|
||||
|
||||
bool digest_create(digest_t *digest, void *indata, size_t inlen, void *outdata) {
|
||||
bool digest_create(digest_t *digest, const void *indata, size_t inlen, void *outdata) {
|
||||
EVP_MD_CTX ctx;
|
||||
|
||||
if(EVP_DigestInit(&ctx, digest->digest)
|
||||
|
@ -64,7 +64,7 @@ bool digest_create(digest_t *digest, void *indata, size_t inlen, void *outdata)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool digest_verify(digest_t *digest, void *indata, size_t inlen, void *cmpdata) {
|
||||
bool digest_verify(digest_t *digest, const void *indata, size_t inlen, const void *cmpdata) {
|
||||
size_t len = EVP_MD_size(digest->digest);
|
||||
char outdata[len];
|
||||
|
||||
|
|
|
@ -34,8 +34,8 @@ extern bool digest_open_by_name(struct digest *, const char *);
|
|||
extern bool digest_open_by_nid(struct digest *, int);
|
||||
extern bool digest_open_sha1(struct digest *);
|
||||
extern void digest_close(struct digest *);
|
||||
extern bool digest_create(struct digest *, void *indata, size_t inlen, void *outdata);
|
||||
extern bool digest_verify(struct digest *, void *indata, size_t inlen, void *digestdata);
|
||||
extern bool digest_create(struct digest *, const void *indata, size_t inlen, void *outdata);
|
||||
extern bool digest_verify(struct digest *, const void *indata, size_t inlen, const void *digestdata);
|
||||
extern int digest_get_nid(const struct digest *);
|
||||
extern size_t digest_length(const struct digest *);
|
||||
extern bool digest_active(const struct digest *);
|
||||
|
|
|
@ -96,9 +96,9 @@ extern bool send_add_subnet(struct connection_t *, const struct subnet_t *);
|
|||
extern bool send_del_subnet(struct connection_t *, const struct subnet_t *);
|
||||
extern bool send_add_edge(struct connection_t *, const struct edge_t *);
|
||||
extern bool send_del_edge(struct connection_t *, const struct edge_t *);
|
||||
extern bool send_key_changed(struct connection_t *, const struct node_t *);
|
||||
extern bool send_req_key(struct connection_t *, const struct node_t *, const struct node_t *);
|
||||
extern bool send_ans_key(struct connection_t *, const struct node_t *, const struct node_t *);
|
||||
extern bool send_key_changed();
|
||||
extern bool send_req_key(struct node_t *);
|
||||
extern bool send_ans_key(struct node_t *);
|
||||
extern bool send_tcppacket(struct connection_t *, struct vpn_packet_t *);
|
||||
|
||||
/* Request handlers */
|
||||
|
|
|
@ -243,7 +243,7 @@ bool send_challenge(connection_t *c) {
|
|||
cp();
|
||||
|
||||
if(!c->hischallenge)
|
||||
c->hischallenge = xmalloc(len);
|
||||
c->hischallenge = xrealloc(c->hischallenge, len);
|
||||
|
||||
/* Copy random data to the buffer */
|
||||
|
||||
|
|
|
@ -93,6 +93,17 @@ bool add_edge_h(connection_t *c, char *request) {
|
|||
/* Lookup nodes */
|
||||
|
||||
from = lookup_node(from_name);
|
||||
to = lookup_node(to_name);
|
||||
|
||||
if(tunnelserver &&
|
||||
from != myself && from != c->node &&
|
||||
to != myself && to != c->node) {
|
||||
/* ignore indirect edge registrations for tunnelserver */
|
||||
ifdebug(PROTOCOL) logger(LOG_WARNING,
|
||||
_("Ignoring indirect %s from %s (%s)"),
|
||||
"ADD_EDGE", c->name, c->hostname);
|
||||
return true;
|
||||
}
|
||||
|
||||
if(!from) {
|
||||
from = new_node();
|
||||
|
@ -100,16 +111,12 @@ bool add_edge_h(connection_t *c, char *request) {
|
|||
node_add(from);
|
||||
}
|
||||
|
||||
to = lookup_node(to_name);
|
||||
|
||||
if(!to) {
|
||||
to = new_node();
|
||||
to->name = xstrdup(to_name);
|
||||
node_add(to);
|
||||
}
|
||||
|
||||
if(tunnelserver && from != myself && from != c->node && to != myself && to != c->node)
|
||||
return false;
|
||||
|
||||
/* Convert addresses */
|
||||
|
||||
|
@ -206,6 +213,17 @@ bool del_edge_h(connection_t *c, char *request) {
|
|||
/* Lookup nodes */
|
||||
|
||||
from = lookup_node(from_name);
|
||||
to = lookup_node(to_name);
|
||||
|
||||
if(tunnelserver &&
|
||||
from != myself && from != c->node &&
|
||||
to != myself && to != c->node) {
|
||||
/* ignore indirect edge registrations for tunnelserver */
|
||||
ifdebug(PROTOCOL) logger(LOG_WARNING,
|
||||
_("Ignoring indirect %s from %s (%s)"),
|
||||
"DEL_EDGE", c->name, c->hostname);
|
||||
return true;
|
||||
}
|
||||
|
||||
if(!from) {
|
||||
ifdebug(PROTOCOL) logger(LOG_ERR, _("Got %s from %s (%s) which does not appear in the edge tree"),
|
||||
|
@ -213,17 +231,12 @@ bool del_edge_h(connection_t *c, char *request) {
|
|||
return true;
|
||||
}
|
||||
|
||||
to = lookup_node(to_name);
|
||||
|
||||
if(!to) {
|
||||
ifdebug(PROTOCOL) logger(LOG_ERR, _("Got %s from %s (%s) which does not appear in the edge tree"),
|
||||
"DEL_EDGE", c->name, c->hostname);
|
||||
return true;
|
||||
}
|
||||
|
||||
if(tunnelserver && from != myself && from != c->node && to != myself && to != c->node)
|
||||
return false;
|
||||
|
||||
/* Check if edge exists */
|
||||
|
||||
e = lookup_edge(from, to);
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "splay_tree.h"
|
||||
#include "cipher.h"
|
||||
#include "connection.h"
|
||||
#include "crypto.h"
|
||||
#include "logger.h"
|
||||
#include "net.h"
|
||||
#include "netutl.h"
|
||||
|
@ -35,17 +36,17 @@
|
|||
|
||||
static bool mykeyused = false;
|
||||
|
||||
bool send_key_changed(connection_t *c, const node_t *n) {
|
||||
bool send_key_changed() {
|
||||
cp();
|
||||
|
||||
/* Only send this message if some other daemon requested our key previously.
|
||||
This reduces unnecessary key_changed broadcasts.
|
||||
*/
|
||||
|
||||
if(n == myself && !mykeyused)
|
||||
if(!mykeyused)
|
||||
return true;
|
||||
|
||||
return send_request(c, "%d %lx %s", KEY_CHANGED, random(), n->name);
|
||||
return send_request(broadcast, "%d %lx %s", KEY_CHANGED, random(), myself->name);
|
||||
}
|
||||
|
||||
bool key_changed_h(connection_t *c, char *request) {
|
||||
|
@ -82,10 +83,10 @@ bool key_changed_h(connection_t *c, char *request) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool send_req_key(connection_t *c, const node_t *from, const node_t *to) {
|
||||
bool send_req_key(node_t *to) {
|
||||
cp();
|
||||
|
||||
return send_request(c, "%d %s %s", REQ_KEY, from->name, to->name);
|
||||
return send_request(to->nexthop->connection, "%d %s %s", REQ_KEY, myself->name, to->name);
|
||||
}
|
||||
|
||||
bool req_key_h(connection_t *c, char *request) {
|
||||
|
@ -120,10 +121,8 @@ bool req_key_h(connection_t *c, char *request) {
|
|||
/* Check if this key request is for us */
|
||||
|
||||
if(to == myself) { /* Yes, send our own key back */
|
||||
mykeyused = true;
|
||||
from->received_seqno = 0;
|
||||
memset(from->late, 0, sizeof from->late);
|
||||
send_ans_key(c, myself, from);
|
||||
|
||||
send_ans_key(from);
|
||||
} else {
|
||||
if(tunnelserver)
|
||||
return false;
|
||||
|
@ -134,27 +133,39 @@ bool req_key_h(connection_t *c, char *request) {
|
|||
return true;
|
||||
}
|
||||
|
||||
send_req_key(to->nexthop->connection, from, to);
|
||||
send_request(to->nexthop->connection, "%s", request);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool send_ans_key(connection_t *c, const node_t *from, const node_t *to) {
|
||||
size_t keylen = cipher_keylength(&from->cipher);
|
||||
bool send_ans_key(node_t *to) {
|
||||
size_t keylen = cipher_keylength(&myself->incipher);
|
||||
char key[keylen * 2 + 1];
|
||||
|
||||
cp();
|
||||
|
||||
cipher_get_key(&from->cipher, key);
|
||||
cipher_open_by_nid(&to->incipher, cipher_get_nid(&myself->incipher));
|
||||
digest_open_by_nid(&to->indigest, digest_get_nid(&myself->indigest));
|
||||
to->inmaclength = myself->inmaclength;
|
||||
to->incompression = myself->incompression;
|
||||
|
||||
randomize(key, keylen);
|
||||
cipher_set_key(&to->incipher, key, true);
|
||||
|
||||
bin2hex(key, key, keylen);
|
||||
key[keylen * 2] = '\0';
|
||||
|
||||
return send_request(c, "%d %s %s %s %d %d %d %d", ANS_KEY,
|
||||
from->name, to->name, key,
|
||||
cipher_get_nid(&from->cipher),
|
||||
digest_get_nid(&from->digest), from->maclength,
|
||||
from->compression);
|
||||
// Reset sequence number and late packet window
|
||||
mykeyused = true;
|
||||
to->received_seqno = 0;
|
||||
memset(to->late, 0, sizeof(to->late));
|
||||
|
||||
return send_request(to->nexthop->connection, "%d %s %s %s %d %d %d %d", ANS_KEY,
|
||||
myself->name, to->name, key,
|
||||
cipher_get_nid(&to->incipher),
|
||||
digest_get_nid(&to->indigest), to->inmaclength,
|
||||
to->incompression);
|
||||
}
|
||||
|
||||
bool ans_key_h(connection_t *c, char *request) {
|
||||
|
@ -207,24 +218,24 @@ bool ans_key_h(connection_t *c, char *request) {
|
|||
|
||||
/* Check and lookup cipher and digest algorithms */
|
||||
|
||||
if(!cipher_open_by_nid(&from->cipher, cipher)) {
|
||||
if(!cipher_open_by_nid(&from->outcipher, cipher)) {
|
||||
logger(LOG_ERR, _("Node %s (%s) uses unknown cipher!"), from->name, from->hostname);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(strlen(key) / 2 != cipher_keylength(&from->cipher)) {
|
||||
if(strlen(key) / 2 != cipher_keylength(&from->outcipher)) {
|
||||
logger(LOG_ERR, _("Node %s (%s) uses wrong keylength!"), from->name, from->hostname);
|
||||
return false;
|
||||
}
|
||||
|
||||
from->maclength = maclength;
|
||||
from->outmaclength = maclength;
|
||||
|
||||
if(!digest_open_by_nid(&from->digest, digest)) {
|
||||
if(!digest_open_by_nid(&from->outdigest, digest)) {
|
||||
logger(LOG_ERR, _("Node %s (%s) uses unknown digest!"), from->name, from->hostname);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(from->maclength > digest_length(&from->digest) || from->maclength < 0) {
|
||||
if(from->outmaclength > digest_length(&from->outdigest) || from->outmaclength < 0) {
|
||||
logger(LOG_ERR, _("Node %s (%s) uses bogus MAC length!"), from->name, from->hostname);
|
||||
return false;
|
||||
}
|
||||
|
@ -234,12 +245,12 @@ bool ans_key_h(connection_t *c, char *request) {
|
|||
return false;
|
||||
}
|
||||
|
||||
from->compression = compression;
|
||||
from->outcompression = compression;
|
||||
|
||||
/* Update our copy of the origin's packet key */
|
||||
|
||||
hex2bin(key, key, cipher_keylength(&from->cipher));
|
||||
cipher_set_key(&from->cipher, key, false);
|
||||
hex2bin(key, key, cipher_keylength(&from->outcipher));
|
||||
cipher_set_key(&from->outcipher, key, false);
|
||||
|
||||
from->status.validkey = true;
|
||||
from->status.waitingforkey = false;
|
||||
|
|
|
@ -60,7 +60,7 @@ bool add_subnet_h(connection_t *c, char *request)
|
|||
return false;
|
||||
}
|
||||
|
||||
/* Check if owner name is a valid */
|
||||
/* Check if owner name is valid */
|
||||
|
||||
if(!check_id(name)) {
|
||||
logger(LOG_ERR, _("Got bad %s from %s (%s): %s"), "ADD_SUBNET", c->name,
|
||||
|
@ -127,8 +127,11 @@ bool add_subnet_h(connection_t *c, char *request)
|
|||
free_subnet(allowed);
|
||||
}
|
||||
|
||||
if(!cfg)
|
||||
if(!cfg) {
|
||||
logger(LOG_WARNING, _("Unauthorized %s from %s (%s) for %s"),
|
||||
"ADD_SUBNET", c->name, c->hostname, subnetstr);
|
||||
return false;
|
||||
}
|
||||
|
||||
free_subnet(allowed);
|
||||
}
|
||||
|
@ -176,7 +179,7 @@ bool del_subnet_h(connection_t *c, char *request)
|
|||
return false;
|
||||
}
|
||||
|
||||
/* Check if owner name is a valid */
|
||||
/* Check if owner name is valid */
|
||||
|
||||
if(!check_id(name)) {
|
||||
logger(LOG_ERR, _("Got bad %s from %s (%s): %s"), "DEL_SUBNET", c->name,
|
||||
|
@ -184,19 +187,6 @@ bool del_subnet_h(connection_t *c, char *request)
|
|||
return false;
|
||||
}
|
||||
|
||||
/* Check if the owner of the new subnet is in the connection list */
|
||||
|
||||
owner = lookup_node(name);
|
||||
|
||||
if(!owner) {
|
||||
ifdebug(PROTOCOL) logger(LOG_WARNING, _("Got %s from %s (%s) for %s which is not in our node tree"),
|
||||
"DEL_SUBNET", c->name, c->hostname, name);
|
||||
return true;
|
||||
}
|
||||
|
||||
if(tunnelserver && owner != myself && owner != c->node)
|
||||
return false;
|
||||
|
||||
/* Check if subnet string is valid */
|
||||
|
||||
if(!str2net(&s, subnetstr)) {
|
||||
|
@ -208,6 +198,23 @@ bool del_subnet_h(connection_t *c, char *request)
|
|||
if(seen_request(request))
|
||||
return true;
|
||||
|
||||
/* Check if the owner of the subnet being deleted is in the connection list */
|
||||
|
||||
owner = lookup_node(name);
|
||||
|
||||
if(tunnelserver && owner != myself && owner != c->node) {
|
||||
/* in case of tunnelserver, ignore indirect subnet deletion */
|
||||
ifdebug(PROTOCOL) logger(LOG_WARNING, _("Ignoring indirect %s from %s (%s) for %s"),
|
||||
"DEL_SUBNET", c->name, c->hostname, subnetstr);
|
||||
return true;
|
||||
}
|
||||
|
||||
if(!owner) {
|
||||
ifdebug(PROTOCOL) logger(LOG_WARNING, _("Got %s from %s (%s) for %s which is not in our node tree"),
|
||||
"DEL_SUBNET", c->name, c->hostname, name);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* If everything is correct, delete the subnet from the list of the owner */
|
||||
|
||||
s.owner = owner;
|
||||
|
|
145
src/tincd.c
145
src/tincd.c
|
@ -33,6 +33,12 @@
|
|||
|
||||
#include LZO1X_H
|
||||
|
||||
#ifndef HAVE_MINGW
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#include <getopt.h>
|
||||
|
||||
#include "conf.h"
|
||||
|
@ -62,6 +68,12 @@ bool bypass_security = false;
|
|||
/* If nonzero, disable swapping for this process. */
|
||||
bool do_mlock = false;
|
||||
|
||||
/* If nonzero, chroot to netdir after startup. */
|
||||
static bool do_chroot = false;
|
||||
|
||||
/* If !NULL, do setuid to given user after startup */
|
||||
static const char *switchuser = NULL;
|
||||
|
||||
/* If nonzero, write log entries to a separate file. */
|
||||
bool use_logfile = false;
|
||||
|
||||
|
@ -81,6 +93,8 @@ static struct option const long_options[] = {
|
|||
{"debug", optional_argument, NULL, 'd'},
|
||||
{"bypass-security", no_argument, NULL, 3},
|
||||
{"mlock", no_argument, NULL, 'L'},
|
||||
{"chroot", no_argument, NULL, 'R'},
|
||||
{"user", required_argument, NULL, 'U'},
|
||||
{"logfile", optional_argument, NULL, 4},
|
||||
{"controlsocket", required_argument, NULL, 5},
|
||||
{NULL, 0, NULL, 0}
|
||||
|
@ -105,7 +119,8 @@ static void usage(bool status)
|
|||
" --logfile[=FILENAME] Write log entries to a logfile.\n"
|
||||
" --controlsocket=FILENAME Open control socket at FILENAME.\n"
|
||||
" --bypass-security Disables meta protocol security, for debugging.\n"
|
||||
" --help Display this help and exit.\n"
|
||||
" -R, --chroot chroot to NET dir at startup.\n"
|
||||
" -U, --user=USER setuid to given USER at startup.\n" " --help Display this help and exit.\n"
|
||||
" --version Output version information and exit.\n\n"));
|
||||
printf(_("Report bugs to tinc@tinc-vpn.org.\n"));
|
||||
}
|
||||
|
@ -116,7 +131,7 @@ static bool parse_options(int argc, char **argv)
|
|||
int r;
|
||||
int option_index = 0;
|
||||
|
||||
while((r = getopt_long(argc, argv, "c:DLd::n:", long_options, &option_index)) != EOF) {
|
||||
while((r = getopt_long(argc, argv, "c:DLd::n:RU:", long_options, &option_index)) != EOF) {
|
||||
switch (r) {
|
||||
case 0: /* long option */
|
||||
break;
|
||||
|
@ -130,8 +145,13 @@ static bool parse_options(int argc, char **argv)
|
|||
break;
|
||||
|
||||
case 'L': /* no detach */
|
||||
#ifndef HAVE_MLOCKALL
|
||||
logger(LOG_ERR, _("%s not supported on this platform"), "mlockall()");
|
||||
return false;
|
||||
#else
|
||||
do_mlock = true;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case 'd': /* inc debug level */
|
||||
if(optarg)
|
||||
|
@ -144,6 +164,14 @@ static bool parse_options(int argc, char **argv)
|
|||
netname = xstrdup(optarg);
|
||||
break;
|
||||
|
||||
case 'R': /* chroot to NETNAME dir */
|
||||
do_chroot = true;
|
||||
break;
|
||||
|
||||
case 'U': /* setuid to USER */
|
||||
switchuser = optarg;
|
||||
break;
|
||||
|
||||
case 1: /* show help */
|
||||
show_help = true;
|
||||
break;
|
||||
|
@ -237,6 +265,63 @@ static void free_names() {
|
|||
if (confbase) free(confbase);
|
||||
}
|
||||
|
||||
static bool drop_privs() {
|
||||
#ifdef HAVE_MINGW
|
||||
if (switchuser) {
|
||||
logger(LOG_ERR, _("%s not supported on this platform"), "-U");
|
||||
return false;
|
||||
}
|
||||
if (do_chroot) {
|
||||
logger(LOG_ERR, _("%s not supported on this platform"), "-R");
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
uid_t uid = 0;
|
||||
if (switchuser) {
|
||||
struct passwd *pw = getpwnam(switchuser);
|
||||
if (!pw) {
|
||||
logger(LOG_ERR, _("unknown user `%s'"), switchuser);
|
||||
return false;
|
||||
}
|
||||
uid = pw->pw_uid;
|
||||
if (initgroups(switchuser, pw->pw_gid) != 0 ||
|
||||
setgid(pw->pw_gid) != 0) {
|
||||
logger(LOG_ERR, _("System call `%s' failed: %s"),
|
||||
"initgroups", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
endgrent();
|
||||
endpwent();
|
||||
}
|
||||
if (do_chroot) {
|
||||
tzset(); /* for proper timestamps in logs */
|
||||
if (chroot(confbase) != 0 || chdir("/") != 0) {
|
||||
logger(LOG_ERR, _("System call `%s' failed: %s"),
|
||||
"chroot", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
free(confbase);
|
||||
confbase = xstrdup("");
|
||||
}
|
||||
if (switchuser)
|
||||
if (setuid(uid) != 0) {
|
||||
logger(LOG_ERR, _("System call `%s' failed: %s"),
|
||||
"setuid", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef HAVE_MINGW
|
||||
# define setpriority(level) SetPriorityClass(GetCurrentProcess(), level);
|
||||
#else
|
||||
# define NORMAL_PRIORITY_CLASS 0
|
||||
# define BELOW_NORMAL_PRIORITY_CLASS 10
|
||||
# define HIGH_PRIORITY_CLASS -10
|
||||
# define setpriority(level) nice(level)
|
||||
#endif
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
program_name = argv[0];
|
||||
|
@ -277,20 +362,6 @@ int main(int argc, char **argv)
|
|||
if(!init_control())
|
||||
return 1;
|
||||
|
||||
/* Lock all pages into memory if requested */
|
||||
|
||||
if(do_mlock)
|
||||
#ifdef HAVE_MLOCKALL
|
||||
if(mlockall(MCL_CURRENT | MCL_FUTURE)) {
|
||||
logger(LOG_ERR, _("System call `%s' failed: %s"), "mlockall",
|
||||
strerror(errno));
|
||||
#else
|
||||
{
|
||||
logger(LOG_ERR, _("mlockall() not supported on this platform!"));
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
g_argv = argv;
|
||||
|
||||
init_configuration(&config_tree);
|
||||
|
@ -326,11 +397,46 @@ int main2(int argc, char **argv)
|
|||
|
||||
if(!detach())
|
||||
return 1;
|
||||
|
||||
|
||||
#ifdef HAVE_MLOCKALL
|
||||
/* Lock all pages into memory if requested.
|
||||
* This has to be done after daemon()/fork() so it works for child.
|
||||
* No need to do that in parent as it's very short-lived. */
|
||||
if(do_mlock && mlockall(MCL_CURRENT | MCL_FUTURE) != 0) {
|
||||
logger(LOG_ERR, _("System call `%s' failed: %s"), "mlockall",
|
||||
strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Setup sockets and open device. */
|
||||
|
||||
if(!setup_network_connections())
|
||||
if(!setup_network())
|
||||
goto end;
|
||||
|
||||
/* Initiate all outgoing connections. */
|
||||
|
||||
try_outgoing_connections();
|
||||
|
||||
/* Change process priority */
|
||||
|
||||
char *priority = 0;
|
||||
|
||||
if(get_config_string(lookup_config(config_tree, "ProcessPriority"), &priority)) {
|
||||
if(!strcasecmp(priority, "Normal"))
|
||||
setpriority(NORMAL_PRIORITY_CLASS);
|
||||
else if(!strcasecmp(priority, "Low"))
|
||||
setpriority(BELOW_NORMAL_PRIORITY_CLASS);
|
||||
else if(!strcasecmp(priority, "High"))
|
||||
setpriority(HIGH_PRIORITY_CLASS);
|
||||
else {
|
||||
logger(LOG_ERR, _("Invalid priority `%s`!"), priority);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
/* drop privileges */
|
||||
if (!drop_privs())
|
||||
goto end;
|
||||
|
||||
/* Start main loop. It only exits when tinc is killed. */
|
||||
|
@ -353,5 +459,8 @@ end:
|
|||
|
||||
crypto_exit();
|
||||
|
||||
exit_configuration(&config_tree);
|
||||
free_names();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue