cmilfo has asked for the wisdom of the Perl Monks concerning the following question:

I'm using Net::ARP to do an ARP lookup (using arp_lookup() from the module). For some (unknown to me) reason, when I store IP addresses as keys in a hash before handing them to arp_lookup(), they will not work unless I first assign the key to another variable. I can then use the original hash key in arp_lookup(). It seems odd to me; I've not run into this situation before. I thought at first the module might have Taint checking on, but that does not appear to be the case.

I coded up a simple example demonstrating the (again, to me) oddity. I hope it's just something I'm doing incorrectly. :)

Thank you for any insight into what is happening here.
Casey

UPDATE: I removed the $ipaddr2 assignment I mentioned. Really, any access to the $ipaddr variable between the first arp_lookup() call and second arp_lookup() call will cause the second call to work. So, the print after the first arp_lookup() fills the access role. Thank you, japhy for helping me simplify the example.

Example:
#!/usr/bin/perl use warnings; use strict; use Net::ARP; my $device = q{eth0}; my %ipaddrs = ( q{192.168.1.100} => q{} ); for my $ipaddr (sort keys %ipaddrs) { my $mac = q{}; Net::ARP::arp_lookup($device, $ipaddr, $mac); print qq{$ipaddr : $mac\n}; Net::ARP::arp_lookup($device, $ipaddr, $mac); print qq{$ipaddr : $mac\n}; }

Example Output
192.168.1.100 : 192.168.1.100 : 01:41:02:8F:70:80

Replies are listed 'Best First'.
Re: Of Net::Arp and Hashes
by japhy (Canon) on Jan 13, 2006 at 19:14 UTC
    The error IS in the XS code. I added a printf() line to ARP.xs:
    char * arp_lookup(dev, ip, mac) unsigned char *dev; unsigned char *ip; unsigned char *mac; CODE: char tmp[20]; printf("TMP(%d) IS %s\n", strlen(tmp), tmp); if(SOCK_TYPE == SOCK_RAW) { arp_lookup_bsd(dev,ip,tmp); } else { arp_lookup_linux(dev,ip,tmp); } mac = tmp; OUTPUT: mac
    Then I ran this:
    #!/usr/bin/perl use Net::ARP; my $mac = ""; Net::ARP::arp_lookup(eth1 => '172.18.0.1', $mac); print "mac=$mac\n"; Net::ARP::arp_lookup(eth1 => '172.18.0.1', $mac); print "mac=$mac\n";
    I get this as output:
    TMP(0) IS mac= TMP(8) IS pï¿ï¿½ï¿½ mac=00:0E:D7:80:37:20
    The simple fix is change char tmp[20]; to char tmp[20] = "unknown";. I will be sending a bug report to the author.

    Jeff japhy Pinyan, P.L., P.M., P.O.D, X.S.: Perl, regex, and perl hacker
    How can we ever be the sold short or the cheated, we who for every service have long ago been overpaid? ~~ Meister Eckhart
        The author has already responded, fixed the bug (and an identical one in get_mac()), and uploaded a new version to CPAN.

        Jeff japhy Pinyan, P.L., P.M., P.O.D, X.S.: Perl, regex, and perl hacker
        How can we ever be the sold short or the cheated, we who for every service have long ago been overpaid? ~~ Meister Eckhart
Re: Of Net::Arp and Hashes
by idsfa (Vicar) on Jan 13, 2006 at 18:51 UTC

    Reading the C code, it appears to be doing an insanely overblown grep on /proc/net/arp. On bsd, the code reads the routing table from the system. Neither method actually performs an ARP.

    The most likely reason I can see for the behaviour you are seeing is this chunk of code:

    if(strlen(mac) > 0) strcpy(mac,"unkown"); else return -1;

    The subroutine is supposed to look up an unknown mac, but I read this as exiting without setting the value if your initial guess is of zero length. I'm not good enough at XS to decipher that, but it looks as if your original guess is discarded and an unintialized buffer is passed in instead, so it may not be fixable without altering the code.

    Given these two, I'd recommend ditching this module. You might want to look at arp-request.pl in the Net::Packet package.

    Updated: Or, just read japhy saying the same thing, but earlier. :-þ Way to blow my 200th node.


    The intelligent reader will judge for himself. Without examining the facts fully and fairly, there is no way of knowing whether vox populi is really vox dei, or merely vox asinorum. — Cyrus H. Gordon

      I'll give Net::Packet a try; a true ARP request would be ideal, anyway. Thank you.

Re: Of Net::Arp and Hashes
by japhy (Canon) on Jan 13, 2006 at 18:19 UTC
    I have no idea what is causing this, but if I had to guess, I'd say it's some artifact/bug of the XS code. But are you sure it doesn't just work when you try it a second time? (That is, comment out the $ipaddr2 line.)

    Jeff japhy Pinyan, P.L., P.M., P.O.D, X.S.: Perl, regex, and perl hacker
    How can we ever be the sold short or the cheated, we who for every service have long ago been overpaid? ~~ Meister Eckhart
      I confirmed (sort of, read on) that commenting out the $ipaddr2 line causes it to fail. After commenting out the $ipaddr2 assignment, the second arp_lookup() still worked. This was odd to me since I tested the snippet a bunch before I posted. I looked further up to the first print. Upon commenting out the first print, the second arp_lookup() failed to work. If I comment out the first print and the $ipaddr2 assignment, the second arp_lookup() no longer works. Odd.
        I think there's a bug in the XS code:
        char * arp_lookup(dev, ip, mac) unsigned char *dev; unsigned char *ip; unsigned char *mac; CODE: char tmp[20]; if(SOCK_TYPE == SOCK_RAW) { arp_lookup_bsd(dev,ip,tmp); } else { arp_lookup_linux(dev,ip,tmp); } mac = tmp; OUTPUT: mac
        That's the XS that handles arp_lookup(). Notice that it creates char tmp[20] without ever assigning anything to it (such as ""). I'm not a C guru, but that's a definite NO-NO. Because in the arp_lookup_linux() code, we have:
        int arp_lookup_linux(char *dev, char *ip, char *mac) { FILE *fp; char ipaddr[100]; char line[200]; char hwa[100]; char mask[100]; char device[100]; int num, type, flags; if(strlen(mac) > 0) strcpy(mac,"unkown"); else return -1;
        which leads me to believe -1 is being returned. I just think it's suspect.

        Jeff japhy Pinyan, P.L., P.M., P.O.D, X.S.: Perl, regex, and perl hacker
        How can we ever be the sold short or the cheated, we who for every service have long ago been overpaid? ~~ Meister Eckhart
Re: Of Net::Arp and Hashes
by glasswalk3r (Friar) on Jan 13, 2006 at 18:22 UTC

    I never used Net::ARP module but I don't believe the reason for this issue is related to Taint mode.

    My guess is that the values of IP address that you need to pass to the module must have a "proper format" (like using pack and unpack with the Socket module).

    Anyway... if your program just needs to loop over a couple of IP address why don't you just use an array? It should run faster and with less memory consumption.

    Alceu Rodrigues de Freitas Junior
    ---------------------------------
    "You have enemies? Good. That means you've stood up for something, sometime in your life." - Sir Winston Churchill

      The original program I'm using Net::ARP in has other values in the datastore from which I'm retrieving the ip addresses; I just removed as much as possible to isolate the issue. Thank you for the suggestion, though.