Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.o
4 changes: 3 additions & 1 deletion Makefile.in
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
OBJ=common.o vars.o iplist.o sockinfo.o actions.o exit.o file_shred.o hooks.o dl_hooks.o exec_hooks.o time_hooks.o file_hooks.o filesys_hooks.o socket_hooks.o config.o net.o socks.o @X11_HOOKS_OBJ@
OBJ=common.o vars.o iplist.o sockinfo.o actions.o exit.o file_shred.o hooks.o dl_hooks.o exec_hooks.o time_hooks.o file_hooks.o filesys_hooks.o socket_hooks.o config.o net.o socks.o socks5.o @X11_HOOKS_OBJ@
CFLAGS=-g -fPIC @CFLAGS@
FLAGS=$(CFLAGS) @DEFS@
CC=gcc
Expand Down Expand Up @@ -65,6 +65,8 @@ net.o: net.c net.h common.h
socks.o: socks.c socks.h common.h
$(CC) $(FLAGS) -c socks.c

socks5.o: socks5.c socks5.h common.h
$(CC) $(FLAGS) -c socks5.c


clean:
Expand Down
11 changes: 10 additions & 1 deletion config.c
Original file line number Diff line number Diff line change
Expand Up @@ -787,6 +787,7 @@ static const char *enhancer_parse_config_item(const char *ConfigStr, TEnhancerCo
ptr=enhancer_config_tok(ConfigStr, &Name);
while (ptr)
{
// fprintf(stderr, "token: %s\n", Name);
if (strcmp(Name,"\n")==0) break;

val=enhancer_match_token_from_list(Name, EnhancerTokNames);
Expand Down Expand Up @@ -1167,12 +1168,14 @@ static const char *enhancer_add_config(const char *ConfigStr, const char *Functi
//enhancer_add_config
static void enhancer_read_prog_config(const char *Config)
{
// fprintf(stderr, "prog full config: %s\n", Config);
char *Tempstr=NULL;
const char *ptr, *dividers="#{} \r\n";

ptr=enhancer_config_tok(Config, &Tempstr);
while (ptr)
{
// fprintf(stderr, "prog token: %s\n", Tempstr);
if (Tempstr && strlen(Tempstr))
{
if (strcmp(Tempstr,"{")==0) /* do nothing */;
Expand All @@ -1185,7 +1188,13 @@ static void enhancer_read_prog_config(const char *Config)
else if (strcmp(Tempstr,"}")==0) break;
else
{
ptr=enhancer_add_config(ptr, Tempstr);
const char *linestart = ptr;
while ((*ptr !='\n') && (*ptr != '\0')) ptr++;
char *full_line = calloc(ptr - linestart + 1, 1);
strncpy(full_line, linestart, ptr - linestart);
// fprintf(stderr, "Adding config func %s, line: %s\n", Tempstr, full_line);
enhancer_add_config(full_line, Tempstr);
free(full_line);
}
}
ptr=enhancer_config_tok(ptr, &Tempstr);
Expand Down
4 changes: 3 additions & 1 deletion socket_hooks.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "actions.h"
#include "net.h"
#include "socks.h"
#include "socks5.h"
#include <dlfcn.h>
#include <sys/types.h>
#include <sys/socket.h>
Expand Down Expand Up @@ -86,7 +87,8 @@ int connect(int socket, const struct sockaddr *address, socklen_t address_len)
if (Flags & FLAG_REDIRECT)
{
close(socket);
if (strncmp(sockinfo->redirect, "socks:", 6)==0) socket=socks_connect(sockinfo->redirect, sockinfo->address, sockinfo->port);
if (strncmp(sockinfo->redirect, "socks5:", 7)==0) socket=socks5_connect(sockinfo->redirect, sockinfo->address, sockinfo->port);
else if (strncmp(sockinfo->redirect, "socks:", 6)==0) socket=socks_connect(sockinfo->redirect, sockinfo->address, sockinfo->port);
else socket=net_connect(sockinfo->redirect);
if (socket==-1) result=-1;
else result=0;
Expand Down
226 changes: 226 additions & 0 deletions socks5.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
#include "socks5.h"
#include "iplist.h"
#include "net.h"
#include <arpa/inet.h>


/*
* Perform SOCKS5 authentication negotiation
* Returns: 1 on success, 0 on failure
*/
static int socks5_auth_negotiate(int fd, const char *Username, const char *Password)
{
char request[3];
char response[2];
int auth_method;

/* Send authentication method selection request */
request[0] = SOCKS5_VERSION;

if (strvalid(Username) && strvalid(Password))
{
/* Support both no auth and username/password */
request[1] = 2; /* Number of methods */
request[2] = SOCKS5_AUTH_NOAUTH;
request[3] = SOCKS5_AUTH_USERPASS;
if (enhancer_real_write(fd, request, 4) != 4) return(0);
}
else
{
/* Only support no authentication */
request[1] = 1; /* Number of methods */
request[2] = SOCKS5_AUTH_NOAUTH;
if (enhancer_real_write(fd, request, 3) != 3) return(0);
}

/* Receive server's authentication method selection */
if (read(fd, response, 2) != 2) return(0);
if (response[0] != SOCKS5_VERSION) return(0);

auth_method = (unsigned char)response[1];

if (auth_method == SOCKS5_AUTH_NOACCEPTABLE) return(0);

/* Handle username/password authentication */
if (auth_method == SOCKS5_AUTH_USERPASS)
{
char auth_request[513];
char auth_response[2];
int ulen, plen, pos = 0;

if (!strvalid(Username) || !strvalid(Password)) return(0);

ulen = strlen(Username);
plen = strlen(Password);

if (ulen > 255 || plen > 255) return(0);

auth_request[pos++] = 0x01; /* Username/password auth version */
auth_request[pos++] = (char)ulen;
memcpy(auth_request + pos, Username, ulen);
pos += ulen;
auth_request[pos++] = (char)plen;
memcpy(auth_request + pos, Password, plen);
pos += plen;

if (enhancer_real_write(fd, auth_request, pos) != pos) return(0);

if (read(fd, auth_response, 2) != 2) return(0);
if (auth_response[0] != 0x01 || auth_response[1] != 0x00) return(0);
}

return(1);
}


/*
* Send SOCKS5 connection request
* Returns: 1 on success, 0 on failure
*/
static int socks5_request(int fd, const char *DestHost, int DestPort)
{
char request[512];
struct in_addr ipv4_addr;
int pos = 0;
int host_len;

if (fd == -1) return(0);

/* Build SOCKS5 request */
request[pos++] = SOCKS5_VERSION;
request[pos++] = SOCKS5_CMD_CONNECT;
request[pos++] = 0x00; /* Reserved */

/* Determine address type and encode destination */
if (inet_aton(DestHost, &ipv4_addr))
{
/* IPv4 address */
request[pos++] = SOCKS5_ATYP_IPV4;
memcpy(request + pos, &ipv4_addr.s_addr, 4);
pos += 4;
}
else
{
/* Domain name */
host_len = strlen(DestHost);
if (host_len > 255) return(0);

request[pos++] = SOCKS5_ATYP_DOMAIN;
request[pos++] = (char)host_len;
memcpy(request + pos, DestHost, host_len);
pos += host_len;
}

/* Add port (network byte order) */
*(uint16_t *)(request + pos) = htons((uint16_t)DestPort);
pos += 2;

/* Send request */
if (enhancer_real_write(fd, request, pos) != pos) return(0);

return(1);
}


/*
* Receive SOCKS5 connection reply
* Returns: 1 on success, 0 on failure
*/
static int socks5_reply(int fd)
{
char response[512];
int addr_len = 0;
int total_len;
unsigned char atyp;

/* Read fixed part of response: VER, REP, RSV, ATYP */
if (read(fd, response, 4) != 4) return(0);

/* Check version */
if ((unsigned char)response[0] != SOCKS5_VERSION) return(0);

/* Check reply code */
if ((unsigned char)response[1] != SOCKS5_REP_SUCCESS) return(0);

/* Parse address type to determine how much more to read */
atyp = (unsigned char)response[3];

switch (atyp)
{
case SOCKS5_ATYP_IPV4:
addr_len = 4;
break;
case SOCKS5_ATYP_IPV6:
addr_len = 16;
break;
case SOCKS5_ATYP_DOMAIN:
/* Read domain name length */
if (read(fd, response + 4, 1) != 1) return(0);
addr_len = (unsigned char)response[4] + 1; /* +1 for length byte itself */
break;
default:
return(0);
}

/* Read address + port (2 bytes) */
total_len = (atyp == SOCKS5_ATYP_DOMAIN) ? addr_len - 1 + 2 : addr_len + 2;

if (atyp == SOCKS5_ATYP_DOMAIN)
{
/* Already read length byte, read domain name + port */
if (read(fd, response + 5, total_len) != total_len) return(0);
}
else
{
/* Read address + port */
if (read(fd, response + 4, total_len) != total_len) return(0);
}

return(1);
}


/*
* Connect to destination through SOCKS5 proxy
* ProxyURL format: socks5://[user:pass@]host:port
* Returns: file descriptor on success, -1 on failure
*/
int socks5_connect(const char *ProxyURL, const char *DestHost, int DestPort)
{
char *Username=NULL, *Password=NULL;
const char *ptr;
int fd;

if (!DestHost) return(-1);

/* Parse authentication credentials if present */
if (strchr(ProxyURL, '@'))
{
ptr=enhancer_strtok(ProxyURL, ":", &Username);
ptr=enhancer_strtok(ptr, "@", &Password);
}

/* Connect to SOCKS5 proxy */
fd=net_connect(ProxyURL);
if (fd > -1)
{
/* Resolve hostname if needed */
ptr=enhancer_iplist_get(DestHost);
if (!strvalid(ptr)) ptr=DestHost;

/* Perform SOCKS5 handshake */
if (
(!socks5_auth_negotiate(fd, Username, Password)) ||
(!socks5_request(fd, ptr, DestPort)) ||
(!socks5_reply(fd))
)
{
close(fd);
fd=-1;
}
}

destroy(Username);
destroy(Password);
return(fd);
}
37 changes: 37 additions & 0 deletions socks5.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#ifndef ENHANCER_SOCKS5_H
#define ENHANCER_SOCKS5_H

#include "common.h"

/* SOCKS5 Protocol Constants */
#define SOCKS5_VERSION 0x05

/* Authentication Methods */
#define SOCKS5_AUTH_NOAUTH 0x00
#define SOCKS5_AUTH_USERPASS 0x02
#define SOCKS5_AUTH_NOACCEPTABLE 0xFF

/* Command Types */
#define SOCKS5_CMD_CONNECT 0x01
#define SOCKS5_CMD_BIND 0x02
#define SOCKS5_CMD_UDP_ASSOCIATE 0x03

/* Address Types */
#define SOCKS5_ATYP_IPV4 0x01
#define SOCKS5_ATYP_DOMAIN 0x03
#define SOCKS5_ATYP_IPV6 0x04

/* Reply Field */
#define SOCKS5_REP_SUCCESS 0x00
#define SOCKS5_REP_GENERAL_FAILURE 0x01
#define SOCKS5_REP_CONN_NOT_ALLOWED 0x02
#define SOCKS5_REP_NETWORK_UNREACHABLE 0x03
#define SOCKS5_REP_HOST_UNREACHABLE 0x04
#define SOCKS5_REP_CONN_REFUSED 0x05
#define SOCKS5_REP_TTL_EXPIRED 0x06
#define SOCKS5_REP_CMD_NOT_SUPPORTED 0x07
#define SOCKS5_REP_ADDR_TYPE_NOT_SUPPORTED 0x08

int socks5_connect(const char *ProxyURL, const char *DestHost, int DestPort);

#endif