|
@@ -3,6 +3,8 @@ package netlink
|
|
import (
|
|
import (
|
|
"encoding/binary"
|
|
"encoding/binary"
|
|
"fmt"
|
|
"fmt"
|
|
|
|
+ "io"
|
|
|
|
+ "math/rand"
|
|
"net"
|
|
"net"
|
|
"sync/atomic"
|
|
"sync/atomic"
|
|
"syscall"
|
|
"syscall"
|
|
@@ -38,12 +40,15 @@ type ifreqFlags struct {
|
|
Ifruflags uint16
|
|
Ifruflags uint16
|
|
}
|
|
}
|
|
|
|
|
|
-func nativeEndian() binary.ByteOrder {
|
|
|
|
|
|
+var native binary.ByteOrder
|
|
|
|
+
|
|
|
|
+func init() {
|
|
var x uint32 = 0x01020304
|
|
var x uint32 = 0x01020304
|
|
if *(*byte)(unsafe.Pointer(&x)) == 0x01 {
|
|
if *(*byte)(unsafe.Pointer(&x)) == 0x01 {
|
|
- return binary.BigEndian
|
|
|
|
|
|
+ native = binary.BigEndian
|
|
|
|
+ } else {
|
|
|
|
+ native = binary.LittleEndian
|
|
}
|
|
}
|
|
- return binary.LittleEndian
|
|
|
|
}
|
|
}
|
|
|
|
|
|
func getIpFamily(ip net.IP) int {
|
|
func getIpFamily(ip net.IP) int {
|
|
@@ -80,8 +85,6 @@ func newIfInfomsgChild(parent *RtAttr, family int) *IfInfomsg {
|
|
}
|
|
}
|
|
|
|
|
|
func (msg *IfInfomsg) ToWireFormat() []byte {
|
|
func (msg *IfInfomsg) ToWireFormat() []byte {
|
|
- native := nativeEndian()
|
|
|
|
-
|
|
|
|
length := syscall.SizeofIfInfomsg
|
|
length := syscall.SizeofIfInfomsg
|
|
b := make([]byte, length)
|
|
b := make([]byte, length)
|
|
b[0] = msg.Family
|
|
b[0] = msg.Family
|
|
@@ -110,8 +113,6 @@ func newIfAddrmsg(family int) *IfAddrmsg {
|
|
}
|
|
}
|
|
|
|
|
|
func (msg *IfAddrmsg) ToWireFormat() []byte {
|
|
func (msg *IfAddrmsg) ToWireFormat() []byte {
|
|
- native := nativeEndian()
|
|
|
|
-
|
|
|
|
length := syscall.SizeofIfAddrmsg
|
|
length := syscall.SizeofIfAddrmsg
|
|
b := make([]byte, length)
|
|
b := make([]byte, length)
|
|
b[0] = msg.Family
|
|
b[0] = msg.Family
|
|
@@ -142,8 +143,6 @@ func newRtMsg() *RtMsg {
|
|
}
|
|
}
|
|
|
|
|
|
func (msg *RtMsg) ToWireFormat() []byte {
|
|
func (msg *RtMsg) ToWireFormat() []byte {
|
|
- native := nativeEndian()
|
|
|
|
-
|
|
|
|
length := syscall.SizeofRtMsg
|
|
length := syscall.SizeofRtMsg
|
|
b := make([]byte, length)
|
|
b := make([]byte, length)
|
|
b[0] = msg.Family
|
|
b[0] = msg.Family
|
|
@@ -202,8 +201,6 @@ func (a *RtAttr) Len() int {
|
|
}
|
|
}
|
|
|
|
|
|
func (a *RtAttr) ToWireFormat() []byte {
|
|
func (a *RtAttr) ToWireFormat() []byte {
|
|
- native := nativeEndian()
|
|
|
|
-
|
|
|
|
length := a.Len()
|
|
length := a.Len()
|
|
buf := make([]byte, rtaAlignOf(length))
|
|
buf := make([]byte, rtaAlignOf(length))
|
|
|
|
|
|
@@ -225,14 +222,18 @@ func (a *RtAttr) ToWireFormat() []byte {
|
|
return buf
|
|
return buf
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+func uint32Attr(t int, n uint32) *RtAttr {
|
|
|
|
+ buf := make([]byte, 4)
|
|
|
|
+ native.PutUint32(buf, n)
|
|
|
|
+ return newRtAttr(t, buf)
|
|
|
|
+}
|
|
|
|
+
|
|
type NetlinkRequest struct {
|
|
type NetlinkRequest struct {
|
|
syscall.NlMsghdr
|
|
syscall.NlMsghdr
|
|
Data []NetlinkRequestData
|
|
Data []NetlinkRequestData
|
|
}
|
|
}
|
|
|
|
|
|
func (rr *NetlinkRequest) ToWireFormat() []byte {
|
|
func (rr *NetlinkRequest) ToWireFormat() []byte {
|
|
- native := nativeEndian()
|
|
|
|
-
|
|
|
|
length := rr.Len
|
|
length := rr.Len
|
|
dataBytes := make([][]byte, len(rr.Data))
|
|
dataBytes := make([][]byte, len(rr.Data))
|
|
for i, data := range rr.Data {
|
|
for i, data := range rr.Data {
|
|
@@ -329,36 +330,44 @@ func (s *NetlinkSocket) GetPid() (uint32, error) {
|
|
return 0, ErrWrongSockType
|
|
return 0, ErrWrongSockType
|
|
}
|
|
}
|
|
|
|
|
|
-func (s *NetlinkSocket) HandleAck(seq uint32) error {
|
|
|
|
- native := nativeEndian()
|
|
|
|
|
|
+func (s *NetlinkSocket) CheckMessage(m syscall.NetlinkMessage, seq, pid uint32) error {
|
|
|
|
+ if m.Header.Seq != seq {
|
|
|
|
+ return fmt.Errorf("netlink: invalid seq %d, expected %d", m.Header.Seq, seq)
|
|
|
|
+ }
|
|
|
|
+ if m.Header.Pid != pid {
|
|
|
|
+ return fmt.Errorf("netlink: wrong pid %d, expected %d", m.Header.Pid, pid)
|
|
|
|
+ }
|
|
|
|
+ if m.Header.Type == syscall.NLMSG_DONE {
|
|
|
|
+ return io.EOF
|
|
|
|
+ }
|
|
|
|
+ if m.Header.Type == syscall.NLMSG_ERROR {
|
|
|
|
+ e := int32(native.Uint32(m.Data[0:4]))
|
|
|
|
+ if e == 0 {
|
|
|
|
+ return io.EOF
|
|
|
|
+ }
|
|
|
|
+ return syscall.Errno(-e)
|
|
|
|
+ }
|
|
|
|
+ return nil
|
|
|
|
+}
|
|
|
|
|
|
|
|
+func (s *NetlinkSocket) HandleAck(seq uint32) error {
|
|
pid, err := s.GetPid()
|
|
pid, err := s.GetPid()
|
|
if err != nil {
|
|
if err != nil {
|
|
return err
|
|
return err
|
|
}
|
|
}
|
|
|
|
|
|
-done:
|
|
|
|
|
|
+outer:
|
|
for {
|
|
for {
|
|
msgs, err := s.Receive()
|
|
msgs, err := s.Receive()
|
|
if err != nil {
|
|
if err != nil {
|
|
return err
|
|
return err
|
|
}
|
|
}
|
|
for _, m := range msgs {
|
|
for _, m := range msgs {
|
|
- if m.Header.Seq != seq {
|
|
|
|
- return fmt.Errorf("Wrong Seq nr %d, expected %d", m.Header.Seq, seq)
|
|
|
|
- }
|
|
|
|
- if m.Header.Pid != pid {
|
|
|
|
- return fmt.Errorf("Wrong pid %d, expected %d", m.Header.Pid, pid)
|
|
|
|
- }
|
|
|
|
- if m.Header.Type == syscall.NLMSG_DONE {
|
|
|
|
- break done
|
|
|
|
- }
|
|
|
|
- if m.Header.Type == syscall.NLMSG_ERROR {
|
|
|
|
- error := int32(native.Uint32(m.Data[0:4]))
|
|
|
|
- if error == 0 {
|
|
|
|
- break done
|
|
|
|
|
|
+ if err := s.CheckMessage(m, seq, pid); err != nil {
|
|
|
|
+ if err == io.EOF {
|
|
|
|
+ break outer
|
|
}
|
|
}
|
|
- return syscall.Errno(-error)
|
|
|
|
|
|
+ return err
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -454,17 +463,11 @@ func AddRoute(destination, source, gateway, device string) error {
|
|
wb.AddData(attr)
|
|
wb.AddData(attr)
|
|
}
|
|
}
|
|
|
|
|
|
- var (
|
|
|
|
- native = nativeEndian()
|
|
|
|
- b = make([]byte, 4)
|
|
|
|
- )
|
|
|
|
iface, err := net.InterfaceByName(device)
|
|
iface, err := net.InterfaceByName(device)
|
|
if err != nil {
|
|
if err != nil {
|
|
return err
|
|
return err
|
|
}
|
|
}
|
|
- native.PutUint32(b, uint32(iface.Index))
|
|
|
|
-
|
|
|
|
- wb.AddData(newRtAttr(syscall.RTA_OIF, b))
|
|
|
|
|
|
+ wb.AddData(uint32Attr(syscall.RTA_OIF, uint32(iface.Index)))
|
|
|
|
|
|
if err := s.Send(wb); err != nil {
|
|
if err := s.Send(wb); err != nil {
|
|
return err
|
|
return err
|
|
@@ -538,15 +541,7 @@ func NetworkSetMTU(iface *net.Interface, mtu int) error {
|
|
msg.Index = int32(iface.Index)
|
|
msg.Index = int32(iface.Index)
|
|
msg.Change = DEFAULT_CHANGE
|
|
msg.Change = DEFAULT_CHANGE
|
|
wb.AddData(msg)
|
|
wb.AddData(msg)
|
|
-
|
|
|
|
- var (
|
|
|
|
- b = make([]byte, 4)
|
|
|
|
- native = nativeEndian()
|
|
|
|
- )
|
|
|
|
- native.PutUint32(b, uint32(mtu))
|
|
|
|
-
|
|
|
|
- data := newRtAttr(syscall.IFLA_MTU, b)
|
|
|
|
- wb.AddData(data)
|
|
|
|
|
|
+ wb.AddData(uint32Attr(syscall.IFLA_MTU, uint32(mtu)))
|
|
|
|
|
|
if err := s.Send(wb); err != nil {
|
|
if err := s.Send(wb); err != nil {
|
|
return err
|
|
return err
|
|
@@ -570,15 +565,7 @@ func NetworkSetMaster(iface, master *net.Interface) error {
|
|
msg.Index = int32(iface.Index)
|
|
msg.Index = int32(iface.Index)
|
|
msg.Change = DEFAULT_CHANGE
|
|
msg.Change = DEFAULT_CHANGE
|
|
wb.AddData(msg)
|
|
wb.AddData(msg)
|
|
-
|
|
|
|
- var (
|
|
|
|
- b = make([]byte, 4)
|
|
|
|
- native = nativeEndian()
|
|
|
|
- )
|
|
|
|
- native.PutUint32(b, uint32(master.Index))
|
|
|
|
-
|
|
|
|
- data := newRtAttr(syscall.IFLA_MASTER, b)
|
|
|
|
- wb.AddData(data)
|
|
|
|
|
|
+ wb.AddData(uint32Attr(syscall.IFLA_MASTER, uint32(master.Index)))
|
|
|
|
|
|
if err := s.Send(wb); err != nil {
|
|
if err := s.Send(wb); err != nil {
|
|
return err
|
|
return err
|
|
@@ -602,15 +589,7 @@ func NetworkSetNsPid(iface *net.Interface, nspid int) error {
|
|
msg.Index = int32(iface.Index)
|
|
msg.Index = int32(iface.Index)
|
|
msg.Change = DEFAULT_CHANGE
|
|
msg.Change = DEFAULT_CHANGE
|
|
wb.AddData(msg)
|
|
wb.AddData(msg)
|
|
-
|
|
|
|
- var (
|
|
|
|
- b = make([]byte, 4)
|
|
|
|
- native = nativeEndian()
|
|
|
|
- )
|
|
|
|
- native.PutUint32(b, uint32(nspid))
|
|
|
|
-
|
|
|
|
- data := newRtAttr(syscall.IFLA_NET_NS_PID, b)
|
|
|
|
- wb.AddData(data)
|
|
|
|
|
|
+ wb.AddData(uint32Attr(syscall.IFLA_NET_NS_PID, uint32(nspid)))
|
|
|
|
|
|
if err := s.Send(wb); err != nil {
|
|
if err := s.Send(wb); err != nil {
|
|
return err
|
|
return err
|
|
@@ -634,15 +613,7 @@ func NetworkSetNsFd(iface *net.Interface, fd int) error {
|
|
msg.Index = int32(iface.Index)
|
|
msg.Index = int32(iface.Index)
|
|
msg.Change = DEFAULT_CHANGE
|
|
msg.Change = DEFAULT_CHANGE
|
|
wb.AddData(msg)
|
|
wb.AddData(msg)
|
|
-
|
|
|
|
- var (
|
|
|
|
- b = make([]byte, 4)
|
|
|
|
- native = nativeEndian()
|
|
|
|
- )
|
|
|
|
- native.PutUint32(b, uint32(fd))
|
|
|
|
-
|
|
|
|
- data := newRtAttr(IFLA_NET_NS_FD, b)
|
|
|
|
- wb.AddData(data)
|
|
|
|
|
|
+ wb.AddData(uint32Attr(IFLA_NET_NS_FD, uint32(fd)))
|
|
|
|
|
|
if err := s.Send(wb); err != nil {
|
|
if err := s.Send(wb); err != nil {
|
|
return err
|
|
return err
|
|
@@ -782,8 +753,6 @@ func NetworkLinkDel(name string) error {
|
|
// Returns an array of IPNet for all the currently routed subnets on ipv4
|
|
// Returns an array of IPNet for all the currently routed subnets on ipv4
|
|
// This is similar to the first column of "ip route" output
|
|
// This is similar to the first column of "ip route" output
|
|
func NetworkGetRoutes() ([]Route, error) {
|
|
func NetworkGetRoutes() ([]Route, error) {
|
|
- native := nativeEndian()
|
|
|
|
-
|
|
|
|
s, err := getNetlinkSocket()
|
|
s, err := getNetlinkSocket()
|
|
if err != nil {
|
|
if err != nil {
|
|
return nil, err
|
|
return nil, err
|
|
@@ -806,28 +775,18 @@ func NetworkGetRoutes() ([]Route, error) {
|
|
|
|
|
|
res := make([]Route, 0)
|
|
res := make([]Route, 0)
|
|
|
|
|
|
-done:
|
|
|
|
|
|
+outer:
|
|
for {
|
|
for {
|
|
msgs, err := s.Receive()
|
|
msgs, err := s.Receive()
|
|
if err != nil {
|
|
if err != nil {
|
|
return nil, err
|
|
return nil, err
|
|
}
|
|
}
|
|
for _, m := range msgs {
|
|
for _, m := range msgs {
|
|
- if m.Header.Seq != wb.Seq {
|
|
|
|
- return nil, fmt.Errorf("Wrong Seq nr %d, expected 1", m.Header.Seq)
|
|
|
|
- }
|
|
|
|
- if m.Header.Pid != pid {
|
|
|
|
- return nil, fmt.Errorf("Wrong pid %d, expected %d", m.Header.Pid, pid)
|
|
|
|
- }
|
|
|
|
- if m.Header.Type == syscall.NLMSG_DONE {
|
|
|
|
- break done
|
|
|
|
- }
|
|
|
|
- if m.Header.Type == syscall.NLMSG_ERROR {
|
|
|
|
- error := int32(native.Uint32(m.Data[0:4]))
|
|
|
|
- if error == 0 {
|
|
|
|
- break done
|
|
|
|
|
|
+ if err := s.CheckMessage(m, wb.Seq, pid); err != nil {
|
|
|
|
+ if err == io.EOF {
|
|
|
|
+ break outer
|
|
}
|
|
}
|
|
- return nil, syscall.Errno(-error)
|
|
|
|
|
|
+ return nil, err
|
|
}
|
|
}
|
|
if m.Header.Type != syscall.RTM_NEWROUTE {
|
|
if m.Header.Type != syscall.RTM_NEWROUTE {
|
|
continue
|
|
continue
|
|
@@ -974,7 +933,7 @@ func CreateBridge(name string, setMacAddr bool) error {
|
|
return err
|
|
return err
|
|
}
|
|
}
|
|
if setMacAddr {
|
|
if setMacAddr {
|
|
- return setBridgeMacAddress(s, name)
|
|
|
|
|
|
+ return NetworkSetMacAddress(name, randMacAddr())
|
|
}
|
|
}
|
|
return nil
|
|
return nil
|
|
}
|
|
}
|
|
@@ -1030,22 +989,40 @@ func AddToBridge(iface, master *net.Interface) error {
|
|
return nil
|
|
return nil
|
|
}
|
|
}
|
|
|
|
|
|
-func setBridgeMacAddress(s int, name string) error {
|
|
|
|
|
|
+func randMacAddr() string {
|
|
|
|
+ hw := make(net.HardwareAddr, 6)
|
|
|
|
+ for i := 0; i < 6; i++ {
|
|
|
|
+ hw[i] = byte(rand.Intn(255))
|
|
|
|
+ }
|
|
|
|
+ hw[0] &^= 0x1 // clear multicast bit
|
|
|
|
+ hw[0] |= 0x2 // set local assignment bit (IEEE802)
|
|
|
|
+ return hw.String()
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func NetworkSetMacAddress(name, addr string) error {
|
|
if len(name) >= IFNAMSIZ {
|
|
if len(name) >= IFNAMSIZ {
|
|
return fmt.Errorf("Interface name %s too long", name)
|
|
return fmt.Errorf("Interface name %s too long", name)
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ hw, err := net.ParseMAC(addr)
|
|
|
|
+ if err != nil {
|
|
|
|
+ return err
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ s, err := getIfSocket()
|
|
|
|
+ if err != nil {
|
|
|
|
+ return err
|
|
|
|
+ }
|
|
|
|
+ defer syscall.Close(s)
|
|
|
|
+
|
|
ifr := ifreqHwaddr{}
|
|
ifr := ifreqHwaddr{}
|
|
ifr.IfruHwaddr.Family = syscall.ARPHRD_ETHER
|
|
ifr.IfruHwaddr.Family = syscall.ARPHRD_ETHER
|
|
copy(ifr.IfrnName[:len(ifr.IfrnName)-1], name)
|
|
copy(ifr.IfrnName[:len(ifr.IfrnName)-1], name)
|
|
|
|
|
|
for i := 0; i < 6; i++ {
|
|
for i := 0; i < 6; i++ {
|
|
- ifr.IfruHwaddr.Data[i] = randIfrDataByte()
|
|
|
|
|
|
+ ifr.IfruHwaddr.Data[i] = ifrDataByte(hw[i])
|
|
}
|
|
}
|
|
|
|
|
|
- ifr.IfruHwaddr.Data[0] &^= 0x1 // clear multicast bit
|
|
|
|
- ifr.IfruHwaddr.Data[0] |= 0x2 // set local assignment bit (IEEE802)
|
|
|
|
-
|
|
|
|
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(s), syscall.SIOCSIFHWADDR, uintptr(unsafe.Pointer(&ifr))); err != 0 {
|
|
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(s), syscall.SIOCSIFHWADDR, uintptr(unsafe.Pointer(&ifr))); err != 0 {
|
|
return err
|
|
return err
|
|
}
|
|
}
|