Adaptive IP rate limiter with hierarchical pattern tracking (p2/p3 patterns) for in-memory rate limiting
npm install node-ip-rate-limiterAn adaptive IP rate limiter with hierarchical pattern tracking (p2/p3 patterns) for in-memory rate limiting. This package automatically detects patterns in IP addresses and applies rate limiting at different levels (single IP, /24 subnet, /16 network).
- Adaptive Rate Limiting: Automatically detects and groups IPs by patterns
- Hierarchical Pattern Tracking:
- Single IP: Individual IP address tracking
- P3 Pattern (/24 subnet): Groups IPs sharing the first 3 octets (e.g., 72.145.152.*)
- P2 Pattern (/16 network): Groups IPs sharing the first 2 octets (e.g., 72.145..)
- Pattern Count Tracking: Increments counts for both p3 and p2 patterns independently
- Automatic Promotion: IPs are automatically promoted to higher levels when patterns are detected
- In-Memory Storage: Fast, efficient in-memory storage with automatic expiration
- Zero Dependencies: No external dependencies required
``bash`
npm install node-ip-rate-limiter
`javascript
const { initRateLimiter, ipRateLimiting } = require('node-ip-rate-limiter');
// Initialize the rate limiter
initRateLimiter({
moduleName: 'my-api',
single: {
maxCount: 10, // Max requests per IP
expiryTime: 60000 // 60 seconds in milliseconds
},
p3Series: {
maxCount: 50, // Max requests per /24 subnet
expiryTime: 60000 // 60 seconds
},
p2Series: {
maxCount: 100, // Max requests per /16 network
expiryTime: 60000 // 60 seconds
}
});
// Check an IP address
const result = ipRateLimiting('72.145.152.42');
if (result.isDuplicate) {
console.log('Rate limit exceeded!');
console.log(result.reason);
} else {
console.log('Request allowed');
console.log(Current level: ${result.level});Count: ${result.count}
console.log();`
}
The rate limiter tracks IP addresses at three levels:
1. Single IP (72.145.152.42): Individual IP tracking72.145.152.*
2. P3 Pattern (): First 3 octets - /24 subnet72.145..
3. P2 Pattern (): First 2 octets - /16 network
When an IP is processed:
- The p3 count (first 3 octets) is incremented
- The p2 count (first 2 octets) is incremented
- Different p3 patterns under the same p2 are tracked separately
Example:
`
IP: 72.145.152.42
→ p3 pattern: 72.145.152 (count = 1)
→ p2 pattern: 72.145 (count = 1)
IP: 72.145.83.96
→ p3 pattern: 72.145.83 (count = 1) [new p3 pattern]
→ p2 pattern: 72.145 (count = 2) [incremented]
IP: 72.145.83.98
→ p3 pattern: 72.145.83 (count = 2) [incremented]
→ p2 pattern: 72.145 (count = 3) [incremented]
`
IPs are automatically promoted to higher rate limiting levels when patterns are detected:
- Single → P3: When 2+ IPs share the same /24 subnet
- Single → P2: When 2+ IPs share the same /16 network
- P3 → P2: When multiple /24 subnets are detected in the same /16 network
Once promoted, IPs stay at that level or higher (no demotion).
Initializes the rate limiter with configuration.
Parameters:
- config (Object): Configuration objectmoduleName
- (string): Unique name for this rate limiter instancesingle
- (Object): Configuration for single IP rate limitingmaxCount
- (number): Maximum number of requests allowedexpiryTime
- (number): Time in milliseconds before the limit resetsp3Series
- (Object): Configuration for /24 subnet rate limitingmaxCount
- (number): Maximum number of requests allowed per subnetexpiryTime
- (number): Time in milliseconds before the limit resetsp2Series
- (Object): Configuration for /16 network rate limitingmaxCount
- (number): Maximum number of requests allowed per networkexpiryTime
- (number): Time in milliseconds before the limit resets
Example:
`javascript`
initRateLimiter({
moduleName: 'api-server',
single: { maxCount: 100, expiryTime: 60000 },
p3Series: { maxCount: 500, expiryTime: 60000 },
p2Series: { maxCount: 1000, expiryTime: 60000 }
});
Checks if an IP address should be rate limited.
Parameters:
- ip (string): IPv4 address (e.g., "192.168.1.1")
Returns:
- Object: Rate limiting resultisDuplicate
- (boolean): true if rate limit exceeded, false otherwiselevel
- (string): Current rate limiting level ("single", "p3", or "p2")reason
- (string): Human-readable explanation of the resultcount
- (number): Current count at the current level
Example:
`javascript`
const result = ipRateLimiting('192.168.1.100');
// {
// isDuplicate: false,
// level: 'single',
// reason: 'Request allowed under the per-IP rate limit...',
// count: 1
// }
`javascript
const express = require('express');
const { initRateLimiter, ipRateLimiting } = require('node-ip-rate-limiter');
const app = express();
// Initialize rate limiter
initRateLimiter({
moduleName: 'express-api',
single: { maxCount: 100, expiryTime: 60000 },
p3Series: { maxCount: 500, expiryTime: 60000 },
p2Series: { maxCount: 1000, expiryTime: 60000 }
});
// Rate limiting middleware
function rateLimitMiddleware(req, res, next) {
const clientIP = req.ip || req.connection.remoteAddress;
const result = ipRateLimiting(clientIP);
if (result.isDuplicate) {
return res.status(429).json({
error: 'Rate limit exceeded',
reason: result.reason,
retryAfter: 60
});
}
// Add rate limit headers
res.setHeader('X-RateLimit-Level', result.level);
res.setHeader('X-RateLimit-Count', result.count);
next();
}
app.use(rateLimitMiddleware);
app.get('/api/data', (req, res) => {
res.json({ message: 'Success' });
});
app.listen(3000);
`
`javascript
const { initRateLimiter, ipRateLimiting } = require('node-ip-rate-limiter');
const fs = require('fs');
// Initialize
initRateLimiter({
moduleName: 'batch-processor',
single: { maxCount: 10, expiryTime: 60000 },
p3Series: { maxCount: 50, expiryTime: 60000 },
p2Series: { maxCount: 100, expiryTime: 60000 }
});
// Process IPs from file
const ips = JSON.parse(fs.readFileSync('ip_addresses.json', 'utf8'));
const results = [];
for (const ip of ips) {
const result = ipRateLimiting(ip);
results.push({ ip, ...result });
if (result.isDuplicate) {
console.log(Blocked: ${ip} - ${result.reason});
}
}
console.log(Processed ${results.length} IPs);`
javascript
{
isDuplicate: false,
level: 'single',
reason: 'Request allowed under the per-IP rate limit. The client is currently treated as a single IP.',
count: 1
}
`$3
`javascript
{
isDuplicate: false,
level: 'p3',
reason: 'Request allowed under the /24 subnet rate limit. Multiple IPs were detected in the same subnet and are sharing a common quota.',
count: 2
}
`$3
`javascript
{
isDuplicate: false,
level: 'p2',
reason: 'Request allowed under the /16 network rate limit. Traffic from a wider network is being grouped and rate-limited together.',
count: 3
}
`$3
`javascript
{
isDuplicate: true,
level: 'p3',
reason: 'Request blocked because the /24 subnet rate limit has been exceeded. Multiple IPs from the same subnet are sharing this quota.',
count: 6
}
``- In-Memory Only: This package uses in-memory storage. Data is lost on process restart.
- Single Process: Designed for single-process applications. For multi-process setups, consider using Redis or a shared storage solution.
- Automatic Cleanup: Expired entries are automatically cleaned up every 10 minutes.
- IPv4 Only: Currently supports IPv4 addresses only.
ISC
Mirabel Technologies
Contributions are welcome! Please feel free to submit a Pull Request.
For issues, questions, or contributions, please visit the npm package page.