mirror of
https://github.com/clearlinux/libnetwork.git
synced 2026-05-14 02:23:34 +00:00
Merge pull request #195 from LK4D4/dummyproxy
Add dummy proxy on port map
This commit is contained in:
@@ -84,6 +84,8 @@ func (pm *PortMapper) Map(container net.Addr, hostIP net.IP, hostPort int, usePr
|
||||
|
||||
if useProxy {
|
||||
m.userlandProxy = newProxy(proto, hostIP, allocatedHostPort, container.(*net.TCPAddr).IP, container.(*net.TCPAddr).Port)
|
||||
} else {
|
||||
m.userlandProxy = newDummyProxy(proto, hostIP, allocatedHostPort)
|
||||
}
|
||||
case *net.UDPAddr:
|
||||
proto = "udp"
|
||||
@@ -99,6 +101,8 @@ func (pm *PortMapper) Map(container net.Addr, hostIP net.IP, hostPort int, usePr
|
||||
|
||||
if useProxy {
|
||||
m.userlandProxy = newProxy(proto, hostIP, allocatedHostPort, container.(*net.UDPAddr).IP, container.(*net.UDPAddr).Port)
|
||||
} else {
|
||||
m.userlandProxy = newDummyProxy(proto, hostIP, allocatedHostPort)
|
||||
}
|
||||
default:
|
||||
return nil, ErrUnknownBackendAddressType
|
||||
@@ -123,9 +127,7 @@ func (pm *PortMapper) Map(container net.Addr, hostIP net.IP, hostPort int, usePr
|
||||
|
||||
cleanup := func() error {
|
||||
// need to undo the iptables rules before we return
|
||||
if m.userlandProxy != nil {
|
||||
m.userlandProxy.Stop()
|
||||
}
|
||||
m.userlandProxy.Stop()
|
||||
pm.forward(iptables.Delete, m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort)
|
||||
if err := pm.Allocator.ReleasePort(hostIP, m.proto, allocatedHostPort); err != nil {
|
||||
return err
|
||||
@@ -134,13 +136,11 @@ func (pm *PortMapper) Map(container net.Addr, hostIP net.IP, hostPort int, usePr
|
||||
return nil
|
||||
}
|
||||
|
||||
if m.userlandProxy != nil {
|
||||
if err := m.userlandProxy.Start(); err != nil {
|
||||
if err := cleanup(); err != nil {
|
||||
return nil, fmt.Errorf("Error during port allocation cleanup: %v", err)
|
||||
}
|
||||
return nil, err
|
||||
if err := m.userlandProxy.Start(); err != nil {
|
||||
if err := cleanup(); err != nil {
|
||||
return nil, fmt.Errorf("Error during port allocation cleanup: %v", err)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pm.currentMappings[key] = m
|
||||
|
||||
@@ -2,6 +2,7 @@ package portmapper
|
||||
|
||||
import (
|
||||
"net"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/libnetwork/iptables"
|
||||
@@ -194,3 +195,77 @@ func TestMapAllPortsSingleInterface(t *testing.T) {
|
||||
hosts = []net.Addr{}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMapTCPDummyListen(t *testing.T) {
|
||||
pm := New()
|
||||
dstIP := net.ParseIP("0.0.0.0")
|
||||
dstAddr := &net.TCPAddr{IP: dstIP, Port: 80}
|
||||
|
||||
// no-op for dummy
|
||||
srcAddr := &net.TCPAddr{Port: 1080, IP: net.ParseIP("172.16.0.1")}
|
||||
|
||||
addrEqual := func(addr1, addr2 net.Addr) bool {
|
||||
return (addr1.Network() == addr2.Network()) && (addr1.String() == addr2.String())
|
||||
}
|
||||
|
||||
if host, err := pm.Map(srcAddr, dstIP, 80, false); err != nil {
|
||||
t.Fatalf("Failed to allocate port: %s", err)
|
||||
} else if !addrEqual(dstAddr, host) {
|
||||
t.Fatalf("Incorrect mapping result: expected %s:%s, got %s:%s",
|
||||
dstAddr.String(), dstAddr.Network(), host.String(), host.Network())
|
||||
}
|
||||
if _, err := net.Listen("tcp", "0.0.0.0:80"); err == nil {
|
||||
t.Fatal("Listen on mapped port without proxy should fail")
|
||||
} else {
|
||||
if !strings.Contains(err.Error(), "address already in use") {
|
||||
t.Fatalf("Error should be about address already in use, got %v", err)
|
||||
}
|
||||
}
|
||||
if _, err := net.Listen("tcp", "0.0.0.0:81"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if host, err := pm.Map(srcAddr, dstIP, 81, false); err == nil {
|
||||
t.Fatalf("Bound port shouldn't be allocated, but it was on: %v", host)
|
||||
} else {
|
||||
if !strings.Contains(err.Error(), "address already in use") {
|
||||
t.Fatalf("Error should be about address already in use, got %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMapUDPDummyListen(t *testing.T) {
|
||||
pm := New()
|
||||
dstIP := net.ParseIP("0.0.0.0")
|
||||
dstAddr := &net.UDPAddr{IP: dstIP, Port: 80}
|
||||
|
||||
// no-op for dummy
|
||||
srcAddr := &net.UDPAddr{Port: 1080, IP: net.ParseIP("172.16.0.1")}
|
||||
|
||||
addrEqual := func(addr1, addr2 net.Addr) bool {
|
||||
return (addr1.Network() == addr2.Network()) && (addr1.String() == addr2.String())
|
||||
}
|
||||
|
||||
if host, err := pm.Map(srcAddr, dstIP, 80, false); err != nil {
|
||||
t.Fatalf("Failed to allocate port: %s", err)
|
||||
} else if !addrEqual(dstAddr, host) {
|
||||
t.Fatalf("Incorrect mapping result: expected %s:%s, got %s:%s",
|
||||
dstAddr.String(), dstAddr.Network(), host.String(), host.Network())
|
||||
}
|
||||
if _, err := net.ListenUDP("udp", &net.UDPAddr{IP: dstIP, Port: 80}); err == nil {
|
||||
t.Fatal("Listen on mapped port without proxy should fail")
|
||||
} else {
|
||||
if !strings.Contains(err.Error(), "address already in use") {
|
||||
t.Fatalf("Error should be about address already in use, got %v", err)
|
||||
}
|
||||
}
|
||||
if _, err := net.ListenUDP("udp", &net.UDPAddr{IP: dstIP, Port: 81}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if host, err := pm.Map(srcAddr, dstIP, 81, false); err == nil {
|
||||
t.Fatalf("Bound port shouldn't be allocated, but it was on: %v", host)
|
||||
} else {
|
||||
if !strings.Contains(err.Error(), "address already in use") {
|
||||
t.Fatalf("Error should be about address already in use, got %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package portmapper
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
@@ -159,3 +160,50 @@ func (p *proxyCommand) Stop() error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// dummyProxy just listen on some port, it is needed to prevent accidental
|
||||
// port allocations on bound port, because without userland proxy we using
|
||||
// iptables rules and not net.Listen
|
||||
type dummyProxy struct {
|
||||
listener io.Closer
|
||||
addr net.Addr
|
||||
}
|
||||
|
||||
func newDummyProxy(proto string, hostIP net.IP, hostPort int) userlandProxy {
|
||||
switch proto {
|
||||
case "tcp":
|
||||
addr := &net.TCPAddr{IP: hostIP, Port: hostPort}
|
||||
return &dummyProxy{addr: addr}
|
||||
case "udp":
|
||||
addr := &net.UDPAddr{IP: hostIP, Port: hostPort}
|
||||
return &dummyProxy{addr: addr}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *dummyProxy) Start() error {
|
||||
switch addr := p.addr.(type) {
|
||||
case *net.TCPAddr:
|
||||
l, err := net.ListenTCP("tcp", addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.listener = l
|
||||
case *net.UDPAddr:
|
||||
l, err := net.ListenUDP("udp", addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.listener = l
|
||||
default:
|
||||
return fmt.Errorf("Unknown addr type: %T", p.addr)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *dummyProxy) Stop() error {
|
||||
if p.listener != nil {
|
||||
return p.listener.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user