CodeLogic.NetUtils 5.0.116-preview

This is a prerelease version of CodeLogic.NetUtils.
This package has a SemVer 2.0.0 package version: 5.0.116-preview+258072a.
dotnet add package CodeLogic.NetUtils --version 5.0.116-preview
                    
NuGet\Install-Package CodeLogic.NetUtils -Version 5.0.116-preview
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="CodeLogic.NetUtils" Version="5.0.116-preview" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="CodeLogic.NetUtils" Version="5.0.116-preview" />
                    
Directory.Packages.props
<PackageReference Include="CodeLogic.NetUtils" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add CodeLogic.NetUtils --version 5.0.116-preview
                    
#r "nuget: CodeLogic.NetUtils, 5.0.116-preview"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package CodeLogic.NetUtils@5.0.116-preview
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=CodeLogic.NetUtils&version=5.0.116-preview&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=CodeLogic.NetUtils&version=5.0.116-preview&prerelease
                    
Install as a Cake Tool

CodeLogic.NetUtils

NuGet License: MIT

DNSBL blacklist checking and MaxMind GeoIP geolocation for CodeLogic 5 — screen abusive IPs and locate visitors with one library.

Bundles two network-reputation tools behind a single NetUtilsLibrary. The DNSBL checker queries multiple blacklist zones (IPv4 and IPv6, primary plus fallback) in parallel and short-circuits private/loopback addresses without a DNS query. The GeoIP service looks addresses up in a MaxMind GeoLite2/GeoIP2 .mmdb database (City, Country, Enterprise, ASN or ISP edition) — loaded from disk or auto-downloaded with your MaxMind credentials.

Install

dotnet add package CodeLogic.NetUtils

Quick start

using CL.NetUtils;

await Libraries.LoadAsync<NetUtilsLibrary>();   // register before ConfigureAsync()
await CodeLogic.ConfigureAsync();
await CodeLogic.StartAsync();

var net = Libraries.Get<NetUtilsLibrary>();

// 1. Is this IP on a blacklist? (uses the zones from config.netutils.json)
DnsblCheckResult check = await net.Dnsbl.CheckIpAsync("203.0.113.1");
if (check.IsBlacklisted)
    Console.WriteLine($"Listed by {check.MatchedService}");
else if (check.Status == DnsblCheckStatus.Indeterminate)
    Console.WriteLine($"Not listed by the zones that answered; unchecked: {string.Join(", ", check.FailedServices)}");

// 2. Where is this IP? Guard with HasGeoIp — GeoIP needs a MaxMind database.
if (net.HasGeoIp)
{
    IpLocationResult geo = await net.GeoIp.LookupIpAsync("203.0.113.1");
    if (geo.IsSuccessful)
        Console.WriteLine($"{geo.CityName}, {geo.CountryName} ({geo.CountryCode})");
}

Local and private addresses (loopback, RFC 1918, link-local, CGNAT, documentation/reserved ranges, IPv6 link/site-local and unique-local) are returned as not blacklisted without any DNS query.

Features

  • DNSBL checking — query multiple blacklist zones per address family, concurrently or one at a time (ParallelQueries), with primary/fallback providers. A check where zones could not be queried is Indeterminate, never reported as clean.
  • Per-call overrides — CheckIpAsync(ip, DnsblCheckRequest) supplies your own zones, timeout, and an async allowlist predicate.
  • Disabled is not an exception — with dnsbl.enabled (or enabled) off, net.Dnsbl is still there: IsEnabled is false and every check returns Status = Error with "DNSBL checking is disabled". HasDnsbl tells you up front.
  • Zone validation — only well-formed DNS names are queried; a blank line, IP literal or other malformed zone is never sent to the resolver and is reported in FailedServices.
  • Private-address short-circuit — loopback and RFC 1918 / IPv6 local ranges skip DNS and return not blacklisted.
  • IP geolocation — country/city/coordinates/time-zone lookups (City, Enterprise), country only (Country), or autonomous system and ISP (ASN, ISP) via MaxMind GeoLite2/GeoIP2. The edition is read from the database itself.
  • Auto-download — fetch the .mmdb when it is missing, using your MaxMind AccountId + LicenseKey, only from an https URL on a trusted host; only the .mmdb is extracted and it replaces the database in one rename.
  • Own result records — DnsblCheckResult and IpLocationResult, each with success/error factories.
  • Localizable messages — log lines and result error messages come from NetUtilsStrings (localization section netutils).

Configuration

Auto-generated on first run as config.netutils.json (section netutils). Keys are camelCase and matched case-sensitively, so a PascalCase key is ignored and its default stays active:

{
  "enabled": true,
  "dnsbl": {
    "enabled": true,
    "ipv4Services": ["zen.spamhaus.org", "dnsbl.sorbs.net"],
    "ipv4FallbackServices": ["b.barracudacentral.org"],
    "ipv6Services": ["zen.spamhaus.org", "dnsbl6.sorbs.net"],
    "ipv6FallbackServices": ["v6.b.barracudacentral.org"],
    "timeoutSeconds": 5,
    "parallelQueries": true,
    "detailedLogging": false
  },
  "geoIp": {
    "enabled": true,
    "databasePath": "",
    "autoUpdate": false,
    "accountId": 0,
    "licenseKey": "",
    "downloadUrl": "https://download.maxmind.com/geoip/databases/{DatabaseType}/download?suffix=tar.gz",
    "trustedDownloadHosts": ["download.maxmind.com"],
    "databaseType": "GeoLite2-City",
    "timeoutSeconds": 30
  }
}
Setting Default Description
Enabled true Master switch for the library.
Dnsbl.Enabled true Enable the DNSBL checker.
Dnsbl.Ipv4Services ["zen.spamhaus.org","dnsbl.sorbs.net"] Primary IPv4 blacklist zones.
Dnsbl.Ipv4FallbackServices ["b.barracudacentral.org"] Queried when no primary zone lists the address.
Dnsbl.Ipv6Services ["zen.spamhaus.org","dnsbl6.sorbs.net"] Primary IPv6 blacklist zones.
Dnsbl.Ipv6FallbackServices ["v6.b.barracudacentral.org"] IPv6 fallback zones.
Dnsbl.TimeoutSeconds 5 Per-zone DNS timeout; a zone that times out is reported in FailedServices.
Dnsbl.ParallelQueries true Query the zones of a list concurrently; false queries one at a time and stops at the first listing.
Dnsbl.DetailedLogging false Log each zone query.
GeoIp.Enabled true Enable the GeoIP service.
GeoIp.DatabasePath "" Explicit .mmdb path; blank auto-resolves to {dataDir}/geoip/{DatabaseType}.mmdb.
GeoIp.AutoUpdate false Refresh the database on startup when credentials are set (a missing database is always downloaded; a failed refresh keeps the old one).
GeoIp.AccountId 0 MaxMind account id (required for download).
GeoIp.LicenseKey "" MaxMind license key (secret; required for download).
GeoIp.DownloadUrl MaxMind, {DatabaseType} edition Download endpoint (tar.gz or zip); {DatabaseType} is replaced with DatabaseType. Must be https on a host in TrustedDownloadHosts, because the credentials are sent to it.
GeoIp.TrustedDownloadHosts ["download.maxmind.com"] Hosts DownloadUrl may use (exact match).
GeoIp.DatabaseType GeoLite2-City MaxMind edition id: a City, Country, Enterprise, ASN or ISP edition (GeoLite2-Country, GeoLite2-ASN, GeoIP2-ISP, ...). Names the default file and fills {DatabaseType} in DownloadUrl; a download must be of the same kind. Letters, digits, -, _, . only.
GeoIp.TimeoutSeconds 30 Download timeout.

Documentation

Full guide: CL.NetUtils documentation

Requirements

  • CodeLogic 5.0+ · .NET 11
  • MaxMind.GeoIP2 6.x
  • A MaxMind GeoLite2/GeoIP2 .mmdb for GeoIP (on disk, or auto-downloaded with credentials)

License

MIT — see LICENSE.

Product Compatible and additional computed target framework versions.
.NET net11.0 is compatible. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on CodeLogic.NetUtils:

Package Downloads
CodeLogic.WebLogic

Web application toolkit for CodeLogic 4 — routing, templates, forms, an ordered security pipeline, auth flows and realtime. No third-party dependencies beyond CodeLogic.*.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
5.0.116-preview 54 11/1/2026
5.0.115-preview 110 11/1/2026
5.0.114-preview 32 10/31/2026
5.0.113-preview 39 10/31/2026
4.9.106 45 10/30/2026
4.9.98 568 10/25/2026
4.8.93 72 9/23/2026
4.8.87 109 9/13/2026
4.8.85 61 9/12/2026
4.6.75-preview 62 8/1/2026
4.6.73 230 7/13/2026
4.6.72 71 6/20/2026
4.6.69-preview 66 6/20/2026
4.5.2 142 5/24/2026
4.5.2-preview.68 98 6/20/2026
4.5.1 188 5/24/2026
4.5.1-preview.56 119 5/24/2026
4.4.2-preview.53 90 5/24/2026
4.4.1 142 5/24/2026
4.0.5 130 5/15/2026
Loading failed

# CL.NetUtils — Changelog

All notable changes to **CodeLogic.NetUtils** are documented here. Versions follow
[Semantic Versioning](https://semver.org/).

## 5.0 (unreleased)

### Breaking

- Targets **.NET 11** (`net11.0`) and requires **CodeLogic 5.0** (`[5.0.0, 6.0.0)`). On .NET 10, stay on
 4.9.x. CodeLogic 5 makes `Result<T>` / `Result` C# 15 unions and `Error` a closed record with
 kind subtypes (`NotFoundError`, `ValidationError`, ...). Results can now be matched exhaustively
 with `switch`.
- **A DNSBL check that could not query a zone is no longer reported as clean.** Timeouts, resolver
 failures and DNSBL error answers (Spamhaus `127.255.255.x`) used to end as `NotBlacklisted`. When no
 zone lists the address but some zone failed, the result is now `Status = DnsblCheckStatus.Indeterminate`
 with the zones in `FailedServices` and a message in `ErrorMessage`; `IsBlacklisted` stays `false`.
 NXDOMAIN is still "not listed". Check `Status` where an unchecked address must not pass.
- **`GeoIp.DownloadUrl` must be `https` on a trusted host.** The MaxMind credentials were sent to any
 configured URL. The host must now be listed in the new `GeoIp.TrustedDownloadHosts` (default
 `["download.maxmind.com"]`); otherwise the download is refused before any request and configuration
 validation fails.
- **SharpCompress dependency removed.** The GeoIP archive is read with the built-in `System.Formats.Tar`
 and `System.IO.Compression` (`tar.gz` and `zip`).
- **`GeoIp.DatabaseType` is validated.** It becomes the default file name, so a value with path separators or
 `..` could place the database outside the data directory. It must now be an edition id (letters, digits, `-`,
 `_`, `.`, at most 64 characters); otherwise configuration validation fails and `GeoIpService` throws
 `ArgumentException`.
- **Malformed DNSBL zones are no longer queried.** A zone that is not a DNS name (blank line, IP literal,
 spaces, control characters, a single label) is skipped and reported in `FailedServices`, so the check is
 `Indeterminate`. Zones are trimmed, and `MatchedService` / `FailedServices` hold the trimmed name.

### Added

- `NetUtilsLibrary.HasDnsbl` and `DnsblChecker.IsEnabled`.
- GeoIP serves the **Country, Enterprise, ASN and ISP** editions as well as City: the edition is read from the
 database metadata (`GeoIpService.LoadedDatabaseType`). New `IpLocationResult.AutonomousSystemNumber` and
 `AutonomousSystemOrganization`; `IsSuccessful` is also `true` for an ASN/ISP result without a country.
- `GeoIp.DownloadUrl` accepts a `{DatabaseType}` placeholder, and the default URL uses it, so the configured
 edition is downloaded (`GeoIpConfig.DatabaseTypePlaceholder`, `GeoIpConfig.IsValidDatabaseType`).
- `DnsblCheckStatus` (`NotBlacklisted`, `Blacklisted`, `Indeterminate`, `Error`), `DnsblCheckResult.Status`,
 `DnsblCheckResult.FailedServices` and `DnsblCheckResult.Indeterminate(...)`.
- `DnsblCheckRequest.ParallelQueries` (default `true`).
- `GeoIpConfig.TrustedDownloadHosts` and `GeoIpConfig.TryGetTrustedDownloadUri(...)`.

### Fixed

- **`NetUtilsLibrary.Dnsbl` no longer throws when DNSBL checking is disabled** (audit 2026-11-01). The docs
 said it is always available, but with `dnsbl.enabled` (or `enabled`) off it threw `InvalidOperationException`.
 It now returns a checker whose checks answer `Status = Error` with "DNSBL checking is disabled", without a
 DNS query. It still throws before the library has initialized.
- **GeoIP is no longer City-only** (audit 2026-11-01). `DatabaseType` was documented as any edition, but only a
 City database installed and every lookup called `City()`. A downloaded database must now be of the same kind
 as `DatabaseType` (a Country download never replaces a City database).
- **`NetUtilsStrings` is used** (audit 2026-11-01). The localization model was registered but nothing read it.
 Lifecycle and DNSBL/GeoIP log lines, and the error messages in `DnsblCheckResult` / `IpLocationResult`
 (invalid address, DNSBL disabled, GeoIP not initialized, location not found), now come from it; new strings
 `InvalidIpAddressFormat`, `DnsblDisabled`, `GeoIpNotInitialized`, `LocationNotFound`. The English defaults
 match the previous messages.
- **Caller input can no longer forge log lines.** IP addresses and zones are logged with control characters
 replaced and cut to 64 characters.
- **A corrupt GeoIP download can no longer replace a working database (re-audit R2).** The extracted file is opened with the MaxMind reader, must be a supported edition of the configured kind, and must answer a test lookup. Only then is it renamed into place. The open reader switches without a gap, and on any failure the old file and reader stay in use. Readers load the database into memory, so the file is never locked.
- **`GeoIp.AutoUpdate` now works:** before, nothing read it. On startup it refreshes an existing database when credentials are set; a failed refresh is logged and the existing database stays in use. A missing database is downloaded regardless.
- **`Dnsbl.ParallelQueries` is honoured.** Zones were always queried one at a time. Now the zones of a
 list are queried concurrently by default, and with `ParallelQueries = false` one at a time, stopping at
 the first listing. DNS lookups use the asynchronous resolver, so the per-zone timeout is enforced.
- **GeoIP database replacement is selective and atomic.** Every archive entry (licence, readme, ...) was
 extracted straight into the database directory, over the live file. Now the archive is unpacked in a
 private temporary directory, only the `.mmdb` entry is extracted (by content, never by entry path),
 checked for the MaxMind metadata marker, and moved over the database in one rename; an open reader is
 switched to the new file. A failed or invalid download leaves the existing database untouched. A custom
 `DatabasePath` with a different file name than the archive's `.mmdb` now gets the database too.
- `LookupIpAsync` reads the database reader under its lock, so a concurrent reload or dispose cannot
 race it.
- Package versions are pinned (`MaxMind.GeoIP2` 6.1.0) instead of floating.
- **DNSBL queries are built from the parsed address.** The IPv4 query label reversed the dot-separated input
 text, so a shorthand that `IPAddress.TryParse` accepts (`1.2.3` = 1.2.0.3, hex `0x01.0x02.0x03.0x04`,
 a single 32-bit number) queried the wrong name and was never found listed. The label now comes from the
 address bytes, and an IPv4-mapped IPv6 address (`::ffff:a.b.c.d`) is checked against the IPv4 zones.
- **More non-routable addresses skip the DNSBL query:** IPv4 `0.0.0.0/8`, link-local `169.254/16`, shared
 address space (CGNAT) `100.64/10`, `192.0.0/24`, the documentation ranges (`192.0.2/24`, `198.51.100/24`,
 `203.0.113/24`), benchmarking `198.18/15`, multicast `224/4`, reserved `240/4` and broadcast; IPv6 unspecified
 `::` and documentation `2001:db8::/32`. Like the existing private ranges they return *not blacklisted*.

### Documentation

- Configuration examples use the camelCase keys the CodeLogic loader reads (PascalCase keys were ignored).
- The DNSBL guide describes the actual query order, fallback rule and failure handling.

## 2026-10-30

### Fixed

- **Health no longer reports optional features that are off as faults.** GeoIP with neither a database file
 nor MaxMind credentials is now *not configured* and Healthy (it was Degraded "GeoIP unavailable"), and is
 logged at Info instead of a startup warning. Degraded now means GeoIP was set up (database file or
 credentials) and still failed to start; the message carries the reason. The health message lists both
 services, e.g. `DNSBL on, GeoIP not configured`. A library with both services switched off is Healthy too.

### Added

- `GeoIpService.DatabasePath` and `GeoIpService.CanDownload`.

## 2026-10-24

### Changed

- Requires **CodeLogic 4.9+**. The official libraries move to the 4.9 line together with the framework,
 whose live config changes the stateful libraries now use. No API changes in this library.

## 2026-09-12

### Changed

- Unified the version line with the CodeLogic framework on **4.8.x**. Every official
 library and the framework now share one `major.minor`, so a given `4.8.<patch>`
 means the same generation across all packages.
- `version.txt` moved from `4.6` to `4.8`. The patch component remains the CI run
 number, composed at pack time; `AssemblyVersion` stays pinned at `Major.Minor.0.0`
 (now `4.8.0.0`) so every patch in the line loads interchangeably.

## 2026-06-20

### Documentation

- Full rewrite of the README and the deep docs page to house style: NuGet + MIT
 badges, blockquote tagline, concise quick-start, feature list, and a complete
 configuration table covering every `Dnsbl.*` and `GeoIp.*` field.
- Documented the correct load pattern (`Libraries.LoadAsync<NetUtilsLibrary>()`
 → `ConfigureAsync` → `StartAsync` → `Libraries.Get`) and both `Dnsbl` /
 `GeoIp` accessors, with the `HasGeoIp` guard for the optional GeoIP service.
- Documented both `CheckIpAsync` overloads, the default IPv4/IPv6 blacklist
 zones, and the per-call `DnsblCheckRequest` (per-call zone lists, timeout, and
 async allowlist predicate).
- Documented the `DnsblCheckResult` and `IpLocationResult` records field by
 field, including `IpLocationResult.IsSuccessful`.
- Documented GeoIP database resolution and auto-download: `DatabasePath` vs the
 `{dataDir}/geoip/{DatabaseType}.mmdb` fallback, and `DownloadDatabaseAsync`
 fetching/extracting the `.mmdb` via HTTP Basic Auth with `AccountId` +
 `LicenseKey`.

## [4.5.2] — 2026-06-20

### Documentation

- Corrected the README Quick Start to match the real API: `Dnsbl.CheckIpAsync`
 (was `CheckAsync`) returning `DnsblCheckResult.IsBlacklisted` / `MatchedService`
 (was `IsListed`), and the async `GeoIp.LookupIpAsync` returning
 `IpLocationResult.CountryName` / `CityName` (was a synchronous `Lookup`).
- Documented the `DnsblCheckRequest` overload of `CheckIpAsync` — per-call
 service lists plus an optional async allowlist predicate (`IsAllowedAsync`).
- Documented the `DnsblCheckResult` and `IpLocationResult` result records and
 the `IpLocationResult.IsSuccessful` helper.
- Documented that local/private addresses are short-circuited as not blacklisted.
- Added the `GeoIp.DownloadUrl` field to the sample `config.netutils.json`.

## [4.5.0] — 2026-05-24

### Changed

- **Unified versioning.** All CodeLogic.Libs now share a single version line
 controlled by `version.txt` in the repo root. This is a version alignment
 release — no functional changes to this library.
## [4.0.4] — 2026-04-16

### Changed

- README + manifest refresh for the v4 baseline. No functional changes vs 4.0.3.
- `LibraryManifest.Version` now reads from assembly metadata.

## [4.0.2] — 2026-04-09

### Added

- `DnsblCheckRequest` overload that accepts a caller-supplied DNSBL service
 list — useful when the calling app stores its own service registry instead
 of relying on the bundled defaults.

### Changed

- Annotated NetUtils configuration with `[ConfigField]` for the admin UI surface.
- Aligned with the v4 baseline across all libraries.

## [4.0.0] — 2026-04-09

Major rewrite. Republished as v4.0.0 to reset the version line under the
unified v4 baseline. GeoIP, DNSBL, and IP/CIDR utilities.

### Notes

- Earlier history is retained in the
 [git log](https://github.com/zyntal-com/CodeLogic.Libs/commits/main/CL.NetUtils).