Skip to content
This repository was archived by the owner on Dec 13, 2018. It is now read-only.
Merged
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
24 changes: 24 additions & 0 deletions netlink/netlink_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"math/rand"
"net"
"os"
"path/filepath"
"sync/atomic"
"syscall"
"unsafe"
Expand Down Expand Up @@ -1204,6 +1205,28 @@ func SetMacAddress(name, addr string) error {
return nil
}

func SetHairpinMode(iface *net.Interface, enabled bool) error {
sysPath := filepath.Join("/sys/class/net", iface.Name, "brport/hairpin_mode")

sysFile, err := os.OpenFile(sysPath, os.O_WRONLY, 0)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: ioutil.WriteFile

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I stayed away from any function which tries to create the file. If the file doesn't exist, it shouldn't create it.
Granted the creation should fail, but I thought this was cleaner.

if err != nil {
return err
}
defer sysFile.Close()

var writeVal []byte
if enabled {
writeVal = []byte("1")
} else {
writeVal = []byte("0")
}
if _, err := sysFile.Write(writeVal); err != nil {
return err
}

return nil
}

func ChangeName(iface *net.Interface, newName string) error {
if len(newName) >= IFNAMSIZ {
return fmt.Errorf("Interface name %s too long", newName)
Expand All @@ -1224,5 +1247,6 @@ func ChangeName(iface *net.Interface, newName string) error {
if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), syscall.SIOCSIFNAME, uintptr(unsafe.Pointer(&data[0]))); errno != 0 {
return errno
}

return nil
}
8 changes: 8 additions & 0 deletions network/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,11 @@ func SetMtu(name string, mtu int) error {
}
return netlink.NetworkSetMTU(iface, mtu)
}

func SetHairpinMode(name string, enabled bool) error {
iface, err := net.InterfaceByName(name)
if err != nil {
return err
}
return netlink.SetHairpinMode(iface, enabled)
}
3 changes: 3 additions & 0 deletions network/veth.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ func (v *Veth) Create(n *Network, nspid int, networkState *NetworkState) error {
if err := SetMtu(name1, n.Mtu); err != nil {
return err
}
if err := SetHairpinMode(name1, true); err != nil {
return err
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to fail the creation if hairpin mode isn't enabled or failed to be setup?
Can we log and forgive?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be possible to limp along without it. I see 2 potential avenues.

  1. If we remove the proxy, hairpin connections would simply fail.
  2. If we keep the proxy, we could not add the iptables rule to DNAT traffic, this would cause the connection to hit the proxy which would route it back in.

I think # 2 is dangerous. The proxy causes all traffic to appear to come from a certain source address. If an app has some sort of automatic blacklist capability, failing back to this method might cause the app to blacklist all traffic.

}
if err := InterfaceUp(name1); err != nil {
return err
}
Expand Down