Not able to read UDP packets on a server using Python - python

I'm trying to stream a video from a webcam installed on a BeagleBoneBlack (linux device) to a server (Windows server). The BeagleBone is connected to the Internet using DHCP (dynamic IP) and basically sends UDP packet to a server. On the server side I implemented a simple python program using sockets that should easily read UDP packet coming from a specific IP or on a specific port. In wireshark I'm able to see the packets arriving on the server but the python program is not able to catch them. I tried to listen on different IP such as 'localhost' or specific IP but nothing seems to work.
Python program server side:
import socket
IP = '192.168.23.240' #IP of the BeagleBone on Wireshark
IP = '109.164.170.155' #IP of the router in which the BeagleBone is attached
IP = '0.0.0.0' #localhost
IP = '' #localhost
IP = '192.168.0.21' #IP localhost server
IP = 'localhost' #localhost
PORT = 5454
if __name__ == "__main__":
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((IP,PORT))
f = open('file.mp4','wb')
data, addr = s.recvfrom(4096)
print 'Receiving from: ' +str(addr)
for i in xrange(1000):
f.write(data)
data, addr = s.recvfrom(4096)
print 'receiving from ' + str(addr) + ' ...'
f.close()
s.close()
In wireshark server side:
How is possible that I'm able to read the packets in wireshark but not using a simple python program? Someone know what am I doing wrong here?

If you run your program verbatim as you posted, it listens on localhost only, while your Wireshark screenshot suggests you're sending packets to "real" NIC with private IP address.
Are you sure your program does not work? When I fed it with netcat command like so:
cat myfile | nc -u 127.0.0.1 5454
it worked:
receiving from ('127.0.0.1', 38182) ...
receiving from ('127.0.0.1', 38182) ...
receiving from ('127.0.0.1', 38182) ...
Note I was sending from localhost to localhost. This reinforces hypothesis you have a simple network config/port configuration problem, not the Python program not working.
Do netstat -a on Windows machine to see if your program really listens on indicated address.
If it does, maybe your local Windows firewall blocks the connection? Can you try turning it off for a moment?

Related

Socket module (python) works but doesn't use specified port number?

I'm using the socket module from Python 3.7 (shouldn't matter, as I tried activating a different Python version from different venv's).
The problem is that I've created a TCP connection listening at port 65432, an arbitrary number that I selected for this simple demo.
server.py looks like the following:
import socket
HOST = '127.0.0.1' # Standard loopback interface address (localhost)
PORT = 65432 # Non-privileged ports are > 1024
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT))
s.listen()
conn, addr = s.accept()
with conn:
print('Connected by', addr)
while True:
data = conn.recv(1024)
if not data:
break
conn.sendall(data)
client.py is relatively straightforward as it makes a connection with 127.0.0.1:65432.
import socket
HOST = '127.0.0.1' # The server's hostname or IP address
PORT = 65432 # Port used by the server
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((HOST, PORT))
# Send its message and then read the server's reply and prints it
s.sendall(b'Hello, world')
data = s.recv(1024)
print('Received', repr(data))
Executing server.py to open the port 65432 for listening (in first console) and then executing client.py to send a simple 'hello world' message (in a second console). This is what got printed to the first console:
Connected by ('127.0.0.1', 56051)
So far so good. Port 56051 connecting to port 65432, right? No.
I execute netstat -am (command tool utility to see state of sockets on the host machine) and found this:
Active Internet connections (including servers)
Proto Recv-Q Send-Q Local Address Foreign Address (state)
tcp4 0 0 127.0.0.1.51495 *.* LISTEN
Instead of 127.0.0.1.65432 as local address, it is using port 51495 instead.
Doing another verification check, this time firing off lsof -i -n:
COMMAND PID FD TYPE DEVICE SIZE/OFF NODE NAME
Code\x20H 51214 37u IPv4 0x1af15eb424ba89f3 0t0 TCP 127.0.0.1:51495 (LISTEN)
Both verifications confirmed that port 51495 is being used instead of 65432 as specified in my server.py and client.py scripts. Any leads or tips? Many thanks in advance!
65432 is the port number of your server socket, not your client socket. As the client end is not attached with any specific port number, it will be dynamically allocated with port number, every time you run the client code.
As far as I understood, you mentioned -
Connected by ('127.0.0.1', 56051)
is shown on the first console which is your server console. so this port number is port number of client socket. not the server socket.
In the server code, you are using, s.accept(), this function returns the connection temporary id and the address of the client which made the request. same thing you are trying to print in the code.
As #ottomeister pointed out, the process name was the first giveaway. The process name should have been Python but it showed VS Code instead, which is indicative that the port 51495 is opened by the VS Code process and has nothing to do with our socket module code.
The way the context manager was setup means that the connection will be closed the moment the last line (in this case, socket.sendall()) is executed. So the server socket is not active anymore.
I run netstat after the client socket has connected, by this point the server port is closed.
When I monitor the ports status while the server port is open (before the client socket connects with it) then sure enough 65432 is what appeared. This is confirmed in netstat, lsof and also nmap. A simple print statement after the socket connection is successful will also confirmed that the server port is in fact using the specified port number, which is 65432.
Sorry for the inconvenience, and again much appreciation to Ottomeister for first pointing this out.

First computer doesn't receive UDP packet sent from Second computer

Today i was trying Python's socket module, but i failed to send/recieve from one PC to another.
At first i tried doing everything on single PC:
Receiver:
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
ip = socket.gethostbyname(socket.gethostname())
port = 5003
s.bind((ip, port))
while True:
data, addr = s.recvfrom(1024)
print(data, addr)
Sender:
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
ip = # I wrote ip manually from socket.gethostbyname(socket.gethostname())
port = 5003
s.sendto("Hello!", (ip, port))
Doing first script on first command line and other on second, on single PC, would work fine. But doing from one PC to another would not.
Whenever i executed Receiver script on first PC, and Sender script on second PC, there were no updates, First PC couldn't receive packet.
Also sending packet from PC2 to PC1 works, but vice versa doesn't.
Operating systems:
PC2 = Windows 8.1 64 bit;
PC1 = Mac OS X El Capitan 10.11.1 64 bit;
I have also tried adding outbound rule in Windows firewall, allowing all connections for specific port.
What could the problem be? Is it because of firewall? If not then am i doing this incorrectly?
Found the problem:
Short:
socket.gethostbyname(socket.gethostname()) contained IPv4 address of VirtualBox. Wireless LAN adapter IPv4 was different, and would receive UDP packet.
Long:
I was looking for Wireless Lan Adapter IPv4 address in ipconfig would be same in socket.gethostbyname(socket.gethostname()), but turns out
socket.gethostbyname(socket.gethostname()) would give the address of VirtualBox Host-Only Network.
When i pinged the VM IPv4 it would give timeout request, but after pinging real local IPv4 it did work.
Fix:
When oracle virtualbox are set, How to get local ip address in python

Connecting to a simple sockets python server remotely

I am trying to setup a very simply sockets app. My server code is:
import socket
s = socket.socket()
host = socket.gethostname()
port = 1234
s.bind((host,port))
s.listen(5) #Here we wait for a client connection
while True:
c, addr = s.accept()
print "Got a connection from: ", addr
c.send("Thanks for connecting")
c.close()
I placed this file on my remote Linode server and run it using python server.py. I have checked that the port is open using nap:
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
1234/tcp open hotline
I now run the client.py on my local machine:
import socket # Import socket module
s = socket.socket() # Create a socket object
port = 1234 # Reserve a port for your service.
s.connect(("139.xxx.xx.xx", port))
print s.recv(1024)
s.close # Close the socket when done
However I am not getting any kind of activity or report of connection. Could someone give me some pointers to what I might have to do? Do I need to include the hostname in the IP address I specify in the client.py? Any help would be really appreciated!
I've just summarize our comments, so your problem is this:
When you trying to using the client program connect to the server via the Internet, not LAN.
You should configure the
port mapping on your router.
And however, you just need configure the
port mapping for your server machine.
After you did that, then you can use the client program connect to your server prigram.

Can't perform TCP-handshake through a NAT between two NICs with SO_BINDTODEVICE

I'm trying to connect my computer to both sides of a NAT (run by OpenWRT) and to establish a TCP connection through the NAT:
I run a DHCP server on my first NIC (eth0, ip address 129.104.0.1) and connect it to the WAN port of the router (ip address 129.104.0.198)
I connect my wifi (wlan0, ip address 192.168.1.119) to the router's SSID behind the NAT
I'm using python and the SO_BINDTODEVICE option to send packet between a server (on eth0) and a client (on wlan0) through the NAT:
For the server:
self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server.bind((str(self.local_ip_addr),self.handler.port))
self.server.setsockopt(socket.SOL_SOCKET,25,self.iface.name+"\0")
self.server.listen(10)
while self.stopped() is False:
connect = self.server.accept()[0]
connect.settimeout(1)
connect.close()
self.server.close()
For the client:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, 25, self.iface.name + "\0")
sock.settimeout(1)
try:
sock.connect((self.dest,self.handler.port))
sock.close()
expect socket.timeout, socket.error as e:
return -1
My problem is that the connection times out before. I wiresharked both my interfaces and it seems the problem resides on the client's side:
wlan0 sends a TCP SYN packet to 129.104.0.1
The packet is correctly NATed by the router and is received from 129.104.0.198 by eth0
eth0 replies with a SYN,ACK packet, which is correctly NATed back to wlan0
wlan0 does not understand this SYN,ACK and tries to retransmit the first SYN packet
I'm thinking it might have something to do with the linux-kernel refusing to receive a packet from an address that belongs to the machine but if anyone has a clue it would be of great help!
EDIT: I narrowed it down: it is indeed a kernel issue, the packets sent from eth0 are perceived as "martians" by the kernel because they have a local ip address as source. Setting net.ipv4.conf.all.accept_local=1 did not help, neither did deactivating net.ipv4.conf.all.rp_filter=0.
After browsing the kernel sources and adding a lot of KERNEL_WARNING we found where it came from: the linux kernel is configured on certain mainstream distributions (Ubuntu...) to act as a router and drop packets where the source address is suspect in order to prevent spoofing (search "rp_filter" on https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt and RFC3704).
To allow such traffic you have to set some variables on your machine (as root):
sysctl -w net.ipv4.conf.all.accept_local=1
sysctl -w net.ipv4.conf.all.rp_filter=0
sysctl -w net.ipv4.conf.your_nic.rp_filter=0
where your_nic is the network interface receiving the packet. Beware to change both net.ipv4.conf.all.rp_filter and net.ipv4.conf.your_nic.rp_filter, it will not work otherwise (the kernel defaults to the most restrictive setting).

Hijacking a client socket

I have set up a server socket (plain raw socket) listening on port A. A client now connects to this server. OS opens up a port for the client for this purpose. Say port B is allocated to this client. Now my question is, can a 3rd script connect to this port B and send data. Or in other words can I spoof a response to the client as if it was coming from the server? I tried spoofing it using scapy, but it wasnt working.
server.py
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(("localhost", A))
s.listen(10)
ns, cli_addr = s.accept()
time.sleep(30) # so that i can trigger my 3rd script
goodclient.py
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("localhost", A))
print s.getsockname() # to get the local port of client - B
s.recv(1024)
badboy.py
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("localhost", B)) # connection refused error
s.send("hihihi")
scapybadboy.py
pack = IP(src="localhost", dst="localhost") / TCP(sport=A, dport=B) / "Hello"
send(pack) # Packet sent but not received by the client
Because server and client using SOCK_STREAM sockets, they both aware of TCP session(including port, IP and (SEQ_NUMBER,ACK_NUMBER)), so when session is already in process, you will have to perform TCP hikacking and IP spoofing in order to send messages in stream.
In other words, you will have to guess(or steal) ACK number of server in order to send fake messages to client using badclient.
However, if you will make somehow goodclient answer you and not a server you should run the following:
iptables -A FORWARD -j NFQUEUE --queue-num 1 , because your operating system doesn't know about session that you just "opened" with goodclient and it will send RST packet. This command will prevent it.

Categories

Resources