Merged new env
This commit is contained in:
commit
557adb0695
31 changed files with 543 additions and 133 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -33,6 +33,9 @@
|
||||||
/src/version_git.h
|
/src/version_git.h
|
||||||
/stamp-h1
|
/stamp-h1
|
||||||
/test-driver
|
/test-driver
|
||||||
|
/test/*.test.*
|
||||||
|
/test/*.log
|
||||||
|
/test/*.trs
|
||||||
Makefile
|
Makefile
|
||||||
Makefile.in
|
Makefile.in
|
||||||
core*
|
core*
|
||||||
|
|
|
@ -234,6 +234,10 @@ Do NOT connect multiple
|
||||||
.Nm tinc
|
.Nm tinc
|
||||||
daemons to the same multicast address, this will very likely cause routing loops.
|
daemons to the same multicast address, this will very likely cause routing loops.
|
||||||
Also note that this can cause decrypted VPN packets to be sent out on a real network if misconfigured.
|
Also note that this can cause decrypted VPN packets to be sent out on a real network if misconfigured.
|
||||||
|
.It fd
|
||||||
|
Use a file descriptor.
|
||||||
|
All packets are read from this interface.
|
||||||
|
Packets received for the local node are written to it.
|
||||||
.It uml Pq not compiled in by default
|
.It uml Pq not compiled in by default
|
||||||
Create a UNIX socket with the filename specified by
|
Create a UNIX socket with the filename specified by
|
||||||
.Va Device ,
|
.Va Device ,
|
||||||
|
|
|
@ -958,6 +958,12 @@ This can be used to connect to UML, QEMU or KVM instances listening on the same
|
||||||
Do NOT connect multiple tinc daemons to the same multicast address, this will very likely cause routing loops.
|
Do NOT connect multiple tinc daemons to the same multicast address, this will very likely cause routing loops.
|
||||||
Also note that this can cause decrypted VPN packets to be sent out on a real network if misconfigured.
|
Also note that this can cause decrypted VPN packets to be sent out on a real network if misconfigured.
|
||||||
|
|
||||||
|
@cindex fd
|
||||||
|
@item fd
|
||||||
|
Use a file descriptor.
|
||||||
|
All packets are read from this interface.
|
||||||
|
Packets received for the local node are written to it.
|
||||||
|
|
||||||
@cindex UML
|
@cindex UML
|
||||||
@item uml (not compiled in by default)
|
@item uml (not compiled in by default)
|
||||||
Create a UNIX socket with the filename specified by
|
Create a UNIX socket with the filename specified by
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
## Produce this file with automake to get Makefile.in
|
## Produce this file with automake to get Makefile.in
|
||||||
|
|
||||||
sbin_PROGRAMS = tincd tinc
|
sbin_PROGRAMS = tincd tinc
|
||||||
|
check_PROGRAMS = sptps_test sptps_keypair
|
||||||
EXTRA_PROGRAMS = sptps_test sptps_keypair
|
EXTRA_PROGRAMS = sptps_test sptps_keypair
|
||||||
|
|
||||||
CLEANFILES = version_git.h
|
CLEANFILES = version_git.h
|
||||||
|
@ -59,6 +60,7 @@ tincd_SOURCES = \
|
||||||
edge.c edge.h \
|
edge.c edge.h \
|
||||||
ethernet.h \
|
ethernet.h \
|
||||||
event.c event.h \
|
event.c event.h \
|
||||||
|
fd_device.c \
|
||||||
graph.c graph.h \
|
graph.c graph.h \
|
||||||
hash.c hash.h \
|
hash.c hash.h \
|
||||||
have.h \
|
have.h \
|
||||||
|
|
|
@ -40,6 +40,7 @@ extern const devops_t os_devops;
|
||||||
extern const devops_t dummy_devops;
|
extern const devops_t dummy_devops;
|
||||||
extern const devops_t raw_socket_devops;
|
extern const devops_t raw_socket_devops;
|
||||||
extern const devops_t multicast_devops;
|
extern const devops_t multicast_devops;
|
||||||
|
extern const devops_t fd_devops;
|
||||||
extern const devops_t uml_devops;
|
extern const devops_t uml_devops;
|
||||||
extern const devops_t vde_devops;
|
extern const devops_t vde_devops;
|
||||||
extern devops_t devops;
|
extern devops_t devops;
|
||||||
|
|
|
@ -25,6 +25,15 @@
|
||||||
#define ETH_ALEN 6
|
#define ETH_ALEN 6
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef ETH_HLEN
|
||||||
|
#define ETH_HLEN 14
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ETHER_TYPE_LEN
|
||||||
|
#define ETHER_TYPE_LEN 2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#ifndef ARPHRD_ETHER
|
#ifndef ARPHRD_ETHER
|
||||||
#define ARPHRD_ETHER 1
|
#define ARPHRD_ETHER 1
|
||||||
#endif
|
#endif
|
||||||
|
@ -45,6 +54,10 @@
|
||||||
#define ETH_P_8021Q 0x8100
|
#define ETH_P_8021Q 0x8100
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef ETH_P_MAX
|
||||||
|
#define ETH_P_MAX 0xFFFF
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef HAVE_STRUCT_ETHER_HEADER
|
#ifndef HAVE_STRUCT_ETHER_HEADER
|
||||||
struct ether_header {
|
struct ether_header {
|
||||||
uint8_t ether_dhost[ETH_ALEN];
|
uint8_t ether_dhost[ETH_ALEN];
|
||||||
|
|
|
@ -366,10 +366,13 @@ bool event_loop(void) {
|
||||||
WSANETWORKEVENTS network_events;
|
WSANETWORKEVENTS network_events;
|
||||||
if (WSAEnumNetworkEvents(io->fd, io->event, &network_events) != 0)
|
if (WSAEnumNetworkEvents(io->fd, io->event, &network_events) != 0)
|
||||||
return false;
|
return false;
|
||||||
if (network_events.lNetworkEvents & WRITE_EVENTS)
|
|
||||||
io->cb(io->data, IO_WRITE);
|
|
||||||
if (network_events.lNetworkEvents & READ_EVENTS)
|
if (network_events.lNetworkEvents & READ_EVENTS)
|
||||||
io->cb(io->data, IO_READ);
|
io->cb(io->data, IO_READ);
|
||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
123
src/fd_device.c
Normal file
123
src/fd_device.c
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
/*
|
||||||
|
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,
|
||||||
|
};
|
23
src/graph.c
23
src/graph.c
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
graph.c -- graph algorithms
|
graph.c -- graph algorithms
|
||||||
Copyright (C) 2001-2013 Guus Sliepen <guus@tinc-vpn.org>,
|
Copyright (C) 2001-2017 Guus Sliepen <guus@tinc-vpn.org>,
|
||||||
2001-2005 Ivo Timmermans
|
2001-2005 Ivo Timmermans
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
@ -268,28 +268,23 @@ static void check_reachability(void) {
|
||||||
char *name;
|
char *name;
|
||||||
char *address;
|
char *address;
|
||||||
char *port;
|
char *port;
|
||||||
char *envp[8] = {NULL};
|
|
||||||
|
|
||||||
xasprintf(&envp[0], "NETNAME=%s", netname ? : "");
|
environment_t env;
|
||||||
xasprintf(&envp[1], "DEVICE=%s", device ? : "");
|
environment_init(&env);
|
||||||
xasprintf(&envp[2], "INTERFACE=%s", iface ? : "");
|
environment_add(&env, "NODE=%s", n->name);
|
||||||
xasprintf(&envp[3], "NODE=%s", n->name);
|
|
||||||
sockaddr2str(&n->address, &address, &port);
|
sockaddr2str(&n->address, &address, &port);
|
||||||
xasprintf(&envp[4], "REMOTEADDRESS=%s", address);
|
environment_add(&env, "REMOTEADDRESS=%s", address);
|
||||||
xasprintf(&envp[5], "REMOTEPORT=%s", port);
|
environment_add(&env, "REMOTEPORT=%s", port);
|
||||||
xasprintf(&envp[6], "NAME=%s", myself->name);
|
|
||||||
|
|
||||||
execute_script(n->status.reachable ? "host-up" : "host-down", envp);
|
execute_script(n->status.reachable ? "host-up" : "host-down", &env);
|
||||||
|
|
||||||
xasprintf(&name, n->status.reachable ? "hosts/%s-up" : "hosts/%s-down", n->name);
|
xasprintf(&name, n->status.reachable ? "hosts/%s-up" : "hosts/%s-down", n->name);
|
||||||
execute_script(name, envp);
|
execute_script(name, &env);
|
||||||
|
|
||||||
free(name);
|
free(name);
|
||||||
free(address);
|
free(address);
|
||||||
free(port);
|
free(port);
|
||||||
|
environment_exit(&env);
|
||||||
for(int i = 0; i < 7; i++)
|
|
||||||
free(envp[i]);
|
|
||||||
|
|
||||||
subnet_update(n, NULL, n->status.reachable);
|
subnet_update(n, NULL, n->status.reachable);
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
invitation.c -- Create and accept invitations
|
invitation.c -- Create and accept invitations
|
||||||
Copyright (C) 2013-2015 Guus Sliepen <guus@tinc-vpn.org>
|
Copyright (C) 2013-2017 Guus Sliepen <guus@tinc-vpn.org>
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
|
@ -239,7 +239,7 @@ int cmd_invite(int argc, char *argv[]) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *myname = get_my_name(true);
|
myname = get_my_name(true);
|
||||||
if(!myname)
|
if(!myname)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
@ -425,15 +425,13 @@ int cmd_invite(int argc, char *argv[]) {
|
||||||
xasprintf(&url, "%s/%s%s", address, hash, cookie);
|
xasprintf(&url, "%s/%s%s", address, hash, cookie);
|
||||||
|
|
||||||
// Call the inviation-created script
|
// Call the inviation-created script
|
||||||
char *envp[6] = {};
|
environment_t env;
|
||||||
xasprintf(&envp[0], "NAME=%s", myname);
|
environment_init(&env);
|
||||||
xasprintf(&envp[1], "NETNAME=%s", netname);
|
environment_add(&env, "NODE=%s", argv[1]);
|
||||||
xasprintf(&envp[2], "NODE=%s", argv[1]);
|
environment_add(&env, "INVITATION_FILE=%s", filename);
|
||||||
xasprintf(&envp[3], "INVITATION_FILE=%s", filename);
|
environment_add(&env, "INVITATION_URL=%s", url);
|
||||||
xasprintf(&envp[4], "INVITATION_URL=%s", url);
|
execute_script("invitation-created", &env);
|
||||||
execute_script("invitation-created", envp);
|
environment_exit(&env);
|
||||||
for(int i = 0; i < 6 && envp[i]; i++)
|
|
||||||
free(envp[i]);
|
|
||||||
|
|
||||||
puts(url);
|
puts(url);
|
||||||
free(url);
|
free(url);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
logger.c -- logging code
|
logger.c -- logging code
|
||||||
Copyright (C) 2004-2015 Guus Sliepen <guus@tinc-vpn.org>
|
Copyright (C) 2004-2017 Guus Sliepen <guus@tinc-vpn.org>
|
||||||
2004-2005 Ivo Timmermans
|
2004-2005 Ivo Timmermans
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
@ -29,7 +29,7 @@
|
||||||
#include "process.h"
|
#include "process.h"
|
||||||
#include "sptps.h"
|
#include "sptps.h"
|
||||||
|
|
||||||
debug_t debug_level = DEBUG_NOTHING;
|
int debug_level = DEBUG_NOTHING;
|
||||||
static logmode_t logmode = LOGMODE_STDERR;
|
static logmode_t logmode = LOGMODE_STDERR;
|
||||||
static pid_t logpid;
|
static pid_t logpid;
|
||||||
static FILE *logfile = NULL;
|
static FILE *logfile = NULL;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
logger.h -- header file for logger.c
|
logger.h -- header file for logger.c
|
||||||
Copyright (C) 1998-2005 Ivo Timmermans
|
Copyright (C) 1998-2005 Ivo Timmermans
|
||||||
2000-2012 Guus Sliepen <guus@tinc-vpn.org>
|
2000-2017 Guus Sliepen <guus@tinc-vpn.org>
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
|
@ -67,7 +67,7 @@ enum {
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
extern debug_t debug_level;
|
extern int debug_level;
|
||||||
extern bool logcontrol;
|
extern bool logcontrol;
|
||||||
extern int umbilical;
|
extern int umbilical;
|
||||||
extern void openlogger(const char *, logmode_t);
|
extern void openlogger(const char *, logmode_t);
|
||||||
|
|
|
@ -214,6 +214,9 @@ static bool setup_device(void) {
|
||||||
|
|
||||||
logger(DEBUG_ALWAYS, LOG_INFO, "%s (%s) is a %s", device, iface, device_info);
|
logger(DEBUG_ALWAYS, LOG_INFO, "%s (%s) is a %s", device, iface, device_info);
|
||||||
|
|
||||||
|
device_read_overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||||
|
device_write_overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,9 +229,6 @@ static void enable_device(void) {
|
||||||
|
|
||||||
/* We don't use the write event directly, but GetOverlappedResult() does, internally. */
|
/* We don't use the write event directly, but GetOverlappedResult() does, internally. */
|
||||||
|
|
||||||
device_read_overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
||||||
device_write_overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
||||||
|
|
||||||
io_add_event(&device_read_io, device_handle_read, NULL, device_read_overlapped.hEvent);
|
io_add_event(&device_read_io, device_handle_read, NULL, device_read_overlapped.hEvent);
|
||||||
device_issue_read();
|
device_issue_read();
|
||||||
}
|
}
|
||||||
|
@ -237,6 +237,19 @@ static void disable_device(void) {
|
||||||
logger(DEBUG_ALWAYS, LOG_INFO, "Disabling %s", device_info);
|
logger(DEBUG_ALWAYS, LOG_INFO, "Disabling %s", device_info);
|
||||||
|
|
||||||
io_del(&device_read_io);
|
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);
|
CancelIo(device_handle);
|
||||||
|
|
||||||
/* According to MSDN, CancelIo() does not necessarily wait for the operation to complete.
|
/* According to MSDN, CancelIo() does not necessarily wait for the operation to complete.
|
||||||
|
@ -253,11 +266,6 @@ static void disable_device(void) {
|
||||||
CloseHandle(device_read_overlapped.hEvent);
|
CloseHandle(device_read_overlapped.hEvent);
|
||||||
CloseHandle(device_write_overlapped.hEvent);
|
CloseHandle(device_write_overlapped.hEvent);
|
||||||
|
|
||||||
ULONG status = 0;
|
|
||||||
DeviceIoControl(device_handle, TAP_IOCTL_SET_MEDIA_STATUS, &status, sizeof status, &status, sizeof status, &len, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void close_device(void) {
|
|
||||||
CloseHandle(device_handle); device_handle = INVALID_HANDLE_VALUE;
|
CloseHandle(device_handle); device_handle = INVALID_HANDLE_VALUE;
|
||||||
|
|
||||||
free(device); device = NULL;
|
free(device); device = NULL;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
names.c -- generate commonly used (file)names
|
names.c -- generate commonly used (file)names
|
||||||
Copyright (C) 1998-2005 Ivo Timmermans
|
Copyright (C) 1998-2005 Ivo Timmermans
|
||||||
2000-2015 Guus Sliepen <guus@tinc-vpn.org>
|
2000-2017 Guus Sliepen <guus@tinc-vpn.org>
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
|
@ -25,6 +25,7 @@
|
||||||
#include "xalloc.h"
|
#include "xalloc.h"
|
||||||
|
|
||||||
char *netname = NULL;
|
char *netname = NULL;
|
||||||
|
char *myname = NULL;
|
||||||
char *confdir = NULL; /* base configuration directory */
|
char *confdir = NULL; /* base configuration directory */
|
||||||
char *confbase = NULL; /* base configuration directory for this instance of tinc */
|
char *confbase = NULL; /* base configuration directory for this instance of tinc */
|
||||||
bool confbase_given;
|
bool confbase_given;
|
||||||
|
@ -137,6 +138,7 @@ void free_names(void) {
|
||||||
free(logfilename);
|
free(logfilename);
|
||||||
free(confbase);
|
free(confbase);
|
||||||
free(confdir);
|
free(confdir);
|
||||||
|
free(myname);
|
||||||
|
|
||||||
identname = NULL;
|
identname = NULL;
|
||||||
netname = NULL;
|
netname = NULL;
|
||||||
|
@ -145,4 +147,5 @@ void free_names(void) {
|
||||||
logfilename = NULL;
|
logfilename = NULL;
|
||||||
confbase = NULL;
|
confbase = NULL;
|
||||||
confdir = NULL;
|
confdir = NULL;
|
||||||
|
myname = NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
names.h -- header for names.c
|
names.h -- header for names.c
|
||||||
Copyright (C) 1998-2005 Ivo Timmermans
|
Copyright (C) 1998-2005 Ivo Timmermans
|
||||||
2000-2015 Guus Sliepen <guus@tinc-vpn.org>
|
2000-2017 Guus Sliepen <guus@tinc-vpn.org>
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
|
@ -25,6 +25,7 @@ extern char *confdir;
|
||||||
extern char *confbase;
|
extern char *confbase;
|
||||||
extern bool confbase_given;
|
extern bool confbase_given;
|
||||||
extern char *netname;
|
extern char *netname;
|
||||||
|
extern char *myname;
|
||||||
extern char *identname;
|
extern char *identname;
|
||||||
extern char *unixsocketname;
|
extern char *unixsocketname;
|
||||||
extern char *logfilename;
|
extern char *logfilename;
|
||||||
|
|
|
@ -127,8 +127,9 @@ typedef struct outgoing_t {
|
||||||
int timeout;
|
int timeout;
|
||||||
splay_tree_t *config_tree;
|
splay_tree_t *config_tree;
|
||||||
struct config_t *cfg;
|
struct config_t *cfg;
|
||||||
struct addrinfo *ai;
|
struct addrinfo *ai; // addresses from config files
|
||||||
struct addrinfo *aip;
|
struct addrinfo *aip;
|
||||||
|
struct addrinfo *kai; // addresses known via other online nodes (use free_known_addresses())
|
||||||
timeout_t ev;
|
timeout_t ev;
|
||||||
} outgoing_t;
|
} outgoing_t;
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
net_setup.c -- Setup.
|
net_setup.c -- Setup.
|
||||||
Copyright (C) 1998-2005 Ivo Timmermans,
|
Copyright (C) 1998-2005 Ivo Timmermans,
|
||||||
2000-2016 Guus Sliepen <guus@tinc-vpn.org>
|
2000-2017 Guus Sliepen <guus@tinc-vpn.org>
|
||||||
2006 Scott Lamb <slamb@slamb.org>
|
2006 Scott Lamb <slamb@slamb.org>
|
||||||
2010 Brandon Black <blblack@gmail.com>
|
2010 Brandon Black <blblack@gmail.com>
|
||||||
|
|
||||||
|
@ -50,7 +50,6 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
char *myport;
|
char *myport;
|
||||||
static char *myname;
|
|
||||||
static io_t device_io;
|
static io_t device_io;
|
||||||
devops_t devops;
|
devops_t devops;
|
||||||
bool device_standby = false;
|
bool device_standby = false;
|
||||||
|
@ -755,29 +754,17 @@ void device_enable(void) {
|
||||||
|
|
||||||
/* Run tinc-up script to further initialize the tap interface */
|
/* Run tinc-up script to further initialize the tap interface */
|
||||||
|
|
||||||
char *envp[5] = {NULL};
|
environment_t env;
|
||||||
xasprintf(&envp[0], "NETNAME=%s", netname ? : "");
|
environment_init(&env);
|
||||||
xasprintf(&envp[1], "DEVICE=%s", device ? : "");
|
execute_script("tinc-up", &env);
|
||||||
xasprintf(&envp[2], "INTERFACE=%s", iface ? : "");
|
environment_exit(&env);
|
||||||
xasprintf(&envp[3], "NAME=%s", myname);
|
|
||||||
|
|
||||||
execute_script("tinc-up", envp);
|
|
||||||
|
|
||||||
for(int i = 0; i < 4; i++)
|
|
||||||
free(envp[i]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void device_disable(void) {
|
void device_disable(void) {
|
||||||
char *envp[5] = {NULL};
|
environment_t env;
|
||||||
xasprintf(&envp[0], "NETNAME=%s", netname ? : "");
|
environment_init(&env);
|
||||||
xasprintf(&envp[1], "DEVICE=%s", device ? : "");
|
execute_script("tinc-down", &env);
|
||||||
xasprintf(&envp[2], "INTERFACE=%s", iface ? : "");
|
environment_exit(&env);
|
||||||
xasprintf(&envp[3], "NAME=%s", myname);
|
|
||||||
|
|
||||||
execute_script("tinc-down", envp);
|
|
||||||
|
|
||||||
for(int i = 0; i < 4; i++)
|
|
||||||
free(envp[i]);
|
|
||||||
|
|
||||||
if (devops.disable)
|
if (devops.disable)
|
||||||
devops.disable();
|
devops.disable();
|
||||||
|
@ -987,6 +974,8 @@ static bool setup_myself(void) {
|
||||||
devops = raw_socket_devops;
|
devops = raw_socket_devops;
|
||||||
else if(!strcasecmp(type, "multicast"))
|
else if(!strcasecmp(type, "multicast"))
|
||||||
devops = multicast_devops;
|
devops = multicast_devops;
|
||||||
|
else if(!strcasecmp(type, "fd"))
|
||||||
|
devops = fd_devops;
|
||||||
#ifdef ENABLE_UML
|
#ifdef ENABLE_UML
|
||||||
else if(!strcasecmp(type, "uml"))
|
else if(!strcasecmp(type, "uml"))
|
||||||
devops = uml_devops;
|
devops = uml_devops;
|
||||||
|
@ -1217,7 +1206,6 @@ void close_network_connections(void) {
|
||||||
|
|
||||||
exit_control();
|
exit_control();
|
||||||
|
|
||||||
free(myname);
|
|
||||||
free(scriptextension);
|
free(scriptextension);
|
||||||
free(scriptinterpreter);
|
free(scriptinterpreter);
|
||||||
|
|
||||||
|
|
|
@ -442,13 +442,20 @@ static void handle_meta_io(void *data, int flags) {
|
||||||
handle_meta_connection_data(c);
|
handle_meta_connection_data(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void free_known_addresses(struct addrinfo *ai) {
|
||||||
|
for(struct addrinfo *aip = ai, *next; aip; aip = next) {
|
||||||
|
next = aip->ai_next;
|
||||||
|
free(aip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool do_outgoing_connection(outgoing_t *outgoing) {
|
bool do_outgoing_connection(outgoing_t *outgoing) {
|
||||||
char *address;
|
char *address;
|
||||||
struct addrinfo *proxyai = NULL;
|
struct addrinfo *proxyai = NULL;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
begin:
|
begin:
|
||||||
if(!outgoing->ai) {
|
if(!outgoing->ai && !outgoing->kai) {
|
||||||
if(!outgoing->cfg) {
|
if(!outgoing->cfg) {
|
||||||
logger(DEBUG_CONNECTIONS, LOG_ERR, "Could not set up a meta connection to %s", outgoing->name);
|
logger(DEBUG_CONNECTIONS, LOG_ERR, "Could not set up a meta connection to %s", outgoing->name);
|
||||||
retry_outgoing(outgoing);
|
retry_outgoing(outgoing);
|
||||||
|
@ -469,6 +476,11 @@ begin:
|
||||||
if(outgoing->ai)
|
if(outgoing->ai)
|
||||||
freeaddrinfo(outgoing->ai);
|
freeaddrinfo(outgoing->ai);
|
||||||
outgoing->ai = NULL;
|
outgoing->ai = NULL;
|
||||||
|
|
||||||
|
if(outgoing->kai)
|
||||||
|
free_known_addresses(outgoing->kai);
|
||||||
|
outgoing->kai = NULL;
|
||||||
|
|
||||||
goto begin;
|
goto begin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -562,6 +574,7 @@ begin:
|
||||||
// Find edges pointing to this node, and use them to build a list of unique, known addresses.
|
// 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) {
|
static struct addrinfo *get_known_addresses(node_t *n) {
|
||||||
struct addrinfo *ai = NULL;
|
struct addrinfo *ai = NULL;
|
||||||
|
struct addrinfo *oai = NULL;
|
||||||
|
|
||||||
for splay_each(edge_t, e, n->edge_tree) {
|
for splay_each(edge_t, e, n->edge_tree) {
|
||||||
if(!e->reverse)
|
if(!e->reverse)
|
||||||
|
@ -577,16 +590,15 @@ static struct addrinfo *get_known_addresses(node_t *n) {
|
||||||
if(found)
|
if(found)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
struct addrinfo *nai = xzalloc(sizeof *nai);
|
oai = ai;
|
||||||
if(ai)
|
ai = xzalloc(sizeof *ai);
|
||||||
ai->ai_next = nai;
|
|
||||||
ai = nai;
|
|
||||||
ai->ai_family = e->reverse->address.sa.sa_family;
|
ai->ai_family = e->reverse->address.sa.sa_family;
|
||||||
ai->ai_socktype = SOCK_STREAM;
|
ai->ai_socktype = SOCK_STREAM;
|
||||||
ai->ai_protocol = IPPROTO_TCP;
|
ai->ai_protocol = IPPROTO_TCP;
|
||||||
ai->ai_addrlen = SALEN(e->reverse->address.sa);
|
ai->ai_addrlen = SALEN(e->reverse->address.sa);
|
||||||
ai->ai_addr = xmalloc(ai->ai_addrlen);
|
ai->ai_addr = xmalloc(ai->ai_addrlen);
|
||||||
memcpy(ai->ai_addr, &e->reverse->address, ai->ai_addrlen);
|
memcpy(ai->ai_addr, &e->reverse->address, ai->ai_addrlen);
|
||||||
|
ai->ai_next = oai;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ai;
|
return ai;
|
||||||
|
@ -640,8 +652,8 @@ void setup_outgoing_connection(outgoing_t *outgoing) {
|
||||||
|
|
||||||
if(!outgoing->cfg) {
|
if(!outgoing->cfg) {
|
||||||
if(n)
|
if(n)
|
||||||
outgoing->aip = outgoing->ai = get_known_addresses(n);
|
outgoing->aip = outgoing->kai = get_known_addresses(n);
|
||||||
if(!outgoing->ai) {
|
if(!outgoing->kai) {
|
||||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "No address known for %s", outgoing->name);
|
logger(DEBUG_ALWAYS, LOG_DEBUG, "No address known for %s", outgoing->name);
|
||||||
goto remove;
|
goto remove;
|
||||||
}
|
}
|
||||||
|
@ -798,6 +810,9 @@ static void free_outgoing(outgoing_t *outgoing) {
|
||||||
if(outgoing->ai)
|
if(outgoing->ai)
|
||||||
freeaddrinfo(outgoing->ai);
|
freeaddrinfo(outgoing->ai);
|
||||||
|
|
||||||
|
if(outgoing->kai)
|
||||||
|
free_known_addresses(outgoing->kai);
|
||||||
|
|
||||||
if(outgoing->config_tree)
|
if(outgoing->config_tree)
|
||||||
exit_configuration(&outgoing->config_tree);
|
exit_configuration(&outgoing->config_tree);
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
protocol_auth.c -- handle the meta-protocol, authentication
|
protocol_auth.c -- handle the meta-protocol, authentication
|
||||||
Copyright (C) 1999-2005 Ivo Timmermans,
|
Copyright (C) 1999-2005 Ivo Timmermans,
|
||||||
2000-2016 Guus Sliepen <guus@tinc-vpn.org>
|
2000-2017 Guus Sliepen <guus@tinc-vpn.org>
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
|
@ -181,21 +181,19 @@ static bool finalize_invitation(connection_t *c, const char *data, uint16_t len)
|
||||||
logger(DEBUG_CONNECTIONS, LOG_INFO, "Key succesfully received from %s (%s)", c->name, c->hostname);
|
logger(DEBUG_CONNECTIONS, LOG_INFO, "Key succesfully received from %s (%s)", c->name, c->hostname);
|
||||||
|
|
||||||
// Call invitation-accepted script
|
// Call invitation-accepted script
|
||||||
char *envp[7] = {NULL};
|
environment_t env;
|
||||||
char *address, *port;
|
char *address, *port;
|
||||||
|
|
||||||
xasprintf(&envp[0], "NETNAME=%s", netname ? : "");
|
environment_init(&env);
|
||||||
xasprintf(&envp[1], "DEVICE=%s", device ? : "");
|
environment_add(&env, "NODE=%s", c->name);
|
||||||
xasprintf(&envp[2], "INTERFACE=%s", iface ? : "");
|
|
||||||
xasprintf(&envp[3], "NODE=%s", c->name);
|
|
||||||
sockaddr2str(&c->address, &address, &port);
|
sockaddr2str(&c->address, &address, &port);
|
||||||
xasprintf(&envp[4], "REMOTEADDRESS=%s", address);
|
environment_add(&env, "REMOTEADDRESS=%s", address);
|
||||||
xasprintf(&envp[5], "NAME=%s", myself->name);
|
environment_add(&env, "NAME=%s", myself->name);
|
||||||
|
|
||||||
execute_script("invitation-accepted", envp);
|
execute_script("invitation-accepted", &env);
|
||||||
|
|
||||||
for(int i = 0; envp[i] && i < 7; i++)
|
environment_exit(&env);
|
||||||
free(envp[i]);
|
|
||||||
|
|
||||||
sptps_send_record(&c->sptps, 2, data, 0);
|
sptps_send_record(&c->sptps, 2, data, 0);
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -734,6 +734,9 @@ static void route_ipv6(node_t *source, vpn_packet_t *packet) {
|
||||||
if(!do_decrement_ttl(source, packet))
|
if(!do_decrement_ttl(source, packet))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if(priorityinheritance)
|
||||||
|
packet->priority = ((DATA(packet)[14] & 0x0f) << 4) | (DATA(packet)[15] >> 4);
|
||||||
|
|
||||||
via = (subnet->owner->via == myself) ? subnet->owner->nexthop : subnet->owner->via;
|
via = (subnet->owner->via == myself) ? subnet->owner->nexthop : subnet->owner->via;
|
||||||
|
|
||||||
if(via == source) {
|
if(via == source) {
|
||||||
|
@ -1005,8 +1008,12 @@ static void route_mac(node_t *source, vpn_packet_t *packet) {
|
||||||
|
|
||||||
uint16_t type = DATA(packet)[12] << 8 | DATA(packet)[13];
|
uint16_t type = DATA(packet)[12] << 8 | DATA(packet)[13];
|
||||||
|
|
||||||
if(priorityinheritance && type == ETH_P_IP && packet->len >= ether_size + ip_size)
|
if(priorityinheritance) {
|
||||||
|
if(type == ETH_P_IP && packet->len >= ether_size + ip_size)
|
||||||
packet->priority = DATA(packet)[15];
|
packet->priority = DATA(packet)[15];
|
||||||
|
else if(type == ETH_P_IPV6 && packet->len >= ether_size + ip6_size)
|
||||||
|
packet->priority = ((DATA(packet)[14] & 0x0f) << 4) | (DATA(packet)[15] >> 4);
|
||||||
|
}
|
||||||
|
|
||||||
// Handle packets larger than PMTU
|
// Handle packets larger than PMTU
|
||||||
|
|
||||||
|
|
64
src/script.c
64
src/script.c
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
script.c -- call an external script
|
script.c -- call an external script
|
||||||
Copyright (C) 1999-2005 Ivo Timmermans,
|
Copyright (C) 1999-2005 Ivo Timmermans,
|
||||||
2000-2015 Guus Sliepen <guus@tinc-vpn.org>
|
2000-2017 Guus Sliepen <guus@tinc-vpn.org>
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
|
@ -21,6 +21,7 @@
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
|
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
|
#include "device.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "names.h"
|
#include "names.h"
|
||||||
#include "script.h"
|
#include "script.h"
|
||||||
|
@ -63,7 +64,58 @@ static void putenv(const char *p) {}
|
||||||
static void unputenv(const char *p) {}
|
static void unputenv(const char *p) {}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool execute_script(const char *name, char **envp) {
|
static const int min_env_size;
|
||||||
|
|
||||||
|
int environment_add(environment_t *env, const char *format, ...) {
|
||||||
|
if(env->n >= env->size) {
|
||||||
|
env->size = env->n ? env->n * 2 : min_env_size;
|
||||||
|
env->entries = xrealloc(env->entries, env->size * sizeof *env->entries);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(format) {
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, format);
|
||||||
|
vasprintf(&env->entries[env->n], format, ap);
|
||||||
|
va_end(ap);
|
||||||
|
} else {
|
||||||
|
env->entries[env->n] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return env->n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void environment_update(environment_t *env, int pos, const char *format, ...) {
|
||||||
|
free(env->entries[pos]);
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, format);
|
||||||
|
vasprintf(&env->entries[pos], format, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void environment_init(environment_t *env) {
|
||||||
|
env->n = 0;
|
||||||
|
env->size = min_env_size;
|
||||||
|
env->entries = 0; //xzalloc(env->size * sizeof *env->entries);
|
||||||
|
|
||||||
|
if(netname)
|
||||||
|
environment_add(env, "NETNAME=%s", netname);
|
||||||
|
if(myname)
|
||||||
|
environment_add(env, "NAME=%s", myname);
|
||||||
|
if(device)
|
||||||
|
environment_add(env, "DEVICE=%s", device);
|
||||||
|
if(iface)
|
||||||
|
environment_add(env, "INTERFACE=%s", iface);
|
||||||
|
if(debug_level >= 0)
|
||||||
|
environment_add(env, "DEBUG=%d", debug_level);
|
||||||
|
}
|
||||||
|
|
||||||
|
void environment_exit(environment_t *env) {
|
||||||
|
for(int i = 0; i < env->n; i++)
|
||||||
|
free(env->entries[i]);
|
||||||
|
free(env->entries);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool execute_script(const char *name, environment_t *env) {
|
||||||
char scriptname[PATH_MAX];
|
char scriptname[PATH_MAX];
|
||||||
char *command;
|
char *command;
|
||||||
|
|
||||||
|
@ -107,8 +159,8 @@ bool execute_script(const char *name, char **envp) {
|
||||||
|
|
||||||
/* Set environment */
|
/* Set environment */
|
||||||
|
|
||||||
for(int i = 0; envp[i]; i++)
|
for(int i = 0; i < env->n; i++)
|
||||||
putenv(envp[i]);
|
putenv(env->entries[i]);
|
||||||
|
|
||||||
if(scriptinterpreter)
|
if(scriptinterpreter)
|
||||||
xasprintf(&command, "%s \"%s\"", scriptinterpreter, scriptname);
|
xasprintf(&command, "%s \"%s\"", scriptinterpreter, scriptname);
|
||||||
|
@ -121,8 +173,8 @@ bool execute_script(const char *name, char **envp) {
|
||||||
|
|
||||||
/* Unset environment */
|
/* Unset environment */
|
||||||
|
|
||||||
for(int i = 0; envp[i]; i++)
|
for(int i = 0; i < env->n; i++)
|
||||||
unputenv(envp[i]);
|
unputenv(env->entries[i]);
|
||||||
|
|
||||||
if(status != -1) {
|
if(status != -1) {
|
||||||
#ifdef WEXITSTATUS
|
#ifdef WEXITSTATUS
|
||||||
|
|
16
src/script.h
16
src/script.h
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
script.h -- header file for script.c
|
script.h -- header file for script.c
|
||||||
Copyright (C) 1999-2005 Ivo Timmermans,
|
Copyright (C) 1999-2005 Ivo Timmermans,
|
||||||
2000-2013 Guus Sliepen <guus@tinc-vpn.org>
|
2000-2017 Guus Sliepen <guus@tinc-vpn.org>
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
|
@ -21,6 +21,18 @@
|
||||||
#ifndef __TINC_SCRIPT_H__
|
#ifndef __TINC_SCRIPT_H__
|
||||||
#define __TINC_SCRIPT_H__
|
#define __TINC_SCRIPT_H__
|
||||||
|
|
||||||
extern bool execute_script(const char *, char **);
|
typedef struct environment {
|
||||||
|
int n;
|
||||||
|
int size;
|
||||||
|
char **entries;
|
||||||
|
} environment_t;
|
||||||
|
|
||||||
|
extern int environment_add(environment_t *env, const char *format, ...);
|
||||||
|
extern int environment_placeholder(environment_t *env);
|
||||||
|
extern void environment_update(environment_t *env, int pos, const char *format, ...);
|
||||||
|
extern void environment_init(environment_t *env);
|
||||||
|
extern void environment_exit(environment_t *env);
|
||||||
|
|
||||||
|
extern bool execute_script(const char *name, environment_t *env);
|
||||||
|
|
||||||
#endif /* __TINC_SCRIPT_H__ */
|
#endif /* __TINC_SCRIPT_H__ */
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
|
|
||||||
#include <sys/stropts.h>
|
#include <sys/stropts.h>
|
||||||
#include <sys/sockio.h>
|
#include <sys/sockio.h>
|
||||||
|
#include <stropts.h>
|
||||||
|
|
||||||
#include "../conf.h"
|
#include "../conf.h"
|
||||||
#include "../device.h"
|
#include "../device.h"
|
||||||
|
@ -41,6 +42,7 @@
|
||||||
|
|
||||||
#define DEFAULT_TUN_DEVICE "/dev/tun"
|
#define DEFAULT_TUN_DEVICE "/dev/tun"
|
||||||
#define DEFAULT_TAP_DEVICE "/dev/tap"
|
#define DEFAULT_TAP_DEVICE "/dev/tap"
|
||||||
|
#define IP_DEVICE "/dev/udp"
|
||||||
|
|
||||||
static enum {
|
static enum {
|
||||||
DEVICE_TYPE_TUN,
|
DEVICE_TYPE_TUN,
|
||||||
|
@ -84,8 +86,8 @@ static bool setup_device(void) {
|
||||||
|
|
||||||
/* The following is black magic copied from OpenVPN. */
|
/* The following is black magic copied from OpenVPN. */
|
||||||
|
|
||||||
if((ip_fd = open("/dev/ip", O_RDWR, 0)) < 0) {
|
if((ip_fd = open(IP_DEVICE, O_RDWR, 0)) < 0) {
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not open %s: %s\n", "/dev/ip", strerror(errno));
|
logger(DEBUG_ALWAYS, LOG_ERR, "Could not open %s: %s\n", IP_DEVICE, strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,7 +205,7 @@ static bool setup_device(void) {
|
||||||
|
|
||||||
/* Push arp module to ip_fd */
|
/* Push arp module to ip_fd */
|
||||||
if(ioctl(ip_fd, I_PUSH, "arp") < 0) {
|
if(ioctl(ip_fd, I_PUSH, "arp") < 0) {
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not push ARP module onto %s!", "/dev/ip");
|
logger(DEBUG_ALWAYS, LOG_ERR, "Could not push ARP module onto %s!", IP_DEVICE);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -295,11 +297,16 @@ static void close_device(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool read_packet(vpn_packet_t *packet) {
|
static bool read_packet(vpn_packet_t *packet) {
|
||||||
int inlen;
|
int result;
|
||||||
|
struct strbuf sbuf;
|
||||||
|
int f = 0;
|
||||||
|
|
||||||
switch(device_type) {
|
switch(device_type) {
|
||||||
case DEVICE_TYPE_TUN:
|
case DEVICE_TYPE_TUN:
|
||||||
if((inlen = read(device_fd, DATA(packet) + 14, MTU - 14)) <= 0) {
|
sbuf.maxlen = MTU - 14;
|
||||||
|
sbuf.buf = (char *)DATA(packet) + 14;
|
||||||
|
|
||||||
|
if((result = getmsg(device_fd, NULL, &sbuf, &f)) < 0) {
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info, device, strerror(errno));
|
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info, device, strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -319,16 +326,19 @@ static bool read_packet(vpn_packet_t *packet) {
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(DATA(packet), 0, 12);
|
memset(DATA(packet), 0, 12);
|
||||||
packet->len = inlen + 14;
|
packet->len = sbuf.len + 14;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DEVICE_TYPE_TAP:
|
case DEVICE_TYPE_TAP:
|
||||||
if((inlen = read(device_fd, DATA(packet), MTU)) <= 0) {
|
sbuf.maxlen = MTU;
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info, device, strerror(errno));
|
sbuf.buf = (char *)DATA(packet);
|
||||||
|
|
||||||
|
if((result = getmsg(device_fd, NULL, &sbuf, &f)) < 0) {
|
||||||
|
logger(LOG_ERR, "Error while reading from %s %s: %s", device_info, device, strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
packet->len = inlen + 14;
|
packet->len = sbuf.len;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -343,17 +353,25 @@ static bool read_packet(vpn_packet_t *packet) {
|
||||||
static bool write_packet(vpn_packet_t *packet) {
|
static bool write_packet(vpn_packet_t *packet) {
|
||||||
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Writing packet of %d bytes to %s", packet->len, device_info);
|
logger(DEBUG_TRAFFIC, LOG_DEBUG, "Writing packet of %d bytes to %s", packet->len, device_info);
|
||||||
|
|
||||||
|
struct strbuf sbuf;
|
||||||
|
|
||||||
switch(device_type) {
|
switch(device_type) {
|
||||||
case DEVICE_TYPE_TUN:
|
case DEVICE_TYPE_TUN:
|
||||||
if(write(device_fd, DATA(packet) + 14, packet->len - 14) < 0) {
|
sbuf.len = packet->len - 14;
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Can't write to %s %s: %s", device_info, device, strerror(errno));
|
sbuf.buf = (char *)DATA(packet) + 14;
|
||||||
|
|
||||||
|
if(putmsg(device_fd, NULL, &sbuf, 0) < 0) {
|
||||||
|
logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device, strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DEVICE_TYPE_TAP:
|
case DEVICE_TYPE_TAP:
|
||||||
if(write(device_fd, DATA(packet), packet->len) < 0) {
|
sbuf.len = packet->len;
|
||||||
logger(DEBUG_ALWAYS, LOG_ERR, "Can't write to %s %s: %s", device_info, device, strerror(errno));
|
sbuf.buf = (char *)DATA(packet);
|
||||||
|
|
||||||
|
if(putmsg(device_fd, NULL, &sbuf, 0) < 0) {
|
||||||
|
logger(LOG_ERR, "Can't write to %s %s: %s", device_info, device, strerror(errno));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
35
src/subnet.c
35
src/subnet.c
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
subnet.c -- handle subnet lookups and lists
|
subnet.c -- handle subnet lookups and lists
|
||||||
Copyright (C) 2000-2013 Guus Sliepen <guus@tinc-vpn.org>,
|
Copyright (C) 2000-2017 Guus Sliepen <guus@tinc-vpn.org>,
|
||||||
2000-2005 Ivo Timmermans
|
2000-2005 Ivo Timmermans
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
@ -206,22 +206,20 @@ void subnet_update(node_t *owner, subnet_t *subnet, bool up) {
|
||||||
|
|
||||||
// Prepare environment variables to be passed to the script
|
// Prepare environment variables to be passed to the script
|
||||||
|
|
||||||
char *envp[10] = {NULL};
|
environment_t env;
|
||||||
int n = 0;
|
environment_init(&env);
|
||||||
xasprintf(&envp[n++], "NETNAME=%s", netname ? : "");
|
environment_add(&env, "NODE=%s", owner->name);
|
||||||
xasprintf(&envp[n++], "DEVICE=%s", device ? : "");
|
|
||||||
xasprintf(&envp[n++], "INTERFACE=%s", iface ? : "");
|
|
||||||
xasprintf(&envp[n++], "NODE=%s", owner->name);
|
|
||||||
|
|
||||||
if(owner != myself) {
|
if(owner != myself) {
|
||||||
sockaddr2str(&owner->address, &address, &port);
|
sockaddr2str(&owner->address, &address, &port);
|
||||||
xasprintf(&envp[n++], "REMOTEADDRESS=%s", address);
|
environment_add(&env, "REMOTEADDRESS=%s", address);
|
||||||
xasprintf(&envp[n++], "REMOTEPORT=%s", port);
|
environment_add(&env, "REMOTEPORT=%s", port);
|
||||||
free(port);
|
free(port);
|
||||||
free(address);
|
free(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
xasprintf(&envp[n++], "NAME=%s", myself->name);
|
int env_subnet = environment_add(&env, NULL);
|
||||||
|
int env_weight = environment_add(&env, NULL);
|
||||||
|
|
||||||
name = up ? "subnet-up" : "subnet-down";
|
name = up ? "subnet-up" : "subnet-down";
|
||||||
|
|
||||||
|
@ -238,12 +236,10 @@ void subnet_update(node_t *owner, subnet_t *subnet, bool up) {
|
||||||
weight = empty;
|
weight = empty;
|
||||||
|
|
||||||
// Prepare the SUBNET and WEIGHT variables
|
// Prepare the SUBNET and WEIGHT variables
|
||||||
free(envp[n]);
|
environment_update(&env, env_subnet, "SUBNET=%s", netstr);
|
||||||
free(envp[n + 1]);
|
environment_update(&env, env_weight, "WEIGHT=%s", weight);
|
||||||
xasprintf(&envp[n], "SUBNET=%s", netstr);
|
|
||||||
xasprintf(&envp[n + 1], "WEIGHT=%s", weight);
|
|
||||||
|
|
||||||
execute_script(name, envp);
|
execute_script(name, &env);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(net2str(netstr, sizeof netstr, subnet)) {
|
if(net2str(netstr, sizeof netstr, subnet)) {
|
||||||
|
@ -255,15 +251,14 @@ void subnet_update(node_t *owner, subnet_t *subnet, bool up) {
|
||||||
weight = empty;
|
weight = empty;
|
||||||
|
|
||||||
// Prepare the SUBNET and WEIGHT variables
|
// Prepare the SUBNET and WEIGHT variables
|
||||||
xasprintf(&envp[n], "SUBNET=%s", netstr);
|
environment_update(&env, env_subnet, "SUBNET=%s", netstr);
|
||||||
xasprintf(&envp[n + 1], "WEIGHT=%s", weight);
|
environment_update(&env, env_weight, "WEIGHT=%s", weight);
|
||||||
|
|
||||||
execute_script(name, envp);
|
execute_script(name, &env);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int i = 0; envp[i] && i < 9; i++)
|
environment_exit(&env);
|
||||||
free(envp[i]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dump_subnets(connection_t *c) {
|
bool dump_subnets(connection_t *c) {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
tincctl.c -- Controlling a running tincd
|
tincctl.c -- Controlling a running tincd
|
||||||
Copyright (C) 2007-2016 Guus Sliepen <guus@tinc-vpn.org>
|
Copyright (C) 2007-2017 Guus Sliepen <guus@tinc-vpn.org>
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
|
@ -73,6 +73,9 @@ bool confbasegiven = false;
|
||||||
char *scriptinterpreter = NULL;
|
char *scriptinterpreter = NULL;
|
||||||
char *scriptextension = "";
|
char *scriptextension = "";
|
||||||
static char *prompt;
|
static char *prompt;
|
||||||
|
char *device = NULL;
|
||||||
|
char *iface = NULL;
|
||||||
|
int debug_level = -1;
|
||||||
|
|
||||||
static struct option const long_options[] = {
|
static struct option const long_options[] = {
|
||||||
{"batch", no_argument, NULL, 'b'},
|
{"batch", no_argument, NULL, 'b'},
|
||||||
|
@ -88,7 +91,7 @@ static struct option const long_options[] = {
|
||||||
static void version(void) {
|
static void version(void) {
|
||||||
printf("%s version %s (built %s %s, protocol %d.%d)\n", PACKAGE,
|
printf("%s version %s (built %s %s, protocol %d.%d)\n", PACKAGE,
|
||||||
BUILD_VERSION, BUILD_DATE, BUILD_TIME, PROT_MAJOR, PROT_MINOR);
|
BUILD_VERSION, BUILD_DATE, BUILD_TIME, PROT_MAJOR, PROT_MINOR);
|
||||||
printf("Copyright (C) 1998-2016 Ivo Timmermans, Guus Sliepen and others.\n"
|
printf("Copyright (C) 1998-2017 Ivo Timmermans, Guus Sliepen and others.\n"
|
||||||
"See the AUTHORS file for a complete list.\n\n"
|
"See the AUTHORS file for a complete list.\n\n"
|
||||||
"tinc comes with ABSOLUTELY NO WARRANTY. This is free software,\n"
|
"tinc comes with ABSOLUTELY NO WARRANTY. This is free software,\n"
|
||||||
"and you are welcome to redistribute it under certain conditions;\n"
|
"and you are welcome to redistribute it under certain conditions;\n"
|
||||||
|
@ -720,6 +723,8 @@ bool connect_tincd(bool verbose) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
|
||||||
|
#ifndef HAVE_MINGW
|
||||||
if ((pid == 0) || (kill(pid, 0) && (errno == ESRCH))) {
|
if ((pid == 0) || (kill(pid, 0) && (errno == ESRCH))) {
|
||||||
fprintf(stderr, "Could not find tincd running at pid %d\n", pid);
|
fprintf(stderr, "Could not find tincd running at pid %d\n", pid);
|
||||||
/* clean up the stale socket and pid file */
|
/* clean up the stale socket and pid file */
|
||||||
|
@ -728,7 +733,6 @@ bool connect_tincd(bool verbose) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef HAVE_MINGW
|
|
||||||
struct sockaddr_un sa;
|
struct sockaddr_un sa;
|
||||||
sa.sun_family = AF_UNIX;
|
sa.sun_family = AF_UNIX;
|
||||||
strncpy(sa.sun_path, unixsocketname, sizeof sa.sun_path);
|
strncpy(sa.sun_path, unixsocketname, sizeof sa.sun_path);
|
||||||
|
|
|
@ -16,9 +16,11 @@ TESTS = \
|
||||||
executables.test \
|
executables.test \
|
||||||
import-export.test \
|
import-export.test \
|
||||||
invite-join.test \
|
invite-join.test \
|
||||||
|
invite-offline.test \
|
||||||
invite-tinc-up.test \
|
invite-tinc-up.test \
|
||||||
ns-ping.test \
|
ns-ping.test \
|
||||||
ping.test \
|
ping.test \
|
||||||
|
scripts.test \
|
||||||
sptps-basic.test \
|
sptps-basic.test \
|
||||||
variables.test
|
variables.test
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,6 @@ EOF
|
||||||
|
|
||||||
# Generate an invitation and let another node join the VPN
|
# Generate an invitation and let another node join the VPN
|
||||||
|
|
||||||
sleep 1
|
|
||||||
|
|
||||||
$tinc $c1 invite bar | $tinc $c2 join
|
$tinc $c1 invite bar | $tinc $c2 join
|
||||||
|
|
||||||
# Test equivalence of host config files
|
# Test equivalence of host config files
|
||||||
|
|
50
test/invite-offline.test
Executable file
50
test/invite-offline.test
Executable file
|
@ -0,0 +1,50 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
. ./testlib.sh
|
||||||
|
|
||||||
|
# Initialize one node
|
||||||
|
|
||||||
|
$tinc $c1 <<EOF
|
||||||
|
init foo
|
||||||
|
set DeviceType dummy
|
||||||
|
set Mode switch
|
||||||
|
set Broadcast no
|
||||||
|
del Port
|
||||||
|
set Address localhost
|
||||||
|
set Port 32758
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Generate an invitation offline and let another node join the VPN
|
||||||
|
|
||||||
|
invitation=`$tinc $c1 invite bar`
|
||||||
|
|
||||||
|
$tinc $c1 start $r1
|
||||||
|
|
||||||
|
$tinc $c2 join $invitation
|
||||||
|
|
||||||
|
# Test equivalence of host config files
|
||||||
|
|
||||||
|
cmp $d1/hosts/foo $d2/hosts/foo
|
||||||
|
test "`grep ^Ed25519PublicKey $d1/hosts/bar`" = "`grep ^Ed25519PublicKey $d2/hosts/bar`"
|
||||||
|
|
||||||
|
# Test Mode, Broadcast and ConnectTo statements
|
||||||
|
|
||||||
|
test `$tinc $c2 get Mode` = switch
|
||||||
|
test `$tinc $c2 get Broadcast` = no
|
||||||
|
test `$tinc $c2 get ConnectTo` = foo
|
||||||
|
|
||||||
|
# Check whether the new node can join the VPN
|
||||||
|
|
||||||
|
$tinc $c2 << EOF
|
||||||
|
set DeviceType dummy
|
||||||
|
set Port 0
|
||||||
|
start $r2
|
||||||
|
EOF
|
||||||
|
|
||||||
|
sleep 1
|
||||||
|
|
||||||
|
test `$tinc $c1 dump reachable nodes | wc -l` = 2
|
||||||
|
test `$tinc $c2 dump reachable nodes | wc -l` = 2
|
||||||
|
|
||||||
|
$tinc $c2 stop
|
||||||
|
$tinc $c1 stop
|
|
@ -8,7 +8,7 @@ $tinc $c1 <<EOF
|
||||||
init foo
|
init foo
|
||||||
set DeviceType dummy
|
set DeviceType dummy
|
||||||
set Address localhost
|
set Address localhost
|
||||||
set Port 32751
|
set Port 32756
|
||||||
start $r1
|
start $r1
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ $tinc $c1 <<EOF
|
||||||
init foo
|
init foo
|
||||||
set Mode switch
|
set Mode switch
|
||||||
set Interface ping.test1
|
set Interface ping.test1
|
||||||
set Port 32573
|
set Port 32577
|
||||||
set Address localhost
|
set Address localhost
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
|
110
test/scripts.test
Executable file
110
test/scripts.test
Executable file
|
@ -0,0 +1,110 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
. ./testlib.sh
|
||||||
|
|
||||||
|
# Initialize server node
|
||||||
|
|
||||||
|
$tinc $c1 <<EOF
|
||||||
|
init foo
|
||||||
|
set DeviceType dummy
|
||||||
|
set Port 32759
|
||||||
|
set Address 127.0.0.1
|
||||||
|
add Subnet 10.0.0.1
|
||||||
|
add Subnet fec0::/64
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Set up scripts
|
||||||
|
|
||||||
|
OUT=$d1/scripts.out
|
||||||
|
rm -f $OUT
|
||||||
|
|
||||||
|
for script in tinc-up tinc-down host-up host-down subnet-up subnet-down hosts/foo-up hosts/foo-down hosts/bar-up hosts/bar-down invitation-created invitation-accepted; do
|
||||||
|
cat >$d1/$script << EOF
|
||||||
|
#!/bin/sh
|
||||||
|
echo $script \$NETNAME,\$NAME,\$DEVICE,\$IFACE,\$NODE,\$REMOTEADDRESS,\$REMOTEPORT,\$SUBNET,\$WEIGHT,\$INVITATION_FILE,\$INVITATION_URL,\$DEBUG >>$OUT
|
||||||
|
EOF
|
||||||
|
chmod u+x $d1/$script
|
||||||
|
done
|
||||||
|
|
||||||
|
# Start server node
|
||||||
|
|
||||||
|
$tinc -n netname $c1 start $r1
|
||||||
|
|
||||||
|
echo foo-started >>$OUT
|
||||||
|
|
||||||
|
# Invite client node
|
||||||
|
|
||||||
|
url=`$tinc -n netname2 $c1 invite bar`
|
||||||
|
file=`cd $d1/invitations; ls | grep -v ed25519_key.priv`
|
||||||
|
echo bar-invited >>$OUT
|
||||||
|
$tinc -n netname3 $c2 join $url
|
||||||
|
echo bar-joined >>$OUT
|
||||||
|
|
||||||
|
# Start and stop client node
|
||||||
|
|
||||||
|
$tinc $c2 << EOF
|
||||||
|
set DeviceType dummy
|
||||||
|
set Port 32760
|
||||||
|
add Subnet 10.0.0.2
|
||||||
|
add Subnet fec0::/64#5
|
||||||
|
start $r2
|
||||||
|
EOF
|
||||||
|
|
||||||
|
sleep 1
|
||||||
|
|
||||||
|
echo bar-started >>$OUT
|
||||||
|
|
||||||
|
$tinc $c1 debug 4
|
||||||
|
$tinc $c2 stop
|
||||||
|
|
||||||
|
sleep 1
|
||||||
|
|
||||||
|
echo bar-stopped >>$OUT
|
||||||
|
|
||||||
|
$tinc $c1 debug 5
|
||||||
|
$tinc $c2 start $r2
|
||||||
|
|
||||||
|
sleep 1
|
||||||
|
|
||||||
|
echo bar-started >>$OUT
|
||||||
|
|
||||||
|
# Stop server node
|
||||||
|
|
||||||
|
$tinc $c1 stop
|
||||||
|
|
||||||
|
# Check if the script output is what is expected
|
||||||
|
|
||||||
|
cat >$OUT.expected << EOF
|
||||||
|
tinc-up netname,foo,dummy,,,,,,,,,5
|
||||||
|
subnet-up netname,foo,dummy,,foo,,,10.0.0.1,,,,5
|
||||||
|
subnet-up netname,foo,dummy,,foo,,,fec0::/64,,,,5
|
||||||
|
foo-started
|
||||||
|
invitation-created netname2,foo,,,bar,,,,,$d1/invitations/$file,$url,
|
||||||
|
bar-invited
|
||||||
|
invitation-accepted netname,foo,dummy,,bar,127.0.0.1,,,,,,5
|
||||||
|
bar-joined
|
||||||
|
host-up netname,foo,dummy,,bar,127.0.0.1,32760,,,,,5
|
||||||
|
hosts/bar-up netname,foo,dummy,,bar,127.0.0.1,32760,,,,,5
|
||||||
|
subnet-up netname,foo,dummy,,bar,127.0.0.1,32760,10.0.0.2,,,,5
|
||||||
|
subnet-up netname,foo,dummy,,bar,127.0.0.1,32760,fec0::/64,5,,,5
|
||||||
|
bar-started
|
||||||
|
host-down netname,foo,dummy,,bar,127.0.0.1,32760,,,,,4
|
||||||
|
hosts/bar-down netname,foo,dummy,,bar,127.0.0.1,32760,,,,,4
|
||||||
|
subnet-down netname,foo,dummy,,bar,127.0.0.1,32760,10.0.0.2,,,,4
|
||||||
|
subnet-down netname,foo,dummy,,bar,127.0.0.1,32760,fec0::/64,5,,,4
|
||||||
|
bar-stopped
|
||||||
|
host-up netname,foo,dummy,,bar,127.0.0.1,32760,,,,,5
|
||||||
|
hosts/bar-up netname,foo,dummy,,bar,127.0.0.1,32760,,,,,5
|
||||||
|
subnet-up netname,foo,dummy,,bar,127.0.0.1,32760,10.0.0.2,,,,5
|
||||||
|
subnet-up netname,foo,dummy,,bar,127.0.0.1,32760,fec0::/64,5,,,5
|
||||||
|
bar-started
|
||||||
|
host-down netname,foo,dummy,,bar,127.0.0.1,32760,,,,,5
|
||||||
|
hosts/bar-down netname,foo,dummy,,bar,127.0.0.1,32760,,,,,5
|
||||||
|
subnet-down netname,foo,dummy,,bar,127.0.0.1,32760,10.0.0.2,,,,5
|
||||||
|
subnet-down netname,foo,dummy,,bar,127.0.0.1,32760,fec0::/64,5,,,5
|
||||||
|
subnet-down netname,foo,dummy,,foo,,,10.0.0.1,,,,5
|
||||||
|
subnet-down netname,foo,dummy,,foo,,,fec0::/64,,,,5
|
||||||
|
tinc-down netname,foo,dummy,,,,,,,,,5
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cmp $OUT $OUT.expected
|
Loading…
Reference in a new issue