blocky
blocky copied to clipboard
Feature Request: support upstream routing using geosite.dat
https://github.com/v2fly/domain-list-community
It works like:
- The
geosite.datfile path can be specified from configuration, likegeodata_path: /path/to/geosite.dat - The file will be loaded into RAM at runtime, and the protobuf encoded binary data will be decoded and prepared for matching.
- So we can reference it in the routing rules like
geosite:private -> upstream1, which means the query that contained ingeosite:privatewill be route to upstream1
Automatic updates will be better, but not the most important feature, update between restart is also acceptable.
import (
"context"
"net"
"strings"
"time"
"github.com/0xERR0R/blocky/config"
"github.com/0xERR0R/blocky/geosite"
"github.com/0xERR0R/blocky/log"
"github.com/miekg/dns"
)
type BlockingResolver struct {
config *config.Blocking
geositeManager *geosite.GeositeManager
// ...
}
func NewBlockingResolver(cfg *config.Config, geositeManager *geosite.GeositeManager) *BlockingResolver {
return &BlockingResolver{
config: &cfg.Blocking,
geositeManager: geositeManager,
// ...
}
}
func (r *BlockingResolver) Resolve(ctx context.Context, request *Request) (response *Response, err error) {
logger := log.LoggerFromContext(ctx).WithFields(log.Fields{
"client_ip": request.ClientIP,
"client_name": request.ClientNames,
"question": request.Req.Question[0].Name,
})
queryDomain := strings.TrimSuffix(request.Req.Question[0].Name, ".")
// Check nxDomainDomains first
for _, nxDomain := range r.config.NxDomainDomains {
if strings.EqualFold(queryDomain, nxDomain) {
logger.Info("returning NXDOMAIN for domain in nxDomainDomains")
resp := new(dns.Msg)
resp.SetRcode(request.Req, dns.RcodeNameError)
return &Response{Res: resp, RType: BLOCKED, Reason: "NXDOMAIN override"}, nil
}
}
// Check blacklists (including geosite: rules)
clientNames := r.clientLookup.GetClientNames(request.ClientIP)
blockGroups := r.getBlockGroups(clientNames)
isBlocked := false
var reason string
for _, group := range blockGroups {
for _, list := range r.config.BlackLists[group] {
if strings.HasPrefix(list, "geosite:") {
category := strings.TrimPrefix(list, "geosite:")
if r.geositeManager.Match(queryDomain, category) {
isBlocked = true
reason = fmt.Sprintf("Blocked by geosite:%s", category)
break
}
} else if r.isBlocked(queryDomain, list) {
isBlocked = true
reason = fmt.Sprintf("Blocked by group: %s", group)
break
}
}
if isBlocked {
break
}
}
if !isBlocked {
return r.next.Resolve(ctx, request)
}
// Apply blockType
resp := new(dns.Msg)
if r.config.BlockType == "nxDomain" {
resp.SetRcode(request.Req, dns.RcodeNameError)
} else {
resp.SetReply(request.Req)
if request.Req.Question[0].Qtype == dns.TypeA {
resp.Answer = []dns.RR{&dns.A{
Hdr: dns.RR_Header{Name: request.Req.Question[0].Name, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: uint32(r.config.BlockTTL / time.Second)},
A: net.ParseIP("0.0.0.0"),
}}
} else if request.Req.Question[0].Qtype == dns.TypeAAAA {
resp.Answer = []dns.RR{&dns.AAAA{
Hdr: dns.RR_Header{Name: request.Req.Question[0].Name, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: uint32(r.config.BlockTTL / time.Second)},
AAAA: net.ParseIP("::"),
}}
}
}
return &Response{Res: resp, RType: BLOCKED, Reason: reason}, nil
}
This issue is stale because it has been open 90 days with no activity. Remove stale label or comment or this will be closed in 5 days.
This issue was closed because it has been stalled for 5 days with no activity.