Skip to content

Commit f94bd32

Browse files
authored
Add 5 IP functions (#321)
1 parent 61b96bc commit f94bd32

File tree

7 files changed

+501
-1
lines changed

7 files changed

+501
-1
lines changed

apl/scalar-functions/ip-functions.mdx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,22 @@ The table summarizes the IP functions available in APL.
1111
| Function | Description |
1212
|-----------------------------------------------------------------------------------------|-------------|
1313
| [format_ipv4](/apl/scalar-functions/ip-functions/format-ipv4) | Parses input with a netmask and returns string representing IPv4 address. |
14+
| [format_ipv4_mask](/apl/scalar-functions/ip-functions/format-ipv4-mask) | Formats an IPv4 address and a bitmask into CIDR notation. |
1415
| [geo_info_from_ip_address](/apl/scalar-functions/ip-functions/geo-info-from-ip-address) | Extracts geographical, geolocation, and network information from IP addresses. |
1516
| [has_any_ipv4](/apl/scalar-functions/ip-functions/has-any-ipv4) | Returns a Boolean value indicating whether the specified column contains any of the given IPv4 addresses. |
1617
| [has_any_ipv4_prefix](/apl/scalar-functions/ip-functions/has-any-ipv4-prefix) | Returns a Boolean value indicating whether the IPv4 address matches any of the specified prefixes. |
1718
| [has_ipv4](/apl/scalar-functions/ip-functions/has-ipv4) | Returns a Boolean value indicating whether the given IPv4 address is valid and found in the source text. |
1819
| [has_ipv4_prefix](/apl/scalar-functions/ip-functions/has-ipv4-prefix) | Returns a Boolean value indicating whether the given IPv4 address starts with a specified prefix. |
1920
| [ipv4_compare](/apl/scalar-functions/ip-functions/ipv4-compare) | Compares two IPv4 addresses. |
20-
| [ipv4_is_in_range](/apl/scalar-functions/ip-functions/ipv4-is-in-range) | Checks if IPv4 string address is in IPv4-prefix notation range. |
2121
| [ipv4_is_in_any_range](/apl/scalar-functions/ip-functions/ipv4-is-in-any-range) | Returns a Boolean value indicating whether the given IPv4 address is in any specified range. |
22+
| [ipv4_is_in_range](/apl/scalar-functions/ip-functions/ipv4-is-in-range) | Checks if IPv4 string address is in IPv4-prefix notation range. |
2223
| [ipv4_is_match](/apl/scalar-functions/ip-functions/ipv4-is-match) | Returns a Boolean value indicating whether the given IPv4 matches the specified pattern. |
2324
| [ipv4_is_private](/apl/scalar-functions/ip-functions/ipv4-is-private) | Checks if IPv4 string address belongs to a set of private network IPs. |
2425
| [ipv4_netmask_suffix](/apl/scalar-functions/ip-functions/ipv4-netmask-suffix) | Returns the value of the IPv4 netmask suffix from IPv4 string address. |
26+
| [ipv6_compare](/apl/scalar-functions/ip-functions/ipv6-compare) | Compares two IPv6 addresses. |
27+
| [ipv6_is_in_any_range](/apl/scalar-functions/ip-functions/ipv6-is-in-any-range) | Returns a Boolean value indicating whether the given IPv6 address is in any specified range. |
28+
| [ipv6_is_in_range](/apl/scalar-functions/ip-functions/ipv6-is-in-range) | Checks if IPv6 string address is in IPv6-prefix notation range. |
29+
| [ipv6_is_match](/apl/scalar-functions/ip-functions/ipv6-is-match) | Returns a Boolean value indicating whether the given IPv6 matches the specified pattern. |
2530
| [parse_ipv4](/apl/scalar-functions/ip-functions/parse-ipv4) | Converts input to long (signed 64-bit) number representation. |
2631
| [parse_ipv4_mask](/apl/scalar-functions/ip-functions/parse-ipv4-mask) | Converts input string and IP-prefix mask to long (signed 64-bit) number representation. |
2732

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
---
2+
title: format_ipv4_mask
3+
description: 'This page explains how to use the format_ipv4_mask function in APL.'
4+
---
5+
6+
Use the `format_ipv4_mask` function to format an IPv4 address and a bitmask into Classless Inter-Domain Routing (CIDR) notation. This function is useful when you need to standardize or analyze network addresses, especially in datasets that contain raw IPs or numerical IP representations. It supports both string-based and numeric IPv4 inputs and can apply an optional prefix to generate a subnet mask.
7+
8+
You can use `format_ipv4_mask` to normalize IP addresses, extract network segments, or apply filtering or grouping logic based on subnet granularity.
9+
10+
## For users of other query languages
11+
12+
If you come from other query languages, this section explains how to adjust your existing queries to achieve the same results in APL.
13+
14+
<AccordionGroup>
15+
<Accordion title="Splunk SPL users">
16+
17+
SPL doesn’t have a direct built-in equivalent to `format_ipv4_mask`. To format IPv4 addresses with subnet masks, you typically use custom field extractions or external lookup tables. In contrast, APL provides a native function for this task, simplifying analysis at the network or subnet level.
18+
19+
<CodeGroup>
20+
```sql Splunk example
21+
| eval cidr=ip."/24"
22+
````
23+
24+
```kusto APL equivalent
25+
format_ipv4_mask('192.168.1.10', 24)
26+
```
27+
28+
</CodeGroup>
29+
30+
</Accordion>
31+
<Accordion title="ANSI SQL users">
32+
33+
Standard SQL lacks native functions for manipulating IP addresses or CIDR notation. This type of transformation usually requires application-side logic or user-defined functions (UDFs). APL simplifies this by offering a first-class function for formatting IPs directly in queries.
34+
35+
<CodeGroup>
36+
```sql SQL example
37+
-- Requires custom UDF or external processing
38+
SELECT format_ip_with_mask(ip, 24) FROM connections
39+
```
40+
41+
```kusto APL equivalent
42+
format_ipv4_mask(ip, 24)
43+
```
44+
45+
</CodeGroup>
46+
47+
</Accordion>
48+
</AccordionGroup>
49+
50+
## Usage
51+
52+
### Syntax
53+
54+
```kusto
55+
format_ipv4_mask(ip, prefix)
56+
```
57+
58+
### Parameters
59+
60+
| Name | Type | Required | Description |
61+
| ------ | ------ | -------- | ------------------------------------------------------------------------------------------------------- |
62+
| ip | string | ✔️ | The IPv4 address in CIDR notation. You can use a string (e.g., `'192.168.1.1'`) or a big-endian number. |
63+
| prefix | int | ✔️ | An integer between 0 and 32. Specifies how many leading bits to include in the mask. |
64+
65+
### Returns
66+
67+
A string representing the IPv4 address in CIDR notation if the conversion succeeds. If the conversion fails, the function returns an empty string.
68+
69+
## Example
70+
71+
**Query**
72+
73+
```kusto
74+
['sample-http-logs']
75+
| extend subnet = format_ipv4_mask('192.168.1.54', 24)
76+
| project _time, subnet
77+
```
78+
79+
[Run in Playground](https://play.axiom.co/axiom-play-qf1k/query?initForm=%7B%22apl%22%3A%22%5B'sample-http-logs'%5D%20%7C%20extend%20subnet%20%3D%20format_ipv4_mask('192.168.1.54'%2C%2024)%20%7C%20project%20_time%2C%20subnet%22%7D)
80+
81+
**Output**
82+
83+
| _time | subnet |
84+
| -------------- | ----- |
85+
| 1Jun 30, 11:11:46 | 192.168.1.0/24 |
86+
87+
## List of related functions
88+
89+
- [format_ipv4](/apl/scalar-functions/ip-functions/format-ipv4): Converts a 32-bit unsigned integer to an IPv4 address string. Use it when your input is a raw numeric IP instead of a prefix length.
90+
- [parse_ipv4](/apl/scalar-functions/ip-functions/parse-ipv4): Parses an IPv4 string into a numeric representation. Use it when you want to do arithmetic or masking on IP addresses.
91+
- [ipv4_is_in_range](/apl/scalar-functions/ip-functions/ipv4-is-in-range): Checks whether an IPv4 address falls within a given range. Use it when you need to filter or classify IPs against subnets.
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
---
2+
title: ipv6_compare
3+
description: 'This page explains how to use the ipv6_compare function in APL.'
4+
---
5+
6+
Use the `ipv6_compare` function to compare two IPv6 addresses and determine their relative order. This function helps you evaluate whether one address is less than, equal to, or greater than another. It returns `-1`, `0`, or `1` accordingly.
7+
8+
You can use `ipv6_compare` in scenarios where IPv6 addresses are relevant, such as sorting traffic logs, grouping metrics by address ranges, or identifying duplicate or misordered entries. It’s especially useful in network observability and security use cases where working with IPv6 is common.
9+
10+
## For users of other query languages
11+
12+
If you come from other query languages, this section explains how to adjust your existing queries to achieve the same results in APL.
13+
14+
<AccordionGroup>
15+
<Accordion title="Splunk SPL users">
16+
17+
Splunk SPL does not have a built-in function for directly comparing IPv6 addresses. Users often work around this limitation by converting the addresses into a comparable numeric format using external scripts or custom commands.
18+
19+
<CodeGroup>
20+
```sql Splunk example
21+
| eval ip1 = "2001:db8::1", ip2 = "2001:db8::2"
22+
| eval comparison = if(ip1 == ip2, 0, if(ip1 < ip2, -1, 1))
23+
````
24+
25+
```kusto APL equivalent
26+
print comparison = ipv6_compare('2001:db8::1', '2001:db8::2')
27+
```
28+
29+
</CodeGroup>
30+
31+
</Accordion>
32+
<Accordion title="ANSI SQL users">
33+
34+
ANSI SQL does not natively support IPv6 comparisons. Typically, users must store IPv6 addresses as strings or binary values and write custom logic to compare them.
35+
36+
<CodeGroup>
37+
```sql SQL example
38+
SELECT CASE
39+
WHEN ip1 = ip2 THEN 0
40+
WHEN ip1 < ip2 THEN -1
41+
ELSE 1
42+
END AS comparison
43+
FROM my_table
44+
```
45+
46+
```kusto APL equivalent
47+
print comparison = ipv6_compare('2001:db8::1', '2001:db8::2')
48+
```
49+
50+
</CodeGroup>
51+
52+
</Accordion>
53+
</AccordionGroup>
54+
55+
## Usage
56+
57+
### Syntax
58+
59+
```kusto
60+
ipv6_compare(ipv6_1, ipv6_2)
61+
```
62+
63+
### Parameters
64+
65+
| Name | Type | Description |
66+
| -------- | ------ | ----------------------------------- |
67+
| `ipv6_1` | string | The first IPv6 address to compare. |
68+
| `ipv6_2` | string | The second IPv6 address to compare. |
69+
70+
### Returns
71+
72+
An integer that represents the result of the comparison:
73+
74+
- `-1` if `ipv6_1` is less than `ipv6_2`
75+
- `0` if `ipv6_1` is equal to `ipv6_2`
76+
- `1` if `ipv6_1` is greater than `ipv6_2`
77+
78+
## Example
79+
80+
Use `ipv6_compare` to identify whether requests from certain IPv6 addresses fall into specific ranges or appear out of expected order.
81+
82+
**Query**
83+
84+
```kusto
85+
['sample-http-logs']
86+
| extend comparison = ipv6_compare('2001:db8::1', '2001:db8::abcd')
87+
| project _time, uri, method, status, comparison
88+
```
89+
90+
[Run in Playground](https://play.axiom.co/axiom-play-qf1k/query?initForm=%7B%22apl%22%3A%22%5B'sample-http-logs'%5D%20%7C%20extend%20comparison%20%3D%20ipv6_compare('2001%3Adb8%3A%3A1'%2C%20'2001%3Adb8%3A%3Aabcd')%20%7C%20project%20_time%2C%20uri%2C%20method%2C%20status%2C%20comparison%22%7D)
91+
92+
**Output**
93+
94+
| _time | uri | method | status | comparison |
95+
| -------------------- | ----------- | ------ | ------ | ---------- |
96+
| 2025-06-29T22:10:00Z | /products/1 | GET | 200 | -1 |
97+
98+
This example compares two static IPv6 addresses and attaches the result to each row for further filtering or grouping.
99+
100+
## List of related functions
101+
102+
- [ipv6_is_match](/apl/scalar-functions/ip-functions/ipv6-is-match): Checks if an IPv6 address matches a given subnet. Use it for range filtering instead of sorting or comparison.
103+
- [ipv4_is_private](/apl/scalar-functions/ip-functions/ipv4-is-private): Determines whether an IPv4 address is in a private range. Use this to filter non-public traffic.
104+
- [ipv4_compare](/apl/scalar-functions/ip-functions/ipv4-compare): Works the same way as `ipv6_compare` but for IPv4 addresses. Use it when your data contains IPv4 instead of IPv6.
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
---
2+
title: ipv6_is_in_any_range
3+
description: 'This page explains how to use the ipv6_is_in_any_range function in APL.'
4+
---
5+
6+
Use the `ipv6_is_in_any_range` function to determine whether a given IPv6 address belongs to any of a specified set of IPv6 CIDR ranges. This function is particularly useful in log enrichment, threat detection, and network analysis tasks that involve validating or filtering IP addresses against allowlists or blocklists.
7+
8+
You can use this function to:
9+
- Detect whether traffic originates from known internal or external networks.
10+
- Match IPv6 addresses against predefined address ranges for compliance or security auditing.
11+
- Filter datasets based on whether requesters fall into allowed or disallowed IP zones.
12+
13+
## For users of other query languages
14+
15+
If you come from other query languages, this section explains how to adjust your existing queries to achieve the same results in APL.
16+
17+
<AccordionGroup>
18+
<Accordion title="Splunk SPL users">
19+
20+
Splunk doesn’t offer a built-in function that directly checks if an IP falls within a list of CIDR ranges. Typically, SPL users must write custom logic using `cidrmatch()` repeatedly or rely on lookup tables.
21+
22+
<CodeGroup>
23+
```sql Splunk example
24+
| eval is_internal = if(cidrmatch("2001:db8::/32", ip), "true", "false")
25+
````
26+
27+
```kusto APL equivalent
28+
ipv6_is_in_any_range('2001:db8::1', dynamic(['2001:db8::/32']))
29+
```
30+
31+
</CodeGroup>
32+
33+
</Accordion>
34+
<Accordion title="ANSI SQL users">
35+
36+
ANSI SQL doesn’t natively support IPv6-aware CIDR range checks. Such functionality usually requires user-defined functions or external extensions.
37+
38+
<CodeGroup>
39+
```sql SQL example
40+
-- Typically handled via stored procedures or UDFs in extended SQL environments
41+
SELECT ip, is_in_range(ip, '2001:db8::/32') FROM traffic_logs
42+
```
43+
44+
```kusto APL equivalent
45+
ipv6_is_in_any_range('2001:db8::1', dynamic(['2001:db8::/32']))
46+
```
47+
48+
</CodeGroup>
49+
50+
</Accordion>
51+
</AccordionGroup>
52+
53+
## Usage
54+
55+
### Syntax
56+
57+
```kusto
58+
ipv6_is_in_any_range(ipv6_address, ipv6_ranges)
59+
```
60+
61+
### Parameters
62+
63+
| Name | Type | Description |
64+
| -------------- | --------------- | --------------------------------------------------------- |
65+
| `ipv6_address` | `string` | An IPv6 address in standard format (e.g., `2001:db8::1`). |
66+
| `ipv6_ranges` | `dynamic array` | A JSON array of IPv6 CIDR strings to compare against. |
67+
68+
### Returns
69+
70+
A `bool` value:
71+
72+
- `true` if the given IPv6 address is within any of the provided CIDR ranges.
73+
- `false` otherwise.
74+
75+
## Example
76+
77+
You want to detect HTTP requests from a specific internal IPv6 block.
78+
79+
**Query**
80+
81+
```kusto
82+
['sample-http-logs']
83+
| extend inRange = ipv6_is_in_any_range('2001:db8::1234', dynamic(['2001:db8::/32', 'fd00::/8']))
84+
| project _time, uri, method, status, inRange
85+
```
86+
87+
[Run in Playground](https://play.axiom.co/axiom-play-qf1k/query?initForm=%7B%22apl%22%3A%22%5B'sample-http-logs'%5D%20%7C%20extend%20inRange%20%3D%20ipv6_is_in_any_range('2001%3Adb8%3A%3A1234'%2C%20dynamic(%5B'2001%3Adb8%3A%3A%2F32'%2C%20'fd00%3A%3A%2F8'%5D))%20%7C%20project%20_time%2C%20id%2C%20uri%2C%20method%2C%20status%2C%20inRange%22%7D)
88+
89+
**Output**
90+
91+
| _time | uri | method | status | inRange
92+
| -------------------- | ------------ | ------ | ------ | --- |
93+
| 2025-06-30T01:00:00Z | /api/login | POST | 200 | true |
94+
| 2025-06-30T01:01:00Z | /healthcheck | GET | 204 | true |
95+
96+
97+
## List of related functions
98+
99+
- [ipv4_is_in_any_range](/apl/scalar-functions/ip-functions/ipv4-is-in-any-range): Use this function when working with IPv4 addresses instead of IPv6.
100+
- [ipv6_compare](/apl/scalar-functions/ip-functions/ipv6-compare): Compares two IPv6 addresses. Use this for sorting or deduplication rather than range matching.
101+
- [ipv6_is_match](/apl/scalar-functions/ip-functions/ipv6-is-match): Checks whether an IPv6 address matches a specific range. Use this if you need to test against a single CIDR block.

0 commit comments

Comments
 (0)