Improve interface finder

This commit is contained in:
世界 2024-04-12 09:05:39 +08:00
parent 2fa039945c
commit eec2fc325a
No known key found for this signature in database
GPG key ID: CD109927C34A63C4
5 changed files with 119 additions and 24 deletions

View file

@ -1,30 +1,18 @@
package control
import "net"
import (
"net/netip"
)
type InterfaceFinder interface {
InterfaceIndexByName(name string) (int, error)
InterfaceNameByIndex(index int) (string, error)
InterfaceByAddr(addr netip.Addr) (*Interface, error)
}
func DefaultInterfaceFinder() InterfaceFinder {
return (*netInterfaceFinder)(nil)
}
type netInterfaceFinder struct{}
func (w *netInterfaceFinder) InterfaceIndexByName(name string) (int, error) {
netInterface, err := net.InterfaceByName(name)
if err != nil {
return 0, err
}
return netInterface.Index, nil
}
func (w *netInterfaceFinder) InterfaceNameByIndex(index int) (string, error) {
netInterface, err := net.InterfaceByIndex(index)
if err != nil {
return "", err
}
return netInterface.Name, nil
type Interface struct {
Index int
MTU int
Name string
Addresses []netip.Prefix
}

View file

@ -0,0 +1,97 @@
package control
import (
"net"
"net/netip"
_ "unsafe"
"github.com/sagernet/sing/common"
M "github.com/sagernet/sing/common/metadata"
)
type DefaultInterfaceFinder struct {
interfaces []Interface
}
func NewDefaultInterfaceFinder() *DefaultInterfaceFinder {
return &DefaultInterfaceFinder{}
}
func (f *DefaultInterfaceFinder) Update() error {
netIfs, err := net.Interfaces()
if err != nil {
return err
}
interfaces := make([]Interface, 0, len(netIfs))
for _, netIf := range netIfs {
ifAddrs, err := netIf.Addrs()
if err != nil {
return err
}
interfaces = append(interfaces, Interface{
Index: netIf.Index,
MTU: netIf.MTU,
Name: netIf.Name,
Addresses: common.Map(ifAddrs, M.PrefixFromNet),
})
}
f.interfaces = interfaces
return nil
}
func (f *DefaultInterfaceFinder) UpdateInterfaces(interfaces []Interface) {
f.interfaces = interfaces
}
func (f *DefaultInterfaceFinder) InterfaceIndexByName(name string) (int, error) {
for _, netInterface := range f.interfaces {
if netInterface.Name == name {
return netInterface.Index, nil
}
}
netInterface, err := net.InterfaceByName(name)
if err != nil {
return 0, err
}
f.Update()
return netInterface.Index, nil
}
func (f *DefaultInterfaceFinder) InterfaceNameByIndex(index int) (string, error) {
for _, netInterface := range f.interfaces {
if netInterface.Index == index {
return netInterface.Name, nil
}
}
netInterface, err := net.InterfaceByIndex(index)
if err != nil {
return "", err
}
f.Update()
return netInterface.Name, nil
}
//go:linkname errNoSuchInterface net.errNoSuchInterface
var errNoSuchInterface error
func (f *DefaultInterfaceFinder) InterfaceByAddr(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 _, prefix := range netInterface.Addresses {
if prefix.Contains(addr) {
return &netInterface, nil
}
}
}
return nil, &net.OpError{Op: "route", Net: "ip+net", Source: nil, Addr: &net.IPAddr{IP: addr.AsSlice()}, Err: errNoSuchInterface}
}

View file

@ -141,7 +141,7 @@ func SocksaddrFromNet(ap net.Addr) Socksaddr {
return ParseSocksaddr(ap.String())
}
func AddrFromNetAddr(netAddr net.Addr) netip.Addr {
func AddrFromNet(netAddr net.Addr) netip.Addr {
if addr := AddrPortFromNet(netAddr); addr.Addr().IsValid() {
return addr.Addr()
}
@ -157,6 +157,16 @@ func AddrFromNetAddr(netAddr net.Addr) netip.Addr {
}
}
func PrefixFromNet(netAddr net.Addr) netip.Prefix {
switch addr := netAddr.(type) {
case *net.IPNet:
bits, _ := addr.Mask.Size()
return netip.PrefixFrom(AddrFromIP(addr.IP), bits)
default:
return netip.Prefix{}
}
}
func AddrPortFromNet(netAddr net.Addr) netip.AddrPort {
var ip net.IP
var port uint16

View file

@ -13,7 +13,7 @@ func LocalAddrs() ([]netip.Addr, error) {
if err != nil {
return nil, err
}
return common.Map(interfaceAddrs, M.AddrFromNetAddr), nil
return common.Map(interfaceAddrs, M.AddrFromNet), nil
}
func IsPublicAddr(addr netip.Addr) bool {

View file

@ -203,7 +203,7 @@ func HandleConnection0(ctx context.Context, conn net.Conn, version byte, authent
return handler.NewConnection(ctx, conn, metadata)
case socks5.CommandUDPAssociate:
var udpConn *net.UDPConn
udpConn, err = net.ListenUDP(M.NetworkFromNetAddr("udp", M.AddrFromNetAddr(conn.LocalAddr())), net.UDPAddrFromAddrPort(netip.AddrPortFrom(M.AddrFromNetAddr(conn.LocalAddr()), 0)))
udpConn, err = net.ListenUDP(M.NetworkFromNetAddr("udp", M.AddrFromNet(conn.LocalAddr())), net.UDPAddrFromAddrPort(netip.AddrPortFrom(M.AddrFromNet(conn.LocalAddr()), 0)))
if err != nil {
return err
}