| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248 |
- package rule
- import (
- "net/netip"
- "os"
- "strings"
- "syscall"
- "time"
- "github.com/sagernet/sing-box/adapter"
- "github.com/sagernet/sing-box/common/sniff"
- C "github.com/sagernet/sing-box/constant"
- "github.com/sagernet/sing-box/option"
- "github.com/sagernet/sing-dns"
- "github.com/sagernet/sing-tun"
- E "github.com/sagernet/sing/common/exceptions"
- F "github.com/sagernet/sing/common/format"
- )
- func NewRuleAction(action option.RuleAction) (adapter.RuleAction, error) {
- switch action.Action {
- case C.RuleActionTypeRoute:
- return &RuleActionRoute{
- Outbound: action.RouteOptions.Outbound,
- UDPDisableDomainUnmapping: action.RouteOptions.UDPDisableDomainUnmapping,
- }, nil
- case C.RuleActionTypeReturn:
- return &RuleActionReturn{}, nil
- case C.RuleActionTypeReject:
- return &RuleActionReject{
- Method: action.RejectOptions.Method,
- }, nil
- case C.RuleActionTypeHijackDNS:
- return &RuleActionHijackDNS{}, nil
- case C.RuleActionTypeSniff:
- sniffAction := &RuleActionSniff{
- snifferNames: action.SniffOptions.Sniffer,
- Timeout: time.Duration(action.SniffOptions.Timeout),
- }
- return sniffAction, sniffAction.build()
- case C.RuleActionTypeResolve:
- return &RuleActionResolve{
- Strategy: dns.DomainStrategy(action.ResolveOptions.Strategy),
- Server: action.ResolveOptions.Server,
- }, nil
- default:
- panic(F.ToString("unknown rule action: ", action.Action))
- }
- }
- func NewDNSRuleAction(action option.DNSRuleAction) adapter.RuleAction {
- switch action.Action {
- case C.RuleActionTypeRoute:
- return &RuleActionDNSRoute{
- Server: action.RouteOptions.Server,
- DisableCache: action.RouteOptions.DisableCache,
- RewriteTTL: action.RouteOptions.RewriteTTL,
- ClientSubnet: action.RouteOptions.ClientSubnet.Build(),
- }
- case C.RuleActionTypeReturn:
- return &RuleActionReturn{}
- case C.RuleActionTypeReject:
- return &RuleActionReject{
- Method: action.RejectOptions.Method,
- }
- default:
- panic(F.ToString("unknown rule action: ", action.Action))
- }
- }
- type RuleActionRoute struct {
- Outbound string
- UDPDisableDomainUnmapping bool
- }
- func (r *RuleActionRoute) Type() string {
- return C.RuleActionTypeRoute
- }
- func (r *RuleActionRoute) String() string {
- return F.ToString("route(", r.Outbound, ")")
- }
- type RuleActionDNSRoute struct {
- Server string
- DisableCache bool
- RewriteTTL *uint32
- ClientSubnet netip.Prefix
- }
- func (r *RuleActionDNSRoute) Type() string {
- return C.RuleActionTypeRoute
- }
- func (r *RuleActionDNSRoute) String() string {
- return F.ToString("route(", r.Server, ")")
- }
- type RuleActionReturn struct{}
- func (r *RuleActionReturn) Type() string {
- return C.RuleActionTypeReturn
- }
- func (r *RuleActionReturn) String() string {
- return "return"
- }
- type RuleActionReject struct {
- Method string
- }
- func (r *RuleActionReject) Type() string {
- return C.RuleActionTypeReject
- }
- func (r *RuleActionReject) String() string {
- if r.Method == C.RuleActionRejectMethodDefault {
- return "reject"
- }
- return F.ToString("reject(", r.Method, ")")
- }
- func (r *RuleActionReject) Error() error {
- switch r.Method {
- case C.RuleActionRejectMethodReset:
- return os.ErrClosed
- case C.RuleActionRejectMethodNetworkUnreachable:
- return syscall.ENETUNREACH
- case C.RuleActionRejectMethodHostUnreachable:
- return syscall.EHOSTUNREACH
- case C.RuleActionRejectMethodDefault, C.RuleActionRejectMethodPortUnreachable:
- return syscall.ECONNREFUSED
- case C.RuleActionRejectMethodDrop:
- return tun.ErrDrop
- default:
- panic(F.ToString("unknown reject method: ", r.Method))
- }
- }
- type RuleActionHijackDNS struct{}
- func (r *RuleActionHijackDNS) Type() string {
- return C.RuleActionTypeHijackDNS
- }
- func (r *RuleActionHijackDNS) String() string {
- return "hijack-dns"
- }
- type RuleActionSniff struct {
- snifferNames []string
- StreamSniffers []sniff.StreamSniffer
- PacketSniffers []sniff.PacketSniffer
- Timeout time.Duration
- // Deprecated
- OverrideDestination bool
- }
- func (r *RuleActionSniff) Type() string {
- return C.RuleActionTypeSniff
- }
- func (r *RuleActionSniff) build() error {
- if len(r.StreamSniffers) > 0 || len(r.PacketSniffers) > 0 {
- return nil
- }
- if len(r.snifferNames) > 0 {
- for _, name := range r.snifferNames {
- switch name {
- case C.ProtocolTLS:
- r.StreamSniffers = append(r.StreamSniffers, sniff.TLSClientHello)
- case C.ProtocolHTTP:
- r.StreamSniffers = append(r.StreamSniffers, sniff.HTTPHost)
- case C.ProtocolQUIC:
- r.PacketSniffers = append(r.PacketSniffers, sniff.QUICClientHello)
- case C.ProtocolDNS:
- r.StreamSniffers = append(r.StreamSniffers, sniff.StreamDomainNameQuery)
- r.PacketSniffers = append(r.PacketSniffers, sniff.DomainNameQuery)
- case C.ProtocolSTUN:
- r.PacketSniffers = append(r.PacketSniffers, sniff.STUNMessage)
- case C.ProtocolBitTorrent:
- r.StreamSniffers = append(r.StreamSniffers, sniff.BitTorrent)
- r.PacketSniffers = append(r.PacketSniffers, sniff.UTP)
- r.PacketSniffers = append(r.PacketSniffers, sniff.UDPTracker)
- case C.ProtocolDTLS:
- r.PacketSniffers = append(r.PacketSniffers, sniff.DTLSRecord)
- case C.ProtocolSSH:
- r.StreamSniffers = append(r.StreamSniffers, sniff.SSH)
- case C.ProtocolRDP:
- r.StreamSniffers = append(r.StreamSniffers, sniff.RDP)
- default:
- return E.New("unknown sniffer: ", name)
- }
- }
- } else {
- r.StreamSniffers = []sniff.StreamSniffer{
- sniff.TLSClientHello,
- sniff.HTTPHost,
- sniff.StreamDomainNameQuery,
- sniff.BitTorrent,
- sniff.SSH,
- sniff.RDP,
- }
- r.PacketSniffers = []sniff.PacketSniffer{
- sniff.DomainNameQuery,
- sniff.QUICClientHello,
- sniff.STUNMessage,
- sniff.UTP,
- sniff.UDPTracker,
- sniff.DTLSRecord,
- }
- }
- return nil
- }
- func (r *RuleActionSniff) String() string {
- if len(r.snifferNames) == 0 && r.Timeout == 0 {
- return "sniff"
- } else if len(r.snifferNames) > 0 && r.Timeout == 0 {
- return F.ToString("sniff(", strings.Join(r.snifferNames, ","), ")")
- } else if len(r.snifferNames) == 0 && r.Timeout > 0 {
- return F.ToString("sniff(", r.Timeout.String(), ")")
- } else {
- return F.ToString("sniff(", strings.Join(r.snifferNames, ","), ",", r.Timeout.String(), ")")
- }
- }
- type RuleActionResolve struct {
- Strategy dns.DomainStrategy
- Server string
- }
- func (r *RuleActionResolve) Type() string {
- return C.RuleActionTypeResolve
- }
- func (r *RuleActionResolve) String() string {
- if r.Strategy == dns.DomainStrategyAsIS && r.Server == "" {
- return F.ToString("resolve")
- } else if r.Strategy != dns.DomainStrategyAsIS && r.Server == "" {
- return F.ToString("resolve(", option.DomainStrategy(r.Strategy).String(), ")")
- } else if r.Strategy == dns.DomainStrategyAsIS && r.Server != "" {
- return F.ToString("resolve(", r.Server, ")")
- } else {
- return F.ToString("resolve(", option.DomainStrategy(r.Strategy).String(), ",", r.Server, ")")
- }
- }
|