CodeLogic.NetUtils
5.0.114-preview
See the version list below for details.
dotnet add package CodeLogic.NetUtils --version 5.0.114-preview
NuGet\Install-Package CodeLogic.NetUtils -Version 5.0.114-preview
<PackageReference Include="CodeLogic.NetUtils" Version="5.0.114-preview" />
<PackageVersion Include="CodeLogic.NetUtils" Version="5.0.114-preview" />
<PackageReference Include="CodeLogic.NetUtils" />
paket add CodeLogic.NetUtils --version 5.0.114-preview
#r "nuget: CodeLogic.NetUtils, 5.0.114-preview"
#:package CodeLogic.NetUtils@5.0.114-preview
#addin nuget:?package=CodeLogic.NetUtils&version=5.0.114-preview&prerelease
#tool nuget:?package=CodeLogic.NetUtils&version=5.0.114-preview&prerelease
CodeLogic.NetUtils
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 does city-level lookups against a MaxMind GeoLite2/GeoIP2 .mmdb database — 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 isIndeterminate, never reported as clean. - Per-call overrides —
CheckIpAsync(ip, DnsblCheckRequest)supplies your own zones, timeout, and an async allowlist predicate. - Private-address short-circuit — loopback and RFC 1918 / IPv6 local ranges skip DNS and return not blacklisted.
- IP geolocation — city-level country/city/coordinates/time-zone lookups via MaxMind GeoLite2/GeoIP2.
- Auto-download — fetch the
.mmdbwhen it is missing, using your MaxMindAccountId+LicenseKey, only from anhttpsURL on a trusted host; only the.mmdbis extracted and it replaces the database in one rename. - Own result records —
DnsblCheckResultandIpLocationResult, each with success/error factories.
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/GeoLite2-City/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 GeoLite2-City | Download endpoint (tar.gz or zip). 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 |
Database/edition id. |
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
.mmdbfor GeoIP (on disk, or auto-downloaded with credentials)
License
MIT — see LICENSE.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net11.0 is compatible. |
-
net11.0
- CodeLogic (>= 5.0.0-preview && < 6.0.0)
- MaxMind.GeoIP2 (>= 6.1.0)
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 | 46 | 11/1/2026 |
| 5.0.115-preview | 103 | 11/1/2026 |
| 5.0.114-preview | 31 | 10/31/2026 |
| 5.0.113-preview | 35 | 10/31/2026 |
| 4.9.106 | 41 | 10/30/2026 |
| 4.9.98 | 538 | 10/25/2026 |
| 4.8.93 | 70 | 9/23/2026 |
| 4.8.87 | 108 | 9/13/2026 |
| 4.8.85 | 58 | 9/12/2026 |
| 4.6.75-preview | 60 | 8/1/2026 |
| 4.6.73 | 228 | 7/13/2026 |
| 4.6.72 | 70 | 6/20/2026 |
| 4.6.69-preview | 65 | 6/20/2026 |
| 4.5.2 | 139 | 5/24/2026 |
| 4.5.2-preview.68 | 96 | 6/20/2026 |
| 4.5.1 | 185 | 5/24/2026 |
| 4.5.1-preview.56 | 117 | 5/24/2026 |
| 4.4.2-preview.53 | 89 | 5/24/2026 |
| 4.4.1 | 139 | 5/24/2026 |
| 4.0.5 | 128 | 5/15/2026 |
# 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`).
### Added
- `DnsblCheckStatus` (`NotBlacklisted`, `Blacklisted`, `Indeterminate`, `Error`), `DnsblCheckResult.Status`,
`DnsblCheckResult.FailedServices` and `DnsblCheckResult.Indeterminate(...)`.
- `DnsblCheckRequest.ParallelQueries` (default `true`).
- `GeoIpConfig.TrustedDownloadHosts` and `GeoIpConfig.TryGetTrustedDownloadUri(...)`.
### Fixed
- **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 City database, 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).