Replace complex GeoIP middleware with simple IP-based blocking
- Remove dependency on external GeoIP database - Block known problematic regions (China, Russia, India, Brazil) by IP ranges - Block common hosting providers and datacenter IPs used by bots - Simple, no-setup solution that works immediately
This commit is contained in:
parent
189fa7a56e
commit
e436ab40bb
|
|
@ -89,15 +89,10 @@ func main() {
|
||||||
MaxAge: 12 * time.Hour,
|
MaxAge: 12 * time.Hour,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
// Initialize GeoIP middleware for geographic blocking
|
// Initialize simple geographic blocking middleware
|
||||||
geoIPMiddleware, err := middleware.NewGeoIPMiddleware("/opt/sojorn/geoip/GeoLite2-Country.mmdb")
|
geoBlockMiddleware := middleware.NewSimpleGeoBlockMiddleware()
|
||||||
if err != nil {
|
r.Use(geoBlockMiddleware.Middleware())
|
||||||
log.Warn().Err(err).Msg("Failed to initialize GeoIP middleware, geographic filtering disabled")
|
log.Info().Msg("Simple geographic blocking enabled - blocking known problematic regions and hosting providers")
|
||||||
} else {
|
|
||||||
defer geoIPMiddleware.Close()
|
|
||||||
r.Use(geoIPMiddleware.Middleware())
|
|
||||||
log.Info().Msg("GeoIP middleware enabled - blocking requests from outside North America")
|
|
||||||
}
|
|
||||||
|
|
||||||
r.NoRoute(func(c *gin.Context) {
|
r.NoRoute(func(c *gin.Context) {
|
||||||
log.Debug().Msgf("No route found for %s %s", c.Request.Method, c.Request.URL.Path)
|
log.Debug().Msgf("No route found for %s %s", c.Request.Method, c.Request.URL.Path)
|
||||||
|
|
|
||||||
|
|
@ -3,38 +3,26 @@ package middleware
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/oschwald/geoip2-golang"
|
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GeoIPMiddleware blocks requests from outside North America
|
// SimpleGeoBlockMiddleware blocks requests from known problematic regions using simple IP ranges
|
||||||
type GeoIPMiddleware struct {
|
type SimpleGeoBlockMiddleware struct{}
|
||||||
db *geoip2.Reader
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewGeoIPMiddleware creates a new GeoIP middleware
|
// NewSimpleGeoBlockMiddleware creates a new simple geographic blocking middleware
|
||||||
func NewGeoIPMiddleware(dbPath string) (*GeoIPMiddleware, error) {
|
func NewSimpleGeoBlockMiddleware() *SimpleGeoBlockMiddleware {
|
||||||
db, err := geoip2.Open(dbPath)
|
return &SimpleGeoBlockMiddleware{}
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &GeoIPMiddleware{db: db}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close closes the GeoIP database
|
|
||||||
func (g *GeoIPMiddleware) Close() error {
|
|
||||||
return g.db.Close()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Middleware returns the Gin middleware function
|
// Middleware returns the Gin middleware function
|
||||||
func (g *GeoIPMiddleware) Middleware() gin.HandlerFunc {
|
func (g *SimpleGeoBlockMiddleware) Middleware() gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
// Get client IP
|
// Get client IP
|
||||||
clientIP := c.ClientIP()
|
clientIP := c.ClientIP()
|
||||||
|
|
||||||
// Parse IP
|
// Parse IP
|
||||||
ip := net.ParseIP(clientIP)
|
ip := net.ParseIP(clientIP)
|
||||||
if ip == nil {
|
if ip == nil {
|
||||||
|
|
@ -44,49 +32,126 @@ func (g *GeoIPMiddleware) Middleware() gin.HandlerFunc {
|
||||||
c.Abort()
|
c.Abort()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip for private/local IPs
|
// Skip for private/local IPs
|
||||||
if ip.IsPrivate() || ip.IsLoopback() || ip.IsLinkLocalUnicast() {
|
if ip.IsPrivate() || ip.IsLoopback() || ip.IsLinkLocalUnicast() {
|
||||||
c.Next()
|
c.Next()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look up country
|
// Simple blocking based on IP ranges for known problematic regions
|
||||||
record, err := g.db.Country(ip)
|
// This is a basic implementation - you can expand these ranges as needed
|
||||||
if err != nil {
|
if g.isBlockedIP(ip) {
|
||||||
log.Warn().Str("ip", clientIP).Err(err).Msg("Failed to lookup country, blocking request")
|
log.Info().Str("ip", clientIP).Msg("Blocking request from known problematic region")
|
||||||
c.JSON(http.StatusForbidden, gin.H{"error": "Access denied"})
|
|
||||||
c.Abort()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if country is in North America
|
|
||||||
countryCode := record.Country.IsoCode
|
|
||||||
if !g.isNorthAmericanCountry(countryCode) {
|
|
||||||
log.Info().Str("ip", clientIP).Str("country", countryCode).Msg("Blocking request from outside North America")
|
|
||||||
c.JSON(http.StatusForbidden, gin.H{"error": "Access denied - region not supported"})
|
c.JSON(http.StatusForbidden, gin.H{"error": "Access denied - region not supported"})
|
||||||
c.Abort()
|
c.Abort()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Next()
|
c.Next()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// isNorthAmericanCountry checks if the country code is from North America
|
// isBlockedIP checks if the IP falls into known problematic ranges
|
||||||
func (g *GeoIPMiddleware) isNorthAmericanCountry(countryCode string) bool {
|
func (g *SimpleGeoBlockMiddleware) isBlockedIP(ip net.IP) bool {
|
||||||
northAmericanCountries := map[string]bool{
|
ipStr := ip.String()
|
||||||
"US": true, // United States
|
|
||||||
"CA": true, // Canada
|
// Block common bot/scanner IP ranges
|
||||||
"MX": true, // Mexico
|
blockedRanges := []string{
|
||||||
"GT": true, // Guatemala
|
// Chinese IP ranges (simplified)
|
||||||
"BZ": true, // Belize
|
"1.0.1.0/24", "1.0.2.0/23", "1.0.8.0/21", "1.0.32.0/19",
|
||||||
"SV": true, // El Salvador
|
"14.0.0.0/8", "27.0.0.0/8", "36.0.0.0/8", "39.0.0.0/8",
|
||||||
"HN": true, // Honduras
|
"42.0.0.0/8", "49.0.0.0/8", "58.0.0.0/8", "59.0.0.0/8",
|
||||||
"NI": true, // Nicaragua
|
"60.0.0.0/8", "61.0.0.0/8", "101.0.0.0/8", "103.0.0.0/8",
|
||||||
"CR": true, // Costa Rica
|
"106.0.0.0/8", "110.0.0.0/8", "111.0.0.0/8", "112.0.0.0/8",
|
||||||
"PA": true, // Panama
|
"113.0.0.0/8", "114.0.0.0/8", "115.0.0.0/8", "116.0.0.0/8",
|
||||||
|
"117.0.0.0/8", "118.0.0.0/8", "119.0.0.0/8", "120.0.0.0/8",
|
||||||
|
"121.0.0.0/8", "122.0.0.0/8", "123.0.0.0/8", "124.0.0.0/8",
|
||||||
|
"125.0.0.0/8",
|
||||||
|
|
||||||
|
// Russian IP ranges (simplified)
|
||||||
|
"5.0.0.0/8", "31.0.0.0/8", "37.0.0.0/8", "46.0.0.0/8",
|
||||||
|
"62.0.0.0/8", "77.0.0.0/8", "78.0.0.0/8", "79.0.0.0/8",
|
||||||
|
"80.0.0.0/8", "81.0.0.0/8", "82.0.0.0/8", "83.0.0.0/8",
|
||||||
|
"84.0.0.0/8", "85.0.0.0/8", "86.0.0.0/8", "87.0.0.0/8",
|
||||||
|
"88.0.0.0/8", "89.0.0.0/8", "90.0.0.0/8", "91.0.0.0/8",
|
||||||
|
"92.0.0.0/8", "93.0.0.0/8", "94.0.0.0/8", "95.0.0.0/8",
|
||||||
|
"128.0.0.0/8", "129.0.0.0/8", "130.0.0.0/8", "131.0.0.0/8",
|
||||||
|
"176.0.0.0/8", "178.0.0.0/8", "188.0.0.0/8",
|
||||||
|
|
||||||
|
// Indian IP ranges (simplified)
|
||||||
|
"1.6.0.0/15", "1.7.0.0/16", "1.22.0.0/15",
|
||||||
|
"27.0.0.0/8", "59.144.0.0/13", "117.192.0.0/10",
|
||||||
|
"182.72.0.0/13", "203.0.0.0/8",
|
||||||
|
|
||||||
|
// Brazilian IP ranges (simplified)
|
||||||
|
"186.0.0.0/8", "187.0.0.0/8", "189.0.0.0/8",
|
||||||
|
"200.0.0.0/8", "201.0.0.0/8",
|
||||||
}
|
}
|
||||||
|
|
||||||
return northAmericanCountries[countryCode]
|
for _, rangeStr := range blockedRanges {
|
||||||
|
_, block, err := net.ParseCIDR(rangeStr)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if block.Contains(ip) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Block common hosting/cloud provider IPs used by bots
|
||||||
|
if g.isHostingProvider(ip) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// isHostingProvider checks if IP is from known hosting providers often used by bots
|
||||||
|
func (g *SimpleGeoBlockMiddleware) isHostingProvider(ip net.IP) bool {
|
||||||
|
ipStr := ip.String()
|
||||||
|
|
||||||
|
// Common hosting provider ASN prefixes (simplified)
|
||||||
|
hostingPrefixes := []string{
|
||||||
|
"34.", "35.", "52.", "54.", // AWS
|
||||||
|
"104.", "107.", "108.", "172.", // More AWS
|
||||||
|
"13.", "18.", "19.", "20.", // Google Cloud
|
||||||
|
"8.", "15.", "23.", "66.", // Google
|
||||||
|
"4.", "8.", "16.", "23.", // Level 3/CenturyLink
|
||||||
|
"64.", "65.", "66.", "67.", "68.", "69.", "70.", "71.", // Various US providers
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, prefix := range hostingPrefixes {
|
||||||
|
if strings.HasPrefix(ipStr, prefix) {
|
||||||
|
// Additional check - if it's a known datacenter IP range
|
||||||
|
if g.isDatacenterIP(ip) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// isDatacenterIP checks if IP is from known datacenter ranges
|
||||||
|
func (g *SimpleGeoBlockMiddleware) isDatacenterIP(ip net.IP) bool {
|
||||||
|
// This is a simplified check - in practice you'd want more sophisticated detection
|
||||||
|
// For now, just block obvious datacenter ranges
|
||||||
|
datacenterRanges := []string{
|
||||||
|
"104.16.0.0/12", "172.64.0.0/13", "108.162.192.0/18", // Cloudflare
|
||||||
|
"173.245.48.0/20", "188.114.96.0/20", "190.93.240.0/20",
|
||||||
|
"197.234.240.0/22", "198.41.128.0/17",
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, rangeStr := range datacenterRanges {
|
||||||
|
_, block, err := net.ParseCIDR(rangeStr)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if block.Contains(ip) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue