Merge branch 'master' of git://tinc-vpn.org/tinc into 1.1
Conflicts: NEWS README configure.in lib/utils.c src/linux/device.c src/meta.c src/net.h src/net_setup.c src/net_socket.c src/protocol.c src/protocol_auth.c src/tincd.c
This commit is contained in:
commit
19be9cf715
16 changed files with 517 additions and 52 deletions
11
NEWS
11
NEWS
|
@ -28,6 +28,17 @@ Version 1.1pre1 June 25 2011
|
|||
Thanks to Scott Lamb and Sven-Haegar Koch for their contributions to this
|
||||
version of tinc.
|
||||
|
||||
Version 1.0.19 June 25 2012
|
||||
|
||||
* Allow :: notation in IPv6 Subnets.
|
||||
|
||||
* Add support for systemd style socket activation.
|
||||
|
||||
* Allow environment variables to be used for the Name option.
|
||||
|
||||
* Add basic support for SOCKS proxies, HTTP proxies, and proxying through an
|
||||
external command.
|
||||
|
||||
Version 1.0.18 March 25 2012
|
||||
|
||||
* Fixed IPv6 in switch mode by turning off DecrementTTL by default.
|
||||
|
|
1
THANKS
1
THANKS
|
@ -3,6 +3,7 @@ We would like to thank the following people for their contributions to tinc:
|
|||
* Alexander Reil and Gemeinde Berg
|
||||
* Allesandro Gatti
|
||||
* Andreas van Cranenburgh
|
||||
* Anthony G. Basile
|
||||
* Armijn Hemel
|
||||
* Brandon Black
|
||||
* Cris van Pelt
|
||||
|
|
|
@ -159,8 +159,25 @@ It is possible to bind only to a single interface with this variable.
|
|||
.Pp
|
||||
This option may not work on all platforms.
|
||||
|
||||
.It Va Broadcast Li = yes | no Po yes Pc Bq experimental
|
||||
When disabled, tinc will drop all broadcast and multicast packets, in both router and switch mode.
|
||||
.It Va Broadcast Li = no | mst | direct Po mst Pc Bq experimental
|
||||
This option selects the way broadcast packets are sent to other daemons.
|
||||
NOTE: all nodes in a VPN must use the same
|
||||
.Va Broadcast
|
||||
mode, otherwise routing loops can form.
|
||||
|
||||
.Bl -tag -width indent
|
||||
.It no
|
||||
Broadcast packets are never sent to other nodes.
|
||||
|
||||
.It mst
|
||||
Broadcast packets are sent and forwarded via the VPN's Minimum Spanning Tree.
|
||||
This ensures broadcast packets reach all nodes.
|
||||
|
||||
.It direct
|
||||
Broadcast packets are sent directly to all nodes that can be reached directly.
|
||||
Broadcast packets received from other nodes are never forwarded.
|
||||
If the IndirectData option is also set, broadcast packets will only be sent to nodes which we have a meta connection to.
|
||||
.El
|
||||
|
||||
.It Va ConnectTo Li = Ar name
|
||||
Specifies which other tinc daemon to connect to on startup.
|
||||
|
@ -409,6 +426,19 @@ while no routing table is managed.
|
|||
.It Va Name Li = Ar name Bq required
|
||||
This is the name which identifies this tinc daemon.
|
||||
It must be unique for the virtual private network this daemon will connect to.
|
||||
The Name may only consist of alphanumeric and underscore characters.
|
||||
|
||||
If
|
||||
.Va Name
|
||||
starts with a
|
||||
.Li $ ,
|
||||
then the contents of the environment variable that follows will be used.
|
||||
In that case, invalid characters will be converted to underscores.
|
||||
If
|
||||
.Va Name
|
||||
is
|
||||
.Li $HOST ,
|
||||
but no such environment variable exist, the hostname will be read using the gethostnname() system call.
|
||||
|
||||
.It Va PingInterval Li = Ar seconds Pq 60
|
||||
The number of seconds of inactivity that
|
||||
|
@ -441,8 +471,41 @@ specified in the configuration file.
|
|||
When this option is used the priority of the tincd process will be adjusted.
|
||||
Increasing the priority may help to reduce latency and packet loss on the VPN.
|
||||
|
||||
.It Va Proxy Li = socks4 | socks5 | http | exec Ar ... Bq experimental
|
||||
Use a proxy when making outgoing connections.
|
||||
The following proxy types are currently supported:
|
||||
.Bl -tag -width indent
|
||||
.It socks4 Ar address Ar port Op Ar username
|
||||
Connects to the proxy using the SOCKS version 4 protocol.
|
||||
Optionally, a
|
||||
.Ar username
|
||||
can be supplied which will be passed on to the proxy server.
|
||||
Only IPv4 connections can be proxied using SOCKS 4.
|
||||
.It socks5 Ar address Ar port Op Ar username Ar password
|
||||
Connect to the proxy using the SOCKS version 5 protocol.
|
||||
If a
|
||||
.Ar username
|
||||
and
|
||||
.Ar password
|
||||
are given, basic username/password authentication will be used,
|
||||
otherwise no authentication will be used.
|
||||
.It http Ar address Ar port
|
||||
Connects to the proxy and sends a HTTP CONNECT request.
|
||||
.It exec Ar command
|
||||
Executes the given
|
||||
.Ar command
|
||||
which should set up the outgoing connection.
|
||||
The environment variables
|
||||
.Ev NAME ,
|
||||
.Ev NODE ,
|
||||
.Ev REMOTEADDRES
|
||||
and
|
||||
.Ev REMOTEPORT
|
||||
are available.
|
||||
.El
|
||||
|
||||
.It Va ReplayWindow Li = Ar bytes Pq 16
|
||||
This is the size of the replay tracking window for each remote node, in bytes.
|
||||
vhis is the size of the replay tracking window for each remote node, in bytes.
|
||||
The window is a bitfield which tracks 1 packet per bit, so for example
|
||||
the default setting of 16 will track up to 128 packets in the window. In high
|
||||
bandwidth scenarios, setting this to a higher value can reduce packet loss from
|
||||
|
|
|
@ -801,8 +801,23 @@ variable.
|
|||
This option may not work on all platforms.
|
||||
|
||||
@cindex Broadcast
|
||||
@item Broadcast = <yes | no> (yes) [experimental]
|
||||
When disabled, tinc will drop all broadcast and multicast packets, in both router and switch mode.
|
||||
@item Broadcast = <no | mst | direct> (mst) [experimental]
|
||||
This option selects the way broadcast packets are sent to other daemons.
|
||||
@emph{NOTE: all nodes in a VPN must use the same Broadcast mode, otherwise routing loops can form.}
|
||||
|
||||
@table @asis
|
||||
@item no
|
||||
Broadcast packets are never sent to other nodes.
|
||||
|
||||
@item mst
|
||||
Broadcast packets are sent and forwarded via the VPN's Minimum Spanning Tree.
|
||||
This ensures broadcast packets reach all nodes.
|
||||
|
||||
@item direct
|
||||
Broadcast packets are sent directly to all nodes that can be reached directly.
|
||||
Broadcast packets received from other nodes are never forwarded.
|
||||
If the IndirectData option is also set, broadcast packets will only be sent to nodes which we have a meta connection to.
|
||||
@end table
|
||||
|
||||
@cindex ConnectTo
|
||||
@item ConnectTo = <@var{name}>
|
||||
|
@ -1031,6 +1046,11 @@ This only has effect when Mode is set to "switch".
|
|||
This is a symbolic name for this connection.
|
||||
The name should consist only of alfanumeric and underscore characters (a-z, A-Z, 0-9 and _).
|
||||
|
||||
If Name starts with a $, then the contents of the environment variable that follows will be used.
|
||||
In that case, invalid characters will be converted to underscores.
|
||||
If Name is $HOST, but no such environment variable exist,
|
||||
the hostname will be read using the gethostnname() system call.
|
||||
|
||||
@cindex PingInterval
|
||||
@item PingInterval = <@var{seconds}> (60)
|
||||
The number of seconds of inactivity that tinc will wait before sending a
|
||||
|
@ -1068,6 +1088,33 @@ specified in the configuration file.
|
|||
When this option is used the priority of the tincd process will be adjusted.
|
||||
Increasing the priority may help to reduce latency and packet loss on the VPN.
|
||||
|
||||
@cindex Proxy
|
||||
@item Proxy = socks4 | socks4 | http | exec @var{...} [experimental]
|
||||
Use a proxy when making outgoing connections.
|
||||
The following proxy types are currently supported:
|
||||
|
||||
@table @asis
|
||||
@cindex socks4
|
||||
@item socks4 <@var{address}> <@var{port}> [<@var{username}>]
|
||||
Connects to the proxy using the SOCKS version 4 protocol.
|
||||
Optionally, a @var{username} can be supplied which will be passed on to the proxy server.
|
||||
|
||||
@cindex socks5
|
||||
@item socks4 <@var{address}> <@var{port}> [<@var{username}> <@var{password}>]
|
||||
Connect to the proxy using the SOCKS version 5 protocol.
|
||||
If a @var{username} and @var{password} are given, basic username/password authentication will be used,
|
||||
otherwise no authentication will be used.
|
||||
|
||||
@cindex http
|
||||
@item http <@var{address}> <@var{port}>
|
||||
Connects to the proxy and sends a HTTP CONNECT request.
|
||||
|
||||
@cindex exec
|
||||
@item exec <@var{command}>
|
||||
Executes the given command which should set up the outgoing connection.
|
||||
The environment variables @env{NAME}, @env{NODE}, @env{REMOTEADDRES} and @env{REMOTEPORT} are available.
|
||||
@end table
|
||||
|
||||
@cindex ReplayWindow
|
||||
@item ReplayWindow = <bytes> (16)
|
||||
This is the size of the replay tracking window for each remote node, in bytes.
|
||||
|
|
1
have.h
1
have.h
|
@ -42,6 +42,7 @@
|
|||
|
||||
#ifdef HAVE_MINGW
|
||||
#include <w32api.h>
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#include <ws2tcpip.h>
|
||||
#endif
|
||||
|
|
10
src/meta.c
10
src/meta.c
|
@ -196,7 +196,15 @@ bool receive_meta(connection_t *c) {
|
|||
if(c->tcplen) {
|
||||
char *tcpbuffer = buffer_read(&c->inbuf, c->tcplen);
|
||||
if(tcpbuffer) {
|
||||
receive_tcppacket(c, tcpbuffer, c->tcplen);
|
||||
if(proxytype == PROXY_SOCKS4 && c->allow_request == ID) {
|
||||
if(tcpbuffer[0] == 0 && tcpbuffer[1] == 0x5a) {
|
||||
logger(DEBUG_CONNECTIONS, LOG_DEBUG, "Proxy request granted");
|
||||
} else {
|
||||
logger(DEBUG_CONNECTIONS, LOG_ERR, "Proxy request rejected");
|
||||
return false;
|
||||
}
|
||||
} else
|
||||
receive_tcppacket(c, tcpbuffer, c->tcplen);
|
||||
c->tcplen = 0;
|
||||
continue;
|
||||
} else {
|
||||
|
|
15
src/net.h
15
src/net.h
|
@ -121,6 +121,20 @@ extern char *myport;
|
|||
extern int contradicting_add_edge;
|
||||
extern int contradicting_del_edge;
|
||||
|
||||
extern char *proxyhost;
|
||||
extern char *proxyport;
|
||||
extern char *proxyuser;
|
||||
extern char *proxypass;
|
||||
typedef enum proxytype_t {
|
||||
PROXY_NONE = 0,
|
||||
PROXY_SOCKS4,
|
||||
PROXY_SOCKS4A,
|
||||
PROXY_SOCKS5,
|
||||
PROXY_HTTP,
|
||||
PROXY_EXEC,
|
||||
} proxytype_t;
|
||||
extern proxytype_t proxytype;
|
||||
|
||||
/* Yes, very strange placement indeed, but otherwise the typedefs get all tangled up */
|
||||
#include "connection.h"
|
||||
#include "node.h"
|
||||
|
@ -135,6 +149,7 @@ extern int setup_vpn_in_socket(const sockaddr_t *);
|
|||
extern void send_packet(struct node_t *, vpn_packet_t *);
|
||||
extern void receive_tcppacket(struct connection_t *, const char *, int);
|
||||
extern void broadcast_packet(const struct node_t *, vpn_packet_t *);
|
||||
extern char *get_name(void);
|
||||
extern bool setup_network(void);
|
||||
extern void setup_outgoing_connection(struct outgoing_t *);
|
||||
extern void try_outgoing_connections(void);
|
||||
|
|
|
@ -576,24 +576,50 @@ void send_packet(node_t *n, vpn_packet_t *packet) {
|
|||
void broadcast_packet(const node_t *from, vpn_packet_t *packet) {
|
||||
splay_node_t *node;
|
||||
connection_t *c;
|
||||
node_t *n;
|
||||
|
||||
// Always give ourself a copy of the packet.
|
||||
if(from != myself)
|
||||
send_packet(myself, packet);
|
||||
|
||||
// In TunnelServer mode, do not forward broadcast packets.
|
||||
// The MST might not be valid and create loops.
|
||||
if(tunnelserver || broadcast_mode == BMODE_NONE)
|
||||
return;
|
||||
|
||||
logger(DEBUG_TRAFFIC, LOG_INFO, "Broadcasting packet of %d bytes from %s (%s)",
|
||||
packet->len, from->name, from->hostname);
|
||||
|
||||
if(from != myself) {
|
||||
send_packet(myself, packet);
|
||||
switch(broadcast_mode) {
|
||||
// In MST mode, broadcast packets travel via the Minimum Spanning Tree.
|
||||
// This guarantees all nodes receive the broadcast packet, and
|
||||
// usually distributes the sending of broadcast packets over all nodes.
|
||||
case BMODE_MST:
|
||||
for(node = connection_tree->head; node; node = node->next) {
|
||||
c = node->data;
|
||||
|
||||
// In TunnelServer mode, do not forward broadcast packets.
|
||||
// The MST might not be valid and create loops.
|
||||
if(tunnelserver)
|
||||
return;
|
||||
}
|
||||
if(c->status.active && c->status.mst && c != from->nexthop->connection)
|
||||
send_packet(c->node, packet);
|
||||
}
|
||||
break;
|
||||
|
||||
for(node = connection_tree->head; node; node = node->next) {
|
||||
c = node->data;
|
||||
// In direct mode, we send copies to each node we know of.
|
||||
// However, this only reaches nodes that can be reached in a single hop.
|
||||
// We don't have enough information to forward broadcast packets in this case.
|
||||
case BMODE_DIRECT:
|
||||
if(from != myself)
|
||||
break;
|
||||
|
||||
if(c->status.active && c->status.mst && c != from->nexthop->connection)
|
||||
send_packet(c->node, packet);
|
||||
for(node = node_udp_tree->head; node; node = node->next) {
|
||||
n = node->data;
|
||||
|
||||
if(n->status.reachable && ((n->via == myself && n->nexthop == n) || n->via == n))
|
||||
send_packet(n, packet);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
130
src/net_setup.c
130
src/net_setup.c
|
@ -46,6 +46,12 @@ char *myport;
|
|||
static struct event device_ev;
|
||||
devops_t devops;
|
||||
|
||||
char *proxyhost;
|
||||
char *proxyport;
|
||||
char *proxyuser;
|
||||
char *proxypass;
|
||||
proxytype_t proxytype;
|
||||
|
||||
bool node_read_ecdsa_public_key(node_t *n) {
|
||||
if(ecdsa_active(&n->ecdsa))
|
||||
return true;
|
||||
|
@ -340,6 +346,44 @@ void load_all_subnets(void) {
|
|||
closedir(dir);
|
||||
}
|
||||
|
||||
char *get_name(void) {
|
||||
char *name = NULL;
|
||||
|
||||
get_config_string(lookup_config(config_tree, "Name"), &name);
|
||||
|
||||
if(!name)
|
||||
return NULL;
|
||||
|
||||
if(*name == '$') {
|
||||
char *envname = getenv(name + 1);
|
||||
if(!envname) {
|
||||
if(strcmp(name + 1, "HOST")) {
|
||||
fprintf(stderr, "Invalid Name: environment variable %s does not exist\n", name + 1);
|
||||
return false;
|
||||
}
|
||||
envname = alloca(32);
|
||||
if(gethostname(envname, 32)) {
|
||||
fprintf(stderr, "Could not get hostname: %s\n", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
envname[31] = 0;
|
||||
}
|
||||
free(name);
|
||||
name = xstrdup(envname);
|
||||
for(char *c = name; *c; c++)
|
||||
if(!isalnum(*c))
|
||||
*c = '_';
|
||||
}
|
||||
|
||||
if(!check_id(name)) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Invalid name for myself!");
|
||||
free(name);
|
||||
return false;
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
/*
|
||||
Configure node_t myself and set up the local sockets (listen only)
|
||||
*/
|
||||
|
@ -349,6 +393,8 @@ static bool setup_myself(void) {
|
|||
char *name, *hostname, *mode, *afname, *cipher, *digest, *type;
|
||||
char *fname = NULL;
|
||||
char *address = NULL;
|
||||
char *proxy = NULL;
|
||||
char *space;
|
||||
char *envp[5];
|
||||
struct addrinfo *ai, *aip, hint = {0};
|
||||
bool choice;
|
||||
|
@ -365,17 +411,11 @@ static bool setup_myself(void) {
|
|||
myself->connection->protocol_major = PROT_MAJOR;
|
||||
myself->connection->protocol_minor = PROT_MINOR;
|
||||
|
||||
if(!get_config_string(lookup_config(config_tree, "Name"), &name)) { /* Not acceptable */
|
||||
if(!(name = get_name())) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Name for tinc daemon required!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!check_id(name)) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Invalid name for myself!");
|
||||
free(name);
|
||||
return false;
|
||||
}
|
||||
|
||||
myself->name = name;
|
||||
myself->connection->name = xstrdup(name);
|
||||
xasprintf(&fname, "%s/hosts/%s", confbase, name);
|
||||
|
@ -404,6 +444,68 @@ static bool setup_myself(void) {
|
|||
sockaddr2str(&sa, NULL, &myport);
|
||||
}
|
||||
|
||||
get_config_string(lookup_config(config_tree, "Proxy"), &proxy);
|
||||
if(proxy) {
|
||||
if((space = strchr(proxy, ' ')))
|
||||
*space++ = 0;
|
||||
|
||||
if(!strcasecmp(proxy, "none")) {
|
||||
proxytype = PROXY_NONE;
|
||||
} else if(!strcasecmp(proxy, "socks4")) {
|
||||
proxytype = PROXY_SOCKS4;
|
||||
} else if(!strcasecmp(proxy, "socks4a")) {
|
||||
proxytype = PROXY_SOCKS4A;
|
||||
} else if(!strcasecmp(proxy, "socks5")) {
|
||||
proxytype = PROXY_SOCKS5;
|
||||
} else if(!strcasecmp(proxy, "http")) {
|
||||
proxytype = PROXY_HTTP;
|
||||
} else if(!strcasecmp(proxy, "exec")) {
|
||||
proxytype = PROXY_EXEC;
|
||||
} else {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unknown proxy type %s!", proxy);
|
||||
return false;
|
||||
}
|
||||
|
||||
switch(proxytype) {
|
||||
case PROXY_NONE:
|
||||
default:
|
||||
break;
|
||||
|
||||
case PROXY_EXEC:
|
||||
if(!space || !*space) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Argument expected for proxy type exec!");
|
||||
return false;
|
||||
}
|
||||
proxyhost = xstrdup(space);
|
||||
break;
|
||||
|
||||
case PROXY_SOCKS4:
|
||||
case PROXY_SOCKS4A:
|
||||
case PROXY_SOCKS5:
|
||||
case PROXY_HTTP:
|
||||
proxyhost = space;
|
||||
if(space && (space = strchr(space, ' ')))
|
||||
*space++ = 0, proxyport = space;
|
||||
if(space && (space = strchr(space, ' ')))
|
||||
*space++ = 0, proxyuser = space;
|
||||
if(space && (space = strchr(space, ' ')))
|
||||
*space++ = 0, proxypass = space;
|
||||
if(!proxyhost || !*proxyhost || !proxyport || !*proxyport) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Host and port argument expected for proxy!");
|
||||
return false;
|
||||
}
|
||||
proxyhost = xstrdup(proxyhost);
|
||||
proxyport = xstrdup(proxyport);
|
||||
if(proxyuser && *proxyuser)
|
||||
proxyuser = xstrdup(proxyuser);
|
||||
if(proxypass && *proxypass)
|
||||
proxypass = xstrdup(proxypass);
|
||||
break;
|
||||
}
|
||||
|
||||
free(proxy);
|
||||
}
|
||||
|
||||
/* Read in all the subnets specified in the host configuration file */
|
||||
|
||||
cfg = lookup_config(config_tree, "Subnet");
|
||||
|
@ -474,7 +576,19 @@ static bool setup_myself(void) {
|
|||
|
||||
get_config_bool(lookup_config(config_tree, "PriorityInheritance"), &priorityinheritance);
|
||||
get_config_bool(lookup_config(config_tree, "DecrementTTL"), &decrement_ttl);
|
||||
get_config_bool(lookup_config(config_tree, "Broadcast"), &broadcast);
|
||||
if(get_config_string(lookup_config(config_tree, "Broadcast"), &mode)) {
|
||||
if(!strcasecmp(mode, "no"))
|
||||
broadcast_mode = BMODE_NONE;
|
||||
else if(!strcasecmp(mode, "yes") || !strcasecmp(mode, "mst"))
|
||||
broadcast_mode = BMODE_MST;
|
||||
else if(!strcasecmp(mode, "direct"))
|
||||
broadcast_mode = BMODE_DIRECT;
|
||||
else {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Invalid broadcast mode!");
|
||||
return false;
|
||||
}
|
||||
free(mode);
|
||||
}
|
||||
|
||||
#if !defined(SOL_IP) || !defined(IP_TOS)
|
||||
if(priorityinheritance)
|
||||
|
|
|
@ -292,7 +292,8 @@ void retry_outgoing(outgoing_t *outgoing) {
|
|||
void finish_connecting(connection_t *c) {
|
||||
logger(DEBUG_CONNECTIONS, LOG_INFO, "Connected to %s (%s)", c->name, c->hostname);
|
||||
|
||||
configure_tcp(c);
|
||||
if(proxytype != PROXY_EXEC)
|
||||
configure_tcp(c);
|
||||
|
||||
c->last_ping_time = time(NULL);
|
||||
c->status.connecting = false;
|
||||
|
@ -300,8 +301,57 @@ void finish_connecting(connection_t *c) {
|
|||
send_id(c);
|
||||
}
|
||||
|
||||
static void do_outgoing_pipe(connection_t *c, char *command) {
|
||||
#ifndef HAVE_MINGW
|
||||
int fd[2];
|
||||
|
||||
if(socketpair(AF_UNIX, SOCK_STREAM, 0, fd)) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not create socketpair: %s\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
if(fork()) {
|
||||
c->socket = fd[0];
|
||||
close(fd[1]);
|
||||
logger(DEBUG_CONNECTIONS, LOG_DEBUG, "Using proxy %s", command);
|
||||
return;
|
||||
}
|
||||
|
||||
close(0);
|
||||
close(1);
|
||||
close(fd[0]);
|
||||
dup2(fd[1], 0);
|
||||
dup2(fd[1], 1);
|
||||
close(fd[1]);
|
||||
|
||||
// Other filedescriptors should be closed automatically by CLOEXEC
|
||||
|
||||
char *host = NULL;
|
||||
char *port = NULL;
|
||||
|
||||
sockaddr2str(&c->address, &host, &port);
|
||||
setenv("REMOTEADDRESS", host, true);
|
||||
setenv("REMOTEPORT", port, true);
|
||||
setenv("NODE", c->name, true);
|
||||
setenv("NAME", myself->name, true);
|
||||
if(netname)
|
||||
setenv("NETNAME", netname, true);
|
||||
|
||||
int result = system(command);
|
||||
if(result < 0)
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Could not execute %s: %s\n", command, strerror(errno));
|
||||
else if(result)
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "%s exited with non-zero status %d", command, result);
|
||||
exit(result);
|
||||
#else
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Proxy type exec not supported on this platform!");
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool do_outgoing_connection(connection_t *c) {
|
||||
char *address, *port, *space;
|
||||
struct addrinfo *proxyai = NULL;
|
||||
int result;
|
||||
|
||||
if(!c->outgoing) {
|
||||
|
@ -357,32 +407,48 @@ begin:
|
|||
logger(DEBUG_CONNECTIONS, LOG_INFO, "Trying to connect to %s (%s)", c->name,
|
||||
c->hostname);
|
||||
|
||||
c->socket = socket(c->address.sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
|
||||
|
||||
#ifdef FD_CLOEXEC
|
||||
fcntl(c->socket, F_SETFD, FD_CLOEXEC);
|
||||
#endif
|
||||
if(!proxytype) {
|
||||
c->socket = socket(c->address.sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
|
||||
configure_tcp(c);
|
||||
} else if(proxytype == PROXY_EXEC) {
|
||||
do_outgoing_pipe(c, proxyhost);
|
||||
} else {
|
||||
proxyai = str2addrinfo(proxyhost, proxyport, SOCK_STREAM);
|
||||
if(!proxyai)
|
||||
goto begin;
|
||||
logger(DEBUG_CONNECTIONS, LOG_INFO, "Using proxy at %s port %s", proxyhost, proxyport);
|
||||
c->socket = socket(proxyai->ai_family, SOCK_STREAM, IPPROTO_TCP);
|
||||
}
|
||||
|
||||
if(c->socket == -1) {
|
||||
logger(DEBUG_CONNECTIONS, LOG_ERR, "Creating socket for %s failed: %s", c->hostname, sockstrerror(sockerrno));
|
||||
goto begin;
|
||||
}
|
||||
|
||||
#if defined(SOL_IPV6) && defined(IPV6_V6ONLY)
|
||||
int option = 1;
|
||||
if(c->address.sa.sa_family == AF_INET6)
|
||||
setsockopt(c->socket, SOL_IPV6, IPV6_V6ONLY, (void *)&option, sizeof option);
|
||||
#ifdef FD_CLOEXEC
|
||||
fcntl(c->socket, F_SETFD, FD_CLOEXEC);
|
||||
#endif
|
||||
|
||||
bind_to_interface(c->socket);
|
||||
if(proxytype != PROXY_EXEC) {
|
||||
#if defined(SOL_IPV6) && defined(IPV6_V6ONLY)
|
||||
int option = 1;
|
||||
if(c->address.sa.sa_family == AF_INET6)
|
||||
setsockopt(c->socket, SOL_IPV6, IPV6_V6ONLY, (void *)&option, sizeof option);
|
||||
#endif
|
||||
|
||||
/* Optimize TCP settings */
|
||||
|
||||
configure_tcp(c);
|
||||
bind_to_interface(c->socket);
|
||||
}
|
||||
|
||||
/* Connect */
|
||||
|
||||
result = connect(c->socket, &c->address.sa, SALEN(c->address.sa));
|
||||
if(!proxytype) {
|
||||
result = connect(c->socket, &c->address.sa, SALEN(c->address.sa));
|
||||
} else if(proxytype == PROXY_EXEC) {
|
||||
result = 0;
|
||||
} else {
|
||||
result = connect(c->socket, proxyai->ai_addr, proxyai->ai_addrlen);
|
||||
freeaddrinfo(proxyai);
|
||||
}
|
||||
|
||||
if(result == -1) {
|
||||
if(sockinprogress(sockerrno)) {
|
||||
|
|
|
@ -82,8 +82,10 @@ void sockaddr2str(const sockaddr_t *sa, char **addrstr, char **portstr) {
|
|||
int err;
|
||||
|
||||
if(sa->sa.sa_family == AF_UNKNOWN) {
|
||||
*addrstr = xstrdup(sa->unknown.address);
|
||||
*portstr = xstrdup(sa->unknown.port);
|
||||
if(addrstr)
|
||||
*addrstr = xstrdup(sa->unknown.address);
|
||||
if(portstr)
|
||||
*portstr = xstrdup(sa->unknown.port);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -108,6 +108,20 @@ void forward_request(connection_t *from, const char *request) {
|
|||
}
|
||||
|
||||
bool receive_request(connection_t *c, const char *request) {
|
||||
if(proxytype == PROXY_HTTP && c->allow_request == ID) {
|
||||
if(!request[0] || request[0] == '\r')
|
||||
return true;
|
||||
if(!strncasecmp(request, "HTTP/1.1 ", 9)) {
|
||||
if(!strncmp(request + 9, "200", 3)) {
|
||||
logger(DEBUG_CONNECTIONS, LOG_DEBUG, "Proxy request granted");
|
||||
return true;
|
||||
} else {
|
||||
logger(DEBUG_ALWAYS, LOG_DEBUG, "Proxy request rejected: %s", request + 9);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int reqno = atoi(request);
|
||||
|
||||
if(reqno || *request == '0') {
|
||||
|
|
|
@ -42,6 +42,92 @@
|
|||
#include "utils.h"
|
||||
#include "xalloc.h"
|
||||
|
||||
static bool send_proxyrequest(connection_t *c) {
|
||||
switch(proxytype) {
|
||||
case PROXY_HTTP: {
|
||||
char *host;
|
||||
char *port;
|
||||
|
||||
sockaddr2str(&c->address, &host, &port);
|
||||
send_request(c, "CONNECT %s:%s HTTP/1.1\r\n\r", host, port);
|
||||
free(host);
|
||||
free(port);
|
||||
return true;
|
||||
}
|
||||
case PROXY_SOCKS4: {
|
||||
if(c->address.sa.sa_family != AF_INET) {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Cannot connect to an IPv6 host through a SOCKS 4 proxy!");
|
||||
return false;
|
||||
}
|
||||
char s4req[9 + (proxyuser ? strlen(proxyuser) : 0)];
|
||||
s4req[0] = 4;
|
||||
s4req[1] = 1;
|
||||
memcpy(s4req + 2, &c->address.in.sin_port, 2);
|
||||
memcpy(s4req + 4, &c->address.in.sin_addr, 4);
|
||||
if(proxyuser)
|
||||
strcpy(s4req + 8, proxyuser);
|
||||
s4req[sizeof s4req - 1] = 0;
|
||||
c->tcplen = 8;
|
||||
return send_meta(c, s4req, sizeof s4req);
|
||||
}
|
||||
case PROXY_SOCKS5: {
|
||||
int len = 3 + 6 + (c->address.sa.sa_family == AF_INET ? 4 : 16);
|
||||
c->tcplen = 2;
|
||||
if(proxypass)
|
||||
len += 3 + strlen(proxyuser) + strlen(proxypass);
|
||||
char s5req[len];
|
||||
int i = 0;
|
||||
s5req[i++] = 5;
|
||||
s5req[i++] = 1;
|
||||
if(proxypass) {
|
||||
s5req[i++] = 2;
|
||||
s5req[i++] = 1;
|
||||
s5req[i++] = strlen(proxyuser);
|
||||
strcpy(s5req + i, proxyuser);
|
||||
i += strlen(proxyuser);
|
||||
s5req[i++] = strlen(proxypass);
|
||||
strcpy(s5req + i, proxypass);
|
||||
i += strlen(proxypass);
|
||||
c->tcplen += 2;
|
||||
} else {
|
||||
s5req[i++] = 0;
|
||||
}
|
||||
s5req[i++] = 5;
|
||||
s5req[i++] = 1;
|
||||
s5req[i++] = 0;
|
||||
if(c->address.sa.sa_family == AF_INET) {
|
||||
s5req[i++] = 1;
|
||||
memcpy(s5req + i, &c->address.in.sin_addr, 4);
|
||||
i += 4;
|
||||
memcpy(s5req + i, &c->address.in.sin_port, 2);
|
||||
i += 2;
|
||||
c->tcplen += 10;
|
||||
} else if(c->address.sa.sa_family == AF_INET6) {
|
||||
s5req[i++] = 3;
|
||||
memcpy(s5req + i, &c->address.in6.sin6_addr, 16);
|
||||
i += 16;
|
||||
memcpy(s5req + i, &c->address.in6.sin6_port, 2);
|
||||
i += 2;
|
||||
c->tcplen += 22;
|
||||
} else {
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Address family %hx not supported for SOCKS 5 proxies!", c->address.sa.sa_family);
|
||||
return false;
|
||||
}
|
||||
if(i > len)
|
||||
abort();
|
||||
return send_meta(c, s5req, sizeof s5req);
|
||||
}
|
||||
case PROXY_SOCKS4A:
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Proxy type not implemented yet");
|
||||
return false;
|
||||
case PROXY_EXEC:
|
||||
return true;
|
||||
default:
|
||||
logger(DEBUG_ALWAYS, LOG_ERR, "Unknown proxy type");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool send_id(connection_t *c) {
|
||||
gettimeofday(&c->start, NULL);
|
||||
|
||||
|
@ -54,6 +140,10 @@ bool send_id(connection_t *c) {
|
|||
minor = myself->connection->protocol_minor;
|
||||
}
|
||||
|
||||
if(proxytype)
|
||||
if(!send_proxyrequest(c))
|
||||
return false;
|
||||
|
||||
return send_request(c, "%d %s %d.%d", ID, myself->connection->name, myself->connection->protocol_major, minor);
|
||||
}
|
||||
|
||||
|
|
|
@ -36,12 +36,12 @@
|
|||
|
||||
rmode_t routing_mode = RMODE_ROUTER;
|
||||
fmode_t forwarding_mode = FMODE_INTERNAL;
|
||||
bmode_t broadcast_mode = BMODE_MST;
|
||||
bool decrement_ttl = false;
|
||||
bool directonly = false;
|
||||
bool priorityinheritance = false;
|
||||
int macexpire = 600;
|
||||
bool overwrite_mac = false;
|
||||
bool broadcast = true;
|
||||
mac_t mymac = {{0xFE, 0xFD, 0, 0, 0, 0}};
|
||||
bool pcap = false;
|
||||
|
||||
|
@ -447,7 +447,7 @@ static void route_ipv4(node_t *source, vpn_packet_t *packet) {
|
|||
if(!checklength(source, packet, ether_size + ip_size))
|
||||
return;
|
||||
|
||||
if(broadcast && (((packet->data[30] & 0xf0) == 0xe0) || (
|
||||
if(broadcast_mode && (((packet->data[30] & 0xf0) == 0xe0) || (
|
||||
packet->data[30] == 255 &&
|
||||
packet->data[31] == 255 &&
|
||||
packet->data[32] == 255 &&
|
||||
|
@ -744,7 +744,7 @@ static void route_ipv6(node_t *source, vpn_packet_t *packet) {
|
|||
return;
|
||||
}
|
||||
|
||||
if(broadcast && packet->data[38] == 255)
|
||||
if(broadcast_mode && packet->data[38] == 255)
|
||||
broadcast_packet(source, packet);
|
||||
else
|
||||
route_ipv6_unicast(source, packet);
|
||||
|
@ -834,8 +834,7 @@ static void route_mac(node_t *source, vpn_packet_t *packet) {
|
|||
subnet = lookup_subnet_mac(NULL, &dest);
|
||||
|
||||
if(!subnet) {
|
||||
if(broadcast)
|
||||
broadcast_packet(source, packet);
|
||||
broadcast_packet(source, packet);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -36,12 +36,18 @@ typedef enum fmode_t {
|
|||
FMODE_KERNEL,
|
||||
} fmode_t;
|
||||
|
||||
typedef enum bmode_t {
|
||||
BMODE_NONE = 0,
|
||||
BMODE_MST,
|
||||
BMODE_DIRECT,
|
||||
} bmode_t;
|
||||
|
||||
extern rmode_t routing_mode;
|
||||
extern fmode_t forwarding_mode;
|
||||
extern bmode_t broadcast_mode;
|
||||
extern bool decrement_ttl;
|
||||
extern bool directonly;
|
||||
extern bool overwrite_mac;
|
||||
extern bool broadcast;
|
||||
extern bool priorityinheritance;
|
||||
extern int macexpire;
|
||||
extern bool pcap;
|
||||
|
|
10
src/utils.c
10
src/utils.c
|
@ -137,15 +137,17 @@ int b64encode(const char *src, char *dst, int length) {
|
|||
#endif
|
||||
|
||||
const char *winerror(int err) {
|
||||
static char buf[1024], *newline;
|
||||
static char buf[1024], *ptr;
|
||||
|
||||
ptr = buf + sprintf(buf, "(%d) ", err);
|
||||
|
||||
if (!FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, sizeof(buf), NULL)) {
|
||||
NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), ptr, sizeof(buf) - (ptr - buf), NULL)) {
|
||||
strncpy(buf, "(unable to format errormessage)", sizeof(buf));
|
||||
};
|
||||
|
||||
if((newline = strchr(buf, '\r')))
|
||||
*newline = '\0';
|
||||
if((ptr = strchr(buf, '\r')))
|
||||
*ptr = '\0';
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue