rule_action.go 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. package rule
  2. import (
  3. "net/netip"
  4. "os"
  5. "strings"
  6. "syscall"
  7. "time"
  8. "github.com/sagernet/sing-box/adapter"
  9. "github.com/sagernet/sing-box/common/sniff"
  10. C "github.com/sagernet/sing-box/constant"
  11. "github.com/sagernet/sing-box/option"
  12. "github.com/sagernet/sing-dns"
  13. "github.com/sagernet/sing-tun"
  14. E "github.com/sagernet/sing/common/exceptions"
  15. F "github.com/sagernet/sing/common/format"
  16. )
  17. func NewRuleAction(action option.RuleAction) (adapter.RuleAction, error) {
  18. switch action.Action {
  19. case C.RuleActionTypeRoute:
  20. return &RuleActionRoute{
  21. Outbound: action.RouteOptions.Outbound,
  22. UDPDisableDomainUnmapping: action.RouteOptions.UDPDisableDomainUnmapping,
  23. }, nil
  24. case C.RuleActionTypeReturn:
  25. return &RuleActionReturn{}, nil
  26. case C.RuleActionTypeReject:
  27. return &RuleActionReject{
  28. Method: action.RejectOptions.Method,
  29. }, nil
  30. case C.RuleActionTypeHijackDNS:
  31. return &RuleActionHijackDNS{}, nil
  32. case C.RuleActionTypeSniff:
  33. sniffAction := &RuleActionSniff{
  34. snifferNames: action.SniffOptions.Sniffer,
  35. Timeout: time.Duration(action.SniffOptions.Timeout),
  36. }
  37. return sniffAction, sniffAction.build()
  38. case C.RuleActionTypeResolve:
  39. return &RuleActionResolve{
  40. Strategy: dns.DomainStrategy(action.ResolveOptions.Strategy),
  41. Server: action.ResolveOptions.Server,
  42. }, nil
  43. default:
  44. panic(F.ToString("unknown rule action: ", action.Action))
  45. }
  46. }
  47. func NewDNSRuleAction(action option.DNSRuleAction) adapter.RuleAction {
  48. switch action.Action {
  49. case C.RuleActionTypeRoute:
  50. return &RuleActionDNSRoute{
  51. Server: action.RouteOptions.Server,
  52. DisableCache: action.RouteOptions.DisableCache,
  53. RewriteTTL: action.RouteOptions.RewriteTTL,
  54. ClientSubnet: action.RouteOptions.ClientSubnet.Build(),
  55. }
  56. case C.RuleActionTypeReturn:
  57. return &RuleActionReturn{}
  58. case C.RuleActionTypeReject:
  59. return &RuleActionReject{
  60. Method: action.RejectOptions.Method,
  61. }
  62. default:
  63. panic(F.ToString("unknown rule action: ", action.Action))
  64. }
  65. }
  66. type RuleActionRoute struct {
  67. Outbound string
  68. UDPDisableDomainUnmapping bool
  69. }
  70. func (r *RuleActionRoute) Type() string {
  71. return C.RuleActionTypeRoute
  72. }
  73. func (r *RuleActionRoute) String() string {
  74. return F.ToString("route(", r.Outbound, ")")
  75. }
  76. type RuleActionDNSRoute struct {
  77. Server string
  78. DisableCache bool
  79. RewriteTTL *uint32
  80. ClientSubnet netip.Prefix
  81. }
  82. func (r *RuleActionDNSRoute) Type() string {
  83. return C.RuleActionTypeRoute
  84. }
  85. func (r *RuleActionDNSRoute) String() string {
  86. return F.ToString("route(", r.Server, ")")
  87. }
  88. type RuleActionReturn struct{}
  89. func (r *RuleActionReturn) Type() string {
  90. return C.RuleActionTypeReturn
  91. }
  92. func (r *RuleActionReturn) String() string {
  93. return "return"
  94. }
  95. type RuleActionReject struct {
  96. Method string
  97. }
  98. func (r *RuleActionReject) Type() string {
  99. return C.RuleActionTypeReject
  100. }
  101. func (r *RuleActionReject) String() string {
  102. if r.Method == C.RuleActionRejectMethodDefault {
  103. return "reject"
  104. }
  105. return F.ToString("reject(", r.Method, ")")
  106. }
  107. func (r *RuleActionReject) Error() error {
  108. switch r.Method {
  109. case C.RuleActionRejectMethodReset:
  110. return os.ErrClosed
  111. case C.RuleActionRejectMethodNetworkUnreachable:
  112. return syscall.ENETUNREACH
  113. case C.RuleActionRejectMethodHostUnreachable:
  114. return syscall.EHOSTUNREACH
  115. case C.RuleActionRejectMethodDefault, C.RuleActionRejectMethodPortUnreachable:
  116. return syscall.ECONNREFUSED
  117. case C.RuleActionRejectMethodDrop:
  118. return tun.ErrDrop
  119. default:
  120. panic(F.ToString("unknown reject method: ", r.Method))
  121. }
  122. }
  123. type RuleActionHijackDNS struct{}
  124. func (r *RuleActionHijackDNS) Type() string {
  125. return C.RuleActionTypeHijackDNS
  126. }
  127. func (r *RuleActionHijackDNS) String() string {
  128. return "hijack-dns"
  129. }
  130. type RuleActionSniff struct {
  131. snifferNames []string
  132. StreamSniffers []sniff.StreamSniffer
  133. PacketSniffers []sniff.PacketSniffer
  134. Timeout time.Duration
  135. // Deprecated
  136. OverrideDestination bool
  137. }
  138. func (r *RuleActionSniff) Type() string {
  139. return C.RuleActionTypeSniff
  140. }
  141. func (r *RuleActionSniff) build() error {
  142. if len(r.StreamSniffers) > 0 || len(r.PacketSniffers) > 0 {
  143. return nil
  144. }
  145. if len(r.snifferNames) > 0 {
  146. for _, name := range r.snifferNames {
  147. switch name {
  148. case C.ProtocolTLS:
  149. r.StreamSniffers = append(r.StreamSniffers, sniff.TLSClientHello)
  150. case C.ProtocolHTTP:
  151. r.StreamSniffers = append(r.StreamSniffers, sniff.HTTPHost)
  152. case C.ProtocolQUIC:
  153. r.PacketSniffers = append(r.PacketSniffers, sniff.QUICClientHello)
  154. case C.ProtocolDNS:
  155. r.StreamSniffers = append(r.StreamSniffers, sniff.StreamDomainNameQuery)
  156. r.PacketSniffers = append(r.PacketSniffers, sniff.DomainNameQuery)
  157. case C.ProtocolSTUN:
  158. r.PacketSniffers = append(r.PacketSniffers, sniff.STUNMessage)
  159. case C.ProtocolBitTorrent:
  160. r.StreamSniffers = append(r.StreamSniffers, sniff.BitTorrent)
  161. r.PacketSniffers = append(r.PacketSniffers, sniff.UTP)
  162. r.PacketSniffers = append(r.PacketSniffers, sniff.UDPTracker)
  163. case C.ProtocolDTLS:
  164. r.PacketSniffers = append(r.PacketSniffers, sniff.DTLSRecord)
  165. case C.ProtocolSSH:
  166. r.StreamSniffers = append(r.StreamSniffers, sniff.SSH)
  167. case C.ProtocolRDP:
  168. r.StreamSniffers = append(r.StreamSniffers, sniff.RDP)
  169. default:
  170. return E.New("unknown sniffer: ", name)
  171. }
  172. }
  173. } else {
  174. r.StreamSniffers = []sniff.StreamSniffer{
  175. sniff.TLSClientHello,
  176. sniff.HTTPHost,
  177. sniff.StreamDomainNameQuery,
  178. sniff.BitTorrent,
  179. sniff.SSH,
  180. sniff.RDP,
  181. }
  182. r.PacketSniffers = []sniff.PacketSniffer{
  183. sniff.DomainNameQuery,
  184. sniff.QUICClientHello,
  185. sniff.STUNMessage,
  186. sniff.UTP,
  187. sniff.UDPTracker,
  188. sniff.DTLSRecord,
  189. }
  190. }
  191. return nil
  192. }
  193. func (r *RuleActionSniff) String() string {
  194. if len(r.snifferNames) == 0 && r.Timeout == 0 {
  195. return "sniff"
  196. } else if len(r.snifferNames) > 0 && r.Timeout == 0 {
  197. return F.ToString("sniff(", strings.Join(r.snifferNames, ","), ")")
  198. } else if len(r.snifferNames) == 0 && r.Timeout > 0 {
  199. return F.ToString("sniff(", r.Timeout.String(), ")")
  200. } else {
  201. return F.ToString("sniff(", strings.Join(r.snifferNames, ","), ",", r.Timeout.String(), ")")
  202. }
  203. }
  204. type RuleActionResolve struct {
  205. Strategy dns.DomainStrategy
  206. Server string
  207. }
  208. func (r *RuleActionResolve) Type() string {
  209. return C.RuleActionTypeResolve
  210. }
  211. func (r *RuleActionResolve) String() string {
  212. if r.Strategy == dns.DomainStrategyAsIS && r.Server == "" {
  213. return F.ToString("resolve")
  214. } else if r.Strategy != dns.DomainStrategyAsIS && r.Server == "" {
  215. return F.ToString("resolve(", option.DomainStrategy(r.Strategy).String(), ")")
  216. } else if r.Strategy == dns.DomainStrategyAsIS && r.Server != "" {
  217. return F.ToString("resolve(", r.Server, ")")
  218. } else {
  219. return F.ToString("resolve(", option.DomainStrategy(r.Strategy).String(), ",", r.Server, ")")
  220. }
  221. }