github.com/pwn-term/docker@v0.0.0-20210616085119-6e977cce2565/libnetwork/drivers/bridge/netlink_deprecated_linux.go (about)

     1  package bridge
     2  
     3  import (
     4  	"fmt"
     5  	"math/rand"
     6  	"net"
     7  	"syscall"
     8  	"time"
     9  	"unsafe"
    10  )
    11  
    12  const (
    13  	ifNameSize   = 16
    14  	ioctlBrAdd   = 0x89a0
    15  	ioctlBrAddIf = 0x89a2
    16  )
    17  
    18  type ifreqIndex struct {
    19  	IfrnName  [ifNameSize]byte
    20  	IfruIndex int32
    21  }
    22  
    23  type ifreqHwaddr struct {
    24  	IfrnName   [ifNameSize]byte
    25  	IfruHwaddr syscall.RawSockaddr
    26  }
    27  
    28  var rnd = rand.New(rand.NewSource(time.Now().UnixNano()))
    29  
    30  // THIS CODE DOES NOT COMMUNICATE WITH KERNEL VIA RTNETLINK INTERFACE
    31  // IT IS HERE FOR BACKWARDS COMPATIBILITY WITH OLDER LINUX KERNELS
    32  // WHICH SHIP WITH OLDER NOT ENTIRELY FUNCTIONAL VERSION OF NETLINK
    33  func getIfSocket() (fd int, err error) {
    34  	for _, socket := range []int{
    35  		syscall.AF_INET,
    36  		syscall.AF_PACKET,
    37  		syscall.AF_INET6,
    38  	} {
    39  		if fd, err = syscall.Socket(socket, syscall.SOCK_DGRAM, 0); err == nil {
    40  			break
    41  		}
    42  	}
    43  	if err == nil {
    44  		return fd, nil
    45  	}
    46  	return -1, err
    47  }
    48  
    49  func ifIoctBridge(iface, master *net.Interface, op uintptr) error {
    50  	if len(master.Name) >= ifNameSize {
    51  		return fmt.Errorf("Interface name %s too long", master.Name)
    52  	}
    53  
    54  	s, err := getIfSocket()
    55  	if err != nil {
    56  		return err
    57  	}
    58  	defer syscall.Close(s)
    59  
    60  	ifr := ifreqIndex{}
    61  	copy(ifr.IfrnName[:len(ifr.IfrnName)-1], master.Name)
    62  	ifr.IfruIndex = int32(iface.Index)
    63  
    64  	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(s), op, uintptr(unsafe.Pointer(&ifr))); err != 0 {
    65  		return err
    66  	}
    67  
    68  	return nil
    69  }
    70  
    71  // Add a slave to a bridge device.  This is more backward-compatible than
    72  // netlink.NetworkSetMaster and works on RHEL 6.
    73  func ioctlAddToBridge(iface, master *net.Interface) error {
    74  	return ifIoctBridge(iface, master, ioctlBrAddIf)
    75  }
    76  
    77  func ioctlSetMacAddress(name, addr string) error {
    78  	if len(name) >= ifNameSize {
    79  		return fmt.Errorf("Interface name %s too long", name)
    80  	}
    81  
    82  	hw, err := net.ParseMAC(addr)
    83  	if err != nil {
    84  		return err
    85  	}
    86  
    87  	s, err := getIfSocket()
    88  	if err != nil {
    89  		return err
    90  	}
    91  	defer syscall.Close(s)
    92  
    93  	ifr := ifreqHwaddr{}
    94  	ifr.IfruHwaddr.Family = syscall.ARPHRD_ETHER
    95  	copy(ifr.IfrnName[:len(ifr.IfrnName)-1], name)
    96  
    97  	for i := 0; i < 6; i++ {
    98  		ifr.IfruHwaddr.Data[i] = ifrDataByte(hw[i])
    99  	}
   100  
   101  	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(s), syscall.SIOCSIFHWADDR, uintptr(unsafe.Pointer(&ifr))); err != 0 {
   102  		return err
   103  	}
   104  	return nil
   105  }
   106  
   107  func ioctlCreateBridge(name, macAddr string) error {
   108  	if len(name) >= ifNameSize {
   109  		return fmt.Errorf("Interface name %s too long", name)
   110  	}
   111  
   112  	s, err := getIfSocket()
   113  	if err != nil {
   114  		return err
   115  	}
   116  	defer syscall.Close(s)
   117  
   118  	nameBytePtr, err := syscall.BytePtrFromString(name)
   119  	if err != nil {
   120  		return err
   121  	}
   122  	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(s), ioctlBrAdd, uintptr(unsafe.Pointer(nameBytePtr))); err != 0 {
   123  		return err
   124  	}
   125  	return ioctlSetMacAddress(name, macAddr)
   126  }