# Networking Built-ins

| Function | Description | Meta |
| --- | --- | --- |
| `net.cidr_contains` | `result := net.cidr_contains(cidr, cidr_or_ip)`  Checks if a CIDR or IP is contained within another CIDR. `output` is `true` if `cidr_or_ip` (e.g. `127.0.0.64/26` or `127.0.0.1`) is contained within `cidr` (e.g. `127.0.0.1/24`) and `false` otherwise. Supports both IPv4 and IPv6 notations.  **Arguments:**  `cidr` (string)  CIDR to check against  `cidr_or_ip` (string)  CIDR or IP to check  **Returns:**  `result` (boolean)  `true` if `cidr_or_ip` is contained within `cidr` | Wasm |
| `net.cidr_contains_matches` | `output := net.cidr_contains_matches(cidrs, cidrs_or_ips)`  Checks if collections of cidrs or ips are contained within another collection of cidrs and returns matches. This function is similar to `net.cidr_contains` except it allows callers to pass collections of CIDRs or IPs as arguments and returns the matches (as opposed to a boolean result indicating a match between two CIDRs/IPs).  **Arguments:**  `cidrs` (any<string, array\[any<string, array\[any\]>\], object\[string: any<string, array\[any\]>\], set\[any<string, array\[any\]>\]>)  CIDRs to check against  `cidrs_or_ips` (any<string, array\[any<string, array\[any\]>\], object\[string: any<string, array\[any\]>\], set\[any<string, array\[any\]>\]>)  CIDRs or IPs to check  **Returns:**  `output` (set\[array<any, any>\])  tuples identifying matches where `cidrs_or_ips` are contained within `cidrs` | [v0.19.0-rc1](https://github.com/open-policy-agent/opa/releases/v0.19.0-rc1) SDK-dependent |
| `net.cidr_expand` | `hosts := net.cidr_expand(cidr)`  Expands CIDR to set of hosts (e.g., `net.cidr_expand("192.168.0.0/30")` generates 4 hosts: `{"192.168.0.0", "192.168.0.1", "192.168.0.2", "192.168.0.3"}`).  **Arguments:**  `cidr` (string)  CIDR to expand  **Returns:**  `hosts` (set\[string\])  set of IP addresses the CIDR `cidr` expands to | SDK-dependent |
| `net.cidr_intersects` | `result := net.cidr_intersects(cidr1, cidr2)`  Checks if a CIDR intersects with another CIDR (e.g. `192.168.0.0/16` overlaps with `192.168.1.0/24`). Supports both IPv4 and IPv6 notations.  **Arguments:**  `cidr1` (string)  first CIDR  `cidr2` (string)  second CIDR  **Returns:**  `result` (boolean)  `true` if `cidr1` intersects with `cidr2` | Wasm |
| `net.cidr_is_valid` | `result := net.cidr_is_valid(cidr)`  Parses an IPv4/IPv6 CIDR and returns a boolean indicating if the provided CIDR is valid.  **Arguments:**  `cidr` (string)  CIDR to validate  **Returns:**  `result` (boolean)  `true` if `cidr` is a valid CIDR | [v0.46.0](https://github.com/open-policy-agent/opa/releases/v0.46.0) SDK-dependent |
| `net.cidr_merge` | `output := net.cidr_merge(addrs)`  Merges IP addresses and subnets into the smallest possible list of CIDRs (e.g., `net.cidr_merge(["192.0.128.0/24", "192.0.129.0/24"])` generates `{"192.0.128.0/23"}`.This function merges adjacent subnets where possible, those contained within others and also removes any duplicates. Supports both IPv4 and IPv6 notations. IPv6 inputs need a prefix length (e.g. "/128").  **Arguments:**  `addrs` (any<array\[any<string>\], set\[string\]>)  CIDRs or IP addresses  **Returns:**  `output` (set\[string\])  smallest possible set of CIDRs obtained after merging the provided list of IP addresses and subnets in `addrs` | [v0.24.0](https://github.com/open-policy-agent/opa/releases/v0.24.0) SDK-dependent |
| `net.lookup_ip_addr` | `addrs := net.lookup_ip_addr(name)`  Returns the set of IP addresses (both v4 and v6) that the passed-in `name` resolves to using the standard name resolution mechanisms available.  **Arguments:**  `name` (string)  domain name to resolve  **Returns:**  `addrs` (set\[string\])  IP addresses (v4 and v6) that `name` resolves to | [v0.35.0](https://github.com/open-policy-agent/opa/releases/v0.35.0) SDK-dependent |

Notes on Name Resolution (`net.lookup_ip_addr`)

The lookup mechanism uses either the pure-Go, or the cgo-based resolver, depending on the operating system and availability of cgo. The latter depends on flags that can be provided when building OPA as a Go library, and can be adjusted at runtime via the GODEBUG environment variable. See [these docs on the `net` package](https://pkg.go.dev/net@go1.17.3#hdr-Name_Resolution) for details.

Note that the cgo-based resolver is often **preferable**: It will take advantage of host-based DNS caching in place. This built-in function only caches DNS lookups within _a single_ policy evaluation.

Examples of `net.cidr_contains_matches`

The `output := net.cidr_contains_matches(a, b)` function allows callers to supply strings, arrays, sets, or objects for either `a` or `b`. The `output` value in all cases is a set of tuples (2-element arrays) that identify matches, i.e., elements of `b` contained by elements of `a`. The first tuple element refers to the match in `a` and the second tuple element refers to the match in `b`.

| Input Type | Output Type |
| --- | --- |
| `string` | `string` |
| `array` | `array` index |
| `set` | `set` element |
| `object` | `object` key |

CIDR Match with String Ranges

If both operands are string values the function is similar to `net.cidr_contains`.

data.json

```
{}
```

input.json

```
{}
```

```
package netcidrcontainsmatchesresult := net.cidr_contains_matches("1.1.1.0/24", "1.1.1.128")
```

Output

\[
  \[
    "1.1.1.0/24",
    "1.1.1.128"
  \]
\]

CIDR Match with Array

Either (or both) operand(s) may be an array, set, or object.

data.json

```
{}
```

input.json

```
{}
```

```
package netcidrcontainsmatchesresult := net.cidr_contains_matches(["1.1.1.0/24", "1.1.2.0/24"], "1.1.1.128")
```

Output

\[
  \[
    0,
    "1.1.1.128"
  \]
\]

CIDR Match with Arrays

The array/set/object elements may be arrays. In that case, the first element must be a valid CIDR/IP.

data.json

```
{}
```

input.json

```
{}
```

```
package netcidrcontainsmatchesresult := net.cidr_contains_matches(	[["1.1.0.0/16", "foo"], "1.1.2.0/24"], 	["1.1.1.128", ["1.1.254.254", "bar"]])
```

Output

\[
  \[
    0,
    0
  \],
  \[
    0,
    1
  \]
\]

CIDR Match with Objects

If the operand is a set, the outputs are matching elements. If the operand is an object, the outputs are matching keys.

data.json

```
{}
```

input.json

```
{}
```

```
package netcidrcontainsmatchesresult := net.cidr_contains_matches(	{["1.1.0.0/16", "foo"], "1.1.2.0/24"}, 	{"x": "1.1.1.128", "y": ["1.1.254.254", "bar"]})
```

Output

\[
  \[
    \[
      "1.1.0.0/16",
      "foo"
    \],
    "x"
  \],
  \[
    \[
      "1.1.0.0/16",
      "foo"
    \],
    "y"
  \]
\]