|
|
@@ -5,25 +5,30 @@ import (
|
|
|
"errors"
|
|
|
"net"
|
|
|
"os"
|
|
|
+ "sync"
|
|
|
"syscall"
|
|
|
+ "time"
|
|
|
"unsafe"
|
|
|
)
|
|
|
|
|
|
const (
|
|
|
- android11 = 11
|
|
|
+ android11ApiLevel = 30
|
|
|
)
|
|
|
|
|
|
var (
|
|
|
- androidVersion uint
|
|
|
- errNoSuchInterface = errors.New("no such network interface")
|
|
|
- errInvalidInterface = errors.New("invalid network interface")
|
|
|
+ customAndroidApiLevel = -1
|
|
|
+ errInvalidInterface = errors.New("invalid network interface")
|
|
|
+ errInvalidInterfaceIndex = errors.New("invalid network interface index")
|
|
|
+ errInvalidInterfaceName = errors.New("invalid network interface name")
|
|
|
+ errNoSuchInterface = errors.New("no such network interface")
|
|
|
+ errNoSuchMulticastInterface = errors.New("no such multicast network interface")
|
|
|
)
|
|
|
|
|
|
type ifReq [40]byte
|
|
|
|
|
|
// Interfaces returns a list of the system's network interfaces.
|
|
|
func Interfaces() ([]net.Interface, error) {
|
|
|
- if androidVersion > android11 {
|
|
|
+ if androidApiLevel() < android11ApiLevel {
|
|
|
return net.Interfaces()
|
|
|
}
|
|
|
|
|
|
@@ -31,7 +36,10 @@ func Interfaces() ([]net.Interface, error) {
|
|
|
if err != nil {
|
|
|
return nil, &net.OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
|
|
|
}
|
|
|
- // TODO: zoneCache implementation
|
|
|
+ if len(ift) != 0 {
|
|
|
+ zoneCache.update(ift, true)
|
|
|
+ zoneCacheX.update(ift, true)
|
|
|
+ }
|
|
|
return ift, nil
|
|
|
}
|
|
|
|
|
|
@@ -41,7 +49,7 @@ func Interfaces() ([]net.Interface, error) {
|
|
|
// The returned list does not identify the associated interface; use
|
|
|
// Interfaces and Interface.Addrs for more detail.
|
|
|
func InterfaceAddrs() ([]net.Addr, error) {
|
|
|
- if androidVersion > android11 {
|
|
|
+ if androidApiLevel() < android11ApiLevel {
|
|
|
return net.InterfaceAddrs()
|
|
|
}
|
|
|
|
|
|
@@ -52,6 +60,51 @@ func InterfaceAddrs() ([]net.Addr, error) {
|
|
|
return ifat, err
|
|
|
}
|
|
|
|
|
|
+// InterfaceByIndex returns the interface specified by index.
|
|
|
+//
|
|
|
+// On Solaris, it returns one of the logical network interfaces
|
|
|
+// sharing the logical data link; for more precision use
|
|
|
+// InterfaceByName.
|
|
|
+func InterfaceByIndex(index int) (*net.Interface, error) {
|
|
|
+ if androidApiLevel() < android11ApiLevel {
|
|
|
+ return net.InterfaceByIndex(index)
|
|
|
+ }
|
|
|
+
|
|
|
+ if index <= 0 {
|
|
|
+ return nil, &net.OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterfaceIndex}
|
|
|
+ }
|
|
|
+ ift, err := interfaceTable(index)
|
|
|
+ if err != nil {
|
|
|
+ return nil, &net.OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
|
|
|
+ }
|
|
|
+ ifi, err := interfaceByIndex(ift, index)
|
|
|
+ if err != nil {
|
|
|
+ err = &net.OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
|
|
|
+ }
|
|
|
+ return ifi, err
|
|
|
+}
|
|
|
+
|
|
|
+// InterfaceByName returns the interface specified by name.
|
|
|
+func InterfaceByName(name string) (*net.Interface, error) {
|
|
|
+ if name == "" {
|
|
|
+ return nil, &net.OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterfaceName}
|
|
|
+ }
|
|
|
+ ift, err := interfaceTable(0)
|
|
|
+ if err != nil {
|
|
|
+ return nil, &net.OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
|
|
|
+ }
|
|
|
+ if len(ift) != 0 {
|
|
|
+ zoneCache.update(ift, true)
|
|
|
+ zoneCacheX.update(ift, true)
|
|
|
+ }
|
|
|
+ for _, ifi := range ift {
|
|
|
+ if name == ifi.Name {
|
|
|
+ return &ifi, nil
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return nil, &net.OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errNoSuchInterface}
|
|
|
+}
|
|
|
+
|
|
|
// InterfaceAddrsByInterface returns a list of the system's unicast
|
|
|
// interface addresses by specific interface.
|
|
|
func InterfaceAddrsByInterface(ifi *net.Interface) ([]net.Addr, error) {
|
|
|
@@ -59,7 +112,7 @@ func InterfaceAddrsByInterface(ifi *net.Interface) ([]net.Addr, error) {
|
|
|
return nil, &net.OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterface}
|
|
|
}
|
|
|
|
|
|
- if androidVersion > android11 {
|
|
|
+ if androidApiLevel() < android11ApiLevel {
|
|
|
return ifi.Addrs()
|
|
|
}
|
|
|
|
|
|
@@ -73,8 +126,73 @@ func InterfaceAddrsByInterface(ifi *net.Interface) ([]net.Addr, error) {
|
|
|
// SetAndroidVersion set the Android environment in which the program runs.
|
|
|
// The Android system version number can be obtained through
|
|
|
// `android.os.Build.VERSION.RELEASE` of the Android framework.
|
|
|
+// If version is 0 the actual version will be detected automatically if possible.
|
|
|
func SetAndroidVersion(version uint) {
|
|
|
- androidVersion = version
|
|
|
+ switch {
|
|
|
+ case version == 0:
|
|
|
+ customAndroidApiLevel = -1
|
|
|
+ case version >= 11:
|
|
|
+ customAndroidApiLevel = android11ApiLevel
|
|
|
+ default:
|
|
|
+ customAndroidApiLevel = 0
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func androidApiLevel() int {
|
|
|
+ if customAndroidApiLevel != -1 {
|
|
|
+ // user-provided api level should be used
|
|
|
+ return customAndroidApiLevel
|
|
|
+ }
|
|
|
+
|
|
|
+ // try to autodetect api level
|
|
|
+ return androidDeviceApiLevel()
|
|
|
+}
|
|
|
+
|
|
|
+// An ipv6ZoneCache represents a cache holding partial network
|
|
|
+// interface information. It is used for reducing the cost of IPv6
|
|
|
+// addressing scope zone resolution.
|
|
|
+//
|
|
|
+// Multiple names sharing the index are managed by first-come
|
|
|
+// first-served basis for consistency.
|
|
|
+type ipv6ZoneCache struct {
|
|
|
+ sync.RWMutex // guard the following
|
|
|
+ lastFetched time.Time // last time routing information was fetched
|
|
|
+ toIndex map[string]int // interface name to its index
|
|
|
+ toName map[int]string // interface index to its name
|
|
|
+}
|
|
|
+
|
|
|
+//go:linkname zoneCache net.zoneCache
|
|
|
+var zoneCache ipv6ZoneCache
|
|
|
+
|
|
|
+//go:linkname zoneCacheX golang.org/x/net/internal/socket.zoneCache
|
|
|
+var zoneCacheX ipv6ZoneCache
|
|
|
+
|
|
|
+// update refreshes the network interface information if the cache was last
|
|
|
+// updated more than 1 minute ago, or if force is set. It reports whether the
|
|
|
+// cache was updated.
|
|
|
+func (zc *ipv6ZoneCache) update(ift []net.Interface, force bool) (updated bool) {
|
|
|
+ zc.Lock()
|
|
|
+ defer zc.Unlock()
|
|
|
+ now := time.Now()
|
|
|
+ if !force && zc.lastFetched.After(now.Add(-60*time.Second)) {
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ zc.lastFetched = now
|
|
|
+ if len(ift) == 0 {
|
|
|
+ var err error
|
|
|
+ if ift, err = interfaceTable(0); err != nil {
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ }
|
|
|
+ zc.toIndex = make(map[string]int, len(ift))
|
|
|
+ zc.toName = make(map[int]string, len(ift))
|
|
|
+ for _, ifi := range ift {
|
|
|
+ zc.toIndex[ifi.Name] = ifi.Index
|
|
|
+ if _, ok := zc.toName[ifi.Index]; !ok {
|
|
|
+ zc.toName[ifi.Index] = ifi.Name
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return true
|
|
|
}
|
|
|
|
|
|
// If the ifindex is zero, interfaceTable returns mappings of all
|