Loading include/containerd/api.h +3 −2 Changes for include/containerd/api.h: 3 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -138,8 +138,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * DeleteContainer {name} stopped only; its changes go too * StartContainer {name} -> state (running, or failed and error) * with network = host not (409) while a port its image exposes is * exposed by another running container with the host's network or * in use on the host (a listening TCP or bound UDP socket) * in use on the host on the wildcard address (a TCP socket listening * or a UDP socket bound to 0.0.0.0 or ::); one on a single address * leaves the port to containers binding addresses of their own * StopContainer {name, timeout? (s, default 10)} the image's * StopSignal (default SIGTERM) to the container, after timeout * everything in its cgroup is killed; replies at once (stopping) Loading src/containers.cpp +14 −23 Changes for src/containers.cpp: 14 added lines, 23 removed lines. Original line number Diff line number Diff line Loading @@ -306,7 +306,10 @@ bool exposedPort(const std::string &spec, std::string &proto, int &first, int &l } // the host's ports of a protocol something listens on (tcp) or is bound // to (udp), on any address: a bind to 0.0.0.0 fails on any of them // to (udp) on the wildcard address (0.0.0.0 or ::): those take the port on // every address, a bind to any of them fails. A socket on one address // leaves the port free on the others -- whether the container binds that // address isn't known here, its bind then fails on its own std::vector<int> hostPorts(const std::string &proto) { std::vector<int> out; for (const char *v : {"", "6"}) { Loading @@ -322,40 +325,28 @@ std::vector<int> hostPorts(const std::string &proto) { // 0A: TCP_LISTEN; 07: TCP_CLOSE, an unconnected UDP socket if (st != (proto == "tcp" ? "0A" : "07")) continue; size_t colon = local.rfind(':'); if (colon != std::string::npos) out.push_back((int)strtol(local.c_str() + colon + 1, nullptr, 16)); if (colon == std::string::npos || local.find_first_not_of('0') < colon) continue; out.push_back((int)strtol(local.c_str() + colon + 1, nullptr, 16)); } } return out; } // with the host's network a container's ports are the host's: what its // image exposes mustn't be taken by another container with the host's // network or by something on the host ("" if it is free) std::string portConflict(const std::string &name, const Settings &s, const Image &image) { // image exposes mustn't be taken on every address by something on the // host ("" if it is free). Other containers with the host's network aren't // asked: an image's exposed ports say nothing of the address, two of them // may well bind the same port on addresses of their own std::string portConflict(const Settings &s, const Image &image) { if (s.network != "host") return ""; for (auto &spec : image.ports) { std::string proto; int first, last; if (!exposedPort(spec, proto, first, last)) continue; std::string what = spec.substr(0, spec.find('/')) + "/" + proto; auto overlaps = [&](const std::string &other) { std::string p; int a, b; return exposedPort(other, p, a, b) && p == proto && a <= last && first <= b; }; for (auto &[other, r] : table()) { Settings os; Image oi; std::string err; if (other == name || !active(r) || !load(other, os, err) || os.network != "host" || !loadImage(os.image, oi)) continue; if (std::any_of(oi.ports.begin(), oi.ports.end(), overlaps)) return tr("port %1 is taken by the container %2 (both have the host's network; give one network=bridge)", "Port %1 ist vom Container %2 belegt (beide haben das Netz des Hosts; einem network=bridge geben)", {what, other}); } for (int port : hostPorts(proto)) if (port >= first && port <= last) return tr("port %1 is in use on the host (the container has the host's network; give it network=bridge)", "Port %1 ist auf dem Host belegt (der Container hat das Netz des Hosts; ihm network=bridge geben)", return tr("port %1 is in use on all of the host's addresses (the container has the host's network; give it network=bridge)", "Port %1 ist auf allen Adressen des Hosts belegt (der Container hat das Netz des Hosts; ihm network=bridge geben)", {std::to_string(port) + "/" + proto}); } return ""; Loading @@ -380,7 +371,7 @@ Result startOne(const std::string &name) { if (!isDir(layerDir(layer))) return fail(tr("a layer of %1 is missing; pull it again", "eine Schicht von %1 fehlt; bitte neu laden", {s.image}), 500); if (s.network == "bridge" && !isDir("/sys/class/net/" + s.bridge + "/bridge")) return fail(tr("there is no bridge %1", "es gibt keine Bridge %1", {s.bridge}), 409); err = portConflict(name, s, l.image); err = portConflict(s, l.image); if (!err.empty()) return fail(err, 409); // a missing bind mount source is created as a directory (a file to // mount has to exist) Loading Loading
include/containerd/api.h +3 −2 Changes for include/containerd/api.h: 3 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -138,8 +138,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * DeleteContainer {name} stopped only; its changes go too * StartContainer {name} -> state (running, or failed and error) * with network = host not (409) while a port its image exposes is * exposed by another running container with the host's network or * in use on the host (a listening TCP or bound UDP socket) * in use on the host on the wildcard address (a TCP socket listening * or a UDP socket bound to 0.0.0.0 or ::); one on a single address * leaves the port to containers binding addresses of their own * StopContainer {name, timeout? (s, default 10)} the image's * StopSignal (default SIGTERM) to the container, after timeout * everything in its cgroup is killed; replies at once (stopping) Loading
src/containers.cpp +14 −23 Changes for src/containers.cpp: 14 added lines, 23 removed lines. Original line number Diff line number Diff line Loading @@ -306,7 +306,10 @@ bool exposedPort(const std::string &spec, std::string &proto, int &first, int &l } // the host's ports of a protocol something listens on (tcp) or is bound // to (udp), on any address: a bind to 0.0.0.0 fails on any of them // to (udp) on the wildcard address (0.0.0.0 or ::): those take the port on // every address, a bind to any of them fails. A socket on one address // leaves the port free on the others -- whether the container binds that // address isn't known here, its bind then fails on its own std::vector<int> hostPorts(const std::string &proto) { std::vector<int> out; for (const char *v : {"", "6"}) { Loading @@ -322,40 +325,28 @@ std::vector<int> hostPorts(const std::string &proto) { // 0A: TCP_LISTEN; 07: TCP_CLOSE, an unconnected UDP socket if (st != (proto == "tcp" ? "0A" : "07")) continue; size_t colon = local.rfind(':'); if (colon != std::string::npos) out.push_back((int)strtol(local.c_str() + colon + 1, nullptr, 16)); if (colon == std::string::npos || local.find_first_not_of('0') < colon) continue; out.push_back((int)strtol(local.c_str() + colon + 1, nullptr, 16)); } } return out; } // with the host's network a container's ports are the host's: what its // image exposes mustn't be taken by another container with the host's // network or by something on the host ("" if it is free) std::string portConflict(const std::string &name, const Settings &s, const Image &image) { // image exposes mustn't be taken on every address by something on the // host ("" if it is free). Other containers with the host's network aren't // asked: an image's exposed ports say nothing of the address, two of them // may well bind the same port on addresses of their own std::string portConflict(const Settings &s, const Image &image) { if (s.network != "host") return ""; for (auto &spec : image.ports) { std::string proto; int first, last; if (!exposedPort(spec, proto, first, last)) continue; std::string what = spec.substr(0, spec.find('/')) + "/" + proto; auto overlaps = [&](const std::string &other) { std::string p; int a, b; return exposedPort(other, p, a, b) && p == proto && a <= last && first <= b; }; for (auto &[other, r] : table()) { Settings os; Image oi; std::string err; if (other == name || !active(r) || !load(other, os, err) || os.network != "host" || !loadImage(os.image, oi)) continue; if (std::any_of(oi.ports.begin(), oi.ports.end(), overlaps)) return tr("port %1 is taken by the container %2 (both have the host's network; give one network=bridge)", "Port %1 ist vom Container %2 belegt (beide haben das Netz des Hosts; einem network=bridge geben)", {what, other}); } for (int port : hostPorts(proto)) if (port >= first && port <= last) return tr("port %1 is in use on the host (the container has the host's network; give it network=bridge)", "Port %1 ist auf dem Host belegt (der Container hat das Netz des Hosts; ihm network=bridge geben)", return tr("port %1 is in use on all of the host's addresses (the container has the host's network; give it network=bridge)", "Port %1 ist auf allen Adressen des Hosts belegt (der Container hat das Netz des Hosts; ihm network=bridge geben)", {std::to_string(port) + "/" + proto}); } return ""; Loading @@ -380,7 +371,7 @@ Result startOne(const std::string &name) { if (!isDir(layerDir(layer))) return fail(tr("a layer of %1 is missing; pull it again", "eine Schicht von %1 fehlt; bitte neu laden", {s.image}), 500); if (s.network == "bridge" && !isDir("/sys/class/net/" + s.bridge + "/bridge")) return fail(tr("there is no bridge %1", "es gibt keine Bridge %1", {s.bridge}), 409); err = portConflict(name, s, l.image); err = portConflict(s, l.image); if (!err.empty()) return fail(err, 409); // a missing bind mount source is created as a directory (a file to // mount has to exist) Loading