Declaratively configure multiple IPs in a Range

I want to configure 80,000 IPs on a NixOS system.

Is there something like allowedTCPPortRanges where i can set a Range in which the IPs should be used?

Like

GenIPsInRange = [{"from": "10.1.0.0", "to": "10.2.56.128"}];

It is possible to configure multiple IPs on a NIC like this:

  networking = {
    interfaces = {
      ens3.ipv4.addresses = [
        { address = "10.0.1.1"; prefixLength = 8; }
        { address = "10.0.1.2"; prefixLength = 8; }
        { address = "10.0.1.3"; prefixLength = 8; }
        { address = "10.0.1.4"; prefixLength = 8; }
        { address = "10.0.1.5"; prefixLength = 8; }
      ];
    };
  };

And to create 500 macvlan interfaces with

  networking = {
    macvlans = lib.attrsets.genAttrs (map (i: "macvlan${toString i}") (lib.lists.range 1 500)) (_: { interface = "enp2s0f1"; mode = "bridge"; });
  };

(they are good when you want to get 500 IPs from DHCP)

Workaround

Use python to generate IP list:

from ipaddress import ip_address

def ips(start, end):
  '''Return IPs in IPv4 range, inclusive.'''
  start_int = int(ip_address(start).packed.hex(), 16)
  end_int = int(ip_address(end).packed.hex(), 16)
  return [ip_address(ip).exploded for ip in range(start_int, end_int)]

for ip in ips('10.1.0.0', '10.2.56.128'):
  print("{{ address = \"{}\"; prefixLength = 8; }}".format(ip))
[davidak@nixos:~/code/scripts]$ python3 generate_ips_in_range.py 
{ address = "10.1.0.0"; prefixLength = 8; }
{ address = "10.1.0.1"; prefixLength = 8; }
{ address = "10.1.0.2"; prefixLength = 8; }
{ address = "10.1.0.3"; prefixLength = 8; }
{ address = "10.1.0.4"; prefixLength = 8; }
{ address = "10.1.0.5"; prefixLength = 8; }
{ address = "10.1.0.6"; prefixLength = 8; }
{ address = "10.1.0.7"; prefixLength = 8; }
{ address = "10.1.0.8"; prefixLength = 8; }
{ address = "10.1.0.9"; prefixLength = 8; }
{ address = "10.1.0.10"; prefixLength = 8; }
...

I saved them in target-ips.nix and imported it in my configuration.nix

[{ address = "10.1.0.0"; prefixLength = 8; }
{ address = "10.1.0.1"; prefixLength = 8; }
{ address = "10.1.0.2"; prefixLength = 8; }
...
{ address = "10.2.56.127"; prefixLength = 8; }]

(the file size is 3.8 MB)

{ config, pkgs, ... }:

let
  target-ips = import ./target-ips.nix;
in
{
...
  networking = {
    interfaces = {
      ens3.ipv4.addresses = [
        { address = "10.0.0.5"; prefixLength = 8; }
      ]++target-ips;
    };
  };
...
}

The nixos-rebuild switch took 7 minutes.

It works, all IPs are reachable.

Screenshot from 2020-09-06 00-08-00

4 Likes

I’m impressed!
But what would you do with 80000 ip’s?

I simulate a network with 80,000 linux systems.

My company develops a vulnerability scanner. I work in QA and want to test how the performance is when scanning 80,000 hosts. I started with VMs, then containers and now use just one physical host with many IPs. It has for example a webserver and a webserver can handle many connections, so it should work this way.

Normally you have a webserver with 1 IP and many clients, but i have one client (our scanner) and a webserver with many IPs.

4 Likes