diff options
Diffstat (limited to 'container/netlink.go')
| -rw-r--r-- | container/netlink.go | 269 |
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()) -} |
