Losgcale, or as it rather be called Crowdstrike Falcon Logscale (say that 3 times fast and Bettlejuice may show up), is a Security Information and Event Management(SIEM) made by Crowdstrike. In other words, it is a glorified log collector that allows you to ask questions, create alerts based on those questions, and present the answers in pretty dashboards and graphs. It is not the only game in town -- there are quite a few open source and commercial ones -- but it is the one we will be talking about today.
Dashboards, dashboards everywhere
A dashboard is way to show what the logs know in a pretty graphical way: most people just want to see what they need to care about the logs; they should not be forced to learn how to do that manually.
For instance, what if you want to show all the times the logs reported a specific event happened? Which event? I don't know. Maybe a failed sshsession. Since we will be using fake data, how about if we want to know if the logs detected the presence of The Dude? Maybe that would look like this in the logs:
<47>Apr 24 08:06:46 192.168.12.9 banana/error[285]: dude-abides=false
Note: This is being fed by my Python-based fake log generator script. So, it says whatever I want.
Now, let's create a quick dashboard since this article is not about how to create one. All we want it to do is to find The Dude and let us know when and where the presence of His Dudeness was detected. Where here would be the host name; it would be nice if we have the full name (balcony.example.org in this example), or FQDN. Technically logscale has a filed called host that should provide us that. Problem is that it gives us whatever the log had: if that was a hostname, we are good. But, what the host does not have the full name, instead just the balcony or IP (192.168.12.9) address? Losgcale provide the query command reverseDNS(), which can return the FQDN:
| reverseDNS(host, as="host_name")
With that, we could create a dashboard whose query looks like this:
tail(100) | reverseDNS(host, as="host_name") | has_dude := if(text:contains(string=msg, substring="dude-abides"), then="Yes", else="No") | table([@timestamp, host_name, type, has_dude, msg])
Just before anyone asks, this is a very simple query because writing dashboards is not the topic of this article. All I want it to do is to get logs like this (one of them has a message body I saved from a real alert down to the IP address)
<63>Apr 24 08:06:41 192.16.94.101 tiktok/error[1197]: Did you see that? <47>Apr 24 08:06:46 192.168.12.9 banana/error[285]: dude-abides=false <66>Apr 24 08:06:47 192.168.55.85 tiktok/error[867]: right_droid=false <1>Apr 24 08:06:48 192.16.55.6 unamed[1155]: Did you see that? <8>Apr 24 08:06:50 192.168.12.137 rm/error[1733]: Cannot destroy all humans <20>Apr 24 08:06:51 192.16.55.6 tiktok/error[121]: %RCMD-4-RSHPORTATTEMPT: Attempted to connect to RSHELL from 217.69.139.202 <45>Apr 24 08:06:52 192.168.55.85 tiktok[426]: right_droid=false
which have IP addresses for hostnames (note the IP range; it will be important later). The "job" of the query is to identify those logs containing dude-abides. To make it look pretty, we are using the function reverseDNS() to convert the IPs to FQDNs.
The output should look like a table with 4 columns (you can stretch the window to try to make table look pretty):
| @timestamp | host_name | has_dude | msg |
|---|---|---|---|
| 2026-04-24 04:06:41.000 | balcony.example.org | No | Did you see that? |
| 2026-04-24 08:06:46.000 | balcony.example.org | Yes | dude-abides=false |
| 2026-04-24 04:06:47.000 | saladbar.example.org | No | right-droid=false |
| 2026-04-24 04:06:48.000 | kitchen.example.org | No | Did you see that? |
| 2026-04-24 04:06:50.000 | bathroom.example.org | No | Cannot destroy all humans |
| 2026-04-24 04:06:51.000 | kitchen.example.org | No | %RCMD-4-RSHPORTATTEMPT: Attempted to connect to RSHELL from 217.69.139.202 |
| 2026-04-24 04:06:52.000 | saladbar.example.org | No | right-droid=false |
Note: The reason we have 000 in the end of the time (ex: 08:06:46.000) is that logscale can handle/expects/would like that to be in microseconds. When it does not get them, it makes microseconds = 000.
It is broken!
When we run it the dashboard, something goes wrong: where is the host_name?
Here's a representation of the above in glorious ASCII):
| @timestamp | has_dude | msg |
|---|---|---|
| 2026-04-24 04:06:41.000 | No | Did you see that? |
| 2026-04-24 08:06:46.000 | Yes | dude-abides=false |
| 2026-04-24 04:06:47.000 | No | right-droid=false |
| 2026-04-24 04:06:48.000 | No | Did you see that? |
| 2026-04-24 04:06:50.000 | No | Cannot destroy all humans |
| 2026-04-24 04:06:51.000 | No | %RCMD-4-RSHPORTATTEMPT: Attempted to connect to RSHELL from 217.69.139.202 |
| 2026-04-24 04:06:52.000 | No | right-droid=false |
So, how to make it work? By default logscale uses the dns servers known by the host it is running on. In Linux they could be defined in resolv.conf (I am going to use dns1, dns2, and so on to define the dns servers instead of using IPs so it is easy to see them; this is getting long):
[banana@logscale-box ~]$ cat /etc/resolv.conf # Generated by NetworkManager search example.org nameserver dns1 nameserver dns2 [banana@logscale-box ~]$
dns1 and dns2, being our internal dns servers, do know all of our hosts in the 192.168.xx.xx (technically I should represent that as 192.168.0.0/16) range, which is a private IP range
Note: Private IP Addresses are those defined by RFC 1918 to belong to one of the following ranges: 192.168.x.x, 10.x.x.x, and 172.16.x.x
It turns out by default (again that word) logscale will not convert IPs in the private IP address ranges, you have to force it to do so. And that is done using 3 environmental variables (I call them constants. but what do I know?) defined in /etc/logscale/humio.conf: RDNS_DEFAULT_SERVER, IP_FILTER_RDNS_SERVER, and IP_FILTER_RDNS:
- RDNS_DEFAULT_SERVER
-
- Defines the server used when no server is explicitly specified in the function call
- Ex: RDNS_DEFAULT_SERVER=192.168.5.3
- IP_FILTER_RDNS
-
- For reverse DNS lookups in reserved IP addresses
- Which IP addresses can be queried with rdns() and reverseDns()
- Ex:
IP_FILTER_RDNS=deny 10.0.5.0/24; allow all
- Cannot query hosts in the 10.0.5.0/24 range
- Can query reserved IP addresses that are in other ranges.
- IP_FILTER_RDNS_SERVER
-
- For RDNS server filtering
- Only restricts which servers can be explicitly specified in rdns() or reverseDns() function calls
- If RDNS_DEFAULT_SERVER is defined, include it
- Ex:
IP_FILTER_RDNS_SERVER=allow 192.168.7.1; deny all
- Allows 192.168.7.1 (and 192.168.5.3) as rdns servers for reserved IP addresses
Since dns1 and dns2 can resolve the problem, all we would need to do is to add the following lines to /etc/logscale/humio.conf:
IP_FILTER_RDNS_SERVER=allow all IP_FILTER_RDNS=allow all
The following screen capture does show hostnames under host_name; I just deleted them because I used real names. I will manually alter the file(!) to put mine later.
Variations on the theme
- What if I just want to only allow the use of dns2 for reverse dns?
Edit IP_FILTER_RDNS_SERVER
IP_FILTER_RDNS_SERVER=allow dns2; deny all
then, optionally, edit the dashboard query| reverseDNS(host, as="host_name", server="dns2")
- What if I want to only use a dns3 for reverse dns, but not define it in resolv.conf?
Edit humio.conf
RDNS_DEFAULT_SERVER=dns3 IP_FILTER_RDNS=allow all IP_FILTER_RDNS_SERVER=allow dns3; deny all
then, optionally, edit the dashboard query| reverseDNS(host, as="host_name", server="dns3")
More Complex Examples
What if I want to add google's dns server to resolv.conf as failover in case my DNS servers are both down?
[banana@logscale-box ~]$ cat /etc/resolv.conf # Generated by NetworkManager search example.org nameserver dns1 nameserver dns2 nameserver 8.8.8.8 [banana@logscale-box ~]$
It depeneds on the other settings:
- If you do not add the IP_FILTER_RDNS*humio.conf? Logscale will be in default mode and never try to resolve private IP addresses. And that is what started the events that lead to this article.
- If you set humio.conf as in the original example,
IP_FILTER_RDNS=allow all IP_FILTER_RDNS_SERVER=allow all
and do not specify a dns server in the dashboard query as in the original case| reverseDNS(host, as="host_name")
Logscale may try to that for the private IPs, which will not work but now oyu are telling google, and possibly others who are listening, which private IPs you use. Don't do this! - If you set humio.conf as in the original example,
IP_FILTER_RDNS=allow all IP_FILTER_RDNS_SERVER=allow all
and specify a dns server in the dashboard query| reverseDNS(host, as="host_name", server="dns2")
Logscale will gracefully not show host_names when dns2 is down, and will not query google's. - If you set humio.conf specifically telling which dns servers to use. This is better than the previous solution
IP_FILTER_RDNS=allow all IP_FILTER_RDNS_SERVER=allow dns1; allow dns2; deny all
and do not specify a dns server in the dashboard query as in the original case| reverseDNS(host, as="host_name")
Logscale will only show host_names when either dns1 or dns2 is up, and will never try to query google's. This is the best because you are limiting which dns servers to use in one single location (humio.conf) instead of possibly filtering every single dahsboard. If you need to have dashboards quering specific dns servers, add them to the humio.conf file as above and then use the specific one where needed. This add a second layer of protection.








