Skip to content

Commit

Permalink
Improve interface finder
Browse files Browse the repository at this point in the history
  • Loading branch information
nekohasekai committed Apr 12, 2024
1 parent 2fa0399 commit eec2fc3
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 24 deletions.
30 changes: 9 additions & 21 deletions common/control/bind_finder.go
Original file line number Diff line number Diff line change
@@ -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
}
97 changes: 97 additions & 0 deletions common/control/bind_finder_default.go
Original file line number Diff line number Diff line change
@@ -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}
}
12 changes: 11 additions & 1 deletion common/metadata/addr.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion common/network/addr.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion protocol/socks/handshake.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down

0 comments on commit eec2fc3

Please sign in to comment.