proxychains-ng icon indicating copy to clipboard operation
proxychains-ng copied to clipboard

How to specify server by DOMAIN PORT not IP PORT?

Open xieranmaya opened this issue 6 years ago • 26 comments

I'm having a server with a dynamic IP address(ADSL) and a DDNS configured for it, thus I need to use DOMAIN to specify the server, any way?

xieranmaya avatar Jun 28 '18 09:06 xieranmaya

yes, you write a script that resolves the host and then creates a proxychains.conf from a template like this:

#!/bin/sh
# proxychains wrapper
PROXY_DNS=foobar.com
PROXY_PORT=1080
PROXY_IP=$(host $PROXY_DNS | tail -n 1 | awk '{n=split($0, a, " "); print a[n];}')
conf=/tmp/pxc4.conf.$$
cat << EOF > $conf
strict_chain
proxy_dns
remote_dns_subnet 224
tcp_read_time_out 15000
tcp_connect_time_out 8000
[ProxyList]
EOF
echo "socks5 $PROXY_IP $PROXY_PORT" >> $conf
trap "rm -f $conf" INT TERM
proxychains4 -f "$conf" "$@"
ec="$?"
rm -f "$conf"
return "$ec"

rofl0r avatar Jun 28 '18 12:06 rofl0r

when i run the script, it occurs: Usage: proxychains4 -q -f config_file program_name [arguments] -q makes proxychains quiet - this overrides the config setting -f allows one to manually specify a configfile to use for example : proxychains telnet somehost.com More help in README file

what should i do?

gemmax avatar Jul 01 '18 01:07 gemmax

did you pass parameters ? usage is like sh script.sh curl ifconfig.me

if it still doesn't work use sh -x instead of sh and paste the output here

rofl0r avatar Jul 01 '18 01:07 rofl0r

to @rofl0r , but shell script is very unreliable, such like:

$ host g.www.ms.akadns.net
g.www.ms.akadns.net is an alias for lb1.www.ms.akadns.net.
lb1.www.ms.akadns.net has address 13.75.118.214

the alias will cause error of host command, and also to multi-line output of some domainname by cut command. I will try to write a proxychains wrapper, upload later.

Justsoos avatar Aug 27 '18 04:08 Justsoos

@Justsoos see above, i fixed the host command, should work now (i wrote the above script "blind", without ever running it)

rofl0r avatar Aug 27 '18 04:08 rofl0r

@rofl0r :D still the obviurs bug PROXY_DNS=foobar.com & host $PROXYDNS, too old to be programmer la ~ :p

Justsoos avatar Aug 27 '18 06:08 Justsoos

@Justsoos fixed. can you confirm it works now ?

rofl0r avatar Aug 27 '18 13:08 rofl0r

so, that is what I need:

  • three more profiles choosed by param -1, -2, -3, and so on
  • no param means default proxy profile
  • appointed manually by -n IP(hostname,Node‘s first letter):port -p Protocol
  • support IPv6
  • support hostname or IP input, use getent but host to resolve hostname (host will RDNS ip address)

suggest setting system alias like: alias p='/home/your_path/p.sh' and then you could run proxychains with ease like: $p curl ipinfo.io or $p -1 curl ipinfo.io or $p -n 1.1.1.1:1080 -p socks5 curl ipinfo.io

thx @rofl0r, this script will be maintained at here https://gist.github.com/Justsoos/8c06f2df7b7c1b01749c19fe598e1e11

#!/bin/sh
# proxychains wrapper
# Choose pre-supposed profile with -1,-2,-3 OR appoint by -n proxy(Node)_ip(hostname):port and -p proxy_protocol and -q as quiet mode

# Default profile
proxy_hostname=127.0.0.1
proxy_port=1080
protocol=socks5
# profile 1
proxy_hostname_1=127.0.0.1
proxy_port_1=9999
protocol_1=socks5
# profile 2
proxy_hostname_2=SomeProxySite.com
proxy_port_2=443
protocol_2=https
# profile 3
proxy_hostname_3=SomeProxySite.com
proxy_port_3=8080
protocol_3=http

quiet=""

while getopts :n:p:q123 opt
do
    case $opt in
        1)
            # profile 1
            proxy_hostname=$proxy_hostname_1
            proxy_port=$proxy_port_1
            protocol=$protocol_1
            ;;
        2)
            # profile 2
            proxy_hostname=$proxy_hostname_2
            proxy_port=$proxy_port_2
            protocol=$protocol_2
            ;;
        3)
            # profile 3
            proxy_hostname=$proxy_hostname_3
            proxy_port=$proxy_port_3
            protocol=$protocol_3
            ;;
        n)
            # appointed proxy hostname & port
            proxy_port=$(echo $OPTARG | awk -F ':' '{print $(NF)}')
            # remove [] of IPv6
            proxy_hostname=$(echo $OPTARG | sed "s/:$proxy_port//g" | sed "s/\[//g" | sed "s/\]//g")
            ;;
        p)
            # appointed proxy protocol
            protocol=$OPTARG
            ;;
        q)
            # quiet
            quiet=" -q "
            ;;
        :)
            ;;
    esac
done
shift "$((OPTIND-1))"
# echo "$proxy_hostname $proxy_port $protocol"
proxy_ip=$(getent hosts $proxy_hostname | head -n1 | cut -d " " -f1)
[ -z $proxy_ip ] && proxy_ip=$proxy_hostname
# echo "$proxy_ip"
# echo "$@"
# echo "$OPTIND"
# echo "$quiet"
# echo $$
conf=/tmp/proxychains4.conf.$UID.$$
cat << EOF > $conf
strict_chain
proxy_dns
remote_dns_subnet 224
tcp_read_time_out 15000
tcp_connect_time_out 8000
[ProxyList]
EOF
echo "$protocol $proxy_ip $proxy_port" >> $conf
trap "rm -f $conf" INT TERM
para=${quiet}" -f "${conf}" "${@}
# echo $para
proxychains4 $para
ec="$?"
rm -f "$conf"
exit "$ec"

Justsoos avatar Aug 28 '18 20:08 Justsoos

Hi, I have kind of similar problem but in my case I have a squid proxy in front of me which has a whitelist. The whitelist already contains the dns name of the second proxy but does not allow HTTP CONNECT to non whitelisted IPs or DNS names.

So

nc -v internal.first.proxy.somewhere 8888
CONNECT external.second.proxy.somewhere:8888 HTTP/1.1
Host: external.second.proxy.somewhere:22225

works fine, whereas:

nc -v internal.first.proxy.somewhere 8888
CONNECT  1.1.1.1:8888 HTTP/1.1

does not (Permission denied). Unfortunately your workaround does not solve this problem. Do you have an idea how to fix this besides rewriting the tool?

Regards

philurlaub avatar Feb 28 '19 10:02 philurlaub

@philurlaub see latest commit ^

rofl0r avatar Feb 28 '19 14:02 rofl0r

@rofl0r thanks a lot! Really appreciate your fast response.

philurlaub avatar Feb 28 '19 15:02 philurlaub

Okay, one more thing, if you could confirm, that basic auth works for the second proxy with dns name, that would help alot :) I currently get always denied.

http 1.1.1.1 8888
http external.second.proxy.somewhere 22225 user password

philurlaub avatar Feb 28 '19 17:02 philurlaub

it worked for my socks5 test server with password auth. can you provide me a pcap recording of the transaction (recorded with tcpdump or wireshark)? (you could change user/pass to something non-sensitive for testing)

rofl0r avatar Feb 28 '19 22:02 rofl0r

tcpdumping something is not a trivial task in my case as I'm in a big company setup surrounded with lots of restrictions. Basic auth seems to work though, it just behaviors not the way I suspected. Some URLs work some doesn't but that's probably because of one of the proxys having more restrictions. Nevertheless thanks again for testing!

philurlaub avatar Mar 01 '19 12:03 philurlaub

Why is domain name not directly supported by the proxychains.conf?

onichandame avatar Jul 12 '20 14:07 onichandame

Why is domain name not directly supported by the proxychains.conf?

it's explained in great detail in one of the issues here. please post a link when you find it.

rofl0r avatar Jul 12 '20 16:07 rofl0r

Why is domain name not directly supported by the proxychains.conf?

I'm curious about this as well. While I agree that adding code to support this is unnecessary since it can be handled via the wrapper script, at first glance it doesn't seem like there's any major hurdles implementation-wise.

The only reference I found was in #184 where you mention that "it's not possible due to the way DNS resolution is internally done." However, in strict-chain mode proxychains already supports hostnames in the config for all except the first server. It seems like one should be able to modify get_chain_data to add a case for count == 1 where we call true_gethostbyname to resolve it using the libc resolver. What am I missing?

krackers avatar Nov 30 '20 21:11 krackers

It seems like one should be able to modify get_chain_data to add a case for count == 1 where we call true_gethostbyname to resolve it using the libc resolver.

ok, try it out and file a PR if it works.

rofl0r avatar Nov 30 '20 23:11 rofl0r

@rofl0r Ah you're right, since gethostbyname ends up calling connect it's not really so straightforward. We end up needing to guard it so we don't call init again if the call stack originates from get_chain_data. This is a really hacky patch that works on linux at least, but I'm not confident it's bulletproof. Either way this was just curiosity on my part to see whether it was possible.

diff --git a/src/libproxychains.c b/src/libproxychains.c
index fc6880f..437cbae 100644
--- a/src/libproxychains.c
+++ b/src/libproxychains.c
@@ -82,6 +82,7 @@ unsigned int remote_dns_subnet = 224;
 pthread_once_t init_once = PTHREAD_ONCE_INIT;
 
 static int init_l = 0;
+static int getting_chain_data = 0;
 
 static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_type * ct);
 
@@ -131,13 +132,16 @@ static void do_init(void) {
        srand(time(NULL));
        core_initialize();
 
+       setup_hooks();
+
        /* read the config file */
+       getting_chain_data = 1;
        get_chain_data(proxychains_pd, &proxychains_proxy_count, &proxychains_ct);
        DUMP_PROXY_CHAIN(proxychains_pd, proxychains_proxy_count);
+       getting_chain_data = 0;
 
        proxychains_write_log(LOG_PREFIX "DLL init: proxychains-ng %s\n", proxychains_get_version());
 
-       setup_hooks();
 
        while(close_fds_cnt) true_close(close_fds[--close_fds_cnt]);
        init_l = 1;
@@ -341,13 +345,32 @@ static void get_chain_data(proxy_data * pd, unsigned int *proxy_count, chain_typ
                                                ip_type4 internal_ip = at_get_ip_for_host(host, strlen(host));
                                                pd[count].ip.is_v6 = 0;
                                                host_ip->addr.v4 = internal_ip;
-                                               if(internal_ip.as_int == IPT4_INVALID.as_int)
-                                                       goto inv_host;
                                        } else {
+                                               struct addrinfo* addr;
+                                               int result = true_getaddrinfo(host, NULL, NULL, &addr);
+                                               if (result != 0) {
+                                                       goto inv_host;
+                                               }
+                                               for (struct addrinfo* res = addr; res != NULL; res = res->ai_next) {
+                                                       int af = res->ai_family;
+                                                       struct sockaddr *addr = res->ai_addr;
+                                                       switch (af)
+                                                       {
+                                                               case AF_INET:
+                                                                       pd[count].ip.is_v6 = 0;
+                                                                       host_ip->addr.v4 = IPT4_INT(((struct sockaddr_in*) addr)->sin_addr.s_addr);
+                                                                       goto got_host;
+                                                               case AF_INET6:
+                                                                       pd[count].ip.is_v6 = 1;
+                                                                       memcpy(host_ip->addr.v6, ((struct sockaddr_in6*) addr)->sin6_addr.s6_addr, 16);
+                                                                       goto got_host;
+                                                       }
+                                               }
+                                       }
+got_host:
+                                       if (!host_ip->is_v6 && host_ip->addr.v4.as_int == IPT4_INVALID.as_int) {
 inv_host:
-                                               fprintf(stderr, "proxy %s has invalid value or is not numeric\n", host);
-                                               fprintf(stderr, "non-numeric ips are only allowed under the following circumstances:\n");
-                                               fprintf(stderr, "chaintype == strict (%s), proxy is not first in list (%s), proxy_dns active (%s)\n\n", bool_str(*ct == STRICT_TYPE), bool_str(count > 0), rdns_resolver_string(proxychains_resolver));
+                                               fprintf(stderr, "proxy %s has invalid value\n", host);
                                                exit(1);
                                        }
                                }
@@ -547,6 +570,9 @@ static int is_v4inv6(const struct in6_addr *a) {
        return !memcmp(a->s6_addr, "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12);
 }
 int connect(int sock, const struct sockaddr *addr, unsigned int len) {
+       if (getting_chain_data) {
+               return true_connect(sock, addr, len);
+       }
        INIT();
        PFUNC();

krackers avatar Dec 01 '20 01:12 krackers

This is a really hacky patch that works on linux at least, but I'm not confident it's bulletproof.

congrats. yes, to know whether it's bulletproof one would have to test it with all different proxy_dns/remote_dns backends. which reminds me that in case the proxyresolv script is installed, one could eventually just call proxy_gethostbyname_old(), which i recently re-added, without any hacks.

rofl0r avatar Dec 01 '20 15:12 rofl0r

whether it's bulletproof one would have to test it with all different backends

I also wonder if there could be some thread related race condition where we after we set getting_chain_data = 1 but before we finish calling get_chain_data, some other application thread calls connect which will be erroneously redirected to true_connect and thus bypass the proxy. I guess you would need to make getting_chain_data a thread-local variable to avoid this.

one could eventually just call proxy_gethostbyname_old

That script injects the libproxychains dylib before calling dig, which would seem to cause an issue since that newly forked process will again try to call get_chain_data in the setup, resulting in endless recursion. I think what you'd want to do is unset LD_PRELOAD, fork/exec host, and then restore the LD_PRELOAD.

That seems even more hacky than the above though. I'll leave it to someone else who cares enough about this to rigorously test and polish the implementation.

krackers avatar Dec 01 '20 22:12 krackers

Is is possible to specify hostname if it can be resolvable by the local DNS or Bonjour? I have a proxy server on system.local, and can resolve it on my Mac. Since it does not need an external DNS server, it should be possible to resolve it.

DUOLabs333 avatar Dec 02 '21 21:12 DUOLabs333

Or could proxychains at least parse hostnames in config file from /etc/hosts?

xlucn avatar Jun 02 '22 06:06 xlucn

Or could proxychains at least parse hostnames in config file from /etc/hosts?

it does already

rofl0r avatar Jun 02 '22 14:06 rofl0r

But proxychains-ng gives an error message:

$ proxychains curl www.google.com
proxy proxy-host has invalid value or is not numeric
non-numeric ips are only allowed under the following circumstances:
chaintype == strict (true), proxy is not first in list (false), proxy_dns active (thread)

Using the config file:

strict_chain
quiet_mode
proxy_dns
[ProxyList]
socks5 proxy-host 1081

and /etc/hosts file:

192.168.1.100   proxy-host

Is this not the use case?

xlucn avatar Jun 02 '22 14:06 xlucn

there's hostsreader code in proxychains-ng, but apparently it's only used for getaddrinfo-style lookups for the proxified program, but not for config processing. eventually this could be added without big effort.

rofl0r avatar Jun 02 '22 19:06 rofl0r

Any updates on this ? Seems like DNS resolution would come a long way to e.g automate proxychains conf deployment in Kubernetes for instance, where you might have a proxy like:

# proxychains.conf  VER 4.x
#
#        HTTP, SOCKS4a, SOCKS5 tunneling proxifier with DNS.

proxy_dns
strict_chain
# dynamic_chain
remote_dns_subnet 224
tcp_read_time_out 15000
tcp_connect_time_out 8000

[ProxyList]
socks5 tor-privoxy.default.svc.cluster.local 9050

That links to an egress proxy service deployed in k8s to control outgoing traffic.

ocervell avatar Sep 25 '23 08:09 ocervell

Any updates on this ?

no. use the wrapper script from my first post.

rofl0r avatar Sep 25 '23 11:09 rofl0r

Sorry but your wrapper script is not very good, goes against all rules of automation ... Not too mention IPs can change in time and make deployments drift ... Seems trivial to add DNS resolution to proxychains, too bad you don't want to open a discussion, I could even have helped write it.

ocervell avatar Sep 25 '23 13:09 ocervell

yes, you write a script that resolves the host and then creates a proxychains.conf from a template like this:

#!/bin/sh
# proxychains wrapper
PROXY_DNS=foobar.com
PROXY_PORT=1080
PROXY_IP=$(host $PROXY_DNS | tail -n 1 | awk '{n=split($0, a, " "); print a[n];}')
conf=/tmp/pxc4.conf.$$
cat << EOF > $conf
strict_chain
proxy_dns
remote_dns_subnet 224
tcp_read_time_out 15000
tcp_connect_time_out 8000
[ProxyList]
EOF
echo "socks5 $PROXY_IP $PROXY_PORT" >> $conf
trap "rm -f $conf" INT TERM
proxychains4 -f "$conf" "$@"
ec="$?"
rm -f "$conf"
return "$ec"

Our proxy IP address may change. If the proxy IP address changes after the program is started, how can it automatically use the new address without restarting?

goooogs avatar Dec 12 '23 11:12 goooogs