Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support connecting to IRC via a SOCKS proxy [$15] #143

kylef opened this issue Mar 19, 2012 · 14 comments

Support connecting to IRC via a SOCKS proxy [$15] #143

kylef opened this issue Mar 19, 2012 · 14 comments


Copy link

@kylef kylef commented Mar 19, 2012

There is a $5.00 bounty open on this issue at Bountysource

## --- There is a **[$15 open bounty](** on this issue. Add to the bounty at [Bountysource](
Copy link

@DarthGandalf DarthGandalf commented Mar 19, 2012

HTTP CONNECT can work too....

Copy link

@ninlilizi ninlilizi commented Apr 16, 2012

I'd really <3 this feature too.
Even basic socks4 support would be both grand and simple to implement

Copy link

@Ramblurr Ramblurr commented Jun 6, 2012

This would be incredibly useful. I'd love to be able to use znc over tor or any other arbitrary socks proxy.

Copy link

@ErebusBat ErebusBat commented Jan 29, 2013

FYI this can be easily accomplished using socat by running the following command on the ZNC server, then using as the server in ZNC.

Freenode via TOR:
socat TCP4-LISTEN:4321,fork SOCKS4A:localhost:p4fsi4ockecnea7l.onion:6667,socksport=9050

Assume you just want to use as your SOCKS proxy, then the command would be:
socat TCP4-LISTEN:4321,fork,socksport=8080

Obviously you can replace the .onion address with another IRC server, or change the port.

Copy link

@Mikaela Mikaela commented Dec 4, 2014

Could this optionally be network specific for exampe using tor only at specific networks? The socat has issue of not starting automatically on boot or crash unlike ZNC in crontab.

To my own comment above: What sense would it make connecting to Tor only with one server and not the rest? Your real host would be seen on the other networks anyway and if only your ZNC was using tor, your IP could always be gotten by making you click some link etc.

Updated on 2015-06-12 while also strikethroughing the previous comment.

2018-09-28, this is probably the issue where I have changed my mind the most.

Tor hidden services provide additional encryption in addition to TLS and they cannot be MITMed (or at least not "as easily"). Their development also seems to only going forwards with Tor Hidden Services version 3.

Thus I might like to connect to freenode (and some other network) hidden service, while connecting to a IRCd on my localhost or LAN without Tor and like irl says below, I wouldn't need or want to use Tor with network using CJDNS or DN42.

I guess the main point to my original comment is that there are other reasons to use Tor than hiding IP. I would recommend reading Tor's mode sof anonymity in their TorifyHOWTO

And to end this round of editing, the original issue only requests SOCKS proxy support (I hope it to mean SOCKS5) and that there likely are other use cases for SOCKS proxy other than Tor (usually even with keeping in mind that the connection between ZNC and the proxy is not encrypted.

2018-09-28 -EDIT2: HexChat also has option to "bypass proxy for this server", WeeChat has proxy as server-specific option that may also be set globally, I don't know if those compare to ZNC, but ZNC would not be the only software featuring per-server proxies. I also forgot above that anonymity networks other than Tor also exist such as I2P which might also need a separate proxy (I haven't investigated it, sorry).

@znc-bountysource znc-bountysource changed the title Support connecting to IRC via a SOCKS proxy [$5] Support connecting to IRC via a SOCKS proxy [$15] Apr 10, 2015
Copy link

@Carlgo11 Carlgo11 commented Apr 10, 2015

Added $10. Please add 😘

Copy link

@pdostal pdostal commented Sep 6, 2016

I'd also like to ask for proxy support in ZNC 👍

Copy link

@irl irl commented Oct 29, 2016


The socat example isn't exactly reliable. In response to @Mikaela, Tor is not the only use case for this. I'd like to use Tor to connect to Freenode and OFTC, but I'd still like to go directly to hackint (via dn42) and another network accessible via cjdns, so this would need to be a per server thing.

Looking at how to implement this (hints to prospective developers, I'm not a C++ dev):

  • ZNC uses the CSocketManager to manage the low-level socket that is the actual connection to the IRC server. It looks like modifications would be required for the Connect() function here to allow for a SOCKS proxy to be specified.
  • When a SOCKS proxy is specified, for the Tor use case at least, it would be necessary to disable DNS resolution and pass the domain name (which may be a hidden service) through the SOCKS proxy.
  • It may be a better idea to provide an alternative function such as ConnectSocks() to implement the acquiring of a socket via SOCKS as you're basically rewriting the whole function.
Copy link

@Mikaela Mikaela commented Sep 28, 2018

As it has been so long time since anything was said here, I would like to add this comment to notify that I have changed my mind on #143 (comment) again and added another set of strikethroughs and written the actual comment there.

Unrelatedly the Bountysource integration in the original post is broken.

Copy link

@paigeadelethompson paigeadelethompson commented Mar 10, 2019

I've been playing around with proxychains which essentially proxifies any program that uses TCP sockets, unfortunately its very slow proxychains4 -f <(echo "[ProxyList]" ; cat /mnt/export/netcrave_docker/srv/proxy_scan/all_uniq.txt | grep -v "[a-z]" | tr ':' ' ' | awk '{print "http " $0}' | shuf ) znc -d /mnt/export/src/oh-my-znc-2.0

but I think its slow because I'm feeding it quite a large list of proxies:

cat /mnt/export/proxy_scan/all_uniq.txt| wc -l 

and my znc.conf connects to around ~400 networks:

cat /mnt/export/src/oh-my-znc-2.0/configs/znc.conf | grep Network  | grep -v "/"  | wc -l 

So maybe this solution would work just fine for somebody who is not me. Here's a list of proxies if anybody else wants to try it. Here's a list of proxies to get you started: (note these are HTTP CONNECT): there's also some other options for the config that are worth checking out.

  • here are also some SOCKS 4 proxies:

  • and some SOCKS 5 proxies

  • you'll also need to change for SOCKS 4 <(echo "[ProxyList]" ; cat /mnt/export/netcrave_docker/srv/proxy_scan/all_uniq.txt | grep -v "[a-z]" | tr ':' ' ' | awk '{print "socks4 " $0}' | shuf )

  • and for SOCKS 5 <(echo "[ProxyList]" ; cat /mnt/export/netcrave_docker/srv/proxy_scan/all_uniq.txt | grep -v "[a-z]" | tr ':' ' ' | awk '{print "socks5 " $0}' | shuf )

depending on what you want to use, you can use all of them like this:

<(echo "[ProxyList]" ; cat /mnt/export/netcrave_docker/srv/proxy_scan/socks4.txt | tr ':' ' ' | awk '{print "socks4 " $0}'; cat /mnt/export/netcrave_docker/srv/proxy_scan/socks5.txt | tr ':' ' ' | awk '{print "socks5 " $0}' ; cat /mnt/export/netcrave_docker/srv/proxy_scan/all_uniq.txt | tr ':' ' ' | awk '{print "http " $0}' )

if you want to get rid of the grep -v [a-z] and make sure you're using all of the proxies you need to resolve the names first, you can include something like this in your command chain cat /mnt/export/netcrave_docker/srv/proxy_scan/all_uniq.txt | tr ':' ' ' | parallel --colsep " " getent ahostsv4 {1} '2>&1' '|' head -n 1 '|' awk \'\{print \$1\}\' '|' tr -d \'\\n\' ';' echo {2} | awk '{print "http " $0}' please mind the use of gnu parallel it was just simply less of a pain in the ass than trying to get xargs to work the way I want it to, so apt-get install parallel and the extra escaping its a bit of a pain in the ass, also redirects that are to be including in the scope of parallel must be single-quoted.

However, you'll probably immediately notice that its working very slowly strace -p $(pgrep znc) if it is.
Sidenote: SOCKS 5 supports UDP but proxychains does not.

Copy link

@paigeadelethompson paigeadelethompson commented Mar 10, 2019

also I agree socat is quite cumbersome if you use it: for this purpose, it ended up becoming two commands when I tried because I couldn't get chaining to work right with SSL:
socat TCP-L:1$x,reuseaddr,fork PROXY:$proxy:$ircserv,proxyport=$port,retry=10 2> /dev/null &
socat TCP-L:2$x,reuseaddr,fork OPENSSL:localhost:1$x,verify=0,compress=auto,retry=10 2> /dev/null &

Also that compress=auto is imperative iirc. It was for this reason I started experimenting with ways to use HAProxy to manage my proxy lists and destinations (that one to many relationship and the added bonus of ongoing healthchecks and load balancing) here's the config:

    log                local0 notice
    maxconn                     32768
    nbproc                      4
    cpu-map                     1 0
    cpu-map                     2 1
    cpu-map                     3 2
    cpu-map                     4 3
    tune.ssl.default-dh-param   2048
    stats socket                /home/proxy_scan/run/haproxy_admin.sock mode 660 level admin
    server-state-file           /home/proxy_scan/run/haproxy.state
    stats                       timeout 30s bind-process 4
    load-server-state-from-file global
    log                         global
    mode                        http
    option                      httplog
    option                      dontlognull
    option                      socket-stats
    default-server              check inter 15000 downinter 25000 fastinter 1000 weight 50 slowstart 120s observe layer7 on-error fastinter
    maxconn                     32768
    retries                     3
    timeout                     connect 3000000
    timeout                     client  6600000
    timeout                     server  6600000
listen stats
    bind                        *:9999
    stats                       enable
    stats                       hide-version
    stats                       realm Proxy\ Health
    stats                       uri /
frontend socks4_fe
    maxconn                     25000
    bind                        *:8388
    mode                        tcp
    default_backend             socks4_be
frontend socks5_fe
    maxconn                     25000
    bind                        *:1080
    mode                        tcp
    default_backend             socks5_be
frontend http_connect_fe
    maxconn                     25000
    bind                        *:3128
    mode                        http
    default_backend             http_connect_be
frontend http_and_https_fe
    maxconn                     25000
    bind                        *:8080
    mode                        http
    default_backend             http_and_https_be
backend socks4_be
    balance                     roundrobin
    mode                        tcp
    server-template             socks4-proxy- 1-2000 check
backend socks5_be
    balance                     roundrobin
    mode                        tcp
    server-template             socks5-proxy- 1-2000 check
backend http_and_https_be
    balance                     roundrobin
    mode                        http
    http-request                set-header Proxy-Connection Keep-Alive
    option                      httpchk GET / "HTTP/1.0\r\nHost:"
    http-check                  expect rstatus (2|3)[0-9][0-9]
    server-template             http-proxy- 1-2000 check
backend http_connect_be
    balance                     roundrobin
    mode                        http
    http-request                set-header Proxy-Connection Keep-Alive
    option                      httpchk GET / "HTTP/1.0\r\nHost:"
    http-check                  expect rstatus (2|3)[0-9][0-9]
    server-template             http-proxy- 1-2000 check

This configuration ensures a control socket which you can use to add and remove the actual proxies to it at run-time, you can do it with bash:
echo "set server backendnodes/${id} addr ${new_host} port ${new_port}" | nc -U /home/proxy_scan/run/haproxy_admin.sock;

However I have recently started re-writing this to fit into a python script and I haven't finished because I haven't wanted to do the work to actually do it right (with weight outs, draining, etc) but I have a start so if anybody else feels like this work needs to be done feel free to take over:

from haproxyadmin import haproxy
from operator import itemgetter, attrgetter
import socket
import math
import fcntl
import asyncio

class HAProxy_Controller:
    hap = haproxy.HAProxy(socket_dir='/home/proxy_scan/run')

    def get_proxies(self):
        f = open('/home/proxy_scan/all_uniq.txt')
        # get exclusive lock on file in case the scanner is already writing or is about to
        fcntl.flock(f, fcntl.LOCK_EX | fcntl.LOCK_NB)
        lines = f.readlines()
        # release lock
        fcntl.flock(f, fcntl.LOCK_UN)
        return lines

    Configures each proxy from /home/proxy_scan/all_uniq.txt as a backend server
    using the haproxy admin socket.
    def init_haproxy(self):
        current_servers = self.hap.backend('backendnodes').servers()
        proxies = self.get_proxies()
        existing = [str(x.address) for x in current_servers]
        last = None

        for x in proxies:
            dup = False

            host = x.split(':')[0]
            port = x.split(':')[1]
            resolved = socket.gethostbyname(host)

            for z in existing:
                if z == "{}:{}".format(resolved, port).strip():
                    dup = True

            if dup == True:

            if last == None:
                last = 0

                last = last + 1

            current_servers[last].setaddress("{} port {}".format(resolved, port).strip())

    backend server cleanup tasks
    def maintain_failed_servers(self):
        servers = self.hap.backend('backendnodes').servers()
        # this first iteration should address most flapping the more frequently it is run
        [x.setweight(0) for x in servers if x.status == "DOWN"]
        # anything that has been weighted down to 0 is considered SOFT STOPPED for for maintenance
        [x.setstate('drain') for x in servers if x.status == "UP" and x.weight == '0']

    Sets the weight for each backend server (highest weight for lowest latency)
    def set_weights_based_health_check_duration(self):
        servers = self.hap.backend('backendnodes').servers()
        stats = [x.stats_per_process()[0][1] for x in servers if x.status == 'UP']
        # sort by latency
        sorted_stats = sorted(stats, key = lambda s: int(s['check_duration']), reverse=False)
        perc = 100.0
        # set weight by sort index 
        for i in range(0, len(sorted_stats)):
            cur_weight = math.ceil(100 - i/len(sorted_stats) * 100)
            [x for x in servers if == sorted_stats[i]['svname']][0].setweight(cur_weight)

either way I'd be interested to see if anybody can substantiate a better means to ensure usefulness using FREE+PUBLIC+PROXY+SERVERS and actually make it easy to use, I started implementing this as a docker container along with my scanner:

and I had pretty good success with this when I was testing it, it just need s to be finished:

Copy link

@paigeadelethompson paigeadelethompson commented Mar 11, 2019

Also with regards to the haproxy solution id reccomend using something like this along with the necessary iptables (example below) rules to masq all tcp outbound except from haproxys uid .. this whole path is a bit of a heavy hand but its one that i know for sure works because ive set it up before. You can also masq udp 53 to go to tordns or something iptables. I suggest also making an isolated gateway to masquerade clients for that are connecting out which is how i have my vpns setup and they cant accidently leak traffic if the vpn connection drops.

Iptables transproxy rules
iptables -t nat -A OUTPUT -o lo -j RETURN
iptables -t nat -A OUTPUT -d -j RETURN
iptables -t nat -A OUTPUT -d -j RETURN
iptables -t nat -A OUTPUT -m owner --uid-owner proxy-owner -j RETURN
iptables -t nat -A OUTPUT -p tcp --syn -j REDIRECT --to-ports $PROXY_PORT

iptables -A OUTPUT -o lo -j ACCEPT
iptables -A OUTPUT -d -j ACCEPT
iptables -A OUTPUT -m owner --uid-owner proxy-owner -j ACCEPT
iptables -A OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A OUTPUT -j LOG
iptables -P OUTPUT DROP
Just need to figure out what to do about general (any) udp traffic now, i want to try to do something with socks5, but haproxy does not support udp endpoints and i know it wouldnt be reliable without a middle tier to manage which socks proxy to use, not sure if it can be done that way or not maybe a job for something else similiar to go any proxy

Copy link

@lessless lessless commented May 30, 2019

Just want to say that this feature is still quite relevant :)

Copy link

@Mikaela Mikaela commented Aug 7, 2019

Currently the wiki tells Tor users to use MapAddress .onion <lan-address> which adds additional difficulties.

If ZNC supported SOCKS proxies, Tor users could simply enter MapAddress ajnvpgl6prmkb7yktvue6im5wiedlz2w32uhcwaamdiecdrfpwwgnlqd.onion to their torrc and thus avoid the /znc *addfingerprint dance.

Currently this doesn't work, MetaNova and another person tested it with the current proxychains instructions and failed due to "Cant resolved server hostname", which MetaNova thinks is caused by ZNC trying to resolve before the query is sent to Tor which would send it to the onion address.

2019-08-07T22:54:42+0300 <MetaNova> Mikaela: also, you need to edit your last comment on #143
2019-08-07T22:54:43+0300 <ZNC-Linker> “Support connecting to IRC via a SOCKS proxy [$15]” (open)
2019-08-07T22:54:46+0300 <MetaNova> "Currently the wiki tells Tor users to use MapAddress .onion <lan-address> which adds additional difficulties."
2019-08-07T22:54:58+0300 <MetaNova> the wiki says to 'mapaddress <lan-ip> .onion'
2019-08-07T22:56:36+0300 <MetaNova> and it's '/znc AddTrustedServerFingerprint' not '/znc *addfingerprint'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet