ConnectionRefusedError: [Errno 111] Connection refused

Executive Summary.

I get "connection refused 111" when trying to communicate over sockets in Python. When the connection is refused, THE LISTENER STOPS LISTENING. Same problem occurs using import of multiprocessing.connection, socket, zeromq.

My feeling is that the link between Python and the OS/network doesn't work. However the NC and socket commands issued in a ubuntu terminal can communicate over the same port.

Notwithstanding the inconvenience it's causing me, there is obviously a severe security risk if an invalid connection request causes a socket to stop listening. Ideal for denial of service attacks.

Evidence:

I have two programs:

t2.py

from multiprocessing.connection import Listener
def main(): listener = Listener(('192.168.1.100', 16001), authkey=b'password') print ("listener ready", listener) running = True while running : print ("ready to connect") conn = listener.accept() print('connection accepted from', listener.last_accepted)
if __name__ == "__main__": main()

and

t1.py

from multiprocessing.connection import Client
def main(): address = ('192.168.1.100', 16001) conn = Client(address, authkey = b'password')
if __name__ == "__main__": main()

When I start the listener (f5 in IDLE), it seems to start ok.

>>>
==================== RESTART: /home/william/Midas/api/t2.py ==================== listener ready <multiprocessing.connection.Listener object at 0x7fccdd472130>
ready to connect

and the socket starts listening:

ss -lt

State Recv-Q Send-Q Local Address:Port Peer Address:Port Process

LISTEN 0 1 192.168.1.100:16001 0.0.0.0:*

However, when I start the client (f5 in IDLE) I get this:

 Traceback (most recent call last): File "/home/william/Midas/api/t1.py", line 25, in <module> main() File "/home/william/Midas/api/t1.py", line 15, in main conn = Client(address, authkey = b'password') File "/usr/lib/python3.8/multiprocessing/connection.py", line 502, in Client
c = SocketClient(address) File "/usr/lib/python3.8/multiprocessing/connection.py", line 630, in SocketClient
s.connect(address) ConnectionRefusedError: [Errno 111] Connection refused

and the listening socket disappears.

ss -lt

State Recv-Q Send-Q Local Address:Port Peer Address:Port Process

LISTEN 0 5 127.0.0.1:ipp 0.0.0.0:* LISTEN 0 1 127.0.0.1:36093
0.0.0.0:*
LISTEN 0 5 [::1]:ipp [::]:*

Ive tried changing port numbers, setting FW rules, IP addresses from hard-coded to "localhost", ... remote client (on Windows) etc etc. Nothing works although symptoms vary.

Ive tried programming the connection using the "socket import" and have exactly the same results. zeromq doesn't work either.

However the NC and socket commands issued in a terminal can communicate over the same port.

fwiw Im running Ubuntu 20.04.2 LTS. Apart from the one client I tried on windows, all testing is done on a single ubuntu system. Its a fairly new install, so its unlikely I've broken something.

Please can someone tell me what I'm doing wrong?

My feeling is that the link between Python and the OS/network doesn't work.

Notwithstanding the inconvenience it's causing me, there is obviously a severe security risk if an invalid connection request causes a socket to stop listening. Ideal for denial of service attacks.

1 Answer

I couldn't reproduce your issue, thus not sure what's the problem. But, some remarks.

I added a simple ping-pong exchange to your code:

# t2.py
from multiprocessing.connection import Listener
listener = Listener(('127.0.5.1', 16001), authkey=b'password')
print ("listener ready", listener)
running = True
while running : print ("ready to connect") conn = listener.accept() print('connection accepted from', listener.last_accepted) msg = conn.recv() print(f"received: {msg}") conn.send(b"PONG")
# t1.py
from multiprocessing.connection import Client
address = ('127.0.5.1', 16001)
conn = Client(address, authkey = b'password')
conn.send(b"PING")
print(conn.recv())

and also changed the listening address to one from the link-local subnet 127.0.0.0/8.

Then simply using 2 terminal tabs/windows, run t2.py then t1.py 3 times:

$ python t2.py
listener ready <multiprocessing.connection.Listener object at 0x7fb115c18a00>
ready to connect
connection accepted from ('127.0.0.1', 36702)
received: b'PING'
ready to connect
connection accepted from ('127.0.0.1', 36704)
received: b'PING'
ready to connect
connection accepted from ('127.0.0.1', 36706)
received: b'PING'
ready to connect

The server process continues to run, as expected. The client tab:

$ python t1.py
b'PONG'
$ python t1.py
b'PONG'
$ python t1.py
b'PONG'

Please pay attention... You may think these things you named are the same — but they are significantly different:

multiprocessing.connection, socket, zeromq.

The python-builtin import socket module is direct translation of the classic BSD sockets API. The "sockets API" is what defines such things as: port, listening on a port, connecting to a port, accepting a connection, send, recv, close and a few more functions. A book on network programming may help (e.g. this one as a random example — I don't endorse it). The sockets API is almost 40 years old, so you'll also easily find free learning materials online.

Next, import multiprocessing module. It's a completely different story. It provides helpers for multi-process Python programs. Those create multiple PIDs and can run on multiple processor cores. Almost certainly you'll want these processes to talk to each other to do useful work. This is where sockets come handy: since processes are isolated by OS from each other, network provides a way to build that communication (even if it's localhost-only). The sub-module multiprocessing.connection provides ergonomic helpers exactly for that.

Next, ØMQ is altogether a separate project (it's not python-builtin; neither it's python-specific). It does something interesting; it redefines another "socket API". ØMQ socket ≠ BSD socket. Zeromq sockets can do things which BSD sockets can't (pub/sub, fanout, app-level routing). Zeromq sockets are built "on top of" BSD sockets; if you have troubles with the lower-level API, I would recommend to approach ZMQ only after you get comfortable with bare basic sockets.

Nothing works although symptoms vary.

Again, you should get comfortable with interpreting network failure modes. The raised error codes have precisely defined meanings. For example, the classic Connection refused errno 111 means that the initial SYN packet to the host you connect() to was responded with an RST packet instead of the normal SYN+ACK — which usually happens when there's no program listening to the given port on the remote computer you connect() to.

One more remark with regards to your security concerns. You should always assume that the network is adversarial (hostile), regardless if it's indeed true at that point in space & time — even the localhost network. This is why the higher-level multiprocessing API has the authkey parameter; it's practically always needed. The password bytestring is one of the worst values for authkey imaginable, try something better. An active network adversary could, theoretically, explain your issue; there's something called "RST injection attack". You might've simply exhausted the listen backlog/SOMAXCONN, too.

Lastly, Wireshark is a wonderful tool.

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

You Might Also Like