I suspect this approach isn't going to work for you, but I may be wrong. I don't have an XP box to test on, and modern Windows restricts raw sockets in all kinds of ways XP didn't. But I'll give you more information to try to help explain why it isn't working, why it probably can't work, and what you can try.
But first, let me explain the right way to do this on Windows: SIO_RCVALL
. Like this:
recvSock.ioctl(socket.SIO_RCVALL, socket.RCVALL_IPLEVEL)
This tells Windows to deliver all IP packets destined for your machine to this socket. (A few packets destined for other machines may also be delivered, but in general they won't. If you want them, you need to put the NIC in promiscuous mode, with RCVALL_ON
instead.)
Note that "all packets" means a whole lot of packets you don't care about, so you will need to filter them. In other words, instead of reading one packet, you will need to keep reading packets, checking their local address, and skipping them until you find the one you want.
Don't try to bind the socket to a particular host and port when using SIO_RCVALL
. There are a number of problems getting this to work right, which change from version to version on Windows, and it's not worth the effort. And there's really no benefit—Windows will still deliver at least some packets meant for other ports, so you'll still need to filter them.
Alternatively, you can use winpcap
with winpcapy
, which makes it easy to set up packet capturing, with whatever options you want, on whatever interfaces you want, with custom filters, and receive the packets you want without all the fuss.
scapy
makes things even easier—although getting scapy
up and running on Windows may not be as easy—try the Windows scapy
project rather than doing it yourself.
Now, here's where you're going wrong.
I'm not sure why you've getting an error on the sendSock.bind
call, but it may be because 10000 is outside of the ephemeral port range. On XP, that range is 1025-5000 by default. See the MSDN bind
docs for details. But if you don't care what the source port is, you can always just sendto
without a bind
, and then use getsockname
to find out which port you ended up with, and then use that to bind
the other socket. However, you may not be able to pick a host if you don't pick a port. (This is platform-dependent, but I'm pretty sure on Windows XP, you can only use a non-INADDR_ANY
host and port 0
for TCP, not UDP.)
On Windows, if two live sockets are both bound to the same address (directly, or indirectly, e.g. via one being bound to 0.0.0.0:10000
and the other to 192.168.1.123:10000
), the kernel delivers packets to one of the two sockets arbitrarily and nondeterministically. See the MSDN article Using SO_REUSEADDR
and SO_EXCLUSIVEADDRUSE
for more details. Despite what those docs say, this isn't completely true for raw sockets. But, at least on some Windows versions, it's partly true.
Windows raw sockets with a protocol of IPPROTO_RAW
won't receive anything at all. Windows only delivers packets to raw sockets if the protocol matches, so an IPPROTO_UDP
packet won't be delivered to an IPPROTO_RAW
socket. But that one's easy to fix—just use IPPROTO_UDP
. See TCP/IP Raw Sockets in MSDN; the Send and Receive Operations section explains how packets are delivered.
Also, you may need to bind the remote side of the raw socket if you bind the local side. You can do that by calling connect
with the same address you used for sendto
on the UDP socket. This wasn't required in early WinSock2, but it may be in later XP service packs (at least with default settings).
This also may be affected (in unpredictable ways) by whether or not the built-in Windows firewall is enabled. Turn it off to avoid that.