Add wifi_ssid and wifi_bssid route and DNS rules

This commit is contained in:
世界 2023-11-18 13:51:32 +08:00
parent 96604c5681
commit 99e5b7bc28
No known key found for this signature in database
GPG Key ID: CD109927C34A63C4
17 changed files with 173 additions and 6 deletions

View File

@ -41,6 +41,7 @@ type Router interface {
NetworkMonitor() tun.NetworkUpdateMonitor
InterfaceMonitor() tun.DefaultInterfaceMonitor
PackageManager() tun.PackageManager
WIFIState() WIFIState
Rules() []Rule
ClashServer() ClashServer
@ -78,3 +79,8 @@ type DNSRule interface {
type InterfaceUpdateListener interface {
InterfaceUpdated()
}
type WIFIState struct {
SSID string
BSSID string
}

View File

@ -1,6 +1,7 @@
package cachefile
import (
"context"
"errors"
"net/netip"
"os"
@ -13,6 +14,7 @@ import (
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing/common"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/service/filemanager"
)
var (
@ -41,7 +43,7 @@ type CacheFile struct {
saveMetadataTimer *time.Timer
}
func Open(path string, cacheID string) (*CacheFile, error) {
func Open(ctx context.Context, path string, cacheID string) (*CacheFile, error) {
const fileMode = 0o666
options := bbolt.Options{Timeout: time.Second}
var (
@ -67,6 +69,10 @@ func Open(path string, cacheID string) (*CacheFile, error) {
if err != nil {
return nil, err
}
err = filemanager.Chown(ctx, path)
if err != nil {
return nil, E.Cause(err, "platform chown")
}
var cacheIDBytes []byte
if cacheID != "" {
cacheIDBytes = append([]byte{0}, []byte(cacheID)...)

View File

@ -148,7 +148,7 @@ func NewServer(ctx context.Context, router adapter.Router, logFactory log.Observ
func (s *Server) PreStart() error {
if s.cacheFilePath != "" {
cacheFile, err := cachefile.Open(s.cacheFilePath, s.cacheID)
cacheFile, err := cachefile.Open(s.ctx, s.cacheFilePath, s.cacheID)
if err != nil {
return E.Cause(err, "open cache file")
}

View File

@ -60,11 +60,11 @@ func (s *CommandServer) handleLogConn(conn net.Conn) error {
for element := s.savedLines.Front(); element != nil; element = element.Next() {
savedLines = append(savedLines, element.Value)
}
s.access.Unlock()
subscription, done, err := s.observer.Subscribe()
if err != nil {
return err
}
s.access.Unlock()
defer s.observer.UnSubscribe(subscription)
for _, line := range savedLines {
err = writeLog(conn, []byte(line))

View File

@ -19,6 +19,7 @@ type PlatformInterface interface {
UsePlatformInterfaceGetter() bool
GetInterfaces() (NetworkInterfaceIterator, error)
UnderNetworkExtension() bool
ReadWIFIState() *WIFIState
ClearDNSCache()
}
@ -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

View File

@ -23,6 +23,7 @@ type Interface interface {
Interfaces() ([]NetworkInterface, error)
UnderNetworkExtension() bool
ClearDNSCache()
ReadWIFIState() adapter.WIFIState
process.Searcher
}

View File

@ -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"
}

2
go.mod
View File

@ -26,7 +26,7 @@ require (
github.com/sagernet/gvisor v0.0.0-20230930141345-5fef6f2e17ab
github.com/sagernet/quic-go v0.40.0
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691
github.com/sagernet/sing v0.2.18-0.20231108041402-4fbbd193203c
github.com/sagernet/sing v0.2.18-0.20231117150934-256fafcd99b6
github.com/sagernet/sing-dns v0.1.11-0.20231116102430-5a2133f5d358
github.com/sagernet/sing-mux v0.1.5-0.20231109075101-6b086ed6bb07
github.com/sagernet/sing-quic v0.1.4-0.20231114135334-e2a6aab55cca

4
go.sum
View File

@ -110,8 +110,8 @@ github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691 h1:5Th31OC6yj8byL
github.com/sagernet/reality v0.0.0-20230406110435-ee17307e7691/go.mod h1:B8lp4WkQ1PwNnrVMM6KyuFR20pU8jYBD+A4EhJovEXU=
github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
github.com/sagernet/sing v0.1.8/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk=
github.com/sagernet/sing v0.2.18-0.20231108041402-4fbbd193203c h1:uask61Pxc3nGqsOSjqnBKrwfODWRoEa80lXm04LNk0E=
github.com/sagernet/sing v0.2.18-0.20231108041402-4fbbd193203c/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo=
github.com/sagernet/sing v0.2.18-0.20231117150934-256fafcd99b6 h1:v6QQn8FPEwF2Wi4jQ0xWg7+NUWMIsnP8uoAG7lua1Qo=
github.com/sagernet/sing v0.2.18-0.20231117150934-256fafcd99b6/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo=
github.com/sagernet/sing-dns v0.1.11-0.20231116102430-5a2133f5d358 h1:psJQg/KXVQTupFFR1liaCAucW+NwCDhe1oYfkmz8EJ8=
github.com/sagernet/sing-dns v0.1.11-0.20231116102430-5a2133f5d358/go.mod h1:vtUimtf7Nq9EdvD5WTpfCr69KL1M7bcgOVKiYBiAY/c=
github.com/sagernet/sing-mux v0.1.5-0.20231109075101-6b086ed6bb07 h1:ncKb5tVOsCQgCsv6UpsA0jinbNb5OQ5GMPJlyQP3EHM=

View File

@ -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"`
}

View File

@ -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"`

View File

@ -86,6 +86,8 @@ type Router struct {
clashServer adapter.ClashServer
v2rayServer adapter.V2RayServer
platformInterface platform.Interface
needWIFIState bool
wifiState adapter.WIFIState
}
func NewRouter(
@ -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,
@ -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
}
@ -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 {
@ -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
}
@ -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)
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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, " "), "]")
}

View File

@ -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, " "), "]")
}