dwt.bar
dwt.bar

Reputation: 49

awk if not matched print "unknown", multiple matches

I am getting an nmap result and I am trying to process various (host up or down) results using awk.

I am passing an ip address and I am trying to get the following: status (up or down), host name, OS.
GOAL: I need to have an access to every field to be able to update the database with its value. Also I am trying to accomplish that in as simple as possible way, maybe there is any way to save field in a variable so then I can use it, check if it's empty etc.?

More into details:

  1. if Host is down host_name="unknown", and OS="unknown"
  2. if Host up grab the host_name and check OS -> two possibilities here, either /Running:/ or /OS guesses/ both of them will give us the OS, but we will have either one or another.

Expected output of host that is up:

                     $ip              $status     $host_name    $os
when host up:        134.99.120.2     host_up     HostName      Linux
when host down:      134.99.120.2     host_down   unknown       unknown

I came up with this one liner here:
sudo nmap -O -R -p 22 -oN -T4 134.99.120.2 | awk '/down/{print$5}/Nmap scan report/{print$5}/Running:/{print$2}/OS guess/{print$4}'
But that does not provide any control over the output.

Raw Outputs from nmap:
When Host up:

 
> Starting Nmap 6.40 ( http://nmap.org ) at 2020-11-29 14:58 EST
> Nmap scan report for HostName (134.99.120.2) Host is up (0.00067s
> latency). PORT   STATE SERVICE 22/tcp open  ssh Warning: OSScan
> results may be unreliable because we could not find at least 1 open
> and 1 closed port Device type: general purpose Running: Linux OS CPE:
> xx:/o:xxx:xxxxxos:9.10 OS details: Linux Network Distance: 7 hops OS
> detection performed. Please report any incorrect results at
> http://nmap.org/submit/ . Nmap done: 1 IP address (1 host up) scanned
> in 2.58 seconds 

When host down:

> Starting Nmap 6.40 ( http://nmap.org ) at 2020-11-29 15:00 EST
> Note: Host seems down. If it is really up, but blocking our ping
> probes, try -Pn Nmap done: 1 IP address (0 hosts up) scanned in 3.64
> seconds 

Upvotes: 1

Views: 223

Answers (3)

markp-fuso
markp-fuso

Reputation: 33799

Decided to take a swipe at a (simple) token analyzer that eliminates the need for hard coded field references in awk, but still assumes the textual output from nmap is as displayed in the OPs sample outputs.

Sample inputs (in lieu of running nmap on my host):

$ cat nmap.up.dat
> Starting Nmap 6.40 ( http://nmap.org ) at 2020-11-29 14:58 EST
> Nmap scan report for HostName (134.99.120.2) Host is up (0.00067s
> latency). PORT   STATE SERVICE 22/tcp open  ssh Warning: OSScan
> results may be unreliable because we could not find at least 1 open
> and 1 closed port Device type: general purpose Running: Linux OS CPE:
> xx:/o:xxx:xxxxxos:9.10 OS details: Linux Network Distance: 7 hops OS
> detection performed. Please report any incorrect results at
> http://nmap.org/submit/ . Nmap done: 1 IP address (1 host up) scanned
> in 2.58 seconds

$ cat nmap.down.dat
> Starting Nmap 6.40 ( http://nmap.org ) at 2020-11-29 15:00 EST
> Note: Host seems down. If it is really up, but blocking our ping
> probes, try -Pn Nmap done: 1 IP address (0 hosts up) scanned in 3.64
> seconds

One awk idea for a token analyzer:

ipaddr='134.99.120.2'

awk -v ip="${ipaddr}" '                             # pass ip addr in as awk variable "ip"
FNR==1  { hstat="host_up"                           # reset defaults for status ...
          hname=hos="unknown"                       # hostname and host OS
          prev=""                                   # clear our "prev"ious token
        }

        { for ( i=1 ; i<=NF ; i++ )                 # process each field
              { token=$(i)                          # make note of current token aka field
                if ( token == ">" ) continue        # ignore the ">" in the first column

                # if our "prev"ious token matches any of the case statements then
                # update our variables according to the current token

                switch (prev) {
                    case "scan"           : if ( token == "report") { prev=prev" "token } ; break
                    case "scan report"    : if ( token == "for"   ) { prev=prev" "token } ; break
                    case "scan report for": hname=token             ; prev=token          ; break

                    case "down."          : hstat="host_down"       ; prev=token          ; break
                    case "Running:"       : hos=token               ; prev=token          ; break
                    default               : prev=token                                    ; break
                }
              }
        }
ENDFILE { fmt="%-18s%-12s%-15s%s\n"                 # re-usable format
          if ( NR==FNR )                            # for first file print a header:
             { printf fmt, "$ip", "$status", "$host_name", "$os" }

          printf fmt, ip, hstat, hname, hos         # otherwise print results
        }

' nmap.up.dat nmap.down.dat

NOTE: ENDFILE requires GNU awk

This above generates:

$ip               $status     $host_name     $os
134.99.120.2      host_up     HostName       Linux
134.99.120.2      host_down   unknown        unknown

Upvotes: 1

markp-fuso
markp-fuso

Reputation: 33799

NOTE Looks like Raman was a bit faster on the 'Post Your Answer' button ...

Assumptions:

  • nmap output will always be like one of the two examples provided by OP
  • nmap output will always have the Hostname and OS name in the same fields (ie, don't have to worry about nmap wrapping lines at different words due to variable lengths of data)
  • while the OP shows OS guess in their sample awk, the sample nmap data shows OS details (answer - below - is based on OS details; OP can modify per what their nmap call actually returns)
  • nmap data does in fact include a > in the first column of every line of output (as displayed in OPs sample inputs); this means OPs awk field references may need to shift +/- accordingly (OP can adjust answer - below - based on whether or not a line starts with >)

Sample inputs (in lieu of running nmap on my host):

$ cat nmap.up.dat
> Starting Nmap 6.40 ( http://nmap.org ) at 2020-11-29 14:58 EST
> Nmap scan report for HostName (134.99.120.2) Host is up (0.00067s
> latency). PORT   STATE SERVICE 22/tcp open  ssh Warning: OSScan
> results may be unreliable because we could not find at least 1 open
> and 1 closed port Device type: general purpose Running: Linux OS CPE:
> xx:/o:xxx:xxxxxos:9.10 OS details: Linux Network Distance: 7 hops OS
> detection performed. Please report any incorrect results at
> http://nmap.org/submit/ . Nmap done: 1 IP address (1 host up) scanned
> in 2.58 seconds

$ cat nmap.down.dat
> Starting Nmap 6.40 ( http://nmap.org ) at 2020-11-29 15:00 EST
> Note: Host seems down. If it is really up, but blocking our ping
> probes, try -Pn Nmap done: 1 IP address (0 hosts up) scanned in 3.64
> seconds

One awk solution, though I'm assuming OP won't actually have 2 sets of nmap output for a single ip address (???) ...

ipaddr='134.99.120.2'

awk -v ip="${ipaddr}" '                                # pass ip addr in as awk variable "ip"
FNR==1            { hstat="host_up"                    # reset defaults for status ...
                    hname=hos="unknown"                # hostname and host OS
                  }
/down/            { hstat="host_down" ; next }         # reset status
/scan report for/ { hname=$6          ; next }         # reset hostname
/OS details/      { hos=$5            ; next }         # reset host OS

ENDFILE           { fmt="%-18s%-12s%-15s%s\n"          # re-usable format
                    if ( NR==FNR )                     # for first file print a header:
                       { printf fmt, "$ip", "$status", "$host_name", "$os" }

                    printf fmt, ip, hstat, hname, hos  # otherwise print results
                  }
' nmap.up.dat nmap.down.dat

NOTE: ENDFILE requires GNU awk (per Ed Morton's comment)

The above generates:

$ip               $status     $host_name     $os
134.99.120.2      host_up     HostName       Linux
134.99.120.2      host_down   unknown        unknown

Upvotes: 1

Raman Sailopal
Raman Sailopal

Reputation: 12867

You can actually format the data as required by setting the extracted data as variables within awk and then printing them in an END block and so:

 sudo nmap -O -R -p 22 -oN -T4  134.99.120.2  | awk -v ip="134.99.120.2" '

 /Host is up/ { 
                 status="host_up" 
              } 
 /Host seems down/ { 
                 status="host_down" 
              } 
 /Nmap scan report/ { 
                 hstname=$5 
              } 
 /Running:/ { 
                 os=$2 
            } 
 /OS guess/ { 
                 os=$4 
            } 
        END { 
                 !os?os="unknown":os=os;
                 !hstname?hstname="unknown":hstname=hstname;
                 printf "%s\t%s\t%s\t%s\n",ip,status,hstname,os 
             }'

One liner:

sudo nmap -O -R -p 22 -oN -T4  134.99.120.2 | awk -v ip="134.99.120.2" '/Host is up/ { status="host_up" } /Host seems down/ { status="host_down" } /Nmap scan report/ { hstname=$5 } /Running:/ { os=$2 } /OS guess/ { os=$4 } END { !os?os="unknown":os=os;!hstname?hstname="unknown":hstname=hstname;printf "%s\t%s\t%s\t%s\n",ip,status,hstname,os }'

Pass the variable ip into awk with -F and then set the os, hstname and status based on the searched text. In the end block, check to see if hstname and os variables exist. If they don't exist, set the variables to unknown, otherwise set them to what they already are. Finally print the variables in the format required.

Upvotes: 3

Related Questions