ArthaTech.IpGuard
1.0.0
dotnet add package ArthaTech.IpGuard --version 1.0.0
NuGet\Install-Package ArthaTech.IpGuard -Version 1.0.0
<PackageReference Include="ArthaTech.IpGuard" Version="1.0.0" />
<PackageVersion Include="ArthaTech.IpGuard" Version="1.0.0" />
<PackageReference Include="ArthaTech.IpGuard" />
paket add ArthaTech.IpGuard --version 1.0.0
#r "nuget: ArthaTech.IpGuard, 1.0.0"
#:package ArthaTech.IpGuard@1.0.0
#addin nuget:?package=ArthaTech.IpGuard&version=1.0.0
#tool nuget:?package=ArthaTech.IpGuard&version=1.0.0
ArthaTech.IpGuard
ASP.NET Core middleware and service for IP-based access control using the IPinfo API.
Features at a glance:
- 🌍 Geo-location lookup (country, city, region, timezone, ASN)
- 🔒 VPN / Proxy / Tor / Hosting detection (requires IPinfo Privacy addon)
- 🚫 Configurable restricted country list
- ✅ IP whitelist
- ⚡ In-memory caching (configurable TTL)
- 🛡️ Fail-open design — allows traffic if IPinfo is unreachable
- 🔌 Works with any ASP.NET Core 6 / 7 / 8 Web API
Installation
dotnet add package ArthaTech.IpGuard
Or via the NuGet Package Manager:
PM> Install-Package ArthaTech.IpGuard
Quick Start
1. Get an IPinfo Token
Sign up at ipinfo.io and copy your API token from the dashboard. Free plan includes 50,000 lookups/month and geo-location data. VPN/Proxy/Tor detection requires the Privacy Detection add-on (paid).
2. Register Services (Program.cs)
Option A — Configuration delegate (code-first):
using IpGuard.Extensions;
builder.Services.AddIpGuard(options =>
{
options.ApiToken = "your_ipinfo_token_here";
options.RestrictedCountries = ["KP", "IR", "CU", "SY"]; // ISO 3166-1 alpha-2
options.BlockVpn = true;
options.BlockProxy = true;
options.BlockTor = true;
});
Option B — From appsettings.json (recommended for production):
builder.Services.AddIpGuard(builder.Configuration);
{
"IpGuard": {
"ApiToken": "your_ipinfo_token_here",
"RestrictedCountries": ["KP", "IR", "CU"],
"BlockVpn": true,
"BlockProxy": true,
"BlockTor": true,
"BlockHosting": false,
"WhitelistedIps": ["127.0.0.1", "10.0.0.5"],
"CacheDurationMinutes": 30,
"BlockedStatusCode": 403,
"BlockedMessage": "Access denied from your region or network.",
"LogBlocked": true,
"Enabled": true
}
}
Option B2 — From a custom config section:
builder.Services.AddIpGuard(builder.Configuration.GetSection("Security:IpGuard"));
3. Add Middleware (Program.cs)
app.UseRouting();
app.UseIpGuard(); // ← Place AFTER UseRouting, BEFORE UseAuthentication
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
That's it. Every request is now checked against your configured rules.
Configuration Reference
| Property | Type | Default | Description |
|---|---|---|---|
ApiToken |
string |
"" |
Required. Your IPinfo API token. |
RestrictedCountries |
List<string> |
[] |
ISO 3166-1 alpha-2 codes to block (e.g. ["KP","IR"]). |
BlockVpn |
bool |
false |
Block VPN connections. Requires Privacy addon. |
BlockProxy |
bool |
false |
Block proxy connections. Requires Privacy addon. |
BlockTor |
bool |
false |
Block Tor exit nodes. Requires Privacy addon. |
BlockHosting |
bool |
false |
Block datacenter/hosting IPs. Requires Privacy addon. |
WhitelistedIps |
List<string> |
[] |
IPs that always bypass all checks. |
CacheDurationMinutes |
int |
30 |
How long to cache each IP result. |
BlockedStatusCode |
int |
403 |
HTTP status code returned when blocked. |
BlockedMessage |
string |
"Access denied..." |
Message body when blocked. |
Enabled |
bool |
true |
Set false to disable all checks (e.g. local dev). |
LogBlocked |
bool |
true |
Log blocked requests at Warning level. |
RealIpHeaders |
List<string> |
["CF-Connecting-IP","X-Forwarded-For","X-Real-IP"] |
Headers to read client IP from (in priority order). |
IpInfoBaseUrl |
string |
"https://ipinfo.io" |
Override for enterprise / self-hosted IPinfo. |
ApiTimeoutSeconds |
int |
5 |
Timeout for IPinfo API calls. |
Blocked Response Format
When an IP is blocked, the middleware returns:
HTTP/1.1 403 Forbidden
Content-Type: application/json; charset=utf-8
{
"error": "Access Denied",
"message": "Access denied from your region or network.",
"reason": "Country not permitted: KP",
"country": "KP",
"ip": "175.45.176.0"
}
Reading IP Info in Controllers
The middleware attaches the result to HttpContext.Items for use in downstream code:
[ApiController]
[Route("api/[controller]")]
public class OrderController : ControllerBase
{
[HttpPost]
public IActionResult CreateOrder([FromBody] OrderRequest req)
{
var ipResult = HttpContext.Items["IpGuardResult"] as IpCheckResult;
if (ipResult != null)
{
Console.WriteLine($"Request from: {ipResult.Country} / {ipResult.City}");
Console.WriteLine($"IsVpn: {ipResult.IsVpn}, IsTor: {ipResult.IsTor}");
Console.WriteLine($"Org: {ipResult.Org}");
}
// ... rest of your logic
return Ok();
}
}
IpCheckResult Properties
| Property | Type | Description |
|---|---|---|
IpAddress |
string |
The resolved client IP |
IsAllowed |
bool |
Whether the request passed all checks |
BlockReason |
string? |
Human-readable reason for blocking (null if allowed) |
Country |
string |
ISO 3166-1 alpha-2 code (e.g. "US") |
City |
string |
City name |
Region |
string |
Region / state |
Timezone |
string? |
IANA timezone (e.g. "America/New_York") |
Org |
string? |
ASN + ISP (e.g. "AS15169 Google LLC") |
IsVpn |
bool |
VPN detected |
IsProxy |
bool |
Proxy detected |
IsTor |
bool |
Tor exit node |
IsRelay |
bool |
iCloud Private Relay or similar |
IsHosting |
bool |
Datacenter / hosting IP |
IsBogon |
bool |
Special/reserved IP (loopback, private, etc.) |
GeoInfo |
IpInfoResponse? |
Raw geo data from IPinfo |
PrivacyInfo |
IpPrivacyResponse? |
Raw privacy data from IPinfo |
Using the Service Directly
For manual lookups outside the middleware (e.g. in a background job or controller action):
[ApiController]
[Route("api/[controller]")]
public class CheckController : ControllerBase
{
private readonly IIpGuardService _ipGuard;
public CheckController(IIpGuardService ipGuard) => _ipGuard = ipGuard;
[HttpGet("ip/{ip}")]
public async Task<IActionResult> CheckIp(string ip)
{
var result = await _ipGuard.CheckIpAsync(ip);
return Ok(result);
}
[HttpGet("geo/{ip}")]
public async Task<IActionResult> GetGeo(string ip)
{
var geo = await _ipGuard.GetGeoInfoAsync(ip);
return geo == null ? NotFound() : Ok(geo);
}
[HttpGet("privacy/{ip}")]
public async Task<IActionResult> GetPrivacy(string ip)
{
var privacy = await _ipGuard.GetPrivacyInfoAsync(ip);
return privacy == null ? NotFound() : Ok(privacy);
}
[HttpDelete("cache/{ip}")]
public IActionResult ClearCache(string ip)
{
_ipGuard.InvalidateCache(ip);
return NoContent();
}
}
Reverse Proxy / Cloudflare Setup
If your app runs behind Cloudflare, nginx, or a load balancer, configure the real IP headers:
{
"IpGuard": {
"RealIpHeaders": ["CF-Connecting-IP", "X-Forwarded-For", "X-Real-IP"]
}
}
Important: Only trust these headers from your own proxy. Clients can forge them. Use ASP.NET Core's
ForwardedHeadersmiddleware to validate the proxy chain first.
// Program.cs — Add BEFORE UseIpGuard
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});
app.UseIpGuard();
Combining with Cloudflare Country Blocking
For maximum security, use Cloudflare WAF (edge layer) + IpGuard (application layer):
| Layer | Tool | Blocks |
|---|---|---|
| Edge (CDN) | Cloudflare WAF → Firewall Rules → Country | High-level country blocks before hitting your server |
| Application | IpGuard | VPN/proxy bypass of Cloudflare, fine-grained control |
Disabling in Development
// appsettings.Development.json
{
"IpGuard": {
"Enabled": false
}
}
Or with environment-specific configuration:
builder.Services.AddIpGuard(options =>
{
options.ApiToken = builder.Configuration["IpGuard:ApiToken"]!;
options.Enabled = !builder.Environment.IsDevelopment();
options.RestrictedCountries = ["KP", "IR", "CU"];
options.BlockVpn = true;
});
IPinfo Plan Comparison
| Feature | Free | Basic | Standard | Business |
|---|---|---|---|---|
| Lookups/month | 50,000 | 150,000 | 500,000 | 3,000,000 |
| Geo-location | ✅ | ✅ | ✅ | ✅ |
| VPN/Proxy/Tor detection | ❌ | ❌ | ✅ | ✅ |
| Tor detection | ❌ | ❌ | ✅ | ✅ |
Sign up at ipinfo.io/pricing.
Publishing to NuGet
First time setup
- Create a NuGet account at nuget.org
- Generate an API key: Account → API Keys → Create
Pack and publish
# Build in Release mode
dotnet build -c Release
# Create the .nupkg
dotnet pack -c Release -o ./nupkg
# Publish to NuGet.org
dotnet nuget push ./nupkg/ArthaTech.IpGuard.1.0.0.nupkg \
--api-key YOUR_NUGET_API_KEY \
--source https://api.nuget.org/v3/index.json
Publish to a private feed (Azure Artifacts / GitHub Packages)
# Azure Artifacts
dotnet nuget push ./nupkg/*.nupkg \
--api-key az \
--source https://pkgs.dev.azure.com/{org}/{feed}/nuget/v3/index.json
# GitHub Packages
dotnet nuget push ./nupkg/*.nupkg \
--api-key YOUR_GITHUB_TOKEN \
--source https://nuget.pkg.github.com/{owner}/index.json
License
MIT © 2025 ArthaTech
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 is compatible. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net6.0
- Microsoft.Extensions.Caching.Memory (>= 8.0.1)
-
net7.0
- Microsoft.Extensions.Caching.Memory (>= 8.0.1)
-
net8.0
- Microsoft.Extensions.Caching.Memory (>= 8.0.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0 | 123 | 3/9/2026 |
v1.0.0 — Initial release.
- IPinfo geo-location API integration
- VPN, proxy, Tor, and hosting detection (requires IPinfo Privacy addon)
- Configurable restricted country list (ISO 3166-1 alpha-2)
- IP whitelist support
- In-memory result caching with configurable TTL
- Real IP resolution from X-Forwarded-For / CF-Connecting-IP / X-Real-IP
- Fail-open design: allows traffic if IPinfo is unreachable
- IpCheckResult available in HttpContext.Items for downstream use