github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/libnetwork/sandbox_externalkey_unix.go (about)

     1  //go:build linux || freebsd
     2  // +build linux freebsd
     3  
     4  package libnetwork
     5  
     6  import (
     7  	"encoding/json"
     8  	"flag"
     9  	"fmt"
    10  	"io"
    11  	"net"
    12  	"os"
    13  	"path/filepath"
    14  
    15  	"github.com/docker/docker/libnetwork/types"
    16  	"github.com/docker/docker/pkg/stringid"
    17  	"github.com/opencontainers/runtime-spec/specs-go"
    18  	"github.com/sirupsen/logrus"
    19  )
    20  
    21  const (
    22  	execSubdir      = "libnetwork"
    23  	defaultExecRoot = "/run/docker"
    24  	success         = "success"
    25  )
    26  
    27  // processSetKeyReexec is a private function that must be called only on an reexec path
    28  // It expects 3 args { [0] = "libnetwork-setkey", [1] = <container-id>, [2] = <short-controller-id> }
    29  // It also expects specs.State as a json string in <stdin>
    30  // Refer to https://github.com/opencontainers/runc/pull/160/ for more information
    31  // The docker exec-root can be specified as "-exec-root" flag. The default value is "/run/docker".
    32  func processSetKeyReexec() {
    33  	var err error
    34  
    35  	// Return a failure to the calling process via ExitCode
    36  	defer func() {
    37  		if err != nil {
    38  			logrus.Fatalf("%v", err)
    39  		}
    40  	}()
    41  
    42  	execRoot := flag.String("exec-root", defaultExecRoot, "docker exec root")
    43  	flag.Parse()
    44  
    45  	// expecting 3 os.Args {[0]="libnetwork-setkey", [1]=<container-id>, [2]=<short-controller-id> }
    46  	// (i.e. expecting 2 flag.Args())
    47  	args := flag.Args()
    48  	if len(args) < 2 {
    49  		err = fmt.Errorf("Re-exec expects 2 args (after parsing flags), received : %d", len(args))
    50  		return
    51  	}
    52  	containerID, shortCtlrID := args[0], args[1]
    53  
    54  	// We expect specs.State as a json string in <stdin>
    55  	stateBuf, err := io.ReadAll(os.Stdin)
    56  	if err != nil {
    57  		return
    58  	}
    59  	var state specs.State
    60  	if err = json.Unmarshal(stateBuf, &state); err != nil {
    61  		return
    62  	}
    63  
    64  	err = SetExternalKey(shortCtlrID, containerID, fmt.Sprintf("/proc/%d/ns/net", state.Pid), *execRoot)
    65  }
    66  
    67  // SetExternalKey provides a convenient way to set an External key to a sandbox
    68  func SetExternalKey(shortCtlrID string, containerID string, key string, execRoot string) error {
    69  	keyData := setKeyData{
    70  		ContainerID: containerID,
    71  		Key:         key}
    72  
    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  	if err = sendKey(c, keyData); err != nil {
    81  		return fmt.Errorf("sendKey failed with : %v", err)
    82  	}
    83  	return processReturn(c)
    84  }
    85  
    86  func sendKey(c net.Conn, data setKeyData) error {
    87  	var err error
    88  	defer func() {
    89  		if err != nil {
    90  			c.Close()
    91  		}
    92  	}()
    93  
    94  	var b []byte
    95  	if b, err = json.Marshal(data); err != nil {
    96  		return err
    97  	}
    98  
    99  	_, err = c.Write(b)
   100  	return err
   101  }
   102  
   103  func processReturn(r io.Reader) error {
   104  	buf := make([]byte, 1024)
   105  	n, err := r.Read(buf[:])
   106  	if err != nil {
   107  		return fmt.Errorf("failed to read buf in processReturn : %v", err)
   108  	}
   109  	if string(buf[0:n]) != success {
   110  		return fmt.Errorf(string(buf[0:n]))
   111  	}
   112  	return nil
   113  }
   114  
   115  func (c *controller) startExternalKeyListener() error {
   116  	execRoot := defaultExecRoot
   117  	if v := c.Config().ExecRoot; v != "" {
   118  		execRoot = v
   119  	}
   120  	udsBase := filepath.Join(execRoot, execSubdir)
   121  	if err := os.MkdirAll(udsBase, 0600); err != nil {
   122  		return err
   123  	}
   124  	shortCtlrID := stringid.TruncateID(c.id)
   125  	uds := filepath.Join(udsBase, shortCtlrID+".sock")
   126  	l, err := net.Listen("unix", uds)
   127  	if err != nil {
   128  		return err
   129  	}
   130  	if err := os.Chmod(uds, 0600); err != nil {
   131  		l.Close()
   132  		return err
   133  	}
   134  	c.Lock()
   135  	c.extKeyListener = l
   136  	c.Unlock()
   137  
   138  	go c.acceptClientConnections(uds, l)
   139  	return nil
   140  }
   141  
   142  func (c *controller) acceptClientConnections(sock string, l net.Listener) {
   143  	for {
   144  		conn, err := l.Accept()
   145  		if err != nil {
   146  			if _, err1 := os.Stat(sock); os.IsNotExist(err1) {
   147  				logrus.Debugf("Unix socket %s doesn't exist. cannot accept client connections", sock)
   148  				return
   149  			}
   150  			logrus.Errorf("Error accepting connection %v", err)
   151  			continue
   152  		}
   153  		go func() {
   154  			defer conn.Close()
   155  
   156  			err := c.processExternalKey(conn)
   157  			ret := success
   158  			if err != nil {
   159  				ret = err.Error()
   160  			}
   161  
   162  			_, err = conn.Write([]byte(ret))
   163  			if err != nil {
   164  				logrus.Errorf("Error returning to the client %v", err)
   165  			}
   166  		}()
   167  	}
   168  }
   169  
   170  func (c *controller) processExternalKey(conn net.Conn) error {
   171  	buf := make([]byte, 1280)
   172  	nr, err := conn.Read(buf)
   173  	if err != nil {
   174  		return err
   175  	}
   176  	var s setKeyData
   177  	if err = json.Unmarshal(buf[0:nr], &s); err != nil {
   178  		return err
   179  	}
   180  
   181  	var sandbox Sandbox
   182  	search := SandboxContainerWalker(&sandbox, s.ContainerID)
   183  	c.WalkSandboxes(search)
   184  	if sandbox == nil {
   185  		return types.BadRequestErrorf("no sandbox present for %s", s.ContainerID)
   186  	}
   187  
   188  	return sandbox.SetKey(s.Key)
   189  }
   190  
   191  func (c *controller) stopExternalKeyListener() {
   192  	c.extKeyListener.Close()
   193  }