Splunk Search

How can I calculate CIDR Range?

atebysandwich
Path Finder

I have two fields: Network_Address and Netmask. The Network_Address field has the network address of the network as field values and the Netmask field has the network mask as it's value. Here is an example:

Network_Address Netmask

10.1.1.0                       255.255.255.0

How can I write a search so Splunk tells me the CIDR subnet rage for the two fields? I need the output to be put in a new field named CIDR. 

Labels (4)
0 Karma
1 Solution

atebysandwich
Path Finder

This is what worked between @yuanliu and @ITWhisperer suggestions:

| eval bitmask = split(Netmask, ".")
| eval bitmask = 32 - sum(mvmap(bitmask, log(256 - bitmask,2)))
| eval CIDR = Network_Address . "/" . bitmask 

 

View solution in original post

0 Karma

tfujita_splunk
Splunk Employee
Splunk Employee

FYI,

I added the following external command lookup to the App below.

Usage:

| makeresults
| eval Network_Address="10.1.1.0", Netmask="255.255.255.0"

| eval ip=Network_Address."/".Netmask
| lookup local=t ipcalclookup Address as ip OUTPUT Network Prefix
| eval CIDR=Network."/".Prefix

Numeral system macros for Splunk
https://splunkbase.splunk.com/app/6595 

0 Karma

atebysandwich
Path Finder

This is what worked between @yuanliu and @ITWhisperer suggestions:

| eval bitmask = split(Netmask, ".")
| eval bitmask = 32 - sum(mvmap(bitmask, log(256 - bitmask,2)))
| eval CIDR = Network_Address . "/" . bitmask 

 

0 Karma

tscroggins
SplunkTrust
SplunkTrust

@atebysandwich 

It's a tidy solution. Just keep in mind that it assumes Netmask is a valid network mask and Network_Address is a valid network address relative to Netmask. If either assumption is false, the resulting CIDR value is invalid.

0 Karma

tscroggins
SplunkTrust
SplunkTrust

To simplify netmask validation, I would introduce a lookup, e.g. netmask_lookup:

netmask,sigbits
0.0.0.0,0
128.0.0.0,1
192.0.0.0,2
224.0.0.0,3
240.0.0.0,4
248.0.0.0,5
252.0.0.0,6
254.0.0.0,7
255.0.0.0,8
255.128.0.0,9
255.192.0.0,10
255.224.0.0,11
255.240.0.0,12
255.248.0.0,13
255.252.0.0,14
255.254.0.0,15
255.255.0.0,16
255.255.128.0,17
255.255.192.0,18
255.255.224.0,19
255.255.240.0,20
255.255.248.0,21
255.255.252.0,22
255.255.254.0,23
255.255.255.0,24
255.255.255.128,25
255.255.255.192,26
255.255.255.224,27
255.255.255.240,28
255.255.255.248,29
255.255.255.252,30
255.255.255.254,31
255.255.255.255,32
| lookup netmask_lookup netmask as Netmask output sigbits

If sigbits (significant bits) is null, the netmask is invalid, and the network cannot be expressed in CIDR notation.

To mask the address using a valid netmask, let's introduce a macro to perform a bitwise AND between two 8-bit values [1]:

 

[bitand_8(2)]
args = x, y
definition = sum(1 * (floor($x$ / 1) % 2) * (floor($y$ / 1) % 2), 2 * (floor($x$ / 2) % 2) * (floor($y$ / 2) % 2), 4 * (floor($x$ / 4) % 2) * (floor($y$ / 4) % 2), 8 * (floor($x$ / 8 ) % 2) * (floor($y$ / 8 ) % 2), 16 * (floor($x$ / 16) % 2) * (floor($y$ / 16) % 2), 32 * (floor($x$ / 32) % 2) * (floor($y$ / 32) % 2), 64 * (floor($x$ / 64) % 2) * (floor($y$ / 64) % 2), 128 * (floor($x$ / 128) % 2) * (floor($y$ / 128) % 2))
iseval = 0

 

Combining all of the above:

| makeresults
| eval Network_Address="10.1.1.0", Netmask="255.255.255.0"
| lookup netmask_lookup netmask as Netmask output sigbits
| eval addr_octets=split(Network_Address, "."), netmask_octets=split(Netmask, ".")
| eval x=tonumber(mvindex(addr_octets, 0, 0)), y=tonumber(mvindex(netmask_octets, 0, 0)), addr0=`bitand_8(x, y)`
| eval x=tonumber(mvindex(addr_octets, 1, 1)), y=tonumber(mvindex(netmask_octets, 1, 1)), addr1=`bitand_8(x, y)`
| eval x=tonumber(mvindex(addr_octets, 2, 2)), y=tonumber(mvindex(netmask_octets, 2, 2)), addr2=`bitand_8(x, y)`
| eval x=tonumber(mvindex(addr_octets, 3, 3)), y=tonumber(mvindex(netmask_octets, 3, 3)), addr3=`bitand_8(x, y)`
| eval CIDR=addr0.".".addr1.".".addr2.".".addr3."/".sigbits

=> 10.1.1.0/24

We can validate with several cases:

| eval Network_Address="10.1.1.0", Netmask="255.255.254.0"

=> 10.1.0.0/23

| eval Network_Address="10.1.1.32", Netmask="0.0.0.0"

=> 0.0.0.0/0 (the default route)

| eval Network_Address="10.1.1.32", Netmask="255.255.255.255"

=> 10.1.1.32/32 (the host route)

| eval Network_Address="10.1.1.32", Netmask="255.0.255.0"

=> null (invalid netmask)

A simpler solution overall--and one compatible with both IPv4 and IPv6--would offload the work to either a custom command or an external lookup, but the above steps should work for any unprivileged Splunk user.

EDIT: I'm apparently stuck in a pre-9.0 world. You can replace the eval and bitand logic with a single ipmask() eval function [2]. That said, it isn't difficult to perform bitwise operations in core Splunk up to a certain size. For IPv6, you're still better off implementing a custom command or external lookup.

1. https://en.wikipedia.org/wiki/Bitwise_operation#Mathematical_equivalents
2. https://docs.splunk.com/Documentation/Splunk/9.0.4/SearchReference/ConversionFunctions#ipmask.28.26l...

0 Karma

yuanliu
SplunkTrust
SplunkTrust

Not so much a search, but mere calculation using the definition.

 

| eval bitmask = split(Netmask, ".")
| eval bitmask = sum(mvmap(bitmask, log(bitmask + 1, 2)))
| eval CIDR = Network_Address . "/" . bitmask

 

Your sample data will return

CIDRNetmaskNetwork_Addressbitmask
10.1.1.0/24255.255.255.010.1.1.024
Tags (2)

atebysandwich
Path Finder

This seemed work for the most part. The only I issue I see is some of the values in the new CIDR field have .99435343685886 at the end.

Example:

Network address            Netmask                          CIDR
10.21.72.1                       255.255.254.0                  10.21.72.0/23.99435343685886

Is there a way to trim the "." and the numbers to the right off it off?

0 Karma

ITWhisperer
SplunkTrust
SplunkTrust

@yuanliu  is close but it fails for mask which aren't 255 - try flipping it to subtract the number of missing bits from 32

| eval bitmask = 32 - sum(mvmap(bitmask, log(256 - bitmask,2)))

atebysandwich
Path Finder

Haha I didn't see this before I replied back to @yuanliu  post. Your idea did the trick. Thank you both for the help!

0 Karma
Got questions? Get answers!

Join the Splunk Community Slack to learn, troubleshoot, and make connections with fellow Splunk practitioners in real time!

Meet up IRL or virtually!

Join Splunk User Groups to connect and learn in-person by region or remotely by topic or industry.

Get Updates on the Splunk Community!

Persistent Queue at TcpOut — One of Splunk's Most Practical Features

Splunk introduced persistent queueing at the tcpout layer as one of the most practical resilience features in ...

Skip the Awkward Silence: Have a .conf-ersation at .conf26

Picture this. You arrive at .conf26 already having your socializing and networking plans mapped out. No ...

Rethinking Zero Trust: From Product Purchases to Logical Control Evidence

Implementing Zero Trust (ZT) across complex environments often falters at the very beginning due to a ...