{
  config,
  lib,
  ...
}:
with lib; {
  options.local.sys.nets = with lib.types;
    mkOption {
      readOnly = true;

      type = attrsOf (submodule ({config, ...}: {
        options = let
          v4config = config.v4;
          v6config = config.v6;
        in {
          hosts = mkOption {
            default = {};

            type = attrsOf (submodule {
              options = {
                v4 = mkOption {
                  default = null;

                  type = nullOr (submodule ({config, ...}: {
                    options = {
                      suffix = mkOption {
                        type = str;
                      };

                      address = mkOption {
                        type = str;
                        readOnly = true;
                      };

                      cidr = mkOption {
                        type = str;
                        readOnly = true;
                      };

                      single = mkOption {
                        type = str;
                        readOnly = true;
                      };
                    };

                    config = {
                      address =
                        if v4config.bits == 0
                        then config.suffix
                        else if v4config.bits == 32
                        then v4config.subnet
                        else "${v4config.prefix}.${config.suffix}";

                      cidr = "${config.address}/${toString v4config.bits}";
                      single = "${config.address}/32";
                    };
                  }));
                };

                v6 = mkOption {
                  default = null;

                  type = nullOr (submodule ({config, ...}: {
                    options = {
                      suffix = mkOption {
                        type = str;
                      };

                      address = mkOption {
                        type = str;
                        readOnly = true;
                      };

                      cidr = mkOption {
                        type = str;
                        readOnly = true;
                      };

                      single = mkOption {
                        type = str;
                        readOnly = true;
                      };
                    };

                    config = {
                      address = let
                        hextets = fragment: length (splitString ":" fragment);
                        separator =
                          if doubleColon
                          then "::"
                          else ":";
                        doubleColon = hextets v6config.prefix + hextets config.suffix < 8;

                        joined =
                          if v6config.bits == 128
                          then v6config.prefix
                          else if v6config.bits == 0
                          then config.suffix
                          else "${v6config.prefix}${separator}${config.suffix}";
                      in
                        joined;

                      cidr = "${config.address}/${toString v6config.bits}";
                      single = "${config.address}/128";
                    };
                  }));
                };
              };
            });
          };

          v4 = mkOption {
            default = null;

            type = nullOr (submodule ({config, ...}: {
              options = {
                bits = mkOption {
                  type = enum [0 8 16 24 32];
                };

                prefix = mkOption {
                  type = str;
                };

                subnet = mkOption {
                  type = str;
                  readOnly = true;
                };

                cidr = mkOption {
                  type = str;
                  readOnly = true;
                };
              };

              config = {
                cidr = "${config.subnet}/${toString config.bits}";
                subnet =
                  if config.bits != 0
                  then config.prefix + strings.replicate (4 - config.bits / 8) ".0"
                  else "0.0.0.0";
              };
            }));
          };

          v6 = mkOption {
            default = null;

            type = nullOr (submodule ({config, ...}: {
              options = {
                bits = mkOption {
                  type =
                    addCheck (ints.between 0 128) (b: mod b 4 == 0)
                    // {
                      description = "IPv6 subnet bits at nibble boundary";
                    };
                };

                prefix = mkOption {
                  type = str;
                };

                subnet = mkOption {
                  type = str;
                  readOnly = true;
                };

                cidr = mkOption {
                  type = str;
                  readOnly = true;
                };
              };

              config = {
                cidr = "${config.subnet}/${toString config.bits}";
                subnet =
                  if config.bits == 128 || length (splitString "::" config.prefix) > 1
                  then config.prefix
                  else "${config.prefix}::";
              };
            }));
          };
        };
      }));
    };
}