Re: Intercepting UDP broadcasts
by duff (Parson) on Jan 30, 2004 at 17:10 UTC
|
This is probably no help whatsoever, but your code works just fine for me. RedHat 9, perl 5.8.0
Perhaps if recv() is blocking you should use IO::Select? (rampant straw grasping here :)
#!/usr/bin/perl
use strict;
use warnings;
use IO::Socket::INET;
use IO::Select;
my $sel = IO::Select->new;
my $port = getservbyname 'bootps', 'udp';
my $socket = IO::Socket::INET -> new (LocalPort => $port,
Broadcast => 1,
Proto => 'udp')
or die "Failed to bind to socket: $@";
$sel->add($socket);
my $n = 10;
my $mess;
while (1) {
my @r = $sel->can_read($n);
unless (@r) { print "Nothing after $n seconds\n"; next; }
$socket -> recv ($mess, 1024);
print "Saw a bootp request.\n";
}
__END__
| [reply] [d/l] |
Re: Intercepting UDP broadcasts
by Fletch (Bishop) on Jan 30, 2004 at 15:34 UTC
|
Not a direct solution, but worst comes to worst you could use Net::Pcap (and/or POE::Component::Pcap) to sniff the packets from the wire directly.
| [reply] |
Re: Intercepting UDP broadcasts
by monktim (Friar) on Jan 30, 2004 at 17:11 UTC
|
I get bootp requests with this code.
Update I don't know if the additional parameters had anything to do with it. I thought restarting the network printer was sending the msgs but apparently that isn't the case. I just got lucky and caught a few boots.
FYI: This is perl, v5.8.0 built for MSWin32-x86-multi-thread
Binary build 806 provided by ActiveState Corp.http://www.ActiveState.com
Built 00:45:44 Mar 31 2003
Running on Windows 2000 Workstation.
@ISA = qw(IO::Socket);
$VERSION = "1.26";
Update2: Abigail-II your code works stright up on my machine. I just got to test it now.
use strict;
use warnings;
use IO::Socket::INET;
my $port = getservbyname 'bootps', 'udp';
my $socket = IO::Socket::INET -> new (LocalPort => $port,
Broadcast => 1,
Proto => 'udp',
ReuseAddr => 1,
Type => SOCK_DGRAM)
or die "Failed to bind to socket: $@";
my $mess;
$socket -> recv ($mess, 1024);
if (defined $mess) {
print "Saw a bootp request.\n$mess\n";
} else {
print "No bootp request.\n";
}
| [reply] [d/l] |
|
| [reply] [d/l] |
Re: Intercepting UDP broadcasts
by jdtoronto (Prior) on Jan 30, 2004 at 16:08 UTC
|
I have never written a 'snooper' type programme in Perl, but I recall that recently I was scanning through a book titled "Programming the Network in Perl" (from a guy in Ireland, not the Lincoln Stein book). I saw some code in there called EtherSnooper. The only thing I could find in a search was this: http://users.telenet.be/jurgen.kobierczynski/support/ethersnooper.pl.txt
Looking at the source code it would seem that a series of modules in the NetPacket namespace would make it a soda to write something which would acheive the result, but not as elegantly as a direct implementation.
I don't know if this info will be useful, but I hope so!
jdtoronto | [reply] |
|
| [reply] |
|
Fair enough too. Now you explain what you are doing then I am completely lost - at least in Perl land!
...john
| [reply] |
Re: Intercepting UDP broadcasts
by Limbic~Region (Chancellor) on Jan 30, 2004 at 16:52 UTC
|
Abigail,
I wasn't going to reply because I have a sum total of 0 experience with socket/network programming. Since other people have wagered guesses and possibilities - I will too:
From the documentation, which I know you said you read, the example that looks most similar to yours is a bit different:
$sock = IO::Socket::INET->new (
PeerPort => 9999,
PeerAddr => inet_ntoa(INADDR_BROADCAST),
Proto => udp,
LocalAddr => 'localhost',
Broadcast => 1
) or die "Can't bind : $@\n";
In particular, the information concerning the peer. I am wondering if setting the PeerAddr to the broadcast does something special even though technically what you have should be picking up from any address. Unfortunately, I do not have the means to test presently.
Cheers - L~R | [reply] [d/l] |
|
I tried that, and it doesn't make a difference.
Abigail
| [reply] |
Re: Intercepting UDP broadcasts
by sfink (Deacon) on Jan 30, 2004 at 18:10 UTC
|
This also works for me on RedHat 7.3 Linux. Here is the relevant portion of the strace output; perhaps it will be useful to compare against on whatever you're running on:
socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP) = 4
fcntl64(4, F_GETFL) = 0x2 (flags O_RDWR)
fstat64(4, {st_mode=S_IFSOCK|0777, st_size=0, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1,
+ 0) = 0x40112000
_llseek(4, 0, 0xbfffe900, SEEK_CUR) = -1 ESPIPE (Illegal seek)
fcntl64(4, F_GETFL) = 0x2 (flags O_RDWR)
fstat64(4, {st_mode=S_IFSOCK|0777, st_size=0, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1,
+ 0) = 0x40113000
_llseek(4, 0, 0xbfffe900, SEEK_CUR) = -1 ESPIPE (Illegal seek)
fcntl64(4, F_SETFD, FD_CLOEXEC) = 0
brk(0x818e000) = 0x818e000
setsockopt(4, SOL_SOCKET, SO_BROADCAST, [1], 4) = 0
bind(4, {sin_family=AF_INET, sin_port=htons(67), sin_addr=inet_addr("0
+.0.0.0")}}, 16) = 0
recvfrom(4, "\1\1\6\0ZeH\n\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0".
+.., 1024, 0, {sin_family=AF_INET, sin_port=htons(68), sin_addr=inet_a
+ddr("0.0.0.0")}}, [16]) = 300
fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 4), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1,
+ 0) = 0x40114000
write(1, "Saw a bootp request.\n", 21) = 21
| [reply] [d/l] |
Re: Intercepting UDP broadcasts
by coreolyn (Parson) on Jan 30, 2004 at 16:27 UTC
|
I think BrowserUK is on the right track. While slightly out my area I was comparing your code to the camel and the thing that struck me as missing was the Listen parameter. Which is defined as the "Queue size for listen" (IO::SOCKET::INET). The type should be set by the protocol, so I doubt that's in your way. I also noticed a reuse parameter was also not present in your code.
Not sure if it helps but as I've so rarely seen you actually ASK for help I figured I'd give it a shot.
| [reply] [d/l] [select] |
|
There is no queue size for UDP. If I add a Listen option
to the constructor, it dies:
Failed to bind to socket: IO::Socket::INET: Operation not supported
+at ./server line 9.
when trying to create the socket.
Adding a Reuse option doesn't help either.
Abigail | [reply] [d/l] |
Re: Intercepting UDP broadcasts
by coreolyn (Parson) on Jan 30, 2004 at 17:16 UTC
|
Well that leaves your $socket->recv as the culprit. I'm suspecting your are not getting 1024 bytes due to fragmentation of the packet. This info (Section 5.8) may be of assistance ( long story short a minimum datagram could be as small as 28 bytes ( IP + UDP header )) due to fragmentation.
| [reply] [d/l] |
|
The length argument is just the maximum that will be read.
It doesn't even work if you set it to 1.
Abigail
| [reply] |
Re: Intercepting UDP broadcasts
by Anonymous Monk on Jan 30, 2004 at 16:33 UTC
|
Just a shot in the dark. Would Reuse => 1 help? | [reply] [d/l] |
Re: Intercepting UDP broadcasts
by Anonymous Monk on Jan 30, 2004 at 16:47 UTC
|
Do you have to specify the socket type to be datagram? I'd think that was the default. Type => SOCK_DGRAM | [reply] |
|
IO::Socket::INET will use a default type of
SOCK_DGRAM for UDP sockets.
Abigail
| [reply] |
Re: Intercepting UDP broadcasts
by Plankton (Vicar) on Jan 30, 2004 at 16:54 UTC
|
Have you tried writing a test "broadcaster"? Maybe bootps is doing something unexpected.
Plankton: 1% Evil, 99% Hot Gas. |
| [reply] |
Re: Intercepting UDP broadcasts
by Abigail-II (Bishop) on Feb 02, 2004 at 16:41 UTC
|
Well, it turned out that RedHat (the distro the box was using)
doesn't trust itself to not run servers with security holes,
as was blocking all incoming requests on low numbered UDP
ports.
Abigail | [reply] |
|
Running into the same issues. How did you turn off redhats security to allow UDP connections on the low ports?
| [reply] |
Re: Intercepting UDP broadcasts
by traveler (Parson) on Jan 30, 2004 at 17:20 UTC
|
If you are not running this as root, try doing so. I have seen systems where the socket is created, but the data is not delivered to the app unless it is being run by (as) root. What kernel are you using? Also, are there any filters (iptables) blocking the data getting to the port?
--traveler | [reply] |
|
If you run the code as non-root, creating the socket fails.
Non-root processes can't bind to ports less than 1024.
Abigail
| [reply] |
|
Not to nit-pick, but non root users can bind to ports less than 1024 on Linux if they have the appropriate capability (CAP_NET_BIND_SERVICE) set. I think Solaris has a similar capability, but I don't have the docs here.
--traveler
| [reply] |
Re: Intercepting UDP broadcasts
by samtregar (Abbot) on Jan 30, 2004 at 19:23 UTC
|
Do have a firewall on the box you're testing on? That might explain why tcpdump can see the packets, but your code can't.
-sam
| [reply] |
|
| [reply] |
|
By default (unless you asked for "no security" or something similar during the install) RH7.3 sets up an ipchains firewall which will block incoming UDP packets for port <= 1023, among others. Is there any chance that's tripping you up?
| [reply] |
|
|
|
| [reply] |
Re: Intercepting UDP broadcasts
by JamesNC (Chaplain) on Jan 31, 2004 at 05:29 UTC
|
This worked for me on Win32, AS 5.8:
use strict;
use warnings;
use IO::Socket::INET;
$|++;
my $port = getservbyname 'bootps', 'udp';
print "Listening on UDP port: $port\n";
my $socket = IO::Socket::INET -> new (
LocalPort => $port,
Broadcast => 1,
Proto => 'udp',
Blocking => 1
)
or die "Failed to bind to socket: $@";
my $mess;
while ($socket -> recv ($mess, 1024)) {
print "Saw: \n$mess\n";
}
... To test it, I just made a dhcp request which also uses BOOTP
c:\> ipconfig /release
c:\> ipconfig /renew
I check to be certain I was on the same lan segment as the other device sending the BOOTP request?
JamesNC
Update: I released and renewed the address on a second machine on my home network and indeed saw both the request and response. I am curious as to how to decode the DHCP message. I started to unpack the message, but I got lazy: See RFC 2131 for the message format.
Here is a link to it: RFC 2131
| [reply] [d/l] [select] |
Re: Intercepting UDP broadcasts
by BrowserUk (Patriarch) on Jan 30, 2004 at 16:09 UTC
|
Update: UDP not TCP!
Don't you need to listen() and accept() before you can recv()? Or is that all taken care of under the covers of IO::Socket?
| [reply] |
|
No, this is a UDP socket. With UDP, you don't have end-to-end
connection (like with TCP) - just datagrams being delivered. So there are no
listen() or accept() steps involved. In fact, if you include
a Listen option in the creation of the socket, the creation
will fail.
Abigail
| [reply] |
Re: Intercepting UDP broadcasts
by welchavw (Pilgrim) on Jan 31, 2004 at 15:11 UTC
|
This is completely off the top of my head, but I think it has a shot at being helpful. Sometimes NICs have to be placed into "promiscuous" mode to pull packets that aren't addressed to the bound address. It may be that this is the step that is not being performed? Good luck.
,welchavw
| [reply] |
A reply falls below the community's threshold of quality. You may see it by logging in. |