mirror of
https://github.com/netbirdio/netbird.git
synced 2026-07-16 03:29:57 +00:00
112 lines
2.3 KiB
Go
112 lines
2.3 KiB
Go
//go:build !ios && !android
|
|
|
|
package cmd
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"net"
|
|
"os"
|
|
"strings"
|
|
"syscall"
|
|
"time"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
)
|
|
|
|
type socketListener struct {
|
|
net.Listener
|
|
network string
|
|
address string
|
|
}
|
|
|
|
func listenOnAddress(addr string) (*socketListener, error) {
|
|
network, address, err := parseListenAddress(addr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if network == "unix" {
|
|
removeStaleUnixSocket(address)
|
|
}
|
|
|
|
listener, err := net.Listen(network, address)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &socketListener{Listener: listener, network: network, address: address}, nil
|
|
}
|
|
|
|
func parseListenAddress(addr string) (string, string, error) {
|
|
network, address, ok := strings.Cut(addr, "://")
|
|
if !ok || network == "" || address == "" {
|
|
return "", "", fmt.Errorf("address must be in [unix|tcp]://[path|host:port] format: %q", addr)
|
|
}
|
|
|
|
switch network {
|
|
case "unix", "tcp":
|
|
return network, address, nil
|
|
default:
|
|
return "", "", fmt.Errorf("unsupported daemon address protocol: %v", network)
|
|
}
|
|
}
|
|
|
|
func removeStaleUnixSocket(path string) {
|
|
stat, err := os.Lstat(path)
|
|
if err != nil {
|
|
if !os.IsNotExist(err) {
|
|
log.Debugf("stat socket file: %v", err)
|
|
}
|
|
return
|
|
}
|
|
|
|
if stat.Mode()&os.ModeSocket == 0 {
|
|
return
|
|
}
|
|
|
|
if !isStaleUnixSocket(path) {
|
|
return
|
|
}
|
|
|
|
if err := os.Remove(path); err != nil {
|
|
log.Debugf("remove socket file: %v", err)
|
|
}
|
|
}
|
|
|
|
func isStaleUnixSocket(path string) bool {
|
|
conn, err := net.DialTimeout("unix", path, 100*time.Millisecond)
|
|
if err == nil {
|
|
if closeErr := conn.Close(); closeErr != nil {
|
|
log.Debugf("close unix socket probe: %v", closeErr)
|
|
}
|
|
return false
|
|
}
|
|
|
|
if os.IsNotExist(err) || os.IsPermission(err) || os.IsTimeout(err) {
|
|
log.Debugf("not removing unix socket %s after probe error: %v", path, err)
|
|
return false
|
|
}
|
|
|
|
return errors.Is(err, syscall.ECONNREFUSED)
|
|
}
|
|
|
|
func removeStaleUnixSocketForAddress(addr string) {
|
|
network, address, err := parseListenAddress(addr)
|
|
if err != nil || network != "unix" {
|
|
return
|
|
}
|
|
removeStaleUnixSocket(address)
|
|
}
|
|
|
|
func (l *socketListener) chmodUnixSocket(description string) error {
|
|
if l == nil || l.network != "unix" {
|
|
return nil
|
|
}
|
|
|
|
if err := os.Chmod(l.address, 0666); err != nil {
|
|
return fmt.Errorf("failed setting %s permissions for %s: %w", description, l.address, err)
|
|
}
|
|
return nil
|
|
}
|