I found multiple answers that suggest using the SO_REUSEPORT socket option when multiple UDP clients need to listen for broadcasts on the same port. However I'm getting an error that this option is not available. Using python 2.7
from socket import *
s = socket(AF_INET, SOCK_DGRAM)
s.setsockopt(SOL_SOCKET, SO_REUSEPORT, 1)
try:
s.bind(('', MYPORT))
except:
print "Error connecting to the UDP stream."
Traceback (most recent call last):
File "qsorder.py", line 119, in <module>
s.setsockopt(SOL_SOCKET, SO_REUSEPORT, 1)
NameError: name 'SO_REUSEPORT' is not defined
I've tried SO_REUSEADDR and it does not give an error but only one client receives broadcasts. Any idea how to work around this?
You need to set SO_BROADCAST option on each socket:
s.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)
SO_REUSEPORT is not standard and usually means same thing as SO_REUSEADDR where supported.
Related
I know there is a similar question already, but none of the solutions solve my problem. Over ssh I am starting a script on a remote client with
nohup python script.py &
This script contains the following:
TCP_PORT = 5005
host = ""
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.settimeout(40)
s.bind((host, TCP_PORT))
s.listen(0)
c, addr = s.accept()
...some code...
try:
while True:
c.send(str(1).ljust(16).encode())
except Exception as e:
print("exiting main")
print(e)
c.close()
s.close()
When I run the code two times in e row, the second time I always get the above mentioned error. The log of the python output:
exiting main
[Errno 32] Broken pipe
Traceback (most recent call last):
File "LogImages.py", line 204, in <module>
main(interv)
File "LogImages.py", line 114, in main
s.bind((host, TCP_PORT))
OSError: [Errno 98] Address already in use
So obviously the process calls c.close() and s.close(). So how can the address still be in use?
Closing a socket just releases the handle to any underlying connection. It can still take the implementation some amount of time to complete the orderly shutdown of the connection and, during that time, the address is still in use.
For example, if you have an active connection and the other side isn't reading from it, the implementation will give it time to read the data that was sent. During that time, the address is still in use.
I have this code:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.bind(('10.0.0.253', 8080))
except:
s.close()
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('10.0.0.253', 8080))
s.listen(1)
conn, addr = s.accept()
which binds, then if it encounters an error with that, destroys the socket then creates a new one and binds it to the same IP and port. For some reason, even after closing the socket, I get this error:
Traceback (most recent call last):
File "C:\Users\other\Desktop\tcpReverseShell_Server.py", line 68, in <module>
main()
File "C:\Users\other\Desktop\tcpReverseShell_Server.py", line 66, in main
connect()
File "C:\Users\other\Desktop\tcpReverseShell_Server.py", line 43, in connect
s.bind(('10.0.0.253', 8080))
File "C:\Python27\lib\socket.py", line 228, in meth
return getattr(self._sock,name)(*args)
error: [Errno 10048] Only one usage of each socket address (protocol/network
address/port) is normally permitted
The only solution I've found is to use s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1), but when I try that I get this error: [Errno 10013] An attempt was made to access a socket in a way forbidden by its access permissions. I
I am on Windows 10, Python 2.7.13.
I can simulate your problem by running the python script twice concurrently. The problem is that some other application is currently also using the socket.
In your code, the except block is triggered when your socket fails to bind. However, when you try to .close() the socket and try again, it does nothing as it is trying to .close() an unbound socket. Hence, your code is equivalent to:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('10.0.0.253', 8080))
s.listen(1)
conn, addr = s.accept()
Note that when you .close() the socket, it also does not .close() the currently bound application, it attempts to .close() to socket object you created. So, trying to bind the socket again will fail.
To find out what is using the socket, you can use netstat:
netstat -aon | findstr :8080
This should give you something like:
TCP 127.0.0.1:8080 0.0.0.0:0 LISTENING 6604
Then, if you want to kill it forcefully, you can use TaskKill and the application's PID:
TaskKill /PID 6604 /F
My python test code:
import socket
s1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s1.bind(('192.168.1.1', 80))
s1.listen(5)
s2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s2.bind(('0.0.0.0', 80))
s2.listen(5)
I got this error:
fpemud-workstation test # ./test.py
Traceback (most recent call last):
File "./test.py", line 11, in <module>
s2.bind(('0.0.0.0', 80))
File "/usr/lib64/python2.7/socket.py", line 224, in meth
return getattr(self._sock,name)(*args)
socket.error: [Errno 98] Address already in use
192.168.1.1 is the ip address of my eth0 interface.
I think 0.0.0.0:80 and 192.168.1.1:80 should be able to co-exist.
Packets with dst-addr 192.168.1.1 goes to socket s1, packets with other dst-addr goes to socket s2.
You cannot bind to both 0.0.0.0:80 and any other IP on port 80, because 0.0.0.0 covers every IP that exists on the machine, including your 192.168.1.1 address. It doesn't mean 'any other destination address', it means 'all interfaces on this box'.
Because it's a contradiction in terms. 0.0.0.0 means 'accept connections from any local IP address'. 192.168.1.1 means 'accept connections only that are addressed to 192.168.1.1'. What exactly do you expect to happen if someone connects to 192.168.1.1?
Despite what other answers have said, this should be possible - it's just that the way bind works is implementation dependent.
On Windows, for example, your code will probably work fine as is. On some *nix operating systems I believe you can get it to work by setting the SO_REUSEADDR socket option. On Linux, I've been able to get it to work using the SO_REUSEPORT socket option, but only on kernel version 3.9 or later.
Unfortunately the SO_REUSEPORT property isn't directly supported in current versions of python, so we have to define it manually.
Basically your code should look like this:
# This adds support for the SO_REUSEPORT constant if not already defined.
if not hasattr(socket, 'SO_REUSEPORT'):
socket.SO_REUSEPORT = 15
s1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s1.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
s1.bind(('192.168.1.1', 80))
s1.listen(5)
s2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s2.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
s2.bind(('0.0.0.0', 80))
s2.listen(5)
I am trying to create a raw socket in Python that listens for UDP packets only:
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_UDP)
s.bind(('0.0.0.0', 1337))
while True:
print s.recvfrom(65535)
This needs to be run as root, and creates a raw socket on port 1337, which listens for UDP packets and prints them whenever they are received; no problems there.
Now let's make a little client to test if this works:
import socket
c = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
c.connect(('127.0.0.1', 1337))
c.send('message 1')
c.send('message 2')
c.send('message 3')
c.send('message 4')
c.send('message 5')
c.send('message 6')
Consistently, only the first, third, and fifth message (message 1, message 3 and message 5) will get through and be printed in the server output. The second, fourth, and sixth messages do not show up on the server output, and instead the client gets an exception:
>>> c.send('message 2')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
socket.error: [Errno 111] Connection refused
Running this in Wireshark shows that it is getting an ICMP reply for "Destination unreachable". I have been able to reproduce this on 3 distinct machines (all running Linux though). Am I missing something? Is this expected behaviour for UDP to consistently drop packets, since protocols using it are supposed to be tolerant of packet loss? Even so, why would packets be dropped when sent on the local interface?
Binding the server to 127.0.0.1 instead of 0.0.0.0 has the same result.
Solved it in kind of a silly manner; please let me know if there is another way, and I will change the accepted answer.
The solution is simply to use two sockets bound on the same port; one raw, one not raw:
import socket, select
s1 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s1.bind(('0.0.0.0', 1337))
s2 = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_UDP)
s2.bind(('0.0.0.0', 1337))
while True:
r, w, x = select.select([s1, s2], [], [])
for i in r:
print i, i.recvfrom(131072)
This makes the "Destination unreachable" ICMP packets go away and makes all packets go through fine. I think the operating system wants a non-raw socket listening on the port for things to go well, and then any raw sockets listening on that same port will receive copies of the packets.
I wrote this code.
import socket
host = 'localhost'
port = 3794
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
s.bind((host, port))
while 1:
print 'Type message you want to send...'
msg = raw_input()
if msg == '':
s.close()
break
s.sendall(msg)
and next execute this code.
Traceback (most recent call last):
File "socket.py", line 11, in ?
s.bind((host, port))
File "<string>", line 1, in bind
socket.error: (99, 'Cannot assign requested address')
What's wrong?
Do you know solutions?
This means that you already have a socket bound to 3794 port.
It may be another application or it means that port didn't got released yet after the previous run of your own script (it happens, if script terminated improperly).
Simply try to use another port number - I believe everything will work fine.
I had this same problem and it was caused by trying to listen on the wrong host. When I changed it to an IP that was actually associated with the machine the code was running on (localhost), the problem went away.
This error comes up mostly due to the the port being already used by another application/service .
Choose a port number above the range of registered ports , i.e 49151