Skip to content

Implement IP 4 to 6 mapping on HostIP listen addresses #50

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 29 additions & 1 deletion cmd/docker-ipv6nat/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"fmt"
"log"
"os"
"strings"
"net"

"github.com/fsouza/go-dockerclient"
"github.com/robbertkl/docker-ipv6nat"
Expand All @@ -18,6 +20,7 @@ var (
userlandProxy bool
version bool
debug bool
mapIpv4 string
)

func usage() {
Expand All @@ -43,6 +46,7 @@ func initFlags() {
flag.BoolVar(&retry, "retry", false, "keep retrying to reconnect after a disconnect")
flag.BoolVar(&version, "version", false, "show version")
flag.BoolVar(&debug, "debug", false, "log ruleset changes to stdout")
flag.StringVar(&mapIpv4, "map-ipv4", "", "IPv4 listen address mapping (IPV4/CIDR=IPV4,...)")

flag.Usage = usage
flag.Parse()
Expand All @@ -66,6 +70,25 @@ func main() {
}
}

func parseIpMapping(mapIpv4 string) (map[*net.IPNet]net.IP, error) {
res := map[*net.IPNet]net.IP{}
for _, map46 := range strings.Split(mapIpv4, ",") {
s := strings.Split(map46, "=")
if len(s)==2 && s[0] != "" && s[1] != "" {
_, ip4, err := net.ParseCIDR(s[0])
if err != nil {
return nil, fmt.Errorf("Cannot parse %+v IPv4, %e", map46, err)
}
ip6 := net.ParseIP(s[1])
if ip6 == nil {
return nil, fmt.Errorf("Cannot parse %+v IPv6, %e", map46)
}
res[ip4] = ip6
}
}
return res, nil
}

func run() error {
if debug {
log.Println("docker-ipv6nat is running in debug mode")
Expand All @@ -76,7 +99,12 @@ func run() error {
return err
}

state, err := dockeripv6nat.NewState(debug)
ipMap, err := parseIpMapping(mapIpv4)
if err != nil {
return err
}

state, err := dockeripv6nat.NewState(debug, ipMap)
if err != nil {
return err
}
Expand Down
15 changes: 14 additions & 1 deletion state.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ type State struct {
manager *Manager
networks map[string]*managedNetwork
containers map[string]*managedContainer
mapIpv4 map[*net.IPNet]net.IP
debug bool
}

// fc00::/7, Unique Local IPv6 Unicast Addresses, see RFC 4193
Expand All @@ -22,7 +24,7 @@ var ulaCIDR = net.IPNet{
}

// NewState constructs a new state
func NewState(debug bool) (*State, error) {
func NewState(debug bool, mapIpv4 map[*net.IPNet]net.IP) (*State, error) {
manager, err := NewManager(debug)
if err != nil {
return nil, err
Expand All @@ -32,6 +34,7 @@ func NewState(debug bool) (*State, error) {
manager: manager,
networks: make(map[string]*managedNetwork),
containers: make(map[string]*managedContainer),
mapIpv4: mapIpv4,
}, nil
}

Expand Down Expand Up @@ -236,6 +239,16 @@ func (s *State) parseContainer(container *docker.Container) *managedContainer {

if binding.HostIP != "" && binding.HostIP != "0.0.0.0" {
ip := net.ParseIP(binding.HostIP)
if ip != nil && ip.To4() != nil {
// Try map Ipv4 to IPv6
for ip4net, ip6 := range s.mapIpv4 {
if ip4net.Contains(ip) {
log.Printf("Converting listen IP %v to %v (matching %v)", ip, ip6, ip4net)
ip = ip6
break
}
}
}
if ip == nil || ip.To4() != nil {
// Skip bindings to IPv4.
continue
Expand Down