2011-02-25 17:40:11 +08:00
|
|
|
/***************************************************************************
|
|
|
|
core.c - description
|
|
|
|
-------------------
|
|
|
|
begin : Tue May 14 2002
|
2011-09-03 04:53:50 +08:00
|
|
|
copyright : netcreature (C) 2002
|
|
|
|
email : netcreature@users.sourceforge.net
|
2011-11-07 00:46:11 +08:00
|
|
|
***************************************************************************
|
|
|
|
* GPL *
|
|
|
|
***************************************************************************
|
2011-02-25 17:40:11 +08:00
|
|
|
* *
|
|
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
|
|
* it under the terms of the GNU General Public License as published by *
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
|
|
* (at your option) any later version. *
|
|
|
|
* *
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdlib.h>
|
2011-09-03 01:55:50 +08:00
|
|
|
#include <string.h>
|
2011-02-25 17:40:11 +08:00
|
|
|
#include <errno.h>
|
|
|
|
#include <netdb.h>
|
|
|
|
|
|
|
|
#include <sys/utsname.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/socket.h>
|
2014-01-08 21:57:10 +08:00
|
|
|
#include <poll.h>
|
2011-02-25 17:40:11 +08:00
|
|
|
#include <sys/wait.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <time.h>
|
2011-09-03 04:53:50 +08:00
|
|
|
#include <sys/time.h>
|
2011-02-25 17:40:11 +08:00
|
|
|
#include <stdarg.h>
|
2012-07-16 07:05:28 +08:00
|
|
|
#include <assert.h>
|
2011-11-07 00:46:11 +08:00
|
|
|
|
2011-02-25 17:40:11 +08:00
|
|
|
#include "core.h"
|
2011-11-06 21:12:50 +08:00
|
|
|
#include "common.h"
|
experimental new feature: proxy_dns_daemon
since many users complain about issues with modern, ultracomplex
clusterfuck software such as chromium, nodejs, etc, i've reconsidered
one of my original ideas how to implement remote dns lookup support.
instead of having a background thread serving requests via a pipe,
the user manually starts a background daemon process before running
proxychains, and the two processes then communicate via UDP.
this requires much less hacks (like hooking of close() to prevent
pipes from getting closed) and doesn't need to call any async-signal
unsafe code like malloc(). this means it should be much more compatible
than the previous method, however it's not as practical and slightly
slower.
it's recommended that the proxychains4-daemon runs on localhost, and
if you use proxychains-ng a lot you might want to set ip up as a service
that starts on boot. a single proxychains4-daemon should theoretically
be able to serve many parallel proxychains4 instances, but this has not
yet been tested so far. it's also possible to run the daemon on other
computers, even over internet, but currently there is no error-checking/
timeout code at all; that means the UDP connection needs to be very
stable.
the library code used for the daemon sources are from my projects
libulz[0] and htab[1], and the server code is loosely based on
microsocks[2]. their licenses are all compatible with the GPL.
if not otherwise mentioned, they're released for this purpose under
the standard proxychains-ng license (see COPYING).
[0]: https://github.com/rofl0r/libulz
[1]: https://github.com/rofl0r/htab
[2]: https://github.com/rofl0r/microsocks
2020-09-24 05:00:29 +08:00
|
|
|
#include "rdns.h"
|
2018-12-02 21:48:43 +08:00
|
|
|
#include "mutex.h"
|
2011-02-25 17:40:11 +08:00
|
|
|
|
|
|
|
extern int tcp_read_time_out;
|
|
|
|
extern int tcp_connect_time_out;
|
|
|
|
extern int proxychains_quiet_mode;
|
2013-06-23 13:13:40 +08:00
|
|
|
extern unsigned int proxychains_proxy_offset;
|
2012-01-26 19:44:42 +08:00
|
|
|
extern unsigned int remote_dns_subnet;
|
2011-02-25 17:40:11 +08:00
|
|
|
|
2012-01-28 01:59:44 +08:00
|
|
|
static int poll_retry(struct pollfd *fds, nfds_t nfsd, int timeout) {
|
2011-11-06 21:12:50 +08:00
|
|
|
int ret;
|
|
|
|
int time_remain = timeout;
|
|
|
|
int time_elapsed = 0;
|
|
|
|
|
|
|
|
struct timeval start_time;
|
|
|
|
struct timeval tv;
|
|
|
|
|
|
|
|
gettimeofday(&start_time, NULL);
|
|
|
|
|
|
|
|
do {
|
|
|
|
//printf("Retry %d\n", time_remain);
|
|
|
|
ret = poll(fds, nfsd, time_remain);
|
|
|
|
gettimeofday(&tv, NULL);
|
2012-01-28 01:59:44 +08:00
|
|
|
time_elapsed = ((tv.tv_sec - start_time.tv_sec) * 1000 + (tv.tv_usec - start_time.tv_usec) / 1000);
|
2011-11-06 21:12:50 +08:00
|
|
|
//printf("Time elapsed %d\n", time_elapsed);
|
|
|
|
time_remain = timeout - time_elapsed;
|
2012-01-28 01:59:44 +08:00
|
|
|
} while(ret == -1 && errno == EINTR && time_remain > 0);
|
2012-01-28 00:55:37 +08:00
|
|
|
|
2011-11-06 21:12:50 +08:00
|
|
|
//if (ret == -1)
|
|
|
|
//printf("Return %d %d %s\n", ret, errno, strerror(errno));
|
|
|
|
return ret;
|
2011-02-25 22:18:29 +08:00
|
|
|
}
|
|
|
|
|
2012-01-28 01:59:44 +08:00
|
|
|
static void encode_base_64(char *src, char *dest, int max_len) {
|
2012-08-04 23:55:37 +08:00
|
|
|
static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
2012-01-28 01:59:44 +08:00
|
|
|
int n, l, i;
|
|
|
|
l = strlen(src);
|
|
|
|
max_len = (max_len - 1) / 4;
|
|
|
|
for(i = 0; i < max_len; i++, src += 3, l -= 3) {
|
2011-02-25 17:40:11 +08:00
|
|
|
switch (l) {
|
2012-01-28 01:59:44 +08:00
|
|
|
case 0:
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
n = src[0] << 16;
|
|
|
|
*dest++ = base64[(n >> 18) & 077];
|
|
|
|
*dest++ = base64[(n >> 12) & 077];
|
|
|
|
*dest++ = '=';
|
|
|
|
*dest++ = '=';
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
n = src[0] << 16 | src[1] << 8;
|
|
|
|
*dest++ = base64[(n >> 18) & 077];
|
|
|
|
*dest++ = base64[(n >> 12) & 077];
|
|
|
|
*dest++ = base64[(n >> 6) & 077];
|
|
|
|
*dest++ = '=';
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
n = src[0] << 16 | src[1] << 8 | src[2];
|
|
|
|
*dest++ = base64[(n >> 18) & 077];
|
|
|
|
*dest++ = base64[(n >> 12) & 077];
|
|
|
|
*dest++ = base64[(n >> 6) & 077];
|
|
|
|
*dest++ = base64[n & 077];
|
2011-02-25 17:40:11 +08:00
|
|
|
}
|
2012-01-28 01:59:44 +08:00
|
|
|
if(l < 3)
|
|
|
|
break;
|
2011-02-25 17:40:11 +08:00
|
|
|
}
|
2012-01-28 01:59:44 +08:00
|
|
|
*dest++ = 0;
|
2011-02-25 17:40:11 +08:00
|
|
|
}
|
|
|
|
|
2012-07-14 23:59:06 +08:00
|
|
|
void proxychains_write_log(char *str, ...) {
|
2019-02-28 21:22:13 +08:00
|
|
|
char buff[1024*4];
|
2011-11-06 21:12:50 +08:00
|
|
|
va_list arglist;
|
2012-01-28 01:59:44 +08:00
|
|
|
if(!proxychains_quiet_mode) {
|
|
|
|
va_start(arglist, str);
|
2012-07-14 23:59:06 +08:00
|
|
|
vsnprintf(buff, sizeof(buff), str, arglist);
|
2011-11-06 21:12:50 +08:00
|
|
|
va_end(arglist);
|
2012-07-14 23:59:06 +08:00
|
|
|
fprintf(stderr, "%s", buff);
|
|
|
|
fflush(stderr);
|
2011-11-06 21:12:50 +08:00
|
|
|
}
|
2011-02-25 17:40:11 +08:00
|
|
|
}
|
|
|
|
|
2012-01-28 01:59:44 +08:00
|
|
|
static int write_n_bytes(int fd, char *buff, size_t size) {
|
|
|
|
int i = 0;
|
|
|
|
size_t wrote = 0;
|
|
|
|
for(;;) {
|
|
|
|
i = write(fd, &buff[wrote], size - wrote);
|
|
|
|
if(i <= 0)
|
2011-09-04 07:45:16 +08:00
|
|
|
return i;
|
|
|
|
wrote += i;
|
2012-01-28 01:59:44 +08:00
|
|
|
if(wrote == size)
|
2011-09-04 07:45:16 +08:00
|
|
|
return wrote;
|
|
|
|
}
|
2011-02-25 17:40:11 +08:00
|
|
|
}
|
|
|
|
|
2012-01-28 01:59:44 +08:00
|
|
|
static int read_n_bytes(int fd, char *buff, size_t size) {
|
2011-09-04 07:45:16 +08:00
|
|
|
int ready;
|
|
|
|
size_t i;
|
|
|
|
struct pollfd pfd[1];
|
|
|
|
|
2012-01-28 01:59:44 +08:00
|
|
|
pfd[0].fd = fd;
|
|
|
|
pfd[0].events = POLLIN;
|
|
|
|
for(i = 0; i < size; i++) {
|
2011-09-04 07:45:16 +08:00
|
|
|
pfd[0].revents = 0;
|
|
|
|
ready = poll_retry(pfd, 1, tcp_read_time_out);
|
2012-01-28 01:59:44 +08:00
|
|
|
if(ready != 1 || !(pfd[0].revents & POLLIN) || 1 != read(fd, &buff[i], 1))
|
2011-09-04 07:45:16 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return (int) size;
|
2011-02-25 17:40:11 +08:00
|
|
|
}
|
|
|
|
|
2012-01-28 01:59:44 +08:00
|
|
|
static int timed_connect(int sock, const struct sockaddr *addr, socklen_t len) {
|
2011-09-03 04:53:50 +08:00
|
|
|
int ret, value;
|
|
|
|
socklen_t value_len;
|
2012-01-28 01:59:44 +08:00
|
|
|
struct pollfd pfd[1];
|
2012-11-07 23:49:14 +08:00
|
|
|
PFUNC();
|
2011-02-25 17:40:11 +08:00
|
|
|
|
2012-01-28 01:59:44 +08:00
|
|
|
pfd[0].fd = sock;
|
|
|
|
pfd[0].events = POLLOUT;
|
2011-02-25 17:40:11 +08:00
|
|
|
fcntl(sock, F_SETFL, O_NONBLOCK);
|
2012-01-28 01:59:44 +08:00
|
|
|
ret = true_connect(sock, addr, len);
|
2012-07-08 10:12:17 +08:00
|
|
|
PDEBUG("\nconnect ret=%d\n", ret);
|
|
|
|
|
2012-01-28 01:59:44 +08:00
|
|
|
if(ret == -1 && errno == EINPROGRESS) {
|
|
|
|
ret = poll_retry(pfd, 1, tcp_connect_time_out);
|
2012-07-08 10:12:17 +08:00
|
|
|
PDEBUG("\npoll ret=%d\n", ret);
|
2012-01-28 01:59:44 +08:00
|
|
|
if(ret == 1) {
|
|
|
|
value_len = sizeof(socklen_t);
|
|
|
|
getsockopt(sock, SOL_SOCKET, SO_ERROR, &value, &value_len);
|
2012-07-08 10:12:17 +08:00
|
|
|
PDEBUG("\nvalue=%d\n", value);
|
2012-01-28 01:59:44 +08:00
|
|
|
if(!value)
|
|
|
|
ret = 0;
|
2011-09-03 04:53:50 +08:00
|
|
|
else
|
2012-01-28 01:59:44 +08:00
|
|
|
ret = -1;
|
2011-02-25 22:18:29 +08:00
|
|
|
} else {
|
2012-01-28 01:59:44 +08:00
|
|
|
ret = -1;
|
2011-02-25 22:18:29 +08:00
|
|
|
}
|
|
|
|
} else {
|
2012-07-08 10:12:17 +08:00
|
|
|
#ifdef DEBUG
|
|
|
|
if(ret == -1)
|
|
|
|
perror("true_connect");
|
|
|
|
#endif
|
2012-01-28 01:59:44 +08:00
|
|
|
if(ret != 0)
|
|
|
|
ret = -1;
|
2012-01-28 00:55:37 +08:00
|
|
|
}
|
2011-02-25 17:40:11 +08:00
|
|
|
|
2011-02-25 22:18:29 +08:00
|
|
|
fcntl(sock, F_SETFL, !O_NONBLOCK);
|
|
|
|
return ret;
|
2011-02-25 17:40:11 +08:00
|
|
|
}
|
|
|
|
|
2011-11-06 21:12:50 +08:00
|
|
|
|
|
|
|
#define INVALID_INDEX 0xFFFFFFFFU
|
2020-10-26 11:03:08 +08:00
|
|
|
#define BUFF_SIZE 1024 // used to read responses from proxies.
|
2012-01-28 01:59:44 +08:00
|
|
|
static int tunnel_to(int sock, ip_type ip, unsigned short port, proxy_type pt, char *user, char *pass) {
|
|
|
|
char *dns_name = NULL;
|
2012-11-08 03:11:14 +08:00
|
|
|
char hostnamebuf[MSG_LEN_MAX];
|
2011-11-06 21:12:50 +08:00
|
|
|
size_t dns_len = 0;
|
2012-01-28 00:55:37 +08:00
|
|
|
|
2012-11-07 23:49:14 +08:00
|
|
|
PFUNC();
|
2012-01-28 02:14:17 +08:00
|
|
|
|
2011-11-06 21:12:50 +08:00
|
|
|
// we use ip addresses with 224.* to lookup their dns name in our table, to allow remote DNS resolution
|
|
|
|
// the range 224-255.* is reserved, and it won't go outside (unless the app does some other stuff with
|
|
|
|
// the results returned from gethostbyname et al.)
|
2012-01-26 19:44:42 +08:00
|
|
|
// the hardcoded number 224 can now be changed using the config option remote_dns_subnet to i.e. 127
|
experimental new feature: proxy_dns_daemon
since many users complain about issues with modern, ultracomplex
clusterfuck software such as chromium, nodejs, etc, i've reconsidered
one of my original ideas how to implement remote dns lookup support.
instead of having a background thread serving requests via a pipe,
the user manually starts a background daemon process before running
proxychains, and the two processes then communicate via UDP.
this requires much less hacks (like hooking of close() to prevent
pipes from getting closed) and doesn't need to call any async-signal
unsafe code like malloc(). this means it should be much more compatible
than the previous method, however it's not as practical and slightly
slower.
it's recommended that the proxychains4-daemon runs on localhost, and
if you use proxychains-ng a lot you might want to set ip up as a service
that starts on boot. a single proxychains4-daemon should theoretically
be able to serve many parallel proxychains4 instances, but this has not
yet been tested so far. it's also possible to run the daemon on other
computers, even over internet, but currently there is no error-checking/
timeout code at all; that means the UDP connection needs to be very
stable.
the library code used for the daemon sources are from my projects
libulz[0] and htab[1], and the server code is loosely based on
microsocks[2]. their licenses are all compatible with the GPL.
if not otherwise mentioned, they're released for this purpose under
the standard proxychains-ng license (see COPYING).
[0]: https://github.com/rofl0r/libulz
[1]: https://github.com/rofl0r/htab
[2]: https://github.com/rofl0r/microsocks
2020-09-24 05:00:29 +08:00
|
|
|
if(!ip.is_v6 && proxychains_resolver >= DNSLF_RDNS_START && ip.addr.v4.octet[0] == remote_dns_subnet) {
|
|
|
|
dns_len = rdns_get_host_for_ip(ip.addr.v4, hostnamebuf);
|
2012-11-08 03:11:14 +08:00
|
|
|
if(!dns_len) goto err;
|
|
|
|
else dns_name = hostnamebuf;
|
2011-11-06 21:12:50 +08:00
|
|
|
}
|
2012-07-09 03:23:39 +08:00
|
|
|
|
|
|
|
PDEBUG("host dns %s\n", dns_name ? dns_name : "<NULL>");
|
2012-01-28 00:55:37 +08:00
|
|
|
|
2011-11-06 21:12:50 +08:00
|
|
|
size_t ulen = strlen(user);
|
|
|
|
size_t passlen = strlen(pass);
|
2012-01-28 00:55:37 +08:00
|
|
|
|
2011-11-08 00:07:00 +08:00
|
|
|
if(ulen > 0xFF || passlen > 0xFF || dns_len > 0xFF) {
|
|
|
|
proxychains_write_log(LOG_PREFIX "error: maximum size of 255 for user/pass or domain name!\n");
|
|
|
|
goto err;
|
|
|
|
}
|
2012-01-28 00:55:37 +08:00
|
|
|
|
2012-01-28 01:59:44 +08:00
|
|
|
int len;
|
|
|
|
unsigned char buff[BUFF_SIZE];
|
2015-08-10 23:59:31 +08:00
|
|
|
char ip_buf[INET6_ADDRSTRLEN];
|
|
|
|
int v6 = ip.is_v6;
|
2012-01-28 03:00:22 +08:00
|
|
|
|
2012-01-28 01:59:44 +08:00
|
|
|
switch (pt) {
|
2020-12-12 16:25:36 +08:00
|
|
|
case RAW_TYPE: {
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
break;
|
2012-01-28 01:59:44 +08:00
|
|
|
case HTTP_TYPE:{
|
2015-06-14 03:32:15 +08:00
|
|
|
if(!dns_len) {
|
2015-08-10 23:59:31 +08:00
|
|
|
if(!inet_ntop(v6?AF_INET6:AF_INET,ip.addr.v6,ip_buf,sizeof ip_buf)) {
|
|
|
|
proxychains_write_log(LOG_PREFIX "error: ip address conversion failed\n");
|
|
|
|
goto err;
|
|
|
|
}
|
2015-06-14 03:32:15 +08:00
|
|
|
dns_name = ip_buf;
|
|
|
|
}
|
|
|
|
#define HTTP_AUTH_MAX ((0xFF * 2) + 1 + 1) /* 2 * 0xff: username and pass, plus 1 for ':' and 1 for zero terminator. */
|
|
|
|
char src[HTTP_AUTH_MAX];
|
|
|
|
char dst[(4 * HTTP_AUTH_MAX)];
|
2015-06-14 19:07:19 +08:00
|
|
|
if(ulen) {
|
2015-06-14 03:32:15 +08:00
|
|
|
snprintf(src, sizeof(src), "%s:%s", user, pass);
|
|
|
|
encode_base_64(src, dst, sizeof(dst));
|
|
|
|
} else dst[0] = 0;
|
|
|
|
|
2016-12-09 12:44:56 +08:00
|
|
|
uint16_t hs_port = ntohs(port);
|
2015-06-14 03:32:15 +08:00
|
|
|
len = snprintf((char *) buff, sizeof(buff),
|
2016-12-09 12:44:56 +08:00
|
|
|
"CONNECT %s:%d HTTP/1.0\r\nHost: %s:%d\r\n%s%s%s\r\n",
|
|
|
|
dns_name, hs_port,
|
|
|
|
dns_name, hs_port,
|
2015-06-14 19:07:19 +08:00
|
|
|
ulen ? "Proxy-Authorization: Basic " : dst,
|
|
|
|
dst, ulen ? "\r\n" : dst);
|
2015-06-14 03:32:15 +08:00
|
|
|
|
2016-12-21 06:18:21 +08:00
|
|
|
if(len < 0 || len != send(sock, buff, len, 0))
|
2015-06-14 03:32:15 +08:00
|
|
|
goto err;
|
|
|
|
|
|
|
|
len = 0;
|
|
|
|
// read header byte by byte.
|
|
|
|
while(len < BUFF_SIZE) {
|
|
|
|
if(1 == read_n_bytes(sock, (char *) (buff + len), 1))
|
|
|
|
len++;
|
|
|
|
else
|
2011-11-06 21:12:50 +08:00
|
|
|
goto err;
|
2015-06-14 03:32:15 +08:00
|
|
|
if(len > 4 &&
|
|
|
|
buff[len - 1] == '\n' &&
|
|
|
|
buff[len - 2] == '\r' && buff[len - 3] == '\n' && buff[len - 4] == '\r')
|
|
|
|
break;
|
|
|
|
}
|
2012-01-28 01:59:44 +08:00
|
|
|
|
2015-06-14 03:32:15 +08:00
|
|
|
// if not ok (200) or response greather than BUFF_SIZE return BLOCKED;
|
|
|
|
if(len == BUFF_SIZE || !(buff[9] == '2' && buff[10] == '0' && buff[11] == '0')) {
|
|
|
|
PDEBUG("HTTP proxy blocked: buff=\"%s\"\n", buff);
|
|
|
|
return BLOCKED;
|
2011-11-06 21:12:50 +08:00
|
|
|
}
|
|
|
|
|
2015-06-14 03:32:15 +08:00
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
break;
|
2012-01-28 01:59:44 +08:00
|
|
|
case SOCKS4_TYPE:{
|
2015-08-10 23:59:31 +08:00
|
|
|
if(v6) {
|
2016-12-05 11:10:09 +08:00
|
|
|
proxychains_write_log(LOG_PREFIX "error: SOCKS4 doesn't support ipv6 addresses\n");
|
2015-08-10 23:59:31 +08:00
|
|
|
goto err;
|
|
|
|
}
|
2015-06-14 03:32:15 +08:00
|
|
|
buff[0] = 4; // socks version
|
|
|
|
buff[1] = 1; // connect command
|
|
|
|
memcpy(&buff[2], &port, 2); // dest port
|
|
|
|
if(dns_len) {
|
2015-08-10 23:59:31 +08:00
|
|
|
ip.addr.v4.octet[0] = 0;
|
|
|
|
ip.addr.v4.octet[1] = 0;
|
|
|
|
ip.addr.v4.octet[2] = 0;
|
|
|
|
ip.addr.v4.octet[3] = 1;
|
2015-06-14 03:32:15 +08:00
|
|
|
}
|
2015-08-10 23:59:31 +08:00
|
|
|
memcpy(&buff[4], &ip.addr.v4, 4); // dest host
|
2015-06-14 03:32:15 +08:00
|
|
|
len = ulen + 1; // username
|
|
|
|
if(len > 1)
|
|
|
|
memcpy(&buff[8], user, len);
|
|
|
|
else {
|
|
|
|
buff[8] = 0;
|
|
|
|
}
|
2012-01-28 00:55:37 +08:00
|
|
|
|
2015-06-14 03:32:15 +08:00
|
|
|
// do socksv4a dns resolution on the server
|
|
|
|
if(dns_len) {
|
|
|
|
memcpy(&buff[8 + len], dns_name, dns_len + 1);
|
|
|
|
len += dns_len + 1;
|
|
|
|
}
|
2012-01-28 00:55:37 +08:00
|
|
|
|
2015-06-14 03:32:15 +08:00
|
|
|
if((len + 8) != write_n_bytes(sock, (char *) buff, (8 + len)))
|
|
|
|
goto err;
|
2011-11-06 21:12:50 +08:00
|
|
|
|
2015-06-14 03:32:15 +08:00
|
|
|
if(8 != read_n_bytes(sock, (char *) buff, 8))
|
|
|
|
goto err;
|
2012-01-28 00:55:37 +08:00
|
|
|
|
2015-06-14 03:32:15 +08:00
|
|
|
if(buff[0] != 0 || buff[1] != 90)
|
|
|
|
return BLOCKED;
|
2011-11-06 21:12:50 +08:00
|
|
|
|
2015-06-14 03:32:15 +08:00
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
break;
|
2012-01-28 01:59:44 +08:00
|
|
|
case SOCKS5_TYPE:{
|
2015-06-14 19:07:19 +08:00
|
|
|
int n_methods = ulen ? 2 : 1;
|
2015-06-14 03:32:15 +08:00
|
|
|
buff[0] = 5; // version
|
|
|
|
buff[1] = n_methods ; // number of methods
|
|
|
|
buff[2] = 0; // no auth method
|
2015-06-14 19:07:19 +08:00
|
|
|
if(ulen) buff[3] = 2; /// auth method -> username / password
|
2015-06-14 03:32:15 +08:00
|
|
|
if(2+n_methods != write_n_bytes(sock, (char *) buff, 2+n_methods))
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
if(2 != read_n_bytes(sock, (char *) buff, 2))
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
if(buff[0] != 5 || (buff[1] != 0 && buff[1] != 2)) {
|
|
|
|
if(buff[0] == 5 && buff[1] == 0xFF)
|
|
|
|
return BLOCKED;
|
|
|
|
else
|
2015-06-14 02:02:11 +08:00
|
|
|
goto err;
|
2015-06-14 03:32:15 +08:00
|
|
|
}
|
2012-01-28 01:59:44 +08:00
|
|
|
|
2015-06-14 03:32:15 +08:00
|
|
|
if(buff[1] == 2) {
|
|
|
|
// authentication
|
|
|
|
char in[2];
|
|
|
|
char out[515];
|
|
|
|
char *cur = out;
|
|
|
|
size_t c;
|
|
|
|
*cur++ = 1; // version
|
|
|
|
c = ulen & 0xFF;
|
|
|
|
*cur++ = c;
|
|
|
|
memcpy(cur, user, c);
|
|
|
|
cur += c;
|
|
|
|
c = passlen & 0xFF;
|
|
|
|
*cur++ = c;
|
|
|
|
memcpy(cur, pass, c);
|
|
|
|
cur += c;
|
|
|
|
|
|
|
|
if((cur - out) != write_n_bytes(sock, out, cur - out))
|
2011-11-06 21:12:50 +08:00
|
|
|
goto err;
|
2011-02-25 17:40:11 +08:00
|
|
|
|
2012-01-28 00:55:37 +08:00
|
|
|
|
2015-06-14 03:32:15 +08:00
|
|
|
if(2 != read_n_bytes(sock, in, 2))
|
|
|
|
goto err;
|
2018-05-30 01:59:25 +08:00
|
|
|
/* according to RFC 1929 the version field for the user/pass auth sub-
|
|
|
|
negotiation should be 1, which is kinda counter-intuitive, so there
|
|
|
|
are some socks5 proxies that return 5 instead. other programs like
|
|
|
|
curl work fine when the version is 5, so let's do the same and accept
|
|
|
|
either of them. */
|
|
|
|
if(!(in[0] == 5 || in[0] == 1))
|
|
|
|
goto err;
|
|
|
|
if(in[1] != 0)
|
|
|
|
return BLOCKED;
|
2015-06-14 03:32:15 +08:00
|
|
|
}
|
|
|
|
int buff_iter = 0;
|
|
|
|
buff[buff_iter++] = 5; // version
|
|
|
|
buff[buff_iter++] = 1; // connect
|
|
|
|
buff[buff_iter++] = 0; // reserved
|
|
|
|
|
|
|
|
if(!dns_len) {
|
2015-08-10 23:59:31 +08:00
|
|
|
buff[buff_iter++] = v6 ? 4 : 1; // ip v4/v6
|
|
|
|
memcpy(buff + buff_iter, ip.addr.v6, v6?16:4); // dest host
|
|
|
|
buff_iter += v6?16:4;
|
2015-06-14 03:32:15 +08:00
|
|
|
} else {
|
|
|
|
buff[buff_iter++] = 3; //dns
|
|
|
|
buff[buff_iter++] = dns_len & 0xFF;
|
|
|
|
memcpy(buff + buff_iter, dns_name, dns_len);
|
|
|
|
buff_iter += dns_len;
|
|
|
|
}
|
2012-01-28 00:55:37 +08:00
|
|
|
|
2015-06-14 03:32:15 +08:00
|
|
|
memcpy(buff + buff_iter, &port, 2); // dest port
|
|
|
|
buff_iter += 2;
|
2011-02-25 17:40:11 +08:00
|
|
|
|
2012-01-28 00:55:37 +08:00
|
|
|
|
2015-06-14 03:32:15 +08:00
|
|
|
if(buff_iter != write_n_bytes(sock, (char *) buff, buff_iter))
|
|
|
|
goto err;
|
2011-02-25 17:40:11 +08:00
|
|
|
|
2015-06-14 03:32:15 +08:00
|
|
|
if(4 != read_n_bytes(sock, (char *) buff, 4))
|
|
|
|
goto err;
|
2011-02-25 17:40:11 +08:00
|
|
|
|
2015-06-14 03:32:15 +08:00
|
|
|
if(buff[0] != 5 || buff[1] != 0)
|
|
|
|
goto err;
|
2012-01-28 00:55:37 +08:00
|
|
|
|
2015-06-14 03:32:15 +08:00
|
|
|
switch (buff[3]) {
|
|
|
|
case 1:
|
|
|
|
len = 4;
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
len = 16;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
len = 0;
|
|
|
|
if(1 != read_n_bytes(sock, (char *) &len, 1))
|
2011-11-06 21:12:50 +08:00
|
|
|
goto err;
|
2015-06-14 03:32:15 +08:00
|
|
|
break;
|
|
|
|
default:
|
2012-01-28 01:59:44 +08:00
|
|
|
goto err;
|
|
|
|
}
|
2015-06-14 03:32:15 +08:00
|
|
|
|
|
|
|
if(len + 2 != read_n_bytes(sock, (char *) buff, len + 2))
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
break;
|
2011-11-06 21:12:50 +08:00
|
|
|
}
|
2011-02-25 17:40:11 +08:00
|
|
|
|
2011-11-06 21:12:50 +08:00
|
|
|
err:
|
|
|
|
return SOCKET_ERROR;
|
2011-02-25 17:40:11 +08:00
|
|
|
}
|
|
|
|
|
2023-09-06 08:22:35 +08:00
|
|
|
|
2023-09-08 20:42:52 +08:00
|
|
|
/* Given a socket connected to a SOCKS5 proxy server, performs a UDP_ASSOCIATE handshake and returns BND_ADDR and BND_PORT if successfull.
|
|
|
|
Pass NULL dst_addr and dst_port to fill those fields with 0 if expected local addr and port for udp sending are unknown (see RFC1928) */
|
2023-12-10 23:05:19 +08:00
|
|
|
static int udp_associate(int sock, ip_type* dst_addr, unsigned short dst_port, ip_type* bnd_addr, unsigned short* bnd_port, char* user, char* pass){
|
2023-09-06 08:22:35 +08:00
|
|
|
//TODO hugoc
|
2023-09-08 20:42:52 +08:00
|
|
|
|
|
|
|
PFUNC();
|
|
|
|
|
|
|
|
size_t ulen = strlen(user);
|
|
|
|
size_t passlen = strlen(pass);
|
|
|
|
|
|
|
|
if(ulen > 0xFF || passlen > 0xFF) {
|
|
|
|
proxychains_write_log(LOG_PREFIX "error: maximum size of 255 for user/pass!\n");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
int len;
|
|
|
|
unsigned char buff[BUFF_SIZE];
|
|
|
|
char ip_buf[INET6_ADDRSTRLEN];
|
|
|
|
|
|
|
|
int n_methods = ulen ? 2 : 1;
|
|
|
|
buff[0] = 5; // version
|
|
|
|
buff[1] = n_methods ; // number of methods
|
|
|
|
buff[2] = 0; // no auth method
|
|
|
|
if(ulen) buff[3] = 2; /// auth method -> username / password
|
|
|
|
if(2+n_methods != write_n_bytes(sock, (char *) buff, 2+n_methods))
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
if(2 != read_n_bytes(sock, (char *) buff, 2))
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
if(buff[0] != 5 || (buff[1] != 0 && buff[1] != 2)) {
|
|
|
|
if(buff[0] == 5 && buff[1] == 0xFF)
|
|
|
|
return BLOCKED;
|
|
|
|
else
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(buff[1] == 2) {
|
|
|
|
// authentication
|
|
|
|
char in[2];
|
|
|
|
char out[515];
|
|
|
|
char *cur = out;
|
|
|
|
size_t c;
|
|
|
|
*cur++ = 1; // version
|
|
|
|
c = ulen & 0xFF;
|
|
|
|
*cur++ = c;
|
|
|
|
memcpy(cur, user, c);
|
|
|
|
cur += c;
|
|
|
|
c = passlen & 0xFF;
|
|
|
|
*cur++ = c;
|
|
|
|
memcpy(cur, pass, c);
|
|
|
|
cur += c;
|
|
|
|
|
|
|
|
if((cur - out) != write_n_bytes(sock, out, cur - out))
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
|
|
|
|
if(2 != read_n_bytes(sock, in, 2))
|
|
|
|
goto err;
|
|
|
|
/* according to RFC 1929 the version field for the user/pass auth sub-
|
|
|
|
negotiation should be 1, which is kinda counter-intuitive, so there
|
|
|
|
are some socks5 proxies that return 5 instead. other programs like
|
|
|
|
curl work fine when the version is 5, so let's do the same and accept
|
|
|
|
either of them. */
|
|
|
|
if(!(in[0] == 5 || in[0] == 1))
|
|
|
|
goto err;
|
|
|
|
if(in[1] != 0)
|
|
|
|
return BLOCKED;
|
|
|
|
}
|
|
|
|
int buff_iter = 0;
|
|
|
|
buff[buff_iter++] = 5; // version
|
|
|
|
buff[buff_iter++] = 3; // udp_associate
|
|
|
|
buff[buff_iter++] = 0; // reserved
|
|
|
|
|
|
|
|
if(dst_addr) {
|
|
|
|
int v6 = dst_addr->is_v6;
|
|
|
|
buff[buff_iter++] = v6 ? 4 : 1; // ip v4/v6
|
|
|
|
memcpy(buff + buff_iter, dst_addr->addr.v6, v6?16:4); // dest host
|
|
|
|
buff_iter += v6?16:4;
|
|
|
|
memcpy(buff + buff_iter, &dst_port, 2); // dest port
|
|
|
|
buff_iter += 2;
|
|
|
|
} else {
|
|
|
|
buff[buff_iter++] = 1; //we put atyp = 1, should we put 0 ?
|
|
|
|
buff[buff_iter++] = 0; // v4 byte1
|
|
|
|
buff[buff_iter++] = 0; // v4 byte2
|
|
|
|
buff[buff_iter++] = 0; // v4 byte3
|
|
|
|
buff[buff_iter++] = 0; // v4 byte4
|
|
|
|
buff[buff_iter++] = 0; // port byte1
|
|
|
|
buff[buff_iter++] = 0; // port byte2
|
|
|
|
}
|
|
|
|
|
|
|
|
if(buff_iter != write_n_bytes(sock, (char *) buff, buff_iter))
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
if(4 != read_n_bytes(sock, (char *) buff, 4))
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
if(buff[0] != 5 || buff[1] != 0)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
|
|
|
|
switch (buff[3]) {
|
2023-12-10 23:05:19 +08:00
|
|
|
case ATYP_V4:
|
|
|
|
bnd_addr->is_v6 = 0;
|
2023-09-08 20:42:52 +08:00
|
|
|
break;
|
2023-12-10 23:05:19 +08:00
|
|
|
case ATYP_V6:
|
|
|
|
bnd_addr->is_v6 = 1;
|
2023-09-08 20:42:52 +08:00
|
|
|
break;
|
2023-12-10 23:05:19 +08:00
|
|
|
case ATYP_DOM:
|
2023-09-08 20:42:52 +08:00
|
|
|
PDEBUG("BND_ADDR in UDP_ASSOCIATE response should not be a domain name!\n");
|
|
|
|
goto err;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
goto err;
|
|
|
|
}
|
2023-12-10 23:05:19 +08:00
|
|
|
len = bnd_addr->is_v6?16:4;
|
2023-09-08 20:42:52 +08:00
|
|
|
|
|
|
|
if(len != read_n_bytes(sock, (char *) buff, len))
|
|
|
|
goto err;
|
|
|
|
|
2023-12-10 23:05:19 +08:00
|
|
|
memcpy(bnd_addr->addr.v6, buff,len);
|
2023-09-08 20:42:52 +08:00
|
|
|
|
|
|
|
if(2 != read_n_bytes(sock, (char *) buff, 2))
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
memcpy(bnd_port, buff, 2);
|
|
|
|
|
2023-09-06 08:22:35 +08:00
|
|
|
return SUCCESS;
|
2023-09-08 20:42:52 +08:00
|
|
|
|
|
|
|
err:
|
|
|
|
return SOCKET_ERROR;
|
2023-09-06 08:22:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Fills buf with the SOCKS5 udp request header for the target dst_addr:dst_port*/
|
2023-09-08 20:42:52 +08:00
|
|
|
static int write_udp_header(socks5_addr dst_addr, unsigned short dst_port , char frag, char * buf, size_t buflen) {
|
|
|
|
|
|
|
|
int size = 0;
|
|
|
|
int v6 = dst_addr.atyp == ATYP_V6;
|
2023-09-06 08:22:35 +08:00
|
|
|
|
2023-09-08 20:42:52 +08:00
|
|
|
if(dst_addr.atyp == ATYP_DOM){
|
|
|
|
size = dst_addr.addr.dom.len;
|
|
|
|
} else {
|
|
|
|
size = v6?16:4;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (buflen <= size) {
|
2023-09-06 08:22:35 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int buf_iter = 0;
|
|
|
|
buf[buf_iter++] = 0; // reserved
|
|
|
|
buf[buf_iter++] = 0; // reserved
|
|
|
|
buf[buf_iter++] = frag; // frag
|
|
|
|
buf[buf_iter++] = dst_addr.atyp; // atyp
|
|
|
|
|
2023-09-08 20:42:52 +08:00
|
|
|
|
2023-09-06 08:22:35 +08:00
|
|
|
switch (dst_addr.atyp){
|
|
|
|
case ATYP_V6:
|
|
|
|
case ATYP_V4:
|
|
|
|
memcpy(buf + buf_iter, dst_addr.addr.v6, v6?16:4);
|
|
|
|
buf_iter += v6?16:4;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ATYP_DOM:
|
|
|
|
buf[buf_iter++] = dst_addr.addr.dom.len;
|
|
|
|
memcpy(buf + buf_iter, dst_addr.addr.dom.name, dst_addr.addr.dom.len);
|
|
|
|
buf_iter += dst_addr.addr.dom.len;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(buf + buf_iter, &dst_port, 2); // dest port
|
|
|
|
buf_iter += 2;
|
|
|
|
|
|
|
|
return buf_iter;
|
|
|
|
}
|
|
|
|
|
2023-11-29 08:13:01 +08:00
|
|
|
|
|
|
|
int read_udp_header(char * buf, size_t buflen, socks5_addr* src_addr, unsigned short* src_port, char* frag) {
|
|
|
|
|
2023-12-10 23:05:19 +08:00
|
|
|
PFUNC();
|
|
|
|
PDEBUG("buflen : %d\n", buflen);
|
2023-11-29 08:13:01 +08:00
|
|
|
if (buflen < 5){
|
|
|
|
PDEBUG("buffer too short to contain a UDP header\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int buf_iter = 0;
|
|
|
|
buf_iter += 2; // first 2 bytes are reserved;
|
|
|
|
*frag = buf[buf_iter++];
|
|
|
|
src_addr->atyp = buf[buf_iter++];
|
2023-12-10 23:05:19 +08:00
|
|
|
int v6;
|
|
|
|
|
2023-11-29 08:13:01 +08:00
|
|
|
switch (src_addr->atyp)
|
|
|
|
{
|
|
|
|
case ATYP_DOM:
|
2023-12-10 23:05:19 +08:00
|
|
|
PDEBUG("UDP header with ATYP_DOM addr type\n");
|
2023-11-29 08:13:01 +08:00
|
|
|
src_addr->addr.dom.len = buf[buf_iter++];
|
2023-12-10 23:05:19 +08:00
|
|
|
if(buflen < (5 + 2 + src_addr->addr.dom.len) ) {
|
2023-11-29 08:13:01 +08:00
|
|
|
PDEBUG("buffer too short to read the UDP header\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
memcpy(src_addr->addr.dom.name, buf + buf_iter, src_addr->addr.dom.len);
|
|
|
|
buf_iter += src_addr->addr.dom.len;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ATYP_V4:
|
|
|
|
case ATYP_V6:
|
2023-12-10 23:05:19 +08:00
|
|
|
PDEBUG("UDP header with ATYP_V4/6 addr type\n");
|
|
|
|
v6 = src_addr->atyp == ATYP_V6;
|
|
|
|
PDEBUG("buflen : %d\n", buflen);
|
|
|
|
if(buflen < (4 + 2 + v6?16:4) ){
|
2023-11-29 08:13:01 +08:00
|
|
|
PDEBUG("buffer too short to read the UDP header\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
memcpy(src_addr->addr.v6, buf + buf_iter, v6?16:4);
|
|
|
|
buf_iter += v6?16:4;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(src_port, buf+buf_iter, 2);
|
|
|
|
buf_iter += 2;
|
|
|
|
|
|
|
|
return buf_iter;
|
|
|
|
}
|
|
|
|
|
2023-12-10 23:05:19 +08:00
|
|
|
int receive_udp_packet(int sockfd, udp_relay_chain chain, ip_type* src_addr, unsigned short* src_port, char* data, unsigned int data_len ){
|
|
|
|
//receives data on sockfd, decapsulates the header for each relay in chain and check they match, returns UDP data and source address/port
|
|
|
|
|
|
|
|
PFUNC();
|
|
|
|
|
|
|
|
char buffer[65535]; //buffer to receive and decapsulate a UDP relay packet. UDP maxsize is 65535
|
|
|
|
int bytes_received;
|
|
|
|
struct sockaddr from;
|
|
|
|
socklen_t addrlen = sizeof(from);
|
|
|
|
PDEBUG("test\n");
|
|
|
|
|
|
|
|
bytes_received = true_recvfrom(sockfd, buffer,sizeof(buffer), 0, &from, &addrlen);
|
|
|
|
if(-1 == bytes_received){
|
|
|
|
PDEBUG("true_receive returned -1\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
PDEBUG("successful recvfrom(), %d bytes received\n", bytes_received);
|
|
|
|
//Check that the packet was received from the first relay of the chain
|
|
|
|
// i.e. does from == chain.head.bnd_addr ?
|
|
|
|
int from_isv6 = ((struct sockaddr_in *) &(from))->sin_family == AF_INET6;
|
|
|
|
int same_address = 0;
|
|
|
|
int same_port = 0;
|
|
|
|
|
|
|
|
if(chain.head->bnd_addr.is_v6){
|
|
|
|
if(from_isv6){
|
|
|
|
same_address = memcmp(((struct sockaddr_in6 *)&from)->sin6_addr.s6_addr, chain.head->bnd_addr.addr.v6, 16);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
uint32_t from_v4_asint;
|
|
|
|
if(from_isv6){
|
|
|
|
// Maybe from is a ipv4-mapped ipv6 ? // TODO: use the existing is_v4inv6 as in connect and sendto
|
|
|
|
memcpy(from_v4_asint, ((struct sockaddr_in6 *)&from)->sin6_addr.s6_addr + 11, 4);
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
from_v4_asint = (uint32_t)(((struct sockaddr_in *)&from)->sin_addr.s_addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
same_address = from_v4_asint == chain.head->bnd_addr.addr.v4.as_int;
|
|
|
|
}
|
|
|
|
|
|
|
|
same_port = chain.head->bnd_port == from_isv6?((struct sockaddr_in6 *)&from)->sin6_port:((struct sockaddr_in *)&from)->sin_port;
|
|
|
|
|
|
|
|
if(!(same_address && same_port)){
|
|
|
|
PDEBUG("UDP packet not received from the proxy chain's head, transfering it as is\n");
|
|
|
|
int min = (bytes_received <= data_len)?bytes_received:data_len;
|
|
|
|
memcpy(data, buffer, min);
|
|
|
|
return min;
|
|
|
|
}
|
|
|
|
|
|
|
|
PDEBUG("packet received from the proxy chain's head\n");
|
|
|
|
// Go through the whole proxy chain, decapsulate each header and check that the addresses match
|
|
|
|
|
|
|
|
udp_relay_node * tmp = chain.head;
|
|
|
|
int read = 0;
|
|
|
|
int rc = 0;
|
|
|
|
socks5_addr header_addr;
|
|
|
|
unsigned short header_port;
|
|
|
|
char header_frag;
|
|
|
|
while (tmp->next != NULL)
|
|
|
|
{
|
|
|
|
same_address = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
rc = read_udp_header(buffer+read, bytes_received-read, &header_addr, &header_port, &header_frag );
|
|
|
|
if(-1 == rc){
|
|
|
|
PDEBUG("error reading UDP header\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
read += rc;
|
|
|
|
|
|
|
|
int header_v6 = header_addr.atyp == ATYP_V6;
|
|
|
|
|
|
|
|
if(tmp->next->bnd_port != header_port){
|
|
|
|
PDEBUG("UDP header port is not equal to proxy node port, dropping packet\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(tmp->next->bnd_addr.is_v6){
|
|
|
|
if(header_v6){
|
|
|
|
same_address = memcmp(tmp->next->bnd_addr.addr.v6, header_addr.addr.v6, 16);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
same_address = memcmp(&(tmp->next->bnd_addr.addr.v4), header_v6?(&(header_addr.addr.v6)+11):&(header_addr.addr.v4), 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if(!same_address){
|
|
|
|
PDEBUG("UDP header addr is not equal to proxy node addr, dropping packet\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
PDEBUG("UDP header's addr and port correspond to proxy node's addr and port\n");
|
|
|
|
tmp = tmp->next;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
PDEBUG("all UDP headers validated\n");
|
|
|
|
|
|
|
|
|
|
|
|
// Decapsulate the last header. No checks needed here, just pass the source addr and port as return values
|
|
|
|
char frag;
|
|
|
|
rc = read_udp_header(buffer+read, bytes_received-read, &header_addr, src_port, &frag);
|
|
|
|
if(-1 == rc){
|
|
|
|
PDEBUG("error reading UDP header\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
read += rc;
|
|
|
|
|
|
|
|
if(header_addr.atyp == ATYP_DOM){ // do the reverse mapping
|
|
|
|
PDEBUG("Fetching matching IP for hostname\n");
|
|
|
|
DUMP_BUFFER(header_addr.addr.dom.name,header_addr.addr.dom.len);
|
|
|
|
ip_type4 tmp_ip = IPT4_INVALID;
|
|
|
|
char host_string[256];
|
|
|
|
memcpy(host_string, header_addr.addr.dom.name, header_addr.addr.dom.len);
|
|
|
|
host_string[header_addr.addr.dom.len] = 0x00;
|
|
|
|
|
|
|
|
tmp_ip = rdns_get_ip_for_host(host_string, header_addr.addr.dom.len);
|
|
|
|
if(tmp_ip.as_int == -1){
|
|
|
|
PDEBUG("No matching IP found for hostname\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
header_addr.atyp = ATYP_V4;
|
|
|
|
header_addr.addr.v4.as_int = tmp_ip.as_int;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
src_addr->is_v6 = (header_addr.atyp == ATYP_V6);
|
|
|
|
if(src_addr->is_v6){
|
|
|
|
memcpy(src_addr->addr.v6, header_addr.addr.v6, 16);
|
|
|
|
} else{
|
|
|
|
src_addr->addr.v4.as_int = header_addr.addr.v4.as_int;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int min = ((bytes_received-read)>data_len)?data_len:(bytes_received-read);
|
|
|
|
memcpy(data,buffer+read, min);
|
|
|
|
|
|
|
|
|
|
|
|
return min;
|
|
|
|
}
|
|
|
|
|
2023-09-08 20:42:52 +08:00
|
|
|
int send_udp_packet(int sockfd, udp_relay_chain chain, ip_type target_ip, unsigned short target_port, char frag, char * data, unsigned int data_len) {
|
|
|
|
|
|
|
|
if (chain.head == NULL ){
|
|
|
|
PDEBUG("provided chain is empty\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *dns_name = NULL;
|
|
|
|
char hostnamebuf[MSG_LEN_MAX];
|
|
|
|
size_t dns_len = 0;
|
|
|
|
socks5_addr target_addr;
|
|
|
|
// we use ip addresses with 224.* to lookup their dns name in our table, to allow remote DNS resolution
|
|
|
|
// the range 224-255.* is reserved, and it won't go outside (unless the app does some other stuff with
|
|
|
|
// the results returned from gethostbyname et al.)
|
|
|
|
// the hardcoded number 224 can now be changed using the config option remote_dns_subnet to i.e. 127
|
|
|
|
if(!target_ip.is_v6 && proxychains_resolver >= DNSLF_RDNS_START && target_ip.addr.v4.octet[0] == remote_dns_subnet) {
|
|
|
|
target_addr.atyp = ATYP_DOM;
|
|
|
|
dns_len = rdns_get_host_for_ip(target_ip.addr.v4, target_addr.addr.dom.name);
|
2023-12-10 23:05:19 +08:00
|
|
|
PDEBUG("dnslen: %d\n", dns_len);
|
2023-09-08 20:42:52 +08:00
|
|
|
if(!dns_len) goto err;
|
|
|
|
else dns_name = target_addr.addr.dom.name;
|
2023-12-10 23:05:19 +08:00
|
|
|
target_addr.addr.dom.len = dns_len & 0xFF;
|
|
|
|
PDEBUG("dnslen in struct: %d\n", target_addr.addr.dom.len);
|
2023-09-08 20:42:52 +08:00
|
|
|
|
|
|
|
} else {
|
|
|
|
if(target_ip.is_v6){
|
|
|
|
target_addr.atyp = ATYP_V6;
|
|
|
|
memcpy(target_addr.addr.v6, target_ip.addr.v6, 16);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
target_addr.atyp = ATYP_V4;
|
|
|
|
memcpy(target_addr.addr.v4.octet, target_ip.addr.v4.octet, 4);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PDEBUG("host dns %s\n", dns_name ? dns_name : "<NULL>");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Allocate a new buffer for the packet data and all the headers
|
|
|
|
unsigned int headers_size = 0;
|
|
|
|
udp_relay_node * tmp = chain.head;
|
|
|
|
int len = 0;
|
|
|
|
while(tmp->next != NULL){
|
|
|
|
|
2023-12-10 23:05:19 +08:00
|
|
|
// switch ((tmp->next)->bnd_addr.atyp)
|
|
|
|
// {
|
|
|
|
// case ATYP_V4:
|
|
|
|
// len = 4;
|
|
|
|
// break;
|
|
|
|
// case ATYP_V6:
|
|
|
|
// len = 6;
|
|
|
|
// break;
|
|
|
|
// case ATYP_DOM:
|
|
|
|
// len = (tmp->next)->bnd_addr.addr.dom.len + 1;
|
|
|
|
// break;
|
|
|
|
// default:
|
|
|
|
// break;
|
|
|
|
// }
|
|
|
|
|
|
|
|
len = (tmp->next)->bnd_addr.is_v6?16:4;
|
2023-09-08 20:42:52 +08:00
|
|
|
|
2023-09-11 19:22:16 +08:00
|
|
|
headers_size += len + 6;
|
2023-09-08 20:42:52 +08:00
|
|
|
tmp = tmp->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (target_addr.atyp)
|
|
|
|
{
|
|
|
|
case ATYP_V4:
|
|
|
|
len = 4;
|
|
|
|
break;
|
|
|
|
case ATYP_V6:
|
|
|
|
len = 6;
|
|
|
|
break;
|
|
|
|
case ATYP_DOM:
|
2023-09-11 19:22:16 +08:00
|
|
|
len = target_addr.addr.dom.len + 1;
|
2023-09-08 20:42:52 +08:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2023-09-11 19:22:16 +08:00
|
|
|
headers_size += len + 6;
|
2023-09-08 20:42:52 +08:00
|
|
|
|
|
|
|
char * buff = NULL;
|
|
|
|
if (NULL == (buff = (char*)malloc(headers_size+data_len))){
|
|
|
|
PDEBUG("error malloc buffer\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Append each header to the buffer
|
|
|
|
|
|
|
|
unsigned int written = 0;
|
|
|
|
unsigned int offset = 0;
|
|
|
|
|
|
|
|
tmp = chain.head;
|
|
|
|
while (tmp->next != NULL)
|
|
|
|
{
|
2023-12-10 23:05:19 +08:00
|
|
|
|
|
|
|
socks5_addr tmpaddr;
|
|
|
|
tmpaddr.atyp = (tmp->next)->bnd_addr.is_v6?ATYP_V6:ATYP_V4;
|
|
|
|
memcpy(tmpaddr.addr.v6, (tmp->next)->bnd_addr.addr.v6, (tmp->next)->bnd_addr.is_v6?16:4);
|
|
|
|
|
|
|
|
written = write_udp_header(tmpaddr, (tmp->next)->bnd_port, 0, buff+offset, headers_size + data_len - offset);
|
2023-09-08 20:42:52 +08:00
|
|
|
if (written == -1){
|
|
|
|
PDEBUG("error write_udp_header\n");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
offset += written;
|
|
|
|
|
|
|
|
tmp = tmp->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
written = write_udp_header(target_addr, target_port, 0, buff + offset, headers_size + data_len - offset);
|
|
|
|
if (written == -1){
|
|
|
|
PDEBUG("error write_udp_header\n");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
offset += written;
|
|
|
|
|
|
|
|
// Append data to the buffer
|
|
|
|
memcpy(buff + offset, data, data_len);
|
|
|
|
|
|
|
|
// Send the packet
|
|
|
|
// FIXME: should write_n_bytes be used here instead ?
|
|
|
|
|
2023-12-10 23:05:19 +08:00
|
|
|
// if(chain.head->bnd_addr.atyp == ATYP_DOM){
|
|
|
|
// PDEBUG("BND_ADDR of type DOMAINE (0x03) not supported yet\n");
|
|
|
|
// goto err;
|
|
|
|
// }
|
|
|
|
int v6 = chain.head->bnd_addr.is_v6 == ATYP_V6;
|
2023-09-08 20:42:52 +08:00
|
|
|
|
|
|
|
struct sockaddr_in addr = {
|
|
|
|
.sin_family = AF_INET,
|
|
|
|
.sin_port = chain.head->bnd_port,
|
|
|
|
.sin_addr.s_addr = (in_addr_t) chain.head->bnd_addr.addr.v4.as_int,
|
|
|
|
};
|
|
|
|
struct sockaddr_in6 addr6 = {
|
|
|
|
.sin6_family = AF_INET6,
|
|
|
|
.sin6_port = chain.head->bnd_port,
|
|
|
|
};
|
|
|
|
if(v6) memcpy(&addr6.sin6_addr.s6_addr, chain.head->bnd_addr.addr.v6, 16);
|
|
|
|
|
2023-09-11 19:22:16 +08:00
|
|
|
int sent = 0;
|
|
|
|
|
|
|
|
sent = true_sendto(sockfd, buff, offset+data_len, 0, (struct sockaddr *) (v6?(void*)&addr6:(void*)&addr), v6?sizeof(addr6):sizeof(addr) );
|
|
|
|
if (sent != offset+data_len){
|
|
|
|
PDEBUG("true_sendto error\n");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
return SUCCESS;
|
2023-09-08 20:42:52 +08:00
|
|
|
|
|
|
|
err:
|
|
|
|
free(buff);
|
|
|
|
return -1;
|
|
|
|
|
2023-09-06 08:22:35 +08:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-11-06 21:12:50 +08:00
|
|
|
#define TP " ... "
|
|
|
|
#define DT "Dynamic chain"
|
|
|
|
#define ST "Strict chain"
|
|
|
|
#define RT "Random chain"
|
2013-06-23 13:13:40 +08:00
|
|
|
#define RRT "Round Robin chain"
|
2023-09-08 20:42:52 +08:00
|
|
|
#define UDPC "UDP_ASSOCIATE tcp socket chain"
|
2011-11-06 21:12:50 +08:00
|
|
|
|
2012-01-28 01:59:44 +08:00
|
|
|
static int start_chain(int *fd, proxy_data * pd, char *begin_mark) {
|
2023-09-08 20:42:52 +08:00
|
|
|
PFUNC();
|
2015-08-10 23:59:31 +08:00
|
|
|
int v6 = pd->ip.is_v6;
|
|
|
|
|
|
|
|
*fd = socket(v6?PF_INET6:PF_INET, SOCK_STREAM, 0);
|
2012-01-28 01:59:44 +08:00
|
|
|
if(*fd == -1)
|
2011-02-25 17:40:11 +08:00
|
|
|
goto error;
|
2012-01-28 03:00:22 +08:00
|
|
|
|
2015-08-10 23:59:31 +08:00
|
|
|
char ip_buf[INET6_ADDRSTRLEN];
|
|
|
|
if(!inet_ntop(v6?AF_INET6:AF_INET,pd->ip.addr.v6,ip_buf,sizeof ip_buf))
|
|
|
|
goto error;
|
|
|
|
|
2012-01-28 01:59:44 +08:00
|
|
|
proxychains_write_log(LOG_PREFIX "%s " TP " %s:%d ",
|
2012-01-28 03:00:22 +08:00
|
|
|
begin_mark, ip_buf, htons(pd->port));
|
2012-01-28 01:59:44 +08:00
|
|
|
pd->ps = PLAY_STATE;
|
2015-06-14 01:37:57 +08:00
|
|
|
struct sockaddr_in addr = {
|
|
|
|
.sin_family = AF_INET,
|
|
|
|
.sin_port = pd->port,
|
2015-08-10 23:59:31 +08:00
|
|
|
.sin_addr.s_addr = (in_addr_t) pd->ip.addr.v4.as_int
|
|
|
|
};
|
|
|
|
struct sockaddr_in6 addr6 = {
|
|
|
|
.sin6_family = AF_INET6,
|
|
|
|
.sin6_port = pd->port,
|
2015-06-14 01:37:57 +08:00
|
|
|
};
|
2015-08-10 23:59:31 +08:00
|
|
|
if(v6) memcpy(&addr6.sin6_addr.s6_addr, pd->ip.addr.v6, 16);
|
|
|
|
if(timed_connect(*fd, (struct sockaddr *) (v6?(void*)&addr6:(void*)&addr), v6?sizeof(addr6):sizeof(addr))) {
|
2012-01-28 01:59:44 +08:00
|
|
|
pd->ps = DOWN_STATE;
|
2011-02-25 17:40:11 +08:00
|
|
|
goto error1;
|
|
|
|
}
|
2012-01-28 01:59:44 +08:00
|
|
|
pd->ps = BUSY_STATE;
|
2011-02-25 17:40:11 +08:00
|
|
|
return SUCCESS;
|
2012-01-28 01:59:44 +08:00
|
|
|
error1:
|
|
|
|
proxychains_write_log(TP " timeout\n");
|
|
|
|
error:
|
|
|
|
if(*fd != -1)
|
2011-02-25 17:40:11 +08:00
|
|
|
close(*fd);
|
|
|
|
return SOCKET_ERROR;
|
|
|
|
}
|
|
|
|
|
2012-01-28 01:59:44 +08:00
|
|
|
static proxy_data *select_proxy(select_type how, proxy_data * pd, unsigned int proxy_count, unsigned int *offset) {
|
2023-09-08 20:42:52 +08:00
|
|
|
PFUNC();
|
|
|
|
PDEBUG("offset: %d\n", *offset);
|
|
|
|
PDEBUG("state: %d\n", pd[0].ps);
|
2012-01-28 01:59:44 +08:00
|
|
|
unsigned int i = 0, k = 0;
|
2011-09-04 07:45:16 +08:00
|
|
|
if(*offset >= proxy_count)
|
2011-02-25 17:40:11 +08:00
|
|
|
return NULL;
|
2012-01-28 01:59:44 +08:00
|
|
|
switch (how) {
|
2011-02-25 17:40:11 +08:00
|
|
|
case RANDOMLY:
|
|
|
|
do {
|
|
|
|
k++;
|
2016-10-10 01:17:07 +08:00
|
|
|
i = rand() % proxy_count;
|
2012-01-28 01:59:44 +08:00
|
|
|
} while(pd[i].ps != PLAY_STATE && k < proxy_count * 100);
|
|
|
|
break;
|
2011-02-25 17:40:11 +08:00
|
|
|
case FIFOLY:
|
2012-01-28 01:59:44 +08:00
|
|
|
for(i = *offset; i < proxy_count; i++) {
|
2011-09-04 07:45:16 +08:00
|
|
|
if(pd[i].ps == PLAY_STATE) {
|
|
|
|
*offset = i;
|
2011-02-25 17:40:11 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
default:
|
2012-01-28 01:59:44 +08:00
|
|
|
break;
|
2011-02-25 17:40:11 +08:00
|
|
|
}
|
2012-01-28 01:59:44 +08:00
|
|
|
if(i >= proxy_count)
|
2011-09-04 07:45:16 +08:00
|
|
|
i = 0;
|
2012-01-28 01:59:44 +08:00
|
|
|
return (pd[i].ps == PLAY_STATE) ? &pd[i] : NULL;
|
2011-02-25 17:40:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-01-28 01:59:44 +08:00
|
|
|
static void release_all(proxy_data * pd, unsigned int proxy_count) {
|
2011-09-04 07:45:16 +08:00
|
|
|
unsigned int i;
|
2012-01-28 01:59:44 +08:00
|
|
|
for(i = 0; i < proxy_count; i++)
|
2011-09-04 07:45:16 +08:00
|
|
|
pd[i].ps = PLAY_STATE;
|
2011-02-25 17:40:11 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-01-28 01:59:44 +08:00
|
|
|
static void release_busy(proxy_data * pd, unsigned int proxy_count) {
|
2011-09-04 07:45:16 +08:00
|
|
|
unsigned int i;
|
2012-01-28 01:59:44 +08:00
|
|
|
for(i = 0; i < proxy_count; i++)
|
2011-09-04 07:45:16 +08:00
|
|
|
if(pd[i].ps == BUSY_STATE)
|
|
|
|
pd[i].ps = PLAY_STATE;
|
2011-02-25 17:40:11 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-01-28 01:59:44 +08:00
|
|
|
static unsigned int calc_alive(proxy_data * pd, unsigned int proxy_count) {
|
2011-09-04 07:45:16 +08:00
|
|
|
unsigned int i;
|
2012-01-28 01:59:44 +08:00
|
|
|
int alive_count = 0;
|
2011-09-04 07:45:16 +08:00
|
|
|
release_busy(pd, proxy_count);
|
2012-01-28 01:59:44 +08:00
|
|
|
for(i = 0; i < proxy_count; i++)
|
2011-09-04 07:45:16 +08:00
|
|
|
if(pd[i].ps == PLAY_STATE)
|
2011-02-25 17:40:11 +08:00
|
|
|
alive_count++;
|
|
|
|
return alive_count;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-01-28 01:59:44 +08:00
|
|
|
static int chain_step(int ns, proxy_data * pfrom, proxy_data * pto) {
|
|
|
|
int retcode = -1;
|
|
|
|
char *hostname;
|
2012-11-08 03:11:14 +08:00
|
|
|
char hostname_buf[MSG_LEN_MAX];
|
2015-08-10 23:59:31 +08:00
|
|
|
char ip_buf[INET6_ADDRSTRLEN];
|
|
|
|
int v6 = pto->ip.is_v6;
|
2012-01-28 02:14:17 +08:00
|
|
|
|
2012-11-07 23:49:14 +08:00
|
|
|
PFUNC();
|
2012-01-28 02:14:17 +08:00
|
|
|
|
experimental new feature: proxy_dns_daemon
since many users complain about issues with modern, ultracomplex
clusterfuck software such as chromium, nodejs, etc, i've reconsidered
one of my original ideas how to implement remote dns lookup support.
instead of having a background thread serving requests via a pipe,
the user manually starts a background daemon process before running
proxychains, and the two processes then communicate via UDP.
this requires much less hacks (like hooking of close() to prevent
pipes from getting closed) and doesn't need to call any async-signal
unsafe code like malloc(). this means it should be much more compatible
than the previous method, however it's not as practical and slightly
slower.
it's recommended that the proxychains4-daemon runs on localhost, and
if you use proxychains-ng a lot you might want to set ip up as a service
that starts on boot. a single proxychains4-daemon should theoretically
be able to serve many parallel proxychains4 instances, but this has not
yet been tested so far. it's also possible to run the daemon on other
computers, even over internet, but currently there is no error-checking/
timeout code at all; that means the UDP connection needs to be very
stable.
the library code used for the daemon sources are from my projects
libulz[0] and htab[1], and the server code is loosely based on
microsocks[2]. their licenses are all compatible with the GPL.
if not otherwise mentioned, they're released for this purpose under
the standard proxychains-ng license (see COPYING).
[0]: https://github.com/rofl0r/libulz
[1]: https://github.com/rofl0r/htab
[2]: https://github.com/rofl0r/microsocks
2020-09-24 05:00:29 +08:00
|
|
|
if(!v6 && proxychains_resolver >= DNSLF_RDNS_START && pto->ip.addr.v4.octet[0] == remote_dns_subnet) {
|
|
|
|
if(!rdns_get_host_for_ip(pto->ip.addr.v4, hostname_buf)) goto usenumericip;
|
2012-11-08 03:11:14 +08:00
|
|
|
else hostname = hostname_buf;
|
2011-11-06 21:12:50 +08:00
|
|
|
} else {
|
2012-01-28 01:59:44 +08:00
|
|
|
usenumericip:
|
2015-08-10 23:59:31 +08:00
|
|
|
if(!inet_ntop(v6?AF_INET6:AF_INET,pto->ip.addr.v6,ip_buf,sizeof ip_buf)) {
|
|
|
|
pto->ps = DOWN_STATE;
|
|
|
|
proxychains_write_log("<--ip conversion error!\n");
|
|
|
|
close(ns);
|
|
|
|
return SOCKET_ERROR;
|
|
|
|
}
|
2012-01-28 03:00:22 +08:00
|
|
|
hostname = ip_buf;
|
2011-11-06 21:12:50 +08:00
|
|
|
}
|
2012-01-28 00:55:37 +08:00
|
|
|
|
2012-01-28 01:59:44 +08:00
|
|
|
proxychains_write_log(TP " %s:%d ", hostname, htons(pto->port));
|
|
|
|
retcode = tunnel_to(ns, pto->ip, pto->port, pfrom->pt, pfrom->user, pfrom->pass);
|
|
|
|
switch (retcode) {
|
2011-02-25 17:40:11 +08:00
|
|
|
case SUCCESS:
|
2012-01-28 01:59:44 +08:00
|
|
|
pto->ps = BUSY_STATE;
|
2011-02-25 17:40:11 +08:00
|
|
|
break;
|
|
|
|
case BLOCKED:
|
2012-01-28 01:59:44 +08:00
|
|
|
pto->ps = BLOCKED_STATE;
|
2011-02-25 17:40:11 +08:00
|
|
|
proxychains_write_log("<--denied\n");
|
|
|
|
close(ns);
|
|
|
|
break;
|
|
|
|
case SOCKET_ERROR:
|
2012-01-28 01:59:44 +08:00
|
|
|
pto->ps = DOWN_STATE;
|
2012-07-09 03:23:39 +08:00
|
|
|
proxychains_write_log("<--socket error or timeout!\n");
|
2011-02-25 17:40:11 +08:00
|
|
|
close(ns);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return retcode;
|
|
|
|
}
|
|
|
|
|
2012-01-28 01:59:44 +08:00
|
|
|
int connect_proxy_chain(int sock, ip_type target_ip,
|
|
|
|
unsigned short target_port, proxy_data * pd,
|
|
|
|
unsigned int proxy_count, chain_type ct, unsigned int max_chain) {
|
2011-02-25 17:40:11 +08:00
|
|
|
proxy_data p4;
|
2012-01-28 01:59:44 +08:00
|
|
|
proxy_data *p1, *p2, *p3;
|
|
|
|
int ns = -1;
|
2013-06-23 13:13:40 +08:00
|
|
|
int rc = -1;
|
2012-01-28 01:59:44 +08:00
|
|
|
unsigned int offset = 0;
|
|
|
|
unsigned int alive_count = 0;
|
|
|
|
unsigned int curr_len = 0;
|
2013-06-23 13:13:40 +08:00
|
|
|
unsigned int looped = 0; // went back to start of list in RR mode
|
2018-08-26 13:18:20 +08:00
|
|
|
unsigned int rr_loop_max = 14;
|
2012-01-28 00:55:37 +08:00
|
|
|
|
2012-01-28 01:59:44 +08:00
|
|
|
p3 = &p4;
|
2012-01-28 02:14:17 +08:00
|
|
|
|
2012-11-07 23:49:14 +08:00
|
|
|
PFUNC();
|
2012-01-28 00:55:37 +08:00
|
|
|
|
2012-01-28 01:59:44 +08:00
|
|
|
again:
|
2013-06-23 13:13:40 +08:00
|
|
|
rc = -1;
|
|
|
|
DUMP_PROXY_CHAIN(pd, proxy_count);
|
2011-09-04 07:45:16 +08:00
|
|
|
|
2012-01-28 01:59:44 +08:00
|
|
|
switch (ct) {
|
2011-02-25 17:40:11 +08:00
|
|
|
case DYNAMIC_TYPE:
|
2012-01-28 01:59:44 +08:00
|
|
|
alive_count = calc_alive(pd, proxy_count);
|
|
|
|
offset = 0;
|
|
|
|
do {
|
|
|
|
if(!(p1 = select_proxy(FIFOLY, pd, proxy_count, &offset)))
|
|
|
|
goto error_more;
|
|
|
|
} while(SUCCESS != start_chain(&ns, p1, DT) && offset < proxy_count);
|
|
|
|
for(;;) {
|
|
|
|
p2 = select_proxy(FIFOLY, pd, proxy_count, &offset);
|
|
|
|
if(!p2)
|
|
|
|
break;
|
|
|
|
if(SUCCESS != chain_step(ns, p1, p2)) {
|
|
|
|
PDEBUG("GOTO AGAIN 1\n");
|
|
|
|
goto again;
|
|
|
|
}
|
|
|
|
p1 = p2;
|
2011-09-04 07:45:16 +08:00
|
|
|
}
|
2012-01-28 01:59:44 +08:00
|
|
|
//proxychains_write_log(TP);
|
|
|
|
p3->ip = target_ip;
|
|
|
|
p3->port = target_port;
|
|
|
|
if(SUCCESS != chain_step(ns, p1, p3))
|
|
|
|
goto error;
|
|
|
|
break;
|
|
|
|
|
2013-06-23 13:13:40 +08:00
|
|
|
case ROUND_ROBIN_TYPE:
|
|
|
|
alive_count = calc_alive(pd, proxy_count);
|
2018-08-26 13:18:20 +08:00
|
|
|
offset = proxychains_proxy_offset;
|
2013-06-23 13:13:40 +08:00
|
|
|
if(alive_count < max_chain)
|
|
|
|
goto error_more;
|
2018-08-26 13:18:20 +08:00
|
|
|
PDEBUG("1:rr_offset = %d\n", offset);
|
2013-06-23 13:13:40 +08:00
|
|
|
/* Check from current RR offset til end */
|
|
|
|
for (;rc != SUCCESS;) {
|
|
|
|
if (!(p1 = select_proxy(FIFOLY, pd, proxy_count, &offset))) {
|
|
|
|
/* We've reached the end of the list, go to the start */
|
|
|
|
offset = 0;
|
|
|
|
looped++;
|
2018-08-23 19:40:27 +08:00
|
|
|
if (looped > rr_loop_max) {
|
|
|
|
proxychains_proxy_offset = 0;
|
|
|
|
goto error_more;
|
|
|
|
} else {
|
|
|
|
PDEBUG("rr_type all proxies down, release all\n");
|
|
|
|
release_all(pd, proxy_count);
|
|
|
|
/* Each loop we wait 10ms more */
|
|
|
|
usleep(10000 * looped);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2013-06-23 13:13:40 +08:00
|
|
|
PDEBUG("2:rr_offset = %d\n", offset);
|
|
|
|
rc=start_chain(&ns, p1, RRT);
|
|
|
|
}
|
|
|
|
/* Create rest of chain using RR */
|
|
|
|
for(curr_len = 1; curr_len < max_chain;) {
|
|
|
|
PDEBUG("3:rr_offset = %d, curr_len = %d, max_chain = %d\n", offset, curr_len, max_chain);
|
|
|
|
p2 = select_proxy(FIFOLY, pd, proxy_count, &offset);
|
|
|
|
if(!p2) {
|
|
|
|
/* Try from the beginning to where we started */
|
|
|
|
offset = 0;
|
|
|
|
continue;
|
|
|
|
} else if(SUCCESS != chain_step(ns, p1, p2)) {
|
|
|
|
PDEBUG("GOTO AGAIN 1\n");
|
|
|
|
goto again;
|
|
|
|
} else
|
|
|
|
p1 = p2;
|
|
|
|
curr_len++;
|
|
|
|
}
|
|
|
|
//proxychains_write_log(TP);
|
|
|
|
p3->ip = target_ip;
|
|
|
|
p3->port = target_port;
|
|
|
|
proxychains_proxy_offset = offset+1;
|
|
|
|
PDEBUG("pd_offset = %d, curr_len = %d\n", proxychains_proxy_offset, curr_len);
|
|
|
|
if(SUCCESS != chain_step(ns, p1, p3))
|
|
|
|
goto error;
|
|
|
|
break;
|
|
|
|
|
2012-01-28 01:59:44 +08:00
|
|
|
case STRICT_TYPE:
|
|
|
|
alive_count = calc_alive(pd, proxy_count);
|
|
|
|
offset = 0;
|
|
|
|
if(!(p1 = select_proxy(FIFOLY, pd, proxy_count, &offset))) {
|
|
|
|
PDEBUG("select_proxy failed\n");
|
2011-02-25 17:40:11 +08:00
|
|
|
goto error_strict;
|
2011-09-04 07:45:16 +08:00
|
|
|
}
|
2012-01-28 01:59:44 +08:00
|
|
|
if(SUCCESS != start_chain(&ns, p1, ST)) {
|
|
|
|
PDEBUG("start_chain failed\n");
|
|
|
|
goto error_strict;
|
|
|
|
}
|
|
|
|
while(offset < proxy_count) {
|
|
|
|
if(!(p2 = select_proxy(FIFOLY, pd, proxy_count, &offset)))
|
|
|
|
break;
|
|
|
|
if(SUCCESS != chain_step(ns, p1, p2)) {
|
|
|
|
PDEBUG("chain_step failed\n");
|
|
|
|
goto error_strict;
|
|
|
|
}
|
|
|
|
p1 = p2;
|
|
|
|
}
|
|
|
|
//proxychains_write_log(TP);
|
|
|
|
p3->ip = target_ip;
|
|
|
|
p3->port = target_port;
|
|
|
|
if(SUCCESS != chain_step(ns, p1, p3))
|
|
|
|
goto error;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case RANDOM_TYPE:
|
|
|
|
alive_count = calc_alive(pd, proxy_count);
|
|
|
|
if(alive_count < max_chain)
|
2011-02-25 17:40:11 +08:00
|
|
|
goto error_more;
|
2012-01-28 01:59:44 +08:00
|
|
|
curr_len = offset = 0;
|
|
|
|
do {
|
|
|
|
if(!(p1 = select_proxy(RANDOMLY, pd, proxy_count, &offset)))
|
|
|
|
goto error_more;
|
|
|
|
} while(SUCCESS != start_chain(&ns, p1, RT) && offset < max_chain);
|
|
|
|
while(++curr_len < max_chain) {
|
|
|
|
if(!(p2 = select_proxy(RANDOMLY, pd, proxy_count, &offset)))
|
|
|
|
goto error_more;
|
|
|
|
if(SUCCESS != chain_step(ns, p1, p2)) {
|
|
|
|
PDEBUG("GOTO AGAIN 2\n");
|
|
|
|
goto again;
|
|
|
|
}
|
|
|
|
p1 = p2;
|
2012-01-28 00:55:37 +08:00
|
|
|
}
|
2012-01-28 01:59:44 +08:00
|
|
|
//proxychains_write_log(TP);
|
|
|
|
p3->ip = target_ip;
|
|
|
|
p3->port = target_port;
|
|
|
|
if(SUCCESS != chain_step(ns, p1, p3))
|
|
|
|
goto error;
|
2012-01-28 00:55:37 +08:00
|
|
|
|
2011-02-25 17:40:11 +08:00
|
|
|
}
|
|
|
|
|
2012-01-28 01:59:44 +08:00
|
|
|
proxychains_write_log(TP " OK\n");
|
|
|
|
dup2(ns, sock);
|
2011-02-25 17:40:11 +08:00
|
|
|
close(ns);
|
|
|
|
return 0;
|
2012-01-28 01:59:44 +08:00
|
|
|
error:
|
|
|
|
if(ns != -1)
|
2011-02-25 17:40:11 +08:00
|
|
|
close(ns);
|
2012-01-28 01:59:44 +08:00
|
|
|
errno = ECONNREFUSED; // for nmap ;)
|
2011-02-25 17:40:11 +08:00
|
|
|
return -1;
|
2012-01-28 00:55:37 +08:00
|
|
|
|
2012-01-28 01:59:44 +08:00
|
|
|
error_more:
|
2011-02-25 17:40:11 +08:00
|
|
|
proxychains_write_log("\n!!!need more proxies!!!\n");
|
2012-01-28 01:59:44 +08:00
|
|
|
error_strict:
|
2011-09-04 07:45:16 +08:00
|
|
|
PDEBUG("error\n");
|
2012-01-28 02:14:17 +08:00
|
|
|
|
2012-01-28 01:59:44 +08:00
|
|
|
release_all(pd, proxy_count);
|
|
|
|
if(ns != -1)
|
2011-02-25 17:40:11 +08:00
|
|
|
close(ns);
|
|
|
|
errno = ETIMEDOUT;
|
|
|
|
return -1;
|
|
|
|
}
|
2023-09-08 20:42:52 +08:00
|
|
|
|
|
|
|
// int connect_to_lastnode(int *sock, udp_relay_chain chain){
|
|
|
|
|
|
|
|
// udp_relay_node * current_node = chain.head;
|
|
|
|
|
|
|
|
// //First connect to the chain head
|
|
|
|
// if(SUCCESS != start_chain(sock, &(current_node->pd), UDPC)){
|
|
|
|
// PDEBUG("start_chain failed\n");
|
|
|
|
// return -1;
|
|
|
|
// }
|
|
|
|
// // Connect to the rest of the chain
|
|
|
|
// while(current_node->next != NULL){
|
|
|
|
// if(SUCCESS != chain_step(sock, &(current_node->pd), &(current_node->next->pd))){
|
|
|
|
// PDEBUG("chain step failed\n");
|
|
|
|
// return -1;
|
|
|
|
// }
|
|
|
|
// current_node = current_node->next;
|
|
|
|
// }
|
|
|
|
|
|
|
|
// return SUCCESS;
|
|
|
|
// }
|
|
|
|
|
|
|
|
int add_node_to_chain(proxy_data * pd, udp_relay_chain * chain){
|
|
|
|
PFUNC();
|
|
|
|
// Allocate memory for the new node structure
|
|
|
|
udp_relay_node * new_node = NULL;
|
|
|
|
if(NULL == (new_node = (udp_relay_node *)malloc(sizeof(udp_relay_node)))){
|
|
|
|
PDEBUG("error malloc new node\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
new_node->next = NULL;
|
|
|
|
|
|
|
|
|
|
|
|
udp_relay_node * tmp = chain->head;
|
|
|
|
|
|
|
|
if(tmp == NULL){ // Means new_node is the first node to be created
|
|
|
|
chain->head = new_node;
|
|
|
|
new_node->prev = NULL;
|
|
|
|
} else {
|
|
|
|
// Moving to the end of the current chain
|
|
|
|
while(tmp->next != NULL){
|
|
|
|
tmp = tmp->next;
|
|
|
|
}
|
|
|
|
// Adding the new node at the end
|
|
|
|
tmp->next = new_node;
|
|
|
|
new_node->prev = tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Initializing the new node
|
|
|
|
new_node->pd.ip = pd->ip;
|
|
|
|
new_node->pd.port = pd->port;
|
|
|
|
new_node->pd.pt = pd->pt;
|
|
|
|
new_node->pd.ps = pd->ps;
|
|
|
|
strcpy(new_node->pd.user, pd->user);
|
|
|
|
strcpy(new_node->pd.pass, pd->pass);
|
|
|
|
|
|
|
|
// Connecting the new node tcp_socketfd to the associated proxy through the current chain
|
|
|
|
//
|
|
|
|
tmp = chain->head;
|
|
|
|
// First connect to the chain head
|
|
|
|
if(SUCCESS != start_chain(&(new_node->tcp_sockfd), &(tmp->pd), UDPC)){
|
|
|
|
PDEBUG("start_chain failed\n");
|
|
|
|
new_node->tcp_sockfd = -1;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
// Connect to the rest of the chain
|
|
|
|
while(tmp->next != NULL){
|
|
|
|
if(SUCCESS != chain_step(new_node->tcp_sockfd, &(tmp->pd), &(tmp->next->pd))){
|
|
|
|
PDEBUG("chain step failed\n");
|
|
|
|
new_node->tcp_sockfd = -1;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
tmp = tmp->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Performing UDP_ASSOCIATE handshake in order to fill the new node BND_ADDR and BND_PORT
|
|
|
|
if(SUCCESS != udp_associate(new_node->tcp_sockfd, NULL, NULL, &(new_node->bnd_addr), &(new_node->bnd_port), new_node->pd.user, new_node->pd.pass)){
|
|
|
|
PDEBUG("udp_associate failed\n");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
PDEBUG("new node added and open to relay UDP packets\n");
|
|
|
|
return SUCCESS;
|
|
|
|
|
|
|
|
err:
|
|
|
|
// Ensure new node tcp socket is closed
|
|
|
|
if(new_node->tcp_sockfd != -1){
|
|
|
|
close(new_node->tcp_sockfd);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remove the new node from the chain
|
|
|
|
if(new_node->prev == NULL){ // means new_node is the only node in chain
|
|
|
|
chain->head = NULL;
|
|
|
|
} else{
|
|
|
|
(new_node->prev)->next = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Free memory
|
|
|
|
free(new_node);
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int free_relay_chain_nodes(udp_relay_chain chain){
|
|
|
|
if(chain.head == NULL){
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
udp_relay_node * current = chain.head;
|
|
|
|
udp_relay_node * next = NULL;
|
|
|
|
|
|
|
|
while(current != NULL){
|
|
|
|
next = current->next;
|
|
|
|
|
|
|
|
close(current->tcp_sockfd);
|
|
|
|
free(current);
|
|
|
|
|
|
|
|
current = next;
|
|
|
|
}
|
|
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
udp_relay_chain * open_relay_chain(proxy_data *pd, unsigned int proxy_count, chain_type ct, unsigned int max_chains){
|
|
|
|
|
|
|
|
PFUNC();
|
|
|
|
// Allocate memory for the new relay chain
|
|
|
|
udp_relay_chain * new_chain = NULL;
|
|
|
|
if(NULL == (new_chain = (udp_relay_chain *)malloc(sizeof(udp_relay_chain)))){
|
|
|
|
PDEBUG("error malloc new chain\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
new_chain->head = NULL;
|
|
|
|
new_chain->sockfd = -1;
|
|
|
|
|
|
|
|
|
|
|
|
unsigned int alive_count = 0;
|
|
|
|
unsigned int offset = 0;
|
|
|
|
proxy_data *p1;
|
|
|
|
|
|
|
|
|
|
|
|
switch (ct)
|
|
|
|
{
|
|
|
|
case DYNAMIC_TYPE:
|
|
|
|
PDEBUG("DYNAMIC_TYPE not yet supported for UDP\n");
|
|
|
|
goto error;
|
|
|
|
break;
|
|
|
|
case ROUND_ROBIN_TYPE:
|
|
|
|
PDEBUG("ROUND_ROBIN_TYPE not yet supported for UDP\n");
|
|
|
|
goto error;
|
|
|
|
break;
|
|
|
|
case STRICT_TYPE:
|
|
|
|
alive_count = calc_alive(pd, proxy_count);
|
|
|
|
offset = 0;
|
|
|
|
PDEBUG("opening STRICT_TYPE relay chain, alive_count=%d, offset=%d\n", alive_count, offset);
|
|
|
|
while((p1 = select_proxy(FIFOLY, pd, proxy_count, &offset))) {
|
|
|
|
if(SUCCESS != add_node_to_chain(p1, new_chain)) {
|
|
|
|
PDEBUG("add_node_to_chain failed\n");
|
2023-09-11 19:22:16 +08:00
|
|
|
p1->ps = BLOCKED_STATE;
|
2023-09-08 20:42:52 +08:00
|
|
|
goto error;
|
|
|
|
}
|
2023-09-11 19:22:16 +08:00
|
|
|
p1->ps = BUSY_STATE;
|
2023-09-08 20:42:52 +08:00
|
|
|
}
|
|
|
|
return new_chain;
|
|
|
|
|
|
|
|
break;
|
|
|
|
case RANDOM_TYPE:
|
|
|
|
PDEBUG("RANDOM_TYPE not yet supported for UDP\n");
|
|
|
|
goto error;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
error:
|
|
|
|
PDEBUG("error\n");
|
|
|
|
release_all(pd, proxy_count);
|
|
|
|
free_relay_chain_nodes(*new_chain);
|
|
|
|
free(new_chain);
|
|
|
|
errno = ETIMEDOUT;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void add_relay_chain(udp_relay_chain_list* chains_list, udp_relay_chain* new_chain){
|
|
|
|
|
|
|
|
new_chain->next = NULL;
|
|
|
|
|
|
|
|
if(chains_list->tail == NULL){ // The current list is empty, set head and tail to the new chain
|
|
|
|
chains_list->head = new_chain;
|
|
|
|
chains_list->tail = new_chain;
|
|
|
|
new_chain->prev = NULL;
|
|
|
|
} else {
|
|
|
|
// Add the new chain at the end
|
|
|
|
chains_list->tail->next = new_chain;
|
|
|
|
new_chain->prev = chains_list->tail;
|
|
|
|
chains_list->tail = new_chain;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void del_relay_chain(udp_relay_chain_list* chains_list, udp_relay_chain* chain){
|
|
|
|
if(chain == chains_list->head){
|
|
|
|
if(chain->next == NULL){
|
|
|
|
free(chain);
|
|
|
|
chains_list->head = NULL;
|
|
|
|
chains_list->tail = NULL;
|
|
|
|
}else{
|
|
|
|
chains_list->head = chain->next;
|
|
|
|
free(chain);
|
|
|
|
}
|
|
|
|
} else if (chain = chains_list->tail){
|
|
|
|
chains_list->tail = chain->prev;
|
|
|
|
free(chain);
|
|
|
|
} else {
|
|
|
|
chain->next->prev = chain->prev;
|
|
|
|
chain->prev->next = chain->next;
|
|
|
|
free(chain);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
udp_relay_chain* get_relay_chain(udp_relay_chain_list chains_list, int sockfd){
|
|
|
|
udp_relay_chain* tmp = chains_list.head;
|
|
|
|
while(tmp != NULL){
|
|
|
|
if(tmp->sockfd == sockfd){
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
tmp = tmp->next;
|
|
|
|
}
|
|
|
|
return tmp;
|
|
|
|
}
|
2011-02-25 17:40:11 +08:00
|
|
|
|
2018-12-02 21:48:43 +08:00
|
|
|
static pthread_mutex_t servbyname_lock;
|
2012-11-08 04:28:09 +08:00
|
|
|
void core_initialize(void) {
|
2018-12-02 21:48:43 +08:00
|
|
|
MUTEX_INIT(&servbyname_lock);
|
2012-11-08 04:28:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void core_unload(void) {
|
2018-12-02 21:48:43 +08:00
|
|
|
MUTEX_DESTROY(&servbyname_lock);
|
2012-11-08 04:28:09 +08:00
|
|
|
}
|
|
|
|
|
2012-11-04 12:02:57 +08:00
|
|
|
static void gethostbyname_data_setstring(struct gethostbyname_data* data, char* name) {
|
|
|
|
snprintf(data->addr_name, sizeof(data->addr_name), "%s", name);
|
|
|
|
data->hostent_space.h_name = data->addr_name;
|
|
|
|
}
|
|
|
|
|
2015-08-10 23:59:31 +08:00
|
|
|
extern ip_type4 hostsreader_get_numeric_ip_for_name(const char* name);
|
2020-09-21 05:11:17 +08:00
|
|
|
struct hostent* proxy_gethostbyname_old(const char *name)
|
|
|
|
{
|
|
|
|
static struct hostent hostent_space;
|
|
|
|
static in_addr_t resolved_addr;
|
|
|
|
static char* resolved_addr_p;
|
2020-10-26 10:53:29 +08:00
|
|
|
static char addr_name[256];
|
2020-09-21 05:11:17 +08:00
|
|
|
|
|
|
|
int pipe_fd[2];
|
|
|
|
char buff[256];
|
|
|
|
in_addr_t addr;
|
|
|
|
pid_t pid;
|
2020-09-21 17:46:38 +08:00
|
|
|
int status, ret;
|
2020-09-21 05:11:17 +08:00
|
|
|
size_t l;
|
|
|
|
struct hostent* hp;
|
|
|
|
|
|
|
|
hostent_space.h_addr_list = &resolved_addr_p;
|
|
|
|
*hostent_space.h_addr_list = (char*)&resolved_addr;
|
|
|
|
resolved_addr = 0;
|
|
|
|
|
2020-10-28 19:05:52 +08:00
|
|
|
if(pc_isnumericipv4(name)) {
|
|
|
|
strcpy(buff, name);
|
|
|
|
goto got_buff;
|
|
|
|
}
|
|
|
|
|
2020-09-21 05:11:17 +08:00
|
|
|
gethostname(buff,sizeof(buff));
|
|
|
|
if(!strcmp(buff,name))
|
|
|
|
goto got_buff;
|
|
|
|
|
|
|
|
memset(buff, 0, sizeof(buff));
|
|
|
|
|
|
|
|
// TODO: this works only once, so cache it ...
|
|
|
|
// later
|
|
|
|
while ((hp=gethostent()))
|
|
|
|
if (!strcmp(hp->h_name,name))
|
|
|
|
return hp;
|
2020-09-21 17:46:38 +08:00
|
|
|
#ifdef HAVE_PIPE2
|
|
|
|
ret = pipe2(pipe_fd, O_CLOEXEC);
|
|
|
|
#else
|
|
|
|
ret = pipe(pipe_fd);
|
|
|
|
if(ret == 0) {
|
|
|
|
fcntl(pipe_fd[0], F_SETFD, FD_CLOEXEC);
|
|
|
|
fcntl(pipe_fd[1], F_SETFD, FD_CLOEXEC);
|
|
|
|
}
|
|
|
|
#endif
|
2020-09-21 05:11:17 +08:00
|
|
|
|
2020-09-21 17:46:38 +08:00
|
|
|
if(ret)
|
2020-09-21 05:11:17 +08:00
|
|
|
goto err;
|
|
|
|
pid = fork();
|
|
|
|
switch(pid) {
|
|
|
|
|
|
|
|
case 0: // child
|
|
|
|
proxychains_write_log("|DNS-request| %s \n", name);
|
|
|
|
close(pipe_fd[0]);
|
|
|
|
dup2(pipe_fd[1],1);
|
|
|
|
close(pipe_fd[1]);
|
|
|
|
|
|
|
|
// putenv("LD_PRELOAD=");
|
|
|
|
execlp("proxyresolv","proxyresolv",name,NULL);
|
|
|
|
perror("can't exec proxyresolv");
|
|
|
|
exit(2);
|
|
|
|
|
|
|
|
case -1: //error
|
|
|
|
close(pipe_fd[0]);
|
|
|
|
close(pipe_fd[1]);
|
|
|
|
perror("can't fork");
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
default:
|
|
|
|
close(pipe_fd[1]);
|
|
|
|
waitpid(pid, &status, 0);
|
|
|
|
buff[0] = 0;
|
|
|
|
read(pipe_fd[0],&buff,sizeof(buff));
|
|
|
|
close(pipe_fd[0]);
|
|
|
|
got_buff:
|
|
|
|
l = strlen(buff);
|
2023-03-08 23:05:06 +08:00
|
|
|
if (!l) goto err_dns;
|
|
|
|
if (buff[l-1] == '\n') buff[l-1] = 0;
|
2020-09-21 05:11:17 +08:00
|
|
|
addr = inet_addr(buff);
|
|
|
|
if (addr == (in_addr_t) (-1))
|
|
|
|
goto err_dns;
|
|
|
|
memcpy(*(hostent_space.h_addr_list),
|
|
|
|
&addr ,sizeof(struct in_addr));
|
|
|
|
hostent_space.h_name = addr_name;
|
2020-10-28 19:09:42 +08:00
|
|
|
snprintf(addr_name, sizeof addr_name, "%s", buff);
|
2020-09-21 05:11:17 +08:00
|
|
|
hostent_space.h_length = sizeof (in_addr_t);
|
2020-10-28 19:06:21 +08:00
|
|
|
hostent_space.h_addrtype = AF_INET;
|
2020-09-21 05:11:17 +08:00
|
|
|
}
|
|
|
|
proxychains_write_log("|DNS-response| %s is %s\n",
|
|
|
|
name, inet_ntoa(*(struct in_addr*)&addr));
|
|
|
|
return &hostent_space;
|
|
|
|
err_dns:
|
2023-03-08 23:05:06 +08:00
|
|
|
proxychains_write_log("|DNS-response|: %s lookup error\n", name);
|
2020-09-21 05:11:17 +08:00
|
|
|
err:
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-07-16 07:05:28 +08:00
|
|
|
struct hostent *proxy_gethostbyname(const char *name, struct gethostbyname_data* data) {
|
2012-11-07 23:49:14 +08:00
|
|
|
PFUNC();
|
2011-02-25 17:40:11 +08:00
|
|
|
char buff[256];
|
2012-01-28 00:55:37 +08:00
|
|
|
|
2012-07-16 07:05:28 +08:00
|
|
|
data->resolved_addr_p[0] = (char *) &data->resolved_addr;
|
|
|
|
data->resolved_addr_p[1] = NULL;
|
2012-01-28 00:55:37 +08:00
|
|
|
|
2012-07-16 07:05:28 +08:00
|
|
|
data->hostent_space.h_addr_list = data->resolved_addr_p;
|
2012-11-04 12:02:57 +08:00
|
|
|
// let aliases point to the NULL member, mimicking an empty list.
|
|
|
|
data->hostent_space.h_aliases = &data->resolved_addr_p[1];
|
2011-11-06 21:12:50 +08:00
|
|
|
|
2012-07-16 07:05:28 +08:00
|
|
|
data->resolved_addr = 0;
|
2012-11-04 08:00:47 +08:00
|
|
|
data->hostent_space.h_addrtype = AF_INET;
|
2012-11-04 12:02:57 +08:00
|
|
|
data->hostent_space.h_length = sizeof(in_addr_t);
|
2012-01-28 00:55:37 +08:00
|
|
|
|
2020-10-28 18:46:23 +08:00
|
|
|
if(pc_isnumericipv4(name)) {
|
|
|
|
data->resolved_addr = inet_addr(name);
|
|
|
|
goto retname;
|
|
|
|
}
|
|
|
|
|
2012-01-28 01:59:44 +08:00
|
|
|
gethostname(buff, sizeof(buff));
|
2012-01-28 00:55:37 +08:00
|
|
|
|
2011-11-06 21:12:50 +08:00
|
|
|
if(!strcmp(buff, name)) {
|
2012-07-16 07:05:28 +08:00
|
|
|
data->resolved_addr = inet_addr(buff);
|
|
|
|
if(data->resolved_addr == (in_addr_t) (-1))
|
2020-09-24 00:00:16 +08:00
|
|
|
data->resolved_addr = (in_addr_t) (IPT4_LOCALHOST.as_int);
|
2012-11-04 12:02:57 +08:00
|
|
|
goto retname;
|
2011-11-06 21:12:50 +08:00
|
|
|
}
|
2012-01-28 00:55:37 +08:00
|
|
|
|
2012-11-04 12:02:57 +08:00
|
|
|
// this iterates over the "known hosts" db, usually /etc/hosts
|
2015-08-10 23:59:31 +08:00
|
|
|
ip_type4 hdb_res = hostsreader_get_numeric_ip_for_name(name);
|
2020-09-24 00:00:16 +08:00
|
|
|
if(hdb_res.as_int != IPT4_INVALID.as_int) {
|
2012-11-08 08:18:19 +08:00
|
|
|
data->resolved_addr = hdb_res.as_int;
|
|
|
|
goto retname;
|
|
|
|
}
|
|
|
|
|
experimental new feature: proxy_dns_daemon
since many users complain about issues with modern, ultracomplex
clusterfuck software such as chromium, nodejs, etc, i've reconsidered
one of my original ideas how to implement remote dns lookup support.
instead of having a background thread serving requests via a pipe,
the user manually starts a background daemon process before running
proxychains, and the two processes then communicate via UDP.
this requires much less hacks (like hooking of close() to prevent
pipes from getting closed) and doesn't need to call any async-signal
unsafe code like malloc(). this means it should be much more compatible
than the previous method, however it's not as practical and slightly
slower.
it's recommended that the proxychains4-daemon runs on localhost, and
if you use proxychains-ng a lot you might want to set ip up as a service
that starts on boot. a single proxychains4-daemon should theoretically
be able to serve many parallel proxychains4 instances, but this has not
yet been tested so far. it's also possible to run the daemon on other
computers, even over internet, but currently there is no error-checking/
timeout code at all; that means the UDP connection needs to be very
stable.
the library code used for the daemon sources are from my projects
libulz[0] and htab[1], and the server code is loosely based on
microsocks[2]. their licenses are all compatible with the GPL.
if not otherwise mentioned, they're released for this purpose under
the standard proxychains-ng license (see COPYING).
[0]: https://github.com/rofl0r/libulz
[1]: https://github.com/rofl0r/htab
[2]: https://github.com/rofl0r/microsocks
2020-09-24 05:00:29 +08:00
|
|
|
data->resolved_addr = rdns_get_ip_for_host((char*) name, strlen(name)).as_int;
|
2020-09-24 00:00:16 +08:00
|
|
|
if(data->resolved_addr == (in_addr_t) IPT4_INVALID.as_int) return NULL;
|
2012-01-28 00:55:37 +08:00
|
|
|
|
2012-11-04 12:02:57 +08:00
|
|
|
retname:
|
2012-01-28 00:55:37 +08:00
|
|
|
|
2012-11-04 12:02:57 +08:00
|
|
|
gethostbyname_data_setstring(data, (char*) name);
|
|
|
|
|
2012-11-07 23:49:14 +08:00
|
|
|
PDEBUG("return hostent space\n");
|
|
|
|
|
2012-07-16 07:05:28 +08:00
|
|
|
return &data->hostent_space;
|
2011-02-25 17:40:11 +08:00
|
|
|
}
|
2012-07-14 23:59:56 +08:00
|
|
|
|
2012-07-16 07:05:28 +08:00
|
|
|
struct addrinfo_data {
|
|
|
|
struct addrinfo addrinfo_space;
|
2019-04-25 21:36:03 +08:00
|
|
|
struct sockaddr_storage sockaddr_space;
|
2012-07-16 07:05:28 +08:00
|
|
|
char addr_name[256];
|
|
|
|
};
|
|
|
|
|
|
|
|
void proxy_freeaddrinfo(struct addrinfo *res) {
|
2012-11-07 23:49:14 +08:00
|
|
|
PFUNC();
|
2012-07-16 07:05:28 +08:00
|
|
|
free(res);
|
|
|
|
}
|
|
|
|
|
2018-12-02 21:48:43 +08:00
|
|
|
static int mygetservbyname_r(const char* name, const char* proto, struct servent* result_buf,
|
2012-08-06 07:26:03 +08:00
|
|
|
char* buf, size_t buflen, struct servent** result) {
|
2012-11-07 23:49:14 +08:00
|
|
|
PFUNC();
|
2018-12-02 21:48:43 +08:00
|
|
|
#ifdef HAVE_GNU_GETSERVBYNAME_R
|
|
|
|
PDEBUG("using host getservbyname_r\n");
|
|
|
|
return getservbyname_r(name, proto, result_buf, buf, buflen, result);
|
|
|
|
#endif
|
2012-08-06 07:26:03 +08:00
|
|
|
struct servent *res;
|
|
|
|
int ret;
|
|
|
|
(void) buf; (void) buflen;
|
2018-12-02 21:48:43 +08:00
|
|
|
MUTEX_LOCK(&servbyname_lock);
|
2012-08-06 07:26:03 +08:00
|
|
|
res = getservbyname(name, proto);
|
|
|
|
if(res) {
|
|
|
|
*result_buf = *res;
|
|
|
|
*result = result_buf;
|
|
|
|
ret = 0;
|
|
|
|
} else {
|
|
|
|
*result = NULL;
|
|
|
|
ret = ENOENT;
|
|
|
|
}
|
2018-12-02 21:48:43 +08:00
|
|
|
MUTEX_UNLOCK(&servbyname_lock);
|
2012-08-06 07:26:03 +08:00
|
|
|
return ret;
|
|
|
|
}
|
2012-07-16 07:05:28 +08:00
|
|
|
|
2019-04-25 21:36:03 +08:00
|
|
|
static int looks_like_numeric_ipv6(const char *node)
|
|
|
|
{
|
|
|
|
if(!strchr(node, ':')) return 0;
|
|
|
|
const char* p= node;
|
|
|
|
while(1) switch(*(p++)) {
|
|
|
|
case 0: return 1;
|
|
|
|
case ':': case '.':
|
|
|
|
case '0': case '1': case '2': case '3': case '4':
|
|
|
|
case '5': case '6': case '7': case '8': case '9':
|
|
|
|
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
|
|
|
|
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
|
|
|
|
break;
|
|
|
|
default: return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int my_inet_aton(const char *node, struct addrinfo_data* space)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
((struct sockaddr_in *) &space->sockaddr_space)->sin_family = AF_INET;
|
|
|
|
ret = inet_aton(node, &((struct sockaddr_in *) &space->sockaddr_space)->sin_addr);
|
|
|
|
if(ret || !looks_like_numeric_ipv6(node)) return ret;
|
|
|
|
ret = inet_pton(AF_INET6, node, &((struct sockaddr_in6 *) &space->sockaddr_space)->sin6_addr);
|
|
|
|
if(ret) ((struct sockaddr_in6 *) &space->sockaddr_space)->sin6_family = AF_INET6;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-01-28 01:59:44 +08:00
|
|
|
int proxy_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) {
|
2012-07-16 07:05:28 +08:00
|
|
|
struct gethostbyname_data ghdata;
|
|
|
|
struct addrinfo_data *space;
|
2011-02-25 17:40:11 +08:00
|
|
|
struct servent *se = NULL;
|
|
|
|
struct hostent *hp = NULL;
|
2012-07-14 23:59:56 +08:00
|
|
|
struct servent se_buf;
|
2012-07-16 07:34:00 +08:00
|
|
|
struct addrinfo *p;
|
2012-07-14 23:59:56 +08:00
|
|
|
char buf[1024];
|
2019-04-25 21:36:03 +08:00
|
|
|
int port, af = AF_INET;
|
2012-01-28 00:55:37 +08:00
|
|
|
|
2021-02-05 09:50:39 +08:00
|
|
|
PDEBUG("proxy_getaddrinfo node:%s service: %s, flags: %d\n",
|
|
|
|
node?node:"",service?service:"",hints?(int)hints->ai_flags:0);
|
|
|
|
|
2012-07-16 07:05:28 +08:00
|
|
|
space = calloc(1, sizeof(struct addrinfo_data));
|
2023-03-08 23:05:06 +08:00
|
|
|
if(!space) return EAI_MEMORY;
|
2014-01-22 23:13:20 +08:00
|
|
|
|
2019-04-25 21:36:03 +08:00
|
|
|
if(node && !my_inet_aton(node, space)) {
|
2014-01-22 23:13:20 +08:00
|
|
|
/* some folks (nmap) use getaddrinfo() with AI_NUMERICHOST to check whether a string
|
|
|
|
containing a numeric ip was passed. we must return failure in that case. */
|
2017-08-23 22:50:57 +08:00
|
|
|
if(hints && (hints->ai_flags & AI_NUMERICHOST)) {
|
2023-03-08 23:05:06 +08:00
|
|
|
err_nn:
|
2017-08-23 22:50:57 +08:00
|
|
|
free(space);
|
|
|
|
return EAI_NONAME;
|
|
|
|
}
|
experimental new feature: proxy_dns_daemon
since many users complain about issues with modern, ultracomplex
clusterfuck software such as chromium, nodejs, etc, i've reconsidered
one of my original ideas how to implement remote dns lookup support.
instead of having a background thread serving requests via a pipe,
the user manually starts a background daemon process before running
proxychains, and the two processes then communicate via UDP.
this requires much less hacks (like hooking of close() to prevent
pipes from getting closed) and doesn't need to call any async-signal
unsafe code like malloc(). this means it should be much more compatible
than the previous method, however it's not as practical and slightly
slower.
it's recommended that the proxychains4-daemon runs on localhost, and
if you use proxychains-ng a lot you might want to set ip up as a service
that starts on boot. a single proxychains4-daemon should theoretically
be able to serve many parallel proxychains4 instances, but this has not
yet been tested so far. it's also possible to run the daemon on other
computers, even over internet, but currently there is no error-checking/
timeout code at all; that means the UDP connection needs to be very
stable.
the library code used for the daemon sources are from my projects
libulz[0] and htab[1], and the server code is loosely based on
microsocks[2]. their licenses are all compatible with the GPL.
if not otherwise mentioned, they're released for this purpose under
the standard proxychains-ng license (see COPYING).
[0]: https://github.com/rofl0r/libulz
[1]: https://github.com/rofl0r/htab
[2]: https://github.com/rofl0r/microsocks
2020-09-24 05:00:29 +08:00
|
|
|
if(proxychains_resolver == DNSLF_FORKEXEC)
|
2020-09-21 05:11:17 +08:00
|
|
|
hp = proxy_gethostbyname_old(node);
|
|
|
|
else
|
|
|
|
hp = proxy_gethostbyname(node, &ghdata);
|
|
|
|
|
2012-01-28 01:59:44 +08:00
|
|
|
if(hp)
|
2012-07-16 07:05:28 +08:00
|
|
|
memcpy(&((struct sockaddr_in *) &space->sockaddr_space)->sin_addr,
|
2012-01-28 01:59:44 +08:00
|
|
|
*(hp->h_addr_list), sizeof(in_addr_t));
|
2011-02-25 17:40:11 +08:00
|
|
|
else
|
2023-03-08 23:05:06 +08:00
|
|
|
goto err_nn;
|
2019-04-25 21:36:03 +08:00
|
|
|
} else if(node) {
|
|
|
|
af = ((struct sockaddr_in *) &space->sockaddr_space)->sin_family;
|
2019-07-21 21:27:55 +08:00
|
|
|
} else if(!node && !(hints->ai_flags & AI_PASSIVE)) {
|
|
|
|
af = ((struct sockaddr_in *) &space->sockaddr_space)->sin_family = AF_INET;
|
|
|
|
memcpy(&((struct sockaddr_in *) &space->sockaddr_space)->sin_addr,
|
|
|
|
(char[]){127,0,0,1}, 4);
|
2011-02-25 17:40:11 +08:00
|
|
|
}
|
2018-12-02 21:48:43 +08:00
|
|
|
if(service) mygetservbyname_r(service, NULL, &se_buf, buf, sizeof(buf), &se);
|
2012-01-28 00:55:37 +08:00
|
|
|
|
2012-07-14 23:59:56 +08:00
|
|
|
port = se ? se->s_port : htons(atoi(service ? service : "0"));
|
2019-04-25 21:36:03 +08:00
|
|
|
if(af == AF_INET)
|
|
|
|
((struct sockaddr_in *) &space->sockaddr_space)->sin_port = port;
|
|
|
|
else
|
|
|
|
((struct sockaddr_in6 *) &space->sockaddr_space)->sin6_port = port;
|
2011-02-25 17:40:11 +08:00
|
|
|
|
2012-07-16 07:34:00 +08:00
|
|
|
*res = p = &space->addrinfo_space;
|
|
|
|
assert((size_t)p == (size_t) space);
|
2014-01-22 23:13:20 +08:00
|
|
|
|
2019-04-25 21:36:03 +08:00
|
|
|
p->ai_addr = (void*) &space->sockaddr_space;
|
2012-01-28 01:59:44 +08:00
|
|
|
if(node)
|
2014-01-23 05:22:18 +08:00
|
|
|
snprintf(space->addr_name, sizeof(space->addr_name), "%s", node);
|
2012-07-16 07:34:00 +08:00
|
|
|
p->ai_canonname = space->addr_name;
|
|
|
|
p->ai_next = NULL;
|
2019-04-25 21:36:03 +08:00
|
|
|
p->ai_family = space->sockaddr_space.ss_family = af;
|
2019-05-25 09:23:38 +08:00
|
|
|
p->ai_addrlen = af == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6);
|
2012-07-16 07:19:30 +08:00
|
|
|
|
|
|
|
if(hints) {
|
2012-07-16 07:34:00 +08:00
|
|
|
p->ai_socktype = hints->ai_socktype;
|
|
|
|
p->ai_flags = hints->ai_flags;
|
|
|
|
p->ai_protocol = hints->ai_protocol;
|
2022-01-23 02:54:33 +08:00
|
|
|
if(!p->ai_socktype && p->ai_protocol == IPPROTO_TCP)
|
|
|
|
p->ai_socktype = SOCK_STREAM;
|
2012-07-16 07:19:30 +08:00
|
|
|
} else {
|
2015-04-07 00:57:09 +08:00
|
|
|
#ifndef AI_V4MAPPED
|
|
|
|
#define AI_V4MAPPED 0
|
|
|
|
#endif
|
2012-07-16 07:34:00 +08:00
|
|
|
p->ai_flags = (AI_V4MAPPED | AI_ADDRCONFIG);
|
2012-07-16 07:19:30 +08:00
|
|
|
}
|
2011-02-25 17:40:11 +08:00
|
|
|
return 0;
|
|
|
|
}
|