Add resolver for inbound

This commit is contained in:
世界
2022-07-07 23:36:32 +08:00
parent 538a1f5909
commit 9c256afc1a
22 changed files with 261 additions and 173 deletions

View File

@@ -56,6 +56,7 @@ type Router struct {
dnsClient adapter.DNSClient
defaultDomainStrategy C.DomainStrategy
dnsRules []adapter.Rule
defaultTransport adapter.DNSTransport
transports []adapter.DNSTransport
@@ -69,9 +70,11 @@ func NewRouter(ctx context.Context, logger log.Logger, options option.RouteOptio
dnsLogger: logger.WithPrefix("dns: "),
outboundByTag: make(map[string]adapter.Outbound),
rules: make([]adapter.Rule, 0, len(options.Rules)),
dnsRules: make([]adapter.Rule, 0, len(dnsOptions.Rules)),
needGeoIPDatabase: hasGeoRule(options.Rules, isGeoIPRule) || hasGeoDNSRule(dnsOptions.Rules, isGeoIPDNSRule),
needGeositeDatabase: hasGeoRule(options.Rules, isGeositeRule) || hasGeoDNSRule(dnsOptions.Rules, isGeositeDNSRule),
geoIPOptions: common.PtrValueOrDefault(options.GeoIP),
geositeOptions: common.PtrValueOrDefault(options.Geosite),
defaultDetour: options.Final,
dnsClient: dns.NewClient(dnsOptions.DNSClientOptions),
defaultDomainStrategy: C.DomainStrategy(dnsOptions.Strategy),
@@ -88,7 +91,7 @@ func NewRouter(ctx context.Context, logger log.Logger, options option.RouteOptio
if err != nil {
return nil, E.Cause(err, "parse dns rule[", i, "]")
}
router.rules = append(router.rules, dnsRule)
router.dnsRules = append(router.dnsRules, dnsRule)
}
transports := make([]adapter.DNSTransport, len(dnsOptions.Servers))
dummyTransportMap := make(map[string]adapter.DNSTransport)
@@ -259,6 +262,12 @@ func (r *Router) Start() error {
return err
}
}
for _, rule := range r.dnsRules {
err := rule.Start()
if err != nil {
return err
}
}
if r.needGeositeDatabase {
for _, rule := range r.rules {
err := rule.UpdateGeosite()
@@ -266,6 +275,12 @@ func (r *Router) Start() error {
r.logger.Error("failed to initialize geosite: ", err)
}
}
for _, rule := range r.dnsRules {
err := rule.UpdateGeosite()
if err != nil {
r.logger.Error("failed to initialize geosite: ", err)
}
}
err := common.Close(r.geositeReader)
if err != nil {
return err
@@ -275,6 +290,18 @@ func (r *Router) Start() error {
}
func (r *Router) Close() error {
for _, rule := range r.rules {
err := rule.Close()
if err != nil {
return err
}
}
for _, rule := range r.dnsRules {
err := rule.Close()
if err != nil {
return err
}
}
return common.Close(
common.PtrOrNil(r.geoIPReader),
)
@@ -325,12 +352,20 @@ func (r *Router) RouteConnection(ctx context.Context, conn net.Conn, metadata ad
conn = bufio.NewCachedConn(conn, buffer)
}
}
if metadata.Destination.IsFqdn() && metadata.DomainStrategy != C.DomainStrategyAsIS {
addresses, err := r.Lookup(adapter.WithContext(ctx, &metadata), metadata.Destination.Fqdn, metadata.DomainStrategy)
if err != nil {
return err
}
metadata.DestinationAddresses = addresses
r.dnsLogger.WithContext(ctx).Info("resolved [", strings.Join(common.Map(metadata.DestinationAddresses, F.ToString0[netip.Addr]), " "), "]")
}
detour := r.match(ctx, metadata, r.defaultOutboundForConnection)
if !common.Contains(detour.Network(), C.NetworkTCP) {
conn.Close()
return E.New("missing supported outbound, closing connection")
}
return detour.NewConnection(adapter.WithContext(ctx, &metadata), conn, metadata.Destination)
return detour.NewConnection(ctx, conn, metadata)
}
func (r *Router) RoutePacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
@@ -359,12 +394,20 @@ func (r *Router) RoutePacketConnection(ctx context.Context, conn N.PacketConn, m
}
conn = bufio.NewCachedPacketConn(conn, buffer, originDestination)
}
if metadata.Destination.IsFqdn() && metadata.DomainStrategy != C.DomainStrategyAsIS {
addresses, err := r.Lookup(adapter.WithContext(ctx, &metadata), metadata.Destination.Fqdn, metadata.DomainStrategy)
if err != nil {
return err
}
metadata.DestinationAddresses = addresses
r.dnsLogger.WithContext(ctx).Info("resolved [", strings.Join(common.Map(metadata.DestinationAddresses, F.ToString0[netip.Addr]), " "), "]")
}
detour := r.match(ctx, metadata, r.defaultOutboundForPacketConnection)
if !common.Contains(detour.Network(), C.NetworkUDP) {
conn.Close()
return E.New("missing supported outbound, closing packet connection")
}
return detour.NewPacketConnection(adapter.WithContext(ctx, &metadata), conn, metadata.Destination)
return detour.NewPacketConnection(ctx, conn, metadata)
}
func (r *Router) Exchange(ctx context.Context, message *dnsmessage.Message) (*dnsmessage.Message, error) {
@@ -397,10 +440,10 @@ func (r *Router) match(ctx context.Context, metadata adapter.InboundContext, def
func (r *Router) matchDNS(ctx context.Context) adapter.DNSTransport {
metadata := adapter.ContextFrom(ctx)
if metadata == nil {
r.dnsLogger.WithContext(ctx).Info("no context")
r.dnsLogger.WithContext(ctx).Warn("no context")
return r.defaultTransport
}
for i, rule := range r.rules {
for i, rule := range r.dnsRules {
if rule.Match(metadata) {
detour := rule.Outbound()
r.dnsLogger.WithContext(ctx).Info("match[", i, "] ", rule.String(), " => ", detour)

View File

@@ -41,12 +41,19 @@ func (r *IPCIDRItem) Match(metadata *adapter.InboundContext) bool {
}
}
} else {
if metadata.Destination.IsFqdn() {
return false
}
for _, prefix := range r.prefixes {
if prefix.Contains(metadata.Destination.Addr) {
return true
if metadata.Destination.IsIP() {
for _, prefix := range r.prefixes {
if prefix.Contains(metadata.Destination.Addr) {
return true
}
}
} else {
for _, address := range metadata.DestinationAddresses {
for _, prefix := range r.prefixes {
if prefix.Contains(address) {
return true
}
}
}
}
}

View File

@@ -3,8 +3,6 @@ package route
import (
"strings"
N "github.com/sagernet/sing/common/network"
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/log"
)
@@ -36,41 +34,26 @@ func NewGeoIPItem(router adapter.Router, logger log.Logger, isSource bool, codes
func (r *GeoIPItem) Match(metadata *adapter.InboundContext) bool {
geoReader := r.router.GeoIPReader()
if geoReader == nil {
return r.match(metadata)
return false
}
if r.isSource {
if metadata.SourceGeoIPCode == "" {
metadata.SourceGeoIPCode = geoReader.Lookup(metadata.Source.Addr)
}
} else {
if metadata.Destination.IsFqdn() {
return false
}
if metadata.GeoIPCode == "" {
metadata.GeoIPCode = geoReader.Lookup(metadata.Destination.Addr)
}
}
return r.match(metadata)
}
func (r *GeoIPItem) match(metadata *adapter.InboundContext) bool {
if r.isSource {
if metadata.SourceGeoIPCode == "" {
if !N.IsPublicAddr(metadata.Source.Addr) {
metadata.SourceGeoIPCode = "private"
}
}
return r.codeMap[metadata.SourceGeoIPCode]
} else {
if metadata.Destination.IsFqdn() {
return false
if metadata.Destination.IsIP() {
if metadata.GeoIPCode == "" {
metadata.GeoIPCode = geoReader.Lookup(metadata.Destination.Addr)
}
return r.codeMap[metadata.GeoIPCode]
}
if metadata.GeoIPCode == "" {
if !N.IsPublicAddr(metadata.Destination.Addr) {
metadata.GeoIPCode = "private"
for _, address := range metadata.DestinationAddresses {
if r.codeMap[geoReader.Lookup(address)] {
return true
}
}
return r.codeMap[metadata.GeoIPCode]
return false
}
}