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.
* Alexander Reil and Gemeinde Berg
* Allesandro Gatti
* Andreas van Cranenburgh
+* Anthony G. Basile
* Armijn Hemel
* Brandon Black
* Cris van Pelt
.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.
.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
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
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}>
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
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.
#ifdef HAVE_MINGW
#include <w32api.h>
+#include <winsock2.h>
#include <windows.h>
#include <ws2tcpip.h>
#endif
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 {
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"
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);
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;
+
+ // 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;
+
+ for(node = node_udp_tree->head; node; node = node->next) {
+ n = node->data;
- for(node = connection_tree->head; node; node = node->next) {
- c = node->data;
+ if(n->status.reachable && ((n->via == myself && n->nexthop == n) || n->via == n))
+ send_packet(n, packet);
+ }
+ break;
- if(c->status.active && c->status.mst && c != from->nexthop->connection)
- send_packet(c->node, packet);
+ default:
+ break;
}
}
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;
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)
*/
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;
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);
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");
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)
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;
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) {
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);
-
- /* Optimize TCP settings */
+ 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
- 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)) {
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;
}
}
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') {
#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);
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);
}
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;
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 &&
return;
}
- if(broadcast && packet->data[38] == 255)
+ if(broadcast_mode && packet->data[38] == 255)
broadcast_packet(source, packet);
else
route_ipv6_unicast(source, packet);
subnet = lookup_subnet_mac(NULL, &dest);
if(!subnet) {
- if(broadcast)
- broadcast_packet(source, packet);
+ broadcast_packet(source, packet);
return;
}
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;
#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;
}