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