Python's recvfrom() function not returning any data

766 Views Asked by At

I would like to preface that I am new to networking and still working on my python skills so go easy on me.

I have started working on a network scanning project and have played with multiple protocols to try and find what works best for my purposes. SSDP seems to be the best for me thus I have been playing with a little universal plug and play script I found to try and test how things are working on my network.

import socket  
import sys

dst = "239.255.255.250"  
st = "upnp:rootdevice"  
msg = [  
    'M-SEARCH * HTTP/1.1',
    'Host:239.255.255.250:1900',
    'Man:"ssdp:discover"',
    'MX:1',
    'ST:%s' % (st,),
    '']
    
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
s.bind((socket.gethostbyname(socket.gethostname()), 0))
print(s.getsockname())
s.settimeout(60)
byte_data = '\r\n'.join(msg) 
s.sendto(bytes(byte_data, 'utf-8'), (dst, 1900))
while True:  
    try:
        data, addr = s.recvfrom(32*1024)
    except socket.timeout:
        print("timeout has occurred")
        break
    print (f"$ {addr}\n{data}")
s.close() 

For some reason this always times out for me and never displays any data. After investigating using WireShark, I can see that my computer is sending out searches and devices are sending replies back to my computer. Does anyone know why this might be occurring (OS is windows 10). I will say I have increased the timeout numerous times to high amounts and still nothing is getting through.

1

There are 1 best solutions below

0
Mario Camilleri On

As pointed out in the comments, there should be an extra blank line in the M-SEARCH request header, so.

import socket
import sys

dst = "239.255.255.250"
st = "upnp:rootdevice"
msg = [
    'M-SEARCH * HTTP/1.1',
    'Host:239.255.255.250:1900',
    'Man:"ssdp:discover"',
    'MX:1',
    'ST:%s' % (st,),
    '',
    '']

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
s.bind((socket.gethostbyname(socket.gethostname()), 0))
print(s.getsockname())
s.settimeout(2)
byte_data = '\r\n'.join(msg)
s.sendto(bytes(byte_data, 'utf-8'), (dst, 1900))
while True:
    try:
        data, addr = s.recvfrom(32 * 1024)
    except socket.timeout:
        print("timeout has occurred")
        break
    print(f"$ {addr}\n{data}")
s.close()

Now it works. Also, with the SSDP MX header set to 1 it is pointless setting timeout to 60 - any device responding to the request MUST reply within MX seconds or not at all.

As it is, this should work fine on a system with a single network interface. But on a multi-homed system you will need to send the request on each interface by binding a socket to that interface, otherwise some UPNP devices might not be reachable.