Add basic support for SOCKS 4 and HTTP CONNECT proxies.
When the Proxy option is used, outgoing connections will be made via the specified proxy. There is no support for authentication methods or for having the proxy forward incoming connections, and there is no attempt to proxy UDP.
This commit is contained in:
parent
84531fb6e6
commit
b58d95eb29
8 changed files with 211 additions and 10 deletions
10
src/meta.c
10
src/meta.c
|
|
@ -177,7 +177,15 @@ bool receive_meta(connection_t *c) {
|
|||
|
||||
if(c->tcplen) {
|
||||
if(c->tcplen <= c->buflen) {
|
||||
receive_tcppacket(c, c->buffer, c->tcplen);
|
||||
if(proxytype == PROXY_SOCKS4 && c->allow_request == ID) {
|
||||
if(c->buffer[0] == 0 && c->buffer[1] == 0x5a) {
|
||||
logger(LOG_DEBUG, "Proxy request granted");
|
||||
} else {
|
||||
logger(LOG_ERR, "Proxy request rejected");
|
||||
return false;
|
||||
}
|
||||
} else
|
||||
receive_tcppacket(c, c->buffer, c->tcplen);
|
||||
|
||||
c->buflen -= c->tcplen;
|
||||
lenin -= c->tcplen - oldlen;
|
||||
|
|
|
|||
14
src/net.h
14
src/net.h
|
|
@ -122,6 +122,20 @@ extern time_t now;
|
|||
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;
|
||||
|
||||
extern volatile bool running;
|
||||
|
||||
/* Yes, very strange placement indeed, but otherwise the typedefs get all tangled up */
|
||||
|
|
|
|||
|
|
@ -47,6 +47,12 @@
|
|||
char *myport;
|
||||
devops_t devops;
|
||||
|
||||
char *proxyhost;
|
||||
char *proxyport;
|
||||
char *proxyuser;
|
||||
char *proxypass;
|
||||
proxytype_t proxytype;
|
||||
|
||||
bool read_rsa_public_key(connection_t *c) {
|
||||
FILE *fp;
|
||||
char *fname;
|
||||
|
|
@ -316,6 +322,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;
|
||||
|
|
@ -359,6 +367,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(LOG_ERR, "Unknown proxy type %s!", proxy);
|
||||
return false;
|
||||
}
|
||||
|
||||
switch(proxytype) {
|
||||
case PROXY_NONE:
|
||||
default:
|
||||
break;
|
||||
|
||||
case PROXY_EXEC:
|
||||
if(!space || !*space) {
|
||||
logger(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(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)
|
||||
proxyuser = xstrdup(proxypass);
|
||||
break;
|
||||
}
|
||||
|
||||
free(proxy);
|
||||
}
|
||||
|
||||
/* Read in all the subnets specified in the host configuration file */
|
||||
|
||||
cfg = lookup_config(config_tree, "Subnet");
|
||||
|
|
|
|||
|
|
@ -303,6 +303,7 @@ void finish_connecting(connection_t *c) {
|
|||
|
||||
void do_outgoing_connection(connection_t *c) {
|
||||
char *address, *port, *space;
|
||||
struct addrinfo *proxyai;
|
||||
int result;
|
||||
|
||||
if(!c->outgoing) {
|
||||
|
|
@ -358,17 +359,25 @@ begin:
|
|||
ifdebug(CONNECTIONS) logger(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);
|
||||
} else {
|
||||
proxyai = str2addrinfo(proxyhost, proxyport, SOCK_STREAM);
|
||||
if(!proxyai)
|
||||
goto begin;
|
||||
ifdebug(CONNECTIONS) logger(LOG_INFO, "Using proxy at %s port %s", proxyhost, proxyport);
|
||||
c->socket = socket(proxyai->ai_family, SOCK_STREAM, IPPROTO_TCP);
|
||||
}
|
||||
|
||||
if(c->socket == -1) {
|
||||
ifdebug(CONNECTIONS) logger(LOG_ERR, "Creating socket for %s failed: %s", c->hostname, sockstrerror(sockerrno));
|
||||
goto begin;
|
||||
}
|
||||
|
||||
#ifdef FD_CLOEXEC
|
||||
fcntl(c->socket, F_SETFD, FD_CLOEXEC);
|
||||
#endif
|
||||
|
||||
#if defined(SOL_IPV6) && defined(IPV6_V6ONLY)
|
||||
int option = 1;
|
||||
if(c->address.sa.sa_family == AF_INET6)
|
||||
|
|
@ -379,11 +388,16 @@ begin:
|
|||
|
||||
/* Optimize TCP settings */
|
||||
|
||||
configure_tcp(c);
|
||||
// configure_tcp(c);
|
||||
|
||||
/* 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 {
|
||||
result = connect(c->socket, proxyai->ai_addr, proxyai->ai_addrlen);
|
||||
freeaddrinfo(proxyai);
|
||||
}
|
||||
|
||||
if(result == -1) {
|
||||
if(sockinprogress(sockerrno)) {
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ bool check_id(const char *id) {
|
|||
bool send_request(connection_t *c, const char *format, ...) {
|
||||
va_list args;
|
||||
char buffer[MAXBUFSIZE];
|
||||
int len, request;
|
||||
int len, request = 0;
|
||||
|
||||
/* Use vsnprintf instead of vxasprintf: faster, no memory
|
||||
fragmentation, cleanup is automatic, and there is a limit on the
|
||||
|
|
@ -125,6 +125,20 @@ void forward_request(connection_t *from) {
|
|||
bool receive_request(connection_t *c) {
|
||||
int request;
|
||||
|
||||
if(proxytype == PROXY_HTTP && c->allow_request == ID) {
|
||||
if(!c->buffer[0] || c->buffer[0] == '\r')
|
||||
return true;
|
||||
if(!strncasecmp(c->buffer, "HTTP/1.1 ", 9)) {
|
||||
if(!strncmp(c->buffer + 9, "200", 3)) {
|
||||
logger(LOG_DEBUG, "Proxy request granted");
|
||||
return true;
|
||||
} else {
|
||||
logger(LOG_DEBUG, "Proxy request rejected: %s", c->buffer + 9);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(sscanf(c->buffer, "%d", &request) == 1) {
|
||||
if((request < 0) || (request >= LAST) || !request_handlers[request]) {
|
||||
ifdebug(META)
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#include "edge.h"
|
||||
#include "graph.h"
|
||||
#include "logger.h"
|
||||
#include "meta.h"
|
||||
#include "net.h"
|
||||
#include "netutl.h"
|
||||
#include "node.h"
|
||||
|
|
@ -38,7 +39,49 @@
|
|||
#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(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_SOCKS4A:
|
||||
case PROXY_SOCKS5:
|
||||
logger(LOG_ERR, "Proxy type not implemented yet");
|
||||
return false;
|
||||
default:
|
||||
logger(LOG_ERR, "Unknown proxy type");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool send_id(connection_t *c) {
|
||||
if(proxytype)
|
||||
if(!send_proxyrequest(c))
|
||||
return false;
|
||||
|
||||
return send_request(c, "%d %s %d", ID, myself->connection->name,
|
||||
myself->connection->protocol_version);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue