@@ -17,6 +17,7 @@ import (
17
17
R "github.com/sagernet/sing-box/route/rule"
18
18
"github.com/sagernet/sing-mux"
19
19
"github.com/sagernet/sing-tun"
20
+ "github.com/sagernet/sing-tun/ping"
20
21
"github.com/sagernet/sing-vmess"
21
22
"github.com/sagernet/sing/common"
22
23
"github.com/sagernet/sing/common/buf"
@@ -271,6 +272,7 @@ func (r *Router) PreMatch(metadata adapter.InboundContext, routeContext tun.Dire
271
272
if err != nil {
272
273
return nil , err
273
274
}
275
+ var directRouteOutbound adapter.DirectRouteOutbound
274
276
if selectedRule != nil {
275
277
switch action := selectedRule .Action ().(type ) {
276
278
case * R.RuleActionReject :
@@ -296,17 +298,69 @@ func (r *Router) PreMatch(metadata adapter.InboundContext, routeContext tun.Dire
296
298
if ! common .Contains (outbound .Network (), metadata .Network ) {
297
299
return nil , E .New (metadata .Network , " is not supported by outbound: " , action .Outbound )
298
300
}
299
- return outbound .(adapter.DirectRouteOutbound ). NewDirectRouteConnection ( metadata , routeContext , timeout )
301
+ directRouteOutbound = outbound .(adapter.DirectRouteOutbound )
300
302
}
301
303
}
302
- if selectedRule != nil || metadata .Network != N .NetworkICMP {
303
- return nil , nil
304
+ if directRouteOutbound == nil {
305
+ if selectedRule != nil || metadata .Network != N .NetworkICMP {
306
+ return nil , nil
307
+ }
308
+ defaultOutbound := r .outbound .Default ()
309
+ if ! common .Contains (defaultOutbound .Network (), metadata .Network ) {
310
+ return nil , E .New (metadata .Network , " is not supported by default outbound: " , defaultOutbound .Tag ())
311
+ }
312
+ directRouteOutbound = defaultOutbound .(adapter.DirectRouteOutbound )
304
313
}
305
- defaultOutbound := r .outbound .Default ()
306
- if ! common .Contains (defaultOutbound .Network (), metadata .Network ) {
307
- return nil , E .New (metadata .Network , " is not supported by default outbound: " , defaultOutbound .Tag ())
314
+ if metadata .Destination .IsFqdn () {
315
+ if len (metadata .DestinationAddresses ) == 0 {
316
+ var strategy C.DomainStrategy
317
+ if metadata .Source .IsIPv4 () {
318
+ strategy = C .DomainStrategyIPv4Only
319
+ } else {
320
+ strategy = C .DomainStrategyIPv6Only
321
+ }
322
+ err = r .actionResolve (r .ctx , & metadata , & R.RuleActionResolve {
323
+ Strategy : strategy ,
324
+ })
325
+ if err != nil {
326
+ return nil , err
327
+ }
328
+ }
329
+ var newDestination netip.Addr
330
+ if metadata .Source .IsIPv4 () {
331
+ for _ , address := range metadata .DestinationAddresses {
332
+ if address .Is4 () {
333
+ newDestination = address
334
+ break
335
+ }
336
+ }
337
+ } else {
338
+ for _ , address := range metadata .DestinationAddresses {
339
+ if address .Is6 () {
340
+ newDestination = address
341
+ break
342
+ }
343
+ }
344
+ }
345
+ if ! newDestination .IsValid () {
346
+ if metadata .Source .IsIPv4 () {
347
+ return nil , E .New ("no IPv4 address found for domain: " , metadata .Destination .Fqdn )
348
+ } else {
349
+ return nil , E .New ("no IPv6 address found for domain: " , metadata .Destination .Fqdn )
350
+ }
351
+ }
352
+ metadata .Destination = M.Socksaddr {
353
+ Addr : newDestination ,
354
+ }
355
+ routeContext = ping .NewContextDestinationWriter (routeContext , metadata .OriginDestination .Addr )
356
+ var routeDestination tun.DirectRouteDestination
357
+ routeDestination , err = directRouteOutbound .NewDirectRouteConnection (metadata , routeContext , timeout )
358
+ if err != nil {
359
+ return nil , err
360
+ }
361
+ return ping .NewDestinationWriter (routeDestination , newDestination ), nil
308
362
}
309
- return defaultOutbound .(adapter. DirectRouteOutbound ) .NewDirectRouteConnection (metadata , routeContext , timeout )
363
+ return directRouteOutbound .NewDirectRouteConnection (metadata , routeContext , timeout )
310
364
}
311
365
312
366
func (r * Router ) matchRule (
0 commit comments