Skip to content

Commit

Permalink
* net/interfaces: fix android "route ip+net: netlinkrib: permission d…
Browse files Browse the repository at this point in the history
…enied"

Signed-off-by: Asutorufa <16442314+Asutorufa@users.noreply.github.com>
  • Loading branch information
Asutorufa committed Aug 23, 2024
1 parent 5a99940 commit aa9976c
Show file tree
Hide file tree
Showing 5 changed files with 529 additions and 2 deletions.
28 changes: 28 additions & 0 deletions internal/anet/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
BSD 3-Clause License

Copyright (c) 2023, wlynxg

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 changes: 26 additions & 0 deletions internal/anet/interface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//go:build androidxx
// +build androidxx

package anet

import (
"net"
)

// Interfaces returns a list of the system's network interfaces.
func Interfaces() ([]net.Interface, error) {
return net.Interfaces()
}

// InterfaceAddrs returns a list of the system's unicast interface
// addresses.
//
// The returned list does not identify the associated interface; use
// Interfaces and Interface.Addrs for more detail.
func InterfaceAddrs() ([]net.Addr, error) {
return net.InterfaceAddrs()
}

func InterfaceAddrTable(i *net.Interface) ([]net.Addr, error) {
return i.Addrs()
}
179 changes: 179 additions & 0 deletions internal/anet/netlink_androida.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Netlink sockets and messages

package anet

import (
"syscall"
"unsafe"
)

// Round the length of a netlink message up to align it properly.
func nlmAlignOf(msglen int) int {
return (msglen + syscall.NLMSG_ALIGNTO - 1) & ^(syscall.NLMSG_ALIGNTO - 1)
}

// Round the length of a netlink route attribute up to align it
// properly.
func rtaAlignOf(attrlen int) int {
return (attrlen + syscall.RTA_ALIGNTO - 1) & ^(syscall.RTA_ALIGNTO - 1)
}

// NetlinkRouteRequest represents a request message to receive routing
// and link states from the kernel.
type NetlinkRouteRequest struct {
Header syscall.NlMsghdr
Data syscall.RtGenmsg
}

func (rr *NetlinkRouteRequest) toWireFormat() []byte {
b := make([]byte, rr.Header.Len)
*(*uint32)(unsafe.Pointer(&b[0:4][0])) = rr.Header.Len
*(*uint16)(unsafe.Pointer(&b[4:6][0])) = rr.Header.Type
*(*uint16)(unsafe.Pointer(&b[6:8][0])) = rr.Header.Flags
*(*uint32)(unsafe.Pointer(&b[8:12][0])) = rr.Header.Seq
*(*uint32)(unsafe.Pointer(&b[12:16][0])) = rr.Header.Pid
b[16] = byte(rr.Data.Family)
return b
}

func newNetlinkRouteRequest(proto, seq, family int) []byte {
rr := &NetlinkRouteRequest{}
rr.Header.Len = uint32(syscall.NLMSG_HDRLEN + syscall.SizeofRtGenmsg)
rr.Header.Type = uint16(proto)
rr.Header.Flags = syscall.NLM_F_DUMP | syscall.NLM_F_REQUEST
rr.Header.Seq = uint32(seq)
rr.Data.Family = uint8(family)
return rr.toWireFormat()
}

// NetlinkRIB returns routing information base, as known as RIB, which
// consists of network facility information, states and parameters.
func NetlinkRIB(proto, family int) ([]byte, error) {
s, err := syscall.Socket(syscall.AF_NETLINK, syscall.SOCK_RAW|syscall.SOCK_CLOEXEC, syscall.NETLINK_ROUTE)
if err != nil {
return nil, err
}
defer syscall.Close(s)
sa := &syscall.SockaddrNetlink{Family: syscall.AF_NETLINK}

wb := newNetlinkRouteRequest(proto, 1, family)
if err := syscall.Sendto(s, wb, 0, sa); err != nil {
return nil, err
}
lsa, err := syscall.Getsockname(s)
if err != nil {
return nil, err
}
lsanl, ok := lsa.(*syscall.SockaddrNetlink)
if !ok {
return nil, syscall.EINVAL
}
var tab []byte
rbNew := make([]byte, syscall.Getpagesize())
done:
for {
rb := rbNew
nr, _, err := syscall.Recvfrom(s, rb, 0)
if err != nil {
return nil, err
}
if nr < syscall.NLMSG_HDRLEN {
return nil, syscall.EINVAL
}
rb = rb[:nr]
tab = append(tab, rb...)
msgs, err := ParseNetlinkMessage(rb)
if err != nil {
return nil, err
}
for _, m := range msgs {
if m.Header.Seq != 1 || m.Header.Pid != lsanl.Pid {
return nil, syscall.EINVAL
}
if m.Header.Type == syscall.NLMSG_DONE {
break done
}
if m.Header.Type == syscall.NLMSG_ERROR {
return nil, syscall.EINVAL
}
}
}
return tab, nil
}

// NetlinkMessage represents a netlink message.
type NetlinkMessage struct {
Header syscall.NlMsghdr
Data []byte
}

// ParseNetlinkMessage parses b as an array of netlink messages and
// returns the slice containing the NetlinkMessage structures.
func ParseNetlinkMessage(b []byte) ([]NetlinkMessage, error) {
var msgs []NetlinkMessage
for len(b) >= syscall.NLMSG_HDRLEN {
h, dbuf, dlen, err := netlinkMessageHeaderAndData(b)
if err != nil {
return nil, err
}
m := NetlinkMessage{Header: *h, Data: dbuf[:int(h.Len)-syscall.NLMSG_HDRLEN]}
msgs = append(msgs, m)
b = b[dlen:]
}
return msgs, nil
}

func netlinkMessageHeaderAndData(b []byte) (*syscall.NlMsghdr, []byte, int, error) {
h := (*syscall.NlMsghdr)(unsafe.Pointer(&b[0]))
l := nlmAlignOf(int(h.Len))
if int(h.Len) < syscall.NLMSG_HDRLEN || l > len(b) {
return nil, nil, 0, syscall.EINVAL
}
return h, b[syscall.NLMSG_HDRLEN:], l, nil
}

// NetlinkRouteAttr represents a netlink route attribute.
type NetlinkRouteAttr struct {
Attr syscall.RtAttr
Value []byte
}

// ParseNetlinkRouteAttr parses m's payload as an array of netlink
// route attributes and returns the slice containing the
// NetlinkRouteAttr structures.
func ParseNetlinkRouteAttr(m *NetlinkMessage) ([]NetlinkRouteAttr, error) {
var b []byte
switch m.Header.Type {
case syscall.RTM_NEWLINK, syscall.RTM_DELLINK:
b = m.Data[syscall.SizeofIfInfomsg:]
case syscall.RTM_NEWADDR, syscall.RTM_DELADDR:
b = m.Data[syscall.SizeofIfAddrmsg:]
case syscall.RTM_NEWROUTE, syscall.RTM_DELROUTE:
b = m.Data[syscall.SizeofRtMsg:]
default:
return nil, syscall.EINVAL
}
var attrs []NetlinkRouteAttr
for len(b) >= syscall.SizeofRtAttr {
a, vbuf, alen, err := netlinkRouteAttrAndValue(b)
if err != nil {
return nil, err
}
ra := NetlinkRouteAttr{Attr: *a, Value: vbuf[:int(a.Len)-syscall.SizeofRtAttr]}
attrs = append(attrs, ra)
b = b[alen:]
}
return attrs, nil
}

func netlinkRouteAttrAndValue(b []byte) (*syscall.RtAttr, []byte, int, error) {
a := (*syscall.RtAttr)(unsafe.Pointer(&b[0]))
if int(a.Len) < syscall.SizeofRtAttr || int(a.Len) > len(b) {
return nil, nil, 0, syscall.EINVAL
}
return a, b[syscall.SizeofRtAttr:], rtaAlignOf(int(a.Len)), nil
}
Loading

0 comments on commit aa9976c

Please sign in to comment.