mirror of
https://github.com/containers/podman.git
synced 2025-06-19 16:33:24 +08:00
Merge pull request #13646 from Luap99/slirp4netns-portrange
fix slirp4netns port forwarding with ranges
This commit is contained in:
@ -614,60 +614,73 @@ func (r *Runtime) setupRootlessPortMappingViaSlirp(ctr *Container, cmd *exec.Cmd
|
||||
|
||||
// for each port we want to add we need to open a connection to the slirp4netns control socket
|
||||
// and send the add_hostfwd command.
|
||||
for _, i := range ctr.convertPortMappings() {
|
||||
conn, err := net.Dial("unix", apiSocket)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "cannot open connection to %s", apiSocket)
|
||||
}
|
||||
defer func() {
|
||||
if err := conn.Close(); err != nil {
|
||||
logrus.Errorf("Unable to close connection: %q", err)
|
||||
for _, port := range ctr.convertPortMappings() {
|
||||
protocols := strings.Split(port.Protocol, ",")
|
||||
for _, protocol := range protocols {
|
||||
hostIP := port.HostIP
|
||||
if hostIP == "" {
|
||||
hostIP = "0.0.0.0"
|
||||
}
|
||||
for i := uint16(0); i < port.Range; i++ {
|
||||
if err := openSlirp4netnsPort(apiSocket, protocol, hostIP, port.HostPort+i, port.ContainerPort+i); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}()
|
||||
hostIP := i.HostIP
|
||||
if hostIP == "" {
|
||||
hostIP = "0.0.0.0"
|
||||
}
|
||||
apiCmd := slirp4netnsCmd{
|
||||
Execute: "add_hostfwd",
|
||||
Args: slirp4netnsCmdArg{
|
||||
Proto: i.Protocol,
|
||||
HostAddr: hostIP,
|
||||
HostPort: i.HostPort,
|
||||
GuestPort: i.ContainerPort,
|
||||
},
|
||||
}
|
||||
// create the JSON payload and send it. Mark the end of request shutting down writes
|
||||
// to the socket, as requested by slirp4netns.
|
||||
data, err := json.Marshal(&apiCmd)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "cannot marshal JSON for slirp4netns")
|
||||
}
|
||||
if _, err := conn.Write([]byte(fmt.Sprintf("%s\n", data))); err != nil {
|
||||
return errors.Wrapf(err, "cannot write to control socket %s", apiSocket)
|
||||
}
|
||||
if err := conn.(*net.UnixConn).CloseWrite(); err != nil {
|
||||
return errors.Wrapf(err, "cannot shutdown the socket %s", apiSocket)
|
||||
}
|
||||
buf := make([]byte, 2048)
|
||||
readLength, err := conn.Read(buf)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "cannot read from control socket %s", apiSocket)
|
||||
}
|
||||
// if there is no 'error' key in the received JSON data, then the operation was
|
||||
// successful.
|
||||
var y map[string]interface{}
|
||||
if err := json.Unmarshal(buf[0:readLength], &y); err != nil {
|
||||
return errors.Wrapf(err, "error parsing error status from slirp4netns")
|
||||
}
|
||||
if e, found := y["error"]; found {
|
||||
return errors.Errorf("from slirp4netns while setting up port redirection: %v", e)
|
||||
}
|
||||
}
|
||||
logrus.Debug("slirp4netns port-forwarding setup via add_hostfwd is ready")
|
||||
return nil
|
||||
}
|
||||
|
||||
// openSlirp4netnsPort sends the slirp4netns pai quey to the given socket
|
||||
func openSlirp4netnsPort(apiSocket, proto, hostip string, hostport, guestport uint16) error {
|
||||
conn, err := net.Dial("unix", apiSocket)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "cannot open connection to %s", apiSocket)
|
||||
}
|
||||
defer func() {
|
||||
if err := conn.Close(); err != nil {
|
||||
logrus.Errorf("Unable to close slirp4netns connection: %q", err)
|
||||
}
|
||||
}()
|
||||
apiCmd := slirp4netnsCmd{
|
||||
Execute: "add_hostfwd",
|
||||
Args: slirp4netnsCmdArg{
|
||||
Proto: proto,
|
||||
HostAddr: hostip,
|
||||
HostPort: hostport,
|
||||
GuestPort: guestport,
|
||||
},
|
||||
}
|
||||
// create the JSON payload and send it. Mark the end of request shutting down writes
|
||||
// to the socket, as requested by slirp4netns.
|
||||
data, err := json.Marshal(&apiCmd)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "cannot marshal JSON for slirp4netns")
|
||||
}
|
||||
if _, err := conn.Write([]byte(fmt.Sprintf("%s\n", data))); err != nil {
|
||||
return errors.Wrapf(err, "cannot write to control socket %s", apiSocket)
|
||||
}
|
||||
if err := conn.(*net.UnixConn).CloseWrite(); err != nil {
|
||||
return errors.Wrapf(err, "cannot shutdown the socket %s", apiSocket)
|
||||
}
|
||||
buf := make([]byte, 2048)
|
||||
readLength, err := conn.Read(buf)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "cannot read from control socket %s", apiSocket)
|
||||
}
|
||||
// if there is no 'error' key in the received JSON data, then the operation was
|
||||
// successful.
|
||||
var y map[string]interface{}
|
||||
if err := json.Unmarshal(buf[0:readLength], &y); err != nil {
|
||||
return errors.Wrapf(err, "error parsing error status from slirp4netns")
|
||||
}
|
||||
if e, found := y["error"]; found {
|
||||
return errors.Errorf("from slirp4netns while setting up port redirection: %v", e)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getRootlessPortChildIP(c *Container, netStatus map[string]types.StatusBlock) string {
|
||||
if c.config.NetMode.IsSlirp4netns() {
|
||||
slirp4netnsIP, err := GetSlirp4netnsIP(c.slirp4netnsSubnet)
|
||||
|
@ -632,4 +632,25 @@ EOF
|
||||
is "$output" ".*nameserver $subnet.1.*" "integrated dns nameserver is set"
|
||||
}
|
||||
|
||||
@test "podman run port forward range" {
|
||||
for netmode in bridge slirp4netns:port_handler=slirp4netns slirp4netns:port_handler=rootlesskit; do
|
||||
local port=$(random_free_port)
|
||||
local end_port=$(( $port + 2 ))
|
||||
local range="$port-$end_port:$port-$end_port"
|
||||
local random=$(random_string)
|
||||
|
||||
run_podman run --network $netmode -p "$range" -d $IMAGE sleep inf
|
||||
cid="$output"
|
||||
for port in $(seq $port $end_port); do
|
||||
run_podman exec -d $cid nc -l -p $port -e /bin/cat
|
||||
# -w 1 adds a 1 second timeout, for some reason ubuntus ncat doesn't close the connection on EOF,
|
||||
# other options to change this are not portable across distros but -w seems to work
|
||||
run nc -w 1 127.0.0.1 $port <<<$random
|
||||
is "$output" "$random" "ncat got data back (netmode=$netmode port=$port)"
|
||||
done
|
||||
|
||||
run_podman rm -f -t0 $cid
|
||||
done
|
||||
}
|
||||
|
||||
# vim: filetype=sh
|
||||
|
Reference in New Issue
Block a user