Projects STRLCPY sing-box Commits 9092139e
🤬
Revision indexing in progress... (symbol navigation in revisions will be accurate after indexed)
  • ■ ■ ■ ■
    adapter/inbound.go
    skipped 26 lines
    27 27  type InboundContext struct {
    28 28   Inbound string
    29 29   InboundType string
    30  - IPVersion int
     30 + IPVersion uint8
    31 31   Network string
    32 32   Source M.Socksaddr
    33 33   Destination M.Socksaddr
    skipped 44 lines
  • ■ ■ ■ ■ ■ ■
    adapter/outbound.go
    skipped 3 lines
    4 4   "context"
    5 5   "net"
    6 6   
     7 + tun "github.com/sagernet/sing-tun"
    7 8   N "github.com/sagernet/sing/common/network"
    8 9  )
    9 10   
    skipped 8 lines
    18 19   NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata InboundContext) error
    19 20  }
    20 21   
     22 +type IPOutbound interface {
     23 + Outbound
     24 + NewIPConnection(ctx context.Context, conn tun.RouteContext, metadata InboundContext) (tun.DirectDestination, error)
     25 +}
     26 + 
  • ■ ■ ■ ■ ■ ■
    adapter/router.go
    skipped 22 lines
    23 23   
    24 24   RouteConnection(ctx context.Context, conn net.Conn, metadata InboundContext) error
    25 25   RoutePacketConnection(ctx context.Context, conn N.PacketConn, metadata InboundContext) error
     26 + RouteIPConnection(ctx context.Context, conn tun.RouteContext, metadata InboundContext) tun.RouteAction
     27 + 
     28 + NatRequired(outbound string) bool
    26 29   
    27 30   GeoIPReader() *geoip.Reader
    28 31   LoadGeosite(code string) (Rule, error)
    skipped 10 lines
    39 42   NetworkMonitor() tun.NetworkUpdateMonitor
    40 43   InterfaceMonitor() tun.DefaultInterfaceMonitor
    41 44   PackageManager() tun.PackageManager
     45 + 
    42 46   Rules() []Rule
     47 + IPRules() []IPRule
    43 48   
    44 49   TimeService
    45 50   
    skipped 30 lines
    76 81  type DNSRule interface {
    77 82   Rule
    78 83   DisableCache() bool
     84 +}
     85 + 
     86 +type IPRule interface {
     87 + Rule
     88 + Action() tun.ActionType
    79 89  }
    80 90   
    81 91  type InterfaceUpdateListener interface {
    skipped 3 lines
  • ■ ■ ■ ■ ■ ■
    box.go
    skipped 237 lines
    238 238   
    239 239  func (s *Box) preStart() error {
    240 240   for serviceName, service := range s.preServices {
     241 + s.logger.Trace("pre-starting ", serviceName)
    241 242   err := adapter.PreStart(service)
    242 243   if err != nil {
    243 244   return E.Cause(err, "pre-start ", serviceName)
    skipped 1 lines
    245 246   }
    246 247   for i, out := range s.outbounds {
    247 248   if starter, isStarter := out.(common.Starter); isStarter {
     249 + var tag string
     250 + if out.Tag() == "" {
     251 + tag = F.ToString(i)
     252 + } else {
     253 + tag = out.Tag()
     254 + }
     255 + s.logger.Trace("initializing outbound ", tag)
    248 256   err := starter.Start()
    249 257   if err != nil {
    250  - var tag string
    251  - if out.Tag() == "" {
    252  - tag = F.ToString(i)
    253  - } else {
    254  - tag = out.Tag()
    255  - }
    256 258   return E.Cause(err, "initialize outbound/", out.Type(), "[", tag, "]")
    257 259   }
    258 260   }
    skipped 7 lines
    266 268   return err
    267 269   }
    268 270   for serviceName, service := range s.preServices {
     271 + s.logger.Trace("starting ", serviceName)
    269 272   err = service.Start()
    270 273   if err != nil {
    271 274   return E.Cause(err, "start ", serviceName)
    272 275   }
    273 276   }
    274 277   for i, in := range s.inbounds {
     278 + var tag string
     279 + if in.Tag() == "" {
     280 + tag = F.ToString(i)
     281 + } else {
     282 + tag = in.Tag()
     283 + }
     284 + s.logger.Trace("initializing inbound ", tag)
    275 285   err = in.Start()
    276 286   if err != nil {
    277  - var tag string
    278  - if in.Tag() == "" {
    279  - tag = F.ToString(i)
    280  - } else {
    281  - tag = in.Tag()
    282  - }
    283 287   return E.Cause(err, "initialize inbound/", in.Type(), "[", tag, "]")
    284 288   }
    285 289   }
    286 290   for serviceName, service := range s.postServices {
     291 + s.logger.Trace("start ", serviceName)
    287 292   err = service.Start()
    288 293   if err != nil {
    289  - return E.Cause(err, "start ", serviceName)
     294 + return E.Cause(err, "starting ", serviceName)
    290 295   }
    291 296   }
    292 297   return nil
    skipped 9 lines
    302 307   var errors error
    303 308   for serviceName, service := range s.postServices {
    304 309   errors = E.Append(errors, service.Close(), func(err error) error {
     310 + s.logger.Trace("closing ", serviceName)
    305 311   return E.Cause(err, "close ", serviceName)
    306 312   })
    307 313   }
    308 314   for i, in := range s.inbounds {
     315 + var tag string
     316 + if in.Tag() == "" {
     317 + tag = F.ToString(i)
     318 + } else {
     319 + tag = in.Tag()
     320 + }
     321 + s.logger.Trace("closing inbound ", tag)
    309 322   errors = E.Append(errors, in.Close(), func(err error) error {
    310 323   return E.Cause(err, "close inbound/", in.Type(), "[", i, "]")
    311 324   })
    312 325   }
    313 326   for i, out := range s.outbounds {
     327 + var tag string
     328 + if out.Tag() == "" {
     329 + tag = F.ToString(i)
     330 + } else {
     331 + tag = out.Tag()
     332 + }
     333 + s.logger.Trace("closing outbound ", tag)
    314 334   errors = E.Append(errors, common.Close(out), func(err error) error {
    315 335   return E.Cause(err, "close inbound/", out.Type(), "[", i, "]")
    316 336   })
    317 337   }
     338 + s.logger.Trace("closing router")
    318 339   if err := common.Close(s.router); err != nil {
    319 340   errors = E.Append(errors, err, func(err error) error {
    320 341   return E.Cause(err, "close router")
    321 342   })
    322 343   }
    323 344   for serviceName, service := range s.preServices {
     345 + s.logger.Trace("closing ", serviceName)
    324 346   errors = E.Append(errors, service.Close(), func(err error) error {
    325 347   return E.Cause(err, "close ", serviceName)
    326 348   })
    327 349   }
     350 + s.logger.Trace("closing logger")
    328 351   if err := common.Close(s.logFactory); err != nil {
    329 352   errors = E.Append(errors, err, func(err error) error {
    330 353   return E.Cause(err, "close log factory")
    skipped 14 lines
  • ■ ■ ■ ■ ■
    common/dialer/tfo.go
    skipped 26 lines
    27 27   
    28 28  func DialSlowContext(dialer *tfo.Dialer, ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
    29 29   if dialer.DisableTFO || N.NetworkName(network) != N.NetworkTCP {
    30  - return dialer.DialContext(ctx, network, destination.String(), nil)
     30 + switch N.NetworkName(network) {
     31 + case N.NetworkTCP, N.NetworkUDP:
     32 + return dialer.Dialer.DialContext(ctx, network, destination.String())
     33 + default:
     34 + return dialer.Dialer.DialContext(ctx, network, destination.AddrString())
     35 + }
    31 36   }
    32 37   return &slowOpenConn{
    33 38   dialer: dialer,
    skipped 109 lines
  • ■ ■ ■ ■ ■ ■
    go.mod
    skipped 24 lines
    25 25   github.com/sagernet/gomobile v0.0.0-20221130124640-349ebaa752ca
    26 26   github.com/sagernet/quic-go v0.0.0-20230202071646-a8c8afb18b32
    27 27   github.com/sagernet/reality v0.0.0-20230312150606-35ea9af0e0b8
    28  - github.com/sagernet/sing v0.2.1-0.20230318094614-4bbf5f2c3046
     28 + github.com/sagernet/sing v0.2.1-0.20230321172705-3e60222a1a7d
    29 29   github.com/sagernet/sing-dns v0.1.4
    30 30   github.com/sagernet/sing-shadowsocks v0.2.0
    31 31   github.com/sagernet/sing-shadowtls v0.1.0
    32  - github.com/sagernet/sing-tun v0.1.3-0.20230315134716-fe89bbded22d
     32 + github.com/sagernet/sing-tun v0.1.3-0.20230321172818-56bedd2f0558
    33 33   github.com/sagernet/sing-vmess v0.1.3
    34 34   github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37
    35 35   github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9
    skipped 60 lines
  • ■ ■ ■ ■ ■ ■
    go.sum
    skipped 110 lines
    111 111  github.com/sagernet/reality v0.0.0-20230312150606-35ea9af0e0b8/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU=
    112 112  github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
    113 113  github.com/sagernet/sing v0.1.8/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk=
    114  -github.com/sagernet/sing v0.2.1-0.20230318094614-4bbf5f2c3046 h1:/+ZWbxRvQmco9ES2qT5Eh/x/IiQRjAcUyRG/vQ4dpxc=
    115  -github.com/sagernet/sing v0.2.1-0.20230318094614-4bbf5f2c3046/go.mod h1:9uHswk2hITw8leDbiLS/xn0t9nzBcbePxzm9PJhwdlw=
     114 +github.com/sagernet/sing v0.2.1-0.20230321172705-3e60222a1a7d h1:ktk03rtgPqTDyUd2dWg1uzyr5RnptX8grSMvIzedJlQ=
     115 +github.com/sagernet/sing v0.2.1-0.20230321172705-3e60222a1a7d/go.mod h1:9uHswk2hITw8leDbiLS/xn0t9nzBcbePxzm9PJhwdlw=
    116 116  github.com/sagernet/sing-dns v0.1.4 h1:7VxgeoSCiiazDSaXXQVcvrTBxFpOePPq/4XdgnUDN+0=
    117 117  github.com/sagernet/sing-dns v0.1.4/go.mod h1:1+6pCa48B1AI78lD+/i/dLgpw4MwfnsSpZo0Ds8wzzk=
    118 118  github.com/sagernet/sing-shadowsocks v0.2.0 h1:ILDWL7pwWfkPLEbviE/MyCgfjaBmJY/JVVY+5jhSb58=
    119 119  github.com/sagernet/sing-shadowsocks v0.2.0/go.mod h1:ysYzszRLpNzJSorvlWRMuzU6Vchsp7sd52q+JNY4axw=
    120 120  github.com/sagernet/sing-shadowtls v0.1.0 h1:05MYce8aR5xfKIn+y7xRFsdKhKt44QZTSEQW+lG5IWQ=
    121 121  github.com/sagernet/sing-shadowtls v0.1.0/go.mod h1:Kn1VUIprdkwCgkS6SXYaLmIpKzQbqBIKJBMY+RvBhYc=
    122  -github.com/sagernet/sing-tun v0.1.3-0.20230315134716-fe89bbded22d h1:1gt4Hu2fHCrmL2NZYCNJ3nCgeczuhK09oCMni9mZmZk=
    123  -github.com/sagernet/sing-tun v0.1.3-0.20230315134716-fe89bbded22d/go.mod h1:KnRkwaDHbb06zgeNPu0LQ8A+vA9myMxKEgHN1brCPHg=
     122 +github.com/sagernet/sing-tun v0.1.3-0.20230321172818-56bedd2f0558 h1:c5Rm6BTOclEeayS6G9+1rI1kTeilCsn0ALSFbOdlgRE=
     123 +github.com/sagernet/sing-tun v0.1.3-0.20230321172818-56bedd2f0558/go.mod h1:cqnZEm+2ArgP4Gq1NcQfVFm9CZaeGw21mG9AcnYOTiU=
    124 124  github.com/sagernet/sing-vmess v0.1.3 h1:q/+tsF46dvvapL6CpQBgPHJ6nQrDUZqEtLHCbsjO7iM=
    125 125  github.com/sagernet/sing-vmess v0.1.3/go.mod h1:GVXqAHwe9U21uS+Voh4YBIrADQyE4F9v0ayGSixSQAE=
    126 126  github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as=
    skipped 117 lines
  • ■ ■ ■ ■ ■
    inbound/tun.go
    skipped 20 lines
    21 21   "github.com/sagernet/sing/common/ranges"
    22 22  )
    23 23   
    24  -var _ adapter.Inbound = (*Tun)(nil)
     24 +var (
     25 + _ adapter.Inbound = (*Tun)(nil)
     26 + _ tun.Router = (*Tun)(nil)
     27 +)
    25 28   
    26 29  type Tun struct {
    27 30   tag string
    skipped 12 lines
    40 43  }
    41 44   
    42 45  func NewTun(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.TunInboundOptions, platformInterface platform.Interface) (*Tun, error) {
    43  - tunName := options.InterfaceName
    44  - if tunName == "" {
    45  - tunName = tun.CalculateInterfaceName("")
    46  - }
    47 46   tunMTU := options.MTU
    48 47   if tunMTU == 0 {
    49 48   tunMTU = 9000
    skipped 27 lines
    77 76   logger: logger,
    78 77   inboundOptions: options.InboundOptions,
    79 78   tunOptions: tun.Options{
    80  - Name: tunName,
     79 + Name: options.InterfaceName,
    81 80   MTU: tunMTU,
    82 81   Inet4Address: common.Map(options.Inet4Address, option.ListenPrefix.Build),
    83 82   Inet6Address: common.Map(options.Inet6Address, option.ListenPrefix.Build),
    skipped 59 lines
    143 142   
    144 143  func (t *Tun) Start() error {
    145 144   if C.IsAndroid && t.platformInterface == nil {
     145 + t.logger.Trace("building android rules")
    146 146   t.tunOptions.BuildAndroidRules(t.router.PackageManager(), t)
     147 + }
     148 + if t.tunOptions.Name == "" {
     149 + t.tunOptions.Name = tun.CalculateInterfaceName("")
    147 150   }
    148 151   var (
    149 152   tunInterface tun.Tun
    150 153   err error
    151 154   )
     155 + t.logger.Trace("opening interface")
    152 156   if t.platformInterface != nil {
    153 157   tunInterface, err = t.platformInterface.OpenTun(t.tunOptions, t.platformOptions)
    154 158   } else {
    skipped 2 lines
    157 161   if err != nil {
    158 162   return E.Cause(err, "configure tun interface")
    159 163   }
     164 + t.logger.Trace("creating stack")
    160 165   t.tunIf = tunInterface
     166 + var tunRouter tun.Router
     167 + if len(t.router.IPRules()) > 0 {
     168 + tunRouter = t
     169 + }
    161 170   t.tunStack, err = tun.NewStack(t.stack, tun.StackOptions{
    162 171   Context: t.ctx,
    163 172   Tun: tunInterface,
    skipped 3 lines
    167 176   Inet6Address: t.tunOptions.Inet6Address,
    168 177   EndpointIndependentNat: t.endpointIndependentNat,
    169 178   UDPTimeout: t.udpTimeout,
     179 + Router: tunRouter,
    170 180   Handler: t,
    171 181   Logger: t.logger,
    172 182   UnderPlatform: t.platformInterface != nil,
    skipped 1 lines
    174 184   if err != nil {
    175 185   return err
    176 186   }
     187 + t.logger.Trace("starting stack")
    177 188   err = t.tunStack.Start()
    178 189   if err != nil {
    179 190   return err
    skipped 7 lines
    187 198   t.tunStack,
    188 199   t.tunIf,
    189 200   )
     201 +}
     202 + 
     203 +func (t *Tun) RouteConnection(session tun.RouteSession, conn tun.RouteContext) tun.RouteAction {
     204 + ctx := log.ContextWithNewID(t.ctx)
     205 + var metadata adapter.InboundContext
     206 + metadata.Inbound = t.tag
     207 + metadata.InboundType = C.TypeTun
     208 + metadata.IPVersion = session.IPVersion
     209 + metadata.Network = tun.NetworkName(session.Network)
     210 + metadata.Source = M.SocksaddrFromNetIP(session.Source)
     211 + metadata.Destination = M.SocksaddrFromNetIP(session.Destination)
     212 + metadata.InboundOptions = t.inboundOptions
     213 + t.logger.DebugContext(ctx, "incoming connection from ", metadata.Source)
     214 + t.logger.DebugContext(ctx, "incoming connection to ", metadata.Destination)
     215 + return t.router.RouteIPConnection(ctx, conn, metadata)
    190 216  }
    191 217   
    192 218  func (t *Tun) NewConnection(ctx context.Context, conn net.Conn, upstreamMetadata M.Metadata) error {
    skipped 40 lines
  • ■ ■ ■ ■ ■ ■
    option/dns.go
    1 1  package option
    2 2   
    3  -import (
    4  - "reflect"
    5  - 
    6  - "github.com/sagernet/sing-box/common/json"
    7  - C "github.com/sagernet/sing-box/constant"
    8  - "github.com/sagernet/sing/common"
    9  - E "github.com/sagernet/sing/common/exceptions"
    10  -)
    11  - 
    12 3  type DNSOptions struct {
    13 4   Servers []DNSServerOptions `json:"servers,omitempty"`
    14 5   Rules []DNSRule `json:"rules,omitempty"`
    skipped 17 lines
    32 23   Detour string `json:"detour,omitempty"`
    33 24  }
    34 25   
    35  -type _DNSRule struct {
    36  - Type string `json:"type,omitempty"`
    37  - DefaultOptions DefaultDNSRule `json:"-"`
    38  - LogicalOptions LogicalDNSRule `json:"-"`
    39  -}
    40  - 
    41  -type DNSRule _DNSRule
    42  - 
    43  -func (r DNSRule) MarshalJSON() ([]byte, error) {
    44  - var v any
    45  - switch r.Type {
    46  - case C.RuleTypeDefault:
    47  - r.Type = ""
    48  - v = r.DefaultOptions
    49  - case C.RuleTypeLogical:
    50  - v = r.LogicalOptions
    51  - default:
    52  - return nil, E.New("unknown rule type: " + r.Type)
    53  - }
    54  - return MarshallObjects((_DNSRule)(r), v)
    55  -}
    56  - 
    57  -func (r *DNSRule) UnmarshalJSON(bytes []byte) error {
    58  - err := json.Unmarshal(bytes, (*_DNSRule)(r))
    59  - if err != nil {
    60  - return err
    61  - }
    62  - var v any
    63  - switch r.Type {
    64  - case "", C.RuleTypeDefault:
    65  - r.Type = C.RuleTypeDefault
    66  - v = &r.DefaultOptions
    67  - case C.RuleTypeLogical:
    68  - v = &r.LogicalOptions
    69  - default:
    70  - return E.New("unknown rule type: " + r.Type)
    71  - }
    72  - err = UnmarshallExcluded(bytes, (*_DNSRule)(r), v)
    73  - if err != nil {
    74  - return E.Cause(err, "dns route rule")
    75  - }
    76  - return nil
    77  -}
    78  - 
    79  -type DefaultDNSRule struct {
    80  - Inbound Listable[string] `json:"inbound,omitempty"`
    81  - IPVersion int `json:"ip_version,omitempty"`
    82  - QueryType Listable[DNSQueryType] `json:"query_type,omitempty"`
    83  - Network string `json:"network,omitempty"`
    84  - AuthUser Listable[string] `json:"auth_user,omitempty"`
    85  - Protocol Listable[string] `json:"protocol,omitempty"`
    86  - Domain Listable[string] `json:"domain,omitempty"`
    87  - DomainSuffix Listable[string] `json:"domain_suffix,omitempty"`
    88  - DomainKeyword Listable[string] `json:"domain_keyword,omitempty"`
    89  - DomainRegex Listable[string] `json:"domain_regex,omitempty"`
    90  - Geosite Listable[string] `json:"geosite,omitempty"`
    91  - SourceGeoIP Listable[string] `json:"source_geoip,omitempty"`
    92  - SourceIPCIDR Listable[string] `json:"source_ip_cidr,omitempty"`
    93  - SourcePort Listable[uint16] `json:"source_port,omitempty"`
    94  - SourcePortRange Listable[string] `json:"source_port_range,omitempty"`
    95  - Port Listable[uint16] `json:"port,omitempty"`
    96  - PortRange Listable[string] `json:"port_range,omitempty"`
    97  - ProcessName Listable[string] `json:"process_name,omitempty"`
    98  - ProcessPath Listable[string] `json:"process_path,omitempty"`
    99  - PackageName Listable[string] `json:"package_name,omitempty"`
    100  - User Listable[string] `json:"user,omitempty"`
    101  - UserID Listable[int32] `json:"user_id,omitempty"`
    102  - Outbound Listable[string] `json:"outbound,omitempty"`
    103  - ClashMode string `json:"clash_mode,omitempty"`
    104  - Invert bool `json:"invert,omitempty"`
    105  - Server string `json:"server,omitempty"`
    106  - DisableCache bool `json:"disable_cache,omitempty"`
    107  -}
    108  - 
    109  -func (r DefaultDNSRule) IsValid() bool {
    110  - var defaultValue DefaultDNSRule
    111  - defaultValue.Invert = r.Invert
    112  - defaultValue.Server = r.Server
    113  - defaultValue.DisableCache = r.DisableCache
    114  - return !reflect.DeepEqual(r, defaultValue)
    115  -}
    116  - 
    117  -type LogicalDNSRule struct {
    118  - Mode string `json:"mode"`
    119  - Rules []DefaultDNSRule `json:"rules,omitempty"`
    120  - Invert bool `json:"invert,omitempty"`
    121  - Server string `json:"server,omitempty"`
    122  - DisableCache bool `json:"disable_cache,omitempty"`
    123  -}
    124  - 
    125  -func (r LogicalDNSRule) IsValid() bool {
    126  - return len(r.Rules) > 0 && common.All(r.Rules, DefaultDNSRule.IsValid)
    127  -}
    128  - 
  • ■ ■ ■ ■ ■
    option/route.go
    1 1  package option
    2 2   
    3  -import (
    4  - "reflect"
    5  - 
    6  - "github.com/sagernet/sing-box/common/json"
    7  - C "github.com/sagernet/sing-box/constant"
    8  - "github.com/sagernet/sing/common"
    9  - E "github.com/sagernet/sing/common/exceptions"
    10  -)
    11  - 
    12 3  type RouteOptions struct {
    13 4   GeoIP *GeoIPOptions `json:"geoip,omitempty"`
    14 5   Geosite *GeositeOptions `json:"geosite,omitempty"`
     6 + IPRules []IPRule `json:"ip_rules,omitempty"`
    15 7   Rules []Rule `json:"rules,omitempty"`
    16 8   Final string `json:"final,omitempty"`
    17 9   FindProcess bool `json:"find_process,omitempty"`
    skipped 15 lines
    33 25   DownloadDetour string `json:"download_detour,omitempty"`
    34 26  }
    35 27   
    36  -type _Rule struct {
    37  - Type string `json:"type,omitempty"`
    38  - DefaultOptions DefaultRule `json:"-"`
    39  - LogicalOptions LogicalRule `json:"-"`
    40  -}
    41  - 
    42  -type Rule _Rule
    43  - 
    44  -func (r Rule) MarshalJSON() ([]byte, error) {
    45  - var v any
    46  - switch r.Type {
    47  - case C.RuleTypeDefault:
    48  - r.Type = ""
    49  - v = r.DefaultOptions
    50  - case C.RuleTypeLogical:
    51  - v = r.LogicalOptions
    52  - default:
    53  - return nil, E.New("unknown rule type: " + r.Type)
    54  - }
    55  - return MarshallObjects((_Rule)(r), v)
    56  -}
    57  - 
    58  -func (r *Rule) UnmarshalJSON(bytes []byte) error {
    59  - err := json.Unmarshal(bytes, (*_Rule)(r))
    60  - if err != nil {
    61  - return err
    62  - }
    63  - var v any
    64  - switch r.Type {
    65  - case "", C.RuleTypeDefault:
    66  - r.Type = C.RuleTypeDefault
    67  - v = &r.DefaultOptions
    68  - case C.RuleTypeLogical:
    69  - v = &r.LogicalOptions
    70  - default:
    71  - return E.New("unknown rule type: " + r.Type)
    72  - }
    73  - err = UnmarshallExcluded(bytes, (*_Rule)(r), v)
    74  - if err != nil {
    75  - return E.Cause(err, "route rule")
    76  - }
    77  - return nil
    78  -}
    79  - 
    80  -type DefaultRule struct {
    81  - Inbound Listable[string] `json:"inbound,omitempty"`
    82  - IPVersion int `json:"ip_version,omitempty"`
    83  - Network string `json:"network,omitempty"`
    84  - AuthUser Listable[string] `json:"auth_user,omitempty"`
    85  - Protocol Listable[string] `json:"protocol,omitempty"`
    86  - Domain Listable[string] `json:"domain,omitempty"`
    87  - DomainSuffix Listable[string] `json:"domain_suffix,omitempty"`
    88  - DomainKeyword Listable[string] `json:"domain_keyword,omitempty"`
    89  - DomainRegex Listable[string] `json:"domain_regex,omitempty"`
    90  - Geosite Listable[string] `json:"geosite,omitempty"`
    91  - SourceGeoIP Listable[string] `json:"source_geoip,omitempty"`
    92  - GeoIP Listable[string] `json:"geoip,omitempty"`
    93  - SourceIPCIDR Listable[string] `json:"source_ip_cidr,omitempty"`
    94  - IPCIDR Listable[string] `json:"ip_cidr,omitempty"`
    95  - SourcePort Listable[uint16] `json:"source_port,omitempty"`
    96  - SourcePortRange Listable[string] `json:"source_port_range,omitempty"`
    97  - Port Listable[uint16] `json:"port,omitempty"`
    98  - PortRange Listable[string] `json:"port_range,omitempty"`
    99  - ProcessName Listable[string] `json:"process_name,omitempty"`
    100  - ProcessPath Listable[string] `json:"process_path,omitempty"`
    101  - PackageName Listable[string] `json:"package_name,omitempty"`
    102  - User Listable[string] `json:"user,omitempty"`
    103  - UserID Listable[int32] `json:"user_id,omitempty"`
    104  - ClashMode string `json:"clash_mode,omitempty"`
    105  - Invert bool `json:"invert,omitempty"`
    106  - Outbound string `json:"outbound,omitempty"`
    107  -}
    108  - 
    109  -func (r DefaultRule) IsValid() bool {
    110  - var defaultValue DefaultRule
    111  - defaultValue.Invert = r.Invert
    112  - defaultValue.Outbound = r.Outbound
    113  - return !reflect.DeepEqual(r, defaultValue)
    114  -}
    115  - 
    116  -type LogicalRule struct {
    117  - Mode string `json:"mode"`
    118  - Rules []DefaultRule `json:"rules,omitempty"`
    119  - Invert bool `json:"invert,omitempty"`
    120  - Outbound string `json:"outbound,omitempty"`
    121  -}
    122  - 
    123  -func (r LogicalRule) IsValid() bool {
    124  - return len(r.Rules) > 0 && common.All(r.Rules, DefaultRule.IsValid)
    125  -}
    126  - 
  • ■ ■ ■ ■ ■ ■
    option/rule.go
     1 +package option
     2 + 
     3 +import (
     4 + "reflect"
     5 + 
     6 + "github.com/sagernet/sing-box/common/json"
     7 + C "github.com/sagernet/sing-box/constant"
     8 + "github.com/sagernet/sing/common"
     9 + E "github.com/sagernet/sing/common/exceptions"
     10 +)
     11 + 
     12 +type _Rule struct {
     13 + Type string `json:"type,omitempty"`
     14 + DefaultOptions DefaultRule `json:"-"`
     15 + LogicalOptions LogicalRule `json:"-"`
     16 +}
     17 + 
     18 +type Rule _Rule
     19 + 
     20 +func (r Rule) MarshalJSON() ([]byte, error) {
     21 + var v any
     22 + switch r.Type {
     23 + case C.RuleTypeDefault:
     24 + r.Type = ""
     25 + v = r.DefaultOptions
     26 + case C.RuleTypeLogical:
     27 + v = r.LogicalOptions
     28 + default:
     29 + return nil, E.New("unknown rule type: " + r.Type)
     30 + }
     31 + return MarshallObjects((_Rule)(r), v)
     32 +}
     33 + 
     34 +func (r *Rule) UnmarshalJSON(bytes []byte) error {
     35 + err := json.Unmarshal(bytes, (*_Rule)(r))
     36 + if err != nil {
     37 + return err
     38 + }
     39 + var v any
     40 + switch r.Type {
     41 + case "", C.RuleTypeDefault:
     42 + r.Type = C.RuleTypeDefault
     43 + v = &r.DefaultOptions
     44 + case C.RuleTypeLogical:
     45 + v = &r.LogicalOptions
     46 + default:
     47 + return E.New("unknown rule type: " + r.Type)
     48 + }
     49 + err = UnmarshallExcluded(bytes, (*_Rule)(r), v)
     50 + if err != nil {
     51 + return E.Cause(err, "route rule")
     52 + }
     53 + return nil
     54 +}
     55 + 
     56 +type DefaultRule struct {
     57 + Inbound Listable[string] `json:"inbound,omitempty"`
     58 + IPVersion int `json:"ip_version,omitempty"`
     59 + Network Listable[string] `json:"network,omitempty"`
     60 + AuthUser Listable[string] `json:"auth_user,omitempty"`
     61 + Protocol Listable[string] `json:"protocol,omitempty"`
     62 + Domain Listable[string] `json:"domain,omitempty"`
     63 + DomainSuffix Listable[string] `json:"domain_suffix,omitempty"`
     64 + DomainKeyword Listable[string] `json:"domain_keyword,omitempty"`
     65 + DomainRegex Listable[string] `json:"domain_regex,omitempty"`
     66 + Geosite Listable[string] `json:"geosite,omitempty"`
     67 + SourceGeoIP Listable[string] `json:"source_geoip,omitempty"`
     68 + GeoIP Listable[string] `json:"geoip,omitempty"`
     69 + SourceIPCIDR Listable[string] `json:"source_ip_cidr,omitempty"`
     70 + IPCIDR Listable[string] `json:"ip_cidr,omitempty"`
     71 + SourcePort Listable[uint16] `json:"source_port,omitempty"`
     72 + SourcePortRange Listable[string] `json:"source_port_range,omitempty"`
     73 + Port Listable[uint16] `json:"port,omitempty"`
     74 + PortRange Listable[string] `json:"port_range,omitempty"`
     75 + ProcessName Listable[string] `json:"process_name,omitempty"`
     76 + ProcessPath Listable[string] `json:"process_path,omitempty"`
     77 + PackageName Listable[string] `json:"package_name,omitempty"`
     78 + User Listable[string] `json:"user,omitempty"`
     79 + UserID Listable[int32] `json:"user_id,omitempty"`
     80 + ClashMode string `json:"clash_mode,omitempty"`
     81 + Invert bool `json:"invert,omitempty"`
     82 + Outbound string `json:"outbound,omitempty"`
     83 +}
     84 + 
     85 +func (r DefaultRule) IsValid() bool {
     86 + var defaultValue DefaultRule
     87 + defaultValue.Invert = r.Invert
     88 + defaultValue.Outbound = r.Outbound
     89 + return !reflect.DeepEqual(r, defaultValue)
     90 +}
     91 + 
     92 +type LogicalRule struct {
     93 + Mode string `json:"mode"`
     94 + Rules []DefaultRule `json:"rules,omitempty"`
     95 + Invert bool `json:"invert,omitempty"`
     96 + Outbound string `json:"outbound,omitempty"`
     97 +}
     98 + 
     99 +func (r LogicalRule) IsValid() bool {
     100 + return len(r.Rules) > 0 && common.All(r.Rules, DefaultRule.IsValid)
     101 +}
     102 + 
  • ■ ■ ■ ■ ■ ■
    option/rule_dns.go
     1 +package option
     2 + 
     3 +import (
     4 + "reflect"
     5 + 
     6 + "github.com/sagernet/sing-box/common/json"
     7 + C "github.com/sagernet/sing-box/constant"
     8 + "github.com/sagernet/sing/common"
     9 + E "github.com/sagernet/sing/common/exceptions"
     10 +)
     11 + 
     12 +type _DNSRule struct {
     13 + Type string `json:"type,omitempty"`
     14 + DefaultOptions DefaultDNSRule `json:"-"`
     15 + LogicalOptions LogicalDNSRule `json:"-"`
     16 +}
     17 + 
     18 +type DNSRule _DNSRule
     19 + 
     20 +func (r DNSRule) MarshalJSON() ([]byte, error) {
     21 + var v any
     22 + switch r.Type {
     23 + case C.RuleTypeDefault:
     24 + r.Type = ""
     25 + v = r.DefaultOptions
     26 + case C.RuleTypeLogical:
     27 + v = r.LogicalOptions
     28 + default:
     29 + return nil, E.New("unknown rule type: " + r.Type)
     30 + }
     31 + return MarshallObjects((_DNSRule)(r), v)
     32 +}
     33 + 
     34 +func (r *DNSRule) UnmarshalJSON(bytes []byte) error {
     35 + err := json.Unmarshal(bytes, (*_DNSRule)(r))
     36 + if err != nil {
     37 + return err
     38 + }
     39 + var v any
     40 + switch r.Type {
     41 + case "", C.RuleTypeDefault:
     42 + r.Type = C.RuleTypeDefault
     43 + v = &r.DefaultOptions
     44 + case C.RuleTypeLogical:
     45 + v = &r.LogicalOptions
     46 + default:
     47 + return E.New("unknown rule type: " + r.Type)
     48 + }
     49 + err = UnmarshallExcluded(bytes, (*_DNSRule)(r), v)
     50 + if err != nil {
     51 + return E.Cause(err, "dns route rule")
     52 + }
     53 + return nil
     54 +}
     55 + 
     56 +type DefaultDNSRule struct {
     57 + Inbound Listable[string] `json:"inbound,omitempty"`
     58 + IPVersion int `json:"ip_version,omitempty"`
     59 + QueryType Listable[DNSQueryType] `json:"query_type,omitempty"`
     60 + Network Listable[string] `json:"network,omitempty"`
     61 + AuthUser Listable[string] `json:"auth_user,omitempty"`
     62 + Protocol Listable[string] `json:"protocol,omitempty"`
     63 + Domain Listable[string] `json:"domain,omitempty"`
     64 + DomainSuffix Listable[string] `json:"domain_suffix,omitempty"`
     65 + DomainKeyword Listable[string] `json:"domain_keyword,omitempty"`
     66 + DomainRegex Listable[string] `json:"domain_regex,omitempty"`
     67 + Geosite Listable[string] `json:"geosite,omitempty"`
     68 + SourceGeoIP Listable[string] `json:"source_geoip,omitempty"`
     69 + SourceIPCIDR Listable[string] `json:"source_ip_cidr,omitempty"`
     70 + SourcePort Listable[uint16] `json:"source_port,omitempty"`
     71 + SourcePortRange Listable[string] `json:"source_port_range,omitempty"`
     72 + Port Listable[uint16] `json:"port,omitempty"`
     73 + PortRange Listable[string] `json:"port_range,omitempty"`
     74 + ProcessName Listable[string] `json:"process_name,omitempty"`
     75 + ProcessPath Listable[string] `json:"process_path,omitempty"`
     76 + PackageName Listable[string] `json:"package_name,omitempty"`
     77 + User Listable[string] `json:"user,omitempty"`
     78 + UserID Listable[int32] `json:"user_id,omitempty"`
     79 + Outbound Listable[string] `json:"outbound,omitempty"`
     80 + ClashMode string `json:"clash_mode,omitempty"`
     81 + Invert bool `json:"invert,omitempty"`
     82 + Server string `json:"server,omitempty"`
     83 + DisableCache bool `json:"disable_cache,omitempty"`
     84 +}
     85 + 
     86 +func (r DefaultDNSRule) IsValid() bool {
     87 + var defaultValue DefaultDNSRule
     88 + defaultValue.Invert = r.Invert
     89 + defaultValue.Server = r.Server
     90 + defaultValue.DisableCache = r.DisableCache
     91 + return !reflect.DeepEqual(r, defaultValue)
     92 +}
     93 + 
     94 +type LogicalDNSRule struct {
     95 + Mode string `json:"mode"`
     96 + Rules []DefaultDNSRule `json:"rules,omitempty"`
     97 + Invert bool `json:"invert,omitempty"`
     98 + Server string `json:"server,omitempty"`
     99 + DisableCache bool `json:"disable_cache,omitempty"`
     100 +}
     101 + 
     102 +func (r LogicalDNSRule) IsValid() bool {
     103 + return len(r.Rules) > 0 && common.All(r.Rules, DefaultDNSRule.IsValid)
     104 +}
     105 + 
  • ■ ■ ■ ■ ■ ■
    option/rule_ip.go
     1 +package option
     2 + 
     3 +import (
     4 + "reflect"
     5 + 
     6 + "github.com/sagernet/sing-box/common/json"
     7 + C "github.com/sagernet/sing-box/constant"
     8 + tun "github.com/sagernet/sing-tun"
     9 + "github.com/sagernet/sing/common"
     10 + E "github.com/sagernet/sing/common/exceptions"
     11 +)
     12 + 
     13 +type _IPRule struct {
     14 + Type string `json:"type,omitempty"`
     15 + DefaultOptions DefaultIPRule `json:"-"`
     16 + LogicalOptions LogicalIPRule `json:"-"`
     17 +}
     18 + 
     19 +type IPRule _IPRule
     20 + 
     21 +func (r IPRule) MarshalJSON() ([]byte, error) {
     22 + var v any
     23 + switch r.Type {
     24 + case C.RuleTypeDefault:
     25 + r.Type = ""
     26 + v = r.DefaultOptions
     27 + case C.RuleTypeLogical:
     28 + v = r.LogicalOptions
     29 + default:
     30 + return nil, E.New("unknown rule type: " + r.Type)
     31 + }
     32 + return MarshallObjects((_IPRule)(r), v)
     33 +}
     34 + 
     35 +func (r *IPRule) UnmarshalJSON(bytes []byte) error {
     36 + err := json.Unmarshal(bytes, (*_IPRule)(r))
     37 + if err != nil {
     38 + return err
     39 + }
     40 + var v any
     41 + switch r.Type {
     42 + case "", C.RuleTypeDefault:
     43 + r.Type = C.RuleTypeDefault
     44 + v = &r.DefaultOptions
     45 + case C.RuleTypeLogical:
     46 + v = &r.LogicalOptions
     47 + default:
     48 + return E.New("unknown rule type: " + r.Type)
     49 + }
     50 + err = UnmarshallExcluded(bytes, (*_IPRule)(r), v)
     51 + if err != nil {
     52 + return E.Cause(err, "ip route rule")
     53 + }
     54 + return nil
     55 +}
     56 + 
     57 +type DefaultIPRule struct {
     58 + Inbound Listable[string] `json:"inbound,omitempty"`
     59 + IPVersion int `json:"ip_version,omitempty"`
     60 + Network Listable[string] `json:"network,omitempty"`
     61 + Domain Listable[string] `json:"domain,omitempty"`
     62 + DomainSuffix Listable[string] `json:"domain_suffix,omitempty"`
     63 + DomainKeyword Listable[string] `json:"domain_keyword,omitempty"`
     64 + DomainRegex Listable[string] `json:"domain_regex,omitempty"`
     65 + Geosite Listable[string] `json:"geosite,omitempty"`
     66 + SourceGeoIP Listable[string] `json:"source_geoip,omitempty"`
     67 + SourceIPCIDR Listable[string] `json:"source_ip_cidr,omitempty"`
     68 + SourcePort Listable[uint16] `json:"source_port,omitempty"`
     69 + SourcePortRange Listable[string] `json:"source_port_range,omitempty"`
     70 + Port Listable[uint16] `json:"port,omitempty"`
     71 + PortRange Listable[string] `json:"port_range,omitempty"`
     72 + Invert bool `json:"invert,omitempty"`
     73 + Action RouteAction `json:"action,omitempty"`
     74 + Outbound string `json:"outbound,omitempty"`
     75 +}
     76 + 
     77 +type RouteAction tun.ActionType
     78 + 
     79 +func (a RouteAction) MarshalJSON() ([]byte, error) {
     80 + switch tun.ActionType(a) {
     81 + case tun.ActionTypeReject, tun.ActionTypeDirect:
     82 + default:
     83 + return nil, E.New("unknown action: ", a)
     84 + }
     85 + return json.Marshal(tun.ActionTypeName(tun.ActionType(a)))
     86 +}
     87 + 
     88 +func (a *RouteAction) UnmarshalJSON(bytes []byte) error {
     89 + var value string
     90 + err := json.Unmarshal(bytes, &value)
     91 + if err != nil {
     92 + return err
     93 + }
     94 + actionType, err := tun.ParseActionType(value)
     95 + if err != nil {
     96 + return err
     97 + }
     98 + switch actionType {
     99 + case tun.ActionTypeReject, tun.ActionTypeDirect:
     100 + default:
     101 + return E.New("unknown action: ", a)
     102 + }
     103 + *a = RouteAction(actionType)
     104 + return nil
     105 +}
     106 + 
     107 +func (r DefaultIPRule) IsValid() bool {
     108 + var defaultValue DefaultIPRule
     109 + defaultValue.Invert = r.Invert
     110 + defaultValue.Action = r.Action
     111 + defaultValue.Outbound = r.Outbound
     112 + return !reflect.DeepEqual(r, defaultValue)
     113 +}
     114 + 
     115 +type LogicalIPRule struct {
     116 + Mode string `json:"mode"`
     117 + Rules []DefaultIPRule `json:"rules,omitempty"`
     118 + Invert bool `json:"invert,omitempty"`
     119 + Action RouteAction `json:"action,omitempty"`
     120 + Outbound string `json:"outbound,omitempty"`
     121 +}
     122 + 
     123 +func (r LogicalIPRule) IsValid() bool {
     124 + return len(r.Rules) > 0 && common.All(r.Rules, DefaultIPRule.IsValid)
     125 +}
     126 + 
  • ■ ■ ■ ■ ■
    option/wireguard.go
    skipped 12 lines
    13 13   Workers int `json:"workers,omitempty"`
    14 14   MTU uint32 `json:"mtu,omitempty"`
    15 15   Network NetworkList `json:"network,omitempty"`
     16 + IPRewrite bool `json:"ip_rewrite,omitempty"`
    16 17  }
    17 18   
  • ■ ■ ■ ■ ■
    outbound/wireguard.go
    skipped 7 lines
    8 8   "encoding/hex"
    9 9   "fmt"
    10 10   "net"
     11 + "os"
    11 12   "strings"
     13 + "syscall"
    12 14   
    13 15   "github.com/sagernet/sing-box/adapter"
    14 16   "github.com/sagernet/sing-box/common/dialer"
    skipped 11 lines
    26 28  )
    27 29   
    28 30  var (
    29  - _ adapter.Outbound = (*WireGuard)(nil)
     31 + _ adapter.IPOutbound = (*WireGuard)(nil)
    30 32   _ adapter.InterfaceUpdateListener = (*WireGuard)(nil)
    31 33  )
    32 34   
    skipped 1 lines
    34 36   myOutboundAdapter
    35 37   bind *wireguard.ClientBind
    36 38   device *device.Device
     39 + natDevice wireguard.NatDevice
    37 40   tunDevice wireguard.Device
    38 41  }
    39 42   
    skipped 66 lines
    106 109   if mtu == 0 {
    107 110   mtu = 1408
    108 111   }
    109  - var wireTunDevice wireguard.Device
     112 + var tunDevice wireguard.Device
    110 113   var err error
    111 114   if !options.SystemInterface && tun.WithGVisor {
    112  - wireTunDevice, err = wireguard.NewStackDevice(localPrefixes, mtu)
     115 + tunDevice, err = wireguard.NewStackDevice(localPrefixes, mtu, options.IPRewrite)
    113 116   } else {
    114  - wireTunDevice, err = wireguard.NewSystemDevice(router, options.InterfaceName, localPrefixes, mtu)
     117 + tunDevice, err = wireguard.NewSystemDevice(router, options.InterfaceName, localPrefixes, mtu)
    115 118   }
    116 119   if err != nil {
    117 120   return nil, E.Cause(err, "create WireGuard device")
    118 121   }
    119  - wgDevice := device.NewDevice(wireTunDevice, outbound.bind, &device.Logger{
     122 + natDevice, isNatDevice := tunDevice.(wireguard.NatDevice)
     123 + if !isNatDevice && router.NatRequired(tag) {
     124 + natDevice = wireguard.NewNATDevice(tunDevice, options.IPRewrite)
     125 + }
     126 + deviceInput := tunDevice
     127 + if natDevice != nil {
     128 + deviceInput = natDevice
     129 + }
     130 + wgDevice := device.NewDevice(deviceInput, outbound.bind, &device.Logger{
    120 131   Verbosef: func(format string, args ...interface{}) {
    121 132   logger.Debug(fmt.Sprintf(strings.ToLower(format), args...))
    122 133   },
    skipped 9 lines
    132 143   return nil, E.Cause(err, "setup wireguard")
    133 144   }
    134 145   outbound.device = wgDevice
    135  - outbound.tunDevice = wireTunDevice
     146 + outbound.natDevice = natDevice
     147 + outbound.tunDevice = tunDevice
    136 148   return outbound, nil
    137 149  }
    138 150   
    skipped 30 lines
    169 181   
    170 182  func (w *WireGuard) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
    171 183   return NewPacketConnection(ctx, w, conn, metadata)
     184 +}
     185 + 
     186 +func (w *WireGuard) NewIPConnection(ctx context.Context, conn tun.RouteContext, metadata adapter.InboundContext) (tun.DirectDestination, error) {
     187 + if w.natDevice == nil {
     188 + return nil, os.ErrInvalid
     189 + }
     190 + session := tun.RouteSession{
     191 + IPVersion: metadata.IPVersion,
     192 + Network: tun.NetworkFromName(metadata.Network),
     193 + Source: metadata.Source.AddrPort(),
     194 + Destination: metadata.Destination.AddrPort(),
     195 + }
     196 + switch session.Network {
     197 + case syscall.IPPROTO_TCP:
     198 + w.logger.InfoContext(ctx, "linked connection to ", metadata.Destination)
     199 + case syscall.IPPROTO_UDP:
     200 + w.logger.InfoContext(ctx, "linked packet connection to ", metadata.Destination)
     201 + default:
     202 + w.logger.InfoContext(ctx, "linked ", metadata.Network, " connection to ", metadata.Destination.AddrString())
     203 + }
     204 + return w.natDevice.CreateDestination(session, conn), nil
    172 205  }
    173 206   
    174 207  func (w *WireGuard) Start() error {
    skipped 10 lines
  • ■ ■ ■ ■ ■
    route/router.go
    skipped 1 lines
    2 2   
    3 3  import (
    4 4   "context"
    5  - "io"
    6 5   "net"
    7  - "net/http"
    8 6   "net/netip"
    9 7   "net/url"
    10 8   "os"
    11 9   "os/user"
    12  - "path/filepath"
    13 10   "strings"
    14 11   "time"
    15 12   
    skipped 21 lines
    37 34   F "github.com/sagernet/sing/common/format"
    38 35   M "github.com/sagernet/sing/common/metadata"
    39 36   N "github.com/sagernet/sing/common/network"
    40  - "github.com/sagernet/sing/common/rw"
    41 37   "github.com/sagernet/sing/common/uot"
    42 38  )
    43 39   
    skipped 28 lines
    72 68   outbounds []adapter.Outbound
    73 69   outboundByTag map[string]adapter.Outbound
    74 70   rules []adapter.Rule
     71 + ipRules []adapter.IPRule
    75 72   defaultDetour string
    76 73   defaultOutboundForConnection adapter.Outbound
    77 74   defaultOutboundForPacketConnection adapter.Outbound
    skipped 50 lines
    128 125   dnsLogger: logFactory.NewLogger("dns"),
    129 126   outboundByTag: make(map[string]adapter.Outbound),
    130 127   rules: make([]adapter.Rule, 0, len(options.Rules)),
     128 + ipRules: make([]adapter.IPRule, 0, len(options.IPRules)),
    131 129   dnsRules: make([]adapter.DNSRule, 0, len(dnsOptions.Rules)),
    132 130   needGeoIPDatabase: hasRule(options.Rules, isGeoIPRule) || hasDNSRule(dnsOptions.Rules, isGeoIPDNSRule),
    133 131   needGeositeDatabase: hasRule(options.Rules, isGeositeRule) || hasDNSRule(dnsOptions.Rules, isGeositeDNSRule),
    skipped 15 lines
    149 147   }
    150 148   router.rules = append(router.rules, routeRule)
    151 149   }
     150 + for i, ipRuleOptions := range options.IPRules {
     151 + ipRule, err := NewIPRule(router, router.logger, ipRuleOptions)
     152 + if err != nil {
     153 + return nil, E.Cause(err, "parse ip rule[", i, "]")
     154 + }
     155 + router.ipRules = append(router.ipRules, ipRule)
     156 + }
    152 157   for i, dnsRuleOptions := range dnsOptions.Rules {
    153 158   dnsRule, err := NewDNSRule(router, router.logger, dnsRuleOptions)
    154 159   if err != nil {
    skipped 1 lines
    156 161   }
    157 162   router.dnsRules = append(router.dnsRules, dnsRule)
    158 163   }
     164 + 
    159 165   transports := make([]dns.Transport, len(dnsOptions.Servers))
    160 166   dummyTransportMap := make(map[string]dns.Transport)
    161 167   transportMap := make(map[string]dns.Transport)
    skipped 354 lines
    516 522   )
    517 523  }
    518 524   
    519  -func (r *Router) GeoIPReader() *geoip.Reader {
    520  - return r.geoIPReader
    521  -}
    522  - 
    523  -func (r *Router) LoadGeosite(code string) (adapter.Rule, error) {
    524  - rule, cached := r.geositeCache[code]
    525  - if cached {
    526  - return rule, nil
    527  - }
    528  - items, err := r.geositeReader.Read(code)
    529  - if err != nil {
    530  - return nil, err
    531  - }
    532  - rule, err = NewDefaultRule(r, nil, geosite.Compile(items))
    533  - if err != nil {
    534  - return nil, err
    535  - }
    536  - r.geositeCache[code] = rule
    537  - return rule, nil
    538  -}
    539  - 
    540 525  func (r *Router) Outbound(tag string) (adapter.Outbound, bool) {
    541 526   outbound, loaded := r.outboundByTag[tag]
    542 527   return outbound, loaded
    skipped 268 lines
    811 796   return r.rules
    812 797  }
    813 798   
     799 +func (r *Router) IPRules() []adapter.IPRule {
     800 + return r.ipRules
     801 +}
     802 + 
    814 803  func (r *Router) NetworkMonitor() tun.NetworkUpdateMonitor {
    815 804   return r.networkMonitor
    816 805  }
    skipped 27 lines
    844 833   
    845 834  func (r *Router) SetV2RayServer(server adapter.V2RayServer) {
    846 835   r.v2rayServer = server
    847  -}
    848  - 
    849  -func hasRule(rules []option.Rule, cond func(rule option.DefaultRule) bool) bool {
    850  - for _, rule := range rules {
    851  - switch rule.Type {
    852  - case C.RuleTypeDefault:
    853  - if cond(rule.DefaultOptions) {
    854  - return true
    855  - }
    856  - case C.RuleTypeLogical:
    857  - for _, subRule := range rule.LogicalOptions.Rules {
    858  - if cond(subRule) {
    859  - return true
    860  - }
    861  - }
    862  - }
    863  - }
    864  - return false
    865  -}
    866  - 
    867  -func hasDNSRule(rules []option.DNSRule, cond func(rule option.DefaultDNSRule) bool) bool {
    868  - for _, rule := range rules {
    869  - switch rule.Type {
    870  - case C.RuleTypeDefault:
    871  - if cond(rule.DefaultOptions) {
    872  - return true
    873  - }
    874  - case C.RuleTypeLogical:
    875  - for _, subRule := range rule.LogicalOptions.Rules {
    876  - if cond(subRule) {
    877  - return true
    878  - }
    879  - }
    880  - }
    881  - }
    882  - return false
    883  -}
    884  - 
    885  -func isGeoIPRule(rule option.DefaultRule) bool {
    886  - return len(rule.SourceGeoIP) > 0 && common.Any(rule.SourceGeoIP, notPrivateNode) || len(rule.GeoIP) > 0 && common.Any(rule.GeoIP, notPrivateNode)
    887  -}
    888  - 
    889  -func isGeoIPDNSRule(rule option.DefaultDNSRule) bool {
    890  - return len(rule.SourceGeoIP) > 0 && common.Any(rule.SourceGeoIP, notPrivateNode)
    891  -}
    892  - 
    893  -func isGeositeRule(rule option.DefaultRule) bool {
    894  - return len(rule.Geosite) > 0
    895  -}
    896  - 
    897  -func isGeositeDNSRule(rule option.DefaultDNSRule) bool {
    898  - return len(rule.Geosite) > 0
    899  -}
    900  - 
    901  -func isProcessRule(rule option.DefaultRule) bool {
    902  - return len(rule.ProcessName) > 0 || len(rule.ProcessPath) > 0 || len(rule.PackageName) > 0 || len(rule.User) > 0 || len(rule.UserID) > 0
    903  -}
    904  - 
    905  -func isProcessDNSRule(rule option.DefaultDNSRule) bool {
    906  - return len(rule.ProcessName) > 0 || len(rule.ProcessPath) > 0 || len(rule.PackageName) > 0 || len(rule.User) > 0 || len(rule.UserID) > 0
    907  -}
    908  - 
    909  -func notPrivateNode(code string) bool {
    910  - return code != "private"
    911  -}
    912  - 
    913  -func (r *Router) prepareGeoIPDatabase() error {
    914  - var geoPath string
    915  - if r.geoIPOptions.Path != "" {
    916  - geoPath = r.geoIPOptions.Path
    917  - } else {
    918  - geoPath = "geoip.db"
    919  - if foundPath, loaded := C.FindPath(geoPath); loaded {
    920  - geoPath = foundPath
    921  - }
    922  - }
    923  - geoPath = C.BasePath(geoPath)
    924  - if !rw.FileExists(geoPath) {
    925  - r.logger.Warn("geoip database not exists: ", geoPath)
    926  - var err error
    927  - for attempts := 0; attempts < 3; attempts++ {
    928  - err = r.downloadGeoIPDatabase(geoPath)
    929  - if err == nil {
    930  - break
    931  - }
    932  - r.logger.Error("download geoip database: ", err)
    933  - os.Remove(geoPath)
    934  - // time.Sleep(10 * time.Second)
    935  - }
    936  - if err != nil {
    937  - return err
    938  - }
    939  - }
    940  - geoReader, codes, err := geoip.Open(geoPath)
    941  - if err != nil {
    942  - return E.Cause(err, "open geoip database")
    943  - }
    944  - r.logger.Info("loaded geoip database: ", len(codes), " codes")
    945  - r.geoIPReader = geoReader
    946  - return nil
    947  -}
    948  - 
    949  -func (r *Router) prepareGeositeDatabase() error {
    950  - var geoPath string
    951  - if r.geositeOptions.Path != "" {
    952  - geoPath = r.geositeOptions.Path
    953  - } else {
    954  - geoPath = "geosite.db"
    955  - if foundPath, loaded := C.FindPath(geoPath); loaded {
    956  - geoPath = foundPath
    957  - }
    958  - }
    959  - geoPath = C.BasePath(geoPath)
    960  - if !rw.FileExists(geoPath) {
    961  - r.logger.Warn("geosite database not exists: ", geoPath)
    962  - var err error
    963  - for attempts := 0; attempts < 3; attempts++ {
    964  - err = r.downloadGeositeDatabase(geoPath)
    965  - if err == nil {
    966  - break
    967  - }
    968  - r.logger.Error("download geosite database: ", err)
    969  - os.Remove(geoPath)
    970  - // time.Sleep(10 * time.Second)
    971  - }
    972  - if err != nil {
    973  - return err
    974  - }
    975  - }
    976  - geoReader, codes, err := geosite.Open(geoPath)
    977  - if err == nil {
    978  - r.logger.Info("loaded geosite database: ", len(codes), " codes")
    979  - r.geositeReader = geoReader
    980  - } else {
    981  - return E.Cause(err, "open geosite database")
    982  - }
    983  - return nil
    984  -}
    985  - 
    986  -func (r *Router) downloadGeoIPDatabase(savePath string) error {
    987  - var downloadURL string
    988  - if r.geoIPOptions.DownloadURL != "" {
    989  - downloadURL = r.geoIPOptions.DownloadURL
    990  - } else {
    991  - downloadURL = "https://github.com/SagerNet/sing-geoip/releases/latest/download/geoip.db"
    992  - }
    993  - r.logger.Info("downloading geoip database")
    994  - var detour adapter.Outbound
    995  - if r.geoIPOptions.DownloadDetour != "" {
    996  - outbound, loaded := r.Outbound(r.geoIPOptions.DownloadDetour)
    997  - if !loaded {
    998  - return E.New("detour outbound not found: ", r.geoIPOptions.DownloadDetour)
    999  - }
    1000  - detour = outbound
    1001  - } else {
    1002  - detour = r.defaultOutboundForConnection
    1003  - }
    1004  - 
    1005  - if parentDir := filepath.Dir(savePath); parentDir != "" {
    1006  - os.MkdirAll(parentDir, 0o755)
    1007  - }
    1008  - 
    1009  - saveFile, err := os.OpenFile(savePath, os.O_CREATE|os.O_WRONLY, 0o644)
    1010  - if err != nil {
    1011  - return E.Cause(err, "open output file: ", downloadURL)
    1012  - }
    1013  - defer saveFile.Close()
    1014  - 
    1015  - httpClient := &http.Client{
    1016  - Transport: &http.Transport{
    1017  - ForceAttemptHTTP2: true,
    1018  - TLSHandshakeTimeout: 5 * time.Second,
    1019  - DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
    1020  - return detour.DialContext(ctx, network, M.ParseSocksaddr(addr))
    1021  - },
    1022  - },
    1023  - }
    1024  - defer httpClient.CloseIdleConnections()
    1025  - response, err := httpClient.Get(downloadURL)
    1026  - if err != nil {
    1027  - return err
    1028  - }
    1029  - defer response.Body.Close()
    1030  - _, err = io.Copy(saveFile, response.Body)
    1031  - return err
    1032  -}
    1033  - 
    1034  -func (r *Router) downloadGeositeDatabase(savePath string) error {
    1035  - var downloadURL string
    1036  - if r.geositeOptions.DownloadURL != "" {
    1037  - downloadURL = r.geositeOptions.DownloadURL
    1038  - } else {
    1039  - downloadURL = "https://github.com/SagerNet/sing-geosite/releases/latest/download/geosite.db"
    1040  - }
    1041  - r.logger.Info("downloading geosite database")
    1042  - var detour adapter.Outbound
    1043  - if r.geositeOptions.DownloadDetour != "" {
    1044  - outbound, loaded := r.Outbound(r.geositeOptions.DownloadDetour)
    1045  - if !loaded {
    1046  - return E.New("detour outbound not found: ", r.geositeOptions.DownloadDetour)
    1047  - }
    1048  - detour = outbound
    1049  - } else {
    1050  - detour = r.defaultOutboundForConnection
    1051  - }
    1052  - 
    1053  - if parentDir := filepath.Dir(savePath); parentDir != "" {
    1054  - os.MkdirAll(parentDir, 0o755)
    1055  - }
    1056  - 
    1057  - saveFile, err := os.OpenFile(savePath, os.O_CREATE|os.O_WRONLY, 0o644)
    1058  - if err != nil {
    1059  - return E.Cause(err, "open output file: ", downloadURL)
    1060  - }
    1061  - defer saveFile.Close()
    1062  - 
    1063  - httpClient := &http.Client{
    1064  - Transport: &http.Transport{
    1065  - ForceAttemptHTTP2: true,
    1066  - TLSHandshakeTimeout: 5 * time.Second,
    1067  - DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
    1068  - return detour.DialContext(ctx, network, M.ParseSocksaddr(addr))
    1069  - },
    1070  - },
    1071  - }
    1072  - defer httpClient.CloseIdleConnections()
    1073  - response, err := httpClient.Get(downloadURL)
    1074  - if err != nil {
    1075  - return err
    1076  - }
    1077  - defer response.Body.Close()
    1078  - _, err = io.Copy(saveFile, response.Body)
    1079  - return err
    1080 836  }
    1081 837   
    1082 838  func (r *Router) OnPackagesUpdated(packages int, sharedUsers int) {
    skipped 37 lines
  • ■ ■ ■ ■ ■ ■
    route/router_geo_resources.go
     1 +package route
     2 + 
     3 +import (
     4 + "context"
     5 + "io"
     6 + "net"
     7 + "net/http"
     8 + "os"
     9 + "path/filepath"
     10 + "time"
     11 + 
     12 + "github.com/sagernet/sing-box/adapter"
     13 + "github.com/sagernet/sing-box/common/geoip"
     14 + "github.com/sagernet/sing-box/common/geosite"
     15 + C "github.com/sagernet/sing-box/constant"
     16 + "github.com/sagernet/sing-box/option"
     17 + "github.com/sagernet/sing/common"
     18 + E "github.com/sagernet/sing/common/exceptions"
     19 + M "github.com/sagernet/sing/common/metadata"
     20 + "github.com/sagernet/sing/common/rw"
     21 +)
     22 + 
     23 +func (r *Router) GeoIPReader() *geoip.Reader {
     24 + return r.geoIPReader
     25 +}
     26 + 
     27 +func (r *Router) LoadGeosite(code string) (adapter.Rule, error) {
     28 + rule, cached := r.geositeCache[code]
     29 + if cached {
     30 + return rule, nil
     31 + }
     32 + items, err := r.geositeReader.Read(code)
     33 + if err != nil {
     34 + return nil, err
     35 + }
     36 + rule, err = NewDefaultRule(r, nil, geosite.Compile(items))
     37 + if err != nil {
     38 + return nil, err
     39 + }
     40 + r.geositeCache[code] = rule
     41 + return rule, nil
     42 +}
     43 + 
     44 +func (r *Router) prepareGeoIPDatabase() error {
     45 + var geoPath string
     46 + if r.geoIPOptions.Path != "" {
     47 + geoPath = r.geoIPOptions.Path
     48 + } else {
     49 + geoPath = "geoip.db"
     50 + if foundPath, loaded := C.FindPath(geoPath); loaded {
     51 + geoPath = foundPath
     52 + }
     53 + }
     54 + geoPath = C.BasePath(geoPath)
     55 + if rw.FileExists(geoPath) {
     56 + geoReader, codes, err := geoip.Open(geoPath)
     57 + if err == nil {
     58 + r.logger.Info("loaded geoip database: ", len(codes), " codes")
     59 + r.geoIPReader = geoReader
     60 + return nil
     61 + }
     62 + }
     63 + if !rw.FileExists(geoPath) {
     64 + r.logger.Warn("geoip database not exists: ", geoPath)
     65 + var err error
     66 + for attempts := 0; attempts < 3; attempts++ {
     67 + err = r.downloadGeoIPDatabase(geoPath)
     68 + if err == nil {
     69 + break
     70 + }
     71 + r.logger.Error("download geoip database: ", err)
     72 + os.Remove(geoPath)
     73 + // time.Sleep(10 * time.Second)
     74 + }
     75 + if err != nil {
     76 + return err
     77 + }
     78 + }
     79 + geoReader, codes, err := geoip.Open(geoPath)
     80 + if err != nil {
     81 + return E.Cause(err, "open geoip database")
     82 + }
     83 + r.logger.Info("loaded geoip database: ", len(codes), " codes")
     84 + r.geoIPReader = geoReader
     85 + return nil
     86 +}
     87 + 
     88 +func (r *Router) prepareGeositeDatabase() error {
     89 + var geoPath string
     90 + if r.geositeOptions.Path != "" {
     91 + geoPath = r.geositeOptions.Path
     92 + } else {
     93 + geoPath = "geosite.db"
     94 + if foundPath, loaded := C.FindPath(geoPath); loaded {
     95 + geoPath = foundPath
     96 + }
     97 + }
     98 + geoPath = C.BasePath(geoPath)
     99 + if !rw.FileExists(geoPath) {
     100 + r.logger.Warn("geosite database not exists: ", geoPath)
     101 + var err error
     102 + for attempts := 0; attempts < 3; attempts++ {
     103 + err = r.downloadGeositeDatabase(geoPath)
     104 + if err == nil {
     105 + break
     106 + }
     107 + r.logger.Error("download geosite database: ", err)
     108 + os.Remove(geoPath)
     109 + // time.Sleep(10 * time.Second)
     110 + }
     111 + if err != nil {
     112 + return err
     113 + }
     114 + }
     115 + geoReader, codes, err := geosite.Open(geoPath)
     116 + if err == nil {
     117 + r.logger.Info("loaded geosite database: ", len(codes), " codes")
     118 + r.geositeReader = geoReader
     119 + } else {
     120 + return E.Cause(err, "open geosite database")
     121 + }
     122 + return nil
     123 +}
     124 + 
     125 +func (r *Router) downloadGeoIPDatabase(savePath string) error {
     126 + var downloadURL string
     127 + if r.geoIPOptions.DownloadURL != "" {
     128 + downloadURL = r.geoIPOptions.DownloadURL
     129 + } else {
     130 + downloadURL = "https://github.com/SagerNet/sing-geoip/releases/latest/download/geoip.db"
     131 + }
     132 + r.logger.Info("downloading geoip database")
     133 + var detour adapter.Outbound
     134 + if r.geoIPOptions.DownloadDetour != "" {
     135 + outbound, loaded := r.Outbound(r.geoIPOptions.DownloadDetour)
     136 + if !loaded {
     137 + return E.New("detour outbound not found: ", r.geoIPOptions.DownloadDetour)
     138 + }
     139 + detour = outbound
     140 + } else {
     141 + detour = r.defaultOutboundForConnection
     142 + }
     143 + 
     144 + if parentDir := filepath.Dir(savePath); parentDir != "" {
     145 + os.MkdirAll(parentDir, 0o755)
     146 + }
     147 + 
     148 + saveFile, err := os.OpenFile(savePath, os.O_CREATE|os.O_WRONLY, 0o644)
     149 + if err != nil {
     150 + return E.Cause(err, "open output file: ", downloadURL)
     151 + }
     152 + defer saveFile.Close()
     153 + 
     154 + httpClient := &http.Client{
     155 + Transport: &http.Transport{
     156 + ForceAttemptHTTP2: true,
     157 + TLSHandshakeTimeout: 5 * time.Second,
     158 + DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
     159 + return detour.DialContext(ctx, network, M.ParseSocksaddr(addr))
     160 + },
     161 + },
     162 + }
     163 + defer httpClient.CloseIdleConnections()
     164 + response, err := httpClient.Get(downloadURL)
     165 + if err != nil {
     166 + return err
     167 + }
     168 + defer response.Body.Close()
     169 + _, err = io.Copy(saveFile, response.Body)
     170 + return err
     171 +}
     172 + 
     173 +func (r *Router) downloadGeositeDatabase(savePath string) error {
     174 + var downloadURL string
     175 + if r.geositeOptions.DownloadURL != "" {
     176 + downloadURL = r.geositeOptions.DownloadURL
     177 + } else {
     178 + downloadURL = "https://github.com/SagerNet/sing-geosite/releases/latest/download/geosite.db"
     179 + }
     180 + r.logger.Info("downloading geosite database")
     181 + var detour adapter.Outbound
     182 + if r.geositeOptions.DownloadDetour != "" {
     183 + outbound, loaded := r.Outbound(r.geositeOptions.DownloadDetour)
     184 + if !loaded {
     185 + return E.New("detour outbound not found: ", r.geositeOptions.DownloadDetour)
     186 + }
     187 + detour = outbound
     188 + } else {
     189 + detour = r.defaultOutboundForConnection
     190 + }
     191 + 
     192 + if parentDir := filepath.Dir(savePath); parentDir != "" {
     193 + os.MkdirAll(parentDir, 0o755)
     194 + }
     195 + 
     196 + saveFile, err := os.OpenFile(savePath, os.O_CREATE|os.O_WRONLY, 0o644)
     197 + if err != nil {
     198 + return E.Cause(err, "open output file: ", downloadURL)
     199 + }
     200 + defer saveFile.Close()
     201 + 
     202 + httpClient := &http.Client{
     203 + Transport: &http.Transport{
     204 + ForceAttemptHTTP2: true,
     205 + TLSHandshakeTimeout: 5 * time.Second,
     206 + DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
     207 + return detour.DialContext(ctx, network, M.ParseSocksaddr(addr))
     208 + },
     209 + },
     210 + }
     211 + defer httpClient.CloseIdleConnections()
     212 + response, err := httpClient.Get(downloadURL)
     213 + if err != nil {
     214 + return err
     215 + }
     216 + defer response.Body.Close()
     217 + _, err = io.Copy(saveFile, response.Body)
     218 + return err
     219 +}
     220 + 
     221 +func hasRule(rules []option.Rule, cond func(rule option.DefaultRule) bool) bool {
     222 + for _, rule := range rules {
     223 + switch rule.Type {
     224 + case C.RuleTypeDefault:
     225 + if cond(rule.DefaultOptions) {
     226 + return true
     227 + }
     228 + case C.RuleTypeLogical:
     229 + for _, subRule := range rule.LogicalOptions.Rules {
     230 + if cond(subRule) {
     231 + return true
     232 + }
     233 + }
     234 + }
     235 + }
     236 + return false
     237 +}
     238 + 
     239 +func hasDNSRule(rules []option.DNSRule, cond func(rule option.DefaultDNSRule) bool) bool {
     240 + for _, rule := range rules {
     241 + switch rule.Type {
     242 + case C.RuleTypeDefault:
     243 + if cond(rule.DefaultOptions) {
     244 + return true
     245 + }
     246 + case C.RuleTypeLogical:
     247 + for _, subRule := range rule.LogicalOptions.Rules {
     248 + if cond(subRule) {
     249 + return true
     250 + }
     251 + }
     252 + }
     253 + }
     254 + return false
     255 +}
     256 + 
     257 +func isGeoIPRule(rule option.DefaultRule) bool {
     258 + return len(rule.SourceGeoIP) > 0 && common.Any(rule.SourceGeoIP, notPrivateNode) || len(rule.GeoIP) > 0 && common.Any(rule.GeoIP, notPrivateNode)
     259 +}
     260 + 
     261 +func isGeoIPDNSRule(rule option.DefaultDNSRule) bool {
     262 + return len(rule.SourceGeoIP) > 0 && common.Any(rule.SourceGeoIP, notPrivateNode)
     263 +}
     264 + 
     265 +func isGeositeRule(rule option.DefaultRule) bool {
     266 + return len(rule.Geosite) > 0
     267 +}
     268 + 
     269 +func isGeositeDNSRule(rule option.DefaultDNSRule) bool {
     270 + return len(rule.Geosite) > 0
     271 +}
     272 + 
     273 +func isProcessRule(rule option.DefaultRule) bool {
     274 + return len(rule.ProcessName) > 0 || len(rule.ProcessPath) > 0 || len(rule.PackageName) > 0 || len(rule.User) > 0 || len(rule.UserID) > 0
     275 +}
     276 + 
     277 +func isProcessDNSRule(rule option.DefaultDNSRule) bool {
     278 + return len(rule.ProcessName) > 0 || len(rule.ProcessPath) > 0 || len(rule.PackageName) > 0 || len(rule.User) > 0 || len(rule.UserID) > 0
     279 +}
     280 + 
     281 +func notPrivateNode(code string) bool {
     282 + return code != "private"
     283 +}
     284 + 
  • ■ ■ ■ ■ ■ ■
    route/router_ip.go
     1 +package route
     2 + 
     3 +import (
     4 + "context"
     5 + 
     6 + "github.com/sagernet/sing-box/adapter"
     7 + "github.com/sagernet/sing-tun"
     8 +)
     9 + 
     10 +func (r *Router) RouteIPConnection(ctx context.Context, conn tun.RouteContext, metadata adapter.InboundContext) tun.RouteAction {
     11 + for i, rule := range r.ipRules {
     12 + if rule.Match(&metadata) {
     13 + if rule.Action() == tun.ActionTypeReject {
     14 + r.logger.InfoContext(ctx, "match[", i, "] ", rule.String(), " => reject")
     15 + return (*tun.ActionReject)(nil)
     16 + }
     17 + detour := rule.Outbound()
     18 + r.logger.InfoContext(ctx, "match[", i, "] ", rule.String(), " => ", detour)
     19 + outbound, loaded := r.Outbound(detour)
     20 + if !loaded {
     21 + r.logger.ErrorContext(ctx, "outbound not found: ", detour)
     22 + break
     23 + }
     24 + ipOutbound, loaded := outbound.(adapter.IPOutbound)
     25 + if !loaded {
     26 + r.logger.ErrorContext(ctx, "outbound have no ip connection support: ", detour)
     27 + break
     28 + }
     29 + destination, err := ipOutbound.NewIPConnection(ctx, conn, metadata)
     30 + if err != nil {
     31 + r.logger.ErrorContext(ctx, err)
     32 + break
     33 + }
     34 + return &tun.ActionDirect{DirectDestination: destination}
     35 + }
     36 + }
     37 + return (*tun.ActionReturn)(nil)
     38 +}
     39 + 
     40 +func (r *Router) NatRequired(outbound string) bool {
     41 + for _, ipRule := range r.ipRules {
     42 + if ipRule.Outbound() == outbound {
     43 + return true
     44 + }
     45 + }
     46 + return false
     47 +}
     48 + 
  • ■ ■ ■ ■ ■ ■
    route/rule_abstract.go
     1 +package route
     2 + 
     3 +import (
     4 + "strings"
     5 + 
     6 + "github.com/sagernet/sing-box/adapter"
     7 + C "github.com/sagernet/sing-box/constant"
     8 + "github.com/sagernet/sing/common"
     9 + F "github.com/sagernet/sing/common/format"
     10 +)
     11 + 
     12 +type abstractDefaultRule struct {
     13 + items []RuleItem
     14 + sourceAddressItems []RuleItem
     15 + sourcePortItems []RuleItem
     16 + destinationAddressItems []RuleItem
     17 + destinationPortItems []RuleItem
     18 + allItems []RuleItem
     19 + invert bool
     20 + outbound string
     21 +}
     22 + 
     23 +func (r *abstractDefaultRule) Type() string {
     24 + return C.RuleTypeDefault
     25 +}
     26 + 
     27 +func (r *abstractDefaultRule) Start() error {
     28 + for _, item := range r.allItems {
     29 + err := common.Start(item)
     30 + if err != nil {
     31 + return err
     32 + }
     33 + }
     34 + return nil
     35 +}
     36 + 
     37 +func (r *abstractDefaultRule) Close() error {
     38 + for _, item := range r.allItems {
     39 + err := common.Close(item)
     40 + if err != nil {
     41 + return err
     42 + }
     43 + }
     44 + return nil
     45 +}
     46 + 
     47 +func (r *abstractDefaultRule) UpdateGeosite() error {
     48 + for _, item := range r.allItems {
     49 + if geositeItem, isSite := item.(*GeositeItem); isSite {
     50 + err := geositeItem.Update()
     51 + if err != nil {
     52 + return err
     53 + }
     54 + }
     55 + }
     56 + return nil
     57 +}
     58 + 
     59 +func (r *abstractDefaultRule) Match(metadata *adapter.InboundContext) bool {
     60 + for _, item := range r.items {
     61 + if !item.Match(metadata) {
     62 + return r.invert
     63 + }
     64 + }
     65 + 
     66 + if len(r.sourceAddressItems) > 0 {
     67 + var sourceAddressMatch bool
     68 + for _, item := range r.sourceAddressItems {
     69 + if item.Match(metadata) {
     70 + sourceAddressMatch = true
     71 + break
     72 + }
     73 + }
     74 + if !sourceAddressMatch {
     75 + return r.invert
     76 + }
     77 + }
     78 + 
     79 + if len(r.sourcePortItems) > 0 {
     80 + var sourcePortMatch bool
     81 + for _, item := range r.sourcePortItems {
     82 + if item.Match(metadata) {
     83 + sourcePortMatch = true
     84 + break
     85 + }
     86 + }
     87 + if !sourcePortMatch {
     88 + return r.invert
     89 + }
     90 + }
     91 + 
     92 + if len(r.destinationAddressItems) > 0 {
     93 + var destinationAddressMatch bool
     94 + for _, item := range r.destinationAddressItems {
     95 + if item.Match(metadata) {
     96 + destinationAddressMatch = true
     97 + break
     98 + }
     99 + }
     100 + if !destinationAddressMatch {
     101 + return r.invert
     102 + }
     103 + }
     104 + 
     105 + if len(r.destinationPortItems) > 0 {
     106 + var destinationPortMatch bool
     107 + for _, item := range r.destinationPortItems {
     108 + if item.Match(metadata) {
     109 + destinationPortMatch = true
     110 + break
     111 + }
     112 + }
     113 + if !destinationPortMatch {
     114 + return r.invert
     115 + }
     116 + }
     117 + 
     118 + return !r.invert
     119 +}
     120 + 
     121 +func (r *abstractDefaultRule) Outbound() string {
     122 + return r.outbound
     123 +}
     124 + 
     125 +func (r *abstractDefaultRule) String() string {
     126 + return strings.Join(F.MapToString(r.allItems), " ")
     127 +}
     128 + 
     129 +type abstractLogicalRule struct {
     130 + rules []adapter.Rule
     131 + mode string
     132 + invert bool
     133 + outbound string
     134 +}
     135 + 
     136 +func (r *abstractLogicalRule) Type() string {
     137 + return C.RuleTypeLogical
     138 +}
     139 + 
     140 +func (r *abstractLogicalRule) UpdateGeosite() error {
     141 + for _, rule := range r.rules {
     142 + err := rule.UpdateGeosite()
     143 + if err != nil {
     144 + return err
     145 + }
     146 + }
     147 + return nil
     148 +}
     149 + 
     150 +func (r *abstractLogicalRule) Start() error {
     151 + for _, rule := range r.rules {
     152 + err := rule.Start()
     153 + if err != nil {
     154 + return err
     155 + }
     156 + }
     157 + return nil
     158 +}
     159 + 
     160 +func (r *abstractLogicalRule) Close() error {
     161 + for _, rule := range r.rules {
     162 + err := rule.Close()
     163 + if err != nil {
     164 + return err
     165 + }
     166 + }
     167 + return nil
     168 +}
     169 + 
     170 +func (r *abstractLogicalRule) Match(metadata *adapter.InboundContext) bool {
     171 + if r.mode == C.LogicalTypeAnd {
     172 + return common.All(r.rules, func(it adapter.Rule) bool {
     173 + return it.Match(metadata)
     174 + }) != r.invert
     175 + } else {
     176 + return common.Any(r.rules, func(it adapter.Rule) bool {
     177 + return it.Match(metadata)
     178 + }) != r.invert
     179 + }
     180 +}
     181 + 
     182 +func (r *abstractLogicalRule) Outbound() string {
     183 + return r.outbound
     184 +}
     185 + 
     186 +func (r *abstractLogicalRule) String() string {
     187 + var op string
     188 + switch r.mode {
     189 + case C.LogicalTypeAnd:
     190 + op = "&&"
     191 + case C.LogicalTypeOr:
     192 + op = "||"
     193 + }
     194 + if !r.invert {
     195 + return strings.Join(F.MapToString(r.rules), " "+op+" ")
     196 + } else {
     197 + return "!(" + strings.Join(F.MapToString(r.rules), " "+op+" ") + ")"
     198 + }
     199 +}
     200 + 
  • ■ ■ ■ ■ ■
    route/rule.go route/rule_default.go
    1 1  package route
    2 2   
    3 3  import (
    4  - "strings"
    5  - 
    6 4   "github.com/sagernet/sing-box/adapter"
    7 5   C "github.com/sagernet/sing-box/constant"
    8 6   "github.com/sagernet/sing-box/log"
    9 7   "github.com/sagernet/sing-box/option"
    10  - "github.com/sagernet/sing/common"
    11 8   E "github.com/sagernet/sing/common/exceptions"
    12  - F "github.com/sagernet/sing/common/format"
    13  - N "github.com/sagernet/sing/common/network"
    14 9  )
    15 10   
    16 11  func NewRule(router adapter.Router, logger log.ContextLogger, options option.Rule) (adapter.Rule, error) {
    skipped 22 lines
    39 34  var _ adapter.Rule = (*DefaultRule)(nil)
    40 35   
    41 36  type DefaultRule struct {
    42  - items []RuleItem
    43  - sourceAddressItems []RuleItem
    44  - sourcePortItems []RuleItem
    45  - destinationAddressItems []RuleItem
    46  - destinationPortItems []RuleItem
    47  - allItems []RuleItem
    48  - invert bool
    49  - outbound string
     37 + abstractDefaultRule
    50 38  }
    51 39   
    52 40  type RuleItem interface {
    skipped 3 lines
    56 44   
    57 45  func NewDefaultRule(router adapter.Router, logger log.ContextLogger, options option.DefaultRule) (*DefaultRule, error) {
    58 46   rule := &DefaultRule{
    59  - invert: options.Invert,
    60  - outbound: options.Outbound,
     47 + abstractDefaultRule{
     48 + invert: options.Invert,
     49 + outbound: options.Outbound,
     50 + },
    61 51   }
    62 52   if len(options.Inbound) > 0 {
    63 53   item := NewInboundRule(options.Inbound)
    skipped 10 lines
    74 64   return nil, E.New("invalid ip version: ", options.IPVersion)
    75 65   }
    76 66   }
    77  - if options.Network != "" {
    78  - switch options.Network {
    79  - case N.NetworkTCP, N.NetworkUDP:
    80  - item := NewNetworkItem(options.Network)
    81  - rule.items = append(rule.items, item)
    82  - rule.allItems = append(rule.allItems, item)
    83  - default:
    84  - return nil, E.New("invalid network: ", options.Network)
    85  - }
     67 + if len(options.Network) > 0 {
     68 + item := NewNetworkItem(options.Network)
     69 + rule.items = append(rule.items, item)
     70 + rule.allItems = append(rule.allItems, item)
    86 71   }
    87 72   if len(options.AuthUser) > 0 {
    88 73   item := NewAuthUserItem(options.AuthUser)
    skipped 113 lines
    202 187   return rule, nil
    203 188  }
    204 189   
    205  -func (r *DefaultRule) Type() string {
    206  - return C.RuleTypeDefault
    207  -}
    208  - 
    209  -func (r *DefaultRule) Start() error {
    210  - for _, item := range r.allItems {
    211  - err := common.Start(item)
    212  - if err != nil {
    213  - return err
    214  - }
    215  - }
    216  - return nil
    217  -}
    218  - 
    219  -func (r *DefaultRule) Close() error {
    220  - for _, item := range r.allItems {
    221  - err := common.Close(item)
    222  - if err != nil {
    223  - return err
    224  - }
    225  - }
    226  - return nil
    227  -}
    228  - 
    229  -func (r *DefaultRule) UpdateGeosite() error {
    230  - for _, item := range r.allItems {
    231  - if geositeItem, isSite := item.(*GeositeItem); isSite {
    232  - err := geositeItem.Update()
    233  - if err != nil {
    234  - return err
    235  - }
    236  - }
    237  - }
    238  - return nil
    239  -}
    240  - 
    241  -func (r *DefaultRule) Match(metadata *adapter.InboundContext) bool {
    242  - for _, item := range r.items {
    243  - if !item.Match(metadata) {
    244  - return r.invert
    245  - }
    246  - }
    247  - 
    248  - if len(r.sourceAddressItems) > 0 {
    249  - var sourceAddressMatch bool
    250  - for _, item := range r.sourceAddressItems {
    251  - if item.Match(metadata) {
    252  - sourceAddressMatch = true
    253  - break
    254  - }
    255  - }
    256  - if !sourceAddressMatch {
    257  - return r.invert
    258  - }
    259  - }
    260  - 
    261  - if len(r.sourcePortItems) > 0 {
    262  - var sourcePortMatch bool
    263  - for _, item := range r.sourcePortItems {
    264  - if item.Match(metadata) {
    265  - sourcePortMatch = true
    266  - break
    267  - }
    268  - }
    269  - if !sourcePortMatch {
    270  - return r.invert
    271  - }
    272  - }
    273  - 
    274  - if len(r.destinationAddressItems) > 0 {
    275  - var destinationAddressMatch bool
    276  - for _, item := range r.destinationAddressItems {
    277  - if item.Match(metadata) {
    278  - destinationAddressMatch = true
    279  - break
    280  - }
    281  - }
    282  - if !destinationAddressMatch {
    283  - return r.invert
    284  - }
    285  - }
    286  - 
    287  - if len(r.destinationPortItems) > 0 {
    288  - var destinationPortMatch bool
    289  - for _, item := range r.destinationPortItems {
    290  - if item.Match(metadata) {
    291  - destinationPortMatch = true
    292  - break
    293  - }
    294  - }
    295  - if !destinationPortMatch {
    296  - return r.invert
    297  - }
    298  - }
    299  - 
    300  - return !r.invert
    301  -}
    302  - 
    303  -func (r *DefaultRule) Outbound() string {
    304  - return r.outbound
    305  -}
    306  - 
    307  -func (r *DefaultRule) String() string {
    308  - if !r.invert {
    309  - return strings.Join(F.MapToString(r.allItems), " ")
    310  - } else {
    311  - return "!(" + strings.Join(F.MapToString(r.allItems), " ") + ")"
    312  - }
    313  -}
    314  - 
    315 190  var _ adapter.Rule = (*LogicalRule)(nil)
    316 191   
    317 192  type LogicalRule struct {
    318  - mode string
    319  - rules []*DefaultRule
    320  - invert bool
    321  - outbound string
     193 + abstractLogicalRule
    322 194  }
    323 195   
    324 196  func NewLogicalRule(router adapter.Router, logger log.ContextLogger, options option.LogicalRule) (*LogicalRule, error) {
    325 197   r := &LogicalRule{
    326  - rules: make([]*DefaultRule, len(options.Rules)),
    327  - invert: options.Invert,
    328  - outbound: options.Outbound,
     198 + abstractLogicalRule{
     199 + rules: make([]adapter.Rule, len(options.Rules)),
     200 + invert: options.Invert,
     201 + outbound: options.Outbound,
     202 + },
    329 203   }
    330 204   switch options.Mode {
    331 205   case C.LogicalTypeAnd:
    skipped 13 lines
    345 219   return r, nil
    346 220  }
    347 221   
    348  -func (r *LogicalRule) Type() string {
    349  - return C.RuleTypeLogical
    350  -}
    351  - 
    352  -func (r *LogicalRule) UpdateGeosite() error {
    353  - for _, rule := range r.rules {
    354  - err := rule.UpdateGeosite()
    355  - if err != nil {
    356  - return err
    357  - }
    358  - }
    359  - return nil
    360  -}
    361  - 
    362  -func (r *LogicalRule) Start() error {
    363  - for _, rule := range r.rules {
    364  - err := rule.Start()
    365  - if err != nil {
    366  - return err
    367  - }
    368  - }
    369  - return nil
    370  -}
    371  - 
    372  -func (r *LogicalRule) Close() error {
    373  - for _, rule := range r.rules {
    374  - err := rule.Close()
    375  - if err != nil {
    376  - return err
    377  - }
    378  - }
    379  - return nil
    380  -}
    381  - 
    382  -func (r *LogicalRule) Match(metadata *adapter.InboundContext) bool {
    383  - if r.mode == C.LogicalTypeAnd {
    384  - return common.All(r.rules, func(it *DefaultRule) bool {
    385  - return it.Match(metadata)
    386  - }) != r.invert
    387  - } else {
    388  - return common.Any(r.rules, func(it *DefaultRule) bool {
    389  - return it.Match(metadata)
    390  - }) != r.invert
    391  - }
    392  -}
    393  - 
    394  -func (r *LogicalRule) Outbound() string {
    395  - return r.outbound
    396  -}
    397  - 
    398  -func (r *LogicalRule) String() string {
    399  - var op string
    400  - switch r.mode {
    401  - case C.LogicalTypeAnd:
    402  - op = "&&"
    403  - case C.LogicalTypeOr:
    404  - op = "||"
    405  - }
    406  - if !r.invert {
    407  - return strings.Join(F.MapToString(r.rules), " "+op+" ")
    408  - } else {
    409  - return "!(" + strings.Join(F.MapToString(r.rules), " "+op+" ") + ")"
    410  - }
    411  -}
    412  - 
  • ■ ■ ■ ■ ■
    route/rule_dns.go
    1 1  package route
    2 2   
    3 3  import (
    4  - "strings"
    5  - 
    6 4   "github.com/sagernet/sing-box/adapter"
    7 5   C "github.com/sagernet/sing-box/constant"
    8 6   "github.com/sagernet/sing-box/log"
    9 7   "github.com/sagernet/sing-box/option"
    10  - "github.com/sagernet/sing/common"
    11 8   E "github.com/sagernet/sing/common/exceptions"
    12  - F "github.com/sagernet/sing/common/format"
    13  - N "github.com/sagernet/sing/common/network"
    14 9  )
    15 10   
    16 11  func NewDNSRule(router adapter.Router, logger log.ContextLogger, options option.DNSRule) (adapter.DNSRule, error) {
    skipped 22 lines
    39 34  var _ adapter.DNSRule = (*DefaultDNSRule)(nil)
    40 35   
    41 36  type DefaultDNSRule struct {
    42  - items []RuleItem
    43  - sourceAddressItems []RuleItem
    44  - sourcePortItems []RuleItem
    45  - destinationAddressItems []RuleItem
    46  - destinationPortItems []RuleItem
    47  - allItems []RuleItem
    48  - invert bool
    49  - outbound string
    50  - disableCache bool
     37 + abstractDefaultRule
     38 + disableCache bool
    51 39  }
    52 40   
    53 41  func NewDefaultDNSRule(router adapter.Router, logger log.ContextLogger, options option.DefaultDNSRule) (*DefaultDNSRule, error) {
    54 42   rule := &DefaultDNSRule{
    55  - invert: options.Invert,
    56  - outbound: options.Server,
     43 + abstractDefaultRule: abstractDefaultRule{
     44 + invert: options.Invert,
     45 + outbound: options.Server,
     46 + },
    57 47   disableCache: options.DisableCache,
    58 48   }
    59 49   if len(options.Inbound) > 0 {
    skipped 16 lines
    76 66   rule.items = append(rule.items, item)
    77 67   rule.allItems = append(rule.allItems, item)
    78 68   }
    79  - if options.Network != "" {
    80  - switch options.Network {
    81  - case N.NetworkTCP, N.NetworkUDP:
    82  - item := NewNetworkItem(options.Network)
    83  - rule.items = append(rule.items, item)
    84  - rule.allItems = append(rule.allItems, item)
    85  - default:
    86  - return nil, E.New("invalid network: ", options.Network)
    87  - }
     69 + if len(options.Network) > 0 {
     70 + item := NewNetworkItem(options.Network)
     71 + rule.items = append(rule.items, item)
     72 + rule.allItems = append(rule.allItems, item)
    88 73   }
    89 74   if len(options.AuthUser) > 0 {
    90 75   item := NewAuthUserItem(options.AuthUser)
    skipped 105 lines
    196 181   return rule, nil
    197 182  }
    198 183   
    199  -func (r *DefaultDNSRule) Type() string {
    200  - return C.RuleTypeDefault
    201  -}
    202  - 
    203  -func (r *DefaultDNSRule) Start() error {
    204  - for _, item := range r.allItems {
    205  - err := common.Start(item)
    206  - if err != nil {
    207  - return err
    208  - }
    209  - }
    210  - return nil
    211  -}
    212  - 
    213  -func (r *DefaultDNSRule) Close() error {
    214  - for _, item := range r.allItems {
    215  - err := common.Close(item)
    216  - if err != nil {
    217  - return err
    218  - }
    219  - }
    220  - return nil
    221  -}
    222  - 
    223  -func (r *DefaultDNSRule) UpdateGeosite() error {
    224  - for _, item := range r.allItems {
    225  - if geositeItem, isSite := item.(*GeositeItem); isSite {
    226  - err := geositeItem.Update()
    227  - if err != nil {
    228  - return err
    229  - }
    230  - }
    231  - }
    232  - return nil
    233  -}
    234  - 
    235  -func (r *DefaultDNSRule) Match(metadata *adapter.InboundContext) bool {
    236  - for _, item := range r.items {
    237  - if !item.Match(metadata) {
    238  - return r.invert
    239  - }
    240  - }
    241  - 
    242  - if len(r.sourceAddressItems) > 0 {
    243  - var sourceAddressMatch bool
    244  - for _, item := range r.sourceAddressItems {
    245  - if item.Match(metadata) {
    246  - sourceAddressMatch = true
    247  - break
    248  - }
    249  - }
    250  - if !sourceAddressMatch {
    251  - return r.invert
    252  - }
    253  - }
    254  - 
    255  - if len(r.sourcePortItems) > 0 {
    256  - var sourcePortMatch bool
    257  - for _, item := range r.sourcePortItems {
    258  - if item.Match(metadata) {
    259  - sourcePortMatch = true
    260  - break
    261  - }
    262  - }
    263  - if !sourcePortMatch {
    264  - return r.invert
    265  - }
    266  - }
    267  - 
    268  - if len(r.destinationAddressItems) > 0 {
    269  - var destinationAddressMatch bool
    270  - for _, item := range r.destinationAddressItems {
    271  - if item.Match(metadata) {
    272  - destinationAddressMatch = true
    273  - break
    274  - }
    275  - }
    276  - if !destinationAddressMatch {
    277  - return r.invert
    278  - }
    279  - }
    280  - 
    281  - if len(r.destinationPortItems) > 0 {
    282  - var destinationPortMatch bool
    283  - for _, item := range r.destinationPortItems {
    284  - if item.Match(metadata) {
    285  - destinationPortMatch = true
    286  - break
    287  - }
    288  - }
    289  - if !destinationPortMatch {
    290  - return r.invert
    291  - }
    292  - }
    293  - 
    294  - return !r.invert
    295  -}
    296  - 
    297  -func (r *DefaultDNSRule) Outbound() string {
    298  - return r.outbound
    299  -}
    300  - 
    301 184  func (r *DefaultDNSRule) DisableCache() bool {
    302 185   return r.disableCache
    303 186  }
    304 187   
    305  -func (r *DefaultDNSRule) String() string {
    306  - return strings.Join(F.MapToString(r.allItems), " ")
    307  -}
    308  - 
    309 188  var _ adapter.DNSRule = (*LogicalDNSRule)(nil)
    310 189   
    311 190  type LogicalDNSRule struct {
    312  - mode string
    313  - rules []*DefaultDNSRule
    314  - invert bool
    315  - outbound string
     191 + abstractLogicalRule
    316 192   disableCache bool
    317 193  }
    318 194   
    319 195  func NewLogicalDNSRule(router adapter.Router, logger log.ContextLogger, options option.LogicalDNSRule) (*LogicalDNSRule, error) {
    320 196   r := &LogicalDNSRule{
    321  - rules: make([]*DefaultDNSRule, len(options.Rules)),
    322  - invert: options.Invert,
    323  - outbound: options.Server,
     197 + abstractLogicalRule: abstractLogicalRule{
     198 + rules: make([]adapter.Rule, len(options.Rules)),
     199 + invert: options.Invert,
     200 + outbound: options.Server,
     201 + },
    324 202   disableCache: options.DisableCache,
    325 203   }
    326 204   switch options.Mode {
    skipped 14 lines
    341 219   return r, nil
    342 220  }
    343 221   
    344  -func (r *LogicalDNSRule) Type() string {
    345  - return C.RuleTypeLogical
    346  -}
    347  - 
    348  -func (r *LogicalDNSRule) UpdateGeosite() error {
    349  - for _, rule := range r.rules {
    350  - err := rule.UpdateGeosite()
    351  - if err != nil {
    352  - return err
    353  - }
    354  - }
    355  - return nil
    356  -}
    357  - 
    358  -func (r *LogicalDNSRule) Start() error {
    359  - for _, rule := range r.rules {
    360  - err := rule.Start()
    361  - if err != nil {
    362  - return err
    363  - }
    364  - }
    365  - return nil
    366  -}
    367  - 
    368  -func (r *LogicalDNSRule) Close() error {
    369  - for _, rule := range r.rules {
    370  - err := rule.Close()
    371  - if err != nil {
    372  - return err
    373  - }
    374  - }
    375  - return nil
    376  -}
    377  - 
    378  -func (r *LogicalDNSRule) Match(metadata *adapter.InboundContext) bool {
    379  - if r.mode == C.LogicalTypeAnd {
    380  - return common.All(r.rules, func(it *DefaultDNSRule) bool {
    381  - return it.Match(metadata)
    382  - }) != r.invert
    383  - } else {
    384  - return common.Any(r.rules, func(it *DefaultDNSRule) bool {
    385  - return it.Match(metadata)
    386  - }) != r.invert
    387  - }
    388  -}
    389  - 
    390  -func (r *LogicalDNSRule) Outbound() string {
    391  - return r.outbound
    392  -}
    393  - 
    394 222  func (r *LogicalDNSRule) DisableCache() bool {
    395 223   return r.disableCache
    396 224  }
    397 225   
    398  -func (r *LogicalDNSRule) String() string {
    399  - var op string
    400  - switch r.mode {
    401  - case C.LogicalTypeAnd:
    402  - op = "&&"
    403  - case C.LogicalTypeOr:
    404  - op = "||"
    405  - }
    406  - if !r.invert {
    407  - return strings.Join(F.MapToString(r.rules), " "+op+" ")
    408  - } else {
    409  - return "!(" + strings.Join(F.MapToString(r.rules), " "+op+" ") + ")"
    410  - }
    411  -}
    412  - 
  • ■ ■ ■ ■ ■ ■
    route/rule_ip.go
     1 +package route
     2 + 
     3 +import (
     4 + "github.com/sagernet/sing-box/adapter"
     5 + C "github.com/sagernet/sing-box/constant"
     6 + "github.com/sagernet/sing-box/log"
     7 + "github.com/sagernet/sing-box/option"
     8 + tun "github.com/sagernet/sing-tun"
     9 + "github.com/sagernet/sing/common"
     10 + E "github.com/sagernet/sing/common/exceptions"
     11 +)
     12 + 
     13 +func NewIPRule(router adapter.Router, logger log.ContextLogger, options option.IPRule) (adapter.IPRule, error) {
     14 + switch options.Type {
     15 + case "", C.RuleTypeDefault:
     16 + if !options.DefaultOptions.IsValid() {
     17 + return nil, E.New("missing conditions")
     18 + }
     19 + if common.IsEmpty(options.DefaultOptions.Action) {
     20 + return nil, E.New("missing action")
     21 + }
     22 + return NewDefaultIPRule(router, logger, options.DefaultOptions)
     23 + case C.RuleTypeLogical:
     24 + if !options.LogicalOptions.IsValid() {
     25 + return nil, E.New("missing conditions")
     26 + }
     27 + if common.IsEmpty(options.DefaultOptions.Action) {
     28 + return nil, E.New("missing action")
     29 + }
     30 + return NewLogicalIPRule(router, logger, options.LogicalOptions)
     31 + default:
     32 + return nil, E.New("unknown rule type: ", options.Type)
     33 + }
     34 +}
     35 + 
     36 +var _ adapter.IPRule = (*DefaultIPRule)(nil)
     37 + 
     38 +type DefaultIPRule struct {
     39 + abstractDefaultRule
     40 + action tun.ActionType
     41 +}
     42 + 
     43 +func NewDefaultIPRule(router adapter.Router, logger log.ContextLogger, options option.DefaultIPRule) (*DefaultIPRule, error) {
     44 + rule := &DefaultIPRule{
     45 + abstractDefaultRule: abstractDefaultRule{
     46 + invert: options.Invert,
     47 + outbound: options.Outbound,
     48 + },
     49 + action: tun.ActionType(options.Action),
     50 + }
     51 + if len(options.Inbound) > 0 {
     52 + item := NewInboundRule(options.Inbound)
     53 + rule.items = append(rule.items, item)
     54 + rule.allItems = append(rule.allItems, item)
     55 + }
     56 + if options.IPVersion > 0 {
     57 + switch options.IPVersion {
     58 + case 4, 6:
     59 + item := NewIPVersionItem(options.IPVersion == 6)
     60 + rule.items = append(rule.items, item)
     61 + rule.allItems = append(rule.allItems, item)
     62 + default:
     63 + return nil, E.New("invalid ip version: ", options.IPVersion)
     64 + }
     65 + }
     66 + if len(options.Network) > 0 {
     67 + item := NewNetworkItem(options.Network)
     68 + rule.items = append(rule.items, item)
     69 + rule.allItems = append(rule.allItems, item)
     70 + }
     71 + if len(options.Domain) > 0 || len(options.DomainSuffix) > 0 {
     72 + item := NewDomainItem(options.Domain, options.DomainSuffix)
     73 + rule.destinationAddressItems = append(rule.destinationAddressItems, item)
     74 + rule.allItems = append(rule.allItems, item)
     75 + }
     76 + if len(options.DomainKeyword) > 0 {
     77 + item := NewDomainKeywordItem(options.DomainKeyword)
     78 + rule.destinationAddressItems = append(rule.destinationAddressItems, item)
     79 + rule.allItems = append(rule.allItems, item)
     80 + }
     81 + if len(options.DomainRegex) > 0 {
     82 + item, err := NewDomainRegexItem(options.DomainRegex)
     83 + if err != nil {
     84 + return nil, E.Cause(err, "domain_regex")
     85 + }
     86 + rule.destinationAddressItems = append(rule.destinationAddressItems, item)
     87 + rule.allItems = append(rule.allItems, item)
     88 + }
     89 + if len(options.Geosite) > 0 {
     90 + item := NewGeositeItem(router, logger, options.Geosite)
     91 + rule.destinationAddressItems = append(rule.destinationAddressItems, item)
     92 + rule.allItems = append(rule.allItems, item)
     93 + }
     94 + if len(options.SourceGeoIP) > 0 {
     95 + item := NewGeoIPItem(router, logger, true, options.SourceGeoIP)
     96 + rule.sourceAddressItems = append(rule.sourceAddressItems, item)
     97 + rule.allItems = append(rule.allItems, item)
     98 + }
     99 + if len(options.SourceIPCIDR) > 0 {
     100 + item, err := NewIPCIDRItem(true, options.SourceIPCIDR)
     101 + if err != nil {
     102 + return nil, E.Cause(err, "source_ipcidr")
     103 + }
     104 + rule.sourceAddressItems = append(rule.sourceAddressItems, item)
     105 + rule.allItems = append(rule.allItems, item)
     106 + }
     107 + if len(options.SourcePort) > 0 {
     108 + item := NewPortItem(true, options.SourcePort)
     109 + rule.sourcePortItems = append(rule.sourcePortItems, item)
     110 + rule.allItems = append(rule.allItems, item)
     111 + }
     112 + if len(options.SourcePortRange) > 0 {
     113 + item, err := NewPortRangeItem(true, options.SourcePortRange)
     114 + if err != nil {
     115 + return nil, E.Cause(err, "source_port_range")
     116 + }
     117 + rule.sourcePortItems = append(rule.sourcePortItems, item)
     118 + rule.allItems = append(rule.allItems, item)
     119 + }
     120 + if len(options.Port) > 0 {
     121 + item := NewPortItem(false, options.Port)
     122 + rule.destinationPortItems = append(rule.destinationPortItems, item)
     123 + rule.allItems = append(rule.allItems, item)
     124 + }
     125 + if len(options.PortRange) > 0 {
     126 + item, err := NewPortRangeItem(false, options.PortRange)
     127 + if err != nil {
     128 + return nil, E.Cause(err, "port_range")
     129 + }
     130 + rule.destinationPortItems = append(rule.destinationPortItems, item)
     131 + rule.allItems = append(rule.allItems, item)
     132 + }
     133 + return rule, nil
     134 +}
     135 + 
     136 +func (r *DefaultIPRule) Action() tun.ActionType {
     137 + return r.action
     138 +}
     139 + 
     140 +var _ adapter.IPRule = (*LogicalIPRule)(nil)
     141 + 
     142 +type LogicalIPRule struct {
     143 + abstractLogicalRule
     144 + action tun.ActionType
     145 +}
     146 + 
     147 +func NewLogicalIPRule(router adapter.Router, logger log.ContextLogger, options option.LogicalIPRule) (*LogicalIPRule, error) {
     148 + r := &LogicalIPRule{
     149 + abstractLogicalRule: abstractLogicalRule{
     150 + rules: make([]adapter.Rule, len(options.Rules)),
     151 + invert: options.Invert,
     152 + outbound: options.Outbound,
     153 + },
     154 + action: tun.ActionType(options.Action),
     155 + }
     156 + switch options.Mode {
     157 + case C.LogicalTypeAnd:
     158 + r.mode = C.LogicalTypeAnd
     159 + case C.LogicalTypeOr:
     160 + r.mode = C.LogicalTypeOr
     161 + default:
     162 + return nil, E.New("unknown logical mode: ", options.Mode)
     163 + }
     164 + for i, subRule := range options.Rules {
     165 + rule, err := NewDefaultIPRule(router, logger, subRule)
     166 + if err != nil {
     167 + return nil, E.Cause(err, "sub rule[", i, "]")
     168 + }
     169 + r.rules[i] = rule
     170 + }
     171 + return r, nil
     172 +}
     173 + 
     174 +func (r *LogicalIPRule) Action() tun.ActionType {
     175 + return r.action
     176 +}
     177 + 
  • route/rule_auth_user.go route/rule_item_auth_user.go
    Content is identical
  • route/rule_cidr.go route/rule_item_cidr.go
    Content is identical
  • route/rule_clash_mode.go route/rule_item_clash_mode.go
    Content is identical
  • route/rule_domain.go route/rule_item_domain.go
    Content is identical
  • route/rule_domain_keyword.go route/rule_item_domain_keyword.go
    Content is identical
  • route/rule_domain_regex.go route/rule_item_domain_regex.go
    Content is identical
  • route/rule_geoip.go route/rule_item_geoip.go
    Content is identical
  • route/rule_geosite.go route/rule_item_geosite.go
    Content is identical
  • route/rule_inbound.go route/rule_item_inbound.go
    Content is identical
  • route/rule_ipversion.go route/rule_item_ipversion.go
    Content is identical
  • ■ ■ ■ ■ ■ ■
    route/rule_item_network.go
     1 +package route
     2 + 
     3 +import (
     4 + "strings"
     5 + 
     6 + "github.com/sagernet/sing-box/adapter"
     7 + F "github.com/sagernet/sing/common/format"
     8 +)
     9 + 
     10 +var _ RuleItem = (*NetworkItem)(nil)
     11 + 
     12 +type NetworkItem struct {
     13 + networks []string
     14 + networkMap map[string]bool
     15 +}
     16 + 
     17 +func NewNetworkItem(networks []string) *NetworkItem {
     18 + networkMap := make(map[string]bool)
     19 + for _, network := range networks {
     20 + networkMap[network] = true
     21 + }
     22 + return &NetworkItem{
     23 + networks: networks,
     24 + networkMap: networkMap,
     25 + }
     26 +}
     27 + 
     28 +func (r *NetworkItem) Match(metadata *adapter.InboundContext) bool {
     29 + return r.networkMap[metadata.Network]
     30 +}
     31 + 
     32 +func (r *NetworkItem) String() string {
     33 + description := "network="
     34 + 
     35 + pLen := len(r.networks)
     36 + if pLen == 1 {
     37 + description += F.ToString(r.networks[0])
     38 + } else {
     39 + description += "[" + strings.Join(F.MapToString(r.networks), " ") + "]"
     40 + }
     41 + return description
     42 +}
     43 + 
  • route/rule_outbound.go route/rule_item_outbound.go
    Content is identical
  • route/rule_package_name.go route/rule_item_package_name.go
    Content is identical
  • route/rule_port.go route/rule_item_port.go
    Content is identical
  • route/rule_port_range.go route/rule_item_port_range.go
    Content is identical
  • route/rule_process_name.go route/rule_item_process_name.go
    Content is identical
  • route/rule_process_path.go route/rule_item_process_path.go
    Content is identical
  • route/rule_protocol.go route/rule_item_protocol.go
    Content is identical
  • route/rule_query_type.go route/rule_item_query_type.go
    Content is identical
  • route/rule_user.go route/rule_item_user.go
    Content is identical
  • route/rule_user_id.go route/rule_item_user_id.go
    Content is identical
  • ■ ■ ■ ■ ■ ■
    route/rule_network.go
    1  -package route
    2  - 
    3  -import (
    4  - "github.com/sagernet/sing-box/adapter"
    5  -)
    6  - 
    7  -var _ RuleItem = (*NetworkItem)(nil)
    8  - 
    9  -type NetworkItem struct {
    10  - network string
    11  -}
    12  - 
    13  -func NewNetworkItem(network string) *NetworkItem {
    14  - return &NetworkItem{network}
    15  -}
    16  - 
    17  -func (r *NetworkItem) Match(metadata *adapter.InboundContext) bool {
    18  - return r.network == metadata.Network
    19  -}
    20  - 
    21  -func (r *NetworkItem) String() string {
    22  - return "network=" + r.network
    23  -}
    24  - 
  • ■ ■ ■ ■ ■ ■
    transport/wireguard/client_bind.go
    skipped 99 lines
    100 100  }
    101 101   
    102 102  func (c *ClientBind) Reset() {
    103  - c.connAccess.Lock()
    104  - defer c.connAccess.Unlock()
    105 103   common.Close(common.PtrOrNil(c.conn))
    106 104  }
    107 105   
    108 106  func (c *ClientBind) Close() error {
    109  - c.connAccess.Lock()
    110  - defer c.connAccess.Unlock()
    111 107   common.Close(common.PtrOrNil(c.conn))
    112 108   if c.done == nil {
    113 109   c.done = make(chan struct{})
    skipped 59 lines
  • ■ ■ ■ ■ ■
    transport/wireguard/device.go
    1 1  package wireguard
    2 2   
    3 3  import (
     4 + "net/netip"
     5 + 
     6 + "github.com/sagernet/sing-tun"
    4 7   N "github.com/sagernet/sing/common/network"
    5  - "github.com/sagernet/wireguard-go/tun"
     8 + wgTun "github.com/sagernet/wireguard-go/tun"
    6 9  )
    7 10   
    8 11  type Device interface {
    9  - tun.Device
     12 + wgTun.Device
    10 13   N.Dialer
    11 14   Start() error
     15 + Inet4Address() netip.Addr
     16 + Inet6Address() netip.Addr
    12 17   // NewEndpoint() (stack.LinkEndpoint, error)
    13 18  }
    14 19   
     20 +type NatDevice interface {
     21 + Device
     22 + CreateDestination(session tun.RouteSession, conn tun.RouteContext) tun.DirectDestination
     23 +}
     24 + 
  • ■ ■ ■ ■ ■ ■
    transport/wireguard/device_nat.go
     1 +package wireguard
     2 + 
     3 +import (
     4 + "github.com/sagernet/sing-tun"
     5 + "github.com/sagernet/sing/common/buf"
     6 +)
     7 + 
     8 +var _ Device = (*natDeviceWrapper)(nil)
     9 + 
     10 +type natDeviceWrapper struct {
     11 + Device
     12 + outbound chan *buf.Buffer
     13 + mapping *tun.NatMapping
     14 + writer *tun.NatWriter
     15 +}
     16 + 
     17 +func NewNATDevice(upstream Device, ipRewrite bool) NatDevice {
     18 + wrapper := &natDeviceWrapper{
     19 + Device: upstream,
     20 + outbound: make(chan *buf.Buffer, 256),
     21 + mapping: tun.NewNatMapping(ipRewrite),
     22 + }
     23 + if ipRewrite {
     24 + wrapper.writer = tun.NewNatWriter(upstream.Inet4Address(), upstream.Inet6Address())
     25 + }
     26 + return wrapper
     27 +}
     28 + 
     29 +func (d *natDeviceWrapper) Read(p []byte, offset int) (int, error) {
     30 + select {
     31 + case packet := <-d.outbound:
     32 + defer packet.Release()
     33 + return copy(p[offset:], packet.Bytes()), nil
     34 + default:
     35 + }
     36 + return d.Device.Read(p, offset)
     37 +}
     38 + 
     39 +func (d *natDeviceWrapper) Write(p []byte, offset int) (int, error) {
     40 + packet := p[offset:]
     41 + handled, err := d.mapping.WritePacket(packet)
     42 + if handled {
     43 + return len(packet), err
     44 + }
     45 + return d.Device.Write(p, offset)
     46 +}
     47 + 
     48 +func (d *natDeviceWrapper) CreateDestination(session tun.RouteSession, conn tun.RouteContext) tun.DirectDestination {
     49 + d.mapping.CreateSession(session, conn)
     50 + return &natDestinationWrapper{d, session}
     51 +}
     52 + 
     53 +var _ tun.DirectDestination = (*natDestinationWrapper)(nil)
     54 + 
     55 +type natDestinationWrapper struct {
     56 + device *natDeviceWrapper
     57 + session tun.RouteSession
     58 +}
     59 + 
     60 +func (d *natDestinationWrapper) WritePacket(buffer *buf.Buffer) error {
     61 + if d.device.writer != nil {
     62 + d.device.writer.RewritePacket(buffer.Bytes())
     63 + }
     64 + d.device.outbound <- buffer
     65 + return nil
     66 +}
     67 + 
     68 +func (d *natDestinationWrapper) Close() error {
     69 + d.device.mapping.DeleteSession(d.session)
     70 + return nil
     71 +}
     72 + 
     73 +func (d *natDestinationWrapper) Timeout() bool {
     74 + return false
     75 +}
     76 + 
  • ■ ■ ■ ■ ■ ■
    transport/wireguard/device_nat_gvisor.go
     1 +//go:build with_gvisor
     2 + 
     3 +package wireguard
     4 + 
     5 +import (
     6 + "github.com/sagernet/sing/common"
     7 + "github.com/sagernet/sing/common/buf"
     8 + 
     9 + "gvisor.dev/gvisor/pkg/tcpip/stack"
     10 +)
     11 + 
     12 +func (d *natDestinationWrapper) WritePacketBuffer(buffer *stack.PacketBuffer) error {
     13 + defer buffer.DecRef()
     14 + if d.device.writer != nil {
     15 + d.device.writer.RewritePacketBuffer(buffer)
     16 + }
     17 + var packetLen int
     18 + for _, slice := range buffer.AsSlices() {
     19 + packetLen += len(slice)
     20 + }
     21 + packet := buf.NewSize(packetLen)
     22 + for _, slice := range buffer.AsSlices() {
     23 + common.Must1(packet.Write(slice))
     24 + }
     25 + d.device.outbound <- packet
     26 + return nil
     27 +}
     28 + 
  • ■ ■ ■ ■ ■
    transport/wireguard/device_stack.go
    skipped 7 lines
    8 8   "net/netip"
    9 9   "os"
    10 10   
     11 + "github.com/sagernet/sing-tun"
     12 + "github.com/sagernet/sing/common/buf"
    11 13   E "github.com/sagernet/sing/common/exceptions"
    12 14   M "github.com/sagernet/sing/common/metadata"
    13 15   N "github.com/sagernet/sing/common/network"
    14  - "github.com/sagernet/wireguard-go/tun"
     16 + wgTun "github.com/sagernet/wireguard-go/tun"
    15 17   
    16 18   "gvisor.dev/gvisor/pkg/bufferv2"
    17 19   "gvisor.dev/gvisor/pkg/tcpip"
    skipped 7 lines
    25 27   "gvisor.dev/gvisor/pkg/tcpip/transport/udp"
    26 28  )
    27 29   
    28  -var _ Device = (*StackDevice)(nil)
     30 +var _ NatDevice = (*StackDevice)(nil)
    29 31   
    30 32  const defaultNIC tcpip.NICID = 1
    31 33   
    32 34  type StackDevice struct {
    33  - stack *stack.Stack
    34  - mtu uint32
    35  - events chan tun.Event
    36  - outbound chan *stack.PacketBuffer
    37  - done chan struct{}
    38  - dispatcher stack.NetworkDispatcher
    39  - addr4 tcpip.Address
    40  - addr6 tcpip.Address
     35 + stack *stack.Stack
     36 + mtu uint32
     37 + events chan wgTun.Event
     38 + outbound chan *stack.PacketBuffer
     39 + packetOutbound chan *buf.Buffer
     40 + done chan struct{}
     41 + dispatcher stack.NetworkDispatcher
     42 + addr4 tcpip.Address
     43 + addr6 tcpip.Address
     44 + mapping *tun.NatMapping
     45 + writer *tun.NatWriter
    41 46  }
    42 47   
    43  -func NewStackDevice(localAddresses []netip.Prefix, mtu uint32) (*StackDevice, error) {
     48 +func NewStackDevice(localAddresses []netip.Prefix, mtu uint32, ipRewrite bool) (*StackDevice, error) {
    44 49   ipStack := stack.New(stack.Options{
    45 50   NetworkProtocols: []stack.NetworkProtocolFactory{ipv4.NewProtocol, ipv6.NewProtocol},
    46 51   TransportProtocols: []stack.TransportProtocolFactory{tcp.NewProtocol, udp.NewProtocol, icmp.NewProtocol4, icmp.NewProtocol6},
    47 52   HandleLocal: true,
    48 53   })
    49 54   tunDevice := &StackDevice{
    50  - stack: ipStack,
    51  - mtu: mtu,
    52  - events: make(chan tun.Event, 1),
    53  - outbound: make(chan *stack.PacketBuffer, 256),
    54  - done: make(chan struct{}),
     55 + stack: ipStack,
     56 + mtu: mtu,
     57 + events: make(chan wgTun.Event, 1),
     58 + outbound: make(chan *stack.PacketBuffer, 256),
     59 + packetOutbound: make(chan *buf.Buffer, 256),
     60 + done: make(chan struct{}),
     61 + mapping: tun.NewNatMapping(ipRewrite),
    55 62   }
    56 63   err := ipStack.CreateNIC(defaultNIC, (*wireEndpoint)(tunDevice))
    57 64   if err != nil {
    skipped 18 lines
    76 83   if err != nil {
    77 84   return nil, E.New("parse local address ", protoAddr.AddressWithPrefix, ": ", err.String())
    78 85   }
     86 + }
     87 + if ipRewrite {
     88 + tunDevice.writer = tun.NewNatWriter(tunDevice.Inet4Address(), tunDevice.Inet6Address())
    79 89   }
    80 90   sOpt := tcpip.TCPSACKEnabled(true)
    81 91   ipStack.SetTransportProtocolOption(tcp.ProtocolNumber, &sOpt)
    skipped 60 lines
    142 152   return nil, err
    143 153   }
    144 154   return udpConn, nil
     155 +}
     156 + 
     157 +func (w *StackDevice) Inet4Address() netip.Addr {
     158 + return M.AddrFromIP(net.IP(w.addr4))
     159 +}
     160 + 
     161 +func (w *StackDevice) Inet6Address() netip.Addr {
     162 + return M.AddrFromIP(net.IP(w.addr6))
    145 163  }
    146 164   
    147 165  func (w *StackDevice) Start() error {
    148  - w.events <- tun.EventUp
     166 + w.events <- wgTun.EventUp
    149 167   return nil
    150 168  }
    151 169   
    skipped 13 lines
    165 183   n += copy(p[n:], slice)
    166 184   }
    167 185   return
     186 + case packet := <-w.packetOutbound:
     187 + defer packet.Release()
     188 + n = copy(p[offset:], packet.Bytes())
     189 + return
    168 190   case <-w.done:
    169 191   return 0, os.ErrClosed
    170 192   }
    skipped 4 lines
    175 197   if len(p) == 0 {
    176 198   return
    177 199   }
     200 + handled, err := w.mapping.WritePacket(p)
     201 + if handled {
     202 + return len(p), err
     203 + }
    178 204   var networkProtocol tcpip.NetworkProtocolNumber
    179 205   switch header.IPVersion(p) {
    180 206   case header.IPv4Version:
    skipped 22 lines
    203 229   return "sing-box", nil
    204 230  }
    205 231   
    206  -func (w *StackDevice) Events() chan tun.Event {
     232 +func (w *StackDevice) Events() chan wgTun.Event {
    207 233   return w.events
    208 234  }
    209 235   
    skipped 10 lines
    220 246   w.stack.Wait()
    221 247   close(w.done)
    222 248   return nil
     249 +}
     250 + 
     251 +func (w *StackDevice) CreateDestination(session tun.RouteSession, conn tun.RouteContext) tun.DirectDestination {
     252 + w.mapping.CreateSession(session, conn)
     253 + return &stackNatDestination{
     254 + device: w,
     255 + session: session,
     256 + }
     257 +}
     258 + 
     259 +type stackNatDestination struct {
     260 + device *StackDevice
     261 + session tun.RouteSession
     262 +}
     263 + 
     264 +func (d *stackNatDestination) WritePacket(buffer *buf.Buffer) error {
     265 + if d.device.writer != nil {
     266 + d.device.writer.RewritePacket(buffer.Bytes())
     267 + }
     268 + d.device.packetOutbound <- buffer
     269 + return nil
     270 +}
     271 + 
     272 +func (d *stackNatDestination) WritePacketBuffer(buffer *stack.PacketBuffer) error {
     273 + if d.device.writer != nil {
     274 + d.device.writer.RewritePacketBuffer(buffer)
     275 + }
     276 + d.device.outbound <- buffer
     277 + return nil
     278 +}
     279 + 
     280 +func (d *stackNatDestination) Close() error {
     281 + d.device.mapping.DeleteSession(d.session)
     282 + return nil
     283 +}
     284 + 
     285 +func (d *stackNatDestination) Timeout() bool {
     286 + return false
    223 287  }
    224 288   
    225 289  var _ stack.LinkEndpoint = (*wireEndpoint)(nil)
    skipped 49 lines
  • ■ ■ ■ ■
    transport/wireguard/device_stack_stub.go
    skipped 7 lines
    8 8   "github.com/sagernet/sing-tun"
    9 9  )
    10 10   
    11  -func NewStackDevice(localAddresses []netip.Prefix, mtu uint32) (Device, error) {
     11 +func NewStackDevice(localAddresses []netip.Prefix, mtu uint32, ipRewrite bool) (Device, error) {
    12 12   return nil, tun.ErrGVisorNotIncluded
    13 13  }
    14 14   
  • ■ ■ ■ ■ ■
    transport/wireguard/device_system.go
    skipped 22 lines
    23 23   name string
    24 24   mtu int
    25 25   events chan wgTun.Event
     26 + addr4 netip.Addr
     27 + addr6 netip.Addr
    26 28  }
    27 29   
    28 30  /*func (w *SystemDevice) NewEndpoint() (stack.LinkEndpoint, error) {
    skipped 26 lines
    55 57   if err != nil {
    56 58   return nil, err
    57 59   }
     60 + var inet4Address netip.Addr
     61 + var inet6Address netip.Addr
     62 + if len(inet4Addresses) > 0 {
     63 + inet4Address = inet4Addresses[0].Addr()
     64 + }
     65 + if len(inet6Addresses) > 0 {
     66 + inet6Address = inet6Addresses[0].Addr()
     67 + }
    58 68   return &SystemDevice{
    59  - dialer.NewDefault(router, option.DialerOptions{
     69 + dialer: dialer.NewDefault(router, option.DialerOptions{
    60 70   BindInterface: interfaceName,
    61 71   }),
    62  - tunInterface, interfaceName, int(mtu), make(chan wgTun.Event),
     72 + device: tunInterface,
     73 + name: interfaceName,
     74 + mtu: int(mtu),
     75 + events: make(chan wgTun.Event),
     76 + addr4: inet4Address,
     77 + addr6: inet6Address,
    63 78   }, nil
    64 79  }
    65 80   
    skipped 3 lines
    69 84   
    70 85  func (w *SystemDevice) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
    71 86   return w.dialer.ListenPacket(ctx, destination)
     87 +}
     88 + 
     89 +func (w *SystemDevice) Inet4Address() netip.Addr {
     90 + return w.addr4
     91 +}
     92 + 
     93 +func (w *SystemDevice) Inet6Address() netip.Addr {
     94 + return w.addr6
    72 95  }
    73 96   
    74 97  func (w *SystemDevice) Start() error {
    skipped 5 lines
    80 103   return nil
    81 104  }
    82 105   
    83  -func (w *SystemDevice) Read(bytes []byte, index int) (int, error) {
    84  - return w.device.Read(bytes[index-tun.PacketOffset:])
     106 +func (w *SystemDevice) Read(p []byte, offset int) (int, error) {
     107 + return w.device.Read(p[offset-tun.PacketOffset:])
    85 108  }
    86 109   
    87  -func (w *SystemDevice) Write(bytes []byte, index int) (int, error) {
    88  - return w.device.Write(bytes[index:])
     110 +func (w *SystemDevice) Write(p []byte, offset int) (int, error) {
     111 + return w.device.Write(p[offset:])
    89 112  }
    90 113   
    91 114  func (w *SystemDevice) Flush() error {
    skipped 19 lines
Please wait...
Page is in error, reload to recover