mirror of
https://github.com/containers/podman
synced 2024-10-21 01:34:37 +00:00
4e2a0b5b9c
Two areas needed tweaking to accomplish this: port parsing and binding ports on the host. Parsing is an obvious problem - we have to accomodate an IPv6 address enclosed by [] as well as a normal IPv4 address. It was slightly complicated by the fact that we previously just counted the number of colons in the whole port definition (a thousand curses on whoever in the IPv6 standard body decided to reuse colons for address separators), but did not end up being that bad. Libpod also (optionally) binds ports on the host to prevent their reuse by host processes. This code was IPv4 only for TCP, and bound to both for UDP (which I'm fairly certain is not correct, and has been adjusted). This just needed protocols adjusted to read "tcp4"/"tcp6" and "udp4"/"udp6" based on what we wanted to bind to. Fixes #5715 Signed-off-by: Matthew Heon <matthew.heon@pm.me>
131 lines
3.4 KiB
Go
131 lines
3.4 KiB
Go
package libpod
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"os"
|
|
"regexp"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/containers/libpod/libpod/define"
|
|
"github.com/cri-o/ocicni/pkg/ocicni"
|
|
"github.com/pkg/errors"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
// Timeout before declaring that runtime has failed to kill a given
|
|
// container
|
|
const killContainerTimeout = 5 * time.Second
|
|
|
|
// ociError is used to parse the OCI runtime JSON log. It is not part of the
|
|
// OCI runtime specifications, it follows what runc does
|
|
type ociError struct {
|
|
Level string `json:"level,omitempty"`
|
|
Time string `json:"time,omitempty"`
|
|
Msg string `json:"msg,omitempty"`
|
|
}
|
|
|
|
// Create systemd unit name for cgroup scopes
|
|
func createUnitName(prefix string, name string) string {
|
|
return fmt.Sprintf("%s-%s.scope", prefix, name)
|
|
}
|
|
|
|
// Bind ports to keep them closed on the host
|
|
func bindPorts(ports []ocicni.PortMapping) ([]*os.File, error) {
|
|
var files []*os.File
|
|
notifySCTP := false
|
|
for _, i := range ports {
|
|
isV6 := net.ParseIP(i.HostIP).To4() == nil
|
|
if i.HostIP == "" {
|
|
isV6 = false
|
|
}
|
|
switch i.Protocol {
|
|
case "udp":
|
|
var (
|
|
addr *net.UDPAddr
|
|
err error
|
|
)
|
|
if isV6 {
|
|
addr, err = net.ResolveUDPAddr("udp6", fmt.Sprintf("[%s]:%d", i.HostIP, i.HostPort))
|
|
} else {
|
|
addr, err = net.ResolveUDPAddr("udp4", fmt.Sprintf("%s:%d", i.HostIP, i.HostPort))
|
|
}
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "cannot resolve the UDP address")
|
|
}
|
|
|
|
proto := "udp4"
|
|
if isV6 {
|
|
proto = "udp6"
|
|
}
|
|
server, err := net.ListenUDP(proto, addr)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "cannot listen on the UDP port")
|
|
}
|
|
f, err := server.File()
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "cannot get file for UDP socket")
|
|
}
|
|
files = append(files, f)
|
|
|
|
case "tcp":
|
|
var (
|
|
addr *net.TCPAddr
|
|
err error
|
|
)
|
|
if isV6 {
|
|
addr, err = net.ResolveTCPAddr("tcp6", fmt.Sprintf("[%s]:%d", i.HostIP, i.HostPort))
|
|
} else {
|
|
addr, err = net.ResolveTCPAddr("tcp4", fmt.Sprintf("%s:%d", i.HostIP, i.HostPort))
|
|
}
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "cannot resolve the TCP address")
|
|
}
|
|
|
|
proto := "tcp4"
|
|
if isV6 {
|
|
proto = "tcp6"
|
|
}
|
|
server, err := net.ListenTCP(proto, addr)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "cannot listen on the TCP port")
|
|
}
|
|
f, err := server.File()
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "cannot get file for TCP socket")
|
|
}
|
|
files = append(files, f)
|
|
case "sctp":
|
|
if !notifySCTP {
|
|
notifySCTP = true
|
|
logrus.Warnf("port reservation for SCTP is not supported")
|
|
}
|
|
default:
|
|
return nil, fmt.Errorf("unknown protocol %s", i.Protocol)
|
|
|
|
}
|
|
}
|
|
return files, nil
|
|
}
|
|
|
|
func getOCIRuntimeError(runtimeMsg string) error {
|
|
includeFullOutput := logrus.GetLevel() == logrus.DebugLevel
|
|
|
|
if match := regexp.MustCompile("(?i).*permission denied.*|.*operation not permitted.*").FindString(runtimeMsg); match != "" {
|
|
errStr := match
|
|
if includeFullOutput {
|
|
errStr = runtimeMsg
|
|
}
|
|
return errors.Wrapf(define.ErrOCIRuntimePermissionDenied, "%s", strings.Trim(errStr, "\n"))
|
|
}
|
|
if match := regexp.MustCompile("(?i).*executable file not found in.*|.*no such file or directory.*").FindString(runtimeMsg); match != "" {
|
|
errStr := match
|
|
if includeFullOutput {
|
|
errStr = runtimeMsg
|
|
}
|
|
return errors.Wrapf(define.ErrOCIRuntimeNotFound, "%s", strings.Trim(errStr, "\n"))
|
|
}
|
|
return errors.Wrapf(define.ErrOCIRuntime, "%s", strings.Trim(runtimeMsg, "\n"))
|
|
}
|