From 782004bec92cea7f30b1e16f78428d9dc47dcc16 Mon Sep 17 00:00:00 2001 From: Darren Shepherd Date: Wed, 22 Jan 2020 10:53:24 -0700 Subject: [PATCH 1/2] Create pidns for rootless --- pkg/rootless/mounts.go | 2 ++ pkg/rootless/rootless.go | 7 +++++-- pkg/rootlessports/controller.go | 9 ++++++++- pkg/server/server.go | 4 ++-- 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/pkg/rootless/mounts.go b/pkg/rootless/mounts.go index 1c820e0f7b..53cfb4cf3a 100644 --- a/pkg/rootless/mounts.go +++ b/pkg/rootless/mounts.go @@ -17,6 +17,8 @@ func setupMounts(stateDir string) error { {"/var/run", ""}, {"/var/log", filepath.Join(stateDir, "logs")}, {"/var/lib/cni", filepath.Join(stateDir, "cni")}, + {"/var/lib/kubelet", filepath.Join(stateDir, "kubelet")}, + {"/etc/rancher", filepath.Join(stateDir, "etc", "rancher")}, } for _, v := range mountMap { diff --git a/pkg/rootless/rootless.go b/pkg/rootless/rootless.go index 32d8f8cd5a..cdb23123a2 100644 --- a/pkg/rootless/rootless.go +++ b/pkg/rootless/rootless.go @@ -89,7 +89,8 @@ func createParentOpt(stateDir string) (*parent.Opt, error) { } opt := &parent.Opt{ - StateDir: stateDir, + StateDir: stateDir, + CreatePIDNS: true, } mtu := 0 @@ -102,7 +103,7 @@ func createParentOpt(stateDir string) (*parent.Opt, error) { if _, err := exec.LookPath(binary); err != nil { return nil, err } - opt.NetworkDriver = slirp4netns.NewParentDriver(binary, mtu, ipnet, disableHostLoopback, "") + opt.NetworkDriver = slirp4netns.NewParentDriver(binary, mtu, ipnet, disableHostLoopback, "", false, false) opt.PortDriver, err = portbuiltin.NewParentDriver(&logrusDebugWriter{}, stateDir) if err != nil { return nil, err @@ -130,5 +131,7 @@ func createChildOpt() (*child.Opt, error) { opt.PortDriver = portbuiltin.NewChildDriver(&logrusDebugWriter{}) opt.CopyUpDirs = []string{"/etc", "/run", "/var/lib"} opt.CopyUpDriver = tmpfssymlink.NewChildDriver() + opt.MountProcfs = true + opt.Reaper = true return opt, nil } diff --git a/pkg/rootlessports/controller.go b/pkg/rootlessports/controller.go index e5a4a7f7af..d4c78212dc 100644 --- a/pkg/rootlessports/controller.go +++ b/pkg/rootlessports/controller.go @@ -17,7 +17,7 @@ var ( all = "_all_" ) -func Register(ctx context.Context, serviceController coreClients.ServiceController, httpsPort int) error { +func Register(ctx context.Context, serviceController coreClients.ServiceController, enabled bool, httpsPort int) error { var ( err error rootlessClient client.Client @@ -41,6 +41,7 @@ func Register(ctx context.Context, serviceController coreClients.ServiceControll } h := &handler{ + enabled: enabled, rootlessClient: rootlessClient, serviceClient: serviceController, serviceCache: serviceController.Cache(), @@ -54,6 +55,7 @@ func Register(ctx context.Context, serviceController coreClients.ServiceControll } type handler struct { + enabled bool rootlessClient client.Client serviceClient coreClients.ServiceController serviceCache coreClients.ServiceCache @@ -122,6 +124,11 @@ func (h *handler) toBindPorts() (map[int]int, error) { toBindPorts := map[int]int{ h.httpsPort: h.httpsPort, } + + if !h.enabled { + return toBindPorts, nil + } + for _, svc := range svcs { for _, ingress := range svc.Status.LoadBalancer.Ingress { if ingress.IP == "" { diff --git a/pkg/server/server.go b/pkg/server/server.go index e0ca1a8f9e..1864be1490 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -151,8 +151,8 @@ func masterControllers(ctx context.Context, sc *Context, config *Config) error { return err } - if !config.DisableServiceLB && config.Rootless { - return rootlessports.Register(ctx, sc.Core.Core().V1().Service(), config.ControlConfig.HTTPSPort) + if config.Rootless { + return rootlessports.Register(ctx, sc.Core.Core().V1().Service(), !config.DisableServiceLB, config.ControlConfig.HTTPSPort) } return nil From 8c9ed8e197d297cc424c54f31a507f2d22013163 Mon Sep 17 00:00:00 2001 From: Darren Shepherd Date: Wed, 22 Jan 2020 10:59:51 -0700 Subject: [PATCH 2/2] Bump rootlesskit --- go.mod | 4 +- go.sum | 18 +- .../docker/docker/pkg/idtools/idtools_unix.go | 231 --------- .../docker/pkg/idtools/idtools_windows.go | 25 - .../docker/pkg/idtools/usergroupadd_linux.go | 164 ------ .../pkg/idtools/usergroupadd_unsupported.go | 12 - .../docker/docker/pkg/idtools/utils_unix.go | 32 -- .../rootlesskit/pkg/child/child.go | 70 ++- .../rootlesskit/pkg/child/hosts.go | 12 +- .../rootlesskit/pkg/child/resolvconf.go | 11 +- .../pkg/copyup/tmpfssymlink/tmpfssymlink.go | 24 +- .../pkg/network/slirp4netns/slirp4netns.go | 114 ++++- .../pkg/parent}/idtools/idtools.go | 28 +- .../rootlesskit/pkg/parent/parent.go | 12 +- .../rootlesskit/pkg/port/builtin/builtin.go | 483 +----------------- .../pkg/port/builtin/child/child.go | 134 +++++ .../rootlesskit/pkg/port/builtin/msg/msg.go | 129 +++++ .../pkg/port/builtin/opaque/opaque.go | 6 + .../pkg/port/builtin/parent/parent.go | 145 ++++++ .../pkg/port/builtin/parent/tcp/tcp.go | 104 ++++ .../pkg/port/builtin/parent/udp/udp.go | 60 +++ .../builtin/parent/udp/udpproxy/udp_proxy.go | 150 ++++++ vendor/modules.txt | 11 +- 23 files changed, 944 insertions(+), 1035 deletions(-) delete mode 100644 vendor/github.com/docker/docker/pkg/idtools/idtools_unix.go delete mode 100644 vendor/github.com/docker/docker/pkg/idtools/idtools_windows.go delete mode 100644 vendor/github.com/docker/docker/pkg/idtools/usergroupadd_linux.go delete mode 100644 vendor/github.com/docker/docker/pkg/idtools/usergroupadd_unsupported.go delete mode 100644 vendor/github.com/docker/docker/pkg/idtools/utils_unix.go rename vendor/github.com/{docker/docker/pkg => rootless-containers/rootlesskit/pkg/parent}/idtools/idtools.go (85%) create mode 100644 vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/child/child.go create mode 100644 vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/msg/msg.go create mode 100644 vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/opaque/opaque.go create mode 100644 vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/parent.go create mode 100644 vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/tcp/tcp.go create mode 100644 vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/udp/udp.go create mode 100644 vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/udp/udpproxy/udp_proxy.go diff --git a/go.mod b/go.mod index 542dadde27..637ae63702 100644 --- a/go.mod +++ b/go.mod @@ -82,7 +82,6 @@ require ( github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4 // indirect github.com/go-bindata/go-bindata v3.1.2+incompatible github.com/go-sql-driver/mysql v1.4.1 - github.com/gofrs/flock v0.7.1 // indirect github.com/gogo/googleapis v1.3.0 // indirect github.com/google/tcpproxy v0.0.0-20180808230851-dfa16c61dad2 github.com/gorilla/mux v1.7.3 @@ -103,11 +102,10 @@ require ( github.com/rancher/remotedialer v0.2.0 github.com/rancher/wrangler v0.4.0 github.com/rancher/wrangler-api v0.4.0 - github.com/rootless-containers/rootlesskit v0.6.0 + github.com/rootless-containers/rootlesskit v0.7.2 github.com/sirupsen/logrus v1.4.2 github.com/spf13/pflag v1.0.5 github.com/tchap/go-patricia v2.3.0+incompatible // indirect - github.com/theckman/go-flock v0.7.1 // indirect github.com/urfave/cli v1.22.2 golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586 golang.org/x/net v0.0.0-20191204025024-5ee1b9f4859a diff --git a/go.sum b/go.sum index f1ebc47a49..8c93c796e8 100644 --- a/go.sum +++ b/go.sum @@ -113,7 +113,6 @@ github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7 github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23 h1:D21IyuvjDCshj1/qq+pCNd3VZOAEI9jy6Bi131YlXgI= github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= github.com/caddyserver/caddy v1.0.3/go.mod h1:G+ouvOY32gENkJC+jhgl62TyhvqEsFaDiZ4uw0RzP1E= -github.com/canonical/go-dqlite v1.2.0 h1:TCsNV/mAmPy7PQa4jIQMoiXbCUVqYTSv6OJSpi/qdX8= github.com/canonical/go-dqlite v1.2.0/go.mod h1:wp00vfMvPYgNCyxcPdHB5XExmDoCGoPUGymloAQT17Y= github.com/canonical/go-dqlite v1.3.0 h1:c+7eGZfh0K7yCmGrBkNRGZdY8R8+2jSSkz6Zr3YCjJE= github.com/canonical/go-dqlite v1.3.0/go.mod h1:wp00vfMvPYgNCyxcPdHB5XExmDoCGoPUGymloAQT17Y= @@ -490,7 +489,9 @@ github.com/imdario/mergo v0.3.7 h1:Y+UAYTZ7gDEuOfhxKWy+dvb5dRQ6rJjFSdX2HZY1/gI= github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/insomniacslk/dhcp v0.0.0-20190712084813-dc1a53400564/go.mod h1:CfMdguCK66I5DAUJgGKyNz8aB6vO5dZzkm9Xep6WGvw= github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA= +github.com/jamescun/tuntap v0.0.0-20190712092105-cb1fb277045c/go.mod h1:zzwpsgcYhzzIP5WyF8g9ivCv38cY9uAV9Gu0m3lThhE= github.com/jefferai/jsonx v1.0.0/go.mod h1:OGmqmi2tTeI/PS+qQfBDToLHHJIy/RMp24fPo8vFvoQ= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= github.com/jetstack/cert-manager v0.7.2/go.mod h1:nbddmhjWxYGt04bxvwVGUSeLhZ2PCyNvd7MpXdq+yWY= @@ -615,6 +616,7 @@ github.com/mitchellh/mapstructure v0.0.0-20180220230111-00c29f56e238/go.mod h1:F github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/moby/vpnkit v0.3.1-0.20190720080441-7dd3dcce7d3d/go.mod h1:KyjUrL9cb6ZSNNAUwZfqRjhwwgJ3BJN+kXh0t43WTUQ= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -649,7 +651,6 @@ github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo= github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.3 h1:OoxbjfXVZyod1fmWYhI7SEyaD8B00ynP3T+D5GiyHOY= github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= @@ -658,7 +659,6 @@ github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGV github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= @@ -781,8 +781,8 @@ github.com/robfig/cron v1.1.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfm github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rootless-containers/rootlesskit v0.6.0 h1:L7DxVAlaNhg4M/+i2GCl24kRkXO5q81C/lu4jlMz3bE= -github.com/rootless-containers/rootlesskit v0.6.0/go.mod h1:HO7iU3+dH2N6yQL4DcUGQpzVZ7e7VYWNdtTAOR/P3FM= +github.com/rootless-containers/rootlesskit v0.7.2 h1:gcWQ9/GN98ne1AqnoeOgQ8e6qpKd3BuB4ug+2h95Fr0= +github.com/rootless-containers/rootlesskit v0.7.2/go.mod h1:r9YL5mKRIdnwcYk4G8E5CSc9MDeFtgYmhfE4CSvDGYA= github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c h1:ht7N4d/B7Ezf58nvMNVF3OlvDlz9pp+WHVcRNS0nink= github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto= github.com/russross/blackfriday v0.0.0-20170610170232-067529f716f4/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= @@ -862,6 +862,7 @@ github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhV github.com/timakin/bodyclose v0.0.0-20190721030226-87058b9bfcec/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8 h1:ndzgwNDnKIqyCvHTXaCqh9KlOWKvBry6nuXMJmonVsE= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/u-root/u-root v5.0.0+incompatible/go.mod h1:RYkpo8pTHrNjW08opNd/U6p/RJE7K0D8fXO0d47+3YY= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ultraware/funlen v0.0.1/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA= github.com/ultraware/funlen v0.0.2/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA= @@ -969,11 +970,11 @@ golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190812203447-cdfb69ac37fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191004110552-13f9640d40b9 h1:rjwSpXsdiK0dV8/Naq3kAw9ymfAeJIyd0upUIElB+lI= golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191204025024-5ee1b9f4859a h1:+HHJiFUXVOIS9mr1ThqkQD1N8vpFCfCShqADBM12KTc= golang.org/x/net v0.0.0-20191204025024-5ee1b9f4859a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -1016,11 +1017,11 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191010194322-b09406accb47 h1:/XfQ9z7ib8eEJX2hdgFTZJ/ntt0swNk5oYBziWeTCvY= golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e h1:9vRrk9YW2BTzLP0VCB9ZDjU4cPqkg+IDWL7XgxA1yxQ= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1094,7 +1095,6 @@ google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRn google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64 h1:iKtrH9Y8mcbADOP0YFaEMth7OfuHY9xHOwNj4znpM1A= google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= @@ -1107,7 +1107,6 @@ google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ij google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.24.0 h1:vb/1TCsVn3DcJlQ0Gs1yB1pKI6Do2/QNwxdKqmc/b0s= google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= google.golang.org/grpc v1.25.1 h1:wdKvqQk7IttEw92GoRyKG2IDrUIpgpj6H6m81yfeMW0= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= @@ -1145,7 +1144,6 @@ gopkg.in/warnings.v0 v0.1.1/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRN gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo= gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/vendor/github.com/docker/docker/pkg/idtools/idtools_unix.go b/vendor/github.com/docker/docker/pkg/idtools/idtools_unix.go deleted file mode 100644 index 3981ff64d3..0000000000 --- a/vendor/github.com/docker/docker/pkg/idtools/idtools_unix.go +++ /dev/null @@ -1,231 +0,0 @@ -// +build !windows - -package idtools // import "github.com/docker/docker/pkg/idtools" - -import ( - "bytes" - "fmt" - "io" - "os" - "path/filepath" - "strings" - "sync" - "syscall" - - "github.com/docker/docker/pkg/system" - "github.com/opencontainers/runc/libcontainer/user" -) - -var ( - entOnce sync.Once - getentCmd string -) - -func mkdirAs(path string, mode os.FileMode, owner Identity, mkAll, chownExisting bool) error { - // make an array containing the original path asked for, plus (for mkAll == true) - // all path components leading up to the complete path that don't exist before we MkdirAll - // so that we can chown all of them properly at the end. If chownExisting is false, we won't - // chown the full directory path if it exists - - var paths []string - - stat, err := system.Stat(path) - if err == nil { - if !stat.IsDir() { - return &os.PathError{Op: "mkdir", Path: path, Err: syscall.ENOTDIR} - } - if !chownExisting { - return nil - } - - // short-circuit--we were called with an existing directory and chown was requested - return lazyChown(path, owner.UID, owner.GID, stat) - } - - if os.IsNotExist(err) { - paths = []string{path} - } - - if mkAll { - // walk back to "/" looking for directories which do not exist - // and add them to the paths array for chown after creation - dirPath := path - for { - dirPath = filepath.Dir(dirPath) - if dirPath == "/" { - break - } - if _, err := os.Stat(dirPath); err != nil && os.IsNotExist(err) { - paths = append(paths, dirPath) - } - } - if err := system.MkdirAll(path, mode); err != nil { - return err - } - } else { - if err := os.Mkdir(path, mode); err != nil && !os.IsExist(err) { - return err - } - } - // even if it existed, we will chown the requested path + any subpaths that - // didn't exist when we called MkdirAll - for _, pathComponent := range paths { - if err := lazyChown(pathComponent, owner.UID, owner.GID, nil); err != nil { - return err - } - } - return nil -} - -// CanAccess takes a valid (existing) directory and a uid, gid pair and determines -// if that uid, gid pair has access (execute bit) to the directory -func CanAccess(path string, pair Identity) bool { - statInfo, err := system.Stat(path) - if err != nil { - return false - } - fileMode := os.FileMode(statInfo.Mode()) - permBits := fileMode.Perm() - return accessible(statInfo.UID() == uint32(pair.UID), - statInfo.GID() == uint32(pair.GID), permBits) -} - -func accessible(isOwner, isGroup bool, perms os.FileMode) bool { - if isOwner && (perms&0100 == 0100) { - return true - } - if isGroup && (perms&0010 == 0010) { - return true - } - if perms&0001 == 0001 { - return true - } - return false -} - -// LookupUser uses traditional local system files lookup (from libcontainer/user) on a username, -// followed by a call to `getent` for supporting host configured non-files passwd and group dbs -func LookupUser(username string) (user.User, error) { - // first try a local system files lookup using existing capabilities - usr, err := user.LookupUser(username) - if err == nil { - return usr, nil - } - // local files lookup failed; attempt to call `getent` to query configured passwd dbs - usr, err = getentUser(fmt.Sprintf("%s %s", "passwd", username)) - if err != nil { - return user.User{}, err - } - return usr, nil -} - -// LookupUID uses traditional local system files lookup (from libcontainer/user) on a uid, -// followed by a call to `getent` for supporting host configured non-files passwd and group dbs -func LookupUID(uid int) (user.User, error) { - // first try a local system files lookup using existing capabilities - usr, err := user.LookupUid(uid) - if err == nil { - return usr, nil - } - // local files lookup failed; attempt to call `getent` to query configured passwd dbs - return getentUser(fmt.Sprintf("%s %d", "passwd", uid)) -} - -func getentUser(args string) (user.User, error) { - reader, err := callGetent(args) - if err != nil { - return user.User{}, err - } - users, err := user.ParsePasswd(reader) - if err != nil { - return user.User{}, err - } - if len(users) == 0 { - return user.User{}, fmt.Errorf("getent failed to find passwd entry for %q", strings.Split(args, " ")[1]) - } - return users[0], nil -} - -// LookupGroup uses traditional local system files lookup (from libcontainer/user) on a group name, -// followed by a call to `getent` for supporting host configured non-files passwd and group dbs -func LookupGroup(groupname string) (user.Group, error) { - // first try a local system files lookup using existing capabilities - group, err := user.LookupGroup(groupname) - if err == nil { - return group, nil - } - // local files lookup failed; attempt to call `getent` to query configured group dbs - return getentGroup(fmt.Sprintf("%s %s", "group", groupname)) -} - -// LookupGID uses traditional local system files lookup (from libcontainer/user) on a group ID, -// followed by a call to `getent` for supporting host configured non-files passwd and group dbs -func LookupGID(gid int) (user.Group, error) { - // first try a local system files lookup using existing capabilities - group, err := user.LookupGid(gid) - if err == nil { - return group, nil - } - // local files lookup failed; attempt to call `getent` to query configured group dbs - return getentGroup(fmt.Sprintf("%s %d", "group", gid)) -} - -func getentGroup(args string) (user.Group, error) { - reader, err := callGetent(args) - if err != nil { - return user.Group{}, err - } - groups, err := user.ParseGroup(reader) - if err != nil { - return user.Group{}, err - } - if len(groups) == 0 { - return user.Group{}, fmt.Errorf("getent failed to find groups entry for %q", strings.Split(args, " ")[1]) - } - return groups[0], nil -} - -func callGetent(args string) (io.Reader, error) { - entOnce.Do(func() { getentCmd, _ = resolveBinary("getent") }) - // if no `getent` command on host, can't do anything else - if getentCmd == "" { - return nil, fmt.Errorf("") - } - out, err := execCmd(getentCmd, args) - if err != nil { - exitCode, errC := system.GetExitCode(err) - if errC != nil { - return nil, err - } - switch exitCode { - case 1: - return nil, fmt.Errorf("getent reported invalid parameters/database unknown") - case 2: - terms := strings.Split(args, " ") - return nil, fmt.Errorf("getent unable to find entry %q in %s database", terms[1], terms[0]) - case 3: - return nil, fmt.Errorf("getent database doesn't support enumeration") - default: - return nil, err - } - - } - return bytes.NewReader(out), nil -} - -// lazyChown performs a chown only if the uid/gid don't match what's requested -// Normally a Chown is a no-op if uid/gid match, but in some cases this can still cause an error, e.g. if the -// dir is on an NFS share, so don't call chown unless we absolutely must. -func lazyChown(p string, uid, gid int, stat *system.StatT) error { - if stat == nil { - var err error - stat, err = system.Stat(p) - if err != nil { - return err - } - } - if stat.UID() == uint32(uid) && stat.GID() == uint32(gid) { - return nil - } - return os.Chown(p, uid, gid) -} diff --git a/vendor/github.com/docker/docker/pkg/idtools/idtools_windows.go b/vendor/github.com/docker/docker/pkg/idtools/idtools_windows.go deleted file mode 100644 index 35ede0fffa..0000000000 --- a/vendor/github.com/docker/docker/pkg/idtools/idtools_windows.go +++ /dev/null @@ -1,25 +0,0 @@ -package idtools // import "github.com/docker/docker/pkg/idtools" - -import ( - "os" - - "github.com/docker/docker/pkg/system" -) - -// This is currently a wrapper around MkdirAll, however, since currently -// permissions aren't set through this path, the identity isn't utilized. -// Ownership is handled elsewhere, but in the future could be support here -// too. -func mkdirAs(path string, mode os.FileMode, owner Identity, mkAll, chownExisting bool) error { - if err := system.MkdirAll(path, mode); err != nil { - return err - } - return nil -} - -// CanAccess takes a valid (existing) directory and a uid, gid pair and determines -// if that uid, gid pair has access (execute bit) to the directory -// Windows does not require/support this function, so always return true -func CanAccess(path string, identity Identity) bool { - return true -} diff --git a/vendor/github.com/docker/docker/pkg/idtools/usergroupadd_linux.go b/vendor/github.com/docker/docker/pkg/idtools/usergroupadd_linux.go deleted file mode 100644 index 6272c5a404..0000000000 --- a/vendor/github.com/docker/docker/pkg/idtools/usergroupadd_linux.go +++ /dev/null @@ -1,164 +0,0 @@ -package idtools // import "github.com/docker/docker/pkg/idtools" - -import ( - "fmt" - "regexp" - "sort" - "strconv" - "strings" - "sync" -) - -// add a user and/or group to Linux /etc/passwd, /etc/group using standard -// Linux distribution commands: -// adduser --system --shell /bin/false --disabled-login --disabled-password --no-create-home --group -// useradd -r -s /bin/false - -var ( - once sync.Once - userCommand string - - cmdTemplates = map[string]string{ - "adduser": "--system --shell /bin/false --no-create-home --disabled-login --disabled-password --group %s", - "useradd": "-r -s /bin/false %s", - "usermod": "-%s %d-%d %s", - } - - idOutRegexp = regexp.MustCompile(`uid=([0-9]+).*gid=([0-9]+)`) - // default length for a UID/GID subordinate range - defaultRangeLen = 65536 - defaultRangeStart = 100000 - userMod = "usermod" -) - -// AddNamespaceRangesUser takes a username and uses the standard system -// utility to create a system user/group pair used to hold the -// /etc/sub{uid,gid} ranges which will be used for user namespace -// mapping ranges in containers. -func AddNamespaceRangesUser(name string) (int, int, error) { - if err := addUser(name); err != nil { - return -1, -1, fmt.Errorf("Error adding user %q: %v", name, err) - } - - // Query the system for the created uid and gid pair - out, err := execCmd("id", name) - if err != nil { - return -1, -1, fmt.Errorf("Error trying to find uid/gid for new user %q: %v", name, err) - } - matches := idOutRegexp.FindStringSubmatch(strings.TrimSpace(string(out))) - if len(matches) != 3 { - return -1, -1, fmt.Errorf("Can't find uid, gid from `id` output: %q", string(out)) - } - uid, err := strconv.Atoi(matches[1]) - if err != nil { - return -1, -1, fmt.Errorf("Can't convert found uid (%s) to int: %v", matches[1], err) - } - gid, err := strconv.Atoi(matches[2]) - if err != nil { - return -1, -1, fmt.Errorf("Can't convert found gid (%s) to int: %v", matches[2], err) - } - - // Now we need to create the subuid/subgid ranges for our new user/group (system users - // do not get auto-created ranges in subuid/subgid) - - if err := createSubordinateRanges(name); err != nil { - return -1, -1, fmt.Errorf("Couldn't create subordinate ID ranges: %v", err) - } - return uid, gid, nil -} - -func addUser(userName string) error { - once.Do(func() { - // set up which commands are used for adding users/groups dependent on distro - if _, err := resolveBinary("adduser"); err == nil { - userCommand = "adduser" - } else if _, err := resolveBinary("useradd"); err == nil { - userCommand = "useradd" - } - }) - if userCommand == "" { - return fmt.Errorf("Cannot add user; no useradd/adduser binary found") - } - args := fmt.Sprintf(cmdTemplates[userCommand], userName) - out, err := execCmd(userCommand, args) - if err != nil { - return fmt.Errorf("Failed to add user with error: %v; output: %q", err, string(out)) - } - return nil -} - -func createSubordinateRanges(name string) error { - - // first, we should verify that ranges weren't automatically created - // by the distro tooling - ranges, err := parseSubuid(name) - if err != nil { - return fmt.Errorf("Error while looking for subuid ranges for user %q: %v", name, err) - } - if len(ranges) == 0 { - // no UID ranges; let's create one - startID, err := findNextUIDRange() - if err != nil { - return fmt.Errorf("Can't find available subuid range: %v", err) - } - out, err := execCmd(userMod, fmt.Sprintf(cmdTemplates[userMod], "v", startID, startID+defaultRangeLen-1, name)) - if err != nil { - return fmt.Errorf("Unable to add subuid range to user: %q; output: %s, err: %v", name, out, err) - } - } - - ranges, err = parseSubgid(name) - if err != nil { - return fmt.Errorf("Error while looking for subgid ranges for user %q: %v", name, err) - } - if len(ranges) == 0 { - // no GID ranges; let's create one - startID, err := findNextGIDRange() - if err != nil { - return fmt.Errorf("Can't find available subgid range: %v", err) - } - out, err := execCmd(userMod, fmt.Sprintf(cmdTemplates[userMod], "w", startID, startID+defaultRangeLen-1, name)) - if err != nil { - return fmt.Errorf("Unable to add subgid range to user: %q; output: %s, err: %v", name, out, err) - } - } - return nil -} - -func findNextUIDRange() (int, error) { - ranges, err := parseSubuid("ALL") - if err != nil { - return -1, fmt.Errorf("Couldn't parse all ranges in /etc/subuid file: %v", err) - } - sort.Sort(ranges) - return findNextRangeStart(ranges) -} - -func findNextGIDRange() (int, error) { - ranges, err := parseSubgid("ALL") - if err != nil { - return -1, fmt.Errorf("Couldn't parse all ranges in /etc/subgid file: %v", err) - } - sort.Sort(ranges) - return findNextRangeStart(ranges) -} - -func findNextRangeStart(rangeList ranges) (int, error) { - startID := defaultRangeStart - for _, arange := range rangeList { - if wouldOverlap(arange, startID) { - startID = arange.Start + arange.Length - } - } - return startID, nil -} - -func wouldOverlap(arange subIDRange, ID int) bool { - low := ID - high := ID + defaultRangeLen - if (low >= arange.Start && low <= arange.Start+arange.Length) || - (high <= arange.Start+arange.Length && high >= arange.Start) { - return true - } - return false -} diff --git a/vendor/github.com/docker/docker/pkg/idtools/usergroupadd_unsupported.go b/vendor/github.com/docker/docker/pkg/idtools/usergroupadd_unsupported.go deleted file mode 100644 index e7c4d63118..0000000000 --- a/vendor/github.com/docker/docker/pkg/idtools/usergroupadd_unsupported.go +++ /dev/null @@ -1,12 +0,0 @@ -// +build !linux - -package idtools // import "github.com/docker/docker/pkg/idtools" - -import "fmt" - -// AddNamespaceRangesUser takes a name and finds an unused uid, gid pair -// and calls the appropriate helper function to add the group and then -// the user to the group in /etc/group and /etc/passwd respectively. -func AddNamespaceRangesUser(name string) (int, int, error) { - return -1, -1, fmt.Errorf("No support for adding users or groups on this OS") -} diff --git a/vendor/github.com/docker/docker/pkg/idtools/utils_unix.go b/vendor/github.com/docker/docker/pkg/idtools/utils_unix.go deleted file mode 100644 index 903ac4501b..0000000000 --- a/vendor/github.com/docker/docker/pkg/idtools/utils_unix.go +++ /dev/null @@ -1,32 +0,0 @@ -// +build !windows - -package idtools // import "github.com/docker/docker/pkg/idtools" - -import ( - "fmt" - "os/exec" - "path/filepath" - "strings" -) - -func resolveBinary(binname string) (string, error) { - binaryPath, err := exec.LookPath(binname) - if err != nil { - return "", err - } - resolvedPath, err := filepath.EvalSymlinks(binaryPath) - if err != nil { - return "", err - } - //only return no error if the final resolved binary basename - //matches what was searched for - if filepath.Base(resolvedPath) == binname { - return resolvedPath, nil - } - return "", fmt.Errorf("Binary %q does not resolve to a binary of that name in $PATH (%q)", binname, resolvedPath) -} - -func execCmd(cmd, args string) ([]byte, error) { - execCmd := exec.Command(cmd, strings.Split(args, " ")...) - return execCmd.CombinedOutput() -} diff --git a/vendor/github.com/rootless-containers/rootlesskit/pkg/child/child.go b/vendor/github.com/rootless-containers/rootlesskit/pkg/child/child.go index 53232be448..5faf99a6a1 100644 --- a/vendor/github.com/rootless-containers/rootlesskit/pkg/child/child.go +++ b/vendor/github.com/rootless-containers/rootlesskit/pkg/child/child.go @@ -4,6 +4,7 @@ import ( "io/ioutil" "os" "os/exec" + "os/signal" "runtime" "strconv" "syscall" @@ -43,39 +44,33 @@ func mountSysfs() error { return errors.Wrap(err, "creating a directory under /tmp") } defer os.RemoveAll(tmp) - cmds := [][]string{{"mount", "--rbind", "/sys/fs/cgroup", tmp}} - if err := common.Execs(os.Stderr, os.Environ(), cmds); err != nil { - return errors.Wrapf(err, "executing %v", cmds) + cgroupDir := "/sys/fs/cgroup" + if err := unix.Mount(cgroupDir, tmp, "", uintptr(unix.MS_BIND|unix.MS_REC), ""); err != nil { + return errors.Wrapf(err, "failed to create bind mount on %s", cgroupDir) } - cmds = [][]string{{"mount", "-t", "sysfs", "none", "/sys"}} - if err := common.Execs(os.Stderr, os.Environ(), cmds); err != nil { + + if err := unix.Mount("none", "/sys", "sysfs", 0, ""); err != nil { // when the sysfs in the parent namespace is RO, // we can't mount RW sysfs even in the child namespace. // https://github.com/rootless-containers/rootlesskit/pull/23#issuecomment-429292632 // https://github.com/torvalds/linux/blob/9f203e2f2f065cd74553e6474f0ae3675f39fb0f/fs/namespace.c#L3326-L3328 - cmdsRo := [][]string{{"mount", "-t", "sysfs", "-o", "ro", "none", "/sys"}} - logrus.Warnf("failed to mount sysfs (%v), falling back to read-only mount (%v): %v", - cmds, cmdsRo, err) - if err := common.Execs(os.Stderr, os.Environ(), cmdsRo); err != nil { + logrus.Warnf("failed to mount sysfs, falling back to read-only mount: %v", err) + if err := unix.Mount("none", "/sys", "sysfs", uintptr(unix.MS_RDONLY), ""); err != nil { // when /sys/firmware is masked, even RO sysfs can't be mounted - logrus.Warnf("failed to mount sysfs (%v): %v", cmdsRo, err) + logrus.Warnf("failed to mount sysfs: %v", err) } } - cmds = [][]string{{"mount", "-n", "--move", tmp, "/sys/fs/cgroup"}} - if err := common.Execs(os.Stderr, os.Environ(), cmds); err != nil { - return errors.Wrapf(err, "executing %v", cmds) + if err := unix.Mount(tmp, cgroupDir, "", uintptr(unix.MS_MOVE), ""); err != nil { + return errors.Wrapf(err, "failed to move mount point from %s to %s", tmp, cgroupDir) } return nil } func mountProcfs() error { - cmds := [][]string{{"mount", "-t", "proc", "none", "/proc"}} - if err := common.Execs(os.Stderr, os.Environ(), cmds); err != nil { - cmdsRo := [][]string{{"mount", "-t", "proc", "-o", "ro", "none", "/proc"}} - logrus.Warnf("failed to mount procfs (%v), falling back to read-only mount (%v): %v", - cmds, cmdsRo, err) - if err := common.Execs(os.Stderr, os.Environ(), cmdsRo); err != nil { - logrus.Warnf("failed to mount procfs (%v): %v", cmdsRo, err) + if err := unix.Mount("none", "/proc", "proc", 0, ""); err != nil { + logrus.Warnf("failed to mount procfs, falling back to read-only mount: %v", err) + if err := unix.Mount("none", "/proc", "proc", uintptr(unix.MS_RDONLY), ""); err != nil { + logrus.Warnf("failed to mount procfs: %v", err) } } return nil @@ -171,6 +166,7 @@ type Opt struct { CopyUpDirs []string PortDriver port.ChildDriver MountProcfs bool // needs to be set if (and only if) parent.Opt.CreatePIDNS is set + Reaper bool } func Child(opt Opt) error { @@ -242,8 +238,14 @@ func Child(opt Opt) error { if err != nil { return err } - if err := cmd.Run(); err != nil { - return errors.Wrapf(err, "command %v exited", opt.TargetCmd) + if opt.Reaper { + if err := runAndReap(cmd); err != nil { + return errors.Wrapf(err, "command %v exited", opt.TargetCmd) + } + } else { + if err := cmd.Run(); err != nil { + return errors.Wrapf(err, "command %v exited", opt.TargetCmd) + } } if opt.PortDriver != nil { portQuitCh <- struct{}{} @@ -251,3 +253,27 @@ func Child(opt Opt) error { } return nil } + +func runAndReap(cmd *exec.Cmd) error { + c := make(chan os.Signal, 32) + signal.Notify(c, syscall.SIGCHLD) + if err := cmd.Start(); err != nil { + return err + } + result := make(chan error) + go func() { + defer close(result) + for range c { + for { + if pid, err := syscall.Wait4(-1, nil, syscall.WNOHANG, nil); err != nil || pid <= 0 { + break + } else { + if pid == cmd.Process.Pid { + result <- cmd.Wait() + } + } + } + } + }() + return <-result +} diff --git a/vendor/github.com/rootless-containers/rootlesskit/pkg/child/hosts.go b/vendor/github.com/rootless-containers/rootlesskit/pkg/child/hosts.go index 4f73910210..ce12cd5c57 100644 --- a/vendor/github.com/rootless-containers/rootlesskit/pkg/child/hosts.go +++ b/vendor/github.com/rootless-containers/rootlesskit/pkg/child/hosts.go @@ -6,9 +6,9 @@ import ( "os" "path/filepath" - "github.com/pkg/errors" + "golang.org/x/sys/unix" - "github.com/rootless-containers/rootlesskit/pkg/common" + "github.com/pkg/errors" ) // generateEtcHosts makes sure the current hostname is resolved into @@ -56,11 +56,9 @@ func mountEtcHosts(tempDir string) error { if err := ioutil.WriteFile(myEtcHosts, newEtcHosts, 0644); err != nil { return errors.Wrapf(err, "writing %s", myEtcHosts) } - cmds := [][]string{ - {"mount", "--bind", myEtcHosts, "/etc/hosts"}, - } - if err := common.Execs(os.Stderr, os.Environ(), cmds); err != nil { - return errors.Wrapf(err, "executing %v", cmds) + + if err := unix.Mount(myEtcHosts, "/etc/hosts", "", uintptr(unix.MS_BIND), ""); err != nil { + return errors.Wrapf(err, "failed to create bind mount /etc/hosts for %s", myEtcHosts) } return nil } diff --git a/vendor/github.com/rootless-containers/rootlesskit/pkg/child/resolvconf.go b/vendor/github.com/rootless-containers/rootlesskit/pkg/child/resolvconf.go index 56cc70926a..6b88047c5c 100644 --- a/vendor/github.com/rootless-containers/rootlesskit/pkg/child/resolvconf.go +++ b/vendor/github.com/rootless-containers/rootlesskit/pkg/child/resolvconf.go @@ -1,13 +1,12 @@ package child import ( + "golang.org/x/sys/unix" "io/ioutil" "os" "path/filepath" "github.com/pkg/errors" - - "github.com/rootless-containers/rootlesskit/pkg/common" ) func generateResolvConf(dns string) []byte { @@ -36,11 +35,9 @@ func mountResolvConf(tempDir, dns string) error { if err := ioutil.WriteFile(myResolvConf, generateResolvConf(dns), 0644); err != nil { return errors.Wrapf(err, "writing %s", myResolvConf) } - cmds := [][]string{ - {"mount", "--bind", myResolvConf, "/etc/resolv.conf"}, - } - if err := common.Execs(os.Stderr, os.Environ(), cmds); err != nil { - return errors.Wrapf(err, "executing %v", cmds) + + if err := unix.Mount(myResolvConf, "/etc/resolv.conf", "", uintptr(unix.MS_BIND), ""); err != nil { + return errors.Wrapf(err, "failed to create bind mount /etc/resolv.conf for %s", myResolvConf) } return nil } diff --git a/vendor/github.com/rootless-containers/rootlesskit/pkg/copyup/tmpfssymlink/tmpfssymlink.go b/vendor/github.com/rootless-containers/rootlesskit/pkg/copyup/tmpfssymlink/tmpfssymlink.go index f4bd495895..35c006e3bf 100644 --- a/vendor/github.com/rootless-containers/rootlesskit/pkg/copyup/tmpfssymlink/tmpfssymlink.go +++ b/vendor/github.com/rootless-containers/rootlesskit/pkg/copyup/tmpfssymlink/tmpfssymlink.go @@ -5,9 +5,10 @@ import ( "os" "path/filepath" + "golang.org/x/sys/unix" + "github.com/pkg/errors" - "github.com/rootless-containers/rootlesskit/pkg/common" "github.com/rootless-containers/rootlesskit/pkg/copyup" ) @@ -33,24 +34,23 @@ func (d *childDriver) CopyUp(dirs []string) ([]string, error) { // TODO: we can support copy-up /tmp by changing bind0TempDir return copied, errors.New("/tmp cannot be copied up") } - cmds := [][]string{ - // TODO: read-only bind (does not work well for /run) - {"mount", "--rbind", d, bind0}, - {"mount", "-n", "-t", "tmpfs", "none", d}, + + if err := unix.Mount(d, bind0, "", uintptr(unix.MS_BIND|unix.MS_REC), ""); err != nil { + return copied, errors.Wrapf(err, "failed to create bind mount on %s", d) } - if err := common.Execs(os.Stderr, os.Environ(), cmds); err != nil { - return copied, errors.Wrapf(err, "executing %v", cmds) + + if err := unix.Mount("none", d, "tmpfs", 0, ""); err != nil { + return copied, errors.Wrapf(err, "failed to mount tmpfs on %s", d) } + bind1, err := ioutil.TempDir(d, ".ro") if err != nil { return copied, errors.Wrapf(err, "creating a directory under %s", d) } - cmds = [][]string{ - {"mount", "-n", "--move", bind0, bind1}, - } - if err := common.Execs(os.Stderr, os.Environ(), cmds); err != nil { - return copied, errors.Wrapf(err, "executing %v", cmds) + if err := unix.Mount(bind0, bind1, "", uintptr(unix.MS_MOVE), ""); err != nil { + return copied, errors.Wrapf(err, "failed to move mount point from %s to %s", bind0, bind1) } + files, err := ioutil.ReadDir(bind1) if err != nil { return copied, errors.Wrapf(err, "reading dir %s", bind1) diff --git a/vendor/github.com/rootless-containers/rootlesskit/pkg/network/slirp4netns/slirp4netns.go b/vendor/github.com/rootless-containers/rootlesskit/pkg/network/slirp4netns/slirp4netns.go index 45e1aa53e7..b31e0cfe08 100644 --- a/vendor/github.com/rootless-containers/rootlesskit/pkg/network/slirp4netns/slirp4netns.go +++ b/vendor/github.com/rootless-containers/rootlesskit/pkg/network/slirp4netns/slirp4netns.go @@ -3,12 +3,16 @@ package slirp4netns import ( "context" "net" + "os" "os/exec" "strconv" + "strings" "syscall" + "time" "github.com/pkg/errors" "github.com/sirupsen/logrus" + "golang.org/x/sys/unix" "github.com/rootless-containers/rootlesskit/pkg/common" "github.com/rootless-containers/rootlesskit/pkg/network" @@ -16,13 +20,62 @@ import ( "github.com/rootless-containers/rootlesskit/pkg/network/parentutils" ) +type Features struct { + // SupportsCIDR --cidr (v0.3.0) + SupportsCIDR bool + // SupportsDisableHostLoopback --disable-host-loopback (v0.3.0) + SupportsDisableHostLoopback bool + // SupportsAPISocket --api-socket (v0.3.0) + SupportsAPISocket bool + // SupportsEnableSandbox --enable-sandbox (v0.4.0) + SupportsEnableSandbox bool + // SupportsEnableSeccomp --enable-seccomp (v0.4.0) + SupportsEnableSeccomp bool + // KernelSupportsSeccomp whether the kernel supports slirp4netns --enable-seccomp + KernelSupportsEnableSeccomp bool +} + +func DetectFeatures(binary string) (*Features, error) { + if binary == "" { + return nil, errors.New("got empty slirp4netns binary") + } + realBinary, err := exec.LookPath(binary) + if err != nil { + return nil, errors.Wrapf(err, "slirp4netns binary %q is not installed", binary) + } + cmd := exec.Command(realBinary, "--help") + cmd.Env = os.Environ() + b, err := cmd.CombinedOutput() + s := string(b) + if err != nil { + return nil, errors.Wrapf(err, + "command \"%s --help\" failed, make sure slirp4netns v0.2.0+ is installed: %q", + realBinary, s) + } + kernelSupportsEnableSeccomp := false + if unix.Prctl(unix.PR_GET_SECCOMP, 0, 0, 0, 0) != unix.EINVAL { + kernelSupportsEnableSeccomp = unix.Prctl(unix.PR_SET_SECCOMP, unix.SECCOMP_MODE_FILTER, 0, 0, 0) != unix.EINVAL + } + f := Features{ + SupportsCIDR: strings.Contains(s, "--cidr"), + SupportsDisableHostLoopback: strings.Contains(s, "--disable-host-loopback"), + SupportsAPISocket: strings.Contains(s, "--api-socket"), + SupportsEnableSandbox: strings.Contains(s, "--enable-sandbox"), + SupportsEnableSeccomp: strings.Contains(s, "--enable-seccomp"), + KernelSupportsEnableSeccomp: kernelSupportsEnableSeccomp, + } + return &f, nil +} + // NewParentDriver instantiates new parent driver. // ipnet is supported only for slirp4netns v0.3.0+. // ipnet MUST be nil for slirp4netns < v0.3.0. // // disableHostLoopback is supported only for slirp4netns v0.3.0+ // apiSocketPath is supported only for slirp4netns v0.3.0+ -func NewParentDriver(binary string, mtu int, ipnet *net.IPNet, disableHostLoopback bool, apiSocketPath string) network.ParentDriver { +// enableSandbox is supported only for slirp4netns v0.4.0+ +// enableSeccomp is supported only for slirp4netns v0.4.0+ +func NewParentDriver(binary string, mtu int, ipnet *net.IPNet, disableHostLoopback bool, apiSocketPath string, enableSandbox, enableSeccomp bool) network.ParentDriver { if binary == "" { panic("got empty slirp4netns binary") } @@ -38,6 +91,8 @@ func NewParentDriver(binary string, mtu int, ipnet *net.IPNet, disableHostLoopba ipnet: ipnet, disableHostLoopback: disableHostLoopback, apiSocketPath: apiSocketPath, + enableSandbox: enableSandbox, + enableSeccomp: enableSeccomp, } } @@ -47,6 +102,8 @@ type parentDriver struct { ipnet *net.IPNet disableHostLoopback bool apiSocketPath string + enableSandbox bool + enableSeccomp bool } func (d *parentDriver) MTU() int { @@ -60,7 +117,14 @@ func (d *parentDriver) ConfigureNetwork(childPID int, stateDir string) (*common. return nil, common.Seq(cleanups), errors.Wrapf(err, "setting up tap %s", tap) } ctx, cancel := context.WithCancel(context.Background()) - opts := []string{"--mtu", strconv.Itoa(d.mtu)} + readyR, readyW, err := os.Pipe() + if err != nil { + return nil, common.Seq(cleanups), err + } + defer readyR.Close() + defer readyW.Close() + // -r: readyFD + opts := []string{"--mtu", strconv.Itoa(d.mtu), "-r", "3"} if d.disableHostLoopback { opts = append(opts, "--disable-host-loopback") } @@ -70,10 +134,17 @@ func (d *parentDriver) ConfigureNetwork(childPID int, stateDir string) (*common. if d.apiSocketPath != "" { opts = append(opts, "--api-socket", d.apiSocketPath) } + if d.enableSandbox { + opts = append(opts, "--enable-sandbox") + } + if d.enableSeccomp { + opts = append(opts, "--enable-seccomp") + } cmd := exec.CommandContext(ctx, d.binary, append(opts, []string{strconv.Itoa(childPID), tap}...)...) cmd.SysProcAttr = &syscall.SysProcAttr{ Pdeathsig: syscall.SIGKILL, } + cmd.ExtraFiles = append(cmd.ExtraFiles, readyW) cleanups = append(cleanups, func() error { logrus.Debugf("killing slirp4netns") cancel() @@ -84,6 +155,10 @@ func (d *parentDriver) ConfigureNetwork(childPID int, stateDir string) (*common. if err := cmd.Start(); err != nil { return nil, common.Seq(cleanups), errors.Wrapf(err, "executing %v", cmd) } + + if err := waitForReadyFD(cmd.Process.Pid, readyR); err != nil { + return nil, common.Seq(cleanups), errors.Wrapf(err, "waiting for ready fd (%v)", cmd) + } netmsg := common.NetworkMessage{ Dev: tap, MTU: d.mtu, @@ -115,6 +190,41 @@ func (d *parentDriver) ConfigureNetwork(childPID int, stateDir string) (*common. return &netmsg, common.Seq(cleanups), nil } +// waitForReady is from libpod +// https://github.com/containers/libpod/blob/e6b843312b93ddaf99d0ef94a7e60ff66bc0eac8/libpod/networking_linux.go#L272-L308 +func waitForReadyFD(cmdPid int, r *os.File) error { + b := make([]byte, 16) + for { + if err := r.SetDeadline(time.Now().Add(1 * time.Second)); err != nil { + return errors.Wrapf(err, "error setting slirp4netns pipe timeout") + } + if _, err := r.Read(b); err == nil { + break + } else { + if os.IsTimeout(err) { + // Check if the process is still running. + var status syscall.WaitStatus + pid, err := syscall.Wait4(cmdPid, &status, syscall.WNOHANG, nil) + if err != nil { + return errors.Wrapf(err, "failed to read slirp4netns process status") + } + if pid != cmdPid { + continue + } + if status.Exited() { + return errors.New("slirp4netns failed") + } + if status.Signaled() { + return errors.New("slirp4netns killed by signal") + } + continue + } + return errors.Wrapf(err, "failed to read from slirp4netns sync pipe") + } + } + return nil +} + func NewChildDriver() network.ChildDriver { return &childDriver{} } diff --git a/vendor/github.com/docker/docker/pkg/idtools/idtools.go b/vendor/github.com/rootless-containers/rootlesskit/pkg/parent/idtools/idtools.go similarity index 85% rename from vendor/github.com/docker/docker/pkg/idtools/idtools.go rename to vendor/github.com/rootless-containers/rootlesskit/pkg/parent/idtools/idtools.go index b3af7a4226..f3811fd8a9 100644 --- a/vendor/github.com/docker/docker/pkg/idtools/idtools.go +++ b/vendor/github.com/rootless-containers/rootlesskit/pkg/parent/idtools/idtools.go @@ -1,9 +1,11 @@ -package idtools // import "github.com/docker/docker/pkg/idtools" +// Package idtools is forked from https://github.com/moby/moby/tree/c12f09bf99b54f274a5ae241dd154fa74020cbab/pkg/idtools +package idtools import ( "bufio" "fmt" "os" + "sort" "strconv" "strings" ) @@ -33,28 +35,6 @@ const ( subgidFileName = "/etc/subgid" ) -// MkdirAllAndChown creates a directory (include any along the path) and then modifies -// ownership to the requested uid/gid. If the directory already exists, this -// function will still change ownership to the requested uid/gid pair. -func MkdirAllAndChown(path string, mode os.FileMode, owner Identity) error { - return mkdirAs(path, mode, owner, true, true) -} - -// MkdirAndChown creates a directory and then modifies ownership to the requested uid/gid. -// If the directory already exists, this function still changes ownership. -// Note that unlike os.Mkdir(), this function does not return IsExist error -// in case path already exists. -func MkdirAndChown(path string, mode os.FileMode, owner Identity) error { - return mkdirAs(path, mode, owner, false, true) -} - -// MkdirAllAndChownNew creates a directory (include any along the path) and then modifies -// ownership ONLY of newly created directories to the requested uid/gid. If the -// directories along the path exist, no change of ownership will be performed -func MkdirAllAndChownNew(path string, mode os.FileMode, owner Identity) error { - return mkdirAs(path, mode, owner, true, false) -} - // GetRootUIDGID retrieves the remapped root uid/gid pair from the set of maps. // If the maps are empty, then the root uid/gid will default to "real" 0/0 func GetRootUIDGID(uidMap, gidMap []IDMap) (int, int, error) { @@ -202,6 +182,8 @@ func (i *IdentityMapping) GIDs() []IDMap { func createIDMap(subidRanges ranges) []IDMap { idMap := []IDMap{} + // sort the ranges by lowest ID first + sort.Sort(subidRanges) containerID := 0 for _, idrange := range subidRanges { idMap = append(idMap, IDMap{ diff --git a/vendor/github.com/rootless-containers/rootlesskit/pkg/parent/parent.go b/vendor/github.com/rootless-containers/rootlesskit/pkg/parent/parent.go index 04a42828aa..e4cee22a4d 100644 --- a/vendor/github.com/rootless-containers/rootlesskit/pkg/parent/parent.go +++ b/vendor/github.com/rootless-containers/rootlesskit/pkg/parent/parent.go @@ -12,7 +12,6 @@ import ( "strconv" "syscall" - "github.com/docker/docker/pkg/idtools" "github.com/gorilla/mux" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -22,6 +21,7 @@ import ( "github.com/rootless-containers/rootlesskit/pkg/common" "github.com/rootless-containers/rootlesskit/pkg/msgutil" "github.com/rootless-containers/rootlesskit/pkg/network" + "github.com/rootless-containers/rootlesskit/pkg/parent/idtools" "github.com/rootless-containers/rootlesskit/pkg/port" ) @@ -103,10 +103,6 @@ func Parent(opt Opt) error { if err := cmd.Start(); err != nil { return errors.Wrap(err, "failed to start the child") } - childPIDPath := filepath.Join(opt.StateDir, StateFileChildPID) - if err := ioutil.WriteFile(childPIDPath, []byte(strconv.Itoa(cmd.Process.Pid)), 0444); err != nil { - return errors.Wrapf(err, "failed to write the child PID %d to %s", cmd.Process.Pid, childPIDPath) - } if err := setupUIDGIDMap(cmd.Process.Pid); err != nil { return errors.Wrap(err, "failed to setup UID/GID map") } @@ -176,6 +172,12 @@ func Parent(opt Opt) error { logrus.Debugf("published port %v", st) } } + + // after child is fully configured, write PID to child_pid file + childPIDPath := filepath.Join(opt.StateDir, StateFileChildPID) + if err := ioutil.WriteFile(childPIDPath, []byte(strconv.Itoa(cmd.Process.Pid)), 0444); err != nil { + return errors.Wrapf(err, "failed to write the child PID %d to %s", cmd.Process.Pid, childPIDPath) + } // listens the API apiSockPath := filepath.Join(opt.StateDir, StateFileAPISock) apiCloser, err := listenServeAPI(apiSockPath, &router.Backend{PortDriver: opt.PortDriver}) diff --git a/vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/builtin.go b/vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/builtin.go index a098714c0a..ca3f10b26d 100644 --- a/vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/builtin.go +++ b/vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/builtin.go @@ -1,487 +1,14 @@ package builtin import ( - "context" - "fmt" "io" - "io/ioutil" - "net" - "os" - "path/filepath" - "sync" - "syscall" - "time" - "github.com/pkg/errors" - "golang.org/x/sys/unix" - - "github.com/rootless-containers/rootlesskit/pkg/msgutil" "github.com/rootless-containers/rootlesskit/pkg/port" - "github.com/rootless-containers/rootlesskit/pkg/port/portutil" + "github.com/rootless-containers/rootlesskit/pkg/port/builtin/child" + "github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent" ) -const ( - opaqueKeySocketPath = "builtin.socketpath" - opaqueKeyChildReadyPipePath = "builtin.readypipepath" +var ( + NewParentDriver func(logWriter io.Writer, stateDir string) (port.ParentDriver, error) = parent.NewDriver + NewChildDriver func(logWriter io.Writer) port.ChildDriver = child.NewDriver ) - -// NewParentDriver for builtin driver. -func NewParentDriver(logWriter io.Writer, stateDir string) (port.ParentDriver, error) { - // TODO: consider using socketpair FD instead of socket file - socketPath := filepath.Join(stateDir, ".bp.sock") - childReadyPipePath := filepath.Join(stateDir, ".bp-ready.pipe") - // remove the path just incase the previous rootlesskit instance crashed - if err := os.RemoveAll(childReadyPipePath); err != nil { - return nil, errors.Wrapf(err, "cannot remove %s", childReadyPipePath) - } - if err := syscall.Mkfifo(childReadyPipePath, 0600); err != nil { - return nil, errors.Wrapf(err, "cannot mkfifo %s", childReadyPipePath) - } - d := driver{ - logWriter: logWriter, - socketPath: socketPath, - childReadyPipePath: childReadyPipePath, - ports: make(map[int]*port.Status, 0), - stoppers: make(map[int]func() error, 0), - nextID: 1, - } - return &d, nil -} - -type driver struct { - logWriter io.Writer - socketPath string - childReadyPipePath string - mu sync.Mutex - ports map[int]*port.Status - stoppers map[int]func() error - nextID int -} - -func (d *driver) OpaqueForChild() map[string]string { - return map[string]string{ - opaqueKeySocketPath: d.socketPath, - opaqueKeyChildReadyPipePath: d.childReadyPipePath, - } -} - -func (d *driver) RunParentDriver(initComplete chan struct{}, quit <-chan struct{}, _ *port.ChildContext) error { - childReadyPipeR, err := os.OpenFile(d.childReadyPipePath, os.O_RDONLY, os.ModeNamedPipe) - if err != nil { - return err - } - if _, err = ioutil.ReadAll(childReadyPipeR); err != nil { - return err - } - childReadyPipeR.Close() - var dialer net.Dialer - conn, err := dialer.Dial("unix", d.socketPath) - if err != nil { - return err - } - err = initiate(conn.(*net.UnixConn)) - conn.Close() - if err != nil { - return err - } - initComplete <- struct{}{} - <-quit - return nil -} - -func (d *driver) AddPort(ctx context.Context, spec port.Spec) (*port.Status, error) { - d.mu.Lock() - err := portutil.ValidatePortSpec(spec, d.ports) - d.mu.Unlock() - if err != nil { - return nil, err - } - routineStopCh := make(chan struct{}) - routineStop := func() error { - close(routineStopCh) - return nil // FIXME - } - switch spec.Proto { - case "tcp": - err = startTCPRoutines(d.socketPath, spec, routineStopCh, d.logWriter) - case "udp": - err = startUDPRoutines(d.socketPath, spec, routineStopCh, d.logWriter) - default: - // NOTREACHED - return nil, errors.New("spec was not validated?") - } - if err != nil { - return nil, err - } - d.mu.Lock() - id := d.nextID - st := port.Status{ - ID: id, - Spec: spec, - } - d.ports[id] = &st - d.stoppers[id] = routineStop - d.nextID++ - d.mu.Unlock() - return &st, nil -} - -func (d *driver) ListPorts(ctx context.Context) ([]port.Status, error) { - var ports []port.Status - d.mu.Lock() - for _, p := range d.ports { - ports = append(ports, *p) - } - d.mu.Unlock() - return ports, nil -} - -func (d *driver) RemovePort(ctx context.Context, id int) error { - d.mu.Lock() - defer d.mu.Unlock() - stop, ok := d.stoppers[id] - if !ok { - return errors.Errorf("unknown id: %d", id) - } - err := stop() - delete(d.stoppers, id) - delete(d.ports, id) - return err -} - -func initiate(c *net.UnixConn) error { - req := request{ - Type: requestTypeInit, - } - if _, err := msgutil.MarshalToWriter(c, &req); err != nil { - return err - } - if err := c.CloseWrite(); err != nil { - return err - } - var rep reply - if _, err := msgutil.UnmarshalFromReader(c, &rep); err != nil { - return err - } - return c.CloseRead() -} - -func connectToChild(socketPath string, spec port.Spec) (int, error) { - var dialer net.Dialer - conn, err := dialer.Dial("unix", socketPath) - if err != nil { - return 0, err - } - defer conn.Close() - c := conn.(*net.UnixConn) - req := request{ - Type: requestTypeConnect, - Proto: spec.Proto, - Port: spec.ChildPort, - } - if _, err := msgutil.MarshalToWriter(c, &req); err != nil { - return 0, err - } - if err := c.CloseWrite(); err != nil { - return 0, err - } - oobSpace := unix.CmsgSpace(4) - oob := make([]byte, oobSpace) - _, oobN, _, _, err := c.ReadMsgUnix(nil, oob) - if err != nil { - return 0, err - } - if oobN != oobSpace { - return 0, errors.Errorf("expected OOB space %d, got %d", oobSpace, oobN) - } - oob = oob[:oobN] - fd, err := parseFDFromOOB(oob) - if err != nil { - return 0, err - } - if err := c.CloseRead(); err != nil { - return 0, err - } - return fd, nil -} - -func connectToChildWithRetry(socketPath string, spec port.Spec, retries int) (int, error) { - for i := 0; i < retries; i++ { - fd, err := connectToChild(socketPath, spec) - if i == retries-1 && err != nil { - return 0, err - } - if err == nil { - return fd, err - } - // TODO: backoff - time.Sleep(time.Duration(i*5) * time.Millisecond) - } - // NOT REACHED - return 0, errors.New("reached max retry") -} - -func parseFDFromOOB(oob []byte) (int, error) { - scms, err := unix.ParseSocketControlMessage(oob) - if err != nil { - return 0, err - } - if len(scms) != 1 { - return 0, errors.Errorf("unexpected scms: %v", scms) - } - scm := scms[0] - fds, err := unix.ParseUnixRights(&scm) - if err != nil { - return 0, err - } - if len(fds) != 1 { - return 0, errors.Errorf("unexpected fds: %v", fds) - } - return fds[0], nil -} - -func startTCPRoutines(socketPath string, spec port.Spec, stopCh <-chan struct{}, logWriter io.Writer) error { - ln, err := net.Listen("tcp", fmt.Sprintf("%s:%d", spec.ParentIP, spec.ParentPort)) - if err != nil { - fmt.Fprintf(logWriter, "listen: %v\n", err) - return err - } - newConns := make(chan net.Conn) - go func() { - for { - c, err := ln.Accept() - if err != nil { - fmt.Fprintf(logWriter, "accept: %v\n", err) - close(newConns) - return - } - newConns <- c - } - }() - go func() { - defer ln.Close() - for { - select { - case c, ok := <-newConns: - if !ok { - return - } - go func() { - if err := copyConnToChild(c, socketPath, spec, stopCh); err != nil { - fmt.Fprintf(logWriter, "copyConnToChild: %v\n", err) - return - } - }() - case <-stopCh: - return - } - } - }() - // no wait - return nil -} - -func startUDPRoutines(socketPath string, spec port.Spec, stopCh <-chan struct{}, logWriter io.Writer) error { - addr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", spec.ParentIP, spec.ParentPort)) - if err != nil { - return err - } - c, err := net.ListenUDP("udp", addr) - if err != nil { - return err - } - go func() { - if err := copyConnToChild(c, socketPath, spec, stopCh); err != nil { - fmt.Fprintf(logWriter, "copyConnToChild: %v\n", err) - return - } - }() - // no wait - return nil -} - -func copyConnToChild(c net.Conn, socketPath string, spec port.Spec, stopCh <-chan struct{}) error { - defer c.Close() - // get fd from the child as an SCM_RIGHTS cmsg - fd, err := connectToChildWithRetry(socketPath, spec, 10) - if err != nil { - return err - } - f := os.NewFile(uintptr(fd), "") - defer f.Close() - fc, err := net.FileConn(f) - if err != nil { - return err - } - defer fc.Close() - bicopy(c, fc, stopCh) - return nil -} - -// bicopy is based on libnetwork/cmd/proxy/tcp_proxy.go . -// NOTE: sendfile(2) cannot be used for sockets -func bicopy(x, y net.Conn, quit <-chan struct{}) { - var wg sync.WaitGroup - var broker = func(to, from net.Conn) { - io.Copy(to, from) - if fromTCP, ok := from.(*net.TCPConn); ok { - fromTCP.CloseRead() - } - if toTCP, ok := to.(*net.TCPConn); ok { - toTCP.CloseWrite() - } - wg.Done() - } - - wg.Add(2) - go broker(x, y) - go broker(y, x) - finish := make(chan struct{}) - go func() { - wg.Wait() - close(finish) - }() - - select { - case <-quit: - case <-finish: - } - x.Close() - y.Close() - <-finish -} - -const ( - requestTypeInit = "init" - requestTypeConnect = "connect" -) - -// request and response are encoded as JSON with uint32le length header. -type request struct { - Type string // "init" or "connect" - Proto string // "tcp" or "udp" - Port int -} - -// may contain FD as OOB -type reply struct { - Error string -} - -func NewChildDriver(logWriter io.Writer) port.ChildDriver { - return &childDriver{ - logWriter: logWriter, - } -} - -type childDriver struct { - logWriter io.Writer -} - -func (d *childDriver) RunChildDriver(opaque map[string]string, quit <-chan struct{}) error { - socketPath := opaque[opaqueKeySocketPath] - if socketPath == "" { - return errors.New("socket path not set") - } - childReadyPipePath := opaque[opaqueKeyChildReadyPipePath] - if childReadyPipePath == "" { - return errors.New("child ready pipe path not set") - } - childReadyPipeW, err := os.OpenFile(childReadyPipePath, os.O_WRONLY, os.ModeNamedPipe) - if err != nil { - return err - } - ln, err := net.ListenUnix("unix", &net.UnixAddr{ - Name: socketPath, - Net: "unix", - }) - if err != nil { - return err - } - // write nothing, just close - if err = childReadyPipeW.Close(); err != nil { - return err - } - stopAccept := make(chan struct{}, 1) - go func() { - <-quit - stopAccept <- struct{}{} - ln.Close() - }() - for { - c, err := ln.AcceptUnix() - if err != nil { - select { - case <-stopAccept: - return nil - default: - } - return err - } - go func() { - if rerr := d.routine(c); rerr != nil { - rep := reply{ - Error: rerr.Error(), - } - msgutil.MarshalToWriter(c, &rep) - } - c.Close() - }() - } - return nil -} - -func (d *childDriver) routine(c *net.UnixConn) error { - var req request - if _, err := msgutil.UnmarshalFromReader(c, &req); err != nil { - return err - } - switch req.Type { - case requestTypeInit: - return d.handleConnectInit(c, &req) - case requestTypeConnect: - return d.handleConnectRequest(c, &req) - default: - return errors.Errorf("unknown request type %q", req.Type) - } -} - -func (d *childDriver) handleConnectInit(c *net.UnixConn, req *request) error { - _, err := msgutil.MarshalToWriter(c, nil) - return err -} - -func (d *childDriver) handleConnectRequest(c *net.UnixConn, req *request) error { - switch req.Proto { - case "tcp": - case "udp": - default: - return errors.Errorf("unknown proto: %q", req.Proto) - } - var dialer net.Dialer - targetConn, err := dialer.Dial(req.Proto, fmt.Sprintf("127.0.0.1:%d", req.Port)) - if err != nil { - return err - } - defer targetConn.Close() // no effect on duplicated FD - targetConnFiler, ok := targetConn.(filer) - if !ok { - return errors.Errorf("unknown target connection: %+v", targetConn) - } - targetConnFile, err := targetConnFiler.File() - if err != nil { - return err - } - oob := unix.UnixRights(int(targetConnFile.Fd())) - f, err := c.File() - if err != nil { - return err - } - err = unix.Sendmsg(int(f.Fd()), []byte("dummy"), oob, nil, 0) - return err -} - -// filer is implemented by *net.TCPConn and *net.UDPConn -type filer interface { - File() (f *os.File, err error) -} diff --git a/vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/child/child.go b/vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/child/child.go new file mode 100644 index 0000000000..5477dda518 --- /dev/null +++ b/vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/child/child.go @@ -0,0 +1,134 @@ +package child + +import ( + "fmt" + "io" + "net" + "os" + + "github.com/pkg/errors" + "golang.org/x/sys/unix" + + "github.com/rootless-containers/rootlesskit/pkg/msgutil" + "github.com/rootless-containers/rootlesskit/pkg/port" + "github.com/rootless-containers/rootlesskit/pkg/port/builtin/msg" + opaquepkg "github.com/rootless-containers/rootlesskit/pkg/port/builtin/opaque" +) + +func NewDriver(logWriter io.Writer) port.ChildDriver { + return &childDriver{ + logWriter: logWriter, + } +} + +type childDriver struct { + logWriter io.Writer +} + +func (d *childDriver) RunChildDriver(opaque map[string]string, quit <-chan struct{}) error { + socketPath := opaque[opaquepkg.SocketPath] + if socketPath == "" { + return errors.New("socket path not set") + } + childReadyPipePath := opaque[opaquepkg.ChildReadyPipePath] + if childReadyPipePath == "" { + return errors.New("child ready pipe path not set") + } + childReadyPipeW, err := os.OpenFile(childReadyPipePath, os.O_WRONLY, os.ModeNamedPipe) + if err != nil { + return err + } + ln, err := net.ListenUnix("unix", &net.UnixAddr{ + Name: socketPath, + Net: "unix", + }) + if err != nil { + return err + } + // write nothing, just close + if err = childReadyPipeW.Close(); err != nil { + return err + } + stopAccept := make(chan struct{}, 1) + go func() { + <-quit + stopAccept <- struct{}{} + ln.Close() + }() + for { + c, err := ln.AcceptUnix() + if err != nil { + select { + case <-stopAccept: + return nil + default: + } + return err + } + go func() { + if rerr := d.routine(c); rerr != nil { + rep := msg.Reply{ + Error: rerr.Error(), + } + msgutil.MarshalToWriter(c, &rep) + } + c.Close() + }() + } + return nil +} + +func (d *childDriver) routine(c *net.UnixConn) error { + var req msg.Request + if _, err := msgutil.UnmarshalFromReader(c, &req); err != nil { + return err + } + switch req.Type { + case msg.RequestTypeInit: + return d.handleConnectInit(c, &req) + case msg.RequestTypeConnect: + return d.handleConnectRequest(c, &req) + default: + return errors.Errorf("unknown request type %q", req.Type) + } +} + +func (d *childDriver) handleConnectInit(c *net.UnixConn, req *msg.Request) error { + _, err := msgutil.MarshalToWriter(c, nil) + return err +} + +func (d *childDriver) handleConnectRequest(c *net.UnixConn, req *msg.Request) error { + switch req.Proto { + case "tcp": + case "udp": + default: + return errors.Errorf("unknown proto: %q", req.Proto) + } + var dialer net.Dialer + targetConn, err := dialer.Dial(req.Proto, fmt.Sprintf("127.0.0.1:%d", req.Port)) + if err != nil { + return err + } + defer targetConn.Close() // no effect on duplicated FD + targetConnFiler, ok := targetConn.(filer) + if !ok { + return errors.Errorf("unknown target connection: %+v", targetConn) + } + targetConnFile, err := targetConnFiler.File() + if err != nil { + return err + } + oob := unix.UnixRights(int(targetConnFile.Fd())) + f, err := c.File() + if err != nil { + return err + } + err = unix.Sendmsg(int(f.Fd()), []byte("dummy"), oob, nil, 0) + return err +} + +// filer is implemented by *net.TCPConn and *net.UDPConn +type filer interface { + File() (f *os.File, err error) +} diff --git a/vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/msg/msg.go b/vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/msg/msg.go new file mode 100644 index 0000000000..c603f473aa --- /dev/null +++ b/vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/msg/msg.go @@ -0,0 +1,129 @@ +package msg + +import ( + "net" + "time" + + "github.com/pkg/errors" + "golang.org/x/sys/unix" + + "github.com/rootless-containers/rootlesskit/pkg/msgutil" + "github.com/rootless-containers/rootlesskit/pkg/port" +) + +const ( + RequestTypeInit = "init" + RequestTypeConnect = "connect" +) + +// Request and Response are encoded as JSON with uint32le length header. +type Request struct { + Type string // "init" or "connect" + Proto string // "tcp" or "udp" + Port int +} + +// Reply may contain FD as OOB +type Reply struct { + Error string +} + +// Initiate sends "init" request to the child UNIX socket. +func Initiate(c *net.UnixConn) error { + req := Request{ + Type: RequestTypeInit, + } + if _, err := msgutil.MarshalToWriter(c, &req); err != nil { + return err + } + if err := c.CloseWrite(); err != nil { + return err + } + var rep Reply + if _, err := msgutil.UnmarshalFromReader(c, &rep); err != nil { + return err + } + return c.CloseRead() +} + +// ConnectToChild connects to the child UNIX socket, and obtains TCP or UDP socket FD +// that corresponds to the port spec. +func ConnectToChild(c *net.UnixConn, spec port.Spec) (int, error) { + req := Request{ + Type: RequestTypeConnect, + Proto: spec.Proto, + Port: spec.ChildPort, + } + if _, err := msgutil.MarshalToWriter(c, &req); err != nil { + return 0, err + } + if err := c.CloseWrite(); err != nil { + return 0, err + } + oobSpace := unix.CmsgSpace(4) + oob := make([]byte, oobSpace) + _, oobN, _, _, err := c.ReadMsgUnix(nil, oob) + if err != nil { + return 0, err + } + if oobN != oobSpace { + return 0, errors.Errorf("expected OOB space %d, got %d", oobSpace, oobN) + } + oob = oob[:oobN] + fd, err := parseFDFromOOB(oob) + if err != nil { + return 0, err + } + if err := c.CloseRead(); err != nil { + return 0, err + } + return fd, nil +} + +// ConnectToChildWithSocketPath wraps ConnectToChild +func ConnectToChildWithSocketPath(socketPath string, spec port.Spec) (int, error) { + var dialer net.Dialer + conn, err := dialer.Dial("unix", socketPath) + if err != nil { + return 0, err + } + defer conn.Close() + c := conn.(*net.UnixConn) + return ConnectToChild(c, spec) +} + +// ConnectToChildWithRetry retries ConnectToChild every (i*5) milliseconds. +func ConnectToChildWithRetry(socketPath string, spec port.Spec, retries int) (int, error) { + for i := 0; i < retries; i++ { + fd, err := ConnectToChildWithSocketPath(socketPath, spec) + if i == retries-1 && err != nil { + return 0, err + } + if err == nil { + return fd, err + } + // TODO: backoff + time.Sleep(time.Duration(i*5) * time.Millisecond) + } + // NOT REACHED + return 0, errors.New("reached max retry") +} + +func parseFDFromOOB(oob []byte) (int, error) { + scms, err := unix.ParseSocketControlMessage(oob) + if err != nil { + return 0, err + } + if len(scms) != 1 { + return 0, errors.Errorf("unexpected scms: %v", scms) + } + scm := scms[0] + fds, err := unix.ParseUnixRights(&scm) + if err != nil { + return 0, err + } + if len(fds) != 1 { + return 0, errors.Errorf("unexpected fds: %v", fds) + } + return fds[0], nil +} diff --git a/vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/opaque/opaque.go b/vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/opaque/opaque.go new file mode 100644 index 0000000000..391b3d3404 --- /dev/null +++ b/vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/opaque/opaque.go @@ -0,0 +1,6 @@ +package opaque + +const ( + SocketPath = "builtin.socketpath" + ChildReadyPipePath = "builtin.readypipepath" +) diff --git a/vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/parent.go b/vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/parent.go new file mode 100644 index 0000000000..893bf1da90 --- /dev/null +++ b/vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/parent.go @@ -0,0 +1,145 @@ +package parent + +import ( + "context" + "io" + "io/ioutil" + "net" + "os" + "path/filepath" + "sync" + "syscall" + + "github.com/pkg/errors" + + "github.com/rootless-containers/rootlesskit/pkg/port" + "github.com/rootless-containers/rootlesskit/pkg/port/builtin/msg" + "github.com/rootless-containers/rootlesskit/pkg/port/builtin/opaque" + "github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/tcp" + "github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/udp" + "github.com/rootless-containers/rootlesskit/pkg/port/portutil" +) + +// NewDriver for builtin driver. +func NewDriver(logWriter io.Writer, stateDir string) (port.ParentDriver, error) { + // TODO: consider using socketpair FD instead of socket file + socketPath := filepath.Join(stateDir, ".bp.sock") + childReadyPipePath := filepath.Join(stateDir, ".bp-ready.pipe") + // remove the path just in case the previous rootlesskit instance crashed + if err := os.RemoveAll(childReadyPipePath); err != nil { + return nil, errors.Wrapf(err, "cannot remove %s", childReadyPipePath) + } + if err := syscall.Mkfifo(childReadyPipePath, 0600); err != nil { + return nil, errors.Wrapf(err, "cannot mkfifo %s", childReadyPipePath) + } + d := driver{ + logWriter: logWriter, + socketPath: socketPath, + childReadyPipePath: childReadyPipePath, + ports: make(map[int]*port.Status, 0), + stoppers: make(map[int]func() error, 0), + nextID: 1, + } + return &d, nil +} + +type driver struct { + logWriter io.Writer + socketPath string + childReadyPipePath string + mu sync.Mutex + ports map[int]*port.Status + stoppers map[int]func() error + nextID int +} + +func (d *driver) OpaqueForChild() map[string]string { + return map[string]string{ + opaque.SocketPath: d.socketPath, + opaque.ChildReadyPipePath: d.childReadyPipePath, + } +} + +func (d *driver) RunParentDriver(initComplete chan struct{}, quit <-chan struct{}, _ *port.ChildContext) error { + childReadyPipeR, err := os.OpenFile(d.childReadyPipePath, os.O_RDONLY, os.ModeNamedPipe) + if err != nil { + return err + } + if _, err = ioutil.ReadAll(childReadyPipeR); err != nil { + return err + } + childReadyPipeR.Close() + var dialer net.Dialer + conn, err := dialer.Dial("unix", d.socketPath) + if err != nil { + return err + } + err = msg.Initiate(conn.(*net.UnixConn)) + conn.Close() + if err != nil { + return err + } + initComplete <- struct{}{} + <-quit + return nil +} + +func (d *driver) AddPort(ctx context.Context, spec port.Spec) (*port.Status, error) { + d.mu.Lock() + err := portutil.ValidatePortSpec(spec, d.ports) + d.mu.Unlock() + if err != nil { + return nil, err + } + routineStopCh := make(chan struct{}) + routineStop := func() error { + close(routineStopCh) + return nil // FIXME + } + switch spec.Proto { + case "tcp": + err = tcp.Run(d.socketPath, spec, routineStopCh, d.logWriter) + case "udp": + err = udp.Run(d.socketPath, spec, routineStopCh, d.logWriter) + default: + // NOTREACHED + return nil, errors.New("spec was not validated?") + } + if err != nil { + return nil, err + } + d.mu.Lock() + id := d.nextID + st := port.Status{ + ID: id, + Spec: spec, + } + d.ports[id] = &st + d.stoppers[id] = routineStop + d.nextID++ + d.mu.Unlock() + return &st, nil +} + +func (d *driver) ListPorts(ctx context.Context) ([]port.Status, error) { + var ports []port.Status + d.mu.Lock() + for _, p := range d.ports { + ports = append(ports, *p) + } + d.mu.Unlock() + return ports, nil +} + +func (d *driver) RemovePort(ctx context.Context, id int) error { + d.mu.Lock() + defer d.mu.Unlock() + stop, ok := d.stoppers[id] + if !ok { + return errors.Errorf("unknown id: %d", id) + } + err := stop() + delete(d.stoppers, id) + delete(d.ports, id) + return err +} diff --git a/vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/tcp/tcp.go b/vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/tcp/tcp.go new file mode 100644 index 0000000000..b9f2d18022 --- /dev/null +++ b/vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/tcp/tcp.go @@ -0,0 +1,104 @@ +package tcp + +import ( + "fmt" + "io" + "net" + "os" + "sync" + + "github.com/rootless-containers/rootlesskit/pkg/port" + "github.com/rootless-containers/rootlesskit/pkg/port/builtin/msg" +) + +func Run(socketPath string, spec port.Spec, stopCh <-chan struct{}, logWriter io.Writer) error { + ln, err := net.Listen("tcp", fmt.Sprintf("%s:%d", spec.ParentIP, spec.ParentPort)) + if err != nil { + fmt.Fprintf(logWriter, "listen: %v\n", err) + return err + } + newConns := make(chan net.Conn) + go func() { + for { + c, err := ln.Accept() + if err != nil { + fmt.Fprintf(logWriter, "accept: %v\n", err) + close(newConns) + return + } + newConns <- c + } + }() + go func() { + defer ln.Close() + for { + select { + case c, ok := <-newConns: + if !ok { + return + } + go func() { + if err := copyConnToChild(c, socketPath, spec, stopCh); err != nil { + fmt.Fprintf(logWriter, "copyConnToChild: %v\n", err) + return + } + }() + case <-stopCh: + return + } + } + }() + // no wait + return nil +} + +func copyConnToChild(c net.Conn, socketPath string, spec port.Spec, stopCh <-chan struct{}) error { + defer c.Close() + // get fd from the child as an SCM_RIGHTS cmsg + fd, err := msg.ConnectToChildWithRetry(socketPath, spec, 10) + if err != nil { + return err + } + f := os.NewFile(uintptr(fd), "") + defer f.Close() + fc, err := net.FileConn(f) + if err != nil { + return err + } + defer fc.Close() + bicopy(c, fc, stopCh) + return nil +} + +// bicopy is based on libnetwork/cmd/proxy/tcp_proxy.go . +// NOTE: sendfile(2) cannot be used for sockets +func bicopy(x, y net.Conn, quit <-chan struct{}) { + var wg sync.WaitGroup + var broker = func(to, from net.Conn) { + io.Copy(to, from) + if fromTCP, ok := from.(*net.TCPConn); ok { + fromTCP.CloseRead() + } + if toTCP, ok := to.(*net.TCPConn); ok { + toTCP.CloseWrite() + } + wg.Done() + } + + wg.Add(2) + go broker(x, y) + go broker(y, x) + finish := make(chan struct{}) + go func() { + wg.Wait() + close(finish) + }() + + select { + case <-quit: + case <-finish: + } + x.Close() + y.Close() + <-finish +} diff --git a/vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/udp/udp.go b/vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/udp/udp.go new file mode 100644 index 0000000000..d8f646b5dc --- /dev/null +++ b/vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/udp/udp.go @@ -0,0 +1,60 @@ +package udp + +import ( + "fmt" + "io" + "net" + "os" + + "github.com/pkg/errors" + + "github.com/rootless-containers/rootlesskit/pkg/port" + "github.com/rootless-containers/rootlesskit/pkg/port/builtin/msg" + "github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/udp/udpproxy" +) + +func Run(socketPath string, spec port.Spec, stopCh <-chan struct{}, logWriter io.Writer) error { + addr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", spec.ParentIP, spec.ParentPort)) + if err != nil { + return err + } + c, err := net.ListenUDP("udp", addr) + if err != nil { + return err + } + udpp := &udpproxy.UDPProxy{ + LogWriter: logWriter, + Listener: c, + BackendDial: func() (*net.UDPConn, error) { + // get fd from the child as an SCM_RIGHTS cmsg + fd, err := msg.ConnectToChildWithRetry(socketPath, spec, 10) + if err != nil { + return nil, err + } + f := os.NewFile(uintptr(fd), "") + defer f.Close() + fc, err := net.FileConn(f) + if err != nil { + return nil, err + } + uc, ok := fc.(*net.UDPConn) + if !ok { + return nil, errors.Errorf("file conn doesn't implement *net.UDPConn: %+v", fc) + } + return uc, nil + }, + } + go udpp.Run() + go func() { + for { + select { + case <-stopCh: + // udpp.Close closes ln as well + udpp.Close() + return + } + } + }() + // no wait + return nil +} diff --git a/vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/udp/udpproxy/udp_proxy.go b/vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/udp/udpproxy/udp_proxy.go new file mode 100644 index 0000000000..af7b7d5d97 --- /dev/null +++ b/vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/udp/udpproxy/udp_proxy.go @@ -0,0 +1,150 @@ +// Package udpproxy is from https://raw.githubusercontent.com/docker/libnetwork/fec6476dfa21380bf8ee4d74048515d968c1ee63/cmd/proxy/udp_proxy.go +package udpproxy + +import ( + "encoding/binary" + "fmt" + "io" + "net" + "strings" + "sync" + "syscall" + "time" +) + +const ( + // UDPConnTrackTimeout is the timeout used for UDP connection tracking + UDPConnTrackTimeout = 90 * time.Second + // UDPBufSize is the buffer size for the UDP proxy + UDPBufSize = 65507 +) + +// A net.Addr where the IP is split into two fields so you can use it as a key +// in a map: +type connTrackKey struct { + IPHigh uint64 + IPLow uint64 + Port int +} + +func newConnTrackKey(addr *net.UDPAddr) *connTrackKey { + if len(addr.IP) == net.IPv4len { + return &connTrackKey{ + IPHigh: 0, + IPLow: uint64(binary.BigEndian.Uint32(addr.IP)), + Port: addr.Port, + } + } + return &connTrackKey{ + IPHigh: binary.BigEndian.Uint64(addr.IP[:8]), + IPLow: binary.BigEndian.Uint64(addr.IP[8:]), + Port: addr.Port, + } +} + +type connTrackMap map[connTrackKey]*net.UDPConn + +// UDPProxy is proxy for which handles UDP datagrams. +// From libnetwork udp_proxy.go . +type UDPProxy struct { + LogWriter io.Writer + Listener *net.UDPConn + BackendDial func() (*net.UDPConn, error) + connTrackTable connTrackMap + connTrackLock sync.Mutex +} + +func (proxy *UDPProxy) replyLoop(proxyConn *net.UDPConn, clientAddr *net.UDPAddr, clientKey *connTrackKey) { + defer func() { + proxy.connTrackLock.Lock() + delete(proxy.connTrackTable, *clientKey) + proxy.connTrackLock.Unlock() + proxyConn.Close() + }() + + readBuf := make([]byte, UDPBufSize) + for { + proxyConn.SetReadDeadline(time.Now().Add(UDPConnTrackTimeout)) + again: + read, err := proxyConn.Read(readBuf) + if err != nil { + if err, ok := err.(*net.OpError); ok && err.Err == syscall.ECONNREFUSED { + // This will happen if the last write failed + // (e.g: nothing is actually listening on the + // proxied port on the container), ignore it + // and continue until UDPConnTrackTimeout + // expires: + goto again + } + return + } + for i := 0; i != read; { + written, err := proxy.Listener.WriteToUDP(readBuf[i:read], clientAddr) + if err != nil { + return + } + i += written + } + } +} + +// Run starts forwarding the traffic using UDP. +func (proxy *UDPProxy) Run() { + proxy.connTrackTable = make(connTrackMap) + readBuf := make([]byte, UDPBufSize) + for { + read, from, err := proxy.Listener.ReadFromUDP(readBuf) + if err != nil { + // NOTE: Apparently ReadFrom doesn't return + // ECONNREFUSED like Read do (see comment in + // UDPProxy.replyLoop) + if !isClosedError(err) { + fmt.Fprintf(proxy.LogWriter, "Stopping proxy on udp: %v\n", err) + } + break + } + + fromKey := newConnTrackKey(from) + proxy.connTrackLock.Lock() + proxyConn, hit := proxy.connTrackTable[*fromKey] + if !hit { + proxyConn, err = proxy.BackendDial() + if err != nil { + fmt.Fprintf(proxy.LogWriter, "Can't proxy a datagram to udp: %v\n", err) + proxy.connTrackLock.Unlock() + continue + } + proxy.connTrackTable[*fromKey] = proxyConn + go proxy.replyLoop(proxyConn, from, fromKey) + } + proxy.connTrackLock.Unlock() + for i := 0; i != read; { + written, err := proxyConn.Write(readBuf[i:read]) + if err != nil { + fmt.Fprintf(proxy.LogWriter, "Can't proxy a datagram to udp: %v\n", err) + break + } + i += written + } + } +} + +// Close stops forwarding the traffic. +func (proxy *UDPProxy) Close() { + proxy.Listener.Close() + proxy.connTrackLock.Lock() + defer proxy.connTrackLock.Unlock() + for _, conn := range proxy.connTrackTable { + conn.Close() + } +} + +func isClosedError(err error) bool { + /* This comparison is ugly, but unfortunately, net.go doesn't export errClosing. + * See: + * http://golang.org/src/pkg/net/net.go + * https://code.google.com/p/go/issues/detail?id=4337 + * https://groups.google.com/forum/#!msg/golang-nuts/0_aaCvBmOcM/SptmDyX1XJMJ + */ + return strings.HasSuffix(err.Error(), "use of closed network connection") +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 4d3e52c86a..f6abc9e8be 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -383,7 +383,6 @@ github.com/docker/docker/api/types/volume github.com/docker/docker/client github.com/docker/docker/daemon/logger/jsonfilelog/jsonlog github.com/docker/docker/errdefs -github.com/docker/docker/pkg/idtools github.com/docker/docker/pkg/jsonmessage github.com/docker/docker/pkg/longpath github.com/docker/docker/pkg/mount @@ -774,7 +773,7 @@ github.com/rancher/wrangler-api/pkg/generated/controllers/rbac github.com/rancher/wrangler-api/pkg/generated/controllers/rbac/v1 # github.com/robfig/cron v1.1.0 github.com/robfig/cron -# github.com/rootless-containers/rootlesskit v0.6.0 +# github.com/rootless-containers/rootlesskit v0.7.2 github.com/rootless-containers/rootlesskit/pkg/api/client github.com/rootless-containers/rootlesskit/pkg/api/router github.com/rootless-containers/rootlesskit/pkg/child @@ -787,8 +786,16 @@ github.com/rootless-containers/rootlesskit/pkg/network/iputils github.com/rootless-containers/rootlesskit/pkg/network/parentutils github.com/rootless-containers/rootlesskit/pkg/network/slirp4netns github.com/rootless-containers/rootlesskit/pkg/parent +github.com/rootless-containers/rootlesskit/pkg/parent/idtools github.com/rootless-containers/rootlesskit/pkg/port github.com/rootless-containers/rootlesskit/pkg/port/builtin +github.com/rootless-containers/rootlesskit/pkg/port/builtin/child +github.com/rootless-containers/rootlesskit/pkg/port/builtin/msg +github.com/rootless-containers/rootlesskit/pkg/port/builtin/opaque +github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent +github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/tcp +github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/udp +github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/udp/udpproxy github.com/rootless-containers/rootlesskit/pkg/port/portutil # github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c github.com/rubiojr/go-vhd/vhd