mirror of
https://github.com/RoganDawes/P4wnP1_aloa.git
synced 2025-03-17 13:21:50 +01:00
514 lines
13 KiB
Diff
514 lines
13 KiB
Diff
--- ../../docker/libcontainer/netlink/netlink_linux.go 2018-05-03 13:34:22.615800101 +0200
|
|
+++ netlink/netlink_linux.go 2018-11-13 12:42:55.325253104 +0100
|
|
@@ -11,6 +11,7 @@
|
|
"syscall"
|
|
"time"
|
|
"unsafe"
|
|
+ "errors"
|
|
)
|
|
|
|
const (
|
|
@@ -31,12 +32,24 @@
|
|
)
|
|
|
|
const (
|
|
- MACVLAN_MODE_PRIVATE = 1 << iota
|
|
+ MACVLAN_MODE_PRIVATE = 1 << iota
|
|
MACVLAN_MODE_VEPA
|
|
MACVLAN_MODE_BRIDGE
|
|
MACVLAN_MODE_PASSTHRU
|
|
)
|
|
|
|
+const (
|
|
+ // See linux/if_arp.h.
|
|
+ // Note that Linux doesn't support IPv4 over IPv6 tunneling.
|
|
+ sysARPHardwareIPv4IPv4 = 768 // IPv4 over IPv4 tunneling
|
|
+ sysARPHardwareIPv6IPv6 = 769 // IPv6 over IPv6 tunneling
|
|
+ sysARPHardwareIPv6IPv4 = 776 // IPv6 over IPv4 tunneling
|
|
+ sysARPHardwareGREIPv4 = 778 // any over GRE over IPv4 tunneling
|
|
+ sysARPHardwareGREIPv6 = 823 // any over GRE over IPv6 tunneling
|
|
+)
|
|
+
|
|
+var errNoSuchInterface = errors.New("no such network interface")
|
|
+
|
|
var nextSeqNr uint32
|
|
|
|
type ifreqHwaddr struct {
|
|
@@ -143,6 +156,29 @@
|
|
return syscall.SizeofIfAddrmsg
|
|
}
|
|
|
|
+type RtGenmsg struct {
|
|
+ syscall.RtGenmsg
|
|
+}
|
|
+
|
|
+func newRtGenMsg(family int) *RtGenmsg {
|
|
+ return &RtGenmsg{
|
|
+ RtGenmsg: syscall.RtGenmsg{
|
|
+ Family: uint8(family),
|
|
+ },
|
|
+ }
|
|
+}
|
|
+
|
|
+func (msg *RtGenmsg) ToWireFormat() []byte {
|
|
+ length := syscall.SizeofRtGenmsg
|
|
+ b := make([]byte, length)
|
|
+ b[0] = msg.Family
|
|
+ return b
|
|
+}
|
|
+
|
|
+func (msg *RtGenmsg) Len() int {
|
|
+ return syscall.SizeofRtGenmsg
|
|
+}
|
|
+
|
|
type RtMsg struct {
|
|
syscall.RtMsg
|
|
}
|
|
@@ -462,6 +498,78 @@
|
|
return s.HandleAck(wb.Seq)
|
|
}
|
|
|
|
+// see https://www.infradead.org/~tgr/libnl/doc/route.html
|
|
+
|
|
+// Returns an array of IPNet for all the currently routed subnets on ipv4
|
|
+// This is similar to the first column of "ip route" output
|
|
+func NetworkLinkGetStateUp(iface *net.Interface) (res bool,err error) {
|
|
+ //fmt.Println("Needed if idx", iface.Index)
|
|
+
|
|
+ s, err := getNetlinkSocket()
|
|
+ if err != nil {
|
|
+ return false,err
|
|
+ }
|
|
+ defer s.Close()
|
|
+
|
|
+ wb := newNetlinkRequest(syscall.RTM_GETLINK, syscall.NLM_F_DUMP)
|
|
+
|
|
+ msg := newIfInfomsg(syscall.AF_UNSPEC)
|
|
+ msg.Index = int32(iface.Index)
|
|
+
|
|
+ wb.AddData(msg)
|
|
+
|
|
+ if err := s.Send(wb); err != nil {
|
|
+ return false, err
|
|
+ }
|
|
+
|
|
+ // retrieve PID
|
|
+ pid, err := s.GetPid()
|
|
+ if err != nil {
|
|
+ return false, err
|
|
+ }
|
|
+
|
|
+outer:
|
|
+// Receive loop
|
|
+ for {
|
|
+ msgs, err := s.Receive()
|
|
+ if err != nil {
|
|
+ return false, err
|
|
+ }
|
|
+ // loop over incoming NL messages
|
|
+ for _, m := range msgs {
|
|
+ // fmt.Printf("Message %+v\n", m)
|
|
+
|
|
+ // check if seq number and receiver PID are correct, abort receive loop on Type == NLMSG_DONE (translated to EOF)
|
|
+ if err := s.CheckMessage(m, wb.Seq, pid); err != nil {
|
|
+ if err == io.EOF {
|
|
+ break outer // abort receive loop if multipart messages reached eof
|
|
+ }
|
|
+ return false, err
|
|
+ }
|
|
+
|
|
+ // the result we want to fetch
|
|
+ if m.Header.Type != syscall.RTM_NEWLINK {
|
|
+ continue
|
|
+ }
|
|
+
|
|
+ //Cast first part to IfInfoMsg
|
|
+ msg := (*IfInfomsg)(unsafe.Pointer(&m.Data[0:syscall.SizeofIfInfomsg][0]))
|
|
+
|
|
+ // Ignore message for different interface
|
|
+ if msg.Index != int32(iface.Index) {
|
|
+ continue
|
|
+ }
|
|
+
|
|
+ if_up := msg.Flags&syscall.IFF_UP != 0
|
|
+ //fmt.Printf("Message: %+v\n", msg)
|
|
+ //fmt.Printf("Flag IFF_UP: %+v\n", if_up)
|
|
+ return if_up, nil
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return false, errors.New("Couldn't retreive link state")
|
|
+}
|
|
+
|
|
// Bring up a particular network interface.
|
|
// This is identical to running: ip link set dev $name up
|
|
func NetworkLinkUp(iface *net.Interface) error {
|
|
@@ -550,6 +658,38 @@
|
|
return s.HandleAck(wb.Seq)
|
|
}
|
|
|
|
+//Added by MaMe82
|
|
+// Bring down a particular network interface.
|
|
+// This is identical to running: ip link set $name down
|
|
+func NetworkSetMulticast(iface *net.Interface, enable bool) error {
|
|
+ s, err := getNetlinkSocket()
|
|
+ if err != nil {
|
|
+ return err
|
|
+ }
|
|
+ defer s.Close()
|
|
+
|
|
+ wb := newNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
|
|
+
|
|
+ msg := newIfInfomsg(syscall.AF_UNSPEC)
|
|
+ msg.Index = int32(iface.Index)
|
|
+ msg.Flags = syscall.NLM_F_REQUEST
|
|
+ msg.Change = DEFAULT_CHANGE
|
|
+ msg.IfInfomsg.Change |= syscall.IFF_MULTICAST
|
|
+ if enable {
|
|
+ msg.IfInfomsg.Flags |= syscall.IFF_MULTICAST
|
|
+ } else {
|
|
+ msg.IfInfomsg.Flags = uint32(int(msg.IfInfomsg.Flags) & ^syscall.IFF_MULTICAST)
|
|
+ }
|
|
+
|
|
+ wb.AddData(msg)
|
|
+
|
|
+ if err := s.Send(wb); err != nil {
|
|
+ return err
|
|
+ }
|
|
+
|
|
+ return s.HandleAck(wb.Seq)
|
|
+}
|
|
+
|
|
// Set link Maximum Transmission Unit
|
|
// This is identical to running: ip link set dev $name mtu $MTU
|
|
// bridge is a bitch here https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=292088
|
|
@@ -907,6 +1047,45 @@
|
|
return s.HandleAck(wb.Seq)
|
|
}
|
|
|
|
+func networkLinkIpAction4(action, flags int, ifa IfAddr, ifa_broadcast IfAddr) error {
|
|
+ s, err := getNetlinkSocket()
|
|
+ if err != nil {
|
|
+ return err
|
|
+ }
|
|
+ defer s.Close()
|
|
+
|
|
+ family := getIpFamily(ifa.IP)
|
|
+ if family != syscall.AF_INET {
|
|
+ return errors.New("Address family has to be AF_INET (IPv4)")
|
|
+ }
|
|
+
|
|
+ wb := newNetlinkRequest(action, flags)
|
|
+
|
|
+ msg := newIfAddrmsg(family)
|
|
+ msg.Index = uint32(ifa.Iface.Index)
|
|
+ prefixLen, _ := ifa.IPNet.Mask.Size()
|
|
+ msg.Prefixlen = uint8(prefixLen)
|
|
+ wb.AddData(msg)
|
|
+
|
|
+ ipData := ifa.IP.To4()
|
|
+
|
|
+ localData := newRtAttr(syscall.IFA_LOCAL, ipData)
|
|
+ wb.AddData(localData)
|
|
+
|
|
+ addrData := newRtAttr(syscall.IFA_ADDRESS, ipData)
|
|
+ wb.AddData(addrData)
|
|
+
|
|
+ ipBcData := ifa_broadcast.IP.To4()
|
|
+ brAddrData := newRtAttr(syscall.IFA_BROADCAST, ipBcData)
|
|
+ wb.AddData(brAddrData)
|
|
+
|
|
+ if err := s.Send(wb); err != nil {
|
|
+ return err
|
|
+ }
|
|
+
|
|
+ return s.HandleAck(wb.Seq)
|
|
+}
|
|
+
|
|
// Delete an IP address from an interface. This is identical to:
|
|
// ip addr del $ip/$ipNet dev $iface
|
|
func NetworkLinkDelIp(iface *net.Interface, ip net.IP, ipNet *net.IPNet) error {
|
|
@@ -917,12 +1096,273 @@
|
|
)
|
|
}
|
|
|
|
+func IpBroadcast4(n *net.IPNet) (net.IP, error) {
|
|
+ ipv4 := n.IP.To4()
|
|
+ if ipv4 == nil {
|
|
+ return nil, errors.New("No IPv4 net")
|
|
+ }
|
|
+ maskv4 := n.Mask
|
|
+ if len(maskv4) == net.IPv6len {
|
|
+ maskv4 = maskv4[12:]
|
|
+ }
|
|
+
|
|
+ res := net.IPv4(0xff, 0xff, 0xff, 0xff).To4()
|
|
+ for i := 0; i < net.IPv4len; i++ {
|
|
+ res[i] = (res[i] ^ maskv4[i]) + ipv4[i]
|
|
+ }
|
|
+ //log.Printf("Calculated broadcast %s", res)
|
|
+ return res, nil
|
|
+}
|
|
+
|
|
// Add an Ip address to an interface. This is identical to:
|
|
// ip addr add $ip/$ipNet dev $iface
|
|
func NetworkLinkAddIp(iface *net.Interface, ip net.IP, ipNet *net.IPNet) error {
|
|
+ family := getIpFamily(ip)
|
|
+ ifa := IfAddr{iface, ip, ipNet}
|
|
+ if family == syscall.AF_INET6 {
|
|
+ return networkLinkIpAction(
|
|
+ syscall.RTM_NEWADDR,
|
|
+ syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK,
|
|
+ ifa,
|
|
+ )
|
|
+ } else {
|
|
+ //For IPv4 calculate broadcast
|
|
+ ipBc, err := IpBroadcast4(ipNet)
|
|
+ //log.Printf("Adding with broadcast ip %v", ipBc)
|
|
+ if err != nil {
|
|
+ return errors.New(fmt.Sprintf("Errof calculating braodcast IP: %v", err))
|
|
+ }
|
|
+ return networkLinkIpAction4(
|
|
+ syscall.RTM_NEWADDR,
|
|
+ syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK,
|
|
+ ifa,
|
|
+ IfAddr{iface, ipBc, ipNet},
|
|
+ )
|
|
+ }
|
|
+
|
|
+}
|
|
+
|
|
+// Add an Ip address to an interface. This is identical to:
|
|
+// ip addr change $ip/$ipNet dev $iface
|
|
+func NetworkLinkChangeIp(iface *net.Interface, ip net.IP, ipNet *net.IPNet) error {
|
|
+ return networkLinkIpAction(
|
|
+ syscall.RTM_NEWADDR,
|
|
+ syscall.NLM_F_REPLACE|syscall.NLM_F_ACK,
|
|
+ IfAddr{iface, ip, ipNet},
|
|
+ )
|
|
+}
|
|
+
|
|
+func linkFlags(rawFlags uint32) net.Flags {
|
|
+ var f net.Flags
|
|
+ if rawFlags&syscall.IFF_UP != 0 {
|
|
+ f |= net.FlagUp
|
|
+ }
|
|
+ if rawFlags&syscall.IFF_BROADCAST != 0 {
|
|
+ f |= net.FlagBroadcast
|
|
+ }
|
|
+ if rawFlags&syscall.IFF_LOOPBACK != 0 {
|
|
+ f |= net.FlagLoopback
|
|
+ }
|
|
+ if rawFlags&syscall.IFF_POINTOPOINT != 0 {
|
|
+ f |= net.FlagPointToPoint
|
|
+ }
|
|
+ if rawFlags&syscall.IFF_MULTICAST != 0 {
|
|
+ f |= net.FlagMulticast
|
|
+ }
|
|
+ return f
|
|
+}
|
|
+
|
|
+func newAddr(ifam *syscall.IfAddrmsg, attrs []syscall.NetlinkRouteAttr) net.Addr {
|
|
+ var ipPointToPoint bool
|
|
+ // Seems like we need to make sure whether the IP interface
|
|
+ // stack consists of IP point-to-point numbered or unnumbered
|
|
+ // addressing.
|
|
+ for _, a := range attrs {
|
|
+ if a.Attr.Type == syscall.IFA_LOCAL {
|
|
+ ipPointToPoint = true
|
|
+ break
|
|
+ }
|
|
+ }
|
|
+ for _, a := range attrs {
|
|
+ if ipPointToPoint && a.Attr.Type == syscall.IFA_ADDRESS {
|
|
+ continue
|
|
+ }
|
|
+ switch ifam.Family {
|
|
+ case syscall.AF_INET:
|
|
+ return &net.IPNet{IP: net.IPv4(a.Value[0], a.Value[1], a.Value[2], a.Value[3]), Mask: net.CIDRMask(int(ifam.Prefixlen), 8*net.IPv4len)}
|
|
+ case syscall.AF_INET6:
|
|
+ ifa := &net.IPNet{IP: make(net.IP, net.IPv6len), Mask: net.CIDRMask(int(ifam.Prefixlen), 8*net.IPv6len)}
|
|
+ copy(ifa.IP, a.Value[:])
|
|
+ return ifa
|
|
+ }
|
|
+ }
|
|
+ return nil
|
|
+}
|
|
+
|
|
+func newLink(ifim *syscall.IfInfomsg, attrs []syscall.NetlinkRouteAttr) *net.Interface {
|
|
+ ifi := &net.Interface{Index: int(ifim.Index), Flags: linkFlags(ifim.Flags)}
|
|
+ for _, a := range attrs {
|
|
+ switch a.Attr.Type {
|
|
+ case syscall.IFLA_ADDRESS:
|
|
+ // We never return any /32 or /128 IP address
|
|
+ // prefix on any IP tunnel interface as the
|
|
+ // hardware address.
|
|
+ switch len(a.Value) {
|
|
+ case net.IPv4len:
|
|
+ switch ifim.Type {
|
|
+ case sysARPHardwareIPv4IPv4, sysARPHardwareGREIPv4, sysARPHardwareIPv6IPv4:
|
|
+ continue
|
|
+ }
|
|
+ case net.IPv6len:
|
|
+ switch ifim.Type {
|
|
+ case sysARPHardwareIPv6IPv6, sysARPHardwareGREIPv6:
|
|
+ continue
|
|
+ }
|
|
+ }
|
|
+ var nonzero bool
|
|
+ for _, b := range a.Value {
|
|
+ if b != 0 {
|
|
+ nonzero = true
|
|
+ break
|
|
+ }
|
|
+ }
|
|
+ if nonzero {
|
|
+ ifi.HardwareAddr = a.Value[:]
|
|
+ }
|
|
+ case syscall.IFLA_IFNAME:
|
|
+ ifi.Name = string(a.Value[:len(a.Value)-1])
|
|
+ case syscall.IFLA_MTU:
|
|
+ ifi.MTU = int(*(*uint32)(unsafe.Pointer(&a.Value[:4][0])))
|
|
+ }
|
|
+ }
|
|
+ return ifi
|
|
+}
|
|
+
|
|
+func interfaceTable(ifindex int) ([]net.Interface, error) {
|
|
+ tab, err := syscall.NetlinkRIB(syscall.RTM_GETLINK, syscall.AF_UNSPEC)
|
|
+ if err != nil {
|
|
+ return nil, os.NewSyscallError("netlinkrib", err)
|
|
+ }
|
|
+ msgs, err := syscall.ParseNetlinkMessage(tab)
|
|
+ if err != nil {
|
|
+ return nil, os.NewSyscallError("parsenetlinkmessage", err)
|
|
+ }
|
|
+ var ift []net.Interface
|
|
+loop:
|
|
+ for _, m := range msgs {
|
|
+ switch m.Header.Type {
|
|
+ case syscall.NLMSG_DONE:
|
|
+ break loop
|
|
+ case syscall.RTM_NEWLINK:
|
|
+ ifim := (*syscall.IfInfomsg)(unsafe.Pointer(&m.Data[0]))
|
|
+ if ifindex == 0 || ifindex == int(ifim.Index) {
|
|
+ attrs, err := syscall.ParseNetlinkRouteAttr(&m)
|
|
+ if err != nil {
|
|
+ return nil, os.NewSyscallError("parsenetlinkrouteattr", err)
|
|
+ }
|
|
+ ift = append(ift, *newLink(ifim, attrs))
|
|
+ if ifindex == int(ifim.Index) {
|
|
+ break loop
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ return ift, nil
|
|
+}
|
|
+
|
|
+func interfaceByIndex(ift []net.Interface, index int) (*net.Interface, error) {
|
|
+ for _, ifi := range ift {
|
|
+ if index == ifi.Index {
|
|
+ return &ifi, nil
|
|
+ }
|
|
+ }
|
|
+ return nil, errNoSuchInterface
|
|
+}
|
|
+
|
|
+func addrTable(ift []net.Interface, ifi *net.Interface, msgs []syscall.NetlinkMessage) ([]net.Addr, error) {
|
|
+ var ifat []net.Addr
|
|
+loop:
|
|
+ for _, m := range msgs {
|
|
+ switch m.Header.Type {
|
|
+ case syscall.NLMSG_DONE:
|
|
+ break loop
|
|
+ case syscall.RTM_NEWADDR:
|
|
+ ifam := (*syscall.IfAddrmsg)(unsafe.Pointer(&m.Data[0]))
|
|
+ if len(ift) != 0 || ifi.Index == int(ifam.Index) {
|
|
+ if len(ift) != 0 {
|
|
+ var err error
|
|
+ ifi, err = interfaceByIndex(ift, int(ifam.Index))
|
|
+
|
|
+ if err != nil {
|
|
+ return nil, err
|
|
+ }
|
|
+ }
|
|
+ attrs, err := syscall.ParseNetlinkRouteAttr(&m)
|
|
+ if err != nil {
|
|
+ return nil, os.NewSyscallError("parsenetlinkrouteattr", err)
|
|
+ }
|
|
+ ifa := newAddr(ifam, attrs)
|
|
+ if ifa != nil {
|
|
+ ifat = append(ifat, ifa)
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ return ifat, nil
|
|
+}
|
|
+
|
|
+func interfaceAddrTable(ifi *net.Interface) ([]net.Addr, error) {
|
|
+ tab, err := syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_UNSPEC)
|
|
+ if err != nil {
|
|
+ return nil, os.NewSyscallError("netlinkrib", err)
|
|
+ }
|
|
+ msgs, err := syscall.ParseNetlinkMessage(tab)
|
|
+ if err != nil {
|
|
+ return nil, os.NewSyscallError("parsenetlinkmessage", err)
|
|
+ }
|
|
+ var ift []net.Interface
|
|
+ if ifi == nil {
|
|
+ var err error
|
|
+ ift, err = interfaceTable(0)
|
|
+ if err != nil {
|
|
+ return nil, err
|
|
+ }
|
|
+ }
|
|
+ ifat, err := addrTable(ift, ifi, msgs)
|
|
+ if err != nil {
|
|
+ return nil, err
|
|
+ }
|
|
+ return ifat, nil
|
|
+}
|
|
+
|
|
+func NetworkLinkList(iface *net.Interface) ([]net.Addr, error) {
|
|
+ return interfaceAddrTable(iface)
|
|
+}
|
|
+
|
|
+func NetworkLinkFlush(iface *net.Interface) (error) {
|
|
+ at, err := NetworkLinkList(iface)
|
|
+ if err != nil {
|
|
+ return err
|
|
+ }
|
|
+ for _, a := range at {
|
|
+ ip, ipnet, err := net.ParseCIDR(a.String())
|
|
+ if err != nil {
|
|
+ return err
|
|
+ }
|
|
+ err = NetworkLinkDelIp(iface, ip, ipnet)
|
|
+ if err != nil {
|
|
+ return err
|
|
+ }
|
|
+ }
|
|
+ return nil
|
|
+}
|
|
+
|
|
+// Add an Ip address to an interface. This is identical to:
|
|
+// ip addr replace $ip/$ipNet dev $iface
|
|
+func NetworkLinkReplaceIp(iface *net.Interface, ip net.IP, ipNet *net.IPNet) error {
|
|
return networkLinkIpAction(
|
|
syscall.RTM_NEWADDR,
|
|
- syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK,
|
|
+ syscall.NLM_F_CREATE|syscall.NLM_F_REPLACE|syscall.NLM_F_ACK,
|
|
IfAddr{iface, ip, ipNet},
|
|
)
|
|
}
|
|
@@ -1108,6 +1548,7 @@
|
|
}
|
|
wb.AddData(uint32Attr(syscall.RTA_OIF, uint32(iface.Index)))
|
|
|
|
+ //Send the message
|
|
if err := s.Send(wb); err != nil {
|
|
return err
|
|
}
|