New upstream version 1.0.36
This commit is contained in:
parent
b511a112e6
commit
10b8518c22
214 changed files with 12416 additions and 59622 deletions
222
src/Makefile.am
222
src/Makefile.am
|
|
@ -1,174 +1,54 @@
|
|||
## Produce this file with automake to get Makefile.in
|
||||
|
||||
sbin_PROGRAMS = tincd tinc
|
||||
check_PROGRAMS = sptps_test sptps_keypair
|
||||
EXTRA_PROGRAMS = sptps_test sptps_keypair
|
||||
|
||||
CLEANFILES = version_git.h
|
||||
|
||||
.PHONY: version-stamp
|
||||
version-stamp:
|
||||
|
||||
version_git.h: version-stamp
|
||||
$(AM_V_GEN)echo >$@
|
||||
@-(cd $(srcdir) && git describe 2>/dev/null >/dev/null) && echo '#define GIT_DESCRIPTION "'`(cd $(srcdir) && git describe) | sed 's/release-//'`'"' >$@ ||:
|
||||
${srcdir}/version.c: version_git.h
|
||||
|
||||
## Now a hack to appease some versions of BSD make that don't understand that "./foo" is the same as "foo".
|
||||
if BSD
|
||||
version.c: ${srcdir}/version.c
|
||||
endif
|
||||
|
||||
if LINUX
|
||||
EXTRA_PROGRAMS += sptps_speed
|
||||
endif
|
||||
|
||||
ed25519_SOURCES = \
|
||||
ed25519/ed25519.h \
|
||||
ed25519/fe.c ed25519/fe.h \
|
||||
ed25519/fixedint.h \
|
||||
ed25519/ge.c ed25519/ge.h \
|
||||
ed25519/key_exchange.c \
|
||||
ed25519/keypair.c \
|
||||
ed25519/precomp_data.h \
|
||||
ed25519/sc.c ed25519/sc.h \
|
||||
ed25519/sha512.c ed25519/sha512.h \
|
||||
ed25519/sign.c \
|
||||
ed25519/verify.c
|
||||
|
||||
chacha_poly1305_SOURCES = \
|
||||
chacha-poly1305/chacha.c chacha-poly1305/chacha.h \
|
||||
chacha-poly1305/chacha-poly1305.c chacha-poly1305/chacha-poly1305.h \
|
||||
chacha-poly1305/poly1305.c chacha-poly1305/poly1305.h
|
||||
sbin_PROGRAMS = tincd
|
||||
|
||||
tincd_SOURCES = \
|
||||
address_cache.c address_cache.h \
|
||||
autoconnect.c autoconnect.h \
|
||||
buffer.c buffer.h \
|
||||
cipher.h \
|
||||
have.h \
|
||||
system.h \
|
||||
avl_tree.c avl_tree.h \
|
||||
conf.c conf.h \
|
||||
connection.c connection.h \
|
||||
control.c control.h \
|
||||
control_common.h \
|
||||
crypto.h \
|
||||
device.h \
|
||||
digest.h \
|
||||
dropin.c dropin.h \
|
||||
dummy_device.c \
|
||||
ecdh.h \
|
||||
ecdsa.h \
|
||||
ecdsagen.h \
|
||||
edge.c edge.h \
|
||||
ethernet.h \
|
||||
event.c event.h \
|
||||
fd_device.c \
|
||||
fake-getaddrinfo.c fake-getaddrinfo.h \
|
||||
fake-getnameinfo.c fake-getnameinfo.h \
|
||||
graph.c graph.h \
|
||||
hash.c hash.h \
|
||||
have.h \
|
||||
ipv4.h \
|
||||
ipv6.h \
|
||||
list.c list.h \
|
||||
logger.c logger.h \
|
||||
meta.c meta.h \
|
||||
multicast_device.c \
|
||||
names.c names.h \
|
||||
net.c net.h \
|
||||
net_packet.c \
|
||||
net_setup.c \
|
||||
net_socket.c \
|
||||
netutl.c netutl.h \
|
||||
node.c node.h \
|
||||
prf.h \
|
||||
pidfile.c pidfile.h \
|
||||
process.c process.h \
|
||||
protocol.c protocol.h \
|
||||
protocol_auth.c \
|
||||
protocol_edge.c \
|
||||
protocol_key.c \
|
||||
protocol_misc.c \
|
||||
protocol_key.c \
|
||||
protocol_subnet.c \
|
||||
proxy.c proxy.h \
|
||||
raw_socket_device.c \
|
||||
route.c route.h \
|
||||
rsa.h \
|
||||
rsagen.h \
|
||||
script.c script.h \
|
||||
splay_tree.c splay_tree.h \
|
||||
sptps.c sptps.h \
|
||||
subnet.c subnet.h \
|
||||
subnet_parse.c \
|
||||
system.h \
|
||||
tincd.c \
|
||||
utils.c utils.h \
|
||||
xalloc.h \
|
||||
version.c version.h \
|
||||
ed25519/ecdh.c \
|
||||
ed25519/ecdsa.c \
|
||||
$(ed25519_SOURCES) \
|
||||
$(chacha_poly1305_SOURCES)
|
||||
|
||||
tinc_SOURCES = \
|
||||
dropin.c dropin.h \
|
||||
fsck.c fsck.h \
|
||||
ifconfig.c ifconfig.h \
|
||||
info.c info.h \
|
||||
invitation.c invitation.h \
|
||||
list.c list.h \
|
||||
names.c names.h \
|
||||
netutl.c netutl.h \
|
||||
script.c script.h \
|
||||
sptps.c sptps.h \
|
||||
subnet_parse.c subnet.h \
|
||||
tincctl.c tincctl.h \
|
||||
top.c top.h \
|
||||
utils.c utils.h \
|
||||
version.c version.h \
|
||||
ed25519/ecdh.c \
|
||||
ed25519/ecdsa.c \
|
||||
ed25519/ecdsagen.c \
|
||||
$(ed25519_SOURCES) \
|
||||
$(chacha_poly1305_SOURCES)
|
||||
|
||||
sptps_test_SOURCES = \
|
||||
logger.c logger.h \
|
||||
sptps.c sptps.h \
|
||||
sptps_test.c \
|
||||
utils.c utils.h \
|
||||
ed25519/ecdh.c \
|
||||
ed25519/ecdsa.c \
|
||||
$(ed25519_SOURCES) \
|
||||
$(chacha_poly1305_SOURCES)
|
||||
|
||||
sptps_keypair_SOURCES = \
|
||||
sptps_keypair.c \
|
||||
utils.c utils.h \
|
||||
ed25519/ecdsagen.c \
|
||||
$(ed25519_SOURCES)
|
||||
|
||||
sptps_speed_SOURCES = \
|
||||
logger.c logger.h \
|
||||
sptps.c sptps.h \
|
||||
sptps_speed.c \
|
||||
utils.c utils.h \
|
||||
ed25519/ecdh.c \
|
||||
ed25519/ecdsa.c \
|
||||
ed25519/ecdsagen.c \
|
||||
$(ed25519_SOURCES) \
|
||||
$(chacha_poly1305_SOURCES)
|
||||
|
||||
## Conditionally compile device drivers
|
||||
xalloc.h
|
||||
|
||||
if !GETOPT
|
||||
tincd_SOURCES += \
|
||||
getopt.c getopt.h \
|
||||
getopt1.c
|
||||
tinc_SOURCES += \
|
||||
getopt.c getopt.h \
|
||||
getopt1.c
|
||||
sptps_test_SOURCES += \
|
||||
getopt.c getopt.h \
|
||||
getopt1.c
|
||||
sptps_keypair_SOURCES += \
|
||||
getopt.c getopt.h \
|
||||
getopt1.c
|
||||
endif
|
||||
|
||||
if LINUX
|
||||
|
|
@ -202,88 +82,8 @@ if VDE
|
|||
tincd_SOURCES += vde_device.c
|
||||
endif
|
||||
|
||||
if OPENSSL
|
||||
tincd_SOURCES += \
|
||||
openssl/cipher.c \
|
||||
openssl/crypto.c \
|
||||
openssl/digest.c openssl/digest.h \
|
||||
openssl/prf.c \
|
||||
openssl/rsa.c
|
||||
tinc_SOURCES += \
|
||||
openssl/cipher.c \
|
||||
openssl/crypto.c \
|
||||
openssl/digest.c openssl/digest.h \
|
||||
openssl/prf.c \
|
||||
openssl/rsa.c \
|
||||
openssl/rsagen.c
|
||||
sptps_test_SOURCES += \
|
||||
openssl/crypto.c \
|
||||
openssl/digest.c openssl/digest.h \
|
||||
openssl/prf.c
|
||||
sptps_keypair_SOURCES += \
|
||||
openssl/crypto.c
|
||||
sptps_speed_SOURCES += \
|
||||
openssl/crypto.c \
|
||||
openssl/digest.c openssl/digest.h \
|
||||
openssl/prf.c
|
||||
else
|
||||
if GCRYPT
|
||||
tincd_SOURCES += \
|
||||
gcrypt/cipher.c \
|
||||
gcrypt/crypto.c \
|
||||
gcrypt/digest.c gcrypt/digest.h \
|
||||
gcrypt/prf.c \
|
||||
gcrypt/rsa.c
|
||||
tinc_SOURCES += \
|
||||
gcrypt/cipher.c \
|
||||
gcrypt/crypto.c \
|
||||
gcrypt/digest.c gcrypt/digest.h \
|
||||
gcrypt/prf.c \
|
||||
gcrypt/rsa.c \
|
||||
gcrypt/rsagen.c
|
||||
sptps_test_SOURCES += \
|
||||
gcrypt/cipher.c \
|
||||
gcrypt/crypto.c \
|
||||
gcrypt/digest.c gcrypt/digest.h \
|
||||
gcrypt/prf.c
|
||||
sptps_keypair_SOURCES += \
|
||||
openssl/crypto.c
|
||||
sptps_speed_SOURCES += \
|
||||
openssl/crypto.c \
|
||||
openssl/digest.c openssl/digest.h \
|
||||
openssl/prf.c
|
||||
else
|
||||
tincd_SOURCES += \
|
||||
nolegacy/crypto.c \
|
||||
nolegacy/prf.c
|
||||
tinc_SOURCES += \
|
||||
nolegacy/crypto.c \
|
||||
nolegacy/prf.c
|
||||
sptps_test_SOURCES += \
|
||||
nolegacy/crypto.c \
|
||||
nolegacy/prf.c
|
||||
sptps_keypair_SOURCES += \
|
||||
nolegacy/crypto.c
|
||||
sptps_speed_SOURCES += \
|
||||
nolegacy/crypto.c \
|
||||
nolegacy/prf.c
|
||||
endif
|
||||
endif
|
||||
|
||||
if MINIUPNPC
|
||||
tincd_SOURCES += upnp.h upnp.c
|
||||
tincd_LDADD = $(MINIUPNPC_LIBS)
|
||||
tincd_LDFLAGS = -pthread
|
||||
endif
|
||||
|
||||
tinc_LDADD = $(READLINE_LIBS) $(CURSES_LIBS)
|
||||
sptps_speed_LDADD = -lrt
|
||||
|
||||
LIBS = @LIBS@ -lm $(CODE_COVERAGE_LIBS)
|
||||
|
||||
if TUNEMU
|
||||
LIBS += -lpcap
|
||||
endif
|
||||
|
||||
AM_CFLAGS = -DCONFDIR=\"$(sysconfdir)\" -DRUNSTATEDIR=\"$(runstatedir)\" -DLOCALSTATEDIR=\"$(localstatedir)\" -DSBINDIR=\"$(sbindir)\" -iquote. $(CODE_COVERAGE_CFLAGS)
|
||||
AM_CPPFLAGS = $(CODE_COVERAGE_CPPFLAGS)
|
||||
AM_CPPFLAGS = -DCONFDIR=\"$(sysconfdir)\" -DRUNSTATEDIR=\"$(runstatedir)\" -DLOCALSTATEDIR=\"$(localstatedir)\" -I $(abs_top_builddir)/
|
||||
|
|
|
|||
836
src/Makefile.in
836
src/Makefile.in
File diff suppressed because it is too large
Load diff
|
|
@ -1,277 +0,0 @@
|
|||
/*
|
||||
address_cache.c -- Manage cache of recently seen addresses
|
||||
Copyright (C) 2018 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "address_cache.h"
|
||||
#include "conf.h"
|
||||
#include "names.h"
|
||||
#include "netutl.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
static const unsigned int NOT_CACHED = -1;
|
||||
|
||||
// Find edges pointing to this node, and use them to build a list of unique, known addresses.
|
||||
static struct addrinfo *get_known_addresses(node_t *n) {
|
||||
struct addrinfo *ai = NULL;
|
||||
struct addrinfo *oai = NULL;
|
||||
|
||||
for splay_each(edge_t, e, n->edge_tree) {
|
||||
if(!e->reverse) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
|
||||
for(struct addrinfo *aip = ai; aip; aip = aip->ai_next) {
|
||||
if(!sockaddrcmp(&e->reverse->address, (sockaddr_t *)aip->ai_addr)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(found) {
|
||||
continue;
|
||||
}
|
||||
|
||||
oai = ai;
|
||||
ai = xzalloc(sizeof(*ai));
|
||||
ai->ai_family = e->reverse->address.sa.sa_family;
|
||||
ai->ai_socktype = SOCK_STREAM;
|
||||
ai->ai_protocol = IPPROTO_TCP;
|
||||
ai->ai_addrlen = SALEN(e->reverse->address.sa);
|
||||
ai->ai_addr = xmalloc(ai->ai_addrlen);
|
||||
memcpy(ai->ai_addr, &e->reverse->address, ai->ai_addrlen);
|
||||
ai->ai_next = oai;
|
||||
}
|
||||
|
||||
return ai;
|
||||
}
|
||||
|
||||
static void free_known_addresses(struct addrinfo *ai) {
|
||||
for(struct addrinfo *aip = ai, *next; aip; aip = next) {
|
||||
next = aip->ai_next;
|
||||
free(aip);
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int find_cached(address_cache_t *cache, const sockaddr_t *sa) {
|
||||
for(unsigned int i = 0; i < cache->data.used; i++)
|
||||
if(!sockaddrcmp(&cache->data.address[i], sa)) {
|
||||
return i;
|
||||
}
|
||||
|
||||
return NOT_CACHED;
|
||||
}
|
||||
|
||||
void add_recent_address(address_cache_t *cache, const sockaddr_t *sa) {
|
||||
// Check if it's already cached
|
||||
unsigned int pos = find_cached(cache, sa);
|
||||
|
||||
// It's in the first spot, so nothing to do
|
||||
if(pos == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Shift everything, move/add the address to the first slot
|
||||
if(pos == NOT_CACHED) {
|
||||
if(cache->data.used < MAX_CACHED_ADDRESSES) {
|
||||
cache->data.used++;
|
||||
}
|
||||
|
||||
pos = cache->data.used - 1;
|
||||
}
|
||||
|
||||
memmove(&cache->data.address[1], &cache->data.address[0], pos * sizeof(cache->data.address[0]));
|
||||
|
||||
cache->data.address[0] = *sa;
|
||||
|
||||
// Write the cache
|
||||
char fname[PATH_MAX];
|
||||
snprintf(fname, sizeof(fname), "%s" SLASH "cache" SLASH "%s", confbase, cache->node->name);
|
||||
FILE *fp = fopen(fname, "wb");
|
||||
|
||||
if(fp) {
|
||||
fwrite(&cache->data, sizeof(cache->data), 1, fp);
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
|
||||
const sockaddr_t *get_recent_address(address_cache_t *cache) {
|
||||
// Check if there is an address in our cache of recently seen addresses
|
||||
if(cache->tried < cache->data.used) {
|
||||
return &cache->data.address[cache->tried++];
|
||||
}
|
||||
|
||||
// Next, check any recently seen addresses not in our cache
|
||||
while(cache->tried == cache->data.used) {
|
||||
if(!cache->ai) {
|
||||
cache->aip = cache->ai = get_known_addresses(cache->node);
|
||||
}
|
||||
|
||||
if(cache->ai) {
|
||||
if(cache->aip) {
|
||||
sockaddr_t *sa = (sockaddr_t *)cache->aip->ai_addr;
|
||||
cache->aip = cache->aip->ai_next;
|
||||
|
||||
if(find_cached(cache, sa) != NOT_CACHED) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return sa;
|
||||
} else {
|
||||
free_known_addresses(cache->ai);
|
||||
cache->ai = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
cache->tried++;
|
||||
}
|
||||
|
||||
// Otherwise, check if there are any known Address statements
|
||||
if(!cache->config_tree) {
|
||||
init_configuration(&cache->config_tree);
|
||||
read_host_config(cache->config_tree, cache->node->name, false);
|
||||
cache->cfg = lookup_config(cache->config_tree, "Address");
|
||||
}
|
||||
|
||||
while(cache->cfg && !cache->ai) {
|
||||
char *address, *port;
|
||||
|
||||
get_config_string(cache->cfg, &address);
|
||||
|
||||
char *space = strchr(address, ' ');
|
||||
|
||||
if(space) {
|
||||
port = xstrdup(space + 1);
|
||||
*space = 0;
|
||||
} else {
|
||||
if(!get_config_string(lookup_config(cache->config_tree, "Port"), &port)) {
|
||||
port = xstrdup("655");
|
||||
}
|
||||
}
|
||||
|
||||
cache->aip = cache->ai = str2addrinfo(address, port, SOCK_STREAM);
|
||||
|
||||
if(cache->ai) {
|
||||
struct addrinfo *ai = NULL;
|
||||
|
||||
for(; cache->aip; cache->aip = cache->aip->ai_next) {
|
||||
struct addrinfo *oai = ai;
|
||||
|
||||
ai = xzalloc(sizeof(*ai));
|
||||
ai->ai_family = cache->aip->ai_family;
|
||||
ai->ai_socktype = cache->aip->ai_socktype;
|
||||
ai->ai_protocol = cache->aip->ai_protocol;
|
||||
ai->ai_addrlen = cache->aip->ai_addrlen;
|
||||
ai->ai_addr = xmalloc(ai->ai_addrlen);
|
||||
memcpy(ai->ai_addr, cache->aip->ai_addr, ai->ai_addrlen);
|
||||
ai->ai_next = oai;
|
||||
}
|
||||
|
||||
freeaddrinfo(cache->ai);
|
||||
cache->aip = cache->ai = ai;
|
||||
}
|
||||
|
||||
free(address);
|
||||
free(port);
|
||||
|
||||
cache->cfg = lookup_config_next(cache->config_tree, cache->cfg);
|
||||
}
|
||||
|
||||
if(cache->ai) {
|
||||
if(cache->aip) {
|
||||
sockaddr_t *sa = (sockaddr_t *)cache->aip->ai_addr;
|
||||
|
||||
cache->aip = cache->aip->ai_next;
|
||||
return sa;
|
||||
} else {
|
||||
free_known_addresses(cache->ai);
|
||||
cache->ai = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// We're all out of addresses.
|
||||
exit_configuration(&cache->config_tree);
|
||||
return false;
|
||||
}
|
||||
|
||||
address_cache_t *open_address_cache(node_t *node) {
|
||||
address_cache_t *cache = xmalloc(sizeof(*cache));
|
||||
cache->node = node;
|
||||
|
||||
// Try to open an existing address cache
|
||||
char fname[PATH_MAX];
|
||||
snprintf(fname, sizeof(fname), "%s" SLASH "cache" SLASH "%s", confbase, node->name);
|
||||
FILE *fp = fopen(fname, "rb");
|
||||
|
||||
if(!fp || fread(&cache->data, sizeof(cache->data), 1, fp) != 1 || cache->data.version != ADDRESS_CACHE_VERSION) {
|
||||
memset(&cache->data, 0, sizeof(cache->data));
|
||||
}
|
||||
|
||||
if(fp) {
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
// Ensure we have a valid state
|
||||
cache->config_tree = NULL;
|
||||
cache->cfg = NULL;
|
||||
cache->ai = NULL;
|
||||
cache->aip = NULL;
|
||||
cache->tried = 0;
|
||||
cache->data.version = ADDRESS_CACHE_VERSION;
|
||||
|
||||
if(cache->data.used > MAX_CACHED_ADDRESSES) {
|
||||
cache->data.used = 0;
|
||||
}
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
void reset_address_cache(address_cache_t *cache, const sockaddr_t *sa) {
|
||||
if(sa) {
|
||||
add_recent_address(cache, sa);
|
||||
}
|
||||
|
||||
if(cache->config_tree) {
|
||||
exit_configuration(&cache->config_tree);
|
||||
}
|
||||
|
||||
if(cache->ai) {
|
||||
free_known_addresses(cache->ai);
|
||||
}
|
||||
|
||||
cache->config_tree = NULL;
|
||||
cache->cfg = NULL;
|
||||
cache->ai = NULL;
|
||||
cache->aip = NULL;
|
||||
cache->tried = 0;
|
||||
}
|
||||
|
||||
void close_address_cache(address_cache_t *cache) {
|
||||
if(cache->config_tree) {
|
||||
exit_configuration(&cache->config_tree);
|
||||
}
|
||||
|
||||
if(cache->ai) {
|
||||
free_known_addresses(cache->ai);
|
||||
}
|
||||
|
||||
free(cache);
|
||||
}
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
#ifndef TINC_ADDRESS_CACHE_H
|
||||
#define TINC_ADDRESS_CACHE_H
|
||||
|
||||
/*
|
||||
address_cache.h -- header for address_cache.c
|
||||
Copyright (C) 2018 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "net.h"
|
||||
|
||||
#define MAX_CACHED_ADDRESSES 8
|
||||
#define ADDRESS_CACHE_VERSION 1
|
||||
|
||||
typedef struct address_cache_t {
|
||||
struct node_t *node;
|
||||
struct splay_tree_t *config_tree;
|
||||
struct config_t *cfg;
|
||||
struct addrinfo *ai;
|
||||
struct addrinfo *aip;
|
||||
unsigned int tried;
|
||||
|
||||
struct {
|
||||
unsigned int version;
|
||||
unsigned int used;
|
||||
sockaddr_t address[MAX_CACHED_ADDRESSES];
|
||||
} data;
|
||||
} address_cache_t;
|
||||
|
||||
void add_recent_address(address_cache_t *cache, const sockaddr_t *sa);
|
||||
const sockaddr_t *get_recent_address(address_cache_t *cache);
|
||||
|
||||
address_cache_t *open_address_cache(struct node_t *node);
|
||||
void reset_address_cache(address_cache_t *cache, const sockaddr_t *sa);
|
||||
void close_address_cache(address_cache_t *cache);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,195 +0,0 @@
|
|||
/*
|
||||
autoconnect.c -- automatic connection establishment
|
||||
Copyright (C) 2017 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "connection.h"
|
||||
#include "logger.h"
|
||||
#include "node.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
static void make_new_connection() {
|
||||
/* Select a random node we haven't connected to yet. */
|
||||
int count = 0;
|
||||
|
||||
for splay_each(node_t, n, node_tree) {
|
||||
if(n == myself || n->connection || !(n->status.has_address || n->status.reachable)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
if(!count) {
|
||||
return;
|
||||
}
|
||||
|
||||
int r = rand() % count;
|
||||
|
||||
for splay_each(node_t, n, node_tree) {
|
||||
if(n == myself || n->connection || !(n->status.has_address || n->status.reachable)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(r--) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
|
||||
for list_each(outgoing_t, outgoing, outgoing_list) {
|
||||
if(outgoing->node == n) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!found) {
|
||||
logger(DEBUG_CONNECTIONS, LOG_INFO, "Autoconnecting to %s", n->name);
|
||||
outgoing_t *outgoing = xzalloc(sizeof(*outgoing));
|
||||
outgoing->node = n;
|
||||
list_insert_tail(outgoing_list, outgoing);
|
||||
setup_outgoing_connection(outgoing, false);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void connect_to_unreachable() {
|
||||
/* Select a random known node. The rationale is that if there are many
|
||||
* reachable nodes, and only a few unreachable nodes, we don't want all
|
||||
* reachable nodes to try to connect to the unreachable ones at the
|
||||
* same time. This way, we back off automatically. Conversely, if there
|
||||
* are only a few reachable nodes, and many unreachable ones, we're
|
||||
* going to try harder to connect to them. */
|
||||
|
||||
int r = rand() % node_tree->count;
|
||||
|
||||
for splay_each(node_t, n, node_tree) {
|
||||
if(r--) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Is it unreachable and do we know an address for it? If not, return. */
|
||||
if(n == myself || n->connection || n->status.reachable || !n->status.has_address) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Are we already trying to make an outgoing connection to it? If so, return. */
|
||||
for list_each(outgoing_t, outgoing, outgoing_list) {
|
||||
if(outgoing->node == n) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
logger(DEBUG_CONNECTIONS, LOG_INFO, "Autoconnecting to %s", n->name);
|
||||
outgoing_t *outgoing = xzalloc(sizeof(*outgoing));
|
||||
outgoing->node = n;
|
||||
list_insert_tail(outgoing_list, outgoing);
|
||||
setup_outgoing_connection(outgoing, false);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void drop_superfluous_outgoing_connection() {
|
||||
/* Choose a random outgoing connection to a node that has at least one other connection. */
|
||||
int count = 0;
|
||||
|
||||
for list_each(connection_t, c, connection_list) {
|
||||
if(!c->edge || !c->outgoing || !c->node || c->node->edge_tree->count < 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
if(!count) {
|
||||
return;
|
||||
}
|
||||
|
||||
int r = rand() % count;
|
||||
|
||||
for list_each(connection_t, c, connection_list) {
|
||||
if(!c->edge || !c->outgoing || !c->node || c->node->edge_tree->count < 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(r--) {
|
||||
continue;
|
||||
}
|
||||
|
||||
logger(DEBUG_CONNECTIONS, LOG_INFO, "Autodisconnecting from %s", c->name);
|
||||
list_delete(outgoing_list, c->outgoing);
|
||||
c->outgoing = NULL;
|
||||
terminate_connection(c, c->edge);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void drop_superfluous_pending_connections() {
|
||||
for list_each(outgoing_t, o, outgoing_list) {
|
||||
/* Only look for connections that are waiting to be retried later. */
|
||||
bool found = false;
|
||||
|
||||
for list_each(connection_t, c, connection_list) {
|
||||
if(c->outgoing == o) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(found) {
|
||||
continue;
|
||||
}
|
||||
|
||||
logger(DEBUG_CONNECTIONS, LOG_INFO, "Cancelled outgoing connection to %s", o->node->name);
|
||||
list_delete_node(outgoing_list, node);
|
||||
}
|
||||
}
|
||||
|
||||
void do_autoconnect() {
|
||||
/* Count number of active connections. */
|
||||
int nc = 0;
|
||||
|
||||
for list_each(connection_t, c, connection_list) {
|
||||
if(c->edge) {
|
||||
nc++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Less than 3 connections? Eagerly try to make a new one. */
|
||||
if(nc < 3) {
|
||||
make_new_connection();
|
||||
return;
|
||||
}
|
||||
|
||||
/* More than 3 connections? See if we can get rid of a superfluous one. */
|
||||
if(nc > 3) {
|
||||
drop_superfluous_outgoing_connection();
|
||||
}
|
||||
|
||||
|
||||
/* Check if there are unreachable nodes that we should try to connect to. */
|
||||
connect_to_unreachable();
|
||||
|
||||
/* Drop pending outgoing connections from the outgoing list. */
|
||||
drop_superfluous_pending_connections();
|
||||
}
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
#ifndef TINC_AUTOCONNECT_H
|
||||
#define TINC_AUTOCONNECT_H
|
||||
|
||||
/*
|
||||
autoconnect.h -- header for autoconnect.c
|
||||
Copyright (C) 2017 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
extern void do_autoconnect(void);
|
||||
|
||||
#endif
|
||||
757
src/avl_tree.c
Normal file
757
src/avl_tree.c
Normal file
|
|
@ -0,0 +1,757 @@
|
|||
/*
|
||||
avl_tree.c -- avl_ tree and linked list convenience
|
||||
Copyright (C) 1998 Michael H. Buselli
|
||||
2000-2005 Ivo Timmermans,
|
||||
2000-2015 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2000-2005 Wessel Dankers <wsl@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Original AVL tree library by Michael H. Buselli <cosine@cosine.org>.
|
||||
|
||||
Modified 2000-11-28 by Wessel Dankers <wsl@tinc-vpn.org> to use counts
|
||||
instead of depths, to add the ->next and ->prev and to generally obfuscate
|
||||
the code. Mail me if you found a bug.
|
||||
|
||||
Cleaned up and incorporated some of the ideas from the red-black tree
|
||||
library for inclusion into tinc (https://www.tinc-vpn.org/) by
|
||||
Guus Sliepen <guus@tinc-vpn.org>.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "avl_tree.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
#ifdef AVL_COUNT
|
||||
#define AVL_NODE_COUNT(n) ((n) ? (n)->count : 0)
|
||||
#define AVL_L_COUNT(n) (AVL_NODE_COUNT((n)->left))
|
||||
#define AVL_R_COUNT(n) (AVL_NODE_COUNT((n)->right))
|
||||
#define AVL_CALC_COUNT(n) (AVL_L_COUNT(n) + AVL_R_COUNT(n) + 1)
|
||||
#endif
|
||||
|
||||
#ifdef AVL_DEPTH
|
||||
#define AVL_NODE_DEPTH(n) ((n) ? (n)->depth : 0)
|
||||
#define L_AVL_DEPTH(n) (AVL_NODE_DEPTH((n)->left))
|
||||
#define R_AVL_DEPTH(n) (AVL_NODE_DEPTH((n)->right))
|
||||
#define AVL_CALC_DEPTH(n) ((L_AVL_DEPTH(n)>R_AVL_DEPTH(n)?L_AVL_DEPTH(n):R_AVL_DEPTH(n)) + 1)
|
||||
#endif
|
||||
|
||||
#ifndef AVL_DEPTH
|
||||
static int lg(unsigned int u) __attribute__((__const__));
|
||||
|
||||
static int lg(unsigned int u) {
|
||||
int r = 1;
|
||||
|
||||
if(!u) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(u & 0xffff0000) {
|
||||
u >>= 16;
|
||||
r += 16;
|
||||
}
|
||||
|
||||
if(u & 0x0000ff00) {
|
||||
u >>= 8;
|
||||
r += 8;
|
||||
}
|
||||
|
||||
if(u & 0x000000f0) {
|
||||
u >>= 4;
|
||||
r += 4;
|
||||
}
|
||||
|
||||
if(u & 0x0000000c) {
|
||||
u >>= 2;
|
||||
r += 2;
|
||||
}
|
||||
|
||||
if(u & 0x00000002) {
|
||||
r++;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Internal helper functions */
|
||||
|
||||
static int avl_check_balance(const avl_node_t *node) {
|
||||
#ifdef AVL_DEPTH
|
||||
int d;
|
||||
|
||||
d = R_AVL_DEPTH(node) - L_AVL_DEPTH(node);
|
||||
|
||||
return d < -1 ? -1 : d > 1 ? 1 : 0;
|
||||
#else
|
||||
/* int d;
|
||||
* d = lg(AVL_R_COUNT(node)) - lg(AVL_L_COUNT(node));
|
||||
* d = d<-1?-1:d>1?1:0;
|
||||
*/
|
||||
int pl, r;
|
||||
|
||||
pl = lg(AVL_L_COUNT(node));
|
||||
r = AVL_R_COUNT(node);
|
||||
|
||||
if(r >> pl + 1) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(pl < 2 || r >> pl - 2) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void avl_rebalance(avl_tree_t *tree, avl_node_t *node) {
|
||||
avl_node_t *child;
|
||||
avl_node_t *gchild;
|
||||
avl_node_t *parent;
|
||||
avl_node_t **superparent;
|
||||
|
||||
while(node) {
|
||||
parent = node->parent;
|
||||
|
||||
superparent =
|
||||
parent ? node ==
|
||||
parent->left ? &parent->left : &parent->right : &tree->root;
|
||||
|
||||
switch(avl_check_balance(node)) {
|
||||
case -1:
|
||||
child = node->left;
|
||||
#ifdef AVL_DEPTH
|
||||
|
||||
if(L_AVL_DEPTH(child) >= R_AVL_DEPTH(child)) {
|
||||
#else
|
||||
|
||||
if(AVL_L_COUNT(child) >= AVL_R_COUNT(child)) {
|
||||
#endif
|
||||
node->left = child->right;
|
||||
|
||||
if(node->left) {
|
||||
node->left->parent = node;
|
||||
}
|
||||
|
||||
child->right = node;
|
||||
node->parent = child;
|
||||
*superparent = child;
|
||||
child->parent = parent;
|
||||
#ifdef AVL_COUNT
|
||||
node->count = AVL_CALC_COUNT(node);
|
||||
child->count = AVL_CALC_COUNT(child);
|
||||
#endif
|
||||
#ifdef AVL_DEPTH
|
||||
node->depth = AVL_CALC_DEPTH(node);
|
||||
child->depth = AVL_CALC_DEPTH(child);
|
||||
#endif
|
||||
} else {
|
||||
gchild = child->right;
|
||||
node->left = gchild->right;
|
||||
|
||||
if(node->left) {
|
||||
node->left->parent = node;
|
||||
}
|
||||
|
||||
child->right = gchild->left;
|
||||
|
||||
if(child->right) {
|
||||
child->right->parent = child;
|
||||
}
|
||||
|
||||
gchild->right = node;
|
||||
|
||||
gchild->right->parent = gchild;
|
||||
gchild->left = child;
|
||||
|
||||
gchild->left->parent = gchild;
|
||||
|
||||
*superparent = gchild;
|
||||
gchild->parent = parent;
|
||||
#ifdef AVL_COUNT
|
||||
node->count = AVL_CALC_COUNT(node);
|
||||
child->count = AVL_CALC_COUNT(child);
|
||||
gchild->count = AVL_CALC_COUNT(gchild);
|
||||
#endif
|
||||
#ifdef AVL_DEPTH
|
||||
node->depth = AVL_CALC_DEPTH(node);
|
||||
child->depth = AVL_CALC_DEPTH(child);
|
||||
gchild->depth = AVL_CALC_DEPTH(gchild);
|
||||
#endif
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 1:
|
||||
child = node->right;
|
||||
#ifdef AVL_DEPTH
|
||||
|
||||
if(R_AVL_DEPTH(child) >= L_AVL_DEPTH(child)) {
|
||||
#else
|
||||
|
||||
if(AVL_R_COUNT(child) >= AVL_L_COUNT(child)) {
|
||||
#endif
|
||||
node->right = child->left;
|
||||
|
||||
if(node->right) {
|
||||
node->right->parent = node;
|
||||
}
|
||||
|
||||
child->left = node;
|
||||
node->parent = child;
|
||||
*superparent = child;
|
||||
child->parent = parent;
|
||||
#ifdef AVL_COUNT
|
||||
node->count = AVL_CALC_COUNT(node);
|
||||
child->count = AVL_CALC_COUNT(child);
|
||||
#endif
|
||||
#ifdef AVL_DEPTH
|
||||
node->depth = AVL_CALC_DEPTH(node);
|
||||
child->depth = AVL_CALC_DEPTH(child);
|
||||
#endif
|
||||
} else {
|
||||
gchild = child->left;
|
||||
node->right = gchild->left;
|
||||
|
||||
if(node->right) {
|
||||
node->right->parent = node;
|
||||
}
|
||||
|
||||
child->left = gchild->right;
|
||||
|
||||
if(child->left) {
|
||||
child->left->parent = child;
|
||||
}
|
||||
|
||||
gchild->left = node;
|
||||
|
||||
gchild->left->parent = gchild;
|
||||
gchild->right = child;
|
||||
|
||||
gchild->right->parent = gchild;
|
||||
|
||||
*superparent = gchild;
|
||||
gchild->parent = parent;
|
||||
#ifdef AVL_COUNT
|
||||
node->count = AVL_CALC_COUNT(node);
|
||||
child->count = AVL_CALC_COUNT(child);
|
||||
gchild->count = AVL_CALC_COUNT(gchild);
|
||||
#endif
|
||||
#ifdef AVL_DEPTH
|
||||
node->depth = AVL_CALC_DEPTH(node);
|
||||
child->depth = AVL_CALC_DEPTH(child);
|
||||
gchild->depth = AVL_CALC_DEPTH(gchild);
|
||||
#endif
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
#ifdef AVL_COUNT
|
||||
node->count = AVL_CALC_COUNT(node);
|
||||
#endif
|
||||
#ifdef AVL_DEPTH
|
||||
node->depth = AVL_CALC_DEPTH(node);
|
||||
#endif
|
||||
}
|
||||
|
||||
node = parent;
|
||||
}
|
||||
}
|
||||
|
||||
/* (De)constructors */
|
||||
|
||||
avl_tree_t *avl_alloc_tree(avl_compare_t compare, avl_action_t delete) {
|
||||
avl_tree_t *tree;
|
||||
|
||||
tree = xmalloc_and_zero(sizeof(avl_tree_t));
|
||||
tree->compare = compare;
|
||||
tree->delete = delete;
|
||||
|
||||
return tree;
|
||||
}
|
||||
|
||||
void avl_free_tree(avl_tree_t *tree) {
|
||||
free(tree);
|
||||
}
|
||||
|
||||
avl_node_t *avl_alloc_node(void) {
|
||||
return xmalloc_and_zero(sizeof(avl_node_t));
|
||||
}
|
||||
|
||||
void avl_free_node(avl_tree_t *tree, avl_node_t *node) {
|
||||
if(node->data && tree->delete) {
|
||||
tree->delete(node->data);
|
||||
}
|
||||
|
||||
free(node);
|
||||
}
|
||||
|
||||
/* Searching */
|
||||
|
||||
void *avl_search(const avl_tree_t *tree, const void *data) {
|
||||
avl_node_t *node;
|
||||
|
||||
node = avl_search_node(tree, data);
|
||||
|
||||
return node ? node->data : NULL;
|
||||
}
|
||||
|
||||
void *avl_search_closest(const avl_tree_t *tree, const void *data, int *result) {
|
||||
avl_node_t *node;
|
||||
|
||||
node = avl_search_closest_node(tree, data, result);
|
||||
|
||||
return node ? node->data : NULL;
|
||||
}
|
||||
|
||||
void *avl_search_closest_smaller(const avl_tree_t *tree, const void *data) {
|
||||
avl_node_t *node;
|
||||
|
||||
node = avl_search_closest_smaller_node(tree, data);
|
||||
|
||||
return node ? node->data : NULL;
|
||||
}
|
||||
|
||||
void *avl_search_closest_greater(const avl_tree_t *tree, const void *data) {
|
||||
avl_node_t *node;
|
||||
|
||||
node = avl_search_closest_greater_node(tree, data);
|
||||
|
||||
return node ? node->data : NULL;
|
||||
}
|
||||
|
||||
avl_node_t *avl_search_node(const avl_tree_t *tree, const void *data) {
|
||||
avl_node_t *node;
|
||||
int result;
|
||||
|
||||
node = avl_search_closest_node(tree, data, &result);
|
||||
|
||||
return result ? NULL : node;
|
||||
}
|
||||
|
||||
avl_node_t *avl_search_closest_node(const avl_tree_t *tree, const void *data,
|
||||
int *result) {
|
||||
avl_node_t *node;
|
||||
int c;
|
||||
|
||||
node = tree->root;
|
||||
|
||||
if(!node) {
|
||||
if(result) {
|
||||
*result = 0;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for(;;) {
|
||||
c = tree->compare(data, node->data);
|
||||
|
||||
if(c < 0) {
|
||||
if(node->left) {
|
||||
node = node->left;
|
||||
} else {
|
||||
if(result) {
|
||||
*result = -1;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
} else if(c > 0) {
|
||||
if(node->right) {
|
||||
node = node->right;
|
||||
} else {
|
||||
if(result) {
|
||||
*result = 1;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if(result) {
|
||||
*result = 0;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
avl_node_t *avl_search_closest_smaller_node(const avl_tree_t *tree,
|
||||
const void *data) {
|
||||
avl_node_t *node;
|
||||
int result;
|
||||
|
||||
node = avl_search_closest_node(tree, data, &result);
|
||||
|
||||
if(result < 0) {
|
||||
node = node->prev;
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
avl_node_t *avl_search_closest_greater_node(const avl_tree_t *tree,
|
||||
const void *data) {
|
||||
avl_node_t *node;
|
||||
int result;
|
||||
|
||||
node = avl_search_closest_node(tree, data, &result);
|
||||
|
||||
if(result > 0) {
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/* Insertion and deletion */
|
||||
|
||||
avl_node_t *avl_insert(avl_tree_t *tree, void *data) {
|
||||
avl_node_t *closest, *new;
|
||||
int result;
|
||||
|
||||
if(!tree->root) {
|
||||
new = avl_alloc_node();
|
||||
new->data = data;
|
||||
avl_insert_top(tree, new);
|
||||
} else {
|
||||
closest = avl_search_closest_node(tree, data, &result);
|
||||
|
||||
switch(result) {
|
||||
case -1:
|
||||
new = avl_alloc_node();
|
||||
new->data = data;
|
||||
avl_insert_before(tree, closest, new);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
new = avl_alloc_node();
|
||||
new->data = data;
|
||||
avl_insert_after(tree, closest, new);
|
||||
break;
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef AVL_COUNT
|
||||
new->count = 1;
|
||||
#endif
|
||||
#ifdef AVL_DEPTH
|
||||
new->depth = 1;
|
||||
#endif
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
avl_node_t *avl_insert_node(avl_tree_t *tree, avl_node_t *node) {
|
||||
avl_node_t *closest;
|
||||
int result;
|
||||
|
||||
if(!tree->root) {
|
||||
avl_insert_top(tree, node);
|
||||
} else {
|
||||
closest = avl_search_closest_node(tree, node->data, &result);
|
||||
|
||||
switch(result) {
|
||||
case -1:
|
||||
avl_insert_before(tree, closest, node);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
avl_insert_after(tree, closest, node);
|
||||
break;
|
||||
|
||||
case 0:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef AVL_COUNT
|
||||
node->count = 1;
|
||||
#endif
|
||||
#ifdef AVL_DEPTH
|
||||
node->depth = 1;
|
||||
#endif
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
void avl_insert_top(avl_tree_t *tree, avl_node_t *node) {
|
||||
node->prev = node->next = node->parent = NULL;
|
||||
tree->head = tree->tail = tree->root = node;
|
||||
}
|
||||
|
||||
void avl_insert_before(avl_tree_t *tree, avl_node_t *before,
|
||||
avl_node_t *node) {
|
||||
if(!before) {
|
||||
if(tree->tail) {
|
||||
avl_insert_after(tree, tree->tail, node);
|
||||
} else {
|
||||
avl_insert_top(tree, node);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
node->next = before;
|
||||
node->parent = before;
|
||||
node->prev = before->prev;
|
||||
|
||||
if(before->left) {
|
||||
avl_insert_after(tree, before->prev, node);
|
||||
return;
|
||||
}
|
||||
|
||||
if(before->prev) {
|
||||
before->prev->next = node;
|
||||
} else {
|
||||
tree->head = node;
|
||||
}
|
||||
|
||||
before->prev = node;
|
||||
before->left = node;
|
||||
|
||||
avl_rebalance(tree, before);
|
||||
}
|
||||
|
||||
void avl_insert_after(avl_tree_t *tree, avl_node_t *after, avl_node_t *node) {
|
||||
if(!after) {
|
||||
if(tree->head) {
|
||||
avl_insert_before(tree, tree->head, node);
|
||||
} else {
|
||||
avl_insert_top(tree, node);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(after->right) {
|
||||
avl_insert_before(tree, after->next, node);
|
||||
return;
|
||||
}
|
||||
|
||||
node->prev = after;
|
||||
node->parent = after;
|
||||
node->next = after->next;
|
||||
|
||||
if(after->next) {
|
||||
after->next->prev = node;
|
||||
} else {
|
||||
tree->tail = node;
|
||||
}
|
||||
|
||||
after->next = node;
|
||||
after->right = node;
|
||||
|
||||
avl_rebalance(tree, after);
|
||||
}
|
||||
|
||||
avl_node_t *avl_unlink(avl_tree_t *tree, void *data) {
|
||||
avl_node_t *node;
|
||||
|
||||
node = avl_search_node(tree, data);
|
||||
|
||||
if(node) {
|
||||
avl_unlink_node(tree, node);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
void avl_unlink_node(avl_tree_t *tree, avl_node_t *node) {
|
||||
avl_node_t *parent;
|
||||
avl_node_t **superparent;
|
||||
avl_node_t *subst, *left, *right;
|
||||
avl_node_t *balnode;
|
||||
|
||||
if(node->prev) {
|
||||
node->prev->next = node->next;
|
||||
} else {
|
||||
tree->head = node->next;
|
||||
}
|
||||
|
||||
if(node->next) {
|
||||
node->next->prev = node->prev;
|
||||
} else {
|
||||
tree->tail = node->prev;
|
||||
}
|
||||
|
||||
parent = node->parent;
|
||||
|
||||
superparent =
|
||||
parent ? node ==
|
||||
parent->left ? &parent->left : &parent->right : &tree->root;
|
||||
|
||||
left = node->left;
|
||||
right = node->right;
|
||||
|
||||
if(!left) {
|
||||
*superparent = right;
|
||||
|
||||
if(right) {
|
||||
right->parent = parent;
|
||||
}
|
||||
|
||||
balnode = parent;
|
||||
} else if(!right) {
|
||||
*superparent = left;
|
||||
left->parent = parent;
|
||||
balnode = parent;
|
||||
} else {
|
||||
subst = node->prev;
|
||||
|
||||
if(!subst) { // This only happens if node is not actually in a tree at all.
|
||||
abort();
|
||||
}
|
||||
|
||||
if(subst == left) {
|
||||
balnode = subst;
|
||||
} else {
|
||||
balnode = subst->parent;
|
||||
balnode->right = subst->left;
|
||||
|
||||
if(balnode->right) {
|
||||
balnode->right->parent = balnode;
|
||||
}
|
||||
|
||||
subst->left = left;
|
||||
left->parent = subst;
|
||||
}
|
||||
|
||||
subst->right = right;
|
||||
subst->parent = parent;
|
||||
right->parent = subst;
|
||||
*superparent = subst;
|
||||
}
|
||||
|
||||
avl_rebalance(tree, balnode);
|
||||
|
||||
node->next = node->prev = node->parent = node->left = node->right = NULL;
|
||||
|
||||
#ifdef AVL_COUNT
|
||||
node->count = 0;
|
||||
#endif
|
||||
#ifdef AVL_DEPTH
|
||||
node->depth = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void avl_delete_node(avl_tree_t *tree, avl_node_t *node) {
|
||||
avl_unlink_node(tree, node);
|
||||
avl_free_node(tree, node);
|
||||
}
|
||||
|
||||
void avl_delete(avl_tree_t *tree, void *data) {
|
||||
avl_node_t *node;
|
||||
|
||||
node = avl_search_node(tree, data);
|
||||
|
||||
if(node) {
|
||||
avl_delete_node(tree, node);
|
||||
}
|
||||
}
|
||||
|
||||
/* Fast tree cleanup */
|
||||
|
||||
void avl_delete_tree(avl_tree_t *tree) {
|
||||
avl_node_t *node, *next;
|
||||
|
||||
for(node = tree->head; node; node = next) {
|
||||
next = node->next;
|
||||
avl_free_node(tree, node);
|
||||
}
|
||||
|
||||
avl_free_tree(tree);
|
||||
}
|
||||
|
||||
/* Tree walking */
|
||||
|
||||
void avl_foreach(const avl_tree_t *tree, avl_action_t action) {
|
||||
avl_node_t *node, *next;
|
||||
|
||||
for(node = tree->head; node; node = next) {
|
||||
next = node->next;
|
||||
action(node->data);
|
||||
}
|
||||
}
|
||||
|
||||
void avl_foreach_node(const avl_tree_t *tree, avl_action_t action) {
|
||||
avl_node_t *node, *next;
|
||||
|
||||
for(node = tree->head; node; node = next) {
|
||||
next = node->next;
|
||||
action(node);
|
||||
}
|
||||
}
|
||||
|
||||
/* Indexing */
|
||||
|
||||
#ifdef AVL_COUNT
|
||||
unsigned int avl_count(const avl_tree_t *tree) {
|
||||
return AVL_NODE_COUNT(tree->root);
|
||||
}
|
||||
|
||||
avl_node_t *avl_get_node(const avl_tree_t *tree, unsigned int index) {
|
||||
avl_node_t *node;
|
||||
unsigned int c;
|
||||
|
||||
node = tree->root;
|
||||
|
||||
while(node) {
|
||||
c = AVL_L_COUNT(node);
|
||||
|
||||
if(index < c) {
|
||||
node = node->left;
|
||||
} else if(index > c) {
|
||||
node = node->right;
|
||||
index -= c + 1;
|
||||
} else {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned int avl_index(const avl_node_t *node) {
|
||||
avl_node_t *next;
|
||||
unsigned int index;
|
||||
|
||||
index = AVL_L_COUNT(node);
|
||||
|
||||
while((next = node->parent)) {
|
||||
if(node == next->right) {
|
||||
index += AVL_L_COUNT(next) + 1;
|
||||
}
|
||||
|
||||
node = next;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
#endif
|
||||
#ifdef AVL_DEPTH
|
||||
unsigned int avl_depth(const avl_tree_t *tree) {
|
||||
return AVL_NODE_DEPTH(tree->root);
|
||||
}
|
||||
#endif
|
||||
142
src/avl_tree.h
Normal file
142
src/avl_tree.h
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
#ifndef TINC_AVL_TREE_H
|
||||
#define TINC_AVL_TREE_H
|
||||
|
||||
/*
|
||||
avl_tree.h -- header file for avl_tree.c
|
||||
Copyright (C) 1998 Michael H. Buselli
|
||||
2000-2005 Ivo Timmermans,
|
||||
2000-2006 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2000-2005 Wessel Dankers <wsl@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Original AVL tree library by Michael H. Buselli <cosine@cosine.org>.
|
||||
|
||||
Modified 2000-11-28 by Wessel Dankers <wsl@tinc-vpn.org> to use counts
|
||||
instead of depths, to add the ->next and ->prev and to generally obfuscate
|
||||
the code. Mail me if you found a bug.
|
||||
|
||||
Cleaned up and incorporated some of the ideas from the red-black tree
|
||||
library for inclusion into tinc (https://www.tinc-vpn.org/) by
|
||||
Guus Sliepen <guus@tinc-vpn.org>.
|
||||
*/
|
||||
|
||||
#ifndef AVL_DEPTH
|
||||
#ifndef AVL_COUNT
|
||||
#define AVL_DEPTH
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef struct avl_node_t {
|
||||
|
||||
/* Linked list part */
|
||||
|
||||
struct avl_node_t *next;
|
||||
struct avl_node_t *prev;
|
||||
|
||||
/* Tree part */
|
||||
|
||||
struct avl_node_t *parent;
|
||||
struct avl_node_t *left;
|
||||
struct avl_node_t *right;
|
||||
|
||||
#ifdef AVL_COUNT
|
||||
unsigned int count;
|
||||
#endif
|
||||
#ifdef AVL_DEPTH
|
||||
unsigned char depth;
|
||||
#endif
|
||||
|
||||
/* Payload */
|
||||
|
||||
void *data;
|
||||
|
||||
} avl_node_t;
|
||||
|
||||
typedef int (*avl_compare_t)(const void *data1, const void *data2);
|
||||
typedef void (*avl_action_t)(const void *data);
|
||||
typedef void (*avl_action_node_t)(const avl_node_t *node);
|
||||
|
||||
typedef struct avl_tree_t {
|
||||
|
||||
/* Linked list part */
|
||||
|
||||
avl_node_t *head;
|
||||
avl_node_t *tail;
|
||||
|
||||
/* Tree part */
|
||||
|
||||
avl_node_t *root;
|
||||
|
||||
avl_compare_t compare;
|
||||
avl_action_t delete;
|
||||
|
||||
} avl_tree_t;
|
||||
|
||||
/* (De)constructors */
|
||||
|
||||
extern avl_tree_t *avl_alloc_tree(avl_compare_t compare, avl_action_t delete);
|
||||
extern void avl_free_tree(avl_tree_t *tree);
|
||||
|
||||
extern avl_node_t *avl_alloc_node(void);
|
||||
extern void avl_free_node(avl_tree_t *tree, avl_node_t *node);
|
||||
|
||||
/* Insertion and deletion */
|
||||
|
||||
extern avl_node_t *avl_insert(avl_tree_t *tree, void *data);
|
||||
extern avl_node_t *avl_insert_node(avl_tree_t *tree, avl_node_t *node);
|
||||
|
||||
extern void avl_insert_top(avl_tree_t *tree, avl_node_t *node);
|
||||
extern void avl_insert_before(avl_tree_t *tree, avl_node_t *before, avl_node_t *node);
|
||||
extern void avl_insert_after(avl_tree_t *tree, avl_node_t *after, avl_node_t *node);
|
||||
|
||||
extern avl_node_t *avl_unlink(avl_tree_t *tree, void *data);
|
||||
extern void avl_unlink_node(avl_tree_t *tree, avl_node_t *node);
|
||||
extern void avl_delete(avl_tree_t *tree, void *data);
|
||||
extern void avl_delete_node(avl_tree_t *tree, avl_node_t *node);
|
||||
|
||||
/* Fast tree cleanup */
|
||||
|
||||
extern void avl_delete_tree(avl_tree_t *tree);
|
||||
|
||||
/* Searching */
|
||||
|
||||
extern void *avl_search(const avl_tree_t *tree, const void *data);
|
||||
extern void *avl_search_closest(const avl_tree_t *tree, const void *data, int *result);
|
||||
extern void *avl_search_closest_smaller(const avl_tree_t *tree, const void *data);
|
||||
extern void *avl_search_closest_greater(const avl_tree_t *tree, const void *data);
|
||||
|
||||
extern avl_node_t *avl_search_node(const avl_tree_t *tree, const void *data);
|
||||
extern avl_node_t *avl_search_closest_node(const avl_tree_t *tree, const void *data, int *result);
|
||||
extern avl_node_t *avl_search_closest_smaller_node(const avl_tree_t *tree, const void *data);
|
||||
extern avl_node_t *avl_search_closest_greater_node(const avl_tree_t *tree, const void *data);
|
||||
|
||||
/* Tree walking */
|
||||
|
||||
extern void avl_foreach(const avl_tree_t *tree, avl_action_t action);
|
||||
extern void avl_foreach_node(const avl_tree_t *tree, avl_action_t action);
|
||||
|
||||
/* Indexing */
|
||||
|
||||
#ifdef AVL_COUNT
|
||||
extern unsigned int avl_count(const avl_tree_t *tree);
|
||||
extern avl_node_t *avl_get_node(const avl_tree_t *tree, unsigned int index);
|
||||
extern unsigned int avl_index(const avl_node_t *node);
|
||||
#endif
|
||||
#ifdef AVL_DEPTH
|
||||
extern unsigned int avl_depth(const avl_tree_t *tree);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
168
src/bsd/device.c
168
src/bsd/device.c
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
device.c -- Interaction BSD tun/tap device
|
||||
Copyright (C) 2001-2005 Ivo Timmermans,
|
||||
2001-2017 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2001-2016 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2009 Grzegorz Dymarek <gregd72002@googlemail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
|
|
@ -24,14 +24,13 @@
|
|||
#include "../conf.h"
|
||||
#include "../device.h"
|
||||
#include "../logger.h"
|
||||
#include "../names.h"
|
||||
#include "../net.h"
|
||||
#include "../route.h"
|
||||
#include "../utils.h"
|
||||
#include "../xalloc.h"
|
||||
|
||||
#ifdef ENABLE_TUNEMU
|
||||
#include "bsd/tunemu.h"
|
||||
#include "tunemu.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NET_IF_UTUN_H
|
||||
|
|
@ -57,6 +56,8 @@ int device_fd = -1;
|
|||
char *device = NULL;
|
||||
char *iface = NULL;
|
||||
static const char *device_info = "OS X utun device";
|
||||
static uint64_t device_total_in = 0;
|
||||
static uint64_t device_total_out = 0;
|
||||
#if defined(ENABLE_TUNEMU)
|
||||
static device_type_t device_type = DEVICE_TYPE_TUNEMU;
|
||||
#elif defined(HAVE_OPENBSD) || defined(HAVE_FREEBSD) || defined(HAVE_DRAGONFLY)
|
||||
|
|
@ -70,7 +71,7 @@ static bool setup_utun(void) {
|
|||
device_fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
|
||||
|
||||
if(device_fd == -1) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not open PF_SYSTEM socket: %s\n", strerror(errno));
|
||||
logger(LOG_ERR, "Could not open PF_SYSTEM socket: %s\n", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -79,7 +80,7 @@ static bool setup_utun(void) {
|
|||
strlcpy(info.ctl_name, UTUN_CONTROL_NAME, sizeof(info.ctl_name));
|
||||
|
||||
if(ioctl(device_fd, CTLIOCGINFO, &info) == -1) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "ioctl(CTLIOCGINFO) failed: %s", strerror(errno));
|
||||
logger(LOG_ERR, "ioctl(CTLIOCGINFO) failed: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -103,7 +104,7 @@ static bool setup_utun(void) {
|
|||
};
|
||||
|
||||
if(connect(device_fd, (struct sockaddr *)&sc, sizeof(sc)) == -1) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not connect utun socket: %s\n", strerror(errno));
|
||||
logger(LOG_ERR, "Could not connect utun socket: %s\n", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -116,14 +117,22 @@ static bool setup_utun(void) {
|
|||
iface = xstrdup(name);
|
||||
}
|
||||
|
||||
logger(DEBUG_ALWAYS, LOG_INFO, "%s is a %s", device, device_info);
|
||||
logger(LOG_INFO, "%s is a %s", device, device_info);
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool setup_device(void) {
|
||||
get_config_string(lookup_config(config_tree, "Device"), &device);
|
||||
// Find out which device file to open
|
||||
|
||||
if(!get_config_string(lookup_config(config_tree, "Device"), &device)) {
|
||||
if(routing_mode == RMODE_ROUTER) {
|
||||
device = xstrdup(DEFAULT_TUN_DEVICE);
|
||||
} else {
|
||||
device = xstrdup(DEFAULT_TAP_DEVICE);
|
||||
}
|
||||
}
|
||||
|
||||
// Find out if it's supposed to be a tun or a tap device
|
||||
|
||||
|
|
@ -152,36 +161,26 @@ static bool setup_device(void) {
|
|||
} else if(!strcasecmp(type, "tap")) {
|
||||
device_type = DEVICE_TYPE_TAP;
|
||||
} else {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unknown device type %s!", type);
|
||||
logger(LOG_ERR, "Unknown device type %s!", type);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
#ifdef HAVE_NET_IF_UTUN_H
|
||||
|
||||
if(device && (strncmp(device, "utun", 4) == 0 || strncmp(device, "/dev/utun", 9) == 0)) {
|
||||
if(strncmp(device, "utun", 4) == 0 || strncmp(device, "/dev/utun", 9) == 0) {
|
||||
device_type = DEVICE_TYPE_UTUN;
|
||||
} else
|
||||
#endif
|
||||
if((device && strstr(device, "tap")) || routing_mode != RMODE_ROUTER) {
|
||||
if(strstr(device, "tap") || routing_mode != RMODE_ROUTER) {
|
||||
device_type = DEVICE_TYPE_TAP;
|
||||
}
|
||||
}
|
||||
|
||||
if(routing_mode == RMODE_SWITCH && device_type != DEVICE_TYPE_TAP) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Only tap devices support switch mode!");
|
||||
logger(LOG_ERR, "Only tap devices support switch mode!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Find out which device file to open
|
||||
|
||||
if(!device) {
|
||||
if(device_type == DEVICE_TYPE_TAP) {
|
||||
device = xstrdup(DEFAULT_TAP_DEVICE);
|
||||
} else {
|
||||
device = xstrdup(DEFAULT_TUN_DEVICE);
|
||||
}
|
||||
}
|
||||
|
||||
// Open the device
|
||||
|
||||
switch(device_type) {
|
||||
|
|
@ -204,7 +203,7 @@ static bool setup_device(void) {
|
|||
}
|
||||
|
||||
if(device_fd < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not open %s: %s", device, strerror(errno));
|
||||
logger(LOG_ERR, "Could not open %s: %s", device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -234,7 +233,7 @@ static bool setup_device(void) {
|
|||
if(!get_config_string(lookup_config(config_tree, "Interface"), &iface)) {
|
||||
iface = xstrdup(strrchr(realname, '/') ? strrchr(realname, '/') + 1 : realname);
|
||||
} else if(strcmp(iface, strrchr(realname, '/') ? strrchr(realname, '/') + 1 : realname)) {
|
||||
logger(DEBUG_ALWAYS, LOG_WARNING, "Warning: Interface does not match Device. $INTERFACE might be set incorrectly.");
|
||||
logger(LOG_WARNING, "Warning: Interface does not match Device. $INTERFACE might be set incorrectly.");
|
||||
}
|
||||
|
||||
// Configure the device as best as we can
|
||||
|
|
@ -249,7 +248,7 @@ static bool setup_device(void) {
|
|||
const int zero = 0;
|
||||
|
||||
if(ioctl(device_fd, TUNSIFHEAD, &zero, sizeof(zero)) == -1) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "ioctl", strerror(errno));
|
||||
logger(LOG_ERR, "System call `%s' failed: %s", "ioctl", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -271,7 +270,7 @@ static bool setup_device(void) {
|
|||
const int one = 1;
|
||||
|
||||
if(ioctl(device_fd, TUNSIFHEAD, &one, sizeof(one)) == -1) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "ioctl", strerror(errno));
|
||||
logger(LOG_ERR, "System call `%s' failed: %s", "ioctl", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -298,7 +297,10 @@ static bool setup_device(void) {
|
|||
struct ifreq ifr;
|
||||
|
||||
if(ioctl(device_fd, TAPGIFNAME, (void *)&ifr) == 0) {
|
||||
free(iface);
|
||||
if(iface) {
|
||||
free(iface);
|
||||
}
|
||||
|
||||
iface = xstrdup(ifr.ifr_name);
|
||||
}
|
||||
}
|
||||
|
|
@ -321,7 +323,7 @@ static bool setup_device(void) {
|
|||
|
||||
#endif
|
||||
|
||||
logger(DEBUG_ALWAYS, LOG_INFO, "%s is a %s", device, device_info);
|
||||
logger(LOG_INFO, "%s is a %s", device, device_info);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -339,115 +341,112 @@ static void close_device(void) {
|
|||
close(device_fd);
|
||||
}
|
||||
|
||||
device_fd = -1;
|
||||
|
||||
free(device);
|
||||
device = NULL;
|
||||
free(iface);
|
||||
iface = NULL;
|
||||
device_info = NULL;
|
||||
}
|
||||
|
||||
static bool read_packet(vpn_packet_t *packet) {
|
||||
int inlen;
|
||||
int lenin;
|
||||
|
||||
switch(device_type) {
|
||||
case DEVICE_TYPE_TUN:
|
||||
#ifdef ENABLE_TUNEMU
|
||||
case DEVICE_TYPE_TUNEMU:
|
||||
if(device_type == DEVICE_TYPE_TUNEMU) {
|
||||
inlen = tunemu_read(device_fd, DATA(packet) + 14, MTU - 14);
|
||||
lenin = tunemu_read(device_fd, packet->data + 14, MTU - 14);
|
||||
} else
|
||||
#endif
|
||||
inlen = read(device_fd, DATA(packet) + 14, MTU - 14);
|
||||
lenin = read(device_fd, packet->data + 14, MTU - 14);
|
||||
|
||||
if(inlen <= 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
||||
if(lenin <= 0) {
|
||||
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
||||
device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
switch(DATA(packet)[14] >> 4) {
|
||||
switch(packet->data[14] >> 4) {
|
||||
case 4:
|
||||
DATA(packet)[12] = 0x08;
|
||||
DATA(packet)[13] = 0x00;
|
||||
packet->data[12] = 0x08;
|
||||
packet->data[13] = 0x00;
|
||||
break;
|
||||
|
||||
case 6:
|
||||
DATA(packet)[12] = 0x86;
|
||||
DATA(packet)[13] = 0xDD;
|
||||
packet->data[12] = 0x86;
|
||||
packet->data[13] = 0xDD;
|
||||
break;
|
||||
|
||||
default:
|
||||
logger(DEBUG_TRAFFIC, LOG_ERR,
|
||||
"Unknown IP version %d while reading packet from %s %s",
|
||||
DATA(packet)[14] >> 4, device_info, device);
|
||||
ifdebug(TRAFFIC) logger(LOG_ERR,
|
||||
"Unknown IP version %d while reading packet from %s %s",
|
||||
packet->data[14] >> 4, device_info, device);
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(DATA(packet), 0, 12);
|
||||
packet->len = inlen + 14;
|
||||
memset(packet->data, 0, 12);
|
||||
packet->len = lenin + 14;
|
||||
break;
|
||||
|
||||
case DEVICE_TYPE_UTUN:
|
||||
case DEVICE_TYPE_TUNIFHEAD: {
|
||||
if((inlen = read(device_fd, DATA(packet) + 10, MTU - 10)) <= 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
||||
if((lenin = read(device_fd, packet->data + 10, MTU - 10)) <= 0) {
|
||||
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
||||
device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
switch(DATA(packet)[14] >> 4) {
|
||||
switch(packet->data[14] >> 4) {
|
||||
case 4:
|
||||
DATA(packet)[12] = 0x08;
|
||||
DATA(packet)[13] = 0x00;
|
||||
packet->data[12] = 0x08;
|
||||
packet->data[13] = 0x00;
|
||||
break;
|
||||
|
||||
case 6:
|
||||
DATA(packet)[12] = 0x86;
|
||||
DATA(packet)[13] = 0xDD;
|
||||
packet->data[12] = 0x86;
|
||||
packet->data[13] = 0xDD;
|
||||
break;
|
||||
|
||||
default:
|
||||
logger(DEBUG_TRAFFIC, LOG_ERR,
|
||||
"Unknown IP version %d while reading packet from %s %s",
|
||||
DATA(packet)[14] >> 4, device_info, device);
|
||||
ifdebug(TRAFFIC) logger(LOG_ERR,
|
||||
"Unknown IP version %d while reading packet from %s %s",
|
||||
packet->data[14] >> 4, device_info, device);
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(DATA(packet), 0, 12);
|
||||
packet->len = inlen + 10;
|
||||
memset(packet->data, 0, 12);
|
||||
packet->len = lenin + 10;
|
||||
break;
|
||||
}
|
||||
|
||||
case DEVICE_TYPE_TAP:
|
||||
if((inlen = read(device_fd, DATA(packet), MTU)) <= 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
||||
if((lenin = read(device_fd, packet->data, MTU)) <= 0) {
|
||||
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
||||
device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
packet->len = inlen;
|
||||
packet->len = lenin;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Read packet of %d bytes from %s",
|
||||
packet->len, device_info);
|
||||
device_total_in += packet->len;
|
||||
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s",
|
||||
packet->len, device_info);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool write_packet(vpn_packet_t *packet) {
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Writing packet of %d bytes to %s",
|
||||
packet->len, device_info);
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
|
||||
packet->len, device_info);
|
||||
|
||||
switch(device_type) {
|
||||
case DEVICE_TYPE_TUN:
|
||||
if(write(device_fd, DATA(packet) + 14, packet->len - 14) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while writing to %s %s: %s", device_info,
|
||||
if(write(device_fd, packet->data + 14, packet->len - 14) < 0) {
|
||||
logger(LOG_ERR, "Error while writing to %s %s: %s", device_info,
|
||||
device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
|
@ -456,7 +455,7 @@ static bool write_packet(vpn_packet_t *packet) {
|
|||
|
||||
case DEVICE_TYPE_UTUN:
|
||||
case DEVICE_TYPE_TUNIFHEAD: {
|
||||
int af = (DATA(packet)[12] << 8) + DATA(packet)[13];
|
||||
int af = (packet->data[12] << 8) + packet->data[13];
|
||||
uint32_t type;
|
||||
|
||||
switch(af) {
|
||||
|
|
@ -469,16 +468,16 @@ static bool write_packet(vpn_packet_t *packet) {
|
|||
break;
|
||||
|
||||
default:
|
||||
logger(DEBUG_TRAFFIC, LOG_ERR,
|
||||
"Unknown address family %x while writing packet to %s %s",
|
||||
af, device_info, device);
|
||||
ifdebug(TRAFFIC) logger(LOG_ERR,
|
||||
"Unknown address family %x while writing packet to %s %s",
|
||||
af, device_info, device);
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(DATA(packet) + 10, &type, sizeof(type));
|
||||
memcpy(packet->data + 10, &type, sizeof(type));
|
||||
|
||||
if(write(device_fd, DATA(packet) + 10, packet->len - 10) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Can't write to %s %s: %s", device_info, device,
|
||||
if(write(device_fd, packet->data + 10, packet->len - 10) < 0) {
|
||||
logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device,
|
||||
strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
|
@ -487,8 +486,8 @@ static bool write_packet(vpn_packet_t *packet) {
|
|||
}
|
||||
|
||||
case DEVICE_TYPE_TAP:
|
||||
if(write(device_fd, DATA(packet), packet->len) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while writing to %s %s: %s", device_info,
|
||||
if(write(device_fd, packet->data, packet->len) < 0) {
|
||||
logger(LOG_ERR, "Error while writing to %s %s: %s", device_info,
|
||||
device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
|
@ -498,8 +497,8 @@ static bool write_packet(vpn_packet_t *packet) {
|
|||
#ifdef ENABLE_TUNEMU
|
||||
|
||||
case DEVICE_TYPE_TUNEMU:
|
||||
if(tunemu_write(device_fd, DATA(packet) + 14, packet->len - 14) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while writing to %s %s: %s", device_info,
|
||||
if(tunemu_write(device_fd, packet->data + 14, packet->len - 14) < 0) {
|
||||
logger(LOG_ERR, "Error while writing to %s %s: %s", device_info,
|
||||
device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
|
@ -511,12 +510,21 @@ static bool write_packet(vpn_packet_t *packet) {
|
|||
return false;
|
||||
}
|
||||
|
||||
device_total_out += packet->len;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void dump_device_stats(void) {
|
||||
logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
|
||||
logger(LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in);
|
||||
logger(LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
|
||||
}
|
||||
|
||||
const devops_t os_devops = {
|
||||
.setup = setup_device,
|
||||
.close = close_device,
|
||||
.read = read_packet,
|
||||
.write = write_packet,
|
||||
.dump_stats = dump_device_stats,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -45,9 +45,9 @@
|
|||
#define PPPIOCSFLAGS _IOW('t', 89, int)
|
||||
#define PPPIOCSNPMODE _IOW('t', 75, struct npioctl)
|
||||
#define PPPIOCATTCHAN _IOW('t', 56, int)
|
||||
#define PPPIOCGCHAN _IOR('t', 55, int)
|
||||
#define PPPIOCGCHAN _IOR('t', 55, int)
|
||||
#define PPPIOCCONNECT _IOW('t', 58, int)
|
||||
#define PPPIOCGUNIT _IOR('t', 86, int)
|
||||
#define PPPIOCGUNIT _IOR('t', 86, int)
|
||||
|
||||
struct sockaddr_ppp {
|
||||
u_int8_t ppp_len;
|
||||
|
|
@ -83,7 +83,7 @@ static char *data_buffer = NULL;
|
|||
static void tun_error(char *format, ...) {
|
||||
va_list vl;
|
||||
va_start(vl, format);
|
||||
vsnprintf(tunemu_error, sizeof(tunemu_error), format, vl);
|
||||
vsnprintf(tunemu_error, ERROR_BUFFER_SIZE, format, vl);
|
||||
va_end(vl);
|
||||
}
|
||||
|
||||
|
|
|
|||
110
src/buffer.c
110
src/buffer.c
|
|
@ -1,110 +0,0 @@
|
|||
/*
|
||||
buffer.c -- buffer management
|
||||
Copyright (C) 2011 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "buffer.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
void buffer_compact(buffer_t *buffer, uint32_t maxsize) {
|
||||
if(buffer->len >= maxsize || buffer->offset / 7 > buffer->len / 8) {
|
||||
memmove(buffer->data, buffer->data + buffer->offset, buffer->len - buffer->offset);
|
||||
buffer->len -= buffer->offset;
|
||||
buffer->offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure we can add size bytes to the buffer, and return a pointer to the start of those bytes.
|
||||
|
||||
char *buffer_prepare(buffer_t *buffer, uint32_t size) {
|
||||
if(!buffer->data) {
|
||||
buffer->maxlen = size;
|
||||
buffer->data = xmalloc(size);
|
||||
} else {
|
||||
if(buffer->offset && buffer->len + size > buffer->maxlen) {
|
||||
memmove(buffer->data, buffer->data + buffer->offset, buffer->len - buffer->offset);
|
||||
buffer->len -= buffer->offset;
|
||||
buffer->offset = 0;
|
||||
}
|
||||
|
||||
if(buffer->len + size > buffer->maxlen) {
|
||||
buffer->maxlen = buffer->len + size;
|
||||
buffer->data = xrealloc(buffer->data, buffer->maxlen);
|
||||
}
|
||||
}
|
||||
|
||||
char *start = buffer->data + buffer->len;
|
||||
|
||||
buffer->len += size;
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
// Copy data into the buffer.
|
||||
|
||||
void buffer_add(buffer_t *buffer, const char *data, uint32_t size) {
|
||||
memcpy(buffer_prepare(buffer, size), data, size);
|
||||
}
|
||||
|
||||
// Remove given number of bytes from the buffer, return a pointer to the start of them.
|
||||
|
||||
static char *buffer_consume(buffer_t *buffer, uint32_t size) {
|
||||
char *start = buffer->data + buffer->offset;
|
||||
|
||||
buffer->offset += size;
|
||||
|
||||
if(buffer->offset >= buffer->len) {
|
||||
buffer->offset = 0;
|
||||
buffer->len = 0;
|
||||
}
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
// Check if there is a complete line in the buffer, and if so, return it NULL-terminated.
|
||||
|
||||
char *buffer_readline(buffer_t *buffer) {
|
||||
char *newline = memchr(buffer->data + buffer->offset, '\n', buffer->len - buffer->offset);
|
||||
|
||||
if(!newline) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint32_t len = newline + 1 - (buffer->data + buffer->offset);
|
||||
*newline = 0;
|
||||
return buffer_consume(buffer, len);
|
||||
}
|
||||
|
||||
// Check if we have enough bytes in the buffer, and if so, return a pointer to the start of them.
|
||||
|
||||
char *buffer_read(buffer_t *buffer, uint32_t size) {
|
||||
if(buffer->len - buffer->offset < size) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return buffer_consume(buffer, size);
|
||||
}
|
||||
|
||||
void buffer_clear(buffer_t *buffer) {
|
||||
free(buffer->data);
|
||||
buffer->data = NULL;
|
||||
buffer->maxlen = 0;
|
||||
buffer->len = 0;
|
||||
buffer->offset = 0;
|
||||
}
|
||||
18
src/buffer.h
18
src/buffer.h
|
|
@ -1,18 +0,0 @@
|
|||
#ifndef TINC_BUFFER_H
|
||||
#define TINC_BUFFER_H
|
||||
|
||||
typedef struct buffer_t {
|
||||
char *data;
|
||||
uint32_t maxlen;
|
||||
uint32_t len;
|
||||
uint32_t offset;
|
||||
} buffer_t;
|
||||
|
||||
extern void buffer_compact(buffer_t *buffer, uint32_t maxsize);
|
||||
extern char *buffer_prepare(buffer_t *buffer, uint32_t size);
|
||||
extern void buffer_add(buffer_t *buffer, const char *data, uint32_t size);
|
||||
extern char *buffer_readline(buffer_t *buffer);
|
||||
extern char *buffer_read(buffer_t *buffer, uint32_t size);
|
||||
extern void buffer_clear(buffer_t *buffer);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,106 +0,0 @@
|
|||
#include "../system.h"
|
||||
|
||||
#include "../cipher.h"
|
||||
#include "../xalloc.h"
|
||||
|
||||
#include "chacha.h"
|
||||
#include "chacha-poly1305.h"
|
||||
#include "poly1305.h"
|
||||
|
||||
struct chacha_poly1305_ctx {
|
||||
struct chacha_ctx main_ctx, header_ctx;
|
||||
};
|
||||
|
||||
chacha_poly1305_ctx_t *chacha_poly1305_init(void) {
|
||||
chacha_poly1305_ctx_t *ctx = xzalloc(sizeof(*ctx));
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void chacha_poly1305_exit(chacha_poly1305_ctx_t *ctx) {
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
bool chacha_poly1305_set_key(chacha_poly1305_ctx_t *ctx, const void *vkey) {
|
||||
const uint8_t *key = vkey;
|
||||
chacha_keysetup(&ctx->main_ctx, key, 256);
|
||||
chacha_keysetup(&ctx->header_ctx, key + 32, 256);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void put_u64(void *vp, uint64_t v) {
|
||||
uint8_t *p = (uint8_t *) vp;
|
||||
|
||||
p[0] = (uint8_t)(v >> 56) & 0xff;
|
||||
p[1] = (uint8_t)(v >> 48) & 0xff;
|
||||
p[2] = (uint8_t)(v >> 40) & 0xff;
|
||||
p[3] = (uint8_t)(v >> 32) & 0xff;
|
||||
p[4] = (uint8_t)(v >> 24) & 0xff;
|
||||
p[5] = (uint8_t)(v >> 16) & 0xff;
|
||||
p[6] = (uint8_t)(v >> 8) & 0xff;
|
||||
p[7] = (uint8_t) v & 0xff;
|
||||
}
|
||||
|
||||
bool chacha_poly1305_encrypt(chacha_poly1305_ctx_t *ctx, uint64_t seqnr, const void *indata, size_t inlen, void *voutdata, size_t *outlen) {
|
||||
uint8_t seqbuf[8];
|
||||
const uint8_t one[8] = { 1, 0, 0, 0, 0, 0, 0, 0 }; /* NB little-endian */
|
||||
uint8_t poly_key[POLY1305_KEYLEN];
|
||||
uint8_t *outdata = voutdata;
|
||||
|
||||
/*
|
||||
* Run ChaCha20 once to generate the Poly1305 key. The IV is the
|
||||
* packet sequence number.
|
||||
*/
|
||||
memset(poly_key, 0, sizeof(poly_key));
|
||||
put_u64(seqbuf, seqnr);
|
||||
chacha_ivsetup(&ctx->main_ctx, seqbuf, NULL);
|
||||
chacha_encrypt_bytes(&ctx->main_ctx, poly_key, poly_key, sizeof(poly_key));
|
||||
|
||||
/* Set Chacha's block counter to 1 */
|
||||
chacha_ivsetup(&ctx->main_ctx, seqbuf, one);
|
||||
|
||||
chacha_encrypt_bytes(&ctx->main_ctx, indata, outdata, inlen);
|
||||
poly1305_auth(outdata + inlen, outdata, inlen, poly_key);
|
||||
|
||||
if(outlen) {
|
||||
*outlen = inlen + POLY1305_TAGLEN;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool chacha_poly1305_decrypt(chacha_poly1305_ctx_t *ctx, uint64_t seqnr, const void *vindata, size_t inlen, void *outdata, size_t *outlen) {
|
||||
uint8_t seqbuf[8];
|
||||
const uint8_t one[8] = { 1, 0, 0, 0, 0, 0, 0, 0 }; /* NB little-endian */
|
||||
uint8_t expected_tag[POLY1305_TAGLEN], poly_key[POLY1305_KEYLEN];
|
||||
const uint8_t *indata = vindata;
|
||||
|
||||
/*
|
||||
* Run ChaCha20 once to generate the Poly1305 key. The IV is the
|
||||
* packet sequence number.
|
||||
*/
|
||||
memset(poly_key, 0, sizeof(poly_key));
|
||||
put_u64(seqbuf, seqnr);
|
||||
chacha_ivsetup(&ctx->main_ctx, seqbuf, NULL);
|
||||
chacha_encrypt_bytes(&ctx->main_ctx, poly_key, poly_key, sizeof(poly_key));
|
||||
|
||||
/* Set Chacha's block counter to 1 */
|
||||
chacha_ivsetup(&ctx->main_ctx, seqbuf, one);
|
||||
|
||||
/* Check tag before anything else */
|
||||
inlen -= POLY1305_TAGLEN;
|
||||
const uint8_t *tag = indata + inlen;
|
||||
|
||||
poly1305_auth(expected_tag, indata, inlen, poly_key);
|
||||
|
||||
if(memcmp(expected_tag, tag, POLY1305_TAGLEN)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
chacha_encrypt_bytes(&ctx->main_ctx, indata, outdata, inlen);
|
||||
|
||||
if(outlen) {
|
||||
*outlen = inlen;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
#ifndef CHACHA_POLY1305_H
|
||||
#define CHACHA_POLY1305_H
|
||||
|
||||
#define CHACHA_POLY1305_KEYLEN 64
|
||||
|
||||
typedef struct chacha_poly1305_ctx chacha_poly1305_ctx_t;
|
||||
|
||||
extern chacha_poly1305_ctx_t *chacha_poly1305_init(void);
|
||||
extern void chacha_poly1305_exit(chacha_poly1305_ctx_t *);
|
||||
extern bool chacha_poly1305_set_key(chacha_poly1305_ctx_t *ctx, const void *key);
|
||||
|
||||
extern bool chacha_poly1305_encrypt(chacha_poly1305_ctx_t *ctx, uint64_t seqnr, const void *indata, size_t inlen, void *outdata, size_t *outlen);
|
||||
extern bool chacha_poly1305_decrypt(chacha_poly1305_ctx_t *ctx, uint64_t seqnr, const void *indata, size_t inlen, void *outdata, size_t *outlen);
|
||||
|
||||
#endif //CHACHA_POLY1305_H
|
||||
|
|
@ -1,224 +0,0 @@
|
|||
/*
|
||||
chacha-merged.c version 20080118
|
||||
D. J. Bernstein
|
||||
Public domain.
|
||||
*/
|
||||
|
||||
#include "../system.h"
|
||||
|
||||
#include "chacha.h"
|
||||
|
||||
typedef struct chacha_ctx chacha_ctx;
|
||||
|
||||
#define U8C(v) (v##U)
|
||||
#define U32C(v) (v##U)
|
||||
|
||||
#define U8V(v) ((uint8_t)(v) & U8C(0xFF))
|
||||
#define U32V(v) ((uint32_t)(v) & U32C(0xFFFFFFFF))
|
||||
|
||||
#define ROTL32(v, n) \
|
||||
(U32V((v) << (n)) | ((v) >> (32 - (n))))
|
||||
|
||||
#define U8TO32_LITTLE(p) \
|
||||
(((uint32_t)((p)[0]) ) | \
|
||||
((uint32_t)((p)[1]) << 8) | \
|
||||
((uint32_t)((p)[2]) << 16) | \
|
||||
((uint32_t)((p)[3]) << 24))
|
||||
|
||||
#define U32TO8_LITTLE(p, v) \
|
||||
do { \
|
||||
(p)[0] = U8V((v) ); \
|
||||
(p)[1] = U8V((v) >> 8); \
|
||||
(p)[2] = U8V((v) >> 16); \
|
||||
(p)[3] = U8V((v) >> 24); \
|
||||
} while (0)
|
||||
|
||||
#define ROTATE(v,c) (ROTL32(v,c))
|
||||
#define XOR(v,w) ((v) ^ (w))
|
||||
#define PLUS(v,w) (U32V((v) + (w)))
|
||||
#define PLUSONE(v) (PLUS((v),1))
|
||||
|
||||
#define QUARTERROUND(a,b,c,d) \
|
||||
a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \
|
||||
c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \
|
||||
a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \
|
||||
c = PLUS(c,d); b = ROTATE(XOR(b,c), 7);
|
||||
|
||||
static const char sigma[16] = "expand 32-byte k";
|
||||
static const char tau[16] = "expand 16-byte k";
|
||||
|
||||
void chacha_keysetup(chacha_ctx *x, const uint8_t *k, uint32_t kbits) {
|
||||
const char *constants;
|
||||
|
||||
x->input[4] = U8TO32_LITTLE(k + 0);
|
||||
x->input[5] = U8TO32_LITTLE(k + 4);
|
||||
x->input[6] = U8TO32_LITTLE(k + 8);
|
||||
x->input[7] = U8TO32_LITTLE(k + 12);
|
||||
|
||||
if(kbits == 256) { /* recommended */
|
||||
k += 16;
|
||||
constants = sigma;
|
||||
} else { /* kbits == 128 */
|
||||
constants = tau;
|
||||
}
|
||||
|
||||
x->input[8] = U8TO32_LITTLE(k + 0);
|
||||
x->input[9] = U8TO32_LITTLE(k + 4);
|
||||
x->input[10] = U8TO32_LITTLE(k + 8);
|
||||
x->input[11] = U8TO32_LITTLE(k + 12);
|
||||
x->input[0] = U8TO32_LITTLE(constants + 0);
|
||||
x->input[1] = U8TO32_LITTLE(constants + 4);
|
||||
x->input[2] = U8TO32_LITTLE(constants + 8);
|
||||
x->input[3] = U8TO32_LITTLE(constants + 12);
|
||||
}
|
||||
|
||||
void chacha_ivsetup(chacha_ctx *x, const uint8_t *iv, const uint8_t *counter) {
|
||||
x->input[12] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 0);
|
||||
x->input[13] = counter == NULL ? 0 : U8TO32_LITTLE(counter + 4);
|
||||
x->input[14] = U8TO32_LITTLE(iv + 0);
|
||||
x->input[15] = U8TO32_LITTLE(iv + 4);
|
||||
}
|
||||
|
||||
void
|
||||
chacha_encrypt_bytes(chacha_ctx *x, const uint8_t *m, uint8_t *c, uint32_t bytes) {
|
||||
uint32_t x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
|
||||
uint32_t j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
|
||||
uint8_t *ctarget = NULL;
|
||||
uint8_t tmp[64];
|
||||
uint32_t i;
|
||||
|
||||
if(!bytes) {
|
||||
return;
|
||||
}
|
||||
|
||||
j0 = x->input[0];
|
||||
j1 = x->input[1];
|
||||
j2 = x->input[2];
|
||||
j3 = x->input[3];
|
||||
j4 = x->input[4];
|
||||
j5 = x->input[5];
|
||||
j6 = x->input[6];
|
||||
j7 = x->input[7];
|
||||
j8 = x->input[8];
|
||||
j9 = x->input[9];
|
||||
j10 = x->input[10];
|
||||
j11 = x->input[11];
|
||||
j12 = x->input[12];
|
||||
j13 = x->input[13];
|
||||
j14 = x->input[14];
|
||||
j15 = x->input[15];
|
||||
|
||||
for(;;) {
|
||||
if(bytes < 64) {
|
||||
for(i = 0; i < bytes; ++i) {
|
||||
tmp[i] = m[i];
|
||||
}
|
||||
|
||||
m = tmp;
|
||||
ctarget = c;
|
||||
c = tmp;
|
||||
}
|
||||
|
||||
x0 = j0;
|
||||
x1 = j1;
|
||||
x2 = j2;
|
||||
x3 = j3;
|
||||
x4 = j4;
|
||||
x5 = j5;
|
||||
x6 = j6;
|
||||
x7 = j7;
|
||||
x8 = j8;
|
||||
x9 = j9;
|
||||
x10 = j10;
|
||||
x11 = j11;
|
||||
x12 = j12;
|
||||
x13 = j13;
|
||||
x14 = j14;
|
||||
x15 = j15;
|
||||
|
||||
for(i = 20; i > 0; i -= 2) {
|
||||
QUARTERROUND(x0, x4, x8, x12)
|
||||
QUARTERROUND(x1, x5, x9, x13)
|
||||
QUARTERROUND(x2, x6, x10, x14)
|
||||
QUARTERROUND(x3, x7, x11, x15)
|
||||
QUARTERROUND(x0, x5, x10, x15)
|
||||
QUARTERROUND(x1, x6, x11, x12)
|
||||
QUARTERROUND(x2, x7, x8, x13)
|
||||
QUARTERROUND(x3, x4, x9, x14)
|
||||
}
|
||||
|
||||
x0 = PLUS(x0, j0);
|
||||
x1 = PLUS(x1, j1);
|
||||
x2 = PLUS(x2, j2);
|
||||
x3 = PLUS(x3, j3);
|
||||
x4 = PLUS(x4, j4);
|
||||
x5 = PLUS(x5, j5);
|
||||
x6 = PLUS(x6, j6);
|
||||
x7 = PLUS(x7, j7);
|
||||
x8 = PLUS(x8, j8);
|
||||
x9 = PLUS(x9, j9);
|
||||
x10 = PLUS(x10, j10);
|
||||
x11 = PLUS(x11, j11);
|
||||
x12 = PLUS(x12, j12);
|
||||
x13 = PLUS(x13, j13);
|
||||
x14 = PLUS(x14, j14);
|
||||
x15 = PLUS(x15, j15);
|
||||
|
||||
x0 = XOR(x0, U8TO32_LITTLE(m + 0));
|
||||
x1 = XOR(x1, U8TO32_LITTLE(m + 4));
|
||||
x2 = XOR(x2, U8TO32_LITTLE(m + 8));
|
||||
x3 = XOR(x3, U8TO32_LITTLE(m + 12));
|
||||
x4 = XOR(x4, U8TO32_LITTLE(m + 16));
|
||||
x5 = XOR(x5, U8TO32_LITTLE(m + 20));
|
||||
x6 = XOR(x6, U8TO32_LITTLE(m + 24));
|
||||
x7 = XOR(x7, U8TO32_LITTLE(m + 28));
|
||||
x8 = XOR(x8, U8TO32_LITTLE(m + 32));
|
||||
x9 = XOR(x9, U8TO32_LITTLE(m + 36));
|
||||
x10 = XOR(x10, U8TO32_LITTLE(m + 40));
|
||||
x11 = XOR(x11, U8TO32_LITTLE(m + 44));
|
||||
x12 = XOR(x12, U8TO32_LITTLE(m + 48));
|
||||
x13 = XOR(x13, U8TO32_LITTLE(m + 52));
|
||||
x14 = XOR(x14, U8TO32_LITTLE(m + 56));
|
||||
x15 = XOR(x15, U8TO32_LITTLE(m + 60));
|
||||
|
||||
j12 = PLUSONE(j12);
|
||||
|
||||
if(!j12) {
|
||||
j13 = PLUSONE(j13);
|
||||
/* stopping at 2^70 bytes per nonce is user's responsibility */
|
||||
}
|
||||
|
||||
U32TO8_LITTLE(c + 0, x0);
|
||||
U32TO8_LITTLE(c + 4, x1);
|
||||
U32TO8_LITTLE(c + 8, x2);
|
||||
U32TO8_LITTLE(c + 12, x3);
|
||||
U32TO8_LITTLE(c + 16, x4);
|
||||
U32TO8_LITTLE(c + 20, x5);
|
||||
U32TO8_LITTLE(c + 24, x6);
|
||||
U32TO8_LITTLE(c + 28, x7);
|
||||
U32TO8_LITTLE(c + 32, x8);
|
||||
U32TO8_LITTLE(c + 36, x9);
|
||||
U32TO8_LITTLE(c + 40, x10);
|
||||
U32TO8_LITTLE(c + 44, x11);
|
||||
U32TO8_LITTLE(c + 48, x12);
|
||||
U32TO8_LITTLE(c + 52, x13);
|
||||
U32TO8_LITTLE(c + 56, x14);
|
||||
U32TO8_LITTLE(c + 60, x15);
|
||||
|
||||
if(bytes <= 64) {
|
||||
if(bytes < 64) {
|
||||
for(i = 0; i < bytes; ++i) {
|
||||
ctarget[i] = c[i];
|
||||
}
|
||||
}
|
||||
|
||||
x->input[12] = j12;
|
||||
x->input[13] = j13;
|
||||
return;
|
||||
}
|
||||
|
||||
bytes -= 64;
|
||||
c += 64;
|
||||
m += 64;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
/*
|
||||
chacha-merged.c version 20080118
|
||||
D. J. Bernstein
|
||||
Public domain.
|
||||
*/
|
||||
|
||||
#ifndef CHACHA_H
|
||||
#define CHACHA_H
|
||||
|
||||
struct chacha_ctx {
|
||||
uint32_t input[16];
|
||||
};
|
||||
|
||||
#define CHACHA_MINKEYLEN 16
|
||||
#define CHACHA_NONCELEN 8
|
||||
#define CHACHA_CTRLEN 8
|
||||
#define CHACHA_STATELEN (CHACHA_NONCELEN+CHACHA_CTRLEN)
|
||||
#define CHACHA_BLOCKLEN 64
|
||||
|
||||
void chacha_keysetup(struct chacha_ctx *x, const uint8_t *k, uint32_t kbits);
|
||||
void chacha_ivsetup(struct chacha_ctx *x, const uint8_t *iv, const uint8_t *ctr);
|
||||
void chacha_encrypt_bytes(struct chacha_ctx *x, const uint8_t *m, uint8_t *c, uint32_t bytes);
|
||||
|
||||
#endif /* CHACHA_H */
|
||||
|
|
@ -1,205 +0,0 @@
|
|||
/*
|
||||
* Public Domain poly1305 from Andrew Moon
|
||||
* poly1305-donna-unrolled.c from https://github.com/floodyberry/poly1305-donna
|
||||
*/
|
||||
|
||||
#include "../system.h"
|
||||
|
||||
#include "poly1305.h"
|
||||
|
||||
#define mul32x32_64(a,b) ((uint64_t)(a) * (b))
|
||||
|
||||
#define U8TO32_LE(p) \
|
||||
(((uint32_t)((p)[0])) | \
|
||||
((uint32_t)((p)[1]) << 8) | \
|
||||
((uint32_t)((p)[2]) << 16) | \
|
||||
((uint32_t)((p)[3]) << 24))
|
||||
|
||||
#define U32TO8_LE(p, v) \
|
||||
do { \
|
||||
(p)[0] = (uint8_t)((v)); \
|
||||
(p)[1] = (uint8_t)((v) >> 8); \
|
||||
(p)[2] = (uint8_t)((v) >> 16); \
|
||||
(p)[3] = (uint8_t)((v) >> 24); \
|
||||
} while (0)
|
||||
|
||||
void
|
||||
poly1305_auth(unsigned char out[POLY1305_TAGLEN], const unsigned char *m, size_t inlen, const unsigned char key[POLY1305_KEYLEN]) {
|
||||
uint32_t t0, t1, t2, t3;
|
||||
uint32_t h0, h1, h2, h3, h4;
|
||||
uint32_t r0, r1, r2, r3, r4;
|
||||
uint32_t s1, s2, s3, s4;
|
||||
uint32_t b, nb;
|
||||
size_t j;
|
||||
uint64_t t[5];
|
||||
uint64_t f0, f1, f2, f3;
|
||||
uint32_t g0, g1, g2, g3, g4;
|
||||
uint64_t c;
|
||||
unsigned char mp[16];
|
||||
|
||||
/* clamp key */
|
||||
t0 = U8TO32_LE(key + 0);
|
||||
t1 = U8TO32_LE(key + 4);
|
||||
t2 = U8TO32_LE(key + 8);
|
||||
t3 = U8TO32_LE(key + 12);
|
||||
|
||||
/* precompute multipliers */
|
||||
r0 = t0 & 0x3ffffff;
|
||||
t0 >>= 26;
|
||||
t0 |= t1 << 6;
|
||||
r1 = t0 & 0x3ffff03;
|
||||
t1 >>= 20;
|
||||
t1 |= t2 << 12;
|
||||
r2 = t1 & 0x3ffc0ff;
|
||||
t2 >>= 14;
|
||||
t2 |= t3 << 18;
|
||||
r3 = t2 & 0x3f03fff;
|
||||
t3 >>= 8;
|
||||
r4 = t3 & 0x00fffff;
|
||||
|
||||
s1 = r1 * 5;
|
||||
s2 = r2 * 5;
|
||||
s3 = r3 * 5;
|
||||
s4 = r4 * 5;
|
||||
|
||||
/* init state */
|
||||
h0 = 0;
|
||||
h1 = 0;
|
||||
h2 = 0;
|
||||
h3 = 0;
|
||||
h4 = 0;
|
||||
|
||||
/* full blocks */
|
||||
if(inlen < 16) {
|
||||
goto poly1305_donna_atmost15bytes;
|
||||
}
|
||||
|
||||
poly1305_donna_16bytes:
|
||||
m += 16;
|
||||
inlen -= 16;
|
||||
|
||||
t0 = U8TO32_LE(m - 16);
|
||||
t1 = U8TO32_LE(m - 12);
|
||||
t2 = U8TO32_LE(m - 8);
|
||||
t3 = U8TO32_LE(m - 4);
|
||||
|
||||
h0 += t0 & 0x3ffffff;
|
||||
h1 += ((((uint64_t) t1 << 32) | t0) >> 26) & 0x3ffffff;
|
||||
h2 += ((((uint64_t) t2 << 32) | t1) >> 20) & 0x3ffffff;
|
||||
h3 += ((((uint64_t) t3 << 32) | t2) >> 14) & 0x3ffffff;
|
||||
h4 += (t3 >> 8) | (1 << 24);
|
||||
|
||||
poly1305_donna_mul:
|
||||
t[0] = mul32x32_64(h0, r0) + mul32x32_64(h1, s4) + mul32x32_64(h2, s3) + mul32x32_64(h3, s2) + mul32x32_64(h4, s1);
|
||||
t[1] = mul32x32_64(h0, r1) + mul32x32_64(h1, r0) + mul32x32_64(h2, s4) + mul32x32_64(h3, s3) + mul32x32_64(h4, s2);
|
||||
t[2] = mul32x32_64(h0, r2) + mul32x32_64(h1, r1) + mul32x32_64(h2, r0) + mul32x32_64(h3, s4) + mul32x32_64(h4, s3);
|
||||
t[3] = mul32x32_64(h0, r3) + mul32x32_64(h1, r2) + mul32x32_64(h2, r1) + mul32x32_64(h3, r0) + mul32x32_64(h4, s4);
|
||||
t[4] = mul32x32_64(h0, r4) + mul32x32_64(h1, r3) + mul32x32_64(h2, r2) + mul32x32_64(h3, r1) + mul32x32_64(h4, r0);
|
||||
|
||||
h0 = (uint32_t) t[0] & 0x3ffffff;
|
||||
c = (t[0] >> 26);
|
||||
t[1] += c;
|
||||
h1 = (uint32_t) t[1] & 0x3ffffff;
|
||||
b = (uint32_t)(t[1] >> 26);
|
||||
t[2] += b;
|
||||
h2 = (uint32_t) t[2] & 0x3ffffff;
|
||||
b = (uint32_t)(t[2] >> 26);
|
||||
t[3] += b;
|
||||
h3 = (uint32_t) t[3] & 0x3ffffff;
|
||||
b = (uint32_t)(t[3] >> 26);
|
||||
t[4] += b;
|
||||
h4 = (uint32_t) t[4] & 0x3ffffff;
|
||||
b = (uint32_t)(t[4] >> 26);
|
||||
h0 += b * 5;
|
||||
|
||||
if(inlen >= 16) {
|
||||
goto poly1305_donna_16bytes;
|
||||
}
|
||||
|
||||
/* final bytes */
|
||||
poly1305_donna_atmost15bytes:
|
||||
|
||||
if(!inlen) {
|
||||
goto poly1305_donna_finish;
|
||||
}
|
||||
|
||||
for(j = 0; j < inlen; j++) {
|
||||
mp[j] = m[j];
|
||||
}
|
||||
|
||||
mp[j++] = 1;
|
||||
|
||||
for(; j < 16; j++) {
|
||||
mp[j] = 0;
|
||||
}
|
||||
|
||||
inlen = 0;
|
||||
|
||||
t0 = U8TO32_LE(mp + 0);
|
||||
t1 = U8TO32_LE(mp + 4);
|
||||
t2 = U8TO32_LE(mp + 8);
|
||||
t3 = U8TO32_LE(mp + 12);
|
||||
|
||||
h0 += t0 & 0x3ffffff;
|
||||
h1 += ((((uint64_t) t1 << 32) | t0) >> 26) & 0x3ffffff;
|
||||
h2 += ((((uint64_t) t2 << 32) | t1) >> 20) & 0x3ffffff;
|
||||
h3 += ((((uint64_t) t3 << 32) | t2) >> 14) & 0x3ffffff;
|
||||
h4 += (t3 >> 8);
|
||||
|
||||
goto poly1305_donna_mul;
|
||||
|
||||
poly1305_donna_finish:
|
||||
b = h0 >> 26;
|
||||
h0 = h0 & 0x3ffffff;
|
||||
h1 += b;
|
||||
b = h1 >> 26;
|
||||
h1 = h1 & 0x3ffffff;
|
||||
h2 += b;
|
||||
b = h2 >> 26;
|
||||
h2 = h2 & 0x3ffffff;
|
||||
h3 += b;
|
||||
b = h3 >> 26;
|
||||
h3 = h3 & 0x3ffffff;
|
||||
h4 += b;
|
||||
b = h4 >> 26;
|
||||
h4 = h4 & 0x3ffffff;
|
||||
h0 += b * 5;
|
||||
b = h0 >> 26;
|
||||
h0 = h0 & 0x3ffffff;
|
||||
h1 += b;
|
||||
|
||||
g0 = h0 + 5;
|
||||
b = g0 >> 26;
|
||||
g0 &= 0x3ffffff;
|
||||
g1 = h1 + b;
|
||||
b = g1 >> 26;
|
||||
g1 &= 0x3ffffff;
|
||||
g2 = h2 + b;
|
||||
b = g2 >> 26;
|
||||
g2 &= 0x3ffffff;
|
||||
g3 = h3 + b;
|
||||
b = g3 >> 26;
|
||||
g3 &= 0x3ffffff;
|
||||
g4 = h4 + b - (1 << 26);
|
||||
|
||||
b = (g4 >> 31) - 1;
|
||||
nb = ~b;
|
||||
h0 = (h0 & nb) | (g0 & b);
|
||||
h1 = (h1 & nb) | (g1 & b);
|
||||
h2 = (h2 & nb) | (g2 & b);
|
||||
h3 = (h3 & nb) | (g3 & b);
|
||||
h4 = (h4 & nb) | (g4 & b);
|
||||
|
||||
f0 = ((h0) | (h1 << 26)) + (uint64_t) U8TO32_LE(&key[16]);
|
||||
f1 = ((h1 >> 6) | (h2 << 20)) + (uint64_t) U8TO32_LE(&key[20]);
|
||||
f2 = ((h2 >> 12) | (h3 << 14)) + (uint64_t) U8TO32_LE(&key[24]);
|
||||
f3 = ((h3 >> 18) | (h4 << 8)) + (uint64_t) U8TO32_LE(&key[28]);
|
||||
|
||||
U32TO8_LE(&out[0], f0);
|
||||
f1 += (f0 >> 32);
|
||||
U32TO8_LE(&out[4], f1);
|
||||
f2 += (f1 >> 32);
|
||||
U32TO8_LE(&out[8], f2);
|
||||
f3 += (f2 >> 32);
|
||||
U32TO8_LE(&out[12], f3);
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
/* $OpenBSD: poly1305.h,v 1.2 2013/12/19 22:57:13 djm Exp $ */
|
||||
|
||||
/*
|
||||
* Public Domain poly1305 from Andrew Moon
|
||||
* poly1305-donna-unrolled.c from https://github.com/floodyberry/poly1305-donna
|
||||
*/
|
||||
|
||||
#ifndef POLY1305_H
|
||||
#define POLY1305_H
|
||||
|
||||
#define POLY1305_KEYLEN 32
|
||||
#define POLY1305_TAGLEN 16
|
||||
|
||||
void poly1305_auth(uint8_t out[POLY1305_TAGLEN], const uint8_t *m, size_t inlen, const uint8_t key[POLY1305_KEYLEN]);
|
||||
|
||||
#endif /* POLY1305_H */
|
||||
46
src/cipher.h
46
src/cipher.h
|
|
@ -1,46 +0,0 @@
|
|||
#ifndef TINC_CIPHER_H
|
||||
#define TINC_CIPHER_H
|
||||
|
||||
/*
|
||||
cipher.h -- header file cipher.c
|
||||
Copyright (C) 2007-2016 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#define CIPHER_MAX_BLOCK_SIZE 32
|
||||
#define CIPHER_MAX_IV_SIZE 16
|
||||
#define CIPHER_MAX_KEY_SIZE 32
|
||||
|
||||
#ifndef DISABLE_LEGACY
|
||||
|
||||
typedef struct cipher cipher_t;
|
||||
|
||||
extern cipher_t *cipher_open_by_name(const char *name) __attribute__((__malloc__));
|
||||
extern cipher_t *cipher_open_by_nid(int nid) __attribute__((__malloc__));
|
||||
extern void cipher_close(cipher_t *cipher);
|
||||
extern size_t cipher_keylength(const cipher_t *cipher);
|
||||
extern size_t cipher_blocksize(const cipher_t *cipher);
|
||||
extern uint64_t cipher_budget(const cipher_t *cipher);
|
||||
extern bool cipher_set_key(cipher_t *cipher, void *key, bool encrypt) __attribute__((__warn_unused_result__));
|
||||
extern bool cipher_set_key_from_rsa(cipher_t *cipher, void *rsa, size_t len, bool encrypt) __attribute__((__warn_unused_result__));
|
||||
extern bool cipher_encrypt(cipher_t *cipher, const void *indata, size_t inlen, void *outdata, size_t *outlen, bool oneshot) __attribute__((__warn_unused_result__));
|
||||
extern bool cipher_decrypt(cipher_t *cipher, const void *indata, size_t inlen, void *outdata, size_t *outlen, bool oneshot) __attribute__((__warn_unused_result__));
|
||||
extern int cipher_get_nid(const cipher_t *cipher);
|
||||
extern bool cipher_active(const cipher_t *cipher);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
257
src/conf.c
257
src/conf.c
|
|
@ -1,11 +1,10 @@
|
|||
/*
|
||||
conf.c -- configuration code
|
||||
Copyright (C) 1998 Robert van der Meulen
|
||||
Copyright (C) 1998 Robert van der Meulen
|
||||
1998-2005 Ivo Timmermans
|
||||
2000 Cris van Pelt
|
||||
2000-2014 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2010-2011 Julien Muchembled <jm@jmuchemb.eu>
|
||||
2000-2015 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2013 Florent Clairambault <florent@clairambault.fr>
|
||||
2000 Cris van Pelt
|
||||
|
||||
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
|
||||
|
|
@ -24,23 +23,25 @@
|
|||
|
||||
#include "system.h"
|
||||
|
||||
#include "splay_tree.h"
|
||||
#include "avl_tree.h"
|
||||
#include "connection.h"
|
||||
#include "conf.h"
|
||||
#include "list.h"
|
||||
#include "logger.h"
|
||||
#include "names.h"
|
||||
#include "netutl.h" /* for str2address */
|
||||
#include "netutl.h" /* for str2address */
|
||||
#include "protocol.h"
|
||||
#include "utils.h" /* for cp */
|
||||
#include "utils.h" /* for cp */
|
||||
#include "xalloc.h"
|
||||
|
||||
splay_tree_t *config_tree;
|
||||
avl_tree_t *config_tree;
|
||||
|
||||
int pinginterval = 0; /* seconds between pings */
|
||||
int pingtimeout = 0; /* seconds to wait for response */
|
||||
int pinginterval = 0; /* seconds between pings */
|
||||
int pingtimeout = 0; /* seconds to wait for response */
|
||||
char *confbase = NULL; /* directory in which all config files are */
|
||||
char *netname = NULL; /* name of the vpn network */
|
||||
list_t *cmdline_conf = NULL; /* global/host configuration values given at the command line */
|
||||
|
||||
|
||||
static int config_compare(const config_t *a, const config_t *b) {
|
||||
int result;
|
||||
|
||||
|
|
@ -66,17 +67,17 @@ static int config_compare(const config_t *a, const config_t *b) {
|
|||
}
|
||||
}
|
||||
|
||||
void init_configuration(splay_tree_t **config_tree) {
|
||||
*config_tree = splay_alloc_tree((splay_compare_t) config_compare, (splay_action_t) free_config);
|
||||
void init_configuration(avl_tree_t **config_tree) {
|
||||
*config_tree = avl_alloc_tree((avl_compare_t) config_compare, (avl_action_t) free_config);
|
||||
}
|
||||
|
||||
void exit_configuration(splay_tree_t **config_tree) {
|
||||
splay_delete_tree(*config_tree);
|
||||
void exit_configuration(avl_tree_t **config_tree) {
|
||||
avl_delete_tree(*config_tree);
|
||||
*config_tree = NULL;
|
||||
}
|
||||
|
||||
config_t *new_config(void) {
|
||||
return xzalloc(sizeof(config_t));
|
||||
return xmalloc_and_zero(sizeof(config_t));
|
||||
}
|
||||
|
||||
void free_config(config_t *cfg) {
|
||||
|
|
@ -86,18 +87,18 @@ void free_config(config_t *cfg) {
|
|||
free(cfg);
|
||||
}
|
||||
|
||||
void config_add(splay_tree_t *config_tree, config_t *cfg) {
|
||||
splay_insert(config_tree, cfg);
|
||||
void config_add(avl_tree_t *config_tree, config_t *cfg) {
|
||||
avl_insert(config_tree, cfg);
|
||||
}
|
||||
|
||||
config_t *lookup_config(splay_tree_t *config_tree, char *variable) {
|
||||
config_t *lookup_config(const avl_tree_t *config_tree, char *variable) {
|
||||
config_t cfg, *found;
|
||||
|
||||
cfg.variable = variable;
|
||||
cfg.file = NULL;
|
||||
cfg.line = 0;
|
||||
|
||||
found = splay_search_closest_greater(config_tree, &cfg);
|
||||
found = avl_search_closest_greater(config_tree, &cfg);
|
||||
|
||||
if(!found) {
|
||||
return NULL;
|
||||
|
|
@ -110,11 +111,11 @@ config_t *lookup_config(splay_tree_t *config_tree, char *variable) {
|
|||
return found;
|
||||
}
|
||||
|
||||
config_t *lookup_config_next(splay_tree_t *config_tree, const config_t *cfg) {
|
||||
splay_node_t *node;
|
||||
config_t *lookup_config_next(const avl_tree_t *config_tree, const config_t *cfg) {
|
||||
avl_node_t *node;
|
||||
config_t *found;
|
||||
|
||||
node = splay_search_node(config_tree, cfg);
|
||||
node = avl_search_node(config_tree, cfg);
|
||||
|
||||
if(node) {
|
||||
if(node->next) {
|
||||
|
|
@ -142,7 +143,7 @@ bool get_config_bool(const config_t *cfg, bool *result) {
|
|||
return true;
|
||||
}
|
||||
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "\"yes\" or \"no\" expected for configuration variable %s in %s line %d",
|
||||
logger(LOG_ERR, "\"yes\" or \"no\" expected for configuration variable %s in %s line %d",
|
||||
cfg->variable, cfg->file, cfg->line);
|
||||
|
||||
return false;
|
||||
|
|
@ -157,7 +158,7 @@ bool get_config_int(const config_t *cfg, int *result) {
|
|||
return true;
|
||||
}
|
||||
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Integer expected for configuration variable %s in %s line %d",
|
||||
logger(LOG_ERR, "Integer expected for configuration variable %s in %s line %d",
|
||||
cfg->variable, cfg->file, cfg->line);
|
||||
|
||||
return false;
|
||||
|
|
@ -187,7 +188,7 @@ bool get_config_address(const config_t *cfg, struct addrinfo **result) {
|
|||
return true;
|
||||
}
|
||||
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Hostname or IP address expected for configuration variable %s in %s line %d",
|
||||
logger(LOG_ERR, "Hostname or IP address expected for configuration variable %s in %s line %d",
|
||||
cfg->variable, cfg->file, cfg->line);
|
||||
|
||||
return false;
|
||||
|
|
@ -201,7 +202,7 @@ bool get_config_subnet(const config_t *cfg, subnet_t **result) {
|
|||
}
|
||||
|
||||
if(!str2net(&subnet, cfg->value)) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Subnet expected for configuration variable %s in %s line %d",
|
||||
logger(LOG_ERR, "Subnet expected for configuration variable %s in %s line %d",
|
||||
cfg->variable, cfg->file, cfg->line);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -209,10 +210,10 @@ bool get_config_subnet(const config_t *cfg, subnet_t **result) {
|
|||
/* Teach newbies what subnets are... */
|
||||
|
||||
if(((subnet.type == SUBNET_IPV4)
|
||||
&& !maskcheck(&subnet.net.ipv4.address, subnet.net.ipv4.prefixlength, sizeof(subnet.net.ipv4.address)))
|
||||
&& !maskcheck(&subnet.net.ipv4.address, subnet.net.ipv4.prefixlength, sizeof(ipv4_t)))
|
||||
|| ((subnet.type == SUBNET_IPV6)
|
||||
&& !maskcheck(&subnet.net.ipv6.address, subnet.net.ipv6.prefixlength, sizeof(subnet.net.ipv6.address)))) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Network address and prefix length do not match for configuration variable %s in %s line %d",
|
||||
&& !maskcheck(&subnet.net.ipv6.address, subnet.net.ipv6.prefixlength, sizeof(ipv6_t)))) {
|
||||
logger(LOG_ERR, "Network address and prefix length do not match for configuration variable %s in %s line %d",
|
||||
cfg->variable, cfg->file, cfg->line);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -245,10 +246,9 @@ static char *readline(FILE *fp, char *buf, size_t buflen) {
|
|||
return buf;
|
||||
}
|
||||
|
||||
/* kill newline and carriage return if necessary */
|
||||
*newline = '\0';
|
||||
*newline = '\0'; /* kill newline */
|
||||
|
||||
if(newline > p && newline[-1] == '\r') {
|
||||
if(newline > p && newline[-1] == '\r') { /* and carriage return if necessary */
|
||||
newline[-1] = '\0';
|
||||
}
|
||||
|
||||
|
|
@ -282,10 +282,10 @@ config_t *parse_config_line(char *line, const char *fname, int lineno) {
|
|||
const char err[] = "No value for variable";
|
||||
|
||||
if(fname)
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "%s `%s' on line %d while reading config file %s",
|
||||
logger(LOG_ERR, "%s `%s' on line %d while reading config file %s",
|
||||
err, variable, lineno, fname);
|
||||
else
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "%s `%s' in command line option %d",
|
||||
logger(LOG_ERR, "%s `%s' in command line option %d",
|
||||
err, variable, lineno);
|
||||
|
||||
return NULL;
|
||||
|
|
@ -304,7 +304,7 @@ config_t *parse_config_line(char *line, const char *fname, int lineno) {
|
|||
Parse a configuration file and put the results in the configuration tree
|
||||
starting at *base.
|
||||
*/
|
||||
bool read_config_file(splay_tree_t *config_tree, const char *fname, bool verbose) {
|
||||
bool read_config_file(avl_tree_t *config_tree, const char *fname) {
|
||||
FILE *fp;
|
||||
char buffer[MAX_STRING_SIZE];
|
||||
char *line;
|
||||
|
|
@ -316,7 +316,7 @@ bool read_config_file(splay_tree_t *config_tree, const char *fname, bool verbose
|
|||
fp = fopen(fname, "r");
|
||||
|
||||
if(!fp) {
|
||||
logger(verbose ? DEBUG_ALWAYS : DEBUG_CONNECTIONS, LOG_ERR, "Cannot open config file %s: %s", fname, strerror(errno));
|
||||
logger(LOG_ERR, "Cannot open config file %s: %s", fname, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -364,12 +364,11 @@ bool read_config_file(splay_tree_t *config_tree, const char *fname, bool verbose
|
|||
return result;
|
||||
}
|
||||
|
||||
void read_config_options(splay_tree_t *config_tree, const char *prefix) {
|
||||
void read_config_options(avl_tree_t *config_tree, const char *prefix) {
|
||||
size_t prefix_len = prefix ? strlen(prefix) : 0;
|
||||
|
||||
for(const list_node_t *node = cmdline_conf->tail; node; node = node->prev) {
|
||||
const config_t *cfg = node->data;
|
||||
config_t *new;
|
||||
|
||||
if(!prefix) {
|
||||
if(strchr(cfg->variable, '.')) {
|
||||
|
|
@ -382,7 +381,7 @@ void read_config_options(splay_tree_t *config_tree, const char *prefix) {
|
|||
}
|
||||
}
|
||||
|
||||
new = new_config();
|
||||
config_t *new = new_config();
|
||||
|
||||
if(prefix) {
|
||||
new->variable = xstrdup(cfg->variable + prefix_len + 1);
|
||||
|
|
@ -404,14 +403,14 @@ bool read_server_config(void) {
|
|||
|
||||
read_config_options(config_tree, NULL);
|
||||
|
||||
snprintf(fname, sizeof(fname), "%s" SLASH "tinc.conf", confbase);
|
||||
snprintf(fname, sizeof(fname), "%s/tinc.conf", confbase);
|
||||
errno = 0;
|
||||
x = read_config_file(config_tree, fname, true);
|
||||
x = read_config_file(config_tree, fname);
|
||||
|
||||
// We will try to read the conf files in the "conf.d" dir
|
||||
if(x) {
|
||||
char dname[PATH_MAX];
|
||||
snprintf(dname, sizeof(dname), "%s" SLASH "conf.d", confbase);
|
||||
snprintf(dname, sizeof(dname), "%s/conf.d", confbase);
|
||||
DIR *dir = opendir(dname);
|
||||
|
||||
// If we can find this dir
|
||||
|
|
@ -424,12 +423,12 @@ bool read_server_config(void) {
|
|||
|
||||
// And we try to read the ones that end with ".conf"
|
||||
if(l > 5 && !strcmp(".conf", & ep->d_name[ l - 5 ])) {
|
||||
if((size_t)snprintf(fname, sizeof(fname), "%s" SLASH "%s", dname, ep->d_name) >= sizeof(fname)) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Pathname too long: %s/%s", dname, ep->d_name);
|
||||
if((size_t)snprintf(fname, sizeof(fname), "%s/%s", dname, ep->d_name) >= sizeof(fname)) {
|
||||
logger(LOG_ERR, "Pathname too long: %s/%s", dname, ep->d_name);
|
||||
return false;
|
||||
}
|
||||
|
||||
x = read_config_file(config_tree, fname, true);
|
||||
x = read_config_file(config_tree, fname);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -438,32 +437,166 @@ bool read_server_config(void) {
|
|||
}
|
||||
|
||||
if(!x && errno) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Failed to read `%s': %s", fname, strerror(errno));
|
||||
logger(LOG_ERR, "Failed to read `%s': %s", fname, strerror(errno));
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
bool read_host_config(splay_tree_t *config_tree, const char *name, bool verbose) {
|
||||
read_config_options(config_tree, name);
|
||||
|
||||
bool read_connection_config(connection_t *c) {
|
||||
char fname[PATH_MAX];
|
||||
snprintf(fname, sizeof(fname), "%s" SLASH "hosts" SLASH "%s", confbase, name);
|
||||
return read_config_file(config_tree, fname, verbose);
|
||||
bool x;
|
||||
|
||||
read_config_options(c->config_tree, c->name);
|
||||
|
||||
snprintf(fname, sizeof(fname), "%s/hosts/%s", confbase, c->name);
|
||||
x = read_config_file(c->config_tree, fname);
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
bool append_config_file(const char *name, const char *key, const char *value) {
|
||||
char fname[PATH_MAX];
|
||||
snprintf(fname, sizeof(fname), "%s" SLASH "hosts" SLASH "%s", confbase, name);
|
||||
static void disable_old_keys(const char *filename) {
|
||||
char tmpfile[PATH_MAX] = "";
|
||||
char buf[1024];
|
||||
bool disabled = false;
|
||||
FILE *r, *w;
|
||||
|
||||
FILE *fp = fopen(fname, "a");
|
||||
r = fopen(filename, "r");
|
||||
|
||||
if(!fp) {
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Cannot open config file %s: %s", fname, strerror(errno));
|
||||
return false;
|
||||
if(!r) {
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(fp, "\n# The following line was automatically added by tinc\n%s = %s\n", key, value);
|
||||
fclose(fp);
|
||||
return true;
|
||||
int len = snprintf(tmpfile, sizeof(tmpfile), "%s.tmp", filename);
|
||||
|
||||
if(len < 0 || len >= PATH_MAX) {
|
||||
fprintf(stderr, "Pathname too long: %s.tmp\n", filename);
|
||||
w = NULL;
|
||||
} else {
|
||||
w = fopen(tmpfile, "w");
|
||||
}
|
||||
|
||||
while(fgets(buf, sizeof(buf), r)) {
|
||||
if(!strncmp(buf, "-----BEGIN RSA", 14)) {
|
||||
buf[11] = 'O';
|
||||
buf[12] = 'L';
|
||||
buf[13] = 'D';
|
||||
disabled = true;
|
||||
} else if(!strncmp(buf, "-----END RSA", 12)) {
|
||||
buf[ 9] = 'O';
|
||||
buf[10] = 'L';
|
||||
buf[11] = 'D';
|
||||
disabled = true;
|
||||
}
|
||||
|
||||
if(w && fputs(buf, w) < 0) {
|
||||
disabled = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(w) {
|
||||
fclose(w);
|
||||
}
|
||||
|
||||
fclose(r);
|
||||
|
||||
if(!w && disabled) {
|
||||
fprintf(stderr, "Warning: old key(s) found, remove them by hand!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if(disabled) {
|
||||
#ifdef HAVE_MINGW
|
||||
// We cannot atomically replace files on Windows.
|
||||
char bakfile[PATH_MAX] = "";
|
||||
snprintf(bakfile, sizeof(bakfile), "%s.bak", filename);
|
||||
|
||||
if(rename(filename, bakfile) || rename(tmpfile, filename)) {
|
||||
rename(bakfile, filename);
|
||||
#else
|
||||
|
||||
if(rename(tmpfile, filename)) {
|
||||
#endif
|
||||
fprintf(stderr, "Warning: old key(s) found, remove them by hand!\n");
|
||||
} else {
|
||||
#ifdef HAVE_MINGW
|
||||
unlink(bakfile);
|
||||
#endif
|
||||
fprintf(stderr, "Warning: old key(s) found and disabled.\n");
|
||||
}
|
||||
}
|
||||
|
||||
unlink(tmpfile);
|
||||
}
|
||||
|
||||
FILE *ask_and_open(const char *filename, const char *what) {
|
||||
FILE *r;
|
||||
char directory[PATH_MAX];
|
||||
char line[PATH_MAX];
|
||||
char abspath[PATH_MAX];
|
||||
const char *fn;
|
||||
|
||||
/* Check stdin and stdout */
|
||||
if(!isatty(0) || !isatty(1)) {
|
||||
/* Argh, they are running us from a script or something. Write
|
||||
the files to the current directory and let them burn in hell
|
||||
for ever. */
|
||||
fn = filename;
|
||||
} else {
|
||||
/* Ask for a file and/or directory name. */
|
||||
fprintf(stdout, "Please enter a file to save %s to [%s]: ",
|
||||
what, filename);
|
||||
fflush(stdout);
|
||||
|
||||
fn = readline(stdin, line, sizeof(line));
|
||||
|
||||
if(!fn) {
|
||||
fprintf(stderr, "Error while reading stdin: %s\n",
|
||||
strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(!strlen(fn))
|
||||
/* User just pressed enter. */
|
||||
{
|
||||
fn = filename;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_MINGW
|
||||
|
||||
if(fn[0] != '\\' && fn[0] != '/' && !strchr(fn, ':')) {
|
||||
#else
|
||||
|
||||
if(fn[0] != '/') {
|
||||
#endif
|
||||
/* The directory is a relative path or a filename. */
|
||||
getcwd(directory, sizeof(directory));
|
||||
|
||||
if((size_t)snprintf(abspath, sizeof(abspath), "%s/%s", directory, fn) >= sizeof(abspath)) {
|
||||
fprintf(stderr, "Pathname too long: %s/%s\n", directory, fn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fn = abspath;
|
||||
}
|
||||
|
||||
umask(0077); /* Disallow everything for group and other */
|
||||
|
||||
disable_old_keys(fn);
|
||||
|
||||
/* Open it first to keep the inode busy */
|
||||
|
||||
r = fopen(fn, "a");
|
||||
|
||||
if(!r) {
|
||||
fprintf(stderr, "Error opening file `%s': %s\n",
|
||||
fn, strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
41
src/conf.h
41
src/conf.h
|
|
@ -4,7 +4,7 @@
|
|||
/*
|
||||
conf.h -- header for conf.c
|
||||
Copyright (C) 1998-2005 Ivo Timmermans
|
||||
2000-2013 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2000-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
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
|
||||
|
|
@ -21,9 +21,8 @@
|
|||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "avl_tree.h"
|
||||
#include "list.h"
|
||||
#include "splay_tree.h"
|
||||
#include "subnet.h"
|
||||
|
||||
typedef struct config_t {
|
||||
char *variable;
|
||||
|
|
@ -32,33 +31,37 @@ typedef struct config_t {
|
|||
int line;
|
||||
} config_t;
|
||||
|
||||
#include "subnet.h"
|
||||
|
||||
extern splay_tree_t *config_tree;
|
||||
extern avl_tree_t *config_tree;
|
||||
|
||||
extern int pinginterval;
|
||||
extern int pingtimeout;
|
||||
extern int maxtimeout;
|
||||
extern int mintimeout;
|
||||
extern bool bypass_security;
|
||||
extern char *confbase;
|
||||
extern char *netname;
|
||||
extern list_t *cmdline_conf;
|
||||
|
||||
extern void init_configuration(splay_tree_t **config_tree);
|
||||
extern void exit_configuration(splay_tree_t **config_tree);
|
||||
extern void init_configuration(avl_tree_t **config_tree);
|
||||
extern void exit_configuration(avl_tree_t **config_tree);
|
||||
extern config_t *new_config(void) __attribute__((__malloc__));
|
||||
extern void free_config(config_t *config);
|
||||
extern void config_add(splay_tree_t *config_tree, config_t *config);
|
||||
extern config_t *lookup_config(splay_tree_t *config_tree, char *variable);
|
||||
extern config_t *lookup_config_next(splay_tree_t *config_tree, const config_t *config);
|
||||
extern bool get_config_bool(const config_t *config, bool *result);
|
||||
extern bool get_config_int(const config_t *config, int *result);
|
||||
extern bool get_config_string(const config_t *config, char **result);
|
||||
extern bool get_config_address(const config_t *config, struct addrinfo **result);
|
||||
extern bool get_config_subnet(const config_t *config, struct subnet_t **result);
|
||||
extern void free_config(config_t *cfg);
|
||||
extern void config_add(avl_tree_t *config_tree, config_t *cfg);
|
||||
extern config_t *lookup_config(const avl_tree_t *config_tree, char *variable);
|
||||
extern config_t *lookup_config_next(const avl_tree_t *config_tree, const config_t *cfg);
|
||||
extern bool get_config_bool(const config_t *cfg, bool *result);
|
||||
extern bool get_config_int(const config_t *cfg, int *result);
|
||||
extern bool get_config_string(const config_t *cfg, char **result);
|
||||
extern bool get_config_address(const config_t *cfg, struct addrinfo **result);
|
||||
extern bool get_config_subnet(const config_t *cfg, struct subnet_t **result);
|
||||
|
||||
extern config_t *parse_config_line(char *line, const char *fname, int lineno);
|
||||
extern bool read_config_file(splay_tree_t *config_tree, const char *filename, bool verbose);
|
||||
extern void read_config_options(splay_tree_t *config_tree, const char *prefix);
|
||||
extern bool read_config_file(avl_tree_t *config_tree, const char *fname);
|
||||
extern void read_config_options(avl_tree_t *config_tree, const char *prefix);
|
||||
extern bool read_server_config(void);
|
||||
extern bool read_host_config(splay_tree_t *config_tree, const char *name, bool verbose);
|
||||
extern bool append_config_file(const char *name, const char *key, const char *value);
|
||||
extern bool read_connection_config(struct connection_t *c);
|
||||
extern FILE *ask_and_open(const char *fname, const char *what);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
137
src/connection.c
137
src/connection.c
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
connection.c -- connection list management
|
||||
Copyright (C) 2000-2013 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
Copyright (C) 2000-2016 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
2000-2005 Ivo Timmermans
|
||||
2008 Max Rijevski <maksuf@gmail.com>
|
||||
|
||||
|
|
@ -21,68 +21,100 @@
|
|||
|
||||
#include "system.h"
|
||||
|
||||
#include "list.h"
|
||||
#include "cipher.h"
|
||||
#include "avl_tree.h"
|
||||
#include "conf.h"
|
||||
#include "control_common.h"
|
||||
#include "list.h"
|
||||
#include "logger.h"
|
||||
#include "net.h"
|
||||
#include "rsa.h"
|
||||
#include "subnet.h"
|
||||
#include "utils.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
list_t *connection_list;
|
||||
avl_tree_t *connection_tree; /* Meta connections */
|
||||
connection_t *everyone;
|
||||
|
||||
static int connection_compare(const connection_t *a, const connection_t *b) {
|
||||
return a < b ? -1 : a == b ? 0 : 1;
|
||||
}
|
||||
|
||||
void init_connections(void) {
|
||||
connection_list = list_alloc((list_action_t) free_connection);
|
||||
connection_tree = avl_alloc_tree((avl_compare_t) connection_compare, (avl_action_t) free_connection);
|
||||
everyone = new_connection();
|
||||
everyone->name = xstrdup("everyone");
|
||||
everyone->hostname = xstrdup("BROADCAST");
|
||||
}
|
||||
|
||||
void exit_connections(void) {
|
||||
list_delete_list(connection_list);
|
||||
avl_delete_tree(connection_tree);
|
||||
free_connection(everyone);
|
||||
}
|
||||
|
||||
connection_t *new_connection(void) {
|
||||
return xzalloc(sizeof(connection_t));
|
||||
connection_t *c;
|
||||
|
||||
c = xmalloc_and_zero(sizeof(connection_t));
|
||||
|
||||
if(!c) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gettimeofday(&c->start, NULL);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
void free_connection_partially(connection_t *c) {
|
||||
free(c->inkey);
|
||||
free(c->outkey);
|
||||
free(c->mychallenge);
|
||||
free(c->hischallenge);
|
||||
free(c->outbuf);
|
||||
|
||||
c->inkey = NULL;
|
||||
c->outkey = NULL;
|
||||
c->mychallenge = NULL;
|
||||
c->hischallenge = NULL;
|
||||
c->outbuf = NULL;
|
||||
|
||||
c->status.pinged = false;
|
||||
c->status.active = false;
|
||||
c->status.connecting = false;
|
||||
c->status.timeout = false;
|
||||
c->status.encryptout = false;
|
||||
c->status.decryptin = false;
|
||||
c->status.mst = false;
|
||||
|
||||
c->options = 0;
|
||||
c->buflen = 0;
|
||||
c->reqlen = 0;
|
||||
c->tcplen = 0;
|
||||
c->allow_request = 0;
|
||||
c->outbuflen = 0;
|
||||
c->outbufsize = 0;
|
||||
c->outbufstart = 0;
|
||||
c->last_ping_time = 0;
|
||||
c->last_flushed_time = 0;
|
||||
c->inbudget = 0;
|
||||
c->outbudget = 0;
|
||||
|
||||
if(c->inctx) {
|
||||
EVP_CIPHER_CTX_reset(c->inctx);
|
||||
free(c->inctx);
|
||||
c->inctx = NULL;
|
||||
}
|
||||
|
||||
if(c->outctx) {
|
||||
EVP_CIPHER_CTX_reset(c->outctx);
|
||||
free(c->outctx);
|
||||
c->outctx = NULL;
|
||||
}
|
||||
|
||||
if(c->rsa_key) {
|
||||
RSA_free(c->rsa_key);
|
||||
c->rsa_key = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void free_connection(connection_t *c) {
|
||||
if(!c) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef DISABLE_LEGACY
|
||||
cipher_close(c->incipher);
|
||||
digest_close(c->indigest);
|
||||
cipher_close(c->outcipher);
|
||||
digest_close(c->outdigest);
|
||||
rsa_free(c->rsa);
|
||||
#endif
|
||||
|
||||
sptps_stop(&c->sptps);
|
||||
ecdsa_free(c->ecdsa);
|
||||
|
||||
free(c->hischallenge);
|
||||
free(c->mychallenge);
|
||||
|
||||
buffer_clear(&c->inbuf);
|
||||
buffer_clear(&c->outbuf);
|
||||
|
||||
io_del(&c->io);
|
||||
|
||||
if(c->socket > 0) {
|
||||
if(c->status.tarpit) {
|
||||
tarpit(c->socket);
|
||||
} else {
|
||||
closesocket(c->socket);
|
||||
}
|
||||
}
|
||||
free_connection_partially(c);
|
||||
|
||||
free(c->name);
|
||||
free(c->hostname);
|
||||
|
|
@ -95,20 +127,25 @@ void free_connection(connection_t *c) {
|
|||
}
|
||||
|
||||
void connection_add(connection_t *c) {
|
||||
list_insert_tail(connection_list, c);
|
||||
avl_insert(connection_tree, c);
|
||||
}
|
||||
|
||||
void connection_del(connection_t *c) {
|
||||
list_delete(connection_list, c);
|
||||
avl_delete(connection_tree, c);
|
||||
}
|
||||
|
||||
bool dump_connections(connection_t *cdump) {
|
||||
for list_each(connection_t, c, connection_list) {
|
||||
send_request(cdump, "%d %d %s %s %x %d %x",
|
||||
CONTROL, REQ_DUMP_CONNECTIONS,
|
||||
c->name, c->hostname, c->options, c->socket,
|
||||
bitfield_to_int(&c->status, sizeof(c->status)));
|
||||
void dump_connections(void) {
|
||||
avl_node_t *node;
|
||||
connection_t *c;
|
||||
|
||||
logger(LOG_DEBUG, "Connections:");
|
||||
|
||||
for(node = connection_tree->head; node; node = node->next) {
|
||||
c = node->data;
|
||||
logger(LOG_DEBUG, " %s at %s options %x socket %d status %04x outbuf %d/%d/%d",
|
||||
c->name, c->hostname, c->options, c->socket, bitfield_to_int(&c->status, sizeof(c->status)),
|
||||
c->outbufsize, c->outbufstart, c->outbuflen);
|
||||
}
|
||||
|
||||
return send_request(cdump, "%d %d", CONTROL, REQ_DUMP_CONNECTIONS);
|
||||
logger(LOG_DEBUG, "End of connections.");
|
||||
}
|
||||
|
|
|
|||
106
src/connection.h
106
src/connection.h
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
/*
|
||||
connection.h -- header for connection.c
|
||||
Copyright (C) 2000-2013 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
Copyright (C) 2000-2016 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
2000-2005 Ivo Timmermans
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
|
|
@ -21,50 +21,45 @@
|
|||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "buffer.h"
|
||||
#include "cipher.h"
|
||||
#include "digest.h"
|
||||
#include "rsa.h"
|
||||
#include "list.h"
|
||||
#include "sptps.h"
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
#define EVP_CIPHER_CTX_reset(c) EVP_CIPHER_CTX_cleanup(c)
|
||||
#endif
|
||||
|
||||
#include "avl_tree.h"
|
||||
|
||||
#define OPTION_INDIRECT 0x0001
|
||||
#define OPTION_TCPONLY 0x0002
|
||||
#define OPTION_PMTU_DISCOVERY 0x0004
|
||||
#define OPTION_CLAMP_MSS 0x0008
|
||||
#define OPTION_VERSION(x) ((x) >> 24) /* Top 8 bits are for protocol minor version */
|
||||
|
||||
typedef struct connection_status_t {
|
||||
unsigned int pinged: 1; /* sent ping */
|
||||
unsigned int unused_active: 1;
|
||||
unsigned int connecting: 1; /* 1 if we are waiting for a non-blocking connect() to finish */
|
||||
unsigned int unused_termreq: 1; /* the termination of this connection was requested */
|
||||
unsigned int remove_unused: 1; /* Set to 1 if you want this connection removed */
|
||||
unsigned int timeout_unused: 1; /* 1 if gotten timeout */
|
||||
unsigned int encryptout: 1; /* 1 if we can encrypt outgoing traffic */
|
||||
unsigned int decryptin: 1; /* 1 if we have to decrypt incoming traffic */
|
||||
unsigned int mst: 1; /* 1 if this connection is part of a minimum spanning tree */
|
||||
unsigned int control: 1; /* 1 if this is a control connection */
|
||||
unsigned int pcap: 1; /* 1 if this is a control connection requesting packet capture */
|
||||
unsigned int log: 1; /* 1 if this is a control connection requesting log dump */
|
||||
unsigned int invitation: 1; /* 1 if this is an invitation */
|
||||
unsigned int invitation_used: 1; /* 1 if the invitation has been consumed */
|
||||
unsigned int tarpit: 1; /* 1 if the connection should be added to the tarpit */
|
||||
unsigned int unused: 17;
|
||||
unsigned int pinged: 1; /* sent ping */
|
||||
unsigned int active: 1; /* 1 if active.. */
|
||||
unsigned int connecting: 1; /* 1 if we are waiting for a non-blocking connect() to finish */
|
||||
unsigned int unused_termreq: 1; /* the termination of this connection was requested */
|
||||
unsigned int remove: 1; /* Set to 1 if you want this connection removed */
|
||||
unsigned int timeout: 1; /* 1 if gotten timeout */
|
||||
unsigned int encryptout: 1; /* 1 if we can encrypt outgoing traffic */
|
||||
unsigned int decryptin: 1; /* 1 if we have to decrypt incoming traffic */
|
||||
unsigned int mst: 1; /* 1 if this connection is part of a minimum spanning tree */
|
||||
unsigned int proxy_passed: 1; /* 1 if we are connecting via a proxy and we have finished talking with it */
|
||||
unsigned int tarpit: 1; /* 1 if the connection should be added to the tarpit */
|
||||
unsigned int unused: 21;
|
||||
} connection_status_t;
|
||||
|
||||
#include "ecdsa.h"
|
||||
#include "edge.h"
|
||||
#include "net.h"
|
||||
#include "node.h"
|
||||
|
||||
typedef struct connection_t {
|
||||
char *name; /* name he claims to have */
|
||||
char *hostname; /* the hostname of its real ip */
|
||||
|
||||
union sockaddr_t address; /* his real (internet) ip */
|
||||
int protocol_major; /* used protocol */
|
||||
int protocol_minor; /* used protocol */
|
||||
char *hostname; /* the hostname of its real ip */
|
||||
int protocol_version; /* used protocol */
|
||||
|
||||
int socket; /* socket used for this connection */
|
||||
uint32_t options; /* options for this connection */
|
||||
|
|
@ -76,48 +71,53 @@ typedef struct connection_t {
|
|||
struct node_t *node; /* node associated with the other end */
|
||||
struct edge_t *edge; /* edge associated with this connection */
|
||||
|
||||
#ifndef DISABLE_LEGACY
|
||||
rsa_t *rsa; /* his public RSA key */
|
||||
cipher_t *incipher; /* Cipher he will use to send data to us */
|
||||
cipher_t *outcipher; /* Cipher we will use to send data to him */
|
||||
digest_t *indigest;
|
||||
digest_t *outdigest;
|
||||
uint64_t inbudget;
|
||||
uint64_t outbudget;
|
||||
#endif
|
||||
|
||||
ecdsa_t *ecdsa; /* his public ECDSA key */
|
||||
sptps_t sptps;
|
||||
|
||||
RSA *rsa_key; /* his public/private key */
|
||||
const EVP_CIPHER *incipher; /* Cipher he will use to send data to us */
|
||||
const EVP_CIPHER *outcipher; /* Cipher we will use to send data to him */
|
||||
EVP_CIPHER_CTX *inctx; /* Context of encrypted meta data that will come from him to us */
|
||||
EVP_CIPHER_CTX *outctx; /* Context of encrypted meta data that will be sent from us to him */
|
||||
uint64_t inbudget; /* Encrypted bytes send budget */
|
||||
uint64_t outbudget; /* Encrypted bytes receive budget */
|
||||
char *inkey; /* His symmetric meta key + iv */
|
||||
char *outkey; /* Our symmetric meta key + iv */
|
||||
int inkeylength; /* Length of his key + iv */
|
||||
int outkeylength; /* Length of our key + iv */
|
||||
const EVP_MD *indigest;
|
||||
const EVP_MD *outdigest;
|
||||
int inmaclength;
|
||||
int outmaclength;
|
||||
int incompression;
|
||||
int outcompression;
|
||||
char *mychallenge; /* challenge we received from him */
|
||||
char *hischallenge; /* challenge we sent to him */
|
||||
|
||||
char *hischallenge; /* The challenge we sent to him */
|
||||
char *mychallenge; /* The challenge we received */
|
||||
|
||||
struct buffer_t inbuf;
|
||||
struct buffer_t outbuf;
|
||||
io_t io; /* input/output event on this metadata connection */
|
||||
int tcplen; /* length of incoming TCPpacket */
|
||||
int sptpslen; /* length of incoming SPTPS packet */
|
||||
char buffer[MAXBUFSIZE]; /* metadata input buffer */
|
||||
int buflen; /* bytes read into buffer */
|
||||
int reqlen; /* length of incoming request */
|
||||
length_t tcplen; /* length of incoming TCPpacket */
|
||||
int allow_request; /* defined if there's only one request possible */
|
||||
|
||||
time_t last_ping_time; /* last time we saw some activity from the other end or pinged them */
|
||||
char *outbuf; /* metadata output buffer */
|
||||
int outbufstart; /* index of first meaningful byte in output buffer */
|
||||
int outbuflen; /* number of meaningful bytes in output buffer */
|
||||
int outbufsize; /* number of bytes allocated to output buffer */
|
||||
|
||||
splay_tree_t *config_tree; /* Pointer to configuration tree belonging to him */
|
||||
time_t last_ping_time; /* last time we saw some activity from the other end or pinged them */
|
||||
time_t last_flushed_time; /* last time buffer was empty. Only meaningful if outbuflen > 0 */
|
||||
|
||||
avl_tree_t *config_tree; /* Pointer to configuration tree belonging to him */
|
||||
} connection_t;
|
||||
|
||||
extern list_t *connection_list;
|
||||
extern avl_tree_t *connection_tree;
|
||||
extern connection_t *everyone;
|
||||
|
||||
extern void init_connections(void);
|
||||
extern void exit_connections(void);
|
||||
extern connection_t *new_connection(void) __attribute__((__malloc__));
|
||||
extern void free_connection(connection_t *c);
|
||||
extern void free_connection_partially(connection_t *c);
|
||||
extern void connection_add(connection_t *c);
|
||||
extern void connection_del(connection_t *c);
|
||||
extern bool dump_connections(struct connection_t *c);
|
||||
extern void dump_connections(void);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
241
src/control.c
241
src/control.c
|
|
@ -1,241 +0,0 @@
|
|||
/*
|
||||
control.c -- Control socket handling.
|
||||
Copyright (C) 2013 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
#include "crypto.h"
|
||||
#include "conf.h"
|
||||
#include "control.h"
|
||||
#include "control_common.h"
|
||||
#include "graph.h"
|
||||
#include "logger.h"
|
||||
#include "meta.h"
|
||||
#include "names.h"
|
||||
#include "net.h"
|
||||
#include "netutl.h"
|
||||
#include "protocol.h"
|
||||
#include "route.h"
|
||||
#include "utils.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
char controlcookie[65];
|
||||
|
||||
static bool control_return(connection_t *c, int type, int error) {
|
||||
return send_request(c, "%d %d %d", CONTROL, type, error);
|
||||
}
|
||||
|
||||
static bool control_ok(connection_t *c, int type) {
|
||||
return control_return(c, type, 0);
|
||||
}
|
||||
|
||||
bool control_h(connection_t *c, const char *request) {
|
||||
int type;
|
||||
|
||||
if(!c->status.control || c->allow_request != CONTROL) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unauthorized control request from %s (%s)", c->name, c->hostname);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sscanf(request, "%*d %d", &type) != 1) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Got bad %s from %s (%s)", "CONTROL", c->name, c->hostname);
|
||||
return false;
|
||||
}
|
||||
|
||||
switch(type) {
|
||||
case REQ_STOP:
|
||||
event_exit();
|
||||
return control_ok(c, REQ_STOP);
|
||||
|
||||
case REQ_DUMP_NODES:
|
||||
return dump_nodes(c);
|
||||
|
||||
case REQ_DUMP_EDGES:
|
||||
return dump_edges(c);
|
||||
|
||||
case REQ_DUMP_SUBNETS:
|
||||
return dump_subnets(c);
|
||||
|
||||
case REQ_DUMP_CONNECTIONS:
|
||||
return dump_connections(c);
|
||||
|
||||
case REQ_PURGE:
|
||||
purge();
|
||||
return control_ok(c, REQ_PURGE);
|
||||
|
||||
case REQ_SET_DEBUG: {
|
||||
int new_level;
|
||||
|
||||
if(sscanf(request, "%*d %*d %d", &new_level) != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
send_request(c, "%d %d %d", CONTROL, REQ_SET_DEBUG, debug_level);
|
||||
|
||||
if(new_level >= 0) {
|
||||
debug_level = new_level;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case REQ_RETRY:
|
||||
retry();
|
||||
return control_ok(c, REQ_RETRY);
|
||||
|
||||
case REQ_RELOAD:
|
||||
logger(DEBUG_ALWAYS, LOG_NOTICE, "Got '%s' command", "reload");
|
||||
int result = reload_configuration();
|
||||
return control_return(c, REQ_RELOAD, result);
|
||||
|
||||
case REQ_DISCONNECT: {
|
||||
char name[MAX_STRING_SIZE];
|
||||
bool found = false;
|
||||
|
||||
if(sscanf(request, "%*d %*d " MAX_STRING, name) != 1) {
|
||||
return control_return(c, REQ_DISCONNECT, -1);
|
||||
}
|
||||
|
||||
for list_each(connection_t, other, connection_list) {
|
||||
if(strcmp(other->name, name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
terminate_connection(other, other->edge);
|
||||
found = true;
|
||||
}
|
||||
|
||||
return control_return(c, REQ_DISCONNECT, found ? 0 : -2);
|
||||
}
|
||||
|
||||
case REQ_DUMP_TRAFFIC:
|
||||
return dump_traffic(c);
|
||||
|
||||
case REQ_PCAP:
|
||||
sscanf(request, "%*d %*d %d", &c->outmaclength);
|
||||
c->status.pcap = true;
|
||||
pcap = true;
|
||||
return true;
|
||||
|
||||
case REQ_LOG:
|
||||
sscanf(request, "%*d %*d %d", &c->outcompression);
|
||||
c->status.log = true;
|
||||
logcontrol = true;
|
||||
return true;
|
||||
|
||||
default:
|
||||
return send_request(c, "%d %d", CONTROL, REQ_INVALID);
|
||||
}
|
||||
}
|
||||
|
||||
bool init_control(void) {
|
||||
randomize(controlcookie, sizeof(controlcookie) / 2);
|
||||
bin2hex(controlcookie, controlcookie, sizeof(controlcookie) / 2);
|
||||
|
||||
mode_t mask = umask(0);
|
||||
umask(mask | 077);
|
||||
FILE *f = fopen(pidfilename, "w");
|
||||
umask(mask);
|
||||
|
||||
if(!f) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Cannot write control socket cookie file %s: %s", pidfilename, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the address and port of the first listening socket
|
||||
|
||||
char *localhost = NULL;
|
||||
sockaddr_t sa = {0};
|
||||
socklen_t len = sizeof(sa);
|
||||
|
||||
// Make sure we have a valid address, and map 0.0.0.0 and :: to 127.0.0.1 and ::1.
|
||||
|
||||
if(getsockname(listen_socket[0].tcp.fd, &sa.sa, &len)) {
|
||||
xasprintf(&localhost, "127.0.0.1 port %s", myport);
|
||||
} else {
|
||||
if(sa.sa.sa_family == AF_INET) {
|
||||
if(sa.in.sin_addr.s_addr == 0) {
|
||||
sa.in.sin_addr.s_addr = htonl(0x7f000001);
|
||||
}
|
||||
} else if(sa.sa.sa_family == AF_INET6) {
|
||||
static const uint8_t zero[16] = {0};
|
||||
|
||||
if(!memcmp(sa.in6.sin6_addr.s6_addr, zero, sizeof(zero))) {
|
||||
sa.in6.sin6_addr.s6_addr[15] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
localhost = sockaddr2hostname(&sa);
|
||||
}
|
||||
|
||||
fprintf(f, "%d %s %s\n", (int)getpid(), controlcookie, localhost);
|
||||
|
||||
free(localhost);
|
||||
fclose(f);
|
||||
|
||||
#ifndef HAVE_MINGW
|
||||
int unix_fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
|
||||
if(unix_fd < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not create UNIX socket: %s", sockstrerror(sockerrno));
|
||||
return false;
|
||||
}
|
||||
|
||||
struct sockaddr_un sa_un;
|
||||
|
||||
sa_un.sun_family = AF_UNIX;
|
||||
|
||||
strncpy(sa_un.sun_path, unixsocketname, sizeof(sa_un.sun_path));
|
||||
|
||||
sa_un.sun_path[sizeof(sa_un.sun_path) - 1] = 0;
|
||||
|
||||
if(connect(unix_fd, (struct sockaddr *)&sa_un, sizeof(sa_un)) >= 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "UNIX socket %s is still in use!", unixsocketname);
|
||||
return false;
|
||||
}
|
||||
|
||||
unlink(unixsocketname);
|
||||
|
||||
umask(mask | 077);
|
||||
int result = bind(unix_fd, (struct sockaddr *)&sa_un, sizeof(sa_un));
|
||||
umask(mask);
|
||||
|
||||
if(result < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not bind UNIX socket to %s: %s", unixsocketname, sockstrerror(sockerrno));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(listen(unix_fd, 3) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not listen on UNIX socket %s: %s", unixsocketname, sockstrerror(sockerrno));
|
||||
return false;
|
||||
}
|
||||
|
||||
io_add(&unix_socket, handle_new_unix_connection, &unix_socket, unix_fd, IO_READ);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void exit_control(void) {
|
||||
#ifndef HAVE_MINGW
|
||||
unlink(unixsocketname);
|
||||
io_del(&unix_socket);
|
||||
close(unix_socket.fd);
|
||||
#endif
|
||||
|
||||
unlink(pidfilename);
|
||||
}
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
#ifndef TINC_CONTROL_H
|
||||
#define TINC_CONTROL_H
|
||||
|
||||
/*
|
||||
control.h -- header for control.c.
|
||||
Copyright (C) 2007 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
extern bool init_control(void);
|
||||
extern void exit_control(void);
|
||||
extern char controlcookie[];
|
||||
|
||||
#endif
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
#ifndef TINC_CONTROL_COMMON_H
|
||||
#define TINC_CONTROL_COMMON_H
|
||||
|
||||
/*
|
||||
control_protocol.h -- control socket protocol.
|
||||
Copyright (C) 2007 Scott Lamb <slamb@slamb.org>
|
||||
2009-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "protocol.h"
|
||||
|
||||
enum request_type {
|
||||
REQ_INVALID = -1,
|
||||
REQ_STOP = 0,
|
||||
REQ_RELOAD,
|
||||
REQ_RESTART,
|
||||
REQ_DUMP_NODES,
|
||||
REQ_DUMP_EDGES,
|
||||
REQ_DUMP_SUBNETS,
|
||||
REQ_DUMP_CONNECTIONS,
|
||||
REQ_DUMP_GRAPH,
|
||||
REQ_PURGE,
|
||||
REQ_SET_DEBUG,
|
||||
REQ_RETRY,
|
||||
REQ_CONNECT,
|
||||
REQ_DISCONNECT,
|
||||
REQ_DUMP_TRAFFIC,
|
||||
REQ_PCAP,
|
||||
REQ_LOG,
|
||||
};
|
||||
|
||||
#define TINC_CTL_VERSION_CURRENT 0
|
||||
|
||||
#endif
|
||||
27
src/crypto.h
27
src/crypto.h
|
|
@ -1,27 +0,0 @@
|
|||
#ifndef TINC_CRYPTO_H
|
||||
#define TINC_CRYPTO_H
|
||||
|
||||
/*
|
||||
crypto.h -- header for crypto.c
|
||||
Copyright (C) 2007-2013 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
extern void crypto_init(void);
|
||||
extern void crypto_exit(void);
|
||||
extern void randomize(void *buf, size_t buflen);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
device.c -- Interaction with Windows tap driver in a Cygwin environment
|
||||
Copyright (C) 2002-2005 Ivo Timmermans,
|
||||
2002-2014 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2002-2016 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
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
|
||||
|
|
@ -27,7 +27,6 @@
|
|||
#include "../conf.h"
|
||||
#include "../device.h"
|
||||
#include "../logger.h"
|
||||
#include "../names.h"
|
||||
#include "../route.h"
|
||||
#include "../utils.h"
|
||||
#include "../xalloc.h"
|
||||
|
|
@ -40,6 +39,9 @@ char *device = NULL;
|
|||
char *iface = NULL;
|
||||
static const char *device_info = "Windows tap device";
|
||||
|
||||
static uint64_t device_total_in = 0;
|
||||
static uint64_t device_total_out = 0;
|
||||
|
||||
static pid_t reader_pid;
|
||||
static int sp[2];
|
||||
|
||||
|
|
@ -66,7 +68,7 @@ static bool setup_device(void) {
|
|||
/* Open registry and look for network adapters */
|
||||
|
||||
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, NETWORK_CONNECTIONS_KEY, 0, KEY_READ, &key)) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to read registry: %s", winerror(GetLastError()));
|
||||
logger(LOG_ERR, "Unable to read registry: %s", winerror(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -125,7 +127,7 @@ static bool setup_device(void) {
|
|||
RegCloseKey(key);
|
||||
|
||||
if(!found) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "No Windows tap device found!");
|
||||
logger(LOG_ERR, "No Windows tap device found!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -144,7 +146,7 @@ static bool setup_device(void) {
|
|||
Furthermore I don't really know how to do it the "Windows" way. */
|
||||
|
||||
if(socketpair(AF_UNIX, SOCK_DGRAM, PF_UNIX, sp)) {
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "System call `%s' failed: %s", "socketpair", strerror(errno));
|
||||
logger(LOG_DEBUG, "System call `%s' failed: %s", "socketpair", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -153,7 +155,7 @@ static bool setup_device(void) {
|
|||
device_handle = CreateFile(tapname, GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0);
|
||||
|
||||
if(device_handle == INVALID_HANDLE_VALUE) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not open Windows tap device %s (%s) for writing: %s", device, iface, winerror(GetLastError()));
|
||||
logger(LOG_ERR, "Could not open Windows tap device %s (%s) for writing: %s", device, iface, winerror(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -162,7 +164,7 @@ static bool setup_device(void) {
|
|||
/* Get MAC address from tap device */
|
||||
|
||||
if(!DeviceIoControl(device_handle, TAP_IOCTL_GET_MAC, mymac.x, sizeof(mymac.x), mymac.x, sizeof(mymac.x), &len, 0)) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not get MAC address from Windows tap device %s (%s): %s", device, iface, winerror(GetLastError()));
|
||||
logger(LOG_ERR, "Could not get MAC address from Windows tap device %s (%s): %s", device, iface, winerror(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -175,7 +177,7 @@ static bool setup_device(void) {
|
|||
reader_pid = fork();
|
||||
|
||||
if(reader_pid == -1) {
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "System call `%s' failed: %s", "fork", strerror(errno));
|
||||
logger(LOG_DEBUG, "System call `%s' failed: %s", "fork", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -184,20 +186,20 @@ static bool setup_device(void) {
|
|||
It passes everything it reads to the socket. */
|
||||
|
||||
char buf[MTU];
|
||||
long inlen;
|
||||
long lenin;
|
||||
|
||||
CloseHandle(device_handle);
|
||||
|
||||
device_handle = CreateFile(tapname, GENERIC_READ, FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM, 0);
|
||||
|
||||
if(device_handle == INVALID_HANDLE_VALUE) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not open Windows tap device %s (%s) for reading: %s", device, iface, winerror(GetLastError()));
|
||||
logger(LOG_ERR, "Could not open Windows tap device %s (%s) for reading: %s", device, iface, winerror(GetLastError()));
|
||||
buf[0] = 0;
|
||||
write(sp[1], buf, 1);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Tap reader forked and running.");
|
||||
logger(LOG_DEBUG, "Tap reader forked and running.");
|
||||
|
||||
/* Notify success */
|
||||
|
||||
|
|
@ -207,19 +209,19 @@ static bool setup_device(void) {
|
|||
/* Pass packets */
|
||||
|
||||
for(;;) {
|
||||
ReadFile(device_handle, buf, MTU, &inlen, NULL);
|
||||
write(sp[1], buf, inlen);
|
||||
ReadFile(device_handle, buf, MTU, &lenin, NULL);
|
||||
write(sp[1], buf, lenin);
|
||||
}
|
||||
}
|
||||
|
||||
read(device_fd, &gelukt, 1);
|
||||
|
||||
if(gelukt != 1) {
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Tap reader failed!");
|
||||
logger(LOG_DEBUG, "Tap reader failed!");
|
||||
return false;
|
||||
}
|
||||
|
||||
logger(DEBUG_ALWAYS, LOG_INFO, "%s (%s) is a %s", device, iface, device_info);
|
||||
logger(LOG_INFO, "%s (%s) is a %s", device, iface, device_info);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -228,51 +230,58 @@ static void close_device(void) {
|
|||
close(sp[0]);
|
||||
close(sp[1]);
|
||||
CloseHandle(device_handle);
|
||||
device_handle = INVALID_HANDLE_VALUE;
|
||||
|
||||
kill(reader_pid, SIGKILL);
|
||||
|
||||
free(device);
|
||||
device = NULL;
|
||||
free(iface);
|
||||
iface = NULL;
|
||||
device_info = NULL;
|
||||
}
|
||||
|
||||
static bool read_packet(vpn_packet_t *packet) {
|
||||
int inlen;
|
||||
int lenin;
|
||||
|
||||
if((inlen = read(sp[0], DATA(packet), MTU)) <= 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
||||
if((lenin = read(sp[0], packet->data, MTU)) <= 0) {
|
||||
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
||||
device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
packet->len = inlen;
|
||||
packet->len = lenin;
|
||||
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Read packet of %d bytes from %s", packet->len,
|
||||
device_info);
|
||||
device_total_in += packet->len;
|
||||
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s", packet->len,
|
||||
device_info);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool write_packet(vpn_packet_t *packet) {
|
||||
long outlen;
|
||||
long lenout;
|
||||
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Writing packet of %d bytes to %s",
|
||||
packet->len, device_info);
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
|
||||
packet->len, device_info);
|
||||
|
||||
if(!WriteFile(device_handle, DATA(packet), packet->len, &outlen, NULL)) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while writing to %s %s: %s", device_info, device, winerror(GetLastError()));
|
||||
if(!WriteFile(device_handle, packet->data, packet->len, &lenout, NULL)) {
|
||||
logger(LOG_ERR, "Error while writing to %s %s: %s", device_info, device, winerror(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
|
||||
device_total_out += packet->len;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void dump_device_stats(void) {
|
||||
logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
|
||||
logger(LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in);
|
||||
logger(LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
|
||||
}
|
||||
|
||||
const devops_t os_devops = {
|
||||
.setup = setup_device,
|
||||
.close = close_device,
|
||||
.read = read_packet,
|
||||
.write = write_packet,
|
||||
.dump_stats = dump_device_stats,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -25,22 +25,21 @@
|
|||
|
||||
extern int device_fd;
|
||||
extern char *device;
|
||||
|
||||
extern char *iface;
|
||||
|
||||
typedef struct devops_t {
|
||||
bool (*setup)(void);
|
||||
void (*close)(void);
|
||||
bool (*read)(struct vpn_packet_t *);
|
||||
bool (*write)(struct vpn_packet_t *);
|
||||
void (*enable)(void); /* optional */
|
||||
void (*disable)(void); /* optional */
|
||||
bool (*read)(struct vpn_packet_t *packet);
|
||||
bool (*write)(struct vpn_packet_t *packet);
|
||||
void (*dump_stats)(void);
|
||||
} devops_t;
|
||||
|
||||
extern const devops_t os_devops;
|
||||
extern const devops_t dummy_devops;
|
||||
extern const devops_t raw_socket_devops;
|
||||
extern const devops_t multicast_devops;
|
||||
extern const devops_t fd_devops;
|
||||
extern const devops_t uml_devops;
|
||||
extern const devops_t vde_devops;
|
||||
extern devops_t devops;
|
||||
|
|
|
|||
42
src/digest.h
42
src/digest.h
|
|
@ -1,42 +0,0 @@
|
|||
#ifndef TINC_DIGEST_H
|
||||
#define TINC_DIGEST_H
|
||||
|
||||
/*
|
||||
digest.h -- header file digest.c
|
||||
Copyright (C) 2007-2016 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#define DIGEST_MAX_SIZE 64
|
||||
|
||||
#ifndef DISABLE_LEGACY
|
||||
|
||||
typedef struct digest digest_t;
|
||||
|
||||
extern digest_t *digest_open_by_name(const char *name, int maclength) __attribute__((__malloc__));
|
||||
extern digest_t *digest_open_by_nid(int nid, int maclength) __attribute__((__malloc__));
|
||||
extern void digest_close(digest_t *digest);
|
||||
extern bool digest_create(digest_t *digest, const void *indata, size_t inlen, void *outdata) __attribute__((__warn_unused_result__));
|
||||
extern bool digest_verify(digest_t *digest, const void *indata, size_t inlen, const void *digestdata) __attribute__((__warn_unused_result__));
|
||||
extern bool digest_set_key(digest_t *digest, const void *key, size_t len) __attribute__((__warn_unused_result__));
|
||||
extern int digest_get_nid(const digest_t *digest);
|
||||
extern size_t digest_keylength(const digest_t *digest);
|
||||
extern size_t digest_length(const digest_t *digest);
|
||||
extern bool digest_active(const digest_t *digest);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
22
src/dropin.c
22
src/dropin.c
|
|
@ -107,6 +107,7 @@ int vasprintf(char **buf, const char *fmt, va_list ap) {
|
|||
|
||||
va_copy(aq, ap);
|
||||
status = vsnprintf(*buf, len, fmt, aq);
|
||||
buf[len - 1] = 0;
|
||||
va_end(aq);
|
||||
|
||||
if(status >= 0) {
|
||||
|
|
@ -114,7 +115,7 @@ int vasprintf(char **buf, const char *fmt, va_list ap) {
|
|||
}
|
||||
|
||||
if(status > len - 1) {
|
||||
len = status + 1;
|
||||
len = status;
|
||||
va_copy(aq, ap);
|
||||
status = vsnprintf(*buf, len, fmt, aq);
|
||||
va_end(aq);
|
||||
|
|
@ -126,25 +127,16 @@ int vasprintf(char **buf, const char *fmt, va_list ap) {
|
|||
|
||||
#ifndef HAVE_GETTIMEOFDAY
|
||||
int gettimeofday(struct timeval *tv, void *tz) {
|
||||
#ifdef HAVE_MINGW
|
||||
FILETIME ft;
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
uint64_t lt = (uint64_t)ft.dwLowDateTime | ((uint64_t)ft.dwHighDateTime << 32);
|
||||
lt -= 116444736000000000ULL;
|
||||
tv->tv_sec = lt / 10000000;
|
||||
tv->tv_usec = (lt / 10) % 1000000;
|
||||
#else
|
||||
#warning No high resolution time source!
|
||||
tv->tv_sec = time(NULL);
|
||||
tv->tv_usec = 0;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_NANOSLEEP
|
||||
int nanosleep(const struct timespec *req, struct timespec *rem) {
|
||||
struct timeval tv = {req->tv_sec, req->tv_nsec / 1000};
|
||||
return select(0, NULL, NULL, NULL, &tv);
|
||||
#ifndef HAVE_USLEEP
|
||||
int usleep(long long usec) {
|
||||
struct timeval tv = {usec / 1000000, (usec / 1000) % 1000};
|
||||
select(0, NULL, NULL, NULL, &tv);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
50
src/dropin.h
50
src/dropin.h
|
|
@ -4,7 +4,7 @@
|
|||
/*
|
||||
dropin.h -- header file for dropin.c
|
||||
Copyright (C) 2000-2005 Ivo Timmermans,
|
||||
2000-2016 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2000-2011 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
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
|
||||
|
|
@ -21,50 +21,28 @@
|
|||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "fake-getaddrinfo.h"
|
||||
#include "fake-getnameinfo.h"
|
||||
|
||||
#ifndef HAVE_DAEMON
|
||||
extern int daemon(int, int);
|
||||
extern int daemon(int nochdir, int noclose);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_GET_CURRENT_DIR_NAME
|
||||
extern char *get_current_dir_name(void);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_ASPRINTF
|
||||
extern int asprintf(char **, const char *, ...);
|
||||
extern int vasprintf(char **, const char *, va_list ap);
|
||||
extern int asprintf(char **buf, const char *fmt, ...);
|
||||
extern int vasprintf(char **buf, const char *fmt, va_list ap);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_GETTIMEOFDAY
|
||||
extern int gettimeofday(struct timeval *, void *);
|
||||
extern int gettimeofday(struct timeval *tv, void *tz);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_NANOSLEEP
|
||||
extern int nanosleep(const struct timespec *req, struct timespec *rem);
|
||||
#endif
|
||||
|
||||
#ifndef timeradd
|
||||
#define timeradd(a, b, r) do {\
|
||||
(r)->tv_sec = (a)->tv_sec + (b)->tv_sec;\
|
||||
(r)->tv_usec = (a)->tv_usec + (b)->tv_usec;\
|
||||
if((r)->tv_usec >= 1000000)\
|
||||
(r)->tv_sec++, (r)->tv_usec -= 1000000;\
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#ifndef timersub
|
||||
#define timersub(a, b, r) do {\
|
||||
(r)->tv_sec = (a)->tv_sec - (b)->tv_sec;\
|
||||
(r)->tv_usec = (a)->tv_usec - (b)->tv_usec;\
|
||||
if((r)->tv_usec < 0)\
|
||||
(r)->tv_sec--, (r)->tv_usec += 1000000;\
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MINGW
|
||||
#define mkdir(a, b) mkdir(a)
|
||||
#ifndef SHUT_RDWR
|
||||
#define SHUT_RDWR SD_BOTH
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef EAI_SYSTEM
|
||||
#define EAI_SYSTEM 0
|
||||
#ifndef HAVE_USLEEP
|
||||
extern int usleep(long long usec);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
device.c -- Dummy device
|
||||
Copyright (C) 2011-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
Copyright (C) 2011 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
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
|
||||
|
|
@ -26,14 +26,19 @@
|
|||
|
||||
static const char *device_info = "dummy device";
|
||||
|
||||
static uint64_t device_total_in = 0;
|
||||
static uint64_t device_total_out = 0;
|
||||
|
||||
static bool setup_device(void) {
|
||||
device = xstrdup("dummy");
|
||||
iface = xstrdup("dummy");
|
||||
logger(DEBUG_ALWAYS, LOG_INFO, "%s (%s) is a %s", device, iface, device_info);
|
||||
logger(LOG_INFO, "%s (%s) is a %s", device, iface, device_info);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void close_device(void) {
|
||||
free(device);
|
||||
free(iface);
|
||||
}
|
||||
|
||||
static bool read_packet(vpn_packet_t *packet) {
|
||||
|
|
@ -42,13 +47,20 @@ static bool read_packet(vpn_packet_t *packet) {
|
|||
}
|
||||
|
||||
static bool write_packet(vpn_packet_t *packet) {
|
||||
(void)packet;
|
||||
device_total_out += packet->len;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void dump_device_stats(void) {
|
||||
logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
|
||||
logger(LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in);
|
||||
logger(LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
|
||||
}
|
||||
|
||||
const devops_t dummy_devops = {
|
||||
.setup = setup_device,
|
||||
.close = close_device,
|
||||
.read = read_packet,
|
||||
.write = write_packet,
|
||||
.dump_stats = dump_device_stats,
|
||||
};
|
||||
|
|
|
|||
34
src/ecdh.h
34
src/ecdh.h
|
|
@ -1,34 +0,0 @@
|
|||
#ifndef TINC_ECDH_H
|
||||
#define TINC_ECDH_H
|
||||
|
||||
/*
|
||||
ecdh.h -- header file for ecdh.c
|
||||
Copyright (C) 2011-2013 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#define ECDH_SIZE 32
|
||||
#define ECDH_SHARED_SIZE 32
|
||||
|
||||
#ifndef TINC_ECDH_INTERNAL
|
||||
typedef struct ecdh ecdh_t;
|
||||
#endif
|
||||
|
||||
extern ecdh_t *ecdh_generate_public(void *pubkey) __attribute__((__malloc__));
|
||||
extern bool ecdh_compute_shared(ecdh_t *ecdh, const void *pubkey, void *shared) __attribute__((__warn_unused_result__));
|
||||
extern void ecdh_free(ecdh_t *ecdh);
|
||||
|
||||
#endif
|
||||
37
src/ecdsa.h
37
src/ecdsa.h
|
|
@ -1,37 +0,0 @@
|
|||
#ifndef TINC_ECDSA_H
|
||||
#define TINC_ECDSA_H
|
||||
|
||||
/*
|
||||
ecdsa.h -- ECDSA key handling
|
||||
Copyright (C) 2011-2013 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef TINC_ECDSA_INTERNAL
|
||||
typedef struct ecdsa ecdsa_t;
|
||||
#endif
|
||||
|
||||
extern ecdsa_t *ecdsa_set_base64_public_key(const char *p) __attribute__((__malloc__));
|
||||
extern char *ecdsa_get_base64_public_key(ecdsa_t *ecdsa);
|
||||
extern ecdsa_t *ecdsa_read_pem_public_key(FILE *fp) __attribute__((__malloc__));
|
||||
extern ecdsa_t *ecdsa_read_pem_private_key(FILE *fp) __attribute__((__malloc__));
|
||||
extern size_t ecdsa_size(ecdsa_t *ecdsa);
|
||||
extern bool ecdsa_sign(ecdsa_t *ecdsa, const void *in, size_t inlen, void *out) __attribute__((__warn_unused_result__));
|
||||
extern bool ecdsa_verify(ecdsa_t *ecdsa, const void *in, size_t inlen, const void *out) __attribute__((__warn_unused_result__));
|
||||
extern bool ecdsa_active(ecdsa_t *ecdsa);
|
||||
extern void ecdsa_free(ecdsa_t *ecdsa);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
#ifndef TINC_ECDSAGEN_H
|
||||
#define TINC_ECDSAGEN_H
|
||||
|
||||
/*
|
||||
ecdsagen.h -- ECDSA key generation and export
|
||||
Copyright (C) 2011-2013 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "ecdsa.h"
|
||||
|
||||
extern ecdsa_t *ecdsa_generate(void) __attribute__((__malloc__));
|
||||
extern bool ecdsa_write_pem_public_key(ecdsa_t *ecdsa, FILE *fp) __attribute__((__warn_unused_result__));
|
||||
extern bool ecdsa_write_pem_private_key(ecdsa_t *ecdsa, FILE *fp) __attribute__((__warn_unused_result__));
|
||||
|
||||
#endif
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
/*
|
||||
ecdh.c -- Diffie-Hellman key exchange handling
|
||||
Copyright (C) 2011-2013 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "../system.h"
|
||||
|
||||
#include "ed25519.h"
|
||||
|
||||
#define TINC_ECDH_INTERNAL
|
||||
typedef struct ecdh_t {
|
||||
uint8_t private[64];
|
||||
} ecdh_t;
|
||||
|
||||
#include "../crypto.h"
|
||||
#include "../ecdh.h"
|
||||
#include "../xalloc.h"
|
||||
|
||||
ecdh_t *ecdh_generate_public(void *pubkey) {
|
||||
ecdh_t *ecdh = xzalloc(sizeof(*ecdh));
|
||||
|
||||
uint8_t seed[32];
|
||||
randomize(seed, sizeof(seed));
|
||||
ed25519_create_keypair(pubkey, ecdh->private, seed);
|
||||
|
||||
return ecdh;
|
||||
}
|
||||
|
||||
bool ecdh_compute_shared(ecdh_t *ecdh, const void *pubkey, void *shared) {
|
||||
ed25519_key_exchange(shared, pubkey, ecdh->private);
|
||||
free(ecdh);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ecdh_free(ecdh_t *ecdh) {
|
||||
free(ecdh);
|
||||
}
|
||||
|
|
@ -1,168 +0,0 @@
|
|||
/*
|
||||
ecdsa.c -- ECDSA key handling
|
||||
Copyright (C) 2011-2013 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "../system.h"
|
||||
|
||||
#include "ed25519.h"
|
||||
|
||||
#define TINC_ECDSA_INTERNAL
|
||||
typedef struct {
|
||||
uint8_t private[64];
|
||||
uint8_t public[32];
|
||||
} ecdsa_t;
|
||||
|
||||
#include "../logger.h"
|
||||
#include "../ecdsa.h"
|
||||
#include "../utils.h"
|
||||
#include "../xalloc.h"
|
||||
|
||||
// Get and set ECDSA keys
|
||||
//
|
||||
ecdsa_t *ecdsa_set_base64_public_key(const char *p) {
|
||||
int len = strlen(p);
|
||||
|
||||
if(len != 43) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Invalid size %d for public key!", len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ecdsa_t *ecdsa = xzalloc(sizeof(*ecdsa));
|
||||
len = b64decode(p, ecdsa->public, len);
|
||||
|
||||
if(len != 32) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Invalid format of public key! len = %d", len);
|
||||
free(ecdsa);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ecdsa;
|
||||
}
|
||||
|
||||
char *ecdsa_get_base64_public_key(ecdsa_t *ecdsa) {
|
||||
char *base64 = xmalloc(44);
|
||||
b64encode(ecdsa->public, base64, sizeof(ecdsa->public));
|
||||
|
||||
return base64;
|
||||
}
|
||||
|
||||
// Read PEM ECDSA keys
|
||||
|
||||
static bool read_pem(FILE *fp, const char *type, void *vbuf, size_t size) {
|
||||
char line[1024];
|
||||
bool data = false;
|
||||
size_t typelen = strlen(type);
|
||||
char *buf = vbuf;
|
||||
|
||||
while(fgets(line, sizeof(line), fp)) {
|
||||
if(!data) {
|
||||
if(strncmp(line, "-----BEGIN ", 11)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(strncmp(line + 11, type, typelen)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
data = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!strncmp(line, "-----END ", 9)) {
|
||||
break;
|
||||
}
|
||||
|
||||
size_t linelen = strcspn(line, "\r\n");
|
||||
size_t len = b64decode(line, line, linelen);
|
||||
|
||||
if(!len) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Invalid base64 data in PEM file\n");
|
||||
errno = EINVAL;
|
||||
return false;
|
||||
}
|
||||
|
||||
if(len > size) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Too much base64 data in PEM file\n");
|
||||
errno = EINVAL;
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(buf, line, len);
|
||||
buf += len;
|
||||
size -= len;
|
||||
}
|
||||
|
||||
if(size) {
|
||||
if(data) {
|
||||
errno = EINVAL;
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Too little base64 data in PEM file\n");
|
||||
} else {
|
||||
errno = ENOENT;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ecdsa_t *ecdsa_read_pem_public_key(FILE *fp) {
|
||||
ecdsa_t *ecdsa = xzalloc(sizeof(*ecdsa));
|
||||
|
||||
if(read_pem(fp, "ED25519 PUBLIC KEY", ecdsa->public, sizeof(ecdsa->public))) {
|
||||
return ecdsa;
|
||||
}
|
||||
|
||||
free(ecdsa);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ecdsa_t *ecdsa_read_pem_private_key(FILE *fp) {
|
||||
ecdsa_t *ecdsa = xmalloc(sizeof(*ecdsa));
|
||||
|
||||
if(read_pem(fp, "ED25519 PRIVATE KEY", ecdsa->private, sizeof(*ecdsa))) {
|
||||
return ecdsa;
|
||||
}
|
||||
|
||||
free(ecdsa);
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t ecdsa_size(ecdsa_t *ecdsa) {
|
||||
(void)ecdsa;
|
||||
return 64;
|
||||
}
|
||||
|
||||
// TODO: standardise output format?
|
||||
|
||||
bool ecdsa_sign(ecdsa_t *ecdsa, const void *in, size_t len, void *sig) {
|
||||
ed25519_sign(sig, in, len, ecdsa->public, ecdsa->private);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ecdsa_verify(ecdsa_t *ecdsa, const void *in, size_t len, const void *sig) {
|
||||
return ed25519_verify(sig, in, len, ecdsa->public);
|
||||
}
|
||||
|
||||
bool ecdsa_active(ecdsa_t *ecdsa) {
|
||||
return ecdsa;
|
||||
}
|
||||
|
||||
void ecdsa_free(ecdsa_t *ecdsa) {
|
||||
free(ecdsa);
|
||||
}
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
/*
|
||||
ecdsagen.c -- ECDSA key generation and export
|
||||
Copyright (C) 2011-2013 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "../system.h"
|
||||
|
||||
#include "ed25519.h"
|
||||
|
||||
#define TINC_ECDSA_INTERNAL
|
||||
typedef struct {
|
||||
uint8_t private[64];
|
||||
uint8_t public[32];
|
||||
} ecdsa_t;
|
||||
|
||||
#include "../crypto.h"
|
||||
#include "../ecdsagen.h"
|
||||
#include "../utils.h"
|
||||
#include "../xalloc.h"
|
||||
|
||||
// Generate ECDSA key
|
||||
|
||||
ecdsa_t *ecdsa_generate(void) {
|
||||
ecdsa_t *ecdsa = xzalloc(sizeof(*ecdsa));
|
||||
|
||||
uint8_t seed[32];
|
||||
randomize(seed, sizeof(seed));
|
||||
ed25519_create_keypair(ecdsa->public, ecdsa->private, seed);
|
||||
|
||||
return ecdsa;
|
||||
}
|
||||
|
||||
// Write PEM ECDSA keys
|
||||
|
||||
static bool write_pem(FILE *fp, const char *type, void *vbuf, size_t size) {
|
||||
fprintf(fp, "-----BEGIN %s-----\n", type);
|
||||
|
||||
char *buf = vbuf;
|
||||
char base64[65];
|
||||
|
||||
while(size) {
|
||||
size_t todo = size > 48 ? 48 : size;
|
||||
b64encode(buf, base64, todo);
|
||||
fprintf(fp, "%s\n", base64);
|
||||
buf += todo;
|
||||
size -= todo;
|
||||
}
|
||||
|
||||
fprintf(fp, "-----END %s-----\n", type);
|
||||
return !ferror(fp);
|
||||
}
|
||||
|
||||
bool ecdsa_write_pem_public_key(ecdsa_t *ecdsa, FILE *fp) {
|
||||
return write_pem(fp, "ED25519 PUBLIC KEY", ecdsa->public, sizeof(ecdsa->public));
|
||||
}
|
||||
|
||||
bool ecdsa_write_pem_private_key(ecdsa_t *ecdsa, FILE *fp) {
|
||||
return write_pem(fp, "ED25519 PRIVATE KEY", ecdsa->private, sizeof(*ecdsa));
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
#ifndef ED25519_H
|
||||
#define ED25519_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#if defined(ED25519_BUILD_DLL)
|
||||
#define ED25519_DECLSPEC __declspec(dllexport)
|
||||
#elif defined(ED25519_DLL)
|
||||
#define ED25519_DECLSPEC __declspec(dllimport)
|
||||
#else
|
||||
#define ED25519_DECLSPEC
|
||||
#endif
|
||||
#else
|
||||
#define ED25519_DECLSPEC
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef ED25519_NO_SEED
|
||||
int ED25519_DECLSPEC ed25519_create_seed(unsigned char *seed);
|
||||
#endif
|
||||
|
||||
void ED25519_DECLSPEC ed25519_create_keypair(unsigned char *public_key, unsigned char *private_key, const unsigned char *seed);
|
||||
void ED25519_DECLSPEC ed25519_sign(unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *public_key, const unsigned char *private_key);
|
||||
int ED25519_DECLSPEC ed25519_verify(const unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *private_key);
|
||||
void ED25519_DECLSPEC ed25519_key_exchange(unsigned char *shared_secret, const unsigned char *public_key, const unsigned char *private_key);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
1511
src/ed25519/fe.c
1511
src/ed25519/fe.c
File diff suppressed because it is too large
Load diff
|
|
@ -1,41 +0,0 @@
|
|||
#ifndef FE_H
|
||||
#define FE_H
|
||||
|
||||
#include "fixedint.h"
|
||||
|
||||
|
||||
/*
|
||||
fe means field element.
|
||||
Here the field is \Z/(2^255-19).
|
||||
An element t, entries t[0]...t[9], represents the integer
|
||||
t[0]+2^26 t[1]+2^51 t[2]+2^77 t[3]+2^102 t[4]+...+2^230 t[9].
|
||||
Bounds on each t[i] vary depending on context.
|
||||
*/
|
||||
|
||||
|
||||
typedef int32_t fe[10];
|
||||
|
||||
|
||||
void fe_0(fe h);
|
||||
void fe_1(fe h);
|
||||
|
||||
void fe_frombytes(fe h, const unsigned char *s);
|
||||
void fe_tobytes(unsigned char *s, const fe h);
|
||||
|
||||
void fe_copy(fe h, const fe f);
|
||||
int fe_isnegative(const fe f);
|
||||
int fe_isnonzero(const fe f);
|
||||
void fe_cmov(fe f, const fe g, unsigned int b);
|
||||
void fe_cswap(fe f, fe g, unsigned int b);
|
||||
|
||||
void fe_neg(fe h, const fe f);
|
||||
void fe_add(fe h, const fe f, const fe g);
|
||||
void fe_invert(fe out, const fe z);
|
||||
void fe_sq(fe h, const fe f);
|
||||
void fe_sq2(fe h, const fe f);
|
||||
void fe_mul(fe h, const fe f, const fe g);
|
||||
void fe_mul121666(fe h, fe f);
|
||||
void fe_pow22523(fe out, const fe z);
|
||||
void fe_sub(fe h, const fe f, const fe g);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,91 +0,0 @@
|
|||
#ifndef TINC_FIXEDINT_H
|
||||
#define TINC_FIXEDINT_H
|
||||
|
||||
/*
|
||||
Portable header to provide the 32 and 64 bits type.
|
||||
|
||||
Not a compatible replacement for <stdint.h>, do not blindly use it as such.
|
||||
*/
|
||||
|
||||
#if ((defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L) || (defined(__WATCOMC__) && (defined(_STDINT_H_INCLUDED) || __WATCOMC__ >= 1250)) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_) || defined(__UINT_FAST64_TYPE__)) )) && !defined(FIXEDINT_H_INCLUDED)
|
||||
#include <stdint.h>
|
||||
#define FIXEDINT_H_INCLUDED
|
||||
|
||||
#if defined(__WATCOMC__) && __WATCOMC__ >= 1250 && !defined(UINT64_C)
|
||||
#include <limits.h>
|
||||
#define UINT64_C(x) (x + (UINT64_MAX - UINT64_MAX))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef FIXEDINT_H_INCLUDED
|
||||
#define FIXEDINT_H_INCLUDED
|
||||
|
||||
/* (u)int32_t */
|
||||
#ifndef uint32_t
|
||||
#if (ULONG_MAX == 0xffffffffUL)
|
||||
typedef unsigned long uint32_t;
|
||||
#elif (UINT_MAX == 0xffffffffUL)
|
||||
typedef unsigned int uint32_t;
|
||||
#elif (USHRT_MAX == 0xffffffffUL)
|
||||
typedef unsigned short uint32_t;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef int32_t
|
||||
#if (LONG_MAX == 0x7fffffffL)
|
||||
typedef signed long int32_t;
|
||||
#elif (INT_MAX == 0x7fffffffL)
|
||||
typedef signed int int32_t;
|
||||
#elif (SHRT_MAX == 0x7fffffffL)
|
||||
typedef signed short int32_t;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/* (u)int64_t */
|
||||
#if (defined(__STDC__) && defined(__STDC_VERSION__) && __STDC__ && __STDC_VERSION__ >= 199901L)
|
||||
typedef long long int64_t;
|
||||
typedef unsigned long long uint64_t;
|
||||
|
||||
#define UINT64_C(v) v ##ULL
|
||||
#define INT64_C(v) v ##LL
|
||||
#elif defined(__GNUC__)
|
||||
__extension__ typedef long long int64_t;
|
||||
__extension__ typedef unsigned long long uint64_t;
|
||||
|
||||
#define UINT64_C(v) v ##ULL
|
||||
#define INT64_C(v) v ##LL
|
||||
#elif defined(__MWERKS__) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) || defined(__APPLE_CC__) || defined(_LONG_LONG) || defined(_CRAYC)
|
||||
typedef long long int64_t;
|
||||
typedef unsigned long long uint64_t;
|
||||
|
||||
#define UINT64_C(v) v ##ULL
|
||||
#define INT64_C(v) v ##LL
|
||||
#elif (defined(__WATCOMC__) && defined(__WATCOM_INT64__)) || (defined(_MSC_VER) && _INTEGRAL_MAX_BITS >= 64) || (defined(__BORLANDC__) && __BORLANDC__ > 0x460) || defined(__alpha) || defined(__DECC)
|
||||
typedef __int64 int64_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
|
||||
#define UINT64_C(v) v ##UI64
|
||||
#define INT64_C(v) v ##I64
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static inline unsigned char shlu8(unsigned char a, uint32_t b) {
|
||||
return a << b;
|
||||
}
|
||||
|
||||
static inline int32_t shl32(uint32_t a, uint32_t b) {
|
||||
return a << b;
|
||||
}
|
||||
|
||||
static inline int64_t shl64(uint64_t a, uint32_t b) {
|
||||
return a << b;
|
||||
}
|
||||
|
||||
static inline uint64_t shlu64(uint64_t a, uint32_t b) {
|
||||
return a << b;
|
||||
}
|
||||
|
||||
#endif
|
||||
467
src/ed25519/ge.c
467
src/ed25519/ge.c
|
|
@ -1,467 +0,0 @@
|
|||
#include "ge.h"
|
||||
#include "precomp_data.h"
|
||||
|
||||
|
||||
/*
|
||||
r = p + q
|
||||
*/
|
||||
|
||||
void ge_add(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q) {
|
||||
fe t0;
|
||||
fe_add(r->X, p->Y, p->X);
|
||||
fe_sub(r->Y, p->Y, p->X);
|
||||
fe_mul(r->Z, r->X, q->YplusX);
|
||||
fe_mul(r->Y, r->Y, q->YminusX);
|
||||
fe_mul(r->T, q->T2d, p->T);
|
||||
fe_mul(r->X, p->Z, q->Z);
|
||||
fe_add(t0, r->X, r->X);
|
||||
fe_sub(r->X, r->Z, r->Y);
|
||||
fe_add(r->Y, r->Z, r->Y);
|
||||
fe_add(r->Z, t0, r->T);
|
||||
fe_sub(r->T, t0, r->T);
|
||||
}
|
||||
|
||||
|
||||
static void slide(signed char *r, const unsigned char *a) {
|
||||
int i;
|
||||
int b;
|
||||
int k;
|
||||
|
||||
for(i = 0; i < 256; ++i) {
|
||||
r[i] = 1 & (a[i >> 3] >> (i & 7));
|
||||
}
|
||||
|
||||
for(i = 0; i < 256; ++i)
|
||||
if(r[i]) {
|
||||
for(b = 1; b <= 6 && i + b < 256; ++b) {
|
||||
if(r[i + b]) {
|
||||
if(r[i] + (r[i + b] << b) <= 15) {
|
||||
r[i] += r[i + b] << b;
|
||||
r[i + b] = 0;
|
||||
} else if(r[i] - (r[i + b] << b) >= -15) {
|
||||
r[i] -= r[i + b] << b;
|
||||
|
||||
for(k = i + b; k < 256; ++k) {
|
||||
if(!r[k]) {
|
||||
r[k] = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
r[k] = 0;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
r = a * A + b * B
|
||||
where a = a[0]+256*a[1]+...+256^31 a[31].
|
||||
and b = b[0]+256*b[1]+...+256^31 b[31].
|
||||
B is the Ed25519 base point (x,4/5) with x positive.
|
||||
*/
|
||||
|
||||
void ge_double_scalarmult_vartime(ge_p2 *r, const unsigned char *a, const ge_p3 *A, const unsigned char *b) {
|
||||
signed char aslide[256];
|
||||
signed char bslide[256];
|
||||
ge_cached Ai[8]; /* A,3A,5A,7A,9A,11A,13A,15A */
|
||||
ge_p1p1 t;
|
||||
ge_p3 u;
|
||||
ge_p3 A2;
|
||||
int i;
|
||||
slide(aslide, a);
|
||||
slide(bslide, b);
|
||||
ge_p3_to_cached(&Ai[0], A);
|
||||
ge_p3_dbl(&t, A);
|
||||
ge_p1p1_to_p3(&A2, &t);
|
||||
ge_add(&t, &A2, &Ai[0]);
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_p3_to_cached(&Ai[1], &u);
|
||||
ge_add(&t, &A2, &Ai[1]);
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_p3_to_cached(&Ai[2], &u);
|
||||
ge_add(&t, &A2, &Ai[2]);
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_p3_to_cached(&Ai[3], &u);
|
||||
ge_add(&t, &A2, &Ai[3]);
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_p3_to_cached(&Ai[4], &u);
|
||||
ge_add(&t, &A2, &Ai[4]);
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_p3_to_cached(&Ai[5], &u);
|
||||
ge_add(&t, &A2, &Ai[5]);
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_p3_to_cached(&Ai[6], &u);
|
||||
ge_add(&t, &A2, &Ai[6]);
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_p3_to_cached(&Ai[7], &u);
|
||||
ge_p2_0(r);
|
||||
|
||||
for(i = 255; i >= 0; --i) {
|
||||
if(aslide[i] || bslide[i]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for(; i >= 0; --i) {
|
||||
ge_p2_dbl(&t, r);
|
||||
|
||||
if(aslide[i] > 0) {
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_add(&t, &u, &Ai[aslide[i] / 2]);
|
||||
} else if(aslide[i] < 0) {
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_sub(&t, &u, &Ai[(-aslide[i]) / 2]);
|
||||
}
|
||||
|
||||
if(bslide[i] > 0) {
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_madd(&t, &u, &Bi[bslide[i] / 2]);
|
||||
} else if(bslide[i] < 0) {
|
||||
ge_p1p1_to_p3(&u, &t);
|
||||
ge_msub(&t, &u, &Bi[(-bslide[i]) / 2]);
|
||||
}
|
||||
|
||||
ge_p1p1_to_p2(r, &t);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static const fe d = {
|
||||
-10913610, 13857413, -15372611, 6949391, 114729, -8787816, -6275908, -3247719, -18696448, -12055116
|
||||
};
|
||||
|
||||
static const fe sqrtm1 = {
|
||||
-32595792, -7943725, 9377950, 3500415, 12389472, -272473, -25146209, -2005654, 326686, 11406482
|
||||
};
|
||||
|
||||
int ge_frombytes_negate_vartime(ge_p3 *h, const unsigned char *s) {
|
||||
fe u;
|
||||
fe v;
|
||||
fe v3;
|
||||
fe vxx;
|
||||
fe check;
|
||||
fe_frombytes(h->Y, s);
|
||||
fe_1(h->Z);
|
||||
fe_sq(u, h->Y);
|
||||
fe_mul(v, u, d);
|
||||
fe_sub(u, u, h->Z); /* u = y^2-1 */
|
||||
fe_add(v, v, h->Z); /* v = dy^2+1 */
|
||||
fe_sq(v3, v);
|
||||
fe_mul(v3, v3, v); /* v3 = v^3 */
|
||||
fe_sq(h->X, v3);
|
||||
fe_mul(h->X, h->X, v);
|
||||
fe_mul(h->X, h->X, u); /* x = uv^7 */
|
||||
fe_pow22523(h->X, h->X); /* x = (uv^7)^((q-5)/8) */
|
||||
fe_mul(h->X, h->X, v3);
|
||||
fe_mul(h->X, h->X, u); /* x = uv^3(uv^7)^((q-5)/8) */
|
||||
fe_sq(vxx, h->X);
|
||||
fe_mul(vxx, vxx, v);
|
||||
fe_sub(check, vxx, u); /* vx^2-u */
|
||||
|
||||
if(fe_isnonzero(check)) {
|
||||
fe_add(check, vxx, u); /* vx^2+u */
|
||||
|
||||
if(fe_isnonzero(check)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
fe_mul(h->X, h->X, sqrtm1);
|
||||
}
|
||||
|
||||
if(fe_isnegative(h->X) == (s[31] >> 7)) {
|
||||
fe_neg(h->X, h->X);
|
||||
}
|
||||
|
||||
fe_mul(h->T, h->X, h->Y);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
r = p + q
|
||||
*/
|
||||
|
||||
void ge_madd(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q) {
|
||||
fe t0;
|
||||
fe_add(r->X, p->Y, p->X);
|
||||
fe_sub(r->Y, p->Y, p->X);
|
||||
fe_mul(r->Z, r->X, q->yplusx);
|
||||
fe_mul(r->Y, r->Y, q->yminusx);
|
||||
fe_mul(r->T, q->xy2d, p->T);
|
||||
fe_add(t0, p->Z, p->Z);
|
||||
fe_sub(r->X, r->Z, r->Y);
|
||||
fe_add(r->Y, r->Z, r->Y);
|
||||
fe_add(r->Z, t0, r->T);
|
||||
fe_sub(r->T, t0, r->T);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
r = p - q
|
||||
*/
|
||||
|
||||
void ge_msub(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q) {
|
||||
fe t0;
|
||||
|
||||
fe_add(r->X, p->Y, p->X);
|
||||
fe_sub(r->Y, p->Y, p->X);
|
||||
fe_mul(r->Z, r->X, q->yminusx);
|
||||
fe_mul(r->Y, r->Y, q->yplusx);
|
||||
fe_mul(r->T, q->xy2d, p->T);
|
||||
fe_add(t0, p->Z, p->Z);
|
||||
fe_sub(r->X, r->Z, r->Y);
|
||||
fe_add(r->Y, r->Z, r->Y);
|
||||
fe_sub(r->Z, t0, r->T);
|
||||
fe_add(r->T, t0, r->T);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
r = p
|
||||
*/
|
||||
|
||||
void ge_p1p1_to_p2(ge_p2 *r, const ge_p1p1 *p) {
|
||||
fe_mul(r->X, p->X, p->T);
|
||||
fe_mul(r->Y, p->Y, p->Z);
|
||||
fe_mul(r->Z, p->Z, p->T);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
r = p
|
||||
*/
|
||||
|
||||
void ge_p1p1_to_p3(ge_p3 *r, const ge_p1p1 *p) {
|
||||
fe_mul(r->X, p->X, p->T);
|
||||
fe_mul(r->Y, p->Y, p->Z);
|
||||
fe_mul(r->Z, p->Z, p->T);
|
||||
fe_mul(r->T, p->X, p->Y);
|
||||
}
|
||||
|
||||
|
||||
void ge_p2_0(ge_p2 *h) {
|
||||
fe_0(h->X);
|
||||
fe_1(h->Y);
|
||||
fe_1(h->Z);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
r = 2 * p
|
||||
*/
|
||||
|
||||
void ge_p2_dbl(ge_p1p1 *r, const ge_p2 *p) {
|
||||
fe t0;
|
||||
|
||||
fe_sq(r->X, p->X);
|
||||
fe_sq(r->Z, p->Y);
|
||||
fe_sq2(r->T, p->Z);
|
||||
fe_add(r->Y, p->X, p->Y);
|
||||
fe_sq(t0, r->Y);
|
||||
fe_add(r->Y, r->Z, r->X);
|
||||
fe_sub(r->Z, r->Z, r->X);
|
||||
fe_sub(r->X, t0, r->Y);
|
||||
fe_sub(r->T, r->T, r->Z);
|
||||
}
|
||||
|
||||
|
||||
void ge_p3_0(ge_p3 *h) {
|
||||
fe_0(h->X);
|
||||
fe_1(h->Y);
|
||||
fe_1(h->Z);
|
||||
fe_0(h->T);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
r = 2 * p
|
||||
*/
|
||||
|
||||
void ge_p3_dbl(ge_p1p1 *r, const ge_p3 *p) {
|
||||
ge_p2 q;
|
||||
ge_p3_to_p2(&q, p);
|
||||
ge_p2_dbl(r, &q);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
r = p
|
||||
*/
|
||||
|
||||
static const fe d2 = {
|
||||
-21827239, -5839606, -30745221, 13898782, 229458, 15978800, -12551817, -6495438, 29715968, 9444199
|
||||
};
|
||||
|
||||
void ge_p3_to_cached(ge_cached *r, const ge_p3 *p) {
|
||||
fe_add(r->YplusX, p->Y, p->X);
|
||||
fe_sub(r->YminusX, p->Y, p->X);
|
||||
fe_copy(r->Z, p->Z);
|
||||
fe_mul(r->T2d, p->T, d2);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
r = p
|
||||
*/
|
||||
|
||||
void ge_p3_to_p2(ge_p2 *r, const ge_p3 *p) {
|
||||
fe_copy(r->X, p->X);
|
||||
fe_copy(r->Y, p->Y);
|
||||
fe_copy(r->Z, p->Z);
|
||||
}
|
||||
|
||||
|
||||
void ge_p3_tobytes(unsigned char *s, const ge_p3 *h) {
|
||||
fe recip;
|
||||
fe x;
|
||||
fe y;
|
||||
fe_invert(recip, h->Z);
|
||||
fe_mul(x, h->X, recip);
|
||||
fe_mul(y, h->Y, recip);
|
||||
fe_tobytes(s, y);
|
||||
s[31] ^= fe_isnegative(x) << 7;
|
||||
}
|
||||
|
||||
|
||||
static unsigned char equal(signed char b, signed char c) {
|
||||
unsigned char ub = b;
|
||||
unsigned char uc = c;
|
||||
unsigned char x = ub ^ uc; /* 0: yes; 1..255: no */
|
||||
uint64_t y = x; /* 0: yes; 1..255: no */
|
||||
y -= 1; /* large: yes; 0..254: no */
|
||||
y >>= 63; /* 1: yes; 0: no */
|
||||
return (unsigned char) y;
|
||||
}
|
||||
|
||||
static unsigned char negative(signed char b) {
|
||||
uint64_t x = b; /* 18446744073709551361..18446744073709551615: yes; 0..255: no */
|
||||
x >>= 63; /* 1: yes; 0: no */
|
||||
return (unsigned char) x;
|
||||
}
|
||||
|
||||
static void cmov(ge_precomp *t, ge_precomp *u, unsigned char b) {
|
||||
fe_cmov(t->yplusx, u->yplusx, b);
|
||||
fe_cmov(t->yminusx, u->yminusx, b);
|
||||
fe_cmov(t->xy2d, u->xy2d, b);
|
||||
}
|
||||
|
||||
|
||||
static void select(ge_precomp *t, int pos, signed char b) {
|
||||
ge_precomp minust;
|
||||
unsigned char bnegative = negative(b);
|
||||
unsigned char babs = b - shlu8(((-bnegative) & b), 1);
|
||||
fe_1(t->yplusx);
|
||||
fe_1(t->yminusx);
|
||||
fe_0(t->xy2d);
|
||||
cmov(t, &base[pos][0], equal(babs, 1));
|
||||
cmov(t, &base[pos][1], equal(babs, 2));
|
||||
cmov(t, &base[pos][2], equal(babs, 3));
|
||||
cmov(t, &base[pos][3], equal(babs, 4));
|
||||
cmov(t, &base[pos][4], equal(babs, 5));
|
||||
cmov(t, &base[pos][5], equal(babs, 6));
|
||||
cmov(t, &base[pos][6], equal(babs, 7));
|
||||
cmov(t, &base[pos][7], equal(babs, 8));
|
||||
fe_copy(minust.yplusx, t->yminusx);
|
||||
fe_copy(minust.yminusx, t->yplusx);
|
||||
fe_neg(minust.xy2d, t->xy2d);
|
||||
cmov(t, &minust, bnegative);
|
||||
}
|
||||
|
||||
/*
|
||||
h = a * B
|
||||
where a = a[0]+256*a[1]+...+256^31 a[31]
|
||||
B is the Ed25519 base point (x,4/5) with x positive.
|
||||
|
||||
Preconditions:
|
||||
a[31] <= 127
|
||||
*/
|
||||
|
||||
void ge_scalarmult_base(ge_p3 *h, const unsigned char *a) {
|
||||
signed char e[64];
|
||||
signed char carry;
|
||||
ge_p1p1 r;
|
||||
ge_p2 s;
|
||||
ge_precomp t;
|
||||
int i;
|
||||
|
||||
for(i = 0; i < 32; ++i) {
|
||||
e[2 * i + 0] = (a[i] >> 0) & 15;
|
||||
e[2 * i + 1] = (a[i] >> 4) & 15;
|
||||
}
|
||||
|
||||
/* each e[i] is between 0 and 15 */
|
||||
/* e[63] is between 0 and 7 */
|
||||
carry = 0;
|
||||
|
||||
for(i = 0; i < 63; ++i) {
|
||||
e[i] += carry;
|
||||
carry = e[i] + 8;
|
||||
carry >>= 4;
|
||||
e[i] -= shl32(carry, 4);
|
||||
}
|
||||
|
||||
e[63] += carry;
|
||||
/* each e[i] is between -8 and 8 */
|
||||
ge_p3_0(h);
|
||||
|
||||
for(i = 1; i < 64; i += 2) {
|
||||
select(&t, i / 2, e[i]);
|
||||
ge_madd(&r, h, &t);
|
||||
ge_p1p1_to_p3(h, &r);
|
||||
}
|
||||
|
||||
ge_p3_dbl(&r, h);
|
||||
ge_p1p1_to_p2(&s, &r);
|
||||
ge_p2_dbl(&r, &s);
|
||||
ge_p1p1_to_p2(&s, &r);
|
||||
ge_p2_dbl(&r, &s);
|
||||
ge_p1p1_to_p2(&s, &r);
|
||||
ge_p2_dbl(&r, &s);
|
||||
ge_p1p1_to_p3(h, &r);
|
||||
|
||||
for(i = 0; i < 64; i += 2) {
|
||||
select(&t, i / 2, e[i]);
|
||||
ge_madd(&r, h, &t);
|
||||
ge_p1p1_to_p3(h, &r);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
r = p - q
|
||||
*/
|
||||
|
||||
void ge_sub(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q) {
|
||||
fe t0;
|
||||
|
||||
fe_add(r->X, p->Y, p->X);
|
||||
fe_sub(r->Y, p->Y, p->X);
|
||||
fe_mul(r->Z, r->X, q->YminusX);
|
||||
fe_mul(r->Y, r->Y, q->YplusX);
|
||||
fe_mul(r->T, q->T2d, p->T);
|
||||
fe_mul(r->X, p->Z, q->Z);
|
||||
fe_add(t0, r->X, r->X);
|
||||
fe_sub(r->X, r->Z, r->Y);
|
||||
fe_add(r->Y, r->Z, r->Y);
|
||||
fe_sub(r->Z, t0, r->T);
|
||||
fe_add(r->T, t0, r->T);
|
||||
}
|
||||
|
||||
|
||||
void ge_tobytes(unsigned char *s, const ge_p2 *h) {
|
||||
fe recip;
|
||||
fe x;
|
||||
fe y;
|
||||
fe_invert(recip, h->Z);
|
||||
fe_mul(x, h->X, recip);
|
||||
fe_mul(y, h->Y, recip);
|
||||
fe_tobytes(s, y);
|
||||
s[31] ^= fe_isnegative(x) << 7;
|
||||
}
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
#ifndef GE_H
|
||||
#define GE_H
|
||||
|
||||
#include "fe.h"
|
||||
|
||||
|
||||
/*
|
||||
ge means group element.
|
||||
|
||||
Here the group is the set of pairs (x,y) of field elements (see fe.h)
|
||||
satisfying -x^2 + y^2 = 1 + d x^2y^2
|
||||
where d = -121665/121666.
|
||||
|
||||
Representations:
|
||||
ge_p2 (projective): (X:Y:Z) satisfying x=X/Z, y=Y/Z
|
||||
ge_p3 (extended): (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT
|
||||
ge_p1p1 (completed): ((X:Z),(Y:T)) satisfying x=X/Z, y=Y/T
|
||||
ge_precomp (Duif): (y+x,y-x,2dxy)
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
fe X;
|
||||
fe Y;
|
||||
fe Z;
|
||||
} ge_p2;
|
||||
|
||||
typedef struct {
|
||||
fe X;
|
||||
fe Y;
|
||||
fe Z;
|
||||
fe T;
|
||||
} ge_p3;
|
||||
|
||||
typedef struct {
|
||||
fe X;
|
||||
fe Y;
|
||||
fe Z;
|
||||
fe T;
|
||||
} ge_p1p1;
|
||||
|
||||
typedef struct {
|
||||
fe yplusx;
|
||||
fe yminusx;
|
||||
fe xy2d;
|
||||
} ge_precomp;
|
||||
|
||||
typedef struct {
|
||||
fe YplusX;
|
||||
fe YminusX;
|
||||
fe Z;
|
||||
fe T2d;
|
||||
} ge_cached;
|
||||
|
||||
void ge_p3_tobytes(unsigned char *s, const ge_p3 *h);
|
||||
void ge_tobytes(unsigned char *s, const ge_p2 *h);
|
||||
int ge_frombytes_negate_vartime(ge_p3 *h, const unsigned char *s);
|
||||
|
||||
void ge_add(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q);
|
||||
void ge_sub(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q);
|
||||
void ge_double_scalarmult_vartime(ge_p2 *r, const unsigned char *a, const ge_p3 *A, const unsigned char *b);
|
||||
void ge_madd(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q);
|
||||
void ge_msub(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q);
|
||||
void ge_scalarmult_base(ge_p3 *h, const unsigned char *a);
|
||||
|
||||
void ge_p1p1_to_p2(ge_p2 *r, const ge_p1p1 *p);
|
||||
void ge_p1p1_to_p3(ge_p3 *r, const ge_p1p1 *p);
|
||||
void ge_p2_0(ge_p2 *h);
|
||||
void ge_p2_dbl(ge_p1p1 *r, const ge_p2 *p);
|
||||
void ge_p3_0(ge_p3 *h);
|
||||
void ge_p3_dbl(ge_p1p1 *r, const ge_p3 *p);
|
||||
void ge_p3_to_cached(ge_cached *r, const ge_p3 *p);
|
||||
void ge_p3_to_p2(ge_p2 *r, const ge_p3 *p);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,80 +0,0 @@
|
|||
#include "ed25519.h"
|
||||
#include "fe.h"
|
||||
|
||||
void ed25519_key_exchange(unsigned char *shared_secret, const unsigned char *public_key, const unsigned char *private_key) {
|
||||
unsigned char e[32];
|
||||
unsigned int i;
|
||||
|
||||
fe x1;
|
||||
fe x2;
|
||||
fe z2;
|
||||
fe x3;
|
||||
fe z3;
|
||||
fe tmp0;
|
||||
fe tmp1;
|
||||
|
||||
int pos;
|
||||
unsigned int swap;
|
||||
unsigned int b;
|
||||
|
||||
/* copy the private key and make sure it's valid */
|
||||
for(i = 0; i < 32; ++i) {
|
||||
e[i] = private_key[i];
|
||||
}
|
||||
|
||||
e[0] &= 248;
|
||||
e[31] &= 63;
|
||||
e[31] |= 64;
|
||||
|
||||
/* unpack the public key and convert edwards to montgomery */
|
||||
/* due to CodesInChaos: montgomeryX = (edwardsY + 1)*inverse(1 - edwardsY) mod p */
|
||||
fe_frombytes(x1, public_key);
|
||||
fe_1(tmp1);
|
||||
fe_add(tmp0, x1, tmp1);
|
||||
fe_sub(tmp1, tmp1, x1);
|
||||
fe_invert(tmp1, tmp1);
|
||||
fe_mul(x1, tmp0, tmp1);
|
||||
|
||||
fe_1(x2);
|
||||
fe_0(z2);
|
||||
fe_copy(x3, x1);
|
||||
fe_1(z3);
|
||||
|
||||
swap = 0;
|
||||
|
||||
for(pos = 254; pos >= 0; --pos) {
|
||||
b = e[pos / 8] >> (pos & 7);
|
||||
b &= 1;
|
||||
swap ^= b;
|
||||
fe_cswap(x2, x3, swap);
|
||||
fe_cswap(z2, z3, swap);
|
||||
swap = b;
|
||||
|
||||
/* from montgomery.h */
|
||||
fe_sub(tmp0, x3, z3);
|
||||
fe_sub(tmp1, x2, z2);
|
||||
fe_add(x2, x2, z2);
|
||||
fe_add(z2, x3, z3);
|
||||
fe_mul(z3, tmp0, x2);
|
||||
fe_mul(z2, z2, tmp1);
|
||||
fe_sq(tmp0, tmp1);
|
||||
fe_sq(tmp1, x2);
|
||||
fe_add(x3, z3, z2);
|
||||
fe_sub(z2, z3, z2);
|
||||
fe_mul(x2, tmp1, tmp0);
|
||||
fe_sub(tmp1, tmp1, tmp0);
|
||||
fe_sq(z2, z2);
|
||||
fe_mul121666(z3, tmp1);
|
||||
fe_sq(x3, x3);
|
||||
fe_add(tmp0, tmp0, z3);
|
||||
fe_mul(z3, x1, z2);
|
||||
fe_mul(z2, tmp1, tmp0);
|
||||
}
|
||||
|
||||
fe_cswap(x2, x3, swap);
|
||||
fe_cswap(z2, z3, swap);
|
||||
|
||||
fe_invert(z2, z2);
|
||||
fe_mul(x2, x2, z2);
|
||||
fe_tobytes(shared_secret, x2);
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
#include "ed25519.h"
|
||||
#include "sha512.h"
|
||||
#include "ge.h"
|
||||
|
||||
|
||||
void ed25519_create_keypair(unsigned char *public_key, unsigned char *private_key, const unsigned char *seed) {
|
||||
ge_p3 A;
|
||||
|
||||
sha512(seed, 32, private_key);
|
||||
private_key[0] &= 248;
|
||||
private_key[31] &= 63;
|
||||
private_key[31] |= 64;
|
||||
|
||||
ge_scalarmult_base(&A, private_key);
|
||||
ge_p3_tobytes(public_key, &A);
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
785
src/ed25519/sc.c
785
src/ed25519/sc.c
|
|
@ -1,785 +0,0 @@
|
|||
#include "fixedint.h"
|
||||
#include "sc.h"
|
||||
|
||||
static uint64_t load_3(const unsigned char *in) {
|
||||
uint64_t result;
|
||||
|
||||
result = in[0];
|
||||
result |= shlu64(in[1], 8);
|
||||
result |= shlu64(in[2], 16);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static uint64_t load_4(const unsigned char *in) {
|
||||
uint64_t result;
|
||||
|
||||
result = in[0];
|
||||
result |= shlu64(in[1], 8);
|
||||
result |= shlu64(in[2], 16);
|
||||
result |= shlu64(in[3], 24);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
Input:
|
||||
s[0]+256*s[1]+...+256^63*s[63] = s
|
||||
|
||||
Output:
|
||||
s[0]+256*s[1]+...+256^31*s[31] = s mod l
|
||||
where l = 2^252 + 27742317777372353535851937790883648493.
|
||||
Overwrites s in place.
|
||||
*/
|
||||
|
||||
void sc_reduce(unsigned char *s) {
|
||||
int64_t s0 = 2097151 & load_3(s);
|
||||
int64_t s1 = 2097151 & (load_4(s + 2) >> 5);
|
||||
int64_t s2 = 2097151 & (load_3(s + 5) >> 2);
|
||||
int64_t s3 = 2097151 & (load_4(s + 7) >> 7);
|
||||
int64_t s4 = 2097151 & (load_4(s + 10) >> 4);
|
||||
int64_t s5 = 2097151 & (load_3(s + 13) >> 1);
|
||||
int64_t s6 = 2097151 & (load_4(s + 15) >> 6);
|
||||
int64_t s7 = 2097151 & (load_3(s + 18) >> 3);
|
||||
int64_t s8 = 2097151 & load_3(s + 21);
|
||||
int64_t s9 = 2097151 & (load_4(s + 23) >> 5);
|
||||
int64_t s10 = 2097151 & (load_3(s + 26) >> 2);
|
||||
int64_t s11 = 2097151 & (load_4(s + 28) >> 7);
|
||||
int64_t s12 = 2097151 & (load_4(s + 31) >> 4);
|
||||
int64_t s13 = 2097151 & (load_3(s + 34) >> 1);
|
||||
int64_t s14 = 2097151 & (load_4(s + 36) >> 6);
|
||||
int64_t s15 = 2097151 & (load_3(s + 39) >> 3);
|
||||
int64_t s16 = 2097151 & load_3(s + 42);
|
||||
int64_t s17 = 2097151 & (load_4(s + 44) >> 5);
|
||||
int64_t s18 = 2097151 & (load_3(s + 47) >> 2);
|
||||
int64_t s19 = 2097151 & (load_4(s + 49) >> 7);
|
||||
int64_t s20 = 2097151 & (load_4(s + 52) >> 4);
|
||||
int64_t s21 = 2097151 & (load_3(s + 55) >> 1);
|
||||
int64_t s22 = 2097151 & (load_4(s + 57) >> 6);
|
||||
int64_t s23 = (load_4(s + 60) >> 3);
|
||||
int64_t carry0;
|
||||
int64_t carry1;
|
||||
int64_t carry2;
|
||||
int64_t carry3;
|
||||
int64_t carry4;
|
||||
int64_t carry5;
|
||||
int64_t carry6;
|
||||
int64_t carry7;
|
||||
int64_t carry8;
|
||||
int64_t carry9;
|
||||
int64_t carry10;
|
||||
int64_t carry11;
|
||||
int64_t carry12;
|
||||
int64_t carry13;
|
||||
int64_t carry14;
|
||||
int64_t carry15;
|
||||
int64_t carry16;
|
||||
|
||||
s11 += s23 * 666643;
|
||||
s12 += s23 * 470296;
|
||||
s13 += s23 * 654183;
|
||||
s14 -= s23 * 997805;
|
||||
s15 += s23 * 136657;
|
||||
s16 -= s23 * 683901;
|
||||
s10 += s22 * 666643;
|
||||
s11 += s22 * 470296;
|
||||
s12 += s22 * 654183;
|
||||
s13 -= s22 * 997805;
|
||||
s14 += s22 * 136657;
|
||||
s15 -= s22 * 683901;
|
||||
s9 += s21 * 666643;
|
||||
s10 += s21 * 470296;
|
||||
s11 += s21 * 654183;
|
||||
s12 -= s21 * 997805;
|
||||
s13 += s21 * 136657;
|
||||
s14 -= s21 * 683901;
|
||||
s8 += s20 * 666643;
|
||||
s9 += s20 * 470296;
|
||||
s10 += s20 * 654183;
|
||||
s11 -= s20 * 997805;
|
||||
s12 += s20 * 136657;
|
||||
s13 -= s20 * 683901;
|
||||
s7 += s19 * 666643;
|
||||
s8 += s19 * 470296;
|
||||
s9 += s19 * 654183;
|
||||
s10 -= s19 * 997805;
|
||||
s11 += s19 * 136657;
|
||||
s12 -= s19 * 683901;
|
||||
s6 += s18 * 666643;
|
||||
s7 += s18 * 470296;
|
||||
s8 += s18 * 654183;
|
||||
s9 -= s18 * 997805;
|
||||
s10 += s18 * 136657;
|
||||
s11 -= s18 * 683901;
|
||||
carry6 = (s6 + (1 << 20)) >> 21;
|
||||
s7 += carry6;
|
||||
s6 -= shl64(carry6, 21);
|
||||
carry8 = (s8 + (1 << 20)) >> 21;
|
||||
s9 += carry8;
|
||||
s8 -= shl64(carry8, 21);
|
||||
carry10 = (s10 + (1 << 20)) >> 21;
|
||||
s11 += carry10;
|
||||
s10 -= shl64(carry10, 21);
|
||||
carry12 = (s12 + (1 << 20)) >> 21;
|
||||
s13 += carry12;
|
||||
s12 -= shl64(carry12, 21);
|
||||
carry14 = (s14 + (1 << 20)) >> 21;
|
||||
s15 += carry14;
|
||||
s14 -= shl64(carry14, 21);
|
||||
carry16 = (s16 + (1 << 20)) >> 21;
|
||||
s17 += carry16;
|
||||
s16 -= shl64(carry16, 21);
|
||||
carry7 = (s7 + (1 << 20)) >> 21;
|
||||
s8 += carry7;
|
||||
s7 -= shl64(carry7, 21);
|
||||
carry9 = (s9 + (1 << 20)) >> 21;
|
||||
s10 += carry9;
|
||||
s9 -= shl64(carry9, 21);
|
||||
carry11 = (s11 + (1 << 20)) >> 21;
|
||||
s12 += carry11;
|
||||
s11 -= shl64(carry11, 21);
|
||||
carry13 = (s13 + (1 << 20)) >> 21;
|
||||
s14 += carry13;
|
||||
s13 -= shl64(carry13, 21);
|
||||
carry15 = (s15 + (1 << 20)) >> 21;
|
||||
s16 += carry15;
|
||||
s15 -= shl64(carry15, 21);
|
||||
s5 += s17 * 666643;
|
||||
s6 += s17 * 470296;
|
||||
s7 += s17 * 654183;
|
||||
s8 -= s17 * 997805;
|
||||
s9 += s17 * 136657;
|
||||
s10 -= s17 * 683901;
|
||||
s4 += s16 * 666643;
|
||||
s5 += s16 * 470296;
|
||||
s6 += s16 * 654183;
|
||||
s7 -= s16 * 997805;
|
||||
s8 += s16 * 136657;
|
||||
s9 -= s16 * 683901;
|
||||
s3 += s15 * 666643;
|
||||
s4 += s15 * 470296;
|
||||
s5 += s15 * 654183;
|
||||
s6 -= s15 * 997805;
|
||||
s7 += s15 * 136657;
|
||||
s8 -= s15 * 683901;
|
||||
s2 += s14 * 666643;
|
||||
s3 += s14 * 470296;
|
||||
s4 += s14 * 654183;
|
||||
s5 -= s14 * 997805;
|
||||
s6 += s14 * 136657;
|
||||
s7 -= s14 * 683901;
|
||||
s1 += s13 * 666643;
|
||||
s2 += s13 * 470296;
|
||||
s3 += s13 * 654183;
|
||||
s4 -= s13 * 997805;
|
||||
s5 += s13 * 136657;
|
||||
s6 -= s13 * 683901;
|
||||
s0 += s12 * 666643;
|
||||
s1 += s12 * 470296;
|
||||
s2 += s12 * 654183;
|
||||
s3 -= s12 * 997805;
|
||||
s4 += s12 * 136657;
|
||||
s5 -= s12 * 683901;
|
||||
s12 = 0;
|
||||
carry0 = (s0 + (1 << 20)) >> 21;
|
||||
s1 += carry0;
|
||||
s0 -= shl64(carry0, 21);
|
||||
carry2 = (s2 + (1 << 20)) >> 21;
|
||||
s3 += carry2;
|
||||
s2 -= shl64(carry2, 21);
|
||||
carry4 = (s4 + (1 << 20)) >> 21;
|
||||
s5 += carry4;
|
||||
s4 -= shl64(carry4, 21);
|
||||
carry6 = (s6 + (1 << 20)) >> 21;
|
||||
s7 += carry6;
|
||||
s6 -= shl64(carry6, 21);
|
||||
carry8 = (s8 + (1 << 20)) >> 21;
|
||||
s9 += carry8;
|
||||
s8 -= shl64(carry8, 21);
|
||||
carry10 = (s10 + (1 << 20)) >> 21;
|
||||
s11 += carry10;
|
||||
s10 -= shl64(carry10, 21);
|
||||
carry1 = (s1 + (1 << 20)) >> 21;
|
||||
s2 += carry1;
|
||||
s1 -= shl64(carry1, 21);
|
||||
carry3 = (s3 + (1 << 20)) >> 21;
|
||||
s4 += carry3;
|
||||
s3 -= shl64(carry3, 21);
|
||||
carry5 = (s5 + (1 << 20)) >> 21;
|
||||
s6 += carry5;
|
||||
s5 -= shl64(carry5, 21);
|
||||
carry7 = (s7 + (1 << 20)) >> 21;
|
||||
s8 += carry7;
|
||||
s7 -= shl64(carry7, 21);
|
||||
carry9 = (s9 + (1 << 20)) >> 21;
|
||||
s10 += carry9;
|
||||
s9 -= shl64(carry9, 21);
|
||||
carry11 = (s11 + (1 << 20)) >> 21;
|
||||
s12 += carry11;
|
||||
s11 -= shl64(carry11, 21);
|
||||
s0 += s12 * 666643;
|
||||
s1 += s12 * 470296;
|
||||
s2 += s12 * 654183;
|
||||
s3 -= s12 * 997805;
|
||||
s4 += s12 * 136657;
|
||||
s5 -= s12 * 683901;
|
||||
s12 = 0;
|
||||
carry0 = s0 >> 21;
|
||||
s1 += carry0;
|
||||
s0 -= shl64(carry0, 21);
|
||||
carry1 = s1 >> 21;
|
||||
s2 += carry1;
|
||||
s1 -= shl64(carry1, 21);
|
||||
carry2 = s2 >> 21;
|
||||
s3 += carry2;
|
||||
s2 -= shl64(carry2, 21);
|
||||
carry3 = s3 >> 21;
|
||||
s4 += carry3;
|
||||
s3 -= shl64(carry3, 21);
|
||||
carry4 = s4 >> 21;
|
||||
s5 += carry4;
|
||||
s4 -= shl64(carry4, 21);
|
||||
carry5 = s5 >> 21;
|
||||
s6 += carry5;
|
||||
s5 -= shl64(carry5, 21);
|
||||
carry6 = s6 >> 21;
|
||||
s7 += carry6;
|
||||
s6 -= shl64(carry6, 21);
|
||||
carry7 = s7 >> 21;
|
||||
s8 += carry7;
|
||||
s7 -= shl64(carry7, 21);
|
||||
carry8 = s8 >> 21;
|
||||
s9 += carry8;
|
||||
s8 -= shl64(carry8, 21);
|
||||
carry9 = s9 >> 21;
|
||||
s10 += carry9;
|
||||
s9 -= shl64(carry9, 21);
|
||||
carry10 = s10 >> 21;
|
||||
s11 += carry10;
|
||||
s10 -= shl64(carry10, 21);
|
||||
carry11 = s11 >> 21;
|
||||
s12 += carry11;
|
||||
s11 -= shl64(carry11, 21);
|
||||
s0 += s12 * 666643;
|
||||
s1 += s12 * 470296;
|
||||
s2 += s12 * 654183;
|
||||
s3 -= s12 * 997805;
|
||||
s4 += s12 * 136657;
|
||||
s5 -= s12 * 683901;
|
||||
carry0 = s0 >> 21;
|
||||
s1 += carry0;
|
||||
s0 -= shl64(carry0, 21);
|
||||
carry1 = s1 >> 21;
|
||||
s2 += carry1;
|
||||
s1 -= shl64(carry1, 21);
|
||||
carry2 = s2 >> 21;
|
||||
s3 += carry2;
|
||||
s2 -= shl64(carry2, 21);
|
||||
carry3 = s3 >> 21;
|
||||
s4 += carry3;
|
||||
s3 -= shl64(carry3, 21);
|
||||
carry4 = s4 >> 21;
|
||||
s5 += carry4;
|
||||
s4 -= shl64(carry4, 21);
|
||||
carry5 = s5 >> 21;
|
||||
s6 += carry5;
|
||||
s5 -= shl64(carry5, 21);
|
||||
carry6 = s6 >> 21;
|
||||
s7 += carry6;
|
||||
s6 -= shl64(carry6, 21);
|
||||
carry7 = s7 >> 21;
|
||||
s8 += carry7;
|
||||
s7 -= shl64(carry7, 21);
|
||||
carry8 = s8 >> 21;
|
||||
s9 += carry8;
|
||||
s8 -= shl64(carry8, 21);
|
||||
carry9 = s9 >> 21;
|
||||
s10 += carry9;
|
||||
s9 -= shl64(carry9, 21);
|
||||
carry10 = s10 >> 21;
|
||||
s11 += carry10;
|
||||
s10 -= shl64(carry10, 21);
|
||||
|
||||
s[0] = (unsigned char)(s0 >> 0);
|
||||
s[1] = (unsigned char)(s0 >> 8);
|
||||
s[2] = (unsigned char)((s0 >> 16) | shl64(s1, 5));
|
||||
s[3] = (unsigned char)(s1 >> 3);
|
||||
s[4] = (unsigned char)(s1 >> 11);
|
||||
s[5] = (unsigned char)((s1 >> 19) | shl64(s2, 2));
|
||||
s[6] = (unsigned char)(s2 >> 6);
|
||||
s[7] = (unsigned char)((s2 >> 14) | shl64(s3, 7));
|
||||
s[8] = (unsigned char)(s3 >> 1);
|
||||
s[9] = (unsigned char)(s3 >> 9);
|
||||
s[10] = (unsigned char)((s3 >> 17) | shl64(s4, 4));
|
||||
s[11] = (unsigned char)(s4 >> 4);
|
||||
s[12] = (unsigned char)(s4 >> 12);
|
||||
s[13] = (unsigned char)((s4 >> 20) | shl64(s5, 1));
|
||||
s[14] = (unsigned char)(s5 >> 7);
|
||||
s[15] = (unsigned char)((s5 >> 15) | shl64(s6, 6));
|
||||
s[16] = (unsigned char)(s6 >> 2);
|
||||
s[17] = (unsigned char)(s6 >> 10);
|
||||
s[18] = (unsigned char)((s6 >> 18) | shl64(s7, 3));
|
||||
s[19] = (unsigned char)(s7 >> 5);
|
||||
s[20] = (unsigned char)(s7 >> 13);
|
||||
s[21] = (unsigned char)(s8 >> 0);
|
||||
s[22] = (unsigned char)(s8 >> 8);
|
||||
s[23] = (unsigned char)((s8 >> 16) | shl64(s9, 5));
|
||||
s[24] = (unsigned char)(s9 >> 3);
|
||||
s[25] = (unsigned char)(s9 >> 11);
|
||||
s[26] = (unsigned char)((s9 >> 19) | shl64(s10, 2));
|
||||
s[27] = (unsigned char)(s10 >> 6);
|
||||
s[28] = (unsigned char)((s10 >> 14) | shl64(s11, 7));
|
||||
s[29] = (unsigned char)(s11 >> 1);
|
||||
s[30] = (unsigned char)(s11 >> 9);
|
||||
s[31] = (unsigned char)(s11 >> 17);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Input:
|
||||
a[0]+256*a[1]+...+256^31*a[31] = a
|
||||
b[0]+256*b[1]+...+256^31*b[31] = b
|
||||
c[0]+256*c[1]+...+256^31*c[31] = c
|
||||
|
||||
Output:
|
||||
s[0]+256*s[1]+...+256^31*s[31] = (ab+c) mod l
|
||||
where l = 2^252 + 27742317777372353535851937790883648493.
|
||||
*/
|
||||
|
||||
void sc_muladd(unsigned char *s, const unsigned char *a, const unsigned char *b, const unsigned char *c) {
|
||||
int64_t a0 = 2097151 & load_3(a);
|
||||
int64_t a1 = 2097151 & (load_4(a + 2) >> 5);
|
||||
int64_t a2 = 2097151 & (load_3(a + 5) >> 2);
|
||||
int64_t a3 = 2097151 & (load_4(a + 7) >> 7);
|
||||
int64_t a4 = 2097151 & (load_4(a + 10) >> 4);
|
||||
int64_t a5 = 2097151 & (load_3(a + 13) >> 1);
|
||||
int64_t a6 = 2097151 & (load_4(a + 15) >> 6);
|
||||
int64_t a7 = 2097151 & (load_3(a + 18) >> 3);
|
||||
int64_t a8 = 2097151 & load_3(a + 21);
|
||||
int64_t a9 = 2097151 & (load_4(a + 23) >> 5);
|
||||
int64_t a10 = 2097151 & (load_3(a + 26) >> 2);
|
||||
int64_t a11 = (load_4(a + 28) >> 7);
|
||||
int64_t b0 = 2097151 & load_3(b);
|
||||
int64_t b1 = 2097151 & (load_4(b + 2) >> 5);
|
||||
int64_t b2 = 2097151 & (load_3(b + 5) >> 2);
|
||||
int64_t b3 = 2097151 & (load_4(b + 7) >> 7);
|
||||
int64_t b4 = 2097151 & (load_4(b + 10) >> 4);
|
||||
int64_t b5 = 2097151 & (load_3(b + 13) >> 1);
|
||||
int64_t b6 = 2097151 & (load_4(b + 15) >> 6);
|
||||
int64_t b7 = 2097151 & (load_3(b + 18) >> 3);
|
||||
int64_t b8 = 2097151 & load_3(b + 21);
|
||||
int64_t b9 = 2097151 & (load_4(b + 23) >> 5);
|
||||
int64_t b10 = 2097151 & (load_3(b + 26) >> 2);
|
||||
int64_t b11 = (load_4(b + 28) >> 7);
|
||||
int64_t c0 = 2097151 & load_3(c);
|
||||
int64_t c1 = 2097151 & (load_4(c + 2) >> 5);
|
||||
int64_t c2 = 2097151 & (load_3(c + 5) >> 2);
|
||||
int64_t c3 = 2097151 & (load_4(c + 7) >> 7);
|
||||
int64_t c4 = 2097151 & (load_4(c + 10) >> 4);
|
||||
int64_t c5 = 2097151 & (load_3(c + 13) >> 1);
|
||||
int64_t c6 = 2097151 & (load_4(c + 15) >> 6);
|
||||
int64_t c7 = 2097151 & (load_3(c + 18) >> 3);
|
||||
int64_t c8 = 2097151 & load_3(c + 21);
|
||||
int64_t c9 = 2097151 & (load_4(c + 23) >> 5);
|
||||
int64_t c10 = 2097151 & (load_3(c + 26) >> 2);
|
||||
int64_t c11 = (load_4(c + 28) >> 7);
|
||||
int64_t s0;
|
||||
int64_t s1;
|
||||
int64_t s2;
|
||||
int64_t s3;
|
||||
int64_t s4;
|
||||
int64_t s5;
|
||||
int64_t s6;
|
||||
int64_t s7;
|
||||
int64_t s8;
|
||||
int64_t s9;
|
||||
int64_t s10;
|
||||
int64_t s11;
|
||||
int64_t s12;
|
||||
int64_t s13;
|
||||
int64_t s14;
|
||||
int64_t s15;
|
||||
int64_t s16;
|
||||
int64_t s17;
|
||||
int64_t s18;
|
||||
int64_t s19;
|
||||
int64_t s20;
|
||||
int64_t s21;
|
||||
int64_t s22;
|
||||
int64_t s23;
|
||||
int64_t carry0;
|
||||
int64_t carry1;
|
||||
int64_t carry2;
|
||||
int64_t carry3;
|
||||
int64_t carry4;
|
||||
int64_t carry5;
|
||||
int64_t carry6;
|
||||
int64_t carry7;
|
||||
int64_t carry8;
|
||||
int64_t carry9;
|
||||
int64_t carry10;
|
||||
int64_t carry11;
|
||||
int64_t carry12;
|
||||
int64_t carry13;
|
||||
int64_t carry14;
|
||||
int64_t carry15;
|
||||
int64_t carry16;
|
||||
int64_t carry17;
|
||||
int64_t carry18;
|
||||
int64_t carry19;
|
||||
int64_t carry20;
|
||||
int64_t carry21;
|
||||
int64_t carry22;
|
||||
|
||||
s0 = c0 + a0 * b0;
|
||||
s1 = c1 + a0 * b1 + a1 * b0;
|
||||
s2 = c2 + a0 * b2 + a1 * b1 + a2 * b0;
|
||||
s3 = c3 + a0 * b3 + a1 * b2 + a2 * b1 + a3 * b0;
|
||||
s4 = c4 + a0 * b4 + a1 * b3 + a2 * b2 + a3 * b1 + a4 * b0;
|
||||
s5 = c5 + a0 * b5 + a1 * b4 + a2 * b3 + a3 * b2 + a4 * b1 + a5 * b0;
|
||||
s6 = c6 + a0 * b6 + a1 * b5 + a2 * b4 + a3 * b3 + a4 * b2 + a5 * b1 + a6 * b0;
|
||||
s7 = c7 + a0 * b7 + a1 * b6 + a2 * b5 + a3 * b4 + a4 * b3 + a5 * b2 + a6 * b1 + a7 * b0;
|
||||
s8 = c8 + a0 * b8 + a1 * b7 + a2 * b6 + a3 * b5 + a4 * b4 + a5 * b3 + a6 * b2 + a7 * b1 + a8 * b0;
|
||||
s9 = c9 + a0 * b9 + a1 * b8 + a2 * b7 + a3 * b6 + a4 * b5 + a5 * b4 + a6 * b3 + a7 * b2 + a8 * b1 + a9 * b0;
|
||||
s10 = c10 + a0 * b10 + a1 * b9 + a2 * b8 + a3 * b7 + a4 * b6 + a5 * b5 + a6 * b4 + a7 * b3 + a8 * b2 + a9 * b1 + a10 * b0;
|
||||
s11 = c11 + a0 * b11 + a1 * b10 + a2 * b9 + a3 * b8 + a4 * b7 + a5 * b6 + a6 * b5 + a7 * b4 + a8 * b3 + a9 * b2 + a10 * b1 + a11 * b0;
|
||||
s12 = a1 * b11 + a2 * b10 + a3 * b9 + a4 * b8 + a5 * b7 + a6 * b6 + a7 * b5 + a8 * b4 + a9 * b3 + a10 * b2 + a11 * b1;
|
||||
s13 = a2 * b11 + a3 * b10 + a4 * b9 + a5 * b8 + a6 * b7 + a7 * b6 + a8 * b5 + a9 * b4 + a10 * b3 + a11 * b2;
|
||||
s14 = a3 * b11 + a4 * b10 + a5 * b9 + a6 * b8 + a7 * b7 + a8 * b6 + a9 * b5 + a10 * b4 + a11 * b3;
|
||||
s15 = a4 * b11 + a5 * b10 + a6 * b9 + a7 * b8 + a8 * b7 + a9 * b6 + a10 * b5 + a11 * b4;
|
||||
s16 = a5 * b11 + a6 * b10 + a7 * b9 + a8 * b8 + a9 * b7 + a10 * b6 + a11 * b5;
|
||||
s17 = a6 * b11 + a7 * b10 + a8 * b9 + a9 * b8 + a10 * b7 + a11 * b6;
|
||||
s18 = a7 * b11 + a8 * b10 + a9 * b9 + a10 * b8 + a11 * b7;
|
||||
s19 = a8 * b11 + a9 * b10 + a10 * b9 + a11 * b8;
|
||||
s20 = a9 * b11 + a10 * b10 + a11 * b9;
|
||||
s21 = a10 * b11 + a11 * b10;
|
||||
s22 = a11 * b11;
|
||||
s23 = 0;
|
||||
carry0 = (s0 + (1 << 20)) >> 21;
|
||||
s1 += carry0;
|
||||
s0 -= shl64(carry0, 21);
|
||||
carry2 = (s2 + (1 << 20)) >> 21;
|
||||
s3 += carry2;
|
||||
s2 -= shl64(carry2, 21);
|
||||
carry4 = (s4 + (1 << 20)) >> 21;
|
||||
s5 += carry4;
|
||||
s4 -= shl64(carry4, 21);
|
||||
carry6 = (s6 + (1 << 20)) >> 21;
|
||||
s7 += carry6;
|
||||
s6 -= shl64(carry6, 21);
|
||||
carry8 = (s8 + (1 << 20)) >> 21;
|
||||
s9 += carry8;
|
||||
s8 -= shl64(carry8, 21);
|
||||
carry10 = (s10 + (1 << 20)) >> 21;
|
||||
s11 += carry10;
|
||||
s10 -= shl64(carry10, 21);
|
||||
carry12 = (s12 + (1 << 20)) >> 21;
|
||||
s13 += carry12;
|
||||
s12 -= shl64(carry12, 21);
|
||||
carry14 = (s14 + (1 << 20)) >> 21;
|
||||
s15 += carry14;
|
||||
s14 -= shl64(carry14, 21);
|
||||
carry16 = (s16 + (1 << 20)) >> 21;
|
||||
s17 += carry16;
|
||||
s16 -= shl64(carry16, 21);
|
||||
carry18 = (s18 + (1 << 20)) >> 21;
|
||||
s19 += carry18;
|
||||
s18 -= shl64(carry18, 21);
|
||||
carry20 = (s20 + (1 << 20)) >> 21;
|
||||
s21 += carry20;
|
||||
s20 -= shl64(carry20, 21);
|
||||
carry22 = (s22 + (1 << 20)) >> 21;
|
||||
s23 += carry22;
|
||||
s22 -= shl64(carry22, 21);
|
||||
carry1 = (s1 + (1 << 20)) >> 21;
|
||||
s2 += carry1;
|
||||
s1 -= shl64(carry1, 21);
|
||||
carry3 = (s3 + (1 << 20)) >> 21;
|
||||
s4 += carry3;
|
||||
s3 -= shl64(carry3, 21);
|
||||
carry5 = (s5 + (1 << 20)) >> 21;
|
||||
s6 += carry5;
|
||||
s5 -= shl64(carry5, 21);
|
||||
carry7 = (s7 + (1 << 20)) >> 21;
|
||||
s8 += carry7;
|
||||
s7 -= shl64(carry7, 21);
|
||||
carry9 = (s9 + (1 << 20)) >> 21;
|
||||
s10 += carry9;
|
||||
s9 -= shl64(carry9, 21);
|
||||
carry11 = (s11 + (1 << 20)) >> 21;
|
||||
s12 += carry11;
|
||||
s11 -= shl64(carry11, 21);
|
||||
carry13 = (s13 + (1 << 20)) >> 21;
|
||||
s14 += carry13;
|
||||
s13 -= shl64(carry13, 21);
|
||||
carry15 = (s15 + (1 << 20)) >> 21;
|
||||
s16 += carry15;
|
||||
s15 -= shl64(carry15, 21);
|
||||
carry17 = (s17 + (1 << 20)) >> 21;
|
||||
s18 += carry17;
|
||||
s17 -= shl64(carry17, 21);
|
||||
carry19 = (s19 + (1 << 20)) >> 21;
|
||||
s20 += carry19;
|
||||
s19 -= shl64(carry19, 21);
|
||||
carry21 = (s21 + (1 << 20)) >> 21;
|
||||
s22 += carry21;
|
||||
s21 -= shl64(carry21, 21);
|
||||
s11 += s23 * 666643;
|
||||
s12 += s23 * 470296;
|
||||
s13 += s23 * 654183;
|
||||
s14 -= s23 * 997805;
|
||||
s15 += s23 * 136657;
|
||||
s16 -= s23 * 683901;
|
||||
s10 += s22 * 666643;
|
||||
s11 += s22 * 470296;
|
||||
s12 += s22 * 654183;
|
||||
s13 -= s22 * 997805;
|
||||
s14 += s22 * 136657;
|
||||
s15 -= s22 * 683901;
|
||||
s9 += s21 * 666643;
|
||||
s10 += s21 * 470296;
|
||||
s11 += s21 * 654183;
|
||||
s12 -= s21 * 997805;
|
||||
s13 += s21 * 136657;
|
||||
s14 -= s21 * 683901;
|
||||
s8 += s20 * 666643;
|
||||
s9 += s20 * 470296;
|
||||
s10 += s20 * 654183;
|
||||
s11 -= s20 * 997805;
|
||||
s12 += s20 * 136657;
|
||||
s13 -= s20 * 683901;
|
||||
s7 += s19 * 666643;
|
||||
s8 += s19 * 470296;
|
||||
s9 += s19 * 654183;
|
||||
s10 -= s19 * 997805;
|
||||
s11 += s19 * 136657;
|
||||
s12 -= s19 * 683901;
|
||||
s6 += s18 * 666643;
|
||||
s7 += s18 * 470296;
|
||||
s8 += s18 * 654183;
|
||||
s9 -= s18 * 997805;
|
||||
s10 += s18 * 136657;
|
||||
s11 -= s18 * 683901;
|
||||
carry6 = (s6 + (1 << 20)) >> 21;
|
||||
s7 += carry6;
|
||||
s6 -= shl64(carry6, 21);
|
||||
carry8 = (s8 + (1 << 20)) >> 21;
|
||||
s9 += carry8;
|
||||
s8 -= shl64(carry8, 21);
|
||||
carry10 = (s10 + (1 << 20)) >> 21;
|
||||
s11 += carry10;
|
||||
s10 -= shl64(carry10, 21);
|
||||
carry12 = (s12 + (1 << 20)) >> 21;
|
||||
s13 += carry12;
|
||||
s12 -= shl64(carry12, 21);
|
||||
carry14 = (s14 + (1 << 20)) >> 21;
|
||||
s15 += carry14;
|
||||
s14 -= shl64(carry14, 21);
|
||||
carry16 = (s16 + (1 << 20)) >> 21;
|
||||
s17 += carry16;
|
||||
s16 -= shl64(carry16, 21);
|
||||
carry7 = (s7 + (1 << 20)) >> 21;
|
||||
s8 += carry7;
|
||||
s7 -= shl64(carry7, 21);
|
||||
carry9 = (s9 + (1 << 20)) >> 21;
|
||||
s10 += carry9;
|
||||
s9 -= shl64(carry9, 21);
|
||||
carry11 = (s11 + (1 << 20)) >> 21;
|
||||
s12 += carry11;
|
||||
s11 -= shl64(carry11, 21);
|
||||
carry13 = (s13 + (1 << 20)) >> 21;
|
||||
s14 += carry13;
|
||||
s13 -= shl64(carry13, 21);
|
||||
carry15 = (s15 + (1 << 20)) >> 21;
|
||||
s16 += carry15;
|
||||
s15 -= shl64(carry15, 21);
|
||||
s5 += s17 * 666643;
|
||||
s6 += s17 * 470296;
|
||||
s7 += s17 * 654183;
|
||||
s8 -= s17 * 997805;
|
||||
s9 += s17 * 136657;
|
||||
s10 -= s17 * 683901;
|
||||
s4 += s16 * 666643;
|
||||
s5 += s16 * 470296;
|
||||
s6 += s16 * 654183;
|
||||
s7 -= s16 * 997805;
|
||||
s8 += s16 * 136657;
|
||||
s9 -= s16 * 683901;
|
||||
s3 += s15 * 666643;
|
||||
s4 += s15 * 470296;
|
||||
s5 += s15 * 654183;
|
||||
s6 -= s15 * 997805;
|
||||
s7 += s15 * 136657;
|
||||
s8 -= s15 * 683901;
|
||||
s2 += s14 * 666643;
|
||||
s3 += s14 * 470296;
|
||||
s4 += s14 * 654183;
|
||||
s5 -= s14 * 997805;
|
||||
s6 += s14 * 136657;
|
||||
s7 -= s14 * 683901;
|
||||
s1 += s13 * 666643;
|
||||
s2 += s13 * 470296;
|
||||
s3 += s13 * 654183;
|
||||
s4 -= s13 * 997805;
|
||||
s5 += s13 * 136657;
|
||||
s6 -= s13 * 683901;
|
||||
s0 += s12 * 666643;
|
||||
s1 += s12 * 470296;
|
||||
s2 += s12 * 654183;
|
||||
s3 -= s12 * 997805;
|
||||
s4 += s12 * 136657;
|
||||
s5 -= s12 * 683901;
|
||||
s12 = 0;
|
||||
carry0 = (s0 + (1 << 20)) >> 21;
|
||||
s1 += carry0;
|
||||
s0 -= shl64(carry0, 21);
|
||||
carry2 = (s2 + (1 << 20)) >> 21;
|
||||
s3 += carry2;
|
||||
s2 -= shl64(carry2, 21);
|
||||
carry4 = (s4 + (1 << 20)) >> 21;
|
||||
s5 += carry4;
|
||||
s4 -= shl64(carry4, 21);
|
||||
carry6 = (s6 + (1 << 20)) >> 21;
|
||||
s7 += carry6;
|
||||
s6 -= shl64(carry6, 21);
|
||||
carry8 = (s8 + (1 << 20)) >> 21;
|
||||
s9 += carry8;
|
||||
s8 -= shl64(carry8, 21);
|
||||
carry10 = (s10 + (1 << 20)) >> 21;
|
||||
s11 += carry10;
|
||||
s10 -= shl64(carry10, 21);
|
||||
carry1 = (s1 + (1 << 20)) >> 21;
|
||||
s2 += carry1;
|
||||
s1 -= shl64(carry1, 21);
|
||||
carry3 = (s3 + (1 << 20)) >> 21;
|
||||
s4 += carry3;
|
||||
s3 -= shl64(carry3, 21);
|
||||
carry5 = (s5 + (1 << 20)) >> 21;
|
||||
s6 += carry5;
|
||||
s5 -= shl64(carry5, 21);
|
||||
carry7 = (s7 + (1 << 20)) >> 21;
|
||||
s8 += carry7;
|
||||
s7 -= shl64(carry7, 21);
|
||||
carry9 = (s9 + (1 << 20)) >> 21;
|
||||
s10 += carry9;
|
||||
s9 -= shl64(carry9, 21);
|
||||
carry11 = (s11 + (1 << 20)) >> 21;
|
||||
s12 += carry11;
|
||||
s11 -= shl64(carry11, 21);
|
||||
s0 += s12 * 666643;
|
||||
s1 += s12 * 470296;
|
||||
s2 += s12 * 654183;
|
||||
s3 -= s12 * 997805;
|
||||
s4 += s12 * 136657;
|
||||
s5 -= s12 * 683901;
|
||||
s12 = 0;
|
||||
carry0 = s0 >> 21;
|
||||
s1 += carry0;
|
||||
s0 -= shl64(carry0, 21);
|
||||
carry1 = s1 >> 21;
|
||||
s2 += carry1;
|
||||
s1 -= shl64(carry1, 21);
|
||||
carry2 = s2 >> 21;
|
||||
s3 += carry2;
|
||||
s2 -= shl64(carry2, 21);
|
||||
carry3 = s3 >> 21;
|
||||
s4 += carry3;
|
||||
s3 -= shl64(carry3, 21);
|
||||
carry4 = s4 >> 21;
|
||||
s5 += carry4;
|
||||
s4 -= shl64(carry4, 21);
|
||||
carry5 = s5 >> 21;
|
||||
s6 += carry5;
|
||||
s5 -= shl64(carry5, 21);
|
||||
carry6 = s6 >> 21;
|
||||
s7 += carry6;
|
||||
s6 -= shl64(carry6, 21);
|
||||
carry7 = s7 >> 21;
|
||||
s8 += carry7;
|
||||
s7 -= shl64(carry7, 21);
|
||||
carry8 = s8 >> 21;
|
||||
s9 += carry8;
|
||||
s8 -= shl64(carry8, 21);
|
||||
carry9 = s9 >> 21;
|
||||
s10 += carry9;
|
||||
s9 -= shl64(carry9, 21);
|
||||
carry10 = s10 >> 21;
|
||||
s11 += carry10;
|
||||
s10 -= shl64(carry10, 21);
|
||||
carry11 = s11 >> 21;
|
||||
s12 += carry11;
|
||||
s11 -= shl64(carry11, 21);
|
||||
s0 += s12 * 666643;
|
||||
s1 += s12 * 470296;
|
||||
s2 += s12 * 654183;
|
||||
s3 -= s12 * 997805;
|
||||
s4 += s12 * 136657;
|
||||
s5 -= s12 * 683901;
|
||||
carry0 = s0 >> 21;
|
||||
s1 += carry0;
|
||||
s0 -= shl64(carry0, 21);
|
||||
carry1 = s1 >> 21;
|
||||
s2 += carry1;
|
||||
s1 -= shl64(carry1, 21);
|
||||
carry2 = s2 >> 21;
|
||||
s3 += carry2;
|
||||
s2 -= shl64(carry2, 21);
|
||||
carry3 = s3 >> 21;
|
||||
s4 += carry3;
|
||||
s3 -= shl64(carry3, 21);
|
||||
carry4 = s4 >> 21;
|
||||
s5 += carry4;
|
||||
s4 -= shl64(carry4, 21);
|
||||
carry5 = s5 >> 21;
|
||||
s6 += carry5;
|
||||
s5 -= shl64(carry5, 21);
|
||||
carry6 = s6 >> 21;
|
||||
s7 += carry6;
|
||||
s6 -= shl64(carry6, 21);
|
||||
carry7 = s7 >> 21;
|
||||
s8 += carry7;
|
||||
s7 -= shl64(carry7, 21);
|
||||
carry8 = s8 >> 21;
|
||||
s9 += carry8;
|
||||
s8 -= shl64(carry8, 21);
|
||||
carry9 = s9 >> 21;
|
||||
s10 += carry9;
|
||||
s9 -= shl64(carry9, 21);
|
||||
carry10 = s10 >> 21;
|
||||
s11 += carry10;
|
||||
s10 -= shl64(carry10, 21);
|
||||
|
||||
s[0] = (unsigned char)(s0 >> 0);
|
||||
s[1] = (unsigned char)(s0 >> 8);
|
||||
s[2] = (unsigned char)((s0 >> 16) | shl64(s1, 5));
|
||||
s[3] = (unsigned char)(s1 >> 3);
|
||||
s[4] = (unsigned char)(s1 >> 11);
|
||||
s[5] = (unsigned char)((s1 >> 19) | shl64(s2, 2));
|
||||
s[6] = (unsigned char)(s2 >> 6);
|
||||
s[7] = (unsigned char)((s2 >> 14) | shl64(s3, 7));
|
||||
s[8] = (unsigned char)(s3 >> 1);
|
||||
s[9] = (unsigned char)(s3 >> 9);
|
||||
s[10] = (unsigned char)((s3 >> 17) | shl64(s4, 4));
|
||||
s[11] = (unsigned char)(s4 >> 4);
|
||||
s[12] = (unsigned char)(s4 >> 12);
|
||||
s[13] = (unsigned char)((s4 >> 20) | shl64(s5, 1));
|
||||
s[14] = (unsigned char)(s5 >> 7);
|
||||
s[15] = (unsigned char)((s5 >> 15) | shl64(s6, 6));
|
||||
s[16] = (unsigned char)(s6 >> 2);
|
||||
s[17] = (unsigned char)(s6 >> 10);
|
||||
s[18] = (unsigned char)((s6 >> 18) | shl64(s7, 3));
|
||||
s[19] = (unsigned char)(s7 >> 5);
|
||||
s[20] = (unsigned char)(s7 >> 13);
|
||||
s[21] = (unsigned char)(s8 >> 0);
|
||||
s[22] = (unsigned char)(s8 >> 8);
|
||||
s[23] = (unsigned char)((s8 >> 16) | shl64(s9, 5));
|
||||
s[24] = (unsigned char)(s9 >> 3);
|
||||
s[25] = (unsigned char)(s9 >> 11);
|
||||
s[26] = (unsigned char)((s9 >> 19) | shl64(s10, 2));
|
||||
s[27] = (unsigned char)(s10 >> 6);
|
||||
s[28] = (unsigned char)((s10 >> 14) | shl64(s11, 7));
|
||||
s[29] = (unsigned char)(s11 >> 1);
|
||||
s[30] = (unsigned char)(s11 >> 9);
|
||||
s[31] = (unsigned char)(s11 >> 17);
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
#ifndef SC_H
|
||||
#define SC_H
|
||||
|
||||
/*
|
||||
The set of scalars is \Z/l
|
||||
where l = 2^252 + 27742317777372353535851937790883648493.
|
||||
*/
|
||||
|
||||
void sc_reduce(unsigned char *s);
|
||||
void sc_muladd(unsigned char *s, const unsigned char *a, const unsigned char *b, const unsigned char *c);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,303 +0,0 @@
|
|||
/* LibTomCrypt, modular cryptographic library -- Tom St Denis
|
||||
*
|
||||
* LibTomCrypt is a library that provides various cryptographic
|
||||
* algorithms in a highly modular and flexible manner.
|
||||
*
|
||||
* The library is free for all purposes without any express
|
||||
* guarantee it works.
|
||||
*
|
||||
* Tom St Denis, tomstdenis@gmail.com, http://libtom.org
|
||||
*/
|
||||
|
||||
#include "fixedint.h"
|
||||
#include "sha512.h"
|
||||
|
||||
/* the K array */
|
||||
static const uint64_t K[80] = {
|
||||
UINT64_C(0x428a2f98d728ae22), UINT64_C(0x7137449123ef65cd),
|
||||
UINT64_C(0xb5c0fbcfec4d3b2f), UINT64_C(0xe9b5dba58189dbbc),
|
||||
UINT64_C(0x3956c25bf348b538), UINT64_C(0x59f111f1b605d019),
|
||||
UINT64_C(0x923f82a4af194f9b), UINT64_C(0xab1c5ed5da6d8118),
|
||||
UINT64_C(0xd807aa98a3030242), UINT64_C(0x12835b0145706fbe),
|
||||
UINT64_C(0x243185be4ee4b28c), UINT64_C(0x550c7dc3d5ffb4e2),
|
||||
UINT64_C(0x72be5d74f27b896f), UINT64_C(0x80deb1fe3b1696b1),
|
||||
UINT64_C(0x9bdc06a725c71235), UINT64_C(0xc19bf174cf692694),
|
||||
UINT64_C(0xe49b69c19ef14ad2), UINT64_C(0xefbe4786384f25e3),
|
||||
UINT64_C(0x0fc19dc68b8cd5b5), UINT64_C(0x240ca1cc77ac9c65),
|
||||
UINT64_C(0x2de92c6f592b0275), UINT64_C(0x4a7484aa6ea6e483),
|
||||
UINT64_C(0x5cb0a9dcbd41fbd4), UINT64_C(0x76f988da831153b5),
|
||||
UINT64_C(0x983e5152ee66dfab), UINT64_C(0xa831c66d2db43210),
|
||||
UINT64_C(0xb00327c898fb213f), UINT64_C(0xbf597fc7beef0ee4),
|
||||
UINT64_C(0xc6e00bf33da88fc2), UINT64_C(0xd5a79147930aa725),
|
||||
UINT64_C(0x06ca6351e003826f), UINT64_C(0x142929670a0e6e70),
|
||||
UINT64_C(0x27b70a8546d22ffc), UINT64_C(0x2e1b21385c26c926),
|
||||
UINT64_C(0x4d2c6dfc5ac42aed), UINT64_C(0x53380d139d95b3df),
|
||||
UINT64_C(0x650a73548baf63de), UINT64_C(0x766a0abb3c77b2a8),
|
||||
UINT64_C(0x81c2c92e47edaee6), UINT64_C(0x92722c851482353b),
|
||||
UINT64_C(0xa2bfe8a14cf10364), UINT64_C(0xa81a664bbc423001),
|
||||
UINT64_C(0xc24b8b70d0f89791), UINT64_C(0xc76c51a30654be30),
|
||||
UINT64_C(0xd192e819d6ef5218), UINT64_C(0xd69906245565a910),
|
||||
UINT64_C(0xf40e35855771202a), UINT64_C(0x106aa07032bbd1b8),
|
||||
UINT64_C(0x19a4c116b8d2d0c8), UINT64_C(0x1e376c085141ab53),
|
||||
UINT64_C(0x2748774cdf8eeb99), UINT64_C(0x34b0bcb5e19b48a8),
|
||||
UINT64_C(0x391c0cb3c5c95a63), UINT64_C(0x4ed8aa4ae3418acb),
|
||||
UINT64_C(0x5b9cca4f7763e373), UINT64_C(0x682e6ff3d6b2b8a3),
|
||||
UINT64_C(0x748f82ee5defb2fc), UINT64_C(0x78a5636f43172f60),
|
||||
UINT64_C(0x84c87814a1f0ab72), UINT64_C(0x8cc702081a6439ec),
|
||||
UINT64_C(0x90befffa23631e28), UINT64_C(0xa4506cebde82bde9),
|
||||
UINT64_C(0xbef9a3f7b2c67915), UINT64_C(0xc67178f2e372532b),
|
||||
UINT64_C(0xca273eceea26619c), UINT64_C(0xd186b8c721c0c207),
|
||||
UINT64_C(0xeada7dd6cde0eb1e), UINT64_C(0xf57d4f7fee6ed178),
|
||||
UINT64_C(0x06f067aa72176fba), UINT64_C(0x0a637dc5a2c898a6),
|
||||
UINT64_C(0x113f9804bef90dae), UINT64_C(0x1b710b35131c471b),
|
||||
UINT64_C(0x28db77f523047d84), UINT64_C(0x32caab7b40c72493),
|
||||
UINT64_C(0x3c9ebe0a15c9bebc), UINT64_C(0x431d67c49c100d4c),
|
||||
UINT64_C(0x4cc5d4becb3e42b6), UINT64_C(0x597f299cfc657e2a),
|
||||
UINT64_C(0x5fcb6fab3ad6faec), UINT64_C(0x6c44198c4a475817)
|
||||
};
|
||||
|
||||
/* Various logical functions */
|
||||
|
||||
#define ROR64c(x, y) \
|
||||
( ((((x)&UINT64_C(0xFFFFFFFFFFFFFFFF))>>((uint64_t)(y)&UINT64_C(63))) | \
|
||||
((x)<<((uint64_t)(64-((y)&UINT64_C(63)))))) & UINT64_C(0xFFFFFFFFFFFFFFFF))
|
||||
|
||||
#define STORE64H(x, y) \
|
||||
{ (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \
|
||||
(y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \
|
||||
(y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \
|
||||
(y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); }
|
||||
|
||||
#define LOAD64H(x, y) \
|
||||
{ x = (((uint64_t)((y)[0] & 255))<<56)|(((uint64_t)((y)[1] & 255))<<48) | \
|
||||
(((uint64_t)((y)[2] & 255))<<40)|(((uint64_t)((y)[3] & 255))<<32) | \
|
||||
(((uint64_t)((y)[4] & 255))<<24)|(((uint64_t)((y)[5] & 255))<<16) | \
|
||||
(((uint64_t)((y)[6] & 255))<<8)|(((uint64_t)((y)[7] & 255))); }
|
||||
|
||||
|
||||
#define Ch(x,y,z) (z ^ (x & (y ^ z)))
|
||||
#define Maj(x,y,z) (((x | y) & z) | (x & y))
|
||||
#define S(x, n) ROR64c(x, n)
|
||||
#define R(x, n) (((x) &UINT64_C(0xFFFFFFFFFFFFFFFF))>>((uint64_t)n))
|
||||
#define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39))
|
||||
#define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41))
|
||||
#define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7))
|
||||
#define Gamma1(x) (S(x, 19) ^ S(x, 61) ^ R(x, 6))
|
||||
#ifndef MIN
|
||||
#define MIN(x, y) ( ((x)<(y))?(x):(y) )
|
||||
#endif
|
||||
|
||||
/* compress 1024-bits */
|
||||
static int sha512_compress(sha512_context *md, const unsigned char *buf) {
|
||||
uint64_t S[8], W[80], t0, t1;
|
||||
int i;
|
||||
|
||||
/* copy state into S */
|
||||
for(i = 0; i < 8; i++) {
|
||||
S[i] = md->state[i];
|
||||
}
|
||||
|
||||
/* copy the state into 1024-bits into W[0..15] */
|
||||
for(i = 0; i < 16; i++) {
|
||||
LOAD64H(W[i], buf + (8 * i));
|
||||
}
|
||||
|
||||
/* fill W[16..79] */
|
||||
for(i = 16; i < 80; i++) {
|
||||
W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16];
|
||||
}
|
||||
|
||||
/* Compress */
|
||||
#define RND(a,b,c,d,e,f,g,h,i) \
|
||||
t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \
|
||||
t1 = Sigma0(a) + Maj(a, b, c);\
|
||||
d += t0; \
|
||||
h = t0 + t1;
|
||||
|
||||
for(i = 0; i < 80; i += 8) {
|
||||
RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i + 0);
|
||||
RND(S[7], S[0], S[1], S[2], S[3], S[4], S[5], S[6], i + 1);
|
||||
RND(S[6], S[7], S[0], S[1], S[2], S[3], S[4], S[5], i + 2);
|
||||
RND(S[5], S[6], S[7], S[0], S[1], S[2], S[3], S[4], i + 3);
|
||||
RND(S[4], S[5], S[6], S[7], S[0], S[1], S[2], S[3], i + 4);
|
||||
RND(S[3], S[4], S[5], S[6], S[7], S[0], S[1], S[2], i + 5);
|
||||
RND(S[2], S[3], S[4], S[5], S[6], S[7], S[0], S[1], i + 6);
|
||||
RND(S[1], S[2], S[3], S[4], S[5], S[6], S[7], S[0], i + 7);
|
||||
}
|
||||
|
||||
#undef RND
|
||||
|
||||
|
||||
|
||||
/* feedback */
|
||||
for(i = 0; i < 8; i++) {
|
||||
md->state[i] = md->state[i] + S[i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Initialize the hash state
|
||||
@param md The hash state you wish to initialize
|
||||
@return 0 if successful
|
||||
*/
|
||||
int sha512_init(sha512_context *md) {
|
||||
if(md == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
md->curlen = 0;
|
||||
md->length = 0;
|
||||
md->state[0] = UINT64_C(0x6a09e667f3bcc908);
|
||||
md->state[1] = UINT64_C(0xbb67ae8584caa73b);
|
||||
md->state[2] = UINT64_C(0x3c6ef372fe94f82b);
|
||||
md->state[3] = UINT64_C(0xa54ff53a5f1d36f1);
|
||||
md->state[4] = UINT64_C(0x510e527fade682d1);
|
||||
md->state[5] = UINT64_C(0x9b05688c2b3e6c1f);
|
||||
md->state[6] = UINT64_C(0x1f83d9abfb41bd6b);
|
||||
md->state[7] = UINT64_C(0x5be0cd19137e2179);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
Process a block of memory though the hash
|
||||
@param md The hash state
|
||||
@param in The data to hash
|
||||
@param inlen The length of the data (octets)
|
||||
@return 0 if successful
|
||||
*/
|
||||
int sha512_update(sha512_context *md, const void *vin, size_t inlen) {
|
||||
const unsigned char *in = vin;
|
||||
size_t n;
|
||||
size_t i;
|
||||
int err;
|
||||
|
||||
if(md == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(in == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(md->curlen > sizeof(md->buf)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
while(inlen > 0) {
|
||||
if(md->curlen == 0 && inlen >= 128) {
|
||||
if((err = sha512_compress(md, in)) != 0) {
|
||||
return err;
|
||||
}
|
||||
|
||||
md->length += 128 * 8;
|
||||
in += 128;
|
||||
inlen -= 128;
|
||||
} else {
|
||||
n = MIN(inlen, (128 - md->curlen));
|
||||
|
||||
for(i = 0; i < n; i++) {
|
||||
md->buf[i + md->curlen] = in[i];
|
||||
}
|
||||
|
||||
|
||||
md->curlen += n;
|
||||
in += n;
|
||||
inlen -= n;
|
||||
|
||||
if(md->curlen == 128) {
|
||||
if((err = sha512_compress(md, md->buf)) != 0) {
|
||||
return err;
|
||||
}
|
||||
|
||||
md->length += 8 * 128;
|
||||
md->curlen = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
Terminate the hash to get the digest
|
||||
@param md The hash state
|
||||
@param out [out] The destination of the hash (64 bytes)
|
||||
@return 0 if successful
|
||||
*/
|
||||
int sha512_final(sha512_context *md, void *vout) {
|
||||
int i;
|
||||
unsigned char *out = vout;
|
||||
|
||||
if(md == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(out == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(md->curlen >= sizeof(md->buf)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* increase the length of the message */
|
||||
md->length += md->curlen * UINT64_C(8);
|
||||
|
||||
/* append the '1' bit */
|
||||
md->buf[md->curlen++] = (unsigned char)0x80;
|
||||
|
||||
/* if the length is currently above 112 bytes we append zeros
|
||||
* then compress. Then we can fall back to padding zeros and length
|
||||
* encoding like normal.
|
||||
*/
|
||||
if(md->curlen > 112) {
|
||||
while(md->curlen < 128) {
|
||||
md->buf[md->curlen++] = (unsigned char)0;
|
||||
}
|
||||
|
||||
sha512_compress(md, md->buf);
|
||||
md->curlen = 0;
|
||||
}
|
||||
|
||||
/* pad up to 120 bytes of zeroes
|
||||
* note: that from 112 to 120 is the 64 MSB of the length. We assume that you won't hash
|
||||
* > 2^64 bits of data... :-)
|
||||
*/
|
||||
while(md->curlen < 120) {
|
||||
md->buf[md->curlen++] = (unsigned char)0;
|
||||
}
|
||||
|
||||
/* store length */
|
||||
STORE64H(md->length, md->buf + 120);
|
||||
sha512_compress(md, md->buf);
|
||||
|
||||
/* copy output */
|
||||
for(i = 0; i < 8; i++) {
|
||||
STORE64H(md->state[i], out + (8 * i));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sha512(const void *message, size_t message_len, void *out) {
|
||||
sha512_context ctx;
|
||||
int ret;
|
||||
|
||||
if((ret = sha512_init(&ctx))) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if((ret = sha512_update(&ctx, message, message_len))) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if((ret = sha512_final(&ctx, out))) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
#ifndef SHA512_H
|
||||
#define SHA512_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "fixedint.h"
|
||||
|
||||
/* state */
|
||||
typedef struct sha512_context_ {
|
||||
uint64_t length, state[8];
|
||||
size_t curlen;
|
||||
unsigned char buf[128];
|
||||
} sha512_context;
|
||||
|
||||
|
||||
int sha512_init(sha512_context *md);
|
||||
int sha512_final(sha512_context *md, void *out);
|
||||
int sha512_update(sha512_context *md, const void *in, size_t inlen);
|
||||
int sha512(const void *message, size_t message_len, void *out);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
#include "ed25519.h"
|
||||
#include "sha512.h"
|
||||
#include "ge.h"
|
||||
#include "sc.h"
|
||||
|
||||
|
||||
void ed25519_sign(unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *public_key, const unsigned char *private_key) {
|
||||
sha512_context hash;
|
||||
unsigned char hram[64];
|
||||
unsigned char r[64];
|
||||
ge_p3 R;
|
||||
|
||||
|
||||
sha512_init(&hash);
|
||||
sha512_update(&hash, private_key + 32, 32);
|
||||
sha512_update(&hash, message, message_len);
|
||||
sha512_final(&hash, r);
|
||||
|
||||
sc_reduce(r);
|
||||
ge_scalarmult_base(&R, r);
|
||||
ge_p3_tobytes(signature, &R);
|
||||
|
||||
sha512_init(&hash);
|
||||
sha512_update(&hash, signature, 32);
|
||||
sha512_update(&hash, public_key, 32);
|
||||
sha512_update(&hash, message, message_len);
|
||||
sha512_final(&hash, hram);
|
||||
|
||||
sc_reduce(hram);
|
||||
sc_muladd(signature + 32, hram, private_key, r);
|
||||
}
|
||||
|
|
@ -1,77 +0,0 @@
|
|||
#include "ed25519.h"
|
||||
#include "sha512.h"
|
||||
#include "ge.h"
|
||||
#include "sc.h"
|
||||
|
||||
static int consttime_equal(const unsigned char *x, const unsigned char *y) {
|
||||
unsigned char r = 0;
|
||||
|
||||
r = x[0] ^ y[0];
|
||||
#define F(i) r |= x[i] ^ y[i]
|
||||
F(1);
|
||||
F(2);
|
||||
F(3);
|
||||
F(4);
|
||||
F(5);
|
||||
F(6);
|
||||
F(7);
|
||||
F(8);
|
||||
F(9);
|
||||
F(10);
|
||||
F(11);
|
||||
F(12);
|
||||
F(13);
|
||||
F(14);
|
||||
F(15);
|
||||
F(16);
|
||||
F(17);
|
||||
F(18);
|
||||
F(19);
|
||||
F(20);
|
||||
F(21);
|
||||
F(22);
|
||||
F(23);
|
||||
F(24);
|
||||
F(25);
|
||||
F(26);
|
||||
F(27);
|
||||
F(28);
|
||||
F(29);
|
||||
F(30);
|
||||
F(31);
|
||||
#undef F
|
||||
|
||||
return !r;
|
||||
}
|
||||
|
||||
int ed25519_verify(const unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *public_key) {
|
||||
unsigned char h[64];
|
||||
unsigned char checker[32];
|
||||
sha512_context hash;
|
||||
ge_p3 A;
|
||||
ge_p2 R;
|
||||
|
||||
if(signature[63] & 224) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(ge_frombytes_negate_vartime(&A, public_key) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
sha512_init(&hash);
|
||||
sha512_update(&hash, signature, 32);
|
||||
sha512_update(&hash, public_key, 32);
|
||||
sha512_update(&hash, message, message_len);
|
||||
sha512_final(&hash, h);
|
||||
|
||||
sc_reduce(h);
|
||||
ge_double_scalarmult_vartime(&R, h, &A, signature + 32);
|
||||
ge_tobytes(checker, &R);
|
||||
|
||||
if(!consttime_equal(checker, signature)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
60
src/edge.c
60
src/edge.c
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
edge.c -- edge tree management
|
||||
Copyright (C) 2000-2013 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
Copyright (C) 2000-2006 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
2000-2005 Ivo Timmermans
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
|
|
@ -20,8 +20,7 @@
|
|||
|
||||
#include "system.h"
|
||||
|
||||
#include "splay_tree.h"
|
||||
#include "control_common.h"
|
||||
#include "avl_tree.h"
|
||||
#include "edge.h"
|
||||
#include "logger.h"
|
||||
#include "netutl.h"
|
||||
|
|
@ -29,7 +28,7 @@
|
|||
#include "utils.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
splay_tree_t *edge_weight_tree;
|
||||
avl_tree_t *edge_weight_tree; /* Tree with all edges, sorted on weight */
|
||||
|
||||
static int edge_compare(const edge_t *a, const edge_t *b) {
|
||||
return strcmp(a->to->name, b->to->name);
|
||||
|
|
@ -54,37 +53,36 @@ static int edge_weight_compare(const edge_t *a, const edge_t *b) {
|
|||
}
|
||||
|
||||
void init_edges(void) {
|
||||
edge_weight_tree = splay_alloc_tree((splay_compare_t) edge_weight_compare, NULL);
|
||||
edge_weight_tree = avl_alloc_tree((avl_compare_t) edge_weight_compare, NULL);
|
||||
}
|
||||
|
||||
splay_tree_t *new_edge_tree(void) {
|
||||
return splay_alloc_tree((splay_compare_t) edge_compare, (splay_action_t) free_edge);
|
||||
avl_tree_t *new_edge_tree(void) {
|
||||
return avl_alloc_tree((avl_compare_t) edge_compare, (avl_action_t) free_edge);
|
||||
}
|
||||
|
||||
void free_edge_tree(splay_tree_t *edge_tree) {
|
||||
splay_delete_tree(edge_tree);
|
||||
void free_edge_tree(avl_tree_t *edge_tree) {
|
||||
avl_delete_tree(edge_tree);
|
||||
}
|
||||
|
||||
void exit_edges(void) {
|
||||
splay_delete_tree(edge_weight_tree);
|
||||
avl_delete_tree(edge_weight_tree);
|
||||
}
|
||||
|
||||
/* Creation and deletion of connection elements */
|
||||
|
||||
edge_t *new_edge(void) {
|
||||
return xzalloc(sizeof(edge_t));
|
||||
return xmalloc_and_zero(sizeof(edge_t));
|
||||
}
|
||||
|
||||
void free_edge(edge_t *e) {
|
||||
sockaddrfree(&e->address);
|
||||
sockaddrfree(&e->local_address);
|
||||
|
||||
free(e);
|
||||
}
|
||||
|
||||
void edge_add(edge_t *e) {
|
||||
splay_insert(edge_weight_tree, e);
|
||||
splay_insert(e->from->edge_tree, e);
|
||||
avl_insert(edge_weight_tree, e);
|
||||
avl_insert(e->from->edge_tree, e);
|
||||
|
||||
e->reverse = lookup_edge(e->to, e->from);
|
||||
|
||||
|
|
@ -98,8 +96,8 @@ void edge_del(edge_t *e) {
|
|||
e->reverse->reverse = NULL;
|
||||
}
|
||||
|
||||
splay_delete(edge_weight_tree, e);
|
||||
splay_delete(e->from->edge_tree, e);
|
||||
avl_delete(edge_weight_tree, e);
|
||||
avl_delete(e->from->edge_tree, e);
|
||||
}
|
||||
|
||||
edge_t *lookup_edge(node_t *from, node_t *to) {
|
||||
|
|
@ -108,22 +106,28 @@ edge_t *lookup_edge(node_t *from, node_t *to) {
|
|||
v.from = from;
|
||||
v.to = to;
|
||||
|
||||
return splay_search(from->edge_tree, &v);
|
||||
return avl_search(from->edge_tree, &v);
|
||||
}
|
||||
|
||||
bool dump_edges(connection_t *c) {
|
||||
for splay_each(node_t, n, node_tree) {
|
||||
for splay_each(edge_t, e, n->edge_tree) {
|
||||
char *address = sockaddr2hostname(&e->address);
|
||||
char *local_address = sockaddr2hostname(&e->local_address);
|
||||
send_request(c, "%d %d %s %s %s %s %x %d",
|
||||
CONTROL, REQ_DUMP_EDGES,
|
||||
e->from->name, e->to->name, address,
|
||||
local_address, e->options, e->weight);
|
||||
void dump_edges(void) {
|
||||
avl_node_t *node, *node2;
|
||||
node_t *n;
|
||||
edge_t *e;
|
||||
char *address;
|
||||
|
||||
logger(LOG_DEBUG, "Edges:");
|
||||
|
||||
for(node = node_tree->head; node; node = node->next) {
|
||||
n = node->data;
|
||||
|
||||
for(node2 = n->edge_tree->head; node2; node2 = node2->next) {
|
||||
e = node2->data;
|
||||
address = sockaddr2hostname(&e->address);
|
||||
logger(LOG_DEBUG, " %s to %s at %s options %x weight %d",
|
||||
e->from->name, e->to->name, address, e->options, e->weight);
|
||||
free(address);
|
||||
free(local_address);
|
||||
}
|
||||
}
|
||||
|
||||
return send_request(c, "%d %d", CONTROL, REQ_DUMP_EDGES);
|
||||
logger(LOG_DEBUG, "End of edges.");
|
||||
}
|
||||
|
|
|
|||
21
src/edge.h
21
src/edge.h
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
/*
|
||||
edge.h -- header for edge.c
|
||||
Copyright (C) 2001-2012 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
Copyright (C) 2001-2006 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
2001-2005 Ivo Timmermans
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
|
|
@ -21,7 +21,7 @@
|
|||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "splay_tree.h"
|
||||
#include "avl_tree.h"
|
||||
#include "connection.h"
|
||||
#include "net.h"
|
||||
#include "node.h"
|
||||
|
|
@ -30,26 +30,25 @@ typedef struct edge_t {
|
|||
struct node_t *from;
|
||||
struct node_t *to;
|
||||
sockaddr_t address;
|
||||
sockaddr_t local_address;
|
||||
|
||||
uint32_t options; /* options turned on for this edge */
|
||||
int weight; /* weight of this edge */
|
||||
uint32_t options; /* options turned on for this edge */
|
||||
int weight; /* weight of this edge */
|
||||
|
||||
struct connection_t *connection; /* connection associated with this edge, if available */
|
||||
struct edge_t *reverse; /* edge in the opposite direction, if available */
|
||||
struct connection_t *connection; /* connection associated with this edge, if available */
|
||||
struct edge_t *reverse; /* edge in the opposite direction, if available */
|
||||
} edge_t;
|
||||
|
||||
extern splay_tree_t *edge_weight_tree; /* Tree with all known edges sorted on weight */
|
||||
extern avl_tree_t *edge_weight_tree; /* Tree with all known edges sorted on weight */
|
||||
|
||||
extern void init_edges(void);
|
||||
extern void exit_edges(void);
|
||||
extern edge_t *new_edge(void) __attribute__((__malloc__));
|
||||
extern void free_edge(edge_t *e);
|
||||
extern splay_tree_t *new_edge_tree(void) __attribute__((__malloc__));
|
||||
extern void free_edge_tree(splay_tree_t *edge_tree);
|
||||
extern avl_tree_t *new_edge_tree(void) __attribute__((__malloc__));
|
||||
extern void free_edge_tree(avl_tree_t *edge_tree);
|
||||
extern void edge_add(edge_t *e);
|
||||
extern void edge_del(edge_t *e);
|
||||
extern edge_t *lookup_edge(struct node_t *from, struct node_t *to);
|
||||
extern bool dump_edges(struct connection_t *c);
|
||||
extern void dump_edges(void);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -25,15 +25,6 @@
|
|||
#define ETH_ALEN 6
|
||||
#endif
|
||||
|
||||
#ifndef ETH_HLEN
|
||||
#define ETH_HLEN 14
|
||||
#endif
|
||||
|
||||
#ifndef ETHER_TYPE_LEN
|
||||
#define ETHER_TYPE_LEN 2
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef ARPHRD_ETHER
|
||||
#define ARPHRD_ETHER 1
|
||||
#endif
|
||||
|
|
@ -54,16 +45,12 @@
|
|||
#define ETH_P_8021Q 0x8100
|
||||
#endif
|
||||
|
||||
#ifndef ETH_P_MAX
|
||||
#define ETH_P_MAX 0xFFFF
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRUCT_ETHER_HEADER
|
||||
struct ether_header {
|
||||
uint8_t ether_dhost[ETH_ALEN];
|
||||
uint8_t ether_shost[ETH_ALEN];
|
||||
uint16_t ether_type;
|
||||
} __attribute__((__gcc_struct__, __packed__));
|
||||
} __attribute__((__packed__));
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRUCT_ARPHDR
|
||||
|
|
@ -73,7 +60,7 @@ struct arphdr {
|
|||
uint8_t ar_hln;
|
||||
uint8_t ar_pln;
|
||||
uint16_t ar_op;
|
||||
} __attribute__((__gcc_struct__, __packed__));
|
||||
} __attribute__((__packed__));
|
||||
|
||||
#define ARPOP_REQUEST 1
|
||||
#define ARPOP_REPLY 2
|
||||
|
|
@ -91,7 +78,7 @@ struct ether_arp {
|
|||
uint8_t arp_spa[4];
|
||||
uint8_t arp_tha[ETH_ALEN];
|
||||
uint8_t arp_tpa[4];
|
||||
} __attribute__((__gcc_struct__, __packed__));
|
||||
} __attribute__((__packed__));
|
||||
#define arp_hrd ea_hdr.ar_hrd
|
||||
#define arp_pro ea_hdr.ar_pro
|
||||
#define arp_hln ea_hdr.ar_hln
|
||||
|
|
|
|||
484
src/event.c
484
src/event.c
|
|
@ -1,6 +1,7 @@
|
|||
/*
|
||||
event.c -- I/O, timeout and signal event handling
|
||||
Copyright (C) 2012-2013 Guus Sliepen <guus@tinc-vpn.org>
|
||||
event.c -- event queue
|
||||
Copyright (C) 2002-2009 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
2002-2005 Ivo Timmermans
|
||||
|
||||
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
|
||||
|
|
@ -19,471 +20,102 @@
|
|||
|
||||
#include "system.h"
|
||||
|
||||
#include "dropin.h"
|
||||
#include "avl_tree.h"
|
||||
#include "event.h"
|
||||
#include "net.h"
|
||||
#include "utils.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
struct timeval now;
|
||||
avl_tree_t *event_tree;
|
||||
extern time_t now;
|
||||
|
||||
#ifndef HAVE_MINGW
|
||||
static fd_set readfds;
|
||||
static fd_set writefds;
|
||||
#else
|
||||
static const long READ_EVENTS = FD_READ | FD_ACCEPT | FD_CLOSE;
|
||||
static const long WRITE_EVENTS = FD_WRITE | FD_CONNECT;
|
||||
static DWORD event_count = 0;
|
||||
#endif
|
||||
static bool running;
|
||||
static int id;
|
||||
|
||||
static int io_compare(const io_t *a, const io_t *b) {
|
||||
#ifndef HAVE_MINGW
|
||||
return a->fd - b->fd;
|
||||
#else
|
||||
|
||||
if(a->event < b->event) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(a->event > b->event) {
|
||||
static int event_compare(const event_t *a, const event_t *b) {
|
||||
if(a->time > b->time) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int timeout_compare(const timeout_t *a, const timeout_t *b) {
|
||||
struct timeval diff;
|
||||
timersub(&a->tv, &b->tv, &diff);
|
||||
|
||||
if(diff.tv_sec < 0) {
|
||||
if(a->time < b->time) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(diff.tv_sec > 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(diff.tv_usec < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(diff.tv_usec > 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(a < b) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(a > b) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return a->id - b->id;
|
||||
}
|
||||
|
||||
static splay_tree_t io_tree = {.compare = (splay_compare_t)io_compare};
|
||||
static splay_tree_t timeout_tree = {.compare = (splay_compare_t)timeout_compare};
|
||||
void init_events(void) {
|
||||
event_tree = avl_alloc_tree((avl_compare_t) event_compare, (avl_action_t) free_event);
|
||||
}
|
||||
|
||||
void io_add(io_t *io, io_cb_t cb, void *data, int fd, int flags) {
|
||||
if(io->cb) {
|
||||
void exit_events(void) {
|
||||
avl_delete_tree(event_tree);
|
||||
}
|
||||
|
||||
void expire_events(void) {
|
||||
avl_node_t *node;
|
||||
event_t *event;
|
||||
time_t diff;
|
||||
|
||||
/*
|
||||
* Make all events appear expired by subtracting the difference between
|
||||
* the expiration time of the last event and the current time.
|
||||
*/
|
||||
|
||||
if(!event_tree->tail) {
|
||||
return;
|
||||
}
|
||||
|
||||
io->fd = fd;
|
||||
#ifdef HAVE_MINGW
|
||||
event = event_tree->tail->data;
|
||||
|
||||
if(io->fd != -1) {
|
||||
io->event = WSACreateEvent();
|
||||
|
||||
if(io->event == WSA_INVALID_EVENT) {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
event_count++;
|
||||
#endif
|
||||
io->cb = cb;
|
||||
io->data = data;
|
||||
io->node.data = io;
|
||||
|
||||
io_set(io, flags);
|
||||
|
||||
if(!splay_insert_node(&io_tree, &io->node)) {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_MINGW
|
||||
void io_add_event(io_t *io, io_cb_t cb, void *data, WSAEVENT event) {
|
||||
io->event = event;
|
||||
io_add(io, cb, data, -1, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
void io_set(io_t *io, int flags) {
|
||||
if(flags == io->flags) {
|
||||
if(event->time <= now) {
|
||||
return;
|
||||
}
|
||||
|
||||
io->flags = flags;
|
||||
diff = event->time - now;
|
||||
|
||||
if(io->fd == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef HAVE_MINGW
|
||||
|
||||
if(flags & IO_READ) {
|
||||
FD_SET(io->fd, &readfds);
|
||||
} else {
|
||||
FD_CLR(io->fd, &readfds);
|
||||
}
|
||||
|
||||
if(flags & IO_WRITE) {
|
||||
FD_SET(io->fd, &writefds);
|
||||
} else {
|
||||
FD_CLR(io->fd, &writefds);
|
||||
}
|
||||
|
||||
#else
|
||||
long events = 0;
|
||||
|
||||
if(flags & IO_WRITE) {
|
||||
events |= WRITE_EVENTS;
|
||||
}
|
||||
|
||||
if(flags & IO_READ) {
|
||||
events |= READ_EVENTS;
|
||||
}
|
||||
|
||||
if(WSAEventSelect(io->fd, io->event, events) != 0) {
|
||||
abort();
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
void io_del(io_t *io) {
|
||||
if(!io->cb) {
|
||||
return;
|
||||
}
|
||||
|
||||
io_set(io, 0);
|
||||
#ifdef HAVE_MINGW
|
||||
|
||||
if(io->fd != -1 && WSACloseEvent(io->event) == FALSE) {
|
||||
abort();
|
||||
}
|
||||
|
||||
event_count--;
|
||||
#endif
|
||||
|
||||
splay_unlink_node(&io_tree, &io->node);
|
||||
io->cb = NULL;
|
||||
}
|
||||
|
||||
void timeout_add(timeout_t *timeout, timeout_cb_t cb, void *data, struct timeval *tv) {
|
||||
timeout->cb = cb;
|
||||
timeout->data = data;
|
||||
timeout->node.data = timeout;
|
||||
|
||||
timeout_set(timeout, tv);
|
||||
}
|
||||
|
||||
void timeout_set(timeout_t *timeout, struct timeval *tv) {
|
||||
if(timerisset(&timeout->tv)) {
|
||||
splay_unlink_node(&timeout_tree, &timeout->node);
|
||||
}
|
||||
|
||||
if(!now.tv_sec) {
|
||||
gettimeofday(&now, NULL);
|
||||
}
|
||||
|
||||
timeradd(&now, tv, &timeout->tv);
|
||||
|
||||
if(!splay_insert_node(&timeout_tree, &timeout->node)) {
|
||||
abort();
|
||||
for(node = event_tree->head; node; node = node->next) {
|
||||
event = node->data;
|
||||
event->time -= diff;
|
||||
}
|
||||
}
|
||||
|
||||
void timeout_del(timeout_t *timeout) {
|
||||
if(!timeout->cb) {
|
||||
return;
|
||||
}
|
||||
|
||||
splay_unlink_node(&timeout_tree, &timeout->node);
|
||||
timeout->cb = 0;
|
||||
timeout->tv = (struct timeval) {
|
||||
0, 0
|
||||
};
|
||||
event_t *new_event(void) {
|
||||
return xmalloc_and_zero(sizeof(event_t));
|
||||
}
|
||||
|
||||
#ifndef HAVE_MINGW
|
||||
static int signal_compare(const signal_t *a, const signal_t *b) {
|
||||
return a->signum - b->signum;
|
||||
void free_event(event_t *event) {
|
||||
free(event);
|
||||
}
|
||||
|
||||
static io_t signalio;
|
||||
static int pipefd[2] = {-1, -1};
|
||||
static splay_tree_t signal_tree = {.compare = (splay_compare_t)signal_compare};
|
||||
|
||||
static void signal_handler(int signum) {
|
||||
unsigned char num = signum;
|
||||
write(pipefd[1], &num, 1);
|
||||
void event_add(event_t *event) {
|
||||
event->id = ++id;
|
||||
avl_insert(event_tree, event);
|
||||
}
|
||||
|
||||
static void signalio_handler(void *data, int flags) {
|
||||
(void)data;
|
||||
(void)flags;
|
||||
unsigned char signum;
|
||||
|
||||
if(read(pipefd[0], &signum, 1) != 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
signal_t *sig = splay_search(&signal_tree, &((signal_t) {
|
||||
.signum = signum
|
||||
}));
|
||||
|
||||
if(sig) {
|
||||
sig->cb(sig->data);
|
||||
}
|
||||
void event_del(event_t *event) {
|
||||
avl_delete(event_tree, event);
|
||||
}
|
||||
|
||||
static void pipe_init(void) {
|
||||
if(!pipe(pipefd)) {
|
||||
io_add(&signalio, signalio_handler, NULL, pipefd[0], IO_READ);
|
||||
}
|
||||
}
|
||||
event_t *get_expired_event(void) {
|
||||
event_t *event;
|
||||
|
||||
void signal_add(signal_t *sig, signal_cb_t cb, void *data, int signum) {
|
||||
if(sig->cb) {
|
||||
return;
|
||||
}
|
||||
if(event_tree->head) {
|
||||
event = event_tree->head->data;
|
||||
|
||||
sig->cb = cb;
|
||||
sig->data = data;
|
||||
sig->signum = signum;
|
||||
sig->node.data = sig;
|
||||
|
||||
if(pipefd[0] == -1) {
|
||||
pipe_init();
|
||||
}
|
||||
|
||||
signal(sig->signum, signal_handler);
|
||||
|
||||
if(!splay_insert_node(&signal_tree, &sig->node)) {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
void signal_del(signal_t *sig) {
|
||||
if(!sig->cb) {
|
||||
return;
|
||||
}
|
||||
|
||||
signal(sig->signum, SIG_DFL);
|
||||
|
||||
splay_unlink_node(&signal_tree, &sig->node);
|
||||
sig->cb = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct timeval *get_time_remaining(struct timeval *diff) {
|
||||
gettimeofday(&now, NULL);
|
||||
struct timeval *tv = NULL;
|
||||
|
||||
while(timeout_tree.head) {
|
||||
timeout_t *timeout = timeout_tree.head->data;
|
||||
timersub(&timeout->tv, &now, diff);
|
||||
|
||||
if(diff->tv_sec < 0) {
|
||||
timeout->cb(timeout->data);
|
||||
|
||||
if(timercmp(&timeout->tv, &now, <)) {
|
||||
timeout_del(timeout);
|
||||
}
|
||||
} else {
|
||||
tv = diff;
|
||||
break;
|
||||
if(event->time <= now) {
|
||||
avl_node_t *node = event_tree->head;
|
||||
avl_unlink_node(event_tree, node);
|
||||
free(node);
|
||||
return event;
|
||||
}
|
||||
}
|
||||
|
||||
return tv;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool event_loop(void) {
|
||||
running = true;
|
||||
|
||||
#ifndef HAVE_MINGW
|
||||
fd_set readable;
|
||||
fd_set writable;
|
||||
|
||||
while(running) {
|
||||
struct timeval diff;
|
||||
struct timeval *tv = get_time_remaining(&diff);
|
||||
memcpy(&readable, &readfds, sizeof(readable));
|
||||
memcpy(&writable, &writefds, sizeof(writable));
|
||||
|
||||
int fds = 0;
|
||||
|
||||
if(io_tree.tail) {
|
||||
io_t *last = io_tree.tail->data;
|
||||
fds = last->fd + 1;
|
||||
}
|
||||
|
||||
int n = select(fds, &readable, &writable, NULL, tv);
|
||||
|
||||
if(n < 0) {
|
||||
if(sockwouldblock(sockerrno)) {
|
||||
continue;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(!n) {
|
||||
continue;
|
||||
}
|
||||
|
||||
unsigned int curgen = io_tree.generation;
|
||||
|
||||
for splay_each(io_t, io, &io_tree) {
|
||||
if(FD_ISSET(io->fd, &writable)) {
|
||||
io->cb(io->data, IO_WRITE);
|
||||
} else if(FD_ISSET(io->fd, &readable)) {
|
||||
io->cb(io->data, IO_READ);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
There are scenarios in which the callback will remove another io_t from the tree
|
||||
(e.g. closing a double connection). Since splay_each does not support that, we
|
||||
need to exit the loop if that happens. That's okay, since any remaining events will
|
||||
get picked up by the next select() call.
|
||||
*/
|
||||
if(curgen != io_tree.generation) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
event_t *peek_next_event(void) {
|
||||
if(event_tree->head) {
|
||||
return event_tree->head->data;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
while(running) {
|
||||
struct timeval diff;
|
||||
struct timeval *tv = get_time_remaining(&diff);
|
||||
DWORD timeout_ms = tv ? (tv->tv_sec * 1000 + tv->tv_usec / 1000 + 1) : WSA_INFINITE;
|
||||
|
||||
if(!event_count) {
|
||||
Sleep(timeout_ms);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
For some reason, Microsoft decided to make the FD_WRITE event edge-triggered instead of level-triggered,
|
||||
which is the opposite of what select() does. In practice, that means that if a FD_WRITE event triggers,
|
||||
it will never trigger again until a send() returns EWOULDBLOCK. Since the semantics of this event loop
|
||||
is that write events are level-triggered (i.e. they continue firing until the socket is full), we need
|
||||
to emulate these semantics by making sure we fire each IO_WRITE that is still writeable.
|
||||
|
||||
Note that technically FD_CLOSE has the same problem, but it's okay because user code does not rely on
|
||||
this event being fired again if ignored.
|
||||
*/
|
||||
unsigned int curgen = io_tree.generation;
|
||||
|
||||
for splay_each(io_t, io, &io_tree) {
|
||||
if(io->flags & IO_WRITE && send(io->fd, NULL, 0, 0) == 0) {
|
||||
io->cb(io->data, IO_WRITE);
|
||||
|
||||
if(curgen != io_tree.generation) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(event_count > WSA_MAXIMUM_WAIT_EVENTS) {
|
||||
WSASetLastError(WSA_INVALID_PARAMETER);
|
||||
return(false);
|
||||
}
|
||||
|
||||
WSAEVENT events[WSA_MAXIMUM_WAIT_EVENTS];
|
||||
io_t *io_map[WSA_MAXIMUM_WAIT_EVENTS];
|
||||
DWORD event_index = 0;
|
||||
|
||||
for splay_each(io_t, io, &io_tree) {
|
||||
events[event_index] = io->event;
|
||||
io_map[event_index] = io;
|
||||
event_index++;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the generation number changes due to event addition
|
||||
* or removal by a callback we restart the loop.
|
||||
*/
|
||||
curgen = io_tree.generation;
|
||||
|
||||
for(DWORD event_offset = 0; event_offset < event_count;) {
|
||||
DWORD result = WSAWaitForMultipleEvents(event_count - event_offset, &events[event_offset], FALSE, timeout_ms, FALSE);
|
||||
|
||||
if(result == WSA_WAIT_TIMEOUT) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(result < WSA_WAIT_EVENT_0 || result >= WSA_WAIT_EVENT_0 + event_count - event_offset) {
|
||||
return(false);
|
||||
}
|
||||
|
||||
/* Look up io in the map by index. */
|
||||
event_index = result - WSA_WAIT_EVENT_0 + event_offset;
|
||||
io_t *io = io_map[event_index];
|
||||
|
||||
if(io->fd == -1) {
|
||||
io->cb(io->data, 0);
|
||||
|
||||
if(curgen != io_tree.generation) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
WSANETWORKEVENTS network_events;
|
||||
|
||||
if(WSAEnumNetworkEvents(io->fd, io->event, &network_events) != 0) {
|
||||
return(false);
|
||||
}
|
||||
|
||||
if(network_events.lNetworkEvents & READ_EVENTS) {
|
||||
io->cb(io->data, IO_READ);
|
||||
|
||||
if(curgen != io_tree.generation) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
The fd might be available for write too. However, if we already fired the read callback, that
|
||||
callback might have deleted the io (e.g. through terminate_connection()), so we can't fire the
|
||||
write callback here. Instead, we loop back and let the writable io loop above handle it.
|
||||
*/
|
||||
}
|
||||
|
||||
/* Continue checking the rest of the events. */
|
||||
event_offset = event_index + 1;
|
||||
|
||||
/* Just poll the next time through. */
|
||||
timeout_ms = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void event_exit(void) {
|
||||
running = false;
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
69
src/event.h
69
src/event.h
|
|
@ -2,8 +2,9 @@
|
|||
#define TINC_EVENT_H
|
||||
|
||||
/*
|
||||
event.h -- I/O, timeout and signal event handling
|
||||
Copyright (C) 2012-2013 Guus Sliepen <guus@tinc-vpn.org>
|
||||
event.h -- header for event.c
|
||||
Copyright (C) 2002-2009 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
2002-2005 Ivo Timmermans
|
||||
|
||||
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
|
||||
|
|
@ -20,57 +21,27 @@
|
|||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "splay_tree.h"
|
||||
#include "avl_tree.h"
|
||||
|
||||
#define IO_READ 1
|
||||
#define IO_WRITE 2
|
||||
extern avl_tree_t *event_tree;
|
||||
|
||||
typedef void (*io_cb_t)(void *data, int flags);
|
||||
typedef void (*timeout_cb_t)(void *data);
|
||||
typedef void (*signal_cb_t)(void *data);
|
||||
typedef void (*event_handler_t)(void *);
|
||||
|
||||
typedef struct io_t {
|
||||
int fd;
|
||||
int flags;
|
||||
#ifdef HAVE_MINGW
|
||||
WSAEVENT event;
|
||||
#endif
|
||||
io_cb_t cb;
|
||||
typedef struct event {
|
||||
time_t time;
|
||||
int id;
|
||||
event_handler_t handler;
|
||||
void *data;
|
||||
splay_node_t node;
|
||||
} io_t;
|
||||
} event_t;
|
||||
|
||||
typedef struct timeout_t {
|
||||
struct timeval tv;
|
||||
timeout_cb_t cb;
|
||||
void *data;
|
||||
splay_node_t node;
|
||||
} timeout_t;
|
||||
|
||||
typedef struct signal_t {
|
||||
int signum;
|
||||
signal_cb_t cb;
|
||||
void *data;
|
||||
splay_node_t node;
|
||||
} signal_t;
|
||||
|
||||
extern struct timeval now;
|
||||
|
||||
extern void io_add(io_t *io, io_cb_t cb, void *data, int fd, int flags);
|
||||
#ifdef HAVE_MINGW
|
||||
extern void io_add_event(io_t *io, io_cb_t cb, void *data, WSAEVENT event);
|
||||
#endif
|
||||
extern void io_del(io_t *io);
|
||||
extern void io_set(io_t *io, int flags);
|
||||
|
||||
extern void timeout_add(timeout_t *timeout, timeout_cb_t cb, void *data, struct timeval *tv);
|
||||
extern void timeout_del(timeout_t *timeout);
|
||||
extern void timeout_set(timeout_t *timeout, struct timeval *tv);
|
||||
|
||||
extern void signal_add(signal_t *sig, signal_cb_t cb, void *data, int signum);
|
||||
extern void signal_del(signal_t *sig);
|
||||
|
||||
extern bool event_loop(void);
|
||||
extern void event_exit(void);
|
||||
extern void init_events(void);
|
||||
extern void exit_events(void);
|
||||
extern void expire_events(void);
|
||||
extern event_t *new_event(void) __attribute__((__malloc__));
|
||||
extern void free_event(event_t *event);
|
||||
extern void event_add(event_t *event);
|
||||
extern void event_del(event_t *event);
|
||||
extern event_t *get_expired_event(void);
|
||||
extern event_t *peek_next_event(void);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
108
src/fake-getaddrinfo.c
Normal file
108
src/fake-getaddrinfo.c
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* fake library for ssh
|
||||
*
|
||||
* This file includes getaddrinfo(), freeaddrinfo() and gai_strerror().
|
||||
* These functions are defined in rfc2133.
|
||||
*
|
||||
* But these functions are not implemented correctly. The minimum subset
|
||||
* is implemented for ssh use only. For example, this routine assumes
|
||||
* that ai_family is AF_INET. Don't use it for another purpose.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "ipv4.h"
|
||||
#include "ipv6.h"
|
||||
#include "fake-getaddrinfo.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
#if !HAVE_DECL_GAI_STRERROR
|
||||
char *gai_strerror(int ecode) {
|
||||
switch(ecode) {
|
||||
case EAI_NODATA:
|
||||
return "No address associated with hostname";
|
||||
|
||||
case EAI_MEMORY:
|
||||
return "Memory allocation failure";
|
||||
|
||||
case EAI_FAMILY:
|
||||
return "Address family not supported";
|
||||
|
||||
default:
|
||||
return "Unknown error";
|
||||
}
|
||||
}
|
||||
#endif /* !HAVE_GAI_STRERROR */
|
||||
|
||||
#if !HAVE_DECL_FREEADDRINFO
|
||||
void freeaddrinfo(struct addrinfo *ai) {
|
||||
struct addrinfo *next;
|
||||
|
||||
while(ai) {
|
||||
next = ai->ai_next;
|
||||
free(ai);
|
||||
ai = next;
|
||||
}
|
||||
}
|
||||
#endif /* !HAVE_FREEADDRINFO */
|
||||
|
||||
#if !HAVE_DECL_GETADDRINFO
|
||||
static struct addrinfo *malloc_ai(uint16_t port, uint32_t addr) {
|
||||
struct addrinfo *ai;
|
||||
|
||||
ai = xmalloc_and_zero(sizeof(struct addrinfo) + sizeof(struct sockaddr_in));
|
||||
|
||||
ai->ai_addr = (struct sockaddr *)(ai + 1);
|
||||
ai->ai_addrlen = sizeof(struct sockaddr_in);
|
||||
ai->ai_addr->sa_family = ai->ai_family = AF_INET;
|
||||
|
||||
((struct sockaddr_in *)(ai)->ai_addr)->sin_port = port;
|
||||
((struct sockaddr_in *)(ai)->ai_addr)->sin_addr.s_addr = addr;
|
||||
|
||||
return ai;
|
||||
}
|
||||
|
||||
int getaddrinfo(const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res) {
|
||||
struct addrinfo *prev = NULL;
|
||||
struct hostent *hp;
|
||||
struct in_addr in = {0};
|
||||
int i;
|
||||
uint16_t port = 0;
|
||||
|
||||
if(hints && hints->ai_family != AF_INET && hints->ai_family != AF_UNSPEC) {
|
||||
return EAI_FAMILY;
|
||||
}
|
||||
|
||||
if(servname) {
|
||||
port = htons(atoi(servname));
|
||||
}
|
||||
|
||||
if(hints && hints->ai_flags & AI_PASSIVE) {
|
||||
*res = malloc_ai(port, htonl(0x00000000));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!hostname) {
|
||||
*res = malloc_ai(port, htonl(0x7f000001));
|
||||
return 0;
|
||||
}
|
||||
|
||||
hp = gethostbyname(hostname);
|
||||
|
||||
if(!hp || !hp->h_addr_list || !hp->h_addr_list[0]) {
|
||||
return EAI_NODATA;
|
||||
}
|
||||
|
||||
for(i = 0; hp->h_addr_list[i]; i++) {
|
||||
*res = malloc_ai(port, ((struct in_addr *)hp->h_addr_list[i])->s_addr);
|
||||
|
||||
if(prev) {
|
||||
prev->ai_next = *res;
|
||||
}
|
||||
|
||||
prev = *res;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* !HAVE_GETADDRINFO */
|
||||
57
src/fake-getaddrinfo.h
Normal file
57
src/fake-getaddrinfo.h
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
#ifndef TINC_FAKE_GETADDRINFO_H
|
||||
#define TINC_FAKE_GETADDRINFO_H
|
||||
|
||||
#ifndef EAI_NODATA
|
||||
#define EAI_NODATA 1
|
||||
#endif
|
||||
|
||||
#ifndef EAI_MEMORY
|
||||
#define EAI_MEMORY 2
|
||||
#endif
|
||||
|
||||
#ifndef EAI_FAMILY
|
||||
#define EAI_FAMILY 3
|
||||
#endif
|
||||
|
||||
#ifndef AI_PASSIVE
|
||||
# define AI_PASSIVE 1
|
||||
# define AI_CANONNAME 2
|
||||
#endif
|
||||
|
||||
#ifndef NI_NUMERICHOST
|
||||
# define NI_NUMERICHOST 2
|
||||
# define NI_NAMEREQD 4
|
||||
# define NI_NUMERICSERV 8
|
||||
#endif
|
||||
|
||||
#ifndef AI_NUMERICHOST
|
||||
#define AI_NUMERICHOST 4
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRUCT_ADDRINFO
|
||||
struct addrinfo {
|
||||
int ai_flags; /* AI_PASSIVE, AI_CANONNAME */
|
||||
int ai_family; /* PF_xxx */
|
||||
int ai_socktype; /* SOCK_xxx */
|
||||
int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
|
||||
size_t ai_addrlen; /* length of ai_addr */
|
||||
char *ai_canonname; /* canonical name for hostname */
|
||||
struct sockaddr *ai_addr; /* binary address */
|
||||
struct addrinfo *ai_next; /* next structure in linked list */
|
||||
};
|
||||
#endif /* !HAVE_STRUCT_ADDRINFO */
|
||||
|
||||
#if !HAVE_DECL_GETADDRINFO
|
||||
int getaddrinfo(const char *hostname, const char *servname,
|
||||
const struct addrinfo *hints, struct addrinfo **res);
|
||||
#endif /* !HAVE_GETADDRINFO */
|
||||
|
||||
#if !HAVE_DECL_GAI_STRERROR
|
||||
char *gai_strerror(int ecode);
|
||||
#endif /* !HAVE_GAI_STRERROR */
|
||||
|
||||
#if !HAVE_DECL_FREEADDRINFO
|
||||
void freeaddrinfo(struct addrinfo *ai);
|
||||
#endif /* !HAVE_FREEADDRINFO */
|
||||
|
||||
#endif
|
||||
64
src/fake-getnameinfo.c
Normal file
64
src/fake-getnameinfo.c
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* fake library for ssh
|
||||
*
|
||||
* This file includes getnameinfo().
|
||||
* These functions are defined in rfc2133.
|
||||
*
|
||||
* But these functions are not implemented correctly. The minimum subset
|
||||
* is implemented for ssh use only. For example, this routine assumes
|
||||
* that ai_family is AF_INET. Don't use it for another purpose.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "fake-getnameinfo.h"
|
||||
#include "fake-getaddrinfo.h"
|
||||
|
||||
#if !HAVE_DECL_GETNAMEINFO
|
||||
|
||||
int getnameinfo(const struct sockaddr *sa, size_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags) {
|
||||
struct sockaddr_in *sin = (struct sockaddr_in *)sa;
|
||||
struct hostent *hp;
|
||||
int len;
|
||||
|
||||
if(sa->sa_family != AF_INET) {
|
||||
return EAI_FAMILY;
|
||||
}
|
||||
|
||||
if(serv && servlen) {
|
||||
len = snprintf(serv, servlen, "%d", ntohs(sin->sin_port));
|
||||
|
||||
if(len < 0 || len >= servlen) {
|
||||
return EAI_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
if(!host || !hostlen) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(flags & NI_NUMERICHOST) {
|
||||
len = snprintf(host, hostlen, "%s", inet_ntoa(sin->sin_addr));
|
||||
|
||||
if(len < 0 || len >= hostlen) {
|
||||
return EAI_MEMORY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
hp = gethostbyaddr((char *)&sin->sin_addr, sizeof(struct in_addr), AF_INET);
|
||||
|
||||
if(!hp || !hp->h_name || !hp->h_name[0]) {
|
||||
return EAI_NODATA;
|
||||
}
|
||||
|
||||
len = snprintf(host, hostlen, "%s", hp->h_name);
|
||||
|
||||
if(len < 0 || len >= hostlen) {
|
||||
return EAI_MEMORY;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* !HAVE_GETNAMEINFO */
|
||||
16
src/fake-getnameinfo.h
Normal file
16
src/fake-getnameinfo.h
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#ifndef TINC_FAKE_GETNAMEINFO_H
|
||||
#define TINC_FAKE_GETNAMEINFO_H
|
||||
|
||||
#if !HAVE_DECL_GETNAMEINFO
|
||||
int getnameinfo(const struct sockaddr *sa, size_t salen, char *host,
|
||||
size_t hostlen, char *serv, size_t servlen, int flags);
|
||||
#endif /* !HAVE_GETNAMEINFO */
|
||||
|
||||
#ifndef NI_MAXSERV
|
||||
# define NI_MAXSERV 32
|
||||
#endif /* !NI_MAXSERV */
|
||||
#ifndef NI_MAXHOST
|
||||
# define NI_MAXHOST 1025
|
||||
#endif /* !NI_MAXHOST */
|
||||
|
||||
#endif
|
||||
125
src/fd_device.c
125
src/fd_device.c
|
|
@ -1,125 +0,0 @@
|
|||
/*
|
||||
fd_device.c -- Interaction with Android tun fd
|
||||
Copyright (C) 2001-2005 Ivo Timmermans,
|
||||
2001-2016 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2009 Grzegorz Dymarek <gregd72002@googlemail.com>
|
||||
2016 Pacien TRAN-GIRARD <pacien@pacien.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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
#include "conf.h"
|
||||
#include "device.h"
|
||||
#include "ethernet.h"
|
||||
#include "logger.h"
|
||||
#include "net.h"
|
||||
#include "route.h"
|
||||
#include "utils.h"
|
||||
|
||||
static inline bool check_config(void) {
|
||||
if(routing_mode == RMODE_SWITCH) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Switch mode not supported (requires unsupported TAP device)!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!get_config_int(lookup_config(config_tree, "Device"), &device_fd)) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not read fd from configuration!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool setup_device(void) {
|
||||
if(!check_config()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(device_fd < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not open %s: %s!", device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
logger(DEBUG_ALWAYS, LOG_INFO, "fd/%d adapter set up.", device_fd);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void close_device(void) {
|
||||
close(device_fd);
|
||||
device_fd = -1;
|
||||
}
|
||||
|
||||
static inline uint16_t get_ip_ethertype(vpn_packet_t *packet) {
|
||||
switch(DATA(packet)[ETH_HLEN] >> 4) {
|
||||
case 4:
|
||||
return ETH_P_IP;
|
||||
|
||||
case 6:
|
||||
return ETH_P_IPV6;
|
||||
|
||||
default:
|
||||
return ETH_P_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void set_etherheader(vpn_packet_t *packet, uint16_t ethertype) {
|
||||
memset(DATA(packet), 0, ETH_HLEN - ETHER_TYPE_LEN);
|
||||
|
||||
DATA(packet)[ETH_HLEN - ETHER_TYPE_LEN] = (ethertype >> 8) & 0xFF;
|
||||
DATA(packet)[ETH_HLEN - ETHER_TYPE_LEN + 1] = ethertype & 0xFF;
|
||||
}
|
||||
|
||||
static bool read_packet(vpn_packet_t *packet) {
|
||||
int lenin = read(device_fd, DATA(packet) + ETH_HLEN, MTU - ETH_HLEN);
|
||||
|
||||
if(lenin <= 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from fd/%d: %s!", device_fd, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16_t ethertype = get_ip_ethertype(packet);
|
||||
|
||||
if(ethertype == ETH_P_MAX) {
|
||||
logger(DEBUG_TRAFFIC, LOG_ERR, "Unknown IP version while reading packet from fd/%d!", device_fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
set_etherheader(packet, ethertype);
|
||||
packet->len = lenin + ETH_HLEN;
|
||||
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Read packet of %d bytes from fd/%d.", packet->len, device_fd);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool write_packet(vpn_packet_t *packet) {
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Writing packet of %d bytes to fd/%d.", packet->len, device_fd);
|
||||
|
||||
if(write(device_fd, DATA(packet) + ETH_HLEN, packet->len - ETH_HLEN) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while writing to fd/%d: %s!", device_fd, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const devops_t fd_devops = {
|
||||
.setup = setup_device,
|
||||
.close = close_device,
|
||||
.read = read_packet,
|
||||
.write = write_packet,
|
||||
};
|
||||
603
src/fsck.c
603
src/fsck.c
|
|
@ -1,603 +0,0 @@
|
|||
/*
|
||||
fsck.c -- Check the configuration files for problems
|
||||
Copyright (C) 2014 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "crypto.h"
|
||||
#include "ecdsa.h"
|
||||
#include "ecdsagen.h"
|
||||
#include "fsck.h"
|
||||
#include "names.h"
|
||||
#ifndef DISABLE_LEGACY
|
||||
#include "rsa.h"
|
||||
#include "rsagen.h"
|
||||
#endif
|
||||
#include "tincctl.h"
|
||||
#include "utils.h"
|
||||
|
||||
static bool ask_fix(void) {
|
||||
if(force) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if(!tty) {
|
||||
return false;
|
||||
}
|
||||
|
||||
again:
|
||||
fprintf(stderr, "Fix y/n? ");
|
||||
char buf[1024];
|
||||
|
||||
if(!fgets(buf, sizeof(buf), stdin)) {
|
||||
tty = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
if(buf[0] == 'y' || buf[0] == 'Y') {
|
||||
return true;
|
||||
}
|
||||
|
||||
if(buf[0] == 'n' || buf[0] == 'N') {
|
||||
return false;
|
||||
}
|
||||
|
||||
goto again;
|
||||
}
|
||||
|
||||
static void print_tinc_cmd(const char *argv0, const char *format, ...) {
|
||||
if(confbasegiven) {
|
||||
fprintf(stderr, "%s -c %s ", argv0, confbase);
|
||||
} else if(netname) {
|
||||
fprintf(stderr, "%s -n %s ", argv0, netname);
|
||||
} else {
|
||||
fprintf(stderr, "%s ", argv0);
|
||||
}
|
||||
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
vfprintf(stderr, format, va);
|
||||
va_end(va);
|
||||
fputc('\n', stderr);
|
||||
}
|
||||
|
||||
static int strtailcmp(const char *str, const char *tail) {
|
||||
size_t slen = strlen(str);
|
||||
size_t tlen = strlen(tail);
|
||||
|
||||
if(tlen > slen) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return memcmp(str + slen - tlen, tail, tlen);
|
||||
}
|
||||
|
||||
static void check_conffile(const char *fname, bool server) {
|
||||
(void)server;
|
||||
|
||||
FILE *f = fopen(fname, "r");
|
||||
|
||||
if(!f) {
|
||||
fprintf(stderr, "ERROR: cannot read %s: %s\n", fname, strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
char line[2048];
|
||||
int lineno = 0;
|
||||
bool skip = false;
|
||||
const int maxvariables = 50;
|
||||
int count[maxvariables];
|
||||
memset(count, 0, sizeof(count));
|
||||
|
||||
while(fgets(line, sizeof(line), f)) {
|
||||
if(skip) {
|
||||
if(!strncmp(line, "-----END", 8)) {
|
||||
skip = false;
|
||||
}
|
||||
|
||||
continue;
|
||||
} else {
|
||||
if(!strncmp(line, "-----BEGIN", 10)) {
|
||||
skip = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
int len;
|
||||
char *variable, *value, *eol;
|
||||
variable = value = line;
|
||||
|
||||
lineno++;
|
||||
|
||||
eol = line + strlen(line);
|
||||
|
||||
while(strchr("\t \r\n", *--eol)) {
|
||||
*eol = '\0';
|
||||
}
|
||||
|
||||
if(!line[0] || line[0] == '#') {
|
||||
continue;
|
||||
}
|
||||
|
||||
len = strcspn(value, "\t =");
|
||||
value += len;
|
||||
value += strspn(value, "\t ");
|
||||
|
||||
if(*value == '=') {
|
||||
value++;
|
||||
value += strspn(value, "\t ");
|
||||
}
|
||||
|
||||
variable[len] = '\0';
|
||||
|
||||
bool found = false;
|
||||
|
||||
for(int i = 0; variables[i].name; i++) {
|
||||
if(strcasecmp(variables[i].name, variable)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
found = true;
|
||||
|
||||
if(variables[i].type & VAR_OBSOLETE) {
|
||||
fprintf(stderr, "WARNING: obsolete variable %s in %s line %d\n", variable, fname, lineno);
|
||||
}
|
||||
|
||||
if(i < maxvariables) {
|
||||
count[i]++;
|
||||
}
|
||||
}
|
||||
|
||||
if(!found) {
|
||||
fprintf(stderr, "WARNING: unknown variable %s in %s line %d\n", variable, fname, lineno);
|
||||
}
|
||||
|
||||
if(!*value) {
|
||||
fprintf(stderr, "ERROR: no value for variable %s in %s line %d\n", variable, fname, lineno);
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = 0; variables[i].name && i < maxvariables; i++) {
|
||||
if(count[i] > 1 && !(variables[i].type & VAR_MULTIPLE)) {
|
||||
fprintf(stderr, "WARNING: multiple instances of variable %s in %s\n", variables[i].name, fname);
|
||||
}
|
||||
}
|
||||
|
||||
if(ferror(f)) {
|
||||
fprintf(stderr, "ERROR: while reading %s: %s\n", fname, strerror(errno));
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
int fsck(const char *argv0) {
|
||||
#ifdef HAVE_MINGW
|
||||
int uid = 0;
|
||||
#else
|
||||
uid_t uid = getuid();
|
||||
#endif
|
||||
|
||||
// Check that tinc.conf is readable.
|
||||
|
||||
if(access(tinc_conf, R_OK)) {
|
||||
fprintf(stderr, "ERROR: cannot read %s: %s\n", tinc_conf, strerror(errno));
|
||||
|
||||
if(errno == ENOENT) {
|
||||
fprintf(stderr, "No tinc configuration found. Create a new one with:\n\n");
|
||||
print_tinc_cmd(argv0, "init");
|
||||
} else if(errno == EACCES) {
|
||||
if(uid != 0) {
|
||||
fprintf(stderr, "You are currently not running tinc as root. Use sudo?\n");
|
||||
} else {
|
||||
fprintf(stderr, "Check the permissions of each component of the path %s.\n", tinc_conf);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *name = get_my_name(true);
|
||||
|
||||
if(!name) {
|
||||
fprintf(stderr, "ERROR: tinc cannot run without a valid Name.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Check for private keys.
|
||||
// TODO: use RSAPrivateKeyFile and Ed25519PrivateKeyFile variables if present.
|
||||
|
||||
struct stat st;
|
||||
char fname[PATH_MAX];
|
||||
char dname[PATH_MAX];
|
||||
|
||||
#ifndef DISABLE_LEGACY
|
||||
rsa_t *rsa_priv = NULL;
|
||||
snprintf(fname, sizeof(fname), "%s/rsa_key.priv", confbase);
|
||||
|
||||
if(stat(fname, &st)) {
|
||||
if(errno != ENOENT) {
|
||||
// Something is seriously wrong here. If we can access the directory with tinc.conf in it, we should certainly be able to stat() an existing file.
|
||||
fprintf(stderr, "ERROR: cannot read %s: %s\n", fname, strerror(errno));
|
||||
fprintf(stderr, "Please correct this error.\n");
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
FILE *f = fopen(fname, "r");
|
||||
|
||||
if(!f) {
|
||||
fprintf(stderr, "ERROR: could not open %s: %s\n", fname, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
rsa_priv = rsa_read_pem_private_key(f);
|
||||
fclose(f);
|
||||
|
||||
if(!rsa_priv) {
|
||||
fprintf(stderr, "ERROR: No key or unusable key found in %s.\n", fname);
|
||||
fprintf(stderr, "You can generate a new RSA key with:\n\n");
|
||||
print_tinc_cmd(argv0, "generate-rsa-keys");
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if !defined(HAVE_MINGW) && !defined(HAVE_CYGWIN)
|
||||
|
||||
if(st.st_mode & 077) {
|
||||
fprintf(stderr, "WARNING: unsafe file permissions on %s.\n", fname);
|
||||
|
||||
if(st.st_uid != uid) {
|
||||
fprintf(stderr, "You are not running %s as the same uid as %s.\n", argv0, fname);
|
||||
} else if(ask_fix()) {
|
||||
if(chmod(fname, st.st_mode & ~077)) {
|
||||
fprintf(stderr, "ERROR: could not change permissions of %s: %s\n", fname, strerror(errno));
|
||||
} else {
|
||||
fprintf(stderr, "Fixed permissions of %s.\n", fname);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
ecdsa_t *ecdsa_priv = NULL;
|
||||
snprintf(fname, sizeof(fname), "%s/ed25519_key.priv", confbase);
|
||||
|
||||
if(stat(fname, &st)) {
|
||||
if(errno != ENOENT) {
|
||||
// Something is seriously wrong here. If we can access the directory with tinc.conf in it, we should certainly be able to stat() an existing file.
|
||||
fprintf(stderr, "ERROR: cannot read %s: %s\n", fname, strerror(errno));
|
||||
fprintf(stderr, "Please correct this error.\n");
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
FILE *f = fopen(fname, "r");
|
||||
|
||||
if(!f) {
|
||||
fprintf(stderr, "ERROR: could not open %s: %s\n", fname, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
ecdsa_priv = ecdsa_read_pem_private_key(f);
|
||||
fclose(f);
|
||||
|
||||
if(!ecdsa_priv) {
|
||||
fprintf(stderr, "ERROR: No key or unusable key found in %s.\n", fname);
|
||||
fprintf(stderr, "You can generate a new Ed25519 key with:\n\n");
|
||||
print_tinc_cmd(argv0, "generate-ed25519-keys");
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if !defined(HAVE_MINGW) && !defined(HAVE_CYGWIN)
|
||||
|
||||
if(st.st_mode & 077) {
|
||||
fprintf(stderr, "WARNING: unsafe file permissions on %s.\n", fname);
|
||||
|
||||
if(st.st_uid != uid) {
|
||||
fprintf(stderr, "You are not running %s as the same uid as %s.\n", argv0, fname);
|
||||
} else if(ask_fix()) {
|
||||
if(chmod(fname, st.st_mode & ~077)) {
|
||||
fprintf(stderr, "ERROR: could not change permissions of %s: %s\n", fname, strerror(errno));
|
||||
} else {
|
||||
fprintf(stderr, "Fixed permissions of %s.\n", fname);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef DISABLE_LEGACY
|
||||
|
||||
if(!ecdsa_priv) {
|
||||
fprintf(stderr, "ERROR: No Ed25519 private key found.\n");
|
||||
#else
|
||||
|
||||
if(!rsa_priv && !ecdsa_priv) {
|
||||
fprintf(stderr, "ERROR: Neither RSA or Ed25519 private key found.\n");
|
||||
#endif
|
||||
fprintf(stderr, "You can generate new keys with:\n\n");
|
||||
print_tinc_cmd(argv0, "generate-keys");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Check for public keys.
|
||||
// TODO: use RSAPublicKeyFile variable if present.
|
||||
|
||||
snprintf(fname, sizeof(fname), "%s/hosts/%s", confbase, name);
|
||||
|
||||
if(access(fname, R_OK)) {
|
||||
fprintf(stderr, "WARNING: cannot read %s\n", fname);
|
||||
}
|
||||
|
||||
FILE *f;
|
||||
|
||||
#ifndef DISABLE_LEGACY
|
||||
rsa_t *rsa_pub = NULL;
|
||||
|
||||
f = fopen(fname, "r");
|
||||
|
||||
if(f) {
|
||||
rsa_pub = rsa_read_pem_public_key(f);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
if(rsa_priv) {
|
||||
if(!rsa_pub) {
|
||||
fprintf(stderr, "WARNING: No (usable) public RSA key found.\n");
|
||||
|
||||
if(ask_fix()) {
|
||||
FILE *f = fopen(fname, "a");
|
||||
|
||||
if(f) {
|
||||
if(rsa_write_pem_public_key(rsa_priv, f)) {
|
||||
fprintf(stderr, "Wrote RSA public key to %s.\n", fname);
|
||||
} else {
|
||||
fprintf(stderr, "ERROR: could not write RSA public key to %s.\n", fname);
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
} else {
|
||||
fprintf(stderr, "ERROR: could not append to %s: %s\n", fname, strerror(errno));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// TODO: suggest remedies
|
||||
size_t len = rsa_size(rsa_priv);
|
||||
|
||||
if(len != rsa_size(rsa_pub)) {
|
||||
fprintf(stderr, "ERROR: public and private RSA keys do not match.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
char buf1[len], buf2[len], buf3[len];
|
||||
randomize(buf1, sizeof(buf1));
|
||||
buf1[0] &= 0x7f;
|
||||
memset(buf2, 0, sizeof(buf2));
|
||||
memset(buf3, 0, sizeof(buf2));
|
||||
|
||||
if(!rsa_public_encrypt(rsa_pub, buf1, sizeof(buf1), buf2)) {
|
||||
fprintf(stderr, "ERROR: public RSA key does not work.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(!rsa_private_decrypt(rsa_priv, buf2, sizeof(buf2), buf3)) {
|
||||
fprintf(stderr, "ERROR: private RSA key does not work.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(memcmp(buf1, buf3, sizeof(buf1))) {
|
||||
fprintf(stderr, "ERROR: public and private RSA keys do not match.\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(rsa_pub) {
|
||||
fprintf(stderr, "WARNING: A public RSA key was found but no private key is known.\n");
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
ecdsa_t *ecdsa_pub = NULL;
|
||||
|
||||
f = fopen(fname, "r");
|
||||
|
||||
if(f) {
|
||||
ecdsa_pub = get_pubkey(f);
|
||||
|
||||
if(!ecdsa_pub) {
|
||||
rewind(f);
|
||||
ecdsa_pub = ecdsa_read_pem_public_key(f);
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
if(ecdsa_priv) {
|
||||
if(!ecdsa_pub) {
|
||||
fprintf(stderr, "WARNING: No (usable) public Ed25519 key found.\n");
|
||||
|
||||
if(ask_fix()) {
|
||||
FILE *f = fopen(fname, "a");
|
||||
|
||||
if(f) {
|
||||
if(ecdsa_write_pem_public_key(ecdsa_priv, f)) {
|
||||
fprintf(stderr, "Wrote Ed25519 public key to %s.\n", fname);
|
||||
} else {
|
||||
fprintf(stderr, "ERROR: could not write Ed25519 public key to %s.\n", fname);
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
} else {
|
||||
fprintf(stderr, "ERROR: could not append to %s: %s\n", fname, strerror(errno));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// TODO: suggest remedies
|
||||
char *key1 = ecdsa_get_base64_public_key(ecdsa_pub);
|
||||
|
||||
if(!key1) {
|
||||
fprintf(stderr, "ERROR: public Ed25519 key does not work.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *key2 = ecdsa_get_base64_public_key(ecdsa_priv);
|
||||
|
||||
if(!key2) {
|
||||
free(key1);
|
||||
fprintf(stderr, "ERROR: private Ed25519 key does not work.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int result = strcmp(key1, key2);
|
||||
free(key1);
|
||||
free(key2);
|
||||
|
||||
if(result) {
|
||||
fprintf(stderr, "ERROR: public and private Ed25519 keys do not match.\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(ecdsa_pub) {
|
||||
fprintf(stderr, "WARNING: A public Ed25519 key was found but no private key is known.\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Check whether scripts are executable
|
||||
|
||||
struct dirent *ent;
|
||||
DIR *dir = opendir(confbase);
|
||||
|
||||
if(!dir) {
|
||||
fprintf(stderr, "ERROR: cannot read directory %s: %s\n", confbase, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
while((ent = readdir(dir))) {
|
||||
if(strtailcmp(ent->d_name, "-up") && strtailcmp(ent->d_name, "-down")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
strncpy(fname, ent->d_name, sizeof(fname));
|
||||
char *dash = strrchr(fname, '-');
|
||||
|
||||
if(!dash) {
|
||||
continue;
|
||||
}
|
||||
|
||||
*dash = 0;
|
||||
|
||||
if(strcmp(fname, "tinc") && strcmp(fname, "host") && strcmp(fname, "subnet")) {
|
||||
static bool explained = false;
|
||||
fprintf(stderr, "WARNING: Unknown script %s" SLASH "%s found.\n", confbase, ent->d_name);
|
||||
|
||||
if(!explained) {
|
||||
fprintf(stderr, "The only scripts in %s executed by tinc are:\n", confbase);
|
||||
fprintf(stderr, "tinc-up, tinc-down, host-up, host-down, subnet-up and subnet-down.\n");
|
||||
explained = true;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
snprintf(fname, sizeof(fname), "%s" SLASH "%s", confbase, ent->d_name);
|
||||
|
||||
if(access(fname, R_OK | X_OK)) {
|
||||
if(errno != EACCES) {
|
||||
fprintf(stderr, "ERROR: cannot access %s: %s\n", fname, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
fprintf(stderr, "WARNING: cannot read and execute %s: %s\n", fname, strerror(errno));
|
||||
|
||||
if(ask_fix()) {
|
||||
if(chmod(fname, 0755)) {
|
||||
fprintf(stderr, "ERROR: cannot change permissions on %s: %s\n", fname, strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
snprintf(dname, sizeof(dname), "%s" SLASH "hosts", confbase);
|
||||
dir = opendir(dname);
|
||||
|
||||
if(!dir) {
|
||||
fprintf(stderr, "ERROR: cannot read directory %s: %s\n", dname, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
while((ent = readdir(dir))) {
|
||||
if(strtailcmp(ent->d_name, "-up") && strtailcmp(ent->d_name, "-down")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
strncpy(fname, ent->d_name, sizeof(fname));
|
||||
char *dash = strrchr(fname, '-');
|
||||
|
||||
if(!dash) {
|
||||
continue;
|
||||
}
|
||||
|
||||
*dash = 0;
|
||||
|
||||
snprintf(fname, sizeof(fname), "%s" SLASH "hosts" SLASH "%s", confbase, ent->d_name);
|
||||
|
||||
if(access(fname, R_OK | X_OK)) {
|
||||
if(errno != EACCES) {
|
||||
fprintf(stderr, "ERROR: cannot access %s: %s\n", fname, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
fprintf(stderr, "WARNING: cannot read and execute %s: %s\n", fname, strerror(errno));
|
||||
|
||||
if(ask_fix()) {
|
||||
if(chmod(fname, 0755)) {
|
||||
fprintf(stderr, "ERROR: cannot change permissions on %s: %s\n", fname, strerror(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
// Check for obsolete / unsafe / unknown configuration variables.
|
||||
|
||||
check_conffile(tinc_conf, true);
|
||||
|
||||
dir = opendir(dname);
|
||||
|
||||
if(dir) {
|
||||
while((ent = readdir(dir))) {
|
||||
if(!check_id(ent->d_name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
snprintf(fname, sizeof(fname), "%s" SLASH "hosts" SLASH "%s", confbase, ent->d_name);
|
||||
check_conffile(fname, false);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
25
src/fsck.h
25
src/fsck.h
|
|
@ -1,25 +0,0 @@
|
|||
#ifndef TINC_FSCK_H
|
||||
#define TINC_FSCK_H
|
||||
|
||||
/*
|
||||
fsck.h -- header for fsck.c.
|
||||
Copyright (C) 2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
extern int fsck(const char *argv0);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,284 +0,0 @@
|
|||
/*
|
||||
cipher.c -- Symmetric block cipher handling
|
||||
Copyright (C) 2007-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "cipher.h"
|
||||
#include "logger.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
static struct {
|
||||
const char *name;
|
||||
int algo;
|
||||
int mode;
|
||||
int nid;
|
||||
} ciphertable[] = {
|
||||
{"none", GCRY_CIPHER_NONE, GCRY_CIPHER_MODE_NONE, 0},
|
||||
|
||||
{NULL, GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_ECB, 92},
|
||||
{"blowfish", GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_CBC, 91},
|
||||
{NULL, GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_CFB, 93},
|
||||
{NULL, GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_OFB, 94},
|
||||
|
||||
{NULL, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 418},
|
||||
{"aes", GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CBC, 419},
|
||||
{NULL, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CFB, 421},
|
||||
{NULL, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_OFB, 420},
|
||||
|
||||
{NULL, GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_ECB, 422},
|
||||
{"aes192", GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CBC, 423},
|
||||
{NULL, GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CFB, 425},
|
||||
{NULL, GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_OFB, 424},
|
||||
|
||||
{NULL, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_ECB, 426},
|
||||
{"aes256", GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC, 427},
|
||||
{NULL, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CFB, 429},
|
||||
{NULL, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_OFB, 428},
|
||||
};
|
||||
|
||||
static bool nametocipher(const char *name, int *algo, int *mode) {
|
||||
size_t i;
|
||||
|
||||
for(i = 0; i < sizeof(ciphertable) / sizeof(*ciphertable); i++) {
|
||||
if(ciphertable[i].name && !strcasecmp(name, ciphertable[i].name)) {
|
||||
*algo = ciphertable[i].algo;
|
||||
*mode = ciphertable[i].mode;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool nidtocipher(int nid, int *algo, int *mode) {
|
||||
size_t i;
|
||||
|
||||
for(i = 0; i < sizeof(ciphertable) / sizeof(*ciphertable); i++) {
|
||||
if(nid == ciphertable[i].nid) {
|
||||
*algo = ciphertable[i].algo;
|
||||
*mode = ciphertable[i].mode;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool ciphertonid(int algo, int mode, int *nid) {
|
||||
size_t i;
|
||||
|
||||
for(i = 0; i < sizeof(ciphertable) / sizeof(*ciphertable); i++) {
|
||||
if(algo == ciphertable[i].algo && mode == ciphertable[i].mode) {
|
||||
*nid = ciphertable[i].nid;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool cipher_open(cipher_t *cipher, int algo, int mode) {
|
||||
gcry_error_t err;
|
||||
|
||||
if(!ciphertonid(algo, mode, &cipher->nid)) {
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Cipher %d mode %d has no corresponding nid!", algo, mode);
|
||||
return false;
|
||||
}
|
||||
|
||||
if((err = gcry_cipher_open(&cipher->handle, algo, mode, 0))) {
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Unable to initialise cipher %d mode %d: %s", algo, mode, gcry_strerror(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
cipher->keylen = gcry_cipher_get_algo_keylen(algo);
|
||||
cipher->blklen = gcry_cipher_get_algo_blklen(algo);
|
||||
cipher->key = xmalloc(cipher->keylen + cipher->blklen);
|
||||
cipher->padding = mode == GCRY_CIPHER_MODE_ECB || mode == GCRY_CIPHER_MODE_CBC;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cipher_open_by_name(cipher_t *cipher, const char *name) {
|
||||
int algo, mode;
|
||||
|
||||
if(!nametocipher(name, &algo, &mode)) {
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Unknown cipher name '%s'!", name);
|
||||
return false;
|
||||
}
|
||||
|
||||
return cipher_open(cipher, algo, mode);
|
||||
}
|
||||
|
||||
bool cipher_open_by_nid(cipher_t *cipher, int nid) {
|
||||
int algo, mode;
|
||||
|
||||
if(!nidtocipher(nid, &algo, &mode)) {
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Unknown cipher ID %d!", nid);
|
||||
return false;
|
||||
}
|
||||
|
||||
return cipher_open(cipher, algo, mode);
|
||||
}
|
||||
|
||||
bool cipher_open_blowfish_ofb(cipher_t *cipher) {
|
||||
return cipher_open(cipher, GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_OFB);
|
||||
}
|
||||
|
||||
void cipher_close(cipher_t *cipher) {
|
||||
if(cipher->handle) {
|
||||
gcry_cipher_close(cipher->handle);
|
||||
cipher->handle = NULL;
|
||||
}
|
||||
|
||||
free(cipher->key);
|
||||
cipher->key = NULL;
|
||||
}
|
||||
|
||||
size_t cipher_keylength(const cipher_t *cipher) {
|
||||
return cipher->keylen + cipher->blklen;
|
||||
}
|
||||
|
||||
void cipher_get_key(const cipher_t *cipher, void *key) {
|
||||
memcpy(key, cipher->key, cipher->keylen + cipher->blklen);
|
||||
}
|
||||
|
||||
bool cipher_set_key(cipher_t *cipher, void *key, bool encrypt) {
|
||||
memcpy(cipher->key, key, cipher->keylen + cipher->blklen);
|
||||
|
||||
gcry_cipher_setkey(cipher->handle, cipher->key, cipher->keylen);
|
||||
gcry_cipher_setiv(cipher->handle, cipher->key + cipher->keylen, cipher->blklen);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cipher_set_key_from_rsa(cipher_t *cipher, void *key, size_t len, bool encrypt) {
|
||||
memcpy(cipher->key, key + len - cipher->keylen, cipher->keylen + cipher->blklen);
|
||||
memcpy(cipher->key + cipher->keylen, key + len - cipher->keylen - cipher->blklen, cipher->blklen);
|
||||
|
||||
gcry_cipher_setkey(cipher->handle, cipher->key, cipher->keylen);
|
||||
gcry_cipher_setiv(cipher->handle, cipher->key + cipher->keylen, cipher->blklen);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cipher_regenerate_key(cipher_t *cipher, bool encrypt) {
|
||||
gcry_create_nonce(cipher->key, cipher->keylen + cipher->blklen);
|
||||
|
||||
gcry_cipher_setkey(cipher->handle, cipher->key, cipher->keylen);
|
||||
gcry_cipher_setiv(cipher->handle, cipher->key + cipher->keylen, cipher->blklen);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cipher_encrypt(cipher_t *cipher, const void *indata, size_t inlen, void *outdata, size_t *outlen, bool oneshot) {
|
||||
gcry_error_t err;
|
||||
uint8_t pad[cipher->blklen];
|
||||
|
||||
if(cipher->padding) {
|
||||
if(!oneshot) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t reqlen = ((inlen + cipher->blklen) / cipher->blklen) * cipher->blklen;
|
||||
|
||||
if(*outlen < reqlen) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while encrypting: not enough room for padding");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t padbyte = reqlen - inlen;
|
||||
inlen = reqlen - cipher->blklen;
|
||||
|
||||
for(int i = 0; i < cipher->blklen; i++)
|
||||
if(i < cipher->blklen - padbyte) {
|
||||
pad[i] = ((uint8_t *)indata)[inlen + i];
|
||||
} else {
|
||||
pad[i] = padbyte;
|
||||
}
|
||||
}
|
||||
|
||||
if(oneshot) {
|
||||
gcry_cipher_setiv(cipher->handle, cipher->key + cipher->keylen, cipher->blklen);
|
||||
}
|
||||
|
||||
if((err = gcry_cipher_encrypt(cipher->handle, outdata, *outlen, indata, inlen))) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while encrypting: %s", gcry_strerror(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(cipher->padding) {
|
||||
if((err = gcry_cipher_encrypt(cipher->handle, outdata + inlen, cipher->blklen, pad, cipher->blklen))) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while encrypting: %s", gcry_strerror(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
inlen += cipher->blklen;
|
||||
}
|
||||
|
||||
*outlen = inlen;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cipher_decrypt(cipher_t *cipher, const void *indata, size_t inlen, void *outdata, size_t *outlen, bool oneshot) {
|
||||
gcry_error_t err;
|
||||
|
||||
if(oneshot) {
|
||||
gcry_cipher_setiv(cipher->handle, cipher->key + cipher->keylen, cipher->blklen);
|
||||
}
|
||||
|
||||
if((err = gcry_cipher_decrypt(cipher->handle, outdata, *outlen, indata, inlen))) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while decrypting: %s", gcry_strerror(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(cipher->padding) {
|
||||
if(!oneshot) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t padbyte = ((uint8_t *)outdata)[inlen - 1];
|
||||
|
||||
if(padbyte == 0 || padbyte > cipher->blklen || padbyte > inlen) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while decrypting: invalid padding");
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t origlen = inlen - padbyte;
|
||||
|
||||
for(int i = inlen - 1; i >= origlen; i--)
|
||||
if(((uint8_t *)outdata)[i] != padbyte) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while decrypting: invalid padding");
|
||||
return false;
|
||||
}
|
||||
|
||||
*outlen = origlen;
|
||||
} else {
|
||||
*outlen = inlen;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int cipher_get_nid(const cipher_t *cipher) {
|
||||
return cipher->nid;
|
||||
}
|
||||
|
||||
bool cipher_active(const cipher_t *cipher) {
|
||||
return cipher->nid != 0;
|
||||
}
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
/*
|
||||
crypto.c -- Cryptographic miscellaneous functions and initialisation
|
||||
Copyright (C) 2007 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include <gcrypt.h>
|
||||
|
||||
#include "crypto.h"
|
||||
|
||||
void crypto_init() {
|
||||
}
|
||||
|
||||
void crypto_exit() {
|
||||
}
|
||||
|
||||
void randomize(void *out, size_t outlen) {
|
||||
gcry_create_nonce(out, outlen);
|
||||
}
|
||||
|
|
@ -1,182 +0,0 @@
|
|||
/*
|
||||
digest.c -- Digest handling
|
||||
Copyright (C) 2007-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "digest.h"
|
||||
#include "logger.h"
|
||||
|
||||
static struct {
|
||||
const char *name;
|
||||
int algo;
|
||||
int nid;
|
||||
} digesttable[] = {
|
||||
{"none", GCRY_MD_NONE, 0},
|
||||
{"sha1", GCRY_MD_SHA1, 64},
|
||||
{"sha256", GCRY_MD_SHA256, 672},
|
||||
{"sha384", GCRY_MD_SHA384, 673},
|
||||
{"sha512", GCRY_MD_SHA512, 674},
|
||||
};
|
||||
|
||||
static bool nametodigest(const char *name, int *algo) {
|
||||
int i;
|
||||
|
||||
for(i = 0; i < sizeof(digesttable) / sizeof(*digesttable); i++) {
|
||||
if(digesttable[i].name && !strcasecmp(name, digesttable[i].name)) {
|
||||
*algo = digesttable[i].algo;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool nidtodigest(int nid, int *algo) {
|
||||
int i;
|
||||
|
||||
for(i = 0; i < sizeof(digesttable) / sizeof(*digesttable); i++) {
|
||||
if(nid == digesttable[i].nid) {
|
||||
*algo = digesttable[i].algo;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool digesttonid(int algo, int *nid) {
|
||||
int i;
|
||||
|
||||
for(i = 0; i < sizeof(digesttable) / sizeof(*digesttable); i++) {
|
||||
if(algo == digesttable[i].algo) {
|
||||
*nid = digesttable[i].nid;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool digest_open(digest_t *digest, int algo, int maclength) {
|
||||
if(!digesttonid(algo, &digest->nid)) {
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Digest %d has no corresponding nid!", algo);
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int len = gcry_md_get_algo_dlen(algo);
|
||||
|
||||
if(maclength > len || maclength < 0) {
|
||||
digest->maclength = len;
|
||||
} else {
|
||||
digest->maclength = maclength;
|
||||
}
|
||||
|
||||
digest->algo = algo;
|
||||
digest->hmac = NULL;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool digest_open_by_name(digest_t *digest, const char *name, int maclength) {
|
||||
int algo;
|
||||
|
||||
if(!nametodigest(name, &algo)) {
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Unknown digest name '%s'!", name);
|
||||
return false;
|
||||
}
|
||||
|
||||
return digest_open(digest, algo, maclength);
|
||||
}
|
||||
|
||||
bool digest_open_by_nid(digest_t *digest, int nid, int maclength) {
|
||||
int algo;
|
||||
|
||||
if(!nidtodigest(nid, &algo)) {
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Unknown digest ID %d!", nid);
|
||||
return false;
|
||||
}
|
||||
|
||||
return digest_open(digest, algo, maclength);
|
||||
}
|
||||
|
||||
bool digest_open_sha1(digest_t *digest, int maclength) {
|
||||
return digest_open(digest, GCRY_MD_SHA1, maclength);
|
||||
}
|
||||
|
||||
void digest_close(digest_t *digest) {
|
||||
if(digest->hmac) {
|
||||
gcry_md_close(digest->hmac);
|
||||
}
|
||||
|
||||
digest->hmac = NULL;
|
||||
}
|
||||
|
||||
bool digest_set_key(digest_t *digest, const void *key, size_t len) {
|
||||
if(!digest->hmac) {
|
||||
gcry_md_open(&digest->hmac, digest->algo, GCRY_MD_FLAG_HMAC);
|
||||
}
|
||||
|
||||
if(!digest->hmac) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !gcry_md_setkey(digest->hmac, key, len);
|
||||
}
|
||||
|
||||
bool digest_create(digest_t *digest, const void *indata, size_t inlen, void *outdata) {
|
||||
unsigned int len = gcry_md_get_algo_dlen(digest->algo);
|
||||
|
||||
if(digest->hmac) {
|
||||
char *tmpdata;
|
||||
gcry_md_reset(digest->hmac);
|
||||
gcry_md_write(digest->hmac, indata, inlen);
|
||||
tmpdata = gcry_md_read(digest->hmac, digest->algo);
|
||||
|
||||
if(!tmpdata) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(outdata, tmpdata, digest->maclength);
|
||||
} else {
|
||||
char tmpdata[len];
|
||||
gcry_md_hash_buffer(digest->algo, tmpdata, indata, inlen);
|
||||
memcpy(outdata, tmpdata, digest->maclength);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool digest_verify(digest_t *digest, const void *indata, size_t inlen, const void *cmpdata) {
|
||||
unsigned int len = digest->maclength;
|
||||
char outdata[len];
|
||||
|
||||
return digest_create(digest, indata, inlen, outdata) && !memcmp(cmpdata, outdata, len);
|
||||
}
|
||||
|
||||
int digest_get_nid(const digest_t *digest) {
|
||||
return digest->nid;
|
||||
}
|
||||
|
||||
size_t digest_length(const digest_t *digest) {
|
||||
return digest->maclength;
|
||||
}
|
||||
|
||||
bool digest_active(const digest_t *digest) {
|
||||
return digest->algo != GCRY_MD_NONE;
|
||||
}
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
#ifndef TINC_GCRYPT_DIGEST_H
|
||||
#define TINC_GCRYPT_DIGEST_H
|
||||
|
||||
/*
|
||||
digest.h -- header file digest.c
|
||||
Copyright (C) 2007-2009 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <gcrypt.h>
|
||||
|
||||
#define DIGEST_MAX_SIZE 64
|
||||
|
||||
typedef struct digest {
|
||||
int algo;
|
||||
int nid;
|
||||
int maclength;
|
||||
gcry_md_hd_t hmac;
|
||||
} digest_t;
|
||||
|
||||
extern bool digest_open_by_name(struct digest *, const char *name, int maclength);
|
||||
extern bool digest_open_by_nid(struct digest *, int nid, int maclength);
|
||||
extern bool digest_open_sha1(struct digest *, int maclength);
|
||||
extern void digest_close(struct digest *);
|
||||
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 bool digest_set_key(struct digest *, const void *key, size_t len);
|
||||
extern int digest_get_nid(const struct digest *);
|
||||
extern size_t digest_length(const struct digest *);
|
||||
extern bool digest_active(const struct digest *);
|
||||
|
||||
#endif
|
||||
121
src/gcrypt/prf.c
121
src/gcrypt/prf.c
|
|
@ -1,121 +0,0 @@
|
|||
/*
|
||||
prf.c -- Pseudo-Random Function for key material generation
|
||||
Copyright (C) 2011-2013 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "../system.h"
|
||||
|
||||
#include "../prf.h"
|
||||
#include "../ed25519/sha512.h"
|
||||
|
||||
static void memxor(char *buf, char c, size_t len) {
|
||||
for(size_t i = 0; i < len; i++) {
|
||||
buf[i] ^= c;
|
||||
}
|
||||
}
|
||||
|
||||
static const size_t mdlen = 64;
|
||||
static const size_t blklen = 128;
|
||||
|
||||
static bool hmac_sha512(const char *key, size_t keylen, const char *msg, size_t msglen, char *out) {
|
||||
char tmp[blklen + mdlen];
|
||||
sha512_context md;
|
||||
|
||||
if(keylen <= blklen) {
|
||||
memcpy(tmp, key, keylen);
|
||||
memset(tmp + keylen, 0, blklen - keylen);
|
||||
} else {
|
||||
if(sha512(key, keylen, tmp) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(tmp + mdlen, 0, blklen - mdlen);
|
||||
}
|
||||
|
||||
if(sha512_init(&md) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// ipad
|
||||
memxor(tmp, 0x36, blklen);
|
||||
|
||||
if(sha512_update(&md, tmp, blklen) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// message
|
||||
if(sha512_update(&md, msg, msglen) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(sha512_final(&md, tmp + blklen) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// opad
|
||||
memxor(tmp, 0x36 ^ 0x5c, blklen);
|
||||
|
||||
if(sha512(tmp, sizeof(tmp), out) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/* Generate key material from a master secret and a seed, based on RFC 4346 section 5.
|
||||
We use SHA512 instead of MD5 and SHA1.
|
||||
*/
|
||||
|
||||
bool prf(const char *secret, size_t secretlen, char *seed, size_t seedlen, char *out, size_t outlen) {
|
||||
/* Data is what the "inner" HMAC function processes.
|
||||
It consists of the previous HMAC result plus the seed.
|
||||
*/
|
||||
|
||||
char data[mdlen + seedlen];
|
||||
memset(data, 0, mdlen);
|
||||
memcpy(data + mdlen, seed, seedlen);
|
||||
|
||||
char hash[mdlen];
|
||||
|
||||
while(outlen > 0) {
|
||||
/* Inner HMAC */
|
||||
if(!hmac_sha512(secret, secretlen, data, sizeof(data), data)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Outer HMAC */
|
||||
if(outlen >= mdlen) {
|
||||
if(!hmac_sha512(secret, secretlen, data, sizeof(data), out)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
out += mdlen;
|
||||
outlen -= mdlen;
|
||||
} else {
|
||||
if(!hmac_sha512(secret, secretlen, data, sizeof(data), hash)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(out, hash, outlen);
|
||||
out += outlen;
|
||||
outlen = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
327
src/gcrypt/rsa.c
327
src/gcrypt/rsa.c
|
|
@ -1,327 +0,0 @@
|
|||
/*
|
||||
rsa.c -- RSA key handling
|
||||
Copyright (C) 2007-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include <gcrypt.h>
|
||||
|
||||
#include "logger.h"
|
||||
#include "rsa.h"
|
||||
|
||||
// Base64 decoding table
|
||||
|
||||
static const uint8_t b64d[128] = {
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
|
||||
0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
|
||||
0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
|
||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
|
||||
0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
|
||||
0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
|
||||
0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
|
||||
0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e,
|
||||
0x1f, 0x20, 0x21, 0x22, 0x23, 0x24,
|
||||
0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,
|
||||
0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
|
||||
0x31, 0x32, 0x33, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff
|
||||
};
|
||||
|
||||
// PEM encoding/decoding functions
|
||||
|
||||
static bool pem_decode(FILE *fp, const char *header, uint8_t *buf, size_t size, size_t *outsize) {
|
||||
bool decode = false;
|
||||
char line[1024];
|
||||
uint16_t word = 0;
|
||||
int shift = 10;
|
||||
size_t i, j = 0;
|
||||
|
||||
while(!feof(fp)) {
|
||||
if(!fgets(line, sizeof(line), fp)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!decode && !strncmp(line, "-----BEGIN ", 11)) {
|
||||
if(!strncmp(line + 11, header, strlen(header))) {
|
||||
decode = true;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if(decode && !strncmp(line, "-----END", 8)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(!decode) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for(i = 0; line[i] >= ' '; i++) {
|
||||
if((signed char)line[i] < 0 || b64d[(int)line[i]] == 0xff) {
|
||||
break;
|
||||
}
|
||||
|
||||
word |= b64d[(int)line[i]] << shift;
|
||||
shift -= 6;
|
||||
|
||||
if(shift <= 2) {
|
||||
if(j > size) {
|
||||
errno = ENOMEM;
|
||||
return false;
|
||||
}
|
||||
|
||||
buf[j++] = word >> 8;
|
||||
word <<= 8;
|
||||
shift += 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(outsize) {
|
||||
*outsize = j;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// BER decoding functions
|
||||
|
||||
static int ber_read_id(unsigned char **p, size_t *buflen) {
|
||||
if(*buflen <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if((**p & 0x1f) == 0x1f) {
|
||||
int id = 0;
|
||||
bool more;
|
||||
|
||||
while(*buflen > 0) {
|
||||
id <<= 7;
|
||||
id |= **p & 0x7f;
|
||||
more = *(*p)++ & 0x80;
|
||||
(*buflen)--;
|
||||
|
||||
if(!more) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return id;
|
||||
} else {
|
||||
(*buflen)--;
|
||||
return *(*p)++ & 0x1f;
|
||||
}
|
||||
}
|
||||
|
||||
static size_t ber_read_len(unsigned char **p, size_t *buflen) {
|
||||
if(*buflen <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(**p & 0x80) {
|
||||
size_t result = 0;
|
||||
int len = *(*p)++ & 0x7f;
|
||||
(*buflen)--;
|
||||
|
||||
if(len > *buflen) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
while(len--) {
|
||||
result <<= 8;
|
||||
result |= *(*p)++;
|
||||
(*buflen)--;
|
||||
}
|
||||
|
||||
return result;
|
||||
} else {
|
||||
(*buflen)--;
|
||||
return *(*p)++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static bool ber_read_sequence(unsigned char **p, size_t *buflen, size_t *result) {
|
||||
int tag = ber_read_id(p, buflen);
|
||||
size_t len = ber_read_len(p, buflen);
|
||||
|
||||
if(tag == 0x10) {
|
||||
if(result) {
|
||||
*result = len;
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool ber_read_mpi(unsigned char **p, size_t *buflen, gcry_mpi_t *mpi) {
|
||||
int tag = ber_read_id(p, buflen);
|
||||
size_t len = ber_read_len(p, buflen);
|
||||
gcry_error_t err = 0;
|
||||
|
||||
if(tag != 0x02 || len > *buflen) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(mpi) {
|
||||
err = gcry_mpi_scan(mpi, GCRYMPI_FMT_USG, *p, len, NULL);
|
||||
}
|
||||
|
||||
*p += len;
|
||||
*buflen -= len;
|
||||
|
||||
return mpi ? !err : true;
|
||||
}
|
||||
|
||||
bool rsa_set_hex_public_key(rsa_t *rsa, char *n, char *e) {
|
||||
gcry_error_t err = 0;
|
||||
|
||||
err = gcry_mpi_scan(&rsa->n, GCRYMPI_FMT_HEX, n, 0, NULL)
|
||||
? : gcry_mpi_scan(&rsa->e, GCRYMPI_FMT_HEX, e, 0, NULL);
|
||||
|
||||
if(err) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading RSA public key: %s", gcry_strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool rsa_set_hex_private_key(rsa_t *rsa, char *n, char *e, char *d) {
|
||||
gcry_error_t err = 0;
|
||||
|
||||
err = gcry_mpi_scan(&rsa->n, GCRYMPI_FMT_HEX, n, 0, NULL)
|
||||
? : gcry_mpi_scan(&rsa->e, GCRYMPI_FMT_HEX, e, 0, NULL)
|
||||
? : gcry_mpi_scan(&rsa->d, GCRYMPI_FMT_HEX, d, 0, NULL);
|
||||
|
||||
if(err) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading RSA public key: %s", gcry_strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Read PEM RSA keys
|
||||
|
||||
bool rsa_read_pem_public_key(rsa_t *rsa, FILE *fp) {
|
||||
uint8_t derbuf[8096], *derp = derbuf;
|
||||
size_t derlen;
|
||||
|
||||
if(!pem_decode(fp, "RSA PUBLIC KEY", derbuf, sizeof(derbuf), &derlen)) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to read RSA public key: %s", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(!ber_read_sequence(&derp, &derlen, NULL)
|
||||
|| !ber_read_mpi(&derp, &derlen, &rsa->n)
|
||||
|| !ber_read_mpi(&derp, &derlen, &rsa->e)
|
||||
|| derlen) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while decoding RSA public key");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool rsa_read_pem_private_key(rsa_t *rsa, FILE *fp) {
|
||||
uint8_t derbuf[8096], *derp = derbuf;
|
||||
size_t derlen;
|
||||
|
||||
if(!pem_decode(fp, "RSA PRIVATE KEY", derbuf, sizeof(derbuf), &derlen)) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to read RSA private key: %s", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(!ber_read_sequence(&derp, &derlen, NULL)
|
||||
|| !ber_read_mpi(&derp, &derlen, NULL)
|
||||
|| !ber_read_mpi(&derp, &derlen, &rsa->n)
|
||||
|| !ber_read_mpi(&derp, &derlen, &rsa->e)
|
||||
|| !ber_read_mpi(&derp, &derlen, &rsa->d)
|
||||
|| !ber_read_mpi(&derp, &derlen, NULL) // p
|
||||
|| !ber_read_mpi(&derp, &derlen, NULL) // q
|
||||
|| !ber_read_mpi(&derp, &derlen, NULL)
|
||||
|| !ber_read_mpi(&derp, &derlen, NULL)
|
||||
|| !ber_read_mpi(&derp, &derlen, NULL) // u
|
||||
|| derlen) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while decoding RSA private key");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t rsa_size(rsa_t *rsa) {
|
||||
return (gcry_mpi_get_nbits(rsa->n) + 7) / 8;
|
||||
}
|
||||
|
||||
/* Well, libgcrypt has functions to handle RSA keys, but they suck.
|
||||
* So we just use libgcrypt's mpi functions, and do the math ourselves.
|
||||
*/
|
||||
|
||||
// TODO: get rid of this macro, properly clean up gcry_ structures after use
|
||||
#define check(foo) { gcry_error_t err = (foo); if(err) {logger(DEBUG_ALWAYS, LOG_ERR, "gcrypt error %s/%s at %s:%d", gcry_strsource(err), gcry_strerror(err), __FILE__, __LINE__); return false; }}
|
||||
|
||||
bool rsa_public_encrypt(rsa_t *rsa, void *in, size_t len, void *out) {
|
||||
gcry_mpi_t inmpi;
|
||||
check(gcry_mpi_scan(&inmpi, GCRYMPI_FMT_USG, in, len, NULL));
|
||||
|
||||
gcry_mpi_t outmpi = gcry_mpi_new(len * 8);
|
||||
gcry_mpi_powm(outmpi, inmpi, rsa->e, rsa->n);
|
||||
|
||||
int pad = len - (gcry_mpi_get_nbits(outmpi) + 7) / 8;
|
||||
|
||||
while(pad--) {
|
||||
*(char *)out++ = 0;
|
||||
}
|
||||
|
||||
check(gcry_mpi_print(GCRYMPI_FMT_USG, out, len, NULL, outmpi));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool rsa_private_decrypt(rsa_t *rsa, void *in, size_t len, void *out) {
|
||||
gcry_mpi_t inmpi;
|
||||
check(gcry_mpi_scan(&inmpi, GCRYMPI_FMT_USG, in, len, NULL));
|
||||
|
||||
gcry_mpi_t outmpi = gcry_mpi_new(len * 8);
|
||||
gcry_mpi_powm(outmpi, inmpi, rsa->d, rsa->n);
|
||||
|
||||
int pad = len - (gcry_mpi_get_nbits(outmpi) + 7) / 8;
|
||||
|
||||
while(pad--) {
|
||||
*(char *)out++ = 0;
|
||||
}
|
||||
|
||||
check(gcry_mpi_print(GCRYMPI_FMT_USG, out, len, NULL, outmpi));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1,239 +0,0 @@
|
|||
/*
|
||||
rsagen.c -- RSA key generation and export
|
||||
Copyright (C) 2008-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include <gcrypt.h>
|
||||
|
||||
#include "rsagen.h"
|
||||
|
||||
#if 0
|
||||
// Base64 encoding table
|
||||
|
||||
static const char b64e[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
// PEM encoding
|
||||
|
||||
static bool pem_encode(FILE *fp, const char *header, uint8_t *buf, size_t size) {
|
||||
bool decode = false;
|
||||
char line[1024];
|
||||
uint32_t word = 0;
|
||||
int shift = 0;
|
||||
size_t i, j = 0;
|
||||
|
||||
fprintf(fp, "-----BEGIN %s-----\n", header);
|
||||
|
||||
for(i = 0; i < size; i += 3) {
|
||||
if(i <= size - 3) {
|
||||
word = buf[i] << 16 | buf[i + 1] << 8 | buf[i + 2];
|
||||
} else {
|
||||
word = buf[i] << 16;
|
||||
|
||||
if(i == size - 2) {
|
||||
word |= buf[i + 1] << 8;
|
||||
}
|
||||
}
|
||||
|
||||
line[j++] = b64e[(word >> 18) ];
|
||||
line[j++] = b64e[(word >> 12) & 0x3f];
|
||||
line[j++] = b64e[(word >> 6) & 0x3f];
|
||||
line[j++] = b64e[(word) & 0x3f];
|
||||
|
||||
if(j >= 64) {
|
||||
line[j++] = '\n';
|
||||
line[j] = 0;
|
||||
fputs(line, fp);
|
||||
j = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(size % 3 > 0) {
|
||||
if(size % 3 > 1) {
|
||||
line[j++] = '=';
|
||||
}
|
||||
|
||||
line[j++] = '=';
|
||||
}
|
||||
|
||||
if(j) {
|
||||
line[j++] = '\n';
|
||||
line[j] = 0;
|
||||
fputs(line, fp);
|
||||
}
|
||||
|
||||
fprintf(fp, "-----END %s-----\n", header);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// BER encoding functions
|
||||
|
||||
static bool ber_write_id(uint8_t **p, size_t *buflen, int id) {
|
||||
if(*buflen <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(id >= 0x1f) {
|
||||
while(id) {
|
||||
if(*buflen <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
(*buflen)--;
|
||||
**p = id & 0x7f;
|
||||
id >>= 7;
|
||||
|
||||
if(id) {
|
||||
**p |= 0x80;
|
||||
}
|
||||
|
||||
(*p)++;
|
||||
}
|
||||
} else {
|
||||
(*buflen)--;
|
||||
*(*p)++ = id;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ber_write_len(uint8_t **p, size_t *buflen, size_t len) {
|
||||
do {
|
||||
if(*buflen <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
(*buflen)--;
|
||||
**p = len & 0x7f;
|
||||
len >>= 7;
|
||||
|
||||
if(len) {
|
||||
**p |= 0x80;
|
||||
}
|
||||
|
||||
(*p)++;
|
||||
} while(len);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ber_write_sequence(uint8_t **p, size_t *buflen, uint8_t *seqbuf, size_t seqlen) {
|
||||
if(!ber_write_id(p, buflen, 0x10) || !ber_write_len(p, buflen, seqlen) || *buflen < seqlen) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(*p, seqbuf, seqlen);
|
||||
*p += seqlen;
|
||||
*buflen -= seqlen;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ber_write_mpi(uint8_t **p, size_t *buflen, gcry_mpi_t mpi) {
|
||||
uint8_t tmpbuf[1024];
|
||||
size_t tmplen = sizeof(tmpbuf);
|
||||
gcry_error_t err;
|
||||
|
||||
err = gcry_mpi_aprint(GCRYMPI_FMT_USG, &tmpbuf, &tmplen, mpi);
|
||||
|
||||
if(err) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!ber_write_id(p, buflen, 0x02) || !ber_write_len(p, buflen, tmplen) || *buflen < tmplen) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(*p, tmpbuf, tmplen);
|
||||
*p += tmplen;
|
||||
*buflen -= tmplen;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Write PEM RSA keys
|
||||
|
||||
bool rsa_write_pem_public_key(rsa_t *rsa, FILE *fp) {
|
||||
uint8_t derbuf1[8096];
|
||||
uint8_t derbuf2[8096];
|
||||
uint8_t *derp1 = derbuf1;
|
||||
uint8_t *derp2 = derbuf2;
|
||||
size_t derlen1 = sizeof(derbuf1);
|
||||
size_t derlen2 = sizeof(derbuf2);
|
||||
|
||||
if(!ber_write_mpi(&derp1, &derlen1, &rsa->n)
|
||||
|| !ber_write_mpi(&derp1, &derlen1, &rsa->e)
|
||||
|| !ber_write_sequence(&derp2, &derlen2, derbuf1, derlen1)) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while encoding RSA public key");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!pem_encode(fp, "RSA PUBLIC KEY", derbuf2, derlen2)) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to write RSA public key: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool rsa_write_pem_private_key(rsa_t *rsa, FILE *fp) {
|
||||
uint8_t derbuf1[8096];
|
||||
uint8_t derbuf2[8096];
|
||||
uint8_t *derp1 = derbuf1;
|
||||
uint8_t *derp2 = derbuf2;
|
||||
size_t derlen1 = sizeof(derbuf1);
|
||||
size_t derlen2 = sizeof(derbuf2);
|
||||
|
||||
if(!ber_write_mpi(&derp1, &derlen1, &bits)
|
||||
|| ber_write_mpi(&derp1, &derlen1, &rsa->n) // modulus
|
||||
|| ber_write_mpi(&derp1, &derlen1, &rsa->e) // public exponent
|
||||
|| ber_write_mpi(&derp1, &derlen1, &rsa->d) // private exponent
|
||||
|| ber_write_mpi(&derp1, &derlen1, &p)
|
||||
|| ber_write_mpi(&derp1, &derlen1, &q)
|
||||
|| ber_write_mpi(&derp1, &derlen1, &exp1)
|
||||
|| ber_write_mpi(&derp1, &derlen1, &exp2)
|
||||
|| ber_write_mpi(&derp1, &derlen1, &coeff)) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while encoding RSA private key");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!pem_encode(fp, "RSA PRIVATE KEY", derbuf2, derlen2)) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to write RSA private key: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool rsa_write_pem_public_key(rsa_t *rsa, FILE *fp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool rsa_write_pem_private_key(rsa_t *rsa, FILE *fp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool rsa_generate(rsa_t *rsa, size_t bits, unsigned long exponent) {
|
||||
fprintf(stderr, "Generating RSA keys with libgcrypt not implemented yet\n");
|
||||
return false;
|
||||
}
|
||||
40
src/getopt.c
40
src/getopt.c
|
|
@ -132,7 +132,7 @@ int optind = 1;
|
|||
causes problems with re-calling getopt as programs generally don't
|
||||
know that. */
|
||||
|
||||
int __getopt_initialized = 0;
|
||||
int getopt_initialized = 0;
|
||||
|
||||
/* The next char to be scanned in the option-element
|
||||
in which the last option character we returned was found.
|
||||
|
|
@ -248,7 +248,7 @@ static int last_nonopt;
|
|||
indicating ARGV elements that should not be considered arguments. */
|
||||
|
||||
/* Defined in getopt_init.c */
|
||||
extern char *__getopt_nonoption_flags;
|
||||
extern char *getopt_nonoption_flags;
|
||||
|
||||
static int nonoption_flags_max_len;
|
||||
static int nonoption_flags_len;
|
||||
|
|
@ -256,7 +256,7 @@ static int nonoption_flags_len;
|
|||
static int original_argc;
|
||||
static char *const *original_argv;
|
||||
|
||||
extern pid_t __libc_pid;
|
||||
extern pid_t libc_pid;
|
||||
|
||||
/* Make sure the environment variable bash 2.0 puts in the environment
|
||||
is valid for the getopt call we must make sure that the ARGV passed
|
||||
|
|
@ -269,14 +269,14 @@ store_args_and_env(int argc, char *const *argv) {
|
|||
original_argc = argc;
|
||||
original_argv = argv;
|
||||
}
|
||||
text_set_element(__libc_subinit, store_args_and_env);
|
||||
text_set_element(libc_subinit, store_args_and_env);
|
||||
|
||||
# define SWAP_FLAGS(ch1, ch2) \
|
||||
if (nonoption_flags_len > 0) \
|
||||
{ \
|
||||
char __tmp = __getopt_nonoption_flags[ch1]; \
|
||||
__getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \
|
||||
__getopt_nonoption_flags[ch2] = __tmp; \
|
||||
char tmp = getopt_nonoption_flags[ch1]; \
|
||||
getopt_nonoption_flags[ch1] = getopt_nonoption_flags[ch2]; \
|
||||
getopt_nonoption_flags[ch2] = tmp; \
|
||||
}
|
||||
#else /* !_LIBC */
|
||||
# define SWAP_FLAGS(ch1, ch2)
|
||||
|
|
@ -311,7 +311,7 @@ char **argv;
|
|||
|
||||
#ifdef _LIBC
|
||||
|
||||
/* First make sure the handling of the `__getopt_nonoption_flags'
|
||||
/* First make sure the handling of the `getopt_nonoption_flags'
|
||||
string can work normally. Our top argument must be in the range
|
||||
of the string. */
|
||||
if(nonoption_flags_len > 0 && top >= nonoption_flags_max_len) {
|
||||
|
|
@ -322,11 +322,11 @@ char **argv;
|
|||
if(new_str == NULL) {
|
||||
nonoption_flags_len = nonoption_flags_max_len = 0;
|
||||
} else {
|
||||
memcpy(new_str, __getopt_nonoption_flags, nonoption_flags_max_len);
|
||||
memcpy(new_str, getopt_nonoption_flags, nonoption_flags_max_len);
|
||||
memset(&new_str[nonoption_flags_max_len], '\0',
|
||||
top + 1 - nonoption_flags_max_len);
|
||||
nonoption_flags_max_len = top + 1;
|
||||
__getopt_nonoption_flags = new_str;
|
||||
getopt_nonoption_flags = new_str;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -412,25 +412,25 @@ const char *optstring;
|
|||
if(posixly_correct == NULL
|
||||
&& argc == original_argc && argv == original_argv) {
|
||||
if(nonoption_flags_max_len == 0) {
|
||||
if(__getopt_nonoption_flags == NULL
|
||||
|| __getopt_nonoption_flags[0] == '\0') {
|
||||
if(getopt_nonoption_flags == NULL
|
||||
|| getopt_nonoption_flags[0] == '\0') {
|
||||
nonoption_flags_max_len = -1;
|
||||
} else {
|
||||
const char *orig_str = __getopt_nonoption_flags;
|
||||
const char *orig_str = getopt_nonoption_flags;
|
||||
int len = nonoption_flags_max_len = strlen(orig_str);
|
||||
|
||||
if(nonoption_flags_max_len < argc) {
|
||||
nonoption_flags_max_len = argc;
|
||||
}
|
||||
|
||||
__getopt_nonoption_flags =
|
||||
getopt_nonoption_flags =
|
||||
(char *) malloc(nonoption_flags_max_len);
|
||||
|
||||
if(__getopt_nonoption_flags == NULL) {
|
||||
if(getopt_nonoption_flags == NULL) {
|
||||
nonoption_flags_max_len = -1;
|
||||
} else {
|
||||
memcpy(__getopt_nonoption_flags, orig_str, len);
|
||||
memset(&__getopt_nonoption_flags[len], '\0',
|
||||
memcpy(getopt_nonoption_flags, orig_str, len);
|
||||
memset(&getopt_nonoption_flags[len], '\0',
|
||||
nonoption_flags_max_len - len);
|
||||
}
|
||||
}
|
||||
|
|
@ -513,13 +513,13 @@ int long_only;
|
|||
{
|
||||
optarg = NULL;
|
||||
|
||||
if(optind == 0 || !__getopt_initialized) {
|
||||
if(optind == 0 || !getopt_initialized) {
|
||||
if(optind == 0) {
|
||||
optind = 1; /* Don't scan ARGV[0], the program name. */
|
||||
}
|
||||
|
||||
optstring = _getopt_initialize(argc, argv, optstring);
|
||||
__getopt_initialized = 1;
|
||||
getopt_initialized = 1;
|
||||
}
|
||||
|
||||
/* Test whether ARGV[optind] points to a non-option argument.
|
||||
|
|
@ -529,7 +529,7 @@ int long_only;
|
|||
#ifdef _LIBC
|
||||
#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \
|
||||
|| (optind < nonoption_flags_len \
|
||||
&& __getopt_nonoption_flags[optind] == '1'))
|
||||
&& getopt_nonoption_flags[optind] == '1'))
|
||||
#else
|
||||
#define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0')
|
||||
#endif
|
||||
|
|
|
|||
139
src/getopt.h
139
src/getopt.h
|
|
@ -22,79 +22,76 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef _GETOPT_H
|
||||
#define _GETOPT_H 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
#ifdef cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* For communication from `getopt' to the caller.
|
||||
When `getopt' finds an option that takes an argument,
|
||||
the argument value is returned here.
|
||||
Also, when `ordering' is RETURN_IN_ORDER,
|
||||
each non-option ARGV-element is returned here. */
|
||||
/* For communication from `getopt' to the caller.
|
||||
When `getopt' finds an option that takes an argument,
|
||||
the argument value is returned here.
|
||||
Also, when `ordering' is RETURN_IN_ORDER,
|
||||
each non-option ARGV-element is returned here. */
|
||||
|
||||
extern char *optarg;
|
||||
extern char *optarg;
|
||||
|
||||
/* Index in ARGV of the next element to be scanned.
|
||||
This is used for communication to and from the caller
|
||||
and for communication between successive calls to `getopt'.
|
||||
/* Index in ARGV of the next element to be scanned.
|
||||
This is used for communication to and from the caller
|
||||
and for communication between successive calls to `getopt'.
|
||||
|
||||
On entry to `getopt', zero means this is the first call; initialize.
|
||||
On entry to `getopt', zero means this is the first call; initialize.
|
||||
|
||||
When `getopt' returns -1, this is the index of the first of the
|
||||
non-option elements that the caller should itself scan.
|
||||
When `getopt' returns -1, this is the index of the first of the
|
||||
non-option elements that the caller should itself scan.
|
||||
|
||||
Otherwise, `optind' communicates from one call to the next
|
||||
how much of ARGV has been scanned so far. */
|
||||
Otherwise, `optind' communicates from one call to the next
|
||||
how much of ARGV has been scanned so far. */
|
||||
|
||||
extern int optind;
|
||||
extern int optind;
|
||||
|
||||
/* Callers store zero here to inhibit the error message `getopt' prints
|
||||
for unrecognized options. */
|
||||
/* Callers store zero here to inhibit the error message `getopt' prints
|
||||
for unrecognized options. */
|
||||
|
||||
extern int opterr;
|
||||
extern int opterr;
|
||||
|
||||
/* Set to an option character which was unrecognized. */
|
||||
/* Set to an option character which was unrecognized. */
|
||||
|
||||
extern int optopt;
|
||||
extern int optopt;
|
||||
|
||||
/* Describe the long-named options requested by the application.
|
||||
The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
|
||||
of `struct option' terminated by an element containing a name which is
|
||||
zero.
|
||||
/* Describe the long-named options requested by the application.
|
||||
The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
|
||||
of `struct option' terminated by an element containing a name which is
|
||||
zero.
|
||||
|
||||
The field `has_arg' is:
|
||||
no_argument (or 0) if the option does not take an argument,
|
||||
required_argument (or 1) if the option requires an argument,
|
||||
optional_argument (or 2) if the option takes an optional argument.
|
||||
The field `has_arg' is:
|
||||
no_argument (or 0) if the option does not take an argument,
|
||||
required_argument (or 1) if the option requires an argument,
|
||||
optional_argument (or 2) if the option takes an optional argument.
|
||||
|
||||
If the field `flag' is not NULL, it points to a variable that is set
|
||||
to the value given in the field `val' when the option is found, but
|
||||
left unchanged if the option is not found.
|
||||
If the field `flag' is not NULL, it points to a variable that is set
|
||||
to the value given in the field `val' when the option is found, but
|
||||
left unchanged if the option is not found.
|
||||
|
||||
To have a long-named option do something other than set an `int' to
|
||||
a compiled-in constant, such as set a value from `optarg', set the
|
||||
option's `flag' field to zero and its `val' field to a nonzero
|
||||
value (the equivalent single-letter option character, if there is
|
||||
one). For long options that have a zero `flag' field, `getopt'
|
||||
returns the contents of the `val' field. */
|
||||
To have a long-named option do something other than set an `int' to
|
||||
a compiled-in constant, such as set a value from `optarg', set the
|
||||
option's `flag' field to zero and its `val' field to a nonzero
|
||||
value (the equivalent single-letter option character, if there is
|
||||
one). For long options that have a zero `flag' field, `getopt'
|
||||
returns the contents of the `val' field. */
|
||||
|
||||
struct option {
|
||||
struct option {
|
||||
#if defined (__STDC__) && __STDC__
|
||||
const char *name;
|
||||
const char *name;
|
||||
#else
|
||||
char *name;
|
||||
char *name;
|
||||
#endif
|
||||
/* has_arg can't be an enum because some compilers complain about
|
||||
type mismatches in all the code that assumes it is an int. */
|
||||
int has_arg;
|
||||
int *flag;
|
||||
int val;
|
||||
};
|
||||
/* has_arg can't be an enum because some compilers complain about
|
||||
type mismatches in all the code that assumes it is an int. */
|
||||
int has_arg;
|
||||
int *flag;
|
||||
int val;
|
||||
};
|
||||
|
||||
/* Names for the values of the `has_arg' field of `struct option'. */
|
||||
/* Names for the values of the `has_arg' field of `struct option'. */
|
||||
|
||||
#define no_argument 0
|
||||
#define required_argument 1
|
||||
|
|
@ -102,33 +99,33 @@ struct option {
|
|||
|
||||
#if defined (__STDC__) && __STDC__
|
||||
#ifdef __GNU_LIBRARY__
|
||||
/* Many other libraries have conflicting prototypes for getopt, with
|
||||
differences in the consts, in stdlib.h. To avoid compilation
|
||||
errors, only prototype getopt for the GNU C library. */
|
||||
extern int getopt(int argc, char *const *argv, const char *shortopts);
|
||||
/* Many other libraries have conflicting prototypes for getopt, with
|
||||
differences in the consts, in stdlib.h. To avoid compilation
|
||||
errors, only prototype getopt for the GNU C library. */
|
||||
extern int getopt(int argc, char *const *argv, const char *shortopts);
|
||||
#else /* not __GNU_LIBRARY__ */
|
||||
extern int getopt();
|
||||
extern int getopt();
|
||||
#endif /* __GNU_LIBRARY__ */
|
||||
extern int getopt_long(int argc, char *const *argv, const char *shortopts,
|
||||
const struct option *longopts, int *longind);
|
||||
extern int getopt_long_only(int argc, char *const *argv,
|
||||
const char *shortopts,
|
||||
const struct option *longopts, int *longind);
|
||||
extern int getopt_long(int argc, char *const *argv, const char *shortopts,
|
||||
const struct option *longopts, int *longind);
|
||||
extern int getopt_long_only(int argc, char *const *argv,
|
||||
const char *shortopts,
|
||||
const struct option *longopts, int *longind);
|
||||
|
||||
/* Internal only. Users should not call this directly. */
|
||||
extern int _getopt_internal(int argc, char *const *argv,
|
||||
const char *shortopts,
|
||||
const struct option *longopts, int *longind,
|
||||
int long_only);
|
||||
/* Internal only. Users should not call this directly. */
|
||||
extern int _getopt_internal(int argc, char *const *argv,
|
||||
const char *shortopts,
|
||||
const struct option *longopts, int *longind,
|
||||
int long_only);
|
||||
#else /* not __STDC__ */
|
||||
extern int getopt();
|
||||
extern int getopt_long();
|
||||
extern int getopt_long_only();
|
||||
extern int getopt();
|
||||
extern int getopt_long();
|
||||
extern int getopt_long_only();
|
||||
|
||||
extern int _getopt_internal();
|
||||
extern int _getopt_internal();
|
||||
#endif /* __STDC__ */
|
||||
|
||||
#ifdef __cplusplus
|
||||
#ifdef cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
|||
262
src/graph.c
262
src/graph.c
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
graph.c -- graph algorithms
|
||||
Copyright (C) 2001-2017 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
Copyright (C) 2001-2014 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
2001-2005 Ivo Timmermans
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
|
|
@ -44,21 +44,22 @@
|
|||
|
||||
#include "system.h"
|
||||
|
||||
#include "avl_tree.h"
|
||||
#include "conf.h"
|
||||
#include "connection.h"
|
||||
#include "device.h"
|
||||
#include "edge.h"
|
||||
#include "graph.h"
|
||||
#include "list.h"
|
||||
#include "logger.h"
|
||||
#include "names.h"
|
||||
#include "netutl.h"
|
||||
#include "node.h"
|
||||
#include "process.h"
|
||||
#include "protocol.h"
|
||||
#include "script.h"
|
||||
#include "subnet.h"
|
||||
#include "utils.h"
|
||||
#include "xalloc.h"
|
||||
#include "graph.h"
|
||||
|
||||
static bool graph_changed = true;
|
||||
|
||||
/* Implementation of Kruskal's algorithm.
|
||||
Running time: O(EN)
|
||||
|
|
@ -66,23 +67,42 @@
|
|||
*/
|
||||
|
||||
static void mst_kruskal(void) {
|
||||
avl_node_t *node, *next;
|
||||
edge_t *e;
|
||||
node_t *n;
|
||||
connection_t *c;
|
||||
int nodes = 0;
|
||||
int safe_edges = 0;
|
||||
bool skipped;
|
||||
|
||||
/* Clear MST status on connections */
|
||||
|
||||
for list_each(connection_t, c, connection_list) {
|
||||
for(node = connection_tree->head; node; node = node->next) {
|
||||
c = node->data;
|
||||
c->status.mst = false;
|
||||
}
|
||||
|
||||
logger(DEBUG_SCARY_THINGS, LOG_DEBUG, "Running Kruskal's algorithm:");
|
||||
/* Do we have something to do at all? */
|
||||
|
||||
if(!edge_weight_tree->head) {
|
||||
return;
|
||||
}
|
||||
|
||||
ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Running Kruskal's algorithm:");
|
||||
|
||||
/* Clear visited status on nodes */
|
||||
|
||||
for splay_each(node_t, n, node_tree) {
|
||||
for(node = node_tree->head; node; node = node->next) {
|
||||
n = node->data;
|
||||
n->status.visited = false;
|
||||
nodes++;
|
||||
}
|
||||
|
||||
/* Starting point */
|
||||
|
||||
for splay_each(edge_t, e, edge_weight_tree) {
|
||||
for(node = edge_weight_tree->head; node; node = node->next) {
|
||||
e = node->data;
|
||||
|
||||
if(e->from->status.reachable) {
|
||||
e->from->status.visited = true;
|
||||
break;
|
||||
|
|
@ -91,10 +111,11 @@ static void mst_kruskal(void) {
|
|||
|
||||
/* Add safe edges */
|
||||
|
||||
bool skipped = false;
|
||||
for(skipped = false, node = edge_weight_tree->head; node; node = next) {
|
||||
next = node->next;
|
||||
e = node->data;
|
||||
|
||||
for splay_each(edge_t, e, edge_weight_tree) {
|
||||
if(!e->reverse || (e->from->status.visited == e->to->status.visited)) {
|
||||
if(!e->reverse || e->from->status.visited == e->to->status.visited) {
|
||||
skipped = true;
|
||||
continue;
|
||||
}
|
||||
|
|
@ -110,13 +131,20 @@ static void mst_kruskal(void) {
|
|||
e->reverse->connection->status.mst = true;
|
||||
}
|
||||
|
||||
logger(DEBUG_SCARY_THINGS, LOG_DEBUG, " Adding edge %s - %s weight %d", e->from->name, e->to->name, e->weight);
|
||||
safe_edges++;
|
||||
|
||||
ifdebug(SCARY_THINGS) logger(LOG_DEBUG, " Adding edge %s - %s weight %d", e->from->name,
|
||||
e->to->name, e->weight);
|
||||
|
||||
if(skipped) {
|
||||
skipped = false;
|
||||
next = edge_weight_tree->head;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Done, counted %d nodes and %d safe edges.", nodes,
|
||||
safe_edges);
|
||||
}
|
||||
|
||||
/* Implementation of a simple breadth-first search algorithm.
|
||||
|
|
@ -124,14 +152,25 @@ static void mst_kruskal(void) {
|
|||
*/
|
||||
|
||||
static void sssp_bfs(void) {
|
||||
list_t *todo_list = list_alloc(NULL);
|
||||
avl_node_t *node, *next, *to;
|
||||
edge_t *e;
|
||||
node_t *n;
|
||||
list_t *todo_list;
|
||||
list_node_t *from, *todonext;
|
||||
bool indirect;
|
||||
char *name;
|
||||
char *address, *port;
|
||||
char *envp[8] = {NULL};
|
||||
int i;
|
||||
|
||||
todo_list = list_alloc(NULL);
|
||||
|
||||
/* Clear visited status on nodes */
|
||||
|
||||
for splay_each(node_t, n, node_tree) {
|
||||
for(node = node_tree->head; node; node = node->next) {
|
||||
n = node->data;
|
||||
n->status.visited = false;
|
||||
n->status.indirect = true;
|
||||
n->distance = -1;
|
||||
}
|
||||
|
||||
/* Begin with myself */
|
||||
|
|
@ -141,20 +180,17 @@ static void sssp_bfs(void) {
|
|||
myself->nexthop = myself;
|
||||
myself->prevedge = NULL;
|
||||
myself->via = myself;
|
||||
myself->distance = 0;
|
||||
list_insert_head(todo_list, myself);
|
||||
|
||||
/* Loop while todo_list is filled */
|
||||
|
||||
for list_each(node_t, n, todo_list) { /* "n" is the node from which we start */
|
||||
logger(DEBUG_SCARY_THINGS, LOG_DEBUG, " Examining edges from %s", n->name);
|
||||
for(from = todo_list->head; from; from = todonext) { /* "from" is the node from which we start */
|
||||
n = from->data;
|
||||
|
||||
if(n->distance < 0) {
|
||||
abort();
|
||||
}
|
||||
for(to = n->edge_tree->head; to; to = to->next) { /* "to" is the edge connected to "from" */
|
||||
e = to->data;
|
||||
|
||||
for splay_each(edge_t, e, n->edge_tree) { /* "e" is the edge connected to "from" */
|
||||
if(!e->reverse || e->to == myself) {
|
||||
if(!e->reverse) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -175,17 +211,16 @@ static void sssp_bfs(void) {
|
|||
of nodes behind it.
|
||||
*/
|
||||
|
||||
bool indirect = n->status.indirect || e->options & OPTION_INDIRECT;
|
||||
indirect = n->status.indirect || e->options & OPTION_INDIRECT;
|
||||
|
||||
if(e->to->status.visited
|
||||
&& (!e->to->status.indirect || indirect)
|
||||
&& (e->to->distance != n->distance + 1 || e->weight >= e->to->prevedge->weight)) {
|
||||
&& (!e->to->status.indirect || indirect)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Only update nexthop if it doesn't increase the path length
|
||||
// Only update nexthop the first time we visit this node.
|
||||
|
||||
if(!e->to->status.visited || (e->to->distance == n->distance + 1 && e->weight >= e->to->prevedge->weight)) {
|
||||
if(!e->to->status.visited) {
|
||||
e->to->nexthop = (n->nexthop == myself) ? e->to : n->nexthop;
|
||||
}
|
||||
|
||||
|
|
@ -194,93 +229,74 @@ static void sssp_bfs(void) {
|
|||
e->to->prevedge = e;
|
||||
e->to->via = indirect ? n->via : e->to;
|
||||
e->to->options = e->options;
|
||||
e->to->distance = n->distance + 1;
|
||||
|
||||
if(!e->to->status.reachable || (e->to->address.sa.sa_family == AF_UNSPEC && e->address.sa.sa_family != AF_UNKNOWN)) {
|
||||
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);
|
||||
}
|
||||
|
||||
next = node->next; /* Because the list_insert_tail() above could have added something extra for us! */
|
||||
list_delete_node(todo_list, node);
|
||||
todonext = from->next;
|
||||
list_delete_node(todo_list, from);
|
||||
}
|
||||
|
||||
list_free(todo_list);
|
||||
}
|
||||
|
||||
static void check_reachability(void) {
|
||||
/* Check reachability status. */
|
||||
|
||||
int reachable_count = 0;
|
||||
int became_reachable_count = 0;
|
||||
int became_unreachable_count = 0;
|
||||
for(node = node_tree->head; node; node = next) {
|
||||
next = node->next;
|
||||
n = node->data;
|
||||
|
||||
for splay_each(node_t, n, node_tree) {
|
||||
if(n->status.visited != n->status.reachable) {
|
||||
n->status.reachable = !n->status.reachable;
|
||||
n->last_state_change = now.tv_sec;
|
||||
|
||||
if(n->status.reachable) {
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Node %s (%s) became reachable",
|
||||
n->name, n->hostname);
|
||||
|
||||
if(n != myself) {
|
||||
became_reachable_count++;
|
||||
}
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Node %s (%s) became reachable",
|
||||
n->name, n->hostname);
|
||||
} else {
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Node %s (%s) became unreachable",
|
||||
n->name, n->hostname);
|
||||
|
||||
if(n != myself) {
|
||||
became_unreachable_count++;
|
||||
}
|
||||
}
|
||||
|
||||
if(experimental && OPTION_VERSION(n->options) >= 2) {
|
||||
n->status.sptps = true;
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Node %s (%s) became unreachable",
|
||||
n->name, n->hostname);
|
||||
}
|
||||
|
||||
/* TODO: only clear status.validkey if node is unreachable? */
|
||||
|
||||
n->status.validkey = false;
|
||||
|
||||
if(n->status.sptps) {
|
||||
sptps_stop(&n->sptps);
|
||||
n->status.waitingforkey = false;
|
||||
}
|
||||
|
||||
n->last_req_key = 0;
|
||||
|
||||
n->status.udp_confirmed = false;
|
||||
n->maxmtu = MTU;
|
||||
n->maxrecentlen = 0;
|
||||
n->minmtu = 0;
|
||||
n->mtuprobes = 0;
|
||||
|
||||
timeout_del(&n->udp_ping_timeout);
|
||||
if(n->mtuevent) {
|
||||
event_del(n->mtuevent);
|
||||
n->mtuevent = NULL;
|
||||
}
|
||||
|
||||
char *name;
|
||||
char *address;
|
||||
char *port;
|
||||
|
||||
environment_t env;
|
||||
environment_init(&env);
|
||||
environment_add(&env, "NODE=%s", n->name);
|
||||
xasprintf(&envp[0], "NETNAME=%s", netname ? netname : "");
|
||||
xasprintf(&envp[1], "DEVICE=%s", device ? device : "");
|
||||
xasprintf(&envp[2], "INTERFACE=%s", iface ? iface : "");
|
||||
xasprintf(&envp[3], "NODE=%s", n->name);
|
||||
sockaddr2str(&n->address, &address, &port);
|
||||
environment_add(&env, "REMOTEADDRESS=%s", address);
|
||||
environment_add(&env, "REMOTEPORT=%s", port);
|
||||
xasprintf(&envp[4], "REMOTEADDRESS=%s", address);
|
||||
xasprintf(&envp[5], "REMOTEPORT=%s", port);
|
||||
xasprintf(&envp[6], "NAME=%s", myself->name);
|
||||
|
||||
execute_script(n->status.reachable ? "host-up" : "host-down", &env);
|
||||
execute_script(n->status.reachable ? "host-up" : "host-down", envp);
|
||||
|
||||
xasprintf(&name, n->status.reachable ? "hosts/%s-up" : "hosts/%s-down", n->name);
|
||||
execute_script(name, &env);
|
||||
xasprintf(&name,
|
||||
n->status.reachable ? "hosts/%s-up" : "hosts/%s-down",
|
||||
n->name);
|
||||
execute_script(name, envp);
|
||||
|
||||
free(name);
|
||||
free(address);
|
||||
free(port);
|
||||
environment_exit(&env);
|
||||
|
||||
for(i = 0; i < 7; i++) {
|
||||
free(envp[i]);
|
||||
}
|
||||
|
||||
subnet_update(n, NULL, n->status.reachable);
|
||||
|
||||
|
|
@ -289,30 +305,86 @@ static void check_reachability(void) {
|
|||
memset(&n->status, 0, sizeof(n->status));
|
||||
n->options = 0;
|
||||
} else if(n->connection) {
|
||||
// Speed up UDP probing by sending our key.
|
||||
if(!n->status.sptps) {
|
||||
send_ans_key(n);
|
||||
}
|
||||
send_ans_key(n);
|
||||
}
|
||||
}
|
||||
|
||||
if(n->status.reachable && n != myself) {
|
||||
reachable_count++;
|
||||
}
|
||||
}
|
||||
|
||||
if(device_standby) {
|
||||
if(reachable_count == 0 && became_unreachable_count > 0) {
|
||||
device_disable();
|
||||
} else if(reachable_count > 0 && reachable_count == became_reachable_count) {
|
||||
device_enable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void graph(void) {
|
||||
subnet_cache_flush();
|
||||
sssp_bfs();
|
||||
check_reachability();
|
||||
mst_kruskal();
|
||||
graph_changed = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Dump nodes and edges to a graphviz file.
|
||||
|
||||
The file can be converted to an image with
|
||||
dot -Tpng graph_filename -o image_filename.png -Gconcentrate=true
|
||||
*/
|
||||
|
||||
void dump_graph(void) {
|
||||
avl_node_t *node;
|
||||
node_t *n;
|
||||
edge_t *e;
|
||||
char *filename = NULL, *tmpname = NULL;
|
||||
FILE *file, *pipe = NULL;
|
||||
|
||||
if(!graph_changed || !get_config_string(lookup_config(config_tree, "GraphDumpFile"), &filename)) {
|
||||
return;
|
||||
}
|
||||
|
||||
graph_changed = false;
|
||||
|
||||
ifdebug(PROTOCOL) logger(LOG_NOTICE, "Dumping graph");
|
||||
|
||||
if(filename[0] == '|') {
|
||||
file = pipe = popen(filename + 1, "w");
|
||||
} else {
|
||||
xasprintf(&tmpname, "%s.new", filename);
|
||||
file = fopen(tmpname, "w");
|
||||
}
|
||||
|
||||
if(!file) {
|
||||
logger(LOG_ERR, "Unable to open graph dump file %s: %s", filename, strerror(errno));
|
||||
free(filename);
|
||||
free(tmpname);
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(file, "digraph {\n");
|
||||
|
||||
/* dump all nodes first */
|
||||
for(node = node_tree->head; node; node = node->next) {
|
||||
n = node->data;
|
||||
fprintf(file, " \"%s\" [label = \"%s\"];\n", n->name, n->name);
|
||||
}
|
||||
|
||||
/* now dump all edges */
|
||||
for(node = edge_weight_tree->head; node; node = node->next) {
|
||||
e = node->data;
|
||||
fprintf(file, " \"%s\" -> \"%s\";\n", e->from->name, e->to->name);
|
||||
}
|
||||
|
||||
fprintf(file, "}\n");
|
||||
|
||||
if(pipe) {
|
||||
pclose(pipe);
|
||||
} else {
|
||||
fclose(file);
|
||||
#ifdef HAVE_MINGW
|
||||
unlink(filename);
|
||||
#endif
|
||||
|
||||
if(rename(tmpname, filename)) {
|
||||
logger(LOG_ERR, "Could not rename %s to %s: %s\n", tmpname, filename, strerror(errno));
|
||||
}
|
||||
|
||||
free(tmpname);
|
||||
}
|
||||
|
||||
free(filename);
|
||||
}
|
||||
|
|
|
|||
128
src/hash.c
128
src/hash.c
|
|
@ -1,128 +0,0 @@
|
|||
/*
|
||||
hash.c -- hash table management
|
||||
Copyright (C) 2012-2013 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "hash.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
/* Generic hash function */
|
||||
|
||||
static uint32_t hash_function(const void *p, size_t len) {
|
||||
const uint8_t *q = p;
|
||||
uint32_t hash = 0;
|
||||
|
||||
while(true) {
|
||||
for(int i = len > 4 ? 4 : len; --i;) {
|
||||
hash += (uint32_t)q[len - i] << (8 * i);
|
||||
}
|
||||
|
||||
hash *= 0x9e370001UL; // Golden ratio prime.
|
||||
|
||||
if(len <= 4) {
|
||||
break;
|
||||
}
|
||||
|
||||
len -= 4;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
/* Map 32 bits int onto 0..n-1, without throwing away too many bits if n is 2^8 or 2^16 */
|
||||
|
||||
static uint32_t modulo(uint32_t hash, size_t n) {
|
||||
if(n == 0x100) {
|
||||
return (hash >> 24) ^ ((hash >> 16) & 0xff) ^ ((hash >> 8) & 0xff) ^ (hash & 0xff);
|
||||
} else if(n == 0x10000) {
|
||||
return (hash >> 16) ^ (hash & 0xffff);
|
||||
} else {
|
||||
return hash % n;
|
||||
}
|
||||
}
|
||||
|
||||
/* (De)allocation */
|
||||
|
||||
hash_t *hash_alloc(size_t n, size_t size) {
|
||||
hash_t *hash = xzalloc(sizeof(*hash));
|
||||
hash->n = n;
|
||||
hash->size = size;
|
||||
hash->keys = xzalloc(hash->n * hash->size);
|
||||
hash->values = xzalloc(hash->n * sizeof(*hash->values));
|
||||
return hash;
|
||||
}
|
||||
|
||||
void hash_free(hash_t *hash) {
|
||||
free(hash->keys);
|
||||
free(hash->values);
|
||||
free(hash);
|
||||
}
|
||||
|
||||
/* Searching and inserting */
|
||||
|
||||
void hash_insert(hash_t *hash, const void *key, const void *value) {
|
||||
uint32_t i = modulo(hash_function(key, hash->size), hash->n);
|
||||
memcpy(hash->keys + i * hash->size, key, hash->size);
|
||||
hash->values[i] = value;
|
||||
}
|
||||
|
||||
void *hash_search(const hash_t *hash, const void *key) {
|
||||
uint32_t i = modulo(hash_function(key, hash->size), hash->n);
|
||||
|
||||
if(hash->values[i] && !memcmp(key, hash->keys + i * hash->size, hash->size)) {
|
||||
return (void *)hash->values[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *hash_search_or_insert(hash_t *hash, const void *key, const void *value) {
|
||||
uint32_t i = modulo(hash_function(key, hash->size), hash->n);
|
||||
|
||||
if(hash->values[i] && !memcmp(key, hash->keys + i * hash->size, hash->size)) {
|
||||
return (void *)hash->values[i];
|
||||
}
|
||||
|
||||
memcpy(hash->keys + i * hash->size, key, hash->size);
|
||||
hash->values[i] = value;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Deleting */
|
||||
|
||||
void hash_delete(hash_t *hash, const void *key) {
|
||||
uint32_t i = modulo(hash_function(key, hash->size), hash->n);
|
||||
hash->values[i] = NULL;
|
||||
}
|
||||
|
||||
/* Utility functions */
|
||||
|
||||
void hash_clear(hash_t *hash) {
|
||||
memset(hash->values, 0, hash->n * sizeof(*hash->values));
|
||||
}
|
||||
|
||||
void hash_resize(hash_t *hash, size_t n) {
|
||||
hash->keys = xrealloc(hash->keys, n * hash->size);
|
||||
hash->values = xrealloc(hash->values, n * sizeof(*hash->values));
|
||||
|
||||
if(n > hash->n) {
|
||||
memset(hash->keys + hash->n * hash->size, 0, (n - hash->n) * hash->size);
|
||||
memset(hash->values + hash->n, 0, (n - hash->n) * sizeof(*hash->values));
|
||||
}
|
||||
}
|
||||
42
src/hash.h
42
src/hash.h
|
|
@ -1,42 +0,0 @@
|
|||
#ifndef TINC_HASH_H
|
||||
#define TINC_HASH_H
|
||||
|
||||
/*
|
||||
hash.h -- header file for hash.c
|
||||
Copyright (C) 2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
typedef struct hash_t {
|
||||
size_t n;
|
||||
size_t size;
|
||||
char *keys;
|
||||
const void **values;
|
||||
} hash_t;
|
||||
|
||||
extern hash_t *hash_alloc(size_t n, size_t size) __attribute__((__malloc__));
|
||||
extern void hash_free(hash_t *);
|
||||
|
||||
extern void hash_insert(hash_t *, const void *key, const void *value);
|
||||
extern void hash_delete(hash_t *, const void *key);
|
||||
|
||||
extern void *hash_search(const hash_t *, const void *key);
|
||||
extern void *hash_search_or_insert(hash_t *, const void *key, const void *value);
|
||||
|
||||
extern void hash_clear(hash_t *);
|
||||
extern void hash_resize(hash_t *, size_t n);
|
||||
|
||||
#endif
|
||||
52
src/have.h
52
src/have.h
|
|
@ -4,7 +4,7 @@
|
|||
/*
|
||||
have.h -- include headers which are known to exist
|
||||
Copyright (C) 1998-2005 Ivo Timmermans
|
||||
2003-2016 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2003-2015 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
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
|
||||
|
|
@ -22,23 +22,27 @@
|
|||
*/
|
||||
|
||||
#ifdef HAVE_MINGW
|
||||
#ifdef WITH_WINDOWS2000
|
||||
#define WINVER Windows2000
|
||||
#else
|
||||
#define WINVER WindowsXP
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
#include <signal.h>
|
||||
|
||||
#ifdef HAVE_MINGW
|
||||
#include <w32api.h>
|
||||
|
|
@ -47,12 +51,16 @@
|
|||
#include <ws2tcpip.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDBOOL_H
|
||||
#include <stdbool.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TERMIOS_H
|
||||
#include <termios.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_INTTYPES_H
|
||||
#include <inttypes.h>
|
||||
#ifdef HAVE_ALLOCA_H
|
||||
#include <alloca.h>
|
||||
#endif
|
||||
|
||||
/* Include system specific headers */
|
||||
|
|
@ -65,6 +73,9 @@
|
|||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TIME_H
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
|
|
@ -94,8 +105,8 @@
|
|||
#include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_UN_H
|
||||
#include <sys/un.h>
|
||||
#ifdef HAVE_SYS_UIO_H
|
||||
#include <sys/uio.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DIRENT_H
|
||||
|
|
@ -187,6 +198,9 @@
|
|||
|
||||
#ifdef HAVE_ARPA_NAMESER_H
|
||||
#include <arpa/nameser.h>
|
||||
#ifdef STATUS
|
||||
#undef STATUS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_RESOLV_H
|
||||
|
|
@ -197,20 +211,4 @@
|
|||
#include <linux/if_tun.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_GETOPT_H
|
||||
#include <getopt.h>
|
||||
#else
|
||||
#include "getopt.h"
|
||||
#endif
|
||||
|
||||
#ifdef STATUS
|
||||
#undef STATUS
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MINGW
|
||||
#define SLASH "\\"
|
||||
#else
|
||||
#define SLASH "/"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
|||
304
src/ifconfig.c
304
src/ifconfig.c
|
|
@ -1,304 +0,0 @@
|
|||
/*
|
||||
ifconfig.c -- Generate platform specific interface configuration commands
|
||||
Copyright (C) 2016-2017 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "conf.h"
|
||||
#include "ifconfig.h"
|
||||
#include "subnet.h"
|
||||
|
||||
static long start;
|
||||
|
||||
#ifndef HAVE_MINGW
|
||||
void ifconfig_header(FILE *out) {
|
||||
fprintf(out, "#!/bin/sh\n");
|
||||
start = ftell(out);
|
||||
}
|
||||
|
||||
void ifconfig_dhcp(FILE *out) {
|
||||
fprintf(out, "dhclient -nw \"$INTERFACE\"\n");
|
||||
}
|
||||
|
||||
void ifconfig_dhcp6(FILE *out) {
|
||||
fprintf(out, "dhclient -6 -nw \"$INTERFACE\"\n");
|
||||
}
|
||||
|
||||
void ifconfig_slaac(FILE *out) {
|
||||
#ifdef HAVE_LINUX
|
||||
fprintf(out, "echo 1 >\"/proc/sys/net/ipv6/conf/$INTERFACE/accept_ra\"\n");
|
||||
fprintf(out, "echo 1 >\"/proc/sys/net/ipv6/conf/$INTERFACE/autoconf\"\n");
|
||||
#else
|
||||
fprintf(out, "rtsol \"$INTERFACE\" &\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
bool ifconfig_footer(FILE *out) {
|
||||
if(ftell(out) == start) {
|
||||
fprintf(out, "echo 'Unconfigured tinc-up script, please edit '$0'!'\n\n#ifconfig $INTERFACE <your vpn IP address> netmask <netmask of whole VPN>\n");
|
||||
return false;
|
||||
} else {
|
||||
#ifdef HAVE_LINUX
|
||||
fprintf(out, "ip link set \"$INTERFACE\" up\n");
|
||||
#else
|
||||
fprintf(out, "ifconfig \"$INTERFACE\" up\n");
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#else
|
||||
void ifconfig_header(FILE *out) {
|
||||
start = ftell(out);
|
||||
}
|
||||
|
||||
void ifconfig_dhcp(FILE *out) {
|
||||
fprintf(out, "netsh interface ipv4 set address \"%%INTERFACE%%\" dhcp\n");
|
||||
}
|
||||
|
||||
void ifconfig_dhcp6(FILE *out) {
|
||||
fprintf(stderr, "DHCPv6 requested, but not supported by tinc on this platform\n");
|
||||
}
|
||||
|
||||
void ifconfig_slaac(FILE *out) {
|
||||
// It's the default?
|
||||
}
|
||||
|
||||
bool ifconfig_footer(FILE *out) {
|
||||
return ftell(out) != start;
|
||||
}
|
||||
#endif
|
||||
|
||||
static subnet_t ipv4, ipv6;
|
||||
|
||||
void ifconfig_address(FILE *out, const char *value) {
|
||||
subnet_t address = {0};
|
||||
char address_str[MAXNETSTR];
|
||||
|
||||
if(!str2net(&address, value) || !net2str(address_str, sizeof(address_str), &address)) {
|
||||
fprintf(stderr, "Could not parse address in Ifconfig statement\n");
|
||||
return;
|
||||
}
|
||||
|
||||
switch(address.type) {
|
||||
case SUBNET_IPV4:
|
||||
ipv4 = address;
|
||||
break;
|
||||
|
||||
case SUBNET_IPV6:
|
||||
ipv6 = address;
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(HAVE_LINUX)
|
||||
|
||||
switch(address.type) {
|
||||
case SUBNET_MAC:
|
||||
fprintf(out, "ip link set \"$INTERFACE\" address %s\n", address_str);
|
||||
break;
|
||||
|
||||
case SUBNET_IPV4:
|
||||
fprintf(out, "ip addr replace %s dev \"$INTERFACE\"\n", address_str);
|
||||
break;
|
||||
|
||||
case SUBNET_IPV6:
|
||||
fprintf(out, "ip addr replace %s dev \"$INTERFACE\"\n", address_str);
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
#elif defined(HAVE_MINGW) || defined(HAVE_CYGWIN)
|
||||
|
||||
switch(address.type) {
|
||||
case SUBNET_MAC:
|
||||
fprintf(out, "ip link set \"$INTERFACE\" address %s\n", address_str);
|
||||
break;
|
||||
|
||||
case SUBNET_IPV4:
|
||||
fprintf(out, "netsh inetface ipv4 set address \"$INTERFACE\" static %s\n", address_str);
|
||||
break;
|
||||
|
||||
case SUBNET_IPV6:
|
||||
fprintf(out, "netsh inetface ipv6 set address \"$INTERFACE\" static %s\n", address_str);
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
#else // assume BSD
|
||||
|
||||
switch(address.type) {
|
||||
case SUBNET_MAC:
|
||||
fprintf(out, "ifconfig \"$INTERFACE\" link %s\n", address_str);
|
||||
break;
|
||||
|
||||
case SUBNET_IPV4:
|
||||
fprintf(out, "ifconfig \"$INTERFACE\" %s\n", address_str);
|
||||
break;
|
||||
|
||||
case SUBNET_IPV6:
|
||||
fprintf(out, "ifconfig \"$INTERFACE\" inet6 %s\n", address_str);
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
void ifconfig_route(FILE *out, const char *value) {
|
||||
subnet_t subnet = {0}, gateway = {0};
|
||||
char subnet_str[MAXNETSTR] = "", gateway_str[MAXNETSTR] = "";
|
||||
char *sep = strchr(value, ' ');
|
||||
|
||||
if(sep) {
|
||||
*sep++ = 0;
|
||||
}
|
||||
|
||||
if(!str2net(&subnet, value) || !net2str(subnet_str, sizeof(subnet_str), &subnet) || subnet.type == SUBNET_MAC) {
|
||||
fprintf(stderr, "Could not parse subnet in Route statement\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if(sep) {
|
||||
if(!str2net(&gateway, sep) || !net2str(gateway_str, sizeof(gateway_str), &gateway) || gateway.type != subnet.type) {
|
||||
fprintf(stderr, "Could not parse gateway in Route statement\n");
|
||||
return;
|
||||
}
|
||||
|
||||
char *slash = strchr(gateway_str, '/');
|
||||
|
||||
if(slash) {
|
||||
*slash = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(HAVE_LINUX)
|
||||
|
||||
if(*gateway_str) {
|
||||
switch(subnet.type) {
|
||||
case SUBNET_IPV4:
|
||||
fprintf(out, "ip route add %s via %s dev \"$INTERFACE\"\n", subnet_str, gateway_str);
|
||||
break;
|
||||
|
||||
case SUBNET_IPV6:
|
||||
fprintf(out, "ip route add %s via %s dev \"$INTERFACE\"\n", subnet_str, gateway_str);
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
switch(subnet.type) {
|
||||
case SUBNET_IPV4:
|
||||
fprintf(out, "ip route add %s dev \"$INTERFACE\"\n", subnet_str);
|
||||
break;
|
||||
|
||||
case SUBNET_IPV6:
|
||||
fprintf(out, "ip route add %s dev \"$INTERFACE\"\n", subnet_str);
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(HAVE_MINGW) || defined(HAVE_CYGWIN)
|
||||
|
||||
if(*gateway_str) {
|
||||
switch(subnet.type) {
|
||||
case SUBNET_IPV4:
|
||||
fprintf(out, "netsh inetface ipv4 add route %s \"%%INTERFACE%%\" %s\n", subnet_str, gateway_str);
|
||||
break;
|
||||
|
||||
case SUBNET_IPV6:
|
||||
fprintf(out, "netsh inetface ipv6 add route %s \"%%INTERFACE%%\" %s\n", subnet_str, gateway_str);
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
switch(subnet.type) {
|
||||
case SUBNET_IPV4:
|
||||
fprintf(out, "netsh inetface ipv4 add route %s \"%%INTERFACE%%\"\n", subnet_str);
|
||||
break;
|
||||
|
||||
case SUBNET_IPV6:
|
||||
fprintf(out, "netsh inetface ipv6 add route %s \"%%INTERFACE%%\"\n", subnet_str);
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#else // assume BSD
|
||||
|
||||
if(!*gateway_str) {
|
||||
switch(subnet.type) {
|
||||
case SUBNET_IPV4:
|
||||
if(!ipv4.type) {
|
||||
fprintf(stderr, "Route requested but no Ifconfig\n");
|
||||
return;
|
||||
}
|
||||
|
||||
net2str(gateway_str, sizeof(gateway_str), &ipv4);
|
||||
break;
|
||||
|
||||
case SUBNET_IPV6:
|
||||
if(!ipv6.type) {
|
||||
fprintf(stderr, "Route requested but no Ifconfig\n");
|
||||
return;
|
||||
}
|
||||
|
||||
net2str(gateway_str, sizeof(gateway_str), &ipv6);
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
char *slash = strchr(gateway_str, '/');
|
||||
|
||||
if(slash) {
|
||||
*slash = 0;
|
||||
}
|
||||
}
|
||||
|
||||
switch(subnet.type) {
|
||||
case SUBNET_IPV4:
|
||||
fprintf(out, "route add %s %s\n", subnet_str, gateway_str);
|
||||
break;
|
||||
|
||||
case SUBNET_IPV6:
|
||||
fprintf(out, "route add -inet6 %s %s\n", subnet_str, gateway_str);
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
#ifndef TINC_IFCONFIG_H
|
||||
#define TINC_IFCONFIG_H
|
||||
|
||||
/*
|
||||
ifconfig.h -- header for ifconfig.c.
|
||||
Copyright (C) 2016 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
extern void ifconfig_dhcp(FILE *out);
|
||||
extern void ifconfig_dhcp6(FILE *out);
|
||||
extern void ifconfig_slaac(FILE *out);
|
||||
extern void ifconfig_address(FILE *out, const char *value);
|
||||
extern void ifconfig_route(FILE *out, const char *value);
|
||||
extern void ifconfig_header(FILE *out);
|
||||
extern bool ifconfig_footer(FILE *out);
|
||||
|
||||
#endif
|
||||
357
src/info.c
357
src/info.c
|
|
@ -1,357 +0,0 @@
|
|||
/*
|
||||
info.c -- Show information about a node, subnet or address
|
||||
Copyright (C) 2012-2017 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "control_common.h"
|
||||
#include "list.h"
|
||||
#include "subnet.h"
|
||||
#include "tincctl.h"
|
||||
#include "info.h"
|
||||
#include "utils.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
void logger(int level, int priority, const char *format, ...) {
|
||||
(void)level;
|
||||
(void)priority;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
vfprintf(stderr, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
fputc('\n', stderr);
|
||||
}
|
||||
|
||||
char *strip_weight(char *netstr) {
|
||||
int len = strlen(netstr);
|
||||
|
||||
if(len >= 3 && !strcmp(netstr + len - 3, "#10")) {
|
||||
netstr[len - 3] = 0;
|
||||
}
|
||||
|
||||
return netstr;
|
||||
}
|
||||
|
||||
static int info_node(int fd, const char *item) {
|
||||
// Check the list of nodes
|
||||
sendline(fd, "%d %d %s", CONTROL, REQ_DUMP_NODES, item);
|
||||
|
||||
bool found = false;
|
||||
char line[4096];
|
||||
|
||||
char node[4096];
|
||||
char id[4096];
|
||||
char from[4096];
|
||||
char to[4096];
|
||||
char subnet[4096];
|
||||
char host[4096];
|
||||
char port[4096];
|
||||
char via[4096];
|
||||
char nexthop[4096];
|
||||
int code, req, cipher, digest, maclength, compression, distance;
|
||||
short int pmtu, minmtu, maxmtu;
|
||||
unsigned int options;
|
||||
union {
|
||||
node_status_t bits;
|
||||
uint32_t raw;
|
||||
} status_union;
|
||||
node_status_t status;
|
||||
long int last_state_change;
|
||||
int udp_ping_rtt;
|
||||
uint64_t in_packets, in_bytes, out_packets, out_bytes;
|
||||
|
||||
while(recvline(fd, line, sizeof(line))) {
|
||||
int n = sscanf(line, "%d %d %4095s %4095s %4095s port %4095s %d %d %d %d %x %"PRIx32" %4095s %4095s %d %hd %hd %hd %ld %d %"PRIu64" %"PRIu64" %"PRIu64" %"PRIu64, &code, &req, node, id, host, port, &cipher, &digest, &maclength, &compression, &options, &status_union.raw, nexthop, via, &distance, &pmtu, &minmtu, &maxmtu, &last_state_change, &udp_ping_rtt, &in_packets, &in_bytes, &out_packets, &out_bytes);
|
||||
|
||||
if(n == 2) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(n != 24) {
|
||||
fprintf(stderr, "Unable to parse node dump from tincd.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(!strcmp(node, item)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!found) {
|
||||
fprintf(stderr, "Unknown node %s.\n", item);
|
||||
return 1;
|
||||
}
|
||||
|
||||
while(recvline(fd, line, sizeof(line))) {
|
||||
if(sscanf(line, "%d %d %4095s", &code, &req, node) == 2) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
printf("Node: %s\n", item);
|
||||
printf("Node ID: %s\n", id);
|
||||
printf("Address: %s port %s\n", host, port);
|
||||
|
||||
char timestr[32] = "never";
|
||||
time_t lsc_time = last_state_change;
|
||||
|
||||
if(last_state_change) {
|
||||
strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S", localtime(&lsc_time));
|
||||
}
|
||||
|
||||
status = status_union.bits;
|
||||
|
||||
if(status.reachable) {
|
||||
printf("Online since: %s\n", timestr);
|
||||
} else {
|
||||
printf("Last seen: %s\n", timestr);
|
||||
}
|
||||
|
||||
printf("Status: ");
|
||||
|
||||
if(status.validkey) {
|
||||
printf(" validkey");
|
||||
}
|
||||
|
||||
if(status.visited) {
|
||||
printf(" visited");
|
||||
}
|
||||
|
||||
if(status.reachable) {
|
||||
printf(" reachable");
|
||||
}
|
||||
|
||||
if(status.indirect) {
|
||||
printf(" indirect");
|
||||
}
|
||||
|
||||
if(status.sptps) {
|
||||
printf(" sptps");
|
||||
}
|
||||
|
||||
if(status.udp_confirmed) {
|
||||
printf(" udp_confirmed");
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
printf("Options: ");
|
||||
|
||||
if(options & OPTION_INDIRECT) {
|
||||
printf(" indirect");
|
||||
}
|
||||
|
||||
if(options & OPTION_TCPONLY) {
|
||||
printf(" tcponly");
|
||||
}
|
||||
|
||||
if(options & OPTION_PMTU_DISCOVERY) {
|
||||
printf(" pmtu_discovery");
|
||||
}
|
||||
|
||||
if(options & OPTION_CLAMP_MSS) {
|
||||
printf(" clamp_mss");
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
printf("Protocol: %d.%d\n", PROT_MAJOR, OPTION_VERSION(options));
|
||||
printf("Reachability: ");
|
||||
|
||||
if(!strcmp(host, "MYSELF")) {
|
||||
printf("can reach itself\n");
|
||||
} else if(!status.reachable) {
|
||||
printf("unreachable\n");
|
||||
} else if(strcmp(via, item)) {
|
||||
printf("indirectly via %s\n", via);
|
||||
} else if(!status.validkey) {
|
||||
printf("unknown\n");
|
||||
} else if(minmtu > 0) {
|
||||
printf("directly with UDP\nPMTU: %d\n", pmtu);
|
||||
|
||||
if(udp_ping_rtt != -1) {
|
||||
printf("RTT: %d.%03d\n", udp_ping_rtt / 1000, udp_ping_rtt % 1000);
|
||||
}
|
||||
} else if(!strcmp(nexthop, item)) {
|
||||
printf("directly with TCP\n");
|
||||
} else {
|
||||
printf("none, forwarded via %s\n", nexthop);
|
||||
}
|
||||
|
||||
printf("RX: %"PRIu64" packets %"PRIu64" bytes\n", in_packets, in_bytes);
|
||||
printf("TX: %"PRIu64" packets %"PRIu64" bytes\n", out_packets, out_bytes);
|
||||
|
||||
// List edges
|
||||
printf("Edges: ");
|
||||
sendline(fd, "%d %d %s", CONTROL, REQ_DUMP_EDGES, item);
|
||||
|
||||
while(recvline(fd, line, sizeof(line))) {
|
||||
int n = sscanf(line, "%d %d %4095s %4095s", &code, &req, from, to);
|
||||
|
||||
if(n == 2) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(n != 4) {
|
||||
fprintf(stderr, "Unable to parse edge dump from tincd.\n%s\n", line);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(!strcmp(from, item)) {
|
||||
printf(" %s", to);
|
||||
}
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
// List subnets
|
||||
printf("Subnets: ");
|
||||
sendline(fd, "%d %d %s", CONTROL, REQ_DUMP_SUBNETS, item);
|
||||
|
||||
while(recvline(fd, line, sizeof(line))) {
|
||||
int n = sscanf(line, "%d %d %4095s %4095s", &code, &req, subnet, from);
|
||||
|
||||
if(n == 2) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(n != 4) {
|
||||
fprintf(stderr, "Unable to parse subnet dump from tincd.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(!strcmp(from, item)) {
|
||||
printf(" %s", strip_weight(subnet));
|
||||
}
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int info_subnet(int fd, const char *item) {
|
||||
subnet_t subnet, find;
|
||||
|
||||
if(!str2net(&find, item)) {
|
||||
fprintf(stderr, "Could not parse subnet or address '%s'.\n", item);
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool address = !strchr(item, '/');
|
||||
bool weight = strchr(item, '#');
|
||||
bool found = false;
|
||||
|
||||
char line[4096];
|
||||
char netstr[4096];
|
||||
char owner[4096];
|
||||
|
||||
int code, req;
|
||||
|
||||
sendline(fd, "%d %d %s", CONTROL, REQ_DUMP_SUBNETS, item);
|
||||
|
||||
while(recvline(fd, line, sizeof(line))) {
|
||||
int n = sscanf(line, "%d %d %4095s %4095s", &code, &req, netstr, owner);
|
||||
|
||||
if(n == 2) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(n != 4 || !str2net(&subnet, netstr)) {
|
||||
fprintf(stderr, "Unable to parse subnet dump from tincd.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(find.type != subnet.type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(weight) {
|
||||
if(find.weight != subnet.weight) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if(find.type == SUBNET_IPV4) {
|
||||
if(address) {
|
||||
if(maskcmp(&find.net.ipv4.address, &subnet.net.ipv4.address, subnet.net.ipv4.prefixlength)) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if(find.net.ipv4.prefixlength != subnet.net.ipv4.prefixlength) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(memcmp(&find.net.ipv4.address, &subnet.net.ipv4.address, sizeof(subnet.net.ipv4))) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else if(find.type == SUBNET_IPV6) {
|
||||
if(address) {
|
||||
if(maskcmp(&find.net.ipv6.address, &subnet.net.ipv6.address, subnet.net.ipv6.prefixlength)) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if(find.net.ipv6.prefixlength != subnet.net.ipv6.prefixlength) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(memcmp(&find.net.ipv6.address, &subnet.net.ipv6.address, sizeof(subnet.net.ipv6))) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(find.type == SUBNET_MAC) {
|
||||
if(memcmp(&find.net.mac.address, &subnet.net.mac.address, sizeof(subnet.net.mac))) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
found = true;
|
||||
printf("Subnet: %s\n", strip_weight(netstr));
|
||||
printf("Owner: %s\n", owner);
|
||||
}
|
||||
|
||||
if(!found) {
|
||||
if(address) {
|
||||
fprintf(stderr, "Unknown address %s.\n", item);
|
||||
} else {
|
||||
fprintf(stderr, "Unknown subnet %s.\n", item);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int info(int fd, const char *item) {
|
||||
if(check_id(item)) {
|
||||
return info_node(fd, item);
|
||||
}
|
||||
|
||||
if(strchr(item, '.') || strchr(item, ':')) {
|
||||
return info_subnet(fd, item);
|
||||
}
|
||||
|
||||
fprintf(stderr, "Argument is not a node name, subnet or address.\n");
|
||||
return 1;
|
||||
}
|
||||
26
src/info.h
26
src/info.h
|
|
@ -1,26 +0,0 @@
|
|||
#ifndef TINC_INFO_H
|
||||
#define TINC_INFO_H
|
||||
|
||||
/*
|
||||
info.h -- header for info.c.
|
||||
Copyright (C) 2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
extern int info(int fd, const char *item);
|
||||
extern char *strip_weight(char *);
|
||||
|
||||
#endif
|
||||
1351
src/invitation.c
1351
src/invitation.c
File diff suppressed because it is too large
Load diff
|
|
@ -1,26 +0,0 @@
|
|||
#ifndef TINC_INVITATION_H
|
||||
#define TINC_INVITATION_H
|
||||
|
||||
/*
|
||||
invitation.h -- header for invitation.c.
|
||||
Copyright (C) 2013 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
int cmd_invite(int argc, char *argv[]);
|
||||
int cmd_join(int argc, char *argv[]);
|
||||
|
||||
#endif
|
||||
|
|
@ -81,7 +81,7 @@ struct ip {
|
|||
uint8_t ip_p;
|
||||
uint16_t ip_sum;
|
||||
struct in_addr ip_src, ip_dst;
|
||||
} __attribute__((__gcc_struct__, __packed__));
|
||||
} __attribute__((__packed__));
|
||||
#endif
|
||||
|
||||
#ifndef IP_OFFMASK
|
||||
|
|
@ -143,7 +143,7 @@ struct icmp {
|
|||
#define icmp_radv icmp_dun.id_radv
|
||||
#define icmp_mask icmp_dun.id_mask
|
||||
#define icmp_data icmp_dun.id_data
|
||||
} __attribute__((__gcc_struct__, __packed__));
|
||||
} __attribute__((__packed__));
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
|||
39
src/ipv6.h
39
src/ipv6.h
|
|
@ -4,7 +4,7 @@
|
|||
/*
|
||||
ipv6.h -- missing IPv6 related definitions
|
||||
Copyright (C) 2005 Ivo Timmermans
|
||||
2006-2016 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2006-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
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
|
||||
|
|
@ -29,11 +29,34 @@
|
|||
#define IPPROTO_ICMPV6 58
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRUCT_IN6_ADDR
|
||||
struct in6_addr {
|
||||
union {
|
||||
uint8_t u6_addr8[16];
|
||||
uint16_t u6_addr16[8];
|
||||
uint32_t u6_addr32[4];
|
||||
} in6_u;
|
||||
} __attribute__((__packed__));
|
||||
#define s6_addr in6_u.u6_addr8
|
||||
#define s6_addr16 in6_u.u6_addr16
|
||||
#define s6_addr32 in6_u.u6_addr32
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRUCT_SOCKADDR_IN6
|
||||
struct sockaddr_in6 {
|
||||
uint16_t sin6_family;
|
||||
uint16_t sin6_port;
|
||||
uint32_t sin6_flowinfo;
|
||||
struct in6_addr sin6_addr;
|
||||
uint32_t sin6_scope_id;
|
||||
} __attribute__((__packed__));
|
||||
#endif
|
||||
|
||||
#ifndef IN6_IS_ADDR_V4MAPPED
|
||||
#define IN6_IS_ADDR_V4MAPPED(a) \
|
||||
((((__const uint32_t *) (a))[0] == 0) \
|
||||
&& (((__const uint32_t *) (a))[1] == 0) \
|
||||
&& (((__const uint32_t *) (a))[2] == htonl (0xffff)))
|
||||
((((const uint32_t *) (a))[0] == 0) \
|
||||
&& (((const uint32_t *) (a))[1] == 0) \
|
||||
&& (((const uint32_t *) (a))[2] == htonl (0xffff)))
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRUCT_IP6_HDR
|
||||
|
|
@ -49,7 +72,7 @@ struct ip6_hdr {
|
|||
} ip6_ctlun;
|
||||
struct in6_addr ip6_src;
|
||||
struct in6_addr ip6_dst;
|
||||
} __attribute__((__gcc_struct__, __packed__));
|
||||
} __attribute__((__packed__));
|
||||
#define ip6_vfc ip6_ctlun.ip6_un2_vfc
|
||||
#define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow
|
||||
#define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen
|
||||
|
|
@ -68,7 +91,7 @@ struct icmp6_hdr {
|
|||
uint16_t icmp6_un_data16[2];
|
||||
uint8_t icmp6_un_data8[4];
|
||||
} icmp6_dataun;
|
||||
} __attribute__((__gcc_struct__, __packed__));
|
||||
} __attribute__((__packed__));
|
||||
#define ICMP6_DST_UNREACH_NOROUTE 0
|
||||
#define ICMP6_DST_UNREACH 1
|
||||
#define ICMP6_PACKET_TOO_BIG 2
|
||||
|
|
@ -88,7 +111,7 @@ struct icmp6_hdr {
|
|||
struct nd_neighbor_solicit {
|
||||
struct icmp6_hdr nd_ns_hdr;
|
||||
struct in6_addr nd_ns_target;
|
||||
} __attribute__((__gcc_struct__, __packed__));
|
||||
} __attribute__((__packed__));
|
||||
#define ND_OPT_SOURCE_LINKADDR 1
|
||||
#define ND_OPT_TARGET_LINKADDR 2
|
||||
#define nd_ns_type nd_ns_hdr.icmp6_type
|
||||
|
|
@ -101,7 +124,7 @@ struct nd_neighbor_solicit {
|
|||
struct nd_opt_hdr {
|
||||
uint8_t nd_opt_type;
|
||||
uint8_t nd_opt_len;
|
||||
} __attribute__((__gcc_struct__, __packed__));
|
||||
} __attribute__((__packed__));
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -20,20 +20,23 @@
|
|||
|
||||
#include "../system.h"
|
||||
|
||||
#ifdef HAVE_LINUX_IF_TUN_H
|
||||
#include <linux/if_tun.h>
|
||||
#define DEFAULT_DEVICE "/dev/net/tun"
|
||||
#else
|
||||
#define DEFAULT_DEVICE "/dev/tap0"
|
||||
#endif
|
||||
|
||||
#include "../conf.h"
|
||||
#include "../device.h"
|
||||
#include "../logger.h"
|
||||
#include "../names.h"
|
||||
#include "../net.h"
|
||||
#include "../route.h"
|
||||
#include "../utils.h"
|
||||
#include "../xalloc.h"
|
||||
#include "../device.h"
|
||||
|
||||
typedef enum device_type_t {
|
||||
DEVICE_TYPE_ETHERTAP,
|
||||
DEVICE_TYPE_TUN,
|
||||
DEVICE_TYPE_TAP,
|
||||
} device_type_t;
|
||||
|
|
@ -46,20 +49,30 @@ static char *type = NULL;
|
|||
static char ifrname[IFNAMSIZ];
|
||||
static const char *device_info;
|
||||
|
||||
static uint64_t device_total_in = 0;
|
||||
static uint64_t device_total_out = 0;
|
||||
|
||||
static bool setup_device(void) {
|
||||
struct ifreq ifr;
|
||||
bool t1q = false;
|
||||
|
||||
if(!get_config_string(lookup_config(config_tree, "Device"), &device)) {
|
||||
device = xstrdup(DEFAULT_DEVICE);
|
||||
}
|
||||
|
||||
if(!get_config_string(lookup_config(config_tree, "Interface"), &iface))
|
||||
if(netname) {
|
||||
#ifdef HAVE_LINUX_IF_TUN_H
|
||||
if(netname != NULL) {
|
||||
iface = xstrdup(netname);
|
||||
}
|
||||
|
||||
#else
|
||||
iface = xstrdup(strrchr(device, '/') ? strrchr(device, '/') + 1 : device);
|
||||
#endif
|
||||
device_fd = open(device, O_RDWR | O_NONBLOCK);
|
||||
|
||||
if(device_fd < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not open %s: %s", device, strerror(errno));
|
||||
logger(LOG_ERR, "Could not open %s: %s", device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -67,12 +80,15 @@ static bool setup_device(void) {
|
|||
fcntl(device_fd, F_SETFD, FD_CLOEXEC);
|
||||
#endif
|
||||
|
||||
struct ifreq ifr = {0};
|
||||
#ifdef HAVE_LINUX_IF_TUN_H
|
||||
/* Ok now check if this is an old ethertap or a new tun/tap thingie */
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
|
||||
get_config_string(lookup_config(config_tree, "DeviceType"), &type);
|
||||
|
||||
if(type && strcasecmp(type, "tun") && strcasecmp(type, "tap")) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unknown device type %s!", type);
|
||||
logger(LOG_ERR, "Unknown device type %s!", type);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -91,10 +107,8 @@ static bool setup_device(void) {
|
|||
}
|
||||
|
||||
#ifdef IFF_ONE_QUEUE
|
||||
|
||||
/* Set IFF_ONE_QUEUE flag... */
|
||||
|
||||
bool t1q = false;
|
||||
|
||||
if(get_config_bool(lookup_config(config_tree, "IffOneQueue"), &t1q) && t1q) {
|
||||
ifr.ifr_flags |= IFF_ONE_QUEUE;
|
||||
}
|
||||
|
|
@ -111,93 +125,105 @@ static bool setup_device(void) {
|
|||
ifrname[IFNAMSIZ - 1] = 0;
|
||||
free(iface);
|
||||
iface = xstrdup(ifrname);
|
||||
} else {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not create a tun/tap interface from %s: %s", device, strerror(errno));
|
||||
} else if(errno == EPERM || errno == EBUSY) {
|
||||
logger(LOG_ERR, "Error while trying to configure %s: %s", device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
logger(DEBUG_ALWAYS, LOG_INFO, "%s is a %s", device, device_info);
|
||||
|
||||
if(ifr.ifr_flags & IFF_TAP) {
|
||||
struct ifreq ifr_mac = {0};
|
||||
|
||||
if(!ioctl(device_fd, SIOCGIFHWADDR, &ifr_mac)) {
|
||||
memcpy(mymac.x, ifr_mac.ifr_hwaddr.sa_data, ETH_ALEN);
|
||||
} else {
|
||||
logger(DEBUG_ALWAYS, LOG_WARNING, "Could not get MAC address of %s: %s", device, strerror(errno));
|
||||
} else if(!ioctl(device_fd, (('T' << 8) | 202), &ifr)) {
|
||||
logger(LOG_WARNING, "Old ioctl() request was needed for %s", device);
|
||||
strncpy(ifrname, ifr.ifr_name, IFNAMSIZ);
|
||||
ifrname[IFNAMSIZ - 1] = 0;
|
||||
free(iface);
|
||||
iface = xstrdup(ifrname);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
if(routing_mode == RMODE_ROUTER) {
|
||||
overwrite_mac = true;
|
||||
}
|
||||
|
||||
device_info = "Linux ethertap device";
|
||||
device_type = DEVICE_TYPE_ETHERTAP;
|
||||
free(iface);
|
||||
iface = xstrdup(strrchr(device, '/') ? strrchr(device, '/') + 1 : device);
|
||||
}
|
||||
|
||||
if(overwrite_mac && !ioctl(device_fd, SIOCGIFHWADDR, &ifr)) {
|
||||
memcpy(mymac.x, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
|
||||
}
|
||||
|
||||
logger(LOG_INFO, "%s is a %s", device, device_info);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void close_device(void) {
|
||||
close(device_fd);
|
||||
device_fd = -1;
|
||||
|
||||
free(type);
|
||||
type = NULL;
|
||||
free(device);
|
||||
device = NULL;
|
||||
free(iface);
|
||||
iface = NULL;
|
||||
device_info = NULL;
|
||||
}
|
||||
|
||||
static bool read_packet(vpn_packet_t *packet) {
|
||||
int inlen;
|
||||
int lenin;
|
||||
|
||||
switch(device_type) {
|
||||
case DEVICE_TYPE_TUN:
|
||||
inlen = read(device_fd, DATA(packet) + 10, MTU - 10);
|
||||
lenin = read(device_fd, packet->data + 10, MTU - 10);
|
||||
|
||||
if(inlen <= 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s",
|
||||
if(lenin <= 0) {
|
||||
logger(LOG_ERR, "Error while reading from %s %s: %s",
|
||||
device_info, device, strerror(errno));
|
||||
|
||||
if(errno == EBADFD) { /* File descriptor in bad state */
|
||||
event_exit();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(DATA(packet), 0, 12);
|
||||
packet->len = inlen + 10;
|
||||
memset(packet->data, 0, 12);
|
||||
packet->len = lenin + 10;
|
||||
break;
|
||||
|
||||
case DEVICE_TYPE_TAP:
|
||||
inlen = read(device_fd, DATA(packet), MTU);
|
||||
lenin = read(device_fd, packet->data, MTU);
|
||||
|
||||
if(inlen <= 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s",
|
||||
if(lenin <= 0) {
|
||||
logger(LOG_ERR, "Error while reading from %s %s: %s",
|
||||
device_info, device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
packet->len = inlen;
|
||||
packet->len = lenin;
|
||||
break;
|
||||
|
||||
default:
|
||||
abort();
|
||||
case DEVICE_TYPE_ETHERTAP:
|
||||
lenin = read(device_fd, packet->data - 2, MTU + 2);
|
||||
|
||||
if(lenin <= 0) {
|
||||
logger(LOG_ERR, "Error while reading from %s %s: %s",
|
||||
device_info, device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
packet->len = lenin - 2;
|
||||
break;
|
||||
}
|
||||
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Read packet of %d bytes from %s", packet->len,
|
||||
device_info);
|
||||
device_total_in += packet->len;
|
||||
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s", packet->len,
|
||||
device_info);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool write_packet(vpn_packet_t *packet) {
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Writing packet of %d bytes to %s",
|
||||
packet->len, device_info);
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
|
||||
packet->len, device_info);
|
||||
|
||||
switch(device_type) {
|
||||
case DEVICE_TYPE_TUN:
|
||||
DATA(packet)[10] = DATA(packet)[11] = 0;
|
||||
packet->data[10] = packet->data[11] = 0;
|
||||
|
||||
if(write(device_fd, DATA(packet) + 10, packet->len - 10) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Can't write to %s %s: %s", device_info, device,
|
||||
if(write(device_fd, packet->data + 10, packet->len - 10) < 0) {
|
||||
logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device,
|
||||
strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
|
@ -205,24 +231,41 @@ static bool write_packet(vpn_packet_t *packet) {
|
|||
break;
|
||||
|
||||
case DEVICE_TYPE_TAP:
|
||||
if(write(device_fd, DATA(packet), packet->len) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Can't write to %s %s: %s", device_info, device,
|
||||
if(write(device_fd, packet->data, packet->len) < 0) {
|
||||
logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device,
|
||||
strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
abort();
|
||||
case DEVICE_TYPE_ETHERTAP:
|
||||
memcpy(packet->data - 2, &packet->len, 2);
|
||||
|
||||
if(write(device_fd, packet->data - 2, packet->len + 2) < 0) {
|
||||
logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device,
|
||||
strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
device_total_out += packet->len;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void dump_device_stats(void) {
|
||||
logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
|
||||
logger(LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in);
|
||||
logger(LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
|
||||
}
|
||||
|
||||
const devops_t os_devops = {
|
||||
.setup = setup_device,
|
||||
.close = close_device,
|
||||
.read = read_packet,
|
||||
.write = write_packet,
|
||||
.dump_stats = dump_device_stats,
|
||||
};
|
||||
|
|
|
|||
80
src/list.c
80
src/list.c
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
list.c -- functions to deal with double linked lists
|
||||
Copyright (C) 2000-2005 Ivo Timmermans
|
||||
2000-2013 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2000-2006 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
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
|
||||
|
|
@ -26,7 +26,9 @@
|
|||
/* (De)constructors */
|
||||
|
||||
list_t *list_alloc(list_action_t delete) {
|
||||
list_t *list = xzalloc(sizeof(list_t));
|
||||
list_t *list;
|
||||
|
||||
list = xmalloc_and_zero(sizeof(list_t));
|
||||
list->delete = delete;
|
||||
|
||||
return list;
|
||||
|
|
@ -37,7 +39,7 @@ void list_free(list_t *list) {
|
|||
}
|
||||
|
||||
list_node_t *list_alloc_node(void) {
|
||||
return xzalloc(sizeof(list_node_t));
|
||||
return xmalloc_and_zero(sizeof(list_node_t));
|
||||
}
|
||||
|
||||
void list_free_node(list_t *list, list_node_t *node) {
|
||||
|
|
@ -51,7 +53,9 @@ void list_free_node(list_t *list, list_node_t *node) {
|
|||
/* Insertion and deletion */
|
||||
|
||||
list_node_t *list_insert_head(list_t *list, void *data) {
|
||||
list_node_t *node = list_alloc_node();
|
||||
list_node_t *node;
|
||||
|
||||
node = list_alloc_node();
|
||||
|
||||
node->data = data;
|
||||
node->prev = NULL;
|
||||
|
|
@ -70,52 +74,14 @@ list_node_t *list_insert_head(list_t *list, void *data) {
|
|||
}
|
||||
|
||||
list_node_t *list_insert_tail(list_t *list, void *data) {
|
||||
list_node_t *node = list_alloc_node();
|
||||
|
||||
node->data = data;
|
||||
node->next = NULL;
|
||||
node->prev = list->tail;
|
||||
list->tail = node;
|
||||
|
||||
if(node->prev) {
|
||||
node->prev->next = node;
|
||||
} else {
|
||||
list->head = node;
|
||||
}
|
||||
|
||||
list->count++;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
list_node_t *list_insert_after(list_t *list, list_node_t *after, void *data) {
|
||||
list_node_t *node = list_alloc_node();
|
||||
|
||||
node->data = data;
|
||||
node->next = after->next;
|
||||
node->prev = after;
|
||||
after->next = node;
|
||||
|
||||
if(node->next) {
|
||||
node->next->prev = node;
|
||||
} else {
|
||||
list->tail = node;
|
||||
}
|
||||
|
||||
list->count++;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
list_node_t *list_insert_before(list_t *list, list_node_t *before, void *data) {
|
||||
list_node_t *node;
|
||||
|
||||
node = list_alloc_node();
|
||||
|
||||
node->data = data;
|
||||
node->next = before;
|
||||
node->prev = before->prev;
|
||||
before->prev = node;
|
||||
node->next = NULL;
|
||||
node->prev = list->tail;
|
||||
list->tail = node;
|
||||
|
||||
if(node->prev) {
|
||||
node->prev->next = node;
|
||||
|
|
@ -157,13 +123,6 @@ void list_delete_tail(list_t *list) {
|
|||
list_delete_node(list, list->tail);
|
||||
}
|
||||
|
||||
void list_delete(list_t *list, const void *data) {
|
||||
for(list_node_t *node = list->head, *next; next = node ? node->next : NULL, node; node = next)
|
||||
if(node->data == data) {
|
||||
list_delete_node(list, node);
|
||||
}
|
||||
}
|
||||
|
||||
/* Head/tail lookup */
|
||||
|
||||
void *list_get_head(list_t *list) {
|
||||
|
|
@ -185,7 +144,10 @@ void *list_get_tail(list_t *list) {
|
|||
/* Fast list deletion */
|
||||
|
||||
void list_delete_list(list_t *list) {
|
||||
for(list_node_t *node = list->head, *next; next = node ? node->next : NULL, node; node = next) {
|
||||
list_node_t *node, *next;
|
||||
|
||||
for(node = list->head; node; node = next) {
|
||||
next = node->next;
|
||||
list_free_node(list, node);
|
||||
}
|
||||
|
||||
|
|
@ -195,14 +157,22 @@ void list_delete_list(list_t *list) {
|
|||
/* Traversing */
|
||||
|
||||
void list_foreach_node(list_t *list, list_action_node_t action) {
|
||||
for(list_node_t *node = list->head, *next; next = node ? node->next : NULL, node; node = next) {
|
||||
list_node_t *node, *next;
|
||||
|
||||
for(node = list->head; node; node = next) {
|
||||
next = node->next;
|
||||
action(node);
|
||||
}
|
||||
}
|
||||
|
||||
void list_foreach(list_t *list, list_action_t action) {
|
||||
for(list_node_t *node = list->head, *next; next = node ? node->next : NULL, node; node = next)
|
||||
list_node_t *node, *next;
|
||||
|
||||
for(node = list->head; node; node = next) {
|
||||
next = node->next;
|
||||
|
||||
if(node->data) {
|
||||
action(node->data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
20
src/list.h
20
src/list.h
|
|
@ -4,7 +4,7 @@
|
|||
/*
|
||||
list.h -- header file for list.c
|
||||
Copyright (C) 2000-2005 Ivo Timmermans
|
||||
2000-2012 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2000-2006 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
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
|
||||
|
|
@ -30,8 +30,8 @@ typedef struct list_node_t {
|
|||
void *data;
|
||||
} list_node_t;
|
||||
|
||||
typedef void (*list_action_t)(const void *data);
|
||||
typedef void (*list_action_node_t)(const list_node_t *node);
|
||||
typedef void (*list_action_t)(const void *);
|
||||
typedef void (*list_action_node_t)(const list_node_t *);
|
||||
|
||||
typedef struct list_t {
|
||||
list_node_t *head;
|
||||
|
|
@ -45,7 +45,7 @@ typedef struct list_t {
|
|||
|
||||
/* (De)constructors */
|
||||
|
||||
extern list_t *list_alloc(list_action_t delete) __attribute__((__malloc__));
|
||||
extern list_t *list_alloc(list_action_t) __attribute__((__malloc__));
|
||||
extern void list_free(list_t *list);
|
||||
extern list_node_t *list_alloc_node(void);
|
||||
extern void list_free_node(list_t *list, list_node_t *node);
|
||||
|
|
@ -54,10 +54,6 @@ extern void list_free_node(list_t *list, list_node_t *node);
|
|||
|
||||
extern list_node_t *list_insert_head(list_t *list, void *data);
|
||||
extern list_node_t *list_insert_tail(list_t *list, void *data);
|
||||
extern list_node_t *list_insert_after(list_t *list, list_node_t *node, void *data);
|
||||
extern list_node_t *list_insert_before(list_t *list, list_node_t *node, void *data);
|
||||
|
||||
extern void list_delete(list_t *list, const void *data);
|
||||
|
||||
extern void list_unlink_node(list_t *list, list_node_t *node);
|
||||
extern void list_delete_node(list_t *list, list_node_t *node);
|
||||
|
|
@ -79,12 +75,4 @@ extern void list_delete_list(list_t *list);
|
|||
extern void list_foreach(list_t *list, list_action_t action);
|
||||
extern void list_foreach_node(list_t *list, list_action_node_t action);
|
||||
|
||||
/*
|
||||
Iterates over a list.
|
||||
|
||||
CAUTION: while this construct supports deleting the current item,
|
||||
it does *not* support deleting *other* nodes while iterating on the list.
|
||||
*/
|
||||
#define list_each(type, item, list) (type *item = (type *)1; item; item = NULL) for(list_node_t *node = (list)->head, *next; item = node ? node->data : NULL, next = node ? node->next : NULL, node; node = next)
|
||||
|
||||
#endif
|
||||
|
|
|
|||
199
src/logger.c
199
src/logger.c
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
logger.c -- logging code
|
||||
Copyright (C) 2004-2017 Guus Sliepen <guus@tinc-vpn.org>
|
||||
Copyright (C) 2004-2016 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2004-2005 Ivo Timmermans
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
|
|
@ -21,146 +21,17 @@
|
|||
#include "system.h"
|
||||
|
||||
#include "conf.h"
|
||||
#include "meta.h"
|
||||
#include "names.h"
|
||||
#include "logger.h"
|
||||
#include "connection.h"
|
||||
#include "control_common.h"
|
||||
#include "process.h"
|
||||
#include "sptps.h"
|
||||
|
||||
int debug_level = DEBUG_NOTHING;
|
||||
debug_t debug_level = DEBUG_NOTHING;
|
||||
static logmode_t logmode = LOGMODE_STDERR;
|
||||
static pid_t logpid;
|
||||
extern char *logfilename;
|
||||
static FILE *logfile = NULL;
|
||||
#ifdef HAVE_MINGW
|
||||
static HANDLE loghandle = NULL;
|
||||
#endif
|
||||
static const char *logident = NULL;
|
||||
bool logcontrol = false;
|
||||
int umbilical = 0;
|
||||
|
||||
static void real_logger(int level, int priority, const char *message) {
|
||||
char timestr[32] = "";
|
||||
static bool suppress = false;
|
||||
|
||||
// Bail out early if there is nothing to do.
|
||||
if(suppress) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!logcontrol && (level > debug_level || logmode == LOGMODE_NULL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(level <= debug_level) {
|
||||
switch(logmode) {
|
||||
case LOGMODE_STDERR:
|
||||
fprintf(stderr, "%s\n", message);
|
||||
fflush(stderr);
|
||||
break;
|
||||
|
||||
case LOGMODE_FILE:
|
||||
if(!now.tv_sec) {
|
||||
gettimeofday(&now, NULL);
|
||||
}
|
||||
|
||||
time_t now_sec = now.tv_sec;
|
||||
strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S", localtime(&now_sec));
|
||||
fprintf(logfile, "%s %s[%ld]: %s\n", timestr, logident, (long)logpid, message);
|
||||
fflush(logfile);
|
||||
break;
|
||||
|
||||
case LOGMODE_SYSLOG:
|
||||
#ifdef HAVE_MINGW
|
||||
{
|
||||
const char *messages[] = {message};
|
||||
ReportEvent(loghandle, priority, 0, 0, NULL, 1, 0, messages, NULL);
|
||||
}
|
||||
|
||||
#else
|
||||
#ifdef HAVE_SYSLOG_H
|
||||
syslog(priority, "%s", message);
|
||||
#endif
|
||||
#endif
|
||||
break;
|
||||
|
||||
case LOGMODE_NULL:
|
||||
break;
|
||||
}
|
||||
|
||||
if(umbilical && do_detach) {
|
||||
write(umbilical, message, strlen(message));
|
||||
write(umbilical, "\n", 1);
|
||||
}
|
||||
}
|
||||
|
||||
if(logcontrol) {
|
||||
suppress = true;
|
||||
logcontrol = false;
|
||||
|
||||
for list_each(connection_t, c, connection_list) {
|
||||
if(!c->status.log) {
|
||||
continue;
|
||||
}
|
||||
|
||||
logcontrol = true;
|
||||
|
||||
if(level > (c->outcompression >= 0 ? c->outcompression : debug_level)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int len = strlen(message);
|
||||
|
||||
if(send_request(c, "%d %d %d", CONTROL, REQ_LOG, len)) {
|
||||
send_meta(c, message, len);
|
||||
}
|
||||
}
|
||||
|
||||
suppress = false;
|
||||
}
|
||||
}
|
||||
|
||||
void logger(int level, int priority, const char *format, ...) {
|
||||
va_list ap;
|
||||
char message[1024] = "";
|
||||
|
||||
va_start(ap, format);
|
||||
int len = vsnprintf(message, sizeof(message), format, ap);
|
||||
message[sizeof(message) - 1] = 0;
|
||||
va_end(ap);
|
||||
|
||||
if(len > 0 && (size_t)len < sizeof(message) - 1 && message[len - 1] == '\n') {
|
||||
message[len - 1] = 0;
|
||||
}
|
||||
|
||||
real_logger(level, priority, message);
|
||||
}
|
||||
|
||||
static void sptps_logger(sptps_t *s, int s_errno, const char *format, va_list ap) {
|
||||
(void)s_errno;
|
||||
char message[1024];
|
||||
size_t msglen = sizeof(message);
|
||||
|
||||
int len = vsnprintf(message, msglen, format, ap);
|
||||
message[sizeof(message) - 1] = 0;
|
||||
|
||||
if(len > 0 && (size_t)len < sizeof(message) - 1) {
|
||||
if(message[len - 1] == '\n') {
|
||||
message[--len] = 0;
|
||||
}
|
||||
|
||||
// WARNING: s->handle can point to a connection_t or a node_t,
|
||||
// but both types have the name and hostname fields at the same offsets.
|
||||
connection_t *c = s->handle;
|
||||
|
||||
if(c) {
|
||||
snprintf(message + len, sizeof(message) - len, " from %s (%s)", c->name, c->hostname);
|
||||
}
|
||||
}
|
||||
|
||||
real_logger(DEBUG_ALWAYS, LOG_ERR, message);
|
||||
}
|
||||
|
||||
void openlogger(const char *ident, logmode_t mode) {
|
||||
logident = ident;
|
||||
|
|
@ -187,7 +58,7 @@ void openlogger(const char *ident, logmode_t mode) {
|
|||
loghandle = RegisterEventSource(NULL, logident);
|
||||
|
||||
if(!loghandle) {
|
||||
fprintf(stderr, "Could not open log handle!\n");
|
||||
fprintf(stderr, "Could not open log handle!");
|
||||
logmode = LOGMODE_NULL;
|
||||
}
|
||||
|
||||
|
|
@ -202,12 +73,6 @@ void openlogger(const char *ident, logmode_t mode) {
|
|||
case LOGMODE_NULL:
|
||||
break;
|
||||
}
|
||||
|
||||
if(logmode != LOGMODE_NULL) {
|
||||
sptps_log = sptps_logger;
|
||||
} else {
|
||||
sptps_log = sptps_log_quiet;
|
||||
}
|
||||
}
|
||||
|
||||
void reopenlogger() {
|
||||
|
|
@ -219,7 +84,7 @@ void reopenlogger() {
|
|||
FILE *newfile = fopen(logfilename, "a");
|
||||
|
||||
if(!newfile) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to reopen log file %s: %s", logfilename, strerror(errno));
|
||||
logger(LOG_ERR, "Unable to reopen log file %s: %s", logfilename, strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -227,6 +92,60 @@ void reopenlogger() {
|
|||
logfile = newfile;
|
||||
}
|
||||
|
||||
void logger(int priority, const char *format, ...) {
|
||||
va_list ap;
|
||||
char timestr[32] = "";
|
||||
time_t now;
|
||||
|
||||
va_start(ap, format);
|
||||
|
||||
switch(logmode) {
|
||||
case LOGMODE_STDERR:
|
||||
vfprintf(stderr, format, ap);
|
||||
fprintf(stderr, "\n");
|
||||
fflush(stderr);
|
||||
break;
|
||||
|
||||
case LOGMODE_FILE:
|
||||
now = time(NULL);
|
||||
strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S", localtime(&now));
|
||||
fprintf(logfile, "%s %s[%ld]: ", timestr, logident, (long)logpid);
|
||||
vfprintf(logfile, format, ap);
|
||||
fprintf(logfile, "\n");
|
||||
fflush(logfile);
|
||||
break;
|
||||
|
||||
case LOGMODE_SYSLOG:
|
||||
#ifdef HAVE_MINGW
|
||||
{
|
||||
char message[4096];
|
||||
const char *messages[] = {message};
|
||||
vsnprintf(message, sizeof(message), format, ap);
|
||||
message[sizeof(message) - 1] = 0;
|
||||
ReportEvent(loghandle, priority, 0, 0, NULL, 1, 0, messages, NULL);
|
||||
}
|
||||
|
||||
#else
|
||||
#ifdef HAVE_SYSLOG_H
|
||||
#ifdef HAVE_VSYSLOG
|
||||
vsyslog(priority, format, ap);
|
||||
#else
|
||||
{
|
||||
char message[4096];
|
||||
vsnprintf(message, sizeof(message), format, ap);
|
||||
syslog(priority, "%s", message);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
case LOGMODE_NULL:
|
||||
break;
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void closelogger(void) {
|
||||
switch(logmode) {
|
||||
|
|
|
|||
31
src/logger.h
31
src/logger.h
|
|
@ -3,8 +3,7 @@
|
|||
|
||||
/*
|
||||
logger.h -- header file for logger.c
|
||||
Copyright (C) 1998-2005 Ivo Timmermans
|
||||
2000-2017 Guus Sliepen <guus@tinc-vpn.org>
|
||||
Copyright (C) 2003-2016 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
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
|
||||
|
|
@ -22,16 +21,16 @@
|
|||
*/
|
||||
|
||||
typedef enum debug_t {
|
||||
DEBUG_NOTHING = 0, /* Quiet mode, only show starting/stopping of the daemon */
|
||||
DEBUG_NOTHING = 0, /* Quiet mode, only show starting/stopping of the daemon */
|
||||
DEBUG_ALWAYS = 0,
|
||||
DEBUG_CONNECTIONS = 1, /* Show (dis)connects of other tinc daemons via TCP */
|
||||
DEBUG_ERROR = 2, /* Show error messages received from other hosts */
|
||||
DEBUG_STATUS = 2, /* Show status messages received from other hosts */
|
||||
DEBUG_PROTOCOL = 3, /* Show the requests that are sent/received */
|
||||
DEBUG_META = 4, /* Show contents of every request that is sent/received */
|
||||
DEBUG_TRAFFIC = 5, /* Show network traffic information */
|
||||
DEBUG_PACKET = 6, /* Show contents of each packet that is being sent/received */
|
||||
DEBUG_SCARY_THINGS = 10 /* You have been warned */
|
||||
DEBUG_CONNECTIONS = 1, /* Show (dis)connects of other tinc daemons via TCP */
|
||||
DEBUG_ERROR = 2, /* Show error messages received from other hosts */
|
||||
DEBUG_STATUS = 2, /* Show status messages received from other hosts */
|
||||
DEBUG_PROTOCOL = 3, /* Show the requests that are sent/received */
|
||||
DEBUG_META = 4, /* Show contents of every request that is sent/received */
|
||||
DEBUG_TRAFFIC = 5, /* Show network traffic information */
|
||||
DEBUG_PACKET = 6, /* Show contents of each packet that is being sent/received */
|
||||
DEBUG_SCARY_THINGS = 10, /* You have been warned */
|
||||
} debug_t;
|
||||
|
||||
typedef enum logmode_t {
|
||||
|
|
@ -65,14 +64,12 @@ enum {
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
extern int debug_level;
|
||||
extern bool logcontrol;
|
||||
extern int umbilical;
|
||||
extern debug_t debug_level;
|
||||
extern void openlogger(const char *ident, logmode_t mode);
|
||||
extern void reopenlogger(void);
|
||||
extern void logger(int level, int priority, const char *format, ...) __attribute__((__format__(printf, 3, 4)));
|
||||
extern void logger(int priority, const char *format, ...) __attribute__((__format__(printf, 2, 3)));
|
||||
extern void closelogger(void);
|
||||
|
||||
#define ifdebug(l) if(debug_level >= DEBUG_##l)
|
||||
|
||||
#endif
|
||||
|
|
|
|||
367
src/meta.c
367
src/meta.c
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
meta.c -- handle the meta communication
|
||||
Copyright (C) 2000-2014 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
Copyright (C) 2000-2017 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
2000-2005 Ivo Timmermans
|
||||
2006 Scott Lamb <slamb@slamb.org>
|
||||
|
||||
|
|
@ -21,147 +21,125 @@
|
|||
|
||||
#include "system.h"
|
||||
|
||||
#include "cipher.h"
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#include "avl_tree.h"
|
||||
#include "connection.h"
|
||||
#include "logger.h"
|
||||
#include "meta.h"
|
||||
#include "net.h"
|
||||
#include "protocol.h"
|
||||
#include "proxy.h"
|
||||
#include "utils.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(x, y) (((x)<(y))?(x):(y))
|
||||
#endif
|
||||
bool send_meta(connection_t *c, const char *buffer, int length) {
|
||||
int outlen;
|
||||
int result;
|
||||
|
||||
bool send_meta_sptps(void *handle, uint8_t type, const void *buffer, size_t length) {
|
||||
(void)type;
|
||||
connection_t *c = handle;
|
||||
ifdebug(META) logger(LOG_DEBUG, "Sending %d bytes of metadata to %s (%s)", length,
|
||||
c->name, c->hostname);
|
||||
|
||||
if(!c) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "send_meta_sptps() called with NULL pointer!");
|
||||
abort();
|
||||
if(!c->outbuflen) {
|
||||
c->last_flushed_time = now;
|
||||
}
|
||||
|
||||
buffer_add(&c->outbuf, buffer, length);
|
||||
io_set(&c->io, IO_READ | IO_WRITE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool send_meta(connection_t *c, const char *buffer, size_t length) {
|
||||
if(!c) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "send_meta() called with NULL pointer!");
|
||||
abort();
|
||||
/* Find room in connection's buffer */
|
||||
if(length + c->outbuflen > c->outbufsize) {
|
||||
c->outbufsize = length + c->outbuflen;
|
||||
c->outbuf = xrealloc(c->outbuf, c->outbufsize);
|
||||
}
|
||||
|
||||
logger(DEBUG_META, LOG_DEBUG, "Sending %lu bytes of metadata to %s (%s)", (unsigned long)length,
|
||||
c->name, c->hostname);
|
||||
|
||||
if(c->protocol_minor >= 2) {
|
||||
return sptps_send_record(&c->sptps, 0, buffer, length);
|
||||
if(length + c->outbuflen + c->outbufstart > c->outbufsize) {
|
||||
memmove(c->outbuf, c->outbuf + c->outbufstart, c->outbuflen);
|
||||
c->outbufstart = 0;
|
||||
}
|
||||
|
||||
/* Add our data to buffer */
|
||||
if(c->status.encryptout) {
|
||||
#ifdef DISABLE_LEGACY
|
||||
return false;
|
||||
#else
|
||||
|
||||
if(length > c->outbudget) {
|
||||
logger(DEBUG_META, LOG_ERR, "Byte limit exceeded for encryption to %s (%s)", c->name, c->hostname);
|
||||
/* Check encryption limits */
|
||||
if((uint64_t)length > c->outbudget) {
|
||||
ifdebug(META) logger(LOG_ERR, "Byte limit exceeded for encryption to %s (%s)", c->name, c->hostname);
|
||||
return false;
|
||||
} else {
|
||||
c->outbudget -= length;
|
||||
}
|
||||
|
||||
size_t outlen = length;
|
||||
result = EVP_EncryptUpdate(c->outctx, (unsigned char *)c->outbuf + c->outbufstart + c->outbuflen,
|
||||
&outlen, (unsigned char *)buffer, length);
|
||||
|
||||
if(!cipher_encrypt(c->outcipher, buffer, length, buffer_prepare(&c->outbuf, length), &outlen, false) || outlen != length) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while encrypting metadata to %s (%s)",
|
||||
c->name, c->hostname);
|
||||
if(!result || outlen < length) {
|
||||
logger(LOG_ERR, "Error while encrypting metadata to %s (%s): %s",
|
||||
c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
} else if(outlen > length) {
|
||||
logger(LOG_EMERG, "Encrypted data too long! Heap corrupted!");
|
||||
abort();
|
||||
}
|
||||
|
||||
#endif
|
||||
c->outbuflen += outlen;
|
||||
} else {
|
||||
buffer_add(&c->outbuf, buffer, length);
|
||||
memcpy(c->outbuf + c->outbufstart + c->outbuflen, buffer, length);
|
||||
c->outbuflen += length;
|
||||
}
|
||||
|
||||
io_set(&c->io, IO_READ | IO_WRITE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void send_meta_raw(connection_t *c, const char *buffer, size_t length) {
|
||||
if(!c) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "send_meta() called with NULL pointer!");
|
||||
abort();
|
||||
}
|
||||
bool flush_meta(connection_t *c) {
|
||||
int result;
|
||||
|
||||
logger(DEBUG_META, LOG_DEBUG, "Sending %lu bytes of raw metadata to %s (%s)", (unsigned long)length,
|
||||
c->name, c->hostname);
|
||||
ifdebug(META) logger(LOG_DEBUG, "Flushing %d bytes to %s (%s)",
|
||||
c->outbuflen, c->name, c->hostname);
|
||||
|
||||
buffer_add(&c->outbuf, buffer, length);
|
||||
while(c->outbuflen) {
|
||||
result = send(c->socket, c->outbuf + c->outbufstart, c->outbuflen, 0);
|
||||
|
||||
io_set(&c->io, IO_READ | IO_WRITE);
|
||||
}
|
||||
if(result <= 0) {
|
||||
if(!errno || errno == EPIPE) {
|
||||
ifdebug(CONNECTIONS) logger(LOG_NOTICE, "Connection closed by %s (%s)",
|
||||
c->name, c->hostname);
|
||||
} else if(errno == EINTR) {
|
||||
continue;
|
||||
} else if(sockwouldblock(sockerrno)) {
|
||||
ifdebug(META) logger(LOG_DEBUG, "Flushing %d bytes to %s (%s) would block",
|
||||
c->outbuflen, c->name, c->hostname);
|
||||
return true;
|
||||
} else {
|
||||
logger(LOG_ERR, "Flushing meta data to %s (%s) failed: %s", c->name,
|
||||
c->hostname, sockstrerror(sockerrno));
|
||||
}
|
||||
|
||||
void broadcast_meta(connection_t *from, const char *buffer, size_t length) {
|
||||
for list_each(connection_t, c, connection_list)
|
||||
if(c != from && c->edge) {
|
||||
send_meta(c, buffer, length);
|
||||
}
|
||||
}
|
||||
|
||||
bool receive_meta_sptps(void *handle, uint8_t type, const void *vdata, uint16_t length) {
|
||||
const char *data = vdata;
|
||||
connection_t *c = handle;
|
||||
|
||||
if(!c) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "receive_meta_sptps() called with NULL pointer!");
|
||||
abort();
|
||||
}
|
||||
|
||||
if(type == SPTPS_HANDSHAKE) {
|
||||
if(c->allow_request == ACK) {
|
||||
return send_ack(c);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if(!data) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Are we receiving a TCPpacket? */
|
||||
|
||||
if(c->tcplen) {
|
||||
if(length != c->tcplen) {
|
||||
return false;
|
||||
}
|
||||
|
||||
receive_tcppacket(c, data, length);
|
||||
c->tcplen = 0;
|
||||
return true;
|
||||
c->outbufstart += result;
|
||||
c->outbuflen -= result;
|
||||
}
|
||||
|
||||
/* Change newline to null byte, just like non-SPTPS requests */
|
||||
c->outbufstart = 0; /* avoid unnecessary memmoves */
|
||||
return true;
|
||||
}
|
||||
|
||||
if(data[length - 1] == '\n') {
|
||||
((char *)data)[length - 1] = 0;
|
||||
void broadcast_meta(connection_t *from, const char *buffer, int length) {
|
||||
avl_node_t *node;
|
||||
connection_t *c;
|
||||
|
||||
for(node = connection_tree->head; node; node = node->next) {
|
||||
c = node->data;
|
||||
|
||||
if(c != from && c->status.active) {
|
||||
send_meta(c, buffer, length);
|
||||
}
|
||||
}
|
||||
|
||||
/* Otherwise we are waiting for a request */
|
||||
|
||||
return receive_request(c, data);
|
||||
}
|
||||
|
||||
bool receive_meta(connection_t *c) {
|
||||
ssize_t inlen;
|
||||
int oldlen, i, result;
|
||||
int lenin, lenout, reqlen;
|
||||
bool decrypted = false;
|
||||
char inbuf[MAXBUFSIZE];
|
||||
char *bufp = inbuf, *endp;
|
||||
|
||||
/* Strategy:
|
||||
- Read as much as possible from the TCP socket in one go.
|
||||
|
|
@ -172,174 +150,109 @@ bool receive_meta(connection_t *c) {
|
|||
- If not, keep stuff in buffer and exit.
|
||||
*/
|
||||
|
||||
buffer_compact(&c->inbuf, MAXBUFSIZE);
|
||||
lenin = recv(c->socket, c->buffer + c->buflen, MAXBUFSIZE - c->buflen, 0);
|
||||
|
||||
if(sizeof(inbuf) <= c->inbuf.len) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Input buffer full for %s (%s)", c->name, c->hostname);
|
||||
return false;
|
||||
}
|
||||
|
||||
inlen = recv(c->socket, inbuf, sizeof(inbuf) - c->inbuf.len, 0);
|
||||
|
||||
if(inlen <= 0) {
|
||||
if(!inlen || !sockerrno) {
|
||||
logger(DEBUG_CONNECTIONS, LOG_NOTICE, "Connection closed by %s (%s)",
|
||||
c->name, c->hostname);
|
||||
if(lenin <= 0) {
|
||||
if(!lenin || !errno) {
|
||||
ifdebug(CONNECTIONS) logger(LOG_NOTICE, "Connection closed by %s (%s)",
|
||||
c->name, c->hostname);
|
||||
} else if(sockwouldblock(sockerrno)) {
|
||||
return true;
|
||||
} else
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Metadata socket read error for %s (%s): %s",
|
||||
logger(LOG_ERR, "Metadata socket read error for %s (%s): %s",
|
||||
c->name, c->hostname, sockstrerror(sockerrno));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
do {
|
||||
/* Are we receiving a SPTPS packet? */
|
||||
oldlen = c->buflen;
|
||||
c->buflen += lenin;
|
||||
|
||||
if(c->sptpslen) {
|
||||
ssize_t len = MIN(inlen, c->sptpslen - c->inbuf.len);
|
||||
buffer_add(&c->inbuf, bufp, len);
|
||||
while(lenin > 0) {
|
||||
reqlen = 0;
|
||||
|
||||
char *sptpspacket = buffer_read(&c->inbuf, c->sptpslen);
|
||||
/* Is it proxy metadata? */
|
||||
|
||||
if(!sptpspacket) {
|
||||
return true;
|
||||
}
|
||||
if(c->allow_request == PROXY) {
|
||||
reqlen = receive_proxy_meta(c);
|
||||
|
||||
if(!receive_tcppacket_sptps(c, sptpspacket, c->sptpslen)) {
|
||||
if(reqlen < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
c->sptpslen = 0;
|
||||
|
||||
bufp += len;
|
||||
inlen -= len;
|
||||
continue;
|
||||
goto consume;
|
||||
}
|
||||
|
||||
if(c->protocol_minor >= 2) {
|
||||
size_t len = sptps_receive_data(&c->sptps, bufp, inlen);
|
||||
/* Decrypt */
|
||||
|
||||
if(!len) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bufp += len;
|
||||
inlen -= len;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!c->status.decryptin) {
|
||||
endp = memchr(bufp, '\n', inlen);
|
||||
|
||||
if(endp) {
|
||||
endp++;
|
||||
} else {
|
||||
endp = bufp + inlen;
|
||||
}
|
||||
|
||||
buffer_add(&c->inbuf, bufp, endp - bufp);
|
||||
|
||||
inlen -= endp - bufp;
|
||||
bufp = endp;
|
||||
} else {
|
||||
#ifdef DISABLE_LEGACY
|
||||
return false;
|
||||
#else
|
||||
|
||||
if((size_t)inlen > c->inbudget) {
|
||||
logger(DEBUG_META, LOG_ERR, "Byte limit exceeded for decryption from %s (%s)", c->name, c->hostname);
|
||||
if(c->status.decryptin && !decrypted) {
|
||||
/* Check decryption limits */
|
||||
if((uint64_t)lenin > c->inbudget) {
|
||||
ifdebug(META) logger(LOG_ERR, "Byte limit exceeded for decryption from %s (%s)", c->name, c->hostname);
|
||||
return false;
|
||||
} else {
|
||||
c->inbudget -= inlen;
|
||||
c->inbudget -= lenin;
|
||||
}
|
||||
|
||||
size_t outlen = inlen;
|
||||
result = EVP_DecryptUpdate(c->inctx, (unsigned char *)inbuf, &lenout, (unsigned char *)c->buffer + oldlen, lenin);
|
||||
|
||||
if(!cipher_decrypt(c->incipher, bufp, inlen, buffer_prepare(&c->inbuf, inlen), &outlen, false) || (size_t)inlen != outlen) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while decrypting metadata from %s (%s)",
|
||||
c->name, c->hostname);
|
||||
if(!result || lenout != lenin) {
|
||||
logger(LOG_ERR, "Error while decrypting metadata from %s (%s): %s",
|
||||
c->name, c->hostname, ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
inlen = 0;
|
||||
#endif
|
||||
memcpy(c->buffer + oldlen, inbuf, lenin);
|
||||
decrypted = true;
|
||||
}
|
||||
|
||||
while(c->inbuf.len) {
|
||||
/* Are we receiving a TCPpacket? */
|
||||
/* Are we receiving a TCPpacket? */
|
||||
|
||||
if(c->tcplen) {
|
||||
char *tcpbuffer = buffer_read(&c->inbuf, c->tcplen);
|
||||
|
||||
if(!tcpbuffer) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(!c->node) {
|
||||
if(c->outgoing && proxytype == PROXY_SOCKS4 && c->allow_request == ID) {
|
||||
if(tcpbuffer[0] == 0 && tcpbuffer[1] == 0x5a) {
|
||||
logger(DEBUG_CONNECTIONS, LOG_DEBUG, "Proxy request granted");
|
||||
} else {
|
||||
logger(DEBUG_CONNECTIONS, LOG_ERR, "Proxy request rejected");
|
||||
return false;
|
||||
}
|
||||
} else if(c->outgoing && proxytype == PROXY_SOCKS5 && c->allow_request == ID) {
|
||||
if(tcpbuffer[0] != 5) {
|
||||
logger(DEBUG_CONNECTIONS, LOG_ERR, "Invalid response from proxy server");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(tcpbuffer[1] == (char)0xff) {
|
||||
logger(DEBUG_CONNECTIONS, LOG_ERR, "Proxy request rejected: unsuitable authentication method");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(tcpbuffer[2] != 5) {
|
||||
logger(DEBUG_CONNECTIONS, LOG_ERR, "Invalid response from proxy server");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(tcpbuffer[3] == 0) {
|
||||
logger(DEBUG_CONNECTIONS, LOG_DEBUG, "Proxy request granted");
|
||||
} else {
|
||||
logger(DEBUG_CONNECTIONS, LOG_DEBUG, "Proxy request rejected");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
logger(DEBUG_CONNECTIONS, LOG_ERR, "c->tcplen set but c->node is NULL!");
|
||||
abort();
|
||||
}
|
||||
} else {
|
||||
if(c->allow_request == ALL) {
|
||||
receive_tcppacket(c, tcpbuffer, c->tcplen);
|
||||
} else {
|
||||
logger(DEBUG_CONNECTIONS, LOG_ERR, "Got unauthorized TCP packet from %s (%s)", c->name, c->hostname);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
c->tcplen = 0;
|
||||
}
|
||||
|
||||
/* Otherwise we are waiting for a request */
|
||||
|
||||
char *request = buffer_readline(&c->inbuf);
|
||||
|
||||
if(request) {
|
||||
bool result = receive_request(c, request);
|
||||
|
||||
if(!result) {
|
||||
if(c->tcplen) {
|
||||
if(c->tcplen <= c->buflen) {
|
||||
if(c->allow_request != ALL) {
|
||||
logger(LOG_ERR, "Got unauthorized TCP packet from %s (%s)", c->name, c->hostname);
|
||||
return false;
|
||||
}
|
||||
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
receive_tcppacket(c, c->buffer, c->tcplen);
|
||||
reqlen = c->tcplen;
|
||||
c->tcplen = 0;
|
||||
}
|
||||
} else {
|
||||
/* Otherwise we are waiting for a request */
|
||||
|
||||
for(i = oldlen; i < c->buflen; i++) {
|
||||
if(c->buffer[i] == '\n') {
|
||||
c->buffer[i] = '\0'; /* replace end-of-line by end-of-string so we can use sscanf */
|
||||
c->reqlen = reqlen = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(reqlen && !receive_request(c)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} while(inlen);
|
||||
|
||||
consume:
|
||||
|
||||
if(reqlen) {
|
||||
c->buflen -= reqlen;
|
||||
lenin -= reqlen - oldlen;
|
||||
memmove(c->buffer, c->buffer + reqlen, c->buflen);
|
||||
oldlen = 0;
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(c->buflen >= MAXBUFSIZE) {
|
||||
logger(LOG_ERR, "Metadata read buffer overflow for %s (%s)",
|
||||
c->name, c->hostname);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
10
src/meta.h
10
src/meta.h
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
/*
|
||||
meta.h -- header for meta.c
|
||||
Copyright (C) 2000-2014 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
Copyright (C) 2000-2006 Guus Sliepen <guus@tinc-vpn.org>,
|
||||
2000-2005 Ivo Timmermans
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
|
|
@ -23,11 +23,9 @@
|
|||
|
||||
#include "connection.h"
|
||||
|
||||
extern bool send_meta(struct connection_t *c, const char *buffer, size_t length);
|
||||
extern void send_meta_raw(struct connection_t *c, const char *buffer, size_t length);
|
||||
extern bool send_meta_sptps(void *handle, uint8_t type, const void *data, size_t length);
|
||||
extern bool receive_meta_sptps(void *handle, uint8_t type, const void *data, uint16_t length);
|
||||
extern void broadcast_meta(struct connection_t *from, const char *buffer, size_t length);
|
||||
extern bool send_meta(struct connection_t *c, const char *buffer, int length);
|
||||
extern void broadcast_meta(struct connection_t *c, const char *buffer, int length);
|
||||
extern bool flush_meta(struct connection_t *c);
|
||||
extern bool receive_meta(struct connection_t *c);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,6 +1,3 @@
|
|||
#ifndef TINC_MINGW_COMMON_H
|
||||
#define TINC_MINGW_COMMON_H
|
||||
|
||||
/*
|
||||
* TAP-Win32 -- A kernel driver to provide virtual tap device functionality
|
||||
* on Windows. Originally derived from the CIPE-Win32
|
||||
|
|
@ -76,5 +73,3 @@
|
|||
//=========================================================
|
||||
|
||||
#define TAP_COMPONENT_ID "tap0801"
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
device.c -- Interaction with Windows tap driver in a MinGW environment
|
||||
Copyright (C) 2002-2005 Ivo Timmermans,
|
||||
2002-2014 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2002-2016 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
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
|
||||
|
|
@ -26,7 +26,6 @@
|
|||
#include "../conf.h"
|
||||
#include "../device.h"
|
||||
#include "../logger.h"
|
||||
#include "../names.h"
|
||||
#include "../net.h"
|
||||
#include "../route.h"
|
||||
#include "../utils.h"
|
||||
|
|
@ -36,59 +35,67 @@
|
|||
|
||||
int device_fd = -1;
|
||||
static HANDLE device_handle = INVALID_HANDLE_VALUE;
|
||||
static io_t device_read_io;
|
||||
static OVERLAPPED device_read_overlapped;
|
||||
static OVERLAPPED device_write_overlapped;
|
||||
static vpn_packet_t device_read_packet;
|
||||
static vpn_packet_t device_write_packet;
|
||||
char *device = NULL;
|
||||
char *iface = NULL;
|
||||
static const char *device_info = "Windows tap device";
|
||||
|
||||
extern char *myport;
|
||||
static uint64_t device_total_in = 0;
|
||||
static uint64_t device_total_out = 0;
|
||||
|
||||
static void device_issue_read() {
|
||||
extern char *myport;
|
||||
OVERLAPPED r_overlapped;
|
||||
OVERLAPPED w_overlapped;
|
||||
|
||||
static DWORD WINAPI tapreader(void *bla) {
|
||||
int status;
|
||||
DWORD len;
|
||||
vpn_packet_t packet;
|
||||
int errors = 0;
|
||||
|
||||
logger(LOG_DEBUG, "Tap reader running");
|
||||
|
||||
/* Read from tap device and send to parent */
|
||||
|
||||
r_overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
|
||||
for(;;) {
|
||||
ResetEvent(device_read_overlapped.hEvent);
|
||||
ResetEvent(r_overlapped.hEvent);
|
||||
|
||||
DWORD len;
|
||||
status = ReadFile(device_handle, (void *)device_read_packet.data, MTU, &len, &device_read_overlapped);
|
||||
status = ReadFile(device_handle, packet.data, MTU, &len, &r_overlapped);
|
||||
|
||||
if(!status) {
|
||||
if(GetLastError() != ERROR_IO_PENDING)
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
||||
if(GetLastError() == ERROR_IO_PENDING) {
|
||||
WaitForSingleObject(r_overlapped.hEvent, INFINITE);
|
||||
|
||||
if(!GetOverlappedResult(device_handle, &r_overlapped, &len, FALSE)) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
||||
device, strerror(errno));
|
||||
errors++;
|
||||
|
||||
break;
|
||||
if(errors >= 10) {
|
||||
EnterCriticalSection(&mutex);
|
||||
running = false;
|
||||
LeaveCriticalSection(&mutex);
|
||||
}
|
||||
|
||||
usleep(1000000);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
device_read_packet.len = len;
|
||||
device_read_packet.priority = 0;
|
||||
route(myself, &device_read_packet);
|
||||
}
|
||||
}
|
||||
errors = 0;
|
||||
packet.len = len;
|
||||
packet.priority = 0;
|
||||
|
||||
static void device_handle_read(void *data, int flags) {
|
||||
DWORD len;
|
||||
|
||||
if(!GetOverlappedResult(device_handle, &device_read_overlapped, &len, FALSE)) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error getting read result from %s %s: %s", device_info,
|
||||
device, strerror(errno));
|
||||
|
||||
if(GetLastError() != ERROR_IO_INCOMPLETE) {
|
||||
/* Must reset event or it will keep firing. */
|
||||
ResetEvent(device_read_overlapped.hEvent);
|
||||
}
|
||||
|
||||
return;
|
||||
EnterCriticalSection(&mutex);
|
||||
route(myself, &packet);
|
||||
LeaveCriticalSection(&mutex);
|
||||
}
|
||||
|
||||
device_read_packet.len = len;
|
||||
device_read_packet.priority = 0;
|
||||
route(myself, &device_read_packet);
|
||||
device_issue_read();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool setup_device(void) {
|
||||
|
|
@ -100,22 +107,24 @@ static bool setup_device(void) {
|
|||
char adaptername[1024];
|
||||
char tapname[1024];
|
||||
DWORD len;
|
||||
unsigned long status;
|
||||
|
||||
bool found = false;
|
||||
|
||||
int err;
|
||||
HANDLE thread;
|
||||
|
||||
get_config_string(lookup_config(config_tree, "Device"), &device);
|
||||
get_config_string(lookup_config(config_tree, "Interface"), &iface);
|
||||
|
||||
if(device && iface) {
|
||||
logger(DEBUG_ALWAYS, LOG_WARNING, "Warning: both Device and Interface specified, results may not be as expected");
|
||||
logger(LOG_WARNING, "Warning: both Device and Interface specified, results may not be as expected");
|
||||
}
|
||||
|
||||
/* Open registry and look for network adapters */
|
||||
|
||||
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, NETWORK_CONNECTIONS_KEY, 0, KEY_READ, &key)) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unable to read registry: %s", winerror(GetLastError()));
|
||||
logger(LOG_ERR, "Unable to read registry: %s", winerror(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -173,7 +182,7 @@ static bool setup_device(void) {
|
|||
RegCloseKey(key);
|
||||
|
||||
if(!found) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "No Windows tap device found!");
|
||||
logger(LOG_ERR, "No Windows tap device found!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -193,34 +202,14 @@ static bool setup_device(void) {
|
|||
}
|
||||
|
||||
if(device_handle == INVALID_HANDLE_VALUE) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "%s (%s) is not a usable Windows tap device: %s", device, iface, winerror(GetLastError()));
|
||||
logger(LOG_ERR, "%s (%s) is not a usable Windows tap device: %s", device, iface, winerror(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Get version information from tap device */
|
||||
|
||||
{
|
||||
ULONG info[3] = {0};
|
||||
DWORD len;
|
||||
|
||||
if(!DeviceIoControl(device_handle, TAP_IOCTL_GET_VERSION, &info, sizeof(info), &info, sizeof(info), &len, NULL)) {
|
||||
logger(DEBUG_ALWAYS, LOG_WARNING, "Could not get version information from Windows tap device %s (%s): %s", device, iface, winerror(GetLastError()));
|
||||
} else {
|
||||
logger(DEBUG_ALWAYS, LOG_INFO, "TAP-Windows driver version: %lu.%lu%s", info[0], info[1], info[2] ? " (DEBUG)" : "");
|
||||
|
||||
/* Warn if using >=9.21. This is because starting from 9.21, TAP-Win32 seems to use a different, less efficient write path. */
|
||||
if(info[0] == 9 && info[1] >= 21)
|
||||
logger(DEBUG_ALWAYS, LOG_WARNING,
|
||||
"You are using the newer (>= 9.0.0.21, NDIS6) series of TAP-Win32 drivers. "
|
||||
"Using these drivers with tinc is not recommended as it can result in poor performance. "
|
||||
"You might want to revert back to 9.0.0.9 instead.");
|
||||
}
|
||||
}
|
||||
|
||||
/* Get MAC address from tap device */
|
||||
|
||||
if(!DeviceIoControl(device_handle, TAP_IOCTL_GET_MAC, mymac.x, sizeof(mymac.x), mymac.x, sizeof(mymac.x), &len, 0)) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not get MAC address from Windows tap device %s (%s): %s", device, iface, winerror(GetLastError()));
|
||||
logger(LOG_ERR, "Could not get MAC address from Windows tap device %s (%s): %s", device, iface, winerror(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -228,75 +217,35 @@ static bool setup_device(void) {
|
|||
overwrite_mac = 1;
|
||||
}
|
||||
|
||||
device_info = "Windows tap device";
|
||||
/* Create overlapped events for tap I/O */
|
||||
|
||||
logger(DEBUG_ALWAYS, LOG_INFO, "%s (%s) is a %s", device, iface, device_info);
|
||||
r_overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
w_overlapped.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
|
||||
|
||||
device_read_overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
device_write_overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
/* Start the tap reader */
|
||||
|
||||
thread = CreateThread(NULL, 0, tapreader, NULL, 0, NULL);
|
||||
|
||||
if(!thread) {
|
||||
logger(LOG_ERR, "System call `%s' failed: %s", "CreateThread", winerror(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Set media status for newer TAP-Win32 devices */
|
||||
|
||||
status = true;
|
||||
DeviceIoControl(device_handle, TAP_IOCTL_SET_MEDIA_STATUS, &status, sizeof(status), &status, sizeof(status), &len, NULL);
|
||||
|
||||
logger(LOG_INFO, "%s (%s) is a %s", device, iface, device_info);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void enable_device(void) {
|
||||
logger(DEBUG_ALWAYS, LOG_INFO, "Enabling %s", device_info);
|
||||
|
||||
ULONG status = 1;
|
||||
DWORD len;
|
||||
DeviceIoControl(device_handle, TAP_IOCTL_SET_MEDIA_STATUS, &status, sizeof(status), &status, sizeof(status), &len, NULL);
|
||||
|
||||
/* We don't use the write event directly, but GetOverlappedResult() does, internally. */
|
||||
|
||||
io_add_event(&device_read_io, device_handle_read, NULL, device_read_overlapped.hEvent);
|
||||
device_issue_read();
|
||||
}
|
||||
|
||||
static void disable_device(void) {
|
||||
logger(DEBUG_ALWAYS, LOG_INFO, "Disabling %s", device_info);
|
||||
|
||||
io_del(&device_read_io);
|
||||
|
||||
ULONG status = 0;
|
||||
DWORD len;
|
||||
DeviceIoControl(device_handle, TAP_IOCTL_SET_MEDIA_STATUS, &status, sizeof(status), &status, sizeof(status), &len, NULL);
|
||||
|
||||
/* Note that we don't try to cancel ongoing I/O here - we just stop listening.
|
||||
This is because some TAP-Win32 drivers don't seem to handle cancellation very well,
|
||||
especially when combined with other events such as the computer going to sleep - cases
|
||||
were observed where the GetOverlappedResult() would just block indefinitely and never
|
||||
return in that case. */
|
||||
}
|
||||
|
||||
static void close_device(void) {
|
||||
CancelIo(device_handle);
|
||||
|
||||
/* According to MSDN, CancelIo() does not necessarily wait for the operation to complete.
|
||||
To prevent race conditions, make sure the operation is complete
|
||||
before we close the event it's referencing. */
|
||||
|
||||
DWORD len;
|
||||
|
||||
if(!GetOverlappedResult(device_handle, &device_read_overlapped, &len, TRUE) && GetLastError() != ERROR_OPERATION_ABORTED) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not wait for %s %s read to cancel: %s", device_info, device, winerror(GetLastError()));
|
||||
}
|
||||
|
||||
if(device_write_packet.len > 0 && !GetOverlappedResult(device_handle, &device_write_overlapped, &len, TRUE) && GetLastError() != ERROR_OPERATION_ABORTED) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not wait for %s %s write to cancel: %s", device_info, device, winerror(GetLastError()));
|
||||
}
|
||||
|
||||
device_write_packet.len = 0;
|
||||
|
||||
CloseHandle(device_read_overlapped.hEvent);
|
||||
CloseHandle(device_write_overlapped.hEvent);
|
||||
|
||||
CloseHandle(device_handle);
|
||||
device_handle = INVALID_HANDLE_VALUE;
|
||||
|
||||
free(device);
|
||||
device = NULL;
|
||||
free(iface);
|
||||
iface = NULL;
|
||||
device_info = NULL;
|
||||
}
|
||||
|
||||
static bool read_packet(vpn_packet_t *packet) {
|
||||
|
|
@ -304,50 +253,70 @@ static bool read_packet(vpn_packet_t *packet) {
|
|||
}
|
||||
|
||||
static bool write_packet(vpn_packet_t *packet) {
|
||||
DWORD outlen;
|
||||
DWORD lenout;
|
||||
static vpn_packet_t queue;
|
||||
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Writing packet of %d bytes to %s",
|
||||
packet->len, device_info);
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
|
||||
packet->len, device_info);
|
||||
|
||||
if(device_write_packet.len > 0) {
|
||||
/* Make sure the previous write operation is finished before we start the next one;
|
||||
otherwise we end up with multiple write ops referencing the same OVERLAPPED structure,
|
||||
which according to MSDN is a no-no. */
|
||||
/* Check if there is something in progress */
|
||||
|
||||
if(!GetOverlappedResult(device_handle, &device_write_overlapped, &outlen, FALSE)) {
|
||||
if(GetLastError() != ERROR_IO_INCOMPLETE) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error completing previously queued write to %s %s: %s", device_info, device, winerror(GetLastError()));
|
||||
if(queue.len) {
|
||||
DWORD size;
|
||||
BOOL success = GetOverlappedResult(device_handle, &w_overlapped, &size, FALSE);
|
||||
|
||||
if(success) {
|
||||
ResetEvent(&w_overlapped);
|
||||
queue.len = 0;
|
||||
} else {
|
||||
int err = GetLastError();
|
||||
|
||||
if(err != ERROR_IO_INCOMPLETE) {
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Error completing previously queued write: %s", winerror(err));
|
||||
ResetEvent(&w_overlapped);
|
||||
queue.len = 0;
|
||||
} else {
|
||||
logger(DEBUG_TRAFFIC, LOG_ERR, "Previous overlapped write to %s %s still in progress", device_info, device);
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Previous overlapped write still in progress");
|
||||
// drop this packet
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy the packet, since the write operation might still be ongoing after we return. */
|
||||
/* Otherwise, try to write. */
|
||||
|
||||
memcpy(&device_write_packet, packet, sizeof(*packet));
|
||||
memcpy(queue.data, packet->data, packet->len);
|
||||
|
||||
ResetEvent(device_write_overlapped.hEvent);
|
||||
if(!WriteFile(device_handle, queue.data, packet->len, &lenout, &w_overlapped)) {
|
||||
int err = GetLastError();
|
||||
|
||||
if(WriteFile(device_handle, DATA(&device_write_packet), device_write_packet.len, &outlen, &device_write_overlapped)) {
|
||||
if(err != ERROR_IO_PENDING) {
|
||||
logger(LOG_ERR, "Error while writing to %s %s: %s", device_info, device, winerror(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write is being done asynchronously.
|
||||
queue.len = packet->len;
|
||||
} else {
|
||||
// Write was completed immediately.
|
||||
device_write_packet.len = 0;
|
||||
} else if(GetLastError() != ERROR_IO_PENDING) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while writing to %s %s: %s", device_info, device, winerror(GetLastError()));
|
||||
device_write_packet.len = 0;
|
||||
return false;
|
||||
ResetEvent(&w_overlapped);
|
||||
}
|
||||
|
||||
device_total_out += packet->len;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void dump_device_stats(void) {
|
||||
logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
|
||||
logger(LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in);
|
||||
logger(LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
|
||||
}
|
||||
|
||||
const devops_t os_devops = {
|
||||
.setup = setup_device,
|
||||
.close = close_device,
|
||||
.read = read_packet,
|
||||
.write = write_packet,
|
||||
.enable = enable_device,
|
||||
.disable = disable_device,
|
||||
.dump_stats = dump_device_stats,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
device.c -- multicast socket
|
||||
Copyright (C) 2002-2005 Ivo Timmermans,
|
||||
2002-2013 Guus Sliepen <guus@tinc-vpn.org>
|
||||
2002-2014 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
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
|
||||
|
|
@ -31,11 +31,14 @@
|
|||
|
||||
static const char *device_info = "multicast socket";
|
||||
|
||||
static uint64_t device_total_in = 0;
|
||||
static uint64_t device_total_out = 0;
|
||||
|
||||
static struct addrinfo *ai = NULL;
|
||||
static mac_t ignore_src = {0};
|
||||
static mac_t ignore_src = {{0}};
|
||||
|
||||
static bool setup_device(void) {
|
||||
char *host = NULL;
|
||||
char *host;
|
||||
char *port;
|
||||
char *space;
|
||||
int ttl = 1;
|
||||
|
|
@ -43,16 +46,17 @@ static bool setup_device(void) {
|
|||
get_config_string(lookup_config(config_tree, "Interface"), &iface);
|
||||
|
||||
if(!get_config_string(lookup_config(config_tree, "Device"), &device)) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Device variable required for %s", device_info);
|
||||
goto error;
|
||||
logger(LOG_ERR, "Device variable required for %s", device_info);
|
||||
return false;
|
||||
}
|
||||
|
||||
host = xstrdup(device);
|
||||
space = strchr(host, ' ');
|
||||
|
||||
if(!space) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Port number required for %s", device_info);
|
||||
goto error;
|
||||
logger(LOG_ERR, "Port number required for %s", device_info);
|
||||
free(host);
|
||||
return false;
|
||||
}
|
||||
|
||||
*space++ = 0;
|
||||
|
|
@ -67,14 +71,16 @@ static bool setup_device(void) {
|
|||
ai = str2addrinfo(host, port, SOCK_DGRAM);
|
||||
|
||||
if(!ai) {
|
||||
goto error;
|
||||
free(host);
|
||||
return false;
|
||||
}
|
||||
|
||||
device_fd = socket(ai->ai_family, SOCK_DGRAM, IPPROTO_UDP);
|
||||
|
||||
if(device_fd < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Creating socket failed: %s", sockstrerror(sockerrno));
|
||||
goto error;
|
||||
logger(LOG_ERR, "Creating socket failed: %s", sockstrerror(sockerrno));
|
||||
free(host);
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef FD_CLOEXEC
|
||||
|
|
@ -85,8 +91,10 @@ static bool setup_device(void) {
|
|||
setsockopt(device_fd, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(one));
|
||||
|
||||
if(bind(device_fd, ai->ai_addr, ai->ai_addrlen)) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Can't bind to %s %s: %s", host, port, sockstrerror(sockerrno));
|
||||
goto error;
|
||||
closesocket(device_fd);
|
||||
logger(LOG_ERR, "Can't bind to %s %s: %s", host, port, sockstrerror(sockerrno));
|
||||
free(host);
|
||||
return false;
|
||||
}
|
||||
|
||||
switch(ai->ai_family) {
|
||||
|
|
@ -100,8 +108,10 @@ static bool setup_device(void) {
|
|||
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
|
||||
|
||||
if(setsockopt(device_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&mreq, sizeof(mreq))) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Cannot join multicast group %s %s: %s", host, port, sockstrerror(sockerrno));
|
||||
goto error;
|
||||
logger(LOG_ERR, "Cannot join multicast group %s %s: %s", host, port, sockstrerror(sockerrno));
|
||||
closesocket(device_fd);
|
||||
free(host);
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef IP_MULTICAST_LOOP
|
||||
|
|
@ -124,8 +134,10 @@ static bool setup_device(void) {
|
|||
mreq.ipv6mr_interface = in6.sin6_scope_id;
|
||||
|
||||
if(setsockopt(device_fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, (void *)&mreq, sizeof(mreq))) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Cannot join multicast group %s %s: %s", host, port, sockstrerror(sockerrno));
|
||||
goto error;
|
||||
logger(LOG_ERR, "Cannot join multicast group %s %s: %s", host, port, sockstrerror(sockerrno));
|
||||
closesocket(device_fd);
|
||||
free(host);
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef IPV6_MULTICAST_LOOP
|
||||
|
|
@ -139,86 +151,97 @@ static bool setup_device(void) {
|
|||
#endif
|
||||
|
||||
default:
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Multicast for address family %x unsupported", ai->ai_family);
|
||||
goto error;
|
||||
}
|
||||
|
||||
logger(DEBUG_ALWAYS, LOG_INFO, "%s is a %s", device, device_info);
|
||||
|
||||
return true;
|
||||
|
||||
error:
|
||||
|
||||
if(device_fd >= 0) {
|
||||
logger(LOG_ERR, "Multicast for address family %x unsupported", ai->ai_family);
|
||||
closesocket(device_fd);
|
||||
}
|
||||
|
||||
if(ai) {
|
||||
freeaddrinfo(ai);
|
||||
free(host);
|
||||
return false;
|
||||
}
|
||||
|
||||
free(host);
|
||||
logger(LOG_INFO, "%s is a %s", device, device_info);
|
||||
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void close_device(void) {
|
||||
close(device_fd);
|
||||
device_fd = -1;
|
||||
|
||||
free(device);
|
||||
device = NULL;
|
||||
free(iface);
|
||||
iface = NULL;
|
||||
|
||||
if(ai) {
|
||||
freeaddrinfo(ai);
|
||||
ai = NULL;
|
||||
}
|
||||
|
||||
device_info = NULL;
|
||||
}
|
||||
|
||||
static bool read_packet(vpn_packet_t *packet) {
|
||||
int lenin;
|
||||
|
||||
if((lenin = recv(device_fd, (void *)DATA(packet), MTU, 0)) <= 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
||||
device, sockstrerror(sockerrno));
|
||||
if((lenin = recv(device_fd, (void *)packet->data, MTU, 0)) <= 0) {
|
||||
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info,
|
||||
device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!memcmp(&ignore_src, DATA(packet) + 6, sizeof(ignore_src))) {
|
||||
logger(DEBUG_SCARY_THINGS, LOG_DEBUG, "Ignoring loopback packet of %d bytes from %s", lenin, device_info);
|
||||
return false;
|
||||
if(!memcmp(&ignore_src, packet->data + 6, sizeof(ignore_src))) {
|
||||
ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Ignoring loopback packet of %d bytes from %s", lenin, device_info);
|
||||
packet->len = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
packet->len = lenin;
|
||||
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Read packet of %d bytes from %s", packet->len,
|
||||
device_info);
|
||||
device_total_in += packet->len;
|
||||
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Read packet of %d bytes from %s", packet->len,
|
||||
device_info);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool write_packet(vpn_packet_t *packet) {
|
||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Writing packet of %d bytes to %s",
|
||||
packet->len, device_info);
|
||||
ifdebug(TRAFFIC) logger(LOG_DEBUG, "Writing packet of %d bytes to %s",
|
||||
packet->len, device_info);
|
||||
|
||||
if(sendto(device_fd, (void *)DATA(packet), packet->len, 0, ai->ai_addr, ai->ai_addrlen) < 0) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Can't write to %s %s: %s", device_info, device,
|
||||
sockstrerror(sockerrno));
|
||||
if(sendto(device_fd, (void *)packet->data, packet->len, 0, ai->ai_addr, ai->ai_addrlen) < 0) {
|
||||
logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device,
|
||||
strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(&ignore_src, DATA(packet) + 6, sizeof(ignore_src));
|
||||
device_total_out += packet->len;
|
||||
|
||||
memcpy(&ignore_src, packet->data + 6, sizeof(ignore_src));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void dump_device_stats(void) {
|
||||
logger(LOG_DEBUG, "Statistics for %s %s:", device_info, device);
|
||||
logger(LOG_DEBUG, " total bytes in: %10"PRIu64, device_total_in);
|
||||
logger(LOG_DEBUG, " total bytes out: %10"PRIu64, device_total_out);
|
||||
}
|
||||
|
||||
const devops_t multicast_devops = {
|
||||
.setup = setup_device,
|
||||
.close = close_device,
|
||||
.read = read_packet,
|
||||
.write = write_packet,
|
||||
.dump_stats = dump_device_stats,
|
||||
};
|
||||
|
||||
#if 0
|
||||
|
||||
static bool not_supported(void) {
|
||||
logger(LOG_ERR, "Raw socket device not supported on this platform");
|
||||
return false;
|
||||
}
|
||||
|
||||
const devops_t multicast_devops = {
|
||||
.setup = not_supported,
|
||||
.close = NULL,
|
||||
.read = NULL,
|
||||
.write = NULL,
|
||||
.dump_stats = NULL,
|
||||
};
|
||||
#endif
|
||||
|
|
|
|||
180
src/names.c
180
src/names.c
|
|
@ -1,180 +0,0 @@
|
|||
/*
|
||||
names.c -- generate commonly used (file)names
|
||||
Copyright (C) 1998-2005 Ivo Timmermans
|
||||
2000-2017 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "system.h"
|
||||
|
||||
#include "logger.h"
|
||||
#include "names.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
char *netname = NULL;
|
||||
char *myname = NULL;
|
||||
char *confdir = NULL; /* base configuration directory */
|
||||
char *confbase = NULL; /* base configuration directory for this instance of tinc */
|
||||
bool confbase_given;
|
||||
char *identname = NULL; /* program name for syslog */
|
||||
char *unixsocketname = NULL; /* UNIX socket location */
|
||||
char *logfilename = NULL; /* log file location */
|
||||
char *pidfilename = NULL;
|
||||
char *program_name = NULL;
|
||||
|
||||
/*
|
||||
Set all files and paths according to netname
|
||||
*/
|
||||
void make_names(bool daemon) {
|
||||
#ifdef HAVE_MINGW
|
||||
HKEY key;
|
||||
char installdir[1024] = "";
|
||||
DWORD len = sizeof(installdir);
|
||||
#endif
|
||||
confbase_given = confbase;
|
||||
|
||||
if(netname && confbase) {
|
||||
logger(DEBUG_ALWAYS, LOG_INFO, "Both netname and configuration directory given, using the latter...");
|
||||
}
|
||||
|
||||
if(netname) {
|
||||
xasprintf(&identname, "tinc.%s", netname);
|
||||
} else {
|
||||
identname = xstrdup("tinc");
|
||||
}
|
||||
|
||||
#ifdef HAVE_MINGW
|
||||
|
||||
if(!RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\tinc", 0, KEY_READ, &key)) {
|
||||
if(!RegQueryValueEx(key, NULL, 0, 0, (LPBYTE)installdir, &len)) {
|
||||
confdir = xstrdup(installdir);
|
||||
|
||||
if(!confbase) {
|
||||
if(netname) {
|
||||
xasprintf(&confbase, "%s" SLASH "%s", installdir, netname);
|
||||
} else {
|
||||
xasprintf(&confbase, "%s", installdir);
|
||||
}
|
||||
}
|
||||
|
||||
if(!logfilename) {
|
||||
xasprintf(&logfilename, "%s" SLASH "tinc.log", confbase);
|
||||
}
|
||||
}
|
||||
|
||||
RegCloseKey(key);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if(!confdir) {
|
||||
confdir = xstrdup(CONFDIR SLASH "tinc");
|
||||
}
|
||||
|
||||
if(!confbase) {
|
||||
if(netname) {
|
||||
xasprintf(&confbase, CONFDIR SLASH "tinc" SLASH "%s", netname);
|
||||
} else {
|
||||
xasprintf(&confbase, CONFDIR SLASH "tinc");
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_MINGW
|
||||
|
||||
if(!logfilename) {
|
||||
xasprintf(&logfilename, "%s" SLASH "log", confbase);
|
||||
}
|
||||
|
||||
if(!pidfilename) {
|
||||
xasprintf(&pidfilename, "%s" SLASH "pid", confbase);
|
||||
}
|
||||
|
||||
#else
|
||||
bool fallback = false;
|
||||
|
||||
if(daemon) {
|
||||
if(access(LOCALSTATEDIR, R_OK | W_OK | X_OK)) {
|
||||
fallback = true;
|
||||
}
|
||||
} else {
|
||||
char fname[PATH_MAX];
|
||||
snprintf(fname, sizeof(fname), LOCALSTATEDIR SLASH "run" SLASH "%s.pid", identname);
|
||||
|
||||
if(access(fname, R_OK)) {
|
||||
snprintf(fname, sizeof(fname), "%s" SLASH "pid", confbase);
|
||||
|
||||
if(!access(fname, R_OK)) {
|
||||
fallback = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!fallback) {
|
||||
if(!logfilename) {
|
||||
xasprintf(&logfilename, LOCALSTATEDIR SLASH "log" SLASH "%s.log", identname);
|
||||
}
|
||||
|
||||
if(!pidfilename) {
|
||||
xasprintf(&pidfilename, LOCALSTATEDIR SLASH "run" SLASH "%s.pid", identname);
|
||||
}
|
||||
} else {
|
||||
if(!logfilename) {
|
||||
xasprintf(&logfilename, "%s" SLASH "log", confbase);
|
||||
}
|
||||
|
||||
if(!pidfilename) {
|
||||
if(daemon) {
|
||||
logger(DEBUG_ALWAYS, LOG_WARNING, "Could not access " LOCALSTATEDIR SLASH " (%s), storing pid and socket files in %s" SLASH, strerror(errno), confbase);
|
||||
}
|
||||
|
||||
xasprintf(&pidfilename, "%s" SLASH "pid", confbase);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if(!unixsocketname) {
|
||||
int len = strlen(pidfilename);
|
||||
unixsocketname = xmalloc(len + 8);
|
||||
memcpy(unixsocketname, pidfilename, len);
|
||||
|
||||
if(len > 4 && !strcmp(pidfilename + len - 4, ".pid")) {
|
||||
strncpy(unixsocketname + len - 4, ".socket", 8);
|
||||
} else {
|
||||
strncpy(unixsocketname + len, ".socket", 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void free_names(void) {
|
||||
free(identname);
|
||||
free(netname);
|
||||
free(unixsocketname);
|
||||
free(pidfilename);
|
||||
free(logfilename);
|
||||
free(confbase);
|
||||
free(confdir);
|
||||
free(myname);
|
||||
|
||||
identname = NULL;
|
||||
netname = NULL;
|
||||
unixsocketname = NULL;
|
||||
pidfilename = NULL;
|
||||
logfilename = NULL;
|
||||
confbase = NULL;
|
||||
confdir = NULL;
|
||||
myname = NULL;
|
||||
}
|
||||
38
src/names.h
38
src/names.h
|
|
@ -1,38 +0,0 @@
|
|||
#ifndef TINC_NAMES_H
|
||||
#define TINC_NAMES_H
|
||||
|
||||
/*
|
||||
names.h -- header for names.c
|
||||
Copyright (C) 1998-2005 Ivo Timmermans
|
||||
2000-2017 Guus Sliepen <guus@tinc-vpn.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
extern char *confdir;
|
||||
extern char *confbase;
|
||||
extern bool confbase_given;
|
||||
extern char *netname;
|
||||
extern char *myname;
|
||||
extern char *identname;
|
||||
extern char *unixsocketname;
|
||||
extern char *logfilename;
|
||||
extern char *pidfilename;
|
||||
extern char *program_name;
|
||||
|
||||
extern void make_names(bool daemon);
|
||||
extern void free_names(void);
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue