Skip to content

Commit

Permalink
Add wifi_ssid and wifi_bssid route and DNS rules
Browse files Browse the repository at this point in the history
  • Loading branch information
nekohasekai committed Nov 24, 2023
1 parent 4fcf29d commit a5cea60
Show file tree
Hide file tree
Showing 12 changed files with 161 additions and 0 deletions.
6 changes: 6 additions & 0 deletions adapter/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ type Router interface {
NetworkMonitor() tun.NetworkUpdateMonitor
InterfaceMonitor() tun.DefaultInterfaceMonitor
PackageManager() tun.PackageManager
WIFIState() WIFIState
Rules() []Rule

ClashServer() ClashServer
Expand Down Expand Up @@ -78,3 +79,8 @@ type DNSRule interface {
type InterfaceUpdateListener interface {
InterfaceUpdated()
}

type WIFIState struct {
SSID string
BSSID string
}
10 changes: 10 additions & 0 deletions experimental/libbox/platform.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ type PlatformInterface interface {
UsePlatformInterfaceGetter() bool
GetInterfaces() (NetworkInterfaceIterator, error)
UnderNetworkExtension() bool
ReadWIFIState() *WIFIState
ClearDNSCache()
}

Expand All @@ -38,6 +39,15 @@ type NetworkInterface struct {
Addresses StringIterator
}

type WIFIState struct {
SSID string
BSSID string
}

func NewWIFIState(wifiSSID string, wifiBSSID string) *WIFIState {
return &WIFIState{wifiSSID, wifiBSSID}
}

type NetworkInterfaceIterator interface {
Next() *NetworkInterface
HasNext() bool
Expand Down
1 change: 1 addition & 0 deletions experimental/libbox/platform/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type Interface interface {
Interfaces() ([]NetworkInterface, error)
UnderNetworkExtension() bool
ClearDNSCache()
ReadWIFIState() adapter.WIFIState
process.Searcher
}

Expand Down
8 changes: 8 additions & 0 deletions experimental/libbox/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,14 @@ func (w *platformInterfaceWrapper) ClearDNSCache() {
w.iif.ClearDNSCache()
}

func (w *platformInterfaceWrapper) ReadWIFIState() adapter.WIFIState {
wifiState := w.iif.ReadWIFIState()
if wifiState == nil {
return adapter.WIFIState{}
}
return (adapter.WIFIState)(*wifiState)
}

func (w *platformInterfaceWrapper) DisableColors() bool {
return runtime.GOOS != "android"
}
Expand Down
2 changes: 2 additions & 0 deletions option/rule.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ type DefaultRule struct {
User Listable[string] `json:"user,omitempty"`
UserID Listable[int32] `json:"user_id,omitempty"`
ClashMode string `json:"clash_mode,omitempty"`
WIFISSID Listable[string] `json:"wifi_ssid,omitempty"`
WIFIBSSID Listable[string] `json:"wifi_bssid,omitempty"`
Invert bool `json:"invert,omitempty"`
Outbound string `json:"outbound,omitempty"`
}
Expand Down
2 changes: 2 additions & 0 deletions option/rule_dns.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ type DefaultDNSRule struct {
UserID Listable[int32] `json:"user_id,omitempty"`
Outbound Listable[string] `json:"outbound,omitempty"`
ClashMode string `json:"clash_mode,omitempty"`
WIFISSID Listable[string] `json:"wifi_ssid,omitempty"`
WIFIBSSID Listable[string] `json:"wifi_bssid,omitempty"`
Invert bool `json:"invert,omitempty"`
Server string `json:"server,omitempty"`
DisableCache bool `json:"disable_cache,omitempty"`
Expand Down
26 changes: 26 additions & 0 deletions route/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ type Router struct {
clashServer adapter.ClashServer
v2rayServer adapter.V2RayServer
platformInterface platform.Interface
needWIFIState bool
wifiState adapter.WIFIState
}

func NewRouter(
Expand Down Expand Up @@ -116,6 +118,7 @@ func NewRouter(
defaultMark: options.DefaultMark,
pauseManager: pause.ManagerFromContext(ctx),
platformInterface: platformInterface,
needWIFIState: hasRule(options.Rules, isWIFIRule) || hasDNSRule(dnsOptions.Rules, isWIFIDNSRule),
}
router.dnsClient = dns.NewClient(dns.ClientOptions{
DisableCache: dnsOptions.DNSClientOptions.DisableCache,
Expand Down Expand Up @@ -328,6 +331,11 @@ func NewRouter(
service.ContextWith[serviceNTP.TimeService](ctx, timeService)
router.timeService = timeService
}
if platformInterface != nil && router.interfaceMonitor != nil && router.needWIFIState {
router.interfaceMonitor.RegisterCallback(func(_ int) {
router.updateWIFIState()
})
}
return router, nil
}

Expand Down Expand Up @@ -468,6 +476,9 @@ func (r *Router) Start() error {
r.geositeCache = nil
r.geositeReader = nil
}
if r.needWIFIState {
r.updateWIFIState()
}
for i, rule := range r.rules {
err := rule.Start()
if err != nil {
Expand Down Expand Up @@ -940,6 +951,10 @@ func (r *Router) Rules() []adapter.Rule {
return r.rules
}

func (r *Router) WIFIState() adapter.WIFIState {
return r.wifiState
}

func (r *Router) NetworkMonitor() tun.NetworkUpdateMonitor {
return r.networkMonitor
}
Expand Down Expand Up @@ -1019,3 +1034,14 @@ func (r *Router) ResetNetwork() error {
}
return nil
}

func (r *Router) updateWIFIState() {
if r.platformInterface == nil {
return
}
state := r.platformInterface.ReadWIFIState()
if state != r.wifiState {
r.wifiState = state
r.logger.Info("updated WIFI state: SSID=", state.SSID, ", BSSID=", state.BSSID)
}
}
8 changes: 8 additions & 0 deletions route/router_geo_resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -307,3 +307,11 @@ func isProcessDNSRule(rule option.DefaultDNSRule) bool {
func notPrivateNode(code string) bool {
return code != "private"
}

func isWIFIRule(rule option.DefaultRule) bool {
return len(rule.WIFISSID) > 0 || len(rule.WIFIBSSID) > 0
}

func isWIFIDNSRule(rule option.DefaultDNSRule) bool {
return len(rule.WIFISSID) > 0 || len(rule.WIFIBSSID) > 0
}
10 changes: 10 additions & 0 deletions route/rule_default.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,16 @@ func NewDefaultRule(router adapter.Router, logger log.ContextLogger, options opt
rule.items = append(rule.items, item)
rule.allItems = append(rule.allItems, item)
}
if len(options.WIFISSID) > 0 {
item := NewWIFISSIDItem(router, options.WIFISSID)
rule.items = append(rule.items, item)
rule.allItems = append(rule.allItems, item)
}
if len(options.WIFIBSSID) > 0 {
item := NewWIFIBSSIDItem(router, options.WIFIBSSID)
rule.items = append(rule.items, item)
rule.allItems = append(rule.allItems, item)
}
return rule, nil
}

Expand Down
10 changes: 10 additions & 0 deletions route/rule_dns.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,16 @@ func NewDefaultDNSRule(router adapter.Router, logger log.ContextLogger, options
rule.items = append(rule.items, item)
rule.allItems = append(rule.allItems, item)
}
if len(options.WIFISSID) > 0 {
item := NewWIFISSIDItem(router, options.WIFISSID)
rule.items = append(rule.items, item)
rule.allItems = append(rule.allItems, item)
}
if len(options.WIFIBSSID) > 0 {
item := NewWIFIBSSIDItem(router, options.WIFIBSSID)
rule.items = append(rule.items, item)
rule.allItems = append(rule.allItems, item)
}
return rule, nil
}

Expand Down
39 changes: 39 additions & 0 deletions route/rule_item_wifi_bssid.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package route

import (
"strings"

"github.com/sagernet/sing-box/adapter"
F "github.com/sagernet/sing/common/format"
)

var _ RuleItem = (*WIFIBSSIDItem)(nil)

type WIFIBSSIDItem struct {
bssidList []string
bssidMap map[string]bool
router adapter.Router
}

func NewWIFIBSSIDItem(router adapter.Router, bssidList []string) *WIFIBSSIDItem {
bssidMap := make(map[string]bool)
for _, bssid := range bssidList {
bssidMap[bssid] = true
}
return &WIFIBSSIDItem{
bssidList,
bssidMap,
router,
}
}

func (r *WIFIBSSIDItem) Match(metadata *adapter.InboundContext) bool {
return r.bssidMap[r.router.WIFIState().BSSID]
}

func (r *WIFIBSSIDItem) String() string {
if len(r.bssidList) == 1 {
return F.ToString("wifi_bssid=", r.bssidList[0])
}
return F.ToString("wifi_bssid=[", strings.Join(r.bssidList, " "), "]")
}
39 changes: 39 additions & 0 deletions route/rule_item_wifi_ssid.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package route

import (
"strings"

"github.com/sagernet/sing-box/adapter"
F "github.com/sagernet/sing/common/format"
)

var _ RuleItem = (*WIFISSIDItem)(nil)

type WIFISSIDItem struct {
ssidList []string
ssidMap map[string]bool
router adapter.Router
}

func NewWIFISSIDItem(router adapter.Router, ssidList []string) *WIFISSIDItem {
ssidMap := make(map[string]bool)
for _, ssid := range ssidList {
ssidMap[ssid] = true
}
return &WIFISSIDItem{
ssidList,
ssidMap,
router,
}
}

func (r *WIFISSIDItem) Match(metadata *adapter.InboundContext) bool {
return r.ssidMap[r.router.WIFIState().SSID]
}

func (r *WIFISSIDItem) String() string {
if len(r.ssidList) == 1 {
return F.ToString("wifi_ssid=", r.ssidList[0])
}
return F.ToString("wifi_ssid=[", strings.Join(r.ssidList, " "), "]")
}

0 comments on commit a5cea60

Please sign in to comment.