github.com/toplink-cn/moby@v0.0.0-20240305205811-460b4aebdf81/libnetwork/sandbox_externalkey_unix.go (about) 1 //go:build linux || freebsd 2 3 package libnetwork 4 5 import ( 6 "context" 7 "encoding/json" 8 "flag" 9 "fmt" 10 "io" 11 "net" 12 "os" 13 "path/filepath" 14 15 "github.com/containerd/log" 16 "github.com/docker/docker/libnetwork/types" 17 "github.com/docker/docker/pkg/reexec" 18 "github.com/docker/docker/pkg/stringid" 19 "github.com/opencontainers/runtime-spec/specs-go" 20 ) 21 22 const ( 23 execSubdir = "libnetwork" 24 defaultExecRoot = "/run/docker" 25 success = "success" 26 ) 27 28 func init() { 29 // TODO(thaJeztah): should this actually be registered on FreeBSD, or only on Linux? 30 reexec.Register("libnetwork-setkey", processSetKeyReexec) 31 } 32 33 type setKeyData struct { 34 ContainerID string 35 Key string 36 } 37 38 // processSetKeyReexec is a private function that must be called only on an reexec path 39 // It expects 3 args { [0] = "libnetwork-setkey", [1] = <container-id>, [2] = <short-controller-id> } 40 // It also expects specs.State as a json string in <stdin> 41 // Refer to https://github.com/opencontainers/runc/pull/160/ for more information 42 // The docker exec-root can be specified as "-exec-root" flag. The default value is "/run/docker". 43 func processSetKeyReexec() { 44 if err := setKey(); err != nil { 45 _, _ = fmt.Fprintln(os.Stderr, err) 46 os.Exit(1) 47 } 48 } 49 50 func setKey() error { 51 execRoot := flag.String("exec-root", defaultExecRoot, "docker exec root") 52 flag.Parse() 53 54 // expecting 3 os.Args {[0]="libnetwork-setkey", [1]=<container-id>, [2]=<short-controller-id> } 55 // (i.e. expecting 2 flag.Args()) 56 args := flag.Args() 57 if len(args) < 2 { 58 return fmt.Errorf("re-exec expects 2 args (after parsing flags), received : %d", len(args)) 59 } 60 containerID, shortCtlrID := args[0], args[1] 61 62 // We expect specs.State as a json string in <stdin> 63 var state specs.State 64 if err := json.NewDecoder(os.Stdin).Decode(&state); err != nil { 65 return err 66 } 67 68 return setExternalKey(shortCtlrID, containerID, fmt.Sprintf("/proc/%d/ns/net", state.Pid), *execRoot) 69 } 70 71 // setExternalKey provides a convenient way to set an External key to a sandbox 72 func setExternalKey(shortCtlrID string, containerID string, key string, execRoot string) error { 73 uds := filepath.Join(execRoot, execSubdir, shortCtlrID+".sock") 74 c, err := net.Dial("unix", uds) 75 if err != nil { 76 return err 77 } 78 defer c.Close() 79 80 err = json.NewEncoder(c).Encode(setKeyData{ 81 ContainerID: containerID, 82 Key: key, 83 }) 84 if err != nil { 85 return fmt.Errorf("sendKey failed with : %v", err) 86 } 87 return processReturn(c) 88 } 89 90 func processReturn(r io.Reader) error { 91 buf := make([]byte, 1024) 92 n, err := r.Read(buf[:]) 93 if err != nil { 94 return fmt.Errorf("failed to read buf in processReturn : %v", err) 95 } 96 if string(buf[0:n]) != success { 97 return fmt.Errorf(string(buf[0:n])) 98 } 99 return nil 100 } 101 102 func (c *Controller) startExternalKeyListener() error { 103 execRoot := defaultExecRoot 104 if v := c.Config().ExecRoot; v != "" { 105 execRoot = v 106 } 107 udsBase := filepath.Join(execRoot, execSubdir) 108 if err := os.MkdirAll(udsBase, 0o600); err != nil { 109 return err 110 } 111 shortCtlrID := stringid.TruncateID(c.id) 112 uds := filepath.Join(udsBase, shortCtlrID+".sock") 113 l, err := net.Listen("unix", uds) 114 if err != nil { 115 return err 116 } 117 if err := os.Chmod(uds, 0o600); err != nil { 118 l.Close() 119 return err 120 } 121 c.mu.Lock() 122 c.extKeyListener = l 123 c.mu.Unlock() 124 125 go c.acceptClientConnections(uds, l) 126 return nil 127 } 128 129 func (c *Controller) acceptClientConnections(sock string, l net.Listener) { 130 for { 131 conn, err := l.Accept() 132 if err != nil { 133 if _, err1 := os.Stat(sock); os.IsNotExist(err1) { 134 // This happens when the socket is closed by the daemon, eg. during shutdown. 135 log.G(context.TODO()).Debugf("Unix socket %s was closed. The external key listener will stop.", sock) 136 return 137 } 138 log.G(context.TODO()).Errorf("Error accepting connection %v", err) 139 continue 140 } 141 go func() { 142 defer conn.Close() 143 144 err := c.processExternalKey(conn) 145 ret := success 146 if err != nil { 147 ret = err.Error() 148 } 149 150 _, err = conn.Write([]byte(ret)) 151 if err != nil { 152 log.G(context.TODO()).Errorf("Error returning to the client %v", err) 153 } 154 }() 155 } 156 } 157 158 func (c *Controller) processExternalKey(conn net.Conn) error { 159 buf := make([]byte, 1280) 160 nr, err := conn.Read(buf) 161 if err != nil { 162 return err 163 } 164 var s setKeyData 165 if err = json.Unmarshal(buf[0:nr], &s); err != nil { 166 return err 167 } 168 sb, err := c.GetSandbox(s.ContainerID) 169 if err != nil { 170 return types.InvalidParameterErrorf("failed to get sandbox for %s", s.ContainerID) 171 } 172 return sb.SetKey(s.Key) 173 } 174 175 func (c *Controller) stopExternalKeyListener() { 176 c.extKeyListener.Close() 177 }