mirror of
https://github.com/nmap/nmap.git
synced 2026-01-19 12:49:02 +00:00
[Ncat] Added support for socks5 and corresponding regression tests.
[Marek Lucaszuk, Petr Stodulka]
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
# Nmap Changelog ($Id$); -*-text-*-
|
||||
|
||||
o [Ncat] Added support for socks5 and corresponding regression tests.
|
||||
[Marek Lucaszuk, Petr Stodulka]
|
||||
|
||||
o [NSE] Add http-ntlm-info script for getting server information from Web
|
||||
servers that require NTLM authentication. [Justin Cacak]
|
||||
|
||||
|
||||
48
ncat/ncat.h
48
ncat/ncat.h
@@ -154,6 +154,8 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define SOCKS_BUFF_SIZE 512
|
||||
|
||||
/* structs */
|
||||
|
||||
#ifdef WIN32
|
||||
@@ -163,8 +165,27 @@ struct socks4_data {
|
||||
char version;
|
||||
char type;
|
||||
unsigned short port;
|
||||
unsigned long address;
|
||||
char username[256];
|
||||
uint32_t address;
|
||||
char data[SOCKS_BUFF_SIZE]; // this has to be able to hold FQDN and username
|
||||
} __attribute__((packed));
|
||||
|
||||
struct socks5_connect {
|
||||
char ver;
|
||||
char nmethods;
|
||||
char methods[3];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct socks5_auth {
|
||||
char ver; // must be always 1
|
||||
char data[SOCKS_BUFF_SIZE];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct socks5_request {
|
||||
char ver;
|
||||
char cmd;
|
||||
char rsv;
|
||||
char atyp;
|
||||
char dst[SOCKS_BUFF_SIZE]; // addr/name and port info
|
||||
} __attribute__((packed));
|
||||
#ifdef WIN32
|
||||
#pragma pack()
|
||||
@@ -192,6 +213,10 @@ struct socks4_data {
|
||||
/* Default port for SOCKS4 */
|
||||
#define DEFAULT_SOCKS4_PORT 1080
|
||||
|
||||
/* Default port for SOCKS5 */
|
||||
#define DEFAULT_SOCKS5_PORT 1080
|
||||
|
||||
|
||||
/* The default port Ncat will connect to when trying to connect to an HTTP
|
||||
* proxy server. The current setting is the default for squid and probably
|
||||
* other HTTP proxies. But it may also be 8080, 8888, etc.
|
||||
@@ -217,10 +242,21 @@ struct socks4_data {
|
||||
#define SOCKS4_VERSION 4
|
||||
#define SOCKS_CONNECT 1
|
||||
#define SOCKS_BIND 2
|
||||
#define SOCKS_CONN_ACC 90 /* woot */
|
||||
#define SOCKS_CONN_REF 91
|
||||
#define SOCKS_CONN_IDENT 92
|
||||
#define SOCKS_CONN_IDENTDIFF 93
|
||||
#define SOCKS4_CONN_ACC 90 /* woot */
|
||||
#define SOCKS4_CONN_REF 91
|
||||
#define SOCKS4_CONN_IDENT 92
|
||||
#define SOCKS4_CONN_IDENTDIFF 93
|
||||
|
||||
/* SOCKS5 protocol */
|
||||
#define SOCKS5_VERSION 5
|
||||
#define SOCKS5_AUTH_NONE 0
|
||||
#define SOCKS5_AUTH_GSSAPI 1
|
||||
#define SOCKS5_AUTH_USERPASS 2
|
||||
#define SOCKS5_AUTH_FAILED 255
|
||||
#define SOCKS5_ATYP_IPv4 1
|
||||
#define SOCKS5_ATYP_NAME 3
|
||||
#define SOCKS5_ATYP_IPv6 4
|
||||
|
||||
|
||||
/* Length of IPv6 address */
|
||||
#ifndef INET6_ADDRSTRLEN
|
||||
|
||||
@@ -298,50 +298,48 @@ static void connect_report(nsock_iod nsi)
|
||||
}
|
||||
|
||||
/* Just like inet_socktop, but it puts IPv6 addresses in square brackets. */
|
||||
static const char *sock_to_url(const union sockaddr_u *su)
|
||||
static const char *sock_to_url(char *host_str, unsigned short port)
|
||||
{
|
||||
static char buf[INET6_ADDRSTRLEN + 32];
|
||||
const char *host_str;
|
||||
unsigned short port;
|
||||
static char buf[512];
|
||||
|
||||
host_str = inet_socktop(su);
|
||||
port = inet_port(su);
|
||||
if (su->storage.ss_family == AF_INET)
|
||||
Snprintf(buf, sizeof(buf), "%s:%hu", host_str, port);
|
||||
else if (su->storage.ss_family == AF_INET6)
|
||||
Snprintf(buf, sizeof(buf), "[%s]:%hu", host_str, port);
|
||||
else
|
||||
bye("Unknown address family in sock_to_url_host.");
|
||||
switch(getaddrfamily(host_str)) {
|
||||
case -1:
|
||||
case 1:
|
||||
Snprintf(buf, sizeof(buf), "%s:%hu", host_str, port);
|
||||
break;
|
||||
case 2:
|
||||
Snprintf(buf, sizeof(buf), "[%s]:%hu]", host_str, port);
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int append_connect_request_line(char **buf, size_t *size, size_t *offset,
|
||||
const union sockaddr_u *su)
|
||||
char* host_str,unsigned short port)
|
||||
{
|
||||
return strbuf_sprintf(buf, size, offset, "CONNECT %s HTTP/1.0\r\n",
|
||||
sock_to_url(su));
|
||||
sock_to_url(host_str,port));
|
||||
}
|
||||
|
||||
static char *http_connect_request(const union sockaddr_u *su, int *n)
|
||||
static char *http_connect_request(char* host_str, unsigned short port, int *n)
|
||||
{
|
||||
char *buf = NULL;
|
||||
size_t size = 0, offset = 0;
|
||||
|
||||
append_connect_request_line(&buf, &size, &offset, su);
|
||||
append_connect_request_line(&buf, &size, &offset, host_str, port);
|
||||
strbuf_append_str(&buf, &size, &offset, "\r\n");
|
||||
*n = offset;
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static char *http_connect_request_auth(const union sockaddr_u *su, int *n,
|
||||
static char *http_connect_request_auth(char* host_str, unsigned short port, int *n,
|
||||
struct http_challenge *challenge)
|
||||
{
|
||||
char *buf = NULL;
|
||||
size_t size = 0, offset = 0;
|
||||
|
||||
append_connect_request_line(&buf, &size, &offset, su);
|
||||
append_connect_request_line(&buf, &size, &offset, host_str, port);
|
||||
strbuf_append_str(&buf, &size, &offset, "Proxy-Authorization:");
|
||||
if (challenge->scheme == AUTH_BASIC) {
|
||||
char *auth_str;
|
||||
@@ -364,7 +362,7 @@ static char *http_connect_request_auth(const union sockaddr_u *su, int *n,
|
||||
return NULL;
|
||||
}
|
||||
response_hdr = http_digest_proxy_authorization(challenge,
|
||||
username, password, "CONNECT", sock_to_url(&httpconnect));
|
||||
username, password, "CONNECT", sock_to_url(o.target,o.portno));
|
||||
if (response_hdr == NULL) {
|
||||
free(proxy_auth);
|
||||
return NULL;
|
||||
@@ -405,7 +403,7 @@ static int do_proxy_http(void)
|
||||
header = NULL;
|
||||
|
||||
/* First try a request with no authentication. */
|
||||
request = http_connect_request(&httpconnect, &n);
|
||||
request = http_connect_request(o.target,o.portno, &n);
|
||||
if (send(sd, request, n, 0) < 0) {
|
||||
loguser("Error sending proxy request: %s.\n", socket_strerror(socket_errno()));
|
||||
free(request);
|
||||
@@ -455,7 +453,7 @@ static int do_proxy_http(void)
|
||||
goto bail;
|
||||
}
|
||||
|
||||
request = http_connect_request_auth(&httpconnect, &n, &challenge);
|
||||
request = http_connect_request_auth(o.target,o.portno, &n, &challenge);
|
||||
if (request == NULL) {
|
||||
loguser("Error building Proxy-Authorization header.\n");
|
||||
http_challenge_free(&challenge);
|
||||
@@ -511,6 +509,355 @@ bail:
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* SOCKS4a support
|
||||
* Return a usable socket descriptor after
|
||||
* proxy negotiation, or -1 on any error.
|
||||
*/
|
||||
static int do_proxy_socks4(void)
|
||||
{
|
||||
struct socket_buffer stateful_buf;
|
||||
struct socks4_data socks4msg;
|
||||
char socksbuf[8];
|
||||
int sd,len = 9;
|
||||
|
||||
sd = do_connect(SOCK_STREAM);
|
||||
if (sd == -1) {
|
||||
loguser("Proxy connection failed: %s.\n", socket_strerror(socket_errno()));
|
||||
return sd;
|
||||
}
|
||||
socket_buffer_init(&stateful_buf, sd);
|
||||
|
||||
if (o.verbose) {
|
||||
loguser("Connected to proxy %s:%hu\n", inet_socktop(&targetss),
|
||||
inet_port(&targetss));
|
||||
}
|
||||
|
||||
/* Fill the socks4_data struct */
|
||||
zmem(&socks4msg, sizeof(socks4msg));
|
||||
socks4msg.version = SOCKS4_VERSION;
|
||||
socks4msg.type = SOCKS_CONNECT;
|
||||
socks4msg.port = htons(o.portno);
|
||||
|
||||
switch(getaddrfamily(o.target)) {
|
||||
case 1: // IPv4 address family
|
||||
socks4msg.address = inet_addr(o.target);
|
||||
|
||||
if (o.proxy_auth){
|
||||
memcpy(socks4msg.data, o.proxy_auth, strlen(o.proxy_auth));
|
||||
len += strlen(o.proxy_auth);
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: // IPv6 address family
|
||||
|
||||
loguser("Error: IPv6 addresses are not supported with Socks4.\n");
|
||||
close(sd);
|
||||
return -1;
|
||||
|
||||
case -1: // fqdn
|
||||
|
||||
socks4msg.address = inet_addr("0.0.0.1");
|
||||
|
||||
if (strlen(o.target) > SOCKS_BUFF_SIZE-2) {
|
||||
loguser("Error: host name is too long.\n");
|
||||
close(sd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (o.proxy_auth){
|
||||
if (strlen(o.target)+strlen(o.proxy_auth) > SOCKS_BUFF_SIZE-2) {
|
||||
loguser("Error: host name and username are too long.\n");
|
||||
close(sd);
|
||||
return -1;
|
||||
}
|
||||
Strncpy(socks4msg.data,o.proxy_auth,sizeof(socks4msg.data));
|
||||
len += strlen(o.proxy_auth);
|
||||
}
|
||||
memcpy(socks4msg.data+(len-8), o.target, strlen(o.target));
|
||||
len += strlen(o.target)+1;
|
||||
}
|
||||
|
||||
if (send(sd, (char *) &socks4msg, len, 0) < 0) {
|
||||
loguser("Error: sending proxy request: %s.\n", socket_strerror(socket_errno()));
|
||||
close(sd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* The size of the socks4 response is 8 bytes. So read exactly
|
||||
8 bytes from the buffer */
|
||||
if (socket_buffer_readcount(&stateful_buf, socksbuf, 8) < 0) {
|
||||
loguser("Error: short response from proxy.\n");
|
||||
close(sd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sd != -1 && socksbuf[1] != SOCKS4_CONN_ACC) {
|
||||
loguser("Proxy connection failed.\n");
|
||||
close(sd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return sd;
|
||||
}
|
||||
|
||||
/* SOCKS5 support
|
||||
* Return a usable socket descriptor after
|
||||
* proxy negotiation, or -1 on any error.
|
||||
*/
|
||||
static int do_proxy_socks5(void)
|
||||
{
|
||||
|
||||
struct socket_buffer stateful_buf;
|
||||
struct socks5_connect socks5msg;
|
||||
uint32_t inetaddr;
|
||||
char inet6addr[16];
|
||||
unsigned short proxyport = htons(o.portno);
|
||||
char socksbuf[8];
|
||||
int sd,len,lenfqdn;
|
||||
|
||||
|
||||
sd = do_connect(SOCK_STREAM);
|
||||
if (sd == -1) {
|
||||
loguser("Proxy connection failed: %s.\n", socket_strerror(socket_errno()));
|
||||
return sd;
|
||||
}
|
||||
|
||||
socket_buffer_init(&stateful_buf, sd);
|
||||
|
||||
if (o.verbose) {
|
||||
loguser("Connected to proxy %s:%hu\n", inet_socktop(&targetss),
|
||||
inet_port(&targetss));
|
||||
}
|
||||
|
||||
zmem(&socks5msg,sizeof(socks5msg));
|
||||
socks5msg.ver = SOCKS5_VERSION;
|
||||
socks5msg.nmethods = 1;
|
||||
socks5msg.methods[0] = SOCKS5_AUTH_NONE;
|
||||
len = 3;
|
||||
|
||||
if (o.proxy_auth){
|
||||
socks5msg.nmethods ++;
|
||||
socks5msg.methods[1] = SOCKS5_AUTH_USERPASS;
|
||||
len ++;
|
||||
}
|
||||
|
||||
if (send(sd, (char *) &socks5msg, len, 0) < 0) {
|
||||
loguser("Error: proxy request: %s.\n", socket_strerror(socket_errno()));
|
||||
close(sd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* first response just two bytes, version and auth method */
|
||||
if (socket_buffer_readcount(&stateful_buf, socksbuf, 2) < 0) {
|
||||
loguser("Error: malformed first response from proxy.\n");
|
||||
close(sd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (socksbuf[0] != 5){
|
||||
loguser("Error: got wrong server version in response.\n");
|
||||
close(sd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch(socksbuf[1]) {
|
||||
case SOCKS5_AUTH_NONE:
|
||||
if (o.verbose)
|
||||
loguser("No authentication needed.\n");
|
||||
break;
|
||||
|
||||
case SOCKS5_AUTH_GSSAPI:
|
||||
loguser("GSSAPI authentication method not supported.\n");
|
||||
close(sd);
|
||||
return -1;
|
||||
|
||||
case SOCKS5_AUTH_USERPASS:
|
||||
if (o.verbose)
|
||||
loguser("Doing username and password authentication.\n");
|
||||
|
||||
if(!o.proxy_auth){
|
||||
loguser("Error: proxy requested to do authentication, but no credentials were provided.\n");
|
||||
close(sd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strlen(o.proxy_auth) > SOCKS_BUFF_SIZE-2){
|
||||
loguser("Error: username and password are too long to fit into buffer.\n");
|
||||
close(sd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *proxy_auth;
|
||||
char *username, *password;
|
||||
|
||||
/* Split up the proxy auth argument. */
|
||||
proxy_auth = Strdup(o.proxy_auth);
|
||||
username = strtok(proxy_auth, ":");
|
||||
password = strtok(NULL, ":");
|
||||
if (password == NULL || username == NULL) {
|
||||
free(proxy_auth);
|
||||
loguser("Error: empty username or password.\n");
|
||||
close(sd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* For username/password authentication the client's authentication request is
|
||||
* field 1: version number, 1 byte (must be 0x01 -- version of subnegotion)
|
||||
* field 2: username length, 1 byte
|
||||
* field 3: username
|
||||
* field 4: password length, 1 byte
|
||||
* field 5: password
|
||||
*
|
||||
* Server response for username/password authentication:
|
||||
* field 1: version, 1 byte
|
||||
* field 2: status code, 1 byte.
|
||||
* 0x00 = success
|
||||
* any other value = failure, connection must be closed
|
||||
*/
|
||||
struct socks5_auth socks5auth;
|
||||
|
||||
socks5auth.ver = 1;
|
||||
socks5auth.data[0] = strlen(username);
|
||||
memcpy(socks5auth.data+1,username,strlen(username));
|
||||
len = 2 + strlen(username); // (version + strlen) + username
|
||||
|
||||
socks5auth.data[len]=strlen(password);
|
||||
memcpy(socks5auth.data+len,password,strlen(password));
|
||||
len += 1 + strlen(password);
|
||||
|
||||
if (send(sd, (char *) &socks5auth, len, 0) < 0) {
|
||||
loguser("Error: sending proxy authentication.\n");
|
||||
close(sd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (socket_buffer_readcount(&stateful_buf, socksbuf, 2) < 0) {
|
||||
loguser("Error: malformed proxy authentication response.\n");
|
||||
close(sd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (socksbuf[0] != 1 || socksbuf[1] != 0) {
|
||||
loguser("Error: authentication failed.\n");
|
||||
close(sd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
loguser("Error - can't choose any authentication method.\n");
|
||||
close(sd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct socks5_request socks5msg2;
|
||||
|
||||
zmem(&socks5msg2,sizeof(socks5msg2));
|
||||
socks5msg2.ver = SOCKS5_VERSION;
|
||||
socks5msg2.cmd = SOCKS_CONNECT;
|
||||
socks5msg2.rsv = 0;
|
||||
|
||||
switch(getaddrfamily(o.target)) {
|
||||
|
||||
case 1: // IPv4 address family
|
||||
socks5msg2.atyp = SOCKS5_ATYP_IPv4;
|
||||
inetaddr = inet_addr(o.target);
|
||||
memcpy(socks5msg2.dst, &inetaddr, 4);
|
||||
len = 4;
|
||||
break;
|
||||
|
||||
case 2: // IPv6 address family
|
||||
socks5msg2.atyp = SOCKS5_ATYP_IPv6;
|
||||
inet_pton(AF_INET6,o.target,&inet6addr);
|
||||
memcpy(socks5msg2.dst, inet6addr,16);
|
||||
len = 16;
|
||||
break;
|
||||
|
||||
case -1: // FQDN
|
||||
socks5msg2.atyp = SOCKS5_ATYP_NAME;
|
||||
lenfqdn=strlen(o.target);
|
||||
if (lenfqdn > SOCKS_BUFF_SIZE-5){
|
||||
loguser("Error: host name too long.\n");
|
||||
close(sd);
|
||||
return -1;
|
||||
}
|
||||
socks5msg2.dst[0]=lenfqdn;
|
||||
memcpy(socks5msg2.dst+1,o.target,lenfqdn);
|
||||
len = 1 + lenfqdn;
|
||||
}
|
||||
|
||||
memcpy(socks5msg2.dst+len, &proxyport, sizeof(proxyport));
|
||||
len += 2 + 1 + 3;
|
||||
|
||||
if (len > sizeof(socks5msg2)){
|
||||
loguser("Error: address information too large.\n");
|
||||
close(sd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (send(sd, (char *) &socks5msg2, len, 0) < 0) {
|
||||
loguser("Error: sending proxy request: %s.\n", socket_strerror(socket_errno()));
|
||||
close(sd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* TODO just two bytes for now, need to read more for bind */
|
||||
if (socket_buffer_readcount(&stateful_buf, socksbuf, 2) < 0) {
|
||||
loguser("Error: malformed second response from proxy.\n");
|
||||
close(sd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch(socksbuf[1]) {
|
||||
case 0:
|
||||
if (o.verbose)
|
||||
loguser("connection succeeded.\n");
|
||||
break;
|
||||
case 1:
|
||||
loguser("Error: general SOCKS server failure.\n");
|
||||
close(sd);
|
||||
return -1;
|
||||
case 2:
|
||||
loguser("Error: connection not allowed by ruleset.\n");
|
||||
close(sd);
|
||||
return -1;
|
||||
case 3:
|
||||
loguser("Error: Network unreachable.\n");
|
||||
close(sd);
|
||||
return -1;
|
||||
case 4:
|
||||
loguser("Error: Host unreachable.\n");
|
||||
close(sd);
|
||||
return -1;
|
||||
case 5:
|
||||
loguser("Error: Connection refused.\n");
|
||||
close(sd);
|
||||
return -1;
|
||||
case 6:
|
||||
loguser("Error: TTL expired.\n");
|
||||
close(sd);
|
||||
return -1;
|
||||
case 7:
|
||||
loguser("Error: Command not supported.\n");
|
||||
close(sd);
|
||||
return -1;
|
||||
case 8:
|
||||
loguser("Error: Address type not supported.\n");
|
||||
close(sd);
|
||||
return -1;
|
||||
default:
|
||||
loguser("Error: unassigned value in the reply.\n");
|
||||
close(sd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return(sd);
|
||||
}
|
||||
|
||||
|
||||
int ncat_connect(void)
|
||||
{
|
||||
nsock_pool mypool;
|
||||
@@ -543,8 +890,7 @@ int ncat_connect(void)
|
||||
set_ssl_ctx_options((SSL_CTX *) nsp_ssl_init(mypool));
|
||||
#endif
|
||||
|
||||
if (httpconnect.storage.ss_family == AF_UNSPEC
|
||||
&& socksconnect.storage.ss_family == AF_UNSPEC) {
|
||||
if (!o.proxytype) {
|
||||
/* A non-proxy connection. Create an iod for a new socket. */
|
||||
cs.sock_nsi = nsi_new(mypool, NULL);
|
||||
if (cs.sock_nsi == NULL)
|
||||
@@ -640,65 +986,23 @@ int ncat_connect(void)
|
||||
} else {
|
||||
/* A proxy connection. */
|
||||
static int connect_socket;
|
||||
int len;
|
||||
char *line;
|
||||
size_t n;
|
||||
|
||||
if (httpconnect.storage.ss_family != AF_UNSPEC) {
|
||||
if (strcmp(o.proxytype, "http") == 0) {
|
||||
connect_socket = do_proxy_http();
|
||||
if (connect_socket == -1)
|
||||
return 1;
|
||||
} else if (socksconnect.storage.ss_family != AF_UNSPEC) {
|
||||
struct socket_buffer stateful_buf;
|
||||
struct socks4_data socks4msg;
|
||||
char socksbuf[8];
|
||||
|
||||
connect_socket = do_connect(SOCK_STREAM);
|
||||
if (connect_socket == -1) {
|
||||
loguser("Proxy connection failed: %s.\n", socket_strerror(socket_errno()));
|
||||
return 1;
|
||||
}
|
||||
|
||||
socket_buffer_init(&stateful_buf, connect_socket);
|
||||
|
||||
if (o.verbose) {
|
||||
loguser("Connected to proxy %s:%hu\n", inet_socktop(&targetss),
|
||||
inet_port(&targetss));
|
||||
}
|
||||
|
||||
/* Fill the socks4_data struct */
|
||||
zmem(&socks4msg, sizeof(socks4msg));
|
||||
socks4msg.version = SOCKS4_VERSION;
|
||||
socks4msg.type = SOCKS_CONNECT;
|
||||
socks4msg.port = socksconnect.in.sin_port;
|
||||
socks4msg.address = socksconnect.in.sin_addr.s_addr;
|
||||
if (o.proxy_auth)
|
||||
Strncpy(socks4msg.username, (char *) o.proxy_auth, sizeof(socks4msg.username));
|
||||
|
||||
len = 8 + strlen(socks4msg.username) + 1;
|
||||
|
||||
if (send(connect_socket, (char *) &socks4msg, len, 0) < 0) {
|
||||
loguser("Error sending proxy request: %s.\n", socket_strerror(socket_errno()));
|
||||
return 1;
|
||||
}
|
||||
/* The size of the socks4 response is 8 bytes. So read exactly
|
||||
8 bytes from the buffer */
|
||||
if (socket_buffer_readcount(&stateful_buf, socksbuf, 8) < 0) {
|
||||
loguser("Error: short reponse from proxy.\n");
|
||||
return 1;
|
||||
}
|
||||
if (socksbuf[1] != 90) {
|
||||
loguser("Proxy connection failed.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Clear out whatever is left in the socket buffer which may be
|
||||
already sent by proxy server along with http response headers. */
|
||||
line = socket_buffer_remainder(&stateful_buf, &n);
|
||||
/* Write the leftover data to stdout. */
|
||||
Write(STDOUT_FILENO, line, n);
|
||||
} else if (strcmp(o.proxytype, "socks4") == 0) {
|
||||
connect_socket = do_proxy_socks4();
|
||||
} else if (strcmp(o.proxytype, "socks5") == 0) {
|
||||
connect_socket = do_proxy_socks5();
|
||||
}
|
||||
|
||||
if (connect_socket == -1)
|
||||
return 1;
|
||||
/* Clear out whatever is left in the socket buffer which may be
|
||||
already sent by proxy server along with http response headers. */
|
||||
//line = socket_buffer_remainder(&stateful_buf, &n);
|
||||
/* Write the leftover data to stdout. */
|
||||
//Write(STDOUT_FILENO, line, n);
|
||||
|
||||
/* Once the proxy negotiation is done, Nsock takes control of the
|
||||
socket. */
|
||||
cs.sock_nsi = nsi_new2(mypool, connect_socket, NULL);
|
||||
|
||||
@@ -150,9 +150,6 @@ size_t srcaddrlen;
|
||||
union sockaddr_u targetss;
|
||||
size_t targetsslen;
|
||||
|
||||
union sockaddr_u httpconnect, socksconnect;
|
||||
size_t httpconnectlen, socksconnectlen;
|
||||
|
||||
/* Global options structure. */
|
||||
struct options o;
|
||||
|
||||
@@ -536,6 +533,32 @@ static int ncat_hexdump(int logfd, const char *data, int len)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* this function will return in what format the target
|
||||
* host is specified. It will return:
|
||||
* 1 - for ipv4,
|
||||
* 2 - for ipv6,
|
||||
* -1 - for hostname
|
||||
* this has to work even if there is no IPv6 support on
|
||||
* local system, proxy may support it.
|
||||
*/
|
||||
int getaddrfamily(const char *addr)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (strchr(addr,':'))
|
||||
return 2;
|
||||
|
||||
struct addrinfo hint, *info =0;
|
||||
zmem(&hint,sizeof(hint));
|
||||
hint.ai_family = AF_UNSPEC;
|
||||
hint.ai_flags = AI_NUMERICHOST;
|
||||
ret = getaddrinfo(addr, 0, &hint, &info);
|
||||
if (ret)
|
||||
return -1;
|
||||
freeaddrinfo(info);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void setup_environment(struct fdinfo *info)
|
||||
{
|
||||
union sockaddr_u su;
|
||||
|
||||
@@ -139,9 +139,6 @@ extern size_t srcaddrlen;
|
||||
extern union sockaddr_u targetss;
|
||||
extern size_t targetsslen;
|
||||
|
||||
extern union sockaddr_u httpconnect, socksconnect;
|
||||
extern size_t httpconnectlen, socksconnectlen;
|
||||
|
||||
enum exec_mode {
|
||||
EXEC_PLAIN,
|
||||
EXEC_SHELL,
|
||||
@@ -197,6 +194,7 @@ struct options {
|
||||
enum exec_mode execmode;
|
||||
char *proxy_auth;
|
||||
char *proxytype;
|
||||
char *proxyaddr;
|
||||
|
||||
int ssl;
|
||||
char *sslcert;
|
||||
@@ -265,5 +263,6 @@ extern int ncat_hostaccess(char *matchaddr, char *filename, char *remoteip);
|
||||
Defined in ncat_posix.c and ncat_win.c. */
|
||||
extern void set_lf_mode(void);
|
||||
|
||||
extern int getaddrfamily(const char *addr);
|
||||
extern int setenv_portable(const char *name, const char *value);
|
||||
extern void setup_environment(struct fdinfo *fdinfo);
|
||||
|
||||
102
ncat/ncat_main.c
102
ncat/ncat_main.c
@@ -154,12 +154,10 @@ static int ncat_connect_mode(void);
|
||||
static int ncat_listen_mode(void);
|
||||
|
||||
/* Determines if it's parsing HTTP or SOCKS by looking at defport */
|
||||
static size_t parseproxy(char *str, struct sockaddr_storage *ss, unsigned short defport)
|
||||
static size_t parseproxy(char *str, struct sockaddr_storage *ss,
|
||||
size_t *sslen, unsigned short *portno)
|
||||
{
|
||||
char *c = strrchr(str, ':'), *ptr;
|
||||
int httpproxy = (defport == DEFAULT_PROXY_PORT);
|
||||
unsigned short portno;
|
||||
size_t sslen;
|
||||
int rc;
|
||||
|
||||
ptr = str;
|
||||
@@ -168,19 +166,17 @@ static size_t parseproxy(char *str, struct sockaddr_storage *ss, unsigned short
|
||||
*c = 0;
|
||||
|
||||
if (c && strlen((c + 1)))
|
||||
portno = (unsigned short) atoi(c + 1);
|
||||
else
|
||||
portno = defport;
|
||||
*portno = (unsigned short) atoi(c + 1);
|
||||
|
||||
rc = resolve(ptr, portno, ss, &sslen, o.af);
|
||||
rc = resolve(ptr, *portno, ss, sslen, o.af);
|
||||
if (rc != 0) {
|
||||
loguser("Could not resolve proxy \"%s\": %s.\n", ptr, gai_strerror(rc));
|
||||
if (o.af == AF_INET6 && httpproxy)
|
||||
if (o.af == AF_INET6 && *portno)
|
||||
loguser("Did you specify the port number? It's required for IPv6.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return sslen;
|
||||
return *sslen;
|
||||
}
|
||||
|
||||
/* These functions implement a simple linked list to hold allow/deny
|
||||
@@ -259,9 +255,9 @@ int main(int argc, char *argv[])
|
||||
struct host_list_node *allow_host_list = NULL;
|
||||
struct host_list_node *deny_host_list = NULL;
|
||||
|
||||
unsigned short proxyport = DEFAULT_PROXY_PORT;
|
||||
int srcport = -1;
|
||||
char *source = NULL;
|
||||
char *proxyaddr = NULL;
|
||||
|
||||
struct option long_options[] = {
|
||||
{"4", no_argument, NULL, '4'},
|
||||
@@ -457,17 +453,17 @@ int main(int argc, char *argv[])
|
||||
print_banner();
|
||||
exit(EXIT_SUCCESS);
|
||||
} else if (strcmp(long_options[option_index].name, "proxy") == 0) {
|
||||
if (proxyaddr)
|
||||
if (o.proxyaddr)
|
||||
bye("You can't specify more than one --proxy.");
|
||||
proxyaddr = Strdup(optarg);
|
||||
o.proxyaddr = optarg;
|
||||
} else if (strcmp(long_options[option_index].name, "proxy-type") == 0) {
|
||||
if (o.proxytype)
|
||||
bye("You can't specify more than one --proxy-type.");
|
||||
o.proxytype = Strdup(optarg);
|
||||
o.proxytype = optarg;
|
||||
} else if (strcmp(long_options[option_index].name, "proxy-auth") == 0) {
|
||||
if (o.proxy_auth)
|
||||
bye("You can't specify more than one --proxy-auth.");
|
||||
o.proxy_auth = Strdup(optarg);
|
||||
o.proxy_auth = optarg;
|
||||
} else if (strcmp(long_options[option_index].name, "nsock-engine") == 0) {
|
||||
if (nsock_set_default_engine(optarg) < 0)
|
||||
bye("Unknown or non-available engine: %s.", optarg);
|
||||
@@ -595,8 +591,9 @@ int main(int argc, char *argv[])
|
||||
" --broker Enable Ncat's connection brokering mode\n"
|
||||
" --chat Start a simple Ncat chat server\n"
|
||||
" --proxy <addr[:port]> Specify address of host to proxy through\n"
|
||||
" --proxy-type <type> Specify proxy type (\"http\" or \"socks4\")\n"
|
||||
" --proxy-type <type> Specify proxy type (\"http\" or \"socks4\" or \"socks5\")\n"
|
||||
" --proxy-auth <auth> Authenticate with HTTP or SOCKS proxy server\n"
|
||||
|
||||
#ifdef HAVE_OPENSSL
|
||||
" --ssl Connect or listen with SSL\n"
|
||||
" --ssl-cert Specify SSL certificate file (PEM) for listening\n"
|
||||
@@ -634,7 +631,7 @@ int main(int argc, char *argv[])
|
||||
#if HAVE_SYS_UN_H
|
||||
/* Using Unix domain sockets, so do the checks now */
|
||||
if (o.af == AF_UNIX) {
|
||||
if (proxyaddr || o.proxytype)
|
||||
if (o.proxyaddr || o.proxytype)
|
||||
bye("Proxy option not supported when using Unix domain sockets.");
|
||||
#ifdef HAVE_OPENSSL
|
||||
if (o.ssl)
|
||||
@@ -652,7 +649,7 @@ int main(int argc, char *argv[])
|
||||
/* Will be AF_INET or AF_INET6 or AF_UNIX when valid */
|
||||
memset(&targetss.storage, 0, sizeof(targetss.storage));
|
||||
targetss.storage.ss_family = AF_UNSPEC;
|
||||
httpconnect.storage = socksconnect.storage = srcaddr.storage = targetss.storage;
|
||||
srcaddr.storage = targetss.storage;
|
||||
|
||||
/* Clear the listenaddrs array */
|
||||
int i;
|
||||
@@ -660,28 +657,32 @@ int main(int argc, char *argv[])
|
||||
listenaddrs[i].storage = targetss.storage;
|
||||
}
|
||||
|
||||
if (proxyaddr) {
|
||||
if (o.proxyaddr) {
|
||||
if (!o.proxytype)
|
||||
o.proxytype = Strdup("http");
|
||||
|
||||
if (!strcmp(o.proxytype, "http")) {
|
||||
/* Parse HTTP proxy address and temporarily store it in httpconnect. If
|
||||
* the proxy server is given as an IPv6 address (not hostname), the port
|
||||
* number MUST be specified as well or parsing will break (due to the
|
||||
* colons in the IPv6 address and host:port separator).
|
||||
if (!strcmp(o.proxytype, "http") ||
|
||||
!strcmp(o.proxytype, "socks4") || !strcmp(o.proxytype, "4") ||
|
||||
!strcmp(o.proxytype, "socks5") || !strcmp(o.proxytype, "5")) {
|
||||
/* Parse HTTP/SOCKS proxy address and store it in targetss.
|
||||
* If the proxy server is given as an IPv6 address (not hostname),
|
||||
* the port number MUST be specified as well or parsing will break
|
||||
* (due to the colons in the IPv6 address and host:port separator).
|
||||
*/
|
||||
|
||||
httpconnectlen = parseproxy(proxyaddr, &httpconnect.storage, DEFAULT_PROXY_PORT);
|
||||
} else if (!strcmp(o.proxytype, "socks4") || !strcmp(o.proxytype, "4")) {
|
||||
/* Parse SOCKS proxy address and temporarily store it in socksconnect */
|
||||
|
||||
socksconnectlen = parseproxy(proxyaddr, &socksconnect.storage, DEFAULT_SOCKS4_PORT);
|
||||
targetsslen = parseproxy(o.proxyaddr,
|
||||
&targetss.storage, &targetsslen, &proxyport);
|
||||
if (o.af == AF_INET) {
|
||||
targetss.in.sin_port = htons(proxyport);
|
||||
} else { // might modify to else if and test AF_{INET6|UNIX|UNSPEC}
|
||||
targetss.in6.sin6_port = htons(proxyport);
|
||||
}
|
||||
} else {
|
||||
bye("Invalid proxy type \"%s\".", o.proxytype);
|
||||
}
|
||||
|
||||
free(o.proxytype);
|
||||
free(proxyaddr);
|
||||
if (o.listen)
|
||||
bye("Invalid option combination: --proxy and -l.");
|
||||
} else {
|
||||
if (o.proxytype) {
|
||||
if (!o.listen)
|
||||
@@ -692,7 +693,10 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
/* Default port */
|
||||
o.portno = DEFAULT_NCAT_PORT;
|
||||
if (o.listen && o.proxytype && !o.portno && srcport == -1)
|
||||
o.portno = DEFAULT_PROXY_PORT;
|
||||
else
|
||||
o.portno = DEFAULT_NCAT_PORT;
|
||||
|
||||
/* Resolve the given source address */
|
||||
if (source) {
|
||||
@@ -753,9 +757,12 @@ int main(int argc, char *argv[])
|
||||
int rc;
|
||||
|
||||
o.target = argv[optind];
|
||||
/* resolve hostname */
|
||||
rc = resolve(o.target, 0, &targetss.storage, &targetsslen, o.af);
|
||||
if (rc != 0)
|
||||
/* resolve hostname only if o.proxytype == NULL
|
||||
* targetss contains data already and you don't want remove them
|
||||
*/
|
||||
if( !o.proxytype
|
||||
&& (rc = resolve(o.target, 0, &targetss.storage, &targetsslen, o.af)) != 0)
|
||||
|
||||
bye("Could not resolve hostname \"%s\": %s.", o.target, gai_strerror(rc));
|
||||
optind++;
|
||||
} else {
|
||||
@@ -790,7 +797,9 @@ int main(int argc, char *argv[])
|
||||
o.portno = (unsigned short) long_port;
|
||||
}
|
||||
|
||||
if (targetss.storage.ss_family == AF_INET)
|
||||
if (o.proxytype && !o.listen)
|
||||
; /* Do nothing - port is already set to proxyport */
|
||||
else if (targetss.storage.ss_family == AF_INET)
|
||||
targetss.in.sin_port = htons(o.portno);
|
||||
#ifdef HAVE_IPV6
|
||||
else if (targetss.storage.ss_family == AF_INET6)
|
||||
@@ -831,25 +840,6 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
/* Since the host we're actually *connecting* to is the proxy server, we
|
||||
* need to reverse these address structures to avoid any further confusion
|
||||
*/
|
||||
if (httpconnect.storage.ss_family != AF_UNSPEC) {
|
||||
union sockaddr_u tmp = targetss;
|
||||
size_t tmplen = targetsslen;
|
||||
targetss = httpconnect;
|
||||
targetsslen = httpconnectlen;
|
||||
httpconnect = tmp;
|
||||
httpconnectlen = tmplen;
|
||||
} else if (socksconnect.storage.ss_family != AF_UNSPEC) {
|
||||
union sockaddr_u tmp = targetss;
|
||||
size_t tmplen = targetsslen;
|
||||
targetss = socksconnect;
|
||||
targetsslen = socksconnectlen;
|
||||
socksconnect = tmp;
|
||||
socksconnectlen = tmplen;
|
||||
}
|
||||
|
||||
if (o.proto == IPPROTO_UDP) {
|
||||
/* Don't allow a false sense of security if someone tries SSL over UDP. */
|
||||
if (o.ssl)
|
||||
@@ -904,7 +894,7 @@ static int ncat_connect_mode(void)
|
||||
static int ncat_listen_mode(void)
|
||||
{
|
||||
/* Can't 'listen' AND 'connect' to a proxy server at the same time. */
|
||||
if (httpconnect.storage.ss_family != AF_UNSPEC || socksconnect.storage.ss_family != AF_UNSPEC)
|
||||
if (o.proxyaddr != NULL)
|
||||
bye("Invalid option combination: --proxy and -l.");
|
||||
|
||||
if (o.broker && o.cmdexec != NULL)
|
||||
|
||||
@@ -10,8 +10,10 @@ use File::Temp qw/ tempfile /;
|
||||
use URI::Escape;
|
||||
use Data::Dumper;
|
||||
use Socket;
|
||||
use Socket6;
|
||||
use Digest::MD5 qw/md5_hex/;
|
||||
use POSIX ":sys_wait_h";
|
||||
use Fcntl qw(F_GETFL F_SETFL O_NONBLOCK);
|
||||
|
||||
use IPC::Open3;
|
||||
use strict;
|
||||
@@ -2767,6 +2769,279 @@ sub {
|
||||
};
|
||||
kill_children;
|
||||
|
||||
# expand IPv6
|
||||
sub ipv6_expand {
|
||||
local($_) = shift;
|
||||
s/^:/0:/;
|
||||
s/:$/:0/;
|
||||
s/(^|:)([^:]{1,3})(?=:|$)/$1.substr("0000$2", -4)/ge;
|
||||
my $c = tr/:/:/;
|
||||
s/::/":".("0000:" x (8-$c))/e;
|
||||
return $_;
|
||||
}
|
||||
sub socks5_auth {
|
||||
my ($pid,$code);
|
||||
my $buf="";
|
||||
my @Barray;
|
||||
my $auth_data = shift;
|
||||
my $ipvx = shift;
|
||||
my $dest_addr = shift;
|
||||
my $passed = 0;
|
||||
|
||||
my $username= "";
|
||||
my $passwd= "";
|
||||
my $recv_addr = "";
|
||||
my $recv_port;
|
||||
|
||||
my ($pf,$s_addr);
|
||||
|
||||
local $SIG{CHLD} = sub { };
|
||||
local *SOCK;
|
||||
local *S;
|
||||
|
||||
if ($ipvx eq -4) {
|
||||
$pf = PF_INET;
|
||||
$s_addr = sockaddr_in($PROXY_PORT, INADDR_ANY);
|
||||
} else {
|
||||
$pf = PF_INET6;
|
||||
$s_addr = sockaddr_in6($PROXY_PORT, inet_pton(PF_INET6, "::1"));
|
||||
}
|
||||
|
||||
|
||||
socket(SOCK, $pf, SOCK_STREAM, getprotobyname("tcp")) or die;
|
||||
setsockopt(SOCK, SOL_SOCKET, SO_REUSEADDR, pack("l", 1)) or die;
|
||||
bind(SOCK, $s_addr) or die;
|
||||
listen(SOCK, 1) or die;
|
||||
|
||||
my ($c_pid, $c_out, $c_in) = ncat("--proxy-type", "socks5", "--proxy", "localhost:$PROXY_PORT", @$auth_data, $ipvx, $dest_addr, $PORT);
|
||||
|
||||
accept(S, SOCK) or die "Client not connected";
|
||||
binmode(S);
|
||||
sysread(S, $buf, 10) or die "Connection closed";
|
||||
|
||||
@Barray = map hex($_), unpack("H*", $buf) =~ /(..)/g;
|
||||
die "wrong request format" if scalar(@Barray) < 3;
|
||||
die "wrong protocol version" if $Barray[0] != 5;
|
||||
|
||||
if(scalar(@$auth_data) > 0) {
|
||||
# subnegotiation for authentication
|
||||
for(my $i=2; $i < scalar(@Barray); $i++) {
|
||||
if($Barray[$i] == 2) {
|
||||
$passed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
die "Client did not sent required authentication method x02" if $passed == 0;
|
||||
|
||||
|
||||
send(S, "\x05\x02",0) or die "Send: Connection closed";
|
||||
sysread(S, $buf, $BUFSIZ) or die "Read: Connection closed";
|
||||
|
||||
@Barray = map hex($_), unpack("H*", $buf) =~ /(..)/g;
|
||||
die "wrong request format - small length" if scalar(@Barray) < 5;
|
||||
die "wrong request format - wrong version" if $Barray[0] != 1;
|
||||
die "wrong request format - username legth longer then packet size"
|
||||
if $Barray[1] >= scalar(@Barray);
|
||||
|
||||
# get username
|
||||
for (my $i=2; $i < $Barray[1]+2; $i++) {
|
||||
$username .= chr($Barray[$i]);
|
||||
}
|
||||
|
||||
#get password
|
||||
for (my $i=3+$Barray[1]; $i < scalar(@Barray); $i++) {
|
||||
$passwd .= chr($Barray[$i]);
|
||||
}
|
||||
|
||||
if ($username ne "vasek" or $passwd ne "admin") {
|
||||
send(S, "\x01\x11", 0);
|
||||
# do not close connection - we can check if client try continue
|
||||
} else {
|
||||
send(S, "\x01\x00",0);
|
||||
}
|
||||
} else {
|
||||
# no authentication
|
||||
send(S, "\x05\x00",0) or die "Send: Connection closed";
|
||||
|
||||
}
|
||||
|
||||
sysread(S, $buf, $BUFSIZ) or die "Read: connection closed";
|
||||
|
||||
@Barray = map hex($_), unpack("H*", $buf) =~ /(..)/g;
|
||||
die "wrong request length format" if scalar(@Barray) < 10;
|
||||
die "wrong protocol version after success authentication" if $Barray[0] != 5;
|
||||
die "expected connect cmd" if $Barray[1] != 1;
|
||||
|
||||
if($Barray[3] == 1) {
|
||||
# IPv4
|
||||
|
||||
$recv_addr = $Barray[4] .".". $Barray[5] .".". $Barray[6] .".". $Barray[7];
|
||||
die "received wrong destination IPv4" if $recv_addr ne $dest_addr;
|
||||
} elsif ($Barray[3] == 4) {
|
||||
#IPv6
|
||||
|
||||
for(my $i=4; $i<20;$i++) {
|
||||
if($i > 4 and $i % 2 == 0) {
|
||||
$recv_addr .= ":";
|
||||
}
|
||||
$recv_addr .= sprintf("%02X",$Barray[$i]);
|
||||
}
|
||||
|
||||
die "received wrong destination IPv6" if $recv_addr ne ipv6_expand($dest_addr);
|
||||
} elsif ($Barray[3] == 3) {
|
||||
# domaint name
|
||||
|
||||
for my $i (@Barray[5..(scalar(@Barray)-3)]) {
|
||||
$recv_addr .= chr($i);
|
||||
}
|
||||
die "received wrong destination domain name" if $recv_addr ne $dest_addr;
|
||||
die "received wrong length of domain name" if length($recv_addr) != $Barray[4];
|
||||
} else {
|
||||
die "unknown ATYP: $Barray[3]";
|
||||
}
|
||||
|
||||
$recv_port = $Barray[-2]*256 + $Barray[-1];
|
||||
die "received wrong destination port" if $recv_port ne $PORT;
|
||||
|
||||
send(S, "\x05\x00\x00\x01\x00\x00\x00\x00\x00\x00", 0);
|
||||
|
||||
# check if connection is still open
|
||||
syswrite($c_in, "abc\n");
|
||||
sysread(S, $buf, 10) or die "Connection closed";
|
||||
|
||||
|
||||
close(S);
|
||||
close(SOCK);
|
||||
};
|
||||
|
||||
|
||||
test "SOCKS5 client, server require auth username/password (access allowed), IPv4",
|
||||
sub { socks5_auth(["--proxy-auth","vasek:admin"], "-4", "127.0.0.1"); };
|
||||
kill_children;
|
||||
|
||||
test "SOCKS5 client, server require auth username/password (access allowed), IPv6",
|
||||
sub { socks5_auth(["--proxy-auth","vasek:admin"], "-6", "::1"); };
|
||||
kill_children;
|
||||
|
||||
test "SOCKS5 client, server require auth username/password (access allowed), domain",
|
||||
sub { socks5_auth(["--proxy-auth","vasek:admin"], "-4", "www.seznam.cz"); };
|
||||
kill_children;
|
||||
|
||||
test "SOCKS5 client, server allows connection - no auth",
|
||||
sub { socks5_auth([], "-4", "127.0.0.1")};
|
||||
kill_children;
|
||||
{
|
||||
local $xfail = 1;
|
||||
test "SOCKS5 client, server require auth username/password (access denied)",
|
||||
sub { socks5_auth(["--proxy-auth","klara:admin"], "-4", "127.0.0.1"); };
|
||||
kill_children;
|
||||
|
||||
test "SOCKS5 client, server require auth username/password (too long login)",
|
||||
sub { socks5_auth(["--proxy-auth",'monika' x 100 . ':admindd'], "-4", "127.0.0.1");};
|
||||
kill_children;
|
||||
}
|
||||
|
||||
{
|
||||
local $xfail = 1;
|
||||
test "SOCKS5 client, server sends short response",
|
||||
sub {
|
||||
my ($pid,$code);
|
||||
my $buf="";
|
||||
local $SIG{CHLD} = sub { };
|
||||
local *SOCK;
|
||||
local *S;
|
||||
|
||||
socket(SOCK, PF_INET, SOCK_STREAM, getprotobyname("tcp")) or die;
|
||||
setsockopt(SOCK, SOL_SOCKET, SO_REUSEADDR, pack("l", 1)) or die;
|
||||
bind(SOCK, sockaddr_in($PROXY_PORT, INADDR_ANY)) or die;
|
||||
listen(SOCK, 1) or die;
|
||||
|
||||
my ($c_pid, $c_out, $c_in) = ncat("-4","--proxy-type", "socks5", "--proxy", "$HOST:$PROXY_PORT", "127.0.0.1", $PORT);
|
||||
|
||||
accept(S, SOCK) or die "Client not connected";
|
||||
binmode(S);
|
||||
sysread(S, $buf, 10) or die "Connection closed";
|
||||
# not important received data now,
|
||||
# when we know that's ok from test above
|
||||
|
||||
# we need O_NONBLOCK for read/write actions else
|
||||
# client block us until we kill process manually
|
||||
fcntl(S, F_SETFL, O_NONBLOCK) or
|
||||
die "Can't set flags for the socket: $!\n";
|
||||
send(S, "\x05", 0) or die "Send: Connection closed";
|
||||
|
||||
sysread(S, $buf, $BUFSIZ) or die "Connection closed";
|
||||
|
||||
close(S);
|
||||
close(SOCK);
|
||||
};
|
||||
kill_children;
|
||||
}
|
||||
|
||||
{
|
||||
local $xfail = 1;
|
||||
test "SOCKS5 client, server sends no acceptable auth method",
|
||||
sub {
|
||||
my ($pid,$code);
|
||||
my $buf="";
|
||||
my ($my_addr,$recv_addr,$recv_port);
|
||||
|
||||
local $SIG{CHLD} = sub { };
|
||||
local *SOCK;
|
||||
local *S;
|
||||
|
||||
socket(SOCK, PF_INET, SOCK_STREAM, getprotobyname("tcp")) or die;
|
||||
setsockopt(SOCK, SOL_SOCKET, SO_REUSEADDR, pack("l", 1)) or die;
|
||||
bind(SOCK, sockaddr_in($PROXY_PORT, INADDR_ANY)) or die;
|
||||
listen(SOCK, 1) or die;
|
||||
|
||||
my ($c_pid, $c_out, $c_in) = ncat("-4","--proxy-type", "socks5", "--proxy", "$HOST:$PROXY_PORT", "127.0.0.1", $PORT);
|
||||
|
||||
accept(S, SOCK) or die "Client not connected";
|
||||
binmode(S);
|
||||
sysread(S, $buf, 10) or die "Connection closed";
|
||||
|
||||
send(S, "\x05\xFF",0) or die "Send: Connection closed";
|
||||
sysread(S, $buf, $BUFSIZ) or die "Connection closed";
|
||||
|
||||
close(S);
|
||||
close(SOCK);
|
||||
};
|
||||
kill_children;
|
||||
}
|
||||
|
||||
{
|
||||
local $xfail = 1;
|
||||
test "SOCKS5 client, server sends unkown code",
|
||||
sub {
|
||||
my ($pid,$code);
|
||||
my $buf="";
|
||||
my ($my_addr,$recv_addr,$recv_port);
|
||||
|
||||
local $SIG{CHLD} = sub { };
|
||||
local *SOCK;
|
||||
local *S;
|
||||
|
||||
socket(SOCK, PF_INET, SOCK_STREAM, getprotobyname("tcp")) or die;
|
||||
setsockopt(SOCK, SOL_SOCKET, SO_REUSEADDR, pack("l", 1)) or die;
|
||||
bind(SOCK, sockaddr_in($PROXY_PORT, INADDR_ANY)) or die;
|
||||
listen(SOCK, 1) or die;
|
||||
|
||||
my ($c_pid, $c_out, $c_in) = ncat("-4","--proxy-type", "socks5", "--proxy", "$HOST:$PROXY_PORT", "127.0.0.1", $PORT);
|
||||
|
||||
accept(S, SOCK) or die "Client not connected";
|
||||
binmode(S);
|
||||
sysread(S, $buf, 10) or die "Connection closed";
|
||||
|
||||
send(S, "\x05\xAA",0) or die "Send: Connection closed";
|
||||
sysread(S, $buf, $BUFSIZ) or die "Connection closed";
|
||||
|
||||
close(S);
|
||||
close(SOCK);
|
||||
};
|
||||
kill_children;
|
||||
}
|
||||
|
||||
for my $count (0, 1, 10) {
|
||||
max_conns_test_tcp_sctp_ssl("--max-conns $count --keep-open", ["--keep-open"], [], $count);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user