# NetworkCalc

> Network calculators and lookups from NetworkCalc: work out subnets, plan VLSM address space, turn IP ranges into CIDR blocks, look up DNS, WHOIS and SPF records, read a site's TLS certificate and its expiry date, and convert numbers between binary, octal, decimal and hex or text to and from Base64.

App · 9 actions. Web page: https://docs.lodol.com/docs/integrations/networkcalc

## Actions

### Calculate a subnet

Work out everything about an IPv4 subnet from an address and its size: the network and broadcast addresses, subnet and wildcard masks, how many devices it holds and the first and last usable address. Write the size on the address (192.168.1.77/24 or 192.168.1.77 255.255.255.0) or pick it from Subnet size.

**Inputs**

- IP address or network (`address`, text, required): An IPv4 address, with or without its size: 192.168.1.77/24, 192.168.1.77 255.255.255.0 or just 192.168.1.77.
- Subnet size (`prefix_length`, text): The subnet's size, if the address doesn't already end in /24 or a mask. Leave it empty for a single address (/32). One of: `32` (/32 (255.255.255.255, 1 address)), `31` (/31 (255.255.255.254, 2 addresses)), `30` (/30 (255.255.255.252, 4 addresses)), `29` (/29 (255.255.255.248, 8 addresses)), `28` (/28 (255.255.255.240, 16 addresses)), `27` (/27 (255.255.255.224, 32 addresses)), `26` (/26 (255.255.255.192, 64 addresses)), `25` (/25 (255.255.255.128, 128 addresses)), `24` (/24 (255.255.255.0, 256 addresses)), `23` (/23 (255.255.254.0, 512 addresses)), and 22 more.
- Show binary (`include_binary`, true/false): Also return the address, masks and range written in binary, octet by octet. Default: `false`.

**Outputs**

- `address` (text): The IP address that was entered.
- `binary` (object): The same details in binary. Empty unless Show binary was turned on.
- `broadcast_address` (text): The last address: the broadcast address.
- `cidr` (text): The address with its prefix, such as 192.168.1.77/24.
- `first_usable_address` (text): The first address a device can use. Empty for a /31 or /32.
- `last_usable_address` (text): The last address a device can use. Empty for a /31 or /32.
- `network_address` (text): The first address: the network itself.
- `network_cidr` (text): The network itself in CIDR notation, such as 192.168.1.0/24.
- `networkcalc_url` (text): This subnet on networkcalc.com.
- `next_address` (text): The address after the one entered, for stepping through a range.
- `prefix_length` (number): The prefix length: 24 for a /24.
- `subnet_mask` (text): The subnet mask, such as 255.255.255.0.
- `total_addresses` (number): How many addresses the subnet holds.
- `usable_hosts` (number): How many addresses can be given to devices (all but the network and broadcast addresses).
- `wildcard_mask` (text): The wildcard mask (the subnet mask inverted), as used in Cisco access lists.

**Example output**

```json
{
  "address": "192.168.1.77",
  "binary": null,
  "broadcast_address": "192.168.1.255",
  "cidr": "192.168.1.77/24",
  "first_usable_address": "192.168.1.1",
  "last_usable_address": "192.168.1.254",
  "network_address": "192.168.1.0",
  "network_cidr": "192.168.1.0/24",
  "networkcalc_url": "https://networkcalc.com/subnet-calculator/192.168.1.77/24",
  "next_address": "192.168.1.78",
  "prefix_length": 24,
  "subnet_mask": "255.255.255.0",
  "total_addresses": 256,
  "usable_hosts": 254,
  "wildcard_mask": "0.0.0.255"
}
```

### Check an SPF record

Check the SPF record that says which servers may send email for a domain: the one a domain publishes, or one you paste in before publishing it. Returns whether each part is valid and how many DNS lookups it needs, since mail servers reject a record that needs more than 10.

**Inputs**

- Check (`check`, text): Whether to check a domain's published record or one you paste in. One of: `domain` (A domain's published record), `record` (A record I paste in). Default: `domain`.
- Domain (`domain`, text): The domain whose SPF record to check, such as example.com. Only when Check is A domain's published record.
- SPF record (`spf_record`, text): The record to check, starting v=spf1, such as v=spf1 mx include:_spf.google.com -all. Only when Check is A record I paste in.

**Outputs**

- `dns_lookups` (number): How many DNS lookups the record needs.
- `domain` (text): The domain checked. Empty when a pasted record was checked.
- `found` (true/false): Whether the domain publishes an SPF record.
- `invalid_terms` (list): The parts of the record that are invalid.
- `is_valid` (true/false): Whether every part of the record is valid.
- `spf_record` (text): The SPF record that was checked.
- `terms` (list): Each part of the record and whether it is valid.
- `within_lookup_limit` (true/false): Whether it stays within the 10 lookups mail servers allow.

**Example output**

```json
{
  "dns_lookups": 3,
  "domain": "networkcalc.com",
  "found": true,
  "invalid_terms": [],
  "is_valid": true,
  "spf_record": "v=spf1 mx include:_spf.google.com include:servers.mcsv.net -all",
  "terms": [
    {
      "dns_lookups": 0,
      "is_valid": true,
      "term": "v=spf1",
      "type": "version"
    },
    {
      "dns_lookups": 1,
      "is_valid": true,
      "term": "mx",
      "type": "mechanism"
    },
    {
      "dns_lookups": 0,
      "is_valid": true,
      "term": "-all",
      "type": "mechanism"
    },
    {
      "dns_lookups": 1,
      "is_valid": true,
      "term": "include:servers.mcsv.net",
      "type": "mechanism"
    },
    {
      "dns_lookups": 1,
      "is_valid": true,
      "term": "include:_spf.google.com",
      "type": "mechanism"
    }
  ],
  "within_lookup_limit": true
}
```

### Convert a number between bases

Convert a whole number between binary, octal, decimal and hexadecimal. Turn on two's complement to convert negative numbers, or to read a binary or hex value as signed.

**Inputs**

- Number (`number`, text, required): The whole number to convert, such as 255, 11111111 or ff. Prefixes such as 0x and 0b, spaces and underscores are ignored.
- Convert from (`from_base`, text): The base the number is written in. One of: `2` (Binary (base 2)), `8` (Octal (base 8)), `10` (Decimal (base 10)), `16` (Hexadecimal (base 16)). Default: `10`.
- Convert to (`to_base`, text): The base to convert it to. One of: `2` (Binary (base 2)), `8` (Octal (base 8)), `10` (Decimal (base 10)), `16` (Hexadecimal (base 16)). Default: `2`.
- Two's complement (`twos_complement`, text): Off for positive numbers. Pick a width to convert negative numbers: binary and hex results are padded to that many bits. One of: `off` (Off (positive numbers only)), `8` (8-bit), `16` (16-bit), `32` (32-bit), `64` (64-bit). Default: `off`.

**Outputs**

- `converted` (text): The converted number.
- `from_base` (number): The base converted from: 2, 8, 10 or 16.
- `from_base_name` (text): binary, octal, decimal or hexadecimal.
- `number` (text): The number that was converted, as it was read.
- `to_base` (number): The base converted to: 2, 8, 10 or 16.
- `to_base_name` (text): binary, octal, decimal or hexadecimal.
- `twos_complement_bits` (number): The two's complement width used. Empty when it was off.

**Example output**

```json
{
  "converted": "111100111110101101101",
  "from_base": 16,
  "from_base_name": "hexadecimal",
  "number": "1e7d6d",
  "to_base": 2,
  "to_base_name": "binary",
  "twos_complement_bits": null
}
```

### Convert IP ranges to CIDR

Turn an IPv4 range such as 10.0.0.5-10.0.3.200 into the exact list of CIDR blocks that covers it, or merge a list of blocks, ranges and addresses into the fewest blocks. Also returns the single smallest block that covers everything and how many extra addresses it would let in. Use the exact list for firewall rules and allowlists.

**Inputs**

- IP ranges (`ranges`, text, required): One or more IPv4 ranges (10.0.0.5-10.0.0.20), networks (10.0.0.0/24) or single addresses, separated by commas or new lines. Up to 1,000.

**Outputs**

- `adjusted_entries` (list): Entries written with an address inside a network (10.0.0.5/24) that were read as the whole network (10.0.0.0/24).
- `block_count` (number): How many blocks the exact answer needs.
- `blocks` (list): The exact blocks, with their details.
- `cidrs` (list): The exact CIDR blocks covering the input, as plain text: ready for a firewall rule or an allowlist.
- `covering_block` (object): The smallest single block covering everything, and what it adds.
- `covering_cidr` (text): The smallest single block that contains every input address.
- `first_address` (text): The lowest address in the input.
- `last_address` (text): The highest address in the input.
- `total_addresses` (number): How many distinct addresses the input covers.

**Example output**

```json
{
  "adjusted_entries": [],
  "block_count": 4,
  "blocks": [
    {
      "addresses": 2,
      "cidr": "192.168.1.10/31",
      "first_address": "192.168.1.10",
      "last_address": "192.168.1.11",
      "subnet_mask": "255.255.255.254",
      "wildcard_mask": "0.0.0.1"
    },
    {
      "addresses": 4,
      "cidr": "192.168.1.12/30",
      "first_address": "192.168.1.12",
      "last_address": "192.168.1.15",
      "subnet_mask": "255.255.255.252",
      "wildcard_mask": "0.0.0.3"
    },
    {
      "addresses": 4,
      "cidr": "192.168.1.16/30",
      "first_address": "192.168.1.16",
      "last_address": "192.168.1.19",
      "subnet_mask": "255.255.255.252",
      "wildcard_mask": "0.0.0.3"
    },
    {
      "addresses": 1,
      "cidr": "192.168.1.20/32",
      "first_address": "192.168.1.20",
      "last_address": "192.168.1.20",
      "subnet_mask": "255.255.255.255",
      "wildcard_mask": "0.0.0.0"
    }
  ],
  "cidrs": [
    "192.168.1.10/31",
    "192.168.1.12/30",
    "192.168.1.16/30",
    "192.168.1.20/32"
  ],
  "covering_block": {
    "addresses": 32,
    "cidr": "192.168.1.0/27",
    "extra_addresses": 21,
    "extra_percent": 65.6,
    "extra_ranges": [
      {
        "addresses": 10,
        "end": "192.168.1.9",
        "start": "192.168.1.0"
      },
      {
        "addresses": 11,
        "end": "192.168.1.31",
        "start": "192.168.1.21"
      }
    ],
    "first_address": "192.168.1.0",
    "is_exact": false,
    "last_address": "192.168.1.31",
    "subnet_mask": "255.255.255.224",
    "wildcard_mask": "0.0.0.31"
  },
  "covering_cidr": "192.168.1.0/27",
  "first_address": "192.168.1.10",
  "last_address": "192.168.1.20",
  "total_addresses": 11
}
```

### Encode or decode text

Encode text as Base64, Base64URL or URL (percent) encoding, or decode it back.

**Inputs**

- Text (`text`, text, required): The text to encode or decode.
- Encoding (`encoding`, text): Which encoding to use. One of: `base64`, `base64url` (Base64URL (safe in web addresses)), `url` (URL encoding (percent-encoding)). Default: `base64`.
- Encode or decode (`direction`, text): Whether to encode the text or decode it. One of: `encode`, `decode`. Default: `encode`.

**Outputs**

- `direction` (text): encode or decode.
- `encoding` (text): base64, base64url or url.
- `result` (text): The encoded or decoded text.
- `text` (text): The text that was given.

**Example output**

```json
{
  "direction": "encode",
  "encoding": "base64",
  "result": "SGVsbG8gV29ybGQh",
  "text": "Hello World!"
}
```

### Get a TLS certificate

Read the TLS/SSL certificate a site is serving right now: who it was issued to and by, when it expires (and in how many days), every name it covers, and whether it covers the hostname you asked about. Use it to watch for expiring certificates or to confirm a renewal went live.

**Inputs**

- Hostname (`hostname`, text, required): The site to check, such as example.com. A pasted web address works too.
- Port (`port`, number): The port the site serves TLS on. Leave it at 443 for a website. From 1 to 65535. Default: `443`.

**Outputs**

- `alternate_names` (list): Every name the certificate covers.
- `covers_hostname` (true/false): Whether the certificate covers the hostname that was checked.
- `days_until_expiry` (number): Whole days until it expires. Negative once it has.
- `fingerprint_sha1` (text): The certificate's SHA-1 fingerprint.
- `hostname` (text): The host that was checked.
- `is_expired` (true/false): Whether the certificate has expired.
- `is_valid_now` (true/false): Whether today is inside its validity dates.
- `issued_by` (text): The certificate authority that issued it.
- `issued_to` (text): The name the certificate was issued to.
- `pem` (text): The certificate itself, in PEM format.
- `port` (number): The port that was checked.
- `serial_number` (text): The certificate's serial number.
- `valid_from` (text): When the certificate became valid (ISO 8601).
- `valid_to` (text): When the certificate expires (ISO 8601).

**Example output**

```json
{
  "alternate_names": [
    "networkcalc.com"
  ],
  "covers_hostname": true,
  "days_until_expiry": 81,
  "fingerprint_sha1": "92:EE:E2:EE:12:90:C4:8D:65:44:1B:52:B7:23:24:B3:9B:8C:43:33",
  "hostname": "networkcalc.com",
  "is_expired": false,
  "is_valid_now": true,
  "issued_by": "WE1",
  "issued_to": "networkcalc.com",
  "pem": "-----BEGIN CERTIFICATE-----\nMIIDdDCCAxqgAwIBAgIRAJKwYk4vafWLE6Jh1L73SvEw...\n-----END CERTIFICATE-----",
  "port": 443,
  "serial_number": "92B0624E2F69F58B13A261D4BEF74AF1",
  "valid_from": "2026-10-07T10:18:39.000Z",
  "valid_to": "2027-01-05T11:18:34.000Z"
}
```

### Look up DNS records

Look up the DNS records published for a hostname: IPv4 addresses (A), aliases (CNAME), mail servers (MX), name servers (NS), the start of authority (SOA) and text records (TXT). A name with no records comes back with found set to false rather than failing, so a workflow can check whether a domain resolves.

**Inputs**

- Hostname (`hostname`, text, required): The hostname or domain to look up, such as example.com or www.example.com. A pasted web address works too.
- Record types (`record_types`, list): Which record types to return. Leave empty for all of them. One or more of: `A` (A (IPv4 addresses)), `CNAME` (CNAME (alias for another name)), `MX` (MX (mail servers)), `NS` (NS (name servers)), `SOA` (SOA (primary name server)), `TXT` (TXT (text, SPF and verification records)).

**Outputs**

- `canonical_names` (list): The names this hostname is an alias of (CNAME).
- `count` (number): How many records were found.
- `found` (true/false): Whether any records of the chosen types were found.
- `hostname` (text): The hostname that was looked up.
- `ip_addresses` (list): The A record addresses.
- `mail_servers` (list): The mail servers (MX), lowest priority number first.
- `name_servers` (list): The name servers (NS).
- `record_types` (list): The record types included.
- `records` (list): Every record found, one row each.
- `soa` (object): The start of authority record. Empty when SOA was not included.
- `txt_records` (list): The TXT records.

**Example output**

```json
{
  "canonical_names": [],
  "count": 6,
  "found": true,
  "hostname": "networkcalc.com",
  "ip_addresses": [
    "172.66.0.96",
    "162.159.140.98"
  ],
  "mail_servers": [
    {
      "host": "aspmx.l.google.com",
      "priority": 1
    }
  ],
  "name_servers": [
    "ns-cloud-b1.googledomains.com"
  ],
  "record_types": [
    "A",
    "CNAME",
    "MX",
    "NS",
    "SOA",
    "TXT"
  ],
  "records": [
    {
      "priority": null,
      "ttl": 30,
      "type": "A",
      "value": "172.66.0.96"
    },
    {
      "priority": null,
      "ttl": 30,
      "type": "A",
      "value": "162.159.140.98"
    },
    {
      "priority": 1,
      "ttl": null,
      "type": "MX",
      "value": "aspmx.l.google.com"
    },
    {
      "priority": null,
      "ttl": null,
      "type": "NS",
      "value": "ns-cloud-b1.googledomains.com"
    },
    {
      "priority": null,
      "ttl": null,
      "type": "SOA",
      "value": "ns-cloud-b1.googledomains.com"
    },
    {
      "priority": null,
      "ttl": null,
      "type": "TXT",
      "value": "v=spf1 mx include:_spf.google.com include:servers.mcsv.net -all"
    }
  ],
  "soa": {
    "hostmaster": "cloud-dns-hostmaster.google.com",
    "primary_name_server": "ns-cloud-b1.googledomains.com"
  },
  "txt_records": [
    "v=spf1 mx include:_spf.google.com include:servers.mcsv.net -all"
  ]
}
```

### Look up domain registration (WHOIS)

Look up who a domain is registered through and when it was registered and expires, with the days left until expiry worked out for you. Give it www.example.com and it looks up example.com. Some country domains publish only the registrar.

**Inputs**

- Domain (`domain`, text, required): The domain to look up, such as example.com.

**Outputs**

- `abuse_email` (text): Where to report abuse.
- `abuse_phone` (text): The registrar's abuse phone number.
- `created_at` (text): When the domain was first registered (ISO 8601).
- `days_until_expiry` (number): Whole days until the registration expires. Negative once it has.
- `domain` (text): The registered domain that was looked up. For www.example.com this is example.com.
- `expires_at` (text): When the registration expires (ISO 8601).
- `found` (true/false): Whether registration details were found.
- `registrar` (text): The company the domain is registered through.
- `registrar_iana_id` (number): The registrar's IANA number.
- `registry_domain_id` (text): The domain's ID at the registry.
- `status` (text): The registry status, such as client transfer prohibited.
- `status_description` (text): What that status means.

**Example output**

```json
{
  "abuse_email": "abuse-complaints@squarespace.com",
  "abuse_phone": "+1.646-693-5324",
  "created_at": "2020-05-17T20:34:26Z",
  "days_until_expiry": 213,
  "domain": "networkcalc.com",
  "expires_at": "2027-05-17T20:34:26Z",
  "found": true,
  "registrar": "Squarespace Domains II LLC",
  "registrar_iana_id": 895,
  "registry_domain_id": "2527354476_DOMAIN_COM-VRSN",
  "status": "client",
  "status_description": null
}
```

### Plan subnets (VLSM)

Divide a network into right-sized subnets for the number of devices each one needs (variable-length subnet masking). Returns the block given to each subnet with its usable range and masks, why that block was chosen, and the space left over as ready-to-use blocks. If they don't all fit, the ones that did are still returned and the rest are listed under did_not_fit.

**Inputs**

- Network to divide (`network`, text, required): The IPv4 network to split up, with its size, such as 192.168.1.0/24. A /30 or larger.
- Subnets (`subnets`, object, required): Each subnet's name and how many devices it needs, such as Sales: 60. Up to 64 subnets; names up to 32 characters.

**Outputs**

- `all_fit` (true/false): Whether every subnet asked for fitted in the network.
- `allocated_addresses` (number): Addresses given to the subnets.
- `allocated_percent` (number): The share of the network given out, in percent.
- `did_not_fit` (list): Subnets there was no room for. Empty when all_fit is true.
- `free_addresses` (number): Addresses left over.
- `free_blocks` (list): The space left over, as CIDR blocks ready to use.
- `free_percent` (number): The share of the network left over, in percent.
- `free_ranges` (list): The space left over, as address ranges.
- `network` (text): The network that was divided, in CIDR notation.
- `network_subnet_mask` (text): The subnet mask, such as 255.255.255.0.
- `network_total_addresses` (number): How many addresses the network holds.
- `subnets` (list): The subnets that were placed, in address order.
- `subnets_placed` (number): How many subnets were placed.
- `subnets_requested` (number): How many subnets were asked for.

**Example output**

```json
{
  "all_fit": true,
  "allocated_addresses": 68,
  "allocated_percent": 26.6,
  "did_not_fit": [],
  "free_addresses": 188,
  "free_blocks": [
    "192.168.1.68/30",
    "192.168.1.72/29",
    "192.168.1.80/28",
    "192.168.1.96/27",
    "192.168.1.128/25"
  ],
  "free_percent": 73.4,
  "free_ranges": [
    {
      "addresses": 188,
      "cidrs": [
        "192.168.1.68/30",
        "192.168.1.72/29",
        "192.168.1.80/28",
        "192.168.1.96/27",
        "192.168.1.128/25"
      ],
      "end": "192.168.1.255",
      "start": "192.168.1.68"
    }
  ],
  "network": "192.168.1.0/24",
  "network_subnet_mask": "255.255.255.0",
  "network_total_addresses": 256,
  "subnets": [
    {
      "broadcast_address": "192.168.1.63",
      "cidr": "192.168.1.0/26",
      "explanation": "60 hosts + 2 reserved (network and broadcast) = 62 addresses. The smallest block that holds that is a /26 (64 addresses, 62 usable), leaving 2 spare. It is placed at the start of the parent network.",
      "first_usable_address": "192.168.1.1",
      "last_usable_address": "192.168.1.62",
      "name": "Sales",
      "network_address": "192.168.1.0",
      "prefix_length": 26,
      "requested_hosts": 60,
      "spare_hosts": 2,
      "subnet_mask": "255.255.255.192",
      "total_addresses": 64,
      "usable_hosts": 62,
      "wildcard_mask": "0.0.0.63"
    },
    {
      "broadcast_address": "192.168.1.67",
      "cidr": "192.168.1.64/30",
      "explanation": "2 hosts + 2 reserved (network and broadcast) = 4 addresses. The smallest block that holds that is a /30 (4 addresses, 2 usable), leaving 0 spare. It is placed at the next /30-aligned address after 192.168.1.0/26.",
      "first_usable_address": "192.168.1.65",
      "last_usable_address": "192.168.1.66",
      "name": "WAN",
      "network_address": "192.168.1.64",
      "prefix_length": 30,
      "requested_hosts": 2,
      "spare_hosts": 0,
      "subnet_mask": "255.255.255.252",
      "total_addresses": 4,
      "usable_hosts": 2,
      "wildcard_mask": "0.0.0.3"
    }
  ],
  "subnets_placed": 2,
  "subnets_requested": 2
}
```
