~ knotless Search/
↑↓ move↵ open⇧↵ all results
0
0
main
175 lines · 4.7 KB Raw History
//go:build linux

package apiserverfront

import (
	"errors"
	"fmt"
	"net"
	"os"
	"strconv"
	"strings"

	"golang.org/x/sys/unix"
)

func ListenerFromFD(fd int) (net.Listener, error) {
	unix.CloseOnExec(fd)
	f := os.NewFile(uintptr(fd), FDName)
	if f == nil {
		return nil, fmt.Errorf("apiserverfront: fd %d is not open", fd)
	}
	defer f.Close()
	ln, err := net.FileListener(f)
	if err != nil {
		return nil, fmt.Errorf("apiserverfront: the inherited fd %d is no listening socket: %w", fd, err)
	}
	if _, ok := ln.(*net.TCPListener); !ok {
		ln.Close()
		return nil, fmt.Errorf("apiserverfront: the inherited fd %d is not a TCP listener", fd)
	}
	return ln, nil
}

func HeldFromFD(fd int, name string) (*Held, error) {
	unix.CloseOnExec(fd)
	port, err := boundPort(fd)
	if err != nil {
		unix.Close(fd)
		return nil, fmt.Errorf("apiserverfront: the inherited hold %q (fd %d): %w", name, fd, err)
	}
	return &Held{Name: name, Port: port, f: os.NewFile(uintptr(fd), HoldFDPrefix+name)}, nil
}

func boundPort(fd int) (int, error) {
	sa, err := unix.Getsockname(fd)
	if err != nil {
		return 0, err
	}
	switch a := sa.(type) {
	case *unix.SockaddrInet6:
		return a.Port, nil
	case *unix.SockaddrInet4:
		return a.Port, nil
	}
	return 0, errors.New("not an inet socket")
}

func bindHold(name string, port int) (*Held, error) {
	h, err := bindHoldOnce(name, port, false)
	if err == nil || port == 0 || !errors.Is(err, unix.EADDRINUSE) || !onlyTimeWait(port) {
		return h, err
	}
	return bindHoldOnce(name, port, true)
}

func onlyTimeWait(port int) bool {
	waiting, other := 0, 0
	for _, table := range []string{"/proc/net/tcp", "/proc/net/tcp6"} {
		raw, err := os.ReadFile(table)
		if err != nil {
			continue
		}
		lines := strings.Split(string(raw), "\n")
		for _, line := range lines[min(1, len(lines)):] {
			f := strings.Fields(line)
			if len(f) < 4 {
				continue
			}
			i := strings.LastIndexByte(f[1], ':')
			if i < 0 {
				continue
			}
			local, err := strconv.ParseUint(f[1][i+1:], 16, 16)
			if err != nil || int(local) != port {
				continue
			}
			if f[3] == tcpTimeWait {
				waiting++
			} else {
				other++
			}
		}
	}
	return waiting > 0 && other == 0
}

const tcpTimeWait = "06"

func bindHoldOnce(name string, port int, reuseFirst bool) (*Held, error) {
	fd, err := unix.Socket(unix.AF_INET6, unix.SOCK_STREAM|unix.SOCK_CLOEXEC, 0)
	var sa unix.Sockaddr = &unix.SockaddrInet6{Port: port}
	if err == nil {
		if err = unix.SetsockoptInt(fd, unix.IPPROTO_IPV6, unix.IPV6_V6ONLY, 0); err != nil {
			unix.Close(fd)
			return nil, fmt.Errorf("apiserverfront: hold %q: a dual-stack socket: %w", name, err)
		}
	} else {
		if fd, err = unix.Socket(unix.AF_INET, unix.SOCK_STREAM|unix.SOCK_CLOEXEC, 0); err != nil {
			return nil, fmt.Errorf("apiserverfront: hold %q: %w", name, err)
		}
		sa = &unix.SockaddrInet4{Port: port}
	}
	if reuseFirst {
		if err := unix.SetsockoptInt(fd, unix.SOL_SOCKET, unix.SO_REUSEADDR, 1); err != nil {
			unix.Close(fd)
			return nil, fmt.Errorf("apiserverfront: hold %q: SO_REUSEADDR before bind over TIME_WAIT: %w", name, err)
		}
	}
	if err := unix.Bind(fd, sa); err != nil {
		unix.Close(fd)
		return nil, fmt.Errorf("apiserverfront: hold %q on port %d: %w", name, port, err)
	}
	if err := unix.SetsockoptInt(fd, unix.SOL_SOCKET, unix.SO_REUSEADDR, 1); err != nil {
		unix.Close(fd)
		return nil, fmt.Errorf("apiserverfront: hold %q: SO_REUSEADDR after bind: %w", name, err)
	}
	got, err := boundPort(fd)
	if err != nil {
		unix.Close(fd)
		return nil, fmt.Errorf("apiserverfront: hold %q: %w", name, err)
	}
	return &Held{Name: name, Port: got, f: os.NewFile(uintptr(fd), HoldFDPrefix+name)}, nil
}

func storeListener(sock string, ln net.Listener) error {
	tl, ok := ln.(*net.TCPListener)
	if !ok {
		return errors.New("apiserverfront: only a TCP listener goes into the fd store")
	}
	raw, err := tl.SyscallConn()
	if err != nil {
		return err
	}
	var werr error
	err = raw.Control(func(fd uintptr) { werr = storeFD(sock, int(fd), "FDNAME="+FDName) })
	if err != nil {
		return err
	}
	return werr
}

func storeHold(sock string, h *Held) error {
	raw, err := h.f.SyscallConn()
	if err != nil {
		return err
	}
	var werr error
	err = raw.Control(func(fd uintptr) { werr = storeFD(sock, int(fd), "FDNAME="+HoldFDPrefix+h.Name+"\nFDPOLL=0") })
	if err != nil {
		return err
	}
	return werr
}

func storeFD(sock string, fd int, fields string) error {
	s, err := unix.Socket(unix.AF_UNIX, unix.SOCK_DGRAM|unix.SOCK_CLOEXEC, 0)
	if err != nil {
		return fmt.Errorf("apiserverfront: a socket for the fd store at %s: %w", sock, err)
	}
	defer unix.Close(s)
	if err := unix.Sendmsg(s, []byte("FDSTORE=1\n"+fields), unix.UnixRights(fd), &unix.SockaddrUnix{Name: sock}, 0); err != nil {
		return fmt.Errorf("apiserverfront: handing %q to the fd store at %s: %w", fields, sock, err)
	}
	return nil
}