Import Upstream version 1.1~pre14-16-g15b868e
This commit is contained in:
parent
aa10d88732
commit
87cef22421
41 changed files with 783 additions and 256 deletions
|
|
@ -196,8 +196,11 @@ sbin_PROGRAMS = tincd$(EXEEXT) tinc$(EXEEXT) sptps_test$(EXEEXT) \
|
|||
subdir = src
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/m4/attribute.m4 \
|
||||
$(top_srcdir)/m4/ax_append_flag.m4 \
|
||||
$(top_srcdir)/m4/ax_cflags_warn_all.m4 \
|
||||
$(top_srcdir)/m4/ax_check_compile_flag.m4 \
|
||||
$(top_srcdir)/m4/ax_check_link_flag.m4 \
|
||||
$(top_srcdir)/m4/ax_require_defined.m4 \
|
||||
$(top_srcdir)/m4/curses.m4 $(top_srcdir)/m4/libgcrypt.m4 \
|
||||
$(top_srcdir)/m4/lzo.m4 $(top_srcdir)/m4/miniupnpc.m4 \
|
||||
$(top_srcdir)/m4/openssl.m4 $(top_srcdir)/m4/readline.m4 \
|
||||
|
|
|
|||
|
|
@ -349,13 +349,13 @@ static bool read_packet(vpn_packet_t *packet) {
|
|||
|
||||
case DEVICE_TYPE_UTUN:
|
||||
case DEVICE_TYPE_TUNIFHEAD: {
|
||||
if((inlen = read(device_fd, packet->data + 10, MTU - 10)) <= 0) {
|
||||
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,
|
||||
device, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (packet->data[14] >> 4) {
|
||||
switch (DATA(packet)[14] >> 4) {
|
||||
case 4:
|
||||
DATA(packet)[12] = 0x08;
|
||||
DATA(packet)[13] = 0x00;
|
||||
|
|
@ -369,7 +369,7 @@ static bool read_packet(vpn_packet_t *packet) {
|
|||
default:
|
||||
logger(DEBUG_TRAFFIC, LOG_ERR,
|
||||
"Unknown IP version %d while reading packet from %s %s",
|
||||
packet->data[14] >> 4, device_info, device);
|
||||
DATA(packet)[14] >> 4, device_info, device);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -430,9 +430,9 @@ static bool write_packet(vpn_packet_t *packet) {
|
|||
return false;
|
||||
}
|
||||
|
||||
memcpy(packet->data + 10, &type, sizeof type);
|
||||
memcpy(DATA(packet) + 10, &type, sizeof type);
|
||||
|
||||
if(write(device_fd, packet->data + 10, packet->len - 10) < 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,
|
||||
strerror(errno));
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ static void tun_error(char *format, ...)
|
|||
{
|
||||
va_list vl;
|
||||
va_start(vl, format);
|
||||
vsnprintf(tunemu_error, ERROR_BUFFER_SIZE, format, vl);
|
||||
vsnprintf(tunemu_error, sizeof tunemu_error, format, vl);
|
||||
va_end(vl);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -106,6 +106,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)
|
||||
|
|
|
|||
|
|
@ -110,20 +110,22 @@ void logger(int level, int priority, const char *format, ...) {
|
|||
|
||||
va_start(ap, format);
|
||||
int len = vsnprintf(message, sizeof message, format, ap);
|
||||
message[sizeof message - 1] = 0;
|
||||
va_end(ap);
|
||||
|
||||
if(len > 0 && len < sizeof message && message[len - 1] == '\n')
|
||||
if(len > 0 && 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) {
|
||||
char message[1024] = "";
|
||||
char message[1024];
|
||||
size_t msglen = sizeof message;
|
||||
|
||||
int len = vsnprintf(message, msglen, format, ap);
|
||||
if(len > 0 && len < sizeof message) {
|
||||
message[sizeof message - 1] = 0;
|
||||
if(len > 0 && len < sizeof message - 1) {
|
||||
if(message[len - 1] == '\n')
|
||||
message[--len] = 0;
|
||||
|
||||
|
|
|
|||
147
src/net.c
147
src/net.c
|
|
@ -42,6 +42,7 @@ static int sleeptime = 10;
|
|||
time_t last_config_check = 0;
|
||||
static timeout_t pingtimer;
|
||||
static timeout_t periodictimer;
|
||||
static struct timeval last_periodic_run_time;
|
||||
|
||||
/* Purge edges and subnets of unreachable nodes. Use carefully. */
|
||||
|
||||
|
|
@ -93,29 +94,31 @@ void purge(void) {
|
|||
void terminate_connection(connection_t *c, bool report) {
|
||||
logger(DEBUG_CONNECTIONS, LOG_NOTICE, "Closing connection with %s (%s)", c->name, c->hostname);
|
||||
|
||||
if(c->node && c->node->connection == c)
|
||||
c->node->connection = NULL;
|
||||
if(c->node) {
|
||||
if(c->node->connection == c)
|
||||
c->node->connection = NULL;
|
||||
|
||||
if(c->edge) {
|
||||
if(report && !tunnelserver)
|
||||
send_del_edge(everyone, c->edge);
|
||||
if(c->edge) {
|
||||
if(report && !tunnelserver)
|
||||
send_del_edge(everyone, c->edge);
|
||||
|
||||
edge_del(c->edge);
|
||||
c->edge = NULL;
|
||||
edge_del(c->edge);
|
||||
c->edge = NULL;
|
||||
|
||||
/* Run MST and SSSP algorithms */
|
||||
/* Run MST and SSSP algorithms */
|
||||
|
||||
graph();
|
||||
graph();
|
||||
|
||||
/* If the node is not reachable anymore but we remember it had an edge to us, clean it up */
|
||||
/* If the node is not reachable anymore but we remember it had an edge to us, clean it up */
|
||||
|
||||
if(report && !c->node->status.reachable) {
|
||||
edge_t *e;
|
||||
e = lookup_edge(c->node, myself);
|
||||
if(e) {
|
||||
if(!tunnelserver)
|
||||
send_del_edge(everyone, e);
|
||||
edge_del(e);
|
||||
if(report && !c->node->status.reachable) {
|
||||
edge_t *e;
|
||||
e = lookup_edge(c->node, myself);
|
||||
if(e) {
|
||||
if(!tunnelserver)
|
||||
send_del_edge(everyone, e);
|
||||
edge_del(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -144,30 +147,76 @@ void terminate_connection(connection_t *c, bool report) {
|
|||
and close the connection.
|
||||
*/
|
||||
static void timeout_handler(void *data) {
|
||||
|
||||
bool close_all_connections = false;
|
||||
|
||||
/*
|
||||
timeout_handler will start after 30 seconds from start of tincd
|
||||
hold information about the elapsed time since last time the handler
|
||||
has been run
|
||||
*/
|
||||
long sleep_time = now.tv_sec - last_periodic_run_time.tv_sec;
|
||||
/*
|
||||
It seems that finding sane default value is harder than expected
|
||||
Since we send every second a UDP packet to make holepunching work
|
||||
And default UDP state expire on firewalls is between 15-30 seconds
|
||||
we drop all connections after 60 Seconds - UDPDiscoveryTimeout=30
|
||||
by default
|
||||
*/
|
||||
if (sleep_time > 2 * udp_discovery_timeout) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Awaking from dead after %ld seconds of sleep", sleep_time);
|
||||
/*
|
||||
Do not send any packets to tinc after we wake up.
|
||||
The other node probably closed our connection but we still
|
||||
are holding context information to them. This may happen on
|
||||
laptops or any other hardware which can be suspended for some time.
|
||||
Sending any data to node that wasn't expecting it will produce
|
||||
annoying and misleading errors on the other side about failed signature
|
||||
verification and or about missing sptps context
|
||||
*/
|
||||
close_all_connections = true;
|
||||
}
|
||||
last_periodic_run_time = now;
|
||||
|
||||
for list_each(connection_t, c, connection_list) {
|
||||
// control connections (eg. tinc ctl) do not have any timeout
|
||||
if(c->status.control)
|
||||
continue;
|
||||
|
||||
if(c->last_ping_time + pingtimeout <= now.tv_sec) {
|
||||
if(c->edge) {
|
||||
try_tx(c->node, false);
|
||||
if(c->status.pinged) {
|
||||
logger(DEBUG_CONNECTIONS, LOG_INFO, "%s (%s) didn't respond to PING in %ld seconds", c->name, c->hostname, (long)(now.tv_sec - c->last_ping_time));
|
||||
} else if(c->last_ping_time + pinginterval <= now.tv_sec) {
|
||||
send_ping(c);
|
||||
continue;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if(c->status.connecting)
|
||||
logger(DEBUG_CONNECTIONS, LOG_WARNING, "Timeout while connecting to %s (%s)", c->name, c->hostname);
|
||||
else
|
||||
logger(DEBUG_CONNECTIONS, LOG_WARNING, "Timeout from %s (%s) during authentication", c->name, c->hostname);
|
||||
}
|
||||
if(close_all_connections) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Forcing connection close after sleep time %s (%s)", c->name, c->hostname);
|
||||
terminate_connection(c, c->edge);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Bail out early if we haven't reached the ping timeout for this node yet
|
||||
if(c->last_ping_time + pingtimeout > now.tv_sec)
|
||||
continue;
|
||||
|
||||
// timeout during connection establishing
|
||||
if(!c->edge) {
|
||||
if(c->status.connecting)
|
||||
logger(DEBUG_CONNECTIONS, LOG_WARNING, "Timeout while connecting to %s (%s)", c->name, c->hostname);
|
||||
else
|
||||
logger(DEBUG_CONNECTIONS, LOG_WARNING, "Timeout from %s (%s) during authentication", c->name, c->hostname);
|
||||
|
||||
terminate_connection(c, c->edge);
|
||||
continue;
|
||||
}
|
||||
|
||||
// helps in UDP holepunching
|
||||
try_tx(c->node, false);
|
||||
|
||||
// timeout during ping
|
||||
if(c->status.pinged) {
|
||||
logger(DEBUG_CONNECTIONS, LOG_INFO, "%s (%s) didn't respond to PING in %ld seconds", c->name, c->hostname, (long)now.tv_sec - c->last_ping_time);
|
||||
terminate_connection(c, c->edge);
|
||||
continue;
|
||||
}
|
||||
|
||||
// check whether we need to send a new ping
|
||||
if(c->last_ping_time + pinginterval <= now.tv_sec)
|
||||
send_ping(c);
|
||||
}
|
||||
|
||||
timeout_set(data, &(struct timeval){1, rand() % 100000});
|
||||
|
|
@ -210,19 +259,25 @@ static void periodic_handler(void *data) {
|
|||
and we are not already trying to make one, create an
|
||||
outgoing connection to this node.
|
||||
*/
|
||||
int r = rand() % (node_tree->count - 1);
|
||||
int i = 0;
|
||||
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)
|
||||
goto end;
|
||||
|
||||
int r = rand() % count;
|
||||
|
||||
for splay_each(node_t, n, node_tree) {
|
||||
if(n == myself)
|
||||
if(n == myself || n->connection || !(n->status.has_address || n->status.reachable))
|
||||
continue;
|
||||
|
||||
if(i++ != r)
|
||||
if(r--)
|
||||
continue;
|
||||
|
||||
if(n->connection)
|
||||
break;
|
||||
|
||||
bool found = false;
|
||||
|
||||
for list_each(outgoing_t, outgoing, outgoing_list) {
|
||||
|
|
@ -239,6 +294,7 @@ static void periodic_handler(void *data) {
|
|||
list_insert_tail(outgoing_list, outgoing);
|
||||
setup_outgoing_connection(outgoing);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
} else if(nc > 3) {
|
||||
|
|
@ -287,6 +343,7 @@ static void periodic_handler(void *data) {
|
|||
}
|
||||
}
|
||||
|
||||
end:
|
||||
timeout_set(data, &(struct timeval){5, rand() % 100000});
|
||||
}
|
||||
|
||||
|
|
@ -344,9 +401,14 @@ int reload_configuration(void) {
|
|||
for splay_each(subnet_t, subnet, subnet_tree)
|
||||
if (subnet->owner)
|
||||
subnet->expires = 1;
|
||||
}
|
||||
|
||||
load_all_subnets();
|
||||
for splay_each(node_t, n, node_tree)
|
||||
n->status.has_address = false;
|
||||
|
||||
load_all_nodes();
|
||||
|
||||
if(strictsubnets) {
|
||||
for splay_each(subnet_t, subnet, subnet_tree) {
|
||||
if (!subnet->owner)
|
||||
continue;
|
||||
|
|
@ -444,6 +506,7 @@ void retry(void) {
|
|||
this is where it all happens...
|
||||
*/
|
||||
int main_loop(void) {
|
||||
last_periodic_run_time = now;
|
||||
timeout_add(&pingtimer, timeout_handler, &pingtimer, &(struct timeval){pingtimeout, rand() % 100000});
|
||||
timeout_add(&periodictimer, periodic_handler, &periodictimer, &(struct timeval){0, 0});
|
||||
|
||||
|
|
|
|||
|
|
@ -217,7 +217,6 @@ extern void regenerate_key(void);
|
|||
extern void purge(void);
|
||||
extern void retry(void);
|
||||
extern int reload_configuration(void);
|
||||
extern void load_all_subnets(void);
|
||||
extern void load_all_nodes(void);
|
||||
extern void try_tx(struct node_t *n, bool);
|
||||
|
||||
|
|
|
|||
|
|
@ -355,16 +355,16 @@ static bool receive_udppacket(node_t *n, vpn_packet_t *inpkt) {
|
|||
if(seqno != n->received_seqno + 1) {
|
||||
if(seqno >= n->received_seqno + replaywin * 8) {
|
||||
if(n->farfuture++ < replaywin >> 2) {
|
||||
logger(DEBUG_ALWAYS, LOG_WARNING, "Packet from %s (%s) is %d seqs in the future, dropped (%u)",
|
||||
logger(DEBUG_TRAFFIC, LOG_WARNING, "Packet from %s (%s) is %d seqs in the future, dropped (%u)",
|
||||
n->name, n->hostname, seqno - n->received_seqno - 1, n->farfuture);
|
||||
return false;
|
||||
}
|
||||
logger(DEBUG_ALWAYS, LOG_WARNING, "Lost %d packets from %s (%s)",
|
||||
logger(DEBUG_TRAFFIC, LOG_WARNING, "Lost %d packets from %s (%s)",
|
||||
seqno - n->received_seqno - 1, n->name, n->hostname);
|
||||
memset(n->late, 0, replaywin);
|
||||
} else if (seqno <= n->received_seqno) {
|
||||
if((n->received_seqno >= replaywin * 8 && seqno <= n->received_seqno - replaywin * 8) || !(n->late[(seqno / 8) % replaywin] & (1 << seqno % 8))) {
|
||||
logger(DEBUG_ALWAYS, LOG_WARNING, "Got late or replayed packet from %s (%s), seqno %d, last received %d",
|
||||
logger(DEBUG_TRAFFIC, LOG_WARNING, "Got late or replayed packet from %s (%s), seqno %d, last received %d",
|
||||
n->name, n->hostname, seqno, n->received_seqno);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -436,7 +436,7 @@ void receive_tcppacket(connection_t *c, const char *buffer, int len) {
|
|||
|
||||
bool receive_tcppacket_sptps(connection_t *c, const char *data, int len) {
|
||||
if (len < sizeof(node_id_t) + sizeof(node_id_t)) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Got too short TCP SPTPS packet from %s (%s)", c->name, c->hostname);
|
||||
logger(DEBUG_PROTOCOL, LOG_ERR, "Got too short TCP SPTPS packet from %s (%s)", c->name, c->hostname);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -499,7 +499,7 @@ static void send_sptps_packet(node_t *n, vpn_packet_t *origpkt) {
|
|||
uint8_t type = 0;
|
||||
int offset = 0;
|
||||
|
||||
if(!(DATA(origpkt)[12] | DATA(origpkt)[13])) {
|
||||
if((!(DATA(origpkt)[12] | DATA(origpkt)[13])) && (n->sptps.outstate)) {
|
||||
sptps_send_record(&n->sptps, PKT_PROBE, (char *)DATA(origpkt), origpkt->len);
|
||||
return;
|
||||
}
|
||||
|
|
@ -767,7 +767,7 @@ bool send_sptps_data(node_t *to, node_t *from, int type, const void *data, size_
|
|||
char buf[len + sizeof to->id + sizeof from->id]; char* buf_ptr = buf;
|
||||
memcpy(buf_ptr, &to->id, sizeof to->id); buf_ptr += sizeof to->id;
|
||||
memcpy(buf_ptr, &from->id, sizeof from->id); buf_ptr += sizeof from->id;
|
||||
memcpy(buf_ptr, data, len); buf_ptr += len;
|
||||
memcpy(buf_ptr, data, len);
|
||||
logger(DEBUG_TRAFFIC, LOG_INFO, "Sending packet from %s (%s) to %s (%s) via %s (%s) (TCP)", from->name, from->hostname, to->name, to->hostname, to->nexthop->name, to->nexthop->hostname);
|
||||
return send_sptps_tcppacket(to->nexthop->connection, buf, sizeof buf);
|
||||
}
|
||||
|
|
|
|||
100
src/net_setup.c
100
src/net_setup.c
|
|
@ -324,62 +324,6 @@ void regenerate_key(void) {
|
|||
n->status.validkey_in = false;
|
||||
}
|
||||
|
||||
/*
|
||||
Read Subnets from all host config files
|
||||
*/
|
||||
void load_all_subnets(void) {
|
||||
DIR *dir;
|
||||
struct dirent *ent;
|
||||
char dname[PATH_MAX];
|
||||
|
||||
snprintf(dname, sizeof dname, "%s" SLASH "hosts", confbase);
|
||||
dir = opendir(dname);
|
||||
if(!dir) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not open %s: %s", dname, strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
while((ent = readdir(dir))) {
|
||||
if(!check_id(ent->d_name))
|
||||
continue;
|
||||
|
||||
node_t *n = lookup_node(ent->d_name);
|
||||
#ifdef _DIRENT_HAVE_D_TYPE
|
||||
//if(ent->d_type != DT_REG)
|
||||
// continue;
|
||||
#endif
|
||||
|
||||
splay_tree_t *config_tree;
|
||||
init_configuration(&config_tree);
|
||||
read_config_options(config_tree, ent->d_name);
|
||||
read_host_config(config_tree, ent->d_name);
|
||||
|
||||
if(!n) {
|
||||
n = new_node();
|
||||
n->name = xstrdup(ent->d_name);
|
||||
node_add(n);
|
||||
}
|
||||
|
||||
for(config_t *cfg = lookup_config(config_tree, "Subnet"); cfg; cfg = lookup_config_next(config_tree, cfg)) {
|
||||
subnet_t *s, *s2;
|
||||
|
||||
if(!get_config_subnet(cfg, &s))
|
||||
continue;
|
||||
|
||||
if((s2 = lookup_subnet(n, s))) {
|
||||
s2->expires = -1;
|
||||
free(s);
|
||||
} else {
|
||||
subnet_add(n, s);
|
||||
}
|
||||
}
|
||||
|
||||
exit_configuration(&config_tree);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
void load_all_nodes(void) {
|
||||
DIR *dir;
|
||||
struct dirent *ent;
|
||||
|
|
@ -397,18 +341,43 @@ void load_all_nodes(void) {
|
|||
continue;
|
||||
|
||||
node_t *n = lookup_node(ent->d_name);
|
||||
if(n)
|
||||
continue;
|
||||
|
||||
n = new_node();
|
||||
n->name = xstrdup(ent->d_name);
|
||||
node_add(n);
|
||||
splay_tree_t *config_tree;
|
||||
init_configuration(&config_tree);
|
||||
read_config_options(config_tree, ent->d_name);
|
||||
read_host_config(config_tree, ent->d_name);
|
||||
|
||||
if(!n) {
|
||||
n = new_node();
|
||||
n->name = xstrdup(ent->d_name);
|
||||
node_add(n);
|
||||
}
|
||||
|
||||
if(strictsubnets) {
|
||||
for(config_t *cfg = lookup_config(config_tree, "Subnet"); cfg; cfg = lookup_config_next(config_tree, cfg)) {
|
||||
subnet_t *s, *s2;
|
||||
|
||||
if(!get_config_subnet(cfg, &s))
|
||||
continue;
|
||||
|
||||
if((s2 = lookup_subnet(n, s))) {
|
||||
s2->expires = -1;
|
||||
free(s);
|
||||
} else {
|
||||
subnet_add(n, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(lookup_config(config_tree, "Address"))
|
||||
n->status.has_address = true;
|
||||
|
||||
exit_configuration(&config_tree);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
|
||||
char *get_name(void) {
|
||||
char *name = NULL;
|
||||
char *returned_name;
|
||||
|
|
@ -707,7 +676,7 @@ static bool add_listen_address(char *address, bool bindto) {
|
|||
|
||||
int udp_fd = setup_vpn_in_socket((sockaddr_t *) aip->ai_addr);
|
||||
|
||||
if(tcp_fd < 0) {
|
||||
if(udp_fd < 0) {
|
||||
close(tcp_fd);
|
||||
continue;
|
||||
}
|
||||
|
|
@ -947,10 +916,7 @@ static bool setup_myself(void) {
|
|||
|
||||
graph();
|
||||
|
||||
if(strictsubnets)
|
||||
load_all_subnets();
|
||||
else if(autoconnect)
|
||||
load_all_nodes();
|
||||
load_all_nodes();
|
||||
|
||||
/* Open device */
|
||||
|
||||
|
|
|
|||
|
|
@ -534,6 +534,8 @@ begin:
|
|||
} else if(proxytype == PROXY_EXEC) {
|
||||
result = 0;
|
||||
} else {
|
||||
if(!proxyai)
|
||||
abort();
|
||||
result = connect(c->socket, proxyai->ai_addr, proxyai->ai_addrlen);
|
||||
freeaddrinfo(proxyai);
|
||||
}
|
||||
|
|
|
|||
19
src/netutl.c
19
src/netutl.c
|
|
@ -234,3 +234,22 @@ void sockaddrunmap(sockaddr_t *sa) {
|
|||
sa->in.sin_family = AF_INET;
|
||||
}
|
||||
}
|
||||
|
||||
void sockaddr_setport(sockaddr_t *sa, const char *port) {
|
||||
uint16_t portnum = htons(atoi(port));
|
||||
if(!portnum)
|
||||
return;
|
||||
switch(sa->sa.sa_family) {
|
||||
case AF_INET:
|
||||
sa->in.sin_port = portnum;
|
||||
break;
|
||||
case AF_INET6:
|
||||
sa->in6.sin6_port = portnum;
|
||||
break;
|
||||
case AF_UNKNOWN:
|
||||
free(sa->unknown.port);
|
||||
sa->unknown.port = xstrdup(port);
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,5 +34,6 @@ extern int sockaddrcmp_noport(const sockaddr_t *, const sockaddr_t *);
|
|||
extern void sockaddrunmap(sockaddr_t *);
|
||||
extern void sockaddrfree(sockaddr_t *);
|
||||
extern void sockaddrcpy(sockaddr_t *, const sockaddr_t *);
|
||||
extern void sockaddr_setport(sockaddr_t *, const char *);
|
||||
|
||||
#endif /* __TINC_NETUTL_H__ */
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ typedef struct node_status_t {
|
|||
unsigned int send_locally:1; /* 1 if the next UDP packet should be sent on the local network */
|
||||
unsigned int udppacket:1; /* 1 if the most recently received packet was UDP */
|
||||
unsigned int validkey_in:1; /* 1 if we have sent a valid key to him */
|
||||
unsigned int unused:21;
|
||||
unsigned int has_address:1; /* 1 if we know an external address for this node */
|
||||
unsigned int unused:20;
|
||||
} node_status_t;
|
||||
|
||||
typedef struct node_t {
|
||||
|
|
|
|||
|
|
@ -28,14 +28,16 @@
|
|||
#include "../xalloc.h"
|
||||
|
||||
struct cipher {
|
||||
EVP_CIPHER_CTX ctx;
|
||||
EVP_CIPHER_CTX *ctx;
|
||||
const EVP_CIPHER *cipher;
|
||||
};
|
||||
|
||||
static cipher_t *cipher_open(const EVP_CIPHER *evp_cipher) {
|
||||
cipher_t *cipher = xzalloc(sizeof *cipher);
|
||||
cipher->cipher = evp_cipher;
|
||||
EVP_CIPHER_CTX_init(&cipher->ctx);
|
||||
cipher->ctx = EVP_CIPHER_CTX_new();
|
||||
if(!cipher->ctx)
|
||||
abort();
|
||||
|
||||
return cipher;
|
||||
}
|
||||
|
|
@ -68,7 +70,7 @@ void cipher_close(cipher_t *cipher) {
|
|||
if(!cipher)
|
||||
return;
|
||||
|
||||
EVP_CIPHER_CTX_cleanup(&cipher->ctx);
|
||||
EVP_CIPHER_CTX_free(cipher->ctx);
|
||||
free(cipher);
|
||||
}
|
||||
|
||||
|
|
@ -76,23 +78,23 @@ size_t cipher_keylength(const cipher_t *cipher) {
|
|||
if(!cipher || !cipher->cipher)
|
||||
return 0;
|
||||
|
||||
return cipher->cipher->key_len + cipher->cipher->iv_len;
|
||||
return EVP_CIPHER_key_length(cipher->cipher) + EVP_CIPHER_iv_length(cipher->cipher);
|
||||
}
|
||||
|
||||
size_t cipher_blocksize(const cipher_t *cipher) {
|
||||
if(!cipher || !cipher->cipher)
|
||||
return 1;
|
||||
|
||||
return cipher->cipher->block_size;
|
||||
return EVP_CIPHER_block_size(cipher->cipher);
|
||||
}
|
||||
|
||||
bool cipher_set_key(cipher_t *cipher, void *key, bool encrypt) {
|
||||
bool result;
|
||||
|
||||
if(encrypt)
|
||||
result = EVP_EncryptInit_ex(&cipher->ctx, cipher->cipher, NULL, (unsigned char *)key, (unsigned char *)key + cipher->cipher->key_len);
|
||||
result = EVP_EncryptInit_ex(cipher->ctx, cipher->cipher, NULL, (unsigned char *)key, (unsigned char *)key + EVP_CIPHER_key_length(cipher->cipher));
|
||||
else
|
||||
result = EVP_DecryptInit_ex(&cipher->ctx, cipher->cipher, NULL, (unsigned char *)key, (unsigned char *)key + cipher->cipher->key_len);
|
||||
result = EVP_DecryptInit_ex(cipher->ctx, cipher->cipher, NULL, (unsigned char *)key, (unsigned char *)key + EVP_CIPHER_key_length(cipher->cipher));
|
||||
|
||||
if(result)
|
||||
return true;
|
||||
|
|
@ -105,9 +107,9 @@ bool cipher_set_key_from_rsa(cipher_t *cipher, void *key, size_t len, bool encry
|
|||
bool result;
|
||||
|
||||
if(encrypt)
|
||||
result = EVP_EncryptInit_ex(&cipher->ctx, cipher->cipher, NULL, (unsigned char *)key + len - cipher->cipher->key_len, (unsigned char *)key + len - cipher->cipher->iv_len - cipher->cipher->key_len);
|
||||
result = EVP_EncryptInit_ex(cipher->ctx, cipher->cipher, NULL, (unsigned char *)key + len - EVP_CIPHER_key_length(cipher->cipher), (unsigned char *)key + len - EVP_CIPHER_iv_length(cipher->cipher) - EVP_CIPHER_key_length(cipher->cipher));
|
||||
else
|
||||
result = EVP_DecryptInit_ex(&cipher->ctx, cipher->cipher, NULL, (unsigned char *)key + len - cipher->cipher->key_len, (unsigned char *)key + len - cipher->cipher->iv_len - cipher->cipher->key_len);
|
||||
result = EVP_DecryptInit_ex(cipher->ctx, cipher->cipher, NULL, (unsigned char *)key + len - EVP_CIPHER_key_length(cipher->cipher), (unsigned char *)key + len - EVP_CIPHER_iv_length(cipher->cipher) - EVP_CIPHER_key_length(cipher->cipher));
|
||||
|
||||
if(result)
|
||||
return true;
|
||||
|
|
@ -119,15 +121,15 @@ bool cipher_set_key_from_rsa(cipher_t *cipher, void *key, size_t len, bool encry
|
|||
bool cipher_encrypt(cipher_t *cipher, const void *indata, size_t inlen, void *outdata, size_t *outlen, bool oneshot) {
|
||||
if(oneshot) {
|
||||
int len, pad;
|
||||
if(EVP_EncryptInit_ex(&cipher->ctx, NULL, NULL, NULL, NULL)
|
||||
&& EVP_EncryptUpdate(&cipher->ctx, (unsigned char *)outdata, &len, indata, inlen)
|
||||
&& EVP_EncryptFinal(&cipher->ctx, (unsigned char *)outdata + len, &pad)) {
|
||||
if(EVP_EncryptInit_ex(cipher->ctx, NULL, NULL, NULL, NULL)
|
||||
&& EVP_EncryptUpdate(cipher->ctx, (unsigned char *)outdata, &len, indata, inlen)
|
||||
&& EVP_EncryptFinal(cipher->ctx, (unsigned char *)outdata + len, &pad)) {
|
||||
if(outlen) *outlen = len + pad;
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
int len;
|
||||
if(EVP_EncryptUpdate(&cipher->ctx, outdata, &len, indata, inlen)) {
|
||||
if(EVP_EncryptUpdate(cipher->ctx, outdata, &len, indata, inlen)) {
|
||||
if(outlen) *outlen = len;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -140,15 +142,15 @@ bool cipher_encrypt(cipher_t *cipher, const void *indata, size_t inlen, void *ou
|
|||
bool cipher_decrypt(cipher_t *cipher, const void *indata, size_t inlen, void *outdata, size_t *outlen, bool oneshot) {
|
||||
if(oneshot) {
|
||||
int len, pad;
|
||||
if(EVP_DecryptInit_ex(&cipher->ctx, NULL, NULL, NULL, NULL)
|
||||
&& EVP_DecryptUpdate(&cipher->ctx, (unsigned char *)outdata, &len, indata, inlen)
|
||||
&& EVP_DecryptFinal(&cipher->ctx, (unsigned char *)outdata + len, &pad)) {
|
||||
if(EVP_DecryptInit_ex(cipher->ctx, NULL, NULL, NULL, NULL)
|
||||
&& EVP_DecryptUpdate(cipher->ctx, (unsigned char *)outdata, &len, indata, inlen)
|
||||
&& EVP_DecryptFinal(cipher->ctx, (unsigned char *)outdata + len, &pad)) {
|
||||
if(outlen) *outlen = len + pad;
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
int len;
|
||||
if(EVP_EncryptUpdate(&cipher->ctx, outdata, &len, indata, inlen)) {
|
||||
if(EVP_EncryptUpdate(cipher->ctx, outdata, &len, indata, inlen)) {
|
||||
if(outlen) *outlen = len;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -162,9 +164,9 @@ int cipher_get_nid(const cipher_t *cipher) {
|
|||
if(!cipher || !cipher->cipher)
|
||||
return 0;
|
||||
|
||||
return cipher->cipher->nid;
|
||||
return EVP_CIPHER_nid(cipher->cipher);
|
||||
}
|
||||
|
||||
bool cipher_active(const cipher_t *cipher) {
|
||||
return cipher && cipher->cipher && cipher->cipher->nid != 0;
|
||||
return cipher && cipher->cipher && EVP_CIPHER_nid(cipher->cipher) != 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -93,14 +93,19 @@ bool digest_create(digest_t *digest, const void *indata, size_t inlen, void *out
|
|||
return false;
|
||||
}
|
||||
} else {
|
||||
EVP_MD_CTX ctx;
|
||||
EVP_MD_CTX *ctx = EVP_MD_CTX_create();
|
||||
if(!ctx)
|
||||
abort();
|
||||
|
||||
if(!EVP_DigestInit(&ctx, digest->digest)
|
||||
|| !EVP_DigestUpdate(&ctx, indata, inlen)
|
||||
|| !EVP_DigestFinal(&ctx, tmpdata, NULL)) {
|
||||
if(!EVP_DigestInit(ctx, digest->digest)
|
||||
|| !EVP_DigestUpdate(ctx, indata, inlen)
|
||||
|| !EVP_DigestFinal(ctx, tmpdata, NULL)) {
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Error creating digest: %s", ERR_error_string(ERR_get_error(), NULL));
|
||||
EVP_MD_CTX_destroy(ctx);
|
||||
return false;
|
||||
}
|
||||
|
||||
EVP_MD_CTX_destroy(ctx);
|
||||
}
|
||||
|
||||
memcpy(outdata, tmpdata, digest->maclength);
|
||||
|
|
@ -118,14 +123,14 @@ int digest_get_nid(const digest_t *digest) {
|
|||
if(!digest || !digest->digest)
|
||||
return 0;
|
||||
|
||||
return digest->digest->type;
|
||||
return EVP_MD_type(digest->digest);
|
||||
}
|
||||
|
||||
size_t digest_keylength(const digest_t *digest) {
|
||||
if(!digest || !digest->digest)
|
||||
return 0;
|
||||
|
||||
return digest->digest->md_size;
|
||||
return EVP_MD_size(digest->digest);
|
||||
}
|
||||
|
||||
size_t digest_length(const digest_t *digest) {
|
||||
|
|
@ -136,5 +141,5 @@ size_t digest_length(const digest_t *digest) {
|
|||
}
|
||||
|
||||
bool digest_active(const digest_t *digest) {
|
||||
return digest && digest->digest && digest->digest->type != 0;
|
||||
return digest && digest->digest && EVP_MD_type(digest->digest) != 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,28 +30,51 @@ typedef RSA rsa_t;
|
|||
|
||||
// Set RSA keys
|
||||
|
||||
#ifndef HAVE_RSA_SET0_KEY
|
||||
int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d) {
|
||||
BN_free(r->n); r->n = n;
|
||||
BN_free(r->e); r->e = e;
|
||||
BN_free(r->d); r->d = d;
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
rsa_t *rsa_set_hex_public_key(char *n, char *e) {
|
||||
BIGNUM *bn_n = NULL;
|
||||
BIGNUM *bn_e = NULL;
|
||||
|
||||
if(BN_hex2bn(&bn_n, n) != strlen(n) || BN_hex2bn(&bn_e, e) != strlen(e)) {
|
||||
BN_free(bn_e);
|
||||
BN_free(bn_n);
|
||||
return false;
|
||||
}
|
||||
|
||||
rsa_t *rsa = RSA_new();
|
||||
if(!rsa)
|
||||
return NULL;
|
||||
|
||||
if(BN_hex2bn(&rsa->n, n) != strlen(n) || BN_hex2bn(&rsa->e, e) != strlen(e)) {
|
||||
RSA_free(rsa);
|
||||
return false;
|
||||
}
|
||||
|
||||
RSA_set0_key(rsa, bn_n, bn_e, NULL);
|
||||
|
||||
return rsa;
|
||||
}
|
||||
|
||||
rsa_t *rsa_set_hex_private_key(char *n, char *e, char *d) {
|
||||
BIGNUM *bn_n = NULL;
|
||||
BIGNUM *bn_e = NULL;
|
||||
BIGNUM *bn_d = NULL;
|
||||
|
||||
if(BN_hex2bn(&bn_n, n) != strlen(n) || BN_hex2bn(&bn_e, e) != strlen(e) || BN_hex2bn(&bn_d, d) != strlen(d)) {
|
||||
BN_free(bn_d);
|
||||
BN_free(bn_e);
|
||||
BN_free(bn_n);
|
||||
return false;
|
||||
}
|
||||
|
||||
rsa_t *rsa = RSA_new();
|
||||
if(!rsa)
|
||||
return NULL;
|
||||
|
||||
if(BN_hex2bn(&rsa->n, n) != strlen(n) || BN_hex2bn(&rsa->e, e) != strlen(e) || BN_hex2bn(&rsa->d, d) != strlen(d)) {
|
||||
RSA_free(rsa);
|
||||
return false;
|
||||
}
|
||||
RSA_set0_key(rsa, bn_n, bn_e, bn_d);
|
||||
|
||||
return rsa;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,10 +27,11 @@ typedef RSA rsa_t;
|
|||
|
||||
#include "../logger.h"
|
||||
#include "../rsagen.h"
|
||||
#include "../xalloc.h"
|
||||
|
||||
/* This function prettyprints the key generation process */
|
||||
|
||||
static void indicator(int a, int b, void *p) {
|
||||
static int indicator(int a, int b, BN_GENCB *cb) {
|
||||
switch (a) {
|
||||
case 0:
|
||||
fprintf(stderr, ".");
|
||||
|
|
@ -62,12 +63,45 @@ static void indicator(int a, int b, void *p) {
|
|||
default:
|
||||
fprintf(stderr, "?");
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Generate RSA key
|
||||
|
||||
#ifndef HAVE_BN_GENCB_NEW
|
||||
BN_GENCB *BN_GENCB_new(void) {
|
||||
return xzalloc(sizeof(BN_GENCB));
|
||||
}
|
||||
|
||||
void BN_GENCB_free(BN_GENCB *cb) {
|
||||
free(cb);
|
||||
}
|
||||
#endif
|
||||
|
||||
rsa_t *rsa_generate(size_t bits, unsigned long exponent) {
|
||||
return RSA_generate_key(bits, exponent, indicator, NULL);
|
||||
BIGNUM *bn_e = BN_new();
|
||||
rsa_t *rsa = RSA_new();
|
||||
BN_GENCB *cb = BN_GENCB_new();
|
||||
|
||||
if(!bn_e || !rsa || !cb)
|
||||
abort();
|
||||
|
||||
BN_set_word(bn_e, exponent);
|
||||
BN_GENCB_set(cb, indicator, NULL);
|
||||
|
||||
int result = RSA_generate_key_ex(rsa, bits, bn_e, cb);
|
||||
|
||||
BN_GENCB_free(cb);
|
||||
BN_free(bn_e);
|
||||
|
||||
if(!result) {
|
||||
fprintf(stderr, "Error during key generation!\n");
|
||||
RSA_free(rsa);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return rsa;
|
||||
}
|
||||
|
||||
// Write PEM RSA keys
|
||||
|
|
|
|||
|
|
@ -72,10 +72,11 @@ bool send_request(connection_t *c, const char *format, ...) {
|
|||
input buffer anyway */
|
||||
|
||||
va_start(args, format);
|
||||
len = vsnprintf(request, MAXBUFSIZE, format, args);
|
||||
len = vsnprintf(request, sizeof request, format, args);
|
||||
request[sizeof request - 1] = 0;
|
||||
va_end(args);
|
||||
|
||||
if(len < 0 || len > MAXBUFSIZE - 1) {
|
||||
if(len < 0 || len > sizeof request - 1) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Output buffer overflow while sending request to %s (%s)",
|
||||
c->name, c->hostname);
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -790,7 +790,6 @@ bool ack_h(connection_t *c, const char *request) {
|
|||
return upgrade_h(c, request);
|
||||
|
||||
char hisport[MAX_STRING_SIZE];
|
||||
char *hisaddress;
|
||||
int weight, mtu;
|
||||
uint32_t options;
|
||||
node_t *n;
|
||||
|
|
@ -867,19 +866,14 @@ bool ack_h(connection_t *c, const char *request) {
|
|||
c->edge = new_edge();
|
||||
c->edge->from = myself;
|
||||
c->edge->to = n;
|
||||
sockaddr2str(&c->address, &hisaddress, NULL);
|
||||
c->edge->address = str2sockaddr(hisaddress, hisport);
|
||||
free(hisaddress);
|
||||
sockaddrcpy(&c->edge->address, &c->address);
|
||||
sockaddr_setport(&c->edge->address, hisport);
|
||||
sockaddr_t local_sa;
|
||||
socklen_t local_salen = sizeof local_sa;
|
||||
if (getsockname(c->socket, &local_sa.sa, &local_salen) < 0)
|
||||
logger(DEBUG_ALWAYS, LOG_WARNING, "Could not get local socket address for connection with %s", c->name);
|
||||
else {
|
||||
char *local_address;
|
||||
sockaddr2str(&local_sa, &local_address, NULL);
|
||||
c->edge->local_address = str2sockaddr(local_address, myport);
|
||||
free(local_address);
|
||||
}
|
||||
else
|
||||
sockaddr_setport(&local_sa, myport);
|
||||
c->edge->weight = (weight + c->estimated_weight) / 2;
|
||||
c->edge->connection = c;
|
||||
c->edge->options = c->options;
|
||||
|
|
|
|||
|
|
@ -547,8 +547,6 @@ size_t sptps_receive_data(sptps_t *s, const void *data, size_t len) {
|
|||
memcpy(s->inbuf + s->buflen, data, toread);
|
||||
total_read += toread;
|
||||
s->buflen += toread;
|
||||
len -= toread;
|
||||
data += toread;
|
||||
|
||||
// If we don't have a whole record, exit.
|
||||
if(s->buflen < s->reclen + (s->instate ? 19UL : 3UL))
|
||||
|
|
|
|||
|
|
@ -560,6 +560,7 @@ bool sendline(int fd, char *format, ...) {
|
|||
|
||||
va_start(ap, format);
|
||||
blen = vsnprintf(buffer, sizeof buffer, format, ap);
|
||||
buffer[sizeof buffer - 1] = 0;
|
||||
va_end(ap);
|
||||
|
||||
if(blen < 1 || blen >= sizeof buffer)
|
||||
|
|
@ -718,6 +719,13 @@ bool connect_tincd(bool verbose) {
|
|||
}
|
||||
|
||||
fclose(f);
|
||||
if ((pid == 0) || (kill(pid, 0) && (errno == ESRCH))) {
|
||||
fprintf(stderr, "Could not find tincd running at pid %d\n", pid);
|
||||
/* clean up the stale socket and pid file */
|
||||
unlink(pidfilename);
|
||||
unlink(unixsocketname);
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef HAVE_MINGW
|
||||
struct sockaddr_un sa;
|
||||
|
|
@ -878,7 +886,7 @@ static int cmd_start(int argc, char *argv[]) {
|
|||
|
||||
if(!pid) {
|
||||
close(pfd[0]);
|
||||
char buf[100] = "";
|
||||
char buf[100];
|
||||
snprintf(buf, sizeof buf, "%d", pfd[1]);
|
||||
setenv("TINC_UMBILICAL", buf, true);
|
||||
exit(execvp(c, nargv));
|
||||
|
|
@ -1384,7 +1392,7 @@ static int cmd_pid(int argc, char *argv[]) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
if(!connect_tincd(true) && !pid)
|
||||
if(!connect_tincd(true) || !pid)
|
||||
return 1;
|
||||
|
||||
printf("%d\n", pid);
|
||||
|
|
@ -2513,6 +2521,7 @@ static int cmd_verify(int argc, char *argv[]) {
|
|||
char *newline = memchr(data, '\n', len);
|
||||
if(!newline || (newline - data > MAX_STRING_SIZE - 1)) {
|
||||
fprintf(stderr, "Invalid input\n");
|
||||
free(data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -2525,11 +2534,13 @@ static int cmd_verify(int argc, char *argv[]) {
|
|||
|
||||
if(sscanf(data, "Signature = %s %ld %s", signer, &t, sig) != 3 || strlen(sig) != 86 || !t || !check_id(signer)) {
|
||||
fprintf(stderr, "Invalid input\n");
|
||||
free(data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(node && strcmp(node, signer)) {
|
||||
fprintf(stderr, "Signature is not made by %s\n", node);
|
||||
free(data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -2823,8 +2834,10 @@ static int cmd_shell(int argc, char *argv[]) {
|
|||
if(nargc == argc)
|
||||
continue;
|
||||
|
||||
if(!strcasecmp(nargv[argc], "exit") || !strcasecmp(nargv[argc], "quit"))
|
||||
if(!strcasecmp(nargv[argc], "exit") || !strcasecmp(nargv[argc], "quit")) {
|
||||
free(nargv);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue