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

I have generated an XML file with following command: nmap -PE -oX - $range > /home/users/axiroot/scripts/monitor-client/tmp/nmap.xml and parse it with following code:
my @IPsinrange = &getAllIPs($range) ; my $np = new Nmap::Parser; $np->parsefile('/home/users/axiroot/scripts/monitor-client/tmp/nmap.xm +l'); #using filenames my $si = $np->get_session(); #my @MACsinrange = &getAllMACs($range,) foreach my $ip (@IPsinrange) { $output .= "<tr>\n" ; $output .= "<th>$ip</th>\n" ; for my $host_obj ($np->all_hosts()){ if ( $host_obj->ipv4_addr() eq $ip ){ my $state = ""; $state = $host_obj->status() ; if ( $state eq "up" ) { $output .= "<td align='center'>$state</td>\n" ; + my $hostname = $host_obj->hostname() ; if ( $hostname eq 0 ) { $hostname = "Hostname niet gekend" ; } #print "hostname: $hostname \n" ; $output .= "<td align='center'>$hostname</td>\n" ; my $a = nslookup(host => $ip, type => "PTR"); if ( $a eq ""){ $output .= "<td align='center'>Niet in DNS</td>\n" ; + } else { $output .= "<td align='center'>$a</td>\n" ; + } my $openPort = (join ',',$host_obj->tcp_ports('open')) +."\n" ; my @ports = split ',', $openPort; $output .= "<td align='left'>"; foreach my $port (@ports) { my $svc = $host_obj->tcp_service($port); my $service = $svc->name() ; #$output .= "$port : $service </br>" ; $output .= "$port : $service </br>" ; } $output .= "</td>\n" ; my $mac = $host_obj->mac_addr() ; $output .= "<td align='center'>$mac</td>\n" ; + my $type = $host_obj->mac_vendor() ; $output .= "<td align='center'>$type</td>\n" ; + } } } $output .= "<tr>\n" ; }
When I delete the section of tcp ports, the script runs without any speed problems. However, as soon as I want to parse the tcp ports output, the script takes very long. For instance a range of 4 addresses takes up to 20 minutes for the script to complete. That's doable but with a /24, this is simply too long. Now I have read that this kind of nmap port scanning takes a long time but is there something wrong with my code that makes it very slow? Perl newbie here so I think that could be the case :)

Replies are listed 'Best First'.
Re: NMAP Parser very slow
by BrowserUk (Patriarch) on Nov 02, 2016 at 13:29 UTC
    For instance a range of 4 addresses takes up to 20 minutes for the script to complete. That's doable but with a /24, this is simply too long. Now I have read that this kind of nmap port scanning takes a long time but is there something wrong with my code that makes it very slow?

    No. Nothing particular.

    You are calling ->tcp_ports('open') for each of the hosts you are investigating. In order to be able to tell you which ports are open, NMap will have to scan all of the ports for each host.

    You say that it is takig 20 for 4 hosts; so 300 seconds per host. Assuming that NMap is limiting itself to the bottom 1024 privileged ports on each host, that means 300 / 1024 = 0.293 seconds per port. Active ports may well respond more quickly than that, but for inactive ports NMap will have to wait a certain amount of time before it times the port out and concludes it is not active. That calculation assumes that NMap scans the ports serially.

    It is also possible that NMap scans the ports in parallel; and that the commonly used default timeout of 300 seconds means that every host will always take a minimum of 5 minutes to scan, unless it all 1024 ports are open.

    Does NMAP::Parser, or one of its dependents allow you to configure the timeout?


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority". I knew I was on the right track :)
    In the absence of evidence, opinion is indistinguishable from prejudice.
      Active ports may well respond more quickly than that, but for inactive ports NMap will have to wait a certain amount of time before it times the port out and concludes it is not active.
      Closed ports are also reported immediately, unless they're blocked by a firewall. Stop portscanning people's firewalls! What's wrong with you?
      I was thinking about something in that direction but I haven't found anything yet about the ports. I think that I need to limit the number of ports in my nmap commando but it would be nice to configure a timeout. I'll look further in this, thanks!
Re: NMAP Parser very slow (updated)
by haukex (Archbishop) on Nov 02, 2016 at 13:36 UTC

    Hi Noosrep,

    I'd say the first step would be to narrow down more closely where the slowdown is happening. Insert some print statements to figure it out, and then narrow down the code to the minimum needed to reproduce the problem. See also Short, Self Contained, Correct Example.

    I had a quick look at Nmap::Parser, and as far as I can tell it's just fetching information out of its internal data structures, which I'm guessing are just the result of parsing the XML file, and I haven't yet seen anything that would explain the slowdown. Looking at your code, the only thing that jumps out at me is the call to nslookup, since I'm guessing that's a network operation, which can cause delays.

    Update: Looked at the Nmap::Parser source again, and it indeed looks like it's just looking stuff up in its data structures and not performing network operations. So aside from my nslookup theory above, it really would be best if you could identify the slow part of your code. Also, look at your loop logic:

    foreach my $ip (@IPsinrange) { for my $host_obj ($np->all_hosts()) { if ($host_obj->ipv4_addr() eq $ip) { foreach my $port (@ports) {

    So if your scan contains a lot of hosts, that could be a lot of looping. I'm guessing not enough to cause your script to run for 20 minutes, but I'd still suggest this logic as being a little more optimal:

    my %IPsinrange = map {$_=>1} @IPsinrange; for my $host_obj ($np->all_hosts()) { next unless $IPsinrange{$host_obj->ipv4_addr()}; for my $port (@ports) {

    Hope this helps,
    -- Hauke D

      Aha, tried this with a /28 (with 2 addresses that are up) and it takes about 4 minutes.

      Will do some further investigating but you're suggestion seems to have done some good. The weird thing is that my last port isn't found as a service:

      32770 : sometimes-rpc3 32775 : sometimes-rpc13 32776 :
      Thanks for the input!
Re: NMAP Parser very slow
by glasswalk3r (Friar) on Nov 02, 2016 at 13:27 UTC

    Hello there,

    I don't know Nmap::Parser, but first you want to find out what is taking so long (parsing the XML, going over the network, etc). For that, you could always read the official documentation about it, but this link seems to be a nice introductory article for that.

    Also, make sure to take a look at Markup in the Monastery, it will help you making your posts easier to read (and hopefully getting more help for it!).

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