Merge pull request #4 from thaJeztah/18.06-backport-register-oci-mediatypes

[18.06] Register OCI image media types
diff --git a/api/server/backend/build/backend.go b/api/server/backend/build/backend.go
index 546ad5f..5e04e83 100644
--- a/api/server/backend/build/backend.go
+++ b/api/server/backend/build/backend.go
@@ -73,7 +73,7 @@
 			return "", err
 		}
 		if config.ProgressWriter.AuxFormatter != nil {
-			if err = config.ProgressWriter.AuxFormatter.Emit(types.BuildResult{ID: imageID}); err != nil {
+			if err = config.ProgressWriter.AuxFormatter.Emit("moby.image.id", types.BuildResult{ID: imageID}); err != nil {
 				return "", err
 			}
 		}
diff --git a/api/server/router/build/build_routes.go b/api/server/router/build/build_routes.go
index 071402a..c4699f3 100644
--- a/api/server/router/build/build_routes.go
+++ b/api/server/router/build/build_routes.go
@@ -14,7 +14,6 @@
 	"strings"
 	"sync"
 
-	"github.com/containerd/containerd/platforms"
 	"github.com/docker/docker/api/server/httputils"
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types/backend"
@@ -24,8 +23,7 @@
 	"github.com/docker/docker/pkg/ioutils"
 	"github.com/docker/docker/pkg/progress"
 	"github.com/docker/docker/pkg/streamformatter"
-	"github.com/docker/docker/pkg/system"
-	"github.com/docker/go-units"
+	units "github.com/docker/go-units"
 	"github.com/pkg/errors"
 	"github.com/sirupsen/logrus"
 )
@@ -72,17 +70,7 @@
 	options.Target = r.FormValue("target")
 	options.RemoteContext = r.FormValue("remote")
 	if versions.GreaterThanOrEqualTo(version, "1.32") {
-		apiPlatform := r.FormValue("platform")
-		if apiPlatform != "" {
-			sp, err := platforms.Parse(apiPlatform)
-			if err != nil {
-				return nil, err
-			}
-			if err := system.ValidatePlatform(sp); err != nil {
-				return nil, err
-			}
-			options.Platform = &sp
-		}
+		options.Platform = r.FormValue("platform")
 	}
 
 	if r.Form.Get("shmsize") != "" {
@@ -243,6 +231,10 @@
 		return errdefs.InvalidParameter(errors.New("squash is only supported with experimental mode"))
 	}
 
+	if buildOptions.Version == types.BuilderBuildKit && !br.daemon.HasExperimental() {
+		return errdefs.InvalidParameter(errors.New("buildkit is only supported with experimental mode"))
+	}
+
 	out := io.Writer(output)
 	if buildOptions.SuppressOutput {
 		out = notVerboseBuffer
@@ -255,10 +247,6 @@
 		return progress.NewProgressReader(in, progressOutput, r.ContentLength, "Downloading context", buildOptions.RemoteContext)
 	}
 
-	if buildOptions.Version == types.BuilderBuildKit && !br.daemon.HasExperimental() {
-		return errdefs.InvalidParameter(errors.New("buildkit is only supported with experimental mode"))
-	}
-
 	wantAux := versions.GreaterThanOrEqualTo(version, "1.30")
 
 	imgID, err := br.backend.Build(ctx, backend.BuildConfig{
diff --git a/api/types/client.go b/api/types/client.go
index 33bc98e..3b698c2 100644
--- a/api/types/client.go
+++ b/api/types/client.go
@@ -7,8 +7,7 @@
 
 	"github.com/docker/docker/api/types/container"
 	"github.com/docker/docker/api/types/filters"
-	"github.com/docker/go-units"
-	specs "github.com/opencontainers/image-spec/specs-go/v1"
+	units "github.com/docker/go-units"
 )
 
 // CheckpointCreateOptions holds parameters to create a checkpoint from a container
@@ -181,7 +180,7 @@
 	ExtraHosts  []string // List of extra hosts
 	Target      string
 	SessionID   string
-	Platform    *specs.Platform
+	Platform    string
 	// Version specifies the version of the unerlying builder to use
 	Version BuilderVersion
 	// BuildID is an optional identifier that can be passed together with the
diff --git a/builder/builder-next/adapters/containerimage/pull.go b/builder/builder-next/adapters/containerimage/pull.go
index f76ac5a..2b6c214 100644
--- a/builder/builder-next/adapters/containerimage/pull.go
+++ b/builder/builder-next/adapters/containerimage/pull.go
@@ -644,7 +644,7 @@
 // featured.
 type jobs struct {
 	name     string
-	added    map[digest.Digest]job
+	added    map[digest.Digest]*job
 	mu       sync.Mutex
 	resolved bool
 }
@@ -658,7 +658,7 @@
 func newJobs(name string) *jobs {
 	return &jobs{
 		name:  name,
-		added: make(map[digest.Digest]job),
+		added: make(map[digest.Digest]*job),
 	}
 }
 
@@ -669,17 +669,17 @@
 	if _, ok := j.added[desc.Digest]; ok {
 		return
 	}
-	j.added[desc.Digest] = job{
+	j.added[desc.Digest] = &job{
 		Descriptor: desc,
 		started:    time.Now(),
 	}
 }
 
-func (j *jobs) jobs() []job {
+func (j *jobs) jobs() []*job {
 	j.mu.Lock()
 	defer j.mu.Unlock()
 
-	descs := make([]job, 0, len(j.added))
+	descs := make([]*job, 0, len(j.added))
 	for _, j := range j.added {
 		descs = append(descs, j)
 	}
diff --git a/builder/builder-next/builder.go b/builder/builder-next/builder.go
index 5a82cdd..b1d31a5 100644
--- a/builder/builder-next/builder.go
+++ b/builder/builder-next/builder.go
@@ -2,7 +2,6 @@
 
 import (
 	"context"
-	"encoding/json"
 	"io"
 	"strings"
 	"sync"
@@ -14,7 +13,8 @@
 	"github.com/docker/docker/api/types/backend"
 	"github.com/docker/docker/builder"
 	"github.com/docker/docker/daemon/images"
-	"github.com/docker/docker/pkg/jsonmessage"
+	"github.com/docker/docker/pkg/streamformatter"
+	"github.com/docker/docker/pkg/system"
 	controlapi "github.com/moby/buildkit/api/services/control"
 	"github.com/moby/buildkit/control"
 	"github.com/moby/buildkit/identity"
@@ -209,8 +209,17 @@
 		frontendAttrs["no-cache"] = ""
 	}
 
-	if opt.Options.Platform != nil {
-		frontendAttrs["platform"] = platforms.Format(*opt.Options.Platform)
+	if opt.Options.Platform != "" {
+		// same as in newBuilder in builder/dockerfile.builder.go
+		// TODO: remove once opt.Options.Platform is of type specs.Platform
+		sp, err := platforms.Parse(opt.Options.Platform)
+		if err != nil {
+			return nil, err
+		}
+		if err := system.ValidatePlatform(sp); err != nil {
+			return nil, err
+		}
+		frontendAttrs["platform"] = opt.Options.Platform
 	}
 
 	exporterAttrs := map[string]string{}
@@ -228,6 +237,8 @@
 		Session:       opt.Options.SessionID,
 	}
 
+	aux := streamformatter.AuxFormatter{opt.ProgressWriter.Output}
+
 	eg, ctx := errgroup.WithContext(ctx)
 
 	eg.Go(func() error {
@@ -240,7 +251,7 @@
 			return errors.Errorf("missing image id")
 		}
 		out.ImageID = id
-		return nil
+		return aux.Emit("moby.image.id", types.BuildResult{ID: id})
 	})
 
 	ch := make(chan *controlapi.StatusResponse)
@@ -258,25 +269,9 @@
 			if err != nil {
 				return err
 			}
-
-			auxJSONBytes, err := json.Marshal(dt)
-			if err != nil {
+			if err := aux.Emit("moby.buildkit.trace", dt); err != nil {
 				return err
 			}
-			auxJSON := new(json.RawMessage)
-			*auxJSON = auxJSONBytes
-			msgJSON, err := json.Marshal(&jsonmessage.JSONMessage{ID: "moby.buildkit.trace", Aux: auxJSON})
-			if err != nil {
-				return err
-			}
-			msgJSON = append(msgJSON, []byte("\r\n")...)
-			n, err := opt.ProgressWriter.Output.Write(msgJSON)
-			if err != nil {
-				return err
-			}
-			if n != len(msgJSON) {
-				return io.ErrShortWrite
-			}
 		}
 		return nil
 	})
diff --git a/builder/dockerfile/builder.go b/builder/dockerfile/builder.go
index b585347..ee95f23 100644
--- a/builder/dockerfile/builder.go
+++ b/builder/dockerfile/builder.go
@@ -10,6 +10,7 @@
 	"strings"
 	"time"
 
+	"github.com/containerd/containerd/platforms"
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types/backend"
 	"github.com/docker/docker/api/types/container"
@@ -25,6 +26,7 @@
 	"github.com/moby/buildkit/frontend/dockerfile/parser"
 	"github.com/moby/buildkit/frontend/dockerfile/shell"
 	"github.com/moby/buildkit/session"
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
 	"github.com/pkg/errors"
 	"github.com/sirupsen/logrus"
 	"golang.org/x/sync/syncmap"
@@ -111,7 +113,11 @@
 		PathCache:      bm.pathCache,
 		IDMappings:     bm.idMappings,
 	}
-	return newBuilder(ctx, builderOptions).build(source, dockerfile)
+	b, err := newBuilder(ctx, builderOptions)
+	if err != nil {
+		return nil, err
+	}
+	return b.build(source, dockerfile)
 }
 
 func (bm *BuildManager) initializeClientSession(ctx context.Context, cancel func(), options *types.ImageBuildOptions) (builder.Source, error) {
@@ -175,10 +181,11 @@
 	pathCache        pathCache
 	containerManager *containerManager
 	imageProber      ImageProber
+	platform         *specs.Platform
 }
 
 // newBuilder creates a new Dockerfile builder from an optional dockerfile and a Options.
-func newBuilder(clientCtx context.Context, options builderOptions) *Builder {
+func newBuilder(clientCtx context.Context, options builderOptions) (*Builder, error) {
 	config := options.Options
 	if config == nil {
 		config = new(types.ImageBuildOptions)
@@ -199,7 +206,20 @@
 		containerManager: newContainerManager(options.Backend),
 	}
 
-	return b
+	// same as in Builder.Build in builder/builder-next/builder.go
+	// TODO: remove once config.Platform is of type specs.Platform
+	if config.Platform != "" {
+		sp, err := platforms.Parse(config.Platform)
+		if err != nil {
+			return nil, err
+		}
+		if err := system.ValidatePlatform(sp); err != nil {
+			return nil, err
+		}
+		b.platform = &sp
+	}
+
+	return b, nil
 }
 
 // Build 'LABEL' command(s) from '--label' options and add to the last stage
@@ -257,7 +277,7 @@
 	if aux == nil || state.imageID == "" {
 		return nil
 	}
-	return aux.Emit(types.BuildResult{ID: state.imageID})
+	return aux.Emit("", types.BuildResult{ID: state.imageID})
 }
 
 func processMetaArg(meta instructions.ArgCommand, shlex *shell.Lex, args *BuildArgs) error {
@@ -365,9 +385,12 @@
 		return nil, errdefs.InvalidParameter(err)
 	}
 
-	b := newBuilder(context.Background(), builderOptions{
+	b, err := newBuilder(context.Background(), builderOptions{
 		Options: &types.ImageBuildOptions{NoCache: true},
 	})
+	if err != nil {
+		return nil, err
+	}
 
 	// ensure that the commands are valid
 	for _, n := range dockerfile.AST.Children {
diff --git a/builder/dockerfile/copy.go b/builder/dockerfile/copy.go
index 7e9dc60..74e245b 100644
--- a/builder/dockerfile/copy.go
+++ b/builder/dockerfile/copy.go
@@ -87,7 +87,7 @@
 		pathCache:   req.builder.pathCache,
 		download:    download,
 		imageSource: imageSource,
-		platform:    req.builder.options.Platform,
+		platform:    req.builder.platform,
 	}
 }
 
diff --git a/builder/dockerfile/dispatchers.go b/builder/dockerfile/dispatchers.go
index 1032c6c..5d72237 100644
--- a/builder/dockerfile/dispatchers.go
+++ b/builder/dockerfile/dispatchers.go
@@ -146,7 +146,7 @@
 		imageRefOrID = stage.Image
 		localOnly = true
 	}
-	return d.builder.imageSources.Get(imageRefOrID, localOnly, d.builder.options.Platform)
+	return d.builder.imageSources.Get(imageRefOrID, localOnly, d.builder.platform)
 }
 
 // FROM [--platform=platform] imagename[:tag | @digest] [AS build-stage-name]
@@ -238,7 +238,7 @@
 	}
 
 	if platform == nil {
-		platform = d.builder.options.Platform
+		platform = d.builder.platform
 	}
 
 	// Windows cannot support a container with no base image unless it is LCOW.
diff --git a/builder/dockerfile/dispatchers_test.go b/builder/dockerfile/dispatchers_test.go
index 047a874..c61a45b 100644
--- a/builder/dockerfile/dispatchers_test.go
+++ b/builder/dockerfile/dispatchers_test.go
@@ -6,7 +6,6 @@
 	"runtime"
 	"testing"
 
-	"github.com/containerd/containerd/platforms"
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types/backend"
 	"github.com/docker/docker/api/types/container"
@@ -23,8 +22,7 @@
 
 func newBuilderWithMockBackend() *Builder {
 	mockBackend := &MockBackend{}
-	defaultPlatform := platforms.DefaultSpec()
-	opts := &types.ImageBuildOptions{Platform: &defaultPlatform}
+	opts := &types.ImageBuildOptions{}
 	ctx := context.Background()
 	b := &Builder{
 		options:       opts,
@@ -116,7 +114,7 @@
 	err := initializeStage(sb, cmd)
 
 	if runtime.GOOS == "windows" && !system.LCOWSupported() {
-		assert.Check(t, is.Error(err, "Windows does not support FROM scratch"))
+		assert.Check(t, is.Error(err, "Linux containers are not supported on this system"))
 		return
 	}
 
diff --git a/builder/dockerfile/internals.go b/builder/dockerfile/internals.go
index 5e2c286..1b3a5b0 100644
--- a/builder/dockerfile/internals.go
+++ b/builder/dockerfile/internals.go
@@ -169,7 +169,7 @@
 		return err
 	}
 
-	imageMount, err := b.imageSources.Get(state.imageID, true, req.builder.options.Platform)
+	imageMount, err := b.imageSources.Get(state.imageID, true, req.builder.platform)
 	if err != nil {
 		return errors.Wrapf(err, "failed to get destination image %q", state.imageID)
 	}
@@ -416,7 +416,9 @@
 
 func (b *Builder) create(runConfig *container.Config) (string, error) {
 	logrus.Debugf("[BUILDER] Command to be executed: %v", runConfig.Cmd)
-	hostConfig := hostConfigFromOptions(b.options)
+
+	isWCOW := runtime.GOOS == "windows" && b.platform != nil && b.platform.OS == "windows"
+	hostConfig := hostConfigFromOptions(b.options, isWCOW)
 	container, err := b.containerManager.Create(runConfig, hostConfig)
 	if err != nil {
 		return "", err
@@ -429,7 +431,7 @@
 	return container.ID, nil
 }
 
-func hostConfigFromOptions(options *types.ImageBuildOptions) *container.HostConfig {
+func hostConfigFromOptions(options *types.ImageBuildOptions, isWCOW bool) *container.HostConfig {
 	resources := container.Resources{
 		CgroupParent: options.CgroupParent,
 		CPUShares:    options.CPUShares,
@@ -457,7 +459,7 @@
 	// is too small for builder scenarios where many users are
 	// using RUN statements to install large amounts of data.
 	// Use 127GB as that's the default size of a VHD in Hyper-V.
-	if runtime.GOOS == "windows" && options.Platform != nil && options.Platform.OS == "windows" {
+	if isWCOW {
 		hc.StorageOpt = make(map[string]string)
 		hc.StorageOpt["size"] = "127GB"
 	}
diff --git a/client/image_build.go b/client/image_build.go
index e501317..9add3c1 100644
--- a/client/image_build.go
+++ b/client/image_build.go
@@ -8,8 +8,8 @@
 	"net/http"
 	"net/url"
 	"strconv"
+	"strings"
 
-	"github.com/containerd/containerd/platforms"
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types/container"
 )
@@ -30,12 +30,6 @@
 	}
 	headers.Add("X-Registry-Config", base64.URLEncoding.EncodeToString(buf))
 
-	if options.Platform != nil {
-		if err := cli.NewVersionError("1.32", "platform"); err != nil {
-			return types.ImageBuildResponse{}, err
-		}
-		query.Set("platform", platforms.Format(*options.Platform))
-	}
 	headers.Set("Content-Type", "application/x-tar")
 
 	serverResp, err := cli.postRaw(ctx, "/build", query, buildContext, headers)
@@ -130,8 +124,11 @@
 	if options.SessionID != "" {
 		query.Set("session", options.SessionID)
 	}
-	if options.Platform != nil {
-		query.Set("platform", platforms.Format(*options.Platform))
+	if options.Platform != "" {
+		if err := cli.NewVersionError("1.32", "platform"); err != nil {
+			return query, err
+		}
+		query.Set("platform", strings.ToLower(options.Platform))
 	}
 	if options.BuildID != "" {
 		query.Set("buildid", options.BuildID)
diff --git a/distribution/pull_v2_windows.go b/distribution/pull_v2_windows.go
index 3c96458..1ae167e 100644
--- a/distribution/pull_v2_windows.go
+++ b/distribution/pull_v2_windows.go
@@ -74,11 +74,14 @@
 		if (manifestDescriptor.Platform.Architecture == runtime.GOARCH) &&
 			((p.OS != "" && manifestDescriptor.Platform.OS == p.OS) || // Explicit user request for an OS we know we support
 				(p.OS == "" && system.IsOSSupported(manifestDescriptor.Platform.OS))) { // No user requested OS, but one we can support
-			matches = append(matches, manifestDescriptor)
-			logrus.Debugf("found match %s/%s %s with media type %s, digest %s", manifestDescriptor.Platform.OS, runtime.GOARCH, manifestDescriptor.Platform.OSVersion, manifestDescriptor.MediaType, manifestDescriptor.Digest.String())
 			if strings.EqualFold("windows", manifestDescriptor.Platform.OS) {
+				if err := checkImageCompatibility("windows", manifestDescriptor.Platform.OSVersion); err != nil {
+					continue
+				}
 				foundWindowsMatch = true
 			}
+			matches = append(matches, manifestDescriptor)
+			logrus.Debugf("found match %s/%s %s with media type %s, digest %s", manifestDescriptor.Platform.OS, runtime.GOARCH, manifestDescriptor.Platform.OSVersion, manifestDescriptor.MediaType, manifestDescriptor.Digest.String())
 		} else {
 			logrus.Debugf("ignoring %s/%s %s with media type %s, digest %s", manifestDescriptor.Platform.OS, manifestDescriptor.Platform.Architecture, manifestDescriptor.Platform.OSVersion, manifestDescriptor.MediaType, manifestDescriptor.Digest.String())
 		}
@@ -103,7 +106,8 @@
 	// TODO: Split version by parts and compare
 	// TODO: Prefer versions which have a greater version number
 	// Move compatible versions to the top, with no other ordering changes
-	return versionMatch(mbv.list[i].Platform.OSVersion, mbv.version) && !versionMatch(mbv.list[j].Platform.OSVersion, mbv.version)
+	return (strings.EqualFold("windows", mbv.list[i].Platform.OS) && !strings.EqualFold("windows", mbv.list[j].Platform.OS)) ||
+		(versionMatch(mbv.list[i].Platform.OSVersion, mbv.version) && !versionMatch(mbv.list[j].Platform.OSVersion, mbv.version))
 }
 
 func (mbv manifestsByVersion) Len() int {
diff --git a/hack/dockerfile/install/containerd.installer b/hack/dockerfile/install/containerd.installer
index e23c8a2..792ea98 100755
--- a/hack/dockerfile/install/containerd.installer
+++ b/hack/dockerfile/install/containerd.installer
@@ -4,7 +4,7 @@
 # containerd is also pinned in vendor.conf. When updating the binary
 # version you may also need to update the vendor version to pick up bug
 # fixes or new APIs.
-CONTAINERD_COMMIT=cbef57047e900aeb2bafe7a634919bec13f4a2a5 # v1.1.1-rc.1
+CONTAINERD_COMMIT=e5fb877b9f6c14b15f48643735a8c9764a7319d3 # v1.1.1-rc.2
 
 install_containerd() {
 	echo "Install containerd version $CONTAINERD_COMMIT"
diff --git a/hack/dockerfile/install/proxy.installer b/hack/dockerfile/install/proxy.installer
index 00c2f1d..b5748b5 100755
--- a/hack/dockerfile/install/proxy.installer
+++ b/hack/dockerfile/install/proxy.installer
@@ -3,7 +3,7 @@
 # LIBNETWORK_COMMIT is used to build the docker-userland-proxy binary. When
 # updating the binary version, consider updating github.com/docker/libnetwork
 # in vendor.conf accordingly
-LIBNETWORK_COMMIT=19279f0492417475b6bfbd0aa529f73e8f178fb5
+LIBNETWORK_COMMIT=430c00a6a6b3dfdd774f21e1abd4ad6b0216c629
 
 install_proxy() {
 	case "$1" in
diff --git a/integration-cli/docker_cli_network_unix_test.go b/integration-cli/docker_cli_network_unix_test.go
index 95f7ccf..a0abb67 100644
--- a/integration-cli/docker_cli_network_unix_test.go
+++ b/integration-cli/docker_cli_network_unix_test.go
@@ -610,17 +610,17 @@
 	// test network with multiple subnets
 	// bridge network doesn't support multiple subnets. hence, use a dummy driver that supports
 
-	dockerCmd(c, "network", "create", "-d", dummyNetworkDriver, "--subnet=192.168.0.0/16", "--subnet=192.170.0.0/16", "test6")
+	dockerCmd(c, "network", "create", "-d", dummyNetworkDriver, "--subnet=192.170.0.0/16", "--subnet=192.171.0.0/16", "test6")
 	assertNwIsAvailable(c, "test6")
 
 	// test network with multiple subnets with valid ipam combinations
 	// also check same subnet across networks when the driver supports it.
 	dockerCmd(c, "network", "create", "-d", dummyNetworkDriver,
-		"--subnet=192.168.0.0/16", "--subnet=192.170.0.0/16",
-		"--gateway=192.168.0.100", "--gateway=192.170.0.100",
-		"--ip-range=192.168.1.0/24",
-		"--aux-address", "a=192.168.1.5", "--aux-address", "b=192.168.1.6",
-		"--aux-address", "c=192.170.1.5", "--aux-address", "d=192.170.1.6",
+		"--subnet=192.172.0.0/16", "--subnet=192.173.0.0/16",
+		"--gateway=192.172.0.100", "--gateway=192.173.0.100",
+		"--ip-range=192.172.1.0/24",
+		"--aux-address", "a=192.172.1.5", "--aux-address", "b=192.172.1.6",
+		"--aux-address", "c=192.173.1.5", "--aux-address", "d=192.173.1.6",
 		"test7")
 	assertNwIsAvailable(c, "test7")
 
diff --git a/pkg/streamformatter/streamformatter.go b/pkg/streamformatter/streamformatter.go
index 2b5e713..04917d4 100644
--- a/pkg/streamformatter/streamformatter.go
+++ b/pkg/streamformatter/streamformatter.go
@@ -139,14 +139,14 @@
 }
 
 // Emit emits the given interface as an aux progress message
-func (sf *AuxFormatter) Emit(aux interface{}) error {
+func (sf *AuxFormatter) Emit(id string, aux interface{}) error {
 	auxJSONBytes, err := json.Marshal(aux)
 	if err != nil {
 		return err
 	}
 	auxJSON := new(json.RawMessage)
 	*auxJSON = auxJSONBytes
-	msgJSON, err := json.Marshal(&jsonmessage.JSONMessage{Aux: auxJSON})
+	msgJSON, err := json.Marshal(&jsonmessage.JSONMessage{ID: id, Aux: auxJSON})
 	if err != nil {
 		return err
 	}
diff --git a/pkg/streamformatter/streamformatter_test.go b/pkg/streamformatter/streamformatter_test.go
index 4399a65..f630699 100644
--- a/pkg/streamformatter/streamformatter_test.go
+++ b/pkg/streamformatter/streamformatter_test.go
@@ -106,7 +106,7 @@
 	sampleAux := &struct {
 		Data string
 	}{"Additional data"}
-	err := aux.Emit(sampleAux)
+	err := aux.Emit("", sampleAux)
 	assert.NilError(t, err)
 	assert.Check(t, is.Equal(`{"aux":{"Data":"Additional data"}}`+streamNewline, b.String()))
 }
diff --git a/vendor.conf b/vendor.conf
index cd059b7..33e2dc8 100644
--- a/vendor.conf
+++ b/vendor.conf
@@ -1,7 +1,7 @@
 # the following lines are in sorted order, FYI
 github.com/Azure/go-ansiterm d6e3b3328b783f23731bc4d058875b0371ff8109
 github.com/Microsoft/hcsshim v0.6.11
-github.com/Microsoft/go-winio v0.4.7
+github.com/Microsoft/go-winio v0.4.8
 github.com/docker/libtrust 9cbd2a1374f46905c68a4eb3694a130610adc62a
 github.com/go-check/check 4ed411733c5785b40214c70bce814c3a3a689609 https://github.com/cpuguy83/check.git
 github.com/golang/gddo 9b12a26f3fbd7397dee4e20939ddca719d840d2a
@@ -26,7 +26,7 @@
 golang.org/x/sync fd80eb99c8f653c847d294a001bdf2a3a6f768f5
 
 # buildkit
-github.com/moby/buildkit cce2080ddbe4698912f2290892b247c83627efa8
+github.com/moby/buildkit 9acf51e49185b348608e0096b2903dd72907adcb
 github.com/tonistiigi/fsutil 8abad97ee3969cdf5e9c367f46adba2c212b3ddb
 github.com/grpc-ecosystem/grpc-opentracing 8e809c8a86450a29b90dcc9efbf062d0fe6d9746
 github.com/opentracing/opentracing-go 1361b9cd60be79c4c3a7fa9841b3c132e40066a7
@@ -37,14 +37,14 @@
 #get libnetwork packages
 
 # When updating, also update LIBNETWORK_COMMIT in hack/dockerfile/install/proxy accordingly
-github.com/docker/libnetwork 19279f0492417475b6bfbd0aa529f73e8f178fb5
+github.com/docker/libnetwork 430c00a6a6b3dfdd774f21e1abd4ad6b0216c629
 github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9
 github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80
 github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
 github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b
 github.com/hashicorp/memberlist 3d8438da9589e7b608a83ffac1ef8211486bcb7c
 github.com/sean-/seed e2103e2c35297fb7e17febb81e49b312087a2372
-github.com/hashicorp/go-sockaddr acd314c5781ea706c710d9ea70069fd2e110d61d
+github.com/hashicorp/go-sockaddr 6d291a969b86c4b633730bfc6b8b9d64c3aafed9
 github.com/hashicorp/go-multierror fcdddc395df1ddf4247c69bd436e84cfa0733f7e
 github.com/hashicorp/serf 598c54895cc5a7b1a24a398d635e8c0ea0959870
 github.com/docker/libkv 1d8431073ae03cdaedb198a89722f3aab6d418ef
diff --git a/vendor/github.com/Microsoft/go-winio/pipe.go b/vendor/github.com/Microsoft/go-winio/pipe.go
index 82cbe7a..806fd34 100644
--- a/vendor/github.com/Microsoft/go-winio/pipe.go
+++ b/vendor/github.com/Microsoft/go-winio/pipe.go
@@ -121,6 +121,11 @@
 		// zero-byte message, ensure that all future Read() calls
 		// also return EOF.
 		f.readEOF = true
+	} else if err == syscall.ERROR_MORE_DATA {
+		// ERROR_MORE_DATA indicates that the pipe's read mode is message mode
+		// and the message still has more bytes. Treat this as a success, since
+		// this package presents all named pipes as byte streams.
+		err = nil
 	}
 	return n, err
 }
@@ -175,16 +180,6 @@
 		return nil, err
 	}
 
-	var state uint32
-	err = getNamedPipeHandleState(h, &state, nil, nil, nil, nil, 0)
-	if err != nil {
-		return nil, err
-	}
-
-	if state&cPIPE_READMODE_MESSAGE != 0 {
-		return nil, &os.PathError{Op: "open", Path: path, Err: errors.New("message readmode pipes not supported")}
-	}
-
 	f, err := makeWin32File(h)
 	if err != nil {
 		syscall.Close(h)
diff --git a/vendor/github.com/docker/libnetwork/controller.go b/vendor/github.com/docker/libnetwork/controller.go
index fe9c4dd..5e967b7 100644
--- a/vendor/github.com/docker/libnetwork/controller.go
+++ b/vendor/github.com/docker/libnetwork/controller.go
@@ -69,6 +69,7 @@
 	"github.com/docker/libnetwork/netlabel"
 	"github.com/docker/libnetwork/osl"
 	"github.com/docker/libnetwork/types"
+	"github.com/pkg/errors"
 	"github.com/sirupsen/logrus"
 )
 
@@ -1252,7 +1253,7 @@
 	}
 
 	if err != nil {
-		if err == plugins.ErrNotFound {
+		if errors.Cause(err) == plugins.ErrNotFound {
 			return types.NotFoundErrorf(err.Error())
 		}
 		return err
diff --git a/vendor/github.com/docker/libnetwork/ipam/allocator.go b/vendor/github.com/docker/libnetwork/ipam/allocator.go
index 29473c5..7213148 100644
--- a/vendor/github.com/docker/libnetwork/ipam/allocator.go
+++ b/vendor/github.com/docker/libnetwork/ipam/allocator.go
@@ -29,7 +29,10 @@
 // Allocator provides per address space ipv4/ipv6 book keeping
 type Allocator struct {
 	// Predefined pools for default address spaces
-	predefined map[string][]*net.IPNet
+	// Separate from the addrSpace because they should not be serialized
+	predefined             map[string][]*net.IPNet
+	predefinedStartIndices map[string]int
+	// The (potentially serialized) address spaces
 	addrSpaces map[string]*addrSpace
 	// stores        []datastore.Datastore
 	// Allocated addresses in each address space's subnet
@@ -47,6 +50,9 @@
 		globalAddressSpace: ipamutils.PredefinedGranularNetworks,
 	}
 
+	// Initialize asIndices map
+	a.predefinedStartIndices = make(map[string]int)
+
 	// Initialize bitseq map
 	a.addresses = make(map[SubnetKey]*bitseq.Handle)
 
@@ -374,11 +380,24 @@
 func (a *Allocator) getPredefineds(as string) []*net.IPNet {
 	a.Lock()
 	defer a.Unlock()
-	l := make([]*net.IPNet, 0, len(a.predefined[as]))
-	for _, pool := range a.predefined[as] {
-		l = append(l, pool)
+
+	p := a.predefined[as]
+	i := a.predefinedStartIndices[as]
+	// defensive in case the list changed since last update
+	if i >= len(p) {
+		i = 0
 	}
-	return l
+	return append(p[i:], p[:i]...)
+}
+
+func (a *Allocator) updateStartIndex(as string, amt int) {
+	a.Lock()
+	i := a.predefinedStartIndices[as] + amt
+	if i < 0 || i >= len(a.predefined[as]) {
+		i = 0
+	}
+	a.predefinedStartIndices[as] = i
+	a.Unlock()
 }
 
 func (a *Allocator) getPredefinedPool(as string, ipV6 bool) (*net.IPNet, error) {
@@ -397,21 +416,26 @@
 		return nil, err
 	}
 
-	for _, nw := range a.getPredefineds(as) {
+	predefined := a.getPredefineds(as)
+
+	aSpace.Lock()
+	for i, nw := range predefined {
 		if v != getAddressVersion(nw.IP) {
 			continue
 		}
-		aSpace.Lock()
+		// Checks whether pool has already been allocated
 		if _, ok := aSpace.subnets[SubnetKey{AddressSpace: as, Subnet: nw.String()}]; ok {
-			aSpace.Unlock()
 			continue
 		}
+		// Shouldn't be necessary, but check prevents IP collisions should
+		// predefined pools overlap for any reason.
 		if !aSpace.contains(as, nw) {
 			aSpace.Unlock()
+			a.updateStartIndex(as, i+1)
 			return nw, nil
 		}
-		aSpace.Unlock()
 	}
+	aSpace.Unlock()
 
 	return nil, types.NotFoundErrorf("could not find an available, non-overlapping IPv%d address pool among the defaults to assign to the network", v)
 }
diff --git a/vendor/github.com/docker/libnetwork/ipam/structures.go b/vendor/github.com/docker/libnetwork/ipam/structures.go
index 09a7769..455a16c 100644
--- a/vendor/github.com/docker/libnetwork/ipam/structures.go
+++ b/vendor/github.com/docker/libnetwork/ipam/structures.go
@@ -262,12 +262,13 @@
 	defer aSpace.Unlock()
 
 	// Check if already allocated
-	if p, ok := aSpace.subnets[k]; ok {
+	if _, ok := aSpace.subnets[k]; ok {
 		if pdf {
 			return nil, types.InternalMaskableErrorf("predefined pool %s is already reserved", nw)
 		}
-		aSpace.incRefCount(p, 1)
-		return func() error { return nil }, nil
+		// This means the same pool is already allocated. updatePoolDBOnAdd is called when there
+		// is request for a pool/subpool. It should ensure there is no overlap with existing pools
+		return nil, ipamapi.ErrPoolOverlap
 	}
 
 	// If master pool, check for overlap
diff --git a/vendor/github.com/docker/libnetwork/network.go b/vendor/github.com/docker/libnetwork/network.go
index e283d65..70d6b1c 100644
--- a/vendor/github.com/docker/libnetwork/network.go
+++ b/vendor/github.com/docker/libnetwork/network.go
@@ -1156,18 +1156,6 @@
 			ep.releaseAddress()
 		}
 	}()
-	// Moving updateToSTore before calling addEndpoint so that we shall clean up VETH interfaces in case
-	// DockerD get killed between addEndpoint and updateSTore call
-	if err = n.getController().updateToStore(ep); err != nil {
-		return nil, err
-	}
-	defer func() {
-		if err != nil {
-			if e := n.getController().deleteFromStore(ep); e != nil {
-				logrus.Warnf("error rolling back endpoint %s from store: %v", name, e)
-			}
-		}
-	}()
 
 	if err = n.addEndpoint(ep); err != nil {
 		return nil, err
@@ -1180,6 +1168,19 @@
 		}
 	}()
 
+	// We should perform updateToStore call right after addEndpoint
+	// in order to have iface properly configured
+	if err = n.getController().updateToStore(ep); err != nil {
+		return nil, err
+	}
+	defer func() {
+		if err != nil {
+			if e := n.getController().deleteFromStore(ep); e != nil {
+				logrus.Warnf("error rolling back endpoint %s from store: %v", name, e)
+			}
+		}
+	}()
+
 	if err = ep.assignAddress(ipam, false, n.enableIPv6 && n.postIPv6); err != nil {
 		return nil, err
 	}
diff --git a/vendor/github.com/docker/libnetwork/networkdb/delegate.go b/vendor/github.com/docker/libnetwork/networkdb/delegate.go
index 9a379fe..6cd827e 100644
--- a/vendor/github.com/docker/libnetwork/networkdb/delegate.go
+++ b/vendor/github.com/docker/libnetwork/networkdb/delegate.go
@@ -41,7 +41,7 @@
 	// If the node is not known from memberlist we cannot process save any state of it else if it actually
 	// dies we won't receive any notification and we will remain stuck with it
 	if _, ok := nDB.nodes[nEvent.NodeName]; !ok {
-		logrus.Error("node: %s is unknown to memberlist", nEvent.NodeName)
+		logrus.Errorf("node: %s is unknown to memberlist", nEvent.NodeName)
 		return false
 	}
 
diff --git a/vendor/github.com/docker/libnetwork/types/types.go b/vendor/github.com/docker/libnetwork/types/types.go
index f851d6f..5968545 100644
--- a/vendor/github.com/docker/libnetwork/types/types.go
+++ b/vendor/github.com/docker/libnetwork/types/types.go
@@ -145,7 +145,12 @@
 	return ret
 }
 
-// FromString reads the PortBinding structure from string
+// FromString reads the PortBinding structure from string s.
+// String s is a triple of "protocol/containerIP:port/hostIP:port"
+// containerIP and hostIP can be in dotted decimal ("192.0.2.1") or IPv6 ("2001:db8::68") form.
+// Zoned addresses ("169.254.0.23%eth0" or "fe80::1ff:fe23:4567:890a%eth0") are not supported.
+// If string s is incorrectly formatted or the IP addresses or ports cannot be parsed, FromString
+// returns an error.
 func (p *PortBinding) FromString(s string) error {
 	ps := strings.Split(s, "/")
 	if len(ps) != 3 {
@@ -167,21 +172,19 @@
 }
 
 func parseIPPort(s string) (net.IP, uint16, error) {
-	pp := strings.Split(s, ":")
-	if len(pp) != 2 {
-		return nil, 0, BadRequestErrorf("invalid format: %s", s)
-	}
-
-	var ip net.IP
-	if pp[0] != "" {
-		if ip = net.ParseIP(pp[0]); ip == nil {
-			return nil, 0, BadRequestErrorf("invalid ip: %s", pp[0])
-		}
-	}
-
-	port, err := strconv.ParseUint(pp[1], 10, 16)
+	hoststr, portstr, err := net.SplitHostPort(s)
 	if err != nil {
-		return nil, 0, BadRequestErrorf("invalid port: %s", pp[1])
+		return nil, 0, err
+	}
+
+	ip := net.ParseIP(hoststr)
+	if ip == nil {
+		return nil, 0, BadRequestErrorf("invalid ip: %s", hoststr)
+	}
+
+	port, err := strconv.ParseUint(portstr, 10, 16)
+	if err != nil {
+		return nil, 0, BadRequestErrorf("invalid port: %s", portstr)
 	}
 
 	return ip, uint16(port), nil
diff --git a/vendor/github.com/docker/libnetwork/vendor.conf b/vendor/github.com/docker/libnetwork/vendor.conf
index 9480699..5237c55 100644
--- a/vendor/github.com/docker/libnetwork/vendor.conf
+++ b/vendor/github.com/docker/libnetwork/vendor.conf
@@ -1,27 +1,28 @@
 github.com/Azure/go-ansiterm d6e3b3328b783f23731bc4d058875b0371ff8109
 github.com/BurntSushi/toml a368813c5e648fee92e5f6c30e3944ff9d5e8895
-github.com/Microsoft/go-winio v0.4.5
-github.com/Microsoft/hcsshim v0.6.5
+github.com/Microsoft/go-winio v0.4.7
+github.com/Microsoft/hcsshim v0.6.11
 github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
 github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80
 github.com/boltdb/bolt fff57c100f4dea1905678da7e90d92429dff2904
 github.com/codegangsta/cli a65b733b303f0055f8d324d805f393cd3e7a7904
-github.com/containerd/console 84eeaae905fa414d03e07bcd6c8d3f19e7cf180e
-github.com/containerd/continuity 22694c680ee48fb8f50015b44618517e2bde77e8
+github.com/containerd/console cb7008ab3d8359b78c5f464cb7cf160107ad5925
+github.com/containerd/continuity d3c23511c1bf5851696cba83143d9cbcd666869b
 github.com/coreos/etcd v3.2.1
 github.com/coreos/go-semver v0.2.0
-github.com/coreos/go-systemd v4
+github.com/coreos/go-systemd v17
+github.com/coreos/pkg fa29b1d70f0beaddd4c7021607cc3c3be8ce94b8
 github.com/deckarep/golang-set ef32fa3046d9f249d399f98ebaf9be944430fd1d
 
-github.com/docker/docker a3efe9722f34af5cf4443fe3a5c4e4e3e0457b54
-github.com/docker/go-connections 3ede32e2033de7505e6500d6c868c2b9ed9f169d
+github.com/docker/docker 162ba6016def672690ee4a1f3978368853a1e149
+github.com/docker/go-connections 7beb39f0b969b075d1325fecb092faf27fd357b6
 github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9
 github.com/docker/go-units 9e638d38cf6977a37a8ea0078f3ee75a7cdb2dd1
 github.com/docker/libkv 1d8431073ae03cdaedb198a89722f3aab6d418ef
 
 github.com/godbus/dbus v4.0.0
-github.com/gogo/protobuf v0.4
-github.com/golang/protobuf 7a211bcf3bce0e3f1d74f9894916e6f116ae83b4
+github.com/gogo/protobuf v1.0.0
+github.com/golang/protobuf v1.1.0
 github.com/gorilla/context v1.1
 github.com/gorilla/mux v1.1
 github.com/hashicorp/consul v0.5.2
@@ -29,27 +30,37 @@
 github.com/hashicorp/go-multierror fcdddc395df1ddf4247c69bd436e84cfa0733f7e
 github.com/hashicorp/memberlist 3d8438da9589e7b608a83ffac1ef8211486bcb7c
 github.com/sean-/seed e2103e2c35297fb7e17febb81e49b312087a2372
-github.com/hashicorp/go-sockaddr acd314c5781ea706c710d9ea70069fd2e110d61d
+github.com/hashicorp/go-sockaddr 6d291a969b86c4b633730bfc6b8b9d64c3aafed9
 github.com/hashicorp/serf 598c54895cc5a7b1a24a398d635e8c0ea0959870
 github.com/mattn/go-shellwords v1.0.3
-github.com/miekg/dns 75e6e86cc601825c5dbcd4e0c209eab180997cd7
+github.com/miekg/dns v1.0.7
 github.com/mrunalp/fileutils ed869b029674c0e9ce4c0dfa781405c2d9946d08
-github.com/opencontainers/go-digest a6d0ee40d4207ea02364bd3b9e8e77b9159ba1eb
-github.com/opencontainers/image-spec 372ad780f63454fbbbbcc7cf80e5b90245c13e13
-github.com/opencontainers/runc 0351df1c5a66838d0c392b4ac4cf9450de844e2d
-github.com/opencontainers/runtime-spec v1.0.0
-github.com/opencontainers/selinux v1.0.0-rc1
+github.com/opencontainers/go-digest v1.0.0-rc1
+github.com/opencontainers/image-spec v1.0.1
+github.com/opencontainers/runc 69663f0bd4b60df09991c08812a60108003fa340
+github.com/opencontainers/runtime-spec v1.0.1
+github.com/opencontainers/selinux b29023b86e4a69d1b46b7e7b4e2b6fda03f0b9cd
 github.com/samuel/go-zookeeper d0e0d8e11f318e000a8cc434616d69e329edc374
 github.com/seccomp/libseccomp-golang 32f571b70023028bd57d9288c20efbcb237f3ce0
 github.com/sirupsen/logrus v1.0.3
 github.com/stretchr/testify dab07ac62d4905d3e48d17dc549c684ac3b7c15a
-github.com/syndtr/gocapability db04d3cc01c8b54962a58ec7e491717d06cfcc16
+github.com/syndtr/gocapability 33e07d32887e1e06b7c025f27ce52f62c7990bc0
 github.com/ugorji/go f1f1a805ed361a0e078bb537e4ea78cd37dcf065
 github.com/vishvananda/netlink b2de5d10e38ecce8607e6b438b6d174f389a004e
 github.com/vishvananda/netns 604eaf189ee867d8c147fafc28def2394e878d25
-golang.org/x/crypto 558b6879de74bc843225cde5686419267ff707ca
-golang.org/x/net b3756b4b77d7b13260a0a2ec658753cf48922eac
-golang.org/x/sys 07c182904dbd53199946ba614a412c61d3c548f5
+golang.org/x/crypto 1a580b3eff7814fc9b40602fd35256c63b50f491
+golang.org/x/net 0ed95abb35c445290478a5348a7b38bb154135fd
+golang.org/x/sys 37707fdb30a5b38865cfb95e5aab41707daec7fd
 golang.org/x/sync fd80eb99c8f653c847d294a001bdf2a3a6f768f5
 github.com/pkg/errors 839d9e913e063e28dfd0e6c7b7512793e0a48be9
 github.com/ishidawataru/sctp 07191f837fedd2f13d1ec7b5f885f0f3ec54b1cb
+
+github.com/davecgh/go-spew 8991bc29aa16c548c550c7ff78260e27b9ab7c73
+github.com/pmezard/go-difflib 792786c7400a136282c1664665ae0a8db921c6c2
+github.com/cyphar/filepath-securejoin v0.2.1
+github.com/hashicorp/errwrap 7554cd9344cec97297fa6649b055a8c98c2a1e55
+github.com/hashicorp/go-immutable-radix 7f3cd4390caab3250a57f30efdb2a65dd7649ecf
+github.com/hashicorp/golang-lru 0fb14efe8c47ae851c0034ed7a448854d3d34cf3
+github.com/hashicorp/go-cleanhttp d5fe4b57a186c716b0e00b8c301cbd9b4182694d
+github.com/hashicorp/go-rootcerts 6bb64b370b90e7ef1fa532be9e591a81c3493e00
+github.com/mitchellh/go-homedir 3864e76763d94a6df2f9960b16a20a33da9f9a66
diff --git a/vendor/github.com/hashicorp/go-sockaddr/ifaddr.go b/vendor/github.com/hashicorp/go-sockaddr/ifaddr.go
index 3e4ff9f..0811b27 100644
--- a/vendor/github.com/hashicorp/go-sockaddr/ifaddr.go
+++ b/vendor/github.com/hashicorp/go-sockaddr/ifaddr.go
@@ -1,5 +1,7 @@
 package sockaddr
 
+import "strings"
+
 // ifAddrAttrMap is a map of the IfAddr type-specific attributes.
 var ifAddrAttrMap map[AttrName]func(IfAddr) string
 var ifAddrAttrs []AttrName
@@ -30,6 +32,53 @@
 	return ip.NetIP().String(), nil
 }
 
+// GetPrivateIPs returns a string with all IP addresses that are part of RFC
+// 6890 (regardless of whether or not there is a default route, unlike
+// GetPublicIP).  If the system can't find any RFC 6890 IP addresses, an empty
+// string will be returned instead.  This function is the `eval` equivalent of:
+//
+// ```
+// $ sockaddr eval -r '{{GetAllInterfaces | include "RFC" "6890" | join "address" " "}}'
+/// ```
+func GetPrivateIPs() (string, error) {
+	ifAddrs, err := GetAllInterfaces()
+	if err != nil {
+		return "", err
+	} else if len(ifAddrs) < 1 {
+		return "", nil
+	}
+
+	ifAddrs, _ = FilterIfByType(ifAddrs, TypeIP)
+	if len(ifAddrs) == 0 {
+		return "", nil
+	}
+
+	OrderedIfAddrBy(AscIfType, AscIfNetworkSize).Sort(ifAddrs)
+
+	ifAddrs, _, err = IfByRFC("6890", ifAddrs)
+	if err != nil {
+		return "", err
+	} else if len(ifAddrs) == 0 {
+		return "", nil
+	}
+
+	_, ifAddrs, err = IfByRFC(ForwardingBlacklistRFC, ifAddrs)
+	if err != nil {
+		return "", err
+	} else if len(ifAddrs) == 0 {
+		return "", nil
+	}
+
+	ips := make([]string, 0, len(ifAddrs))
+	for _, ifAddr := range ifAddrs {
+		ip := *ToIPAddr(ifAddr.SockAddr)
+		s := ip.NetIP().String()
+		ips = append(ips, s)
+	}
+
+	return strings.Join(ips, " "), nil
+}
+
 // GetPublicIP returns a string with a single IP address that is NOT part of RFC
 // 6890 and has a default route.  If the system can't determine its IP address
 // or find a non RFC 6890 IP address, an empty string will be returned instead.
@@ -51,6 +100,47 @@
 	return ip.NetIP().String(), nil
 }
 
+// GetPublicIPs returns a string with all IP addresses that are NOT part of RFC
+// 6890 (regardless of whether or not there is a default route, unlike
+// GetPublicIP).  If the system can't find any non RFC 6890 IP addresses, an
+// empty string will be returned instead.  This function is the `eval`
+// equivalent of:
+//
+// ```
+// $ sockaddr eval -r '{{GetAllInterfaces | exclude "RFC" "6890" | join "address" " "}}'
+/// ```
+func GetPublicIPs() (string, error) {
+	ifAddrs, err := GetAllInterfaces()
+	if err != nil {
+		return "", err
+	} else if len(ifAddrs) < 1 {
+		return "", nil
+	}
+
+	ifAddrs, _ = FilterIfByType(ifAddrs, TypeIP)
+	if len(ifAddrs) == 0 {
+		return "", nil
+	}
+
+	OrderedIfAddrBy(AscIfType, AscIfNetworkSize).Sort(ifAddrs)
+
+	_, ifAddrs, err = IfByRFC("6890", ifAddrs)
+	if err != nil {
+		return "", err
+	} else if len(ifAddrs) == 0 {
+		return "", nil
+	}
+
+	ips := make([]string, 0, len(ifAddrs))
+	for _, ifAddr := range ifAddrs {
+		ip := *ToIPAddr(ifAddr.SockAddr)
+		s := ip.NetIP().String()
+		ips = append(ips, s)
+	}
+
+	return strings.Join(ips, " "), nil
+}
+
 // GetInterfaceIP returns a string with a single IP address sorted by the size
 // of the network (i.e. IP addresses with a smaller netmask, larger network
 // size, are sorted first).  This function is the `eval` equivalent of:
@@ -91,6 +181,44 @@
 	return IPAddrAttr(*ip, "address"), nil
 }
 
+// GetInterfaceIPs returns a string with all IPs, sorted by the size of the
+// network (i.e. IP addresses with a smaller netmask, larger network size, are
+// sorted first), on a named interface.  This function is the `eval` equivalent
+// of:
+//
+// ```
+// $ sockaddr eval -r '{{GetAllInterfaces | include "name" <<ARG>> | sort "type,size" | join "address" " "}}'
+/// ```
+func GetInterfaceIPs(namedIfRE string) (string, error) {
+	ifAddrs, err := GetAllInterfaces()
+	if err != nil {
+		return "", err
+	}
+
+	ifAddrs, _, err = IfByName(namedIfRE, ifAddrs)
+	if err != nil {
+		return "", err
+	}
+
+	ifAddrs, err = SortIfBy("+type,+size", ifAddrs)
+	if err != nil {
+		return "", err
+	}
+
+	if len(ifAddrs) == 0 {
+		return "", err
+	}
+
+	ips := make([]string, 0, len(ifAddrs))
+	for _, ifAddr := range ifAddrs {
+		ip := *ToIPAddr(ifAddr.SockAddr)
+		s := ip.NetIP().String()
+		ips = append(ips, s)
+	}
+
+	return strings.Join(ips, " "), nil
+}
+
 // IfAddrAttrs returns a list of attributes supported by the IfAddr type
 func IfAddrAttrs() []AttrName {
 	return ifAddrAttrs
diff --git a/vendor/github.com/hashicorp/go-sockaddr/ifaddrs.go b/vendor/github.com/hashicorp/go-sockaddr/ifaddrs.go
index 8233be2..2a706c3 100644
--- a/vendor/github.com/hashicorp/go-sockaddr/ifaddrs.go
+++ b/vendor/github.com/hashicorp/go-sockaddr/ifaddrs.go
@@ -1,8 +1,10 @@
 package sockaddr
 
 import (
+	"encoding/binary"
 	"errors"
 	"fmt"
+	"math/big"
 	"net"
 	"regexp"
 	"sort"
@@ -10,6 +12,14 @@
 	"strings"
 )
 
+var (
+	// Centralize all regexps and regexp.Copy() where necessary.
+	signRE       *regexp.Regexp = regexp.MustCompile(`^[\s]*[+-]`)
+	whitespaceRE *regexp.Regexp = regexp.MustCompile(`[\s]+`)
+	ifNameRE     *regexp.Regexp = regexp.MustCompile(`^(?:Ethernet|Wireless LAN) adapter ([^:]+):`)
+	ipAddrRE     *regexp.Regexp = regexp.MustCompile(`^   IPv[46] Address\. \. \. \. \. \. \. \. \. \. \. : ([^\s]+)`)
+)
+
 // IfAddrs is a slice of IfAddr
 type IfAddrs []IfAddr
 
@@ -91,6 +101,40 @@
 	return AscAddress(&p1Ptr.SockAddr, &p2Ptr.SockAddr)
 }
 
+// AscIfDefault is a sorting function to sort IfAddrs by whether or not they
+// have a default route or not.  Non-equal types are deferred in the sort.
+//
+// FIXME: This is a particularly expensive sorting operation because of the
+// non-memoized calls to NewRouteInfo().  In an ideal world the routeInfo data
+// once at the start of the sort and pass it along as a context or by wrapping
+// the IfAddr type with this information (this would also solve the inability to
+// return errors and the possibility of failing silently).  Fortunately,
+// N*log(N) where N = 3 is only ~6.2 invocations.  Not ideal, but not worth
+// optimizing today.  The common case is this gets called once or twice.
+// Patches welcome.
+func AscIfDefault(p1Ptr, p2Ptr *IfAddr) int {
+	ri, err := NewRouteInfo()
+	if err != nil {
+		return sortDeferDecision
+	}
+
+	defaultIfName, err := ri.GetDefaultInterfaceName()
+	if err != nil {
+		return sortDeferDecision
+	}
+
+	switch {
+	case p1Ptr.Interface.Name == defaultIfName && p2Ptr.Interface.Name == defaultIfName:
+		return sortDeferDecision
+	case p1Ptr.Interface.Name == defaultIfName:
+		return sortReceiverBeforeArg
+	case p2Ptr.Interface.Name == defaultIfName:
+		return sortArgBeforeReceiver
+	default:
+		return sortDeferDecision
+	}
+}
+
 // AscIfName is a sorting function to sort IfAddrs by their interface names.
 func AscIfName(p1Ptr, p2Ptr *IfAddr) int {
 	return strings.Compare(p1Ptr.Name, p2Ptr.Name)
@@ -127,6 +171,11 @@
 	return -1 * AscAddress(&p1Ptr.SockAddr, &p2Ptr.SockAddr)
 }
 
+// DescIfDefault is identical to AscIfDefault but reverse ordered.
+func DescIfDefault(p1Ptr, p2Ptr *IfAddr) int {
+	return -1 * AscIfDefault(p1Ptr, p2Ptr)
+}
+
 // DescIfName is identical to AscIfName but reverse ordered.
 func DescIfName(p1Ptr, p2Ptr *IfAddr) int {
 	return -1 * strings.Compare(p1Ptr.Name, p2Ptr.Name)
@@ -169,7 +218,15 @@
 
 // IfAttr forwards the selector to IfAttr.Attr() for resolution.  If there is
 // more than one IfAddr, only the first IfAddr is used.
-func IfAttr(selectorName string, ifAddrs IfAddrs) (string, error) {
+func IfAttr(selectorName string, ifAddr IfAddr) (string, error) {
+	attrName := AttrName(strings.ToLower(selectorName))
+	attrVal, err := ifAddr.Attr(attrName)
+	return attrVal, err
+}
+
+// IfAttrs forwards the selector to IfAttrs.Attr() for resolution.  If there is
+// more than one IfAddr, only the first IfAddr is used.
+func IfAttrs(selectorName string, ifAddrs IfAddrs) (string, error) {
 	if len(ifAddrs) == 0 {
 		return "", nil
 	}
@@ -243,10 +300,10 @@
 // the `eval` equivalent of:
 //
 // ```
-// $ sockaddr eval -r '{{GetDefaultInterfaces | include "type" "ip" | include "flags" "forwardable|up" | sort "type,size" | include "RFC" "6890" }}'
+// $ sockaddr eval -r '{{GetAllInterfaces | include "type" "ip" | include "flags" "forwardable" | include "flags" "up" | sort "default,type,size" | include "RFC" "6890" }}'
 /// ```
 func GetPrivateInterfaces() (IfAddrs, error) {
-	privateIfs, err := GetDefaultInterfaces()
+	privateIfs, err := GetAllInterfaces()
 	if err != nil {
 		return IfAddrs{}, err
 	}
@@ -259,15 +316,21 @@
 		return IfAddrs{}, nil
 	}
 
-	privateIfs, _, err = IfByFlag("forwardable|up", privateIfs)
+	privateIfs, _, err = IfByFlag("forwardable", privateIfs)
 	if err != nil {
 		return IfAddrs{}, err
 	}
+
+	privateIfs, _, err = IfByFlag("up", privateIfs)
+	if err != nil {
+		return IfAddrs{}, err
+	}
+
 	if len(privateIfs) == 0 {
 		return IfAddrs{}, nil
 	}
 
-	OrderedIfAddrBy(AscIfType, AscIfNetworkSize).Sort(privateIfs)
+	OrderedIfAddrBy(AscIfDefault, AscIfType, AscIfNetworkSize).Sort(privateIfs)
 
 	privateIfs, _, err = IfByRFC("6890", privateIfs)
 	if err != nil {
@@ -285,10 +348,10 @@
 // function is the `eval` equivalent of:
 //
 // ```
-// $ sockaddr eval -r '{{GetDefaultInterfaces | include "type" "ip" | include "flags" "forwardable|up" | sort "type,size" | exclude "RFC" "6890" }}'
+// $ sockaddr eval -r '{{GetAllInterfaces | include "type" "ip" | include "flags" "forwardable" | include "flags" "up" | sort "default,type,size" | exclude "RFC" "6890" }}'
 /// ```
 func GetPublicInterfaces() (IfAddrs, error) {
-	publicIfs, err := GetDefaultInterfaces()
+	publicIfs, err := GetAllInterfaces()
 	if err != nil {
 		return IfAddrs{}, err
 	}
@@ -301,15 +364,21 @@
 		return IfAddrs{}, nil
 	}
 
-	publicIfs, _, err = IfByFlag("forwardable|up", publicIfs)
+	publicIfs, _, err = IfByFlag("forwardable", publicIfs)
 	if err != nil {
 		return IfAddrs{}, err
 	}
+
+	publicIfs, _, err = IfByFlag("up", publicIfs)
+	if err != nil {
+		return IfAddrs{}, err
+	}
+
 	if len(publicIfs) == 0 {
 		return IfAddrs{}, nil
 	}
 
-	OrderedIfAddrBy(AscIfType, AscIfNetworkSize).Sort(publicIfs)
+	OrderedIfAddrBy(AscIfDefault, AscIfType, AscIfNetworkSize).Sort(publicIfs)
 
 	_, publicIfs, err = IfByRFC("6890", publicIfs)
 	if err != nil {
@@ -652,6 +721,245 @@
 	return includedIfs, excludedIfs, nil
 }
 
+// IfAddrMath will return a new IfAddr struct with a mutated value.
+func IfAddrMath(operation, value string, inputIfAddr IfAddr) (IfAddr, error) {
+	// Regexp used to enforce the sign being a required part of the grammar for
+	// some values.
+	signRe := signRE.Copy()
+
+	switch strings.ToLower(operation) {
+	case "address":
+		// "address" operates on the IP address and is allowed to overflow or
+		// underflow networks, however it will wrap along the underlying address's
+		// underlying type.
+
+		if !signRe.MatchString(value) {
+			return IfAddr{}, fmt.Errorf("sign (+/-) is required for operation %q", operation)
+		}
+
+		switch sockType := inputIfAddr.SockAddr.Type(); sockType {
+		case TypeIPv4:
+			// 33 == Accept any uint32 value
+			// TODO(seanc@): Add the ability to parse hex
+			i, err := strconv.ParseInt(value, 10, 33)
+			if err != nil {
+				return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err)
+			}
+
+			ipv4 := *ToIPv4Addr(inputIfAddr.SockAddr)
+			ipv4Uint32 := uint32(ipv4.Address)
+			ipv4Uint32 += uint32(i)
+			return IfAddr{
+				SockAddr: IPv4Addr{
+					Address: IPv4Address(ipv4Uint32),
+					Mask:    ipv4.Mask,
+				},
+				Interface: inputIfAddr.Interface,
+			}, nil
+		case TypeIPv6:
+			// 64 == Accept any int32 value
+			// TODO(seanc@): Add the ability to parse hex.  Also parse a bignum int.
+			i, err := strconv.ParseInt(value, 10, 64)
+			if err != nil {
+				return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err)
+			}
+
+			ipv6 := *ToIPv6Addr(inputIfAddr.SockAddr)
+			ipv6BigIntA := new(big.Int)
+			ipv6BigIntA.Set(ipv6.Address)
+			ipv6BigIntB := big.NewInt(i)
+
+			ipv6Addr := ipv6BigIntA.Add(ipv6BigIntA, ipv6BigIntB)
+			ipv6Addr.And(ipv6Addr, ipv6HostMask)
+
+			return IfAddr{
+				SockAddr: IPv6Addr{
+					Address: IPv6Address(ipv6Addr),
+					Mask:    ipv6.Mask,
+				},
+				Interface: inputIfAddr.Interface,
+			}, nil
+		default:
+			return IfAddr{}, fmt.Errorf("unsupported type for operation %q: %T", operation, sockType)
+		}
+	case "network":
+		// "network" operates on the network address.  Positive values start at the
+		// network address and negative values wrap at the network address, which
+		// means a "-1" value on a network will be the broadcast address after
+		// wrapping is applied.
+
+		if !signRe.MatchString(value) {
+			return IfAddr{}, fmt.Errorf("sign (+/-) is required for operation %q", operation)
+		}
+
+		switch sockType := inputIfAddr.SockAddr.Type(); sockType {
+		case TypeIPv4:
+			// 33 == Accept any uint32 value
+			// TODO(seanc@): Add the ability to parse hex
+			i, err := strconv.ParseInt(value, 10, 33)
+			if err != nil {
+				return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err)
+			}
+
+			ipv4 := *ToIPv4Addr(inputIfAddr.SockAddr)
+			ipv4Uint32 := uint32(ipv4.NetworkAddress())
+
+			// Wrap along network mask boundaries.  EZ-mode wrapping made possible by
+			// use of int64 vs a uint.
+			var wrappedMask int64
+			if i >= 0 {
+				wrappedMask = i
+			} else {
+				wrappedMask = 1 + i + int64(^uint32(ipv4.Mask))
+			}
+
+			ipv4Uint32 = ipv4Uint32 + (uint32(wrappedMask) &^ uint32(ipv4.Mask))
+
+			return IfAddr{
+				SockAddr: IPv4Addr{
+					Address: IPv4Address(ipv4Uint32),
+					Mask:    ipv4.Mask,
+				},
+				Interface: inputIfAddr.Interface,
+			}, nil
+		case TypeIPv6:
+			// 64 == Accept any int32 value
+			// TODO(seanc@): Add the ability to parse hex.  Also parse a bignum int.
+			i, err := strconv.ParseInt(value, 10, 64)
+			if err != nil {
+				return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err)
+			}
+
+			ipv6 := *ToIPv6Addr(inputIfAddr.SockAddr)
+			ipv6BigInt := new(big.Int)
+			ipv6BigInt.Set(ipv6.NetworkAddress())
+
+			mask := new(big.Int)
+			mask.Set(ipv6.Mask)
+			if i > 0 {
+				wrappedMask := new(big.Int)
+				wrappedMask.SetInt64(i)
+
+				wrappedMask.AndNot(wrappedMask, mask)
+				ipv6BigInt.Add(ipv6BigInt, wrappedMask)
+			} else {
+				// Mask off any bits that exceed the network size.  Subtract the
+				// wrappedMask from the last usable - 1
+				wrappedMask := new(big.Int)
+				wrappedMask.SetInt64(-1 * i)
+				wrappedMask.Sub(wrappedMask, big.NewInt(1))
+
+				wrappedMask.AndNot(wrappedMask, mask)
+
+				lastUsable := new(big.Int)
+				lastUsable.Set(ipv6.LastUsable().(IPv6Addr).Address)
+
+				ipv6BigInt = lastUsable.Sub(lastUsable, wrappedMask)
+			}
+
+			return IfAddr{
+				SockAddr: IPv6Addr{
+					Address: IPv6Address(ipv6BigInt),
+					Mask:    ipv6.Mask,
+				},
+				Interface: inputIfAddr.Interface,
+			}, nil
+		default:
+			return IfAddr{}, fmt.Errorf("unsupported type for operation %q: %T", operation, sockType)
+		}
+	case "mask":
+		// "mask" operates on the IP address and returns the IP address on
+		// which the given integer mask has been applied. If the applied mask
+		// corresponds to a larger network than the mask of the IP address,
+		// the latter will be replaced by the former.
+		switch sockType := inputIfAddr.SockAddr.Type(); sockType {
+		case TypeIPv4:
+			i, err := strconv.ParseUint(value, 10, 32)
+			if err != nil {
+				return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err)
+			}
+
+			if i > 32 {
+				return IfAddr{}, fmt.Errorf("parameter for operation %q on ipv4 addresses must be between 0 and 32", operation)
+			}
+
+			ipv4 := *ToIPv4Addr(inputIfAddr.SockAddr)
+
+			ipv4Mask := net.CIDRMask(int(i), 32)
+			ipv4MaskUint32 := binary.BigEndian.Uint32(ipv4Mask)
+
+			maskedIpv4 := ipv4.NetIP().Mask(ipv4Mask)
+			maskedIpv4Uint32 := binary.BigEndian.Uint32(maskedIpv4)
+
+			maskedIpv4MaskUint32 := uint32(ipv4.Mask)
+
+			if ipv4MaskUint32 < maskedIpv4MaskUint32 {
+				maskedIpv4MaskUint32 = ipv4MaskUint32
+			}
+
+			return IfAddr{
+				SockAddr: IPv4Addr{
+					Address: IPv4Address(maskedIpv4Uint32),
+					Mask:    IPv4Mask(maskedIpv4MaskUint32),
+				},
+				Interface: inputIfAddr.Interface,
+			}, nil
+		case TypeIPv6:
+			i, err := strconv.ParseUint(value, 10, 32)
+			if err != nil {
+				return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err)
+			}
+
+			if i > 128 {
+				return IfAddr{}, fmt.Errorf("parameter for operation %q on ipv6 addresses must be between 0 and 64", operation)
+			}
+
+			ipv6 := *ToIPv6Addr(inputIfAddr.SockAddr)
+
+			ipv6Mask := net.CIDRMask(int(i), 128)
+			ipv6MaskBigInt := new(big.Int)
+			ipv6MaskBigInt.SetBytes(ipv6Mask)
+
+			maskedIpv6 := ipv6.NetIP().Mask(ipv6Mask)
+			maskedIpv6BigInt := new(big.Int)
+			maskedIpv6BigInt.SetBytes(maskedIpv6)
+
+			maskedIpv6MaskBigInt := new(big.Int)
+			maskedIpv6MaskBigInt.Set(ipv6.Mask)
+
+			if ipv6MaskBigInt.Cmp(maskedIpv6MaskBigInt) == -1 {
+				maskedIpv6MaskBigInt = ipv6MaskBigInt
+			}
+
+			return IfAddr{
+				SockAddr: IPv6Addr{
+					Address: IPv6Address(maskedIpv6BigInt),
+					Mask:    IPv6Mask(maskedIpv6MaskBigInt),
+				},
+				Interface: inputIfAddr.Interface,
+			}, nil
+		default:
+			return IfAddr{}, fmt.Errorf("unsupported type for operation %q: %T", operation, sockType)
+		}
+	default:
+		return IfAddr{}, fmt.Errorf("unsupported math operation: %q", operation)
+	}
+}
+
+// IfAddrsMath will apply an IfAddrMath operation each IfAddr struct.  Any
+// failure will result in zero results.
+func IfAddrsMath(operation, value string, inputIfAddrs IfAddrs) (IfAddrs, error) {
+	outputAddrs := make(IfAddrs, 0, len(inputIfAddrs))
+	for _, ifAddr := range inputIfAddrs {
+		result, err := IfAddrMath(operation, value, ifAddr)
+		if err != nil {
+			return IfAddrs{}, fmt.Errorf("unable to perform an IPMath operation on %s: %v", ifAddr, err)
+		}
+		outputAddrs = append(outputAddrs, result)
+	}
+	return outputAddrs, nil
+}
+
 // IncludeIfs returns an IfAddrs based on the passed in selector.
 func IncludeIfs(selectorName, selectorParam string, inputIfAddrs IfAddrs) (IfAddrs, error) {
 	var includedIfs IfAddrs
@@ -736,6 +1044,10 @@
 			sortFuncs[i] = AscIfAddress
 		case "-address":
 			sortFuncs[i] = DescIfAddress
+		case "+default", "default":
+			sortFuncs[i] = AscIfDefault
+		case "-default":
+			sortFuncs[i] = DescIfDefault
 		case "+name", "name":
 			// The "name" selector returns an array of IfAddrs
 			// ordered by the interface name.
@@ -886,7 +1198,7 @@
 // Linux.
 func parseDefaultIfNameFromIPCmd(routeOut string) (string, error) {
 	lines := strings.Split(routeOut, "\n")
-	re := regexp.MustCompile(`[\s]+`)
+	re := whitespaceRE.Copy()
 	for _, line := range lines {
 		kvs := re.Split(line, -1)
 		if len(kvs) < 5 {
@@ -929,7 +1241,7 @@
 // support added.
 func parseDefaultIPAddrWindowsRoute(routeOut string) (string, error) {
 	lines := strings.Split(routeOut, "\n")
-	re := regexp.MustCompile(`[\s]+`)
+	re := whitespaceRE.Copy()
 	for _, line := range lines {
 		kvs := re.Split(strings.TrimSpace(line), -1)
 		if len(kvs) < 3 {
@@ -949,17 +1261,17 @@
 // interface name forwarding traffic to the default gateway.
 func parseDefaultIfNameWindowsIPConfig(defaultIPAddr, routeOut string) (string, error) {
 	lines := strings.Split(routeOut, "\n")
-	ifNameRE := regexp.MustCompile(`^Ethernet adapter ([^\s:]+):`)
-	ipAddrRE := regexp.MustCompile(`^   IPv[46] Address\. \. \. \. \. \. \. \. \. \. \. : ([^\s]+)`)
+	ifNameRe := ifNameRE.Copy()
+	ipAddrRe := ipAddrRE.Copy()
 	var ifName string
 	for _, line := range lines {
-		switch ifNameMatches := ifNameRE.FindStringSubmatch(line); {
+		switch ifNameMatches := ifNameRe.FindStringSubmatch(line); {
 		case len(ifNameMatches) > 1:
 			ifName = ifNameMatches[1]
 			continue
 		}
 
-		switch ipAddrMatches := ipAddrRE.FindStringSubmatch(line); {
+		switch ipAddrMatches := ipAddrRe.FindStringSubmatch(line); {
 		case len(ipAddrMatches) > 1 && ipAddrMatches[1] == defaultIPAddr:
 			return ifName, nil
 		}
diff --git a/vendor/github.com/hashicorp/go-sockaddr/ipv4addr.go b/vendor/github.com/hashicorp/go-sockaddr/ipv4addr.go
index 9f2616a..4d395dc 100644
--- a/vendor/github.com/hashicorp/go-sockaddr/ipv4addr.go
+++ b/vendor/github.com/hashicorp/go-sockaddr/ipv4addr.go
@@ -58,7 +58,8 @@
 	// Strip off any bogus hex-encoded netmasks that will be mis-parsed by Go.  In
 	// particular, clients with the Barracuda VPN client will see something like:
 	// `192.168.3.51/00ffffff` as their IP address.
-	if match := trailingHexNetmaskRE.FindStringIndex(ipv4Str); match != nil {
+	trailingHexNetmaskRe := trailingHexNetmaskRE.Copy()
+	if match := trailingHexNetmaskRe.FindStringIndex(ipv4Str); match != nil {
 		ipv4Str = ipv4Str[:match[0]]
 	}
 
diff --git a/vendor/github.com/hashicorp/go-sockaddr/rfc.go b/vendor/github.com/hashicorp/go-sockaddr/rfc.go
index fd9be94..02e188f 100644
--- a/vendor/github.com/hashicorp/go-sockaddr/rfc.go
+++ b/vendor/github.com/hashicorp/go-sockaddr/rfc.go
@@ -3,6 +3,7 @@
 // ForwardingBlacklist is a faux RFC that includes a list of non-forwardable IP
 // blocks.
 const ForwardingBlacklist = 4294967295
+const ForwardingBlacklistRFC = "4294967295"
 
 // IsRFC tests to see if an SockAddr matches the specified RFC
 func IsRFC(rfcNum uint, sa SockAddr) bool {
diff --git a/vendor/github.com/hashicorp/go-sockaddr/route_info_linux.go b/vendor/github.com/hashicorp/go-sockaddr/route_info_linux.go
index b33e4c0..c2ec91e 100644
--- a/vendor/github.com/hashicorp/go-sockaddr/route_info_linux.go
+++ b/vendor/github.com/hashicorp/go-sockaddr/route_info_linux.go
@@ -5,10 +5,6 @@
 	"os/exec"
 )
 
-var cmds map[string][]string = map[string][]string{
-	"ip": {"/sbin/ip", "route"},
-}
-
 type routeInfo struct {
 	cmds map[string][]string
 }
@@ -16,15 +12,22 @@
 // NewRouteInfo returns a Linux-specific implementation of the RouteInfo
 // interface.
 func NewRouteInfo() (routeInfo, error) {
+	// CoreOS Container Linux moved ip to /usr/bin/ip, so look it up on
+	// $PATH and fallback to /sbin/ip on error.
+	path, _ := exec.LookPath("ip")
+	if path == "" {
+		path = "/sbin/ip"
+	}
+
 	return routeInfo{
-		cmds: cmds,
+		cmds: map[string][]string{"ip": {path, "route"}},
 	}, nil
 }
 
 // GetDefaultInterfaceName returns the interface name attached to the default
 // route on the default interface.
 func (ri routeInfo) GetDefaultInterfaceName() (string, error) {
-	out, err := exec.Command(cmds["ip"][0], cmds["ip"][1:]...).Output()
+	out, err := exec.Command(ri.cmds["ip"][0], ri.cmds["ip"][1:]...).Output()
 	if err != nil {
 		return "", err
 	}
diff --git a/vendor/github.com/hashicorp/go-sockaddr/sockaddr.go b/vendor/github.com/hashicorp/go-sockaddr/sockaddr.go
index 51389eb..826c91c 100644
--- a/vendor/github.com/hashicorp/go-sockaddr/sockaddr.go
+++ b/vendor/github.com/hashicorp/go-sockaddr/sockaddr.go
@@ -1,6 +1,7 @@
 package sockaddr
 
 import (
+	"encoding/json"
 	"fmt"
 	"strings"
 )
@@ -176,3 +177,30 @@
 func SockAddrAttrs() []AttrName {
 	return sockAddrAttrs
 }
+
+// Although this is pretty trivial to do in a program, having the logic here is
+// useful all around. Note that this marshals into a *string* -- the underlying
+// string representation of the sockaddr. If you then unmarshal into this type
+// in Go, all will work as expected, but externally you can take what comes out
+// and use the string value directly.
+type SockAddrMarshaler struct {
+	SockAddr
+}
+
+func (s *SockAddrMarshaler) MarshalJSON() ([]byte, error) {
+	return json.Marshal(s.SockAddr.String())
+}
+
+func (s *SockAddrMarshaler) UnmarshalJSON(in []byte) error {
+	var str string
+	err := json.Unmarshal(in, &str)
+	if err != nil {
+		return err
+	}
+	sa, err := NewSockAddr(str)
+	if err != nil {
+		return err
+	}
+	s.SockAddr = sa
+	return nil
+}
diff --git a/vendor/github.com/moby/buildkit/README.md b/vendor/github.com/moby/buildkit/README.md
index ba8525c..5679476 100644
--- a/vendor/github.com/moby/buildkit/README.md
+++ b/vendor/github.com/moby/buildkit/README.md
@@ -138,11 +138,11 @@
 
 ##### Building a Dockerfile using [external frontend](https://hub.docker.com/r/tonistiigi/dockerfile/tags/):
 
-During development, an external version of the Dockerfile frontend is pushed to https://hub.docker.com/r/tonistiigi/dockerfile that can be used with the gateway frontend. The source for the external frontend is currently located in `./frontend/dockerfile/cmd/dockerfile-frontend` but will move out of this repository in the future ([#163](https://github.com/moby/buildkit/issues/163)).
+During development, an external version of the Dockerfile frontend is pushed to https://hub.docker.com/r/tonistiigi/dockerfile that can be used with the gateway frontend. The source for the external frontend is currently located in `./frontend/dockerfile/cmd/dockerfile-frontend` but will move out of this repository in the future ([#163](https://github.com/moby/buildkit/issues/163)). For automatic build from master branch of this repository `tonistiigi/dockerfile:master` image can be used.
 
 ```
-buildctl build --frontend=gateway.v0 --frontend-opt=source=tonistiigi/dockerfile:v0 --local context=. --local dockerfile=.
-buildctl build --frontend gateway.v0 --frontend-opt=source=tonistiigi/dockerfile:v0 --frontend-opt=context=git://github.com/moby/moby --frontend-opt build-arg:APT_MIRROR=cdn-fastly.deb.debian.org
+buildctl build --frontend=gateway.v0 --frontend-opt=source=tonistiigi/dockerfile --local context=. --local dockerfile=.
+buildctl build --frontend gateway.v0 --frontend-opt=source=tonistiigi/dockerfile --frontend-opt=context=git://github.com/moby/moby --frontend-opt build-arg:APT_MIRROR=cdn-fastly.deb.debian.org
 ````
 
 ### Exporters
diff --git a/vendor/github.com/moby/buildkit/cache/remotecache/export.go b/vendor/github.com/moby/buildkit/cache/remotecache/export.go
index 40a3675..0536ba2 100644
--- a/vendor/github.com/moby/buildkit/cache/remotecache/export.go
+++ b/vendor/github.com/moby/buildkit/cache/remotecache/export.go
@@ -9,7 +9,6 @@
 
 	"github.com/containerd/containerd/content"
 	"github.com/containerd/containerd/images"
-	"github.com/docker/distribution/manifest"
 	v1 "github.com/moby/buildkit/cache/remotecache/v1"
 	"github.com/moby/buildkit/session"
 	"github.com/moby/buildkit/solver"
@@ -17,6 +16,7 @@
 	"github.com/moby/buildkit/util/progress"
 	"github.com/moby/buildkit/util/push"
 	digest "github.com/opencontainers/go-digest"
+	specs "github.com/opencontainers/image-spec/specs-go"
 	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
 	"github.com/pkg/errors"
 )
@@ -46,7 +46,9 @@
 
 	// own type because oci type can't be pushed and docker type doesn't have annotations
 	type manifestList struct {
-		manifest.Versioned
+		specs.Versioned
+
+		MediaType string `json:"mediaType,omitempty"`
 
 		// Manifests references platform specific manifests.
 		Manifests []ocispec.Descriptor `json:"manifests"`
diff --git a/vendor/github.com/moby/buildkit/executor/oci/user.go b/vendor/github.com/moby/buildkit/executor/oci/user.go
index ce755f1..ac5dbeb 100644
--- a/vendor/github.com/moby/buildkit/executor/oci/user.go
+++ b/vendor/github.com/moby/buildkit/executor/oci/user.go
@@ -2,27 +2,31 @@
 
 import (
 	"context"
+	"errors"
 	"os"
 	"strconv"
 	"strings"
 
+	"github.com/containerd/containerd/containers"
+	containerdoci "github.com/containerd/containerd/oci"
 	"github.com/containerd/continuity/fs"
 	"github.com/opencontainers/runc/libcontainer/user"
+	"github.com/opencontainers/runtime-spec/specs-go"
 )
 
-func GetUser(ctx context.Context, root, username string) (uint32, uint32, error) {
+func GetUser(ctx context.Context, root, username string) (uint32, uint32, []uint32, error) {
 	// fast path from uid/gid
-	if uid, gid, err := ParseUser(username); err == nil {
-		return uid, gid, nil
+	if uid, gid, err := ParseUIDGID(username); err == nil {
+		return uid, gid, nil, nil
 	}
 
 	passwdPath, err := user.GetPasswdPath()
 	if err != nil {
-		return 0, 0, err
+		return 0, 0, nil, err
 	}
 	groupPath, err := user.GetGroupPath()
 	if err != nil {
-		return 0, 0, err
+		return 0, 0, nil, err
 	}
 	passwdFile, err := openUserFile(root, passwdPath)
 	if err == nil {
@@ -35,33 +39,29 @@
 
 	execUser, err := user.GetExecUser(username, nil, passwdFile, groupFile)
 	if err != nil {
-		return 0, 0, err
+		return 0, 0, nil, err
 	}
-
-	return uint32(execUser.Uid), uint32(execUser.Gid), nil
+	var sgids []uint32
+	for _, g := range execUser.Sgids {
+		sgids = append(sgids, uint32(g))
+	}
+	return uint32(execUser.Uid), uint32(execUser.Gid), sgids, nil
 }
 
-func ParseUser(str string) (uid uint32, gid uint32, err error) {
+// ParseUIDGID takes the fast path to parse UID and GID if and only if they are both provided
+func ParseUIDGID(str string) (uid uint32, gid uint32, err error) {
 	if str == "" {
 		return 0, 0, nil
 	}
 	parts := strings.SplitN(str, ":", 2)
-	for i, v := range parts {
-		switch i {
-		case 0:
-			uid, err = parseUID(v)
-			if err != nil {
-				return 0, 0, err
-			}
-			if len(parts) == 1 {
-				gid = uid
-			}
-		case 1:
-			gid, err = parseUID(v)
-			if err != nil {
-				return 0, 0, err
-			}
-		}
+	if len(parts) == 1 {
+		return 0, 0, errors.New("groups ID is not provided")
+	}
+	if uid, err = parseUID(parts[0]); err != nil {
+		return 0, 0, err
+	}
+	if gid, err = parseUID(parts[1]); err != nil {
+		return 0, 0, err
 	}
 	return
 }
@@ -84,3 +84,24 @@
 	}
 	return uint32(uid), nil
 }
+
+// WithUIDGID allows the UID and GID for the Process to be set
+// FIXME: This is a temporeray fix for the missing supplementary GIDs from containerd
+// once the PR in containerd is merged we should remove this function.
+func WithUIDGID(uid, gid uint32, sgids []uint32) containerdoci.SpecOpts {
+	return func(_ context.Context, _ containerdoci.Client, _ *containers.Container, s *containerdoci.Spec) error {
+		setProcess(s)
+		s.Process.User.UID = uid
+		s.Process.User.GID = gid
+		s.Process.User.AdditionalGids = sgids
+		return nil
+	}
+}
+
+// setProcess sets Process to empty if unset
+// FIXME: Same on this one. Need to be removed after containerd fix merged
+func setProcess(s *containerdoci.Spec) {
+	if s.Process == nil {
+		s.Process = &specs.Process{}
+	}
+}
diff --git a/vendor/github.com/moby/buildkit/executor/runcexecutor/executor.go b/vendor/github.com/moby/buildkit/executor/runcexecutor/executor.go
index edffb5b..97eb343 100644
--- a/vendor/github.com/moby/buildkit/executor/runcexecutor/executor.go
+++ b/vendor/github.com/moby/buildkit/executor/runcexecutor/executor.go
@@ -133,7 +133,7 @@
 	}
 	defer mount.Unmount(rootFSPath, 0)
 
-	uid, gid, err := oci.GetUser(ctx, rootFSPath, meta.User)
+	uid, gid, sgids, err := oci.GetUser(ctx, rootFSPath, meta.User)
 	if err != nil {
 		return err
 	}
@@ -143,7 +143,7 @@
 		return err
 	}
 	defer f.Close()
-	opts := []containerdoci.SpecOpts{containerdoci.WithUIDGID(uid, gid)}
+	opts := []containerdoci.SpecOpts{oci.WithUIDGID(uid, gid, sgids)}
 	if system.SeccompSupported() {
 		opts = append(opts, seccomp.WithDefaultProfile())
 	}
@@ -170,9 +170,7 @@
 	}
 
 	if w.rootless {
-		specconv.ToRootless(spec, &specconv.RootlessOpts{
-			MapSubUIDGID: true,
-		})
+		specconv.ToRootless(spec, nil)
 		// TODO(AkihiroSuda): keep Cgroups enabled if /sys/fs/cgroup/cpuset/buildkit exists and writable
 		spec.Linux.CgroupsPath = ""
 		// TODO(AkihiroSuda): ToRootless removes netns, but we should readd netns here
diff --git a/vendor/github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb/convert.go b/vendor/github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb/convert.go
index 00e92b3..ac70fb8 100644
--- a/vendor/github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb/convert.go
+++ b/vendor/github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb/convert.go
@@ -91,8 +91,7 @@
 		metaResolver = imagemetaresolver.Default()
 	}
 
-	var allDispatchStates []*dispatchState
-	dispatchStatesByName := map[string]*dispatchState{}
+	allDispatchStates := newDispatchStates()
 
 	// set base state for every image
 	for _, st := range stages {
@@ -100,6 +99,9 @@
 		if err != nil {
 			return nil, nil, err
 		}
+		if name == "" {
+			return nil, nil, errors.Errorf("base name (%s) should not be blank", st.BaseName)
+		}
 		st.BaseName = name
 
 		ds := &dispatchState{
@@ -121,13 +123,7 @@
 			ds.platform = &p
 		}
 
-		if d, ok := dispatchStatesByName[st.BaseName]; ok {
-			ds.base = d
-		}
-		allDispatchStates = append(allDispatchStates, ds)
-		if st.Name != "" {
-			dispatchStatesByName[strings.ToLower(st.Name)] = ds
-		}
+		allDispatchStates.addState(ds)
 		if opt.IgnoreCache != nil {
 			if len(opt.IgnoreCache) == 0 {
 				ds.ignoreCache = true
@@ -143,20 +139,20 @@
 
 	var target *dispatchState
 	if opt.Target == "" {
-		target = allDispatchStates[len(allDispatchStates)-1]
+		target = allDispatchStates.lastTarget()
 	} else {
 		var ok bool
-		target, ok = dispatchStatesByName[strings.ToLower(opt.Target)]
+		target, ok = allDispatchStates.findStateByName(opt.Target)
 		if !ok {
 			return nil, nil, errors.Errorf("target stage %s could not be found", opt.Target)
 		}
 	}
 
 	// fill dependencies to stages so unreachable ones can avoid loading image configs
-	for _, d := range allDispatchStates {
+	for _, d := range allDispatchStates.states {
 		d.commands = make([]command, len(d.stage.Commands))
 		for i, cmd := range d.stage.Commands {
-			newCmd, err := toCommand(cmd, dispatchStatesByName, allDispatchStates)
+			newCmd, err := toCommand(cmd, allDispatchStates)
 			if err != nil {
 				return nil, nil, err
 			}
@@ -165,7 +161,7 @@
 				if src != nil {
 					d.deps[src] = struct{}{}
 					if src.unregistered {
-						allDispatchStates = append(allDispatchStates, src)
+						allDispatchStates.addState(src)
 					}
 				}
 			}
@@ -173,7 +169,7 @@
 	}
 
 	eg, ctx := errgroup.WithContext(ctx)
-	for i, d := range allDispatchStates {
+	for i, d := range allDispatchStates.states {
 		reachable := isReachable(target, d)
 		// resolve image config for every stage
 		if d.base == nil {
@@ -239,7 +235,7 @@
 	buildContext := &mutableOutput{}
 	ctxPaths := map[string]struct{}{}
 
-	for _, d := range allDispatchStates {
+	for _, d := range allDispatchStates.states {
 		if !isReachable(target, d) {
 			continue
 		}
@@ -271,17 +267,16 @@
 		}
 
 		opt := dispatchOpt{
-			allDispatchStates:    allDispatchStates,
-			dispatchStatesByName: dispatchStatesByName,
-			metaArgs:             metaArgs,
-			buildArgValues:       opt.BuildArgs,
-			shlex:                shlex,
-			sessionID:            opt.SessionID,
-			buildContext:         llb.NewState(buildContext),
-			proxyEnv:             proxyEnv,
-			cacheIDNamespace:     opt.CacheIDNamespace,
-			buildPlatforms:       opt.BuildPlatforms,
-			targetPlatform:       *opt.TargetPlatform,
+			allDispatchStates: allDispatchStates,
+			metaArgs:          metaArgs,
+			buildArgValues:    opt.BuildArgs,
+			shlex:             shlex,
+			sessionID:         opt.SessionID,
+			buildContext:      llb.NewState(buildContext),
+			proxyEnv:          proxyEnv,
+			cacheIDNamespace:  opt.CacheIDNamespace,
+			buildPlatforms:    opt.BuildPlatforms,
+			targetPlatform:    *opt.TargetPlatform,
 		}
 
 		if err = dispatchOnBuild(d, d.image.Config.OnBuild, opt); err != nil {
@@ -330,14 +325,14 @@
 	return &st, &target.image, nil
 }
 
-func toCommand(ic instructions.Command, dispatchStatesByName map[string]*dispatchState, allDispatchStates []*dispatchState) (command, error) {
+func toCommand(ic instructions.Command, allDispatchStates *dispatchStates) (command, error) {
 	cmd := command{Command: ic}
 	if c, ok := ic.(*instructions.CopyCommand); ok {
 		if c.From != "" {
 			var stn *dispatchState
 			index, err := strconv.Atoi(c.From)
 			if err != nil {
-				stn, ok = dispatchStatesByName[strings.ToLower(c.From)]
+				stn, ok = allDispatchStates.findStateByName(c.From)
 				if !ok {
 					stn = &dispatchState{
 						stage:        instructions.Stage{BaseName: c.From},
@@ -346,16 +341,16 @@
 					}
 				}
 			} else {
-				if index < 0 || index >= len(allDispatchStates) {
-					return command{}, errors.Errorf("invalid stage index %d", index)
+				stn, err = allDispatchStates.findStateByIndex(index)
+				if err != nil {
+					return command{}, err
 				}
-				stn = allDispatchStates[index]
 			}
 			cmd.sources = []*dispatchState{stn}
 		}
 	}
 
-	if ok := detectRunMount(&cmd, dispatchStatesByName, allDispatchStates); ok {
+	if ok := detectRunMount(&cmd, allDispatchStates); ok {
 		return cmd, nil
 	}
 
@@ -363,17 +358,16 @@
 }
 
 type dispatchOpt struct {
-	allDispatchStates    []*dispatchState
-	dispatchStatesByName map[string]*dispatchState
-	metaArgs             []instructions.ArgCommand
-	buildArgValues       map[string]string
-	shlex                *shell.Lex
-	sessionID            string
-	buildContext         llb.State
-	proxyEnv             *llb.ProxyEnv
-	cacheIDNamespace     string
-	targetPlatform       specs.Platform
-	buildPlatforms       []specs.Platform
+	allDispatchStates *dispatchStates
+	metaArgs          []instructions.ArgCommand
+	buildArgValues    map[string]string
+	shlex             *shell.Lex
+	sessionID         string
+	buildContext      llb.State
+	proxyEnv          *llb.ProxyEnv
+	cacheIDNamespace  string
+	targetPlatform    specs.Platform
+	buildPlatforms    []specs.Platform
 }
 
 func dispatch(d *dispatchState, cmd command, opt dispatchOpt) error {
@@ -456,6 +450,43 @@
 	unregistered bool
 }
 
+type dispatchStates struct {
+	states       []*dispatchState
+	statesByName map[string]*dispatchState
+}
+
+func newDispatchStates() *dispatchStates {
+	return &dispatchStates{statesByName: map[string]*dispatchState{}}
+}
+
+func (dss *dispatchStates) addState(ds *dispatchState) {
+	dss.states = append(dss.states, ds)
+
+	if d, ok := dss.statesByName[ds.stage.BaseName]; ok {
+		ds.base = d
+	}
+	if ds.stage.Name != "" {
+		dss.statesByName[strings.ToLower(ds.stage.Name)] = ds
+	}
+}
+
+func (dss *dispatchStates) findStateByName(name string) (*dispatchState, bool) {
+	ds, ok := dss.statesByName[strings.ToLower(name)]
+	return ds, ok
+}
+
+func (dss *dispatchStates) findStateByIndex(index int) (*dispatchState, error) {
+	if index < 0 || index >= len(dss.states) {
+		return nil, errors.Errorf("invalid stage index %d", index)
+	}
+
+	return dss.states[index], nil
+}
+
+func (dss *dispatchStates) lastTarget() *dispatchState {
+	return dss.states[len(dss.states)-1]
+}
+
 type command struct {
 	instructions.Command
 	sources []*dispatchState
@@ -474,7 +505,7 @@
 		if err != nil {
 			return err
 		}
-		cmd, err := toCommand(ic, opt.dispatchStatesByName, opt.allDispatchStates)
+		cmd, err := toCommand(ic, opt.allDispatchStates)
 		if err != nil {
 			return err
 		}
@@ -570,7 +601,11 @@
 
 	for i, src := range c.Sources() {
 		commitMessage.WriteString(" " + src)
-		if isAddCommand && (strings.HasPrefix(src, "http://") || strings.HasPrefix(src, "https://")) {
+		if strings.HasPrefix(src, "http://") || strings.HasPrefix(src, "https://") {
+			if !isAddCommand {
+				return errors.New("source can't be a URL for COPY")
+			}
+
 			// Resources from remote URLs are not decompressed.
 			// https://docs.docker.com/engine/reference/builder/#add
 			//
diff --git a/vendor/github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb/convert_norunmount.go b/vendor/github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb/convert_norunmount.go
index a4544e7..d764340 100644
--- a/vendor/github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb/convert_norunmount.go
+++ b/vendor/github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb/convert_norunmount.go
@@ -7,7 +7,7 @@
 	"github.com/moby/buildkit/frontend/dockerfile/instructions"
 )
 
-func detectRunMount(cmd *command, dispatchStatesByName map[string]*dispatchState, allDispatchStates []*dispatchState) bool {
+func detectRunMount(cmd *command, allDispatchStates *dispatchStates) bool {
 	return false
 }
 
diff --git a/vendor/github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb/convert_runmount.go b/vendor/github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb/convert_runmount.go
index 61408e1..aea61b3 100644
--- a/vendor/github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb/convert_runmount.go
+++ b/vendor/github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb/convert_runmount.go
@@ -5,14 +5,13 @@
 import (
 	"path"
 	"path/filepath"
-	"strings"
 
 	"github.com/moby/buildkit/client/llb"
 	"github.com/moby/buildkit/frontend/dockerfile/instructions"
 	"github.com/pkg/errors"
 )
 
-func detectRunMount(cmd *command, dispatchStatesByName map[string]*dispatchState, allDispatchStates []*dispatchState) bool {
+func detectRunMount(cmd *command, allDispatchStates *dispatchStates) bool {
 	if c, ok := cmd.Command.(*instructions.RunCommand); ok {
 		mounts := instructions.GetMounts(c)
 		sources := make([]*dispatchState, len(mounts))
@@ -24,7 +23,7 @@
 			if from == "" || mount.Type == instructions.MountTypeTmpfs {
 				continue
 			}
-			stn, ok := dispatchStatesByName[strings.ToLower(from)]
+			stn, ok := allDispatchStates.findStateByName(from)
 			if !ok {
 				stn = &dispatchState{
 					stage:        instructions.Stage{BaseName: from},
diff --git a/vendor/github.com/moby/buildkit/frontend/dockerfile/instructions/bflag.go b/vendor/github.com/moby/buildkit/frontend/dockerfile/instructions/bflag.go
index e299d52..d8bf747 100644
--- a/vendor/github.com/moby/buildkit/frontend/dockerfile/instructions/bflag.go
+++ b/vendor/github.com/moby/buildkit/frontend/dockerfile/instructions/bflag.go
@@ -72,7 +72,7 @@
 	return flag
 }
 
-// AddString adds a string flag to BFlags that can match multiple values
+// AddStrings adds a string flag to BFlags that can match multiple values
 func (bf *BFlags) AddStrings(name string) *Flag {
 	flag := bf.addFlag(name, stringsType)
 	if flag == nil {
diff --git a/vendor/github.com/moby/buildkit/frontend/dockerfile/instructions/commands.go b/vendor/github.com/moby/buildkit/frontend/dockerfile/instructions/commands.go
index b96010f..903353e 100644
--- a/vendor/github.com/moby/buildkit/frontend/dockerfile/instructions/commands.go
+++ b/vendor/github.com/moby/buildkit/frontend/dockerfile/instructions/commands.go
@@ -159,7 +159,7 @@
 
 // AddCommand : ADD foo /path
 //
-// Add the file 'foo' to '/path'. Tarball and Remote URL (git, http) handling
+// Add the file 'foo' to '/path'. Tarball and Remote URL (http, https) handling
 // exist here. If you do not wish to have this automatic handling, use COPY.
 //
 type AddCommand struct {
diff --git a/vendor/github.com/moby/buildkit/frontend/dockerfile/shell/equal_env_unix.go b/vendor/github.com/moby/buildkit/frontend/dockerfile/shell/equal_env_unix.go
index 6e3f6b8..36903ec 100644
--- a/vendor/github.com/moby/buildkit/frontend/dockerfile/shell/equal_env_unix.go
+++ b/vendor/github.com/moby/buildkit/frontend/dockerfile/shell/equal_env_unix.go
@@ -2,8 +2,9 @@
 
 package shell
 
-// EqualEnvKeys compare two strings and returns true if they are equal. On
-// Windows this comparison is case insensitive.
+// EqualEnvKeys compare two strings and returns true if they are equal.
+// On Unix this comparison is case sensitive.
+// On Windows this comparison is case insensitive.
 func EqualEnvKeys(from, to string) bool {
 	return from == to
 }
diff --git a/vendor/github.com/moby/buildkit/frontend/dockerfile/shell/equal_env_windows.go b/vendor/github.com/moby/buildkit/frontend/dockerfile/shell/equal_env_windows.go
index 7780fb6..010569b 100644
--- a/vendor/github.com/moby/buildkit/frontend/dockerfile/shell/equal_env_windows.go
+++ b/vendor/github.com/moby/buildkit/frontend/dockerfile/shell/equal_env_windows.go
@@ -2,8 +2,9 @@
 
 import "strings"
 
-// EqualEnvKeys compare two strings and returns true if they are equal. On
-// Windows this comparison is case insensitive.
+// EqualEnvKeys compare two strings and returns true if they are equal.
+// On Unix this comparison is case sensitive.
+// On Windows this comparison is case insensitive.
 func EqualEnvKeys(from, to string) bool {
 	return strings.ToUpper(from) == strings.ToUpper(to)
 }
diff --git a/vendor/github.com/moby/buildkit/util/imageutil/config.go b/vendor/github.com/moby/buildkit/util/imageutil/config.go
index 2c2e18b..356ed53 100644
--- a/vendor/github.com/moby/buildkit/util/imageutil/config.go
+++ b/vendor/github.com/moby/buildkit/util/imageutil/config.go
@@ -141,13 +141,17 @@
 	}
 
 	var mfst struct {
-		Config json.RawMessage `json:"config"`
+		MediaType string          `json:"mediaType"`
+		Config    json.RawMessage `json:"config"`
 	}
 
 	if err := json.Unmarshal(p, &mfst); err != nil {
 		return "", err
 	}
 
+	if mfst.MediaType != "" {
+		return mfst.MediaType, nil
+	}
 	if mfst.Config != nil {
 		return images.MediaTypeDockerSchema2Manifest, nil
 	}