Developers

PQL first() function


first() — Selects the first leaf in a tree, such as the first interface from /network/device.


Syntax

The first() function returns a string and takes one parameter:

string first(tree input)

Return value

The first() function returns a string.


Description

The first() function selects the first leaf in a tree, such as the first interface in a list of interfaces from /network/device. The first() function must include 1 parameter.

This function is useful in limited circumstances. For example, if you want to display the results in a field that has limited space, such as an application with a small UI, you can run the query and show only its first result.

Note: Although the first leaf of a given tree will probably not change much, there is no guarantee that it will always be the same leaf. Over time, the order of leaves can change as new data is added and existing data is reindexed.


Examples


Example 1: Find the first IP address

Query: What is the first leaf of the first interface of each device on the network?

SELECT first(interface) 
FROM /network/device

Results: Depending on the database, this query returns results similar to this:

row
   first(interface) vlan1
row
   first(interface) 5
row
   first(interface) 00:11:43:55:16:28
row
   first(interface) naf0
row
   first(interface) 00:11:11:45:6A:20
row
   first(interface) 00:13:20:4A:A3:78 
   . . .

Example 2: Find the first MAC address

Query: What is the first MAC address of each interface of each device on the network?

SELECT first(mac_address) 
FROM /network/device/interface

Results: Depending on the database, this query returns results similar to this:

row
   first(mac_address) 00:10:DB:4C:BA:68
row
   first(mac_address) 00:10:DB:49:98:00
row
   first(mac_address) 00:10:DB:6F:34:E0
row
   first(mac_address) 00:10:DB:3A:F7:70 
   . . .


Example 3: Find open ports on the first device

Query: What ports are open on the first network device?

SELECT coalesce(system/dns_name, 
  first(interface/inet/ip_address)) as "Device", 
  join(evidence/tcp_port/param/port, ',') as "TCP Ports", 
  join(evidence/udp_port/param/port, ',') as "UDP Ports" 
FROM /network/device ORDER BY 1

This query shows the open TCP and UDP ports for a device on the network. The query uses the first() function to select the first device from the list of network devices, and display all open TCP and UDP ports on that device.

Results: Depending on the database, this query returns results similar to this:

row 
   Device 10.10.10.102 
   TCP Ports 9100,631,515,514,80,23,21 
   UDP Ports 161 
row 
   Device 10.10.10.111 
   TCP Ports 111,81,80,22 
   UDP Ports null 
row 
   Device 10.10.10.13 
   TCP Ports 280,80,23 
   UDP Ports 161 
row 
   Device 10.10.10.14 
   TCP Ports 23 
   UDP Ports 161
   . . .


Example 4: Find open ports on all devices

Query: What ports are open on each machine on the network?

SELECT nvl(system/dns_name, 
    first(interface/inet/ip_address)) as "Device", 
  join(evidence/tcp_port/param/port, ',') 
    as "Open TCP Ports", 
  join(evidence/udp_port/param/port, ',') 
    as "Open UDP Ports" 
from /network/device 
order by 1

Since the nvl() and coalesce() functions are interchangeable, they work the same way in the same query:

SELECT coalesce(system/dns_name, 
    first(interface/inet/ip_address)) as "Device", 
  join(evidence/tcp_port/param/port, ',') 
    as "Open TCP Ports", 
  join(evidence/udp_port/param/port, ',') 
    as "Open UDP Ports" 
from /network/device 
order by 1

Both queries display the name of every device on the network, alongside the TCP and UDP ports that are open on that device.

In the first line, either the nvl() or coalesce() function identifies the device by the DNS name or IP address. The coalesce() function uses the first non-NULL value, which displays the IP address for devices that don't have DNS names. The first() function is applied to the IP address so that the query only uses the first IP address of the device. The next 2 lines gather the lists of TCP and UDP ports that are open. The join() function takes the port trees and turns them into comma-separated lists. The data comes from the /network/device level of the tree, and put in order by the first column.

Results: Depending on the database, this query returns results similar to this:

row
   Device 10.10.10.102
   Open TCP Ports 9100,631,515,514,80,23,21
   Open UDP Ports 161
row
   Device 10.10.10.111
   Open TCP Ports 111,81,80,22
   Open UDP Ports null
row
   Device 10.10.10.13
   Open TCP Ports 280,80,23
   Open UDP Ports null 
  . . .  

These results are easier to read when converted to a table:



Example 5: Find open ports on one device

Query: What ports are open on a specific device?

The query from Example 4 can be modified so you can look up the open ports on any single device. This is handy to post on a dashboard, and uses a search template so you can choose which device to display by selecting the IP address of that device.

SELECT coalesce(system/dns_name, 
    first(interface/inet/ip_address)) as "Device", 
  join(evidence/tcp_port/param/port, ',') 
    as "Open TCP Ports", 
  join(evidence/udp_port/param/port, ',') 
    as "Open UDP Ports" 
from /network/device 
where interface/inet/ip_address = 
'[[1param|All hosts|select first(interface/inet/ip_address),
  coalesce(system/dns_name || ' - ' || 
    first(interface/inet/ip_address),
  first(interface/inet/ip_address)) 
from /network/device 
where interface/inet/ip_address is not null
order by 2]]'
order by 1

To see other PQL functions, see Functions.


How do I find out more?