Receiving UDP broadcast packets on Linux - linux

We have existing software that periodically broadcasts UDP packets to a specific port (7125) on the local subnet (x.x.x.255). We have monitoring software running on HP-UX (11.11) that is able to receive these packets no problem. However, after porting the monitoring software to Linux (RHEL 6.1) we have found that it does not receive the broadcast packets. tcpdump shows the packets arriving at the Linux host, but the kernel does not send them through to our software.
I've been using a couple of python 2.x scripts that mimic the socket API calls the monitoring software uses to test different scenarios. The Linux kernel passes the packets to the receiver software if the sender uses unicast (10.1.0.5), but not broadcast (10.1.0.255). I've been searching the web for several days and have not found anyone with the same problem. Any ideas?
receiver.py
from __future__ import print_function
import socket
localHost = ''
localPort = 7125
remoteHost = '10.1.0.5'
remotePort = 19100
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
s.bind((localHost, localPort))
s.connect((remoteHost, remotePort))
print('Listening on {0}:{1} for traffic from {2}:{3}'.format(localHost, localPort, remoteHost, remotePort))
data = s.recv(1024)
print('Received: {0}'.format(data))
s.close()
sender.py
from __future__ import print_function
import socket
import time
localHost = ''
localPort = 19100
remoteHost = '10.1.0.255'
remotePort = 7125
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
s.bind((localHost, localPort))
s.connect((remoteHost, remotePort))
data = 'sending this from {0}:{1} to {2}:{3}'.format(localHost, localPort, remoteHost, remotePort)
print(data)
print('2')
time.sleep(1)
print('1')
time.sleep(1)
s.send(data)
print('sent at {0}'.format(time.ctime()))
s.close()

Well, I suggested this answer in a comment, and it proved correct in practice. I would like to investigate surrounding nuances further with my own code, but this is the canonical case-closer.
In addition to setting the SO_BROADCAST socket option on both sides (as you are already correctly doing), you must also bind your receiver to the broadcast address (e.g., INADDR_BROADCAST, which is 255.255.255.255 and essentially serves the same role as INADDR_ANY for unicast).
Apparently, in the HP-UX configuration of the original poster, a UDP socket bound to a unicast address (or INADDR_ANY, specifically) but with the SO_BROADCAST socket option set will still receive all UDP datagrams addressed to the local broadcast address as well as unicast traffic directed at the host.
Under Linux, this is not the case. Binding a UDP socket, even when SO_BROADCAST-enabled, to INADDR_ANY is insufficient to receive both unicast and broadcast datagrams on the bound port. One can use a separate INADDR_BROADCAST-bound SO_BROADCAST socket for the broadcast traffic.

Related

Network sniffing raw format with socket programming at python

I want to sniff network traffic. I used to this code
but this code sniff only TCP packets. I want to sniff all packet formats. How can i do this.
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_TCP)
while True:
print s.recvfrom(65565)
etc. if i sniff UDP packets, i using to this code
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_UDP)
while True:
print s.recvfrom(65565)
You can try Scapy module for python. You can sniff all protocols with Scapy. If you want to see which protocol supported, type ls() to Scapy console.
for more details, please check this source: https://github.com/besimaltnok/scapy-cheatsheet
Best regards,
Besim.

Why is my Socket Client not allowing the outgoing connection in python 3?

I have created a very simple UDP Socket client and server in python3.
I'm trying to send the simple message 'hello' to the server and I am getting the error:
ConnectionRefusedError: [WinError 10061] No connection could be made because the target machine actively refused it
I'm not sure that it's actually the target machine's fault as the target machine is an AWS EC2 Ubuntu instance with 'All Traffic Allowed' configured with the security group.
I'm convinced it has to be some sort of outbound policy on my desktop computer...
Any help is appreciated.
Here is my code:
client.py
import socket
client_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_sock.connect(('servers public ipv4 ip', 8089))
client_sock.send('hello'.encode())
server.py
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('localhost', 8089))
s.listen(5) #5 connections
while True:
conn, addr = s.accept()
buffer = conn.recv(64)
if len(buffer) > 0:
print(buffer.decode())
break
First, despite your repeated claims (in body and tags) that you are using UDP you are actually using TCP as can be seen from your use of SOCK_STREAM and accept.
s.bind(('localhost', 8089))
You explicitly bind the server to localhost. But localhost is only the loopback interface of the computer (127.0.0.1) which is not reachable from outside. If you want to accept connections from other systems you need to either bind to the IP address of the specific network interface or broadly to 0.0.0.0 - or simply use s.bind('',8089).

Basic UDP networking doesn't receive

I'm trying to learn UDP networking so I tried the simplest code to begin with. It's a python code client-server that works perfectly when I send data to localhost or to the LAN IP from the same computer, but it doesn't work when I try to send from my computer using the public IP, and also doesn't work from another computer using private network IP or public IP.
I did the port forwarding, created the input rules for windows firewall, turned off the router internal firewall, and it still doesn't work.
When I scan my port from canyouseeme.org or using netcat it says connection refused and port closed.
Maybe somebody can guess what is happening here or what may I do to succeed?
I write the code below in case it's needed.
Server:
import socket
UDP_IP = "0.0.0.0"
UDP_PORT = XXXX
sock = socket.socket(socket.AF_INET, # Internet
socket.SOCK_DGRAM) # UDP
sock.bind((UDP_IP, UDP_PORT))
while True:
data, addr = sock.recvfrom(1024) # buffer size is 1024 bytes
message = data.decode()
print("received message:", message)
Client:
import socket
UDP_IP = "192.168.1.133"
UDP_PORT = XXXX
MESSAGE = "Hello, World!"
print("UDP target IP:", UDP_IP)
print("UDP target port:", UDP_PORT)
print("message:", MESSAGE)
sock = socket.socket(socket.AF_INET, # Internet
socket.SOCK_DGRAM) # UDP
sock.sendto(MESSAGE.encode(), (UDP_IP, UDP_PORT))
Thanks in advance.
After some investigation I have found a partial solution. I'm posting an answer because it may help some people with similar problems, but it's not the best solution yet, so the issue is still there.
I found that there's no problem in communicating within a LAN if I completely disable the firewall in both computers. I don't know why the input rules or exceptions don't work.
For networking beyond the LAN I have tried successfully to use a virtual LAN (i.e. hamachi) and there's no necessity of port forwarding nor disabling the firewall. The bad thing about hamachi is that I don't control the protocol it uses, and I don't control the way of ensuring reliability.
For the applications I'm dealing with right now I probably have enough with this solution, but it would be interesting to know more.

Create a virtual serial port connection over TCP

I am developing an application that should be able to write to a virtual serial port and receive data through the same port from remote clients over network.
The application runs on a linux server. I am new in using serial ports and I have some questions on this topic.
Clients
The client can establish a TCP connection to a server. When we setup a client, we have to provide the IP address of the server, a tcp port (usually 8080) and a virtual com port.
The client then will automatically try to connect to the server.
Server
The server has a virtual com port, the same we set in the client config (e.g. COM1). When an application on the server writes data to this port, the data should be send to all clients connected via tcp. The response from the clients is send over TCP back to the server which can read it over the virtual serial port.
Question
On windows I used a virtual serial port connector http://www.eterlogic.com/Products.VSPE.html which did most of the work. However I want to solve this problem on linux machines.
My question is, how can I create a TCP server that has a virtual serial port attached and can send/receive data through this port over TCP to listening clients?
Try socat. Possible scenario:
socat pty,link=/dev/virtualcom0,raw tcp:192.168.254.254:8080&
socat creates TCP connection to 192.168.254.254:8080, so that everything, that will be written to /dev/virtualcom0 will be forwarded to 192.168.254.254:8080 and vice versa.
Another approach would be to use RFC2217 via ser2net on Linux sever side and RFC2217 driver on Windows side (for example http://www.hw-group.com/products/hw_vsp/index_en.html single port version). You can also try to get http://pyserial.sourceforge.net/ to work with ser2net.
you have socat and ser2net and other programs but my experience is very bad... not working properly. I've done this small python program, can be useful. Update port, baudrate... then use any tcp client. Remove first line if don't want to use is as auto executable script
#!/usr/bin/python
import socket
import sys
import serial
#open serial port
ser = serial.Serial('/dev/ttyAMA0', 115200, timeout=0)
#create socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
#bond to the port. Don't use localhost to accept external connections
server_address = ('', 2105)
print('starting up on {} port {}'.format(*server_address))
sock.bind(server_address)
#listen
sock.listen(1)
#loop
while True:
#waits for a new connection
print('waiting for a connection')
connection, client_address = sock.accept()
try:
print('connection from', client_address)
#continously send from serial port to tcp and viceversa
connection.settimeout(0.1)
while True:
try:
data = connection.recv(16)
if data == '': break
ser.write(data)
except KeyboardInterrupt:
connection.close()
sys.exit()
except Exception as e:
pass
received_data = ser.read(ser.inWaiting())
connection.sendall(received_data)
except Exception as e:
print e
finally:
#clean up connection
connection.close()
The software will help to establish server and client connection over TCP http://www.serial-com-port.com/
I use it for creating virtual serial communications over network, but I have the real RS232 port on the computer. So I just transfer the data over network. If you need to create a virtual COM on the server too, use the Virtual Serial Port Driver.

UDP broadcast and unicast through the same socket?

I have a Linux application that opens a UDP socket and binds it to a port. I haven't had any problem sending unicast packets through the socket. I had occasion to send a broadcast packet, so I enabled SO_BROADCAST, which allowed the broadcast packets to pass, but then I noticed that the unicast packets were being broadcast as well. Is this expected behaviour for a UDP socket, or is it more likely that I've misconfigured something?
From what I understand SO_BROADCAST is a socket option. So if you enable it on your socket this socket will broadcast. I guess you will need to open different sockets if you want to do unicast and broadcast from the same code.
I have not done much hands on programming here, but you probably need to provide more information about the library, OS version, code, etc. Maybe a code sample?
If I remember the books I read, if you set the flag on the socket, that is going to affect all datagrams sent from the socket, because the socket is a basically a data structure of network flags + a file descriptor.
I have figured out the same issue on Linux about having a socket getting unicast and broadcast at the same time. I solved the problem as follow (pseudo-code):
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
Open the socket
setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &1)
Allows incoming and outgoing broadcast from this socket
bind(sock, bindaddr, sizeof(struct sockaddr) with
bindaddr.sin_family = AF_INET
bindaddr.sin_port = <YourPort>
bindaddr.sin_addr.s_addr = INADDR_ANY
Get all incoming messages on any card for <YourPort>
The caveat is that there is no filtering (see caveat in 3.). So you will get all messages.
The sent messages are either unicasted or broadcasted depedning on the given address in the sendto().

Resources