aboutsummaryrefslogtreecommitdiffhomepage
path: root/container/netlink.go
diff options
context:
space:
mode:
Diffstat (limited to 'container/netlink.go')
-rw-r--r--container/netlink.go269
1 files changed, 0 insertions, 269 deletions
diff --git a/container/netlink.go b/container/netlink.go
deleted file mode 100644
index 412f964e..00000000
--- a/container/netlink.go
+++ /dev/null
@@ -1,269 +0,0 @@
-package container
-
-import (
- "encoding/binary"
- "errors"
- "net"
- "os"
- . "syscall"
- "unsafe"
-
- "hakurei.app/container/std"
- "hakurei.app/message"
-)
-
-// rtnetlink represents a NETLINK_ROUTE socket.
-type rtnetlink struct {
- // Sent as part of rtnetlink messages.
- pid uint32
- // AF_NETLINK socket.
- fd int
- // Whether the socket is open.
- ok bool
- // Message sequence number.
- seq uint32
-}
-
-// open creates the underlying NETLINK_ROUTE socket.
-func (s *rtnetlink) open() (err error) {
- if s.ok || s.fd < 0 {
- return os.ErrInvalid
- }
-
- s.pid = uint32(Getpid())
- if s.fd, err = Socket(
- AF_NETLINK,
- SOCK_RAW|SOCK_CLOEXEC,
- NETLINK_ROUTE,
- ); err != nil {
- return os.NewSyscallError("socket", err)
- } else if err = Bind(s.fd, &SockaddrNetlink{
- Family: AF_NETLINK,
- Pid: s.pid,
- }); err != nil {
- _ = s.close()
- return os.NewSyscallError("bind", err)
- } else {
- s.ok = true
- return nil
- }
-}
-
-// close closes the underlying NETLINK_ROUTE socket.
-func (s *rtnetlink) close() error {
- if !s.ok {
- return os.ErrInvalid
- }
-
- s.ok = false
- err := Close(s.fd)
- s.fd = -1
- return err
-}
-
-// roundtrip sends a netlink message and handles the reply.
-func (s *rtnetlink) roundtrip(data []byte) error {
- if !s.ok {
- return os.ErrInvalid
- }
-
- defer func() { s.seq++ }()
-
- if err := Sendto(s.fd, data, 0, &SockaddrNetlink{
- Family: AF_NETLINK,
- }); err != nil {
- return os.NewSyscallError("sendto", err)
- }
- buf := make([]byte, Getpagesize())
-
-done:
- for {
- p := buf
- if n, _, err := Recvfrom(s.fd, p, 0); err != nil {
- return os.NewSyscallError("recvfrom", err)
- } else if n < NLMSG_HDRLEN {
- return errors.ErrUnsupported
- } else {
- p = p[:n]
- }
-
- if msgs, err := ParseNetlinkMessage(p); err != nil {
- return err
- } else {
- for _, m := range msgs {
- if m.Header.Seq != s.seq || m.Header.Pid != s.pid {
- return errors.ErrUnsupported
- }
- if m.Header.Type == NLMSG_DONE {
- break done
- }
- if m.Header.Type == NLMSG_ERROR {
- if len(m.Data) >= 4 {
- errno := Errno(-std.Int(binary.NativeEndian.Uint32(m.Data)))
- if errno == 0 {
- return nil
- }
- return errno
- }
- return errors.ErrUnsupported
- }
- }
- }
- }
-
- return nil
-}
-
-// mustRoundtrip calls roundtrip and terminates via msg for a non-nil error.
-func (s *rtnetlink) mustRoundtrip(msg message.Msg, data []byte) {
- err := s.roundtrip(data)
- if err == nil {
- return
- }
- if closeErr := Close(s.fd); closeErr != nil {
- msg.Verbosef("cannot close: %v", err)
- }
-
- switch err.(type) {
- case *os.SyscallError:
- msg.GetLogger().Fatalf("cannot %v", err)
-
- case Errno:
- msg.GetLogger().Fatalf("RTNETLINK answers: %v", err)
-
- default:
- msg.GetLogger().Fatalln("RTNETLINK answers with unexpected message")
- }
-}
-
-// newaddrLo represents a RTM_NEWADDR message with two addresses.
-type newaddrLo struct {
- header NlMsghdr
- data IfAddrmsg
-
- r0 RtAttr
- a0 [4]byte // in_addr
- r1 RtAttr
- a1 [4]byte // in_addr
-}
-
-// sizeofNewaddrLo is the expected size of newaddrLo.
-const sizeofNewaddrLo = NLMSG_HDRLEN + SizeofIfAddrmsg + (SizeofRtAttr+4)*2
-
-// newaddrLo returns the address of a populated newaddrLo.
-func (s *rtnetlink) newaddrLo(lo int) *newaddrLo {
- return &newaddrLo{NlMsghdr{
- Len: sizeofNewaddrLo,
- Type: RTM_NEWADDR,
- Flags: NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_EXCL,
- Seq: s.seq,
- Pid: s.pid,
- }, IfAddrmsg{
- Family: AF_INET,
- Prefixlen: 8,
- Flags: IFA_F_PERMANENT,
- Scope: RT_SCOPE_HOST,
- Index: uint32(lo),
- }, RtAttr{
- Len: uint16(SizeofRtAttr + len(newaddrLo{}.a0)),
- Type: IFA_LOCAL,
- }, [4]byte{127, 0, 0, 1}, RtAttr{
- Len: uint16(SizeofRtAttr + len(newaddrLo{}.a1)),
- Type: IFA_ADDRESS,
- }, [4]byte{127, 0, 0, 1}}
-}
-
-func (msg *newaddrLo) toWireFormat() []byte {
- var buf [sizeofNewaddrLo]byte
-
- *(*uint32)(unsafe.Pointer(&buf[0:4][0])) = msg.header.Len
- *(*uint16)(unsafe.Pointer(&buf[4:6][0])) = msg.header.Type
- *(*uint16)(unsafe.Pointer(&buf[6:8][0])) = msg.header.Flags
- *(*uint32)(unsafe.Pointer(&buf[8:12][0])) = msg.header.Seq
- *(*uint32)(unsafe.Pointer(&buf[12:16][0])) = msg.header.Pid
-
- buf[16] = msg.data.Family
- buf[17] = msg.data.Prefixlen
- buf[18] = msg.data.Flags
- buf[19] = msg.data.Scope
- *(*uint32)(unsafe.Pointer(&buf[20:24][0])) = msg.data.Index
-
- *(*uint16)(unsafe.Pointer(&buf[24:26][0])) = msg.r0.Len
- *(*uint16)(unsafe.Pointer(&buf[26:28][0])) = msg.r0.Type
- copy(buf[28:32], msg.a0[:])
- *(*uint16)(unsafe.Pointer(&buf[32:34][0])) = msg.r1.Len
- *(*uint16)(unsafe.Pointer(&buf[34:36][0])) = msg.r1.Type
- copy(buf[36:40], msg.a1[:])
-
- return buf[:]
-}
-
-// newlinkLo represents a RTM_NEWLINK message.
-type newlinkLo struct {
- header NlMsghdr
- data IfInfomsg
-}
-
-// sizeofNewlinkLo is the expected size of newlinkLo.
-const sizeofNewlinkLo = NLMSG_HDRLEN + SizeofIfInfomsg
-
-// newlinkLo returns the address of a populated newlinkLo.
-func (s *rtnetlink) newlinkLo(lo int) *newlinkLo {
- return &newlinkLo{NlMsghdr{
- Len: sizeofNewlinkLo,
- Type: RTM_NEWLINK,
- Flags: NLM_F_REQUEST | NLM_F_ACK,
- Seq: s.seq,
- Pid: s.pid,
- }, IfInfomsg{
- Family: AF_UNSPEC,
- Index: int32(lo),
- Flags: IFF_UP,
- Change: IFF_UP,
- }}
-}
-
-func (msg *newlinkLo) toWireFormat() []byte {
- var buf [sizeofNewlinkLo]byte
-
- *(*uint32)(unsafe.Pointer(&buf[0:4][0])) = msg.header.Len
- *(*uint16)(unsafe.Pointer(&buf[4:6][0])) = msg.header.Type
- *(*uint16)(unsafe.Pointer(&buf[6:8][0])) = msg.header.Flags
- *(*uint32)(unsafe.Pointer(&buf[8:12][0])) = msg.header.Seq
- *(*uint32)(unsafe.Pointer(&buf[12:16][0])) = msg.header.Pid
-
- buf[16] = msg.data.Family
- *(*uint16)(unsafe.Pointer(&buf[18:20][0])) = msg.data.Type
- *(*int32)(unsafe.Pointer(&buf[20:24][0])) = msg.data.Index
- *(*uint32)(unsafe.Pointer(&buf[24:28][0])) = msg.data.Flags
- *(*uint32)(unsafe.Pointer(&buf[28:32][0])) = msg.data.Change
-
- return buf[:]
-}
-
-// mustLoopback creates the loopback address and brings the lo interface up.
-// mustLoopback calls a fatal method of the underlying [log.Logger] of m with a
-// user-facing error message if RTNETLINK behaves unexpectedly.
-func mustLoopback(msg message.Msg) {
- log := msg.GetLogger()
-
- var lo int
- if ifi, err := net.InterfaceByName("lo"); err != nil {
- log.Fatalln(err)
- } else {
- lo = ifi.Index
- }
-
- var s rtnetlink
- if err := s.open(); err != nil {
- log.Fatalln(err)
- }
- defer func() {
- if err := s.close(); err != nil {
- msg.Verbosef("cannot close netlink: %v", err)
- }
- }()
-
- s.mustRoundtrip(msg, s.newaddrLo(lo).toWireFormat())
- s.mustRoundtrip(msg, s.newlinkLo(lo).toWireFormat())
-}