mirror of
https://github.com/SagerNet/sing.git
synced 2025-04-03 11:57:39 +03:00
control: Refactor interface finder
This commit is contained in:
parent
0998999911
commit
cc7e630923
6 changed files with 91 additions and 70 deletions
|
@ -157,6 +157,18 @@ func IndexIndexed[T any](arr []T, block func(index int, it T) bool) int {
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Equal[S ~[]E, E comparable](s1, s2 S) bool {
|
||||||
|
if len(s1) != len(s2) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for i := range s1 {
|
||||||
|
if s1[i] != s2[i] {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
//go:norace
|
//go:norace
|
||||||
func Dup[T any](obj T) T {
|
func Dup[T any](obj T) T {
|
||||||
pointer := uintptr(unsafe.Pointer(&obj))
|
pointer := uintptr(unsafe.Pointer(&obj))
|
||||||
|
@ -268,6 +280,14 @@ func Reverse[T any](arr []T) []T {
|
||||||
return arr
|
return arr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ReverseMap[K comparable, V comparable](m map[K]V) map[V]K {
|
||||||
|
ret := make(map[V]K, len(m))
|
||||||
|
for k, v := range m {
|
||||||
|
ret[v] = k
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
func Done(ctx context.Context) bool {
|
func Done(ctx context.Context) bool {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
|
@ -362,24 +382,3 @@ func Close(closers ...any) error {
|
||||||
}
|
}
|
||||||
return retErr
|
return retErr
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deprecated: wtf is this?
|
|
||||||
type Starter interface {
|
|
||||||
Start() error
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: wtf is this?
|
|
||||||
func Start(starters ...any) error {
|
|
||||||
for _, rawStarter := range starters {
|
|
||||||
if rawStarter == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if starter, isStarter := rawStarter.(Starter); isStarter {
|
|
||||||
err := starter.Start()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -9,15 +9,15 @@ import (
|
||||||
|
|
||||||
func bindToInterface(conn syscall.RawConn, network string, address string, finder InterfaceFinder, interfaceName string, interfaceIndex int, preferInterfaceName bool) error {
|
func bindToInterface(conn syscall.RawConn, network string, address string, finder InterfaceFinder, interfaceName string, interfaceIndex int, preferInterfaceName bool) error {
|
||||||
return Raw(conn, func(fd uintptr) error {
|
return Raw(conn, func(fd uintptr) error {
|
||||||
var err error
|
|
||||||
if interfaceIndex == -1 {
|
if interfaceIndex == -1 {
|
||||||
if finder == nil {
|
if finder == nil {
|
||||||
return os.ErrInvalid
|
return os.ErrInvalid
|
||||||
}
|
}
|
||||||
interfaceIndex, err = finder.InterfaceIndexByName(interfaceName)
|
iif, err := finder.ByName(interfaceName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
interfaceIndex = iif.Index
|
||||||
}
|
}
|
||||||
switch network {
|
switch network {
|
||||||
case "tcp6", "udp6":
|
case "tcp6", "udp6":
|
||||||
|
|
|
@ -3,21 +3,57 @@ package control
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing/common"
|
||||||
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
)
|
)
|
||||||
|
|
||||||
type InterfaceFinder interface {
|
type InterfaceFinder interface {
|
||||||
Update() error
|
Update() error
|
||||||
Interfaces() []Interface
|
Interfaces() []Interface
|
||||||
InterfaceIndexByName(name string) (int, error)
|
ByName(name string) (*Interface, error)
|
||||||
InterfaceNameByIndex(index int) (string, error)
|
ByIndex(index int) (*Interface, error)
|
||||||
InterfaceByAddr(addr netip.Addr) (*Interface, error)
|
ByAddr(addr netip.Addr) (*Interface, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Interface struct {
|
type Interface struct {
|
||||||
Index int
|
Index int
|
||||||
MTU int
|
MTU int
|
||||||
Name string
|
Name string
|
||||||
Addresses []netip.Prefix
|
|
||||||
HardwareAddr net.HardwareAddr
|
HardwareAddr net.HardwareAddr
|
||||||
Flags net.Flags
|
Flags net.Flags
|
||||||
|
Addresses []netip.Prefix
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i Interface) Equals(other Interface) bool {
|
||||||
|
return i.Index == other.Index &&
|
||||||
|
i.MTU == other.MTU &&
|
||||||
|
i.Name == other.Name &&
|
||||||
|
common.Equal(i.HardwareAddr, other.HardwareAddr) &&
|
||||||
|
i.Flags == other.Flags &&
|
||||||
|
common.Equal(i.Addresses, other.Addresses)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i Interface) NetInterface() net.Interface {
|
||||||
|
return *(*net.Interface)(unsafe.Pointer(&i))
|
||||||
|
}
|
||||||
|
|
||||||
|
func InterfaceFromNet(iif net.Interface) (Interface, error) {
|
||||||
|
ifAddrs, err := iif.Addrs()
|
||||||
|
if err != nil {
|
||||||
|
return Interface{}, err
|
||||||
|
}
|
||||||
|
return InterfaceFromNetAddrs(iif, common.Map(ifAddrs, M.PrefixFromNet)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func InterfaceFromNetAddrs(iif net.Interface, addresses []netip.Prefix) Interface {
|
||||||
|
return Interface{
|
||||||
|
Index: iif.Index,
|
||||||
|
MTU: iif.MTU,
|
||||||
|
Name: iif.Name,
|
||||||
|
HardwareAddr: iif.HardwareAddr,
|
||||||
|
Flags: iif.Flags,
|
||||||
|
Addresses: addresses,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,11 +3,8 @@ package control
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
_ "unsafe"
|
|
||||||
|
|
||||||
"github.com/sagernet/sing/common"
|
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
M "github.com/sagernet/sing/common/metadata"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ InterfaceFinder = (*DefaultInterfaceFinder)(nil)
|
var _ InterfaceFinder = (*DefaultInterfaceFinder)(nil)
|
||||||
|
@ -27,18 +24,12 @@ func (f *DefaultInterfaceFinder) Update() error {
|
||||||
}
|
}
|
||||||
interfaces := make([]Interface, 0, len(netIfs))
|
interfaces := make([]Interface, 0, len(netIfs))
|
||||||
for _, netIf := range netIfs {
|
for _, netIf := range netIfs {
|
||||||
ifAddrs, err := netIf.Addrs()
|
var iif Interface
|
||||||
|
iif, err = InterfaceFromNet(netIf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
interfaces = append(interfaces, Interface{
|
interfaces = append(interfaces, iif)
|
||||||
Index: netIf.Index,
|
|
||||||
MTU: netIf.MTU,
|
|
||||||
Name: netIf.Name,
|
|
||||||
Addresses: common.Map(ifAddrs, M.PrefixFromNet),
|
|
||||||
HardwareAddr: netIf.HardwareAddr,
|
|
||||||
Flags: netIf.Flags,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
f.interfaces = interfaces
|
f.interfaces = interfaces
|
||||||
return nil
|
return nil
|
||||||
|
@ -52,46 +43,41 @@ func (f *DefaultInterfaceFinder) Interfaces() []Interface {
|
||||||
return f.interfaces
|
return f.interfaces
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *DefaultInterfaceFinder) InterfaceIndexByName(name string) (int, error) {
|
func (f *DefaultInterfaceFinder) ByName(name string) (*Interface, error) {
|
||||||
for _, netInterface := range f.interfaces {
|
for _, netInterface := range f.interfaces {
|
||||||
if netInterface.Name == name {
|
if netInterface.Name == name {
|
||||||
return netInterface.Index, nil
|
return &netInterface, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
netInterface, err := net.InterfaceByName(name)
|
_, err := net.InterfaceByName(name)
|
||||||
if err != nil {
|
if err == nil {
|
||||||
return 0, err
|
err = f.Update()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return f.ByName(name)
|
||||||
}
|
}
|
||||||
f.Update()
|
return nil, &net.OpError{Op: "route", Net: "ip+net", Source: nil, Addr: &net.IPAddr{IP: nil}, Err: E.New("no such network interface")}
|
||||||
return netInterface.Index, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *DefaultInterfaceFinder) InterfaceNameByIndex(index int) (string, error) {
|
func (f *DefaultInterfaceFinder) ByIndex(index int) (*Interface, error) {
|
||||||
for _, netInterface := range f.interfaces {
|
for _, netInterface := range f.interfaces {
|
||||||
if netInterface.Index == index {
|
if netInterface.Index == index {
|
||||||
return netInterface.Name, nil
|
return &netInterface, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
netInterface, err := net.InterfaceByIndex(index)
|
_, err := net.InterfaceByIndex(index)
|
||||||
if err != nil {
|
if err == nil {
|
||||||
return "", err
|
err = f.Update()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return f.ByIndex(index)
|
||||||
}
|
}
|
||||||
f.Update()
|
return nil, &net.OpError{Op: "route", Net: "ip+net", Source: nil, Addr: &net.IPAddr{IP: nil}, Err: E.New("no such network interface")}
|
||||||
return netInterface.Name, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *DefaultInterfaceFinder) InterfaceByAddr(addr netip.Addr) (*Interface, error) {
|
func (f *DefaultInterfaceFinder) ByAddr(addr netip.Addr) (*Interface, error) {
|
||||||
for _, netInterface := range f.interfaces {
|
|
||||||
for _, prefix := range netInterface.Addresses {
|
|
||||||
if prefix.Contains(addr) {
|
|
||||||
return &netInterface, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
err := f.Update()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
for _, netInterface := range f.interfaces {
|
for _, netInterface := range f.interfaces {
|
||||||
for _, prefix := range netInterface.Addresses {
|
for _, prefix := range netInterface.Addresses {
|
||||||
if prefix.Contains(addr) {
|
if prefix.Contains(addr) {
|
||||||
|
|
|
@ -19,11 +19,11 @@ func bindToInterface(conn syscall.RawConn, network string, address string, finde
|
||||||
if interfaceName == "" {
|
if interfaceName == "" {
|
||||||
return os.ErrInvalid
|
return os.ErrInvalid
|
||||||
}
|
}
|
||||||
var err error
|
iif, err := finder.ByName(interfaceName)
|
||||||
interfaceIndex, err = finder.InterfaceIndexByName(interfaceName)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
interfaceIndex = iif.Index
|
||||||
}
|
}
|
||||||
err := unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_BINDTOIFINDEX, interfaceIndex)
|
err := unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_BINDTOIFINDEX, interfaceIndex)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
|
|
@ -11,19 +11,19 @@ import (
|
||||||
|
|
||||||
func bindToInterface(conn syscall.RawConn, network string, address string, finder InterfaceFinder, interfaceName string, interfaceIndex int, preferInterfaceName bool) error {
|
func bindToInterface(conn syscall.RawConn, network string, address string, finder InterfaceFinder, interfaceName string, interfaceIndex int, preferInterfaceName bool) error {
|
||||||
return Raw(conn, func(fd uintptr) error {
|
return Raw(conn, func(fd uintptr) error {
|
||||||
var err error
|
|
||||||
if interfaceIndex == -1 {
|
if interfaceIndex == -1 {
|
||||||
if finder == nil {
|
if finder == nil {
|
||||||
return os.ErrInvalid
|
return os.ErrInvalid
|
||||||
}
|
}
|
||||||
interfaceIndex, err = finder.InterfaceIndexByName(interfaceName)
|
iif, err := finder.ByName(interfaceName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
interfaceIndex = iif.Index
|
||||||
}
|
}
|
||||||
handle := syscall.Handle(fd)
|
handle := syscall.Handle(fd)
|
||||||
if M.ParseSocksaddr(address).AddrString() == "" {
|
if M.ParseSocksaddr(address).AddrString() == "" {
|
||||||
err = bind4(handle, interfaceIndex)
|
err := bind4(handle, interfaceIndex)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue