mirror of
https://blitiri.com.ar/repos/chasquid
synced 2025-12-18 14:47:03 +00:00
We want to be able to distinguish between connections for SMTP and connections for submission, so we can make different policy decisions. To do that, we first make the configuration aware of the different kinds of addresses. This is done in this patch in a backwards-incompatible way, but at this point in time it is ok to do so. Then, we extend systemd's socket passing library to support socket naming, so we can tell the different sockets apart. This is done via the LISTEN_FDNAMES/FileDescriptorName mechanism. And finally we make the server and connection types aware of the socket mode.
86 lines
2.3 KiB
Go
86 lines
2.3 KiB
Go
// Package systemd implements utility functions to interact with systemd.
|
|
package systemd
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"net"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
"syscall"
|
|
)
|
|
|
|
var (
|
|
// Error to return when $LISTEN_PID does not refer to us.
|
|
ErrPIDMismatch = errors.New("$LISTEN_PID != our PID")
|
|
|
|
// First FD for listeners.
|
|
// It's 3 by definition, but using a variable simplifies testing.
|
|
firstFD = 3
|
|
)
|
|
|
|
// Listeners creates a slice net.Listener from the file descriptors passed
|
|
// by systemd, via the LISTEN_FDS environment variable.
|
|
// See sd_listen_fds(3) and sd_listen_fds_with_names(3) for more details.
|
|
func Listeners() (map[string][]net.Listener, error) {
|
|
pidStr := os.Getenv("LISTEN_PID")
|
|
nfdsStr := os.Getenv("LISTEN_FDS")
|
|
fdNamesStr := os.Getenv("LISTEN_FDNAMES")
|
|
fdNames := strings.Split(fdNamesStr, ":")
|
|
|
|
// Nothing to do if the variables are not set.
|
|
if pidStr == "" || nfdsStr == "" {
|
|
return nil, nil
|
|
}
|
|
|
|
pid, err := strconv.Atoi(pidStr)
|
|
if err != nil {
|
|
return nil, fmt.Errorf(
|
|
"error converting $LISTEN_PID=%q: %v", pidStr, err)
|
|
} else if pid != os.Getpid() {
|
|
return nil, ErrPIDMismatch
|
|
}
|
|
|
|
nfds, err := strconv.Atoi(os.Getenv("LISTEN_FDS"))
|
|
if err != nil {
|
|
return nil, fmt.Errorf(
|
|
"error reading $LISTEN_FDS=%q: %v", nfdsStr, err)
|
|
}
|
|
|
|
// We should have as many names as we have descriptors.
|
|
// Note that if we have no descriptors, fdNames will be [""] (due to how
|
|
// strings.Split works), so we consider that special case.
|
|
if nfds > 0 && (fdNamesStr == "" || len(fdNames) != nfds) {
|
|
return nil, fmt.Errorf(
|
|
"Incorrect LISTEN_FDNAMES, have you set FileDescriptorName?")
|
|
}
|
|
|
|
listeners := map[string][]net.Listener{}
|
|
|
|
for i := 0; i < nfds; i++ {
|
|
fd := firstFD + i
|
|
// We don't want childs to inherit these file descriptors.
|
|
syscall.CloseOnExec(fd)
|
|
|
|
name := fdNames[i]
|
|
|
|
sysName := fmt.Sprintf("[systemd-fd-%d-%v]", fd, name)
|
|
lis, err := net.FileListener(os.NewFile(uintptr(fd), sysName))
|
|
if err != nil {
|
|
return nil, fmt.Errorf(
|
|
"Error making listener out of fd %d: %v", fd, err)
|
|
}
|
|
|
|
listeners[name] = append(listeners[name], lis)
|
|
}
|
|
|
|
// Remove them from the environment, to prevent accidental reuse (by
|
|
// us or children processes).
|
|
os.Unsetenv("LISTEN_PID")
|
|
os.Unsetenv("LISTEN_FDS")
|
|
os.Unsetenv("LISTEN_FDNAMES")
|
|
|
|
return listeners, nil
|
|
}
|