Merge pull request #1449 from weaveworks/1368-start-hostconfig
Override sneaky /start HostConfig params Fixes #1368.
This commit is contained in:
commit
7d7c5ce63e
6 files changed
+130
-83
No files matched your search
@@ -2,16 +2,11 @@ package proxy
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/fsouza/go-dockerclient"
|
||||
|
||||
. "github.com/weaveworks/weave/common"
|
||||
"github.com/weaveworks/weave/nameserver"
|
||||
"github.com/weaveworks/weave/router"
|
||||
)
|
||||
|
||||
const MaxDockerHostname = 64
|
||||
@@ -55,7 +50,7 @@ func (i *createContainerInterceptor) InterceptRequest(r *http.Request) error {
|
||||
if container.Config == nil {
|
||||
container.Config = &docker.Config{}
|
||||
}
|
||||
i.addWeaveWaitVolume(container.HostConfig)
|
||||
i.proxy.addWeaveWaitVolume(container.HostConfig)
|
||||
if err := i.setWeaveWaitEntrypoint(container.Config); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -66,8 +61,11 @@ func (i *createContainerInterceptor) InterceptRequest(r *http.Request) error {
|
||||
}
|
||||
}
|
||||
hostname = i.proxy.hostnameMatchRegexp.ReplaceAllString(hostname, i.proxy.HostnameReplacement)
|
||||
if err := i.setWeaveDNS(&container, hostname); err != nil {
|
||||
return err
|
||||
if dnsDomain := i.proxy.getDNSDomain(); dnsDomain != "" {
|
||||
i.setHostname(&container, hostname, dnsDomain)
|
||||
if err := i.proxy.setWeaveDNS(container.HostConfig, container.Hostname, dnsDomain); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return marshalRequestBody(r, container)
|
||||
@@ -76,18 +74,6 @@ func (i *createContainerInterceptor) InterceptRequest(r *http.Request) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *createContainerInterceptor) addWeaveWaitVolume(hostConfig *docker.HostConfig) {
|
||||
var binds []string
|
||||
for _, bind := range hostConfig.Binds {
|
||||
s := strings.Split(bind, ":")
|
||||
if len(s) >= 2 && s[1] == "/w" {
|
||||
continue
|
||||
}
|
||||
binds = append(binds, bind)
|
||||
}
|
||||
hostConfig.Binds = append(binds, fmt.Sprintf("%s:/w:ro", i.proxy.weaveWaitVolume))
|
||||
}
|
||||
|
||||
func (i *createContainerInterceptor) setWeaveWaitEntrypoint(container *docker.Config) error {
|
||||
if len(container.Entrypoint) == 0 {
|
||||
image, err := i.proxy.client.InspectImage(container.Image)
|
||||
@@ -117,18 +103,7 @@ func (i *createContainerInterceptor) setWeaveWaitEntrypoint(container *docker.Co
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *createContainerInterceptor) setWeaveDNS(container *createContainerRequestBody, name string) error {
|
||||
if i.proxy.WithoutDNS {
|
||||
return nil
|
||||
}
|
||||
|
||||
dnsDomain, dnsRunning := i.getDNSDomain()
|
||||
if !(dnsRunning || i.proxy.WithDNS) {
|
||||
return nil
|
||||
}
|
||||
|
||||
container.HostConfig.DNS = append(container.HostConfig.DNS, i.proxy.dockerBridgeIP)
|
||||
|
||||
func (i *createContainerInterceptor) setHostname(container *createContainerRequestBody, name, dnsDomain string) {
|
||||
if container.Hostname == "" && name != "" {
|
||||
// Strip trailing period because it's unusual to see it used on the end of a host name
|
||||
trimmedDNSDomain := strings.TrimSuffix(dnsDomain, ".")
|
||||
@@ -140,39 +115,7 @@ func (i *createContainerInterceptor) setWeaveDNS(container *createContainerReque
|
||||
}
|
||||
}
|
||||
|
||||
if len(container.HostConfig.DNSSearch) == 0 {
|
||||
if container.Hostname == "" {
|
||||
container.HostConfig.DNSSearch = []string{dnsDomain}
|
||||
} else {
|
||||
container.HostConfig.DNSSearch = []string{"."}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *createContainerInterceptor) getDNSDomain() (domain string, running bool) {
|
||||
domain = nameserver.DefaultDomain
|
||||
weaveContainer, err := i.proxy.client.InspectContainer("weave")
|
||||
if err != nil ||
|
||||
weaveContainer.NetworkSettings == nil ||
|
||||
weaveContainer.NetworkSettings.IPAddress == "" {
|
||||
return
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("http://%s:%d/domain", weaveContainer.NetworkSettings.IPAddress, router.HTTPPort)
|
||||
resp, err := http.Get(url)
|
||||
if err != nil || resp.StatusCode != http.StatusOK {
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
b, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return string(b), true
|
||||
return
|
||||
}
|
||||
|
||||
func (i *createContainerInterceptor) InterceptResponse(r *http.Response) error {
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -15,6 +16,8 @@ import (
|
||||
docker "github.com/fsouza/go-dockerclient"
|
||||
. "github.com/weaveworks/weave/common"
|
||||
weavedocker "github.com/weaveworks/weave/common/docker"
|
||||
"github.com/weaveworks/weave/nameserver"
|
||||
"github.com/weaveworks/weave/router"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -365,3 +368,60 @@ func (proxy *Proxy) weaveCIDRsFromConfig(config *docker.Config, hostConfig *dock
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (proxy *Proxy) addWeaveWaitVolume(hostConfig *docker.HostConfig) {
|
||||
var binds []string
|
||||
for _, bind := range hostConfig.Binds {
|
||||
s := strings.Split(bind, ":")
|
||||
if len(s) >= 2 && s[1] == "/w" {
|
||||
continue
|
||||
}
|
||||
binds = append(binds, bind)
|
||||
}
|
||||
hostConfig.Binds = append(binds, fmt.Sprintf("%s:/w:ro", proxy.weaveWaitVolume))
|
||||
}
|
||||
|
||||
func (proxy *Proxy) setWeaveDNS(hostConfig *docker.HostConfig, hostname, dnsDomain string) error {
|
||||
hostConfig.DNS = append(hostConfig.DNS, proxy.dockerBridgeIP)
|
||||
|
||||
if len(hostConfig.DNSSearch) == 0 {
|
||||
if hostname == "" {
|
||||
hostConfig.DNSSearch = []string{dnsDomain}
|
||||
} else {
|
||||
hostConfig.DNSSearch = []string{"."}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (proxy *Proxy) getDNSDomain() (domain string) {
|
||||
if proxy.WithoutDNS {
|
||||
return ""
|
||||
}
|
||||
|
||||
if proxy.WithDNS {
|
||||
domain = nameserver.DefaultDomain
|
||||
}
|
||||
|
||||
weaveContainer, err := proxy.client.InspectContainer("weave")
|
||||
if err != nil ||
|
||||
weaveContainer.NetworkSettings == nil ||
|
||||
weaveContainer.NetworkSettings.IPAddress == "" {
|
||||
return
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("http://%s:%d/domain", weaveContainer.NetworkSettings.IPAddress, router.HTTPPort)
|
||||
resp, err := http.Get(url)
|
||||
if err != nil || resp.StatusCode != http.StatusOK {
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
b, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return string(b)
|
||||
}
|
||||
@@ -2,16 +2,44 @@ package proxy
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/fsouza/go-dockerclient"
|
||||
)
|
||||
|
||||
type startContainerInterceptor struct{ proxy *Proxy }
|
||||
|
||||
type startContainerRequestBody struct {
|
||||
HostConfig *docker.HostConfig `json:"HostConfig,omitempty" yaml:"HostConfig,omitempty"`
|
||||
}
|
||||
|
||||
func (i *startContainerInterceptor) InterceptRequest(r *http.Request) error {
|
||||
container, err := inspectContainerInPath(i.proxy.client, r.URL.Path)
|
||||
if err == nil && containerShouldAttach(container) {
|
||||
i.proxy.createWait(r, container.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return err
|
||||
|
||||
if !containerShouldAttach(container) || r.Header.Get("Content-Type") != "application/json" {
|
||||
i.proxy.createWait(r, container.ID)
|
||||
return nil
|
||||
}
|
||||
|
||||
hostConfig := &docker.HostConfig{}
|
||||
if err := unmarshalRequestBody(r, &hostConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
i.proxy.addWeaveWaitVolume(hostConfig)
|
||||
if dnsDomain := i.proxy.getDNSDomain(); dnsDomain != "" {
|
||||
if err := i.proxy.setWeaveDNS(hostConfig, container.Config.Hostname, dnsDomain); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := marshalRequestBody(r, hostConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
i.proxy.createWait(r, container.ID)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *startContainerInterceptor) InterceptResponse(r *http.Response) error {
|
||||
|
||||
Executable
+21
@@ -0,0 +1,21 @@
|
||||
#! /bin/bash
|
||||
|
||||
. ./config.sh
|
||||
|
||||
start_suite "Abuse of 'start' operation"
|
||||
|
||||
weave_on $HOST1 launch
|
||||
docker_bridge_ip=$(weave_on $HOST1 docker-bridge-ip)
|
||||
proxy_start_container $HOST1 --name=c1
|
||||
|
||||
# Start c2 with a sneaky HostConfig
|
||||
proxy docker_on $HOST1 create --name=c2 $SMALL_IMAGE $CHECK_ETHWE_UP
|
||||
proxy docker_api_on $HOST1 POST /containers/c2/start '{"NetworkMode": "container:c1"}'
|
||||
assert "docker_on $HOST1 inspect -f '{{.State.Running}} {{.State.ExitCode}} {{.HostConfig.Dns}}' c2" "false 0 [$docker_bridge_ip]"
|
||||
|
||||
# Start c3 with HostConfig having empty binds and null dns/networking settings
|
||||
proxy docker_on $HOST1 create --name=c3 -v /tmp:/hosttmp $SMALL_IMAGE $CHECK_ETHWE_UP
|
||||
proxy docker_api_on $HOST1 POST /containers/c3/start '{"Binds":[],"Dns":null,"DnsSearch":null,"ExtraHosts":null,"VolumesFrom":null,"Devices":null,"NetworkMode":""}'
|
||||
assert "docker_on $HOST1 inspect -f '{{.State.Running}} {{.State.ExitCode}} {{.HostConfig.Dns}}' c3" "false 0 [$docker_bridge_ip]"
|
||||
|
||||
end_suite
|
||||
@@ -1,15 +0,0 @@
|
||||
#! /bin/bash
|
||||
|
||||
. ./config.sh
|
||||
|
||||
start_suite "Abuse of 'start' operation"
|
||||
|
||||
weave_on $HOST1 launch
|
||||
|
||||
proxy_start_container $HOST1 --name=c1
|
||||
proxy docker_on $HOST1 create --name=c2 $SMALL_IMAGE grep "^1$" /sys/class/net/ethwe/carrier
|
||||
# Now start c2 with a sneaky HostConfig
|
||||
curl -X POST -H Content-Type:application/json -d '{"HostConfig": {"NetworkMode": "container:c1"}}' http://$HOST1:12375/containers/c2/start
|
||||
assert "docker_on $HOST1 inspect -f '{{.State.Running}} {{.State.ExitCode}}' c2" "false 0"
|
||||
|
||||
end_suite
|
||||
@@ -99,6 +99,16 @@ docker_on() {
|
||||
docker -H tcp://$host:$DOCKER_PORT "$@"
|
||||
}
|
||||
|
||||
docker_api_on() {
|
||||
host=$1
|
||||
method=$2
|
||||
url=$3
|
||||
data=$4
|
||||
shift 4
|
||||
[ -z "$DEBUG" ] || greyly echo "Docker (API) on $host:$DOCKER_PORT: $method $url" >&2
|
||||
echo -n "$data" | curl -s -X "$method" -H Content-Type:application/json "http://$host:$DOCKER_PORT/v1.15$url" -d @-
|
||||
}
|
||||
|
||||
proxy() {
|
||||
DOCKER_PORT=12375 "$@"
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user