Here's the current list:
locate pcap.hUse the directory location returned from locate as the value for the INC I- argument to the perl Makefile.PL command. That is, if the directory location returned is /usr/include/pcap, use the following command to build the makefile:
perl Makefile.PL INC=-I/usr/include/pcap LIBS='-L/usr/lib/pcap -lpcap'Then proceed with the usual make, make test and make install commands as described in the book. See the README file that comes with Net::Pcap for more details. [Be sure to issue both make test and make install as root.]
my $remote_name = gethostbyaddr( $the_ip, AF_INET );There are two fixes. The first is to change the line to read:
my $remote_name = inet_ntoa( $the_ip );which avoids the problem by only reporting dotted-decimal IP addresses. The second fix it to add an OR to the original statement which has the effect of reporting the IP name if one exists and reporting the IP address is one doesn't:
my $remote_name = gethostbyaddr( $the_ip, AF_INET ) || inet_ntoa( $the_ip );
Unfortunately, a problem has surfaced with Release 2.4 of the Linux kernel. I first noticed this when demonstrating the tcp_c1 and tcp_s1 programs (from Chapter 3, Sockets) to some of my students (on RedHat Linux 7.2). When the server (tcp_s1) is started and the client (tcp_c1) is then invoked, communication fails and the following error message is generated by the server (which promptly 'dies'):
Bad arg length for Socket::unpack_sockaddr_in, length is 4095, should be 16 at /usr/local/lib/perl5/5.6.1/i686-linux/Socket.pm line 312.To the best of my knowledge, the code which causes this error in tcp_s1 is the call to the recv subroutine, as follows:
while ( $from_who = accept( CLIENT_SOCK, TCP_SOCK ) ) { my $data; $from_who = recv( CLIENT_SOCK, $data, MAX_RECV_LEN, 0 ); if ( $from_who ) { my ( $the_port, $the_ip ) = sockaddr_in( $from_who );The code needs to be amended to remove the assignment to the $from_who scalar as a result of the call to recv, as follows:
while ( $from_who = accept( CLIENT_SOCK, TCP_SOCK ) ) { my $data; recv( CLIENT_SOCK, $data, MAX_RECV_LEN, 0 ); # <---- Line changed. if ( $from_who ) { my ( $the_port, $the_ip ) = sockaddr_in( $from_who );
Further discussion of this issue can be found on the use.perl.org website.
Chip Turner at RedHat has tracked down the problem for me. As was suspected, my code incorrectly assigned the result from recv to the $from_who variable. Here's the contents of the e-mail from Chip:
Hey Paul,
I've traced down the problem. recvfrom isn't required by the UNIX98 spec to populate the from fields for connection-oriented sockets (in this case, TCP). I've confirmed that this is standard behavior in the default Linux 2.4 kernel.
The man page for recvfrom (which is what Perl's recv ends up using, as can be seen from strace) states:
If from is not NULL, and the socket is not connection-oriented, the source address of the message is filled in. The argument fromlen is a value-result parameter, initialized to the size of the buffer associated with from, and modified on return to indicate the actual size of the address stored there.So ... it's a change from the 2.2 kernel to the 2.4 kernel, and is within UNIX98 specifications (and documented in the man page). From a Perl perspective, just don't use the return value of recv when not using a connection-oriented socket (TCP, UNIX domain socket, etc).
Chip.
And here's my reply (I believe this is called 'eating some crow' in North America):
Thanks for this. Great to have the issue resolved.
I need to be more careful. I'd written a client/server pair using UDP, then re-written it to use TCP (and, being lazy, copied/pasted from the UDP code into the TCP programs). That assignment as a result of the call to recv should never have stayed in the TCP code. I'll pay more attention to these details in future.
Thanks for taking the time to devote to this problem. I very much appreciate it.
It's a case of RTFM for me.
Source code for Chapter 3 updated on Saturday, March 9th, 2002.
In addition, the opening description on page 333 fails to mention that in addition to issuing the ls command, the user also issues the whoami command immediately before logging-out (see pages 343 through 345 of the network capture).
v-string in use/require non-portable at test.pl line 3. test.pl syntax OKAccording to the 5.8.0 perldiag documentation, such statements have been designated 'non-portable' (refer to the manpage for more details).
To remove the warning message, change:
use 5.6.0;to:
use 5.006_000;which does the same thing. (Remember: TMTOWTDI).
My thanks to the 2002/2003 class of undergraduate software engineers for bringing this to my attention.
if ( $from_who )line should read:
if ( !$from_who )as the call to recv behaves differently when called on a TCP socket (as opposed to a socket using UDP).
Return to the Programming the Network with Perl website.