github.com/google/fleetspeak@v0.1.15-0.20240426164851-4f31f62c1aea/fleetspeak/src/client/socketservice/socketservice_unix.go (about) 1 // Copyright 2017 Google Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 //go:build linux || darwin 16 17 package socketservice 18 19 import ( 20 "fmt" 21 "net" 22 "os" 23 "path/filepath" 24 25 "golang.org/x/sys/unix" 26 27 "github.com/google/fleetspeak/fleetspeak/src/client/socketservice/checks" 28 ) 29 30 func listen(path string) (net.Listener, error) { 31 // We create the listener in this temporary location, chmod it, and then move 32 // it. This prevents the client library from observing the listener before its 33 // permissions are set. 34 tmpPath := path + ".tmp" 35 parent := filepath.Dir(path) 36 37 // Although golang documentation does not explicitly mention this, there is a 38 // limit for how long socket paths can be on different platforms. If you try 39 // to bind to a socket path that is too long, you get a kernel error saying 40 // 'invalid argument'. Also see http://pubs.opengroup.org/onlinepubs/009604499/basedefs/sys/un.h.html 41 maxPathLen := len(unix.RawSockaddrUnix{}.Path) - 1 // C-strings are null-terminated 42 if len(tmpPath) > maxPathLen { 43 return nil, fmt.Errorf("socket path is too long (%d chars) - max allowed length is %d: %s", len(tmpPath), maxPathLen, tmpPath) 44 } 45 46 // Ensure that the parent directory exists and that the socket itself does not. 47 if err := os.MkdirAll(parent, 0700); err != nil { 48 return nil, fmt.Errorf("os.MkdirAll failed: %v", err) 49 } 50 for _, f := range []string{path, tmpPath} { 51 if err := os.Remove(f); err != nil { 52 if !os.IsNotExist(err) { 53 return nil, fmt.Errorf("os.Remove(%q): %v", f, err) 54 } 55 } 56 } 57 58 l, err := net.ListenUnix("unix", &net.UnixAddr{Name: tmpPath, Net: "unix"}) 59 if err != nil { 60 return nil, fmt.Errorf("failed to create a Unix domain listener: %v", err) 61 } 62 63 if err := os.Chmod(tmpPath, 0600); err != nil { 64 return nil, fmt.Errorf("failed to chmod a Unix domain listener: %v", err) 65 } 66 67 if err := os.Rename(tmpPath, path); err != nil { 68 return nil, fmt.Errorf("failed to rename a Unix domain listener: %v", err) 69 } 70 71 if err := checks.CheckSocketFile(path); err != nil { 72 return nil, fmt.Errorf("CheckSocketFile(...): %v", err) 73 } 74 75 return l, nil 76 }